@ewhauser/world-celld 0.1.1 → 0.2.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"worker.js","names":["#now","#scheduleNextAlarm","#armAlarmAtMost","#claimPhase","#deliver","#intVar","#fetch","#ack","#retry","#rearm"],"sources":["../src/vendor/shared/serialization.ts","../src/codec.ts","../src/worker/auth.ts","../src/worker/router.ts","../src/vendor/shared/util.ts","../src/worker/durable-objects/IndexDO.ts","../src/worker/durable-objects/QueueDO.ts","../src/worker/durable-objects/StreamDO.ts","../src/apply-event.ts","../src/worker/durable-objects/WorkflowRunDO.ts","../src/worker/worker.ts"],"sourcesContent":["/** Standard Date fields used across all worlds */\nexport const DATE_FIELDS = new Set([\n 'createdAt',\n 'updatedAt',\n 'startedAt',\n 'completedAt',\n 'retryAfter',\n] as const);\n\n/**\n * JSON reviver that converts ISO date strings to Date objects.\n * Use with JSON.parse(json, dateReviver).\n */\nexport function dateReviver(key: string, value: unknown): unknown {\n if (\n DATE_FIELDS.has(key as typeof DATE_FIELDS extends Set<infer T> ? T : never) &&\n typeof value === 'string'\n ) {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? value : date;\n }\n return value;\n}\n\n/**\n * Base64 helpers. Modified vs upstream: implemented over atob/btoa instead of\n * Buffer so this module is safe inside the celld worker bundle (workerd has\n * no Buffer global); atob/btoa are global in both workerd and Node >= 16.\n */\nexport function b64encode(bytes: Uint8Array): string {\n let bin = '';\n const CHUNK = 0x8000;\n for (let i = 0; i < bytes.length; i += CHUNK) {\n bin += String.fromCharCode(...bytes.subarray(i, i + CHUNK));\n }\n return btoa(bin);\n}\n\nexport function b64decode(text: string): Uint8Array {\n const bin = atob(text);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) {\n out[i] = bin.charCodeAt(i);\n }\n return out;\n}\n\n/**\n * JSON replacer that encodes Uint8Array as a tagged object with base64 data.\n */\nexport function uint8ArrayReplacer(_key: string, value: unknown): unknown {\n if (value instanceof Uint8Array) {\n return {\n __type: 'Uint8Array',\n data: b64encode(value),\n };\n }\n return value;\n}\n\n/**\n * JSON reviver that decodes tagged Uint8Array objects and ISO date strings.\n * Supports both:\n * - New format: { __type: 'Uint8Array', data: '<base64>' }\n * - Legacy format: { __uint8array: true, data: [1, 2, 3] }\n */\nexport function uint8ArrayReviver(key: string, value: unknown): unknown {\n if (value && typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n // New format: base64-encoded\n if (obj.__type === 'Uint8Array' && typeof obj.data === 'string') {\n return b64decode(obj.data);\n }\n // Legacy format: number array (backwards compat with NATS JetStream data)\n if (obj.__uint8array === true && Array.isArray(obj.data)) {\n return new Uint8Array(obj.data as number[]);\n }\n }\n return dateReviver(key, value);\n}\n\n/** Stringify with Uint8Array support. */\nexport function stringify(value: unknown): string {\n return JSON.stringify(value, uint8ArrayReplacer);\n}\n\n/** Parse with Uint8Array and Date support. */\nexport function parse<T>(text: string): T {\n return JSON.parse(text, uint8ArrayReviver) as T;\n}\n\n/** Deep clone using structuredClone */\nexport function deepClone<T>(value: T): T {\n return structuredClone(value);\n}\n","/**\n * RPC wire codec for the Node client <-> worker router HTTP boundary.\n *\n * Extends the shared tagged-JSON format (`{__type:'Uint8Array', data}` +\n * DATE_FIELDS revival) with explicitly tagged Dates: on Cloudflare the DO RPC\n * boundary is structured clone, which preserves EVERY Date — including ones\n * outside the well-known DATE_FIELDS (e.g. inside applyEvent outcomes and\n * user payloads). The HTTP hop must preserve them too, so Dates travel as\n * `{__type:'Date', iso}`.\n *\n * Runs on both sides of the wire, including inside the celld worker — so no\n * Node built-ins (Buffer): base64 goes through atob/btoa.\n */\nimport { b64decode, b64encode, dateReviver } from './vendor/shared/serialization.js';\n\nfunction rpcReplacer(this: unknown, key: string, value: unknown): unknown {\n // JSON.stringify invokes Date.toJSON before the replacer sees the value;\n // recover the original from the holder object.\n const original =\n this && typeof this === 'object' ? (this as Record<string, unknown>)[key] : undefined;\n if (original instanceof Date) {\n return { __type: 'Date', iso: original.toISOString() };\n }\n if (value instanceof Uint8Array) {\n return { __type: 'Uint8Array', data: b64encode(value) };\n }\n return value;\n}\n\nfunction rpcReviver(key: string, value: unknown): unknown {\n if (value && typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n if (obj.__type === 'Date' && typeof obj.iso === 'string') {\n return new Date(obj.iso);\n }\n if (obj.__type === 'Uint8Array' && typeof obj.data === 'string') {\n return b64decode(obj.data);\n }\n }\n // Fallback shared-codec semantics for untagged ISO strings in DATE_FIELDS.\n return dateReviver(key, value);\n}\n\nexport function rpcStringify(value: unknown): string {\n return JSON.stringify(value, rpcReplacer);\n}\n\nexport function rpcParse<T>(text: string): T {\n return JSON.parse(text, rpcReviver) as T;\n}\n","/**\n * Bearer-token auth for the worker router.\n *\n * Fails closed: when the WORLD_SECRET var is not configured, every protected\n * route returns 503 instead of forwarding unauthenticated traffic (the\n * eve-ambient celld-worker pattern).\n */\n\n/**\n * Constant-time string comparison via SHA-256 digests (digest-then-compare\n * is length-independent). crypto.subtle is global in both workerd and Node.\n */\nasync function timingSafeEqual(a: string, b: string): Promise<boolean> {\n const enc = new TextEncoder();\n const [da, db] = await Promise.all([\n crypto.subtle.digest('SHA-256', enc.encode(a)),\n crypto.subtle.digest('SHA-256', enc.encode(b)),\n ]);\n const va = new Uint8Array(da);\n const vb = new Uint8Array(db);\n let diff = 0;\n for (let i = 0; i < va.length; i++) {\n diff |= va[i] ^ vb[i];\n }\n return diff === 0;\n}\n\nexport type AuthResult = { ok: true } | { ok: false; response: Response };\n\nexport async function authenticate(\n request: Request,\n secret: string | undefined,\n): Promise<AuthResult> {\n if (!secret) {\n return {\n ok: false,\n response: Response.json(\n { error: { name: 'WorldNotConfigured', message: 'WORLD_SECRET is not configured' } },\n { status: 503 },\n ),\n };\n }\n\n const header = request.headers.get('authorization') ?? '';\n const token = header.startsWith('Bearer ') ? header.slice('Bearer '.length) : '';\n if (!token || !(await timingSafeEqual(token, secret))) {\n return {\n ok: false,\n response: Response.json(\n { error: { name: 'Unauthorized', message: 'invalid or missing bearer token' } },\n { status: 401 },\n ),\n };\n }\n\n return { ok: true };\n}\n","/**\n * Worker-level HTTP router: the fleet-facing RPC surface of the celld world.\n *\n * Routes:\n * GET /v1/health — liveness + spec version (unauthenticated)\n * POST /v1/rpc/{binding}/{name}/{method} — DO RPC (bearer auth)\n *\n * The RPC body is an rpc-codec-encoded JSON array of arguments; the response\n * body is the rpc-codec-encoded return value. Only whitelisted methods\n * dispatch — everything else (including fetch/alarm) is unreachable.\n */\nimport { SPEC_VERSION_CURRENT } from '@workflow/world';\nimport { rpcParse, rpcStringify } from '../codec.js';\nimport { authenticate } from './auth.js';\n\nexport const WORLD_NAME = 'world-celld';\nexport const WORLD_VERSION = '0.1.0';\n\n/** Minimal structural DO namespace type (celld provides the real thing). */\nexport interface DONamespaceLike {\n idFromName(name: string): { toString(): string };\n get(id: { toString(): string }): unknown;\n}\n\nexport interface WorkerEnv {\n WORKFLOW_DB: DONamespaceLike;\n WORKFLOW_STREAMS: DONamespaceLike;\n WORKFLOW_INDEX: DONamespaceLike;\n WORKFLOW_QUEUE: DONamespaceLike;\n WORLD_SECRET?: string;\n}\n\nconst BINDINGS: Record<string, { env: keyof WorkerEnv; methods: ReadonlySet<string> }> = {\n runs: {\n env: 'WORKFLOW_DB',\n methods: new Set([\n 'applyEvent',\n 'getRun',\n 'getStep',\n 'getEvent',\n 'listEvents',\n 'listSteps',\n 'listHooks',\n ]),\n },\n streams: {\n env: 'WORKFLOW_STREAMS',\n methods: new Set([\n 'writeChunk',\n 'closeStream',\n 'getChunks',\n 'getInfo',\n 'registerStream',\n 'listStreams',\n ]),\n },\n index: {\n env: 'WORKFLOW_INDEX',\n methods: new Set([\n 'get',\n 'put',\n 'delete',\n 'list',\n 'reserveHookToken',\n 'finalizeHookIndexes',\n 'releaseHookToken',\n 'deleteHookIndexes',\n ]),\n },\n queue: {\n env: 'WORKFLOW_QUEUE',\n methods: new Set([\n 'enqueue',\n 'stats',\n 'listDeadLetters',\n 'redriveDeadLetter',\n 'purgeDeadLetters',\n 'rearmAlarm',\n ]),\n },\n};\n\n/** Request body cap: oversize payloads get a clear 413 instead of an OOM. */\nconst MAX_BODY_BYTES = 32 * 1024 * 1024;\n\nfunction errorResponse(status: number, name: string, message: string): Response {\n return Response.json({ error: { name, message } }, { status });\n}\n\nasync function readBoundedBody(request: Request): Promise<string | null> {\n if (!request.body) return '';\n const reader = request.body.getReader();\n const decoder = new TextDecoder();\n let total = 0;\n let text = '';\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > MAX_BODY_BYTES) {\n await reader.cancel('RPC body exceeds configured limit').catch(() => undefined);\n return null;\n }\n text += decoder.decode(value, { stream: true });\n }\n return text + decoder.decode();\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function createRouter(env: WorkerEnv) {\n return async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const parts = url.pathname.split('/').filter(Boolean);\n\n if (parts[0] !== 'v1') {\n return errorResponse(404, 'NotFound', `unknown path: ${url.pathname}`);\n }\n\n if (parts[1] === 'health' && parts.length === 2) {\n return Response.json({\n ok: true,\n name: WORLD_NAME,\n version: WORLD_VERSION,\n specVersion: SPEC_VERSION_CURRENT,\n });\n }\n\n if (parts[1] !== 'rpc') {\n return errorResponse(404, 'NotFound', `unknown path: ${url.pathname}`);\n }\n\n const auth = await authenticate(request, env.WORLD_SECRET);\n if (!auth.ok) {\n return auth.response;\n }\n\n if (request.method !== 'POST' || parts.length !== 5) {\n return errorResponse(404, 'NotFound', 'expected POST /v1/rpc/{binding}/{name}/{method}');\n }\n\n const [, , bindingKey, encodedName, method] = parts;\n const binding = BINDINGS[bindingKey];\n if (!binding) {\n return errorResponse(404, 'NotFound', `unknown binding: ${bindingKey}`);\n }\n if (!binding.methods.has(method)) {\n return errorResponse(404, 'NotFound', `unknown method: ${bindingKey}.${method}`);\n }\n\n const contentLength = Number(request.headers.get('content-length') ?? '0');\n if (contentLength > MAX_BODY_BYTES) {\n return errorResponse(413, 'PayloadTooLarge', `body exceeds ${MAX_BODY_BYTES} bytes`);\n }\n\n let args: unknown[];\n try {\n const text = await readBoundedBody(request);\n if (text === null) {\n return errorResponse(413, 'PayloadTooLarge', `body exceeds ${MAX_BODY_BYTES} bytes`);\n }\n const parsed = rpcParse<unknown>(text);\n if (!Array.isArray(parsed)) {\n return errorResponse(400, 'BadRequest', 'body must be an argument array');\n }\n args = parsed;\n } catch {\n return errorResponse(400, 'BadRequest', 'malformed rpc body');\n }\n\n const name = decodeURIComponent(encodedName);\n const namespace = env[binding.env] as DONamespaceLike | undefined;\n if (!namespace) {\n return errorResponse(500, 'WorldMisconfigured', `missing binding: ${binding.env}`);\n }\n\n try {\n const stub = namespace.get(namespace.idFromName(name)) as Record<\n string,\n (...a: unknown[]) => Promise<unknown>\n >;\n const result = await stub[method](...args);\n return new Response(rpcStringify(result ?? null), {\n status: 200,\n headers: { 'content-type': 'application/json' },\n });\n } catch (error) {\n // Guard failures travel as structured outcomes, so a thrown error here\n // is exceptional (e.g. writing to a closed stream). Serialize by name\n // for client-side reconstruction.\n const err = error as { name?: string; message?: string; status?: number };\n return Response.json(\n {\n error: {\n name: err?.name ?? 'Error',\n message: err?.message ?? String(error),\n status: typeof err?.status === 'number' ? err.status : undefined,\n },\n },\n { status: 500 },\n );\n }\n };\n}\n","export class Mutex {\n promise: Promise<unknown> = Promise.resolve();\n andThen<T>(fn: () => Promise<T> | T): Promise<T> {\n this.promise = this.promise.then(\n () => fn(),\n () => fn(),\n );\n return this.promise as Promise<T>;\n }\n}\n\nexport function compact<T extends object>(obj: T) {\n const value = {} as {\n [key in keyof T]: null extends T[key] ? undefined | NonNullable<T[key]> : T[key];\n };\n for (const key in obj) {\n if (obj[key] !== null) {\n value[key] = obj[key] as any;\n } else {\n value[key] = undefined as any;\n }\n }\n return value;\n}\n\n/**\n * Reference counting helper for managing resource lifecycle\n */\nexport class Rc {\n private count = 0;\n private disposeFn?: () => void | Promise<void>;\n\n constructor(disposeFn?: () => void | Promise<void>) {\n this.disposeFn = disposeFn;\n }\n\n inc(): void {\n this.count++;\n }\n\n async dec(): Promise<void> {\n this.count--;\n if (this.count === 0 && this.disposeFn) {\n await this.disposeFn();\n }\n }\n\n getCount(): number {\n return this.count;\n }\n}\n","import type { Hook } from '@workflow/world';\nimport type { HookTokenOwner } from '../../config.js';\nimport { parse } from '../../vendor/shared/index.js';\nimport { DurableObject } from '../do-base.js';\n\ninterface HookClaim {\n owner: HookTokenOwner;\n reservedAt: number;\n}\n\nfunction sameOwner(left: HookTokenOwner, right: HookTokenOwner): boolean {\n return left.runId === right.runId && left.hookId === right.hookId;\n}\n\nfunction ownerFromHook(raw: string): HookTokenOwner {\n const hook = parse<Hook>(raw);\n return { runId: hook.runId, hookId: hook.hookId };\n}\n\n/**\n * Global index cell, replacing the Workers KV namespace world-cloudflare\n * uses for run listing and hook token/id lookup.\n *\n * A single cell (named `index`) serializes every read and write. Hook-token\n * reservation, publication, and release use storage transactions so\n * concurrent runs cannot both acquire the same token.\n *\n * The RPC surface matches the storage-layer KVNamespace interface bit-for-bit\n * (including MockKVNamespace's pagination contract: cursor = last returned\n * key, `list_complete` reflects whether further keys exist), so the vendored\n * storage.ts works against it unchanged.\n */\nexport class IndexDO extends DurableObject {\n async get(key: string): Promise<string | null> {\n const value = await this.ctx.storage.get<string>(key);\n return value ?? null;\n }\n\n async put(key: string, value: string): Promise<void> {\n await this.ctx.storage.put(key, value);\n }\n\n async delete(key: string): Promise<void> {\n await this.ctx.storage.delete(key);\n }\n\n async list(options?: {\n prefix?: string;\n cursor?: string;\n limit?: number;\n reverse?: boolean;\n }): Promise<{\n keys: Array<{ name: string }>;\n list_complete: boolean;\n cursor?: string;\n }> {\n const prefix = options?.prefix ?? '';\n const limit = options?.limit ?? 1000;\n\n // Fetch one extra key to learn whether the listing is complete without\n // advancing past the page (the \"exact limit + list_complete\" contract\n // storage.ts relies on).\n const entries = await this.ctx.storage.list({\n prefix,\n ...(options?.reverse\n ? { reverse: true, end: options.cursor }\n : { startAfter: options?.cursor }),\n limit: limit + 1,\n });\n\n const names = Array.from(entries.keys());\n const page = names.slice(0, limit);\n const listComplete = names.length <= limit;\n\n return {\n keys: page.map((name) => ({ name })),\n list_complete: listComplete,\n cursor: listComplete ? undefined : page.at(-1),\n };\n }\n\n async reserveHookToken(\n token: string,\n owner: HookTokenOwner,\n ): Promise<{ claimed: boolean; holder?: HookTokenOwner }> {\n return this.ctx.storage.transaction(async (txn) => {\n const indexedHook = await txn.get<string>(`hook:${token}`);\n if (indexedHook !== undefined) {\n const holder = ownerFromHook(indexedHook);\n return { claimed: false, holder };\n }\n\n const claimKey = `hookclaim:${token}`;\n const claim = await txn.get<HookClaim>(claimKey);\n if (claim !== undefined && !sameOwner(claim.owner, owner)) {\n return { claimed: false, holder: claim.owner };\n }\n\n await txn.put(claimKey, { owner, reservedAt: Date.now() });\n return { claimed: true };\n });\n }\n\n async finalizeHookIndexes(\n token: string,\n hookId: string,\n serializedHook: string,\n owner: HookTokenOwner,\n ): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n const indexedHook = await txn.get<string>(`hook:${token}`);\n if (indexedHook !== undefined && !sameOwner(ownerFromHook(indexedHook), owner)) {\n throw new Error(`Hook token ${token} is owned by another hook`);\n }\n const claim = await txn.get<HookClaim>(`hookclaim:${token}`);\n if (claim !== undefined && !sameOwner(claim.owner, owner)) {\n throw new Error(`Hook token ${token} is reserved by another hook`);\n }\n\n await txn.put(`hook:${token}`, serializedHook);\n await txn.put(`hookid:${hookId}`, serializedHook);\n if (claim !== undefined) {\n await txn.delete(`hookclaim:${token}`);\n }\n });\n }\n\n async releaseHookToken(token: string, owner: HookTokenOwner): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n const key = `hookclaim:${token}`;\n const claim = await txn.get<HookClaim>(key);\n if (claim !== undefined && sameOwner(claim.owner, owner)) {\n await txn.delete(key);\n }\n });\n }\n\n async deleteHookIndexes(token: string, hookId: string, owner: HookTokenOwner): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n const tokenKey = `hook:${token}`;\n const idKey = `hookid:${hookId}`;\n const claimKey = `hookclaim:${token}`;\n const [byToken, byId, claim] = await Promise.all([\n txn.get<string>(tokenKey),\n txn.get<string>(idKey),\n txn.get<HookClaim>(claimKey),\n ]);\n if (byToken !== undefined && sameOwner(ownerFromHook(byToken), owner)) {\n await txn.delete(tokenKey);\n }\n if (byId !== undefined && sameOwner(ownerFromHook(byId), owner)) {\n await txn.delete(idKey);\n }\n if (claim !== undefined && sameOwner(claim.owner, owner)) {\n await txn.delete(claimKey);\n }\n });\n }\n}\n","import { DurableObject } from '../do-base.js';\nimport type { EnqueueOutcome, EnqueueRequest } from '../../queue.js';\n\n/**\n * Queue cell: the celld replacement for Cloudflare Queues.\n *\n * One cell (`q:<shard>`) owns the full lifecycle of its messages: durable\n * scheduling via the cell alarm, delivery via outbound fetch (the same x-vqs\n * dialect as the in-process test pump), retries with capped exponential\n * backoff, idempotencyKey dedup, and a dead-letter table.\n *\n * Storage layout (KV-style, ordered scans via zero-padded epoch-ms keys):\n * cfg pinned QueueCellConfig (first-enqueue wins)\n * msg:<messageId> MessageRow\n * due:<paddedMs>:<messageId> schedule index -> messageId\n * inflight:<messageId> crash-recovery deadline (epoch ms)\n * key:<idempotencyKey> active dedup claim -> messageId\n * dlq:<paddedMs>:<messageId> DeadLetterRow\n *\n * celld gotchas designed around:\n * - celld#144 (alarm handlers can overlap): the storage-only claim phase runs\n * inside blockConcurrencyWhile; slow delivery I/O runs outside the gate via\n * waitUntil.\n * - six-failure alarm abandonment: the alarm handler never throws for data\n * conditions — backoff reschedules the alarm instead. rearmAlarm() is the\n * recovery hatch, and every enqueue also re-arms.\n * - deploys restart the fleet: in-flight deliveries die with the isolate; the\n * inflight-deadline sweep on the next alarm redelivers (at-least-once).\n */\n\nexport interface MessageRow {\n messageId: string;\n queueName: string;\n pathname: 'flow' | 'step';\n /** Pre-encoded tagged-JSON payload — forwarded byte-identical. */\n body: string;\n /**\n * Delivery target captured at enqueue time. Carried per message (not\n * pinned on the cell) so an app redeploy at a new URL never bricks the\n * queue: old messages deliver (or dead-letter) against their original\n * target, new messages against the new one.\n */\n targetBaseUrl: string;\n idempotencyKey?: string;\n /** Completed delivery attempts. */\n attempt: number;\n enqueuedAt: number;\n lastError?: string;\n}\n\nexport interface DeadLetterRow extends MessageRow {\n failedAt: number;\n}\n\nexport interface QueueStats {\n pending: number;\n inflight: number;\n deadLetters: number;\n alarmAt: number | null;\n}\n\nconst PERMANENT_STATUSES = new Set([404, 409, 410, 422]);\n\nconst DEFAULT_MAX_ATTEMPTS = 5;\nconst DEFAULT_MAX_INFLIGHT = 5;\nconst DEFAULT_DELIVERY_TIMEOUT_MS = 300_000;\n/** Grace period past the delivery timeout before a claim counts as lost. */\nconst INFLIGHT_GRACE_MS = 30_000;\n/** Move overdue alarms to a new timestamp so celld observes a fresh edge. */\nconst MIN_ALARM_DELAY_MS = 1;\n\ntype AlarmStorage = Pick<DurableObjectStorage, 'list' | 'getAlarm' | 'setAlarm' | 'deleteAlarm'>;\n\nfunction pad(ms: number): string {\n return String(Math.max(0, Math.floor(ms))).padStart(13, '0');\n}\n\nfunction dueKey(atMs: number, messageId: string): string {\n return `due:${pad(atMs)}:${messageId}`;\n}\n\nfunction backoffSeconds(attempt: number): number {\n return Math.min(60, 2 ** attempt);\n}\n\ninterface QueueCellEnv {\n QUEUE_MAX_ATTEMPTS?: string;\n QUEUE_MAX_INFLIGHT?: string;\n QUEUE_DELIVERY_TIMEOUT_MS?: string;\n WORKFLOW_CALLBACK_SECRET?: string;\n /** Test seams (never set by a real deploy — celld vars are strings). */\n clock?: () => number;\n fetch?: typeof fetch;\n}\n\nexport class QueueDO extends DurableObject {\n #now(): number {\n const clock = (this.env as QueueCellEnv)?.clock;\n return typeof clock === 'function' ? clock() : Date.now();\n }\n\n #fetch(): typeof fetch {\n const impl = (this.env as QueueCellEnv)?.fetch;\n return typeof impl === 'function' ? impl : fetch;\n }\n\n #intVar(\n name: 'QUEUE_MAX_ATTEMPTS' | 'QUEUE_MAX_INFLIGHT' | 'QUEUE_DELIVERY_TIMEOUT_MS',\n fallback: number,\n ): number {\n const raw = (this.env as QueueCellEnv)?.[name];\n const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n }\n\n async enqueue(request: EnqueueRequest): Promise<EnqueueOutcome> {\n const storage = this.ctx.storage;\n const now = this.#now();\n\n const outcome = await storage.transaction<EnqueueOutcome>(async (txn) => {\n // Pin the shard count from the first enqueue and reject drift loudly:\n // idempotencyKey -> cell affinity (and therefore dedup correctness)\n // depends on every producer agreeing on the shard count. The delivery\n // URL deliberately is NOT pinned — it travels per message.\n const pinned = await txn.get<{ queueShards: number; pinnedAt: number }>('cfg');\n if (!pinned) {\n await txn.put('cfg', { queueShards: request.config.queueShards, pinnedAt: now });\n } else if (pinned.queueShards !== request.config.queueShards) {\n return {\n ok: false,\n code: 'CONFIG_MISMATCH',\n message:\n `queue cell shard-count mismatch: pinned ${pinned.queueShards}, ` +\n `got ${request.config.queueShards} — changing queueShards requires draining the fleet`,\n };\n }\n\n // Dedup: while a message with this idempotencyKey is active, return the\n // original messageId (core re-enqueues pending steps on every replay and\n // relies on this).\n if (request.idempotencyKey) {\n const existing = await txn.get<string>(`key:${request.idempotencyKey}`);\n if (existing) {\n if (await txn.get(`msg:${existing}`)) {\n await this.#scheduleNextAlarm(txn, now);\n return { ok: true, messageId: existing, deduped: true };\n }\n // Stale claim (message gone without release) — steal it.\n await txn.delete(`key:${request.idempotencyKey}`);\n }\n await txn.put(`key:${request.idempotencyKey}`, request.messageId);\n }\n\n const row: MessageRow = {\n messageId: request.messageId,\n queueName: request.queueName,\n pathname: request.pathname,\n body: request.body,\n targetBaseUrl: request.config.targetBaseUrl,\n idempotencyKey: request.idempotencyKey,\n attempt: 0,\n enqueuedAt: now,\n };\n const dueAt = now + Math.max(0, request.delaySeconds ?? 0) * 1000;\n await txn.put(`msg:${row.messageId}`, row);\n await txn.put(dueKey(dueAt, row.messageId), row.messageId);\n await this.#armAlarmAtMost(txn, dueAt, now);\n\n return { ok: true, messageId: row.messageId, deduped: false };\n });\n\n return outcome;\n }\n\n async alarm(): Promise<void> {\n // celld#144: alarm handlers can overlap while awaiting. The storage-only\n // claim phase runs under the input gate; a failure is carried out and\n // rethrown outside so a failed critical section cannot reset the cell.\n let claimed: MessageRow[] = [];\n let failure: unknown = null;\n const attempt = async () => {\n try {\n claimed = await this.#claimPhase();\n } catch (error) {\n failure = error;\n }\n };\n if (typeof this.ctx.blockConcurrencyWhile === 'function') {\n await this.ctx.blockConcurrencyWhile(attempt);\n } else {\n await attempt();\n }\n if (failure !== null) throw failure;\n\n for (const row of claimed) {\n this.ctx.waitUntil(this.#deliver(row));\n }\n }\n\n /**\n * Storage-only: recover lost inflight claims, claim due messages up to the\n * inflight cap, and re-arm the alarm. Never throws for data conditions.\n */\n async #claimPhase(): Promise<MessageRow[]> {\n const storage = this.ctx.storage;\n const now = this.#now();\n const maxInflight = this.#intVar('QUEUE_MAX_INFLIGHT', DEFAULT_MAX_INFLIGHT);\n const claimed = await storage.transaction<MessageRow[]>(async (txn) => {\n // 1. Recover: an inflight entry past its deadline is a lost delivery\n // (node crash, deploy restart) — back to due for redelivery.\n const inflight = await txn.list<number>({ prefix: 'inflight:' });\n let inflightCount = 0;\n for (const [key, deadline] of inflight) {\n if (deadline <= now) {\n const messageId = key.slice('inflight:'.length);\n await txn.delete(key);\n if (await txn.get(`msg:${messageId}`)) {\n await txn.put(dueKey(now, messageId), messageId);\n }\n } else {\n inflightCount++;\n }\n }\n\n // 2. Claim due messages up to the cap.\n const rows: MessageRow[] = [];\n if (inflightCount < maxInflight) {\n const due = await txn.list<string>({\n prefix: 'due:',\n end: `due:${pad(now + 1)}`,\n limit: maxInflight - inflightCount,\n });\n const timeoutMs = this.#intVar('QUEUE_DELIVERY_TIMEOUT_MS', DEFAULT_DELIVERY_TIMEOUT_MS);\n for (const [key, messageId] of due) {\n await txn.delete(key);\n const row = await txn.get<MessageRow>(`msg:${messageId}`);\n if (!row) continue; // orphaned schedule entry\n await txn.put(`inflight:${messageId}`, now + timeoutMs + INFLIGHT_GRACE_MS);\n rows.push(row);\n }\n }\n await this.#scheduleNextAlarm(txn, now);\n return rows;\n });\n\n return claimed;\n }\n\n async #deliver(row: MessageRow): Promise<void> {\n const storage = this.ctx.storage;\n const timeoutMs = this.#intVar('QUEUE_DELIVERY_TIMEOUT_MS', DEFAULT_DELIVERY_TIMEOUT_MS);\n const callbackSecret = (this.env as QueueCellEnv)?.WORKFLOW_CALLBACK_SECRET;\n const url = `${row.targetBaseUrl.replace(/\\/$/, '')}/.well-known/workflow/v1/${row.pathname}`;\n\n let response: Response | null = null;\n let transportError: unknown = null;\n try {\n response = await this.#fetch()(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-vqs-queue-name': row.queueName,\n 'x-vqs-message-id': row.messageId,\n 'x-vqs-message-attempt': String(row.attempt + 1),\n ...(callbackSecret ? { 'x-workflow-callback-secret': callbackSecret } : {}),\n },\n body: row.body,\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (error) {\n transportError = error;\n }\n\n const now = this.#now();\n\n if (response?.ok) {\n // Ack: the message is done; release the dedup claim.\n await this.#ack(row);\n } else if (response && response.status === 503) {\n // {timeoutSeconds} means \"redeliver later, same message\": the attempt\n // count does not advance and the dedup key stays claimed.\n let timeoutSeconds: number | undefined;\n try {\n const parsed = (await response.json()) as { timeoutSeconds?: number };\n timeoutSeconds = parsed?.timeoutSeconds;\n } catch {\n timeoutSeconds = undefined;\n }\n if (typeof timeoutSeconds === 'number') {\n await storage.transaction(async (txn) => {\n await txn.delete(`inflight:${row.messageId}`);\n await txn.put(dueKey(now + timeoutSeconds * 1000, row.messageId), row.messageId);\n await this.#scheduleNextAlarm(txn, now);\n });\n } else {\n await this.#retry(row, 'HTTP 503');\n }\n } else if (response && PERMANENT_STATUSES.has(response.status)) {\n // Permanent: drop without burning retries; the handler already\n // classified this as unreplayable.\n await this.#ack(row);\n } else {\n const reason = response\n ? `HTTP ${response.status}`\n : `transport error: ${String(transportError)}`;\n await this.#retry(row, reason);\n }\n }\n\n async #ack(row: MessageRow): Promise<void> {\n const storage = this.ctx.storage;\n await storage.transaction(async (txn) => {\n await txn.delete(`msg:${row.messageId}`);\n await txn.delete(`inflight:${row.messageId}`);\n if (row.idempotencyKey) {\n const holder = await txn.get<string>(`key:${row.idempotencyKey}`);\n if (holder === row.messageId) {\n await txn.delete(`key:${row.idempotencyKey}`);\n }\n }\n await this.#scheduleNextAlarm(txn, this.#now());\n });\n }\n\n async #retry(row: MessageRow, reason: string): Promise<void> {\n const storage = this.ctx.storage;\n const now = this.#now();\n const maxAttempts = this.#intVar('QUEUE_MAX_ATTEMPTS', DEFAULT_MAX_ATTEMPTS);\n const attempt = row.attempt + 1;\n\n await storage.transaction(async (txn) => {\n await txn.delete(`inflight:${row.messageId}`);\n\n if (attempt >= maxAttempts) {\n const dead: DeadLetterRow = { ...row, attempt, lastError: reason, failedAt: now };\n await txn.put(`dlq:${pad(now)}:${row.messageId}`, dead);\n await txn.delete(`msg:${row.messageId}`);\n if (row.idempotencyKey) {\n const holder = await txn.get<string>(`key:${row.idempotencyKey}`);\n if (holder === row.messageId) {\n await txn.delete(`key:${row.idempotencyKey}`);\n }\n }\n await this.#scheduleNextAlarm(txn, now);\n return;\n }\n\n const updated: MessageRow = { ...row, attempt, lastError: reason };\n await txn.put(`msg:${row.messageId}`, updated);\n await txn.put(dueKey(now + backoffSeconds(attempt) * 1000, row.messageId), row.messageId);\n await this.#scheduleNextAlarm(txn, now);\n });\n }\n\n /** Arm the alarm no later than `atMs` (durable backoff never throws). */\n async #armAlarmAtMost(storage: AlarmStorage, atMs: number, now: number): Promise<void> {\n const current = await storage.getAlarm();\n if (current !== null && current <= now) {\n await storage.setAlarm(now + MIN_ALARM_DELAY_MS);\n return;\n }\n\n const target = atMs <= now ? now + MIN_ALARM_DELAY_MS : atMs;\n if (current === null || target < current) {\n await storage.setAlarm(target);\n }\n }\n\n /** Recompute the alarm from the earliest due entry / inflight deadline. */\n async #rearm(): Promise<void> {\n await this.#scheduleNextAlarm(this.ctx.storage, this.#now());\n }\n\n /** Keep the alarm index consistent with message state in the same transaction. */\n async #scheduleNextAlarm(storage: AlarmStorage, now: number): Promise<void> {\n let next: number | null = null;\n\n const due = await storage.list<string>({ prefix: 'due:', limit: 1 });\n for (const key of due.keys()) {\n next = Number.parseInt(key.slice('due:'.length, 'due:'.length + 13), 10);\n }\n\n const inflight = await storage.list<number>({ prefix: 'inflight:' });\n for (const deadline of inflight.values()) {\n if (next === null || deadline < next) next = deadline;\n }\n\n if (next !== null) {\n await storage.setAlarm(next <= now ? now + MIN_ALARM_DELAY_MS : next);\n } else {\n await storage.deleteAlarm();\n }\n }\n\n // ---- Admin RPC (exposed through the router's queue binding) ----\n\n async stats(): Promise<QueueStats> {\n const storage = this.ctx.storage;\n const [due, inflight, dlq, alarmAt] = await Promise.all([\n storage.list({ prefix: 'due:' }),\n storage.list({ prefix: 'inflight:' }),\n storage.list({ prefix: 'dlq:' }),\n storage.getAlarm(),\n ]);\n return {\n pending: due.size,\n inflight: inflight.size,\n deadLetters: dlq.size,\n alarmAt,\n };\n }\n\n async listDeadLetters(params?: {\n limit?: number;\n cursor?: string;\n }): Promise<{ data: DeadLetterRow[]; cursor: string | null; hasMore: boolean }> {\n const limit = params?.limit ?? 100;\n const entries = await this.ctx.storage.list<DeadLetterRow>({\n prefix: 'dlq:',\n startAfter: params?.cursor,\n limit: limit + 1,\n });\n const keys = Array.from(entries.keys());\n const page = keys.slice(0, limit);\n const hasMore = keys.length > limit;\n return {\n data: page.map((k) => entries.get(k) as DeadLetterRow),\n cursor: hasMore ? page.at(-1)! : null,\n hasMore,\n };\n }\n\n /** Move a dead letter back to the live queue (attempt count reset). */\n async redriveDeadLetter(messageId: string): Promise<{ ok: boolean }> {\n const storage = this.ctx.storage;\n const now = this.#now();\n const outcome = await storage.transaction<{ ok: boolean }>(async (txn) => {\n const dlq = await txn.list<DeadLetterRow>({ prefix: 'dlq:' });\n for (const [key, dead] of dlq) {\n if (dead.messageId !== messageId) continue;\n const { failedAt: _failedAt, ...rest } = dead;\n const row: MessageRow = { ...rest, attempt: 0, lastError: undefined };\n\n if (row.idempotencyKey) {\n const dedupKey = `key:${row.idempotencyKey}`;\n const holder = await txn.get<string>(dedupKey);\n if (holder && holder !== row.messageId && (await txn.get(`msg:${holder}`))) {\n return { ok: false };\n }\n if (holder && holder !== row.messageId) {\n await txn.delete(dedupKey);\n }\n await txn.put(dedupKey, row.messageId);\n }\n\n await txn.put(`msg:${row.messageId}`, row);\n await txn.put(dueKey(now, row.messageId), row.messageId);\n await txn.delete(key);\n await this.#armAlarmAtMost(txn, now, now);\n return { ok: true };\n }\n return { ok: false };\n });\n\n return outcome;\n }\n\n async purgeDeadLetters(): Promise<{ purged: number }> {\n const storage = this.ctx.storage;\n return await storage.transaction(async (txn) => {\n const dlq = await txn.list({ prefix: 'dlq:' });\n for (const key of dlq.keys()) {\n await txn.delete(key);\n }\n return { purged: dlq.size };\n });\n }\n\n /**\n * Recovery hatch for celld's six-failure alarm abandonment: derive the due\n * time again and arm it.\n */\n async rearmAlarm(): Promise<{ alarmAt: number | null }> {\n await this.#rearm();\n return { alarmAt: await this.ctx.storage.getAlarm() };\n }\n}\n","import { DurableObject } from '../do-base.js';\n\ninterface StreamMeta {\n /** Number of chunks written so far (also the next chunk index). */\n count: number;\n /** Whether the stream has been closed (EOF). */\n closed: boolean;\n}\n\nconst META_KEY = 'meta';\nconst CHUNK_KEY_PREFIX = 'chunk:';\n/** Registry keys used when this DO instance acts as a per-run stream index. */\nconst STREAM_REGISTRY_PREFIX = 'stream:';\n\n/**\n * Zero-pad chunk indexes so `storage.list({ prefix })` returns chunks in\n * write order. 12 digits comfortably exceeds any realistic chunk count.\n */\nfunction chunkKey(index: number): string {\n return `${CHUNK_KEY_PREFIX}${index.toString().padStart(12, '0')}`;\n}\n\n/**\n * Durable Object backing workflow streams.\n *\n * Two roles, selected by the DO name:\n * - `stream:<name>`: chunk storage for a single stream. A monotonic\n * per-stream counter (maintained transactionally inside the DO) assigns\n * each chunk its index; one chunk per storage key.\n * - `run-streams:<runId>`: registry of stream names owned by a run,\n * powering `listStreamsByRunId`.\n */\nexport class StreamDO extends DurableObject {\n private async getMeta(): Promise<StreamMeta> {\n const meta = await this.ctx.storage.get<StreamMeta>(META_KEY);\n return meta ?? { count: 0, closed: false };\n }\n\n /**\n * Append a chunk. The index is allocated inside the transaction, so\n * concurrent writers can never collide or skip.\n */\n async writeChunk(data: Uint8Array): Promise<number> {\n return await this.ctx.storage.transaction(async (txn) => {\n const meta = (await txn.get<StreamMeta>(META_KEY)) ?? { count: 0, closed: false };\n if (meta.closed) {\n throw new Error('Cannot write to a closed stream');\n }\n const index = meta.count;\n await txn.put(chunkKey(index), data);\n await txn.put<StreamMeta>(META_KEY, { count: index + 1, closed: false });\n return index;\n });\n }\n\n /**\n * Close the stream (idempotent). Readers observe `done: true` once all\n * previously written chunks have been consumed.\n */\n async closeStream(): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n const meta = (await txn.get<StreamMeta>(META_KEY)) ?? { count: 0, closed: false };\n await txn.put<StreamMeta>(META_KEY, { ...meta, closed: true });\n });\n }\n\n /**\n * Read up to `limit` chunks starting at `startIndex` (0-based, inclusive).\n */\n async getChunks(params: { startIndex: number; limit: number }): Promise<{\n chunks: Uint8Array[];\n /** Whether the stream is closed. */\n done: boolean;\n /** Index of the last written chunk, -1 when empty. */\n tailIndex: number;\n }> {\n const meta = await this.getMeta();\n const start = Math.max(0, params.startIndex);\n const entries = await this.ctx.storage.list<Uint8Array>({\n prefix: CHUNK_KEY_PREFIX,\n start: chunkKey(start),\n limit: params.limit,\n });\n return {\n chunks: Array.from(entries.values()),\n done: meta.closed,\n tailIndex: meta.count - 1,\n };\n }\n\n /**\n * Lightweight stream metadata: last chunk index and completion flag.\n */\n async getInfo(): Promise<{ tailIndex: number; done: boolean }> {\n const meta = await this.getMeta();\n return { tailIndex: meta.count - 1, done: meta.closed };\n }\n\n /**\n * Register a stream name against this per-run registry instance.\n */\n async registerStream(name: string): Promise<void> {\n await this.ctx.storage.put(`${STREAM_REGISTRY_PREFIX}${name}`, true);\n }\n\n /**\n * List stream names registered against this per-run registry instance.\n */\n async listStreams(): Promise<string[]> {\n const entries = await this.ctx.storage.list<boolean>({ prefix: STREAM_REGISTRY_PREFIX });\n return Array.from(entries.keys()).map((key) => key.slice(STREAM_REGISTRY_PREFIX.length));\n }\n}\n","/**\n * Transactional event-application core shared by the real WorkflowRunDO and\n * the in-memory test mocks.\n *\n * All guard checks, the event append, and the entity mutation happen against a\n * single {@link EventStore}. The Durable Object wraps a call to\n * {@link applyEvent} in `ctx.storage.transaction()`, so the whole operation is\n * atomic; the mocks run it against an in-memory store.\n *\n * Guard semantics are ported from the upstream `@workflow/world-local` /\n * `@workflow/world-postgres` reference implementations (4.2.x contract):\n * - run_started on a terminal run -> RunExpiredError\n * - terminal transitions on a terminal run -> EntityConflictError\n * - run_cancelled is idempotent on an already-cancelled run\n * - duplicate step_created / hook_created -> EntityConflictError\n * - step events on a terminal step -> EntityConflictError\n * - step_started before step.retryAfter -> TooEarlyError\n * - error/output/completedAt are cleared whenever a run re-enters a\n * non-final status (WorkflowRunSchema is a discriminated union)\n *\n * Errors are returned as structured outcomes (never thrown) because custom\n * error classes do not survive the Durable Object RPC boundary with their\n * `name` intact — and `@workflow/errors` matches errors by name via `.is()`.\n * The storage layer converts outcomes back into the typed errors.\n */\n\nimport type {\n CreateEventRequest,\n Event,\n Hook,\n RunCreatedEventRequest,\n Step,\n WorkflowRun,\n} from '@workflow/world';\nimport {\n EventSchema,\n HookSchema,\n isLegacySpecVersion,\n isTerminalStepStatus,\n isTerminalWorkflowRunStatus,\n requiresNewerWorld,\n SPEC_VERSION_CURRENT,\n StepSchema,\n WorkflowRunSchema,\n} from '@workflow/world';\nimport { compact } from './util.js';\n\n/** Storage key for the run entity. */\nconst RUN_KEY = 'run';\n/** Key prefixes for per-entity storage. */\nexport const EVENT_KEY_PREFIX = 'event:';\nexport const STEP_KEY_PREFIX = 'step:';\nexport const HOOK_KEY_PREFIX = 'hook:';\nexport const STEP_CREATED_KEY_PREFIX = 'stepcreated:';\nexport const HOOK_CREATED_KEY_PREFIX = 'hookcreated:';\n/**\n * Marker recording that a hook_created event was committed for a hookId.\n * Mirrors postgres' `workflow_events_entity_creation_unique` partial index:\n * it outlives hook disposal so a replayed hook_created after dispose is\n * rejected as a duplicate instead of resurrecting the hook.\n */\nconst HOOK_EVENT_MARKER_PREFIX = 'hookevent:';\n\nexport interface EventStoreListOptions {\n prefix: string;\n /** Exclusive lower bound (full key). */\n startAfter?: string;\n /** Exclusive upper bound (full key). */\n end?: string;\n limit?: number;\n reverse?: boolean;\n}\n\n/**\n * Minimal transactional key-value surface, satisfied by\n * `DurableObjectTransaction` / `DurableObjectStorage` and by the in-memory\n * test-mock store. Keys list in lexicographic order (reversed when\n * `reverse: true`).\n */\nexport interface EventStore {\n get<T>(key: string): Promise<T | undefined>;\n put<T>(key: string, value: T): Promise<void>;\n delete(key: string): Promise<boolean>;\n list<T>(options: EventStoreListOptions): Promise<Map<string, T>>;\n}\n\nexport interface ApplyEventRequest {\n /** The effective run id (already resolved / generated by the caller). */\n runId: string;\n data: CreateEventRequest | RunCreatedEventRequest;\n /**\n * Current holder of the hook token per the global KV token index\n * (hook_created only). `null` means the token is unclaimed.\n */\n tokenHolder?: { runId: string; hookId: string } | null;\n}\n\nexport type ApplyEventErrorCode =\n | 'RUN_NOT_FOUND'\n | 'STEP_NOT_FOUND'\n | 'HOOK_NOT_FOUND'\n | 'ENTITY_CONFLICT'\n | 'RUN_EXPIRED'\n | 'TOO_EARLY'\n | 'RUN_NOT_SUPPORTED'\n | 'LEGACY_RUN_NOT_SUPPORTED';\n\nexport interface ApplyEventFailure {\n ok: false;\n code: ApplyEventErrorCode;\n message: string;\n /** Seconds until retry is allowed (TOO_EARLY only). */\n retryAfterSeconds?: number;\n /** The run's spec version (RUN_NOT_SUPPORTED only). */\n runSpecVersion?: number;\n}\n\nexport interface ApplyEventSuccess {\n ok: true;\n /** Absent for idempotent replays that record no new event. */\n event?: Event;\n run?: WorkflowRun;\n step?: Step;\n hook?: Hook;\n /** Hooks whose tokens must be released from the global KV index. */\n releasedHooks: Array<{ hookId: string; token: string }>;\n /** Set when a run entity was created (run_created or resilient bootstrap). */\n runCreated?: { workflowName: string; createdAt: Date };\n /** Set when the global KV hook index must be (re)written. */\n hookToIndex?: Hook;\n /** All events (ascending), preloaded for run_started responses. */\n events?: Event[];\n}\n\nexport type ApplyEventOutcome = ApplyEventSuccess | ApplyEventFailure;\n\ninterface ApplyEventContext extends ApplyEventRequest {\n nextEventId(): string;\n now: Date;\n}\n\nfunction failure(\n code: ApplyEventErrorCode,\n message: string,\n extra?: Pick<ApplyEventFailure, 'retryAfterSeconds' | 'runSpecVersion'>,\n): ApplyEventFailure {\n return { ok: false, code, message, ...extra };\n}\n\nfunction readStringProp(value: unknown, key: string): string | undefined {\n if (value !== null && typeof value === 'object') {\n const prop = (value as Record<string, unknown>)[key];\n if (typeof prop === 'string') return prop;\n }\n return undefined;\n}\n\n/**\n * Map a failure eventData.error (which may be a string, an Error-shaped\n * object, or anything else) to the structured error stored on entities.\n * Matches upstream: string errors keep their text, errorCode is preserved.\n */\nfunction toStructuredError(\n error: unknown,\n opts?: { stack?: string; code?: string },\n): { message: string; stack?: string; code?: string } {\n const message =\n typeof error === 'string' ? error : (readStringProp(error, 'message') ?? 'Unknown error');\n return {\n message,\n stack: opts?.stack ?? readStringProp(error, 'stack'),\n code: opts?.code ?? readStringProp(error, 'code'),\n };\n}\n\n/**\n * Shared cursor pagination over a key prefix. Fetches `limit + 1` entries to\n * detect `hasMore` without ever skipping the boundary entry (the cursor is\n * derived from the last *returned* item, not the peeked one).\n */\nexport async function listByPrefix<T>(\n store: EventStore,\n prefix: string,\n params: { limit: number; cursor?: string; sortOrder?: 'asc' | 'desc' },\n getId: (item: T) => string,\n): Promise<{ data: T[]; cursor: string | null; hasMore: boolean }> {\n const { limit, cursor, sortOrder = 'asc' } = params;\n const options: EventStoreListOptions =\n sortOrder === 'desc'\n ? { prefix, reverse: true, limit: limit + 1, end: cursor ? `${prefix}${cursor}` : undefined }\n : { prefix, limit: limit + 1, startAfter: cursor ? `${prefix}${cursor}` : undefined };\n const entries = await store.list<T>(options);\n const values = Array.from(entries.values());\n const hasMore = values.length > limit;\n const data = values.slice(0, limit);\n const last = data.at(-1);\n return {\n data,\n cursor: hasMore && last !== undefined ? getId(last) : null,\n hasMore,\n };\n}\n\nfunction creationIndexKey(prefix: string, createdAt: Date, id: string): string {\n return `${prefix}${createdAt.toISOString()}:${id}`;\n}\n\n/**\n * Cursor pagination over an explicit creation-time index. Entity ids are\n * values rather than key suffixes, so caller-supplied ids cannot disturb the\n * requested ordering.\n */\nexport async function listByCreationTime<T>(\n store: EventStore,\n indexPrefix: string,\n entityPrefix: string,\n params: { limit: number; cursor?: string; sortOrder?: 'asc' | 'desc' },\n): Promise<{ data: T[]; cursor: string | null; hasMore: boolean }> {\n const { limit, cursor, sortOrder = 'asc' } = params;\n const entries = await store.list<string>(\n sortOrder === 'desc'\n ? {\n prefix: indexPrefix,\n reverse: true,\n limit: limit + 1,\n end: cursor ? `${indexPrefix}${cursor}` : undefined,\n }\n : {\n prefix: indexPrefix,\n limit: limit + 1,\n startAfter: cursor ? `${indexPrefix}${cursor}` : undefined,\n },\n );\n const page = Array.from(entries.entries()).slice(0, limit);\n const data: T[] = [];\n for (const [, id] of page) {\n const item = await store.get<T>(`${entityPrefix}${id}`);\n if (item !== undefined) data.push(item);\n }\n const hasMore = entries.size > limit;\n const lastKey = page.at(-1)?.[0];\n return {\n data,\n cursor: hasMore && lastKey ? lastKey.slice(indexPrefix.length) : null,\n hasMore,\n };\n}\n\n/** Delete all hook entities for the run, returning the released tokens. */\nasync function releaseAllHooks(\n store: EventStore,\n): Promise<Array<{ hookId: string; token: string }>> {\n const hooks = await store.list<Hook>({ prefix: HOOK_KEY_PREFIX });\n const released: Array<{ hookId: string; token: string }> = [];\n for (const hook of hooks.values()) {\n await store.delete(`${HOOK_KEY_PREFIX}${hook.hookId}`);\n await store.delete(creationIndexKey(HOOK_CREATED_KEY_PREFIX, hook.createdAt, hook.hookId));\n released.push({ hookId: hook.hookId, token: hook.token });\n }\n return released;\n}\n\nexport async function applyEvent(\n store: EventStore,\n ctx: ApplyEventContext,\n): Promise<ApplyEventOutcome> {\n const { runId, data, now } = ctx;\n const specVersion = data.specVersion ?? SPEC_VERSION_CURRENT;\n\n /** Build and validate the stored event BEFORE anything is persisted. */\n const buildEvent = (record: Record<string, unknown>): Event => {\n const withMeta: Record<string, unknown> = {\n ...record,\n runId,\n eventId: ctx.nextEventId(),\n createdAt: now,\n specVersion,\n };\n // eventData belongs on run_created only; run_started must not carry it.\n if (record.eventType === 'run_started') {\n delete withMeta.eventData;\n }\n return EventSchema.parse(compact(withMeta));\n };\n\n const putEvent = async (event: Event): Promise<void> => {\n await store.put(`${EVENT_KEY_PREFIX}${event.eventId}`, event);\n };\n\n // ============================================================\n // VALIDATION: current run state (skipped for run_created and for\n // step_completed / step_retrying, matching upstream — those only operate\n // on running steps regardless of run state).\n // ============================================================\n let currentRun: WorkflowRun | undefined;\n const skipRunValidation =\n data.eventType === 'run_created' ||\n data.eventType === 'step_completed' ||\n data.eventType === 'step_retrying';\n if (!skipRunValidation) {\n currentRun = await store.get<WorkflowRun>(RUN_KEY);\n }\n\n // ============================================================\n // RESILIENT START: run_started on a non-existent run bootstraps the run\n // from the message's runInput (spec >= 3 queue transport).\n // ============================================================\n let bootstrapped: ApplyEventSuccess['runCreated'];\n if (data.eventType === 'run_started' && !currentRun && data.eventData) {\n const { deploymentId, workflowName, input, executionContext } = data.eventData;\n if (deploymentId && workflowName && input !== undefined) {\n const createdRun = WorkflowRunSchema.parse(\n compact({\n runId,\n deploymentId,\n workflowName,\n specVersion,\n executionContext,\n input,\n status: 'pending',\n output: undefined,\n error: undefined,\n startedAt: undefined,\n completedAt: undefined,\n createdAt: now,\n updatedAt: now,\n }),\n );\n const runCreatedEvent = buildEvent({\n eventType: 'run_created',\n eventData: { deploymentId, workflowName, input, executionContext },\n });\n await store.put(RUN_KEY, createdRun);\n await putEvent(runCreatedEvent);\n currentRun = createdRun;\n bootstrapped = { workflowName, createdAt: now };\n }\n }\n\n // ============================================================\n // VERSION COMPATIBILITY\n // ============================================================\n if (currentRun) {\n if (requiresNewerWorld(currentRun.specVersion)) {\n return failure(\n 'RUN_NOT_SUPPORTED',\n `Run \"${runId}\" requires a newer world (run specVersion ${currentRun.specVersion}, world ${SPEC_VERSION_CURRENT})`,\n { runSpecVersion: currentRun.specVersion },\n );\n }\n if (isLegacySpecVersion(currentRun.specVersion)) {\n return failure(\n 'LEGACY_RUN_NOT_SUPPORTED',\n `Run \"${runId}\" was created with a legacy spec version (${currentRun.specVersion ?? 'undefined'}) not supported by this world`,\n );\n }\n }\n\n // ============================================================\n // GUARDS: terminal run state\n // ============================================================\n if (currentRun && isTerminalWorkflowRunStatus(currentRun.status)) {\n // Idempotent: run_cancelled on an already-cancelled run records the event\n // and returns the current state.\n if (data.eventType === 'run_cancelled' && currentRun.status === 'cancelled') {\n const event = buildEvent({ ...data });\n await putEvent(event);\n return { ok: true, event, run: currentRun, releasedHooks: [] };\n }\n if (data.eventType === 'run_started') {\n return failure(\n 'RUN_EXPIRED',\n `Workflow run \"${runId}\" is already in terminal state \"${currentRun.status}\"`,\n );\n }\n if (\n data.eventType === 'run_completed' ||\n data.eventType === 'run_failed' ||\n data.eventType === 'run_cancelled'\n ) {\n return failure(\n 'ENTITY_CONFLICT',\n `Cannot transition run from terminal state \"${currentRun.status}\"`,\n );\n }\n if (\n data.eventType === 'step_created' ||\n data.eventType === 'hook_created' ||\n data.eventType === 'wait_created'\n ) {\n return failure(\n 'ENTITY_CONFLICT',\n `Cannot create new entities on run in terminal state \"${currentRun.status}\"`,\n );\n }\n }\n\n // ============================================================\n // GUARDS: step ordering and terminal state\n // ============================================================\n let validatedStep: Step | undefined;\n if (\n data.eventType === 'step_started' ||\n data.eventType === 'step_completed' ||\n data.eventType === 'step_failed' ||\n data.eventType === 'step_retrying'\n ) {\n validatedStep = await store.get<Step>(`${STEP_KEY_PREFIX}${data.correlationId}`);\n if (!validatedStep) {\n return failure('STEP_NOT_FOUND', `Step \"${data.correlationId}\" not found`);\n }\n if (isTerminalStepStatus(validatedStep.status)) {\n return failure(\n 'ENTITY_CONFLICT',\n `Cannot modify step in terminal state \"${validatedStep.status}\"`,\n );\n }\n // On terminal runs, only in-flight steps may still record progress.\n if (\n currentRun &&\n isTerminalWorkflowRunStatus(currentRun.status) &&\n validatedStep.status !== 'running'\n ) {\n return failure(\n 'RUN_EXPIRED',\n `Cannot modify non-running step on run in terminal state \"${currentRun.status}\"`,\n );\n }\n }\n\n // ============================================================\n // GUARDS: hook event ordering\n // ============================================================\n if (\n (data.eventType === 'hook_disposed' || data.eventType === 'hook_received') &&\n data.correlationId\n ) {\n const existingHook = await store.get<Hook>(`${HOOK_KEY_PREFIX}${data.correlationId}`);\n if (!existingHook) {\n return failure('HOOK_NOT_FOUND', `Hook \"${data.correlationId}\" not found`);\n }\n }\n\n // Non-run_created events require the run to exist (after the resilient\n // start bootstrap had its chance). step_completed / step_retrying skip the\n // run read entirely — their step guard above already proves the run exists.\n if (!skipRunValidation && data.eventType !== 'run_started' && !currentRun) {\n return failure('RUN_NOT_FOUND', `Workflow run \"${runId}\" not found`);\n }\n\n // ============================================================\n // EVENT + ENTITY WRITES (single transaction)\n // ============================================================\n switch (data.eventType) {\n case 'run_created': {\n const existing = await store.get<WorkflowRun>(RUN_KEY);\n if (existing) {\n // Idempotent replay: return the existing run without appending a\n // duplicate run_created event to the log.\n return { ok: true, run: existing, releasedHooks: [] };\n }\n const run = WorkflowRunSchema.parse(\n compact({\n runId,\n deploymentId: data.eventData.deploymentId,\n workflowName: data.eventData.workflowName,\n specVersion,\n executionContext: data.eventData.executionContext,\n input: data.eventData.input,\n status: 'pending',\n output: undefined,\n error: undefined,\n startedAt: undefined,\n completedAt: undefined,\n createdAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(RUN_KEY, run);\n await putEvent(event);\n return {\n ok: true,\n event,\n run,\n releasedHooks: [],\n runCreated: { workflowName: data.eventData.workflowName, createdAt: now },\n };\n }\n\n case 'run_started': {\n if (!currentRun) {\n return failure('RUN_NOT_FOUND', `Workflow run \"${runId}\" not found`);\n }\n // Idempotent for concurrent invocations / queue redeliveries: if the\n // run is already running this is a replay — no duplicate event.\n if (currentRun.status === 'running') {\n return { ok: true, run: currentRun, releasedHooks: [] };\n }\n const run = WorkflowRunSchema.parse(\n compact({\n ...currentRun,\n status: 'running',\n output: undefined,\n error: undefined,\n completedAt: undefined,\n startedAt: currentRun.startedAt ?? now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(RUN_KEY, run);\n await putEvent(event);\n // Preload all events so the runtime can skip the initial events.list.\n const allEvents = await listByPrefix<Event>(\n store,\n EVENT_KEY_PREFIX,\n { limit: 1000, sortOrder: 'asc' },\n (e) => e.eventId,\n );\n return {\n ok: true,\n event,\n run,\n releasedHooks: [],\n runCreated: bootstrapped,\n events: allEvents.data,\n };\n }\n\n case 'run_completed': {\n if (!currentRun) {\n return failure('RUN_NOT_FOUND', `Workflow run \"${runId}\" not found`);\n }\n const run = WorkflowRunSchema.parse(\n compact({\n ...currentRun,\n status: 'completed',\n output: data.eventData.output,\n error: undefined,\n completedAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(RUN_KEY, run);\n await putEvent(event);\n const releasedHooks = await releaseAllHooks(store);\n return { ok: true, event, run, releasedHooks };\n }\n\n case 'run_failed': {\n if (!currentRun) {\n return failure('RUN_NOT_FOUND', `Workflow run \"${runId}\" not found`);\n }\n const run = WorkflowRunSchema.parse(\n compact({\n ...currentRun,\n status: 'failed',\n output: undefined,\n error: toStructuredError(data.eventData.error, {\n code: data.eventData.errorCode ?? readStringProp(data.eventData.error, 'code'),\n }),\n completedAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(RUN_KEY, run);\n await putEvent(event);\n const releasedHooks = await releaseAllHooks(store);\n return { ok: true, event, run, releasedHooks };\n }\n\n case 'run_cancelled': {\n if (!currentRun) {\n return failure('RUN_NOT_FOUND', `Workflow run \"${runId}\" not found`);\n }\n const run = WorkflowRunSchema.parse(\n compact({\n ...currentRun,\n status: 'cancelled',\n output: undefined,\n error: undefined,\n completedAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(RUN_KEY, run);\n await putEvent(event);\n const releasedHooks = await releaseAllHooks(store);\n return { ok: true, event, run, releasedHooks };\n }\n\n case 'step_created': {\n const stepKey = `${STEP_KEY_PREFIX}${data.correlationId}`;\n const existing = await store.get<Step>(stepKey);\n if (existing) {\n // Core catches EntityConflictError for exactly this replay case\n // (\"Step already exists, continuing\").\n return failure('ENTITY_CONFLICT', `Step \"${data.correlationId}\" already exists`);\n }\n const step = StepSchema.parse(\n compact({\n runId,\n stepId: data.correlationId,\n stepName: data.eventData.stepName,\n status: 'pending',\n input: data.eventData.input,\n output: undefined,\n error: undefined,\n attempt: 0,\n startedAt: undefined,\n completedAt: undefined,\n retryAfter: undefined,\n createdAt: now,\n updatedAt: now,\n specVersion,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(stepKey, step);\n await store.put(\n creationIndexKey(STEP_CREATED_KEY_PREFIX, step.createdAt, step.stepId),\n step.stepId,\n );\n await putEvent(event);\n return { ok: true, event, step, releasedHooks: [] };\n }\n\n case 'step_started': {\n const step = validatedStep;\n if (!step) {\n return failure('STEP_NOT_FOUND', `Step \"${data.correlationId}\" not found`);\n }\n if (step.retryAfter && step.retryAfter.getTime() > now.getTime()) {\n return failure(\n 'TOO_EARLY',\n `Cannot start step \"${data.correlationId}\": retryAfter timestamp has not been reached yet`,\n {\n retryAfterSeconds: Math.ceil((step.retryAfter.getTime() - now.getTime()) / 1000),\n },\n );\n }\n const updated = StepSchema.parse(\n compact({\n ...step,\n status: 'running',\n // Only set startedAt on the first start; increment attempt each start.\n startedAt: step.startedAt ?? now,\n attempt: step.attempt + 1,\n retryAfter: undefined,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(`${STEP_KEY_PREFIX}${data.correlationId}`, updated);\n await putEvent(event);\n return { ok: true, event, step: updated, releasedHooks: [] };\n }\n\n case 'step_completed': {\n const step = validatedStep;\n if (!step) {\n return failure('STEP_NOT_FOUND', `Step \"${data.correlationId}\" not found`);\n }\n const updated = StepSchema.parse(\n compact({\n ...step,\n status: 'completed',\n output: data.eventData.result,\n completedAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(`${STEP_KEY_PREFIX}${data.correlationId}`, updated);\n await putEvent(event);\n return { ok: true, event, step: updated, releasedHooks: [] };\n }\n\n case 'step_failed': {\n const step = validatedStep;\n if (!step) {\n return failure('STEP_NOT_FOUND', `Step \"${data.correlationId}\" not found`);\n }\n const updated = StepSchema.parse(\n compact({\n ...step,\n status: 'failed',\n error: toStructuredError(data.eventData.error, { stack: data.eventData.stack }),\n completedAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(`${STEP_KEY_PREFIX}${data.correlationId}`, updated);\n await putEvent(event);\n return { ok: true, event, step: updated, releasedHooks: [] };\n }\n\n case 'step_retrying': {\n const step = validatedStep;\n if (!step) {\n return failure('STEP_NOT_FOUND', `Step \"${data.correlationId}\" not found`);\n }\n const updated = StepSchema.parse(\n compact({\n ...step,\n status: 'pending',\n error: toStructuredError(data.eventData.error, { stack: data.eventData.stack }),\n retryAfter: data.eventData.retryAfter ? new Date(data.eventData.retryAfter) : undefined,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(`${STEP_KEY_PREFIX}${data.correlationId}`, updated);\n await putEvent(event);\n return { ok: true, event, step: updated, releasedHooks: [] };\n }\n\n case 'hook_created': {\n const hookId = data.correlationId;\n const token = data.eventData.token;\n const holder = ctx.tokenHolder ?? null;\n const markerKey = `${HOOK_EVENT_MARKER_PREFIX}${hookId}`;\n const hookKey = `${HOOK_KEY_PREFIX}${hookId}`;\n\n if (holder && (holder.runId !== runId || holder.hookId !== hookId)) {\n // A different (runId, hookId) holds this token. Record a\n // hook_conflict event carrying conflictingRunId so the claiming\n // workflow fails deterministically when the hook is awaited. The\n // legitimate holder's KV index entry is left untouched.\n const event = buildEvent({\n eventType: 'hook_conflict',\n correlationId: hookId,\n eventData: { token, conflictingRunId: holder.runId },\n });\n await putEvent(event);\n return { ok: true, event, releasedHooks: [] };\n }\n\n const existingMarker = await store.get<string>(markerKey);\n if (existingMarker !== undefined) {\n const existingHook = await store.get<Hook>(hookKey);\n if (existingHook && !holder) {\n // Crash orphan: hook + event committed but the global KV index\n // write was lost. Complete the partial write by re-indexing.\n return { ok: true, hook: existingHook, hookToIndex: existingHook, releasedHooks: [] };\n }\n // Fully-committed duplicate (or re-create after disposal): reject so\n // the runtime's concurrent-replay catch path can swallow it.\n return failure('ENTITY_CONFLICT', `Hook \"${hookId}\" already created`);\n }\n\n const hook = HookSchema.parse(\n compact({\n runId,\n hookId,\n token,\n metadata: data.eventData.metadata,\n ownerId: '',\n projectId: '',\n environment: '',\n createdAt: now,\n specVersion,\n isWebhook: data.eventData.isWebhook ?? false,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(hookKey, hook);\n await store.put(\n creationIndexKey(HOOK_CREATED_KEY_PREFIX, hook.createdAt, hook.hookId),\n hook.hookId,\n );\n await store.put(markerKey, event.eventId);\n await putEvent(event);\n return { ok: true, event, hook, hookToIndex: hook, releasedHooks: [] };\n }\n\n case 'hook_disposed': {\n const hookKey = `${HOOK_KEY_PREFIX}${data.correlationId}`;\n // Existence was validated above; read again for the token.\n const hook = await store.get<Hook>(hookKey);\n if (!hook) {\n return failure('HOOK_NOT_FOUND', `Hook \"${data.correlationId}\" not found`);\n }\n await store.delete(hookKey);\n await store.delete(creationIndexKey(HOOK_CREATED_KEY_PREFIX, hook.createdAt, hook.hookId));\n const event = buildEvent({ ...data });\n await putEvent(event);\n return {\n ok: true,\n event,\n releasedHooks: [{ hookId: hook.hookId, token: hook.token }],\n };\n }\n\n // hook_received, hook_conflict, wait_created, wait_completed are\n // event-only at the storage level for this world.\n default: {\n const event = buildEvent({ ...data });\n await putEvent(event);\n return { ok: true, event, releasedHooks: [] };\n }\n }\n}\n","import { DurableObject } from '../do-base.js';\nimport type { Event, Hook, Step, WorkflowRun } from '@workflow/world';\nimport {\n applyEvent,\n type ApplyEventOutcome,\n type ApplyEventRequest,\n EVENT_KEY_PREFIX,\n type EventStore,\n HOOK_CREATED_KEY_PREFIX,\n HOOK_KEY_PREFIX,\n listByCreationTime,\n listByPrefix,\n STEP_CREATED_KEY_PREFIX,\n STEP_KEY_PREFIX,\n} from '../../apply-event.js';\n\n/**\n * Current schema version for DO storage.\n * Increment when making breaking changes to the storage layout.\n * Migrations run lazily on first request after deploy.\n *\n * v2: one storage key per event ('event:<eventId>'), step ('step:<stepId>')\n * and hook ('hook:<hookId>') instead of single aggregate values. This package\n * is pre-production, so the migration simply drops the legacy aggregates.\n */\nconst CURRENT_SCHEMA_VERSION = 3;\n\n/**\n * Idempotent migration functions keyed by target version. The schema version\n * is written only after the migration completes, so eviction safely retries\n * an interrupted migration.\n */\nconst MIGRATIONS: Record<number, (storage: DurableObjectStorage) => Promise<void>> = {\n 2: async (storage) => {\n await storage.transaction(async (txn) => {\n // Pre-production layout change: drop the v1 aggregate values.\n await txn.delete('events');\n await txn.delete('steps');\n await txn.delete('hooks');\n });\n },\n 3: async (storage) => {\n await backfillCreationIndex<Step>(\n storage,\n STEP_KEY_PREFIX,\n STEP_CREATED_KEY_PREFIX,\n (step) => step.stepId,\n );\n await backfillCreationIndex<Hook>(\n storage,\n HOOK_KEY_PREFIX,\n HOOK_CREATED_KEY_PREFIX,\n (hook) => hook.hookId,\n );\n },\n};\n\nasync function backfillCreationIndex<T extends { createdAt: Date }>(\n storage: DurableObjectStorage,\n entityPrefix: string,\n indexPrefix: string,\n getId: (entity: T) => string,\n): Promise<void> {\n let startAfter: string | undefined;\n while (true) {\n const entities = await storage.list<T>({ prefix: entityPrefix, startAfter, limit: 100 });\n if (entities.size === 0) return;\n for (const [key, entity] of entities) {\n const id = getId(entity);\n await storage.put(`${indexPrefix}${entity.createdAt.toISOString()}:${id}`, id);\n startAfter = key;\n }\n if (entities.size < 100) return;\n }\n}\n\n/**\n * Ensure the DO storage schema is up to date.\n * Runs any pending migrations sequentially inside transactions,\n * persisting the version after each successful migration.\n * Safe to call on every request -- it's a no-op when already current.\n */\nasync function ensureSchemaUpToDate(storage: DurableObjectStorage): Promise<void> {\n const stored = (await storage.get<number>('schema_version')) ?? 1;\n\n for (let v = stored + 1; v <= CURRENT_SCHEMA_VERSION; v++) {\n const migration = MIGRATIONS[v];\n if (migration) {\n await migration(storage);\n }\n await storage.put('schema_version', v);\n }\n}\n\n/**\n * Adapt DO storage (or a transaction) to the {@link EventStore} interface\n * shared with the test mocks. No casts: the methods line up structurally,\n * this just pins the subset we rely on.\n */\nfunction storeFrom(storage: DurableObjectStorage | DurableObjectTransaction): EventStore {\n return {\n get: (key) => storage.get(key),\n put: (key, value) => storage.put(key, value),\n delete: (key) => storage.delete(key),\n list: (options) => storage.list(options),\n };\n}\n\ninterface InflightClaim {\n messageId: string;\n claimedAt: number;\n}\n\n/**\n * Durable Object for managing a single workflow run's state.\n *\n * All event-sourced writes go through {@link applyEvent} inside a single\n * storage transaction: guard checks, the event append, and the entity\n * mutation are atomic even if the DO is evicted mid-operation.\n *\n * Instances named `claim:<queueName>:<idempotencyKey>` are used purely as\n * queue-message dedup claims (see claimInflight/releaseInflight).\n */\nexport class WorkflowRunDO extends DurableObject {\n private schemaReady: Promise<void> | null = null;\n\n /**\n * Lazily ensure schema migrations have run.\n * Memoized so it only runs once per DO instantiation.\n */\n private ensureSchema(): Promise<void> {\n if (!this.schemaReady) {\n this.schemaReady = ensureSchemaUpToDate(this.ctx.storage);\n }\n return this.schemaReady;\n }\n\n /**\n * Apply an event: validate, guard, append the event and mutate the entity\n * in ONE storage transaction. Guard failures are returned as structured\n * outcomes (not thrown) because typed errors do not survive the RPC\n * boundary with their `name` intact.\n */\n async applyEvent(request: ApplyEventRequest): Promise<ApplyEventOutcome> {\n await this.ensureSchema();\n return await this.ctx.storage.transaction(async (txn) => {\n let eventSequence = (await txn.get<number>('event_sequence')) ?? 0;\n const outcome = await applyEvent(storeFrom(txn), {\n ...request,\n // The sequence is durable, so a newly instantiated DO can never\n // allocate an event id that sorts before an earlier commit.\n nextEventId: () => `wevt_z${String(++eventSequence).padStart(20, '0')}`,\n now: new Date(),\n });\n if (outcome.ok) {\n await txn.put('event_sequence', eventSequence);\n }\n return outcome;\n });\n }\n\n /**\n * Get the workflow run\n */\n async getRun(): Promise<WorkflowRun | null> {\n await this.ensureSchema();\n const run = await this.ctx.storage.get<WorkflowRun>('run');\n return run ?? null;\n }\n\n /**\n * Get a specific step\n */\n async getStep(stepId: string): Promise<Step | null> {\n await this.ensureSchema();\n const step = await this.ctx.storage.get<Step>(`${STEP_KEY_PREFIX}${stepId}`);\n return step ?? null;\n }\n\n /**\n * List steps with real limit/cursor pagination (cursor = last stepId).\n */\n async listSteps(params?: {\n limit?: number;\n cursor?: string;\n sortOrder?: 'asc' | 'desc';\n }): Promise<{ data: Step[]; cursor: string | null; hasMore: boolean }> {\n await this.ensureSchema();\n return listByCreationTime<Step>(\n storeFrom(this.ctx.storage),\n STEP_CREATED_KEY_PREFIX,\n STEP_KEY_PREFIX,\n {\n limit: params?.limit ?? 20,\n cursor: params?.cursor,\n sortOrder: params?.sortOrder ?? 'asc',\n },\n );\n }\n\n /**\n * Get a specific event\n */\n async getEvent(eventId: string): Promise<Event | null> {\n await this.ensureSchema();\n const event = await this.ctx.storage.get<Event>(`${EVENT_KEY_PREFIX}${eventId}`);\n return event ?? null;\n }\n\n /**\n * List events with real limit/cursor pagination. Events are keyed by their\n * monotonic ULID eventId, so storage order == event order.\n */\n async listEvents(params?: {\n limit?: number;\n cursor?: string;\n sortOrder?: 'asc' | 'desc';\n }): Promise<{ data: Event[]; cursor: string | null; hasMore: boolean }> {\n await this.ensureSchema();\n return listByPrefix<Event>(\n storeFrom(this.ctx.storage),\n EVENT_KEY_PREFIX,\n {\n limit: params?.limit ?? 100,\n cursor: params?.cursor,\n sortOrder: params?.sortOrder ?? 'asc',\n },\n (event) => event.eventId,\n );\n }\n\n /**\n * List hooks with real limit/cursor pagination (cursor = last hookId).\n */\n async listHooks(params?: {\n limit?: number;\n cursor?: string;\n sortOrder?: 'asc' | 'desc';\n }): Promise<{ data: Hook[]; cursor: string | null; hasMore: boolean }> {\n await this.ensureSchema();\n return listByCreationTime<Hook>(\n storeFrom(this.ctx.storage),\n HOOK_CREATED_KEY_PREFIX,\n HOOK_KEY_PREFIX,\n {\n limit: params?.limit ?? 100,\n cursor: params?.cursor,\n sortOrder: params?.sortOrder ?? 'asc',\n },\n );\n }\n\n /**\n * Claim a queue-message dedup slot. Used on DO instances dedicated to a\n * single idempotency key (`claim:<queueName>:<idempotencyKey>`).\n *\n * - Unclaimed -> claim and proceed.\n * - Claimed by the SAME messageId -> redelivery of the same message\n * (previous attempt failed transiently) -> proceed.\n * - Claimed by a DIFFERENT messageId -> concurrent duplicate -> reject,\n * unless the claim is stale (holder crashed / went to the DLQ without\n * releasing), in which case the claim is stolen.\n */\n async claimInflight(params: {\n messageId: string;\n staleMs: number;\n }): Promise<{ claimed: boolean }> {\n await this.ensureSchema();\n return await this.ctx.storage.transaction(async (txn) => {\n const existing = await txn.get<InflightClaim>('claim');\n const now = Date.now();\n if (\n existing &&\n existing.messageId !== params.messageId &&\n now - existing.claimedAt < params.staleMs\n ) {\n return { claimed: false };\n }\n await txn.put<InflightClaim>('claim', { messageId: params.messageId, claimedAt: now });\n return { claimed: true };\n });\n }\n\n /**\n * Release a queue-message dedup claim after the message was fully handled.\n */\n async releaseInflight(): Promise<void> {\n await this.ensureSchema();\n await this.ctx.storage.delete('claim');\n }\n}\n","/**\n * celld worker entry: exports the Durable Object (cell) classes and the\n * default fetch router. This module (and everything it imports) must stay\n * free of Node built-ins — it runs inside celld's workerd runtime.\n */\nimport { createRouter, type WorkerEnv } from './router.js';\n\nexport { IndexDO } from './durable-objects/IndexDO.js';\nexport { QueueDO } from './durable-objects/QueueDO.js';\nexport { StreamDO } from './durable-objects/StreamDO.js';\nexport { WorkflowRunDO } from './durable-objects/WorkflowRunDO.js';\nexport { createRouter, type WorkerEnv } from './router.js';\n\nexport default {\n async fetch(request: Request, env: WorkerEnv): Promise<Response> {\n return createRouter(env)(request);\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"worker.js","names":["#now","#scheduleNextAlarm","#armAlarmAtMost","#claimPhase","#deliver","#intVar","#fetch","#ack","#retry","#rearm"],"sources":["../src/vendor/shared/serialization.ts","../src/codec.ts","../src/worker/auth.ts","../src/worker/router.ts","../src/vendor/shared/util.ts","../src/worker/durable-objects/IndexDO.ts","../src/worker/durable-objects/QueueDO.ts","../src/worker/durable-objects/StreamDO.ts","../src/apply-event.ts","../src/retention.ts","../src/worker/durable-objects/WorkflowRunDO.ts","../src/worker/worker.ts"],"sourcesContent":["/** Standard Date fields used across all worlds */\nexport const DATE_FIELDS = new Set([\n 'createdAt',\n 'updatedAt',\n 'startedAt',\n 'completedAt',\n 'retryAfter',\n] as const);\n\n/**\n * JSON reviver that converts ISO date strings to Date objects.\n * Use with JSON.parse(json, dateReviver).\n */\nexport function dateReviver(key: string, value: unknown): unknown {\n if (\n DATE_FIELDS.has(key as typeof DATE_FIELDS extends Set<infer T> ? T : never) &&\n typeof value === 'string'\n ) {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? value : date;\n }\n return value;\n}\n\n/**\n * Base64 helpers. Modified vs upstream: implemented over atob/btoa instead of\n * Buffer so this module is safe inside the celld worker bundle (workerd has\n * no Buffer global); atob/btoa are global in both workerd and Node >= 16.\n */\nexport function b64encode(bytes: Uint8Array): string {\n let bin = '';\n const CHUNK = 0x8000;\n for (let i = 0; i < bytes.length; i += CHUNK) {\n bin += String.fromCharCode(...bytes.subarray(i, i + CHUNK));\n }\n return btoa(bin);\n}\n\nexport function b64decode(text: string): Uint8Array {\n const bin = atob(text);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) {\n out[i] = bin.charCodeAt(i);\n }\n return out;\n}\n\n/**\n * JSON replacer that encodes Uint8Array as a tagged object with base64 data.\n */\nexport function uint8ArrayReplacer(_key: string, value: unknown): unknown {\n if (value instanceof Uint8Array) {\n return {\n __type: 'Uint8Array',\n data: b64encode(value),\n };\n }\n return value;\n}\n\n/**\n * JSON reviver that decodes tagged Uint8Array objects and ISO date strings.\n * Supports both:\n * - New format: { __type: 'Uint8Array', data: '<base64>' }\n * - Legacy format: { __uint8array: true, data: [1, 2, 3] }\n */\nexport function uint8ArrayReviver(key: string, value: unknown): unknown {\n if (value && typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n // New format: base64-encoded\n if (obj.__type === 'Uint8Array' && typeof obj.data === 'string') {\n return b64decode(obj.data);\n }\n // Legacy format: number array (backwards compat with NATS JetStream data)\n if (obj.__uint8array === true && Array.isArray(obj.data)) {\n return new Uint8Array(obj.data as number[]);\n }\n }\n return dateReviver(key, value);\n}\n\n/** Stringify with Uint8Array support. */\nexport function stringify(value: unknown): string {\n return JSON.stringify(value, uint8ArrayReplacer);\n}\n\n/** Parse with Uint8Array and Date support. */\nexport function parse<T>(text: string): T {\n return JSON.parse(text, uint8ArrayReviver) as T;\n}\n\n/** Deep clone using structuredClone */\nexport function deepClone<T>(value: T): T {\n return structuredClone(value);\n}\n","/**\n * RPC wire codec for the Node client <-> worker router HTTP boundary.\n *\n * Extends the shared tagged-JSON format (`{__type:'Uint8Array', data}` +\n * DATE_FIELDS revival) with explicitly tagged Dates: on Cloudflare the DO RPC\n * boundary is structured clone, which preserves EVERY Date — including ones\n * outside the well-known DATE_FIELDS (e.g. inside applyEvent outcomes and\n * user payloads). The HTTP hop must preserve them too, so Dates travel as\n * `{__type:'Date', iso}`.\n *\n * Runs on both sides of the wire, including inside the celld worker — so no\n * Node built-ins (Buffer): base64 goes through atob/btoa.\n */\nimport { b64decode, b64encode, dateReviver } from './vendor/shared/serialization.js';\n\nfunction rpcReplacer(this: unknown, key: string, value: unknown): unknown {\n // JSON.stringify invokes Date.toJSON before the replacer sees the value;\n // recover the original from the holder object.\n const original =\n this && typeof this === 'object' ? (this as Record<string, unknown>)[key] : undefined;\n if (original instanceof Date) {\n return { __type: 'Date', iso: original.toISOString() };\n }\n if (value instanceof Uint8Array) {\n return { __type: 'Uint8Array', data: b64encode(value) };\n }\n return value;\n}\n\nfunction rpcReviver(key: string, value: unknown): unknown {\n if (value && typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n if (obj.__type === 'Date' && typeof obj.iso === 'string') {\n return new Date(obj.iso);\n }\n if (obj.__type === 'Uint8Array' && typeof obj.data === 'string') {\n return b64decode(obj.data);\n }\n }\n // Fallback shared-codec semantics for untagged ISO strings in DATE_FIELDS.\n return dateReviver(key, value);\n}\n\nexport function rpcStringify(value: unknown): string {\n return JSON.stringify(value, rpcReplacer);\n}\n\nexport function rpcParse<T>(text: string): T {\n return JSON.parse(text, rpcReviver) as T;\n}\n","/**\n * Bearer-token auth for the worker router.\n *\n * Fails closed: when the WORLD_SECRET var is not configured, every protected\n * route returns 503 instead of forwarding unauthenticated traffic (the\n * eve-ambient celld-worker pattern).\n */\n\n/**\n * Constant-time string comparison via SHA-256 digests (digest-then-compare\n * is length-independent). crypto.subtle is global in both workerd and Node.\n */\nasync function timingSafeEqual(a: string, b: string): Promise<boolean> {\n const enc = new TextEncoder();\n const [da, db] = await Promise.all([\n crypto.subtle.digest('SHA-256', enc.encode(a)),\n crypto.subtle.digest('SHA-256', enc.encode(b)),\n ]);\n const va = new Uint8Array(da);\n const vb = new Uint8Array(db);\n let diff = 0;\n for (let i = 0; i < va.length; i++) {\n diff |= va[i] ^ vb[i];\n }\n return diff === 0;\n}\n\nexport type AuthResult = { ok: true } | { ok: false; response: Response };\n\nexport async function authenticate(\n request: Request,\n secret: string | undefined,\n): Promise<AuthResult> {\n if (!secret) {\n return {\n ok: false,\n response: Response.json(\n { error: { name: 'WorldNotConfigured', message: 'WORLD_SECRET is not configured' } },\n { status: 503 },\n ),\n };\n }\n\n const header = request.headers.get('authorization') ?? '';\n const token = header.startsWith('Bearer ') ? header.slice('Bearer '.length) : '';\n if (!token || !(await timingSafeEqual(token, secret))) {\n return {\n ok: false,\n response: Response.json(\n { error: { name: 'Unauthorized', message: 'invalid or missing bearer token' } },\n { status: 401 },\n ),\n };\n }\n\n return { ok: true };\n}\n","/**\n * Worker-level HTTP router: the fleet-facing RPC surface of the celld world.\n *\n * Routes:\n * GET /v1/health — liveness + spec version (unauthenticated)\n * POST /v1/rpc/{binding}/{name}/{method} — DO RPC (bearer auth)\n *\n * The RPC body is an rpc-codec-encoded JSON array of arguments; the response\n * body is the rpc-codec-encoded return value. Only whitelisted methods\n * dispatch — everything else (including fetch/alarm) is unreachable.\n */\nimport { SPEC_VERSION_CURRENT } from '@workflow/world';\nimport { rpcParse, rpcStringify } from '../codec.js';\nimport { authenticate } from './auth.js';\n\nexport const WORLD_NAME = 'world-celld';\nexport const WORLD_VERSION = '0.1.0';\n\n/** Minimal structural DO namespace type (celld provides the real thing). */\nexport interface DONamespaceLike {\n idFromName(name: string): { toString(): string };\n get(id: { toString(): string }): unknown;\n}\n\nexport interface WorkerEnv {\n WORKFLOW_DB: DONamespaceLike;\n WORKFLOW_STREAMS: DONamespaceLike;\n WORKFLOW_INDEX: DONamespaceLike;\n WORKFLOW_QUEUE: DONamespaceLike;\n WORLD_SECRET?: string;\n}\n\nconst BINDINGS: Record<string, { env: keyof WorkerEnv; methods: ReadonlySet<string> }> = {\n runs: {\n env: 'WORKFLOW_DB',\n methods: new Set([\n 'applyEvent',\n 'getRun',\n 'getStep',\n 'getEvent',\n 'listEvents',\n 'listSteps',\n 'listHooks',\n 'getCleanupStatus',\n 'scheduleCleanup',\n 'cleanupNow',\n 'rearmCleanup',\n ]),\n },\n streams: {\n env: 'WORKFLOW_STREAMS',\n methods: new Set([\n 'writeChunk',\n 'closeStream',\n 'getChunks',\n 'getInfo',\n 'registerStream',\n 'listStreams',\n 'expireRegistry',\n 'finalizeRegistry',\n 'expireStream',\n ]),\n },\n index: {\n env: 'WORKFLOW_INDEX',\n methods: new Set([\n 'get',\n 'put',\n 'delete',\n 'putOwned',\n 'expireRun',\n 'list',\n 'reserveHookToken',\n 'finalizeHookIndexes',\n 'releaseHookToken',\n 'deleteHookIndexes',\n ]),\n },\n queue: {\n env: 'WORKFLOW_QUEUE',\n methods: new Set([\n 'enqueue',\n 'stats',\n 'listDeadLetters',\n 'redriveDeadLetter',\n 'purgeDeadLetters',\n 'rearmAlarm',\n 'expireRun',\n ]),\n },\n};\n\n/** Request body cap: oversize payloads get a clear 413 instead of an OOM. */\nconst MAX_BODY_BYTES = 32 * 1024 * 1024;\n\nfunction errorResponse(status: number, name: string, message: string): Response {\n return Response.json({ error: { name, message } }, { status });\n}\n\nasync function readBoundedBody(request: Request): Promise<string | null> {\n if (!request.body) return '';\n const reader = request.body.getReader();\n const decoder = new TextDecoder();\n let total = 0;\n let text = '';\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > MAX_BODY_BYTES) {\n await reader.cancel('RPC body exceeds configured limit').catch(() => undefined);\n return null;\n }\n text += decoder.decode(value, { stream: true });\n }\n return text + decoder.decode();\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function createRouter(env: WorkerEnv) {\n return async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const parts = url.pathname.split('/').filter(Boolean);\n\n if (parts[0] !== 'v1') {\n return errorResponse(404, 'NotFound', `unknown path: ${url.pathname}`);\n }\n\n if (parts[1] === 'health' && parts.length === 2) {\n return Response.json({\n ok: true,\n name: WORLD_NAME,\n version: WORLD_VERSION,\n specVersion: SPEC_VERSION_CURRENT,\n });\n }\n\n if (parts[1] !== 'rpc') {\n return errorResponse(404, 'NotFound', `unknown path: ${url.pathname}`);\n }\n\n const auth = await authenticate(request, env.WORLD_SECRET);\n if (!auth.ok) {\n return auth.response;\n }\n\n if (request.method !== 'POST' || parts.length !== 5) {\n return errorResponse(404, 'NotFound', 'expected POST /v1/rpc/{binding}/{name}/{method}');\n }\n\n const [, , bindingKey, encodedName, method] = parts;\n const binding = BINDINGS[bindingKey];\n if (!binding) {\n return errorResponse(404, 'NotFound', `unknown binding: ${bindingKey}`);\n }\n if (!binding.methods.has(method)) {\n return errorResponse(404, 'NotFound', `unknown method: ${bindingKey}.${method}`);\n }\n\n const contentLength = Number(request.headers.get('content-length') ?? '0');\n if (contentLength > MAX_BODY_BYTES) {\n return errorResponse(413, 'PayloadTooLarge', `body exceeds ${MAX_BODY_BYTES} bytes`);\n }\n\n let args: unknown[];\n try {\n const text = await readBoundedBody(request);\n if (text === null) {\n return errorResponse(413, 'PayloadTooLarge', `body exceeds ${MAX_BODY_BYTES} bytes`);\n }\n const parsed = rpcParse<unknown>(text);\n if (!Array.isArray(parsed)) {\n return errorResponse(400, 'BadRequest', 'body must be an argument array');\n }\n args = parsed;\n } catch {\n return errorResponse(400, 'BadRequest', 'malformed rpc body');\n }\n\n const name = decodeURIComponent(encodedName);\n const namespace = env[binding.env] as DONamespaceLike | undefined;\n if (!namespace) {\n return errorResponse(500, 'WorldMisconfigured', `missing binding: ${binding.env}`);\n }\n\n try {\n const stub = namespace.get(namespace.idFromName(name)) as Record<\n string,\n (...a: unknown[]) => Promise<unknown>\n >;\n const result = await stub[method](...args);\n return new Response(rpcStringify(result ?? null), {\n status: 200,\n headers: { 'content-type': 'application/json' },\n });\n } catch (error) {\n // Guard failures travel as structured outcomes, so a thrown error here\n // is exceptional (e.g. writing to a closed stream). Serialize by name\n // for client-side reconstruction.\n const err = error as { name?: string; message?: string; status?: number };\n return Response.json(\n {\n error: {\n name: err?.name ?? 'Error',\n message: err?.message ?? String(error),\n status: typeof err?.status === 'number' ? err.status : undefined,\n },\n },\n { status: 500 },\n );\n }\n };\n}\n","export class Mutex {\n promise: Promise<unknown> = Promise.resolve();\n andThen<T>(fn: () => Promise<T> | T): Promise<T> {\n this.promise = this.promise.then(\n () => fn(),\n () => fn(),\n );\n return this.promise as Promise<T>;\n }\n}\n\nexport function compact<T extends object>(obj: T) {\n const value = {} as {\n [key in keyof T]: null extends T[key] ? undefined | NonNullable<T[key]> : T[key];\n };\n for (const key in obj) {\n if (obj[key] !== null) {\n value[key] = obj[key] as any;\n } else {\n value[key] = undefined as any;\n }\n }\n return value;\n}\n\n/**\n * Reference counting helper for managing resource lifecycle\n */\nexport class Rc {\n private count = 0;\n private disposeFn?: () => void | Promise<void>;\n\n constructor(disposeFn?: () => void | Promise<void>) {\n this.disposeFn = disposeFn;\n }\n\n inc(): void {\n this.count++;\n }\n\n async dec(): Promise<void> {\n this.count--;\n if (this.count === 0 && this.disposeFn) {\n await this.disposeFn();\n }\n }\n\n getCount(): number {\n return this.count;\n }\n}\n","import type { Hook } from '@workflow/world';\nimport type { HookTokenOwner } from '../../config.js';\nimport { parse } from '../../vendor/shared/index.js';\nimport { DurableObject } from '../do-base.js';\nimport type { ExpireRunIndexesRequest, ExpireRunIndexesResult } from '../../retention.js';\n\ninterface HookClaim {\n owner: HookTokenOwner;\n reservedAt: number;\n}\n\nfunction sameOwner(left: HookTokenOwner, right: HookTokenOwner): boolean {\n return left.runId === right.runId && left.hookId === right.hookId;\n}\n\nfunction ownerFromHook(raw: string): HookTokenOwner {\n const hook = parse<Hook>(raw);\n return { runId: hook.runId, hookId: hook.hookId };\n}\n\n/**\n * Global index cell, replacing the Workers KV namespace world-cloudflare\n * uses for run listing and hook token/id lookup.\n *\n * A single cell (named `index`) serializes every read and write. Hook-token\n * reservation, publication, and release use storage transactions so\n * concurrent runs cannot both acquire the same token.\n *\n * The RPC surface matches the storage-layer KVNamespace interface bit-for-bit\n * (including MockKVNamespace's pagination contract: cursor = last returned\n * key, `list_complete` reflects whether further keys exist), so the vendored\n * storage.ts works against it unchanged.\n */\nexport class IndexDO extends DurableObject {\n async get(key: string): Promise<string | null> {\n const value = await this.ctx.storage.get<string>(key);\n return value ?? null;\n }\n\n async put(key: string, value: string): Promise<void> {\n await this.ctx.storage.put(key, value);\n }\n\n /** Publish a derived index only while its owning run is not expired. */\n async putOwned(runId: string, key: string, value: string): Promise<{ stored: boolean }> {\n return await this.ctx.storage.transaction(async (txn) => {\n if ((await txn.get(`expired:${runId}`)) !== undefined) {\n return { stored: false };\n }\n await txn.put(key, value);\n return { stored: true };\n });\n }\n\n async delete(key: string): Promise<void> {\n await this.ctx.storage.delete(key);\n }\n\n async list(options?: {\n prefix?: string;\n cursor?: string;\n limit?: number;\n reverse?: boolean;\n }): Promise<{\n keys: Array<{ name: string }>;\n list_complete: boolean;\n cursor?: string;\n }> {\n const prefix = options?.prefix ?? '';\n const limit = options?.limit ?? 1000;\n\n // Fetch one extra key to learn whether the listing is complete without\n // advancing past the page (the \"exact limit + list_complete\" contract\n // storage.ts relies on).\n const entries = await this.ctx.storage.list({\n prefix,\n ...(options?.reverse\n ? { reverse: true, end: options.cursor }\n : { startAfter: options?.cursor }),\n limit: limit + 1,\n });\n\n const names = Array.from(entries.keys());\n const page = names.slice(0, limit);\n const listComplete = names.length <= limit;\n\n return {\n keys: page.map((name) => ({ name })),\n list_complete: listComplete,\n cursor: listComplete ? undefined : page.at(-1),\n };\n }\n\n async reserveHookToken(\n token: string,\n owner: HookTokenOwner,\n ): Promise<{ claimed: boolean; holder?: HookTokenOwner }> {\n return this.ctx.storage.transaction(async (txn) => {\n const indexedHook = await txn.get<string>(`hook:${token}`);\n if (indexedHook !== undefined) {\n const holder = ownerFromHook(indexedHook);\n return { claimed: false, holder };\n }\n\n const claimKey = `hookclaim:${token}`;\n const claim = await txn.get<HookClaim>(claimKey);\n if (claim !== undefined && !sameOwner(claim.owner, owner)) {\n return { claimed: false, holder: claim.owner };\n }\n\n await txn.put(claimKey, { owner, reservedAt: Date.now() });\n return { claimed: true };\n });\n }\n\n async finalizeHookIndexes(\n token: string,\n hookId: string,\n serializedHook: string,\n owner: HookTokenOwner,\n ): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n if ((await txn.get(`expired:${owner.runId}`)) !== undefined) {\n const claim = await txn.get<HookClaim>(`hookclaim:${token}`);\n if (claim !== undefined && sameOwner(claim.owner, owner)) {\n await txn.delete(`hookclaim:${token}`);\n }\n return;\n }\n const indexedHook = await txn.get<string>(`hook:${token}`);\n if (indexedHook !== undefined && !sameOwner(ownerFromHook(indexedHook), owner)) {\n throw new Error(`Hook token ${token} is owned by another hook`);\n }\n const claim = await txn.get<HookClaim>(`hookclaim:${token}`);\n if (claim !== undefined && !sameOwner(claim.owner, owner)) {\n throw new Error(`Hook token ${token} is reserved by another hook`);\n }\n\n await txn.put(`hook:${token}`, serializedHook);\n await txn.put(`hookid:${hookId}`, serializedHook);\n if (claim !== undefined) {\n await txn.delete(`hookclaim:${token}`);\n }\n });\n }\n\n async releaseHookToken(token: string, owner: HookTokenOwner): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n const key = `hookclaim:${token}`;\n const claim = await txn.get<HookClaim>(key);\n if (claim !== undefined && sameOwner(claim.owner, owner)) {\n await txn.delete(key);\n }\n });\n }\n\n async deleteHookIndexes(token: string, hookId: string, owner: HookTokenOwner): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n const tokenKey = `hook:${token}`;\n const idKey = `hookid:${hookId}`;\n const claimKey = `hookclaim:${token}`;\n const [byToken, byId, claim] = await Promise.all([\n txn.get<string>(tokenKey),\n txn.get<string>(idKey),\n txn.get<HookClaim>(claimKey),\n ]);\n if (byToken !== undefined && sameOwner(ownerFromHook(byToken), owner)) {\n await txn.delete(tokenKey);\n }\n if (byId !== undefined && sameOwner(ownerFromHook(byId), owner)) {\n await txn.delete(idKey);\n }\n if (claim !== undefined && sameOwner(claim.owner, owner)) {\n await txn.delete(claimKey);\n }\n });\n }\n\n /**\n * Fence a run and remove all of its known derived indexes atomically.\n * Once the fence exists, putOwned() and hook finalization cannot resurrect\n * entries from a delayed request.\n */\n async expireRun(request: ExpireRunIndexesRequest): Promise<ExpireRunIndexesResult> {\n return await this.ctx.storage.transaction(async (txn) => {\n await txn.put(`expired:${request.runId}`, request.expiredAt);\n let deleted = 0;\n\n for (const key of new Set(request.keys)) {\n if (await txn.delete(key)) deleted++;\n }\n\n for (const hook of request.hooks) {\n const owner = { runId: request.runId, hookId: hook.hookId };\n const tokenKey = `hook:${hook.token}`;\n const idKey = `hookid:${hook.hookId}`;\n const claimKey = `hookclaim:${hook.token}`;\n const [byToken, byId, claim] = await Promise.all([\n txn.get<string>(tokenKey),\n txn.get<string>(idKey),\n txn.get<HookClaim>(claimKey),\n ]);\n if (byToken !== undefined && sameOwner(ownerFromHook(byToken), owner)) {\n if (await txn.delete(tokenKey)) deleted++;\n }\n if (byId !== undefined && sameOwner(ownerFromHook(byId), owner)) {\n if (await txn.delete(idKey)) deleted++;\n }\n if (claim !== undefined && sameOwner(claim.owner, owner)) {\n if (await txn.delete(claimKey)) deleted++;\n }\n }\n\n return { deleted };\n });\n }\n}\n","import { DurableObject } from '../do-base.js';\nimport type { EnqueueOutcome, EnqueueRequest } from '../../queue.js';\nimport type { ExpireQueueRunResult } from '../../retention.js';\n\n/**\n * Queue cell: the celld replacement for Cloudflare Queues.\n *\n * One cell (`q:<shard>`) owns the full lifecycle of its messages: durable\n * scheduling via the cell alarm, delivery via outbound fetch (the same x-vqs\n * dialect as the in-process test pump), retries with capped exponential\n * backoff, idempotencyKey dedup, and a dead-letter table.\n *\n * Storage layout (KV-style, ordered scans via zero-padded epoch-ms keys):\n * cfg pinned QueueCellConfig (first-enqueue wins)\n * msg:<messageId> MessageRow\n * due:<paddedMs>:<messageId> schedule index -> messageId\n * inflight:<messageId> crash-recovery deadline (epoch ms)\n * key:<idempotencyKey> active dedup claim -> messageId\n * dlq:<paddedMs>:<messageId> DeadLetterRow\n * run:<runId>:<messageId> QueueRunReference for retention cleanup\n * expired-run:<runId> run fence preventing delayed enqueue\n *\n * celld gotchas designed around:\n * - celld#144 (alarm handlers can overlap): the storage-only claim phase runs\n * inside blockConcurrencyWhile; slow delivery I/O runs outside the gate via\n * waitUntil.\n * - six-failure alarm abandonment: the alarm handler never throws for data\n * conditions — backoff reschedules the alarm instead. rearmAlarm() is the\n * recovery hatch, and every enqueue also re-arms.\n * - deploys restart the fleet: in-flight deliveries die with the isolate; the\n * inflight-deadline sweep on the next alarm redelivers (at-least-once).\n */\n\nexport interface MessageRow {\n messageId: string;\n queueName: string;\n pathname: 'flow' | 'step';\n /** Pre-encoded tagged-JSON payload — forwarded byte-identical. */\n body: string;\n runId?: string;\n /**\n * Delivery target captured at enqueue time. Carried per message (not\n * pinned on the cell) so an app redeploy at a new URL never bricks the\n * queue: old messages deliver (or dead-letter) against their original\n * target, new messages against the new one.\n */\n targetBaseUrl: string;\n idempotencyKey?: string;\n /** Completed delivery attempts. */\n attempt: number;\n enqueuedAt: number;\n lastError?: string;\n}\n\nexport interface DeadLetterRow extends MessageRow {\n failedAt: number;\n}\n\nexport interface QueueStats {\n pending: number;\n inflight: number;\n deadLetters: number;\n alarmAt: number | null;\n}\n\ninterface QueueRunReference {\n messageId: string;\n dueKey?: string;\n dlqKey?: string;\n idempotencyKey?: string;\n}\n\ninterface ExpiredRunFence {\n expiredAt: number;\n deleted: number;\n}\n\nconst PERMANENT_STATUSES = new Set([404, 409, 410, 422]);\n\nconst DEFAULT_MAX_ATTEMPTS = 5;\nconst DEFAULT_MAX_INFLIGHT = 5;\nconst DEFAULT_DELIVERY_TIMEOUT_MS = 300_000;\n/** Grace period past the delivery timeout before a claim counts as lost. */\nconst INFLIGHT_GRACE_MS = 30_000;\n/** Move overdue alarms to a new timestamp so celld observes a fresh edge. */\nconst MIN_ALARM_DELAY_MS = 1;\n\ntype AlarmStorage = Pick<DurableObjectStorage, 'list' | 'getAlarm' | 'setAlarm' | 'deleteAlarm'>;\n\nfunction pad(ms: number): string {\n return String(Math.max(0, Math.floor(ms))).padStart(13, '0');\n}\n\nfunction dueKey(atMs: number, messageId: string): string {\n return `due:${pad(atMs)}:${messageId}`;\n}\n\nfunction runReferenceKey(runId: string, messageId: string): string {\n return `run:${runId}:${messageId}`;\n}\n\nfunction expiredRunKey(runId: string): string {\n return `expired-run:${runId}`;\n}\n\nfunction backoffSeconds(attempt: number): number {\n return Math.min(60, 2 ** attempt);\n}\n\ninterface QueueCellEnv {\n QUEUE_MAX_ATTEMPTS?: string;\n QUEUE_MAX_INFLIGHT?: string;\n QUEUE_DELIVERY_TIMEOUT_MS?: string;\n WORKFLOW_CALLBACK_SECRET?: string;\n /** Test seams (never set by a real deploy — celld vars are strings). */\n clock?: () => number;\n fetch?: typeof fetch;\n}\n\nexport class QueueDO extends DurableObject {\n #now(): number {\n const clock = (this.env as QueueCellEnv)?.clock;\n return typeof clock === 'function' ? clock() : Date.now();\n }\n\n #fetch(): typeof fetch {\n const impl = (this.env as QueueCellEnv)?.fetch;\n return typeof impl === 'function' ? impl : fetch;\n }\n\n #intVar(\n name: 'QUEUE_MAX_ATTEMPTS' | 'QUEUE_MAX_INFLIGHT' | 'QUEUE_DELIVERY_TIMEOUT_MS',\n fallback: number,\n ): number {\n const raw = (this.env as QueueCellEnv)?.[name];\n const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n }\n\n async enqueue(request: EnqueueRequest): Promise<EnqueueOutcome> {\n const storage = this.ctx.storage;\n const now = this.#now();\n\n const outcome = await storage.transaction<EnqueueOutcome>(async (txn) => {\n if (request.runId && (await txn.get(expiredRunKey(request.runId))) !== undefined) {\n return {\n ok: false,\n code: 'RUN_EXPIRED',\n message: `Workflow run \"${request.runId}\" has expired`,\n };\n }\n // Pin the shard count from the first enqueue and reject drift loudly:\n // idempotencyKey -> cell affinity (and therefore dedup correctness)\n // depends on every producer agreeing on the shard count. The delivery\n // URL deliberately is NOT pinned — it travels per message.\n const pinned = await txn.get<{ queueShards: number; pinnedAt: number }>('cfg');\n if (!pinned) {\n await txn.put('cfg', { queueShards: request.config.queueShards, pinnedAt: now });\n } else if (pinned.queueShards !== request.config.queueShards) {\n return {\n ok: false,\n code: 'CONFIG_MISMATCH',\n message:\n `queue cell shard-count mismatch: pinned ${pinned.queueShards}, ` +\n `got ${request.config.queueShards} — changing queueShards requires draining the fleet`,\n };\n }\n\n // Dedup: while a message with this idempotencyKey is active, return the\n // original messageId (core re-enqueues pending steps on every replay and\n // relies on this).\n if (request.idempotencyKey) {\n const existing = await txn.get<string>(`key:${request.idempotencyKey}`);\n if (existing) {\n if (await txn.get(`msg:${existing}`)) {\n await this.#scheduleNextAlarm(txn, now);\n return { ok: true, messageId: existing, deduped: true };\n }\n // Stale claim (message gone without release) — steal it.\n await txn.delete(`key:${request.idempotencyKey}`);\n }\n await txn.put(`key:${request.idempotencyKey}`, request.messageId);\n }\n\n const row: MessageRow = {\n messageId: request.messageId,\n queueName: request.queueName,\n pathname: request.pathname,\n body: request.body,\n runId: request.runId,\n targetBaseUrl: request.config.targetBaseUrl,\n idempotencyKey: request.idempotencyKey,\n attempt: 0,\n enqueuedAt: now,\n };\n const dueAt = now + Math.max(0, request.delaySeconds ?? 0) * 1000;\n const scheduleKey = dueKey(dueAt, row.messageId);\n await txn.put(`msg:${row.messageId}`, row);\n await txn.put(scheduleKey, row.messageId);\n if (row.runId) {\n await txn.put<QueueRunReference>(runReferenceKey(row.runId, row.messageId), {\n messageId: row.messageId,\n dueKey: scheduleKey,\n idempotencyKey: row.idempotencyKey,\n });\n }\n await this.#armAlarmAtMost(txn, dueAt, now);\n\n return { ok: true, messageId: row.messageId, deduped: false };\n });\n\n return outcome;\n }\n\n async alarm(): Promise<void> {\n // celld#144: alarm handlers can overlap while awaiting. The storage-only\n // claim phase runs under the input gate; a failure is carried out and\n // rethrown outside so a failed critical section cannot reset the cell.\n let claimed: MessageRow[] = [];\n let failure: unknown = null;\n const attempt = async () => {\n try {\n claimed = await this.#claimPhase();\n } catch (error) {\n failure = error;\n }\n };\n if (typeof this.ctx.blockConcurrencyWhile === 'function') {\n await this.ctx.blockConcurrencyWhile(attempt);\n } else {\n await attempt();\n }\n if (failure !== null) throw failure;\n\n for (const row of claimed) {\n this.ctx.waitUntil(this.#deliver(row));\n }\n }\n\n /**\n * Storage-only: recover lost inflight claims, claim due messages up to the\n * inflight cap, and re-arm the alarm. Never throws for data conditions.\n */\n async #claimPhase(): Promise<MessageRow[]> {\n const storage = this.ctx.storage;\n const now = this.#now();\n const maxInflight = this.#intVar('QUEUE_MAX_INFLIGHT', DEFAULT_MAX_INFLIGHT);\n const claimed = await storage.transaction<MessageRow[]>(async (txn) => {\n // 1. Recover: an inflight entry past its deadline is a lost delivery\n // (node crash, deploy restart) — back to due for redelivery.\n const inflight = await txn.list<number>({ prefix: 'inflight:' });\n let inflightCount = 0;\n for (const [key, deadline] of inflight) {\n if (deadline <= now) {\n const messageId = key.slice('inflight:'.length);\n await txn.delete(key);\n const row = await txn.get<MessageRow>(`msg:${messageId}`);\n if (row) {\n const scheduleKey = dueKey(now, messageId);\n await txn.put(scheduleKey, messageId);\n if (row.runId) {\n await txn.put<QueueRunReference>(runReferenceKey(row.runId, row.messageId), {\n messageId: row.messageId,\n dueKey: scheduleKey,\n idempotencyKey: row.idempotencyKey,\n });\n }\n }\n } else {\n inflightCount++;\n }\n }\n\n // 2. Claim due messages up to the cap.\n const rows: MessageRow[] = [];\n if (inflightCount < maxInflight) {\n const due = await txn.list<string>({\n prefix: 'due:',\n end: `due:${pad(now + 1)}`,\n limit: maxInflight - inflightCount,\n });\n const timeoutMs = this.#intVar('QUEUE_DELIVERY_TIMEOUT_MS', DEFAULT_DELIVERY_TIMEOUT_MS);\n for (const [key, messageId] of due) {\n await txn.delete(key);\n const row = await txn.get<MessageRow>(`msg:${messageId}`);\n if (!row) continue; // orphaned schedule entry\n await txn.put(`inflight:${messageId}`, now + timeoutMs + INFLIGHT_GRACE_MS);\n rows.push(row);\n }\n }\n await this.#scheduleNextAlarm(txn, now);\n return rows;\n });\n\n return claimed;\n }\n\n async #deliver(row: MessageRow): Promise<void> {\n const storage = this.ctx.storage;\n const timeoutMs = this.#intVar('QUEUE_DELIVERY_TIMEOUT_MS', DEFAULT_DELIVERY_TIMEOUT_MS);\n const callbackSecret = (this.env as QueueCellEnv)?.WORKFLOW_CALLBACK_SECRET;\n const url = `${row.targetBaseUrl.replace(/\\/$/, '')}/.well-known/workflow/v1/${row.pathname}`;\n\n let response: Response | null = null;\n let transportError: unknown = null;\n try {\n response = await this.#fetch()(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-vqs-queue-name': row.queueName,\n 'x-vqs-message-id': row.messageId,\n 'x-vqs-message-attempt': String(row.attempt + 1),\n ...(callbackSecret ? { 'x-workflow-callback-secret': callbackSecret } : {}),\n },\n body: row.body,\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (error) {\n transportError = error;\n }\n\n const now = this.#now();\n\n if (response?.ok) {\n // Ack: the message is done; release the dedup claim.\n await this.#ack(row);\n } else if (response && response.status === 503) {\n // {timeoutSeconds} means \"redeliver later, same message\": the attempt\n // count does not advance and the dedup key stays claimed.\n let timeoutSeconds: number | undefined;\n try {\n const parsed = (await response.json()) as { timeoutSeconds?: number };\n timeoutSeconds = parsed?.timeoutSeconds;\n } catch {\n timeoutSeconds = undefined;\n }\n if (typeof timeoutSeconds === 'number') {\n await storage.transaction(async (txn) => {\n if (row.runId && (await txn.get(expiredRunKey(row.runId))) !== undefined) {\n await txn.delete(`msg:${row.messageId}`);\n await txn.delete(`inflight:${row.messageId}`);\n await txn.delete(runReferenceKey(row.runId, row.messageId));\n if (row.idempotencyKey) {\n const dedupKey = `key:${row.idempotencyKey}`;\n if ((await txn.get<string>(dedupKey)) === row.messageId) {\n await txn.delete(dedupKey);\n }\n }\n await this.#scheduleNextAlarm(txn, now);\n return;\n }\n await txn.delete(`inflight:${row.messageId}`);\n const scheduleKey = dueKey(now + timeoutSeconds * 1000, row.messageId);\n await txn.put(scheduleKey, row.messageId);\n if (row.runId) {\n await txn.put<QueueRunReference>(runReferenceKey(row.runId, row.messageId), {\n messageId: row.messageId,\n dueKey: scheduleKey,\n idempotencyKey: row.idempotencyKey,\n });\n }\n await this.#scheduleNextAlarm(txn, now);\n });\n } else {\n await this.#retry(row, 'HTTP 503');\n }\n } else if (response && PERMANENT_STATUSES.has(response.status)) {\n // Permanent: drop without burning retries; the handler already\n // classified this as unreplayable.\n await this.#ack(row);\n } else {\n const reason = response\n ? `HTTP ${response.status}`\n : `transport error: ${String(transportError)}`;\n await this.#retry(row, reason);\n }\n }\n\n async #ack(row: MessageRow): Promise<void> {\n const storage = this.ctx.storage;\n await storage.transaction(async (txn) => {\n await txn.delete(`msg:${row.messageId}`);\n await txn.delete(`inflight:${row.messageId}`);\n if (row.idempotencyKey) {\n const holder = await txn.get<string>(`key:${row.idempotencyKey}`);\n if (holder === row.messageId) {\n await txn.delete(`key:${row.idempotencyKey}`);\n }\n }\n if (row.runId) {\n await txn.delete(runReferenceKey(row.runId, row.messageId));\n }\n await this.#scheduleNextAlarm(txn, this.#now());\n });\n }\n\n async #retry(row: MessageRow, reason: string): Promise<void> {\n const storage = this.ctx.storage;\n const now = this.#now();\n const maxAttempts = this.#intVar('QUEUE_MAX_ATTEMPTS', DEFAULT_MAX_ATTEMPTS);\n const attempt = row.attempt + 1;\n\n await storage.transaction(async (txn) => {\n if (row.runId && (await txn.get(expiredRunKey(row.runId))) !== undefined) {\n await txn.delete(`msg:${row.messageId}`);\n await txn.delete(`inflight:${row.messageId}`);\n await txn.delete(runReferenceKey(row.runId, row.messageId));\n if (row.idempotencyKey) {\n const dedupKey = `key:${row.idempotencyKey}`;\n if ((await txn.get<string>(dedupKey)) === row.messageId) {\n await txn.delete(dedupKey);\n }\n }\n await this.#scheduleNextAlarm(txn, now);\n return;\n }\n await txn.delete(`inflight:${row.messageId}`);\n\n if (attempt >= maxAttempts) {\n const dead: DeadLetterRow = { ...row, attempt, lastError: reason, failedAt: now };\n const deadKey = `dlq:${pad(now)}:${row.messageId}`;\n await txn.put(deadKey, dead);\n await txn.delete(`msg:${row.messageId}`);\n if (row.idempotencyKey) {\n const holder = await txn.get<string>(`key:${row.idempotencyKey}`);\n if (holder === row.messageId) {\n await txn.delete(`key:${row.idempotencyKey}`);\n }\n }\n if (row.runId) {\n await txn.put<QueueRunReference>(runReferenceKey(row.runId, row.messageId), {\n messageId: row.messageId,\n dlqKey: deadKey,\n idempotencyKey: row.idempotencyKey,\n });\n }\n await this.#scheduleNextAlarm(txn, now);\n return;\n }\n\n const updated: MessageRow = { ...row, attempt, lastError: reason };\n const scheduleKey = dueKey(now + backoffSeconds(attempt) * 1000, row.messageId);\n await txn.put(`msg:${row.messageId}`, updated);\n await txn.put(scheduleKey, row.messageId);\n if (row.runId) {\n await txn.put<QueueRunReference>(runReferenceKey(row.runId, row.messageId), {\n messageId: row.messageId,\n dueKey: scheduleKey,\n idempotencyKey: row.idempotencyKey,\n });\n }\n await this.#scheduleNextAlarm(txn, now);\n });\n }\n\n /** Arm the alarm no later than `atMs` (durable backoff never throws). */\n async #armAlarmAtMost(storage: AlarmStorage, atMs: number, now: number): Promise<void> {\n const current = await storage.getAlarm();\n if (current !== null && current <= now) {\n await storage.setAlarm(now + MIN_ALARM_DELAY_MS);\n return;\n }\n\n const target = atMs <= now ? now + MIN_ALARM_DELAY_MS : atMs;\n if (current === null || target < current) {\n await storage.setAlarm(target);\n }\n }\n\n /** Recompute the alarm from the earliest due entry / inflight deadline. */\n async #rearm(): Promise<void> {\n await this.#scheduleNextAlarm(this.ctx.storage, this.#now());\n }\n\n /** Keep the alarm index consistent with message state in the same transaction. */\n async #scheduleNextAlarm(storage: AlarmStorage, now: number): Promise<void> {\n let next: number | null = null;\n\n const due = await storage.list<string>({ prefix: 'due:', limit: 1 });\n for (const key of due.keys()) {\n next = Number.parseInt(key.slice('due:'.length, 'due:'.length + 13), 10);\n }\n\n const inflight = await storage.list<number>({ prefix: 'inflight:' });\n for (const deadline of inflight.values()) {\n if (next === null || deadline < next) next = deadline;\n }\n\n if (next !== null) {\n await storage.setAlarm(next <= now ? now + MIN_ALARM_DELAY_MS : next);\n } else {\n await storage.deleteAlarm();\n }\n }\n\n // ---- Admin RPC (exposed through the router's queue binding) ----\n\n async stats(): Promise<QueueStats> {\n const storage = this.ctx.storage;\n const [due, inflight, dlq, alarmAt] = await Promise.all([\n storage.list({ prefix: 'due:' }),\n storage.list({ prefix: 'inflight:' }),\n storage.list({ prefix: 'dlq:' }),\n storage.getAlarm(),\n ]);\n return {\n pending: due.size,\n inflight: inflight.size,\n deadLetters: dlq.size,\n alarmAt,\n };\n }\n\n async listDeadLetters(params?: {\n limit?: number;\n cursor?: string;\n }): Promise<{ data: DeadLetterRow[]; cursor: string | null; hasMore: boolean }> {\n const limit = params?.limit ?? 100;\n const entries = await this.ctx.storage.list<DeadLetterRow>({\n prefix: 'dlq:',\n startAfter: params?.cursor,\n limit: limit + 1,\n });\n const keys = Array.from(entries.keys());\n const page = keys.slice(0, limit);\n const hasMore = keys.length > limit;\n return {\n data: page.map((k) => entries.get(k) as DeadLetterRow),\n cursor: hasMore ? page.at(-1)! : null,\n hasMore,\n };\n }\n\n /** Move a dead letter back to the live queue (attempt count reset). */\n async redriveDeadLetter(messageId: string): Promise<{ ok: boolean }> {\n const storage = this.ctx.storage;\n const now = this.#now();\n const outcome = await storage.transaction<{ ok: boolean }>(async (txn) => {\n const dlq = await txn.list<DeadLetterRow>({ prefix: 'dlq:' });\n for (const [key, dead] of dlq) {\n if (dead.messageId !== messageId) continue;\n const { failedAt: _failedAt, ...rest } = dead;\n const row: MessageRow = { ...rest, attempt: 0, lastError: undefined };\n\n if (row.idempotencyKey) {\n const dedupKey = `key:${row.idempotencyKey}`;\n const holder = await txn.get<string>(dedupKey);\n if (holder && holder !== row.messageId && (await txn.get(`msg:${holder}`))) {\n return { ok: false };\n }\n if (holder && holder !== row.messageId) {\n await txn.delete(dedupKey);\n }\n await txn.put(dedupKey, row.messageId);\n }\n\n await txn.put(`msg:${row.messageId}`, row);\n const scheduleKey = dueKey(now, row.messageId);\n await txn.put(scheduleKey, row.messageId);\n await txn.delete(key);\n if (row.runId) {\n await txn.put<QueueRunReference>(runReferenceKey(row.runId, row.messageId), {\n messageId: row.messageId,\n dueKey: scheduleKey,\n idempotencyKey: row.idempotencyKey,\n });\n }\n await this.#armAlarmAtMost(txn, now, now);\n return { ok: true };\n }\n return { ok: false };\n });\n\n return outcome;\n }\n\n async purgeDeadLetters(): Promise<{ purged: number }> {\n const storage = this.ctx.storage;\n return await storage.transaction(async (txn) => {\n const dlq = await txn.list({ prefix: 'dlq:' });\n for (const [key, value] of dlq) {\n await txn.delete(key);\n const dead = value as DeadLetterRow;\n if (dead.runId) {\n await txn.delete(runReferenceKey(dead.runId, dead.messageId));\n }\n }\n return { purged: dlq.size };\n });\n }\n\n /**\n * Recovery hatch for celld's six-failure alarm abandonment: derive the due\n * time again and arm it.\n */\n async rearmAlarm(): Promise<{ alarmAt: number | null }> {\n await this.#rearm();\n return { alarmAt: await this.ctx.storage.getAlarm() };\n }\n\n /** Fence a run and purge every live, inflight, and dead-letter message it owns. */\n async expireRun(runId: string, expiredAt: number): Promise<ExpireQueueRunResult> {\n const storage = this.ctx.storage;\n const deleted = await storage.transaction(async (txn) => {\n const existing = await txn.get<ExpiredRunFence>(expiredRunKey(runId));\n const references = await txn.list<QueueRunReference>({ prefix: `run:${runId}:` });\n let count = existing?.deleted ?? 0;\n for (const [key, reference] of references) {\n await txn.delete(`msg:${reference.messageId}`);\n await txn.delete(`inflight:${reference.messageId}`);\n if (reference.dueKey) await txn.delete(reference.dueKey);\n if (reference.dlqKey) await txn.delete(reference.dlqKey);\n if (reference.idempotencyKey) {\n const dedupKey = `key:${reference.idempotencyKey}`;\n if ((await txn.get<string>(dedupKey)) === reference.messageId) {\n await txn.delete(dedupKey);\n }\n }\n await txn.delete(key);\n count++;\n }\n await txn.put<ExpiredRunFence>(expiredRunKey(runId), { expiredAt, deleted: count });\n await this.#scheduleNextAlarm(txn, this.#now());\n return count;\n });\n return { deleted };\n }\n}\n","import { DurableObject } from '../do-base.js';\nimport type { ExpireRunStreamsResult, ExpireStreamResult } from '../../retention.js';\n\ninterface StreamMeta {\n /** Number of chunks written so far (also the next chunk index). */\n count: number;\n /** Whether the stream has been closed (EOF). */\n closed: boolean;\n ownerRunId?: string;\n expiredAt?: number;\n}\n\nconst META_KEY = 'meta';\nconst CHUNK_KEY_PREFIX = 'chunk:';\n/** Registry keys used when this DO instance acts as a per-run stream index. */\nconst STREAM_REGISTRY_PREFIX = 'stream:';\nconst REGISTRY_OWNER_KEY = 'registry:owner';\nconst REGISTRY_EXPIRED_KEY = 'registry:expired';\n\n/**\n * Zero-pad chunk indexes so `storage.list({ prefix })` returns chunks in\n * write order. 12 digits comfortably exceeds any realistic chunk count.\n */\nfunction chunkKey(index: number): string {\n return `${CHUNK_KEY_PREFIX}${index.toString().padStart(12, '0')}`;\n}\n\n/**\n * Durable Object backing workflow streams.\n *\n * Two roles, selected by the DO name:\n * - `stream:<name>`: chunk storage for a single stream. A monotonic\n * per-stream counter (maintained transactionally inside the DO) assigns\n * each chunk its index; one chunk per storage key.\n * - `run-streams:<runId>`: registry of stream names owned by a run,\n * powering `listStreamsByRunId`.\n */\nexport class StreamDO extends DurableObject {\n private async getMeta(): Promise<StreamMeta> {\n const meta = await this.ctx.storage.get<StreamMeta>(META_KEY);\n return meta ?? { count: 0, closed: false };\n }\n\n private assertOwner(meta: StreamMeta, runId: string): void {\n if (meta.expiredAt !== undefined) {\n throw new Error(`Workflow run \"${runId}\" has expired`);\n }\n if (meta.ownerRunId !== undefined && meta.ownerRunId !== runId) {\n throw new Error(`Stream is owned by workflow run \"${meta.ownerRunId}\"`);\n }\n }\n\n /**\n * Append a chunk. The index is allocated inside the transaction, so\n * concurrent writers can never collide or skip.\n */\n async writeChunk(runId: string, data: Uint8Array): Promise<number> {\n return await this.ctx.storage.transaction(async (txn) => {\n const meta = (await txn.get<StreamMeta>(META_KEY)) ?? { count: 0, closed: false };\n this.assertOwner(meta, runId);\n if (meta.closed) {\n throw new Error('Cannot write to a closed stream');\n }\n const index = meta.count;\n await txn.put(chunkKey(index), data);\n await txn.put<StreamMeta>(META_KEY, {\n count: index + 1,\n closed: false,\n ownerRunId: runId,\n });\n return index;\n });\n }\n\n /**\n * Close the stream (idempotent). Readers observe `done: true` once all\n * previously written chunks have been consumed.\n */\n async closeStream(runId: string): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n const meta = (await txn.get<StreamMeta>(META_KEY)) ?? { count: 0, closed: false };\n this.assertOwner(meta, runId);\n await txn.put<StreamMeta>(META_KEY, { ...meta, ownerRunId: runId, closed: true });\n });\n }\n\n /**\n * Read up to `limit` chunks starting at `startIndex` (0-based, inclusive).\n */\n async getChunks(params: { startIndex: number; limit: number }): Promise<{\n chunks: Uint8Array[];\n /** Whether the stream is closed. */\n done: boolean;\n /** Index of the last written chunk, -1 when empty. */\n tailIndex: number;\n }> {\n const meta = await this.getMeta();\n if (meta.expiredAt !== undefined) {\n throw new Error('Stream has expired');\n }\n const start = Math.max(0, params.startIndex);\n const entries = await this.ctx.storage.list<Uint8Array>({\n prefix: CHUNK_KEY_PREFIX,\n start: chunkKey(start),\n limit: params.limit,\n });\n return {\n chunks: Array.from(entries.values()),\n done: meta.closed,\n tailIndex: meta.count - 1,\n };\n }\n\n /**\n * Lightweight stream metadata: last chunk index and completion flag.\n */\n async getInfo(): Promise<{ tailIndex: number; done: boolean }> {\n const meta = await this.getMeta();\n if (meta.expiredAt !== undefined) {\n throw new Error('Stream has expired');\n }\n return { tailIndex: meta.count - 1, done: meta.closed };\n }\n\n /**\n * Register a stream name against this per-run registry instance.\n */\n async registerStream(runId: string, name: string): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n if ((await txn.get(REGISTRY_EXPIRED_KEY)) !== undefined) {\n throw new Error(`Workflow run \"${runId}\" has expired`);\n }\n const owner = await txn.get<string>(REGISTRY_OWNER_KEY);\n if (owner !== undefined && owner !== runId) {\n throw new Error(`Stream registry is owned by workflow run \"${owner}\"`);\n }\n await txn.put(REGISTRY_OWNER_KEY, runId);\n await txn.put(`${STREAM_REGISTRY_PREFIX}${name}`, true);\n });\n }\n\n /**\n * List stream names registered against this per-run registry instance.\n */\n async listStreams(): Promise<string[]> {\n if ((await this.ctx.storage.get(REGISTRY_EXPIRED_KEY)) !== undefined) {\n throw new Error('Workflow run streams have expired');\n }\n const entries = await this.ctx.storage.list<boolean>({ prefix: STREAM_REGISTRY_PREFIX });\n return Array.from(entries.keys()).map((key) => key.slice(STREAM_REGISTRY_PREFIX.length));\n }\n\n /** Fence a run's registry before any stream cells are removed. */\n async expireRegistry(runId: string, expiredAt: number): Promise<ExpireRunStreamsResult> {\n return await this.ctx.storage.transaction(async (txn) => {\n const owner = await txn.get<string>(REGISTRY_OWNER_KEY);\n if (owner !== undefined && owner !== runId) {\n throw new Error(`Stream registry is owned by workflow run \"${owner}\"`);\n }\n await txn.put(REGISTRY_OWNER_KEY, runId);\n await txn.put(REGISTRY_EXPIRED_KEY, expiredAt);\n const entries = await txn.list<boolean>({ prefix: STREAM_REGISTRY_PREFIX });\n return {\n streams: Array.from(entries.keys()).map((key) => key.slice(STREAM_REGISTRY_PREFIX.length)),\n };\n });\n }\n\n /** Remove the registry payload after every referenced stream was fenced. */\n async finalizeRegistry(runId: string): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n const owner = await txn.get<string>(REGISTRY_OWNER_KEY);\n const expiredAt = await txn.get<number>(REGISTRY_EXPIRED_KEY);\n if (owner !== runId || expiredAt === undefined) {\n throw new Error(`Stream registry for workflow run \"${runId}\" is not expired`);\n }\n const entries = await txn.list({ prefix: STREAM_REGISTRY_PREFIX });\n for (const key of entries.keys()) await txn.delete(key);\n });\n }\n\n /** Delete stream payload while leaving a small ownership tombstone. */\n async expireStream(runId: string, expiredAt: number): Promise<ExpireStreamResult> {\n return await this.ctx.storage.transaction(async (txn) => {\n const meta = (await txn.get<StreamMeta>(META_KEY)) ?? { count: 0, closed: false };\n if (meta.ownerRunId !== undefined && meta.ownerRunId !== runId) {\n throw new Error(`Stream is owned by workflow run \"${meta.ownerRunId}\"`);\n }\n const chunks = await txn.list({ prefix: CHUNK_KEY_PREFIX });\n for (const key of chunks.keys()) {\n await txn.delete(key);\n }\n await txn.put<StreamMeta>(META_KEY, {\n count: 0,\n closed: true,\n ownerRunId: runId,\n expiredAt,\n });\n return { deleted: true, chunks: chunks.size };\n });\n }\n}\n","/**\n * Transactional event-application core shared by the real WorkflowRunDO and\n * the in-memory test mocks.\n *\n * All guard checks, the event append, and the entity mutation happen against a\n * single {@link EventStore}. The Durable Object wraps a call to\n * {@link applyEvent} in `ctx.storage.transaction()`, so the whole operation is\n * atomic; the mocks run it against an in-memory store.\n *\n * Guard semantics are ported from the upstream `@workflow/world-local` /\n * `@workflow/world-postgres` reference implementations (4.2.x contract):\n * - run_started on a terminal run -> RunExpiredError\n * - terminal transitions on a terminal run -> EntityConflictError\n * - run_cancelled is idempotent on an already-cancelled run\n * - duplicate step_created / hook_created -> EntityConflictError\n * - step events on a terminal step -> EntityConflictError\n * - step_started before step.retryAfter -> TooEarlyError\n * - error/output/completedAt are cleared whenever a run re-enters a\n * non-final status (WorkflowRunSchema is a discriminated union)\n *\n * Errors are returned as structured outcomes (never thrown) because custom\n * error classes do not survive the Durable Object RPC boundary with their\n * `name` intact — and `@workflow/errors` matches errors by name via `.is()`.\n * The storage layer converts outcomes back into the typed errors.\n */\n\nimport type {\n CreateEventRequest,\n Event,\n Hook,\n RunCreatedEventRequest,\n Step,\n WorkflowRun,\n} from '@workflow/world';\nimport {\n EventSchema,\n HookSchema,\n isLegacySpecVersion,\n isTerminalStepStatus,\n isTerminalWorkflowRunStatus,\n requiresNewerWorld,\n SPEC_VERSION_CURRENT,\n StepSchema,\n WorkflowRunSchema,\n} from '@workflow/world';\nimport { compact } from './util.js';\nimport type { ScheduleCleanupRequest } from './retention.js';\n\n/** Storage key for the run entity. */\nconst RUN_KEY = 'run';\n/** Key prefixes for per-entity storage. */\nexport const EVENT_KEY_PREFIX = 'event:';\nexport const STEP_KEY_PREFIX = 'step:';\nexport const HOOK_KEY_PREFIX = 'hook:';\nexport const STEP_CREATED_KEY_PREFIX = 'stepcreated:';\nexport const HOOK_CREATED_KEY_PREFIX = 'hookcreated:';\n/**\n * Marker recording that a hook_created event was committed for a hookId.\n * Mirrors postgres' `workflow_events_entity_creation_unique` partial index:\n * it outlives hook disposal so a replayed hook_created after dispose is\n * rejected as a duplicate instead of resurrecting the hook.\n */\nconst HOOK_EVENT_MARKER_PREFIX = 'hookevent:';\n\nexport interface EventStoreListOptions {\n prefix: string;\n /** Exclusive lower bound (full key). */\n startAfter?: string;\n /** Exclusive upper bound (full key). */\n end?: string;\n limit?: number;\n reverse?: boolean;\n}\n\n/**\n * Minimal transactional key-value surface, satisfied by\n * `DurableObjectTransaction` / `DurableObjectStorage` and by the in-memory\n * test-mock store. Keys list in lexicographic order (reversed when\n * `reverse: true`).\n */\nexport interface EventStore {\n get<T>(key: string): Promise<T | undefined>;\n put<T>(key: string, value: T): Promise<void>;\n delete(key: string): Promise<boolean>;\n list<T>(options: EventStoreListOptions): Promise<Map<string, T>>;\n}\n\nexport interface ApplyEventRequest {\n /** The effective run id (already resolved / generated by the caller). */\n runId: string;\n data: CreateEventRequest | RunCreatedEventRequest;\n /**\n * Current holder of the hook token per the global KV token index\n * (hook_created only). `null` means the token is unclaimed.\n */\n tokenHolder?: { runId: string; hookId: string } | null;\n /** Internal world-celld retention policy captured with the event. */\n cleanup?: ScheduleCleanupRequest;\n}\n\nexport type ApplyEventErrorCode =\n | 'RUN_NOT_FOUND'\n | 'STEP_NOT_FOUND'\n | 'HOOK_NOT_FOUND'\n | 'ENTITY_CONFLICT'\n | 'RUN_EXPIRED'\n | 'TOO_EARLY'\n | 'RUN_NOT_SUPPORTED'\n | 'LEGACY_RUN_NOT_SUPPORTED';\n\nexport interface ApplyEventFailure {\n ok: false;\n code: ApplyEventErrorCode;\n message: string;\n /** Seconds until retry is allowed (TOO_EARLY only). */\n retryAfterSeconds?: number;\n /** The run's spec version (RUN_NOT_SUPPORTED only). */\n runSpecVersion?: number;\n}\n\nexport interface ApplyEventSuccess {\n ok: true;\n /** Absent for idempotent replays that record no new event. */\n event?: Event;\n run?: WorkflowRun;\n step?: Step;\n hook?: Hook;\n /** Hooks whose tokens must be released from the global KV index. */\n releasedHooks: Array<{ hookId: string; token: string }>;\n /** Set when a run entity was created (run_created or resilient bootstrap). */\n runCreated?: { workflowName: string; createdAt: Date };\n /** Set when the global KV hook index must be (re)written. */\n hookToIndex?: Hook;\n /** All events (ascending), preloaded for run_started responses. */\n events?: Event[];\n}\n\nexport type ApplyEventOutcome = ApplyEventSuccess | ApplyEventFailure;\n\ninterface ApplyEventContext extends ApplyEventRequest {\n nextEventId(): string;\n now: Date;\n}\n\nfunction failure(\n code: ApplyEventErrorCode,\n message: string,\n extra?: Pick<ApplyEventFailure, 'retryAfterSeconds' | 'runSpecVersion'>,\n): ApplyEventFailure {\n return { ok: false, code, message, ...extra };\n}\n\nfunction readStringProp(value: unknown, key: string): string | undefined {\n if (value !== null && typeof value === 'object') {\n const prop = (value as Record<string, unknown>)[key];\n if (typeof prop === 'string') return prop;\n }\n return undefined;\n}\n\n/**\n * Map a failure eventData.error (which may be a string, an Error-shaped\n * object, or anything else) to the structured error stored on entities.\n * Matches upstream: string errors keep their text, errorCode is preserved.\n */\nfunction toStructuredError(\n error: unknown,\n opts?: { stack?: string; code?: string },\n): { message: string; stack?: string; code?: string } {\n const message =\n typeof error === 'string' ? error : (readStringProp(error, 'message') ?? 'Unknown error');\n return {\n message,\n stack: opts?.stack ?? readStringProp(error, 'stack'),\n code: opts?.code ?? readStringProp(error, 'code'),\n };\n}\n\n/**\n * Shared cursor pagination over a key prefix. Fetches `limit + 1` entries to\n * detect `hasMore` without ever skipping the boundary entry (the cursor is\n * derived from the last *returned* item, not the peeked one).\n */\nexport async function listByPrefix<T>(\n store: EventStore,\n prefix: string,\n params: { limit: number; cursor?: string; sortOrder?: 'asc' | 'desc' },\n getId: (item: T) => string,\n): Promise<{ data: T[]; cursor: string | null; hasMore: boolean }> {\n const { limit, cursor, sortOrder = 'asc' } = params;\n const options: EventStoreListOptions =\n sortOrder === 'desc'\n ? { prefix, reverse: true, limit: limit + 1, end: cursor ? `${prefix}${cursor}` : undefined }\n : { prefix, limit: limit + 1, startAfter: cursor ? `${prefix}${cursor}` : undefined };\n const entries = await store.list<T>(options);\n const values = Array.from(entries.values());\n const hasMore = values.length > limit;\n const data = values.slice(0, limit);\n const last = data.at(-1);\n return {\n data,\n cursor: hasMore && last !== undefined ? getId(last) : null,\n hasMore,\n };\n}\n\nfunction creationIndexKey(prefix: string, createdAt: Date, id: string): string {\n return `${prefix}${createdAt.toISOString()}:${id}`;\n}\n\n/**\n * Cursor pagination over an explicit creation-time index. Entity ids are\n * values rather than key suffixes, so caller-supplied ids cannot disturb the\n * requested ordering.\n */\nexport async function listByCreationTime<T>(\n store: EventStore,\n indexPrefix: string,\n entityPrefix: string,\n params: { limit: number; cursor?: string; sortOrder?: 'asc' | 'desc' },\n): Promise<{ data: T[]; cursor: string | null; hasMore: boolean }> {\n const { limit, cursor, sortOrder = 'asc' } = params;\n const entries = await store.list<string>(\n sortOrder === 'desc'\n ? {\n prefix: indexPrefix,\n reverse: true,\n limit: limit + 1,\n end: cursor ? `${indexPrefix}${cursor}` : undefined,\n }\n : {\n prefix: indexPrefix,\n limit: limit + 1,\n startAfter: cursor ? `${indexPrefix}${cursor}` : undefined,\n },\n );\n const page = Array.from(entries.entries()).slice(0, limit);\n const data: T[] = [];\n for (const [, id] of page) {\n const item = await store.get<T>(`${entityPrefix}${id}`);\n if (item !== undefined) data.push(item);\n }\n const hasMore = entries.size > limit;\n const lastKey = page.at(-1)?.[0];\n return {\n data,\n cursor: hasMore && lastKey ? lastKey.slice(indexPrefix.length) : null,\n hasMore,\n };\n}\n\n/** Delete all hook entities for the run, returning the released tokens. */\nasync function releaseAllHooks(\n store: EventStore,\n): Promise<Array<{ hookId: string; token: string }>> {\n const hooks = await store.list<Hook>({ prefix: HOOK_KEY_PREFIX });\n const released: Array<{ hookId: string; token: string }> = [];\n for (const hook of hooks.values()) {\n await store.delete(`${HOOK_KEY_PREFIX}${hook.hookId}`);\n await store.delete(creationIndexKey(HOOK_CREATED_KEY_PREFIX, hook.createdAt, hook.hookId));\n released.push({ hookId: hook.hookId, token: hook.token });\n }\n return released;\n}\n\nexport async function applyEvent(\n store: EventStore,\n ctx: ApplyEventContext,\n): Promise<ApplyEventOutcome> {\n const { runId, data, now } = ctx;\n const specVersion = data.specVersion ?? SPEC_VERSION_CURRENT;\n\n /** Build and validate the stored event BEFORE anything is persisted. */\n const buildEvent = (record: Record<string, unknown>): Event => {\n const withMeta: Record<string, unknown> = {\n ...record,\n runId,\n eventId: ctx.nextEventId(),\n createdAt: now,\n specVersion,\n };\n // eventData belongs on run_created only; run_started must not carry it.\n if (record.eventType === 'run_started') {\n delete withMeta.eventData;\n }\n return EventSchema.parse(compact(withMeta));\n };\n\n const putEvent = async (event: Event): Promise<void> => {\n await store.put(`${EVENT_KEY_PREFIX}${event.eventId}`, event);\n };\n\n // ============================================================\n // VALIDATION: current run state (skipped for run_created and for\n // step_completed / step_retrying, matching upstream — those only operate\n // on running steps regardless of run state).\n // ============================================================\n let currentRun: WorkflowRun | undefined;\n const skipRunValidation =\n data.eventType === 'run_created' ||\n data.eventType === 'step_completed' ||\n data.eventType === 'step_retrying';\n if (!skipRunValidation) {\n currentRun = await store.get<WorkflowRun>(RUN_KEY);\n }\n\n // ============================================================\n // RESILIENT START: run_started on a non-existent run bootstraps the run\n // from the message's runInput (spec >= 3 queue transport).\n // ============================================================\n let bootstrapped: ApplyEventSuccess['runCreated'];\n if (data.eventType === 'run_started' && !currentRun && data.eventData) {\n const { deploymentId, workflowName, input, executionContext } = data.eventData;\n if (deploymentId && workflowName && input !== undefined) {\n const createdRun = WorkflowRunSchema.parse(\n compact({\n runId,\n deploymentId,\n workflowName,\n specVersion,\n executionContext,\n input,\n status: 'pending',\n output: undefined,\n error: undefined,\n startedAt: undefined,\n completedAt: undefined,\n createdAt: now,\n updatedAt: now,\n }),\n );\n const runCreatedEvent = buildEvent({\n eventType: 'run_created',\n eventData: { deploymentId, workflowName, input, executionContext },\n });\n await store.put(RUN_KEY, createdRun);\n await putEvent(runCreatedEvent);\n currentRun = createdRun;\n bootstrapped = { workflowName, createdAt: now };\n }\n }\n\n // ============================================================\n // VERSION COMPATIBILITY\n // ============================================================\n if (currentRun) {\n if (requiresNewerWorld(currentRun.specVersion)) {\n return failure(\n 'RUN_NOT_SUPPORTED',\n `Run \"${runId}\" requires a newer world (run specVersion ${currentRun.specVersion}, world ${SPEC_VERSION_CURRENT})`,\n { runSpecVersion: currentRun.specVersion },\n );\n }\n if (isLegacySpecVersion(currentRun.specVersion)) {\n return failure(\n 'LEGACY_RUN_NOT_SUPPORTED',\n `Run \"${runId}\" was created with a legacy spec version (${currentRun.specVersion ?? 'undefined'}) not supported by this world`,\n );\n }\n }\n\n // ============================================================\n // GUARDS: terminal run state\n // ============================================================\n if (currentRun && isTerminalWorkflowRunStatus(currentRun.status)) {\n // Idempotent: run_cancelled on an already-cancelled run records the event\n // and returns the current state.\n if (data.eventType === 'run_cancelled' && currentRun.status === 'cancelled') {\n const event = buildEvent({ ...data });\n await putEvent(event);\n return { ok: true, event, run: currentRun, releasedHooks: [] };\n }\n if (data.eventType === 'run_started') {\n return failure(\n 'RUN_EXPIRED',\n `Workflow run \"${runId}\" is already in terminal state \"${currentRun.status}\"`,\n );\n }\n if (\n data.eventType === 'run_completed' ||\n data.eventType === 'run_failed' ||\n data.eventType === 'run_cancelled'\n ) {\n return failure(\n 'ENTITY_CONFLICT',\n `Cannot transition run from terminal state \"${currentRun.status}\"`,\n );\n }\n if (\n data.eventType === 'step_created' ||\n data.eventType === 'hook_created' ||\n data.eventType === 'wait_created'\n ) {\n return failure(\n 'ENTITY_CONFLICT',\n `Cannot create new entities on run in terminal state \"${currentRun.status}\"`,\n );\n }\n }\n\n // ============================================================\n // GUARDS: step ordering and terminal state\n // ============================================================\n let validatedStep: Step | undefined;\n if (\n data.eventType === 'step_started' ||\n data.eventType === 'step_completed' ||\n data.eventType === 'step_failed' ||\n data.eventType === 'step_retrying'\n ) {\n validatedStep = await store.get<Step>(`${STEP_KEY_PREFIX}${data.correlationId}`);\n if (!validatedStep) {\n return failure('STEP_NOT_FOUND', `Step \"${data.correlationId}\" not found`);\n }\n if (isTerminalStepStatus(validatedStep.status)) {\n return failure(\n 'ENTITY_CONFLICT',\n `Cannot modify step in terminal state \"${validatedStep.status}\"`,\n );\n }\n // On terminal runs, only in-flight steps may still record progress.\n if (\n currentRun &&\n isTerminalWorkflowRunStatus(currentRun.status) &&\n validatedStep.status !== 'running'\n ) {\n return failure(\n 'RUN_EXPIRED',\n `Cannot modify non-running step on run in terminal state \"${currentRun.status}\"`,\n );\n }\n }\n\n // ============================================================\n // GUARDS: hook event ordering\n // ============================================================\n if (\n (data.eventType === 'hook_disposed' || data.eventType === 'hook_received') &&\n data.correlationId\n ) {\n const existingHook = await store.get<Hook>(`${HOOK_KEY_PREFIX}${data.correlationId}`);\n if (!existingHook) {\n return failure('HOOK_NOT_FOUND', `Hook \"${data.correlationId}\" not found`);\n }\n }\n\n // Non-run_created events require the run to exist (after the resilient\n // start bootstrap had its chance). step_completed / step_retrying skip the\n // run read entirely — their step guard above already proves the run exists.\n if (!skipRunValidation && data.eventType !== 'run_started' && !currentRun) {\n return failure('RUN_NOT_FOUND', `Workflow run \"${runId}\" not found`);\n }\n\n // ============================================================\n // EVENT + ENTITY WRITES (single transaction)\n // ============================================================\n switch (data.eventType) {\n case 'run_created': {\n const existing = await store.get<WorkflowRun>(RUN_KEY);\n if (existing) {\n // Idempotent replay: return the existing run without appending a\n // duplicate run_created event to the log.\n return { ok: true, run: existing, releasedHooks: [] };\n }\n const run = WorkflowRunSchema.parse(\n compact({\n runId,\n deploymentId: data.eventData.deploymentId,\n workflowName: data.eventData.workflowName,\n specVersion,\n executionContext: data.eventData.executionContext,\n input: data.eventData.input,\n status: 'pending',\n output: undefined,\n error: undefined,\n startedAt: undefined,\n completedAt: undefined,\n createdAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(RUN_KEY, run);\n await putEvent(event);\n return {\n ok: true,\n event,\n run,\n releasedHooks: [],\n runCreated: { workflowName: data.eventData.workflowName, createdAt: now },\n };\n }\n\n case 'run_started': {\n if (!currentRun) {\n return failure('RUN_NOT_FOUND', `Workflow run \"${runId}\" not found`);\n }\n // Idempotent for concurrent invocations / queue redeliveries: if the\n // run is already running this is a replay — no duplicate event.\n if (currentRun.status === 'running') {\n return { ok: true, run: currentRun, releasedHooks: [] };\n }\n const run = WorkflowRunSchema.parse(\n compact({\n ...currentRun,\n status: 'running',\n output: undefined,\n error: undefined,\n completedAt: undefined,\n startedAt: currentRun.startedAt ?? now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(RUN_KEY, run);\n await putEvent(event);\n // Preload all events so the runtime can skip the initial events.list.\n const allEvents = await listByPrefix<Event>(\n store,\n EVENT_KEY_PREFIX,\n { limit: 1000, sortOrder: 'asc' },\n (e) => e.eventId,\n );\n return {\n ok: true,\n event,\n run,\n releasedHooks: [],\n runCreated: bootstrapped,\n events: allEvents.data,\n };\n }\n\n case 'run_completed': {\n if (!currentRun) {\n return failure('RUN_NOT_FOUND', `Workflow run \"${runId}\" not found`);\n }\n const run = WorkflowRunSchema.parse(\n compact({\n ...currentRun,\n status: 'completed',\n output: data.eventData.output,\n error: undefined,\n completedAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(RUN_KEY, run);\n await putEvent(event);\n const releasedHooks = await releaseAllHooks(store);\n return { ok: true, event, run, releasedHooks };\n }\n\n case 'run_failed': {\n if (!currentRun) {\n return failure('RUN_NOT_FOUND', `Workflow run \"${runId}\" not found`);\n }\n const run = WorkflowRunSchema.parse(\n compact({\n ...currentRun,\n status: 'failed',\n output: undefined,\n error: toStructuredError(data.eventData.error, {\n code: data.eventData.errorCode ?? readStringProp(data.eventData.error, 'code'),\n }),\n completedAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(RUN_KEY, run);\n await putEvent(event);\n const releasedHooks = await releaseAllHooks(store);\n return { ok: true, event, run, releasedHooks };\n }\n\n case 'run_cancelled': {\n if (!currentRun) {\n return failure('RUN_NOT_FOUND', `Workflow run \"${runId}\" not found`);\n }\n const run = WorkflowRunSchema.parse(\n compact({\n ...currentRun,\n status: 'cancelled',\n output: undefined,\n error: undefined,\n completedAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(RUN_KEY, run);\n await putEvent(event);\n const releasedHooks = await releaseAllHooks(store);\n return { ok: true, event, run, releasedHooks };\n }\n\n case 'step_created': {\n const stepKey = `${STEP_KEY_PREFIX}${data.correlationId}`;\n const existing = await store.get<Step>(stepKey);\n if (existing) {\n // Core catches EntityConflictError for exactly this replay case\n // (\"Step already exists, continuing\").\n return failure('ENTITY_CONFLICT', `Step \"${data.correlationId}\" already exists`);\n }\n const step = StepSchema.parse(\n compact({\n runId,\n stepId: data.correlationId,\n stepName: data.eventData.stepName,\n status: 'pending',\n input: data.eventData.input,\n output: undefined,\n error: undefined,\n attempt: 0,\n startedAt: undefined,\n completedAt: undefined,\n retryAfter: undefined,\n createdAt: now,\n updatedAt: now,\n specVersion,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(stepKey, step);\n await store.put(\n creationIndexKey(STEP_CREATED_KEY_PREFIX, step.createdAt, step.stepId),\n step.stepId,\n );\n await putEvent(event);\n return { ok: true, event, step, releasedHooks: [] };\n }\n\n case 'step_started': {\n const step = validatedStep;\n if (!step) {\n return failure('STEP_NOT_FOUND', `Step \"${data.correlationId}\" not found`);\n }\n if (step.retryAfter && step.retryAfter.getTime() > now.getTime()) {\n return failure(\n 'TOO_EARLY',\n `Cannot start step \"${data.correlationId}\": retryAfter timestamp has not been reached yet`,\n {\n retryAfterSeconds: Math.ceil((step.retryAfter.getTime() - now.getTime()) / 1000),\n },\n );\n }\n const updated = StepSchema.parse(\n compact({\n ...step,\n status: 'running',\n // Only set startedAt on the first start; increment attempt each start.\n startedAt: step.startedAt ?? now,\n attempt: step.attempt + 1,\n retryAfter: undefined,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(`${STEP_KEY_PREFIX}${data.correlationId}`, updated);\n await putEvent(event);\n return { ok: true, event, step: updated, releasedHooks: [] };\n }\n\n case 'step_completed': {\n const step = validatedStep;\n if (!step) {\n return failure('STEP_NOT_FOUND', `Step \"${data.correlationId}\" not found`);\n }\n const updated = StepSchema.parse(\n compact({\n ...step,\n status: 'completed',\n output: data.eventData.result,\n completedAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(`${STEP_KEY_PREFIX}${data.correlationId}`, updated);\n await putEvent(event);\n return { ok: true, event, step: updated, releasedHooks: [] };\n }\n\n case 'step_failed': {\n const step = validatedStep;\n if (!step) {\n return failure('STEP_NOT_FOUND', `Step \"${data.correlationId}\" not found`);\n }\n const updated = StepSchema.parse(\n compact({\n ...step,\n status: 'failed',\n error: toStructuredError(data.eventData.error, { stack: data.eventData.stack }),\n completedAt: now,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(`${STEP_KEY_PREFIX}${data.correlationId}`, updated);\n await putEvent(event);\n return { ok: true, event, step: updated, releasedHooks: [] };\n }\n\n case 'step_retrying': {\n const step = validatedStep;\n if (!step) {\n return failure('STEP_NOT_FOUND', `Step \"${data.correlationId}\" not found`);\n }\n const updated = StepSchema.parse(\n compact({\n ...step,\n status: 'pending',\n error: toStructuredError(data.eventData.error, { stack: data.eventData.stack }),\n retryAfter: data.eventData.retryAfter ? new Date(data.eventData.retryAfter) : undefined,\n updatedAt: now,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(`${STEP_KEY_PREFIX}${data.correlationId}`, updated);\n await putEvent(event);\n return { ok: true, event, step: updated, releasedHooks: [] };\n }\n\n case 'hook_created': {\n const hookId = data.correlationId;\n const token = data.eventData.token;\n const holder = ctx.tokenHolder ?? null;\n const markerKey = `${HOOK_EVENT_MARKER_PREFIX}${hookId}`;\n const hookKey = `${HOOK_KEY_PREFIX}${hookId}`;\n\n if (holder && (holder.runId !== runId || holder.hookId !== hookId)) {\n // A different (runId, hookId) holds this token. Record a\n // hook_conflict event carrying conflictingRunId so the claiming\n // workflow fails deterministically when the hook is awaited. The\n // legitimate holder's KV index entry is left untouched.\n const event = buildEvent({\n eventType: 'hook_conflict',\n correlationId: hookId,\n eventData: { token, conflictingRunId: holder.runId },\n });\n await putEvent(event);\n return { ok: true, event, releasedHooks: [] };\n }\n\n const existingMarker = await store.get<string>(markerKey);\n if (existingMarker !== undefined) {\n const existingHook = await store.get<Hook>(hookKey);\n if (existingHook && !holder) {\n // Crash orphan: hook + event committed but the global KV index\n // write was lost. Complete the partial write by re-indexing.\n return { ok: true, hook: existingHook, hookToIndex: existingHook, releasedHooks: [] };\n }\n // Fully-committed duplicate (or re-create after disposal): reject so\n // the runtime's concurrent-replay catch path can swallow it.\n return failure('ENTITY_CONFLICT', `Hook \"${hookId}\" already created`);\n }\n\n const hook = HookSchema.parse(\n compact({\n runId,\n hookId,\n token,\n metadata: data.eventData.metadata,\n ownerId: '',\n projectId: '',\n environment: '',\n createdAt: now,\n specVersion,\n isWebhook: data.eventData.isWebhook ?? false,\n }),\n );\n const event = buildEvent({ ...data });\n await store.put(hookKey, hook);\n await store.put(\n creationIndexKey(HOOK_CREATED_KEY_PREFIX, hook.createdAt, hook.hookId),\n hook.hookId,\n );\n await store.put(markerKey, event.eventId);\n await putEvent(event);\n return { ok: true, event, hook, hookToIndex: hook, releasedHooks: [] };\n }\n\n case 'hook_disposed': {\n const hookKey = `${HOOK_KEY_PREFIX}${data.correlationId}`;\n // Existence was validated above; read again for the token.\n const hook = await store.get<Hook>(hookKey);\n if (!hook) {\n return failure('HOOK_NOT_FOUND', `Hook \"${data.correlationId}\" not found`);\n }\n await store.delete(hookKey);\n await store.delete(creationIndexKey(HOOK_CREATED_KEY_PREFIX, hook.createdAt, hook.hookId));\n const event = buildEvent({ ...data });\n await putEvent(event);\n return {\n ok: true,\n event,\n releasedHooks: [{ hookId: hook.hookId, token: hook.token }],\n };\n }\n\n // hook_received, hook_conflict, wait_created, wait_completed are\n // event-only at the storage level for this world.\n default: {\n const event = buildEvent({ ...data });\n await putEvent(event);\n return { ok: true, event, releasedHooks: [] };\n }\n }\n}\n","import type { TerminalWorkflowRunStatus, WorkflowRun } from '@workflow/world';\n\nexport const CLEANUP_RECORD_KEY = 'retention:cleanup';\nexport const TOMBSTONE_KEY = 'retention:tombstone';\nexport const INDEX_MARKER_PREFIX = 'retention:index:';\nexport const HOOK_MARKER_PREFIX = 'retention:hook:';\n\nexport type CleanupPhase = 'retained' | 'index' | 'streams' | 'queues' | 'payload' | 'tombstoned';\n\nexport interface CleanupRecord {\n version: 1;\n runId: string;\n workflowName: string;\n createdAt: Date;\n completedAt: Date;\n terminalStatus: TerminalWorkflowRunStatus;\n dueAt: Date;\n queueShards: number;\n phase: CleanupPhase;\n attempts: number;\n lastError?: string;\n lastAttemptAt?: Date;\n tombstonedAt?: Date;\n deletedPayloadKeys: number;\n deletedStreams: number;\n deletedQueueMessages: number;\n}\n\nexport interface RunTombstone {\n version: 1;\n runId: string;\n terminalStatus: TerminalWorkflowRunStatus;\n completedAt: Date;\n expiredAt: Date;\n tombstonedAt: Date;\n}\n\nexport type RunReadOutcome<T> =\n | { ok: true; value: T }\n | { ok: false; code: 'RUN_EXPIRED'; message: string; tombstone: RunTombstone };\n\nexport interface HookIndexReference {\n hookId: string;\n token: string;\n}\n\nexport interface ExpireRunIndexesRequest {\n runId: string;\n keys: string[];\n hooks: HookIndexReference[];\n expiredAt: number;\n}\n\nexport interface ExpireRunIndexesResult {\n deleted: number;\n}\n\nexport interface ExpireRunStreamsResult {\n streams: string[];\n}\n\nexport interface ExpireStreamResult {\n deleted: boolean;\n chunks: number;\n}\n\nexport interface ExpireQueueRunResult {\n deleted: number;\n}\n\nexport interface ScheduleCleanupRequest {\n retentionMs: number;\n queueShards: number;\n}\n\nexport function sortableTimestamp(date: Date): string {\n return date.getTime().toString().padStart(13, '0');\n}\n\nexport function workflowRunIndexKey(\n run: Pick<WorkflowRun, 'workflowName' | 'createdAt' | 'runId'>,\n) {\n return `run:${run.workflowName}:${sortableTimestamp(run.createdAt)}:${run.runId}`;\n}\n\nexport function globalRunIndexKey(run: Pick<WorkflowRun, 'createdAt' | 'runId'>) {\n return `runall:${sortableTimestamp(run.createdAt)}:${run.runId}`;\n}\n\nexport function correlationIndexKey(\n correlationId: string,\n createdAt: Date,\n eventId: string,\n runId: string,\n): string {\n return `correlation:${encodeURIComponent(correlationId)}:${sortableTimestamp(createdAt)}:${eventId}:${runId}`;\n}\n\nexport function indexMarkerKey(indexKey: string): string {\n return `${INDEX_MARKER_PREFIX}${encodeURIComponent(indexKey)}`;\n}\n\nexport function hookMarkerKey(reference: HookIndexReference): string {\n return `${HOOK_MARKER_PREFIX}${encodeURIComponent(reference.hookId)}:${encodeURIComponent(reference.token)}`;\n}\n\nexport function cleanupTombstone(record: CleanupRecord, now: Date): RunTombstone {\n return {\n version: 1,\n runId: record.runId,\n terminalStatus: record.terminalStatus,\n completedAt: record.completedAt,\n expiredAt: record.dueAt,\n tombstonedAt: now,\n };\n}\n\nexport function expiredRead<T>(tombstone: RunTombstone): RunReadOutcome<T> {\n return {\n ok: false,\n code: 'RUN_EXPIRED',\n message: `Workflow run \"${tombstone.runId}\" expired at ${tombstone.expiredAt.toISOString()}`,\n tombstone,\n };\n}\n","import { DurableObject } from '../do-base.js';\nimport type { Event, Hook, Step, WorkflowRun } from '@workflow/world';\nimport { isTerminalWorkflowRunStatus, WorkflowRunSchema } from '@workflow/world';\nimport {\n applyEvent,\n type ApplyEventOutcome,\n type ApplyEventRequest,\n EVENT_KEY_PREFIX,\n type EventStore,\n HOOK_CREATED_KEY_PREFIX,\n HOOK_KEY_PREFIX,\n listByCreationTime,\n listByPrefix,\n STEP_CREATED_KEY_PREFIX,\n STEP_KEY_PREFIX,\n} from '../../apply-event.js';\nimport {\n CLEANUP_RECORD_KEY,\n type CleanupRecord,\n cleanupTombstone,\n correlationIndexKey,\n type ExpireQueueRunResult,\n type ExpireRunIndexesRequest,\n type ExpireRunIndexesResult,\n type ExpireRunStreamsResult,\n type ExpireStreamResult,\n expiredRead,\n globalRunIndexKey,\n HOOK_MARKER_PREFIX,\n type HookIndexReference,\n hookMarkerKey,\n INDEX_MARKER_PREFIX,\n indexMarkerKey,\n type RunReadOutcome,\n type RunTombstone,\n type ScheduleCleanupRequest,\n TOMBSTONE_KEY,\n workflowRunIndexKey,\n} from '../../retention.js';\n\ninterface CellId {\n toString(): string;\n}\n\ninterface CellNamespace<T> {\n idFromName(name: string): CellId;\n get(id: CellId): T;\n}\n\ninterface IndexCleanupStub {\n expireRun(request: ExpireRunIndexesRequest): Promise<ExpireRunIndexesResult>;\n}\n\ninterface StreamCleanupStub {\n expireRegistry(runId: string, expiredAt: number): Promise<ExpireRunStreamsResult>;\n finalizeRegistry(runId: string): Promise<void>;\n expireStream(runId: string, expiredAt: number): Promise<ExpireStreamResult>;\n}\n\ninterface QueueCleanupStub {\n expireRun(runId: string, expiredAt: number): Promise<ExpireQueueRunResult>;\n}\n\ninterface WorkflowRunDOEnv {\n WORKFLOW_INDEX?: CellNamespace<IndexCleanupStub>;\n WORKFLOW_STREAMS?: CellNamespace<StreamCleanupStub>;\n WORKFLOW_QUEUE?: CellNamespace<QueueCleanupStub>;\n /** Test seam; celld deployments use Date.now(). */\n clock?: () => number;\n}\n\nconst PAYLOAD_DELETE_BATCH = 256;\nconst STREAM_DELETE_CONCURRENCY = 16;\nconst CLEANUP_RETRY_MAX_MS = 60 * 60 * 1000;\ntype TerminalRun = Extract<WorkflowRun, { status: 'completed' | 'failed' | 'cancelled' }>;\n\n/**\n * Current schema version for DO storage.\n * Increment when making breaking changes to the storage layout.\n * Migrations run lazily on first request after deploy.\n *\n * v2: one storage key per event ('event:<eventId>'), step ('step:<stepId>')\n * and hook ('hook:<hookId>') instead of single aggregate values. This package\n * is pre-production, so the migration simply drops the legacy aggregates.\n */\nconst CURRENT_SCHEMA_VERSION = 3;\n\n/**\n * Idempotent migration functions keyed by target version. The schema version\n * is written only after the migration completes, so eviction safely retries\n * an interrupted migration.\n */\nconst MIGRATIONS: Record<number, (storage: DurableObjectStorage) => Promise<void>> = {\n 2: async (storage) => {\n await storage.transaction(async (txn) => {\n // Pre-production layout change: drop the v1 aggregate values.\n await txn.delete('events');\n await txn.delete('steps');\n await txn.delete('hooks');\n });\n },\n 3: async (storage) => {\n await backfillCreationIndex<Step>(\n storage,\n STEP_KEY_PREFIX,\n STEP_CREATED_KEY_PREFIX,\n (step) => step.stepId,\n );\n await backfillCreationIndex<Hook>(\n storage,\n HOOK_KEY_PREFIX,\n HOOK_CREATED_KEY_PREFIX,\n (hook) => hook.hookId,\n );\n },\n};\n\nasync function backfillCreationIndex<T extends { createdAt: Date }>(\n storage: DurableObjectStorage,\n entityPrefix: string,\n indexPrefix: string,\n getId: (entity: T) => string,\n): Promise<void> {\n let startAfter: string | undefined;\n while (true) {\n const entities = await storage.list<T>({ prefix: entityPrefix, startAfter, limit: 100 });\n if (entities.size === 0) return;\n for (const [key, entity] of entities) {\n const id = getId(entity);\n await storage.put(`${indexPrefix}${entity.createdAt.toISOString()}:${id}`, id);\n startAfter = key;\n }\n if (entities.size < 100) return;\n }\n}\n\n/**\n * Ensure the DO storage schema is up to date.\n * Runs any pending migrations sequentially inside transactions,\n * persisting the version after each successful migration.\n * Safe to call on every request -- it's a no-op when already current.\n */\nasync function ensureSchemaUpToDate(storage: DurableObjectStorage): Promise<void> {\n const stored = (await storage.get<number>('schema_version')) ?? 1;\n\n for (let v = stored + 1; v <= CURRENT_SCHEMA_VERSION; v++) {\n const migration = MIGRATIONS[v];\n if (migration) {\n await migration(storage);\n }\n await storage.put('schema_version', v);\n }\n}\n\n/**\n * Adapt DO storage (or a transaction) to the {@link EventStore} interface\n * shared with the test mocks. No casts: the methods line up structurally,\n * this just pins the subset we rely on.\n */\nfunction storeFrom(storage: DurableObjectStorage | DurableObjectTransaction): EventStore {\n return {\n get: (key) => storage.get(key),\n put: (key, value) => storage.put(key, value),\n delete: (key) => storage.delete(key),\n list: (options) => storage.list(options),\n };\n}\n\ninterface InflightClaim {\n messageId: string;\n claimedAt: number;\n}\n\n/**\n * Durable Object for managing a single workflow run's state.\n *\n * All event-sourced writes go through {@link applyEvent} inside a single\n * storage transaction: guard checks, the event append, and the entity\n * mutation are atomic even if the DO is evicted mid-operation.\n *\n * Instances named `claim:<queueName>:<idempotencyKey>` are used purely as\n * queue-message dedup claims (see claimInflight/releaseInflight).\n */\nexport class WorkflowRunDO extends DurableObject {\n private schemaReady: Promise<void> | null = null;\n\n private now(): number {\n const clock = (this.env as WorkflowRunDOEnv)?.clock;\n return typeof clock === 'function' ? clock() : Date.now();\n }\n\n private ensureSchema(): Promise<void> {\n if (!this.schemaReady) {\n this.schemaReady = ensureSchemaUpToDate(this.ctx.storage);\n }\n return this.schemaReady;\n }\n\n private async expiredTombstone(\n storage: Pick<DurableObjectStorage, 'get'>,\n now = this.now(),\n ): Promise<RunTombstone | null> {\n const tombstone = await storage.get<RunTombstone>(TOMBSTONE_KEY);\n if (tombstone) return tombstone;\n const cleanup = await storage.get<CleanupRecord>(CLEANUP_RECORD_KEY);\n if (!cleanup || (cleanup.phase === 'retained' && cleanup.dueAt.getTime() > now)) return null;\n return cleanupTombstone(cleanup, cleanup.tombstonedAt ?? cleanup.dueAt);\n }\n\n private async read<T>(reader: () => Promise<T>): Promise<RunReadOutcome<T>> {\n await this.ensureSchema();\n const tombstone = await this.expiredTombstone(this.ctx.storage);\n if (tombstone) return expiredRead(tombstone);\n return { ok: true, value: await reader() };\n }\n\n /** Apply an event and capture all retention metadata in the same transaction. */\n async applyEvent(request: ApplyEventRequest): Promise<ApplyEventOutcome> {\n await this.ensureSchema();\n return await this.ctx.storage.transaction(async (txn) => {\n const now = new Date(this.now());\n const tombstone = await this.expiredTombstone(txn, now.getTime());\n if (tombstone) {\n return {\n ok: false,\n code: 'RUN_EXPIRED',\n message: `Workflow run \"${request.runId}\" expired at ${tombstone.expiredAt.toISOString()}`,\n };\n }\n\n let eventSequence = (await txn.get<number>('event_sequence')) ?? 0;\n const outcome = await applyEvent(storeFrom(txn), {\n ...request,\n nextEventId: () => `wevt_z${String(++eventSequence).padStart(20, '0')}`,\n now,\n });\n if (!outcome.ok) return outcome;\n\n await txn.put('event_sequence', eventSequence);\n if (outcome.event?.correlationId) {\n const key = correlationIndexKey(\n outcome.event.correlationId,\n outcome.event.createdAt,\n outcome.event.eventId,\n request.runId,\n );\n await txn.put(indexMarkerKey(key), key);\n }\n if (outcome.hookToIndex) {\n const reference = {\n hookId: outcome.hookToIndex.hookId,\n token: outcome.hookToIndex.token,\n };\n await txn.put(hookMarkerKey(reference), reference);\n }\n for (const reference of outcome.releasedHooks) {\n await txn.put(hookMarkerKey(reference), reference);\n }\n\n const retentionMs = request.cleanup?.retentionMs ?? 0;\n if (\n retentionMs > 0 &&\n outcome.run &&\n isTerminalWorkflowRunStatus(outcome.run.status) &&\n !(await txn.get<CleanupRecord>(CLEANUP_RECORD_KEY))\n ) {\n const terminalRun = outcome.run as TerminalRun;\n const dueAt = new Date(terminalRun.completedAt.getTime() + retentionMs);\n const run = WorkflowRunSchema.parse({ ...terminalRun, expiredAt: dueAt }) as TerminalRun;\n const cleanup: CleanupRecord = {\n version: 1,\n runId: run.runId,\n workflowName: run.workflowName,\n createdAt: run.createdAt,\n completedAt: run.completedAt,\n terminalStatus: run.status,\n dueAt,\n queueShards: request.cleanup?.queueShards ?? 1,\n phase: 'retained',\n attempts: 0,\n deletedPayloadKeys: 0,\n deletedStreams: 0,\n deletedQueueMessages: 0,\n };\n await txn.put('run', run);\n await txn.put(CLEANUP_RECORD_KEY, cleanup);\n await txn.setAlarm(dueAt);\n outcome.run = run;\n }\n return outcome;\n });\n }\n\n async getRun(): Promise<RunReadOutcome<WorkflowRun | null>> {\n return this.read(async () => (await this.ctx.storage.get<WorkflowRun>('run')) ?? null);\n }\n\n async getStep(stepId: string): Promise<RunReadOutcome<Step | null>> {\n return this.read(\n async () => (await this.ctx.storage.get<Step>(`${STEP_KEY_PREFIX}${stepId}`)) ?? null,\n );\n }\n\n async listSteps(params?: {\n limit?: number;\n cursor?: string;\n sortOrder?: 'asc' | 'desc';\n }): Promise<RunReadOutcome<{ data: Step[]; cursor: string | null; hasMore: boolean }>> {\n return this.read(() =>\n listByCreationTime<Step>(\n storeFrom(this.ctx.storage),\n STEP_CREATED_KEY_PREFIX,\n STEP_KEY_PREFIX,\n {\n limit: params?.limit ?? 20,\n cursor: params?.cursor,\n sortOrder: params?.sortOrder ?? 'asc',\n },\n ),\n );\n }\n\n async getEvent(eventId: string): Promise<RunReadOutcome<Event | null>> {\n return this.read(\n async () => (await this.ctx.storage.get<Event>(`${EVENT_KEY_PREFIX}${eventId}`)) ?? null,\n );\n }\n\n async listEvents(params?: {\n limit?: number;\n cursor?: string;\n sortOrder?: 'asc' | 'desc';\n }): Promise<RunReadOutcome<{ data: Event[]; cursor: string | null; hasMore: boolean }>> {\n return this.read(() =>\n listByPrefix<Event>(\n storeFrom(this.ctx.storage),\n EVENT_KEY_PREFIX,\n {\n limit: params?.limit ?? 100,\n cursor: params?.cursor,\n sortOrder: params?.sortOrder ?? 'asc',\n },\n (event) => event.eventId,\n ),\n );\n }\n\n async listHooks(params?: {\n limit?: number;\n cursor?: string;\n sortOrder?: 'asc' | 'desc';\n }): Promise<RunReadOutcome<{ data: Hook[]; cursor: string | null; hasMore: boolean }>> {\n return this.read(() =>\n listByCreationTime<Hook>(\n storeFrom(this.ctx.storage),\n HOOK_CREATED_KEY_PREFIX,\n HOOK_KEY_PREFIX,\n {\n limit: params?.limit ?? 100,\n cursor: params?.cursor,\n sortOrder: params?.sortOrder ?? 'asc',\n },\n ),\n );\n }\n\n async getCleanupStatus(): Promise<CleanupRecord | null> {\n await this.ensureSchema();\n return (await this.ctx.storage.get<CleanupRecord>(CLEANUP_RECORD_KEY)) ?? null;\n }\n\n /** Explicitly schedule an existing terminal run, used for opt-in backfills. */\n async scheduleCleanup(request: ScheduleCleanupRequest): Promise<CleanupRecord | null> {\n await this.ensureSchema();\n if (request.retentionMs <= 0) return this.getCleanupStatus();\n return await this.ctx.storage.transaction(async (txn) => {\n const existing = await txn.get<CleanupRecord>(CLEANUP_RECORD_KEY);\n if (existing) return existing;\n if (await txn.get<RunTombstone>(TOMBSTONE_KEY)) return null;\n const current = await txn.get<WorkflowRun>('run');\n if (!current || !isTerminalWorkflowRunStatus(current.status)) return null;\n const terminalRun = current as TerminalRun;\n const dueAt = new Date(terminalRun.completedAt.getTime() + request.retentionMs);\n const run = WorkflowRunSchema.parse({ ...terminalRun, expiredAt: dueAt }) as TerminalRun;\n const cleanup: CleanupRecord = {\n version: 1,\n runId: run.runId,\n workflowName: run.workflowName,\n createdAt: run.createdAt,\n completedAt: run.completedAt,\n terminalStatus: run.status,\n dueAt,\n queueShards: request.queueShards,\n phase: 'retained',\n attempts: 0,\n deletedPayloadKeys: 0,\n deletedStreams: 0,\n deletedQueueMessages: 0,\n };\n await txn.put('run', run);\n await txn.put(CLEANUP_RECORD_KEY, cleanup);\n await txn.setAlarm(dueAt.getTime() <= this.now() ? this.now() + 1 : dueAt);\n return cleanup;\n });\n }\n\n async cleanupNow(request: ScheduleCleanupRequest): Promise<CleanupRecord | null> {\n await this.ensureSchema();\n if (!(await this.ctx.storage.get<CleanupRecord>(CLEANUP_RECORD_KEY))) {\n await this.scheduleCleanup({ ...request, retentionMs: Math.max(1, request.retentionMs) });\n }\n await this.ctx.storage.transaction(async (txn) => {\n const cleanup = await txn.get<CleanupRecord>(CLEANUP_RECORD_KEY);\n if (!cleanup || cleanup.phase === 'tombstoned') return;\n const dueAt = new Date(this.now());\n const run = await txn.get<WorkflowRun>('run');\n if (run) await txn.put('run', WorkflowRunSchema.parse({ ...run, expiredAt: dueAt }));\n await txn.put(CLEANUP_RECORD_KEY, { ...cleanup, dueAt });\n await txn.setAlarm(this.now() + 1);\n });\n try {\n await this.executeCleanup();\n } catch (error) {\n await this.recordCleanupFailure(error);\n }\n return this.getCleanupStatus();\n }\n\n async rearmCleanup(): Promise<CleanupRecord | null> {\n await this.ensureSchema();\n const cleanup = await this.ctx.storage.get<CleanupRecord>(CLEANUP_RECORD_KEY);\n if (!cleanup) return null;\n if (cleanup.phase === 'tombstoned') {\n await this.ctx.storage.deleteAlarm();\n } else {\n await this.ctx.storage.setAlarm(Math.max(this.now() + 1, cleanup.dueAt.getTime()));\n }\n return cleanup;\n }\n\n async alarm(): Promise<void> {\n await this.ensureSchema();\n try {\n await this.executeCleanup();\n } catch (error) {\n await this.recordCleanupFailure(error);\n }\n }\n\n private namespace<T>(name: keyof WorkflowRunDOEnv): CellNamespace<T> {\n const namespace = (this.env as WorkflowRunDOEnv)?.[name];\n if (!namespace || typeof namespace === 'function') {\n throw new Error(`world-celld retention missing binding ${name}`);\n }\n return namespace as CellNamespace<T>;\n }\n\n private async setCleanupPhase(\n expected: CleanupRecord['phase'],\n next: CleanupRecord['phase'],\n updates: Partial<CleanupRecord> = {},\n ): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n const cleanup = await txn.get<CleanupRecord>(CLEANUP_RECORD_KEY);\n if (!cleanup || cleanup.phase !== expected) return;\n await txn.put(CLEANUP_RECORD_KEY, {\n ...cleanup,\n ...updates,\n phase: next,\n attempts: 0,\n lastError: undefined,\n });\n });\n }\n\n private async executeCleanup(): Promise<void> {\n for (;;) {\n const cleanup = await this.ctx.storage.get<CleanupRecord>(CLEANUP_RECORD_KEY);\n if (!cleanup) {\n await this.ctx.storage.deleteAlarm();\n return;\n }\n if (cleanup.phase === 'tombstoned') {\n await this.ctx.storage.deleteAlarm();\n return;\n }\n if (cleanup.phase === 'retained') {\n if (cleanup.dueAt.getTime() > this.now()) {\n await this.ctx.storage.setAlarm(cleanup.dueAt);\n return;\n }\n await this.setCleanupPhase('retained', 'index');\n continue;\n }\n\n if (cleanup.phase === 'index') {\n const [indexMarkers, hookMarkers] = await Promise.all([\n this.ctx.storage.list<string>({ prefix: INDEX_MARKER_PREFIX }),\n this.ctx.storage.list<HookIndexReference>({ prefix: HOOK_MARKER_PREFIX }),\n ]);\n const indexNamespace = this.namespace<IndexCleanupStub>('WORKFLOW_INDEX');\n const index = indexNamespace.get(indexNamespace.idFromName('index'));\n await index.expireRun({\n runId: cleanup.runId,\n keys: [\n workflowRunIndexKey(cleanup),\n globalRunIndexKey(cleanup),\n ...indexMarkers.values(),\n ],\n hooks: Array.from(hookMarkers.values()),\n expiredAt: cleanup.dueAt.getTime(),\n });\n await this.setCleanupPhase('index', 'streams');\n continue;\n }\n\n if (cleanup.phase === 'streams') {\n const streamsNamespace = this.namespace<StreamCleanupStub>('WORKFLOW_STREAMS');\n const registry = streamsNamespace.get(\n streamsNamespace.idFromName(`run-streams:${cleanup.runId}`),\n );\n const { streams } = await registry.expireRegistry(cleanup.runId, cleanup.dueAt.getTime());\n let deletedStreams = streams.length === 0 ? cleanup.deletedStreams : 0;\n for (let offset = 0; offset < streams.length; offset += STREAM_DELETE_CONCURRENCY) {\n const batch = streams.slice(offset, offset + STREAM_DELETE_CONCURRENCY);\n const results = await Promise.all(\n batch.map((name) => {\n const stream = streamsNamespace.get(streamsNamespace.idFromName(`stream:${name}`));\n return stream.expireStream(cleanup.runId, cleanup.dueAt.getTime());\n }),\n );\n deletedStreams += results.filter((result) => result.deleted).length;\n }\n await this.ctx.storage.transaction(async (txn) => {\n const current = await txn.get<CleanupRecord>(CLEANUP_RECORD_KEY);\n if (current?.phase === 'streams') {\n await txn.put(CLEANUP_RECORD_KEY, { ...current, deletedStreams });\n }\n });\n await registry.finalizeRegistry(cleanup.runId);\n await this.setCleanupPhase('streams', 'queues');\n continue;\n }\n\n if (cleanup.phase === 'queues') {\n const queues = this.namespace<QueueCleanupStub>('WORKFLOW_QUEUE');\n let deletedQueueMessages = 0;\n for (let shard = 0; shard < cleanup.queueShards; shard++) {\n const queue = queues.get(queues.idFromName(`q:${shard}`));\n const result = await queue.expireRun(cleanup.runId, cleanup.dueAt.getTime());\n deletedQueueMessages += result.deleted;\n }\n await this.setCleanupPhase('queues', 'payload', { deletedQueueMessages });\n continue;\n }\n\n if (cleanup.phase === 'payload') {\n const finished = await this.deletePayloadBatch();\n if (!finished) return;\n }\n }\n }\n\n private async deletePayloadBatch(): Promise<boolean> {\n return await this.ctx.storage.transaction(async (txn) => {\n const cleanup = await txn.get<CleanupRecord>(CLEANUP_RECORD_KEY);\n if (!cleanup || cleanup.phase !== 'payload') return true;\n const entries = await txn.list({ limit: PAYLOAD_DELETE_BATCH + 3 });\n const keys = Array.from(entries.keys())\n .filter(\n (key) => key !== CLEANUP_RECORD_KEY && key !== TOMBSTONE_KEY && key !== 'schema_version',\n )\n .slice(0, PAYLOAD_DELETE_BATCH);\n const now = new Date(this.now());\n await txn.put(TOMBSTONE_KEY, cleanupTombstone(cleanup, now));\n for (const key of keys) await txn.delete(key);\n\n if (keys.length > 0) {\n await txn.put(CLEANUP_RECORD_KEY, {\n ...cleanup,\n deletedPayloadKeys: cleanup.deletedPayloadKeys + keys.length,\n lastError: undefined,\n });\n await txn.setAlarm(this.now() + 1);\n return false;\n }\n\n await txn.put(CLEANUP_RECORD_KEY, {\n ...cleanup,\n phase: 'tombstoned',\n attempts: 0,\n lastError: undefined,\n tombstonedAt: now,\n });\n await txn.deleteAlarm();\n return true;\n });\n }\n\n private async recordCleanupFailure(error: unknown): Promise<void> {\n await this.ctx.storage.transaction(async (txn) => {\n const cleanup = await txn.get<CleanupRecord>(CLEANUP_RECORD_KEY);\n if (!cleanup || cleanup.phase === 'tombstoned') return;\n const attempts = cleanup.attempts + 1;\n const delay = Math.min(CLEANUP_RETRY_MAX_MS, 1000 * 2 ** Math.min(attempts - 1, 12));\n await txn.put(CLEANUP_RECORD_KEY, {\n ...cleanup,\n attempts,\n lastError: error instanceof Error ? error.message : String(error),\n lastAttemptAt: new Date(this.now()),\n });\n await txn.setAlarm(this.now() + delay);\n });\n }\n\n async claimInflight(params: {\n messageId: string;\n staleMs: number;\n }): Promise<{ claimed: boolean }> {\n await this.ensureSchema();\n return await this.ctx.storage.transaction(async (txn) => {\n const existing = await txn.get<InflightClaim>('claim');\n const now = this.now();\n if (\n existing &&\n existing.messageId !== params.messageId &&\n now - existing.claimedAt < params.staleMs\n ) {\n return { claimed: false };\n }\n await txn.put<InflightClaim>('claim', { messageId: params.messageId, claimedAt: now });\n return { claimed: true };\n });\n }\n\n async releaseInflight(): Promise<void> {\n await this.ensureSchema();\n await this.ctx.storage.delete('claim');\n }\n}\n","/**\n * celld worker entry: exports the Durable Object (cell) classes and the\n * default fetch router. This module (and everything it imports) must stay\n * free of Node built-ins — it runs inside celld's workerd runtime.\n */\nimport { createRouter, type WorkerEnv } from './router.js';\n\nexport { IndexDO } from './durable-objects/IndexDO.js';\nexport { QueueDO } from './durable-objects/QueueDO.js';\nexport { StreamDO } from './durable-objects/StreamDO.js';\nexport { WorkflowRunDO } from './durable-objects/WorkflowRunDO.js';\nexport { createRouter, type WorkerEnv } from './router.js';\n\nexport default {\n async fetch(request: Request, env: WorkerEnv): Promise<Response> {\n return createRouter(env)(request);\n },\n};\n"],"mappings":"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"}