* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
Instead of accessing private files from SvelteKit, we use @sveltejs/load-config to load the Svelte config (that package also knows about checking Vite config). The deadlock is avoided by having a module-level Set to see if we're currently recursing or not.
This is necessary for SvelteKit 3 since there the config lives exclusively in the vite config, and the previous logic did not handle that.
This also uncovered that we're needlessly rebuilding the generated files in sub builds/workers (SvelteKit, at least below 3, starts off secondary builds; and some things are done in workers), which a new file cache now checks.
Picked from stable branch PR #3474
Signed-off-by: Simon Holthausen <simon.holthausen@vercel.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
The Astro and SvelteKit webhook wrappers copied the incoming request via
`normalizeRequest()`, which buffers the whole body with `arrayBuffer()`,
before calling the handler that validates the webhook token. Requests
carrying an unknown token therefore did unnecessary work before being
rejected.
The copy turns out to be unnecessary: both frameworks already hand the
route a standard `Request`, so the webhook wrappers now pass it straight
to the handler. The body is left untouched until `resumeWebhook()` has
accepted the token.
The flow route keeps `normalizeRequest()` for now — it authenticates via
the queue trigger rather than a URL token, so the ordering does not
matter there, and whether the shim is needed at all is a separate
question.
Note that the Astro dev server buffers request bodies upstream of the
route handler, so the new behavior is only observable in built output;
the node adapter and Vercel builds both benefit.
* fix(sveltekit): patch server chunks with rollup-renamed __filename bindings
The adapter-node chunk patch skipped any chunk matching
/\b(const|let|var)\s+__(file|dir)name\b/ — but $ is not a regex word
character, so rollup-renamed declarations like `__filename$1` (produced
when adapter-node re-bundles the intermediate server output and our
banner's declaration collides) satisfied the check. Chunks that declared
only a renamed binding while a bundled CJS dependency referenced the
bare `__filename` were skipped, and the production server crashed at
boot (observed on main with the TypeScript compiler bundled via
cosmiconfig through @workflow/world-postgres).
Anchor both regexes with (?![\w$]) so renamed identifiers no longer
match. Verified: the sveltekit workbench production server now boots and
serves health checks (with and without a base path), and queue
deliveries from start() succeed.
Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
* fix(sveltekit): keep the TypeScript compiler out of the server bundle
Since the world-target injection change, the sveltekit workbench's
hooks.server.ts imports @workflow/world-postgres, whose dependency chain
(graphile-worker -> cosmiconfig) reaches cosmiconfig's TS-config loader.
At runtime that loader's require('typescript') is lazy and never fires,
but SvelteKit bundles the whole chain into the server and rollup's CJS
conversion hoists it into an eager top-level evaluation — executing the
entire TypeScript compiler at boot and crashing the server
("__filename is not defined" inside the bundled compiler).
Alias 'typescript' to a stub module in the SvelteKit plugin, following
the existing pg-native pattern. Server output shrinks from 36MB to 11MB
and boots cleanly.
Verified: sveltekit workbench production build boots, serves
flow?__health (200), and start() runs execute with clean queue
deliveries. The chunk-patch regex fix from the previous commit stays as
hardening for any other CJS dependency that references __filename.
Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
* Update .changeset/fix-sveltekit-filename-chunk-patch.md
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
---------
Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
* Statically inject workflow world target
* Fix static world injection in host bundles
* Fix static world injection gaps
* Fix Vite Nitro server startup
* Fix Nitro pg-native aliasing
* Fix static world target CI gaps
* Fix static world dev rebuild gaps
* Avoid broad runtime alias in Nitro
* Refresh Next dev route for step HMR
* Externalize Nest target world
* Use canary HMR rediscovery timeout
* Bundle local world in Nest builds
* Dedupe world target helpers and fix SvelteKit chunk patch guard
* feat: enforce max queue deliveries in handlers with graceful failure
Replace VQS maxDeliveries cap with handler-level enforcement. Handlers
now gracefully fail runs/steps after excessive queue redeliveries,
preventing "phantom stuck" runs.
- Add MAX_QUEUE_DELIVERIES constant (64) and enforce in both workflow
and step handlers with run_failed/step_failed events
- Remove maxDeliveries from VQS trigger configs (builders + sveltekit)
- Improve world-local queue: safety limit loop, structured logging
with runId/stepId, backoff delay on failures
- Add MAX_DELIVERIES_EXCEEDED error code
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* address PR review comments
- Expand max-delivery comments explaining minimal-work approach
- Make workflow handler error message verbose (matching step handler)
- Fix comment: "consume the message silently"
- Reduce local queue safety limit from 1000 to 256
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* change MAX_QUEUE_DELIVERIES to 48 and use 5s linear backoff locally
VQS uses linear 5s backoff for attempts 1-32, then exponential capped
at 2h. At 48 attempts total elapsed time is ~20h, safely under the
24h message visibility limit. Local world now uses 5s linear backoff
to approximate VQS timing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Set maxDuration: "max" in vc-config for workflow functions
* Use maxDuration: 60 for flow route, "max" for step/webhook
* Remove explicit maxDuration from webhook route, rely on plan default
## Summary
When `WORKFLOW_PUBLIC_MANIFEST=1` is set, each framework builder exposes the workflow manifest at `/.well-known/workflow/v1/manifest.json` via the most appropriate mechanism for the framework:
- **Next.js**: Copies manifest to `public/.well-known/workflow/v1/manifest.json` (served as a static file)
- **SvelteKit**: Copies manifest to `static/.well-known/workflow/v1/manifest.json` (served as a static file)
- **Vercel Build Output API** (example workbench): Copies manifest to `.vercel/output/static/.well-known/workflow/v1/manifest.json` (served as a static file)
- **Nitro** (vite, hono, express, fastify, nuxt, nitro-v2, nitro-v3): Registers a virtual handler that reads and serves the manifest JSON
- **Astro**: Generates a `manifest.json.js` page route that returns the manifest JSON
- **NestJS**: Adds a `@Get('manifest.json')` endpoint on the `WorkflowController` (gated by the env var at runtime)
### Other changes
- `BaseBuilder.createManifest()` now returns the manifest JSON string so framework builders can use it
- Added `shouldExposePublicManifest` getter to `BaseBuilder`
- Fixed Astro `LocalBuilder` which was missing the `createManifest()` call that all other framework builders have
- Removed unused `public/` directory and static file copy from the example workbench build script
- Added `WORKFLOW_PUBLIC_MANIFEST` to `turbo.json` build task env so Vercel builds can access it
- Added generated manifest paths to `.gitignore`
Fixed a bug in module specifier resolution and added support for package subpath exports in workflow IDs.
### What changed?
- Fixed a caching bug in the module specifier resolution system that could cause incorrect IDs
- Added support for subpath exports in package IDs (e.g., `workflow/internal/builtins@4.0.0`)
- Improved module resolution by passing absolute file paths to the SWC transform
- Enhanced manifest merging to properly combine results from both workflow and step bundles
- Updated builders to return and merge manifests from both workflow and step bundles
### How to test?
1. Build a project that uses subpath exports in packages
2. Verify that workflow IDs correctly include the subpath (e.g., `workflow/internal/builtins@4.0.0`)
3. Test with a project that has multiple builds to ensure module specifier caching works correctly
### Why make this change?
This change addresses an issue where the module specifier cache could return incorrect results, leading to inconsistent workflow IDs. It also adds support for packages with multiple entry points through subpath exports, ensuring that steps with the same name in different subpaths don't collide. This improves the reliability of cross-bundle references and makes the system more robust when working with complex package structures.
nitro, sveltekit and astro and additional vite integrations will use `hotUpdate` for hmr in the future. this adds a `@workflow/vite` package to standardize hmr in workflows
* test: make dev e2e sequential
* test: increase timeout between tests in dev test
* add logs
* feat: add queue for builds
* refactor: cleanup vite hmr
* chore: cleanup comments
* fix: regex base builder
* test: reduce sleep time between test suites in dev test
* refactor: naming conventions and remove builder value check
* refactor: sveltekit builder queue
* changeset
* fix: regex on base builder workflow code
* test: increase sleep
* format
* fix: make writeFile atomic on workflow entrypoint
* refactor: move build queue to @workflow/builders
* revert: regex stuff with workflow code
* add console log for workflow file changed
* 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>
* feat: add type safety for builder configurations with discriminated unions
Improves type safety by creating discriminated union types for builder-specific
configurations, making it clear which configuration options are required for
each builder type.
Changes:
- Created BaseWorkflowConfig interface with common options
- Created StandaloneConfig, VercelBuildOutputConfig, and NextConfig types
- Made WorkflowConfig a discriminated union based on buildTarget
- Added documentation for each configuration type
- Exported new types from @workflow/builders
This enables better IntelliSense and type checking when constructing builder
configurations, preventing invalid configuration combinations at compile time.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* .
Signed-off-by: Nathan Rajlich <n@n8.io>
---------
Signed-off-by: Nathan Rajlich <n@n8.io>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Nathan Rajlich <n@n8.io>