@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
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Interaction Model
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
> The one write path every actor shares: load, claim, update, confirm.
|
|
4
|
+
|
|
5
|
+
When two agents, a server action, and a person can all write to the same row, you
|
|
6
|
+
need one write path that stops them from clobbering each other. Ablo gives you
|
|
7
|
+
exactly one: load the row, claim it while you work, update it, and wait for
|
|
6
8
|
confirmation. This page walks through that path and the few primitives behind it.
|
|
7
9
|
|
|
8
10
|
Here's the whole path in one block — claim a row, update it inside the claim, and
|
|
@@ -24,7 +26,7 @@ of clobbering.
|
|
|
24
26
|
| Primitive | Plane | Purpose |
|
|
25
27
|
|---|---|---|
|
|
26
28
|
| `Schema` | State | Declares typed models the app and agents can read and write. |
|
|
27
|
-
| `Model` | State | The generated `ablo.<model>` model. Use `retrieve`/`list` (async
|
|
29
|
+
| `Model` | State | The generated `ablo.<model>` model. Use `retrieve`/`list` (async reads), `local.retrieve`/`local.list`/`local.count` (the same verbs, synchronous and local-only), `create`, `update`, and `delete`. |
|
|
28
30
|
| `Claim` | Coordination | Who is working on a target. Taken via `ablo.<model>.claim({ id })` and read via `ablo.<model>.claim.state({ id })`. Ephemeral — never persisted. |
|
|
29
31
|
| `Commit` | Protocol | The durable write underneath model updates. Most users do not call it directly. |
|
|
30
32
|
| `Receipt` | Protocol | The lower-level durable result for custom runtimes. Schema writes use `wait: 'confirmed'`. |
|
package/docs/mcp.md
CHANGED
|
@@ -1,38 +1,64 @@
|
|
|
1
1
|
# Model Context Protocol
|
|
2
2
|
|
|
3
|
+
> Two MCP servers for two different jobs — one of them is a data plane, one is not.
|
|
4
|
+
|
|
3
5
|
Ablo publishes **two** MCP servers for two different jobs. Don't confuse them:
|
|
4
6
|
|
|
5
7
|
| Server | Purpose | Auth | Tools |
|
|
6
8
|
|---|---|---|---|
|
|
7
|
-
| **Coordination** (`@
|
|
9
|
+
| **Coordination** (`@abloatai/mcp`) | Manage your Ablo the way the CLI does, and let an agent safely read & mutate application data | API key (`sk_…` / `rk_…`) | projects, schema, logs, usage — plus `get` / `list` / `create` / `update` / `delete` / `claim` / `release` over your rows |
|
|
8
10
|
| **Integration-helper** (hosted `/api/mcp`) | Help an AI coding assistant write SDK integration code that compiles | none (public docs) | doc search, export surface, schema lint, scaffold |
|
|
9
11
|
|
|
10
|
-
The coordination server **is the data plane** — it is
|
|
11
|
-
state. The integration-helper server only serves docs,
|
|
12
|
-
scaffolds; it does **not** read or write application data (there are no
|
|
12
|
+
The coordination server manages your account **and is the data plane** — it is
|
|
13
|
+
how an agent changes state. The integration-helper server only serves docs,
|
|
14
|
+
schema lint, and scaffolds; it does **not** read or write application data (there are no
|
|
13
15
|
per-model data tools on it). Pick by what you're doing: shipping an agent that
|
|
14
16
|
edits rows → coordination; teaching your IDE assistant the SDK → helper.
|
|
15
17
|
|
|
16
|
-
## Coordination server (`@
|
|
18
|
+
## Coordination server (`@abloatai/mcp`)
|
|
17
19
|
|
|
18
|
-
The coordination server
|
|
19
|
-
(`/api/v1/models/...`)
|
|
20
|
-
the
|
|
21
|
-
gets one safe loop: **claim → read → commit → release.**
|
|
20
|
+
The coordination server does two jobs: it manages your Ablo the way the `ablo`
|
|
21
|
+
CLI does, and it renders the model-scoped API (`/api/v1/models/...`) as tools —
|
|
22
|
+
the same surface as `ablo.<model>.create/update/claim`. An agent connects with
|
|
23
|
+
your API key and gets one safe loop: **claim → read → commit → release.**
|
|
22
24
|
|
|
23
25
|
Install over stdio; set your key in the host's MCP env:
|
|
24
26
|
|
|
25
27
|
```bash
|
|
26
|
-
claude mcp add ablo -- npx -y @
|
|
28
|
+
claude mcp add ablo -- npx -y @abloatai/mcp
|
|
27
29
|
# env: ABLO_API_KEY=sk_… (ABLO_API_URL optional; defaults to the hosted API)
|
|
28
30
|
```
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
### Managing your Ablo
|
|
33
|
+
|
|
34
|
+
| Tool | Mirrors | Does |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `get_schema` | `ablo status` | the models this key can address, and its environment + project |
|
|
37
|
+
| `list_projects` | `ablo projects list` | the org's projects (needs `sk_`) |
|
|
38
|
+
| `create_project` | `ablo projects create` | create one (needs `sk_`) |
|
|
39
|
+
| `tail_logs` | `ablo logs` | recent commits and the actor behind each |
|
|
40
|
+
| `get_usage` | — | usage in daily buckets |
|
|
41
|
+
|
|
42
|
+
There are no key-management tools. A mint returns the plaintext once — only a
|
|
43
|
+
hash is kept — so no tool can hand it back later, and returning it at mint time
|
|
44
|
+
would write a live secret into the agent's context and the conversation
|
|
45
|
+
transcript, where it outlives any revocation. Listing and revoking will arrive
|
|
46
|
+
once a grant identifies the caller as a person rather than a key. Manage keys
|
|
47
|
+
with `ablo login` or the dashboard.
|
|
48
|
+
|
|
49
|
+
`ablo init`, `push`, `pull`, and `generate` have no tools: they read and write
|
|
50
|
+
files in your repo, which the server cannot see. Run those in a shell — then
|
|
51
|
+
call `get_schema` to see the result.
|
|
52
|
+
|
|
53
|
+
### Reading and changing rows
|
|
54
|
+
|
|
55
|
+
Each tool mirrors an SDK verb, scoped to a model + id. Model names come from
|
|
56
|
+
`get_schema`:
|
|
31
57
|
|
|
32
58
|
| Tool | Mirrors | Does |
|
|
33
59
|
|---|---|---|
|
|
34
|
-
| `get_model` | `ablo.<model>.
|
|
35
|
-
| `
|
|
60
|
+
| `get_model` | `ablo.<model>.local.retrieve(id)` | read latest state + active claims |
|
|
61
|
+
| `list_records` | `ablo.<model>.list({…})` | cursor-paginated list with filters |
|
|
36
62
|
| `create_model` | `ablo.<model>.create({ data })` | guarded create |
|
|
37
63
|
| `update_model` | `ablo.<model>.update({ id, … })` | guarded update |
|
|
38
64
|
| `delete_model` | `ablo.<model>.delete({ id })` | guarded delete |
|
|
@@ -41,8 +67,7 @@ Each tool mirrors an SDK verb, scoped to a model + id:
|
|
|
41
67
|
|
|
42
68
|
The agent-facing contract — the safe loop, the "derive idempotency keys from
|
|
43
69
|
the business event" rule, and the error-code playbook — ships as a loadable
|
|
44
|
-
skill at `@
|
|
45
|
-
(`createCoordinationMcpServer`, `src/tools.ts`).
|
|
70
|
+
skill at `@abloatai/mcp/skill.md`.
|
|
46
71
|
|
|
47
72
|
## Integration-helper server
|
|
48
73
|
|
|
@@ -57,7 +82,7 @@ server above, never here.
|
|
|
57
82
|
> The `@abloatai/ablo` npm package itself bundles neither server — it has
|
|
58
83
|
> no `@modelcontextprotocol/sdk` dependency. The helper is a feature of Ablo's
|
|
59
84
|
> hosted app, mounted at `/api/mcp`; the coordination server is the separate
|
|
60
|
-
> `@
|
|
85
|
+
> `@abloatai/mcp` package.
|
|
61
86
|
|
|
62
87
|
### Install
|
|
63
88
|
|
package/docs/migration.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Version History & Migration Guide
|
|
2
2
|
|
|
3
|
+
> Every breaking change and the edit it requires, newest first.
|
|
4
|
+
|
|
3
5
|
The breaking-changes-first companion to the [Changelog](../CHANGELOG.md). The
|
|
4
6
|
changelog tells the story of each release; this page tells you exactly what to
|
|
5
7
|
change when you upgrade.
|
|
@@ -11,6 +13,8 @@ change when you upgrade.
|
|
|
11
13
|
|
|
12
14
|
| Version | What changed | What to do |
|
|
13
15
|
|---|---|---|
|
|
16
|
+
| **0.35.0** | Synchronous reads moved under `local`, mirroring the async verbs | `get(id)` → `local.retrieve(id)`; `getAll(options)` → `local.list(options)`; `getCount(options)` → `local.count(options)` |
|
|
17
|
+
| **0.35.0** | `causedByTaskId` write option + seven `turn_*` error codes removed | Delete the `causedByTaskId` argument from writes; a branch on `turn_validation_failed` was unreachable and can go with it |
|
|
14
18
|
| **0.34.0** | Presence verb renamed `watch` → `join` | `ablo.<model>.watch(ids)` → `ablo.<model>.join(ids)`; `useWatch` → `useJoin`; the `WatchOptions` / `UseWatchOptions` / `UseWatchReturn` types → `JoinOptions` / `UseJoinOptions` / `UseJoinReturn`; error code `model_watch_not_configured` → `model_join_not_configured` |
|
|
15
19
|
| **0.28.0** | Removed React placeholders that had no working runtime | `usePresence` → `usePeers` or `useJoin`; `useClaim` → `ablo.<model>.claim`; `SyncGroupProvider` / `useSyncGroup` → `useJoin({ scope })` |
|
|
16
20
|
| **0.11.0** | Historical `intent` → `claim` rename | The hook renamed in that release was later removed in 0.28.0. Current code uses `ablo.<model>.claim` or `useJoin` |
|
|
@@ -27,6 +31,60 @@ change when you upgrade.
|
|
|
27
31
|
|
|
28
32
|
---
|
|
29
33
|
|
|
34
|
+
## 0.35.0 — the synchronous reads move under `local`
|
|
35
|
+
|
|
36
|
+
```diff
|
|
37
|
+
- const task = ablo.tasks.get(id);
|
|
38
|
+
- const open = ablo.tasks.getAll({ where: { status: 'open' } });
|
|
39
|
+
- const count = ablo.tasks.getCount({ where: { status: 'open' } });
|
|
40
|
+
+ const task = ablo.tasks.local.retrieve(id);
|
|
41
|
+
+ const open = ablo.tasks.local.list({ where: { status: 'open' } });
|
|
42
|
+
+ const count = ablo.tasks.local.count({ where: { status: 'open' } });
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Options, return types, and reactivity inside `useAblo` selectors are unchanged.
|
|
46
|
+
Every verb now matches its asynchronous sibling, and `local` narrows the read to
|
|
47
|
+
what has already synced — which is what lets it return a value rather than a
|
|
48
|
+
promise.
|
|
49
|
+
|
|
50
|
+
`getAll` and `getCount` are distinctive enough to rename by search. `get` is not:
|
|
51
|
+
in most codebases it is outnumbered many times over by `Map.get` and
|
|
52
|
+
`headers.get`, and no search separates them. Upgrade the package first and let
|
|
53
|
+
the compiler name the sites — each one is a type error at exactly the call that
|
|
54
|
+
has to move.
|
|
55
|
+
|
|
56
|
+
## 0.35.0 — `causedByTaskId` and the `turn_*` error codes removed
|
|
57
|
+
|
|
58
|
+
0.9.2 retired the `turn` primitive but left one field standing: `causedByTaskId`
|
|
59
|
+
on the write options bag. It was never usable. The server validated it against a
|
|
60
|
+
task record that nothing in the system has ever created, so supplying it had the
|
|
61
|
+
whole batch rejected with `turn_validation_failed`, while leaving it null passed
|
|
62
|
+
straight through. The safe way to use the option was to not use it.
|
|
63
|
+
|
|
64
|
+
**Removed:** `MutationOptions.causedByTaskId`, the seven `turn_*` error codes
|
|
65
|
+
(`turn_validation_failed`, `turn_open_failed`, `turn_close_failed`,
|
|
66
|
+
`turn_not_found`, `turn_foreign_agent`, `parent_turn_not_found`,
|
|
67
|
+
`parent_turn_foreign_agent`), and the stored row's provenance slice
|
|
68
|
+
(`deltaProvenanceSchema` and the `DeltaProvenance` type). `syncDeltaRowSchema` is
|
|
69
|
+
now the core and attribution slices composed.
|
|
70
|
+
|
|
71
|
+
```diff
|
|
72
|
+
- await ablo.documents.update({ id, data, causedByTaskId: turnId });
|
|
73
|
+
+ await ablo.documents.update({ id, data });
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Attribution is unaffected. A delta still records the actor, the `onBehalfOf`
|
|
77
|
+
principal behind a delegated write, the capability that authorized it, and the
|
|
78
|
+
claim it was made under — which is what answers "who did this, and by what
|
|
79
|
+
right." On the wire the field was optional and nullable, so a client that still
|
|
80
|
+
sends it is accepted and ignored.
|
|
81
|
+
|
|
82
|
+
The `caused_by_task_id` column stays, for the reason 0.9.2 gave when it kept it:
|
|
83
|
+
the audit hash-chain signs its value into every row. Dropping it is a versioned
|
|
84
|
+
migration of its own.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
30
88
|
## 0.34.0 — presence verb renamed `watch` → `join`
|
|
31
89
|
|
|
32
90
|
The model-level presence verb read like a data subscription but delivered
|
|
@@ -35,13 +93,13 @@ does. `ablo.<model>.join(ids, { ttl })` opens the participant handle
|
|
|
35
93
|
(`.peers`, `.claims`, `await using` disposal); the returned `status` was
|
|
36
94
|
already `'joined'`, and the layer beneath always called itself `join`, so the
|
|
37
95
|
verb now matches. `onChange` remains the way to hear row *values* change, and
|
|
38
|
-
`track` remains the durable
|
|
96
|
+
`track` remains the durable premise for actors.
|
|
39
97
|
|
|
40
98
|
```ts
|
|
41
99
|
// before
|
|
42
|
-
await using room = await ablo.
|
|
100
|
+
await using room = await ablo.documents.watch(documentIds, { ttl: '5m' });
|
|
43
101
|
// after
|
|
44
|
-
await using room = await ablo.
|
|
102
|
+
await using room = await ablo.documents.join(documentIds, { ttl: '5m' });
|
|
45
103
|
```
|
|
46
104
|
|
|
47
105
|
The React hook follows: `useWatch({ scope })` → `useJoin({ scope })`. There is
|
|
@@ -148,7 +206,7 @@ distinct stores.
|
|
|
148
206
|
server-side actors (agents, workers, serverless): the same `ablo.<model>` surface
|
|
149
207
|
and `claim` coordination, but each call is one HTTP round-trip with identity on
|
|
150
208
|
the Bearer credential — no websocket, no local synced pool. The return type
|
|
151
|
-
narrows, so stateful-only APIs (
|
|
209
|
+
narrows, so stateful-only APIs (the `local` reads, `onChange`) become compile
|
|
152
210
|
errors instead of latent runtime gaps. Existing code keeps the default
|
|
153
211
|
`'websocket'` transport, unchanged.
|
|
154
212
|
|
|
@@ -227,7 +285,7 @@ modifier are named siblings. Reactive local reads stay on the synchronous
|
|
|
227
285
|
+ await ablo.tasks.retrieve({ id })
|
|
228
286
|
|
|
229
287
|
- useAblo((ablo) => ablo.tasks.retrieve(id)) ?? serverTask
|
|
230
|
-
+ useAblo((ablo) => ablo.tasks.
|
|
288
|
+
+ useAblo((ablo) => ablo.tasks.local.retrieve(id)) ?? serverTask
|
|
231
289
|
```
|
|
232
290
|
|
|
233
291
|
`claim` now returns a disposable handle instead of taking a callback. The handle
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Operating on Your Database
|
|
2
|
+
|
|
3
|
+
> Which actions run freely, which to verify first, and which belong to a human.
|
|
4
|
+
|
|
5
|
+
Ablo sits over your database as a coordination layer, not an owner. It reads
|
|
6
|
+
your Postgres replication stream and routes each write through a claim-checked
|
|
7
|
+
commit that lands in your own tables. It never runs DDL, never migrates, never
|
|
8
|
+
drops. That single boundary is why almost everything you do through Ablo is
|
|
9
|
+
either read-only or reversible — and why the few actions that aren't are easy to
|
|
10
|
+
name. This page is how to tell them apart, so you can work on a real database
|
|
11
|
+
without guessing which move is the dangerous one.
|
|
12
|
+
|
|
13
|
+
The habit that makes it easy is to look before you act. One command shows you
|
|
14
|
+
the real shape of your database measured against your schema, and changes
|
|
15
|
+
nothing:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx ablo check # read-only — reports which columns fit your models and which don't
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
When a question is about the live database — does this column exist, is it
|
|
22
|
+
nullable, will this write fit — you can usually answer it by observing rather
|
|
23
|
+
than reasoning in the dark.
|
|
24
|
+
|
|
25
|
+
## The floor: what Ablo never does
|
|
26
|
+
|
|
27
|
+
These hold on every database Ablo connects to, and they are what bound the blast
|
|
28
|
+
radius of anything you do through the model API:
|
|
29
|
+
|
|
30
|
+
- It **never runs DDL or migrations** on your database, and never drops a table
|
|
31
|
+
or column. Schema changes to your own tables are always your application's
|
|
32
|
+
action, run with your admin credential — never Ablo's.
|
|
33
|
+
- It **never owns your rows.** Canonical data stays in your tables; Ablo hosts
|
|
34
|
+
only the transaction log and the coordination state.
|
|
35
|
+
- Every model write is **claim-checked and recorded.** A write based on a row
|
|
36
|
+
that moved under you is rejected rather than applied, and the prior value is
|
|
37
|
+
retained in the log, so a confirmed change is attributable and
|
|
38
|
+
reconstructable.
|
|
39
|
+
|
|
40
|
+
So a normal `ablo.<model>.update(...)` cannot silently corrupt your database:
|
|
41
|
+
the worst case is a clean rejection and a re-read, not a lost row.
|
|
42
|
+
|
|
43
|
+
## Three kinds of action
|
|
44
|
+
|
|
45
|
+
Sort any action you're about to take into one of these, and the right move
|
|
46
|
+
follows.
|
|
47
|
+
|
|
48
|
+
**Run freely — read-only or reversible.**
|
|
49
|
+
Reads (`retrieve`, `list`, `get`), `ablo check`, and `ablo pull` observe and
|
|
50
|
+
never change anything. Previews — `--show-sql`, `--dry-run` — print the exact
|
|
51
|
+
SQL a command would run without executing it. Model writes through
|
|
52
|
+
`ablo.<model>.create` / `update` are claim-checked, optimistic, rolled back if
|
|
53
|
+
the server rejects them, and recorded in the log with the prior value. All of
|
|
54
|
+
these are safe to run on your own initiative.
|
|
55
|
+
|
|
56
|
+
**Verify first — needs one look at the live database.**
|
|
57
|
+
Routing an existing table's writes through a model requires the model to match
|
|
58
|
+
the table's real columns. Run `ablo check`: it names the columns that fit and
|
|
59
|
+
the ones that don't, so a `NOT NULL` column your model doesn't set shows up as a
|
|
60
|
+
line in the report rather than a surprise at commit time. Decide the model shape
|
|
61
|
+
from what `check` tells you, then proceed. Nothing here is risky — it just reads
|
|
62
|
+
better after you've seen the ground truth.
|
|
63
|
+
|
|
64
|
+
**Hand to a human — irreversible, outside the log's protection.**
|
|
65
|
+
Raw DDL on the live database — `ALTER TABLE … OWNER TO`, adding or dropping a
|
|
66
|
+
column, changing a constraint — changes the database itself and is not covered
|
|
67
|
+
by the reversible log, so it belongs to a person with their hand on it. So does
|
|
68
|
+
a `connect` cutover run with its confirmation skipped (`--yes`): the prompt
|
|
69
|
+
exists because the step provisions real roles and reconciles publication on a
|
|
70
|
+
live database, and on a shared or production database that confirmation is the
|
|
71
|
+
human's to give. Removing a model from your schema belongs here too — for the
|
|
72
|
+
reason below.
|
|
73
|
+
|
|
74
|
+
## The one action that isn't what it looks like
|
|
75
|
+
|
|
76
|
+
Deleting a model from `ablo/schema.ts` reads like a code cleanup, but it is a
|
|
77
|
+
schema change. Your schema is a desired-state declaration: `ablo push` diffs it
|
|
78
|
+
against the server's copy, and a model that has vanished from the schema can be
|
|
79
|
+
read as a table that should no longer exist. "Nothing imports it" answers a
|
|
80
|
+
code question. The question that governs safety is *does removing this drop a
|
|
81
|
+
real table on the next push* — and that one is answered against the database,
|
|
82
|
+
not the codebase. Before removing a model that maps a live table, confirm the
|
|
83
|
+
table is gone or empty and that your push path is additive; otherwise keep the
|
|
84
|
+
model until the data is dealt with. A `load: 'lazy'` mapping is often present
|
|
85
|
+
precisely to hold a table in place, so treat its comment as load-bearing.
|
|
86
|
+
|
|
87
|
+
## The verification loop
|
|
88
|
+
|
|
89
|
+
Most of the uncertainty in working on a live database dissolves into a few
|
|
90
|
+
read-only checks:
|
|
91
|
+
|
|
92
|
+
- `ablo check` — does the live database match the schema? Reports the exact
|
|
93
|
+
column-by-column fit. Read-only.
|
|
94
|
+
- `ablo pull` — what is actually in the database, expressed as a schema.
|
|
95
|
+
Read-only, like `prisma db pull`.
|
|
96
|
+
- `--show-sql` / `--dry-run` on `connect` and `migrate` — the exact statements,
|
|
97
|
+
printed and unexecuted, so you approve the SQL before it runs.
|
|
98
|
+
- Read the row and its claim state before you write — `retrieve` / `list`, and
|
|
99
|
+
`ablo.<model>.claim.state({ id })` for who is already working on it.
|
|
100
|
+
|
|
101
|
+
The pattern underneath all of it is steady: reads and model writes flow freely
|
|
102
|
+
because the boundary and the log make them safe, DDL and cutovers pause for a
|
|
103
|
+
human because they change the database itself, and the space between the two is
|
|
104
|
+
one `ablo check` away from certain.
|
|
105
|
+
|
|
106
|
+
## See also
|
|
107
|
+
|
|
108
|
+
- [Connect Your Database](./data-sources.md) — the one path a database joins Ablo.
|
|
109
|
+
- [Guarantees](./guarantees.md) — what a confirmed write, a stale check, and a claim promise.
|
|
110
|
+
- [CLI & Migrations](./cli.md) — `check`, `pull`, `migrate`, and their read-only / preview flags.
|
|
111
|
+
- [Schema Contract](./schema-contract.md) — how the schema drives push, and why it is a desired-state declaration.
|
package/docs/projects.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Projects
|
|
2
2
|
|
|
3
|
+
> One organization, many apps — each with its own schema, data planes, and keys.
|
|
4
|
+
|
|
3
5
|
A **project** is the isolation unit inside your organization — the shape you
|
|
4
6
|
know from Neon or Supabase. Each app you build gets its own project, and each
|
|
5
7
|
project gets its own schema, its own sandbox/production data planes, and its
|
package/docs/quickstart.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# Quickstart
|
|
2
2
|
|
|
3
|
+
> Make your first coordinated write, on the Postgres you already have.
|
|
4
|
+
|
|
3
5
|
Build with Ablo on **the Postgres you already have**. You declare a small Ablo
|
|
4
|
-
schema for the models
|
|
6
|
+
schema for the models your agents edit together, connect Ablo to your
|
|
5
7
|
database (`ablo connect`), and read and write every one of those models through
|
|
6
8
|
`ablo.<model>`. You write through Ablo; it lands the change in your Postgres and
|
|
7
9
|
confirms it by tailing your write-ahead log (WAL). Your rows live in your database,
|
|
@@ -86,6 +88,22 @@ import type { Model } from '@abloatai/ablo/schema';
|
|
|
86
88
|
type WeatherReport = Model<'weatherReports'>; // fully typed from YOUR schema
|
|
87
89
|
```
|
|
88
90
|
|
|
91
|
+
The same block is where you name the metadata your claims carry. Add a
|
|
92
|
+
`ClaimMeta` key and every `claim.state`, `claim.queue`, and held claim reads
|
|
93
|
+
`target.meta` as that shape:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
declare module '@abloatai/ablo' {
|
|
97
|
+
interface Register {
|
|
98
|
+
Schema: typeof schema;
|
|
99
|
+
ClaimMeta: { blocks: string[] };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const holder = ablo.weatherReports.claim.state({ id });
|
|
104
|
+
holder?.target.meta?.blocks.length; // typed, no guard
|
|
105
|
+
```
|
|
106
|
+
|
|
89
107
|
(The same `Register` binding types every hook and client — it's the
|
|
90
108
|
TanStack-Router pattern: declare the source of truth once, everything
|
|
91
109
|
infers from it.)
|
|
@@ -169,10 +187,9 @@ tables** — Ablo reads them, it does not create or migrate them:
|
|
|
169
187
|
the tables with your own migration tool; Ablo syncs the subset of models you
|
|
170
188
|
declared and reports the rest as "ignored / owned by you."
|
|
171
189
|
|
|
172
|
-
> **
|
|
173
|
-
>
|
|
174
|
-
>
|
|
175
|
-
> your own migrations stay in charge of your schema.
|
|
190
|
+
> **Starting from an empty database?** `npx ablo migrate` creates the tables
|
|
191
|
+
> your schema needs. Once they exist, your own migration tool stays in charge
|
|
192
|
+
> of them — Ablo adopts whatever shape you evolve.
|
|
176
193
|
|
|
177
194
|
Nothing runs locally — there is no dev server to start. Your app talks to Ablo's
|
|
178
195
|
hosted API; the rows live in your database.
|
package/docs/react.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# React
|
|
2
2
|
|
|
3
|
+
> Provider, hooks, and reactive reads for the interfaces people watch agent work arrive in.
|
|
4
|
+
|
|
3
5
|
The React bindings for `@abloatai/ablo`. Use them when you want live
|
|
4
6
|
data on the client without writing fetch + WebSocket plumbing yourself.
|
|
5
7
|
|
|
@@ -85,7 +87,7 @@ org / team / user map to what a participant can see.
|
|
|
85
87
|
import { useAblo } from '@abloatai/ablo/react';
|
|
86
88
|
|
|
87
89
|
export function ReportView({ report: serverReport }: { report: { id: string; location: string } }) {
|
|
88
|
-
const report = useAblo((ablo) => ablo.weatherReports.
|
|
90
|
+
const report = useAblo((ablo) => ablo.weatherReports.local.retrieve(serverReport.id)) ?? serverReport;
|
|
89
91
|
const active = useAblo((ablo) => ablo.weatherReports.claim.state({ id: serverReport.id }));
|
|
90
92
|
const claimed = Boolean(active);
|
|
91
93
|
|
|
@@ -95,7 +97,7 @@ export function ReportView({ report: serverReport }: { report: { id: string; loc
|
|
|
95
97
|
|
|
96
98
|
The hook:
|
|
97
99
|
|
|
98
|
-
1. Uses the same `ablo.<model>.
|
|
100
|
+
1. Uses the same `ablo.<model>.local.retrieve(id)` / `.local.list()` methods you'd call anywhere
|
|
99
101
|
else in the SDK — the hook just makes them reactive.
|
|
100
102
|
2. Tracks the model fields read by the selector and re-renders when confirmed
|
|
101
103
|
deltas arrive.
|
|
@@ -110,14 +112,14 @@ effects, or writes:
|
|
|
110
112
|
const abloClient = useAblo();
|
|
111
113
|
```
|
|
112
114
|
|
|
113
|
-
Prefer selector reads like `useAblo((ablo) => ablo.<model>.
|
|
115
|
+
Prefer selector reads like `useAblo((ablo) => ablo.<model>.local.retrieve(id))`. Older hooks
|
|
114
116
|
also accept a string model name; prefer the selector form shown above.
|
|
115
117
|
|
|
116
118
|
For collections, keep the selector on the model client too:
|
|
117
119
|
|
|
118
120
|
```tsx
|
|
119
121
|
const reports = useAblo((ablo) =>
|
|
120
|
-
ablo.weatherReports.
|
|
122
|
+
ablo.weatherReports.local.list({
|
|
121
123
|
where: { projectId },
|
|
122
124
|
filter: (report) => report.status !== 'ready',
|
|
123
125
|
state: 'live',
|
|
@@ -135,7 +137,7 @@ Use `retrieve` in Server Components when the row may not be in the local pool
|
|
|
135
137
|
yet — it hydrates from the local store and the server, and returns a Promise, so
|
|
136
138
|
`await` it. (Server reads come in two shapes: `retrieve({ id })` for one row and
|
|
137
139
|
`list({ where })` for many; both are async. The synchronous local reads are
|
|
138
|
-
`
|
|
140
|
+
the `local` reads, used in render below.)
|
|
139
141
|
|
|
140
142
|
## Writes
|
|
141
143
|
|
|
@@ -191,11 +193,11 @@ write interest in it.
|
|
|
191
193
|
|
|
192
194
|
import { useJoin } from '@abloatai/ablo/react';
|
|
193
195
|
|
|
194
|
-
export function DeckPresence({
|
|
196
|
+
export function DeckPresence({ workspaceId }: { workspaceId: string }) {
|
|
195
197
|
const { peers, claims, status } = useJoin({
|
|
196
|
-
scope: { slideDecks:
|
|
198
|
+
scope: { slideDecks: workspaceId },
|
|
197
199
|
claim: true, // I intend to write — pin the scope + let peers observe the claim
|
|
198
|
-
hydrate: true, // backfill the
|
|
200
|
+
hydrate: true, // backfill the workspace's current rows if not already loaded
|
|
199
201
|
});
|
|
200
202
|
|
|
201
203
|
if (status !== 'joined') return <span>connecting…</span>;
|
|
@@ -230,8 +232,8 @@ connection is subscribed to.
|
|
|
230
232
|
|
|
231
233
|
import { usePeers } from '@abloatai/ablo/react';
|
|
232
234
|
|
|
233
|
-
export function CursorBroadcaster({
|
|
234
|
-
const peers = usePeers({ slideDecks:
|
|
235
|
+
export function CursorBroadcaster({ workspaceId }: { workspaceId: string }) {
|
|
236
|
+
const peers = usePeers({ slideDecks: workspaceId });
|
|
235
237
|
const alone = !peers.some((p) => p.participantKind === 'user');
|
|
236
238
|
// suppress live-cursor broadcasts while alone
|
|
237
239
|
}
|
package/docs/schema-contract.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Schema Contract
|
|
2
2
|
|
|
3
|
+
> One schema becomes typed clients, agent writes, interface reads, and the hosted push.
|
|
4
|
+
|
|
3
5
|
Ablo's schema is the integration contract. Define it once, pass it to `Ablo(...)`,
|
|
4
6
|
and every actor gets the same typed model surface:
|
|
5
7
|
|
|
@@ -10,7 +12,7 @@ defineSchema(...) -> ablo.<model>.create/retrieve/update/claim(...)
|
|
|
10
12
|
That one object drives:
|
|
11
13
|
|
|
12
14
|
- typed model clients in trusted server runtimes,
|
|
13
|
-
- React selectors through `useAblo((ablo) => ablo.<model>.
|
|
15
|
+
- React selectors through `useAblo((ablo) => ablo.<model>.local.retrieve(id))`,
|
|
14
16
|
- agent and background-worker writes,
|
|
15
17
|
- Data Source request/response shape when your database stays canonical,
|
|
16
18
|
- hosted schema push, migration planning, and schema-version gating.
|
|
@@ -75,8 +77,8 @@ const ready = await ablo.weatherReports.list({ where: { status: 'ready' } });
|
|
|
75
77
|
Use synchronous local reads in render after data has synced:
|
|
76
78
|
|
|
77
79
|
```ts
|
|
78
|
-
const report = ablo.weatherReports.
|
|
79
|
-
const pending = ablo.weatherReports.
|
|
80
|
+
const report = ablo.weatherReports.local.retrieve(reportId);
|
|
81
|
+
const pending = ablo.weatherReports.local.list({ where: { status: 'pending' } });
|
|
80
82
|
```
|
|
81
83
|
|
|
82
84
|
Use model writes for every actor:
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Session Settings
|
|
2
|
+
|
|
3
|
+
> Point your row-level-security policies at Ablo's writes, by naming the Postgres session settings they already read.
|
|
4
|
+
|
|
5
|
+
Ablo writes your rows through a scoped role with `row_security` on and
|
|
6
|
+
`NOBYPASSRLS` set, so your policies govern its writes the same way they govern
|
|
7
|
+
your own application's. They only govern well if they can see who the write is
|
|
8
|
+
for. Before each write, Ablo sets its own identity context on the transaction —
|
|
9
|
+
and if your policies read settings under names you chose, `sessionSettings` maps
|
|
10
|
+
one to the other:
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { defineSchema, model, z } from '@abloatai/ablo/schema';
|
|
14
|
+
|
|
15
|
+
export const schema = defineSchema(
|
|
16
|
+
{
|
|
17
|
+
invoices: model({
|
|
18
|
+
total: z.number(),
|
|
19
|
+
reference: z.string(),
|
|
20
|
+
}),
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
sessionSettings: { 'app.current_org': 'orgId' },
|
|
24
|
+
},
|
|
25
|
+
);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
A policy written against `current_setting('app.current_org')` now applies to
|
|
29
|
+
Ablo's write, unchanged:
|
|
30
|
+
|
|
31
|
+
```sql
|
|
32
|
+
CREATE POLICY tenant_isolation ON invoices
|
|
33
|
+
USING (organization_id = current_setting('app.current_org', true));
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The key is the setting name **your** policies read. The value names which piece
|
|
37
|
+
of Ablo's authenticated identity fills it.
|
|
38
|
+
|
|
39
|
+
## What Ablo sets on its own
|
|
40
|
+
|
|
41
|
+
Every direct write runs inside a transaction that begins by setting this
|
|
42
|
+
context, whether or not you map anything:
|
|
43
|
+
|
|
44
|
+
| Setting | Carries |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `app.current_org_id` | The organization the credential acts for |
|
|
47
|
+
| `app.current_project_id` | The project |
|
|
48
|
+
| `app.current_environment` | The environment |
|
|
49
|
+
| `app.current_sandbox_id` | The sandbox, when the write is in one |
|
|
50
|
+
| `app.current_participant_id` | The participant making the write |
|
|
51
|
+
| `app.current_participant_kind` | Whether that participant is a person, an agent, or the system |
|
|
52
|
+
| `app.current_user_id` | The person on whose behalf the write is made |
|
|
53
|
+
|
|
54
|
+
If your policies read these names directly, you need no mapping at all — this
|
|
55
|
+
page is for the case where they read different ones.
|
|
56
|
+
|
|
57
|
+
`app.current_user_id` is worth reading twice, because it has three states rather
|
|
58
|
+
than two. It carries a person's id when a person is behind the write. It carries
|
|
59
|
+
`*` when a backend credential is acting as the organization itself, which is the
|
|
60
|
+
authority a server-side key holds. And it carries the empty string when no
|
|
61
|
+
identity could be established — written explicitly rather than left alone, so a
|
|
62
|
+
policy on a pooled connection reads absence as absence and denies, instead of
|
|
63
|
+
inheriting whatever the previous transaction left behind.
|
|
64
|
+
|
|
65
|
+
## What a mapping may name
|
|
66
|
+
|
|
67
|
+
The value side is a closed set, and every member is resolved by Ablo from the
|
|
68
|
+
authenticated key and the plane:
|
|
69
|
+
|
|
70
|
+
`orgId` · `projectId` · `environment` · `sandboxId` · `participantId` ·
|
|
71
|
+
`participantKind`
|
|
72
|
+
|
|
73
|
+
Because none of them come from the caller, a mapping can forward the tenant
|
|
74
|
+
identity Ablo already trusts, but cannot widen what a writer sees. A setting name
|
|
75
|
+
takes exactly one source — the name is the key — so naming the same setting twice
|
|
76
|
+
is unrepresentable rather than something to resolve later.
|
|
77
|
+
|
|
78
|
+
## What a mapping may not name
|
|
79
|
+
|
|
80
|
+
The settings in the table above, along with `row_security`, `search_path`,
|
|
81
|
+
`statement_timeout`, and `lock_timeout`, are reserved. `defineSchema` rejects a
|
|
82
|
+
mapping onto any of them, and the engine refuses one at write time too.
|
|
83
|
+
|
|
84
|
+
The reason is worth stating plainly: those settings are how Ablo bounds its own
|
|
85
|
+
write. A schema that could reassign them could relax the scoping under which
|
|
86
|
+
Ablo writes, which would put the boundary inside the thing being bounded. Point
|
|
87
|
+
your policies at a name you own — `app.current_org` rather than
|
|
88
|
+
`app.current_org_id` — and map that.
|
|
89
|
+
|
|
90
|
+
## Reads served from the log
|
|
91
|
+
|
|
92
|
+
One arrangement cannot honour a policy that names a person. When a plane is
|
|
93
|
+
served from its retained log rather than from its tables, every row carries the
|
|
94
|
+
organization and the project, but not the owner — so a rule about who owns a row
|
|
95
|
+
has nothing to act on.
|
|
96
|
+
|
|
97
|
+
Rather than fold those rows and return a plausible answer, such a read is
|
|
98
|
+
declined whole with `user_scope_not_enforced`: a member reading a colleague's
|
|
99
|
+
private records would otherwise be indistinguishable from a member reading their
|
|
100
|
+
own. Reads made by a credential acting for the organization are unaffected, as is
|
|
101
|
+
every plane served from its tables.
|
|
102
|
+
|
|
103
|
+
## Related
|
|
104
|
+
|
|
105
|
+
- [Data Sources](./data-sources.md) — the writer role's privileges, and what it
|
|
106
|
+
can and cannot do to your database.
|
|
107
|
+
- [Operating on Your Database](./operating-on-your-database.md) — which actions
|
|
108
|
+
are read-only, which are reversible, and which belong to a human.
|
package/docs/sessions.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Sessions
|
|
2
2
|
|
|
3
|
+
> Short-lived scoped credentials your backend mints for a browser or an agent.
|
|
4
|
+
|
|
3
5
|
A **session** is a short-lived credential your backend mints with its `sk_` and
|
|
4
6
|
hands to one actor — a signed-in **person's browser** or a scoped **agent**. It's
|
|
5
7
|
the same primitive in both cases (backend-minted, short-lived, scoped); the only
|
|
@@ -16,7 +18,7 @@ const userSession = await ablo.sessions.create({
|
|
|
16
18
|
// A scoped agent session — gated to exactly the operations you name.
|
|
17
19
|
const agentSession = await ablo.sessions.create({
|
|
18
20
|
agent: { id: 'agent:task-writer' },
|
|
19
|
-
can: { Task: ['read', 'update'],
|
|
21
|
+
can: { Task: ['read', 'update'], Workspace: ['read'] },
|
|
20
22
|
});
|
|
21
23
|
```
|
|
22
24
|
|
package/docs/webhooks.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# Webhooks
|
|
2
2
|
|
|
3
|
+
> Stream the committed transaction log to your own systems as signed events.
|
|
4
|
+
|
|
3
5
|
Ablo keeps an ordered transaction log of every committed change and coordinates
|
|
4
|
-
the writers —
|
|
6
|
+
the writers — agents, and the people alongside them — that produce it. Your rows live in your own
|
|
5
7
|
database; Ablo holds only the log. **Webhooks stream that log to your systems as
|
|
6
8
|
signed events:** every committed change is POSTed to an endpoint in your app, and
|
|
7
9
|
your handler decides what to do with it.
|