Commit Graph

994 Commits

Author SHA1 Message Date
Nathan Rajlich ba916e1566 Add DOMException to VM context and first-class serialization support (#1512)
- Pass DOMException through to the workflow VM context alongside other
  Web APIs (Headers, URL, TextEncoder, etc.)
- Add DOMException reducer/reviver to the serialization pipeline,
  preserving message, name, derived code, and cause when present
- Add DOMException to the Serializable type union
- 8 new tests: round-trip for AbortError, NotFoundError, default name,
  cause preservation, cause absence, serialization key, cross-VM
  boundaries, and VM context availability
2026-04-06 06:10:30 +00:00
workflow-devkit-release-bot[bot] 29fe9ded57 Version Packages (beta) (#1600) 2026-04-03 17:05:54 -07:00
Peter Wielander ab872cc9fb [core] Make registeredSteps a global singleton to protect against module duplication (#1606) 2026-04-03 21:53:58 +00:00
Gregor Martynus e9ebe8faa3 [ai] Preserve reasoning content in DurableAgent conversation history (#1444)
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-04-03 14:42:10 -07:00
Nathan Rajlich f5d2aef58f Add serde compliance tooling and improve custom class serialization DX (#1552)
* Add serde compliance tooling and update skill documentation

- Add serde compliance checker library to @workflow/builders
- Add build-time warnings for serde classes with Node.js imports in workflow bundle
- Add 'workflow transform' CLI command for inspecting SWC output
- Implement 'workflow validate' CLI command with serde compliance checks
- Add serde analysis panel to SWC playground
- Update workflow skill with custom class serialization documentation

* Fix --json + --strict: use process.exitCode so JSON output is returned before exit

* Address code review feedback

- Fix --strict exit code: honor process.exitCode in BaseCommand.finally()
- Remove unused --module-specifier flag from transform command
- Add missing Node.js builtins (e.g. test) to playground detection list
- De-dupe build-time serde warnings by grouping identical issues across classes
- Make Serde Analysis panel collapsible like the output panels

* Use .gitignore for validate file discovery; fix changeset wording
2026-04-03 21:03:59 +00:00
Peter Wielander d8aaf27c79 [core] Enforce single ALS context to protect against duplicate module and caching issues (#1591) 2026-04-03 13:47:19 -07:00
Nathan Rajlich 7c996a76c5 fix(swc-plugin): rewrite anonymous export default class to const declaration (#1601)
* fix(builders): override sideEffects:false for discovered workflow/step/serde entries

When node_modules packages include "sideEffects": false in their
package.json, esbuild drops bare imports from the virtual-entry.js
file. This is incorrect because the SWC compiler transform injects
side-effectful registration code (workflow IDs, step IDs, class
serialization) into these modules.

Fix: return the resolved path alongside sideEffects: true from the
onResolve handler so esbuild uses the plugin's resolution result
instead of re-reading the package.json.

* refactor(builders): normalize sideEffectEntries with realpaths for symlink compatibility

Extract withRealpaths() helper and use it for both normalizedEntriesToBundle
and sideEffectEntries at all three bundle sites. This ensures the
sideEffects override works correctly under pnpm/workspace symlinked
layouts where enhanced-resolve may return realpaths that differ from
the original discovered file paths.

* perf(builders): skip enhanced-resolve for transitive imports when only sideEffectEntries is set

When entriesToBundle is not set (workflow/client bundles), only top-level
import statements need the sideEffects override — transitive imports
from deep within the bundle are not bare imports and don't need resolution.
Skip enhanced-resolve for non-import-statement kinds to reduce overhead.

* fix(swc-plugin): use binding name for class expression method registrations

When a pre-bundled package (e.g. via tsup) contains class expressions
like `var Foo = class _Foo { ... }`, the internal name `_Foo` is only
scoped inside the class body. The SWC plugin was incorrectly using the
internal name for method step registrations and class serialization
registrations emitted at module scope, causing ReferenceError at runtime.

Fix: always use the binding name (registration_name) for
current_class_name in visit_mut_class_expr, consistent with the existing
handling for anonymous class expressions. This ensures:
- registerStepFunction calls reference the binding name (Foo)
- Only one class registration IIFE is emitted (not duplicates for both
  Foo and _Foo)
- Step IDs use the binding name in their qualified path

* refactor(swc-plugin): rename internal_class_name to tracked_class_name for clarity

The variable no longer represents the internal class expression identifier
after being reassigned to the binding name. Rename to tracked_class_name
and eliminate the intermediate registration_name variable to make the
intent clearer and reduce confusion for future readers.

* fix(swc-plugin): rewrite anonymous export default class to const declaration

When an anonymous class with serde/step methods is exported as a default
export (`export default class { ... }`), the generated registration code
(registerStepFunction, class registry IIFE) would reference a nonexistent
variable at module scope, causing a ReferenceError at runtime.

Fix: detect anonymous default class exports in visit_mut_export_default_decl
and visit_mut_export_default_expr, generate a unique binding name
(__defaultClass), and defer a rewrite in visit_mut_module_items that
transforms the export into:
  const __defaultClass = class __defaultClass { ... };
  export default __defaultClass;

Named default class exports (export default class Foo { ... }) are
handled by setting current_class_binding_name so the transformer
uses the existing class name for registration code.

* refactor(swc-plugin): rename __defaultClass to __DefaultClass for class naming convention

* fix(swc-plugin): fix panic for step-only anonymous default class exports

Address review feedback:
- Remove expect() that panicked when anonymous default class had step
  methods but no serde methods (ident was not re-inserted). Keep
  const_name in a local variable instead of relying on class_expr.ident.
- Add debug_assert for single default class export invariant.
- Update spec.md and test fixture inputs to use new this() instead of
  referencing the generated binding name.
- Add step-only anonymous default class fixture to cover the bug path.

* refactor(swc-plugin): address review feedback for export default class handling

- Remove dead Expr::Class handler in visit_mut_export_default_expr
  (SWC wraps parenthesized form in Expr::Paren, so it never fires)
- Extract class_needs_binding_rewrite() helper, eliminating duplicated
  detection logic and unnecessary body clones
- Add debug_assert for mutual exclusivity of default_workflow_exports
  and default_class_exports
- Clarify spec.md on self-name behavior difference between serde and
  step-only classes
2026-04-03 19:54:20 +00:00
Peter Wielander b30b0dcab6 [world] Asymmetric ULID timestamp validation thresholds (#1605) 2026-04-03 12:54:09 -07:00
Pranay Prakash d1330cfebc Fix node-module-error plugin matching identifiers in multi-line comments (#1554)
* Fix node-module-error plugin matching identifiers in multi-line comments

The findIdentifierUsage function only stripped single-line comments and
same-line block comments, but didn't track multi-line block comment state.
Lines inside JSDoc/block comments (e.g. ` * ... Writable stream`) passed
through unstripped, causing the plugin to point at comments instead of
actual code usage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Strip string literals before scanning for comment delimiters

Move string stripping before comment detection so that comment delimiters
inside string literals (e.g. `const s = "/*"`) don't incorrectly trigger
block comment mode. Adds regression test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-04-03 11:55:11 -07:00
Nathan Rajlich 5d22e61446 fix(swc-plugin): use binding name for class expression method registrations (#1599)
* fix(builders): override sideEffects:false for discovered workflow/step/serde entries

When node_modules packages include "sideEffects": false in their
package.json, esbuild drops bare imports from the virtual-entry.js
file. This is incorrect because the SWC compiler transform injects
side-effectful registration code (workflow IDs, step IDs, class
serialization) into these modules.

Fix: return the resolved path alongside sideEffects: true from the
onResolve handler so esbuild uses the plugin's resolution result
instead of re-reading the package.json.

* refactor(builders): normalize sideEffectEntries with realpaths for symlink compatibility

Extract withRealpaths() helper and use it for both normalizedEntriesToBundle
and sideEffectEntries at all three bundle sites. This ensures the
sideEffects override works correctly under pnpm/workspace symlinked
layouts where enhanced-resolve may return realpaths that differ from
the original discovered file paths.

* perf(builders): skip enhanced-resolve for transitive imports when only sideEffectEntries is set

When entriesToBundle is not set (workflow/client bundles), only top-level
import statements need the sideEffects override — transitive imports
from deep within the bundle are not bare imports and don't need resolution.
Skip enhanced-resolve for non-import-statement kinds to reduce overhead.

* fix(swc-plugin): use binding name for class expression method registrations

When a pre-bundled package (e.g. via tsup) contains class expressions
like `var Foo = class _Foo { ... }`, the internal name `_Foo` is only
scoped inside the class body. The SWC plugin was incorrectly using the
internal name for method step registrations and class serialization
registrations emitted at module scope, causing ReferenceError at runtime.

Fix: always use the binding name (registration_name) for
current_class_name in visit_mut_class_expr, consistent with the existing
handling for anonymous class expressions. This ensures:
- registerStepFunction calls reference the binding name (Foo)
- Only one class registration IIFE is emitted (not duplicates for both
  Foo and _Foo)
- Step IDs use the binding name in their qualified path

* refactor(swc-plugin): rename internal_class_name to tracked_class_name for clarity

The variable no longer represents the internal class expression identifier
after being reassigned to the binding name. Rename to tracked_class_name
and eliminate the intermediate registration_name variable to make the
intent clearer and reduce confusion for future readers.
2026-04-03 18:36:27 +00:00
Nathan Rajlich 443a9e62f9 fix(builders): override sideEffects: false for discovered workflow/step/serde entries (#1598)
* fix(builders): override sideEffects:false for discovered workflow/step/serde entries

When node_modules packages include "sideEffects": false in their
package.json, esbuild drops bare imports from the virtual-entry.js
file. This is incorrect because the SWC compiler transform injects
side-effectful registration code (workflow IDs, step IDs, class
serialization) into these modules.

Fix: return the resolved path alongside sideEffects: true from the
onResolve handler so esbuild uses the plugin's resolution result
instead of re-reading the package.json.

* refactor(builders): normalize sideEffectEntries with realpaths for symlink compatibility

Extract withRealpaths() helper and use it for both normalizedEntriesToBundle
and sideEffectEntries at all three bundle sites. This ensures the
sideEffects override works correctly under pnpm/workspace symlinked
layouts where enhanced-resolve may return realpaths that differ from
the original discovered file paths.

* perf(builders): skip enhanced-resolve for transitive imports when only sideEffectEntries is set

When entriesToBundle is not set (workflow/client bundles), only top-level
import statements need the sideEffects override — transitive imports
from deep within the bundle are not bare imports and don't need resolution.
Skip enhanced-resolve for non-import-statement kinds to reduce overhead.
2026-04-03 18:11:37 +00:00
Karthik Kalyan 760ebf161b [world-vercel] align header names to x-vercel-workflow-* convention (#1602)
* update x-vercel-workflow-run-id and x-vercel-workflow-step-id

* Update dark-olives-fix.md

Signed-off-by: Karthik Kalyan <105607645+karthikscale3@users.noreply.github.com>

---------

Signed-off-by: Karthik Kalyan <105607645+karthikscale3@users.noreply.github.com>
2026-04-03 10:35:22 -07:00
Pranay Prakash 047c01bc15 Make start() types unknown when deploymentId is provided (#1367)
* fix: update types and documentation for start function overloads

Ensure types are 'unknown[]' and 'unknown' for 'deploymentId' and update exports and documentation.

Slack-Thread: https://vercel.slack.com/archives/C09G3EQAL84/p1773368990070059?thread_ts=1773368990.070059&cid=C09G3EQAL84
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>

* fix: use generics in deploymentId overloads to avoid contravariance issue

Addresses PR review feedback: typed workflows like
WorkflowFunction<[string], number> were not assignable to
WorkflowFunction<unknown[], unknown> under strictFunctionTypes.
Changed to generic parameters while keeping Run<unknown> return type.
Also adds type-level tests for overload resolution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: add changeset for start() deploymentId type changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: v0 <v0[bot]@users.noreply.github.com>
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 19:52:47 -07:00
Nathan Rajlich 44290785e1 fix(next): stop force-setting WORKFLOW_PUBLIC_MANIFEST=1 during next dev (#1597) 2026-04-02 22:49:14 +00:00
workflow-devkit-release-bot[bot] 45fd831b1d Version Packages (beta) (#1593) 2026-04-02 21:25:14 +00:00
Peter Wielander 136c1f4e97 [docs] Tidy world API docs and document new stream helpers (#1581) 2026-04-02 20:08:51 +00:00
Nathan Rajlich 7e33c62736 Rename 'Workflow Development Kit' / 'DevKit' to 'Workflow SDK' (#1595)
* Rename 'Workflow Development Kit' / 'DevKit' to 'Workflow SDK' across docs, code, and config

Follow-up to cdf90d5a38 (#1541)

* Fix missing </h1> closing tag and add article 'the' before 'Workflow SDK' in docs
2026-04-02 19:39:02 +00:00
Peter Wielander ef2218ab22 [world] Use zod/v4 in queue files to match @workflow/world schemas (#1588) 2026-04-02 12:38:13 -07:00
Peter Wielander c0f07a985c [ai] Fix fatal stream errors surfacing as [object Object] (#1589) 2026-04-02 12:37:15 -07:00
Peter Wielander 74c4cdb651 [web] Fix server crash on unmatched routes (#1590) 2026-04-02 10:57:41 -07:00
workflow-devkit-release-bot[bot] 8462c5df89 Version Packages (beta) (#1563) 2026-04-01 16:08:49 -07:00
Peter Wielander 6dc1b78582 [core] Extend flow route duration to "max" and fail runs where replay takes too long (#1567) 2026-04-01 21:33:39 +00:00
Nathan Rajlich d38114bff1 fix: check target run capabilities before encrypting hook payloads (#1572)
* fix: check target run capabilities before encrypting hook payloads

When resumeHook()/resumeWebhook() is called on a newer deployment that
supports encryption, it would encode the payload with the 'encr' format.
If the target workflow run was created by an older deployment that
predates encryption support, the run would fail with:
  Error: Unknown serialization format: "encr". Known formats: devl

Add a capabilities table that maps @workflow/core versions to supported
serialization formats. Before encoding, resumeHook() now checks the
target run's workflowCoreVersion and suppresses encryption when the
run's deployment doesn't support it.

* address review: guard against invalid/non-string workflowCoreVersion

- Validate with semver.valid() before comparing, falling back to
  baseline formats for malformed version strings
- Add typeof guard at the call site in resumeHook() since
  executionContext is Record<string, any>
- Add tests for invalid version strings (dev, empty, partial, etc.)
- Add encryption commit reference to capabilities module header
2026-04-01 21:32:51 +00:00
Peter Wielander a98f8de53f [core] Combine initial run fetch, event fetch, and run_started event creation (#1569) 2026-04-01 14:23:29 -07:00
Lucas Ralph e574ad2107 [docs] Split World API docs into sub-pages, update skill.md (#1457)
Signed-off-by: Lucas Ralph <lucas.ralph@vercel.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-04-01 09:39:22 -07:00
comfuture 0e8a880b6b [nitro] Preserve workflow step registration side effects (#1386)
In Nitro/Nuxt local production builds, the generated workflow/steps.mjs bundle could be treated as a pure export provider when the virtual handler only imports { POST }. That allowed the step bundle's top-level registerStepFunction(...) calls to disappear from the final Nitro server bundle, which led to runtime failures like Step \"...\" not found when a queued step executes.

Signed-off-by: comfuture <comfuture@gmail.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-04-01 09:28:47 -07:00
Peter Wielander 329cdb3e1b [world] Re-enqueue active runs on world restart (#1534) 2026-03-30 13:48:09 -07:00
workflow-devkit-release-bot[bot] 91ba457764 Version Packages (beta) (#1550) 2026-03-30 13:42:22 -07:00
Karthik Kalyan c488877727 [web] Switch web package stream reader to getStreamChunks (#1542)
* fix: switch web stream reader from readFromStream to getStreamChunksix

* add decrypt button for stream

* add decrypt button for stream

* add polling for streams tab

* add polling for streams tab

* add jsdoc

* address review comments
2026-03-30 13:11:49 -07:00
Nathan Rajlich 4f646e3d58 Polyfill TC39 Uint8Array base64/hex methods in workflow VM context (#1547)
* Polyfill TC39 `Uint8Array` base64/hex methods in workflow VM context

* Replace `declare global` with local type interfaces to avoid type leakage

* Document Uint8Array base64/hex methods in Workflow Globals page
2026-03-30 19:50:08 +00:00
Peter Wielander d119c740d0 [builders] Fix import.meta.url missing when using CJS (#1509) 2026-03-30 12:18:39 -07:00
Peter Wielander bd1f7e4b4c [world-local] Tidy stream chunk list code (#1494) 2026-03-30 12:15:11 -07:00
Peter Wielander a3b7c480e0 [builders] Scope .ts→.js extension rewriting to vitest only (#1560) 2026-03-30 11:37:17 -07:00
Nathan Rajlich 1885c4a9f4 Fix flaky tests by replacing setTimeout with deterministic awaits (#1551)
Replace fragile setTimeout-based waits in sleep, step, and
events-consumer tests with withResolvers/vi.waitFor patterns,
following the approach established in #1347.
2026-03-30 11:23:25 -07:00
Nathan Rajlich 781d64b737 Move SWC playground to client-side WASM and add Monaco type intellisense (#1553)
* Move SWC playground transform from server action to client-side WASM

Create a new swc-playground-wasm crate that bundles swc_ecma_parser,
swc_ecma_codegen, and the swc_workflow transform visitor into a single
WASM binary via wasm-bindgen/wasm-pack. This runs the code
transformation entirely in the browser, eliminating the server action
round-trip and serverless function cold starts on every keystroke.

- New packages/swc-playground-wasm Rust crate targeting wasm32-unknown-unknown
- Exposes transform() and transformAll() functions via wasm-bindgen
- Client loads WASM + JS glue from public/wasm/ as static assets
- Removed @swc/core and @workflow/swc-plugin server-side dependencies
- Removed serverExternalPackages/outputFileTracingIncludes Next.js config
- Added WASM loading indicator and error state in the UI
- Reduced transform debounce from 500ms to 300ms (no network latency)

* Add missing extends key to swc-playground-wasm turbo.json

* Fix build: ensure rustup is available for wasm32-unknown-unknown target

The Vercel build environment has a system Rust without rustup, so
the wasm32-unknown-unknown target can't be managed. Now the build
script checks for rustup specifically (not just cargo) and installs
it when missing, matching the pattern in swc-plugin-workflow/build.js.

* Add workflow type definitions to Monaco editor for intellisense

Auto-generate type declarations from built .d.ts files of workflow,
@workflow/core, @workflow/errors, @workflow/world, and @workflow/utils
packages. Register them with Monaco's TypeScript language service via
addExtraLib() so imports like 'workflow' resolve with full types,
eliminating red squiggles and enabling autocomplete/hover info.

* Fix Monaco type resolution: register root index.d.ts for each package

Monaco's NodeJs module resolution looks for index.d.ts at the package
root, not just in dist/. Register the main entry .d.ts content at both
paths (dist/ and root) so bare imports resolve with full type info.

Also remove the 2307 diagnostic suppression so non-existent imports
correctly show errors.

* Fix Monaco tooltip overflow by enabling fixedOverflowWidgets

* Fix hydration mismatch, Monaco type resolution paths, and WASM init warning

- Fix hydration mismatch: gate Reset button disabled state on isHydrated
  so server and client render consistently during hydration
- Fix Monaco types: use bare node_modules/ paths instead of file:///
  URIs for addExtraLib, which is what Monaco's NodeJs resolver expects
- Remove virtual package.json entries (Monaco doesn't use them)
- Fix wasm-bindgen init deprecation: pass object { module_or_path }
  instead of bare string argument

* Fix Monaco module resolution: set model URI to file:/// and match addExtraLib paths

Monaco's TypeScript NodeJs resolver needs the editor model and the
addExtraLib entries to share the same URI scheme. Set the input editor
model path to file:///src/input.tsx and register all type declarations
at file:///node_modules/... so resolution of bare imports like
'workflow' correctly finds the virtual node_modules.

Also register a root index.d.ts for packages like @workflow/world that
lack an explicit 'types' field in their package.json exports.

* Use declare module ambient declarations for reliable Monaco type resolution

Replace the virtual node_modules filesystem approach with declare module
ambient declarations. This is the standard approach used by TypeScript
Playground and StackBlitz — it works regardless of Monaco's internal URI
scheme and module resolution quirks.

The generation script now:
- Registers all .d.ts files at file:///node_modules/<pkg>/dist/... paths
- Generates a global ambient declarations file with declare module blocks
  that map bare import specifiers to their .d.ts entry points
- Includes @workflow/serde and workflow sub-exports (api, errors, observability)
- Supports configurable sub-export mappings per package

* Inline types into declare module blocks for full Monaco type support

Replace the export-from-file approach with fully inlined declare module
blocks. The script now reads each .d.ts entry point, recursively inlines
all relative imports, strips external import statements (resolved via
other declare module blocks), and produces a single ambient declarations
string.

This correctly handles:
- unique symbol exports (@workflow/serde)
- cross-package re-exports (workflow re-exporting from @workflow/core)
- JSDoc comments preserved for hover documentation
- Sub-path exports (workflow/api, workflow/errors, workflow/observability)
- Added @workflow/serde package

* Add workspace packages as dependencies so Turbo builds their types

The generate-monaco-types script reads .d.ts files from the built
dist/ directories of workflow, @workflow/core, @workflow/errors, etc.
On Vercel, Turbo only builds explicit dependencies — without these
workspace references, the packages were never built and the dist/
directories didn't exist, resulting in 0 type modules generated.

* Add @types/node declarations to Monaco editor

Register all @types/node .d.ts files via addExtraLib so Node.js
built-in modules (crypto, fs, path, etc.) are available in the
playground editor with full type information.

* Collect @types/node .d.ts files recursively to include subpath modules

The previous non-recursive scan missed subdirectory files like
fs/promises.d.ts, stream/web.d.ts, dns/promises.d.ts, etc., causing
'Cannot find module node:fs/promises' errors.
2026-03-30 18:17:53 +00:00
Peter Wielander a0a71957ef [ai] Fix WorkflowChatTransport blocking browser paint during stream reconnect (#1529) 2026-03-30 10:44:05 -07:00
Harpreet cdf90d5a38 Rename Workflow DevKit to Workflow SDK, remove beta badge, add tweet wall (#1541)
* Rename Workflow DevKit to Workflow SDK, remove beta badge, add tweet wall

- Rename "Workflow DevKit" to "Workflow SDK" across all files (~108 files)
- Rename standalone "WDK" references to "Workflow SDK"
- Remove beta badge from homepage hero
- Add tweet wall component to homepage with 4 builder testimonials

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Rename Workflow DevKit to Workflow SDK, remove beta badge, add tweet wall

- Rename "Workflow DevKit" to "Workflow SDK" across all files (~108 files)
- Rename standalone "WDK" references to "Workflow SDK"
- Remove beta badge from homepage hero
- Add tweet wall component to homepage with 4 builder testimonials

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Harpreet Arora <harpreet.txt@gmail.com>

* Address review: fix missed trigger phrase renames and bump skill versions

- Rename "workflow devkit" to "workflow sdk" in trigger phrases for both skill files
- Bump workflow-init SKILL.md version to 1.1
- Bump workflow SKILL.md version to 1.5
- Note: CLAUDE.md is a symlink to AGENTS.md, already renamed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Harpreet Arora <harpreet.txt@gmail.com>

* link correct tweet

---------

Signed-off-by: Harpreet Arora <harpreet.txt@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Karthik Kalyanaraman <karthik.kalyanaraman@vercel.com>
2026-03-29 16:05:39 -07:00
Nathan Rajlich 62ff6004f6 Remove Buffer global from workflow VM context (#1546)
* Remove `Buffer` global from workflow VM context

* 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>
2026-03-29 21:56:22 +00:00
workflow-devkit-release-bot[bot] e11eebf1e5 Version Packages (beta) (#1514) 2026-03-27 11:17:22 -07:00
Will Ceolin c739b99581 Fix step-level getWritable() stream timeout on Vercel (#770) (#1518)
Signed-off-by: ceolinwill <4393133+ceolinwill@users.noreply.github.com>
2026-03-26 16:12:23 -07:00
Nathan Colosimo e045b59dc4 [world-postgres] Add maxPoolSize config for graphile (#1527)
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-03-26 16:09:08 -07:00
Matan Kushner 52db376c39 Support projects with Node.js step dependencies in vitest plugin (#1524)
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-03-26 23:05:05 +00:00
Pranay Prakash d1391e1fd9 Fix race condition allowing duplicate hook_disposed events (#1523)
* Fix race condition allowing duplicate hook_disposed events

Concurrent workflow invocations could both post hook_disposed for the
same hook, corrupting the event log with duplicate events. This mirrors
the wait_completed race condition fixed in #1057/#1434.

- world-local: Add writeExclusive lock file for hook_disposed (same
  pattern as wait_completed and step terminal states)
- world-postgres: Use DELETE ... RETURNING to atomically detect if
  another caller already deleted the hook entity
- suspension-handler: Improve log messages to distinguish hook-already-
  disposed (EntityConflictError) from run-already-completed (RunExpiredError)

Fixes #1266

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Accept either EntityConflictError or HookNotFoundError in race test

The concurrent hook_disposed race has two possible orderings: the loser
may hit the lock file (EntityConflictError) or find the hook entity
already deleted by the winner (HookNotFoundError). Both are correct.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Assert only one hook_disposed event in event log after race

Verifies the losing concurrent caller didn't sneak an event in before
the guard threw.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 15:51:29 -07:00
Pranay Prakash 8e7083b327 Add btoa, atob, and Buffer globals to workflow VM context (#1520)
* feat: add base64 encoding/decoding and Buffer support to virtual machine context

Slack-Thread: https://vercel.slack.com/archives/CDSJDH8QH/p1774470115717019?thread_ts=1774470115.717019&cid=CDSJDH8QH
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>

* Add changeset for btoa/atob/Buffer globals

---------

Co-authored-by: v0 <v0[bot]@users.noreply.github.com>
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
2026-03-25 17:34:56 -07:00
Karthik Kalyan bb86b695c2 [web] Fix Streams tab crash when decrypting large stream chunks (#1515)
* optimize stream tab

* add changeset
2026-03-24 19:00:32 -07:00
Karthik Kalyan dab106acd3 hide graph tab for web (#1492) 2026-03-24 22:04:44 +00:00
workflow-devkit-release-bot[bot] a375a3fd85 Version Packages (beta) (#1440)
Co-authored-by: workflow-devkit-release-bot[bot] <workflow-devkit-release-bot[bot]@users.noreply.github.com>
2026-03-24 17:19:33 +00:00
Pranay Prakash 672d9195a4 Fix step/workflow not found errors to fail gracefully instead of queue retry (#1452)
* feat: enhance error handling for missing workflow functions

Slack-Thread: https://vercel.slack.com/archives/C09G3EQAL84/p1773856370214769?thread_ts=1773856370.214769&cid=C09G3EQAL84
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>

* fix: update step not found handling to match FatalError pattern

Move step function validation after step_started and call step_failed directly if not found.

Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>

* changes

Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>

* feat: add StepNotRegisteredError and WorkflowNotRegisteredError semantic errors

Introduce dedicated error types for when step/workflow functions are not
registered in the current deployment, replacing generic WorkflowRuntimeError.
These are infrastructure errors (not user code errors) with proper error
slugs, docs pages, and a new FUNCTION_NOT_REGISTERED error code.

Step not found fails the step (like FatalError) so the workflow can handle
it gracefully. Workflow not found fails the run.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review comments

- Remove FUNCTION_NOT_REGISTERED error code, use RUNTIME_ERROR instead
- Use .is() instead of instanceof for WorkflowRuntimeError check in runtime.ts
- Remove non-working example from WorkflowNotRegisteredError docs (custom
  errors not serialized yet)
- Update all references from FUNCTION_NOT_REGISTERED to RUNTIME_ERROR

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add e2e tests for step/workflow not registered errors and fix docs typecheck

E2E tests:
- WorkflowNotRegisteredError: start a run with a fake workflowId, verify
  the run fails with RUNTIME_ERROR
- StepNotRegisteredError (caught): workflow catches the step failure,
  verify workflow completes and step is marked failed
- StepNotRegisteredError (uncaught): verify the run fails when workflow
  doesn't catch the error

Step not registered is tested by manually invoking useStep with a
non-existent step ID in the workflow VM — this is the same pattern the
SWC transform generates for real step calls.

Also fix docs typecheck by using declare/\@setup pattern instead of
\@skip-typecheck for code samples.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: cast globalThis to any for Symbol index access in e2e workflow

TypeScript's strict mode doesn't allow using a symbol to index
globalThis. Cast to any since this runs in the workflow VM where
the symbol is defined.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: classify WorkflowNotRegisteredError as RUNTIME_ERROR

The .is() check uses name-based matching, so WorkflowNotRegisteredError
(name='WorkflowNotRegisteredError') doesn't match WorkflowRuntimeError.is().
Add explicit check in classifyRunError so the error code is RUNTIME_ERROR
instead of USER_ERROR.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use instanceof for WorkflowRuntimeError checks, improve docs

Address PR review feedback:

1. Revert .is() checks back to instanceof WorkflowRuntimeError in
   runtime.ts and classify-error.ts. instanceof catches all subclasses
   (current and future), which is the correct behavior for these catch
   blocks.

2. Remove duplicated try/catch example from step-not-registered-error
   API reference (troubleshooting page already has it).

3. Add Callout in API reference docs clarifying that .is() works in
   server-side Node.js code but not inside "use workflow" functions
   where errors arrive deserialized from the event log.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* changes

Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>

---------

Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
Co-authored-by: v0 <v0[bot]@users.noreply.github.com>
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 10:04:42 -07:00
Nathan Rajlich 77fd9ad355 Inline class serialization registration to fix 3rd-party package support (v2) (#1503)
* Inline class serialization registration to fix 3rd-party package support (#1480)

* Inline class serialization registration to fix 3rd-party package support

The SWC plugin previously generated:
  import { registerSerializationClass } from "workflow/internal/class-serialization";
  registerSerializationClass("class//...", ClassName);

This broke for 3rd-party packages (e.g. @vercel/sandbox) that define
serializable classes but don't depend on the 'workflow' package. The
bare 'workflow' specifier is unresolvable from within node_modules of
a package that doesn't list it as a dependency.

Now the plugin generates a self-contained IIFE that uses
Symbol.for('workflow-class-registry') on globalThis directly, with
zero module dependencies:

  (function(__wf_cls, __wf_id) {
    var __wf_sym = Symbol.for("workflow-class-registry"),
        __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = new Map());
    __wf_reg.set(__wf_id, __wf_cls);
    Object.defineProperty(__wf_cls, "classId", { ... });
  })(ClassName, "class//...");

This is fully compatible with the existing deserialization side in
@workflow/core which reads from the same globalThis registry.

* Address review feedback: fix comment and update docstring

- Fix inaccurate IIFE comment in lib.rs: the second arg is the
  generated class ID string, not the literal "classId"
- Update registerSerializationClass docstring to reflect that the
  SWC plugin now inlines equivalent logic rather than importing it

* Update CJS require fixture outputs for inline class serialization

The original PR #1480 was merged but reverted because it didn't include
updated fixtures for the CJS require patterns added by PR #1144
(custom-serialization-require-destructured and
custom-serialization-require-namespace). These fixtures still had the
old 'import { registerSerializationClass }' pattern instead of the
new inline IIFE.
2026-03-24 09:30:55 -03:00
Pranay Prakash ef4ca00b77 chore: bump next to 16.2.1 and fix deferred build (#1496)
* chore: bump next to 16.2.1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: run deferred Next dev e2e assertions on stable

Bump Next.js to 16.2.1 in docs and swc-playground and update lockfile.

* fix(next): copy all deferred step sources for step-mode transforms

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-03-23 21:25:28 -07:00