@abloatai/ablo 0.34.0 → 0.35.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 (483) hide show
  1. package/AGENTS.md +4 -1
  2. package/CHANGELOG.md +684 -5
  3. package/README.md +39 -22
  4. package/dist/BaseSyncedStore.d.ts +152 -44
  5. package/dist/BaseSyncedStore.js +300 -184
  6. package/dist/Database.d.ts +9 -24
  7. package/dist/Database.js +37 -22
  8. package/dist/InstanceCache.d.ts +25 -4
  9. package/dist/InstanceCache.js +48 -15
  10. package/dist/LazyReferenceCollection.d.ts +3 -3
  11. package/dist/LazyReferenceCollection.js +4 -4
  12. package/dist/Model.d.ts +6 -6
  13. package/dist/Model.js +10 -10
  14. package/dist/ModelRegistry.d.ts +4 -4
  15. package/dist/ModelRegistry.js +3 -3
  16. package/dist/{SyncEngineContext.d.ts → RuntimeContext.d.ts} +20 -13
  17. package/dist/{SyncEngineContext.js → RuntimeContext.js} +11 -12
  18. package/dist/SyncClient.d.ts +42 -32
  19. package/dist/SyncClient.js +166 -110
  20. package/dist/ai-sdk/coordinatedTool.d.ts +2 -2
  21. package/dist/ai-sdk/coordinatedTool.js +1 -1
  22. package/dist/ai-sdk/coordinationContext.d.ts +2 -2
  23. package/dist/ai-sdk/coordinationContext.js +1 -1
  24. package/dist/ai-sdk/wrap.d.ts +3 -3
  25. package/dist/ai-sdk/wrap.js +2 -2
  26. package/dist/auth/index.d.ts +1 -156
  27. package/dist/auth/index.js +8 -301
  28. package/dist/cli.cjs +3459 -1126
  29. package/dist/client/Ablo.d.ts +42 -287
  30. package/dist/client/Ablo.js +118 -963
  31. package/dist/client/abloClient.d.ts +309 -0
  32. package/dist/client/abloClient.js +13 -0
  33. package/dist/client/clientPrelude.d.ts +52 -0
  34. package/dist/client/clientPrelude.js +60 -0
  35. package/dist/client/consoleLogger.d.ts +2 -2
  36. package/dist/client/coreClient.d.ts +60 -0
  37. package/dist/client/coreClient.js +118 -0
  38. package/dist/client/createInternalComponents.d.ts +4 -4
  39. package/dist/client/createInternalComponents.js +9 -8
  40. package/dist/client/createModelProxy.d.ts +78 -373
  41. package/dist/client/createModelProxy.js +114 -86
  42. package/dist/client/humans.d.ts +48 -0
  43. package/dist/client/humans.js +52 -0
  44. package/dist/client/modelRegistration.d.ts +1 -1
  45. package/dist/client/modelRegistration.js +9 -9
  46. package/dist/client/options.d.ts +73 -17
  47. package/dist/client/reactiveEngine.d.ts +48 -0
  48. package/dist/client/reactiveEngine.js +910 -0
  49. package/dist/client/resourceTypes.d.ts +9 -250
  50. package/dist/client/resourceTypes.js +8 -5
  51. package/dist/client/schemaConfig.d.ts +4 -4
  52. package/dist/client/schemaConfig.js +6 -2
  53. package/dist/client/validateAbloOptions.d.ts +3 -2
  54. package/dist/client/validateAbloOptions.js +1 -1
  55. package/dist/client/wsMutationExecutor.d.ts +3 -3
  56. package/dist/client/wsMutationExecutor.js +3 -3
  57. package/dist/context.d.ts +9 -9
  58. package/dist/context.js +10 -9
  59. package/dist/coordination/ClaimLog.d.ts +26 -0
  60. package/dist/coordination/ClaimLog.js +32 -0
  61. package/dist/coordination/index.d.ts +1 -15
  62. package/dist/coordination/index.js +8 -31
  63. package/dist/core/DatabaseManager.js +1 -1
  64. package/dist/core/QueryView.d.ts +1 -1
  65. package/dist/core/QueryView.js +1 -1
  66. package/dist/core/StoreManager.d.ts +4 -23
  67. package/dist/core/StoreManager.js +5 -55
  68. package/dist/core/index.d.ts +2 -2
  69. package/dist/core/index.js +2 -2
  70. package/dist/core/storeContract.d.ts +2 -2
  71. package/dist/docs/catalog.d.ts +72 -0
  72. package/dist/docs/catalog.js +227 -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 +40 -34
  78. package/dist/index.js +26 -20
  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 +2 -2
  99. package/dist/query/client.js +4 -4
  100. package/dist/query/types.d.ts +6 -41
  101. package/dist/query/types.js +2 -2
  102. package/dist/react/AbloProvider.d.ts +6 -8
  103. package/dist/react/AbloProvider.js +5 -7
  104. package/dist/react/context.d.ts +1 -1
  105. package/dist/react/context.js +1 -1
  106. package/dist/react/index.d.ts +5 -5
  107. package/dist/react/index.js +3 -3
  108. package/dist/react/internalContext.d.ts +1 -1
  109. package/dist/react/useAblo.d.ts +3 -3
  110. package/dist/react/useAblo.js +1 -1
  111. package/dist/react/useCurrentUserId.js +1 -1
  112. package/dist/react/useErrorListener.js +1 -1
  113. package/dist/react/useMutationFailureListener.d.ts +2 -2
  114. package/dist/react/useMutationFailureListener.js +1 -1
  115. package/dist/react/useMutators.d.ts +3 -3
  116. package/dist/react/useMutators.js +3 -3
  117. package/dist/react/useUndoScope.d.ts +5 -5
  118. package/dist/react/useUndoScope.js +1 -1
  119. package/dist/schema/coordination.d.ts +69 -10
  120. package/dist/schema/coordination.js +86 -9
  121. package/dist/schema/ddl.js +2 -2
  122. package/dist/schema/diff.d.ts +1 -1
  123. package/dist/schema/generate.js +1 -1
  124. package/dist/schema/index.d.ts +10 -10
  125. package/dist/schema/index.js +18 -18
  126. package/dist/schema/queries.d.ts +27 -27
  127. package/dist/schema/queries.js +23 -23
  128. package/dist/schema/select.d.ts +3 -3
  129. package/dist/schema/select.js +3 -3
  130. package/dist/schema/serialize.d.ts +15 -6
  131. package/dist/schema/serialize.js +17 -3
  132. package/dist/schema/sugar.d.ts +6 -7
  133. package/dist/schema/sugar.js +9 -12
  134. package/dist/schema/syncDeltaRow.d.ts +4 -152
  135. package/dist/schema/syncDeltaRow.js +4 -105
  136. package/dist/server/adapter.d.ts +18 -1
  137. package/dist/server/commit.d.ts +10 -16
  138. package/dist/server/index.d.ts +1 -1
  139. package/dist/server/index.js +1 -1
  140. package/dist/server/readConfig.d.ts +1 -1
  141. package/dist/source/adapters/drizzle.d.ts +1 -1
  142. package/dist/source/adapters/drizzle.js +2 -2
  143. package/dist/source/adapters/kysely.d.ts +1 -1
  144. package/dist/source/adapters/kysely.js +1 -1
  145. package/dist/source/adapters/kyselyMutationCore.d.ts +1 -1
  146. package/dist/source/adapters/kyselyMutationCore.js +2 -2
  147. package/dist/source/adapters/memory.js +1 -1
  148. package/dist/source/adapters/prisma.d.ts +8 -3
  149. package/dist/source/adapters/prisma.js +1 -1
  150. package/dist/source/connector.js +1 -1
  151. package/dist/source/connectorProtocol.d.ts +2 -8
  152. package/dist/source/connectorProtocol.js +3 -2
  153. package/dist/source/contract.d.ts +29 -17
  154. package/dist/source/contract.js +27 -22
  155. package/dist/source/factory.d.ts +1 -1
  156. package/dist/source/footprint.d.ts +111 -0
  157. package/dist/source/footprint.js +0 -0
  158. package/dist/source/idempotency.js +2 -2
  159. package/dist/source/index.d.ts +1 -0
  160. package/dist/source/index.js +3 -0
  161. package/dist/source/next.d.ts +1 -1
  162. package/dist/source/signing.d.ts +9 -2
  163. package/dist/source/signing.js +4 -1
  164. package/dist/source/types.d.ts +6 -4
  165. package/dist/source/types.js +1 -1
  166. package/dist/stores/ObjectStore.d.ts +1 -1
  167. package/dist/stores/SyncActionStore.d.ts +1 -1
  168. package/dist/stores/SyncActionStore.js +2 -10
  169. package/dist/stores/syncAction.d.ts +26 -0
  170. package/dist/stores/syncAction.js +16 -0
  171. package/dist/surface.d.ts +3 -3
  172. package/dist/surface.js +6 -4
  173. package/dist/sync/BootstrapFetcher.d.ts +123 -6
  174. package/dist/sync/BootstrapFetcher.js +492 -66
  175. package/dist/sync/ConnectionManager.d.ts +6 -198
  176. package/dist/sync/ConnectionManager.js +6 -677
  177. package/dist/sync/OnDemandLoader.d.ts +2 -2
  178. package/dist/sync/OnDemandLoader.js +60 -21
  179. package/dist/sync/SubscriptionManager.d.ts +13 -2
  180. package/dist/sync/SubscriptionManager.js +23 -5
  181. package/dist/sync/SyncWebSocket.d.ts +27 -510
  182. package/dist/sync/SyncWebSocket.js +76 -954
  183. package/dist/sync/awaitClaimGrant.d.ts +4 -44
  184. package/dist/sync/awaitClaimGrant.js +4 -109
  185. package/dist/sync/commitFrames.d.ts +6 -40
  186. package/dist/sync/commitFrames.js +6 -97
  187. package/dist/sync/contextPorts.d.ts +18 -0
  188. package/dist/sync/contextPorts.js +31 -0
  189. package/dist/sync/createClaimStream.d.ts +5 -49
  190. package/dist/sync/createClaimStream.js +5 -469
  191. package/dist/sync/createPresenceStream.d.ts +26 -4
  192. package/dist/sync/createPresenceStream.js +28 -20
  193. package/dist/sync/createSnapshot.d.ts +2 -2
  194. package/dist/sync/createSnapshot.js +1 -1
  195. package/dist/sync/credentialLifecycle.d.ts +5 -173
  196. package/dist/sync/credentialLifecycle.js +5 -320
  197. package/dist/sync/deltaPipeline.d.ts +1 -1
  198. package/dist/sync/participants.d.ts +5 -4
  199. package/dist/sync/participants.js +29 -22
  200. package/dist/sync/schemaDrift.d.ts +55 -0
  201. package/dist/sync/schemaDrift.js +53 -0
  202. package/dist/sync/schemas.d.ts +21 -32
  203. package/dist/sync/schemas.js +26 -17
  204. package/dist/sync/syncPlan.d.ts +3 -3
  205. package/dist/sync/wsFrameHandlers.d.ts +6 -114
  206. package/dist/sync/wsFrameHandlers.js +6 -392
  207. package/dist/testing/fixtures/bootstrap.d.ts +1 -1
  208. package/dist/testing/fixtures/deltas.d.ts +1 -1
  209. package/dist/testing/fixtures/httpResponses.d.ts +70 -0
  210. package/dist/testing/fixtures/httpResponses.js +90 -0
  211. package/dist/testing/fixtures/models.js +1 -1
  212. package/dist/testing/helpers/wait.js +1 -1
  213. package/dist/testing/mocks/MockMutationExecutor.d.ts +2 -2
  214. package/dist/testing/mocks/MockMutationExecutor.js +8 -14
  215. package/dist/testing/mocks/MockSyncContext.d.ts +11 -11
  216. package/dist/testing/mocks/MockSyncContext.js +10 -9
  217. package/dist/testing/mocks/MockSyncStore.js +1 -1
  218. package/dist/testing/mocks/MockWebSocket.d.ts +2 -2
  219. package/dist/transaction/ablo.d.ts +88 -0
  220. package/dist/transaction/ablo.js +33 -0
  221. package/dist/{client/auth.d.ts → transaction/auth/apiKey.d.ts} +43 -8
  222. package/dist/{client/auth.js → transaction/auth/apiKey.js} +19 -0
  223. package/dist/transaction/auth/bootstrapScope.d.ts +15 -0
  224. package/dist/transaction/auth/bootstrapScope.js +1 -0
  225. package/dist/transaction/auth/capability.d.ts +177 -0
  226. package/dist/transaction/auth/capability.js +199 -0
  227. package/dist/{auth → transaction/auth}/credentialSource.d.ts +8 -1
  228. package/dist/{client → transaction/auth}/identity.d.ts +8 -7
  229. package/dist/{client → transaction/auth}/identity.js +1 -1
  230. package/dist/transaction/auth/index.d.ts +162 -0
  231. package/dist/transaction/auth/index.js +304 -0
  232. package/dist/{auth → transaction/auth}/schemas.d.ts +1 -1
  233. package/dist/{auth → transaction/auth}/schemas.js +13 -13
  234. package/dist/{client → transaction/auth}/sessionMint.d.ts +8 -8
  235. package/dist/{client → transaction/auth}/sessionMint.js +4 -7
  236. package/dist/transaction/coordination/awaitClaimGrant.d.ts +49 -0
  237. package/dist/transaction/coordination/awaitClaimGrant.js +112 -0
  238. package/dist/transaction/coordination/claimMeta.d.ts +49 -0
  239. package/dist/transaction/coordination/claimMeta.js +52 -0
  240. package/dist/transaction/coordination/createClaimStream.d.ts +64 -0
  241. package/dist/transaction/coordination/createClaimStream.js +475 -0
  242. package/dist/transaction/coordination/events.d.ts +74 -0
  243. package/dist/transaction/coordination/events.js +7 -0
  244. package/dist/transaction/coordination/index.d.ts +19 -0
  245. package/dist/transaction/coordination/index.js +44 -0
  246. package/dist/transaction/coordination/locator.d.ts +83 -0
  247. package/dist/transaction/coordination/locator.js +82 -0
  248. package/dist/transaction/coordination/schema.d.ts +1473 -0
  249. package/dist/{coordination → transaction/coordination}/schema.js +490 -55
  250. package/dist/transaction/coordination/targetConflict.d.ts +2 -0
  251. package/dist/transaction/coordination/targetConflict.js +103 -0
  252. package/dist/{coordination → transaction/coordination}/trace.d.ts +7 -18
  253. package/dist/{coordination → transaction/coordination}/trace.js +18 -25
  254. package/dist/transaction/durableWrites.d.ts +62 -0
  255. package/dist/{client → transaction}/durableWrites.js +28 -3
  256. package/dist/transaction/environment.d.ts +105 -0
  257. package/dist/transaction/environment.js +108 -0
  258. package/dist/{errorCodes.d.ts → transaction/errorCodes.d.ts} +11 -11
  259. package/dist/{errorCodes.js → transaction/errorCodes.js} +35 -12
  260. package/dist/{errors.d.ts → transaction/errors.d.ts} +37 -13
  261. package/dist/{errors.js → transaction/errors.js} +85 -16
  262. package/dist/transaction/index.d.ts +20 -0
  263. package/dist/transaction/index.js +20 -0
  264. package/dist/transaction/keys/index.d.ts +87 -0
  265. package/dist/transaction/keys/index.js +207 -0
  266. package/dist/transaction/log/syncDeltaRow.d.ts +158 -0
  267. package/dist/transaction/log/syncDeltaRow.js +95 -0
  268. package/dist/{sync/syncPosition.d.ts → transaction/logPosition.d.ts} +22 -8
  269. package/dist/{sync/syncPosition.js → transaction/logPosition.js} +15 -6
  270. package/dist/transaction/logger.d.ts +16 -0
  271. package/dist/transaction/logger.js +7 -0
  272. package/dist/transaction/observability.d.ts +53 -0
  273. package/dist/transaction/observability.js +19 -0
  274. package/dist/transaction/plugin.d.ts +192 -0
  275. package/dist/transaction/plugin.js +87 -0
  276. package/dist/{policy → transaction/policy}/types.d.ts +3 -3
  277. package/dist/{policy → transaction/policy}/types.js +2 -0
  278. package/dist/transaction/resources/httpResources.d.ts +266 -0
  279. package/dist/transaction/resources/httpResources.js +7 -0
  280. package/dist/transaction/resources/modelOperations.d.ts +319 -0
  281. package/dist/transaction/resources/modelOperations.js +12 -0
  282. package/dist/transaction/resources/mutationOptions.d.ts +66 -0
  283. package/dist/transaction/resources/mutationOptions.js +9 -0
  284. package/dist/transaction/resources/where.d.ts +85 -0
  285. package/dist/transaction/resources/where.js +70 -0
  286. package/dist/{client → transaction/resources}/writeOptionsSchema.d.ts +2 -6
  287. package/dist/{client → transaction/resources}/writeOptionsSchema.js +9 -5
  288. package/dist/{schema → transaction/schema}/field.d.ts +5 -5
  289. package/dist/{schema → transaction/schema}/field.js +5 -5
  290. package/dist/transaction/schema/loadStrategy.d.ts +45 -0
  291. package/dist/transaction/schema/loadStrategy.js +46 -0
  292. package/dist/{schema → transaction/schema}/model.d.ts +50 -35
  293. package/dist/{schema → transaction/schema}/model.js +30 -20
  294. package/dist/transaction/schema/openapi.d.ts +57 -0
  295. package/dist/transaction/schema/openapi.js +340 -0
  296. package/dist/{schema → transaction/schema}/relation.d.ts +14 -14
  297. package/dist/{schema → transaction/schema}/relation.js +7 -7
  298. package/dist/{schema → transaction/schema}/residency.d.ts +0 -9
  299. package/dist/{schema → transaction/schema}/residency.js +0 -5
  300. package/dist/{schema → transaction/schema}/roles.d.ts +5 -5
  301. package/dist/{schema → transaction/schema}/roles.js +5 -5
  302. package/dist/{schema → transaction/schema}/schema.d.ts +12 -10
  303. package/dist/{schema → transaction/schema}/schema.js +4 -3
  304. package/dist/{schema → transaction/schema}/tenancy.d.ts +1 -1
  305. package/dist/{schema → transaction/schema}/tenancy.js +7 -4
  306. package/dist/transaction/transactionLayer.d.ts +82 -0
  307. package/dist/transaction/transactionLayer.js +24 -0
  308. package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.d.ts +4 -5
  309. package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.js +9 -13
  310. package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.d.ts +9 -2
  311. package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.js +5 -9
  312. package/dist/{transactions/durableWriteStore.d.ts → transaction/transactions/settlement/pendingWrite.d.ts} +10 -36
  313. package/dist/transaction/transactions/settlement/pendingWrite.js +20 -0
  314. package/dist/transaction/transport/commitFrames.d.ts +90 -0
  315. package/dist/transaction/transport/commitFrames.js +134 -0
  316. package/dist/transaction/transport/connectionManager.d.ts +215 -0
  317. package/dist/transaction/transport/connectionManager.js +673 -0
  318. package/dist/transaction/transport/credentialLifecycle.d.ts +177 -0
  319. package/dist/transaction/transport/credentialLifecycle.js +324 -0
  320. package/dist/{sync → transaction/transport}/heartbeat.d.ts +3 -1
  321. package/dist/{sync → transaction/transport}/heartbeat.js +6 -4
  322. package/dist/{client → transaction/transport}/httpClient.d.ts +59 -16
  323. package/dist/{client → transaction/transport}/httpClient.js +5 -5
  324. package/dist/transaction/transport/httpOptions.d.ts +33 -0
  325. package/dist/transaction/transport/httpOptions.js +12 -0
  326. package/dist/{client → transaction/transport}/httpTransport.js +171 -85
  327. package/dist/{sync/NetworkProbe.d.ts → transaction/transport/networkProbe.d.ts} +7 -4
  328. package/dist/{sync/NetworkProbe.js → transaction/transport/networkProbe.js} +14 -13
  329. package/dist/transaction/transport/wsFrameHandlers.d.ts +128 -0
  330. package/dist/transaction/transport/wsFrameHandlers.js +429 -0
  331. package/dist/transaction/transport/wsTransport.d.ts +576 -0
  332. package/dist/transaction/transport/wsTransport.js +1017 -0
  333. package/dist/transaction/types/assertExact.d.ts +17 -0
  334. package/dist/transaction/types/assertExact.js +1 -0
  335. package/dist/{types → transaction/types}/global.d.ts +17 -2
  336. package/dist/{types → transaction/types}/global.js +2 -1
  337. package/dist/{types → transaction/types}/index.d.ts +14 -46
  338. package/dist/{types → transaction/types}/index.js +7 -16
  339. package/dist/{types → transaction/types}/streams.d.ts +63 -45
  340. package/dist/{utils → transaction/utils}/json.d.ts +18 -0
  341. package/dist/transaction/utils/json.js +276 -0
  342. package/dist/transaction/wire/accountResponses.d.ts +351 -0
  343. package/dist/transaction/wire/accountResponses.js +255 -0
  344. package/dist/transaction/wire/auth.d.ts +49 -0
  345. package/dist/transaction/wire/auth.js +57 -0
  346. package/dist/transaction/wire/claimEvent.d.ts +76 -0
  347. package/dist/transaction/wire/claimEvent.js +73 -0
  348. package/dist/transaction/wire/claims.d.ts +463 -0
  349. package/dist/transaction/wire/claims.js +229 -0
  350. package/dist/{wire → transaction/wire}/commit.d.ts +125 -193
  351. package/dist/{wire → transaction/wire}/commit.js +68 -47
  352. package/dist/{wire → transaction/wire}/delta.d.ts +66 -17
  353. package/dist/{wire → transaction/wire}/delta.js +37 -13
  354. package/dist/transaction/wire/errorEnvelope.d.ts +72 -0
  355. package/dist/{wire → transaction/wire}/errorEnvelope.js +36 -5
  356. package/dist/transaction/wire/feedCursor.d.ts +60 -0
  357. package/dist/transaction/wire/feedCursor.js +82 -0
  358. package/dist/transaction/wire/feedEvent.d.ts +177 -0
  359. package/dist/transaction/wire/feedEvent.js +39 -0
  360. package/dist/transaction/wire/frames.d.ts +194 -0
  361. package/dist/transaction/wire/frames.js +50 -0
  362. package/dist/transaction/wire/inboundFrames.d.ts +552 -0
  363. package/dist/transaction/wire/inboundFrames.js +116 -0
  364. package/dist/transaction/wire/index.d.ts +50 -0
  365. package/dist/transaction/wire/index.js +74 -0
  366. package/dist/{wire → transaction/wire}/listEnvelope.d.ts +13 -14
  367. package/dist/transaction/wire/listEnvelope.js +42 -0
  368. package/dist/transaction/wire/modelResponses.d.ts +85 -0
  369. package/dist/transaction/wire/modelResponses.js +43 -0
  370. package/dist/transactions/{TransactionQueue.d.ts → mutations/MutationQueue.d.ts} +79 -38
  371. package/dist/transactions/{TransactionQueue.js → mutations/MutationQueue.js} +110 -59
  372. package/dist/transactions/{TransactionStore.d.ts → mutations/MutationStore.d.ts} +8 -8
  373. package/dist/transactions/{TransactionStore.js → mutations/MutationStore.js} +2 -2
  374. package/dist/transactions/{coalesceRules.d.ts → mutations/coalesceRules.d.ts} +10 -10
  375. package/dist/transactions/{coalesceRules.js → mutations/coalesceRules.js} +1 -1
  376. package/dist/transactions/mutations/commitLatency.d.ts +52 -0
  377. package/dist/transactions/mutations/commitLatency.js +130 -0
  378. package/dist/transactions/{commitOutboxStore.d.ts → mutations/commitOutboxStore.d.ts} +1 -5
  379. package/dist/transactions/{commitOutboxStore.js → mutations/commitOutboxStore.js} +1 -1
  380. package/dist/transactions/{commitPayload.d.ts → mutations/commitPayload.d.ts} +16 -15
  381. package/dist/transactions/{commitPayload.js → mutations/commitPayload.js} +12 -12
  382. package/dist/transactions/{deltaConfirmation.d.ts → mutations/deltaConfirmation.d.ts} +11 -11
  383. package/dist/transactions/{deltaConfirmation.js → mutations/deltaConfirmation.js} +7 -7
  384. package/dist/transactions/mutations/durableWriteStore.d.ts +14 -0
  385. package/dist/transactions/mutations/durableWriteStore.js +12 -0
  386. package/dist/transactions/{optimisticApply.d.ts → mutations/optimisticApply.d.ts} +7 -7
  387. package/dist/transactions/{replayValidation.d.ts → mutations/replayValidation.d.ts} +3 -3
  388. package/dist/transactions/{replayValidation.js → mutations/replayValidation.js} +4 -3
  389. package/dist/utils/mobxSetup.d.ts +1 -1
  390. package/dist/utils/mobxSetup.js +5 -2
  391. package/dist/webhooks/events.d.ts +2 -2
  392. package/dist/wire/index.d.ts +1 -34
  393. package/dist/wire/index.js +8 -49
  394. package/docs/agent-messaging.md +3 -3
  395. package/docs/agents.md +19 -12
  396. package/docs/api-keys.md +8 -4
  397. package/docs/api.md +22 -18
  398. package/docs/audit.md +2 -0
  399. package/docs/cli.md +31 -3
  400. package/docs/client-behavior.md +8 -6
  401. package/docs/concurrency-convention.md +30 -24
  402. package/docs/coordination.md +48 -38
  403. package/docs/data-sources.md +3 -1
  404. package/docs/debugging.md +5 -3
  405. package/docs/deployment.md +267 -0
  406. package/docs/examples/agent-human.md +49 -42
  407. package/docs/examples/ai-sdk-tool.md +69 -44
  408. package/docs/examples/existing-python-backend.md +8 -6
  409. package/docs/examples/nextjs.md +129 -47
  410. package/docs/examples/scoped-agent.md +45 -44
  411. package/docs/examples/server-agent.md +46 -26
  412. package/docs/groups.md +32 -29
  413. package/docs/guarantees.md +4 -2
  414. package/docs/how-it-works.md +9 -7
  415. package/docs/idempotency.md +126 -0
  416. package/docs/identity.md +58 -54
  417. package/docs/index.md +172 -84
  418. package/docs/integration-guide.md +17 -16
  419. package/docs/interaction-model.md +6 -4
  420. package/docs/mcp.md +41 -16
  421. package/docs/migration.md +63 -5
  422. package/docs/operating-on-your-database.md +111 -0
  423. package/docs/projects.md +2 -0
  424. package/docs/quickstart.md +22 -5
  425. package/docs/react.md +12 -10
  426. package/docs/schema-contract.md +5 -3
  427. package/docs/session-settings.md +108 -0
  428. package/docs/sessions.md +3 -1
  429. package/docs/webhooks.md +3 -1
  430. package/llms.txt +47 -17
  431. package/package.json +10 -8
  432. package/dist/agent/Agent.d.ts +0 -366
  433. package/dist/agent/Agent.js +0 -514
  434. package/dist/agent/index.d.ts +0 -115
  435. package/dist/agent/index.js +0 -128
  436. package/dist/agent/session.d.ts +0 -93
  437. package/dist/agent/session.js +0 -149
  438. package/dist/agent/types.d.ts +0 -68
  439. package/dist/agent/types.js +0 -9
  440. package/dist/client/durableWrites.d.ts +0 -21
  441. package/dist/coordination/schema.d.ts +0 -722
  442. package/dist/schema/openapi.d.ts +0 -29
  443. package/dist/schema/openapi.js +0 -124
  444. package/dist/transactions/durableWriteStore.js +0 -30
  445. package/dist/utils/json.js +0 -88
  446. package/dist/wire/errorEnvelope.d.ts +0 -55
  447. package/dist/wire/frames.d.ts +0 -197
  448. package/dist/wire/frames.js +0 -49
  449. package/dist/wire/listEnvelope.js +0 -18
  450. /package/dist/{client → transaction/auth}/credentialEndpoint.d.ts +0 -0
  451. /package/dist/{client → transaction/auth}/credentialEndpoint.js +0 -0
  452. /package/dist/{auth → transaction/auth}/credentialPolicy.d.ts +0 -0
  453. /package/dist/{auth → transaction/auth}/credentialPolicy.js +0 -0
  454. /package/dist/{auth → transaction/auth}/credentialSource.js +0 -0
  455. /package/dist/{client → transaction/auth}/hostedEndpoints.d.ts +0 -0
  456. /package/dist/{client → transaction/auth}/hostedEndpoints.js +0 -0
  457. /package/dist/{client → transaction/coordination}/claimHeartbeatLoop.d.ts +0 -0
  458. /package/dist/{client → transaction/coordination}/claimHeartbeatLoop.js +0 -0
  459. /package/dist/{client → transaction}/persistence.d.ts +0 -0
  460. /package/dist/{client → transaction}/persistence.js +0 -0
  461. /package/dist/{client → transaction/resources}/functionalUpdate.d.ts +0 -0
  462. /package/dist/{client → transaction/resources}/functionalUpdate.js +0 -0
  463. /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.d.ts +0 -0
  464. /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.js +0 -0
  465. /package/dist/{client → transaction/transport}/httpTransport.d.ts +0 -0
  466. /package/dist/{types → transaction/types}/modelData.d.ts +0 -0
  467. /package/dist/{types → transaction/types}/modelData.js +0 -0
  468. /package/dist/{types → transaction/types}/participant.d.ts +0 -0
  469. /package/dist/{types → transaction/types}/participant.js +0 -0
  470. /package/dist/{types → transaction/types}/streams.js +0 -0
  471. /package/dist/{utils → transaction/utils}/asyncIterator.d.ts +0 -0
  472. /package/dist/{utils → transaction/utils}/asyncIterator.js +0 -0
  473. /package/dist/{utils → transaction/utils}/duration.d.ts +0 -0
  474. /package/dist/{utils → transaction/utils}/duration.js +0 -0
  475. /package/dist/{wire → transaction/wire}/bootstrapReason.d.ts +0 -0
  476. /package/dist/{wire → transaction/wire}/bootstrapReason.js +0 -0
  477. /package/dist/{wire → transaction/wire}/protocol.d.ts +0 -0
  478. /package/dist/{wire → transaction/wire}/protocol.js +0 -0
  479. /package/dist/{wire → transaction/wire}/protocolVersion.d.ts +0 -0
  480. /package/dist/{wire → transaction/wire}/protocolVersion.js +0 -0
  481. /package/dist/transactions/{UnconfirmedWrites.d.ts → mutations/UnconfirmedWrites.d.ts} +0 -0
  482. /package/dist/transactions/{UnconfirmedWrites.js → mutations/UnconfirmedWrites.js} +0 -0
  483. /package/dist/transactions/{optimisticApply.js → mutations/optimisticApply.js} +0 -0
@@ -37,7 +37,7 @@ import { z } from 'zod';
37
37
  * error documentation and returned on the `Ablo-Version` response header, so a
38
38
  * consumer can detect when its expected contract has drifted from the server's.
39
39
  */
40
- export const ERROR_CONTRACT_VERSION = '2026-07-15';
40
+ export const ERROR_CONTRACT_VERSION = '2026-07-21';
41
41
  /**
42
42
  * A closed classification of how a failure can be recovered from — a level above
43
43
  * the raw {@link ErrorCode}. Where a code says what went wrong, a recovery class
@@ -136,6 +136,7 @@ export const ERROR_CODES = {
136
136
  database_role_unreadable: wire('permission', 403, false, 'Ablo could not introspect the database role it connects with, so it cannot verify that row-level security is enforced.'),
137
137
  database_tables_unforced_rls: wire('permission', 403, false, 'Some synced tables do not have `FORCE ROW LEVEL SECURITY` applied, so the table owner can bypass row isolation. Run `ALTER TABLE ... FORCE ROW LEVEL SECURITY` on each synced table.'),
138
138
  database_host_not_allowed: wire('permission', 403, false, "The database host resolves to a private, loopback, or link-local address, which Ablo's servers will not connect to. Use a publicly resolvable host."),
139
+ connected_database_unreachable: wire('tenant', 503, false, 'Ablo could not reach the database connected to this environment: it refused the credentials on file, or did not answer at all. A database often changes after it is connected — a password is rotated, an instance is replaced — while the connection goes on pointing at what used to be there. The error names the host it tried. If the password changed, `ablo connect rotate` re-keys the roles and re-registers them; if the database itself was replaced, `ablo connect apply` sets up the new one and `ablo connect register` hands it over. Run either with a key for this environment.'),
139
140
  // Older spellings of the `database_*` codes above, still sent by some servers
140
141
  // and kept so they classify identically. Prefer the `database_*` codes.
141
142
  byo_role_cannot_enforce_rls: wire('permission', 403, false, 'The direct Postgres connector role cannot enforce row-level security.'),
@@ -152,8 +153,21 @@ export const ERROR_CODES = {
152
153
  claim_lost: wire('claim', 409, false, 'The claim held on this row was lost before the write could apply. Re-acquire the claim and retry.'),
153
154
  fence_token_stale: wire('claim', 409, false, 'This write carried a fencing token below the row’s current high-water: a later holder claimed the row, wrote, and moved on while this claim was lapsed, so applying the write would silently overwrite their work. The claim is gone — re-claim the row and retry from the current state.'),
154
155
  entity_claimed: wire('claim', 409, false, 'This row is currently claimed by another participant, so the write was blocked. Queue behind the holder with `ablo.<model>.claim`, or wait for the claim to clear.'),
155
- malformed_claim: wire('claim', 400, false, 'The claim payload could not be parsed. A claim must name the model and the entity it targets; check the payload shape and resend.'),
156
+ // A claim payload that cannot be parsed is a malformed request, not
157
+ // contention — it is filed with `malformed_subscription` below rather than
158
+ // with the 409s above, so the claim category stays purely about a target
159
+ // being held. This is the code for a claim that fails to name its target,
160
+ // over either transport.
161
+ malformed_claim: wire('validation', 400, false, 'The claim payload could not be parsed. A claim must name the model and the entity it targets; check the payload shape and resend.'),
156
162
  malformed_subscription: wire('validation', 400, false, 'The `update_subscription` payload was malformed; expected `{ syncGroups: string[] }`.'),
163
+ // The counterpart to the two above, pointing the other way: those are a
164
+ // client sending the server something it cannot read, this is the server
165
+ // sending the client something it cannot read. One code covers both
166
+ // transports — a mis-shaped socket frame and a mis-shaped HTTP body are the
167
+ // same failure, and the message says which arrived. Not retryable: it means
168
+ // the two sides are running different versions of the protocol, and waiting
169
+ // does not change that.
170
+ malformed_response: wire('transport', 502, false, 'The server sent a message this client could not read, so it was declined whole rather than applied in part. Nothing was changed locally. This normally means the client and the server are running different versions; upgrading the client resolves it.'),
157
171
  model_claimed: wire('claim', 409, false, 'Another participant holds a claim on this row. Read `claim.state` to see who holds it, or queue behind them with a claim of your own.'),
158
172
  model_claimed_timeout: wire('claim', 409, false, 'Another participant held a claim on this row and did not release it in time. Retry, or read `claim.state` to see who holds it.'),
159
173
  model_claim_not_configured: client('claim', 'Claiming requires the collaboration runtime, which the standard Ablo({ schema, apiKey }) client wires up for every model automatically — there is no per-model claim configuration to add. This appears only when a model proxy is constructed directly without that runtime (an internal/advanced path).'),
@@ -176,6 +190,7 @@ export const ERROR_CODES = {
176
190
  idempotency_key_too_long: wire('validation', 400, false, 'The supplied `Idempotency-Key` exceeds the maximum length. Use a shorter key — a UUID works well.'),
177
191
  // ── validation (400 / 422) ─────────────────────────────────────────
178
192
  write_options_invalid: client('validation', 'The write options (`idempotencyKey` / `label` / `wait` / `readAt` / `onStale` / `claim`) failed validation against the write-options schema.'),
193
+ write_payload_invalid: client('validation', 'A write payload contained a value that cannot be represented safely as JSON. Use plain objects, arrays, finite numbers, strings, booleans, null, or valid dates.'),
179
194
  source_operation_id_required: client('validation', 'A data-source operation arrived without the entity `id` it targets.'),
180
195
  source_adapter_misconfigured: client('validation', 'The data-source ORM adapter could not map a schema model onto the backing client — the client exposes no matching delegate or model. Check that the adapter and schema agree on model names.'),
181
196
  // The server validates every incoming data-source event before appending it
@@ -186,7 +201,6 @@ export const ERROR_CODES = {
186
201
  duration_invalid: client('validation', 'A duration value was not a number of seconds or a "500ms" | "30s" | "3m" | "24h" string.'),
187
202
  schema_definition_invalid: client('validation', 'A schema definition value was invalid (bad column identifier, non-finite backfill, or unsupported schema-JSON version).'),
188
203
  cli_invalid_arguments: client('validation', 'The CLI was invoked with an unknown flag or a malformed flag value.'),
189
- turn_validation_failed: wire('validation', 422, false, 'The agent turn payload failed server-side validation and was not applied.'),
190
204
  commit_operation_required: wire('validation', 400, false, 'A commit must carry `operation` or `operations`.'),
191
205
  // Both commit transports — the WebSocket `commit` frame and the HTTP
192
206
  // `/v1/commits` endpoint — validate every operation and reject the whole batch
@@ -251,10 +265,15 @@ export const ERROR_CODES = {
251
265
  claim_wait_aborted: wire('claim', 409, true, 'The wait for this claim lease was aborted before the lease was granted.'),
252
266
  claim_wait_poll_interval_required: client('claim', 'Waiting on a claim requires a poll interval, and none was provided.'),
253
267
  grant_timeout: wire('claim', 504, true, 'The wait for a capability grant timed out before one arrived. Retry the request.'),
254
- slide_intent_missing_deck_id: wire('claim', 400, false, 'This slide claim is missing the id of the deck it belongs to.'),
255
- slide_intent_unknown_sibling: wire('claim', 400, false, 'This slide claim references a sibling slide that does not exist in the deck.'),
256
268
  // ── bootstrap (transport) ──────────────────────────────────────────
257
269
  bootstrap_fetch_timeout: wire('bootstrap', 504, true, 'The initial bootstrap fetch timed out before the server responded. Retry shortly.'),
270
+ // Deliberate cancellation, never a failure of the network. It is what the
271
+ // client hands to `abort()` so the layer above can tell "we stopped this on
272
+ // purpose" apart from "the transfer died" — the two are indistinguishable
273
+ // from a bare abort, and retrying the first re-issues requests that were just
274
+ // killed. Non-retryable by construction: whoever cancelled it either has a
275
+ // newer request in flight or has already given up.
276
+ bootstrap_cancelled: client('bootstrap', 'This bootstrap request was cancelled before it finished, because a newer one replaced it or the bootstrap it belonged to had already failed. It is not retried on its own.'),
258
277
  bootstrap_offline: wire('bootstrap', 503, true, 'Bootstrap could not run because the client is offline. It can proceed once the network returns.'),
259
278
  bootstrap_offline_no_cache: wire('bootstrap', 503, false, 'The client is offline and no cached snapshot is available to start from, so there is no data to load until the network returns.'),
260
279
  bootstrap_response_invalid: wire('bootstrap', 502, true, 'The bootstrap response could not be parsed. Retrying may succeed.'),
@@ -294,8 +313,6 @@ export const ERROR_CODES = {
294
313
  // fail closed, so the request was rejected rather than admitted unchecked. It
295
314
  // is retryable: the next attempt re-probes the backend.
296
315
  rate_limiter_unavailable: wire('server', 503, true, 'The rate-limiter backend is unavailable and this endpoint is configured to fail closed; retry shortly.'),
297
- turn_open_failed: wire('server', 500, true, 'The agent turn could not be opened on the server. It is safe to retry.'),
298
- turn_close_failed: wire('server', 500, true, 'The agent turn could not be closed cleanly on the server. It is safe to retry the close.'),
299
316
  // ── client-only invariants (never serialized) ──────────────────────
300
317
  invalid_options: client('client', 'The Ablo client was constructed with invalid or incomplete options.'),
301
318
  no_ablo_provider: client('client', 'An Ablo hook was used outside of an Ablo provider.'),
@@ -345,12 +362,14 @@ export const ERROR_CODES = {
345
362
  forbidden: wire('permission', 403, false, 'The caller lacks permission for this operation.'),
346
363
  source_api_key_unresolved: wire('auth', 401, false, 'The API key presented for this data source could not be resolved to a known key. Check the key and its environment.'),
347
364
  capability_auth_disabled: wire('server', 503, false, 'Capability authentication is disabled on this server.'),
365
+ capability_rotation_unavailable: wire('server', 500, false, 'This capability could not be rotated, because the environment it belongs to could not be read from it. It is unchanged and still works. Create a replacement capability and retire this one.'),
348
366
  provisioner_unavailable: wire('server', 503, false, 'This deployment has no database provisioner configured, so tables cannot be created here.'),
349
367
  invalid_model: wire('validation', 400, false, 'The model name in the request is not a valid model identifier.'),
350
368
  invalid_id: wire('validation', 400, false, 'The id in the request is not a valid identifier.'),
351
369
  unknown_model: wire('tenant', 400, false, 'Named a model the server does not know. Run `ablo push` (or keep `ablo dev` running) to upload `ablo/schema.ts` — the server keeps its own copy of the schema.'),
352
370
  model_not_tenant_scoped: wire('tenant', 400, false, 'This model is not tenant-scoped, so it cannot be queried through the tenant-scoped read path.'),
353
371
  source_tenancy_not_enforced: wire('tenant', 400, false, "This model is scoped by its connected data source (`policy: { by: 'source' }`), so its tenant is resolved from the source registration rather than a row column. Enforcing that resolution requires the write-through connect path, which is not enabled on this plane yet — so the model cannot be served through the tenant-scoped read or bootstrap path without risking a cross-tenant read. If this model lives on a log plane, scope it with `by: 'column'` or `by: 'parent'` instead."),
372
+ user_scope_not_enforced: wire('tenant', 400, false, "Rows in this model belong to one person rather than to the whole organization, and that boundary is kept where the rows are stored. This plane is currently served from its log, which carries the organization and the project on every row but not the owner — so the boundary cannot be applied here, and serving the read would show one member another member's private records. It was declined whole and nothing was returned. Serve the plane from its tables, or read with a credential that acts for the organization rather than for a person."),
354
373
  model_not_provisioned: wire('tenant', 409, false, "This model is in the plane's registered schema, but its table has not been provisioned yet. Registering a schema with `ablo push` records the model; a plane's physical tables are created separately, out of band, so a model can appear in the schema before its table exists. Provision the plane's tables, then retry the read."),
355
374
  schema_table_invalid: wire('schema', 500, false, "The model's table identifier is invalid."),
356
375
  schema_scope_invalid: wire('schema', 500, false, "The model's scope predicate could not be built."),
@@ -367,6 +386,7 @@ export const ERROR_CODES = {
367
386
  protocol_version_unsupported: wire('transport', 426, false, 'The client sync-protocol version is outside the range this server supports — upgrade the SDK (or the server was rolled back mid-fleet).'),
368
387
  database_unreachable: wire('validation', 400, false, "Ablo could not reach this database to check that it can stream replication. The connection string may be wrong, the host may not be reachable from Ablo's servers, or the credentials may not be accepted."),
369
388
  database_not_replication_ready: wire('validation', 400, false, 'This database is not set up for logical replication yet. Every failing item — wal_level, the publication, the replication grant, a replica identity — is listed in the error details with its exact fix. `ablo connect` prints the one-time setup; `ablo connect check` verifies it.'),
389
+ database_already_connected: wire('conflict', 409, false, 'This database is already connected to another environment in your organization. Ablo streams a database from one environment at a time, so connecting it to a second one would leave the two reading the same change stream, and the newer connection would take the stream over from the older. Give this environment a database of its own — on a branching provider a branch of the same database is the usual answer, and it is what sandbox is for. If you meant to move the connection rather than add one, disconnect it from the environment that holds it with `ablo connect deregister` first.'),
370
390
  replication_publication_drift: wire('validation', 400, false, 'Your schema maps to tables that are not members of the replication publication, so their changes silently never stream and the source looks frozen. The missing tables and the exact `ALTER PUBLICATION … ADD TABLE …` to add them are in the error details — Ablo never alters your database for you.'),
371
391
  query_unknown_relation: wire('validation', 400, false, 'The query references a relation the model does not define. Check the relation name against the schema.'),
372
392
  query_relation_target_unknown: wire('schema', 500, false, 'A relation in the query targets a model the schema does not define.'),
@@ -384,16 +404,19 @@ export const ERROR_CODES = {
384
404
  usage_invalid: wire('validation', 400, false, 'The usage request was invalid.'),
385
405
  invalid_request: wire('validation', 400, false, 'The request parameters were invalid.'),
386
406
  capability_not_found: wire('not_found', 404, false, 'No capability exists with the given id.'),
407
+ claim_not_found: wire('not_found', 404, false, 'No claim of yours exists with the given id. It was released, it expired, or it was never acquired on this plane.'),
387
408
  invalid_participant_kind: wire('validation', 400, false, 'The participant kind is not one the server recognizes.'),
388
409
  invalid_sync_group: wire('validation', 400, false, 'Sync groups must be `default` or `<namespace>:<id>`.'),
389
410
  narrow_scope_required: wire('validation', 400, false, 'This request requires a scope narrowed to specific resources; the presented scope is too broad.'),
390
411
  wide_scope_forbidden: wire('permission', 403, false, 'This caller may not use a wide scope. Request a scope narrowed to the resources you need.'),
391
412
  capability_required: wire('auth', 401, false, 'This operation requires a capability, and none was presented.'),
392
- parent_turn_not_found: wire('not_found', 404, false, 'The referenced parent turn does not exist.'),
393
- parent_turn_foreign_agent: wire('permission', 403, false, 'The referenced parent turn belongs to a different agent, so it cannot be used here.'),
394
- turn_not_found: wire('not_found', 404, false, 'The referenced turn does not exist.'),
395
- turn_foreign_agent: wire('permission', 403, false, 'This turn belongs to a different agent, so the caller cannot act on it.'),
396
- invalid_intent: wire('validation', 400, false, 'The claim request was malformed and could not be processed.'),
413
+ // A row in an ordered collection can be created at a position stated relative
414
+ // to its neighbours ("before this one"), so the position has to be resolved
415
+ // against the parent before the row lands. These are the two ways that request
416
+ // can fail to describe a real place: no parent to resolve against, and a
417
+ // neighbour that is not in it.
418
+ position_missing_parent: wire('validation', 400, false, 'This row gives a position but not the parent it belongs to, so the position cannot be resolved. Send the parent id alongside the position.'),
419
+ position_unknown_sibling: wire('validation', 400, false, 'This row is positioned relative to another row that is not in the same parent. Check that the neighbouring row id is correct and still present.'),
397
420
  schema_too_large: wire('validation', 413, false, 'The submitted schema exceeds the maximum size.'),
398
421
  request_too_large: wire('validation', 413, false, 'The request body exceeds the maximum size.'),
399
422
  invalid_schema: wire('validation', 400, false, 'The submitted schema could not be parsed.'),
@@ -14,6 +14,7 @@
14
14
  *
15
15
  * Both work on every subclass.
16
16
  */
17
+ import { z } from 'zod';
17
18
  import type { ErrorCode } from './errorCodes.js';
18
19
  import { type WireClaimSummary, type ModelClaim, type ModelTarget, type ParticipantKind } from './coordination/schema.js';
19
20
  export type { ErrorCode, WireErrorCode, ErrorCategory, ErrorCodeSpec, RecoveryClass } from './errorCodes.js';
@@ -274,7 +275,7 @@ export declare function claimedError(target: {
274
275
  * narrow an existing capability into, one that would pass on retry.
275
276
  */
276
277
  export interface RequiredCapability {
277
- /** The operation or capability scope, for example `"slide.update"` or
278
+ /** The operation or capability scope, for example `"report.update"` or
278
279
  * `"subscribe"`. */
279
280
  readonly scope: string;
280
281
  /** The concrete constraints the capability must satisfy — for example
@@ -314,19 +315,19 @@ export declare class CapabilityError extends AbloPermissionError {
314
315
  * user should be sent to sign in again rather than offered a generic retry.
315
316
  *
316
317
  * It extends {@link AbloAuthenticationError}, so it is caught both by code using
317
- * the {@link SyncSessionError.isSessionError} check and by code that catches the
318
+ * the {@link AbloSessionError.isSessionError} check and by code that catches the
318
319
  * authentication category in general.
319
320
  */
320
- export declare class SyncSessionError extends AbloAuthenticationError {
321
+ export declare class AbloSessionError extends AbloAuthenticationError {
321
322
  readonly isSessionError = true;
322
323
  readonly statusCode: number;
323
324
  constructor(message: string, statusCode?: number);
324
325
  /**
325
- * Returns true when a value is a {@link SyncSessionError}, or any error-like
326
+ * Returns true when a value is a {@link AbloSessionError}, or any error-like
326
327
  * object that reports itself as a session error through an `isSessionError`
327
328
  * flag.
328
329
  */
329
- static isSessionError(error: unknown): error is SyncSessionError;
330
+ static isSessionError(error: unknown): error is AbloSessionError;
330
331
  /**
331
332
  * Determines whether an HTTP response means the login session has expired and
332
333
  * the user should sign in again. When the body carries a structured Ablo error
@@ -336,7 +337,17 @@ export declare class SyncSessionError extends AbloAuthenticationError {
336
337
  static isSessionErrorResponse(status: number, body?: string): boolean;
337
338
  }
338
339
  /**
339
- * The WebSocket-close counterpart to {@link SyncSessionError.isSessionErrorResponse}:
340
+ * @deprecated Renamed to {@link AbloSessionError} — the one engine-named class
341
+ * in the Ablo* hierarchy, brought in line with the family. Same class, same
342
+ * `instanceof` identity. Removed in 0.36.0.
343
+ */
344
+ export declare const SyncSessionError: typeof AbloSessionError;
345
+ /**
346
+ * @deprecated Renamed to {@link AbloSessionError}. Removed in 0.36.0.
347
+ */
348
+ export type SyncSessionError = AbloSessionError;
349
+ /**
350
+ * The WebSocket-close counterpart to {@link AbloSessionError.isSessionErrorResponse}:
340
351
  * returns true for close reasons that mean the short-lived access credential
341
352
  * (`ek_` or `rk_`) has expired. The server closes such sockets with code 4001
342
353
  * and reason `'credential_expired'`. Because the credential is re-mintable from
@@ -345,6 +356,24 @@ export declare class SyncSessionError extends AbloAuthenticationError {
345
356
  * reason, such as a revoked key or a genuinely lost login, stays terminal.
346
357
  */
347
358
  export declare function isAccessCredentialExpiryCloseReason(reason: string): boolean;
359
+ /**
360
+ * The one definition of the {@link RequiredCapability} wire shape. Every
361
+ * boundary that carries a denial's capability detail — the error body parsed
362
+ * here, and the rejected commit receipt in `wire/commit.ts` — composes this
363
+ * schema rather than restating the fields, so a new member cannot reach one
364
+ * boundary and miss the other.
365
+ *
366
+ * Unknown keys pass through: the server may describe a capability in more
367
+ * detail than this build knows, and dropping those keys would leave a caller
368
+ * unable to act on a denial it could otherwise satisfy.
369
+ */
370
+ export declare const requiredCapabilityWireSchema: z.ZodObject<{
371
+ scope: z.ZodString;
372
+ constraints: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodString]>>>;
373
+ issuer: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
374
+ ttlSeconds: z.ZodPreprocess<z.ZodOptional<z.ZodNumber>>;
375
+ nonce: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
376
+ }, z.core.$loose>;
348
377
  /**
349
378
  * Coerces any thrown value into an {@link AbloError}, so a consumer never catches
350
379
  * an untyped error from the SDK. An error that is already an {@link AbloError}
@@ -377,14 +406,9 @@ export declare function errorFromWire(message: string, opts?: {
377
406
  requestId?: string;
378
407
  requiredCapability?: RequiredCapability;
379
408
  claims?: readonly ClaimErrorClaim[];
409
+ /** Everything the producer attached beyond the envelope's own fields. */
410
+ details?: Readonly<Record<string, unknown>>;
380
411
  }): AbloError;
381
- /**
382
- * Translates an HTTP response into the appropriate typed {@link AbloError}. This
383
- * is the single mapping every request path routes a non-2xx response through, so
384
- * the error a consumer sees is always the right subclass. After extracting the
385
- * code and message from the response body, it delegates the class selection to
386
- * {@link errorFromWire}, the same logic the frame transports use.
387
- */
388
412
  export declare function translateHttpError(status: number, body: unknown, requestId?: string): AbloError;
389
413
  /**
390
414
  * Reports whether an HTTP error body carries a code that {@link translateHttpError}
@@ -335,27 +335,27 @@ export class CapabilityError extends AbloPermissionError {
335
335
  * user should be sent to sign in again rather than offered a generic retry.
336
336
  *
337
337
  * It extends {@link AbloAuthenticationError}, so it is caught both by code using
338
- * the {@link SyncSessionError.isSessionError} check and by code that catches the
338
+ * the {@link AbloSessionError.isSessionError} check and by code that catches the
339
339
  * authentication category in general.
340
340
  */
341
- export class SyncSessionError extends AbloAuthenticationError {
341
+ export class AbloSessionError extends AbloAuthenticationError {
342
342
  isSessionError = true;
343
343
  statusCode;
344
344
  constructor(message, statusCode = 401) {
345
345
  super(message, { httpStatus: statusCode, code: 'session_expired' });
346
- this.name = 'SyncSessionError';
346
+ this.name = 'AbloSessionError';
347
347
  this.statusCode = statusCode;
348
348
  if (Error.captureStackTrace) {
349
- Error.captureStackTrace(this, SyncSessionError);
349
+ Error.captureStackTrace(this, AbloSessionError);
350
350
  }
351
351
  }
352
352
  /**
353
- * Returns true when a value is a {@link SyncSessionError}, or any error-like
353
+ * Returns true when a value is a {@link AbloSessionError}, or any error-like
354
354
  * object that reports itself as a session error through an `isSessionError`
355
355
  * flag.
356
356
  */
357
357
  static isSessionError(error) {
358
- if (error instanceof SyncSessionError) {
358
+ if (error instanceof AbloSessionError) {
359
359
  return true;
360
360
  }
361
361
  if (error && typeof error === 'object' && 'isSessionError' in error) {
@@ -392,7 +392,13 @@ export class SyncSessionError extends AbloAuthenticationError {
392
392
  }
393
393
  }
394
394
  /**
395
- * The WebSocket-close counterpart to {@link SyncSessionError.isSessionErrorResponse}:
395
+ * @deprecated Renamed to {@link AbloSessionError} — the one engine-named class
396
+ * in the Ablo* hierarchy, brought in line with the family. Same class, same
397
+ * `instanceof` identity. Removed in 0.36.0.
398
+ */
399
+ export const SyncSessionError = AbloSessionError;
400
+ /**
401
+ * The WebSocket-close counterpart to {@link AbloSessionError.isSessionErrorResponse}:
396
402
  * returns true for close reasons that mean the short-lived access credential
397
403
  * (`ek_` or `rk_`) has expired. The server closes such sockets with code 4001
398
404
  * and reason `'credential_expired'`. Because the credential is re-mintable from
@@ -405,7 +411,18 @@ export function isAccessCredentialExpiryCloseReason(reason) {
405
411
  }
406
412
  // ── HTTP → class mapping ──────────────────────────────────────────────
407
413
  const OptionalWireStringSchema = z.preprocess((value) => (typeof value === 'string' ? value : undefined), z.string().optional());
408
- const RequiredCapabilityWireSchema = z
414
+ /**
415
+ * The one definition of the {@link RequiredCapability} wire shape. Every
416
+ * boundary that carries a denial's capability detail — the error body parsed
417
+ * here, and the rejected commit receipt in `wire/commit.ts` — composes this
418
+ * schema rather than restating the fields, so a new member cannot reach one
419
+ * boundary and miss the other.
420
+ *
421
+ * Unknown keys pass through: the server may describe a capability in more
422
+ * detail than this build knows, and dropping those keys would leave a caller
423
+ * unable to act on a denial it could otherwise satisfy.
424
+ */
425
+ export const requiredCapabilityWireSchema = z
409
426
  .object({
410
427
  scope: z.string(),
411
428
  constraints: z
@@ -416,19 +433,19 @@ const RequiredCapabilityWireSchema = z
416
433
  .preprocess((value) => (typeof value === 'number' ? value : undefined), z.number().optional()),
417
434
  nonce: OptionalWireStringSchema,
418
435
  })
419
- .passthrough();
436
+ .loose();
420
437
  const NestedErrorShapeSchema = z
421
438
  .object({
422
439
  code: OptionalWireStringSchema,
423
440
  message: OptionalWireStringSchema,
424
441
  field: OptionalWireStringSchema,
425
- requiredCapability: RequiredCapabilityWireSchema.optional().catch(undefined),
442
+ requiredCapability: requiredCapabilityWireSchema.optional().catch(undefined),
426
443
  heldBy: OptionalWireStringSchema,
427
444
  policyReason: OptionalWireStringSchema,
428
445
  heldByClaim: wireClaimSummarySchema.optional().catch(undefined),
429
446
  claims: z.array(wireClaimSummarySchema).optional().catch(undefined),
430
447
  })
431
- .passthrough();
448
+ .loose();
432
449
  const ErrorFieldSchema = z
433
450
  .preprocess((value) => typeof value === 'string' || (typeof value === 'object' && value !== null)
434
451
  ? value
@@ -442,13 +459,13 @@ const ErrorBodyShapeSchema = z
442
459
  code: OptionalWireStringSchema,
443
460
  reason: OptionalWireStringSchema,
444
461
  message: OptionalWireStringSchema,
445
- requiredCapability: RequiredCapabilityWireSchema.optional().catch(undefined),
462
+ requiredCapability: requiredCapabilityWireSchema.optional().catch(undefined),
446
463
  heldBy: OptionalWireStringSchema,
447
464
  policyReason: OptionalWireStringSchema,
448
465
  heldByClaim: wireClaimSummarySchema.optional().catch(undefined),
449
466
  claims: z.array(wireClaimSummarySchema).optional().catch(undefined),
450
467
  })
451
- .passthrough();
468
+ .loose();
452
469
  function parseErrorBodyShape(body) {
453
470
  if (typeof body !== 'object' || body === null)
454
471
  return {};
@@ -489,7 +506,7 @@ export function toAbloError(err) {
489
506
  * subclass, with its `code`, status, and retryability intact.
490
507
  */
491
508
  export function errorFromWire(message, opts = {}) {
492
- const { code, requestId, requiredCapability, claims } = opts;
509
+ const { code, requestId, requiredCapability, claims, details } = opts;
493
510
  // Effective status: an explicit HTTP status wins; otherwise fall back to
494
511
  // the code's canonical status from the registry (undefined for unknown /
495
512
  // forward-compat codes, which then map to the base AbloError).
@@ -498,7 +515,12 @@ export function errorFromWire(message, opts = {}) {
498
515
  // may send a code this SDK predates). Cast to ErrorCode here — the one
499
516
  // sanctioned crossing — so internal producers stay statically checked.
500
517
  const publicCode = (code === 'claim_conflict' ? 'claim_conflict' : code);
501
- const baseOpts = { code: publicCode, httpStatus, requestId };
518
+ const baseOpts = {
519
+ code: publicCode,
520
+ httpStatus,
521
+ requestId,
522
+ ...(details && Object.keys(details).length > 0 ? { details } : {}),
523
+ };
502
524
  // ── Code-first specials (transport-independent) ──────────────────────
503
525
  // A scoped credential was denied — route through CapabilityError so callers
504
526
  // can read `.requiredCapability` to attenuate-and-retry.
@@ -519,6 +541,14 @@ export function errorFromWire(message, opts = {}) {
519
541
  if (code === 'stale_context') {
520
542
  return new AbloStaleContextError(message, baseOpts);
521
543
  }
544
+ // The database connected to the caller's environment could not be reached.
545
+ // It rides a 503, but the generic 5xx rule below would rebuild it as an
546
+ // `AbloServerError` — telling the reader Ablo is broken and to wait, when the
547
+ // remedy is on their side and the server already classified it as a
548
+ // connection failure. Keep the class the producer chose.
549
+ if (code === 'connected_database_unreachable') {
550
+ return new AbloConnectionError(message, baseOpts);
551
+ }
522
552
  // ── Status-driven dispatch (HTTP parity) ─────────────────────────────
523
553
  if (httpStatus === 401)
524
554
  return new AbloAuthenticationError(message, baseOpts);
@@ -541,6 +571,38 @@ export function errorFromWire(message, opts = {}) {
541
571
  * code and message from the response body, it delegates the class selection to
542
572
  * {@link errorFromWire}, the same logic the frame transports use.
543
573
  */
574
+ /**
575
+ * The keys the error envelope spends on itself. {@link AbloError.toJSON} spreads
576
+ * `details` FLAT alongside them rather than nesting it, so everything here is
577
+ * the envelope and everything else was `details` — which is how
578
+ * {@link translateHttpError} puts it back.
579
+ */
580
+ const ENVELOPE_KEYS = new Set([
581
+ 'type',
582
+ 'code',
583
+ 'param',
584
+ 'message',
585
+ 'doc_url',
586
+ 'request_id',
587
+ // Read into typed properties below, so they are not detail as well.
588
+ 'error',
589
+ 'reason',
590
+ 'requiredCapability',
591
+ 'claims',
592
+ 'heldByClaim',
593
+ ]);
594
+ /** The non-envelope remainder of an error body — what `details` was before it
595
+ * was spread. Empty when the producer attached nothing. */
596
+ function detailsFromBody(body) {
597
+ if (typeof body !== 'object' || body === null)
598
+ return undefined;
599
+ const rest = {};
600
+ for (const [key, value] of Object.entries(body)) {
601
+ if (!ENVELOPE_KEYS.has(key))
602
+ rest[key] = value;
603
+ }
604
+ return Object.keys(rest).length > 0 ? rest : undefined;
605
+ }
544
606
  export function translateHttpError(status, body, requestId) {
545
607
  const parsed = parseErrorBodyShape(body);
546
608
  const nested = parsed.error != null && typeof parsed.error === 'object'
@@ -561,12 +623,19 @@ export function translateHttpError(status, body, requestId) {
561
623
  : nested?.heldByClaim
562
624
  ? [nested.heldByClaim]
563
625
  : undefined);
626
+ // The envelope carries `request_id`, so a caller that has only the body still
627
+ // gets the correlation id — without this it was dropped unless the caller
628
+ // happened to read the header and pass it in separately.
629
+ const bodyRequestId = typeof body === 'object' && body !== null && 'request_id' in body
630
+ ? body.request_id
631
+ : undefined;
564
632
  return errorFromWire(message, {
565
633
  code,
566
634
  httpStatus: status,
567
- requestId,
635
+ requestId: requestId ?? (typeof bodyRequestId === 'string' ? bodyRequestId : undefined),
568
636
  requiredCapability,
569
637
  claims,
638
+ details: detailsFromBody(body),
570
639
  });
571
640
  }
572
641
  /**
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The Ablo settlement core (ADR 0013).
3
+ *
4
+ * The transaction layer that the reactive client is a consumer of, not the
5
+ * other way round. The root barrel is deliberate: it exports the seam —
6
+ * {@link TransactionLayer} — plus exactly the vocabulary its signatures
7
+ * reference and the error hierarchy callers catch. Everything else stays on
8
+ * subpaths; every addition here is a decision
9
+ * (docs/plans/transaction-layer-barrel-design.md).
10
+ */
11
+ export type { TransactionLayer, ListQuery, CommitReceipt } from './transactionLayer.js';
12
+ export { Ablo } from './ablo.js';
13
+ export type { AbloHttpClient, AbloHttpClientOptions, HttpModelClient, } from './transport/httpClient.js';
14
+ export type { Delta, HeldClaim, HeldLease, ClaimTarget, ClaimLeaseOptions, } from './types/streams.js';
15
+ export type { ModelData } from './types/modelData.js';
16
+ export { LogPosition, logPositionSchema, parseLogPosition } from './logPosition.js';
17
+ export type { LogPositionSnapshot } from './logPosition.js';
18
+ export { AbloError, AbloAuthenticationError, AbloPermissionError, AbloRateLimitError, AbloIdempotencyError, AbloConnectionError, AbloValidationError, AbloNotFoundError, AbloServerError, AbloStaleContextError, AbloContentionError, AbloClaimedError, AbloSessionError, toAbloError, } from './errors.js';
19
+ export * from './errorCodes.js';
20
+ export * from './environment.js';
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The Ablo settlement core (ADR 0013).
3
+ *
4
+ * The transaction layer that the reactive client is a consumer of, not the
5
+ * other way round. The root barrel is deliberate: it exports the seam —
6
+ * {@link TransactionLayer} — plus exactly the vocabulary its signatures
7
+ * reference and the error hierarchy callers catch. Everything else stays on
8
+ * subpaths; every addition here is a decision
9
+ * (docs/plans/transaction-layer-barrel-design.md).
10
+ */
11
+ // The client entry point (ADR 0016). The bare import constructs the
12
+ // coordination layer over request/response transport; the reactive
13
+ // materialiser is the consumer package's entry point, layered above it.
14
+ export { Ablo } from './ablo.js';
15
+ export { LogPosition, logPositionSchema, parseLogPosition } from './logPosition.js';
16
+ // The error hierarchy callers catch.
17
+ export { AbloError, AbloAuthenticationError, AbloPermissionError, AbloRateLimitError, AbloIdempotencyError, AbloConnectionError, AbloValidationError, AbloNotFoundError, AbloServerError, AbloStaleContextError, AbloContentionError, AbloClaimedError, AbloSessionError, toAbloError, } from './errors.js';
18
+ // Pre-seam leaf surfaces, kept for compatibility with the first extraction.
19
+ export * from './errorCodes.js';
20
+ export * from './environment.js';
@@ -0,0 +1,87 @@
1
+ /**
2
+ * The Ablo API-key format: how keys are minted, hashed, and validated, in one
3
+ * place so every component that issues or checks a key agrees on the format.
4
+ *
5
+ * This module uses `node:crypto` and is therefore Node-only. It is published on
6
+ * the `@abloatai/ablo/keys` subpath and kept off the main browser-facing entry
7
+ * so a browser bundle never pulls in `node:crypto`.
8
+ *
9
+ * A key looks like `<sk|rk|ek|pk>_<live|test>_<30 base62 chars><6-char base62
10
+ * CRC32 checksum>`. The middle segment is the stable environment prefix, mapped
11
+ * on parse to `production` or `sandbox`. The recognizable prefix lets secret
12
+ * scanners spot a leaked key, and the trailing checksum lets the format reject a
13
+ * mistyped or forged key locally, without a database round-trip. Older keys
14
+ * (roughly a 43-character base64url body with no checksum) still validate by hash
15
+ * and parse here with `checksummed: false`.
16
+ */
17
+ import { z } from 'zod';
18
+ import { type KeyEnvironment } from '../environment.js';
19
+ export declare const API_KEY_KINDS: readonly ["secret", "restricted", "ephemeral", "publishable"];
20
+ export type ApiKeyKind = (typeof API_KEY_KINDS)[number];
21
+ export declare const API_KEY_ENVS: readonly ["production", "sandbox"];
22
+ export type ApiKeyEnv = KeyEnvironment;
23
+ /** A structurally-valid Ablo API key, parsed into its parts. */
24
+ export interface ParsedApiKey {
25
+ /** The original plaintext. */
26
+ raw: string;
27
+ kind: ApiKeyKind;
28
+ env: ApiKeyEnv;
29
+ /** The chars after `<prefix>_<env>_` (body + checksum for new keys). */
30
+ body: string;
31
+ /** True when this is the new checksummed format (36-char base62 body). */
32
+ checksummed: boolean;
33
+ }
34
+ /**
35
+ * The Zod schema for an Ablo API key. `parse` and `safeParse` return a typed
36
+ * {@link ParsedApiKey}. A checksummed-format key whose checksum does not match is
37
+ * rejected without any network call; an older key with no checksum parses with
38
+ * `checksummed: false` and is left for the server to validate by hash.
39
+ */
40
+ export declare const apiKeySchema: z.ZodPipe<z.ZodString, z.ZodTransform<ParsedApiKey, string>>;
41
+ /** Parse + fully validate (incl. checksum). Returns null when invalid. */
42
+ export declare function parseApiKey(raw: string): ParsedApiKey | null;
43
+ /**
44
+ * Read the environment off a STORED display prefix (`keyPrefix`, the first 12
45
+ * chars — `rk_test_abcd`), rather than off a full plaintext key.
46
+ *
47
+ * A key row records its environment nowhere but its prefix, so this is how a
48
+ * server-side flow that only has the row — rotation, most importantly — recovers
49
+ * the credential's own mode. Returns null when the prefix is not a recognizable
50
+ * key spelling, so callers can fail closed rather than fall back to a default.
51
+ */
52
+ export declare function environmentFromStoredKeyPrefix(prefix: string): KeyEnvironment | null;
53
+ /** True when the key uses the new checksummed format (regardless of validity). */
54
+ export declare function isChecksummedKey(raw: string): boolean;
55
+ /** Verify the embedded checksum. Meaningful only for checksummed-format keys. */
56
+ export declare function keyChecksumMatches(raw: string): boolean;
57
+ /**
58
+ * Mint a key: `<prefix>_<env>_<body><checksum>`. Returns the plaintext (shown
59
+ * once), its SHA-256 hash (persisted), and the 12-char display prefix.
60
+ */
61
+ export declare function generateApiKey(env?: ApiKeyEnv, kind?: ApiKeyKind): {
62
+ plaintext: string;
63
+ hash: string;
64
+ prefix: string;
65
+ };
66
+ /**
67
+ * The stable SHA-256 hex digest of a plaintext key, computed both when a key is
68
+ * minted and when one is looked up. A fast hash is the right choice here rather
69
+ * than a password hash like bcrypt: API keys are long random strings, so there is
70
+ * no dictionary of guesses to slow down.
71
+ */
72
+ export declare function hashApiKey(plaintext: string): string;
73
+ /** `whsec_` label prefix per the Standard Webhooks spec (not part of the key material). */
74
+ export declare const WEBHOOK_SECRET_PREFIX = "whsec_";
75
+ /**
76
+ * Mints a webhook signing secret following the Standard Webhooks specification
77
+ * (https://www.standardwebhooks.com): a base64-encoded random key of 24–64 bytes,
78
+ * labelled with the `whsec_` prefix. This uses 32 bytes (256 bits), comfortably
79
+ * inside that range. Unlike an API key, a signing secret is not hashed at rest,
80
+ * because signing a request with {@link signAbloSourceRequest} needs the live
81
+ * value. It is therefore kept in a secret store, returned to the customer once at
82
+ * creation, and never shown again.
83
+ */
84
+ export declare function generateWebhookSecret(): {
85
+ plaintext: string;
86
+ last4: string;
87
+ };