@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.
- package/AGENTS.md +4 -1
- package/CHANGELOG.md +684 -5
- package/README.md +39 -22
- package/dist/BaseSyncedStore.d.ts +152 -44
- package/dist/BaseSyncedStore.js +300 -184
- package/dist/Database.d.ts +9 -24
- package/dist/Database.js +37 -22
- package/dist/InstanceCache.d.ts +25 -4
- package/dist/InstanceCache.js +48 -15
- package/dist/LazyReferenceCollection.d.ts +3 -3
- package/dist/LazyReferenceCollection.js +4 -4
- package/dist/Model.d.ts +6 -6
- package/dist/Model.js +10 -10
- package/dist/ModelRegistry.d.ts +4 -4
- package/dist/ModelRegistry.js +3 -3
- package/dist/{SyncEngineContext.d.ts → RuntimeContext.d.ts} +20 -13
- package/dist/{SyncEngineContext.js → RuntimeContext.js} +11 -12
- package/dist/SyncClient.d.ts +42 -32
- package/dist/SyncClient.js +166 -110
- 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/cli.cjs +3459 -1126
- package/dist/client/Ablo.d.ts +42 -287
- package/dist/client/Ablo.js +118 -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 +4 -4
- package/dist/client/createInternalComponents.js +9 -8
- package/dist/client/createModelProxy.d.ts +78 -373
- package/dist/client/createModelProxy.js +114 -86
- package/dist/client/humans.d.ts +48 -0
- package/dist/client/humans.js +52 -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 +48 -0
- package/dist/client/reactiveEngine.js +910 -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/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 +9 -9
- package/dist/context.js +10 -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/DatabaseManager.js +1 -1
- package/dist/core/QueryView.d.ts +1 -1
- package/dist/core/QueryView.js +1 -1
- package/dist/core/StoreManager.d.ts +4 -23
- package/dist/core/StoreManager.js +5 -55
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +2 -2
- package/dist/core/storeContract.d.ts +2 -2
- package/dist/docs/catalog.d.ts +72 -0
- package/dist/docs/catalog.js +227 -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 +40 -34
- package/dist/index.js +26 -20
- 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 +2 -2
- package/dist/query/client.js +4 -4
- package/dist/query/types.d.ts +6 -41
- package/dist/query/types.js +2 -2
- package/dist/react/AbloProvider.d.ts +6 -8
- package/dist/react/AbloProvider.js +5 -7
- package/dist/react/context.d.ts +1 -1
- package/dist/react/context.js +1 -1
- package/dist/react/index.d.ts +5 -5
- package/dist/react/index.js +3 -3
- package/dist/react/internalContext.d.ts +1 -1
- package/dist/react/useAblo.d.ts +3 -3
- package/dist/react/useAblo.js +1 -1
- 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 +86 -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 +10 -10
- package/dist/schema/index.js +18 -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 +3 -3
- package/dist/schema/serialize.d.ts +15 -6
- package/dist/schema/serialize.js +17 -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/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/footprint.d.ts +111 -0
- package/dist/source/footprint.js +0 -0
- 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/stores/ObjectStore.d.ts +1 -1
- package/dist/stores/SyncActionStore.d.ts +1 -1
- package/dist/stores/SyncActionStore.js +2 -10
- 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 +123 -6
- package/dist/sync/BootstrapFetcher.js +492 -66
- package/dist/sync/ConnectionManager.d.ts +6 -198
- package/dist/sync/ConnectionManager.js +6 -677
- package/dist/sync/OnDemandLoader.d.ts +2 -2
- package/dist/sync/OnDemandLoader.js +60 -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/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 +1 -1
- package/dist/sync/participants.d.ts +5 -4
- package/dist/sync/participants.js +29 -22
- package/dist/sync/schemaDrift.d.ts +55 -0
- package/dist/sync/schemaDrift.js +53 -0
- package/dist/sync/schemas.d.ts +21 -32
- package/dist/sync/schemas.js +26 -17
- 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/testing/fixtures/bootstrap.d.ts +1 -1
- package/dist/testing/fixtures/deltas.d.ts +1 -1
- package/dist/testing/fixtures/httpResponses.d.ts +70 -0
- package/dist/testing/fixtures/httpResponses.js +90 -0
- package/dist/testing/fixtures/models.js +1 -1
- package/dist/testing/helpers/wait.js +1 -1
- package/dist/testing/mocks/MockMutationExecutor.d.ts +2 -2
- package/dist/testing/mocks/MockMutationExecutor.js +8 -14
- package/dist/testing/mocks/MockSyncContext.d.ts +11 -11
- package/dist/testing/mocks/MockSyncContext.js +10 -9
- package/dist/testing/mocks/MockSyncStore.js +1 -1
- package/dist/testing/mocks/MockWebSocket.d.ts +2 -2
- 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 +177 -0
- package/dist/transaction/auth/capability.js +199 -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 +49 -0
- package/dist/transaction/coordination/awaitClaimGrant.js +112 -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 +44 -0
- package/dist/transaction/coordination/locator.d.ts +83 -0
- package/dist/transaction/coordination/locator.js +82 -0
- package/dist/transaction/coordination/schema.d.ts +1473 -0
- package/dist/{coordination → transaction/coordination}/schema.js +490 -55
- package/dist/transaction/coordination/targetConflict.d.ts +2 -0
- package/dist/transaction/coordination/targetConflict.js +103 -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} +11 -11
- package/dist/{errorCodes.js → transaction/errorCodes.js} +35 -12
- package/dist/{errors.d.ts → transaction/errors.d.ts} +37 -13
- package/dist/{errors.js → transaction/errors.js} +85 -16
- 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 +192 -0
- package/dist/transaction/plugin.js +87 -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 +266 -0
- package/dist/transaction/resources/httpResources.js +7 -0
- package/dist/transaction/resources/modelOperations.d.ts +319 -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 +85 -0
- package/dist/transaction/resources/where.js +70 -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 +5 -5
- package/dist/{schema → transaction/schema}/field.js +5 -5
- 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 +57 -0
- package/dist/transaction/schema/openapi.js +340 -0
- package/dist/{schema → transaction/schema}/relation.d.ts +14 -14
- 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 +12 -10
- package/dist/{schema → transaction/schema}/schema.js +4 -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 +4 -5
- 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} +10 -36
- 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/{client → transaction/transport}/httpClient.d.ts +59 -16
- package/dist/{client → transaction/transport}/httpClient.js +5 -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 +171 -85
- 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 +576 -0
- package/dist/transaction/transport/wsTransport.js +1017 -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 +63 -45
- 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 +351 -0
- package/dist/transaction/wire/accountResponses.js +255 -0
- package/dist/transaction/wire/auth.d.ts +49 -0
- package/dist/transaction/wire/auth.js +57 -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 +463 -0
- package/dist/transaction/wire/claims.js +229 -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 +177 -0
- package/dist/transaction/wire/feedEvent.js +39 -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 +552 -0
- package/dist/transaction/wire/inboundFrames.js +116 -0
- package/dist/transaction/wire/index.d.ts +50 -0
- package/dist/transaction/wire/index.js +74 -0
- package/dist/{wire → transaction/wire}/listEnvelope.d.ts +13 -14
- package/dist/transaction/wire/listEnvelope.js +42 -0
- package/dist/transaction/wire/modelResponses.d.ts +85 -0
- package/dist/transaction/wire/modelResponses.js +43 -0
- package/dist/transactions/{TransactionQueue.d.ts → mutations/MutationQueue.d.ts} +79 -38
- package/dist/transactions/{TransactionQueue.js → mutations/MutationQueue.js} +110 -59
- 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} +16 -15
- package/dist/transactions/{commitPayload.js → mutations/commitPayload.js} +12 -12
- package/dist/transactions/{deltaConfirmation.d.ts → mutations/deltaConfirmation.d.ts} +11 -11
- package/dist/transactions/{deltaConfirmation.js → mutations/deltaConfirmation.js} +7 -7
- 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} +3 -3
- package/dist/transactions/{replayValidation.js → mutations/replayValidation.js} +4 -3
- package/dist/utils/mobxSetup.d.ts +1 -1
- package/dist/utils/mobxSetup.js +5 -2
- 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 +19 -12
- package/docs/api-keys.md +8 -4
- package/docs/api.md +22 -18
- package/docs/audit.md +2 -0
- package/docs/cli.md +31 -3
- package/docs/client-behavior.md +8 -6
- package/docs/concurrency-convention.md +30 -24
- package/docs/coordination.md +48 -38
- package/docs/data-sources.md +3 -1
- package/docs/debugging.md +5 -3
- 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 +45 -44
- package/docs/examples/server-agent.md +46 -26
- package/docs/groups.md +32 -29
- package/docs/guarantees.md +4 -2
- package/docs/how-it-works.md +9 -7
- package/docs/idempotency.md +126 -0
- package/docs/identity.md +58 -54
- package/docs/index.md +172 -84
- package/docs/integration-guide.md +17 -16
- package/docs/interaction-model.md +6 -4
- package/docs/mcp.md +41 -16
- package/docs/migration.md +63 -5
- package/docs/operating-on-your-database.md +111 -0
- package/docs/projects.md +2 -0
- package/docs/quickstart.md +22 -5
- package/docs/react.md +12 -10
- package/docs/schema-contract.md +5 -3
- package/docs/session-settings.md +108 -0
- package/docs/sessions.md +3 -1
- package/docs/webhooks.md +3 -1
- package/llms.txt +47 -17
- package/package.json +10 -8
- 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/client/durableWrites.d.ts +0 -21
- package/dist/coordination/schema.d.ts +0 -722
- package/dist/schema/openapi.d.ts +0 -29
- package/dist/schema/openapi.js +0 -124
- package/dist/transactions/durableWriteStore.js +0 -30
- 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/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/coordination}/claimHeartbeatLoop.d.ts +0 -0
- /package/dist/{client → transaction/coordination}/claimHeartbeatLoop.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/{utils → transaction/utils}/duration.d.ts +0 -0
- /package/dist/{utils → transaction/utils}/duration.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/docs/identity.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Identity & Sync Groups
|
|
2
2
|
|
|
3
|
+
> Who is connecting, and which slice of state they are allowed to see.
|
|
4
|
+
|
|
3
5
|
This is the doc the Quickstart skips: **who is connecting, and which slice
|
|
4
6
|
of shared state do they get?** If you've wired `<AbloProvider client={ablo}>`
|
|
5
7
|
and wondered where org / team / user actually come from — start here.
|
|
@@ -20,7 +22,7 @@ that.
|
|
|
20
22
|
## What a sync group is
|
|
21
23
|
|
|
22
24
|
A **sync group** is a named channel of shared state — a string like
|
|
23
|
-
`org:acme` or `
|
|
25
|
+
`org:acme` or `workspace:abc123`. It is simultaneously:
|
|
24
26
|
|
|
25
27
|
- **the unit of fan-out** — a confirmed write to a row publishes a delta to
|
|
26
28
|
every participant subscribed to that row's sync group(s), and
|
|
@@ -38,7 +40,7 @@ runnable place, so the concepts below have code to attach to.
|
|
|
38
40
|
The entire declaration surface is: `identityRoles` (who may see what), and on
|
|
39
41
|
each model `scope` / `parent` / `grants` (which group a row fans out on), plus
|
|
40
42
|
optional `syncGroups` at session-mint time (narrowing). Read the three blocks first —
|
|
41
|
-
a human gets their `org` / `team` scope, an agent gets one `
|
|
43
|
+
a human gets their `org` / `team` scope, an agent gets one `workspace` — then the
|
|
42
44
|
sections after explain each.
|
|
43
45
|
|
|
44
46
|
```ts
|
|
@@ -47,20 +49,18 @@ import { defineSchema, identityRole, relation, model, z } from '@abloatai/ablo/s
|
|
|
47
49
|
|
|
48
50
|
export const schema = defineSchema(
|
|
49
51
|
{
|
|
50
|
-
// A scope root: its rows form the group `
|
|
52
|
+
// A scope root: its rows form the group `workspace:<id>` (kind from `groups.root`).
|
|
51
53
|
// Tenant isolation defaults to a row-local `organization_id` column, so no
|
|
52
54
|
// `policy` is needed here.
|
|
53
|
-
|
|
55
|
+
workspaces: model(
|
|
54
56
|
{ title: z.string(), status: z.enum(['draft', 'published']) },
|
|
55
|
-
{},
|
|
56
|
-
{ groups: { root: 'deck' } },
|
|
57
|
+
{ groups: { root: 'workspace' } },
|
|
57
58
|
),
|
|
58
|
-
// A child: it has no group of its own; it inherits its
|
|
59
|
-
// `parent` edge. A write to a
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
{
|
|
63
|
-
{},
|
|
59
|
+
// A child: it has no group of its own; it inherits its workspace's group via the
|
|
60
|
+
// `parent` edge. A write to a document reaches everyone viewing the workspace.
|
|
61
|
+
documents: model(
|
|
62
|
+
{ workspaceId: z.string() },
|
|
63
|
+
{ relations: { workspace: relation.belongsTo('workspaces', 'workspaceId', { parent: true }) } },
|
|
64
64
|
),
|
|
65
65
|
},
|
|
66
66
|
{
|
|
@@ -88,12 +88,12 @@ export const schema = defineSchema(
|
|
|
88
88
|
// 3. an AGENT run inherits its user, narrowed to the entities in play.
|
|
89
89
|
// You narrow at SESSION-MINT time: your backend calls `sessions.create` with the
|
|
90
90
|
// agent's allowed `syncGroups`, built from each model's scope via the
|
|
91
|
-
// `syncGroup(kind, id)` helper — never a hand-built `
|
|
91
|
+
// `syncGroup(kind, id)` helper — never a hand-built `workspace:<id>` string. The agent's
|
|
92
92
|
// runtime then connects with the minted token.
|
|
93
93
|
const session = await server.sessions.create({
|
|
94
94
|
agent: { id: agentId },
|
|
95
|
-
can: {
|
|
96
|
-
syncGroups: [syncGroup('
|
|
95
|
+
can: { Workspace: ['read', 'update'] },
|
|
96
|
+
syncGroups: [syncGroup('workspace', workspaceId)], // floor: just the workspace it's working on
|
|
97
97
|
});
|
|
98
98
|
// the agent runtime authenticates with the minted token
|
|
99
99
|
const ablo = Ablo({ schema, apiKey: session.token });
|
|
@@ -103,27 +103,27 @@ That's the whole surface. The rest of this doc is the *why* behind each line.
|
|
|
103
103
|
|
|
104
104
|
## Two kinds of group — the whole mental model
|
|
105
105
|
|
|
106
|
-
You just saw a human get `org` / `team` groups and an agent get one `
|
|
106
|
+
You just saw a human get `org` / `team` groups and an agent get one `workspace`
|
|
107
107
|
group. That split is the model. Every sync group is named after one of two
|
|
108
108
|
things:
|
|
109
109
|
|
|
110
110
|
- **Membership groups** — named after *who you are*: `org:{id}`, `team:{id}`,
|
|
111
111
|
`user:{id}`. Produced from **identity** (`identityRoles`, Half 1). They're
|
|
112
112
|
standing and durable — they don't change as you work.
|
|
113
|
-
- **Entity groups** — named after *a thing*: `dataroom:{id}`, `
|
|
114
|
-
`
|
|
113
|
+
- **Entity groups** — named after *a thing*: `dataroom:{id}`, `workspace:{id}`,
|
|
114
|
+
`document:{id}`. Produced from a **row's id** (a model's entity scope, Half 2).
|
|
115
115
|
They're granular — one per record — and any participant can be pointed at a
|
|
116
116
|
specific set of them.
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
different places.
|
|
120
|
-
|
|
121
|
-
so you
|
|
118
|
+
Agents and people fill that same space differently, and you declare the two in
|
|
119
|
+
different places. An agent's groups come from what it's working on right now, so
|
|
120
|
+
you pass them in code when you start the run. A person's groups come from who
|
|
121
|
+
they are, so you declare them once in the schema.
|
|
122
122
|
|
|
123
123
|
| | Subscribed by | Declared where | Gets |
|
|
124
124
|
| --- | --- | --- | --- |
|
|
125
125
|
| **Human** | *who they are* — membership | **the schema** (`identityRoles`) — a rule, written once | every `org` / `team` / `user` group their identity implies — their whole standing world |
|
|
126
|
-
| **Agent** | *what it's been given* — entities | **code, at the spawn site** — chosen per run | a handful of entity groups: the dataroom it's in, the
|
|
126
|
+
| **Agent** | *what it's been given* — entities | **code, at the spawn site** — chosen per run | a handful of entity groups: the dataroom it's in, the documents it has read — never beyond what its user's membership could reach |
|
|
127
127
|
|
|
128
128
|
> **One line:** humans subscribe by who they are; agents subscribe by what
|
|
129
129
|
> they've been given.
|
|
@@ -135,9 +135,9 @@ depends on *what it's working on*, which is only knowable at dispatch — so you
|
|
|
135
135
|
pass its `syncGroups` **when your backend mints the agent session**
|
|
136
136
|
(`sessions.create({ agent, can, syncGroups })`). The schema's
|
|
137
137
|
only job for entities is to declare *that* a model is
|
|
138
|
-
entity-scopable and *what its group is named* (`scope: '
|
|
138
|
+
entity-scopable and *what its group is named* (`scope: 'workspace'` → `workspace:{id}`);
|
|
139
139
|
it never declares *which* entities a given agent gets. (A human can opt into the
|
|
140
|
-
same runtime narrowing — a page scoped to one
|
|
140
|
+
same runtime narrowing — a page scoped to one workspace — but by default a human's
|
|
141
141
|
scope is fully schema-derived.)
|
|
142
142
|
|
|
143
143
|
So an agent doesn't need a `user:{id}` standing grant. It's a participant pointed
|
|
@@ -212,7 +212,7 @@ import { defineSchema, identityRole, model, z } from '@abloatai/ablo/schema';
|
|
|
212
212
|
|
|
213
213
|
export const schema = defineSchema(
|
|
214
214
|
{
|
|
215
|
-
|
|
215
|
+
workspaces: model({
|
|
216
216
|
title: z.string(),
|
|
217
217
|
status: z.enum(['draft', 'published']),
|
|
218
218
|
}),
|
|
@@ -247,28 +247,30 @@ declarations, in order of how often you reach for them:
|
|
|
247
247
|
**`groups.root` — this model is a scope root.** Its rows form a group of their
|
|
248
248
|
own. The kind comes from the model's `typename` by default, or pass a string to
|
|
249
249
|
set it explicitly (use the string form when the wire kind differs from the
|
|
250
|
-
typename, e.g. typename `SlideDeck` but group `
|
|
250
|
+
typename, e.g. typename `SlideDeck` but group `workspace:<id>`):
|
|
251
251
|
|
|
252
252
|
```ts
|
|
253
|
-
|
|
254
|
-
// a
|
|
253
|
+
workspaces: model({ title: z.string() }, { groups: { root: 'workspace' } });
|
|
254
|
+
// a workspace row → group `workspace:<id>`
|
|
255
255
|
```
|
|
256
256
|
|
|
257
257
|
**`parent` — this row lives inside another entity.** Mark the `belongsTo` edge
|
|
258
258
|
to its owner; the row inherits that owner's group. This is the Zanzibar/ReBAC
|
|
259
259
|
*parent* relation — "access inherits from parent" — and it chains transitively
|
|
260
|
-
(a
|
|
260
|
+
(a block → its document → its workspace), so a write to any descendant reaches everyone
|
|
261
261
|
viewing the root. A *reference* (a provenance/template pointer, not ownership)
|
|
262
262
|
must **not** be marked `parent`, or the row would leak into an unrelated scope:
|
|
263
263
|
|
|
264
264
|
```ts
|
|
265
|
-
|
|
266
|
-
{
|
|
265
|
+
documents: model(
|
|
266
|
+
{ workspaceId: z.string(), sourceSlideId: z.string().optional() },
|
|
267
267
|
{
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
// default policy: row-local organization_id
|
|
269
|
+
relations: {
|
|
270
|
+
workspace: relation.belongsTo('workspaces', 'workspaceId', { parent: true }), // ownership → inherit workspace:<id>
|
|
271
|
+
sourceSlide: relation.belongsTo('documents', 'sourceSlideId'), // reference → NOT routed
|
|
272
|
+
},
|
|
270
273
|
},
|
|
271
|
-
{}, // default policy: row-local organization_id
|
|
272
274
|
);
|
|
273
275
|
```
|
|
274
276
|
|
|
@@ -288,10 +290,12 @@ org membership is already covered by the `org:` identity role.
|
|
|
288
290
|
dataroomMember: model(
|
|
289
291
|
{ userId: z.string(), dataroomId: z.string() },
|
|
290
292
|
{
|
|
291
|
-
|
|
292
|
-
|
|
293
|
+
relations: {
|
|
294
|
+
member: relation.belongsTo('users', 'userId'),
|
|
295
|
+
room: relation.belongsTo('datarooms', 'dataroomId'),
|
|
296
|
+
},
|
|
297
|
+
groups: { grants: { subject: 'member', scope: 'room' } },
|
|
293
298
|
},
|
|
294
|
-
{ groups: { grants: { subject: 'member', scope: 'room' } } },
|
|
295
299
|
);
|
|
296
300
|
```
|
|
297
301
|
|
|
@@ -398,7 +402,7 @@ What carries identity — and just as importantly, what does *not* set the bound
|
|
|
398
402
|
| ------------ | ------------------------------------------------------------------------------------------------ |
|
|
399
403
|
| `userId` prop | App-level participant id, used for app-owned fields and read by your `identityRole` `source`. **Not** the security boundary — the server enforces scope from the authenticated request. |
|
|
400
404
|
| `teamIds` (on the client) | Team ids expanded into team sync groups via your `identityRoles`. |
|
|
401
|
-
| `syncGroups` (at session mint) | Optional. **Narrows** a minted session's subscription to a subset of what auth already allows — it can never widen it. Passed to `sessions.create({ user \| agent, syncGroups })`; build entries with `syncGroup(kind, id)`. Use it to scope an agent (or a focused page's session) to one entity, e.g. `[syncGroup('
|
|
405
|
+
| `syncGroups` (at session mint) | Optional. **Narrows** a minted session's subscription to a subset of what auth already allows — it can never widen it. Passed to `sessions.create({ user \| agent, syncGroups })`; build entries with `syncGroup(kind, id)`. Use it to scope an agent (or a focused page's session) to one entity, e.g. `[syncGroup('workspace', 'abc123')]`. |
|
|
402
406
|
|
|
403
407
|
Because the server is the boundary, a client that changes `userId` to another
|
|
404
408
|
user's id does not gain their data — the server resolves and enforces the real
|
|
@@ -433,21 +437,21 @@ an entity anchor on the models an agent operates on:
|
|
|
433
437
|
|
|
434
438
|
```ts
|
|
435
439
|
// each scope-root model an agent edits forms a per-entity group
|
|
436
|
-
documents: model({ /* … */ }, {
|
|
437
|
-
|
|
440
|
+
documents: model({ /* … */ }, { groups: { root: 'document' } }),
|
|
441
|
+
workspaces: model({ /* … */ }, { groups: { root: 'workspace' } }),
|
|
438
442
|
```
|
|
439
443
|
|
|
440
444
|
Then a run subscribes only to the entity groups for the rows it works on — a
|
|
441
445
|
subset of what its user could see:
|
|
442
446
|
|
|
443
447
|
```ts
|
|
444
|
-
// agent run triggered by `user`, working on one document + one
|
|
448
|
+
// agent run triggered by `user`, working on one document + one workspace.
|
|
445
449
|
// Your backend mints the agent session narrowed to just the entities in play
|
|
446
450
|
// (the floor). Build each group from the model's scope with `syncGroup(kind, id)`.
|
|
447
451
|
const session = await server.sessions.create({
|
|
448
452
|
agent: { id: agentId },
|
|
449
|
-
can: { Document: ['read', 'update'],
|
|
450
|
-
syncGroups: [syncGroup('document', documentId), syncGroup('
|
|
453
|
+
can: { Document: ['read', 'update'], Workspace: ['read', 'update'] },
|
|
454
|
+
syncGroups: [syncGroup('document', documentId), syncGroup('workspace', workspaceId)],
|
|
451
455
|
});
|
|
452
456
|
// identity (the ceiling) is inherited from the triggering user via your
|
|
453
457
|
// session-mint logic; the agent runtime connects with the minted token.
|
|
@@ -491,9 +495,9 @@ it claimed.
|
|
|
491
495
|
## Narrowing to specific entities
|
|
492
496
|
|
|
493
497
|
A human gets their full membership automatically (`identityRoles`). There are
|
|
494
|
-
three ways to narrow a participant to specific entities — a page on one
|
|
498
|
+
three ways to narrow a participant to specific entities — a page on one workspace, or
|
|
495
499
|
an agent pointed at the entities it's working on. You **never hand-write**
|
|
496
|
-
`
|
|
500
|
+
`workspace:<id>`; build groups from the model's `scope` (Half 2) with the typed
|
|
497
501
|
`syncGroup(kind, id)` helper from `@abloatai/ablo/schema`.
|
|
498
502
|
|
|
499
503
|
1. **At session mint — `syncGroups`.** When your backend mints a session, pass the
|
|
@@ -501,13 +505,13 @@ an agent pointed at the entities it's working on. You **never hand-write**
|
|
|
501
505
|
the way to scope a focused page's session):
|
|
502
506
|
|
|
503
507
|
```ts
|
|
504
|
-
// an agent working across two
|
|
508
|
+
// an agent working across two workspaces and a document
|
|
505
509
|
const session = await server.sessions.create({
|
|
506
510
|
agent: { id: agentId },
|
|
507
|
-
can: {
|
|
511
|
+
can: { Workspace: ['read', 'update'], Document: ['read'] },
|
|
508
512
|
syncGroups: [
|
|
509
|
-
syncGroup('
|
|
510
|
-
syncGroup('
|
|
513
|
+
syncGroup('workspace', deckA),
|
|
514
|
+
syncGroup('workspace', deckB),
|
|
511
515
|
syncGroup('document', docId),
|
|
512
516
|
],
|
|
513
517
|
});
|
|
@@ -525,9 +529,9 @@ an agent pointed at the entities it's working on. You **never hand-write**
|
|
|
525
529
|
[Coordination](./coordination.md).
|
|
526
530
|
|
|
527
531
|
> **`groups.root` is the schema model option, not a client setting.**
|
|
528
|
-
> `groups: { root: '
|
|
532
|
+
> `groups: { root: 'workspace' }` in `model(...)` declares a scope root
|
|
529
533
|
> ([Half 2](#half-2--per-model-scope-row--group)) — it names the group
|
|
530
|
-
> (`
|
|
534
|
+
> (`workspace:<id>`) that the mechanisms above then subscribe to.
|
|
531
535
|
> There is no `Ablo({ scope })` constructor option. The lifecycle filter on
|
|
532
536
|
> [`list()`](./api.md#model-methods) is a separate axis named **`state`**
|
|
533
537
|
> (`'live' | 'archived' | 'all'`, GitHub's open/closed/all), precisely so it
|
|
@@ -536,7 +540,7 @@ an agent pointed at the entities it's working on. You **never hand-write**
|
|
|
536
540
|
> **Requested groups never grant.** At connect, the server intersects the session's
|
|
537
541
|
> `syncGroups` with what the identity is actually allowed (`requested ∩ allowed`).
|
|
538
542
|
> So `syncGroups` only ever *narrows* within a participant's ceiling — an agent
|
|
539
|
-
> can't reach a
|
|
543
|
+
> can't reach a workspace its capability doesn't already permit, no matter what it
|
|
540
544
|
> passes. Smaller bootstrap, less fan-out, same server-enforced boundary.
|
|
541
545
|
|
|
542
546
|
## How this compares — and the best practices it follows
|
|
@@ -583,7 +587,7 @@ The best practices Ablo inherits from that lineage:
|
|
|
583
587
|
never the boundary. This is why changing `userId` in the browser grants nothing.
|
|
584
588
|
|
|
585
589
|
3. **Scope by a hierarchical naming convention, declared once.** Ablo's `kind:id`
|
|
586
|
-
group naming (`org:…` / `team:…` from `identityRoles`, `
|
|
590
|
+
group naming (`org:…` / `team:…` from `identityRoles`, `workspace:…` from a model's
|
|
587
591
|
`scope`) is the same idea as [Liveblocks' recommended room-id naming pattern](https://liveblocks.io/docs/authentication/access-token)
|
|
588
592
|
(`org:*`, `org:group:*`) and [Ably's channel capabilities](https://ably.com/docs/auth/capabilities).
|
|
589
593
|
Declaring the convention in one place — never composing scope strings in
|
package/docs/index.md
CHANGED
|
@@ -1,101 +1,189 @@
|
|
|
1
1
|
# Ablo Docs
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
users are editing — without the two clobbering each other's work. Ablo gives
|
|
5
|
-
the agent a narrow, audited write path: you declare your models, then everyone
|
|
6
|
-
(React components, server actions, and agents) calls the same
|
|
7
|
-
`ablo.deck.update(...)`. Ablo streams confirmed changes to everyone live and
|
|
8
|
-
rejects any write based on stale data.
|
|
3
|
+
> The agentic coordination layer: one API for AI agents, apps, and services to claim, change, and confirm the same rows.
|
|
9
4
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
Two agents reach for the same row. One claims it, does slow work — an LLM call,
|
|
6
|
+
a fetch, a chain of tools — and commits. The second is neither rejected nor
|
|
7
|
+
allowed to clobber: it waits in line, is handed the row as it now stands, and
|
|
8
|
+
proceeds. Contention becomes an ordering problem instead of a retry loop.
|
|
13
9
|
|
|
14
10
|
```ts
|
|
15
|
-
//
|
|
16
|
-
await ablo.
|
|
11
|
+
// Take the row. Anyone else who wants it waits, then reads it fresh.
|
|
12
|
+
await using claim = await ablo.reports.claim({ id: reportId });
|
|
13
|
+
|
|
14
|
+
await ablo.reports.update({
|
|
15
|
+
id: claim.data.id,
|
|
16
|
+
data: { forecast: await generateForecast(claim.data) },
|
|
17
|
+
wait: 'confirmed',
|
|
18
|
+
});
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
Claims
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## What you get
|
|
24
|
-
|
|
25
|
-
Three things stay true no matter how you use Ablo:
|
|
26
|
-
|
|
27
|
-
- **One model API for every actor.** `ablo.<model>.update(...)` is the
|
|
28
|
-
call from React components, server actions, background workers, and
|
|
29
|
-
AI agents alike. No separate "agent SDK," no parallel mutation path.
|
|
30
|
-
Attribution comes from the credential, not the call site.
|
|
31
|
-
- **You declare tenancy scopes once.** Tenancy / per-entity scope
|
|
32
|
-
prefixes (`org:`, `deck:`, or your own `region:` / `customer:`) are
|
|
33
|
-
declared once on the schema's `identityRoles`, so application code
|
|
34
|
-
never builds an `org:123` string by hand — which keeps tenant
|
|
35
|
-
boundaries from leaking.
|
|
36
|
-
- **Stale writes are rejected.** If the row changed after you read it,
|
|
37
|
-
your write is turned away instead of silently overwriting the change
|
|
38
|
-
you didn't see.
|
|
39
|
-
|
|
40
|
-
## Start here
|
|
41
|
-
|
|
42
|
-
- [Quickstart](./quickstart.md) — Make your first schema-backed write.
|
|
43
|
-
- [Schema Contract](./schema-contract.md) — One schema becomes typed model clients, React reads, agent writes, Data Source shape, and schema push.
|
|
44
|
-
- [CLI & Migrations](./cli.md) — `init` / `migrate` / `push` / `generate`, the shared Zod→Postgres type map, and structured migration errors.
|
|
45
|
-
- [Identity & Sync Groups](./identity.md) — Use your own authentication; tell Ablo who's connecting and how org / team / user map to sync-group scope.
|
|
46
|
-
- [Integration Guide](./integration-guide.md) — Connect your database via Data Source, plus React, multiplayer, and agent patterns.
|
|
47
|
-
- [Guarantees](./guarantees.md) — What confirmed writes, stale checks, and claims guarantee.
|
|
48
|
-
- [Interaction Model](./interaction-model.md) — The schema, claim, update, confirmation loop.
|
|
49
|
-
- [API Reference](./api.md) — Model-by-model method shape.
|
|
50
|
-
- [Client Behavior](./client-behavior.md) — Options, errors, retries, timeouts, and imports.
|
|
51
|
-
- [Debugging & Logs](./debugging.md) — Turn on the `[Ablo]` coordination trace (`debug` / `logLevel`) to watch claims, queueing, and grants while you build — or read the same activity in code via `ClaimLog` to render an activity feed.
|
|
52
|
-
- [Connect Your Database](./data-sources.md) — Keep canonical rows in your app database without giving Ablo database credentials.
|
|
53
|
-
- [React](./react.md) — Provider, hooks, and reactive reads for React apps.
|
|
54
|
-
- [API Keys](./api-keys.md) — Bearer tokens for the public API.
|
|
55
|
-
|
|
56
|
-
## API shape
|
|
57
|
-
|
|
58
|
-
| Plane | Primitives | Purpose |
|
|
59
|
-
|---|---|---|
|
|
60
|
-
| State | `Schema`, `Model`, `Claim`, `Receipt` | The product path. Load, coordinate, write, confirm. |
|
|
61
|
-
| Storage | `Data Source` | Your rows live in your own database behind a signed Data Source endpoint. |
|
|
62
|
-
|
|
63
|
-
## Use cases
|
|
64
|
-
|
|
65
|
-
- **Let agents write to shared state** — Give an AI agent scoped, revocable write access to your typed data.
|
|
66
|
-
- **Coordinate multiple actors** — Use claims to show pre-write work across humans and agents.
|
|
67
|
-
- **Audit every agent action** — Trace any write back to a human in one query.
|
|
68
|
-
- **Build collaborative editors** — Humans and agents on the same record, with realtime updates and stale-read protection.
|
|
69
|
-
- **Meter and gate API usage** — Per-key, per-team usage reports and quota enforcement.
|
|
70
|
-
- **Integrate with A2A and MCP** — Speak the same protocols as Claude, Cursor, Gemini.
|
|
21
|
+
Claims do not lock. A lock is held against a caller who may never come back; a
|
|
22
|
+
claim is a durable lease with a wait-line behind it, so you can always ask who
|
|
23
|
+
holds a row and who is queued for it. The write returns a receipt, and a write
|
|
24
|
+
based on a row that has since changed is turned away rather than applied.
|
|
71
25
|
|
|
72
|
-
##
|
|
26
|
+
## What people build
|
|
73
27
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
- [Audit Log](./audit.md) — Trace any confirmed write back to the human behind it.
|
|
83
|
-
- [MCP](./mcp.md) — Expose Ablo models to MCP clients (Claude, Cursor).
|
|
28
|
+
<Columns>
|
|
29
|
+
<Card title="Run agents in parallel" icon="users" href="/coordination">
|
|
30
|
+
Many agents over one dataset. Claims put them in a line instead of a race.
|
|
31
|
+
</Card>
|
|
32
|
+
|
|
33
|
+
<Card title="Hand work between agents" icon="arrow-left-right" href="/agent-messaging">
|
|
34
|
+
One agent claims, works, releases. The next picks up with the fresh row and a durable note about why.
|
|
35
|
+
</Card>
|
|
84
36
|
|
|
85
|
-
|
|
37
|
+
<Card title="Scope what an agent may write" icon="key-round" href="/api-keys">
|
|
38
|
+
A revocable key bound to one project's models. Attribution comes from the credential, not the call site.
|
|
39
|
+
</Card>
|
|
40
|
+
|
|
41
|
+
<Card title="Confirm what landed" icon="receipt" href="/guarantees">
|
|
42
|
+
Every write returns a receipt. Nothing is fire-and-forget, and stale writes are rejected.
|
|
43
|
+
</Card>
|
|
44
|
+
|
|
45
|
+
<Card title="Audit every agent action" icon="scroll-text" href="/audit">
|
|
46
|
+
Trace any committed change back to the key that made it, and to the person who authorized that key.
|
|
47
|
+
</Card>
|
|
48
|
+
|
|
49
|
+
<Card title="Keep a person in the loop" icon="hand" href="/react">
|
|
50
|
+
Add the `humans()` plugin and people get presence and live queries. A person's claim is just another holder the agent waits behind.
|
|
51
|
+
</Card>
|
|
52
|
+
</Columns>
|
|
53
|
+
|
|
54
|
+
## Using Ablo
|
|
55
|
+
|
|
56
|
+
<Steps>
|
|
57
|
+
<Step title="Declare the models agents share">
|
|
58
|
+
`npx ablo init` scaffolds `ablo/schema.ts`, the typed client, and the type registration.
|
|
59
|
+
Declare only the models agents coordinate over — your auth, billing, and everything else
|
|
60
|
+
stay in your own migrations.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx ablo init && npx ablo push
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`push` is the step everything depends on: the server keeps its own copy of the schema, and
|
|
67
|
+
until it has yours, a write to a new model fails with `server_execute_unknown_model`.
|
|
68
|
+
</Step>
|
|
69
|
+
|
|
70
|
+
<Step title="Connect the database the rows live in">
|
|
71
|
+
Ablo writes through a scoped role and confirms by tailing your write-ahead log. It runs no
|
|
72
|
+
DDL and owns no schema — your migration tool stays in charge of the shape of your database.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npx ablo connect
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
No database yet? Pass an `apiKey` only and Ablo keeps the rows in its own log, so you can
|
|
79
|
+
build the whole system today and point it at Postgres when you are ready.
|
|
80
|
+
</Step>
|
|
81
|
+
|
|
82
|
+
<Step title="Build with Ablo">
|
|
83
|
+
You are writing the agent yourself — a worker, a job handler, a tool inside a model loop.
|
|
84
|
+
Agents hold no socket; the credential is the identity.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const ablo = Ablo({ schema, apiKey: process.env.ABLO_API_KEY, transport: 'http' });
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Read with `list` / `retrieve`, coordinate with `claim`, write with `create` / `update` /
|
|
91
|
+
`delete`. See [Agents](./agents.md) for the loop and [API Reference](./api.md) for the shape.
|
|
92
|
+
</Step>
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
- [Server Agent](./examples/server-agent.md) — Schema-backed worker.
|
|
91
|
-
- [Next.js](./examples/nextjs.md) — App-router setup with React bindings.
|
|
94
|
+
<Step title="Or point an MCP host at it">
|
|
95
|
+
The agent is Claude, Cursor, or another MCP host, and you want it operating your data
|
|
96
|
+
directly. The coordination server exposes the same claim-and-commit loop as tools.
|
|
92
97
|
|
|
93
|
-
|
|
98
|
+
```bash
|
|
99
|
+
claude mcp add ablo -- npx -y @abloatai/mcp
|
|
100
|
+
```
|
|
94
101
|
|
|
95
|
-
|
|
102
|
+
See [Model Context Protocol](./mcp.md) — and read the surface table below before you pick,
|
|
103
|
+
because Ablo publishes two MCP servers and only one of them is a data plane.
|
|
104
|
+
</Step>
|
|
105
|
+
</Steps>
|
|
106
|
+
|
|
107
|
+
## Surfaces
|
|
108
|
+
|
|
109
|
+
Every surface reaches the same coordinated state. Pick by who is calling.
|
|
110
|
+
|
|
111
|
+
| Surface | Use it for |
|
|
112
|
+
|---|---|
|
|
113
|
+
| **SDK** — `@abloatai/ablo`, `transport: 'http'` | The agents themselves. Stateless, request/response, nothing held open. The main path. |
|
|
114
|
+
| **Coordination MCP** — `@abloatai/mcp` | An agent living inside an MCP host that needs claim and commit as tools. A data plane. |
|
|
115
|
+
| **`humans()`** — with `@abloatai/ablo/react` | The interfaces a person watches agent work arrive in: presence, live queries, a local copy. |
|
|
116
|
+
| **CLI** — `ablo` | Scaffolding, schema push, connecting a database. Terminals and CI. |
|
|
117
|
+
| **REST** — `/api/v1` | Runtimes with no SDK. |
|
|
118
|
+
| **Integration-helper MCP** — hosted `/api/mcp` | Teaching a coding assistant the SDK while you build. Docs, lint, and scaffolds only. |
|
|
119
|
+
|
|
120
|
+
The two MCP servers are not interchangeable. The coordination server changes
|
|
121
|
+
your data; the integration-helper server serves documentation and has no
|
|
122
|
+
per-model data tools at all. An agent that edits rows uses the SDK or the
|
|
123
|
+
coordination server — never the helper.
|
|
124
|
+
|
|
125
|
+
### Where people fit
|
|
126
|
+
|
|
127
|
+
The bare client is the coordination layer: commit, read, observe, claim. People
|
|
128
|
+
are something you add to it. `humans()` is the plugin that declares the local,
|
|
129
|
+
watchable copy — the offline store, live queries, presence, and the framework
|
|
130
|
+
bindings — and it needs a duplex connection, so a stateless agent cannot install
|
|
131
|
+
it and is told so at construction rather than left with a subscription that never
|
|
132
|
+
delivers.
|
|
133
|
+
|
|
134
|
+
There is no `agents()` plugin, and the absence is the point: agents are the
|
|
135
|
+
default caller, not a special one.
|
|
136
|
+
|
|
137
|
+
## Concepts
|
|
138
|
+
|
|
139
|
+
- [Coordination](./coordination.md) — `claim`, `claim.state`, and `claim.queue`: who holds a row, and who is waiting.
|
|
140
|
+
- [Concurrency Convention](./concurrency-convention.md) — the governing rule for how concurrent writes resolve.
|
|
141
|
+
- [Guarantees](./guarantees.md) — what a confirmed write, a stale-write rejection, and a claim each promise.
|
|
142
|
+
- [Idempotency](./idempotency.md) — make a retried write safe; what replays, what re-runs, and for how long.
|
|
143
|
+
- [Schema Contract](./schema-contract.md) — one schema becomes typed clients, agent writes, React reads, and the push.
|
|
144
|
+
- [Agents](./agents.md) — the stateless participant: wake, read, claim, commit, idle.
|
|
145
|
+
- [Agent Messaging](./agent-messaging.md) — durable handoffs between agents, linked to the claim they discuss.
|
|
146
|
+
- [Identity & Sync Groups](./identity.md) — who is connecting, and which slice of state they see.
|
|
147
|
+
- [Interaction Model](./interaction-model.md) — the schema, claim, update, confirmation loop.
|
|
148
|
+
- [Change Propagation](./groups.md) — how one row's change reaches the actors that depend on it.
|
|
149
|
+
- [Client Behavior](./client-behavior.md) — options, errors, retries, timeouts, and imports.
|
|
150
|
+
|
|
151
|
+
## Authority
|
|
152
|
+
|
|
153
|
+
- [Projects](./projects.md) — one organization, many apps; each with its own schema, planes, and keys.
|
|
154
|
+
- [API Keys](./api-keys.md) — the credential that carries an agent's identity and its scopes.
|
|
155
|
+
- [Sessions](./sessions.md) — short-lived scoped credentials your backend mints.
|
|
156
|
+
- [Audit Log](./audit.md) — trace any confirmed write back to the person behind it.
|
|
157
|
+
- [Operating on Your Database](./operating-on-your-database.md) — which actions run freely, which to verify first, and which belong to a human.
|
|
158
|
+
- [Session Settings](./session-settings.md) — point your row-level-security policies at Ablo's writes, by naming the settings they already read.
|
|
159
|
+
|
|
160
|
+
## Build
|
|
161
|
+
|
|
162
|
+
- [Quickstart](./quickstart.md) — make your first coordinated write.
|
|
163
|
+
- [Integration Guide](./integration-guide.md) — the canonical end-to-end integration.
|
|
164
|
+
- [CLI & Migrations](./cli.md) — `init` / `connect` / `push` / `migrate` / `generate`.
|
|
165
|
+
- [Connect Your Database](./data-sources.md) — where rows land when your own database is canonical.
|
|
166
|
+
- [Deployment](./deployment.md) — the database, the keys, and the schema push that take an integration to production.
|
|
167
|
+
- [React](./react.md) — provider, hooks, and reactive reads.
|
|
168
|
+
- [Webhooks](./webhooks.md) — react to confirmed change from outside the SDK.
|
|
169
|
+
- [Debugging & Logs](./debugging.md) — watch claims, queueing, and grants while you build.
|
|
170
|
+
|
|
171
|
+
## Reference
|
|
172
|
+
|
|
173
|
+
- [API Reference](./api.md) — model-by-model method shape.
|
|
174
|
+
- [Errors](./errors.md) — the code registry, its categories, and what to do about each.
|
|
175
|
+
- [Version History & Migration](./migration.md) — every breaking change and its migration.
|
|
176
|
+
- [Changelog](../CHANGELOG.md) — what shipped recently.
|
|
177
|
+
|
|
178
|
+
## Examples
|
|
179
|
+
|
|
180
|
+
- [AI SDK Tool](./examples/ai-sdk-tool.md) — put Ablo inside a model's tool call.
|
|
181
|
+
- [Agent + Human](./examples/agent-human.md) — yield when a person is holding the same report.
|
|
182
|
+
- [Server Agent](./examples/server-agent.md) — a schema-backed worker.
|
|
183
|
+
- [Existing Python Backend](./examples/existing-python-backend.md) — add coordination without replacing your API server.
|
|
184
|
+
- [Next.js](./examples/nextjs.md) — app-router setup with React bindings.
|
|
96
185
|
|
|
97
186
|
## More
|
|
98
187
|
|
|
99
188
|
- [README](../README.md) — product overview and first example.
|
|
100
|
-
- [AGENTS.md](../AGENTS.md) —
|
|
101
|
-
- [Changelog](../CHANGELOG.md) — what shipped recently.
|
|
189
|
+
- [AGENTS.md](../AGENTS.md) — installation guidance for coding assistants.
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Integration Guide
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
> The canonical end-to-end integration, added to an existing product one model at a time.
|
|
4
|
+
|
|
5
|
+
When several AI agents edit the same records in your app — alongside any people
|
|
6
|
+
watching them work — they overwrite each other, and there is no good place to
|
|
7
|
+
coordinate. Ablo gives them one shared, typed write path: the same
|
|
8
|
+
`ablo.<model>.update(...)` call from an agent, a background worker, a server
|
|
9
|
+
action, or a React component. This guide adds it to a product that already has a
|
|
10
|
+
backend and a database, one model at a time.
|
|
9
11
|
|
|
10
12
|
Three things hold no matter which actor is writing:
|
|
11
13
|
|
|
@@ -79,7 +81,7 @@ and write path are ready for production.
|
|
|
79
81
|
When handing this to a coding agent, give it a concrete target:
|
|
80
82
|
|
|
81
83
|
```txt
|
|
82
|
-
Add Ablo to this app for one model
|
|
84
|
+
Add Ablo to this app for one model your agents edit.
|
|
83
85
|
Use the org sandbox sk_test_* key. Declare schema, add the Ablo client, replace
|
|
84
86
|
one write with ablo.<model>.update(..., { readAt, onStale: 'reject',
|
|
85
87
|
wait: 'confirmed' }), and add a smoke test for two concurrent writers.
|
|
@@ -139,7 +141,6 @@ model(
|
|
|
139
141
|
{
|
|
140
142
|
/* fields */
|
|
141
143
|
},
|
|
142
|
-
/* relations */ {},
|
|
143
144
|
{
|
|
144
145
|
// Axis 1 — `policy`: who may READ a row (tenant isolation / RLS). A
|
|
145
146
|
// row-local `organization_id` column is the default, so you omit this for
|
|
@@ -256,7 +257,7 @@ refreshes before expiry.
|
|
|
256
257
|
Reads come in two flavors, and you pick based on whether you can wait.
|
|
257
258
|
`retrieve({ id })` and `list({ where })` hit the server (and hydrate the local
|
|
258
259
|
store) — they're async, so you `await` them. `get(id)` (positional),
|
|
259
|
-
`
|
|
260
|
+
`local.list({ where })`, and `local.count({ where })` read the already-synced local
|
|
260
261
|
graph synchronously, so they're the ones you call in render — and the ones you
|
|
261
262
|
use inside a `useAblo` selector, never the async `retrieve`/`list`.
|
|
262
263
|
|
|
@@ -270,12 +271,12 @@ const report = await ablo.weatherReports.retrieve({ id: 'report_stockholm' });
|
|
|
270
271
|
if (!report) throw new Error('report not found');
|
|
271
272
|
```
|
|
272
273
|
|
|
273
|
-
Use `
|
|
274
|
+
Use `local.retrieve`, `local.list`, and `local.count` for synchronous local-graph reads after
|
|
274
275
|
data has synced.
|
|
275
276
|
|
|
276
277
|
```ts
|
|
277
|
-
const report = ablo.weatherReports.
|
|
278
|
-
const activeReports = ablo.weatherReports.
|
|
278
|
+
const report = ablo.weatherReports.local.retrieve('report_stockholm');
|
|
279
|
+
const activeReports = ablo.weatherReports.local.list({
|
|
279
280
|
where: { projectId: 'proj_123' },
|
|
280
281
|
filter: (report) => report.status !== 'ready',
|
|
281
282
|
orderBy: { updatedAt: 'desc' },
|
|
@@ -295,7 +296,7 @@ export function ReportRow({
|
|
|
295
296
|
}: {
|
|
296
297
|
report: { id: string; location: string; status: string };
|
|
297
298
|
}) {
|
|
298
|
-
const report = useAblo((ablo) => ablo.weatherReports.
|
|
299
|
+
const report = useAblo((ablo) => ablo.weatherReports.local.retrieve(serverReport.id)) ?? serverReport;
|
|
299
300
|
const active = useAblo((ablo) => ablo.weatherReports.claim.state({ id: serverReport.id }));
|
|
300
301
|
|
|
301
302
|
return <button disabled={Boolean(active) || report.status === 'ready'}>{report.location}</button>;
|
|
@@ -375,7 +376,7 @@ The migration can be gradual:
|
|
|
375
376
|
|
|
376
377
|
1. Declare schema for one model, such as `reports`.
|
|
377
378
|
2. Keep existing server loads for first paint.
|
|
378
|
-
3. Add `useAblo((ablo) => ablo.weatherReports.
|
|
379
|
+
3. Add `useAblo((ablo) => ablo.weatherReports.local.retrieve(id)) ?? serverReport` for live rows.
|
|
379
380
|
4. Add one Data Source endpoint that calls the existing service layer.
|
|
380
381
|
5. Move one mutation button from `fetch('/api/reports/...')` to `ablo.weatherReports.update(...)`.
|
|
381
382
|
6. Add an outbox/events path for writes that still happen outside Ablo.
|
|
@@ -507,8 +508,8 @@ them.
|
|
|
507
508
|
| `retrieve({ id })` | Async read of one row from the server (await it). |
|
|
508
509
|
| `list({ where })` | Async read of many rows from the server (await it). |
|
|
509
510
|
| `get(id)` | Synchronous local read of one synced row (positional id; use in render). |
|
|
510
|
-
| `
|
|
511
|
-
| `
|
|
511
|
+
| `local.list({ where })` | Synchronous local read of many synced rows. |
|
|
512
|
+
| `local.count({ where })` | Synchronous local count of synced rows. |
|
|
512
513
|
| `create({ data, id? })` | Create through the model client. |
|
|
513
514
|
| `update({ id, data, ...opts })` | Update through the model client. |
|
|
514
515
|
| `delete({ id, ...opts })` | Delete through the model client. |
|