@ewhauser/world-celld 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 0.3.1 (2026-08-19)
6
+
7
+ ## What's Changed
8
+ * perf: reduce runs.list RPC fanout by @ewhauser in https://github.com/ewhauser/world-celld/pull/21
9
+ * perf: remove unused correlation index by @ewhauser in https://github.com/ewhauser/world-celld/pull/23
10
+ * perf: bound QueueDO inflight deadline work by @ewhauser in https://github.com/ewhauser/world-celld/pull/24
11
+ * chore(deps-dev): bump @types/node from 22.20.1 to 26.1.2 by @dependabot[bot] in https://github.com/ewhauser/world-celld/pull/4
12
+ * chore(deps-dev): bump the development-dependencies group across 1 directory with 2 updates by @dependabot[bot] in https://github.com/ewhauser/world-celld/pull/25
13
+ * perf: batch and long-poll stream I/O by @ewhauser in https://github.com/ewhauser/world-celld/pull/26
14
+ * perf: bound cleanup and batch Durable Object storage by @ewhauser in https://github.com/ewhauser/world-celld/pull/27
15
+ * perf: shard workflow indexes by @ewhauser in https://github.com/ewhauser/world-celld/pull/28
16
+
17
+
18
+ **Full Changelog**: https://github.com/ewhauser/world-celld/compare/v0.3.0...v0.3.1
19
+
20
+ ## 0.3.0 (2026-08-16)
21
+
22
+ ## What's Changed
23
+ * fix: split Release Please release and PR phases by @ewhauser in https://github.com/ewhauser/world-celld/pull/16
24
+ * feat: target Workflow 5 beta by @ewhauser in https://github.com/ewhauser/world-celld/pull/17
25
+ * fix: enforce Workflow 5 storage contracts by @ewhauser in https://github.com/ewhauser/world-celld/pull/19
26
+
27
+
28
+ **Full Changelog**: https://github.com/ewhauser/world-celld/compare/v0.2.0...v0.3.0
29
+
5
30
  ## 0.2.0 (2026-08-16)
6
31
 
7
32
  ## What's Changed
package/README.md CHANGED
@@ -115,39 +115,60 @@ More deployment detail is in [`celld-worker/README.md`](./celld-worker/README.md
115
115
  ```text
116
116
  Workflow application
117
117
  |
118
- | authenticated HTTP RPC
118
+ | authenticated HTTP RPC + binary stream batches
119
119
  v
120
120
  celld worker router
121
121
  |-- WorkflowRunDO one cell per workflow run
122
+ |-- RunCatalogDO 16 stable run-id shards; merged ordered listing
123
+ |-- RunFenceDO one lifecycle fence cell per workflow run
124
+ |-- HookTokenDO 32 stable token-ownership shards
125
+ |-- HookIdDO 32 stable hook-id lookup shards
122
126
  |-- StreamDO stream chunks and run/stream indexes
123
- |-- IndexDO run and hook lookup indexes
124
127
  `-- QueueDO delayed delivery, retries, and dead letters
125
128
  |
126
129
  | HTTP callbacks
127
130
  v
128
- Workflow application /.well-known/workflow/v1/{flow|step}
131
+ Workflow application /.well-known/workflow/v1/flow
129
132
  ```
130
133
 
131
134
  The application-side package implements the Workflow `World` interface and
132
- translates its storage, stream, and queue operations into RPC calls. The celld
133
- worker accepts only a fixed set of methods and routes each request to the named
134
- cell that owns the data.
135
+ translates its storage and queue operations into JSON RPC calls. Stream chunk
136
+ writes and bounded long-poll reads use a binary batch route; stream control and
137
+ retention operations remain fixed, authenticated RPC methods. The worker routes
138
+ each request to the named cell that owns the data.
139
+
140
+ Index routing is a versioned hard-cutover protocol. Run catalog writes hash the
141
+ `runId` across 16 shards, while hook ownership and hook-ID lookup hash their
142
+ natural keys across 32 shards each. A single stateless worker request queries
143
+ all 16 catalog shards in parallel and merges their lexicographic pages before
144
+ authoritative RunDO reads. A terminal or expired run is hidden through its own
145
+ `RunFenceDO`, so no global fence cell remains. Token and hook-ID admission are
146
+ each transactional inside their natural-key shards. The RunDO remains the
147
+ authoritative commit domain, and exact claim IDs plus a serialized cancellation
148
+ fence resolve ambiguous delivery without pretending the two ownership shards
149
+ form a cross-Durable-Object transaction. Stateless cohesive index routes keep
150
+ catalog listing, terminal commits, hook finalization, and hook release to one
151
+ public request each while exposing the internal shard work in measurements.
152
+
153
+ The routing rationale and before/after RPC, storage, latency, and contention
154
+ evidence are recorded in [`docs/index-sharding.md`](./docs/index-sharding.md).
135
155
 
136
156
  ## Configuration
137
157
 
138
158
  Application options can be passed to `createCelldWorld()` unless an environment
139
159
  variable is shown below.
140
160
 
141
- | Option | Environment variable | Default |
142
- | ---------------- | ------------------------ | ------------------------ |
143
- | `fleetUrl` | `CELLD_FLEET_URL` | required |
144
- | `secret` | `CELLD_WORLD_SECRET` | required with `fleetUrl` |
145
- | `baseUrl` | `WORKFLOW_BASE_URL` | `http://localhost:$PORT` |
146
- | `deploymentId` | `CELLD_DEPLOYMENT_ID` | `celld-default` |
147
- | `queueShards` | — | `1` |
148
- | `runRetentionMs` | `CELLD_RUN_RETENTION_MS` | `0` (disabled) |
149
- | `readPollMs` | — | `250` |
150
- | `rpcTimeoutMs` | — | `30000` |
161
+ | Option | Environment variable | Default |
162
+ | ----------------------- | ------------------------ | ------------------------ |
163
+ | `fleetUrl` | `CELLD_FLEET_URL` | required |
164
+ | `secret` | `CELLD_WORLD_SECRET` | required with `fleetUrl` |
165
+ | `baseUrl` | `WORKFLOW_BASE_URL` | `http://localhost:$PORT` |
166
+ | `deploymentId` | `CELLD_DEPLOYMENT_ID` | `celld-default` |
167
+ | `queueShards` | — | `1` |
168
+ | `runRetentionMs` | `CELLD_RUN_RETENTION_MS` | `0` (disabled) |
169
+ | `streamLongPollMs` | — | `20000` |
170
+ | `streamFlushIntervalMs` | — | `0` |
171
+ | `rpcTimeoutMs` | — | `30000` |
151
172
 
152
173
  The deployed worker also accepts these celld variables:
153
174
 
@@ -156,7 +177,7 @@ The deployed worker also accepts these celld variables:
156
177
  | `WORLD_SECRET` | none | Required bearer secret for RPC routes |
157
178
  | `WORKFLOW_CALLBACK_SECRET` | none | Sent with deliveries as `x-workflow-callback-secret` |
158
179
  | `QUEUE_MAX_ATTEMPTS` | `5` | Attempts before a message is dead-lettered |
159
- | `QUEUE_MAX_INFLIGHT` | `5` | Concurrent deliveries per queue cell |
180
+ | `QUEUE_MAX_INFLIGHT` | `5` | Concurrent deliveries per queue cell (maximum `128`) |
160
181
  | `QUEUE_DELIVERY_TIMEOUT_MS` | `300000` | Timeout for an application callback |
161
182
 
162
183
  `queueShards` is part of queue placement and is pinned when a queue cell is
@@ -171,8 +192,13 @@ pending runs are never eligible for automatic cleanup.
171
192
 
172
193
  At expiration, the run cell fences new writes and removes the run's derived
173
194
  indexes, stream chunks, pending and dead-letter queue messages, and durable run
174
- payloads. Cleanup is a persisted, idempotent state machine: an interrupted
175
- phase records its error and re-arms itself with capped backoff.
195
+ payloads. Cleanup is a persisted, idempotent state machine. Each alarm processes
196
+ one bounded page, persists its progress, and re-arms the next alarm; an
197
+ interrupted phase records its error and retries with capped backoff.
198
+
199
+ Terminal hook and wait disposal uses the same alarm mechanism even when run
200
+ retention is disabled, so a terminal event never performs an unbounded storage
201
+ transaction.
176
202
 
177
203
  The final state is a metadata-only tombstone, not an empty cell. It prevents a
178
204
  delayed queue delivery or stale RPC from recreating an expired run. Reads and
@@ -199,6 +225,8 @@ an existing terminal run that has no cleanup record.
199
225
  must be idempotent.
200
226
  - Queue cells expose `stats`, `listDeadLetters`, `redriveDeadLetter`,
201
227
  `purgeDeadLetters`, and `rearmAlarm` through the authenticated RPC endpoint.
228
+ `purgeDeadLetters` deletes at most 128 entries per call; repeat it while its
229
+ result reports `hasMore`.
202
230
  - Run cells expose retention status, scheduling, immediate cleanup, and alarm
203
231
  recovery through `world.retention`.
204
232
  - A new application URL applies to newly enqueued messages. Existing messages
@@ -1,8 +1,10 @@
1
1
  # world-celld worker
2
2
 
3
- The celld-deployable half of `@ewhauser/world-celld`: four cell classes
4
- (WorkflowRunDO, StreamDO, IndexDO, QueueDO) behind an authenticated HTTP RPC
5
- router.
3
+ The celld-deployable half of `@ewhauser/world-celld`: seven cell classes
4
+ (WorkflowRunDO, RunCatalogDO, RunFenceDO, HookTokenDO, HookIdDO, StreamDO, and
5
+ QueueDO) behind an authenticated HTTP router.
6
+ Storage, control, and queue methods use fixed JSON RPC routes; stream chunks use
7
+ bounded binary batch writes and binary long-poll reads.
6
8
 
7
9
  ## Deploy
8
10
 
@@ -2,4 +2,13 @@
2
2
  // project directory; this one-liner resolves the real worker through the
3
3
  // application's node_modules so the deployed bundle stays in step with the
4
4
  // installed @ewhauser/world-celld version.
5
- export { IndexDO, QueueDO, StreamDO, WorkflowRunDO, default } from '@ewhauser/world-celld/worker';
5
+ export {
6
+ HookIdDO,
7
+ HookTokenDO,
8
+ QueueDO,
9
+ RunCatalogDO,
10
+ RunFenceDO,
11
+ StreamDO,
12
+ WorkflowRunDO,
13
+ default,
14
+ } from '@ewhauser/world-celld/worker';
@@ -9,19 +9,30 @@
9
9
  "bindings": [
10
10
  { "name": "WORKFLOW_DB", "class_name": "WorkflowRunDO" },
11
11
  { "name": "WORKFLOW_STREAMS", "class_name": "StreamDO" },
12
- { "name": "WORKFLOW_INDEX", "class_name": "IndexDO" },
12
+ { "name": "WORKFLOW_RUN_CATALOG", "class_name": "RunCatalogDO" },
13
+ { "name": "WORKFLOW_RUN_FENCES", "class_name": "RunFenceDO" },
14
+ { "name": "WORKFLOW_HOOK_TOKENS", "class_name": "HookTokenDO" },
15
+ { "name": "WORKFLOW_HOOK_IDS", "class_name": "HookIdDO" },
13
16
  { "name": "WORKFLOW_QUEUE", "class_name": "QueueDO" },
14
17
  ],
15
18
  },
16
19
  "migrations": [
17
20
  {
18
21
  "tag": "v1",
19
- "new_sqlite_classes": ["WorkflowRunDO", "StreamDO", "IndexDO", "QueueDO"],
22
+ "new_sqlite_classes": [
23
+ "WorkflowRunDO",
24
+ "StreamDO",
25
+ "RunCatalogDO",
26
+ "RunFenceDO",
27
+ "HookTokenDO",
28
+ "HookIdDO",
29
+ "QueueDO",
30
+ ],
20
31
  },
21
32
  ],
22
33
  "vars": {
23
- // REQUIRED: bearer secret for the world's RPC surface. All /v1/rpc
24
- // routes fail closed with 503 while this is empty. Inject the real value
34
+ // REQUIRED: bearer secret for the world's RPC and binary stream surface.
35
+ // Authenticated routes fail closed with 503 while this is empty. Inject the real value
25
36
  // at the node level with CELLD_VAR_WORLD_SECRET instead of committing it.
26
37
  "WORLD_SECRET": "",
27
38
  // Optional: forwarded as x-workflow-callback-secret on queue deliveries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CreateEventRequest, Event, Hook, RunCreatedEventRequest, Step, TerminalWorkflowRunStatus, ValidQueueName, WorkflowRun, World } from "@workflow/world";
1
+ import { CreateEventParams, CreateEventRequest, Event, GetChunksOptions, Hook, RunCreatedEventRequest, Step, StreamChunksResponse, StreamInfoResponse, Streamer, TerminalWorkflowRunStatus, ValidQueueName, Wait, WorkflowRun, World } from "@workflow/world";
2
2
  //#region src/retention.d.ts
3
3
  type CleanupPhase = 'retained' | 'index' | 'streams' | 'queues' | 'payload' | 'tombstoned';
4
4
  interface CleanupRecord {
@@ -11,6 +11,8 @@ interface CleanupRecord {
11
11
  dueAt: Date;
12
12
  queueShards: number;
13
13
  phase: CleanupPhase;
14
+ /** Optimistic-concurrency token for alarm/RPC work that awaits another cell. */
15
+ generation: number;
14
16
  attempts: number;
15
17
  lastError?: string;
16
18
  lastAttemptAt?: Date;
@@ -40,6 +42,15 @@ interface HookIndexReference {
40
42
  hookId: string;
41
43
  token: string;
42
44
  }
45
+ interface ReleaseHookIndexesRequest {
46
+ runId: string;
47
+ hooks: HookIndexReference[];
48
+ /** Install a fence that prevents delayed hook finalization after terminal state. */
49
+ terminal: boolean;
50
+ }
51
+ interface ReleaseHookIndexesResult {
52
+ deleted: number;
53
+ }
43
54
  interface ExpireRunIndexesRequest {
44
55
  runId: string;
45
56
  keys: string[];
@@ -52,12 +63,24 @@ interface ExpireRunIndexesResult {
52
63
  interface ExpireRunStreamsResult {
53
64
  streams: string[];
54
65
  }
66
+ interface FinalizeRunStreamsResult {
67
+ /** Cumulative registry entries removed for this run. */
68
+ deleted: number;
69
+ done: boolean;
70
+ }
55
71
  interface ExpireStreamResult {
72
+ /** True only when this call installed the stream's expiration fence. */
56
73
  deleted: boolean;
74
+ /** Chunk rows removed by this bounded call. */
57
75
  chunks: number;
76
+ /** Payload bytes represented by the removed chunk rows. */
77
+ bytes: number;
78
+ done: boolean;
58
79
  }
59
80
  interface ExpireQueueRunResult {
81
+ /** Cumulative messages removed for this run in this queue shard. */
60
82
  deleted: number;
83
+ done: boolean;
61
84
  }
62
85
  interface ScheduleCleanupRequest {
63
86
  retentionMs: number;
@@ -69,18 +92,22 @@ interface ApplyEventRequest {
69
92
  /** The effective run id (already resolved / generated by the caller). */
70
93
  runId: string;
71
94
  data: CreateEventRequest | RunCreatedEventRequest;
95
+ /** Workflow 5 event-log position and preload options. */
96
+ params?: CreateEventParams;
72
97
  /**
73
- * Current holder of the hook token per the global KV token index
98
+ * Current holder of the hook token per the sharded token-ownership index
74
99
  * (hook_created only). `null` means the token is unclaimed.
75
100
  */
76
101
  tokenHolder?: {
77
102
  runId: string;
78
103
  hookId: string;
79
104
  } | null;
105
+ /** Exact token/ID reservation fenced on ambiguous-delivery resolution. */
106
+ hookClaimId?: string;
80
107
  /** Internal world-celld retention policy captured with the event. */
81
108
  cleanup?: ScheduleCleanupRequest;
82
109
  }
83
- type ApplyEventErrorCode = 'RUN_NOT_FOUND' | 'STEP_NOT_FOUND' | 'HOOK_NOT_FOUND' | 'ENTITY_CONFLICT' | 'RUN_EXPIRED' | 'TOO_EARLY' | 'RUN_NOT_SUPPORTED' | 'LEGACY_RUN_NOT_SUPPORTED';
110
+ type ApplyEventErrorCode = 'RUN_NOT_FOUND' | 'STEP_NOT_FOUND' | 'HOOK_NOT_FOUND' | 'WAIT_NOT_FOUND' | 'ENTITY_CONFLICT' | 'HOOK_CLAIM_CANCELLED' | 'RUN_EXPIRED' | 'TOO_EARLY' | 'RUN_NOT_SUPPORTED';
84
111
  interface ApplyEventFailure {
85
112
  ok: false;
86
113
  code: ApplyEventErrorCode;
@@ -97,7 +124,10 @@ interface ApplyEventSuccess {
97
124
  run?: WorkflowRun;
98
125
  step?: Step;
99
126
  hook?: Hook;
100
- /** Hooks whose tokens must be released from the global KV index. */
127
+ wait?: Wait;
128
+ /** True when a lazy step_started atomically created its step. */
129
+ stepCreated?: true;
130
+ /** Hooks whose token and ID indexes must be released. */
101
131
  releasedHooks: Array<{
102
132
  hookId: string;
103
133
  token: string;
@@ -107,10 +137,15 @@ interface ApplyEventSuccess {
107
137
  workflowName: string;
108
138
  createdAt: Date;
109
139
  };
110
- /** Set when the global KV hook index must be (re)written. */
140
+ /** Set when the sharded hook indexes must be (re)written. */
111
141
  hookToIndex?: Hook;
112
142
  /** All events (ascending), preloaded for run_started responses. */
113
143
  events?: Event[];
144
+ /** Pagination metadata required whenever events are returned. */
145
+ cursor?: string | null;
146
+ hasMore?: boolean;
147
+ /** Server-owned event ceiling advertised on run lifecycle writes. */
148
+ maxEvents?: number;
114
149
  }
115
150
  type ApplyEventOutcome = ApplyEventSuccess | ApplyEventFailure;
116
151
  //#endregion
@@ -121,6 +156,13 @@ type ApplyEventOutcome = ApplyEventSuccess | ApplyEventFailure;
121
156
  */
122
157
  interface WorkflowRunDOStub {
123
158
  applyEvent(request: ApplyEventRequest): Promise<ApplyEventOutcome>;
159
+ resolveHookTokenClaim(request: {
160
+ hookId: string;
161
+ token: string;
162
+ claimId: string;
163
+ }): Promise<{
164
+ committed: boolean;
165
+ }>;
124
166
  getRun(): Promise<RunReadOutcome<WorkflowRun | null>>;
125
167
  getStep(stepId: string): Promise<RunReadOutcome<Step | null>>;
126
168
  getEvent(eventId: string): Promise<RunReadOutcome<Event | null>>;
@@ -164,32 +206,74 @@ interface DurableObjectIdLike {
164
206
  toString(): string;
165
207
  }
166
208
  //#endregion
209
+ //#region src/stream-protocol.d.ts
210
+ /** Metadata plus payload and size-index entries remain below the 128-key platform limit. */
211
+ declare const MAX_STREAM_WRITE_CHUNKS = 32;
212
+ /** A chunk remains below the 2 MiB SQLite-backed DO key/value limit. */
213
+ declare const MAX_STREAM_CHUNK_BYTES: number;
214
+ /** Keeps serialized RPC bodies well below the 32 MiB Workers RPC limit. */
215
+ declare const MAX_STREAM_BATCH_BYTES: number;
216
+ declare const MAX_STREAM_READ_CHUNKS = 32;
217
+ declare const MAX_STREAM_READ_BYTES: number;
218
+ declare const MAX_STREAM_ERROR_BYTES: number;
219
+ /** Must remain below the default 30 second fleet request deadline. */
220
+ declare const MAX_STREAM_LONG_POLL_MS = 20000;
221
+ type StreamTerminalState = 'open' | 'closed' | 'errored' | 'expired';
222
+ interface StreamErrorData {
223
+ name: string;
224
+ message: string;
225
+ }
226
+ interface StreamWriteResult {
227
+ startIndex: number;
228
+ count: number;
229
+ tailIndex: number;
230
+ }
231
+ interface StreamReadRequest {
232
+ runId: string;
233
+ startIndex: number;
234
+ maxChunks: number;
235
+ maxBytes: number;
236
+ waitMs: number;
237
+ }
238
+ interface StreamReadResult {
239
+ startIndex: number;
240
+ tailIndex: number;
241
+ chunks: Uint8Array[];
242
+ state: StreamTerminalState;
243
+ timedOut: boolean;
244
+ error?: StreamErrorData;
245
+ }
246
+ //#endregion
167
247
  //#region src/streamer.d.ts
168
- /**
169
- * RPC surface of StreamDO (see durable-objects/StreamDO.ts). The streamer
170
- * talks to the DO exclusively via these methods — there is no fetch()
171
- * protocol.
172
- */
248
+ interface CelldStreamer extends Omit<Streamer, 'streams'> {
249
+ streams: Streamer['streams'] & {
250
+ fail(runId: string, name: string, error: StreamErrorData | string): Promise<void>;
251
+ };
252
+ writeToStream(name: string, runId: string | Promise<string>, chunk: string | Uint8Array): Promise<void>;
253
+ writeChunksToStream(name: string, runId: string | Promise<string>, chunks: readonly (string | Uint8Array)[]): Promise<void>;
254
+ closeStream(name: string, runId: string | Promise<string>): Promise<void>;
255
+ errorStream(name: string, runId: string | Promise<string>, error: StreamErrorData | string): Promise<void>;
256
+ readFromStream(name: string, runId: string, startIndex?: number): Promise<ReadableStream<Uint8Array>>;
257
+ listStreamsByRunId(runId: string): Promise<string[]>;
258
+ getStreamChunks(name: string, runId: string, options?: GetChunksOptions): Promise<StreamChunksResponse>;
259
+ getStreamInfo(name: string, runId: string): Promise<StreamInfoResponse>;
260
+ }
261
+ /** Direct StreamDO RPC surface. Remote stubs specialize read/write as binary HTTP. */
173
262
  interface StreamDOStub {
174
- writeChunk(runId: string, data: Uint8Array): Promise<number>;
263
+ writeChunks(runId: string, chunks: Uint8Array[]): Promise<StreamWriteResult>;
264
+ readChunks(request: StreamReadRequest, signal?: AbortSignal): Promise<StreamReadResult>;
175
265
  closeStream(runId: string): Promise<void>;
176
- getChunks(params: {
177
- startIndex: number;
178
- limit: number;
179
- }): Promise<{
180
- chunks: Uint8Array[];
181
- done: boolean;
182
- tailIndex: number;
183
- }>;
184
- getInfo(): Promise<{
185
- tailIndex: number;
186
- done: boolean;
187
- }>;
266
+ failStream(runId: string, error: StreamErrorData | string): Promise<void>;
188
267
  registerStream(runId: string, name: string): Promise<void>;
189
268
  listStreams(): Promise<string[]>;
190
- expireRegistry(runId: string, expiredAt: number): Promise<ExpireRunStreamsResult>;
191
- finalizeRegistry(runId: string): Promise<void>;
192
- expireStream(runId: string, expiredAt: number): Promise<ExpireStreamResult>;
269
+ expireRegistry(runId: string, expiredAt: number, options?: {
270
+ limit?: number;
271
+ }): Promise<ExpireRunStreamsResult>;
272
+ finalizeRegistry(runId: string, streams: string[]): Promise<FinalizeRunStreamsResult>;
273
+ expireStream(runId: string, expiredAt: number, options?: {
274
+ limit?: number;
275
+ byteLimit?: number;
276
+ }): Promise<ExpireStreamResult>;
193
277
  }
194
278
  interface StreamDONamespace {
195
279
  idFromName(name: string): StreamDOId;
@@ -200,7 +284,7 @@ interface StreamDOId {
200
284
  }
201
285
  //#endregion
202
286
  //#region src/queue.d.ts
203
- type Pathname = 'flow' | 'step';
287
+ type Pathname = 'flow';
204
288
  /**
205
289
  * Enqueue request accepted by a QueueDO cell. The message payload travels
206
290
  * pre-encoded with the shared tagged-JSON codec (`body`), so the cell can
@@ -223,7 +307,7 @@ interface EnqueueRequest {
223
307
  config: QueueCellConfig;
224
308
  }
225
309
  interface QueueCellConfig {
226
- /** Base URL of the app; deliveries POST to `${baseUrl}/.well-known/workflow/v1/{flow|step}`. */
310
+ /** Base URL of the app; deliveries POST to `${baseUrl}/.well-known/workflow/v1/flow`. */
227
311
  targetBaseUrl: string;
228
312
  queueShards: number;
229
313
  }
@@ -239,7 +323,9 @@ type EnqueueOutcome = {
239
323
  /** RPC surface of QueueDO used by the queue producer. */
240
324
  interface QueueCellStub {
241
325
  enqueue(request: EnqueueRequest): Promise<EnqueueOutcome>;
242
- expireRun(runId: string, expiredAt: number): Promise<ExpireQueueRunResult>;
326
+ expireRun(runId: string, expiredAt: number, options?: {
327
+ limit?: number;
328
+ }): Promise<ExpireQueueRunResult>;
243
329
  }
244
330
  interface QueueCellNamespace {
245
331
  idFromName(name: string): {
@@ -250,36 +336,51 @@ interface QueueCellNamespace {
250
336
  }): QueueCellStub;
251
337
  }
252
338
  //#endregion
253
- //#region src/config.d.ts
254
- /** Storage-layer KV interface (satisfied by IndexDO over HTTP, or a mock). */
255
- interface IndexNamespace {
256
- get(key: string): Promise<string | null>;
257
- put(key: string, value: string): Promise<void>;
258
- delete(key: string): Promise<void>;
259
- putOwned(runId: string, key: string, value: string): Promise<{
339
+ //#region src/indexes.d.ts
340
+ interface IndexListOptions {
341
+ prefix?: string;
342
+ cursor?: string;
343
+ limit?: number;
344
+ reverse?: boolean;
345
+ }
346
+ interface IndexListPage {
347
+ keys: Array<{
348
+ name: string;
349
+ value: string;
350
+ }>;
351
+ list_complete: boolean;
352
+ cursor?: string;
353
+ }
354
+ interface HookReservation {
355
+ claimId: string;
356
+ tokenClaimId?: string;
357
+ hookIdClaimId?: string;
358
+ }
359
+ type HookReservationResult = {
360
+ admitted: true;
361
+ reservation: HookReservation;
362
+ } | {
363
+ admitted: false;
364
+ holder: HookTokenOwner;
365
+ };
366
+ /** High-level client used by the World storage layer and retention coordinator. */
367
+ interface WorkflowIndex {
368
+ commitRun(run: WorkflowRun, serializedMetadata: string): Promise<{
260
369
  stored: boolean;
261
370
  }>;
371
+ listRuns(options?: IndexListOptions): Promise<IndexListPage>;
372
+ getHookByToken(token: string): Promise<string | null>;
373
+ getHookById(hookId: string): Promise<string | null>;
374
+ reserveHook(token: string, owner: HookTokenOwner): Promise<HookReservationResult>;
375
+ finalizeHookIndexes(token: string, hookId: string, serializedHook: string, owner: HookTokenOwner, reservation?: HookReservation): Promise<void>;
376
+ releaseHookReservation(token: string, owner: HookTokenOwner, reservation: HookReservation): Promise<void>;
377
+ releaseHookIndexes(request: ReleaseHookIndexesRequest): Promise<ReleaseHookIndexesResult>;
262
378
  expireRun(request: ExpireRunIndexesRequest): Promise<ExpireRunIndexesResult>;
263
- list(options?: {
264
- prefix?: string;
265
- cursor?: string;
266
- limit?: number;
267
- reverse?: boolean;
268
- }): Promise<{
269
- keys: Array<{
270
- name: string;
271
- }>;
272
- list_complete: boolean;
273
- cursor?: string;
274
- }>;
275
- reserveHookToken(token: string, owner: HookTokenOwner): Promise<{
276
- claimed: boolean;
277
- holder?: HookTokenOwner;
278
- }>;
279
- finalizeHookIndexes(token: string, hookId: string, serializedHook: string, owner: HookTokenOwner): Promise<void>;
280
- releaseHookToken(token: string, owner: HookTokenOwner): Promise<void>;
281
- deleteHookIndexes(token: string, hookId: string, owner: HookTokenOwner): Promise<void>;
282
379
  }
380
+ //#endregion
381
+ //#region src/config.d.ts
382
+ /** Public alias retained for custom in-process environments. */
383
+ type IndexNamespace = WorkflowIndex;
283
384
  interface HookTokenOwner {
284
385
  runId: string;
285
386
  hookId: string;
@@ -312,7 +413,7 @@ interface CelldWorldConfig {
312
413
  deploymentId?: string;
313
414
  /**
314
415
  * Base URL the app's workflow endpoints are mounted on; QueueDO cells
315
- * deliver to `${baseUrl}/.well-known/workflow/v1/{flow|step}`.
416
+ * deliver to `${baseUrl}/.well-known/workflow/v1/flow`.
316
417
  * Default: process.env.WORKFLOW_BASE_URL || `http://localhost:${PORT ?? 3000}`
317
418
  */
318
419
  baseUrl?: string;
@@ -324,8 +425,10 @@ interface CelldWorldConfig {
324
425
  * Default: process.env.CELLD_RUN_RETENTION_MS || 0
325
426
  */
326
427
  runRetentionMs?: number;
327
- /** Poll interval (ms) while waiting for new chunks on a live stream. Default: 250 */
328
- readPollMs?: number;
428
+ /** Duration of one bounded idle stream read. Default: 20000 */
429
+ streamLongPollMs?: number;
430
+ /** Runtime stream batching delay. Default: 0 */
431
+ streamFlushIntervalMs?: number;
329
432
  /** Per-attempt fleet RPC deadline in milliseconds. Default: 30000 */
330
433
  rpcTimeoutMs?: number;
331
434
  }
@@ -337,10 +440,10 @@ interface CelldRetentionAdmin {
337
440
  cleanupNow(runId: string): Promise<CleanupRecord | null>;
338
441
  rearm(runId: string): Promise<CleanupRecord | null>;
339
442
  }
340
- type CelldWorld = World & {
443
+ type CelldWorld = World & CelldStreamer & {
341
444
  retention: CelldRetentionAdmin;
342
445
  };
343
446
  declare function createCelldWorld(config?: CelldWorldConfig): CelldWorld;
344
447
  //#endregion
345
- export { CelldRetentionAdmin, CelldWorld, type CelldWorldConfig, type CelldWorldEnv, type CleanupPhase, type CleanupRecord, type EnqueueOutcome, type EnqueueRequest, type IndexNamespace, type QueueCellConfig, type QueueCellNamespace, type QueueCellStub, type RunTombstone, type StreamDONamespace, type StreamDOStub, type WorkflowRunDONamespace, type WorkflowRunDOStub, createCelldWorld, createCelldWorld as createWorld };
448
+ export { CelldRetentionAdmin, CelldWorld, type CelldWorldConfig, type CelldWorldEnv, type CleanupPhase, type CleanupRecord, type EnqueueOutcome, type EnqueueRequest, type IndexNamespace, MAX_STREAM_BATCH_BYTES, MAX_STREAM_CHUNK_BYTES, MAX_STREAM_ERROR_BYTES, MAX_STREAM_LONG_POLL_MS, MAX_STREAM_READ_BYTES, MAX_STREAM_READ_CHUNKS, MAX_STREAM_WRITE_CHUNKS, type QueueCellConfig, type QueueCellNamespace, type QueueCellStub, type RunTombstone, type StreamDONamespace, type StreamDOStub, type StreamErrorData, type StreamReadRequest, type StreamReadResult, type StreamTerminalState, type StreamWriteResult, type WorkflowRunDONamespace, type WorkflowRunDOStub, createCelldWorld, createCelldWorld as createWorld };
346
449
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/retention.ts","../src/apply-event.ts","../src/storage.ts","../src/streamer.ts","../src/queue.ts","../src/config.ts","../src/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/retention.ts","../src/apply-event.ts","../src/storage.ts","../src/stream-protocol.ts","../src/streamer.ts","../src/queue.ts","../src/indexes.ts","../src/config.ts","../src/index.ts"],"mappings":"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"}