mirror of
https://github.com/vercel/workflow.git
synced 2026-09-14 19:59:43 +08:00
changeset-release/main
51 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f14c378846 | fix(ci): read manifests from the commit in check-published (#4147) | ||
|
|
c29200fac5 |
docs(ai): clean up WorkflowAgent docs and examples (#3891)
Co-authored-by: Peter Wielander <peter.wielander@vercel.com> |
||
|
|
f5aeaa869c |
Move to changesets v3 and changesets/action v2 (#3974)
Co-authored-by: Peter Wielander <peter.wielander@vercel.com> |
||
|
|
c477cfa3d3 | Keep one failed publish from taking down the release, and verify what actually reached npm (#3967) | ||
|
|
8a91d18d0d | [core] Add the wake-loop scenario to the event log race repro (#4017) | ||
|
|
22a9668dcf |
Validate pending changesets in CI so a bad one fails the PR, not the Release job (#3964)
`changeset version` assembles a release plan from every pending changeset before it bumps anything, and throws on a changeset it cannot place there: one naming a package outside the workspace, or one mixing a package from the `ignore` list with published ones. #3938 shipped the latter and every push to main since has failed to publish (#3963). Nothing at PR time ran that step. scripts/check-changesets.mjs runs the same assembly on the same inputs, resolving the libraries from @changesets/cli's own install so the check uses exactly the versions the Release job does, and stops before the network-bound changelog generation. lint.yml runs it on every PR. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
5c4eef0a97 |
chore: upgrade to pnpm 11.24.0 (#3901)
* chore: upgrade to pnpm 12 * fix: support pnpm 12 in CI * fix: enable pnpm 12 on Vercel * refactor: simplify pnpm 12 setup * refactor: target pnpm 11.24.0 * refactor: let pnpm setup own CI installs * refactor: limit workspace Node versions * fix: complete pnpm 11 CI migration |
||
|
|
f771585486 |
fix(world-vercel,world-local): hold process-wide state on globalThis (#3728)
* fix(world-vercel,world-local): hold process-wide state on globalThis Both packages are bundled into the host application's server build, and a bundler keys module identity on (resource, layer) — Next.js alone builds `instrument`, app-route, `ssr` and `edge` layers, so one process holds one copy of each of these modules per layer. Every module-scope `const`/`let` in them was therefore per-copy state wearing the costume of a process singleton. vercel/workflow#3493 made `@workflow/world-vercel` bundled rather than external and the events WebSocket transport regressed to HTTP for exactly this reason: the queue consumer registered its channel in the `instrument` copy's `Map` and the write path looked it up in the route copy's empty one. A deterministic miss, for the life of the process. `@workflow/world-local` had the same exposure all along — including `runFileLocks`, where a duplicated mutex simply stops mutually excluding. Add `globalSingleton()` to `@workflow/utils` (the primitive `@workflow/core` already hand-rolls for its World cache) and route every mutable module-scope binding in both worlds through it. Regression cover, in three layers: - `global-singleton.test.ts` pins the primitive's semantics. - `ws-transport-module-copies.test.ts` imports the module twice in one process and asserts a transport registered by one copy is found by the other — it fails on a plain module-scope `Map`, which is the shipped bug. - `scripts/lint/module-scope-state.mjs` fails the class: an AST rule banning mutable module-scope state in these packages, with `// per-copy-ok: <why>` as the deliberate escape. Wired into both packages' `vitest run src`, with fixture self-tests so it cannot rot into a no-op. * test(world-postgres): pin the module-scope-state rule for the postgres world It is deduped today only because `getRuntimeRequire()` loads it — a property of how it is loaded, not how it is written, and exactly what changed for world-vercel in #3493. The package is already clean; this keeps it that way. * docs(worlds): codify "a world must not hold mutable module state" A world package is loaded one of two ways, and only one of them gives it a single module instance: a runtime `require()` (deduped by Node) or the host's bundler (one copy per layer). Which one you get is a property of how the world is loaded, not of how it is written, and it changed under `world-vercel` in #3493 — so the rule has to be "never rely on module scope", not "rely on it until someone flips a config". Written down in the four places someone can meet it: - `docs/content/worlds/{v4,v5}/building-a-world.mdx` — a "Process-wide state" section for custom-world authors, with the loading modes spelled out and a nudge to prefer World-instance state over a global. - `packages/world/README.md` — the same constraint on the contract package. - `CLAUDE.md` — so the next contributor working in these packages sees it. - `packages/core/src/runtime/world.ts` — at the two static imports, which is where the difference between a bundled world and a required one originates. The rule's own error message now teaches it too, rather than naming a helper. Consolidates the guard while here: `@workflow/utils` owns the rule and its fixture self-tests, and sweeps every *published* `packages/world-*` discovered at runtime, so a world package added later is covered without anyone remembering. Each world keeps a one-assertion mirror for locality. * style: drop prose em dashes from this branch's new text #3704 landed a repo-wide writing pass hours after this branch was written and took `world-vercel/src` from 406 em dashes to 130 (`ws-transport.ts` alone went 35 to 1). This branch's docs section, README, comments and lint messages were written before that and would have put 36 of them straight back into the files that were just cleaned. Rewritten sentence by sentence rather than by substitution: an em dash becomes a colon, a comma, a full stop or a parenthetical depending on what it was doing. Also fixes a real defect the sweep surfaced: `world-postgres`'s guard test was generated through a shell heredoc and had literal backslash-backticks in its doc comment. * Update .changeset/world-module-scope-state.md Co-authored-by: Peter Wielander <mittgfu@gmail.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> * fix(core): build the entrypoint's queue handler from getWorld() Adopted from #3666 by @MintedKenny, which implements #3665 and could not run CI as a fork PR. One line of behavior: `workflowEntrypoint`'s lazy handler init calls `getWorld()` rather than `getWorldHandlers()`. `getWorldHandlers()` owns a second, build-time-safe cache, so calling it from the runtime route built a *second* World in the same process. That costs a stateful World duplicate resources on every instance — world-postgres eagerly constructs a `pg.Pool` (default `max: 10`) and a nested world-local World in `createWorld()`, so self-hosted users have been paying for two of each — and, for a bundled world package, the two Worlds are built by two different module copies, which is the mechanism behind the WS transport regression the rest of this branch contains. The public `getWorldHandlers()` and its separate build-time cache are unchanged; only the runtime route stops using it. Kept from the original: the regression test asserting the factory runs exactly once, and the api-reference wording (re-applied over #3704's list punctuation). Not taken: renaming the `workflow.route.get_world_handlers` span. It is a distinct span from the per-request `workflow.route.get_world` at the top of the flow route, and reusing that name would collide with it in traces and in `runtime-trace-mode.test.ts`; a comment records why the name outlived the call. Co-authored-by: Kenneth <kenneth@standardforensics.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address AI review on the module-scope work Two blocking findings, both real: - **Cross-version state sharing** (`ws-transport.ts`). A process can hold two *published versions* of `@workflow/world-vercel` (a transitive dependency pinning an older `@workflow/core`, which depends on this package by exact version). Both wrote to the same unversioned `Symbol.for` key, so one version's write path could be handed a `WsEventsTransport` built by the other's class and frame against a protocol it may not share — with no version negotiation on the socket to catch it. `shapeVersion` cannot express this: the container is stable, the hazard is its contents. The registry and the events dispatcher recycler are now keyed by package version. The plain connection pools stay unversioned; sharing those across copies is the point. - **The documented pattern failed the rule this PR adds.** The custom-world docs teach `store[StateKey] ??= …`, which the rule flagged as a field write. It now recognizes state rooted at `globalThis`, following one alias hop, which is also what `core/private.ts:23` and `next/src/index.ts:58` are already doing correctly (core drops 26 findings to 22, next 7 to 6). The docs also now say outright that `globalSingleton()` is the same thing, since AGENTS.md prescribes it and the page did not mention it. Rule precision, from the review's probes: - `.mts`/`.cts` are scanned. `@workflow/world-testing` is authored in `.mts`, so its entry in the sweep was passing vacuously — with the walk fixed it reports a real finding, now annotated (it is a standalone `serve()` entry). - Mutations in top-level statements no longer count. A table filled at module evaluation is identical in every copy; divergence needs a later write. - `static` class fields are collected, attributed to the class name. - An *exported* binding initialized to an empty collection is a finding on its own, which approximates the cross-file case the walk cannot resolve. Six fixtures pin the new behavior. The rule's header now states what it does not see, and AGENTS.md states where the sweep stops and why core is not gated yet. Also tags `resetGlobalSingletonForTest` `@internal`. * fix(lint): attribute a static-field write to the field, not the class The static-field support added in the previous commit keyed `declared` on the class name, so a class carrying more than one mutable static reported one finding instead of one per field, and labelled the survivor with whichever mutation was seen first. On a two-static fixture it reported `static Registry.latch (`.set()`)`: the name of one field, the reason belonging to the other, pointing the reader at the wrong line. Key static fields `Class.field` and resolve a write to the same shape, via a new `memberPath()` that takes the first two segments of a member chain and tries that key before the bare root identifier. Two follow-ons fall out of having the path: - `this.field` inside a `static` member resolves to the class, which is the ordinary way to write the mutation. `staticClassOf()` returns nothing for an instance member, where `this` is an instance and the state is per-instance rather than per-copy, and nothing inside a nested `function`, which rebinds `this`. - `state.count++` is now a finding, like the `state.count += 1` that `assignment()` already reported. Fixtures pin all four, including the instance-field case that must stay clean. The four world packages still report zero, and the extracted `recordMutation()` keeps the file at its previous two Biome complexity warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: make module duplication inert across every bundled package `@workflow/core` is bundled into the host server build the same way the worlds are, and always has been — the original repro measured three live copies in every arm, including the pre-#3493 external one. One instance is not reachable: layers cannot share a module, and core cannot be external because it *is* workflow code (`runtime/start.ts:253` and nine methods in `runtime/run.ts` are `'use step'`), so it must go through the SWC loader. The Next integration already encodes that rule by removing workflow-bearing packages from `serverExternalPackages`. So the duplication stays and the hazard is removed instead, everywhere the duplication can happen. `@workflow/core` (22 findings to 0): warn-once latches in `constants.ts`, `start.ts` and `telemetry.ts`; the source-map tracer cache; the VM script cache; the QuickJS compiled-assets and baseline caches; the dev-server port cache (its own comment already said "per process"); the text codecs; the zstd browser decoder; and the `useStep` closure brand, where a function marked by one copy was invisible to another. The one with teeth was `step-single-flight.ts`: a per-copy map is not single-flight. Two invocations reaching it through different layers would each believe they were alone in the process and both run the step body, silently degrading in-process dedup to the cross-process residual its own doc scopes out to the ownership lease. Also `@workflow/world` (a warn-once set, hand-rolled onto `globalThis` to keep that package dependency-free), `@workflow/ai` (the lazy OTel API), and `@workflow/nest` (bootstrap config in a module-level `let` and two static class fields — configure one copy, read another, and the controller is unconfigured for the life of the process). Five sites are deliberately per-copy and now say why: state keyed on objects that never cross copies (the barrier safety-net `WeakSet`, the QuickJS pending byte `WeakMap`), the synchronously-scoped guest-code sink, and the OTel diagnostic that reports what *this* copy sees. The sweep now covers all of it. Packages with a single module graph stay out (build-time code, the CLI, the o11y UI, the test runner) and AGENTS.md records which and why. Found while doing this: two static fields on one class collapsed into a single entry in the rule, so `WorkflowModule.options` was invisible behind `WorkflowModule.outDir`. Statics are now keyed `Class.field`. * fix(world): suppress noAssignInExpressions on the globalThis idiom The hand-rolled form trips Biome, as it does in `packages/core/src/private.ts`, which carries the same suppression. Restructuring it into a helper function instead would hide the state behind a call the module-scope rule cannot follow, so the binding would stop being recognized as off-module and the package would report a finding for correct code. * fix: sweep every bundled package, and mark utils side-effect free @shalabhc asked on review whether `@workflow/utils` needs this too. It does, and so do three others: `utils`, `errors`, `serde` and `workflow` all end up in the host application's server build and none were in the sweep. All four report zero today, which is exactly the state `world-testing` appeared to be in before the `.mts` walk was fixed and it turned out to have a real finding. Being clean and being *checked* are different properties, and only the second one survives the next contributor. `sideEffects: false` on `@workflow/utils`: verified that every module in the package only declares (no import-time work), so a bundler can now drop the unused parts of the barrel instead of keeping all ~64 KB of it because three packages import one 476-byte function. --------- Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> Co-authored-by: Peter Wielander <mittgfu@gmail.com> Co-authored-by: Kenneth <kenneth@standardforensics.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Peter Wielander <peter.wielander@vercel.com> |
||
|
|
447013b73a |
Run the test suites CI was silently skipping (#3733)
* Run the test suites CI was silently skipping `turbo test` runs a package's tests only if that package declares a `test` script, so a suite can sit in the repo for months without ever running. Four were in that state: @workflow/world (13 files, 160 tests), @workflow/cli (5 / 51), @workflow/nitro (1 / 30), and two files under packages/core/e2e that no workflow named. Wire each one up, and add scripts/check-test-suites-wired.mjs plus a lint job so the next unwired suite fails CI instead of going unnoticed. Fixes #3731 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Drop the changesets and rename the guard job The PR only wires up existing suites and adds a CI check, so there is nothing to release. Rename the job to match its `no-test-overrides` sibling. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
9760f640bb | [e2e] Change race repro hook poke to soft-degrade instead of hard-stop at budget (#3561) | ||
|
|
f6513f1f75 | [ci] Remove the disabled Front release-PR dispatch workflow (#3680) | ||
|
|
f5591aa278 | [e2e] Fix event-log-race-repro for local/postgres (#3558) | ||
|
|
0c5a6495bc | [ci] Report all three event-log-race-repro lanes in one small PR comment (#3556) | ||
|
|
0f4b35f629 | [world-local] Fix CORRUPTED_EVENT_LOG from hook-resume staging slot holes (#3492) | ||
|
|
f8f6e17aeb |
Add opt-in QuickJS WASM VM engine (WORKFLOW_VM=quickjs) (#3048)
* Add opt-in QuickJS WASM VM engine (WORKFLOW_VM=quickjs) with full event replay * QuickJS engine: AbortController, setAttributes, terminal drain, turbo-safe requeue, stable PRNG seed * QuickJS engine: hook.getConflict support, cross-run writable forwarding symbols * QuickJS engine: stream framing round-trip, bound step proxies, webhook fidelity * Apply biome fixes to QuickJS engine files * Address review feedback: anchor source-map strip to end-of-input, use getWorkflowQueueName for conflict requeue, Buffer-free asset decoding, function replacers for payload injection, maxEventsLimit guard * CI: include generated QuickJS source assets in shared e2e build artifacts * Fix same-token hook ordering and conflicted-hook disposal in the QuickJS engine * CI: run both VM engines across all frameworks and worlds; label jobs with the engine * Fix stack overflow stripping inline source maps from webpack dev bundles; harden step-listing e2e assertions against eventually-consistent reads * e2e: poll step listings until analytics rows include attempt (optional column can lag terminal status) * e2e: use --withData to force storage-backed step listings for attempt assertions (analytics listing can omit attempt entirely) * Sort imports in QuickJS serialization files (biome organizeImports) * QuickJS engine: resolve the run's full payload-key capability so sealed (encp) hook payloads open Main's sealed-box work (#3096) makes cross-deployment resumeHook() seal hook payloads to the target run's published X25519 public key. The shared start() path publishes that key regardless of engine, so QuickJS runs receive sealed payloads too — but the QuickJS entrypoint resolved only the bare symmetric key via importKey(), which cannot open encp envelopes. The first sealed hook payload wedged the run right after hook_received, timing out every hook/webhook e2e on Vercel prod (node:vm legs were fine — the node engine resolves the full capability via memoizeEncryptionKey). Resolve deriveRunPayloadKeys() in the entrypoint instead and widen the runtime's key types from CryptoKey to DecryptionKey. Writes stay symmetric (encrypt() with RunPayloadKeys takes the encr path). Regression test seals a payload exactly as resumeHook does and round-trips it through the VM. * Address review: crypto/process parity, loud Intl guards, lazy engine import, VM-leak guard, telemetry namespace, eval-string escaping - Deterministic crypto.getRandomValues/randomUUID in the VM bootstrap, drawing from the seeded Math.random (identical sequences to the node engine's vm/index.ts implementations); all crypto.subtle methods throw with step-function guidance. process.env exposed as a frozen copy, matching node. - Intl: throwing constructors (no ICU in QuickJS), and toLocale*-family methods (incl. localeCompare) throw when given an explicit locale so cross-engine divergence is loud instead of silently writing different values into the event log. No-argument forms keep working. - runtime.ts lazy-imports the QuickJS entrypoint at dispatch, keeping the ~1.3MB embedded WASM assets out of node-engine deployments. - runQuickJSWorkflow wraps the per-run phase so an exceptional exit disposes the VM instead of leaking it in a reused compute instance; corrected the misleading fail-loud comment (run_failed, not retry); warn when the event drain loop exhausts its iteration bound. - Telemetry attributes renamed quickjs.* → workflow.vm.* to stay in the file's workflow.* namespace. - Eval-string correlation-id interpolation uses JSON.stringify instead of quote-only escaping. - common-vm.test.ts pins the reducer/reviver superset invariant against common.ts so the duplicated sets can't silently drift. - Docs enumerate the remaining global-surface differences (subtle.digest, Intl, WebAssembly, Atomics); quickjs-entrypoint documents the known precondition-guard gap. * QuickJS engine: implement resilient resumeHook (hookInput materialization + resumeId dedup) #1834 made resumeHook() fall back to enqueueing the run with a hookInput payload when the direct hook_received write fails transiently, with the runtime materializing the missing event on delivery. Only the node:vm path implemented it — the QuickJS dispatch returned before the node block, so the resilient payload was silently dropped and the new e2e timed out on every quickjs leg. - runtime.ts threads hookInput into runWorkflowWithQuickJS; the entrypoint materializes the missing hook_received after loading the event log (resumeId-keyed dedup, occurredAt from the resumeId ULID, local eventData substitution for lazy/ref responses, EntityConflict / HookNotFound handling) — mirroring the node block. - processEvents drops duplicate hook_received rows sharing a resumeId (first-in-log wins), matching the node engine's EventsConsumer dedup; the seen-set lives in the VM heap so it is deterministic per replay. Verified against the dev server with WORKFLOW_VM=quickjs: the resilient resume e2e passes and the materialization is observable in the logs; all 27 hook e2e tests green. * Rerun CI * QuickJS engine: split VM-local class/step-function reducers off the hardened host codec The hardened host-side serialization (#3257) made the shared reducers/class.ts and reducers/step-function.ts depend on serialization/hardened.ts, which imports node:util and captures host intrinsics — unbundleable and meaningless inside the QuickJS guest, where the codec already runs in the guest realm. Point the VM codec at pre-hardening copies with identical wire format; the host/guest boundary hardening for this engine arrives with the host-side serde that retires the VM bundle. * QuickJS engine: enqueue explicit wait continuations instead of same-message redelivery Scheduling sleep wakeups by returning { timeoutSeconds } redelivers the CURRENT queue message. When that message is a hook-resume delivery (carrying hookInput), its redelivery re-runs the lazy-resume re-ensure in the handler prologue; if the workflow disposed the hook during the first delivery (dispose -> sleep), the re-ensure gets HookNotFound, the prologue acks the message as 'nothing left to resume', and the wait timer it carried is silently lost — the run wedges (caught by the hookDisposeTestWorkflow e2e). Enqueue fresh continuation messages instead, matching the node engine's suspension handler: getWaitContinuationDispatch for pending waits (gaining delay clamping/hop chaining and pending-wait dedup keys) and a plain immediate message for elapsed-wait / attr_set / getConflict requeues. A fresh message carries only runId, so its delivery always reaches replay. Also: read hook_received resumeId from the canonical top-level event field (eventData.resumeId is the deprecated legacy fallback), and stop passing hookInput into the entrypoint — the shared prologue in runtime.ts materializes the event for both engines. Adds a VM replay test for the hook -> dispose -> sleep shape. * Sort imports in quickjs-entrypoint (biome organizeImports) * Address review: dispatch inside run-level try/catch, queue namespace + run-origin trace carrier threading, configurable interrupt budget - Move the QuickJS engine dispatch inside the replay loop's try so escaping engine failures (MaxEventsExceededError, WASM OOM, bundle-eval errors) reach the catch that classifies and records run_failed, instead of nacking the message and burning all 48 queue redeliveries into MAX_DELIVERIES_EXCEEDED. Transient world errors still rethrow for redelivery. Updated the two comments that describe the propagation. - Thread the queue namespace from runtime.ts through runWorkflowWithQuickJS into every message publish (step dispatch, hook_conflict requeue, immediate requeue, wait continuation) — without it, publishes on a namespaced deployment land on __wkf_workflow_* while consumers listen on __<ns>_wkf_workflow_*. - Thread the run-origin nextTraceCarrier accessor through instead of capturing the current invocation context, so linked-mode invocations form a star around workflow.start rather than chaining; the hook_conflict requeue now carries a traceCarrier and requestedAt. - Replace the hardcoded 30s VM interrupt budget with the configurable replay budget (getReplayTimeoutMs, default 240s), matching the node engine. * Sort imports in quickjs-runtime (biome organizeImports) |
||
|
|
4174a6ea73 | [ci] Shrink the event-log race repro job 100x and add a local world-postgres runner (#3273) | ||
|
|
32ac8e73fd |
Fix Biome lint violations and add Biome CI check (#3222)
* Fix Biome lint violations and add Biome CI check Biome was not configured to respect .gitignore, so ~92% of the 13,355 reported diagnostics came from gitignored build artifacts. Enable VCS integration (useIgnoreFile), apply safe auto-fixes across the repo, fix the remaining mechanical errors by hand, downgrade judgment-call a11y / dangerouslySetInnerHTML rules to warnings, and add a 'biome ci' job to the Lint workflow so violations block PRs going forward. * Use an empty changeset (no behavior change, no release needed) |
||
|
|
62d570ed4b | Remove retired v1 step route plumbing (#3061) | ||
|
|
2bb4164c9c |
Add Platformatic World to worlds-manifest.json (#1450)
* Add Platformatic World to worlds-manifest.json Signed-off-by: marcopiraccini <marco.piraccini@gmail.com> * ci fixup Signed-off-by: marcopiraccini <marco.piraccini@gmail.com> * ci: pin platformatic world image to 0.8.1 and harden community-world runner Signed-off-by: marcopiraccini <marco.piraccini@gmail.com> * platforamtic-world version Signed-off-by: marcopiraccini <marco.piraccini@gmail.com> * ci: wire generic docker service-type into community benchmark workflow The shared community-worlds matrix now emits service-type "docker" for any world with non-builtin or multiple services (e.g. Platformatic, which needs postgres + the platformatic/workflow image). tests.yml's e2e-community path already handles it, but benchmarks.yml's benchmark-community path (label-gated, non-blocking) did not — so a "community-benchmarks" run would start no services and fail. Mirror the e2e "Start Docker services" step, package-version pin, and docker cleanup into benchmark-community-world.yml, and pass `services`/`version` through from benchmarks.yml. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Signed-off-by: marcopiraccini <marco.piraccini@gmail.com> Co-authored-by: Pranay Prakash <pranay.gp@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
57cccaf373 | Remove lazy discovery from workflow/next (#2545) | ||
|
|
b805a8d660 |
test: support Vercel protection bypass secret in e2e headers (#2458)
Allow local or CI-adjacent e2e runs to bypass deployment protection with a Protection Bypass for Automation secret via VERCEL_PROTECTION_BYPASS. When set, getTrustedSourcesHeaders returns x-vercel-protection-bypass; otherwise existing GitHub Actions / VERCEL_OIDC_TOKEN trusted-sources behavior is unchanged. |
||
|
|
4708a77a35 |
CI: drop setup-command input from reusable community-world workflows (#1828)
* drop setup-command input from reusable community-world workflows The community-world matrix is produced by running scripts/create-community-worlds-matrix.mjs in the fork PR's checkout, so any field on it is attacker-controlled. Forwarding matrix.world.setup-command into the reusable workflow and eval-ing it let a malicious fork PR execute arbitrary shell on the runner. Replace the pass-through with a hardcoded per-world-id case in the reusable workflows (only turso currently needs a setup step) and drop the setup field from the matrix generator. * rename step to "Per-world setup" Addresses Copilot review feedback: the step no longer executes an arbitrary command, so the old name was misleading. |
||
|
|
00a011dee4 |
Add stable Next.js eager and lazy test coverage (#1747)
* Add stable Next.js eager and lazy test coverage * Address PR review feedback * Fix eager Next step route builds * Fix eager Next manifest refreshes * Fix eager Next e2e stack assertions * Externalize native step bundle bindings * Lazy load Vercel world runtime * Fix Next dev step sourcemap assertions * Consolidate eager build changesets * Fix Vercel world tracing in Next deployments * Externalize Vercel world in Next builds * Fix webpack tracing for Vercel world deps * Fix eager workflow route bundling * Rely on Next server externals |
||
|
|
8ea1532e48 | [core] Combine flow+step bundle and process steps eagerly (#1338) | ||
|
|
8202663857 | [workbench] Add TanStack Start workbench and tests (#1875) | ||
|
|
cd50618d1f |
ci: switch Vercel deployment-protection bypass to OIDC Trusted Sources (#1882)
* ci: switch Vercel deployment-protection bypass to OIDC Trusted Sources The e2e, benchmark, and docs-smoke CI jobs previously used the static `VERCEL_AUTOMATION_BYPASS_SECRET` deployment-protection bypass token to reach protected Vercel deployments. Switch them over to the new OIDC Trusted Sources flow: the GitHub Actions runner mints a short-lived OIDC token via `core.getIDToken()` and forwards it on requests in the `x-vercel-trusted-oidc-idp-token` header. Each workbench project (and `workflow-docs`) has been configured with a matching trusted-source rule: aud=https://github.com/vercel, repository=vercel/workflow The shared header helper now lives at `scripts/trusted-sources-headers.mjs` and is imported by both the e2e/bench tests and the docs smoke script, removing the previous duplication. * rename to VERCEL_OIDC_TOKEN and wire through world-vercel - Rename the env var from VERCEL_TRUSTED_OIDC_TOKEN to VERCEL_OIDC_TOKEN to match Vercel's convention (also read by @vercel/oidc's getVercelOidcToken()). - In @workflow/world-vercel, replace the legacy VERCEL_WORKFLOW_SERVER_PROTECTION_BYPASS / x-vercel-protection-bypass flow with VERCEL_OIDC_TOKEN / x-vercel-trusted-oidc-idp-token. The trusted-source header is attached on every outbound workflow-server request (both proxied through api.vercel.com and direct). - Drop the bypass header from the encryption-key and resolve-latest-deployment fetches: those go to api.vercel.com which is public. - Drop VERCEL_WORKFLOW_SERVER_PROTECTION_BYPASS plumbing from tests.yml. - Update the pending world-vercel changeset to describe the final trusted-sources flow. * . * . * ci: add statuses:read permission for wait-for-vercel-project action The action queries /commits/{sha}/status (Commit Statuses API) in addition to the Deployments API, in order to extract the Vercel `dpl_...` ID. With an explicit permissions block in place, GITHUB_TOKEN now needs `statuses: read` or the action 403s when resolving the deployment ID. Reported by Copilot review on #1882. * ci(docs): log status code and body when waitForServer times out Helps diagnose deployment-protection / OIDC-trusted-source bypass failures (e.g. SSO redirects) on the workflow-docs preview. * ci(docs): log OIDC token claims (aud, repository, etc.) for diagnostics Helps determine whether the bypass is failing because of missing trusted-source config, claim mismatch, or audience mismatch. * ci(docs): add curl debug step to verify OIDC header reaches Vercel * . * ci: remove debug logging now that trusted-sources config is correct The fetch-failure root cause was the trusted-sources rule format: the labs workbench projects had been PATCHed with just `to.slugs` (no `preset`), but Vercel's edge requires the dashboard-form-style `to.preset: 'all-custom'` field plus `development` in the slug list to match incoming requests. After re-PATCHing all projects with the correct format, the bypass works end-to-end. * ci(docs): debug — test trusted-sources bypass against docs and labs deployments Trying repository_owner claim added to one labs project to see if that fixes the bypass. * ci(docs): revert curl debug step The GitHub Actions OIDC trusted-sources bypass returns 401 on all tested projects regardless of claim configuration (including workflow-docs which was set up via the dashboard). This is not a per-project config issue. Need to investigate with Vercel team before continuing. * ci(docs): probe trusted-sources bypass and surface x-vercel-id Adds a debug step that does two HEAD requests against the docs preview deployment (with and without the OIDC trusted-sources header) and prints the response status line plus `x-vercel-id` for each. The proxy-side trusted-sources changes for GitHub Actions OIDC tokens are rolling out gradually (~12+ hours), so the edge-node identifier in `x-vercel-id` helps explain why a request might succeed or fail during the rollout window. Also includes `x-vercel-id` in the `waitForServer` timeout error so post-mortem analysis of failing runs has the same edge-node info. * ci(docs): drop trusted-sources curl probe — bypass works once proxy fix reaches the serving edge node The probe served its purpose: confirmed the bypass is functional once the request lands on a region that has the proxy-side trusted-sources fix rolled out. The waitForServer error message still surfaces x-vercel-id for any future rollout-window debugging. * . * world-vercel: log outbound OIDC token claims once per process Adds a one-shot diagnostic that prints the non-sensitive claims of the OIDC token (`iss`, `aud`, `owner_id`, `project_id`, `environment`, `sub`, `scope`, `exp`) on the first request that uses bearer auth. This is invaluable for debugging Vercel deployment-protection trusted-source rule mismatches: a 401 from the edge tells you nothing about why the rule didn't match, and the token's claims are the only thing that determines that. The signature is never logged. Gated to once per process — Vercel-issued tokens are process-stable for the lambda's lifetime so further log lines would just be redundant spam. * world-vercel: route trusted-sources header through getVercelOidcToken() The Authorization bearer correctly preferred config.token (a static Vercel auth token from CLI / Actions runner) and fell back to getVercelOidcToken() inside a Vercel function. But the trusted-sources bypass header (x-vercel-trusted-oidc-idp-token) was being read directly from process.env.VERCEL_OIDC_TOKEN inside getHeaders(). That env var is the bake-time token, frozen at deployment-creation time — on a project that has been redeployed after a settings change, it carries stale claims (e.g. an iss from when the project was briefly in 'global' mode) that no longer match the workflow-server's trusted-sources rule. Move trusted-sources header attachment from getHeaders() (sync) to getHttpConfig() (async) and source it from getVercelOidcToken(). That function reads getContext().headers['x-vercel-oidc-token'] first — a freshly minted per-request token that always reflects current project settings — and only falls back to the env var when that header is missing. Bearer auth source remains config.token-first. Also expand the diagnostic to log claims from BOTH the per-request OIDC token AND the bake-time env var so the divergence is visible in logs when debugging future trusted-source mismatches. Removes the now-misleading getProtectionBypassHeader() helper (its 'read env var directly' semantics were exactly the bug). * world-vercel: skip OIDC trusted-sources header on proxied path The two outbound flows have different auth requirements: 1. Proxied (usingProxy=true) — calls api.vercel.com/v1/workflow. Public endpoint, authenticated with a static Vercel auth token via config.token. The api-workflow proxy mints its own OIDC token before forwarding to workflow-server, so the trusted-sources bypass header on the SDK→proxy hop is meaningless. CLI, GitHub Actions, and other API-client callers take this path. 2. Direct (usingProxy=false) — runs inside a Vercel deployment talking straight to workflow-server. workflow-server validates a Vercel OIDC bearer; Vercel's edge validates the trusted-sources header. Both must come from getVercelOidcToken() (the per-request fresh token), not process.env.VERCEL_OIDC_TOKEN (the bake-time token that can be stale after a project config change). Previously getHttpConfig attached x-vercel-trusted-oidc-idp-token on both paths whenever getVercelOidcToken() resolved. That accidentally forwarded the GitHub Actions OIDC token (when wired into VERCEL_OIDC_TOKEN by the test runner) onto every SDK→proxy request, which is harmless but wrong-by-design — the proxy is public, doesn't look at that header on its inbound side, and the GHA token isn't its intended audience. Bearer auth source rules: - Proxied: only config.token. (No fallback to OIDC; that auth pathway doesn't go through the proxy's auth checks.) - Direct: config.token (for tests / local dev), falling back to getVercelOidcToken() (for Vercel-runtime calls). * world-vercel: throw if proxied path is hit without a Vercel auth token The api-workflow proxy authenticates the caller with a regular Vercel auth token (not OIDC), so reaching the proxied path with no config.token is always wrong: the proxy will reject the request and the SDK caller would see an opaque 401 with no actionable hint. Throw at config-resolution time with a clear message that points to the WORKFLOW_VERCEL_AUTH_TOKEN env var the SDK reads from. Adds tests covering both the no-token-throws case and the with-token-attaches- bearer-and-skips-trusted-sources case. * test(e2e): include x-vercel-id in startWorkflowViaHttp error message When the trusted-sources bypass returns 401, the error message now surfaces the response's x-vercel-id header so we can identify which edge node served the failure. Helps distinguish proxy-rollout incompleteness from actual config errors during incremental rollouts of edge-side changes. * ci: mint GHA OIDC tokens on demand to survive 5-minute expiry GitHub Actions OIDC tokens have a hard 5-minute lifetime that cannot be extended (no API to ask for a longer TTL — exp is always iat + ~300s). Pre-minting once at the start of the job and shipping the result down to the test runner via env var means tests that run late in the suite hit an expired token and 401 on /api/trigger-pages (and any other trusted-sources protected endpoint). Move minting into scripts/trusted-sources-headers.mjs: - getTrustedSourcesHeaders() is now async. - It calls the runner's ACTIONS_ID_TOKEN_REQUEST_URL endpoint directly (the env vars GHA exposes when permissions: id-token: write is on) and re-mints 60s before the cached token's exp. - Falls back to process.env.VERCEL_OIDC_TOKEN for non-GHA contexts (Vercel runtime, local dev). Workflow files drop the now-redundant 'Mint OIDC token' step and the VERCEL_OIDC_TOKEN env-var passthrough on the test step. The runner env vars propagate to subsequent steps automatically. Updates all 17 callers in e2e.test.ts / bench.bench.ts / utils.ts / docs/scripts/check-docs-smoke.mjs to await the now-async call. * address PR #1882 code review - Drop `statuses: read` from the three workflow permission blocks (the wait-for-vercel-project action works without it on a public repo). - Revert the `x-vercel-id` debug logging in `startWorkflowViaHttp`. - Delete `packages/world-vercel/src/jwt-claims.ts` (debug-only helper). - Drop the JWT claims diagnostic logging from `getHttpConfig`. - Tighten the auth-flow comment in `getHttpConfig` and remove the historical 'no longer attaches' note from `getHeaders`/its test. - Restore `.changeset/world-vercel-protection-bypass.md` (already shipped in a beta release per .changeset/pre.json). - Trim the `.changeset/world-vercel-trusted-sources.md` description to one short paragraph. * docs(AGENTS): document local VERCEL_OIDC_TOKEN via vercel env pull Configured trustedSources.projects on all 11 workbench app projects so each one accepts a Vercel-issued OIDC token from any of the others. A developer running e2e locally can now do `vercel env pull` from any workbench app's directory and use the resulting VERCEL_OIDC_TOKEN to bypass Deployment Protection on any of the workbench preview/prod deployments — no need to disable protection on the project just to run the suite locally. |
||
|
|
a9fea9132e |
Update workbench tests to build and run outside of monorepo (#1230)
* Setup fixes * ci: run local e2e against staged tarball workbenches * ci: update staged workbench tarball setup script * chore: set nextjs workbenches back to next 16.1.6 * update lock * test(e2e): resolve workbench path from WORKBENCH_APP_PATH * fix: address deferred builder issues outside monorepo * ci: stage tarball workbenches only for nextjs local e2e * fix(next): discover deferred steps imported via workflows * test(core): gate deferred step-discovery dev test to canary * test(e2e): cover cross-file imported step in build/start lanes * fix(e2e): use local manifest in local runs and relax dev rebuild timeout * fix(workbench): add imported-step workflow symlink for sveltekit/astro * test(e2e): scope imported-step workflow test to nextjs lanes * fix(next): rebuild deferred entries on discovered file updates * fix(next): watch transitive deferred step deps for dev rebuilds * fix(next): restore socket-driven deferred step rebuilds * add changeset * chore: address review feedback on deferred e2e updates * fix(cli): guard stream flush against closed write streams |
||
|
|
596f9bf139 |
[workflow] dispatch front release PR sync workflow (#1224)
* sync front release PR on changeset * Add github dispatcher for raising PRs on workflow releases on front |
||
|
|
b0464b6af2 | Always run canary Next.js tests (#1042) | ||
|
|
86f62f2779 |
Refactor e2e tests to no longer use "trigger" endpoint (#958)
## Summary
Refactors the E2E tests to call `start()` from `workflow/api` directly instead of going through the `/api/trigger` HTTP endpoint in each workbench app. This removes a layer of indirection — the tests now use the same API that users would use to start workflows programmatically.
### Before
```ts
const run = await triggerWorkflow('addTenWorkflow', [123]);
const returnValue = await getWorkflowReturnValue(run.runId);
```
- `triggerWorkflow()` sent an HTTP POST to `/api/trigger` on the workbench app
- The workbench app looked up the workflow function, called `start()`, and returned the run ID
- `getWorkflowReturnValue()` polled `GET /api/trigger?runId=...` until the workflow completed
### After
```ts
const run = await start(await e2e('addTenWorkflow'), [123]);
const returnValue = await run.returnValue;
```
- `e2e()` / `getWorkflowMetadata()` fetches the manifest from `/.well-known/workflow/v1/manifest.json` to look up the correct `workflowId`
- `start()` is called directly from the test process via the configured World
- `run.returnValue` polls for completion via the World (no HTTP polling endpoint needed)
### Changes
**`packages/core/e2e/e2e.test.ts`**
- Removed `triggerWorkflow()` and `getWorkflowReturnValue()` helpers
- Added `fetchManifest()` to fetch and cache the workflow manifest from the deployment
- Added `getWorkflowMetadata(file, fn)` to look up `{ workflowId }` from the manifest
- Added `e2e(fn)` shorthand for the common case of `workflows/99_e2e.ts`
- All tests call `start()` and `run.returnValue` directly
- Error tests use `.catch()` to inspect `WorkflowRunFailedError`
- Output stream tests use `run.getReadable()` directly (skipped on local world where cross-process streaming isn't supported)
- `beforeAll` configures the local World with the correct data directory and base URL
- Pages Router tests use `startWorkflowViaHttp()` to specifically validate the HTTP trigger path
**Workbench apps (hono, express, fastify, nest)**
- Removed `/api/trigger` route handlers
- Kept `/api/hook`, `/api/test-direct-step-call`, `/api/test-health-check` endpoints
- Re-added `_workflows.js` side-effect import for hono/express/fastify to maintain Nitro's HMR dependency graph
**Deleted trigger-only route files** from: nextjs-turbopack, nextjs-webpack, vite, sveltekit, astro, nuxt, nitro-v2, nitro-v3, example
**`.github/workflows/tests.yml`**
- Added `WORKFLOW_PUBLIC_MANIFEST: '1'` to all E2E test jobs
### Dependencies
Stacked on #963 which adds `WORKFLOW_PUBLIC_MANIFEST` support to all framework builders.
|
||
|
|
50f50f44d7 | NestJS framework support (#840) | ||
|
|
f491237e1e | [ai] Fix collectUiMessages option by accumulating chunks in a separate step call (#784) | ||
|
|
722c17243c | Dedupe release Slack lines by PR number (#793) | ||
|
|
aced2968ba | [ci] Post weekly github issue digest to slack (#780) | ||
|
|
c4f8033d8e | [ci] Post release notes to slack (#779) | ||
|
|
cbf9b46aea | [ci] Github changelog: fix packages that haven't changed being re-listed with same changes (#664) | ||
|
|
696ef450f2 | [ci] Fix github changelog generation missing some PR links (#663) | ||
|
|
28224fff13 | Compile release note summaries using custom script in CI (#637) | ||
|
|
54ba1888cd |
fix: compare benchmarks against PR base branch instead of main (#560)
* fix: compare benchmarks against PR base branch instead of main - Use github.event.pull_request.base.ref instead of hardcoded main - Remove search_artifacts: true to ensure most recent baseline is used - For stacked PRs, this compares against the parent PR's baseline 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: group failed e2e tests by category and app in summary Instead of listing each failed test as a separate item, group them by: 1. Category (world): e.g., "Community Worlds", "Vercel Production" 2. App (framework): e.g., "mongodb", "turso", "nextjs-turbopack" This makes the summary much more readable when there are many failures. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: ensure local E2E tests always produce JSON output - Add 'fastify' to app detection list in aggregate-e2e-results.js - Change && to ; so e2e tests run even if dev.test.ts fails - This ensures local-dev, local-prod, and local-postgres categories appear in the E2E summary comment 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: ensure local E2E tests always produce JSON output - Add 'fastify' to app detection list in aggregate-e2e-results.js - Change && to ; so e2e tests run even if dev.test.ts fails - This ensures local-dev, local-prod, and local-postgres categories appear in the E2E summary comment 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: publish CI results to GitHub Pages for docs - Add generate-docs-data.js script to create JSON summaries from CI artifacts - Add publish-results job to tests.yml and benchmarks.yml workflows - Update docs/lib/worlds-data.ts to fetch from GitHub Pages URLs - Results published to https://vercel.github.io/workflow/ci/ This allows the docs worlds page to display actual test/benchmark results without requiring a GITHUB_TOKEN. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: correct outputFile path for local E2E test artifacts The --outputFile path was using ../../ which placed files outside the repo because pnpm run test:e2e executes from workspace root, not from the cd'd workbench directory. This prevented local-dev, local-prod, and local-postgres test results from being uploaded as artifacts. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: show green checkmark for skipped tests instead of warning Skipped tests are intentional and shouldn't show as warnings in the E2E test summary comments. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: use collapsible sections in benchmark PR comment Wrap each benchmark, stream benchmarks section, and summary tables in <details> toggles to make the PR comment more compact and readable. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: add Vercel observability links to benchmark PR comments - Store runId in benchmark timing data - Add project-slug to Vercel benchmark matrix - Pass WORKFLOW_VERCEL_PROJECT_SLUG env var to benchmarks - Store Vercel metadata (teamSlug, projectSlug, environment) in timing files - Generate observability deep links for each Vercel world benchmark - Show observability links below Production (Vercel) tables 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: use correct Vercel project slugs for observability links - nextjs-turbopack → example-nextjs-workflow-turbopack - nitro-v3 → workbench-nitro-workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
49e2df4691 | fix: fastify and astro test matrix (#538) | ||
|
|
23e1fc59ca |
Feat: fastify support with nitro (#386)
* init Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * not using my prototype fastify plugin Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * renamed workbench dir Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * lockfile update Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * removed Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * symlinked workflows dir Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * added readme Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * symlinked client page Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * scope nitro route to allow renderer fallback Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * allow empty json bodies Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * comments Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * improve error handling and cleanup in /api/trigger Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * consistent server replies Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * expect json res Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * fix json res for e2e test 3,4,5,11 Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * fix fastify streaming responses Stream web streams the same way express or hono do. Read the web reader and write each json chunk to reply.raw. Avoids fastifys async iterator quirks that reordered frames and sent undefined data in the output stream tests Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * fix stream responses for e2e tests Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * clearer comments Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * fix streaming res content type. passes all core e2e tests Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * updated dev deps fastify bench Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * fastify logo (light/dark mode) Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * update url Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * fastify docs Signed-off-by: Sree Narayanan <sreeaadhi07@gmail.com> * Apply suggestions from code review Co-authored-by: Adrian <me@adriandlam.com> * Update docs/content/docs/getting-started/fastify.mdx Co-authored-by: Adrian <me@adriandlam.com> * Update docs/content/docs/getting-started/fastify.mdx Co-authored-by: Adrian <me@adriandlam.com> * Update docs/content/docs/getting-started/fastify.mdx Co-authored-by: Adrian <me@adriandlam.com> * Update docs/content/docs/getting-started/fastify.mdx Co-authored-by: Adrian <me@adriandlam.com> * Update docs/content/docs/getting-started/fastify.mdx Co-authored-by: Adrian <me@adriandlam.com> * Update docs/content/docs/getting-started/fastify.mdx Co-authored-by: Adrian <me@adriandlam.com> * Update docs/content/docs/getting-started/fastify.mdx Co-authored-by: Adrian <me@adriandlam.com> * Sree Narayanan <sreeaadhi07@gmail.com> DCO Remediation Commit for Sree Narayanan <sreeaadhi07@gmail.com> I, Sree Narayanan <sreeaadhi07@gmail.com>, hereby add my Signed-off-by to this commit: |
||
|
|
5dd15452cd |
Test and benchmark community worlds against e2e tests (#482)
* Add new github workflow * Enable pull_request trigger for community worlds workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add community worlds manifest and generation scripts - Add community-worlds.json manifest as single source of truth - Add scripts/generate-community-worlds-workflow.mjs to generate CI workflow - Add scripts/generate-community-worlds-docs.mjs to generate docs section - Update aggregate-benchmarks.js to load community worlds dynamically - Add pnpm generate:community-worlds script - Update docs/deploying/world/index.mdx with community worlds The manifest-based approach allows: - E2E tests to be auto-generated from the manifest - Benchmark aggregation to include community worlds - Docs to stay in sync with tested worlds 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix YAML syntax error - quote strings starting with @ The @ symbol has special meaning in YAML, so package names like @workflow-worlds/turso need to be quoted. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix Redis health-cmd quoting, remove unpublished starter world - Quote health-cmd when it contains spaces (fixes Docker arg parsing) - Remove @workflow-worlds/starter as it's not published to npm 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add benchmarks and summary job for community worlds - Add build job to share artifacts between benchmark jobs - Add benchmark jobs for Turso, MongoDB, and Redis worlds - Update summary job to show both E2E and benchmark status matrix - Add left border/indent to sidebar child items for visual hierarchy - Update workflow generator to support benchmark generation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Reuse build artifacts for E2E tests E2E jobs now depend on the shared build job and download artifacts instead of rebuilding packages from scratch. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add Worlds Ecosystem dashboard to docs - Create worlds-manifest.json with official and community worlds - Add aggregate-worlds-data.mjs script for processing E2E and benchmark results - Create WorldsDashboard, WorldCard, and BenchmarkChart components - Add /docs/worlds page showing compatibility status and performance - Include sample data for development The dashboard shows: - E2E test progress per world (pass/fail/skip counts) - Benchmark performance comparison across all worlds - Filter by official vs community worlds 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix CI to output JSON test results and add Jazz world - Update workflow generator to output JSON test results from vitest - Upload E2E results as artifacts for parsing in summary job - Summary job now shows actual pass/fail/skip counts per world - Add Jazz world to worlds-manifest.json (requires external credentials) - Add update-worlds-status.yml workflow to auto-update dashboard data - Update TypeScript types to support null lastRun and metrics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Refactor community worlds to use reusable workflows Instead of a generated workflow file, integrate community world testing directly into tests.yml and benchmarks.yml using reusable workflows. - Add reusable workflows for E2E tests: e2e-community-world.yml (no services), e2e-community-world-mongodb.yml, e2e-community-world-redis.yml - Add reusable workflows for benchmarks: benchmark-community-world.yml, benchmark-community-world-mongodb.yml, benchmark-community-world-redis.yml - Update tests.yml to call reusable workflows for Turso, MongoDB, Redis - Update benchmarks.yml to include community world benchmarks in summary - Delete generated community-worlds.yml and generator script This approach: - Inherits proper Rust/SWC setup from the main workflows - Keeps all CI in the established patterns - Makes adding new community worlds straightforward 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix benchmark timing file naming for community worlds Add WORKFLOW_BENCH_BACKEND env var support to bench.bench.ts so community world benchmarks generate timing files with the correct backend suffix (e.g., bench-timings-nextjs-turbopack-turso.json instead of -local.json). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add @workflow-worlds/starter to community worlds test matrix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Unify worlds manifest and add dynamic GitHub API fetching - Merge community-worlds.json into worlds-manifest.json with type field - Add server-side data fetching from GitHub API for worlds dashboard - Remove static worlds-status.json, fetch CI artifacts dynamically - Update all references to use unified manifest format - Remove obsolete community-worlds.yml and update-worlds-status.yml workflows 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Skip community worlds for non-nextjs-turbopack in benchmark summary Community worlds only run against nextjs-turbopack, so hide the "missing" rows for Express and Nitro frameworks in the benchmark comparison tables. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix stream benchmark detection to check for actual TTFB data The previous check `!== null` incorrectly returned true for undefined, causing all benchmarks to show TTFB columns. Now explicitly checks for a number type. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Hide Worlds Ecosystem page from sidebar The page is still accessible via direct link at /docs/worlds but won't appear in the navigation until it's been further iterated on. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix review comments: trailing newline and division by zero - Add trailing newline when replacing Community Worlds section in docs - Fix division by zero in WorldCard benchmark calculation when metrics is empty 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Consolidate community world workflows with service-type parameter - Create setup-workflow-dev composite action for common setup steps - Add service-type input to benchmark-community-world.yml and e2e-community-world.yml - Use conditional job execution (if: inputs.service-type == 'mongodb') to handle different services - Update benchmarks.yml and tests.yml to pass service-type parameter - Delete redundant workflow files: - benchmark-community-world-mongodb.yml - benchmark-community-world-redis.yml - e2e-community-world-mongodb.yml - e2e-community-world-redis.yml Reduces workflow files from 11 to 7 and eliminates ~500 lines of duplicated YAML. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Generate community world test matrix from worlds-manifest.json Replace hardcoded community world jobs with dynamic matrix generation using scripts/create-community-worlds-matrix.mjs. This allows adding/removing community worlds by editing the manifest instead of multiple workflow files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Apply suggestion from @vercel[bot] Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> * Add Samples column and separate local/production benchmarks - Add Samples column to all benchmark tables showing iteration count - Separate benchmark results into Local Development and Production sections - Add explanatory context for each section (localhost vs Vercel deployment) - Add GitHub action step summaries to e2e community world tests - Create aggregate-e2e-results.js script for parsing vitest JSON output 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Remove obsolete generate-community-worlds-docs script The Worlds Ecosystem page now fetches from worlds-manifest.json at runtime, making this script unnecessary. The npm script also referenced a non-existent workflow generator script. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Maximize composite action usage and reorganize benchmark output - Update setup-workflow-dev composite action with optional Rust, install-dependencies, and install-args inputs - Update tests.yml to use composite action in unit, e2e-vercel-prod, getTestMatrix, e2e-local-*, and getCommunityWorldsMatrix jobs - Update benchmarks.yml to use composite action in build, benchmark-local, benchmark-postgres, benchmark-vercel, and getCommunityWorldsMatrix jobs - Reorganize benchmark output to group by benchmark test with local/production tables within each benchmark - Remove invalid $schema reference from worlds-manifest.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add beads stealth mode stuff (for personal claude memory - will remove stealth if people want) * Add E2E test results PR comment summary - Add pr-comment-start job to create/update PR comment when tests start - Add artifact uploads to all e2e test jobs (vercel-prod, local-dev, local-prod, local-postgres, windows) - Update e2e-community-world.yml with consistent artifact naming (e2e-community-*) - Add summary job to aggregate all e2e results and update PR comment - Extend aggregate-e2e-results.js with --mode aggregate for multi-job PR summary - Group results by category (Vercel Production, Local Development, etc.) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add step summaries to all e2e test jobs Add "Generate E2E summary" step to each individual e2e job: - e2e-vercel-prod - e2e-local-dev - e2e-local-prod - e2e-local-postgres - e2e-windows Each job now outputs pass/fail/skip counts to GITHUB_STEP_SUMMARY. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Consolidate community world workflows to single job Replace 3 mutually exclusive jobs (e2e/e2e-mongodb/e2e-redis) with a single job that starts services via docker run when needed. This eliminates the skipped job entries that appear in the GitHub Actions UI. - Use conditional docker run steps instead of services: block - Add health check loops to wait for service readiness - Add cleanup step to stop containers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix extractWorldId to handle community world artifact naming Add handling for `e2e-results-community-{world}` pattern so community world test results are properly extracted (e.g., `e2e-results-community-turso` now correctly extracts `turso` instead of `community-turso`). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> |
||
|
|
1ac5592452 | feat: add astro support (#347) | ||
|
|
00066be07b |
feat: add express support (#138)
* refactor: migrate to latest nitro v3 Signed-off-by: Pooya Parsa <pooya@pi0.io> * update workaround * fix(nitro): nitro builder using deprecated srcDir * fix: testing matrix dirs * fix(hono): externalize nitro workflow output dir * chore: format * fix(nitro): externalize .nitro/workflow folder * docs(hono): update getting started * update docs and workbench * improve plugin patch * docs: preserve code style * update `getWorkflowDirs` * test: fix hono dev config * fix: wrong api file path in hono dev config * fix(nitro): check all dirs for builder * chore: add comments * add express workbench testing app * docs: add express wip page * add workflows symlink for express workbench * add hook and trigger routes for express workbench * update server entrypoint to use hook and trigger router * remove h3 and add express types * docs: add express getting started guide * test: wire up express workbench * Update workbench/express/routes/hook.routes.ts Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> * Update workbench/express/routes/trigger.routes.ts Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> * build: missing deps in workbench express * build: remove express as dev dep * lockfile * build: remove test command from express workbench * fix: url query parsing * chore: add README * remove app hook and trigger routers * . * fix: json body not getting parsed in workbench express * fix: writing streams in workbench * fix: wrong stream piping express workbench * update * fix: json parsing body workbench express * update * fix: add js file extension for relative import on workflow express workbench * test * refactor: route naming conventions for nitro * refactore: convert to catch all api on express * Update workbench/express/package.json Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> * refactor: api file convention * testing presets * refactor: use simple `index.ts` * update * switch entry format to node * add generate workflow script to express * fix: express nitro config * docs(express): update express getting started * test: add express * fix(express): workbench api routes * fix(express): add workflowsDir to testing matrix * format * update gitignore * fix * . * trigger ci * update workflows dir * fix: streaming in express * fix: not json parsing body express * fix: missing dev test in express * fix: test matrix for express * docs(express): update getting started and add rollup dep * . * docs: add express card to home page and getting started * Update docs/content/docs/getting-started/express.mdx Co-authored-by: Pooya Parsa <pooya@pi0.io> * docs: fix express * remove h1 on express --------- Signed-off-by: Pooya Parsa <pooya@pi0.io> Co-authored-by: Pooya Parsa <pooya@pi0.io> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> |
||
|
|
ee25bd9d55 |
refactor: upgrade to latest nitro v3 (#293)
* refactor: migrate to latest nitro v3 Signed-off-by: Pooya Parsa <pooya@pi0.io> * update workaround * fix(nitro): nitro builder using deprecated srcDir * fix: add back nitro config * fix: testing matrix dirs * fix(hono): externalize nitro workflow output dir * chore: format * fix(nitro): externalize .nitro/workflow folder * docs(hono): update getting started * changeset * update docs and workbench * improve plugin patch * docs: preserve code style * update `getWorkflowDirs` * update vite workbench * test: fix hono dev config * fix: wrong api file path in hono dev config * fix(nitro): check all dirs for builder * chore: add comments --------- Signed-off-by: Pooya Parsa <pooya@pi0.io> Co-authored-by: Adrian Lam <me@adriandlam.com> |
||
|
|
945a946812 |
Normalize Workbenches (#283)
* Normalize Workbenches Normalize trigger scripts across workbenches fix: include hono in local build test test: include src dir for test test: add workflow dir config in test to fix sveltekit dev tests add temp 7_full in example wokrflow format fix(sveltekit): detecting workflow folders and customizable dir Remove 7_full and 1_simple error replace API symlink in webpack workbench Fix sveltekit and vite tests Fix sveltekit symlinks Test fixes Fix sveltekit workflows path Dont symlink routes in vite Include e2e tests for hono and vite fix error tests post normalization wip - attempted fixes * Add claude demo command * fix: normalize workbench tests (#292) * Proper stacktrace propogation in world Proper stacktrace propogation in world * Standardize the error type in the world spec * Normalize Workbenches Normalize trigger scripts across workbenches fix: include hono in local build test test: include src dir for test test: add workflow dir config in test to fix sveltekit dev tests add temp 7_full in example wokrflow format fix(sveltekit): detecting workflow folders and customizable dir Remove 7_full and 1_simple error replace API symlink in webpack workbench Fix sveltekit and vite tests Fix sveltekit symlinks Test fixes Fix sveltekit workflows path Dont symlink routes in vite Include e2e tests for hono and vite * fix error tests post normalization * fix(sveltekit): reading file on hmr delete * changeset * fix(vite): add resolve symlink script * fix(vite): missing building on hmr * test local builder in vite * test: increase timeout on hookWorkflow * test: ignore vite based apps in crossFileWorkflow * test: fix nitro based apps status codes * fix: intercept default vite spa handler on 404 workflow routes * fix: vite hook route returning 422 * test: use 422 for hookWorkflow expected * test: fix hono returning 404 * chore: add comment to middleware to clarify * make api route for duplicate case * revert * revert: nitro builder * add back nitro unhandled rejection logic * test: add hono * changeset * fix: unused method * fix: remove duplicate import * remove * chore: add comments to clarify * test remove vite symlink script --------- Co-authored-by: Pranay Prakash <pranay.gp@gmail.com> * refactor: add top level resolve symlinks script * fix: cleanup builder directories (#319) * fix: add sveltekit server routes to builder * fix: remove root workflow dir check * fix missing root level workflow route * Fix: The constructor now hardcodes `dirs: ['src/routes', 'src/lib']` which silently ignores any user\-provided `dirs` option passed to the plugin\, breaking the documented API and removing support for custom workflow directories\. * Fix: The test expectations don\'t match the new implementation of `getWorkflowDirs()`\. The mock provides `scanDirs` which the new code no longer uses\, and the new implementation adds scanning of `routesDir` and `apiDir` instead\. * fix(nitro): use src dir --------- Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> * refactor(nitro): use suppressUndefinedRejections * revert: sveltekit builder --------- Co-authored-by: Adrian <me@adriandlam.com> Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> |
||
|
|
fb8153bec4 |
feat: add Nuxt module and documentation (#187)
* feat: add Nuxt module and documentation * fix: add the prepare in the build command * Apply suggestion from @vercel[bot] Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> * chore: simplify usage without /nuxt * wip * Update nuxt.mdx Co-Authored-By: Daniel Roe <daniel@roe.dev> * add clean command and ignore prepare * use @workflow/nitro * Changeset Added a Nuxt module and updated documentation accordingly. * feat: enable typescript plugin in tsconfig * chore: revert accordion value * chore: use symlink * fix: json parsing in trigger route for nitro-v2 * ci: add e2e tests for nuxt * ci: add nuxt to test matrix * chore: make sure to add /nuxt to avoid conflicts when importing entry-points * chore: move typescriptPlugin option to Nitro * chore: body is already parsed * fix: use readRawBody * fix: use rawBody in hook.post too * chore: add missing import (but not required) * chore: update pm * Create resolve-symlinks.sh * chore: add also node-rs/xxhash * Update create-test-matrix.mjs * update matrix * Update create-test-matrix.mjs * remove symlink to nitro-v2 --------- Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> Co-authored-by: Daniel Roe <daniel@roe.dev> Co-authored-by: Pranay Prakash <pranay.gp@gmail.com> Co-authored-by: Adrian Lam <me@adriandlam.com> |
||
|
|
adf0cfeb91 |
feat: add getPort for detecting pid port (#233)
* feat: add getPort method for detecting pid port * lockfile * update tests and fix getPort usage * changeset * docs: update sveltekit getting started * fix: use pid-port * fix: not using config port env * fix: remove unused getPort from world core * remove unused stuff * fix: world local config returning port 3000 as fallback * changeset * fix: rebase conflicts * fix: util test missing http import * changeset * fix: wrong import for getPort in core runtime * fix: getPort in @workflow/utils being imported into workflow runtime * test: simplify sveltekit test * fix missing import in test * fix: async await stuff with getPort * refactor: move getPort to @workflow/utils/get-port * test: simplfiy getPort tests * test: fix sveltekit ports |
||
|
|
98c36f1eb0 |
feat: add hmr and fix dev tests (#199)
* add hmr and dev tests for nitro and sveltekit * changeset * revert: e2e testing code * add streams.ts to workbench apps * fix: test confnigs * fix: hmr failing on new files for sveltekit plugin * lockfile * switch testing to use 3_stream.ts * fix: sveltekit hmr test file import * fix: nextjs testing file * remove stuff * changeset * refactor(tests): expose config through matrix config * fix: add symlink for nextjs turbopack * add resolve symlinks script * fix: nextjs-webpack resolve symlinks script |
||
|
|
05714f7924 |
feat: add sveltekit support (#131)
* add workbench sveltekit * add sveltekit package * fix: use js for generated server routes in svelte * add test routes for sveltekit workbench * updates from debugging * feat: add sveltekit build target * update user sign up workflow workbench sveltekit * fix: base builder missing GET route handler for sveltekit * feat: add vercel builder and check for vercel env * refactor: workflowPlugin for sveltekit * ci: add tests to workbench sveltekit * fix: no start command and vercel builder outputs * fix: base builder conditions * . * add auto adapter sveltekit * fix: disable checking origin for cross site ci stuff * allow all trusted origins in svelte config * fix: add catch for error thrown when waiting for ops * fix: sveltekit workbench adapter * test * test * refactor: move vercel builder on config resolved * update package json * add demo workflow trigger * test letting sveltekit handle route generation * fix: exclude git ignore for local builder outputs * update config * add debug logs * update debug * update turbo.json * fix env check * another output * use top-level await * ensure vercel functions are patched * change hook * update * fix spread * debug * update * chore: remove vercel builder * chore: update comments in sveltekit workflow package * chore: remove console comment * refactor: workflow svelte plugin * refactor: simplify local builder config * chore: remove unused deps * chore: add comment for workbench svelte app * chore: add sveltekit export to workflow * export sveltekit from workflow * lockfile * chore: remove unused deps svelte workbench * update styling * add sveltekit getting started docs * update sveltekit docs getting started * changeset * Apply suggestion from @vercel[bot] Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> * use proper env var * Update packages/sveltekit/src/index.ts Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> * Update docs/content/docs/getting-started/sveltekit.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Document CSRF protection bypass in SvelteKit workbench config (#157) * Initial plan * docs: add CSRF security warning to svelte.config.js Co-authored-by: adriandlam <93681064+adriandlam@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: adriandlam <93681064+adriandlam@users.noreply.github.com> * refactor: deduplicate SvelteKit request conversion logic (#156) * Initial plan * refactor: extract duplicated SvelteKit request conversion to helper Co-authored-by: adriandlam <93681064+adriandlam@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: adriandlam <93681064+adriandlam@users.noreply.github.com> * docs: fix getting staretd sveltekit missing folder * chore: cleanup sveltekit builder after rebase * lockfile * fix: sveltekit building logic in base builder * refactor: move sveltekit builder logic to its own package * fix: console log base builder * changeset * test * feat: create hmr plugin * fix: add initial build on load * fix: check all files for workflows and steps * add comments for plugin todo * remove catching error * fix: missing context for nodejs envs causing waitUntil to fail * fix: setting global request conext in vercel environments --------- Co-authored-by: JJ Kasper <jj@jjsweb.site> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> |