experimental-a2 0.20.0 → 0.22.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 (309) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +1 -1
  3. package/dist/{actor-C7b-1arn.d.ts → actor-CqibLgjQ.d.ts} +15 -7
  4. package/dist/actor-CqibLgjQ.d.ts.map +1 -0
  5. package/dist/actor-client.d.ts +1 -1
  6. package/dist/actor-client.js +2 -2
  7. package/dist/actor-react.d.ts +3 -3
  8. package/dist/actor-react.js +5 -5
  9. package/dist/{actor-shared-t7w8xIKP.js → actor-shared-DFET5q16.js} +3 -3
  10. package/dist/actor-shared-DFET5q16.js.map +1 -0
  11. package/dist/actor.d.ts +1 -1
  12. package/dist/actor.js +54 -43
  13. package/dist/actor.js.map +1 -1
  14. package/dist/{ai-Cz3hqVhk.d.ts → ai-DAu77CDr.d.ts} +8 -8
  15. package/dist/{ai-Cz3hqVhk.d.ts.map → ai-DAu77CDr.d.ts.map} +1 -1
  16. package/dist/{ai-mMiWul1T.js → ai-EEfKyc-z.js} +9 -9
  17. package/dist/ai-EEfKyc-z.js.map +1 -0
  18. package/dist/ai-client.d.ts +2 -2
  19. package/dist/ai-client.js +2 -2
  20. package/dist/ai-fx.d.ts +4 -2
  21. package/dist/ai-fx.d.ts.map +1 -1
  22. package/dist/ai-fx.js +214 -67
  23. package/dist/ai-fx.js.map +1 -1
  24. package/dist/{ai-harness-CV6rXbB3.d.ts → ai-harness-DTjkAr2T.d.ts} +2 -2
  25. package/dist/{ai-harness-CV6rXbB3.d.ts.map → ai-harness-DTjkAr2T.d.ts.map} +1 -1
  26. package/dist/{ai-harness-Clbg5ei7.js → ai-harness-dQeJaR1t.js} +7 -3
  27. package/dist/ai-harness-dQeJaR1t.js.map +1 -0
  28. package/dist/ai-pi.d.ts +1 -1
  29. package/dist/ai-pi.js +3 -3
  30. package/dist/ai-pi.js.map +1 -1
  31. package/dist/ai-react.d.ts +5 -5
  32. package/dist/ai-react.js +2 -2
  33. package/dist/ai-server.d.ts +14 -17
  34. package/dist/ai-server.d.ts.map +1 -1
  35. package/dist/ai-server.js +86 -73
  36. package/dist/ai-server.js.map +1 -1
  37. package/dist/ai.d.ts +2 -2
  38. package/dist/ai.js +2 -2
  39. package/dist/{client-BhHLoNKF.js → client-BQS4i_V9.js} +29 -6
  40. package/dist/client-BQS4i_V9.js.map +1 -0
  41. package/dist/{client-h_DKFAjj.d.ts → client-CUMbS_38.d.ts} +3 -3
  42. package/dist/{client-h_DKFAjj.d.ts.map → client-CUMbS_38.d.ts.map} +1 -1
  43. package/dist/client.d.ts +3 -3
  44. package/dist/client.js +1 -1
  45. package/dist/{contract-BYKASlCV.js → contract-CWukt01d.js} +2 -2
  46. package/dist/contract-CWukt01d.js.map +1 -0
  47. package/dist/index.d.ts +5 -5
  48. package/dist/index.js +3 -3
  49. package/dist/{initial-snapshot-Bx-c0pDP.d.ts → initial-snapshot-D3Lve43o.d.ts} +4 -4
  50. package/dist/initial-snapshot-D3Lve43o.d.ts.map +1 -0
  51. package/dist/{internal-CscSY7K_.js → internal-CvsrprnU.js} +40 -16
  52. package/dist/internal-CvsrprnU.js.map +1 -0
  53. package/dist/otel.d.ts +1 -1
  54. package/dist/otel.js +1 -1
  55. package/dist/otel.js.map +1 -1
  56. package/dist/{react-BBXgHWFc.d.ts → react-BoHvC3v9.d.ts} +4 -4
  57. package/dist/{react-BBXgHWFc.d.ts.map → react-BoHvC3v9.d.ts.map} +1 -1
  58. package/dist/react.d.ts +1 -1
  59. package/dist/react.js +1 -1
  60. package/dist/{reducer-CqA59Q6U.d.ts → reducer-CYPHsSmd.d.ts} +2 -2
  61. package/dist/{reducer-CqA59Q6U.d.ts.map → reducer-CYPHsSmd.d.ts.map} +1 -1
  62. package/dist/{reducer-BAXc8JyF.js → reducer-CjmvZSAb.js} +2 -2
  63. package/dist/{reducer-BAXc8JyF.js.map → reducer-CjmvZSAb.js.map} +1 -1
  64. package/dist/runtime-consumer-CIeL33wj.js +12 -0
  65. package/dist/runtime-consumer-CIeL33wj.js.map +1 -0
  66. package/dist/scheduler-qstash.d.ts +2 -2
  67. package/dist/scheduler-qstash.js +3 -3
  68. package/dist/scheduler-task-X1SToDjP.js.map +1 -1
  69. package/dist/scheduler-vercel.d.ts +2 -2
  70. package/dist/scheduler-vercel.js +3 -3
  71. package/dist/scheduler-vercel.js.map +1 -1
  72. package/dist/{server-qyb5aJJG.js → server-DtFrWxi3.js} +412 -116
  73. package/dist/server-DtFrWxi3.js.map +1 -0
  74. package/dist/{server-DYAATFuT.d.ts → server-qgez0Xny.d.ts} +108 -41
  75. package/dist/server-qgez0Xny.d.ts.map +1 -0
  76. package/dist/server.browser.js +1 -1
  77. package/dist/server.browser.js.map +1 -1
  78. package/dist/server.d.ts +4 -4
  79. package/dist/server.js +2 -2
  80. package/dist/{session-clear-C-QwTXV1.d.ts → session-clear-D1PFe7xl.d.ts} +2 -2
  81. package/dist/session-clear-D1PFe7xl.d.ts.map +1 -0
  82. package/dist/{session-clear-DGI4jTQ5.js → session-clear-wHd5GCpZ.js} +5 -4
  83. package/dist/session-clear-wHd5GCpZ.js.map +1 -0
  84. package/dist/store-D0MhBvg6.d.ts +532 -0
  85. package/dist/store-D0MhBvg6.d.ts.map +1 -0
  86. package/dist/store-N8PXxDAS.js.map +1 -1
  87. package/dist/store-codec-DwrWlgQx.js +65 -0
  88. package/dist/store-codec-DwrWlgQx.js.map +1 -0
  89. package/dist/store-memory.d.ts +1 -1
  90. package/dist/store-memory.d.ts.map +1 -1
  91. package/dist/store-memory.js +406 -225
  92. package/dist/store-memory.js.map +1 -1
  93. package/dist/{store-polling-7WJV0YWP.js → store-polling-BZt2Rf3D.js} +2 -2
  94. package/dist/{store-polling-7WJV0YWP.js.map → store-polling-BZt2Rf3D.js.map} +1 -1
  95. package/dist/store-postgres.d.ts +1 -1
  96. package/dist/store-postgres.d.ts.map +1 -1
  97. package/dist/store-postgres.js +1598 -587
  98. package/dist/store-postgres.js.map +1 -1
  99. package/dist/store-presence-polling-JuAy2Ck2.js +111 -0
  100. package/dist/store-presence-polling-JuAy2Ck2.js.map +1 -0
  101. package/dist/store-redis-http.d.ts +1 -1
  102. package/dist/store-redis-http.js +4 -4
  103. package/dist/store-redis-notify-CsJw_hfD.js +3060 -0
  104. package/dist/store-redis-notify-CsJw_hfD.js.map +1 -0
  105. package/dist/store-redis.d.ts +1 -1
  106. package/dist/store-redis.d.ts.map +1 -1
  107. package/dist/store-redis.js +4 -5
  108. package/dist/store-redis.js.map +1 -1
  109. package/dist/store-sqlite.d.ts +1 -1
  110. package/dist/store-sqlite.d.ts.map +1 -1
  111. package/dist/store-sqlite.js +527 -299
  112. package/dist/store-sqlite.js.map +1 -1
  113. package/dist/stream-buffer-DrTyiIuo.js +57 -0
  114. package/dist/stream-buffer-DrTyiIuo.js.map +1 -0
  115. package/dist/{telemetry-Cyfqo6Qt.d.ts → telemetry-CWwsh-Gx.d.ts} +3 -3
  116. package/dist/telemetry-CWwsh-Gx.d.ts.map +1 -0
  117. package/dist/{wire-BKxH1vbP.js → wire-CV-Z7wz-.js} +6 -5
  118. package/dist/wire-CV-Z7wz-.js.map +1 -0
  119. package/docs/01-quickstart.mdx +21 -15
  120. package/docs/02-examples.mdx +1 -1
  121. package/docs/actors/01-introduction.mdx +13 -2
  122. package/docs/actors/02-concurrency.mdx +1 -1
  123. package/docs/agents/01-introduction.mdx +1 -1
  124. package/docs/agents/02-tools.mdx +12 -11
  125. package/docs/agents/03-conversations.mdx +36 -25
  126. package/docs/agents/04-harnesses.mdx +14 -7
  127. package/docs/client/03-presence.mdx +18 -14
  128. package/docs/contract/01-events.mdx +2 -2
  129. package/docs/contract/02-state.mdx +18 -14
  130. package/docs/contract/03-sessions.mdx +32 -25
  131. package/docs/index.mdx +29 -24
  132. package/docs/reference/01-core.mdx +7 -6
  133. package/docs/reference/02-server.mdx +250 -191
  134. package/docs/reference/04-ai.mdx +33 -23
  135. package/docs/reference/05-telemetry.mdx +27 -13
  136. package/docs/reference/06-errors.mdx +25 -19
  137. package/docs/reference/meta.ts +1 -1
  138. package/docs/schedulers/01-overview.mdx +8 -8
  139. package/docs/schedulers/02-vercel-queues.mdx +2 -2
  140. package/docs/schedulers/03-qstash.mdx +4 -4
  141. package/docs/server/01-consumers.mdx +418 -0
  142. package/docs/server/02-timers.mdx +31 -21
  143. package/docs/server/03-cancellation.mdx +52 -44
  144. package/docs/server/04-routes.mdx +4 -1
  145. package/docs/server/05-sql-projections.mdx +391 -0
  146. package/docs/server/06-guarantees.mdx +61 -51
  147. package/docs/stores/01-overview.mdx +3 -3
  148. package/docs/stores/02-redis.mdx +24 -10
  149. package/docs/stores/03-redis-http.mdx +8 -6
  150. package/docs/stores/04-postgres.mdx +65 -14
  151. package/docs/stores/05-sqlite.mdx +5 -3
  152. package/docs/upgrades/01-overview.mdx +31 -0
  153. package/docs/upgrades/78-0-22.mdx +115 -0
  154. package/docs/upgrades/79-0-21.mdx +165 -0
  155. package/docs/upgrades/80-0-20.mdx +43 -0
  156. package/docs/upgrades/81-0-19.mdx +33 -0
  157. package/docs/upgrades/82-0-18.mdx +33 -0
  158. package/docs/upgrades/83-0-17.mdx +69 -0
  159. package/docs/upgrades/meta.ts +3 -0
  160. package/examples/playground/DEPLOY.md +39 -7
  161. package/examples/playground/app/a0/chat.test.tsx +2 -2
  162. package/examples/playground/app/a0/sandbox-log.ts +17 -15
  163. package/examples/playground/app/a0/sandbox.ts +58 -13
  164. package/examples/playground/app/a0/server.ts +4 -4
  165. package/examples/playground/app/a2slack/a2slack.css +1067 -0
  166. package/examples/playground/app/a2slack/c/[channel]/page.tsx +20 -0
  167. package/examples/playground/app/a2slack/consumers/agent.ts +63 -0
  168. package/examples/playground/app/a2slack/consumers/feed.ts +164 -0
  169. package/examples/playground/app/a2slack/consumers/notify.ts +116 -0
  170. package/examples/playground/app/a2slack/consumers/search.ts +37 -0
  171. package/examples/playground/app/a2slack/consumers/triage.ts +31 -0
  172. package/examples/playground/app/a2slack/consumers/welcome.ts +25 -0
  173. package/examples/playground/app/a2slack/db/a2.ts +209 -0
  174. package/examples/playground/app/a2slack/db/index.ts +73 -0
  175. package/examples/playground/app/a2slack/db/migrations/0000_extensions.sql +4 -0
  176. package/examples/playground/app/a2slack/db/migrations/0001_workspace.sql +74 -0
  177. package/examples/playground/app/a2slack/db/migrations/0002_a2.sql +215 -0
  178. package/examples/playground/app/a2slack/db/migrations/0003_a2_batch.sql +67 -0
  179. package/examples/playground/app/a2slack/db/migrations/0004_a2_session_event_ids.sql +2 -0
  180. package/examples/playground/app/a2slack/db/migrations/meta/0000_snapshot.json +18 -0
  181. package/examples/playground/app/a2slack/db/migrations/meta/0001_snapshot.json +500 -0
  182. package/examples/playground/app/a2slack/db/migrations/meta/0002_snapshot.json +1159 -0
  183. package/examples/playground/app/a2slack/db/migrations/meta/0003_snapshot.json +1159 -0
  184. package/examples/playground/app/a2slack/db/migrations/meta/0004_snapshot.json +1165 -0
  185. package/examples/playground/app/a2slack/db/migrations/meta/_journal.json +41 -0
  186. package/examples/playground/app/a2slack/db/queries.ts +263 -0
  187. package/examples/playground/app/a2slack/db/schema.ts +145 -0
  188. package/examples/playground/app/a2slack/drills/a2slack.drill.ts +708 -0
  189. package/examples/playground/app/a2slack/drills/harness.ts +244 -0
  190. package/examples/playground/app/a2slack/events/route.ts +36 -0
  191. package/examples/playground/app/a2slack/identity.ts +44 -0
  192. package/examples/playground/app/a2slack/inbox/route.ts +8 -0
  193. package/examples/playground/app/a2slack/lag/data/route.ts +8 -0
  194. package/examples/playground/app/a2slack/lag/page.tsx +101 -0
  195. package/examples/playground/app/a2slack/lag.ts +73 -0
  196. package/examples/playground/app/a2slack/layout.tsx +43 -0
  197. package/examples/playground/app/a2slack/messages/route.ts +17 -0
  198. package/examples/playground/app/a2slack/model.test.ts +208 -0
  199. package/examples/playground/app/a2slack/model.ts +369 -0
  200. package/examples/playground/app/a2slack/models.test.ts +72 -0
  201. package/examples/playground/app/a2slack/page.tsx +10 -0
  202. package/examples/playground/app/a2slack/scheduler/route.ts +5 -0
  203. package/examples/playground/app/a2slack/search/route.ts +40 -0
  204. package/examples/playground/app/a2slack/search-index.ts +108 -0
  205. package/examples/playground/app/a2slack/server.test.ts +315 -0
  206. package/examples/playground/app/a2slack/server.ts +55 -0
  207. package/examples/playground/app/a2slack/sessions.ts +50 -0
  208. package/examples/playground/app/a2slack/thread/route.ts +8 -0
  209. package/examples/playground/app/a2slack/ui/ChannelView.tsx +87 -0
  210. package/examples/playground/app/a2slack/ui/Composer.tsx +117 -0
  211. package/examples/playground/app/a2slack/ui/DotsShadow.tsx +42 -0
  212. package/examples/playground/app/a2slack/ui/Feed.tsx +157 -0
  213. package/examples/playground/app/a2slack/ui/InboxContext.tsx +63 -0
  214. package/examples/playground/app/a2slack/ui/InboxView.tsx +82 -0
  215. package/examples/playground/app/a2slack/ui/Menu.tsx +128 -0
  216. package/examples/playground/app/a2slack/ui/MessageRow.tsx +314 -0
  217. package/examples/playground/app/a2slack/ui/NameGate.tsx +35 -0
  218. package/examples/playground/app/a2slack/ui/SearchContext.tsx +146 -0
  219. package/examples/playground/app/a2slack/ui/SearchResults.tsx +97 -0
  220. package/examples/playground/app/a2slack/ui/Shell.tsx +34 -0
  221. package/examples/playground/app/a2slack/ui/Sidebar.tsx +199 -0
  222. package/examples/playground/app/a2slack/ui/ThreadPanel.tsx +134 -0
  223. package/examples/playground/app/a2slack/ui/useInbox.ts +71 -0
  224. package/examples/playground/app/agent/server.ts +3 -3
  225. package/examples/playground/app/chat/[chatId]/chat-client.tsx +1 -1
  226. package/examples/playground/app/chat/server.ts +45 -35
  227. package/examples/playground/app/components/demo-icons.tsx +7 -0
  228. package/examples/playground/app/components/demos.tsx +7 -0
  229. package/examples/playground/app/orders/[orderId]/order-client.tsx +2 -2
  230. package/examples/playground/app/orders/page.tsx +1 -1
  231. package/examples/playground/app/orders/server.ts +49 -30
  232. package/examples/playground/app/recovery/[recoveryId]/recovery-client.tsx +14 -15
  233. package/examples/playground/app/recovery/page.tsx +4 -4
  234. package/examples/playground/app/recovery/server.ts +23 -32
  235. package/examples/playground/drizzle.config.ts +14 -0
  236. package/examples/playground/lib/store.ts +1 -1
  237. package/examples/playground/next.config.ts +6 -1
  238. package/examples/playground/package.json +12 -1
  239. package/examples/playground/scripts/migrate.mjs +31 -0
  240. package/examples/playground/vercel.json +9 -0
  241. package/examples/playground/vitest.drills.config.ts +32 -0
  242. package/package.json +5 -2
  243. package/sql/postgres/drizzle-schema.ts +209 -0
  244. package/sql/postgres/schema.sql +227 -67
  245. package/src/actor-shared.ts +10 -2
  246. package/src/actor.ts +101 -71
  247. package/src/ai-agent.ts +162 -111
  248. package/src/ai-control-server.ts +8 -8
  249. package/src/ai-fx.ts +324 -82
  250. package/src/ai-harness.ts +17 -2
  251. package/src/ai-pi.ts +2 -2
  252. package/src/ai-server.ts +2 -2
  253. package/src/ai.ts +7 -7
  254. package/src/client.ts +19 -2
  255. package/src/contract.ts +1 -1
  256. package/src/deterministic-id.ts +27 -4
  257. package/src/errors.ts +8 -5
  258. package/src/idempotent-replay.ts +0 -1
  259. package/src/index.ts +1 -1
  260. package/src/internal.ts +57 -16
  261. package/src/otel.ts +1 -1
  262. package/src/postgres-schema.ts +98 -57
  263. package/src/presence-recovery.ts +18 -11
  264. package/src/presence-tombstones.ts +52 -0
  265. package/src/push-envelope.ts +20 -0
  266. package/src/runtime-consumer.ts +10 -0
  267. package/src/scheduler-task.ts +2 -2
  268. package/src/scheduler-vercel.ts +1 -1
  269. package/src/server.browser.ts +1 -1
  270. package/src/server.ts +819 -218
  271. package/src/session-socket.ts +1 -1
  272. package/src/store-codec.ts +66 -0
  273. package/src/store-memory.ts +604 -286
  274. package/src/store-postgres.ts +2006 -857
  275. package/src/store-presence-polling.ts +59 -34
  276. package/src/store-redis-core.ts +1961 -1333
  277. package/src/store-redis-notify.ts +76 -26
  278. package/src/store-redis.ts +2 -3
  279. package/src/store-sqlite.ts +915 -516
  280. package/src/store.ts +241 -102
  281. package/src/telemetry.ts +2 -1
  282. package/src/wire.ts +1 -0
  283. package/dist/actor-C7b-1arn.d.ts.map +0 -1
  284. package/dist/actor-shared-t7w8xIKP.js.map +0 -1
  285. package/dist/ai-harness-Clbg5ei7.js.map +0 -1
  286. package/dist/ai-mMiWul1T.js.map +0 -1
  287. package/dist/client-BhHLoNKF.js.map +0 -1
  288. package/dist/contract-BYKASlCV.js.map +0 -1
  289. package/dist/idempotent-replay-JdgMQRRm.js +0 -21
  290. package/dist/idempotent-replay-JdgMQRRm.js.map +0 -1
  291. package/dist/initial-snapshot-Bx-c0pDP.d.ts.map +0 -1
  292. package/dist/internal-CscSY7K_.js.map +0 -1
  293. package/dist/server-DYAATFuT.d.ts.map +0 -1
  294. package/dist/server-qyb5aJJG.js.map +0 -1
  295. package/dist/session-clear-C-QwTXV1.d.ts.map +0 -1
  296. package/dist/session-clear-DGI4jTQ5.js.map +0 -1
  297. package/dist/store-CyLUy86v.d.ts +0 -404
  298. package/dist/store-CyLUy86v.d.ts.map +0 -1
  299. package/dist/store-codec-DTG0Ftek.js +0 -10
  300. package/dist/store-codec-DTG0Ftek.js.map +0 -1
  301. package/dist/store-presence-polling-B1ixeqIS.js +0 -94
  302. package/dist/store-presence-polling-B1ixeqIS.js.map +0 -1
  303. package/dist/store-redis-notify-CM0AfLY0.js +0 -2544
  304. package/dist/store-redis-notify-CM0AfLY0.js.map +0 -1
  305. package/dist/stream-buffer-Cx7AAPGq.js +0 -23
  306. package/dist/stream-buffer-Cx7AAPGq.js.map +0 -1
  307. package/dist/telemetry-Cyfqo6Qt.d.ts.map +0 -1
  308. package/dist/wire-BKxH1vbP.js.map +0 -1
  309. package/docs/server/01-handlers.mdx +0 -227
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-clear-C-QwTXV1.d.ts","names":[],"sources":["../src/session-clear.ts"],"mappings":";;;cAOa;;KAGD,iBAAiB;EAC3B,aAAa;EACb"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-clear-DGI4jTQ5.js","names":[],"sources":["../src/errors.ts","../src/session-clear.ts"],"sourcesContent":["export type A2ServerErrorCode =\n | 'INVALID_PAYLOAD' // schema validation failed — thrown before anything is written\n | 'FORBIDDEN' // external ingress was denied by server.fetch authorization\n | 'UNKNOWN_EVENT_TYPE' // event type not in the machine's `events` map\n | 'PARTIAL_DUPLICATE_BATCH' // batch mixed already-appended and fresh events\n | 'SUPERSEDED_ATTEMPT' // handler append from an attempt a recovery claim or a clear replaced\n | 'SESSION_CLEARED' // a read or call reached across the session's latest clear\n | 'CLAIM_EXPIRED' // ctx.signal abort reason: the attempt's lease lapsed without renewal\n | 'STORE_UNAVAILABLE' // store backend failure — retryable, nothing was written\n | 'STORE_NOT_CONFIGURED' // no `store` in production, a missing peer dependency, or Postgres lacks A2's tables\n | 'UNKNOWN_PRESENCE_FIELD' // presence field not in the contract's `presence` map\n | 'PRESENCE_NOT_SUPPORTED' // contract declares presence but the store lacks the capability\n\nexport type A2ErrorCode =\n A2ServerErrorCode | 'TIMEOUT' | 'HTTP_ERROR' | 'CONNECTION_FAILED' | 'UNKNOWN'\n\nexport class A2Error extends Error {\n readonly code: A2ErrorCode\n /** e.g. the Standard Schema issues for INVALID_PAYLOAD */\n readonly details: unknown\n\n constructor(\n code: A2ErrorCode,\n message: string,\n options?: { details?: unknown; cause?: unknown },\n ) {\n super(\n message,\n options && 'cause' in options ? { cause: options.cause } : undefined,\n )\n this.name = 'A2Error'\n this.code = code\n this.details = options?.details\n }\n}\n\n/** A handler write whose attempt no longer owns its triggering event. */\nexport function supersededAttemptError(\n sessionId: string,\n cause: { index: number; attempt: number },\n): A2Error {\n return new A2Error(\n 'SUPERSEDED_ATTEMPT',\n `attempt ${cause.attempt} no longer owns event ${cause.index} in session '${sessionId}'`,\n )\n}\n\n/**\n * Wrap an arbitrary thrown value as STORE_UNAVAILABLE, preserving the\n * original as `cause`. A2Errors pass through untouched — they already\n * carry their own meaning.\n */\nexport function asStoreUnavailable(err: unknown): A2Error {\n if (err instanceof A2Error) return err\n return new A2Error('STORE_UNAVAILABLE', 'the store backend failed', {\n cause: err,\n })\n}\n\n/**\n * Throw from a handler to reject retrying: the failure is adjudicated\n * terminal immediately (dead-lettered on the first throw) instead of\n * consuming the ten-failure retry budget. For deterministic failures —\n * a guard that will refuse identically on every attempt — retrying is\n * waste and dead-lettering is the honest outcome. Matched by\n * `instanceof`, so subclasses carry domain meaning.\n */\nexport class NonRetriableError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n this.name = 'NonRetriableError'\n }\n}\n","import { A2Error } from './errors.ts'\nimport type { Event } from './store.ts'\n\n/** A2's own event types start with this; application contracts cannot. */\nexport const RESERVED_EVENT_PREFIX = 'a2.'\n\n/** Reserved type of the marker a clear appends. */\nexport const CLEAR_EVENT_TYPE = 'a2.cleared'\n\n/** The marker `session.stream()` yields where a clear ended a lifetime. */\nexport type SessionCleared = Event & {\n type: typeof CLEAR_EVENT_TYPE\n payload: null\n}\n\n/** Accepts any stream item, including presence patches and snapshots. */\nexport function isSessionCleared(item: object): item is SessionCleared {\n return (item as { type?: unknown }).type === CLEAR_EVENT_TYPE\n}\n\nexport function sessionClearedError(message: string): A2Error {\n return new A2Error('SESSION_CLEARED', message)\n}\n"],"mappings":";AAgBA,IAAa,UAAb,cAA6B,MAAM;CACjC;;CAEA;CAEA,YACE,MACA,SACA,SACA;EACA,MACE,SACA,WAAW,WAAW,UAAU,EAAE,OAAO,QAAQ,MAAM,IAAI,KAAA,CAC7D;EACA,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK,UAAU,SAAS;CAC1B;AACF;;AAGA,SAAgB,uBACd,WACA,OACS;CACT,OAAO,IAAI,QACT,sBACA,WAAW,MAAM,QAAQ,wBAAwB,MAAM,MAAM,eAAe,UAAU,EACxF;AACF;;;;;;AAOA,SAAgB,mBAAmB,KAAuB;CACxD,IAAI,eAAe,SAAS,OAAO;CACnC,OAAO,IAAI,QAAQ,qBAAqB,4BAA4B,EAClE,OAAO,IACT,CAAC;AACH;;;;;;;;;AAUA,IAAa,oBAAb,cAAuC,MAAM;CAC3C,YAAY,SAAiB,SAA+B;EAC1D,MAAM,SAAS,OAAO;EACtB,KAAK,OAAO;CACd;AACF;;;;ACjEA,MAAa,mBAAmB;;AAShC,SAAgB,iBAAiB,MAAsC;CACrE,OAAQ,KAA4B,SAAS;AAC/C;AAEA,SAAgB,oBAAoB,SAA0B;CAC5D,OAAO,IAAI,QAAQ,mBAAmB,OAAO;AAC/C"}
@@ -1,404 +0,0 @@
1
- import { p as PresencePatch } from "./reducer-CqA59Q6U.js";
2
- //#region src/store.d.ts
3
- /** A stored event, as the public API exposes it. */
4
- type Event = {
5
- id: string;
6
- type: string;
7
- payload: unknown;
8
- /** Position in the session's event log, from 1. */
9
- index: number;
10
- sessionId: string;
11
- createdAt: Date;
12
- };
13
- /** The handler dispatch whose append first persisted a child event. */
14
- type EventCause = {
15
- index: number;
16
- attempt: number;
17
- /** Size of one named handler append, used to reject truncated retries. */
18
- batchSize?: number;
19
- };
20
- /**
21
- * What the store persists: immutable event history, including its causal edge,
22
- * plus derived dispatch and failure bookkeeping. The bookkeeping is disposable;
23
- * the event and its cause are not.
24
- */
25
- type StoredEvent = Event & {
26
- /** Same-session handler dispatch that appended this event; null means root. */
27
- cause: EventCause | null;
28
- /** Session-scoped serial execution key resolved when the event is appended. */
29
- lane: string | null;
30
- /** Adapter clock time recorded by append settlement, completion, or manual skip; null while pending. */
31
- processedAt: Date | null;
32
- /** Dispatch attempt that completed this event; null without dispatch or while pending. */
33
- processedByAttempt: number | null;
34
- /** Exact ordered child ids atomically returned by the completing attempt. */
35
- returnedEventIds: string[] | null;
36
- /** Adapter clock time recorded by the first durable dispatch claim. */
37
- firstClaimedAt: Date | null;
38
- /** Adapter clock time recorded by the most recent durable dispatch claim. */
39
- lastClaimedAt: Date | null;
40
- /** Durable dispatch claims, including claims abandoned by hard kills. */
41
- attemptCount: number;
42
- /** Current dispatch holder; null when the event is not claimed. */
43
- claimHolder: string | null;
44
- /**
45
- * Adapter clock expiry for the current dispatch claim, or, with no holder,
46
- * the end of a failed attempt's retry hold.
47
- */
48
- claimExpiresAt: Date | null;
49
- /**
50
- * Failed attempts: caught handler failures, and lapsed claims a later claim
51
- * took over. This alone drives dead-lettering.
52
- */
53
- failureCount: number;
54
- /** Adapter clock time recorded by the most recent caught handler failure. */
55
- lastFailedAt: Date | null;
56
- /** Dispatch attempt that produced the most recent caught handler failure. */
57
- lastFailedAttempt: number | null;
58
- /** The last handler failure, stringified. */
59
- lastError: string | null;
60
- /** Adapter clock time recorded when dead-lettered; null otherwise. */
61
- failedAt: Date | null;
62
- /** Latest clear marker, on claimed events of a cleared session. */
63
- clearIndex?: number;
64
- };
65
- /**
66
- * One live presence value, as `A2Store.presence.read` returns it. The
67
- * row is the LWW unit — one participant's one field. `at` is the
68
- * sender's stamp, the LWW comparator. `expiresAt` is the storage's
69
- * own clock at the applied set plus its `ttlMs` — never derived from
70
- * the sender stamp; a row is live strictly before it.
71
- */
72
- type PresenceRow = {
73
- participant: string;
74
- field: string;
75
- value: unknown;
76
- seen: number;
77
- at: Date;
78
- expiresAt: Date;
79
- };
80
- /** One consistent cache-plus-tail read for a reducer fold. */
81
- type StoreStateRead = {
82
- /** The current head checkpoint, even when an older historical snapshot is selected. */
83
- headIndex: number | null;
84
- /** The greatest cached fold at or before the requested snapshot frontier. */
85
- snapshot: {
86
- index: number;
87
- state: unknown;
88
- } | null;
89
- /** Immutable events strictly after `snapshot.index`, or the full log on a miss. */
90
- events: Event[];
91
- /** Latest clear marker; omitted when the session was never cleared. */
92
- clearIndex?: number;
93
- };
94
- type StoreSnapshotWrite = {
95
- index: number;
96
- state: unknown;
97
- /** Unfinished trigger events that durably retain this exact checkpoint. */
98
- pinEventIndexes?: readonly number[];
99
- };
100
- type StoreStateReadRequest = {
101
- sessionId: string;
102
- throughIndex?: number;
103
- snapshotThroughIndex?: number;
104
- };
105
- /** The result of atomically claiming every currently eligible event. */
106
- type StoreClaimAvailableResult = {
107
- outcome: "claimed";
108
- events: StoredEvent[];
109
- } | {
110
- outcome: "busy";
111
- retryAt: Date;
112
- } | {
113
- outcome: "settled";
114
- };
115
- /** A completion may lose to a newer claim or an earlier completion. */
116
- type CompleteAttemptResult = {
117
- outcome: "completed";
118
- events: StoredEvent[];
119
- } | {
120
- outcome: "superseded";
121
- };
122
- /** The result of one claim-renewal heartbeat, both lists in append order. */
123
- type RenewClaimsResult = {
124
- /** Listed claims that remain owned by the holder. */
125
- renewed: number[];
126
- /** Listed claims whose event a newer attempt has durably taken. */
127
- superseded: number[];
128
- };
129
- /** The result of atomically recording a caught handler failure. */
130
- type FailAttemptResult = {
131
- outcome: "failed" | "dead_lettered" | "superseded";
132
- failureCount: number;
133
- };
134
- /** Input to `A2Store.append` — already validated by the machine. */
135
- type AppendEvent = {
136
- type: string;
137
- payload: unknown;
138
- /** Caller-supplied idempotency key; generated when absent. */
139
- id?: string;
140
- /** Internal causal edge supplied atomically by handler `session.append`. */
141
- cause?: EventCause;
142
- /** Session-scoped serial execution key resolved before persistence. */
143
- lane?: string;
144
- /** Internal hint: settle this event in the append transaction; no handler is registered. */
145
- settled?: true;
146
- };
147
- /** A handler-returned event with the deterministic id retries require. */
148
- type ReturnedEvent = AppendEvent & {
149
- id: string;
150
- };
151
- /** The rows written by an append and the session's pending state. */
152
- type StoreAppendResult = {
153
- events: StoredEvent[];
154
- /** Whether the session contains an event without a completion marker. */
155
- hasPending: boolean;
156
- };
157
- type StoreClearOptions = {
158
- sessionId: string;
159
- ifLastIndex?: number;
160
- /** The clearing handler's dispatch, fenced like a handler append. */
161
- cause?: EventCause;
162
- };
163
- type StoreClearResult = {
164
- cleared: boolean;
165
- /** The head after the operation. */
166
- index: number;
167
- /** The latest clear marker after the operation, or 0. */
168
- clearIndex: number;
169
- };
170
- type StoreReclaimResult = {
171
- deleted: number;
172
- done: boolean;
173
- };
174
- type StoreRedriveOptions = {
175
- sessionId: string;
176
- index: number;
177
- /** `retry` clears the dead letter; `skip` settles it without a handler. */
178
- action: "retry" | "skip";
179
- };
180
- type StoreRedriveResult = {
181
- /** Whether the event was dead-lettered and this operation resolved it. */
182
- redriven: boolean;
183
- /** Whether the session contains an event without a completion marker. */
184
- hasPending: boolean;
185
- };
186
- /**
187
- * An injectable clock. Adapters take one so tests can drive claim
188
- * expiry, failure timestamps, and (later) stuck-session detection
189
- * deterministically — against real storage, no mocking.
190
- */
191
- type Clock = {
192
- now(): Date;
193
- };
194
- /** An injectable id source for generated event ids. */
195
- type IdSource = () => string;
196
- interface A2Store {
197
- /**
198
- * Accepts a batch; the batch is atomic — one transaction, consecutive
199
- * `index`es, all-or-nothing. The idempotency key covers the whole
200
- * operation, not each item: if *every* event's `id` already exists in
201
- * this session, this is a retry of a committed batch whose ack was
202
- * lost — return the existing rows as success. If only *some* ids
203
- * exist, the caller mixed an already-sent batch with fresh events —
204
- * always a caller bug — so throw `A2Error('PARTIAL_DUPLICATE_BATCH')`.
205
- * Events carrying `settled: true` get `processedAt` in this same atomic
206
- * operation, with no dispatch claim or `processedByAttempt`. The result's
207
- * `hasPending` reflects the whole session in the same atomic operation,
208
- * including older events and idempotent retries.
209
- *
210
- * An event carrying `cause` is a handler append, fenced by attempt
211
- * currency: accept it only while `cause.attempt` is still the parent
212
- * event's latest attempt and the parent is not dead-lettered; otherwise
213
- * throw `A2Error('SUPERSEDED_ATTEMPT')` and write nothing. The check is
214
- * part of this atomic operation and must serialize against a concurrent
215
- * `claimAvailable` — an unlocked read of the parent admits write skew.
216
- * The idempotent-replay path runs first, so a batch whose ids all exist
217
- * replays regardless of the current attempt.
218
- *
219
- * Clearing stores (a2-implementation.md §17.2) fence one level earlier:
220
- * a `cause` at or below the latest clear marker throws
221
- * `SUPERSEDED_ATTEMPT`, an `originIndex` there throws `SESSION_CLEARED`,
222
- * and ids whose rows lie below the marker are free to reuse.
223
- */
224
- append(sessionId: string, events: AppendEvent[], options?: {
225
- originIndex?: number;
226
- }): Promise<StoreAppendResult>;
227
- /**
228
- * Optional with `reclaim`. Serialized with `append`: checks
229
- * `ifLastIndex` against the head and the latest marker, then appends a
230
- * settled clear marker at the next index without touching existing
231
- * rows. Afterwards every event at or below the marker is superseded.
232
- */
233
- clear?(options: StoreClearOptions): Promise<StoreClearResult>;
234
- /**
235
- * Deletes one bounded batch of rows below the latest clear marker, with
236
- * their bookkeeping, id records, and cached folds. `done` once nothing
237
- * remains below it. Never waits on a lock that other operations hold.
238
- */
239
- reclaim?(sessionId: string): Promise<StoreReclaimResult>;
240
- /**
241
- * Optional with `redrive`. The session's dead-lettered events above the
242
- * latest clear marker, oldest first.
243
- */
244
- deadLetters?(sessionId: string): Promise<StoredEvent[]>;
245
- /**
246
- * Optional with `deadLetters`. Atomically resolves one dead-lettered event
247
- * above the latest clear marker; any other event is untouched and reports
248
- * `redriven: false`. `retry` clears `failedAt` and `failureCount`, so the
249
- * event is claimable again with a fresh failure budget, keeping its claim
250
- * history and last failure. `skip` records `processedAt` with no
251
- * `processedByAttempt` or `returnedEventIds` and exposes the next event in
252
- * its lane. Both serialize with `claimAvailable` and the handler-append
253
- * parent fence; `skip` also serializes with lane promotion in `append` and
254
- * `completeAttempt`. `hasPending` is read in the same step.
255
- */
256
- redrive?(options: StoreRedriveOptions): Promise<StoreRedriveResult>;
257
- /** Events for one session, oldest first. Bounds form `(afterIndex, throughIndex]`. */
258
- read(sessionId: string, opts?: {
259
- afterIndex?: number;
260
- throughIndex?: number;
261
- }): Promise<StoredEvent[]>;
262
- /** Public history without dispatch metadata; core falls back to read when absent. */
263
- readHistory?(sessionId: string, opts?: {
264
- afterIndex?: number;
265
- throughIndex?: number;
266
- }): Promise<Event[]>;
267
- /**
268
- * Atomically claims every eligible pending event. Unlaned events are all
269
- * independently eligible. Within a lane, only the lowest-index unfinished
270
- * event is eligible. A live claim produces `busy` only when it is the sole
271
- * remaining obstacle to actionable work. Claimed events are returned in event-log
272
- * order. Excluded rows remain lane barriers.
273
- */
274
- claimAvailable(options: {
275
- sessionId: string;
276
- holder: string;
277
- ttlMs: number;
278
- expiresAtMs?: number;
279
- excludeIndexes?: readonly number[];
280
- /**
281
- * Taking over a lapsed claim (one whose holder is still recorded, never
282
- * completed or failed) adds one to `failureCount`. When that reaches
283
- * `maxFailures`, the event dead-letters instead of being claimed: it
284
- * comes back in `events` with `failedAt` set and no claim. Its
285
- * `attemptCount` still advances, fencing the lapsed attempt, and its
286
- * `lastFailedAttempt` is unchanged.
287
- */
288
- maxFailures?: number;
289
- }): Promise<StoreClaimAvailableResult>;
290
- /**
291
- * Renews the listed live claims still owned by `holder`. Each listed claim
292
- * carries the attempt ordinal the holder owns. `renewed` lists the claims
293
- * that remain owned after the operation; `superseded` lists the claims
294
- * whose event's `attemptCount` has durably passed the listed attempt. An
295
- * expired claim no successor has taken appears in neither list — its
296
- * attempt may still complete (`completeAttempt` is the fence), so it is
297
- * not reported as lost. Renewal never revives an expired claim.
298
- */
299
- renewClaims(options: {
300
- sessionId: string;
301
- holder: string;
302
- claims: readonly {
303
- index: number;
304
- attempt: number;
305
- }[];
306
- ttlMs: number;
307
- expiresAtMs?: number;
308
- }): Promise<RenewClaimsResult>;
309
- /**
310
- * Atomically completes one current attempt and appends its returned events.
311
- * Retrying a committed completion with the same attempt and deterministic
312
- * child ids returns the existing children. A stale attempt never appends.
313
- */
314
- completeAttempt(options: {
315
- sessionId: string;
316
- index: number;
317
- attempt: number;
318
- events: ReturnedEvent[];
319
- }): Promise<CompleteAttemptResult>;
320
- /**
321
- * Atomically records a caught failure for one claimed attempt. A stale
322
- * attempt cannot poison a processed event or a newer dispatch. Accepted
323
- * failures record the operation's clock time. A failure that does not
324
- * dead-letter releases the claim and, with `retryAfterMs`, keeps the event
325
- * unclaimable for that long: its claim expiry is set with no holder, so
326
- * `claimAvailable` reports it `busy` until then.
327
- */
328
- failAttempt(options: {
329
- sessionId: string;
330
- index: number;
331
- attempt: number;
332
- error: string;
333
- maxFailures: number;
334
- retryAfterMs?: number;
335
- }): Promise<FailAttemptResult>;
336
- /**
337
- * Reads a reducer snapshot and its event tail as one consistent adapter
338
- * operation. On a cache miss, `snapshot` is null and `events` is the full
339
- * log. The snapshot is untrusted; core may reject it and issue a full
340
- * `read()` when its state schema no longer accepts the cached value.
341
- * Operational failures propagate without falling back to a full-log read.
342
- */
343
- readState(sessionId: string, reducerName: string, options?: {
344
- throughIndex?: number;
345
- snapshotThroughIndex?: number;
346
- }): Promise<StoreStateRead>;
347
- /**
348
- * Optional batched `readState` — one consistent snapshot-plus-tail read
349
- * per session id, aligned positionally with the input (duplicates
350
- * allowed). Each element has its own frontier; the batch makes no
351
- * cross-session consistency claim. Core falls back to parallel
352
- * `readState` calls when absent.
353
- */
354
- readStates?(requests: readonly StoreStateReadRequest[], reducerName: string): Promise<StoreStateRead[]>;
355
- /**
356
- * Atomically writes disposable reducer checkpoints. The greatest index
357
- * advances the head cache. Older checkpoints survive only when at least one
358
- * listed trigger event is still unfinished; completion and dead-lettering
359
- * release that event's pins and collect unreferenced historical checkpoints.
360
- */
361
- putSnapshots(sessionId: string, reducerName: string, snapshots: readonly StoreSnapshotWrite[]): Promise<void>;
362
- /**
363
- * Optional ephemeral-plane capability (specs/a2-implementation.md
364
- * §15.1) — optional like snapshots are. Values arrive already
365
- * validated by core; adapters store them opaquely. Presence never
366
- * touches the event log: no index, no history row, no recovery arm.
367
- */
368
- presence?: {
369
- /**
370
- * Field-wise last-writer-wins merge of one participant's values:
371
- * a field whose existing row has a strictly newer `at` (the
372
- * sender's stamp) is left untouched; `null` deletes the row. Every
373
- * applied write refreshes that field's expiry to the storage's own
374
- * clock plus `ttlMs` — the sender stamp orders writes but never
375
- * anchors their lifetime.
376
- */
377
- set(ns: string, participant: string, values: Record<string, unknown | null>, meta: {
378
- seen: number;
379
- at: Date;
380
- ttlMs: number;
381
- }): Promise<void>;
382
- /** The current map, pruned of rows at or past their `expiresAt`. */
383
- read(ns: string): Promise<PresenceRow[]>;
384
- /**
385
- * Adapter-managed patch delivery. Without it, live feeds re-read
386
- * presence on their poll cadence. HTTP Redis uses adaptive polling
387
- * here when its endpoint does not support subscriptions.
388
- */
389
- subscribe?(ns: string, onPatch: (patch: PresencePatch) => void): () => void;
390
- };
391
- /**
392
- * A live feed of one session's events, starting after `startAfter`
393
- * (exclusive). Transport is the backend's choice — in-process pub/sub,
394
- * polling, LISTEN/NOTIFY — callers never branch on which. The iterable
395
- * ends when the consumer calls `return()` (e.g. a disconnecting SSE
396
- * client) and must deliver events appended after subscription.
397
- */
398
- stream(sessionId: string, opts?: {
399
- startAfter?: number;
400
- }): AsyncIterable<Event>;
401
- }
402
- //#endregion
403
- export { EventCause as a, PresenceRow as c, StoreStateRead as d, StoredEvent as f, Event as i, StoreAppendResult as l, AppendEvent as n, FailAttemptResult as o, Clock as r, IdSource as s, A2Store as t, StoreClaimAvailableResult as u };
404
- //# sourceMappingURL=store-CyLUy86v.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"store-CyLUy86v.d.ts","names":[],"sources":["../src/store.ts"],"mappings":";;;KAaY;EACV;EACA;EACA;;EAEA;EACA;EACA,WAAW;;;KAID;EACV;EACA;;EAEA;;;;;;;KAQU,cAAc;;EAExB,OAAO;;EAEP;;EAEA,aAAa;;EAEb;;EAEA;;EAEA,gBAAgB;;EAEhB,eAAe;;EAEf;;EAEA;;;;;EAKA,gBAAgB;;;;;EAKhB;;EAEA,cAAc;;EAEd;;EAEA;;EAEA,UAAU;;EAEV;;;;;;;;;KAUU;EACV;EACA;EACA;EACA;EACA,IAAI;EACJ,WAAW;;;KAID;;EAEV;;EAEA;IAAY;IAAe;;;EAE3B,QAAQ;;EAER;;KAGU;EACV;EACA;;EAEA;;KAGU;EACV;EACA;EACA;;;KAGU;EACN;EAAoB,QAAQ;;EAC5B;EAAiB,SAAS;;EAC1B;;;KAGM;EACR;EAAsB,QAAQ;;EAAoB;;;KAG1C;;EAEV;;EAEA;;;KAIU;EACV;EACA;;;KAIU;EACV;EACA;;EAEA;;EAEA,QAAQ;;EAER;;EAEA;;;KAIU,gBAAgB;EAAgB;;;KAGhC;EACV,QAAQ;;EAER;;KAGU;EACV;EACA;;EAEA,QAAQ;;KAGE;EACV;;EAEA;;EAEA;;KAGU;EAAuB;EAAiB;;KAExC;EACV;EACA;;EAEA;;KAGU;;EAEV;;EAEA;;;;;;;KAQU;EACV,OAAO;;;KAIG;UAQK;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4Bf,OACE,mBACA,QAAQ,eACR;IAAY;MACX,QAAQ;;;;;;;EAQX,OAAO,SAAS,oBAAoB,QAAQ;;;;;;EAO5C,SAAS,oBAAoB,QAAQ;;;;;EAMrC,aAAa,oBAAoB,QAAQ;;;;;;;;;;;;EAazC,SAAS,SAAS,sBAAsB,QAAQ;;EAGhD,KACE,mBACA;IAAS;IAAqB;MAC7B,QAAQ;;EAGX,aACE,mBACA;IAAS;IAAqB;MAC7B,QAAQ;;;;;;;;EASX,eAAe;IACb;IACA;IACA;IACA;IACA;;;;;;;;;IASA;MACE,QAAQ;;;;;;;;;;EAWZ,YAAY;IACV;IACA;IACA;MAAmB;MAAe;;IAClC;IACA;MACE,QAAQ;;;;;;EAOZ,gBAAgB;IACd;IACA;IACA;IACA,QAAQ;MACN,QAAQ;;;;;;;;;EAUZ,YAAY;IACV;IACA;IACA;IACA;IACA;IACA;MACE,QAAQ;;;;;;;;EASZ,UACE,mBACA,qBACA;IAAY;IAAuB;MAClC,QAAQ;;;;;;;;EASX,YACE,mBAAmB,yBACnB,sBACC,QAAQ;;;;;;;EAQX,aACE,mBACA,qBACA,oBAAoB,uBACnB;;;;;;;EAQH;;;;;;;;;IASE,IACE,YACA,qBACA,QAAQ,gCACR;MAAQ;MAAc,IAAI;MAAM;QAC/B;;IAGH,KAAK,aAAa,QAAQ;;;;;;IAO1B,WAAW,YAAY,UAAU,OAAO;;;;;;;;;EAU1C,OACE,mBACA;IAAS;MACR,cAAc"}
@@ -1,10 +0,0 @@
1
- //#region src/store-codec.ts
2
- const decodeReturnedEventIds = (value) => {
3
- const decoded = typeof value === "string" ? JSON.parse(value) : value;
4
- if (!Array.isArray(decoded) || decoded.some((eventId) => typeof eventId !== "string")) throw new TypeError("stored event has invalid returned event ids");
5
- return decoded;
6
- };
7
- //#endregion
8
- export { decodeReturnedEventIds as t };
9
-
10
- //# sourceMappingURL=store-codec-DTG0Ftek.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"store-codec-DTG0Ftek.js","names":[],"sources":["../src/store-codec.ts"],"sourcesContent":["export const decodeReturnedEventIds = (value: unknown): string[] => {\n const decoded: unknown = typeof value === 'string' ? JSON.parse(value) : value\n if (\n !Array.isArray(decoded) ||\n decoded.some((eventId) => typeof eventId !== 'string')\n ) {\n throw new TypeError('stored event has invalid returned event ids')\n }\n return decoded\n}\n"],"mappings":";AAAA,MAAa,0BAA0B,UAA6B;CAClE,MAAM,UAAmB,OAAO,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI;CACzE,IACE,CAAC,MAAM,QAAQ,OAAO,KACtB,QAAQ,MAAM,YAAY,OAAO,YAAY,QAAQ,GAErD,MAAM,IAAI,UAAU,6CAA6C;CAEnE,OAAO;AACT"}
@@ -1,94 +0,0 @@
1
- import { i as POLL_TIMINGS } from "./internal-CscSY7K_.js";
2
- import { t as defaultSleep } from "./store-polling-7WJV0YWP.js";
3
- //#region src/store-presence-polling.ts
4
- const key = ({ participant, field }) => JSON.stringify([participant, field]);
5
- function pollPresence({ read, deliver, sleep = defaultSleep }) {
6
- let stopped = false;
7
- let pending;
8
- let interval = Math.min(POLL_TIMINGS.activeFloorMs, POLL_TIMINGS.idleCeilingMs);
9
- let version = 0;
10
- const seen = /* @__PURE__ */ new Map();
11
- const activate = () => {
12
- version += 1;
13
- interval = Math.min(POLL_TIMINGS.activeFloorMs, POLL_TIMINGS.idleCeilingMs);
14
- pending?.cancel();
15
- };
16
- const ready = read().then((rows) => {
17
- if (stopped) return;
18
- for (const row of rows) seen.set(key(row), row);
19
- }).catch(() => void 0);
20
- const run = async () => {
21
- await ready;
22
- for (;;) {
23
- if (stopped) return;
24
- const before = version;
25
- pending = sleep(interval);
26
- await pending.promise;
27
- if (stopped) return;
28
- try {
29
- const reading = version;
30
- const rows = await read();
31
- if (stopped) return;
32
- if (version !== reading) continue;
33
- const live = /* @__PURE__ */ new Set();
34
- let changed = false;
35
- for (const row of rows) {
36
- const id = key(row);
37
- live.add(id);
38
- const prior = seen.get(id);
39
- seen.set(id, row);
40
- if (prior?.seen === row.seen && prior.at.getTime() === row.at.getTime() && JSON.stringify(prior.value) === JSON.stringify(row.value)) continue;
41
- changed = true;
42
- deliver({
43
- participant: row.participant,
44
- values: { [row.field]: row.value },
45
- seen: row.seen,
46
- at: row.at
47
- });
48
- }
49
- for (const [id, row] of seen) {
50
- if (live.has(id)) continue;
51
- seen.delete(id);
52
- changed = true;
53
- deliver({
54
- participant: row.participant,
55
- values: { [row.field]: null },
56
- seen: row.seen,
57
- at: /* @__PURE__ */ new Date()
58
- });
59
- }
60
- if (changed) activate();
61
- else if (version === before) interval = Math.min(interval * 2, POLL_TIMINGS.idleCeilingMs);
62
- } catch {
63
- interval = POLL_TIMINGS.idleCeilingMs;
64
- }
65
- }
66
- };
67
- run();
68
- return {
69
- ready,
70
- wake: activate,
71
- update(patch) {
72
- for (const [field, value] of Object.entries(patch.values)) seen.set(key({
73
- participant: patch.participant,
74
- field
75
- }), {
76
- participant: patch.participant,
77
- field,
78
- value,
79
- seen: patch.seen,
80
- at: patch.at
81
- });
82
- activate();
83
- },
84
- stop() {
85
- stopped = true;
86
- pending?.cancel();
87
- seen.clear();
88
- }
89
- };
90
- }
91
- //#endregion
92
- export { pollPresence as t };
93
-
94
- //# sourceMappingURL=store-presence-polling-B1ixeqIS.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"store-presence-polling-B1ixeqIS.js","names":[],"sources":["../src/store-presence-polling.ts"],"sourcesContent":["import type { PresencePatch } from './contract.ts'\nimport { POLL_TIMINGS } from './internal.ts'\nimport { defaultSleep, type Sleeper } from './store-polling.ts'\nimport type { PresenceRow } from './store.ts'\n\nconst key = ({\n participant,\n field,\n}: Pick<PresenceRow, 'participant' | 'field'>): string =>\n JSON.stringify([participant, field])\n\nexport function pollPresence({\n read,\n deliver,\n sleep = defaultSleep,\n}: {\n read: () => Promise<PresenceRow[]>\n deliver: (patch: PresencePatch) => void\n sleep?: (ms: number) => Sleeper\n}): {\n ready: Promise<void>\n update(patch: PresencePatch): void\n wake(): void\n stop(): void\n} {\n let stopped = false\n let pending: Sleeper | undefined\n let interval = Math.min(\n POLL_TIMINGS.activeFloorMs,\n POLL_TIMINGS.idleCeilingMs,\n )\n let version = 0\n const seen = new Map<string, Omit<PresenceRow, 'expiresAt'>>()\n const activate = (): void => {\n version += 1\n interval = Math.min(POLL_TIMINGS.activeFloorMs, POLL_TIMINGS.idleCeilingMs)\n pending?.cancel()\n }\n const ready = read()\n .then((rows) => {\n if (stopped) return\n for (const row of rows) seen.set(key(row), row)\n return undefined\n })\n // Seeding is best effort; foreground snapshots still report read errors.\n .catch(() => undefined)\n\n const run = async (): Promise<void> => {\n await ready\n for (;;) {\n if (stopped) return\n const before = version\n pending = sleep(interval)\n // oxlint-disable-next-line no-await-in-loop -- adaptive presence polling\n await pending.promise\n if (stopped) return\n try {\n const reading = version\n // oxlint-disable-next-line no-await-in-loop -- read each new presence snapshot\n const rows = await read()\n if (stopped) return\n if (version !== reading) continue\n const live = new Set<string>()\n let changed = false\n for (const row of rows) {\n const id = key(row)\n live.add(id)\n const prior = seen.get(id)\n seen.set(id, row)\n if (\n prior?.seen === row.seen &&\n prior.at.getTime() === row.at.getTime() &&\n JSON.stringify(prior.value) === JSON.stringify(row.value)\n )\n continue\n changed = true\n deliver({\n participant: row.participant,\n values: { [row.field]: row.value },\n seen: row.seen,\n at: row.at,\n })\n }\n for (const [id, row] of seen) {\n if (live.has(id)) continue\n seen.delete(id)\n changed = true\n deliver({\n participant: row.participant,\n values: { [row.field]: null },\n seen: row.seen,\n at: new Date(),\n })\n }\n if (changed) activate()\n else if (version === before)\n interval = Math.min(interval * 2, POLL_TIMINGS.idleCeilingMs)\n } catch {\n interval = POLL_TIMINGS.idleCeilingMs\n }\n }\n }\n void run()\n return {\n ready,\n wake: activate,\n update(patch) {\n for (const [field, value] of Object.entries(patch.values)) {\n seen.set(key({ participant: patch.participant, field }), {\n participant: patch.participant,\n field,\n value,\n seen: patch.seen,\n at: patch.at,\n })\n }\n activate()\n },\n stop() {\n stopped = true\n pending?.cancel()\n seen.clear()\n },\n }\n}\n"],"mappings":";;;AAKA,MAAM,OAAO,EACX,aACA,YAEA,KAAK,UAAU,CAAC,aAAa,KAAK,CAAC;AAErC,SAAgB,aAAa,EAC3B,MACA,SACA,QAAQ,gBAUR;CACA,IAAI,UAAU;CACd,IAAI;CACJ,IAAI,WAAW,KAAK,IAClB,aAAa,eACb,aAAa,aACf;CACA,IAAI,UAAU;CACd,MAAM,uBAAO,IAAI,IAA4C;CAC7D,MAAM,iBAAuB;EAC3B,WAAW;EACX,WAAW,KAAK,IAAI,aAAa,eAAe,aAAa,aAAa;EAC1E,SAAS,OAAO;CAClB;CACA,MAAM,QAAQ,KAAK,CAAC,CACjB,MAAM,SAAS;EACd,IAAI,SAAS;EACb,KAAK,MAAM,OAAO,MAAM,KAAK,IAAI,IAAI,GAAG,GAAG,GAAG;CAEhD,CAAC,CAAC,CAED,YAAY,KAAA,CAAS;CAExB,MAAM,MAAM,YAA2B;EACrC,MAAM;EACN,SAAS;GACP,IAAI,SAAS;GACb,MAAM,SAAS;GACf,UAAU,MAAM,QAAQ;GAExB,MAAM,QAAQ;GACd,IAAI,SAAS;GACb,IAAI;IACF,MAAM,UAAU;IAEhB,MAAM,OAAO,MAAM,KAAK;IACxB,IAAI,SAAS;IACb,IAAI,YAAY,SAAS;IACzB,MAAM,uBAAO,IAAI,IAAY;IAC7B,IAAI,UAAU;IACd,KAAK,MAAM,OAAO,MAAM;KACtB,MAAM,KAAK,IAAI,GAAG;KAClB,KAAK,IAAI,EAAE;KACX,MAAM,QAAQ,KAAK,IAAI,EAAE;KACzB,KAAK,IAAI,IAAI,GAAG;KAChB,IACE,OAAO,SAAS,IAAI,QACpB,MAAM,GAAG,QAAQ,MAAM,IAAI,GAAG,QAAQ,KACtC,KAAK,UAAU,MAAM,KAAK,MAAM,KAAK,UAAU,IAAI,KAAK,GAExD;KACF,UAAU;KACV,QAAQ;MACN,aAAa,IAAI;MACjB,QAAQ,GAAG,IAAI,QAAQ,IAAI,MAAM;MACjC,MAAM,IAAI;MACV,IAAI,IAAI;KACV,CAAC;IACH;IACA,KAAK,MAAM,CAAC,IAAI,QAAQ,MAAM;KAC5B,IAAI,KAAK,IAAI,EAAE,GAAG;KAClB,KAAK,OAAO,EAAE;KACd,UAAU;KACV,QAAQ;MACN,aAAa,IAAI;MACjB,QAAQ,GAAG,IAAI,QAAQ,KAAK;MAC5B,MAAM,IAAI;MACV,oBAAI,IAAI,KAAK;KACf,CAAC;IACH;IACA,IAAI,SAAS,SAAS;SACjB,IAAI,YAAY,QACnB,WAAW,KAAK,IAAI,WAAW,GAAG,aAAa,aAAa;GAChE,QAAQ;IACN,WAAW,aAAa;GAC1B;EACF;CACF;CACA,IAAS;CACT,OAAO;EACL;EACA,MAAM;EACN,OAAO,OAAO;GACZ,KAAK,MAAM,CAAC,OAAO,UAAU,OAAO,QAAQ,MAAM,MAAM,GACtD,KAAK,IAAI,IAAI;IAAE,aAAa,MAAM;IAAa;GAAM,CAAC,GAAG;IACvD,aAAa,MAAM;IACnB;IACA;IACA,MAAM,MAAM;IACZ,IAAI,MAAM;GACZ,CAAC;GAEH,SAAS;EACX;EACA,OAAO;GACL,UAAU;GACV,SAAS,OAAO;GAChB,KAAK,MAAM;EACb;CACF;AACF"}