@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,44 +1,40 @@
1
1
  /**
2
- * SyncCursor the sync-position state of one SyncWebSocket session.
2
+ * Holds the resume state of one WebSocket sync session: the `lastSyncId`
3
+ * watermark, which marks the highest delta the client has seen, and an opaque
4
+ * server cursor used for incremental sync. The transport carries both across
5
+ * reconnects so the session can resume where it left off.
3
6
  *
4
- * Owns the two pieces of resume state the transport carries between
5
- * connects: the `lastSyncId` watermark and the opaque server cursor.
6
- * Extracted from SyncWebSocket so cursor bookkeeping is one cohesive
7
- * leaf instead of fields + accessors spread through the transport
8
- * class. The advance DISCIPLINE (only move `lastSyncId` on a
9
- * persistence-gated ack) is documented at the call sites in
10
- * SyncWebSocket (`sendAck` / `handleDelta`).
11
- *
12
- * (The per-entity version vector that used to live here was a Go-era
13
- * ghost — zero decision reads client- or server-side; one total-ordered
14
- * log per plane makes the scalar `sync_id` watermark the causality
15
- * token. Removed in W4a.)
7
+ * The watermark advances under a strict rule it moves forward only on an
8
+ * acknowledgement that is gated on durable persistence which the transport
9
+ * enforces at its acknowledgement and delta-handling call sites.
16
10
  */
17
11
  export declare class SyncCursor {
18
12
  lastSyncId: number;
19
13
  syncCursor: string | null;
20
14
  constructor(lastSyncId: number);
21
15
  /**
22
- * Advance the local cursor for an ack this is what
23
- * `requestIncrementalSync` and the connect handshake will send next,
24
- * and what `getLastSyncId()` reports for clean-shutdown persistence.
25
- * Monotonic: a stale (lower) ack never moves the cursor backward.
16
+ * Advances the watermark in response to an acknowledgement. This becomes the
17
+ * value the next incremental-sync request and the connect handshake send, and
18
+ * the value {@link SyncCursor.getLastSyncId} reports when persisting on a
19
+ * clean shutdown. The move is monotonic: a stale, lower acknowledgement never
20
+ * pulls the watermark backward.
26
21
  */
27
22
  ackAdvance(syncId: number): void;
28
23
  /**
29
- * Update last sync ID (for persistence)
24
+ * Sets the watermark outright, used when restoring persisted state.
30
25
  */
31
26
  setLastSyncId(syncId: number): void;
32
27
  /**
33
- * Update sync cursor (for incremental sync)
28
+ * Sets the opaque server cursor used for incremental sync.
34
29
  */
35
30
  setSyncCursor(cursor: string | null): void;
36
31
  /**
37
- * Get current sync cursor
32
+ * Returns the current opaque server cursor, or null if none is set.
38
33
  */
39
34
  getSyncCursor(): string | null;
40
35
  /**
41
- * Get the highest syncId seen this session (for persistence on clean shutdown)
36
+ * Returns the highest delta id seen this session, for persistence on a clean
37
+ * shutdown.
42
38
  */
43
39
  getLastSyncId(): number;
44
40
  }
@@ -1,18 +1,12 @@
1
1
  /**
2
- * SyncCursor the sync-position state of one SyncWebSocket session.
2
+ * Holds the resume state of one WebSocket sync session: the `lastSyncId`
3
+ * watermark, which marks the highest delta the client has seen, and an opaque
4
+ * server cursor used for incremental sync. The transport carries both across
5
+ * reconnects so the session can resume where it left off.
3
6
  *
4
- * Owns the two pieces of resume state the transport carries between
5
- * connects: the `lastSyncId` watermark and the opaque server cursor.
6
- * Extracted from SyncWebSocket so cursor bookkeeping is one cohesive
7
- * leaf instead of fields + accessors spread through the transport
8
- * class. The advance DISCIPLINE (only move `lastSyncId` on a
9
- * persistence-gated ack) is documented at the call sites in
10
- * SyncWebSocket (`sendAck` / `handleDelta`).
11
- *
12
- * (The per-entity version vector that used to live here was a Go-era
13
- * ghost — zero decision reads client- or server-side; one total-ordered
14
- * log per plane makes the scalar `sync_id` watermark the causality
15
- * token. Removed in W4a.)
7
+ * The watermark advances under a strict rule it moves forward only on an
8
+ * acknowledgement that is gated on durable persistence which the transport
9
+ * enforces at its acknowledgement and delta-handling call sites.
16
10
  */
17
11
  export class SyncCursor {
18
12
  lastSyncId;
@@ -22,10 +16,11 @@ export class SyncCursor {
22
16
  this.syncCursor = null;
23
17
  }
24
18
  /**
25
- * Advance the local cursor for an ack this is what
26
- * `requestIncrementalSync` and the connect handshake will send next,
27
- * and what `getLastSyncId()` reports for clean-shutdown persistence.
28
- * Monotonic: a stale (lower) ack never moves the cursor backward.
19
+ * Advances the watermark in response to an acknowledgement. This becomes the
20
+ * value the next incremental-sync request and the connect handshake send, and
21
+ * the value {@link SyncCursor.getLastSyncId} reports when persisting on a
22
+ * clean shutdown. The move is monotonic: a stale, lower acknowledgement never
23
+ * pulls the watermark backward.
29
24
  */
30
25
  ackAdvance(syncId) {
31
26
  if (syncId > this.lastSyncId) {
@@ -33,25 +28,26 @@ export class SyncCursor {
33
28
  }
34
29
  }
35
30
  /**
36
- * Update last sync ID (for persistence)
31
+ * Sets the watermark outright, used when restoring persisted state.
37
32
  */
38
33
  setLastSyncId(syncId) {
39
34
  this.lastSyncId = syncId;
40
35
  }
41
36
  /**
42
- * Update sync cursor (for incremental sync)
37
+ * Sets the opaque server cursor used for incremental sync.
43
38
  */
44
39
  setSyncCursor(cursor) {
45
40
  this.syncCursor = cursor;
46
41
  }
47
42
  /**
48
- * Get current sync cursor
43
+ * Returns the current opaque server cursor, or null if none is set.
49
44
  */
50
45
  getSyncCursor() {
51
46
  return this.syncCursor;
52
47
  }
53
48
  /**
54
- * Get the highest syncId seen this session (for persistence on clean shutdown)
49
+ * Returns the highest delta id seen this session, for persistence on a clean
50
+ * shutdown.
55
51
  */
56
52
  getLastSyncId() {
57
53
  return this.lastSyncId || 0;
@@ -1,60 +1,52 @@
1
1
  /**
2
- * syncPlan schema sync-plan derivation.
3
- *
4
- * Pure leaf extracted from BaseSyncedStore.ts: walks a `Schema` and derives
5
- * the two declarative arrays the store's constructor consumes (FK indexes,
6
- * enrichment plan). No class state, no side effects — `BaseSyncedStore`
7
- * re-exports everything here so importers are unchanged.
2
+ * Derives a client's sync plan from its {@link Schema}. Walking the schema's
3
+ * models and relations, it produces two declarative arrays consumed when the
4
+ * store is constructed: the foreign-key indexes to register on the in-memory
5
+ * object pool, and the enrichment rules that attach related parents to
6
+ * incoming rows. See {@link deriveSyncPlanFromSchema}.
8
7
  */
9
8
  import type { Schema } from '../schema/schema.js';
10
- /** A foreign-key index to register on the ObjectPool at construction time. */
9
+ /** A foreign-key index to register on the in-memory object pool when the store is constructed. */
11
10
  export interface ForeignKeyIndexSpec {
12
11
  /**
13
- * The child model name (where the FK field lives) this is the type
14
- * that will be passed to `pool.registerForeignKey(modelName, fieldName)`
15
- * and later to `pool.getByForeignKey(modelName, fieldName, value)`.
16
- *
17
- * Use the wire `__typename` casing (e.g., `'SlideLayer'`, not
18
- * `'slideLayer'`) — that's the value `createFromData` stamps onto
19
- * models and the pool indexes by.
12
+ * The name of the child model, where the foreign-key field lives, and the
13
+ * name the object pool indexes by. Use the wire type-name casing (for
14
+ * example `'SlideLayer'`, not `'slideLayer'`), since that is the value
15
+ * stamped onto reconstructed models and the key the pool looks up.
20
16
  */
21
17
  readonly modelName: string;
22
- /** The FK field name on the child model, e.g. `'slideId'`. */
18
+ /** The foreign-key field name on the child model, for example `'slideId'`. */
23
19
  readonly fieldName: string;
24
20
  }
25
21
  /**
26
- * A declarative enrichment rule for the delta-apply path.
27
- *
28
- * When a delta for `modelName` arrives, after the model is constructed
29
- * the base store reads `data[foreignKey]` from the payload, looks up
30
- * the matching parent in the ObjectPool, and attaches it as
31
- * `data[relationKey]`. Best-effort: if the parent isn't yet in the
32
- * pool (e.g., arrived later in the same bootstrap batch), enrichment
33
- * silently no-ops.
22
+ * A declarative rule for enriching an incoming row with its related parent.
34
23
  *
35
- * Replaces the previous pattern of overriding `enrichRelations` on a
36
- * subclass to hardcode per-model enrichment logic.
24
+ * When a delta for `modelName` arrives and its row has been constructed, the
25
+ * store reads the row's `foreignKey` value, looks up the matching parent in
26
+ * the object pool, and attaches it under `relationKey`. Enrichment is
27
+ * best-effort: if the parent is not in the pool yet — for example, it arrives
28
+ * later in the same bootstrap batch — the step is skipped without error.
37
29
  */
38
30
  export interface EnrichmentPlanEntry {
39
31
  /** The child model whose incoming deltas should be enriched. */
40
32
  readonly modelName: string;
41
- /** The FK field on the child that points at the parent's id. */
33
+ /** The foreign-key field on the child that points at the parent's id. */
42
34
  readonly foreignKey: string;
43
35
  /** The property name under which to attach the parent model. */
44
36
  readonly relationKey: string;
45
37
  }
46
38
  /**
47
- * Walk a schema and derive the two sync-plan arrays consumed by
48
- * `BaseSyncedStore`'s constructor: FK indexes to register on the pool,
49
- * and the enrichment plan.
50
- *
51
- * FK indexes and enrichment entries are pulled from each `belongsTo`
52
- * relation where `options.index` / `options.enrich` is set. Relations
53
- * without those options are skipped — this is an opt-in mechanism so
54
- * adding a `belongsTo` never silently changes delta or lookup semantics.
39
+ * Walks a schema and derives the two sync-plan arrays used when the store is
40
+ * constructed: the foreign-key indexes to register on the object pool and the
41
+ * enrichment plan. See {@link ForeignKeyIndexSpec} and
42
+ * {@link EnrichmentPlanEntry}.
55
43
  *
56
- * Pure function: takes a Schema, returns two arrays. No side effects,
57
- * no class state. Called once at construction time from `BaseSyncedStore`.
44
+ * Both are drawn from each `belongsTo` relation that sets `options.index` or
45
+ * `options.enrich`; relations without those options are skipped. Enabling them
46
+ * is opt-in, so adding a `belongsTo` relation never silently changes how deltas
47
+ * apply or how lookups resolve. A `hasMany` or `hasOne` relation registers its
48
+ * index on the target model, since that is where the foreign key lives. The
49
+ * function has no side effects and is called once at construction.
58
50
  */
59
51
  export declare function deriveSyncPlanFromSchema(schema: Schema): {
60
52
  enrichmentPlan: EnrichmentPlanEntry[];
@@ -1,23 +1,22 @@
1
1
  /**
2
- * syncPlan schema sync-plan derivation.
3
- *
4
- * Pure leaf extracted from BaseSyncedStore.ts: walks a `Schema` and derives
5
- * the two declarative arrays the store's constructor consumes (FK indexes,
6
- * enrichment plan). No class state, no side effects — `BaseSyncedStore`
7
- * re-exports everything here so importers are unchanged.
2
+ * Derives a client's sync plan from its {@link Schema}. Walking the schema's
3
+ * models and relations, it produces two declarative arrays consumed when the
4
+ * store is constructed: the foreign-key indexes to register on the in-memory
5
+ * object pool, and the enrichment rules that attach related parents to
6
+ * incoming rows. See {@link deriveSyncPlanFromSchema}.
8
7
  */
9
8
  /**
10
- * Walk a schema and derive the two sync-plan arrays consumed by
11
- * `BaseSyncedStore`'s constructor: FK indexes to register on the pool,
12
- * and the enrichment plan.
13
- *
14
- * FK indexes and enrichment entries are pulled from each `belongsTo`
15
- * relation where `options.index` / `options.enrich` is set. Relations
16
- * without those options are skipped — this is an opt-in mechanism so
17
- * adding a `belongsTo` never silently changes delta or lookup semantics.
9
+ * Walks a schema and derives the two sync-plan arrays used when the store is
10
+ * constructed: the foreign-key indexes to register on the object pool and the
11
+ * enrichment plan. See {@link ForeignKeyIndexSpec} and
12
+ * {@link EnrichmentPlanEntry}.
18
13
  *
19
- * Pure function: takes a Schema, returns two arrays. No side effects,
20
- * no class state. Called once at construction time from `BaseSyncedStore`.
14
+ * Both are drawn from each `belongsTo` relation that sets `options.index` or
15
+ * `options.enrich`; relations without those options are skipped. Enabling them
16
+ * is opt-in, so adding a `belongsTo` relation never silently changes how deltas
17
+ * apply or how lookups resolve. A `hasMany` or `hasOne` relation registers its
18
+ * index on the target model, since that is where the foreign key lives. The
19
+ * function has no side effects and is called once at construction.
21
20
  */
22
21
  export function deriveSyncPlanFromSchema(schema) {
23
22
  const enrichmentPlan = [];
@@ -38,9 +37,9 @@ export function deriveSyncPlanFromSchema(schema) {
38
37
  }
39
38
  }
40
39
  else if (rel.type === 'hasMany' || rel.type === 'hasOne') {
41
- // hasMany/hasOne: the FK lives on the TARGET model, not the current model.
42
- // Register the FK index on the target so getByForeignKey works.
43
- // Target typename is resolved at registration time from the schema.
40
+ // For hasMany and hasOne, the foreign key lives on the target model,
41
+ // not the current one, so register the index on the target. Its wire
42
+ // type name is resolved from the schema here.
44
43
  const targetDef = schema.models[rel.target];
45
44
  const targetTypename = targetDef?.typename ?? rel.target;
46
45
  foreignKeyIndexes.push({ modelName: targetTypename, fieldName: rel.foreignKey });
@@ -1,40 +1,39 @@
1
1
  /**
2
- * THE sync-position structure one typed object for "where is this client
3
- * in the global delta order", replacing five scattered private counters
4
- * (`lastSeenSyncId` on the queue, `highestProcessedSyncId` + `lastAckedId`
5
- * on the store, ad-hoc acked watermarks, `max()` calls at snapshot sites).
2
+ * Records where this client stands in the global delta order. It is a single
3
+ * typed object holding three related but distinct positions, each with its own
4
+ * rule for when it may advance. Keeping them separate is deliberate: collapsing
5
+ * them into one counter is a classic source of sync bugs.
6
6
  *
7
- * Three facts with DIFFERENT advance disciplines flattening them was the
8
- * historical bug source, so the structure models them explicitly:
7
+ * - `persisted` the resume cursor. It advances only after deltas have
8
+ * committed to durable local storage. This is the value reconnect catch-up
9
+ * sends to the server, so it must never run ahead of what actually landed
10
+ * on disk; otherwise the server would skip deltas the client never stored.
9
11
  *
10
- * - `persisted` — the resume/ack cursor. Advances ONLY after deltas have
11
- * committed to IndexedDB (the Replicache "lastMutationID read in the
12
- * same transaction as the client view" rule see SyncWebSocket.sendAck).
13
- * This is what reconnect catch-up sends; it must never run ahead of
14
- * durable state or the server skips deltas that never landed.
12
+ * - `applied` — the in-memory cursor: the last delta applied to the object
13
+ * pool. It drives the guards that deduplicate and reject replayed deltas.
14
+ * It may run ahead of `persisted`, because the pool is updated before the
15
+ * flush to disk, and behind what has merely been received, because
16
+ * bootstrap-queued deltas arrive before they are applied.
15
17
  *
16
- * - `applied` — the in-memory cursor: the last delta APPLIED to the
17
- * object pool. Drives delta dedup/replay guards. May run ahead of
18
- * `persisted` (pool applies before the IDB flush) and behind receipt
19
- * (bootstrap-queued deltas are received but not yet applied).
18
+ * - `acked` — the highest server position acknowledged for this client's own
19
+ * commits. An acknowledgement at N means the server applied our write at N;
20
+ * the optimistic pool already reflects it, so for the entities we wrote we
21
+ * have effectively read through N even before the echo returns on the
22
+ * stream.
20
23
  *
21
- * - `acked` the highest server watermark ACKED to this client's OWN
22
- * commits. An ack at N means the server applied our write at N; the
23
- * optimistic pool already reflects it, so for entities we wrote we have
24
- * logically read through N even before the stream echo arrives.
24
+ * One value is derived: `readFloor` is the greater of `applied` and `acked`,
25
+ * and is the only position a snapshot or claim should stamp as its read point.
26
+ * Using the raw stream cursor alone would make a claim taken right after a
27
+ * confirmed write look stale against that write's own delta; using the raw
28
+ * acknowledgement alone would be wrong for read-only clients. The maximum is
29
+ * correct per entity, because a competing change to an entity we just wrote
30
+ * necessarily lands above our acknowledgement and still rejects as stale.
25
31
  *
26
- * One derived read: `readFloor` = max(applied, acked) the ONLY value
27
- * snapshots/claims may stamp as `readAt`. The bare stream cursor made a
28
- * claim taken right after an ack-confirmed write stale against that write's
29
- * own delta; the bare ack would be wrong for read-only clients. Per-entity
30
- * correct: a foreign change to an entity we just wrote necessarily lands
31
- * ABOVE our ack and still stale-rejects.
32
- *
33
- * The Zod schema IS the state shape — the class holds exactly one
34
- * `SyncPositionSnapshot` and applies monotonic merges to it, so
35
- * snapshot/restore are identity-shaped and the schema is the single gate
36
- * for anything loaded from disk (`parseSyncPosition`; a corrupted stored
37
- * cursor "ahead of reality" is an existing, known failure mode).
32
+ * The validation schema is the state shape: the class holds exactly one
33
+ * {@link SyncPositionSnapshot} and merges monotonically into it, so snapshot
34
+ * and restore share that shape and {@link parseSyncPosition} is the single gate
35
+ * for anything loaded from disk a corrupted cursor stored "ahead of reality"
36
+ * being a known failure mode.
38
37
  */
39
38
  import { z } from 'zod';
40
39
  export declare const syncPositionSchema: z.ZodObject<{
@@ -44,35 +43,41 @@ export declare const syncPositionSchema: z.ZodObject<{
44
43
  }, z.core.$strip>;
45
44
  export type SyncPositionSnapshot = z.infer<typeof syncPositionSchema>;
46
45
  /**
47
- * PERSISTENCE DESIGN: only the `persisted` cursor is stored durably (as
48
- * `WorkspaceMetadata.lastSyncId`, written by Database after each IDB delta
49
- * commit and gated on load through `syncPositionSchema.shape.persisted` in
50
- * `Database.requiredBootstrap`). Persisting `applied`/`acked` would be
51
- * meaningless: on resume the pool is rebuilt FROM the persisted state, so
52
- * the correct restore is exactly `advancePersisted(storedCursor)` — which
53
- * implies `applied`, while `acked` starts at 0 (a dead session's acks carry
54
- * no read authority; the offline queue re-acks its own replays).
46
+ * Only the `persisted` cursor is stored durably; `applied` and `acked` are
47
+ * not. On resume the object pool is rebuilt from the persisted state, so the
48
+ * correct restore is simply to advance `persisted` to the stored value, which
49
+ * also implies `applied`. `acked` starts at zero, because a past session's
50
+ * acknowledgements carry no read authority and the offline queue
51
+ * re-acknowledges its own replays.
52
+ */
53
+ /**
54
+ * Validates an untrusted value, such as one loaded from disk, into a position
55
+ * snapshot, or returns null when it does not match the schema.
55
56
  */
56
- /** Validate a persisted/foreign value into a position snapshot. */
57
57
  export declare function parseSyncPosition(value: unknown): SyncPositionSnapshot | null;
58
- /** The live position. One instance per client (owned by SyncClient); the
59
- * three producers advance their own fact, consumers read. */
58
+ /**
59
+ * The live sync position: one instance per client. Three producers each
60
+ * advance their own cursor, and consumers read the result.
61
+ */
60
62
  export declare class SyncPosition {
61
63
  #private;
62
- /** Current state the schema shape, frozen-by-copy. */
64
+ /** Returns a copy of the current state in the schema's shape. */
63
65
  snapshot(): SyncPositionSnapshot;
64
66
  get persisted(): number;
65
67
  get applied(): number;
66
68
  get acked(): number;
67
- /** THE value snapshots/claims stamp as `readAt`. */
69
+ /** The position a snapshot or claim stamps as its read point: the greater of `applied` and `acked`. */
68
70
  get readFloor(): number;
69
- /** Deltas through `syncId` have COMMITTED to IndexedDB. Persisting
70
- * implies applied the flush path applies before/with persisting. */
71
+ /**
72
+ * Records that deltas through `syncId` have committed to durable local
73
+ * storage. This also advances `applied`, since the flush applies each delta
74
+ * before or as it persists.
75
+ */
71
76
  advancePersisted(syncId: number): void;
72
- /** A delta was APPLIED to the in-memory pool. */
77
+ /** Records that a delta was applied to the in-memory object pool. */
73
78
  advanceApplied(syncId: number): void;
74
- /** The server acked one of OUR commits at this watermark. */
79
+ /** Records that the server acknowledged one of this client's commits at the given position. */
75
80
  noteAck(lastSyncId: number | undefined): void;
76
- /** Restore from a VALIDATED snapshot (e.g. IDB resume). Monotonic. */
81
+ /** Restores from an already-validated snapshot, for example on resume from disk. The merge is monotonic. */
77
82
  restore(snapshot: SyncPositionSnapshot): void;
78
83
  }
@@ -1,61 +1,61 @@
1
1
  /**
2
- * THE sync-position structure one typed object for "where is this client
3
- * in the global delta order", replacing five scattered private counters
4
- * (`lastSeenSyncId` on the queue, `highestProcessedSyncId` + `lastAckedId`
5
- * on the store, ad-hoc acked watermarks, `max()` calls at snapshot sites).
2
+ * Records where this client stands in the global delta order. It is a single
3
+ * typed object holding three related but distinct positions, each with its own
4
+ * rule for when it may advance. Keeping them separate is deliberate: collapsing
5
+ * them into one counter is a classic source of sync bugs.
6
6
  *
7
- * Three facts with DIFFERENT advance disciplines flattening them was the
8
- * historical bug source, so the structure models them explicitly:
7
+ * - `persisted` the resume cursor. It advances only after deltas have
8
+ * committed to durable local storage. This is the value reconnect catch-up
9
+ * sends to the server, so it must never run ahead of what actually landed
10
+ * on disk; otherwise the server would skip deltas the client never stored.
9
11
  *
10
- * - `persisted` — the resume/ack cursor. Advances ONLY after deltas have
11
- * committed to IndexedDB (the Replicache "lastMutationID read in the
12
- * same transaction as the client view" rule see SyncWebSocket.sendAck).
13
- * This is what reconnect catch-up sends; it must never run ahead of
14
- * durable state or the server skips deltas that never landed.
12
+ * - `applied` — the in-memory cursor: the last delta applied to the object
13
+ * pool. It drives the guards that deduplicate and reject replayed deltas.
14
+ * It may run ahead of `persisted`, because the pool is updated before the
15
+ * flush to disk, and behind what has merely been received, because
16
+ * bootstrap-queued deltas arrive before they are applied.
15
17
  *
16
- * - `applied` — the in-memory cursor: the last delta APPLIED to the
17
- * object pool. Drives delta dedup/replay guards. May run ahead of
18
- * `persisted` (pool applies before the IDB flush) and behind receipt
19
- * (bootstrap-queued deltas are received but not yet applied).
18
+ * - `acked` — the highest server position acknowledged for this client's own
19
+ * commits. An acknowledgement at N means the server applied our write at N;
20
+ * the optimistic pool already reflects it, so for the entities we wrote we
21
+ * have effectively read through N even before the echo returns on the
22
+ * stream.
20
23
  *
21
- * - `acked` the highest server watermark ACKED to this client's OWN
22
- * commits. An ack at N means the server applied our write at N; the
23
- * optimistic pool already reflects it, so for entities we wrote we have
24
- * logically read through N even before the stream echo arrives.
24
+ * One value is derived: `readFloor` is the greater of `applied` and `acked`,
25
+ * and is the only position a snapshot or claim should stamp as its read point.
26
+ * Using the raw stream cursor alone would make a claim taken right after a
27
+ * confirmed write look stale against that write's own delta; using the raw
28
+ * acknowledgement alone would be wrong for read-only clients. The maximum is
29
+ * correct per entity, because a competing change to an entity we just wrote
30
+ * necessarily lands above our acknowledgement and still rejects as stale.
25
31
  *
26
- * One derived read: `readFloor` = max(applied, acked) the ONLY value
27
- * snapshots/claims may stamp as `readAt`. The bare stream cursor made a
28
- * claim taken right after an ack-confirmed write stale against that write's
29
- * own delta; the bare ack would be wrong for read-only clients. Per-entity
30
- * correct: a foreign change to an entity we just wrote necessarily lands
31
- * ABOVE our ack and still stale-rejects.
32
- *
33
- * The Zod schema IS the state shape — the class holds exactly one
34
- * `SyncPositionSnapshot` and applies monotonic merges to it, so
35
- * snapshot/restore are identity-shaped and the schema is the single gate
36
- * for anything loaded from disk (`parseSyncPosition`; a corrupted stored
37
- * cursor "ahead of reality" is an existing, known failure mode).
32
+ * The validation schema is the state shape: the class holds exactly one
33
+ * {@link SyncPositionSnapshot} and merges monotonically into it, so snapshot
34
+ * and restore share that shape and {@link parseSyncPosition} is the single gate
35
+ * for anything loaded from disk a corrupted cursor stored "ahead of reality"
36
+ * being a known failure mode.
38
37
  */
39
38
  import { z } from 'zod';
40
39
  export const syncPositionSchema = z.object({
41
- /** Resume/ack cursor advances only after IDB persistence. */
40
+ /** The resume cursor; advances only after deltas persist to durable local storage. */
42
41
  persisted: z.number().int().nonnegative(),
43
- /** In-memory cursor last delta applied to the pool. */
42
+ /** The in-memory cursor: the last delta applied to the object pool. */
44
43
  applied: z.number().int().nonnegative(),
45
- /** Highest server watermark acked to this client's own commits. */
44
+ /** The highest server position acknowledged for this client's own commits. */
46
45
  acked: z.number().int().nonnegative(),
47
46
  });
48
47
  /**
49
- * PERSISTENCE DESIGN: only the `persisted` cursor is stored durably (as
50
- * `WorkspaceMetadata.lastSyncId`, written by Database after each IDB delta
51
- * commit and gated on load through `syncPositionSchema.shape.persisted` in
52
- * `Database.requiredBootstrap`). Persisting `applied`/`acked` would be
53
- * meaningless: on resume the pool is rebuilt FROM the persisted state, so
54
- * the correct restore is exactly `advancePersisted(storedCursor)` — which
55
- * implies `applied`, while `acked` starts at 0 (a dead session's acks carry
56
- * no read authority; the offline queue re-acks its own replays).
48
+ * Only the `persisted` cursor is stored durably; `applied` and `acked` are
49
+ * not. On resume the object pool is rebuilt from the persisted state, so the
50
+ * correct restore is simply to advance `persisted` to the stored value, which
51
+ * also implies `applied`. `acked` starts at zero, because a past session's
52
+ * acknowledgements carry no read authority and the offline queue
53
+ * re-acknowledges its own replays.
54
+ */
55
+ /**
56
+ * Validates an untrusted value, such as one loaded from disk, into a position
57
+ * snapshot, or returns null when it does not match the schema.
57
58
  */
58
- /** Validate a persisted/foreign value into a position snapshot. */
59
59
  export function parseSyncPosition(value) {
60
60
  const result = syncPositionSchema.safeParse(value);
61
61
  return result.success ? result.data : null;
@@ -69,11 +69,13 @@ function advance(state, next) {
69
69
  acked: Math.max(state.acked, next.acked ?? 0),
70
70
  };
71
71
  }
72
- /** The live position. One instance per client (owned by SyncClient); the
73
- * three producers advance their own fact, consumers read. */
72
+ /**
73
+ * The live sync position: one instance per client. Three producers each
74
+ * advance their own cursor, and consumers read the result.
75
+ */
74
76
  export class SyncPosition {
75
77
  #state = ZERO;
76
- /** Current state the schema shape, frozen-by-copy. */
78
+ /** Returns a copy of the current state in the schema's shape. */
77
79
  snapshot() {
78
80
  return { ...this.#state };
79
81
  }
@@ -86,25 +88,28 @@ export class SyncPosition {
86
88
  get acked() {
87
89
  return this.#state.acked;
88
90
  }
89
- /** THE value snapshots/claims stamp as `readAt`. */
91
+ /** The position a snapshot or claim stamps as its read point: the greater of `applied` and `acked`. */
90
92
  get readFloor() {
91
93
  return Math.max(this.#state.applied, this.#state.acked);
92
94
  }
93
- /** Deltas through `syncId` have COMMITTED to IndexedDB. Persisting
94
- * implies applied the flush path applies before/with persisting. */
95
+ /**
96
+ * Records that deltas through `syncId` have committed to durable local
97
+ * storage. This also advances `applied`, since the flush applies each delta
98
+ * before or as it persists.
99
+ */
95
100
  advancePersisted(syncId) {
96
101
  this.#state = advance(this.#state, { persisted: syncId, applied: syncId });
97
102
  }
98
- /** A delta was APPLIED to the in-memory pool. */
103
+ /** Records that a delta was applied to the in-memory object pool. */
99
104
  advanceApplied(syncId) {
100
105
  this.#state = advance(this.#state, { applied: syncId });
101
106
  }
102
- /** The server acked one of OUR commits at this watermark. */
107
+ /** Records that the server acknowledged one of this client's commits at the given position. */
103
108
  noteAck(lastSyncId) {
104
109
  if (lastSyncId !== undefined)
105
110
  this.#state = advance(this.#state, { acked: lastSyncId });
106
111
  }
107
- /** Restore from a VALIDATED snapshot (e.g. IDB resume). Monotonic. */
112
+ /** Restores from an already-validated snapshot, for example on resume from disk. The merge is monotonic. */
108
113
  restore(snapshot) {
109
114
  this.#state = advance(this.#state, snapshot);
110
115
  }