@abloatai/ablo 0.34.0 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (483) hide show
  1. package/AGENTS.md +4 -1
  2. package/CHANGELOG.md +684 -5
  3. package/README.md +39 -22
  4. package/dist/BaseSyncedStore.d.ts +152 -44
  5. package/dist/BaseSyncedStore.js +300 -184
  6. package/dist/Database.d.ts +9 -24
  7. package/dist/Database.js +37 -22
  8. package/dist/InstanceCache.d.ts +25 -4
  9. package/dist/InstanceCache.js +48 -15
  10. package/dist/LazyReferenceCollection.d.ts +3 -3
  11. package/dist/LazyReferenceCollection.js +4 -4
  12. package/dist/Model.d.ts +6 -6
  13. package/dist/Model.js +10 -10
  14. package/dist/ModelRegistry.d.ts +4 -4
  15. package/dist/ModelRegistry.js +3 -3
  16. package/dist/{SyncEngineContext.d.ts → RuntimeContext.d.ts} +20 -13
  17. package/dist/{SyncEngineContext.js → RuntimeContext.js} +11 -12
  18. package/dist/SyncClient.d.ts +42 -32
  19. package/dist/SyncClient.js +166 -110
  20. package/dist/ai-sdk/coordinatedTool.d.ts +2 -2
  21. package/dist/ai-sdk/coordinatedTool.js +1 -1
  22. package/dist/ai-sdk/coordinationContext.d.ts +2 -2
  23. package/dist/ai-sdk/coordinationContext.js +1 -1
  24. package/dist/ai-sdk/wrap.d.ts +3 -3
  25. package/dist/ai-sdk/wrap.js +2 -2
  26. package/dist/auth/index.d.ts +1 -156
  27. package/dist/auth/index.js +8 -301
  28. package/dist/cli.cjs +3459 -1126
  29. package/dist/client/Ablo.d.ts +42 -287
  30. package/dist/client/Ablo.js +118 -963
  31. package/dist/client/abloClient.d.ts +309 -0
  32. package/dist/client/abloClient.js +13 -0
  33. package/dist/client/clientPrelude.d.ts +52 -0
  34. package/dist/client/clientPrelude.js +60 -0
  35. package/dist/client/consoleLogger.d.ts +2 -2
  36. package/dist/client/coreClient.d.ts +60 -0
  37. package/dist/client/coreClient.js +118 -0
  38. package/dist/client/createInternalComponents.d.ts +4 -4
  39. package/dist/client/createInternalComponents.js +9 -8
  40. package/dist/client/createModelProxy.d.ts +78 -373
  41. package/dist/client/createModelProxy.js +114 -86
  42. package/dist/client/humans.d.ts +48 -0
  43. package/dist/client/humans.js +52 -0
  44. package/dist/client/modelRegistration.d.ts +1 -1
  45. package/dist/client/modelRegistration.js +9 -9
  46. package/dist/client/options.d.ts +73 -17
  47. package/dist/client/reactiveEngine.d.ts +48 -0
  48. package/dist/client/reactiveEngine.js +910 -0
  49. package/dist/client/resourceTypes.d.ts +9 -250
  50. package/dist/client/resourceTypes.js +8 -5
  51. package/dist/client/schemaConfig.d.ts +4 -4
  52. package/dist/client/schemaConfig.js +6 -2
  53. package/dist/client/validateAbloOptions.d.ts +3 -2
  54. package/dist/client/validateAbloOptions.js +1 -1
  55. package/dist/client/wsMutationExecutor.d.ts +3 -3
  56. package/dist/client/wsMutationExecutor.js +3 -3
  57. package/dist/context.d.ts +9 -9
  58. package/dist/context.js +10 -9
  59. package/dist/coordination/ClaimLog.d.ts +26 -0
  60. package/dist/coordination/ClaimLog.js +32 -0
  61. package/dist/coordination/index.d.ts +1 -15
  62. package/dist/coordination/index.js +8 -31
  63. package/dist/core/DatabaseManager.js +1 -1
  64. package/dist/core/QueryView.d.ts +1 -1
  65. package/dist/core/QueryView.js +1 -1
  66. package/dist/core/StoreManager.d.ts +4 -23
  67. package/dist/core/StoreManager.js +5 -55
  68. package/dist/core/index.d.ts +2 -2
  69. package/dist/core/index.js +2 -2
  70. package/dist/core/storeContract.d.ts +2 -2
  71. package/dist/docs/catalog.d.ts +72 -0
  72. package/dist/docs/catalog.js +227 -0
  73. package/dist/docs/index.d.ts +10 -0
  74. package/dist/docs/index.js +10 -0
  75. package/dist/environment.d.ts +1 -40
  76. package/dist/environment.js +8 -37
  77. package/dist/index.d.ts +40 -34
  78. package/dist/index.js +26 -20
  79. package/dist/interfaces/index.d.ts +44 -134
  80. package/dist/keys/index.d.ts +1 -77
  81. package/dist/keys/index.js +8 -190
  82. package/dist/mutators/{RecordingTransaction.d.ts → RecordingMutation.d.ts} +4 -4
  83. package/dist/mutators/{RecordingTransaction.js → RecordingMutation.js} +2 -2
  84. package/dist/mutators/Transaction.d.ts +1 -1
  85. package/dist/mutators/Transaction.js +1 -1
  86. package/dist/mutators/UndoManager.d.ts +6 -6
  87. package/dist/mutators/UndoManager.js +5 -5
  88. package/dist/mutators/defineMutators.d.ts +3 -3
  89. package/dist/mutators/defineMutators.js +1 -1
  90. package/dist/mutators/inverseOp.js +2 -2
  91. package/dist/mutators/mutateActions.d.ts +3 -3
  92. package/dist/mutators/mutateActions.js +1 -1
  93. package/dist/mutators/readerActions.d.ts +1 -1
  94. package/dist/mutators/undoApply.d.ts +1 -1
  95. package/dist/mutators/undoApply.js +1 -1
  96. package/dist/policy/index.d.ts +2 -2
  97. package/dist/policy/index.js +1 -1
  98. package/dist/query/client.d.ts +2 -2
  99. package/dist/query/client.js +4 -4
  100. package/dist/query/types.d.ts +6 -41
  101. package/dist/query/types.js +2 -2
  102. package/dist/react/AbloProvider.d.ts +6 -8
  103. package/dist/react/AbloProvider.js +5 -7
  104. package/dist/react/context.d.ts +1 -1
  105. package/dist/react/context.js +1 -1
  106. package/dist/react/index.d.ts +5 -5
  107. package/dist/react/index.js +3 -3
  108. package/dist/react/internalContext.d.ts +1 -1
  109. package/dist/react/useAblo.d.ts +3 -3
  110. package/dist/react/useAblo.js +1 -1
  111. package/dist/react/useCurrentUserId.js +1 -1
  112. package/dist/react/useErrorListener.js +1 -1
  113. package/dist/react/useMutationFailureListener.d.ts +2 -2
  114. package/dist/react/useMutationFailureListener.js +1 -1
  115. package/dist/react/useMutators.d.ts +3 -3
  116. package/dist/react/useMutators.js +3 -3
  117. package/dist/react/useUndoScope.d.ts +5 -5
  118. package/dist/react/useUndoScope.js +1 -1
  119. package/dist/schema/coordination.d.ts +69 -10
  120. package/dist/schema/coordination.js +86 -9
  121. package/dist/schema/ddl.js +2 -2
  122. package/dist/schema/diff.d.ts +1 -1
  123. package/dist/schema/generate.js +1 -1
  124. package/dist/schema/index.d.ts +10 -10
  125. package/dist/schema/index.js +18 -18
  126. package/dist/schema/queries.d.ts +27 -27
  127. package/dist/schema/queries.js +23 -23
  128. package/dist/schema/select.d.ts +3 -3
  129. package/dist/schema/select.js +3 -3
  130. package/dist/schema/serialize.d.ts +15 -6
  131. package/dist/schema/serialize.js +17 -3
  132. package/dist/schema/sugar.d.ts +6 -7
  133. package/dist/schema/sugar.js +9 -12
  134. package/dist/schema/syncDeltaRow.d.ts +4 -152
  135. package/dist/schema/syncDeltaRow.js +4 -105
  136. package/dist/server/adapter.d.ts +18 -1
  137. package/dist/server/commit.d.ts +10 -16
  138. package/dist/server/index.d.ts +1 -1
  139. package/dist/server/index.js +1 -1
  140. package/dist/server/readConfig.d.ts +1 -1
  141. package/dist/source/adapters/drizzle.d.ts +1 -1
  142. package/dist/source/adapters/drizzle.js +2 -2
  143. package/dist/source/adapters/kysely.d.ts +1 -1
  144. package/dist/source/adapters/kysely.js +1 -1
  145. package/dist/source/adapters/kyselyMutationCore.d.ts +1 -1
  146. package/dist/source/adapters/kyselyMutationCore.js +2 -2
  147. package/dist/source/adapters/memory.js +1 -1
  148. package/dist/source/adapters/prisma.d.ts +8 -3
  149. package/dist/source/adapters/prisma.js +1 -1
  150. package/dist/source/connector.js +1 -1
  151. package/dist/source/connectorProtocol.d.ts +2 -8
  152. package/dist/source/connectorProtocol.js +3 -2
  153. package/dist/source/contract.d.ts +29 -17
  154. package/dist/source/contract.js +27 -22
  155. package/dist/source/factory.d.ts +1 -1
  156. package/dist/source/footprint.d.ts +111 -0
  157. package/dist/source/footprint.js +0 -0
  158. package/dist/source/idempotency.js +2 -2
  159. package/dist/source/index.d.ts +1 -0
  160. package/dist/source/index.js +3 -0
  161. package/dist/source/next.d.ts +1 -1
  162. package/dist/source/signing.d.ts +9 -2
  163. package/dist/source/signing.js +4 -1
  164. package/dist/source/types.d.ts +6 -4
  165. package/dist/source/types.js +1 -1
  166. package/dist/stores/ObjectStore.d.ts +1 -1
  167. package/dist/stores/SyncActionStore.d.ts +1 -1
  168. package/dist/stores/SyncActionStore.js +2 -10
  169. package/dist/stores/syncAction.d.ts +26 -0
  170. package/dist/stores/syncAction.js +16 -0
  171. package/dist/surface.d.ts +3 -3
  172. package/dist/surface.js +6 -4
  173. package/dist/sync/BootstrapFetcher.d.ts +123 -6
  174. package/dist/sync/BootstrapFetcher.js +492 -66
  175. package/dist/sync/ConnectionManager.d.ts +6 -198
  176. package/dist/sync/ConnectionManager.js +6 -677
  177. package/dist/sync/OnDemandLoader.d.ts +2 -2
  178. package/dist/sync/OnDemandLoader.js +60 -21
  179. package/dist/sync/SubscriptionManager.d.ts +13 -2
  180. package/dist/sync/SubscriptionManager.js +23 -5
  181. package/dist/sync/SyncWebSocket.d.ts +27 -510
  182. package/dist/sync/SyncWebSocket.js +76 -954
  183. package/dist/sync/awaitClaimGrant.d.ts +4 -44
  184. package/dist/sync/awaitClaimGrant.js +4 -109
  185. package/dist/sync/commitFrames.d.ts +6 -40
  186. package/dist/sync/commitFrames.js +6 -97
  187. package/dist/sync/contextPorts.d.ts +18 -0
  188. package/dist/sync/contextPorts.js +31 -0
  189. package/dist/sync/createClaimStream.d.ts +5 -49
  190. package/dist/sync/createClaimStream.js +5 -469
  191. package/dist/sync/createPresenceStream.d.ts +26 -4
  192. package/dist/sync/createPresenceStream.js +28 -20
  193. package/dist/sync/createSnapshot.d.ts +2 -2
  194. package/dist/sync/createSnapshot.js +1 -1
  195. package/dist/sync/credentialLifecycle.d.ts +5 -173
  196. package/dist/sync/credentialLifecycle.js +5 -320
  197. package/dist/sync/deltaPipeline.d.ts +1 -1
  198. package/dist/sync/participants.d.ts +5 -4
  199. package/dist/sync/participants.js +29 -22
  200. package/dist/sync/schemaDrift.d.ts +55 -0
  201. package/dist/sync/schemaDrift.js +53 -0
  202. package/dist/sync/schemas.d.ts +21 -32
  203. package/dist/sync/schemas.js +26 -17
  204. package/dist/sync/syncPlan.d.ts +3 -3
  205. package/dist/sync/wsFrameHandlers.d.ts +6 -114
  206. package/dist/sync/wsFrameHandlers.js +6 -392
  207. package/dist/testing/fixtures/bootstrap.d.ts +1 -1
  208. package/dist/testing/fixtures/deltas.d.ts +1 -1
  209. package/dist/testing/fixtures/httpResponses.d.ts +70 -0
  210. package/dist/testing/fixtures/httpResponses.js +90 -0
  211. package/dist/testing/fixtures/models.js +1 -1
  212. package/dist/testing/helpers/wait.js +1 -1
  213. package/dist/testing/mocks/MockMutationExecutor.d.ts +2 -2
  214. package/dist/testing/mocks/MockMutationExecutor.js +8 -14
  215. package/dist/testing/mocks/MockSyncContext.d.ts +11 -11
  216. package/dist/testing/mocks/MockSyncContext.js +10 -9
  217. package/dist/testing/mocks/MockSyncStore.js +1 -1
  218. package/dist/testing/mocks/MockWebSocket.d.ts +2 -2
  219. package/dist/transaction/ablo.d.ts +88 -0
  220. package/dist/transaction/ablo.js +33 -0
  221. package/dist/{client/auth.d.ts → transaction/auth/apiKey.d.ts} +43 -8
  222. package/dist/{client/auth.js → transaction/auth/apiKey.js} +19 -0
  223. package/dist/transaction/auth/bootstrapScope.d.ts +15 -0
  224. package/dist/transaction/auth/bootstrapScope.js +1 -0
  225. package/dist/transaction/auth/capability.d.ts +177 -0
  226. package/dist/transaction/auth/capability.js +199 -0
  227. package/dist/{auth → transaction/auth}/credentialSource.d.ts +8 -1
  228. package/dist/{client → transaction/auth}/identity.d.ts +8 -7
  229. package/dist/{client → transaction/auth}/identity.js +1 -1
  230. package/dist/transaction/auth/index.d.ts +162 -0
  231. package/dist/transaction/auth/index.js +304 -0
  232. package/dist/{auth → transaction/auth}/schemas.d.ts +1 -1
  233. package/dist/{auth → transaction/auth}/schemas.js +13 -13
  234. package/dist/{client → transaction/auth}/sessionMint.d.ts +8 -8
  235. package/dist/{client → transaction/auth}/sessionMint.js +4 -7
  236. package/dist/transaction/coordination/awaitClaimGrant.d.ts +49 -0
  237. package/dist/transaction/coordination/awaitClaimGrant.js +112 -0
  238. package/dist/transaction/coordination/claimMeta.d.ts +49 -0
  239. package/dist/transaction/coordination/claimMeta.js +52 -0
  240. package/dist/transaction/coordination/createClaimStream.d.ts +64 -0
  241. package/dist/transaction/coordination/createClaimStream.js +475 -0
  242. package/dist/transaction/coordination/events.d.ts +74 -0
  243. package/dist/transaction/coordination/events.js +7 -0
  244. package/dist/transaction/coordination/index.d.ts +19 -0
  245. package/dist/transaction/coordination/index.js +44 -0
  246. package/dist/transaction/coordination/locator.d.ts +83 -0
  247. package/dist/transaction/coordination/locator.js +82 -0
  248. package/dist/transaction/coordination/schema.d.ts +1473 -0
  249. package/dist/{coordination → transaction/coordination}/schema.js +490 -55
  250. package/dist/transaction/coordination/targetConflict.d.ts +2 -0
  251. package/dist/transaction/coordination/targetConflict.js +103 -0
  252. package/dist/{coordination → transaction/coordination}/trace.d.ts +7 -18
  253. package/dist/{coordination → transaction/coordination}/trace.js +18 -25
  254. package/dist/transaction/durableWrites.d.ts +62 -0
  255. package/dist/{client → transaction}/durableWrites.js +28 -3
  256. package/dist/transaction/environment.d.ts +105 -0
  257. package/dist/transaction/environment.js +108 -0
  258. package/dist/{errorCodes.d.ts → transaction/errorCodes.d.ts} +11 -11
  259. package/dist/{errorCodes.js → transaction/errorCodes.js} +35 -12
  260. package/dist/{errors.d.ts → transaction/errors.d.ts} +37 -13
  261. package/dist/{errors.js → transaction/errors.js} +85 -16
  262. package/dist/transaction/index.d.ts +20 -0
  263. package/dist/transaction/index.js +20 -0
  264. package/dist/transaction/keys/index.d.ts +87 -0
  265. package/dist/transaction/keys/index.js +207 -0
  266. package/dist/transaction/log/syncDeltaRow.d.ts +158 -0
  267. package/dist/transaction/log/syncDeltaRow.js +95 -0
  268. package/dist/{sync/syncPosition.d.ts → transaction/logPosition.d.ts} +22 -8
  269. package/dist/{sync/syncPosition.js → transaction/logPosition.js} +15 -6
  270. package/dist/transaction/logger.d.ts +16 -0
  271. package/dist/transaction/logger.js +7 -0
  272. package/dist/transaction/observability.d.ts +53 -0
  273. package/dist/transaction/observability.js +19 -0
  274. package/dist/transaction/plugin.d.ts +192 -0
  275. package/dist/transaction/plugin.js +87 -0
  276. package/dist/{policy → transaction/policy}/types.d.ts +3 -3
  277. package/dist/{policy → transaction/policy}/types.js +2 -0
  278. package/dist/transaction/resources/httpResources.d.ts +266 -0
  279. package/dist/transaction/resources/httpResources.js +7 -0
  280. package/dist/transaction/resources/modelOperations.d.ts +319 -0
  281. package/dist/transaction/resources/modelOperations.js +12 -0
  282. package/dist/transaction/resources/mutationOptions.d.ts +66 -0
  283. package/dist/transaction/resources/mutationOptions.js +9 -0
  284. package/dist/transaction/resources/where.d.ts +85 -0
  285. package/dist/transaction/resources/where.js +70 -0
  286. package/dist/{client → transaction/resources}/writeOptionsSchema.d.ts +2 -6
  287. package/dist/{client → transaction/resources}/writeOptionsSchema.js +9 -5
  288. package/dist/{schema → transaction/schema}/field.d.ts +5 -5
  289. package/dist/{schema → transaction/schema}/field.js +5 -5
  290. package/dist/transaction/schema/loadStrategy.d.ts +45 -0
  291. package/dist/transaction/schema/loadStrategy.js +46 -0
  292. package/dist/{schema → transaction/schema}/model.d.ts +50 -35
  293. package/dist/{schema → transaction/schema}/model.js +30 -20
  294. package/dist/transaction/schema/openapi.d.ts +57 -0
  295. package/dist/transaction/schema/openapi.js +340 -0
  296. package/dist/{schema → transaction/schema}/relation.d.ts +14 -14
  297. package/dist/{schema → transaction/schema}/relation.js +7 -7
  298. package/dist/{schema → transaction/schema}/residency.d.ts +0 -9
  299. package/dist/{schema → transaction/schema}/residency.js +0 -5
  300. package/dist/{schema → transaction/schema}/roles.d.ts +5 -5
  301. package/dist/{schema → transaction/schema}/roles.js +5 -5
  302. package/dist/{schema → transaction/schema}/schema.d.ts +12 -10
  303. package/dist/{schema → transaction/schema}/schema.js +4 -3
  304. package/dist/{schema → transaction/schema}/tenancy.d.ts +1 -1
  305. package/dist/{schema → transaction/schema}/tenancy.js +7 -4
  306. package/dist/transaction/transactionLayer.d.ts +82 -0
  307. package/dist/transaction/transactionLayer.js +24 -0
  308. package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.d.ts +4 -5
  309. package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.js +9 -13
  310. package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.d.ts +9 -2
  311. package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.js +5 -9
  312. package/dist/{transactions/durableWriteStore.d.ts → transaction/transactions/settlement/pendingWrite.d.ts} +10 -36
  313. package/dist/transaction/transactions/settlement/pendingWrite.js +20 -0
  314. package/dist/transaction/transport/commitFrames.d.ts +90 -0
  315. package/dist/transaction/transport/commitFrames.js +134 -0
  316. package/dist/transaction/transport/connectionManager.d.ts +215 -0
  317. package/dist/transaction/transport/connectionManager.js +673 -0
  318. package/dist/transaction/transport/credentialLifecycle.d.ts +177 -0
  319. package/dist/transaction/transport/credentialLifecycle.js +324 -0
  320. package/dist/{sync → transaction/transport}/heartbeat.d.ts +3 -1
  321. package/dist/{sync → transaction/transport}/heartbeat.js +6 -4
  322. package/dist/{client → transaction/transport}/httpClient.d.ts +59 -16
  323. package/dist/{client → transaction/transport}/httpClient.js +5 -5
  324. package/dist/transaction/transport/httpOptions.d.ts +33 -0
  325. package/dist/transaction/transport/httpOptions.js +12 -0
  326. package/dist/{client → transaction/transport}/httpTransport.js +171 -85
  327. package/dist/{sync/NetworkProbe.d.ts → transaction/transport/networkProbe.d.ts} +7 -4
  328. package/dist/{sync/NetworkProbe.js → transaction/transport/networkProbe.js} +14 -13
  329. package/dist/transaction/transport/wsFrameHandlers.d.ts +128 -0
  330. package/dist/transaction/transport/wsFrameHandlers.js +429 -0
  331. package/dist/transaction/transport/wsTransport.d.ts +576 -0
  332. package/dist/transaction/transport/wsTransport.js +1017 -0
  333. package/dist/transaction/types/assertExact.d.ts +17 -0
  334. package/dist/transaction/types/assertExact.js +1 -0
  335. package/dist/{types → transaction/types}/global.d.ts +17 -2
  336. package/dist/{types → transaction/types}/global.js +2 -1
  337. package/dist/{types → transaction/types}/index.d.ts +14 -46
  338. package/dist/{types → transaction/types}/index.js +7 -16
  339. package/dist/{types → transaction/types}/streams.d.ts +63 -45
  340. package/dist/{utils → transaction/utils}/json.d.ts +18 -0
  341. package/dist/transaction/utils/json.js +276 -0
  342. package/dist/transaction/wire/accountResponses.d.ts +351 -0
  343. package/dist/transaction/wire/accountResponses.js +255 -0
  344. package/dist/transaction/wire/auth.d.ts +49 -0
  345. package/dist/transaction/wire/auth.js +57 -0
  346. package/dist/transaction/wire/claimEvent.d.ts +76 -0
  347. package/dist/transaction/wire/claimEvent.js +73 -0
  348. package/dist/transaction/wire/claims.d.ts +463 -0
  349. package/dist/transaction/wire/claims.js +229 -0
  350. package/dist/{wire → transaction/wire}/commit.d.ts +125 -193
  351. package/dist/{wire → transaction/wire}/commit.js +68 -47
  352. package/dist/{wire → transaction/wire}/delta.d.ts +66 -17
  353. package/dist/{wire → transaction/wire}/delta.js +37 -13
  354. package/dist/transaction/wire/errorEnvelope.d.ts +72 -0
  355. package/dist/{wire → transaction/wire}/errorEnvelope.js +36 -5
  356. package/dist/transaction/wire/feedCursor.d.ts +60 -0
  357. package/dist/transaction/wire/feedCursor.js +82 -0
  358. package/dist/transaction/wire/feedEvent.d.ts +177 -0
  359. package/dist/transaction/wire/feedEvent.js +39 -0
  360. package/dist/transaction/wire/frames.d.ts +194 -0
  361. package/dist/transaction/wire/frames.js +50 -0
  362. package/dist/transaction/wire/inboundFrames.d.ts +552 -0
  363. package/dist/transaction/wire/inboundFrames.js +116 -0
  364. package/dist/transaction/wire/index.d.ts +50 -0
  365. package/dist/transaction/wire/index.js +74 -0
  366. package/dist/{wire → transaction/wire}/listEnvelope.d.ts +13 -14
  367. package/dist/transaction/wire/listEnvelope.js +42 -0
  368. package/dist/transaction/wire/modelResponses.d.ts +85 -0
  369. package/dist/transaction/wire/modelResponses.js +43 -0
  370. package/dist/transactions/{TransactionQueue.d.ts → mutations/MutationQueue.d.ts} +79 -38
  371. package/dist/transactions/{TransactionQueue.js → mutations/MutationQueue.js} +110 -59
  372. package/dist/transactions/{TransactionStore.d.ts → mutations/MutationStore.d.ts} +8 -8
  373. package/dist/transactions/{TransactionStore.js → mutations/MutationStore.js} +2 -2
  374. package/dist/transactions/{coalesceRules.d.ts → mutations/coalesceRules.d.ts} +10 -10
  375. package/dist/transactions/{coalesceRules.js → mutations/coalesceRules.js} +1 -1
  376. package/dist/transactions/mutations/commitLatency.d.ts +52 -0
  377. package/dist/transactions/mutations/commitLatency.js +130 -0
  378. package/dist/transactions/{commitOutboxStore.d.ts → mutations/commitOutboxStore.d.ts} +1 -5
  379. package/dist/transactions/{commitOutboxStore.js → mutations/commitOutboxStore.js} +1 -1
  380. package/dist/transactions/{commitPayload.d.ts → mutations/commitPayload.d.ts} +16 -15
  381. package/dist/transactions/{commitPayload.js → mutations/commitPayload.js} +12 -12
  382. package/dist/transactions/{deltaConfirmation.d.ts → mutations/deltaConfirmation.d.ts} +11 -11
  383. package/dist/transactions/{deltaConfirmation.js → mutations/deltaConfirmation.js} +7 -7
  384. package/dist/transactions/mutations/durableWriteStore.d.ts +14 -0
  385. package/dist/transactions/mutations/durableWriteStore.js +12 -0
  386. package/dist/transactions/{optimisticApply.d.ts → mutations/optimisticApply.d.ts} +7 -7
  387. package/dist/transactions/{replayValidation.d.ts → mutations/replayValidation.d.ts} +3 -3
  388. package/dist/transactions/{replayValidation.js → mutations/replayValidation.js} +4 -3
  389. package/dist/utils/mobxSetup.d.ts +1 -1
  390. package/dist/utils/mobxSetup.js +5 -2
  391. package/dist/webhooks/events.d.ts +2 -2
  392. package/dist/wire/index.d.ts +1 -34
  393. package/dist/wire/index.js +8 -49
  394. package/docs/agent-messaging.md +3 -3
  395. package/docs/agents.md +19 -12
  396. package/docs/api-keys.md +8 -4
  397. package/docs/api.md +22 -18
  398. package/docs/audit.md +2 -0
  399. package/docs/cli.md +31 -3
  400. package/docs/client-behavior.md +8 -6
  401. package/docs/concurrency-convention.md +30 -24
  402. package/docs/coordination.md +48 -38
  403. package/docs/data-sources.md +3 -1
  404. package/docs/debugging.md +5 -3
  405. package/docs/deployment.md +267 -0
  406. package/docs/examples/agent-human.md +49 -42
  407. package/docs/examples/ai-sdk-tool.md +69 -44
  408. package/docs/examples/existing-python-backend.md +8 -6
  409. package/docs/examples/nextjs.md +129 -47
  410. package/docs/examples/scoped-agent.md +45 -44
  411. package/docs/examples/server-agent.md +46 -26
  412. package/docs/groups.md +32 -29
  413. package/docs/guarantees.md +4 -2
  414. package/docs/how-it-works.md +9 -7
  415. package/docs/idempotency.md +126 -0
  416. package/docs/identity.md +58 -54
  417. package/docs/index.md +172 -84
  418. package/docs/integration-guide.md +17 -16
  419. package/docs/interaction-model.md +6 -4
  420. package/docs/mcp.md +41 -16
  421. package/docs/migration.md +63 -5
  422. package/docs/operating-on-your-database.md +111 -0
  423. package/docs/projects.md +2 -0
  424. package/docs/quickstart.md +22 -5
  425. package/docs/react.md +12 -10
  426. package/docs/schema-contract.md +5 -3
  427. package/docs/session-settings.md +108 -0
  428. package/docs/sessions.md +3 -1
  429. package/docs/webhooks.md +3 -1
  430. package/llms.txt +47 -17
  431. package/package.json +10 -8
  432. package/dist/agent/Agent.d.ts +0 -366
  433. package/dist/agent/Agent.js +0 -514
  434. package/dist/agent/index.d.ts +0 -115
  435. package/dist/agent/index.js +0 -128
  436. package/dist/agent/session.d.ts +0 -93
  437. package/dist/agent/session.js +0 -149
  438. package/dist/agent/types.d.ts +0 -68
  439. package/dist/agent/types.js +0 -9
  440. package/dist/client/durableWrites.d.ts +0 -21
  441. package/dist/coordination/schema.d.ts +0 -722
  442. package/dist/schema/openapi.d.ts +0 -29
  443. package/dist/schema/openapi.js +0 -124
  444. package/dist/transactions/durableWriteStore.js +0 -30
  445. package/dist/utils/json.js +0 -88
  446. package/dist/wire/errorEnvelope.d.ts +0 -55
  447. package/dist/wire/frames.d.ts +0 -197
  448. package/dist/wire/frames.js +0 -49
  449. package/dist/wire/listEnvelope.js +0 -18
  450. /package/dist/{client → transaction/auth}/credentialEndpoint.d.ts +0 -0
  451. /package/dist/{client → transaction/auth}/credentialEndpoint.js +0 -0
  452. /package/dist/{auth → transaction/auth}/credentialPolicy.d.ts +0 -0
  453. /package/dist/{auth → transaction/auth}/credentialPolicy.js +0 -0
  454. /package/dist/{auth → transaction/auth}/credentialSource.js +0 -0
  455. /package/dist/{client → transaction/auth}/hostedEndpoints.d.ts +0 -0
  456. /package/dist/{client → transaction/auth}/hostedEndpoints.js +0 -0
  457. /package/dist/{client → transaction/coordination}/claimHeartbeatLoop.d.ts +0 -0
  458. /package/dist/{client → transaction/coordination}/claimHeartbeatLoop.js +0 -0
  459. /package/dist/{client → transaction}/persistence.d.ts +0 -0
  460. /package/dist/{client → transaction}/persistence.js +0 -0
  461. /package/dist/{client → transaction/resources}/functionalUpdate.d.ts +0 -0
  462. /package/dist/{client → transaction/resources}/functionalUpdate.js +0 -0
  463. /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.d.ts +0 -0
  464. /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.js +0 -0
  465. /package/dist/{client → transaction/transport}/httpTransport.d.ts +0 -0
  466. /package/dist/{types → transaction/types}/modelData.d.ts +0 -0
  467. /package/dist/{types → transaction/types}/modelData.js +0 -0
  468. /package/dist/{types → transaction/types}/participant.d.ts +0 -0
  469. /package/dist/{types → transaction/types}/participant.js +0 -0
  470. /package/dist/{types → transaction/types}/streams.js +0 -0
  471. /package/dist/{utils → transaction/utils}/asyncIterator.d.ts +0 -0
  472. /package/dist/{utils → transaction/utils}/asyncIterator.js +0 -0
  473. /package/dist/{utils → transaction/utils}/duration.d.ts +0 -0
  474. /package/dist/{utils → transaction/utils}/duration.js +0 -0
  475. /package/dist/{wire → transaction/wire}/bootstrapReason.d.ts +0 -0
  476. /package/dist/{wire → transaction/wire}/bootstrapReason.js +0 -0
  477. /package/dist/{wire → transaction/wire}/protocol.d.ts +0 -0
  478. /package/dist/{wire → transaction/wire}/protocol.js +0 -0
  479. /package/dist/{wire → transaction/wire}/protocolVersion.d.ts +0 -0
  480. /package/dist/{wire → transaction/wire}/protocolVersion.js +0 -0
  481. /package/dist/transactions/{UnconfirmedWrites.d.ts → mutations/UnconfirmedWrites.d.ts} +0 -0
  482. /package/dist/transactions/{UnconfirmedWrites.js → mutations/UnconfirmedWrites.js} +0 -0
  483. /package/dist/transactions/{optimisticApply.js → mutations/optimisticApply.js} +0 -0
@@ -1,175 +1,7 @@
1
1
  /**
2
- * Keeps the short-lived access credential fresh. It owns the re-mint hook, a
3
- * single-flight guard that stops concurrent triggers from minting more than
4
- * once, and a browser-only proactive refresh a timer plus an OS-wake listener
5
- * that renews the credential ahead of expiry. It reaches the rest of the
6
- * client only through the small {@link CredentialLifecycleContext} interface,
7
- * so the two can reference each other without an import cycle.
2
+ * Moved to the settlement core with the duplex transport (ADR 0016): keeping
3
+ * a long-lived socket's credential fresh is connection plumbing an agent needs
4
+ * as much as a browser does. This path re-exports it so existing importers
5
+ * stay unchanged.
8
6
  */
9
- import type { RecoveryClass } from '../errorCodes.js';
10
- /**
11
- * Tri-state outcome of a credential re-mint, mirroring the `getToken`
12
- * contract (see {@link CredentialLifecycle.refresh}).
13
- */
14
- export type CredentialRefreshOutcome = 'refreshed' | 'session_error' | 'network_error';
15
- /**
16
- * What an auth-rejected transport should do after recovery has run. `'retry'`
17
- * means a fresh credential is now in place — replay the request once. `'stop'`
18
- * means don't replay: either the session is gone for good, the rejection is one
19
- * a re-mint can't cure, or the mint failed transiently and the caller's own
20
- * retry path will recover later.
21
- */
22
- export type CredentialRecoveryOutcome = 'retry' | 'stop';
23
- /**
24
- * What a credential refresher may resolve with. The plain-string form returns
25
- * just the token. The object form also carries the mint response's `expiresAt`
26
- * (an ISO string, epoch milliseconds, or a `Date`), which lets the proactive
27
- * pre-roll schedule against the credential's real lifetime rather than assume
28
- * the server's default expiry.
29
- */
30
- export type CredentialRefreshResult = string | {
31
- readonly token: string;
32
- readonly expiresAt?: string | number | Date;
33
- } | null;
34
- /** A credential re-mint hook. `Promise<string | null>` resolvers remain
35
- * assignable — the widened result type is a superset. */
36
- export type CredentialRefresher = () => Promise<CredentialRefreshResult>;
37
- /** The fallback pre-roll interval, and also its ceiling: 10 minutes, which sits
38
- * comfortably inside the server's 15-minute default credential lifetime. Used
39
- * as-is when the refresher reports no expiry. */
40
- export declare const DEFAULT_PREROLL_INTERVAL_MS: number;
41
- /** Floor so a very short (or already-elapsed) TTL can't hot-loop the mint. */
42
- export declare const MIN_PREROLL_DELAY_MS: number;
43
- /**
44
- * Computes how long to wait before pre-rolling a credential that expires at
45
- * `expiresAtMs`: about two-thirds of the remaining lifetime (a 15-minute
46
- * credential yields 10 minutes), clamped to
47
- * [{@link MIN_PREROLL_DELAY_MS}, {@link DEFAULT_PREROLL_INTERVAL_MS}]. An
48
- * unknown expiry (`null`) falls back to the 10-minute interval. Exported for
49
- * unit tests.
50
- */
51
- export declare function computePrerollDelayMs(expiresAtMs: number | null, nowMs: number): number;
52
- /**
53
- * The callbacks this lifecycle needs back from the surrounding client. It is
54
- * deliberately minimal — three callbacks, each resolved lazily at call time,
55
- * because the connection machinery behind two of them isn't constructed until
56
- * the sync connection is set up.
57
- */
58
- export interface CredentialLifecycleContext {
59
- /** Push a freshly-minted access token into the shared credential source
60
- * (no-op when the deployment wired no credential source). */
61
- setAuthToken(token: string): void;
62
- /** Nudge the connection to re-probe using the credential now in place. */
63
- nudgeReconnect(): void;
64
- /** Report that the long-lived login is gone, so the connection can move to
65
- * its signed-out state. */
66
- reportSessionExpired(): void;
67
- }
68
- export declare class CredentialLifecycle {
69
- private readonly ctx;
70
- /**
71
- * The hook that mints a fresh short-lived access credential (the `ek_`/`rk_`
72
- * key). An integrator wires it from their own token endpoint: this lifecycle
73
- * decides when to refresh (a stale-credential probe or an external nudge),
74
- * and the hook decides how to mint. It follows the same contract as a
75
- * `getToken` function — it resolves a token string on success, `null` when
76
- * the long-lived login is gone (a terminal state), and throws on a transient
77
- * or offline failure. Used by {@link refresh}. When it is absent there is no
78
- * silent re-mint, as with a static `apiKey` whose credential source is
79
- * refreshed elsewhere.
80
- */
81
- private credentialRefresher;
82
- /** Single-flight guard so a wake nudge + an in-flight request + a probe don't
83
- * all mint at once (the classic "token thrash → random logout" bug). */
84
- private inFlightCredentialRefresh;
85
- /** Tears down the proactive credential lifecycle (the refresh timer and the
86
- * OS-wake listener) installed by {@link start}; cleared when the client
87
- * disconnects. Null when no refresher is wired. */
88
- private credentialLifecycleTeardown;
89
- /** Epoch milliseconds at which the current credential expires, when the
90
- * refresher reports it (the object form of {@link CredentialRefreshResult}).
91
- * `null` for the string-form resolver, in which case the pre-roll uses its
92
- * fixed interval. */
93
- private credentialExpiresAtMs;
94
- /** Re-arms the proactive pre-roll timer (set by {@link start}). Called after
95
- * every successful mint, so a refresh triggered reactively (by a probe, an
96
- * OS wake, or the first mint) re-anchors the schedule to the fresh
97
- * credential's real expiry instead of a stale fixed delay. */
98
- private prerollReschedule;
99
- constructor(ctx: CredentialLifecycleContext);
100
- /**
101
- * Registers the re-mint hook for the access credential — a function that
102
- * mints a fresh `ek_`/`rk_` key, typically the integrator's `getToken`. See
103
- * {@link credentialRefresher}.
104
- */
105
- setRefresher(refresher: CredentialRefresher | null): void;
106
- /**
107
- * Re-mints the short-lived access credential, pushes it into the credential
108
- * source, and reports a three-way outcome the connection layer acts on:
109
- * - a token string → `'refreshed'` (the fresh key is in place; re-probe and reconnect)
110
- * - `null` → `'session_error'` (the login itself is gone — terminal, sign out)
111
- * - a thrown error → `'network_error'` (the mint endpoint was unreachable — transient)
112
- *
113
- * The call is single-flight: concurrent triggers (an OS wake, an in-flight
114
- * request, a probe) share one in-flight promise, so the credential is never
115
- * minted twice at once. This avoids the failure where every rejected request
116
- * mints a new token and the resulting thrash logs the user out.
117
- *
118
- * With no refresher wired, it resolves `'refreshed'` as a no-op re-probe: a
119
- * static-`apiKey` client has no session to mint from and its credential
120
- * source is refreshed elsewhere, so it simply re-probes with what it holds.
121
- */
122
- refresh(): Promise<CredentialRefreshOutcome>;
123
- /**
124
- * Interprets a refresh outcome and drives the connection accordingly. This is
125
- * the single place the three-way outcome is acted on, shared by the proactive
126
- * pre-roll, the OS-wake nudge, and the HTTP auth-recovery path, so every
127
- * trigger converges on the same behavior.
128
- */
129
- private routeRefreshOutcome;
130
- /**
131
- * The shared recovery path for a request rejected on authentication, over any
132
- * transport. The WebSocket probe already routes its own 401s; HTTP callers
133
- * call this instead of inventing their own handling, so every path shares one
134
- * single-flight mint, one outcome routing, and one taxonomy. It classifies
135
- * the same recovery codes the connection probe does:
136
- * - `access_credential_expiry` — the routine case, an expired `ek_`/`rk_`:
137
- * silently re-mint through the single-flight {@link refresh} and tell the
138
- * caller to replay once on success. This never signs out on its own; the
139
- * only terminal path is the mint resolving `null`.
140
- * - `session_expiry` — the login is gone: report it (which drives sign-out)
141
- * and stop, since replaying is pointless.
142
- * - `auth_blocked`, `permission`, and everything else — re-minting would
143
- * produce the same rejected credential, so stop and leave the connection
144
- * alone.
145
- */
146
- recoverFromAuthRejection(recovery: RecoveryClass): Promise<CredentialRecoveryOutcome>;
147
- /**
148
- * Installs the credential lifecycle. It has two parts:
149
- * 1. Reactive — registers `getToken` as the re-mint hook the connection
150
- * calls when a probe finds the key stale, or on a nudge.
151
- * 2. Proactive — keeps the short-lived key fresh ahead of expiry with a
152
- * refresh timer inside the credential's lifetime, plus a re-mint on OS
153
- * wake. The whole proactive block is browser-gated on `typeof window`,
154
- * because a server render has no socket to keep warm and the resolver is
155
- * browser-oriented; arming it under Node would fire a relative-URL fetch
156
- * and throw. (Agents pass a static `apiKey` with no resolver, so this
157
- * method is never called for them.)
158
- *
159
- * Refreshing is automatic — a consumer never calls a refresh method. The call
160
- * is idempotent: a second call replaces the first, and it is torn down when
161
- * the client disconnects.
162
- *
163
- * `opts.proactiveInNode` arms the refresh timer on a windowless host as well.
164
- * Set it for agent or system participants — long-lived server sockets whose
165
- * `rk_`/`ek_` must renew before the server's keepalive check closes them.
166
- * Node timers are `unref`ed, so a finishing script is never held alive by the
167
- * pre-roll. The OS-wake listener stays browser-only regardless, since there
168
- * is no `window` to listen on.
169
- */
170
- start(getToken: CredentialRefresher, opts?: {
171
- proactiveInNode?: boolean;
172
- }): void;
173
- /** Tear down the proactive credential lifecycle (idempotent). */
174
- stop(): void;
175
- }
7
+ export { DEFAULT_PREROLL_INTERVAL_MS, MIN_PREROLL_DELAY_MS, computePrerollDelayMs, CredentialLifecycle, type CredentialRefreshOutcome, type CredentialRecoveryOutcome, type CredentialRefreshResult, type CredentialRefresher, type CredentialLifecycleContext, } from '../transaction/transport/credentialLifecycle.js';
@@ -1,322 +1,7 @@
1
1
  /**
2
- * Keeps the short-lived access credential fresh. It owns the re-mint hook, a
3
- * single-flight guard that stops concurrent triggers from minting more than
4
- * once, and a browser-only proactive refresh a timer plus an OS-wake listener
5
- * that renews the credential ahead of expiry. It reaches the rest of the
6
- * client only through the small {@link CredentialLifecycleContext} interface,
7
- * so the two can reference each other without an import cycle.
2
+ * Moved to the settlement core with the duplex transport (ADR 0016): keeping
3
+ * a long-lived socket's credential fresh is connection plumbing an agent needs
4
+ * as much as a browser does. This path re-exports it so existing importers
5
+ * stay unchanged.
8
6
  */
9
- import { getContext } from '../context.js';
10
- /** The fallback pre-roll interval, and also its ceiling: 10 minutes, which sits
11
- * comfortably inside the server's 15-minute default credential lifetime. Used
12
- * as-is when the refresher reports no expiry. */
13
- export const DEFAULT_PREROLL_INTERVAL_MS = 10 * 60 * 1000;
14
- /** Floor so a very short (or already-elapsed) TTL can't hot-loop the mint. */
15
- export const MIN_PREROLL_DELAY_MS = 30 * 1000;
16
- /**
17
- * Computes how long to wait before pre-rolling a credential that expires at
18
- * `expiresAtMs`: about two-thirds of the remaining lifetime (a 15-minute
19
- * credential yields 10 minutes), clamped to
20
- * [{@link MIN_PREROLL_DELAY_MS}, {@link DEFAULT_PREROLL_INTERVAL_MS}]. An
21
- * unknown expiry (`null`) falls back to the 10-minute interval. Exported for
22
- * unit tests.
23
- */
24
- export function computePrerollDelayMs(expiresAtMs, nowMs) {
25
- if (expiresAtMs === null || !Number.isFinite(expiresAtMs)) {
26
- return DEFAULT_PREROLL_INTERVAL_MS;
27
- }
28
- const remaining = expiresAtMs - nowMs;
29
- if (remaining <= 0)
30
- return MIN_PREROLL_DELAY_MS;
31
- const twoThirds = Math.floor((remaining * 2) / 3);
32
- return Math.min(Math.max(twoThirds, MIN_PREROLL_DELAY_MS), DEFAULT_PREROLL_INTERVAL_MS);
33
- }
34
- /** Narrow a refresher-supplied `expiresAt` to epoch ms, or `null` when
35
- * absent/unparseable (→ fallback cadence, never a crash). */
36
- function normalizeExpiresAtMs(expiresAt) {
37
- if (expiresAt === undefined)
38
- return null;
39
- const ms = expiresAt instanceof Date
40
- ? expiresAt.getTime()
41
- : typeof expiresAt === 'number'
42
- ? expiresAt
43
- : Date.parse(expiresAt);
44
- return Number.isFinite(ms) ? ms : null;
45
- }
46
- export class CredentialLifecycle {
47
- ctx;
48
- /**
49
- * The hook that mints a fresh short-lived access credential (the `ek_`/`rk_`
50
- * key). An integrator wires it from their own token endpoint: this lifecycle
51
- * decides when to refresh (a stale-credential probe or an external nudge),
52
- * and the hook decides how to mint. It follows the same contract as a
53
- * `getToken` function — it resolves a token string on success, `null` when
54
- * the long-lived login is gone (a terminal state), and throws on a transient
55
- * or offline failure. Used by {@link refresh}. When it is absent there is no
56
- * silent re-mint, as with a static `apiKey` whose credential source is
57
- * refreshed elsewhere.
58
- */
59
- credentialRefresher = null;
60
- /** Single-flight guard so a wake nudge + an in-flight request + a probe don't
61
- * all mint at once (the classic "token thrash → random logout" bug). */
62
- inFlightCredentialRefresh = null;
63
- /** Tears down the proactive credential lifecycle (the refresh timer and the
64
- * OS-wake listener) installed by {@link start}; cleared when the client
65
- * disconnects. Null when no refresher is wired. */
66
- credentialLifecycleTeardown = null;
67
- /** Epoch milliseconds at which the current credential expires, when the
68
- * refresher reports it (the object form of {@link CredentialRefreshResult}).
69
- * `null` for the string-form resolver, in which case the pre-roll uses its
70
- * fixed interval. */
71
- credentialExpiresAtMs = null;
72
- /** Re-arms the proactive pre-roll timer (set by {@link start}). Called after
73
- * every successful mint, so a refresh triggered reactively (by a probe, an
74
- * OS wake, or the first mint) re-anchors the schedule to the fresh
75
- * credential's real expiry instead of a stale fixed delay. */
76
- prerollReschedule = null;
77
- constructor(ctx) {
78
- this.ctx = ctx;
79
- }
80
- /**
81
- * Registers the re-mint hook for the access credential — a function that
82
- * mints a fresh `ek_`/`rk_` key, typically the integrator's `getToken`. See
83
- * {@link credentialRefresher}.
84
- */
85
- setRefresher(refresher) {
86
- this.credentialRefresher = refresher;
87
- }
88
- /**
89
- * Re-mints the short-lived access credential, pushes it into the credential
90
- * source, and reports a three-way outcome the connection layer acts on:
91
- * - a token string → `'refreshed'` (the fresh key is in place; re-probe and reconnect)
92
- * - `null` → `'session_error'` (the login itself is gone — terminal, sign out)
93
- * - a thrown error → `'network_error'` (the mint endpoint was unreachable — transient)
94
- *
95
- * The call is single-flight: concurrent triggers (an OS wake, an in-flight
96
- * request, a probe) share one in-flight promise, so the credential is never
97
- * minted twice at once. This avoids the failure where every rejected request
98
- * mints a new token and the resulting thrash logs the user out.
99
- *
100
- * With no refresher wired, it resolves `'refreshed'` as a no-op re-probe: a
101
- * static-`apiKey` client has no session to mint from and its credential
102
- * source is refreshed elsewhere, so it simply re-probes with what it holds.
103
- */
104
- async refresh() {
105
- const refresher = this.credentialRefresher;
106
- if (!refresher)
107
- return 'refreshed';
108
- if (this.inFlightCredentialRefresh)
109
- return this.inFlightCredentialRefresh;
110
- const run = (async () => {
111
- try {
112
- const result = await refresher();
113
- const token = typeof result === 'string' ? result : result?.token;
114
- if (!token) {
115
- // null = the long-lived login is gone (the mint endpoint answered
116
- // 401/403). Terminal — this routes to sign-out.
117
- return 'session_error';
118
- }
119
- // Object-form resolvers carry the mint's actual expiry; remember it so
120
- // the proactive pre-roll schedules off the real TTL (string-form
121
- // resolvers leave it null → fixed fallback cadence).
122
- this.credentialExpiresAtMs =
123
- typeof result === 'object' && result !== null
124
- ? normalizeExpiresAtMs(result.expiresAt)
125
- : null;
126
- this.ctx.setAuthToken(token);
127
- // Re-anchor the proactive pre-roll to the fresh credential's expiry.
128
- this.prerollReschedule?.();
129
- return 'refreshed';
130
- }
131
- catch (error) {
132
- // A throw = transient (offline / mint endpoint unreachable / 5xx). The
133
- // login may be perfectly valid; never sign out for this — back off and
134
- // retry. Mirrors the `getToken` throw-vs-null contract end-to-end.
135
- const message = error?.message ?? String(error);
136
- // A relative-URL resolver invoked on the server (Node's fetch has no
137
- // origin to resolve against) throws the opaque "Failed to parse URL" or
138
- // "Only absolute URLs are supported". Translate it into something
139
- // actionable rather than a mystery transient blip: the proactive
140
- // refresh is browser-only, so reaching here means the resolver fired
141
- // from a server render or a server route.
142
- if (typeof window === 'undefined' && /parse URL|absolute URLs?/i.test(message)) {
143
- getContext().logger.warn('credential resolver ran on the server with a relative URL — Node fetch needs an absolute URL. ' +
144
- 'Refresh the Ablo client in the browser, or build an absolute URL server-side ' +
145
- "(e.g. new URL('/api/ablo-session', process.env.NEXT_PUBLIC_APP_URL)).", { error: message });
146
- }
147
- else {
148
- getContext().logger.debug('access-credential re-mint failed (transient)', { error: message });
149
- }
150
- return 'network_error';
151
- }
152
- })();
153
- this.inFlightCredentialRefresh = run;
154
- try {
155
- return await run;
156
- }
157
- finally {
158
- this.inFlightCredentialRefresh = null;
159
- }
160
- }
161
- /**
162
- * Interprets a refresh outcome and drives the connection accordingly. This is
163
- * the single place the three-way outcome is acted on, shared by the proactive
164
- * pre-roll, the OS-wake nudge, and the HTTP auth-recovery path, so every
165
- * trigger converges on the same behavior.
166
- */
167
- routeRefreshOutcome(outcome) {
168
- if (outcome === 'refreshed') {
169
- // Fresh key already pushed into the credential source by `refresh`;
170
- // nudge a parked connection to re-probe with it.
171
- this.ctx.nudgeReconnect();
172
- return 'retry';
173
- }
174
- if (outcome === 'session_error') {
175
- // The long-lived login is gone (the mint answered 401/403). Report it;
176
- // this is harmless in connection states that don't accept the event,
177
- // which converge on sign-out anyway.
178
- this.ctx.reportSessionExpired();
179
- return 'stop';
180
- }
181
- // 'network_error' → transient (offline or a mint hiccup); the next proactive
182
- // tick or the connection's own probe retries. Never sign out, never replay now.
183
- return 'stop';
184
- }
185
- /**
186
- * The shared recovery path for a request rejected on authentication, over any
187
- * transport. The WebSocket probe already routes its own 401s; HTTP callers
188
- * call this instead of inventing their own handling, so every path shares one
189
- * single-flight mint, one outcome routing, and one taxonomy. It classifies
190
- * the same recovery codes the connection probe does:
191
- * - `access_credential_expiry` — the routine case, an expired `ek_`/`rk_`:
192
- * silently re-mint through the single-flight {@link refresh} and tell the
193
- * caller to replay once on success. This never signs out on its own; the
194
- * only terminal path is the mint resolving `null`.
195
- * - `session_expiry` — the login is gone: report it (which drives sign-out)
196
- * and stop, since replaying is pointless.
197
- * - `auth_blocked`, `permission`, and everything else — re-minting would
198
- * produce the same rejected credential, so stop and leave the connection
199
- * alone.
200
- */
201
- async recoverFromAuthRejection(recovery) {
202
- switch (recovery) {
203
- case 'access_credential_expiry':
204
- return this.routeRefreshOutcome(await this.refresh());
205
- case 'session_expiry':
206
- this.ctx.reportSessionExpired();
207
- return 'stop';
208
- default:
209
- return 'stop';
210
- }
211
- }
212
- /**
213
- * Installs the credential lifecycle. It has two parts:
214
- * 1. Reactive — registers `getToken` as the re-mint hook the connection
215
- * calls when a probe finds the key stale, or on a nudge.
216
- * 2. Proactive — keeps the short-lived key fresh ahead of expiry with a
217
- * refresh timer inside the credential's lifetime, plus a re-mint on OS
218
- * wake. The whole proactive block is browser-gated on `typeof window`,
219
- * because a server render has no socket to keep warm and the resolver is
220
- * browser-oriented; arming it under Node would fire a relative-URL fetch
221
- * and throw. (Agents pass a static `apiKey` with no resolver, so this
222
- * method is never called for them.)
223
- *
224
- * Refreshing is automatic — a consumer never calls a refresh method. The call
225
- * is idempotent: a second call replaces the first, and it is torn down when
226
- * the client disconnects.
227
- *
228
- * `opts.proactiveInNode` arms the refresh timer on a windowless host as well.
229
- * Set it for agent or system participants — long-lived server sockets whose
230
- * `rk_`/`ek_` must renew before the server's keepalive check closes them.
231
- * Node timers are `unref`ed, so a finishing script is never held alive by the
232
- * pre-roll. The OS-wake listener stays browser-only regardless, since there
233
- * is no `window` to listen on.
234
- */
235
- start(getToken, opts) {
236
- this.stop();
237
- this.setRefresher(getToken);
238
- // Re-mint through the same single-flight path the reactive probe uses
239
- // (`refresh`) rather than calling `getToken()` directly. This gives two
240
- // things: the mint stays single-flight, so an OS wake, an in-flight probe,
241
- // and this proactive roll share one in-flight promise instead of thrashing;
242
- // and the three-way outcome is honored, so a `null` result (the login is
243
- // gone) actually drives expiry instead of being dropped, which would leave a
244
- // zombie session that re-mints on every tab focus.
245
- const refresh = async () => {
246
- // Same outcome routing as every other trigger (see routeRefreshOutcome):
247
- // refreshed → nudge, session_error → report, network_error → wait for
248
- // the next tick / the FSM's own probe. Never sign out for a transient.
249
- this.routeRefreshOutcome(await this.refresh());
250
- };
251
- const teardowns = [];
252
- // The proactive pre-roll arms in the browser, or under Node when the host
253
- // opts in (`proactiveInNode`, for agent or system participants). The
254
- // default Node posture stays reactive-only, because a server render can
255
- // construct user-kind clients whose resolver is browser-oriented (a
256
- // relative-URL `fetch('/api/ablo-session')`); arming a timer there fires
257
- // that resolver under Node, where fetch has no origin for a relative URL and
258
- // throws "Failed to parse URL" on every tick. Long-lived server
259
- // participants are the opposite case: their socket must outlive the
260
- // credential's lifetime, so they get the timer. The reactive re-mint hook
261
- // (`setRefresher` above) stays unconditional: it only fires on a real
262
- // connection probe, which can't happen during a bare server-side module
263
- // evaluation.
264
- if (typeof window !== 'undefined' || opts?.proactiveInNode === true) {
265
- // A missed tick (throttled in the background) is recovered by the next
266
- // one, or by the reactive probe. This timer is the only proactive
267
- // pre-roll — it keeps the key warm ahead of expiry even while the socket
268
- // sits healthy and connected, a state the connection never probes. The
269
- // delay comes from the minted credential's real `expiresAt` when the
270
- // refresher reports one (about two-thirds of the remaining lifetime), with
271
- // the 10-minute value as both ceiling and fallback, so a deployment that
272
- // mints shorter-lived keys still pre-rolls in time rather than dropping to
273
- // reactive-only recovery.
274
- let timer = null;
275
- const scheduleNext = () => {
276
- if (timer !== null)
277
- clearTimeout(timer); // idempotent re-arm
278
- const delay = computePrerollDelayMs(this.credentialExpiresAtMs, Date.now());
279
- timer = setTimeout(() => {
280
- // `.finally` keeps the chain alive after a transient failure; a
281
- // successful mint has already re-armed via `prerollReschedule` (the
282
- // clearTimeout above makes the double-arm a no-op).
283
- void refresh().finally(scheduleNext);
284
- }, delay);
285
- // Node: never keep a finishing process alive just for the pre-roll
286
- // (browser timers have no unref — optional call is a no-op there).
287
- timer.unref?.();
288
- };
289
- scheduleNext();
290
- this.prerollReschedule = scheduleNext;
291
- teardowns.push(() => {
292
- if (timer !== null)
293
- clearTimeout(timer);
294
- timer = null;
295
- this.prerollReschedule = null;
296
- });
297
- // OS-wake, on desktop only: the Electron shell bridges `powerMonitor`
298
- // 'resume' to this DOM event. It is the one event trigger this lifecycle
299
- // still owns, because `visibilitychange` does not fire on wake-from-sleep
300
- // and the connection's own browser listeners don't cover wake. It is
301
- // browser-gated separately from the timer, since a `proactiveInNode` host
302
- // has no `window` to listen on and no OS sleep to wake from. Coming back
303
- // online and regaining tab visibility are handled elsewhere — the
304
- // connection already re-probes through this same credential path — so
305
- // listening for them here too would only fire a second, redundant mint.
306
- if (typeof window !== 'undefined') {
307
- const onWake = () => void refresh();
308
- window.addEventListener('ablo:wake', onWake);
309
- teardowns.push(() => { window.removeEventListener('ablo:wake', onWake); });
310
- }
311
- }
312
- this.credentialLifecycleTeardown = () => {
313
- for (const t of teardowns)
314
- t();
315
- };
316
- }
317
- /** Tear down the proactive credential lifecycle (idempotent). */
318
- stop() {
319
- this.credentialLifecycleTeardown?.();
320
- this.credentialLifecycleTeardown = null;
321
- }
322
- }
7
+ export { DEFAULT_PREROLL_INTERVAL_MS, MIN_PREROLL_DELAY_MS, computePrerollDelayMs, CredentialLifecycle, } from '../transaction/transport/credentialLifecycle.js';
@@ -12,7 +12,7 @@
12
12
  */
13
13
  import { ModelScope } from '../InstanceCache.js';
14
14
  import type { Model } from '../Model.js';
15
- import type { ModelData } from '../types/modelData.js';
15
+ import type { ModelData } from '../transaction/types/modelData.js';
16
16
  import type { SyncDelta } from './SyncWebSocket.js';
17
17
  /** One applied-delta result from the persistence layer's batch write, forwarded to the pool. */
18
18
  interface DeltaDbResult {
@@ -1,6 +1,6 @@
1
1
  import type { SyncWebSocket } from './SyncWebSocket.js';
2
- import type { Schema } from '../schema/schema.js';
3
- import type { Claim, Activity, ClaimTarget, ClaimStream, Peer, PresenceStream, PresenceTarget } from '../types/streams.js';
2
+ import type { Schema } from '../transaction/schema/schema.js';
3
+ import type { Claim, Activity, ClaimTarget, ClaimStream, Peer, PresenceStream, PresenceTarget } from '../transaction/types/streams.js';
4
4
  import type { AttachableClaimStream } from './createClaimStream.js';
5
5
  /**
6
6
  * The scope a participant can be joined to. The usual form is an entity target
@@ -64,7 +64,7 @@ export interface ScopedClaimOptions {
64
64
  /** Peer-visible description of the work. Defaults to `'editing'`. */
65
65
  readonly description?: string;
66
66
  /** How long the claim lives; the server expires it automatically after this. */
67
- readonly ttl?: import('../types/streams.js').Duration;
67
+ readonly ttl?: import('../transaction/types/streams.js').Duration;
68
68
  }
69
69
  export interface ScopedClaims {
70
70
  readonly focus: ClaimTarget | null;
@@ -102,7 +102,8 @@ export interface ParticipantManager {
102
102
  }
103
103
  export interface ParticipantManagerConfig {
104
104
  readonly ready: () => Promise<void>;
105
- readonly getTransport: () => SyncWebSocket | null;
105
+ /** The connection, host-built and stable for the client's lifetime. */
106
+ readonly transport: SyncWebSocket;
106
107
  readonly presence: PresenceStream;
107
108
  readonly claims: AttachableClaimStream;
108
109
  readonly schema?: Schema;
@@ -1,5 +1,6 @@
1
- import { scopeKindOf } from '../schema/model.js';
2
- import { AbloConnectionError, AbloValidationError } from '../errors.js';
1
+ import { scopeKindOf } from '../transaction/schema/model.js';
2
+ import { AbloValidationError } from '../transaction/errors.js';
3
+ import { subTarget, streamTarget, wireTarget, } from '../transaction/coordination/index.js';
3
4
  export function createParticipantManager(config) {
4
5
  return {
5
6
  async join(input, overrides) {
@@ -9,10 +10,9 @@ export function createParticipantManager(config) {
9
10
  : null;
10
11
  const syncGroups = unique(resolveParticipantSyncGroups(options.scope ?? target ?? undefined, config.schema));
11
12
  await config.ready();
12
- const transport = config.getTransport();
13
- if (!transport) {
14
- throw new AbloConnectionError('Ablo participant join failed: WebSocket is not connected', { code: 'ws_not_ready' });
15
- }
13
+ // Not-connected joins surface through `sendClaim`'s diagnosed
14
+ // rejection below; a scopeless join needs no wire send at all.
15
+ const transport = config.transport;
16
16
  const claimId = createParticipantClaimId();
17
17
  if (syncGroups.length > 0) {
18
18
  await transport.sendClaim(claimId, syncGroups, {
@@ -74,15 +74,30 @@ export function resolveParticipantSyncGroups(scope, schema) {
74
74
  }
75
75
  return out;
76
76
  }
77
+ /**
78
+ * The group kind for a model, in the wire dialect every plane shares: a
79
+ * declared scope root wins; otherwise the lowercased typename — the same
80
+ * token the commit plane and claim targets use (`wireModel`). Never the
81
+ * camelCase schema key: the server validates inbound subscription groups
82
+ * against a lowercase-only grammar, so a key like `reportBlocks` would be
83
+ * rejected as malformed on subscribe — and even a lowercase key would put
84
+ * this client in a different group than a peer who resolved the same row
85
+ * through an entity ref, so the two would never see each other's claims.
86
+ */
87
+ function groupKindForModel(def, key) {
88
+ return scopeKindOf(def, key) ?? (def.typename ?? key).toLowerCase();
89
+ }
77
90
  export function syncGroupFromEntityRef(ref, schema) {
78
91
  const match = findModelForEntityRef(ref, schema);
79
- const kind = match ? scopeKindOf(match.def, match.key) : undefined;
80
- return `${kind ?? ref.type.toLowerCase()}:${ref.id}`;
92
+ const kind = match
93
+ ? groupKindForModel(match.def, match.key)
94
+ : ref.type.toLowerCase();
95
+ return `${kind}:${ref.id}`;
81
96
  }
82
97
  function syncGroupFromSchemaKey(schemaKey, id, schema) {
83
98
  const def = schema?.models?.[schemaKey];
84
- const kind = def ? scopeKindOf(def, schemaKey) : undefined;
85
- return `${kind ?? schemaKey}:${id}`;
99
+ const kind = def ? groupKindForModel(def, schemaKey) : schemaKey.toLowerCase();
100
+ return `${kind}:${id}`;
86
101
  }
87
102
  function findModelForEntityRef(ref, schema) {
88
103
  if (!schema?.models)
@@ -296,12 +311,8 @@ function createJoinedParticipant(args) {
296
311
  }
297
312
  function activityFromTarget(target) {
298
313
  return {
299
- entityType: target.type,
300
- entityId: target.id,
301
- path: target.path,
302
- range: target.range,
303
- field: target.field,
304
- meta: target.meta,
314
+ ...wireTarget(target),
315
+ ...subTarget(target),
305
316
  };
306
317
  }
307
318
  function presenceMatchesParticipant(entry, target, syncGroups) {
@@ -310,12 +321,8 @@ function presenceMatchesParticipant(entry, target, syncGroups) {
310
321
  if (!target)
311
322
  return true;
312
323
  return targetsOverlap({
313
- type: entry.activity.entityType,
314
- id: entry.activity.entityId,
315
- path: entry.activity.path,
316
- range: entry.activity.range,
317
- field: entry.activity.field,
318
- meta: entry.activity.meta,
324
+ ...streamTarget(entry.activity),
325
+ ...subTarget(entry.activity),
319
326
  }, target);
320
327
  }
321
328
  function targetsOverlap(a, b) {