@abloatai/ablo 0.25.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (425) hide show
  1. package/AGENTS.md +5 -3
  2. package/CHANGELOG.md +34 -0
  3. package/README.md +104 -88
  4. package/dist/BaseSyncedStore.d.ts +140 -266
  5. package/dist/BaseSyncedStore.js +338 -739
  6. package/dist/Database.d.ts +62 -77
  7. package/dist/Database.js +106 -127
  8. package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
  9. package/dist/{ObjectPool.js → InstanceCache.js} +91 -83
  10. package/dist/LazyReferenceCollection.d.ts +11 -15
  11. package/dist/LazyReferenceCollection.js +16 -15
  12. package/dist/Model.d.ts +37 -52
  13. package/dist/Model.js +52 -69
  14. package/dist/ModelRegistry.d.ts +46 -25
  15. package/dist/ModelRegistry.js +32 -30
  16. package/dist/NetworkMonitor.d.ts +5 -6
  17. package/dist/NetworkMonitor.js +6 -7
  18. package/dist/SyncClient.d.ts +119 -109
  19. package/dist/SyncClient.js +303 -224
  20. package/dist/SyncEngineContext.d.ts +1 -3
  21. package/dist/SyncEngineContext.js +1 -2
  22. package/dist/adapters/alwaysOnline.d.ts +6 -8
  23. package/dist/adapters/alwaysOnline.js +6 -8
  24. package/dist/adapters/inMemoryStorage.d.ts +9 -9
  25. package/dist/adapters/inMemoryStorage.js +9 -9
  26. package/dist/agent/Agent.d.ts +39 -31
  27. package/dist/agent/Agent.js +35 -23
  28. package/dist/agent/index.d.ts +4 -4
  29. package/dist/agent/index.js +5 -5
  30. package/dist/agent/session.d.ts +47 -44
  31. package/dist/agent/session.js +37 -48
  32. package/dist/agent/types.d.ts +26 -31
  33. package/dist/agent/types.js +6 -7
  34. package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
  35. package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
  36. package/dist/ai-sdk/coordinationContext.d.ts +46 -0
  37. package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +30 -31
  38. package/dist/ai-sdk/index.d.ts +25 -22
  39. package/dist/ai-sdk/index.js +25 -22
  40. package/dist/ai-sdk/wrap.d.ts +7 -8
  41. package/dist/ai-sdk/wrap.js +2 -2
  42. package/dist/auth/credentialPolicy.d.ts +74 -71
  43. package/dist/auth/credentialPolicy.js +51 -56
  44. package/dist/auth/credentialSource.d.ts +7 -18
  45. package/dist/auth/credentialSource.js +10 -18
  46. package/dist/auth/index.d.ts +59 -58
  47. package/dist/auth/index.js +34 -40
  48. package/dist/auth/schemas.d.ts +5 -4
  49. package/dist/auth/schemas.js +5 -4
  50. package/dist/batching/index.d.ts +19 -21
  51. package/dist/batching/index.js +14 -17
  52. package/dist/cli.cjs +483 -369
  53. package/dist/client/Ablo.d.ts +107 -836
  54. package/dist/client/Ablo.js +174 -833
  55. package/dist/client/ApiClient.d.ts +44 -20
  56. package/dist/client/ApiClient.js +193 -44
  57. package/dist/client/auth.d.ts +51 -60
  58. package/dist/client/auth.js +137 -110
  59. package/dist/client/claimHeartbeatLoop.d.ts +50 -0
  60. package/dist/client/claimHeartbeatLoop.js +88 -0
  61. package/dist/client/consoleLogger.d.ts +35 -0
  62. package/dist/client/consoleLogger.js +44 -0
  63. package/dist/client/createInternalComponents.d.ts +14 -17
  64. package/dist/client/createInternalComponents.js +26 -31
  65. package/dist/client/createModelProxy.d.ts +130 -120
  66. package/dist/client/createModelProxy.js +158 -124
  67. package/dist/client/credentialEndpoint.d.ts +61 -0
  68. package/dist/client/credentialEndpoint.js +86 -0
  69. package/dist/client/functionalUpdate.d.ts +29 -27
  70. package/dist/client/functionalUpdate.js +21 -21
  71. package/dist/client/hostedEndpoints.d.ts +21 -0
  72. package/dist/client/hostedEndpoints.js +21 -0
  73. package/dist/client/httpClient.d.ts +58 -54
  74. package/dist/client/httpClient.js +29 -31
  75. package/dist/client/identity.d.ts +15 -20
  76. package/dist/client/identity.js +49 -59
  77. package/dist/client/modelRegistration.d.ts +10 -0
  78. package/dist/client/modelRegistration.js +301 -0
  79. package/dist/client/options.d.ts +373 -0
  80. package/dist/client/options.js +6 -0
  81. package/dist/client/registerDataSource.d.ts +9 -9
  82. package/dist/client/registerDataSource.js +15 -16
  83. package/dist/client/resourceTypes.d.ts +333 -0
  84. package/dist/client/resourceTypes.js +7 -0
  85. package/dist/client/schemaConfig.d.ts +44 -0
  86. package/dist/client/schemaConfig.js +176 -0
  87. package/dist/client/sessionMint.d.ts +17 -13
  88. package/dist/client/sessionMint.js +26 -31
  89. package/dist/client/validateAbloOptions.d.ts +12 -14
  90. package/dist/client/validateAbloOptions.js +9 -10
  91. package/dist/client/writeOptionsSchema.d.ts +18 -16
  92. package/dist/client/writeOptionsSchema.js +23 -20
  93. package/dist/client/wsMutationExecutor.d.ts +28 -0
  94. package/dist/client/wsMutationExecutor.js +71 -0
  95. package/dist/context.d.ts +6 -4
  96. package/dist/context.js +6 -7
  97. package/dist/coordination/index.d.ts +13 -4
  98. package/dist/coordination/index.js +29 -4
  99. package/dist/coordination/schema.d.ts +176 -128
  100. package/dist/coordination/schema.js +197 -133
  101. package/dist/coordination/trace.d.ts +9 -11
  102. package/dist/coordination/trace.js +13 -15
  103. package/dist/core/DatabaseManager.d.ts +5 -8
  104. package/dist/core/DatabaseManager.js +38 -40
  105. package/dist/core/QueryProcessor.d.ts +7 -9
  106. package/dist/core/QueryProcessor.js +27 -34
  107. package/dist/core/QueryView.d.ts +17 -5
  108. package/dist/core/QueryView.js +6 -7
  109. package/dist/core/StoreManager.d.ts +14 -16
  110. package/dist/core/StoreManager.js +26 -25
  111. package/dist/core/ViewRegistry.d.ts +5 -5
  112. package/dist/core/ViewRegistry.js +4 -4
  113. package/dist/core/index.d.ts +18 -13
  114. package/dist/core/index.js +32 -26
  115. package/dist/core/openIDBWithTimeout.d.ts +38 -36
  116. package/dist/core/openIDBWithTimeout.js +57 -54
  117. package/dist/core/queryUtils.d.ts +45 -0
  118. package/dist/core/queryUtils.js +69 -0
  119. package/dist/core/storeContract.d.ts +145 -0
  120. package/dist/core/storeContract.js +12 -0
  121. package/dist/environment.d.ts +28 -0
  122. package/dist/environment.js +21 -0
  123. package/dist/errorCodes.d.ts +118 -101
  124. package/dist/errorCodes.js +277 -260
  125. package/dist/errors.d.ts +170 -165
  126. package/dist/errors.js +161 -151
  127. package/dist/index.d.ts +30 -27
  128. package/dist/index.js +90 -82
  129. package/dist/interfaces/index.d.ts +108 -133
  130. package/dist/interfaces/index.js +5 -4
  131. package/dist/keys/index.d.ts +27 -29
  132. package/dist/keys/index.js +59 -49
  133. package/dist/mutators/RecordingTransaction.d.ts +16 -16
  134. package/dist/mutators/RecordingTransaction.js +31 -37
  135. package/dist/mutators/Transaction.d.ts +18 -26
  136. package/dist/mutators/Transaction.js +14 -20
  137. package/dist/mutators/UndoManager.d.ts +122 -131
  138. package/dist/mutators/UndoManager.js +149 -155
  139. package/dist/mutators/defineMutators.d.ts +24 -37
  140. package/dist/mutators/defineMutators.js +14 -20
  141. package/dist/mutators/inverseOp.d.ts +12 -15
  142. package/dist/mutators/inverseOp.js +12 -15
  143. package/dist/mutators/mutateActions.d.ts +10 -9
  144. package/dist/mutators/mutateActions.js +1 -1
  145. package/dist/mutators/readerActions.d.ts +9 -8
  146. package/dist/mutators/readerActions.js +2 -2
  147. package/dist/mutators/undoApply.d.ts +31 -27
  148. package/dist/mutators/undoApply.js +26 -24
  149. package/dist/policy/index.d.ts +5 -3
  150. package/dist/policy/index.js +5 -3
  151. package/dist/policy/types.d.ts +105 -101
  152. package/dist/policy/types.js +67 -66
  153. package/dist/query/client.d.ts +32 -16
  154. package/dist/query/client.js +103 -72
  155. package/dist/query/types.d.ts +37 -60
  156. package/dist/query/types.js +13 -33
  157. package/dist/react/AbloProvider.d.ts +7 -11
  158. package/dist/react/AbloProvider.js +24 -17
  159. package/dist/react/context.d.ts +27 -146
  160. package/dist/react/context.js +9 -10
  161. package/dist/react/index.d.ts +41 -42
  162. package/dist/react/index.js +37 -38
  163. package/dist/react/internalContext.d.ts +17 -19
  164. package/dist/react/useAblo.d.ts +23 -22
  165. package/dist/react/useAblo.js +17 -15
  166. package/dist/react/useCurrentUserId.d.ts +8 -7
  167. package/dist/react/useCurrentUserId.js +8 -7
  168. package/dist/react/useErrorListener.d.ts +7 -7
  169. package/dist/react/useErrorListener.js +11 -12
  170. package/dist/react/useMutationFailureListener.d.ts +8 -8
  171. package/dist/react/useMutationFailureListener.js +9 -9
  172. package/dist/react/useMutators.d.ts +11 -11
  173. package/dist/react/useMutators.js +10 -4
  174. package/dist/react/useReactive.js +2 -3
  175. package/dist/react/useSyncStatus.d.ts +4 -6
  176. package/dist/react/useUndoScope.d.ts +7 -9
  177. package/dist/react/useUndoScope.js +3 -3
  178. package/dist/schema/coordination.d.ts +21 -25
  179. package/dist/schema/coordination.js +21 -25
  180. package/dist/schema/ddl.d.ts +43 -39
  181. package/dist/schema/ddl.js +75 -68
  182. package/dist/schema/ddlLock.d.ts +35 -0
  183. package/dist/schema/ddlLock.js +46 -0
  184. package/dist/schema/diff.d.ts +99 -61
  185. package/dist/schema/diff.js +43 -34
  186. package/dist/schema/field.d.ts +37 -42
  187. package/dist/schema/field.js +36 -49
  188. package/dist/schema/generate.d.ts +12 -12
  189. package/dist/schema/generate.js +12 -12
  190. package/dist/schema/index.d.ts +5 -4
  191. package/dist/schema/index.js +29 -21
  192. package/dist/schema/model.d.ts +121 -146
  193. package/dist/schema/model.js +24 -35
  194. package/dist/schema/openapi.d.ts +10 -9
  195. package/dist/schema/openapi.js +7 -1
  196. package/dist/schema/queries.d.ts +30 -32
  197. package/dist/schema/queries.js +24 -25
  198. package/dist/schema/relation.d.ts +89 -99
  199. package/dist/schema/relation.js +13 -13
  200. package/dist/schema/residency.d.ts +38 -0
  201. package/dist/schema/residency.js +30 -0
  202. package/dist/schema/roles.d.ts +45 -27
  203. package/dist/schema/roles.js +52 -21
  204. package/dist/schema/schema.d.ts +36 -45
  205. package/dist/schema/schema.js +42 -39
  206. package/dist/schema/select.d.ts +13 -13
  207. package/dist/schema/select.js +13 -13
  208. package/dist/schema/serialize.d.ts +36 -39
  209. package/dist/schema/serialize.js +27 -31
  210. package/dist/schema/sugar.d.ts +17 -32
  211. package/dist/schema/sugar.js +14 -29
  212. package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +27 -50
  213. package/dist/schema/syncDeltaRow.js +89 -0
  214. package/dist/schema/tenancy.d.ts +44 -46
  215. package/dist/schema/tenancy.js +46 -48
  216. package/dist/server/adapter.d.ts +58 -58
  217. package/dist/server/adapter.js +13 -14
  218. package/dist/server/commit.d.ts +60 -64
  219. package/dist/server/index.d.ts +9 -10
  220. package/dist/server/index.js +1 -1
  221. package/dist/server/readConfig.d.ts +70 -0
  222. package/dist/server/readConfig.js +8 -0
  223. package/dist/server/storageMode.d.ts +23 -0
  224. package/dist/server/storageMode.js +17 -0
  225. package/dist/source/adapter.d.ts +31 -26
  226. package/dist/source/adapter.js +10 -10
  227. package/dist/source/adapters/drizzle.d.ts +28 -23
  228. package/dist/source/adapters/drizzle.js +34 -28
  229. package/dist/source/adapters/kysely.d.ts +27 -25
  230. package/dist/source/adapters/kysely.js +28 -26
  231. package/dist/source/adapters/memory.d.ts +8 -7
  232. package/dist/source/adapters/memory.js +10 -9
  233. package/dist/source/adapters/prisma.d.ts +13 -12
  234. package/dist/source/adapters/prisma.js +27 -29
  235. package/dist/source/conformance.d.ts +18 -11
  236. package/dist/source/conformance.js +27 -19
  237. package/dist/source/connector.d.ts +31 -32
  238. package/dist/source/connector.js +30 -28
  239. package/dist/source/connectorProtocol.d.ts +160 -0
  240. package/dist/source/connectorProtocol.js +162 -0
  241. package/dist/source/contract.d.ts +26 -27
  242. package/dist/source/contract.js +28 -29
  243. package/dist/source/factory.d.ts +94 -0
  244. package/dist/source/factory.js +268 -0
  245. package/dist/source/index.d.ts +10 -462
  246. package/dist/source/index.js +17 -421
  247. package/dist/source/migrations.d.ts +9 -9
  248. package/dist/source/migrations.js +9 -9
  249. package/dist/source/next.d.ts +10 -11
  250. package/dist/source/next.js +7 -8
  251. package/dist/source/pushQueue.d.ts +70 -48
  252. package/dist/source/pushQueue.js +36 -29
  253. package/dist/source/signing.d.ts +88 -0
  254. package/dist/source/signing.js +159 -0
  255. package/dist/source/types.d.ts +351 -0
  256. package/dist/source/types.js +43 -0
  257. package/dist/stores/ObjectStore.d.ts +11 -12
  258. package/dist/stores/ObjectStore.js +34 -35
  259. package/dist/stores/ObjectStoreContract.d.ts +12 -15
  260. package/dist/stores/SyncActionStore.d.ts +8 -12
  261. package/dist/stores/SyncActionStore.js +77 -46
  262. package/dist/surface.d.ts +28 -21
  263. package/dist/surface.js +28 -20
  264. package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +37 -45
  265. package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +101 -80
  266. package/dist/sync/ConnectionManager.d.ts +47 -50
  267. package/dist/sync/ConnectionManager.js +74 -70
  268. package/dist/sync/NetworkProbe.d.ts +27 -31
  269. package/dist/sync/NetworkProbe.js +67 -72
  270. package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +49 -36
  271. package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +79 -54
  272. package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +45 -59
  273. package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +44 -52
  274. package/dist/sync/SyncWebSocket.d.ts +175 -250
  275. package/dist/sync/SyncWebSocket.js +431 -769
  276. package/dist/sync/awaitClaimGrant.d.ts +18 -18
  277. package/dist/sync/awaitClaimGrant.js +38 -30
  278. package/dist/sync/bootstrapApply.d.ts +70 -0
  279. package/dist/sync/bootstrapApply.js +73 -0
  280. package/dist/sync/commitFrames.d.ts +44 -0
  281. package/dist/sync/commitFrames.js +94 -0
  282. package/dist/sync/createClaimStream.d.ts +23 -22
  283. package/dist/sync/createClaimStream.js +108 -25
  284. package/dist/sync/createPresenceStream.d.ts +19 -18
  285. package/dist/sync/createPresenceStream.js +25 -26
  286. package/dist/sync/createSnapshot.d.ts +13 -17
  287. package/dist/sync/createSnapshot.js +20 -26
  288. package/dist/sync/credentialLifecycle.d.ts +175 -0
  289. package/dist/sync/credentialLifecycle.js +322 -0
  290. package/dist/sync/deltaPipeline.d.ts +113 -0
  291. package/dist/sync/deltaPipeline.js +261 -0
  292. package/dist/sync/groupChange.d.ts +113 -0
  293. package/dist/sync/groupChange.js +242 -0
  294. package/dist/sync/heartbeat.d.ts +63 -0
  295. package/dist/sync/heartbeat.js +91 -0
  296. package/dist/sync/participants.d.ts +27 -27
  297. package/dist/sync/schemas.d.ts +3 -2
  298. package/dist/sync/schemas.js +14 -10
  299. package/dist/sync/syncCursor.d.ts +40 -0
  300. package/dist/sync/syncCursor.js +55 -0
  301. package/dist/sync/syncPlan.d.ts +54 -0
  302. package/dist/sync/syncPlan.js +50 -0
  303. package/dist/sync/syncPosition.d.ts +54 -49
  304. package/dist/sync/syncPosition.js +57 -52
  305. package/dist/sync/wsFrameHandlers.d.ts +116 -0
  306. package/dist/sync/wsFrameHandlers.js +374 -0
  307. package/dist/testing/fixtures/bootstrap.d.ts +21 -17
  308. package/dist/testing/fixtures/bootstrap.js +12 -6
  309. package/dist/testing/fixtures/deltas.d.ts +31 -34
  310. package/dist/testing/fixtures/deltas.js +30 -33
  311. package/dist/testing/fixtures/models.d.ts +11 -10
  312. package/dist/testing/fixtures/models.js +12 -10
  313. package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
  314. package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
  315. package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -18
  316. package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +14 -11
  317. package/dist/testing/helpers/wait.d.ts +13 -8
  318. package/dist/testing/helpers/wait.js +13 -8
  319. package/dist/testing/index.d.ts +4 -4
  320. package/dist/testing/index.js +3 -3
  321. package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
  322. package/dist/testing/mocks/MockMutationExecutor.js +15 -14
  323. package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
  324. package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
  325. package/dist/testing/mocks/MockSyncContext.d.ts +21 -34
  326. package/dist/testing/mocks/MockSyncContext.js +16 -45
  327. package/dist/testing/mocks/MockSyncStore.d.ts +14 -14
  328. package/dist/testing/mocks/MockSyncStore.js +11 -11
  329. package/dist/testing/mocks/MockWebSocket.d.ts +28 -24
  330. package/dist/testing/mocks/MockWebSocket.js +22 -21
  331. package/dist/transactions/TransactionQueue.d.ts +190 -221
  332. package/dist/transactions/TransactionQueue.js +424 -822
  333. package/dist/transactions/TransactionStore.d.ts +20 -0
  334. package/dist/transactions/TransactionStore.js +53 -0
  335. package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
  336. package/dist/transactions/UnconfirmedWrites.js +104 -0
  337. package/dist/transactions/coalesceRules.d.ts +58 -0
  338. package/dist/transactions/coalesceRules.js +140 -0
  339. package/dist/transactions/commitPayload.d.ts +130 -0
  340. package/dist/transactions/commitPayload.js +143 -0
  341. package/dist/transactions/deltaConfirmation.d.ts +58 -0
  342. package/dist/transactions/deltaConfirmation.js +215 -0
  343. package/dist/transactions/optimisticApply.d.ts +49 -0
  344. package/dist/transactions/optimisticApply.js +65 -0
  345. package/dist/transactions/replayValidation.d.ts +99 -0
  346. package/dist/transactions/replayValidation.js +111 -0
  347. package/dist/types/global.d.ts +46 -41
  348. package/dist/types/global.js +20 -19
  349. package/dist/types/index.d.ts +74 -80
  350. package/dist/types/index.js +22 -27
  351. package/dist/types/modelData.d.ts +10 -0
  352. package/dist/types/modelData.js +9 -0
  353. package/dist/types/participant.d.ts +20 -0
  354. package/dist/types/participant.js +10 -0
  355. package/dist/types/streams.d.ts +216 -209
  356. package/dist/types/streams.js +7 -7
  357. package/dist/utils/asyncIterator.d.ts +25 -32
  358. package/dist/utils/asyncIterator.js +25 -32
  359. package/dist/utils/duration.d.ts +12 -15
  360. package/dist/utils/duration.js +12 -15
  361. package/dist/utils/mobxSetup.d.ts +53 -0
  362. package/dist/utils/{mobx-setup.js → mobxSetup.js} +44 -100
  363. package/dist/webhooks/events.d.ts +21 -16
  364. package/dist/webhooks/events.js +10 -8
  365. package/dist/webhooks/index.d.ts +5 -7
  366. package/dist/webhooks/index.js +5 -7
  367. package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
  368. package/dist/wire/delta.js +114 -0
  369. package/dist/wire/errorEnvelope.d.ts +35 -27
  370. package/dist/wire/errorEnvelope.js +38 -32
  371. package/dist/wire/frames.d.ts +150 -67
  372. package/dist/wire/frames.js +48 -1
  373. package/dist/wire/index.d.ts +18 -13
  374. package/dist/wire/index.js +36 -13
  375. package/dist/wire/listEnvelope.d.ts +16 -23
  376. package/dist/wire/listEnvelope.js +7 -6
  377. package/dist/wire/protocol.d.ts +38 -0
  378. package/dist/wire/protocol.js +38 -0
  379. package/dist/wire/protocolVersion.d.ts +60 -0
  380. package/dist/wire/protocolVersion.js +67 -0
  381. package/docs/api-keys.md +4 -3
  382. package/docs/coordination.md +59 -0
  383. package/docs/examples/existing-python-backend.md +3 -3
  384. package/docs/identity.md +4 -4
  385. package/docs/integration-guide.md +1 -1
  386. package/docs/react.md +1 -1
  387. package/docs/sessions.md +5 -7
  388. package/package.json +24 -21
  389. package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
  390. package/dist/ai-sdk/coordination-context.d.ts +0 -52
  391. package/dist/client/index.d.ts +0 -36
  392. package/dist/client/index.js +0 -33
  393. package/dist/config/index.d.ts +0 -10
  394. package/dist/config/index.js +0 -12
  395. package/dist/core/query-utils.d.ts +0 -34
  396. package/dist/core/query-utils.js +0 -59
  397. package/dist/interfaces/headless.d.ts +0 -95
  398. package/dist/interfaces/headless.js +0 -41
  399. package/dist/query/index.d.ts +0 -6
  400. package/dist/query/index.js +0 -5
  401. package/dist/realtime/index.d.ts +0 -10
  402. package/dist/realtime/index.js +0 -9
  403. package/dist/schema/plane.d.ts +0 -23
  404. package/dist/schema/plane.js +0 -19
  405. package/dist/schema/sync-delta-row.js +0 -103
  406. package/dist/schema/sync-delta-wire.js +0 -102
  407. package/dist/server/next.d.ts +0 -51
  408. package/dist/server/next.js +0 -47
  409. package/dist/server/read-config.d.ts +0 -67
  410. package/dist/server/read-config.js +0 -8
  411. package/dist/server/storage-mode.d.ts +0 -1
  412. package/dist/server/storage-mode.js +0 -18
  413. package/dist/source/connector-protocol.d.ts +0 -159
  414. package/dist/source/connector-protocol.js +0 -161
  415. package/dist/sync/OfflineFlush.d.ts +0 -9
  416. package/dist/sync/OfflineFlush.js +0 -22
  417. package/dist/sync/OfflineTransactionStore.d.ts +0 -37
  418. package/dist/sync/OfflineTransactionStore.js +0 -263
  419. package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
  420. package/dist/transactions/OptimisticEchoTracker.js +0 -104
  421. package/dist/transactions/index.d.ts +0 -16
  422. package/dist/transactions/index.js +0 -7
  423. package/dist/transactions/mutation-error-handler.d.ts +0 -5
  424. package/dist/transactions/mutation-error-handler.js +0 -39
  425. package/dist/utils/mobx-setup.d.ts +0 -42
@@ -1,39 +1,36 @@
1
1
  /**
2
- * UndoManager per-scope history of reversible mutations.
2
+ * Keeps a per-scope history of reversible changes so a surface can offer undo
3
+ * and redo. Each mutator invocation records an ordered list of inverse
4
+ * operations; `undo()` pops the most recent group and replays those inverses
5
+ * without recording them, then moves the entry onto the redo stack.
3
6
  *
4
- * Each mutator invocation records an ordered list of inverse operations.
5
- * On `undo()` we pop the last group and apply the inverses as a non-recorded
6
- * transaction (so the inverse itself doesn't push to the redo stack; we do
7
- * that explicitly below).
7
+ * History is divided into named scopes, one per surface — a deck editor, a
8
+ * spreadsheet, and so on reached through {@link UndoManager.getScope}. Undo in
9
+ * one surface never affects another.
8
10
  *
9
- * Scopes: every consumer (deck editor, spreadsheet, etc.) gets a named scope
10
- * via `getScope(name)`. Cmd+Z in one surface never affects another.
11
- *
12
- * V1 limitations:
13
- * - No persistence across sessions (in-memory stack).
14
- * - No collaborative awareness — undoing after a teammate edited the same
15
- * row produces a "last writer wins" outcome, not a true merge.
16
- * - Server-side mutation rejection after optimistic apply does NOT
17
- * automatically invalidate the undo stack. Consumers should `clear()`
18
- * the scope on sync error if they want strict correctness.
11
+ * Two things to know about its reach. History lives in memory and does not
12
+ * persist across sessions. And if the server rejects a change after it was
13
+ * applied optimistically, the undo stack is not invalidated automatically; call
14
+ * {@link UndoScope.clear} on a sync error if you need strict correctness.
19
15
  */
20
16
  import { getContext } from '../context.js';
21
17
  import { createTransaction } from './Transaction.js';
22
18
  import { parseUndoEntry } from './inverseOp.js';
23
19
  import { resolveOps, DEFAULT_UNDO_CONFLICT_POLICY, } from './undoApply.js';
24
- /** Normalize a registered model name to the queue's lowercased alias form
25
- * (mirrors TransactionQueue's `normalizeModelKey`). */
20
+ /** Normalize a registered model name to its lowercased alias form. */
26
21
  const normalizeModelAlias = (modelName) => modelName.replace('Model', '').toLowerCase();
27
22
  /**
28
- * A single undo stack for one surface. Access via `UndoManager.getScope(name)`.
29
- * Consumers call `record(entry)` after each mutator; `undo()` / `redo()` to
30
- * traverse the stacks.
23
+ * A single undo stack for one surface, obtained from
24
+ * {@link UndoManager.getScope}. Call {@link UndoScope.record} after a mutator to
25
+ * add an entry, and {@link UndoScope.undo} / {@link UndoScope.redo} to move
26
+ * through the history.
31
27
  */
32
28
  /**
33
- * How long a marked replay-echo stays armed before it's pruned. The real echo
34
- * arrives within a couple of IndexedDB round-trips (tens of ms); this is a
35
- * generous safety ceiling so a never-arriving echo (e.g. the commit was skipped
36
- * offline) can't suppress a genuine later edit to the same row indefinitely.
29
+ * How long a pending replay-echo marker stays armed before it is pruned. A real
30
+ * echo returns within a couple of local-store round-trips (tens of milliseconds);
31
+ * this is a generous ceiling so that an echo which never arrives for instance,
32
+ * because the write was skipped while offline cannot suppress a genuine later
33
+ * edit to the same row indefinitely.
37
34
  */
38
35
  const REPLAY_ECHO_TTL_MS = 5000;
39
36
  export class UndoScope {
@@ -45,36 +42,34 @@ export class UndoScope {
45
42
  maxHistory;
46
43
  conflictPolicy;
47
44
  /**
48
- * Observers notified after each successful {@link record}. These see FORWARD
49
- * user actions only `undo()`/`redo()` replays move entries between stacks
50
- * without calling `record()`, so a listener never observes a reversal. This
51
- * is a deliberately domain-agnostic seam: analytics, gamification, and audit
52
- * can tap the committed-mutation stream without the scope knowing about them.
53
- * A throwing listener is isolated (see {@link emitRecord}) so a faulty
54
- * observer can never wedge the editor's recording path.
45
+ * Observers notified after each successful {@link UndoScope.record}. They see
46
+ * forward user actions only: undo and redo move entries between the stacks
47
+ * without calling `record`, so a listener never observes a reversal. It is a
48
+ * deliberately generic hook analytics or audit code can watch the stream of
49
+ * committed mutations without the scope knowing about it. A listener that throws
50
+ * is isolated so it cannot break recording.
55
51
  */
56
52
  recordListeners = new Set();
57
53
  /**
58
- * Observers notified after ANY stack change — record, undo, redo, or clear.
59
- * Distinct from {@link recordListeners} (forward actions only): this fires on
60
- * reversals too, so React consumers can keep `canUndo`/`canRedo` live. The
61
- * stream-recording path pushes entries WITHOUT a React render, so without this
62
- * a freshly-recorded entry leaves `canUndo` stale (snapshot from last render)
63
- * and a Cmd+Z handler gated on `canUndo !== false` silently no-ops.
54
+ * Observers notified after any stack change — record, undo, redo, or clear.
55
+ * Unlike {@link recordListeners}, which fires on forward actions only, this
56
+ * fires on reversals too, so a React consumer can keep `canUndo` and `canRedo`
57
+ * current. Because the stream-recording path adds entries without triggering a
58
+ * render, a component that read `canUndo` on its last render would otherwise go
59
+ * stale and a keyboard handler gated on it would quietly do nothing.
64
60
  */
65
61
  changeListeners = new Set();
66
62
  /**
67
- * Serialization tail. Recording, undo, and redo all chain off this single
68
- * promise so they run strictly in the order they were *invoked* never
69
- * interleaved. This is load-bearing for correctness, not just throughput:
70
- * - Ordering: callers fire writes un-awaited (`void mutations.x.update`).
71
- * Without serialization, an entry lands on the stack when its mutator
72
- * *resolves*, so a fast second write can record before a slow first one
73
- * undo replays in the wrong order.
74
- * - Snapshot integrity: every recording reads/clears the shared models'
75
- * `modifiedProperties` (the undo "before" baseline). Two recordings
76
- * interleaving on the same model corrupt each other's inverse snapshot.
77
- * Serializing the whole scope closes both holes with one mechanism.
63
+ * The serialization tail. Recording, undo, and redo all chain off this one
64
+ * promise, so they run strictly in the order they were invoked and never
65
+ * interleave. This matters for correctness, not just throughput, in two ways.
66
+ * Ordering: callers often fire writes without awaiting them, so without
67
+ * serialization an entry would land on the stack when its mutator resolves, and
68
+ * a fast second write could record before a slow first — replaying undo in the
69
+ * wrong order. Snapshot integrity: each recording reads and clears a model's
70
+ * modified-field markers, which form the undo baseline, so two recordings
71
+ * interleaving on the same model would corrupt each other's before-image.
72
+ * Serializing the whole scope closes both gaps at once.
78
73
  */
79
74
  tail = Promise.resolve();
80
75
  /** Predicate selecting which models this surface records (see options). */
@@ -84,37 +79,37 @@ export class UndoScope {
84
79
  /** Unsubscribe from the local-mutation stream. */
85
80
  unsubscribe;
86
81
  /**
87
- * True while `undo()`/`redo()` replays ops. Replays write through the same
88
- * commit path, so they re-emit on the local-mutation stream; this flag tells
89
- * our own listener to ignore them (no echo) the engine equivalent of Yjs's
90
- * `trackedOrigins` exclusion / Liveblocks pausing history during undo.
82
+ * True while undo or redo is replaying operations. A replay writes through the
83
+ * normal commit path and therefore re-emits on the local-mutation stream; this
84
+ * flag tells the scope's own listener to ignore those writes so they are not
85
+ * recorded again.
91
86
  */
92
87
  replaying = false;
93
- /** Ops collected during the current tick, flushed as ONE entry. */
88
+ /** Operations collected during the current tick, flushed together as one entry. */
94
89
  batch = [];
95
90
  flushScheduled = false;
96
91
  /**
97
- * Open grouping session (Liveblocks `history.pause()` / Yjs `stopCapturing`
98
- * analogue). While set, stream ops accumulate here ACROSS ticks instead of
99
- * flushing per-tick, so a multi-tick action (a drag, a whole streaming AI
100
- * response) collapses into ONE Cmd+Z. `endGroup()` flushes it.
92
+ * An open grouping session. While set, stream operations accumulate here across
93
+ * ticks instead of flushing each tick, so a multi-tick action a drag, or a
94
+ * whole streaming AI response collapses into a single undo step.
95
+ * {@link UndoScope.endGroup} flushes it.
101
96
  */
102
97
  group = null;
103
98
  /**
104
- * ASYNC replay-echo suppression, keyed by `${modelKey}:${id}`.
99
+ * Suppression of a replay's asynchronous echo, keyed by `${modelKey}:${id}`.
105
100
  *
106
- * The synchronous {@link replaying} flag only catches echoes delivered INLINE
107
- * during `applyOps`. The real engine doesn't emit `transaction:created`
108
- * synchronously: `SyncClient` defers the commit behind `scheduleSync()` +
109
- * `await persistMutationQueue()` (an IndexedDB write), so a replayed write's
110
- * echo lands on the stream AFTER `undo()`/`redo()` has already reset
111
- * `replaying` and pushed the entry. That late echo would be recorded as a
112
- * NEW edit and `record()` clears the redo stack, so every undo silently
113
- * destroyed its own redo. We mark the (modelKey,id) of every op we're about
114
- * to replay here (synchronously, before the write), and consume one mark when
115
- * the matching mutation arrives — independent of WHEN it arrives. Entries
116
- * carry a TTL so a never-arriving echo (offline: the commit is skipped) can't
117
- * leak and wrongly suppress a much-later genuine edit to the same row.
101
+ * The synchronous {@link UndoScope.replaying} flag catches only echoes
102
+ * delivered inline while operations are applied. In practice the engine does not
103
+ * emit a replayed write's echo synchronously: the commit is deferred behind a
104
+ * local-store write, so the echo arrives on the stream after undo or redo has
105
+ * already reset `replaying` and pushed its entry. That late echo would be
106
+ * recorded as a new edit and recording clears the redo stack, so every undo
107
+ * would quietly destroy its own redo. To prevent that, the row of each operation
108
+ * about to be replayed is marked here synchronously, before the write, and one
109
+ * mark is consumed when the matching mutation arrives, whenever that is. Marks
110
+ * carry a time-to-live so an echo that never arrives — because the write was
111
+ * skipped while offline cannot linger and wrongly suppress a much later, real
112
+ * edit to the same row.
118
113
  */
119
114
  pendingReplayEchoes = new Map();
120
115
  constructor(schema, store, organizationId, options = {}) {
@@ -124,10 +119,10 @@ export class UndoScope {
124
119
  this.maxHistory = options.maxHistory ?? 100;
125
120
  this.conflictPolicy = options.conflictPolicy ?? DEFAULT_UNDO_CONFLICT_POLICY;
126
121
  this.tracksModel = options.tracksModel;
127
- // Build the registered-name schema-key alias map. The mutation stream
128
- // reports `model.getModelName()` (e.g. `'SlideLayer'`), but inverse ops
129
- // and the replay transaction are keyed by the SCHEMA key (e.g.
130
- // `'slideLayers'`). Map every reasonable spelling to the schema key.
122
+ // Build the map from registered name to schema key. The mutation stream
123
+ // reports a model's registered name (for example `'SlideLayer'`), but inverse
124
+ // operations and the replay transaction are keyed by the schema key (for
125
+ // example `'slideLayers'`), so map every reasonable spelling to the schema key.
131
126
  for (const schemaKey of Object.keys(this.schema.models)) {
132
127
  const def = this.schema.models[schemaKey];
133
128
  const typename = def?.typename ?? schemaKey;
@@ -137,23 +132,21 @@ export class UndoScope {
137
132
  this.schemaKeyByAlias.set(normalizeModelAlias(alias), schemaKey);
138
133
  }
139
134
  }
140
- // Subscribe to the local-mutation stream ONLY when this scope opts into
141
- // stream recording. Transitional flag: surfaces still on the legacy
142
- // manual-record path (mutator `RecordingTransaction`, AI pipeline
143
- // sessions) keep `recordFromStream: false` so writes aren't double-counted.
144
- // Once every surface is migrated, stream recording becomes the only path
145
- // and the flag is removed. Optional on the contract so minimal test
146
- // doubles can omit it (undo then records nothing).
135
+ // Subscribe to the local-mutation stream only when this scope opts into
136
+ // stream recording. A scope using explicit `record()` calls instead keeps
137
+ // `recordFromStream` false so writes are not counted twice. The stream method
138
+ // on the store is optional, so a minimal test double can omit it, in which
139
+ // case undo records nothing.
147
140
  this.unsubscribe =
148
141
  options.recordFromStream && this.store.subscribeLocalMutations
149
- ? this.store.subscribeLocalMutations((m) => this.onLocalMutation(m))
142
+ ? this.store.subscribeLocalMutations((m) => { this.onLocalMutation(m); })
150
143
  : () => { };
151
144
  }
152
145
  /**
153
- * Open a grouping session: every stream-recorded op until {@link endGroup}
154
- * collapses into a single undo entry. Mirrors Liveblocks `history.pause()`
155
- * call on gesture start (pointerdown) or AI-response start. Idempotent-ish:
156
- * a second call closes the previous group first.
146
+ * Opens a grouping session: every stream-recorded operation until
147
+ * {@link UndoScope.endGroup} collapses into one undo entry. Call it at the start
148
+ * of a gesture, such as a pointer-down, or at the start of an AI response. A
149
+ * second call closes the previous group first.
157
150
  */
158
151
  beginGroup(label) {
159
152
  if (this.group)
@@ -210,9 +203,9 @@ export class UndoScope {
210
203
  }
211
204
  }
212
205
  /**
213
- * Arm async-echo suppression for the rows a replay is about to write. Called
214
- * synchronously, before `applyOps`, so the marks exist no matter how long the
215
- * engine takes to surface the echo on the stream. See {@link pendingReplayEchoes}.
206
+ * Arms echo suppression for the rows a replay is about to write. Called
207
+ * synchronously, before the writes, so the marks exist however long the engine
208
+ * takes to surface each echo on the stream. See {@link UndoScope.pendingReplayEchoes}.
216
209
  */
217
210
  markReplayEchoes(ops) {
218
211
  const expiresAt = Date.now() + REPLAY_ECHO_TTL_MS;
@@ -228,9 +221,9 @@ export class UndoScope {
228
221
  }
229
222
  }
230
223
  /**
231
- * If `${schemaKey}:${modelId}` has an armed echo mark, consume one and report
232
- * that this mutation is our own replay echo (caller drops it). Prunes expired
233
- * marks opportunistically so a skipped/never-arriving echo can't leak.
224
+ * If `${schemaKey}:${modelId}` has an armed mark, consume one and report that
225
+ * this mutation is the scope's own replay echo, so the caller drops it. Expired
226
+ * marks are pruned along the way, so an echo that never arrives cannot linger.
234
227
  */
235
228
  consumeReplayEcho(schemaKey, modelId) {
236
229
  if (this.pendingReplayEchoes.size === 0)
@@ -256,11 +249,11 @@ export class UndoScope {
256
249
  null);
257
250
  }
258
251
  /**
259
- * Stream listener the sole place entries are born. Skips replay echoes
260
- * and out-of-scope models, derives the forward+inverse op from the
261
- * mutation's `data`/`previousData`, and defers the stack push to a
262
- * per-tick flush so a burst of writes (e.g. align 5 layers) becomes ONE
263
- * undo step riding the same tick boundary the TransactionQueue batches on.
252
+ * The stream listener, and the only place stream-recorded entries originate. It
253
+ * skips replay echoes and out-of-scope models, derives the forward and inverse
254
+ * operations from the mutation's `data` and `previousData`, and defers the stack
255
+ * push to a per-tick flush, so a burst of writes aligning five layers at once,
256
+ * saybecomes a single undo step.
264
257
  */
265
258
  onLocalMutation(m) {
266
259
  if (this.replaying)
@@ -309,7 +302,7 @@ export class UndoScope {
309
302
  const collected = this.batch;
310
303
  this.batch = [];
311
304
  const forwards = collected.map((c) => c.forward);
312
- // Undo applies inverses in REVERSE order of how the forwards ran.
305
+ // Undo applies the inverses in reverse order of how the forwards ran.
313
306
  const inverses = collected
314
307
  .map((c) => c.inverse)
315
308
  .filter((i) => i !== null)
@@ -330,27 +323,25 @@ export class UndoScope {
330
323
  return result;
331
324
  }
332
325
  /**
333
- * Run a recording mutator exclusively on the scope's serialization chain.
334
- * Used by the legacy manual-record path (`useMutators` + `RecordingTransaction`)
335
- * so the snapshot write `record()` sequence is atomic relative to undo/
336
- * redo. The stream-recording path doesn't need this (it derives entries from
337
- * already-committed mutations); kept until all surfaces migrate off manual.
326
+ * Runs a recording mutator by itself on the scope's serialization chain, so its
327
+ * snapshot, write, and {@link UndoScope.record} happen atomically with respect to
328
+ * undo and redo. This is used by the explicit-record path; the stream-recording
329
+ * path does not need it, since it derives entries from already-committed
330
+ * mutations.
338
331
  */
339
332
  runRecorded(work) {
340
333
  return this.enqueue(work);
341
334
  }
342
335
  /**
343
- * Record one entry onto the undo stack. Clears the redo stack. Fed by
344
- * {@link flushBatch}/{@link endGroup} from the local-mutation stream, and
345
- * still called directly by the legacy manual-record consumers
346
- * (`useMutators`, the AI mutation pipeline) until they migrate. Entries are
347
- * built internally (trusted), so the schema check is DEV-ONLY: it catches
348
- * recorder bugs in dev/test (rejecting a malformed op at ingestion, with its
349
- * path, instead of letting it crash later inside `applyOps`) without paying a
350
- * Zod parse on every user action in production. The real validation boundary
351
- * is `parseUndoEntry`, applied when entries are deserialized from persistence
352
- * (untrusted input). Best practice: validate at trust boundaries, type-check
353
- * internal calls.
336
+ * Records one entry onto the undo stack and clears the redo stack. It is fed
337
+ * both by the per-tick flush and grouping paths from the local-mutation stream
338
+ * and by direct callers using explicit recording. Entries are built internally
339
+ * and therefore trusted, so the schema check here runs only outside production:
340
+ * it catches recorder bugs early, rejecting a malformed operation at ingestion
341
+ * with a clear path rather than letting it fail later during replay, without
342
+ * paying a validation cost on every user action in production. The real
343
+ * validation boundary is {@link parseUndoEntry}, applied to entries loaded from
344
+ * persistence, which is untrusted input.
354
345
  */
355
346
  record(entry) {
356
347
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
@@ -364,13 +355,11 @@ export class UndoScope {
364
355
  this.emitChange();
365
356
  }
366
357
  /**
367
- * Subscribe to every recorded mutation. Fires synchronously at the tail of
368
- * each {@link record} call, after the entry is on the undo stack. Returns an
369
- * unsubscribe function call it on teardown.
370
- *
371
- * Listeners receive the full {@link UndoEntry} (its `forwards` carry the
372
- * `{ kind, modelKey, data }` ops), so a consumer can derive what changed
373
- * (e.g. "a slideLayers row of type 'chart' was created") without re-querying.
358
+ * Subscribes to every recorded mutation. The listener fires synchronously at the
359
+ * end of each {@link UndoScope.record} call, once the entry is on the undo stack,
360
+ * and the returned function unsubscribes it. The listener receives the full
361
+ * {@link UndoEntry} — its `forwards` carry the `{ kind, modelKey, data }`
362
+ * operations so a consumer can tell what changed without querying again.
374
363
  */
375
364
  onRecord(listener) {
376
365
  this.recordListeners.add(listener);
@@ -384,18 +373,17 @@ export class UndoScope {
384
373
  listener(entry);
385
374
  }
386
375
  catch (err) {
387
- // A faulty observer must never break the editor's recording path.
388
- // Routed through the gated logger; the consumer's own onRecord callback
389
- // is at fault, so this is actionable → warn (no engine tag on the line).
376
+ // A faulty observer must never break the recording path. The consumer's
377
+ // own onRecord callback is at fault, so log it as an actionable warning.
390
378
  getContext().logger.warn('An undo/redo onRecord listener threw — your callback should not throw', err);
391
379
  }
392
380
  }
393
381
  }
394
382
  /**
395
- * Subscribe to ANY stack change (record/undo/redo/clear). Used by
396
- * `useUndoScope` to re-render so `canUndo`/`canRedo` stay live across every
397
- * consumer not just the component that invoked undo/redo. Returns an
398
- * unsubscribe function.
383
+ * Subscribes to any stack change record, undo, redo, or clear. The React
384
+ * `useUndoScope` hook uses this to re-render so `canUndo` and `canRedo` stay
385
+ * current for every consumer, not only the component that invoked undo or redo.
386
+ * The returned function unsubscribes.
399
387
  */
400
388
  onChange(listener) {
401
389
  this.changeListeners.add(listener);
@@ -409,8 +397,8 @@ export class UndoScope {
409
397
  listener();
410
398
  }
411
399
  catch (err) {
412
- // Consumer's own onChange callback is at fault actionable warn,
413
- // routed through the gated logger (no engine tag on the line).
400
+ // The consumer's own onChange callback is at fault, so log it as an
401
+ // actionable warning.
414
402
  getContext().logger.warn('An undo/redo onChange listener threw — your callback should not throw', err);
415
403
  }
416
404
  }
@@ -422,12 +410,11 @@ export class UndoScope {
422
410
  return this.redoStack.length > 0;
423
411
  }
424
412
  /**
425
- * Pop the last mutator and apply its inverses. Pushes to redo.
426
- *
427
- * Under the default `skip-stale` policy the inverses are filtered against
428
- * live state first (paired with the entry's forwards = "what I set"), so a
429
- * field a collaborator changed after my op is left untouched undo reverts
430
- * my change only where it still stands.
413
+ * Pops the most recent entry, applies its inverse operations, and pushes it onto
414
+ * the redo stack. Under the default `skip-stale` policy the inverses are first
415
+ * filtered against the current state paired with the entry's forwards, which
416
+ * record what this change set so a field a collaborator changed afterward is
417
+ * left untouched, and undo reverts the change only where it still stands.
431
418
  */
432
419
  undo() {
433
420
  return this.enqueue(async () => {
@@ -436,19 +423,19 @@ export class UndoScope {
436
423
  return;
437
424
  const tx = createTransaction(this.schema, this.store, this.organizationId);
438
425
  const ops = resolveOps(entry.inverses, entry.forwards, this.store, this.conflictPolicy);
439
- // Suppress our own stream listener so replayed writes don't record as
440
- // new undo entries. `replaying` covers inline echoes; `markReplayEchoes`
441
- // covers the engine's async (IDB-gated) echo that lands after this method
442
- // returns. Cleared in `finally` even if a replay op throws.
426
+ // Suppress the scope's own stream listener so replayed writes are not
427
+ // recorded as new entries. `replaying` covers echoes delivered inline;
428
+ // `markReplayEchoes` covers the asynchronous echo that lands after this
429
+ // method returns. Cleared in `finally` even if a replay throws.
443
430
  this.markReplayEchoes(ops);
444
431
  this.replaying = true;
445
432
  try {
446
433
  await applyOps(tx, ops);
447
434
  }
448
435
  catch (err) {
449
- // The replay was rejected (e.g. a server 409): the world didn't change,
450
- // so restore the entry to the undo stack rather than silently dropping
451
- // it (which would also strand it off the redo stack invisible undo).
436
+ // The replay was rejected (for example, a server 409). Nothing changed,
437
+ // so restore the entry to the undo stack rather than dropping it, which
438
+ // would also strand it off the redo stack and lose the action entirely.
452
439
  this.undoStack.push(entry);
453
440
  this.emitChange();
454
441
  throw err;
@@ -463,10 +450,11 @@ export class UndoScope {
463
450
  });
464
451
  }
465
452
  /**
466
- * Pop the last undone entry and re-apply the forward ops. Pushes to undo.
467
- * Symmetric to {@link undo}: forwards are filtered against live state
468
- * (paired with the entry's inverses = "what undo restored"), so redo
469
- * re-asserts my change only where the undone value still stands.
453
+ * Pops the most recently undone entry, re-applies its forward operations, and
454
+ * pushes it onto the undo stack. It mirrors {@link UndoScope.undo}: the forwards
455
+ * are filtered against the current state — paired with the entry's inverses,
456
+ * which record what undo restored — so redo re-asserts the change only where the
457
+ * undone value still stands.
470
458
  */
471
459
  redo() {
472
460
  return this.enqueue(async () => {
@@ -523,9 +511,9 @@ export class UndoScope {
523
511
  }
524
512
  }
525
513
  /**
526
- * Derive the forward + inverse op for a single local mutation. Returns null
527
- * when the mutation can't be reversed (e.g. an update with no captured
528
- * previous values), so the caller can drop it rather than push a half-entry.
514
+ * Derives the forward and inverse operation for a single local mutation. Returns
515
+ * null when the mutation cannot be reversed for example, an update with no
516
+ * captured previous values so the caller drops it rather than push a half-entry.
529
517
  */
530
518
  function buildUndoOps(m, modelKey) {
531
519
  const id = m.modelId;
@@ -572,8 +560,9 @@ function buildUndoOps(m, modelKey) {
572
560
  }
573
561
  // ── Manager ────────────────────────────────────────────────────────────────
574
562
  /**
575
- * Central registry of named undo scopes. One per-app instance, created once
576
- * during engine setup. Mutator invocations find their scope by name.
563
+ * The registry of named undo scopes. One instance is created per application
564
+ * during engine setup, and each surface finds its scope by name through
565
+ * {@link UndoManager.getScope}.
577
566
  */
578
567
  export class UndoManager {
579
568
  schema;
@@ -600,14 +589,19 @@ export class UndoManager {
600
589
  }
601
590
  // ── Internal helpers ───────────────────────────────────────────────────────
602
591
  /**
603
- * Replay a list of InverseOps through a Transaction. Used by both undo
604
- * (replaying captured inverses) and redo (replaying the captured forwards).
605
- * Every op is awaited sequentially to preserve ordering guarantees.
592
+ * Replays a list of operations through a {@link Transaction}. Used by both undo,
593
+ * which replays the captured inverses, and redo, which replays the captured
594
+ * forwards. Each operation is awaited in turn to preserve ordering.
606
595
  */
607
596
  async function applyOps(tx, ops) {
608
597
  const mutateAny = tx.mutations;
609
598
  for (const op of ops) {
610
599
  const m = mutateAny[op.modelKey];
600
+ if (!m) {
601
+ // A persisted inverse op references a model the schema no longer has;
602
+ // fail with a clear message rather than an opaque TypeError.
603
+ throw new Error(`Cannot undo: model "${op.modelKey}" is not part of the current schema.`);
604
+ }
611
605
  switch (op.kind) {
612
606
  case 'create':
613
607
  await m.create(op.data);
@@ -1,55 +1,42 @@
1
1
  /**
2
- * defineMutators Zero-style custom mutator declaration.
2
+ * Declares a tree of named custom mutators grouped by model key. Each mutator is
3
+ * a plain async function that receives `{ tx, args }` and composes any number of
4
+ * `tx.mutations.*` and `tx.read.*` calls to carry out a named operation, such as
5
+ * `slides.createWithLayers`.
3
6
  *
4
- * Consumers declare a tree of named mutators grouped by model key. Each
5
- * mutator is a plain async function that receives `{ tx, args }`. The body
6
- * composes any number of `tx.mutate.*` / `tx.read.*` calls to implement a
7
- * named operation (e.g. `slides.createWithLayers`).
8
- *
9
- * This file is pure type scaffolding + a pass-through factory. The runtime
10
- * dispatcher lives in `./Transaction` (the `tx` object) and
11
- * `../react/useMutators` (the React-side invoker builder). Keeping those
12
- * concerns separate makes the types trivially inferable at the call site:
13
- * `defineMutators(schema, { ... })` returns the literal object the consumer
14
- * wrote, so `typeof mutators` carries every mutator's exact `args`/result
15
- * signature into `useMutators`.
7
+ * The function is purely a place for types to anchor and returns its input
8
+ * unchanged; the runtime that dispatches a mutator lives elsewhere the
9
+ * transaction object it receives and the React hook that invokes it. Because
10
+ * `defineMutators(schema, { ... })` returns the exact object you wrote,
11
+ * `typeof mutators` carries every mutator's precise `args` and result types
12
+ * through to wherever they are invoked.
16
13
  */
17
14
  import type { Schema } from '../schema/schema.js';
18
15
  import type { Transaction } from './Transaction.js';
19
16
  /**
20
- * Signature of a single custom mutator. The host injects `tx`; the consumer
21
- * controls `args` (whatever shape they want) and the resolved return value.
22
- *
23
- * We bound `TArgs`/`TResult` with `unknown` rather than `any` so consumers
24
- * opt into the inference they need — the `MutatorDefs` record relaxes to
25
- * `unknown` to let heterogeneous mutator trees unify without `any`.
17
+ * The signature of a single custom mutator. The engine supplies `tx`; you control
18
+ * `args`, in whatever shape you like, and the resolved return value. `TArgs` and
19
+ * `TResult` are bounded by `unknown` rather than `any`, so a mixed tree of
20
+ * mutators can be typed together without falling back to `any`.
26
21
  */
27
22
  export type MutatorFn<S extends Schema, TArgs, TResult = void> = (options: {
28
23
  tx: Transaction<S>;
29
24
  args: TArgs;
30
25
  }) => Promise<TResult>;
31
26
  /**
32
- * The shape `defineMutators` accepts: an optional record per model key whose
33
- * values are named mutator functions.
34
- *
35
- * We intentionally use `unknown` in the bounds rather than `any` to preserve
36
- * type-safety at the public API boundary. When a consumer writes their
37
- * mutators inline, TypeScript infers the concrete `TArgs`/`TResult` for each
38
- * function — the `unknown` here is just a ceiling, not what the consumer
39
- * ends up seeing.
27
+ * The shape {@link defineMutators} accepts: an optional record per model key
28
+ * whose values are named mutator functions. The `unknown` bounds keep the public
29
+ * boundary type-safe without `any`; when you write your mutators inline,
30
+ * TypeScript still infers the concrete `args` and result of each function, so the
31
+ * `unknown` here is only a ceiling, not what you end up working with.
40
32
  */
41
33
  export type MutatorDefs<S extends Schema> = {
42
- [K in keyof S['models']]?: {
43
- [mutatorName: string]: MutatorFn<S, never, unknown>;
44
- };
34
+ [K in keyof S['models']]?: Record<string, MutatorFn<S, never, unknown>>;
45
35
  };
46
36
  /**
47
- * Identity function that forwards the mutators object while constraining its
48
- * shape against the schema. The `S` generic pins model keys; the `M` generic
49
- * is `const`-inferred so each mutator's literal signature survives.
50
- *
51
- * Pattern mirrors Zero's own `defineMutators` / `createBuilder` — there is
52
- * no runtime work to do here, it's purely a location for type inference to
53
- * anchor.
37
+ * Returns the mutators object unchanged while constraining its shape against the
38
+ * schema. The `S` generic pins the model keys, and the `M` generic is inferred as
39
+ * a `const`, so each mutator's literal signature survives. There is no runtime
40
+ * work here; the function exists purely as a place for type inference to anchor.
54
41
  */
55
42
  export declare function defineMutators<S extends Schema, const M extends MutatorDefs<S>>(_schema: S, mutators: M): M;