experimental-a2 0.16.1 → 0.18.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 (406) hide show
  1. package/CHANGELOG.md +373 -0
  2. package/README.md +1 -1
  3. package/dist/{actor-ohPC-81x.d.ts → actor-Bjce9_5U.d.ts} +21 -11
  4. package/dist/actor-Bjce9_5U.d.ts.map +1 -0
  5. package/dist/actor-client.d.ts +2 -5
  6. package/dist/actor-client.d.ts.map +1 -1
  7. package/dist/actor-client.js +13 -4
  8. package/dist/actor-client.js.map +1 -1
  9. package/dist/actor-react.d.ts +5 -3
  10. package/dist/actor-react.d.ts.map +1 -1
  11. package/dist/actor-react.js +20 -10
  12. package/dist/actor-react.js.map +1 -1
  13. package/dist/{actor-shared-B5tJfzt-.js → actor-shared-t7w8xIKP.js} +12 -7
  14. package/dist/actor-shared-t7w8xIKP.js.map +1 -0
  15. package/dist/actor.d.ts +1 -1
  16. package/dist/actor.js +42 -23
  17. package/dist/actor.js.map +1 -1
  18. package/dist/{ai-DgOBltJ_.js → ai-BpOGm-zB.js} +621 -216
  19. package/dist/ai-BpOGm-zB.js.map +1 -0
  20. package/dist/{ai-CrEf6p_W.d.ts → ai-DrUaMyRt.d.ts} +114 -100
  21. package/dist/ai-DrUaMyRt.d.ts.map +1 -0
  22. package/dist/ai-client.d.ts +27 -0
  23. package/dist/ai-client.d.ts.map +1 -0
  24. package/dist/ai-client.js +29 -0
  25. package/dist/ai-client.js.map +1 -0
  26. package/dist/ai-fx.browser.d.ts +1 -0
  27. package/dist/ai-fx.browser.js +6 -0
  28. package/dist/ai-fx.browser.js.map +1 -0
  29. package/dist/ai-fx.d.ts +10 -0
  30. package/dist/ai-fx.d.ts.map +1 -0
  31. package/dist/ai-fx.js +634 -0
  32. package/dist/ai-fx.js.map +1 -0
  33. package/dist/ai-harness-BuLh_EYi.js +273 -0
  34. package/dist/ai-harness-BuLh_EYi.js.map +1 -0
  35. package/dist/ai-harness-DvsPeJeB.d.ts +26 -0
  36. package/dist/ai-harness-DvsPeJeB.d.ts.map +1 -0
  37. package/dist/ai-pi.browser.d.ts +1 -0
  38. package/dist/ai-pi.browser.js +6 -0
  39. package/dist/ai-pi.browser.js.map +1 -0
  40. package/dist/ai-pi.d.ts +17 -0
  41. package/dist/ai-pi.d.ts.map +1 -0
  42. package/dist/ai-pi.js +904 -0
  43. package/dist/ai-pi.js.map +1 -0
  44. package/dist/ai-react.d.ts +96 -0
  45. package/dist/ai-react.d.ts.map +1 -0
  46. package/dist/ai-react.js +142 -0
  47. package/dist/ai-react.js.map +1 -0
  48. package/dist/ai-server.browser.js +2 -2
  49. package/dist/ai-server.browser.js.map +1 -1
  50. package/dist/ai-server.d.ts +109 -43
  51. package/dist/ai-server.d.ts.map +1 -1
  52. package/dist/ai-server.js +526 -283
  53. package/dist/ai-server.js.map +1 -1
  54. package/dist/ai.d.ts +2 -2
  55. package/dist/ai.js +2 -2
  56. package/dist/bounded-cache-CPHWF-8h.js +41 -0
  57. package/dist/bounded-cache-CPHWF-8h.js.map +1 -0
  58. package/dist/{client-BYzHjkwU.js → client-BReKqwZC.js} +447 -80
  59. package/dist/client-BReKqwZC.js.map +1 -0
  60. package/dist/{client-CzyacQpJ.d.ts → client-h_DKFAjj.d.ts} +14 -13
  61. package/dist/client-h_DKFAjj.d.ts.map +1 -0
  62. package/dist/client.d.ts +4 -2
  63. package/dist/client.js +1 -1
  64. package/dist/{contract-CKRg_E4q.js → contract-BYKASlCV.js} +12 -21
  65. package/dist/contract-BYKASlCV.js.map +1 -0
  66. package/dist/{idempotent-replay-DVOlyYbx.js → idempotent-replay-JdgMQRRm.js} +2 -2
  67. package/dist/{idempotent-replay-DVOlyYbx.js.map → idempotent-replay-JdgMQRRm.js.map} +1 -1
  68. package/dist/index.d.ts +6 -5
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +4 -3
  71. package/dist/{errors-DvhSXnxk.d.ts → initial-snapshot-Bx-c0pDP.d.ts} +7 -3
  72. package/dist/initial-snapshot-Bx-c0pDP.d.ts.map +1 -0
  73. package/dist/{internal-Dq2qYxou.js → internal-B2T3U4Rq.js} +29 -2
  74. package/dist/internal-B2T3U4Rq.js.map +1 -0
  75. package/dist/otel.d.ts +1 -1
  76. package/dist/react-BBXgHWFc.d.ts +86 -0
  77. package/dist/react-BBXgHWFc.d.ts.map +1 -0
  78. package/dist/react.d.ts +2 -122
  79. package/dist/react.js +107 -100
  80. package/dist/react.js.map +1 -1
  81. package/dist/reducer-BAXc8JyF.js +87 -0
  82. package/dist/reducer-BAXc8JyF.js.map +1 -0
  83. package/dist/{reducer-otzHjuJj.d.ts → reducer-CqA59Q6U.d.ts} +46 -30
  84. package/dist/reducer-CqA59Q6U.d.ts.map +1 -0
  85. package/dist/reducer-runtime-DQwz_J59.js +28 -0
  86. package/dist/reducer-runtime-DQwz_J59.js.map +1 -0
  87. package/dist/scheduler-qstash.d.ts +3 -3
  88. package/dist/scheduler-qstash.d.ts.map +1 -1
  89. package/dist/scheduler-qstash.js +33 -10
  90. package/dist/scheduler-qstash.js.map +1 -1
  91. package/dist/{scheduler-task-BpzhPnRS.js → scheduler-task-X1SToDjP.js} +18 -3
  92. package/dist/scheduler-task-X1SToDjP.js.map +1 -0
  93. package/dist/scheduler-vercel.d.ts +4 -9
  94. package/dist/scheduler-vercel.d.ts.map +1 -1
  95. package/dist/scheduler-vercel.js +25 -44
  96. package/dist/scheduler-vercel.js.map +1 -1
  97. package/dist/{server-BD5ckxZb.js → server-Dw_k_7kO.js} +904 -219
  98. package/dist/server-Dw_k_7kO.js.map +1 -0
  99. package/dist/{server-DbD7IJVK.d.ts → server-En7cbi3v.d.ts} +116 -26
  100. package/dist/server-En7cbi3v.d.ts.map +1 -0
  101. package/dist/server.d.ts +4 -4
  102. package/dist/server.js +2 -2
  103. package/dist/session-clear-Bo-XTFEy.d.ts +12 -0
  104. package/dist/session-clear-Bo-XTFEy.d.ts.map +1 -0
  105. package/dist/{errors-DCk6ch5n.js → session-clear-DGI4jTQ5.js} +17 -2
  106. package/dist/session-clear-DGI4jTQ5.js.map +1 -0
  107. package/dist/{store-DyZM6fS5.d.ts → store-Djdv0bnZ.d.ts} +73 -3
  108. package/dist/store-Djdv0bnZ.d.ts.map +1 -0
  109. package/dist/store-N8PXxDAS.js.map +1 -1
  110. package/dist/store-memory.d.ts +1 -1
  111. package/dist/store-memory.d.ts.map +1 -1
  112. package/dist/store-memory.js +205 -66
  113. package/dist/store-memory.js.map +1 -1
  114. package/dist/{store-polling-CmxUbV93.js → store-polling-B5FcwJfo.js} +21 -4
  115. package/dist/store-polling-B5FcwJfo.js.map +1 -0
  116. package/dist/store-postgres.d.ts +1 -1
  117. package/dist/store-postgres.d.ts.map +1 -1
  118. package/dist/store-postgres.js +450 -108
  119. package/dist/store-postgres.js.map +1 -1
  120. package/dist/{store-presence-polling-C7-XZyW9.js → store-presence-polling-BAwS8RWn.js} +3 -3
  121. package/dist/{store-presence-polling-C7-XZyW9.js.map → store-presence-polling-BAwS8RWn.js.map} +1 -1
  122. package/dist/store-redis-http.d.ts +1 -1
  123. package/dist/store-redis-http.d.ts.map +1 -1
  124. package/dist/store-redis-http.js +293 -11
  125. package/dist/store-redis-http.js.map +1 -1
  126. package/dist/store-redis-notify-BRITti_o.js +2493 -0
  127. package/dist/store-redis-notify-BRITti_o.js.map +1 -0
  128. package/dist/store-redis.d.ts +1 -1
  129. package/dist/store-redis.d.ts.map +1 -1
  130. package/dist/store-redis.js +11 -11
  131. package/dist/store-redis.js.map +1 -1
  132. package/dist/store-sqlite.d.ts +1 -1
  133. package/dist/store-sqlite.d.ts.map +1 -1
  134. package/dist/store-sqlite.js +197 -33
  135. package/dist/store-sqlite.js.map +1 -1
  136. package/dist/stream-buffer-Cx7AAPGq.js +23 -0
  137. package/dist/stream-buffer-Cx7AAPGq.js.map +1 -0
  138. package/dist/{telemetry-B5jzpy6y.d.ts → telemetry-Cyfqo6Qt.d.ts} +2 -2
  139. package/dist/telemetry-Cyfqo6Qt.d.ts.map +1 -0
  140. package/dist/{wire-BO5wWCb1.js → wire-rSUglYo8.js} +132 -10
  141. package/dist/wire-rSUglYo8.js.map +1 -0
  142. package/docs/01-quickstart.mdx +50 -84
  143. package/docs/{guides/07-examples.mdx → 02-examples.mdx} +10 -20
  144. package/docs/actors/01-introduction.mdx +48 -82
  145. package/docs/actors/02-concurrency.mdx +43 -70
  146. package/docs/actors/03-timers.mdx +28 -42
  147. package/docs/actors/04-routes.mdx +110 -137
  148. package/docs/actors/meta.ts +1 -1
  149. package/docs/agents/01-introduction.mdx +257 -0
  150. package/docs/agents/02-tools.mdx +247 -0
  151. package/docs/agents/03-conversations.mdx +538 -0
  152. package/docs/agents/04-harnesses.mdx +136 -0
  153. package/docs/agents/meta.ts +1 -0
  154. package/docs/client/01-react.mdx +294 -0
  155. package/docs/client/02-transports.mdx +86 -0
  156. package/docs/client/03-presence.mdx +224 -0
  157. package/docs/client/meta.ts +1 -0
  158. package/docs/contract/01-events.mdx +57 -0
  159. package/docs/contract/02-state.mdx +142 -0
  160. package/docs/contract/03-sessions.mdx +175 -0
  161. package/docs/index.mdx +112 -156
  162. package/docs/reference/01-core.mdx +139 -0
  163. package/docs/reference/02-server.mdx +855 -0
  164. package/docs/reference/03-client.mdx +301 -0
  165. package/docs/reference/04-ai.mdx +722 -0
  166. package/docs/reference/05-adapters.mdx +351 -0
  167. package/docs/reference/06-errors.mdx +138 -0
  168. package/docs/reference/meta.ts +1 -1
  169. package/docs/server/01-handlers.mdx +200 -0
  170. package/docs/server/02-timers.mdx +130 -0
  171. package/docs/server/03-cancellation.mdx +141 -0
  172. package/docs/server/04-routes.mdx +243 -0
  173. package/docs/server/05-production.mdx +322 -0
  174. package/docs/server/06-guarantees.mdx +123 -0
  175. package/examples/playground/DEPLOY.md +53 -7
  176. package/examples/playground/app/a0/[appId]/loading.tsx +16 -0
  177. package/examples/playground/app/a0/[appId]/page.tsx +53 -0
  178. package/examples/playground/app/a0/a0.css +818 -0
  179. package/examples/playground/app/a0/app-list.tsx +218 -0
  180. package/examples/playground/app/a0/app-view.tsx +63 -0
  181. package/examples/playground/app/a0/apps/[appId]/preview/route.ts +27 -0
  182. package/examples/playground/app/a0/apps/[appId]/route.ts +28 -0
  183. package/examples/playground/app/a0/apps.test.ts +128 -0
  184. package/examples/playground/app/a0/apps.ts +102 -0
  185. package/examples/playground/app/a0/chat.tsx +410 -0
  186. package/examples/playground/app/a0/columns.tsx +109 -0
  187. package/examples/playground/app/a0/context-menu.tsx +116 -0
  188. package/examples/playground/app/a0/cookies.ts +46 -0
  189. package/examples/playground/app/a0/crash-on-request.ts +72 -0
  190. package/examples/playground/app/a0/crashes/route.ts +3 -0
  191. package/examples/playground/app/a0/crashes.test.ts +33 -0
  192. package/examples/playground/app/a0/crashes.ts +28 -0
  193. package/examples/playground/app/a0/devtools.tsx +164 -0
  194. package/examples/playground/app/a0/events/route.ts +6 -0
  195. package/examples/playground/app/a0/flags.ts +30 -0
  196. package/examples/playground/app/a0/fx/events/route.ts +9 -0
  197. package/examples/playground/app/a0/fx/scheduler/route.ts +7 -0
  198. package/examples/playground/app/a0/fx/short/events/route.ts +11 -0
  199. package/examples/playground/app/a0/layout.tsx +38 -0
  200. package/examples/playground/app/a0/list/route.ts +10 -0
  201. package/examples/playground/app/a0/model.test.ts +73 -0
  202. package/examples/playground/app/a0/model.ts +95 -0
  203. package/examples/playground/app/a0/no-photon.cjs +4 -0
  204. package/examples/playground/app/a0/no-quickjs.cjs +3 -0
  205. package/examples/playground/app/a0/page.tsx +14 -0
  206. package/examples/playground/app/a0/pi/events/route.ts +9 -0
  207. package/examples/playground/app/a0/pi/scheduler/route.ts +7 -0
  208. package/examples/playground/app/a0/pi/short/events/route.ts +11 -0
  209. package/examples/playground/app/a0/preview-pane.tsx +145 -0
  210. package/examples/playground/app/a0/preview.test.ts +53 -0
  211. package/examples/playground/app/a0/preview.ts +26 -0
  212. package/examples/playground/app/a0/sandbox-log.ts +75 -0
  213. package/examples/playground/app/a0/sandbox-session.ts +152 -0
  214. package/examples/playground/app/a0/sandbox.ts +191 -0
  215. package/examples/playground/app/a0/sandboxes/scheduler/route.ts +6 -0
  216. package/examples/playground/app/a0/scheduler/route.ts +7 -0
  217. package/examples/playground/app/a0/server.ts +213 -0
  218. package/examples/playground/app/a0/session.ts +59 -0
  219. package/examples/playground/app/a0/shell.tsx +158 -0
  220. package/examples/playground/app/a0/short/events/route.ts +9 -0
  221. package/examples/playground/app/a0/splitter.tsx +120 -0
  222. package/examples/playground/app/agent/[agentId]/agent-client.tsx +144 -174
  223. package/examples/playground/app/agent/[agentId]/command-receipt.test.tsx +65 -0
  224. package/examples/playground/app/agent/[agentId]/command-receipt.tsx +27 -0
  225. package/examples/playground/app/agent/[agentId]/compaction-event.tsx +25 -24
  226. package/examples/playground/app/agent/[agentId]/compaction-panel.test.tsx +119 -0
  227. package/examples/playground/app/agent/[agentId]/compaction-panel.tsx +208 -165
  228. package/examples/playground/app/agent/[agentId]/page.tsx +2 -16
  229. package/examples/playground/app/agent/events/route.ts +5 -2
  230. package/examples/playground/app/agent/ingress.test.ts +101 -0
  231. package/examples/playground/app/agent/model-input.test.tsx +58 -0
  232. package/examples/playground/app/agent/model-input.tsx +115 -0
  233. package/examples/playground/app/agent/model.test.ts +73 -0
  234. package/examples/playground/app/agent/model.ts +58 -26
  235. package/examples/playground/app/agent/new-agent-session.tsx +37 -19
  236. package/examples/playground/app/agent/page.tsx +4 -4
  237. package/examples/playground/app/agent/server.ts +19 -15
  238. package/examples/playground/app/agent/session.ts +5 -6
  239. package/examples/playground/app/agent/telemetry.test.ts +189 -0
  240. package/examples/playground/app/agent/telemetry.ts +30 -0
  241. package/examples/playground/app/agent/trace.test.ts +23 -0
  242. package/examples/playground/app/agent/trace.ts +18 -0
  243. package/examples/playground/app/canvas/[canvasId]/canvas-client.tsx +12 -12
  244. package/examples/playground/app/canvas/[canvasId]/page.tsx +1 -2
  245. package/examples/playground/app/canvas/[canvasId]/session.ts +2 -2
  246. package/examples/playground/app/canvas/model.ts +53 -53
  247. package/examples/playground/app/chat/[chatId]/agent-state.test.ts +176 -0
  248. package/examples/playground/app/chat/[chatId]/agent-stream-drawer.tsx +16 -1
  249. package/examples/playground/app/chat/[chatId]/chat-client.tsx +55 -77
  250. package/examples/playground/app/chat/[chatId]/chat-view.ts +37 -3
  251. package/examples/playground/app/chat/[chatId]/page.tsx +7 -15
  252. package/examples/playground/app/chat/[chatId]/session.ts +2 -19
  253. package/examples/playground/app/chat/agent/route.ts +9 -0
  254. package/examples/playground/app/chat/model.test.ts +46 -119
  255. package/examples/playground/app/chat/model.ts +82 -128
  256. package/examples/playground/app/chat/scheduler/route.ts +2 -2
  257. package/examples/playground/app/chat/server.test.ts +112 -0
  258. package/examples/playground/app/chat/server.ts +113 -117
  259. package/examples/playground/app/components/activity-feed.tsx +30 -1
  260. package/examples/playground/app/components/activity-history.test.tsx +35 -0
  261. package/examples/playground/app/components/demo-icons.tsx +89 -0
  262. package/examples/playground/app/components/demos.tsx +33 -0
  263. package/examples/playground/app/components/fast-link.test.tsx +58 -0
  264. package/examples/playground/app/components/fast-link.tsx +55 -0
  265. package/examples/playground/app/components/site-header.tsx +96 -0
  266. package/examples/playground/app/counter/counter-client.tsx +3 -3
  267. package/examples/playground/app/counter/model.test.ts +3 -3
  268. package/examples/playground/app/counter/model.ts +11 -21
  269. package/examples/playground/app/counter/page.tsx +2 -15
  270. package/examples/playground/app/counter/session.ts +2 -2
  271. package/examples/playground/app/documents/[documentId]/code-editor.tsx +12 -1
  272. package/examples/playground/app/documents/[documentId]/document-client.tsx +10 -11
  273. package/examples/playground/app/documents/[documentId]/page.tsx +1 -2
  274. package/examples/playground/app/documents/[documentId]/session.ts +2 -2
  275. package/examples/playground/app/documents/model.ts +27 -27
  276. package/examples/playground/app/globals.css +420 -207
  277. package/examples/playground/app/initial-state.test.tsx +54 -0
  278. package/examples/playground/app/layout.tsx +7 -23
  279. package/examples/playground/app/orders/[orderId]/page.tsx +1 -2
  280. package/examples/playground/app/orders/[orderId]/session.ts +2 -2
  281. package/examples/playground/app/orders/model.ts +49 -49
  282. package/examples/playground/app/page.tsx +13 -102
  283. package/examples/playground/app/recovery/[recoveryId]/page.tsx +1 -2
  284. package/examples/playground/app/recovery/[recoveryId]/session.ts +2 -2
  285. package/examples/playground/app/recovery/model.ts +30 -30
  286. package/examples/playground/instrumentation.ts +5 -0
  287. package/examples/playground/next.config.ts +17 -5
  288. package/examples/playground/package.json +13 -2
  289. package/examples/playground/scripts/a0-template.ts +77 -0
  290. package/examples/playground/vercel.json +36 -0
  291. package/package.json +29 -3
  292. package/src/actor-client.ts +16 -4
  293. package/src/actor-react.ts +25 -11
  294. package/src/actor-shared.ts +21 -6
  295. package/src/actor.ts +76 -31
  296. package/src/ai-agent-actions.ts +219 -0
  297. package/src/ai-agent.ts +2517 -0
  298. package/src/ai-app-state.ts +91 -0
  299. package/src/ai-client-state.ts +6 -3
  300. package/src/ai-client.ts +62 -0
  301. package/src/ai-context-schema.ts +25 -5
  302. package/src/ai-context.ts +90 -40
  303. package/src/ai-control-server.ts +92 -72
  304. package/src/ai-coordinator.ts +23 -22
  305. package/src/ai-fx.browser.ts +5 -0
  306. package/src/ai-fx.ts +833 -0
  307. package/src/ai-harness.ts +518 -0
  308. package/src/ai-message-base.ts +209 -0
  309. package/src/ai-message-projection.ts +262 -64
  310. package/src/ai-model-metadata.ts +11 -6
  311. package/src/ai-pi.browser.ts +5 -0
  312. package/src/ai-pi.ts +1263 -0
  313. package/src/ai-progress-batches.ts +26 -0
  314. package/src/ai-projector.ts +95 -14
  315. package/src/ai-react.ts +146 -0
  316. package/src/ai-sdk-step.ts +2 -2
  317. package/src/ai-server.browser.ts +2 -2
  318. package/src/ai-server.ts +23 -1965
  319. package/src/ai-stored-state.ts +48 -163
  320. package/src/ai.ts +339 -155
  321. package/src/bootstrap-stream.ts +72 -0
  322. package/src/bounded-cache.ts +55 -0
  323. package/src/client-render-session.ts +49 -0
  324. package/src/client.ts +688 -151
  325. package/src/contract.ts +92 -42
  326. package/src/deterministic-id.ts +37 -0
  327. package/src/equal-json.ts +32 -0
  328. package/src/errors.ts +13 -1
  329. package/src/index.ts +5 -1
  330. package/src/initial-snapshot.ts +39 -0
  331. package/src/internal.ts +52 -0
  332. package/src/libfx.d.ts +34 -0
  333. package/src/postgres-notification-scope.ts +14 -3
  334. package/src/react.ts +171 -206
  335. package/src/redis-http-reply.ts +256 -0
  336. package/src/redis-http-stream.ts +73 -0
  337. package/src/redis-http-subscriptions.ts +13 -5
  338. package/src/reducer-runtime.ts +52 -0
  339. package/src/reducer.ts +93 -11
  340. package/src/scheduler-qstash.ts +49 -20
  341. package/src/scheduler-task.ts +34 -2
  342. package/src/scheduler-vercel.ts +32 -84
  343. package/src/server-fetch.ts +139 -35
  344. package/src/server.ts +1133 -255
  345. package/src/session-clear.ts +23 -0
  346. package/src/session-socket.ts +154 -49
  347. package/src/sse.ts +71 -4
  348. package/src/store-memory.ts +252 -75
  349. package/src/store-polling.ts +18 -4
  350. package/src/store-postgres.ts +541 -114
  351. package/src/store-redis-core.ts +1450 -493
  352. package/src/store-redis-http.ts +18 -2
  353. package/src/store-redis-notify.ts +262 -85
  354. package/src/store-redis.ts +19 -9
  355. package/src/store-sqlite.ts +319 -45
  356. package/src/store.ts +79 -1
  357. package/src/stream-buffer.ts +43 -0
  358. package/src/telemetry.ts +14 -1
  359. package/src/wire.ts +241 -13
  360. package/dist/actor-ohPC-81x.d.ts.map +0 -1
  361. package/dist/actor-shared-B5tJfzt-.js.map +0 -1
  362. package/dist/ai-CrEf6p_W.d.ts.map +0 -1
  363. package/dist/ai-DgOBltJ_.js.map +0 -1
  364. package/dist/client-BYzHjkwU.js.map +0 -1
  365. package/dist/client-CzyacQpJ.d.ts.map +0 -1
  366. package/dist/contract-CKRg_E4q.js.map +0 -1
  367. package/dist/errors-DCk6ch5n.js.map +0 -1
  368. package/dist/errors-DvhSXnxk.d.ts.map +0 -1
  369. package/dist/internal-Dq2qYxou.js.map +0 -1
  370. package/dist/react.d.ts.map +0 -1
  371. package/dist/reducer-DEMjEY_O.js +0 -29
  372. package/dist/reducer-DEMjEY_O.js.map +0 -1
  373. package/dist/reducer-otzHjuJj.d.ts.map +0 -1
  374. package/dist/scheduler-task-BpzhPnRS.js.map +0 -1
  375. package/dist/server-BD5ckxZb.js.map +0 -1
  376. package/dist/server-DbD7IJVK.d.ts.map +0 -1
  377. package/dist/store-DyZM6fS5.d.ts.map +0 -1
  378. package/dist/store-polling-CmxUbV93.js.map +0 -1
  379. package/dist/store-redis-notify-BVLUfI3j.js +0 -1583
  380. package/dist/store-redis-notify-BVLUfI3j.js.map +0 -1
  381. package/dist/telemetry-B5jzpy6y.d.ts.map +0 -1
  382. package/dist/validate-XKT4FSNn.js +0 -30
  383. package/dist/validate-XKT4FSNn.js.map +0 -1
  384. package/dist/wire-BO5wWCb1.js.map +0 -1
  385. package/docs/concepts/01-contracts.mdx +0 -142
  386. package/docs/concepts/02-handlers.mdx +0 -284
  387. package/docs/concepts/03-durability.mdx +0 -314
  388. package/docs/concepts/04-state.mdx +0 -209
  389. package/docs/guides/01-timers.mdx +0 -185
  390. package/docs/guides/02-cancellation.mdx +0 -161
  391. package/docs/guides/03-react.mdx +0 -384
  392. package/docs/guides/04-local-first.mdx +0 -88
  393. package/docs/guides/05-production.mdx +0 -521
  394. package/docs/guides/06-ai-agents.mdx +0 -1318
  395. package/docs/guides/08-application-data.mdx +0 -113
  396. package/docs/guides/09-presence.mdx +0 -266
  397. package/docs/guides/10-transports.mdx +0 -221
  398. package/docs/reference/01-api.mdx +0 -1896
  399. package/docs/reference/02-errors.mdx +0 -149
  400. package/examples/playground/app/agent/[agentId]/compaction/route.ts +0 -14
  401. package/examples/playground/app/agent/compaction-settings.test.ts +0 -144
  402. package/examples/playground/app/agent/compaction-settings.ts +0 -49
  403. package/examples/playground/app/agent/compaction-timeline.test.ts +0 -377
  404. package/examples/playground/app/agent/compaction-timeline.ts +0 -208
  405. /package/docs/{concepts → contract}/meta.ts +0 -0
  406. /package/docs/{guides → server}/meta.ts +0 -0
@@ -1,4 +1,7 @@
1
- import type { ReactNode } from 'react'
1
+ 'use client'
2
+
3
+ import { useState, type ReactNode } from 'react'
4
+ import type { HistoryState } from 'experimental-a2/client'
2
5
 
3
6
  /** The structural shape every machine's events share — enough for a
4
7
  * feed that shows the log itself. */
@@ -18,11 +21,26 @@ export function ActivityFeed({
18
21
  events,
19
22
  index,
20
23
  status,
24
+ history,
25
+ loadHistory,
21
26
  }: {
22
27
  events: readonly FeedEvent[]
23
28
  index: number
24
29
  status?: ReactNode
30
+ history?: HistoryState
31
+ loadHistory?: () => Promise<unknown>
25
32
  }): ReactNode {
33
+ const [error, setError] = useState<string | null>(null)
34
+ const loadEarlier = async (): Promise<void> => {
35
+ setError(null)
36
+ try {
37
+ await loadHistory?.()
38
+ } catch (cause) {
39
+ setError(
40
+ cause instanceof Error ? cause.message : 'Could not load history.',
41
+ )
42
+ }
43
+ }
26
44
  return (
27
45
  <section>
28
46
  <h2>Activity</h2>
@@ -45,6 +63,17 @@ export function ActivityFeed({
45
63
  </ol>
46
64
  )}
47
65
  {status ? <p className="activity-status">{status}</p> : null}
66
+ {history && loadHistory && !history.complete ? (
67
+ <button
68
+ type="button"
69
+ className="secondary"
70
+ disabled={history.loading}
71
+ onClick={() => void loadEarlier()}
72
+ >
73
+ {history.loading ? 'Loading…' : 'Load earlier events'}
74
+ </button>
75
+ ) : null}
76
+ {error ? <p role="alert">{error}</p> : null}
48
77
  <p className="frontier">
49
78
  Stream frontier: <code>{index}</code> — the last server-confirmed log
50
79
  position this browser has folded.
@@ -0,0 +1,35 @@
1
+ // @vitest-environment jsdom
2
+ import { act, cleanup, fireEvent, render, screen } from '@testing-library/react'
3
+ import { afterEach, expect, it, vi } from 'vitest'
4
+ import { ActivityFeed } from './activity-feed'
5
+
6
+ afterEach(cleanup)
7
+
8
+ it('loads an earlier page only on request and keeps failures retryable', async () => {
9
+ const loadHistory = vi
10
+ .fn<() => Promise<unknown>>()
11
+ .mockRejectedValueOnce(new Error('Read failed'))
12
+ .mockResolvedValueOnce([])
13
+ render(
14
+ <ActivityFeed
15
+ events={[]}
16
+ index={100}
17
+ history={{ loading: false, complete: false, oldestLoaded: null }}
18
+ loadHistory={loadHistory}
19
+ />,
20
+ )
21
+ expect(loadHistory).not.toHaveBeenCalled()
22
+ await act(async () =>
23
+ fireEvent.click(
24
+ screen.getByRole('button', { name: 'Load earlier events' }),
25
+ ),
26
+ )
27
+ expect(screen.getByRole('alert').textContent).toBe('Read failed')
28
+ await act(async () =>
29
+ fireEvent.click(
30
+ screen.getByRole('button', { name: 'Load earlier events' }),
31
+ ),
32
+ )
33
+ expect(screen.queryByRole('alert')).toBeNull()
34
+ expect(loadHistory).toHaveBeenCalledTimes(2)
35
+ })
@@ -0,0 +1,89 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ /** A 24px line icon: ink strokes, with its `accent` parts in orange. */
4
+ function Glyph({ children }: { children: ReactNode }): ReactNode {
5
+ return (
6
+ <svg
7
+ viewBox="0 0 24 24"
8
+ fill="none"
9
+ stroke="currentColor"
10
+ strokeWidth={1.5}
11
+ strokeLinecap="square"
12
+ aria-hidden
13
+ >
14
+ {children}
15
+ </svg>
16
+ )
17
+ }
18
+
19
+ export const A0Icon = (): ReactNode => (
20
+ <Glyph>
21
+ <rect x="3" y="4" width="18" height="16" />
22
+ <path d="M3 8h18" />
23
+ <path className="accent" d="M7 12l2.5 2L7 16M12 16h5" />
24
+ </Glyph>
25
+ )
26
+
27
+ export const OrdersIcon = (): ReactNode => (
28
+ <Glyph>
29
+ <path d="M3 4h18v5H3zM5 9v11h14V9" />
30
+ <path className="accent" d="M10 13h4" />
31
+ </Glyph>
32
+ )
33
+
34
+ export const ChatIcon = (): ReactNode => (
35
+ <Glyph>
36
+ <path d="M3 4h18v13H10l-4 3.5V17H3z" />
37
+ <rect className="fill" x="7" y="10" width="2" height="2" />
38
+ <rect className="fill" x="11" y="10" width="2" height="2" />
39
+ <rect className="accent-fill" x="15" y="10" width="2" height="2" />
40
+ </Glyph>
41
+ )
42
+
43
+ export const AgentIcon = (): ReactNode => (
44
+ <Glyph>
45
+ <rect x="3" y="3" width="18" height="18" />
46
+ <path className="accent" d="M12 7v10M7.7 9.5l8.6 5M7.7 14.5l8.6-5" />
47
+ </Glyph>
48
+ )
49
+
50
+ export const CanvasIcon = (): ReactNode => (
51
+ <Glyph>
52
+ <rect x="3" y="3" width="10" height="10" />
53
+ <circle cx="13" cy="13" r="5" />
54
+ <path className="accent-fill" d="M13 13l8.5 3.4-3.6 1.3-1.3 3.6z" />
55
+ </Glyph>
56
+ )
57
+
58
+ export const DocumentsIcon = (): ReactNode => (
59
+ <Glyph>
60
+ <path d="M5 3h10l4 4v14H5z" />
61
+ <path d="M8 10h8M8 14h4M8 18h7" />
62
+ <path className="accent" d="M14 12v4" />
63
+ </Glyph>
64
+ )
65
+
66
+ export const RecoveryIcon = (): ReactNode => (
67
+ <Glyph>
68
+ <path d="M20.5 12a8.5 8.5 0 1 1-2.5-6l2.5 2.5" />
69
+ <path d="M20.5 3.5v5h-5" />
70
+ <rect className="accent-fill" x="10" y="10" width="4" height="4" />
71
+ </Glyph>
72
+ )
73
+
74
+ export const VaultIcon = (): ReactNode => (
75
+ <Glyph>
76
+ <rect x="3" y="4" width="18" height="15" />
77
+ <circle cx="11" cy="11.5" r="3.5" />
78
+ <path className="accent" d="M11 11.5l2-2" />
79
+ <path d="M17.5 9.5v4M6 19v2M18 19v2" />
80
+ </Glyph>
81
+ )
82
+
83
+ export const CounterIcon = (): ReactNode => (
84
+ <Glyph>
85
+ <rect x="3" y="6" width="18" height="12" />
86
+ <path className="accent" d="M6.5 12h5M9 9.5v5" />
87
+ <path d="M16.5 9v6M15 10.5L16.5 9" />
88
+ </Glyph>
89
+ )
@@ -0,0 +1,33 @@
1
+ import type { ReactNode } from 'react'
2
+ import {
3
+ A0Icon,
4
+ AgentIcon,
5
+ CanvasIcon,
6
+ ChatIcon,
7
+ CounterIcon,
8
+ DocumentsIcon,
9
+ OrdersIcon,
10
+ RecoveryIcon,
11
+ VaultIcon,
12
+ } from './demo-icons'
13
+
14
+ export type Demo = {
15
+ href: string
16
+ name: string
17
+ icon: ReactNode
18
+ /** The demo fills the window and places the site nav itself. */
19
+ fullWindow?: true
20
+ }
21
+
22
+ /** Every demo, in the order the header menu and the home page list them. */
23
+ export const demos: Demo[] = [
24
+ { href: '/a0', name: 'A0', icon: <A0Icon />, fullWindow: true },
25
+ { href: '/orders', name: 'Orders', icon: <OrdersIcon /> },
26
+ { href: '/chat', name: 'Chat', icon: <ChatIcon /> },
27
+ { href: '/agent', name: 'Agent', icon: <AgentIcon /> },
28
+ { href: '/canvas', name: 'Canvas', icon: <CanvasIcon /> },
29
+ { href: '/documents', name: 'Documents', icon: <DocumentsIcon /> },
30
+ { href: '/recovery', name: 'Recovery', icon: <RecoveryIcon /> },
31
+ { href: '/vault', name: 'Vault', icon: <VaultIcon /> },
32
+ { href: '/counter', name: 'Counter', icon: <CounterIcon /> },
33
+ ]
@@ -0,0 +1,58 @@
1
+ // @vitest-environment jsdom
2
+ import {
3
+ cleanup,
4
+ createEvent,
5
+ fireEvent,
6
+ render,
7
+ screen,
8
+ } from '@testing-library/react'
9
+ import { afterEach, beforeEach, expect, it, vi } from 'vitest'
10
+ import { FastLink } from './fast-link'
11
+
12
+ const push = vi.fn<(href: string) => void>()
13
+ vi.mock('next/navigation', () => ({ useRouter: () => ({ push }) }))
14
+
15
+ // Whether each click reached the browser's default; then stop jsdom's
16
+ // unimplemented navigation.
17
+ let navigatedByClick: boolean[] = []
18
+ const record = (event: MouseEvent): void => {
19
+ navigatedByClick.push(!event.defaultPrevented)
20
+ event.preventDefault()
21
+ }
22
+ beforeEach(() => {
23
+ push.mockReset()
24
+ navigatedByClick = []
25
+ document.addEventListener('click', record)
26
+ })
27
+ afterEach(() => {
28
+ document.removeEventListener('click', record)
29
+ cleanup()
30
+ })
31
+
32
+ const link = () => screen.getByRole('link', { name: 'Apps' })
33
+ const press = (): void => {
34
+ const event = createEvent.pointerDown(link())
35
+ // jsdom has no PointerEvent, so the plain event gets its fields here.
36
+ Object.defineProperties(event, {
37
+ pointerType: { value: 'mouse' },
38
+ button: { value: 0 },
39
+ })
40
+ fireEvent(link(), event)
41
+ }
42
+
43
+ it('navigates on the press and swallows only that click', () => {
44
+ render(<FastLink href="/a0">Apps</FastLink>)
45
+ press()
46
+ expect(push).toHaveBeenCalledWith('/a0')
47
+ fireEvent.click(link(), { detail: 1 })
48
+ fireEvent.click(link(), { detail: 1 })
49
+ expect(navigatedByClick).toEqual([false, true])
50
+ })
51
+
52
+ it('lets a keyboard activation through after a press that never clicked', () => {
53
+ render(<FastLink href="/a0">Apps</FastLink>)
54
+ press()
55
+ // The pointer left before release, so no click followed the press.
56
+ fireEvent.click(link(), { detail: 0 })
57
+ expect(navigatedByClick).toEqual([true])
58
+ })
@@ -0,0 +1,55 @@
1
+ 'use client'
2
+ import type { ComponentProps, ReactNode } from 'react'
3
+ import { useRef } from 'react'
4
+ import Link from 'next/link'
5
+ import { useRouter } from 'next/navigation'
6
+
7
+ /**
8
+ * A Link that navigates on mouse down instead of on click, which saves the
9
+ * press-to-release time. Anything else keeps the browser's behavior: modified
10
+ * presses (open in a new tab or window), other buttons, and touch, where a
11
+ * press can still turn into a scroll.
12
+ */
13
+ export function FastLink({
14
+ href,
15
+ onPointerDown,
16
+ onClick,
17
+ ...props
18
+ }: Omit<ComponentProps<typeof Link>, 'href'> & { href: string }): ReactNode {
19
+ const router = useRouter()
20
+ const navigated = useRef(false)
21
+ return (
22
+ <Link
23
+ href={href}
24
+ {...props}
25
+ onPointerDown={(event) => {
26
+ onPointerDown?.(event)
27
+ navigated.current = false
28
+ if (
29
+ event.defaultPrevented ||
30
+ event.pointerType !== 'mouse' ||
31
+ event.button !== 0 ||
32
+ event.metaKey ||
33
+ event.ctrlKey ||
34
+ event.shiftKey ||
35
+ event.altKey ||
36
+ props.target
37
+ )
38
+ return
39
+ navigated.current = true
40
+ router.push(href)
41
+ }}
42
+ onClick={(event) => {
43
+ onClick?.(event)
44
+ const pressed = navigated.current
45
+ navigated.current = false
46
+ // The press already navigated, so its click doesn't navigate again. A
47
+ // keyboard activation (detail 0) is never that click, even when an
48
+ // earlier press never got one.
49
+ if (pressed && event.detail !== 0) {
50
+ event.preventDefault()
51
+ }
52
+ }}
53
+ />
54
+ )
55
+ }
@@ -0,0 +1,96 @@
1
+ 'use client'
2
+ import type { FocusEvent, ReactNode } from 'react'
3
+ import { useEffect, useRef } from 'react'
4
+ import { FastLink } from './fast-link'
5
+ import { usePathname } from 'next/navigation'
6
+ import { Asterisk, ChevronDown } from 'lucide-react'
7
+ import { type Demo, demos } from './demos'
8
+
9
+ const close = (details: HTMLDetailsElement | null): void =>
10
+ details?.removeAttribute('open')
11
+
12
+ function useCurrentDemo(): { pathname: string; current: Demo | undefined } {
13
+ const pathname = usePathname()
14
+ const current = demos.find(
15
+ (demo) => pathname === demo.href || pathname.startsWith(`${demo.href}/`),
16
+ )
17
+ return { pathname, current }
18
+ }
19
+
20
+ /** The site header, unless the demo lays out the whole window itself. */
21
+ export function SiteHeader(): ReactNode {
22
+ const { current } = useCurrentDemo()
23
+ if (current?.fullWindow) return null
24
+ return (
25
+ <header className="site-header">
26
+ <SiteNav />
27
+ </header>
28
+ )
29
+ }
30
+
31
+ /** The wordmark, then a menu that switches between the demos. */
32
+ export function SiteNav(): ReactNode {
33
+ const { pathname, current } = useCurrentDemo()
34
+ const menu = useRef<HTMLDetailsElement>(null)
35
+
36
+ useEffect(() => {
37
+ const outside = (event: PointerEvent): void => {
38
+ if (!menu.current?.contains(event.target as Node)) close(menu.current)
39
+ }
40
+ const escape = (event: KeyboardEvent): void => {
41
+ const details = menu.current
42
+ if (event.key !== 'Escape' || !details?.open) return
43
+ const hadFocus = details.contains(document.activeElement)
44
+ close(details)
45
+ if (hadFocus) details.querySelector('summary')?.focus()
46
+ }
47
+ document.addEventListener('pointerdown', outside)
48
+ document.addEventListener('keydown', escape)
49
+ return () => {
50
+ document.removeEventListener('pointerdown', outside)
51
+ document.removeEventListener('keydown', escape)
52
+ }
53
+ }, [])
54
+
55
+ const leave = (event: FocusEvent<HTMLDetailsElement>): void => {
56
+ if (!event.currentTarget.contains(event.relatedTarget)) {
57
+ close(event.currentTarget)
58
+ }
59
+ }
60
+
61
+ return (
62
+ <>
63
+ <FastLink href="/" className="brand">
64
+ <Asterisk size={18} strokeWidth={2.5} aria-hidden />
65
+ <span>A2</span>
66
+ </FastLink>
67
+ <details ref={menu} className="demo-menu" onBlur={leave}>
68
+ <summary>
69
+ <span aria-hidden>/</span>
70
+ <span className="sr-only">Demo:</span>
71
+ {current?.name ?? 'Playground'}
72
+ <ChevronDown size={13} aria-hidden />
73
+ </summary>
74
+ <nav aria-label="Demos">
75
+ {demos.map((demo) => (
76
+ <FastLink
77
+ key={demo.href}
78
+ href={demo.href}
79
+ aria-current={
80
+ demo !== current
81
+ ? undefined
82
+ : pathname === demo.href
83
+ ? 'page'
84
+ : 'true'
85
+ }
86
+ onClick={() => close(menu.current)}
87
+ >
88
+ {demo.name}
89
+ {demo === current ? <Asterisk size={12} aria-hidden /> : null}
90
+ </FastLink>
91
+ ))}
92
+ </nav>
93
+ </details>
94
+ </>
95
+ )
96
+ }
@@ -34,9 +34,9 @@ export function CounterClient(): ReactNode {
34
34
  <span className="badge live">shared</span>
35
35
  </header>
36
36
  <p className="lede">
37
- Every click appends one fact to a durable log. This page folds those
38
- facts into a value on the server for the first paint, then keeps folding
39
- the live stream in your browser.
37
+ Every click appends one fact to a durable log. The subscription starts
38
+ with the current value from the server, then keeps folding live events
39
+ in your browser.
40
40
  </p>
41
41
 
42
42
  <section className="counter-panel" aria-label="Shared counter controls">
@@ -1,6 +1,6 @@
1
1
  import type { ContractEvent } from 'experimental-a2'
2
2
  import { describe, expect, it } from 'vitest'
3
- import { counter, counterReducer } from './model'
3
+ import { counter } from './model'
4
4
 
5
5
  type CounterEvents = typeof counter.events
6
6
  type CounterEvent<
@@ -27,8 +27,8 @@ describe('counter reducer', () => {
27
27
  event(2, 'incremented'),
28
28
  event(3, 'decremented'),
29
29
  ].reduce(
30
- (current, nextEvent) => counterReducer.fold(current, nextEvent),
31
- counterReducer.initialState,
30
+ (current, nextEvent) => counter.reducer.fold(current, nextEvent),
31
+ counter.reducer.initialState,
32
32
  )
33
33
 
34
34
  expect(state).toEqual({ value: 1 })
@@ -1,31 +1,21 @@
1
- import * as a2 from 'experimental-a2'
1
+ import { contract } from 'experimental-a2'
2
2
  import { z } from 'zod'
3
3
 
4
- export const counter = a2.contract({
4
+ const counterState = z.object({ value: z.number().int() })
5
+ export type CounterState = z.output<typeof counterState>
6
+
7
+ export const counter = contract({
5
8
  name: 'counter',
6
9
  events: {
7
10
  incremented: z.object({}),
8
11
  decremented: z.object({}),
9
12
  },
10
- })
11
-
12
- const counterState = z.object({ value: z.number().int() })
13
-
14
- export type CounterState = z.output<typeof counterState>
15
-
16
- export const counterReducer = counter
17
- .reducer({
13
+ reducer: {
18
14
  name: 'counter-value',
19
15
  initialState: { value: 0 },
20
16
  stateSchema: counterState,
21
- })
22
- .fold((state, event) => {
23
- switch (event.type) {
24
- case 'incremented':
25
- return { value: state.value + 1 }
26
- case 'decremented':
27
- return { value: state.value - 1 }
28
- default:
29
- return state
30
- }
31
- })
17
+ fold: (state, event) => ({
18
+ value: state.value + (event.type === 'incremented' ? 1 : -1),
19
+ }),
20
+ },
21
+ })
@@ -1,23 +1,10 @@
1
1
  import type { ReactNode } from 'react'
2
- import { counterReducer } from './model'
3
- import { counterServer } from './server'
4
2
  import { CounterClient } from './counter-client'
5
3
  import { SessionProvider } from './session'
6
4
 
7
- export const dynamic = 'force-dynamic'
8
-
9
- const COUNTER_SESSION_ID = 'shared'
10
-
11
- export default async function CounterPage(): Promise<ReactNode> {
12
- const session = counterServer.session(COUNTER_SESSION_ID)
13
- const { state, index } = await session.state(counterReducer)
14
-
5
+ export default function CounterPage(): ReactNode {
15
6
  return (
16
- <SessionProvider
17
- sessionId={COUNTER_SESSION_ID}
18
- initialState={state}
19
- initialIndex={index}
20
- >
7
+ <SessionProvider sessionId="shared">
21
8
  <CounterClient />
22
9
  </SessionProvider>
23
10
  )
@@ -1,10 +1,10 @@
1
1
  'use client'
2
2
  import { createClient } from 'experimental-a2/client'
3
3
  import { createReact } from 'experimental-a2/react'
4
- import { counterReducer } from './model'
4
+ import { counter } from './model'
5
5
 
6
6
  export const counterClient = createClient({
7
- reducer: counterReducer,
7
+ contract: counter,
8
8
  api: '/counter/events',
9
9
  })
10
10
 
@@ -23,10 +23,14 @@ export function CodeMirrorEditor({
23
23
  const host = useRef<HTMLDivElement>(null)
24
24
  const view = useRef<EditorView | null>(null)
25
25
  const [editable] = useState(() => new Compartment())
26
+ const [theme] = useState(() => new Compartment())
26
27
 
27
28
  useEffect(() => {
28
29
  if (!host.current) return
29
30
 
31
+ // CodeMirror's own defaults (cursor, search panel, tooltips) follow the
32
+ // system theme along with the page.
33
+ const dark = window.matchMedia('(prefers-color-scheme: dark)')
30
34
  const body = doc.getText('body')
31
35
  const editor = new EditorView({
32
36
  parent: host.current,
@@ -34,6 +38,7 @@ export function CodeMirrorEditor({
34
38
  doc: body.toString(),
35
39
  extensions: [
36
40
  basicSetup,
41
+ theme.of(EditorView.darkTheme.of(dark.matches)),
37
42
  EditorView.lineWrapping,
38
43
  EditorView.contentAttributes.of({
39
44
  'aria-label': 'Document body',
@@ -60,12 +65,18 @@ export function CodeMirrorEditor({
60
65
  }),
61
66
  })
62
67
  view.current = editor
68
+ const followTheme = (): void =>
69
+ editor.dispatch({
70
+ effects: theme.reconfigure(EditorView.darkTheme.of(dark.matches)),
71
+ })
72
+ dark.addEventListener('change', followTheme)
63
73
 
64
74
  return () => {
75
+ dark.removeEventListener('change', followTheme)
65
76
  editor.destroy()
66
77
  view.current = null
67
78
  }
68
- }, [doc, awareness, editable])
79
+ }, [doc, awareness, editable, theme])
69
80
 
70
81
  useEffect(() => {
71
82
  view.current?.dispatch({
@@ -1,4 +1,5 @@
1
1
  'use client'
2
+ import type { StateSnapshot } from 'experimental-a2'
2
3
  import type { CSSProperties, ChangeEvent, ReactNode } from 'react'
3
4
  import {
4
5
  useCallback,
@@ -25,11 +26,11 @@ const ADJECTIVES = ['Bright', 'Calm', 'Curious', 'Kind', 'Swift'] as const
25
26
  const ANIMALS = ['Fox', 'Heron', 'Otter', 'Panda', 'Wren'] as const
26
27
  const COLORS = ['teal', 'amber', 'blue', 'violet', 'rose'] as const
27
28
  const COLOR_HEX: Record<DocumentActor['color'], string> = {
28
- teal: '#16836a',
29
- amber: '#bd7917',
30
- blue: '#3874c8',
31
- violet: '#7956b6',
32
- rose: '#bd5269',
29
+ teal: '#3ccf9f',
30
+ amber: '#f2b54b',
31
+ blue: '#6ea8fe',
32
+ violet: '#a98bff',
33
+ rose: '#ff7a93',
33
34
  }
34
35
 
35
36
  type SyncState = 'saved' | 'saving' | 'error'
@@ -154,12 +155,10 @@ function useYText(doc: Y.Doc, name: string): string {
154
155
 
155
156
  export function DocumentSession({
156
157
  documentId,
157
- initialState,
158
- initialIndex,
158
+ initial,
159
159
  }: {
160
160
  documentId: string
161
- initialState: DocumentState
162
- initialIndex: number
161
+ initial: StateSnapshot<DocumentState>
163
162
  }): ReactNode {
164
163
  // Minted before the provider connects, so the session carries its
165
164
  // participant id from the first frame. The rendered UI keeps its
@@ -172,8 +171,8 @@ export function DocumentSession({
172
171
  <SessionProvider
173
172
  sessionId={documentId}
174
173
  api="/documents/events"
175
- initialState={initialState}
176
- initialIndex={initialIndex}
174
+ initial={initial}
175
+
177
176
  {...(identity ? { participant: identity.id } : {})}
178
177
  >
179
178
  <DocumentClient documentId={documentId} />
@@ -16,8 +16,7 @@ export default async function DocumentPage({
16
16
  return (
17
17
  <DocumentSession
18
18
  documentId={documentId}
19
- initialState={state}
20
- initialIndex={index}
19
+ initial={{ state: state, index: index }}
21
20
  />
22
21
  )
23
22
  }
@@ -1,7 +1,7 @@
1
1
  'use client'
2
2
  import { createReact } from 'experimental-a2/react'
3
- import { documentsReducer } from '../model'
3
+ import { documents } from '../model'
4
4
 
5
5
  export const { SessionProvider, useSession } = createReact({
6
- reducer: documentsReducer,
6
+ contract: documents,
7
7
  })