@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
@@ -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-23';
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.'),
@@ -149,11 +150,28 @@ export const ERROR_CODES = {
149
150
  // only loop. Recovery belongs to the caller: take a claim, which queues fairly
150
151
  // behind the holder (`ablo.<model>.claim`), or re-read and rebase.
151
152
  claim_conflict: wire('claim', 409, false, 'Another participant holds a claim on this row, so the write was rejected. Take a claim with `ablo.<model>.claim` to queue fairly behind the holder, or re-read and rebase.'),
152
- 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
+ claim_lost: wire('claim', 409, false, 'The claim held on this row was lost before the write could apply. Re-acquire with `ablo.<model>.claim` and retry from its fresh snapshot.'),
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 — and for the participant claim behind `join`, which
161
+ // names scopes rather than a row but fails the same way and to the same
162
+ // caller. The copy covers both because the caller sees one word, `claim`, and
163
+ // needs to be told which shape was expected without being handed a lecture on
164
+ // the two frames.
165
+ malformed_claim: wire('validation', 400, false, 'The claim payload could not be parsed. A claim on a row must name the model and the entity it targets; a claim on a scope, which is what `join` opens, must name sync groups spelled `kind:id` or `default`. Check the payload shape and resend.'),
156
166
  malformed_subscription: wire('validation', 400, false, 'The `update_subscription` payload was malformed; expected `{ syncGroups: string[] }`.'),
167
+ // The counterpart to the two above, pointing the other way: those are a
168
+ // client sending the server something it cannot read, this is the server
169
+ // sending the client something it cannot read. One code covers both
170
+ // transports — a mis-shaped socket frame and a mis-shaped HTTP body are the
171
+ // same failure, and the message says which arrived. Not retryable: it means
172
+ // the two sides are running different versions of the protocol, and waiting
173
+ // does not change that.
174
+ 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
175
  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
176
  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
177
  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).'),
@@ -163,7 +181,7 @@ export const ERROR_CODES = {
163
181
  // `readAt`, so resending the identical payload can never succeed. Recovery
164
182
  // is a caller-level re-read that produces a NEW request with a fresh
165
183
  // watermark — the same shape as `claim_conflict`.
166
- stale_context: wire('conflict', 409, false, "The row changed after you read it — the write's `readAt` watermark is older than the current row version. Re-read the row and retry."),
184
+ stale_context: wire('conflict', 409, false, "The row changed after you read it — the write's `readAt` watermark is older than the current row version. Pass a function to `update(id, current => next)` and the SDK re-reads and retries for you; or re-read and retry by hand."),
167
185
  // Raised by the functional `update(id, current => next)` form once its
168
186
  // internal reconcile budget is exhausted, because the row stayed continuously
169
187
  // contended. The SDK has already retried; the caller decides whether to back
@@ -176,6 +194,7 @@ export const ERROR_CODES = {
176
194
  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
195
  // ── validation (400 / 422) ─────────────────────────────────────────
178
196
  write_options_invalid: client('validation', 'The write options (`idempotencyKey` / `label` / `wait` / `readAt` / `onStale` / `claim`) failed validation against the write-options schema.'),
197
+ 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
198
  source_operation_id_required: client('validation', 'A data-source operation arrived without the entity `id` it targets.'),
180
199
  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
200
  // The server validates every incoming data-source event before appending it
@@ -186,7 +205,6 @@ export const ERROR_CODES = {
186
205
  duration_invalid: client('validation', 'A duration value was not a number of seconds or a "500ms" | "30s" | "3m" | "24h" string.'),
187
206
  schema_definition_invalid: client('validation', 'A schema definition value was invalid (bad column identifier, non-finite backfill, or unsupported schema-JSON version).'),
188
207
  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
208
  commit_operation_required: wire('validation', 400, false, 'A commit must carry `operation` or `operations`.'),
191
209
  // Both commit transports — the WebSocket `commit` frame and the HTTP
192
210
  // `/v1/commits` endpoint — validate every operation and reject the whole batch
@@ -247,14 +265,18 @@ export const ERROR_CODES = {
247
265
  // ── claim / lease (409 / transport) ───────────────────────────────
248
266
  claim_lease_unavailable: wire('claim', 503, true, 'The claim-lease coordination subsystem is temporarily unavailable, so the claim could not be processed. Retry shortly.'),
249
267
  claim_not_wired: client('claim', 'Claims were used, but this runtime has no claim support wired in. The standard `Ablo({ schema, apiKey })` client wires it up automatically.'),
250
- claim_queued: wire('claim', 409, true, 'The claim was queued behind the current lease holder and will be granted in turn. Wait, or read `claim.queue` to see your position.'),
268
+ claim_queued: wire('claim', 409, true, 'The claim was queued behind the current lease holder and will be granted in turn. Poll `claims.retrieve({ claimId })` for the grant — the id rides on the error — or read `claim.queue` to see the line.'),
251
269
  claim_wait_aborted: wire('claim', 409, true, 'The wait for this claim lease was aborted before the lease was granted.'),
252
- claim_wait_poll_interval_required: client('claim', 'Waiting on a claim requires a poll interval, and none was provided.'),
253
- 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.'),
270
+ grant_timeout: wire('claim', 504, true, 'The wait for the claim grant timed out before your turn arrived (`waitTimeoutMs`). Claim again to rejoin the line, raise the cap, or re-read and proceed without the claim.'),
256
271
  // ── bootstrap (transport) ──────────────────────────────────────────
257
272
  bootstrap_fetch_timeout: wire('bootstrap', 504, true, 'The initial bootstrap fetch timed out before the server responded. Retry shortly.'),
273
+ // Deliberate cancellation, never a failure of the network. It is what the
274
+ // client hands to `abort()` so the layer above can tell "we stopped this on
275
+ // purpose" apart from "the transfer died" — the two are indistinguishable
276
+ // from a bare abort, and retrying the first re-issues requests that were just
277
+ // killed. Non-retryable by construction: whoever cancelled it either has a
278
+ // newer request in flight or has already given up.
279
+ 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
280
  bootstrap_offline: wire('bootstrap', 503, true, 'Bootstrap could not run because the client is offline. It can proceed once the network returns.'),
259
281
  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
282
  bootstrap_response_invalid: wire('bootstrap', 502, true, 'The bootstrap response could not be parsed. Retrying may succeed.'),
@@ -270,7 +292,7 @@ export const ERROR_CODES = {
270
292
  commit_failed: wire('transport', 500, true, 'The commit reached the server but failed to apply. Retrying may succeed.'),
271
293
  replication_lag_timeout: wire('transport', 504, true, "The data source accepted the write, but its correlated authoritative source delta did not arrive before the confirmation deadline. The write may still materialize; retry with the same idempotency key or wait for source ingestion to recover."),
272
294
  commit_offline_grace_expired: wire('transport', 503, false, 'The offline grace window expired before this commit could be sent, so it was not applied. Re-apply the change once the connection returns.'),
273
- queue_too_deep: wire('transport', 503, true, 'The transaction queue is over its depth limit, so new writes are being rejected until it drains. Retry shortly.'),
295
+ queue_too_deep: wire('transport', 503, true, 'The line is already past its depth limit. For a claim, more participants were waiting than your `maxQueueDepth` allows — claim again without the cap to wait anyway, or work elsewhere and retry later. For a write, the transaction queue is draining — retry shortly.'),
274
296
  flush_timeout: wire('transport', 504, true, 'Flushing the transaction queue timed out before every pending write was sent. Retry once connectivity stabilizes.'),
275
297
  wait_for_timeout: wire('transport', 504, true, 'A wait-for condition timed out before it was satisfied. Retry, or extend the timeout.'),
276
298
  instance_at_capacity: wire('transport', 503, true, 'The server is at connection capacity. Retry shortly — transient and not specific to your credentials.'),
@@ -294,8 +316,6 @@ export const ERROR_CODES = {
294
316
  // fail closed, so the request was rejected rather than admitted unchecked. It
295
317
  // is retryable: the next attempt re-probes the backend.
296
318
  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
319
  // ── client-only invariants (never serialized) ──────────────────────
300
320
  invalid_options: client('client', 'The Ablo client was constructed with invalid or incomplete options.'),
301
321
  no_ablo_provider: client('client', 'An Ablo hook was used outside of an Ablo provider.'),
@@ -345,12 +365,14 @@ export const ERROR_CODES = {
345
365
  forbidden: wire('permission', 403, false, 'The caller lacks permission for this operation.'),
346
366
  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
367
  capability_auth_disabled: wire('server', 503, false, 'Capability authentication is disabled on this server.'),
368
+ 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
369
  provisioner_unavailable: wire('server', 503, false, 'This deployment has no database provisioner configured, so tables cannot be created here.'),
349
370
  invalid_model: wire('validation', 400, false, 'The model name in the request is not a valid model identifier.'),
350
371
  invalid_id: wire('validation', 400, false, 'The id in the request is not a valid identifier.'),
351
372
  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
373
  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
374
  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."),
375
+ 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
376
  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
377
  schema_table_invalid: wire('schema', 500, false, "The model's table identifier is invalid."),
356
378
  schema_scope_invalid: wire('schema', 500, false, "The model's scope predicate could not be built."),
@@ -367,6 +389,7 @@ export const ERROR_CODES = {
367
389
  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
390
  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
391
  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.'),
392
+ 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
393
  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
394
  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
395
  query_relation_target_unknown: wire('schema', 500, false, 'A relation in the query targets a model the schema does not define.'),
@@ -384,20 +407,24 @@ export const ERROR_CODES = {
384
407
  usage_invalid: wire('validation', 400, false, 'The usage request was invalid.'),
385
408
  invalid_request: wire('validation', 400, false, 'The request parameters were invalid.'),
386
409
  capability_not_found: wire('not_found', 404, false, 'No capability exists with the given id.'),
410
+ 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
411
  invalid_participant_kind: wire('validation', 400, false, 'The participant kind is not one the server recognizes.'),
388
412
  invalid_sync_group: wire('validation', 400, false, 'Sync groups must be `default` or `<namespace>:<id>`.'),
389
413
  narrow_scope_required: wire('validation', 400, false, 'This request requires a scope narrowed to specific resources; the presented scope is too broad.'),
390
414
  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
415
  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.'),
416
+ // A row in an ordered collection can be created at a position stated relative
417
+ // to its neighbours ("before this one"), so the position has to be resolved
418
+ // against the parent before the row lands. These are the two ways that request
419
+ // can fail to describe a real place: no parent to resolve against, and a
420
+ // neighbour that is not in it.
421
+ 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.'),
422
+ 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
423
  schema_too_large: wire('validation', 413, false, 'The submitted schema exceeds the maximum size.'),
398
424
  request_too_large: wire('validation', 413, false, 'The request body exceeds the maximum size.'),
399
425
  invalid_schema: wire('validation', 400, false, 'The submitted schema could not be parsed.'),
400
426
  incompatible_change: wire('conflict', 409, false, 'The schema change is incompatible with the schema currently deployed and cannot be applied as-is.'),
427
+ replication_reset_required: wire('conflict', 409, false, 'A connected log plane has live rows for a mapped model that disappeared. Declare a rename or an explicit drop/reset before advancing the schema.'),
401
428
  };
402
429
  /** Looks up the {@link ErrorCodeSpec} for a code. Returns `undefined` for the
403
430
  * dynamic `policy:*` family and for any newer code this client does not yet
@@ -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,111 @@
1
+ /**
2
+ * The footprint — every object Ablo leaves inside a customer's own database,
3
+ * declared once.
4
+ *
5
+ * Four things need this list and each used to carry its own copy: the setup SQL
6
+ * that creates the objects, the replication runtime that reads them, the audit
7
+ * that tells a customer what Ablo put there, and (eventually) the teardown that
8
+ * removes them. They drifted, as hand-maintained copies do — `ABLO_PUBLICATION`
9
+ * was declared twice, under a comment insisting the literals "MUST equal the
10
+ * CLI's" and pointing at a file that no longer held it, and the audit went on
11
+ * looking for a footprint from an earlier era while seeing none of what Ablo
12
+ * installs today.
13
+ *
14
+ * The audit is the copy that matters most. A customer runs it to answer "what is
15
+ * still in my database", and a stale list answers "nothing" — which reads as
16
+ * clean rather than as unexamined. So the list lives here, every consumer
17
+ * derives from it, and an object added to Ablo's setup is visible to the audit
18
+ * because it could not have been added anywhere else.
19
+ *
20
+ * Retired objects stay in the list, marked {@link FootprintArtifact.retired}.
21
+ * They are no longer installed, but a database connected to an older Ablo still
22
+ * holds them, and those are precisely the ones a customer would never think to
23
+ * look for.
24
+ */
25
+ /** The Postgres object class, which decides how the audit looks it up. */
26
+ export type FootprintKind = 'publication' | 'slot' | 'role' | 'table' | 'type';
27
+ export interface FootprintArtifact {
28
+ readonly kind: FootprintKind;
29
+ readonly name: string;
30
+ /** What it is for, in the words a customer reading an audit would want. */
31
+ readonly purpose: string;
32
+ /**
33
+ * Installed only for a data source that reports through the signed endpoint
34
+ * rather than the write-ahead log.
35
+ */
36
+ readonly endpointOnly?: boolean;
37
+ /**
38
+ * No longer installed by any current version. A database that once ran an
39
+ * older Ablo still holds it; the audit reports it so it can be cleaned up.
40
+ */
41
+ readonly retired?: boolean;
42
+ /**
43
+ * What it costs to leave behind, when leaving it behind costs something. The
44
+ * audit leads with this, because "you still have an object named X" is not a
45
+ * reason to act and "this one is retaining your write-ahead log" is.
46
+ */
47
+ readonly hazard?: string;
48
+ }
49
+ /**
50
+ * The publication Ablo's replication reads from. Constant by design: a
51
+ * publication declares what streams, and several readers are meant to share one
52
+ * (`publication_names` is a per-stream option, not slot state).
53
+ */
54
+ export declare const ABLO_PUBLICATION = "ablo_publication";
55
+ /**
56
+ * The replication slot that holds Ablo's position in the write-ahead log.
57
+ *
58
+ * Constant, and it should not be — a slot stores ONE position, so two
59
+ * connections sharing this name compete for the same marker. It is why a
60
+ * database can be connected to one plane at a time. ADR 0020 derives it per
61
+ * connection; {@link isValidReplicationSlotName} is the check a derived name
62
+ * has to pass.
63
+ */
64
+ export declare const ABLO_REPLICATION_SLOT = "ablo_slot";
65
+ /** The least-privilege login Ablo reads with. Per-connection under ADR 0020. */
66
+ export declare const ABLO_REPLICATION_ROLE = "ablo_replicator";
67
+ /** The separate least-privilege login used only for row writes. */
68
+ export declare const ABLO_WRITE_ROLE = "ablo_writer";
69
+ /** The bookkeeping table that makes a retried write land once. */
70
+ export declare const ABLO_IDEMPOTENCY_TABLE = "ablo_idempotency";
71
+ /** The transactional outbox an endpoint source reports through. */
72
+ export declare const ABLO_OUTBOX_TABLE = "ablo_outbox";
73
+ /**
74
+ * Postgres will not accept a replication slot name outside this shape — the
75
+ * check is in `ReplicationSlotValidateNameInternal`, and identifier quoting does
76
+ * not exempt a name from it. Anything derived into a slot name is validated
77
+ * here, at the point it is derived, rather than failing at the point it is used.
78
+ */
79
+ export declare const REPLICATION_SLOT_NAME: RegExp;
80
+ export declare function isValidReplicationSlotName(name: string): boolean;
81
+ /** The four plane axes a connection is identified by. */
82
+ export interface FootprintPlane {
83
+ readonly organizationId: string;
84
+ readonly environment: string;
85
+ /** '' for the organization-default project. */
86
+ readonly projectId?: string;
87
+ /** '' for the default sandbox. */
88
+ readonly sandboxId?: string;
89
+ }
90
+ /** The names one connection owns. Nothing here is shared with another plane. */
91
+ export interface FootprintNames {
92
+ readonly slot: string;
93
+ readonly publication: string;
94
+ readonly replicationRole: string;
95
+ readonly writeRole: string;
96
+ }
97
+ /**
98
+ * The objects this connection owns, named so no other connection can claim them.
99
+ *
100
+ * A slot stores ONE position, so two connections sharing a name compete for the
101
+ * same marker and Postgres reports nothing — which is why the constants these
102
+ * replace made a database connectable to one plane at a time. The publication
103
+ * and roles are derived from the same digest so a database's footprint reads as
104
+ * one set per connection rather than a mix of shared and private objects.
105
+ *
106
+ * Stable: the same plane always derives the same names, so re-running setup is a
107
+ * no-op rather than a second installation.
108
+ */
109
+ export declare function footprintNamesFor(plane: FootprintPlane): FootprintNames;
110
+ /** Everything Ablo has ever put in a customer's database, current and retired. */
111
+ export declare const ABLO_FOOTPRINT: readonly FootprintArtifact[];
Binary file
@@ -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';