@abloatai/ablo 0.26.0 → 0.28.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 (418) hide show
  1. package/CHANGELOG.md +42 -2
  2. package/README.md +102 -86
  3. package/dist/BaseSyncedStore.d.ts +85 -88
  4. package/dist/BaseSyncedStore.js +134 -151
  5. package/dist/Database.d.ts +68 -69
  6. package/dist/Database.js +316 -135
  7. package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
  8. package/dist/{ObjectPool.js → InstanceCache.js} +85 -83
  9. package/dist/LazyReferenceCollection.d.ts +11 -15
  10. package/dist/LazyReferenceCollection.js +12 -16
  11. package/dist/Model.d.ts +54 -52
  12. package/dist/Model.js +78 -62
  13. package/dist/ModelRegistry.d.ts +21 -19
  14. package/dist/ModelRegistry.js +23 -27
  15. package/dist/NetworkMonitor.d.ts +5 -6
  16. package/dist/NetworkMonitor.js +5 -6
  17. package/dist/SyncClient.d.ts +122 -118
  18. package/dist/SyncClient.js +541 -245
  19. package/dist/adapters/alwaysOnline.d.ts +6 -8
  20. package/dist/adapters/alwaysOnline.js +6 -8
  21. package/dist/adapters/inMemoryStorage.d.ts +10 -9
  22. package/dist/adapters/inMemoryStorage.js +21 -9
  23. package/dist/agent/Agent.d.ts +27 -32
  24. package/dist/agent/Agent.js +18 -19
  25. package/dist/agent/index.d.ts +4 -4
  26. package/dist/agent/index.js +5 -5
  27. package/dist/agent/session.d.ts +47 -44
  28. package/dist/agent/session.js +37 -48
  29. package/dist/agent/types.d.ts +26 -31
  30. package/dist/agent/types.js +6 -7
  31. package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
  32. package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
  33. package/dist/ai-sdk/coordinationContext.d.ts +46 -0
  34. package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +26 -33
  35. package/dist/ai-sdk/index.d.ts +25 -22
  36. package/dist/ai-sdk/index.js +25 -22
  37. package/dist/ai-sdk/wrap.d.ts +6 -7
  38. package/dist/ai-sdk/wrap.js +1 -1
  39. package/dist/auth/credentialPolicy.d.ts +69 -74
  40. package/dist/auth/credentialPolicy.js +51 -56
  41. package/dist/auth/credentialSource.d.ts +6 -5
  42. package/dist/auth/credentialSource.js +9 -10
  43. package/dist/auth/index.d.ts +59 -58
  44. package/dist/auth/index.js +31 -37
  45. package/dist/auth/schemas.d.ts +5 -4
  46. package/dist/auth/schemas.js +5 -4
  47. package/dist/batching/index.d.ts +19 -21
  48. package/dist/batching/index.js +14 -17
  49. package/dist/cli.cjs +173 -121
  50. package/dist/client/Ablo.d.ts +97 -74
  51. package/dist/client/Ablo.js +129 -163
  52. package/dist/client/ApiClient.d.ts +30 -19
  53. package/dist/client/ApiClient.js +442 -81
  54. package/dist/client/auth.d.ts +47 -47
  55. package/dist/client/auth.js +108 -117
  56. package/dist/client/claimHeartbeatLoop.d.ts +50 -0
  57. package/dist/client/claimHeartbeatLoop.js +88 -0
  58. package/dist/client/consoleLogger.d.ts +5 -6
  59. package/dist/client/consoleLogger.js +5 -6
  60. package/dist/client/createInternalComponents.d.ts +16 -17
  61. package/dist/client/createInternalComponents.js +26 -31
  62. package/dist/client/createModelProxy.d.ts +130 -120
  63. package/dist/client/createModelProxy.js +152 -122
  64. package/dist/client/credentialEndpoint.d.ts +40 -42
  65. package/dist/client/credentialEndpoint.js +35 -36
  66. package/dist/client/functionalUpdate.d.ts +29 -27
  67. package/dist/client/functionalUpdate.js +21 -21
  68. package/dist/client/hostedEndpoints.d.ts +9 -12
  69. package/dist/client/hostedEndpoints.js +9 -12
  70. package/dist/client/httpClient.d.ts +59 -53
  71. package/dist/client/httpClient.js +29 -31
  72. package/dist/client/identity.d.ts +15 -20
  73. package/dist/client/identity.js +47 -58
  74. package/dist/client/modelRegistration.d.ts +5 -9
  75. package/dist/client/modelRegistration.js +78 -87
  76. package/dist/client/options.d.ts +157 -157
  77. package/dist/client/options.js +3 -7
  78. package/dist/client/registerDataSource.d.ts +9 -9
  79. package/dist/client/registerDataSource.js +15 -16
  80. package/dist/client/resourceTypes.d.ts +64 -75
  81. package/dist/client/resourceTypes.js +4 -10
  82. package/dist/client/schemaConfig.d.ts +31 -43
  83. package/dist/client/schemaConfig.js +38 -50
  84. package/dist/client/sessionMint.d.ts +16 -12
  85. package/dist/client/sessionMint.js +26 -31
  86. package/dist/client/validateAbloOptions.d.ts +12 -14
  87. package/dist/client/validateAbloOptions.js +8 -9
  88. package/dist/client/writeOptionsSchema.d.ts +18 -16
  89. package/dist/client/writeOptionsSchema.js +23 -20
  90. package/dist/client/wsMutationExecutor.d.ts +16 -20
  91. package/dist/client/wsMutationExecutor.js +18 -23
  92. package/dist/commit/contract.d.ts +493 -0
  93. package/dist/commit/contract.js +187 -0
  94. package/dist/commit/index.d.ts +6 -0
  95. package/dist/commit/index.js +5 -0
  96. package/dist/context.d.ts +6 -4
  97. package/dist/context.js +6 -4
  98. package/dist/coordination/index.d.ts +10 -8
  99. package/dist/coordination/index.js +14 -12
  100. package/dist/coordination/schema.d.ts +176 -128
  101. package/dist/coordination/schema.js +197 -133
  102. package/dist/coordination/trace.d.ts +9 -10
  103. package/dist/coordination/trace.js +13 -14
  104. package/dist/core/DatabaseManager.d.ts +5 -7
  105. package/dist/core/DatabaseManager.js +15 -19
  106. package/dist/core/QueryProcessor.d.ts +7 -9
  107. package/dist/core/QueryProcessor.js +22 -28
  108. package/dist/core/QueryView.d.ts +8 -8
  109. package/dist/core/QueryView.js +2 -2
  110. package/dist/core/StoreManager.d.ts +14 -14
  111. package/dist/core/StoreManager.js +33 -24
  112. package/dist/core/ViewRegistry.d.ts +5 -5
  113. package/dist/core/ViewRegistry.js +4 -4
  114. package/dist/core/index.d.ts +17 -12
  115. package/dist/core/index.js +32 -26
  116. package/dist/core/openIDBWithTimeout.d.ts +38 -36
  117. package/dist/core/openIDBWithTimeout.js +42 -43
  118. package/dist/core/queryUtils.d.ts +45 -0
  119. package/dist/core/queryUtils.js +69 -0
  120. package/dist/core/storeContract.d.ts +63 -61
  121. package/dist/core/storeContract.js +8 -12
  122. package/dist/environment.d.ts +28 -0
  123. package/dist/environment.js +21 -0
  124. package/dist/errorCodes.d.ts +107 -99
  125. package/dist/errorCodes.js +137 -134
  126. package/dist/errors.d.ts +160 -166
  127. package/dist/errors.js +155 -158
  128. package/dist/index.d.ts +36 -27
  129. package/dist/index.js +91 -86
  130. package/dist/interfaces/index.d.ts +102 -113
  131. package/dist/interfaces/index.js +5 -4
  132. package/dist/keys/index.d.ts +27 -29
  133. package/dist/keys/index.js +41 -40
  134. package/dist/mutators/RecordingTransaction.d.ts +16 -16
  135. package/dist/mutators/RecordingTransaction.js +31 -37
  136. package/dist/mutators/Transaction.d.ts +18 -26
  137. package/dist/mutators/Transaction.js +14 -20
  138. package/dist/mutators/UndoManager.d.ts +124 -131
  139. package/dist/mutators/UndoManager.js +177 -156
  140. package/dist/mutators/defineMutators.d.ts +23 -34
  141. package/dist/mutators/defineMutators.js +14 -20
  142. package/dist/mutators/inverseOp.d.ts +12 -15
  143. package/dist/mutators/inverseOp.js +12 -15
  144. package/dist/mutators/mutateActions.d.ts +10 -9
  145. package/dist/mutators/mutateActions.js +1 -1
  146. package/dist/mutators/readerActions.d.ts +9 -8
  147. package/dist/mutators/readerActions.js +2 -2
  148. package/dist/mutators/undoApply.d.ts +31 -27
  149. package/dist/mutators/undoApply.js +26 -24
  150. package/dist/policy/index.d.ts +5 -3
  151. package/dist/policy/index.js +5 -3
  152. package/dist/policy/types.d.ts +104 -100
  153. package/dist/policy/types.js +67 -66
  154. package/dist/query/client.d.ts +28 -23
  155. package/dist/query/client.js +45 -43
  156. package/dist/query/types.d.ts +37 -60
  157. package/dist/query/types.js +13 -33
  158. package/dist/react/AbloProvider.d.ts +1 -1
  159. package/dist/react/AbloProvider.js +2 -2
  160. package/dist/react/context.d.ts +25 -28
  161. package/dist/react/context.js +9 -10
  162. package/dist/react/index.d.ts +41 -42
  163. package/dist/react/index.js +37 -38
  164. package/dist/react/internalContext.d.ts +17 -19
  165. package/dist/react/useAblo.d.ts +28 -25
  166. package/dist/react/useAblo.js +41 -17
  167. package/dist/react/useCurrentUserId.d.ts +8 -7
  168. package/dist/react/useCurrentUserId.js +8 -7
  169. package/dist/react/useErrorListener.d.ts +7 -7
  170. package/dist/react/useErrorListener.js +10 -11
  171. package/dist/react/useMutationFailureListener.d.ts +8 -8
  172. package/dist/react/useMutationFailureListener.js +8 -8
  173. package/dist/react/useMutators.d.ts +11 -11
  174. package/dist/react/useMutators.js +3 -3
  175. package/dist/react/useReactive.js +2 -2
  176. package/dist/react/useSyncStatus.d.ts +4 -6
  177. package/dist/react/useUndoScope.d.ts +7 -9
  178. package/dist/react/useUndoScope.js +1 -1
  179. package/dist/schema/coordination.d.ts +21 -25
  180. package/dist/schema/coordination.js +21 -25
  181. package/dist/schema/ddl.d.ts +43 -39
  182. package/dist/schema/ddl.js +75 -68
  183. package/dist/schema/ddlLock.d.ts +20 -24
  184. package/dist/schema/ddlLock.js +18 -23
  185. package/dist/schema/diff.d.ts +99 -61
  186. package/dist/schema/diff.js +43 -34
  187. package/dist/schema/field.d.ts +37 -42
  188. package/dist/schema/field.js +35 -48
  189. package/dist/schema/generate.d.ts +12 -12
  190. package/dist/schema/generate.js +12 -12
  191. package/dist/schema/index.d.ts +3 -3
  192. package/dist/schema/index.js +21 -23
  193. package/dist/schema/model.d.ts +118 -143
  194. package/dist/schema/model.js +22 -33
  195. package/dist/schema/openapi.d.ts +10 -9
  196. package/dist/schema/openapi.js +5 -3
  197. package/dist/schema/queries.d.ts +29 -31
  198. package/dist/schema/queries.js +23 -25
  199. package/dist/schema/relation.d.ts +89 -99
  200. package/dist/schema/relation.js +13 -13
  201. package/dist/schema/residency.d.ts +16 -13
  202. package/dist/schema/residency.js +16 -13
  203. package/dist/schema/roles.d.ts +36 -43
  204. package/dist/schema/roles.js +31 -37
  205. package/dist/schema/schema.d.ts +64 -43
  206. package/dist/schema/schema.js +31 -32
  207. package/dist/schema/select.d.ts +13 -13
  208. package/dist/schema/select.js +13 -13
  209. package/dist/schema/serialize.d.ts +28 -31
  210. package/dist/schema/serialize.js +27 -31
  211. package/dist/schema/sugar.d.ts +17 -32
  212. package/dist/schema/sugar.js +14 -29
  213. package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +26 -49
  214. package/dist/schema/syncDeltaRow.js +89 -0
  215. package/dist/schema/tenancy.d.ts +44 -46
  216. package/dist/schema/tenancy.js +46 -48
  217. package/dist/server/adapter.d.ts +58 -58
  218. package/dist/server/adapter.js +13 -14
  219. package/dist/server/commit.d.ts +60 -64
  220. package/dist/server/index.d.ts +9 -10
  221. package/dist/server/index.js +1 -1
  222. package/dist/server/readConfig.d.ts +70 -0
  223. package/dist/server/readConfig.js +8 -0
  224. package/dist/server/storageMode.d.ts +23 -0
  225. package/dist/server/storageMode.js +17 -0
  226. package/dist/source/adapter.d.ts +30 -25
  227. package/dist/source/adapter.js +10 -10
  228. package/dist/source/adapters/drizzle.d.ts +28 -23
  229. package/dist/source/adapters/drizzle.js +30 -25
  230. package/dist/source/adapters/kysely.d.ts +27 -25
  231. package/dist/source/adapters/kysely.js +24 -23
  232. package/dist/source/adapters/memory.d.ts +8 -7
  233. package/dist/source/adapters/memory.js +9 -8
  234. package/dist/source/adapters/prisma.d.ts +13 -12
  235. package/dist/source/adapters/prisma.js +22 -25
  236. package/dist/source/conformance.d.ts +18 -11
  237. package/dist/source/conformance.js +17 -11
  238. package/dist/source/connector.d.ts +31 -32
  239. package/dist/source/connector.js +28 -28
  240. package/dist/source/connectorProtocol.d.ts +160 -0
  241. package/dist/source/connectorProtocol.js +162 -0
  242. package/dist/source/contract.d.ts +26 -27
  243. package/dist/source/contract.js +28 -29
  244. package/dist/source/factory.d.ts +46 -58
  245. package/dist/source/factory.js +22 -27
  246. package/dist/source/index.d.ts +7 -9
  247. package/dist/source/index.js +12 -14
  248. package/dist/source/migrations.d.ts +9 -9
  249. package/dist/source/migrations.js +9 -9
  250. package/dist/source/next.d.ts +9 -10
  251. package/dist/source/next.js +6 -7
  252. package/dist/source/pushQueue.d.ts +69 -47
  253. package/dist/source/pushQueue.js +32 -28
  254. package/dist/source/signing.d.ts +46 -17
  255. package/dist/source/signing.js +28 -11
  256. package/dist/source/types.d.ts +121 -104
  257. package/dist/source/types.js +13 -14
  258. package/dist/stores/ObjectStore.d.ts +24 -12
  259. package/dist/stores/ObjectStore.js +38 -16
  260. package/dist/stores/ObjectStoreContract.d.ts +14 -15
  261. package/dist/stores/SyncActionStore.d.ts +7 -11
  262. package/dist/stores/SyncActionStore.js +13 -17
  263. package/dist/surface.d.ts +28 -21
  264. package/dist/surface.js +29 -20
  265. package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +36 -42
  266. package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +76 -76
  267. package/dist/sync/ConnectionManager.d.ts +39 -50
  268. package/dist/sync/ConnectionManager.js +55 -66
  269. package/dist/sync/NetworkProbe.d.ts +24 -29
  270. package/dist/sync/NetworkProbe.js +63 -69
  271. package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +42 -41
  272. package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +59 -54
  273. package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +43 -57
  274. package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +43 -51
  275. package/dist/sync/SyncWebSocket.d.ts +141 -166
  276. package/dist/sync/SyncWebSocket.js +191 -223
  277. package/dist/sync/awaitClaimGrant.d.ts +18 -18
  278. package/dist/sync/awaitClaimGrant.js +11 -11
  279. package/dist/sync/bootstrapApply.d.ts +34 -24
  280. package/dist/sync/bootstrapApply.js +27 -19
  281. package/dist/sync/commitFrames.d.ts +21 -20
  282. package/dist/sync/commitFrames.js +18 -18
  283. package/dist/sync/createClaimStream.d.ts +23 -22
  284. package/dist/sync/createClaimStream.js +105 -23
  285. package/dist/sync/createPresenceStream.d.ts +19 -18
  286. package/dist/sync/createPresenceStream.js +25 -26
  287. package/dist/sync/createSnapshot.d.ts +12 -14
  288. package/dist/sync/createSnapshot.js +20 -26
  289. package/dist/sync/credentialLifecycle.d.ts +104 -104
  290. package/dist/sync/credentialLifecycle.js +140 -147
  291. package/dist/sync/deltaPipeline.d.ts +36 -34
  292. package/dist/sync/deltaPipeline.js +64 -65
  293. package/dist/sync/groupChange.d.ts +63 -61
  294. package/dist/sync/groupChange.js +74 -78
  295. package/dist/sync/heartbeat.d.ts +34 -33
  296. package/dist/sync/heartbeat.js +31 -31
  297. package/dist/sync/participants.d.ts +19 -19
  298. package/dist/sync/persistedPrefix.d.ts +12 -0
  299. package/dist/sync/persistedPrefix.js +22 -0
  300. package/dist/sync/schemas.d.ts +3 -2
  301. package/dist/sync/schemas.js +14 -10
  302. package/dist/sync/syncCursor.d.ts +17 -21
  303. package/dist/sync/syncCursor.js +17 -21
  304. package/dist/sync/syncPlan.d.ts +28 -36
  305. package/dist/sync/syncPlan.js +18 -19
  306. package/dist/sync/syncPosition.d.ts +54 -49
  307. package/dist/sync/syncPosition.js +57 -52
  308. package/dist/sync/wsFrameHandlers.d.ts +35 -36
  309. package/dist/sync/wsFrameHandlers.js +63 -67
  310. package/dist/testing/fixtures/bootstrap.d.ts +12 -6
  311. package/dist/testing/fixtures/bootstrap.js +12 -6
  312. package/dist/testing/fixtures/deltas.d.ts +30 -33
  313. package/dist/testing/fixtures/deltas.js +30 -33
  314. package/dist/testing/fixtures/models.d.ts +11 -10
  315. package/dist/testing/fixtures/models.js +11 -10
  316. package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
  317. package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
  318. package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -15
  319. package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +12 -10
  320. package/dist/testing/helpers/wait.d.ts +13 -8
  321. package/dist/testing/helpers/wait.js +13 -8
  322. package/dist/testing/index.d.ts +5 -3
  323. package/dist/testing/index.js +3 -2
  324. package/dist/testing/mocks/FakeDatabase.d.ts +18 -0
  325. package/dist/testing/mocks/FakeDatabase.js +10 -0
  326. package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
  327. package/dist/testing/mocks/MockMutationExecutor.js +15 -14
  328. package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
  329. package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
  330. package/dist/testing/mocks/MockSyncContext.d.ts +20 -17
  331. package/dist/testing/mocks/MockSyncContext.js +15 -13
  332. package/dist/testing/mocks/MockSyncStore.d.ts +10 -10
  333. package/dist/testing/mocks/MockSyncStore.js +11 -11
  334. package/dist/testing/mocks/MockWebSocket.d.ts +28 -23
  335. package/dist/testing/mocks/MockWebSocket.js +22 -21
  336. package/dist/transactions/TransactionQueue.d.ts +244 -181
  337. package/dist/transactions/TransactionQueue.js +929 -423
  338. package/dist/transactions/TransactionStore.d.ts +6 -4
  339. package/dist/transactions/TransactionStore.js +6 -4
  340. package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
  341. package/dist/transactions/UnconfirmedWrites.js +104 -0
  342. package/dist/transactions/coalesceRules.d.ts +41 -17
  343. package/dist/transactions/coalesceRules.js +40 -17
  344. package/dist/transactions/commitEnvelope.d.ts +132 -0
  345. package/dist/transactions/commitEnvelope.js +139 -0
  346. package/dist/transactions/commitOutboxStore.d.ts +32 -0
  347. package/dist/transactions/commitOutboxStore.js +26 -0
  348. package/dist/transactions/commitPayload.d.ts +63 -52
  349. package/dist/transactions/commitPayload.js +54 -57
  350. package/dist/transactions/deltaConfirmation.d.ts +20 -22
  351. package/dist/transactions/deltaConfirmation.js +37 -45
  352. package/dist/transactions/httpCommitEnvelope.d.ts +43 -0
  353. package/dist/transactions/httpCommitEnvelope.js +179 -0
  354. package/dist/transactions/optimisticApply.d.ts +49 -0
  355. package/dist/transactions/optimisticApply.js +65 -0
  356. package/dist/transactions/replayValidation.d.ts +182 -0
  357. package/dist/transactions/replayValidation.js +156 -0
  358. package/dist/types/global.d.ts +46 -41
  359. package/dist/types/global.js +20 -19
  360. package/dist/types/index.d.ts +71 -77
  361. package/dist/types/index.js +22 -22
  362. package/dist/types/modelData.d.ts +6 -8
  363. package/dist/types/modelData.js +5 -7
  364. package/dist/types/participant.d.ts +10 -11
  365. package/dist/types/participant.js +6 -8
  366. package/dist/types/streams.d.ts +208 -195
  367. package/dist/types/streams.js +7 -7
  368. package/dist/utils/asyncIterator.d.ts +25 -32
  369. package/dist/utils/asyncIterator.js +25 -32
  370. package/dist/utils/duration.d.ts +12 -15
  371. package/dist/utils/duration.js +12 -15
  372. package/dist/utils/mobxSetup.d.ts +53 -0
  373. package/dist/utils/{mobx-setup.js → mobxSetup.js} +42 -98
  374. package/dist/webhooks/events.d.ts +21 -16
  375. package/dist/webhooks/events.js +10 -8
  376. package/dist/webhooks/index.d.ts +5 -7
  377. package/dist/webhooks/index.js +5 -7
  378. package/dist/wire/bootstrapReason.d.ts +9 -0
  379. package/dist/wire/bootstrapReason.js +8 -0
  380. package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
  381. package/dist/wire/delta.js +114 -0
  382. package/dist/wire/errorEnvelope.d.ts +30 -31
  383. package/dist/wire/errorEnvelope.js +34 -40
  384. package/dist/wire/frames.d.ts +315 -86
  385. package/dist/wire/frames.js +47 -33
  386. package/dist/wire/index.d.ts +18 -14
  387. package/dist/wire/index.js +32 -27
  388. package/dist/wire/listEnvelope.d.ts +16 -23
  389. package/dist/wire/listEnvelope.js +7 -6
  390. package/dist/wire/protocol.d.ts +25 -32
  391. package/dist/wire/protocol.js +25 -32
  392. package/dist/wire/protocolVersion.d.ts +44 -40
  393. package/dist/wire/protocolVersion.js +44 -40
  394. package/docs/api.md +10 -10
  395. package/docs/coordination.md +59 -0
  396. package/docs/mcp.md +1 -1
  397. package/package.json +17 -11
  398. package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
  399. package/dist/ai-sdk/coordination-context.d.ts +0 -52
  400. package/dist/core/query-utils.d.ts +0 -34
  401. package/dist/core/query-utils.js +0 -59
  402. package/dist/schema/sync-delta-row.js +0 -103
  403. package/dist/schema/sync-delta-wire.js +0 -102
  404. package/dist/server/read-config.d.ts +0 -67
  405. package/dist/server/read-config.js +0 -8
  406. package/dist/server/storage-mode.d.ts +0 -8
  407. package/dist/server/storage-mode.js +0 -28
  408. package/dist/source/connector-protocol.d.ts +0 -159
  409. package/dist/source/connector-protocol.js +0 -161
  410. package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
  411. package/dist/transactions/OptimisticEchoTracker.js +0 -104
  412. package/dist/transactions/mutation-error-handler.d.ts +0 -5
  413. package/dist/transactions/mutation-error-handler.js +0 -39
  414. package/dist/transactions/optimistic.d.ts +0 -24
  415. package/dist/transactions/optimistic.js +0 -45
  416. package/dist/transactions/persistedReplay.d.ts +0 -93
  417. package/dist/transactions/persistedReplay.js +0 -105
  418. package/dist/utils/mobx-setup.d.ts +0 -42
@@ -1,34 +1,42 @@
1
1
  /**
2
- * Transport-driven ClaimStream factory.
2
+ * Creates a {@link ClaimStream} over a live sync connection. A claim is a
3
+ * short-lived, advisory lease a participant takes on an entity (or a field of
4
+ * one) to signal "I'm working on this"; the stream lets you take claims, see
5
+ * everyone else's, and watch the wait queue when a claim is contended.
3
6
  *
4
- * Mirrors `createPresenceStream` built directly on `SyncWebSocket`,
5
- * no SyncAgent wrapper. Claims derive their `others` view from the
6
- * same `presence_update` frames the presence stream consumes (the
7
- * Hub piggybacks `activeClaims` on every presence frame). Outbound
8
- * announce/revoke ride the same socket via `claim_begin` /
7
+ * The stream is built directly on the sync WebSocket and shares that one
8
+ * connection. It learns about other participants' claims from the same
9
+ * `presence_update` frames the {@link createPresenceStream} presence stream
10
+ * consumes — the server piggybacks each participant's `activeClaims` on every
11
+ * presence frame and sends its own claims as `claim_begin` and
9
12
  * `claim_abandon` frames.
10
13
  *
11
- * Wire contract (apps/sync-server/src/hub/types.ts):
12
- * • Outbound: `{ type: 'claim_begin', payload: { claimId,
13
- * entityType, entityId, reason, field?, estimatedMs? } }`
14
- * • Outbound: `{ type: 'claim_abandon', payload: { claimId,
15
- * entityType?, entityId? } }`
16
- * • Inbound (via presence): `event.activeClaims: Claim[]`
17
- * stamped with `declaredAt`, `expiresAt`.
18
- * • Inbound: `claim_rejected` event with conflict metadata.
19
- *
20
- * After the dual-engine collapse (step #36), this is the only
21
- * ClaimStream factory in the SDK; the older compatibility path
22
- * deletes.
14
+ * Wire frames:
15
+ * • Outbound `claim_begin` announce a claim: `{ claimId, entityType,
16
+ * entityId, reason, field?, estimatedMs? }`.
17
+ * • Outbound `claim_abandon` release it: `{ claimId, entityType?,
18
+ * entityId? }`.
19
+ * • Inbound, via presence `event.activeClaims`, each stamped with
20
+ * `declaredAt` and `expiresAt`.
21
+ * • Inbound `claim_rejected` the server refused the claim, with conflict
22
+ * metadata.
23
23
  */
24
24
  import { asyncIteratorFrom } from '../utils/asyncIterator.js';
25
25
  import { toMs } from '../utils/duration.js';
26
- import { descriptionFromMeta, participantKindFromWire, } from '../coordination/schema.js';
26
+ import { claimHeartbeatAckPayloadSchema, descriptionFromMeta, participantKindFromWire, } from '../coordination/schema.js';
27
+ import { AbloClaimedError, AbloConnectionError } from '../errors.js';
28
+ import { resolveHeartbeatOptions } from '../client/claimHeartbeatLoop.js';
27
29
  import { getContext } from '../context.js';
28
30
  /** Readable target for the coordination trace: `documents:abc` / `documents:abc.title`. */
29
31
  function claimLabel(type, id, field) {
30
32
  return field ? `${type}:${id}.${field}` : `${type}:${id}`;
31
33
  }
34
+ /**
35
+ * How long a heartbeat waits for its `claim_heartbeat_ack` before giving up
36
+ * as transient (the auto-heartbeat loop's next tick retries). Comfortably
37
+ * above a round trip, comfortably below the ttl/3 beat cadence.
38
+ */
39
+ const HEARTBEAT_ACK_TIMEOUT_MS = 10_000;
32
40
  export function createClaimStream(config, transport = null) {
33
41
  const { participantId } = config;
34
42
  // ── State: others' open claims, keyed by claimId ───────────────
@@ -49,6 +57,16 @@ export function createClaimStream(config, transport = null) {
49
57
  const listeners = new Set();
50
58
  const rejectionListeners = new Set();
51
59
  const lostListeners = new Set();
60
+ // ── State: in-flight heartbeats awaiting their ack, keyed by claimId ──
61
+ const pendingHeartbeats = new Map();
62
+ const settleHeartbeat = (claimId, settle) => {
63
+ const pending = pendingHeartbeats.get(claimId);
64
+ if (!pending)
65
+ return;
66
+ pendingHeartbeats.delete(claimId);
67
+ clearTimeout(pending.timer);
68
+ settle(pending);
69
+ };
52
70
  const notifyListeners = () => {
53
71
  claimsSnapshot = Object.freeze(Array.from(activeByClaimId.values()));
54
72
  for (const l of listeners) {
@@ -151,8 +169,9 @@ export function createClaimStream(config, transport = null) {
151
169
  }
152
170
  }
153
171
  }));
154
- // (2a) Server-side LOSS frames — you held it, then lost it (preempted /
155
- // expired). Distinct from a rejection (a claim the server refused).
172
+ // (2a) Server-side loss frames — you held the claim, then lost it
173
+ // (preempted or expired). Distinct from a rejection, which is a claim
174
+ // the server refused.
156
175
  unsubs.push(t.subscribe('claim_lost', (payload) => {
157
176
  const lost = payload;
158
177
  if (!lost.claimId)
@@ -186,7 +205,7 @@ export function createClaimStream(config, transport = null) {
186
205
  queueByEntity.delete(key);
187
206
  else
188
207
  queueByEntity.set(key, Object.freeze([...line]));
189
- // If WE are in this line, trace our position (the "agent queued behind a
208
+ // If we are in this line, trace our position (the "agent queued behind a
190
209
  // claim" moment) — once per position change, so advancing is visible.
191
210
  const ourIndex = line.findIndex((c) => ownClaims.has(c.id));
192
211
  const ourClaim = ourIndex >= 0 ? line[ourIndex] : undefined;
@@ -199,6 +218,30 @@ export function createClaimStream(config, transport = null) {
199
218
  }
200
219
  notifyListeners();
201
220
  }));
221
+ // (2c) Heartbeat replies — correlate back to the awaiting beat by
222
+ // claimId. `held` resolves with the extended expiry; `queued` and
223
+ // `lost` reject with a typed claimed error, because a heartbeat on
224
+ // a handle we thought we held coming back as anything but `held`
225
+ // means the lease is no longer ours.
226
+ unsubs.push(t.subscribe('claim_heartbeat_ack', (payload) => {
227
+ const parsed = claimHeartbeatAckPayloadSchema.safeParse(payload);
228
+ if (!parsed.success)
229
+ return;
230
+ const ack = parsed.data;
231
+ settleHeartbeat(ack.claimId, ({ resolve, reject }) => {
232
+ if (ack.status === 'held' && ack.expiresAt !== undefined) {
233
+ resolve({
234
+ expiresAt: ack.expiresAt,
235
+ ...(ack.queueDepth !== undefined
236
+ ? { queueDepth: ack.queueDepth }
237
+ : {}),
238
+ });
239
+ return;
240
+ }
241
+ const c = ownClaims.get(ack.claimId);
242
+ reject(new AbloClaimedError(`The lease behind ${c ? claimLabel(c.entityType, c.entityId, c.field) : `claim ${ack.claimId}`} is no longer held — it expired or was granted onward while this participant was working. Re-acquire the claim and retry; a write attempted under the old lease is rejected by its \`readAt\` guard.`, { code: 'claim_lost' }));
243
+ });
244
+ }));
202
245
  // (3) On reconnect, re-announce every open self-claim — the
203
246
  // server's claim state is in-memory and is lost across
204
247
  // restarts. Without this, peers would see our claims vanish
@@ -245,6 +288,39 @@ export function createClaimStream(config, transport = null) {
245
288
  },
246
289
  });
247
290
  }
291
+ /**
292
+ * Send one heartbeat and await its ack. Rejects with
293
+ * {@link AbloConnectionError} (transient — the auto-heartbeat loop retries
294
+ * on its next tick) when the socket is down or the ack times out, and with
295
+ * {@link AbloClaimedError} (definitive) when the server answers that the
296
+ * lease is no longer ours.
297
+ */
298
+ function sendHeartbeat(claimId, claim, options) {
299
+ if (!attached?.isConnected()) {
300
+ return Promise.reject(new AbloConnectionError(`The heartbeat for ${claimLabel(claim.entityType, claim.entityId, claim.field)} was skipped because the connection is down. The keepalive renews held leases automatically on reconnect; the next beat retries.`));
301
+ }
302
+ return new Promise((resolve, reject) => {
303
+ settleHeartbeat(claimId, ({ reject: rejectPrior }) => {
304
+ rejectPrior(new AbloConnectionError('A newer heartbeat for this claim superseded the one still awaiting its reply.'));
305
+ });
306
+ const timer = setTimeout(() => {
307
+ settleHeartbeat(claimId, ({ reject: rejectTimeout }) => {
308
+ rejectTimeout(new AbloConnectionError(`No reply to the heartbeat for ${claimLabel(claim.entityType, claim.entityId, claim.field)} arrived within ${HEARTBEAT_ACK_TIMEOUT_MS / 1000}s. The next beat retries.`));
309
+ });
310
+ }, HEARTBEAT_ACK_TIMEOUT_MS);
311
+ pendingHeartbeats.set(claimId, { resolve, reject, timer });
312
+ attached?.send({
313
+ type: 'claim_heartbeat',
314
+ payload: {
315
+ claimId,
316
+ entityType: claim.entityType,
317
+ entityId: claim.entityId,
318
+ ...(options.ttl !== undefined ? { ttlMs: toMs(options.ttl) } : {}),
319
+ ...(options.details !== undefined ? { details: options.details } : {}),
320
+ },
321
+ });
322
+ });
323
+ }
248
324
  function sendAbandon(claimId, claim) {
249
325
  if (!attached?.isConnected())
250
326
  return;
@@ -281,7 +357,7 @@ export function createClaimStream(config, transport = null) {
281
357
  };
282
358
  ownClaims.set(claimId, claim);
283
359
  sendBegin(claimId, claim);
284
- // Coordination trace (info): the creator can SEE their human/agent claims.
360
+ // Coordination trace (info): the creator can see their human/agent claims.
285
361
  getContext().logger.info(`claim: requesting ${claimLabel(claim.entityType, claim.entityId, claim.field)} for "${claim.reason}"` +
286
362
  (claim.queue ? ' (will queue if contended)' : ''), { claimId });
287
363
  let revoked = false;
@@ -310,6 +386,7 @@ export function createClaimStream(config, transport = null) {
310
386
  revoke();
311
387
  },
312
388
  revoke,
389
+ heartbeat: (options) => sendHeartbeat(claimId, claim, resolveHeartbeatOptions(options)),
313
390
  [Symbol.asyncDispose]: async () => {
314
391
  revoke();
315
392
  },
@@ -377,6 +454,11 @@ export function createClaimStream(config, transport = null) {
377
454
  for (const off of unsubs)
378
455
  off();
379
456
  unsubs.length = 0;
457
+ for (const claimId of [...pendingHeartbeats.keys()]) {
458
+ settleHeartbeat(claimId, ({ reject }) => {
459
+ reject(new AbloConnectionError('The claim stream was disposed while this heartbeat was awaiting its reply.'));
460
+ });
461
+ }
380
462
  listeners.clear();
381
463
  rejectionListeners.clear();
382
464
  lostListeners.clear();
@@ -1,25 +1,26 @@
1
1
  /**
2
- * Transport-driven PresenceStream factory.
2
+ * Creates a {@link PresenceStream} over a live sync connection. Presence is the
3
+ * lightweight, ephemeral "who's here and what are they doing" view: each
4
+ * participant broadcasts a status and an activity, and sees everyone else's.
5
+ * The stream is built directly on the sync WebSocket and adds no second
6
+ * connection. It is the sibling of {@link createClaimStream}, which reuses the
7
+ * same presence frames.
3
8
  *
4
- * This is the engine's home for presence — built directly on
5
- * `SyncWebSocket`, no SyncAgent wrapper, no second connection. The
6
- * older compatibility path predates this and will be deleted when
7
- * the dual-engine collapse completes.
9
+ * There are two ways to construct it:
8
10
  *
9
- * Two construction modes:
11
+ * 1. Direct pass an already-open `transport`, for example an agent worker
12
+ * or a test.
13
+ * 2. Deferred — construct without a transport and call `attach(transport)`
14
+ * once the connection is ready. The returned stream object is stable from
15
+ * construction, so callers can hold the reference and let attachment
16
+ * happen later.
10
17
  *
11
- * 1. Direct — pass `transport: SyncWebSocket` when it's already
12
- * open (agent worker, tests).
13
- * 2. Deferred pass `attachLater: true` and call `.attach(transport)`
14
- * once the engine's WS lifecycle has produced one. The returned
15
- * stream object is stable from construction; attachment can
16
- * happen later without callers having to re-grab the reference.
17
- *
18
- * Wire contract (apps/sync-server/src/hub/types.ts):
19
- * • Outbound: `{ type: 'presence_update', payload: { status, activity? } }`
20
- * — server stamps `userId`, `kind`, `timestamp`, `isAgent` and
21
- * broadcasts to other clients on the same sync groups.
22
- * • Inbound: same frame, with `kind: 'enter' | 'update' | 'leave'`.
18
+ * Wire frames:
19
+ * Outbound `presence_update` — `{ status, activity? }`. The server stamps
20
+ * `userId`, `kind`, `timestamp`, and `isAgent`, then broadcasts to the
21
+ * other participants on the same sync groups.
22
+ * Inbound the same frame, with `kind` one of `enter`, `update`, or
23
+ * `leave`.
23
24
  */
24
25
  import type { SyncWebSocket } from './SyncWebSocket.js';
25
26
  import type { PresenceStream } from '../types/streams.js';
@@ -1,25 +1,26 @@
1
1
  /**
2
- * Transport-driven PresenceStream factory.
2
+ * Creates a {@link PresenceStream} over a live sync connection. Presence is the
3
+ * lightweight, ephemeral "who's here and what are they doing" view: each
4
+ * participant broadcasts a status and an activity, and sees everyone else's.
5
+ * The stream is built directly on the sync WebSocket and adds no second
6
+ * connection. It is the sibling of {@link createClaimStream}, which reuses the
7
+ * same presence frames.
3
8
  *
4
- * This is the engine's home for presence — built directly on
5
- * `SyncWebSocket`, no SyncAgent wrapper, no second connection. The
6
- * older compatibility path predates this and will be deleted when
7
- * the dual-engine collapse completes.
9
+ * There are two ways to construct it:
8
10
  *
9
- * Two construction modes:
11
+ * 1. Direct pass an already-open `transport`, for example an agent worker
12
+ * or a test.
13
+ * 2. Deferred — construct without a transport and call `attach(transport)`
14
+ * once the connection is ready. The returned stream object is stable from
15
+ * construction, so callers can hold the reference and let attachment
16
+ * happen later.
10
17
  *
11
- * 1. Direct — pass `transport: SyncWebSocket` when it's already
12
- * open (agent worker, tests).
13
- * 2. Deferred pass `attachLater: true` and call `.attach(transport)`
14
- * once the engine's WS lifecycle has produced one. The returned
15
- * stream object is stable from construction; attachment can
16
- * happen later without callers having to re-grab the reference.
17
- *
18
- * Wire contract (apps/sync-server/src/hub/types.ts):
19
- * • Outbound: `{ type: 'presence_update', payload: { status, activity? } }`
20
- * — server stamps `userId`, `kind`, `timestamp`, `isAgent` and
21
- * broadcasts to other clients on the same sync groups.
22
- * • Inbound: same frame, with `kind: 'enter' | 'update' | 'leave'`.
18
+ * Wire frames:
19
+ * Outbound `presence_update` — `{ status, activity? }`. The server stamps
20
+ * `userId`, `kind`, `timestamp`, and `isAgent`, then broadcasts to the
21
+ * other participants on the same sync groups.
22
+ * Inbound the same frame, with `kind` one of `enter`, `update`, or
23
+ * `leave`.
23
24
  */
24
25
  import { asyncIteratorFrom } from '../utils/asyncIterator.js';
25
26
  import { participantKindFromWire } from '../coordination/schema.js';
@@ -67,10 +68,9 @@ export function createPresenceStream(config, transport = null) {
67
68
  if (self.activity.entityId)
68
69
  sendUpdate(self.activity);
69
70
  }));
70
- // Inbound presence frames translate the legacy wire vocabulary
71
- // (userId / isAgent / timestamp) into the engine shape
72
- // (participantId / participantKind / lastActive). When the server
73
- // adopts the engine names this block collapses to a pass-through.
71
+ // Inbound presence frames arrive in the wire vocabulary
72
+ // (userId / isAgent / timestamp); translate them into the shape this
73
+ // stream exposes (participantId / participantKind / lastActive).
74
74
  unsubs.push(t.subscribe('presence_update', (event) => {
75
75
  if (event.userId === participantId)
76
76
  return; // own echo
@@ -117,10 +117,9 @@ export function createPresenceStream(config, transport = null) {
117
117
  if (transport)
118
118
  attach(transport);
119
119
  // ── Outbound ────────────────────────────────────────────────────
120
- // Note: do NOT include `isAgent` in the payload. Server derives it
121
- // authoritatively from the connection's identity prefix; clients
122
- // self-declaring `isAgent` caused human sessions to broadcast as
123
- // agents to peers (real bug we caught earlier).
120
+ // Do not include `isAgent` in the payload. The server derives it
121
+ // authoritatively from the connection's identity, and letting a client
122
+ // self-declare it once caused human sessions to broadcast as agents to peers.
124
123
  function sendUpdate(activity) {
125
124
  if (!attached?.isConnected())
126
125
  return; // no-op until connected
@@ -1,24 +1,22 @@
1
1
  /**
2
- * Engine-attached snapshot factory.
2
+ * Captures a {@link Snapshot} of a chosen set of entities, along with a
3
+ * watermark, so a caller can detect when that state has gone stale. This is
4
+ * what an LLM caller threads into a prompt: `stamp` flows into later writes as
5
+ * `readAt`, so the server rejects a mutation premised on data that has since
6
+ * changed; `signal` is an `AbortSignal` that fires as soon as any captured
7
+ * entity receives a delta, so a mid-generation invalidation can abort the token
8
+ * stream instead of producing output against stale context.
3
9
  *
4
- * Captures the engine's current entity state + watermark for context-
5
- * staleness detection. The returned Snapshot is what an LLM caller
6
- * threads into a prompt: `stamp` flows into writes as `readAt` so the
7
- * server rejects mutations against now-stale data; `signal` fires on
8
- * any captured-entity delta so mid-generation invalidations abort
9
- * the token stream rather than producing output against dead context.
10
- *
11
- * Reads from the engine's MobX-reactive ObjectPool, picks up the
12
- * engine's `lastSyncId`, and subscribes to delta frames on the
13
- * engine's transport. Same socket as entity sync — no second
14
- * connection.
10
+ * It reads the current entity state from the in-memory pool, reads the engine's
11
+ * current `lastSyncId` as the watermark, and subscribes to delta frames on the
12
+ * existing sync connection no second connection.
15
13
  */
16
- import type { ObjectPool } from '../ObjectPool.js';
14
+ import type { InstanceCache } from '../InstanceCache.js';
17
15
  import type { Schema } from '../schema/schema.js';
18
16
  import type { SyncWebSocket } from './SyncWebSocket.js';
19
17
  import type { Snapshot } from '../types/streams.js';
20
18
  export interface CreateSnapshotArgs<TSchema extends Schema = Schema, K extends keyof TSchema['models'] & string = keyof TSchema['models'] & string> {
21
- pool: ObjectPool;
19
+ pool: InstanceCache;
22
20
  /** Live transport for delta subscriptions. May be null if the engine
23
21
  * hasn't connected yet — the snapshot still resolves with current
24
22
  * pool state, but `signal` won't fire until reconnect. */
@@ -1,24 +1,22 @@
1
1
  /**
2
- * Engine-attached snapshot factory.
2
+ * Captures a {@link Snapshot} of a chosen set of entities, along with a
3
+ * watermark, so a caller can detect when that state has gone stale. This is
4
+ * what an LLM caller threads into a prompt: `stamp` flows into later writes as
5
+ * `readAt`, so the server rejects a mutation premised on data that has since
6
+ * changed; `signal` is an `AbortSignal` that fires as soon as any captured
7
+ * entity receives a delta, so a mid-generation invalidation can abort the token
8
+ * stream instead of producing output against stale context.
3
9
  *
4
- * Captures the engine's current entity state + watermark for context-
5
- * staleness detection. The returned Snapshot is what an LLM caller
6
- * threads into a prompt: `stamp` flows into writes as `readAt` so the
7
- * server rejects mutations against now-stale data; `signal` fires on
8
- * any captured-entity delta so mid-generation invalidations abort
9
- * the token stream rather than producing output against dead context.
10
- *
11
- * Reads from the engine's MobX-reactive ObjectPool, picks up the
12
- * engine's `lastSyncId`, and subscribes to delta frames on the
13
- * engine's transport. Same socket as entity sync — no second
14
- * connection.
10
+ * It reads the current entity state from the in-memory pool, reads the engine's
11
+ * current `lastSyncId` as the watermark, and subscribes to delta frames on the
12
+ * existing sync connection no second connection.
15
13
  */
16
14
  import { AbloValidationError } from '../errors.js';
17
15
  import { Model, modelAsRow } from '../Model.js';
18
16
  /**
19
- * Three top-level keys that conflict with the per-model buckets if a
20
- * customer's schema declares a model named `stamp` / `signal` /
21
- * `onChange`. Throw at snapshot time so the collision is loud.
17
+ * The snapshot result exposes `stamp`, `signal`, and `onChange` at its top
18
+ * level, alongside one bucket per model. If a schema declares a model with one
19
+ * of these names, the two would collide, so snapshot creation throws instead.
22
20
  */
23
21
  const RESERVED_SNAPSHOT_KEYS = new Set([
24
22
  'stamp',
@@ -80,9 +78,7 @@ export function createSnapshot(args) {
80
78
  const key = `${delta.modelName}:${delta.modelId}`;
81
79
  if (!watched.has(key))
82
80
  return;
83
- // The snapshot API treats every delta as 'semantic' severity.
84
- // Future: distinguish metadata-only deltas (e.g., updatedAt
85
- // bumps) from content changes — that's a separate scope.
81
+ // Every delta to a captured entity is reported as 'semantic' severity.
86
82
  fireChange({
87
83
  model: delta.modelName,
88
84
  id: delta.modelId,
@@ -96,16 +92,14 @@ export function createSnapshot(args) {
96
92
  signal: controller.signal,
97
93
  onChange: (listener) => {
98
94
  listeners.add(listener);
99
- // Caller is responsible for unsubscribing when they're done.
100
- // The delta subscription itself stays for the snapshot's life;
101
- // there's no public dispose because snapshots are short-lived
102
- // (one LLM call's worth) and the transport-level subscription
103
- // is cheap. If a long-lived consumer needs explicit teardown,
104
- // we can add `.dispose()` in a follow-up.
95
+ // The caller unsubscribes its own listener via the returned function.
96
+ // The underlying delta subscription lives for the snapshot's lifetime;
97
+ // there is no explicit dispose because a snapshot is short-lived (one
98
+ // LLM call's worth) and the subscription is cheap.
105
99
  return () => {
106
100
  listeners.delete(listener);
107
- // If the last listener AND the abort fired, drop the delta
108
- // subscription too — no one's listening anymore.
101
+ // Once the last listener is gone and the abort has fired, drop the
102
+ // delta subscription too — nothing is listening anymore.
109
103
  if (listeners.size === 0 && controller.signal.aborted && unsubDelta) {
110
104
  unsubDelta();
111
105
  unsubDelta = null;