web: construct worlds explicitly instead of via static-injection stub#2804
Conversation
Since #2752, createWorld() from @workflow/core/runtime is a stub that throws unless a framework build plugin aliases it to a world package. The CLI was migrated to construct worlds directly, but @workflow/web still called the stub, so 'workflow web' crashed with 'Workflow target world was not statically injected' for local and postgres backends (the vercel path was unaffected since it constructs the world directly). Mirror the CLI: import the local world statically and resolve any other configured world package from the inspected project's directory. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: a42603f The changes in this PR will be included in the next version bump. This PR includes changesets to release 16 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
🧪 E2E Test Results✅ All tests passed Summary
Details by Category✅ ▲ Vercel Production
✅ 💻 Local Development
✅ 📦 Local Production
✅ 🐘 Local Postgres
✅ 🪟 Windows
✅ 📋 Other
❌ Some E2E test jobs failed:
Check the workflow run for details. |
📊 Benchmark Results
workflow with no steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) workflow with 1 step💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) workflow with 10 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) workflow with 25 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) workflow with 50 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) Promise.all with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) Promise.all with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) Promise.all with 50 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) Promise.race with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) Promise.race with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) Promise.race with 50 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) workflow with 10 sequential data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) workflow with 25 sequential data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) workflow with 50 sequential data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) workflow with 10 concurrent data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) workflow with 25 concurrent data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) workflow with 50 concurrent data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) Stream Benchmarks (includes TTFB metrics)workflow with stream💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) stream pipeline with 5 transform steps (1MB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) 10 parallel streams (1MB each)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) fan-out fan-in 10 streams (1MB each)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) SummaryFastest Framework by WorldWinner determined by most benchmark wins
Fastest World by FrameworkWinner determined by most benchmark wins
Column Definitions
Worlds:
|
VaguelySerious
left a comment
There was a problem hiding this comment.
workflow-web preview doesn't load runs on this PR, but did on #2752
|
^ actually seems to have broken some other commit, ignore |
TooTallNate
left a comment
There was a problem hiding this comment.
Reviewed and validated the fix live. Approving.
Bug confirmed reproducible: I ran the web dev server on this branch against a local-world project (WORKFLOW_TARGET_WORLD=local, WORKFLOW_OBSERVABILITY_CWD pointed at a project dir), then swapped in main's version of workflow-server-actions.server.ts — main fails every RPC with exactly the static-injection error from the description, this branch returns successful responses. Also exercised the dynamic-resolution error path (WORKFLOW_TARGET_WORLD=@acme/world-missing) and got the clear "Make sure the package is installed in the inspected project" message.
Correctness checks:
- The env dance holds together:
ensureLocalWorldDataDirEnv()still runs before construction and before theWORKFLOW_*-derived cache key is computed, and@workflow/world-local'screateWorld()readsWORKFLOW_LOCAL_DATA_DIR— so the arg-lesscreateLocalWorld()call picks up the inspected project's data dir, matching the CLI. - The dynamic path is a faithful mirror of the CLI's
createPostgresCliWorld()(createRequire(join(cwd, 'package.json')).resolve+import(pathToFileURL(...))), generalized to any backend id — which correctly restores pre-#2752 community-world support for the web UI.@workflow/world-postgresis"type": "module", so the namedcreateWorldexport resolves without interop concerns. - No remaining call sites of the core stub in
packages/web;@workflow/world-localproperly added todependencieswith lockfile update; changeset present and accurate (patch). - 85/85 web tests pass locally.
CI: 101 pass; the 2 fails are the nextjs-webpack canary HMR fuzz timeout (hmrFuzzAddedStep manifest wait) and its downstream required-check aggregator — a known flaky lane, and this PR touches only web server actions, nothing in the Next integration or manifest rebuild path.
Two non-blocking thoughts:
- For community worlds shipped as CJS,
import()'s named-export detection depends on cjs-module-lexer; amod.createWorld ?? mod.default?.createWorldfallback would make the dynamic path a bit more forgiving. The CLI has the same shape today, so fine to defer or do both together. - The CLI's world setup now lags this implementation — it hard-throws on backends other than vercel/postgres/local, while this generalizes to any package exporting
createWorld(). A follow-up unifying both on a shared helper (this version) would fix that asymmetry and remove the duplication.
Review feedback on #2804: import() of a require-resolved CJS entry relies on cjs-module-lexer to surface named exports; fall back to mod.default.createWorld when detection fails. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review feedback: import() of a require-resolved CJS entry relies on cjs-module-lexer to surface named exports; fall back to mod.default.createWorld when detection fails. Mirrored in the CLI in #2806. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Addressed the review feedback:
|
* cli: restore dynamic world loading for community backends Since #2752 moved world selection to static injection, setupCliWorld only constructed the vercel, local, and postgres worlds explicitly and threw 'Unsupported workflow backend' for anything else — breaking community worlds (e.g. @workflow-worlds/turso) that previously loaded through the dynamic createWorld() in @workflow/core/runtime. Generalize the postgres-only dynamic path: any backend other than vercel/local is now resolved from the user's project directory and loaded via its createWorld() export, matching @workflow/web's world construction (#2804), with clear errors when the package is missing or does not export createWorld(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cli: fall back to default.createWorld for CJS world packages Review feedback on #2804: import() of a require-resolved CJS entry relies on cjs-module-lexer to surface named exports; fall back to mod.default.createWorld when detection fails. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Update .changeset/cli-generic-world-backends.md Signed-off-by: Peter Wielander <mittgfu@gmail.com> --------- Signed-off-by: Peter Wielander <mittgfu@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Peter Wielander <mittgfu@gmail.com>
|
No backport to This commit works around the static-injection To override, re-run the Backport to stable workflow manually via |
What changed
Fixes
workflow webcrashing for the local and postgres backends on latest main.Since #2752,
createWorld()from@workflow/core/runtimeis a static-injection stub that throws unless a framework build plugin aliases@workflow/core/runtime/world-targetto the selected world package at the host app's build time. The CLI was migrated to construct worlds explicitly (packages/cli/src/lib/inspect/setup.ts), but@workflow/web'sgetWorldFromEnvstill called the stub. Since the web UI selects its backend at runtime via env, no build plugin ever aliases its bundle, so every server action failed with:The Vercel backend was unaffected because that path constructs
createVercelWorlddirectly.Fix
Mirror the CLI's approach in
getWorldFromEnv:local/@workflow/world-local→ importcreateWorldfrom@workflow/world-localdirectly (added as a dependency of@workflow/web)@workflow/world-postgres, community worlds) → resolve the package from the inspected project's directory (WORKFLOW_OBSERVABILITY_CWD) and call itscreateWorld(), preserving the pre-Statically inject workflow world target #2752 dynamic-selection behavior with a clear error when the package isn't installedRepro / validation
workflow webagainst a local-world project → every RPC returns the static-injection error.@workflow/weband verified end-to-end against a local-world project (runs/steps/events/hooks list + detail + lazy hook-token fetch all working), and against the Vercel backend (unaffected path, still works).pnpm exec vitest run app/server/workflow-server-actions.server.test.ts— 3/3 passtsc --noEmiton@workflow/web— 15 errors, identical to the pre-existing main baseline (zero new)🤖 Generated with Claude Code