* fix(world-local): prevent path traversal via request-supplied IDs
Request-supplied identifiers (runId, eventId, stepId, hookId, correlationId,
stream names, and tags) flowed directly into path.join() calls, allowing a
client to send values like '../../../package' and cause the backend to read
or write files outside the workflow data directory.
Add a centralized validator (assertSafeEntityId) that rejects IDs which are
empty, start with '.', or contain path separators or NUL bytes. Apply it at
each storage-layer entry point that composes IDs into filesystem paths:
fs.taggedPath / readJSONWithFallback / paginatedFileSystemQuery, the runs /
steps / events / hooks storage methods, and the streamer.
* address review feedback
- UnsafeEntityIdError now extends WorkflowWorldError for consistency with
other storage-layer errors and the platform error-to-HTTP mapping.
- Add resolveWithinBase(basedir, ...segments) containment helper and
apply it at every taggedPath / readJSONWithFallback / .locks path
construction site in events-storage and legacy, so a forgotten
assertSafeEntityId at a future call site can't silently regress.
- Truncate attacker-controlled values in the error message.
- Drop unused assertSafeEntityIds helper and the unreachable typeof
check under the TS signature.
- Fix docstrings on assertSafeEntityId / taggedPath JSDoc example /
filePrefix validation comment to match what the code actually does.
- handleLegacyEvent now re-asserts runId locally so the invariant is
documented at the call site instead of implicitly inherited from
events.create.
---------
Co-authored-by: JJ Kasper <jj@jjsweb.site>
* docs: tighten changeset description guidance in AGENTS.md
Specify that changeset descriptions should be one sentence (two at
most), and remove the redundant BREAKING CHANGE marker guidance since
breaking changes are already communicated via the major semver bump.
* docs: address Copilot review feedback
- Align command reference to `pnpm changeset add` (matching line 188)
- Drop the "see existing changesets for examples" parenthetical since
existing changesets predate the new sentence-limit guidance
A recurring Turbopack-on-Windows bug causes the dev server to enter a
'MODULE_UNPARSABLE' state during HMR in dev.test.ts, after which every
request returns 500. The remaining e2e suite then polls stuck workflows
for 60s each, burning the full 30-minute job window before getting
cancelled (~50% of recent main runs).
Bail out of the Windows e2e job as soon as dev.test.ts fails, and
health-check the dev server before kicking off test:e2e so any other
silent breakage is surfaced quickly instead of via a 30-minute timeout.
* refactor(next): remove step file copy mechanism from deferred builder
Step sources are now imported directly into the generated `step/route.js`
using the same `getImportPath`-based logic already used for serde files.
This is possible because the SWC plugin's client mode was merged into
step mode (#1686), so the workflow loader always runs in step mode and
transforms every file it sees, including those from packages.
Removed:
- `__workflow_step_files__/` per-file copies with hashed names, metadata
comments, inline source maps, and bare-specifier rewriting via
`enhanced-resolve`
- `createResponseBuiltinsStepFile`; builtins are now imported via
`require.resolve('workflow/internal/builtins')` at build time
- `step-copy-utils.ts` and all copy-specific branches in `loader.ts`
- `enhanced-resolve` dependency
The deferred builder still removes the legacy `__workflow_step_files__/`
directory on boot so upgrades leave no stale artifacts behind.
Dev tests that inspected copied step file contents now inspect the
manifest.json entries (which list every discovered step keyed by source
path).
* refactor(next): scrub historical phrasing from code comments
* test: update next step stack expectations
---------
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Matches the convention used by readableStreamWorkflow and webhookWorkflow.
The 60s budget is too tight when a single Vercel Queue delivery retry can
take 30-60s, causing intermittent flakiness on the nitro workbench.
Made-with: Cursor
The repo enforces "Commits must have verified signatures" via an
org/enterprise-level ruleset, which blocks unsigned commits pushed via
the Git CLI by GITHUB_TOKEN. Switching the changesets action to
commitMode: github-api makes commits GPG-signed by GitHub.
The Release App has been temporarily removed. Switch the Release and
Backport workflows to use the default GITHUB_TOKEN, and disable the
cross-repo Front dispatch workflow until the App is restored.
Also add a workflow_dispatch trigger to release.yml so the Version
Packages PR can be created/updated manually (since pushes made by
GITHUB_TOKEN do not trigger downstream workflow runs).
* Decode typed array stream chunks
* Render decoded stream bytes with raw view
* Render decoded bytes in data inspector
* Use generic byte inspector for streams
* review feedback: narrow stream-display exports, fix tab a11y, add collapseRefs tests
- Remove unused formatStreamChunkForDisplay/sanitizeStreamChunkForDisplay
exports; keep only the formatArrayBufferViewForDisplay path actually used
by DataInspector.
- Replace broken role=tablist/role=tab on the Decoded/Bytes switcher
with aria-pressed toggle-button semantics.
- Export collapseRefs/isBytesDisplay and add regression tests covering
typed-array detection (top-level, nested in object/array/Map/Set,
DataView exclusion).
* Replace eval with JSON.parse in serialization revive helper (#1848)
* Replace eval with JSON.parse in serialization revive helper
devalue.stringify() always produces valid JSON — special values
(undefined, NaN, Infinity, -0) are encoded as negative integer
sentinels. JSON.parse yields the same flattened array form that
unflatten() expects, without the eval anti-pattern (VULN-918).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Drop redundant workflow package from changeset
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* Add e2e test for UTF-8 parseable stream chunks
Emits Uint8Array chunks containing multi-byte UTF-8 (Latin Extended,
CJK, emoji, RTL Arabic) plus a UTF-8 encoded JSON document, and
asserts each chunk round-trips through TextDecoder({ fatal: true }).
Exercises the same decode path the web inspector relies on for
typed-array stream values.
Made-with: Cursor
---------
Co-authored-by: Pranay Prakash <pranay.gp@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Nitro users can declare packages as externals via
`externals: { external: ['fsevents'] }` in `nitro.config.ts`. Previously
the workflow SDK's step/workflow/webhook bundles were built in isolation
and ignored that config, forcing users to either patch the Nitro adapter
or ship a custom builder (as in the 250MB bundle-size workaround gist).
Forward string entries from `nitro.options.externals.external` to the
builder's esbuild `external` option. Only string entries are forwarded
— RegExp and function matchers aren't supported by esbuild's
`external` API, so those are skipped.
* fix(docs): highlight active top-bar nav item and drop duplicate keys
Match the current pathname (accounting for the hidden default locale)
and forward an `active` prop to the Radix NavigationMenuLink so the
selected top-bar item stays highlighted. Also remove module-level
`key` props from the intro Loading/Success/Error indicators — they
fired React's duplicate-key warning whenever two lines shared a state.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* update saga cookbook docs with adaptation guidance and streaming example
Made-with: Cursor
* docs(cookbook): rewrite core recipes, dedupe, reorder sidebar
Pass over the cookbook focused on correctness, concrete examples, and
tighter information architecture.
Rewrites:
- Saga / Batching / Scheduling: concrete use cases (order fulfillment,
CSV import, cancellable drip campaign); added "how it works" +
"adapting" sections.
- Durable Agent / Human-in-the-Loop / Stop Workflow: fixed broken
patterns (tool invocations don't stream before return; prepareStep
flag checks never fire); canonical single example per page.
- AI SDK integration: refocused from DurableAgent showcase to
streamText(); added multi-turn session pattern with durable stream
slicing, ai-sdk.dev deep links, and a pitfalls section.
- Sandbox integration: rewrote around the real @vercel/sandbox SDK;
flagship pattern is one workflow run = one persistent sandbox
session that outlives the 5-hour VM cap via snapshot rotation.
- Chat SDK integration: full rewrite — previous page documented AI
SDK's useChat, not chat-sdk.dev. New page covers durable chat
sessions, Mermaid flowchart, and cross-SDK serialization.
- Publishing Libraries: swapped ASCII tree for Fumadocs <Files>
(font-independent); corrected isomorphic guidance ("use workflow" /
"use step" are safe no-ops when SWC plugin doesn't process them);
added Mux AI and World ID adopter examples with canonical links.
Deletions (redundant or flawed):
- Fan-Out, Conditional Routing (covered by Batching / not a pattern).
- Tool Streaming, Tool Orchestration (covered by foundations/streaming
and ai/defining-tools).
- Durable Objects (hook-in-loop bug; framing doesn't hold up).
- Custom Serialization, Isomorphic Packages (merged into
foundations/serialization and publishing-libraries respectively).
Sidebar restructure:
- Reordered: Overview -> Agent Patterns -> Common Patterns ->
Integrations -> Advanced (Agent Patterns leads since it drives most
new-visitor traffic).
- Moved Child Workflows + Distributed Abort Controller from Common
Patterns to Advanced (composition / coordination concerns, not
common reliability recipes); permanent redirects added in
next.config.ts.
Made-with: Cursor
* docs(cookbook): rename Agent Stop Signal → Agent Cancellation, migrate common patterns
The agent cancellation page now covers two named patterns — Hard
Cancellation via getRun(runId).cancel() and Stop Signal via a hook +
Promise.race — so the prior "Agent Stop Signal" title biased toward only
one of them. Rename to the broader noun phrase and update the intro,
description, and section heading to frame both approaches equally.
Also migrate all patterns from foundations/common-patterns into dedicated
cookbook recipes (timeouts, sequential-and-parallel, workflow-composition)
and remove the foundations page. Permanent redirects added for the prior
URLs (stop-workflow, agent-stop-signal, foundations/common-patterns) so
no inbound link breaks.
Made-with: Cursor
* docs(cookbook): fix CI typecheck failures on three snippets
- publishing-libraries.mdx: the second processPayment snippet uses
getWorkflowRunId() defined in the prior block. Each block is type-checked
independently, so add @skip-typecheck (matches the existing pattern in
this file).
- ai-sdk.mdx: the "snapshot tailIndex first" pitfall is a fragment
referencing probe / turnHook / run / text from the surrounding multi-turn
pattern. Add @skip-typecheck.
- chat-sdk.mdx: the [platform] webhook route used Next.js 15 typegen
(RouteContext<"/api/webhooks/[platform]">), which isn't part of the
docs-typecheck environment. Switch to the manually-typed
{ params }: { params: Promise<{ platform: string }> } form — still fully
supported by Next.js 15+ and doesn't depend on .next/types.
Made-with: Cursor
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Replace eval with JSON.parse in serialization revive helper
devalue.stringify() always produces valid JSON — special values
(undefined, NaN, Infinity, -0) are encoded as negative integer
sentinels. JSON.parse yields the same flattened array form that
unflatten() expects, without the eval anti-pattern (VULN-918).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Drop redundant workflow package from changeset
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* ci: refactor wait-for-vercel-project to use GitHub Deployments API
Replaces the Vercel SDK / Vercel API token-based implementation with one
that resolves the deployment URL via the GitHub Deployments API:
- Find the GitHub Deployment for (target SHA, environment) where
environment matches the Vercel-app-created "Preview \u2013 <slug>" or
"Production \u2013 <slug>" naming pattern.
- Wait for the latest deployment status to be `success` (or `inactive`
when Vercel skips a duplicate build, in which case its environment_url
still points at the live deployment).
- Probe the URL to confirm the edge can route to it (any non-5xx
response counts as live, including 401/403 from Deployment Protection
and 404/405 from the app). Manual redirect handling treats redirects
to vercel.com as "still building".
- Resolve the dpl_xxx deployment ID from the matching commit status
(Vercel posts `Vercel \u2013 <slug>` statuses where target_url's last
path segment is the inspector ID == deployment ID without the prefix).
Inputs change: project-slug + bypass-secret + github-token (with
GITHUB_TOKEN default) replace team-id + project-id + vercel-token.
Removes the @vercel/sdk dependency, shrinking the bundled dist from
5.4MB to 829KB. The VERCEL_DOCS_TOKEN secret is no longer referenced
anywhere in the repo and can be deleted from GH after this lands.
* ci(wait-for-vercel-project): drop URL probe and bypass-secret input
The GitHub Deployment status transitions to `success` only after the
Vercel app finishes building and routing is live, so an extra HTTP
liveness probe of the deployment URL was redundant. Removing it lets
us also drop the bypass-secret input \u2014 protected deployments don't
need a workaround anymore because we never make the request.
Reduces the action surface area and eliminates a runtime fetch.
* ci(wait-for-vercel-project): address PR review
- Fail loudly when the dpl_xxx deployment ID can't be resolved instead
of returning an empty string. Consumers wire this into
VERCEL_DEPLOYMENT_ID, which world-target uses to pick between the
vercel and local worlds (packages/utils/src/world-target.ts), so an
empty value would silently flip execution mode.
- Pass the GitHub App token to wait-for-vercel-project in the dispatch
release workflow. The job sets `permissions: contents: read`, which
blocks the default GITHUB_TOKEN from reading the Deployments API.
The App token (already generated for workflow,front) has the
necessary scopes.
* test: enable step source-map assertions for vite local dev
Vite ^7.3.2 (bumped in #1827) preserves step bundle source maps in
dev mode, so stack traces now contain original file paths. Update
hasStepSourceMaps() so vite returns true in local dev and stays false
only in local prod, fixing the consistently failing 'basic step error'
and 'cross-file step error' e2e tests.
* chore: drop body from empty changeset
* address review: drop redundant vite local-prod guard
The default `!DEV_TEST_CONFIG` fall-through already returns false for
vite local prod, so the vite-specific guard is dead code. Just remove
the vite block entirely now that vite local dev matches the default
'has source maps' behavior.
* ci: fix VERCEL_WORKFLOW_SERVER_* ternary so main actually unsets them
In GitHub Actions expressions, '' is falsy, so the original
`cond && '' || secrets.X` pattern always fell through to the secret
regardless of branch. The result was that pushes to main were sending
preview workflow-server values to production, causing 'invalid_url'
errors on `x-vercel-workflow-api-url` across all e2e jobs.
Flip the condition so the secret sits in the truthy branch and ||
correctly selects '' on main.
* ci: skip pnpm cache in matrix-generation jobs
The Get Test Matrix and Get Community Worlds Matrix jobs only run a
small Node script to emit a JSON matrix; they never run `pnpm install`.
With `cache: 'pnpm'` set on actions/setup-node, the post-job cache save
step fails with 'Path Validation Error' because the pnpm store path was
never created, marking the whole job as failed.
Add a cache-pnpm input to setup-workflow-dev (default true) and opt out
in the two matrix-generation jobs.
* CI script improvements
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* address codex feedback: harden remaining workflows
- add allowlist regex in prepare-workbench-path to block path traversal
- move matrix/input values to env vars across e2e-vercel-prod,
benchmarks (local/postgres/vercel), and the reusable community-world
workflows
- validate app-name/world-id/world-package inputs in the reusable
community-world workflows
- pipe getCommunityWorldsMatrix script output through jq -c to prevent
\$GITHUB_OUTPUT injection
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* feat(world-vercel): support WORKFLOW_VERCEL_PROTECTION_BYPASS env var
Allows sending a Vercel Deployment Protection bypass secret via the
`x-vercel-protection-bypass` header on all outbound requests made by
the Vercel world, enabling use against protected deployments (e.g.
previews, or workflow-server once protection is enabled).
* feat(world-vercel): support VERCEL_WORKFLOW_SERVER_URL env var
Replace hard-coded WORKFLOW_SERVER_URL_OVERRIDE constant with a function
that reads from the VERCEL_WORKFLOW_SERVER_URL env var. Allows configuring
the workflow-server URL per-deployment (e.g. workbench Preview envs
pointing to a branch deployment) without editing source.
* fix(world-vercel): preserve inline WORKFLOW_SERVER_URL_OVERRIDE const
Keep the inline const as an empty-string literal so external CI rewrite
tooling continues to work unmodified; the env var is a fallback when the
inline value is empty.
* refactor(world-vercel): rename to VERCEL_WORKFLOW_SERVER_PROTECTION_BYPASS
Align env var naming with VERCEL_WORKFLOW_SERVER_URL.
* ci: expose workflow-server protection bypass env vars to e2e-vercel-prod
Set VERCEL_WORKFLOW_SERVER_URL and VERCEL_WORKFLOW_SERVER_PROTECTION_BYPASS
on PR runs so e2e tests hit the protected workflow-server preview; leave
unset on main so production runs use the public default URL.
* refactor(world-vercel): address PR review comments
- Consolidate bypass header logic in getHeaders() to reuse
getProtectionBypassHeader() instead of duplicating env lookup.
- Use consistent 'Authorization' casing in direct fetch() calls.
- Add unit tests for getProtectionBypassHeader, getHttpUrl, and getHeaders
covering env var toggling and proxy/override combinations.
Throw a FatalError at the top of fibonacciWorkflow if n is not a finite
number. Prevents a runaway recursion if the workflow is ever invoked
without its numeric argument — NaN - 1 === NaN, NaN <= 1 === false, so
the base case would never fire and every descendant would spawn two
more children.
* feat: add distributed abort controller guide and implementation
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
* feat: implement abort signal step function and refactor workflows to use it
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
* feat: enhance distributed abort controller with user-provided ID
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
* feat: enhance distributed abort controller with TTL and reconnection logic
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
* feat: add grace period to abort controller workflow
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
* feat: add distributed abort controller workflow and tests
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
* add the pattern to the sidebar
* fix: correct start() call signature and run.id → run.runId
start() takes args as a positional second argument, not an options
object property. The Run object exposes runId, not id.
Made-with: Cursor
* fix: address PR review comments on distributed abort controller
- Make abort() idempotent by catching hook-not-found/expired errors
- Add error handling to signal getter's stream reader IIFE
- Fix tests: use instance methods instead of non-existent static
methods, pass required ttlMs/graceMs args, include expired field
in assertions
Made-with: Cursor
* fix: add missing import to Custom TTL docs code sample
The docs typecheck runs each code block in isolation. The Custom TTL
example was missing the DistributedAbortController import.
Made-with: Cursor
* fix: only sleep grace period on TTL expiration, not manual abort
Manual aborts now complete immediately instead of sleeping through
the full TTL + grace period. This fixes vitest timeouts where all
3 distributed-abort-controller tests exceeded the 30s limit.
Made-with: Cursor
* fix: wait for hook registration before aborting in test
The DistributedAbortController instance test was timing out because
abort() was called before the workflow had registered the hook. The
idempotent catch silently swallowed the "not found" error, leaving the
workflow running forever.
- Make runId readonly (was private) so tests can access it
- Add waitForHook(getRun(controller.runId)) before controller.abort()
Made-with: Cursor
* fix: apply conditional grace period to E2E workflow copy
The distributedAbortControllerWorkflow in 99_e2e.ts had the same
unconditional grace sleep bug, causing the reconnect test to timeout
at 60s while waiting ~66s for the grace period after manual abort.
Made-with: Cursor
---------
Co-authored-by: v0 <v0[bot]@users.noreply.github.com>
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
Co-authored-by: Karthik Kalyanaraman <karthik.kalyanaraman@vercel.com>
* ci: auto-resolve skills/ conflicts in backport to stable
The skills/ directory is not maintained on the stable branch (skill
files are unrelated to npm packaging). Extend the backport workflow's
auto-resolution — and the AI-assisted fallback prompt — to treat
skills/ conflicts the same way docs app conflicts are handled: keep
the stable side and drop the incoming change from main.
Also updates AGENTS.md to document which directories are stable-only
placeholders and how the backport action handles them.
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Nathan Rajlich <n@n8.io>
---------
Signed-off-by: Nathan Rajlich <n@n8.io>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* feat: allow start() to be called directly inside workflow functions
Add 'use step' to start() so it can be called directly from workflow
code. The SWC compiler strips the function body in workflow mode and
replaces it with a step proxy. When called from a workflow:
1. The workflow function reference is serialized via WorkflowFunction
reducer (serializes { workflowId })
2. start() executes in the step context with full Node.js access
3. The returned Run is serialized via WORKFLOW_SERIALIZE and deserialized
back in the workflow VM
4. Run getters (.status, .returnValue, etc.) are 'use step' getters
that each execute as separate steps
Also re-exports start from @workflow/core/runtime/start in api-workflow.ts
instead of using a throwing stub, adds e2e tests for startFromWorkflow
(with hook communication) and fibonacciWorkflow (recursive composition).
* fix(next): don't copy package step files in deferred builder to avoid duplicate classes
Files belonging to packages (detected by walking up to find a
package.json with a name field) are imported via relative path
instead of being copied to __workflow_step_files__/. Copying creates
a second module instance which breaks JS native private field (#)
brand checks when the runtime creates instances from one copy and
the step handler accesses fields from the other.
* fix(next): only skip copying package files that are serde classes, not all package step files
Regular package step files (like fetch) must still be copied to ensure
the SWC loader registers them. Only serde class files from packages are
excluded from copying since those define classes with JS native private
fields (#) that break when duplicated.
* fix(next): generate thin wrappers for package serde step files instead of full copies
For package files that define serde classes (like Run), generate a thin
wrapper that imports the original class and registers steps/classes from
the manifest. This avoids duplicating the class definition (which breaks
JS native private field brand checks) while still registering all step
functions and the class in the serialization registry.
Regular package step files (like fetch) are still copied as before.
* fix(next): use forceStepModeFiles to transform package serde files in step mode
Instead of copying package serde+step files (which creates duplicate
classes with #private brand check issues) or generating fragile wrappers,
add the original file paths to a shared forceStepModeFiles set. The
loader checks this set and transforms those files in step mode directly,
so the SWC plugin generates proper step registrations on the original
class — no duplication, no reimplemented registration logic.
* fix(next): use step mode for all files with step/serde patterns, not just copies
The loader now selects step mode for any file that has 'use step'
directives or serde patterns, regardless of whether it's a deferred
step copy. Step mode is a superset of client mode — the only addition
is step registry IIFEs, which are harmless for non-step consumers.
This means package serde+step files (like Run) no longer need to be
copied to get step registrations. They're imported directly in the
step route and the loader transforms the original file in step mode.
One class instance, no duplication, no wrapper generation.
---------
Co-authored-by: Nathan Rajlich <n@n8.io>
* Prefer stable version for docs app conflicts in backport workflow
After #1786 restored a minimal Next.js placeholder docs app on stable,
docs app conflicts should resolve to the stable branch version rather
than being deleted. Only docs/content/ is actively maintained on stable,
so conflicts there should still be resolved normally.
Update both the auto-resolution logic in backport.yml and the AI prompt
to reflect the new policy, and update AGENTS.md to match.
* Use git show :2:$file to detect ours-side presence in conflicts
git ls-files --error-unmatch succeeds for unmerged paths even when
the file only exists on the incoming (theirs) side, which would then
fail on git checkout --ours. Use git show :2:$file to specifically
check for a stage-2 entry, which indicates the file exists on the
ours (stable) side.
* ci: upgrade pnpm/action-setup to v6 and read version from package.json
Removes hardcoded pnpm version (10.14.0) from all workflows and instead
reads the version from the packageManager field in package.json, so CI
stays in sync with the version used locally.
* ci: update setup-workflow-dev composite action to use pnpm/action-setup@v6
Also removes the pnpm-version input since the action now reads the
version from package.json#packageManager.
* ci: downgrade pnpm/action-setup to v5
v6 installs pnpm 11 RC/beta, which has a regression
(pnpm/pnpm#11264, pnpm/action-setup#225/#227/#228) that causes
'ERR_PNPM_BROKEN_LOCKFILE: expected a single document in the stream'
when the project's packageManager pins a 10.x pnpm version. v5 is the
latest stable release before v6 and supports reading the version from
package.json#packageManager.
* refactor(swc-plugin): remove client transform mode, merge into step mode
Remove the `client` transform mode from the SWC compiler plugin. The
`client` and `step` modes were nearly identical — both preserved step
function bodies, replaced workflow bodies with throw stubs, and emitted
the same JSON manifest. Step mode now absorbs all client-mode behaviors:
- Dead code elimination (previously only workflow + client)
- Hoisted variable references for object property steps
- All integrations use mode: 'step' instead of 'client'
BREAKING CHANGE: The `client` value for the SWC plugin `mode` option is
no longer accepted. Use `step` instead.
* fix(nitro): force-inline workflow packages in dev mode for serde classId registration
In dev mode, Nitro's Rollup externalizes npm packages like @workflow/core,
so the SWC transform plugin never processes files like run.js. This means
serde classes (e.g. Run) never get the classId registration IIFE, causing
serialization failures when step functions return Run instances.
Uses a Rollup resolveId hook to force workflow SDK packages to be bundled
(non-external) while leaving all other dependencies external. This is more
targeted than noExternals=true which bundles everything and causes TDZ
errors from circular imports in packages like vue-bundle-renderer/h3.
The Nitro module now also ignores .nitro/workflow/** in watchOptions so
writing generated workflow bundles does not retrigger Nitro's own dev
bundle rebuild loop.
Also wraps dev:reload workflow rebuilds and makes LocalBuilder.build()
atomic (writes to temp files, renames on success) to avoid partial output
state during HMR.
For Nuxt, also configures Vite's ssr.noExternal to bundle workflow
packages in the SSR context.
* fix(nitro,nuxt): address review feedback on dev-mode classId fix
- nitro builders: use crypto.randomUUID() for temp file suffix instead of
Date.now() to avoid collisions under rapid/concurrent build() calls,
and serialize concurrent build() calls through an internal queue so
two overlapping dev rebuilds cannot clobber each other's temp outputs.
- nitro index: use fileURLToPath() to convert file:// URLs to filesystem
paths, which correctly handles Windows paths (file:///C:/... -> C:\...)
and percent-decoding, instead of relying on new URL(...).pathname.
- nuxt module: normalize vite.ssr.noExternal to an array (preserving any
existing string/RegExp/array entry) before appending workflow package
matchers, so the force-bundle behavior is not a no-op when noExternal
is already set to a non-array value.
* Auto-resolve docs/ and pnpm-lock.yaml conflicts in backport workflow
The docs/ directory is not maintained on the stable branch. When cherry-picking
from main to stable, any conflicts in docs/ files are now auto-resolved by
deleting them. Lockfile conflicts are resolved by re-running pnpm install.
If these resolve all conflicts, the cherry-pick pushes directly to stable
without needing AI resolution or a separate PR.
* Add --signoff to cherry-pick to pass DCO check
* Preserve docs/content/ in backport conflict resolution
The docs/content/ directory is kept on stable because the markdown
files are bundled into npm packages via prepack scripts. Update the
conflict auto-resolution to only delete docs app files (outside of
docs/content/), and update AGENTS.md accordingly.
* Address review: setup pnpm before cherry-pick, fix grep pipefail, guard lockfile resolution
- Move pnpm/node setup before the cherry-pick step so pnpm install
is available during conflict resolution
- Add || true to the docs grep pipeline to prevent pipefail exit
when there are no non-content docs conflicts
- Only run pnpm install for lockfile conflicts when no other
conflicts remain, to avoid choking on conflict markers
* Let pnpm resolve lockfile conflicts natively
* Remove redundant Setup Node.js step for opencode path
Node.js is now set up unconditionally at the start of the job for
the cherry-pick step's pnpm install, so the conditional setup for
the opencode path is redundant.
* fix(swc-plugin): preserve step function names in stack traces after bundler minification
Add Object.defineProperty(fn, 'name', { value, configurable: true }) to the
IIFE step registration so the original function name survives bundler name
mangling (e.g. Turbopack renaming errorStepFn to eD). V8 uses the .name
property for stack traces, so this ensures 'at errorStepFn (...)' appears
instead of 'at eD (...)'.
* Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Nathan Rajlich <n@n8.io>
---------
Signed-off-by: Nathan Rajlich <n@n8.io>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refine homepage: simplify feature grid, update templates section
Remove "Zero infrastructure management", "Deploy confidently", "No timeout
limits", and "Pay for what you use" sections from the feature grid. Update
the observability section with new copy, larger typography, and CTA buttons
for Vercel and self-hosting. Redesign the templates section with a
side-by-side layout, "All examples" button, and vercel.com/workflow card
images with dark mode support.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: christopherkindl <53372002+christopherkindl@users.noreply.github.com>
* Make observability CTA buttons stack vertically on mobile
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: christopherkindl <53372002+christopherkindl@users.noreply.github.com>
* Add Vercel section with o11y dashboard, update homepage layout
- Add O11yDashboard SVG component with Vercel dashboard preview
showing sidebar nav and observability trace visualization
- Add VercelSection with desktop (offset right) and mobile views
- Update "Run anywhere" section with new copy and CTA buttons
- Normalize all grid section buttons to h-10
- Fix mobile padding in UseCases section
- Remove barrel file for vercel-com-visuals, use direct imports
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: christopherkindl <53372002+christopherkindl@users.noreply.github.com>
* Make use-case selector inline on mobile
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: christopherkindl <53372002+christopherkindl@users.noreply.github.com>
---------
Signed-off-by: christopherkindl <53372002+christopherkindl@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enable TypeScript inlineSources in the shared package tsconfig so published @workflow packages ship self-contained JavaScript sourcemaps. This fixes Vite and Vitest warnings in downstream repos when sourcemaps point at ../src/*.ts paths that are not published.
* [docs] Rename workflowdevkit references to workflowsdk
* [docs] Rename useworkflow.dev to workflow-sdk.dev
* [chore] Add changeset for domain rename
* [docs] Revert sitemap rewrite to useworkflow.dev (crawled-sitemap not yet available for new domain)