experimental-a2 0.6.0 → 0.8.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 (148) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/ai-server.d.ts +4 -5
  3. package/dist/ai-server.d.ts.map +1 -1
  4. package/dist/ai-server.js +20 -17
  5. package/dist/ai-server.js.map +1 -1
  6. package/dist/ai.d.ts +334 -2
  7. package/dist/ai.d.ts.map +1 -0
  8. package/dist/ai.js +1 -1
  9. package/dist/client.d.ts +202 -2
  10. package/dist/client.d.ts.map +1 -0
  11. package/dist/client.js +1025 -1
  12. package/dist/client.js.map +1 -0
  13. package/dist/errors-BQuJpe82.js.map +1 -1
  14. package/dist/index.d.ts +22 -3
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/{internal-DstsI6Re.js → internal-DRXJ56EI.js} +5 -28
  17. package/dist/internal-DRXJ56EI.js.map +1 -0
  18. package/dist/react.d.ts +1 -1
  19. package/dist/react.js +1 -1
  20. package/dist/scheduler-qstash.d.ts +3 -3
  21. package/dist/scheduler-qstash.js +4 -5
  22. package/dist/scheduler-qstash.js.map +1 -1
  23. package/dist/scheduler-vercel.d.ts +2 -2
  24. package/dist/scheduler-vercel.js +4 -4
  25. package/dist/scheduler-vercel.js.map +1 -1
  26. package/dist/{server-Duw6MVlB.js → server-B2XNevQA.js} +830 -131
  27. package/dist/server-B2XNevQA.js.map +1 -0
  28. package/dist/{server-DpvjhdoE.d.ts → server-DjPhHnbI.d.ts} +71 -50
  29. package/dist/server-DjPhHnbI.d.ts.map +1 -0
  30. package/dist/server.d.ts +3 -3
  31. package/dist/server.js +1 -1
  32. package/dist/store-N8PXxDAS.js.map +1 -1
  33. package/dist/{store-DysUkTH3.d.ts → store-RJO35BMj.d.ts} +24 -62
  34. package/dist/store-RJO35BMj.d.ts.map +1 -0
  35. package/dist/store-memory.d.ts +1 -1
  36. package/dist/store-memory.d.ts.map +1 -1
  37. package/dist/store-memory.js +80 -78
  38. package/dist/store-memory.js.map +1 -1
  39. package/dist/{store-polling-dSeLxzfb.js → store-polling-6DW7F1DT.js} +2 -2
  40. package/dist/{store-polling-dSeLxzfb.js.map → store-polling-6DW7F1DT.js.map} +1 -1
  41. package/dist/store-postgres.d.ts +1 -1
  42. package/dist/store-postgres.d.ts.map +1 -1
  43. package/dist/store-postgres.js +231 -182
  44. package/dist/store-postgres.js.map +1 -1
  45. package/dist/{store-redis-core-BFLwz0Wj.js → store-redis-core-DT01r4GZ.js} +213 -161
  46. package/dist/store-redis-core-DT01r4GZ.js.map +1 -0
  47. package/dist/store-redis-http.d.ts +1 -1
  48. package/dist/store-redis-http.js +3 -4
  49. package/dist/store-redis-http.js.map +1 -1
  50. package/dist/store-redis.d.ts +1 -1
  51. package/dist/store-redis.js +4 -5
  52. package/dist/store-redis.js.map +1 -1
  53. package/dist/store-sqlite.d.ts +1 -1
  54. package/dist/store-sqlite.d.ts.map +1 -1
  55. package/dist/store-sqlite.js +104 -91
  56. package/dist/store-sqlite.js.map +1 -1
  57. package/dist/{wire-BFQmSJ-9.js → wire-B6te_wns.js} +4 -3
  58. package/dist/wire-B6te_wns.js.map +1 -0
  59. package/docs/concepts/02-handlers.mdx +4 -0
  60. package/docs/concepts/04-state.mdx +57 -9
  61. package/docs/guides/03-react.mdx +20 -28
  62. package/docs/guides/05-production.mdx +9 -11
  63. package/docs/guides/06-ai-agents.mdx +10 -15
  64. package/docs/guides/09-presence.mdx +14 -19
  65. package/docs/guides/10-transports.mdx +104 -86
  66. package/docs/reference/01-api.mdx +182 -293
  67. package/docs/reference/02-errors.mdx +5 -7
  68. package/package.json +1 -14
  69. package/src/ai-server.ts +36 -15
  70. package/src/client.ts +2 -2
  71. package/src/errors.ts +1 -0
  72. package/src/internal.ts +3 -62
  73. package/src/push-envelope.ts +24 -21
  74. package/src/scheduler-qstash.ts +3 -3
  75. package/src/scheduler-vercel.ts +2 -2
  76. package/src/server-fetch.ts +344 -0
  77. package/src/server.ts +315 -312
  78. package/src/session-socket.ts +36 -20
  79. package/src/sse.ts +2 -2
  80. package/src/store-memory.ts +138 -101
  81. package/src/store-postgres.ts +355 -238
  82. package/src/store-redis-core.ts +247 -237
  83. package/src/store-redis-http.ts +1 -2
  84. package/src/store-redis.ts +1 -2
  85. package/src/store-sqlite.ts +191 -153
  86. package/src/store.ts +24 -66
  87. package/src/wire.ts +2 -1
  88. package/dist/ai-D_PGS-JR.d.ts +0 -334
  89. package/dist/ai-D_PGS-JR.d.ts.map +0 -1
  90. package/dist/cli-B3VuxoDe.js +0 -599
  91. package/dist/cli-B3VuxoDe.js.map +0 -1
  92. package/dist/cli-bin.d.ts +0 -1
  93. package/dist/cli-bin.js +0 -7
  94. package/dist/cli-bin.js.map +0 -1
  95. package/dist/cli.d.ts +0 -20
  96. package/dist/cli.d.ts.map +0 -1
  97. package/dist/cli.js +0 -2
  98. package/dist/client-CdMqi7mC.d.ts +0 -202
  99. package/dist/client-CdMqi7mC.d.ts.map +0 -1
  100. package/dist/client-Dj5d3SP_.js +0 -1026
  101. package/dist/client-Dj5d3SP_.js.map +0 -1
  102. package/dist/devtools-J_jZ2vQf.d.ts +0 -152
  103. package/dist/devtools-J_jZ2vQf.d.ts.map +0 -1
  104. package/dist/devtools-kJJaORn-.js +0 -340
  105. package/dist/devtools-kJJaORn-.js.map +0 -1
  106. package/dist/devtools-server.browser.d.ts +0 -1
  107. package/dist/devtools-server.browser.js +0 -6
  108. package/dist/devtools-server.browser.js.map +0 -1
  109. package/dist/devtools-server.d.ts +0 -23
  110. package/dist/devtools-server.d.ts.map +0 -1
  111. package/dist/devtools-server.js +0 -1270
  112. package/dist/devtools-server.js.map +0 -1
  113. package/dist/devtools.d.ts +0 -2
  114. package/dist/devtools.js +0 -2
  115. package/dist/errors-W6nwJ-fm.d.ts +0 -21
  116. package/dist/errors-W6nwJ-fm.d.ts.map +0 -1
  117. package/dist/http.d.ts +0 -151
  118. package/dist/http.d.ts.map +0 -1
  119. package/dist/http.js +0 -706
  120. package/dist/http.js.map +0 -1
  121. package/dist/inspection-DaxB5jM2.js +0 -13
  122. package/dist/inspection-DaxB5jM2.js.map +0 -1
  123. package/dist/internal-DstsI6Re.js.map +0 -1
  124. package/dist/platform-B4TnJtWu.js +0 -34
  125. package/dist/platform-B4TnJtWu.js.map +0 -1
  126. package/dist/server-DpvjhdoE.d.ts.map +0 -1
  127. package/dist/server-Duw6MVlB.js.map +0 -1
  128. package/dist/store-DysUkTH3.d.ts.map +0 -1
  129. package/dist/store-redis-core-BFLwz0Wj.js.map +0 -1
  130. package/dist/testing.browser.d.ts +0 -1
  131. package/dist/testing.browser.js +0 -6
  132. package/dist/testing.browser.js.map +0 -1
  133. package/dist/testing.d.ts +0 -32
  134. package/dist/testing.d.ts.map +0 -1
  135. package/dist/testing.js +0 -103
  136. package/dist/testing.js.map +0 -1
  137. package/dist/wire-BFQmSJ-9.js.map +0 -1
  138. package/docs/guides/07-devtools.mdx +0 -229
  139. package/src/cli-bin.ts +0 -5
  140. package/src/cli.ts +0 -1046
  141. package/src/devtools-app.ts +0 -989
  142. package/src/devtools-server.browser.ts +0 -5
  143. package/src/devtools-server.ts +0 -604
  144. package/src/devtools.ts +0 -716
  145. package/src/http.ts +0 -394
  146. package/src/inspection.ts +0 -39
  147. package/src/testing.browser.ts +0 -5
  148. package/src/testing.ts +0 -185
@@ -1,5 +1,5 @@
1
1
  import { t as A2Error } from "./errors-BQuJpe82.js";
2
- import { g as nullProtoRecord } from "./internal-DstsI6Re.js";
2
+ import { h as nullProtoRecord } from "./internal-DRXJ56EI.js";
3
3
  import { t as idempotentReplay } from "./idempotent-replay-DuqEkYA7.js";
4
4
  import { n as SYSTEM_CLOCK, t as RANDOM_IDS } from "./store-N8PXxDAS.js";
5
5
  //#region src/store-memory.ts
@@ -34,6 +34,8 @@ const toEvent = (row) => ({
34
34
  sessionId: row.sessionId,
35
35
  createdAt: new Date(row.createdAt)
36
36
  });
37
+ const snapshotKey = (sessionId, reducerName) => `${sessionId}\u0000${reducerName}`;
38
+ const eventPinKey = (sessionId, index) => `${sessionId}\u0000${index}`;
37
39
  function memory(options = {}) {
38
40
  const clock = options.clock ?? SYSTEM_CLOCK;
39
41
  const generateId = options.ids ?? RANDOM_IDS;
@@ -43,6 +45,9 @@ function memory(options = {}) {
43
45
  const byEventId = /* @__PURE__ */ new Map();
44
46
  /** Keyed by `${sessionId}\u0000${reducerName}` — a pure cache. */
45
47
  const snapshots = /* @__PURE__ */ new Map();
48
+ const historicalSnapshots = /* @__PURE__ */ new Map();
49
+ const snapshotPins = /* @__PURE__ */ new Map();
50
+ const snapshotPinCounts = /* @__PURE__ */ new Map();
46
51
  const streamSubscribers = /* @__PURE__ */ new Map();
47
52
  /** ns → participant → field → latest surviving write. */
48
53
  const presenceRows = /* @__PURE__ */ new Map();
@@ -60,6 +65,20 @@ function memory(options = {}) {
60
65
  }
61
66
  return rows;
62
67
  };
68
+ const checkpointKey = (sessionId, reducerName, index) => `${snapshotKey(sessionId, reducerName)}\u0000${index}`;
69
+ const releaseSnapshotPins = (sessionId, eventIndex) => {
70
+ const pinKey = eventPinKey(sessionId, eventIndex);
71
+ const checkpoints = snapshotPins.get(pinKey);
72
+ if (!checkpoints) return;
73
+ for (const key of checkpoints) {
74
+ const next = (snapshotPinCounts.get(key) ?? 1) - 1;
75
+ if (next === 0) {
76
+ snapshotPinCounts.delete(key);
77
+ historicalSnapshots.delete(key);
78
+ } else snapshotPinCounts.set(key, next);
79
+ }
80
+ snapshotPins.delete(pinKey);
81
+ };
63
82
  const dispatchOf = (sessionId) => {
64
83
  let state = dispatch.get(sessionId);
65
84
  if (!state) {
@@ -162,16 +181,24 @@ function memory(options = {}) {
162
181
  }
163
182
  return inserted;
164
183
  };
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)
184
+ const readStateOf = (sessionId, reducerName, throughIndex, snapshotThroughIndex) => {
185
+ const key = snapshotKey(sessionId, reducerName);
186
+ const snapshotFrontier = snapshotThroughIndex ?? throughIndex;
187
+ const head = snapshots.get(key);
188
+ let candidate = head && (snapshotFrontier === void 0 || head.index <= snapshotFrontier) ? head : null;
189
+ if (snapshotFrontier !== void 0) {
190
+ const prefix = `${key}\u0000`;
191
+ for (const [historicalKey, snapshot] of historicalSnapshots) if (historicalKey.startsWith(prefix) && snapshot.index <= snapshotFrontier && (!candidate || snapshot.index > candidate.index)) candidate = snapshot;
192
+ }
193
+ const snapshot = candidate ? {
194
+ index: candidate.index,
195
+ state: structuredClone(candidate.state)
170
196
  } : null;
171
197
  const afterIndex = snapshot?.index ?? 0;
172
198
  return {
199
+ headIndex: head?.index ?? null,
173
200
  snapshot,
174
- events: (sessions.get(sessionId) ?? []).filter((row) => row.index > afterIndex).map(toEvent)
201
+ events: (sessions.get(sessionId) ?? []).filter((row) => row.index > afterIndex && (throughIndex === void 0 || row.index <= throughIndex)).map(toEvent)
175
202
  };
176
203
  };
177
204
  return {
@@ -275,6 +302,7 @@ function memory(options = {}) {
275
302
  parent.claimHolder = null;
276
303
  parent.claimExpiresAt = null;
277
304
  settle(sessionId, parent);
305
+ releaseSnapshotPins(sessionId, index);
278
306
  notifyStreams(sessionId, inserted);
279
307
  return {
280
308
  outcome: "completed",
@@ -305,6 +333,7 @@ function memory(options = {}) {
305
333
  if (row.failureCount >= maxFailures) {
306
334
  row.failedAt = new Date(failedAt);
307
335
  dispatchOf(sessionId).ready.delete(row.index);
336
+ releaseSnapshotPins(sessionId, index);
308
337
  return {
309
338
  outcome: "dead_lettered",
310
339
  failureCount: row.failureCount
@@ -315,21 +344,52 @@ function memory(options = {}) {
315
344
  failureCount: row.failureCount
316
345
  };
317
346
  },
318
- async readState(sessionId, reducerName) {
319
- return readStateOf(sessionId, reducerName);
347
+ async readState(sessionId, reducerName, stateOptions) {
348
+ return readStateOf(sessionId, reducerName, stateOptions?.throughIndex, stateOptions?.snapshotThroughIndex);
320
349
  },
321
- async readStates(sessionIds, reducerName) {
322
- return sessionIds.map((sessionId) => readStateOf(sessionId, reducerName));
350
+ async readStates(requests, reducerName) {
351
+ return requests.map((request) => readStateOf(request.sessionId, reducerName, request.throughIndex, request.snapshotThroughIndex));
323
352
  },
324
- async putSnapshot(sessionId, reducerName, index, state) {
325
- const key = `${sessionId}\u0000${reducerName}`;
326
- const existing = snapshots.get(key);
327
- if (existing && existing.index >= index) return;
328
- snapshots.set(key, {
329
- index,
330
- state: structuredClone(state),
331
- updatedAt: clock.now()
332
- });
353
+ async putSnapshots(sessionId, reducerName, writes) {
354
+ const key = snapshotKey(sessionId, reducerName);
355
+ for (const write of writes.toSorted((a, b) => a.index - b.index)) {
356
+ const checkpoint = checkpointKey(sessionId, reducerName, write.index);
357
+ for (const eventIndex of write.pinEventIndexes ?? []) {
358
+ const event = sessions.get(sessionId)?.[eventIndex - 1];
359
+ if (!event || event.processedAt !== null || event.failedAt !== null) continue;
360
+ const pinKey = eventPinKey(sessionId, eventIndex);
361
+ let pinned = snapshotPins.get(pinKey);
362
+ if (!pinned) {
363
+ pinned = /* @__PURE__ */ new Set();
364
+ snapshotPins.set(pinKey, pinned);
365
+ }
366
+ if (!pinned.has(checkpoint)) {
367
+ pinned.add(checkpoint);
368
+ snapshotPinCounts.set(checkpoint, (snapshotPinCounts.get(checkpoint) ?? 0) + 1);
369
+ }
370
+ }
371
+ const current = snapshots.get(key);
372
+ if (!current || write.index >= current.index) {
373
+ if (current && write.index > current.index) {
374
+ const currentCheckpoint = checkpointKey(sessionId, reducerName, current.index);
375
+ if ((snapshotPinCounts.get(currentCheckpoint) ?? 0) > 0) historicalSnapshots.set(currentCheckpoint, {
376
+ index: current.index,
377
+ state: structuredClone(current.state),
378
+ updatedAt: new Date(current.updatedAt)
379
+ });
380
+ }
381
+ snapshots.set(key, {
382
+ index: write.index,
383
+ state: structuredClone(write.state),
384
+ updatedAt: clock.now()
385
+ });
386
+ historicalSnapshots.delete(checkpoint);
387
+ } else if (write.index < current.index && (snapshotPinCounts.get(checkpoint) ?? 0) > 0) historicalSnapshots.set(checkpoint, {
388
+ index: write.index,
389
+ state: structuredClone(write.state),
390
+ updatedAt: clock.now()
391
+ });
392
+ }
333
393
  },
334
394
  presence: {
335
395
  async set(ns, participant, values, meta) {
@@ -410,64 +470,6 @@ function memory(options = {}) {
410
470
  };
411
471
  }
412
472
  },
413
- inspect: {
414
- async listSessions(inspectionOptions) {
415
- const ids = [...sessions.keys()].filter((sessionId) => sessionId.startsWith(inspectionOptions.prefix) && (inspectionOptions.cursor === void 0 || sessionId > inspectionOptions.cursor)).toSorted();
416
- const visible = ids.slice(0, inspectionOptions.limit);
417
- return {
418
- sessions: visible.map((sessionId) => {
419
- const rows = sessions.get(sessionId);
420
- const first = rows[0];
421
- let updatedAt = first.createdAt;
422
- let pendingCount = 0;
423
- let failedCount = 0;
424
- let attemptCount = 0;
425
- let failureCount = 0;
426
- for (const row of rows) {
427
- attemptCount += row.attemptCount;
428
- failureCount += row.failureCount;
429
- if (row.processedAt === null && row.failedAt === null) pendingCount += 1;
430
- if (row.failedAt !== null) failedCount += 1;
431
- for (const timestamp of [
432
- row.createdAt,
433
- row.firstClaimedAt,
434
- row.lastClaimedAt,
435
- row.lastFailedAt,
436
- row.processedAt,
437
- row.failedAt
438
- ]) if (timestamp && timestamp > updatedAt) updatedAt = timestamp;
439
- }
440
- return {
441
- sessionId,
442
- eventCount: rows.length,
443
- pendingCount,
444
- failedCount,
445
- attemptCount,
446
- failureCount,
447
- firstEventAt: new Date(first.createdAt),
448
- updatedAt: new Date(updatedAt)
449
- };
450
- }),
451
- cursor: ids.length > visible.length ? visible.at(-1) ?? null : null
452
- };
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
- },
462
- async listSnapshots(sessionId) {
463
- const prefix = `${sessionId}\u0000`;
464
- return [...snapshots.entries()].filter(([key]) => key.startsWith(prefix)).map(([key, snapshot]) => ({
465
- reducerName: key.slice(prefix.length),
466
- index: snapshot.index,
467
- updatedAt: new Date(snapshot.updatedAt)
468
- })).toSorted((a, b) => a.reducerName.localeCompare(b.reducerName));
469
- }
470
- },
471
473
  stream(sessionId, opts) {
472
474
  const startAfter = opts?.startAfter ?? 0;
473
475
  return { [Symbol.asyncIterator]() {
@@ -1 +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
+ {"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 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\nconst snapshotKey = (sessionId: string, reducerName: string): string =>\n `${sessionId}\\u0000${reducerName}`\n\nconst eventPinKey = (sessionId: string, index: number): string =>\n `${sessionId}\\u0000${index}`\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 historicalSnapshots = new Map<\n string,\n { index: number; state: unknown; updatedAt: Date }\n >()\n const snapshotPins = new Map<string, Set<string>>()\n const snapshotPinCounts = new Map<string, number>()\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 checkpointKey = (\n sessionId: string,\n reducerName: string,\n index: number,\n ): string => `${snapshotKey(sessionId, reducerName)}\\u0000${index}`\n\n const releaseSnapshotPins = (sessionId: string, eventIndex: number): void => {\n const pinKey = eventPinKey(sessionId, eventIndex)\n const checkpoints = snapshotPins.get(pinKey)\n if (!checkpoints) return\n for (const key of checkpoints) {\n const next = (snapshotPinCounts.get(key) ?? 1) - 1\n if (next === 0) {\n snapshotPinCounts.delete(key)\n historicalSnapshots.delete(key)\n } else {\n snapshotPinCounts.set(key, next)\n }\n }\n snapshotPins.delete(pinKey)\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 throughIndex?: number,\n snapshotThroughIndex?: number,\n ): StoreStateRead => {\n const key = snapshotKey(sessionId, reducerName)\n const snapshotFrontier = snapshotThroughIndex ?? throughIndex\n const head = snapshots.get(key)\n let candidate =\n head && (snapshotFrontier === undefined || head.index <= snapshotFrontier)\n ? head\n : null\n if (snapshotFrontier !== undefined) {\n const prefix = `${key}\\u0000`\n for (const [historicalKey, snapshot] of historicalSnapshots) {\n if (\n historicalKey.startsWith(prefix) &&\n snapshot.index <= snapshotFrontier &&\n (!candidate || snapshot.index > candidate.index)\n ) {\n candidate = snapshot\n }\n }\n }\n const snapshot = candidate\n ? { index: candidate.index, state: structuredClone(candidate.state) }\n : null\n const afterIndex = snapshot?.index ?? 0\n return {\n headIndex: head?.index ?? null,\n snapshot,\n events: (sessions.get(sessionId) ?? [])\n .filter(\n (row) =>\n row.index > afterIndex &&\n (throughIndex === undefined || row.index <= throughIndex),\n )\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 releaseSnapshotPins(sessionId, index)\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 releaseSnapshotPins(sessionId, 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, stateOptions) {\n return readStateOf(\n sessionId,\n reducerName,\n stateOptions?.throughIndex,\n stateOptions?.snapshotThroughIndex,\n )\n },\n\n async readStates(requests, reducerName) {\n return requests.map((request) =>\n readStateOf(\n request.sessionId,\n reducerName,\n request.throughIndex,\n request.snapshotThroughIndex,\n ),\n )\n },\n\n async putSnapshots(sessionId, reducerName, writes) {\n const key = snapshotKey(sessionId, reducerName)\n for (const write of writes.toSorted((a, b) => a.index - b.index)) {\n const checkpoint = checkpointKey(sessionId, reducerName, write.index)\n for (const eventIndex of write.pinEventIndexes ?? []) {\n const event = sessions.get(sessionId)?.[eventIndex - 1]\n if (!event || event.processedAt !== null || event.failedAt !== null) {\n continue\n }\n const pinKey = eventPinKey(sessionId, eventIndex)\n let pinned = snapshotPins.get(pinKey)\n if (!pinned) {\n pinned = new Set()\n snapshotPins.set(pinKey, pinned)\n }\n if (!pinned.has(checkpoint)) {\n pinned.add(checkpoint)\n snapshotPinCounts.set(\n checkpoint,\n (snapshotPinCounts.get(checkpoint) ?? 0) + 1,\n )\n }\n }\n\n const current = snapshots.get(key)\n if (!current || write.index >= current.index) {\n if (current && write.index > current.index) {\n const currentCheckpoint = checkpointKey(\n sessionId,\n reducerName,\n current.index,\n )\n if ((snapshotPinCounts.get(currentCheckpoint) ?? 0) > 0) {\n historicalSnapshots.set(currentCheckpoint, {\n index: current.index,\n state: structuredClone(current.state),\n updatedAt: new Date(current.updatedAt),\n })\n }\n }\n snapshots.set(key, {\n index: write.index,\n state: structuredClone(write.state),\n updatedAt: clock.now(),\n })\n historicalSnapshots.delete(checkpoint)\n } else if (\n write.index < current.index &&\n (snapshotPinCounts.get(checkpoint) ?? 0) > 0\n ) {\n historicalSnapshots.set(checkpoint, {\n index: write.index,\n state: structuredClone(write.state),\n updatedAt: clock.now(),\n })\n }\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 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,4 +1,4 @@
1
- import { i as POLL_TIMINGS } from "./internal-DstsI6Re.js";
1
+ import { i as POLL_TIMINGS } from "./internal-DRXJ56EI.js";
2
2
  //#region src/store-polling.ts
3
3
  /**
4
4
  * The shared polling stream — how poll-based backends (sqlite,
@@ -83,4 +83,4 @@ function pollingStream(readAfter, options) {
83
83
  //#endregion
84
84
  export { pollingStream as n, defaultSleep as t };
85
85
 
86
- //# sourceMappingURL=store-polling-dSeLxzfb.js.map
86
+ //# sourceMappingURL=store-polling-6DW7F1DT.js.map
@@ -1 +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
+ {"version":3,"file":"store-polling-6DW7F1DT.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,4 +1,4 @@
1
- import { c as IdSource, i as Clock, t as A2Store } from "./store-DysUkTH3.js";
1
+ import { r as Clock, s as IdSource, t as A2Store } from "./store-RJO35BMj.js";
2
2
  //#region src/store-postgres.d.ts
3
3
  /** The result shape this backend reads: just rows. */
4
4
  type PostgresQueryResult = {
@@ -1 +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"}
1
+ {"version":3,"file":"store-postgres.d.ts","names":[],"sources":["../src/store-postgres.ts"],"mappings":";;;KAsCY;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;;iBAwMK,SAAS,UAAS,uBAA4B"}