experimental-a2 0.3.0 → 0.5.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 (205) hide show
  1. package/CHANGELOG.md +207 -0
  2. package/dist/ai-CFNeCrRl.d.ts +334 -0
  3. package/dist/ai-CFNeCrRl.d.ts.map +1 -0
  4. package/dist/ai-server.browser.js +2 -0
  5. package/dist/ai-server.browser.js.map +1 -0
  6. package/dist/ai-server.d.ts +49 -9
  7. package/dist/ai-server.d.ts.map +1 -0
  8. package/dist/ai-server.js +123 -49
  9. package/dist/ai-server.js.map +1 -0
  10. package/dist/ai.d.ts +2 -303
  11. package/dist/ai.js +233 -86
  12. package/dist/ai.js.map +1 -0
  13. package/dist/cli-B3VuxoDe.js +599 -0
  14. package/dist/cli-B3VuxoDe.js.map +1 -0
  15. package/dist/cli-bin.d.ts +1 -0
  16. package/dist/cli-bin.js +7 -0
  17. package/dist/cli-bin.js.map +1 -0
  18. package/dist/cli.d.ts +20 -0
  19. package/dist/cli.d.ts.map +1 -0
  20. package/dist/cli.js +2 -0
  21. package/dist/client-BKlyLiOU.js +1008 -0
  22. package/dist/client-BKlyLiOU.js.map +1 -0
  23. package/dist/client-D7mvIXrF.d.ts +191 -0
  24. package/dist/client-D7mvIXrF.d.ts.map +1 -0
  25. package/dist/client.d.ts +2 -90
  26. package/dist/client.js +1 -409
  27. package/dist/{contract-CG_adnu_.js → contract-48bUMgcL.js} +12 -2
  28. package/dist/contract-48bUMgcL.js.map +1 -0
  29. package/dist/{contract-C_3dIIEU.d.ts → contract-jIfaR085.d.ts} +63 -8
  30. package/dist/contract-jIfaR085.d.ts.map +1 -0
  31. package/dist/devtools-J_jZ2vQf.d.ts +152 -0
  32. package/dist/devtools-J_jZ2vQf.d.ts.map +1 -0
  33. package/dist/devtools-kJJaORn-.js +340 -0
  34. package/dist/devtools-kJJaORn-.js.map +1 -0
  35. package/dist/devtools-server.browser.js +3 -1
  36. package/dist/devtools-server.browser.js.map +1 -0
  37. package/dist/devtools-server.d.ts +4 -3
  38. package/dist/devtools-server.d.ts.map +1 -0
  39. package/dist/devtools-server.js +226 -43
  40. package/dist/devtools-server.js.map +1 -0
  41. package/dist/devtools.d.ts +2 -0
  42. package/dist/devtools.js +2 -0
  43. package/dist/{errors-BJRMd-h6.js → errors-BQuJpe82.js} +6 -4
  44. package/dist/errors-BQuJpe82.js.map +1 -0
  45. package/dist/{errors-xL_JTXsY.d.ts → errors-W6nwJ-fm.d.ts} +3 -2
  46. package/dist/errors-W6nwJ-fm.d.ts.map +1 -0
  47. package/dist/http.d.ts +135 -28
  48. package/dist/http.d.ts.map +1 -0
  49. package/dist/http.js +647 -61
  50. package/dist/http.js.map +1 -0
  51. package/dist/{idempotent-replay-BMyHrP0L.js → idempotent-replay-DuqEkYA7.js} +4 -2
  52. package/dist/idempotent-replay-DuqEkYA7.js.map +1 -0
  53. package/dist/index.d.ts +5 -5
  54. package/dist/index.js +2 -2
  55. package/dist/{inspection-E7qbD0Xj.js → inspection-DaxB5jM2.js} +4 -1
  56. package/dist/inspection-DaxB5jM2.js.map +1 -0
  57. package/dist/internal-DstsI6Re.js +211 -0
  58. package/dist/internal-DstsI6Re.js.map +1 -0
  59. package/dist/otel.d.ts +3 -2
  60. package/dist/otel.d.ts.map +1 -0
  61. package/dist/otel.js +2 -0
  62. package/dist/otel.js.map +1 -0
  63. package/dist/platform-B4TnJtWu.js +34 -0
  64. package/dist/platform-B4TnJtWu.js.map +1 -0
  65. package/dist/react.d.ts +47 -15
  66. package/dist/react.d.ts.map +1 -0
  67. package/dist/react.js +30 -15
  68. package/dist/react.js.map +1 -0
  69. package/dist/retryable-lazy-DZWmHpii.js +2 -0
  70. package/dist/retryable-lazy-DZWmHpii.js.map +1 -0
  71. package/dist/scheduler-qstash.d.ts +79 -0
  72. package/dist/scheduler-qstash.d.ts.map +1 -0
  73. package/dist/scheduler-qstash.js +501 -0
  74. package/dist/scheduler-qstash.js.map +1 -0
  75. package/dist/scheduler-task-BpzhPnRS.js +56 -0
  76. package/dist/scheduler-task-BpzhPnRS.js.map +1 -0
  77. package/dist/{recovery-vercel.d.ts → scheduler-vercel.d.ts} +18 -24
  78. package/dist/scheduler-vercel.d.ts.map +1 -0
  79. package/dist/scheduler-vercel.js +228 -0
  80. package/dist/scheduler-vercel.js.map +1 -0
  81. package/dist/server-C72KOw51.js +1457 -0
  82. package/dist/server-C72KOw51.js.map +1 -0
  83. package/dist/server-DUF9pjsx.d.ts +261 -0
  84. package/dist/server-DUF9pjsx.d.ts.map +1 -0
  85. package/dist/server.browser.js +2 -0
  86. package/dist/server.browser.js.map +1 -0
  87. package/dist/server.d.ts +4 -155
  88. package/dist/server.js +2 -2
  89. package/dist/{log-ldf5g8Cx.d.ts → store-DysUkTH3.d.ts} +120 -35
  90. package/dist/store-DysUkTH3.d.ts.map +1 -0
  91. package/dist/{log-yJbXUf72.js → store-N8PXxDAS.js} +3 -1
  92. package/dist/store-N8PXxDAS.js.map +1 -0
  93. package/dist/store-codec-DTG0Ftek.js +10 -0
  94. package/dist/store-codec-DTG0Ftek.js.map +1 -0
  95. package/dist/store-memory.d.ts +12 -0
  96. package/dist/store-memory.d.ts.map +1 -0
  97. package/dist/{log-memory.js → store-memory.js} +145 -34
  98. package/dist/store-memory.js.map +1 -0
  99. package/dist/{log-polling-DZ1MiKLg.js → store-polling-dSeLxzfb.js} +7 -5
  100. package/dist/store-polling-dSeLxzfb.js.map +1 -0
  101. package/dist/{log-postgres.d.ts → store-postgres.d.ts} +7 -6
  102. package/dist/store-postgres.d.ts.map +1 -0
  103. package/dist/{log-postgres.js → store-postgres.js} +214 -24
  104. package/dist/store-postgres.js.map +1 -0
  105. package/dist/{log-redis-core-CyJ5L8yR.js → store-redis-core-BFLwz0Wj.js} +271 -66
  106. package/dist/store-redis-core-BFLwz0Wj.js.map +1 -0
  107. package/dist/{log-redis-http.d.ts → store-redis-http.d.ts} +8 -7
  108. package/dist/store-redis-http.d.ts.map +1 -0
  109. package/dist/{log-redis-http.js → store-redis-http.js} +22 -12
  110. package/dist/store-redis-http.js.map +1 -0
  111. package/dist/{log-redis.d.ts → store-redis.d.ts} +7 -6
  112. package/dist/store-redis.d.ts.map +1 -0
  113. package/dist/{log-redis.js → store-redis.js} +101 -39
  114. package/dist/store-redis.js.map +1 -0
  115. package/dist/{log-sqlite.d.ts → store-sqlite.d.ts} +7 -6
  116. package/dist/store-sqlite.d.ts.map +1 -0
  117. package/dist/{log-sqlite.js → store-sqlite.js} +118 -22
  118. package/dist/store-sqlite.js.map +1 -0
  119. package/dist/{telemetry-Cso0qyHQ.d.ts → telemetry-BjYHTfh2.d.ts} +3 -2
  120. package/dist/telemetry-BjYHTfh2.d.ts.map +1 -0
  121. package/dist/testing.browser.d.ts +1 -0
  122. package/dist/testing.browser.js +6 -0
  123. package/dist/testing.browser.js.map +1 -0
  124. package/dist/testing.d.ts +32 -0
  125. package/dist/testing.d.ts.map +1 -0
  126. package/dist/testing.js +103 -0
  127. package/dist/testing.js.map +1 -0
  128. package/dist/validate-XKT4FSNn.js +2 -0
  129. package/dist/validate-XKT4FSNn.js.map +1 -0
  130. package/dist/wire-BFQmSJ-9.js +284 -0
  131. package/dist/wire-BFQmSJ-9.js.map +1 -0
  132. package/docs/01-quickstart.mdx +3 -3
  133. package/docs/concepts/01-contracts.mdx +18 -13
  134. package/docs/concepts/02-handlers.mdx +7 -7
  135. package/docs/concepts/03-durability.mdx +21 -21
  136. package/docs/concepts/04-state.mdx +18 -21
  137. package/docs/guides/01-timers.mdx +154 -49
  138. package/docs/guides/02-cancellation.mdx +30 -4
  139. package/docs/guides/03-react.mdx +76 -57
  140. package/docs/guides/04-local-first.mdx +1 -1
  141. package/docs/guides/05-production.mdx +310 -61
  142. package/docs/guides/06-ai-agents.mdx +252 -74
  143. package/docs/guides/07-devtools.mdx +137 -12
  144. package/docs/guides/08-application-data.mdx +1 -1
  145. package/docs/guides/09-presence.mdx +263 -0
  146. package/docs/guides/10-transports.mdx +140 -0
  147. package/docs/index.mdx +18 -14
  148. package/docs/reference/01-api.mdx +839 -110
  149. package/docs/reference/02-errors.mdx +13 -6
  150. package/package.json +24 -7
  151. package/src/ai-coordinator.ts +358 -0
  152. package/src/ai-projector.ts +524 -0
  153. package/src/ai-sdk-step.ts +261 -0
  154. package/src/ai-server.browser.ts +5 -0
  155. package/src/ai-server.ts +1719 -0
  156. package/src/ai.ts +2155 -0
  157. package/src/cache-indexeddb.ts +10 -0
  158. package/src/cli-bin.ts +5 -0
  159. package/src/cli.ts +1046 -0
  160. package/src/client.ts +1826 -0
  161. package/src/contract.ts +206 -0
  162. package/src/deterministic-id.ts +72 -0
  163. package/src/devtools-app.ts +989 -0
  164. package/src/devtools-server.browser.ts +5 -0
  165. package/src/devtools-server.ts +604 -0
  166. package/src/devtools.ts +716 -0
  167. package/src/errors.ts +50 -0
  168. package/src/http.ts +394 -0
  169. package/src/idempotent-replay.ts +53 -0
  170. package/src/index.ts +37 -0
  171. package/src/inspection.ts +39 -0
  172. package/src/internal.ts +426 -0
  173. package/src/otel.ts +59 -0
  174. package/src/platform.ts +60 -0
  175. package/src/push-envelope.ts +137 -0
  176. package/src/react.ts +284 -0
  177. package/src/reducer.ts +108 -0
  178. package/src/retryable-lazy.ts +27 -0
  179. package/src/scheduler-qstash.ts +915 -0
  180. package/src/scheduler-task.ts +106 -0
  181. package/src/scheduler-vercel.ts +437 -0
  182. package/src/server.browser.ts +12 -0
  183. package/src/server.ts +2700 -0
  184. package/src/session-socket.ts +548 -0
  185. package/src/sse.ts +141 -0
  186. package/src/standard-schema.ts +77 -0
  187. package/src/store-codec.ts +10 -0
  188. package/src/store-memory.ts +788 -0
  189. package/src/store-polling.ts +102 -0
  190. package/src/store-postgres.ts +1212 -0
  191. package/src/store-redis-core.ts +1494 -0
  192. package/src/store-redis-http.ts +116 -0
  193. package/src/store-redis.ts +458 -0
  194. package/src/store-sqlite.ts +1108 -0
  195. package/src/store.ts +385 -0
  196. package/src/telemetry.ts +47 -0
  197. package/src/testing.browser.ts +5 -0
  198. package/src/testing.ts +185 -0
  199. package/src/validate.ts +39 -0
  200. package/src/wire.ts +454 -0
  201. package/dist/internal-gCd5qMry.js +0 -44
  202. package/dist/log-memory.d.ts +0 -11
  203. package/dist/recovery-vercel.js +0 -119
  204. package/dist/server-BcLa4RFL.js +0 -877
  205. package/dist/wire-BVsgR8o9.js +0 -62
@@ -1,14 +1,8 @@
1
- import { t as A2Error } from "./errors-BJRMd-h6.js";
2
- import { t as idempotentReplay } from "./idempotent-replay-BMyHrP0L.js";
3
- import { n as SYSTEM_CLOCK, t as RANDOM_IDS } from "./log-yJbXUf72.js";
4
- //#region src/log-memory.ts
5
- /**
6
- * experimental-a2/log-memory — in-memory log backend (the test default).
7
- *
8
- * Implements the A2Log interface with zero dependencies. See
9
- * specs/a2-implementation.md §3 for the contract; the conformance suite
10
- * in test/conformance is the executable version of it.
11
- */
1
+ import { t as A2Error } from "./errors-BQuJpe82.js";
2
+ import { g as nullProtoRecord } from "./internal-DstsI6Re.js";
3
+ import { t as idempotentReplay } from "./idempotent-replay-DuqEkYA7.js";
4
+ import { n as SYSTEM_CLOCK, t as RANDOM_IDS } from "./store-N8PXxDAS.js";
5
+ //#region src/store-memory.ts
12
6
  const toStored = (row) => ({
13
7
  id: row.id,
14
8
  type: row.type,
@@ -50,6 +44,9 @@ function memory(options = {}) {
50
44
  /** Keyed by `${sessionId}\u0000${reducerName}` — a pure cache. */
51
45
  const snapshots = /* @__PURE__ */ new Map();
52
46
  const streamSubscribers = /* @__PURE__ */ new Map();
47
+ /** ns → participant → field → latest surviving write. */
48
+ const presenceRows = /* @__PURE__ */ new Map();
49
+ const presenceSubscribers = /* @__PURE__ */ new Map();
53
50
  const notifyStreams = (sessionId, rows) => {
54
51
  const subs = streamSubscribers.get(sessionId);
55
52
  if (!subs) return;
@@ -165,6 +162,18 @@ function memory(options = {}) {
165
162
  }
166
163
  return inserted;
167
164
  };
165
+ const readStateOf = (sessionId, reducerName) => {
166
+ const snap = snapshots.get(`${sessionId}\u0000${reducerName}`);
167
+ const snapshot = snap ? {
168
+ index: snap.index,
169
+ state: structuredClone(snap.state)
170
+ } : null;
171
+ const afterIndex = snapshot?.index ?? 0;
172
+ return {
173
+ snapshot,
174
+ events: (sessions.get(sessionId) ?? []).filter((row) => row.index > afterIndex).map(toEvent)
175
+ };
176
+ };
168
177
  return {
169
178
  async append(sessionId, events) {
170
179
  if (events.length === 0) return appendResult(sessionId, []);
@@ -173,16 +182,23 @@ function memory(options = {}) {
173
182
  if (existing.length === events.length) return appendResult(sessionId, idempotentReplay(events, existing.map(toStored)));
174
183
  throw new A2Error("PARTIAL_DUPLICATE_BATCH", `batch mixes ${existing.length} already-appended and ${events.length - existing.length} fresh events`);
175
184
  }
185
+ const rows = sessions.get(sessionId) ?? [];
186
+ for (const event of events) {
187
+ if (!event.cause) continue;
188
+ const parent = rows[event.cause.index - 1];
189
+ if (!parent) throw new TypeError(`no event at index ${event.cause.index} in session '${sessionId}'`);
190
+ if (parent.attemptCount !== event.cause.attempt || parent.failedAt !== null) throw new A2Error("SUPERSEDED_ATTEMPT", `attempt ${event.cause.attempt} no longer owns event ${event.cause.index} in session '${sessionId}'`);
191
+ }
176
192
  const now = clock.now();
177
193
  const inserted = insert(sessionId, events, now);
178
194
  notifyStreams(sessionId, inserted);
179
195
  return appendResult(sessionId, inserted.map(toStored));
180
196
  },
181
197
  async read(sessionId, opts) {
182
- return (sessions.get(sessionId) ?? []).filter((row) => {
183
- if (opts?.afterIndex !== void 0 && row.index <= opts.afterIndex) return false;
184
- return true;
185
- }).map(toStored);
198
+ const rows = sessions.get(sessionId) ?? [];
199
+ const start = Math.max(0, opts?.afterIndex ?? 0);
200
+ const end = Math.max(0, opts?.throughIndex ?? rows.length);
201
+ return rows.slice(start, end).map(toStored);
186
202
  },
187
203
  async claimAvailable({ sessionId, holder, ttlMs, expiresAtMs, excludeIndexes }) {
188
204
  const claimedAt = clock.now();
@@ -209,16 +225,28 @@ function memory(options = {}) {
209
225
  events: eligible.map((row) => claim(row, holder, claimedAt, expiresAt))
210
226
  };
211
227
  },
212
- async renewClaims({ sessionId, holder, indexes, ttlMs, expiresAtMs }) {
228
+ async renewClaims({ sessionId, holder, claims, ttlMs, expiresAtMs }) {
213
229
  const now = clock.now();
214
230
  const expiresAt = new Date(expiresAtMs ?? now.getTime() + ttlMs);
215
- const requested = new Set(indexes);
231
+ const requested = new Map(claims.map((c) => [c.index, c.attempt]));
216
232
  const renewed = [];
217
- for (const row of sessions.get(sessionId) ?? []) if (requested.has(row.index) && row.processedAt === null && row.failedAt === null && row.claimHolder === holder && row.claimExpiresAt !== null && row.claimExpiresAt > now) {
218
- row.claimExpiresAt = new Date(expiresAt);
219
- renewed.push(row.index);
233
+ const superseded = [];
234
+ for (const row of sessions.get(sessionId) ?? []) {
235
+ const attempt = requested.get(row.index);
236
+ if (attempt === void 0) continue;
237
+ if (row.attemptCount > attempt) {
238
+ superseded.push(row.index);
239
+ continue;
240
+ }
241
+ if (row.processedAt === null && row.failedAt === null && row.claimHolder === holder && row.claimExpiresAt !== null && row.claimExpiresAt > now) {
242
+ row.claimExpiresAt = new Date(expiresAt);
243
+ renewed.push(row.index);
244
+ }
220
245
  }
221
- return renewed;
246
+ return {
247
+ renewed,
248
+ superseded
249
+ };
222
250
  },
223
251
  async completeAttempt({ sessionId, index, attempt, events }) {
224
252
  const parent = find(sessionId, index);
@@ -288,16 +316,10 @@ function memory(options = {}) {
288
316
  };
289
317
  },
290
318
  async readState(sessionId, reducerName) {
291
- const snap = snapshots.get(`${sessionId}\u0000${reducerName}`);
292
- const snapshot = snap ? {
293
- index: snap.index,
294
- state: structuredClone(snap.state)
295
- } : null;
296
- const afterIndex = snapshot?.index ?? 0;
297
- return {
298
- snapshot,
299
- events: (sessions.get(sessionId) ?? []).filter((row) => row.index > afterIndex).map(toEvent)
300
- };
319
+ return readStateOf(sessionId, reducerName);
320
+ },
321
+ async readStates(sessionIds, reducerName) {
322
+ return sessionIds.map((sessionId) => readStateOf(sessionId, reducerName));
301
323
  },
302
324
  async putSnapshot(sessionId, reducerName, index, state) {
303
325
  const key = `${sessionId}\u0000${reducerName}`;
@@ -309,6 +331,85 @@ function memory(options = {}) {
309
331
  updatedAt: clock.now()
310
332
  });
311
333
  },
334
+ presence: {
335
+ async set(ns, participant, values, meta) {
336
+ let participants = presenceRows.get(ns);
337
+ if (!participants) {
338
+ participants = /* @__PURE__ */ new Map();
339
+ presenceRows.set(ns, participants);
340
+ }
341
+ let fields = participants.get(participant);
342
+ if (!fields) {
343
+ fields = /* @__PURE__ */ new Map();
344
+ participants.set(participant, fields);
345
+ }
346
+ const expiresAtMs = clock.now().getTime() + meta.ttlMs;
347
+ const applied = nullProtoRecord();
348
+ let appliedCount = 0;
349
+ for (const [field, value] of Object.entries(values)) {
350
+ const existing = fields.get(field);
351
+ if (existing && existing.at > meta.at) continue;
352
+ if (value === null) fields.delete(field);
353
+ else fields.set(field, {
354
+ value: structuredClone(value),
355
+ seen: meta.seen,
356
+ at: new Date(meta.at),
357
+ expiresAt: new Date(expiresAtMs)
358
+ });
359
+ applied[field] = structuredClone(value);
360
+ appliedCount += 1;
361
+ }
362
+ if (fields.size === 0) participants.delete(participant);
363
+ if (participants.size === 0) presenceRows.delete(ns);
364
+ if (appliedCount === 0) return;
365
+ const subs = presenceSubscribers.get(ns);
366
+ if (!subs) return;
367
+ const patch = {
368
+ participant,
369
+ values: applied,
370
+ seen: meta.seen,
371
+ at: new Date(meta.at)
372
+ };
373
+ for (const listener of subs) listener(patch);
374
+ },
375
+ async read(ns) {
376
+ const participants = presenceRows.get(ns);
377
+ if (!participants) return [];
378
+ const now = clock.now();
379
+ const rows = [];
380
+ for (const [participant, fields] of participants) {
381
+ for (const [field, entry] of fields) {
382
+ if (entry.expiresAt <= now) {
383
+ fields.delete(field);
384
+ continue;
385
+ }
386
+ rows.push({
387
+ participant,
388
+ field,
389
+ value: structuredClone(entry.value),
390
+ seen: entry.seen,
391
+ at: new Date(entry.at),
392
+ expiresAt: new Date(entry.expiresAt)
393
+ });
394
+ }
395
+ if (fields.size === 0) participants.delete(participant);
396
+ }
397
+ if (participants.size === 0) presenceRows.delete(ns);
398
+ return rows;
399
+ },
400
+ subscribe(ns, onPatch) {
401
+ let subs = presenceSubscribers.get(ns);
402
+ if (!subs) {
403
+ subs = /* @__PURE__ */ new Set();
404
+ presenceSubscribers.set(ns, subs);
405
+ }
406
+ subs.add(onPatch);
407
+ return () => {
408
+ subs.delete(onPatch);
409
+ if (subs.size === 0) presenceSubscribers.delete(ns);
410
+ };
411
+ }
412
+ },
312
413
  inspect: {
313
414
  async listSessions(inspectionOptions) {
314
415
  const ids = [...sessions.keys()].filter((sessionId) => sessionId.startsWith(inspectionOptions.prefix) && (inspectionOptions.cursor === void 0 || sessionId > inspectionOptions.cursor)).toSorted();
@@ -350,6 +451,14 @@ function memory(options = {}) {
350
451
  cursor: ids.length > visible.length ? visible.at(-1) ?? null : null
351
452
  };
352
453
  },
454
+ async readEvents(sessionId, pageOptions) {
455
+ const rows = sessions.get(sessionId) ?? [];
456
+ const throughIndex = Math.min(pageOptions.throughIndex ?? rows.length, rows.length);
457
+ return {
458
+ events: rows.slice(pageOptions.afterIndex, throughIndex).slice(0, pageOptions.limit).map(toStored),
459
+ throughIndex
460
+ };
461
+ },
353
462
  async listSnapshots(sessionId) {
354
463
  const prefix = `${sessionId}\u0000`;
355
464
  return [...snapshots.entries()].filter(([key]) => key.startsWith(prefix)).map(([key, snapshot]) => ({
@@ -360,9 +469,9 @@ function memory(options = {}) {
360
469
  }
361
470
  },
362
471
  stream(sessionId, opts) {
363
- const startAt = opts?.startAt ?? 0;
472
+ const startAfter = opts?.startAfter ?? 0;
364
473
  return { [Symbol.asyncIterator]() {
365
- let last = startAt;
474
+ let last = startAfter;
366
475
  const buffer = [];
367
476
  let wake = null;
368
477
  let closed = false;
@@ -377,7 +486,7 @@ function memory(options = {}) {
377
486
  }
378
487
  subs.add(onRow);
379
488
  const existing = sessions.get(sessionId) ?? [];
380
- buffer.unshift(...existing.filter((row) => row.index > startAt));
489
+ buffer.unshift(...existing.filter((row) => row.index > startAfter));
381
490
  const unsubscribe = () => {
382
491
  subs.delete(onRow);
383
492
  if (subs.size === 0) streamSubscribers.delete(sessionId);
@@ -420,3 +529,5 @@ function memory(options = {}) {
420
529
  }
421
530
  //#endregion
422
531
  export { memory };
532
+
533
+ //# sourceMappingURL=store-memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-memory.js","names":[],"sources":["../src/store-memory.ts"],"sourcesContent":["/**\n * experimental-a2/store-memory — in-memory store backend (the test default).\n *\n * Implements the A2Store interface with zero dependencies. See\n * specs/a2-implementation.md §3 for the contract; the conformance suite\n * in test/conformance is the executable version of it.\n */\n\nimport type { PresencePatch } from './contract.ts'\nimport { A2Error } from './errors.ts'\nimport { idempotentReplay } from './idempotent-replay.ts'\nimport { nullProtoRecord } from './internal.ts'\nimport {\n RANDOM_IDS,\n SYSTEM_CLOCK,\n type A2Store,\n type AppendEvent,\n type Clock,\n type Event,\n type EventCause,\n type IdSource,\n type PresenceRow,\n type StoredEvent,\n type StoredSessionSummary,\n type StoreStateRead,\n} from './store.ts'\n\nexport type MemoryStoreOptions = {\n /** Injectable clock — every stored timestamp comes from here. */\n clock?: Clock\n /** Injectable id source for generated event ids. */\n ids?: IdSource\n}\n\ntype Row = {\n id: string\n type: string\n payload: unknown\n index: number\n sessionId: string\n createdAt: Date\n cause: EventCause | null\n lane: string | null\n processedAt: Date | null\n processedByAttempt: number | null\n returnedEventIds: string[] | null\n firstClaimedAt: Date | null\n lastClaimedAt: Date | null\n attemptCount: number\n claimHolder: string | null\n claimExpiresAt: Date | null\n failureCount: number\n lastFailedAt: Date | null\n lastFailedAttempt: number | null\n lastError: string | null\n failedAt: Date | null\n}\n\ntype PresenceEntry = {\n value: unknown\n seen: number\n at: Date\n expiresAt: Date\n}\n\ntype LaneQueue = { rows: Row[]; head: number }\ntype SessionDispatch = {\n ready: Map<number, Row>\n lanes: Map<string, LaneQueue>\n}\n\nconst toStored = (row: Row): StoredEvent => ({\n id: row.id,\n type: row.type,\n payload: structuredClone(row.payload),\n index: row.index,\n sessionId: row.sessionId,\n createdAt: new Date(row.createdAt),\n cause: row.cause ? { ...row.cause } : null,\n lane: row.lane,\n processedAt: row.processedAt ? new Date(row.processedAt) : null,\n processedByAttempt: row.processedByAttempt,\n returnedEventIds: row.returnedEventIds ? [...row.returnedEventIds] : null,\n firstClaimedAt: row.firstClaimedAt ? new Date(row.firstClaimedAt) : null,\n lastClaimedAt: row.lastClaimedAt ? new Date(row.lastClaimedAt) : null,\n attemptCount: row.attemptCount,\n claimHolder: row.claimHolder,\n claimExpiresAt: row.claimExpiresAt ? new Date(row.claimExpiresAt) : null,\n failureCount: row.failureCount,\n lastFailedAt: row.lastFailedAt ? new Date(row.lastFailedAt) : null,\n lastFailedAttempt: row.lastFailedAttempt,\n lastError: row.lastError,\n failedAt: row.failedAt ? new Date(row.failedAt) : null,\n})\n\nconst toEvent = (row: Row): Event => ({\n id: row.id,\n type: row.type,\n payload: structuredClone(row.payload),\n index: row.index,\n sessionId: row.sessionId,\n createdAt: new Date(row.createdAt),\n})\n\nexport function memory(options: MemoryStoreOptions = {}): A2Store {\n const clock = options.clock ?? SYSTEM_CLOCK\n const generateId = options.ids ?? RANDOM_IDS\n\n const sessions = new Map<string, Row[]>()\n const dispatch = new Map<string, SessionDispatch>()\n /** Global unique index on event ids, like the SQL schema's. */\n const byEventId = new Map<string, Row>()\n /** Keyed by `${sessionId}\\u0000${reducerName}` — a pure cache. */\n const snapshots = new Map<\n string,\n { index: number; state: unknown; updatedAt: Date }\n >()\n const streamSubscribers = new Map<string, Set<(row: Row) => void>>()\n /** ns → participant → field → latest surviving write. */\n const presenceRows = new Map<\n string,\n Map<string, Map<string, PresenceEntry>>\n >()\n const presenceSubscribers = new Map<\n string,\n Set<(patch: PresencePatch) => void>\n >()\n\n const notifyStreams = (sessionId: string, rows: Row[]): void => {\n const subs = streamSubscribers.get(sessionId)\n if (!subs) return\n for (const listener of subs) {\n for (const row of rows) listener(row)\n }\n }\n\n const rowsOf = (sessionId: string): Row[] => {\n let rows = sessions.get(sessionId)\n if (!rows) {\n rows = []\n sessions.set(sessionId, rows)\n }\n return rows\n }\n\n const dispatchOf = (sessionId: string): SessionDispatch => {\n let state = dispatch.get(sessionId)\n if (!state) {\n state = { ready: new Map(), lanes: new Map() }\n dispatch.set(sessionId, state)\n }\n return state\n }\n\n const enqueue = (sessionId: string, row: Row): void => {\n if (row.processedAt !== null) return\n const state = dispatchOf(sessionId)\n if (row.lane === null) {\n state.ready.set(row.index, row)\n return\n }\n let queue = state.lanes.get(row.lane)\n if (!queue) {\n queue = { rows: [], head: 0 }\n state.lanes.set(row.lane, queue)\n }\n queue.rows.push(row)\n if (queue.rows.length === 1) state.ready.set(row.index, row)\n }\n\n const settle = (sessionId: string, row: Row): void => {\n const state = dispatchOf(sessionId)\n state.ready.delete(row.index)\n if (row.lane === null) return\n const queue = state.lanes.get(row.lane)!\n if (queue.rows[queue.head] !== row) return\n queue.head += 1\n if (queue.head === queue.rows.length) {\n state.lanes.delete(row.lane)\n return\n }\n const next = queue.rows[queue.head]!\n if (next.failedAt === null) state.ready.set(next.index, next)\n }\n\n const find = (sessionId: string, index: number): Row => {\n const row = sessions.get(sessionId)?.[index - 1]\n if (!row) {\n throw new TypeError(\n `no event at index ${index} in session '${sessionId}'`,\n )\n }\n return row\n }\n\n const appendResult = (sessionId: string, events: StoredEvent[]) => ({\n events,\n hasPending: (sessions.get(sessionId) ?? []).some(\n (row) => row.processedAt === null,\n ),\n })\n\n const claim = (\n row: Row,\n holder: string,\n now: Date,\n expiresAt: Date,\n ): StoredEvent => {\n row.attemptCount += 1\n row.firstClaimedAt ??= new Date(now)\n row.lastClaimedAt = new Date(now)\n row.claimHolder = holder\n row.claimExpiresAt = new Date(expiresAt)\n return toStored(row)\n }\n\n const checkBatchIds = (\n sessionId: string,\n events: readonly (AppendEvent & { id?: string })[],\n ): Row[] => {\n const supplied = events.filter(\n (candidate): candidate is AppendEvent & { id: string } =>\n candidate.id !== undefined,\n )\n const suppliedIds = new Set(supplied.map((candidate) => candidate.id))\n if (suppliedIds.size !== supplied.length) {\n throw new A2Error(\n 'PARTIAL_DUPLICATE_BATCH',\n 'batch contains the same event id more than once',\n )\n }\n const existing = supplied\n .map((candidate) => byEventId.get(candidate.id))\n .filter((row): row is Row => row !== undefined)\n const foreign = existing.find((row) => row.sessionId !== sessionId)\n if (foreign) {\n throw new A2Error(\n 'PARTIAL_DUPLICATE_BATCH',\n `event id '${foreign.id}' already exists in another session`,\n )\n }\n return existing\n }\n\n const insert = (\n sessionId: string,\n events: readonly AppendEvent[],\n now: Date,\n cause?: EventCause,\n ): Row[] => {\n const rows = rowsOf(sessionId)\n const base = rows.length === 0 ? 0 : rows[rows.length - 1]!.index\n const inserted = events.map((candidate, offset): Row => ({\n id: candidate.id ?? generateId(),\n type: candidate.type,\n payload: structuredClone(candidate.payload),\n index: base + 1 + offset,\n sessionId,\n createdAt: new Date(now),\n cause: cause\n ? { ...cause }\n : candidate.cause\n ? { ...candidate.cause }\n : null,\n lane: candidate.lane ?? null,\n processedAt: candidate.settled ? new Date(now) : null,\n processedByAttempt: null,\n returnedEventIds: null,\n firstClaimedAt: null,\n lastClaimedAt: null,\n attemptCount: 0,\n claimHolder: null,\n claimExpiresAt: null,\n failureCount: 0,\n lastFailedAt: null,\n lastFailedAttempt: null,\n lastError: null,\n failedAt: null,\n }))\n for (const row of inserted) {\n if (byEventId.has(row.id)) {\n throw new A2Error(\n 'PARTIAL_DUPLICATE_BATCH',\n `event id '${row.id}' already exists`,\n )\n }\n }\n for (const row of inserted) {\n rows.push(row)\n byEventId.set(row.id, row)\n enqueue(sessionId, row)\n }\n return inserted\n }\n\n const readStateOf = (\n sessionId: string,\n reducerName: string,\n ): StoreStateRead => {\n const snap = snapshots.get(`${sessionId}\\u0000${reducerName}`)\n const snapshot = snap\n ? { index: snap.index, state: structuredClone(snap.state) }\n : null\n const afterIndex = snapshot?.index ?? 0\n return {\n snapshot,\n events: (sessions.get(sessionId) ?? [])\n .filter((row) => row.index > afterIndex)\n .map(toEvent),\n }\n }\n\n return {\n async append(sessionId, events) {\n if (events.length === 0) return appendResult(sessionId, [])\n\n // Batch-scoped idempotency (a2-implementation.md §3): all ids\n // already present → lost-ack retry, return the original rows;\n // some present → the caller mixed sent and fresh events.\n const existing = checkBatchIds(sessionId, events)\n if (existing.length > 0) {\n if (existing.length === events.length) {\n return appendResult(\n sessionId,\n idempotentReplay(events, existing.map(toStored)),\n )\n }\n throw new A2Error(\n 'PARTIAL_DUPLICATE_BATCH',\n `batch mixes ${existing.length} already-appended and ${events.length - existing.length} fresh events`,\n )\n }\n\n // Attempt-currency fence: a fresh handler append commits only while\n // its causal attempt is still the parent's latest (store.ts `append`).\n const rows = sessions.get(sessionId) ?? []\n for (const event of events) {\n if (!event.cause) continue\n const parent = rows[event.cause.index - 1]\n if (!parent) {\n throw new TypeError(\n `no event at index ${event.cause.index} in session '${sessionId}'`,\n )\n }\n if (\n parent.attemptCount !== event.cause.attempt ||\n parent.failedAt !== null\n ) {\n throw new A2Error(\n 'SUPERSEDED_ATTEMPT',\n `attempt ${event.cause.attempt} no longer owns event ${event.cause.index} in session '${sessionId}'`,\n )\n }\n }\n\n const now = clock.now()\n const inserted = insert(sessionId, events, now)\n notifyStreams(sessionId, inserted)\n return appendResult(sessionId, inserted.map(toStored))\n },\n\n async read(sessionId, opts) {\n const rows = sessions.get(sessionId) ?? []\n const start = Math.max(0, opts?.afterIndex ?? 0)\n const end = Math.max(0, opts?.throughIndex ?? rows.length)\n return rows.slice(start, end).map(toStored)\n },\n\n async claimAvailable({\n sessionId,\n holder,\n ttlMs,\n expiresAtMs,\n excludeIndexes,\n }) {\n const claimedAt = clock.now()\n const now = claimedAt.getTime()\n const expiresAt = new Date(expiresAtMs ?? now + ttlMs)\n const excluded = new Set(excludeIndexes ?? [])\n const eligible: Row[] = []\n let retryAt: Date | null = null\n\n for (const row of dispatchOf(sessionId).ready.values()) {\n if (row.failedAt !== null || excluded.has(row.index)) continue\n if (row.claimExpiresAt && row.claimExpiresAt.getTime() > now) {\n if (!retryAt || row.claimExpiresAt < retryAt) {\n retryAt = new Date(row.claimExpiresAt)\n }\n continue\n }\n eligible.push(row)\n }\n\n if (eligible.length === 0) {\n return retryAt ? { outcome: 'busy', retryAt } : { outcome: 'settled' }\n }\n eligible.sort((a, b) => a.index - b.index)\n return {\n outcome: 'claimed',\n events: eligible.map((row) => claim(row, holder, claimedAt, expiresAt)),\n }\n },\n\n async renewClaims({ sessionId, holder, claims, ttlMs, expiresAtMs }) {\n const now = clock.now()\n const expiresAt = new Date(expiresAtMs ?? now.getTime() + ttlMs)\n const requested = new Map(claims.map((c) => [c.index, c.attempt]))\n const renewed: number[] = []\n const superseded: number[] = []\n for (const row of sessions.get(sessionId) ?? []) {\n const attempt = requested.get(row.index)\n if (attempt === undefined) continue\n if (row.attemptCount > attempt) {\n superseded.push(row.index)\n continue\n }\n if (\n row.processedAt === null &&\n row.failedAt === null &&\n row.claimHolder === holder &&\n row.claimExpiresAt !== null &&\n row.claimExpiresAt > now\n ) {\n row.claimExpiresAt = new Date(expiresAt)\n renewed.push(row.index)\n }\n }\n return { renewed, superseded }\n },\n\n async completeAttempt({ sessionId, index, attempt, events }) {\n const parent = find(sessionId, index)\n const cause = { index, attempt }\n if (parent.processedAt !== null) {\n if (parent.processedByAttempt !== attempt) {\n return { outcome: 'superseded' }\n }\n const requestedIds = events.map((event) => event.id)\n if (\n parent.returnedEventIds === null ||\n parent.returnedEventIds.length !== requestedIds.length ||\n parent.returnedEventIds.some(\n (id, offset) => id !== requestedIds[offset],\n )\n ) {\n throw new A2Error(\n 'PARTIAL_DUPLICATE_BATCH',\n 'completed attempt does not match the returned event batch',\n )\n }\n const existing = checkBatchIds(sessionId, events)\n if (\n existing.length !== events.length ||\n existing.some(\n (row) =>\n row.cause?.index !== index || row.cause.attempt !== attempt,\n )\n ) {\n throw new A2Error(\n 'PARTIAL_DUPLICATE_BATCH',\n 'completed attempt does not match the returned event batch',\n )\n }\n return {\n outcome: 'completed',\n events: idempotentReplay(events, existing.map(toStored)),\n }\n }\n if (\n parent.attemptCount !== attempt ||\n parent.failedAt !== null ||\n parent.claimHolder === null\n ) {\n return { outcome: 'superseded' }\n }\n\n const existing = checkBatchIds(sessionId, events)\n if (existing.length > 0) {\n throw new A2Error(\n 'PARTIAL_DUPLICATE_BATCH',\n 'returned event batch contains already-appended ids',\n )\n }\n const now = clock.now()\n const inserted = insert(sessionId, events, now, cause)\n parent.processedAt = new Date(now)\n parent.processedByAttempt = attempt\n parent.returnedEventIds = events.map((event) => event.id)\n parent.claimHolder = null\n parent.claimExpiresAt = null\n settle(sessionId, parent)\n notifyStreams(sessionId, inserted)\n return { outcome: 'completed', events: inserted.map(toStored) }\n },\n\n async failAttempt({ sessionId, index, attempt, error, maxFailures }) {\n const row = find(sessionId, index)\n if (\n row.processedAt ||\n row.attemptCount !== attempt ||\n (row.claimHolder === null && row.lastFailedAttempt !== attempt)\n ) {\n return { outcome: 'superseded', failureCount: row.failureCount }\n }\n if (row.lastFailedAttempt === attempt && row.claimHolder === null) {\n return {\n outcome: row.failedAt ? 'dead_lettered' : 'failed',\n failureCount: row.failureCount,\n }\n }\n if (row.failedAt) {\n return { outcome: 'dead_lettered', failureCount: row.failureCount }\n }\n row.failureCount += 1\n row.lastError = error\n const failedAt = clock.now()\n row.lastFailedAt = new Date(failedAt)\n row.lastFailedAttempt = attempt\n row.claimHolder = null\n row.claimExpiresAt = null\n if (row.failureCount >= maxFailures) {\n row.failedAt = new Date(failedAt)\n dispatchOf(sessionId).ready.delete(row.index)\n return {\n outcome: 'dead_lettered',\n failureCount: row.failureCount,\n }\n }\n return { outcome: 'failed', failureCount: row.failureCount }\n },\n\n async readState(sessionId, reducerName) {\n return readStateOf(sessionId, reducerName)\n },\n\n async readStates(sessionIds, reducerName) {\n return sessionIds.map((sessionId) => readStateOf(sessionId, reducerName))\n },\n\n async putSnapshot(sessionId, reducerName, index, state) {\n const key = `${sessionId}\\u0000${reducerName}`\n const existing = snapshots.get(key)\n // Guarded upsert: a slower concurrent writer must never clobber a\n // further-along snapshot. A lost race costs a few refolded events\n // next read — never correctness.\n if (existing && existing.index >= index) return\n snapshots.set(key, {\n index,\n state: structuredClone(state),\n updatedAt: clock.now(),\n })\n },\n\n presence: {\n async set(ns, participant, values, meta) {\n let participants = presenceRows.get(ns)\n if (!participants) {\n participants = new Map()\n presenceRows.set(ns, participants)\n }\n let fields = participants.get(participant)\n if (!fields) {\n fields = new Map()\n participants.set(participant, fields)\n }\n\n // Expiry anchors on the storage's own clock — the sender's\n // `at` orders writes but never extends or shortens a lifetime.\n const expiresAtMs = clock.now().getTime() + meta.ttlMs\n // Field-keyed and caller-named — null-prototype, like every\n // presence map (see `nullProtoRecord`).\n const applied: Record<string, unknown> = nullProtoRecord()\n let appliedCount = 0\n for (const [field, value] of Object.entries(values)) {\n // Field-wise LWW by `at`; ties go to the incoming write, so\n // same-stamp sets keep set-then-read intuition.\n const existing = fields.get(field)\n if (existing && existing.at > meta.at) continue\n if (value === null) {\n fields.delete(field)\n } else {\n fields.set(field, {\n value: structuredClone(value),\n seen: meta.seen,\n at: new Date(meta.at),\n expiresAt: new Date(expiresAtMs),\n })\n }\n applied[field] = structuredClone(value)\n appliedCount += 1\n }\n if (fields.size === 0) participants.delete(participant)\n if (participants.size === 0) presenceRows.delete(ns)\n\n // Only applied fields broadcast — a losing write repaints nothing,\n // so subscribers stay consistent with what read() returns.\n if (appliedCount === 0) return\n const subs = presenceSubscribers.get(ns)\n if (!subs) return\n const patch: PresencePatch = {\n participant,\n values: applied,\n seen: meta.seen,\n at: new Date(meta.at),\n }\n for (const listener of subs) listener(patch)\n },\n\n async read(ns) {\n const participants = presenceRows.get(ns)\n if (!participants) return []\n const now = clock.now()\n const rows: PresenceRow[] = []\n for (const [participant, fields] of participants) {\n for (const [field, entry] of fields) {\n // Expiry is enforced lazily on read — no timers; a silent\n // participant's rows vanish the next time anyone looks.\n if (entry.expiresAt <= now) {\n fields.delete(field)\n continue\n }\n rows.push({\n participant,\n field,\n value: structuredClone(entry.value),\n seen: entry.seen,\n at: new Date(entry.at),\n expiresAt: new Date(entry.expiresAt),\n })\n }\n if (fields.size === 0) participants.delete(participant)\n }\n if (participants.size === 0) presenceRows.delete(ns)\n return rows\n },\n\n subscribe(ns, onPatch) {\n let subs = presenceSubscribers.get(ns)\n if (!subs) {\n subs = new Set()\n presenceSubscribers.set(ns, subs)\n }\n subs.add(onPatch)\n return () => {\n subs.delete(onPatch)\n if (subs.size === 0) presenceSubscribers.delete(ns)\n }\n },\n },\n\n inspect: {\n async listSessions(inspectionOptions) {\n const ids = [...sessions.keys()]\n .filter(\n (sessionId) =>\n sessionId.startsWith(inspectionOptions.prefix) &&\n (inspectionOptions.cursor === undefined ||\n sessionId > inspectionOptions.cursor),\n )\n .toSorted()\n const visible = ids.slice(0, inspectionOptions.limit)\n const summaries = visible.map((sessionId): StoredSessionSummary => {\n const rows = sessions.get(sessionId)!\n const first = rows[0]!\n let updatedAt = first.createdAt\n let pendingCount = 0\n let failedCount = 0\n let attemptCount = 0\n let failureCount = 0\n for (const row of rows) {\n attemptCount += row.attemptCount\n failureCount += row.failureCount\n if (row.processedAt === null && row.failedAt === null) {\n pendingCount += 1\n }\n if (row.failedAt !== null) failedCount += 1\n for (const timestamp of [\n row.createdAt,\n row.firstClaimedAt,\n row.lastClaimedAt,\n row.lastFailedAt,\n row.processedAt,\n row.failedAt,\n ]) {\n if (timestamp && timestamp > updatedAt) updatedAt = timestamp\n }\n }\n return {\n sessionId,\n eventCount: rows.length,\n pendingCount,\n failedCount,\n attemptCount,\n failureCount,\n firstEventAt: new Date(first.createdAt),\n updatedAt: new Date(updatedAt),\n }\n })\n return {\n sessions: summaries,\n cursor: ids.length > visible.length ? (visible.at(-1) ?? null) : null,\n }\n },\n async readEvents(sessionId, pageOptions) {\n const rows = sessions.get(sessionId) ?? []\n const throughIndex = Math.min(\n pageOptions.throughIndex ?? rows.length,\n rows.length,\n )\n return {\n events: rows\n .slice(pageOptions.afterIndex, throughIndex)\n .slice(0, pageOptions.limit)\n .map(toStored),\n throughIndex,\n }\n },\n async listSnapshots(sessionId) {\n const prefix = `${sessionId}\\u0000`\n return [...snapshots.entries()]\n .filter(([key]) => key.startsWith(prefix))\n .map(([key, snapshot]) => ({\n reducerName: key.slice(prefix.length),\n index: snapshot.index,\n updatedAt: new Date(snapshot.updatedAt),\n }))\n .toSorted((a, b) => a.reducerName.localeCompare(b.reducerName))\n },\n },\n\n stream(sessionId, opts) {\n const startAfter = opts?.startAfter ?? 0\n return {\n [Symbol.asyncIterator](): AsyncIterator<Event> {\n let last = startAfter\n const buffer: Row[] = []\n let wake: (() => void) | null = null\n let closed = false\n\n const onRow = (row: Row): void => {\n buffer.push(row)\n wake?.()\n }\n let subs = streamSubscribers.get(sessionId)\n if (!subs) {\n subs = new Set()\n streamSubscribers.set(sessionId, subs)\n }\n subs.add(onRow)\n // Seed with history — synchronously, in the same tick as the\n // subscription, so nothing can slip between the two.\n const existing = sessions.get(sessionId) ?? []\n buffer.unshift(...existing.filter((row) => row.index > startAfter))\n\n const unsubscribe = (): void => {\n subs.delete(onRow)\n if (subs.size === 0) streamSubscribers.delete(sessionId)\n }\n\n return {\n async next(): Promise<IteratorResult<Event>> {\n for (;;) {\n while (buffer.length > 0) {\n const row = buffer.shift()!\n if (row.index <= last) continue\n last = row.index\n return { value: toStored(row), done: false }\n }\n if (closed) return { value: undefined, done: true }\n // oxlint-disable-next-line no-await-in-loop -- wait-for-wake\n await new Promise<void>((resolve) => {\n wake = resolve\n })\n wake = null\n }\n },\n async return(): Promise<IteratorResult<Event>> {\n closed = true\n unsubscribe()\n wake?.()\n return { value: undefined, done: true }\n },\n }\n },\n }\n },\n }\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
- import { r as POLL_TIMINGS } from "./internal-gCd5qMry.js";
2
- //#region src/log-polling.ts
1
+ import { i as POLL_TIMINGS } from "./internal-DstsI6Re.js";
2
+ //#region src/store-polling.ts
3
3
  /**
4
4
  * The shared polling stream — how poll-based backends (sqlite,
5
- * postgres) implement `A2Log.stream`.
5
+ * postgres) implement `A2Store.stream`.
6
6
  *
7
7
  * The cadence is activity-adaptive: while events are flowing, polls
8
8
  * run at a tight floor (25ms) so streams feel pushed — a token
@@ -38,10 +38,10 @@ const floor = () => Math.min(POLL_TIMINGS.activeFloorMs, POLL_TIMINGS.idleCeilin
38
38
  * SSE client), waking any pending sleep immediately.
39
39
  */
40
40
  function pollingStream(readAfter, options) {
41
- const startAt = options.startAt ?? 0;
41
+ const startAfter = options.startAfter ?? 0;
42
42
  const sleep = options.sleep ?? defaultSleep;
43
43
  return { [Symbol.asyncIterator]() {
44
- let last = startAt;
44
+ let last = startAfter;
45
45
  let buffer = [];
46
46
  let closed = false;
47
47
  let pending = null;
@@ -82,3 +82,5 @@ function pollingStream(readAfter, options) {
82
82
  }
83
83
  //#endregion
84
84
  export { pollingStream as n, defaultSleep as t };
85
+
86
+ //# sourceMappingURL=store-polling-dSeLxzfb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-polling-dSeLxzfb.js","names":[],"sources":["../src/store-polling.ts"],"sourcesContent":["/**\n * The shared polling stream — how poll-based backends (sqlite,\n * postgres) implement `A2Store.stream`.\n *\n * The cadence is activity-adaptive: while events are flowing, polls\n * run at a tight floor (25ms) so streams feel pushed — a token\n * generation reads smoothly instead of clumping at the idle interval;\n * every empty poll doubles the gap until the idle ceiling. The cadence\n * is owned (POLL_TIMINGS in internal.ts), not a public option: the\n * floor already keeps active streams smooth, so tuning it is a cost\n * decision a2 makes, not one it delegates. Correctness never depends\n * on the cadence — each poll is a catch-up read (`index > last`, in\n * order), so nothing can be missed, only arrive a beat later.\n */\n\nimport { POLL_TIMINGS } from './internal.ts'\nimport type { StoredEvent } from './store.ts'\n\n/** One cancellable sleep — the injection seam for cadence tests. */\nexport type Sleeper = { promise: Promise<void>; cancel: () => void }\n\n/** Unref'd cancellable timer — shared with the redis safety read. */\nexport const defaultSleep = (ms: number): Sleeper => {\n let timer: ReturnType<typeof setTimeout> | undefined\n let wake: (() => void) | undefined\n const promise = new Promise<void>((resolve) => {\n wake = resolve // assigned synchronously by the executor\n timer = setTimeout(resolve, ms)\n // Don't hold the process open for an idle poll.\n ;(timer as { unref?: () => void }).unref?.()\n })\n return {\n promise,\n cancel: () => {\n clearTimeout(timer)\n wake?.()\n },\n }\n}\n\n// Read the seam lazily — tests shrink POLL_TIMINGS in their setup.\nconst ceiling = (): number => POLL_TIMINGS.idleCeilingMs\nconst floor = (): number =>\n Math.min(POLL_TIMINGS.activeFloorMs, POLL_TIMINGS.idleCeilingMs)\n\nexport type PollingStreamOptions = {\n /** Deliver events strictly after this index (exclusive). */\n startAfter?: number\n /** Injectable sleep — tests assert the cadence without wall-clock waits. */\n sleep?: (ms: number) => Sleeper\n}\n\n/**\n * Build the `stream()` iterable from a backend's catch-up read. The\n * iterable ends when the consumer calls `return()` (a disconnecting\n * SSE client), waking any pending sleep immediately.\n */\nexport function pollingStream(\n readAfter: (afterIndex: number) => StoredEvent[] | Promise<StoredEvent[]>,\n options: PollingStreamOptions,\n): AsyncIterable<StoredEvent> {\n const startAfter = options.startAfter ?? 0\n const sleep = options.sleep ?? defaultSleep\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<StoredEvent> {\n let last = startAfter\n let buffer: StoredEvent[] = []\n let closed = false\n let pending: Sleeper | null = null\n let interval = floor()\n\n return {\n async next(): Promise<IteratorResult<StoredEvent>> {\n for (;;) {\n if (closed) return { value: undefined, done: true }\n // oxlint-disable-next-line no-await-in-loop -- poll loop\n if (buffer.length === 0) buffer = await readAfter(last)\n const row = buffer.shift()\n if (row) {\n // Activity: tighten back to the floor.\n interval = floor()\n last = row.index\n return { value: row, done: false }\n }\n // Empty poll: wait, then back off toward the idle ceiling.\n pending = sleep(interval)\n // oxlint-disable-next-line no-await-in-loop -- poll loop\n await pending.promise\n pending = null\n interval = Math.min(interval * 2, ceiling())\n }\n },\n async return(): Promise<IteratorResult<StoredEvent>> {\n closed = true\n pending?.cancel()\n return { value: undefined, done: true }\n },\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAsBA,MAAa,gBAAgB,OAAwB;CACnD,IAAI;CACJ,IAAI;CAOJ,OAAO;EACL,SAAA,IAPkB,SAAe,YAAY;GAC7C,OAAO;GACP,QAAQ,WAAW,SAAS,EAAE;GAE7B,MAAkC,QAAQ;EAC7C,CAEQ;EACN,cAAc;GACZ,aAAa,KAAK;GAClB,OAAO;EACT;CACF;AACF;AAGA,MAAM,gBAAwB,aAAa;AAC3C,MAAM,cACJ,KAAK,IAAI,aAAa,eAAe,aAAa,aAAa;;;;;;AAcjE,SAAgB,cACd,WACA,SAC4B;CAC5B,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,QAAQ,QAAQ,SAAS;CAE/B,OAAO,EACL,CAAC,OAAO,iBAA6C;EACnD,IAAI,OAAO;EACX,IAAI,SAAwB,CAAC;EAC7B,IAAI,SAAS;EACb,IAAI,UAA0B;EAC9B,IAAI,WAAW,MAAM;EAErB,OAAO;GACL,MAAM,OAA6C;IACjD,SAAS;KACP,IAAI,QAAQ,OAAO;MAAE,OAAO,KAAA;MAAW,MAAM;KAAK;KAElD,IAAI,OAAO,WAAW,GAAG,SAAS,MAAM,UAAU,IAAI;KACtD,MAAM,MAAM,OAAO,MAAM;KACzB,IAAI,KAAK;MAEP,WAAW,MAAM;MACjB,OAAO,IAAI;MACX,OAAO;OAAE,OAAO;OAAK,MAAM;MAAM;KACnC;KAEA,UAAU,MAAM,QAAQ;KAExB,MAAM,QAAQ;KACd,UAAU;KACV,WAAW,KAAK,IAAI,WAAW,GAAG,QAAQ,CAAC;IAC7C;GACF;GACA,MAAM,SAA+C;IACnD,SAAS;IACT,SAAS,OAAO;IAChB,OAAO;KAAE,OAAO,KAAA;KAAW,MAAM;IAAK;GACxC;EACF;CACF,EACF;AACF"}
@@ -1,5 +1,5 @@
1
- import { c as IdSource, i as Clock, t as A2Log } from "./log-ldf5g8Cx.js";
2
- //#region src/log-postgres.d.ts
1
+ import { c as IdSource, i as Clock, t as A2Store } from "./store-DysUkTH3.js";
2
+ //#region src/store-postgres.d.ts
3
3
  /** The result shape this backend reads: just rows. */
4
4
  type PostgresQueryResult = {
5
5
  rows: Record<string, unknown>[];
@@ -20,7 +20,7 @@ type PostgresClient = {
20
20
  connect?(): Promise<PostgresConnection>;
21
21
  end?(): Promise<void>;
22
22
  };
23
- type PostgresLogOptions = {
23
+ type PostgresStoreOptions = {
24
24
  /** Creates a `pg` Pool lazily (requires the optional peer dep `pg`). */
25
25
  connectionString?: string | undefined;
26
26
  /** Bring your own client — a `pg` Pool, PGlite, a pooler wrapper. */
@@ -30,11 +30,12 @@ type PostgresLogOptions = {
30
30
  /** Injectable id source for generated event ids. */
31
31
  ids?: IdSource;
32
32
  };
33
- type PostgresLog = A2Log & {
33
+ type PostgresStore = A2Store & {
34
34
  /** End the underlying pool/client (when this backend created it, or
35
35
  * the injected client has `end`). */
36
36
  close(): Promise<void>;
37
37
  };
38
- declare function postgres(options?: PostgresLogOptions): PostgresLog;
38
+ declare function postgres(options?: PostgresStoreOptions): PostgresStore;
39
39
  //#endregion
40
- export { PostgresClient, PostgresConnection, PostgresLog, PostgresLogOptions, PostgresQueryResult, postgres };
40
+ export { PostgresClient, PostgresConnection, PostgresQueryResult, PostgresStore, PostgresStoreOptions, postgres };
41
+ //# sourceMappingURL=store-postgres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-postgres.d.ts","names":[],"sources":["../src/store-postgres.ts"],"mappings":";;;KAqCY;EAAwB,MAAM;;;KAG9B;EACV,MAAM,cAAc,qBAAqB,QAAQ;EACjD;;;;;;;;KASU;EACV,MAAM,cAAc,qBAAqB,QAAQ;EACjD,YAAY,QAAQ;EACpB,QAAQ;;KAGE;;EAEV;;EAEA,SAAS;;EAET,QAAQ;;EAER,MAAM;;KAGI,gBAAgB;;;EAG1B,SAAS;;iBAoLK,SAAS,UAAS,uBAA4B"}