Skip to content

feat(devtools)!: move to osls 4 for 2.0.1 (ADR-050) - #704

Open
seanspeaks wants to merge 5 commits into
nextfrom
feat/osls-4
Open

seanspeaks wants to merge 5 commits into
nextfrom
feat/osls-4

Conversation

@seanspeaks

@seanspeaks seanspeaks commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements ADR-050 (#664): Frigg 2.0.1 moves from osls 3 to osls ^4.4.0. Execution checklist: #665. The PR has two code steps so each artifact diff isolates one change: commit 1 converts the config while on osls 3, and commit 3 bumps osls.

Commit What
feat(devtools): emit package.patterns and omit useDotenv=false New toPackagePatterns({ include, exclude }) → [!exclude…, include…]. Routes E1 (auth/user/health), E3 (integration HTTP, webhook, extension routes, queue worker, dlqProcessor), E4/E5 (migration worker/router, individually kept) and E6 (admin script + report functions) through it. Deletes the dead E2 functionPackageConfig. Emits useDotenv: true only for offline. Leaves custom.esbuild.exclude alone.
fix(serverless-plugin): create LocalStack queues with a declared SDK v3 client See Deviation from ADR-050 below.
feat(devtools)!: move to osls ^4.4.0 with one frameworkVersion osls ^4.4.0 (devtools devDep, frigg-cli dep, lockfile). A single OSLS_FRAMEWORK_VERSION = '^4.4.0' replaces >=3.17.0 and the ADR-048 >=3.58.0 floor. engines.node: ^22.13.0 || >=24 on devtools and frigg-cli. The CLI checks the Node version first and prints a clear message. The serverless-config schema accepts ^/~ ranges. The management-ui scaffold uses ^4.4.0. iamRoleStatements is unchanged.
docs: osls 4 upgrade notes, operator notes and package size budget docs/reference/aws-sdk-v3-osls-migration.md, the devtools, infrastructure and frigg-cli READMEs, LOGGING.md, and the frigg skill reference.

Deviation from ADR-050: asyncInit in serverless-plugin is not dead code

ADR-050 says asyncInit → setupOfflineQueues → createLocalStackSQSClient (require('aws-sdk')) is not attached to a hook and can be deleted. That is not right. osls calls plugin.asyncInit() on every plugin in PluginManager.loadAllPlugins → asyncPluginInit(). This happens in osls 3.78.0 (plugin-manager.js:147/677) and in osls 4.4.0 (:208/753). So this path creates the LocalStack queues on every frigg start, and deleting it would break offline queues.

I kept the path and changed the client to a declared @aws-sdk/client-sqs v3 aggregated SQS client, which keeps the callback-style createQueue. I verified it under osls 4: frigg start on the featured app created InternalErrorQueue, DemoQueue and AdminScriptQueue on a moto endpoint at :4566 and set the *_QUEUE_URL env vars. I suggest an ADR-050 erratum.

Equivalence check (pattern ordering)

I read resolveFilePathsFromPatterns in both versions (osls 3.78.0 package-service.js:262, osls 4.4.0 :253). Frigg emits no service-level include, exclude or patterns. Function patterns go in include position unchanged. So [!exclude…, include…] gives exactly the osls 3 list: [!defaults…, !funcExclude…, funcInclude…, devDepIncludes…, !devDepExcludes…].

lib/utils/glob.js is byte-identical in the two versions, and so is excludeDevDependencies. In buildTasks, a !x pattern only prunes the ** candidates that come before it. A file pruned that way would also be set to excluded by !x in the osls 3 list. Later positive patterns (the CA file, dev-dep re-includes) are globbed as their own tasks. The artifact diffs below confirm the result.

Artifact gate 1: conversion only, osls 3.78.0 both sides

Two apps, packaged with osls package --config infrastructure.js --stage prod (what frigg build --production runs). Discovery and the layer describeStacks ran against moto (AWS_ENDPOINT_URL, plus a preload that points osls 3's SDK v2 at moto). No real AWS.

  • (a) scaffold: auth, user, health, dbMigrationRouter, dbMigrationWorker, prisma layer
  • (b) featured: integration demo + demoWebhook + demoQueueWorker, dlqProcessor, dbMigrationRouter/Worker, adminScriptExecutor/Router, VPC on, prisma layer

frigg init is not usable on next (the frigg-cli/templates dir is missing), so I hand-built both apps.

File lists (unzip -Z1, sorted) Per-file CRC (unzip -lv) CFN templates (create + update, normalised)
(a) before vs after identical for all 6 zips identical except .frigg-infrastructure-cache.json identical
(b) before vs after identical for all 12 zips identical except .frigg-infrastructure-cache.json identical
  • Templates: normalised for the artifact dir timestamp, LambdaVersion<hash> / CodeSha256 and layer hashes, with sorted keys.
  • Cache file: .frigg-infrastructure-cache.json is the composed-definition cache. It holds a timestamp and the definition, so it changes on every build. Code hashes differ only because of it. Pre-existing: this file is shipped in every function zip. That is worth a follow-up that excludes it.
  • Warnings: osls 3 warnings dropped from 3 deprecations to 1 after the conversion. useDotenv: must be equal to constant and the include/exclude deprecation are gone.

Artifact gate 2: osls 3.78.0 (converted) vs osls 4.4.0

File lists Per-file CRC CFN templates
(a) identical identical except package.json, node_modules/.package-lock.json and the cache file identical
(b) identical same three files only identical
  • Explained differences:
    • package.json is the app's own file; its osls devDependency changed.
    • node_modules/.package-lock.json is npm's hidden lockfile.
    • The changes to the installed tree are dev-only (osls's own deps), so they do not reach the zips.
  • Schema check: osls 4.4.0 packaged both apps with its default configValidationMode: error, with no config errors. The only remaining deprecation is the expected iamRoleStatements one.

Sizes

Identical on v3 and v4.

Function Zipped Unzipped
core, integration, dlqProcessor, admin functions 9.3 MB 31.4 MB
dbMigrationRouter 4.1 MB 13.6 MB
dbMigrationWorker 4.2 MB 13.9 MB
prisma layer 14.6–22.7 MB 37.2–56.3 MB
  • Budget: each function under 100 MB unzipped, and function + layers under 200 MB, against Lambda's 250 MB limit. The largest measured total is about 88 MB. This is documented in the migration doc.
  • Why ADR-050 saw ~73 MB zips: npm 9+ masks UUID-shaped path segments as *** in npm ls --parseable output. osls's dev-dependency exclusion parses that output. In a project path that contains a UUID, the exclusion matches nothing and every function ships the dev tree: about 195 MB unzipped and 67.6 MB zipped here, before I worked around it. This is independent of osls 3 vs 4, and it probably explains the ~73 MB zips in ADR-050's scratch run. All numbers above come from a run with a test-harness npm shim that un-masks the path. The doc tells users to build from a path without a UUID.

Runtime checks

  • frigg start, Node 24.10.0, osls 4.4.0:
    • scaffold: GET /health → 200
    • featured: GET /health → 200, and the three LocalStack queues were created through the new SDK v3 client
    • Not run: user create/login, integration list and an SQS message through serverless-offline-sqs. They need a running database.
  • Node 23.5.0:
    • The CLI exits early with the new message.
    • With FRIGG_SKIP_NODE_VERSION_CHECK=true, osls itself refuses: osls v4.4.0 does not support Node.js v23.5.0 … Supported versions: ^20.19.0 || ^22.13.0 || >=24.
    • osls 3.78.0 refuses Node 23 the same way.
  • Node 22.11: the CLI rejects it, as expected.

Tests

Baseline is origin/next vs this branch, Node 24, same install.

Suite set Baseline Branch
devtools infrastructure/** 1470 pass / 117 fail (18 failed suites) 1511 pass / 108 fail (18 failed suites)
serverless-plugin 44 / 0 47 / 0
frigg-cli 217 / 4 (4 failed suites) 233 / 4 (same 4 suites)
schemas — 128 / 0
  • No suite regressed. Every suite that fails on the branch also fails on next, with the same or fewer failures.
  • Builder suites: all pass, and each has new ADR-050 assertions.
  • Pre-existing failures: infrastructure-composer.test.js (51), template-generation.test.js, cloudformation-discovery.test.js, vpc-builder.test.js (8), health-domain suites, postgres-config, integration.test.js, build-time-discovery, build-prisma-layer, aws-provider-adapter, and the helper/fixture files picked up as suites.
  • template-generation: went from 29 to 20 failures. That is environmental (Prisma layer build state), not from this change.
  • frigg-cli failures, same on both: install.test.js (3), dependencies.test.js (1: expects devtools as a dependency), doctor/deploy/generate suite-load errors.
  • New tests:
    • helper table tests compared with the osls 3 ordering, including nestedNodeModulesExcludes in both modes
    • per-builder "no include/exclude, correct patterns" tests
    • a composer-level walk over a fully featured definition (VPC, KMS, webhook, extension, queue worker, migrations, admin scripts, reports, DocumentDB CA)
    • a useDotenv argv test
    • a framework-version/semver test
    • a CLI Node-range test
    • plugin SQS client tests

#665 checklist (items completed here)

PR 1 / helper and conversion:

PR 2 / bump:

  • osls ^4.4.0 in devtools + frigg-cli, lockfile regenerated
  • Single frameworkVersion constant ^4.4.0, tests updated
  • engines.node ^22.13.0 || >=24; the CLI prints a clear message
  • iamRoleStatements left as is
  • Follow-up issue for provider.iam.role.statements (not opened from here)
  • (a) and (b) validated against osls 4.4.0 with configValidationMode: error (packaged with no config errors)
  • Artifact gate 2: file lists + CRC, templates normalised, sizes recorded

Runtime:

  • frigg start GET /health 200 on (a) and (b) (partial: user/login, integration list and the SQS message were not run)
  • frigg build --stage prod against moto
  • frigg build against real credentials
  • Sandbox deploy + function invocations + no-op redeploy: needs real AWS, not done
  • frigg doctor on the sandbox stack

Docs:

Other findings (not fixed here)

  • @friggframework/core@2.0.0-next.120 requires @aws-sdk/client-scheduler without declaring it. The chain is infrastructure/scheduler/eventbridge-scheduler-adapter.js via core/index.js, and only packages/admin-scripts declares the package. An app that installs only core plus devtools fails to load infrastructure.js. I added the package to the test apps to get past it.
  • .frigg-infrastructure-cache.json is packaged into every function zip. It holds the full composed definition.

Test plan

  • npx jest infrastructure (devtools), serverless-plugin, frigg-cli and schemas suites: compared above
  • Gates 1 and 2 on the scaffold and featured apps against moto
  • frigg start on Node 24 (GET /health 200); Node 23 behaviour checked
  • Sandbox deploy gate (real AWS) before 2.0.1 ships

🤖 Generated with Claude Code

https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7

📦 Published PR as canary version: 2.0.0--canary.704.6a606c3.0

✨ Test out this PR locally via:

npm install @friggframework/admin-scripts@2.0.0--canary.704.6a606c3.0
npm install @friggframework/core@2.0.0--canary.704.6a606c3.0
npm install @friggframework/devtools@2.0.0--canary.704.6a606c3.0
npm install @friggframework/eslint-config@2.0.0--canary.704.6a606c3.0
npm install @friggframework/prettier-config@2.0.0--canary.704.6a606c3.0
npm install @friggframework/schemas@2.0.0--canary.704.6a606c3.0
npm install @friggframework/serverless-plugin@2.0.0--canary.704.6a606c3.0
npm install @friggframework/test@2.0.0--canary.704.6a606c3.0
npm install @friggframework/ui@2.0.0--canary.704.6a606c3.0
# or 
yarn add @friggframework/admin-scripts@2.0.0--canary.704.6a606c3.0
yarn add @friggframework/core@2.0.0--canary.704.6a606c3.0
yarn add @friggframework/devtools@2.0.0--canary.704.6a606c3.0
yarn add @friggframework/eslint-config@2.0.0--canary.704.6a606c3.0
yarn add @friggframework/prettier-config@2.0.0--canary.704.6a606c3.0
yarn add @friggframework/schemas@2.0.0--canary.704.6a606c3.0
yarn add @friggframework/serverless-plugin@2.0.0--canary.704.6a606c3.0
yarn add @friggframework/test@2.0.0--canary.704.6a606c3.0
yarn add @friggframework/ui@2.0.0--canary.704.6a606c3.0

Note

High Risk
Changes the deploy toolchain, Lambda packaging contract, and supported Node versions; misconfigured apps or leftover osls 3 pins can fail builds or ship oversized bundles, and osls 4 credential/AWS_ENDPOINT_URL behavior can misroute deploys.

Overview
Frigg 2.0.1 targets osls ^4.4.0 (ADR-050): devtools and frigg-cli bump the dependency and lockfile, and composed definitions emit a single frameworkVersion: ^4.4.0 via OSLS_FRAMEWORK_VERSION instead of osls 3 ranges.

Infrastructure builders now ship Lambda packaging as package.patterns through toPackagePatterns (excludes negated first, then includes), with useDotenv: true only for frigg start / offline. The CLI enforces host Node ^22.13.0 || >=24 before startup (FRIGG_SKIP_NODE_VERSION_CHECK to bypass). Tests and docs cover upgrade rules, operator/credential notes, and package size budgets; scaffold/schema examples move to ^4.4.0.

Reviewed by Cursor Bugbot for commit 6a606c3. Bugbot is set up for automated code reviews on this repo. Configure here.

@seanspeaks seanspeaks added release Create a release when this pr is merged prerelease This change is available in a prerelease. labels Oct 22, 2026
@netlify

netlify Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for friggframework-org canceled.

Name Link
🔨 Latest commit 6a606c3
🔍 Latest deploy log https://app.netlify.com/projects/friggframework-org/deploys/6adb85f9ce57f84dfd66bcda

@seanspeaks
seanspeaks marked this pull request as ready for review October 22, 2026 20:56

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization has no extra usage available to pay for this review.

If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.

Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.

seanspeaks and others added 5 commits October 23, 2026 12:02
osls 4 rejects function-level package.include / package.exclude and
accepts only `useDotenv: true`. Convert every emitter while Frigg is
still on osls 3, where package.patterns is equally valid, so the change
can be verified on its own.

- Add toPackagePatterns({ include, exclude }) -> [!exclude..., include...].
  osls 3 placed a function's excludes (negated) ahead of its includes in
  resolveFilePathsFromPatterns, and Frigg emits no service-level
  include/exclude/patterns, so this is the same ordered list. An exclude
  that already starts with `!` becomes an include in exclude position,
  as osls 3 handled it.
- Route the auth/user/health config (base-definition-factory), the
  integration function config, both migration configs and the admin
  script/report config through the helper. The lists are unchanged.
- Delete the unused functionPackageConfig in base-definition-factory.
- Emit `useDotenv: true` only for `offline`; omit the key otherwise
  (osls treats an absent key as false).
- custom.esbuild.exclude is a serverless-esbuild option and is unchanged.

Tests: helper table tests against the osls 3 ordering, per-builder
assertions that no function carries include/exclude, and a composer
test that walks every function of a fully featured definition.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
…v3 client

createLocalStackSQSClient() required 'aws-sdk', which the plugin never
declared; it resolved only because osls 3 depends on SDK v2. ADR-050
treats this path as dead code, but osls calls asyncInit() on every
plugin in PluginManager.loadAllPlugins (osls 3 and 4), so it runs on
every `frigg start` to create the LocalStack queues. Deleting it would
break offline queues.

Keep the path and build the client from @aws-sdk/client-sqs (now a
declared dependency). The v3 aggregated SQS client keeps the
callback-style createQueue that LocalStackQueueService calls, with the
same region, endpoint and LocalStack credential defaults.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
- osls ^4.4.0 in devtools (devDependency) and frigg-cli (dependency);
  lockfile regenerated. osls 4 drops the AWS SDK v2 dependency that
  osls 3 brought into every app.
- One OSLS_FRAMEWORK_VERSION constant ('^4.4.0') replaces '>=3.17.0' in
  base-definition-factory and the ADR-048 LoggingConfig floor
  ('>=3.58.0') in logging-config. An app that still resolves osls 3 now
  fails fast with FRAMEWORK_VERSION_MISMATCH.
- engines.node '^22.13.0 || >=24' on devtools and frigg-cli. The CLI
  checks the host Node version first and prints a clear message on
  Node 23 and Node 22.0-22.12 (FRIGG_SKIP_NODE_VERSION_CHECK=true
  bypasses it).
- serverless-config schema accepts caret/tilde ranges; management-ui
  scaffold and schema examples use '^4.4.0'.
- provider.iamRoleStatements is unchanged (osls 4 deprecation warning
  only; tracked for osls 5).

BREAKING CHANGE: apps must run osls 4. Apps whose infrastructure.js adds
package.include/exclude, sets useDotenv: false, pins frameworkVersion
'3' or ^3.x, or loads a plugin that uses SDK v2 provider surfaces now
fail. Node 23 and Node 22.0-22.12 hosts are unsupported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
…DR-050)

- aws-sdk-v3-osls-migration.md: osls ^4.4.0 install, the Node host
  range, what Frigg now emits, an "Upgrading an app to 2.0.1" table
  (include/exclude -> patterns, useDotenv, frameworkVersion, service
  patterns ordering, SDK v2 plugin surfaces, Node 23), operator notes
  (profiles + role_arn, mfa_serial, regional STS, AWS_ENDPOINT_URL, CRC32
  checksums), the measured per-function sizes and budget, and rollback.
- devtools, infrastructure and frigg-cli READMEs: requirements and the
  packaging rules; LOGGING.md and the frigg skill reference updated.
- frigg-cli dependency test now requires osls 4.4+ within major 4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
#639 added the SDK v3 LocalStack client and its tests with @aws-sdk/client-sqs
mocked; the ADR-050 copies needed the real client and failed under that mock.
Keep only the guard that the plugin no longer requires aws-sdk.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
@sonarqubecloud

Copy link
Copy Markdown

@cursor

cursor Bot commented Oct 24, 2026

Copy link
Copy Markdown

Frigg 2.0.1 review (Group 2) — COMMENT only

Checklist

  • Function package.patterns: excludes (!) before includes: pass (toPackagePatterns)
  • useDotenv only when true (osls offline): pass
  • LocalStack queues use AWS SDK v3: pass (createLocalStackSQSClient → @aws-sdk/client-sqs)
  • Node engines ^22.13.0 || >=24 + CLI check + FRIGG_SKIP_NODE_VERSION_CHECK=true: pass
  • Per-function size budget: pass (documented in docs/reference/aws-sdk-v3-osls-migration.md; measured budget, not a hard CI gate — acceptable per ADR-050 notes)
  • Nothing references aws-sdk v2 in runtime packaging path: mostly pass (esbuild external/exclude listing aws-sdk is defensive; see should-fix)

Verdict (would): would approve

Findings

  1. should-fix — packages/core/handlers/webhook-flow.integration.test.js

    • Still jest.mock('aws-sdk', …) and require('aws-sdk') for SQS doubles.
    • Scenario: Fresh install / osls 4 tree without a transitive aws-sdk v2 → this suite fails to load the mock module even though production LocalStack/queue code is on v3. Point the test at @aws-sdk/client-sqs (or @aws-sdk/client-sqs mock client) so CI does not reintroduce a v2 dependency.
  2. nit — enforceNodeVersion only treats FRIGG_SKIP_NODE_VERSION_CHECK === 'true' (not 1 / case variants). Documented as true; fine unless you want parity with encryption’s isTrue.

No blocking issues for ADR-050.

*/
function toPackagePatterns({ include = [], exclude = [] } = {}) {
return [
...exclude.map((pattern) =>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checklist note (pass): toPackagePatterns emits excludes (negated) before includes, matching osls 3’s include/exclude evaluation order for osls 4 package.patterns.

@cursor

cursor Bot commented Oct 24, 2026

Copy link
Copy Markdown

Follow-up findings (COMMENT)

  1. should-fix — docs/reference/aws-sdk-v3-osls-migration.md:14 links to ../architecture-decisions/050-osls-4.md, which is not on this branch (lives on #664 / adr/050-osls-4).

    • Scenario: #704 merges before #664 → broken in-repo ADR link for anyone following the upgrade guide.
  2. nit — packages/serverless-plugin/package.json declares "dependencies" twice (lines ~6 and ~13). Last-key-win; still invalid style and noisy for tooling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

prerelease This change is available in a prerelease. release Create a release when this pr is merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant