iterate 0.2.7 → 0.3.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.
Files changed (218) hide show
  1. package/README.md +86 -76
  2. package/THIRD_PARTY_NOTICES.md +55 -0
  3. package/bin/iterate.js +11 -3
  4. package/dist/api-url-B6404M82.mjs +17 -0
  5. package/dist/api-url-B6404M82.mjs.map +1 -0
  6. package/dist/app-ref-BipL0feU.mjs +35 -0
  7. package/dist/app-ref-BipL0feU.mjs.map +1 -0
  8. package/dist/app-ref-C1CrgXqX.mjs +7 -0
  9. package/dist/app-ref-C1CrgXqX.mjs.map +1 -0
  10. package/dist/app-ref-DYai_om1.mjs +7 -0
  11. package/dist/app-ref-DYai_om1.mjs.map +1 -0
  12. package/dist/cli-D0c-pDL_.mjs +1010 -0
  13. package/dist/cli-D0c-pDL_.mjs.map +1 -0
  14. package/dist/client.d.ts +3 -0
  15. package/dist/client.mjs +4 -0
  16. package/dist/cloudflare-BTm90gQ4.mjs +951 -0
  17. package/dist/cloudflare-BTm90gQ4.mjs.map +1 -0
  18. package/dist/contract-s4FW4eES.mjs +309 -0
  19. package/dist/contract-s4FW4eES.mjs.map +1 -0
  20. package/dist/document-review/index.d.ts +5 -0
  21. package/dist/document-review/types.d.ts +107 -0
  22. package/dist/document-review.mjs +7015 -0
  23. package/dist/document-review.mjs.map +1 -0
  24. package/dist/durable-object-processor-durability-CNsTjAJS.mjs +205 -0
  25. package/dist/durable-object-processor-durability-CNsTjAJS.mjs.map +1 -0
  26. package/dist/idempotency-DleloJNt.mjs +28 -0
  27. package/dist/idempotency-DleloJNt.mjs.map +1 -0
  28. package/dist/index.mjs +1 -1
  29. package/dist/itx/api-url.d.ts +6 -0
  30. package/dist/itx/itx-node-client.d.ts +65 -0
  31. package/dist/itx/itx-session.d.ts +215 -0
  32. package/dist/itx/owned-rpc-session.d.ts +14 -0
  33. package/dist/itx/query-client.d.ts +10 -0
  34. package/dist/itx-api.generated.d.ts +6195 -0
  35. package/dist/itx-session-sjud8GiT.mjs +534 -0
  36. package/dist/itx-session-sjud8GiT.mjs.map +1 -0
  37. package/dist/live-state-BJNqOwFw.mjs +299 -0
  38. package/dist/live-state-BJNqOwFw.mjs.map +1 -0
  39. package/dist/next/api.d.ts +479 -0
  40. package/dist/next/api.mjs +0 -0
  41. package/dist/next/app-server.d.ts +44 -0
  42. package/dist/next/app-server.mjs +479 -0
  43. package/dist/next/app-server.mjs.map +1 -0
  44. package/dist/next/app-session.d.ts +49 -0
  45. package/dist/next/app-session.mjs +238 -0
  46. package/dist/next/app-session.mjs.map +1 -0
  47. package/dist/next/app.d.ts +29 -0
  48. package/dist/next/app.mjs +141 -0
  49. package/dist/next/app.mjs.map +1 -0
  50. package/dist/next/client/live-state.d.ts +63 -0
  51. package/dist/next/client/oauth.d.ts +12 -0
  52. package/dist/next/client/react.d.ts +109 -0
  53. package/dist/next/client/socket.d.ts +6 -0
  54. package/dist/next/client.mjs +156 -0
  55. package/dist/next/client.mjs.map +1 -0
  56. package/dist/next/expression.d.ts +146 -0
  57. package/dist/next/expression.mjs +399 -0
  58. package/dist/next/expression.mjs.map +1 -0
  59. package/dist/next/lib.d.ts +56 -0
  60. package/dist/next/lib.mjs +199 -0
  61. package/dist/next/lib.mjs.map +1 -0
  62. package/dist/next/oauth-scopes.d.ts +32 -0
  63. package/dist/next/oauth-scopes.mjs +40 -0
  64. package/dist/next/oauth-scopes.mjs.map +1 -0
  65. package/dist/next/oauth.mjs +29 -0
  66. package/dist/next/oauth.mjs.map +1 -0
  67. package/dist/next/principal.d.ts +64 -0
  68. package/dist/next/principal.mjs +98 -0
  69. package/dist/next/principal.mjs.map +1 -0
  70. package/dist/next/project-ingress.d.ts +37 -0
  71. package/dist/next/project-ingress.mjs +75 -0
  72. package/dist/next/project-ingress.mjs.map +1 -0
  73. package/dist/next/react.mjs +285 -0
  74. package/dist/next/react.mjs.map +1 -0
  75. package/dist/next/sdk/auth.d.ts +5 -0
  76. package/dist/next/sdk/index.d.ts +112 -0
  77. package/dist/next/sdk.mjs +139 -0
  78. package/dist/next/sdk.mjs.map +1 -0
  79. package/dist/next/stream/processor.d.ts +378 -0
  80. package/dist/next/stream/processor.mjs +582 -0
  81. package/dist/next/stream/processor.mjs.map +1 -0
  82. package/dist/next/stream/run.d.ts +58 -0
  83. package/dist/next/stream/run.mjs +40 -0
  84. package/dist/next/stream/run.mjs.map +1 -0
  85. package/dist/next-node.d.ts +15 -0
  86. package/dist/next-node.mjs +51 -0
  87. package/dist/next-node.mjs.map +1 -0
  88. package/dist/node.d.ts +3 -0
  89. package/dist/node.mjs +185 -0
  90. package/dist/node.mjs.map +1 -0
  91. package/dist/processor-host-capabilities-BMFH3KTM.mjs +56 -0
  92. package/dist/processor-host-capabilities-BMFH3KTM.mjs.map +1 -0
  93. package/dist/processors/cloudflare.d.ts +3 -0
  94. package/dist/processors/durable-object-processor-durability.d.ts +79 -0
  95. package/dist/processors/event-consumption-metrics.d.ts +82 -0
  96. package/dist/processors/idempotency.d.ts +13 -0
  97. package/dist/processors/index.d.ts +12 -0
  98. package/dist/processors/processor-contracts.d.ts +342 -0
  99. package/dist/processors/processor-facet.d.ts +186 -0
  100. package/dist/processors/processor-host-capabilities.d.ts +60 -0
  101. package/dist/processors/prompt-sections.d.ts +17 -0
  102. package/dist/processors/rpc-types.d.ts +515 -0
  103. package/dist/processors/schemas.d.ts +102 -0
  104. package/dist/processors/stream-handle.d.ts +45 -0
  105. package/dist/processors/stream-processor-keepalive.d.ts +95 -0
  106. package/dist/processors/stream-processor-registry.d.ts +233 -0
  107. package/dist/processors/stream-processor-runner.d.ts +289 -0
  108. package/dist/processors/stream-processor.d.ts +339 -0
  109. package/dist/processors/stream-runtime-metrics.d.ts +107 -0
  110. package/dist/processors/testing.d.ts +302 -0
  111. package/dist/processors-BoNyeBfQ.mjs +10 -0
  112. package/dist/processors-BoNyeBfQ.mjs.map +1 -0
  113. package/dist/processors-cloudflare.mjs +3 -0
  114. package/dist/processors-testing.mjs +435 -0
  115. package/dist/processors-testing.mjs.map +1 -0
  116. package/dist/processors.mjs +52 -0
  117. package/dist/processors.mjs.map +1 -0
  118. package/dist/protocol-DnK_f2m6.mjs +251 -0
  119. package/dist/protocol-DnK_f2m6.mjs.map +1 -0
  120. package/dist/sdk/capnweb/index.d.ts +2 -0
  121. package/dist/sdk/capnweb/live-state/compact.d.ts +5 -0
  122. package/dist/sdk/capnweb/live-state/diff.d.ts +41 -0
  123. package/dist/sdk/capnweb/live-state/engine.d.ts +44 -0
  124. package/dist/sdk/capnweb/live-state/index.d.ts +41 -0
  125. package/dist/sdk/capnweb/live-state/protocol.d.ts +87 -0
  126. package/dist/sdk/capnweb/live-state/retain.d.ts +23 -0
  127. package/dist/sdk/capnweb/live-state/store.d.ts +20 -0
  128. package/dist/sdk/capnweb/live-state/types.d.ts +11 -0
  129. package/dist/sdk/capnweb/react.d.ts +45 -0
  130. package/dist/sdk/capnweb/react.mjs +316 -0
  131. package/dist/sdk/capnweb/react.mjs.map +1 -0
  132. package/dist/sdk/capnweb.mjs +4 -0
  133. package/dist/sdk/itx/react.d.ts +191 -0
  134. package/dist/sdk/itx/react.mjs +383 -0
  135. package/dist/sdk/itx/react.mjs.map +1 -0
  136. package/dist/sdk-DMB-IM11.mjs +933 -0
  137. package/dist/sdk-DMB-IM11.mjs.map +1 -0
  138. package/dist/sdk.d.ts +339 -0
  139. package/dist/sdk.mjs +2 -0
  140. package/dist/serve-itx.d.ts +46 -0
  141. package/dist/starter-apps/flake-dashboard/app-ref.d.ts +31 -0
  142. package/dist/starter-apps/flake-dashboard/configured-worker.mjs +1055 -0
  143. package/dist/starter-apps/flake-dashboard/configured-worker.mjs.map +1 -0
  144. package/dist/starter-apps/flake-dashboard/contract.d.ts +4839 -0
  145. package/dist/starter-apps/flake-dashboard/contract.mjs +2 -0
  146. package/dist/starter-apps/flake-dashboard/index.d.ts +17 -0
  147. package/dist/starter-apps/flake-dashboard/index.mjs +56 -0
  148. package/dist/starter-apps/flake-dashboard/index.mjs.map +1 -0
  149. package/dist/starter-apps/flake-dashboard/worker.d.ts +4607 -0
  150. package/dist/starter-apps/github-ai-linter/ai-linter.d.ts +8914 -0
  151. package/dist/starter-apps/github-ai-linter/configured-worker.mjs +17987 -0
  152. package/dist/starter-apps/github-ai-linter/configured-worker.mjs.map +1 -0
  153. package/dist/starter-apps/github-ai-linter/contract.d.ts +9193 -0
  154. package/dist/starter-apps/github-ai-linter/index.d.ts +10 -0
  155. package/dist/starter-apps/github-ai-linter/index.mjs +36 -0
  156. package/dist/starter-apps/github-ai-linter/index.mjs.map +1 -0
  157. package/dist/starter-apps/github-ai-linter/prompt.d.ts +13 -0
  158. package/dist/starter-apps/github-ai-linter/review-bot.d.ts +808 -0
  159. package/dist/starter-apps/github-ai-linter/rules.d.ts +34 -0
  160. package/dist/starter-apps/github-ai-linter/worker-ref.d.ts +19 -0
  161. package/dist/starter-apps/github-ai-linter/worker.d.ts +19 -0
  162. package/dist/starter-apps/github-ai-linter/worker.mjs +947 -0
  163. package/dist/starter-apps/github-ai-linter/worker.mjs.map +1 -0
  164. package/dist/starter-apps/guestbook/app-ref.d.ts +27 -0
  165. package/dist/starter-apps/guestbook/client.d.ts +7 -0
  166. package/dist/starter-apps/guestbook/client.mjs +59 -0
  167. package/dist/starter-apps/guestbook/configured-worker.mjs +205 -0
  168. package/dist/starter-apps/guestbook/configured-worker.mjs.map +1 -0
  169. package/dist/starter-apps/guestbook/index.d.ts +9 -0
  170. package/dist/starter-apps/guestbook/index.mjs +31 -0
  171. package/dist/starter-apps/guestbook/index.mjs.map +1 -0
  172. package/dist/starter-apps/guestbook/processor.d.ts +2267 -0
  173. package/dist/starter-apps/guestbook/worker.d.ts +26 -0
  174. package/dist/starter-apps/guestbook/worker.mjs +191 -0
  175. package/dist/starter-apps/guestbook/worker.mjs.map +1 -0
  176. package/dist/starter-apps/media/configured-worker.mjs +577 -0
  177. package/dist/starter-apps/media/configured-worker.mjs.map +1 -0
  178. package/dist/starter-apps/media/index.mjs +36 -0
  179. package/dist/starter-apps/media/index.mjs.map +1 -0
  180. package/dist/starter-apps/media/ref.mjs +20 -0
  181. package/dist/starter-apps/media/ref.mjs.map +1 -0
  182. package/dist/starter-apps/media/worker.mjs +579 -0
  183. package/dist/starter-apps/media/worker.mjs.map +1 -0
  184. package/dist/starter-apps/notes/configured-worker.mjs +6134 -0
  185. package/dist/starter-apps/notes/configured-worker.mjs.map +1 -0
  186. package/dist/starter-apps/notes/index.mjs +23 -0
  187. package/dist/starter-apps/notes/index.mjs.map +1 -0
  188. package/dist/starter-apps/notes/ref.mjs +21 -0
  189. package/dist/starter-apps/notes/ref.mjs.map +1 -0
  190. package/dist/starter-apps/notes/worker.mjs +427 -0
  191. package/dist/starter-apps/notes/worker.mjs.map +1 -0
  192. package/dist/starter-apps/todo/client.mjs +59 -0
  193. package/dist/starter-apps/todo/configured-worker.mjs +2864 -0
  194. package/dist/starter-apps/todo/configured-worker.mjs.map +1 -0
  195. package/dist/starter-apps/todo/index.d.ts +8 -0
  196. package/dist/starter-apps/todo/index.mjs +29 -0
  197. package/dist/starter-apps/todo/index.mjs.map +1 -0
  198. package/dist/stream-processor-keepalive-DAQTP6m3.mjs +2082 -0
  199. package/dist/stream-processor-keepalive-DAQTP6m3.mjs.map +1 -0
  200. package/dist/usingCtx-inzbY1Qz.mjs +57 -0
  201. package/dist/usingCtx-mZx5nsAW.mjs +11800 -0
  202. package/dist/usingCtx-mZx5nsAW.mjs.map +1 -0
  203. package/dist/worker-ref-DZxPDmb_.mjs +390 -0
  204. package/dist/worker-ref-DZxPDmb_.mjs.map +1 -0
  205. package/menubar/Iterate.entitlements +12 -0
  206. package/menubar/Iterate.swift +914 -0
  207. package/menubar/IterateIcon.swift +145 -0
  208. package/menubar/README.md +28 -0
  209. package/menubar/build-menubar-app.sh +59 -0
  210. package/package.json +235 -18
  211. package/dist/cli-DMS4kJph.mjs +0 -868
  212. package/dist/cli-DMS4kJph.mjs.map +0 -1
  213. package/dist/config-DtnR7Lv7.mjs +0 -170
  214. package/dist/config-DtnR7Lv7.mjs.map +0 -1
  215. package/dist/index.d.mts.map +0 -1
  216. package/dist/stream-tui/agent-chat-terminal.d.mts +0 -1
  217. package/dist/stream-tui/agent-chat-terminal.mjs +0 -933
  218. package/dist/stream-tui/agent-chat-terminal.mjs.map +0 -1
@@ -0,0 +1,951 @@
1
+ import { o as StreamProcessorRunner } from "./stream-processor-keepalive-DAQTP6m3.mjs";
2
+ import { n as durableObjectRecovery, t as durableObjectProgressStore } from "./durable-object-processor-durability-CNsTjAJS.mjs";
3
+ import { n as hostRuntimeCapabilities, t as announceContract } from "./processor-host-capabilities-BMFH3KTM.mjs";
4
+ import * as cloudflareWorkers from "cloudflare:workers";
5
+ import { DurableObject } from "cloudflare:workers";
6
+ import { z } from "zod";
7
+ //#region src/sdk/capnweb/live-state/retain.ts
8
+ /**
9
+ * Retain a single-argument RPC callback so it survives past the call that
10
+ * carried it. `dup()` duplicates the underlying remote stub (that dup is what
11
+ * `[Symbol.dispose]` releases); `onRpcBroken` is forwarded defensively — Cap'n
12
+ * Web stubs expose no own property descriptors and a Workers RPC property access
13
+ * can fabricate a pipelined method that rejects at call time, so we wire whatever
14
+ * the stub claims and swallow registration failures. `onRpcBroken` is only a
15
+ * prompt hint; callers that need a terminal verdict must model one explicitly
16
+ * (for example, the durable wake lane's independent settlement capability).
17
+ */
18
+ function retainCallback(callback) {
19
+ const retainable = callback;
20
+ const retained = retainable.dup?.() ?? retainable;
21
+ const dispose = retained[Symbol.dispose]?.bind(retained);
22
+ let disposed = false;
23
+ const wrapped = Object.assign((arg) => retained(arg), { [Symbol.dispose]() {
24
+ if (disposed) return;
25
+ disposed = true;
26
+ dispose?.();
27
+ } });
28
+ const onRpcBroken = retained.onRpcBroken;
29
+ if (typeof onRpcBroken === "function") wrapped.onRpcBroken = (handler) => {
30
+ try {
31
+ const result = onRpcBroken.call(retained, handler);
32
+ if (isThenable(result)) Promise.resolve(result).catch(() => {});
33
+ } catch {}
34
+ };
35
+ return wrapped;
36
+ }
37
+ /** Thenable probe: RPC stubs and their call results are thenable-shaped. */
38
+ function isThenable(value) {
39
+ return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
40
+ }
41
+ /**
42
+ * Dispose the result of an RPC call whose value the caller ignores. Reading a
43
+ * Cap'n Web / Workers RPC method yields a disposable stub even when unused, and
44
+ * dropping it without disposal leaks the remote reference.
45
+ */
46
+ function disposeIgnoredRpcResult(result) {
47
+ if (result !== null && (typeof result === "object" || typeof result === "function") && Symbol.dispose in result) result[Symbol.dispose]();
48
+ }
49
+ //#endregion
50
+ //#region src/sdk/capnweb/live-state/diff.ts
51
+ /**
52
+ * Structural diff between two JSON values, producing the minimal `LiveStatePatch`
53
+ * — or `undefined` when nothing changed.
54
+ *
55
+ * The diff is REFERENCE-FIRST: identical references short-circuit immediately
56
+ * (`Object.is`), so the cost is O(changed), not O(size) — *as long as callers
57
+ * update state immutably* (unchanged sub-objects keep their identity). That one
58
+ * discipline is the whole performance story: a single touched row in a
59
+ * thousand-entry index yields one tiny patch instead of a full rescan.
60
+ *
61
+ * PLAIN objects (prototype `Object.prototype` or `null`) are treated as keyed
62
+ * maps and diffed per key. Dense arrays are diffed by position. Everything
63
+ * else — primitives, `null`, sparse arrays, and
64
+ * non-plain instances like `Date`/`Map`/`Set` — is a leaf, replaced wholesale.
65
+ * Descending into an instance would diff its own enumerable keys, which for a
66
+ * `Date` is NONE — two different Dates would read as "unchanged" and the
67
+ * subscriber would stay stale forever. Keyed objects remain preferable for
68
+ * collections whose entries frequently move; positional patches do not infer moves.
69
+ */
70
+ function diff(prev, next, options = {}) {
71
+ if (Object.is(prev, next)) return void 0;
72
+ if (Array.isArray(prev) && Array.isArray(next) && options.arrays !== false) {
73
+ const items = [];
74
+ for (let index = 0; index < next.length; index++) {
75
+ if (!Object.hasOwn(next, index) || index < prev.length && !Object.hasOwn(prev, index)) return { set: next };
76
+ const patch = index < prev.length ? diff(prev[index], next[index], options) : { set: next[index] };
77
+ if (patch) items.push([index, patch]);
78
+ }
79
+ return items.length > 0 || prev.length !== next.length ? { array: {
80
+ length: next.length,
81
+ items
82
+ } } : void 0;
83
+ }
84
+ if (!isPlainObject(prev) || !isPlainObject(next)) return { set: next };
85
+ const fields = [];
86
+ const drop = [];
87
+ for (const key of Object.keys(next)) {
88
+ if (next[key] === void 0) {
89
+ if (Object.hasOwn(prev, key)) drop.push(key);
90
+ continue;
91
+ }
92
+ const childPatch = diff(Object.hasOwn(prev, key) ? prev[key] : void 0, next[key], options);
93
+ if (childPatch !== void 0) fields.push([key, childPatch]);
94
+ }
95
+ for (const key of Object.keys(prev)) if (!Object.hasOwn(next, key)) drop.push(key);
96
+ if (fields.length === 0 && drop.length === 0) return void 0;
97
+ const patch = {};
98
+ if (fields.length > 0) patch.fields = Object.fromEntries(fields);
99
+ if (drop.length > 0) patch.drop = drop;
100
+ return patch;
101
+ }
102
+ /**
103
+ * Apply a `LiveStatePatch` to a previous value, returning the next value.
104
+ *
105
+ * Like `diff`, this preserves structural sharing: a fresh object is built only
106
+ * along changed paths, so untouched branches keep their previous reference.
107
+ * That's what lets a client selector (`s => s.streamsIndex`) skip re-rendering
108
+ * when an unrelated slice changed — the slice it reads stays `Object.is`-equal
109
+ * across applies.
110
+ */
111
+ function applyPatch(prev, patch) {
112
+ if ("set" in patch) return patch.set;
113
+ if ("array" in patch) {
114
+ if (!Array.isArray(prev)) throw new Error("Live-state array patch requires an array baseline");
115
+ const next = prev.slice(0, patch.array.length);
116
+ next.length = patch.array.length;
117
+ for (const [index, child] of patch.array.items) {
118
+ if (!Number.isSafeInteger(index) || index < 0 || index >= next.length) throw new Error("Live-state array patch index is outside its resulting length");
119
+ next[index] = applyPatch(prev[index], child);
120
+ }
121
+ return next;
122
+ }
123
+ const base = isPlainObject(prev) ? prev : {};
124
+ const next = { ...base };
125
+ if (patch.fields) for (const [key, childPatch] of Object.entries(patch.fields)) Object.defineProperty(next, key, {
126
+ value: applyPatch(Object.hasOwn(base, key) ? base[key] : void 0, childPatch),
127
+ enumerable: true,
128
+ writable: true,
129
+ configurable: true
130
+ });
131
+ if (patch.drop) for (const key of patch.drop) delete next[key];
132
+ return next;
133
+ }
134
+ /**
135
+ * A PLAIN object — prototype `Object.prototype` or `null` — the only thing
136
+ * `diff` descends into and `applyPatch` merges over. Arrays and class instances
137
+ * (`Date`, `Map`, `Set`, …) fail this on purpose: they carry state outside
138
+ * their own enumerable keys, so per-key diffing would misread them (see the
139
+ * `diff` docstring) — they are leaves, replaced wholesale.
140
+ */
141
+ function isPlainObject(value) {
142
+ if (typeof value !== "object" || value === null) return false;
143
+ const proto = Object.getPrototypeOf(value);
144
+ return proto === Object.prototype || proto === null;
145
+ }
146
+ //#endregion
147
+ //#region src/sdk/capnweb/live-state/compact.ts
148
+ const fieldAddresses = /* @__PURE__ */ new WeakMap();
149
+ function addresses(value) {
150
+ let cached = fieldAddresses.get(value);
151
+ if (!cached) {
152
+ const keys = Object.keys(value).filter((key) => value[key] !== void 0).sort();
153
+ cached = {
154
+ keys,
155
+ indices: new Map(keys.map((key, index) => [key, index]))
156
+ };
157
+ fieldAddresses.set(value, cached);
158
+ }
159
+ return cached;
160
+ }
161
+ /** Encode only the changed paths of an existing structural diff. */
162
+ function compactPatch(previous, patch) {
163
+ if ("set" in patch) {
164
+ const next = patch.set;
165
+ if (typeof previous === "string" && typeof next === "string" && previous.length >= 16 && previous.length <= 4096 && next.length > previous.length && next.startsWith(previous)) return [previous.length, next.slice(previous.length)];
166
+ if (next === null || typeof next === "string" || typeof next === "number" || typeof next === "boolean") return next;
167
+ return [next];
168
+ }
169
+ if ("array" in patch) {
170
+ if (!Array.isArray(previous)) throw new Error("Live-state array patch requires an array baseline");
171
+ const result = {};
172
+ if (patch.array.length !== previous.length) result["#"] = patch.array.length;
173
+ for (const [index, child] of patch.array.items) result[index] = compactPatch(previous[index], child);
174
+ return result;
175
+ }
176
+ if (!isPlainObject(previous)) throw new Error("Live-state object patch requires an object baseline");
177
+ const { indices } = addresses(previous);
178
+ const fields = [];
179
+ for (const [key, child] of Object.entries(patch.fields || {})) {
180
+ const index = indices.get(key);
181
+ fields.push([index === void 0 ? `+${key}` : String(index), compactPatch(index === void 0 ? void 0 : previous[key], child)]);
182
+ }
183
+ for (const key of patch.drop || []) {
184
+ const index = indices.get(key);
185
+ if (index !== void 0) fields.push([String(index), []]);
186
+ }
187
+ return Object.fromEntries(fields);
188
+ }
189
+ /** Apply a version 3 patch, retaining every untouched object's identity. */
190
+ function applyCompactPatch(previous, patch) {
191
+ return applyCompactValue(previous, patch);
192
+ }
193
+ function applyCompactValue(previous, patch) {
194
+ if (patch === null || typeof patch !== "object") return patch;
195
+ if (Array.isArray(patch)) {
196
+ if (patch.length === 1) return patch[0];
197
+ if (patch.length !== 2 || typeof previous !== "string" || previous.length !== patch[0]) throw new Error("Live-state append does not match its string baseline");
198
+ return previous + patch[1];
199
+ }
200
+ if (Array.isArray(previous)) {
201
+ const length = Object.hasOwn(patch, "#") ? patch["#"] : previous.length;
202
+ if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0 || length > 4294967295) throw new Error("Live-state array patch has an invalid length");
203
+ const next = previous.slice(0, length);
204
+ next.length = length;
205
+ for (const [address, child] of Object.entries(patch)) {
206
+ if (address === "#") continue;
207
+ const index = position(address, length);
208
+ next[index] = applyCompactValue(previous[index], child);
209
+ }
210
+ return next;
211
+ }
212
+ if (!isPlainObject(previous)) throw new Error("Live-state object patch requires an object baseline");
213
+ const { keys } = addresses(previous);
214
+ const next = { ...previous };
215
+ for (const [address, child] of Object.entries(patch)) {
216
+ const added = address.startsWith("+");
217
+ const key = added ? address.slice(1) : keys[position(address, keys.length)];
218
+ if (added && Object.hasOwn(previous, key) && previous[key] !== void 0) throw new Error("Live-state new field already exists in its baseline");
219
+ if (Array.isArray(child) && child.length === 0) {
220
+ if (added) throw new Error("Live-state cannot delete a new field");
221
+ delete next[key];
222
+ } else Object.defineProperty(next, key, {
223
+ value: applyCompactValue(added ? void 0 : previous[key], child),
224
+ enumerable: true,
225
+ writable: true,
226
+ configurable: true
227
+ });
228
+ }
229
+ return next;
230
+ }
231
+ function position(address, length) {
232
+ const index = Number(address);
233
+ if (!Number.isSafeInteger(index) || index < 0 || index >= length || String(index) !== address) throw new Error("Live-state field address is outside its baseline");
234
+ return index;
235
+ }
236
+ //#endregion
237
+ //#region src/sdk/capnweb/live-state/engine.ts
238
+ const DEFAULT_DEBOUNCE_MS = 100;
239
+ const ACK_TIMEOUT_MS = 1e4;
240
+ /**
241
+ * A source-agnostic live store: hold a state value, and when it changes push the
242
+ * minimal diff to every subscriber. It does not know or care where the state
243
+ * comes from — a Durable Object folds events into it, a stateless RpcTarget polls
244
+ * a third-party API into it — so ANY RpcTarget can expose live state by holding
245
+ * one and returning a read-only wrapper from a `.live` getter.
246
+ *
247
+ * Two rules make it cheap and correct:
248
+ * - Updates are IMMUTABLE (`setState`/`assign` build a new value, never mutate),
249
+ * so the diff short-circuits unchanged branches by identity — O(changed), not
250
+ * O(size). See `diff.ts`.
251
+ * - Push work runs only while a subscriber exists. Transient readers call
252
+ * `readSince` explicitly; a dormant engine schedules nothing.
253
+ *
254
+ * All subscribers share one revision line. Fast subscribers share a patch;
255
+ * slow subscribers receive a coalesced patch from their acknowledged state.
256
+ * A revision mismatch makes the client resync instead of applying stale data.
257
+ */
258
+ var LiveState = class {
259
+ #current;
260
+ /** Latest flushed state — the shared diff baseline. */
261
+ #broadcast;
262
+ #revision = 0;
263
+ #epoch = crypto.randomUUID();
264
+ #lastUpdate;
265
+ #lastCompactUpdate;
266
+ #subscribers = /* @__PURE__ */ new Map();
267
+ #debounceMs;
268
+ #flushTimer;
269
+ constructor(initial, options = {}) {
270
+ this.#current = initial;
271
+ this.#broadcast = initial;
272
+ this.#debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
273
+ }
274
+ /** The current state — reflects every `setState`/`assign`, even while dormant. */
275
+ getState() {
276
+ return this.#current;
277
+ }
278
+ /** One retained delta bounds history while a single parent can pull incrementally.
279
+ * A late reader or a new incarnation receives an explicit snapshot instead. */
280
+ readSince(cursor, options = {}) {
281
+ if (this.#flushTimer !== void 0) clearTimeout(this.#flushTimer);
282
+ this.#flushTimer = void 0;
283
+ this.#flush();
284
+ if (cursor?.epoch === this.#epoch) {
285
+ if (cursor.revision === this.#revision) return {
286
+ epoch: this.#epoch,
287
+ update: null
288
+ };
289
+ if (cursor.revision === this.#lastUpdate?.from) return {
290
+ epoch: this.#epoch,
291
+ update: options.patchVersion === 3 ? this.#lastCompactUpdate : this.#lastUpdate
292
+ };
293
+ }
294
+ return {
295
+ epoch: this.#epoch,
296
+ update: options.patchVersion === 3 ? { s: [this.#revision, this.#broadcast] } : {
297
+ type: "snapshot",
298
+ revision: this.#revision,
299
+ state: this.#broadcast
300
+ }
301
+ };
302
+ }
303
+ /** True while at least one live subscriber makes projection work observable. */
304
+ get observed() {
305
+ return this.#subscribers.size > 0;
306
+ }
307
+ /** Replace the state. Build a NEW value (don't mutate) so the diff stays cheap. */
308
+ setState(next) {
309
+ this.#current = typeof next === "function" ? next(this.#current) : next;
310
+ if (this.#subscribers.size > 0) this.#scheduleFlush();
311
+ }
312
+ /** Shallow-merge a partial into the state — sugar for `setState(p => ({ ...p, ...partial }))`. */
313
+ assign(partial) {
314
+ this.setState((prev) => ({
315
+ ...prev,
316
+ ...partial
317
+ }));
318
+ }
319
+ subscribe(sink, options = {}) {
320
+ if (this.#subscribers.size === 0) this.#flush();
321
+ const retained = retainCallback(sink);
322
+ this.#subscribers.set(retained, {
323
+ version: options.patchVersion ?? 1,
324
+ state: this.#broadcast,
325
+ revision: this.#revision,
326
+ busy: false
327
+ });
328
+ retained.onRpcBroken?.(() => this.#drop(retained));
329
+ this.#deliver(retained, options.patchVersion === 3 ? { s: [this.#revision, this.#broadcast] } : {
330
+ type: "snapshot",
331
+ revision: this.#revision,
332
+ state: this.#broadcast
333
+ });
334
+ return {
335
+ ping: () => this.#subscribers.has(retained),
336
+ unsubscribe: () => this.#drop(retained),
337
+ [Symbol.dispose]: () => this.#drop(retained)
338
+ };
339
+ }
340
+ #scheduleFlush() {
341
+ this.#flushTimer ??= setTimeout(() => {
342
+ this.#flushTimer = void 0;
343
+ this.#flush();
344
+ }, this.#debounceMs);
345
+ }
346
+ #flush() {
347
+ const previous = this.#broadcast;
348
+ const patch = diff(previous, this.#current);
349
+ if (patch === void 0) return;
350
+ const from = this.#revision;
351
+ const to = this.#revision += 1;
352
+ this.#broadcast = this.#current;
353
+ const update = {
354
+ type: "patch",
355
+ from,
356
+ to,
357
+ patch
358
+ };
359
+ this.#lastUpdate = update;
360
+ this.#lastCompactUpdate = { p: [
361
+ from,
362
+ to,
363
+ compactPatch(previous, patch)
364
+ ] };
365
+ for (const subscriber of this.#subscribers.keys()) this.#sendLatest(subscriber);
366
+ }
367
+ /** Slow subscribers hold one call and one baseline, never a queue of token updates. */
368
+ #sendLatest(subscriber) {
369
+ const held = this.#subscribers.get(subscriber);
370
+ if (!held || held.busy || held.revision === this.#revision) return;
371
+ if (held.version === 3) {
372
+ if (held.revision === this.#lastUpdate?.from) this.#deliver(subscriber, this.#lastCompactUpdate);
373
+ else {
374
+ const patch = diff(held.state, this.#broadcast);
375
+ this.#deliver(subscriber, { p: [
376
+ held.revision,
377
+ this.#revision,
378
+ patch ? compactPatch(held.state, patch) : {}
379
+ ] });
380
+ }
381
+ return;
382
+ }
383
+ const patch = held.version === 2 && held.revision === this.#lastUpdate?.from ? this.#lastUpdate.patch : diff(held.state, this.#broadcast, { arrays: held.version === 2 });
384
+ this.#deliver(subscriber, {
385
+ type: "patch",
386
+ from: held.revision,
387
+ to: this.#revision,
388
+ patch: patch ?? {}
389
+ });
390
+ }
391
+ /** Only acknowledgement releases the next coalesced update; a dead sink is dropped. */
392
+ #deliver(subscriber, update) {
393
+ const held = this.#subscribers.get(subscriber);
394
+ if (!held) return;
395
+ held.state = this.#broadcast;
396
+ held.revision = this.#revision;
397
+ held.busy = true;
398
+ let result;
399
+ try {
400
+ result = subscriber(update);
401
+ } catch {
402
+ this.#drop(subscriber);
403
+ return;
404
+ }
405
+ if (isThenable(result)) {
406
+ held.timeout = setTimeout(() => {
407
+ console.warn("Live-state subscriber dropped: acknowledgement timed out", {
408
+ revision: held.revision,
409
+ timeoutMs: ACK_TIMEOUT_MS
410
+ });
411
+ this.#drop(subscriber);
412
+ }, ACK_TIMEOUT_MS);
413
+ Promise.resolve(result).then(() => {
414
+ if (held.timeout !== void 0) clearTimeout(held.timeout);
415
+ held.busy = false;
416
+ this.#sendLatest(subscriber);
417
+ }, () => this.#drop(subscriber)).finally(() => disposeIgnoredRpcResult(result));
418
+ return;
419
+ }
420
+ held.busy = false;
421
+ disposeIgnoredRpcResult(result);
422
+ }
423
+ #drop(subscriber) {
424
+ const timeout = this.#subscribers.get(subscriber)?.timeout;
425
+ if (timeout !== void 0) clearTimeout(timeout);
426
+ if (!this.#subscribers.delete(subscriber)) return;
427
+ subscriber[Symbol.dispose]();
428
+ if (this.#subscribers.size === 0 && this.#flushTimer !== void 0) {
429
+ clearTimeout(this.#flushTimer);
430
+ this.#flushTimer = void 0;
431
+ }
432
+ }
433
+ };
434
+ //#endregion
435
+ //#region src/processors/stream-processor-registry.ts
436
+ const tracing = cloudflareWorkers.tracing ?? { enterSpan: (_name, fn) => fn({ setAttribute() {} }) };
437
+ const WakeDeliveryThrowableFields = z.object({
438
+ durableObjectReset: z.unknown().optional(),
439
+ itxCallId: z.unknown().optional(),
440
+ message: z.unknown().optional(),
441
+ name: z.unknown().optional(),
442
+ overloaded: z.unknown().optional(),
443
+ retryable: z.unknown().optional()
444
+ });
445
+ function serializeWakeDeliveryError(error) {
446
+ const parsed = WakeDeliveryThrowableFields.safeParse(error);
447
+ const candidate = parsed.success ? parsed.data : void 0;
448
+ return {
449
+ name: typeof candidate?.name === "string" ? candidate.name : "Error",
450
+ message: typeof candidate?.message === "string" ? candidate.message : String(error) || "unknown delivery failure",
451
+ ...typeof candidate?.itxCallId === "string" && candidate.itxCallId.length > 0 && candidate.itxCallId.length <= 200 && { itxCallId: candidate.itxCallId },
452
+ ...candidate?.durableObjectReset === true && { durableObjectReset: true },
453
+ ...candidate?.overloaded === true && { overloaded: true },
454
+ ...candidate?.retryable === true && { retryable: true }
455
+ };
456
+ }
457
+ /**
458
+ * Report one final wake-delivery result without awaiting the report call's
459
+ * return value. Calling the callback sends the result; awaiting it would keep
460
+ * the original cross-Durable-Object call chain open.
461
+ */
462
+ function reportWakeDeliveryResult(reportDeliveryResult, deliveryResult) {
463
+ let result;
464
+ try {
465
+ result = reportDeliveryResult(deliveryResult);
466
+ } catch (error) {
467
+ console.warn("stream wake delivery result could not be reported", { error });
468
+ return;
469
+ }
470
+ try {
471
+ disposeIgnoredRpcResult(result);
472
+ } catch (error) {
473
+ console.warn("stream wake delivery report result disposal failed", { error });
474
+ }
475
+ }
476
+ function createStreamProcessorRegistry(ctx, options) {
477
+ const entries = /* @__PURE__ */ new Map();
478
+ const now = options.now ?? (() => Date.now());
479
+ const alarmSlices = /* @__PURE__ */ new Map();
480
+ /**
481
+ * A durable alarm armed by a PREVIOUS incarnation whose owning slice we
482
+ * cannot know (in-memory desires died with it). The first reconcile adopts
483
+ * it as a desire of its own so this incarnation's arming/disarming cannot
484
+ * clobber it; the next actual fire drops it — every subsystem re-derives
485
+ * its desire in that turn.
486
+ */
487
+ const INHERITED_ALARM_SLICE = "@inherited";
488
+ /** What the platform alarm holds; null = cleared, undefined = unknown. */
489
+ let platformAlarmAtMs;
490
+ /** Serializes alarm storage ops so read-adopt and writes cannot interleave. */
491
+ let alarmChain = Promise.resolve();
492
+ /**
493
+ * Returns the settled write for callers whose correctness depends on the
494
+ * alarm being DURABLY armed (the alarm handler, the scheduler's error-path
495
+ * fallback) — a rejected step means the platform alarm may not exist, and
496
+ * such callers must rethrow so the platform retries them. Fire-and-forget
497
+ * callers may ignore the result: the chain observes the rejection either
498
+ * way, and the next reconcile re-reads and re-issues.
499
+ */
500
+ function reconcileAlarm() {
501
+ const step = alarmChain.then(async () => {
502
+ if (platformAlarmAtMs === void 0) {
503
+ const existing = await ctx.storage.getAlarm();
504
+ platformAlarmAtMs = existing;
505
+ if (existing !== null) alarmSlices.set(INHERITED_ALARM_SLICE, existing);
506
+ }
507
+ let earliest = null;
508
+ for (const atMs of alarmSlices.values()) if (earliest === null || atMs < earliest) earliest = atMs;
509
+ if (earliest === platformAlarmAtMs) return;
510
+ platformAlarmAtMs = earliest;
511
+ if (earliest === null) await ctx.storage.deleteAlarm();
512
+ else await ctx.storage.setAlarm(earliest);
513
+ });
514
+ alarmChain = step.catch((error) => {
515
+ platformAlarmAtMs = void 0;
516
+ console.error("stream processor registry alarm arming failed", error);
517
+ });
518
+ ctx.waitUntil(alarmChain);
519
+ return step;
520
+ }
521
+ function setAlarmSlice(name, atMs) {
522
+ if (atMs === null) alarmSlices.delete(name);
523
+ else alarmSlices.set(name, atMs);
524
+ return reconcileAlarm();
525
+ }
526
+ function requireEntry(name) {
527
+ const entry = entries.get(name);
528
+ if (entry === void 0) throw new Error(`Unknown stream processor name "${name}" on this registry (registered: ${[...entries.keys()].join(", ") || "none"})`);
529
+ return entry;
530
+ }
531
+ function requireEntryForInstance(processor, verb) {
532
+ for (const entry of entries.values()) if (entry.processor === processor) return entry;
533
+ throw new Error(`stream processor "${processor.contract.slug}" instance passed to ${verb}() is not registered on this registry — pass the exact instance register() returned (registered names: ${[...entries.keys()].join(", ") || "none"})`);
534
+ }
535
+ /**
536
+ * Route a wake to a registered entry. The subscription NAME is the key —
537
+ * and equals the contract slug (enforced at configure time; under facet
538
+ * placement it is also the facet name). An unknown name is a loud error.
539
+ */
540
+ function resolveProcessorName(args) {
541
+ if (entries.get(args.name) === void 0) throw new Error(`wakeStreamProcessor for unknown name "${args.name}" — subscribe by registered name (registered: ${[...entries.keys()].join(", ") || "none"})`);
542
+ return args.name;
543
+ }
544
+ const live = new LiveState({});
545
+ function assembleLive() {
546
+ if ([...entries.values()].some((entry) => !entry.runner.isLoaded)) {
547
+ options.onLiveAssembled?.({ skippedUnloadedRunners: true });
548
+ return;
549
+ }
550
+ const primary = [...entries.values()][0]?.runner.currentState;
551
+ live.setState(options.getLiveState?.() ?? primary ?? {});
552
+ options.onLiveAssembled?.({ skippedUnloadedRunners: false });
553
+ }
554
+ async function loadThenAssemble() {
555
+ await Promise.all([...entries.values()].map((entry) => entry.runner.snapshot()));
556
+ assembleLive();
557
+ }
558
+ return {
559
+ stream: options.stream,
560
+ live,
561
+ refreshLive: assembleLive,
562
+ loadAndRefreshLive: loadThenAssemble,
563
+ get names() {
564
+ return [...entries.keys()];
565
+ },
566
+ register(processor, opts) {
567
+ const name = opts?.name ?? processor.contract.slug;
568
+ if (entries.has(name)) throw new Error(`Stream processor name "${name}" is already registered on this registry`);
569
+ for (const [registeredName, entry] of entries) if (entry.processor === processor) throw new Error(`this exact processor instance is already registered as "${registeredName}" — construct one instance per registration`);
570
+ const recovery = opts?.recovery ? durableObjectRecovery({
571
+ storage: ctx.storage,
572
+ name,
573
+ stream: options.stream,
574
+ version: options.version,
575
+ armAlarm: (atMs) => void setAlarmSlice(`keepalive:${name}`, atMs),
576
+ waitUntil: (work) => ctx.waitUntil(work),
577
+ now
578
+ }) : void 0;
579
+ const runner = new StreamProcessorRunner({
580
+ processor,
581
+ stream: options.stream,
582
+ durability: {
583
+ progress: durableObjectProgressStore({
584
+ storage: ctx.storage,
585
+ name,
586
+ resetForStream: opts?.resetForStream,
587
+ reductionCache: opts?.reductionCache
588
+ }),
589
+ ...recovery === void 0 ? {} : { recovery }
590
+ },
591
+ keepAlive: (work) => ctx.waitUntil(work()),
592
+ now
593
+ });
594
+ entries.set(name, {
595
+ processor,
596
+ runner,
597
+ ...recovery === void 0 ? {} : { recovery }
598
+ });
599
+ runner.observeStateChanges(() => assembleLive());
600
+ return processor;
601
+ },
602
+ reads(processorOrName) {
603
+ const entry = typeof processorOrName === "string" ? requireEntry(processorOrName) : requireEntryForInstance(processorOrName, "reads");
604
+ const { runner } = entry;
605
+ return {
606
+ snapshot: () => runner.snapshot(),
607
+ getRuntimeState: async () => {
608
+ return {
609
+ ...await entry.processor.getRuntimeState(),
610
+ snapshot: await runner.snapshot()
611
+ };
612
+ },
613
+ waitUntilEvent: (input) => "offset" in input ? runner.waitUntilEvent(input) : runner.waitUntilEvent(input),
614
+ catchUp: () => runner.catchUp(),
615
+ get currentAcknowledgedThroughOffset() {
616
+ return runner.currentAcknowledgedThroughOffset;
617
+ },
618
+ get currentStreamId() {
619
+ return runner.currentStreamId;
620
+ },
621
+ get currentState() {
622
+ return runner.currentState;
623
+ },
624
+ get isLoaded() {
625
+ return runner.isLoaded;
626
+ }
627
+ };
628
+ },
629
+ observeStateChanges(processor, observer) {
630
+ return requireEntryForInstance(processor, "observeStateChanges").runner.observeStateChanges(observer);
631
+ },
632
+ async catchUp(name) {
633
+ await requireEntry(name).runner.catchUp();
634
+ },
635
+ resetRecoveryBackoff(name) {
636
+ requireEntry(name).recovery?.resetBackoff?.();
637
+ },
638
+ handleAlarm(alarmInfo) {
639
+ return tracing.enterSpan("alarm processor keepalive", async (span) => {
640
+ platformAlarmAtMs = null;
641
+ const firedAt = now();
642
+ for (const [name, atMs] of alarmSlices) if (atMs <= firedAt) alarmSlices.delete(name);
643
+ span.setAttribute("iterate.alarm.kind", "processor_keepalive");
644
+ if (alarmInfo !== void 0) {
645
+ span.setAttribute("iterate.alarm.is_retry", alarmInfo.isRetry);
646
+ span.setAttribute("iterate.alarm.retry_count", alarmInfo.retryCount);
647
+ }
648
+ try {
649
+ const failures = [];
650
+ for (const [name, entry] of entries) try {
651
+ await entry.runner.handleAlarm(alarmInfo);
652
+ } catch (error) {
653
+ console.error(`stream processor "${name}" alarm handling failed`, error);
654
+ failures.push(error);
655
+ }
656
+ if (failures.length > 0) throw failures[0];
657
+ } finally {
658
+ await reconcileAlarm();
659
+ }
660
+ });
661
+ },
662
+ setAlarmSlice,
663
+ getAlarmSlice: (name) => alarmSlices.get(name) ?? null,
664
+ async wakeStreamProcessor(args) {
665
+ if (args.stream.projectId !== options.projectId || args.stream.path !== options.path) throw new Error(`wakeStreamProcessor coordinate mismatch: wake for ${args.stream.projectId ?? "null"}:${args.stream.path} does not match registry ${options.projectId ?? "null"}:${options.path}`);
666
+ const name = resolveProcessorName(args);
667
+ const entry = requireEntry(name);
668
+ if (!z.uuid().safeParse(args.stream.streamId).success) throw new Error(`wakeStreamProcessor streamId must be a UUID`);
669
+ const opened = await entry.runner.openHostedEventBatchCallback(args.stream.streamId);
670
+ const processEventBatch = (batch) => {
671
+ const { reportDeliveryResult, ...frame } = batch;
672
+ if (frame.projectId !== options.projectId || frame.path !== options.path || frame.streamId !== args.stream.streamId) throw new Error(`hosted processor "${name}" received batch for ${frame.projectId ?? "null"}:${frame.path}:${frame.streamId}; expected ${options.projectId ?? "null"}:${options.path}:${args.stream.streamId}`);
673
+ let retainedResultCallback;
674
+ try {
675
+ retainedResultCallback = retainCallback(reportDeliveryResult);
676
+ } catch (error) {
677
+ console.error("stream wake delivery result callback could not be retained", { error });
678
+ return;
679
+ }
680
+ let attempt;
681
+ try {
682
+ attempt = opened.processEventBatch(frame);
683
+ } catch (error) {
684
+ attempt = Promise.reject(error);
685
+ }
686
+ const report = attempt.then(() => reportWakeDeliveryResult(retainedResultCallback, { outcome: "ok" }), (error) => reportWakeDeliveryResult(retainedResultCallback, {
687
+ outcome: "error",
688
+ error: serializeWakeDeliveryError(error)
689
+ }));
690
+ ctx.waitUntil(report.finally(() => {
691
+ try {
692
+ retainedResultCallback[Symbol.dispose]();
693
+ } catch (error) {
694
+ console.warn("stream wake delivery result callback disposal failed", { error });
695
+ }
696
+ }));
697
+ };
698
+ const capabilities = hostRuntimeCapabilities(entry.processor, {
699
+ now,
700
+ snapshot: () => entry.runner.snapshot()
701
+ });
702
+ return {
703
+ streamId: args.stream.streamId,
704
+ checkpointOffset: opened.checkpointOffset,
705
+ processEventBatch,
706
+ openedBy: { processor: { announcement: announceContract(entry.processor.contract) } },
707
+ ...capabilities
708
+ };
709
+ }
710
+ };
711
+ }
712
+ //#endregion
713
+ //#region src/processors/processor-facet.ts
714
+ /**
715
+ * Where the configured identity lives in the facet's own kv. Exported so a
716
+ * subclass's own doors can self-heal a fresh incarnation (re-run the
717
+ * idempotent `configure` from the stash) before the base's boot microtask has
718
+ * run — see apps/os `ProcessorFacet.#requireRegistry`.
719
+ */
720
+ const FACET_IDENTITY_KEY = "iterate:processor-facet:identity";
721
+ /**
722
+ * A view of `target` with `overrides` in front and everything else passed
723
+ * through. Proxies (not spreads or Object.create) because DurableObjectState
724
+ * and DurableObjectStorage are host objects: their methods must be invoked
725
+ * with the REAL receiver or workerd throws "Illegal invocation". (The same
726
+ * overlay as sdk.ts's `selfAlarmState` facade — duplicated here because the
727
+ * sdk entry drags its whole dependency graph along.)
728
+ */
729
+ function overlay(target, overrides) {
730
+ return new Proxy(target, { get(object, prop) {
731
+ if (Object.hasOwn(overrides, prop)) return overrides[prop];
732
+ const value = Reflect.get(object, prop, object);
733
+ return typeof value === "function" ? value.bind(object) : value;
734
+ } });
735
+ }
736
+ /**
737
+ * A facet's `DurableObjectState` facade for `createStreamProcessorRegistry`:
738
+ * ONLY `storage.setAlarm` / `storage.deleteAlarm` / `storage.getAlarm` are
739
+ * overridden to dial the parent's {@link ProcessorFacetAlarmProxy}; kv,
740
+ * waitUntil, and everything else pass through untouched. `parentAlarms` is
741
+ * invoked PER CALL — the parent stub must be resolved lazily from the stashed
742
+ * identity, because the recovery adapter's boot reconcile issues alarm calls
743
+ * at construction and a stub captured once would outlive its RPC session.
744
+ */
745
+ function facetProcessorDurableObjectState(ctx, parentAlarms) {
746
+ return overlay(ctx, { storage: overlay(ctx.storage, {
747
+ setAlarm: async (scheduledTime) => {
748
+ disposeIgnoredRpcResult(await parentAlarms().proxySetAlarm(typeof scheduledTime === "number" ? scheduledTime : scheduledTime.getTime()));
749
+ },
750
+ deleteAlarm: async () => {
751
+ disposeIgnoredRpcResult(await parentAlarms().proxyDeleteAlarm());
752
+ },
753
+ getAlarm: async () => await parentAlarms().proxyGetAlarm()
754
+ }) });
755
+ }
756
+ /**
757
+ * Plain-copy an `AlarmInvocationInfo` before a facet hop. The platform hands
758
+ * the parent's `alarm()` a host object that does not serialize across RPC;
759
+ * a parent replaying a fire into {@link ProcessorFacet.handleAlarm} must send
760
+ * this copy instead.
761
+ */
762
+ function plainAlarmInvocationInfo(info) {
763
+ if (info === void 0) return void 0;
764
+ const { scheduledTime } = info;
765
+ return {
766
+ ...scheduledTime === void 0 ? {} : { scheduledTime },
767
+ isRetry: info.isRetry,
768
+ retryCount: info.retryCount
769
+ };
770
+ }
771
+ /**
772
+ * Generic base for hosting stream processors in a Durable Object facet.
773
+ * Subclasses are the per-host composition (the facets task's target shape) and
774
+ * supply exactly two things: how to dial the parent's alarm proxy and what
775
+ * this host runs —
776
+ *
777
+ * ```ts
778
+ * export class AgentProcessors extends ProcessorFacet<Env> {
779
+ * protected parentAlarms({ parentName }: ProcessorFacetIdentity) {
780
+ * return this.env.STREAM.getByName(parentName);
781
+ * }
782
+ * protected createHost({ path, projectId }: ProcessorFacetIdentity): ProcessorFacetHost {
783
+ * const stream = ...; // dial the parent stream
784
+ * return {
785
+ * stream,
786
+ * version: workerVersion(this.env),
787
+ * registerProcessors: (registry) => {
788
+ * registry.register(
789
+ * new AgentProcessor({ stream, path, projectId, ... }),
790
+ * { recovery: true, name: "agent" },
791
+ * );
792
+ * },
793
+ * };
794
+ * }
795
+ * }
796
+ * ```
797
+ *
798
+ * The parent creates it with `ctx.facets.get(name, () => ({ class:
799
+ * ctx.exports.AgentProcessors }))`, calls `configure()` once (idempotent), and
800
+ * routes wakes/alarms/doors to the RPC surface below.
801
+ *
802
+ * THIS CLASS MUST NEVER DEFINE `alarm()` — and neither may a subclass. The
803
+ * fire arrives as `handleAlarm` (an ordinary RPC verb) instead: workerd
804
+ * reserves `alarm` for its native handler, and with one present a failed
805
+ * native `setAlarm` poisons the facet's output gate (workerd#6810). The
806
+ * constructor enforces this.
807
+ */
808
+ var ProcessorFacet = class extends DurableObject {
809
+ #host;
810
+ constructor(ctx, env) {
811
+ super(ctx, env);
812
+ if ("alarm" in this && typeof this.alarm === "function") throw new Error(`${this.constructor.name} must not define alarm(): facets have no native alarms (workerd#6810 — a failed setAlarm would poison this facet's output gate). The parent's fire arrives as handleAlarm() instead.`);
813
+ Promise.resolve().then(() => {
814
+ try {
815
+ if (this.#readIdentity() !== void 0) this.#requireHost();
816
+ } catch (error) {
817
+ console.error("ProcessorFacet boot host construction failed", error);
818
+ }
819
+ });
820
+ }
821
+ /**
822
+ * First-contact identity stash, idempotent: re-configuring with the same
823
+ * identity is a no-op (and ensures the host is built); a DIFFERENT identity
824
+ * throws — a facet's coordinate never changes, so a mismatch is a miswire,
825
+ * not a migration.
826
+ */
827
+ configure(identity) {
828
+ const stashed = this.#readIdentity();
829
+ if (stashed !== void 0) {
830
+ if (stashed.parentName !== identity.parentName || stashed.projectId !== identity.projectId || stashed.path !== identity.path) throw new Error(`ProcessorFacet is configured for ${stashed.projectId ?? "null"}:${stashed.path} (parent "${stashed.parentName}") and cannot be re-configured for ${identity.projectId ?? "null"}:${identity.path} (parent "${identity.parentName}")`);
831
+ this.#requireHost();
832
+ return;
833
+ }
834
+ this.ctx.storage.kv.put(FACET_IDENTITY_KEY, {
835
+ parentName: identity.parentName,
836
+ projectId: identity.projectId,
837
+ path: identity.path
838
+ });
839
+ this.#requireHost();
840
+ }
841
+ /** The wake door — the parent's colocated delivery dial. Routes to the
842
+ * registry: name-first resolution, coordinate fence, per-batch settlement
843
+ * through each batch's independent `reportDeliveryResult`. */
844
+ wakeStreamProcessor(request) {
845
+ return this.#requireHost().registry.wakeStreamProcessor(request);
846
+ }
847
+ /**
848
+ * The parent's alarm replay door — deliberately NOT named `alarm` (see the
849
+ * class doc). The parent plain-copies its `AlarmInvocationInfo`
850
+ * ({@link plainAlarmInvocationInfo}) and awaits this; a rejection propagates
851
+ * so the parent can rethrow and get the platform's alarm retry.
852
+ */
853
+ async handleAlarm(info) {
854
+ if (this.#readIdentity() === void 0) {
855
+ console.warn("ProcessorFacet.handleAlarm before configure(); nothing to revive");
856
+ return;
857
+ }
858
+ await this.#requireHost().registry.handleAlarm(plainAlarmInvocationInfo(info));
859
+ }
860
+ /** One consistent read of a hosted processor's committed fold. `name` may be
861
+ * omitted on a single-processor host. */
862
+ async snapshot(args) {
863
+ return await this.#reads(args?.name).snapshot();
864
+ }
865
+ /** The hosted processor's runtime state (runner snapshot + contributed
866
+ * runtime bag). `name` may be omitted on a single-processor host. */
867
+ async getRuntimeState(args) {
868
+ return await this.#reads(args?.name).getRuntimeState();
869
+ }
870
+ /** Resolve once the named processor's acknowledged cursor reaches `offset` —
871
+ * the read-your-writes barrier. The subscription catalog's uniform
872
+ * `waitUntilProcessed` delegates its facet-placed processor rows here. */
873
+ async waitUntilProcessed(args) {
874
+ const { name, ...input } = args;
875
+ await this.#reads(name).waitUntilEvent(input);
876
+ }
877
+ /** Pull the named processor through the durable stream tail — the parent
878
+ * facade's catch-up-before-snapshot leg, dialed before every facet read.
879
+ * `name` may be omitted on a single-processor host. */
880
+ async catchUp(args) {
881
+ await this.#reads(args?.name).catchUp();
882
+ }
883
+ /** Read a transient snapshot or delta for the parent's current stream lifetime.
884
+ * Cold or replaced processors hydrate from durable progress. Warm reads use
885
+ * committed local state: polling must not call back into the parent stream
886
+ * for every processor while it is delivering events to this facet. */
887
+ async readLiveState(args) {
888
+ const { registry } = this.#requireHost();
889
+ if (registry.names.some((name) => {
890
+ const reads = registry.reads(name);
891
+ return !reads.isLoaded || reads.currentStreamId !== args.streamId;
892
+ })) await registry.loadAndRefreshLive();
893
+ else registry.refreshLive();
894
+ return registry.live.readSince(args.cursor, { patchVersion: args.patchVersion });
895
+ }
896
+ /** Direct subscriptions retain their callbacks across the Workers RPC hop. */
897
+ liveState() {
898
+ const { registry } = this.#requireHost();
899
+ return {
900
+ get: async () => {
901
+ await registry.loadAndRefreshLive();
902
+ return registry.live.getState();
903
+ },
904
+ subscribe: async (onUpdate, options) => {
905
+ await registry.loadAndRefreshLive();
906
+ const subscription = registry.live.subscribe(onUpdate, options);
907
+ return {
908
+ ping: () => subscription.ping(),
909
+ unsubscribe: () => subscription.unsubscribe(),
910
+ [Symbol.dispose]: () => subscription.unsubscribe()
911
+ };
912
+ }
913
+ };
914
+ }
915
+ #readIdentity() {
916
+ return this.ctx.storage.kv.get(FACET_IDENTITY_KEY);
917
+ }
918
+ #requireIdentity() {
919
+ const identity = this.#readIdentity();
920
+ if (identity === void 0) throw new Error("ProcessorFacet has no stashed identity yet — call configure() first");
921
+ return identity;
922
+ }
923
+ #requireHost() {
924
+ if (this.#host === void 0) {
925
+ const identity = this.#requireIdentity();
926
+ const host = this.createHost(identity);
927
+ const registry = createStreamProcessorRegistry(facetProcessorDurableObjectState(this.ctx, () => this.parentAlarms(this.#requireIdentity())), {
928
+ stream: host.stream,
929
+ path: identity.path,
930
+ projectId: identity.projectId,
931
+ version: host.version,
932
+ ...host.now === void 0 ? {} : { now: host.now },
933
+ ...host.getLiveState === void 0 ? {} : { getLiveState: host.getLiveState }
934
+ });
935
+ host.registerProcessors(registry);
936
+ this.#host = { registry };
937
+ }
938
+ return this.#host;
939
+ }
940
+ #reads(name) {
941
+ const { registry } = this.#requireHost();
942
+ if (name !== void 0) return registry.reads(name);
943
+ const names = registry.names;
944
+ if (names.length === 1) return registry.reads(names[0]);
945
+ throw new Error(`this facet hosts ${names.length} processors (${names.join(", ") || "none"}); pass a name`);
946
+ }
947
+ };
948
+ //#endregion
949
+ export { createStreamProcessorRegistry as a, compactPatch as c, disposeIgnoredRpcResult as d, isThenable as f, plainAlarmInvocationInfo as i, applyPatch as l, ProcessorFacet as n, LiveState as o, retainCallback as p, facetProcessorDurableObjectState as r, applyCompactPatch as s, FACET_IDENTITY_KEY as t, diff as u };
950
+
951
+ //# sourceMappingURL=cloudflare-BTm90gQ4.mjs.map