Generate runId client-side in start() and simplify streaming types#954
Generate runId client-side in start() and simplify streaming types#954TooTallNate merged 1 commit intomainfrom
runId client-side in start() and simplify streaming types#954Conversation
🦋 Changeset detectedLatest commit: c9082c5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 18 packages
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 |
📊 Benchmark Results
workflow with no steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express | Nitro workflow with 1 step💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) | Nitro workflow with 10 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) | Nitro workflow with 25 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) | Nitro workflow with 50 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) Promise.all with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) Promise.all with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) Promise.all with 50 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Next.js (Turbopack) | Express Promise.race with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) Promise.race with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) Promise.race with 50 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) | Nitro Stream Benchmarks (includes TTFB metrics)workflow with stream💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) SummaryFastest Framework by WorldWinner determined by most benchmark wins
Fastest World by FrameworkWinner determined by most benchmark wins
Column Definitions
Worlds:
|
🧪 E2E Test Results❌ Some tests failed Summary
❌ Failed Tests🌍 Community Worlds (163 failed)mongodb (40 failed):
redis (40 failed):
starter (42 failed):
turso (41 failed):
Details by Category✅ ▲ Vercel Production
✅ 💻 Local Development
✅ 📦 Local Production
✅ 🐘 Local Postgres
✅ 🪟 Windows
❌ 🌍 Community Worlds
✅ 📋 Other
|
There was a problem hiding this comment.
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>tostringthroughout the serialization layer - Updates Storage.events.create() interface to accept
string | nullfor the first overload (previously justnull)
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.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
f99520a to
96619e7
Compare
runId client-side in start() and simplify streaming types
49b2939 to
c9082c5
Compare

Summary
runIdclient-side instart()using ULID (wrun_${ulid()}), instead of deferring to the serverrunIdtoevents.create()and verifies the server accepted itrunIdtypes fromstring | Promise<string>tostringthroughout the serialization layerwithResolvers<string>()/ deferred runId pattern that was needed whenrunIdwas server-generatedStreamerinterface andWorkflowServerWritableStreamto use plainstringrunIdStorage.events.create()first overload to acceptstring | nullinstead of justnullThis is a prerequisite for E2E encryption, where we need the
runIdbefore serialization so it can be used as part of the encryption context.Test plan
All existing tests pass. Updated
start.test.tsto expect client-generated runId, removedwritable-stream.test.tspromise runId test (no longer applicable).