@abloatai/ablo 0.34.1 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -1
- package/CHANGELOG.md +758 -5
- package/README.md +56 -502
- package/bin/ablo.cjs +39 -0
- package/dist/BaseSyncedStore.d.ts +176 -48
- package/dist/BaseSyncedStore.js +346 -214
- package/dist/Database.d.ts +17 -44
- package/dist/Database.js +96 -79
- package/dist/InstanceCache.d.ts +31 -6
- package/dist/InstanceCache.js +65 -30
- package/dist/LazyReferenceCollection.d.ts +3 -3
- package/dist/LazyReferenceCollection.js +4 -4
- package/dist/Model.d.ts +23 -13
- package/dist/Model.js +27 -17
- package/dist/ModelRegistry.d.ts +8 -4
- package/dist/ModelRegistry.js +20 -18
- package/dist/NetworkMonitor.d.ts +3 -1
- package/dist/NetworkMonitor.js +7 -5
- package/dist/{SyncEngineContext.d.ts → RuntimeContext.d.ts} +20 -13
- package/dist/{SyncEngineContext.js → RuntimeContext.js} +11 -12
- package/dist/SyncClient.d.ts +47 -47
- package/dist/SyncClient.js +215 -156
- package/dist/ai-sdk/coordinatedTool.d.ts +2 -2
- package/dist/ai-sdk/coordinatedTool.js +1 -1
- package/dist/ai-sdk/coordinationContext.d.ts +2 -2
- package/dist/ai-sdk/coordinationContext.js +1 -1
- package/dist/ai-sdk/wrap.d.ts +3 -3
- package/dist/ai-sdk/wrap.js +2 -2
- package/dist/auth/index.d.ts +1 -156
- package/dist/auth/index.js +8 -301
- package/dist/client/Ablo.d.ts +42 -287
- package/dist/client/Ablo.js +129 -963
- package/dist/client/abloClient.d.ts +309 -0
- package/dist/client/abloClient.js +13 -0
- package/dist/client/clientPrelude.d.ts +52 -0
- package/dist/client/clientPrelude.js +60 -0
- package/dist/client/consoleLogger.d.ts +2 -2
- package/dist/client/coreClient.d.ts +60 -0
- package/dist/client/coreClient.js +118 -0
- package/dist/client/createInternalComponents.d.ts +8 -4
- package/dist/client/createInternalComponents.js +17 -10
- package/dist/client/createModelProxy.d.ts +98 -373
- package/dist/client/createModelProxy.js +233 -139
- package/dist/client/humans.d.ts +69 -0
- package/dist/client/humans.js +78 -0
- package/dist/client/modelRegistration.d.ts +1 -1
- package/dist/client/modelRegistration.js +9 -9
- package/dist/client/options.d.ts +73 -17
- package/dist/client/reactiveEngine.d.ts +53 -0
- package/dist/client/reactiveEngine.js +688 -0
- package/dist/client/resourceTypes.d.ts +9 -250
- package/dist/client/resourceTypes.js +8 -5
- package/dist/client/schemaConfig.d.ts +4 -4
- package/dist/client/schemaConfig.js +6 -2
- package/dist/client/storeCluster.d.ts +47 -0
- package/dist/client/storeCluster.js +118 -0
- package/dist/client/storeLifecycle.d.ts +61 -0
- package/dist/client/storeLifecycle.js +231 -0
- package/dist/client/validateAbloOptions.d.ts +3 -2
- package/dist/client/validateAbloOptions.js +1 -1
- package/dist/client/wsMutationExecutor.d.ts +3 -3
- package/dist/client/wsMutationExecutor.js +3 -3
- package/dist/context.d.ts +22 -9
- package/dist/context.js +33 -9
- package/dist/coordination/ClaimLog.d.ts +26 -0
- package/dist/coordination/ClaimLog.js +32 -0
- package/dist/coordination/index.d.ts +1 -15
- package/dist/coordination/index.js +8 -31
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +2 -2
- package/dist/docs/catalog.d.ts +72 -0
- package/dist/docs/catalog.js +230 -0
- package/dist/docs/index.d.ts +10 -0
- package/dist/docs/index.js +10 -0
- package/dist/environment.d.ts +1 -40
- package/dist/environment.js +8 -37
- package/dist/index.d.ts +44 -36
- package/dist/index.js +30 -22
- package/dist/interfaces/index.d.ts +44 -134
- package/dist/keys/index.d.ts +1 -77
- package/dist/keys/index.js +8 -190
- package/dist/mutators/{RecordingTransaction.d.ts → RecordingMutation.d.ts} +4 -4
- package/dist/mutators/{RecordingTransaction.js → RecordingMutation.js} +2 -2
- package/dist/mutators/Transaction.d.ts +1 -1
- package/dist/mutators/Transaction.js +1 -1
- package/dist/mutators/UndoManager.d.ts +6 -6
- package/dist/mutators/UndoManager.js +5 -5
- package/dist/mutators/defineMutators.d.ts +3 -3
- package/dist/mutators/defineMutators.js +1 -1
- package/dist/mutators/inverseOp.js +2 -2
- package/dist/mutators/mutateActions.d.ts +3 -3
- package/dist/mutators/mutateActions.js +1 -1
- package/dist/mutators/readerActions.d.ts +1 -1
- package/dist/mutators/undoApply.d.ts +1 -1
- package/dist/mutators/undoApply.js +1 -1
- package/dist/policy/index.d.ts +2 -2
- package/dist/policy/index.js +1 -1
- package/dist/query/client.d.ts +5 -2
- package/dist/query/client.js +10 -9
- package/dist/query/types.d.ts +6 -41
- package/dist/query/types.js +2 -2
- package/dist/react/AbloProvider.d.ts +18 -8
- package/dist/react/AbloProvider.js +10 -9
- package/dist/react/context.d.ts +3 -3
- package/dist/react/context.js +1 -1
- package/dist/react/createAbloReact.d.ts +56 -0
- package/dist/react/createAbloReact.js +51 -0
- package/dist/react/index.d.ts +6 -5
- package/dist/react/index.js +6 -3
- package/dist/react/internalContext.d.ts +1 -1
- package/dist/react/useAblo.d.ts +12 -5
- package/dist/react/useAblo.js +26 -8
- package/dist/react/useCurrentUserId.js +1 -1
- package/dist/react/useErrorListener.js +1 -1
- package/dist/react/useMutationFailureListener.d.ts +2 -2
- package/dist/react/useMutationFailureListener.js +1 -1
- package/dist/react/useMutators.d.ts +3 -3
- package/dist/react/useMutators.js +3 -3
- package/dist/react/useUndoScope.d.ts +5 -5
- package/dist/react/useUndoScope.js +1 -1
- package/dist/schema/coordination.d.ts +69 -10
- package/dist/schema/coordination.js +90 -9
- package/dist/schema/ddl.js +2 -2
- package/dist/schema/diff.d.ts +1 -1
- package/dist/schema/generate.js +1 -1
- package/dist/schema/index.d.ts +11 -10
- package/dist/schema/index.js +22 -18
- package/dist/schema/queries.d.ts +27 -27
- package/dist/schema/queries.js +23 -23
- package/dist/schema/select.d.ts +3 -3
- package/dist/schema/select.js +6 -3
- package/dist/schema/serialize.d.ts +15 -6
- package/dist/schema/serialize.js +20 -3
- package/dist/schema/sugar.d.ts +6 -7
- package/dist/schema/sugar.js +9 -12
- package/dist/schema/syncDeltaRow.d.ts +4 -152
- package/dist/schema/syncDeltaRow.js +4 -105
- package/dist/server/adapter.d.ts +18 -1
- package/dist/server/commit.d.ts +10 -16
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/readConfig.d.ts +1 -1
- package/dist/source/adapter.d.ts +7 -5
- package/dist/source/adapter.js +7 -5
- package/dist/source/adapters/drizzle.d.ts +1 -1
- package/dist/source/adapters/drizzle.js +2 -2
- package/dist/source/adapters/kysely.d.ts +1 -1
- package/dist/source/adapters/kysely.js +1 -1
- package/dist/source/adapters/kyselyMutationCore.d.ts +1 -1
- package/dist/source/adapters/kyselyMutationCore.js +2 -2
- package/dist/source/adapters/memory.js +1 -1
- package/dist/source/adapters/prisma.d.ts +8 -3
- package/dist/source/adapters/prisma.js +1 -1
- package/dist/source/connector.js +1 -1
- package/dist/source/connectorProtocol.d.ts +2 -8
- package/dist/source/connectorProtocol.js +3 -2
- package/dist/source/contract.d.ts +29 -17
- package/dist/source/contract.js +27 -22
- package/dist/source/factory.d.ts +1 -1
- package/dist/source/idempotency.js +2 -2
- package/dist/source/index.d.ts +1 -0
- package/dist/source/index.js +3 -0
- package/dist/source/next.d.ts +1 -1
- package/dist/source/signing.d.ts +9 -2
- package/dist/source/signing.js +4 -1
- package/dist/source/types.d.ts +6 -4
- package/dist/source/types.js +1 -1
- package/dist/{core/storeContract.d.ts → storeContract.d.ts} +6 -6
- package/dist/{core → stores}/DatabaseManager.d.ts +3 -1
- package/dist/{core → stores}/DatabaseManager.js +14 -13
- package/dist/stores/ObjectStore.d.ts +1 -1
- package/dist/{core → stores}/StoreManager.d.ts +9 -26
- package/dist/{core → stores}/StoreManager.js +29 -77
- package/dist/stores/SyncActionStore.d.ts +4 -2
- package/dist/stores/SyncActionStore.js +11 -17
- package/dist/stores/syncAction.d.ts +26 -0
- package/dist/stores/syncAction.js +16 -0
- package/dist/surface.d.ts +3 -3
- package/dist/surface.js +6 -4
- package/dist/sync/BootstrapFetcher.d.ts +127 -6
- package/dist/sync/BootstrapFetcher.js +511 -83
- package/dist/sync/ConnectionManager.d.ts +6 -198
- package/dist/sync/ConnectionManager.js +6 -677
- package/dist/sync/OnDemandLoader.d.ts +5 -2
- package/dist/sync/OnDemandLoader.js +61 -21
- package/dist/sync/SubscriptionManager.d.ts +13 -2
- package/dist/sync/SubscriptionManager.js +23 -5
- package/dist/sync/SyncWebSocket.d.ts +27 -510
- package/dist/sync/SyncWebSocket.js +76 -954
- package/dist/sync/awaitClaimGrant.d.ts +4 -44
- package/dist/sync/awaitClaimGrant.js +4 -109
- package/dist/sync/bootstrapApply.d.ts +3 -0
- package/dist/sync/bootstrapApply.js +2 -2
- package/dist/sync/commitFrames.d.ts +6 -40
- package/dist/sync/commitFrames.js +6 -97
- package/dist/sync/contextPorts.d.ts +18 -0
- package/dist/sync/contextPorts.js +31 -0
- package/dist/sync/createClaimStream.d.ts +5 -49
- package/dist/sync/createClaimStream.js +5 -469
- package/dist/sync/createPresenceStream.d.ts +26 -4
- package/dist/sync/createPresenceStream.js +28 -20
- package/dist/sync/createSnapshot.d.ts +2 -2
- package/dist/sync/createSnapshot.js +1 -1
- package/dist/sync/credentialLifecycle.d.ts +5 -173
- package/dist/sync/credentialLifecycle.js +5 -320
- package/dist/sync/deltaPipeline.d.ts +13 -12
- package/dist/sync/deltaPipeline.js +21 -4
- package/dist/sync/groupChange.d.ts +3 -0
- package/dist/sync/groupChange.js +16 -14
- package/dist/sync/participants.d.ts +24 -6
- package/dist/sync/participants.js +32 -23
- package/dist/sync/schemaDrift.d.ts +55 -0
- package/dist/sync/schemaDrift.js +53 -0
- package/dist/sync/schemas.d.ts +23 -33
- package/dist/sync/schemas.js +29 -20
- package/dist/sync/syncPlan.d.ts +3 -3
- package/dist/sync/wsFrameHandlers.d.ts +6 -114
- package/dist/sync/wsFrameHandlers.js +6 -392
- package/dist/syncLog/contract.d.ts +20 -0
- package/dist/syncLog/contract.js +19 -0
- package/dist/syncLog/index.d.ts +1 -0
- package/dist/syncLog/index.js +1 -0
- package/dist/transaction/ablo.d.ts +88 -0
- package/dist/transaction/ablo.js +33 -0
- package/dist/{client/auth.d.ts → transaction/auth/apiKey.d.ts} +43 -8
- package/dist/{client/auth.js → transaction/auth/apiKey.js} +19 -0
- package/dist/transaction/auth/bootstrapScope.d.ts +15 -0
- package/dist/transaction/auth/bootstrapScope.js +1 -0
- package/dist/transaction/auth/capability.d.ts +212 -0
- package/dist/transaction/auth/capability.js +224 -0
- package/dist/{auth → transaction/auth}/credentialSource.d.ts +8 -1
- package/dist/{client → transaction/auth}/identity.d.ts +8 -7
- package/dist/{client → transaction/auth}/identity.js +1 -1
- package/dist/transaction/auth/index.d.ts +162 -0
- package/dist/transaction/auth/index.js +304 -0
- package/dist/{auth → transaction/auth}/schemas.d.ts +1 -1
- package/dist/{auth → transaction/auth}/schemas.js +13 -13
- package/dist/{client → transaction/auth}/sessionMint.d.ts +8 -8
- package/dist/{client → transaction/auth}/sessionMint.js +4 -7
- package/dist/transaction/coordination/awaitClaimGrant.d.ts +56 -0
- package/dist/transaction/coordination/awaitClaimGrant.js +124 -0
- package/dist/{client → transaction/coordination}/claimHeartbeatLoop.d.ts +34 -0
- package/dist/{client → transaction/coordination}/claimHeartbeatLoop.js +20 -0
- package/dist/transaction/coordination/claimMeta.d.ts +49 -0
- package/dist/transaction/coordination/claimMeta.js +52 -0
- package/dist/transaction/coordination/createClaimStream.d.ts +64 -0
- package/dist/transaction/coordination/createClaimStream.js +475 -0
- package/dist/transaction/coordination/events.d.ts +74 -0
- package/dist/transaction/coordination/events.js +7 -0
- package/dist/transaction/coordination/index.d.ts +19 -0
- package/dist/transaction/coordination/index.js +45 -0
- package/dist/transaction/coordination/locator.d.ts +104 -0
- package/dist/transaction/coordination/locator.js +102 -0
- package/dist/transaction/coordination/schema.d.ts +1536 -0
- package/dist/transaction/coordination/schema.js +1177 -0
- package/dist/transaction/coordination/targetConflict.d.ts +2 -0
- package/dist/transaction/coordination/targetConflict.js +107 -0
- package/dist/{coordination → transaction/coordination}/trace.d.ts +7 -18
- package/dist/{coordination → transaction/coordination}/trace.js +18 -25
- package/dist/transaction/durableWrites.d.ts +62 -0
- package/dist/{client → transaction}/durableWrites.js +28 -3
- package/dist/transaction/environment.d.ts +105 -0
- package/dist/transaction/environment.js +108 -0
- package/dist/{errorCodes.d.ts → transaction/errorCodes.d.ts} +12 -12
- package/dist/{errorCodes.js → transaction/errorCodes.js} +45 -18
- package/dist/{errors.d.ts → transaction/errors.d.ts} +37 -13
- package/dist/{errors.js → transaction/errors.js} +85 -16
- package/dist/transaction/footprint.d.ts +111 -0
- package/dist/transaction/footprint.js +0 -0
- package/dist/transaction/index.d.ts +20 -0
- package/dist/transaction/index.js +20 -0
- package/dist/transaction/keys/index.d.ts +87 -0
- package/dist/transaction/keys/index.js +207 -0
- package/dist/transaction/log/syncDeltaRow.d.ts +158 -0
- package/dist/transaction/log/syncDeltaRow.js +95 -0
- package/dist/{sync/syncPosition.d.ts → transaction/logPosition.d.ts} +22 -8
- package/dist/{sync/syncPosition.js → transaction/logPosition.js} +15 -6
- package/dist/transaction/logger.d.ts +16 -0
- package/dist/transaction/logger.js +7 -0
- package/dist/transaction/observability.d.ts +53 -0
- package/dist/transaction/observability.js +19 -0
- package/dist/transaction/plugin.d.ts +285 -0
- package/dist/transaction/plugin.js +106 -0
- package/dist/{policy → transaction/policy}/types.d.ts +3 -3
- package/dist/{policy → transaction/policy}/types.js +2 -0
- package/dist/transaction/resources/httpResources.d.ts +321 -0
- package/dist/transaction/resources/httpResources.js +7 -0
- package/dist/transaction/resources/modelOperations.d.ts +427 -0
- package/dist/transaction/resources/modelOperations.js +12 -0
- package/dist/transaction/resources/mutationOptions.d.ts +66 -0
- package/dist/transaction/resources/mutationOptions.js +9 -0
- package/dist/transaction/resources/where.d.ts +101 -0
- package/dist/transaction/resources/where.js +115 -0
- package/dist/{client → transaction/resources}/writeOptionsSchema.d.ts +2 -6
- package/dist/{client → transaction/resources}/writeOptionsSchema.js +9 -5
- package/dist/{schema → transaction/schema}/field.d.ts +17 -23
- package/dist/{schema → transaction/schema}/field.js +5 -5
- package/dist/transaction/schema/fieldRef.d.ts +38 -0
- package/dist/transaction/schema/fieldRef.js +11 -0
- package/dist/transaction/schema/loadStrategy.d.ts +45 -0
- package/dist/transaction/schema/loadStrategy.js +46 -0
- package/dist/{schema → transaction/schema}/model.d.ts +50 -35
- package/dist/{schema → transaction/schema}/model.js +30 -20
- package/dist/transaction/schema/openapi.d.ts +58 -0
- package/dist/transaction/schema/openapi.js +501 -0
- package/dist/{schema → transaction/schema}/relation.d.ts +21 -16
- package/dist/{schema → transaction/schema}/relation.js +7 -7
- package/dist/{schema → transaction/schema}/residency.d.ts +0 -9
- package/dist/{schema → transaction/schema}/residency.js +0 -5
- package/dist/{schema → transaction/schema}/roles.d.ts +5 -5
- package/dist/{schema → transaction/schema}/roles.js +5 -5
- package/dist/{schema → transaction/schema}/schema.d.ts +39 -10
- package/dist/{schema → transaction/schema}/schema.js +24 -3
- package/dist/{schema → transaction/schema}/tenancy.d.ts +1 -1
- package/dist/{schema → transaction/schema}/tenancy.js +7 -4
- package/dist/transaction/transactionLayer.d.ts +82 -0
- package/dist/transaction/transactionLayer.js +24 -0
- package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.d.ts +5 -6
- package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.js +9 -13
- package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.d.ts +9 -2
- package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.js +5 -9
- package/dist/{transactions/durableWriteStore.d.ts → transaction/transactions/settlement/pendingWrite.d.ts} +11 -37
- package/dist/transaction/transactions/settlement/pendingWrite.js +20 -0
- package/dist/transaction/transport/commitFrames.d.ts +90 -0
- package/dist/transaction/transport/commitFrames.js +134 -0
- package/dist/transaction/transport/connectionManager.d.ts +215 -0
- package/dist/transaction/transport/connectionManager.js +673 -0
- package/dist/transaction/transport/credentialLifecycle.d.ts +177 -0
- package/dist/transaction/transport/credentialLifecycle.js +324 -0
- package/dist/{sync → transaction/transport}/heartbeat.d.ts +3 -1
- package/dist/{sync → transaction/transport}/heartbeat.js +6 -4
- package/dist/transaction/transport/httpClient.d.ts +131 -0
- package/dist/{client → transaction/transport}/httpClient.js +6 -5
- package/dist/transaction/transport/httpOptions.d.ts +33 -0
- package/dist/transaction/transport/httpOptions.js +12 -0
- package/dist/{client → transaction/transport}/httpTransport.js +295 -97
- package/dist/{sync/NetworkProbe.d.ts → transaction/transport/networkProbe.d.ts} +7 -4
- package/dist/{sync/NetworkProbe.js → transaction/transport/networkProbe.js} +14 -13
- package/dist/transaction/transport/wsFrameHandlers.d.ts +128 -0
- package/dist/transaction/transport/wsFrameHandlers.js +429 -0
- package/dist/transaction/transport/wsTransport.d.ts +574 -0
- package/dist/transaction/transport/wsTransport.js +1023 -0
- package/dist/transaction/types/assertExact.d.ts +17 -0
- package/dist/transaction/types/assertExact.js +1 -0
- package/dist/{types → transaction/types}/global.d.ts +17 -2
- package/dist/{types → transaction/types}/global.js +2 -1
- package/dist/{types → transaction/types}/index.d.ts +14 -46
- package/dist/{types → transaction/types}/index.js +7 -16
- package/dist/{types → transaction/types}/streams.d.ts +73 -45
- package/dist/transaction/utils/duration.d.ts +50 -0
- package/dist/{utils → transaction/utils}/duration.js +32 -0
- package/dist/{utils → transaction/utils}/json.d.ts +18 -0
- package/dist/transaction/utils/json.js +276 -0
- package/dist/transaction/wire/accountResponses.d.ts +420 -0
- package/dist/transaction/wire/accountResponses.js +290 -0
- package/dist/transaction/wire/auth.d.ts +56 -0
- package/dist/transaction/wire/auth.js +63 -0
- package/dist/transaction/wire/claimEvent.d.ts +76 -0
- package/dist/transaction/wire/claimEvent.js +73 -0
- package/dist/transaction/wire/claims.d.ts +530 -0
- package/dist/transaction/wire/claims.js +327 -0
- package/dist/{wire → transaction/wire}/commit.d.ts +125 -193
- package/dist/{wire → transaction/wire}/commit.js +68 -47
- package/dist/{wire → transaction/wire}/delta.d.ts +66 -17
- package/dist/{wire → transaction/wire}/delta.js +37 -13
- package/dist/transaction/wire/errorEnvelope.d.ts +72 -0
- package/dist/{wire → transaction/wire}/errorEnvelope.js +36 -5
- package/dist/transaction/wire/feedCursor.d.ts +60 -0
- package/dist/transaction/wire/feedCursor.js +82 -0
- package/dist/transaction/wire/feedEvent.d.ts +204 -0
- package/dist/transaction/wire/feedEvent.js +65 -0
- package/dist/transaction/wire/frames.d.ts +194 -0
- package/dist/transaction/wire/frames.js +50 -0
- package/dist/transaction/wire/inboundFrames.d.ts +562 -0
- package/dist/transaction/wire/inboundFrames.js +116 -0
- package/dist/transaction/wire/index.d.ts +54 -0
- package/dist/transaction/wire/index.js +83 -0
- package/dist/{wire → transaction/wire}/listEnvelope.d.ts +13 -14
- package/dist/transaction/wire/listEnvelope.js +42 -0
- package/dist/transaction/wire/modelMutations.d.ts +31 -0
- package/dist/transaction/wire/modelMutations.js +52 -0
- package/dist/transaction/wire/modelResponses.d.ts +85 -0
- package/dist/transaction/wire/modelResponses.js +43 -0
- package/dist/transaction/wire/modelShape.d.ts +78 -0
- package/dist/transaction/wire/modelShape.js +74 -0
- package/dist/transactions/{TransactionQueue.d.ts → mutations/MutationQueue.d.ts} +85 -38
- package/dist/transactions/{TransactionQueue.js → mutations/MutationQueue.js} +141 -80
- package/dist/transactions/{TransactionStore.d.ts → mutations/MutationStore.d.ts} +8 -8
- package/dist/transactions/{TransactionStore.js → mutations/MutationStore.js} +2 -2
- package/dist/transactions/{coalesceRules.d.ts → mutations/coalesceRules.d.ts} +10 -10
- package/dist/transactions/{coalesceRules.js → mutations/coalesceRules.js} +1 -1
- package/dist/transactions/mutations/commitLatency.d.ts +52 -0
- package/dist/transactions/mutations/commitLatency.js +130 -0
- package/dist/transactions/{commitOutboxStore.d.ts → mutations/commitOutboxStore.d.ts} +1 -5
- package/dist/transactions/{commitOutboxStore.js → mutations/commitOutboxStore.js} +1 -1
- package/dist/transactions/{commitPayload.d.ts → mutations/commitPayload.d.ts} +18 -16
- package/dist/transactions/{commitPayload.js → mutations/commitPayload.js} +15 -15
- package/dist/transactions/{deltaConfirmation.d.ts → mutations/deltaConfirmation.d.ts} +15 -11
- package/dist/transactions/{deltaConfirmation.js → mutations/deltaConfirmation.js} +14 -12
- package/dist/transactions/mutations/durableWriteStore.d.ts +14 -0
- package/dist/transactions/mutations/durableWriteStore.js +12 -0
- package/dist/transactions/{optimisticApply.d.ts → mutations/optimisticApply.d.ts} +7 -7
- package/dist/transactions/{replayValidation.d.ts → mutations/replayValidation.d.ts} +4 -3
- package/dist/transactions/{replayValidation.js → mutations/replayValidation.js} +7 -5
- package/dist/utils/mobxSetup.d.ts +1 -1
- package/dist/utils/mobxSetup.js +5 -2
- package/dist/{core → views}/QueryView.d.ts +2 -2
- package/dist/{core → views}/QueryView.js +2 -2
- package/dist/{core → views}/ViewRegistry.d.ts +1 -1
- package/dist/{core/queryUtils.d.ts → views/incrementalView.d.ts} +6 -6
- package/dist/{core/queryUtils.js → views/incrementalView.js} +6 -6
- package/dist/webhooks/events.d.ts +2 -2
- package/dist/wire/index.d.ts +1 -34
- package/dist/wire/index.js +8 -49
- package/docs/agent-messaging.md +3 -3
- package/docs/agents.md +20 -13
- package/docs/api-keys.md +14 -10
- package/docs/api.md +27 -61
- package/docs/audit.md +6 -3
- package/docs/cli.md +41 -13
- package/docs/client-behavior.md +11 -9
- package/docs/concurrency-convention.md +49 -57
- package/docs/coordination.md +283 -121
- package/docs/data-sources.md +7 -5
- package/docs/debugging.md +39 -15
- package/docs/deployment.md +267 -0
- package/docs/examples/agent-human.md +49 -42
- package/docs/examples/ai-sdk-tool.md +69 -44
- package/docs/examples/existing-python-backend.md +8 -6
- package/docs/examples/nextjs.md +129 -47
- package/docs/examples/scoped-agent.md +46 -45
- package/docs/examples/server-agent.md +46 -26
- package/docs/groups.md +87 -30
- package/docs/guarantees.md +41 -12
- package/docs/how-it-works.md +38 -12
- package/docs/idempotency.md +126 -0
- package/docs/identity.md +77 -74
- package/docs/index.md +172 -86
- package/docs/integration-guide.md +31 -19
- package/docs/mcp.md +46 -21
- package/docs/migration.md +95 -18
- package/docs/operating-on-your-database.md +3 -1
- package/docs/projects.md +3 -1
- package/docs/quickstart.md +22 -5
- package/docs/react.md +31 -18
- package/docs/schema-contract.md +5 -3
- package/docs/session-settings.md +108 -0
- package/docs/sessions.md +4 -2
- package/docs/webhooks.md +12 -10
- package/llms.txt +48 -18
- package/package.json +21 -26
- package/dist/agent/Agent.d.ts +0 -366
- package/dist/agent/Agent.js +0 -514
- package/dist/agent/index.d.ts +0 -115
- package/dist/agent/index.js +0 -128
- package/dist/agent/session.d.ts +0 -93
- package/dist/agent/session.js +0 -149
- package/dist/agent/types.d.ts +0 -68
- package/dist/agent/types.js +0 -9
- package/dist/cli.cjs +0 -286329
- package/dist/client/durableWrites.d.ts +0 -21
- package/dist/client/httpClient.d.ts +0 -80
- package/dist/coordination/schema.d.ts +0 -722
- package/dist/coordination/schema.js +0 -578
- package/dist/schema/openapi.d.ts +0 -29
- package/dist/schema/openapi.js +0 -124
- package/dist/testing/fixtures/bootstrap.d.ts +0 -49
- package/dist/testing/fixtures/bootstrap.js +0 -59
- package/dist/testing/fixtures/deltas.d.ts +0 -83
- package/dist/testing/fixtures/deltas.js +0 -136
- package/dist/testing/fixtures/models.d.ts +0 -83
- package/dist/testing/fixtures/models.js +0 -272
- package/dist/testing/helpers/reactWrapper.d.ts +0 -69
- package/dist/testing/helpers/reactWrapper.js +0 -67
- package/dist/testing/helpers/syncEngineHarness.d.ts +0 -54
- package/dist/testing/helpers/syncEngineHarness.js +0 -73
- package/dist/testing/helpers/wait.d.ts +0 -30
- package/dist/testing/helpers/wait.js +0 -49
- package/dist/testing/index.d.ts +0 -23
- package/dist/testing/index.js +0 -33
- package/dist/testing/mocks/FakeDatabase.d.ts +0 -18
- package/dist/testing/mocks/FakeDatabase.js +0 -10
- package/dist/testing/mocks/MockMutationExecutor.d.ts +0 -87
- package/dist/testing/mocks/MockMutationExecutor.js +0 -192
- package/dist/testing/mocks/MockNetworkMonitor.d.ts +0 -20
- package/dist/testing/mocks/MockNetworkMonitor.js +0 -46
- package/dist/testing/mocks/MockSyncContext.d.ts +0 -51
- package/dist/testing/mocks/MockSyncContext.js +0 -71
- package/dist/testing/mocks/MockSyncStore.d.ts +0 -88
- package/dist/testing/mocks/MockSyncStore.js +0 -171
- package/dist/testing/mocks/MockWebSocket.d.ts +0 -71
- package/dist/testing/mocks/MockWebSocket.js +0 -118
- package/dist/transactions/durableWriteStore.js +0 -30
- package/dist/utils/duration.d.ts +0 -25
- package/dist/utils/json.js +0 -88
- package/dist/wire/errorEnvelope.d.ts +0 -55
- package/dist/wire/frames.d.ts +0 -197
- package/dist/wire/frames.js +0 -49
- package/dist/wire/listEnvelope.js +0 -18
- package/docs/interaction-model.md +0 -97
- /package/dist/{core → query}/QueryProcessor.d.ts +0 -0
- /package/dist/{core → query}/QueryProcessor.js +0 -0
- /package/dist/{core/storeContract.js → storeContract.js} +0 -0
- /package/dist/{core → stores}/openIDBWithTimeout.d.ts +0 -0
- /package/dist/{core → stores}/openIDBWithTimeout.js +0 -0
- /package/dist/{client → transaction/auth}/credentialEndpoint.d.ts +0 -0
- /package/dist/{client → transaction/auth}/credentialEndpoint.js +0 -0
- /package/dist/{auth → transaction/auth}/credentialPolicy.d.ts +0 -0
- /package/dist/{auth → transaction/auth}/credentialPolicy.js +0 -0
- /package/dist/{auth → transaction/auth}/credentialSource.js +0 -0
- /package/dist/{client → transaction/auth}/hostedEndpoints.d.ts +0 -0
- /package/dist/{client → transaction/auth}/hostedEndpoints.js +0 -0
- /package/dist/{client → transaction}/persistence.d.ts +0 -0
- /package/dist/{client → transaction}/persistence.js +0 -0
- /package/dist/{client → transaction/resources}/functionalUpdate.d.ts +0 -0
- /package/dist/{client → transaction/resources}/functionalUpdate.js +0 -0
- /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.d.ts +0 -0
- /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.js +0 -0
- /package/dist/{client → transaction/transport}/httpTransport.d.ts +0 -0
- /package/dist/{types → transaction/types}/modelData.d.ts +0 -0
- /package/dist/{types → transaction/types}/modelData.js +0 -0
- /package/dist/{types → transaction/types}/participant.d.ts +0 -0
- /package/dist/{types → transaction/types}/participant.js +0 -0
- /package/dist/{types → transaction/types}/streams.js +0 -0
- /package/dist/{utils → transaction/utils}/asyncIterator.d.ts +0 -0
- /package/dist/{utils → transaction/utils}/asyncIterator.js +0 -0
- /package/dist/{wire → transaction/wire}/bootstrapReason.d.ts +0 -0
- /package/dist/{wire → transaction/wire}/bootstrapReason.js +0 -0
- /package/dist/{wire → transaction/wire}/protocol.d.ts +0 -0
- /package/dist/{wire → transaction/wire}/protocol.js +0 -0
- /package/dist/{wire → transaction/wire}/protocolVersion.d.ts +0 -0
- /package/dist/{wire → transaction/wire}/protocolVersion.js +0 -0
- /package/dist/transactions/{UnconfirmedWrites.d.ts → mutations/UnconfirmedWrites.d.ts} +0 -0
- /package/dist/transactions/{UnconfirmedWrites.js → mutations/UnconfirmedWrites.js} +0 -0
- /package/dist/transactions/{optimisticApply.js → mutations/optimisticApply.js} +0 -0
- /package/dist/{core → views}/ViewRegistry.js +0 -0
package/docs/identity.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Identity & Sync Groups
|
|
2
2
|
|
|
3
|
+
> Who is connecting, and which slice of state they are allowed to see.
|
|
4
|
+
|
|
3
5
|
This is the doc the Quickstart skips: **who is connecting, and which slice
|
|
4
6
|
of shared state do they get?** If you've wired `<AbloProvider client={ablo}>`
|
|
5
7
|
and wondered where org / team / user actually come from — start here.
|
|
@@ -20,11 +22,11 @@ that.
|
|
|
20
22
|
## What a sync group is
|
|
21
23
|
|
|
22
24
|
A **sync group** is a named channel of shared state — a string like
|
|
23
|
-
`org:acme` or `
|
|
25
|
+
`org:acme` or `workspace:abc123`. It is simultaneously:
|
|
24
26
|
|
|
25
|
-
- **the unit of fan-out
|
|
27
|
+
- **the unit of fan-out:** a confirmed write to a row publishes a delta to
|
|
26
28
|
every participant subscribed to that row's sync group(s), and
|
|
27
|
-
- **the unit of access
|
|
29
|
+
- **the unit of access:** a participant receives a row's deltas *only if* the
|
|
28
30
|
row's sync group is in their allowed set.
|
|
29
31
|
|
|
30
32
|
There is no built-in `org` / `team` / `user` concept in the engine. Those are
|
|
@@ -38,7 +40,7 @@ runnable place, so the concepts below have code to attach to.
|
|
|
38
40
|
The entire declaration surface is: `identityRoles` (who may see what), and on
|
|
39
41
|
each model `scope` / `parent` / `grants` (which group a row fans out on), plus
|
|
40
42
|
optional `syncGroups` at session-mint time (narrowing). Read the three blocks first —
|
|
41
|
-
a human gets their `org` / `team` scope, an agent gets one `
|
|
43
|
+
a human gets their `org` / `team` scope, an agent gets one `workspace` — then the
|
|
42
44
|
sections after explain each.
|
|
43
45
|
|
|
44
46
|
```ts
|
|
@@ -47,20 +49,18 @@ import { defineSchema, identityRole, relation, model, z } from '@abloatai/ablo/s
|
|
|
47
49
|
|
|
48
50
|
export const schema = defineSchema(
|
|
49
51
|
{
|
|
50
|
-
// A scope root: its rows form the group `
|
|
52
|
+
// A scope root: its rows form the group `workspace:<id>` (kind from `groups.root`).
|
|
51
53
|
// Tenant isolation defaults to a row-local `organization_id` column, so no
|
|
52
54
|
// `policy` is needed here.
|
|
53
|
-
|
|
55
|
+
workspaces: model(
|
|
54
56
|
{ title: z.string(), status: z.enum(['draft', 'published']) },
|
|
55
|
-
{},
|
|
56
|
-
{ groups: { root: 'deck' } },
|
|
57
|
+
{ groups: { root: 'workspace' } },
|
|
57
58
|
),
|
|
58
|
-
// A child: it has no group of its own; it inherits its
|
|
59
|
-
// `parent` edge. A write to a
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
{
|
|
63
|
-
{},
|
|
59
|
+
// A child: it has no group of its own; it inherits its workspace's group via the
|
|
60
|
+
// `parent` edge. A write to a document reaches everyone viewing the workspace.
|
|
61
|
+
documents: model(
|
|
62
|
+
{ workspaceId: z.string() },
|
|
63
|
+
{ relations: { workspace: relation.belongsTo('workspaces', 'workspaceId', { parent: true }) } },
|
|
64
64
|
),
|
|
65
65
|
},
|
|
66
66
|
{
|
|
@@ -88,12 +88,12 @@ export const schema = defineSchema(
|
|
|
88
88
|
// 3. an AGENT run inherits its user, narrowed to the entities in play.
|
|
89
89
|
// You narrow at SESSION-MINT time: your backend calls `sessions.create` with the
|
|
90
90
|
// agent's allowed `syncGroups`, built from each model's scope via the
|
|
91
|
-
// `syncGroup(kind, id)` helper — never a hand-built `
|
|
91
|
+
// `syncGroup(kind, id)` helper — never a hand-built `workspace:<id>` string. The agent's
|
|
92
92
|
// runtime then connects with the minted token.
|
|
93
93
|
const session = await server.sessions.create({
|
|
94
94
|
agent: { id: agentId },
|
|
95
|
-
can: {
|
|
96
|
-
syncGroups: [syncGroup('
|
|
95
|
+
can: { Workspace: ['read', 'update'] },
|
|
96
|
+
syncGroups: [syncGroup('workspace', workspaceId)], // floor: just the workspace it's working on
|
|
97
97
|
});
|
|
98
98
|
// the agent runtime authenticates with the minted token
|
|
99
99
|
const ablo = Ablo({ schema, apiKey: session.token });
|
|
@@ -101,29 +101,29 @@ const ablo = Ablo({ schema, apiKey: session.token });
|
|
|
101
101
|
|
|
102
102
|
That's the whole surface. The rest of this doc is the *why* behind each line.
|
|
103
103
|
|
|
104
|
-
## Two kinds of group
|
|
104
|
+
## Two kinds of group: the whole mental model
|
|
105
105
|
|
|
106
|
-
You just saw a human get `org` / `team` groups and an agent get one `
|
|
106
|
+
You just saw a human get `org` / `team` groups and an agent get one `workspace`
|
|
107
107
|
group. That split is the model. Every sync group is named after one of two
|
|
108
108
|
things:
|
|
109
109
|
|
|
110
|
-
- **Membership groups
|
|
110
|
+
- **Membership groups:** named after *who you are*: `org:{id}`, `team:{id}`,
|
|
111
111
|
`user:{id}`. Produced from **identity** (`identityRoles`, Half 1). They're
|
|
112
112
|
standing and durable — they don't change as you work.
|
|
113
|
-
- **Entity groups
|
|
114
|
-
`
|
|
113
|
+
- **Entity groups:** named after *a thing*: `dataroom:{id}`, `workspace:{id}`,
|
|
114
|
+
`document:{id}`. Produced from a **row's id** (a model's entity scope, Half 2).
|
|
115
115
|
They're granular — one per record — and any participant can be pointed at a
|
|
116
116
|
specific set of them.
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
different places.
|
|
120
|
-
|
|
121
|
-
so you
|
|
118
|
+
Agents and people fill that same space differently, and you declare the two in
|
|
119
|
+
different places. An agent's groups come from what it's working on right now, so
|
|
120
|
+
you pass them in code when you start the run. A person's groups come from who
|
|
121
|
+
they are, so you declare them once in the schema.
|
|
122
122
|
|
|
123
123
|
| | Subscribed by | Declared where | Gets |
|
|
124
124
|
| --- | --- | --- | --- |
|
|
125
|
-
| **Human** | *who they are
|
|
126
|
-
| **Agent** | *what it's been given
|
|
125
|
+
| **Human** | *who they are*: membership | **the schema** (`identityRoles`): a rule, written once | every `org` / `team` / `user` group their identity implies: their whole standing world |
|
|
126
|
+
| **Agent** | *what it's been given*: entities | **code, at the spawn site**: chosen per run | a handful of entity groups: the dataroom it's in, the documents it has read: never beyond what its user's membership could reach |
|
|
127
127
|
|
|
128
128
|
> **One line:** humans subscribe by who they are; agents subscribe by what
|
|
129
129
|
> they've been given.
|
|
@@ -135,9 +135,9 @@ depends on *what it's working on*, which is only knowable at dispatch — so you
|
|
|
135
135
|
pass its `syncGroups` **when your backend mints the agent session**
|
|
136
136
|
(`sessions.create({ agent, can, syncGroups })`). The schema's
|
|
137
137
|
only job for entities is to declare *that* a model is
|
|
138
|
-
entity-scopable and *what its group is named* (`scope: '
|
|
138
|
+
entity-scopable and *what its group is named* (`scope: 'workspace'` → `workspace:{id}`);
|
|
139
139
|
it never declares *which* entities a given agent gets. (A human can opt into the
|
|
140
|
-
same runtime narrowing — a page scoped to one
|
|
140
|
+
same runtime narrowing — a page scoped to one workspace — but by default a human's
|
|
141
141
|
scope is fully schema-derived.)
|
|
142
142
|
|
|
143
143
|
So an agent doesn't need a `user:{id}` standing grant. It's a participant pointed
|
|
@@ -197,7 +197,7 @@ Scoping is two declarations that meet in the middle. One describes the
|
|
|
197
197
|
(which group does this row belong to?). A participant sees a row **iff** the
|
|
198
198
|
row's sync group is in the participant's allowed set.
|
|
199
199
|
|
|
200
|
-
### Half 1
|
|
200
|
+
### Half 1 (`identityRoles`): identity → allowed groups
|
|
201
201
|
|
|
202
202
|
Declared once, on the schema, via the `identityRole({ kind, source })` factory.
|
|
203
203
|
Each role is **pure data**: a `kind` (the group's prefix — `org`, `user`, `team`)
|
|
@@ -212,7 +212,7 @@ import { defineSchema, identityRole, model, z } from '@abloatai/ablo/schema';
|
|
|
212
212
|
|
|
213
213
|
export const schema = defineSchema(
|
|
214
214
|
{
|
|
215
|
-
|
|
215
|
+
workspaces: model({
|
|
216
216
|
title: z.string(),
|
|
217
217
|
status: z.enum(['draft', 'published']),
|
|
218
218
|
}),
|
|
@@ -238,7 +238,7 @@ in-process and on a hosted server that only ever sees the compiled JSON.
|
|
|
238
238
|
> `user:{id}` role above already covers it — see
|
|
239
239
|
> [Agents are participants too](#agents-are-participants-too).
|
|
240
240
|
|
|
241
|
-
### Half 2
|
|
241
|
+
### Half 2 (per-model scope): row → group
|
|
242
242
|
|
|
243
243
|
You never write a sync-group string for a row. You declare a model's *place* in
|
|
244
244
|
the entity graph and the engine derives the groups its rows fan out on. Three
|
|
@@ -247,28 +247,30 @@ declarations, in order of how often you reach for them:
|
|
|
247
247
|
**`groups.root` — this model is a scope root.** Its rows form a group of their
|
|
248
248
|
own. The kind comes from the model's `typename` by default, or pass a string to
|
|
249
249
|
set it explicitly (use the string form when the wire kind differs from the
|
|
250
|
-
typename, e.g. typename `SlideDeck` but group `
|
|
250
|
+
typename, e.g. typename `SlideDeck` but group `workspace:<id>`):
|
|
251
251
|
|
|
252
252
|
```ts
|
|
253
|
-
|
|
254
|
-
// a
|
|
253
|
+
workspaces: model({ title: z.string() }, { groups: { root: 'workspace' } });
|
|
254
|
+
// a workspace row → group `workspace:<id>`
|
|
255
255
|
```
|
|
256
256
|
|
|
257
257
|
**`parent` — this row lives inside another entity.** Mark the `belongsTo` edge
|
|
258
258
|
to its owner; the row inherits that owner's group. This is the Zanzibar/ReBAC
|
|
259
259
|
*parent* relation — "access inherits from parent" — and it chains transitively
|
|
260
|
-
(a
|
|
260
|
+
(a block → its document → its workspace), so a write to any descendant reaches everyone
|
|
261
261
|
viewing the root. A *reference* (a provenance/template pointer, not ownership)
|
|
262
262
|
must **not** be marked `parent`, or the row would leak into an unrelated scope:
|
|
263
263
|
|
|
264
264
|
```ts
|
|
265
|
-
|
|
266
|
-
{
|
|
265
|
+
documents: model(
|
|
266
|
+
{ workspaceId: z.string(), sourceSlideId: z.string().optional() },
|
|
267
267
|
{
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
// default policy: row-local organization_id
|
|
269
|
+
relations: {
|
|
270
|
+
workspace: relation.belongsTo('workspaces', 'workspaceId', { parent: true }), // ownership → inherit workspace:<id>
|
|
271
|
+
sourceSlide: relation.belongsTo('documents', 'sourceSlideId'), // reference → NOT routed
|
|
272
|
+
},
|
|
270
273
|
},
|
|
271
|
-
{}, // default policy: row-local organization_id
|
|
272
274
|
);
|
|
273
275
|
```
|
|
274
276
|
|
|
@@ -288,10 +290,12 @@ org membership is already covered by the `org:` identity role.
|
|
|
288
290
|
dataroomMember: model(
|
|
289
291
|
{ userId: z.string(), dataroomId: z.string() },
|
|
290
292
|
{
|
|
291
|
-
|
|
292
|
-
|
|
293
|
+
relations: {
|
|
294
|
+
member: relation.belongsTo('users', 'userId'),
|
|
295
|
+
room: relation.belongsTo('datarooms', 'dataroomId'),
|
|
296
|
+
},
|
|
297
|
+
groups: { grants: { subject: 'member', scope: 'room' } },
|
|
293
298
|
},
|
|
294
|
-
{ groups: { grants: { subject: 'member', scope: 'room' } } },
|
|
295
299
|
);
|
|
296
300
|
```
|
|
297
301
|
|
|
@@ -306,7 +310,7 @@ options as `tenancy-option-removed` errors and steers you to `policy: { by:
|
|
|
306
310
|
explicit `policy: { by: 'none' }`. See
|
|
307
311
|
`packages/sync-engine/src/schema/model.ts` for the full option set.
|
|
308
312
|
|
|
309
|
-
## How identity reaches Ablo
|
|
313
|
+
## How identity reaches Ablo: the proxy model
|
|
310
314
|
|
|
311
315
|
This is the part the README's "authenticates with the signed-in user's
|
|
312
316
|
session" glossed over. Concretely:
|
|
@@ -396,9 +400,9 @@ What carries identity — and just as importantly, what does *not* set the bound
|
|
|
396
400
|
|
|
397
401
|
| Where | Purpose |
|
|
398
402
|
| ------------ | ------------------------------------------------------------------------------------------------ |
|
|
399
|
-
| `userId` prop | App-level participant id, used for app-owned fields and read by your `identityRole` `source`. **Not** the security boundary
|
|
403
|
+
| `userId` prop | App-level participant id, used for app-owned fields and read by your `identityRole` `source`. **Not** the security boundary: the server enforces scope from the authenticated request. |
|
|
400
404
|
| `teamIds` (on the client) | Team ids expanded into team sync groups via your `identityRoles`. |
|
|
401
|
-
| `syncGroups` (at session mint) | Optional. **Narrows** a minted session's subscription to a subset of what auth already allows
|
|
405
|
+
| `syncGroups` (at session mint) | Optional. **Narrows** a minted session's subscription to a subset of what auth already allows: it can never widen it. Passed to `sessions.create({ user \| agent, syncGroups })`; build entries with `syncGroup(kind, id)`. Use it to scope an agent (or a focused page's session) to one entity, e.g. `[syncGroup('workspace', 'abc123')]`. |
|
|
402
406
|
|
|
403
407
|
Because the server is the boundary, a client that changes `userId` to another
|
|
404
408
|
user's id does not gain their data — the server resolves and enforces the real
|
|
@@ -427,27 +431,27 @@ agent authority = (triggering user's allowed set) ← ceiling, inherited (on-
|
|
|
427
431
|
```
|
|
428
432
|
|
|
429
433
|
Concretely: each model an agent edits declares a `scope`
|
|
430
|
-
([Half 2](#half-2
|
|
434
|
+
([Half 2](#half-2-per-model-scope-row--group)), so each row forms its own
|
|
431
435
|
group. The agent subscribes only to the groups for the rows it touches. Declare
|
|
432
436
|
an entity anchor on the models an agent operates on:
|
|
433
437
|
|
|
434
438
|
```ts
|
|
435
439
|
// each scope-root model an agent edits forms a per-entity group
|
|
436
|
-
documents: model({ /* … */ }, {
|
|
437
|
-
|
|
440
|
+
documents: model({ /* … */ }, { groups: { root: 'document' } }),
|
|
441
|
+
workspaces: model({ /* … */ }, { groups: { root: 'workspace' } }),
|
|
438
442
|
```
|
|
439
443
|
|
|
440
444
|
Then a run subscribes only to the entity groups for the rows it works on — a
|
|
441
445
|
subset of what its user could see:
|
|
442
446
|
|
|
443
447
|
```ts
|
|
444
|
-
// agent run triggered by `user`, working on one document + one
|
|
448
|
+
// agent run triggered by `user`, working on one document + one workspace.
|
|
445
449
|
// Your backend mints the agent session narrowed to just the entities in play
|
|
446
450
|
// (the floor). Build each group from the model's scope with `syncGroup(kind, id)`.
|
|
447
451
|
const session = await server.sessions.create({
|
|
448
452
|
agent: { id: agentId },
|
|
449
|
-
can: { Document: ['read', 'update'],
|
|
450
|
-
syncGroups: [syncGroup('document', documentId), syncGroup('
|
|
453
|
+
can: { Document: ['read', 'update'], Workspace: ['read', 'update'] },
|
|
454
|
+
syncGroups: [syncGroup('document', documentId), syncGroup('workspace', workspaceId)],
|
|
451
455
|
});
|
|
452
456
|
// identity (the ceiling) is inherited from the triggering user via your
|
|
453
457
|
// session-mint logic; the agent runtime connects with the minted token.
|
|
@@ -471,29 +475,28 @@ not *what's reachable*.
|
|
|
471
475
|
Three rules make agent access safe, and they fall out of the model above rather
|
|
472
476
|
than needing a separate agent permission system:
|
|
473
477
|
|
|
474
|
-
- **Inherit the user, and no more
|
|
478
|
+
- **Inherit the user, and no more:** the OAuth
|
|
475
479
|
[on-behalf-of](https://workos.com/blog/oauth-on-behalf-of-ai-agents) model: the
|
|
476
480
|
agent's reach is tied to the consenting user, never the org.
|
|
477
|
-
- **Least privilege, just-in-time
|
|
481
|
+
- **Least privilege, just-in-time:** scoped to the task's entities, not standing
|
|
478
482
|
org-wide access (the over-privilege pattern
|
|
479
483
|
[OWASP's NHI Top 10](https://www.token.security/assets/the-ultimate-non-human-identity-security-guide)
|
|
480
484
|
flags as the dominant agent risk).
|
|
481
|
-
- **Dual-principal attribution
|
|
485
|
+
- **Dual-principal attribution:** record both the executing agent and the
|
|
482
486
|
triggering human.
|
|
483
487
|
|
|
484
488
|
Identity is 1:1 with a human participant; authority is narrowed to the work. That
|
|
485
489
|
split is what lets Ablo keep *one model API for every actor* without ever
|
|
486
490
|
granting an agent standing access to everything its user can see. The agent that
|
|
487
|
-
runs the [
|
|
488
|
-
|
|
489
|
-
it claimed.
|
|
491
|
+
runs the [Coordination](./coordination.md) `claim` loop is, to the scoping layer,
|
|
492
|
+
that same participant — scoped to the row it claimed.
|
|
490
493
|
|
|
491
494
|
## Narrowing to specific entities
|
|
492
495
|
|
|
493
496
|
A human gets their full membership automatically (`identityRoles`). There are
|
|
494
|
-
three ways to narrow a participant to specific entities — a page on one
|
|
497
|
+
three ways to narrow a participant to specific entities — a page on one workspace, or
|
|
495
498
|
an agent pointed at the entities it's working on. You **never hand-write**
|
|
496
|
-
`
|
|
499
|
+
`workspace:<id>`; build groups from the model's `scope` (Half 2) with the typed
|
|
497
500
|
`syncGroup(kind, id)` helper from `@abloatai/ablo/schema`.
|
|
498
501
|
|
|
499
502
|
1. **At session mint — `syncGroups`.** When your backend mints a session, pass the
|
|
@@ -501,13 +504,13 @@ an agent pointed at the entities it's working on. You **never hand-write**
|
|
|
501
504
|
the way to scope a focused page's session):
|
|
502
505
|
|
|
503
506
|
```ts
|
|
504
|
-
// an agent working across two
|
|
507
|
+
// an agent working across two workspaces and a document
|
|
505
508
|
const session = await server.sessions.create({
|
|
506
509
|
agent: { id: agentId },
|
|
507
|
-
can: {
|
|
510
|
+
can: { Workspace: ['read', 'update'], Document: ['read'] },
|
|
508
511
|
syncGroups: [
|
|
509
|
-
syncGroup('
|
|
510
|
-
syncGroup('
|
|
512
|
+
syncGroup('workspace', deckA),
|
|
513
|
+
syncGroup('workspace', deckB),
|
|
511
514
|
syncGroup('document', docId),
|
|
512
515
|
],
|
|
513
516
|
});
|
|
@@ -525,9 +528,9 @@ an agent pointed at the entities it's working on. You **never hand-write**
|
|
|
525
528
|
[Coordination](./coordination.md).
|
|
526
529
|
|
|
527
530
|
> **`groups.root` is the schema model option, not a client setting.**
|
|
528
|
-
> `groups: { root: '
|
|
529
|
-
> ([Half 2](#half-2
|
|
530
|
-
> (`
|
|
531
|
+
> `groups: { root: 'workspace' }` in `model(...)` declares a scope root
|
|
532
|
+
> ([Half 2](#half-2-per-model-scope-row--group)) — it names the group
|
|
533
|
+
> (`workspace:<id>`) that the mechanisms above then subscribe to.
|
|
531
534
|
> There is no `Ablo({ scope })` constructor option. The lifecycle filter on
|
|
532
535
|
> [`list()`](./api.md#model-methods) is a separate axis named **`state`**
|
|
533
536
|
> (`'live' | 'archived' | 'all'`, GitHub's open/closed/all), precisely so it
|
|
@@ -536,10 +539,10 @@ an agent pointed at the entities it's working on. You **never hand-write**
|
|
|
536
539
|
> **Requested groups never grant.** At connect, the server intersects the session's
|
|
537
540
|
> `syncGroups` with what the identity is actually allowed (`requested ∩ allowed`).
|
|
538
541
|
> So `syncGroups` only ever *narrows* within a participant's ceiling — an agent
|
|
539
|
-
> can't reach a
|
|
542
|
+
> can't reach a workspace its capability doesn't already permit, no matter what it
|
|
540
543
|
> passes. Smaller bootstrap, less fan-out, same server-enforced boundary.
|
|
541
544
|
|
|
542
|
-
## How this compares
|
|
545
|
+
## How this compares, and the best practices it follows
|
|
543
546
|
|
|
544
547
|
Ablo's identity model is not novel; it's the convergent answer every serious
|
|
545
548
|
realtime / sync SDK arrived at. Knowing which industry pattern it *is* tells you
|
|
@@ -547,7 +550,7 @@ how to reason about it.
|
|
|
547
550
|
|
|
548
551
|
**Realtime authorization splits into two shapes.** Ablo is firmly in the first:
|
|
549
552
|
|
|
550
|
-
- **Server derives scope from authenticated identity
|
|
553
|
+
- **Server derives scope from authenticated identity:** the server decides what
|
|
551
554
|
a participant may read/write and the client cannot override it. This is Ablo's
|
|
552
555
|
proxy model. It's the same shape as
|
|
553
556
|
[Supabase Realtime's RLS-on-connect](https://supabase.com/docs/guides/realtime/authorization)
|
|
@@ -556,7 +559,7 @@ how to reason about it.
|
|
|
556
559
|
checks the permissions for you" — recommended for production), and
|
|
557
560
|
[ElectricSQL **proxy auth**](https://electric-sql.com/docs/guides/auth) (a
|
|
558
561
|
reverse-proxy sets shape params server-side before forwarding).
|
|
559
|
-
- **Client proposes, server authorizes the exact request
|
|
562
|
+
- **Client proposes, server authorizes the exact request:** the client names
|
|
560
563
|
the room/shape and the server signs off, as in
|
|
561
564
|
[Pusher's channel authorization endpoint](https://pusher.com/docs/channels/server_api/authorizing-users/),
|
|
562
565
|
[ElectricSQL **gatekeeper auth**](https://github.com/electric-sql/electric/blob/main/examples/gatekeeper-auth/README.md),
|
|
@@ -583,7 +586,7 @@ The best practices Ablo inherits from that lineage:
|
|
|
583
586
|
never the boundary. This is why changing `userId` in the browser grants nothing.
|
|
584
587
|
|
|
585
588
|
3. **Scope by a hierarchical naming convention, declared once.** Ablo's `kind:id`
|
|
586
|
-
group naming (`org:…` / `team:…` from `identityRoles`, `
|
|
589
|
+
group naming (`org:…` / `team:…` from `identityRoles`, `workspace:…` from a model's
|
|
587
590
|
`scope`) is the same idea as [Liveblocks' recommended room-id naming pattern](https://liveblocks.io/docs/authentication/access-token)
|
|
588
591
|
(`org:*`, `org:group:*`) and [Ably's channel capabilities](https://ably.com/docs/auth/capabilities).
|
|
589
592
|
Declaring the convention in one place — never composing scope strings in
|