Commit Graph

1497 Commits

Author SHA1 Message Date
Peter Wielander b2ba6ff70e [ci] Add flag that can disable non-vercel e2e tests (#1006) 2026-02-11 16:53:55 -08:00
JJ Kasper dc2dc6ac79 next: stop esbuild bundling for deferred step route (#992)
* next: remove deferred step esbuild bundle and use copied step files

* chore: bump workspace Next.js deps to canary

* web: avoid type re-exports from use server actions module

* next: resolve copied step import extensions for symlinked TS sources

* next: fix deferred copied step dependency discovery and imports

* next: add deferred step copy source-map plumbing

* add changeset

* next/builders: scope deferred logging and warning suppression

* next: derive deferred transitive entries from tracked deps

* fix(next): include transitive step files in deferred step copy

* fix(next): include transitive serde files in deferred builds

* fix(next): clean deferred artifacts on startup

* reset to stable next

* bump
2026-02-11 16:26:41 -08:00
Vercel Release Bot 9f442d2dd7 Version Packages (beta) (#987)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
workflow@4.1.0-beta.55
2026-02-11 15:46:37 -08:00
Nathan Rajlich 054e40c91b Fix anonymous class expression names for serialization classes (#991)
When upstream bundlers like tsup/esbuild transform class declarations into anonymous class expressions (e.g. `var Foo = class { ... }`), the SWC plugin now re-inserts the binding name into the class expression (e.g. `var Foo = class Foo { ... }`). This preserves the class `.name` property through subsequent bundling passes, preventing runtime failures in downstream bundlers like Nitro's Rollup bundler that rely on the class expression name for serialization class registration.
2026-02-11 23:34:01 +00:00
Pranay Prakash 87478d7d54 ignore jj (jujitsu vcs files) 2026-02-11 15:00:52 -08:00
Nathan Rajlich a4a9b526a8 docs: use markdown image syntax in observability page (#1008) 2026-02-11 14:44:11 -08:00
JJ Kasper bb45816f0a Fix hydration mismatch in Next.js workbench workflow defaults (#1009) 2026-02-11 22:44:04 +00:00
JJ Kasper 8cb7be5f48 Ensure unit tests are included in required check (#1001) 2026-02-10 23:25:48 -08:00
JJ Kasper 3d770d5385 Expose workflows manifest under diagnostics folder (#998)
* Expose workflows manifest under Next.js diagnostics folder

* feat(builders): emit diagnostics manifest for vercel world

* dedupe function

* update changeset

* fix(builders): write vercel diagnostics manifest under workflows

* fix(builders): rename vercel diagnostics manifest path
2026-02-10 17:25:19 -08:00
JJ Kasper d8a9ee9c29 ci: add final E2E required-check job (#996)
* ci: add final e2e required check job

* bump
2026-02-10 15:30:42 -08:00
Nathan Rajlich 613d008c6b Remove @workflow-worlds/starter from worlds manifest (#995)
The starter world uses in-memory storage that can't be shared across
processes, making E2E tests fundamentally incompatible with the CI
setup (test runner and dev server run in separate processes). This
caused the "E2E Community World (Starter)" job to hang until the
30m timeout.
2026-02-10 14:48:43 -08:00
JJ Kasper a5935abec7 Add lazy workflow/step discovery via deferredEntries in next (#976)
* Add lazy workflow/step discovery via deferredEntries in next

* discover serde in loader

* fix implicit steps discovery

* update serde

* fix symlink case

* pre-warm non-next

* add resolution cache

* Fix deferred build error propagation and restore start-arg workflow

* revert

* Fix step function alias lookup and dev prewarm stability

* Fix step function alias tests for updated reviver context

* next: address deferred discovery review feedback

* update lockfile

* builders: extract shared workflow alias resolver

* chore: pin next deps to latest canary

* unlock from canary version from testing
2026-02-10 12:03:59 -08:00
Karthik Kalyan fc4cad6808 [core] Fix workflow runtime error normalization to avoid [object Promise] and preserve provider failure context (#989)
* [workflow/core] normalize errors cleanly

* test fix
2026-02-10 09:44:13 -08:00
JJ Kasper da64519db8 ci: use PR head SHA for tests workflow checkout (#988)
Signed-off-by: JJ Kasper <jj@jjsweb.site>
2026-02-09 16:51:16 -08:00
Nathan Rajlich 1adcc6a618 Fix discovery of serde classes to detect [WORKFLOW_SERIALIZE] and [WORKFLOW_DESERIALIZE] computed property usage in bundled code (#908) 2026-02-09 15:05:56 -08:00
Peter Wielander 56f22219b3 [core] Handle 429 and 500 errors from worlds in runtime (#966) 2026-02-09 14:43:12 -08:00
Vercel Release Bot d25630a27c Version Packages (beta) (#971) workflow@4.1.0-beta.54 2026-02-09 13:47:40 -08:00
Peter Wielander aa448c29b4 [world-vercel] Allow specifying backend URL via env variable (#985) 2026-02-09 13:38:38 -08:00
Dustin Townsend ea145a65d3 Fix manifest 404 errors in community world e2e tests (#977)
Add missing WORKFLOW_PUBLIC_MANIFEST env var to e2e-community-world.yml.
The e2e tests fetch the workflow manifest from
/.well-known/workflow/v1/manifest.json, but this endpoint is only
exposed when WORKFLOW_PUBLIC_MANIFEST=1 is set. Every other CI workflow
(tests.yml, benchmarks.yml, benchmark-community-world.yml) already sets
this variable, but it was missing from the community world e2e workflow.

https://claude.ai/code/session_01GezavpthQcEpyYVisScncM

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-08 12:16:17 -08:00
Nathan Rajlich d9e98590fa Generate runId client-side in start() and simplify streaming types (#954)
## Summary

- Generates `runId` client-side in `start()` using ULID (`wrun_${ulid()}`), instead of deferring to the server
- Passes client-generated `runId` to `events.create()` and verifies the server accepted it
- Simplifies `runId` types from `string | Promise<string>` to `string` throughout the serialization layer
- Removes the `withResolvers<string>()` / deferred runId pattern that was needed when `runId` was server-generated
- Updates `Streamer` interface and `WorkflowServerWritableStream` to use plain `string` runId
- Updates `Storage.events.create()` first overload to accept `string | null` instead of just `null`

This is a prerequisite for E2E encryption, where we need the `runId` before serialization so it can be used as part of the encryption context.

## Test plan

All existing tests pass. Updated `start.test.ts` to expect client-generated runId, removed `writable-stream.test.ts` promise runId test (no longer applicable).
2026-02-08 00:27:40 -08:00
Nathan Rajlich fcfaf8bbaa Support step function serialization in client mode (#924) 2026-02-07 15:34:29 -08:00
JJ Kasper 2d1d69f4ca Fix getImportPath package handling (#972)
* Fix getImportPath package handling

* Add root entrypoint comments and coverage for package imports
2026-02-07 14:02:07 -08:00
Nathan Rajlich ef23b0be77 Fix step functions nested multiple levels deep in an object (#923)
Fixed a bug where step functions nested multiple levels deep in an object weren't being properly transformed.

### What changed?

- Enhanced the SWC plugin to recursively process nested objects to find step functions
- Added support for step functions defined inside deeply nested object properties, including function call arguments
- Implemented proper path handling for nested step IDs, using compound paths (e.g., `vade/tools/VercelRequest/execute`)
- Fixed variable name generation by replacing slashes with `$` to create valid JavaScript identifiers
- Updated documentation with examples of nested object property step functions
- Added test cases for deeply nested step functions and agent tool steps

### How to test?

Test with code that has step functions nested multiple levels deep in objects:

```javascript
export const config = createConfig({
  level1: {
    level2: {
      level3: {
        myStep: async (input) => {
          "use step";
          return input * 2;
        },
      },
    },
  },
});
```

Or with agent tools:

```javascript
export const vade = agent({
  tools: {
    VercelRequest: {
      execute: async (input, ctx) => {
        "use step";
        return 1 + 1;
      },
    },
  },
});
```

### Why make this change?

This fix ensures that step functions can be properly identified and transformed regardless of how deeply they are nested in object structures. This is particularly important for complex configurations like agent tools where step functions might be several levels deep in the object hierarchy.
2026-02-07 11:14:20 -08:00
Nathan Rajlich 5b5b36a03b [e2e] Remove /api/hook and /api/test-health-check endpoints, call APIs directly
- Remove debug logging from bench.bench.ts
- Remove awaitReturnValue() wrapper, use run.returnValue directly in benchmarks
- Add changeset for Nitro builder manifest fix
- Refactor hookWorkflow tests to call getHookByToken()/resumeHook() directly
  (pass hook object to resumeHook to avoid duplicate lookups)
- Refactor queue-based health check test to call healthCheck() directly
- Assert specific error message for invalid hook token test
- Remove /api/hook and /api/test-health-check endpoints from all workbench apps
  (nextjs-turbopack, nextjs-webpack, vite, hono, express, fastify, sveltekit,
  astro, nuxt, nitro-v2, nitro-v3, nest, example)
2026-02-07 09:00:19 -08:00
JJ Kasper 82c209c669 Add missing env for tests on deploy (#973) 2026-02-06 16:57:11 -08:00
Nathan Rajlich 86f62f2779 Refactor e2e tests to no longer use "trigger" endpoint (#958)
## Summary

Refactors the E2E tests to call `start()` from `workflow/api` directly instead of going through the `/api/trigger` HTTP endpoint in each workbench app. This removes a layer of indirection — the tests now use the same API that users would use to start workflows programmatically.

### Before

```ts
const run = await triggerWorkflow('addTenWorkflow', [123]);
const returnValue = await getWorkflowReturnValue(run.runId);
```

- `triggerWorkflow()` sent an HTTP POST to `/api/trigger` on the workbench app
- The workbench app looked up the workflow function, called `start()`, and returned the run ID
- `getWorkflowReturnValue()` polled `GET /api/trigger?runId=...` until the workflow completed

### After

```ts
const run = await start(await e2e('addTenWorkflow'), [123]);
const returnValue = await run.returnValue;
```

- `e2e()` / `getWorkflowMetadata()` fetches the manifest from `/.well-known/workflow/v1/manifest.json` to look up the correct `workflowId`
- `start()` is called directly from the test process via the configured World
- `run.returnValue` polls for completion via the World (no HTTP polling endpoint needed)

### Changes

**`packages/core/e2e/e2e.test.ts`**
- Removed `triggerWorkflow()` and `getWorkflowReturnValue()` helpers
- Added `fetchManifest()` to fetch and cache the workflow manifest from the deployment
- Added `getWorkflowMetadata(file, fn)` to look up `{ workflowId }` from the manifest
- Added `e2e(fn)` shorthand for the common case of `workflows/99_e2e.ts`
- All tests call `start()` and `run.returnValue` directly
- Error tests use `.catch()` to inspect `WorkflowRunFailedError`
- Output stream tests use `run.getReadable()` directly (skipped on local world where cross-process streaming isn't supported)
- `beforeAll` configures the local World with the correct data directory and base URL
- Pages Router tests use `startWorkflowViaHttp()` to specifically validate the HTTP trigger path

**Workbench apps (hono, express, fastify, nest)**
- Removed `/api/trigger` route handlers
- Kept `/api/hook`, `/api/test-direct-step-call`, `/api/test-health-check` endpoints
- Re-added `_workflows.js` side-effect import for hono/express/fastify to maintain Nitro's HMR dependency graph

**Deleted trigger-only route files** from: nextjs-turbopack, nextjs-webpack, vite, sveltekit, astro, nuxt, nitro-v2, nitro-v3, example

**`.github/workflows/tests.yml`**
- Added `WORKFLOW_PUBLIC_MANIFEST: '1'` to all E2E test jobs

### Dependencies

Stacked on #963 which adds `WORKFLOW_PUBLIC_MANIFEST` support to all framework builders.
2026-02-06 16:25:47 -08:00
Peter Wielander f7fd88ea96 [core] Tidy health check latency calculation (#951) 2026-02-06 15:54:53 -08:00
Vercel Release Bot 835e2fbd3c Version Packages (beta) (#921)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
workflow@4.1.0-beta.53
2026-02-06 14:20:08 -08:00
Nathan Rajlich a733449e48 Fix release PR bad lockfile (#968) 2026-02-06 14:08:43 -08:00
Nathan Rajlich 54432085e1 Ignore "swc-playground" app in changesets (#967) 2026-02-06 13:51:30 -08:00
Karthik Kalyan f090de1eb4 Refactor web-shared to separate UI components from server concerns (#927)
* Refactor web-shared to separate UI components from server concerns

- Move UI components into src/components/ subdirectory
- Move server actions and API client to @workflow/web
- Add world-actions/ module with shared helpers (recreateRun, cancelRun, etc.)
- Add runtime subpath exports to @workflow/core
- Components now accept callbacks as props for data fetching

* add support for streams

* update lock file

* Migrate helpers from web-shared to core

* Migrate helpers from web-shared to core

* Migrate helpers from web-shared to core

* Migrate helpers from web-shared to core

* Fix claude's comments

* Fix server actions bug for web

* fix copilot bugs
2026-02-06 13:16:48 -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
Pranay Prakash 01732dac93 [docs] Add single-region limitation to Vercel World (#953)
* [docs] Add single-region limitation to Vercel World page

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

* [docs] Use bullet point format for limitations section

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 11:52:26 -08:00
Pranay Prakash 088de0ae42 Various Performance Improvements (#932)
* Parallelize async operations in step handler for performance

- Parallelize getPort(), getSpanKind(), and world.steps.get() calls
- Start step_started event creation while hydrating arguments (CPU work)
- Parallelize step_completed event with trace serialization

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

* Fix race condition: await step_started before hydration

Reverts Optimization 1 to fix a race condition where hydrateStepArguments()
could throw before stepStartedPromise was awaited, causing stale step.attempt
in the catch handler and potentially allowing extra retries.

Optimizations 0 and 2 are preserved as they don't have this issue.

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

* Skip initial world.steps.get() in step handler for performance

Eliminate the world.steps.get() HTTP call by calling step_started first
and relying on server-side validation. This saves 50-80ms per step
execution by removing one HTTP round-trip.

The server (workflow-server) now validates:
- Step not in terminal state (returns 409)
- retryAfter timestamp reached (returns 425 with Retry-After header)
- Workflow still active (returns 410 if completed)

Changes:
- Remove world.steps.get() from initial Promise.all
- Call step_started first to get step entity and validate state
- Handle 409 (terminal state) by re-queueing workflow
- Handle 425 (retryAfter not reached) by returning timeout
- Handle 410 (workflow gone) as no-op

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

* Add retryAfter validation to local and postgres worlds

Add server-side retryAfter validation to match workflow-server behavior:
- Check retryAfter timestamp before allowing step_started
- Return HTTP 425 with retryAfter timestamp in response meta
- Clear retryAfter field when step starts successfully

This ensures consistent behavior across all world implementations
and allows the step-handler optimization to work correctly.

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

* Fix step terminal state HTTP status code to 409 (Conflict)

Aligns local and postgres worlds with workflow-server, which returns
409 via InvalidOperationStateError for step in terminal state.

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

* Fix world-vercel telemetry to use parent application's tracer

The world-vercel package was creating spans under a separate
'workflow-world-vercel' service name, causing HTTP spans for
workflow-server API calls (step_started, step_completed) to be
filtered out when viewing traces for the main application service.

Now uses the same 'workflow' tracer name as @workflow/core to
ensure all spans are reported under the parent application's service.

* Update /demo command to include OTEL tracing with Jaeger

- Start Jaeger container for local trace visualization
- Configure OTEL exporter environment variables for dev server
- Open Jaeger UI automatically
- Add documentation about available trace attributes

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

* Add OTEL instrumentation to world-local and improve trace consistency

- Add telemetry.ts and instrumentObject.ts to world-local for tracing parity
  with world-vercel (world.runs, world.steps, world.events, world.hooks spans)
- Change workflow span name from uppercase "WORKFLOW" to lowercase "workflow"
  for consistency with step spans and OTEL naming conventions
- Add step.execute child span to trace actual user step function execution
  separately from step handler infrastructure

These changes enable local development to have the same observability as
production deployments, making performance analysis and debugging easier.

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

* Use uppercase WORKFLOW and STEP span names for consistency with HTTP spans

HTTP spans use uppercase methods like "GET /path" and "POST /path".
Following the same convention, workflow and step spans now use:
- WORKFLOW <workflow-name>
- STEP <step-name>

Child spans (workflow.run, workflow.loadEvents, step.execute, world.events.create)
remain lowercase as they represent internal operations, not top-level entries.

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

* Add W3C trace context headers to step queue messages

Include traceparent and tracestate headers when queueing step
execution messages. This enables automatic trace propagation
by Vercel's infrastructure, potentially linking step invocation
spans to the parent workflow trace.

The trace carrier is now serialized once and included in both:
- Payload: for manual context restoration in step handler
- Headers: for automatic HTTP-based trace propagation

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

* Improve OTEL tracing with service attribution and enhanced instrumentation

- Add peer.service attributes for workflow-server and VQS for Datadog service maps
- Rename queueMessage span to queue.publish for consistency
- Add step.hydrate, step.dehydrate, and workflow.replay spans
- Include event type in world.events.create span names (e.g., "world.events.create step_started")
- Add span.recordException() for errors with category classification (fatal/retryable/transient)
- Add span events for milestones: retry.scheduled, step.skipped, step.delayed
- Add HTTP semantic conventions with peer.service for world-vercel HTTP calls
- Add baggage propagation for workflow context (run_id, workflow_name)

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

* Update changesets to reflect all PR changes

- step-handler-parallelization.md: Add race condition fix and 409 status code fix
- world-vercel-telemetry-tracer.md: Add peer.service and event type in span names
- otel-tracing-improvements.md: New changeset for comprehensive OTEL improvements

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

* Use span name for rpc.method to show event type in Datadog resource

Datadog derives the resource name from rpc.method attribute. Updated to
use the full span name (which includes event type) instead of just the
method name, so Datadog shows "world.events.create step_started" instead
of "world.events.create workflow-server".

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

* Use lazy ref resolution for events where client discards response data

Skip expensive S3 ref resolution (~200-460ms) for event types where
the client doesn't use the response entity data (step_created,
step_completed, step_failed, run_completed, etc). Only resolve refs
for run_created, run_started, and step_started where the client
reads the response.

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

* Update changeset to include lazy ref resolution optimization

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

* Address PR review comments: module scope const, comment cleanup, status code audit

- Move eventsNeedingResolve Set to module scope (PR review #2)
- Rewrite changelog-style OPTIMIZATION comments as current-state docs (PR review #4)
- Fix run terminal state errors: 410 → 409 in world-local and world-postgres to
  match workflow-server's InvalidOperationStateError (409) (PR review #3)
- Fix remaining step terminal state 410 → 409 in world-postgres fallback paths

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 11:52:03 -08:00
Karthik Kalyan fc077108ef Remove dirs option (#961) 2026-02-05 22:56:03 -08:00
Nathan Rajlich 90ca1eff27 Remove "beads" config (#952)
* Remove "beads" config

* Remove .beads
2026-02-05 16:19:16 -08:00
Nathan Rajlich c28d6ca660 Upload Next.js server logs as artifact for Windows E2E (#946) 2026-02-05 11:10:22 -08:00
Nathan Rajlich efb33b2b5e Pass class as this context to custom serializer/deserializer methods (#947)
* fix: pass class as this context to custom serializer/deserializer methods

When calling WORKFLOW_SERIALIZE and WORKFLOW_DESERIALIZE static methods,
use .call(ctor, value) and .call(cls, data) respectively to ensure the
class is passed as 'this' context. This is necessary for serializers that
access static properties or methods via 'this'.

Adds test case to verify this behavior.

* fix: address PR review feedback

- Fix test to actually use `this` instead of `Counter` directly, which
  properly validates the fix
- Standardize variable naming: rename `ctor` to `cls` in the Instance
  reducer for consistency with the reviver

* Add changeset

* fix: use this in test serde functions with biome-ignore

The test now properly uses `this.serializedCount` and `this.deserializedCount`
to validate the fix. Added biome-ignore comments to prevent the linter from
auto-fixing `this` back to the class name.
2026-02-05 11:09:53 -08:00
Peter Wielander 4712931c26 [docs] Fix image link in NestJS getting started guide (#941) 2026-02-05 09:44:27 -08:00
Pranay Prakash 0ce46b91d9 Add x-workflow-run-id header to queue messages (#922)
* Add x-workflow-run-id header to queue messages

Pass the workflow run ID as a custom header when enqueueing messages, enabling better observability and correlation with VQS server logs.

- Add headers field to QueueOptions interface in @workflow/world
- Pass headers through to VQS client in @workflow/world-vercel
- Include x-workflow-run-id header in all queueMessage calls

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

* Upgrade @vercel/queue to 0.0.0-alpha.36

This version includes the headers support needed for passing x-workflow-run-id to VQS.

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

* Pass custom headers through world-local queue implementation

Custom headers are now spread first in the fetch headers so that system
headers (x-vqs-*, content-type) take precedence and cannot be overridden.

Also adds TODO comment in world-postgres noting headers are not propagated.

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 20:34:12 -08:00
Pranay Prakash fed805a15f Bump Next.js and React in workbenches (#944)
* Bump Next.js and React in workbenches

- Next.js: 16.0.10 → 16.1.6 in nextjs-turbopack, nextjs-webpack, swc-playground workbenches
- Next.js: 16.0.10 → 16.1.6 in @workflow/next devDependencies (for type compatibility)
- React/React-DOM: ^19.0.0/19.2.1 → 19.2.4

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

* Add changeset

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 18:07:14 -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
Pranay Prakash e0061b861d Consolidate console logging to structured logger utility (#935)
* Consolidate console logging to structured logger utility

Replace all console.log, console.warn, and console.error calls in
packages/core/src with the structured logger utility from logger.ts.
This provides consistent, filterable logging with OpenTelemetry
integration.

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

* Add changeset

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

* Improve logging: fix levels and ensure visibility

- Logger now outputs error/warn to console (always visible, not just when DEBUG enabled)
- Downgrade warn → info for expected states (OTel unavailable, workflow/step already completed, idempotency cases)
- Downgrade error → warn for transient failures (step invoked erroneously, error with retry pending)
- Remove verbose debug logs from hot paths (events-consumer)

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 16:16:46 -08:00
Pranay Prakash 79e988fa85 Add improved OpenTelemetry instrumentation for workflow observability (#933)
* Add improved OpenTelemetry instrumentation for workflow observability

- Add tracing to HTTP requests in world-vercel with method, endpoint, and status attributes
- Add tracing to storage operations (runs, steps, events, hooks)
- Add tracing to event loading with event count and pages loaded attributes
- Add queue timing breakdown attributes (deserialize, execution, serialize times)
- Add new semantic conventions for world/storage, events, serialization, and queue breakdown

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

* Split changeset into separate entries for core and world-vercel

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

* Update OTEL instrumentation to use standard semantic conventions

- Replace custom world.http.* attributes with standard OTEL HTTP conventions
  (http.request.method, http.response.status_code, url.full, server.address, server.port)
- Replace custom queue.* attributes with standard OTEL messaging conventions
  (messaging.system, messaging.destination.name, messaging.message.id, messaging.operation.type)
- Add error.type attribute for HTTP error spans
- Add span.recordException() for proper error recording
- Namespace workflow-specific attributes under workflow.* prefix
- Fix span naming: use "HTTP {method}" instead of "WORLD.http {method} {endpoint}"

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

* Address PR review comments

- Remove unused semantic conventions (SerializeFormat, SerializeBytes, DeserializeFormat, DeserializeBytes, WorldParseBytes)
- Add documentation explaining intentional duplication in world-vercel/telemetry.ts
- Add documentation explaining why WorkflowSuspension isn't handled in world-vercel
- Add comment about deserialize timing measurement limitation

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

* Use lowercase span names per OTEL semantic conventions

- world.runs, world.steps, world.events, world.hooks (storage)
- world.parse, world.validate (HTTP parsing)
- http {method} (HTTP client spans)
- workflow.run, workflow.start, workflow.loadEvents
- step {name}, hook.resume

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 16:12:30 -08:00
Nathan Rajlich 2506f9e107 Add debug-windows workflow with tmate SSH access for debugging Windows CI issues (#937) 2026-02-04 15:08:35 -08:00
Nathan Rajlich ad21f3f608 Add configurable moduleSpecifier value for SWC Playground (#936) 2026-02-04 14:40:25 -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 b895446bc3 Show git commit sha in swc-playground (#934) 2026-02-04 11:37:46 -08:00
JJ Kasper 8ab1ba24d6 Add Next.js cache invalidation on swc transform change (#926)
* Add Next.js cache invalidation on swc transform change

* fix exports

* update distDir

* Use build-hash instead of package version

* refactor to util
2026-02-04 09:56:37 -08:00
Nathan Rajlich 08e1169061 Add "swc-playground" workbench app (#930) 2026-02-04 09:28:02 -08:00