Skip to content

Generate runId client-side in start() and simplify streaming types#954

Merged
TooTallNate merged 1 commit intomainfrom
nate/client-side-runid
Feb 8, 2026
Merged

Generate runId client-side in start() and simplify streaming types#954
TooTallNate merged 1 commit intomainfrom
nate/client-side-runid

Conversation

@TooTallNate
Copy link
Member

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).

@vercel
Copy link
Contributor

vercel bot commented Feb 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
example-nextjs-workflow-turbopack Ready Ready Preview, Comment Feb 8, 2026 8:12am
example-nextjs-workflow-webpack Ready Ready Preview, Comment Feb 8, 2026 8:12am
example-workflow Ready Ready Preview, Comment Feb 8, 2026 8:12am
workbench-astro-workflow Ready Ready Preview, Comment Feb 8, 2026 8:12am
workbench-express-workflow Ready Ready Preview, Comment Feb 8, 2026 8:12am
workbench-fastify-workflow Ready Ready Preview, Comment Feb 8, 2026 8:12am
workbench-hono-workflow Ready Ready Preview, Comment Feb 8, 2026 8:12am
workbench-nitro-workflow Ready Ready Preview, Comment Feb 8, 2026 8:12am
workbench-nuxt-workflow Ready Ready Preview, Comment Feb 8, 2026 8:12am
workbench-sveltekit-workflow Ready Ready Preview, Comment Feb 8, 2026 8:12am
workbench-vite-workflow Ready Ready Preview, Comment Feb 8, 2026 8:12am
workflow-docs Ready Ready Preview, Comment, Open in v0 Feb 8, 2026 8:12am
workflow-nest Ready Ready Preview, Comment Feb 8, 2026 8:12am
workflow-swc-playground Ready Ready Preview, Comment Feb 8, 2026 8:12am

Copilot AI review requested due to automatic review settings February 6, 2026 01:49
@changeset-bot
Copy link

changeset-bot bot commented Feb 6, 2026

🦋 Changeset detected

Latest commit: c9082c5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
@workflow/core Patch
@workflow/world Patch
@workflow/builders Patch
@workflow/cli Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/web-shared Patch
workflow Patch
@workflow/world-local Patch
@workflow/world-postgres Patch
@workflow/world-testing Patch
@workflow/world-vercel Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/nuxt Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 0.031s (-8.0% 🟢) 1.005s (~) 0.973s 10 1.00x
💻 Local Nitro 0.033s (+31.6% 🔺) 1.005s (~) 0.972s 10 1.07x
🐘 Postgres Express 0.159s (-27.5% 🟢) 1.010s (~) 0.851s 10 5.08x
🐘 Postgres Nitro 0.501s (+342.2% 🔺) 1.010s (~) 0.508s 10 16.07x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 0.897s (+3.2%) 2.803s (+13.8% 🔺) 1.906s 10 1.00x
▲ Vercel Express 0.961s (+0.7%) 2.859s (+3.9%) 1.898s 10 1.07x
▲ Vercel Nitro 1.030s (+26.7% 🔺) 2.630s (-0.9%) 1.600s 10 1.15x

🔍 Observability: Next.js (Turbopack) | Express | Nitro

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 1.105s (~) 2.005s (~) 0.900s 10 1.00x
💻 Local Nitro 1.109s (+3.3%) 2.006s (~) 0.897s 10 1.00x
🐘 Postgres Express 2.325s (-5.4% 🟢) 3.014s (~) 0.689s 10 2.10x
🐘 Postgres Nitro 2.379s (-2.3%) 3.014s (~) 0.636s 10 2.15x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.713s (~) 4.146s (+3.3%) 1.433s 10 1.00x
▲ Vercel Next.js (Turbopack) 2.778s (~) 3.981s (~) 1.203s 10 1.02x
▲ Vercel Nitro 2.813s (+4.2%) 4.122s (+2.9%) 1.308s 10 1.04x

🔍 Observability: Express | Next.js (Turbopack) | Nitro

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 10.831s (~) 11.022s (~) 0.191s 3 1.00x
💻 Local Nitro 10.851s (+2.9%) 11.022s (~) 0.172s 3 1.00x
🐘 Postgres Nitro 20.224s (-0.6%) 21.059s (~) 0.835s 2 1.87x
🐘 Postgres Express 20.373s (~) 21.057s (~) 0.684s 2 1.88x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 19.625s (-4.1%) 21.007s (-5.3% 🟢) 1.382s 2 1.00x
▲ Vercel Next.js (Turbopack) 19.983s (-3.2%) 21.787s (~) 1.804s 2 1.02x
▲ Vercel Nitro 20.271s (-1.6%) 21.301s (-5.7% 🟢) 1.030s 2 1.03x

🔍 Observability: Express | Next.js (Turbopack) | Nitro

workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 27.459s (~) 28.051s (~) 0.592s 3 1.00x
💻 Local Nitro 27.513s (+2.8%) 28.053s (+3.7%) 0.540s 3 1.00x
🐘 Postgres Nitro 38.331s (-23.9% 🟢) 38.595s (-24.5% 🟢) 0.263s 2 1.40x
🐘 Postgres Express 50.367s (~) 51.120s (~) 0.753s 2 1.83x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 47.767s (-8.3% 🟢) 50.065s (-6.5% 🟢) 2.298s 2 1.00x
▲ Vercel Next.js (Turbopack) 48.350s (-8.1% 🟢) 49.826s (-8.3% 🟢) 1.476s 2 1.01x
▲ Vercel Nitro 48.580s (-3.4%) 50.301s (-4.1%) 1.721s 2 1.02x

🔍 Observability: Express | Next.js (Turbopack) | Nitro

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 57.158s (~) 58.106s (~) 0.948s 2 1.00x
💻 Local Nitro 57.221s (+2.9%) 58.102s (+3.6%) 0.881s 2 1.00x
🐘 Postgres Nitro 75.254s (-23.0% 🟢) 76.177s (-22.4% 🟢) 0.923s 2 1.32x
🐘 Postgres Express 75.468s (-24.8% 🟢) 75.670s (-25.2% 🟢) 0.202s 2 1.32x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 101.896s (+0.8%) 103.003s (-0.9%) 1.107s 1 1.00x
▲ Vercel Express 102.641s (-1.3%) 104.584s (-1.4%) 1.943s 1 1.01x
▲ Vercel Next.js (Turbopack) 104.787s (-1.0%) 106.421s (~) 1.634s 1 1.03x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 1.400s (-2.0%) 2.005s (~) 0.605s 15 1.00x
💻 Local Nitro 1.404s (+3.9%) 2.005s (~) 0.601s 15 1.00x
🐘 Postgres Nitro 1.877s (-20.4% 🟢) 2.320s (-23.0% 🟢) 0.443s 13 1.34x
🐘 Postgres Express 2.025s (-14.1% 🟢) 2.515s (-16.5% 🟢) 0.490s 12 1.45x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.934s (+3.2%) 4.357s (+2.7%) 1.423s 7 1.00x
▲ Vercel Express 2.981s (-11.2% 🟢) 4.576s (-8.9% 🟢) 1.596s 7 1.02x
▲ Vercel Next.js (Turbopack) 3.083s (+3.8%) 4.661s (+12.0% 🔺) 1.578s 7 1.05x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 2.572s (-3.0%) 3.007s (~) 0.435s 10 1.00x
💻 Local Nitro 2.589s (+15.7% 🔺) 3.007s (~) 0.418s 10 1.01x
🐘 Postgres Nitro 7.555s (-21.1% 🟢) 8.039s (-17.8% 🟢) 0.484s 4 2.94x
🐘 Postgres Express 10.632s (+40.5% 🔺) 11.366s (+41.6% 🔺) 0.734s 3 4.13x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.162s (-1.6%) 4.571s (+5.8% 🔺) 1.409s 7 1.00x
▲ Vercel Nitro 3.246s (~) 4.685s (+1.9%) 1.440s 7 1.03x
▲ Vercel Next.js (Turbopack) 3.622s (+13.1% 🔺) 5.743s (+29.5% 🔺) 2.122s 6 1.15x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 7.207s (-5.1% 🟢) 8.024s (~) 0.817s 4 1.00x
💻 Local Nitro 7.297s (+20.5% 🔺) 8.024s (+21.2% 🔺) 0.726s 4 1.01x
🐘 Postgres Nitro 47.245s (+3.7%) 48.122s (+4.3%) 0.877s 1 6.56x
🐘 Postgres Express 52.096s (+5.3% 🔺) 53.123s (+5.9% 🔺) 1.027s 1 7.23x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 3.513s (-51.0% 🟢) 5.418s (-37.6% 🟢) 1.905s 6 1.00x
▲ Vercel Next.js (Turbopack) 3.971s (-53.3% 🟢) 6.069s (-40.0% 🟢) 2.098s 5 1.13x
▲ Vercel Express 5.244s (+2.2%) 6.580s (-4.7%) 1.336s 5 1.49x

🔍 Observability: Nitro | Next.js (Turbopack) | Express

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 1.403s (-1.7%) 2.004s (~) 0.601s 15 1.00x
💻 Local Nitro 1.435s (+5.1% 🔺) 2.005s (~) 0.570s 15 1.02x
🐘 Postgres Nitro 1.978s (-14.2% 🟢) 2.154s (-23.9% 🟢) 0.176s 14 1.41x
🐘 Postgres Express 2.064s (-3.9%) 2.680s (~) 0.616s 12 1.47x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.613s (-30.7% 🟢) 4.034s (-23.3% 🟢) 1.421s 8 1.00x
▲ Vercel Express 2.647s (-50.2% 🟢) 4.064s (-40.3% 🟢) 1.417s 8 1.01x
▲ Vercel Next.js (Turbopack) 2.746s (-19.6% 🟢) 4.177s (-8.5% 🟢) 1.432s 8 1.05x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 2.664s (-4.4%) 3.007s (~) 0.343s 10 1.00x
💻 Local Nitro 2.728s (+14.8% 🔺) 3.007s (~) 0.279s 10 1.02x
🐘 Postgres Nitro 10.811s (+9.2% 🔺) 11.370s (+9.7% 🔺) 0.559s 3 4.06x
🐘 Postgres Express 13.208s (+7.3% 🔺) 13.369s (+5.3% 🔺) 0.161s 3 4.96x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.873s (-6.2% 🟢) 4.139s (-3.2%) 1.266s 8 1.00x
▲ Vercel Nitro 2.970s (-2.3%) 4.248s (-2.1%) 1.278s 8 1.03x
▲ Vercel Next.js (Turbopack) 3.116s (+4.9%) 4.393s (+1.6%) 1.278s 7 1.08x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 7.769s (-5.4% 🟢) 8.017s (-11.1% 🟢) 0.248s 4 1.00x
💻 Local Nitro 7.814s (+13.8% 🔺) 8.020s (+11.2% 🔺) 0.206s 4 1.01x
🐘 Postgres Nitro 51.492s (-3.5%) 52.138s (-3.7%) 0.646s 1 6.63x
🐘 Postgres Express 53.449s (+1.1%) 54.121s (+1.9%) 0.672s 1 6.88x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.280s (-52.6% 🟢) 5.036s (-38.2% 🟢) 1.756s 7 1.00x
▲ Vercel Next.js (Turbopack) 3.425s (-66.3% 🟢) 4.705s (-61.1% 🟢) 1.279s 7 1.04x
▲ Vercel Nitro 3.632s (-43.7% 🟢) 5.099s (-34.2% 🟢) 1.467s 6 1.11x

🔍 Observability: Express | Next.js (Turbopack) | Nitro

Stream Benchmarks (includes TTFB metrics)
workflow with stream

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 0.172s (-4.3%) 1.002s (~) 0.010s (-9.2% 🟢) 1.015s (~) 0.843s 10 1.00x
💻 Local Nitro 0.179s (+58.3% 🔺) 1.002s (~) 0.010s (+8.9% 🔺) 1.015s (~) 0.836s 10 1.04x
🐘 Postgres Express 1.267s (-47.7% 🟢) 1.772s (-32.3% 🟢) 0.001s (~) 2.014s (-33.2% 🟢) 0.746s 10 7.36x
🐘 Postgres Nitro 1.363s (-0.8%) 1.755s (+5.4% 🔺) 0.001s (~) 2.013s (~) 0.650s 10 7.92x
💻 Local Next.js (Turbopack) ⚠️ missing - - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - - -

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.477s (-6.6% 🟢) 3.341s (+3.7%) 0.178s (-0.8%) 4.412s (+3.3%) 1.935s 10 1.00x
▲ Vercel Nitro 2.505s (-4.7%) 3.213s (+3.1%) 0.160s (-4.2%) 4.161s (~) 1.656s 10 1.01x
▲ Vercel Next.js (Turbopack) 2.644s (-6.5% 🟢) 3.137s (-2.5%) 0.114s (-52.6% 🟢) 4.167s (-4.3%) 1.523s 10 1.07x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World 🥇 Fastest Framework Wins
💻 Local Express 12/12
🐘 Postgres Nitro 9/12
▲ Vercel Express 7/12
Fastest World by Framework

Winner determined by most benchmark wins

Framework 🥇 Fastest World Wins
Express 💻 Local 10/12
Next.js (Turbopack) ▲ Vercel 12/12
Nitro 💻 Local 10/12
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Starter: Community world (local development)
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 490 0 38 528
✅ 💻 Local Development 418 0 62 480
✅ 📦 Local Production 418 0 62 480
✅ 🐘 Local Postgres 418 0 62 480
✅ 🪟 Windows 45 0 3 48
❌ 🌍 Community Worlds 29 163 12 204
✅ 📋 Other 123 0 21 144
Total 1941 163 260 2364

❌ Failed Tests

🌍 Community Worlds (163 failed)

mongodb (40 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

redis (40 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

starter (42 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • health check (CLI) - workflow health command reports healthy endpoints
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

turso (41 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 44 0 4
✅ example 44 0 4
✅ express 44 0 4
✅ fastify 44 0 4
✅ hono 44 0 4
✅ nextjs-turbopack 47 0 1
✅ nextjs-webpack 47 0 1
✅ nitro 44 0 4
✅ nuxt 44 0 4
✅ sveltekit 44 0 4
✅ vite 44 0 4
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 41 0 7
✅ express-stable 41 0 7
✅ fastify-stable 41 0 7
✅ hono-stable 41 0 7
✅ nextjs-turbopack-stable 45 0 3
✅ nextjs-webpack-stable 45 0 3
✅ nitro-stable 41 0 7
✅ nuxt-stable 41 0 7
✅ sveltekit-stable 41 0 7
✅ vite-stable 41 0 7
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 41 0 7
✅ express-stable 41 0 7
✅ fastify-stable 41 0 7
✅ hono-stable 41 0 7
✅ nextjs-turbopack-stable 45 0 3
✅ nextjs-webpack-stable 45 0 3
✅ nitro-stable 41 0 7
✅ nuxt-stable 41 0 7
✅ sveltekit-stable 41 0 7
✅ vite-stable 41 0 7
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 41 0 7
✅ express-stable 41 0 7
✅ fastify-stable 41 0 7
✅ hono-stable 41 0 7
✅ nextjs-turbopack-stable 45 0 3
✅ nextjs-webpack-stable 45 0 3
✅ nitro-stable 41 0 7
✅ nuxt-stable 41 0 7
✅ sveltekit-stable 41 0 7
✅ vite-stable 41 0 7
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 45 0 3
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 3 0 0
❌ mongodb 5 40 3
✅ redis-dev 3 0 0
❌ redis 5 40 3
✅ starter-dev 3 0 0
❌ starter 3 42 3
✅ turso-dev 3 0 0
❌ turso 4 41 3
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 41 0 7
✅ e2e-local-postgres-nest-stable 41 0 7
✅ e2e-local-prod-nest-stable 41 0 7

📋 View full workflow run

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request implements client-side runId generation as a prerequisite for the planned E2E encryption feature. It generates workflow run IDs using ULID (wrun_${ulid()}) in the start() function before serialization, eliminating the need for the deferred Promise<string> pattern that was previously used when runIds were server-generated.

Changes:

  • Generates runId client-side in start() using monotonic ULID factory before serialization
  • Simplifies runId types from string | Promise<string> to string throughout the serialization layer
  • Updates Storage.events.create() interface to accept string | null for the first overload (previously just null)

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/core/src/runtime/start.ts Adds client-side runId generation using ULID and verification that server accepted it; removes withResolvers pattern
packages/core/src/serialization.ts Simplifies runId parameter types from string | Promise<string> to string in all dehydrate/hydrate functions and stream classes
packages/core/src/runtime/start.test.ts Updates mock to return client-provided runId and expects wrun_ prefix instead of null
packages/core/src/writable-stream.test.ts Removes tests for Promise-based runId handling; updates error messages
packages/world/src/interfaces.ts Updates Streamer methods and Storage.events.create() signature to use plain string runId
packages/world/src/events.ts Updates comment for RunCreatedEventRequest
packages/world-vercel/src/events.ts Updates comment to reflect client-provided runId support
packages/world-postgres/src/storage.ts Updates comment to reflect client-provided runId support
packages/world-local/src/storage/events-storage.ts Updates comment to reflect client-provided runId support
.opencode/plans/e2e-encryption-plan.md Adds comprehensive E2E encryption implementation plan that relies on client-side runId generation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Member Author

TooTallNate commented Feb 6, 2026

@TooTallNate TooTallNate force-pushed the nate/client-side-runid branch from 49b2939 to c9082c5 Compare February 8, 2026 08:09
@TooTallNate TooTallNate merged commit d9e9859 into main Feb 8, 2026
152 of 153 checks passed
@TooTallNate TooTallNate deleted the nate/client-side-runid branch February 8, 2026 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants