Commit Graph

242 Commits

Author SHA1 Message Date
Vercel Release Bot 835e2fbd3c Version Packages (beta) (#921)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-02-06 14:20:08 -08:00
Nathan Rajlich 661724c01e Expose workflow manifest via HTTP when WORKFLOW_PUBLIC_MANIFEST=1 (#963)
## 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`
2026-02-06 12:22:37 -08:00
Nathan Rajlich 35a9f0cb03 Add subpath export resolution for package IDs (#901)
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.
2026-02-04 16:49:16 -08:00
Nathan Rajlich 73bf7be925 Change compiler ID generation logic to use Node.js import specifier (#899)
## Summary

This PR changes how the SWC compiler generates IDs for workflows, steps, and classes. Instead of using raw file paths, IDs are now based on **Node.js module specifiers** when the file belongs to a package (either in `node_modules` or a workspace package).

## Motivation

Previously, IDs were generated using file paths like `step//src/jobs/order.ts//fetchData`. This caused several issues:

1. **Package exports conditions**: When a package uses conditional exports (e.g., `"workflow"` vs `"default"` conditions in `package.json`), the same import specifier can resolve to different files. Using file paths meant IDs could differ based on which export condition was used.
2. **Cross-bundle consistency**: Classes serialized in one bundle couldn't be deserialized in another if the file paths differed.
3. **Version tracking**: No way to include package versions in IDs for cache invalidation.

## Changes

### New ID Format

IDs now use the format `{type}//{modulePath}//{identifier}` where `modulePath` is either:

- A **module specifier** like `point@0.0.1` or `@myorg/shared@1.2.3` for package files
- A **relative path** prefixed with `./` like `./src/jobs/order` for local app files

Examples:

- `step//workflow@4.0.1-beta.50//fetch` (SDK step)
- `step//./workflows/order//processOrder` (local step)
- `class//point@0.0.1//Point` (package class)
- `class//./src/models/User//User` (local class)

### New Module Specifier Resolution

Added `packages/builders/src/module-specifier.ts` which:

- Detects if a file is in `node_modules` or a workspace package
- Finds the nearest `package.json` and extracts name/version
- Returns the module specifier for the SWC plugin to use

### SWC Plugin Changes

- Added `moduleSpecifier` option to plugin config
- Updated `naming.rs` to support both module specifiers and relative paths
- Added `get_module_path()` helper that uses specifier when available, falls back to `./filename` format

### Special Cases

- **Builtin functions** (`__builtin_*`): Continue to use just the function name as the ID for stable, version-independent lookup from the workflow VM runtime.

## Testing

- Updated all 125+ SWC plugin test fixtures to use new ID format
- Added tests for module specifier resolution
- Added tests for Windows path normalization in naming

## Breaking Changes

This is technically a breaking change for any persisted workflow runs that reference the old ID format. However, since IDs are internal implementation details and not user-facing, this should not affect end users.

## Files Changed

- `packages/builders/src/module-specifier.ts` - **NEW**: Module specifier resolution logic
- `packages/builders/src/apply-swc-transform.ts` - Pass module specifier to SWC plugin
- `packages/builders/src/base-builder.ts` - Use `getImportPath` for virtual entry imports
- `packages/swc-plugin-workflow/transform/src/lib.rs` - Accept and use module specifier
- `packages/swc-plugin-workflow/transform/src/naming.rs` - New ID formatting with module paths
- `packages/swc-plugin-workflow/spec.md` - Updated documentation
- `packages/core/e2e/e2e.test.ts` - Updated test assertions for new ID format
2026-02-04 14:23:02 -08:00
Nathan Rajlich 2453b29426 Make wf build --manifest-file include steps / classes metadata (#931) 2026-02-04 09:22:11 -08:00
Nathan Rajlich b5296a7a32 Add discovered serializable classes in all context modes (#874)
This PR ensures that all classes with custom serialization are automatically included in all bundle contexts (step, workflow, client) to ensure proper serialization/deserialization when crossing execution boundaries:

- Classes defined in any context can now be properly serialized when passing data between:
  - Client → Workflow (when starting workflows)
  - Workflow → Step (when calling steps)
  - Step → Workflow (when returning step results)
  - Workflow → Client (when returning workflow results)

- The build system now automatically discovers all files containing serializable classes and includes them in each bundle, regardless of where the class is originally defined.

- No manual configuration is required - cross-registration happens automatically during the build process.
2026-02-02 23:26:29 -08:00
Nathan Rajlich 8114792600 Add discovery for custom classes with workflow serialization (#859)
Added automatic discovery for custom classes with workflow serialization, allowing serialization classes to be defined in separate files without requiring explicit directives.

### What changed?

- Added detection for files containing custom class serialization patterns:
    - Files importing from `@workflow/serde`
    - Files using `Symbol.for('workflow-serialize')` or `Symbol.for('workflow-deserialize')`
- Created shared utilities in `transform-utils.ts` for consistent pattern detection across all build tools
- Updated Next.js, Nitro, Rollup, and Vite plugins to use the new detection patterns
- Added exclusion logic to prevent re-processing of generated workflow files
- Added tests to verify the pattern detection works correctly
- Updated documentation in the SWC plugin spec to explain the new discovery mechanism

### How to test?

1. Create a class with custom serialization in a separate file:

```js
// models/point.js
export class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  static [Symbol.for('workflow-serialize')](instance) {
    return { x: instance.x, y: instance.y };
  }

  static [Symbol.for('workflow-deserialize')](data) {
    return new Point(data.x, data.y);
  }
}
```

1. Import and use this class in a workflow or step file:

```js
'use workflow';
import { Point } from '../models/point';

export function myWorkflow() {
  const point = new Point(10, 20);
  return point;
}
```

1. Verify the class is properly serialized when passed between client and server

### Why make this change?

Previously, files containing custom serialization classes needed to include a `'use step'` directive to be discovered and transformed, even if they weren't actual step functions. This was unintuitive and could lead to confusion.

This change allows for a more natural code organization pattern where model classes with serialization can be defined in their own files without requiring directives. The build system will automatically discover and transform these files to ensure the serialization works correctly when the classes are used in workflows or steps.
2026-02-02 23:19:00 -08:00
Vercel Release Bot f6deb699af Version Packages (beta) (#915) 2026-02-02 16:53:50 -08:00
Karthik Kalyan f40532a872 fix(builders): Inline Next.js pseudo‑packages and strip server-only/client-only requires in workflow bundles (#911)
* Fix bundling behavior for dynamic imports and server-only, client-only imports

* Generate changeset

* Filter tsconfig to only pull in code from within the current working directory(workflow dir)

* Rewrite server-only and client-only

* add additional pseudo directives

* upmerge

* fix failing unit test
2026-02-02 11:07:53 -08:00
Vercel Release Bot 3dde14d529 Version Packages (beta) (#834) 2026-02-02 10:33:56 -08:00
Nathan Rajlich 13d4ceef74 Use proper pluarlization in the builder log line (#898) 2026-01-30 11:58:55 -08:00
Alan Cohen 4ad3fcd0a3 Pass runtime option to Vercel Build Output API functions (#800)
Signed-off-by: Alan Cohen <alan.mit@gmail.com>
2026-01-28 10:15:12 -08:00
Nathan Rajlich 81c5a835ae Add "classes" object to manifest.json file (#864) 2026-01-27 00:35:34 -08:00
Peter Wielander 50f50f44d7 NestJS framework support (#840) 2026-01-26 13:31:22 -08:00
Michael Han 0b5cc48140 fix(builders): manifest missing workflow-only files (no steps), add tests (#831)
* Fix manifest missing workflow-only files (no steps), add tests

Signed-off-by: voyager14 <21mh124@queensu.ca>

* Update packages/builders/src/base-builder.ts

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Signed-off-by: Michael Han <21mh124@queensu.ca>

---------

Signed-off-by: voyager14 <21mh124@queensu.ca>
Signed-off-by: Michael Han <21mh124@queensu.ca>
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
2026-01-22 17:22:14 -08:00
Vercel Release Bot cd7c03d45d Version Packages (beta) (#819)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-22 14:12:34 -08:00
Vercel Release Bot 3856ce8c20 Version Packages (beta) (#807)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-20 18:37:54 -08:00
Vercel Release Bot 96d17286b1 Version Packages (beta) (#791) 2026-01-16 11:06:05 +01:00
Vercel Release Bot 4bd877b474 Version Packages (beta) (#778) 2026-01-14 13:25:24 +01:00
Vercel Release Bot 101585cce0 Version Packages (beta) (#758)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-13 14:10:19 -08:00
Rishabh 97c78755da fix: add TypeScript decorator support to SWC transform (#757)
* fix: add TypeScript decorator support to SWC transform

  Enable decorator parsing in SWC configuration to support codebases using
  TypeScript decorators (TypeORM, NestJS, class-validator, custom decorators).

  Without this fix, projects importing files with decorators fail with:
  "Unexpected token `@`. Expected identifier..." syntax errors.

  Changes:
  - Add `decorators: true` to parser options for TypeScript and ECMAScript
  - Add `legacyDecorator: true` for TypeScript's experimentalDecorators
  - Add `decoratorMetadata: true` for emitDecoratorMetadata support

* fix: conditionally enable decorators based on tsconfig compilerOptions

  Read experimentalDecorators and emitDecoratorMetadata from tsconfig.json
  to match Next.js behavior. Decorators are now only enabled when explicitly
  configured in the project's tsconfig.

  - Add getDecoratorOptionsForDirectory() to read tsconfig settings
  - Update applySwcTransform and Next.js loader to use tsconfig options
  - Handle JSONC format (comments, trailing commas) in tsconfig parsing

* fix: use json5 for parsing tsconfig in decorator options

  Replace manual regex-based JSONC parsing with json5 library for more
  robust handling of comments and trailing commas in tsconfig.json files.

* bump

* apply fix

* DCO Remediation Commit for JJ Kasper <jj@jjsweb.site>

I, JJ Kasper <jj@jjsweb.site>, hereby add my Signed-off-by to this commit: aa1dc36db7
I, JJ Kasper <jj@jjsweb.site>, hereby add my Signed-off-by to this commit: e25f1748c6

Signed-off-by: JJ Kasper <jj@jjsweb.site>

* DCO Remediation Commit for Rishabh <rishabh.pugalia@gmail.com>

I, Rishabh <rishabh.pugalia@gmail.com>, hereby add my Signed-off-by to this commit: e2f93048aa
I, Rishabh <rishabh.pugalia@gmail.com>, hereby add my Signed-off-by to this commit: 3faee5d3c2
I, Rishabh <rishabh.pugalia@gmail.com>, hereby add my Signed-off-by to this commit: 9dbbda6362

Signed-off-by: Rishabh <rishabh.pugalia@gmail.com>

---------

Signed-off-by: JJ Kasper <jj@jjsweb.site>
Signed-off-by: Rishabh <rishabh.pugalia@gmail.com>
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2026-01-13 00:09:47 -08:00
Vercel Release Bot 073e26a372 Version Packages (beta) (#735) 2026-01-08 19:32:27 +01:00
Nathan Rajlich dc44dab49d Biome config tweaks and fixes applied (#741) 2026-01-07 12:52:52 -08:00
Vercel Release Bot a0045ac607 Version Packages (beta) (#723) 2026-01-06 18:07:45 -08:00
Nathan Rajlich 505063cbb9 Special-case "server-only" and "client-only" packages as external (#731) 2026-01-06 18:00:14 -08:00
Pranay Prakash 4d6f797274 Fix step stack trace propogation and refactor e2e error tests (#720)
* Refactor e2e tests for errors

* Improve step error tests to check workflow return value

Step error workflows now catch the error and return message/stack,
making assertions cleaner. Tests verify both:
- Workflow return value (caught error message)
- CLI step result (original stack with function names)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add assertion for stack trace in caught step error

With the fix in step.ts that propagates original stack traces,
we can now verify that caught step errors include function names
directly in the workflow return value (not just via CLI).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* logging

* Fix: When a step handler is re-invoked after max retries are exhausted, the step_failed event doesn't include a stack trace, breaking stack trace propagation for this edge case.

This commit fixes the issue reported at packages/core/src/runtime/step-handler.ts:127-146

## Stack trace loss in step_failed event when max retries are exceeded

**What fails:** Step handler does not include stack property in step_failed event when step is re-invoked after max retries exhausted, causing FatalError in workflow to lose original stack trace

**How to reproduce:**
1. Create a step that always fails with an error that includes a stack trace
2. Exhaust all retry attempts (e.g., maxRetries = 3, so 4 total attempts)
3. The step handler is re-invoked (attempt > maxRetries + 1)
4. This triggers the edge case at lines 127-146 in step-handler.ts
5. A step_failed event is created with fatal: true but without stack property
6. When step.ts processes this event (lines 103-104), the stack remains unset since event.eventData.stack is undefined

**Result:** FatalError created in workflow has default stack (from step.ts) instead of original error stack from step execution

**Expected:** Stack trace should be propagated consistently across all error paths. All other step_failed events with fatal: true include stack property (lines 311-313 and 351-353), but edge case was missing it.

**Root cause:** When step handler is re-invoked after max retries exhausted (attempt > maxRetries + 1), the code creates a step_failed event without including step.error?.stack, which contains the previous error information from the last failed attempt. Other code paths capture this correctly.

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>

* add withData

* Enable source maps for step bundles and validate in e2e tests

- Move sourcemap generation from intermediate workflow bundle to steps bundle
- Enhance step error tests to validate function names and source files in stack traces
- Remove isLocalDeployment() checks since source maps now work in dev mode

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add changeset for step bundle source maps

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add changeset for core package e2e test improvements

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Enable source maps in CI e2e tests

Add NODE_OPTIONS="--enable-source-maps" to all e2e test jobs to ensure
stack traces show original source file paths.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix step error source map checks for local prod builds

Add hasStepSourceMaps() helper that correctly identifies when source maps
are expected to work:
- Vercel prod: works (production builds have proper source maps)
- Local dev: works (DEV_TEST_CONFIG is set, uses step bundle with inline source maps)
- Local prod: doesn't work (nitro/bundler output doesn't preserve source maps)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add hasWorkflowSourceMaps() utility for vite-based framework exception

- Add isViteBasedFramework() helper to detect vite, sveltekit, astro apps
- Add hasWorkflowSourceMaps() to check if workflow errors have source maps
  (known issue: vite-based frameworks in local deployments don't preserve them)
- Refactor e2e.test.ts to use the new utility instead of inline check

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* prevent sourcemap checks in nextjs and sveltekit (known offenders)

* improve source maps matrix check

* fix matrix again

* ugh more matrix ignoring

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
2026-01-05 14:12:24 -08:00
Vercel Release Bot 6660e578bb Version Packages (beta) (#719) 2026-01-03 10:27:22 +01:00
Nathan Rajlich d552374b13 Resolve @workflow/swc-plugin relative to the "builders" package (#713) 2026-01-02 10:03:55 -08:00
Vercel Release Bot 6d7e5035a4 Version Packages (beta) (#711) 2025-12-31 10:17:49 -08:00
JJ Kasper 307f4b0e41 Revert "Add lazy workflow and step discovery in Next.js (#640)" (#712) 2025-12-31 09:37:56 -08:00
Nathan Rajlich 7ff68d1753 Pass tsconfig to esbuild for support of "paths" aliases (#705) 2025-12-31 01:00:24 -08:00
Vercel Release Bot b49bb4eb54 Version Packages (beta) (#707) 2025-12-30 11:01:55 +01:00
Vercel Release Bot e6b1bef5bb Version Packages (beta) (#693) 2025-12-27 12:40:09 -08:00
Karthik Kalyanaraman e3f0390469 Workflows graph extractor (#455)
---------

Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
2025-12-27 16:52:19 +01:00
Vercel Release Bot 96a4d3a2fd Version Packages (beta) (#676)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-12-24 09:51:14 -08:00
JJ Kasper ea3afce222 Add lazy workflow and step discovery in Next.js (#640) 2025-12-22 23:16:17 -06:00
Vercel Release Bot 560dda3014 Version Packages (beta) (#660) 2025-12-20 10:58:29 +01:00
Vercel Release Bot bd3385ff6d Version Packages (beta) (#652)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-12-19 15:41:36 -08:00
Vercel Release Bot b4132d0895 Version Packages (beta) (#635) 2025-12-18 20:07:06 +01:00
Vercel Release Bot fc6a32d6dc Version Packages (beta) (#607) 2025-12-16 21:05:18 +01:00
Vercel Release Bot 7018f490e6 Version Packages (beta) (#589)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-12-12 18:11:25 -08:00
Vercel Release Bot 76795b0cd0 Version Packages (beta) (#561) 2025-12-09 09:26:51 -08:00
Adrian 19c271c072 refactor: move request converters to @workflow/builders (#503)
sveltekit and astro use the exact same code for normalizing requests so it's been refactored to `request-converter.ts` inside `@workflow/builders`
2025-12-05 16:02:26 -08:00
Vercel Release Bot 6194ded51b Version Packages (beta) (#533) 2025-12-05 15:24:04 -08:00
Nathan Rajlich 43f2dec31b Improved workflow registration in workflow mode (#557)
Primary motivation here is to allow a `use workflow` function to be non-exported, meaning that it is called by `start()` in i.e. an API route within the same function:

- SWC plugin now emits `globalThis.__private_workflows.set(workflowId, fn)` directly after setting `workflowId`
- Non-exported workflow functions are now properly registered and can be invoked
- Removed runtime iteration over exports in the workflow bundle - registration happens at transform time
- Simplified virtual entry generation in base-builder
2025-12-05 15:19:24 -08:00
Nathan Rajlich 21cff154a3 Add support for .mjs, .mts, .cjs, and .cts file extensions in the SWC transform (#556)
- Updated turbopack rules to include `*.mjs`, `*.mts`, `*.cjs`, `*.cts` in addition to existing extensions
- Fixed TypeScript detection for `.mts` and `.cts` files across all transform plugins
- Updated esbuild `resolveExtensions` to include `.mts` and `.cts`
- Updated the file watcher's `watchableExtensions` to include `.cts`
2025-12-05 14:39:10 -08:00
Adrian b73fc72f0e test: fix getViolationLocation sync in test (#540) 2025-12-04 18:25:03 -08:00
Adrian fc774e57d0 fix: error messages in esbuild node module plugin (#264)
* feat: add file dependency tracing for node module plugin

* feat: add violation identifier and read file to show contents

* Update packages/builders/src/node-module-esbuild-plugin.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* changeset

* fix: node module plugin silently failing when enhanced resolve fails

* chore: fix comment jsdoc

* fix: infinite loop in traversing dep grpah

* Update packages/builders/src/node-module-esbuild-plugin.test.ts

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>

* fix

* cleanup

* test: add comprehensive build errors test

* add more tests

* fix generate workflows

* update test

* fix: use readFile over readFileSync

* fix test

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
2025-12-04 16:53:41 -08:00
Vercel Release Bot 1ea0826fad Version Packages (beta) (#517)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-12-03 15:50:12 -08:00
Vercel Release Bot 4b79bee16c Version Packages (beta) (#513)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-12-03 12:07:57 -08:00