iterate 0.3.0 → 0.4.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.
- package/README.md +164 -82
- package/dist/{next/api.d.ts → api.d.ts} +197 -33
- package/dist/{next/app-server.d.ts → app-server.d.ts} +7 -0
- package/dist/{next/app-server.mjs → app-server.mjs} +17 -15
- package/dist/app-server.mjs.map +1 -0
- package/dist/{next/app-session.mjs → app-session.mjs} +12 -15
- package/dist/app-session.mjs.map +1 -0
- package/dist/{next/app.mjs → app.mjs} +53 -14
- package/dist/app.mjs.map +1 -0
- package/dist/{next/client → client}/live-state.d.ts +11 -11
- package/dist/client/oauth.d.ts +17 -0
- package/dist/{next/client → client}/react.d.ts +10 -42
- package/dist/{next/client → client}/socket.d.ts +1 -0
- package/dist/client.mjs +156 -4
- package/dist/client.mjs.map +1 -0
- package/dist/{next/expression.d.ts → expression.d.ts} +11 -69
- package/dist/{next/expression.mjs → expression.mjs} +11 -109
- package/dist/expression.mjs.map +1 -0
- package/dist/lib-BWr-5mFO.mjs +36 -0
- package/dist/lib-BWr-5mFO.mjs.map +1 -0
- package/dist/{next/lib.d.ts → lib.d.ts} +16 -2
- package/dist/{next/lib.mjs → lib.mjs} +32 -3
- package/dist/lib.mjs.map +1 -0
- package/dist/node.d.ts +15 -3
- package/dist/node.mjs +36 -174
- package/dist/node.mjs.map +1 -1
- package/dist/{next/oauth-scopes.mjs → oauth-scopes.mjs} +1 -1
- package/dist/oauth-scopes.mjs.map +1 -0
- package/dist/{next/oauth.mjs → oauth.mjs} +14 -2
- package/dist/oauth.mjs.map +1 -0
- package/dist/principal.d.ts +8 -0
- package/dist/principal.mjs +8 -0
- package/dist/principal.mjs.map +1 -0
- package/dist/project-ingress.d.ts +58 -0
- package/dist/project-ingress.mjs +104 -0
- package/dist/project-ingress.mjs.map +1 -0
- package/dist/{next/react.mjs → react.mjs} +12 -12
- package/dist/react.mjs.map +1 -0
- package/dist/sdk/auth.d.ts +25 -0
- package/dist/sdk/index.d.ts +155 -0
- package/dist/sdk/record-pipelined-steps.d.ts +19 -0
- package/dist/sdk.mjs +245 -2
- package/dist/sdk.mjs.map +1 -0
- package/dist/{next/stream → stream}/processor.d.ts +28 -23
- package/dist/{next/stream → stream}/processor.mjs +48 -25
- package/dist/stream/processor.mjs.map +1 -0
- package/dist/{next/stream → stream}/run.d.ts +9 -6
- package/dist/{next/stream → stream}/run.mjs +13 -8
- package/dist/stream/run.mjs.map +1 -0
- package/dist/stream/test-support.d.ts +45 -0
- package/dist/stream/test-support.mjs +196 -0
- package/dist/stream/test-support.mjs.map +1 -0
- package/package.json +65 -219
- package/THIRD_PARTY_NOTICES.md +0 -55
- package/bin/iterate.js +0 -94
- package/dist/api-url-B6404M82.mjs +0 -17
- package/dist/api-url-B6404M82.mjs.map +0 -1
- package/dist/app-ref-BipL0feU.mjs +0 -35
- package/dist/app-ref-BipL0feU.mjs.map +0 -1
- package/dist/app-ref-C1CrgXqX.mjs +0 -7
- package/dist/app-ref-C1CrgXqX.mjs.map +0 -1
- package/dist/app-ref-DYai_om1.mjs +0 -7
- package/dist/app-ref-DYai_om1.mjs.map +0 -1
- package/dist/cli-D0c-pDL_.mjs +0 -1010
- package/dist/cli-D0c-pDL_.mjs.map +0 -1
- package/dist/client.d.ts +0 -3
- package/dist/cloudflare-BTm90gQ4.mjs +0 -951
- package/dist/cloudflare-BTm90gQ4.mjs.map +0 -1
- package/dist/contract-s4FW4eES.mjs +0 -309
- package/dist/contract-s4FW4eES.mjs.map +0 -1
- package/dist/document-review/index.d.ts +0 -5
- package/dist/document-review/types.d.ts +0 -107
- package/dist/document-review.mjs +0 -7015
- package/dist/document-review.mjs.map +0 -1
- package/dist/durable-object-processor-durability-CNsTjAJS.mjs +0 -205
- package/dist/durable-object-processor-durability-CNsTjAJS.mjs.map +0 -1
- package/dist/idempotency-DleloJNt.mjs +0 -28
- package/dist/idempotency-DleloJNt.mjs.map +0 -1
- package/dist/index.d.mts +0 -5
- package/dist/index.mjs +0 -8
- package/dist/index.mjs.map +0 -1
- package/dist/itx/api-url.d.ts +0 -6
- package/dist/itx/itx-node-client.d.ts +0 -65
- package/dist/itx/itx-session.d.ts +0 -215
- package/dist/itx/owned-rpc-session.d.ts +0 -14
- package/dist/itx/query-client.d.ts +0 -10
- package/dist/itx-api.generated.d.ts +0 -6195
- package/dist/itx-session-sjud8GiT.mjs +0 -534
- package/dist/itx-session-sjud8GiT.mjs.map +0 -1
- package/dist/live-state-BJNqOwFw.mjs +0 -299
- package/dist/live-state-BJNqOwFw.mjs.map +0 -1
- package/dist/next/app-server.mjs.map +0 -1
- package/dist/next/app-session.mjs.map +0 -1
- package/dist/next/app.mjs.map +0 -1
- package/dist/next/client/oauth.d.ts +0 -12
- package/dist/next/client.mjs +0 -156
- package/dist/next/client.mjs.map +0 -1
- package/dist/next/expression.mjs.map +0 -1
- package/dist/next/lib.mjs.map +0 -1
- package/dist/next/oauth-scopes.mjs.map +0 -1
- package/dist/next/oauth.mjs.map +0 -1
- package/dist/next/principal.d.ts +0 -64
- package/dist/next/principal.mjs +0 -98
- package/dist/next/principal.mjs.map +0 -1
- package/dist/next/project-ingress.d.ts +0 -37
- package/dist/next/project-ingress.mjs +0 -75
- package/dist/next/project-ingress.mjs.map +0 -1
- package/dist/next/react.mjs.map +0 -1
- package/dist/next/sdk/auth.d.ts +0 -5
- package/dist/next/sdk/index.d.ts +0 -112
- package/dist/next/sdk.mjs +0 -139
- package/dist/next/sdk.mjs.map +0 -1
- package/dist/next/stream/processor.mjs.map +0 -1
- package/dist/next/stream/run.mjs.map +0 -1
- package/dist/next-node.d.ts +0 -15
- package/dist/next-node.mjs +0 -51
- package/dist/next-node.mjs.map +0 -1
- package/dist/processor-host-capabilities-BMFH3KTM.mjs +0 -56
- package/dist/processor-host-capabilities-BMFH3KTM.mjs.map +0 -1
- package/dist/processors/cloudflare.d.ts +0 -3
- package/dist/processors/durable-object-processor-durability.d.ts +0 -79
- package/dist/processors/event-consumption-metrics.d.ts +0 -82
- package/dist/processors/idempotency.d.ts +0 -13
- package/dist/processors/index.d.ts +0 -12
- package/dist/processors/processor-contracts.d.ts +0 -342
- package/dist/processors/processor-facet.d.ts +0 -186
- package/dist/processors/processor-host-capabilities.d.ts +0 -60
- package/dist/processors/prompt-sections.d.ts +0 -17
- package/dist/processors/rpc-types.d.ts +0 -515
- package/dist/processors/schemas.d.ts +0 -102
- package/dist/processors/stream-handle.d.ts +0 -45
- package/dist/processors/stream-processor-keepalive.d.ts +0 -95
- package/dist/processors/stream-processor-registry.d.ts +0 -233
- package/dist/processors/stream-processor-runner.d.ts +0 -289
- package/dist/processors/stream-processor.d.ts +0 -339
- package/dist/processors/stream-runtime-metrics.d.ts +0 -107
- package/dist/processors/testing.d.ts +0 -302
- package/dist/processors-BoNyeBfQ.mjs +0 -10
- package/dist/processors-BoNyeBfQ.mjs.map +0 -1
- package/dist/processors-cloudflare.mjs +0 -3
- package/dist/processors-testing.mjs +0 -435
- package/dist/processors-testing.mjs.map +0 -1
- package/dist/processors.mjs +0 -52
- package/dist/processors.mjs.map +0 -1
- package/dist/protocol-DnK_f2m6.mjs +0 -251
- package/dist/protocol-DnK_f2m6.mjs.map +0 -1
- package/dist/sdk/capnweb/index.d.ts +0 -2
- package/dist/sdk/capnweb/live-state/compact.d.ts +0 -5
- package/dist/sdk/capnweb/live-state/diff.d.ts +0 -41
- package/dist/sdk/capnweb/live-state/engine.d.ts +0 -44
- package/dist/sdk/capnweb/live-state/index.d.ts +0 -41
- package/dist/sdk/capnweb/live-state/protocol.d.ts +0 -87
- package/dist/sdk/capnweb/live-state/retain.d.ts +0 -23
- package/dist/sdk/capnweb/live-state/store.d.ts +0 -20
- package/dist/sdk/capnweb/live-state/types.d.ts +0 -11
- package/dist/sdk/capnweb/react.d.ts +0 -45
- package/dist/sdk/capnweb/react.mjs +0 -316
- package/dist/sdk/capnweb/react.mjs.map +0 -1
- package/dist/sdk/capnweb.mjs +0 -4
- package/dist/sdk/itx/react.d.ts +0 -191
- package/dist/sdk/itx/react.mjs +0 -383
- package/dist/sdk/itx/react.mjs.map +0 -1
- package/dist/sdk-DMB-IM11.mjs +0 -933
- package/dist/sdk-DMB-IM11.mjs.map +0 -1
- package/dist/sdk.d.ts +0 -339
- package/dist/serve-itx.d.ts +0 -46
- package/dist/starter-apps/flake-dashboard/app-ref.d.ts +0 -31
- package/dist/starter-apps/flake-dashboard/configured-worker.mjs +0 -1055
- package/dist/starter-apps/flake-dashboard/configured-worker.mjs.map +0 -1
- package/dist/starter-apps/flake-dashboard/contract.d.ts +0 -4839
- package/dist/starter-apps/flake-dashboard/contract.mjs +0 -2
- package/dist/starter-apps/flake-dashboard/index.d.ts +0 -17
- package/dist/starter-apps/flake-dashboard/index.mjs +0 -56
- package/dist/starter-apps/flake-dashboard/index.mjs.map +0 -1
- package/dist/starter-apps/flake-dashboard/worker.d.ts +0 -4607
- package/dist/starter-apps/github-ai-linter/ai-linter.d.ts +0 -8914
- package/dist/starter-apps/github-ai-linter/configured-worker.mjs +0 -17987
- package/dist/starter-apps/github-ai-linter/configured-worker.mjs.map +0 -1
- package/dist/starter-apps/github-ai-linter/contract.d.ts +0 -9193
- package/dist/starter-apps/github-ai-linter/index.d.ts +0 -10
- package/dist/starter-apps/github-ai-linter/index.mjs +0 -36
- package/dist/starter-apps/github-ai-linter/index.mjs.map +0 -1
- package/dist/starter-apps/github-ai-linter/prompt.d.ts +0 -13
- package/dist/starter-apps/github-ai-linter/review-bot.d.ts +0 -808
- package/dist/starter-apps/github-ai-linter/rules.d.ts +0 -34
- package/dist/starter-apps/github-ai-linter/worker-ref.d.ts +0 -19
- package/dist/starter-apps/github-ai-linter/worker.d.ts +0 -19
- package/dist/starter-apps/github-ai-linter/worker.mjs +0 -947
- package/dist/starter-apps/github-ai-linter/worker.mjs.map +0 -1
- package/dist/starter-apps/guestbook/app-ref.d.ts +0 -27
- package/dist/starter-apps/guestbook/client.d.ts +0 -7
- package/dist/starter-apps/guestbook/client.mjs +0 -59
- package/dist/starter-apps/guestbook/configured-worker.mjs +0 -205
- package/dist/starter-apps/guestbook/configured-worker.mjs.map +0 -1
- package/dist/starter-apps/guestbook/index.d.ts +0 -9
- package/dist/starter-apps/guestbook/index.mjs +0 -31
- package/dist/starter-apps/guestbook/index.mjs.map +0 -1
- package/dist/starter-apps/guestbook/processor.d.ts +0 -2267
- package/dist/starter-apps/guestbook/worker.d.ts +0 -26
- package/dist/starter-apps/guestbook/worker.mjs +0 -191
- package/dist/starter-apps/guestbook/worker.mjs.map +0 -1
- package/dist/starter-apps/media/configured-worker.mjs +0 -577
- package/dist/starter-apps/media/configured-worker.mjs.map +0 -1
- package/dist/starter-apps/media/index.mjs +0 -36
- package/dist/starter-apps/media/index.mjs.map +0 -1
- package/dist/starter-apps/media/ref.mjs +0 -20
- package/dist/starter-apps/media/ref.mjs.map +0 -1
- package/dist/starter-apps/media/worker.mjs +0 -579
- package/dist/starter-apps/media/worker.mjs.map +0 -1
- package/dist/starter-apps/notes/configured-worker.mjs +0 -6134
- package/dist/starter-apps/notes/configured-worker.mjs.map +0 -1
- package/dist/starter-apps/notes/index.mjs +0 -23
- package/dist/starter-apps/notes/index.mjs.map +0 -1
- package/dist/starter-apps/notes/ref.mjs +0 -21
- package/dist/starter-apps/notes/ref.mjs.map +0 -1
- package/dist/starter-apps/notes/worker.mjs +0 -427
- package/dist/starter-apps/notes/worker.mjs.map +0 -1
- package/dist/starter-apps/todo/client.mjs +0 -59
- package/dist/starter-apps/todo/configured-worker.mjs +0 -2864
- package/dist/starter-apps/todo/configured-worker.mjs.map +0 -1
- package/dist/starter-apps/todo/index.d.ts +0 -8
- package/dist/starter-apps/todo/index.mjs +0 -29
- package/dist/starter-apps/todo/index.mjs.map +0 -1
- package/dist/stream-processor-keepalive-DAQTP6m3.mjs +0 -2082
- package/dist/stream-processor-keepalive-DAQTP6m3.mjs.map +0 -1
- package/dist/usingCtx-mZx5nsAW.mjs +0 -11800
- package/dist/usingCtx-mZx5nsAW.mjs.map +0 -1
- package/dist/worker-ref-DZxPDmb_.mjs +0 -390
- package/dist/worker-ref-DZxPDmb_.mjs.map +0 -1
- package/dist/worker.d.mts +0 -33
- package/dist/worker.mjs +0 -18
- package/dist/worker.mjs.map +0 -1
- package/menubar/Iterate.entitlements +0 -12
- package/menubar/Iterate.swift +0 -914
- package/menubar/IterateIcon.swift +0 -145
- package/menubar/README.md +0 -28
- package/menubar/build-menubar-app.sh +0 -59
- /package/dist/{next/api.mjs → api.mjs} +0 -0
- /package/dist/{next/app-session.d.ts → app-session.d.ts} +0 -0
- /package/dist/{next/app.d.ts → app.d.ts} +0 -0
- /package/dist/{next/oauth-scopes.d.ts → oauth-scopes.d.ts} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare-BTm90gQ4.mjs","names":["#epoch","#subscribers","#debounceMs","#current","#broadcast","#flushTimer","#flush","#revision","#lastUpdate","#lastCompactUpdate","#scheduleFlush","#drop","#deliver","#sendLatest","#readIdentity","#requireHost","#reads","#host","#requireIdentity"],"sources":["../src/sdk/capnweb/live-state/retain.ts","../src/sdk/capnweb/live-state/diff.ts","../src/sdk/capnweb/live-state/compact.ts","../src/sdk/capnweb/live-state/engine.ts","../src/processors/stream-processor-registry.ts","../src/processors/processor-facet.ts"],"sourcesContent":["// Canonical retention for RPC callback stubs — the one place that knows a sink\n// might be a remote Cap'n Web / Workers RPC stub rather than a local function.\n//\n// A \"sink\" is a callback the server keeps calling AFTER the RPC method that\n// carried it returned (a live subscription's push). Retaining it means: dup the\n// underlying stub while the transport supports it, and dispose the dup on close.\n// Stream event delivery and the live-state engine both build on these primitives\n// instead of re-deriving the transport dance.\n\n/** An RPC callback after retention: still callable, plus disposable and (best-effort) broken-transport aware. */\nexport type RetainedCallback<Arg> = ((arg: Arg) => unknown) &\n Disposable & { onRpcBroken?(handler: (error: unknown) => void): void };\n\n/**\n * Retain a single-argument RPC callback so it survives past the call that\n * carried it. `dup()` duplicates the underlying remote stub (that dup is what\n * `[Symbol.dispose]` releases); `onRpcBroken` is forwarded defensively — Cap'n\n * Web stubs expose no own property descriptors and a Workers RPC property access\n * can fabricate a pipelined method that rejects at call time, so we wire whatever\n * the stub claims and swallow registration failures. `onRpcBroken` is only a\n * prompt hint; callers that need a terminal verdict must model one explicitly\n * (for example, the durable wake lane's independent settlement capability).\n */\nexport function retainCallback<Arg>(callback: (arg: Arg) => unknown): RetainedCallback<Arg> {\n const retainable = callback as ((arg: Arg) => unknown) &\n Partial<Disposable> & {\n dup?(): (arg: Arg) => unknown;\n onRpcBroken?(handler: (error: unknown) => void): void;\n };\n const retained = (retainable.dup?.() ?? retainable) as typeof retainable;\n const dispose = retained[Symbol.dispose]?.bind(retained);\n // Idempotent by contract: owners often dispose from several paths (engine\n // drop + connection teardown), and a double release of the underlying dup\n // would free someone else's reference.\n let disposed = false;\n const wrapped = Object.assign((arg: Arg) => retained(arg), {\n [Symbol.dispose]() {\n if (disposed) return;\n disposed = true;\n dispose?.();\n },\n }) as RetainedCallback<Arg>;\n const onRpcBroken = retained.onRpcBroken;\n if (typeof onRpcBroken === \"function\") {\n wrapped.onRpcBroken = (handler: (error: unknown) => void) => {\n try {\n const result = onRpcBroken.call(retained, handler);\n if (isThenable(result)) void Promise.resolve(result).catch(() => {});\n } catch {\n // Registration is best-effort.\n }\n };\n }\n return wrapped;\n}\n\n/** Thenable probe: RPC stubs and their call results are thenable-shaped. */\nexport function isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n value !== null &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n typeof (value as PromiseLike<unknown>).then === \"function\"\n );\n}\n\n/**\n * Dispose the result of an RPC call whose value the caller ignores. Reading a\n * Cap'n Web / Workers RPC method yields a disposable stub even when unused, and\n * dropping it without disposal leaks the remote reference.\n */\nexport function disposeIgnoredRpcResult(result: unknown): void {\n if (\n result !== null &&\n (typeof result === \"object\" || typeof result === \"function\") &&\n Symbol.dispose in result\n ) {\n (result as Disposable)[Symbol.dispose]();\n }\n}\n","import type { LiveStatePatch } from \"./protocol.ts\";\n\n/**\n * Structural diff between two JSON values, producing the minimal `LiveStatePatch`\n * — or `undefined` when nothing changed.\n *\n * The diff is REFERENCE-FIRST: identical references short-circuit immediately\n * (`Object.is`), so the cost is O(changed), not O(size) — *as long as callers\n * update state immutably* (unchanged sub-objects keep their identity). That one\n * discipline is the whole performance story: a single touched row in a\n * thousand-entry index yields one tiny patch instead of a full rescan.\n *\n * PLAIN objects (prototype `Object.prototype` or `null`) are treated as keyed\n * maps and diffed per key. Dense arrays are diffed by position. Everything\n * else — primitives, `null`, sparse arrays, and\n * non-plain instances like `Date`/`Map`/`Set` — is a leaf, replaced wholesale.\n * Descending into an instance would diff its own enumerable keys, which for a\n * `Date` is NONE — two different Dates would read as \"unchanged\" and the\n * subscriber would stay stale forever. Keyed objects remain preferable for\n * collections whose entries frequently move; positional patches do not infer moves.\n */\nexport function diff(\n prev: unknown,\n next: unknown,\n options: { arrays?: boolean } = {},\n): LiveStatePatch | undefined {\n if (Object.is(prev, next)) return undefined;\n if (Array.isArray(prev) && Array.isArray(next) && options.arrays !== false) {\n const items: [number, LiveStatePatch][] = [];\n for (let index = 0; index < next.length; index++) {\n // Sparse arrays retain the replacement semantics of their wire value.\n if (!Object.hasOwn(next, index) || (index < prev.length && !Object.hasOwn(prev, index))) {\n return { set: next };\n }\n const patch =\n index < prev.length ? diff(prev[index], next[index], options) : { set: next[index] };\n if (patch) items.push([index, patch]);\n }\n return items.length > 0 || prev.length !== next.length\n ? { array: { length: next.length, items } }\n : undefined;\n }\n if (!isPlainObject(prev) || !isPlainObject(next)) return { set: next };\n\n // Entries + fromEntries, not `bag[key] = …`: assignment with key \"__proto__\"\n // would SET THE BAG'S PROTOTYPE instead of recording the field — the change\n // would silently vanish from the patch. `Object.fromEntries` DEFINES own\n // properties (safe for any key) and yields an ordinary Object.prototype\n // object — which matters, because patches cross capnweb, whose serializer\n // accepts exactly Object.prototype (a null-proto bag reads as unsupported\n // and kills the push). (applyPatch has the mirror-image write guard.)\n // Own-property checks throughout (`Object.hasOwn`, not `in` / bare reads):\n // `\"__proto__\" in x` is true for EVERY object via inheritance, so `in` would\n // misread that key's presence in both directions.\n const fields: [string, LiveStatePatch][] = [];\n const drop: string[] = [];\n for (const key of Object.keys(next)) {\n if (next[key] === undefined) {\n if (Object.hasOwn(prev, key)) drop.push(key); // a key set to `undefined` reads as removed\n continue;\n }\n const childPatch = diff(Object.hasOwn(prev, key) ? prev[key] : undefined, next[key], options);\n if (childPatch !== undefined) fields.push([key, childPatch]);\n }\n for (const key of Object.keys(prev)) {\n if (!Object.hasOwn(next, key)) drop.push(key);\n }\n\n if (fields.length === 0 && drop.length === 0) return undefined;\n const patch: { fields?: Record<string, LiveStatePatch>; drop?: string[] } = {};\n if (fields.length > 0) patch.fields = Object.fromEntries(fields);\n if (drop.length > 0) patch.drop = drop;\n return patch;\n}\n\n/**\n * Apply a `LiveStatePatch` to a previous value, returning the next value.\n *\n * Like `diff`, this preserves structural sharing: a fresh object is built only\n * along changed paths, so untouched branches keep their previous reference.\n * That's what lets a client selector (`s => s.streamsIndex`) skip re-rendering\n * when an unrelated slice changed — the slice it reads stays `Object.is`-equal\n * across applies.\n */\nexport function applyPatch<State>(prev: State, patch: LiveStatePatch): State {\n if (\"set\" in patch) return patch.set as State;\n if (\"array\" in patch) {\n if (!Array.isArray(prev)) throw new Error(\"Live-state array patch requires an array baseline\");\n const next = prev.slice(0, patch.array.length);\n next.length = patch.array.length;\n for (const [index, child] of patch.array.items) {\n if (!Number.isSafeInteger(index) || index < 0 || index >= next.length) {\n throw new Error(\"Live-state array patch index is outside its resulting length\");\n }\n next[index] = applyPatch(prev[index], child);\n }\n // The array operation preserves State's shape; only the generic parameter\n // prevents TypeScript from expressing the Array.isArray narrowing on return.\n return next as State;\n }\n const base: Record<string, unknown> = isPlainObject(prev) ? prev : {};\n const next: Record<string, unknown> = { ...base };\n if (patch.fields) {\n for (const [key, childPatch] of Object.entries(patch.fields)) {\n // Define, don't assign: `next[key] =` with key \"__proto__\" would SET THE\n // PROTOTYPE instead of creating an own property — dropping the field and\n // letting a hostile patch inject one. (The spread above is already safe:\n // spread uses define semantics.) `Object.hasOwn` guards the read the same\n // way — a bare `base[\"__proto__\"]` reads the prototype, not a field.\n Object.defineProperty(next, key, {\n value: applyPatch(Object.hasOwn(base, key) ? base[key] : undefined, childPatch),\n enumerable: true,\n writable: true,\n configurable: true,\n });\n }\n }\n if (patch.drop) {\n for (const key of patch.drop) delete next[key];\n }\n return next as State;\n}\n\n/**\n * A PLAIN object — prototype `Object.prototype` or `null` — the only thing\n * `diff` descends into and `applyPatch` merges over. Arrays and class instances\n * (`Date`, `Map`, `Set`, …) fail this on purpose: they carry state outside\n * their own enumerable keys, so per-key diffing would misread them (see the\n * `diff` docstring) — they are leaves, replaced wholesale.\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n","import { isPlainObject } from \"./diff.ts\";\nimport type { CompactLiveStatePatch, LiveStatePatch } from \"./protocol.ts\";\n\nconst fieldAddresses = new WeakMap<object, { keys: string[]; indices: Map<string, number> }>();\n\nfunction addresses(value: Record<string, unknown>) {\n let cached = fieldAddresses.get(value);\n if (!cached) {\n // Undefined object fields are absent after a JSON transport. They must not\n // shift addresses on either side of the next update.\n const keys = Object.keys(value)\n .filter((key) => value[key] !== undefined)\n .sort();\n cached = { keys, indices: new Map(keys.map((key, index) => [key, index])) };\n fieldAddresses.set(value, cached);\n }\n return cached;\n}\n\n/** Encode only the changed paths of an existing structural diff. */\nexport function compactPatch(previous: unknown, patch: LiveStatePatch): CompactLiveStatePatch {\n if (\"set\" in patch) {\n const next = patch.set;\n if (\n typeof previous === \"string\" &&\n typeof next === \"string\" &&\n previous.length >= 16 &&\n // Bound prefix checks even for a multi-megabyte string. Immutable text\n // blocks are ~1 KiB; larger ordinary strings retain replacement semantics.\n previous.length <= 4096 &&\n next.length > previous.length &&\n next.startsWith(previous)\n )\n return [previous.length, next.slice(previous.length)];\n if (\n next === null ||\n typeof next === \"string\" ||\n typeof next === \"number\" ||\n typeof next === \"boolean\"\n )\n return next;\n return [next];\n }\n if (\"array\" in patch) {\n if (!Array.isArray(previous))\n throw new Error(\"Live-state array patch requires an array baseline\");\n const result: Record<string, CompactLiveStatePatch> = {};\n if (patch.array.length !== previous.length) result[\"#\"] = patch.array.length;\n for (const [index, child] of patch.array.items)\n result[index] = compactPatch(previous[index], child);\n return result;\n }\n if (!isPlainObject(previous))\n throw new Error(\"Live-state object patch requires an object baseline\");\n const { indices } = addresses(previous);\n const fields: [string, CompactLiveStatePatch][] = [];\n for (const [key, child] of Object.entries(patch.fields || {})) {\n const index = indices.get(key);\n fields.push([\n index === undefined ? `+${key}` : String(index),\n compactPatch(index === undefined ? undefined : previous[key], child),\n ]);\n }\n for (const key of patch.drop || []) {\n const index = indices.get(key);\n // An undefined field was already absent on the wire.\n if (index !== undefined) fields.push([String(index), []]);\n }\n return Object.fromEntries(fields);\n}\n\n/** Apply a version 3 patch, retaining every untouched object's identity. */\nexport function applyCompactPatch<State>(previous: State, patch: CompactLiveStatePatch): State {\n // Like applyPatch, the wire operation preserves the caller's State contract;\n // TypeScript cannot infer that contract from a recursive, generic JSON codec.\n return applyCompactValue(previous, patch) as State;\n}\n\nfunction applyCompactValue(previous: unknown, patch: CompactLiveStatePatch): unknown {\n if (patch === null || typeof patch !== \"object\") return patch;\n if (Array.isArray(patch)) {\n if (patch.length === 1) return patch[0];\n if (patch.length !== 2 || typeof previous !== \"string\" || previous.length !== patch[0]) {\n throw new Error(\"Live-state append does not match its string baseline\");\n }\n return previous + patch[1];\n }\n if (Array.isArray(previous)) {\n const length = Object.hasOwn(patch, \"#\") ? patch[\"#\"] : previous.length;\n if (\n typeof length !== \"number\" ||\n !Number.isSafeInteger(length) ||\n length < 0 ||\n length > 0xffffffff\n ) {\n throw new Error(\"Live-state array patch has an invalid length\");\n }\n const next = previous.slice(0, length);\n next.length = length;\n for (const [address, child] of Object.entries(patch)) {\n if (address === \"#\") continue;\n const index = position(address, length);\n next[index] = applyCompactValue(previous[index], child);\n }\n return next;\n }\n if (!isPlainObject(previous))\n throw new Error(\"Live-state object patch requires an object baseline\");\n const { keys } = addresses(previous);\n const next = { ...previous };\n for (const [address, child] of Object.entries(patch)) {\n const added = address.startsWith(\"+\");\n const key = added ? address.slice(1) : keys[position(address, keys.length)]!;\n if (added && Object.hasOwn(previous, key) && previous[key] !== undefined) {\n throw new Error(\"Live-state new field already exists in its baseline\");\n }\n if (Array.isArray(child) && child.length === 0) {\n if (added) throw new Error(\"Live-state cannot delete a new field\");\n delete next[key];\n } else {\n // Define own properties, including __proto__, without mutating prototypes.\n Object.defineProperty(next, key, {\n value: applyCompactValue(added ? undefined : previous[key], child),\n enumerable: true,\n writable: true,\n configurable: true,\n });\n }\n }\n return next;\n}\n\nfunction position(address: string, length: number): number {\n const index = Number(address);\n if (!Number.isSafeInteger(index) || index < 0 || index >= length || String(index) !== address) {\n throw new Error(\"Live-state field address is outside its baseline\");\n }\n return index;\n}\n","import {\n disposeIgnoredRpcResult,\n isThenable,\n retainCallback,\n type RetainedCallback,\n} from \"./retain.ts\";\nimport { diff } from \"./diff.ts\";\nimport { compactPatch } from \"./compact.ts\";\nimport type {\n LiveStateCursor,\n LiveStateRead,\n LiveStateSubscriptionOptions,\n LiveUpdate,\n} from \"./protocol.ts\";\n\n/** Handle returned by `LiveState.subscribe` — the ownership + liveness surface for one subscriber. */\nexport type LiveStateSubscription = {\n /** Still registered on a live engine? A dead DO incarnation also makes the call reject. */\n ping(): boolean;\n unsubscribe(): void;\n [Symbol.dispose](): void;\n};\n\nconst DEFAULT_DEBOUNCE_MS = 100;\nconst ACK_TIMEOUT_MS = 10_000;\n\ntype Subscriber<State> = {\n version: 1 | 2 | 3;\n state: State;\n revision: number;\n busy: boolean;\n timeout?: ReturnType<typeof setTimeout>;\n};\n\n/**\n * A source-agnostic live store: hold a state value, and when it changes push the\n * minimal diff to every subscriber. It does not know or care where the state\n * comes from — a Durable Object folds events into it, a stateless RpcTarget polls\n * a third-party API into it — so ANY RpcTarget can expose live state by holding\n * one and returning a read-only wrapper from a `.live` getter.\n *\n * Two rules make it cheap and correct:\n * - Updates are IMMUTABLE (`setState`/`assign` build a new value, never mutate),\n * so the diff short-circuits unchanged branches by identity — O(changed), not\n * O(size). See `diff.ts`.\n * - Push work runs only while a subscriber exists. Transient readers call\n * `readSince` explicitly; a dormant engine schedules nothing.\n *\n * All subscribers share one revision line. Fast subscribers share a patch;\n * slow subscribers receive a coalesced patch from their acknowledged state.\n * A revision mismatch makes the client resync instead of applying stale data.\n */\nexport class LiveState<State extends object> {\n #current: State;\n /** Latest flushed state — the shared diff baseline. */\n #broadcast: State;\n #revision = 0;\n readonly #epoch = crypto.randomUUID();\n #lastUpdate: Extract<LiveUpdate<State>, { type: \"patch\" }> | undefined;\n #lastCompactUpdate: Extract<LiveUpdate<State>, { p: unknown }> | undefined;\n readonly #subscribers = new Map<RetainedCallback<LiveUpdate<State>>, Subscriber<State>>();\n readonly #debounceMs: number;\n #flushTimer: ReturnType<typeof setTimeout> | undefined;\n\n constructor(initial: State, options: { debounceMs?: number } = {}) {\n this.#current = initial;\n this.#broadcast = initial;\n this.#debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;\n }\n\n /** The current state — reflects every `setState`/`assign`, even while dormant. */\n getState(): State {\n return this.#current;\n }\n\n /** One retained delta bounds history while a single parent can pull incrementally.\n * A late reader or a new incarnation receives an explicit snapshot instead. */\n readSince(\n cursor?: LiveStateCursor,\n options: LiveStateSubscriptionOptions = {},\n ): LiveStateRead<State> {\n if (this.#flushTimer !== undefined) clearTimeout(this.#flushTimer);\n this.#flushTimer = undefined;\n this.#flush();\n if (cursor?.epoch === this.#epoch) {\n if (cursor.revision === this.#revision) return { epoch: this.#epoch, update: null };\n if (cursor.revision === this.#lastUpdate?.from) {\n return {\n epoch: this.#epoch,\n update: options.patchVersion === 3 ? this.#lastCompactUpdate! : this.#lastUpdate,\n };\n }\n }\n return {\n epoch: this.#epoch,\n update:\n options.patchVersion === 3\n ? { s: [this.#revision, this.#broadcast] }\n : { type: \"snapshot\", revision: this.#revision, state: this.#broadcast },\n };\n }\n\n /** True while at least one live subscriber makes projection work observable. */\n get observed(): boolean {\n return this.#subscribers.size > 0;\n }\n\n /** Replace the state. Build a NEW value (don't mutate) so the diff stays cheap. */\n setState(next: State | ((prev: State) => State)): void {\n this.#current = typeof next === \"function\" ? next(this.#current) : next;\n if (this.#subscribers.size > 0) this.#scheduleFlush();\n }\n\n /** Shallow-merge a partial into the state — sugar for `setState(p => ({ ...p, ...partial }))`. */\n assign(partial: Partial<State>): void {\n this.setState((prev) => ({ ...prev, ...partial }));\n }\n\n subscribe(\n sink: (update: LiveUpdate<State>) => unknown,\n options: LiveStateSubscriptionOptions = {},\n ): LiveStateSubscription {\n // First subscriber after dormancy: adopt the latest state as the shared\n // baseline. While subscribers exist, `#broadcast` only advances inside a\n // flush (with a patch to everyone), so it always matches what they've seen.\n if (this.#subscribers.size === 0) {\n this.#flush();\n }\n\n const retained = retainCallback(sink);\n this.#subscribers.set(retained, {\n version: options.patchVersion ?? 1,\n state: this.#broadcast,\n revision: this.#revision,\n busy: false,\n });\n retained.onRpcBroken?.(() => this.#drop(retained));\n // The initial snapshot is the first paint — delivered now, never debounced.\n // A synchronously-throwing sink is dropped here and never becomes live.\n this.#deliver(\n retained,\n options.patchVersion === 3\n ? { s: [this.#revision, this.#broadcast] }\n : { type: \"snapshot\", revision: this.#revision, state: this.#broadcast },\n );\n\n return {\n ping: () => this.#subscribers.has(retained),\n unsubscribe: () => this.#drop(retained),\n [Symbol.dispose]: () => this.#drop(retained),\n };\n }\n\n #scheduleFlush(): void {\n this.#flushTimer ??= setTimeout(() => {\n this.#flushTimer = undefined;\n this.#flush();\n }, this.#debounceMs);\n }\n\n #flush(): void {\n const previous = this.#broadcast;\n const patch = diff(previous, this.#current);\n if (patch === undefined) return;\n const from = this.#revision;\n const to = (this.#revision += 1);\n this.#broadcast = this.#current;\n const update = { type: \"patch\", from, to, patch } satisfies LiveUpdate<State>;\n this.#lastUpdate = update;\n this.#lastCompactUpdate = { p: [from, to, compactPatch(previous, patch)] };\n for (const subscriber of this.#subscribers.keys()) {\n this.#sendLatest(subscriber);\n }\n }\n\n /** Slow subscribers hold one call and one baseline, never a queue of token updates. */\n #sendLatest(subscriber: RetainedCallback<LiveUpdate<State>>): void {\n const held = this.#subscribers.get(subscriber);\n if (!held || held.busy || held.revision === this.#revision) return;\n if (held.version === 3) {\n if (held.revision === this.#lastUpdate?.from) {\n this.#deliver(subscriber, this.#lastCompactUpdate!);\n } else {\n const patch = diff(held.state, this.#broadcast);\n this.#deliver(subscriber, {\n p: [held.revision, this.#revision, patch ? compactPatch(held.state, patch) : {}],\n });\n }\n return;\n }\n const patch =\n held.version === 2 && held.revision === this.#lastUpdate?.from\n ? this.#lastUpdate.patch\n : diff(held.state, this.#broadcast, { arrays: held.version === 2 });\n // A coalesced sequence may return to the same value. An empty object patch\n // still advances its revision so the following shared update applies.\n this.#deliver(subscriber, {\n type: \"patch\",\n from: held.revision,\n to: this.#revision,\n patch: patch ?? {},\n });\n }\n\n /** Only acknowledgement releases the next coalesced update; a dead sink is dropped. */\n #deliver(subscriber: RetainedCallback<LiveUpdate<State>>, update: LiveUpdate<State>): void {\n const held = this.#subscribers.get(subscriber);\n if (!held) return;\n held.state = this.#broadcast;\n held.revision = this.#revision;\n held.busy = true;\n let result: unknown;\n try {\n result = subscriber(update);\n } catch {\n this.#drop(subscriber);\n return;\n }\n if (isThenable(result)) {\n held.timeout = setTimeout(() => {\n console.warn(\"Live-state subscriber dropped: acknowledgement timed out\", {\n revision: held.revision,\n timeoutMs: ACK_TIMEOUT_MS,\n });\n this.#drop(subscriber);\n }, ACK_TIMEOUT_MS);\n void Promise.resolve(result)\n .then(\n () => {\n if (held.timeout !== undefined) clearTimeout(held.timeout);\n held.busy = false;\n this.#sendLatest(subscriber);\n },\n () => this.#drop(subscriber),\n )\n .finally(() => disposeIgnoredRpcResult(result));\n return;\n }\n held.busy = false;\n disposeIgnoredRpcResult(result);\n }\n\n #drop(subscriber: RetainedCallback<LiveUpdate<State>>): void {\n const timeout = this.#subscribers.get(subscriber)?.timeout;\n if (timeout !== undefined) clearTimeout(timeout);\n if (!this.#subscribers.delete(subscriber)) return;\n subscriber[Symbol.dispose]();\n if (this.#subscribers.size === 0 && this.#flushTimer !== undefined) {\n clearTimeout(this.#flushTimer); // dormant again: no work until the next subscriber\n this.#flushTimer = undefined;\n }\n }\n}\n","// The DO-side \"thin registry\" over per-processor StreamProcessorRunners —\n// every processor-hosting Durable Object runs one. WIRED INTO: the secret DO\n// (secret-durable-object.ts — the reference wiring), the project DO\n// (multi-processor), the scheduler DO (domain alarm slice), the\n// capability-host DO (the recovery template), the repo DO (caught-up processing\n// inside processEvent), and the\n// agent DO (agent-durable-object.ts — multi-processor with per-processor\n// recovery on its registered processors; stream redelivery alone cannot\n// cover a SIMULTANEOUS\n// Agent+Stream DO death mid-blocker — codex review P1).\n//\n// THE WIRING RECIPE (established by the secret DO; the same on every DO):\n// 1. `createStreamProcessorRegistry(this.ctx, { stream, path, projectId,\n// version: workerVersion(this.env), getLiveState? })`.\n// 2. The DO CONSTRUCTS its processor (`new XProcessor({ stream, path,\n// projectId, ...deps })` — the runner owns progress and keepalive; the\n// processor holds no injected durability plumbing) and passes it\n// to `register`, deciding recovery per the module-doc rule below.\n// 3. READ-YOUR-WRITES REPOINTING: build `#reads = registry.reads(processor)`\n// and serve every read from it — `new StreamProcessorRpcTarget(this.#reads,\n// { catchUpBeforeSnapshot: () => registry.catchUp(slug), ... })`, DO verbs\n// that read their own fold via `#reads.snapshot()`, and `getLiveState`\n// closures via `#reads.currentState`. The runner owns the cursors; the\n// processor instance holds no fold to read (see `reads` below).\n// 4. `alarm()` → `registry.handleAlarm(alarmInfo)`, `wakeStreamProcessor`\n// → `registry.wakeStreamProcessor`, `.liveState` →\n// `new LiveStateRpcTarget(registry)`.\n//\n// The redesign (docs/stream-processor-runner-redesign.md, \"option B\") allows\n// the registry exactly these jobs:\n//\n// 1. the single-DO-alarm MULTIPLEX — a Durable Object has ONE alarm and\n// `setAlarm` clobbers it, so every subsystem's desire (each runner's\n// keepalive, the scheduler) goes through a named slice and the earliest\n// wins;\n// 2. slug→runner ROUTING — wake calls to the named runner, alarm fires\n// to every runner (each keepalive self-gates on its persisted armed\n// time);\n// 3. building each runner's `durability` adapters from `ctx`\n// (durable-object-processor-durability.ts);\n// 4. the DO transport boundary — wake sink calls return immediately and\n// their eventual runner outcome crosses an independent one-way\n// result callback. This must remain transport adaptation only;\n// frame semantics stay in the runner.\n//\n// plus the two responsibilities that live ABOVE any single runner and so\n// cannot move into one: the node's LIVE-STATE assembly and the catch-up door.\n// Everything per-processor — processEventBatch serialization, offset\n// dedupe, keepalive tracking of the whole event-batch attempt, the trailing\n// type-unfiltered catch-up behind a consumes-filtered wake batch, cold-load /\n// schema-refold handling, read-your-writes waiters — lives in the RUNNER\n// (stream-processor-runner.ts); the registry must not re-implement any of it.\n// If this file grows behavior beyond the jobs above, it has failed.\n//\n// RECOVERY IS OPT-IN PER PROCESSOR, AND THE OPT-IN IS LOAD-BEARING (codex\n// review §4/#6): the runner cannot detect whether a processor's\n// `runInBackground` work is consequential, so the DO author MUST pass\n// `{ recovery: true }` to `register` for every processor whose background\n// work has an outcome that matters (LLM turns, repo seeds, vendor calls with\n// stream-backed obligations). A processor registered without recovery gets NO\n// post-eviction revival: an incarnation that dies owing its work loses that\n// work silently — acceptable only for telemetry-grade effects. Consuming the\n// core `stream/processor-revived` fact is optional: do it when the processor\n// reacts to that fact itself. Otherwise its append still wakes delivery, and\n// the runner's eventless at-head pass gives recovery its turn.\n//\n// KNOWN LIMITATION — processor retry vs stream-delivery halt (codex review §4/#7): a\n// permanently failing batch is rethrown by the runner's processEventBatch, and the\n// stream's durable sending loop still backs off and eventually HALTS the\n// subscription as a durable event (stream-event-sender.ts). The registry does\n// NOT deliver the redesign's \"retry blockers indefinitely\" policy — transport\n// halt semantics are deliberately unchanged in this slice, and the stream's\n// halt-resume controls remain the operator escape. Do not read this file as\n// retry-forever.\n\nimport * as cloudflareWorkers from \"cloudflare:workers\";\nimport { z } from \"zod\";\nimport { disposeIgnoredRpcResult, retainCallback } from \"../sdk/capnweb/live-state/retain.ts\";\nimport { LiveState } from \"../sdk/capnweb/live-state/engine.ts\";\nimport type { ProcessorStream } from \"./stream-handle.ts\";\nimport type { StreamEvent } from \"./schemas.ts\";\nimport type {\n StreamEventBatch,\n StreamProcessorWakeRequest,\n StreamProcessorWakeResponse,\n StreamWakeDeliveryError,\n StreamWakeDeliveryResult,\n StreamWakeEventBatch,\n} from \"./rpc-types.ts\";\nimport type { ProcessorState } from \"./processor-contracts.ts\";\nimport type { ProcessorReads, StreamProcessor } from \"./stream-processor.ts\";\nimport { StreamProcessorRunner, type ProcessorRecovery } from \"./stream-processor-runner.ts\";\nimport {\n durableObjectProgressStore,\n durableObjectRecovery,\n} from \"./durable-object-processor-durability.ts\";\nimport {\n announceContract,\n hostRuntimeCapabilities,\n type AnyHostedProcessor,\n} from \"./processor-host-capabilities.ts\";\n\n// Namespace import + fallback rather than a named import: named imports of a\n// missing export are ESM LINK errors, and workerd only exposes `tracing`\n// where the tracing API is enabled. OS workers get real spans; a runtime\n// without them (dynamic user workers, node harnesses) gets the no-op.\nconst tracing: {\n enterSpan<T>(\n name: string,\n fn: (span: { setAttribute(key: string, value: unknown): void }) => T,\n ): T;\n} = cloudflareWorkers.tracing ?? { enterSpan: (_name, fn) => fn({ setAttribute() {} }) };\n\n/**\n * What `register` accepts: a real {@link StreamProcessor} subclass instance\n * that also carries the hosted-capability surface — contract description,\n * runtime state, event-consumption metrics — the wake call shares with the\n * browser host. The bound is STRUCTURAL ({@link AnyHostedProcessor})\n * because the class itself cannot appear here: it is\n * invariant in its contract parameter (private state storage holds `State` in\n * both positions), so no single instantiation is a supertype of all\n * processors. The \"must be a real StreamProcessor\" half is enforced at\n * construction instead — the runner's `StreamProcessor.runnerHooks` reaches\n * the class's own private hooks and throws on a structural impostor.\n */\nexport type RegisterableProcessor = AnyHostedProcessor;\n\n/**\n * The folded-state type of a registered processor, derived from its\n * contract's `stateSchema` — the class's contract parameter is invariant and\n * cannot be named through {@link RegisterableProcessor}'s structural bound,\n * but every concrete subclass's `contract` property already carries the\n * schema whose output IS the state type.\n */\nexport type RegisteredProcessorState<P extends RegisterableProcessor> = ProcessorState<\n P[\"contract\"]\n>;\n\n/**\n * What {@link StreamProcessorRegistry.reads} returns: the RPC-facing\n * {@link ProcessorReads} plus the two synchronous reads a DO's `getLiveState`\n * closure needs (live-state assembly runs synchronously; see `refreshLive`),\n * with `waitUntilEvent` widened to the runner's full waiter — the offset\n * barrier {@link ProcessorReads} publishes over RPC PLUS the in-process-only\n * predicate form (a function cannot cross the RPC facade; a DO wires it into\n * processor deps that wait for a specific future event, e.g. the capability\n * host's script-completion wait).\n */\nexport type RegisteredProcessorReads<State> = Omit<ProcessorReads<State>, \"waitUntilEvent\"> & {\n waitUntilEvent(\n input:\n | { offset: number; timeoutMs?: number; signal?: AbortSignal }\n | {\n predicate: (event: StreamEvent) => boolean;\n timeoutMs?: number;\n signal?: AbortSignal;\n },\n ): Promise<void>;\n /** The runner's committed fold, synchronously (schema default until loaded). */\n readonly currentState: State;\n /** Committed processing cursor, read atomically with currentState in live assembly. */\n readonly currentAcknowledgedThroughOffset: number;\n /** Source lifetime paired atomically with currentState and its cursor. */\n readonly currentStreamId: string | undefined;\n /** Whether `currentState` is a real fold — gate live publishing on it. */\n readonly isLoaded: boolean;\n /**\n * Fold through the durable stream tail or throw. The registry and this\n * processor-specific door have the same strict contract.\n */\n catchUp(): Promise<void>;\n};\n\ntype RegistryEntry = {\n processor: RegisterableProcessor;\n runner: StreamProcessorRunner<any>;\n /** Present when registered with `{ recovery: true }` — the keepalive-backed\n * recovery adapter, kept for the operator reset seam. */\n recovery?: ProcessorRecovery;\n};\n\n/**\n * Options for {@link StreamProcessorRegistry.register}. A processor registers\n * under its contract slug by default — which IS the subscription name under the\n * identity doctrine (docs/stream-subscription-model-redesign.md): the same\n * string as the stream's catalog key, the facet name under facet placement,\n * and the progress-key component. Pass an explicit `name` to register a second\n * instance of one contract under a distinct name; reads, wake routing, and\n * progress storage all already key by that name (see `reads`, `resolveProcessorName`,\n * and `durableObjectProgressStore`), so the instances stay independent.\n */\nexport type RegisterProcessorOptions<State = unknown> = {\n /** Clear this processor's related projections synchronously with source-lifetime replacement. */\n resetForStream?: () => void;\n /** Post-eviction keepalive recovery — REQUIRED for consequential\n * `runInBackground` work (see the module doc). */\n recovery?: boolean;\n /** Registered/progress name for this instance. Defaults to the contract slug\n * (name === slug, the identity-doctrine default). Supply a distinct name to\n * host two instances of one contract on one registry without colliding. */\n name?: string;\n /** Persist a bounded reduction cache; a cold runner refolds when it is omitted. */\n reductionCache?: {\n shouldCacheReduction(state: State): boolean;\n initialState(): State;\n };\n};\n\nconst WakeDeliveryThrowableFields = z.object({\n durableObjectReset: z.unknown().optional(),\n itxCallId: z.unknown().optional(),\n message: z.unknown().optional(),\n name: z.unknown().optional(),\n overloaded: z.unknown().optional(),\n retryable: z.unknown().optional(),\n});\n\nfunction serializeWakeDeliveryError(error: unknown): StreamWakeDeliveryError {\n const parsed = WakeDeliveryThrowableFields.safeParse(error);\n const candidate = parsed.success ? parsed.data : undefined;\n return {\n name: typeof candidate?.name === \"string\" ? candidate.name : \"Error\",\n message:\n typeof candidate?.message === \"string\"\n ? candidate.message\n : String(error) || \"unknown delivery failure\",\n ...(typeof candidate?.itxCallId === \"string\" &&\n candidate.itxCallId.length > 0 &&\n candidate.itxCallId.length <= 200 && { itxCallId: candidate.itxCallId }),\n ...(candidate?.durableObjectReset === true && { durableObjectReset: true as const }),\n ...(candidate?.overloaded === true && { overloaded: true as const }),\n ...(candidate?.retryable === true && { retryable: true as const }),\n };\n}\n\n/**\n * Report one final wake-delivery result without awaiting the report call's\n * return value. Calling the callback sends the result; awaiting it would keep\n * the original cross-Durable-Object call chain open.\n */\nfunction reportWakeDeliveryResult(\n reportDeliveryResult: (result: StreamWakeDeliveryResult) => unknown,\n deliveryResult: StreamWakeDeliveryResult,\n): void {\n let result: unknown;\n try {\n result = reportDeliveryResult(deliveryResult);\n } catch (error) {\n console.warn(\"stream wake delivery result could not be reported\", { error });\n return;\n }\n try {\n disposeIgnoredRpcResult(result);\n } catch (error) {\n // The message was already dispatched. Cleanup failure must not turn a\n // completed processor attempt into a second, contradictory failure.\n console.warn(\"stream wake delivery report result disposal failed\", { error });\n }\n}\n\nexport type StreamProcessorRegistry<Live extends object = Record<string, unknown>> = {\n readonly stream: ProcessorStream;\n /** The node's live-state engine; a `.liveState` RpcTarget exposes getState()/subscribe() over it. */\n readonly live: LiveState<Live>;\n /**\n * Reassemble the live state from current inputs — the ONE writer for the\n * engine. Call it after mutating any non-runner live-state input (the\n * streams index, the demo counter); a runner's own committed-state change\n * calls it automatically via `observeStateChanges`. On a cold DO (a\n * runner's progress not yet loaded) it does nothing instead of publishing\n * the schema default over real facts; `loadAndRefreshLive` is the explicit\n * asynchronous loading door.\n */\n refreshLive(): void;\n /**\n * `refreshLive`'s cold-start sibling: LOAD every runner's progress, THEN\n * reassemble — so the first read or connection reflects committed writes\n * even on a cold DO. (Distinct names because the difference — one awaits\n * storage, one must not — is exactly what a call site gets wrong.)\n */\n loadAndRefreshLive(): Promise<void>;\n /** Registered processor names, in registration order. */\n readonly names: readonly string[];\n /**\n * Register a processor (constructed by the DO — the processor is the star,\n * the registry is plumbing) under its contract slug (= subscription name —\n * see {@link RegisterProcessorOptions}) and build its runner: durable\n * two-cursor progress in DO KV keyed by the name, plus — WHEN THE\n * DO PASSES `{ recovery: true }` — the per-runner recovery adapter\n * (keepalive + the core `stream/processor-revived` fact). See the module\n * doc: recovery is REQUIRED for any processor whose `runInBackground` work\n * is consequential; the registry cannot infer that.\n * Duplicate names (and re-registering the same instance) throw. Returns the\n * processor, so DOs keep their `field = registry.register(new XProcessor(...))` shape.\n */\n register<P extends RegisterableProcessor>(\n processor: P,\n opts?: RegisterProcessorOptions<RegisteredProcessorState<P>>,\n ): P;\n /**\n * The runner-backed READ surface for one registered processor. The runner\n * owns both cursors and the fold — the processor instance holds no\n * readable state at all — so every read goes through here. Hand THIS to\n * `new StreamProcessorRpcTarget(...)` and to every DO verb that reads its\n * own fold: `snapshot`/`waitUntilEvent` come from the runner's committed\n * progress; `getRuntimeState` assembles the processor's contributed\n * runtime bag under the runner's snapshot; `currentState` / `isLoaded`\n * serve `getLiveState` closures without an async hop. Takes the registered\n * instance so the state type flows through, or a registered NAME for hosts\n * that route doors by subscription name (the facet) — the name form cannot\n * carry the state type, so its reads publish `unknown` state.\n */\n reads<P extends RegisterableProcessor>(\n processor: P,\n ): RegisteredProcessorReads<RegisteredProcessorState<P>>;\n reads(name: string): RegisteredProcessorReads<unknown>;\n /** Observe committed fold changes for one registered processor. */\n observeStateChanges<P extends RegisterableProcessor>(\n processor: P,\n observer: (snapshot: { offset: number; state: RegisteredProcessorState<P> }) => void,\n ): () => void;\n /**\n * Wire this to the host DO's wakeStreamProcessor RPC method. Resolves the\n * woken runner by the request's `name` (= contract slug) and answers with\n * its acknowledged cursor and a fresh processEventBatch.\n */\n wakeStreamProcessor(args: StreamProcessorWakeRequest): Promise<StreamProcessorWakeResponse>;\n /**\n * Pull any events stream delivery has not (yet) brought this runner and\n * drive them now. Call before serving a read that must reflect a write the\n * caller just made (read-your-writes): push delivery is asynchronous. The\n * pull is serialized with live frames on the runner's chain, so racing a\n * sink is safe. A direct Durable Object lifecycle loss gets one replay on\n * the runner's durable cursor; all application failures and a second\n * availability failure throw. Stale state is never presented as success.\n */\n catchUp(name: string): Promise<void>;\n /**\n * Operator seam: clear one runner's revival crash-loop budget and pull its\n * owed retry in to the confirmation lead — the no-deploy antidote for a\n * 3-strikes plateau (\"backing off (plateau 360m). A deploy resets the\n * budget.\"). No-op for a recovery-less runner.\n */\n resetRecoveryBackoff(name: string): void;\n /**\n * Wire this to the host DO's `alarm()` handler — REQUIRED on every hosting\n * class. The fire routes to EVERY runner (each keepalive self-gates on its\n * own persisted armed time), so a DO sharing the alarm with its own\n * scheduling (see {@link setAlarmSlice}) calls this unconditionally and\n * then runs its own due work.\n */\n handleAlarm(alarmInfo?: AlarmInvocationInfo): Promise<void>;\n /**\n * Share the single DO alarm: each named slice states its own desired fire\n * time (or null for none) and the registry arms the earliest across all\n * slices (each runner's keepalive rides its own `keepalive:<slug>` slice).\n * A slice owner must tolerate early fires (another slice's) and re-arm\n * itself during its handler — in-memory desires do not survive eviction;\n * the durable alarm plus each subsystem's re-derivation do. The returned\n * promise settles when the platform alarm durably reflects the change;\n * await it (and rethrow) where durability is load-bearing (error-path\n * fallbacks), ignore it everywhere else.\n */\n setAlarmSlice(name: string, atMs: number | null): Promise<void>;\n /** The slice's own current desire (NOT the merged alarm time). */\n getAlarmSlice(name: string): number | null;\n};\n\nexport function createStreamProcessorRegistry<Live extends object = Record<string, unknown>>(\n ctx: DurableObjectState,\n options: {\n stream: ProcessorStream;\n /** Path of the hosted stream. The registry fences every\n * `wakeStreamProcessor` against this exact `(projectId, path)`: a wake\n * carrying a matching processor slug but a DIFFERENT coordinate is\n * rejected, so a stale or miswired subscription can never fold a foreign\n * stream into this processor. (Provenance stamping still lives in the\n * processors; this is the delivery-side isolation check.) */\n path: string;\n /** Owning project, or null on a global (deployment-root) stream. The other\n * half of the wake coordinate fence (see `path`). */\n projectId: string | null;\n /** Worker deploy version; a change resets each keepalive's crash-loop\n * budget (the antidote deploy). Pass `workerVersion(env)`. REQUIRED: a\n * registry that silently defaulted this could never take the\n * version-reset path, so a deterministic crash loop would wait out the\n * full plateau even after the fixing deploy shipped. */\n version: string;\n /** Injected clock for the node test harness; production uses Date.now. */\n now?: () => number;\n /**\n * Assemble this node's live state (see `LiveState`) — this is what TYPES\n * the registry's `Live` parameter. Called on every registered runner's\n * committed-state change and on `loadAndRefreshLive`. Omit and the live\n * state is the primary (first-registered) runner's reduced state\n * (untyped: `Live` stays the default record); provide it to project a\n * redacted view or fold in extras (e.g. a streams index).\n */\n getLiveState?: () => Live;\n /**\n * Fires after every `assembleLive` pass — with `skippedUnloadedRunners:\n * false` when the live state was actually reassembled, `true` when the\n * pass no-oped on the unloaded-runner wall (a fresh incarnation woken by\n * one runner's delivery while other runners are still cold). A host that\n * pushes live state to external watchers (the liveState socket lane)\n * needs the skipped signal: without it, a change committed behind the\n * wall would never reach them. A dumb callback — policy lives with the\n * caller.\n */\n onLiveAssembled?: (assembly: { skippedUnloadedRunners: boolean }) => void;\n },\n): StreamProcessorRegistry<Live> {\n const entries = new Map<string, RegistryEntry>();\n const now = options.now ?? (() => Date.now());\n\n // ---------------------------------------------------------------------------\n // The shared DO alarm. A Durable Object has exactly ONE alarm and setAlarm\n // clobbers it, so every desire goes through this slice map and the earliest\n // wins.\n // Slices are in-memory (an eviction loses them) and that is correct: the\n // durable alarm itself survives, its fire runs every subsystem's handler,\n // and each handler re-derives its own desire — a keepalive from its KV\n // record, the scheduler from its fold.\n // ---------------------------------------------------------------------------\n const alarmSlices = new Map<string, number>();\n /**\n * A durable alarm armed by a PREVIOUS incarnation whose owning slice we\n * cannot know (in-memory desires died with it). The first reconcile adopts\n * it as a desire of its own so this incarnation's arming/disarming cannot\n * clobber it; the next actual fire drops it — every subsystem re-derives\n * its desire in that turn.\n */\n const INHERITED_ALARM_SLICE = \"@inherited\";\n /** What the platform alarm holds; null = cleared, undefined = unknown. */\n let platformAlarmAtMs: number | null | undefined;\n /** Serializes alarm storage ops so read-adopt and writes cannot interleave. */\n let alarmChain: Promise<void> = Promise.resolve();\n /**\n * Returns the settled write for callers whose correctness depends on the\n * alarm being DURABLY armed (the alarm handler, the scheduler's error-path\n * fallback) — a rejected step means the platform alarm may not exist, and\n * such callers must rethrow so the platform retries them. Fire-and-forget\n * callers may ignore the result: the chain observes the rejection either\n * way, and the next reconcile re-reads and re-issues.\n */\n function reconcileAlarm(): Promise<void> {\n const step = alarmChain.then(async () => {\n if (platformAlarmAtMs === undefined) {\n const existing = await ctx.storage.getAlarm();\n platformAlarmAtMs = existing;\n if (existing !== null) alarmSlices.set(INHERITED_ALARM_SLICE, existing);\n }\n let earliest: number | null = null;\n for (const atMs of alarmSlices.values()) {\n if (earliest === null || atMs < earliest) earliest = atMs;\n }\n if (earliest === platformAlarmAtMs) return;\n platformAlarmAtMs = earliest;\n if (earliest === null) await ctx.storage.deleteAlarm();\n else await ctx.storage.setAlarm(earliest);\n });\n alarmChain = step.catch((error: unknown) => {\n platformAlarmAtMs = undefined; // unknown — the next reconcile re-reads\n console.error(\"stream processor registry alarm arming failed\", error);\n });\n ctx.waitUntil(alarmChain);\n return step;\n }\n function setAlarmSlice(name: string, atMs: number | null): Promise<void> {\n if (atMs === null) alarmSlices.delete(name);\n else alarmSlices.set(name, atMs);\n return reconcileAlarm();\n }\n\n function requireEntry(name: string): RegistryEntry {\n const entry = entries.get(name);\n if (entry === undefined) {\n throw new Error(\n `Unknown stream processor name \"${name}\" on this registry (registered: ${[...entries.keys()].join(\", \") || \"none\"})`,\n );\n }\n return entry;\n }\n\n function requireEntryForInstance(processor: RegisterableProcessor, verb: string): RegistryEntry {\n for (const entry of entries.values()) {\n if (entry.processor === processor) return entry;\n }\n // Instance identity, not slug lookup: two instances of one contract can be\n // registered under two names, so only the exact registered instance names\n // its runner.\n throw new Error(\n `stream processor \"${processor.contract.slug}\" instance passed to ${verb}() is not ` +\n `registered on this registry — pass the exact instance register() returned ` +\n `(registered names: ${[...entries.keys()].join(\", \") || \"none\"})`,\n );\n }\n\n /**\n * Route a wake to a registered entry. The subscription NAME is the key —\n * and equals the contract slug (enforced at configure time; under facet\n * placement it is also the facet name). An unknown name is a loud error.\n */\n function resolveProcessorName(args: StreamProcessorWakeRequest): string {\n const named = entries.get(args.name);\n if (named === undefined) {\n throw new Error(\n `wakeStreamProcessor for unknown name \"${args.name}\" — ` +\n `subscribe by registered name (registered: ${[...entries.keys()].join(\", \") || \"none\"})`,\n );\n }\n return args.name;\n }\n\n // The node's live-state engine. Seeded empty; assembled from runner state\n // on the first `loadAndRefreshLive`\n // and kept fresh by each runner's committed-state observer. The empty seed\n // and the primary-runner fallback are the two places the registry must\n // assert `Live` (they only apply when `getLiveState` was omitted, where\n // `Live` is the default record type anyway).\n const live = new LiveState<Live>({} as Live);\n function assembleLive(): void {\n // An unloaded runner reports the schema DEFAULT as currentState —\n // assembling from that would push patches that wipe real facts to live\n // LiveState clients (e.g. a cold DO whose first wake is a touchStreamActivity).\n // Only loadAndRefreshLive may cross storage; once it completes this\n // reassembly runs with every real fold.\n if ([...entries.values()].some((entry) => !entry.runner.isLoaded)) {\n options.onLiveAssembled?.({ skippedUnloadedRunners: true });\n return;\n }\n const primary = [...entries.values()][0]?.runner.currentState as Live | undefined;\n live.setState(options.getLiveState?.() ?? primary ?? ({} as Live));\n options.onLiveAssembled?.({ skippedUnloadedRunners: false });\n }\n async function loadThenAssemble(): Promise<void> {\n // Loading is all-or-nothing: publishing a projection assembled from only\n // the processors whose storage happened to respond would turn an\n // availability failure into false domain state. snapshot() performs any\n // required refold and throws on failure; the caller sees that failure and\n // may retry the read against a fresh incarnation.\n await Promise.all([...entries.values()].map((entry) => entry.runner.snapshot()));\n assembleLive();\n }\n\n return {\n stream: options.stream,\n live,\n refreshLive: assembleLive,\n loadAndRefreshLive: loadThenAssemble,\n\n get names() {\n return [...entries.keys()];\n },\n\n register(processor, opts) {\n // The registered name defaults to the contract slug (one identity — see\n // RegisterProcessorOptions); an explicit name hosts a second instance of\n // one contract without colliding.\n const name = opts?.name ?? processor.contract.slug;\n if (entries.has(name)) {\n throw new Error(`Stream processor name \"${name}\" is already registered on this registry`);\n }\n for (const [registeredName, entry] of entries) {\n if (entry.processor === processor) {\n throw new Error(\n `this exact processor instance is already registered as \"${registeredName}\" — ` +\n `construct one instance per registration`,\n );\n }\n }\n // Recovery FIRST, because durableObjectRecovery's construction re-issues\n // a persisted alarm desire (the lost-platform-alarm heal) through this\n // runner's own slice before the runner can start work.\n const recovery = opts?.recovery\n ? durableObjectRecovery({\n storage: ctx.storage,\n name,\n stream: options.stream,\n version: options.version,\n armAlarm: (atMs) => void setAlarmSlice(`keepalive:${name}`, atMs),\n waitUntil: (work) => ctx.waitUntil(work),\n now,\n })\n : undefined;\n const runner = new StreamProcessorRunner({\n // See RegisterableProcessor: the class is invariant in its contract,\n // so the structural door narrows back to the class here; runnerHooks\n // (inside the constructor) fails loudly on anything that is not a\n // real StreamProcessor instance.\n processor: processor as unknown as StreamProcessor<any, any>,\n stream: options.stream,\n durability: {\n progress: durableObjectProgressStore({\n storage: ctx.storage,\n name,\n resetForStream: opts?.resetForStream,\n reductionCache: opts?.reductionCache,\n }),\n ...(recovery === undefined ? {} : { recovery }),\n },\n // Recovery-less runners still keep the incarnation alive while their\n // registered work runs; they just get no post-eviction alarm (see the\n // module doc for when that is acceptable).\n keepAlive: (work) => ctx.waitUntil(work()),\n now,\n });\n entries.set(name, { processor, runner, ...(recovery === undefined ? {} : { recovery }) });\n // Any runner's committed-state change reassembles the node's live state.\n runner.observeStateChanges(() => assembleLive());\n return processor;\n },\n\n reads(processorOrName: RegisterableProcessor | string) {\n const entry =\n typeof processorOrName === \"string\"\n ? requireEntry(processorOrName)\n : requireEntryForInstance(processorOrName, \"reads\");\n const { runner } = entry;\n const reads: RegisteredProcessorReads<unknown> = {\n snapshot: () => runner.snapshot(),\n getRuntimeState: async () => {\n // The processor contributes only its runtime bag; the SNAPSHOT half\n // comes from the runner's committed progress — the same assembly\n // the wake response's capability performs (metrics excluded here:\n // this is the inspection read, not the wake capability).\n const contributed = await entry.processor.getRuntimeState();\n return { ...contributed, snapshot: await runner.snapshot() };\n },\n // The union parameter narrows into the runner's two overloads; both\n // branches are the same passthrough.\n waitUntilEvent: (input) =>\n \"offset\" in input ? runner.waitUntilEvent(input) : runner.waitUntilEvent(input),\n catchUp: () => runner.catchUp(),\n get currentAcknowledgedThroughOffset() {\n return runner.currentAcknowledgedThroughOffset;\n },\n get currentStreamId() {\n return runner.currentStreamId;\n },\n get currentState() {\n return runner.currentState;\n },\n get isLoaded() {\n return runner.isLoaded;\n },\n };\n // The runner is stored under the type-erased `RegistryEntry` (a map of\n // heterogeneous processors), so the concrete state type re-enters at the\n // overloaded signature: the registered instance's contract carries it\n // and `reads()` promised it there; the name form honestly publishes\n // `unknown` state.\n return reads as RegisteredProcessorReads<any>;\n },\n\n observeStateChanges(processor, observer) {\n const entry = requireEntryForInstance(processor, \"observeStateChanges\");\n // The instance-identity lookup restores the relationship erased by the\n // registry's heterogeneous entry map: this runner and observer share the\n // state type carried by the exact registered processor instance.\n return entry.runner.observeStateChanges(\n observer as (snapshot: { offset: number; state: unknown }) => void,\n );\n },\n\n // Catch-up failures — availability and application alike — propagate to\n // the caller unretried: the door that called into this DO owns the one\n // idempotent replay, and a swallowed failure here would serve stale\n // state as success.\n async catchUp(name: string): Promise<void> {\n await requireEntry(name).runner.catchUp();\n },\n\n resetRecoveryBackoff(name: string): void {\n requireEntry(name).recovery?.resetBackoff?.();\n },\n\n handleAlarm(alarmInfo) {\n return tracing.enterSpan(\"alarm processor keepalive\", async (span) => {\n // Entering alarm() means the platform consumed the durable alarm:\n // whatever we believed was armed no longer is, and every reconcile\n // from here must re-issue rather than skip as \"unchanged\".\n platformAlarmAtMs = null;\n // Every DUE desire is dropped, not just the inherited one: the slice\n // that caused this fire is delivered — its owner re-derives and\n // re-arms during this very turn (a keepalive synchronously in\n // onAlarm; the scheduler at the end of its body). Keeping a due\n // desire would re-arm the just-consumed alarm IN THE PAST and refire\n // it concurrently with the handler body still running.\n const firedAt = now();\n for (const [name, atMs] of alarmSlices) {\n if (atMs <= firedAt) alarmSlices.delete(name);\n }\n span.setAttribute(\"iterate.alarm.kind\", \"processor_keepalive\");\n if (alarmInfo !== undefined) {\n span.setAttribute(\"iterate.alarm.is_retry\", alarmInfo.isRetry);\n span.setAttribute(\"iterate.alarm.retry_count\", alarmInfo.retryCount);\n }\n try {\n // EVERY runner gets the fire — each keepalive self-gates on its own\n // persisted armed time, so a foreign fire is a no-op. Failures are\n // collected (never short-circuit: the runners behind a throwing one\n // still need their fire) and rethrown after the loop so the\n // platform retries the handler; retried fires are safe for runners\n // that already handled theirs (self-gated again).\n const failures: unknown[] = [];\n for (const [name, entry] of entries) {\n try {\n await entry.runner.handleAlarm(alarmInfo);\n } catch (error) {\n console.error(`stream processor \"${name}\" alarm handling failed`, error);\n failures.push(error);\n }\n }\n if (failures.length > 0) throw failures[0];\n } finally {\n // Awaited AND rethrown: the platform only retries an alarm whose\n // handler THREW. Resolving with the re-arm still queued (or\n // silently failed) would consume the alarm for good — an eviction\n // in that window loses the only thing that revives this DO.\n await reconcileAlarm();\n }\n });\n },\n\n setAlarmSlice,\n getAlarmSlice: (name) => alarmSlices.get(name) ?? null,\n\n async wakeStreamProcessor(args) {\n // Coordinate fence. A wake is only legitimate from the EXACT stream this\n // registry hosts, `(projectId, path)`. The wake is a trusted-internal\n // RPC, but a stale, malformed, hand-configured, or copied subscription\n // can still target this registry's slug from a DIFFERENT coordinate —\n // and the stream event sender would invoke it. Without this check the mismatch\n // is accepted: foreign events fold into this processor's state, its\n // consequences run against this processor's fixed Stream capability, and\n // its checkpoint advances on foreign offsets. Reject before resolving the\n // processor or opening delivery. (Selecting by name alone is the gap\n // this closes — a name is not unique across streams.)\n if (args.stream.projectId !== options.projectId || args.stream.path !== options.path) {\n throw new Error(\n `wakeStreamProcessor coordinate mismatch: wake for ${args.stream.projectId ?? \"null\"}:${args.stream.path} does not match registry ${options.projectId ?? \"null\"}:${options.path}`,\n );\n }\n const name = resolveProcessorName(args);\n const entry = requireEntry(name);\n if (!z.uuid().safeParse(args.stream.streamId).success) {\n throw new Error(`wakeStreamProcessor streamId must be a UUID`);\n }\n // The runner owns frame serialization, offset dedupe, and whole-attempt\n // keepalive. The hosted source owns catch-up: it scans every raw offset\n // and sends empty frames for configured-filter gaps, so an unfiltered\n // runner pull would bypass that filter. The registry otherwise adds only\n // the transport boundary: the stream's callback call returns\n // immediately, while this DO reports the eventual attempt outcome\n // through the batch's independent one-shot capability.\n //\n // That separation is load-bearing. Processor blockers routinely append\n // back to the same stream that delivered them. Returning `attempt` from\n // this RPC makes the stream pull a result that cannot settle until the\n // nested append reaches the stream again — a cyclic actor-drain tree\n // that workerd can retain until idle teardown.\n const opened = await entry.runner.openHostedEventBatchCallback(args.stream.streamId);\n const processEventBatch = (batch: StreamWakeEventBatch) => {\n const { reportDeliveryResult, ...frame } = batch;\n if (\n frame.projectId !== options.projectId ||\n frame.path !== options.path ||\n frame.streamId !== args.stream.streamId\n ) {\n throw new Error(\n `hosted processor \"${name}\" received batch for ${frame.projectId ?? \"null\"}:${frame.path}:${frame.streamId}; ` +\n `expected ${options.projectId ?? \"null\"}:${options.path}:${args.stream.streamId}`,\n );\n }\n\n let retainedResultCallback;\n try {\n retainedResultCallback = retainCallback<StreamWakeDeliveryResult>(reportDeliveryResult);\n } catch (error) {\n // Processing a batch that can never report its result would strand\n // the source's pending attempt. Leave the processor checkpoint\n // untouched so the source watchdog can wake it again.\n console.error(\"stream wake delivery result callback could not be retained\", {\n error,\n });\n return;\n }\n\n let attempt: Promise<void>;\n try {\n attempt = opened.processEventBatch(frame satisfies StreamEventBatch);\n } catch (error) {\n attempt = Promise.reject(error);\n }\n const report = attempt.then(\n () =>\n reportWakeDeliveryResult(retainedResultCallback, {\n outcome: \"ok\",\n }),\n (error: unknown) =>\n reportWakeDeliveryResult(retainedResultCallback, {\n outcome: \"error\",\n error: serializeWakeDeliveryError(error),\n }),\n );\n ctx.waitUntil(\n report.finally(() => {\n try {\n retainedResultCallback[Symbol.dispose]();\n } catch (error) {\n console.warn(\"stream wake delivery result callback disposal failed\", {\n error,\n });\n }\n }),\n );\n };\n // The capability assembles runtime state from its two honest sources:\n // the SNAPSHOT from the runner (the cursor owner) and the runtime bag +\n // metrics from the processor. Same Cloudflare clock domain, so the\n // ping's one-way estimate is omitted and the clock-offset estimate is\n // ~zero.\n const capabilities = hostRuntimeCapabilities(entry.processor, {\n now,\n snapshot: () => entry.runner.snapshot(),\n });\n return {\n streamId: args.stream.streamId,\n // The PROCESSING cursor — the stream persists this as its delivery\n // checkpoint, and a reduction-pinned offset could skip events whose\n // effects were never acknowledged (codex review §2).\n checkpointOffset: opened.checkpointOffset,\n processEventBatch,\n openedBy: {\n processor: { announcement: announceContract(entry.processor.contract) },\n },\n ...capabilities,\n };\n },\n };\n}\n","// Facet hosting for stream processors: the SAME `createStreamProcessorRegistry`\n// machinery a processor-hosting Durable Object runs, placed inside a Durable\n// Object FACET of the stream it serves (tasks/stream-processors-as-facets.md).\n// Checkpoints and projections land in the facet's own private SQLite under the\n// standard keys; the ONLY adaptation between placements is durable alarms:\n// workerd does not implement alarms for facets (workerd#6810 — a facet\n// `setAlarm` even appears to succeed locally, then poisons the facet's output\n// gate), so the parent keeps the real platform alarm on the facet's behalf and\n// the facet dials three proxy verbs on it. Everything else is verbatim.\n//\n// Identity follows the creation-is-an-event doctrine adapted to facets: a\n// facet can never receive constructor arguments from its parent, so its\n// coordinate — parent Durable Object name, project, stream path — arrives\n// through a first-contact `configure()` call and is stashed durably in the\n// facet's own kv. Every later incarnation (including the fresh one a replayed\n// alarm boots) reconstructs its host from that stash alone.\n\nimport { DurableObject } from \"cloudflare:workers\";\nimport type { LiveStateCursor } from \"../sdk/capnweb/live-state/protocol.ts\";\nimport type { LiveStateRpc } from \"../sdk/capnweb/live-state/types.ts\";\nimport { disposeIgnoredRpcResult } from \"../sdk/capnweb/live-state/retain.ts\";\nimport type { ProcessorStream } from \"./stream-handle.ts\";\nimport type { MaybePromise } from \"./stream-processor.ts\";\nimport type {\n ProcessorRuntimeState,\n ProcessorSnapshot,\n StreamProcessorWakeRequest,\n StreamProcessorWakeResponse,\n} from \"./rpc-types.ts\";\nimport {\n createStreamProcessorRegistry,\n type StreamProcessorRegistry,\n} from \"./stream-processor-registry.ts\";\n\n/**\n * Where the configured identity lives in the facet's own kv. Exported so a\n * subclass's own doors can self-heal a fresh incarnation (re-run the\n * idempotent `configure` from the stash) before the base's boot microtask has\n * run — see apps/os `ProcessorFacet.#requireRegistry`.\n */\nexport const FACET_IDENTITY_KEY = \"iterate:processor-facet:identity\";\n\n/**\n * The identity a {@link ProcessorFacet} is configured with on first contact —\n * stashed durably in the facet's own kv, never passed again. `path` +\n * `projectId` are the registry's wake coordinate fence; `parentName` is how\n * the facet dials BACK to the Durable Object hosting it (the Stream DO) for\n * the alarm proxy.\n */\nexport type ProcessorFacetIdentity = {\n /** Durable Object name of the hosting parent (the Stream DO). */\n parentName: string;\n /** Owning project of the hosted stream, or null on a deployment-global stream. */\n projectId: string | null;\n /** Path of the hosted stream. */\n path: string;\n};\n\n/**\n * The three parent-side alarm doors a facet dials in place of its own\n * (unimplemented) `ctx.storage` alarm verbs. The parent implements them over\n * its REAL platform alarm and replays each fire into the facet's\n * {@link ProcessorFacet.handleAlarm}. The parent's implementations MUST\n * tolerate being called reentrantly while the parent itself is still awaiting\n * `handleAlarm` — the keepalive re-arms from inside its own alarm turn.\n */\nexport type ProcessorFacetAlarmProxy = {\n proxySetAlarm(scheduledTimeMs: number): MaybePromise<unknown>;\n proxyDeleteAlarm(): MaybePromise<unknown>;\n proxyGetAlarm(): MaybePromise<number | null>;\n};\n\n/**\n * Everything app-specific about one facet host, derived from the stashed\n * identity by {@link ProcessorFacet.createHost}: the stream handle processors\n * append through, the worker deploy version (keepalive crash-loop budget\n * reset), and the per-host processor composition — the subclass constructs its\n * processors here and registers each under its subscription name.\n */\nexport type ProcessorFacetHost = {\n /** The hosted stream — how processors append/read (colocated: a dial back\n * to the parent Stream DO's stream surface). */\n stream: ProcessorStream;\n /** Worker deploy version — pass this worker's build identity. A change\n * resets each keepalive's crash-loop budget (the antidote deploy). */\n version: string;\n /** Injected clock for tests; production omits it (Date.now). */\n now?: () => number;\n /** Assemble this node's live state; omit for the primary runner's fold. */\n getLiveState?: () => Record<string, unknown>;\n /** Construct and register this host's processors (`registry.register(new\n * XProcessor({...}), { recovery, name })`) — called once, right after the\n * registry is built. Per-processor recovery stays the author's explicit\n * choice, exactly as on a hosting DO. */\n registerProcessors(registry: StreamProcessorRegistry): void;\n};\n\n/**\n * A view of `target` with `overrides` in front and everything else passed\n * through. Proxies (not spreads or Object.create) because DurableObjectState\n * and DurableObjectStorage are host objects: their methods must be invoked\n * with the REAL receiver or workerd throws \"Illegal invocation\". (The same\n * overlay as sdk.ts's `selfAlarmState` facade — duplicated here because the\n * sdk entry drags its whole dependency graph along.)\n */\nfunction overlay<T extends object>(target: T, overrides: Record<PropertyKey, unknown>): T {\n return new Proxy(target, {\n get(object, prop) {\n // Own keys only: `in` would match Object.prototype inherits\n // (toString, …) and shadow the host object's.\n if (Object.hasOwn(overrides, prop)) return overrides[prop];\n const value = Reflect.get(object, prop, object);\n return typeof value === \"function\" ? value.bind(object) : value;\n },\n });\n}\n\n/**\n * A facet's `DurableObjectState` facade for `createStreamProcessorRegistry`:\n * ONLY `storage.setAlarm` / `storage.deleteAlarm` / `storage.getAlarm` are\n * overridden to dial the parent's {@link ProcessorFacetAlarmProxy}; kv,\n * waitUntil, and everything else pass through untouched. `parentAlarms` is\n * invoked PER CALL — the parent stub must be resolved lazily from the stashed\n * identity, because the recovery adapter's boot reconcile issues alarm calls\n * at construction and a stub captured once would outlive its RPC session.\n */\nexport function facetProcessorDurableObjectState(\n ctx: DurableObjectState,\n parentAlarms: () => ProcessorFacetAlarmProxy,\n): DurableObjectState {\n const storage = overlay(ctx.storage, {\n setAlarm: async (scheduledTime: number | Date) => {\n disposeIgnoredRpcResult(\n await parentAlarms().proxySetAlarm(\n typeof scheduledTime === \"number\" ? scheduledTime : scheduledTime.getTime(),\n ),\n );\n },\n deleteAlarm: async () => {\n disposeIgnoredRpcResult(await parentAlarms().proxyDeleteAlarm());\n },\n getAlarm: async () => await parentAlarms().proxyGetAlarm(),\n });\n return overlay(ctx, { storage });\n}\n\n/**\n * Plain-copy an `AlarmInvocationInfo` before a facet hop. The platform hands\n * the parent's `alarm()` a host object that does not serialize across RPC;\n * a parent replaying a fire into {@link ProcessorFacet.handleAlarm} must send\n * this copy instead.\n */\nexport function plainAlarmInvocationInfo(\n info: AlarmInvocationInfo | undefined,\n): AlarmInvocationInfo | undefined {\n if (info === undefined) return undefined;\n // scheduledTime is absent from this package's ambient AlarmInvocationInfo\n // but present at runtime (and in apps/os's patched types) — carry it through.\n const { scheduledTime } = info as { scheduledTime?: number };\n return {\n ...(scheduledTime === undefined ? {} : { scheduledTime }),\n isRetry: info.isRetry,\n retryCount: info.retryCount,\n } as AlarmInvocationInfo;\n}\n\n/**\n * Generic base for hosting stream processors in a Durable Object facet.\n * Subclasses are the per-host composition (the facets task's target shape) and\n * supply exactly two things: how to dial the parent's alarm proxy and what\n * this host runs —\n *\n * ```ts\n * export class AgentProcessors extends ProcessorFacet<Env> {\n * protected parentAlarms({ parentName }: ProcessorFacetIdentity) {\n * return this.env.STREAM.getByName(parentName);\n * }\n * protected createHost({ path, projectId }: ProcessorFacetIdentity): ProcessorFacetHost {\n * const stream = ...; // dial the parent stream\n * return {\n * stream,\n * version: workerVersion(this.env),\n * registerProcessors: (registry) => {\n * registry.register(\n * new AgentProcessor({ stream, path, projectId, ... }),\n * { recovery: true, name: \"agent\" },\n * );\n * },\n * };\n * }\n * }\n * ```\n *\n * The parent creates it with `ctx.facets.get(name, () => ({ class:\n * ctx.exports.AgentProcessors }))`, calls `configure()` once (idempotent), and\n * routes wakes/alarms/doors to the RPC surface below.\n *\n * THIS CLASS MUST NEVER DEFINE `alarm()` — and neither may a subclass. The\n * fire arrives as `handleAlarm` (an ordinary RPC verb) instead: workerd\n * reserves `alarm` for its native handler, and with one present a failed\n * native `setAlarm` poisons the facet's output gate (workerd#6810). The\n * constructor enforces this.\n */\nexport abstract class ProcessorFacet<Env = unknown> extends DurableObject<Env> {\n #host: { registry: StreamProcessorRegistry } | undefined;\n\n constructor(ctx: DurableObjectState, env: Env) {\n super(ctx, env);\n if (\"alarm\" in this && typeof this.alarm === \"function\") {\n throw new Error(\n `${this.constructor.name} must not define alarm(): facets have no native alarms ` +\n `(workerd#6810 — a failed setAlarm would poison this facet's output gate). ` +\n `The parent's fire arrives as handleAlarm() instead.`,\n );\n }\n // Boot reconcile: a configured facet rebuilds its host as soon as the\n // incarnation exists — the recovery adapters re-issue any persisted alarm\n // desire (the lost-platform-alarm heal), through the parent proxy. Wrapped in\n // a microtask so the SUBCLASS constructor has finished before its hooks\n // run; failures here only defer construction to the first RPC verb.\n void Promise.resolve().then(() => {\n try {\n if (this.#readIdentity() !== undefined) this.#requireHost();\n } catch (error) {\n console.error(\"ProcessorFacet boot host construction failed\", error);\n }\n });\n }\n\n /**\n * Resolve the parent's alarm-proxy stub for the stashed identity — e.g.\n * `this.env.STREAM.getByName(identity.parentName)`. Called once per alarm\n * verb invocation (stubs must not outlive their call turn).\n */\n protected abstract parentAlarms(identity: ProcessorFacetIdentity): ProcessorFacetAlarmProxy;\n\n /** Build this host's app-specific wiring from the stashed identity — called\n * once per incarnation, lazily on first use. */\n protected abstract createHost(identity: ProcessorFacetIdentity): ProcessorFacetHost;\n\n // ---------------------------------------------------------------------------\n // RPC surface (parent-only callers).\n // ---------------------------------------------------------------------------\n\n /**\n * First-contact identity stash, idempotent: re-configuring with the same\n * identity is a no-op (and ensures the host is built); a DIFFERENT identity\n * throws — a facet's coordinate never changes, so a mismatch is a miswire,\n * not a migration.\n */\n configure(identity: ProcessorFacetIdentity): void {\n const stashed = this.#readIdentity();\n if (stashed !== undefined) {\n if (\n stashed.parentName !== identity.parentName ||\n stashed.projectId !== identity.projectId ||\n stashed.path !== identity.path\n ) {\n throw new Error(\n `ProcessorFacet is configured for ${stashed.projectId ?? \"null\"}:${stashed.path} ` +\n `(parent \"${stashed.parentName}\") and cannot be re-configured for ` +\n `${identity.projectId ?? \"null\"}:${identity.path} (parent \"${identity.parentName}\")`,\n );\n }\n this.#requireHost();\n return;\n }\n // Plain-copy on stash: keep exactly the declared fields, dropping any RPC\n // envelope decoration the argument object carries.\n this.ctx.storage.kv.put(FACET_IDENTITY_KEY, {\n parentName: identity.parentName,\n projectId: identity.projectId,\n path: identity.path,\n } satisfies ProcessorFacetIdentity);\n this.#requireHost();\n }\n\n /** The wake door — the parent's colocated delivery dial. Routes to the\n * registry: name-first resolution, coordinate fence, per-batch settlement\n * through each batch's independent `reportDeliveryResult`. */\n wakeStreamProcessor(request: StreamProcessorWakeRequest): Promise<StreamProcessorWakeResponse> {\n return this.#requireHost().registry.wakeStreamProcessor(request);\n }\n\n /**\n * The parent's alarm replay door — deliberately NOT named `alarm` (see the\n * class doc). The parent plain-copies its `AlarmInvocationInfo`\n * ({@link plainAlarmInvocationInfo}) and awaits this; a rejection propagates\n * so the parent can rethrow and get the platform's alarm retry.\n */\n async handleAlarm(info?: AlarmInvocationInfo): Promise<void> {\n if (this.#readIdentity() === undefined) {\n // No identity means no keepalive record either — nothing to revive. Do\n // not throw: the parent would rethrow into the platform's alarm retry\n // loop with nothing to retry for.\n console.warn(\"ProcessorFacet.handleAlarm before configure(); nothing to revive\");\n return;\n }\n await this.#requireHost().registry.handleAlarm(plainAlarmInvocationInfo(info));\n }\n\n /** One consistent read of a hosted processor's committed fold. `name` may be\n * omitted on a single-processor host. */\n async snapshot(args?: { name?: string }): Promise<ProcessorSnapshot<unknown>> {\n return await this.#reads(args?.name).snapshot();\n }\n\n /** The hosted processor's runtime state (runner snapshot + contributed\n * runtime bag). `name` may be omitted on a single-processor host. */\n async getRuntimeState(args?: { name?: string }): Promise<ProcessorRuntimeState> {\n return await this.#reads(args?.name).getRuntimeState();\n }\n\n /** Resolve once the named processor's acknowledged cursor reaches `offset` —\n * the read-your-writes barrier. The subscription catalog's uniform\n * `waitUntilProcessed` delegates its facet-placed processor rows here. */\n async waitUntilProcessed(args: {\n offset: number;\n timeoutMs?: number;\n name?: string;\n }): Promise<void> {\n const { name, ...input } = args;\n await this.#reads(name).waitUntilEvent(input);\n }\n\n /** Pull the named processor through the durable stream tail — the parent\n * facade's catch-up-before-snapshot leg, dialed before every facet read.\n * `name` may be omitted on a single-processor host. */\n async catchUp(args?: { name?: string }): Promise<void> {\n await this.#reads(args?.name).catchUp();\n }\n\n /** Read a transient snapshot or delta for the parent's current stream lifetime.\n * Cold or replaced processors hydrate from durable progress. Warm reads use\n * committed local state: polling must not call back into the parent stream\n * for every processor while it is delivering events to this facet. */\n async readLiveState(args: { streamId: string; cursor?: LiveStateCursor; patchVersion?: 2 | 3 }) {\n const { registry } = this.#requireHost();\n if (\n registry.names.some((name) => {\n const reads = registry.reads(name);\n return !reads.isLoaded || reads.currentStreamId !== args.streamId;\n })\n ) {\n await registry.loadAndRefreshLive();\n } else {\n registry.refreshLive();\n }\n // An omitted version keeps warm parents on the pre-deploy wire format.\n return registry.live.readSince(args.cursor, { patchVersion: args.patchVersion });\n }\n\n /** Direct subscriptions retain their callbacks across the Workers RPC hop. */\n liveState(): LiveStateRpc<Record<string, unknown>> {\n const { registry } = this.#requireHost();\n return {\n get: async () => {\n await registry.loadAndRefreshLive();\n return registry.live.getState();\n },\n subscribe: async (onUpdate, options) => {\n await registry.loadAndRefreshLive();\n const subscription = registry.live.subscribe(onUpdate, options);\n return {\n ping: () => subscription.ping(),\n unsubscribe: () => subscription.unsubscribe(),\n [Symbol.dispose]: () => subscription.unsubscribe(),\n };\n },\n };\n }\n\n // ---------------------------------------------------------------------------\n // Internals.\n // ---------------------------------------------------------------------------\n\n #readIdentity(): ProcessorFacetIdentity | undefined {\n return this.ctx.storage.kv.get<ProcessorFacetIdentity>(FACET_IDENTITY_KEY);\n }\n\n #requireIdentity(): ProcessorFacetIdentity {\n const identity = this.#readIdentity();\n if (identity === undefined) {\n throw new Error(\"ProcessorFacet has no stashed identity yet — call configure() first\");\n }\n return identity;\n }\n\n #requireHost(): { registry: StreamProcessorRegistry } {\n if (this.#host === undefined) {\n const identity = this.#requireIdentity();\n const host = this.createHost(identity);\n const registry = createStreamProcessorRegistry(\n // The alarm facade re-reads the stashed identity PER CALL (see\n // facetProcessorDurableObjectState): recovery's boot reconcile dials\n // it during this very construction.\n facetProcessorDurableObjectState(this.ctx, () =>\n this.parentAlarms(this.#requireIdentity()),\n ),\n {\n stream: host.stream,\n path: identity.path,\n projectId: identity.projectId,\n version: host.version,\n ...(host.now === undefined ? {} : { now: host.now }),\n ...(host.getLiveState === undefined ? {} : { getLiveState: host.getLiveState }),\n },\n );\n host.registerProcessors(registry);\n this.#host = { registry };\n }\n return this.#host;\n }\n\n #reads(name: string | undefined) {\n const { registry } = this.#requireHost();\n if (name !== undefined) return registry.reads(name);\n const names = registry.names;\n if (names.length === 1) return registry.reads(names[0]!);\n throw new Error(\n `this facet hosts ${names.length} processors (${names.join(\", \") || \"none\"}); pass a name`,\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
import { h as defineProcessorContract } from "./stream-processor-keepalive-DAQTP6m3.mjs";
|
|
2
|
-
import "./processors.mjs";
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
//#region ../shared/src/test-support/flake-suite-summary.ts
|
|
5
|
-
/** A full CI suite publishes this even when its flake record list is empty. */
|
|
6
|
-
const FlakeSuiteSummary = z.object({
|
|
7
|
-
headSha: z.string().min(1),
|
|
8
|
-
branch: z.string(),
|
|
9
|
-
status: z.enum(["complete", "incomplete"]),
|
|
10
|
-
startedAt: z.iso.datetime(),
|
|
11
|
-
finishedAt: z.iso.datetime(),
|
|
12
|
-
testCount: z.number().int().nonnegative(),
|
|
13
|
-
tests: z.array(z.object({
|
|
14
|
-
name: z.string().min(1),
|
|
15
|
-
outcome: z.enum([
|
|
16
|
-
"pass",
|
|
17
|
-
"fail",
|
|
18
|
-
"skip"
|
|
19
|
-
])
|
|
20
|
-
})).optional(),
|
|
21
|
-
unknownFlakeCount: z.number().int().nonnegative(),
|
|
22
|
-
failedCount: z.number().int().nonnegative(),
|
|
23
|
-
diagnostics: z.array(z.string()),
|
|
24
|
-
runUrl: z.url()
|
|
25
|
-
}).refine((summary) => summary.status !== "complete" || summary.testCount > 0 && !!summary.branch && summary.diagnostics.length === 0, "A complete suite needs executed tests and no missing-result diagnostics");
|
|
26
|
-
//#endregion
|
|
27
|
-
//#region src/starter-apps/flake-dashboard/contract.ts
|
|
28
|
-
const flakeEventTypes = {
|
|
29
|
-
created: "events.iterate.com/flakes/created",
|
|
30
|
-
runRecorded: "events.iterate.com/flakes/run-recorded",
|
|
31
|
-
transitionProposed: "events.iterate.com/flakes/transition-proposed",
|
|
32
|
-
dashboardRenderSettled: "events.iterate.com/flakes/dashboard-render-settled"
|
|
33
|
-
};
|
|
34
|
-
const StreamOffset = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
35
|
-
/**
|
|
36
|
-
* One `createFlake` test outcome. Mirrors `FlakeRecord` in
|
|
37
|
-
* `@iterate-com/shared/test-support/flake-test` — the wrapper writes these
|
|
38
|
-
* lines to `FLAKE_RECORD_DIR` and CI ships them here verbatim.
|
|
39
|
-
*/
|
|
40
|
-
const FlakeOutcome = z.enum([
|
|
41
|
-
"pass",
|
|
42
|
-
"flake-fail",
|
|
43
|
-
"unexpected-error",
|
|
44
|
-
"pinned-fail",
|
|
45
|
-
"unexpected-pass",
|
|
46
|
-
"retried-pass"
|
|
47
|
-
]);
|
|
48
|
-
/**
|
|
49
|
-
* Which wrapper (or reporter) produced a record: createFlake, createFailing,
|
|
50
|
-
* or the telemetry reporters' retried-pass records for tests nobody has
|
|
51
|
-
* classified yet. Old events predate the field — they were all createFlake.
|
|
52
|
-
*/
|
|
53
|
-
const FlakeKind = z.enum([
|
|
54
|
-
"flake",
|
|
55
|
-
"failing",
|
|
56
|
-
"unknown"
|
|
57
|
-
]);
|
|
58
|
-
const FlakeRecord = z.object({
|
|
59
|
-
name: z.string().min(1).max(1e3),
|
|
60
|
-
kind: FlakeKind.default("flake"),
|
|
61
|
-
outcome: FlakeOutcome,
|
|
62
|
-
pattern: z.string().min(1).max(2e3).optional(),
|
|
63
|
-
durationMs: z.number().nonnegative(),
|
|
64
|
-
at: z.string().min(1),
|
|
65
|
-
error: z.string().max(4e3).optional()
|
|
66
|
-
});
|
|
67
|
-
const FlakeDashboardConfig = z.object({
|
|
68
|
-
repository: z.object({
|
|
69
|
-
owner: z.string().min(1),
|
|
70
|
-
repo: z.string().min(1)
|
|
71
|
-
}),
|
|
72
|
-
issueTitle: z.string().min(1).max(200),
|
|
73
|
-
defaultBranch: z.string().min(1)
|
|
74
|
-
});
|
|
75
|
-
const FlakeRunRecorded = z.object({
|
|
76
|
-
runId: z.string().min(1).max(200),
|
|
77
|
-
suite: z.string().min(1).max(200),
|
|
78
|
-
branch: z.string().min(1).max(500),
|
|
79
|
-
commit: z.string().min(1).max(100),
|
|
80
|
-
records: z.array(FlakeRecord).max(1e4),
|
|
81
|
-
summary: FlakeSuiteSummary.optional()
|
|
82
|
-
});
|
|
83
|
-
const MainSuiteRun = z.object({
|
|
84
|
-
runId: z.string(),
|
|
85
|
-
commit: z.string(),
|
|
86
|
-
summary: FlakeSuiteSummary
|
|
87
|
-
});
|
|
88
|
-
const FlakeTransition = z.enum([
|
|
89
|
-
"unwrap",
|
|
90
|
-
"switch-to-failing",
|
|
91
|
-
"unwrap-failing"
|
|
92
|
-
]);
|
|
93
|
-
const FlakeTransitionProposed = z.object({
|
|
94
|
-
testName: z.string().min(1),
|
|
95
|
-
transition: FlakeTransition,
|
|
96
|
-
evidence: z.object({
|
|
97
|
-
consecutiveRuns: z.number().int().positive(),
|
|
98
|
-
firstAt: z.string().min(1),
|
|
99
|
-
lastAt: z.string().min(1)
|
|
100
|
-
})
|
|
101
|
-
});
|
|
102
|
-
const FlakeDashboardRenderResult = z.discriminatedUnion("status", [z.object({
|
|
103
|
-
status: z.literal("succeeded"),
|
|
104
|
-
issueNumber: z.number().int().positive(),
|
|
105
|
-
issueUrl: z.string().url()
|
|
106
|
-
}), z.object({
|
|
107
|
-
status: z.literal("failed"),
|
|
108
|
-
error: z.string().min(1).max(8e3)
|
|
109
|
-
})]);
|
|
110
|
-
/**
|
|
111
|
-
* A run of consecutive same-outcome recorded runs on the default branch.
|
|
112
|
-
* `unexpected-error` outcomes and outcome changes reset it. The streak is the
|
|
113
|
-
* whole input to transition proposals, so it lives in reduced state rather
|
|
114
|
-
* than being recomputed from history.
|
|
115
|
-
*/
|
|
116
|
-
const DefaultBranchStreak = z.object({
|
|
117
|
-
outcome: FlakeOutcome,
|
|
118
|
-
runs: z.number().int().positive(),
|
|
119
|
-
firstAt: z.string().min(1),
|
|
120
|
-
lastAt: z.string().min(1)
|
|
121
|
-
});
|
|
122
|
-
const TrackedTest = z.object({
|
|
123
|
-
/** Latest record's kind wins: adopting an unknown flake into createFlake migrates its row. */
|
|
124
|
-
kind: FlakeKind.default("flake"),
|
|
125
|
-
/** Empty for kind "unknown" — those rows show error samples instead. */
|
|
126
|
-
pattern: z.string().default(""),
|
|
127
|
-
suites: z.array(z.string()).default([]),
|
|
128
|
-
/**
|
|
129
|
-
* Per suite, the offset of the newest run-recorded event (any branch) whose
|
|
130
|
-
* records included this test. Compared against the suite's
|
|
131
|
-
* `recentRunOffsets` window at render time: a test absent from all of its
|
|
132
|
-
* suite's last few ingested runs is retired from the table — hidden, not
|
|
133
|
-
* deleted, so a transient absence self-heals on the next record.
|
|
134
|
-
*/
|
|
135
|
-
lastSeenOffset: z.record(z.string(), StreamOffset).default({}),
|
|
136
|
-
/**
|
|
137
|
-
* The latest (up to) 10 outcomes on any branch, ordered by test time — the
|
|
138
|
-
* render's emoji streak bar, each entry carrying the commit that produced
|
|
139
|
-
* it so the square can link straight to that commit's checks. All branches,
|
|
140
|
-
* like the counts, for debugging PR failures too. The numeric
|
|
141
|
-
* defaultBranchStreak below stays main-only and carries the
|
|
142
|
-
* transition-threshold counts past what 10 entries can show.
|
|
143
|
-
*/
|
|
144
|
-
recent: z.array(z.object({
|
|
145
|
-
outcome: FlakeOutcome,
|
|
146
|
-
commit: z.string().min(1).max(100),
|
|
147
|
-
at: z.string()
|
|
148
|
-
})).max(10).default([]),
|
|
149
|
-
/** Keyed by outcome value ("pass", "pinned-fail", …). */
|
|
150
|
-
counts: z.record(z.string(), z.number().int().nonnegative()).default({}),
|
|
151
|
-
/**
|
|
152
|
-
* The last few error samples worth showing (retried-pass and
|
|
153
|
-
* unexpected-error records) — for unknown flakes these are the copy-paste
|
|
154
|
-
* material for the createFlake pattern.
|
|
155
|
-
*/
|
|
156
|
-
recentErrors: z.array(z.object({
|
|
157
|
-
error: z.string().max(4e3),
|
|
158
|
-
commit: z.string(),
|
|
159
|
-
at: z.string()
|
|
160
|
-
})).max(3).default([]),
|
|
161
|
-
lastFlakeAt: z.string().nullable().default(null),
|
|
162
|
-
firstRecordedAt: z.string(),
|
|
163
|
-
lastRecordedAt: z.string(),
|
|
164
|
-
defaultBranchStreak: DefaultBranchStreak.nullable().default(null),
|
|
165
|
-
/** Older retry evidence cannot undo a wrapper observed on main in this suite. */
|
|
166
|
-
lastMainWrapperAt: z.record(z.string(), z.string()).default({}),
|
|
167
|
-
/**
|
|
168
|
-
* One entry per proposal already made, keyed `${transition}:${streak.firstAt}`
|
|
169
|
-
* — a streak proposes at most once however long it grows.
|
|
170
|
-
*/
|
|
171
|
-
proposed: z.array(z.string()).default([])
|
|
172
|
-
});
|
|
173
|
-
const FlakeDashboardState = z.object({
|
|
174
|
-
birthCertificate: z.object({ config: FlakeDashboardConfig }).nullable().default(null),
|
|
175
|
-
tests: z.record(z.string(), TrackedTest).default({}),
|
|
176
|
-
/**
|
|
177
|
-
* Main-only unknowns, isolated by suite. Healthy rows are hidden, retaining
|
|
178
|
-
* their streak so late failures can correct an apparent recovery.
|
|
179
|
-
*/
|
|
180
|
-
unknownFlakes: z.record(z.string(), z.record(z.string(), z.object({
|
|
181
|
-
record: FlakeRecord,
|
|
182
|
-
passStreak: z.number().int().nonnegative(),
|
|
183
|
-
/** Newest run that actually contained this test, including skips. */
|
|
184
|
-
lastRunAt: z.string(),
|
|
185
|
-
recent: z.array(z.object({
|
|
186
|
-
outcome: FlakeOutcome,
|
|
187
|
-
commit: z.string(),
|
|
188
|
-
at: z.string()
|
|
189
|
-
})).max(10)
|
|
190
|
-
}))).default({}),
|
|
191
|
-
mainRuns: z.record(z.string(), z.object({
|
|
192
|
-
latest: MainSuiteRun,
|
|
193
|
-
complete: MainSuiteRun.nullable(),
|
|
194
|
-
inventory: z.object({
|
|
195
|
-
startedAt: z.iso.datetime(),
|
|
196
|
-
names: z.array(z.string())
|
|
197
|
-
}).nullable().default(null)
|
|
198
|
-
})).default({}),
|
|
199
|
-
/**
|
|
200
|
-
* The newest three ingested results across all branches retire absent
|
|
201
|
-
* tracked tests. This preserves visibility during partial PR runs. Unknown
|
|
202
|
-
* flakes retire after 20 main passes, wrapper adoption, or proven absence
|
|
203
|
-
* from their suite's full main inventory.
|
|
204
|
-
*/
|
|
205
|
-
suites: z.record(z.string(), z.object({ recentRunOffsets: z.array(StreamOffset).max(3).default([]) })).default({}),
|
|
206
|
-
/**
|
|
207
|
-
* Offset of the newest reduced DATA event (created / run-recorded /
|
|
208
|
-
* transition-proposed). Render settlements deliberately do not bump it —
|
|
209
|
-
* that is what stops a settled render from demanding another render.
|
|
210
|
-
*/
|
|
211
|
-
lastDataOffset: StreamOffset.default(0),
|
|
212
|
-
render: z.object({
|
|
213
|
-
throughOffset: StreamOffset,
|
|
214
|
-
issueNumber: z.number().int().positive().nullable(),
|
|
215
|
-
issueUrl: z.string().nullable()
|
|
216
|
-
}).nullable().default(null)
|
|
217
|
-
});
|
|
218
|
-
/**
|
|
219
|
-
* Suggest unwrapping createFlake after 20 consecutive main passes, regardless
|
|
220
|
-
* of elapsed time. Unknown flakes retire automatically at the same count.
|
|
221
|
-
* Propose createFailing after 25 matched failures over >=2 days.
|
|
222
|
-
* Tunable constants. Sentinel tests are excluded from proposals entirely —
|
|
223
|
-
* they are designed to flake.
|
|
224
|
-
*/
|
|
225
|
-
const flakeTransitionThresholds = {
|
|
226
|
-
unwrap: {
|
|
227
|
-
runs: 20,
|
|
228
|
-
minSpanMs: 0
|
|
229
|
-
},
|
|
230
|
-
"switch-to-failing": {
|
|
231
|
-
runs: 25,
|
|
232
|
-
minSpanMs: 2880 * 60 * 1e3
|
|
233
|
-
},
|
|
234
|
-
"unwrap-failing": {
|
|
235
|
-
runs: 10,
|
|
236
|
-
minSpanMs: 2880 * 60 * 1e3
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
/**
|
|
240
|
-
* The exact shape of a delivered event this app ingests: a platform-verified
|
|
241
|
-
* GitHub webhook for a COMPLETED check_run on a connection stream. This
|
|
242
|
-
* repo's test suites run on Depot CI, whose jobs are GitHub check runs (NOT
|
|
243
|
-
* GitHub Actions workflow runs — `workflow_run` never fires for them). Zod
|
|
244
|
-
* strips the rest of GitHub's (huge) payload; only these fields are read.
|
|
245
|
-
*/
|
|
246
|
-
const CheckRunWebhookEvent = z.object({
|
|
247
|
-
type: z.literal("events.iterate.com/github/webhook-received"),
|
|
248
|
-
path: z.string().regex(/^\/integrations\/github\/[^/]+$/),
|
|
249
|
-
payload: z.object({
|
|
250
|
-
delivery: z.object({ name: z.literal("check_run") }),
|
|
251
|
-
body: z.object({
|
|
252
|
-
action: z.literal("completed"),
|
|
253
|
-
check_run: z.object({
|
|
254
|
-
conclusion: z.enum(["success", "failure"]),
|
|
255
|
-
head_sha: z.string().min(1),
|
|
256
|
-
check_suite: z.object({ head_branch: z.string().nullish() }).optional()
|
|
257
|
-
}),
|
|
258
|
-
repository: z.object({
|
|
259
|
-
name: z.string().min(1),
|
|
260
|
-
owner: z.object({ login: z.string().min(1) }),
|
|
261
|
-
default_branch: z.string().nullish()
|
|
262
|
-
})
|
|
263
|
-
})
|
|
264
|
-
})
|
|
265
|
-
});
|
|
266
|
-
const FlakeDashboardProcessorContract = defineProcessorContract({
|
|
267
|
-
slug: "flake-dashboard",
|
|
268
|
-
version: "0.8.0",
|
|
269
|
-
description: "Folds createFlake test outcomes reported by CI into per-test flake stats, renders the GitHub 'Flake dashboard' issue, and proposes data-provable lifecycle transitions.",
|
|
270
|
-
stateSchema: FlakeDashboardState,
|
|
271
|
-
events: {
|
|
272
|
-
[flakeEventTypes.created]: {
|
|
273
|
-
description: "The flake dashboard exists: target repository, issue title, and which branch counts for transitions.",
|
|
274
|
-
payloadSchema: z.object({ config: FlakeDashboardConfig }),
|
|
275
|
-
examples: [{
|
|
276
|
-
description: "The dogfood dashboard for this repo.",
|
|
277
|
-
payload: { config: {
|
|
278
|
-
repository: {
|
|
279
|
-
owner: "iterate",
|
|
280
|
-
repo: "iterate"
|
|
281
|
-
},
|
|
282
|
-
issueTitle: "Flake dashboard",
|
|
283
|
-
defaultBranch: "main"
|
|
284
|
-
} }
|
|
285
|
-
}]
|
|
286
|
-
},
|
|
287
|
-
[flakeEventTypes.runRecorded]: {
|
|
288
|
-
description: "One CI run+suite's createFlake outcomes, appended by the CI reporter script (never by this processor). Idempotency-keyed on run+suite so CI retries cannot double-count.",
|
|
289
|
-
payloadSchema: FlakeRunRecorded
|
|
290
|
-
},
|
|
291
|
-
[flakeEventTypes.transitionProposed]: {
|
|
292
|
-
description: "A test's default-branch streak crossed a lifecycle threshold; downstream automation (an agent) should open the unwrap / switch-to-failing PR. The file-edit guard (a streak is only trustworthy if the test file did not change during it) is applied by that agent, which can read git history — the fold cannot.",
|
|
293
|
-
payloadSchema: FlakeTransitionProposed
|
|
294
|
-
},
|
|
295
|
-
[flakeEventTypes.dashboardRenderSettled]: {
|
|
296
|
-
description: "Terminal fact for one dashboard render attempt: the GitHub issue reached (or the error), and the data offset it covered.",
|
|
297
|
-
payloadSchema: z.object({
|
|
298
|
-
throughOffset: StreamOffset,
|
|
299
|
-
result: FlakeDashboardRenderResult
|
|
300
|
-
})
|
|
301
|
-
}
|
|
302
|
-
},
|
|
303
|
-
consumes: [...Object.values(flakeEventTypes)],
|
|
304
|
-
emits: [flakeEventTypes.transitionProposed, flakeEventTypes.dashboardRenderSettled]
|
|
305
|
-
});
|
|
306
|
-
//#endregion
|
|
307
|
-
export { FlakeKind as a, FlakeTransition as c, FlakeSuiteSummary as d, FlakeDashboardState as i, flakeEventTypes as l, FlakeDashboardConfig as n, FlakeOutcome as o, FlakeDashboardProcessorContract as r, FlakeRecord as s, CheckRunWebhookEvent as t, flakeTransitionThresholds as u };
|
|
308
|
-
|
|
309
|
-
//# sourceMappingURL=contract-s4FW4eES.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contract-s4FW4eES.mjs","names":[],"sources":["../../shared/src/test-support/flake-suite-summary.ts","../src/starter-apps/flake-dashboard/contract.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/** A full CI suite publishes this even when its flake record list is empty. */\nexport const FlakeSuiteSummary = z\n .object({\n headSha: z.string().min(1),\n branch: z.string(),\n status: z.enum([\"complete\", \"incomplete\"]),\n startedAt: z.iso.datetime(),\n finishedAt: z.iso.datetime(),\n testCount: z.number().int().nonnegative(),\n // Older artifacts have only counts and cannot advance per-test pass streaks.\n tests: z\n .array(\n z.object({\n name: z.string().min(1),\n outcome: z.enum([\"pass\", \"fail\", \"skip\"]),\n }),\n )\n .optional(),\n unknownFlakeCount: z.number().int().nonnegative(),\n failedCount: z.number().int().nonnegative(),\n diagnostics: z.array(z.string()),\n runUrl: z.url(),\n })\n .refine(\n (summary) =>\n summary.status !== \"complete\" ||\n (summary.testCount > 0 && !!summary.branch && summary.diagnostics.length === 0),\n \"A complete suite needs executed tests and no missing-result diagnostics\",\n );\n","import { FlakeSuiteSummary } from \"@iterate-com/shared/test-support/flake-suite-summary\";\nimport { z } from \"zod\";\nimport { defineProcessorContract } from \"../../processors/index.ts\";\n\nexport { FlakeSuiteSummary } from \"@iterate-com/shared/test-support/flake-suite-summary\";\n\nexport const flakeEventTypes = {\n created: \"events.iterate.com/flakes/created\",\n runRecorded: \"events.iterate.com/flakes/run-recorded\",\n transitionProposed: \"events.iterate.com/flakes/transition-proposed\",\n dashboardRenderSettled: \"events.iterate.com/flakes/dashboard-render-settled\",\n} as const;\n\nconst StreamOffset = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);\n\n/**\n * One `createFlake` test outcome. Mirrors `FlakeRecord` in\n * `@iterate-com/shared/test-support/flake-test` — the wrapper writes these\n * lines to `FLAKE_RECORD_DIR` and CI ships them here verbatim.\n */\nexport const FlakeOutcome = z.enum([\n \"pass\",\n \"flake-fail\",\n \"unexpected-error\",\n \"pinned-fail\",\n \"unexpected-pass\",\n \"retried-pass\",\n]);\n\n/**\n * Which wrapper (or reporter) produced a record: createFlake, createFailing,\n * or the telemetry reporters' retried-pass records for tests nobody has\n * classified yet. Old events predate the field — they were all createFlake.\n */\nexport const FlakeKind = z.enum([\"flake\", \"failing\", \"unknown\"]);\n\nexport const FlakeRecord = z.object({\n name: z.string().min(1).max(1_000),\n kind: FlakeKind.default(\"flake\"),\n outcome: FlakeOutcome,\n // Optional: kind \"unknown\" records carry error samples instead of a pattern.\n pattern: z.string().min(1).max(2_000).optional(),\n durationMs: z.number().nonnegative(),\n at: z.string().min(1),\n error: z.string().max(4_000).optional(),\n});\n\nexport const FlakeDashboardConfig = z.object({\n repository: z.object({\n owner: z.string().min(1),\n repo: z.string().min(1),\n }),\n issueTitle: z.string().min(1).max(200),\n defaultBranch: z.string().min(1),\n});\n\nconst FlakeRunRecorded = z.object({\n runId: z.string().min(1).max(200),\n suite: z.string().min(1).max(200),\n branch: z.string().min(1).max(500),\n commit: z.string().min(1).max(100),\n records: z.array(FlakeRecord).max(10_000),\n // Historical events have records only; they cannot certify a complete suite.\n summary: FlakeSuiteSummary.optional(),\n});\n\nconst MainSuiteRun = z.object({\n runId: z.string(),\n commit: z.string(),\n summary: FlakeSuiteSummary,\n});\n\nexport const FlakeTransition = z.enum([\"unwrap\", \"switch-to-failing\", \"unwrap-failing\"]);\n\nconst FlakeTransitionProposed = z.object({\n testName: z.string().min(1),\n transition: FlakeTransition,\n evidence: z.object({\n consecutiveRuns: z.number().int().positive(),\n firstAt: z.string().min(1),\n lastAt: z.string().min(1),\n }),\n});\n\nconst FlakeDashboardRenderResult = z.discriminatedUnion(\"status\", [\n z.object({\n status: z.literal(\"succeeded\"),\n issueNumber: z.number().int().positive(),\n issueUrl: z.string().url(),\n }),\n z.object({\n status: z.literal(\"failed\"),\n error: z.string().min(1).max(8_000),\n }),\n]);\n\n/**\n * A run of consecutive same-outcome recorded runs on the default branch.\n * `unexpected-error` outcomes and outcome changes reset it. The streak is the\n * whole input to transition proposals, so it lives in reduced state rather\n * than being recomputed from history.\n */\nconst DefaultBranchStreak = z.object({\n // Any outcome except unexpected-error, which resets the streak instead.\n outcome: FlakeOutcome,\n runs: z.number().int().positive(),\n firstAt: z.string().min(1),\n lastAt: z.string().min(1),\n});\n\nconst TrackedTest = z.object({\n /** Latest record's kind wins: adopting an unknown flake into createFlake migrates its row. */\n kind: FlakeKind.default(\"flake\"),\n /** Empty for kind \"unknown\" — those rows show error samples instead. */\n pattern: z.string().default(\"\"),\n suites: z.array(z.string()).default([]),\n /**\n * Per suite, the offset of the newest run-recorded event (any branch) whose\n * records included this test. Compared against the suite's\n * `recentRunOffsets` window at render time: a test absent from all of its\n * suite's last few ingested runs is retired from the table — hidden, not\n * deleted, so a transient absence self-heals on the next record.\n */\n lastSeenOffset: z.record(z.string(), StreamOffset).default({}),\n /**\n * The latest (up to) 10 outcomes on any branch, ordered by test time — the\n * render's emoji streak bar, each entry carrying the commit that produced\n * it so the square can link straight to that commit's checks. All branches,\n * like the counts, for debugging PR failures too. The numeric\n * defaultBranchStreak below stays main-only and carries the\n * transition-threshold counts past what 10 entries can show.\n */\n recent: z\n .array(z.object({ outcome: FlakeOutcome, commit: z.string().min(1).max(100), at: z.string() }))\n .max(10)\n .default([]),\n /** Keyed by outcome value (\"pass\", \"pinned-fail\", …). */\n counts: z.record(z.string(), z.number().int().nonnegative()).default({}),\n /**\n * The last few error samples worth showing (retried-pass and\n * unexpected-error records) — for unknown flakes these are the copy-paste\n * material for the createFlake pattern.\n */\n recentErrors: z\n .array(z.object({ error: z.string().max(4_000), commit: z.string(), at: z.string() }))\n .max(3)\n .default([]),\n lastFlakeAt: z.string().nullable().default(null),\n firstRecordedAt: z.string(),\n lastRecordedAt: z.string(),\n defaultBranchStreak: DefaultBranchStreak.nullable().default(null),\n /** Older retry evidence cannot undo a wrapper observed on main in this suite. */\n lastMainWrapperAt: z.record(z.string(), z.string()).default({}),\n /**\n * One entry per proposal already made, keyed `${transition}:${streak.firstAt}`\n * — a streak proposes at most once however long it grows.\n */\n proposed: z.array(z.string()).default([]),\n});\n\nexport const FlakeDashboardState = z.object({\n birthCertificate: z.object({ config: FlakeDashboardConfig }).nullable().default(null),\n tests: z.record(z.string(), TrackedTest).default({}),\n /**\n * Main-only unknowns, isolated by suite. Healthy rows are hidden, retaining\n * their streak so late failures can correct an apparent recovery.\n */\n unknownFlakes: z\n .record(\n z.string(),\n z.record(\n z.string(),\n z.object({\n record: FlakeRecord,\n passStreak: z.number().int().nonnegative(),\n /** Newest run that actually contained this test, including skips. */\n lastRunAt: z.string(),\n recent: z\n .array(z.object({ outcome: FlakeOutcome, commit: z.string(), at: z.string() }))\n .max(10),\n }),\n ),\n )\n .default({}),\n mainRuns: z\n .record(\n z.string(),\n z.object({\n latest: MainSuiteRun,\n complete: MainSuiteRun.nullable(),\n // Keep the last full test list even if a newer legacy summary has only counts.\n inventory: z\n .object({ startedAt: z.iso.datetime(), names: z.array(z.string()) })\n .nullable()\n .default(null),\n }),\n )\n .default({}),\n /**\n * The newest three ingested results across all branches retire absent\n * tracked tests. This preserves visibility during partial PR runs. Unknown\n * flakes retire after 20 main passes, wrapper adoption, or proven absence\n * from their suite's full main inventory.\n */\n suites: z\n .record(z.string(), z.object({ recentRunOffsets: z.array(StreamOffset).max(3).default([]) }))\n .default({}),\n /**\n * Offset of the newest reduced DATA event (created / run-recorded /\n * transition-proposed). Render settlements deliberately do not bump it —\n * that is what stops a settled render from demanding another render.\n */\n lastDataOffset: StreamOffset.default(0),\n render: z\n .object({\n throughOffset: StreamOffset,\n issueNumber: z.number().int().positive().nullable(),\n issueUrl: z.string().nullable(),\n })\n .nullable()\n .default(null),\n});\n\n/**\n * Suggest unwrapping createFlake after 20 consecutive main passes, regardless\n * of elapsed time. Unknown flakes retire automatically at the same count.\n * Propose createFailing after 25 matched failures over >=2 days.\n * Tunable constants. Sentinel tests are excluded from proposals entirely —\n * they are designed to flake.\n */\nexport const flakeTransitionThresholds = {\n unwrap: { runs: 20, minSpanMs: 0 },\n \"switch-to-failing\": { runs: 25, minSpanMs: 2 * 24 * 60 * 60 * 1000 },\n // A pin that keeps passing unexpectedly looks fixed: propose deleting the\n // createFailing wrapper after a sustained streak.\n \"unwrap-failing\": { runs: 10, minSpanMs: 2 * 24 * 60 * 60 * 1000 },\n} as const;\n\n/**\n * The exact shape of a delivered event this app ingests: a platform-verified\n * GitHub webhook for a COMPLETED check_run on a connection stream. This\n * repo's test suites run on Depot CI, whose jobs are GitHub check runs (NOT\n * GitHub Actions workflow runs — `workflow_run` never fires for them). Zod\n * strips the rest of GitHub's (huge) payload; only these fields are read.\n */\nexport const CheckRunWebhookEvent = z.object({\n type: z.literal(\"events.iterate.com/github/webhook-received\"),\n path: z.string().regex(/^\\/integrations\\/github\\/[^/]+$/),\n payload: z.object({\n delivery: z.object({ name: z.literal(\"check_run\") }),\n body: z.object({\n action: z.literal(\"completed\"),\n check_run: z.object({\n // Cancelled/skipped checks upload no fresh artifacts worth scanning.\n conclusion: z.enum([\"success\", \"failure\"]),\n head_sha: z.string().min(1),\n check_suite: z.object({ head_branch: z.string().nullish() }).optional(),\n }),\n repository: z.object({\n name: z.string().min(1),\n owner: z.object({ login: z.string().min(1) }),\n default_branch: z.string().nullish(),\n }),\n }),\n }),\n});\n\nexport const FlakeDashboardProcessorContract = defineProcessorContract({\n slug: \"flake-dashboard\",\n version: \"0.8.0\",\n description:\n \"Folds createFlake test outcomes reported by CI into per-test flake stats, renders the GitHub 'Flake dashboard' issue, and proposes data-provable lifecycle transitions.\",\n stateSchema: FlakeDashboardState,\n events: {\n [flakeEventTypes.created]: {\n description:\n \"The flake dashboard exists: target repository, issue title, and which branch counts for transitions.\",\n payloadSchema: z.object({ config: FlakeDashboardConfig }),\n examples: [\n {\n description: \"The dogfood dashboard for this repo.\",\n payload: {\n config: {\n repository: { owner: \"iterate\", repo: \"iterate\" },\n issueTitle: \"Flake dashboard\",\n defaultBranch: \"main\",\n },\n },\n },\n ],\n },\n [flakeEventTypes.runRecorded]: {\n description:\n \"One CI run+suite's createFlake outcomes, appended by the CI reporter script (never by this processor). Idempotency-keyed on run+suite so CI retries cannot double-count.\",\n payloadSchema: FlakeRunRecorded,\n },\n [flakeEventTypes.transitionProposed]: {\n description:\n \"A test's default-branch streak crossed a lifecycle threshold; downstream automation (an agent) should open the unwrap / switch-to-failing PR. The file-edit guard (a streak is only trustworthy if the test file did not change during it) is applied by that agent, which can read git history — the fold cannot.\",\n payloadSchema: FlakeTransitionProposed,\n },\n [flakeEventTypes.dashboardRenderSettled]: {\n description:\n \"Terminal fact for one dashboard render attempt: the GitHub issue reached (or the error), and the data offset it covered.\",\n payloadSchema: z.object({\n throughOffset: StreamOffset,\n result: FlakeDashboardRenderResult,\n }),\n },\n },\n consumes: [...Object.values(flakeEventTypes)],\n emits: [flakeEventTypes.transitionProposed, flakeEventTypes.dashboardRenderSettled],\n});\n\nexport type FlakeDashboardProcessorContract = typeof FlakeDashboardProcessorContract;\nexport type FlakeDashboardState = z.infer<typeof FlakeDashboardState>;\nexport type FlakeRecord = z.infer<typeof FlakeRecord>;\nexport type FlakeDashboardRenderResult = z.infer<typeof FlakeDashboardRenderResult>;\n"],"mappings":"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"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { ApplyReviewOperationResult, DocumentReview, ReviewOperation, ReviewProjection, ReviewRange } from "./types.ts";
|
|
2
|
-
export type { ApplyReviewOperationResult, DocumentReview, ReviewAnchor, ReviewComment, ReviewDiagnostic, ReviewOperation, ReviewProjection, ReviewProjectionSegment, ReviewRange, ReviewSuggestion, ReviewThread, } from "./types.ts";
|
|
3
|
-
export declare function readReview(source: string): DocumentReview;
|
|
4
|
-
export declare function applyReviewOperation(source: string, operation: ReviewOperation): ApplyReviewOperationResult;
|
|
5
|
-
export declare function sourceRangeForDisplayRange(projection: ReviewProjection, range: ReviewRange): ReviewRange | null;
|