@abloatai/ablo 0.26.0 → 0.28.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 (418) hide show
  1. package/CHANGELOG.md +42 -2
  2. package/README.md +102 -86
  3. package/dist/BaseSyncedStore.d.ts +85 -88
  4. package/dist/BaseSyncedStore.js +134 -151
  5. package/dist/Database.d.ts +68 -69
  6. package/dist/Database.js +316 -135
  7. package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
  8. package/dist/{ObjectPool.js → InstanceCache.js} +85 -83
  9. package/dist/LazyReferenceCollection.d.ts +11 -15
  10. package/dist/LazyReferenceCollection.js +12 -16
  11. package/dist/Model.d.ts +54 -52
  12. package/dist/Model.js +78 -62
  13. package/dist/ModelRegistry.d.ts +21 -19
  14. package/dist/ModelRegistry.js +23 -27
  15. package/dist/NetworkMonitor.d.ts +5 -6
  16. package/dist/NetworkMonitor.js +5 -6
  17. package/dist/SyncClient.d.ts +122 -118
  18. package/dist/SyncClient.js +541 -245
  19. package/dist/adapters/alwaysOnline.d.ts +6 -8
  20. package/dist/adapters/alwaysOnline.js +6 -8
  21. package/dist/adapters/inMemoryStorage.d.ts +10 -9
  22. package/dist/adapters/inMemoryStorage.js +21 -9
  23. package/dist/agent/Agent.d.ts +27 -32
  24. package/dist/agent/Agent.js +18 -19
  25. package/dist/agent/index.d.ts +4 -4
  26. package/dist/agent/index.js +5 -5
  27. package/dist/agent/session.d.ts +47 -44
  28. package/dist/agent/session.js +37 -48
  29. package/dist/agent/types.d.ts +26 -31
  30. package/dist/agent/types.js +6 -7
  31. package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
  32. package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
  33. package/dist/ai-sdk/coordinationContext.d.ts +46 -0
  34. package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +26 -33
  35. package/dist/ai-sdk/index.d.ts +25 -22
  36. package/dist/ai-sdk/index.js +25 -22
  37. package/dist/ai-sdk/wrap.d.ts +6 -7
  38. package/dist/ai-sdk/wrap.js +1 -1
  39. package/dist/auth/credentialPolicy.d.ts +69 -74
  40. package/dist/auth/credentialPolicy.js +51 -56
  41. package/dist/auth/credentialSource.d.ts +6 -5
  42. package/dist/auth/credentialSource.js +9 -10
  43. package/dist/auth/index.d.ts +59 -58
  44. package/dist/auth/index.js +31 -37
  45. package/dist/auth/schemas.d.ts +5 -4
  46. package/dist/auth/schemas.js +5 -4
  47. package/dist/batching/index.d.ts +19 -21
  48. package/dist/batching/index.js +14 -17
  49. package/dist/cli.cjs +173 -121
  50. package/dist/client/Ablo.d.ts +97 -74
  51. package/dist/client/Ablo.js +129 -163
  52. package/dist/client/ApiClient.d.ts +30 -19
  53. package/dist/client/ApiClient.js +442 -81
  54. package/dist/client/auth.d.ts +47 -47
  55. package/dist/client/auth.js +108 -117
  56. package/dist/client/claimHeartbeatLoop.d.ts +50 -0
  57. package/dist/client/claimHeartbeatLoop.js +88 -0
  58. package/dist/client/consoleLogger.d.ts +5 -6
  59. package/dist/client/consoleLogger.js +5 -6
  60. package/dist/client/createInternalComponents.d.ts +16 -17
  61. package/dist/client/createInternalComponents.js +26 -31
  62. package/dist/client/createModelProxy.d.ts +130 -120
  63. package/dist/client/createModelProxy.js +152 -122
  64. package/dist/client/credentialEndpoint.d.ts +40 -42
  65. package/dist/client/credentialEndpoint.js +35 -36
  66. package/dist/client/functionalUpdate.d.ts +29 -27
  67. package/dist/client/functionalUpdate.js +21 -21
  68. package/dist/client/hostedEndpoints.d.ts +9 -12
  69. package/dist/client/hostedEndpoints.js +9 -12
  70. package/dist/client/httpClient.d.ts +59 -53
  71. package/dist/client/httpClient.js +29 -31
  72. package/dist/client/identity.d.ts +15 -20
  73. package/dist/client/identity.js +47 -58
  74. package/dist/client/modelRegistration.d.ts +5 -9
  75. package/dist/client/modelRegistration.js +78 -87
  76. package/dist/client/options.d.ts +157 -157
  77. package/dist/client/options.js +3 -7
  78. package/dist/client/registerDataSource.d.ts +9 -9
  79. package/dist/client/registerDataSource.js +15 -16
  80. package/dist/client/resourceTypes.d.ts +64 -75
  81. package/dist/client/resourceTypes.js +4 -10
  82. package/dist/client/schemaConfig.d.ts +31 -43
  83. package/dist/client/schemaConfig.js +38 -50
  84. package/dist/client/sessionMint.d.ts +16 -12
  85. package/dist/client/sessionMint.js +26 -31
  86. package/dist/client/validateAbloOptions.d.ts +12 -14
  87. package/dist/client/validateAbloOptions.js +8 -9
  88. package/dist/client/writeOptionsSchema.d.ts +18 -16
  89. package/dist/client/writeOptionsSchema.js +23 -20
  90. package/dist/client/wsMutationExecutor.d.ts +16 -20
  91. package/dist/client/wsMutationExecutor.js +18 -23
  92. package/dist/commit/contract.d.ts +493 -0
  93. package/dist/commit/contract.js +187 -0
  94. package/dist/commit/index.d.ts +6 -0
  95. package/dist/commit/index.js +5 -0
  96. package/dist/context.d.ts +6 -4
  97. package/dist/context.js +6 -4
  98. package/dist/coordination/index.d.ts +10 -8
  99. package/dist/coordination/index.js +14 -12
  100. package/dist/coordination/schema.d.ts +176 -128
  101. package/dist/coordination/schema.js +197 -133
  102. package/dist/coordination/trace.d.ts +9 -10
  103. package/dist/coordination/trace.js +13 -14
  104. package/dist/core/DatabaseManager.d.ts +5 -7
  105. package/dist/core/DatabaseManager.js +15 -19
  106. package/dist/core/QueryProcessor.d.ts +7 -9
  107. package/dist/core/QueryProcessor.js +22 -28
  108. package/dist/core/QueryView.d.ts +8 -8
  109. package/dist/core/QueryView.js +2 -2
  110. package/dist/core/StoreManager.d.ts +14 -14
  111. package/dist/core/StoreManager.js +33 -24
  112. package/dist/core/ViewRegistry.d.ts +5 -5
  113. package/dist/core/ViewRegistry.js +4 -4
  114. package/dist/core/index.d.ts +17 -12
  115. package/dist/core/index.js +32 -26
  116. package/dist/core/openIDBWithTimeout.d.ts +38 -36
  117. package/dist/core/openIDBWithTimeout.js +42 -43
  118. package/dist/core/queryUtils.d.ts +45 -0
  119. package/dist/core/queryUtils.js +69 -0
  120. package/dist/core/storeContract.d.ts +63 -61
  121. package/dist/core/storeContract.js +8 -12
  122. package/dist/environment.d.ts +28 -0
  123. package/dist/environment.js +21 -0
  124. package/dist/errorCodes.d.ts +107 -99
  125. package/dist/errorCodes.js +137 -134
  126. package/dist/errors.d.ts +160 -166
  127. package/dist/errors.js +155 -158
  128. package/dist/index.d.ts +36 -27
  129. package/dist/index.js +91 -86
  130. package/dist/interfaces/index.d.ts +102 -113
  131. package/dist/interfaces/index.js +5 -4
  132. package/dist/keys/index.d.ts +27 -29
  133. package/dist/keys/index.js +41 -40
  134. package/dist/mutators/RecordingTransaction.d.ts +16 -16
  135. package/dist/mutators/RecordingTransaction.js +31 -37
  136. package/dist/mutators/Transaction.d.ts +18 -26
  137. package/dist/mutators/Transaction.js +14 -20
  138. package/dist/mutators/UndoManager.d.ts +124 -131
  139. package/dist/mutators/UndoManager.js +177 -156
  140. package/dist/mutators/defineMutators.d.ts +23 -34
  141. package/dist/mutators/defineMutators.js +14 -20
  142. package/dist/mutators/inverseOp.d.ts +12 -15
  143. package/dist/mutators/inverseOp.js +12 -15
  144. package/dist/mutators/mutateActions.d.ts +10 -9
  145. package/dist/mutators/mutateActions.js +1 -1
  146. package/dist/mutators/readerActions.d.ts +9 -8
  147. package/dist/mutators/readerActions.js +2 -2
  148. package/dist/mutators/undoApply.d.ts +31 -27
  149. package/dist/mutators/undoApply.js +26 -24
  150. package/dist/policy/index.d.ts +5 -3
  151. package/dist/policy/index.js +5 -3
  152. package/dist/policy/types.d.ts +104 -100
  153. package/dist/policy/types.js +67 -66
  154. package/dist/query/client.d.ts +28 -23
  155. package/dist/query/client.js +45 -43
  156. package/dist/query/types.d.ts +37 -60
  157. package/dist/query/types.js +13 -33
  158. package/dist/react/AbloProvider.d.ts +1 -1
  159. package/dist/react/AbloProvider.js +2 -2
  160. package/dist/react/context.d.ts +25 -28
  161. package/dist/react/context.js +9 -10
  162. package/dist/react/index.d.ts +41 -42
  163. package/dist/react/index.js +37 -38
  164. package/dist/react/internalContext.d.ts +17 -19
  165. package/dist/react/useAblo.d.ts +28 -25
  166. package/dist/react/useAblo.js +41 -17
  167. package/dist/react/useCurrentUserId.d.ts +8 -7
  168. package/dist/react/useCurrentUserId.js +8 -7
  169. package/dist/react/useErrorListener.d.ts +7 -7
  170. package/dist/react/useErrorListener.js +10 -11
  171. package/dist/react/useMutationFailureListener.d.ts +8 -8
  172. package/dist/react/useMutationFailureListener.js +8 -8
  173. package/dist/react/useMutators.d.ts +11 -11
  174. package/dist/react/useMutators.js +3 -3
  175. package/dist/react/useReactive.js +2 -2
  176. package/dist/react/useSyncStatus.d.ts +4 -6
  177. package/dist/react/useUndoScope.d.ts +7 -9
  178. package/dist/react/useUndoScope.js +1 -1
  179. package/dist/schema/coordination.d.ts +21 -25
  180. package/dist/schema/coordination.js +21 -25
  181. package/dist/schema/ddl.d.ts +43 -39
  182. package/dist/schema/ddl.js +75 -68
  183. package/dist/schema/ddlLock.d.ts +20 -24
  184. package/dist/schema/ddlLock.js +18 -23
  185. package/dist/schema/diff.d.ts +99 -61
  186. package/dist/schema/diff.js +43 -34
  187. package/dist/schema/field.d.ts +37 -42
  188. package/dist/schema/field.js +35 -48
  189. package/dist/schema/generate.d.ts +12 -12
  190. package/dist/schema/generate.js +12 -12
  191. package/dist/schema/index.d.ts +3 -3
  192. package/dist/schema/index.js +21 -23
  193. package/dist/schema/model.d.ts +118 -143
  194. package/dist/schema/model.js +22 -33
  195. package/dist/schema/openapi.d.ts +10 -9
  196. package/dist/schema/openapi.js +5 -3
  197. package/dist/schema/queries.d.ts +29 -31
  198. package/dist/schema/queries.js +23 -25
  199. package/dist/schema/relation.d.ts +89 -99
  200. package/dist/schema/relation.js +13 -13
  201. package/dist/schema/residency.d.ts +16 -13
  202. package/dist/schema/residency.js +16 -13
  203. package/dist/schema/roles.d.ts +36 -43
  204. package/dist/schema/roles.js +31 -37
  205. package/dist/schema/schema.d.ts +64 -43
  206. package/dist/schema/schema.js +31 -32
  207. package/dist/schema/select.d.ts +13 -13
  208. package/dist/schema/select.js +13 -13
  209. package/dist/schema/serialize.d.ts +28 -31
  210. package/dist/schema/serialize.js +27 -31
  211. package/dist/schema/sugar.d.ts +17 -32
  212. package/dist/schema/sugar.js +14 -29
  213. package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +26 -49
  214. package/dist/schema/syncDeltaRow.js +89 -0
  215. package/dist/schema/tenancy.d.ts +44 -46
  216. package/dist/schema/tenancy.js +46 -48
  217. package/dist/server/adapter.d.ts +58 -58
  218. package/dist/server/adapter.js +13 -14
  219. package/dist/server/commit.d.ts +60 -64
  220. package/dist/server/index.d.ts +9 -10
  221. package/dist/server/index.js +1 -1
  222. package/dist/server/readConfig.d.ts +70 -0
  223. package/dist/server/readConfig.js +8 -0
  224. package/dist/server/storageMode.d.ts +23 -0
  225. package/dist/server/storageMode.js +17 -0
  226. package/dist/source/adapter.d.ts +30 -25
  227. package/dist/source/adapter.js +10 -10
  228. package/dist/source/adapters/drizzle.d.ts +28 -23
  229. package/dist/source/adapters/drizzle.js +30 -25
  230. package/dist/source/adapters/kysely.d.ts +27 -25
  231. package/dist/source/adapters/kysely.js +24 -23
  232. package/dist/source/adapters/memory.d.ts +8 -7
  233. package/dist/source/adapters/memory.js +9 -8
  234. package/dist/source/adapters/prisma.d.ts +13 -12
  235. package/dist/source/adapters/prisma.js +22 -25
  236. package/dist/source/conformance.d.ts +18 -11
  237. package/dist/source/conformance.js +17 -11
  238. package/dist/source/connector.d.ts +31 -32
  239. package/dist/source/connector.js +28 -28
  240. package/dist/source/connectorProtocol.d.ts +160 -0
  241. package/dist/source/connectorProtocol.js +162 -0
  242. package/dist/source/contract.d.ts +26 -27
  243. package/dist/source/contract.js +28 -29
  244. package/dist/source/factory.d.ts +46 -58
  245. package/dist/source/factory.js +22 -27
  246. package/dist/source/index.d.ts +7 -9
  247. package/dist/source/index.js +12 -14
  248. package/dist/source/migrations.d.ts +9 -9
  249. package/dist/source/migrations.js +9 -9
  250. package/dist/source/next.d.ts +9 -10
  251. package/dist/source/next.js +6 -7
  252. package/dist/source/pushQueue.d.ts +69 -47
  253. package/dist/source/pushQueue.js +32 -28
  254. package/dist/source/signing.d.ts +46 -17
  255. package/dist/source/signing.js +28 -11
  256. package/dist/source/types.d.ts +121 -104
  257. package/dist/source/types.js +13 -14
  258. package/dist/stores/ObjectStore.d.ts +24 -12
  259. package/dist/stores/ObjectStore.js +38 -16
  260. package/dist/stores/ObjectStoreContract.d.ts +14 -15
  261. package/dist/stores/SyncActionStore.d.ts +7 -11
  262. package/dist/stores/SyncActionStore.js +13 -17
  263. package/dist/surface.d.ts +28 -21
  264. package/dist/surface.js +29 -20
  265. package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +36 -42
  266. package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +76 -76
  267. package/dist/sync/ConnectionManager.d.ts +39 -50
  268. package/dist/sync/ConnectionManager.js +55 -66
  269. package/dist/sync/NetworkProbe.d.ts +24 -29
  270. package/dist/sync/NetworkProbe.js +63 -69
  271. package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +42 -41
  272. package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +59 -54
  273. package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +43 -57
  274. package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +43 -51
  275. package/dist/sync/SyncWebSocket.d.ts +141 -166
  276. package/dist/sync/SyncWebSocket.js +191 -223
  277. package/dist/sync/awaitClaimGrant.d.ts +18 -18
  278. package/dist/sync/awaitClaimGrant.js +11 -11
  279. package/dist/sync/bootstrapApply.d.ts +34 -24
  280. package/dist/sync/bootstrapApply.js +27 -19
  281. package/dist/sync/commitFrames.d.ts +21 -20
  282. package/dist/sync/commitFrames.js +18 -18
  283. package/dist/sync/createClaimStream.d.ts +23 -22
  284. package/dist/sync/createClaimStream.js +105 -23
  285. package/dist/sync/createPresenceStream.d.ts +19 -18
  286. package/dist/sync/createPresenceStream.js +25 -26
  287. package/dist/sync/createSnapshot.d.ts +12 -14
  288. package/dist/sync/createSnapshot.js +20 -26
  289. package/dist/sync/credentialLifecycle.d.ts +104 -104
  290. package/dist/sync/credentialLifecycle.js +140 -147
  291. package/dist/sync/deltaPipeline.d.ts +36 -34
  292. package/dist/sync/deltaPipeline.js +64 -65
  293. package/dist/sync/groupChange.d.ts +63 -61
  294. package/dist/sync/groupChange.js +74 -78
  295. package/dist/sync/heartbeat.d.ts +34 -33
  296. package/dist/sync/heartbeat.js +31 -31
  297. package/dist/sync/participants.d.ts +19 -19
  298. package/dist/sync/persistedPrefix.d.ts +12 -0
  299. package/dist/sync/persistedPrefix.js +22 -0
  300. package/dist/sync/schemas.d.ts +3 -2
  301. package/dist/sync/schemas.js +14 -10
  302. package/dist/sync/syncCursor.d.ts +17 -21
  303. package/dist/sync/syncCursor.js +17 -21
  304. package/dist/sync/syncPlan.d.ts +28 -36
  305. package/dist/sync/syncPlan.js +18 -19
  306. package/dist/sync/syncPosition.d.ts +54 -49
  307. package/dist/sync/syncPosition.js +57 -52
  308. package/dist/sync/wsFrameHandlers.d.ts +35 -36
  309. package/dist/sync/wsFrameHandlers.js +63 -67
  310. package/dist/testing/fixtures/bootstrap.d.ts +12 -6
  311. package/dist/testing/fixtures/bootstrap.js +12 -6
  312. package/dist/testing/fixtures/deltas.d.ts +30 -33
  313. package/dist/testing/fixtures/deltas.js +30 -33
  314. package/dist/testing/fixtures/models.d.ts +11 -10
  315. package/dist/testing/fixtures/models.js +11 -10
  316. package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
  317. package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
  318. package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -15
  319. package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +12 -10
  320. package/dist/testing/helpers/wait.d.ts +13 -8
  321. package/dist/testing/helpers/wait.js +13 -8
  322. package/dist/testing/index.d.ts +5 -3
  323. package/dist/testing/index.js +3 -2
  324. package/dist/testing/mocks/FakeDatabase.d.ts +18 -0
  325. package/dist/testing/mocks/FakeDatabase.js +10 -0
  326. package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
  327. package/dist/testing/mocks/MockMutationExecutor.js +15 -14
  328. package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
  329. package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
  330. package/dist/testing/mocks/MockSyncContext.d.ts +20 -17
  331. package/dist/testing/mocks/MockSyncContext.js +15 -13
  332. package/dist/testing/mocks/MockSyncStore.d.ts +10 -10
  333. package/dist/testing/mocks/MockSyncStore.js +11 -11
  334. package/dist/testing/mocks/MockWebSocket.d.ts +28 -23
  335. package/dist/testing/mocks/MockWebSocket.js +22 -21
  336. package/dist/transactions/TransactionQueue.d.ts +244 -181
  337. package/dist/transactions/TransactionQueue.js +929 -423
  338. package/dist/transactions/TransactionStore.d.ts +6 -4
  339. package/dist/transactions/TransactionStore.js +6 -4
  340. package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
  341. package/dist/transactions/UnconfirmedWrites.js +104 -0
  342. package/dist/transactions/coalesceRules.d.ts +41 -17
  343. package/dist/transactions/coalesceRules.js +40 -17
  344. package/dist/transactions/commitEnvelope.d.ts +132 -0
  345. package/dist/transactions/commitEnvelope.js +139 -0
  346. package/dist/transactions/commitOutboxStore.d.ts +32 -0
  347. package/dist/transactions/commitOutboxStore.js +26 -0
  348. package/dist/transactions/commitPayload.d.ts +63 -52
  349. package/dist/transactions/commitPayload.js +54 -57
  350. package/dist/transactions/deltaConfirmation.d.ts +20 -22
  351. package/dist/transactions/deltaConfirmation.js +37 -45
  352. package/dist/transactions/httpCommitEnvelope.d.ts +43 -0
  353. package/dist/transactions/httpCommitEnvelope.js +179 -0
  354. package/dist/transactions/optimisticApply.d.ts +49 -0
  355. package/dist/transactions/optimisticApply.js +65 -0
  356. package/dist/transactions/replayValidation.d.ts +182 -0
  357. package/dist/transactions/replayValidation.js +156 -0
  358. package/dist/types/global.d.ts +46 -41
  359. package/dist/types/global.js +20 -19
  360. package/dist/types/index.d.ts +71 -77
  361. package/dist/types/index.js +22 -22
  362. package/dist/types/modelData.d.ts +6 -8
  363. package/dist/types/modelData.js +5 -7
  364. package/dist/types/participant.d.ts +10 -11
  365. package/dist/types/participant.js +6 -8
  366. package/dist/types/streams.d.ts +208 -195
  367. package/dist/types/streams.js +7 -7
  368. package/dist/utils/asyncIterator.d.ts +25 -32
  369. package/dist/utils/asyncIterator.js +25 -32
  370. package/dist/utils/duration.d.ts +12 -15
  371. package/dist/utils/duration.js +12 -15
  372. package/dist/utils/mobxSetup.d.ts +53 -0
  373. package/dist/utils/{mobx-setup.js → mobxSetup.js} +42 -98
  374. package/dist/webhooks/events.d.ts +21 -16
  375. package/dist/webhooks/events.js +10 -8
  376. package/dist/webhooks/index.d.ts +5 -7
  377. package/dist/webhooks/index.js +5 -7
  378. package/dist/wire/bootstrapReason.d.ts +9 -0
  379. package/dist/wire/bootstrapReason.js +8 -0
  380. package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
  381. package/dist/wire/delta.js +114 -0
  382. package/dist/wire/errorEnvelope.d.ts +30 -31
  383. package/dist/wire/errorEnvelope.js +34 -40
  384. package/dist/wire/frames.d.ts +315 -86
  385. package/dist/wire/frames.js +47 -33
  386. package/dist/wire/index.d.ts +18 -14
  387. package/dist/wire/index.js +32 -27
  388. package/dist/wire/listEnvelope.d.ts +16 -23
  389. package/dist/wire/listEnvelope.js +7 -6
  390. package/dist/wire/protocol.d.ts +25 -32
  391. package/dist/wire/protocol.js +25 -32
  392. package/dist/wire/protocolVersion.d.ts +44 -40
  393. package/dist/wire/protocolVersion.js +44 -40
  394. package/docs/api.md +10 -10
  395. package/docs/coordination.md +59 -0
  396. package/docs/mcp.md +1 -1
  397. package/package.json +17 -11
  398. package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
  399. package/dist/ai-sdk/coordination-context.d.ts +0 -52
  400. package/dist/core/query-utils.d.ts +0 -34
  401. package/dist/core/query-utils.js +0 -59
  402. package/dist/schema/sync-delta-row.js +0 -103
  403. package/dist/schema/sync-delta-wire.js +0 -102
  404. package/dist/server/read-config.d.ts +0 -67
  405. package/dist/server/read-config.js +0 -8
  406. package/dist/server/storage-mode.d.ts +0 -8
  407. package/dist/server/storage-mode.js +0 -28
  408. package/dist/source/connector-protocol.d.ts +0 -159
  409. package/dist/source/connector-protocol.js +0 -161
  410. package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
  411. package/dist/transactions/OptimisticEchoTracker.js +0 -104
  412. package/dist/transactions/mutation-error-handler.d.ts +0 -5
  413. package/dist/transactions/mutation-error-handler.js +0 -39
  414. package/dist/transactions/optimistic.d.ts +0 -24
  415. package/dist/transactions/optimistic.js +0 -45
  416. package/dist/transactions/persistedReplay.d.ts +0 -93
  417. package/dist/transactions/persistedReplay.js +0 -105
  418. package/dist/utils/mobx-setup.d.ts +0 -42
@@ -1,18 +1,14 @@
1
1
  /**
2
- * Per-model client factory.
2
+ * Builds the typed client for a single schema model — the object reached as
3
+ * `ablo.<model>`.
3
4
  *
4
- * Mirrors Anthropic SDK's per-endpoint module pattern: each model client
5
- * has its own file, and the root client just instantiates
6
- * one per model. Extracted from `Ablo.ts` so the proxy logic is
7
- * testable in isolation and the constructor doesn't carry it.
8
- *
9
- * Each schema model gets one `ModelOperations<T, CreateInput>`
10
- * exposes the async server reads `retrieve` / `list`, the synchronous
11
- * local-graph snapshots `get` / `getAll` / `getCount`, the writes
12
- * `create` / `update` / `delete`, the coordination namespace `claim`
13
- * (`claim({ id })` plus `claim.state` / `claim.queue` / `claim.release` /
14
- * `claim.reorder`), and `onChange`. The factory returns a plain object; the
15
- * client assembles the `ablo.<model>` lookup table from these.
5
+ * Each schema model gets one {@link ModelOperations}: the async server reads
6
+ * `retrieve` and `list`, the synchronous local-graph snapshots `get`, `getAll`,
7
+ * and `getCount`, the writes `create`, `update`, and `delete`, the coordination
8
+ * namespace `claim` (callable as `claim({ id })`, plus `claim.state`,
9
+ * `claim.queue`, `claim.release`, and `claim.reorder`), `watch`, and `onChange`.
10
+ * The factory returns a plain object; the client assembles the `ablo.<model>`
11
+ * lookup table from one of these per model.
16
12
  */
17
13
  import { autorun } from 'mobx';
18
14
  import { AbloClaimedError, AbloStaleContextError, AbloValidationError, formatClaimedErrorMessage, toAbloError, } from '../errors.js';
@@ -21,6 +17,7 @@ import { reconcileFunctionalUpdate, } from './functionalUpdate.js';
21
17
  import { Model, modelAsRow } from '../Model.js';
22
18
  import { toMs } from '../utils/duration.js';
23
19
  import { LEASE_TTL_MS } from '../wire/protocol.js';
20
+ import { heartbeatCadenceMs, resolveHeartbeatOptions, startClaimHeartbeatLoop, } from './claimHeartbeatLoop.js';
24
21
  import { assertWriteOptions } from './writeOptionsSchema.js';
25
22
  import { ModelScope } from '../types/index.js';
26
23
  const modelClientMeta = new WeakMap();
@@ -35,15 +32,15 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
35
32
  throw new AbloValidationError(`Ablo: schema model "${schemaKey}" resolved to "${registeredModelName}", ` +
36
33
  'but no matching constructor was registered.', { code: 'model_not_registered' });
37
34
  }
38
- // The coordination plane (claims/claims) must speak the SAME wire dialect
39
- // as the commit plane: the lowercased TYPENAME (`task`), not the schema key
40
- // (`tasks`). The server's commit-time claim guard probes the lease store
41
- // with the commit op's model name; a lease recorded under the schema key
42
- // never collides with it — which silently disarmed the guard for every
43
- // model whose schema key differs from its typename (i.e. nearly all of
44
- // them, plural key vs singular typename). Public surfaces (Claim.
45
- // target.model) keep the schema key; only the wire/coordination targets
46
- // use this.
35
+ // The coordination plane must speak the same wire dialect as the commit
36
+ // plane: the lowercased typename (`task`), not the schema key (`tasks`). The
37
+ // server's commit-time claim guard probes the lease store with the commit
38
+ // operation's model name, so a lease recorded under the schema key never
39
+ // matches — which would silently disarm the guard for every model whose
40
+ // schema key differs from its typename (a plural key against a singular
41
+ // typename, i.e. nearly all of them). Public surfaces such as
42
+ // `Claim.target.model` keep the schema key; only the wire and coordination
43
+ // targets use this.
47
44
  const wireModel = registeredModelName.toLowerCase();
48
45
  // Last-line guarantee for the public surface: any rejection from a lower
49
46
  // layer (transport timeout, IndexedDB failure, a third-party throw) is
@@ -76,20 +73,21 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
76
73
  await syncClient.waitForConfirmation(model.getModelName(), model.id);
77
74
  };
78
75
  // Claims this proxy currently holds, keyed by entity id. Lets the flat
79
- // `release({ id })` and `update({ id, data })` find the lease + snapshot a `claim({ id })`
80
- // took no per-call handle. Released on dispose, explicit release, or TTL.
76
+ // `release({ id })` and `update({ id, data })` find the lease and snapshot a
77
+ // `claim({ id })` took, without a per-call handle. Released on dispose,
78
+ // explicit release, or TTL expiry.
81
79
  //
82
- // `target` / `reason` / `expiresAt` are kept alongside the lease so
80
+ // `target`, `reason`, and `expiresAt` are kept alongside the lease so
83
81
  // `claim.state` can synthesize a self-claim: the server excludes a holder's
84
- // own presence frames, so the local proxy is the ONLY place that knows "I
85
- // hold this." `expiresAt` is the client's best estimate from the requested
86
- // TTL (a genuine epoch-ms expiry, not a fabricated watermark), defaulting to
87
- // the server's keepalive lease window when no TTL was requested.
82
+ // own presence frames, so this proxy is the only place that knows the client
83
+ // holds the row. `expiresAt` is the client's best estimate from the requested
84
+ // TTL (a real epoch-millisecond expiry, not a fabricated watermark), defaulting
85
+ // to the server's keepalive lease window when no TTL was requested.
88
86
  const activeClaims = new Map();
89
- // Server keepalive lease window (Hub `LEASE_RENEW_TTL_MS` the same
90
- // `LEASE_TTL_MS` from wire/protocol.ts, so client estimate and server
91
- // lease can't drift). The fallback expiry estimate when a claim is
92
- // taken without an explicit TTL.
87
+ // Server keepalive lease window the same `LEASE_TTL_MS` the wire protocol
88
+ // declares, so the client's estimate and the server's lease cannot drift.
89
+ // This is the fallback expiry estimate when a claim is taken without an
90
+ // explicit TTL.
93
91
  const DEFAULT_LEASE_TTL_MS = LEASE_TTL_MS;
94
92
  const isClaimHandle = (value) => typeof value === 'object' &&
95
93
  value !== null &&
@@ -124,9 +122,9 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
124
122
  };
125
123
  const mutationOptions = (params) => {
126
124
  const { id: _id, data: _data, claim: _claim, ...rest } = params;
127
- // THE write-options schema — runtime twin of the compile-time params.
128
- // Catches plain-JS callers (`onStale: 'rejct'`) at the call site with
129
- // a typed error instead of a silent no-op or a server 400.
125
+ // The write-options schema — the runtime twin of the compile-time params.
126
+ // Catches plain-JavaScript callers (for example `onStale: 'rejct'`) at the
127
+ // call site with a typed error instead of a silent no-op or a server 400.
130
128
  assertWriteOptions(rest, `${schemaKey} write`);
131
129
  return rest;
132
130
  };
@@ -142,12 +140,12 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
142
140
  throw new AbloValidationError(`Model "${schemaKey}" was built without the collaboration runtime, so claim() is unavailable here. Claiming needs no per-model config — use the standard Ablo({ schema, apiKey }) client and every model is claimable.`, { code: 'model_claim_not_configured' });
143
141
  }
144
142
  const { id, ...options } = params;
145
- // Is someone ELSE already on this target? Read the local coordination
146
- // snapshot up front — it decides whether we'll need to re-read after the
147
- // claim (a free / already-mine target can't have changed under us).
143
+ // Is someone else already on this target? Read the local coordination
144
+ // snapshot up front — it decides whether a re-read is needed after the
145
+ // claim (a free or already-held target cannot have changed underneath us).
148
146
  const held = collaboration.state({ model: wireModel, id });
149
147
  const contended = !!held && held.heldBy !== collaboration.selfParticipantId;
150
- const failFast = options?.queue === false;
148
+ const failFast = options.queue === false;
151
149
  // Fail-fast (`queue: false`): if another participant already holds it,
152
150
  // reject now instead of queuing. Best-effort at the client (a racing
153
151
  // claim not yet synced into our snapshot slips through here) — the
@@ -155,13 +153,13 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
155
153
  // the loser's first write. For work-distribution dedup that's exactly
156
154
  // right: don't wait (that would double-process), skip.
157
155
  if (failFast && contended) {
158
- const claim = held ? claimContextFromClaim(held) : undefined;
156
+ const claim = claimContextFromClaim(held);
159
157
  throw new AbloClaimedError(formatClaimedErrorMessage({
160
158
  targetLabel: `${registeredModelName}/${id}`,
161
- heldBy: held?.heldBy,
159
+ heldBy: held.heldBy,
162
160
  claim,
163
- fallback: `${registeredModelName}/${id} is held by ${held?.heldBy ?? 'another participant'}.`,
164
- }), { code: 'entity_claimed', claims: claim ? [claim] : undefined });
161
+ fallback: `${registeredModelName}/${id} is held by ${held.heldBy ?? 'another participant'}.`,
162
+ }), { code: 'entity_claimed', claims: [claim] });
165
163
  }
166
164
  // Ensure the row exists locally before claiming.
167
165
  let model = objectPool.get(id);
@@ -172,65 +170,65 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
172
170
  if (!model) {
173
171
  throw new AbloValidationError(`Entity not found: ${registeredModelName}/${id}`, { code: 'entity_not_found' });
174
172
  }
175
- // Write-intent: enter the entity scope BEFORE acquiring the lease so the
176
- // holder's claim presence broadcasts to whoever is in this entity group
177
- // including a peer that subscribed just before us. Pinning before the
178
- // lease (rather than after) closes the subscribe-vs-broadcast race: the
179
- // server fans `broadcastPresenceChange` out at claim time, so we must be
180
- // in the group when `createClaim` lands. Awaited because the broadcast
181
- // ordering depends on it; still soft (the store swallows reconcile errors).
173
+ // Write intent: enter the entity scope before acquiring the lease so the
174
+ // holder's claim presence broadcasts to everyone in this entity group,
175
+ // including a peer that subscribed just before us. Pinning before the lease
176
+ // rather than after closes the subscribe-versus-broadcast race: the server
177
+ // fans presence out at claim time, so this client must be in the group when
178
+ // the claim lands. Awaited because the broadcast ordering depends on it;
179
+ // still best-effort (the store swallows reconcile errors).
182
180
  await collaboration.pinScope?.({ [schemaKey]: id });
183
- // Acquire the lease. Default (`queue` !== false) goes through the server's
184
- // fair FIFO queue `queue: true` resolves only once the lease is genuinely
185
- // ours, blocking behind any current holder, with no TOCTOU gap (the server
186
- // orders contenders). Fail-fast skips the queue: we already rejected an
187
- // observed conflict above, so this just records our lease.
181
+ // Acquire the lease. By default (`queue` is not false) this goes through the
182
+ // server's fair FIFO queue: `queue: true` resolves only once the lease is
183
+ // genuinely ours, blocking behind any current holder, with no check-then-act
184
+ // gap because the server orders contenders. Fail-fast skips the queue: an
185
+ // observed conflict was already rejected above, so this just records the lease.
188
186
  const lease = await collaboration.createClaim({
189
187
  target: {
190
188
  model: wireModel,
191
189
  id,
192
- ...(options?.field ? { field: options.field } : {}),
193
- ...(options?.path ? { path: options.path } : {}),
194
- ...(options?.range ? { range: options.range } : {}),
190
+ ...(options.field ? { field: options.field } : {}),
191
+ ...(options.path ? { path: options.path } : {}),
192
+ ...(options.range ? { range: options.range } : {}),
195
193
  ...(claimMeta(options) ? { meta: claimMeta(options) } : {}),
196
194
  },
197
- reason: options?.reason ?? 'editing',
198
- ttl: options?.ttl,
195
+ reason: options.reason ?? 'editing',
196
+ ttl: options.ttl,
199
197
  queue: !failFast,
200
- maxQueueDepth: options?.maxQueueDepth,
198
+ maxQueueDepth: options.maxQueueDepth,
201
199
  });
202
- // Only when we actually waited behind another holder can the row have
203
- // changed underneath us — re-read so the claimed snapshot reflects what
204
- // they committed before releasing. Two signals, either suffices:
205
- // - `lease.waited` — the server granted via `claim_granted`, i.e. we
206
- // provably queued behind a holder. Authoritative; works even when
207
- // the local snapshot is blind (claim fan-out is entity-scoped, so
208
- // org-wide-subscribed clients never observe peers' claims).
209
- // - `contended` — the local snapshot saw a holder up front. Kept for
210
- // the no-queue paths where no grant frame exists.
200
+ // Only when the claim actually waited behind another holder can the row have
201
+ // changed underneath us — re-read so the claimed snapshot reflects what that
202
+ // holder committed before releasing. Either of two signals suffices:
203
+ // - `lease.waited` — the server granted the claim after the client
204
+ // provably queued behind a holder. Authoritative; it works even when the
205
+ // local snapshot is blind, since claim fan-out is entity-scoped and a
206
+ // broadly-subscribed client never observes peers' claims.
207
+ // - `contended` — the local snapshot saw a holder up front. Kept for the
208
+ // no-queue paths, where no grant frame exists.
211
209
  if ((contended || lease.waited === true) && !failFast) {
212
- // `type: 'complete'` forces the round-trip: the hydration ledger
213
- // otherwise serves the LOCAL row for an already-hydrated id, and the
214
- // holder's final write may not have fanned out to us yet — the exact
215
- // stale-snapshot race this re-read exists to close.
210
+ // `type: 'complete'` forces the round-trip: the hydration ledger would
211
+ // otherwise serve the local row for an already-hydrated id, and the
212
+ // holder's final write may not have fanned out yet — the exact
213
+ // stale-snapshot race this re-read closes.
216
214
  await load({ where: [['id', id]], type: 'complete' });
217
215
  model = objectPool.get(id) ?? model;
218
216
  }
219
217
  const snapshot = collaboration.createSnapshot(schemaKey, id);
220
- const reason = options?.reason ?? 'editing';
218
+ const reason = options.reason ?? 'editing';
221
219
  // The self-claim's `ClaimTarget` mirrors what a peer's `claim.state` would
222
- // report (`state` maps `held.target.model` `type`), so a holder and a
223
- // peer see the SAME target.type for one row — the wire model token.
220
+ // report (`state` maps `held.target.model` to `type`), so a holder and a
221
+ // peer see the same `target.type` for one row — the wire model token.
224
222
  const selfTarget = {
225
223
  type: wireModel,
226
224
  id,
227
- ...(options?.field ? { field: options.field } : {}),
228
- ...(options?.path ? { path: options.path } : {}),
229
- ...(options?.range ? { range: options.range } : {}),
225
+ ...(options.field ? { field: options.field } : {}),
226
+ ...(options.path ? { path: options.path } : {}),
227
+ ...(options.range ? { range: options.range } : {}),
230
228
  ...(claimMeta(options) ? { meta: claimMeta(options) } : {}),
231
229
  };
232
- const expiresAt = Date.now() +
233
- (options?.ttl !== undefined ? toMs(options.ttl) : DEFAULT_LEASE_TTL_MS);
230
+ const ttlMs = options.ttl !== undefined ? toMs(options.ttl) : DEFAULT_LEASE_TTL_MS;
231
+ const expiresAt = Date.now() + ttlMs;
234
232
  activeClaims.set(id, {
235
233
  lease,
236
234
  snapshot,
@@ -241,24 +239,57 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
241
239
  const target = {
242
240
  type: schemaKey,
243
241
  id,
244
- ...(options?.field ? { field: options.field } : {}),
245
- ...(options?.path ? { path: options.path } : {}),
246
- ...(options?.range ? { range: options.range } : {}),
242
+ ...(options.field ? { field: options.field } : {}),
243
+ ...(options.path ? { path: options.path } : {}),
244
+ ...(options.range ? { range: options.range } : {}),
247
245
  ...(claimMeta(options) ? { meta: claimMeta(options) } : {}),
248
246
  };
249
- const release = () => releaseClaim(id);
247
+ // A beat resolves with the server's extended expiry; keep the local
248
+ // self-claim estimate in step so `claim.state` renders the real window,
249
+ // and surface every answer through `onHeartbeat` (pressure signal).
250
+ const heartbeat = async (beatOptions) => {
251
+ if (!lease.heartbeat) {
252
+ throw new AbloValidationError('This claim handle has no heartbeat wiring, which the standard Ablo({ schema, apiKey }) client provides on every claim. This appears only when a claim is minted through an internal path that predates heartbeats.', { code: 'claim_not_wired' });
253
+ }
254
+ const resolved = resolveHeartbeatOptions(beatOptions);
255
+ const beat = await lease.heartbeat({
256
+ ttl: resolved.ttl ?? options.ttl,
257
+ ...(resolved.details !== undefined ? { details: resolved.details } : {}),
258
+ });
259
+ const held = activeClaims.get(id);
260
+ if (held)
261
+ held.expiresAt = beat.expiresAt;
262
+ options.onHeartbeat?.(beat);
263
+ return beat;
264
+ };
265
+ // Opt-in auto-heartbeat: the loop beats until release, and a definitive
266
+ // loss stops it and surfaces through `onHeartbeatLost`.
267
+ const stopHeartbeatLoop = options.heartbeat
268
+ ? startClaimHeartbeatLoop({
269
+ beat: () => heartbeat(),
270
+ intervalMs: heartbeatCadenceMs(ttlMs, options.heartbeat),
271
+ ...(options.onHeartbeatLost
272
+ ? { onLost: options.onHeartbeatLost }
273
+ : {}),
274
+ })
275
+ : undefined;
276
+ const release = () => {
277
+ stopHeartbeatLoop?.();
278
+ return releaseClaim(id);
279
+ };
250
280
  return {
251
281
  object: 'claim',
252
282
  id: lease.id,
253
283
  readAt: snapshot.stamp,
254
284
  target,
255
285
  reason,
256
- ...(options?.description ? { description: options.description } : {}),
286
+ ...(options.description ? { description: options.description } : {}),
257
287
  data: modelAsRow(model),
258
288
  release,
259
289
  revoke: () => {
260
290
  void release();
261
291
  },
292
+ heartbeat,
262
293
  [Symbol.asyncDispose]: release,
263
294
  };
264
295
  };
@@ -269,15 +300,15 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
269
300
  // are the same object.
270
301
  const claimApi = Object.assign(guard(claim), {
271
302
  state(params) {
272
- // Read-interest: a passive observer subscribing to a row's claim state
273
- // must enter that row's entity scope, or it sits on `org:`/`user:`
274
- // groups only and never receives the holder's entity-scoped claim
275
- // presence. Soft + fire-and-forget — never blocks or rejects the read.
303
+ // Read interest: a passive observer of a row's claim state must enter that
304
+ // row's entity scope, or it sits only on broader `org:`/`user:` groups and
305
+ // never receives the holder's entity-scoped claim presence. Best-effort
306
+ // and fire-and-forget — it never blocks or rejects the read.
276
307
  void collaboration?.enterScope?.({ [schemaKey]: params.id });
277
- // Self-awareness: the server excludes a holder's OWN presence frames and
278
- // the client skips them, so `state` returns null for a row WE hold.
279
- // Synthesize the active claim for self from the stored lease so the
280
- // holder sees its own claim (the JSDoc contract on `claim.state`).
308
+ // Self-awareness: the server excludes a holder's own presence frames and
309
+ // the client skips them, so `state` would return null for a row this client
310
+ // holds. Synthesize the active claim from the stored lease so the holder
311
+ // sees its own claim, honoring the documented contract on `claim.state`.
281
312
  const own = activeClaims.get(params.id);
282
313
  if (own) {
283
314
  return {
@@ -306,10 +337,10 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
306
337
  });
307
338
  const operations = {
308
339
  retrieve: guard(async (params) => {
309
- // Read-interest enrolment: READ a row enter its entity scope, so a
310
- // Node/agent client lands in the same group the holder's claim presence
311
- // fans out on and `claim.state`/`claim.queue` report peers. Soft +
312
- // fire-and-forget — never make the read reject or slower.
340
+ // Read-interest enrolment: reading a row enters its entity scope, so a
341
+ // client lands in the same group the holder's claim presence fans out
342
+ // on and `claim.state`/`claim.queue` report peers. Best-effort and
343
+ // fire-and-forget — it never makes the read reject or run slower.
313
344
  void collaboration?.enterScope?.({ [schemaKey]: params.id });
314
345
  const rows = await load({
315
346
  ...params,
@@ -318,9 +349,8 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
318
349
  });
319
350
  return rows[0];
320
351
  }),
321
- // NB: no auto scope enrolment on bulk `list`/`getAll` that would
322
- // subscribe to an unbounded set of rows' entity groups. Bulk-list scope
323
- // enrolment is a deliberate follow-up (a bounded, opt-in policy).
352
+ // No automatic scope enrolment on bulk `list`/`getAll`: that would subscribe
353
+ // to an unbounded set of rows' entity groups.
324
354
  list: guard(load),
325
355
  get(id) {
326
356
  return objectPool.get(id);
@@ -371,11 +401,11 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
371
401
  if (!collaboration) {
372
402
  throw new AbloValidationError(`Model "${schemaKey}" was built without the collaboration runtime, so claim() is unavailable here. Claiming needs no per-model config — use the standard Ablo({ schema, apiKey }) client and every model is claimable.`, { code: 'model_claim_not_configured' });
373
403
  }
374
- // Write-intent: enter the new row's entity scope BEFORE acquiring the
375
- // create-claim so the holder's claim presence broadcasts to whoever is
376
- // already in this entity group (closing the subscribe-vs-broadcast
404
+ // Write intent: enter the new row's entity scope before acquiring the
405
+ // create-claim so the holder's claim presence broadcasts to everyone
406
+ // already in this entity group (closing the subscribe-versus-broadcast
377
407
  // race — see `takeClaim`). Released with the lease in the `finally`
378
- // below. Awaited for broadcast ordering; still soft.
408
+ // below. Awaited for broadcast ordering; still best-effort.
379
409
  await collaboration.pinScope?.({ [schemaKey]: id });
380
410
  autoLease = await collaboration.createClaim({
381
411
  target: {
@@ -392,10 +422,10 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
392
422
  maxQueueDepth: claim.maxQueueDepth,
393
423
  });
394
424
  }
395
- // Default `organizationId` from the client's identity exactly like the
396
- // mutator path (`buildModelForCreate`) — without this, a caller that
397
- // omits it creates an org-unscoped row on one write door but not the
398
- // other. An explicit value in `data` still wins via the spread.
425
+ // Default `organizationId` from the client's identity, matching the other
426
+ // write path — without this, a caller that omits it would create an
427
+ // org-unscoped row on one write path but not the other. An explicit value
428
+ // in `data` still wins via the spread.
399
429
  const orgDefault = params.data.organizationId ??
400
430
  syncClient.getOrganizationId();
401
431
  const model = new ModelClass({
@@ -481,7 +511,7 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
481
511
  return await operations.update({ ...params, claim: handle });
482
512
  }
483
513
  finally {
484
- await handle.release?.();
514
+ await handle.release();
485
515
  }
486
516
  }
487
517
  const { id } = params;
@@ -515,10 +545,10 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
515
545
  ...opts,
516
546
  ...(handle ? { claim: { id: handle.id } } : {}),
517
547
  };
518
- // Local user update: `applyChanges` keeps change tracking ON so
519
- // the edited fields land in `modifiedProperties` and actually get
520
- // sent to the server. (`updateFromData` is the hydration path and
521
- // would discard the tracking empty `input: {}` no-op mutation.)
548
+ // Local user update: `applyChanges` keeps change tracking on so the
549
+ // edited fields land in `modifiedProperties` and are actually sent to
550
+ // the server. (`updateFromData` is the hydration path and would discard
551
+ // the tracking, producing an empty `input: {}` no-op mutation.)
522
552
  model.applyChanges(params.data);
523
553
  syncClient.update(model, effective);
524
554
  await waitForMutation(model, effective);
@@ -537,17 +567,17 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
537
567
  await operations.delete({ ...params, claim: handle });
538
568
  }
539
569
  finally {
540
- await handle.release?.();
570
+ await handle.release();
541
571
  }
542
572
  return;
543
573
  }
544
574
  const { id } = params;
545
575
  const model = objectPool.get(id);
546
- // Idempotent delete (AIP-135 for client-assigned ids): "ensure absent". A
547
- // row that isn't in our replicated view is already gone from our
548
- // perspective, so a delete is a no-op success not an `entity_not_found`
549
- // error. This matches the HTTP client (which never threw here) and makes
550
- // delete safe to retry / race (two actors deleting the same row).
576
+ // Idempotent delete: "ensure absent". A row that isn't in this client's
577
+ // replicated view is already gone from its perspective, so a delete is a
578
+ // no-op success rather than an `entity_not_found` error. This matches the
579
+ // HTTP client and makes delete safe to retry or race (two actors deleting
580
+ // the same row).
551
581
  if (!model)
552
582
  return;
553
583
  const claimed = activeClaims.get(id);
@@ -1,45 +1,42 @@
1
1
  /**
2
- * credentialEndpoint the endpoint-string shape of `apiKey`.
2
+ * Support for the endpoint-string form of `apiKey`.
3
3
  *
4
- * `Ablo({ schema, apiKey: '/api/ablo-session' })` point the client at your
5
- * session-mint route and the SDK owns the exchange: it POSTs the endpoint,
6
- * parses the minted token, keeps it fresh (the credential lifecycle), and
7
- * classifies failures onto the resolver tri-state. This is the Ably `authUrl`
8
- * / Liveblocks `authEndpoint` model the string form is the 95% case; the
9
- * function form of `apiKey` remains the escape hatch for custom headers,
4
+ * With `Ablo({ schema, apiKey: '/api/ablo-session' })`, you point the client at
5
+ * your own session-mint route and the client owns the exchange: it POSTs to the
6
+ * endpoint, parses the minted token, keeps it fresh, and classifies failures
7
+ * onto the resolver's three outcomes. The string form covers the common case;
8
+ * the function form of `apiKey` remains the escape hatch for custom headers,
10
9
  * bodies, or non-HTTP mints.
11
10
  *
12
- * Detection is by prefix: a string starting with `/`, `http://`, or
13
- * `https://` is an endpoint; anything else is a literal key. Real Ablo keys
14
- * are `sk_`/`pk_`/`ek_`/`rk_`-prefixed, so the two shapes cannot collide.
15
- * (`ABLO_API_KEY` env values are NEVER endpoint-detectedthe env var is
16
- * always a literal key; see `resolveApiKey`.)
11
+ * The form is detected by prefix: a string starting with `/`, `http://`, or
12
+ * `https://` is an endpoint, and anything else is a literal key. Ablo keys are
13
+ * prefixed (`sk_`/`pk_`/`ek_`/`rk_`), so the two shapes cannot collide. An
14
+ * `ABLO_API_KEY` environment value is never treated as an endpoint — it is
15
+ * always a literal key (see `resolveApiKey`).
17
16
  *
18
- * Wire contract — matches the `ablo init` scaffold route exactly:
17
+ * Wire contract:
19
18
  * POST <endpoint> (same-origin, `credentials: 'include'` so cookies flow)
20
- * → 200 `{ token, expiresAt? }` fresh short-lived `ek_`/`rk_`
21
- * → 200 `{ token: null }` or 401/403 the login itself is gone (sign out)
22
- * → anything else transient — retry, NEVER sign out
19
+ * → 200 `{ token, expiresAt? }` a fresh short-lived `ek_`/`rk_`
20
+ * → 200 `{ token: null }` or 401/403 the login itself is gone (sign out)
21
+ * → anything else transient — retry, do not sign out
23
22
  *
24
- * The tri-state mapping is the whole point of building this in: hand-written
25
- * thunks routinely get it wrong (mapping any `!res.ok` to `null` signs the
26
- * user out on a 500). Encoded here once, every consumer inherits the correct
27
- * terminal-vs-transient split (the Liveblocks `{ error: "forbidden" }` vs
28
- * retry contract, translated to HTTP statuses).
23
+ * The three-way mapping is the reason to build this in. Hand-written token
24
+ * fetchers routinely get it wrong mapping any non-OK response to `null` signs
25
+ * the user out on a 500. Encoded here once, every consumer inherits the correct
26
+ * split between a terminal sign-out and a transient retry.
29
27
  */
30
28
  /**
31
- * Async callable that resolves the current credential. Mirrors the shape
32
- * Anthropic / OpenAI / Stripe ship used for credential rotation
33
- * (e.g. AWS STS, GCP IAM, Vault) AND the short-lived per-user browser
34
- * path (mint a fresh `ek_`/`rk_` from the signed-in session). Re-exported
35
- * from `./auth` (and thence `./Ablo`) so existing import paths work; defined
36
- * in this leaf so the credential resolver it types has no import cycle.
29
+ * An async callable that resolves the current credential. It serves two uses:
30
+ * credential rotation (for example against AWS STS, GCP IAM, or Vault) and the
31
+ * short-lived per-user browser path (minting a fresh `ek_`/`rk_` from the
32
+ * signed-in session). It is re-exported from `./auth` so existing import paths
33
+ * keep working, and defined here so the resolver it types has no import cycle.
37
34
  *
38
- * Contract: resolve a token; resolve `null` when the login itself is gone
39
- * (terminal the credential lifecycle treats this as `session_expired` and
40
- * signs out); or THROW on a transient failure (back off and retry, never
41
- * sign out). A long-lived static `apiKey` string needs none of this — it is
42
- * used as-is. This is the single credential resolver the SDK supports.
35
+ * The contract has three outcomes: resolve a token; resolve `null` when the
36
+ * login itself is gone (terminal the credential lifecycle treats this as
37
+ * `session_expired` and signs out); or throw on a transient failure (back off
38
+ * and retry, without signing out). A long-lived static `apiKey` string needs
39
+ * none of this and is used as-is.
43
40
  */
44
41
  export type ApiKeySetter = () => Promise<string | null>;
45
42
  /**
@@ -48,16 +45,17 @@ export type ApiKeySetter = () => Promise<string | null>;
48
45
  */
49
46
  export declare function isCredentialEndpoint(value: string): boolean;
50
47
  /**
51
- * Build the resolver behind an endpoint-string `apiKey`. Conforms to the
52
- * `ApiKeySetter` contract end-to-end:
53
- * - resolves the minted token string on success,
54
- * - resolves `null` when the login is gone (401/403, or an explicit
55
- * `{ token: null }`) terminal, the client signs out,
56
- * - THROWS on anything transient (network failure, 5xx/429, malformed
57
- * response) the lifecycle backs off and retries, never signs out.
48
+ * Builds the resolver behind an endpoint-string `apiKey`. It follows the
49
+ * {@link ApiKeySetter} contract end to end:
50
+ * - resolves the minted token string on success;
51
+ * - resolves `null` when the login is gone (a 401 or 403, or an explicit
52
+ * `{ token: null }`) terminal, so the client signs out;
53
+ * - throws on anything transient (a network failure, a 5xx or 429, or a
54
+ * malformed response) so the lifecycle backs off and retries without
55
+ * signing out.
58
56
  *
59
- * A relative endpoint invoked server-side (Node fetch has no origin) throws
60
- * transient by contract, and `credentialLifecycle` already translates that
61
- * exact failure into an actionable "use an absolute URL server-side" warning.
57
+ * A relative endpoint invoked on a server (where `fetch` has no origin) throws,
58
+ * which is transient by contract; the credential lifecycle translates that exact
59
+ * failure into an actionable "use an absolute URL server-side" warning.
62
60
  */
63
61
  export declare function createEndpointCredentialResolver(endpoint: string): ApiKeySetter;