@abloatai/ablo 0.25.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 (425) hide show
  1. package/AGENTS.md +5 -3
  2. package/CHANGELOG.md +34 -0
  3. package/README.md +104 -88
  4. package/dist/BaseSyncedStore.d.ts +140 -266
  5. package/dist/BaseSyncedStore.js +338 -739
  6. package/dist/Database.d.ts +62 -77
  7. package/dist/Database.js +106 -127
  8. package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
  9. package/dist/{ObjectPool.js → InstanceCache.js} +91 -83
  10. package/dist/LazyReferenceCollection.d.ts +11 -15
  11. package/dist/LazyReferenceCollection.js +16 -15
  12. package/dist/Model.d.ts +37 -52
  13. package/dist/Model.js +52 -69
  14. package/dist/ModelRegistry.d.ts +46 -25
  15. package/dist/ModelRegistry.js +32 -30
  16. package/dist/NetworkMonitor.d.ts +5 -6
  17. package/dist/NetworkMonitor.js +6 -7
  18. package/dist/SyncClient.d.ts +119 -109
  19. package/dist/SyncClient.js +303 -224
  20. package/dist/SyncEngineContext.d.ts +1 -3
  21. package/dist/SyncEngineContext.js +1 -2
  22. package/dist/adapters/alwaysOnline.d.ts +6 -8
  23. package/dist/adapters/alwaysOnline.js +6 -8
  24. package/dist/adapters/inMemoryStorage.d.ts +9 -9
  25. package/dist/adapters/inMemoryStorage.js +9 -9
  26. package/dist/agent/Agent.d.ts +39 -31
  27. package/dist/agent/Agent.js +35 -23
  28. package/dist/agent/index.d.ts +4 -4
  29. package/dist/agent/index.js +5 -5
  30. package/dist/agent/session.d.ts +47 -44
  31. package/dist/agent/session.js +37 -48
  32. package/dist/agent/types.d.ts +26 -31
  33. package/dist/agent/types.js +6 -7
  34. package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
  35. package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
  36. package/dist/ai-sdk/coordinationContext.d.ts +46 -0
  37. package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +30 -31
  38. package/dist/ai-sdk/index.d.ts +25 -22
  39. package/dist/ai-sdk/index.js +25 -22
  40. package/dist/ai-sdk/wrap.d.ts +7 -8
  41. package/dist/ai-sdk/wrap.js +2 -2
  42. package/dist/auth/credentialPolicy.d.ts +74 -71
  43. package/dist/auth/credentialPolicy.js +51 -56
  44. package/dist/auth/credentialSource.d.ts +7 -18
  45. package/dist/auth/credentialSource.js +10 -18
  46. package/dist/auth/index.d.ts +59 -58
  47. package/dist/auth/index.js +34 -40
  48. package/dist/auth/schemas.d.ts +5 -4
  49. package/dist/auth/schemas.js +5 -4
  50. package/dist/batching/index.d.ts +19 -21
  51. package/dist/batching/index.js +14 -17
  52. package/dist/cli.cjs +483 -369
  53. package/dist/client/Ablo.d.ts +107 -836
  54. package/dist/client/Ablo.js +174 -833
  55. package/dist/client/ApiClient.d.ts +44 -20
  56. package/dist/client/ApiClient.js +193 -44
  57. package/dist/client/auth.d.ts +51 -60
  58. package/dist/client/auth.js +137 -110
  59. package/dist/client/claimHeartbeatLoop.d.ts +50 -0
  60. package/dist/client/claimHeartbeatLoop.js +88 -0
  61. package/dist/client/consoleLogger.d.ts +35 -0
  62. package/dist/client/consoleLogger.js +44 -0
  63. package/dist/client/createInternalComponents.d.ts +14 -17
  64. package/dist/client/createInternalComponents.js +26 -31
  65. package/dist/client/createModelProxy.d.ts +130 -120
  66. package/dist/client/createModelProxy.js +158 -124
  67. package/dist/client/credentialEndpoint.d.ts +61 -0
  68. package/dist/client/credentialEndpoint.js +86 -0
  69. package/dist/client/functionalUpdate.d.ts +29 -27
  70. package/dist/client/functionalUpdate.js +21 -21
  71. package/dist/client/hostedEndpoints.d.ts +21 -0
  72. package/dist/client/hostedEndpoints.js +21 -0
  73. package/dist/client/httpClient.d.ts +58 -54
  74. package/dist/client/httpClient.js +29 -31
  75. package/dist/client/identity.d.ts +15 -20
  76. package/dist/client/identity.js +49 -59
  77. package/dist/client/modelRegistration.d.ts +10 -0
  78. package/dist/client/modelRegistration.js +301 -0
  79. package/dist/client/options.d.ts +373 -0
  80. package/dist/client/options.js +6 -0
  81. package/dist/client/registerDataSource.d.ts +9 -9
  82. package/dist/client/registerDataSource.js +15 -16
  83. package/dist/client/resourceTypes.d.ts +333 -0
  84. package/dist/client/resourceTypes.js +7 -0
  85. package/dist/client/schemaConfig.d.ts +44 -0
  86. package/dist/client/schemaConfig.js +176 -0
  87. package/dist/client/sessionMint.d.ts +17 -13
  88. package/dist/client/sessionMint.js +26 -31
  89. package/dist/client/validateAbloOptions.d.ts +12 -14
  90. package/dist/client/validateAbloOptions.js +9 -10
  91. package/dist/client/writeOptionsSchema.d.ts +18 -16
  92. package/dist/client/writeOptionsSchema.js +23 -20
  93. package/dist/client/wsMutationExecutor.d.ts +28 -0
  94. package/dist/client/wsMutationExecutor.js +71 -0
  95. package/dist/context.d.ts +6 -4
  96. package/dist/context.js +6 -7
  97. package/dist/coordination/index.d.ts +13 -4
  98. package/dist/coordination/index.js +29 -4
  99. package/dist/coordination/schema.d.ts +176 -128
  100. package/dist/coordination/schema.js +197 -133
  101. package/dist/coordination/trace.d.ts +9 -11
  102. package/dist/coordination/trace.js +13 -15
  103. package/dist/core/DatabaseManager.d.ts +5 -8
  104. package/dist/core/DatabaseManager.js +38 -40
  105. package/dist/core/QueryProcessor.d.ts +7 -9
  106. package/dist/core/QueryProcessor.js +27 -34
  107. package/dist/core/QueryView.d.ts +17 -5
  108. package/dist/core/QueryView.js +6 -7
  109. package/dist/core/StoreManager.d.ts +14 -16
  110. package/dist/core/StoreManager.js +26 -25
  111. package/dist/core/ViewRegistry.d.ts +5 -5
  112. package/dist/core/ViewRegistry.js +4 -4
  113. package/dist/core/index.d.ts +18 -13
  114. package/dist/core/index.js +32 -26
  115. package/dist/core/openIDBWithTimeout.d.ts +38 -36
  116. package/dist/core/openIDBWithTimeout.js +57 -54
  117. package/dist/core/queryUtils.d.ts +45 -0
  118. package/dist/core/queryUtils.js +69 -0
  119. package/dist/core/storeContract.d.ts +145 -0
  120. package/dist/core/storeContract.js +12 -0
  121. package/dist/environment.d.ts +28 -0
  122. package/dist/environment.js +21 -0
  123. package/dist/errorCodes.d.ts +118 -101
  124. package/dist/errorCodes.js +277 -260
  125. package/dist/errors.d.ts +170 -165
  126. package/dist/errors.js +161 -151
  127. package/dist/index.d.ts +30 -27
  128. package/dist/index.js +90 -82
  129. package/dist/interfaces/index.d.ts +108 -133
  130. package/dist/interfaces/index.js +5 -4
  131. package/dist/keys/index.d.ts +27 -29
  132. package/dist/keys/index.js +59 -49
  133. package/dist/mutators/RecordingTransaction.d.ts +16 -16
  134. package/dist/mutators/RecordingTransaction.js +31 -37
  135. package/dist/mutators/Transaction.d.ts +18 -26
  136. package/dist/mutators/Transaction.js +14 -20
  137. package/dist/mutators/UndoManager.d.ts +122 -131
  138. package/dist/mutators/UndoManager.js +149 -155
  139. package/dist/mutators/defineMutators.d.ts +24 -37
  140. package/dist/mutators/defineMutators.js +14 -20
  141. package/dist/mutators/inverseOp.d.ts +12 -15
  142. package/dist/mutators/inverseOp.js +12 -15
  143. package/dist/mutators/mutateActions.d.ts +10 -9
  144. package/dist/mutators/mutateActions.js +1 -1
  145. package/dist/mutators/readerActions.d.ts +9 -8
  146. package/dist/mutators/readerActions.js +2 -2
  147. package/dist/mutators/undoApply.d.ts +31 -27
  148. package/dist/mutators/undoApply.js +26 -24
  149. package/dist/policy/index.d.ts +5 -3
  150. package/dist/policy/index.js +5 -3
  151. package/dist/policy/types.d.ts +105 -101
  152. package/dist/policy/types.js +67 -66
  153. package/dist/query/client.d.ts +32 -16
  154. package/dist/query/client.js +103 -72
  155. package/dist/query/types.d.ts +37 -60
  156. package/dist/query/types.js +13 -33
  157. package/dist/react/AbloProvider.d.ts +7 -11
  158. package/dist/react/AbloProvider.js +24 -17
  159. package/dist/react/context.d.ts +27 -146
  160. package/dist/react/context.js +9 -10
  161. package/dist/react/index.d.ts +41 -42
  162. package/dist/react/index.js +37 -38
  163. package/dist/react/internalContext.d.ts +17 -19
  164. package/dist/react/useAblo.d.ts +23 -22
  165. package/dist/react/useAblo.js +17 -15
  166. package/dist/react/useCurrentUserId.d.ts +8 -7
  167. package/dist/react/useCurrentUserId.js +8 -7
  168. package/dist/react/useErrorListener.d.ts +7 -7
  169. package/dist/react/useErrorListener.js +11 -12
  170. package/dist/react/useMutationFailureListener.d.ts +8 -8
  171. package/dist/react/useMutationFailureListener.js +9 -9
  172. package/dist/react/useMutators.d.ts +11 -11
  173. package/dist/react/useMutators.js +10 -4
  174. package/dist/react/useReactive.js +2 -3
  175. package/dist/react/useSyncStatus.d.ts +4 -6
  176. package/dist/react/useUndoScope.d.ts +7 -9
  177. package/dist/react/useUndoScope.js +3 -3
  178. package/dist/schema/coordination.d.ts +21 -25
  179. package/dist/schema/coordination.js +21 -25
  180. package/dist/schema/ddl.d.ts +43 -39
  181. package/dist/schema/ddl.js +75 -68
  182. package/dist/schema/ddlLock.d.ts +35 -0
  183. package/dist/schema/ddlLock.js +46 -0
  184. package/dist/schema/diff.d.ts +99 -61
  185. package/dist/schema/diff.js +43 -34
  186. package/dist/schema/field.d.ts +37 -42
  187. package/dist/schema/field.js +36 -49
  188. package/dist/schema/generate.d.ts +12 -12
  189. package/dist/schema/generate.js +12 -12
  190. package/dist/schema/index.d.ts +5 -4
  191. package/dist/schema/index.js +29 -21
  192. package/dist/schema/model.d.ts +121 -146
  193. package/dist/schema/model.js +24 -35
  194. package/dist/schema/openapi.d.ts +10 -9
  195. package/dist/schema/openapi.js +7 -1
  196. package/dist/schema/queries.d.ts +30 -32
  197. package/dist/schema/queries.js +24 -25
  198. package/dist/schema/relation.d.ts +89 -99
  199. package/dist/schema/relation.js +13 -13
  200. package/dist/schema/residency.d.ts +38 -0
  201. package/dist/schema/residency.js +30 -0
  202. package/dist/schema/roles.d.ts +45 -27
  203. package/dist/schema/roles.js +52 -21
  204. package/dist/schema/schema.d.ts +36 -45
  205. package/dist/schema/schema.js +42 -39
  206. package/dist/schema/select.d.ts +13 -13
  207. package/dist/schema/select.js +13 -13
  208. package/dist/schema/serialize.d.ts +36 -39
  209. package/dist/schema/serialize.js +27 -31
  210. package/dist/schema/sugar.d.ts +17 -32
  211. package/dist/schema/sugar.js +14 -29
  212. package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +27 -50
  213. package/dist/schema/syncDeltaRow.js +89 -0
  214. package/dist/schema/tenancy.d.ts +44 -46
  215. package/dist/schema/tenancy.js +46 -48
  216. package/dist/server/adapter.d.ts +58 -58
  217. package/dist/server/adapter.js +13 -14
  218. package/dist/server/commit.d.ts +60 -64
  219. package/dist/server/index.d.ts +9 -10
  220. package/dist/server/index.js +1 -1
  221. package/dist/server/readConfig.d.ts +70 -0
  222. package/dist/server/readConfig.js +8 -0
  223. package/dist/server/storageMode.d.ts +23 -0
  224. package/dist/server/storageMode.js +17 -0
  225. package/dist/source/adapter.d.ts +31 -26
  226. package/dist/source/adapter.js +10 -10
  227. package/dist/source/adapters/drizzle.d.ts +28 -23
  228. package/dist/source/adapters/drizzle.js +34 -28
  229. package/dist/source/adapters/kysely.d.ts +27 -25
  230. package/dist/source/adapters/kysely.js +28 -26
  231. package/dist/source/adapters/memory.d.ts +8 -7
  232. package/dist/source/adapters/memory.js +10 -9
  233. package/dist/source/adapters/prisma.d.ts +13 -12
  234. package/dist/source/adapters/prisma.js +27 -29
  235. package/dist/source/conformance.d.ts +18 -11
  236. package/dist/source/conformance.js +27 -19
  237. package/dist/source/connector.d.ts +31 -32
  238. package/dist/source/connector.js +30 -28
  239. package/dist/source/connectorProtocol.d.ts +160 -0
  240. package/dist/source/connectorProtocol.js +162 -0
  241. package/dist/source/contract.d.ts +26 -27
  242. package/dist/source/contract.js +28 -29
  243. package/dist/source/factory.d.ts +94 -0
  244. package/dist/source/factory.js +268 -0
  245. package/dist/source/index.d.ts +10 -462
  246. package/dist/source/index.js +17 -421
  247. package/dist/source/migrations.d.ts +9 -9
  248. package/dist/source/migrations.js +9 -9
  249. package/dist/source/next.d.ts +10 -11
  250. package/dist/source/next.js +7 -8
  251. package/dist/source/pushQueue.d.ts +70 -48
  252. package/dist/source/pushQueue.js +36 -29
  253. package/dist/source/signing.d.ts +88 -0
  254. package/dist/source/signing.js +159 -0
  255. package/dist/source/types.d.ts +351 -0
  256. package/dist/source/types.js +43 -0
  257. package/dist/stores/ObjectStore.d.ts +11 -12
  258. package/dist/stores/ObjectStore.js +34 -35
  259. package/dist/stores/ObjectStoreContract.d.ts +12 -15
  260. package/dist/stores/SyncActionStore.d.ts +8 -12
  261. package/dist/stores/SyncActionStore.js +77 -46
  262. package/dist/surface.d.ts +28 -21
  263. package/dist/surface.js +28 -20
  264. package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +37 -45
  265. package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +101 -80
  266. package/dist/sync/ConnectionManager.d.ts +47 -50
  267. package/dist/sync/ConnectionManager.js +74 -70
  268. package/dist/sync/NetworkProbe.d.ts +27 -31
  269. package/dist/sync/NetworkProbe.js +67 -72
  270. package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +49 -36
  271. package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +79 -54
  272. package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +45 -59
  273. package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +44 -52
  274. package/dist/sync/SyncWebSocket.d.ts +175 -250
  275. package/dist/sync/SyncWebSocket.js +431 -769
  276. package/dist/sync/awaitClaimGrant.d.ts +18 -18
  277. package/dist/sync/awaitClaimGrant.js +38 -30
  278. package/dist/sync/bootstrapApply.d.ts +70 -0
  279. package/dist/sync/bootstrapApply.js +73 -0
  280. package/dist/sync/commitFrames.d.ts +44 -0
  281. package/dist/sync/commitFrames.js +94 -0
  282. package/dist/sync/createClaimStream.d.ts +23 -22
  283. package/dist/sync/createClaimStream.js +108 -25
  284. package/dist/sync/createPresenceStream.d.ts +19 -18
  285. package/dist/sync/createPresenceStream.js +25 -26
  286. package/dist/sync/createSnapshot.d.ts +13 -17
  287. package/dist/sync/createSnapshot.js +20 -26
  288. package/dist/sync/credentialLifecycle.d.ts +175 -0
  289. package/dist/sync/credentialLifecycle.js +322 -0
  290. package/dist/sync/deltaPipeline.d.ts +113 -0
  291. package/dist/sync/deltaPipeline.js +261 -0
  292. package/dist/sync/groupChange.d.ts +113 -0
  293. package/dist/sync/groupChange.js +242 -0
  294. package/dist/sync/heartbeat.d.ts +63 -0
  295. package/dist/sync/heartbeat.js +91 -0
  296. package/dist/sync/participants.d.ts +27 -27
  297. package/dist/sync/schemas.d.ts +3 -2
  298. package/dist/sync/schemas.js +14 -10
  299. package/dist/sync/syncCursor.d.ts +40 -0
  300. package/dist/sync/syncCursor.js +55 -0
  301. package/dist/sync/syncPlan.d.ts +54 -0
  302. package/dist/sync/syncPlan.js +50 -0
  303. package/dist/sync/syncPosition.d.ts +54 -49
  304. package/dist/sync/syncPosition.js +57 -52
  305. package/dist/sync/wsFrameHandlers.d.ts +116 -0
  306. package/dist/sync/wsFrameHandlers.js +374 -0
  307. package/dist/testing/fixtures/bootstrap.d.ts +21 -17
  308. package/dist/testing/fixtures/bootstrap.js +12 -6
  309. package/dist/testing/fixtures/deltas.d.ts +31 -34
  310. package/dist/testing/fixtures/deltas.js +30 -33
  311. package/dist/testing/fixtures/models.d.ts +11 -10
  312. package/dist/testing/fixtures/models.js +12 -10
  313. package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
  314. package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
  315. package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -18
  316. package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +14 -11
  317. package/dist/testing/helpers/wait.d.ts +13 -8
  318. package/dist/testing/helpers/wait.js +13 -8
  319. package/dist/testing/index.d.ts +4 -4
  320. package/dist/testing/index.js +3 -3
  321. package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
  322. package/dist/testing/mocks/MockMutationExecutor.js +15 -14
  323. package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
  324. package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
  325. package/dist/testing/mocks/MockSyncContext.d.ts +21 -34
  326. package/dist/testing/mocks/MockSyncContext.js +16 -45
  327. package/dist/testing/mocks/MockSyncStore.d.ts +14 -14
  328. package/dist/testing/mocks/MockSyncStore.js +11 -11
  329. package/dist/testing/mocks/MockWebSocket.d.ts +28 -24
  330. package/dist/testing/mocks/MockWebSocket.js +22 -21
  331. package/dist/transactions/TransactionQueue.d.ts +190 -221
  332. package/dist/transactions/TransactionQueue.js +424 -822
  333. package/dist/transactions/TransactionStore.d.ts +20 -0
  334. package/dist/transactions/TransactionStore.js +53 -0
  335. package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
  336. package/dist/transactions/UnconfirmedWrites.js +104 -0
  337. package/dist/transactions/coalesceRules.d.ts +58 -0
  338. package/dist/transactions/coalesceRules.js +140 -0
  339. package/dist/transactions/commitPayload.d.ts +130 -0
  340. package/dist/transactions/commitPayload.js +143 -0
  341. package/dist/transactions/deltaConfirmation.d.ts +58 -0
  342. package/dist/transactions/deltaConfirmation.js +215 -0
  343. package/dist/transactions/optimisticApply.d.ts +49 -0
  344. package/dist/transactions/optimisticApply.js +65 -0
  345. package/dist/transactions/replayValidation.d.ts +99 -0
  346. package/dist/transactions/replayValidation.js +111 -0
  347. package/dist/types/global.d.ts +46 -41
  348. package/dist/types/global.js +20 -19
  349. package/dist/types/index.d.ts +74 -80
  350. package/dist/types/index.js +22 -27
  351. package/dist/types/modelData.d.ts +10 -0
  352. package/dist/types/modelData.js +9 -0
  353. package/dist/types/participant.d.ts +20 -0
  354. package/dist/types/participant.js +10 -0
  355. package/dist/types/streams.d.ts +216 -209
  356. package/dist/types/streams.js +7 -7
  357. package/dist/utils/asyncIterator.d.ts +25 -32
  358. package/dist/utils/asyncIterator.js +25 -32
  359. package/dist/utils/duration.d.ts +12 -15
  360. package/dist/utils/duration.js +12 -15
  361. package/dist/utils/mobxSetup.d.ts +53 -0
  362. package/dist/utils/{mobx-setup.js → mobxSetup.js} +44 -100
  363. package/dist/webhooks/events.d.ts +21 -16
  364. package/dist/webhooks/events.js +10 -8
  365. package/dist/webhooks/index.d.ts +5 -7
  366. package/dist/webhooks/index.js +5 -7
  367. package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
  368. package/dist/wire/delta.js +114 -0
  369. package/dist/wire/errorEnvelope.d.ts +35 -27
  370. package/dist/wire/errorEnvelope.js +38 -32
  371. package/dist/wire/frames.d.ts +150 -67
  372. package/dist/wire/frames.js +48 -1
  373. package/dist/wire/index.d.ts +18 -13
  374. package/dist/wire/index.js +36 -13
  375. package/dist/wire/listEnvelope.d.ts +16 -23
  376. package/dist/wire/listEnvelope.js +7 -6
  377. package/dist/wire/protocol.d.ts +38 -0
  378. package/dist/wire/protocol.js +38 -0
  379. package/dist/wire/protocolVersion.d.ts +60 -0
  380. package/dist/wire/protocolVersion.js +67 -0
  381. package/docs/api-keys.md +4 -3
  382. package/docs/coordination.md +59 -0
  383. package/docs/examples/existing-python-backend.md +3 -3
  384. package/docs/identity.md +4 -4
  385. package/docs/integration-guide.md +1 -1
  386. package/docs/react.md +1 -1
  387. package/docs/sessions.md +5 -7
  388. package/package.json +24 -21
  389. package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
  390. package/dist/ai-sdk/coordination-context.d.ts +0 -52
  391. package/dist/client/index.d.ts +0 -36
  392. package/dist/client/index.js +0 -33
  393. package/dist/config/index.d.ts +0 -10
  394. package/dist/config/index.js +0 -12
  395. package/dist/core/query-utils.d.ts +0 -34
  396. package/dist/core/query-utils.js +0 -59
  397. package/dist/interfaces/headless.d.ts +0 -95
  398. package/dist/interfaces/headless.js +0 -41
  399. package/dist/query/index.d.ts +0 -6
  400. package/dist/query/index.js +0 -5
  401. package/dist/realtime/index.d.ts +0 -10
  402. package/dist/realtime/index.js +0 -9
  403. package/dist/schema/plane.d.ts +0 -23
  404. package/dist/schema/plane.js +0 -19
  405. package/dist/schema/sync-delta-row.js +0 -103
  406. package/dist/schema/sync-delta-wire.js +0 -102
  407. package/dist/server/next.d.ts +0 -51
  408. package/dist/server/next.js +0 -47
  409. package/dist/server/read-config.d.ts +0 -67
  410. package/dist/server/read-config.js +0 -8
  411. package/dist/server/storage-mode.d.ts +0 -1
  412. package/dist/server/storage-mode.js +0 -18
  413. package/dist/source/connector-protocol.d.ts +0 -159
  414. package/dist/source/connector-protocol.js +0 -161
  415. package/dist/sync/OfflineFlush.d.ts +0 -9
  416. package/dist/sync/OfflineFlush.js +0 -22
  417. package/dist/sync/OfflineTransactionStore.d.ts +0 -37
  418. package/dist/sync/OfflineTransactionStore.js +0 -263
  419. package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
  420. package/dist/transactions/OptimisticEchoTracker.js +0 -104
  421. package/dist/transactions/index.d.ts +0 -16
  422. package/dist/transactions/index.js +0 -7
  423. package/dist/transactions/mutation-error-handler.d.ts +0 -5
  424. package/dist/transactions/mutation-error-handler.js +0 -39
  425. package/dist/utils/mobx-setup.d.ts +0 -42
@@ -1,28 +1,28 @@
1
1
  /**
2
- * HTTP client for the generic /sync/query endpoint.
2
+ * The HTTP client for the sync query endpoint.
3
3
  *
4
- * Thin wrapper over fetch() that:
5
- * - POSTs a QueryBatch as JSON
6
- * - Sends the bearer credential via withAuthHeaders (Authorization header)
7
- * - Throws on non-2xx responses
8
- * - Parses the response into a typed QueryBatchResult
4
+ * {@link postQuery} is a small wrapper over `fetch` that POSTs a
5
+ * {@link QueryBatch} as JSON to `/sync/query`, attaches the bearer credential
6
+ * as an `Authorization` header, and parses the response into a typed
7
+ * {@link QueryBatchResult}. An HTTP failure is not thrown: it is logged, and
8
+ * every query in the batch comes back with an empty result, so a
9
+ * fire-and-forget caller cannot crash on an unhandled rejection.
9
10
  *
10
- * The higher-level BootstrapHelper methods (fetchDeckSlideLayers,
11
- * fetchChatMessages, etc.) use this to issue structured queries
12
- * without duplicating the fetch boilerplate.
11
+ * Higher-level query helpers build on this to issue structured queries without
12
+ * repeating the fetch and error-handling boilerplate.
13
13
  */
14
14
  import { z } from 'zod';
15
15
  import { translateHttpError } from '../errors.js';
16
+ import { classifyRecovery } from '../errorCodes.js';
16
17
  import { withAuthHeaders } from '../auth/credentialSource.js';
17
18
  import { getContext } from '../context.js';
18
19
  // ── Response validation ─────────────────────────────────────────────────
19
20
  //
20
- // Each result slot is an array of rows (or an object for bundled
21
- // responses). Server-side per-query failures surface here as `[]`, but
22
- // the server logs them via `console.error('[query.error] ...')` alert
23
- // on that prefix, not on emptiness. Parsing through Zod normalizes
24
- // `null` slots into empty arrays so downstream callers never see raw
25
- // null.
21
+ // Each result slot is an array of rows, or an object for a bundled response.
22
+ // A per-query failure on the server surfaces here as an empty array rather
23
+ // than an error, so emptiness alone does not distinguish "no rows" from
24
+ // "the query failed." Parsing through Zod normalizes a `null` slot into an
25
+ // empty array, so callers never receive a raw null.
26
26
  const QueryResultSchema = z
27
27
  .union([z.array(z.unknown()), z.record(z.string(), z.unknown()), z.null()])
28
28
  .transform((val) => {
@@ -36,71 +36,102 @@ const QueryBatchResultSchema = z
36
36
  })
37
37
  .passthrough();
38
38
  /**
39
- * POST a batch of queries to /sync/query. Returns the parsed
40
- * QueryBatchResult. Throws a descriptive error on HTTP failure.
39
+ * Sends a batch of queries to `/sync/query` and returns the parsed
40
+ * {@link QueryBatchResult}. An HTTP failure is not thrown: it is logged, and
41
+ * every query in the batch comes back with an empty result, which keeps a
42
+ * fire-and-forget caller from crashing on an unhandled rejection. A 401 may
43
+ * first be handed to {@link PostQueryOptions.recoverCredential} for a single
44
+ * retry.
41
45
  *
42
- * The server guarantees results[i] corresponds to queries[i] in the
43
- * request callers can rely on index alignment to extract typed
44
- * results from a multi-query batch.
46
+ * The response preserves order: `results[i]` corresponds to the query at
47
+ * `queries[i]`, so callers can rely on index alignment to pull typed results
48
+ * out of a multi-query batch.
45
49
  */
46
50
  export async function postQuery(options, batch) {
47
51
  const url = `${options.baseUrl}/sync/query`;
48
52
  const timeout = options.fetchTimeout ?? 30_000;
49
- // Race the fetch against a timeout so hung requests don't block
50
- // the calling helper indefinitely.
51
- const controller = new AbortController();
52
- const timer = setTimeout(() => controller.abort(), timeout);
53
- try {
54
- const headers = withAuthHeaders(options.getAuthToken, { 'Content-Type': 'application/json' }, options.capabilityToken);
55
- const response = await fetch(url, {
56
- method: 'POST',
57
- headers,
58
- body: JSON.stringify(batch),
59
- signal: controller.signal,
60
- });
61
- if (!response.ok) {
62
- // Build the typed AbloError for this HTTP failure (same code→class
63
- // map the throwing paths use) so the log is tagged + carries a
64
- // registry `code` (e.g. AbloAuthenticationError/session_expired on a
65
- // 401) instead of a bare status. We deliberately DON'T throw —
66
- // fire-and-forget callers would kill the Next.js router on an
67
- // unhandled rejection — and still return empty slots, but the failure
68
- // is now legible as an Ablo error. Routed through the gated logger so it
69
- // obeys ABLO_LOG_LEVEL like everything else: a consumer-register `warn`
70
- // (their models + the typed message + a wire `code`) with the forensics on
71
- // a `debug` companion. Actionable and not self-healing the read returns
72
- // empty until the underlying cause (auth, network) is resolved.
73
- let body = null;
74
- try {
75
- body = await response.clone().json();
53
+ // At most two attempts: the original request, plus one replay after a
54
+ // successful credential recovery (see `recoverCredential`). A second auth
55
+ // rejection falls through to the log-and-empty path, so a wedged credential
56
+ // can never retry-loop.
57
+ for (let attempt = 0;; attempt++) {
58
+ // Race the fetch against a timeout so hung requests don't block
59
+ // the calling helper indefinitely. Fresh controller per attempt.
60
+ const controller = new AbortController();
61
+ const timer = setTimeout(() => { controller.abort(); }, timeout);
62
+ try {
63
+ // Recomputed per attempt: `withAuthHeaders` reads the live credential
64
+ // source, so a replay after recovery carries the freshly-minted key.
65
+ const headers = withAuthHeaders(options.getAuthToken, { 'Content-Type': 'application/json' }, options.capabilityToken);
66
+ const response = await fetch(url, {
67
+ method: 'POST',
68
+ headers,
69
+ body: JSON.stringify(batch),
70
+ signal: controller.signal,
71
+ });
72
+ if (!response.ok) {
73
+ // Build the typed AbloError for this HTTP failure (the same
74
+ // code-to-class map the throwing paths use) so the log carries a
75
+ // registry `code` for example an authentication error with
76
+ // `session_expired` on a 401 rather than a bare status. This path
77
+ // deliberately does not throw, since a fire-and-forget caller could
78
+ // crash on an unhandled rejection. It returns empty slots while still
79
+ // logging a legible Ablo error.
80
+ let body = null;
81
+ try {
82
+ body = await response.clone().json();
83
+ }
84
+ catch {
85
+ // non-JSON error page — translateHttpError falls back to status text
86
+ }
87
+ const err = translateHttpError(response.status, body);
88
+ // On a 401, hand the failure to the recovery hook once. The recovery
89
+ // class routes the outcome: an expired access credential is re-minted
90
+ // and the request replays; a lost session is terminal and stops here;
91
+ // anything else stops. A bare 401 with no readable code is treated as
92
+ // an expired access credential, so the only terminal path is the
93
+ // re-mint itself coming back empty, never an ambiguous status.
94
+ if (attempt === 0 && response.status === 401 && options.recoverCredential) {
95
+ const recovery = typeof err.code === 'string'
96
+ ? classifyRecovery(err.code)
97
+ : 'access_credential_expiry';
98
+ const outcome = await options.recoverCredential(recovery);
99
+ if (outcome === 'retry') {
100
+ getContext().logger.debug('[postQuery] credential recovered — replaying query once', {
101
+ code: err.code ?? response.status,
102
+ });
103
+ continue;
104
+ }
105
+ }
106
+ // Logged through the level-gated logger, so it honors ABLO_LOG_LEVEL:
107
+ // a `warn` line the app developer can read (the models, the typed
108
+ // message, and a wire `code`), with the forensic detail on a companion
109
+ // `debug` line. The read stays empty until the underlying cause, such
110
+ // as auth or network, is resolved.
111
+ const models = batch.queries.map((q) => q.model).join(', ');
112
+ getContext().logger.warn(`Could not load ${models} — ${err.message} (code: ${err.code ?? response.status}). No results were returned.`);
113
+ getContext().logger.debug('[postQuery.error] query http failure', {
114
+ type: err.type,
115
+ code: err.code ?? response.status,
116
+ models,
117
+ message: err.message,
118
+ });
119
+ return { results: batch.queries.map(() => []) };
76
120
  }
77
- catch {
78
- // non-JSON error page — translateHttpError falls back to status text
121
+ const raw = await response.json();
122
+ const parsed = QueryBatchResultSchema.safeParse(raw);
123
+ if (!parsed.success) {
124
+ // A malformed server response isn't something the consumer can act on
125
+ // (server/protocol issue) → debug, gated like everything else.
126
+ getContext().logger.debug('[postQuery.error] malformed response', {
127
+ issues: parsed.error.issues,
128
+ });
129
+ return { results: batch.queries.map(() => []) };
79
130
  }
80
- const err = translateHttpError(response.status, body);
81
- const models = batch.queries.map((q) => q.model).join(', ');
82
- getContext().logger.warn(`Could not load ${models} — ${err.message} (code: ${err.code ?? response.status}). No results were returned.`);
83
- getContext().logger.debug('[postQuery.error] query http failure', {
84
- type: err.type,
85
- code: err.code ?? response.status,
86
- models,
87
- message: err.message,
88
- });
89
- return { results: batch.queries.map(() => []) };
131
+ return parsed.data;
90
132
  }
91
- const raw = await response.json();
92
- const parsed = QueryBatchResultSchema.safeParse(raw);
93
- if (!parsed.success) {
94
- // A malformed server response isn't something the consumer can act on
95
- // (server/protocol issue) → debug, gated like everything else.
96
- getContext().logger.debug('[postQuery.error] malformed response', {
97
- issues: parsed.error.issues,
98
- });
99
- return { results: batch.queries.map(() => []) };
133
+ finally {
134
+ clearTimeout(timer);
100
135
  }
101
- return parsed.data;
102
- }
103
- finally {
104
- clearTimeout(timer);
105
136
  }
106
137
  }
@@ -1,44 +1,25 @@
1
1
  /**
2
- * Structured query types for the generic /sync/query endpoint.
2
+ * Structured query types for the `/sync/query` endpoint.
3
3
  *
4
- * Zero-shaped ZQL-ish wire format: `where` is a flat list of `[col, op, val]`
5
- * tuples (AND'd together), and `related` is a list of schema-declared
6
- * relation names to traverse. The server compiler reads the schema's
7
- * relation metadata to turn `related: ['layers']` into the right JOIN.
4
+ * A query describes a filtered read in a compact wire format. `where` is a flat
5
+ * list of `[column, operator, value]` conditions combined with AND, and
6
+ * `related` names the schema relations to fetch alongside each row. The server
7
+ * compiles a query against your schema: it reads the model's relation metadata
8
+ * to turn `related: ['layers']` into the right join, and turns each condition
9
+ * into a WHERE fragment. The protocol carries no model-specific logic, so
10
+ * adding a model or relation is a schema change rather than a server change.
8
11
  *
9
- * # Why this shape
10
- *
11
- * An earlier revision used equality-only `where: Record<string, unknown>`
12
- * plus a PK-only `ids: string[]` batch field. That worked for simple cases
13
- * but collapsed on two real workloads:
14
- *
15
- * 1. "Fetch all layers for these slide IDs" — the IDs are foreign keys
16
- * (`SlideLayer.slideId`), not primary keys. The old `ids` field
17
- * filtered on `id`, silently returning empty.
18
- *
19
- * 2. "Fetch all layers for this deck" — needs a JOIN through
20
- * `slides.deck_id → slide_layers.slide_id`. Equality-only `where` had
21
- * no way to express it, so the Go server hardcoded a dispatch case.
22
- *
23
- * Both are generic patterns ("batch by FK column", "filter via relation")
24
- * that should be first-class in the protocol, not model-specific escape
25
- * hatches on the server. This shape matches Zero's ZQL:
26
- *
27
- * - `where('slideId', 'IN', ids)` → `['slideId', 'IN', ids]`
28
- * - `.related('layers')` → `related: ['layers']`
29
- *
30
- * The server's compiler stays schema-driven: given a model name, it reads
31
- * the schema's declared relations to emit JOIN SQL, and given a `[col, op,
32
- * val]` tuple it emits a WHERE fragment — never a switch on specific model
33
- * names. Adding a new model or relation is a schema change, not a server
34
- * change.
12
+ * The `IN` operator lets you batch a read by any column, including a foreign
13
+ * key — for example, fetching every layer whose `slideId` falls in a set of
14
+ * ids.
35
15
  */
36
16
  /** Primitive operand types allowed in a where clause. */
37
17
  export type WherePrimitive = string | number | boolean | null;
38
18
  /**
39
- * Comparison operators. Mirrors Zero's ZQL set so client authors can
40
- * lean on familiar semantics and server compilers that already target
41
- * ZQL stay portable.
19
+ * The comparison operators a {@link WhereClause} may use: equality and
20
+ * inequality, ordering, set membership (`IN` / `NOT IN`), null checks
21
+ * (`IS` / `IS NOT`), and case-sensitive or case-insensitive pattern
22
+ * matching (`LIKE`, `ILIKE`, and their negations).
42
23
  */
43
24
  export type WhereOp = '=' | '!=' | '<' | '<=' | '>' | '>=' | 'IN' | 'NOT IN' | 'IS' | 'IS NOT' | 'LIKE' | 'NOT LIKE' | 'ILIKE' | 'NOT ILIKE';
44
25
  /**
@@ -77,20 +58,17 @@ export interface Query {
77
58
  */
78
59
  model: string;
79
60
  /**
80
- * List of where clauses AND'd together. Empty or omitted means "no
81
- * filter" (still subject to server-side org scoping).
82
- *
83
- * Use `['col', 'IN', values]` to batch by any column — the old
84
- * primary-key-only `ids` field is subsumed by this form.
61
+ * The conditions to filter by, combined with AND. Empty or omitted returns
62
+ * every row the caller may see; reads are still scoped to the caller's
63
+ * organization on the server. Use `['col', 'IN', values]` to batch a read by
64
+ * any column.
85
65
  */
86
66
  where?: readonly WhereClause[];
87
67
  /**
88
- * Relation names declared in the schema for this model. The server's
89
- * compiler resolves each name via the schema's relation metadata
90
- * (`relation.hasMany` / `relation.belongsTo`) and emits the JOIN
91
- * SQL no model-specific dispatch on the server.
92
- *
93
- * Results come back as nested objects under the relation key:
68
+ * The relations to fetch with each row, named as they are declared on this
69
+ * model in the schema. The server resolves each name from the schema's
70
+ * relation metadata and joins the related rows in. They come back nested
71
+ * under the relation key:
94
72
  *
95
73
  * { __typename: 'Slide', id: '…', layers: [{ __typename: 'SlideLayer', … }] }
96
74
  */
@@ -119,25 +97,24 @@ export interface QueryBatch {
119
97
  /** Response body from POST /sync/query. */
120
98
  export interface QueryBatchResult {
121
99
  /**
122
- * Per-query results in request order. `results[i]` corresponds to
123
- * `queries[i]`. Each element is an array of rows for array-shaped
124
- * queries, or a bundled object for providers that return multiple
125
- * collections under named keys.
126
- *
127
- * Each row carries `__typename` for client-side model dispatch, plus
128
- * any `related` keys nested under the row.
100
+ * The result of each query, in request order: `results[i]` corresponds to
101
+ * `queries[i]`. Each element is an array of rows, or an object bundling
102
+ * several named row collections when the source returns more than one. Every
103
+ * row carries a `__typename` field naming its model, so callers can dispatch
104
+ * on it, along with any requested `related` rows nested under their relation
105
+ * key.
129
106
  *
130
- * Failed queries surface as empty arrays. The server logs them via
131
- * `console.error('[query.error] ...')` alert on that prefix rather
132
- * than trying to infer failure from empty results. A tagged-union
133
- * wire shape that forces caller acknowledgement is the right next
134
- * step once every `postQuery` consumer is updated at once.
107
+ * A query that fails on the server comes back as an empty array, which is
108
+ * indistinguishable from a query that simply matched nothing treat an empty
109
+ * result as "no rows", not as proof the query succeeded. The element type is
110
+ * `unknown` because one batch can mix row shapes, so narrow each result
111
+ * before use.
135
112
  */
136
113
  results: unknown[];
137
114
  /**
138
- * Server watermark observed after the batch ran. Public model reads
139
- * expose this as `stamp` and callers thread it into `commits.create({
140
- * readAt })` to reject stale writes.
115
+ * The server watermark observed after the batch ran. Model reads expose this
116
+ * as `stamp`, and callers thread it into `commits.create({ readAt })` so the
117
+ * server can reject a write built on stale data.
141
118
  */
142
119
  lastSyncId?: number;
143
120
  }
@@ -1,36 +1,16 @@
1
1
  /**
2
- * Structured query types for the generic /sync/query endpoint.
3
- *
4
- * Zero-shaped ZQL-ish wire format: `where` is a flat list of `[col, op, val]`
5
- * tuples (AND'd together), and `related` is a list of schema-declared
6
- * relation names to traverse. The server compiler reads the schema's
7
- * relation metadata to turn `related: ['layers']` into the right JOIN.
8
- *
9
- * # Why this shape
10
- *
11
- * An earlier revision used equality-only `where: Record<string, unknown>`
12
- * plus a PK-only `ids: string[]` batch field. That worked for simple cases
13
- * but collapsed on two real workloads:
14
- *
15
- * 1. "Fetch all layers for these slide IDs" — the IDs are foreign keys
16
- * (`SlideLayer.slideId`), not primary keys. The old `ids` field
17
- * filtered on `id`, silently returning empty.
18
- *
19
- * 2. "Fetch all layers for this deck" — needs a JOIN through
20
- * `slides.deck_id → slide_layers.slide_id`. Equality-only `where` had
21
- * no way to express it, so the Go server hardcoded a dispatch case.
22
- *
23
- * Both are generic patterns ("batch by FK column", "filter via relation")
24
- * that should be first-class in the protocol, not model-specific escape
25
- * hatches on the server. This shape matches Zero's ZQL:
26
- *
27
- * - `where('slideId', 'IN', ids)` → `['slideId', 'IN', ids]`
28
- * - `.related('layers')` → `related: ['layers']`
29
- *
30
- * The server's compiler stays schema-driven: given a model name, it reads
31
- * the schema's declared relations to emit JOIN SQL, and given a `[col, op,
32
- * val]` tuple it emits a WHERE fragment — never a switch on specific model
33
- * names. Adding a new model or relation is a schema change, not a server
34
- * change.
2
+ * Structured query types for the `/sync/query` endpoint.
3
+ *
4
+ * A query describes a filtered read in a compact wire format. `where` is a flat
5
+ * list of `[column, operator, value]` conditions combined with AND, and
6
+ * `related` names the schema relations to fetch alongside each row. The server
7
+ * compiles a query against your schema: it reads the model's relation metadata
8
+ * to turn `related: ['layers']` into the right join, and turns each condition
9
+ * into a WHERE fragment. The protocol carries no model-specific logic, so
10
+ * adding a model or relation is a schema change rather than a server change.
11
+ *
12
+ * The `IN` operator lets you batch a read by any column, including a foreign
13
+ * key for example, fetching every layer whose `slideId` falls in a set of
14
+ * ids.
35
15
  */
36
16
  export {};
@@ -34,13 +34,9 @@ import { type SyncStoreContract } from './context.js';
34
34
  *
35
35
  * ```tsx
36
36
  * // Build once at module scope — a new instance per render tears down the socket.
37
- * const ablo = Ablo({
38
- * schema,
39
- * apiKey: () =>
40
- * fetch('/api/ablo-session', { method: 'POST' })
41
- * .then((r) => r.json())
42
- * .then((d) => d.token),
43
- * });
37
+ * // The endpoint string points at your session-mint route (`ablo init`
38
+ * // scaffolds it); the SDK fetches it and keeps the token fresh.
39
+ * const ablo = Ablo({ schema, authEndpoint: '/api/ablo-session' });
44
40
  *
45
41
  * <AbloProvider client={ablo}>
46
42
  * <App />
@@ -152,9 +148,9 @@ export type MeshParticipantStatus = ParticipantStatus;
152
148
  export interface UseWatchReturn {
153
149
  readonly participant: EngineParticipant | null;
154
150
  /** Everyone else on the engine's sync groups (`participant.presence.others`), bridged to React. */
155
- readonly peers: ReadonlyArray<Peer>;
151
+ readonly peers: readonly Peer[];
156
152
  /** Active claim claims by peers (`participant.claims.others`), bridged to React. */
157
- readonly claims: ReadonlyArray<Claim>;
153
+ readonly claims: readonly Claim[];
158
154
  readonly status: ParticipantStatus;
159
155
  readonly error: Error | null;
160
156
  }
@@ -196,7 +192,7 @@ export declare function useWatch(opts: UseWatchOptions): UseWatchReturn;
196
192
  * const alone = !peers.some((p) => p.participantKind === 'user');
197
193
  * ```
198
194
  */
199
- export declare function usePeers(scope?: ParticipantScope): ReadonlyArray<Peer>;
195
+ export declare function usePeers(scope?: ParticipantScope): readonly Peer[];
200
196
  /**
201
197
  * Returns the raw `SyncEngine` proxy. Typically you want the typed
202
198
  * hooks (`useQuery`, `useOne`, `useMutate`) — this is for rare cases
@@ -217,7 +213,7 @@ export declare function useSync<R extends SchemaRecord = SchemaRecord>(): Ablo<R
217
213
  /**
218
214
  * Returns the underlying `SyncStoreContract` (the BaseSyncedStore).
219
215
  * Most consumers should prefer the typed hooks (`useQuery` etc.); this
220
- * is for advanced cases like direct ObjectPool access or custom
216
+ * is for advanced cases like direct InstanceCache access or custom
221
217
  * reactive bridges. Throws if the provider hasn't mounted the store
222
218
  * yet — wrap consumers in `<ClientSideSuspense>` to gate correctly.
223
219
  *
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useContext, useEffect, useMemo, useRef, useState, } from 'react';
3
+ import { useCallback, useContext, useEffect, useMemo, useRef, useState, createContext, } from 'react';
4
+ import { Ablo } from '../client/Ablo.js';
4
5
  import { createParticipantClaimId, parseParticipantTtlSeconds, resolveParticipantSyncGroups, } from '../sync/participants.js';
5
6
  import { SyncContext } from './context.js';
6
7
  import { AbloInternalContext } from './internalContext.js';
@@ -77,18 +78,24 @@ export function AbloProvider(props) {
77
78
  // It does NOT dispose the client (consumer-owned) and does NOT touch auth.
78
79
  useEffect(() => {
79
80
  let stale = false;
80
- const unsubscribeSession = engine.onSessionError(async (err) => {
81
+ const unsubscribeSession = engine.onSessionError((err) => {
81
82
  errorEmitter.emit(err);
82
- try {
83
- await engine.purge();
84
- }
85
- catch { }
86
- try {
87
- await onSessionExpiredRef.current?.();
88
- }
89
- catch (hookErr) {
90
- errorEmitter.emit(hookErr);
91
- }
83
+ void (async () => {
84
+ try {
85
+ await engine.purge();
86
+ }
87
+ catch { }
88
+ try {
89
+ await onSessionExpiredRef.current?.();
90
+ }
91
+ catch (hookErr) {
92
+ errorEmitter.emit(hookErr);
93
+ }
94
+ })().catch(() => {
95
+ // Only a throwing errorEmitter subscriber can land here — it was
96
+ // already the error-reporting path, so swallow rather than surface
97
+ // an unhandled rejection loop.
98
+ });
92
99
  });
93
100
  engine
94
101
  .ready()
@@ -122,7 +129,7 @@ export function AbloProvider(props) {
122
129
  }
123
130
  };
124
131
  window.addEventListener('beforeunload', handler);
125
- return () => window.removeEventListener('beforeunload', handler);
132
+ return () => { window.removeEventListener('beforeunload', handler); };
126
133
  }, [engine, preventUnsavedChanges]);
127
134
  // ── SyncContext value (for useQuery/useOne/useMutate hooks) ──────
128
135
  //
@@ -259,7 +266,7 @@ export function useWatch(opts) {
259
266
  // Subscribe the connection to the scope's sync groups while mounted +
260
267
  // connected — the area-of-interest navigation primitive. No claim, no
261
268
  // TTL: a viewer just receives the scope's deltas. Hysteresis (warm TTL)
262
- // lives in the store's AreaOfInterestManager, so a quick unmount/remount
269
+ // lives in the store's SubscriptionManager, so a quick unmount/remount
263
270
  // (tab flip) doesn't re-bootstrap.
264
271
  useEffect(() => {
265
272
  const scope = opts.scope;
@@ -389,7 +396,7 @@ export function usePeers(scope) {
389
396
  // rarely; a frame of stale presence is harmless (same rationale as
390
397
  // useWatch's peers bridge).
391
398
  setPeers(compute());
392
- return presence.onChange(() => setPeers(compute()));
399
+ return presence.onChange(() => { setPeers(compute()); });
393
400
  }, [engine, scopeKey]);
394
401
  return peers;
395
402
  }
@@ -424,7 +431,7 @@ export function useSync() {
424
431
  /**
425
432
  * Returns the underlying `SyncStoreContract` (the BaseSyncedStore).
426
433
  * Most consumers should prefer the typed hooks (`useQuery` etc.); this
427
- * is for advanced cases like direct ObjectPool access or custom
434
+ * is for advanced cases like direct InstanceCache access or custom
428
435
  * reactive bridges. Throws if the provider hasn't mounted the store
429
436
  * yet — wrap consumers in `<ClientSideSuspense>` to gate correctly.
430
437
  *
@@ -442,7 +449,7 @@ export function useSync() {
442
449
  */
443
450
  export function useSyncStore() {
444
451
  const sync = useContext(SyncContext);
445
- if (!sync || !sync.store) {
452
+ if (!sync?.store) {
446
453
  throw new AbloValidationError('useSyncStore: the sync engine has not yet initialized. Wrap ' +
447
454
  'consumers in <ClientSideSuspense> or guard on useSyncStatus().', { code: 'sync_not_ready' });
448
455
  }