@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,87 +1,112 @@
1
1
  # AI SDK Tool
2
2
 
3
- When an AI agent updates a shared record from inside a tool call, you have a concurrency problem: another agent or a user might be editing the same row, and a naive write silently overwrites their change. This example shows the safe pattern — read the record, claim the row so anyone else waits their turn, write through a version-checked update, and release the claim automatically.
3
+ > Put a claim-and-commit loop inside an AI SDK tool call.
4
4
 
5
- Claims don't lock. If another writer holds the row, `claim` waits for them, re-reads the fresh row, then hands it to you — so two writers serialize instead of clobbering.
5
+ Use AI SDK for the agent loop and Ablo for the state boundary inside the tool.
6
+ When an agent updates a shared record from inside a tool call you have a
7
+ concurrency problem: another agent may be editing the same row, and a naive write
8
+ silently overwrites it. This is the safe pattern — read the record, claim the row
9
+ so anyone else waits their turn, write through a checked update, and release the
10
+ claim automatically.
11
+
12
+ Claims don't lock. If another writer holds the row, `claim` waits for them,
13
+ re-reads the fresh row, then hands it to you — so two writers serialize instead
14
+ of clobbering.
6
15
 
7
16
  ```ts
17
+ // app/api/chat/route.ts
8
18
  import Ablo from '@abloatai/ablo';
9
19
  import { defineSchema, model, z as schemaZ } from '@abloatai/ablo/schema';
10
20
  import { anthropic } from '@ai-sdk/anthropic';
11
- import { convertToModelMessages, streamText, tool, type UIMessage } from 'ai';
21
+ import {
22
+ streamText,
23
+ tool,
24
+ convertToModelMessages,
25
+ stepCountIs,
26
+ type UIMessage,
27
+ } from 'ai';
12
28
  import { z } from 'zod';
13
29
 
30
+ export const runtime = 'nodejs';
31
+
14
32
  const schema = defineSchema({
15
- weatherReports: model({
16
- location: schemaZ.string(),
17
- status: schemaZ.enum(['pending', 'ready']),
18
- forecast: schemaZ.string().optional(),
33
+ tasks: model({
34
+ title: schemaZ.string(),
35
+ status: schemaZ.enum(['todo', 'doing', 'done']),
36
+ summary: schemaZ.string().optional(),
19
37
  }),
20
38
  });
21
39
 
22
40
  const ablo = Ablo({
23
41
  schema,
24
42
  apiKey: process.env.ABLO_API_KEY,
43
+ transport: 'http',
25
44
  });
26
45
 
27
- const updateReport = tool({
28
- description: 'Update a weather report in the product database.',
46
+ const updateTask = tool({
47
+ description: 'Update a task in the product database.',
29
48
  inputSchema: z.object({
30
- reportId: z.string(),
31
- status: z.enum(['pending', 'ready']).optional(),
32
- forecast: z.string().optional(),
49
+ taskId: z.string(),
50
+ status: z.enum(['todo', 'doing', 'done']).optional(),
51
+ summary: z.string().optional(),
33
52
  }),
34
- execute: async ({ reportId, status, forecast }) => {
53
+ execute: async ({ taskId, status, summary }) => {
35
54
  await ablo.ready();
36
55
 
37
56
  // retrieve hits the server for the latest row (async — await it).
38
- const report = await ablo.weatherReports.retrieve({ id: reportId });
39
- if (!report) return { ok: false, reason: 'not_found' };
40
-
41
- // If another agent or user already holds this row, claim waits for them
42
- // to finish, re-reads the fresh row, then hands it back on `claim.data`.
43
- // The claim is released automatically when it goes out of scope.
44
- await using claim = await ablo.weatherReports.claim({
45
- id: reportId,
57
+ const task = await ablo.tasks.retrieve({ id: taskId });
58
+ if (!task) return { ok: false, reason: 'not_found' };
59
+
60
+ // If another agent already holds this row, claim waits for them to finish,
61
+ // re-reads the fresh row, then hands it back on `claim.data`. The claim is
62
+ // released automatically when it goes out of scope.
63
+ await using claim = await ablo.tasks.claim({
64
+ id: taskId,
46
65
  description: 'editing',
47
66
  ttl: '2m',
48
67
  });
49
- const claimed = claim.data;
50
68
 
51
- // Because you hold the claim, this update is rejected if the row
52
- // changed underneath you, instead of silently overwriting it.
53
- const updated = await ablo.weatherReports.update({
54
- id: claimed.id,
69
+ // Because you hold the claim, this update is rejected if the row changed
70
+ // underneath you, instead of silently overwriting it.
71
+ const updated = await ablo.tasks.update({
72
+ id: claim.data.id,
55
73
  data: {
56
- status: status ?? claimed.status,
57
- forecast: forecast ?? claimed.forecast,
74
+ status: status ?? claim.data.status,
75
+ summary: summary ?? claim.data.summary,
58
76
  },
77
+ wait: 'confirmed',
59
78
  });
60
79
 
61
- return { ok: true, report: updated };
80
+ return { ok: true, task: updated };
62
81
  },
63
82
  });
64
83
 
65
84
  export async function POST(req: Request) {
66
- // `useChat` posts UIMessage[]; the model is a server-bound provider instance,
67
- // never read off the request body.
85
+ // useChat sends UIMessage[]; convert before handing to the model.
68
86
  const { messages }: { messages: UIMessage[] } = await req.json();
69
87
 
70
- return streamText({
71
- model: anthropic('claude-sonnet-4-6'),
88
+ const result = streamText({
89
+ // The model is a SERVER-bound provider instance — never sent from the client.
90
+ model: anthropic('claude-sonnet-5'),
72
91
  messages: await convertToModelMessages(messages),
73
- tools: { updateReport },
74
- }).toUIMessageStreamResponse();
92
+ tools: { updateTask },
93
+ stopWhen: stepCountIs(5),
94
+ maxOutputTokens: 2048,
95
+ });
96
+
97
+ return result.toUIMessageStreamResponse();
75
98
  }
76
99
  ```
77
100
 
78
101
  The model provider is interchangeable — swap `anthropic(...)` for any
79
- server-bound provider instance. What matters is that the route binds the model
80
- on the server (never trusting one sent in the request body), converts the
81
- incoming `UIMessage[]` with `convertToModelMessages`, and that the tool:
82
-
83
- - reads the latest weather report with `retrieve` (a server read),
84
- - claims the row — if someone else holds it, the claim waits for them, then re-reads,
85
- - writes through `update`, which is rejected if the row changed underneath you,
86
- - releases the claim automatically when the handle goes out of scope,
87
- - waits for server confirmation.
102
+ server-bound provider instance. What matters is that the route binds the model on
103
+ the server (never trusting one sent in the request body), converts the incoming
104
+ `UIMessage[]` with `convertToModelMessages`, and that the tool:
105
+
106
+ - reads the latest row with `retrieve` (a server read),
107
+ - claims it for exclusive, ordered access — if someone else holds it, the claim
108
+ waits for them, then re-reads,
109
+ - writes through the model resource, which is rejected if the row changed
110
+ underneath you,
111
+ - waits for confirmation with `wait: 'confirmed'`,
112
+ - and auto-releases the claim when the tool returns.
@@ -1,10 +1,12 @@
1
1
  # Existing Python Backend
2
2
 
3
- Put Ablo in front of the records several people (or AI agents) edit at once and
4
- you get two things at no cost to your stack: every edit fans out live to
5
- everyone watching, and humans and agents write through one shared contract. Your
6
- Python service and database stay the source of truth Ablo doesn't replace your
7
- backend, it coordinates the writes into it. You stop calling your endpoint
3
+ > Add agent coordination to a Python API server without replacing it.
4
+
5
+ Put Ablo in front of the records several agents (or the people alongside them)
6
+ edit at once and you get two things at no cost to your stack: every edit fans out
7
+ live to everyone watching, and agents and people write through one shared
8
+ contract. The goal is not to replace the backend — your Python service and
9
+ database stay the source of truth, and Ablo coordinates the writes into them. You stop calling your endpoint
8
10
  directly; you call Ablo, Ablo calls your endpoint, and Ablo pushes the result
9
11
  back out to every browser and agent on that record.
10
12
 
@@ -110,7 +112,7 @@ export function ReportRow({
110
112
  }: {
111
113
  report: { id: string; location: string; status: string };
112
114
  }) {
113
- const report = useAblo((ablo) => ablo.weatherReports.get(serverReport.id)) ?? serverReport;
115
+ const report = useAblo((ablo) => ablo.weatherReports.local.retrieve(serverReport.id)) ?? serverReport;
114
116
  const active = useAblo((ablo) => ablo.weatherReports.claim.state({ id: serverReport.id }));
115
117
  const claimed = Boolean(active);
116
118
 
@@ -1,80 +1,163 @@
1
1
  # Next.js Example
2
2
 
3
- Building collaborative state in a Next.js app means handling three things at
4
- once: a fast initial render from the server, writes that don't overwrite a
5
- teammate's change, and a UI that updates the moment data changes. This example
6
- wires all three with Ablo Sync. The key piece is `claim()` — commit a write
7
- through it and Ablo rejects the write if someone edited the same record since
8
- you read it, so you never silently clobber another person's work.
3
+ > App-router setup: the two clients, the session route, and reactive reads.
9
4
 
10
- Claims don't lock. If another writer holds the row, `claim` waits for them,
11
- re-reads the fresh row, then hands it to you so two writers serialize instead
12
- of clobbering.
5
+ A production-shaped Next.js app on Ablo App Router, Server Actions, React
6
+ Server Components, and live client subscriptions. It handles three things at
7
+ once: a fast initial render from the server, writes that don't overwrite work
8
+ already in progress, and a UI that updates the moment data changes.
13
9
 
14
- The app uses three layers, mapped to three files: a React Server Component reads
15
- and renders, a Server Action claims and writes, and a client component shows
16
- live updates.
10
+ The key piece is `claim()`. Commit a write through it and Ablo rejects the write
11
+ if the record moved since you read it, so nothing is silently clobbered. Claims
12
+ don't lock: if another writer holds the row, `claim` waits for them, re-reads the
13
+ fresh row, then hands it to you — writers serialize instead of colliding.
17
14
 
18
15
  ## Structure
19
16
 
20
17
  ```txt
21
18
  app/
22
- reports/
19
+ layout.tsx # wraps the tree in <Providers>
20
+ providers.tsx # Client: browser Ablo client + <AbloProvider>
21
+ api/
22
+ ablo-session/
23
+ route.ts # mints a per-user ek_ token for the browser
24
+ tasks/
23
25
  [id]/
24
- page.tsx # RSC: retrieve + render
25
- actions.ts # Server Action: write that's rejected if someone else edited first
26
- ReportEditor.tsx # Client: live updates
27
- lib/
28
- ablo.ts # Schema-backed Ablo client for server actions
26
+ page.tsx # RSC: retrieve + render
27
+ actions.ts # Server Action: claim, then write
28
+ TaskEditor.tsx # Client: live updates
29
+ lib/
30
+ ablo.ts # Server Ablo client (holds ABLO_API_KEY)
31
+ ablo.schema.ts # shared schema
32
+ ```
33
+
34
+ There are **two** Ablo clients, and the split is the whole point:
35
+
36
+ - **Server** (`lib/ablo.ts`) holds the secret `apiKey` (`sk_`). Used by RSCs,
37
+ Server Actions, and route handlers. Never imported into a client component.
38
+ - **Browser** (`app/providers.tsx`) holds **no secret**. It fetches a
39
+ short-lived per-user token (`ek_`) from a backend route via `authEndpoint`.
40
+
41
+ Skipping the browser half is the most common setup mistake — the client then
42
+ has no credential and the engine fails to initialize with `session_expired`.
43
+
44
+ ## Server Client
45
+
46
+ ```ts
47
+ // lib/ablo.ts — server-only
48
+ import Ablo from '@abloatai/ablo';
49
+ import { schema } from './ablo.schema';
50
+
51
+ export const ablo = Ablo({
52
+ schema,
53
+ apiKey: process.env.ABLO_API_KEY,
54
+ transport: 'http',
55
+ });
56
+ ```
57
+
58
+ ## Session Route
59
+
60
+ The browser can't hold `sk_`, so a backend route mints a scoped, short-lived
61
+ `ek_` for the signed-in user. Guard it with your own auth.
62
+
63
+ ```ts
64
+ // app/api/ablo-session/route.ts
65
+ import { ablo } from '@/lib/ablo';
66
+ import { getCurrentUser } from '@/auth';
67
+
68
+ export async function POST() {
69
+ const user = await getCurrentUser();
70
+ if (!user) return new Response('Unauthorized', { status: 401 });
71
+
72
+ const session = await ablo.sessions.create({ user: { id: user.id } });
73
+ return Response.json({ token: session.token });
74
+ }
75
+ ```
76
+
77
+ ## Provider
78
+
79
+ The browser client points `authEndpoint` at that route and is handed to
80
+ `<AbloProvider>` as an instance. Build it once at module scope so the socket
81
+ isn't torn down on every render.
82
+
83
+ ```tsx
84
+ // app/providers.tsx
85
+ 'use client';
86
+
87
+ import Ablo from '@abloatai/ablo';
88
+ import { AbloProvider } from '@abloatai/ablo/react';
89
+ import { schema } from '@/lib/ablo.schema';
90
+
91
+ const ablo = Ablo({
92
+ schema,
93
+ authEndpoint: '/api/ablo-session',
94
+ });
95
+
96
+ export function Providers({ children }: { children: React.ReactNode }) {
97
+ return <AbloProvider client={ablo}>{children}</AbloProvider>;
98
+ }
99
+ ```
100
+
101
+ ```tsx
102
+ // app/layout.tsx
103
+ import { Providers } from './providers';
104
+
105
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
106
+ return (
107
+ <html lang="en">
108
+ <body>
109
+ <Providers>{children}</Providers>
110
+ </body>
111
+ </html>
112
+ );
113
+ }
29
114
  ```
30
115
 
31
116
  ## RSC Initial Render
32
117
 
33
118
  ```tsx
34
- // app/reports/[id]/page.tsx
119
+ // app/tasks/[id]/page.tsx
35
120
  import { ablo } from '@/lib/ablo';
36
121
 
37
- export default async function ReportPage({
122
+ export default async function TaskPage({
38
123
  params,
39
124
  }: { params: Promise<{ id: string }> }) {
40
125
  const { id } = await params;
41
126
  await ablo.ready();
42
- const report = await ablo.weatherReports.retrieve({ id });
43
- if (!report) return null;
127
+ const task = await ablo.tasks.retrieve({ id });
128
+ if (!task) return null;
44
129
 
45
- return <ReportEditor report={report} />;
130
+ return <TaskEditor task={task} />;
46
131
  }
47
132
  ```
48
133
 
49
134
  ## Server Action Commit
50
135
 
51
136
  ```ts
52
- // app/reports/[id]/actions.ts
137
+ // app/tasks/[id]/actions.ts
53
138
  'use server';
54
139
 
55
140
  import { ablo } from '@/lib/ablo';
56
141
 
57
- export async function markReady(id: string) {
58
- await using claim = await ablo.weatherReports.claim({
59
- id,
60
- queue: false,
61
- description: 'marking_ready',
62
- });
63
- const claimed = claim.data;
142
+ export async function markDone(id: string) {
143
+ // Claim grants exclusive, ordered access and hands back the fresh row.
144
+ await using claim = await ablo.tasks.claim({ id });
64
145
 
65
- const report = await ablo.weatherReports.update({
66
- id: claimed.id,
67
- data: { status: 'ready' },
146
+ const task = await ablo.tasks.update({
147
+ id,
148
+ data: { status: 'done' },
149
+ claim,
68
150
  wait: 'confirmed',
69
151
  });
70
152
 
71
- return { status: 'ready', report };
153
+ return { status: 'done', task };
154
+ // claim auto-releases as the action returns
72
155
  }
73
156
  ```
74
157
 
75
- The write runs while the `claim` is held. If another participant commits
76
- between the read and the write, the commit is rejected because the row changed
77
- underneath you. The action can re-fetch and ask the user to retry.
158
+ The write runs while the claim is held. If anything else commits between the
159
+ read and the write, the commit is rejected because the row changed underneath
160
+ you re-fetch and retry.
78
161
 
79
162
  ## Live Client
80
163
 
@@ -83,14 +166,14 @@ underneath you. The action can re-fetch and ask the user to retry.
83
166
 
84
167
  import { useAblo } from '@abloatai/ablo/react';
85
168
 
86
- export function ReportEditor({ report: serverReport }: Props) {
87
- const data = useAblo((ablo) => ablo.weatherReports.get(serverReport.id)) ?? serverReport;
88
- const active = useAblo((ablo) => ablo.weatherReports.claim.state({ id: serverReport.id }));
89
- const claimed = Boolean(active);
169
+ export function TaskEditor({ task: serverTask }: Props) {
170
+ const data = useAblo((ablo) => ablo.tasks.local.retrieve(serverTask.id)) ?? serverTask;
171
+ const holder = useAblo((ablo) => ablo.tasks.claim.state({ id: serverTask.id }));
172
+ const busy = Boolean(holder);
90
173
 
91
174
  return (
92
- <button disabled={claimed || data.status === 'ready'}>
93
- {claimed ? 'Someone is editing' : 'Mark ready'}
175
+ <button disabled={busy || data.status === 'done'}>
176
+ {busy ? 'Someone is editing' : 'Mark done'}
94
177
  </button>
95
178
  );
96
179
  }
@@ -98,6 +181,5 @@ export function ReportEditor({ report: serverReport }: Props) {
98
181
 
99
182
  ## More
100
183
 
101
- - [Next.js landing](/nextjs) — the product overview.
102
- - [React reference](/docs/react) — every option on `useAblo`.
103
- - [API reference](/docs/api) — every option on the write path.
184
+ - [React reference](../react.md) — every option on `useAblo`.
185
+ - [API reference](../api.md) — every option on the write path.
@@ -1,12 +1,15 @@
1
- # Agent Scoped to One Deck
1
+ # Agent Scoped to One Workspace
2
2
 
3
- You want an agent that edits **one deck** and pushes realtime updates to the
4
- people on **that deck only** — not a broadcast to the whole org. The catch most
5
- people hit: which write reaches whom is decided by how the rows *relate*, not by
6
- which columns the write touched. So a slide edit that never sets `deckId` still
7
- reaches everyone viewing the deck, because the slide already belongs to it. You
8
- get this by declaring the relationship once, then narrowing the agent to the deck
9
- id you never assemble a `deck:<id>` audience string by hand.
3
+ > Narrow an agent to a single record's audience, so its writes reach that group and no one else.
4
+
5
+ You want an agent that edits **one workspace** and pushes realtime updates to the
6
+ participants on **that workspace only** not a broadcast to the whole org. The
7
+ catch most people hit: which write reaches whom is decided by how the rows
8
+ *relate*, not by which columns the write touched. So a task edit that never sets
9
+ `workspaceId` still reaches everyone watching the workspace, because the task already
10
+ belongs to it. You get this by declaring the relationship once, then narrowing the
11
+ agent to the workspace id — you never assemble a `workspace:<id>` audience string by
12
+ hand.
10
13
 
11
14
  The three steps below show how to declare it, scope the agent, and write.
12
15
 
@@ -19,22 +22,20 @@ import { defineSchema, identityRole, model, relation, z } from '@abloatai/ablo/s
19
22
 
20
23
  export const schema = defineSchema(
21
24
  {
22
- // A deck's rows form the group `deck:<id>` (the kind comes from `groups.root`).
23
- decks: model(
25
+ // A workspace's rows form the group `workspace:<id>` (the kind comes from `groups.root`).
26
+ workspaces: model(
24
27
  { title: z.string() },
25
- {},
26
- { groups: { root: 'deck' } },
28
+ { groups: { root: 'workspace' } },
27
29
  ),
28
- // A slide has no group of its own. It inherits its deck's group via the
29
- // `parent` edge, so a slide write reaches everyone viewing the deck.
30
- slides: model(
31
- { deckId: z.string(), body: z.string() },
32
- { deck: relation.belongsTo('decks', 'deckId', { parent: true }) },
33
- {},
30
+ // A task has no group of its own. It inherits its workspace's group via the
31
+ // `parent` edge, so a task write reaches everyone watching the workspace.
32
+ tasks: model(
33
+ { workspaceId: z.string(), title: z.string() },
34
+ { relations: { workspace: relation.belongsTo('workspaces', 'workspaceId', { parent: true }) } },
34
35
  ),
35
36
  },
36
37
  {
37
- // Humans get their full org scope automatically from these.
38
+ // People get their full org scope automatically from these.
38
39
  identityRoles: [
39
40
  identityRole({ kind: 'org', source: 'organizationId' }),
40
41
  identityRole({ kind: 'user', source: 'userId' }),
@@ -43,31 +44,31 @@ export const schema = defineSchema(
43
44
  );
44
45
  ```
45
46
 
46
- ## 2. Dispatch — narrow the agent to the deck it's working on
47
+ ## 2. Dispatch — narrow the agent to the workspace it's working on
47
48
 
48
49
  An agent can never reach more than the user who triggered it — that's the upper
49
- limit. From there you narrow it to a single deck by minting the agent's session
50
- against **just that deck's sync group**. You build the group from the **model
51
- kind and id** with the typed `syncGroup` helper — `syncGroup('deck', deckId)`,
52
- never a hand-assembled `deck:<id>` string — where `'deck'` is the kind declared
53
- by the `decks` model's `scope`.
50
+ limit. From there you narrow it to a single workspace by minting the agent's session
51
+ against **just that workspace's sync group**. You build the group from the **model
52
+ kind and id** with the typed `syncGroup` helper — `syncGroup('workspace', workspaceId)`,
53
+ never a hand-assembled `workspace:<id>` string — where `'workspace'` is the kind
54
+ declared by the `workspaces` model's `groups.root`.
54
55
 
55
56
  Mint the scoped session on your backend (it holds the `sk_` key; the browser
56
57
  never does), then hand the short-lived token to the browser client:
57
58
 
58
59
  ```ts
59
- // server — mints a scoped agent session for one deck
60
+ // server — mints a scoped agent session for one workspace
60
61
  import Ablo from '@abloatai/ablo';
61
62
  import { syncGroup } from '@abloatai/ablo/schema';
62
63
  import { schema } from './schema';
63
64
 
64
65
  const server = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
65
66
 
66
- export async function mintDeckAgentSession(deckId: string, agentId: string) {
67
+ export async function mintProjectAgentSession(workspaceId: string, agentId: string) {
67
68
  const { token } = await server.sessions.create({
68
69
  agent: { id: agentId },
69
- can: { slides: ['read', 'update'] }, // operation allowlist for this run
70
- syncGroups: [syncGroup('deck', deckId)], // narrowed to just this deck
70
+ can: { tasks: ['read', 'update'] }, // operation allowlist for this run
71
+ syncGroups: [syncGroup('workspace', workspaceId)], // narrowed to just this workspace
71
72
  });
72
73
  return token;
73
74
  }
@@ -81,7 +82,7 @@ import { schema } from './schema';
81
82
 
82
83
  const ablo = Ablo({
83
84
  schema,
84
- apiKey: async () => mintDeckAgentSession(deckId, agentId),
85
+ apiKey: async () => mintProjectAgentSession(workspaceId, agentId),
85
86
  });
86
87
 
87
88
  // The agent run is mounted on behalf of its triggering user.
@@ -91,30 +92,30 @@ const ablo = Ablo({
91
92
  ```
92
93
 
93
94
  `syncGroups` requests, it never grants: at connect the server intersects the
94
- groups the session asks for with the groups the identity is actually allowed,
95
- so the agent can never reach a deck its triggering user couldn't.
95
+ groups the session asks for with the groups the identity is actually allowed, so
96
+ the agent can never reach a workspace its triggering user couldn't.
96
97
 
97
- ## 3. Write — it fans out to everyone on that deck
98
+ ## 3. Write — it fans out to everyone on that workspace
98
99
 
99
100
  Inside any component under the provider, grab the scoped client with `useAblo()`
100
- and write. The connection is already narrowed to `deck:<deckId>` from Step 2.
101
+ and write. The connection is already narrowed to `workspace:<workspaceId>` from Step 2.
101
102
 
102
103
  ```ts
103
- const ablo = useAblo<(typeof schema)['models']>();
104
+ const ablo = useAblo();
104
105
 
105
- // Other participants subscribed to deck:<deckId> — the human in the editor,
106
- // a reviewer agent — receive this delta in realtime. Participants on other
107
- // decks never see it.
108
- await ablo.slides.update({ id: slideId, data: { body: 'Q4 revenue up 12% YoY' } });
106
+ // Other participants subscribed to workspace:<workspaceId> — a reviewer agent, a
107
+ // person watching in the UI — receive this delta in realtime. Participants on
108
+ // other workspaces never see it.
109
+ await ablo.tasks.update({ id: taskId, data: { title: 'Ship the Q4 report' } });
109
110
  ```
110
111
 
111
- The slide's delta is stamped `deck:<deckId>`, derived server-side from the
112
- slidedeck `parent` edge — not from `deckId` appearing in this particular
112
+ The task's delta is stamped `workspace:<workspaceId>`, derived server-side from the
113
+ taskworkspace `parent` edge — not from `workspaceId` appearing in this particular
113
114
  write, and not from whatever the agent happened to subscribe to. The routing is
114
- decided by the data: a slide belongs to its deck, so its writes go to the deck's
115
- group, full stop.
115
+ decided by the data: a task belongs to its workspace, so its writes go to the
116
+ workspace's group, full stop.
116
117
 
117
118
  ## See also
118
119
 
119
120
  - [Identity & Sync Groups](../identity.md) — the full scope / parent / grants model.
120
- - [Agent + Human](./agent-human.md) — yielding when a human edits the same row.
121
+ - [Agent + Human](./agent-human.md) — yielding when someone else edits the same row.