@abloatai/ablo 0.34.1 → 0.36.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 (536) hide show
  1. package/AGENTS.md +2 -1
  2. package/CHANGELOG.md +758 -5
  3. package/README.md +56 -502
  4. package/bin/ablo.cjs +39 -0
  5. package/dist/BaseSyncedStore.d.ts +176 -48
  6. package/dist/BaseSyncedStore.js +346 -214
  7. package/dist/Database.d.ts +17 -44
  8. package/dist/Database.js +96 -79
  9. package/dist/InstanceCache.d.ts +31 -6
  10. package/dist/InstanceCache.js +65 -30
  11. package/dist/LazyReferenceCollection.d.ts +3 -3
  12. package/dist/LazyReferenceCollection.js +4 -4
  13. package/dist/Model.d.ts +23 -13
  14. package/dist/Model.js +27 -17
  15. package/dist/ModelRegistry.d.ts +8 -4
  16. package/dist/ModelRegistry.js +20 -18
  17. package/dist/NetworkMonitor.d.ts +3 -1
  18. package/dist/NetworkMonitor.js +7 -5
  19. package/dist/{SyncEngineContext.d.ts → RuntimeContext.d.ts} +20 -13
  20. package/dist/{SyncEngineContext.js → RuntimeContext.js} +11 -12
  21. package/dist/SyncClient.d.ts +47 -47
  22. package/dist/SyncClient.js +215 -156
  23. package/dist/ai-sdk/coordinatedTool.d.ts +2 -2
  24. package/dist/ai-sdk/coordinatedTool.js +1 -1
  25. package/dist/ai-sdk/coordinationContext.d.ts +2 -2
  26. package/dist/ai-sdk/coordinationContext.js +1 -1
  27. package/dist/ai-sdk/wrap.d.ts +3 -3
  28. package/dist/ai-sdk/wrap.js +2 -2
  29. package/dist/auth/index.d.ts +1 -156
  30. package/dist/auth/index.js +8 -301
  31. package/dist/client/Ablo.d.ts +42 -287
  32. package/dist/client/Ablo.js +129 -963
  33. package/dist/client/abloClient.d.ts +309 -0
  34. package/dist/client/abloClient.js +13 -0
  35. package/dist/client/clientPrelude.d.ts +52 -0
  36. package/dist/client/clientPrelude.js +60 -0
  37. package/dist/client/consoleLogger.d.ts +2 -2
  38. package/dist/client/coreClient.d.ts +60 -0
  39. package/dist/client/coreClient.js +118 -0
  40. package/dist/client/createInternalComponents.d.ts +8 -4
  41. package/dist/client/createInternalComponents.js +17 -10
  42. package/dist/client/createModelProxy.d.ts +98 -373
  43. package/dist/client/createModelProxy.js +233 -139
  44. package/dist/client/humans.d.ts +69 -0
  45. package/dist/client/humans.js +78 -0
  46. package/dist/client/modelRegistration.d.ts +1 -1
  47. package/dist/client/modelRegistration.js +9 -9
  48. package/dist/client/options.d.ts +73 -17
  49. package/dist/client/reactiveEngine.d.ts +53 -0
  50. package/dist/client/reactiveEngine.js +688 -0
  51. package/dist/client/resourceTypes.d.ts +9 -250
  52. package/dist/client/resourceTypes.js +8 -5
  53. package/dist/client/schemaConfig.d.ts +4 -4
  54. package/dist/client/schemaConfig.js +6 -2
  55. package/dist/client/storeCluster.d.ts +47 -0
  56. package/dist/client/storeCluster.js +118 -0
  57. package/dist/client/storeLifecycle.d.ts +61 -0
  58. package/dist/client/storeLifecycle.js +231 -0
  59. package/dist/client/validateAbloOptions.d.ts +3 -2
  60. package/dist/client/validateAbloOptions.js +1 -1
  61. package/dist/client/wsMutationExecutor.d.ts +3 -3
  62. package/dist/client/wsMutationExecutor.js +3 -3
  63. package/dist/context.d.ts +22 -9
  64. package/dist/context.js +33 -9
  65. package/dist/coordination/ClaimLog.d.ts +26 -0
  66. package/dist/coordination/ClaimLog.js +32 -0
  67. package/dist/coordination/index.d.ts +1 -15
  68. package/dist/coordination/index.js +8 -31
  69. package/dist/core/index.d.ts +3 -3
  70. package/dist/core/index.js +2 -2
  71. package/dist/docs/catalog.d.ts +72 -0
  72. package/dist/docs/catalog.js +230 -0
  73. package/dist/docs/index.d.ts +10 -0
  74. package/dist/docs/index.js +10 -0
  75. package/dist/environment.d.ts +1 -40
  76. package/dist/environment.js +8 -37
  77. package/dist/index.d.ts +44 -36
  78. package/dist/index.js +30 -22
  79. package/dist/interfaces/index.d.ts +44 -134
  80. package/dist/keys/index.d.ts +1 -77
  81. package/dist/keys/index.js +8 -190
  82. package/dist/mutators/{RecordingTransaction.d.ts → RecordingMutation.d.ts} +4 -4
  83. package/dist/mutators/{RecordingTransaction.js → RecordingMutation.js} +2 -2
  84. package/dist/mutators/Transaction.d.ts +1 -1
  85. package/dist/mutators/Transaction.js +1 -1
  86. package/dist/mutators/UndoManager.d.ts +6 -6
  87. package/dist/mutators/UndoManager.js +5 -5
  88. package/dist/mutators/defineMutators.d.ts +3 -3
  89. package/dist/mutators/defineMutators.js +1 -1
  90. package/dist/mutators/inverseOp.js +2 -2
  91. package/dist/mutators/mutateActions.d.ts +3 -3
  92. package/dist/mutators/mutateActions.js +1 -1
  93. package/dist/mutators/readerActions.d.ts +1 -1
  94. package/dist/mutators/undoApply.d.ts +1 -1
  95. package/dist/mutators/undoApply.js +1 -1
  96. package/dist/policy/index.d.ts +2 -2
  97. package/dist/policy/index.js +1 -1
  98. package/dist/query/client.d.ts +5 -2
  99. package/dist/query/client.js +10 -9
  100. package/dist/query/types.d.ts +6 -41
  101. package/dist/query/types.js +2 -2
  102. package/dist/react/AbloProvider.d.ts +18 -8
  103. package/dist/react/AbloProvider.js +10 -9
  104. package/dist/react/context.d.ts +3 -3
  105. package/dist/react/context.js +1 -1
  106. package/dist/react/createAbloReact.d.ts +56 -0
  107. package/dist/react/createAbloReact.js +51 -0
  108. package/dist/react/index.d.ts +6 -5
  109. package/dist/react/index.js +6 -3
  110. package/dist/react/internalContext.d.ts +1 -1
  111. package/dist/react/useAblo.d.ts +12 -5
  112. package/dist/react/useAblo.js +26 -8
  113. package/dist/react/useCurrentUserId.js +1 -1
  114. package/dist/react/useErrorListener.js +1 -1
  115. package/dist/react/useMutationFailureListener.d.ts +2 -2
  116. package/dist/react/useMutationFailureListener.js +1 -1
  117. package/dist/react/useMutators.d.ts +3 -3
  118. package/dist/react/useMutators.js +3 -3
  119. package/dist/react/useUndoScope.d.ts +5 -5
  120. package/dist/react/useUndoScope.js +1 -1
  121. package/dist/schema/coordination.d.ts +69 -10
  122. package/dist/schema/coordination.js +90 -9
  123. package/dist/schema/ddl.js +2 -2
  124. package/dist/schema/diff.d.ts +1 -1
  125. package/dist/schema/generate.js +1 -1
  126. package/dist/schema/index.d.ts +11 -10
  127. package/dist/schema/index.js +22 -18
  128. package/dist/schema/queries.d.ts +27 -27
  129. package/dist/schema/queries.js +23 -23
  130. package/dist/schema/select.d.ts +3 -3
  131. package/dist/schema/select.js +6 -3
  132. package/dist/schema/serialize.d.ts +15 -6
  133. package/dist/schema/serialize.js +20 -3
  134. package/dist/schema/sugar.d.ts +6 -7
  135. package/dist/schema/sugar.js +9 -12
  136. package/dist/schema/syncDeltaRow.d.ts +4 -152
  137. package/dist/schema/syncDeltaRow.js +4 -105
  138. package/dist/server/adapter.d.ts +18 -1
  139. package/dist/server/commit.d.ts +10 -16
  140. package/dist/server/index.d.ts +1 -1
  141. package/dist/server/index.js +1 -1
  142. package/dist/server/readConfig.d.ts +1 -1
  143. package/dist/source/adapter.d.ts +7 -5
  144. package/dist/source/adapter.js +7 -5
  145. package/dist/source/adapters/drizzle.d.ts +1 -1
  146. package/dist/source/adapters/drizzle.js +2 -2
  147. package/dist/source/adapters/kysely.d.ts +1 -1
  148. package/dist/source/adapters/kysely.js +1 -1
  149. package/dist/source/adapters/kyselyMutationCore.d.ts +1 -1
  150. package/dist/source/adapters/kyselyMutationCore.js +2 -2
  151. package/dist/source/adapters/memory.js +1 -1
  152. package/dist/source/adapters/prisma.d.ts +8 -3
  153. package/dist/source/adapters/prisma.js +1 -1
  154. package/dist/source/connector.js +1 -1
  155. package/dist/source/connectorProtocol.d.ts +2 -8
  156. package/dist/source/connectorProtocol.js +3 -2
  157. package/dist/source/contract.d.ts +29 -17
  158. package/dist/source/contract.js +27 -22
  159. package/dist/source/factory.d.ts +1 -1
  160. package/dist/source/idempotency.js +2 -2
  161. package/dist/source/index.d.ts +1 -0
  162. package/dist/source/index.js +3 -0
  163. package/dist/source/next.d.ts +1 -1
  164. package/dist/source/signing.d.ts +9 -2
  165. package/dist/source/signing.js +4 -1
  166. package/dist/source/types.d.ts +6 -4
  167. package/dist/source/types.js +1 -1
  168. package/dist/{core/storeContract.d.ts → storeContract.d.ts} +6 -6
  169. package/dist/{core → stores}/DatabaseManager.d.ts +3 -1
  170. package/dist/{core → stores}/DatabaseManager.js +14 -13
  171. package/dist/stores/ObjectStore.d.ts +1 -1
  172. package/dist/{core → stores}/StoreManager.d.ts +9 -26
  173. package/dist/{core → stores}/StoreManager.js +29 -77
  174. package/dist/stores/SyncActionStore.d.ts +4 -2
  175. package/dist/stores/SyncActionStore.js +11 -17
  176. package/dist/stores/syncAction.d.ts +26 -0
  177. package/dist/stores/syncAction.js +16 -0
  178. package/dist/surface.d.ts +3 -3
  179. package/dist/surface.js +6 -4
  180. package/dist/sync/BootstrapFetcher.d.ts +127 -6
  181. package/dist/sync/BootstrapFetcher.js +511 -83
  182. package/dist/sync/ConnectionManager.d.ts +6 -198
  183. package/dist/sync/ConnectionManager.js +6 -677
  184. package/dist/sync/OnDemandLoader.d.ts +5 -2
  185. package/dist/sync/OnDemandLoader.js +61 -21
  186. package/dist/sync/SubscriptionManager.d.ts +13 -2
  187. package/dist/sync/SubscriptionManager.js +23 -5
  188. package/dist/sync/SyncWebSocket.d.ts +27 -510
  189. package/dist/sync/SyncWebSocket.js +76 -954
  190. package/dist/sync/awaitClaimGrant.d.ts +4 -44
  191. package/dist/sync/awaitClaimGrant.js +4 -109
  192. package/dist/sync/bootstrapApply.d.ts +3 -0
  193. package/dist/sync/bootstrapApply.js +2 -2
  194. package/dist/sync/commitFrames.d.ts +6 -40
  195. package/dist/sync/commitFrames.js +6 -97
  196. package/dist/sync/contextPorts.d.ts +18 -0
  197. package/dist/sync/contextPorts.js +31 -0
  198. package/dist/sync/createClaimStream.d.ts +5 -49
  199. package/dist/sync/createClaimStream.js +5 -469
  200. package/dist/sync/createPresenceStream.d.ts +26 -4
  201. package/dist/sync/createPresenceStream.js +28 -20
  202. package/dist/sync/createSnapshot.d.ts +2 -2
  203. package/dist/sync/createSnapshot.js +1 -1
  204. package/dist/sync/credentialLifecycle.d.ts +5 -173
  205. package/dist/sync/credentialLifecycle.js +5 -320
  206. package/dist/sync/deltaPipeline.d.ts +13 -12
  207. package/dist/sync/deltaPipeline.js +21 -4
  208. package/dist/sync/groupChange.d.ts +3 -0
  209. package/dist/sync/groupChange.js +16 -14
  210. package/dist/sync/participants.d.ts +24 -6
  211. package/dist/sync/participants.js +32 -23
  212. package/dist/sync/schemaDrift.d.ts +55 -0
  213. package/dist/sync/schemaDrift.js +53 -0
  214. package/dist/sync/schemas.d.ts +23 -33
  215. package/dist/sync/schemas.js +29 -20
  216. package/dist/sync/syncPlan.d.ts +3 -3
  217. package/dist/sync/wsFrameHandlers.d.ts +6 -114
  218. package/dist/sync/wsFrameHandlers.js +6 -392
  219. package/dist/syncLog/contract.d.ts +20 -0
  220. package/dist/syncLog/contract.js +19 -0
  221. package/dist/syncLog/index.d.ts +1 -0
  222. package/dist/syncLog/index.js +1 -0
  223. package/dist/transaction/ablo.d.ts +88 -0
  224. package/dist/transaction/ablo.js +33 -0
  225. package/dist/{client/auth.d.ts → transaction/auth/apiKey.d.ts} +43 -8
  226. package/dist/{client/auth.js → transaction/auth/apiKey.js} +19 -0
  227. package/dist/transaction/auth/bootstrapScope.d.ts +15 -0
  228. package/dist/transaction/auth/bootstrapScope.js +1 -0
  229. package/dist/transaction/auth/capability.d.ts +212 -0
  230. package/dist/transaction/auth/capability.js +224 -0
  231. package/dist/{auth → transaction/auth}/credentialSource.d.ts +8 -1
  232. package/dist/{client → transaction/auth}/identity.d.ts +8 -7
  233. package/dist/{client → transaction/auth}/identity.js +1 -1
  234. package/dist/transaction/auth/index.d.ts +162 -0
  235. package/dist/transaction/auth/index.js +304 -0
  236. package/dist/{auth → transaction/auth}/schemas.d.ts +1 -1
  237. package/dist/{auth → transaction/auth}/schemas.js +13 -13
  238. package/dist/{client → transaction/auth}/sessionMint.d.ts +8 -8
  239. package/dist/{client → transaction/auth}/sessionMint.js +4 -7
  240. package/dist/transaction/coordination/awaitClaimGrant.d.ts +56 -0
  241. package/dist/transaction/coordination/awaitClaimGrant.js +124 -0
  242. package/dist/{client → transaction/coordination}/claimHeartbeatLoop.d.ts +34 -0
  243. package/dist/{client → transaction/coordination}/claimHeartbeatLoop.js +20 -0
  244. package/dist/transaction/coordination/claimMeta.d.ts +49 -0
  245. package/dist/transaction/coordination/claimMeta.js +52 -0
  246. package/dist/transaction/coordination/createClaimStream.d.ts +64 -0
  247. package/dist/transaction/coordination/createClaimStream.js +475 -0
  248. package/dist/transaction/coordination/events.d.ts +74 -0
  249. package/dist/transaction/coordination/events.js +7 -0
  250. package/dist/transaction/coordination/index.d.ts +19 -0
  251. package/dist/transaction/coordination/index.js +45 -0
  252. package/dist/transaction/coordination/locator.d.ts +104 -0
  253. package/dist/transaction/coordination/locator.js +102 -0
  254. package/dist/transaction/coordination/schema.d.ts +1536 -0
  255. package/dist/transaction/coordination/schema.js +1177 -0
  256. package/dist/transaction/coordination/targetConflict.d.ts +2 -0
  257. package/dist/transaction/coordination/targetConflict.js +107 -0
  258. package/dist/{coordination → transaction/coordination}/trace.d.ts +7 -18
  259. package/dist/{coordination → transaction/coordination}/trace.js +18 -25
  260. package/dist/transaction/durableWrites.d.ts +62 -0
  261. package/dist/{client → transaction}/durableWrites.js +28 -3
  262. package/dist/transaction/environment.d.ts +105 -0
  263. package/dist/transaction/environment.js +108 -0
  264. package/dist/{errorCodes.d.ts → transaction/errorCodes.d.ts} +12 -12
  265. package/dist/{errorCodes.js → transaction/errorCodes.js} +45 -18
  266. package/dist/{errors.d.ts → transaction/errors.d.ts} +37 -13
  267. package/dist/{errors.js → transaction/errors.js} +85 -16
  268. package/dist/transaction/footprint.d.ts +111 -0
  269. package/dist/transaction/footprint.js +0 -0
  270. package/dist/transaction/index.d.ts +20 -0
  271. package/dist/transaction/index.js +20 -0
  272. package/dist/transaction/keys/index.d.ts +87 -0
  273. package/dist/transaction/keys/index.js +207 -0
  274. package/dist/transaction/log/syncDeltaRow.d.ts +158 -0
  275. package/dist/transaction/log/syncDeltaRow.js +95 -0
  276. package/dist/{sync/syncPosition.d.ts → transaction/logPosition.d.ts} +22 -8
  277. package/dist/{sync/syncPosition.js → transaction/logPosition.js} +15 -6
  278. package/dist/transaction/logger.d.ts +16 -0
  279. package/dist/transaction/logger.js +7 -0
  280. package/dist/transaction/observability.d.ts +53 -0
  281. package/dist/transaction/observability.js +19 -0
  282. package/dist/transaction/plugin.d.ts +285 -0
  283. package/dist/transaction/plugin.js +106 -0
  284. package/dist/{policy → transaction/policy}/types.d.ts +3 -3
  285. package/dist/{policy → transaction/policy}/types.js +2 -0
  286. package/dist/transaction/resources/httpResources.d.ts +321 -0
  287. package/dist/transaction/resources/httpResources.js +7 -0
  288. package/dist/transaction/resources/modelOperations.d.ts +427 -0
  289. package/dist/transaction/resources/modelOperations.js +12 -0
  290. package/dist/transaction/resources/mutationOptions.d.ts +66 -0
  291. package/dist/transaction/resources/mutationOptions.js +9 -0
  292. package/dist/transaction/resources/where.d.ts +101 -0
  293. package/dist/transaction/resources/where.js +115 -0
  294. package/dist/{client → transaction/resources}/writeOptionsSchema.d.ts +2 -6
  295. package/dist/{client → transaction/resources}/writeOptionsSchema.js +9 -5
  296. package/dist/{schema → transaction/schema}/field.d.ts +17 -23
  297. package/dist/{schema → transaction/schema}/field.js +5 -5
  298. package/dist/transaction/schema/fieldRef.d.ts +38 -0
  299. package/dist/transaction/schema/fieldRef.js +11 -0
  300. package/dist/transaction/schema/loadStrategy.d.ts +45 -0
  301. package/dist/transaction/schema/loadStrategy.js +46 -0
  302. package/dist/{schema → transaction/schema}/model.d.ts +50 -35
  303. package/dist/{schema → transaction/schema}/model.js +30 -20
  304. package/dist/transaction/schema/openapi.d.ts +58 -0
  305. package/dist/transaction/schema/openapi.js +501 -0
  306. package/dist/{schema → transaction/schema}/relation.d.ts +21 -16
  307. package/dist/{schema → transaction/schema}/relation.js +7 -7
  308. package/dist/{schema → transaction/schema}/residency.d.ts +0 -9
  309. package/dist/{schema → transaction/schema}/residency.js +0 -5
  310. package/dist/{schema → transaction/schema}/roles.d.ts +5 -5
  311. package/dist/{schema → transaction/schema}/roles.js +5 -5
  312. package/dist/{schema → transaction/schema}/schema.d.ts +39 -10
  313. package/dist/{schema → transaction/schema}/schema.js +24 -3
  314. package/dist/{schema → transaction/schema}/tenancy.d.ts +1 -1
  315. package/dist/{schema → transaction/schema}/tenancy.js +7 -4
  316. package/dist/transaction/transactionLayer.d.ts +82 -0
  317. package/dist/transaction/transactionLayer.js +24 -0
  318. package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.d.ts +5 -6
  319. package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.js +9 -13
  320. package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.d.ts +9 -2
  321. package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.js +5 -9
  322. package/dist/{transactions/durableWriteStore.d.ts → transaction/transactions/settlement/pendingWrite.d.ts} +11 -37
  323. package/dist/transaction/transactions/settlement/pendingWrite.js +20 -0
  324. package/dist/transaction/transport/commitFrames.d.ts +90 -0
  325. package/dist/transaction/transport/commitFrames.js +134 -0
  326. package/dist/transaction/transport/connectionManager.d.ts +215 -0
  327. package/dist/transaction/transport/connectionManager.js +673 -0
  328. package/dist/transaction/transport/credentialLifecycle.d.ts +177 -0
  329. package/dist/transaction/transport/credentialLifecycle.js +324 -0
  330. package/dist/{sync → transaction/transport}/heartbeat.d.ts +3 -1
  331. package/dist/{sync → transaction/transport}/heartbeat.js +6 -4
  332. package/dist/transaction/transport/httpClient.d.ts +131 -0
  333. package/dist/{client → transaction/transport}/httpClient.js +6 -5
  334. package/dist/transaction/transport/httpOptions.d.ts +33 -0
  335. package/dist/transaction/transport/httpOptions.js +12 -0
  336. package/dist/{client → transaction/transport}/httpTransport.js +295 -97
  337. package/dist/{sync/NetworkProbe.d.ts → transaction/transport/networkProbe.d.ts} +7 -4
  338. package/dist/{sync/NetworkProbe.js → transaction/transport/networkProbe.js} +14 -13
  339. package/dist/transaction/transport/wsFrameHandlers.d.ts +128 -0
  340. package/dist/transaction/transport/wsFrameHandlers.js +429 -0
  341. package/dist/transaction/transport/wsTransport.d.ts +574 -0
  342. package/dist/transaction/transport/wsTransport.js +1023 -0
  343. package/dist/transaction/types/assertExact.d.ts +17 -0
  344. package/dist/transaction/types/assertExact.js +1 -0
  345. package/dist/{types → transaction/types}/global.d.ts +17 -2
  346. package/dist/{types → transaction/types}/global.js +2 -1
  347. package/dist/{types → transaction/types}/index.d.ts +14 -46
  348. package/dist/{types → transaction/types}/index.js +7 -16
  349. package/dist/{types → transaction/types}/streams.d.ts +73 -45
  350. package/dist/transaction/utils/duration.d.ts +50 -0
  351. package/dist/{utils → transaction/utils}/duration.js +32 -0
  352. package/dist/{utils → transaction/utils}/json.d.ts +18 -0
  353. package/dist/transaction/utils/json.js +276 -0
  354. package/dist/transaction/wire/accountResponses.d.ts +420 -0
  355. package/dist/transaction/wire/accountResponses.js +290 -0
  356. package/dist/transaction/wire/auth.d.ts +56 -0
  357. package/dist/transaction/wire/auth.js +63 -0
  358. package/dist/transaction/wire/claimEvent.d.ts +76 -0
  359. package/dist/transaction/wire/claimEvent.js +73 -0
  360. package/dist/transaction/wire/claims.d.ts +530 -0
  361. package/dist/transaction/wire/claims.js +327 -0
  362. package/dist/{wire → transaction/wire}/commit.d.ts +125 -193
  363. package/dist/{wire → transaction/wire}/commit.js +68 -47
  364. package/dist/{wire → transaction/wire}/delta.d.ts +66 -17
  365. package/dist/{wire → transaction/wire}/delta.js +37 -13
  366. package/dist/transaction/wire/errorEnvelope.d.ts +72 -0
  367. package/dist/{wire → transaction/wire}/errorEnvelope.js +36 -5
  368. package/dist/transaction/wire/feedCursor.d.ts +60 -0
  369. package/dist/transaction/wire/feedCursor.js +82 -0
  370. package/dist/transaction/wire/feedEvent.d.ts +204 -0
  371. package/dist/transaction/wire/feedEvent.js +65 -0
  372. package/dist/transaction/wire/frames.d.ts +194 -0
  373. package/dist/transaction/wire/frames.js +50 -0
  374. package/dist/transaction/wire/inboundFrames.d.ts +562 -0
  375. package/dist/transaction/wire/inboundFrames.js +116 -0
  376. package/dist/transaction/wire/index.d.ts +54 -0
  377. package/dist/transaction/wire/index.js +83 -0
  378. package/dist/{wire → transaction/wire}/listEnvelope.d.ts +13 -14
  379. package/dist/transaction/wire/listEnvelope.js +42 -0
  380. package/dist/transaction/wire/modelMutations.d.ts +31 -0
  381. package/dist/transaction/wire/modelMutations.js +52 -0
  382. package/dist/transaction/wire/modelResponses.d.ts +85 -0
  383. package/dist/transaction/wire/modelResponses.js +43 -0
  384. package/dist/transaction/wire/modelShape.d.ts +78 -0
  385. package/dist/transaction/wire/modelShape.js +74 -0
  386. package/dist/transactions/{TransactionQueue.d.ts → mutations/MutationQueue.d.ts} +85 -38
  387. package/dist/transactions/{TransactionQueue.js → mutations/MutationQueue.js} +141 -80
  388. package/dist/transactions/{TransactionStore.d.ts → mutations/MutationStore.d.ts} +8 -8
  389. package/dist/transactions/{TransactionStore.js → mutations/MutationStore.js} +2 -2
  390. package/dist/transactions/{coalesceRules.d.ts → mutations/coalesceRules.d.ts} +10 -10
  391. package/dist/transactions/{coalesceRules.js → mutations/coalesceRules.js} +1 -1
  392. package/dist/transactions/mutations/commitLatency.d.ts +52 -0
  393. package/dist/transactions/mutations/commitLatency.js +130 -0
  394. package/dist/transactions/{commitOutboxStore.d.ts → mutations/commitOutboxStore.d.ts} +1 -5
  395. package/dist/transactions/{commitOutboxStore.js → mutations/commitOutboxStore.js} +1 -1
  396. package/dist/transactions/{commitPayload.d.ts → mutations/commitPayload.d.ts} +18 -16
  397. package/dist/transactions/{commitPayload.js → mutations/commitPayload.js} +15 -15
  398. package/dist/transactions/{deltaConfirmation.d.ts → mutations/deltaConfirmation.d.ts} +15 -11
  399. package/dist/transactions/{deltaConfirmation.js → mutations/deltaConfirmation.js} +14 -12
  400. package/dist/transactions/mutations/durableWriteStore.d.ts +14 -0
  401. package/dist/transactions/mutations/durableWriteStore.js +12 -0
  402. package/dist/transactions/{optimisticApply.d.ts → mutations/optimisticApply.d.ts} +7 -7
  403. package/dist/transactions/{replayValidation.d.ts → mutations/replayValidation.d.ts} +4 -3
  404. package/dist/transactions/{replayValidation.js → mutations/replayValidation.js} +7 -5
  405. package/dist/utils/mobxSetup.d.ts +1 -1
  406. package/dist/utils/mobxSetup.js +5 -2
  407. package/dist/{core → views}/QueryView.d.ts +2 -2
  408. package/dist/{core → views}/QueryView.js +2 -2
  409. package/dist/{core → views}/ViewRegistry.d.ts +1 -1
  410. package/dist/{core/queryUtils.d.ts → views/incrementalView.d.ts} +6 -6
  411. package/dist/{core/queryUtils.js → views/incrementalView.js} +6 -6
  412. package/dist/webhooks/events.d.ts +2 -2
  413. package/dist/wire/index.d.ts +1 -34
  414. package/dist/wire/index.js +8 -49
  415. package/docs/agent-messaging.md +3 -3
  416. package/docs/agents.md +20 -13
  417. package/docs/api-keys.md +14 -10
  418. package/docs/api.md +27 -61
  419. package/docs/audit.md +6 -3
  420. package/docs/cli.md +41 -13
  421. package/docs/client-behavior.md +11 -9
  422. package/docs/concurrency-convention.md +49 -57
  423. package/docs/coordination.md +283 -121
  424. package/docs/data-sources.md +7 -5
  425. package/docs/debugging.md +39 -15
  426. package/docs/deployment.md +267 -0
  427. package/docs/examples/agent-human.md +49 -42
  428. package/docs/examples/ai-sdk-tool.md +69 -44
  429. package/docs/examples/existing-python-backend.md +8 -6
  430. package/docs/examples/nextjs.md +129 -47
  431. package/docs/examples/scoped-agent.md +46 -45
  432. package/docs/examples/server-agent.md +46 -26
  433. package/docs/groups.md +87 -30
  434. package/docs/guarantees.md +41 -12
  435. package/docs/how-it-works.md +38 -12
  436. package/docs/idempotency.md +126 -0
  437. package/docs/identity.md +77 -74
  438. package/docs/index.md +172 -86
  439. package/docs/integration-guide.md +31 -19
  440. package/docs/mcp.md +46 -21
  441. package/docs/migration.md +95 -18
  442. package/docs/operating-on-your-database.md +3 -1
  443. package/docs/projects.md +3 -1
  444. package/docs/quickstart.md +22 -5
  445. package/docs/react.md +31 -18
  446. package/docs/schema-contract.md +5 -3
  447. package/docs/session-settings.md +108 -0
  448. package/docs/sessions.md +4 -2
  449. package/docs/webhooks.md +12 -10
  450. package/llms.txt +48 -18
  451. package/package.json +21 -26
  452. package/dist/agent/Agent.d.ts +0 -366
  453. package/dist/agent/Agent.js +0 -514
  454. package/dist/agent/index.d.ts +0 -115
  455. package/dist/agent/index.js +0 -128
  456. package/dist/agent/session.d.ts +0 -93
  457. package/dist/agent/session.js +0 -149
  458. package/dist/agent/types.d.ts +0 -68
  459. package/dist/agent/types.js +0 -9
  460. package/dist/cli.cjs +0 -286329
  461. package/dist/client/durableWrites.d.ts +0 -21
  462. package/dist/client/httpClient.d.ts +0 -80
  463. package/dist/coordination/schema.d.ts +0 -722
  464. package/dist/coordination/schema.js +0 -578
  465. package/dist/schema/openapi.d.ts +0 -29
  466. package/dist/schema/openapi.js +0 -124
  467. package/dist/testing/fixtures/bootstrap.d.ts +0 -49
  468. package/dist/testing/fixtures/bootstrap.js +0 -59
  469. package/dist/testing/fixtures/deltas.d.ts +0 -83
  470. package/dist/testing/fixtures/deltas.js +0 -136
  471. package/dist/testing/fixtures/models.d.ts +0 -83
  472. package/dist/testing/fixtures/models.js +0 -272
  473. package/dist/testing/helpers/reactWrapper.d.ts +0 -69
  474. package/dist/testing/helpers/reactWrapper.js +0 -67
  475. package/dist/testing/helpers/syncEngineHarness.d.ts +0 -54
  476. package/dist/testing/helpers/syncEngineHarness.js +0 -73
  477. package/dist/testing/helpers/wait.d.ts +0 -30
  478. package/dist/testing/helpers/wait.js +0 -49
  479. package/dist/testing/index.d.ts +0 -23
  480. package/dist/testing/index.js +0 -33
  481. package/dist/testing/mocks/FakeDatabase.d.ts +0 -18
  482. package/dist/testing/mocks/FakeDatabase.js +0 -10
  483. package/dist/testing/mocks/MockMutationExecutor.d.ts +0 -87
  484. package/dist/testing/mocks/MockMutationExecutor.js +0 -192
  485. package/dist/testing/mocks/MockNetworkMonitor.d.ts +0 -20
  486. package/dist/testing/mocks/MockNetworkMonitor.js +0 -46
  487. package/dist/testing/mocks/MockSyncContext.d.ts +0 -51
  488. package/dist/testing/mocks/MockSyncContext.js +0 -71
  489. package/dist/testing/mocks/MockSyncStore.d.ts +0 -88
  490. package/dist/testing/mocks/MockSyncStore.js +0 -171
  491. package/dist/testing/mocks/MockWebSocket.d.ts +0 -71
  492. package/dist/testing/mocks/MockWebSocket.js +0 -118
  493. package/dist/transactions/durableWriteStore.js +0 -30
  494. package/dist/utils/duration.d.ts +0 -25
  495. package/dist/utils/json.js +0 -88
  496. package/dist/wire/errorEnvelope.d.ts +0 -55
  497. package/dist/wire/frames.d.ts +0 -197
  498. package/dist/wire/frames.js +0 -49
  499. package/dist/wire/listEnvelope.js +0 -18
  500. package/docs/interaction-model.md +0 -97
  501. /package/dist/{core → query}/QueryProcessor.d.ts +0 -0
  502. /package/dist/{core → query}/QueryProcessor.js +0 -0
  503. /package/dist/{core/storeContract.js → storeContract.js} +0 -0
  504. /package/dist/{core → stores}/openIDBWithTimeout.d.ts +0 -0
  505. /package/dist/{core → stores}/openIDBWithTimeout.js +0 -0
  506. /package/dist/{client → transaction/auth}/credentialEndpoint.d.ts +0 -0
  507. /package/dist/{client → transaction/auth}/credentialEndpoint.js +0 -0
  508. /package/dist/{auth → transaction/auth}/credentialPolicy.d.ts +0 -0
  509. /package/dist/{auth → transaction/auth}/credentialPolicy.js +0 -0
  510. /package/dist/{auth → transaction/auth}/credentialSource.js +0 -0
  511. /package/dist/{client → transaction/auth}/hostedEndpoints.d.ts +0 -0
  512. /package/dist/{client → transaction/auth}/hostedEndpoints.js +0 -0
  513. /package/dist/{client → transaction}/persistence.d.ts +0 -0
  514. /package/dist/{client → transaction}/persistence.js +0 -0
  515. /package/dist/{client → transaction/resources}/functionalUpdate.d.ts +0 -0
  516. /package/dist/{client → transaction/resources}/functionalUpdate.js +0 -0
  517. /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.d.ts +0 -0
  518. /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.js +0 -0
  519. /package/dist/{client → transaction/transport}/httpTransport.d.ts +0 -0
  520. /package/dist/{types → transaction/types}/modelData.d.ts +0 -0
  521. /package/dist/{types → transaction/types}/modelData.js +0 -0
  522. /package/dist/{types → transaction/types}/participant.d.ts +0 -0
  523. /package/dist/{types → transaction/types}/participant.js +0 -0
  524. /package/dist/{types → transaction/types}/streams.js +0 -0
  525. /package/dist/{utils → transaction/utils}/asyncIterator.d.ts +0 -0
  526. /package/dist/{utils → transaction/utils}/asyncIterator.js +0 -0
  527. /package/dist/{wire → transaction/wire}/bootstrapReason.d.ts +0 -0
  528. /package/dist/{wire → transaction/wire}/bootstrapReason.js +0 -0
  529. /package/dist/{wire → transaction/wire}/protocol.d.ts +0 -0
  530. /package/dist/{wire → transaction/wire}/protocol.js +0 -0
  531. /package/dist/{wire → transaction/wire}/protocolVersion.d.ts +0 -0
  532. /package/dist/{wire → transaction/wire}/protocolVersion.js +0 -0
  533. /package/dist/transactions/{UnconfirmedWrites.d.ts → mutations/UnconfirmedWrites.d.ts} +0 -0
  534. /package/dist/transactions/{UnconfirmedWrites.js → mutations/UnconfirmedWrites.js} +0 -0
  535. /package/dist/transactions/{optimisticApply.js → mutations/optimisticApply.js} +0 -0
  536. /package/dist/{core → views}/ViewRegistry.js +0 -0
@@ -7,10 +7,11 @@
7
7
  * operations, and the source mutations it supersedes.
8
8
  */
9
9
  import { z } from 'zod';
10
- import { readDependencySchema, trackDependencySchema } from '../coordination/schema.js';
11
- import { commitOperationSchema } from '../wire/frames.js';
12
- import { correlationIdSchema } from '../wire/commit.js';
10
+ import { readDependencySchema, trackDependencySchema } from '../../coordination/schema.js';
11
+ import { wireCommitOperationSchema } from '../../wire/frames.js';
12
+ import { correlationIdSchema } from '../../wire/commit.js';
13
13
  import { idempotencyKeySchema } from './idempotencyKey.js';
14
+ import { snapshotJsonValue } from '../../utils/json.js';
14
15
  export const COMMIT_ENVELOPE_VERSION = 1;
15
16
  export const COMMIT_ENVELOPE_RECORD_PREFIX = 'commit-envelope:';
16
17
  /** One transaction's position in a commit; this is not the envelope itself. */
@@ -24,7 +25,7 @@ export const commitEnvelopeMemberSchema = z
24
25
  })
25
26
  .refine(({ operationIndex, operationCount }) => operationIndex < operationCount, { message: 'operationIndex must be smaller than operationCount' });
26
27
  /** One operation stored exactly as the current commit transport sends it. */
27
- export const durableCommitOperationSchema = commitOperationSchema
28
+ export const durableCommitOperationSchema = wireCommitOperationSchema
28
29
  .pick({
29
30
  type: true,
30
31
  model: true,
@@ -48,7 +49,6 @@ export const durableCommitOperationSchema = commitOperationSchema
48
49
  .optional(),
49
50
  });
50
51
  const durableCommitOptionsSchema = z.strictObject({
51
- causedByTaskId: z.string().min(1).nullable().optional(),
52
52
  reads: z.array(readDependencySchema).nullable().optional(),
53
53
  track: z.array(trackDependencySchema).nullable().optional(),
54
54
  });
@@ -145,9 +145,9 @@ export function createCommitEnvelopeMember(value) {
145
145
  return commitEnvelopeMemberSchema.parse(value);
146
146
  }
147
147
  /**
148
- * Freezes the exact JSON request that will be persisted and sent. The JSON
149
- * round-trip deliberately applies the same Date/undefined semantics as the
150
- * WebSocket transport before the request fingerprint becomes durable.
148
+ * Freezes the exact JSON request that will be persisted and sent. The shared
149
+ * snapshot contract makes framework proxies plain and rejects values that
150
+ * would be lost or corrupted by JSON serialization.
151
151
  */
152
152
  export function createDurableCommitEnvelope(value) {
153
153
  const candidate = {
@@ -157,9 +157,5 @@ export function createDurableCommitEnvelope(value) {
157
157
  storageVersion: COMMIT_ENVELOPE_VERSION,
158
158
  timestamp: value.sealedAt,
159
159
  };
160
- const serialized = JSON.stringify(candidate);
161
- if (serialized === undefined) {
162
- throw new TypeError('Commit envelope is not JSON serializable');
163
- }
164
- return durableCommitEnvelopeSchema.parse(JSON.parse(serialized));
160
+ return durableCommitEnvelopeSchema.parse(snapshotJsonValue(candidate, '$.commitEnvelope'));
165
161
  }
@@ -4,7 +4,7 @@ export declare const HTTP_COMMIT_ENVELOPE_VERSION: 1;
4
4
  export declare const HTTP_COMMIT_ENVELOPE_PREFIX = "http-commit-envelope:";
5
5
  /** Stay one hour inside the server's 24-hour idempotency retention window. */
6
6
  export declare const HTTP_COMMIT_REPLAY_WINDOW_MS: number;
7
- /** Apply normal JSON semantics once, then make object-key order canonical. */
7
+ /** Snapshot the JSON contract once, then make object-key order canonical. */
8
8
  export declare function canonicalHttpCommitBody(value: unknown): string;
9
9
  export declare const durableHttpCommitEnvelopeSchema: z.ZodObject<{
10
10
  id: z.ZodString;
@@ -30,11 +30,18 @@ export declare const durableHttpCommitEnvelopeSchema: z.ZodObject<{
30
30
  timestamp: z.ZodNumber;
31
31
  }, z.core.$strict>;
32
32
  export type DurableHttpCommitEnvelope = z.infer<typeof durableHttpCommitEnvelopeSchema>;
33
+ /**
34
+ * The HTTP verbs a durable commit envelope can carry, projected out of the
35
+ * persisted schema above. Callers that build, seal, or dispatch an envelope
36
+ * take this rather than restating the verbs: the envelope is a stored contract,
37
+ * so a verb the schema does not accept must not be constructible.
38
+ */
39
+ export type DurableHttpCommitMethod = DurableHttpCommitEnvelope['request']['method'];
33
40
  export declare function httpCommitEnvelopeRecordId(idempotencyKey: string, scopeNamespace?: string): string;
34
41
  export declare function createDurableHttpCommitEnvelope(input: {
35
42
  idempotencyKey: string;
36
43
  request: {
37
- method: 'POST' | 'PATCH' | 'DELETE';
44
+ method: DurableHttpCommitMethod;
38
45
  path: string;
39
46
  body: unknown;
40
47
  };
@@ -1,9 +1,9 @@
1
1
  /** Crash-durable exact HTTP request used by the stateless agent client. */
2
2
  import { z } from 'zod';
3
3
  import { v5 as uuidv5 } from 'uuid';
4
- import { stableStringify } from '../utils/json.js';
5
- import { correlationIdSchema } from '../wire/commit.js';
6
- import { PROTOCOL_VERSION } from '../wire/protocolVersion.js';
4
+ import { snapshotJsonValue, stableStringify } from '../../utils/json.js';
5
+ import { correlationIdSchema } from '../../wire/commit.js';
6
+ import { PROTOCOL_VERSION } from '../../wire/protocolVersion.js';
7
7
  import { idempotencyKeySchema } from './idempotencyKey.js';
8
8
  export const HTTP_COMMIT_ENVELOPE_VERSION = 1;
9
9
  export const HTTP_COMMIT_ENVELOPE_PREFIX = 'http-commit-envelope:';
@@ -33,13 +33,9 @@ function hasSafeModelPathSegments(path) {
33
33
  return false;
34
34
  }
35
35
  }
36
- /** Apply normal JSON semantics once, then make object-key order canonical. */
36
+ /** Snapshot the JSON contract once, then make object-key order canonical. */
37
37
  export function canonicalHttpCommitBody(value) {
38
- const serialized = JSON.stringify(value);
39
- if (serialized === undefined) {
40
- throw new TypeError('HTTP commit body is not JSON serializable');
41
- }
42
- return stableStringify(JSON.parse(serialized));
38
+ return stableStringify(snapshotJsonValue(value, '$.body'));
43
39
  }
44
40
  export const durableHttpCommitEnvelopeSchema = z
45
41
  .strictObject({
@@ -1,9 +1,14 @@
1
1
  /**
2
- * Product-facing persistence contract for writes that must survive a process
3
- * restart or an ambiguous network response.
2
+ * The persisted shape of a write awaiting a definitive outcome.
4
3
  *
5
- * The engine implements this contract with a transactional outbox internally,
6
- * but callers should only need to think in terms of pending durable writes.
4
+ * Owns one authoritative union over the two durable commit envelopes — the
5
+ * WebSocket envelope and its HTTP counterpart so an injected store and the
6
+ * engine that reads back from it agree on exactly one set of records. The
7
+ * envelope schemas in this directory remain authoritative for their own fields;
8
+ * this module only unions them.
9
+ *
10
+ * The port that persists these records is a behavior contract, not a persisted
11
+ * shape, so it lives outside this directory in `src/durableWrites.ts`.
7
12
  */
8
13
  import { z } from 'zod';
9
14
  /** Every write shape that Ablo may ask an injected store to persist. */
@@ -42,12 +47,11 @@ export declare const pendingWriteSchema: z.ZodUnion<readonly [z.ZodObject<{
42
47
  }, z.core.$strip>>;
43
48
  sourceMutationIds: z.ZodDefault<z.ZodArray<z.ZodString>>;
44
49
  commitOptions: z.ZodDefault<z.ZodObject<{
45
- causedByTaskId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
46
50
  reads: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
47
51
  model: z.ZodString;
48
52
  id: z.ZodString;
49
53
  readAt: z.ZodNumber;
50
- fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
54
+ fields: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
51
55
  onStale: z.ZodOptional<z.ZodEnum<{
52
56
  reject: "reject";
53
57
  overwrite: "overwrite";
@@ -63,8 +67,8 @@ export declare const pendingWriteSchema: z.ZodUnion<readonly [z.ZodObject<{
63
67
  }>>;
64
68
  }, z.core.$strip>]>>>>;
65
69
  track: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
66
- model: z.ZodString;
67
70
  id: z.ZodString;
71
+ model: z.ZodString;
68
72
  readAt: z.ZodOptional<z.ZodNumber>;
69
73
  }, z.core.$strip>, z.ZodObject<{
70
74
  group: z.ZodString;
@@ -106,33 +110,3 @@ export declare const pendingWriteSchema: z.ZodUnion<readonly [z.ZodObject<{
106
110
  timestamp: z.ZodNumber;
107
111
  }, z.core.$strict>]>;
108
112
  export type PendingWrite = z.infer<typeof pendingWriteSchema>;
109
- /**
110
- * Persistence port used by `Ablo({ durableWrites })`.
111
- *
112
- * `seal` is the durability boundary: it must atomically persist the exact write
113
- * and consume the staged records that write supersedes. Resolving this promise
114
- * authorizes Ablo to dispatch the request, so adapters must never report success
115
- * before the data is durable.
116
- */
117
- export interface DurableWriteStore {
118
- /**
119
- * Atomically reserve a pending write and consume the staged records it owns.
120
- * The same id + same request is idempotent; the same id + a different request
121
- * must be rejected. For a source-accepted envelope, a re-seal may add the
122
- * monotonic `acceptedAt`/`correlationId` evidence and the store must preserve
123
- * that upgrade atomically rather than ignoring it.
124
- */
125
- seal(write: PendingWrite, consumedRecordIds: readonly string[]): Promise<void>;
126
- /** Load all unacknowledged writes. Stored data is treated as untrusted. */
127
- list(): Promise<readonly unknown[]>;
128
- /** Remove one write only after its outcome is definitive. */
129
- remove(writeId: string): Promise<void>;
130
- }
131
- /** Runtime validation for injected adapters, including JavaScript consumers. */
132
- export declare const durableWriteStoreSchema: z.ZodCustom<DurableWriteStore, DurableWriteStore>;
133
- /** Options for crash-durable `create`, `update`, and `delete` calls. */
134
- export declare const durableWritesConfigSchema: z.ZodObject<{
135
- store: z.ZodCustom<DurableWriteStore, DurableWriteStore>;
136
- namespace: z.ZodOptional<z.ZodString>;
137
- }, z.core.$strict>;
138
- export type DurableWritesConfig = z.infer<typeof durableWritesConfigSchema>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The persisted shape of a write awaiting a definitive outcome.
3
+ *
4
+ * Owns one authoritative union over the two durable commit envelopes — the
5
+ * WebSocket envelope and its HTTP counterpart — so an injected store and the
6
+ * engine that reads back from it agree on exactly one set of records. The
7
+ * envelope schemas in this directory remain authoritative for their own fields;
8
+ * this module only unions them.
9
+ *
10
+ * The port that persists these records is a behavior contract, not a persisted
11
+ * shape, so it lives outside this directory in `src/durableWrites.ts`.
12
+ */
13
+ import { z } from 'zod';
14
+ import { durableCommitEnvelopeSchema } from './commitEnvelope.js';
15
+ import { durableHttpCommitEnvelopeSchema } from './httpCommitEnvelope.js';
16
+ /** Every write shape that Ablo may ask an injected store to persist. */
17
+ export const pendingWriteSchema = z.union([
18
+ durableCommitEnvelopeSchema,
19
+ durableHttpCommitEnvelopeSchema,
20
+ ]);
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Builds the outgoing frames the sync WebSocket sends on the commit path, and
3
+ * provides the single place claim events are traced. These are stateless
4
+ * helpers that hold no socket state, so both the transport and its frame
5
+ * dispatch can share them.
6
+ */
7
+ import type { CommitMessage } from '../wire/index.js';
8
+ import type { CommitAck as CanonicalCommitAck } from '../wire/commit.js';
9
+ import type { OnStaleMode, StaleNotification, ReadDependency, TrackDependency } from '../coordination/schema.js';
10
+ import type { ClaimAcquired, ClaimGranted, ClaimQueued, ClaimLost, ClaimRejection, ClaimExpired } from '../coordination/schema.js';
11
+ import type { Logger } from '../logger.js';
12
+ import type { SocketObservability } from '../observability.js';
13
+ /**
14
+ * The value a commit acknowledgement resolves to. `notifications` is present
15
+ * only when a guarded write (`onStale: 'notify'`) met a concurrent change; it
16
+ * carries the advisory signal that lets the writer self-heal, and the same
17
+ * signal also arrives on the `conflict:notified` event.
18
+ */
19
+ export type CommitAck = CanonicalCommitAck;
20
+ /**
21
+ * The slice of a queued client mutation the commit frame reads — a structural
22
+ * port, so the reactive engine's fatter `MutationOperation` satisfies it
23
+ * without this module importing the consumer package.
24
+ */
25
+ export interface CommitFrameOperation {
26
+ readonly type: string;
27
+ readonly model: string;
28
+ readonly id: string;
29
+ readonly input?: Record<string, unknown>;
30
+ readonly transactionId?: string;
31
+ readonly readAt?: number | null;
32
+ readonly onStale?: OnStaleMode | null;
33
+ readonly fenceToken?: number | null;
34
+ }
35
+ /**
36
+ * Converts the client's list of {@link CommitFrameOperation} values into the wire
37
+ * {@link CommitMessage} the server accepts. This is the one place the loosely
38
+ * typed operation — its `type` is a string, and it carries client-only
39
+ * `options` the server never reads — becomes the strict wire contract. Mapping
40
+ * each field by hand means a change to {@link WireCommitOperation} fails to compile
41
+ * here; the single `as` cast narrows the validated `type` to the wire union and
42
+ * is the only place that loosening happens.
43
+ */
44
+ export declare function buildCommitFrame(operations: readonly CommitFrameOperation[], clientTxId: string, reads?: readonly ReadDependency[] | null, track?: readonly TrackDependency[] | null): CommitMessage;
45
+ /**
46
+ * Defensively validate the optional `notifications` array off a commit ack.
47
+ * Untrusted wire data — a malformed entry is dropped rather than throwing,
48
+ * so a bad notification never sinks an otherwise-successful commit.
49
+ */
50
+ export declare function parseNotifications(raw: unknown): StaleNotification[] | undefined;
51
+ /** The reporting ports a claim trace writes through — supplied by the caller
52
+ * (the frame dispatch passes its session's own ports). */
53
+ export interface ClaimTracePorts {
54
+ readonly logger: Logger;
55
+ readonly observability: SocketObservability;
56
+ }
57
+ /**
58
+ * Which frame reports each phase of a claim's life.
59
+ *
60
+ * The correspondence is real and was previously implicit: six dispatch handlers
61
+ * each passed their own payload alongside a phase they picked by hand, and
62
+ * nothing checked that the two matched. Stating it once means a caller cannot
63
+ * label a rejection as an acquisition.
64
+ *
65
+ * Every value is the `z.infer` of the schema the dispatcher parsed with, so no
66
+ * field is restated here — this maps existing types, it does not describe them.
67
+ */
68
+ interface ClaimFrameByPhase {
69
+ acquired: ClaimAcquired;
70
+ granted: ClaimGranted;
71
+ queued: ClaimQueued;
72
+ lost: ClaimLost;
73
+ rejected: ClaimRejection;
74
+ expired: ClaimExpired;
75
+ }
76
+ /**
77
+ * The single place claim events are traced. Every `claim_*` frame passes
78
+ * through here, so a developer debugging a collision gets one consistent record
79
+ * — a console line and a structured capture — without each frame case
80
+ * re-deriving the row and holder shape.
81
+ *
82
+ * The payload arrives already validated against its frame's schema, so this
83
+ * reads it as the shape it is rather than re-narrowing an untyped record. That
84
+ * distinction is not cosmetic: while this took `Record<string, unknown>` it
85
+ * read `actor`, `participantKind`, and `description` off frames that carry none
86
+ * of them, and every one of those reads silently produced `undefined` because a
87
+ * string key never has to exist.
88
+ */
89
+ export declare function recordClaim<P extends keyof ClaimFrameByPhase>(ports: ClaimTracePorts, phase: P, payload: ClaimFrameByPhase[P]): void;
90
+ export {};
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Builds the outgoing frames the sync WebSocket sends on the commit path, and
3
+ * provides the single place claim events are traced. These are stateless
4
+ * helpers that hold no socket state, so both the transport and its frame
5
+ * dispatch can share them.
6
+ */
7
+ import { claimEventReasonSchema, staleNotificationSchema, } from '../coordination/schema.js';
8
+ import { formatClaim } from '../coordination/trace.js';
9
+ import { modelTarget } from '../coordination/locator.js';
10
+ /**
11
+ * Converts the client's list of {@link CommitFrameOperation} values into the wire
12
+ * {@link CommitMessage} the server accepts. This is the one place the loosely
13
+ * typed operation — its `type` is a string, and it carries client-only
14
+ * `options` the server never reads — becomes the strict wire contract. Mapping
15
+ * each field by hand means a change to {@link WireCommitOperation} fails to compile
16
+ * here; the single `as` cast narrows the validated `type` to the wire union and
17
+ * is the only place that loosening happens.
18
+ */
19
+ export function buildCommitFrame(operations, clientTxId, reads, track) {
20
+ const payload = {
21
+ operations: operations.map((op) => ({
22
+ type: op.type,
23
+ model: op.model,
24
+ id: op.id,
25
+ input: op.input,
26
+ transactionId: op.transactionId,
27
+ readAt: op.readAt,
28
+ onStale: op.onStale,
29
+ fenceToken: op.fenceToken,
30
+ })),
31
+ clientTxId,
32
+ };
33
+ // The batch premise: the rows or groups the writer read before committing.
34
+ if (reads && reads.length > 0)
35
+ payload.reads = [...reads];
36
+ // Durable premises the writer is registering: the rows or groups it
37
+ // wants to keep hearing about after this commit, delivered on a future receipt.
38
+ if (track && track.length > 0)
39
+ payload.track = [...track];
40
+ return { type: 'commit', payload };
41
+ }
42
+ /**
43
+ * Defensively validate the optional `notifications` array off a commit ack.
44
+ * Untrusted wire data — a malformed entry is dropped rather than throwing,
45
+ * so a bad notification never sinks an otherwise-successful commit.
46
+ */
47
+ export function parseNotifications(raw) {
48
+ if (!Array.isArray(raw) || raw.length === 0)
49
+ return undefined;
50
+ const out = [];
51
+ for (const entry of raw) {
52
+ const parsed = staleNotificationSchema.safeParse(entry);
53
+ if (parsed.success)
54
+ out.push(parsed.data);
55
+ }
56
+ return out.length > 0 ? out : undefined;
57
+ }
58
+ // The phases this map covers and the phases a ClaimEvent can report are the
59
+ // same set. Adding one to either without the other stops compiling here.
60
+ const _phaseCoverage = true;
61
+ void _phaseCoverage;
62
+ /**
63
+ * The single place claim events are traced. Every `claim_*` frame passes
64
+ * through here, so a developer debugging a collision gets one consistent record
65
+ * — a console line and a structured capture — without each frame case
66
+ * re-deriving the row and holder shape.
67
+ *
68
+ * The payload arrives already validated against its frame's schema, so this
69
+ * reads it as the shape it is rather than re-narrowing an untyped record. That
70
+ * distinction is not cosmetic: while this took `Record<string, unknown>` it
71
+ * read `actor`, `participantKind`, and `description` off frames that carry none
72
+ * of them, and every one of those reads silently produced `undefined` because a
73
+ * string key never has to exist.
74
+ */
75
+ export function recordClaim(ports, phase, payload) {
76
+ // Widened so the members can be told apart with `in`. The parameter above
77
+ // stays correlated to `phase`, which is what the widening cannot undo.
78
+ const frame = payload;
79
+ const target = 'target' in frame ? frame.target : undefined;
80
+ // The holder rides on the rejection and queued frames, with a summary of
81
+ // their claim beside it. Collecting it is the whole of "name the
82
+ // counterparty" — the wire has carried it all along and this projection used
83
+ // to flatten it into one string alongside the cause.
84
+ const counterparty = {
85
+ ...('heldBy' in frame && frame.heldBy !== undefined
86
+ ? { actor: frame.heldBy }
87
+ : {}),
88
+ ...('heldByKind' in frame && frame.heldByKind !== undefined
89
+ ? { participantKind: frame.heldByKind }
90
+ : {}),
91
+ ...('heldByClaimId' in frame && frame.heldByClaimId !== undefined
92
+ ? { claimId: frame.heldByClaimId }
93
+ : {}),
94
+ ...('heldByExpiresAt' in frame && frame.heldByExpiresAt !== undefined
95
+ ? { expiresAt: frame.heldByExpiresAt }
96
+ : {}),
97
+ ...('heldByClaim' in frame && frame.heldByClaim?.description !== undefined
98
+ ? { description: frame.heldByClaim.description }
99
+ : {}),
100
+ };
101
+ // `reason` is a plain string on the wire, which is frozen, so an older server
102
+ // may send a word the closed set does not list. One that parses becomes the
103
+ // typed reason; one that does not is absent rather than passed off as prose.
104
+ const parsedReason = 'reason' in frame ? claimEventReasonSchema.safeParse(frame.reason) : undefined;
105
+ const event = {
106
+ phase,
107
+ claimId: frame.claimId,
108
+ ...(target ? modelTarget(target) : {}),
109
+ ...(target?.field !== undefined ? { field: target.field } : {}),
110
+ // No claim frame names an actor of its own; the only participant one
111
+ // carries is the holder that blocked it.
112
+ ...('heldBy' in frame && frame.heldBy !== undefined
113
+ ? { actor: frame.heldBy }
114
+ : {}),
115
+ ...('position' in frame ? { position: frame.position } : {}),
116
+ ...(parsedReason?.success ? { reason: parsedReason.data } : {}),
117
+ ...('policyReason' in frame && frame.policyReason !== undefined
118
+ ? { policyReason: frame.policyReason }
119
+ : {}),
120
+ ...(Object.keys(counterparty).length > 0 ? { heldBy: counterparty } : {}),
121
+ };
122
+ const message = formatClaim(event);
123
+ // A rejection or lost lease is the collision a developer is actively
124
+ // debugging → warn (shows at the default log level). The routine events
125
+ // (acquired/queued/granted/expired) are debug-only so they never drown the
126
+ // console until you opt in with `new Ablo({ debug: true })`.
127
+ const isCollision = phase === 'rejected' || phase === 'lost';
128
+ if (isCollision)
129
+ ports.logger.warn(message);
130
+ else
131
+ ports.logger.debug(message);
132
+ ports.observability.breadcrumb(message, 'sync.coordination', isCollision ? 'warning' : 'info');
133
+ ports.observability.captureClaim(event);
134
+ }
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Owns the sync engine's connection lifecycle: the state machine that carries a
3
+ * client from a healthy connection, through a dropout, and back to live. It
4
+ * watches the browser's online/offline and visibility events, probes real
5
+ * connectivity and session validity with {@link probeNetwork}, applies retry
6
+ * backoff with a ceiling and jitter, and runs a watchdog for the cases where
7
+ * the browser never fires an event (VPN flips, captive portals). When it
8
+ * decides to recover, it drives the reconnect sequence — bootstrap, then
9
+ * WebSocket connect — through the {@link ConnectionCallbacks.onReconnect}
10
+ * callback and reacts to the outcome.
11
+ *
12
+ * It deliberately does not perform the bootstrap, local-storage, or object-pool
13
+ * work itself; that lives in the embedding store, which the manager reaches
14
+ * only through its callbacks. One manager is created per store, started on the
15
+ * first successful connect and disposed on teardown.
16
+ *
17
+ * This is a plain state machine, not a reactive object: it lives in the
18
+ * settlement core, which carries no reactivity runtime (ADR 0016). A consumer
19
+ * that wants to render recovery progress mirrors the transitions through
20
+ * {@link ConnectionCallbacks.onStateChange} into its own observable state —
21
+ * which is what the reactive engine's store does.
22
+ *
23
+ * CONNECTED ──(socket drop)──► PROBING_NETWORK ──► RECONNECTING ──► CONNECTED
24
+ * │ │ │
25
+ * (network lost) ▼ ▼
26
+ * ▼ SESSION_EXPIRED BACKOFF ──► PROBING_NETWORK
27
+ * OFFLINE ──(online)──► PROBING_NETWORK
28
+ * │
29
+ * ▼
30
+ * WAITING_FOR_NETWORK
31
+ *
32
+ * Three behaviors are worth calling out. A network return or tab focus during a
33
+ * backoff delay jumps straight to probing instead of waiting out the full
34
+ * interval. Reaching the retry ceiling while the browser reports offline parks
35
+ * in `waiting_for_network` rather than hard-reloading a browser that has no
36
+ * network. And a socket drop (close code 1006) goes straight to probing rather
37
+ * than the passive `offline` state — 1006 is generated locally and carries no
38
+ * connectivity signal, so on a healthy machine no online/offline event ever
39
+ * fires; only a genuine operating-system network loss parks in `offline` to
40
+ * wait for the `online` event.
41
+ */
42
+ import { type ProbeResult } from './networkProbe.js';
43
+ import type { AuthTokenGetter } from '../auth/credentialSource.js';
44
+ import type { CredentialRefreshOutcome } from './credentialLifecycle.js';
45
+ import { type Logger } from '../logger.js';
46
+ import { type TransportObservability } from '../observability.js';
47
+ export type ConnectionState = 'connected' | 'offline' | 'probing_network' | 'validating_session' | 'refreshing_credential' | 'reconnecting' | 'backoff' | 'waiting_for_network' | 'auth_blocked' | 'session_expired';
48
+ export type ConnectionEvent = {
49
+ type: 'NETWORK_LOST';
50
+ } | {
51
+ type: 'NETWORK_ONLINE';
52
+ } | {
53
+ type: 'TAB_VISIBLE';
54
+ } | {
55
+ type: 'WS_CONNECTED';
56
+ } | {
57
+ type: 'WS_DISCONNECTED';
58
+ } | {
59
+ type: 'WS_SESSION_ERROR';
60
+ } | {
61
+ type: 'WS_HANDSHAKE_FAILED';
62
+ } | {
63
+ type: 'PROBE_SUCCESS';
64
+ sessionValid: boolean;
65
+ } | {
66
+ type: 'PROBE_AUTH_BLOCKED';
67
+ }
68
+ /** The probe saw an expired ephemeral access key (`access_credential_expiry`).
69
+ * Recoverable: re-mint a fresh `ek_`/`rk_` and re-probe — never a sign-out. */
70
+ | {
71
+ type: 'PROBE_CREDENTIAL_STALE';
72
+ } | {
73
+ type: 'PROBE_FAILED';
74
+ }
75
+ /** A fresh access credential is available (the re-mint succeeded, or one was
76
+ * pushed in via `setAuthToken`). Re-probe so a parked connection picks it up. */
77
+ | {
78
+ type: 'CREDENTIAL_REFRESHED';
79
+ } | {
80
+ type: 'RECONNECT_SUCCESS';
81
+ } | {
82
+ type: 'RECONNECT_FAILED';
83
+ } | {
84
+ type: 'BACKOFF_ELAPSED';
85
+ } | {
86
+ type: 'BOOTSTRAP_FAILED_SESSION';
87
+ } | {
88
+ type: 'MANUAL_RETRY';
89
+ };
90
+ export interface ConnectionCallbacks {
91
+ /** Run bootstrap + WebSocket reconnect. Returns the outcome. */
92
+ onReconnect: () => Promise<'success' | 'session_error' | 'network_error'>;
93
+ /**
94
+ * Re-mints the short-lived access credential (the `ek_`/`rk_`) and pushes it
95
+ * into the credential source, then reports the outcome. Invoked in the
96
+ * `refreshing_credential` state — that is, when a probe found the access key
97
+ * stale (`PROBE_CREDENTIAL_STALE`). The three outcomes map onto recovery:
98
+ * - `'refreshed'` → a fresh credential is in place; re-probe and reconnect.
99
+ * - `'session_error'` → the long-lived login itself is gone (the mint
100
+ * returned null, a 401/403); terminal, so sign out.
101
+ * - `'network_error'` → the mint endpoint was unreachable (offline, 5xx, or
102
+ * a throw); transient, so back off and retry rather
103
+ * than sign out.
104
+ * Optional: a deployment with no re-mint path (for example a static `apiKey`)
105
+ * omits it, and the state machine falls back to a plain re-probe.
106
+ */
107
+ onRefreshCredential?: () => Promise<CredentialRefreshOutcome>;
108
+ /** Called when the session is confirmed expired — route to signin. */
109
+ onSessionExpired: () => void;
110
+ /** Called to tear down the WebSocket when entering a dead state. */
111
+ onDisconnectWebSocket: () => void;
112
+ /**
113
+ * Fires on every state transition. It lets the embedding store mirror
114
+ * recovery progress into its visible `syncStatus`, so the UI can show
115
+ * "Reconnecting…" instead of a sticky "offline" while the machine cycles
116
+ * through `probing_network` → `reconnecting` → `backoff`. Optional; when
117
+ * omitted, the state machine is simply opaque to the UI.
118
+ */
119
+ onStateChange?: (next: ConnectionState, prev: ConnectionState) => void;
120
+ }
121
+ export interface ConnectionManagerOptions {
122
+ /**
123
+ * Sync-server base URL used for probes. Falls back to the env-based
124
+ * default of `probeNetwork`.
125
+ */
126
+ baseUrl?: string;
127
+ /**
128
+ * Current bearer credential for authenticated probes. Read lazily so token
129
+ * refreshes pushed through `Ablo.setAuthToken()` are used by the next probe
130
+ * without recreating the manager.
131
+ */
132
+ getAuthToken?: AuthTokenGetter;
133
+ /** Override retry ceilings / jitter. Production should leave defaults. */
134
+ backoff?: Partial<typeof DEFAULT_BACKOFF>;
135
+ /** Where transitions are logged. Defaults to silent. */
136
+ logger?: Logger;
137
+ /** Where dead-end states are reported. Defaults to silent. */
138
+ observability?: TransportObservability;
139
+ }
140
+ declare const DEFAULT_BACKOFF: {
141
+ readonly BASE_MS: 2000;
142
+ readonly MAX_MS: 30000;
143
+ readonly MAX_ATTEMPTS: 8;
144
+ readonly JITTER: 0.15;
145
+ };
146
+ export declare class ConnectionManager {
147
+ state: ConnectionState;
148
+ offlineSince: Date | null;
149
+ attempt: number;
150
+ lastProbeResult: ProbeResult | null;
151
+ private callbacks;
152
+ private backoffTimer;
153
+ private debounceTimer;
154
+ private watchdogTimer;
155
+ private stuckCycles;
156
+ /** Consecutive access-key re-mints in the current recovery cycle; reset on
157
+ * reaching `connected`. See {@link MAX_CREDENTIAL_REFRESH_ATTEMPTS}. */
158
+ private credentialRefreshAttempts;
159
+ private disposed;
160
+ private readonly baseUrl?;
161
+ private readonly getAuthToken?;
162
+ private readonly backoff;
163
+ private readonly logger;
164
+ private readonly observability;
165
+ private handleBrowserOnline;
166
+ private handleBrowserOffline;
167
+ private handleVisibilityChange;
168
+ constructor(options?: ConnectionManagerOptions);
169
+ start(callbacks: ConnectionCallbacks): void;
170
+ dispose(): void;
171
+ send(event: ConnectionEvent): void;
172
+ private transition;
173
+ private onEnterState;
174
+ /**
175
+ * FSM effects are fire-and-forget by design (`onEnterState` is sync). Each
176
+ * effect catches its own operational failures and maps them onto an FSM
177
+ * event, so a rejection here means the machine wedged mid-transition
178
+ * (`send()` or a transition listener threw) with no retry timer armed past
179
+ * it — capture it instead of losing the reconnect loop silently.
180
+ */
181
+ private captureEffectFailure;
182
+ private runProbe;
183
+ /**
184
+ * Re-mint the short-lived access key on `refreshing_credential`. Delegates to
185
+ * the `onRefreshCredential` callback (which mints a fresh `ek_`/`rk_` from the
186
+ * still-valid login and pushes it into the credential source) and maps its
187
+ * tri-state outcome onto the FSM:
188
+ * - `refreshed` → `CREDENTIAL_REFRESHED` → re-probe & reconnect.
189
+ * - `session_error` → `BOOTSTRAP_FAILED_SESSION` → sign out (login is gone).
190
+ * - `network_error` → `RECONNECT_FAILED` → back off & retry (never sign out).
191
+ *
192
+ * A bounded attempt counter guards against a hot loop where the server keeps
193
+ * reporting the key stale even after a "successful" re-mint (e.g. a clock skew
194
+ * or a mint that returns an already-rejected key): after
195
+ * `MAX_CREDENTIAL_REFRESH_ATTEMPTS` we fall through to `auth_blocked` (stop,
196
+ * no sign-out) rather than spin. The counter resets once we reach `connected`.
197
+ *
198
+ * When no refresher is wired (e.g. a static `apiKey` deployment), we re-probe
199
+ * directly — the credential source's own scheduler owns refresh there.
200
+ */
201
+ private runRefreshCredential;
202
+ private runReconnect;
203
+ private scheduleBackoff;
204
+ private setupBrowserListeners;
205
+ private removeBrowserListeners;
206
+ private startWatchdog;
207
+ get isConnected(): boolean;
208
+ get isOffline(): boolean;
209
+ get isReconnecting(): boolean;
210
+ get isSessionExpired(): boolean;
211
+ get offlineDuration(): string | null;
212
+ private clearBackoffTimer;
213
+ private clearDebounceTimer;
214
+ }
215
+ export {};