@abloatai/ablo 0.34.1 → 0.36.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.
- package/AGENTS.md +2 -1
- package/CHANGELOG.md +758 -5
- package/README.md +56 -502
- package/bin/ablo.cjs +39 -0
- package/dist/BaseSyncedStore.d.ts +176 -48
- package/dist/BaseSyncedStore.js +346 -214
- package/dist/Database.d.ts +17 -44
- package/dist/Database.js +96 -79
- package/dist/InstanceCache.d.ts +31 -6
- package/dist/InstanceCache.js +65 -30
- package/dist/LazyReferenceCollection.d.ts +3 -3
- package/dist/LazyReferenceCollection.js +4 -4
- package/dist/Model.d.ts +23 -13
- package/dist/Model.js +27 -17
- package/dist/ModelRegistry.d.ts +8 -4
- package/dist/ModelRegistry.js +20 -18
- package/dist/NetworkMonitor.d.ts +3 -1
- package/dist/NetworkMonitor.js +7 -5
- package/dist/{SyncEngineContext.d.ts → RuntimeContext.d.ts} +20 -13
- package/dist/{SyncEngineContext.js → RuntimeContext.js} +11 -12
- package/dist/SyncClient.d.ts +47 -47
- package/dist/SyncClient.js +215 -156
- package/dist/ai-sdk/coordinatedTool.d.ts +2 -2
- package/dist/ai-sdk/coordinatedTool.js +1 -1
- package/dist/ai-sdk/coordinationContext.d.ts +2 -2
- package/dist/ai-sdk/coordinationContext.js +1 -1
- package/dist/ai-sdk/wrap.d.ts +3 -3
- package/dist/ai-sdk/wrap.js +2 -2
- package/dist/auth/index.d.ts +1 -156
- package/dist/auth/index.js +8 -301
- package/dist/client/Ablo.d.ts +42 -287
- package/dist/client/Ablo.js +129 -963
- package/dist/client/abloClient.d.ts +309 -0
- package/dist/client/abloClient.js +13 -0
- package/dist/client/clientPrelude.d.ts +52 -0
- package/dist/client/clientPrelude.js +60 -0
- package/dist/client/consoleLogger.d.ts +2 -2
- package/dist/client/coreClient.d.ts +60 -0
- package/dist/client/coreClient.js +118 -0
- package/dist/client/createInternalComponents.d.ts +8 -4
- package/dist/client/createInternalComponents.js +17 -10
- package/dist/client/createModelProxy.d.ts +98 -373
- package/dist/client/createModelProxy.js +233 -139
- package/dist/client/humans.d.ts +69 -0
- package/dist/client/humans.js +78 -0
- package/dist/client/modelRegistration.d.ts +1 -1
- package/dist/client/modelRegistration.js +9 -9
- package/dist/client/options.d.ts +73 -17
- package/dist/client/reactiveEngine.d.ts +53 -0
- package/dist/client/reactiveEngine.js +688 -0
- package/dist/client/resourceTypes.d.ts +9 -250
- package/dist/client/resourceTypes.js +8 -5
- package/dist/client/schemaConfig.d.ts +4 -4
- package/dist/client/schemaConfig.js +6 -2
- package/dist/client/storeCluster.d.ts +47 -0
- package/dist/client/storeCluster.js +118 -0
- package/dist/client/storeLifecycle.d.ts +61 -0
- package/dist/client/storeLifecycle.js +231 -0
- package/dist/client/validateAbloOptions.d.ts +3 -2
- package/dist/client/validateAbloOptions.js +1 -1
- package/dist/client/wsMutationExecutor.d.ts +3 -3
- package/dist/client/wsMutationExecutor.js +3 -3
- package/dist/context.d.ts +22 -9
- package/dist/context.js +33 -9
- package/dist/coordination/ClaimLog.d.ts +26 -0
- package/dist/coordination/ClaimLog.js +32 -0
- package/dist/coordination/index.d.ts +1 -15
- package/dist/coordination/index.js +8 -31
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +2 -2
- package/dist/docs/catalog.d.ts +72 -0
- package/dist/docs/catalog.js +230 -0
- package/dist/docs/index.d.ts +10 -0
- package/dist/docs/index.js +10 -0
- package/dist/environment.d.ts +1 -40
- package/dist/environment.js +8 -37
- package/dist/index.d.ts +44 -36
- package/dist/index.js +30 -22
- package/dist/interfaces/index.d.ts +44 -134
- package/dist/keys/index.d.ts +1 -77
- package/dist/keys/index.js +8 -190
- package/dist/mutators/{RecordingTransaction.d.ts → RecordingMutation.d.ts} +4 -4
- package/dist/mutators/{RecordingTransaction.js → RecordingMutation.js} +2 -2
- package/dist/mutators/Transaction.d.ts +1 -1
- package/dist/mutators/Transaction.js +1 -1
- package/dist/mutators/UndoManager.d.ts +6 -6
- package/dist/mutators/UndoManager.js +5 -5
- package/dist/mutators/defineMutators.d.ts +3 -3
- package/dist/mutators/defineMutators.js +1 -1
- package/dist/mutators/inverseOp.js +2 -2
- package/dist/mutators/mutateActions.d.ts +3 -3
- package/dist/mutators/mutateActions.js +1 -1
- package/dist/mutators/readerActions.d.ts +1 -1
- package/dist/mutators/undoApply.d.ts +1 -1
- package/dist/mutators/undoApply.js +1 -1
- package/dist/policy/index.d.ts +2 -2
- package/dist/policy/index.js +1 -1
- package/dist/query/client.d.ts +5 -2
- package/dist/query/client.js +10 -9
- package/dist/query/types.d.ts +6 -41
- package/dist/query/types.js +2 -2
- package/dist/react/AbloProvider.d.ts +18 -8
- package/dist/react/AbloProvider.js +10 -9
- package/dist/react/context.d.ts +3 -3
- package/dist/react/context.js +1 -1
- package/dist/react/createAbloReact.d.ts +56 -0
- package/dist/react/createAbloReact.js +51 -0
- package/dist/react/index.d.ts +6 -5
- package/dist/react/index.js +6 -3
- package/dist/react/internalContext.d.ts +1 -1
- package/dist/react/useAblo.d.ts +12 -5
- package/dist/react/useAblo.js +26 -8
- package/dist/react/useCurrentUserId.js +1 -1
- package/dist/react/useErrorListener.js +1 -1
- package/dist/react/useMutationFailureListener.d.ts +2 -2
- package/dist/react/useMutationFailureListener.js +1 -1
- package/dist/react/useMutators.d.ts +3 -3
- package/dist/react/useMutators.js +3 -3
- package/dist/react/useUndoScope.d.ts +5 -5
- package/dist/react/useUndoScope.js +1 -1
- package/dist/schema/coordination.d.ts +69 -10
- package/dist/schema/coordination.js +90 -9
- package/dist/schema/ddl.js +2 -2
- package/dist/schema/diff.d.ts +1 -1
- package/dist/schema/generate.js +1 -1
- package/dist/schema/index.d.ts +11 -10
- package/dist/schema/index.js +22 -18
- package/dist/schema/queries.d.ts +27 -27
- package/dist/schema/queries.js +23 -23
- package/dist/schema/select.d.ts +3 -3
- package/dist/schema/select.js +6 -3
- package/dist/schema/serialize.d.ts +15 -6
- package/dist/schema/serialize.js +20 -3
- package/dist/schema/sugar.d.ts +6 -7
- package/dist/schema/sugar.js +9 -12
- package/dist/schema/syncDeltaRow.d.ts +4 -152
- package/dist/schema/syncDeltaRow.js +4 -105
- package/dist/server/adapter.d.ts +18 -1
- package/dist/server/commit.d.ts +10 -16
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/readConfig.d.ts +1 -1
- package/dist/source/adapter.d.ts +7 -5
- package/dist/source/adapter.js +7 -5
- package/dist/source/adapters/drizzle.d.ts +1 -1
- package/dist/source/adapters/drizzle.js +2 -2
- package/dist/source/adapters/kysely.d.ts +1 -1
- package/dist/source/adapters/kysely.js +1 -1
- package/dist/source/adapters/kyselyMutationCore.d.ts +1 -1
- package/dist/source/adapters/kyselyMutationCore.js +2 -2
- package/dist/source/adapters/memory.js +1 -1
- package/dist/source/adapters/prisma.d.ts +8 -3
- package/dist/source/adapters/prisma.js +1 -1
- package/dist/source/connector.js +1 -1
- package/dist/source/connectorProtocol.d.ts +2 -8
- package/dist/source/connectorProtocol.js +3 -2
- package/dist/source/contract.d.ts +29 -17
- package/dist/source/contract.js +27 -22
- package/dist/source/factory.d.ts +1 -1
- package/dist/source/idempotency.js +2 -2
- package/dist/source/index.d.ts +1 -0
- package/dist/source/index.js +3 -0
- package/dist/source/next.d.ts +1 -1
- package/dist/source/signing.d.ts +9 -2
- package/dist/source/signing.js +4 -1
- package/dist/source/types.d.ts +6 -4
- package/dist/source/types.js +1 -1
- package/dist/{core/storeContract.d.ts → storeContract.d.ts} +6 -6
- package/dist/{core → stores}/DatabaseManager.d.ts +3 -1
- package/dist/{core → stores}/DatabaseManager.js +14 -13
- package/dist/stores/ObjectStore.d.ts +1 -1
- package/dist/{core → stores}/StoreManager.d.ts +9 -26
- package/dist/{core → stores}/StoreManager.js +29 -77
- package/dist/stores/SyncActionStore.d.ts +4 -2
- package/dist/stores/SyncActionStore.js +11 -17
- package/dist/stores/syncAction.d.ts +26 -0
- package/dist/stores/syncAction.js +16 -0
- package/dist/surface.d.ts +3 -3
- package/dist/surface.js +6 -4
- package/dist/sync/BootstrapFetcher.d.ts +127 -6
- package/dist/sync/BootstrapFetcher.js +511 -83
- package/dist/sync/ConnectionManager.d.ts +6 -198
- package/dist/sync/ConnectionManager.js +6 -677
- package/dist/sync/OnDemandLoader.d.ts +5 -2
- package/dist/sync/OnDemandLoader.js +61 -21
- package/dist/sync/SubscriptionManager.d.ts +13 -2
- package/dist/sync/SubscriptionManager.js +23 -5
- package/dist/sync/SyncWebSocket.d.ts +27 -510
- package/dist/sync/SyncWebSocket.js +76 -954
- package/dist/sync/awaitClaimGrant.d.ts +4 -44
- package/dist/sync/awaitClaimGrant.js +4 -109
- package/dist/sync/bootstrapApply.d.ts +3 -0
- package/dist/sync/bootstrapApply.js +2 -2
- package/dist/sync/commitFrames.d.ts +6 -40
- package/dist/sync/commitFrames.js +6 -97
- package/dist/sync/contextPorts.d.ts +18 -0
- package/dist/sync/contextPorts.js +31 -0
- package/dist/sync/createClaimStream.d.ts +5 -49
- package/dist/sync/createClaimStream.js +5 -469
- package/dist/sync/createPresenceStream.d.ts +26 -4
- package/dist/sync/createPresenceStream.js +28 -20
- package/dist/sync/createSnapshot.d.ts +2 -2
- package/dist/sync/createSnapshot.js +1 -1
- package/dist/sync/credentialLifecycle.d.ts +5 -173
- package/dist/sync/credentialLifecycle.js +5 -320
- package/dist/sync/deltaPipeline.d.ts +13 -12
- package/dist/sync/deltaPipeline.js +21 -4
- package/dist/sync/groupChange.d.ts +3 -0
- package/dist/sync/groupChange.js +16 -14
- package/dist/sync/participants.d.ts +24 -6
- package/dist/sync/participants.js +32 -23
- package/dist/sync/schemaDrift.d.ts +55 -0
- package/dist/sync/schemaDrift.js +53 -0
- package/dist/sync/schemas.d.ts +23 -33
- package/dist/sync/schemas.js +29 -20
- package/dist/sync/syncPlan.d.ts +3 -3
- package/dist/sync/wsFrameHandlers.d.ts +6 -114
- package/dist/sync/wsFrameHandlers.js +6 -392
- package/dist/syncLog/contract.d.ts +20 -0
- package/dist/syncLog/contract.js +19 -0
- package/dist/syncLog/index.d.ts +1 -0
- package/dist/syncLog/index.js +1 -0
- package/dist/transaction/ablo.d.ts +88 -0
- package/dist/transaction/ablo.js +33 -0
- package/dist/{client/auth.d.ts → transaction/auth/apiKey.d.ts} +43 -8
- package/dist/{client/auth.js → transaction/auth/apiKey.js} +19 -0
- package/dist/transaction/auth/bootstrapScope.d.ts +15 -0
- package/dist/transaction/auth/bootstrapScope.js +1 -0
- package/dist/transaction/auth/capability.d.ts +212 -0
- package/dist/transaction/auth/capability.js +224 -0
- package/dist/{auth → transaction/auth}/credentialSource.d.ts +8 -1
- package/dist/{client → transaction/auth}/identity.d.ts +8 -7
- package/dist/{client → transaction/auth}/identity.js +1 -1
- package/dist/transaction/auth/index.d.ts +162 -0
- package/dist/transaction/auth/index.js +304 -0
- package/dist/{auth → transaction/auth}/schemas.d.ts +1 -1
- package/dist/{auth → transaction/auth}/schemas.js +13 -13
- package/dist/{client → transaction/auth}/sessionMint.d.ts +8 -8
- package/dist/{client → transaction/auth}/sessionMint.js +4 -7
- package/dist/transaction/coordination/awaitClaimGrant.d.ts +56 -0
- package/dist/transaction/coordination/awaitClaimGrant.js +124 -0
- package/dist/{client → transaction/coordination}/claimHeartbeatLoop.d.ts +34 -0
- package/dist/{client → transaction/coordination}/claimHeartbeatLoop.js +20 -0
- package/dist/transaction/coordination/claimMeta.d.ts +49 -0
- package/dist/transaction/coordination/claimMeta.js +52 -0
- package/dist/transaction/coordination/createClaimStream.d.ts +64 -0
- package/dist/transaction/coordination/createClaimStream.js +475 -0
- package/dist/transaction/coordination/events.d.ts +74 -0
- package/dist/transaction/coordination/events.js +7 -0
- package/dist/transaction/coordination/index.d.ts +19 -0
- package/dist/transaction/coordination/index.js +45 -0
- package/dist/transaction/coordination/locator.d.ts +104 -0
- package/dist/transaction/coordination/locator.js +102 -0
- package/dist/transaction/coordination/schema.d.ts +1536 -0
- package/dist/transaction/coordination/schema.js +1177 -0
- package/dist/transaction/coordination/targetConflict.d.ts +2 -0
- package/dist/transaction/coordination/targetConflict.js +107 -0
- package/dist/{coordination → transaction/coordination}/trace.d.ts +7 -18
- package/dist/{coordination → transaction/coordination}/trace.js +18 -25
- package/dist/transaction/durableWrites.d.ts +62 -0
- package/dist/{client → transaction}/durableWrites.js +28 -3
- package/dist/transaction/environment.d.ts +105 -0
- package/dist/transaction/environment.js +108 -0
- package/dist/{errorCodes.d.ts → transaction/errorCodes.d.ts} +12 -12
- package/dist/{errorCodes.js → transaction/errorCodes.js} +45 -18
- package/dist/{errors.d.ts → transaction/errors.d.ts} +37 -13
- package/dist/{errors.js → transaction/errors.js} +85 -16
- package/dist/transaction/footprint.d.ts +111 -0
- package/dist/transaction/footprint.js +0 -0
- package/dist/transaction/index.d.ts +20 -0
- package/dist/transaction/index.js +20 -0
- package/dist/transaction/keys/index.d.ts +87 -0
- package/dist/transaction/keys/index.js +207 -0
- package/dist/transaction/log/syncDeltaRow.d.ts +158 -0
- package/dist/transaction/log/syncDeltaRow.js +95 -0
- package/dist/{sync/syncPosition.d.ts → transaction/logPosition.d.ts} +22 -8
- package/dist/{sync/syncPosition.js → transaction/logPosition.js} +15 -6
- package/dist/transaction/logger.d.ts +16 -0
- package/dist/transaction/logger.js +7 -0
- package/dist/transaction/observability.d.ts +53 -0
- package/dist/transaction/observability.js +19 -0
- package/dist/transaction/plugin.d.ts +285 -0
- package/dist/transaction/plugin.js +106 -0
- package/dist/{policy → transaction/policy}/types.d.ts +3 -3
- package/dist/{policy → transaction/policy}/types.js +2 -0
- package/dist/transaction/resources/httpResources.d.ts +321 -0
- package/dist/transaction/resources/httpResources.js +7 -0
- package/dist/transaction/resources/modelOperations.d.ts +427 -0
- package/dist/transaction/resources/modelOperations.js +12 -0
- package/dist/transaction/resources/mutationOptions.d.ts +66 -0
- package/dist/transaction/resources/mutationOptions.js +9 -0
- package/dist/transaction/resources/where.d.ts +101 -0
- package/dist/transaction/resources/where.js +115 -0
- package/dist/{client → transaction/resources}/writeOptionsSchema.d.ts +2 -6
- package/dist/{client → transaction/resources}/writeOptionsSchema.js +9 -5
- package/dist/{schema → transaction/schema}/field.d.ts +17 -23
- package/dist/{schema → transaction/schema}/field.js +5 -5
- package/dist/transaction/schema/fieldRef.d.ts +38 -0
- package/dist/transaction/schema/fieldRef.js +11 -0
- package/dist/transaction/schema/loadStrategy.d.ts +45 -0
- package/dist/transaction/schema/loadStrategy.js +46 -0
- package/dist/{schema → transaction/schema}/model.d.ts +50 -35
- package/dist/{schema → transaction/schema}/model.js +30 -20
- package/dist/transaction/schema/openapi.d.ts +58 -0
- package/dist/transaction/schema/openapi.js +501 -0
- package/dist/{schema → transaction/schema}/relation.d.ts +21 -16
- package/dist/{schema → transaction/schema}/relation.js +7 -7
- package/dist/{schema → transaction/schema}/residency.d.ts +0 -9
- package/dist/{schema → transaction/schema}/residency.js +0 -5
- package/dist/{schema → transaction/schema}/roles.d.ts +5 -5
- package/dist/{schema → transaction/schema}/roles.js +5 -5
- package/dist/{schema → transaction/schema}/schema.d.ts +39 -10
- package/dist/{schema → transaction/schema}/schema.js +24 -3
- package/dist/{schema → transaction/schema}/tenancy.d.ts +1 -1
- package/dist/{schema → transaction/schema}/tenancy.js +7 -4
- package/dist/transaction/transactionLayer.d.ts +82 -0
- package/dist/transaction/transactionLayer.js +24 -0
- package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.d.ts +5 -6
- package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.js +9 -13
- package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.d.ts +9 -2
- package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.js +5 -9
- package/dist/{transactions/durableWriteStore.d.ts → transaction/transactions/settlement/pendingWrite.d.ts} +11 -37
- package/dist/transaction/transactions/settlement/pendingWrite.js +20 -0
- package/dist/transaction/transport/commitFrames.d.ts +90 -0
- package/dist/transaction/transport/commitFrames.js +134 -0
- package/dist/transaction/transport/connectionManager.d.ts +215 -0
- package/dist/transaction/transport/connectionManager.js +673 -0
- package/dist/transaction/transport/credentialLifecycle.d.ts +177 -0
- package/dist/transaction/transport/credentialLifecycle.js +324 -0
- package/dist/{sync → transaction/transport}/heartbeat.d.ts +3 -1
- package/dist/{sync → transaction/transport}/heartbeat.js +6 -4
- package/dist/transaction/transport/httpClient.d.ts +131 -0
- package/dist/{client → transaction/transport}/httpClient.js +6 -5
- package/dist/transaction/transport/httpOptions.d.ts +33 -0
- package/dist/transaction/transport/httpOptions.js +12 -0
- package/dist/{client → transaction/transport}/httpTransport.js +295 -97
- package/dist/{sync/NetworkProbe.d.ts → transaction/transport/networkProbe.d.ts} +7 -4
- package/dist/{sync/NetworkProbe.js → transaction/transport/networkProbe.js} +14 -13
- package/dist/transaction/transport/wsFrameHandlers.d.ts +128 -0
- package/dist/transaction/transport/wsFrameHandlers.js +429 -0
- package/dist/transaction/transport/wsTransport.d.ts +574 -0
- package/dist/transaction/transport/wsTransport.js +1023 -0
- package/dist/transaction/types/assertExact.d.ts +17 -0
- package/dist/transaction/types/assertExact.js +1 -0
- package/dist/{types → transaction/types}/global.d.ts +17 -2
- package/dist/{types → transaction/types}/global.js +2 -1
- package/dist/{types → transaction/types}/index.d.ts +14 -46
- package/dist/{types → transaction/types}/index.js +7 -16
- package/dist/{types → transaction/types}/streams.d.ts +73 -45
- package/dist/transaction/utils/duration.d.ts +50 -0
- package/dist/{utils → transaction/utils}/duration.js +32 -0
- package/dist/{utils → transaction/utils}/json.d.ts +18 -0
- package/dist/transaction/utils/json.js +276 -0
- package/dist/transaction/wire/accountResponses.d.ts +420 -0
- package/dist/transaction/wire/accountResponses.js +290 -0
- package/dist/transaction/wire/auth.d.ts +56 -0
- package/dist/transaction/wire/auth.js +63 -0
- package/dist/transaction/wire/claimEvent.d.ts +76 -0
- package/dist/transaction/wire/claimEvent.js +73 -0
- package/dist/transaction/wire/claims.d.ts +530 -0
- package/dist/transaction/wire/claims.js +327 -0
- package/dist/{wire → transaction/wire}/commit.d.ts +125 -193
- package/dist/{wire → transaction/wire}/commit.js +68 -47
- package/dist/{wire → transaction/wire}/delta.d.ts +66 -17
- package/dist/{wire → transaction/wire}/delta.js +37 -13
- package/dist/transaction/wire/errorEnvelope.d.ts +72 -0
- package/dist/{wire → transaction/wire}/errorEnvelope.js +36 -5
- package/dist/transaction/wire/feedCursor.d.ts +60 -0
- package/dist/transaction/wire/feedCursor.js +82 -0
- package/dist/transaction/wire/feedEvent.d.ts +204 -0
- package/dist/transaction/wire/feedEvent.js +65 -0
- package/dist/transaction/wire/frames.d.ts +194 -0
- package/dist/transaction/wire/frames.js +50 -0
- package/dist/transaction/wire/inboundFrames.d.ts +562 -0
- package/dist/transaction/wire/inboundFrames.js +116 -0
- package/dist/transaction/wire/index.d.ts +54 -0
- package/dist/transaction/wire/index.js +83 -0
- package/dist/{wire → transaction/wire}/listEnvelope.d.ts +13 -14
- package/dist/transaction/wire/listEnvelope.js +42 -0
- package/dist/transaction/wire/modelMutations.d.ts +31 -0
- package/dist/transaction/wire/modelMutations.js +52 -0
- package/dist/transaction/wire/modelResponses.d.ts +85 -0
- package/dist/transaction/wire/modelResponses.js +43 -0
- package/dist/transaction/wire/modelShape.d.ts +78 -0
- package/dist/transaction/wire/modelShape.js +74 -0
- package/dist/transactions/{TransactionQueue.d.ts → mutations/MutationQueue.d.ts} +85 -38
- package/dist/transactions/{TransactionQueue.js → mutations/MutationQueue.js} +141 -80
- package/dist/transactions/{TransactionStore.d.ts → mutations/MutationStore.d.ts} +8 -8
- package/dist/transactions/{TransactionStore.js → mutations/MutationStore.js} +2 -2
- package/dist/transactions/{coalesceRules.d.ts → mutations/coalesceRules.d.ts} +10 -10
- package/dist/transactions/{coalesceRules.js → mutations/coalesceRules.js} +1 -1
- package/dist/transactions/mutations/commitLatency.d.ts +52 -0
- package/dist/transactions/mutations/commitLatency.js +130 -0
- package/dist/transactions/{commitOutboxStore.d.ts → mutations/commitOutboxStore.d.ts} +1 -5
- package/dist/transactions/{commitOutboxStore.js → mutations/commitOutboxStore.js} +1 -1
- package/dist/transactions/{commitPayload.d.ts → mutations/commitPayload.d.ts} +18 -16
- package/dist/transactions/{commitPayload.js → mutations/commitPayload.js} +15 -15
- package/dist/transactions/{deltaConfirmation.d.ts → mutations/deltaConfirmation.d.ts} +15 -11
- package/dist/transactions/{deltaConfirmation.js → mutations/deltaConfirmation.js} +14 -12
- package/dist/transactions/mutations/durableWriteStore.d.ts +14 -0
- package/dist/transactions/mutations/durableWriteStore.js +12 -0
- package/dist/transactions/{optimisticApply.d.ts → mutations/optimisticApply.d.ts} +7 -7
- package/dist/transactions/{replayValidation.d.ts → mutations/replayValidation.d.ts} +4 -3
- package/dist/transactions/{replayValidation.js → mutations/replayValidation.js} +7 -5
- package/dist/utils/mobxSetup.d.ts +1 -1
- package/dist/utils/mobxSetup.js +5 -2
- package/dist/{core → views}/QueryView.d.ts +2 -2
- package/dist/{core → views}/QueryView.js +2 -2
- package/dist/{core → views}/ViewRegistry.d.ts +1 -1
- package/dist/{core/queryUtils.d.ts → views/incrementalView.d.ts} +6 -6
- package/dist/{core/queryUtils.js → views/incrementalView.js} +6 -6
- package/dist/webhooks/events.d.ts +2 -2
- package/dist/wire/index.d.ts +1 -34
- package/dist/wire/index.js +8 -49
- package/docs/agent-messaging.md +3 -3
- package/docs/agents.md +20 -13
- package/docs/api-keys.md +14 -10
- package/docs/api.md +27 -61
- package/docs/audit.md +6 -3
- package/docs/cli.md +41 -13
- package/docs/client-behavior.md +11 -9
- package/docs/concurrency-convention.md +49 -57
- package/docs/coordination.md +283 -121
- package/docs/data-sources.md +7 -5
- package/docs/debugging.md +39 -15
- package/docs/deployment.md +267 -0
- package/docs/examples/agent-human.md +49 -42
- package/docs/examples/ai-sdk-tool.md +69 -44
- package/docs/examples/existing-python-backend.md +8 -6
- package/docs/examples/nextjs.md +129 -47
- package/docs/examples/scoped-agent.md +46 -45
- package/docs/examples/server-agent.md +46 -26
- package/docs/groups.md +87 -30
- package/docs/guarantees.md +41 -12
- package/docs/how-it-works.md +38 -12
- package/docs/idempotency.md +126 -0
- package/docs/identity.md +77 -74
- package/docs/index.md +172 -86
- package/docs/integration-guide.md +31 -19
- package/docs/mcp.md +46 -21
- package/docs/migration.md +95 -18
- package/docs/operating-on-your-database.md +3 -1
- package/docs/projects.md +3 -1
- package/docs/quickstart.md +22 -5
- package/docs/react.md +31 -18
- package/docs/schema-contract.md +5 -3
- package/docs/session-settings.md +108 -0
- package/docs/sessions.md +4 -2
- package/docs/webhooks.md +12 -10
- package/llms.txt +48 -18
- package/package.json +21 -26
- package/dist/agent/Agent.d.ts +0 -366
- package/dist/agent/Agent.js +0 -514
- package/dist/agent/index.d.ts +0 -115
- package/dist/agent/index.js +0 -128
- package/dist/agent/session.d.ts +0 -93
- package/dist/agent/session.js +0 -149
- package/dist/agent/types.d.ts +0 -68
- package/dist/agent/types.js +0 -9
- package/dist/cli.cjs +0 -286329
- package/dist/client/durableWrites.d.ts +0 -21
- package/dist/client/httpClient.d.ts +0 -80
- package/dist/coordination/schema.d.ts +0 -722
- package/dist/coordination/schema.js +0 -578
- package/dist/schema/openapi.d.ts +0 -29
- package/dist/schema/openapi.js +0 -124
- package/dist/testing/fixtures/bootstrap.d.ts +0 -49
- package/dist/testing/fixtures/bootstrap.js +0 -59
- package/dist/testing/fixtures/deltas.d.ts +0 -83
- package/dist/testing/fixtures/deltas.js +0 -136
- package/dist/testing/fixtures/models.d.ts +0 -83
- package/dist/testing/fixtures/models.js +0 -272
- package/dist/testing/helpers/reactWrapper.d.ts +0 -69
- package/dist/testing/helpers/reactWrapper.js +0 -67
- package/dist/testing/helpers/syncEngineHarness.d.ts +0 -54
- package/dist/testing/helpers/syncEngineHarness.js +0 -73
- package/dist/testing/helpers/wait.d.ts +0 -30
- package/dist/testing/helpers/wait.js +0 -49
- package/dist/testing/index.d.ts +0 -23
- package/dist/testing/index.js +0 -33
- package/dist/testing/mocks/FakeDatabase.d.ts +0 -18
- package/dist/testing/mocks/FakeDatabase.js +0 -10
- package/dist/testing/mocks/MockMutationExecutor.d.ts +0 -87
- package/dist/testing/mocks/MockMutationExecutor.js +0 -192
- package/dist/testing/mocks/MockNetworkMonitor.d.ts +0 -20
- package/dist/testing/mocks/MockNetworkMonitor.js +0 -46
- package/dist/testing/mocks/MockSyncContext.d.ts +0 -51
- package/dist/testing/mocks/MockSyncContext.js +0 -71
- package/dist/testing/mocks/MockSyncStore.d.ts +0 -88
- package/dist/testing/mocks/MockSyncStore.js +0 -171
- package/dist/testing/mocks/MockWebSocket.d.ts +0 -71
- package/dist/testing/mocks/MockWebSocket.js +0 -118
- package/dist/transactions/durableWriteStore.js +0 -30
- package/dist/utils/duration.d.ts +0 -25
- package/dist/utils/json.js +0 -88
- package/dist/wire/errorEnvelope.d.ts +0 -55
- package/dist/wire/frames.d.ts +0 -197
- package/dist/wire/frames.js +0 -49
- package/dist/wire/listEnvelope.js +0 -18
- package/docs/interaction-model.md +0 -97
- /package/dist/{core → query}/QueryProcessor.d.ts +0 -0
- /package/dist/{core → query}/QueryProcessor.js +0 -0
- /package/dist/{core/storeContract.js → storeContract.js} +0 -0
- /package/dist/{core → stores}/openIDBWithTimeout.d.ts +0 -0
- /package/dist/{core → stores}/openIDBWithTimeout.js +0 -0
- /package/dist/{client → transaction/auth}/credentialEndpoint.d.ts +0 -0
- /package/dist/{client → transaction/auth}/credentialEndpoint.js +0 -0
- /package/dist/{auth → transaction/auth}/credentialPolicy.d.ts +0 -0
- /package/dist/{auth → transaction/auth}/credentialPolicy.js +0 -0
- /package/dist/{auth → transaction/auth}/credentialSource.js +0 -0
- /package/dist/{client → transaction/auth}/hostedEndpoints.d.ts +0 -0
- /package/dist/{client → transaction/auth}/hostedEndpoints.js +0 -0
- /package/dist/{client → transaction}/persistence.d.ts +0 -0
- /package/dist/{client → transaction}/persistence.js +0 -0
- /package/dist/{client → transaction/resources}/functionalUpdate.d.ts +0 -0
- /package/dist/{client → transaction/resources}/functionalUpdate.js +0 -0
- /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.d.ts +0 -0
- /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.js +0 -0
- /package/dist/{client → transaction/transport}/httpTransport.d.ts +0 -0
- /package/dist/{types → transaction/types}/modelData.d.ts +0 -0
- /package/dist/{types → transaction/types}/modelData.js +0 -0
- /package/dist/{types → transaction/types}/participant.d.ts +0 -0
- /package/dist/{types → transaction/types}/participant.js +0 -0
- /package/dist/{types → transaction/types}/streams.js +0 -0
- /package/dist/{utils → transaction/utils}/asyncIterator.d.ts +0 -0
- /package/dist/{utils → transaction/utils}/asyncIterator.js +0 -0
- /package/dist/{wire → transaction/wire}/bootstrapReason.d.ts +0 -0
- /package/dist/{wire → transaction/wire}/bootstrapReason.js +0 -0
- /package/dist/{wire → transaction/wire}/protocol.d.ts +0 -0
- /package/dist/{wire → transaction/wire}/protocol.js +0 -0
- /package/dist/{wire → transaction/wire}/protocolVersion.d.ts +0 -0
- /package/dist/{wire → transaction/wire}/protocolVersion.js +0 -0
- /package/dist/transactions/{UnconfirmedWrites.d.ts → mutations/UnconfirmedWrites.d.ts} +0 -0
- /package/dist/transactions/{UnconfirmedWrites.js → mutations/UnconfirmedWrites.js} +0 -0
- /package/dist/transactions/{optimisticApply.js → mutations/optimisticApply.js} +0 -0
- /package/dist/{core → views}/ViewRegistry.js +0 -0
|
@@ -1,87 +1,112 @@
|
|
|
1
1
|
# AI SDK Tool
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Put a claim-and-commit loop inside an AI SDK tool call.
|
|
4
4
|
|
|
5
|
-
|
|
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 {
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
status: schemaZ.enum(['
|
|
18
|
-
|
|
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
|
|
28
|
-
description: 'Update a
|
|
46
|
+
const updateTask = tool({
|
|
47
|
+
description: 'Update a task in the product database.',
|
|
29
48
|
inputSchema: z.object({
|
|
30
|
-
|
|
31
|
-
status: z.enum(['
|
|
32
|
-
|
|
49
|
+
taskId: z.string(),
|
|
50
|
+
status: z.enum(['todo', 'doing', 'done']).optional(),
|
|
51
|
+
summary: z.string().optional(),
|
|
33
52
|
}),
|
|
34
|
-
execute: async ({
|
|
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
|
|
39
|
-
if (!
|
|
40
|
-
|
|
41
|
-
// If another agent
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
await using claim = await ablo.
|
|
45
|
-
id:
|
|
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
|
-
//
|
|
53
|
-
const updated = await ablo.
|
|
54
|
-
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 ??
|
|
57
|
-
|
|
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,
|
|
80
|
+
return { ok: true, task: updated };
|
|
62
81
|
},
|
|
63
82
|
});
|
|
64
83
|
|
|
65
84
|
export async function POST(req: Request) {
|
|
66
|
-
//
|
|
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
|
-
|
|
71
|
-
model
|
|
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: {
|
|
74
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
- reads the latest
|
|
84
|
-
- claims
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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.
|
|
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
|
|
package/docs/examples/nextjs.md
CHANGED
|
@@ -1,80 +1,163 @@
|
|
|
1
1
|
# Next.js Example
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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
|
|
25
|
-
actions.ts
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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/
|
|
119
|
+
// app/tasks/[id]/page.tsx
|
|
35
120
|
import { ablo } from '@/lib/ablo';
|
|
36
121
|
|
|
37
|
-
export default async function
|
|
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
|
|
43
|
-
if (!
|
|
127
|
+
const task = await ablo.tasks.retrieve({ id });
|
|
128
|
+
if (!task) return null;
|
|
44
129
|
|
|
45
|
-
return <
|
|
130
|
+
return <TaskEditor task={task} />;
|
|
46
131
|
}
|
|
47
132
|
```
|
|
48
133
|
|
|
49
134
|
## Server Action Commit
|
|
50
135
|
|
|
51
136
|
```ts
|
|
52
|
-
// app/
|
|
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
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
66
|
-
id
|
|
67
|
-
data: { status: '
|
|
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: '
|
|
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
|
|
76
|
-
|
|
77
|
-
|
|
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
|
|
87
|
-
const data = useAblo((ablo) => ablo.
|
|
88
|
-
const
|
|
89
|
-
const
|
|
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={
|
|
93
|
-
{
|
|
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
|
-
- [
|
|
102
|
-
- [
|
|
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,40 +1,41 @@
|
|
|
1
|
-
# Agent Scoped to One
|
|
1
|
+
# Agent Scoped to One Workspace
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
|
13
16
|
See [Identity & Sync Groups](../identity.md) for the full reference.
|
|
14
17
|
|
|
15
|
-
## 1. Schema
|
|
18
|
+
## 1. Schema: declare the relationship, once
|
|
16
19
|
|
|
17
20
|
```ts
|
|
18
21
|
import { defineSchema, identityRole, model, relation, z } from '@abloatai/ablo/schema';
|
|
19
22
|
|
|
20
23
|
export const schema = defineSchema(
|
|
21
24
|
{
|
|
22
|
-
// A
|
|
23
|
-
|
|
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
|
|
29
|
-
// `parent` edge, so a
|
|
30
|
-
|
|
31
|
-
{
|
|
32
|
-
{
|
|
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
|
-
//
|
|
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
|
|
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
|
|
50
|
-
against **just that
|
|
51
|
-
kind and id** with the typed `syncGroup` helper — `syncGroup('
|
|
52
|
-
never a hand-assembled `
|
|
53
|
-
by the `
|
|
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
|
|
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
|
|
67
|
+
export async function mintProjectAgentSession(workspaceId: string, agentId: string) {
|
|
67
68
|
const { token } = await server.sessions.create({
|
|
68
69
|
agent: { id: agentId },
|
|
69
|
-
can: {
|
|
70
|
-
syncGroups: [syncGroup('
|
|
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 () =>
|
|
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
|
-
|
|
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
|
|
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 `
|
|
101
|
+
and write. The connection is already narrowed to `workspace:<workspaceId>` from Step 2.
|
|
101
102
|
|
|
102
103
|
```ts
|
|
103
|
-
const ablo = useAblo
|
|
104
|
+
const ablo = useAblo();
|
|
104
105
|
|
|
105
|
-
// Other participants subscribed to
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
await ablo.
|
|
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
|
|
112
|
-
|
|
112
|
+
The task's delta is stamped `workspace:<workspaceId>`, derived server-side from the
|
|
113
|
+
task → workspace `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
|
|
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
|
|
121
|
+
- [Agent + Human](./agent-human.md) — yielding when someone else edits the same row.
|