Skip to content

Commit 2d8b8a3

Browse files
pranaygpclaude
andauthored
feat(world-vercel): export openEventsChannel for writers outside a queue delivery (#4469)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 1aad998 commit 2d8b8a3

4 files changed

Lines changed: 68 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@workflow/world-vercel': patch
3+
---
4+
5+
Export `openEventsChannel` so code writing a run's events outside a queue delivery can use the WebSocket events transport.

‎packages/world-vercel/README.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,30 @@ Backend connection failures and interrupted event streams follow existing retry
1212

1313
See [Backend connection failures](https://workflow-sdk.dev/docs/foundations/errors-and-retries#backend-connection-failures) for retry behavior and diagnostics.
1414

15+
## Events channel
16+
17+
Event writes go over a per-run WebSocket (the default `WORKFLOW_EVENTS_TRANSPORT`)
18+
only while that run's channel is open. The queue handler opens it for each
19+
delivery, so workflows need nothing extra. Code that writes a run's events
20+
outside a delivery (a custom driver, a long-lived process) opens and releases
21+
it itself; otherwise those writes go over HTTP:
22+
23+
```ts
24+
import { createWorld, openEventsChannel } from '@workflow/world-vercel';
25+
26+
const world = createWorld();
27+
const release = openEventsChannel(runId);
28+
try {
29+
await world.events.create(runId, event);
30+
} finally {
31+
release?.();
32+
}
33+
```
34+
35+
It returns `undefined`, and writes stay on HTTP, when the transport is
36+
disabled or the World cannot hold a socket (a `projectConfig` World, as the
37+
CLI uses).
38+
1539
## Custom dispatcher
1640

1741
HTTP requests (including the queue) default to a shared undici `RetryAgent` that handles connection pooling and retries. Pass a custom `dispatcher` to override it, for example, to tune undici on newer Node.js runtimes:
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { afterEach, describe, expect, it } from 'vitest';
2+
import { openEventsChannel } from './index.js';
3+
4+
describe('openEventsChannel', () => {
5+
const previous = process.env.WORKFLOW_EVENTS_TRANSPORT;
6+
afterEach(() => {
7+
if (previous === undefined) delete process.env.WORKFLOW_EVENTS_TRANSPORT;
8+
else process.env.WORKFLOW_EVENTS_TRANSPORT = previous;
9+
});
10+
11+
it('is exported from the package root', () => {
12+
expect(typeof openEventsChannel).toBe('function');
13+
});
14+
15+
it('returns undefined, so writes stay on HTTP, when the transport is disabled', () => {
16+
process.env.WORKFLOW_EVENTS_TRANSPORT = 'http';
17+
expect(
18+
openEventsChannel('wrun_01ARZ3NDEKTSV4RRFFQ69G5FAV')
19+
).toBeUndefined();
20+
});
21+
22+
it('returns undefined for a projectConfig World, which cannot hold a socket', () => {
23+
delete process.env.WORKFLOW_EVENTS_TRANSPORT;
24+
expect(
25+
openEventsChannel('wrun_01ARZ3NDEKTSV4RRFFQ69G5FAV', {
26+
projectConfig: { projectId: 'prj_test', teamId: 'team_test' },
27+
} as never)
28+
).toBeUndefined();
29+
});
30+
});

‎packages/world-vercel/src/index.ts‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ export { createQueue } from './queue.js';
2222
export { createStorage } from './storage.js';
2323
export { createStreamer } from './streamer.js';
2424
export type { APIConfig } from './utils.js';
25+
/**
26+
* Open a run's WebSocket events channel and return its release (or
27+
* `undefined` when the World writes over HTTP). Event writes for that run go
28+
* over the socket while at least one claim is held. The flow route already
29+
* does this for queue deliveries; call it yourself when you write a run's
30+
* events from anywhere else, and call the release when you are done, or the
31+
* open socket keeps the process alive.
32+
*/
33+
export { openWsChannel as openEventsChannel } from './ws-transport.js';
2534

2635
export function createWorld(config?: APIConfig): World {
2736
// Project ID for HKDF key derivation context.

0 commit comments

Comments
 (0)