@abloatai/ablo 0.34.1 → 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 +2 -1
- package/CHANGELOG.md +674 -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 +3344 -1073
- 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 -86
- 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 +3 -1
- 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/coordination.md
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# Coordination Reference
|
|
2
2
|
|
|
3
|
+
> Claim mechanics and the API behind them: who holds a row, who is waiting, and how the line moves.
|
|
4
|
+
|
|
3
5
|
> **Governing convention:** [`concurrency-convention.md`](./concurrency-convention.md)
|
|
4
6
|
> — the non-coercion principle (surface state, let the actor decide), the full
|
|
5
|
-
> `onStale` taxonomy, the
|
|
6
|
-
> the *why* and the contract; this reference is the *how* (claim
|
|
7
|
+
> `onStale` taxonomy, the batch premise (`reads[]`), and the boundaries. Read
|
|
8
|
+
> that for the *why* and the contract; this reference is the *how* (claim
|
|
9
|
+
> mechanics + API).
|
|
7
10
|
|
|
8
|
-
Coordinate long-running work on a row so
|
|
9
|
-
other. Most writes need none of this — a plain `ablo.<model>.update({ id, data })`
|
|
11
|
+
Coordinate long-running work on a row so agents — and the people watching them —
|
|
12
|
+
don't clobber each other. Most writes need none of this — a plain `ablo.<model>.update({ id, data })`
|
|
10
13
|
is **last-write-wins** by default.
|
|
11
14
|
|
|
12
15
|
> **Read-modify-write under contention? Use the functional update — it owns all
|
|
@@ -128,46 +131,53 @@ disposition once, in the schema, so every commit to that model is governed
|
|
|
128
131
|
without per-call wiring. This is the third coordination axis — orthogonal to
|
|
129
132
|
`policy` (who may read a row) and `groups` (which delta channels it fans into).
|
|
130
133
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
| value | meaning |
|
|
135
|
-
|---|---|
|
|
136
|
-
| `'overwrite'` | the write wins; that committer is never blocked. |
|
|
137
|
-
| `'reject'` | the write is refused; that committer yields to a held claim / stale snapshot. |
|
|
138
|
-
| `'notify'` | hold the write and hand back the current value so the committer re-reads and re-applies (stale writes only). |
|
|
134
|
+
Set a model's `conflict` stance with `coordination`, naming one rule per kind of
|
|
135
|
+
committer:
|
|
139
136
|
|
|
140
137
|
```ts
|
|
141
|
-
import { model,
|
|
142
|
-
|
|
143
|
-
export const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
138
|
+
import { coordination, model, z } from '@abloatai/ablo/schema';
|
|
139
|
+
|
|
140
|
+
export const cards = model(
|
|
141
|
+
{
|
|
142
|
+
title: z.string(),
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
// "a human's edit always wins (never blocked); an agent yields"
|
|
146
|
+
conflict: coordination.humansOverwrite().agentsReject(),
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
Each rule pairs a committer with a disposition, drawn from the same `onStale`
|
|
152
|
+
vocabulary the write guards use:
|
|
152
153
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
| disposition | meaning |
|
|
155
|
+
|---|---|
|
|
156
|
+
| `overwrite` | the write wins; that committer is never blocked. |
|
|
157
|
+
| `reject` | the write is refused; that committer yields to a held claim / stale snapshot. |
|
|
158
|
+
| `notify` | hold the write and hand back the current value so the committer re-reads and re-applies (stale writes only). |
|
|
159
|
+
|
|
160
|
+
That gives nine rules — `humansOverwrite` / `humansReject` / `humansNotify`,
|
|
161
|
+
`agentsOverwrite` / `agentsReject` / `agentsNotify`, `systemOverwrite` /
|
|
162
|
+
`systemReject` / `systemNotify` — and a chain may name as many as it needs. A
|
|
163
|
+
kind left unnamed falls through to the engine default, and a kind named twice
|
|
164
|
+
takes the later rule.
|
|
165
|
+
|
|
166
|
+
When the rules are assembled at runtime rather than written out, each one is
|
|
167
|
+
also a standalone function, and `coordination()` merges them:
|
|
156
168
|
|
|
157
169
|
```ts
|
|
158
|
-
import {
|
|
170
|
+
import { coordination, humansOverwrite, agentsReject } from '@abloatai/ablo/schema';
|
|
159
171
|
|
|
160
|
-
|
|
161
|
-
title: field.string(),
|
|
162
|
-
}, {
|
|
163
|
-
conflict: coordination(humansOverwrite(), agentsReject()),
|
|
164
|
-
// → { user: 'overwrite', agent: 'reject' }
|
|
165
|
-
});
|
|
172
|
+
const stance = coordination(humansOverwrite(), agentsReject());
|
|
166
173
|
```
|
|
167
174
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
175
|
+
Both forms produce the same thing: a map keyed by the committer's participant
|
|
176
|
+
kind, which is what travels to the server.
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
{ user: 'overwrite', agent: 'reject' }
|
|
180
|
+
```
|
|
171
181
|
|
|
172
182
|
### How it relates to per-write coordination
|
|
173
183
|
|
|
@@ -293,7 +303,7 @@ equivalent for when you hold a claim without `await using`.
|
|
|
293
303
|
### Claim-gated reads
|
|
294
304
|
|
|
295
305
|
`claim.state({ id })` always returns immediately. Model reads such as
|
|
296
|
-
`ablo.<model>.
|
|
306
|
+
`ablo.<model>.local.retrieve(id)` are local reads and stay available while a claim is
|
|
297
307
|
held. Server/model reads can choose a claimed policy:
|
|
298
308
|
|
|
299
309
|
```ts
|
|
@@ -546,11 +556,11 @@ snapshot.
|
|
|
546
556
|
|
|
547
557
|
Reading or claiming a row auto-enrolls you in its sync group, which is enough for
|
|
548
558
|
`claim.state`/`claim.queue` to observe co-participants. When you want to *hold*
|
|
549
|
-
presence on a known set of rows — a
|
|
559
|
+
presence on a known set of rows — a workspace's documents, a board's cards — and react to
|
|
550
560
|
who joins or leaves, use `join`:
|
|
551
561
|
|
|
552
562
|
```ts
|
|
553
|
-
await using room = await ablo.
|
|
563
|
+
await using room = await ablo.documents.join(slideIds, { ttl: '5m' });
|
|
554
564
|
room.peers; // who else is here, live
|
|
555
565
|
```
|
|
556
566
|
|
|
@@ -627,7 +637,7 @@ inspect the `code`.
|
|
|
627
637
|
|
|
628
638
|
`AbloStaleContextError.conflicts` lists the `(model, id, observedSyncId)` rows
|
|
629
639
|
that moved during your generation window — use it for selective regeneration
|
|
630
|
-
(re-think only the
|
|
640
|
+
(re-think only the documents that changed, not the whole workspace) and for metrics.
|
|
631
641
|
|
|
632
642
|
```ts
|
|
633
643
|
try {
|
package/docs/data-sources.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Connect Your Database
|
|
2
2
|
|
|
3
|
+
> Keep the rows in your own Postgres while Ablo coordinates and confirms every write.
|
|
4
|
+
|
|
3
5
|
You write through Ablo, and Ablo writes to your Postgres. A call to
|
|
4
6
|
`ablo.<model>.create / update / delete` enters Ablo's commit chokepoint — where
|
|
5
7
|
claims, ordering, and idempotency are enforced — and Ablo applies the change to
|
|
@@ -180,7 +182,7 @@ await ablo.weatherReports.update({ id: 'report_stockholm', data: { high: 21 } })
|
|
|
180
182
|
await ablo.weatherReports.update({ id: 'report_stockholm', data: { high: 21 }, wait: 'confirmed' });
|
|
181
183
|
|
|
182
184
|
// Reads are live off the same stream.
|
|
183
|
-
const report = ablo.weatherReports.
|
|
185
|
+
const report = ablo.weatherReports.local.retrieve('report_stockholm');
|
|
184
186
|
```
|
|
185
187
|
|
|
186
188
|
A commit is accepted the moment Ablo takes it (`queued`); it becomes `confirmed`
|
package/docs/debugging.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Debugging & Logs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Watch claims, queueing, and grants as they happen while you build.
|
|
4
|
+
|
|
5
|
+
By default the SDK is quiet — it logs only warnings and errors. When you're building a multi-agent flow and want to *see* the coordination happen (who claimed what, who's waiting in line, who got preempted), turn on Ablo's diagnostic logging. Every line is prefixed `[Ablo]` so it's obvious which output is ours in a console full of other tools.
|
|
4
6
|
|
|
5
7
|
## Turn it on
|
|
6
8
|
|
|
@@ -39,7 +41,7 @@ Precedence: an explicit `logLevel` wins, then `debug: true` (⇒ `debug`), then
|
|
|
39
41
|
|
|
40
42
|
## What you'll see — the coordination trace
|
|
41
43
|
|
|
42
|
-
These lines (all at `info`) let you watch the
|
|
44
|
+
These lines (all at `info`) let you watch the handover you built:
|
|
43
45
|
|
|
44
46
|
```
|
|
45
47
|
[Ablo] claim: requesting documents:doc_42 for "editing" (will queue if contended)
|
|
@@ -61,7 +63,7 @@ Read it as the lifecycle of one claim:
|
|
|
61
63
|
|
|
62
64
|
## Where the logs run
|
|
63
65
|
|
|
64
|
-
The coordination trace and the proactive credential refresh run **in the browser** (and any client that holds a live socket) — that's where the
|
|
66
|
+
The coordination trace and the proactive credential refresh run **in the browser** (and any client that holds a live socket) — that's where the live coordination activity is. Server-side code that mints credentials or does one-shot reads won't emit the trace; it has no live session to narrate.
|
|
65
67
|
|
|
66
68
|
## Bring your own logger
|
|
67
69
|
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# Deployment
|
|
2
|
+
|
|
3
|
+
> What production takes: a database Ablo can reach, a key minted for the plane you mean, and a schema push in the deploy.
|
|
4
|
+
|
|
5
|
+
One command answers the question this page exists for — would a write succeed
|
|
6
|
+
right now, and if not, why:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
ABLO_API_KEY=sk_live_… npx ablo status
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
ablo status
|
|
14
|
+
|
|
15
|
+
key sk_live_51H8… (ABLO_API_KEY env — overrides stored)
|
|
16
|
+
mode production
|
|
17
|
+
org org_3nKq…
|
|
18
|
+
project checkout (prj_7Yb2…)
|
|
19
|
+
acts on production
|
|
20
|
+
○ sandbox sk_test_9fJd… · expires in 71d
|
|
21
|
+
● production — no key
|
|
22
|
+
push production with sk_live_51H8… (env)
|
|
23
|
+
api https://api.abloatai.com reachable
|
|
24
|
+
data ✓ database connected to this plane (direct)
|
|
25
|
+
schema 4 models pushed (rev 12) hash 3f9a2c81 @ 2026-07-18
|
|
26
|
+
• orders typename=orders
|
|
27
|
+
• lineItems typename=lineItems
|
|
28
|
+
• fulfilments typename=fulfilments
|
|
29
|
+
• reviews typename=reviews
|
|
30
|
+
|
|
31
|
+
✓ ready — a write should succeed
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`status` asks the routing authority rather than sampling a read, because reads
|
|
35
|
+
resolve while writes are held — a plane with no database connected serves every
|
|
36
|
+
read and refuses every write. The verdict at the bottom is the whole page in one
|
|
37
|
+
line, and `--json` puts the same conclusion in a `blockers` array you can gate a
|
|
38
|
+
deploy on.
|
|
39
|
+
|
|
40
|
+
## The three ingredients
|
|
41
|
+
|
|
42
|
+
There is no Ablo service for you to deploy. Ablo is hosted, your rows live in
|
|
43
|
+
your own Postgres, and your app runs where it already runs — so a deployment is
|
|
44
|
+
three pieces pointed at the same plane.
|
|
45
|
+
|
|
46
|
+
| Ingredient | Who runs it | What "deploying" means for it |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| **Your Postgres** | You (or your provider) | Registering it against your production plane, once, with a production key. |
|
|
49
|
+
| **Ablo** | Hosted at `api.abloatai.com` | Nothing to run. You choose a project, a plane, and the keys that reach them. |
|
|
50
|
+
| **Your app and agents** | You | Holding the right credential for the runtime, and pushing the schema in the deploy. |
|
|
51
|
+
|
|
52
|
+
Everything below is those three in order.
|
|
53
|
+
|
|
54
|
+
### Planes: what a deployment targets
|
|
55
|
+
|
|
56
|
+
A **plane** is the isolation unit a credential acts on. `production` is the root
|
|
57
|
+
plane; every sandbox sits beside it. Three things are per-plane, and knowing
|
|
58
|
+
which three is most of what production readiness means:
|
|
59
|
+
|
|
60
|
+
- **Rows** — a sandbox write is invisible to production and to every other sandbox.
|
|
61
|
+
- **The registered database** — one per plane, so your production database and
|
|
62
|
+
your dev database are separate registrations.
|
|
63
|
+
- **The active schema artifact** — the model shapes the engine actually routes on.
|
|
64
|
+
|
|
65
|
+
A key's plane is fixed at mint and spelled in its prefix: `sk_live_` acts on
|
|
66
|
+
production, `sk_test_` on a sandbox. There is no runtime override — the
|
|
67
|
+
credential *is* the environment selector, which is why application code never
|
|
68
|
+
passes one.
|
|
69
|
+
|
|
70
|
+
One asymmetry is worth carrying into your deploy plan. A sandbox with no schema
|
|
71
|
+
artifact of its own reads **production's**, so a schema pushed to production
|
|
72
|
+
reaches your sandboxes automatically. The reverse does not hold: a push from a
|
|
73
|
+
sandbox key creates a sandbox artifact that shadows production **for that
|
|
74
|
+
sandbox's readers only**, and production keeps running the schema it was last
|
|
75
|
+
pushed. Production gets its models when you push to production.
|
|
76
|
+
|
|
77
|
+
## 1. The database production writes to
|
|
78
|
+
|
|
79
|
+
Your production database joins Ablo the same way your dev database did — logical
|
|
80
|
+
replication so Ablo can read and confirm, a scoped writer role so Ablo can land
|
|
81
|
+
rows — run once, with a production key so the registration attaches to the
|
|
82
|
+
production plane:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
ABLO_API_KEY=sk_live_… npx ablo connect apply --url postgres://admin:…@host:5432/db
|
|
86
|
+
ABLO_API_KEY=sk_live_… npx ablo connect check
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
[Connect Your Database](./data-sources.md) is the full walkthrough — the SQL, the
|
|
90
|
+
two roles, and the complete list of what Ablo touches. Five things about it are
|
|
91
|
+
specifically production concerns:
|
|
92
|
+
|
|
93
|
+
**Your agents do not each hold a connection.** Every agent, worker, and function
|
|
94
|
+
talks to Ablo, and Ablo holds the database connections — at most 4 connections
|
|
95
|
+
per plane, the same 4 whether one caller is writing behind them or ten thousand
|
|
96
|
+
are. They identify themselves as `ablo-direct-writer`, so `pg_stat_activity`
|
|
97
|
+
accounts for everything Ablo has open at any moment. Size the database for that
|
|
98
|
+
number rather than for your agent count.
|
|
99
|
+
|
|
100
|
+
**Register the direct host, not the pooler.** A pooler terminates the session
|
|
101
|
+
that replication needs, and it refuses the connection in the same words a wrong
|
|
102
|
+
password would — so a pooled host reads as a credentials problem for as long as
|
|
103
|
+
you let it. `ablo status` names a pooled host when it sees one, with the direct
|
|
104
|
+
host to use instead.
|
|
105
|
+
|
|
106
|
+
**Reachability is measured from Ablo's network, not yours.** `connect check`
|
|
107
|
+
runs from the infrastructure replication runs on, so an IPv6-only,
|
|
108
|
+
IP-allowlisted, or VPC-private database still verifies — and a database your
|
|
109
|
+
laptop can reach but Ablo cannot fails here rather than at the first write.
|
|
110
|
+
|
|
111
|
+
**`wal_level = logical` needs a restart.** It is server-wide and not reloadable.
|
|
112
|
+
On RDS and Aurora it is a parameter-group change plus a reboot. Schedule it;
|
|
113
|
+
it is the one setup step with downtime in it.
|
|
114
|
+
|
|
115
|
+
**A replication slot retains WAL.** While Ablo is connected the slot holds what
|
|
116
|
+
it has not yet acknowledged, so a long disconnection accumulates disk. Ablo
|
|
117
|
+
monitors slot lag and retention and surfaces it, and drops an abandoned slot
|
|
118
|
+
rather than letting it grow without bound.
|
|
119
|
+
|
|
120
|
+
A database that cannot grant a `REPLICATION` role connects through the signed
|
|
121
|
+
[Data Source endpoint](./data-sources.md) instead. Same model surface, same
|
|
122
|
+
commit chokepoint — it is the marked fallback, so reach for it when replication
|
|
123
|
+
is genuinely unavailable.
|
|
124
|
+
|
|
125
|
+
## 2. The credential each runtime holds
|
|
126
|
+
|
|
127
|
+
There is one field, `apiKey`, and what goes in it follows from where the code
|
|
128
|
+
runs. In production that resolves to four rows:
|
|
129
|
+
|
|
130
|
+
| Runtime | Credential | Notes |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| Server, worker, agent, cron | `sk_live_` in `ABLO_API_KEY` | Defaults from the environment, so most code passes nothing. |
|
|
133
|
+
| Serverless function | `sk_live_` in `ABLO_API_KEY`, with `transport: 'http'` | Stateless request/response; nothing held open across invocations. |
|
|
134
|
+
| Browser, read-only | `pk_live_` | Publishable and safe to ship, like a Stripe `pk_`. Reads only. |
|
|
135
|
+
| Browser, writing as the signed-in user | `authEndpoint` | A route on your backend mints a short-lived `ek_` per user. |
|
|
136
|
+
|
|
137
|
+
[API Keys](./api-keys.md) covers the model; [Sessions](./sessions.md) covers
|
|
138
|
+
minting. Two things bite specifically at deploy time.
|
|
139
|
+
|
|
140
|
+
**The live key `ablo login` gives you cannot push schema.** It is a restricted,
|
|
141
|
+
observe-only `rk_live_` by design, so a stolen CLI config cannot write to
|
|
142
|
+
production. A production deploy needs a **secret** `sk_live_` from the dashboard,
|
|
143
|
+
supplied as `ABLO_API_KEY`. You do not have to discover this from a failed
|
|
144
|
+
deploy: `ablo login`, `ablo mode production`, and `ablo status` each name what
|
|
145
|
+
the key in hand does, and `ablo status --json` reports it as `effectiveKey.kind`
|
|
146
|
+
for a pipeline to check before it pushes.
|
|
147
|
+
|
|
148
|
+
**An explicit key always wins.** The CLI resolves `ABLO_API_KEY`, then
|
|
149
|
+
`.env.local`, then `.env`, then the stored login — and `ablo status` prints which
|
|
150
|
+
one it found under `key`, with its source. When a deploy lands somewhere
|
|
151
|
+
surprising, that line is usually the answer.
|
|
152
|
+
|
|
153
|
+
## 3. Pushing the schema is a deploy step
|
|
154
|
+
|
|
155
|
+
The server keeps its own copy of your schema and routes on that copy. Until it
|
|
156
|
+
has yours, a write to a new model fails with `server_execute_unknown_model` — so
|
|
157
|
+
`ablo push` belongs in your deploy pipeline, ordered **before** the code that
|
|
158
|
+
depends on the new models goes live.
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
ABLO_API_KEY=sk_live_… npx ablo push --yes
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Production requires confirmation: interactively you type the destination
|
|
165
|
+
project's name, which is what makes a wrong-project deploy impossible to do by
|
|
166
|
+
reflex. In CI there is no TTY, so `--yes` is the confirmation and a push without
|
|
167
|
+
it stops rather than proceeding unattended.
|
|
168
|
+
|
|
169
|
+
**Additive changes pass; destructive ones ask.** Adding a model or an optional
|
|
170
|
+
field applies cleanly. Dropping a model or a field, narrowing an enum, or a lossy
|
|
171
|
+
cast is classified as data loss and needs `--force`; adding a required field to a
|
|
172
|
+
populated table needs a `--backfill`. A push that fails is recorded `failed` and
|
|
173
|
+
never activated, so a broken migration cannot leave clients gated against tables
|
|
174
|
+
that do not match.
|
|
175
|
+
|
|
176
|
+
This is the same expand-and-contract shape any online migration has, and it
|
|
177
|
+
sequences the same way: push the additive change, deploy the code that writes
|
|
178
|
+
both shapes, backfill, then push the removal in a later deploy once nothing reads
|
|
179
|
+
the old field.
|
|
180
|
+
|
|
181
|
+
**Drift is a connect-time rejection, not a runtime surprise.** A client built
|
|
182
|
+
against a schema the server is no longer running is turned away when it connects.
|
|
183
|
+
`ablo status` prints the local hash beside the deployed one, and the running
|
|
184
|
+
client reports the same `serverSchemaHash` value, so the two can be matched at a
|
|
185
|
+
glance.
|
|
186
|
+
|
|
187
|
+
## Gate the deploy on the verdict
|
|
188
|
+
|
|
189
|
+
`ablo status --json` reports the same conclusion the human output ends with, in a
|
|
190
|
+
form a pipeline can act on. An empty `blockers` array is the machine-readable
|
|
191
|
+
form of "ready":
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
blockers=$(ABLO_API_KEY=$ABLO_API_KEY npx ablo status --json | jq '.blockers | length')
|
|
195
|
+
[ "$blockers" -eq 0 ] || { npx ablo status; exit 1; }
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Each blocker carries a `problem` and the single `fix` that resolves it, in the
|
|
199
|
+
order you should act on them: an unreachable API makes every other finding
|
|
200
|
+
unverifiable, and a plane with nothing connected makes a schema question
|
|
201
|
+
academic. The JSON also carries `confirmedTarget` — the org, project, and
|
|
202
|
+
environment the server says this key resolves to — which is the authoritative
|
|
203
|
+
answer to where a push would land.
|
|
204
|
+
|
|
205
|
+
## Webhooks point at the deployed URL
|
|
206
|
+
|
|
207
|
+
`npx ablo dev` forwards commits to your machine while you build, the way
|
|
208
|
+
`stripe listen` does. A deployed endpoint is registered once, and Ablo returns
|
|
209
|
+
the signing secret a single time:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
ABLO_API_KEY=sk_live_… npx ablo webhooks create https://yourapp.com/api/ablo/[...all]
|
|
213
|
+
ABLO_API_KEY=sk_live_… npx ablo webhooks list # endpoints + delivery health
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`webhooks list` reports each endpoint's status, cursor, and last error — the
|
|
217
|
+
place to look when a mirror falls behind. [Webhooks](./webhooks.md) covers the
|
|
218
|
+
handler, the Standard Webhooks signature, and rolling a secret.
|
|
219
|
+
|
|
220
|
+
## What to watch once it is live
|
|
221
|
+
|
|
222
|
+
- **`ablo logs`** — commit activity as it happens, scoped by the key, so a live
|
|
223
|
+
key streams the org and a test key streams only its sandbox. `--json` emits
|
|
224
|
+
NDJSON for piping.
|
|
225
|
+
- **`ablo status`** — the readiness verdict. Cheap enough to run from a health
|
|
226
|
+
check on your own side.
|
|
227
|
+
- **The [audit log](./audit.md)** — every confirmed write traced back to the key
|
|
228
|
+
that made it and the person who authorized that key.
|
|
229
|
+
- **Your own logger** — pass `logger` to the client and SDK lifecycle, sync,
|
|
230
|
+
retry, and rollback events join your existing pipeline.
|
|
231
|
+
|
|
232
|
+
Writes carry receipts rather than being fire-and-forget: a commit is accepted the
|
|
233
|
+
moment Ablo takes it (`queued`) and becomes `confirmed` once the row appears on
|
|
234
|
+
your database's WAL. [Guarantees](./guarantees.md) covers which state to wait for
|
|
235
|
+
and what each promises.
|
|
236
|
+
|
|
237
|
+
## When something is wrong
|
|
238
|
+
|
|
239
|
+
| What you see | What it means | The fix |
|
|
240
|
+
|---|---|---|
|
|
241
|
+
| `no database is connected to this plane` | Writes are held rather than routed. Reads still resolve, which is why a read probe stays quiet. | `ablo connect apply` with a key for that plane. |
|
|
242
|
+
| `password authentication failed` during connect | Often a pooled host refusing a session it cannot serve, in the words of a wrong password. | Register the direct database host. |
|
|
243
|
+
| `server_execute_unknown_model` | The plane's active schema does not carry that model. | `ablo push` with a key for that plane. |
|
|
244
|
+
| Clients rejected at connect | The deployed schema and the client's schema disagree. | Push this tree, or deploy the revision the server is running. |
|
|
245
|
+
| `project_scope_denied` (403) | The model belongs to another project in your org. | Use a key minted for that project — a push cannot cross projects. |
|
|
246
|
+
| 403 on `ablo push` | The key authenticated but cannot author schema. | A secret `sk_live_`; the `ablo login` live key is observe-only. |
|
|
247
|
+
|
|
248
|
+
## The checklist
|
|
249
|
+
|
|
250
|
+
1. Production database registered against the production plane, direct host, and
|
|
251
|
+
`ablo connect check` all green.
|
|
252
|
+
2. A secret `sk_live_` in the deploy environment as `ABLO_API_KEY` — never in a
|
|
253
|
+
browser bundle.
|
|
254
|
+
3. `ablo push --yes` in the pipeline, ahead of the code that needs the new models.
|
|
255
|
+
4. `ablo status --json` gating the deploy on an empty `blockers` array.
|
|
256
|
+
5. Browser clients on a `pk_live_` or an `authEndpoint`, not a secret key.
|
|
257
|
+
6. Webhook endpoints registered at their deployed URLs, with the signing secret
|
|
258
|
+
in your environment.
|
|
259
|
+
|
|
260
|
+
## Next steps
|
|
261
|
+
|
|
262
|
+
- [Connect Your Database](./data-sources.md) — the setup this page registers, in full.
|
|
263
|
+
- [Projects](./projects.md) — one org, many apps, each with its own planes and keys.
|
|
264
|
+
- [API Keys](./api-keys.md) — which credential each runtime holds, and what it may do.
|
|
265
|
+
- [CLI](./cli.md) — every command, its flags, and the environment variables.
|
|
266
|
+
- [Operating on Your Database](./operating-on-your-database.md) — which actions run freely and which belong to a human.
|
|
267
|
+
- [Debugging & Logs](./debugging.md) — watching claims, queueing, and grants while you build.
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
# Agent + Human
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> An agent that yields the row when a person is already holding it.
|
|
4
|
+
|
|
5
|
+
A task-writing agent that yields when a person is editing the same task.
|
|
4
6
|
|
|
5
7
|
## Scenario
|
|
6
8
|
|
|
7
|
-
The same
|
|
9
|
+
The same tasks are edited by agents and by the people watching them. They must
|
|
10
|
+
not collide:
|
|
8
11
|
|
|
9
|
-
- If a
|
|
12
|
+
- If a person already holds the row, the agent yields instead of fighting for it.
|
|
10
13
|
- While the agent is updating, the UI can show who is active.
|
|
11
|
-
- If the
|
|
12
|
-
|
|
14
|
+
- If the task changes mid-run, the commit is rejected instead of overwriting the
|
|
15
|
+
newer edit.
|
|
13
16
|
|
|
14
17
|
A **claim** does both jobs. Claims don't lock — if another writer holds the row,
|
|
15
18
|
`claim` waits for them, re-reads the fresh row, then hands it back to you on
|
|
@@ -21,70 +24,74 @@ a typed error if the row moved underneath you while the agent was busy.
|
|
|
21
24
|
|
|
22
25
|
## Schema-Backed Worker
|
|
23
26
|
|
|
24
|
-
The worker uses the same schema client the app uses. It reads the
|
|
25
|
-
|
|
26
|
-
`ablo.
|
|
27
|
-
|
|
27
|
+
The worker uses the same schema client the app uses. It reads the task from the
|
|
28
|
+
server with `retrieve({ id })`, claims the row, and writes through
|
|
29
|
+
`ablo.tasks.update(...)` with a stale-check so a concurrent edit can't be
|
|
30
|
+
overwritten.
|
|
28
31
|
|
|
29
32
|
```ts
|
|
30
33
|
import Ablo, { AbloClaimedError, AbloStaleContextError } from '@abloatai/ablo';
|
|
31
34
|
import { defineSchema, model, z } from '@abloatai/ablo/schema';
|
|
32
35
|
|
|
33
36
|
const schema = defineSchema({
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
status: z.enum(['
|
|
37
|
+
tasks: model({
|
|
38
|
+
title: z.string(),
|
|
39
|
+
status: z.enum(['todo', 'doing', 'done']),
|
|
37
40
|
}),
|
|
38
41
|
});
|
|
39
42
|
|
|
40
|
-
const ablo = Ablo({
|
|
43
|
+
const ablo = Ablo({
|
|
44
|
+
schema,
|
|
45
|
+
apiKey: process.env.ABLO_API_KEY,
|
|
46
|
+
transport: 'http',
|
|
47
|
+
});
|
|
41
48
|
|
|
42
|
-
export async function
|
|
49
|
+
export async function markDone(taskId: string) {
|
|
43
50
|
await ablo.ready();
|
|
44
51
|
|
|
45
52
|
// retrieve({ id }) is an async server read — await it.
|
|
46
|
-
const
|
|
47
|
-
if (!
|
|
53
|
+
const task = await ablo.tasks.retrieve({ id: taskId });
|
|
54
|
+
if (!task) return { status: 'not_found' };
|
|
48
55
|
|
|
49
56
|
try {
|
|
50
|
-
// queue: false → don't queue behind a current holder. If
|
|
57
|
+
// queue: false → don't queue behind a current holder. If someone already
|
|
51
58
|
// holds the row, claim rejects with AbloClaimedError (caught below), so the
|
|
52
59
|
// agent yields instead of waiting. Omit it, or pass queue: true, to queue
|
|
53
60
|
// behind them. description → the label observers see while we work.
|
|
54
|
-
await using claim = await ablo.
|
|
55
|
-
id:
|
|
61
|
+
await using claim = await ablo.tasks.claim({
|
|
62
|
+
id: taskId,
|
|
56
63
|
queue: false,
|
|
57
|
-
description: '
|
|
64
|
+
description: 'marking_done',
|
|
58
65
|
});
|
|
59
|
-
|
|
66
|
+
if (claim.data.status === 'done') return { status: 'noop' };
|
|
60
67
|
|
|
61
68
|
// Inside an active claim, `update` is stale-checked automatically: the SDK
|
|
62
69
|
// attaches the claim's snapshot version as `readAt` and sets
|
|
63
70
|
// `onStale: 'reject'`. The write below is therefore equivalent to passing
|
|
64
71
|
// those options yourself:
|
|
65
72
|
//
|
|
66
|
-
// ablo.
|
|
67
|
-
// id:
|
|
68
|
-
// data: { status: '
|
|
73
|
+
// ablo.tasks.update({
|
|
74
|
+
// id: claim.data.id,
|
|
75
|
+
// data: { status: 'done' },
|
|
69
76
|
// wait: 'confirmed',
|
|
70
77
|
// readAt: <claim snapshot version>,
|
|
71
78
|
// onStale: 'reject',
|
|
72
79
|
// });
|
|
73
80
|
//
|
|
74
|
-
// If a
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
const updated = await ablo.
|
|
78
|
-
id:
|
|
79
|
-
data: { status: '
|
|
81
|
+
// If a newer version landed mid-run, the row no longer matches `readAt`, so
|
|
82
|
+
// the server rejects this commit with AbloStaleContextError (caught below)
|
|
83
|
+
// instead of clobbering that edit.
|
|
84
|
+
const updated = await ablo.tasks.update({
|
|
85
|
+
id: claim.data.id,
|
|
86
|
+
data: { status: 'done' },
|
|
80
87
|
wait: 'confirmed',
|
|
81
88
|
});
|
|
82
89
|
|
|
83
|
-
return { status: '
|
|
90
|
+
return { status: 'done', task: updated };
|
|
84
91
|
} catch (err) {
|
|
85
|
-
//
|
|
92
|
+
// Someone already holds the row — yield this run and let them finish.
|
|
86
93
|
if (err instanceof AbloClaimedError) return { status: 'yielded' };
|
|
87
|
-
// A
|
|
94
|
+
// A newer version was saved while we held the claim. The stale-check
|
|
88
95
|
// rejected our commit, so nothing was overwritten — re-run on fresh data.
|
|
89
96
|
if (err instanceof AbloStaleContextError) return { status: 'stale' };
|
|
90
97
|
throw err;
|
|
@@ -101,14 +108,14 @@ Keep workers on the same schema-backed client as the app.
|
|
|
101
108
|
|
|
102
109
|
import { useAblo } from '@abloatai/ablo/react';
|
|
103
110
|
|
|
104
|
-
export function
|
|
105
|
-
const data = useAblo((ablo) => ablo.
|
|
106
|
-
const
|
|
107
|
-
const agentActive =
|
|
111
|
+
export function TaskRow({ task: serverTask }: Props) {
|
|
112
|
+
const data = useAblo((ablo) => ablo.tasks.local.retrieve(serverTask.id)) ?? serverTask;
|
|
113
|
+
const holder = useAblo((ablo) => ablo.tasks.claim.state({ id: serverTask.id }));
|
|
114
|
+
const agentActive = holder?.participantKind === 'agent';
|
|
108
115
|
|
|
109
116
|
return (
|
|
110
117
|
<div>
|
|
111
|
-
<span>{data.
|
|
118
|
+
<span>{data.title}</span>
|
|
112
119
|
{agentActive ? <span>Agent is updating...</span> : null}
|
|
113
120
|
</div>
|
|
114
121
|
);
|
|
@@ -120,9 +127,9 @@ export function ReportRow({ report: serverReport }: Props) {
|
|
|
120
127
|
- The claim is visible to everyone: the UI reads it synchronously with
|
|
121
128
|
`claim.state({ id })`, and it also arrives over the live stream.
|
|
122
129
|
- `claim({ id })` makes writers take turns instead of racing — with
|
|
123
|
-
`queue: false`, the agent simply yields when
|
|
124
|
-
- The `update` made while the claim is held is stale-checked automatically, so
|
|
130
|
+
`queue: false`, the agent simply yields when someone already holds the row.
|
|
131
|
+
- The `update` made while the claim is held is stale-checked automatically, so an
|
|
125
132
|
edit landing mid-run rejects the agent's write with a typed
|
|
126
133
|
`AbloStaleContextError` instead of overwriting it.
|
|
127
|
-
- That same write carries the claim, so each accepted change is attributed to
|
|
128
|
-
|
|
134
|
+
- That same write carries the claim, so each accepted change is attributed to the
|
|
135
|
+
run that made it.
|