@abloatai/ablo 0.34.1 → 0.36.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 (536) hide show
  1. package/AGENTS.md +2 -1
  2. package/CHANGELOG.md +758 -5
  3. package/README.md +56 -502
  4. package/bin/ablo.cjs +39 -0
  5. package/dist/BaseSyncedStore.d.ts +176 -48
  6. package/dist/BaseSyncedStore.js +346 -214
  7. package/dist/Database.d.ts +17 -44
  8. package/dist/Database.js +96 -79
  9. package/dist/InstanceCache.d.ts +31 -6
  10. package/dist/InstanceCache.js +65 -30
  11. package/dist/LazyReferenceCollection.d.ts +3 -3
  12. package/dist/LazyReferenceCollection.js +4 -4
  13. package/dist/Model.d.ts +23 -13
  14. package/dist/Model.js +27 -17
  15. package/dist/ModelRegistry.d.ts +8 -4
  16. package/dist/ModelRegistry.js +20 -18
  17. package/dist/NetworkMonitor.d.ts +3 -1
  18. package/dist/NetworkMonitor.js +7 -5
  19. package/dist/{SyncEngineContext.d.ts → RuntimeContext.d.ts} +20 -13
  20. package/dist/{SyncEngineContext.js → RuntimeContext.js} +11 -12
  21. package/dist/SyncClient.d.ts +47 -47
  22. package/dist/SyncClient.js +215 -156
  23. package/dist/ai-sdk/coordinatedTool.d.ts +2 -2
  24. package/dist/ai-sdk/coordinatedTool.js +1 -1
  25. package/dist/ai-sdk/coordinationContext.d.ts +2 -2
  26. package/dist/ai-sdk/coordinationContext.js +1 -1
  27. package/dist/ai-sdk/wrap.d.ts +3 -3
  28. package/dist/ai-sdk/wrap.js +2 -2
  29. package/dist/auth/index.d.ts +1 -156
  30. package/dist/auth/index.js +8 -301
  31. package/dist/client/Ablo.d.ts +42 -287
  32. package/dist/client/Ablo.js +129 -963
  33. package/dist/client/abloClient.d.ts +309 -0
  34. package/dist/client/abloClient.js +13 -0
  35. package/dist/client/clientPrelude.d.ts +52 -0
  36. package/dist/client/clientPrelude.js +60 -0
  37. package/dist/client/consoleLogger.d.ts +2 -2
  38. package/dist/client/coreClient.d.ts +60 -0
  39. package/dist/client/coreClient.js +118 -0
  40. package/dist/client/createInternalComponents.d.ts +8 -4
  41. package/dist/client/createInternalComponents.js +17 -10
  42. package/dist/client/createModelProxy.d.ts +98 -373
  43. package/dist/client/createModelProxy.js +233 -139
  44. package/dist/client/humans.d.ts +69 -0
  45. package/dist/client/humans.js +78 -0
  46. package/dist/client/modelRegistration.d.ts +1 -1
  47. package/dist/client/modelRegistration.js +9 -9
  48. package/dist/client/options.d.ts +73 -17
  49. package/dist/client/reactiveEngine.d.ts +53 -0
  50. package/dist/client/reactiveEngine.js +688 -0
  51. package/dist/client/resourceTypes.d.ts +9 -250
  52. package/dist/client/resourceTypes.js +8 -5
  53. package/dist/client/schemaConfig.d.ts +4 -4
  54. package/dist/client/schemaConfig.js +6 -2
  55. package/dist/client/storeCluster.d.ts +47 -0
  56. package/dist/client/storeCluster.js +118 -0
  57. package/dist/client/storeLifecycle.d.ts +61 -0
  58. package/dist/client/storeLifecycle.js +231 -0
  59. package/dist/client/validateAbloOptions.d.ts +3 -2
  60. package/dist/client/validateAbloOptions.js +1 -1
  61. package/dist/client/wsMutationExecutor.d.ts +3 -3
  62. package/dist/client/wsMutationExecutor.js +3 -3
  63. package/dist/context.d.ts +22 -9
  64. package/dist/context.js +33 -9
  65. package/dist/coordination/ClaimLog.d.ts +26 -0
  66. package/dist/coordination/ClaimLog.js +32 -0
  67. package/dist/coordination/index.d.ts +1 -15
  68. package/dist/coordination/index.js +8 -31
  69. package/dist/core/index.d.ts +3 -3
  70. package/dist/core/index.js +2 -2
  71. package/dist/docs/catalog.d.ts +72 -0
  72. package/dist/docs/catalog.js +230 -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 +44 -36
  78. package/dist/index.js +30 -22
  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 +5 -2
  99. package/dist/query/client.js +10 -9
  100. package/dist/query/types.d.ts +6 -41
  101. package/dist/query/types.js +2 -2
  102. package/dist/react/AbloProvider.d.ts +18 -8
  103. package/dist/react/AbloProvider.js +10 -9
  104. package/dist/react/context.d.ts +3 -3
  105. package/dist/react/context.js +1 -1
  106. package/dist/react/createAbloReact.d.ts +56 -0
  107. package/dist/react/createAbloReact.js +51 -0
  108. package/dist/react/index.d.ts +6 -5
  109. package/dist/react/index.js +6 -3
  110. package/dist/react/internalContext.d.ts +1 -1
  111. package/dist/react/useAblo.d.ts +12 -5
  112. package/dist/react/useAblo.js +26 -8
  113. package/dist/react/useCurrentUserId.js +1 -1
  114. package/dist/react/useErrorListener.js +1 -1
  115. package/dist/react/useMutationFailureListener.d.ts +2 -2
  116. package/dist/react/useMutationFailureListener.js +1 -1
  117. package/dist/react/useMutators.d.ts +3 -3
  118. package/dist/react/useMutators.js +3 -3
  119. package/dist/react/useUndoScope.d.ts +5 -5
  120. package/dist/react/useUndoScope.js +1 -1
  121. package/dist/schema/coordination.d.ts +69 -10
  122. package/dist/schema/coordination.js +90 -9
  123. package/dist/schema/ddl.js +2 -2
  124. package/dist/schema/diff.d.ts +1 -1
  125. package/dist/schema/generate.js +1 -1
  126. package/dist/schema/index.d.ts +11 -10
  127. package/dist/schema/index.js +22 -18
  128. package/dist/schema/queries.d.ts +27 -27
  129. package/dist/schema/queries.js +23 -23
  130. package/dist/schema/select.d.ts +3 -3
  131. package/dist/schema/select.js +6 -3
  132. package/dist/schema/serialize.d.ts +15 -6
  133. package/dist/schema/serialize.js +20 -3
  134. package/dist/schema/sugar.d.ts +6 -7
  135. package/dist/schema/sugar.js +9 -12
  136. package/dist/schema/syncDeltaRow.d.ts +4 -152
  137. package/dist/schema/syncDeltaRow.js +4 -105
  138. package/dist/server/adapter.d.ts +18 -1
  139. package/dist/server/commit.d.ts +10 -16
  140. package/dist/server/index.d.ts +1 -1
  141. package/dist/server/index.js +1 -1
  142. package/dist/server/readConfig.d.ts +1 -1
  143. package/dist/source/adapter.d.ts +7 -5
  144. package/dist/source/adapter.js +7 -5
  145. package/dist/source/adapters/drizzle.d.ts +1 -1
  146. package/dist/source/adapters/drizzle.js +2 -2
  147. package/dist/source/adapters/kysely.d.ts +1 -1
  148. package/dist/source/adapters/kysely.js +1 -1
  149. package/dist/source/adapters/kyselyMutationCore.d.ts +1 -1
  150. package/dist/source/adapters/kyselyMutationCore.js +2 -2
  151. package/dist/source/adapters/memory.js +1 -1
  152. package/dist/source/adapters/prisma.d.ts +8 -3
  153. package/dist/source/adapters/prisma.js +1 -1
  154. package/dist/source/connector.js +1 -1
  155. package/dist/source/connectorProtocol.d.ts +2 -8
  156. package/dist/source/connectorProtocol.js +3 -2
  157. package/dist/source/contract.d.ts +29 -17
  158. package/dist/source/contract.js +27 -22
  159. package/dist/source/factory.d.ts +1 -1
  160. package/dist/source/idempotency.js +2 -2
  161. package/dist/source/index.d.ts +1 -0
  162. package/dist/source/index.js +3 -0
  163. package/dist/source/next.d.ts +1 -1
  164. package/dist/source/signing.d.ts +9 -2
  165. package/dist/source/signing.js +4 -1
  166. package/dist/source/types.d.ts +6 -4
  167. package/dist/source/types.js +1 -1
  168. package/dist/{core/storeContract.d.ts → storeContract.d.ts} +6 -6
  169. package/dist/{core → stores}/DatabaseManager.d.ts +3 -1
  170. package/dist/{core → stores}/DatabaseManager.js +14 -13
  171. package/dist/stores/ObjectStore.d.ts +1 -1
  172. package/dist/{core → stores}/StoreManager.d.ts +9 -26
  173. package/dist/{core → stores}/StoreManager.js +29 -77
  174. package/dist/stores/SyncActionStore.d.ts +4 -2
  175. package/dist/stores/SyncActionStore.js +11 -17
  176. package/dist/stores/syncAction.d.ts +26 -0
  177. package/dist/stores/syncAction.js +16 -0
  178. package/dist/surface.d.ts +3 -3
  179. package/dist/surface.js +6 -4
  180. package/dist/sync/BootstrapFetcher.d.ts +127 -6
  181. package/dist/sync/BootstrapFetcher.js +511 -83
  182. package/dist/sync/ConnectionManager.d.ts +6 -198
  183. package/dist/sync/ConnectionManager.js +6 -677
  184. package/dist/sync/OnDemandLoader.d.ts +5 -2
  185. package/dist/sync/OnDemandLoader.js +61 -21
  186. package/dist/sync/SubscriptionManager.d.ts +13 -2
  187. package/dist/sync/SubscriptionManager.js +23 -5
  188. package/dist/sync/SyncWebSocket.d.ts +27 -510
  189. package/dist/sync/SyncWebSocket.js +76 -954
  190. package/dist/sync/awaitClaimGrant.d.ts +4 -44
  191. package/dist/sync/awaitClaimGrant.js +4 -109
  192. package/dist/sync/bootstrapApply.d.ts +3 -0
  193. package/dist/sync/bootstrapApply.js +2 -2
  194. package/dist/sync/commitFrames.d.ts +6 -40
  195. package/dist/sync/commitFrames.js +6 -97
  196. package/dist/sync/contextPorts.d.ts +18 -0
  197. package/dist/sync/contextPorts.js +31 -0
  198. package/dist/sync/createClaimStream.d.ts +5 -49
  199. package/dist/sync/createClaimStream.js +5 -469
  200. package/dist/sync/createPresenceStream.d.ts +26 -4
  201. package/dist/sync/createPresenceStream.js +28 -20
  202. package/dist/sync/createSnapshot.d.ts +2 -2
  203. package/dist/sync/createSnapshot.js +1 -1
  204. package/dist/sync/credentialLifecycle.d.ts +5 -173
  205. package/dist/sync/credentialLifecycle.js +5 -320
  206. package/dist/sync/deltaPipeline.d.ts +13 -12
  207. package/dist/sync/deltaPipeline.js +21 -4
  208. package/dist/sync/groupChange.d.ts +3 -0
  209. package/dist/sync/groupChange.js +16 -14
  210. package/dist/sync/participants.d.ts +24 -6
  211. package/dist/sync/participants.js +32 -23
  212. package/dist/sync/schemaDrift.d.ts +55 -0
  213. package/dist/sync/schemaDrift.js +53 -0
  214. package/dist/sync/schemas.d.ts +23 -33
  215. package/dist/sync/schemas.js +29 -20
  216. package/dist/sync/syncPlan.d.ts +3 -3
  217. package/dist/sync/wsFrameHandlers.d.ts +6 -114
  218. package/dist/sync/wsFrameHandlers.js +6 -392
  219. package/dist/syncLog/contract.d.ts +20 -0
  220. package/dist/syncLog/contract.js +19 -0
  221. package/dist/syncLog/index.d.ts +1 -0
  222. package/dist/syncLog/index.js +1 -0
  223. package/dist/transaction/ablo.d.ts +88 -0
  224. package/dist/transaction/ablo.js +33 -0
  225. package/dist/{client/auth.d.ts → transaction/auth/apiKey.d.ts} +43 -8
  226. package/dist/{client/auth.js → transaction/auth/apiKey.js} +19 -0
  227. package/dist/transaction/auth/bootstrapScope.d.ts +15 -0
  228. package/dist/transaction/auth/bootstrapScope.js +1 -0
  229. package/dist/transaction/auth/capability.d.ts +212 -0
  230. package/dist/transaction/auth/capability.js +224 -0
  231. package/dist/{auth → transaction/auth}/credentialSource.d.ts +8 -1
  232. package/dist/{client → transaction/auth}/identity.d.ts +8 -7
  233. package/dist/{client → transaction/auth}/identity.js +1 -1
  234. package/dist/transaction/auth/index.d.ts +162 -0
  235. package/dist/transaction/auth/index.js +304 -0
  236. package/dist/{auth → transaction/auth}/schemas.d.ts +1 -1
  237. package/dist/{auth → transaction/auth}/schemas.js +13 -13
  238. package/dist/{client → transaction/auth}/sessionMint.d.ts +8 -8
  239. package/dist/{client → transaction/auth}/sessionMint.js +4 -7
  240. package/dist/transaction/coordination/awaitClaimGrant.d.ts +56 -0
  241. package/dist/transaction/coordination/awaitClaimGrant.js +124 -0
  242. package/dist/{client → transaction/coordination}/claimHeartbeatLoop.d.ts +34 -0
  243. package/dist/{client → transaction/coordination}/claimHeartbeatLoop.js +20 -0
  244. package/dist/transaction/coordination/claimMeta.d.ts +49 -0
  245. package/dist/transaction/coordination/claimMeta.js +52 -0
  246. package/dist/transaction/coordination/createClaimStream.d.ts +64 -0
  247. package/dist/transaction/coordination/createClaimStream.js +475 -0
  248. package/dist/transaction/coordination/events.d.ts +74 -0
  249. package/dist/transaction/coordination/events.js +7 -0
  250. package/dist/transaction/coordination/index.d.ts +19 -0
  251. package/dist/transaction/coordination/index.js +45 -0
  252. package/dist/transaction/coordination/locator.d.ts +104 -0
  253. package/dist/transaction/coordination/locator.js +102 -0
  254. package/dist/transaction/coordination/schema.d.ts +1536 -0
  255. package/dist/transaction/coordination/schema.js +1177 -0
  256. package/dist/transaction/coordination/targetConflict.d.ts +2 -0
  257. package/dist/transaction/coordination/targetConflict.js +107 -0
  258. package/dist/{coordination → transaction/coordination}/trace.d.ts +7 -18
  259. package/dist/{coordination → transaction/coordination}/trace.js +18 -25
  260. package/dist/transaction/durableWrites.d.ts +62 -0
  261. package/dist/{client → transaction}/durableWrites.js +28 -3
  262. package/dist/transaction/environment.d.ts +105 -0
  263. package/dist/transaction/environment.js +108 -0
  264. package/dist/{errorCodes.d.ts → transaction/errorCodes.d.ts} +12 -12
  265. package/dist/{errorCodes.js → transaction/errorCodes.js} +45 -18
  266. package/dist/{errors.d.ts → transaction/errors.d.ts} +37 -13
  267. package/dist/{errors.js → transaction/errors.js} +85 -16
  268. package/dist/transaction/footprint.d.ts +111 -0
  269. package/dist/transaction/footprint.js +0 -0
  270. package/dist/transaction/index.d.ts +20 -0
  271. package/dist/transaction/index.js +20 -0
  272. package/dist/transaction/keys/index.d.ts +87 -0
  273. package/dist/transaction/keys/index.js +207 -0
  274. package/dist/transaction/log/syncDeltaRow.d.ts +158 -0
  275. package/dist/transaction/log/syncDeltaRow.js +95 -0
  276. package/dist/{sync/syncPosition.d.ts → transaction/logPosition.d.ts} +22 -8
  277. package/dist/{sync/syncPosition.js → transaction/logPosition.js} +15 -6
  278. package/dist/transaction/logger.d.ts +16 -0
  279. package/dist/transaction/logger.js +7 -0
  280. package/dist/transaction/observability.d.ts +53 -0
  281. package/dist/transaction/observability.js +19 -0
  282. package/dist/transaction/plugin.d.ts +285 -0
  283. package/dist/transaction/plugin.js +106 -0
  284. package/dist/{policy → transaction/policy}/types.d.ts +3 -3
  285. package/dist/{policy → transaction/policy}/types.js +2 -0
  286. package/dist/transaction/resources/httpResources.d.ts +321 -0
  287. package/dist/transaction/resources/httpResources.js +7 -0
  288. package/dist/transaction/resources/modelOperations.d.ts +427 -0
  289. package/dist/transaction/resources/modelOperations.js +12 -0
  290. package/dist/transaction/resources/mutationOptions.d.ts +66 -0
  291. package/dist/transaction/resources/mutationOptions.js +9 -0
  292. package/dist/transaction/resources/where.d.ts +101 -0
  293. package/dist/transaction/resources/where.js +115 -0
  294. package/dist/{client → transaction/resources}/writeOptionsSchema.d.ts +2 -6
  295. package/dist/{client → transaction/resources}/writeOptionsSchema.js +9 -5
  296. package/dist/{schema → transaction/schema}/field.d.ts +17 -23
  297. package/dist/{schema → transaction/schema}/field.js +5 -5
  298. package/dist/transaction/schema/fieldRef.d.ts +38 -0
  299. package/dist/transaction/schema/fieldRef.js +11 -0
  300. package/dist/transaction/schema/loadStrategy.d.ts +45 -0
  301. package/dist/transaction/schema/loadStrategy.js +46 -0
  302. package/dist/{schema → transaction/schema}/model.d.ts +50 -35
  303. package/dist/{schema → transaction/schema}/model.js +30 -20
  304. package/dist/transaction/schema/openapi.d.ts +58 -0
  305. package/dist/transaction/schema/openapi.js +501 -0
  306. package/dist/{schema → transaction/schema}/relation.d.ts +21 -16
  307. package/dist/{schema → transaction/schema}/relation.js +7 -7
  308. package/dist/{schema → transaction/schema}/residency.d.ts +0 -9
  309. package/dist/{schema → transaction/schema}/residency.js +0 -5
  310. package/dist/{schema → transaction/schema}/roles.d.ts +5 -5
  311. package/dist/{schema → transaction/schema}/roles.js +5 -5
  312. package/dist/{schema → transaction/schema}/schema.d.ts +39 -10
  313. package/dist/{schema → transaction/schema}/schema.js +24 -3
  314. package/dist/{schema → transaction/schema}/tenancy.d.ts +1 -1
  315. package/dist/{schema → transaction/schema}/tenancy.js +7 -4
  316. package/dist/transaction/transactionLayer.d.ts +82 -0
  317. package/dist/transaction/transactionLayer.js +24 -0
  318. package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.d.ts +5 -6
  319. package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.js +9 -13
  320. package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.d.ts +9 -2
  321. package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.js +5 -9
  322. package/dist/{transactions/durableWriteStore.d.ts → transaction/transactions/settlement/pendingWrite.d.ts} +11 -37
  323. package/dist/transaction/transactions/settlement/pendingWrite.js +20 -0
  324. package/dist/transaction/transport/commitFrames.d.ts +90 -0
  325. package/dist/transaction/transport/commitFrames.js +134 -0
  326. package/dist/transaction/transport/connectionManager.d.ts +215 -0
  327. package/dist/transaction/transport/connectionManager.js +673 -0
  328. package/dist/transaction/transport/credentialLifecycle.d.ts +177 -0
  329. package/dist/transaction/transport/credentialLifecycle.js +324 -0
  330. package/dist/{sync → transaction/transport}/heartbeat.d.ts +3 -1
  331. package/dist/{sync → transaction/transport}/heartbeat.js +6 -4
  332. package/dist/transaction/transport/httpClient.d.ts +131 -0
  333. package/dist/{client → transaction/transport}/httpClient.js +6 -5
  334. package/dist/transaction/transport/httpOptions.d.ts +33 -0
  335. package/dist/transaction/transport/httpOptions.js +12 -0
  336. package/dist/{client → transaction/transport}/httpTransport.js +295 -97
  337. package/dist/{sync/NetworkProbe.d.ts → transaction/transport/networkProbe.d.ts} +7 -4
  338. package/dist/{sync/NetworkProbe.js → transaction/transport/networkProbe.js} +14 -13
  339. package/dist/transaction/transport/wsFrameHandlers.d.ts +128 -0
  340. package/dist/transaction/transport/wsFrameHandlers.js +429 -0
  341. package/dist/transaction/transport/wsTransport.d.ts +574 -0
  342. package/dist/transaction/transport/wsTransport.js +1023 -0
  343. package/dist/transaction/types/assertExact.d.ts +17 -0
  344. package/dist/transaction/types/assertExact.js +1 -0
  345. package/dist/{types → transaction/types}/global.d.ts +17 -2
  346. package/dist/{types → transaction/types}/global.js +2 -1
  347. package/dist/{types → transaction/types}/index.d.ts +14 -46
  348. package/dist/{types → transaction/types}/index.js +7 -16
  349. package/dist/{types → transaction/types}/streams.d.ts +73 -45
  350. package/dist/transaction/utils/duration.d.ts +50 -0
  351. package/dist/{utils → transaction/utils}/duration.js +32 -0
  352. package/dist/{utils → transaction/utils}/json.d.ts +18 -0
  353. package/dist/transaction/utils/json.js +276 -0
  354. package/dist/transaction/wire/accountResponses.d.ts +420 -0
  355. package/dist/transaction/wire/accountResponses.js +290 -0
  356. package/dist/transaction/wire/auth.d.ts +56 -0
  357. package/dist/transaction/wire/auth.js +63 -0
  358. package/dist/transaction/wire/claimEvent.d.ts +76 -0
  359. package/dist/transaction/wire/claimEvent.js +73 -0
  360. package/dist/transaction/wire/claims.d.ts +530 -0
  361. package/dist/transaction/wire/claims.js +327 -0
  362. package/dist/{wire → transaction/wire}/commit.d.ts +125 -193
  363. package/dist/{wire → transaction/wire}/commit.js +68 -47
  364. package/dist/{wire → transaction/wire}/delta.d.ts +66 -17
  365. package/dist/{wire → transaction/wire}/delta.js +37 -13
  366. package/dist/transaction/wire/errorEnvelope.d.ts +72 -0
  367. package/dist/{wire → transaction/wire}/errorEnvelope.js +36 -5
  368. package/dist/transaction/wire/feedCursor.d.ts +60 -0
  369. package/dist/transaction/wire/feedCursor.js +82 -0
  370. package/dist/transaction/wire/feedEvent.d.ts +204 -0
  371. package/dist/transaction/wire/feedEvent.js +65 -0
  372. package/dist/transaction/wire/frames.d.ts +194 -0
  373. package/dist/transaction/wire/frames.js +50 -0
  374. package/dist/transaction/wire/inboundFrames.d.ts +562 -0
  375. package/dist/transaction/wire/inboundFrames.js +116 -0
  376. package/dist/transaction/wire/index.d.ts +54 -0
  377. package/dist/transaction/wire/index.js +83 -0
  378. package/dist/{wire → transaction/wire}/listEnvelope.d.ts +13 -14
  379. package/dist/transaction/wire/listEnvelope.js +42 -0
  380. package/dist/transaction/wire/modelMutations.d.ts +31 -0
  381. package/dist/transaction/wire/modelMutations.js +52 -0
  382. package/dist/transaction/wire/modelResponses.d.ts +85 -0
  383. package/dist/transaction/wire/modelResponses.js +43 -0
  384. package/dist/transaction/wire/modelShape.d.ts +78 -0
  385. package/dist/transaction/wire/modelShape.js +74 -0
  386. package/dist/transactions/{TransactionQueue.d.ts → mutations/MutationQueue.d.ts} +85 -38
  387. package/dist/transactions/{TransactionQueue.js → mutations/MutationQueue.js} +141 -80
  388. package/dist/transactions/{TransactionStore.d.ts → mutations/MutationStore.d.ts} +8 -8
  389. package/dist/transactions/{TransactionStore.js → mutations/MutationStore.js} +2 -2
  390. package/dist/transactions/{coalesceRules.d.ts → mutations/coalesceRules.d.ts} +10 -10
  391. package/dist/transactions/{coalesceRules.js → mutations/coalesceRules.js} +1 -1
  392. package/dist/transactions/mutations/commitLatency.d.ts +52 -0
  393. package/dist/transactions/mutations/commitLatency.js +130 -0
  394. package/dist/transactions/{commitOutboxStore.d.ts → mutations/commitOutboxStore.d.ts} +1 -5
  395. package/dist/transactions/{commitOutboxStore.js → mutations/commitOutboxStore.js} +1 -1
  396. package/dist/transactions/{commitPayload.d.ts → mutations/commitPayload.d.ts} +18 -16
  397. package/dist/transactions/{commitPayload.js → mutations/commitPayload.js} +15 -15
  398. package/dist/transactions/{deltaConfirmation.d.ts → mutations/deltaConfirmation.d.ts} +15 -11
  399. package/dist/transactions/{deltaConfirmation.js → mutations/deltaConfirmation.js} +14 -12
  400. package/dist/transactions/mutations/durableWriteStore.d.ts +14 -0
  401. package/dist/transactions/mutations/durableWriteStore.js +12 -0
  402. package/dist/transactions/{optimisticApply.d.ts → mutations/optimisticApply.d.ts} +7 -7
  403. package/dist/transactions/{replayValidation.d.ts → mutations/replayValidation.d.ts} +4 -3
  404. package/dist/transactions/{replayValidation.js → mutations/replayValidation.js} +7 -5
  405. package/dist/utils/mobxSetup.d.ts +1 -1
  406. package/dist/utils/mobxSetup.js +5 -2
  407. package/dist/{core → views}/QueryView.d.ts +2 -2
  408. package/dist/{core → views}/QueryView.js +2 -2
  409. package/dist/{core → views}/ViewRegistry.d.ts +1 -1
  410. package/dist/{core/queryUtils.d.ts → views/incrementalView.d.ts} +6 -6
  411. package/dist/{core/queryUtils.js → views/incrementalView.js} +6 -6
  412. package/dist/webhooks/events.d.ts +2 -2
  413. package/dist/wire/index.d.ts +1 -34
  414. package/dist/wire/index.js +8 -49
  415. package/docs/agent-messaging.md +3 -3
  416. package/docs/agents.md +20 -13
  417. package/docs/api-keys.md +14 -10
  418. package/docs/api.md +27 -61
  419. package/docs/audit.md +6 -3
  420. package/docs/cli.md +41 -13
  421. package/docs/client-behavior.md +11 -9
  422. package/docs/concurrency-convention.md +49 -57
  423. package/docs/coordination.md +283 -121
  424. package/docs/data-sources.md +7 -5
  425. package/docs/debugging.md +39 -15
  426. package/docs/deployment.md +267 -0
  427. package/docs/examples/agent-human.md +49 -42
  428. package/docs/examples/ai-sdk-tool.md +69 -44
  429. package/docs/examples/existing-python-backend.md +8 -6
  430. package/docs/examples/nextjs.md +129 -47
  431. package/docs/examples/scoped-agent.md +46 -45
  432. package/docs/examples/server-agent.md +46 -26
  433. package/docs/groups.md +87 -30
  434. package/docs/guarantees.md +41 -12
  435. package/docs/how-it-works.md +38 -12
  436. package/docs/idempotency.md +126 -0
  437. package/docs/identity.md +77 -74
  438. package/docs/index.md +172 -86
  439. package/docs/integration-guide.md +31 -19
  440. package/docs/mcp.md +46 -21
  441. package/docs/migration.md +95 -18
  442. package/docs/operating-on-your-database.md +3 -1
  443. package/docs/projects.md +3 -1
  444. package/docs/quickstart.md +22 -5
  445. package/docs/react.md +31 -18
  446. package/docs/schema-contract.md +5 -3
  447. package/docs/session-settings.md +108 -0
  448. package/docs/sessions.md +4 -2
  449. package/docs/webhooks.md +12 -10
  450. package/llms.txt +48 -18
  451. package/package.json +21 -26
  452. package/dist/agent/Agent.d.ts +0 -366
  453. package/dist/agent/Agent.js +0 -514
  454. package/dist/agent/index.d.ts +0 -115
  455. package/dist/agent/index.js +0 -128
  456. package/dist/agent/session.d.ts +0 -93
  457. package/dist/agent/session.js +0 -149
  458. package/dist/agent/types.d.ts +0 -68
  459. package/dist/agent/types.js +0 -9
  460. package/dist/cli.cjs +0 -286329
  461. package/dist/client/durableWrites.d.ts +0 -21
  462. package/dist/client/httpClient.d.ts +0 -80
  463. package/dist/coordination/schema.d.ts +0 -722
  464. package/dist/coordination/schema.js +0 -578
  465. package/dist/schema/openapi.d.ts +0 -29
  466. package/dist/schema/openapi.js +0 -124
  467. package/dist/testing/fixtures/bootstrap.d.ts +0 -49
  468. package/dist/testing/fixtures/bootstrap.js +0 -59
  469. package/dist/testing/fixtures/deltas.d.ts +0 -83
  470. package/dist/testing/fixtures/deltas.js +0 -136
  471. package/dist/testing/fixtures/models.d.ts +0 -83
  472. package/dist/testing/fixtures/models.js +0 -272
  473. package/dist/testing/helpers/reactWrapper.d.ts +0 -69
  474. package/dist/testing/helpers/reactWrapper.js +0 -67
  475. package/dist/testing/helpers/syncEngineHarness.d.ts +0 -54
  476. package/dist/testing/helpers/syncEngineHarness.js +0 -73
  477. package/dist/testing/helpers/wait.d.ts +0 -30
  478. package/dist/testing/helpers/wait.js +0 -49
  479. package/dist/testing/index.d.ts +0 -23
  480. package/dist/testing/index.js +0 -33
  481. package/dist/testing/mocks/FakeDatabase.d.ts +0 -18
  482. package/dist/testing/mocks/FakeDatabase.js +0 -10
  483. package/dist/testing/mocks/MockMutationExecutor.d.ts +0 -87
  484. package/dist/testing/mocks/MockMutationExecutor.js +0 -192
  485. package/dist/testing/mocks/MockNetworkMonitor.d.ts +0 -20
  486. package/dist/testing/mocks/MockNetworkMonitor.js +0 -46
  487. package/dist/testing/mocks/MockSyncContext.d.ts +0 -51
  488. package/dist/testing/mocks/MockSyncContext.js +0 -71
  489. package/dist/testing/mocks/MockSyncStore.d.ts +0 -88
  490. package/dist/testing/mocks/MockSyncStore.js +0 -171
  491. package/dist/testing/mocks/MockWebSocket.d.ts +0 -71
  492. package/dist/testing/mocks/MockWebSocket.js +0 -118
  493. package/dist/transactions/durableWriteStore.js +0 -30
  494. package/dist/utils/duration.d.ts +0 -25
  495. package/dist/utils/json.js +0 -88
  496. package/dist/wire/errorEnvelope.d.ts +0 -55
  497. package/dist/wire/frames.d.ts +0 -197
  498. package/dist/wire/frames.js +0 -49
  499. package/dist/wire/listEnvelope.js +0 -18
  500. package/docs/interaction-model.md +0 -97
  501. /package/dist/{core → query}/QueryProcessor.d.ts +0 -0
  502. /package/dist/{core → query}/QueryProcessor.js +0 -0
  503. /package/dist/{core/storeContract.js → storeContract.js} +0 -0
  504. /package/dist/{core → stores}/openIDBWithTimeout.d.ts +0 -0
  505. /package/dist/{core → stores}/openIDBWithTimeout.js +0 -0
  506. /package/dist/{client → transaction/auth}/credentialEndpoint.d.ts +0 -0
  507. /package/dist/{client → transaction/auth}/credentialEndpoint.js +0 -0
  508. /package/dist/{auth → transaction/auth}/credentialPolicy.d.ts +0 -0
  509. /package/dist/{auth → transaction/auth}/credentialPolicy.js +0 -0
  510. /package/dist/{auth → transaction/auth}/credentialSource.js +0 -0
  511. /package/dist/{client → transaction/auth}/hostedEndpoints.d.ts +0 -0
  512. /package/dist/{client → transaction/auth}/hostedEndpoints.js +0 -0
  513. /package/dist/{client → transaction}/persistence.d.ts +0 -0
  514. /package/dist/{client → transaction}/persistence.js +0 -0
  515. /package/dist/{client → transaction/resources}/functionalUpdate.d.ts +0 -0
  516. /package/dist/{client → transaction/resources}/functionalUpdate.js +0 -0
  517. /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.d.ts +0 -0
  518. /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.js +0 -0
  519. /package/dist/{client → transaction/transport}/httpTransport.d.ts +0 -0
  520. /package/dist/{types → transaction/types}/modelData.d.ts +0 -0
  521. /package/dist/{types → transaction/types}/modelData.js +0 -0
  522. /package/dist/{types → transaction/types}/participant.d.ts +0 -0
  523. /package/dist/{types → transaction/types}/participant.js +0 -0
  524. /package/dist/{types → transaction/types}/streams.js +0 -0
  525. /package/dist/{utils → transaction/utils}/asyncIterator.d.ts +0 -0
  526. /package/dist/{utils → transaction/utils}/asyncIterator.js +0 -0
  527. /package/dist/{wire → transaction/wire}/bootstrapReason.d.ts +0 -0
  528. /package/dist/{wire → transaction/wire}/bootstrapReason.js +0 -0
  529. /package/dist/{wire → transaction/wire}/protocol.d.ts +0 -0
  530. /package/dist/{wire → transaction/wire}/protocol.js +0 -0
  531. /package/dist/{wire → transaction/wire}/protocolVersion.d.ts +0 -0
  532. /package/dist/{wire → transaction/wire}/protocolVersion.js +0 -0
  533. /package/dist/transactions/{UnconfirmedWrites.d.ts → mutations/UnconfirmedWrites.d.ts} +0 -0
  534. /package/dist/transactions/{UnconfirmedWrites.js → mutations/UnconfirmedWrites.js} +0 -0
  535. /package/dist/transactions/{optimisticApply.js → mutations/optimisticApply.js} +0 -0
  536. /package/dist/{core → views}/ViewRegistry.js +0 -0
@@ -1,5 +1,5 @@
1
1
  /**
2
- * TransactionQueue manages the lifecycle of local writes on their way to the
2
+ * MutationQueue manages the lifecycle of local writes on their way to the
3
3
  * server: it applies each change optimistically, batches the writes made in one
4
4
  * event-loop tick into a single commit, retries transient failures, and rolls
5
5
  * back on permanent rejection.
@@ -13,25 +13,25 @@
13
13
  */
14
14
  import { EventEmitter } from 'events';
15
15
  import { v4 as uuid } from 'uuid';
16
- import { Model } from '../Model.js';
17
- import { getContext } from '../context.js';
18
- import { AbloError, AbloConnectionError, AbloIdempotencyError, AbloNotFoundError, AbloValidationError, errorCodeSpec, } from '../errors.js';
19
- import { SyncPosition } from '../sync/syncPosition.js';
20
- import { mutationCommitResultSchema, } from '../wire/commit.js';
16
+ import { Model } from '../../Model.js';
17
+ import { globalRuntime } from '../../context.js';
18
+ import { AbloError, AbloConnectionError, AbloIdempotencyError, AbloNotFoundError, AbloValidationError, errorCodeSpec, } from '../../transaction/errors.js';
19
+ import { LogPosition } from '../../transaction/logPosition.js';
20
+ import { mutationCommitResultSchema, } from '../../transaction/wire/commit.js';
21
21
  import { projectCommitPayload, computePriorityScore, normalizeModelKey,
22
22
  // Includes stale guards as well as request identity/audit barriers.
23
23
  hasCommitCoalescingBarrier, applyWriteOptions, asTransportError, extractStatusCode, TX_TYPE_TO_MUTATION_OP, } from './commitPayload.js';
24
- import { TransactionStore } from './TransactionStore.js';
24
+ import { MutationStore } from './MutationStore.js';
25
25
  import { entityKey, mergeUpdateData, takeUnsentCreateForModel, findCreateBarrierForDelete, deferDeleteUntilCreateSettles, releaseDeferredDeletesForCreate, } from './coalesceRules.js';
26
26
  import { DeltaConfirmationTracker } from './deltaConfirmation.js';
27
27
  import { deserializePersistedTransaction, isNonReplayablePersistedRow, pendingMutationRecordId, } from './replayValidation.js';
28
- import { createCommitEnvelopeMember, createDurableCommitEnvelope, commitEnvelopeRecordId, durableCommitEnvelopeSchema, } from './commitEnvelope.js';
29
- import { stableStringify } from '../utils/json.js';
28
+ import { createCommitEnvelopeMember, createDurableCommitEnvelope, commitEnvelopeRecordId, durableCommitEnvelopeSchema, } from '../../transaction/transactions/settlement/commitEnvelope.js';
29
+ import { stableStringify } from '../../transaction/utils/json.js';
30
30
  import { applyOptimisticCreate, applyOptimisticUpdate, applyOptimisticDelete, rollbackOptimistic, } from './optimisticApply.js';
31
- export class TransactionQueue extends EventEmitter {
31
+ export class MutationQueue extends EventEmitter {
32
32
  // Keep one hour of clock/network margin inside the server's 24-hour ledger.
33
33
  static DURABLE_REPLAY_WINDOW_MS = 23 * 60 * 60 * 1000;
34
- store = new TransactionStore();
34
+ store = new MutationStore();
35
35
  // Signature of the last permanent-error we logged at `warn`. A `create`
36
36
  // whose id already exists (`unique_violation`) is a permanent rejection
37
37
  // that the offline queue re-drives on every reconnect/bootstrap — without
@@ -51,8 +51,9 @@ export class TransactionQueue extends EventEmitter {
51
51
  // queue treats as transient and retries endlessly.
52
52
  _mutationExecutor = null;
53
53
  get mutationExecutor() {
54
- return this._mutationExecutor ?? getContext().mutationExecutor;
54
+ return this._mutationExecutor ?? this.runtime.mutationExecutor;
55
55
  }
56
+ runtime;
56
57
  executionQueue = [];
57
58
  isProcessing = false;
58
59
  processTimer;
@@ -100,7 +101,7 @@ export class TransactionQueue extends EventEmitter {
100
101
  this.emit(event, payload);
101
102
  }
102
103
  catch (error) {
103
- getContext().observability.captureTransactionFailure({
104
+ this.runtime.observability.captureMutationFailure({
104
105
  context: `commit-lifecycle-listener:${event}`,
105
106
  error: error instanceof Error ? error : String(error),
106
107
  });
@@ -114,13 +115,19 @@ export class TransactionQueue extends EventEmitter {
114
115
  this.assertDurableReplayOpen();
115
116
  if (envelope.acceptedAt === undefined &&
116
117
  Date.now() - envelope.sealedAt >=
117
- TransactionQueue.DURABLE_REPLAY_WINDOW_MS) {
118
+ MutationQueue.DURABLE_REPLAY_WINDOW_MS) {
118
119
  this.durableReplayBlock = new AbloIdempotencyError('A pending commit is older than the server idempotency window; newer writes are blocked until it is reviewed.', { code: 'idempotency_conflict' });
120
+ // This gate stops EVERY subsequent write on this client, and each of
121
+ // those rejections is captured to observability rather than surfaced to
122
+ // the caller — without this line the session degrades into "nothing
123
+ // saves and nothing errors". One loud line at the moment the block
124
+ // engages is the only visible trace.
125
+ this.runtime.logger.warn('sync paused: a saved write from an earlier session is older than the server replay window, so newer writes are held until it is reviewed', { sealedAt: envelope.sealedAt });
119
126
  throw this.durableReplayBlock;
120
127
  }
121
128
  }
122
129
  computePriorityScore(type, modelName) {
123
- return computePriorityScore(type, modelName);
130
+ return computePriorityScore(type, modelName, this.runtime);
124
131
  }
125
132
  ensureDerivedFields(transaction) {
126
133
  if (!transaction.modelKey) {
@@ -256,6 +263,7 @@ export class TransactionQueue extends EventEmitter {
256
263
  deltaConfirmationTimeout: 30000,
257
264
  retryBackoff: { baseMs: 200, capMs: 1500 },
258
265
  commitOfflineGraceMs: 30_000,
266
+ commitDispatchTimeoutMs: 30_000,
259
267
  };
260
268
  // Track executing transactions for backpressure
261
269
  executingCount = 0;
@@ -264,7 +272,7 @@ export class TransactionQueue extends EventEmitter {
264
272
  // completion paths, `getStats`, and `dispose` all read it.
265
273
  optimisticUpdates = new Map();
266
274
  // Stale-context notifications, keyed by transaction id. When the server
267
- // accepts a commit but reports that an operation's read premise had moved,
275
+ // accepts a commit but reports that an operation's premise had moved,
268
276
  // the notification lands here from the commit acknowledgement and is drained
269
277
  // by `waitForCommitReceipt`, so the receipt can carry it back to the caller.
270
278
  commitNotifications = new Map();
@@ -287,7 +295,7 @@ export class TransactionQueue extends EventEmitter {
287
295
  * shared: the client injects one, and a standalone queue creates its own. The
288
296
  * queue advances the `acked` cursor as commit responses arrive, the store
289
297
  * advances `applied` and `persisted`, and snapshots and claims read
290
- * `readFloor`. See `../sync/syncPosition.js` for the full contract.
298
+ * `readFloor`. See `../logPosition.js` for the full contract.
291
299
  */
292
300
  position;
293
301
  /** Applied-cursor alias, kept so the many internal read sites stay legible. */
@@ -390,9 +398,6 @@ export class TransactionQueue extends EventEmitter {
390
398
  operations: [...input.operations],
391
399
  sourceMutationIds,
392
400
  commitOptions: {
393
- ...(input.commitOptions?.causedByTaskId !== undefined
394
- ? { causedByTaskId: input.commitOptions.causedByTaskId }
395
- : {}),
396
401
  ...(input.commitOptions?.reads !== undefined
397
402
  ? {
398
403
  reads: input.commitOptions.reads === null
@@ -440,7 +445,7 @@ export class TransactionQueue extends EventEmitter {
440
445
  await this.commitOutbox.remove(commitEnvelopeRecordId(idempotencyKey));
441
446
  }
442
447
  catch (error) {
443
- getContext().logger.debug('[TransactionQueue] Durable-write cleanup deferred', {
448
+ this.runtime.logger.debug('[MutationQueue] Durable-write cleanup deferred', {
444
449
  idempotencyKey,
445
450
  error: error instanceof Error ? error.message : String(error),
446
451
  });
@@ -489,6 +494,35 @@ export class TransactionQueue extends EventEmitter {
489
494
  return parsed.data;
490
495
  throw new AbloConnectionError('The mutation transport returned an invalid commit receipt; its outcome remains pending and is safe to retry.', { code: 'commit_no_result', cause: parsed.error });
491
496
  }
497
+ /**
498
+ * Dispatch a sealed envelope to the transport, bounded by
499
+ * `commitDispatchTimeoutMs`. Every executor call site routes through here:
500
+ * a transport that never answers must become a retryable no-receipt failure
501
+ * (the same class as a malformed receipt) instead of an eternally in-flight
502
+ * commit, because an unanswered commit holds the staged-batch lock and
503
+ * silently stalls every later write in the session. The abandoned commit's
504
+ * eventual result, if it ever arrives, is discarded; the retry re-sends the
505
+ * identical idempotency key, so the server deduplicates an already-applied
506
+ * write.
507
+ */
508
+ dispatchCommitBounded(...args) {
509
+ const timeoutMs = this.config.commitDispatchTimeoutMs;
510
+ const dispatched = this.mutationExecutor.commit(...args);
511
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
512
+ return dispatched;
513
+ return new Promise((resolve, reject) => {
514
+ const timer = setTimeout(() => {
515
+ reject(new AbloConnectionError('The mutation transport did not acknowledge the commit in time; its outcome remains pending and is safe to retry.', { code: 'commit_no_result' }));
516
+ }, timeoutMs);
517
+ dispatched.then((value) => {
518
+ clearTimeout(timer);
519
+ resolve(value);
520
+ }, (error) => {
521
+ clearTimeout(timer);
522
+ reject(error instanceof Error ? error : new Error(String(error)));
523
+ });
524
+ });
525
+ }
492
526
  clearReplicationLagState(transactionId) {
493
527
  const timeout = this.replicationLagTimeouts.get(transactionId);
494
528
  if (timeout)
@@ -620,13 +654,14 @@ export class TransactionQueue extends EventEmitter {
620
654
  * Resolvers for per-transaction `confirmation` promises. Populated in
621
655
  * `attachConfirmation` at staging time, consumed by the constructor-time
622
656
  * listeners on `transaction:completed` / `transaction:failed`. Kept off
623
- * the Transaction row so the store's iteration order stays plain-data
657
+ * the QueuedMutation row so the store's iteration order stays plain-data
624
658
  * and serialization-friendly.
625
659
  */
626
660
  confirmationResolvers = new Map();
627
661
  constructor(config) {
628
662
  super();
629
- this.position = config?.position ?? new SyncPosition();
663
+ this.runtime = config?.runtime ?? globalRuntime;
664
+ this.position = config?.position ?? new LogPosition();
630
665
  // Bind the confirmation tracker to this queue's store/ledger/events.
631
666
  // `isConnected` closes over `isConnectedFn` so `setConnectionChecker`
632
667
  // swaps stay visible to in-flight timeouts.
@@ -638,6 +673,7 @@ export class TransactionQueue extends EventEmitter {
638
673
  },
639
674
  isConnected: () => this.isConnectedFn(),
640
675
  position: this.position,
676
+ runtime: this.runtime,
641
677
  });
642
678
  if (config) {
643
679
  this.config = { ...this.config, ...config };
@@ -683,7 +719,7 @@ export class TransactionQueue extends EventEmitter {
683
719
  * be rolled back — `pending`, `executing`, and `awaiting_delta` — and ignores
684
720
  * `completed` (already settled) and `failed`/`rolled_back` (already
685
721
  * rejected). This complements the `confirmation` promise carried on a known
686
- * {@link Transaction}: use this method at call sites that hold a model
722
+ * {@link QueuedMutation}: use this method at call sites that hold a model
687
723
  * returned by `ablo.<model>.create()` but never see the underlying
688
724
  * transaction.
689
725
  */
@@ -771,7 +807,7 @@ export class TransactionQueue extends EventEmitter {
771
807
  return;
772
808
  // Each failed commit reaches the consumer through its own rejection path,
773
809
  // so this aggregate line is forensic and logged at debug rather than warn.
774
- getContext().logger.debug(`[TransactionQueue] WS disconnected > ${graceMs}ms; failing ${inFlight.length} in-flight commit(s) with AbloConnectionError`, { inFlightIds: inFlight.map((id) => id.slice(0, 8)) });
810
+ this.runtime.logger.debug(`[MutationQueue] WS disconnected > ${graceMs}ms; failing ${inFlight.length} in-flight commit(s) with AbloConnectionError`, { inFlightIds: inFlight.map((id) => id.slice(0, 8)) });
775
811
  for (const id of inFlight) {
776
812
  const tx = this.commitStore.get(id);
777
813
  if (!tx)
@@ -844,7 +880,7 @@ export class TransactionQueue extends EventEmitter {
844
880
  this.batchIndex++;
845
881
  const currentBatchIndex = this.batchIndex;
846
882
  // Log batch commit for performance monitoring
847
- getContext().logger.debug('[TransactionQueue] commitCreatedTransactions', {
883
+ this.runtime.logger.debug('[MutationQueue] commitCreatedTransactions', {
848
884
  count: this.createdTransactions.length,
849
885
  batchIndex: currentBatchIndex,
850
886
  types: this.createdTransactions.map((t) => `${t.type}:${t.modelName}`),
@@ -907,7 +943,7 @@ export class TransactionQueue extends EventEmitter {
907
943
  sequence: batch[0]?.commitEnvelope?.sequence,
908
944
  });
909
945
  this.assertEnvelopeInsideReplayWindow(durableEnvelope);
910
- const result = this.parseMutationCommitResult(await this.mutationExecutor.commit(durableEnvelope.operations, {
946
+ const result = this.parseMutationCommitResult(await this.dispatchCommitBounded(durableEnvelope.operations, {
911
947
  idempotencyKey,
912
948
  }));
913
949
  await this.persistDurableCommitAcceptance(durableEnvelope, result);
@@ -948,7 +984,7 @@ export class TransactionQueue extends EventEmitter {
948
984
  this.optimisticUpdates.delete(tx.id);
949
985
  }
950
986
  }
951
- getContext().logger.debug('txn:commit', 0, {
987
+ this.runtime.logger.debug('txn:commit', 0, {
952
988
  count: batch.length,
953
989
  lastSyncId: result.lastSyncId,
954
990
  });
@@ -957,13 +993,13 @@ export class TransactionQueue extends EventEmitter {
957
993
  catch (err) {
958
994
  // If one request fails, hand it and every later request back to the
959
995
  // normal lane. Their envelopes stay attached for safe retry.
960
- const isOffline = !getContext().onlineStatus.isOnline();
996
+ const isOffline = !this.runtime.onlineStatus.isOnline();
961
997
  const isNetworkError = err instanceof Error &&
962
998
  (err.message.includes('Failed to fetch') ||
963
999
  err.message.includes('Network request failed') ||
964
1000
  err.message.includes('NetworkError'));
965
1001
  if (!isOffline || !isNetworkError) {
966
- getContext().observability.breadcrumb('Batch flush fallback failed', 'sync.transaction', 'warning', {
1002
+ this.runtime.observability.breadcrumb('Batch flush fallback failed', 'sync.transaction', 'warning', {
967
1003
  error: err instanceof Error ? err.message : String(err),
968
1004
  });
969
1005
  }
@@ -976,7 +1012,7 @@ export class TransactionQueue extends EventEmitter {
976
1012
  }
977
1013
  /**
978
1014
  * Records a create and applies it optimistically, then stages it for the next
979
- * batched commit. Returns the {@link Transaction}, whose `confirmation`
1015
+ * batched commit. Returns the {@link QueuedMutation}, whose `confirmation`
980
1016
  * promise settles once the server confirms the write.
981
1017
  */
982
1018
  async create(model, context, writeOptions, sourceMutationId) {
@@ -1080,7 +1116,7 @@ export class TransactionQueue extends EventEmitter {
1080
1116
  const actualModelName = model.getModelName();
1081
1117
  // Skip Activity delete transactions - activities are permanent audit records
1082
1118
  if (actualModelName === 'Activity') {
1083
- getContext().logger.debug('TransactionQueue.delete() skipping Activity deletion - permanent audit records', { modelId: model.id });
1119
+ this.runtime.logger.debug('MutationQueue.delete() skipping Activity deletion - permanent audit records', { modelId: model.id });
1084
1120
  const modelKey = normalizeModelKey(actualModelName);
1085
1121
  const priorityScore = this.computePriorityScore('delete', actualModelName);
1086
1122
  const mockTransaction = {
@@ -1147,7 +1183,14 @@ export class TransactionQueue extends EventEmitter {
1147
1183
  transaction.sourceMutationIds = [
1148
1184
  ...new Set([
1149
1185
  ...(transaction.sourceMutationIds ?? []),
1150
- ...canceledUpdates.flatMap((candidate) => candidate.sourceMutationIds ?? []),
1186
+ // Absorb journal sources only from updates that never sealed an
1187
+ // envelope. A sealed update's seal already CONSUMED its journal rows
1188
+ // — they belong to that envelope forever — so listing them here
1189
+ // poisons this delete's own seal: the new-envelope guard finds its
1190
+ // sources missing, rejects with `idempotency_conflict`, and the
1191
+ // optimistic delete reverts. That was a user-visible lost delete
1192
+ // (edit a layer, then delete it while the edit was on the wire).
1193
+ ...canceledUpdates.flatMap((candidate) => candidate.commitEnvelope ? [] : (candidate.sourceMutationIds ?? [])),
1151
1194
  ...(pendingMerge?.sourceMutationIds ?? []),
1152
1195
  ]),
1153
1196
  ];
@@ -1319,7 +1362,7 @@ export class TransactionQueue extends EventEmitter {
1319
1362
  // are already executing, so the server is not flooded with concurrent
1320
1363
  // requests.
1321
1364
  if (this.executingCount >= this.config.maxExecutingTransactions) {
1322
- getContext().logger.debug('[TransactionQueue] Backpressure: delaying batch, too many executing', {
1365
+ this.runtime.logger.debug('[MutationQueue] Backpressure: delaying batch, too many executing', {
1323
1366
  executingCount: this.executingCount,
1324
1367
  max: this.config.maxExecutingTransactions,
1325
1368
  });
@@ -1360,7 +1403,7 @@ export class TransactionQueue extends EventEmitter {
1360
1403
  this.isProcessing = true;
1361
1404
  // Declare batch outside try so it's accessible in finally for backpressure tracking
1362
1405
  let batch = [];
1363
- await getContext().observability.startSpanAsync('sync.batch', 'sync.transaction.batch', async () => {
1406
+ await this.runtime.observability.startSpanAsync('sync.batch', 'sync.transaction.batch', async () => {
1364
1407
  try {
1365
1408
  // Sort the execution queue by foreign-key priority before selecting a
1366
1409
  // batch, so a parent row is always committed before its children, even
@@ -1432,7 +1475,7 @@ export class TransactionQueue extends EventEmitter {
1432
1475
  // the exact key assigned before the first transport attempt.
1433
1476
  this.assertEnvelopeInsideReplayWindow(durableEnvelope);
1434
1477
  dispatchStarted = true;
1435
- const result = this.parseMutationCommitResult(await this.mutationExecutor.commit(operations, {
1478
+ const result = this.parseMutationCommitResult(await this.dispatchCommitBounded(operations, {
1436
1479
  idempotencyKey: commitIdempotencyKey,
1437
1480
  }));
1438
1481
  await this.persistDurableCommitAcceptance(durableEnvelope, result);
@@ -1496,7 +1539,7 @@ export class TransactionQueue extends EventEmitter {
1496
1539
  }
1497
1540
  this.store.updateStatus(tx.id, 'awaiting_delta');
1498
1541
  this.scheduleReplicationLagTimeout(tx.id, commitIdempotencyKey, result.correlationId);
1499
- getContext().logger.debug('tx:awaiting_delta', {
1542
+ this.runtime.logger.debug('tx:awaiting_delta', {
1500
1543
  txId: tx.id.slice(0, 8),
1501
1544
  model: tx.modelName,
1502
1545
  reason: 'queued_forward_waiting_for_correlated_echo',
@@ -1514,7 +1557,7 @@ export class TransactionQueue extends EventEmitter {
1514
1557
  // A lastSyncId of 0 means the mutation succeeded but the server
1515
1558
  // emitted no sync delta; record that anomaly for observability.
1516
1559
  if (lastSyncId === 0) {
1517
- getContext().observability.captureCommitZeroSyncId({
1560
+ this.runtime.observability.captureCommitZeroSyncId({
1518
1561
  operationCount: operations.length,
1519
1562
  operations: operations.map((op) => `${op.type}:${op.model}:${op.id?.slice(0, 8) ?? '?'}`),
1520
1563
  });
@@ -1532,7 +1575,7 @@ export class TransactionQueue extends EventEmitter {
1532
1575
  this.emit('transaction:completed', tx);
1533
1576
  this.emit(`transaction:completed:${tx.id}`, tx);
1534
1577
  this.optimisticUpdates.delete(tx.id);
1535
- getContext().logger.debug('tx:confirm_delete_zero_syncid', {
1578
+ this.runtime.logger.debug('tx:confirm_delete_zero_syncid', {
1536
1579
  txId: tx.id.slice(0, 8),
1537
1580
  model: tx.modelName,
1538
1581
  reason: 'delete_idempotent_no_delta',
@@ -1547,7 +1590,7 @@ export class TransactionQueue extends EventEmitter {
1547
1590
  this.emit('transaction:completed', tx);
1548
1591
  this.emit(`transaction:completed:${tx.id}`, tx);
1549
1592
  this.optimisticUpdates.delete(tx.id);
1550
- getContext().logger.debug('tx:confirm_ack', {
1593
+ this.runtime.logger.debug('tx:confirm_ack', {
1551
1594
  txId: tx.id.slice(0, 8),
1552
1595
  model: tx.modelName,
1553
1596
  serverSyncId: lastSyncId,
@@ -1556,7 +1599,7 @@ export class TransactionQueue extends EventEmitter {
1556
1599
  }
1557
1600
  else {
1558
1601
  this.store.updateStatus(tx.id, 'awaiting_delta');
1559
- getContext().logger.debug('tx:awaiting_delta', {
1602
+ this.runtime.logger.debug('tx:awaiting_delta', {
1560
1603
  txId: tx.id.slice(0, 8),
1561
1604
  model: tx.modelName,
1562
1605
  neededSyncId: lastSyncId,
@@ -1603,7 +1646,7 @@ export class TransactionQueue extends EventEmitter {
1603
1646
  // authoritative `warn` with the same typed cause) — passes
1604
1647
  // through here. Logging it at `warn` made one rejected write
1605
1648
  // surface three identical dumps; keep it at `debug`.
1606
- getContext().logger.debug('[TransactionQueue] Batch commit rejected', {
1649
+ this.runtime.logger.debug('[MutationQueue] Batch commit rejected', {
1607
1650
  batchSize: batchOps.length,
1608
1651
  models: batchOps.map(({ op }) => `${op.type}:${op.model}`),
1609
1652
  errorType: abloErr?.type ?? error?.name,
@@ -1621,7 +1664,7 @@ export class TransactionQueue extends EventEmitter {
1621
1664
  if (dispatchStarted) {
1622
1665
  await this.removeDurableCommit(commitIdempotencyKey);
1623
1666
  }
1624
- getContext().logger.info('[TransactionQueue] Graceful handling: entity already deleted', {
1667
+ this.runtime.logger.info('[MutationQueue] Graceful handling: entity already deleted', {
1625
1668
  batchSize: batchOps.length,
1626
1669
  });
1627
1670
  for (const { tx, op } of batchOps) {
@@ -1629,7 +1672,7 @@ export class TransactionQueue extends EventEmitter {
1629
1672
  // Row already gone: the intended state holds, mark completed.
1630
1673
  this.store.updateStatus(tx.id, 'completed');
1631
1674
  this.emit('transaction:completed', tx);
1632
- getContext().logger.debug('[TransactionQueue] Orphaned transaction treated as success', {
1675
+ this.runtime.logger.debug('[MutationQueue] Orphaned transaction treated as success', {
1633
1676
  txId: tx.id.slice(0, 12),
1634
1677
  model: tx.modelName,
1635
1678
  type: op.type,
@@ -1689,7 +1732,7 @@ export class TransactionQueue extends EventEmitter {
1689
1732
  this.scheduleProcessing(true);
1690
1733
  }
1691
1734
  const batchEnd = typeof performance !== 'undefined' ? performance.now() : Date.now();
1692
- getContext().logger.debug('txn:batch', batchEnd - batchStart, {
1735
+ this.runtime.logger.debug('txn:batch', batchEnd - batchStart, {
1693
1736
  maxBatchSize: this.config.maxBatchSize,
1694
1737
  remaining: this.executionQueue.length,
1695
1738
  executingCount: this.executingCount,
@@ -1834,13 +1877,11 @@ export class TransactionQueue extends EventEmitter {
1834
1877
  await existing.sealPromise;
1835
1878
  const existingIntent = stableStringify({
1836
1879
  operations: existing.operations,
1837
- causedByTaskId: existing.causedByTaskId ?? null,
1838
1880
  reads: existing.reads ?? null,
1839
1881
  track: existing.track ?? null,
1840
1882
  });
1841
1883
  const incomingIntent = stableStringify({
1842
1884
  operations,
1843
- causedByTaskId: options.causedByTaskId ?? null,
1844
1885
  reads: options.reads ?? null,
1845
1886
  track: options.track ?? null,
1846
1887
  });
@@ -1871,7 +1912,6 @@ export class TransactionQueue extends EventEmitter {
1871
1912
  id: clientTxId,
1872
1913
  kind: 'commit',
1873
1914
  operations: [...operations],
1874
- causedByTaskId: options.causedByTaskId ?? null,
1875
1915
  ...(options.reads ? { reads: options.reads } : {}),
1876
1916
  ...(options.track ? { track: options.track } : {}),
1877
1917
  status: 'pending',
@@ -1886,7 +1926,6 @@ export class TransactionQueue extends EventEmitter {
1886
1926
  origin: 'atomic_commit',
1887
1927
  operations: tx.operations,
1888
1928
  commitOptions: {
1889
- causedByTaskId: tx.causedByTaskId ?? null,
1890
1929
  ...(tx.reads ? { reads: tx.reads } : {}),
1891
1930
  ...(tx.track ? { track: tx.track } : {}),
1892
1931
  },
@@ -1950,7 +1989,6 @@ export class TransactionQueue extends EventEmitter {
1950
1989
  operations: tx.operations,
1951
1990
  sourceMutationIds: tx.sourceMutationIds,
1952
1991
  commitOptions: {
1953
- causedByTaskId: tx.causedByTaskId ?? null,
1954
1992
  ...(tx.reads ? { reads: tx.reads } : {}),
1955
1993
  ...(tx.track ? { track: tx.track } : {}),
1956
1994
  },
@@ -1961,9 +1999,8 @@ export class TransactionQueue extends EventEmitter {
1961
1999
  tx.durableEnvelope = durableEnvelope;
1962
2000
  this.assertEnvelopeInsideReplayWindow(durableEnvelope);
1963
2001
  dispatchStarted = true;
1964
- const result = this.parseMutationCommitResult(await this.mutationExecutor.commit(durableEnvelope.operations, {
2002
+ const result = this.parseMutationCommitResult(await this.dispatchCommitBounded(durableEnvelope.operations, {
1965
2003
  idempotencyKey: tx.id,
1966
- causedByTaskId: durableEnvelope.commitOptions.causedByTaskId ?? undefined,
1967
2004
  ...(durableEnvelope.commitOptions.reads
1968
2005
  ? { reads: durableEnvelope.commitOptions.reads }
1969
2006
  : {}),
@@ -1991,7 +2028,7 @@ export class TransactionQueue extends EventEmitter {
1991
2028
  }
1992
2029
  else {
1993
2030
  this.scheduleReplicationLagTimeout(tx.id, tx.id, result.correlationId);
1994
- getContext().logger.debug('[TransactionQueue] commit lane awaiting source echo', {
2031
+ this.runtime.logger.debug('[MutationQueue] commit lane awaiting source echo', {
1995
2032
  txId: tx.id.slice(0, 12),
1996
2033
  });
1997
2034
  }
@@ -2012,14 +2049,29 @@ export class TransactionQueue extends EventEmitter {
2012
2049
  if (dispatchStarted && this.isDefinitiveRejection(error)) {
2013
2050
  await this.removeDurableCommit(tx.id);
2014
2051
  }
2015
- if (!this.isPermanentError(error)) {
2052
+ // A transport that is DOWN is not a failing write: the envelope is
2053
+ // meant to wait for reconnect, which is what makes a commit survive a
2054
+ // dropped connection. A transient error the SERVER keeps returning is
2055
+ // a different thing, and this lane has no attempt bound of its own —
2056
+ // so a 5xx carrying no wire code reads as transient on every kick,
2057
+ // sits at the head of the lane, and `waitForCommitReceipt` never
2058
+ // settles. The caller sees a write that neither lands nor fails.
2059
+ //
2060
+ // Counting only the non-connection failures keeps offline waiting
2061
+ // unbounded while giving a repeating server rejection an end.
2062
+ if (!(error instanceof AbloConnectionError)) {
2063
+ tx.transientAttempts = (tx.transientAttempts ?? 0) + 1;
2064
+ }
2065
+ const exhausted = (tx.transientAttempts ?? 0) > this.config.maxRetries;
2066
+ if (!this.isPermanentError(error) && !exhausted) {
2016
2067
  // Transient: leave it at the head and retry on the next kick
2017
2068
  // (reconnect or the next enqueueCommit) rather than tight-looping
2018
2069
  // while the connection is down.
2019
2070
  tx.status = 'pending';
2020
- getContext().logger.debug('[TransactionQueue] commit lane transient', {
2071
+ this.runtime.logger.debug('[MutationQueue] commit lane transient', {
2021
2072
  txId: tx.id.slice(0, 12),
2022
2073
  attempts: tx.attempts,
2074
+ transientAttempts: tx.transientAttempts ?? 0,
2023
2075
  message: error.message,
2024
2076
  });
2025
2077
  break;
@@ -2030,7 +2082,7 @@ export class TransactionQueue extends EventEmitter {
2030
2082
  // Internal bookkeeping; the consumer-facing rejection is emitted on
2031
2083
  // 'transaction:failed' and surfaced by the permanent-error headline,
2032
2084
  // so this line stays at debug.
2033
- getContext().logger.debug('[TransactionQueue] commit lane permanent error', {
2085
+ this.runtime.logger.debug('[MutationQueue] commit lane permanent error', {
2034
2086
  txId: tx.id.slice(0, 12),
2035
2087
  attempts: tx.attempts,
2036
2088
  message: error.message,
@@ -2240,7 +2292,7 @@ export class TransactionQueue extends EventEmitter {
2240
2292
  const sig = `${details.type}:${details.model}:${details.modelId}:${details.errorCode ?? details.errorType}`;
2241
2293
  const isRepeat = sig === this.lastPermanentErrorSig;
2242
2294
  this.lastPermanentErrorSig = sig;
2243
- const logger = getContext().logger;
2295
+ const logger = this.runtime.logger;
2244
2296
  // Two registers from one call site, split by log level (the default
2245
2297
  // logger is gated at `warn`, so `debug` stays hidden unless
2246
2298
  // ABLO_LOG_LEVEL=debug is set to inspect the engine):
@@ -2256,7 +2308,17 @@ export class TransactionQueue extends EventEmitter {
2256
2308
  : '';
2257
2309
  const reason = abloErr?.message ? ` — ${abloErr.message}` : '';
2258
2310
  const code = abloErr?.code ? ` (code: ${abloErr.code})` : '';
2259
- const headline = `Your ${transaction.type} to "${transaction.modelName}" was not saved${reason}${code}.${revertNote}`;
2311
+ // An optimistic write resolves before the server answers, so a later
2312
+ // rejection has no caller left to return to and this log is the only
2313
+ // place it appears. That reads to an application developer as their own
2314
+ // save silently failing — the write showed, then vanished — and sends
2315
+ // them into their editor instead of here. Name the subscription that
2316
+ // hands them the same typed error, so the application can say what
2317
+ // happened rather than only the console.
2318
+ const channelNote = this.config.enableOptimistic
2319
+ ? ' To surface this in your app, subscribe with `ablo.onMutationFailure(…)`.'
2320
+ : '';
2321
+ const headline = `Your ${transaction.type} to "${transaction.modelName}" was not saved${reason}${code}.${revertNote}${channelNote}`;
2260
2322
  if (isRepeat) {
2261
2323
  // Same write rejected for the same reason on each reconnect replay —
2262
2324
  // log the forensics once, stay quiet after.
@@ -2388,7 +2450,7 @@ export class TransactionQueue extends EventEmitter {
2388
2450
  }
2389
2451
  }
2390
2452
  catch (error) {
2391
- getContext().observability.captureTransactionFailure({
2453
+ this.runtime.observability.captureMutationFailure({
2392
2454
  context: 'load-persisted-transactions',
2393
2455
  error: error instanceof Error ? error : String(error),
2394
2456
  });
@@ -2418,8 +2480,8 @@ export class TransactionQueue extends EventEmitter {
2418
2480
  envelopes.push(parsed.data);
2419
2481
  }
2420
2482
  else {
2421
- getContext().logger.warn('A saved local write is unreadable and was held for review.');
2422
- getContext().observability.captureTransactionFailure({
2483
+ this.runtime.logger.warn('A saved local write is unreadable and was held for review.');
2484
+ this.runtime.observability.captureMutationFailure({
2423
2485
  context: 'restore-commit-envelope',
2424
2486
  error: parsed.error,
2425
2487
  });
@@ -2435,9 +2497,9 @@ export class TransactionQueue extends EventEmitter {
2435
2497
  }
2436
2498
  if (envelope.acceptedAt === undefined &&
2437
2499
  Date.now() - envelope.sealedAt >=
2438
- TransactionQueue.DURABLE_REPLAY_WINDOW_MS) {
2439
- getContext().logger.warn('A saved local write is too old to retry safely and was held for review.');
2440
- getContext().observability.captureTransactionFailure({
2500
+ MutationQueue.DURABLE_REPLAY_WINDOW_MS) {
2501
+ this.runtime.logger.warn('A saved local write is too old to retry safely and was held for review.');
2502
+ this.runtime.observability.captureMutationFailure({
2441
2503
  context: 'quarantine-expired-commit-envelope',
2442
2504
  error: `Envelope ${envelope.idempotencyKey} is too old to replay safely`,
2443
2505
  });
@@ -2448,7 +2510,7 @@ export class TransactionQueue extends EventEmitter {
2448
2510
  envelope.scope.organizationId !== this.commitOutboxScope.organizationId ||
2449
2511
  envelope.scope.participantId !== this.commitOutboxScope.participantId ||
2450
2512
  envelope.scope.namespace !== this.commitOutboxScope.namespace)) {
2451
- getContext().logger.warn('A saved local write belongs to a different account or server and was held for review.');
2513
+ this.runtime.logger.warn('A saved local write belongs to a different account or server and was held for review.');
2452
2514
  continue;
2453
2515
  }
2454
2516
  if (this.commitStore.has(envelope.idempotencyKey))
@@ -2457,7 +2519,6 @@ export class TransactionQueue extends EventEmitter {
2457
2519
  id: envelope.idempotencyKey,
2458
2520
  kind: 'commit',
2459
2521
  operations: envelope.operations.map((operation) => ({ ...operation })),
2460
- causedByTaskId: envelope.commitOptions.causedByTaskId ?? null,
2461
2522
  ...(envelope.commitOptions.reads
2462
2523
  ? { reads: [...envelope.commitOptions.reads] }
2463
2524
  : {}),
@@ -2482,10 +2543,10 @@ export class TransactionQueue extends EventEmitter {
2482
2543
  void this.processCommitLane();
2483
2544
  }
2484
2545
  catch (error) {
2485
- getContext().logger.debug('[TransactionQueue] Failed to restore durable writes', {
2546
+ this.runtime.logger.debug('[MutationQueue] Failed to restore durable writes', {
2486
2547
  error: error instanceof Error ? error.message : String(error),
2487
2548
  });
2488
- getContext().observability.captureTransactionFailure({
2549
+ this.runtime.observability.captureMutationFailure({
2489
2550
  context: 'restore-commit-envelopes',
2490
2551
  error: error instanceof Error ? error : String(error),
2491
2552
  });
@@ -2502,15 +2563,15 @@ export class TransactionQueue extends EventEmitter {
2502
2563
  deserializeTransaction(data) {
2503
2564
  if (isNonReplayablePersistedRow(data))
2504
2565
  return null;
2505
- const transaction = deserializePersistedTransaction(data);
2566
+ const transaction = deserializePersistedTransaction(data, this.runtime);
2506
2567
  if (!transaction) {
2507
2568
  const rowId = typeof data === 'object' && data !== null && typeof data.id === 'string'
2508
2569
  ? data.id
2509
2570
  : undefined;
2510
- getContext().logger.debug('[TransactionQueue] Dropping malformed persisted transaction', {
2571
+ this.runtime.logger.debug('[MutationQueue] Dropping malformed persisted transaction', {
2511
2572
  rowId,
2512
2573
  });
2513
- getContext().observability.captureTransactionFailure({
2574
+ this.runtime.observability.captureMutationFailure({
2514
2575
  context: 'deserialize-persisted-transaction',
2515
2576
  error: `Persisted transaction failed schema validation${rowId ? ` (id: ${rowId})` : ''}`,
2516
2577
  });
@@ -2538,7 +2599,7 @@ export class TransactionQueue extends EventEmitter {
2538
2599
  // listener) must surface, not vanish — the status flip above is
2539
2600
  // already committed either way.
2540
2601
  void this.rollbackOptimistic(transaction, 'model_cancelled').catch((error) => {
2541
- getContext().observability.captureTransactionFailure({
2602
+ this.runtime.observability.captureMutationFailure({
2542
2603
  context: 'rollback-model-cancelled',
2543
2604
  error: error instanceof Error ? error : String(error),
2544
2605
  });
@@ -2553,8 +2614,8 @@ export class TransactionQueue extends EventEmitter {
2553
2614
  * used to cascade a parent deletion. The caller supplies the foreign-key
2554
2615
  * relationship; this method performs the cancellation.
2555
2616
  *
2556
- * @param childModelName - The child model type (for example 'SlideLayer').
2557
- * @param foreignKey - The foreign-key property name (for example 'slideId').
2617
+ * @param childModelName - The child model type (for example 'Block').
2618
+ * @param foreignKey - The foreign-key property name (for example 'sectionId').
2558
2619
  * @param parentId - The deleted parent's id.
2559
2620
  * @returns The number of transactions cancelled.
2560
2621
  */
@@ -2572,13 +2633,13 @@ export class TransactionQueue extends EventEmitter {
2572
2633
  if (fkValue === parentId) {
2573
2634
  this.store.updateStatus(transaction.id, 'rolled_back');
2574
2635
  void this.rollbackOptimistic(transaction, 'cascade_parent_deleted').catch((error) => {
2575
- getContext().observability.captureTransactionFailure({
2636
+ this.runtime.observability.captureMutationFailure({
2576
2637
  context: 'rollback-cascade-parent-deleted',
2577
2638
  error: error instanceof Error ? error : String(error),
2578
2639
  });
2579
2640
  });
2580
2641
  cancelled++;
2581
- getContext().logger.debug('[TransactionQueue] Cascade cancelled orphaned transaction', {
2642
+ this.runtime.logger.debug('[MutationQueue] Cascade cancelled orphaned transaction', {
2582
2643
  txId: transaction.id.slice(0, 12),
2583
2644
  model: childModelName,
2584
2645
  foreignKey,
@@ -2603,13 +2664,13 @@ export class TransactionQueue extends EventEmitter {
2603
2664
  return { ...(remote || {}), ...(local || {}) };
2604
2665
  }
2605
2666
  extractCreateData(model) {
2606
- return projectCommitPayload(model.getModelName(), model.toJSON(), { dropUndefined: false });
2667
+ return projectCommitPayload(model.getModelName(), model.toJSON(), { dropUndefined: false }, this.runtime);
2607
2668
  }
2608
2669
  mapChangesToInput(modelName, changes) {
2609
- return projectCommitPayload(modelName, changes, { dropUndefined: true });
2670
+ return projectCommitPayload(modelName, changes, { dropUndefined: true }, this.runtime);
2610
2671
  }
2611
2672
  extractUpdateData(model) {
2612
- return projectCommitPayload(model.getModelName(), model.getChanges(), { dropUndefined: true });
2673
+ return projectCommitPayload(model.getModelName(), model.getChanges(), { dropUndefined: true }, this.runtime);
2613
2674
  }
2614
2675
  // Derive previous values for changed fields to support accurate rollback.
2615
2676
  // Model-specific special cases do not belong here; a model that needs to
@@ -2624,7 +2685,7 @@ export class TransactionQueue extends EventEmitter {
2624
2685
  // inverse rather than inventing one. With no `updateInput` (a full extract)
2625
2686
  // it falls back to every tracked field. `Model.capturePreviousValues` is the
2626
2687
  // single before-image source, shared with
2627
- // `RecordingTransaction.snapshotFields`.
2688
+ // `RecordingMutation.snapshotFields`.
2628
2689
  const keys = updateInput
2629
2690
  ? Object.keys(updateInput)
2630
2691
  : [...(model.modifiedProperties instanceof Map ? model.modifiedProperties.keys() : [])];