@abloatai/ablo 0.34.1 → 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 +2 -1
  2. package/CHANGELOG.md +674 -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 +3344 -1073
  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 -86
  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 +3 -1
  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
@@ -7,13 +7,16 @@
7
7
  */
8
8
  import { AbloClaimedError, AbloAuthenticationError, AbloConnectionError, AbloIdempotencyError, AbloValidationError, AbloNotFoundError, claimedError, translateHttpError, } from '../errors.js';
9
9
  import { v5 as uuidv5 } from 'uuid';
10
- import { reconcileFunctionalUpdate, } from './functionalUpdate.js';
11
- import { assertBrowserSafety, readProcessEnv, resolveApiKey, resolveApiKeyValue, resolveAuthToken, resolveBaseURL, resolveBootstrapBaseUrl, rejectRemovedDatabaseUrlOption, warnIfCliKeyMismatch, } from './auth.js';
10
+ import { z } from 'zod';
11
+ import { reconcileFunctionalUpdate, } from '../resources/functionalUpdate.js';
12
+ import { assertBrowserSafety, readProcessEnv, resolveApiKey, resolveApiKeyValue, resolveAuthToken, resolveBaseURL, resolveBootstrapBaseUrl, rejectRemovedDatabaseUrlOption, warnIfCliKeyMismatch, } from '../auth/apiKey.js';
12
13
  import { PROTOCOL_VERSION, PROTOCOL_VERSION_HEADER } from '../wire/protocolVersion.js';
13
14
  import { commitReceiptSchema } from '../wire/commit.js';
15
+ import { claimAcquireResponseSchema, claimHeartbeatReplySchema, claimListResponseSchema, } from '../wire/claims.js';
16
+ import { modelListResponseSchema, modelReadResponseSchema, } from '../wire/modelResponses.js';
14
17
  import { toMs } from '../utils/duration.js';
15
- import { heartbeatCadenceMs, resolveHeartbeatOptions, startClaimHeartbeatLoop, } from './claimHeartbeatLoop.js';
16
- import { mintSession } from './sessionMint.js';
18
+ import { heartbeatCadenceMs, resolveHeartbeatOptions, startClaimHeartbeatLoop, } from '../coordination/claimHeartbeatLoop.js';
19
+ import { mintSession } from '../auth/sessionMint.js';
17
20
  import { parseIdentityResolveResponse } from '../auth/schemas.js';
18
21
  /**
19
22
  * Interpret a heartbeat reply for a lease this handle HOLDS: anything other
@@ -31,12 +34,20 @@ function heldHeartbeatReply(reply, label) {
31
34
  }
32
35
  throw new AbloClaimedError(`The lease behind ${label} is no longer held — it expired or was granted onward. Re-acquire the claim and retry; a write attempted under the old lease is rejected by its \`readAt\` guard.`, { code: 'claim_lost' });
33
36
  }
34
- import { assertWriteOptions } from './writeOptionsSchema.js';
35
- import { createDurableHttpCommitEnvelope, canonicalHttpCommitBody, durableHttpCommitEnvelopeSchema, httpCommitEnvelopeRecordId, isHttpCommitReplayExpired, } from '../transactions/httpCommitEnvelope.js';
36
- import { resolveDurableWrites } from './durableWrites.js';
37
+ import { claimDescription } from '../coordination/schema.js';
38
+ import { subTarget, streamTarget } from '../coordination/locator.js';
39
+ import { declaredMeta, wireMeta } from '../coordination/claimMeta.js';
40
+ import { assertWriteOptions } from '../resources/writeOptionsSchema.js';
41
+ import { createDurableHttpCommitEnvelope, canonicalHttpCommitBody, durableHttpCommitEnvelopeSchema, httpCommitEnvelopeRecordId, isHttpCommitReplayExpired, } from '../transactions/settlement/httpCommitEnvelope.js';
42
+ import { resolveDurableWrites } from '../durableWrites.js';
37
43
  /** @internal Default per-request deadline for the private HTTP transport. */
38
44
  export const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
39
45
  const HTTP_CONFIRMATION_POLL_INTERVAL_MS = 250;
46
+ /**
47
+ * The server's acquire window, mirrored here as the client-side default for a
48
+ * claim that names no `ttl` — it sets the auto-heartbeat cadence.
49
+ */
50
+ const DEFAULT_CLAIM_TTL_MS = 60_000;
40
51
  function parseSuccessfulCommitResponse(value, idempotencyKey) {
41
52
  const parsed = commitReceiptSchema.safeParse(value);
42
53
  if (!parsed.success || parsed.data.clientTxId !== idempotencyKey) {
@@ -51,6 +62,10 @@ function parseSuccessfulCommitResponse(value, idempotencyKey) {
51
62
  }
52
63
  /** Decode the HTTP claim DTO into the one public Claim shape. */
53
64
  function claimFromModelClaim(claim) {
65
+ // The handle a caller reads back is a public claim, so its `meta` is the
66
+ // declared shape; the rest of the sub-entity locator crosses whole rather
67
+ // than member by member, which is how `fields` used to die on this hop.
68
+ const { meta, ...details } = subTarget(claim.target);
54
69
  return {
55
70
  object: 'claim',
56
71
  id: claim.id,
@@ -62,12 +77,9 @@ function claimFromModelClaim(claim) {
62
77
  expiresAt: claim.expiresAt,
63
78
  ...(claim.position !== undefined ? { position: claim.position } : {}),
64
79
  target: {
65
- type: claim.target.model,
66
- id: claim.target.id,
67
- ...(claim.target.path ? { path: claim.target.path } : {}),
68
- ...(claim.target.range ? { range: claim.target.range } : {}),
69
- ...(claim.target.field ? { field: claim.target.field } : {}),
70
- ...(claim.target.meta ? { meta: claim.target.meta } : {}),
80
+ ...streamTarget(claim.target),
81
+ ...details,
82
+ ...(meta !== undefined ? { meta: declaredMeta(meta) } : {}),
71
83
  },
72
84
  };
73
85
  }
@@ -159,7 +171,7 @@ export function createHttpTransport(options) {
159
171
  }
160
172
  : undefined;
161
173
  if (!scope) {
162
- const rawIdentity = await requestJson('/auth/identity', { method: 'GET' }, true);
174
+ const rawIdentity = await requestRaw('/auth/identity', { method: 'GET' }, true);
163
175
  const identity = parseIdentityResolveResponse(rawIdentity);
164
176
  scope = {
165
177
  organizationId: identity.accountScope,
@@ -226,7 +238,15 @@ export function createHttpTransport(options) {
226
238
  return target.toString();
227
239
  }
228
240
  const requestTimeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
229
- async function requestJson(path, init, skipReady = false) {
241
+ /**
242
+ * Issues one request and returns its decoded body without a contract.
243
+ *
244
+ * Use this only where the response has no shape worth checking — a release
245
+ * that answers `{}` — or where the caller runs a richer check of its own, as
246
+ * the commit paths do with their receipt schema. Everywhere else, go through
247
+ * {@link requestJson}, which will not let a response past unvalidated.
248
+ */
249
+ async function requestRaw(path, init, skipReady = false) {
230
250
  if (!skipReady)
231
251
  await ready();
232
252
  const { idempotencyKey, sealedProtocolVersion, ...requestInit } = init;
@@ -295,6 +315,22 @@ export function createHttpTransport(options) {
295
315
  }
296
316
  return body;
297
317
  }
318
+ /**
319
+ * Issues one request and validates its body against the route's schema.
320
+ *
321
+ * The schema is the route's response contract, declared once in `wire/` and
322
+ * shared with the server that produces it. A body that does not match is a
323
+ * version disagreement between the two, so it is refused whole rather than
324
+ * read field by field and half-trusted.
325
+ */
326
+ async function requestJson(path, init, responseSchema, skipReady = false) {
327
+ const body = await requestRaw(path, init, skipReady);
328
+ const parsed = responseSchema.safeParse(body);
329
+ if (!parsed.success) {
330
+ throw new AbloConnectionError(`The Ablo API returned a response for ${init.method ?? 'GET'} ${path} that this client could not read; nothing was applied.`, { code: 'malformed_response', cause: parsed.error });
331
+ }
332
+ return parsed.data;
333
+ }
298
334
  function isDefinitiveHttpRejection(error) {
299
335
  if (typeof error !== 'object' || error === null)
300
336
  return false;
@@ -388,7 +424,7 @@ export function createHttpTransport(options) {
388
424
  }, remaining)
389
425
  : null;
390
426
  try {
391
- const raw = await requestJson(request.path, {
427
+ const raw = await requestRaw(request.path, {
392
428
  method: request.method,
393
429
  idempotencyKey: request.idempotencyKey,
394
430
  ...(request.sealedProtocolVersion !== undefined
@@ -456,7 +492,7 @@ export function createHttpTransport(options) {
456
492
  a.id.localeCompare(b.id));
457
493
  for (const envelope of envelopes) {
458
494
  try {
459
- const raw = await requestJson(envelope.request.path, {
495
+ const raw = await requestRaw(envelope.request.path, {
460
496
  method: envelope.request.method,
461
497
  idempotencyKey: envelope.idempotencyKey,
462
498
  sealedProtocolVersion: envelope.protocolVersion,
@@ -613,7 +649,7 @@ export function createHttpTransport(options) {
613
649
  };
614
650
  let response;
615
651
  try {
616
- const raw = await requestJson(exactRequest.path, {
652
+ const raw = await requestRaw(exactRequest.path, {
617
653
  method: exactRequest.method,
618
654
  idempotencyKey: exactRequest.idempotencyKey,
619
655
  ...(exactRequest.sealedProtocolVersion !== undefined
@@ -654,11 +690,6 @@ export function createHttpTransport(options) {
654
690
  ? crypto.randomUUID()
655
691
  : `tx_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
656
692
  }
657
- function createClaimId() {
658
- return typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
659
- ? `int_${crypto.randomUUID()}`
660
- : `int_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
661
- }
662
693
  function createModelId(modelName, idempotencyKey) {
663
694
  if (idempotencyKey) {
664
695
  return uuidv5(`${modelName}:${idempotencyKey}`, 'aa4ba6d4-bf0b-5b38-9c45-116f79a6e548');
@@ -698,13 +729,8 @@ export function createHttpTransport(options) {
698
729
  if (target?.field)
699
730
  params.set('field', target.field);
700
731
  const suffix = params.toString();
701
- const body = await requestJson(`/v1/claims${suffix ? `?${suffix}` : ''}`, {
702
- method: 'GET',
703
- });
704
- return {
705
- active: body.claims ?? [],
706
- queue: body.queue ?? [],
707
- };
732
+ const body = await requestJson(`/v1/claims${suffix ? `?${suffix}` : ''}`, { method: 'GET' }, claimListResponseSchema);
733
+ return { active: body.claims, queue: body.queue };
708
734
  }
709
735
  async function applyClaimedPolicy(target, options, defaultPolicy = 'return') {
710
736
  const policy = options?.ifClaimed ?? defaultPolicy;
@@ -761,14 +787,14 @@ export function createHttpTransport(options) {
761
787
  })));
762
788
  throw error;
763
789
  }
764
- // `requestJson` throws via `translateHttpError` on any non-2xx,
765
- // so reaching here implies success. Narrow `status` to the
766
- // `CommitWait`-compatible subset; `'rejected'` only appears on
767
- // the rejection body (already thrown).
768
- const status = body.status === 'queued' ? 'queued' : 'confirmed';
790
+ // `requestJson` throws via `translateHttpError` on any non-2xx, so
791
+ // reaching here implies success and `body` is already the success-only
792
+ // receipt union a rejection is a separate type that never arrives here.
793
+ // The settlement status therefore passes through verbatim: no branch may
794
+ // collapse a state the server reported into a different one.
769
795
  return {
770
796
  id: body.id ?? body.clientTxId,
771
- status,
797
+ status: body.status,
772
798
  lastSyncId: body.lastSyncId,
773
799
  ...(body.notifications && body.notifications.length > 0
774
800
  ? { notifications: body.notifications }
@@ -799,26 +825,26 @@ export function createHttpTransport(options) {
799
825
  }
800
826
  }
801
827
  const qs = params.toString();
802
- const res = await requestJson(`/v1/models/${encodeURIComponent(modelName)}${qs ? `?${qs}` : ''}`, { method: 'GET' });
803
- return res.data ?? [];
828
+ const res = await requestJson(`/v1/models/${encodeURIComponent(modelName)}${qs ? `?${qs}` : ''}`, { method: 'GET' }, modelListResponseSchema);
829
+ // The envelope is checked; the rows are not, and cannot be here. This
830
+ // transport is schema-agnostic — it moves rows for whatever schema the
831
+ // caller declared, and `T` is that declaration. Row validation belongs to
832
+ // the typed facade above, which holds the model's schema.
833
+ return res.data;
804
834
  }
805
835
  async function retrieveModel(modelName, params) {
806
836
  await applyClaimedPolicy({ model: modelName, id: params.id }, params);
807
- const query = await requestJson(`/v1/models/${encodeURIComponent(modelName)}/${encodeURIComponent(params.id)}`, {
808
- method: 'GET',
809
- });
837
+ const query = await requestJson(`/v1/models/${encodeURIComponent(modelName)}/${encodeURIComponent(params.id)}`, { method: 'GET' }, modelReadResponseSchema);
810
838
  // A miss is `data: undefined`, not a thrown error. The WebSocket client's
811
839
  // `retrieve` returns `T | undefined` for a missing row; throwing only here
812
840
  // made the obvious read ("does this row exist?") a hard edge that an agent
813
841
  // had to wrap in try/catch. Both transports agree: an absent row means absent
814
842
  // data. Callers branch on `.data` (the documented `.data?.x` usage).
815
843
  // Normalize a miss to `undefined` (the server may send `null` or omit it).
844
+ // The row itself is the caller's declared type — see the note in `listModel`
845
+ // on why this transport validates the envelope and not the row.
816
846
  const data = (query.data ?? undefined);
817
- return {
818
- data,
819
- stamp: query.stamp ?? 0,
820
- claims: query.claims ?? [],
821
- };
847
+ return { data, stamp: query.stamp, claims: query.claims };
822
848
  }
823
849
  /**
824
850
  * A single-operation mutation over the model-scoped routes — the canonical
@@ -884,13 +910,12 @@ export function createHttpTransport(options) {
884
910
  recordCoordinationConflict(error, clientTxId, [{ model: modelName, id }]);
885
911
  throw error;
886
912
  }
887
- // `requestJson` throws via `translateHttpError` on any non-2xx, so reaching
888
- // here implies success. Narrow `status` to the `CommitWait`-compatible
889
- // subset; `'rejected'` only appears on a thrown rejection body.
890
- const status = body.status === 'queued' ? 'queued' : 'confirmed';
913
+ // Same contract as `commits.create` above: a non-2xx already threw, so
914
+ // `body` is the success-only receipt union and its settlement status passes
915
+ // through verbatim rather than through a catch-all branch.
891
916
  return {
892
917
  id: body.serverTxId,
893
- status,
918
+ status: body.status,
894
919
  lastSyncId: body.lastSyncId,
895
920
  };
896
921
  }
@@ -904,30 +929,56 @@ export function createHttpTransport(options) {
904
929
  value.object === 'claim' &&
905
930
  typeof value.id === 'string' &&
906
931
  typeof value.release === 'function';
907
- const claimMeta = (options) => options?.meta;
908
932
  const acquireClaim = async (params) => {
909
- const body = await requestJson(claimPath(params.id), {
910
- method: 'POST',
911
- body: JSON.stringify({
912
- description: params.description ?? 'editing',
913
- ...(params.ttl !== undefined ? { ttl: params.ttl } : {}),
914
- ...(claimMeta(params) ? { meta: claimMeta(params) } : {}),
915
- // `queue` (default true) queue behind the holder; false → fail-fast
916
- // with AbloClaimedError (work-distribution dedup).
917
- queue: params.queue ?? true,
918
- }),
919
- });
920
- if (body.status === 'queued') {
921
- throw new AbloClaimedError(`Target ${name}/${params.id} is held; queued at position ${body.position ?? 0}. ` +
922
- `The HTTP client cannot await the grant without a WebSocket.`, { code: 'claim_queued' });
933
+ // The row is named by the URL, so `target` carries only the narrowing a
934
+ // claim adds below it. Sending it is what makes a field-scoped claim
935
+ // actually field-scoped: the server's conflict rule reads `path`,
936
+ // `range`, and `field`, so a claim that keeps them client-side takes a
937
+ // lease on the whole row while its handle says otherwise.
938
+ // Projected in one move rather than member by member. The member-by-member
939
+ // version is how `field` came to be sent while `fields` was not, which
940
+ // left a set-scoped claim silently holding the whole row.
941
+ const narrowing = subTarget(params);
942
+ // Typed as the request contract rather than a bare literal — the omission
943
+ // above was invisible for exactly as long as this was an untyped object.
944
+ const request = {
945
+ description: claimDescription(params),
946
+ ...(params.ttl !== undefined ? { ttl: params.ttl } : {}),
947
+ // The caller's `meta` is the declared shape; the body is wire-shaped,
948
+ // so it crosses through the same conversion `subTarget` used above.
949
+ ...(params.meta !== undefined ? { meta: wireMeta(params.meta) } : {}),
950
+ ...(Object.keys(narrowing).length > 0 ? { target: narrowing } : {}),
951
+ // `queue` (default true) → queue behind the holder; false → fail-fast
952
+ // with AbloClaimedError (work-distribution dedup).
953
+ queue: params.queue ?? true,
954
+ };
955
+ const body = await requestJson(claimPath(params.id), { method: 'POST', body: JSON.stringify(request) }, claimAcquireResponseSchema);
956
+ // HELD BY ADR 0018 (`docs/decisions/0018-the-premise-is-the-missing-structure.md`).
957
+ // Raising a successful outcome as an exception is wrong, and this stays
958
+ // wrong on purpose: it is the symptom the ADR is derived from, so removing
959
+ // the smell without the structure would hide the reason for the work.
960
+ //
961
+ // Being queued is not a transport failure — it is "I cannot establish my
962
+ // premise yet." Premise is the structure the codebase approximates six
963
+ // ways and has never modelled, which is why this was never solvable here.
964
+ // A client-side polling loop is specifically ruled out: it would become a
965
+ // shape callers build against, and the better it worked the harder it
966
+ // would be to replace with the status this should be.
967
+ //
968
+ // A caller that must wait today can poll `GET /v1/claims/{claimId}`, which
969
+ // is served and published. That primitive is safe to build on; a blessed
970
+ // wait algorithm here is not.
971
+ // The two arms are told apart by `status`, which only the queued reply
972
+ // carries — see `claimAcquireResponseSchema` for why they cannot be a
973
+ // discriminated union.
974
+ if ('status' in body) {
975
+ throw new AbloClaimedError(`Target ${name}/${params.id} is held; queued at position ${body.position}. ` +
976
+ `Poll \`GET /v1/claims/{claimId}\` for the grant — the HTTP client does not await it.`, { code: 'claim_queued' });
923
977
  }
924
- // `claimId` is the field name the queued response uses; check it alongside
925
- // the other id shapes the response may carry.
926
- const id = body.claim?.id ?? body.id ?? body.claimId ?? createClaimId();
927
- const fenceToken = body.claim?.fenceToken;
978
+ const { id, fenceToken } = body.claim;
928
979
  return fenceToken !== undefined ? { id, fenceToken } : { id };
929
980
  };
930
- const releaseClaim = (params) => requestJson(claimPath(isClaimHandle(params) ? params.target.id : params.id), {
981
+ const releaseClaim = (params) => requestRaw(claimPath(isClaimHandle(params) ? params.target.id : params.id), {
931
982
  method: 'DELETE',
932
983
  }).then(() => undefined);
933
984
  // One beat on the held lease. A lapsed lease answers `claim_lost`
@@ -941,7 +992,7 @@ export function createHttpTransport(options) {
941
992
  ...(options.ttl !== undefined ? { ttl: options.ttl } : {}),
942
993
  ...(options.details !== undefined ? { details: options.details } : {}),
943
994
  }),
944
- });
995
+ }, claimHeartbeatReplySchema);
945
996
  return heldHeartbeatReply(reply, `claim ${claimId} on ${name}/${id}`);
946
997
  };
947
998
  async function claimImpl(params) {
@@ -952,7 +1003,7 @@ export function createHttpTransport(options) {
952
1003
  model: name,
953
1004
  id: params.id,
954
1005
  ...(params.field ? { field: params.field } : {}),
955
- reason: params.description ?? 'editing',
1006
+ description: claimDescription(params),
956
1007
  });
957
1008
  const { data, stamp } = await retrieveModel(name, { id: params.id });
958
1009
  // A held claim hands back a snapshot; the typed `HeldClaim.data` is `T`.
@@ -971,12 +1022,12 @@ export function createHttpTransport(options) {
971
1022
  return beat;
972
1023
  };
973
1024
  // Opt-in auto-heartbeat — the background-worker cadence. The stateless
974
- // HTTP claim defaults to the server's 60s acquire window when no TTL
1025
+ // HTTP claim defaults to the server's acquire window when no TTL
975
1026
  // was requested, so the default cadence lands at 20s beats.
976
1027
  const stopHeartbeatLoop = params.heartbeat
977
1028
  ? startClaimHeartbeatLoop({
978
1029
  beat: () => heartbeat(),
979
- intervalMs: heartbeatCadenceMs(params.ttl !== undefined ? toMs(params.ttl) : 60_000, params.heartbeat),
1030
+ intervalMs: heartbeatCadenceMs(params.ttl !== undefined ? toMs(params.ttl) : DEFAULT_CLAIM_TTL_MS, params.heartbeat),
980
1031
  ...(params.onHeartbeatLost ? { onLost: params.onHeartbeatLost } : {}),
981
1032
  })
982
1033
  : undefined;
@@ -984,20 +1035,22 @@ export function createHttpTransport(options) {
984
1035
  stopHeartbeatLoop?.();
985
1036
  return releaseClaim(params);
986
1037
  };
1038
+ // The handle handed back is a public claim, so its `meta` is the declared
1039
+ // shape — the same crossing the two decodes above make, spelled the same
1040
+ // way. `subTarget` is wire-shaped by contract, including here, where the
1041
+ // value happens to have started out declared.
1042
+ const { meta, ...narrowed } = subTarget(params);
987
1043
  return {
988
1044
  object: 'claim',
989
1045
  id: claimId,
990
1046
  readAt: stamp,
991
1047
  ...(fenceToken !== undefined ? { fenceToken } : {}),
992
1048
  target: {
993
- type: name,
994
- id: params.id,
995
- ...(params.field ? { field: params.field } : {}),
996
- ...(params.path ? { path: params.path } : {}),
997
- ...(params.range ? { range: params.range } : {}),
998
- ...(claimMeta(params) ? { meta: claimMeta(params) } : {}),
1049
+ ...streamTarget({ model: name, id: params.id }),
1050
+ ...narrowed,
1051
+ ...(meta !== undefined ? { meta: declaredMeta(meta) } : {}),
999
1052
  },
1000
- description: params.description ?? 'editing',
1053
+ description: claimDescription(params),
1001
1054
  data,
1002
1055
  release,
1003
1056
  revoke: () => {
@@ -1007,7 +1060,7 @@ export function createHttpTransport(options) {
1007
1060
  [Symbol.asyncDispose]: release,
1008
1061
  };
1009
1062
  }
1010
- const claimsForEntity = async (params) => requestJson(`/v1/claims?model=${encodeURIComponent(name)}&id=${encodeURIComponent(params.id)}${params.field ? `&field=${encodeURIComponent(params.field)}` : ''}`, { method: 'GET' });
1063
+ const claimsForEntity = (params) => requestJson(`/v1/claims?model=${encodeURIComponent(name)}&id=${encodeURIComponent(params.id)}${params.field ? `&field=${encodeURIComponent(params.field)}` : ''}`, { method: 'GET' }, claimListResponseSchema);
1011
1064
  const claim = Object.assign(claimImpl, {
1012
1065
  release: releaseClaim,
1013
1066
  state: async (params) => {
@@ -1023,7 +1076,7 @@ export function createHttpTransport(options) {
1023
1076
  };
1024
1077
  },
1025
1078
  reorder: async (params) => {
1026
- await requestJson(`${claimPath(params.id)}/reorder`, {
1079
+ await requestRaw(`${claimPath(params.id)}/reorder`, {
1027
1080
  method: 'POST',
1028
1081
  // The reorder route's payload is `{ heldBy, claimId }[]` — a Claim's id
1029
1082
  // is the claimId.
@@ -1136,6 +1189,29 @@ export function createHttpTransport(options) {
1136
1189
  return mutateModel('delete', name, params.id, undefined, options);
1137
1190
  });
1138
1191
  },
1192
+ async track(params) {
1193
+ const dependency = {
1194
+ model: name.toLowerCase(),
1195
+ id: params.id,
1196
+ ...(params.readAt !== undefined ? { readAt: params.readAt } : {}),
1197
+ };
1198
+ // A track carries no write, so it rides the commit lane as a
1199
+ // zero-operation body — the shape `/v1/commits` accepts for registering
1200
+ // a premise without one. Going through the same durable lane as every
1201
+ // other commit means a disconnect replays the registration rather than
1202
+ // dropping it, and a notification that had already fired is not lost to
1203
+ // a retry.
1204
+ const body = await dispatchHttpCommit({
1205
+ path: '/v1/commits',
1206
+ method: 'POST',
1207
+ idempotencyKey: createClientTxId(),
1208
+ body: { track: [dependency] },
1209
+ wait: 'confirmed',
1210
+ });
1211
+ return body.notifications && body.notifications.length > 0
1212
+ ? { notifications: body.notifications }
1213
+ : {};
1214
+ },
1139
1215
  };
1140
1216
  }
1141
1217
  return {
@@ -1158,11 +1234,21 @@ export function createHttpTransport(options) {
1158
1234
  if (!apiKey) {
1159
1235
  throw new AbloAuthenticationError('sessions.create requires a secret (sk_) API key — call it from your backend, not the browser.', { code: 'apikey_missing' });
1160
1236
  }
1237
+ // A transport built without a schema has no way to translate `can`'s
1238
+ // schema keys into the type names the server gates on. Minting anyway
1239
+ // would spell every override wrong and surface as
1240
+ // `capability_scope_denied` on the agent's first write, so refuse here
1241
+ // instead of guessing.
1242
+ if (!options.modelTypenames) {
1243
+ throw new AbloValidationError('sessions.create needs the schema this client is bound to. Construct it ' +
1244
+ "through Ablo({ schema, apiKey, transport: 'http' }) rather than the " +
1245
+ 'bare transport.', { code: 'invalid_options', param: 'schema' });
1246
+ }
1161
1247
  return mintSession(params, {
1162
1248
  apiKey,
1163
1249
  baseUrl: apiBaseUrl,
1250
+ modelTypenames: options.modelTypenames,
1164
1251
  ...(options.fetch ? { fetch: options.fetch } : {}),
1165
- ...(options.modelTypenames ? { modelTypenames: options.modelTypenames } : {}),
1166
1252
  });
1167
1253
  },
1168
1254
  },
@@ -23,11 +23,12 @@
23
23
  */
24
24
  import { z } from 'zod';
25
25
  import { type AuthTokenGetter } from '../auth/credentialSource.js';
26
+ import { type Logger } from '../logger.js';
26
27
  /**
27
28
  * The complete set of probe outcomes. Each value carries both reachability and
28
- * credential state, so {@link ConnectionManager} can branch on one exhaustive
29
+ * credential state, so the connection state machine can branch on one exhaustive
29
30
  * discriminant instead of piecing the situation together from several booleans.
30
- * It mirrors the {@link RecoveryClass} taxonomy at the connectivity layer.
31
+ * It mirrors the `RecoveryClass` taxonomy at the connectivity layer.
31
32
  */
32
33
  export declare const PROBE_OUTCOMES: readonly ["reachable", "unreachable", "session_expired", "credential_stale", "auth_blocked"];
33
34
  /** Zod enum derived from {@link PROBE_OUTCOMES}. */
@@ -69,11 +70,13 @@ export interface NetworkProbeOptions {
69
70
  getAuthToken?: AuthTokenGetter;
70
71
  /** Compatibility fallback for callers with a copied token string. */
71
72
  authToken?: string | null;
73
+ /** Where probe outcomes are logged. Defaults to silent. */
74
+ logger?: Logger;
72
75
  }
73
76
  /**
74
77
  * Probes the sync server with a lightweight HEAD request, returning both
75
- * reachability and session status in a single call so {@link ConnectionManager}
76
- * can pick the right state transition without guessing.
78
+ * reachability and session status in a single call so the connection state
79
+ * machine can pick the right transition without guessing.
77
80
  *
78
81
  * @param input The sync-server base URL (an HTTP or WS scheme is accepted), or
79
82
  * an options bag. A bare string is also accepted.
@@ -22,15 +22,15 @@
22
22
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine
23
23
  */
24
24
  import { z } from 'zod';
25
- import { getContext } from '../context.js';
26
25
  import { classifyRecovery } from '../errors.js';
27
26
  import { withAuthHeaders } from '../auth/credentialSource.js';
28
- import { ABLO_DEFAULT_BASE_URL } from '../client/hostedEndpoints.js';
27
+ import { ABLO_DEFAULT_BASE_URL } from '../auth/hostedEndpoints.js';
28
+ import { noopLogger } from '../logger.js';
29
29
  /**
30
30
  * The complete set of probe outcomes. Each value carries both reachability and
31
- * credential state, so {@link ConnectionManager} can branch on one exhaustive
31
+ * credential state, so the connection state machine can branch on one exhaustive
32
32
  * discriminant instead of piecing the situation together from several booleans.
33
- * It mirrors the {@link RecoveryClass} taxonomy at the connectivity layer.
33
+ * It mirrors the `RecoveryClass` taxonomy at the connectivity layer.
34
34
  */
35
35
  export const PROBE_OUTCOMES = [
36
36
  /** Server reachable and the access credential is currently valid. */
@@ -72,8 +72,8 @@ function resolveProbeUrl(baseUrl) {
72
72
  }
73
73
  /**
74
74
  * Probes the sync server with a lightweight HEAD request, returning both
75
- * reachability and session status in a single call so {@link ConnectionManager}
76
- * can pick the right state transition without guessing.
75
+ * reachability and session status in a single call so the connection state
76
+ * machine can pick the right transition without guessing.
77
77
  *
78
78
  * @param input The sync-server base URL (an HTTP or WS scheme is accepted), or
79
79
  * an options bag. A bare string is also accepted.
@@ -82,6 +82,7 @@ export async function probeNetwork(input) {
82
82
  const baseUrl = typeof input === 'string' ? input : input?.baseUrl;
83
83
  const getAuthToken = typeof input === 'string' ? undefined : input?.getAuthToken;
84
84
  const authToken = typeof input === 'string' ? undefined : input?.authToken;
85
+ const logger = (typeof input === 'string' ? undefined : input?.logger) ?? noopLogger;
85
86
  const url = resolveProbeUrl(baseUrl);
86
87
  // Fast-fail: if navigator.onLine is false, skip the probe entirely. This is
87
88
  // the one case where navigator.onLine is reliable (MDN: "false means
@@ -115,14 +116,14 @@ export async function probeNetwork(input) {
115
116
  const recovery = classifyRecovery(authFailure);
116
117
  switch (recovery) {
117
118
  case 'session_expiry':
118
- getContext().logger.info('[NetworkProbe] Server reachable, login expired', {
119
+ logger.info('[NetworkProbe] Server reachable, login expired', {
119
120
  status: response.status,
120
121
  code: authFailure,
121
122
  latencyMs,
122
123
  });
123
124
  return { outcome: 'session_expired', latencyMs };
124
125
  case 'access_credential_expiry':
125
- getContext().logger.info('[NetworkProbe] Server reachable, access key stale — will re-mint', {
126
+ logger.info('[NetworkProbe] Server reachable, access key stale — will re-mint', {
126
127
  status: response.status,
127
128
  code: authFailure,
128
129
  latencyMs,
@@ -136,7 +137,7 @@ export async function probeNetwork(input) {
136
137
  // Re-authenticating re-mints the same rejected credential and
137
138
  // retrying will not help, so stop rather than reconnect-loop or sign
138
139
  // the user out.
139
- getContext().logger.debug('[NetworkProbe] Reachable but auth-blocked (non-retryable, non-expiry)', {
140
+ logger.debug('[NetworkProbe] Reachable but auth-blocked (non-retryable, non-expiry)', {
140
141
  status: response.status,
141
142
  code: authFailure,
142
143
  recovery,
@@ -168,7 +169,7 @@ export async function probeNetwork(input) {
168
169
  // counter falls through to `auth_blocked` (stop) — still never a spurious
169
170
  // logout. The invariant holds: null is the only terminal path, never a
170
171
  // bare 401.
171
- getContext().logger.info('[NetworkProbe] Server reachable, bare 401 — re-mint (not sign-out)', {
172
+ logger.info('[NetworkProbe] Server reachable, bare 401 — re-mint (not sign-out)', {
172
173
  latencyMs,
173
174
  });
174
175
  return { outcome: 'credential_stale', latencyMs };
@@ -178,14 +179,14 @@ export async function probeNetwork(input) {
178
179
  // expected 204; log a warning so misconfigurations surface instead of
179
180
  // silently passing.
180
181
  if (response.status < 200 || response.status >= 300) {
181
- getContext().logger.debug('[NetworkProbe] Unexpected probe response', {
182
+ logger.debug('[NetworkProbe] Unexpected probe response', {
182
183
  status: response.status,
183
184
  url,
184
185
  latencyMs,
185
186
  });
186
187
  }
187
188
  else {
188
- getContext().logger.debug('[NetworkProbe] Server reachable, credential valid', {
189
+ logger.debug('[NetworkProbe] Server reachable, credential valid', {
189
190
  status: response.status,
190
191
  latencyMs,
191
192
  });
@@ -195,7 +196,7 @@ export async function probeNetwork(input) {
195
196
  catch (error) {
196
197
  clearTimeout(timeout);
197
198
  const isAbort = error instanceof DOMException && error.name === 'AbortError';
198
- getContext().logger.info('[NetworkProbe] Probe failed', {
199
+ logger.info('[NetworkProbe] Probe failed', {
199
200
  reason: isAbort ? 'timeout' : error.message,
200
201
  });
201
202
  return { outcome: 'unreachable', latencyMs: null };