@abloatai/ablo 0.34.0 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (483) hide show
  1. package/AGENTS.md +4 -1
  2. package/CHANGELOG.md +684 -5
  3. package/README.md +39 -22
  4. package/dist/BaseSyncedStore.d.ts +152 -44
  5. package/dist/BaseSyncedStore.js +300 -184
  6. package/dist/Database.d.ts +9 -24
  7. package/dist/Database.js +37 -22
  8. package/dist/InstanceCache.d.ts +25 -4
  9. package/dist/InstanceCache.js +48 -15
  10. package/dist/LazyReferenceCollection.d.ts +3 -3
  11. package/dist/LazyReferenceCollection.js +4 -4
  12. package/dist/Model.d.ts +6 -6
  13. package/dist/Model.js +10 -10
  14. package/dist/ModelRegistry.d.ts +4 -4
  15. package/dist/ModelRegistry.js +3 -3
  16. package/dist/{SyncEngineContext.d.ts → RuntimeContext.d.ts} +20 -13
  17. package/dist/{SyncEngineContext.js → RuntimeContext.js} +11 -12
  18. package/dist/SyncClient.d.ts +42 -32
  19. package/dist/SyncClient.js +166 -110
  20. package/dist/ai-sdk/coordinatedTool.d.ts +2 -2
  21. package/dist/ai-sdk/coordinatedTool.js +1 -1
  22. package/dist/ai-sdk/coordinationContext.d.ts +2 -2
  23. package/dist/ai-sdk/coordinationContext.js +1 -1
  24. package/dist/ai-sdk/wrap.d.ts +3 -3
  25. package/dist/ai-sdk/wrap.js +2 -2
  26. package/dist/auth/index.d.ts +1 -156
  27. package/dist/auth/index.js +8 -301
  28. package/dist/cli.cjs +3459 -1126
  29. package/dist/client/Ablo.d.ts +42 -287
  30. package/dist/client/Ablo.js +118 -963
  31. package/dist/client/abloClient.d.ts +309 -0
  32. package/dist/client/abloClient.js +13 -0
  33. package/dist/client/clientPrelude.d.ts +52 -0
  34. package/dist/client/clientPrelude.js +60 -0
  35. package/dist/client/consoleLogger.d.ts +2 -2
  36. package/dist/client/coreClient.d.ts +60 -0
  37. package/dist/client/coreClient.js +118 -0
  38. package/dist/client/createInternalComponents.d.ts +4 -4
  39. package/dist/client/createInternalComponents.js +9 -8
  40. package/dist/client/createModelProxy.d.ts +78 -373
  41. package/dist/client/createModelProxy.js +114 -86
  42. package/dist/client/humans.d.ts +48 -0
  43. package/dist/client/humans.js +52 -0
  44. package/dist/client/modelRegistration.d.ts +1 -1
  45. package/dist/client/modelRegistration.js +9 -9
  46. package/dist/client/options.d.ts +73 -17
  47. package/dist/client/reactiveEngine.d.ts +48 -0
  48. package/dist/client/reactiveEngine.js +910 -0
  49. package/dist/client/resourceTypes.d.ts +9 -250
  50. package/dist/client/resourceTypes.js +8 -5
  51. package/dist/client/schemaConfig.d.ts +4 -4
  52. package/dist/client/schemaConfig.js +6 -2
  53. package/dist/client/validateAbloOptions.d.ts +3 -2
  54. package/dist/client/validateAbloOptions.js +1 -1
  55. package/dist/client/wsMutationExecutor.d.ts +3 -3
  56. package/dist/client/wsMutationExecutor.js +3 -3
  57. package/dist/context.d.ts +9 -9
  58. package/dist/context.js +10 -9
  59. package/dist/coordination/ClaimLog.d.ts +26 -0
  60. package/dist/coordination/ClaimLog.js +32 -0
  61. package/dist/coordination/index.d.ts +1 -15
  62. package/dist/coordination/index.js +8 -31
  63. package/dist/core/DatabaseManager.js +1 -1
  64. package/dist/core/QueryView.d.ts +1 -1
  65. package/dist/core/QueryView.js +1 -1
  66. package/dist/core/StoreManager.d.ts +4 -23
  67. package/dist/core/StoreManager.js +5 -55
  68. package/dist/core/index.d.ts +2 -2
  69. package/dist/core/index.js +2 -2
  70. package/dist/core/storeContract.d.ts +2 -2
  71. package/dist/docs/catalog.d.ts +72 -0
  72. package/dist/docs/catalog.js +227 -0
  73. package/dist/docs/index.d.ts +10 -0
  74. package/dist/docs/index.js +10 -0
  75. package/dist/environment.d.ts +1 -40
  76. package/dist/environment.js +8 -37
  77. package/dist/index.d.ts +40 -34
  78. package/dist/index.js +26 -20
  79. package/dist/interfaces/index.d.ts +44 -134
  80. package/dist/keys/index.d.ts +1 -77
  81. package/dist/keys/index.js +8 -190
  82. package/dist/mutators/{RecordingTransaction.d.ts → RecordingMutation.d.ts} +4 -4
  83. package/dist/mutators/{RecordingTransaction.js → RecordingMutation.js} +2 -2
  84. package/dist/mutators/Transaction.d.ts +1 -1
  85. package/dist/mutators/Transaction.js +1 -1
  86. package/dist/mutators/UndoManager.d.ts +6 -6
  87. package/dist/mutators/UndoManager.js +5 -5
  88. package/dist/mutators/defineMutators.d.ts +3 -3
  89. package/dist/mutators/defineMutators.js +1 -1
  90. package/dist/mutators/inverseOp.js +2 -2
  91. package/dist/mutators/mutateActions.d.ts +3 -3
  92. package/dist/mutators/mutateActions.js +1 -1
  93. package/dist/mutators/readerActions.d.ts +1 -1
  94. package/dist/mutators/undoApply.d.ts +1 -1
  95. package/dist/mutators/undoApply.js +1 -1
  96. package/dist/policy/index.d.ts +2 -2
  97. package/dist/policy/index.js +1 -1
  98. package/dist/query/client.d.ts +2 -2
  99. package/dist/query/client.js +4 -4
  100. package/dist/query/types.d.ts +6 -41
  101. package/dist/query/types.js +2 -2
  102. package/dist/react/AbloProvider.d.ts +6 -8
  103. package/dist/react/AbloProvider.js +5 -7
  104. package/dist/react/context.d.ts +1 -1
  105. package/dist/react/context.js +1 -1
  106. package/dist/react/index.d.ts +5 -5
  107. package/dist/react/index.js +3 -3
  108. package/dist/react/internalContext.d.ts +1 -1
  109. package/dist/react/useAblo.d.ts +3 -3
  110. package/dist/react/useAblo.js +1 -1
  111. package/dist/react/useCurrentUserId.js +1 -1
  112. package/dist/react/useErrorListener.js +1 -1
  113. package/dist/react/useMutationFailureListener.d.ts +2 -2
  114. package/dist/react/useMutationFailureListener.js +1 -1
  115. package/dist/react/useMutators.d.ts +3 -3
  116. package/dist/react/useMutators.js +3 -3
  117. package/dist/react/useUndoScope.d.ts +5 -5
  118. package/dist/react/useUndoScope.js +1 -1
  119. package/dist/schema/coordination.d.ts +69 -10
  120. package/dist/schema/coordination.js +86 -9
  121. package/dist/schema/ddl.js +2 -2
  122. package/dist/schema/diff.d.ts +1 -1
  123. package/dist/schema/generate.js +1 -1
  124. package/dist/schema/index.d.ts +10 -10
  125. package/dist/schema/index.js +18 -18
  126. package/dist/schema/queries.d.ts +27 -27
  127. package/dist/schema/queries.js +23 -23
  128. package/dist/schema/select.d.ts +3 -3
  129. package/dist/schema/select.js +3 -3
  130. package/dist/schema/serialize.d.ts +15 -6
  131. package/dist/schema/serialize.js +17 -3
  132. package/dist/schema/sugar.d.ts +6 -7
  133. package/dist/schema/sugar.js +9 -12
  134. package/dist/schema/syncDeltaRow.d.ts +4 -152
  135. package/dist/schema/syncDeltaRow.js +4 -105
  136. package/dist/server/adapter.d.ts +18 -1
  137. package/dist/server/commit.d.ts +10 -16
  138. package/dist/server/index.d.ts +1 -1
  139. package/dist/server/index.js +1 -1
  140. package/dist/server/readConfig.d.ts +1 -1
  141. package/dist/source/adapters/drizzle.d.ts +1 -1
  142. package/dist/source/adapters/drizzle.js +2 -2
  143. package/dist/source/adapters/kysely.d.ts +1 -1
  144. package/dist/source/adapters/kysely.js +1 -1
  145. package/dist/source/adapters/kyselyMutationCore.d.ts +1 -1
  146. package/dist/source/adapters/kyselyMutationCore.js +2 -2
  147. package/dist/source/adapters/memory.js +1 -1
  148. package/dist/source/adapters/prisma.d.ts +8 -3
  149. package/dist/source/adapters/prisma.js +1 -1
  150. package/dist/source/connector.js +1 -1
  151. package/dist/source/connectorProtocol.d.ts +2 -8
  152. package/dist/source/connectorProtocol.js +3 -2
  153. package/dist/source/contract.d.ts +29 -17
  154. package/dist/source/contract.js +27 -22
  155. package/dist/source/factory.d.ts +1 -1
  156. package/dist/source/footprint.d.ts +111 -0
  157. package/dist/source/footprint.js +0 -0
  158. package/dist/source/idempotency.js +2 -2
  159. package/dist/source/index.d.ts +1 -0
  160. package/dist/source/index.js +3 -0
  161. package/dist/source/next.d.ts +1 -1
  162. package/dist/source/signing.d.ts +9 -2
  163. package/dist/source/signing.js +4 -1
  164. package/dist/source/types.d.ts +6 -4
  165. package/dist/source/types.js +1 -1
  166. package/dist/stores/ObjectStore.d.ts +1 -1
  167. package/dist/stores/SyncActionStore.d.ts +1 -1
  168. package/dist/stores/SyncActionStore.js +2 -10
  169. package/dist/stores/syncAction.d.ts +26 -0
  170. package/dist/stores/syncAction.js +16 -0
  171. package/dist/surface.d.ts +3 -3
  172. package/dist/surface.js +6 -4
  173. package/dist/sync/BootstrapFetcher.d.ts +123 -6
  174. package/dist/sync/BootstrapFetcher.js +492 -66
  175. package/dist/sync/ConnectionManager.d.ts +6 -198
  176. package/dist/sync/ConnectionManager.js +6 -677
  177. package/dist/sync/OnDemandLoader.d.ts +2 -2
  178. package/dist/sync/OnDemandLoader.js +60 -21
  179. package/dist/sync/SubscriptionManager.d.ts +13 -2
  180. package/dist/sync/SubscriptionManager.js +23 -5
  181. package/dist/sync/SyncWebSocket.d.ts +27 -510
  182. package/dist/sync/SyncWebSocket.js +76 -954
  183. package/dist/sync/awaitClaimGrant.d.ts +4 -44
  184. package/dist/sync/awaitClaimGrant.js +4 -109
  185. package/dist/sync/commitFrames.d.ts +6 -40
  186. package/dist/sync/commitFrames.js +6 -97
  187. package/dist/sync/contextPorts.d.ts +18 -0
  188. package/dist/sync/contextPorts.js +31 -0
  189. package/dist/sync/createClaimStream.d.ts +5 -49
  190. package/dist/sync/createClaimStream.js +5 -469
  191. package/dist/sync/createPresenceStream.d.ts +26 -4
  192. package/dist/sync/createPresenceStream.js +28 -20
  193. package/dist/sync/createSnapshot.d.ts +2 -2
  194. package/dist/sync/createSnapshot.js +1 -1
  195. package/dist/sync/credentialLifecycle.d.ts +5 -173
  196. package/dist/sync/credentialLifecycle.js +5 -320
  197. package/dist/sync/deltaPipeline.d.ts +1 -1
  198. package/dist/sync/participants.d.ts +5 -4
  199. package/dist/sync/participants.js +29 -22
  200. package/dist/sync/schemaDrift.d.ts +55 -0
  201. package/dist/sync/schemaDrift.js +53 -0
  202. package/dist/sync/schemas.d.ts +21 -32
  203. package/dist/sync/schemas.js +26 -17
  204. package/dist/sync/syncPlan.d.ts +3 -3
  205. package/dist/sync/wsFrameHandlers.d.ts +6 -114
  206. package/dist/sync/wsFrameHandlers.js +6 -392
  207. package/dist/testing/fixtures/bootstrap.d.ts +1 -1
  208. package/dist/testing/fixtures/deltas.d.ts +1 -1
  209. package/dist/testing/fixtures/httpResponses.d.ts +70 -0
  210. package/dist/testing/fixtures/httpResponses.js +90 -0
  211. package/dist/testing/fixtures/models.js +1 -1
  212. package/dist/testing/helpers/wait.js +1 -1
  213. package/dist/testing/mocks/MockMutationExecutor.d.ts +2 -2
  214. package/dist/testing/mocks/MockMutationExecutor.js +8 -14
  215. package/dist/testing/mocks/MockSyncContext.d.ts +11 -11
  216. package/dist/testing/mocks/MockSyncContext.js +10 -9
  217. package/dist/testing/mocks/MockSyncStore.js +1 -1
  218. package/dist/testing/mocks/MockWebSocket.d.ts +2 -2
  219. package/dist/transaction/ablo.d.ts +88 -0
  220. package/dist/transaction/ablo.js +33 -0
  221. package/dist/{client/auth.d.ts → transaction/auth/apiKey.d.ts} +43 -8
  222. package/dist/{client/auth.js → transaction/auth/apiKey.js} +19 -0
  223. package/dist/transaction/auth/bootstrapScope.d.ts +15 -0
  224. package/dist/transaction/auth/bootstrapScope.js +1 -0
  225. package/dist/transaction/auth/capability.d.ts +177 -0
  226. package/dist/transaction/auth/capability.js +199 -0
  227. package/dist/{auth → transaction/auth}/credentialSource.d.ts +8 -1
  228. package/dist/{client → transaction/auth}/identity.d.ts +8 -7
  229. package/dist/{client → transaction/auth}/identity.js +1 -1
  230. package/dist/transaction/auth/index.d.ts +162 -0
  231. package/dist/transaction/auth/index.js +304 -0
  232. package/dist/{auth → transaction/auth}/schemas.d.ts +1 -1
  233. package/dist/{auth → transaction/auth}/schemas.js +13 -13
  234. package/dist/{client → transaction/auth}/sessionMint.d.ts +8 -8
  235. package/dist/{client → transaction/auth}/sessionMint.js +4 -7
  236. package/dist/transaction/coordination/awaitClaimGrant.d.ts +49 -0
  237. package/dist/transaction/coordination/awaitClaimGrant.js +112 -0
  238. package/dist/transaction/coordination/claimMeta.d.ts +49 -0
  239. package/dist/transaction/coordination/claimMeta.js +52 -0
  240. package/dist/transaction/coordination/createClaimStream.d.ts +64 -0
  241. package/dist/transaction/coordination/createClaimStream.js +475 -0
  242. package/dist/transaction/coordination/events.d.ts +74 -0
  243. package/dist/transaction/coordination/events.js +7 -0
  244. package/dist/transaction/coordination/index.d.ts +19 -0
  245. package/dist/transaction/coordination/index.js +44 -0
  246. package/dist/transaction/coordination/locator.d.ts +83 -0
  247. package/dist/transaction/coordination/locator.js +82 -0
  248. package/dist/transaction/coordination/schema.d.ts +1473 -0
  249. package/dist/{coordination → transaction/coordination}/schema.js +490 -55
  250. package/dist/transaction/coordination/targetConflict.d.ts +2 -0
  251. package/dist/transaction/coordination/targetConflict.js +103 -0
  252. package/dist/{coordination → transaction/coordination}/trace.d.ts +7 -18
  253. package/dist/{coordination → transaction/coordination}/trace.js +18 -25
  254. package/dist/transaction/durableWrites.d.ts +62 -0
  255. package/dist/{client → transaction}/durableWrites.js +28 -3
  256. package/dist/transaction/environment.d.ts +105 -0
  257. package/dist/transaction/environment.js +108 -0
  258. package/dist/{errorCodes.d.ts → transaction/errorCodes.d.ts} +11 -11
  259. package/dist/{errorCodes.js → transaction/errorCodes.js} +35 -12
  260. package/dist/{errors.d.ts → transaction/errors.d.ts} +37 -13
  261. package/dist/{errors.js → transaction/errors.js} +85 -16
  262. package/dist/transaction/index.d.ts +20 -0
  263. package/dist/transaction/index.js +20 -0
  264. package/dist/transaction/keys/index.d.ts +87 -0
  265. package/dist/transaction/keys/index.js +207 -0
  266. package/dist/transaction/log/syncDeltaRow.d.ts +158 -0
  267. package/dist/transaction/log/syncDeltaRow.js +95 -0
  268. package/dist/{sync/syncPosition.d.ts → transaction/logPosition.d.ts} +22 -8
  269. package/dist/{sync/syncPosition.js → transaction/logPosition.js} +15 -6
  270. package/dist/transaction/logger.d.ts +16 -0
  271. package/dist/transaction/logger.js +7 -0
  272. package/dist/transaction/observability.d.ts +53 -0
  273. package/dist/transaction/observability.js +19 -0
  274. package/dist/transaction/plugin.d.ts +192 -0
  275. package/dist/transaction/plugin.js +87 -0
  276. package/dist/{policy → transaction/policy}/types.d.ts +3 -3
  277. package/dist/{policy → transaction/policy}/types.js +2 -0
  278. package/dist/transaction/resources/httpResources.d.ts +266 -0
  279. package/dist/transaction/resources/httpResources.js +7 -0
  280. package/dist/transaction/resources/modelOperations.d.ts +319 -0
  281. package/dist/transaction/resources/modelOperations.js +12 -0
  282. package/dist/transaction/resources/mutationOptions.d.ts +66 -0
  283. package/dist/transaction/resources/mutationOptions.js +9 -0
  284. package/dist/transaction/resources/where.d.ts +85 -0
  285. package/dist/transaction/resources/where.js +70 -0
  286. package/dist/{client → transaction/resources}/writeOptionsSchema.d.ts +2 -6
  287. package/dist/{client → transaction/resources}/writeOptionsSchema.js +9 -5
  288. package/dist/{schema → transaction/schema}/field.d.ts +5 -5
  289. package/dist/{schema → transaction/schema}/field.js +5 -5
  290. package/dist/transaction/schema/loadStrategy.d.ts +45 -0
  291. package/dist/transaction/schema/loadStrategy.js +46 -0
  292. package/dist/{schema → transaction/schema}/model.d.ts +50 -35
  293. package/dist/{schema → transaction/schema}/model.js +30 -20
  294. package/dist/transaction/schema/openapi.d.ts +57 -0
  295. package/dist/transaction/schema/openapi.js +340 -0
  296. package/dist/{schema → transaction/schema}/relation.d.ts +14 -14
  297. package/dist/{schema → transaction/schema}/relation.js +7 -7
  298. package/dist/{schema → transaction/schema}/residency.d.ts +0 -9
  299. package/dist/{schema → transaction/schema}/residency.js +0 -5
  300. package/dist/{schema → transaction/schema}/roles.d.ts +5 -5
  301. package/dist/{schema → transaction/schema}/roles.js +5 -5
  302. package/dist/{schema → transaction/schema}/schema.d.ts +12 -10
  303. package/dist/{schema → transaction/schema}/schema.js +4 -3
  304. package/dist/{schema → transaction/schema}/tenancy.d.ts +1 -1
  305. package/dist/{schema → transaction/schema}/tenancy.js +7 -4
  306. package/dist/transaction/transactionLayer.d.ts +82 -0
  307. package/dist/transaction/transactionLayer.js +24 -0
  308. package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.d.ts +4 -5
  309. package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.js +9 -13
  310. package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.d.ts +9 -2
  311. package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.js +5 -9
  312. package/dist/{transactions/durableWriteStore.d.ts → transaction/transactions/settlement/pendingWrite.d.ts} +10 -36
  313. package/dist/transaction/transactions/settlement/pendingWrite.js +20 -0
  314. package/dist/transaction/transport/commitFrames.d.ts +90 -0
  315. package/dist/transaction/transport/commitFrames.js +134 -0
  316. package/dist/transaction/transport/connectionManager.d.ts +215 -0
  317. package/dist/transaction/transport/connectionManager.js +673 -0
  318. package/dist/transaction/transport/credentialLifecycle.d.ts +177 -0
  319. package/dist/transaction/transport/credentialLifecycle.js +324 -0
  320. package/dist/{sync → transaction/transport}/heartbeat.d.ts +3 -1
  321. package/dist/{sync → transaction/transport}/heartbeat.js +6 -4
  322. package/dist/{client → transaction/transport}/httpClient.d.ts +59 -16
  323. package/dist/{client → transaction/transport}/httpClient.js +5 -5
  324. package/dist/transaction/transport/httpOptions.d.ts +33 -0
  325. package/dist/transaction/transport/httpOptions.js +12 -0
  326. package/dist/{client → transaction/transport}/httpTransport.js +171 -85
  327. package/dist/{sync/NetworkProbe.d.ts → transaction/transport/networkProbe.d.ts} +7 -4
  328. package/dist/{sync/NetworkProbe.js → transaction/transport/networkProbe.js} +14 -13
  329. package/dist/transaction/transport/wsFrameHandlers.d.ts +128 -0
  330. package/dist/transaction/transport/wsFrameHandlers.js +429 -0
  331. package/dist/transaction/transport/wsTransport.d.ts +576 -0
  332. package/dist/transaction/transport/wsTransport.js +1017 -0
  333. package/dist/transaction/types/assertExact.d.ts +17 -0
  334. package/dist/transaction/types/assertExact.js +1 -0
  335. package/dist/{types → transaction/types}/global.d.ts +17 -2
  336. package/dist/{types → transaction/types}/global.js +2 -1
  337. package/dist/{types → transaction/types}/index.d.ts +14 -46
  338. package/dist/{types → transaction/types}/index.js +7 -16
  339. package/dist/{types → transaction/types}/streams.d.ts +63 -45
  340. package/dist/{utils → transaction/utils}/json.d.ts +18 -0
  341. package/dist/transaction/utils/json.js +276 -0
  342. package/dist/transaction/wire/accountResponses.d.ts +351 -0
  343. package/dist/transaction/wire/accountResponses.js +255 -0
  344. package/dist/transaction/wire/auth.d.ts +49 -0
  345. package/dist/transaction/wire/auth.js +57 -0
  346. package/dist/transaction/wire/claimEvent.d.ts +76 -0
  347. package/dist/transaction/wire/claimEvent.js +73 -0
  348. package/dist/transaction/wire/claims.d.ts +463 -0
  349. package/dist/transaction/wire/claims.js +229 -0
  350. package/dist/{wire → transaction/wire}/commit.d.ts +125 -193
  351. package/dist/{wire → transaction/wire}/commit.js +68 -47
  352. package/dist/{wire → transaction/wire}/delta.d.ts +66 -17
  353. package/dist/{wire → transaction/wire}/delta.js +37 -13
  354. package/dist/transaction/wire/errorEnvelope.d.ts +72 -0
  355. package/dist/{wire → transaction/wire}/errorEnvelope.js +36 -5
  356. package/dist/transaction/wire/feedCursor.d.ts +60 -0
  357. package/dist/transaction/wire/feedCursor.js +82 -0
  358. package/dist/transaction/wire/feedEvent.d.ts +177 -0
  359. package/dist/transaction/wire/feedEvent.js +39 -0
  360. package/dist/transaction/wire/frames.d.ts +194 -0
  361. package/dist/transaction/wire/frames.js +50 -0
  362. package/dist/transaction/wire/inboundFrames.d.ts +552 -0
  363. package/dist/transaction/wire/inboundFrames.js +116 -0
  364. package/dist/transaction/wire/index.d.ts +50 -0
  365. package/dist/transaction/wire/index.js +74 -0
  366. package/dist/{wire → transaction/wire}/listEnvelope.d.ts +13 -14
  367. package/dist/transaction/wire/listEnvelope.js +42 -0
  368. package/dist/transaction/wire/modelResponses.d.ts +85 -0
  369. package/dist/transaction/wire/modelResponses.js +43 -0
  370. package/dist/transactions/{TransactionQueue.d.ts → mutations/MutationQueue.d.ts} +79 -38
  371. package/dist/transactions/{TransactionQueue.js → mutations/MutationQueue.js} +110 -59
  372. package/dist/transactions/{TransactionStore.d.ts → mutations/MutationStore.d.ts} +8 -8
  373. package/dist/transactions/{TransactionStore.js → mutations/MutationStore.js} +2 -2
  374. package/dist/transactions/{coalesceRules.d.ts → mutations/coalesceRules.d.ts} +10 -10
  375. package/dist/transactions/{coalesceRules.js → mutations/coalesceRules.js} +1 -1
  376. package/dist/transactions/mutations/commitLatency.d.ts +52 -0
  377. package/dist/transactions/mutations/commitLatency.js +130 -0
  378. package/dist/transactions/{commitOutboxStore.d.ts → mutations/commitOutboxStore.d.ts} +1 -5
  379. package/dist/transactions/{commitOutboxStore.js → mutations/commitOutboxStore.js} +1 -1
  380. package/dist/transactions/{commitPayload.d.ts → mutations/commitPayload.d.ts} +16 -15
  381. package/dist/transactions/{commitPayload.js → mutations/commitPayload.js} +12 -12
  382. package/dist/transactions/{deltaConfirmation.d.ts → mutations/deltaConfirmation.d.ts} +11 -11
  383. package/dist/transactions/{deltaConfirmation.js → mutations/deltaConfirmation.js} +7 -7
  384. package/dist/transactions/mutations/durableWriteStore.d.ts +14 -0
  385. package/dist/transactions/mutations/durableWriteStore.js +12 -0
  386. package/dist/transactions/{optimisticApply.d.ts → mutations/optimisticApply.d.ts} +7 -7
  387. package/dist/transactions/{replayValidation.d.ts → mutations/replayValidation.d.ts} +3 -3
  388. package/dist/transactions/{replayValidation.js → mutations/replayValidation.js} +4 -3
  389. package/dist/utils/mobxSetup.d.ts +1 -1
  390. package/dist/utils/mobxSetup.js +5 -2
  391. package/dist/webhooks/events.d.ts +2 -2
  392. package/dist/wire/index.d.ts +1 -34
  393. package/dist/wire/index.js +8 -49
  394. package/docs/agent-messaging.md +3 -3
  395. package/docs/agents.md +19 -12
  396. package/docs/api-keys.md +8 -4
  397. package/docs/api.md +22 -18
  398. package/docs/audit.md +2 -0
  399. package/docs/cli.md +31 -3
  400. package/docs/client-behavior.md +8 -6
  401. package/docs/concurrency-convention.md +30 -24
  402. package/docs/coordination.md +48 -38
  403. package/docs/data-sources.md +3 -1
  404. package/docs/debugging.md +5 -3
  405. package/docs/deployment.md +267 -0
  406. package/docs/examples/agent-human.md +49 -42
  407. package/docs/examples/ai-sdk-tool.md +69 -44
  408. package/docs/examples/existing-python-backend.md +8 -6
  409. package/docs/examples/nextjs.md +129 -47
  410. package/docs/examples/scoped-agent.md +45 -44
  411. package/docs/examples/server-agent.md +46 -26
  412. package/docs/groups.md +32 -29
  413. package/docs/guarantees.md +4 -2
  414. package/docs/how-it-works.md +9 -7
  415. package/docs/idempotency.md +126 -0
  416. package/docs/identity.md +58 -54
  417. package/docs/index.md +172 -84
  418. package/docs/integration-guide.md +17 -16
  419. package/docs/interaction-model.md +6 -4
  420. package/docs/mcp.md +41 -16
  421. package/docs/migration.md +63 -5
  422. package/docs/operating-on-your-database.md +111 -0
  423. package/docs/projects.md +2 -0
  424. package/docs/quickstart.md +22 -5
  425. package/docs/react.md +12 -10
  426. package/docs/schema-contract.md +5 -3
  427. package/docs/session-settings.md +108 -0
  428. package/docs/sessions.md +3 -1
  429. package/docs/webhooks.md +3 -1
  430. package/llms.txt +47 -17
  431. package/package.json +10 -8
  432. package/dist/agent/Agent.d.ts +0 -366
  433. package/dist/agent/Agent.js +0 -514
  434. package/dist/agent/index.d.ts +0 -115
  435. package/dist/agent/index.js +0 -128
  436. package/dist/agent/session.d.ts +0 -93
  437. package/dist/agent/session.js +0 -149
  438. package/dist/agent/types.d.ts +0 -68
  439. package/dist/agent/types.js +0 -9
  440. package/dist/client/durableWrites.d.ts +0 -21
  441. package/dist/coordination/schema.d.ts +0 -722
  442. package/dist/schema/openapi.d.ts +0 -29
  443. package/dist/schema/openapi.js +0 -124
  444. package/dist/transactions/durableWriteStore.js +0 -30
  445. package/dist/utils/json.js +0 -88
  446. package/dist/wire/errorEnvelope.d.ts +0 -55
  447. package/dist/wire/frames.d.ts +0 -197
  448. package/dist/wire/frames.js +0 -49
  449. package/dist/wire/listEnvelope.js +0 -18
  450. /package/dist/{client → transaction/auth}/credentialEndpoint.d.ts +0 -0
  451. /package/dist/{client → transaction/auth}/credentialEndpoint.js +0 -0
  452. /package/dist/{auth → transaction/auth}/credentialPolicy.d.ts +0 -0
  453. /package/dist/{auth → transaction/auth}/credentialPolicy.js +0 -0
  454. /package/dist/{auth → transaction/auth}/credentialSource.js +0 -0
  455. /package/dist/{client → transaction/auth}/hostedEndpoints.d.ts +0 -0
  456. /package/dist/{client → transaction/auth}/hostedEndpoints.js +0 -0
  457. /package/dist/{client → transaction/coordination}/claimHeartbeatLoop.d.ts +0 -0
  458. /package/dist/{client → transaction/coordination}/claimHeartbeatLoop.js +0 -0
  459. /package/dist/{client → transaction}/persistence.d.ts +0 -0
  460. /package/dist/{client → transaction}/persistence.js +0 -0
  461. /package/dist/{client → transaction/resources}/functionalUpdate.d.ts +0 -0
  462. /package/dist/{client → transaction/resources}/functionalUpdate.js +0 -0
  463. /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.d.ts +0 -0
  464. /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.js +0 -0
  465. /package/dist/{client → transaction/transport}/httpTransport.d.ts +0 -0
  466. /package/dist/{types → transaction/types}/modelData.d.ts +0 -0
  467. /package/dist/{types → transaction/types}/modelData.js +0 -0
  468. /package/dist/{types → transaction/types}/participant.d.ts +0 -0
  469. /package/dist/{types → transaction/types}/participant.js +0 -0
  470. /package/dist/{types → transaction/types}/streams.js +0 -0
  471. /package/dist/{utils → transaction/utils}/asyncIterator.d.ts +0 -0
  472. /package/dist/{utils → transaction/utils}/asyncIterator.js +0 -0
  473. /package/dist/{utils → transaction/utils}/duration.d.ts +0 -0
  474. /package/dist/{utils → transaction/utils}/duration.js +0 -0
  475. /package/dist/{wire → transaction/wire}/bootstrapReason.d.ts +0 -0
  476. /package/dist/{wire → transaction/wire}/bootstrapReason.js +0 -0
  477. /package/dist/{wire → transaction/wire}/protocol.d.ts +0 -0
  478. /package/dist/{wire → transaction/wire}/protocol.js +0 -0
  479. /package/dist/{wire → transaction/wire}/protocolVersion.d.ts +0 -0
  480. /package/dist/{wire → transaction/wire}/protocolVersion.js +0 -0
  481. /package/dist/transactions/{UnconfirmedWrites.d.ts → mutations/UnconfirmedWrites.d.ts} +0 -0
  482. /package/dist/transactions/{UnconfirmedWrites.js → mutations/UnconfirmedWrites.js} +0 -0
  483. /package/dist/transactions/{optimisticApply.js → mutations/optimisticApply.js} +0 -0
@@ -4,24 +4,26 @@
4
4
  * optimistic changes, holds them while the client is offline, sends them to
5
5
  * the server when connectivity returns, and resolves conflicts when the
6
6
  * server's version of a row disagrees with the local one. It sits between the
7
- * reactive object pool and the {@link TransactionQueue} that delivers writes
7
+ * reactive object pool and the {@link MutationQueue} that delivers writes
8
8
  * over the network.
9
9
  */
10
10
  import { runInAction } from 'mobx';
11
11
  import { v4 as uuid } from 'uuid';
12
12
  import { InstanceCache, ModelScope } from './InstanceCache.js';
13
13
  import { Model } from './Model.js';
14
+ import { snapshotJsonValue } from './transaction/utils/json.js';
14
15
  // ModelRegistry instance accessed via this.objectPool.registry
15
- import { LoadStrategy } from './types/index.js';
16
+ import { LoadStrategy } from './transaction/types/index.js';
16
17
  import { getContext } from './context.js';
17
- import { AbloAuthenticationError, AbloError, AbloValidationError } from './errors.js';
18
+ import { AbloAuthenticationError, AbloError, AbloValidationError } from './transaction/errors.js';
18
19
  import { EventEmitter } from 'events';
19
20
  import { NetworkMonitor } from './NetworkMonitor.js';
20
- import { TransactionQueue } from './transactions/TransactionQueue.js';
21
- import { legacyPendingMutationRecordSchema, PENDING_MUTATION_REPLAY_WINDOW_MS, pendingMutationRecordId, pendingMutationRecordSchema, persistedMutationSchema, } from './transactions/replayValidation.js';
22
- import { UnconfirmedWrites, } from './transactions/UnconfirmedWrites.js';
23
- import { SyncPosition } from './sync/syncPosition.js';
24
- import { DatabaseCommitOutboxStore, } from './transactions/commitOutboxStore.js';
21
+ import { MutationQueue } from './transactions/mutations/MutationQueue.js';
22
+ import { observeCommitLatency, } from './transactions/mutations/commitLatency.js';
23
+ import { legacyPendingMutationRecordSchema, PENDING_MUTATION_REPLAY_WINDOW_MS, pendingMutationRecordId, pendingMutationRecordSchema, persistedMutationSchema, } from './transactions/mutations/replayValidation.js';
24
+ import { UnconfirmedWrites, } from './transactions/mutations/UnconfirmedWrites.js';
25
+ import { LogPosition } from './transaction/logPosition.js';
26
+ import { DatabaseCommitOutboxStore, } from './transactions/mutations/commitOutboxStore.js';
25
27
  /**
26
28
  * Reports whether an incoming snapshot record is strictly newer than the
27
29
  * model already in the pool. The comparison uses the server-stamped
@@ -73,7 +75,7 @@ export class SyncClient extends EventEmitter {
73
75
  * @internal — test seam, stripped from the published declarations by
74
76
  * `stripInternal`. Unit suites deliver queue lifecycle events directly.
75
77
  */
76
- transactionQueue;
78
+ mutationQueue;
77
79
  observers = new Set();
78
80
  // Authentication context
79
81
  userId = null;
@@ -104,19 +106,19 @@ export class SyncClient extends EventEmitter {
104
106
  isDisposed = false;
105
107
  /**
106
108
  * The client's position in the global delta order, held as the single
107
- * canonical {@link SyncPosition} instance. The store advances `applied` and
109
+ * canonical {@link LogPosition} instance. The store advances `applied` and
108
110
  * `persisted` as deltas land, the queue advances `acked` on commit
109
111
  * responses, and snapshots and claims read `readFloor`.
110
112
  */
111
- position = new SyncPosition();
113
+ position = new LogPosition();
112
114
  constructor(objectPool, database, commitOutbox = new DatabaseCommitOutboxStore(database), commitOutboxNamespace = 'default') {
113
115
  super();
114
116
  this.objectPool = objectPool;
115
117
  this.database = database;
116
118
  this.commitOutboxNamespace = commitOutboxNamespace;
117
119
  this.networkMonitor = new NetworkMonitor();
118
- // Initialize TransactionQueue with proper configuration
119
- this.transactionQueue = new TransactionQueue({
120
+ // Initialize MutationQueue with proper configuration
121
+ this.mutationQueue = new MutationQueue({
120
122
  position: this.position,
121
123
  maxBatchSize: 50, // Larger batches keep the batch count low for bulk operations
122
124
  // A short delay keeps writes responsive; coalescing still groups them
@@ -128,8 +130,8 @@ export class SyncClient extends EventEmitter {
128
130
  strategy: 'last-write-wins',
129
131
  },
130
132
  });
131
- this.transactionQueue.setCommitOutbox(commitOutbox);
132
- this.transactionQueue.on('commit:envelope_persisted', (event) => {
133
+ this.mutationQueue.setCommitOutbox(commitOutbox);
134
+ this.mutationQueue.on('commit:envelope_persisted', (event) => {
133
135
  if (event.sourceMutationIds.length === 0)
134
136
  return;
135
137
  const consumed = new Set(event.sourceMutationIds);
@@ -140,7 +142,7 @@ export class SyncClient extends EventEmitter {
140
142
  this.scheduleSync();
141
143
  }
142
144
  });
143
- this.transactionQueue.on('transaction:completed', (transaction) => {
145
+ this.mutationQueue.on('transaction:completed', (transaction) => {
144
146
  const completed = new Set(transaction.sourceMutationIds ?? []);
145
147
  if (completed.size > 0) {
146
148
  this.pendingMutations = this.pendingMutations.filter((mutation) => !completed.has(mutation.mutationId));
@@ -155,7 +157,7 @@ export class SyncClient extends EventEmitter {
155
157
  this.scheduleSync();
156
158
  }
157
159
  });
158
- this.transactionQueue.on('transaction:failed', ({ transaction }) => {
160
+ this.mutationQueue.on('transaction:failed', ({ transaction }) => {
159
161
  const failed = transaction.sourceMutationIds ?? [];
160
162
  if (failed.length === 0)
161
163
  return;
@@ -175,8 +177,8 @@ export class SyncClient extends EventEmitter {
175
177
  this.scheduleSync();
176
178
  }
177
179
  });
178
- // Provide connection state to TransactionQueue - prevents rollbacks during disconnection
179
- this.transactionQueue.setConnectionChecker(() => this.connectionState === 'connected');
180
+ // Provide connection state to MutationQueue - prevents rollbacks during disconnection
181
+ this.mutationQueue.setConnectionChecker(() => this.connectionState === 'connected');
180
182
  // Restore object-pool state when a transaction is rolled back. If the
181
183
  // server rejects a write or it times out, the model's previous state is
182
184
  // put back. Because writes are no longer applied to IndexedDB
@@ -201,7 +203,7 @@ export class SyncClient extends EventEmitter {
201
203
  // losing a failed reconnect flush silently.
202
204
  this.networkMonitor.on('online', () => {
203
205
  void this.handleReconnection().catch((error) => {
204
- getContext().observability.captureTransactionFailure({
206
+ getContext().observability.captureMutationFailure({
205
207
  context: 'network-online-reconnection',
206
208
  error: error instanceof Error ? error : new Error(String(error)),
207
209
  });
@@ -209,7 +211,7 @@ export class SyncClient extends EventEmitter {
209
211
  });
210
212
  this.networkMonitor.on('offline', () => {
211
213
  void this.handleDisconnection().catch((error) => {
212
- getContext().observability.captureTransactionFailure({
214
+ getContext().observability.captureMutationFailure({
213
215
  context: 'network-offline-handler',
214
216
  error: error instanceof Error ? error : new Error(String(error)),
215
217
  });
@@ -233,12 +235,12 @@ export class SyncClient extends EventEmitter {
233
235
  * discard the optimistic state silently.
234
236
  *
235
237
  * Treating both paths the same caused the deletion-flicker bug: every
236
- * cancelled update on a multi-layer chart fired a per-model observer
238
+ * cancelled update on a multi-child record fired a per-model observer
237
239
  * event and a `[SyncClient.rollback]` warn, producing N renders and N
238
240
  * spam log lines for one user-initiated delete.
239
241
  */
240
242
  setupTransactionRollbackHandling() {
241
- this.transactionQueue.on('optimistic:rollback', (event) => {
243
+ this.mutationQueue.on('optimistic:rollback', (event) => {
242
244
  const { model, previousState, transaction, reason, error } = event;
243
245
  // Local cleanup path — discard quietly. The optimistic state was
244
246
  // applied to a model that's already disposed by the cascading
@@ -253,7 +255,7 @@ export class SyncClient extends EventEmitter {
253
255
  // `AbloServerError` with `httpStatus: 500`). Falling back to
254
256
  // generic message lets us still see unstructured errors.
255
257
  // Mechanic-level breadcrumb only. The authoritative, user-facing
256
- // reason is logged once at `warn` by `TransactionQueue.handleFailure`
258
+ // reason is logged once at `warn` by `MutationQueue.handleFailure`
257
259
  // (`Permanent error - rolling back`). Logging the same typed cause
258
260
  // again here at `warn` is what produced three identical dumps per
259
261
  // rejected write — keep it at `debug` so the rollback mechanics are
@@ -303,7 +305,7 @@ export class SyncClient extends EventEmitter {
303
305
  if (model.disposed) {
304
306
  // Follow-on of an already-logged permanent error, not its own
305
307
  // problem: the tx that failed has already surfaced the cause in
306
- // TransactionQueue. Restoring a disposed model is a no-op by
308
+ // MutationQueue. Restoring a disposed model is a no-op by
307
309
  // design (can't revive the private isDisposed flag), so keep this
308
310
  // at `debug` instead of emitting a second `warn` that reads as a
309
311
  // distinct failure in the console.
@@ -334,7 +336,7 @@ export class SyncClient extends EventEmitter {
334
336
  });
335
337
  }
336
338
  catch (error) {
337
- getContext().observability.captureTransactionFailure({
339
+ getContext().observability.captureMutationFailure({
338
340
  context: 'rollback-failed',
339
341
  transactionId: transaction.id,
340
342
  modelName: transaction.modelName,
@@ -345,13 +347,13 @@ export class SyncClient extends EventEmitter {
345
347
  });
346
348
  }
347
349
  /**
348
- * Forward reconciliation requests from the {@link TransactionQueue} to the
350
+ * Forward reconciliation requests from the {@link MutationQueue} to the
349
351
  * sync layer. When delta confirmation times out, the queue emits
350
352
  * `reconciliation:needed` instead of rolling back, so optimistic state the
351
353
  * server may already have committed is never destroyed.
352
354
  */
353
355
  setupReconciliationForwarding() {
354
- this.transactionQueue.on('reconciliation:needed', (event) => {
356
+ this.mutationQueue.on('reconciliation:needed', (event) => {
355
357
  getContext().observability.captureReconciliation({
356
358
  reason: event.reason,
357
359
  model: event.model,
@@ -372,12 +374,12 @@ export class SyncClient extends EventEmitter {
372
374
  * deliver the missing deltas and confirm the transaction.
373
375
  */
374
376
  setupAwaitingTransactionPersistence() {
375
- this.transactionQueue.on('transaction:persist_awaiting', (event) => {
377
+ this.mutationQueue.on('transaction:persist_awaiting', (event) => {
376
378
  // void is safe: the handler's body is fully try/catch'd.
377
379
  void this.persistAwaitingTransaction(event);
378
380
  });
379
381
  // Clean up persisted awaiting transactions when they're finally confirmed
380
- this.transactionQueue.on('transaction:completed', (tx) => {
382
+ this.mutationQueue.on('transaction:completed', (tx) => {
381
383
  // void is safe: the handler's body is fully try/catch'd.
382
384
  void this.removeAwaitingTransaction(tx.id);
383
385
  });
@@ -389,11 +391,11 @@ export class SyncClient extends EventEmitter {
389
391
  // server processes it, we drain on rollback too so a stale id
390
392
  // doesn't permanently silence a foreign delta sharing the same id
391
393
  // (vanishingly unlikely for UUIDs, but cheap insurance).
392
- this.transactionQueue.on('transaction:created', (tx) => {
394
+ this.mutationQueue.on('transaction:created', (tx) => {
393
395
  if (!tx.localOnly)
394
396
  this.echoTracker.markPending(tx.id);
395
397
  });
396
- this.transactionQueue.on('optimistic:rollback', (event) => {
398
+ this.mutationQueue.on('optimistic:rollback', (event) => {
397
399
  this.echoTracker.drainOnRollback(event.transaction.id);
398
400
  });
399
401
  }
@@ -420,7 +422,7 @@ export class SyncClient extends EventEmitter {
420
422
  });
421
423
  }
422
424
  catch (error) {
423
- getContext().observability.captureTransactionFailure({
425
+ getContext().observability.captureMutationFailure({
424
426
  context: 'persist-awaiting-transaction',
425
427
  modelName: event.model,
426
428
  modelId: event.modelId,
@@ -446,7 +448,7 @@ export class SyncClient extends EventEmitter {
446
448
  this.userId = userId;
447
449
  this.organizationId = organizationId;
448
450
  getContext().observability.setContext(userId, organizationId);
449
- this.transactionQueue.setCommitOutboxScope({
451
+ this.mutationQueue.setCommitOutboxScope({
450
452
  organizationId,
451
453
  participantId: userId,
452
454
  namespace: this.commitOutboxNamespace,
@@ -461,7 +463,7 @@ export class SyncClient extends EventEmitter {
461
463
  // Restore exact, already-sealed requests first. The returned source ids
462
464
  // suppress any legacy queue entry left behind by an older non-atomic
463
465
  // handoff.
464
- const sealedMutationIds = await this.transactionQueue.restoreDurableCommits();
466
+ const sealedMutationIds = await this.mutationQueue.restoreDurableCommits();
465
467
  await this.restoreMutationQueue(sealedMutationIds);
466
468
  // Read the initial network status from the injected OnlineStatusProvider.
467
469
  // In the browser this reflects the host's connectivity signal; in Node it
@@ -501,7 +503,7 @@ export class SyncClient extends EventEmitter {
501
503
  * 2. **Required-field gate** — if the row is missing any field listed
502
504
  * in the model's `requiredFields`, return `null` so the caller
503
505
  * skips this record. Used for FK columns whose absence renders the
504
- * row unrecoverable (e.g. a SlideLayer with no slideId).
506
+ * row unrecoverable (e.g. a Block with no sectionId).
505
507
  *
506
508
  * The engine itself is product-neutral: model identity (which fields
507
509
  * to back-fill, which absences are fatal) lives entirely in the
@@ -559,7 +561,7 @@ export class SyncClient extends EventEmitter {
559
561
  // Get model types that should be hydrated on startup (skip lazy per LSE)
560
562
  const modelTypes = this.objectPool.registry.getRegisteredModelNames().filter((name) => {
561
563
  const meta = this.objectPool.registry.getMetadata(name);
562
- return (meta?.loadStrategy === LoadStrategy.instant || meta?.loadStrategy === LoadStrategy.partial);
564
+ return meta?.loadStrategy === LoadStrategy.instant;
563
565
  });
564
566
  const totalStart = typeof performance !== 'undefined' ? performance.now() : Date.now();
565
567
  // Phase 1: Fetch all data from IndexedDB and create model instances (async I/O).
@@ -609,7 +611,7 @@ export class SyncClient extends EventEmitter {
609
611
  getContext().logger.info(`[SyncClient.hydrate] Successfully healed ${recordsToHeal.length} ${modelType} records`);
610
612
  }
611
613
  catch (err) {
612
- getContext().observability.captureTransactionFailure({
614
+ getContext().observability.captureMutationFailure({
613
615
  context: 'persist-healed-records',
614
616
  modelName: modelType,
615
617
  error: err instanceof Error ? err : new Error(String(err)),
@@ -681,7 +683,7 @@ export class SyncClient extends EventEmitter {
681
683
  // Model types to rehydrate (same filter as hydrateFromDatabase)
682
684
  const modelTypes = this.objectPool.registry.getRegisteredModelNames().filter((name) => {
683
685
  const meta = this.objectPool.registry.getMetadata(name);
684
- return (meta?.loadStrategy === LoadStrategy.instant || meta?.loadStrategy === LoadStrategy.partial);
686
+ return meta?.loadStrategy === LoadStrategy.instant;
685
687
  });
686
688
  // ── Phase 1: Read from IndexedDB & create model instances (async I/O) ──
687
689
  const allModels = [];
@@ -819,8 +821,9 @@ export class SyncClient extends EventEmitter {
819
821
  // object can reach here with `hasChanges === undefined`. `undefined === false`
820
822
  // is false → we fall through to the normal path rather than risk dropping a
821
823
  // real write. Only a genuine Model with an empty dirty-set is skipped.
822
- if (type === 'update' && model.hasChanges === false)
824
+ if (type === 'update' && model.hasChanges === false) {
823
825
  return;
826
+ }
824
827
  // Capture changes before the pool action runs. Pool operations —
825
828
  // upsert in particular — can clear the model's local changes, so
826
829
  // capturing first ensures they are never lost.
@@ -834,7 +837,7 @@ export class SyncClient extends EventEmitter {
834
837
  modelId: model.id,
835
838
  });
836
839
  // QueryProcessor uses `models:changed` to invalidate caches. Coalesce
837
- // to one event per microtask: a paste of 100 layers should re-run
840
+ // to one event per microtask: a paste of 100 rows should re-run
838
841
  // affected queries ONCE, not 100×.
839
842
  this.markModelChanged(model.getModelName());
840
843
  }
@@ -876,7 +879,7 @@ export class SyncClient extends EventEmitter {
876
879
  /**
877
880
  * Update existing model with pre-computed changes.
878
881
  * Used by saveManyOptimized when incoming models have empty change-tracking
879
- * (e.g. freshly constructed SpreadsheetCellModels from decomposeSpreadsheetDocument).
882
+ * (e.g. freshly constructed cell models from a bulk document decomposition).
880
883
  */
881
884
  updateWithChanges(model, changes) {
882
885
  getContext().logger.debug(`SyncClient.updateWithChanges`, {
@@ -903,7 +906,7 @@ export class SyncClient extends EventEmitter {
903
906
  modelId: model.id,
904
907
  });
905
908
  }
906
- /** Expose the GraphQL client for atomic mutations (e.g., createSlideWithLayers).
909
+ /** Expose the GraphQL client for atomic mutations (e.g., createSectionWithBlocks).
907
910
  * Used by SyncedStore for operations that bypass the transaction queue
908
911
  * but still need optimistic pool updates at the sync layer. */
909
912
  get gql() {
@@ -917,7 +920,7 @@ export class SyncClient extends EventEmitter {
917
920
  }
918
921
  /**
919
922
  * Clear all pending mutations for a specific model
920
- * Called before deletion to prevent "layer not found" errors on the server
923
+ * Called before deletion to prevent "record not found" errors on the server
921
924
  */
922
925
  clearPendingMutationsForModel(modelId) {
923
926
  const beforeCount = this.pendingMutations.length;
@@ -931,7 +934,7 @@ export class SyncClient extends EventEmitter {
931
934
  remainingCount: afterCount,
932
935
  });
933
936
  for (const mutation of removed) {
934
- // Once staged, TransactionQueue owns cancellation and transfers this
937
+ // Once staged, MutationQueue owns cancellation and transfers this
935
938
  // source id into the superseding delete envelope. Deleting the journal
936
939
  // row here would make that valid atomic promotion look like a
937
940
  // multi-tab loser. Truly unstaged work can be canceled locally.
@@ -946,7 +949,7 @@ export class SyncClient extends EventEmitter {
946
949
  }
947
950
  /**
948
951
  * Upload a file and create its attachment record. The upload runs through
949
- * the {@link TransactionQueue}, and a model is built from the server's
952
+ * the {@link MutationQueue}, and a model is built from the server's
950
953
  * response and added to the pool.
951
954
  */
952
955
  async uploadFile(file, options) {
@@ -956,8 +959,8 @@ export class SyncClient extends EventEmitter {
956
959
  });
957
960
  }
958
961
  try {
959
- // Use TransactionQueue to handle the upload mutation
960
- const result = await this.transactionQueue.uploadAttachment(file, {
962
+ // Use MutationQueue to handle the upload mutation
963
+ const result = await this.mutationQueue.uploadAttachment(file, {
961
964
  id: options.id,
962
965
  attachableType: options.attachableType,
963
966
  attachableId: options.attachableId,
@@ -985,7 +988,7 @@ export class SyncClient extends EventEmitter {
985
988
  return null;
986
989
  }
987
990
  catch (error) {
988
- getContext().observability.captureTransactionFailure({
991
+ getContext().observability.captureMutationFailure({
989
992
  context: 'file-upload',
990
993
  error: error instanceof Error ? error : new Error(String(error)),
991
994
  });
@@ -1015,7 +1018,7 @@ export class SyncClient extends EventEmitter {
1015
1018
  attachableId: options.attachableId,
1016
1019
  metadata: options.metadata,
1017
1020
  }));
1018
- const results = await this.transactionQueue.batchUploadAttachments(files, items, {
1021
+ const results = await this.mutationQueue.batchUploadAttachments(files, items, {
1019
1022
  userId: this.userId,
1020
1023
  organizationId: this.organizationId,
1021
1024
  });
@@ -1044,7 +1047,7 @@ export class SyncClient extends EventEmitter {
1044
1047
  * IndexedDB persistence and the server push are deferred to a microtask, so
1045
1048
  * many pushes within the same tick collapse into a single serialization and
1046
1049
  * a single process call. Without the deferral, queueing a hundred mutations
1047
- * at once — a large paste, a document import, bulk layer creation — would
1050
+ * at once — a large paste, a document import, bulk row creation — would
1048
1051
  * reserialize the whole growing queue a hundred times, an O(N²) cost in
1049
1052
  * `model.toJSON()`.
1050
1053
  *
@@ -1113,20 +1116,59 @@ export class SyncClient extends EventEmitter {
1113
1116
  return;
1114
1117
  }
1115
1118
  try {
1116
- const records = batch.map((mutation) => this.pendingMutationRecord(mutation));
1119
+ // Build each durable row independently. A malformed mutation must not
1120
+ // prevent unrelated writes from the same event-loop burst from being
1121
+ // journaled and dispatched.
1122
+ const entries = [];
1123
+ for (const mutation of batch) {
1124
+ try {
1125
+ entries.push({
1126
+ mutation,
1127
+ record: this.pendingMutationRecord(mutation),
1128
+ });
1129
+ }
1130
+ catch (error) {
1131
+ mutation.rejectJournal?.(error);
1132
+ }
1133
+ }
1134
+ if (entries.length === 0)
1135
+ return;
1117
1136
  const database = this.database;
1137
+ const saveOne = async (record) => {
1138
+ // Some adapters (including IndexedDB's put path) can throw before
1139
+ // returning a Promise. The async wrapper turns that into an individual
1140
+ // rejected outcome instead of aborting construction of the whole list.
1141
+ await database.saveTransaction(record);
1142
+ };
1143
+ let outcomes;
1118
1144
  if (database.saveTransactions) {
1119
- await database.saveTransactions(records);
1145
+ try {
1146
+ await database.saveTransactions(entries.map(({ record }) => record));
1147
+ outcomes = entries.map(() => ({
1148
+ status: 'fulfilled',
1149
+ value: undefined,
1150
+ }));
1151
+ }
1152
+ catch {
1153
+ // IndexedDB aborts a multi-row transaction when any value cannot be
1154
+ // cloned. Retry one row per transaction to identify the offender and
1155
+ // preserve every valid sibling. Re-putting a row is idempotent by id.
1156
+ outcomes = await Promise.allSettled(entries.map(({ record }) => saveOne(record)));
1157
+ }
1120
1158
  }
1121
1159
  else {
1122
- await Promise.all(records.map((record) => database.saveTransaction(record)));
1160
+ outcomes = await Promise.allSettled(entries.map(({ record }) => saveOne(record)));
1161
+ }
1162
+ for (const [index, entry] of entries.entries()) {
1163
+ const outcome = outcomes[index];
1164
+ if (outcome?.status === 'fulfilled') {
1165
+ entry.mutation.resolveJournal?.();
1166
+ }
1167
+ else {
1168
+ entry.mutation.rejectJournal?.(outcome?.reason ??
1169
+ new Error('Mutation journal persistence failed'));
1170
+ }
1123
1171
  }
1124
- for (const mutation of batch)
1125
- mutation.resolveJournal?.();
1126
- }
1127
- catch (error) {
1128
- for (const mutation of batch)
1129
- mutation.rejectJournal?.(error);
1130
1172
  }
1131
1173
  finally {
1132
1174
  for (const mutation of batch) {
@@ -1156,7 +1198,7 @@ export class SyncClient extends EventEmitter {
1156
1198
  if (!this.userId || !this.organizationId) {
1157
1199
  throw new AbloValidationError('Cannot persist a mutation before participant scope is initialized', { code: 'write_options_invalid' });
1158
1200
  }
1159
- return pendingMutationRecordSchema.parse({
1201
+ const candidate = {
1160
1202
  id: pendingMutationRecordId(mutation.mutationId),
1161
1203
  type: 'pending_mutation',
1162
1204
  storageVersion: 2,
@@ -1179,7 +1221,10 @@ export class SyncClient extends EventEmitter {
1179
1221
  namespace: this.commitOutboxNamespace,
1180
1222
  },
1181
1223
  timestamp: mutation.timestamp.getTime(),
1182
- });
1224
+ };
1225
+ // One framework-neutral boundary contract owns both Proxy unwrapping and
1226
+ // rejection of values JSON would silently corrupt before IndexedDB sees it.
1227
+ return pendingMutationRecordSchema.parse(snapshotJsonValue(candidate, '$.pendingMutation'));
1183
1228
  }
1184
1229
  async persistPendingMutation(mutation) {
1185
1230
  await this.database.saveTransaction(this.pendingMutationRecord(mutation));
@@ -1292,7 +1337,7 @@ export class SyncClient extends EventEmitter {
1292
1337
  getContext().logger.debug('[SyncClient] Failed to restore offline mutation queue', {
1293
1338
  error: error instanceof Error ? error.message : String(error),
1294
1339
  });
1295
- getContext().observability.captureTransactionFailure({
1340
+ getContext().observability.captureMutationFailure({
1296
1341
  context: 'restore-mutation-queue',
1297
1342
  error: error instanceof Error ? error : String(error),
1298
1343
  });
@@ -1303,7 +1348,7 @@ export class SyncClient extends EventEmitter {
1303
1348
  *
1304
1349
  * Best Practice: Only sync models that still exist locally (local-first principle)
1305
1350
  * - If a model was deleted locally → skip any pending updates/creates for it
1306
- * - This prevents "layer not found" errors from fast copy-paste-delete workflows
1351
+ * - This prevents "record not found" errors from fast copy-paste-delete workflows
1307
1352
  */
1308
1353
  async processPendingMutations() {
1309
1354
  if (this.pendingMutations.length === 0)
@@ -1374,7 +1419,7 @@ export class SyncClient extends EventEmitter {
1374
1419
  this.stagedMutationIds.delete(mutation.mutationId);
1375
1420
  this.pendingMutations = this.pendingMutations.filter((pending) => pending.mutationId !== mutation.mutationId);
1376
1421
  mutation.rejectStaged?.(outcome.reason);
1377
- getContext().observability.captureTransactionFailure({
1422
+ getContext().observability.captureMutationFailure({
1378
1423
  context: 'persist-pending-mutation',
1379
1424
  error: outcome.reason instanceof Error
1380
1425
  ? outcome.reason
@@ -1384,12 +1429,12 @@ export class SyncClient extends EventEmitter {
1384
1429
  // Stage every mutation synchronously within the same event-loop tick;
1385
1430
  // the transaction queue's microtask batches and sends them together.
1386
1431
  for (const mutation of journaledMutations) {
1387
- // Stage synchronously - TransactionQueue handles batching, retry, and errors
1432
+ // Stage synchronously - MutationQueue handles batching, retry, and errors
1388
1433
  this.stageMutation(mutation);
1389
1434
  }
1390
1435
  }
1391
1436
  /**
1392
- * Stage mutation to TransactionQueue - mutations in same tick are batched via microtask
1437
+ * Stage mutation to MutationQueue - mutations in same tick are batched via microtask
1393
1438
  *
1394
1439
  * @param mutation.capturedChanges - Pre-captured changes to use instead of re-reading from model
1395
1440
  */
@@ -1406,7 +1451,7 @@ export class SyncClient extends EventEmitter {
1406
1451
  // apply, store add). That means the write never entered the queue, so
1407
1452
  // capture it instead of dropping it silently.
1408
1453
  const captureStagingFailure = (error) => {
1409
- getContext().observability.captureTransactionFailure({
1454
+ getContext().observability.captureMutationFailure({
1410
1455
  context: `stage-mutation-${mutation.type}`,
1411
1456
  modelName: mutation.model.getModelName(),
1412
1457
  modelId: mutation.model.id,
@@ -1415,8 +1460,8 @@ export class SyncClient extends EventEmitter {
1415
1460
  this.stagedMutationIds.delete(mutation.mutationId);
1416
1461
  };
1417
1462
  const staging = mutation.type === 'update'
1418
- ? this.transactionQueue.update(mutation.model, ctx, mutation.capturedChanges, mutation.writeOptions, mutation.mutationId)
1419
- : this.transactionQueue[mutation.type].bind(this.transactionQueue)(mutation.model, ctx, mutation.writeOptions, mutation.mutationId);
1463
+ ? this.mutationQueue.update(mutation.model, ctx, mutation.capturedChanges, mutation.writeOptions, mutation.mutationId)
1464
+ : this.mutationQueue[mutation.type].bind(this.mutationQueue)(mutation.model, ctx, mutation.writeOptions, mutation.mutationId);
1420
1465
  staging
1421
1466
  .then(() => mutation.resolveStaged?.())
1422
1467
  .catch((error) => {
@@ -1535,7 +1580,7 @@ export class SyncClient extends EventEmitter {
1535
1580
  try {
1536
1581
  // Prefer a single batch flush for pending mutations (fast path)
1537
1582
  try {
1538
- await this.transactionQueue.flushOfflineQueue();
1583
+ await this.mutationQueue.flushOfflineQueue();
1539
1584
  }
1540
1585
  catch { }
1541
1586
  // Process all queued mutations
@@ -1544,7 +1589,7 @@ export class SyncClient extends EventEmitter {
1544
1589
  this.emit('sync:reconnected');
1545
1590
  }
1546
1591
  catch (error) {
1547
- getContext().observability.captureTransactionFailure({
1592
+ getContext().observability.captureMutationFailure({
1548
1593
  context: 'reconnection-sync',
1549
1594
  error: error instanceof Error ? error : new Error(String(error)),
1550
1595
  });
@@ -1581,11 +1626,11 @@ export class SyncClient extends EventEmitter {
1581
1626
  getContext().observability.breadcrumb(`Connection: ${oldState} → ${state}`, 'sync.websocket');
1582
1627
  if (state === 'connected') {
1583
1628
  this.emit('connection:established');
1584
- this.transactionQueue.setConnectionState('connected');
1629
+ this.mutationQueue.setConnectionState('connected');
1585
1630
  }
1586
1631
  else if (state === 'disconnected') {
1587
1632
  this.emit('connection:disconnected');
1588
- this.transactionQueue.setConnectionState('disconnected');
1633
+ this.mutationQueue.setConnectionState('disconnected');
1589
1634
  }
1590
1635
  }
1591
1636
  }
@@ -1643,8 +1688,8 @@ export class SyncClient extends EventEmitter {
1643
1688
  // Browser online state may have marked the client connected before the
1644
1689
  // WebSocket itself was ready. Always kick both durable lanes on the real
1645
1690
  // socket event, even when the high-level state did not change.
1646
- void this.transactionQueue.flushOfflineQueue().catch((error) => {
1647
- getContext().observability.captureTransactionFailure({
1691
+ void this.mutationQueue.flushOfflineQueue().catch((error) => {
1692
+ getContext().observability.captureMutationFailure({
1648
1693
  context: 'restore-commit-outbox',
1649
1694
  error: error instanceof Error ? error : new Error(String(error)),
1650
1695
  });
@@ -1663,7 +1708,7 @@ export class SyncClient extends EventEmitter {
1663
1708
  this.removeAllListeners();
1664
1709
  }
1665
1710
  /**
1666
- * Notify the {@link TransactionQueue} of an incoming delta so it can confirm
1711
+ * Notify the {@link MutationQueue} of an incoming delta so it can confirm
1667
1712
  * hosted writes by sync-id threshold and queued forwards by their echoed
1668
1713
  * source-batch correlation id.
1669
1714
  * @param syncId - The sync id of the received delta.
@@ -1672,7 +1717,7 @@ export class SyncClient extends EventEmitter {
1672
1717
  */
1673
1718
  onDeltaReceived(syncId, transactionId, correlationId) {
1674
1719
  try {
1675
- this.transactionQueue.onDeltaReceived(syncId, transactionId, correlationId);
1720
+ this.mutationQueue.onDeltaReceived(syncId, transactionId, correlationId);
1676
1721
  }
1677
1722
  catch (e) {
1678
1723
  getContext().observability.breadcrumb('Failed to notify delta received', 'sync.transaction', 'warning', {
@@ -1687,20 +1732,20 @@ export class SyncClient extends EventEmitter {
1687
1732
  * deletion. The store calls this when a delete delta arrives for a parent,
1688
1733
  * cancelling any queued writes on children that reference it.
1689
1734
  *
1690
- * @param childModelName - The child model type (for example, `SlideLayer`).
1691
- * @param foreignKey - The foreign-key property name (for example, `slideId`).
1735
+ * @param childModelName - The child model type (for example, `Block`).
1736
+ * @param foreignKey - The foreign-key property name (for example, `sectionId`).
1692
1737
  * @param parentId - The id of the deleted parent.
1693
1738
  * @returns The number of transactions cancelled.
1694
1739
  */
1695
1740
  cancelTransactionsByForeignKey(childModelName, foreignKey, parentId) {
1696
- return this.transactionQueue.cancelTransactionsByForeignKey(childModelName, foreignKey, parentId);
1741
+ return this.mutationQueue.cancelTransactionsByForeignKey(childModelName, foreignKey, parentId);
1697
1742
  }
1698
1743
  /**
1699
1744
  * Wait for a transaction to be confirmed by its delta echo. Delegates to the
1700
- * {@link TransactionQueue}, which handles the confirmation timeout.
1745
+ * {@link MutationQueue}, which handles the confirmation timeout.
1701
1746
  */
1702
1747
  waitForDeltaConfirmation(transactionId) {
1703
- return this.transactionQueue.waitForConfirmation(transactionId);
1748
+ return this.mutationQueue.waitForConfirmation(transactionId);
1704
1749
  }
1705
1750
  /**
1706
1751
  * Force sync now - process pending mutations
@@ -1728,11 +1773,11 @@ export class SyncClient extends EventEmitter {
1728
1773
  };
1729
1774
  }
1730
1775
  /**
1731
- * Get pending transaction count from TransactionQueue
1776
+ * Get pending transaction count from MutationQueue
1732
1777
  * Used by SyncedStore to compute hasUnsyncedChanges
1733
1778
  */
1734
1779
  getPendingTransactionCount() {
1735
- const stats = this.transactionQueue.getStats();
1780
+ const stats = this.mutationQueue.getStats();
1736
1781
  // Include pending and executing as "unsynced"
1737
1782
  // awaiting_delta transactions are included in 'executing' until confirmed
1738
1783
  // Completed and failed are "synced" (either done or gave up)
@@ -1744,12 +1789,12 @@ export class SyncClient extends EventEmitter {
1744
1789
  */
1745
1790
  onTransactionEvent(event, callback) {
1746
1791
  const eventName = `transaction:${event}`;
1747
- this.transactionQueue.on(eventName, callback);
1748
- return () => this.transactionQueue.off(eventName, callback);
1792
+ this.mutationQueue.on(eventName, callback);
1793
+ return () => this.mutationQueue.off(eventName, callback);
1749
1794
  }
1750
1795
  /**
1751
1796
  * Subscribe to mutation failures with the full payload. Mirrors the
1752
- * underlying TransactionQueue 'transaction:failed' shape so consumers
1797
+ * underlying MutationQueue 'transaction:failed' shape so consumers
1753
1798
  * can render typed UI (toast keyed by `AbloError.type`, route-level
1754
1799
  * "this entity reverted" boundaries, telemetry).
1755
1800
  *
@@ -1759,15 +1804,26 @@ export class SyncClient extends EventEmitter {
1759
1804
  * this typed listener drives user-visible surfaces.
1760
1805
  */
1761
1806
  onMutationFailure(listener) {
1762
- this.transactionQueue.on('transaction:failed', listener);
1763
- return () => this.transactionQueue.off('transaction:failed', listener);
1807
+ this.mutationQueue.on('transaction:failed', listener);
1808
+ return () => this.mutationQueue.off('transaction:failed', listener);
1809
+ }
1810
+ /**
1811
+ * Subscribe to commit round-trip latency, split into the local seal and the
1812
+ * remote acknowledgement. Fires once per completed commit.
1813
+ *
1814
+ * Taps the {@link MutationQueue} emitter for the same reason
1815
+ * {@link onMutationFailure} does: the commit lifecycle events originate
1816
+ * there and the SyncClient's own emitter never rebroadcasts them.
1817
+ */
1818
+ onCommitLatency(listener) {
1819
+ return observeCommitLatency(this.mutationQueue, listener);
1764
1820
  }
1765
1821
  /**
1766
- * Subscribe to local transaction creation with the full {@link Transaction}
1822
+ * Subscribe to local transaction creation with the full {@link QueuedMutation}
1767
1823
  * payload (`type`, `modelName`, `modelId`, `data`, `previousData`). This is
1768
1824
  * the feed the store's local-mutation subscription taps for undo recording.
1769
1825
  *
1770
- * It subscribes to the {@link TransactionQueue}'s emitter directly, since
1826
+ * It subscribes to the {@link MutationQueue}'s emitter directly, since
1771
1827
  * that is the only emitter that fires `transaction:created`. The SyncClient's
1772
1828
  * own emitter (reached through {@link subscribe}) never rebroadcasts that
1773
1829
  * event, so routing undo through `subscribe('transaction:created')` would
@@ -1775,7 +1831,7 @@ export class SyncClient extends EventEmitter {
1775
1831
  * reason.
1776
1832
  */
1777
1833
  onLocalTransaction(listener) {
1778
- this.transactionQueue.on('transaction:created', listener);
1834
+ this.mutationQueue.on('transaction:created', listener);
1779
1835
  const snapshotsByCommit = new Map();
1780
1836
  const onCommitStaging = (payload) => {
1781
1837
  snapshotsByCommit.set(payload.clientTxId, payload.operations.map((operation) => {
@@ -1843,14 +1899,14 @@ export class SyncClient extends EventEmitter {
1843
1899
  });
1844
1900
  });
1845
1901
  };
1846
- this.transactionQueue.on('commit:staging', onCommitStaging);
1847
- this.transactionQueue.on('commit:seal_failed', onCommitSealFailed);
1848
- this.transactionQueue.on('commit:created', onCommitCreated);
1902
+ this.mutationQueue.on('commit:staging', onCommitStaging);
1903
+ this.mutationQueue.on('commit:seal_failed', onCommitSealFailed);
1904
+ this.mutationQueue.on('commit:created', onCommitCreated);
1849
1905
  return () => {
1850
- this.transactionQueue.off('transaction:created', listener);
1851
- this.transactionQueue.off('commit:staging', onCommitStaging);
1852
- this.transactionQueue.off('commit:seal_failed', onCommitSealFailed);
1853
- this.transactionQueue.off('commit:created', onCommitCreated);
1906
+ this.mutationQueue.off('transaction:created', listener);
1907
+ this.mutationQueue.off('commit:staging', onCommitStaging);
1908
+ this.mutationQueue.off('commit:seal_failed', onCommitSealFailed);
1909
+ this.mutationQueue.off('commit:created', onCommitCreated);
1854
1910
  snapshotsByCommit.clear();
1855
1911
  };
1856
1912
  }
@@ -1858,14 +1914,14 @@ export class SyncClient extends EventEmitter {
1858
1914
  * Wait for the latest in-flight transaction for (modelName, modelId)
1859
1915
  * to be confirmed by the server, or reject if it's rolled back.
1860
1916
  * Resolves immediately when no transaction is in flight — see
1861
- * `TransactionQueue.confirmationFor` for the lookup contract.
1917
+ * `MutationQueue.confirmationFor` for the lookup contract.
1862
1918
  *
1863
1919
  * Distinct from `waitForDeltaConfirmation(transactionId)` which keys
1864
1920
  * off a known tx id; this variant is for call sites that hold a
1865
1921
  * Model reference but never see the underlying transaction.
1866
1922
  */
1867
1923
  waitForConfirmation(modelName, modelId) {
1868
- return this.transactionQueue.confirmationFor(modelName, modelId);
1924
+ return this.mutationQueue.confirmationFor(modelName, modelId);
1869
1925
  }
1870
1926
  /**
1871
1927
  * Get detailed debug info for the sync debug page
@@ -1874,7 +1930,7 @@ export class SyncClient extends EventEmitter {
1874
1930
  return {
1875
1931
  connectionState: this.connectionState,
1876
1932
  pendingMutationsCount: this.pendingMutations.length,
1877
- transactionQueue: this.transactionQueue.getDebugInfo(),
1933
+ mutationQueue: this.mutationQueue.getDebugInfo(),
1878
1934
  };
1879
1935
  }
1880
1936
  // --- Best-practice assignment ops ---
@@ -1900,7 +1956,7 @@ export class SyncClient extends EventEmitter {
1900
1956
  * Mark a local transaction as optimistically applied. The matching
1901
1957
  * server delta (when it arrives with the same `transactionId`) will
1902
1958
  * be recognized as an echo and skip the pool mutation. Called
1903
- * automatically by `TransactionQueue` when a transaction is staged;
1959
+ * automatically by `MutationQueue` when a transaction is staged;
1904
1960
  * exposed publicly so tests can drive the API directly.
1905
1961
  */
1906
1962
  markTransactionPending(transactionId) {
@@ -1916,15 +1972,15 @@ export class SyncClient extends EventEmitter {
1916
1972
  return this.echoTracker.getMetrics();
1917
1973
  }
1918
1974
  /**
1919
- * Package-internal accessor for the {@link TransactionQueue}. Used by
1975
+ * Package-internal accessor for the {@link MutationQueue}. Used by
1920
1976
  * `Ablo.commits.create()` to route raw multi-operation envelopes through the
1921
1977
  * same retry-on-reconnect lane as the model proxy path, and by tests to
1922
1978
  * exercise the queue's interaction with {@link markTransactionPending} on the
1923
1979
  * real instance the SyncClient subscribes to. It is not re-exported to SDK
1924
1980
  * consumers; `Ablo` is the public surface.
1925
1981
  */
1926
- getTransactionQueue() {
1927
- return this.transactionQueue;
1982
+ getMutationQueue() {
1983
+ return this.mutationQueue;
1928
1984
  }
1929
1985
  applyDeltaBatchToPool(dbResults, enrichRelations) {
1930
1986
  const modelsToAdd = [];
@@ -1932,8 +1988,8 @@ export class SyncClient extends EventEmitter {
1932
1988
  const idsToRemove = [];
1933
1989
  const idsToArchive = [];
1934
1990
  // Pre-pass: collect every id slated for `remove` in this batch. The
1935
- // chart-delete flicker came from this exact pattern: a peer (or the
1936
- // user themself) deletes a chart with N layers; the commit produces
1991
+ // parent-delete flicker came from this exact pattern: a peer (or the
1992
+ // user themself) deletes a parent with N children; the commit produces
1937
1993
  // BOTH residual `update` deltas (from the optimistic edits that
1938
1994
  // happened just before the delete) AND `remove` deltas. The
1939
1995
  // `update` branch below would `createFromData` the row back into
@@ -1962,7 +2018,7 @@ export class SyncClient extends EventEmitter {
1962
2018
  }
1963
2019
  // If a later op in this batch will remove this id, skip earlier
1964
2020
  // add/update ops on it. Server FK ordering can produce
1965
- // U(layer)+D(layer) when an optimistic edit and a delete both
2021
+ // U(child)+D(child) when an optimistic edit and a delete both
1966
2022
  // commit in the same window; only the final state matters.
1967
2023
  if ((action === 'add' || action === 'update') && idsBeingRemoved.has(modelId)) {
1968
2024
  continue;