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.
Files changed (241) hide show
  1. package/README.md +164 -82
  2. package/dist/{next/api.d.ts → api.d.ts} +197 -33
  3. package/dist/{next/app-server.d.ts → app-server.d.ts} +7 -0
  4. package/dist/{next/app-server.mjs → app-server.mjs} +17 -15
  5. package/dist/app-server.mjs.map +1 -0
  6. package/dist/{next/app-session.mjs → app-session.mjs} +12 -15
  7. package/dist/app-session.mjs.map +1 -0
  8. package/dist/{next/app.mjs → app.mjs} +53 -14
  9. package/dist/app.mjs.map +1 -0
  10. package/dist/{next/client → client}/live-state.d.ts +11 -11
  11. package/dist/client/oauth.d.ts +17 -0
  12. package/dist/{next/client → client}/react.d.ts +10 -42
  13. package/dist/{next/client → client}/socket.d.ts +1 -0
  14. package/dist/client.mjs +156 -4
  15. package/dist/client.mjs.map +1 -0
  16. package/dist/{next/expression.d.ts → expression.d.ts} +11 -69
  17. package/dist/{next/expression.mjs → expression.mjs} +11 -109
  18. package/dist/expression.mjs.map +1 -0
  19. package/dist/lib-BWr-5mFO.mjs +36 -0
  20. package/dist/lib-BWr-5mFO.mjs.map +1 -0
  21. package/dist/{next/lib.d.ts → lib.d.ts} +16 -2
  22. package/dist/{next/lib.mjs → lib.mjs} +32 -3
  23. package/dist/lib.mjs.map +1 -0
  24. package/dist/node.d.ts +15 -3
  25. package/dist/node.mjs +36 -174
  26. package/dist/node.mjs.map +1 -1
  27. package/dist/{next/oauth-scopes.mjs → oauth-scopes.mjs} +1 -1
  28. package/dist/oauth-scopes.mjs.map +1 -0
  29. package/dist/{next/oauth.mjs → oauth.mjs} +14 -2
  30. package/dist/oauth.mjs.map +1 -0
  31. package/dist/principal.d.ts +8 -0
  32. package/dist/principal.mjs +8 -0
  33. package/dist/principal.mjs.map +1 -0
  34. package/dist/project-ingress.d.ts +58 -0
  35. package/dist/project-ingress.mjs +104 -0
  36. package/dist/project-ingress.mjs.map +1 -0
  37. package/dist/{next/react.mjs → react.mjs} +12 -12
  38. package/dist/react.mjs.map +1 -0
  39. package/dist/sdk/auth.d.ts +25 -0
  40. package/dist/sdk/index.d.ts +155 -0
  41. package/dist/sdk/record-pipelined-steps.d.ts +19 -0
  42. package/dist/sdk.mjs +245 -2
  43. package/dist/sdk.mjs.map +1 -0
  44. package/dist/{next/stream → stream}/processor.d.ts +28 -23
  45. package/dist/{next/stream → stream}/processor.mjs +48 -25
  46. package/dist/stream/processor.mjs.map +1 -0
  47. package/dist/{next/stream → stream}/run.d.ts +9 -6
  48. package/dist/{next/stream → stream}/run.mjs +13 -8
  49. package/dist/stream/run.mjs.map +1 -0
  50. package/dist/stream/test-support.d.ts +45 -0
  51. package/dist/stream/test-support.mjs +196 -0
  52. package/dist/stream/test-support.mjs.map +1 -0
  53. package/package.json +65 -219
  54. package/THIRD_PARTY_NOTICES.md +0 -55
  55. package/bin/iterate.js +0 -94
  56. package/dist/api-url-B6404M82.mjs +0 -17
  57. package/dist/api-url-B6404M82.mjs.map +0 -1
  58. package/dist/app-ref-BipL0feU.mjs +0 -35
  59. package/dist/app-ref-BipL0feU.mjs.map +0 -1
  60. package/dist/app-ref-C1CrgXqX.mjs +0 -7
  61. package/dist/app-ref-C1CrgXqX.mjs.map +0 -1
  62. package/dist/app-ref-DYai_om1.mjs +0 -7
  63. package/dist/app-ref-DYai_om1.mjs.map +0 -1
  64. package/dist/cli-D0c-pDL_.mjs +0 -1010
  65. package/dist/cli-D0c-pDL_.mjs.map +0 -1
  66. package/dist/client.d.ts +0 -3
  67. package/dist/cloudflare-BTm90gQ4.mjs +0 -951
  68. package/dist/cloudflare-BTm90gQ4.mjs.map +0 -1
  69. package/dist/contract-s4FW4eES.mjs +0 -309
  70. package/dist/contract-s4FW4eES.mjs.map +0 -1
  71. package/dist/document-review/index.d.ts +0 -5
  72. package/dist/document-review/types.d.ts +0 -107
  73. package/dist/document-review.mjs +0 -7015
  74. package/dist/document-review.mjs.map +0 -1
  75. package/dist/durable-object-processor-durability-CNsTjAJS.mjs +0 -205
  76. package/dist/durable-object-processor-durability-CNsTjAJS.mjs.map +0 -1
  77. package/dist/idempotency-DleloJNt.mjs +0 -28
  78. package/dist/idempotency-DleloJNt.mjs.map +0 -1
  79. package/dist/index.d.mts +0 -5
  80. package/dist/index.mjs +0 -8
  81. package/dist/index.mjs.map +0 -1
  82. package/dist/itx/api-url.d.ts +0 -6
  83. package/dist/itx/itx-node-client.d.ts +0 -65
  84. package/dist/itx/itx-session.d.ts +0 -215
  85. package/dist/itx/owned-rpc-session.d.ts +0 -14
  86. package/dist/itx/query-client.d.ts +0 -10
  87. package/dist/itx-api.generated.d.ts +0 -6195
  88. package/dist/itx-session-sjud8GiT.mjs +0 -534
  89. package/dist/itx-session-sjud8GiT.mjs.map +0 -1
  90. package/dist/live-state-BJNqOwFw.mjs +0 -299
  91. package/dist/live-state-BJNqOwFw.mjs.map +0 -1
  92. package/dist/next/app-server.mjs.map +0 -1
  93. package/dist/next/app-session.mjs.map +0 -1
  94. package/dist/next/app.mjs.map +0 -1
  95. package/dist/next/client/oauth.d.ts +0 -12
  96. package/dist/next/client.mjs +0 -156
  97. package/dist/next/client.mjs.map +0 -1
  98. package/dist/next/expression.mjs.map +0 -1
  99. package/dist/next/lib.mjs.map +0 -1
  100. package/dist/next/oauth-scopes.mjs.map +0 -1
  101. package/dist/next/oauth.mjs.map +0 -1
  102. package/dist/next/principal.d.ts +0 -64
  103. package/dist/next/principal.mjs +0 -98
  104. package/dist/next/principal.mjs.map +0 -1
  105. package/dist/next/project-ingress.d.ts +0 -37
  106. package/dist/next/project-ingress.mjs +0 -75
  107. package/dist/next/project-ingress.mjs.map +0 -1
  108. package/dist/next/react.mjs.map +0 -1
  109. package/dist/next/sdk/auth.d.ts +0 -5
  110. package/dist/next/sdk/index.d.ts +0 -112
  111. package/dist/next/sdk.mjs +0 -139
  112. package/dist/next/sdk.mjs.map +0 -1
  113. package/dist/next/stream/processor.mjs.map +0 -1
  114. package/dist/next/stream/run.mjs.map +0 -1
  115. package/dist/next-node.d.ts +0 -15
  116. package/dist/next-node.mjs +0 -51
  117. package/dist/next-node.mjs.map +0 -1
  118. package/dist/processor-host-capabilities-BMFH3KTM.mjs +0 -56
  119. package/dist/processor-host-capabilities-BMFH3KTM.mjs.map +0 -1
  120. package/dist/processors/cloudflare.d.ts +0 -3
  121. package/dist/processors/durable-object-processor-durability.d.ts +0 -79
  122. package/dist/processors/event-consumption-metrics.d.ts +0 -82
  123. package/dist/processors/idempotency.d.ts +0 -13
  124. package/dist/processors/index.d.ts +0 -12
  125. package/dist/processors/processor-contracts.d.ts +0 -342
  126. package/dist/processors/processor-facet.d.ts +0 -186
  127. package/dist/processors/processor-host-capabilities.d.ts +0 -60
  128. package/dist/processors/prompt-sections.d.ts +0 -17
  129. package/dist/processors/rpc-types.d.ts +0 -515
  130. package/dist/processors/schemas.d.ts +0 -102
  131. package/dist/processors/stream-handle.d.ts +0 -45
  132. package/dist/processors/stream-processor-keepalive.d.ts +0 -95
  133. package/dist/processors/stream-processor-registry.d.ts +0 -233
  134. package/dist/processors/stream-processor-runner.d.ts +0 -289
  135. package/dist/processors/stream-processor.d.ts +0 -339
  136. package/dist/processors/stream-runtime-metrics.d.ts +0 -107
  137. package/dist/processors/testing.d.ts +0 -302
  138. package/dist/processors-BoNyeBfQ.mjs +0 -10
  139. package/dist/processors-BoNyeBfQ.mjs.map +0 -1
  140. package/dist/processors-cloudflare.mjs +0 -3
  141. package/dist/processors-testing.mjs +0 -435
  142. package/dist/processors-testing.mjs.map +0 -1
  143. package/dist/processors.mjs +0 -52
  144. package/dist/processors.mjs.map +0 -1
  145. package/dist/protocol-DnK_f2m6.mjs +0 -251
  146. package/dist/protocol-DnK_f2m6.mjs.map +0 -1
  147. package/dist/sdk/capnweb/index.d.ts +0 -2
  148. package/dist/sdk/capnweb/live-state/compact.d.ts +0 -5
  149. package/dist/sdk/capnweb/live-state/diff.d.ts +0 -41
  150. package/dist/sdk/capnweb/live-state/engine.d.ts +0 -44
  151. package/dist/sdk/capnweb/live-state/index.d.ts +0 -41
  152. package/dist/sdk/capnweb/live-state/protocol.d.ts +0 -87
  153. package/dist/sdk/capnweb/live-state/retain.d.ts +0 -23
  154. package/dist/sdk/capnweb/live-state/store.d.ts +0 -20
  155. package/dist/sdk/capnweb/live-state/types.d.ts +0 -11
  156. package/dist/sdk/capnweb/react.d.ts +0 -45
  157. package/dist/sdk/capnweb/react.mjs +0 -316
  158. package/dist/sdk/capnweb/react.mjs.map +0 -1
  159. package/dist/sdk/capnweb.mjs +0 -4
  160. package/dist/sdk/itx/react.d.ts +0 -191
  161. package/dist/sdk/itx/react.mjs +0 -383
  162. package/dist/sdk/itx/react.mjs.map +0 -1
  163. package/dist/sdk-DMB-IM11.mjs +0 -933
  164. package/dist/sdk-DMB-IM11.mjs.map +0 -1
  165. package/dist/sdk.d.ts +0 -339
  166. package/dist/serve-itx.d.ts +0 -46
  167. package/dist/starter-apps/flake-dashboard/app-ref.d.ts +0 -31
  168. package/dist/starter-apps/flake-dashboard/configured-worker.mjs +0 -1055
  169. package/dist/starter-apps/flake-dashboard/configured-worker.mjs.map +0 -1
  170. package/dist/starter-apps/flake-dashboard/contract.d.ts +0 -4839
  171. package/dist/starter-apps/flake-dashboard/contract.mjs +0 -2
  172. package/dist/starter-apps/flake-dashboard/index.d.ts +0 -17
  173. package/dist/starter-apps/flake-dashboard/index.mjs +0 -56
  174. package/dist/starter-apps/flake-dashboard/index.mjs.map +0 -1
  175. package/dist/starter-apps/flake-dashboard/worker.d.ts +0 -4607
  176. package/dist/starter-apps/github-ai-linter/ai-linter.d.ts +0 -8914
  177. package/dist/starter-apps/github-ai-linter/configured-worker.mjs +0 -17987
  178. package/dist/starter-apps/github-ai-linter/configured-worker.mjs.map +0 -1
  179. package/dist/starter-apps/github-ai-linter/contract.d.ts +0 -9193
  180. package/dist/starter-apps/github-ai-linter/index.d.ts +0 -10
  181. package/dist/starter-apps/github-ai-linter/index.mjs +0 -36
  182. package/dist/starter-apps/github-ai-linter/index.mjs.map +0 -1
  183. package/dist/starter-apps/github-ai-linter/prompt.d.ts +0 -13
  184. package/dist/starter-apps/github-ai-linter/review-bot.d.ts +0 -808
  185. package/dist/starter-apps/github-ai-linter/rules.d.ts +0 -34
  186. package/dist/starter-apps/github-ai-linter/worker-ref.d.ts +0 -19
  187. package/dist/starter-apps/github-ai-linter/worker.d.ts +0 -19
  188. package/dist/starter-apps/github-ai-linter/worker.mjs +0 -947
  189. package/dist/starter-apps/github-ai-linter/worker.mjs.map +0 -1
  190. package/dist/starter-apps/guestbook/app-ref.d.ts +0 -27
  191. package/dist/starter-apps/guestbook/client.d.ts +0 -7
  192. package/dist/starter-apps/guestbook/client.mjs +0 -59
  193. package/dist/starter-apps/guestbook/configured-worker.mjs +0 -205
  194. package/dist/starter-apps/guestbook/configured-worker.mjs.map +0 -1
  195. package/dist/starter-apps/guestbook/index.d.ts +0 -9
  196. package/dist/starter-apps/guestbook/index.mjs +0 -31
  197. package/dist/starter-apps/guestbook/index.mjs.map +0 -1
  198. package/dist/starter-apps/guestbook/processor.d.ts +0 -2267
  199. package/dist/starter-apps/guestbook/worker.d.ts +0 -26
  200. package/dist/starter-apps/guestbook/worker.mjs +0 -191
  201. package/dist/starter-apps/guestbook/worker.mjs.map +0 -1
  202. package/dist/starter-apps/media/configured-worker.mjs +0 -577
  203. package/dist/starter-apps/media/configured-worker.mjs.map +0 -1
  204. package/dist/starter-apps/media/index.mjs +0 -36
  205. package/dist/starter-apps/media/index.mjs.map +0 -1
  206. package/dist/starter-apps/media/ref.mjs +0 -20
  207. package/dist/starter-apps/media/ref.mjs.map +0 -1
  208. package/dist/starter-apps/media/worker.mjs +0 -579
  209. package/dist/starter-apps/media/worker.mjs.map +0 -1
  210. package/dist/starter-apps/notes/configured-worker.mjs +0 -6134
  211. package/dist/starter-apps/notes/configured-worker.mjs.map +0 -1
  212. package/dist/starter-apps/notes/index.mjs +0 -23
  213. package/dist/starter-apps/notes/index.mjs.map +0 -1
  214. package/dist/starter-apps/notes/ref.mjs +0 -21
  215. package/dist/starter-apps/notes/ref.mjs.map +0 -1
  216. package/dist/starter-apps/notes/worker.mjs +0 -427
  217. package/dist/starter-apps/notes/worker.mjs.map +0 -1
  218. package/dist/starter-apps/todo/client.mjs +0 -59
  219. package/dist/starter-apps/todo/configured-worker.mjs +0 -2864
  220. package/dist/starter-apps/todo/configured-worker.mjs.map +0 -1
  221. package/dist/starter-apps/todo/index.d.ts +0 -8
  222. package/dist/starter-apps/todo/index.mjs +0 -29
  223. package/dist/starter-apps/todo/index.mjs.map +0 -1
  224. package/dist/stream-processor-keepalive-DAQTP6m3.mjs +0 -2082
  225. package/dist/stream-processor-keepalive-DAQTP6m3.mjs.map +0 -1
  226. package/dist/usingCtx-mZx5nsAW.mjs +0 -11800
  227. package/dist/usingCtx-mZx5nsAW.mjs.map +0 -1
  228. package/dist/worker-ref-DZxPDmb_.mjs +0 -390
  229. package/dist/worker-ref-DZxPDmb_.mjs.map +0 -1
  230. package/dist/worker.d.mts +0 -33
  231. package/dist/worker.mjs +0 -18
  232. package/dist/worker.mjs.map +0 -1
  233. package/menubar/Iterate.entitlements +0 -12
  234. package/menubar/Iterate.swift +0 -914
  235. package/menubar/IterateIcon.swift +0 -145
  236. package/menubar/README.md +0 -28
  237. package/menubar/build-menubar-app.sh +0 -59
  238. /package/dist/{next/api.mjs → api.mjs} +0 -0
  239. /package/dist/{next/app-session.d.ts → app-session.d.ts} +0 -0
  240. /package/dist/{next/app.d.ts → app.d.ts} +0 -0
  241. /package/dist/{next/oauth-scopes.d.ts → oauth-scopes.d.ts} +0 -0
package/dist/sdk.mjs CHANGED
@@ -1,2 +1,245 @@
1
- import { a as createProcessorHost, i as StreamProcessorFacet, n as IterateWorkerEntrypoint, o as itxProjectStream, r as StreamProcessorDurableObject, s as serveItx, t as IterateDurableObject } from "./sdk-DMB-IM11.mjs";
2
- export { IterateDurableObject, IterateWorkerEntrypoint, StreamProcessorDurableObject, StreamProcessorFacet, createProcessorHost, itxProjectStream, serveItx };
1
+ import { applyPatch, diff, isSameOriginBrowserRequest, jsonEqual, releaseRpcSessions } from "./lib.mjs";
2
+ import { LiveState, ProcessorEngine, ReduceCheckpointTable, StreamProcessor, defineProcessorContract } from "./stream/processor.mjs";
3
+ import { ITX_PRINCIPAL_HEADER } from "./principal.mjs";
4
+ import { RunContract, RunRequested, RunSettled } from "./stream/run.mjs";
5
+ import { DurableObject, WorkerEntrypoint } from "cloudflare:workers";
6
+ import { z, z as z$1 } from "zod";
7
+ import { newHttpBatchRpcSession, newWebSocketRpcSession, newWorkersRpcResponse } from "capnweb";
8
+ //#region src/sdk/auth.ts
9
+ const Principal = z$1.object({
10
+ actor: z$1.string().min(1),
11
+ email: z$1.string().optional()
12
+ });
13
+ /** Project ingress strips public identity headers and stamps `x-itx-principal` for a project member
14
+ * only: a visitor signed out, signed in without this project, or riding a session cookie on a
15
+ * cross-site write arrives without one. This guard runs in the config worker, before it proxies an
16
+ * app.
17
+ *
18
+ * Signed out, every request gets `401` with `WWW-Authenticate: Bearer realm="iterate"`: the
19
+ * platform's edge turns that answer into the sign-in for a page load (or into "sign in again with
20
+ * this project" for someone signed in without it), whatever path the app is served under, and hands
21
+ * a fetch, a write or a WebSocket upgrade the 401 itself. Any app can ask for a signed-in visitor
22
+ * the same way:
23
+ *
24
+ * ```js
25
+ * if (!request.headers.get("x-itx-principal"))
26
+ * return new Response("Sign in\n", { status: 401, headers: { "WWW-Authenticate": 'Bearer realm="iterate"' } });
27
+ * ```
28
+ *
29
+ * A write or a WebSocket upgrade must also come from this origin (or carry no Origin, a non-browser
30
+ * client), else 403. The edge already sends such a cookie request on anonymous; this repeats the
31
+ * check where the app runs. The handshake is a GET, but it opens a two-way channel, and the app
32
+ * session cookie is `SameSite=Lax`: every `<routingSlug>--<project>.iterate.app` host is same-site with
33
+ * every other, so a page on another project's host could otherwise open a socket to this app with
34
+ * the visitor's cookie. */
35
+ const auth = { require(request) {
36
+ const isWebSocketUpgrade = request.headers.get("upgrade")?.toLowerCase() === "websocket";
37
+ if (!([
38
+ "GET",
39
+ "HEAD",
40
+ "OPTIONS"
41
+ ].includes(request.method) && !isWebSocketUpgrade) && !isSameOriginBrowserRequest(request)) return new Response("Cross-site request refused", { status: 403 });
42
+ const principal = request.headers.get(ITX_PRINCIPAL_HEADER);
43
+ if (principal) {
44
+ Principal.parse(JSON.parse(principal));
45
+ return null;
46
+ }
47
+ return new Response("Sign in\n", {
48
+ status: 401,
49
+ headers: {
50
+ "WWW-Authenticate": "Bearer realm=\"iterate\"",
51
+ "Cache-Control": "no-store"
52
+ }
53
+ });
54
+ } };
55
+ //#endregion
56
+ //#region src/sdk/record-pipelined-steps.ts
57
+ /** ONE round trip on `entrypoint.get()`, then RELEASE EVERYTHING IT REACHED: the scope and every call
58
+ * `call` made through it or through a handle it awaited, the last first. A release that throws is reported and the rest still run
59
+ * (lib.ts `releaseRpcSessions`), so the call's answer stands. Data it answers stays usable; a stub or
60
+ * handle it answers is released with the rest, so return data.
61
+ *
62
+ * const { projectSlug } = await withItx(this.env.ITX, (itx) => itx.whoami());
63
+ */
64
+ async function withItx(entrypoint, call) {
65
+ const steps = [];
66
+ const itx = entrypoint.get();
67
+ try {
68
+ return await call(recordPipelinedSteps(itx, steps));
69
+ } finally {
70
+ releaseRpcSessions([itx, ...steps]);
71
+ }
72
+ }
73
+ /** `stub` as the caller sees it, except that every CALL made through it — at any depth, on the stub,
74
+ * on a call's result, or on the handle a call's result resolves to once awaited — is pushed onto
75
+ * `steps`, so the caller can dispose each one: a Workers-RPC call's result is a stub-bearing promise
76
+ * that keeps its session open until disposed, awaited or not. Awaiting hands back a handle (a stub
77
+ * is callable, in workerd and capnweb alike) recorded and pushed too, and plain data untouched, so
78
+ * data still copies across RPC. `catch`/`finally` and symbol members (`Symbol.dispose`) are the
79
+ * value's own, bound to it, so disposing behaves exactly as on the bare stub; an argument that is
80
+ * itself a recorded value crosses the wire as the stub it wraps. */
81
+ function recordPipelinedSteps(stub, steps) {
82
+ const wrapped = /* @__PURE__ */ new WeakMap();
83
+ const record = (value, receiver) => {
84
+ if (!value || typeof value !== "object" && typeof value !== "function") return value;
85
+ const proxy = new Proxy(value, {
86
+ get(target, key) {
87
+ const member = Reflect.get(target, key);
88
+ if (key === "then" && typeof member === "function") return (onFulfilled, onRejected) => Reflect.apply(member, target, [typeof onFulfilled === "function" ? (answer) => {
89
+ if (typeof answer !== "function") return onFulfilled(answer);
90
+ steps.push(answer);
91
+ return onFulfilled(record(answer, void 0));
92
+ } : onFulfilled, onRejected]);
93
+ if (typeof key === "symbol" || key === "then" || key === "catch" || key === "finally") return typeof member === "function" ? member.bind(target) : member;
94
+ return record(member, target);
95
+ },
96
+ apply(target, _proxyReceiver, args) {
97
+ const result = Reflect.apply(target, receiver, args.map((arg) => wrapped.get(Object(arg)) ?? arg));
98
+ steps.push(result);
99
+ return record(result, void 0);
100
+ }
101
+ });
102
+ wrapped.set(proxy, value);
103
+ return proxy;
104
+ };
105
+ return record(stub, void 0);
106
+ }
107
+ //#endregion
108
+ //#region src/sdk/index.ts
109
+ /** THE FACET SHELL: a `DurableObject` a context hosts as a facet — `itx.facets.get(name, { source,
110
+ * className })`, a rule naming it, or a processor's row. A caller reaches a facet by itx expression
111
+ * (`itx.facets.get(name).<method>(…)`) only through what its class lists in `publicMethods`: the
112
+ * context refuses any other first step FORBIDDEN before the call reaches the facet
113
+ * (apps/os context/facet-public-methods.ts). The platform's own calls — the delivery loop's push
114
+ * and catch-up, the alarm's revive — never go through the list. A loaded class that does not
115
+ * extend this shell lists nothing, so no caller reaches it by expression. */
116
+ var FacetDurableObject = class extends DurableObject {
117
+ /** What a caller may reach by itx expression: the FIRST step of `itx.facets.get(name).<step>…`, a
118
+ * method or a property of this class. A subclass lists its own on top of its parent's:
119
+ * `static override publicMethods = [...super.publicMethods, "send"]`. */
120
+ static publicMethods = ["fetch"];
121
+ /** This class's `publicMethods`, for the context that loaded it — a static does not cross the
122
+ * isolate. On no list: only the context asks it. */
123
+ listPublicMethods() {
124
+ return this.constructor.publicMethods;
125
+ }
126
+ };
127
+ var StreamProcessorDurableObject = class extends FacetDurableObject {
128
+ /** The reads a caller reaches on every processor: `fetch`, and the state caught up through the log
129
+ * (`snapshot`, `liveSnapshot`) or awaited (`waitUntilProcessed`). What feeds the processor —
130
+ * `processEventBatch`, `catchUpFromLog`, `revive` — is the platform's, never a caller's. */
131
+ static publicMethods = [
132
+ ...super.publicMethods,
133
+ "snapshot",
134
+ "liveSnapshot",
135
+ "waitUntilProcessed"
136
+ ];
137
+ /** After a runtime field on the processor moved OUTSIDE a batch (an RPC method on this object);
138
+ * inside `processEvent` the engine re-projects on its own. */
139
+ publishLiveState() {
140
+ this.#engine.publishLiveState();
141
+ }
142
+ /** THE push: the context hands over each committed batch with its scanned-range proof. */
143
+ processEventBatch(events, range) {
144
+ return this.#engine.processEventBatch(events, range);
145
+ }
146
+ /** Catch up from the log (the delivery loop's, when a row is configured or resumed). */
147
+ catchUpFromLog() {
148
+ return this.#engine.catchUpFromLog();
149
+ }
150
+ /** THE REVIVE: the context's alarm pass calls it for a due claim — catch up, then run the
151
+ * at-head pass, so an attempt the last incarnation was running is started again from state. */
152
+ revive() {
153
+ return this.#engine.revive();
154
+ }
155
+ /** Caught up through the log, then `{ offset, state }`. */
156
+ snapshot() {
157
+ return this.#engine.snapshot();
158
+ }
159
+ /** The live-state seed read: `{ rev, state: projectLiveState(reduced) }`. */
160
+ liveSnapshot() {
161
+ return this.#engine.liveSnapshot();
162
+ }
163
+ /** The barrier: resolves once processed at least through `offset` (default timeout 10s). */
164
+ waitUntilProcessed(input) {
165
+ return this.#engine.waitUntilProcessed(input);
166
+ }
167
+ /** The loopback to this facet's context: a LOADED class gets it as `env.ITX` (the loader bakes the
168
+ * stub in, worker-loader.ts); a class of THIS worker hosted through `ctx.exports` has the
169
+ * worker's real env and mints the same stub itself from its props — `ctx.exports` is populated
170
+ * inside a facet (__workers-tests__/facet-props.test.ts). */
171
+ #itxEntrypoint() {
172
+ return this.env.ITX ?? this.ctx.exports.ItxEntrypoint({ props: {
173
+ iterateContextName: this.ctx.props.iterateContextName,
174
+ platform: true
175
+ } });
176
+ }
177
+ #engineBuiltOnFirstUse;
178
+ get #engine() {
179
+ return this.#engineBuiltOnFirstUse ??= new ProcessorEngine(this.processor, {
180
+ stream: {
181
+ append: (...events) => this.withItx((itx) => itx.append(...events)),
182
+ read: (after, limit) => this.withItx((itx) => itx.readEvents(after, limit)),
183
+ claim: (at) => this.withItx((itx) => itx.processors.claim(this.ctx.props.name, at))
184
+ },
185
+ storage: new ReduceCheckpointTable(this.ctx.storage.sql),
186
+ fedByPushes: this.ctx.props.fedByPushes === true
187
+ });
188
+ }
189
+ /** ONE round trip on the itx scope, then RELEASE EVERYTHING IT REACHED: the get, and every call the
190
+ * callback made through it — not only the last. A Workers-RPC value this facet leaves undisposed —
191
+ * the `itx.cd(path)` of `itx.cd(path).append(…)`, the `cfArtifacts.get(p)` of `.remote()`, an
192
+ * answer awaited inside the callback (`const { state } = await context.invoke(…)`), data included —
193
+ * keeps THIS FACET running after its context is evicted, until V8 collects the value, which an
194
+ * idle isolate may not do for many minutes: each new incarnation of the context reattaches to the
195
+ * facet, and the object stays billed (measured 2026-09-23: a new website project's `/` and
196
+ * `/repos/config` billed 60 s of every minute for 30 min with no request). The context's own
197
+ * `invoke` cannot end this from its side: the facet holds the value (context-residency.e2e.test.ts,
198
+ * "… does not outlive …"). Protected: a host with methods of its own (the workspace,
199
+ * src/workspace/durable-object.ts) reaches its context the same way. */
200
+ withItx(call) {
201
+ return withItx(this.#itxEntrypoint(), call);
202
+ }
203
+ };
204
+ var ConfigWorker = class extends WorkerEntrypoint {
205
+ /** At fetch entry: `const denied = this.auth.require(request); if (denied) return denied;`
206
+ * `x-itx-principal` is on a request only when a project member (or the operator) sent it, safe
207
+ * to act on. A private route written by hand answers the platform's sign-in challenge, which
208
+ * the edge turns into the sign-in for a page load (`auth.require` does the same):
209
+ *
210
+ * ```js
211
+ * if (!request.headers.get("x-itx-principal"))
212
+ * return new Response("Sign in\n", { status: 401, headers: { "WWW-Authenticate": 'Bearer realm="iterate"' } });
213
+ * ``` */
214
+ auth = auth;
215
+ /** Process an explicitly subscribed batch with this worker's context scope. */
216
+ async processEventBatch(events, range) {
217
+ await this.withItx(async (itx) => {
218
+ for (const event of events) await this.processEvent({
219
+ event,
220
+ range,
221
+ itx
222
+ });
223
+ });
224
+ }
225
+ /** ONE round trip on the itx scope, then release the scope and every call made through it
226
+ * (`StreamProcessorDurableObject.withItx` says why an undisposed step keeps a context billed). */
227
+ withItx(call) {
228
+ return withItx(this.env.ITX, call);
229
+ }
230
+ /** THE AUTHOR HOOK — one event at a time, in offset order. Append reactions through the itx scope;
231
+ * make them idempotent (a redelivery must be a no-op). Default: ignore the event. */
232
+ processEvent(_args) {}
233
+ /** THE WEB ROOT — every Request on a host of the project (the project's configured ingress
234
+ * target). The host's routing slug is in `x-iterate-routing-slug` (`notes` for
235
+ * `notes--<project>.<hostname>`; absent on the apex), written only by the platform: route on it
236
+ * in plain code, answering here (reaching the context through `this.withItx`) or forwarding the
237
+ * Request. Default: not found. */
238
+ fetch(_request) {
239
+ return new Response("Not found\n", { status: 404 });
240
+ }
241
+ };
242
+ //#endregion
243
+ export { ConfigWorker, FacetDurableObject, LiveState, RunContract, RunRequested, RunSettled, StreamProcessor, StreamProcessorDurableObject, applyPatch, defineProcessorContract, diff, jsonEqual, newHttpBatchRpcSession, newWebSocketRpcSession, newWorkersRpcResponse, withItx, z };
244
+
245
+ //# sourceMappingURL=sdk.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk.mjs","names":["z","#engine","#engineBuiltOnFirstUse","#itxEntrypoint"],"sources":["../src/sdk/auth.ts","../src/sdk/record-pipelined-steps.ts","../src/sdk/index.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { isSameOriginBrowserRequest } from \"../lib.ts\";\nimport { ITX_PRINCIPAL_HEADER } from \"../principal.ts\";\n\nconst Principal = z.object({ actor: z.string().min(1), email: z.string().optional() });\n\n/** Project ingress strips public identity headers and stamps `x-itx-principal` for a project member\n * only: a visitor signed out, signed in without this project, or riding a session cookie on a\n * cross-site write arrives without one. This guard runs in the config worker, before it proxies an\n * app.\n *\n * Signed out, every request gets `401` with `WWW-Authenticate: Bearer realm=\"iterate\"`: the\n * platform's edge turns that answer into the sign-in for a page load (or into \"sign in again with\n * this project\" for someone signed in without it), whatever path the app is served under, and hands\n * a fetch, a write or a WebSocket upgrade the 401 itself. Any app can ask for a signed-in visitor\n * the same way:\n *\n * ```js\n * if (!request.headers.get(\"x-itx-principal\"))\n * return new Response(\"Sign in\\n\", { status: 401, headers: { \"WWW-Authenticate\": 'Bearer realm=\"iterate\"' } });\n * ```\n *\n * A write or a WebSocket upgrade must also come from this origin (or carry no Origin, a non-browser\n * client), else 403. The edge already sends such a cookie request on anonymous; this repeats the\n * check where the app runs. The handshake is a GET, but it opens a two-way channel, and the app\n * session cookie is `SameSite=Lax`: every `<routingSlug>--<project>.iterate.app` host is same-site with\n * every other, so a page on another project's host could otherwise open a socket to this app with\n * the visitor's cookie. */\nexport const auth = {\n require(request: Request): Response | null {\n const isWebSocketUpgrade = request.headers.get(\"upgrade\")?.toLowerCase() === \"websocket\";\n const isRead = [\"GET\", \"HEAD\", \"OPTIONS\"].includes(request.method) && !isWebSocketUpgrade;\n if (!isRead && !isSameOriginBrowserRequest(request))\n return new Response(\"Cross-site request refused\", { status: 403 });\n const principal = request.headers.get(ITX_PRINCIPAL_HEADER);\n if (principal) {\n Principal.parse(JSON.parse(principal)); // Platform-owned stamp; malformed means a defect.\n return null;\n }\n return new Response(\"Sign in\\n\", {\n status: 401,\n headers: { \"WWW-Authenticate\": 'Bearer realm=\"iterate\"', \"Cache-Control\": \"no-store\" },\n });\n },\n};\n","// sdk/record-pipelined-steps.ts — `withItx`, THE one way code reaches its context: ONE round trip on\n// `env.ITX`, then RELEASE a Workers-RPC round trip completely — the scope and every call it made, not\n// only the last. Loaded code imports it from \"./processor.js\" (`withItx(this.env.ITX, (itx) => …)`); the\n// SDK's hosts (`StreamProcessorDurableObject.withItx`, `ConfigWorker.withItx`) delegate to it. No\n// workerd import, so the unit tests run it in node (record-pipelined-steps.test.ts) and the platform\n// bundles it alone for a script's isolate (apps/os `runScriptModule`); on native RpcPromises it is\n// proven by every apps/os e2e row that reaches a facet, and pinned by\n// apps/os/e2e/context-residency.e2e.test.ts (\"… does not outlive …\": a facet that kept one value from\n// its context stayed running, billed). Lint refuses the raw `env.ITX.get()` (iterate/no-raw-itx-get).\n\nimport { releaseRpcSessions } from \"../lib.ts\";\n\n/** ONE round trip on `entrypoint.get()`, then RELEASE EVERYTHING IT REACHED: the scope and every call\n * `call` made through it or through a handle it awaited, the last first. A release that throws is reported and the rest still run\n * (lib.ts `releaseRpcSessions`), so the call's answer stands. Data it answers stays usable; a stub or\n * handle it answers is released with the rest, so return data.\n *\n * const { projectSlug } = await withItx(this.env.ITX, (itx) => itx.whoami());\n */\nexport async function withItx<Scope, T>(\n entrypoint: { get(): Scope },\n call: (itx: Scope) => T,\n): Promise<Awaited<T>> {\n const steps: unknown[] = [];\n const itx = entrypoint.get();\n try {\n return await call(recordPipelinedSteps(itx, steps));\n } finally {\n releaseRpcSessions([itx, ...steps]);\n }\n}\n\n/** `stub` as the caller sees it, except that every CALL made through it — at any depth, on the stub,\n * on a call's result, or on the handle a call's result resolves to once awaited — is pushed onto\n * `steps`, so the caller can dispose each one: a Workers-RPC call's result is a stub-bearing promise\n * that keeps its session open until disposed, awaited or not. Awaiting hands back a handle (a stub\n * is callable, in workerd and capnweb alike) recorded and pushed too, and plain data untouched, so\n * data still copies across RPC. `catch`/`finally` and symbol members (`Symbol.dispose`) are the\n * value's own, bound to it, so disposing behaves exactly as on the bare stub; an argument that is\n * itself a recorded value crosses the wire as the stub it wraps. */\nexport function recordPipelinedSteps<T>(stub: T, steps: unknown[]): T {\n const wrapped = new WeakMap<object, object>();\n const record = (value: unknown, receiver: unknown): unknown => {\n // oxlint-disable-next-line iterate/simple-truthiness-check -- a Proxy target must be an object or a function: a call may answer any value, and only those two can be wrapped\n if (!value || (typeof value !== \"object\" && typeof value !== \"function\")) return value;\n const proxy = new Proxy(value, {\n get(target, key) {\n const member: unknown = Reflect.get(target, key);\n if (key === \"then\" && typeof member === \"function\")\n // `const repo = await itx.repos.get(p); await repo.whoami()`: disposing the step releases\n // `repo` (workerd disposes a promise's result with it), never `whoami`'s call, and an\n // awaited property (`await itx.repos`) is no step at all.\n return (onFulfilled?: unknown, onRejected?: unknown) =>\n Reflect.apply(member, target, [\n typeof onFulfilled === \"function\"\n ? (answer: unknown) => {\n if (typeof answer !== \"function\") return onFulfilled(answer);\n steps.push(answer);\n return onFulfilled(record(answer, undefined));\n }\n : onFulfilled,\n onRejected,\n ]);\n if (typeof key === \"symbol\" || key === \"then\" || key === \"catch\" || key === \"finally\")\n return typeof member === \"function\" ? member.bind(target) : member;\n return record(member, target);\n },\n apply(target, _proxyReceiver, args: unknown[]) {\n // Only a callable target reaches this trap; the call runs on the unwrapped receiver, as\n // `stub.method(…)` would have.\n const result: unknown = Reflect.apply(\n target as (...args: unknown[]) => unknown,\n receiver,\n // `Object(arg)` is a fresh wrapper for a primitive, so only a recorded value is found.\n args.map((arg) => wrapped.get(Object(arg)) ?? arg),\n );\n steps.push(result);\n return record(result, undefined);\n },\n });\n wrapped.set(proxy, value);\n return proxy;\n };\n // The proxy answers every member the stub does (it forwards each one), so it is the stub's type.\n return record(stub, undefined) as T;\n}\n","// sdk/index.ts — THE userspace SDK surface, bundled (zod included — the owner's call) into every\n// loaded isolate as `processor.js` (apps/os/scripts/build.ts bundles it):\n//\n// import { StreamProcessor, StreamProcessorDurableObject, defineProcessorContract, z } from \"./processor.js\";\n//\n// The workerd HOSTS live here too (this file imports cloudflare:workers; the Node unit tests never import it):\n// FacetDurableObject — the `DurableObject` shell a context hosts as a facet: its class lists\n// the methods a caller reaches by itx expression (`publicMethods`)\n// StreamProcessorDurableObject — the facet shell that hosts ONE `StreamProcessor`\n// ConfigWorker — the stateless `WorkerEntrypoint` a project's one event handler extends\n\nimport { DurableObject, WorkerEntrypoint } from \"cloudflare:workers\";\nimport type { IterateContextApi, StreamPage } from \"../api.ts\";\nimport {\n ProcessorEngine,\n type ScannedRange,\n type StreamProcessor,\n ReduceCheckpointTable,\n type StreamEvent,\n type StreamEventInput,\n} from \"../stream/processor.ts\";\nimport { auth } from \"./auth.ts\";\nimport { withItx } from \"./record-pipelined-steps.ts\";\n// THE ONE WAY code reaches its context: `withItx(this.env.ITX, (itx) => …)` — one round trip, then\n// everything it reached released (record-pipelined-steps.ts). A host's `this.withItx(fn)` is the same\n// function. Never `env.ITX.get()` alone: whatever it hands out keeps this isolate, and the object\n// hosting it, running and billed after the context is evicted (lint: iterate/no-raw-itx-get).\nexport { withItx };\nexport {\n // LIVE STATE for a mini-app DO that is NOT a processor (a processor's base owns one internally):\n // `new LiveState({ append: (e) => withItx(this.env.ITX, (itx) => itx.append(e)) }, \"chat\", {…})` — a\n // field initializer cannot await — then `set` to mutate and `snapshot()` as the client's seed read\n // (stream/processor.ts).\n LiveState,\n StreamProcessor,\n defineProcessorContract,\n type ConsumedEvent,\n type EventCatalog,\n type EventDefinition,\n type EmittedEventInput,\n type EventInput,\n type LiveStateSink,\n type ProcessorContract,\n type ProcessorState,\n type ProcessorStream,\n type ProcessEventArgs,\n type ReduceArgs,\n type ScannedRange,\n type StreamEvent,\n type StreamEventInput,\n} from \"../stream/processor.ts\";\nexport { z } from \"zod\";\n// capnweb's CLIENT constructors, so userspace can dial a remote capnweb API from inside its isolate\n// through the context's own egress, and `newWorkersRpcResponse`, the SERVER half, so a loaded worker\n// can serve a capnweb API over its `fetch`. The HTTP batch is exported ON PURPOSE beside the\n// WebSocket session: a stateless entrypoint answering one method with one remote call has no session\n// to hold across calls, and a one-shot POST is the honest shape (the lint rule targets long-lived workers).\n// oxlint-disable-next-line iterate/no-capnweb-http-batch -- userspace one-shot remote calls; see above\nexport { newHttpBatchRpcSession, newWebSocketRpcSession, newWorkersRpcResponse } from \"capnweb\";\nexport { applyPatch, diff, jsonEqual, type PatchOp } from \"../lib.ts\";\n// ── StreamProcessorDurableObject ── THE SDK HOST: the `DurableObject` shell that hosts ONE\n// `StreamProcessor` as a facet of its context. An author writes the pure processor and its host,\n// one line long:\n//\n// export class PresenceDurableObject extends StreamProcessorDurableObject {\n// processor = new PresenceProcessor();\n// }\n//\n// hosted through the ordinary `itx.facets.get('presence', { source, className: 'PresenceDurableObject' })`\n// — a processor is a named facet that additionally gets pushed every commit. `processor` is a FIELD\n// so it can take what its effects need from this object — reach as a `WithItx` accessor, never a\n// scope: `new Notifier((call) => this.withItx(call))` — and so the same class is constructed bare in\n// a test. A method of the host's own that callers reach by itx expression goes on its list:\n// `static override publicMethods = [...super.publicMethods, \"message\"]`.\n//\n// IDENTITY is `ctx.props` — `{ iterateContextName, name }`, minted by the parent, the only party\n// that knows it (pinned in __workers-tests__/facet-props.test.ts), plus `fedByPushes` when a row\n// pushes it (FacetProps). THE STREAM is the itx scope `this.withItx(fn)` hands `fn` (apps/os\n// iterate-context.ts `ItxEntrypoint`); the engine's `append`/`read` ride it like any other dotted call.\n//\n// NEVER define alarm(): facets have none (workerd#6810 — the runtime answers \"Facets currently\n// cannot set alarms.\"); a timer, when one is needed, is a scheduled append on the context. The\n// engine's own recovery is a CLAIM on the context's alarm (processor.ts, rule 3): while a\n// `runInBackground` attempt is in flight the context owes this facet a `revive()`, so a host that\n// dies mid-attempt is re-materialized and runs its at-head pass again\n// (__workers-tests__/agent-revive.test.ts: an LLM call survives its context's death).\n//\n// THE CLAIM IS ALSO WHAT KEEPS A FACET RUNNING: a loaded facet that holds none when its context\n// starts a new incarnation is reset then (os FacetHost `resetUnclaimedLoadedFacets`). So work that\n// must outlive the call that started it — a model request, a retry's backoff sleep, an open\n// provider socket — runs through `runInBackground` (ProcessEventArgs), never as a bare floating\n// promise, a `ctx.waitUntil` or a timer the facet keeps on its own.\n\n/** What the parent mints a facet's class with — the whole identity, and one fact about its feed. */\nexport type FacetProps = {\n iterateContextName: string;\n name: string;\n /** Set when, as this facet started, a subscription row of its context pushed it every commit it\n * consumes (`processEventBatch`, the delivery loop's push): a processor's engine then trusts the\n * head a catch-up read until the next push (stream/processor.ts, the read verbs). Absent, only a\n * push is proof, so a processor no row pushes reads its log on every read. */\n fedByPushes?: true;\n};\n\n/** THE FACET SHELL: a `DurableObject` a context hosts as a facet — `itx.facets.get(name, { source,\n * className })`, a rule naming it, or a processor's row. A caller reaches a facet by itx expression\n * (`itx.facets.get(name).<method>(…)`) only through what its class lists in `publicMethods`: the\n * context refuses any other first step FORBIDDEN before the call reaches the facet\n * (apps/os context/facet-public-methods.ts). The platform's own calls — the delivery loop's push\n * and catch-up, the alarm's revive — never go through the list. A loaded class that does not\n * extend this shell lists nothing, so no caller reaches it by expression. */\nexport abstract class FacetDurableObject<Env = unknown> extends DurableObject<Env, FacetProps> {\n /** What a caller may reach by itx expression: the FIRST step of `itx.facets.get(name).<step>…`, a\n * method or a property of this class. A subclass lists its own on top of its parent's:\n * `static override publicMethods = [...super.publicMethods, \"send\"]`. */\n static publicMethods: readonly string[] = [\"fetch\"];\n\n /** This class's `publicMethods`, for the context that loaded it — a static does not cross the\n * isolate. On no list: only the context asks it. */\n listPublicMethods(): readonly string[] {\n // `this.constructor` is the concrete facet class, a subclass of this one; TypeScript types it as\n // `Function`, which has no `publicMethods`.\n return (this.constructor as typeof FacetDurableObject).publicMethods;\n }\n}\n\n/** The itx scope `withItx` hands its callback: a context's declared API (api.ts) — a capnweb stub\n * of apps/os's `IterateContextRpcTarget`, which satisfies it. */\nexport type ItxScope = IterateContextApi;\n/** What hands the scope over: the loopback entrypoint a loaded worker has as `env.ITX`, or the one a\n * class of the platform's own worker mints from `ctx.exports`. */\nexport type ItxEntrypointService = { get(): ItxScope };\n/** The least a host needs of its scope: the fixed-point log calls the engine makes. The platform's own\n * facets pass the Workers-RPC STUB of a context (every dotted step pipelined; a property there is a\n * promise), which no plain-promise interface can name — so the constraint is this, not `ItxScope`. */\nexport type ProcessorScope = {\n append(...events: StreamEventInput[]): Promise<unknown>;\n readEvents(afterOffset?: number, limit?: number): Promise<unknown>;\n /** The engine's claim on the context's alarm (processor.ts rule 3): \"come back by `at`\", or null. */\n processors: { claim(name: string, at: number | null): Promise<unknown> };\n /** Another context of the project by its dotted surface (`.append`), which the platform's handle\n * and a loaded worker's alike answer — how an entity's processor cross-posts its certificate to\n * `/` (`withItx((itx) => itx.cd(\"/\").append(certificate))`). Through the table like every other\n * word here: a loaded processor's `cd` goes down only (the app wall), the platform's own go\n * anywhere within the project. */\n cd(path: string): { append(...events: StreamEventInput[]): Promise<unknown> };\n};\n\n/** THE SCOPE ACCESSOR a host hands its processor: one pipelined round trip on the context's itx,\n * released after (`StreamProcessorDurableObject.withItx`). A processor that needs an effect —\n * `itx.cfArtifacts.create(path)`, `itx.ai.run(…)` — takes this and nothing else, so a unit test\n * hands it a fake and the e2e lends one by rule on the context. */\nexport type WithItx<Scope = ItxScope> = <T>(call: (itx: Scope) => T) => Promise<Awaited<T>>;\n\nexport abstract class StreamProcessorDurableObject<\n State = unknown,\n Env extends { ITX?: ItxEntrypointService } = { ITX: ItxEntrypointService },\n Scope extends ProcessorScope = ItxScope,\n> extends FacetDurableObject<Env> {\n /** The reads a caller reaches on every processor: `fetch`, and the state caught up through the log\n * (`snapshot`, `liveSnapshot`) or awaited (`waitUntilProcessed`). What feeds the processor —\n * `processEventBatch`, `catchUpFromLog`, `revive` — is the platform's, never a caller's. */\n static override publicMethods = [\n ...super.publicMethods,\n \"snapshot\",\n \"liveSnapshot\",\n \"waitUntilProcessed\",\n ];\n\n /** The processor this object hosts — `processor = new PresenceProcessor()` at the top of the subclass. */\n abstract readonly processor: StreamProcessor<State>;\n\n // ── what an author reaches (the itx scope: `this.withItx(fn)`; identity: `this.ctx.props`) ──\n\n /** After a runtime field on the processor moved OUTSIDE a batch (an RPC method on this object);\n * inside `processEvent` the engine re-projects on its own. */\n protected publishLiveState(): void {\n this.#engine.publishLiveState();\n }\n\n // ── what the platform calls: the delivery loop's push and catch-up, the alarm's revive ──\n\n /** THE push: the context hands over each committed batch with its scanned-range proof. */\n processEventBatch(events: StreamEvent[], range: ScannedRange): Promise<void> {\n return this.#engine.processEventBatch(events, range);\n }\n /** Catch up from the log (the delivery loop's, when a row is configured or resumed). */\n catchUpFromLog(): Promise<void> {\n return this.#engine.catchUpFromLog();\n }\n /** THE REVIVE: the context's alarm pass calls it for a due claim — catch up, then run the\n * at-head pass, so an attempt the last incarnation was running is started again from state. */\n revive(): Promise<void> {\n return this.#engine.revive();\n }\n\n // ── what a caller reaches by itx expression (`publicMethods`) ──\n\n /** Caught up through the log, then `{ offset, state }`. */\n snapshot(): Promise<{ offset: number; state: State }> {\n return this.#engine.snapshot();\n }\n /** The live-state seed read: `{ rev, state: projectLiveState(reduced) }`. */\n liveSnapshot(): Promise<{ rev: number; state: unknown }> {\n return this.#engine.liveSnapshot();\n }\n /** The barrier: resolves once processed at least through `offset` (default timeout 10s). */\n waitUntilProcessed(input: { offset: number; timeoutMs?: number }): Promise<void> {\n return this.#engine.waitUntilProcessed(input);\n }\n\n /** The loopback to this facet's context: a LOADED class gets it as `env.ITX` (the loader bakes the\n * stub in, worker-loader.ts); a class of THIS worker hosted through `ctx.exports` has the\n * worker's real env and mints the same stub itself from its props — `ctx.exports` is populated\n * inside a facet (__workers-tests__/facet-props.test.ts). */\n #itxEntrypoint(): { get(): Scope } {\n return (this.env.ITX ??\n (\n this.ctx.exports as unknown as {\n ItxEntrypoint: (options: { props: object }) => ItxEntrypointService;\n }\n ).ItxEntrypoint({\n // PLATFORM: this worker's own class, minted from its own exports — the full handle, the fixed\n // point spellable, `cd` free to go up. A LOADED class never reaches this branch (it has\n // `env.ITX`, baked in by the loader, and its own module's exports).\n props: { iterateContextName: this.ctx.props.iterateContextName, platform: true },\n })) as unknown as {\n get(): Scope;\n };\n }\n // ── the engine: one ProcessorEngine over `processor` and this object's storage, built on first use —\n // `processor` is a subclass field, which does not exist yet while this base class constructs. ──\n #engineBuiltOnFirstUse?: ProcessorEngine<State>;\n get #engine(): ProcessorEngine<State> {\n return (this.#engineBuiltOnFirstUse ??= new ProcessorEngine(this.processor, {\n // The engine's own emits, catch-up and gap repair are the CONTEXT ROOTS `append`, `readEvents`,\n // `processors.claim` — implicit in every context (itx-expression-rewriting.ts rule 3), so they\n // resolve to this log with no row and no hop; a row at `itx.append` is the OWNER's deliberate\n // wall (a jailed processor halts visibly), never a loaded worker's — the fixed point is not a\n // loaded worker's word.\n stream: {\n // A stub scope's answers are pipelined shapes by type and plain data on the wire (the\n // engine awaits them): the engine's own types, asserted.\n append: (...events) =>\n this.withItx((itx) => itx.append(...events)) as Promise<StreamEvent[]>,\n read: (after, limit) =>\n this.withItx((itx) => itx.readEvents(after, limit)) as Promise<StreamPage>,\n claim: (at) => this.withItx((itx) => itx.processors.claim(this.ctx.props.name, at)),\n },\n storage: new ReduceCheckpointTable(this.ctx.storage.sql),\n fedByPushes: this.ctx.props.fedByPushes === true,\n }));\n }\n\n /** ONE round trip on the itx scope, then RELEASE EVERYTHING IT REACHED: the get, and every call the\n * callback made through it — not only the last. A Workers-RPC value this facet leaves undisposed —\n * the `itx.cd(path)` of `itx.cd(path).append(…)`, the `cfArtifacts.get(p)` of `.remote()`, an\n * answer awaited inside the callback (`const { state } = await context.invoke(…)`), data included —\n * keeps THIS FACET running after its context is evicted, until V8 collects the value, which an\n * idle isolate may not do for many minutes: each new incarnation of the context reattaches to the\n * facet, and the object stays billed (measured 2026-09-23: a new website project's `/` and\n * `/repos/config` billed 60 s of every minute for 30 min with no request). The context's own\n * `invoke` cannot end this from its side: the facet holds the value (context-residency.e2e.test.ts,\n * \"… does not outlive …\"). Protected: a host with methods of its own (the workspace,\n * src/workspace/durable-object.ts) reaches its context the same way. */\n protected withItx<T>(call: (itx: Scope) => T): Promise<Awaited<T>> {\n return withItx(this.#itxEntrypoint(), call);\n }\n}\n\n// ConfigWorker is a stateless event handler loaded with an explicit workers.get spec.\n// Subscribe its processEventBatch method explicitly; fetch routing is configured separately.\nexport type ConfigEventArgs = { event: StreamEvent; range: ScannedRange; itx: ItxScope };\n\nexport abstract class ConfigWorker<\n Env extends { ITX: ItxEntrypointService } = { ITX: ItxEntrypointService },\n> extends WorkerEntrypoint<Env> {\n /** At fetch entry: `const denied = this.auth.require(request); if (denied) return denied;`\n * `x-itx-principal` is on a request only when a project member (or the operator) sent it, safe\n * to act on. A private route written by hand answers the platform's sign-in challenge, which\n * the edge turns into the sign-in for a page load (`auth.require` does the same):\n *\n * ```js\n * if (!request.headers.get(\"x-itx-principal\"))\n * return new Response(\"Sign in\\n\", { status: 401, headers: { \"WWW-Authenticate\": 'Bearer realm=\"iterate\"' } });\n * ``` */\n protected readonly auth = auth;\n /** Process an explicitly subscribed batch with this worker's context scope. */\n async processEventBatch(events: StreamEvent[], range: ScannedRange): Promise<void> {\n await this.withItx(async (itx) => {\n for (const event of events) {\n await this.processEvent({ event, range, itx });\n }\n });\n }\n\n /** ONE round trip on the itx scope, then release the scope and every call made through it\n * (`StreamProcessorDurableObject.withItx` says why an undisposed step keeps a context billed). */\n protected withItx<T>(call: (itx: ItxScope) => T): Promise<Awaited<T>> {\n return withItx(this.env.ITX, call);\n }\n\n /** THE AUTHOR HOOK — one event at a time, in offset order. Append reactions through the itx scope;\n * make them idempotent (a redelivery must be a no-op). Default: ignore the event. */\n processEvent(_args: ConfigEventArgs): void | Promise<void> {}\n\n /** THE WEB ROOT — every Request on a host of the project (the project's configured ingress\n * target). The host's routing slug is in `x-iterate-routing-slug` (`notes` for\n * `notes--<project>.<hostname>`; absent on the apex), written only by the platform: route on it\n * in plain code, answering here (reaching the context through `this.withItx`) or forwarding the\n * Request. Default: not found. */\n override fetch(_request: Request): Response | Promise<Response> {\n return new Response(\"Not found\\n\", { status: 404 });\n }\n}\n\nexport { RunContract, RunRequested, RunSettled } from \"../stream/run.ts\";\n"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  import type { SqlStorageValue } from "@cloudflare/workers-types";
2
2
  import { z } from "zod";
3
- import { jsonEqual } from "../lib.ts";
4
3
  /** What a processor declares: its checkpoint slug and reducer version, what it consumes and emits,
5
4
  * and its initial state (`defineProcessorContract` below builds one from zod schemas). */
6
5
  export type ProcessorContract<State = unknown> = {
@@ -27,9 +26,6 @@ export type ProcessorContract<State = unknown> = {
27
26
  * says whether the page was cut; its length says nothing (a budget cut is short of `limit`). */
28
27
  export type ProcessorStream = {
29
28
  append(...events: StreamEventInput[]): Promise<StreamEvent[]> | StreamEvent[];
30
- /** Append onto ANOTHER context of the same project, by path — how an entity's processor lands its
31
- * birth certificate on `/` for the project catalog. A stand-in with one path may omit it. */
32
- appendTo?(path: string, ...events: StreamEventInput[]): Promise<StreamEvent[]> | StreamEvent[];
33
29
  read(afterOffset?: number, limit?: number): Promise<{
34
30
  events: StreamEvent[];
35
31
  scannedThroughOffset: number;
@@ -54,8 +50,8 @@ export type ReduceArgs<State, Event = StreamEvent> = {
54
50
  state: State;
55
51
  };
56
52
  export type ProcessEventArgs<State, Event = StreamEvent,
57
- /** What `append`/`appendTo` take: `EmittedEventInput<typeof Contract>` for a processor that
58
- * declares one — each type the contract `emits`, its payload as the catalog spells it. */
53
+ /** What `append` takes: `EmittedEventInput<typeof Contract>` for a processor that declares one —
54
+ * each type the contract `emits`, its payload as the catalog spells it. */
59
55
  Emitted extends StreamEventInput = StreamEventInput> = {
60
56
  /** The consumed event — or `null` for the eventless at-head pass. */
61
57
  event: Event | null;
@@ -66,8 +62,6 @@ Emitted extends StreamEventInput = StreamEventInput> = {
66
62
  * assignable to `StreamProcessor<State>` (the host's field), and only method parameters are
67
63
  * compared bivariantly. */
68
64
  append(...events: Emitted[]): Promise<StreamEvent[]>;
69
- /** The same, onto the context at `path` (apps/os's `appendTo`): a certificate cross-posted to `/`. */
70
- appendTo(path: string, ...events: Emitted[]): Promise<StreamEvent[]>;
71
65
  /** Hold the cursor until `work` settles; FIFO with other blockers of the SAME event. */
72
66
  blockProcessorWhile: (work: () => Promise<unknown>) => void;
73
67
  /** Fire-and-forget attempt; may overtake later events; outcome must be state-recoverable. */
@@ -80,8 +74,8 @@ Emitted extends StreamEventInput = StreamEventInput> = {
80
74
  * reduces all call this; there is no second copy to drift. `consumes` undefined = every durable event
81
75
  * (a subscriber's default). "*" = every durable event. A NAMED type opts that type in, INCLUDING
82
76
  * ephemerals ("*" NEVER sweeps ephemerals) — so a live-state watcher spells
83
- * `consumes: ["events.iterate.com/live-state/changed"]` and filters `payload.key` itself. The wake
84
- * record (`stream/woken`) is a durable event like any other: a "*" row receives every incarnation's. */
77
+ * `consumes: ["events.iterate.com/itx/live-state-changed"]` and filters `payload.key` itself. The wake
78
+ * record (`itx/woken`) is a durable event like any other: a "*" row receives every incarnation's. */
85
79
  export declare function consumesEvent(consumes: readonly string[] | undefined, event: {
86
80
  type: string;
87
81
  ephemeral?: boolean;
@@ -97,7 +91,7 @@ export declare abstract class StreamProcessor<State, Event extends StreamEvent =
97
91
  * untyped `StreamEvent` for processors that don't declare one. */
98
92
  reduce(_args: ReduceArgs<State, Event>): State | null | undefined;
99
93
  /** Side-effect hook. Synchronous by design: register async work via the two helpers on args.
100
- * `append`/`appendTo` take what THIS class's `contract` emits (`EmittedEventInput<this["contract"]>`:
94
+ * `append` takes what THIS class's `contract` emits (`EmittedEventInput<this["contract"]>`:
101
95
  * a subclass whose `contract` is a defined one gets each emitted type's payload as its catalog
102
96
  * spells it; the base, and a hand-built contract, take any input). */
103
97
  processEvent(_args: ProcessEventArgs<State, Event, EmittedEventInput<this["contract"]>>): undefined;
@@ -120,8 +114,12 @@ export declare class ProcessorEngine<State> {
120
114
  constructor(processor: StreamProcessor<State>, deps: {
121
115
  stream: ProcessorStream;
122
116
  storage: ReduceCheckpointTable;
117
+ /** The host's word that a subscription row pushes this processor every commit it consumes
118
+ * (`processEventBatch`). The read verbs then trust the head a catch-up read until a push shows
119
+ * a later one; absent, only a push's head is trusted, so an unpushed processor reads each time. */
120
+ fedByPushes?: boolean;
123
121
  });
124
- /** THE SEED DOOR for live-state clients (LiveState.snapshot), caught up first. */
122
+ /** THE SEED READ for live-state clients (LiveState.snapshot), caught up first. */
125
123
  liveSnapshot(): Promise<{
126
124
  rev: number;
127
125
  state: unknown;
@@ -130,7 +128,7 @@ export declare class ProcessorEngine<State> {
130
128
  * calls this after every batch; the host calls it after a runtime field moved outside a batch. A
131
129
  * throwing projection loses only its notification (the client re-seeds on the chain gap). */
132
130
  publishLiveState(): void;
133
- /** THE push door: contiguous → reduce it directly (no read); anything else → gap repair from the
131
+ /** THE push method: contiguous → reduce it directly (no read); anything else → gap repair from the
134
132
  * own cursor first. Fire-and-forget safe: enqueues on the serial chain. */
135
133
  processEventBatch(events: StreamEvent[], range: ScannedRange): Promise<void>;
136
134
  /** Catch up from the own checkpoint (a cold boot, the read verbs, the barrier), page by page — a
@@ -154,11 +152,11 @@ export declare class ProcessorEngine<State> {
154
152
  * here claims again, later each time (20 s, 40 s, … `REVIVE_AFTER_MAX_MS`). */
155
153
  revive(): Promise<void>;
156
154
  }
157
- export { jsonEqual };
158
155
  /** What `append` accepts: the event body, before the stream assigns its committed identity. The
159
- * door checks ONE rule by hand: `type` is a non-empty string. */
156
+ * append method checks ONE rule by hand: `type` is a non-empty string. */
160
157
  export type StreamEventInput = {
161
- /** Convention: `events.iterate.com/<domain>/<fact>`. */
158
+ /** `events.iterate.com/<namespace>/<event>` for the platform's types, named by the rules in
159
+ * packages/iterate/README.md#event-types; any other string is the appender's own. */
162
160
  type: string;
163
161
  payload?: Record<string, unknown>;
164
162
  metadata?: Record<string, unknown>;
@@ -188,12 +186,16 @@ export type StreamEventInput = {
188
186
  };
189
187
  /** THE CONNECTION the principal acted through: the OAuth grant's id — one per
190
188
  * connected client (a Claude Code install, a dash sign-in, a personal token). Stamped beside
191
- * `principal` by the DO's append root (src/principal.ts); absent for the admin secret and the kernel. */
189
+ * `principal` by the platform when it appends; absent for the admin secret and the kernel. */
192
190
  grant?: string;
191
+ /** THE PLATFORM WROTE THIS FACT, on the principal's behalf:
192
+ * what a processor folding an account's or an organization's facts requires — a client can
193
+ * append any type to a context it holds, never this. */
194
+ platform?: true;
193
195
  };
194
196
  /** Same key + same body = dedupe (the existing event is returned); different body = loud error. */
195
197
  idempotencyKey?: string;
196
- /** OPTIONAL PRECONDITION (apps/os): land at exactly this offset or refuse the whole batch with
198
+ /** OPTIONAL PRECONDITION: land at exactly this offset or refuse the whole batch with
197
199
  * OFFSET_CONFLICT — "nothing has happened since I last looked". Never stored in the body. */
198
200
  offset?: number;
199
201
  /** An EPHEMERAL event rides the stream to live subscribers but is NEVER persisted: it consumes an
@@ -225,7 +227,7 @@ export type ReduceCheckpoint<State> = {
225
227
  state: State | undefined;
226
228
  };
227
229
  /** What BOTH hosts read and write their checkpoints through — the stream's storage and a facet's
228
- * own (the unit lane drives it over node:sqlite, stream/test-support.ts). */
230
+ * own (the Node unit tests drive it over node:sqlite, stream/test-support.ts). */
229
231
  export declare class ReduceCheckpointTable {
230
232
  #private;
231
233
  /** `createTable: false` when the caller knows the table exists (the stream's storage skips every
@@ -242,7 +244,9 @@ export declare class ReduceCheckpointTable {
242
244
  }, state: State, stateChanged: boolean): void;
243
245
  }
244
246
  /** The only thing a LiveState needs from its host: somewhere to append the delta. A
245
- * `ProcessorStream` and the itx scope both satisfy it. */
247
+ * `ProcessorStream` satisfies it; a facet that is no processor passes one round trip per delta,
248
+ * `{ append: (e) => withItx(this.env.ITX, (itx) => itx.append(e)) }` (sdk/index.ts), never a scope it
249
+ * holds. */
246
250
  export type LiveStateSink = {
247
251
  append(event: {
248
252
  type: string;
@@ -255,7 +259,7 @@ export declare class LiveState<S> {
255
259
  constructor(sink: LiveStateSink, key: string, initial: S);
256
260
  /** The current value (reflects every `set`). */
257
261
  get(): S;
258
- /** THE seed door: `{rev, state}` read together (single-threaded ⇒ atomically), which is what lets
262
+ /** THE seed read: `{rev, state}` read together (single-threaded ⇒ atomically), which is what lets
259
263
  * a client chain patches exactly instead of guessing which changes its snapshot already contains. */
260
264
  snapshot(): {
261
265
  rev: number;
@@ -305,7 +309,7 @@ export type ConsumedEvent<Contract> = Contract extends {
305
309
  consumes: infer Consumes extends readonly string[];
306
310
  } ? EventForTypes<Events, DepsOf<Contract>, Consumes> : never;
307
311
  /** The input for ONE event type as a catalog spells it (`EventInput`'s row) — or, for a type no
308
- * catalog defines (a core control event a processor emits, `project/ingress-configured`), the plain
312
+ * catalog defines (a core control event a processor emits, `itx/ingress-configured`), the plain
309
313
  * input: it widens the whole union, so a contract that emits one undefined type appends untyped
310
314
  * until that type is in a catalog it depends on. */
311
315
  type EventInputForType<Events extends EventCatalog, Deps extends readonly unknown[], Type extends string> = Type extends unknown ? [DefinitionForType<Events, Deps, Type>] extends [never] ? StreamEventInput : DefinitionForType<Events, Deps, Type> extends {
@@ -322,7 +326,7 @@ type EventInputForType<Events extends EventCatalog, Deps extends readonly unknow
322
326
  } : {
323
327
  ephemeral?: never;
324
328
  }) : never : never;
325
- /** What a processor's `append`/`appendTo` take: one input per type the contract `emits` — its own
329
+ /** What a processor's `append` takes: one input per type the contract `emits` — its own
326
330
  * events and its deps' as their catalogs spell them (`z.input`), a type no catalog defines as the
327
331
  * plain input under that name. A contract whose `emits` is not a literal tuple gets every input. */
328
332
  export type EmittedEventInput<Contract> = Contract extends {
@@ -376,3 +380,4 @@ export declare function defineProcessorContract<const StateSchema extends z.ZodT
376
380
  consumes: Consumes;
377
381
  emits: Emits;
378
382
  }): DefinedProcessorContract<StateSchema, Events, Consumes, Deps, Emits>;
383
+ export {};