@abloatai/ablo 0.26.0 → 0.27.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 (398) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +101 -85
  3. package/dist/BaseSyncedStore.d.ts +85 -88
  4. package/dist/BaseSyncedStore.js +131 -147
  5. package/dist/Database.d.ts +54 -68
  6. package/dist/Database.js +97 -113
  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 +37 -52
  12. package/dist/Model.js +46 -61
  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 +112 -112
  18. package/dist/SyncClient.js +165 -172
  19. package/dist/adapters/alwaysOnline.d.ts +6 -8
  20. package/dist/adapters/alwaysOnline.js +6 -8
  21. package/dist/adapters/inMemoryStorage.d.ts +9 -9
  22. package/dist/adapters/inMemoryStorage.js +9 -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 +167 -119
  50. package/dist/client/Ablo.d.ts +73 -73
  51. package/dist/client/Ablo.js +125 -160
  52. package/dist/client/ApiClient.d.ts +30 -19
  53. package/dist/client/ApiClient.js +133 -38
  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 +14 -17
  61. package/dist/client/createInternalComponents.js +25 -30
  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 +57 -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 +67 -87
  76. package/dist/client/options.d.ts +134 -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 +15 -20
  91. package/dist/client/wsMutationExecutor.js +17 -23
  92. package/dist/context.d.ts +6 -4
  93. package/dist/context.js +6 -4
  94. package/dist/coordination/index.d.ts +10 -8
  95. package/dist/coordination/index.js +14 -12
  96. package/dist/coordination/schema.d.ts +176 -128
  97. package/dist/coordination/schema.js +197 -133
  98. package/dist/coordination/trace.d.ts +9 -10
  99. package/dist/coordination/trace.js +13 -14
  100. package/dist/core/DatabaseManager.d.ts +5 -7
  101. package/dist/core/DatabaseManager.js +15 -19
  102. package/dist/core/QueryProcessor.d.ts +7 -9
  103. package/dist/core/QueryProcessor.js +22 -28
  104. package/dist/core/QueryView.d.ts +8 -8
  105. package/dist/core/QueryView.js +2 -2
  106. package/dist/core/StoreManager.d.ts +12 -14
  107. package/dist/core/StoreManager.js +21 -24
  108. package/dist/core/ViewRegistry.d.ts +5 -5
  109. package/dist/core/ViewRegistry.js +4 -4
  110. package/dist/core/index.d.ts +17 -12
  111. package/dist/core/index.js +32 -26
  112. package/dist/core/openIDBWithTimeout.d.ts +38 -36
  113. package/dist/core/openIDBWithTimeout.js +42 -43
  114. package/dist/core/queryUtils.d.ts +45 -0
  115. package/dist/core/queryUtils.js +69 -0
  116. package/dist/core/storeContract.d.ts +63 -61
  117. package/dist/core/storeContract.js +8 -12
  118. package/dist/environment.d.ts +28 -0
  119. package/dist/environment.js +21 -0
  120. package/dist/errorCodes.d.ts +107 -99
  121. package/dist/errorCodes.js +131 -132
  122. package/dist/errors.d.ts +160 -166
  123. package/dist/errors.js +155 -158
  124. package/dist/index.d.ts +30 -27
  125. package/dist/index.js +89 -86
  126. package/dist/interfaces/index.d.ts +102 -113
  127. package/dist/interfaces/index.js +5 -4
  128. package/dist/keys/index.d.ts +27 -29
  129. package/dist/keys/index.js +41 -40
  130. package/dist/mutators/RecordingTransaction.d.ts +16 -16
  131. package/dist/mutators/RecordingTransaction.js +31 -37
  132. package/dist/mutators/Transaction.d.ts +18 -26
  133. package/dist/mutators/Transaction.js +14 -20
  134. package/dist/mutators/UndoManager.d.ts +122 -131
  135. package/dist/mutators/UndoManager.js +145 -156
  136. package/dist/mutators/defineMutators.d.ts +23 -34
  137. package/dist/mutators/defineMutators.js +14 -20
  138. package/dist/mutators/inverseOp.d.ts +12 -15
  139. package/dist/mutators/inverseOp.js +12 -15
  140. package/dist/mutators/mutateActions.d.ts +10 -9
  141. package/dist/mutators/mutateActions.js +1 -1
  142. package/dist/mutators/readerActions.d.ts +9 -8
  143. package/dist/mutators/readerActions.js +2 -2
  144. package/dist/mutators/undoApply.d.ts +31 -27
  145. package/dist/mutators/undoApply.js +26 -24
  146. package/dist/policy/index.d.ts +5 -3
  147. package/dist/policy/index.js +5 -3
  148. package/dist/policy/types.d.ts +104 -100
  149. package/dist/policy/types.js +67 -66
  150. package/dist/query/client.d.ts +28 -23
  151. package/dist/query/client.js +45 -43
  152. package/dist/query/types.d.ts +37 -60
  153. package/dist/query/types.js +13 -33
  154. package/dist/react/AbloProvider.d.ts +1 -1
  155. package/dist/react/AbloProvider.js +2 -2
  156. package/dist/react/context.d.ts +25 -28
  157. package/dist/react/context.js +9 -10
  158. package/dist/react/index.d.ts +41 -42
  159. package/dist/react/index.js +37 -38
  160. package/dist/react/internalContext.d.ts +17 -19
  161. package/dist/react/useAblo.d.ts +23 -22
  162. package/dist/react/useAblo.js +16 -14
  163. package/dist/react/useCurrentUserId.d.ts +8 -7
  164. package/dist/react/useCurrentUserId.js +8 -7
  165. package/dist/react/useErrorListener.d.ts +7 -7
  166. package/dist/react/useErrorListener.js +10 -11
  167. package/dist/react/useMutationFailureListener.d.ts +8 -8
  168. package/dist/react/useMutationFailureListener.js +8 -8
  169. package/dist/react/useMutators.d.ts +11 -11
  170. package/dist/react/useMutators.js +3 -3
  171. package/dist/react/useReactive.js +2 -2
  172. package/dist/react/useSyncStatus.d.ts +4 -6
  173. package/dist/react/useUndoScope.d.ts +7 -9
  174. package/dist/react/useUndoScope.js +1 -1
  175. package/dist/schema/coordination.d.ts +21 -25
  176. package/dist/schema/coordination.js +21 -25
  177. package/dist/schema/ddl.d.ts +43 -39
  178. package/dist/schema/ddl.js +75 -68
  179. package/dist/schema/ddlLock.d.ts +20 -24
  180. package/dist/schema/ddlLock.js +18 -23
  181. package/dist/schema/diff.d.ts +99 -61
  182. package/dist/schema/diff.js +43 -34
  183. package/dist/schema/field.d.ts +37 -42
  184. package/dist/schema/field.js +35 -48
  185. package/dist/schema/generate.d.ts +12 -12
  186. package/dist/schema/generate.js +12 -12
  187. package/dist/schema/index.d.ts +2 -2
  188. package/dist/schema/index.js +21 -23
  189. package/dist/schema/model.d.ts +118 -143
  190. package/dist/schema/model.js +22 -33
  191. package/dist/schema/openapi.d.ts +10 -9
  192. package/dist/schema/openapi.js +5 -3
  193. package/dist/schema/queries.d.ts +29 -31
  194. package/dist/schema/queries.js +23 -25
  195. package/dist/schema/relation.d.ts +89 -99
  196. package/dist/schema/relation.js +13 -13
  197. package/dist/schema/residency.d.ts +16 -13
  198. package/dist/schema/residency.js +16 -13
  199. package/dist/schema/roles.d.ts +36 -43
  200. package/dist/schema/roles.js +31 -37
  201. package/dist/schema/schema.d.ts +33 -42
  202. package/dist/schema/schema.js +31 -32
  203. package/dist/schema/select.d.ts +13 -13
  204. package/dist/schema/select.js +13 -13
  205. package/dist/schema/serialize.d.ts +28 -31
  206. package/dist/schema/serialize.js +27 -31
  207. package/dist/schema/sugar.d.ts +17 -32
  208. package/dist/schema/sugar.js +14 -29
  209. package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +26 -49
  210. package/dist/schema/syncDeltaRow.js +89 -0
  211. package/dist/schema/tenancy.d.ts +44 -46
  212. package/dist/schema/tenancy.js +46 -48
  213. package/dist/server/adapter.d.ts +58 -58
  214. package/dist/server/adapter.js +13 -14
  215. package/dist/server/commit.d.ts +60 -64
  216. package/dist/server/index.d.ts +9 -10
  217. package/dist/server/index.js +1 -1
  218. package/dist/server/readConfig.d.ts +70 -0
  219. package/dist/server/readConfig.js +8 -0
  220. package/dist/server/storageMode.d.ts +23 -0
  221. package/dist/server/storageMode.js +17 -0
  222. package/dist/source/adapter.d.ts +30 -25
  223. package/dist/source/adapter.js +10 -10
  224. package/dist/source/adapters/drizzle.d.ts +28 -23
  225. package/dist/source/adapters/drizzle.js +30 -25
  226. package/dist/source/adapters/kysely.d.ts +27 -25
  227. package/dist/source/adapters/kysely.js +24 -23
  228. package/dist/source/adapters/memory.d.ts +8 -7
  229. package/dist/source/adapters/memory.js +9 -8
  230. package/dist/source/adapters/prisma.d.ts +13 -12
  231. package/dist/source/adapters/prisma.js +22 -25
  232. package/dist/source/conformance.d.ts +18 -11
  233. package/dist/source/conformance.js +17 -11
  234. package/dist/source/connector.d.ts +31 -32
  235. package/dist/source/connector.js +28 -28
  236. package/dist/source/connectorProtocol.d.ts +160 -0
  237. package/dist/source/connectorProtocol.js +162 -0
  238. package/dist/source/contract.d.ts +26 -27
  239. package/dist/source/contract.js +28 -29
  240. package/dist/source/factory.d.ts +46 -58
  241. package/dist/source/factory.js +22 -27
  242. package/dist/source/index.d.ts +7 -9
  243. package/dist/source/index.js +12 -14
  244. package/dist/source/migrations.d.ts +9 -9
  245. package/dist/source/migrations.js +9 -9
  246. package/dist/source/next.d.ts +9 -10
  247. package/dist/source/next.js +6 -7
  248. package/dist/source/pushQueue.d.ts +69 -47
  249. package/dist/source/pushQueue.js +32 -28
  250. package/dist/source/signing.d.ts +46 -17
  251. package/dist/source/signing.js +28 -11
  252. package/dist/source/types.d.ts +121 -104
  253. package/dist/source/types.js +13 -14
  254. package/dist/stores/ObjectStore.d.ts +10 -11
  255. package/dist/stores/ObjectStore.js +11 -12
  256. package/dist/stores/ObjectStoreContract.d.ts +12 -15
  257. package/dist/stores/SyncActionStore.d.ts +7 -11
  258. package/dist/stores/SyncActionStore.js +13 -17
  259. package/dist/surface.d.ts +27 -20
  260. package/dist/surface.js +27 -20
  261. package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +36 -42
  262. package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +76 -76
  263. package/dist/sync/ConnectionManager.d.ts +39 -50
  264. package/dist/sync/ConnectionManager.js +55 -66
  265. package/dist/sync/NetworkProbe.d.ts +24 -29
  266. package/dist/sync/NetworkProbe.js +63 -69
  267. package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +42 -41
  268. package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +59 -54
  269. package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +43 -57
  270. package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +43 -51
  271. package/dist/sync/SyncWebSocket.d.ts +139 -165
  272. package/dist/sync/SyncWebSocket.js +191 -223
  273. package/dist/sync/awaitClaimGrant.d.ts +18 -18
  274. package/dist/sync/awaitClaimGrant.js +11 -11
  275. package/dist/sync/bootstrapApply.d.ts +34 -24
  276. package/dist/sync/bootstrapApply.js +27 -19
  277. package/dist/sync/commitFrames.d.ts +21 -20
  278. package/dist/sync/commitFrames.js +18 -18
  279. package/dist/sync/createClaimStream.d.ts +23 -22
  280. package/dist/sync/createClaimStream.js +105 -23
  281. package/dist/sync/createPresenceStream.d.ts +19 -18
  282. package/dist/sync/createPresenceStream.js +25 -26
  283. package/dist/sync/createSnapshot.d.ts +12 -14
  284. package/dist/sync/createSnapshot.js +20 -26
  285. package/dist/sync/credentialLifecycle.d.ts +104 -104
  286. package/dist/sync/credentialLifecycle.js +140 -147
  287. package/dist/sync/deltaPipeline.d.ts +36 -34
  288. package/dist/sync/deltaPipeline.js +64 -65
  289. package/dist/sync/groupChange.d.ts +63 -61
  290. package/dist/sync/groupChange.js +74 -78
  291. package/dist/sync/heartbeat.d.ts +34 -33
  292. package/dist/sync/heartbeat.js +31 -31
  293. package/dist/sync/participants.d.ts +19 -19
  294. package/dist/sync/schemas.d.ts +3 -2
  295. package/dist/sync/schemas.js +14 -10
  296. package/dist/sync/syncCursor.d.ts +17 -21
  297. package/dist/sync/syncCursor.js +17 -21
  298. package/dist/sync/syncPlan.d.ts +28 -36
  299. package/dist/sync/syncPlan.js +18 -19
  300. package/dist/sync/syncPosition.d.ts +54 -49
  301. package/dist/sync/syncPosition.js +57 -52
  302. package/dist/sync/wsFrameHandlers.d.ts +35 -36
  303. package/dist/sync/wsFrameHandlers.js +63 -67
  304. package/dist/testing/fixtures/bootstrap.d.ts +12 -6
  305. package/dist/testing/fixtures/bootstrap.js +12 -6
  306. package/dist/testing/fixtures/deltas.d.ts +30 -33
  307. package/dist/testing/fixtures/deltas.js +30 -33
  308. package/dist/testing/fixtures/models.d.ts +11 -10
  309. package/dist/testing/fixtures/models.js +11 -10
  310. package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
  311. package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
  312. package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -15
  313. package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +12 -10
  314. package/dist/testing/helpers/wait.d.ts +13 -8
  315. package/dist/testing/helpers/wait.js +13 -8
  316. package/dist/testing/index.d.ts +3 -3
  317. package/dist/testing/index.js +2 -2
  318. package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
  319. package/dist/testing/mocks/MockMutationExecutor.js +15 -14
  320. package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
  321. package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
  322. package/dist/testing/mocks/MockSyncContext.d.ts +20 -17
  323. package/dist/testing/mocks/MockSyncContext.js +15 -13
  324. package/dist/testing/mocks/MockSyncStore.d.ts +10 -10
  325. package/dist/testing/mocks/MockSyncStore.js +11 -11
  326. package/dist/testing/mocks/MockWebSocket.d.ts +26 -22
  327. package/dist/testing/mocks/MockWebSocket.js +22 -21
  328. package/dist/transactions/TransactionQueue.d.ts +181 -176
  329. package/dist/transactions/TransactionQueue.js +338 -350
  330. package/dist/transactions/TransactionStore.d.ts +6 -4
  331. package/dist/transactions/TransactionStore.js +6 -4
  332. package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
  333. package/dist/transactions/UnconfirmedWrites.js +104 -0
  334. package/dist/transactions/coalesceRules.d.ts +41 -17
  335. package/dist/transactions/coalesceRules.js +40 -17
  336. package/dist/transactions/commitPayload.d.ts +48 -52
  337. package/dist/transactions/commitPayload.js +48 -57
  338. package/dist/transactions/deltaConfirmation.d.ts +20 -22
  339. package/dist/transactions/deltaConfirmation.js +37 -45
  340. package/dist/transactions/optimisticApply.d.ts +49 -0
  341. package/dist/transactions/optimisticApply.js +65 -0
  342. package/dist/transactions/{persistedReplay.d.ts → replayValidation.d.ts} +28 -22
  343. package/dist/transactions/{persistedReplay.js → replayValidation.js} +33 -27
  344. package/dist/types/global.d.ts +46 -41
  345. package/dist/types/global.js +20 -19
  346. package/dist/types/index.d.ts +71 -77
  347. package/dist/types/index.js +22 -22
  348. package/dist/types/modelData.d.ts +6 -8
  349. package/dist/types/modelData.js +5 -7
  350. package/dist/types/participant.d.ts +10 -11
  351. package/dist/types/participant.js +6 -8
  352. package/dist/types/streams.d.ts +208 -195
  353. package/dist/types/streams.js +7 -7
  354. package/dist/utils/asyncIterator.d.ts +25 -32
  355. package/dist/utils/asyncIterator.js +25 -32
  356. package/dist/utils/duration.d.ts +12 -15
  357. package/dist/utils/duration.js +12 -15
  358. package/dist/utils/mobxSetup.d.ts +53 -0
  359. package/dist/utils/{mobx-setup.js → mobxSetup.js} +42 -98
  360. package/dist/webhooks/events.d.ts +21 -16
  361. package/dist/webhooks/events.js +10 -8
  362. package/dist/webhooks/index.d.ts +5 -7
  363. package/dist/webhooks/index.js +5 -7
  364. package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
  365. package/dist/wire/delta.js +114 -0
  366. package/dist/wire/errorEnvelope.d.ts +30 -31
  367. package/dist/wire/errorEnvelope.js +34 -40
  368. package/dist/wire/frames.d.ts +79 -86
  369. package/dist/wire/frames.js +26 -33
  370. package/dist/wire/index.d.ts +14 -12
  371. package/dist/wire/index.js +30 -26
  372. package/dist/wire/listEnvelope.d.ts +16 -23
  373. package/dist/wire/listEnvelope.js +7 -6
  374. package/dist/wire/protocol.d.ts +25 -32
  375. package/dist/wire/protocol.js +25 -32
  376. package/dist/wire/protocolVersion.d.ts +44 -40
  377. package/dist/wire/protocolVersion.js +44 -40
  378. package/docs/coordination.md +59 -0
  379. package/package.json +11 -10
  380. package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
  381. package/dist/ai-sdk/coordination-context.d.ts +0 -52
  382. package/dist/core/query-utils.d.ts +0 -34
  383. package/dist/core/query-utils.js +0 -59
  384. package/dist/schema/sync-delta-row.js +0 -103
  385. package/dist/schema/sync-delta-wire.js +0 -102
  386. package/dist/server/read-config.d.ts +0 -67
  387. package/dist/server/read-config.js +0 -8
  388. package/dist/server/storage-mode.d.ts +0 -8
  389. package/dist/server/storage-mode.js +0 -28
  390. package/dist/source/connector-protocol.d.ts +0 -159
  391. package/dist/source/connector-protocol.js +0 -161
  392. package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
  393. package/dist/transactions/OptimisticEchoTracker.js +0 -104
  394. package/dist/transactions/mutation-error-handler.d.ts +0 -5
  395. package/dist/transactions/mutation-error-handler.js +0 -39
  396. package/dist/transactions/optimistic.d.ts +0 -24
  397. package/dist/transactions/optimistic.js +0 -45
  398. package/dist/utils/mobx-setup.d.ts +0 -42
@@ -1,15 +1,15 @@
1
1
  /**
2
- * Auth + URL resolution for `Ablo()`.
2
+ * Authentication and URL resolution for the `Ablo()` client.
3
3
  *
4
- * Mirrors the small, focused helpers Anthropic ships in `client.ts`
5
- * (`apiKeyAuth`, `bearerAuth`, `validateHeaders`). Each function does
6
- * one thing resolve a value with the right precedence, or fail
7
- * with an actionable message — so the constructor reads as a
8
- * sequence of named decisions rather than a stream of `??`-chains.
4
+ * Each function here makes one decision: it resolves a configuration value with
5
+ * the right precedence, or fails with an actionable message. Together they let
6
+ * the client constructor read as a sequence of named steps rather than a chain
7
+ * of fallbacks.
9
8
  *
10
- * Customer-facing env surface is intentionally small: `ABLO_API_KEY`
11
- * is the only environment fallback. Other routing/auth overrides are
12
- * explicit options so generated apps do not accrete hidden env knobs.
9
+ * The environment surface is deliberately small: `ABLO_API_KEY` is the only
10
+ * value read from the environment. Every other routing or authentication
11
+ * override is an explicit option, so an app never picks up hidden behavior from
12
+ * a stray environment variable.
13
13
  */
14
14
  import { AbloAuthenticationError, AbloValidationError } from '../errors.js';
15
15
  import { classifyCredentialKind } from '../auth/credentialPolicy.js';
@@ -25,13 +25,12 @@ export function readProcessEnv() {
25
25
  return maybeGlobal.process?.env ?? {};
26
26
  }
27
27
  export function resolveApiKey(input) {
28
- // `authEndpoint` the NAMED session-mint field (Liveblocks `authEndpoint` /
29
- // Ably `authUrl`): a route string the SDK exchanges for a short-lived token,
30
- // or an async resolver for custom exchanges. Resolved HERE — the one
31
- // resolution point all three factory branches (WS, `transport: 'http'`,
32
- // protocol client) share into an `ApiKeySetter`, so every downstream
33
- // consumer sees the familiar resolver and the credential lifecycle drives
34
- // renewal off it.
28
+ // `authEndpoint` is the option that names a session-mint route: a URL the
29
+ // client exchanges for a short-lived token, or an async resolver for custom
30
+ // exchanges. It is resolved into an `ApiKeySetter` here — the single point
31
+ // shared by every client variant (WebSocket, HTTP, and protocol clients) — so
32
+ // every downstream consumer sees the same resolver and the credential
33
+ // lifecycle drives renewal off it.
35
34
  const endpoint = input.options.authEndpoint;
36
35
  const configured = input.options.apiKey;
37
36
  if (endpoint != null) {
@@ -48,10 +47,10 @@ export function resolveApiKey(input) {
48
47
  }
49
48
  return createEndpointCredentialResolver(endpoint);
50
49
  }
51
- // `apiKey` also accepts the endpoint-string shape directly (same detection
52
- // key strings are `sk_`/`ek_`/`rk_`-prefixed so the shapes can't collide).
53
- // Deliberately only the EXPLICIT option: an `ABLO_API_KEY` env value is
54
- // always a literal key, never endpoint-detected.
50
+ // `apiKey` also accepts the endpoint-string form directly, detected the same
51
+ // way — key strings are prefixed (`sk_`/`ek_`/`rk_`), so the two shapes never
52
+ // collide. Only the explicit option is treated this way: an `ABLO_API_KEY`
53
+ // environment value is always a literal key, never an endpoint.
55
54
  if (typeof configured === 'string' && isCredentialEndpoint(configured)) {
56
55
  return createEndpointCredentialResolver(configured);
57
56
  }
@@ -63,7 +62,7 @@ export function resolveAuthToken(input) {
63
62
  function keyPrefix(key) {
64
63
  return `${key.slice(0, 12)}…`;
65
64
  }
66
- /** Infer sandbox/production from Ablo key prefixes without importing CLI code. */
65
+ /** Infer the sandbox or production mode from an Ablo key's prefix. */
67
66
  export function modeFromApiKey(key) {
68
67
  if (/^(sk|rk)_test_/.test(key))
69
68
  return 'sandbox';
@@ -225,39 +224,38 @@ export function describeCliKeyMismatch(configured, cli) {
225
224
  return null;
226
225
  }
227
226
  /**
228
- * Resolve the direct-URL connector's Postgres connection string.
227
+ * Resolves the Postgres connection string for the direct-connection option, or
228
+ * `null` when none was given.
229
229
  *
230
- * `databaseUrl` is an EXPLICIT, opt-in option: Ablo registers a dedicated
231
- * tenant database only when the caller passes it to `Ablo(...)`. It is NOT
232
- * read from `process.env.DATABASE_URL` per this module's invariant
233
- * (`ABLO_API_KEY` is the only environment fallback), an app's `DATABASE_URL`
234
- * (commonly set for Prisma/Drizzle/docker) must never silently flip the client
235
- * into connection-string mode. The default Data Source path keeps `DATABASE_URL`
236
- * in the app and exposes `dataSource(...)`; that path leaves this null.
237
- * `warnIfDatabaseUrlEnvIgnored` nudges callers who set the env but omitted the option.
230
+ * `databaseUrl` is opt-in: the client registers a dedicated database only when
231
+ * the caller passes it explicitly. It is never read from
232
+ * `process.env.DATABASE_URL`, because this module treats `ABLO_API_KEY` as the
233
+ * one environment fallback an app's `DATABASE_URL`, commonly set for other
234
+ * tools, must not silently switch the client into connection-string mode. The
235
+ * default path leaves `DATABASE_URL` untouched and reads through `dataSource(...)`
236
+ * instead, so this returns `null`. {@link warnIfDatabaseUrlEnvIgnored} nudges a
237
+ * caller who set the environment variable but omitted the option.
238
238
  */
239
239
  export function resolveDatabaseUrl(input) {
240
240
  return input.options.databaseUrl ?? null;
241
241
  }
242
242
  /**
243
- * One-time migration nudge for the dropped `DATABASE_URL` env fallback.
243
+ * Warns once when `DATABASE_URL` is set in the environment but `databaseUrl` was
244
+ * not passed as an option.
244
245
  *
245
- * Earlier versions silently adopted `process.env.DATABASE_URL` when `databaseUrl`
246
- * was not passed, registering a direct connector behind the caller's back — which
247
- * surprised any app that keeps `DATABASE_URL` for another tool (Prisma, Drizzle,
248
- * docker-compose) and, on localhost, tried to register a database Ablo's cloud
249
- * cannot reach. The env value is now ignored; this points the developer at the
250
- * explicit option instead of flipping their mode for them. Warns once per process
251
- * so it never spams, and falls back to `console.warn` when no logger is supplied
252
- * (the `transport: 'api'` client has none).
246
+ * The client does not adopt `process.env.DATABASE_URL` on its own, because that
247
+ * value is commonly set for other tools and switching the client into
248
+ * connection-string mode behind the caller's back is surprising and on
249
+ * localhost it would try to register a database the hosted service cannot reach.
250
+ * This warning points the developer at the explicit option instead. It fires at
251
+ * most once per process and falls back to `console.warn` when no logger is
252
+ * supplied.
253
253
  *
254
- * Suppressed entirely on the hosted/token path: if an `apiKey` resolves (option
255
- * or `ABLO_API_KEY` env), the caller has chosen the hosted capability-token /
256
- * Data Source transport, which is mutually exclusive with direct `databaseUrl`
257
- * mode. A `DATABASE_URL` sitting in that environment is unrelated infra (Prisma,
258
- * Drizzle, the sync-server) — never an omitted option — so nudging would be a
259
- * false positive. This is the first-party hosted app's exact shape, where the
260
- * stray nudge otherwise reaches end-user desktop logs.
254
+ * The warning is skipped entirely when an `apiKey` resolves (from the option or
255
+ * `ABLO_API_KEY`): that caller has chosen the hosted, token-based transport,
256
+ * which is separate from the direct `databaseUrl` connection. A `DATABASE_URL`
257
+ * present in that environment belongs to unrelated infrastructure, not an omitted
258
+ * option, so warning would be a false positive.
261
259
  */
262
260
  let warnedDatabaseUrlEnvIgnored = false;
263
261
  export function warnIfDatabaseUrlEnvIgnored(input, warn) {
@@ -282,19 +280,18 @@ export function warnIfDatabaseUrlEnvIgnored(input, warn) {
282
280
  console.warn('[Ablo]', message);
283
281
  }
284
282
  /**
285
- * One-time deprecation nudge for the `databaseUrl` direct connector.
283
+ * Warns once when the deprecated `databaseUrl` option is used.
286
284
  *
287
- * `databaseUrl` registers the `dedicated` storage mode Ablo opens a pool INTO
288
- * the caller's Postgres and writes into it directly. That is the operate-their-
289
- * database posture we are moving off. Ablo is Stripe-shaped: it hosts only the
290
- * transaction log (the ordered sync_deltas) + coordination, never your data your
291
- * rows always live in your own database. The supported path is the signed Data
292
- * Source endpoint (`dataSource(...)`), where your app owns the write and your
293
- * credentials never leave it. See docs/plans/stripe-shaped-storage-posture.md.
285
+ * Passing `databaseUrl` opens a connection pool directly into your Postgres and
286
+ * writes to it. That option is deprecated. Ablo is designed to host only the
287
+ * ordered transaction log (the `sync_deltas` table) and coordination state,
288
+ * never your rows your data stays in your own database. The supported path is
289
+ * a signed data-source endpoint (`dataSource(...)`), where your app owns the
290
+ * write and your database credentials never leave it.
294
291
  *
295
- * Still honored at runtime so existing integrations keep working; this only warns
296
- * once per process (so it never spams) and falls back to `console.warn` when no
297
- * logger is supplied (the `transport: 'http'`/`'api'` client has none).
292
+ * The option still works at runtime so existing integrations keep running. This
293
+ * warning fires at most once per process and falls back to `console.warn` when
294
+ * no logger is supplied.
298
295
  */
299
296
  let warnedDatabaseUrlDeprecated = false;
300
297
  export function warnIfDatabaseUrlDeprecated(input, warn) {
@@ -335,8 +332,8 @@ export async function warnIfCliKeyMismatch(input, warn) {
335
332
  else if (typeof console !== 'undefined')
336
333
  console.warn('[Ablo]', mismatch.message);
337
334
  }
338
- // Declared in the dependency-free `hostedEndpoints.ts` leaf (single source of
339
- // the hosted domain); re-exported here so existing import paths keep working.
335
+ // Declared in `./hostedEndpoints`, the single source of the hosted domain, and
336
+ // re-exported here so existing import paths keep working.
340
337
  export { ABLO_HOSTED_API_DOMAIN, ABLO_HOSTED_HTTP_BASE_URL, ABLO_DEFAULT_BASE_URL } from './hostedEndpoints.js';
341
338
  const LEGACY_HOSTED_API_HOSTS = new Set([
342
339
  'mesh.ablo.finance',
@@ -345,29 +342,29 @@ const LEGACY_HOSTED_API_HOSTS = new Set([
345
342
  'sync-staging.ablo.finance',
346
343
  ]);
347
344
  /**
348
- * Normalize old hosted aliases to the public API domain. Self-hosted/custom
349
- * URLs pass through unchanged; only first-party legacy hosts are rewritten.
345
+ * Normalizes older hosted host names to the current public API domain.
346
+ * Self-hosted or custom URLs pass through unchanged; only the retired
347
+ * first-party host names are rewritten.
350
348
  */
351
349
  export function normalizeAbloHostedBaseUrl(rawUrl) {
352
350
  const trimmed = rawUrl.trim();
353
351
  if (!trimmed)
354
352
  return trimmed;
355
- // A scheme-less value (e.g. `api-staging.abloatai.com`) is a RELATIVE URL:
356
- // `new URL()` throws on it, and downstream `fetch` then resolves it against
357
- // the current page — producing `https://<app-host>/<route>/api-staging…/api/
358
- // auth/identity`, a 404 from the app's own origin. Prepend a scheme so the
359
- // base is absolute. `https` mirrors `ABLO_HOSTED_HTTP_BASE_URL`; the socket
360
- // layer derives `wss` from it. An existing scheme (ws/wss/http/https) is
361
- // preserved untouched.
353
+ // A scheme-less value (e.g. `api-staging.abloatai.com`) is treated as a
354
+ // relative URL: `new URL()` throws on it, and a later `fetch` would resolve it
355
+ // against the current page — producing a 404 from the app's own origin.
356
+ // Prepending a scheme makes the base absolute. `https` matches
357
+ // {@link ABLO_HOSTED_HTTP_BASE_URL}; the socket layer derives `wss` from it.
358
+ // An existing scheme (ws, wss, http, or https) is preserved untouched.
362
359
  const schemed = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
363
360
  try {
364
361
  const url = new URL(schemed);
365
- // Canonicalize the scheme to the HTTP family the WHATWG WebSocket
366
- // model: accept all four schemes (`http`/`https`/`ws`/`wss`), normalize
367
- // ONCE at the entry point, and let each layer derive its own protocol
368
- // (the socket layer maps http→ws / https→wss; fetch uses it as-is).
369
- // Before this, a `ws://` baseURL reached HTTP consumers un-normalized
370
- // and the client wedged at startup instead of connecting.
362
+ // Canonicalize the scheme to the HTTP family: accept all four schemes
363
+ // (http, https, ws, wss), normalize at this single entry point, and let
364
+ // each layer derive its own protocol (the socket layer maps http to ws and
365
+ // https to wss; fetch uses the URL as-is). Without this, a `ws://` base URL
366
+ // reaches HTTP consumers un-normalized and the client fails at startup
367
+ // instead of connecting.
371
368
  if (url.protocol === 'ws:')
372
369
  url.protocol = 'http:';
373
370
  if (url.protocol === 'wss:')
@@ -388,11 +385,12 @@ export function resolveBaseURL(input) {
388
385
  return normalizeAbloHostedBaseUrl(input.options.baseURL ?? ABLO_DEFAULT_BASE_URL);
389
386
  }
390
387
  /**
391
- * Browser guard apiKey is server-side-only by default. Same check
392
- * Anthropic, OpenAI, and Stripe ship: shipping `sk_live_...` to a
393
- * browser exposes it in every visitor's network tab. Consumers opt
394
- * in explicitly when the browser holds a minted session token
395
- * (`ek_`/`rk_`) or routes through a server proxy.
388
+ * Guards against using a secret `apiKey` in a browser. A secret key is
389
+ * server-side only by default: shipping an `sk_live_...` key to a browser would
390
+ * expose it in every visitor's network tab. Callers opt in explicitly when the
391
+ * browser instead holds a minted session token (`ek_`/`rk_`) or routes through a
392
+ * server proxy. Throws {@link AbloAuthenticationError} when a secret key is
393
+ * detected in a browser without opt-in.
396
394
  */
397
395
  export function assertBrowserSafety(input) {
398
396
  const inBrowser = typeof window !== 'undefined';
@@ -407,9 +405,9 @@ export function assertBrowserSafety(input) {
407
405
  '`dangerouslyAllowBrowser` option to `true`, e.g.,\n\n' +
408
406
  ' Ablo({ schema, apiKey, dangerouslyAllowBrowser: true });\n', { code: 'browser_apikey_blocked' });
409
407
  }
410
- // `databaseUrl` carries DB credentials and is NEVER browser-safe, so
411
- // `dangerouslyAllowBrowser` does not override it. Register your database from
412
- // a server-side runtime.
408
+ // `databaseUrl` carries database credentials and is never browser-safe, so
409
+ // `dangerouslyAllowBrowser` does not override this check. Register your
410
+ // database from a server-side runtime.
413
411
  if (inBrowser && typeof input.databaseUrl === 'string' && input.databaseUrl.length > 0) {
414
412
  throw new AbloAuthenticationError('Ablo `databaseUrl` cannot be used in a browser-like environment — it ' +
415
413
  'carries your database credentials. Initialize the client with ' +
@@ -417,12 +415,10 @@ export function assertBrowserSafety(input) {
417
415
  }
418
416
  }
419
417
  /**
420
- * Resolve an `ApiKeySetter` callable to its current string value.
421
- * Used at request time so a rotating credential picks up rotations
422
- * between requests. Returns `null` when no key was configured.
423
- *
424
- * Mirrors Anthropic's pattern of supporting both a static string and
425
- * a callable for credential rotation.
418
+ * Resolves an {@link ApiKeySetter} callable to its current string value, or
419
+ * returns a plain string key as-is. Called at request time so a rotating
420
+ * credential picks up new values between requests. Returns `null` when no key
421
+ * was configured.
426
422
  */
427
423
  export async function resolveApiKeyValue(apiKey) {
428
424
  if (apiKey == null)
@@ -432,44 +428,39 @@ export async function resolveApiKeyValue(apiKey) {
432
428
  return apiKey;
433
429
  }
434
430
  /**
435
- * Translate a sync-engine WebSocket URL to the matching HTTP API
436
- * base URL, defaulting to `${url}/api` when the caller hasn't
437
- * overridden `bootstrapBaseUrl`. Used by `BootstrapHelper`,
438
- * `HydrationCoordinator`, the apiKey-exchange flow, and the
439
- * self-derived identity flow — same derivation in all four spots,
440
- * so it lives here as a single source of truth.
431
+ * Translates a WebSocket URL into the matching HTTP API base URL, defaulting to
432
+ * `${url}/api` when the caller has not overridden `bootstrapBaseUrl`. The
433
+ * bootstrap helper, the hydration coordinator, the credential-exchange flow, and
434
+ * the identity flow all derive their base URL through this one function, so the
435
+ * derivation stays consistent across them.
441
436
  *
442
- * Note: when both `wss://` and `https://` are valid, `replace(/^ws/, 'http')`
443
- * preserves the protocol family (ws http, wss https).
437
+ * When both `wss://` and `https://` are valid, the ws-to-http rewrite preserves
438
+ * the protocol family: ws becomes http and wss becomes https.
444
439
  */
445
440
  export function resolveBootstrapBaseUrl(input) {
446
441
  if (input.bootstrapBaseUrl) {
447
- // Coerce ws/wss http/https on the override path too. This base URL is
448
- // used for HTTP fetches (identity resolve, apiKey exchange, bootstrap) and
449
- // the browser `fetch` rejects ws/wss schemes outright ("URL scheme \"wss\"
450
- // is not supported"). apps/web derives this override as `${baseUrl}/api`
451
- // where `baseUrl` may carry a WebSocket scheme, so the override can
452
- // legitimately arrive as `wss://…` normalize it here rather than
453
- // faceplanting at fetch time. The derive branch below already does this;
454
- // the override branch silently skipped it.
442
+ // Coerce ws/wss to http/https on the override path as well. This base URL is
443
+ // used for HTTP fetches (identity resolution, credential exchange, and
444
+ // bootstrap), and the browser `fetch` rejects ws and wss schemes outright.
445
+ // The override can legitimately arrive with a WebSocket scheme when a caller
446
+ // derives it as `${baseUrl}/api` from a WebSocket base URL, so normalize it
447
+ // here rather than failing at fetch time.
455
448
  return ensureApiSuffix(normalizeAbloHostedBaseUrl(input.bootstrapBaseUrl).replace(/^ws/, 'http'));
456
449
  }
457
450
  const url = normalizeAbloHostedBaseUrl(input.url);
458
451
  return ensureApiSuffix(url.replace(/^ws/, 'http'));
459
452
  }
460
453
  /**
461
- * Guarantee the HTTP base ends in the `/api` route segment the sync-server
462
- * mounts every endpoint under (`apps/sync-server/src/index.ts` — `app.route('/api', …)`).
454
+ * Ensures the HTTP base ends in the `/api` route segment that every endpoint is
455
+ * mounted under.
463
456
  *
464
- * The derive branch always appended `/api`; the override branch did NOT,
465
- * trusting the caller (apps/web passes `${baseUrl}/api`). But a hosted
466
- * customer setting a custom `baseURL`/`bootstrapBaseUrl` (their own subdomain,
467
- * staging, etc.) without the suffix sent every credential exchange to
468
- * `…/auth/capability` instead of `…/api/auth/capability` a 404 surfaced as
469
- * `exchange_failed`. Since the SDK hardcodes routes relative to this base and
470
- * there is no valid Ablo deployment that serves them off the root, normalizing
471
- * to a single trailing `/api` here is always correct — and idempotent for
472
- * callers who already include it.
457
+ * A hosted deployment that sets a custom `baseURL` or `bootstrapBaseUrl` (a
458
+ * custom subdomain, a staging host, and so on) without the `/api` suffix would
459
+ * send every credential exchange to `…/auth/capability` instead of
460
+ * `…/api/auth/capability`, producing a 404 that surfaces as `exchange_failed`.
461
+ * Since the client builds routes relative to this base and no valid deployment
462
+ * serves them from the root, appending a single trailing `/api` here is always
463
+ * correct, and it is idempotent for callers who already include it.
473
464
  */
474
465
  function ensureApiSuffix(httpBase) {
475
466
  const trimmed = httpBase.replace(/\/+$/, '');
@@ -482,8 +473,8 @@ function ensureApiSuffix(httpBase) {
482
473
  return u.toString().replace(/\/+$/, '');
483
474
  }
484
475
  catch {
485
- // Should be unreachable post-`normalizeAbloHostedBaseUrl` (which yields an
486
- // absolute URL), but fall back to a string check rather than throwing.
476
+ // Should be unreachable after `normalizeAbloHostedBaseUrl`, which yields an
477
+ // absolute URL, but fall back to a string check rather than throwing.
487
478
  return trimmed.endsWith("/api") ? trimmed : `${trimmed}/api`;
488
479
  }
489
480
  }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The auto-heartbeat loop behind `claim({ id, heartbeat: true })` — one
3
+ * implementation shared by both transports (the WebSocket claim stream and the
4
+ * HTTP `ApiClient`), so the cadence and failure semantics cannot drift.
5
+ *
6
+ * A beat is the "still working" signal that keeps a lease alive for the
7
+ * duration of real work. The loop's failure handling follows the lease-system
8
+ * convention (SQS visibility heartbeats, Kubernetes leases): a beat that fails
9
+ * for a transient reason — the network blipped, the server was briefly
10
+ * unavailable — is simply retried on the next tick, because the lease has
11
+ * runway to spare by construction (the default cadence is a third of the TTL,
12
+ * so two consecutive beats can fail before the lease is even at risk). Only a
13
+ * definitive answer from the server — the lease lapsed and may have been
14
+ * granted to the next in line ({@link AbloClaimedError}) — stops the loop and
15
+ * surfaces the loss, because for a caller with no push channel the failed beat
16
+ * IS the loss notification.
17
+ */
18
+ import { AbloClaimedError } from '../errors.js';
19
+ import type { ClaimHeartbeat, ClaimHeartbeatOptions, Duration } from '../types/streams.js';
20
+ /**
21
+ * Normalize the public `heartbeat(options?)` argument — a bare Duration is
22
+ * shorthand for `{ ttl }`. Shared by both transports' handle assembly so the
23
+ * shorthand cannot drift.
24
+ */
25
+ export declare function resolveHeartbeatOptions(input: Duration | ClaimHeartbeatOptions | undefined): ClaimHeartbeatOptions;
26
+ /**
27
+ * The beat cadence for a lease of `ttlMs`: an explicit duration when the
28
+ * caller set one, otherwise a third of the TTL (floored at 1s) — the
29
+ * DynamoDB-lock-client rule, leaving two missed beats of runway before the
30
+ * lease is at risk while keeping crash recovery within one beat window.
31
+ */
32
+ export declare function heartbeatCadenceMs(ttlMs: number, heartbeat: true | Duration): number;
33
+ export interface ClaimHeartbeatLoopOptions {
34
+ /** Send one beat; resolves while the lease is still ours. */
35
+ beat(): Promise<ClaimHeartbeat>;
36
+ /** Cadence between beats. Callers default this to a third of the TTL. */
37
+ intervalMs: number;
38
+ /**
39
+ * Called once when a beat comes back with a definitive loss — the lease
40
+ * expired or was taken. The loop has already stopped by the time this runs.
41
+ */
42
+ onLost?(error: AbloClaimedError): void;
43
+ }
44
+ /**
45
+ * Start beating. Returns a stop function; callers stop the loop when the
46
+ * claim is released (all held-claim assembly sites tie this to `release`).
47
+ * Beats never overlap: a tick that fires while the previous beat is still
48
+ * in flight is skipped rather than stacked.
49
+ */
50
+ export declare function startClaimHeartbeatLoop(options: ClaimHeartbeatLoopOptions): () => void;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The auto-heartbeat loop behind `claim({ id, heartbeat: true })` — one
3
+ * implementation shared by both transports (the WebSocket claim stream and the
4
+ * HTTP `ApiClient`), so the cadence and failure semantics cannot drift.
5
+ *
6
+ * A beat is the "still working" signal that keeps a lease alive for the
7
+ * duration of real work. The loop's failure handling follows the lease-system
8
+ * convention (SQS visibility heartbeats, Kubernetes leases): a beat that fails
9
+ * for a transient reason — the network blipped, the server was briefly
10
+ * unavailable — is simply retried on the next tick, because the lease has
11
+ * runway to spare by construction (the default cadence is a third of the TTL,
12
+ * so two consecutive beats can fail before the lease is even at risk). Only a
13
+ * definitive answer from the server — the lease lapsed and may have been
14
+ * granted to the next in line ({@link AbloClaimedError}) — stops the loop and
15
+ * surfaces the loss, because for a caller with no push channel the failed beat
16
+ * IS the loss notification.
17
+ */
18
+ import { AbloClaimedError } from '../errors.js';
19
+ import { toMs } from '../utils/duration.js';
20
+ /**
21
+ * Normalize the public `heartbeat(options?)` argument — a bare Duration is
22
+ * shorthand for `{ ttl }`. Shared by both transports' handle assembly so the
23
+ * shorthand cannot drift.
24
+ */
25
+ export function resolveHeartbeatOptions(input) {
26
+ if (input === undefined)
27
+ return {};
28
+ if (typeof input === 'string' || typeof input === 'number') {
29
+ return { ttl: input };
30
+ }
31
+ return input;
32
+ }
33
+ /**
34
+ * The beat cadence for a lease of `ttlMs`: an explicit duration when the
35
+ * caller set one, otherwise a third of the TTL (floored at 1s) — the
36
+ * DynamoDB-lock-client rule, leaving two missed beats of runway before the
37
+ * lease is at risk while keeping crash recovery within one beat window.
38
+ */
39
+ export function heartbeatCadenceMs(ttlMs, heartbeat) {
40
+ if (heartbeat !== true)
41
+ return toMs(heartbeat);
42
+ return Math.max(Math.floor(ttlMs / 3), 1_000);
43
+ }
44
+ /**
45
+ * Start beating. Returns a stop function; callers stop the loop when the
46
+ * claim is released (all held-claim assembly sites tie this to `release`).
47
+ * Beats never overlap: a tick that fires while the previous beat is still
48
+ * in flight is skipped rather than stacked.
49
+ */
50
+ export function startClaimHeartbeatLoop(options) {
51
+ let stopped = false;
52
+ let inFlight = false;
53
+ const stop = () => {
54
+ if (stopped)
55
+ return;
56
+ stopped = true;
57
+ clearInterval(timer);
58
+ };
59
+ const timer = setInterval(() => {
60
+ if (stopped || inFlight)
61
+ return;
62
+ inFlight = true;
63
+ options
64
+ .beat()
65
+ .catch((error) => {
66
+ if (stopped)
67
+ return;
68
+ if (error instanceof AbloClaimedError) {
69
+ stop();
70
+ options.onLost?.(error);
71
+ return;
72
+ }
73
+ // Transient (connection, brief server unavailability): the next tick
74
+ // is the retry — the ttl/3 cadence leaves runway for missed beats.
75
+ })
76
+ .finally(() => {
77
+ inFlight = false;
78
+ });
79
+ }, options.intervalMs);
80
+ // The loop must never be what keeps a Node process alive — the held work
81
+ // is. A worker that finishes without releasing exits anyway, and the lease
82
+ // lapses on schedule. No-op in browsers (where setInterval returns a number
83
+ // without `unref`), which is why the call is optional even though the Node
84
+ // timer type always has it.
85
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
86
+ timer.unref?.();
87
+ return stop;
88
+ }
@@ -1,9 +1,8 @@
1
1
  /**
2
- * The default `[Ablo]` console logger + its level resolution.
2
+ * The default `[Ablo]` console logger and its level resolution.
3
3
  *
4
- * Extracted from `Ablo.ts`; exported so other entry points that build a
5
- * default logger (e.g. the agent runtime) can reuse the same gating instead
6
- * of hand-rolling a console shim.
4
+ * These helpers are exported so any entry point that needs a default logger can
5
+ * reuse the same level gating rather than hand-rolling a console wrapper.
7
6
  */
8
7
  import type { SyncLogger } from '../interfaces/index.js';
9
8
  /**
@@ -30,7 +29,7 @@ export declare function resolveLogLevel(opts?: {
30
29
  logLevel?: LogLevel;
31
30
  }): LogLevel;
32
31
  /**
33
- * Build the default logger, gated at `level` and prefixed `[Ablo]` so a creator
34
- * with a console full of other tools' logs can see at a glance what's ours.
32
+ * Builds the default logger, gated at `level` and prefixed `[Ablo]` so its lines
33
+ * stand out in a console full of other tools' output.
35
34
  */
36
35
  export declare function createConsoleLogger(level: LogLevel): SyncLogger;
@@ -1,9 +1,8 @@
1
1
  /**
2
- * The default `[Ablo]` console logger + its level resolution.
2
+ * The default `[Ablo]` console logger and its level resolution.
3
3
  *
4
- * Extracted from `Ablo.ts`; exported so other entry points that build a
5
- * default logger (e.g. the agent runtime) can reuse the same gating instead
6
- * of hand-rolling a console shim.
4
+ * These helpers are exported so any entry point that needs a default logger can
5
+ * reuse the same level gating rather than hand-rolling a console wrapper.
7
6
  */
8
7
  const LOG_LEVEL_RANK = { debug: 10, info: 20, warn: 30, error: 40, silent: 99 };
9
8
  /**
@@ -26,8 +25,8 @@ export function resolveLogLevel(opts) {
26
25
  return 'warn';
27
26
  }
28
27
  /**
29
- * Build the default logger, gated at `level` and prefixed `[Ablo]` so a creator
30
- * with a console full of other tools' logs can see at a glance what's ours.
28
+ * Builds the default logger, gated at `level` and prefixed `[Ablo]` so its lines
29
+ * stand out in a console full of other tools' output.
31
30
  */
32
31
  export function createConsoleLogger(level) {
33
32
  const threshold = LOG_LEVEL_RANK[level];
@@ -1,28 +1,25 @@
1
1
  /**
2
- * Internal component construction for `Ablo()`.
2
+ * Builds the internal component graph the client runs on.
3
3
  *
4
- * Builds the full sync-engine component graph from options + schema:
5
- * `ModelRegistry`, `ObjectPool`, `BootstrapHelper`, `Database`,
6
- * `SyncClient`, `HydrationCoordinator`. Each component depends on
7
- * the previous one, so the construction order matters; isolating it
8
- * here means `Ablo.ts` doesn't need to know the dependency order.
9
- *
10
- * Mirrors the pattern Anthropic uses: their client constructor wires
11
- * endpoint modules. Ours wires the sync-engine components instead.
4
+ * From the caller's options and schema this wires together the model registry,
5
+ * object pool, bootstrap helper, database, sync client, and hydration
6
+ * coordinator. Each component depends on the one before it, so construction
7
+ * order matters; keeping it here means the client constructor does not have to
8
+ * know that order.
12
9
  */
13
10
  import { Database } from '../Database.js';
14
11
  import { ModelRegistry } from '../ModelRegistry.js';
15
- import { ObjectPool } from '../ObjectPool.js';
12
+ import { InstanceCache } from '../InstanceCache.js';
16
13
  import { SyncClient } from '../SyncClient.js';
17
- import { HydrationCoordinator } from '../sync/HydrationCoordinator.js';
18
- import { BootstrapHelper } from '../sync/BootstrapHelper.js';
14
+ import { OnDemandLoader } from '../sync/OnDemandLoader.js';
15
+ import { BootstrapFetcher } from '../sync/BootstrapFetcher.js';
19
16
  import type { AuthCredentialSource } from '../auth/credentialSource.js';
20
17
  import type { Schema, SchemaRecord } from '../schema/schema.js';
21
18
  import { type AbloPersistence } from './persistence.js';
22
19
  export interface InternalComponentsInput<S extends SchemaRecord> {
23
20
  readonly schema: Schema<S>;
24
- /** WebSocket URL used to derive bootstrap HTTP base when the
25
- * caller didn't override `bootstrapBaseUrl`. */
21
+ /** The WebSocket URL. Used to derive the bootstrap HTTP base URL when the
22
+ * caller has not overridden `bootstrapBaseUrl`. */
26
23
  readonly url: string;
27
24
  readonly options: {
28
25
  readonly maxPoolSize?: number;
@@ -36,10 +33,10 @@ export interface InternalComponentsInput<S extends SchemaRecord> {
36
33
  }
37
34
  export interface InternalComponents {
38
35
  readonly modelRegistry: ModelRegistry;
39
- readonly objectPool: ObjectPool;
40
- readonly bootstrapHelper: BootstrapHelper;
36
+ readonly objectPool: InstanceCache;
37
+ readonly bootstrapHelper: BootstrapFetcher;
41
38
  readonly database: Database;
42
39
  readonly syncClient: SyncClient;
43
- readonly hydration: HydrationCoordinator;
40
+ readonly hydration: OnDemandLoader;
44
41
  }
45
42
  export declare function createInternalComponents<S extends SchemaRecord>(input: InternalComponentsInput<S>): InternalComponents;