@abloatai/ablo 0.35.0 → 0.37.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 (622) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +71 -1929
  3. package/NOTICE +2 -2
  4. package/README.md +23 -532
  5. package/assets/banner.png +0 -0
  6. package/dist/auth.d.ts +2 -0
  7. package/dist/auth.d.ts.map +1 -0
  8. package/dist/auth.js +2 -0
  9. package/dist/auth.js.map +1 -0
  10. package/dist/client.d.ts +3 -0
  11. package/dist/client.d.ts.map +1 -0
  12. package/dist/client.js +3 -0
  13. package/dist/client.js.map +1 -0
  14. package/dist/coordination.d.ts +2 -0
  15. package/dist/coordination.d.ts.map +1 -0
  16. package/dist/coordination.js +2 -0
  17. package/dist/coordination.js.map +1 -0
  18. package/dist/index.d.ts +3 -112
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +3 -161
  21. package/dist/index.js.map +1 -0
  22. package/dist/react.d.ts +4 -0
  23. package/dist/react.d.ts.map +1 -0
  24. package/dist/react.js +3 -0
  25. package/dist/react.js.map +1 -0
  26. package/dist/schema.d.ts +2 -0
  27. package/dist/schema.d.ts.map +1 -0
  28. package/dist/schema.js +2 -0
  29. package/dist/schema.js.map +1 -0
  30. package/dist/server.d.ts +2 -0
  31. package/dist/server.d.ts.map +1 -0
  32. package/dist/server.js +2 -0
  33. package/dist/server.js.map +1 -0
  34. package/dist/source-conformance.d.ts +2 -0
  35. package/dist/source-conformance.d.ts.map +1 -0
  36. package/dist/source-conformance.js +2 -0
  37. package/dist/source-conformance.js.map +1 -0
  38. package/dist/source-drizzle.d.ts +2 -0
  39. package/dist/source-drizzle.d.ts.map +1 -0
  40. package/dist/source-drizzle.js +2 -0
  41. package/dist/source-drizzle.js.map +1 -0
  42. package/dist/source-kysely.d.ts +2 -0
  43. package/dist/source-kysely.d.ts.map +1 -0
  44. package/dist/source-kysely.js +2 -0
  45. package/dist/source-kysely.js.map +1 -0
  46. package/dist/source-next.d.ts +2 -0
  47. package/dist/source-next.d.ts.map +1 -0
  48. package/dist/source-next.js +2 -0
  49. package/dist/source-next.js.map +1 -0
  50. package/dist/source.d.ts +2 -0
  51. package/dist/source.d.ts.map +1 -0
  52. package/dist/source.js +2 -0
  53. package/dist/source.js.map +1 -0
  54. package/dist/wire.d.ts +2 -0
  55. package/dist/wire.d.ts.map +1 -0
  56. package/dist/wire.js +2 -0
  57. package/dist/wire.js.map +1 -0
  58. package/docs/agents.md +2 -2
  59. package/docs/api-keys.md +13 -12
  60. package/docs/api.md +15 -53
  61. package/docs/audit.md +4 -3
  62. package/docs/cli.md +11 -11
  63. package/docs/client-behavior.md +9 -9
  64. package/docs/concurrency-convention.md +28 -42
  65. package/docs/coordination.md +228 -86
  66. package/docs/data-sources.md +5 -5
  67. package/docs/debugging.md +34 -12
  68. package/docs/deployment.md +8 -8
  69. package/docs/examples/agent-human.md +4 -4
  70. package/docs/examples/ai-sdk-tool.md +1 -1
  71. package/docs/examples/existing-python-backend.md +15 -4
  72. package/docs/examples/nextjs.md +27 -6
  73. package/docs/examples/scoped-agent.md +3 -3
  74. package/docs/examples/server-agent.md +2 -2
  75. package/docs/groups.md +57 -3
  76. package/docs/guarantees.md +37 -10
  77. package/docs/how-it-works.md +32 -8
  78. package/docs/idempotency.md +6 -6
  79. package/docs/identity.md +24 -24
  80. package/docs/index.md +8 -8
  81. package/docs/integration-guide.md +38 -16
  82. package/docs/internal/README.md +18 -0
  83. package/docs/internal/agent-fleet-coordination-design.md +171 -0
  84. package/docs/internal/agent-orchestration.md +58 -0
  85. package/docs/internal/commit-identifiers.md +91 -0
  86. package/docs/internal/concurrency-open-decisions.md +37 -0
  87. package/docs/internal/data-source-reverse-channel.md +150 -0
  88. package/docs/internal/per-field-conflict-detection.md +165 -0
  89. package/docs/internal/postgres-replication.md +64 -0
  90. package/docs/internal/serializable-schema.md +119 -0
  91. package/docs/internal/structure.md +32 -0
  92. package/docs/mcp.md +9 -9
  93. package/docs/migration.md +37 -18
  94. package/docs/projects.md +1 -1
  95. package/docs/quickstart.md +2 -2
  96. package/docs/react.md +24 -13
  97. package/docs/schema-contract.md +3 -3
  98. package/docs/sessions.md +91 -37
  99. package/docs/webhooks.md +9 -9
  100. package/examples/README.md +2 -2
  101. package/examples/data-source/README.md +1 -1
  102. package/examples/data-source/ablo-driver.ts +1 -1
  103. package/examples/data-source/customer-server.ts +1 -1
  104. package/examples/data-source/run.ts +1 -1
  105. package/examples/data-source/schema.ts +1 -1
  106. package/examples/quickstart.ts +2 -2
  107. package/llms.txt +12 -12
  108. package/package.json +64 -174
  109. package/dist/BaseSyncedStore.d.ts +0 -823
  110. package/dist/BaseSyncedStore.js +0 -1955
  111. package/dist/Database.d.ts +0 -335
  112. package/dist/Database.js +0 -1500
  113. package/dist/InstanceCache.d.ts +0 -233
  114. package/dist/InstanceCache.js +0 -1164
  115. package/dist/LazyReferenceCollection.d.ts +0 -177
  116. package/dist/LazyReferenceCollection.js +0 -461
  117. package/dist/Model.d.ts +0 -444
  118. package/dist/Model.js +0 -909
  119. package/dist/ModelRegistry.d.ts +0 -221
  120. package/dist/ModelRegistry.js +0 -537
  121. package/dist/NetworkMonitor.d.ts +0 -26
  122. package/dist/NetworkMonitor.js +0 -77
  123. package/dist/RuntimeContext.d.ts +0 -52
  124. package/dist/RuntimeContext.js +0 -80
  125. package/dist/SyncClient.d.ts +0 -551
  126. package/dist/SyncClient.js +0 -2199
  127. package/dist/adapters/alwaysOnline.d.ts +0 -14
  128. package/dist/adapters/alwaysOnline.js +0 -17
  129. package/dist/adapters/inMemoryStorage.d.ts +0 -31
  130. package/dist/adapters/inMemoryStorage.js +0 -110
  131. package/dist/ai-sdk/coordinatedTool.d.ts +0 -120
  132. package/dist/ai-sdk/coordinatedTool.js +0 -134
  133. package/dist/ai-sdk/coordinationContext.d.ts +0 -46
  134. package/dist/ai-sdk/coordinationContext.js +0 -106
  135. package/dist/ai-sdk/index.d.ts +0 -121
  136. package/dist/ai-sdk/index.js +0 -121
  137. package/dist/ai-sdk/wrap.d.ts +0 -65
  138. package/dist/ai-sdk/wrap.js +0 -39
  139. package/dist/auth/index.d.ts +0 -1
  140. package/dist/auth/index.js +0 -8
  141. package/dist/batching/index.d.ts +0 -55
  142. package/dist/batching/index.js +0 -147
  143. package/dist/cli.cjs +0 -288600
  144. package/dist/client/Ablo.d.ts +0 -231
  145. package/dist/client/Ablo.js +0 -149
  146. package/dist/client/abloClient.d.ts +0 -309
  147. package/dist/client/abloClient.js +0 -13
  148. package/dist/client/clientPrelude.d.ts +0 -52
  149. package/dist/client/clientPrelude.js +0 -60
  150. package/dist/client/consoleLogger.d.ts +0 -35
  151. package/dist/client/consoleLogger.js +0 -44
  152. package/dist/client/coreClient.d.ts +0 -60
  153. package/dist/client/coreClient.js +0 -118
  154. package/dist/client/createInternalComponents.d.ts +0 -46
  155. package/dist/client/createInternalComponents.js +0 -92
  156. package/dist/client/createModelProxy.d.ts +0 -228
  157. package/dist/client/createModelProxy.js +0 -818
  158. package/dist/client/humans.d.ts +0 -48
  159. package/dist/client/humans.js +0 -52
  160. package/dist/client/modelRegistration.d.ts +0 -10
  161. package/dist/client/modelRegistration.js +0 -312
  162. package/dist/client/options.d.ts +0 -461
  163. package/dist/client/options.js +0 -7
  164. package/dist/client/reactiveEngine.d.ts +0 -48
  165. package/dist/client/reactiveEngine.js +0 -910
  166. package/dist/client/resourceTypes.d.ts +0 -12
  167. package/dist/client/resourceTypes.js +0 -10
  168. package/dist/client/schemaConfig.d.ts +0 -44
  169. package/dist/client/schemaConfig.js +0 -185
  170. package/dist/client/validateAbloOptions.d.ts +0 -42
  171. package/dist/client/validateAbloOptions.js +0 -43
  172. package/dist/client/wsMutationExecutor.d.ts +0 -27
  173. package/dist/client/wsMutationExecutor.js +0 -72
  174. package/dist/context.d.ts +0 -29
  175. package/dist/context.js +0 -58
  176. package/dist/coordination/ClaimLog.d.ts +0 -26
  177. package/dist/coordination/ClaimLog.js +0 -32
  178. package/dist/coordination/index.d.ts +0 -1
  179. package/dist/coordination/index.js +0 -8
  180. package/dist/core/DatabaseManager.d.ts +0 -105
  181. package/dist/core/DatabaseManager.js +0 -387
  182. package/dist/core/QueryProcessor.d.ts +0 -75
  183. package/dist/core/QueryProcessor.js +0 -255
  184. package/dist/core/QueryView.d.ts +0 -79
  185. package/dist/core/QueryView.js +0 -218
  186. package/dist/core/StoreManager.d.ts +0 -112
  187. package/dist/core/StoreManager.js +0 -302
  188. package/dist/core/ViewRegistry.d.ts +0 -20
  189. package/dist/core/ViewRegistry.js +0 -55
  190. package/dist/core/index.d.ts +0 -33
  191. package/dist/core/index.js +0 -48
  192. package/dist/core/openIDBWithTimeout.d.ts +0 -65
  193. package/dist/core/openIDBWithTimeout.js +0 -153
  194. package/dist/core/queryUtils.d.ts +0 -45
  195. package/dist/core/queryUtils.js +0 -69
  196. package/dist/core/storeContract.d.ts +0 -145
  197. package/dist/core/storeContract.js +0 -12
  198. package/dist/docs/catalog.d.ts +0 -72
  199. package/dist/docs/catalog.js +0 -227
  200. package/dist/docs/index.d.ts +0 -10
  201. package/dist/docs/index.js +0 -10
  202. package/dist/environment.d.ts +0 -1
  203. package/dist/environment.js +0 -8
  204. package/dist/interfaces/index.d.ts +0 -311
  205. package/dist/interfaces/index.js +0 -9
  206. package/dist/keys/index.d.ts +0 -1
  207. package/dist/keys/index.js +0 -8
  208. package/dist/mutators/RecordingMutation.d.ts +0 -36
  209. package/dist/mutators/RecordingMutation.js +0 -182
  210. package/dist/mutators/Transaction.d.ts +0 -40
  211. package/dist/mutators/Transaction.js +0 -58
  212. package/dist/mutators/UndoManager.d.ts +0 -258
  213. package/dist/mutators/UndoManager.js +0 -658
  214. package/dist/mutators/defineMutators.d.ts +0 -60
  215. package/dist/mutators/defineMutators.js +0 -18
  216. package/dist/mutators/inverseOp.d.ts +0 -126
  217. package/dist/mutators/inverseOp.js +0 -71
  218. package/dist/mutators/mutateActions.d.ts +0 -45
  219. package/dist/mutators/mutateActions.js +0 -105
  220. package/dist/mutators/readerActions.d.ts +0 -33
  221. package/dist/mutators/readerActions.js +0 -57
  222. package/dist/mutators/undoApply.d.ts +0 -51
  223. package/dist/mutators/undoApply.js +0 -117
  224. package/dist/policy/index.d.ts +0 -21
  225. package/dist/policy/index.js +0 -20
  226. package/dist/query/client.d.ts +0 -61
  227. package/dist/query/client.js +0 -137
  228. package/dist/query/types.d.ts +0 -85
  229. package/dist/query/types.js +0 -16
  230. package/dist/react/AbloProvider.d.ts +0 -230
  231. package/dist/react/AbloProvider.js +0 -455
  232. package/dist/react/ClientSideSuspense.d.ts +0 -36
  233. package/dist/react/ClientSideSuspense.js +0 -17
  234. package/dist/react/DefaultFallback.d.ts +0 -24
  235. package/dist/react/DefaultFallback.js +0 -43
  236. package/dist/react/context.d.ts +0 -55
  237. package/dist/react/context.js +0 -29
  238. package/dist/react/index.d.ts +0 -61
  239. package/dist/react/index.js +0 -66
  240. package/dist/react/internalContext.d.ts +0 -33
  241. package/dist/react/internalContext.js +0 -3
  242. package/dist/react/useAblo.d.ts +0 -75
  243. package/dist/react/useAblo.js +0 -102
  244. package/dist/react/useCurrentUserId.d.ts +0 -22
  245. package/dist/react/useCurrentUserId.js +0 -34
  246. package/dist/react/useErrorListener.d.ts +0 -20
  247. package/dist/react/useErrorListener.js +0 -38
  248. package/dist/react/useMutationFailureListener.d.ts +0 -26
  249. package/dist/react/useMutationFailureListener.js +0 -38
  250. package/dist/react/useMutators.d.ts +0 -56
  251. package/dist/react/useMutators.js +0 -84
  252. package/dist/react/useReactive.d.ts +0 -35
  253. package/dist/react/useReactive.js +0 -123
  254. package/dist/react/useSyncStatus.d.ts +0 -59
  255. package/dist/react/useSyncStatus.js +0 -76
  256. package/dist/react/useUndoScope.d.ts +0 -34
  257. package/dist/react/useUndoScope.js +0 -81
  258. package/dist/schema/coordination.d.ts +0 -112
  259. package/dist/schema/coordination.js +0 -129
  260. package/dist/schema/ddl.d.ts +0 -97
  261. package/dist/schema/ddl.js +0 -491
  262. package/dist/schema/ddlLock.d.ts +0 -35
  263. package/dist/schema/ddlLock.js +0 -46
  264. package/dist/schema/diff.d.ts +0 -225
  265. package/dist/schema/diff.js +0 -289
  266. package/dist/schema/generate.d.ts +0 -19
  267. package/dist/schema/generate.js +0 -86
  268. package/dist/schema/index.d.ts +0 -41
  269. package/dist/schema/index.js +0 -76
  270. package/dist/schema/queries.d.ts +0 -201
  271. package/dist/schema/queries.js +0 -144
  272. package/dist/schema/select.d.ts +0 -40
  273. package/dist/schema/select.js +0 -87
  274. package/dist/schema/serialize.d.ts +0 -115
  275. package/dist/schema/serialize.js +0 -262
  276. package/dist/schema/sugar.d.ts +0 -109
  277. package/dist/schema/sugar.js +0 -83
  278. package/dist/schema/syncDeltaRow.d.ts +0 -6
  279. package/dist/schema/syncDeltaRow.js +0 -6
  280. package/dist/server/adapter.d.ts +0 -173
  281. package/dist/server/adapter.js +0 -18
  282. package/dist/server/commit.d.ts +0 -107
  283. package/dist/server/commit.js +0 -1
  284. package/dist/server/index.d.ts +0 -14
  285. package/dist/server/index.js +0 -2
  286. package/dist/server/readConfig.d.ts +0 -80
  287. package/dist/server/readConfig.js +0 -8
  288. package/dist/server/storageMode.d.ts +0 -23
  289. package/dist/server/storageMode.js +0 -17
  290. package/dist/source/adapter.d.ts +0 -81
  291. package/dist/source/adapter.js +0 -22
  292. package/dist/source/adapters/drizzle.d.ts +0 -48
  293. package/dist/source/adapters/drizzle.js +0 -219
  294. package/dist/source/adapters/kysely.d.ts +0 -42
  295. package/dist/source/adapters/kysely.js +0 -205
  296. package/dist/source/adapters/kyselyMutationCore.d.ts +0 -76
  297. package/dist/source/adapters/kyselyMutationCore.js +0 -125
  298. package/dist/source/adapters/memory.d.ts +0 -13
  299. package/dist/source/adapters/memory.js +0 -130
  300. package/dist/source/adapters/prisma.d.ts +0 -63
  301. package/dist/source/adapters/prisma.js +0 -202
  302. package/dist/source/conformance.d.ts +0 -37
  303. package/dist/source/conformance.js +0 -215
  304. package/dist/source/connector.d.ts +0 -95
  305. package/dist/source/connector.js +0 -266
  306. package/dist/source/connectorProtocol.d.ts +0 -154
  307. package/dist/source/connectorProtocol.js +0 -163
  308. package/dist/source/contract.d.ts +0 -195
  309. package/dist/source/contract.js +0 -164
  310. package/dist/source/factory.d.ts +0 -92
  311. package/dist/source/factory.js +0 -286
  312. package/dist/source/footprint.d.ts +0 -111
  313. package/dist/source/footprint.js +0 -0
  314. package/dist/source/idempotency.d.ts +0 -61
  315. package/dist/source/idempotency.js +0 -144
  316. package/dist/source/index.d.ts +0 -23
  317. package/dist/source/index.js +0 -30
  318. package/dist/source/migrations.d.ts +0 -21
  319. package/dist/source/migrations.js +0 -103
  320. package/dist/source/next.d.ts +0 -32
  321. package/dist/source/next.js +0 -25
  322. package/dist/source/pushQueue.d.ts +0 -134
  323. package/dist/source/pushQueue.js +0 -256
  324. package/dist/source/signing.d.ts +0 -92
  325. package/dist/source/signing.js +0 -162
  326. package/dist/source/types.d.ts +0 -401
  327. package/dist/source/types.js +0 -59
  328. package/dist/stores/ObjectStore.d.ts +0 -115
  329. package/dist/stores/ObjectStore.js +0 -393
  330. package/dist/stores/ObjectStoreContract.d.ts +0 -38
  331. package/dist/stores/ObjectStoreContract.js +0 -1
  332. package/dist/stores/SyncActionStore.d.ts +0 -97
  333. package/dist/stores/SyncActionStore.js +0 -504
  334. package/dist/stores/syncAction.d.ts +0 -26
  335. package/dist/stores/syncAction.js +0 -16
  336. package/dist/surface.d.ts +0 -36
  337. package/dist/surface.js +0 -75
  338. package/dist/sync/BootstrapFetcher.d.ts +0 -280
  339. package/dist/sync/BootstrapFetcher.js +0 -962
  340. package/dist/sync/ConnectionManager.d.ts +0 -8
  341. package/dist/sync/ConnectionManager.js +0 -8
  342. package/dist/sync/OnDemandLoader.d.ts +0 -228
  343. package/dist/sync/OnDemandLoader.js +0 -742
  344. package/dist/sync/SubscriptionManager.d.ts +0 -159
  345. package/dist/sync/SubscriptionManager.js +0 -243
  346. package/dist/sync/SyncWebSocket.d.ts +0 -173
  347. package/dist/sync/SyncWebSocket.js +0 -438
  348. package/dist/sync/awaitClaimGrant.d.ts +0 -6
  349. package/dist/sync/awaitClaimGrant.js +0 -6
  350. package/dist/sync/bootstrapApply.d.ts +0 -70
  351. package/dist/sync/bootstrapApply.js +0 -73
  352. package/dist/sync/commitFrames.d.ts +0 -8
  353. package/dist/sync/commitFrames.js +0 -8
  354. package/dist/sync/contextPorts.d.ts +0 -18
  355. package/dist/sync/contextPorts.js +0 -31
  356. package/dist/sync/createClaimStream.d.ts +0 -7
  357. package/dist/sync/createClaimStream.js +0 -7
  358. package/dist/sync/createPresenceStream.d.ts +0 -69
  359. package/dist/sync/createPresenceStream.js +0 -200
  360. package/dist/sync/createSnapshot.d.ts +0 -29
  361. package/dist/sync/createSnapshot.js +0 -118
  362. package/dist/sync/credentialLifecycle.d.ts +0 -7
  363. package/dist/sync/credentialLifecycle.js +0 -7
  364. package/dist/sync/deltaPipeline.d.ts +0 -113
  365. package/dist/sync/deltaPipeline.js +0 -261
  366. package/dist/sync/groupChange.d.ts +0 -113
  367. package/dist/sync/groupChange.js +0 -242
  368. package/dist/sync/participants.d.ts +0 -115
  369. package/dist/sync/participants.js +0 -344
  370. package/dist/sync/persistedPrefix.d.ts +0 -12
  371. package/dist/sync/persistedPrefix.js +0 -22
  372. package/dist/sync/schemaDrift.d.ts +0 -55
  373. package/dist/sync/schemaDrift.js +0 -53
  374. package/dist/sync/schemas.d.ts +0 -70
  375. package/dist/sync/schemas.js +0 -94
  376. package/dist/sync/syncCursor.d.ts +0 -40
  377. package/dist/sync/syncCursor.js +0 -55
  378. package/dist/sync/syncPlan.d.ts +0 -54
  379. package/dist/sync/syncPlan.js +0 -50
  380. package/dist/sync/wsFrameHandlers.d.ts +0 -8
  381. package/dist/sync/wsFrameHandlers.js +0 -8
  382. package/dist/testing/fixtures/bootstrap.d.ts +0 -49
  383. package/dist/testing/fixtures/bootstrap.js +0 -59
  384. package/dist/testing/fixtures/deltas.d.ts +0 -83
  385. package/dist/testing/fixtures/deltas.js +0 -136
  386. package/dist/testing/fixtures/httpResponses.d.ts +0 -70
  387. package/dist/testing/fixtures/httpResponses.js +0 -90
  388. package/dist/testing/fixtures/models.d.ts +0 -83
  389. package/dist/testing/fixtures/models.js +0 -272
  390. package/dist/testing/helpers/reactWrapper.d.ts +0 -69
  391. package/dist/testing/helpers/reactWrapper.js +0 -67
  392. package/dist/testing/helpers/syncEngineHarness.d.ts +0 -54
  393. package/dist/testing/helpers/syncEngineHarness.js +0 -73
  394. package/dist/testing/helpers/wait.d.ts +0 -30
  395. package/dist/testing/helpers/wait.js +0 -49
  396. package/dist/testing/index.d.ts +0 -23
  397. package/dist/testing/index.js +0 -33
  398. package/dist/testing/mocks/FakeDatabase.d.ts +0 -18
  399. package/dist/testing/mocks/FakeDatabase.js +0 -10
  400. package/dist/testing/mocks/MockMutationExecutor.d.ts +0 -87
  401. package/dist/testing/mocks/MockMutationExecutor.js +0 -186
  402. package/dist/testing/mocks/MockNetworkMonitor.d.ts +0 -20
  403. package/dist/testing/mocks/MockNetworkMonitor.js +0 -46
  404. package/dist/testing/mocks/MockSyncContext.d.ts +0 -51
  405. package/dist/testing/mocks/MockSyncContext.js +0 -72
  406. package/dist/testing/mocks/MockSyncStore.d.ts +0 -88
  407. package/dist/testing/mocks/MockSyncStore.js +0 -171
  408. package/dist/testing/mocks/MockWebSocket.d.ts +0 -71
  409. package/dist/testing/mocks/MockWebSocket.js +0 -118
  410. package/dist/transaction/ablo.d.ts +0 -88
  411. package/dist/transaction/ablo.js +0 -33
  412. package/dist/transaction/auth/apiKey.d.ts +0 -152
  413. package/dist/transaction/auth/apiKey.js +0 -419
  414. package/dist/transaction/auth/bootstrapScope.d.ts +0 -15
  415. package/dist/transaction/auth/bootstrapScope.js +0 -1
  416. package/dist/transaction/auth/capability.d.ts +0 -177
  417. package/dist/transaction/auth/capability.js +0 -199
  418. package/dist/transaction/auth/credentialEndpoint.d.ts +0 -61
  419. package/dist/transaction/auth/credentialEndpoint.js +0 -86
  420. package/dist/transaction/auth/credentialPolicy.d.ts +0 -148
  421. package/dist/transaction/auth/credentialPolicy.js +0 -125
  422. package/dist/transaction/auth/credentialSource.d.ts +0 -30
  423. package/dist/transaction/auth/credentialSource.js +0 -55
  424. package/dist/transaction/auth/hostedEndpoints.d.ts +0 -21
  425. package/dist/transaction/auth/hostedEndpoints.js +0 -21
  426. package/dist/transaction/auth/identity.d.ts +0 -55
  427. package/dist/transaction/auth/identity.js +0 -210
  428. package/dist/transaction/auth/index.d.ts +0 -162
  429. package/dist/transaction/auth/index.js +0 -304
  430. package/dist/transaction/auth/schemas.d.ts +0 -59
  431. package/dist/transaction/auth/schemas.js +0 -85
  432. package/dist/transaction/auth/sessionMint.d.ts +0 -28
  433. package/dist/transaction/auth/sessionMint.js +0 -85
  434. package/dist/transaction/coordination/awaitClaimGrant.d.ts +0 -49
  435. package/dist/transaction/coordination/awaitClaimGrant.js +0 -112
  436. package/dist/transaction/coordination/claimHeartbeatLoop.d.ts +0 -50
  437. package/dist/transaction/coordination/claimHeartbeatLoop.js +0 -88
  438. package/dist/transaction/coordination/claimMeta.d.ts +0 -49
  439. package/dist/transaction/coordination/claimMeta.js +0 -52
  440. package/dist/transaction/coordination/createClaimStream.d.ts +0 -64
  441. package/dist/transaction/coordination/createClaimStream.js +0 -475
  442. package/dist/transaction/coordination/events.d.ts +0 -74
  443. package/dist/transaction/coordination/events.js +0 -7
  444. package/dist/transaction/coordination/index.d.ts +0 -19
  445. package/dist/transaction/coordination/index.js +0 -44
  446. package/dist/transaction/coordination/locator.d.ts +0 -83
  447. package/dist/transaction/coordination/locator.js +0 -82
  448. package/dist/transaction/coordination/schema.d.ts +0 -1473
  449. package/dist/transaction/coordination/schema.js +0 -1013
  450. package/dist/transaction/coordination/targetConflict.d.ts +0 -2
  451. package/dist/transaction/coordination/targetConflict.js +0 -103
  452. package/dist/transaction/coordination/trace.d.ts +0 -78
  453. package/dist/transaction/coordination/trace.js +0 -138
  454. package/dist/transaction/durableWrites.d.ts +0 -62
  455. package/dist/transaction/durableWrites.js +0 -71
  456. package/dist/transaction/environment.d.ts +0 -105
  457. package/dist/transaction/environment.js +0 -108
  458. package/dist/transaction/errorCodes.d.ts +0 -403
  459. package/dist/transaction/errorCodes.js +0 -480
  460. package/dist/transaction/errors.d.ts +0 -428
  461. package/dist/transaction/errors.js +0 -686
  462. package/dist/transaction/index.d.ts +0 -20
  463. package/dist/transaction/index.js +0 -20
  464. package/dist/transaction/keys/index.d.ts +0 -87
  465. package/dist/transaction/keys/index.js +0 -207
  466. package/dist/transaction/log/syncDeltaRow.d.ts +0 -158
  467. package/dist/transaction/log/syncDeltaRow.js +0 -95
  468. package/dist/transaction/logPosition.d.ts +0 -97
  469. package/dist/transaction/logPosition.js +0 -125
  470. package/dist/transaction/logger.d.ts +0 -16
  471. package/dist/transaction/logger.js +0 -7
  472. package/dist/transaction/observability.d.ts +0 -53
  473. package/dist/transaction/observability.js +0 -19
  474. package/dist/transaction/persistence.d.ts +0 -12
  475. package/dist/transaction/persistence.js +0 -11
  476. package/dist/transaction/plugin.d.ts +0 -192
  477. package/dist/transaction/plugin.js +0 -87
  478. package/dist/transaction/policy/types.d.ts +0 -217
  479. package/dist/transaction/policy/types.js +0 -126
  480. package/dist/transaction/resources/functionalUpdate.d.ts +0 -79
  481. package/dist/transaction/resources/functionalUpdate.js +0 -87
  482. package/dist/transaction/resources/httpResources.d.ts +0 -266
  483. package/dist/transaction/resources/httpResources.js +0 -7
  484. package/dist/transaction/resources/modelOperations.d.ts +0 -319
  485. package/dist/transaction/resources/modelOperations.js +0 -12
  486. package/dist/transaction/resources/mutationOptions.d.ts +0 -66
  487. package/dist/transaction/resources/mutationOptions.js +0 -9
  488. package/dist/transaction/resources/where.d.ts +0 -85
  489. package/dist/transaction/resources/where.js +0 -70
  490. package/dist/transaction/resources/writeOptionsSchema.d.ts +0 -47
  491. package/dist/transaction/resources/writeOptionsSchema.js +0 -73
  492. package/dist/transaction/schema/field.d.ts +0 -126
  493. package/dist/transaction/schema/field.js +0 -265
  494. package/dist/transaction/schema/loadStrategy.d.ts +0 -45
  495. package/dist/transaction/schema/loadStrategy.js +0 -46
  496. package/dist/transaction/schema/model.d.ts +0 -379
  497. package/dist/transaction/schema/model.js +0 -123
  498. package/dist/transaction/schema/openapi.d.ts +0 -57
  499. package/dist/transaction/schema/openapi.js +0 -340
  500. package/dist/transaction/schema/relation.d.ts +0 -199
  501. package/dist/transaction/schema/relation.js +0 -104
  502. package/dist/transaction/schema/residency.d.ts +0 -29
  503. package/dist/transaction/schema/residency.js +0 -25
  504. package/dist/transaction/schema/roles.d.ts +0 -249
  505. package/dist/transaction/schema/roles.js +0 -230
  506. package/dist/transaction/schema/schema.d.ts +0 -324
  507. package/dist/transaction/schema/schema.js +0 -305
  508. package/dist/transaction/schema/tenancy.d.ts +0 -139
  509. package/dist/transaction/schema/tenancy.js +0 -190
  510. package/dist/transaction/transactionLayer.d.ts +0 -82
  511. package/dist/transaction/transactionLayer.js +0 -24
  512. package/dist/transaction/transactions/settlement/commitEnvelope.d.ts +0 -143
  513. package/dist/transaction/transactions/settlement/commitEnvelope.js +0 -161
  514. package/dist/transaction/transactions/settlement/httpCommitEnvelope.d.ts +0 -53
  515. package/dist/transaction/transactions/settlement/httpCommitEnvelope.js +0 -207
  516. package/dist/transaction/transactions/settlement/idempotencyKey.d.ts +0 -10
  517. package/dist/transaction/transactions/settlement/idempotencyKey.js +0 -9
  518. package/dist/transaction/transactions/settlement/pendingWrite.d.ts +0 -112
  519. package/dist/transaction/transactions/settlement/pendingWrite.js +0 -20
  520. package/dist/transaction/transport/commitFrames.d.ts +0 -90
  521. package/dist/transaction/transport/commitFrames.js +0 -134
  522. package/dist/transaction/transport/connectionManager.d.ts +0 -215
  523. package/dist/transaction/transport/connectionManager.js +0 -673
  524. package/dist/transaction/transport/credentialLifecycle.d.ts +0 -177
  525. package/dist/transaction/transport/credentialLifecycle.js +0 -324
  526. package/dist/transaction/transport/heartbeat.d.ts +0 -65
  527. package/dist/transaction/transport/heartbeat.js +0 -93
  528. package/dist/transaction/transport/httpClient.d.ts +0 -123
  529. package/dist/transaction/transport/httpClient.js +0 -145
  530. package/dist/transaction/transport/httpOptions.d.ts +0 -33
  531. package/dist/transaction/transport/httpOptions.js +0 -12
  532. package/dist/transaction/transport/httpTransport.d.ts +0 -8
  533. package/dist/transaction/transport/httpTransport.js +0 -1276
  534. package/dist/transaction/transport/networkProbe.d.ts +0 -84
  535. package/dist/transaction/transport/networkProbe.js +0 -207
  536. package/dist/transaction/transport/wsFrameHandlers.d.ts +0 -128
  537. package/dist/transaction/transport/wsFrameHandlers.js +0 -429
  538. package/dist/transaction/transport/wsTransport.d.ts +0 -576
  539. package/dist/transaction/transport/wsTransport.js +0 -1017
  540. package/dist/transaction/types/assertExact.d.ts +0 -17
  541. package/dist/transaction/types/assertExact.js +0 -1
  542. package/dist/transaction/types/global.d.ts +0 -107
  543. package/dist/transaction/types/global.js +0 -40
  544. package/dist/transaction/types/index.d.ts +0 -205
  545. package/dist/transaction/types/index.js +0 -56
  546. package/dist/transaction/types/modelData.d.ts +0 -10
  547. package/dist/transaction/types/modelData.js +0 -9
  548. package/dist/transaction/types/participant.d.ts +0 -20
  549. package/dist/transaction/types/participant.js +0 -10
  550. package/dist/transaction/types/streams.d.ts +0 -540
  551. package/dist/transaction/types/streams.js +0 -11
  552. package/dist/transaction/utils/asyncIterator.d.ts +0 -34
  553. package/dist/transaction/utils/asyncIterator.js +0 -135
  554. package/dist/transaction/utils/duration.d.ts +0 -25
  555. package/dist/transaction/utils/duration.js +0 -45
  556. package/dist/transaction/utils/json.d.ts +0 -57
  557. package/dist/transaction/utils/json.js +0 -276
  558. package/dist/transaction/wire/accountResponses.d.ts +0 -351
  559. package/dist/transaction/wire/accountResponses.js +0 -255
  560. package/dist/transaction/wire/auth.d.ts +0 -49
  561. package/dist/transaction/wire/auth.js +0 -57
  562. package/dist/transaction/wire/bootstrapReason.d.ts +0 -9
  563. package/dist/transaction/wire/bootstrapReason.js +0 -8
  564. package/dist/transaction/wire/claimEvent.d.ts +0 -76
  565. package/dist/transaction/wire/claimEvent.js +0 -73
  566. package/dist/transaction/wire/claims.d.ts +0 -463
  567. package/dist/transaction/wire/claims.js +0 -229
  568. package/dist/transaction/wire/commit.d.ts +0 -603
  569. package/dist/transaction/wire/commit.js +0 -321
  570. package/dist/transaction/wire/delta.d.ts +0 -250
  571. package/dist/transaction/wire/delta.js +0 -147
  572. package/dist/transaction/wire/errorEnvelope.d.ts +0 -72
  573. package/dist/transaction/wire/errorEnvelope.js +0 -123
  574. package/dist/transaction/wire/feedCursor.d.ts +0 -60
  575. package/dist/transaction/wire/feedCursor.js +0 -82
  576. package/dist/transaction/wire/feedEvent.d.ts +0 -177
  577. package/dist/transaction/wire/feedEvent.js +0 -39
  578. package/dist/transaction/wire/frames.d.ts +0 -194
  579. package/dist/transaction/wire/frames.js +0 -50
  580. package/dist/transaction/wire/inboundFrames.d.ts +0 -552
  581. package/dist/transaction/wire/inboundFrames.js +0 -116
  582. package/dist/transaction/wire/index.d.ts +0 -50
  583. package/dist/transaction/wire/index.js +0 -74
  584. package/dist/transaction/wire/listEnvelope.d.ts +0 -37
  585. package/dist/transaction/wire/listEnvelope.js +0 -42
  586. package/dist/transaction/wire/modelResponses.d.ts +0 -85
  587. package/dist/transaction/wire/modelResponses.js +0 -43
  588. package/dist/transaction/wire/protocol.d.ts +0 -38
  589. package/dist/transaction/wire/protocol.js +0 -38
  590. package/dist/transaction/wire/protocolVersion.d.ts +0 -73
  591. package/dist/transaction/wire/protocolVersion.js +0 -83
  592. package/dist/transactions/mutations/MutationQueue.d.ts +0 -655
  593. package/dist/transactions/mutations/MutationQueue.js +0 -2797
  594. package/dist/transactions/mutations/MutationStore.d.ts +0 -20
  595. package/dist/transactions/mutations/MutationStore.js +0 -53
  596. package/dist/transactions/mutations/UnconfirmedWrites.d.ts +0 -82
  597. package/dist/transactions/mutations/UnconfirmedWrites.js +0 -104
  598. package/dist/transactions/mutations/coalesceRules.d.ts +0 -58
  599. package/dist/transactions/mutations/coalesceRules.js +0 -140
  600. package/dist/transactions/mutations/commitLatency.d.ts +0 -52
  601. package/dist/transactions/mutations/commitLatency.js +0 -130
  602. package/dist/transactions/mutations/commitOutboxStore.d.ts +0 -28
  603. package/dist/transactions/mutations/commitOutboxStore.js +0 -26
  604. package/dist/transactions/mutations/commitPayload.d.ts +0 -164
  605. package/dist/transactions/mutations/commitPayload.js +0 -152
  606. package/dist/transactions/mutations/deltaConfirmation.d.ts +0 -59
  607. package/dist/transactions/mutations/deltaConfirmation.js +0 -233
  608. package/dist/transactions/mutations/durableWriteStore.d.ts +0 -14
  609. package/dist/transactions/mutations/durableWriteStore.js +0 -12
  610. package/dist/transactions/mutations/optimisticApply.d.ts +0 -49
  611. package/dist/transactions/mutations/optimisticApply.js +0 -65
  612. package/dist/transactions/mutations/replayValidation.d.ts +0 -186
  613. package/dist/transactions/mutations/replayValidation.js +0 -163
  614. package/dist/utils/mobxSetup.d.ts +0 -53
  615. package/dist/utils/mobxSetup.js +0 -330
  616. package/dist/webhooks/events.d.ts +0 -43
  617. package/dist/webhooks/events.js +0 -42
  618. package/dist/webhooks/index.d.ts +0 -8
  619. package/dist/webhooks/index.js +0 -8
  620. package/dist/wire/index.d.ts +0 -1
  621. package/dist/wire/index.js +0 -8
  622. package/docs/interaction-model.md +0 -99
@@ -1,658 +0,0 @@
1
- /**
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.
6
- *
7
- * History is divided into named scopes, one per surface — a report editor, a
8
- * ledger grid, and so on — reached through {@link UndoManager.getScope}. Undo in
9
- * one surface never affects another.
10
- *
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.
15
- */
16
- import { getContext } from '../context.js';
17
- import { createTransaction } from './Transaction.js';
18
- import { parseUndoEntry } from './inverseOp.js';
19
- import { resolveOps, DEFAULT_UNDO_CONFLICT_POLICY, } from './undoApply.js';
20
- /** Normalize a registered model name to its lowercased alias form. */
21
- const normalizeModelAlias = (modelName) => modelName.replace('Model', '').toLowerCase();
22
- /**
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.
27
- */
28
- /**
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.
34
- */
35
- const REPLAY_ECHO_TTL_MS = 5000;
36
- export class UndoScope {
37
- schema;
38
- store;
39
- organizationId;
40
- undoStack = [];
41
- redoStack = [];
42
- maxHistory;
43
- conflictPolicy;
44
- /**
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.
51
- */
52
- recordListeners = new Set();
53
- /**
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.
60
- */
61
- changeListeners = new Set();
62
- /**
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.
73
- */
74
- tail = Promise.resolve();
75
- /** Predicate selecting which models this surface records (see options). */
76
- tracksModel;
77
- /** registered-name / alias → schema key, built once from the schema. */
78
- schemaKeyByAlias = new Map();
79
- /** Unsubscribe from the local-mutation stream. */
80
- unsubscribe;
81
- /**
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.
86
- */
87
- replaying = false;
88
- /** Operations collected during the current tick, flushed together as one entry. */
89
- batch = [];
90
- flushScheduled = false;
91
- /**
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.
96
- */
97
- group = null;
98
- /**
99
- * Suppression of a replay's asynchronous echo, keyed by `${modelKey}:${id}`.
100
- *
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.
113
- */
114
- pendingReplayEchoes = new Map();
115
- constructor(schema, store, organizationId, options = {}) {
116
- this.schema = schema;
117
- this.store = store;
118
- this.organizationId = organizationId;
119
- this.maxHistory = options.maxHistory ?? 100;
120
- this.conflictPolicy = options.conflictPolicy ?? DEFAULT_UNDO_CONFLICT_POLICY;
121
- this.tracksModel = options.tracksModel;
122
- // Build the map from registered name to schema key. The mutation stream
123
- // reports a model's registered name (for example `'Block'`), but inverse
124
- // operations and the replay transaction are keyed by the schema key (for
125
- // example `'blocks'`), so map every reasonable spelling to the schema key.
126
- for (const schemaKey of Object.keys(this.schema.models)) {
127
- const def = this.schema.models[schemaKey];
128
- const typename = def?.typename ?? schemaKey;
129
- for (const alias of [schemaKey, typename]) {
130
- this.schemaKeyByAlias.set(alias, schemaKey);
131
- this.schemaKeyByAlias.set(alias.toLowerCase(), schemaKey);
132
- this.schemaKeyByAlias.set(normalizeModelAlias(alias), schemaKey);
133
- }
134
- }
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.
140
- this.unsubscribe =
141
- options.recordFromStream && this.store.subscribeLocalMutations
142
- ? this.store.subscribeLocalMutations((m) => { this.onLocalMutation(m); })
143
- : () => { };
144
- }
145
- /**
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.
150
- */
151
- beginGroup(label) {
152
- if (this.group)
153
- this.endGroup();
154
- this.group = { label, ops: [] };
155
- }
156
- /** Close the grouping session and record the accumulated ops as one entry. */
157
- endGroup(label) {
158
- const g = this.group;
159
- if (!g)
160
- return;
161
- this.group = null;
162
- const forwards = g.ops.map((c) => c.forward);
163
- const inverses = g.ops
164
- .map((c) => c.inverse)
165
- .filter((i) => i !== null)
166
- .reverse();
167
- if (forwards.length === 0 && inverses.length === 0)
168
- return;
169
- this.record({ label: label ?? g.label, inverses, forwards });
170
- }
171
- /** Every `${modelKey}:${id}` a set of ops will touch (all op kinds). */
172
- *replayEchoKeys(ops) {
173
- for (const op of ops) {
174
- switch (op.kind) {
175
- case 'create': {
176
- const id = op.data.id;
177
- if (typeof id === 'string')
178
- yield `${op.modelKey}:${id}`;
179
- break;
180
- }
181
- case 'update':
182
- yield `${op.modelKey}:${op.patch.id}`;
183
- break;
184
- case 'delete':
185
- yield `${op.modelKey}:${op.id}`;
186
- break;
187
- case 'createMany':
188
- for (const d of op.data) {
189
- const id = d.id;
190
- if (typeof id === 'string')
191
- yield `${op.modelKey}:${id}`;
192
- }
193
- break;
194
- case 'updateMany':
195
- for (const p of op.patches)
196
- yield `${op.modelKey}:${p.id}`;
197
- break;
198
- case 'deleteMany':
199
- for (const id of op.ids)
200
- yield `${op.modelKey}:${id}`;
201
- break;
202
- }
203
- }
204
- }
205
- /**
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}.
209
- */
210
- markReplayEchoes(ops) {
211
- const expiresAt = Date.now() + REPLAY_ECHO_TTL_MS;
212
- for (const key of this.replayEchoKeys(ops)) {
213
- const existing = this.pendingReplayEchoes.get(key);
214
- if (existing) {
215
- existing.count += 1;
216
- existing.expiresAt = expiresAt;
217
- }
218
- else {
219
- this.pendingReplayEchoes.set(key, { count: 1, expiresAt });
220
- }
221
- }
222
- }
223
- /**
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.
227
- */
228
- consumeReplayEcho(schemaKey, modelId) {
229
- if (this.pendingReplayEchoes.size === 0)
230
- return false;
231
- const now = Date.now();
232
- for (const [k, v] of this.pendingReplayEchoes) {
233
- if (v.expiresAt <= now)
234
- this.pendingReplayEchoes.delete(k);
235
- }
236
- const key = `${schemaKey}:${modelId}`;
237
- const pending = this.pendingReplayEchoes.get(key);
238
- if (!pending)
239
- return false;
240
- pending.count -= 1;
241
- if (pending.count <= 0)
242
- this.pendingReplayEchoes.delete(key);
243
- return true;
244
- }
245
- /** Resolve a stream mutation's registered name to its schema key, or null. */
246
- resolveSchemaKey(modelName) {
247
- return (this.schemaKeyByAlias.get(modelName) ??
248
- this.schemaKeyByAlias.get(normalizeModelAlias(modelName)) ??
249
- null);
250
- }
251
- /**
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 blocks at once,
256
- * say — becomes a single undo step.
257
- */
258
- onLocalMutation(m) {
259
- if (this.replaying)
260
- return;
261
- const schemaKey = this.resolveSchemaKey(m.modelName);
262
- if (!schemaKey)
263
- return;
264
- // Drop the ASYNC echo of our own replayed writes. The engine surfaces a
265
- // replay's `transaction:created` only after an IndexedDB-gated commit, i.e.
266
- // after `replaying` has already reset — so the synchronous flag above misses
267
- // it. The (modelKey,id) marks armed in `markReplayEchoes` catch it whenever
268
- // it lands, which is what stops every undo from wiping its own redo stack.
269
- if (this.consumeReplayEcho(schemaKey, m.modelId))
270
- return;
271
- if (this.tracksModel && !this.tracksModel(schemaKey))
272
- return;
273
- const ops = buildUndoOps(m, schemaKey);
274
- if (!ops)
275
- return;
276
- // Inside a grouping session, accumulate across ticks (flushed on
277
- // endGroup); otherwise coalesce per-tick.
278
- if (this.group) {
279
- this.group.ops.push(ops);
280
- return;
281
- }
282
- this.batch.push(ops);
283
- this.scheduleFlush();
284
- }
285
- scheduleFlush() {
286
- if (this.flushScheduled)
287
- return;
288
- this.flushScheduled = true;
289
- const run = () => {
290
- this.flushScheduled = false;
291
- this.flushBatch();
292
- };
293
- if (typeof queueMicrotask === 'function')
294
- queueMicrotask(run);
295
- else
296
- void Promise.resolve().then(run);
297
- }
298
- /** Coalesce the tick's collected ops into one entry and record it. */
299
- flushBatch() {
300
- if (this.batch.length === 0)
301
- return;
302
- const collected = this.batch;
303
- this.batch = [];
304
- const forwards = collected.map((c) => c.forward);
305
- // Undo applies the inverses in reverse order of how the forwards ran.
306
- const inverses = collected
307
- .map((c) => c.inverse)
308
- .filter((i) => i !== null)
309
- .reverse();
310
- if (forwards.length === 0 && inverses.length === 0)
311
- return;
312
- this.record({ inverses, forwards });
313
- }
314
- /**
315
- * Run `work` after every previously-enqueued scope operation has settled,
316
- * in invocation order. The internal `tail` always resolves (failures are
317
- * swallowed *for the chain only*) so one rejected mutator can't wedge the
318
- * queue; the original settlement is still surfaced to this call's caller.
319
- */
320
- enqueue(work) {
321
- const result = this.tail.then(work, work);
322
- this.tail = result.then(() => undefined, () => undefined);
323
- return result;
324
- }
325
- /**
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.
331
- */
332
- runRecorded(work) {
333
- return this.enqueue(work);
334
- }
335
- /**
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.
345
- */
346
- record(entry) {
347
- if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
348
- parseUndoEntry(entry);
349
- }
350
- this.undoStack.push(entry);
351
- if (this.undoStack.length > this.maxHistory)
352
- this.undoStack.shift();
353
- this.redoStack = [];
354
- this.emitRecord(entry);
355
- this.emitChange();
356
- }
357
- /**
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.
363
- */
364
- onRecord(listener) {
365
- this.recordListeners.add(listener);
366
- return () => {
367
- this.recordListeners.delete(listener);
368
- };
369
- }
370
- emitRecord(entry) {
371
- for (const listener of this.recordListeners) {
372
- try {
373
- listener(entry);
374
- }
375
- catch (err) {
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.
378
- getContext().logger.warn('An undo/redo onRecord listener threw — your callback should not throw', err);
379
- }
380
- }
381
- }
382
- /**
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.
387
- */
388
- onChange(listener) {
389
- this.changeListeners.add(listener);
390
- return () => {
391
- this.changeListeners.delete(listener);
392
- };
393
- }
394
- emitChange() {
395
- for (const listener of this.changeListeners) {
396
- try {
397
- listener();
398
- }
399
- catch (err) {
400
- // The consumer's own onChange callback is at fault, so log it as an
401
- // actionable warning.
402
- getContext().logger.warn('An undo/redo onChange listener threw — your callback should not throw', err);
403
- }
404
- }
405
- }
406
- canUndo() {
407
- return this.undoStack.length > 0;
408
- }
409
- canRedo() {
410
- return this.redoStack.length > 0;
411
- }
412
- /**
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.
418
- */
419
- undo() {
420
- return this.enqueue(async () => {
421
- const entry = this.undoStack.pop();
422
- if (!entry)
423
- return;
424
- const tx = createTransaction(this.schema, this.store, this.organizationId);
425
- const ops = resolveOps(entry.inverses, entry.forwards, this.store, this.conflictPolicy);
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.
430
- this.markReplayEchoes(ops);
431
- this.replaying = true;
432
- try {
433
- await applyOps(tx, ops);
434
- }
435
- catch (err) {
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.
439
- this.undoStack.push(entry);
440
- this.emitChange();
441
- throw err;
442
- }
443
- finally {
444
- this.replaying = false;
445
- }
446
- this.redoStack.push(entry);
447
- if (this.redoStack.length > this.maxHistory)
448
- this.redoStack.shift();
449
- this.emitChange();
450
- });
451
- }
452
- /**
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.
458
- */
459
- redo() {
460
- return this.enqueue(async () => {
461
- const entry = this.redoStack.pop();
462
- if (!entry)
463
- return;
464
- const tx = createTransaction(this.schema, this.store, this.organizationId);
465
- const ops = resolveOps(entry.forwards, entry.inverses, this.store, this.conflictPolicy);
466
- // See undo(): arm async-echo suppression before the replayed writes.
467
- this.markReplayEchoes(ops);
468
- this.replaying = true;
469
- try {
470
- await applyOps(tx, ops);
471
- }
472
- catch (err) {
473
- // Symmetric to undo: a rejected re-apply leaves state unchanged, so put
474
- // the entry back on the redo stack instead of losing it.
475
- this.redoStack.push(entry);
476
- this.emitChange();
477
- throw err;
478
- }
479
- finally {
480
- this.replaying = false;
481
- }
482
- this.undoStack.push(entry);
483
- if (this.undoStack.length > this.maxHistory)
484
- this.undoStack.shift();
485
- this.emitChange();
486
- });
487
- }
488
- /** Drop all history. Use after bootstrap / sync group change / sync error. */
489
- clear() {
490
- this.undoStack = [];
491
- this.redoStack = [];
492
- this.batch = [];
493
- this.pendingReplayEchoes.clear();
494
- this.emitChange();
495
- }
496
- /** Introspection — for debug panels / e2e tests. */
497
- size() {
498
- return { undo: this.undoStack.length, redo: this.redoStack.length };
499
- }
500
- /**
501
- * Detach from the local-mutation stream and drop listeners. Scopes are
502
- * cached for the store's lifetime by `UndoManager`, so this is mainly for
503
- * tests and explicit teardown.
504
- */
505
- dispose() {
506
- this.unsubscribe();
507
- this.recordListeners.clear();
508
- this.changeListeners.clear();
509
- this.batch = [];
510
- this.pendingReplayEchoes.clear();
511
- }
512
- }
513
- /**
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.
517
- */
518
- function buildUndoOps(m, modelKey) {
519
- const id = m.modelId;
520
- const stripId = (o) => {
521
- const out = { ...(o ?? {}) };
522
- delete out.id;
523
- return out;
524
- };
525
- switch (m.type) {
526
- case 'create':
527
- return {
528
- forward: { kind: 'create', modelKey, data: { ...stripId(m.data), id } },
529
- inverse: { kind: 'delete', modelKey, id },
530
- };
531
- case 'update': {
532
- const next = stripId(m.data);
533
- const prev = stripId(m.previousData);
534
- return {
535
- forward: { kind: 'update', modelKey, patch: { id, ...next } },
536
- // No previous values captured → not reversible; drop the inverse.
537
- inverse: Object.keys(prev).length > 0
538
- ? { kind: 'update', modelKey, patch: { id, ...prev } }
539
- : null,
540
- };
541
- }
542
- case 'delete':
543
- return {
544
- forward: { kind: 'delete', modelKey, id },
545
- inverse: { kind: 'create', modelKey, data: { ...stripId(m.previousData), id } },
546
- };
547
- case 'archive':
548
- return {
549
- forward: { kind: 'update', modelKey, patch: { id, archivedAt: new Date() } },
550
- inverse: { kind: 'update', modelKey, patch: { id, archivedAt: null } },
551
- };
552
- case 'unarchive':
553
- return {
554
- forward: { kind: 'update', modelKey, patch: { id, archivedAt: null } },
555
- inverse: { kind: 'update', modelKey, patch: { id, archivedAt: new Date() } },
556
- };
557
- default:
558
- return null;
559
- }
560
- }
561
- // ── Manager ────────────────────────────────────────────────────────────────
562
- /**
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}.
566
- */
567
- export class UndoManager {
568
- schema;
569
- store;
570
- organizationId;
571
- scopes = new Map();
572
- /** The options each scope was constructed with, for the mismatch warning below. */
573
- creationOptions = new Map();
574
- constructor(schema, store, organizationId) {
575
- this.schema = schema;
576
- this.store = store;
577
- this.organizationId = organizationId;
578
- }
579
- getScope(name, options) {
580
- let scope = this.scopes.get(name);
581
- if (!scope) {
582
- scope = new UndoScope(this.schema, this.store, this.organizationId, options);
583
- this.scopes.set(name, scope);
584
- this.creationOptions.set(name, options);
585
- return scope;
586
- }
587
- // A scope keeps the options it was created with; later calls cannot change
588
- // them. Requesting the shared scope with no options is the normal pattern
589
- // and stays silent — but passing options that conflict with the creation
590
- // values means one caller believes it configured a scope that another
591
- // caller already configured differently, which is how a surface silently
592
- // ends up with, say, no stream recording. Surface that instead of letting
593
- // it pass.
594
- if (options) {
595
- const created = this.creationOptions.get(name);
596
- const conflicts = [];
597
- if (options.recordFromStream !== undefined &&
598
- options.recordFromStream !== (created?.recordFromStream ?? false)) {
599
- conflicts.push('recordFromStream');
600
- }
601
- if (options.maxHistory !== undefined && options.maxHistory !== (created?.maxHistory ?? 100)) {
602
- conflicts.push('maxHistory');
603
- }
604
- if (options.conflictPolicy !== undefined &&
605
- options.conflictPolicy !== (created?.conflictPolicy ?? DEFAULT_UNDO_CONFLICT_POLICY)) {
606
- conflicts.push('conflictPolicy');
607
- }
608
- if (conflicts.length > 0) {
609
- getContext().logger.warn(`The undo scope "${name}" already exists with different options — ` +
610
- `${conflicts.join(', ')} cannot be changed after creation and the requested ` +
611
- `values are ignored. Create the scope with its full options before any ` +
612
- `caller requests it without them, or use a differently named scope.`);
613
- }
614
- }
615
- return scope;
616
- }
617
- clearAll() {
618
- for (const scope of this.scopes.values())
619
- scope.clear();
620
- }
621
- }
622
- // ── Internal helpers ───────────────────────────────────────────────────────
623
- /**
624
- * Replays a list of operations through a {@link Transaction}. Used by both undo,
625
- * which replays the captured inverses, and redo, which replays the captured
626
- * forwards. Each operation is awaited in turn to preserve ordering.
627
- */
628
- async function applyOps(tx, ops) {
629
- const mutateAny = tx.mutations;
630
- for (const op of ops) {
631
- const m = mutateAny[op.modelKey];
632
- if (!m) {
633
- // A persisted inverse op references a model the schema no longer has;
634
- // fail with a clear message rather than an opaque TypeError.
635
- throw new Error(`Cannot undo: model "${op.modelKey}" is not part of the current schema.`);
636
- }
637
- switch (op.kind) {
638
- case 'create':
639
- await m.create(op.data);
640
- break;
641
- case 'update':
642
- await m.update(op.patch);
643
- break;
644
- case 'delete':
645
- await m.delete(op.id);
646
- break;
647
- case 'createMany':
648
- await m.create(op.data);
649
- break;
650
- case 'updateMany':
651
- await m.update(op.patches);
652
- break;
653
- case 'deleteMany':
654
- await m.delete(op.ids);
655
- break;
656
- }
657
- }
658
- }