@abloatai/ablo 0.25.0 → 0.27.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 +5 -3
- package/CHANGELOG.md +34 -0
- package/README.md +104 -88
- package/dist/BaseSyncedStore.d.ts +140 -266
- package/dist/BaseSyncedStore.js +338 -739
- package/dist/Database.d.ts +62 -77
- package/dist/Database.js +106 -127
- package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
- package/dist/{ObjectPool.js → InstanceCache.js} +91 -83
- package/dist/LazyReferenceCollection.d.ts +11 -15
- package/dist/LazyReferenceCollection.js +16 -15
- package/dist/Model.d.ts +37 -52
- package/dist/Model.js +52 -69
- package/dist/ModelRegistry.d.ts +46 -25
- package/dist/ModelRegistry.js +32 -30
- package/dist/NetworkMonitor.d.ts +5 -6
- package/dist/NetworkMonitor.js +6 -7
- package/dist/SyncClient.d.ts +119 -109
- package/dist/SyncClient.js +303 -224
- package/dist/SyncEngineContext.d.ts +1 -3
- package/dist/SyncEngineContext.js +1 -2
- package/dist/adapters/alwaysOnline.d.ts +6 -8
- package/dist/adapters/alwaysOnline.js +6 -8
- package/dist/adapters/inMemoryStorage.d.ts +9 -9
- package/dist/adapters/inMemoryStorage.js +9 -9
- package/dist/agent/Agent.d.ts +39 -31
- package/dist/agent/Agent.js +35 -23
- package/dist/agent/index.d.ts +4 -4
- package/dist/agent/index.js +5 -5
- package/dist/agent/session.d.ts +47 -44
- package/dist/agent/session.js +37 -48
- package/dist/agent/types.d.ts +26 -31
- package/dist/agent/types.js +6 -7
- package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
- package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
- package/dist/ai-sdk/coordinationContext.d.ts +46 -0
- package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +30 -31
- package/dist/ai-sdk/index.d.ts +25 -22
- package/dist/ai-sdk/index.js +25 -22
- package/dist/ai-sdk/wrap.d.ts +7 -8
- package/dist/ai-sdk/wrap.js +2 -2
- package/dist/auth/credentialPolicy.d.ts +74 -71
- package/dist/auth/credentialPolicy.js +51 -56
- package/dist/auth/credentialSource.d.ts +7 -18
- package/dist/auth/credentialSource.js +10 -18
- package/dist/auth/index.d.ts +59 -58
- package/dist/auth/index.js +34 -40
- package/dist/auth/schemas.d.ts +5 -4
- package/dist/auth/schemas.js +5 -4
- package/dist/batching/index.d.ts +19 -21
- package/dist/batching/index.js +14 -17
- package/dist/cli.cjs +483 -369
- package/dist/client/Ablo.d.ts +107 -836
- package/dist/client/Ablo.js +174 -833
- package/dist/client/ApiClient.d.ts +44 -20
- package/dist/client/ApiClient.js +193 -44
- package/dist/client/auth.d.ts +51 -60
- package/dist/client/auth.js +137 -110
- package/dist/client/claimHeartbeatLoop.d.ts +50 -0
- package/dist/client/claimHeartbeatLoop.js +88 -0
- package/dist/client/consoleLogger.d.ts +35 -0
- package/dist/client/consoleLogger.js +44 -0
- package/dist/client/createInternalComponents.d.ts +14 -17
- package/dist/client/createInternalComponents.js +26 -31
- package/dist/client/createModelProxy.d.ts +130 -120
- package/dist/client/createModelProxy.js +158 -124
- package/dist/client/credentialEndpoint.d.ts +61 -0
- package/dist/client/credentialEndpoint.js +86 -0
- package/dist/client/functionalUpdate.d.ts +29 -27
- package/dist/client/functionalUpdate.js +21 -21
- package/dist/client/hostedEndpoints.d.ts +21 -0
- package/dist/client/hostedEndpoints.js +21 -0
- package/dist/client/httpClient.d.ts +58 -54
- package/dist/client/httpClient.js +29 -31
- package/dist/client/identity.d.ts +15 -20
- package/dist/client/identity.js +49 -59
- package/dist/client/modelRegistration.d.ts +10 -0
- package/dist/client/modelRegistration.js +301 -0
- package/dist/client/options.d.ts +373 -0
- package/dist/client/options.js +6 -0
- package/dist/client/registerDataSource.d.ts +9 -9
- package/dist/client/registerDataSource.js +15 -16
- package/dist/client/resourceTypes.d.ts +333 -0
- package/dist/client/resourceTypes.js +7 -0
- package/dist/client/schemaConfig.d.ts +44 -0
- package/dist/client/schemaConfig.js +176 -0
- package/dist/client/sessionMint.d.ts +17 -13
- package/dist/client/sessionMint.js +26 -31
- package/dist/client/validateAbloOptions.d.ts +12 -14
- package/dist/client/validateAbloOptions.js +9 -10
- package/dist/client/writeOptionsSchema.d.ts +18 -16
- package/dist/client/writeOptionsSchema.js +23 -20
- package/dist/client/wsMutationExecutor.d.ts +28 -0
- package/dist/client/wsMutationExecutor.js +71 -0
- package/dist/context.d.ts +6 -4
- package/dist/context.js +6 -7
- package/dist/coordination/index.d.ts +13 -4
- package/dist/coordination/index.js +29 -4
- package/dist/coordination/schema.d.ts +176 -128
- package/dist/coordination/schema.js +197 -133
- package/dist/coordination/trace.d.ts +9 -11
- package/dist/coordination/trace.js +13 -15
- package/dist/core/DatabaseManager.d.ts +5 -8
- package/dist/core/DatabaseManager.js +38 -40
- package/dist/core/QueryProcessor.d.ts +7 -9
- package/dist/core/QueryProcessor.js +27 -34
- package/dist/core/QueryView.d.ts +17 -5
- package/dist/core/QueryView.js +6 -7
- package/dist/core/StoreManager.d.ts +14 -16
- package/dist/core/StoreManager.js +26 -25
- package/dist/core/ViewRegistry.d.ts +5 -5
- package/dist/core/ViewRegistry.js +4 -4
- package/dist/core/index.d.ts +18 -13
- package/dist/core/index.js +32 -26
- package/dist/core/openIDBWithTimeout.d.ts +38 -36
- package/dist/core/openIDBWithTimeout.js +57 -54
- package/dist/core/queryUtils.d.ts +45 -0
- package/dist/core/queryUtils.js +69 -0
- package/dist/core/storeContract.d.ts +145 -0
- package/dist/core/storeContract.js +12 -0
- package/dist/environment.d.ts +28 -0
- package/dist/environment.js +21 -0
- package/dist/errorCodes.d.ts +118 -101
- package/dist/errorCodes.js +277 -260
- package/dist/errors.d.ts +170 -165
- package/dist/errors.js +161 -151
- package/dist/index.d.ts +30 -27
- package/dist/index.js +90 -82
- package/dist/interfaces/index.d.ts +108 -133
- package/dist/interfaces/index.js +5 -4
- package/dist/keys/index.d.ts +27 -29
- package/dist/keys/index.js +59 -49
- package/dist/mutators/RecordingTransaction.d.ts +16 -16
- package/dist/mutators/RecordingTransaction.js +31 -37
- package/dist/mutators/Transaction.d.ts +18 -26
- package/dist/mutators/Transaction.js +14 -20
- package/dist/mutators/UndoManager.d.ts +122 -131
- package/dist/mutators/UndoManager.js +149 -155
- package/dist/mutators/defineMutators.d.ts +24 -37
- package/dist/mutators/defineMutators.js +14 -20
- package/dist/mutators/inverseOp.d.ts +12 -15
- package/dist/mutators/inverseOp.js +12 -15
- package/dist/mutators/mutateActions.d.ts +10 -9
- package/dist/mutators/mutateActions.js +1 -1
- package/dist/mutators/readerActions.d.ts +9 -8
- package/dist/mutators/readerActions.js +2 -2
- package/dist/mutators/undoApply.d.ts +31 -27
- package/dist/mutators/undoApply.js +26 -24
- package/dist/policy/index.d.ts +5 -3
- package/dist/policy/index.js +5 -3
- package/dist/policy/types.d.ts +105 -101
- package/dist/policy/types.js +67 -66
- package/dist/query/client.d.ts +32 -16
- package/dist/query/client.js +103 -72
- package/dist/query/types.d.ts +37 -60
- package/dist/query/types.js +13 -33
- package/dist/react/AbloProvider.d.ts +7 -11
- package/dist/react/AbloProvider.js +24 -17
- package/dist/react/context.d.ts +27 -146
- package/dist/react/context.js +9 -10
- package/dist/react/index.d.ts +41 -42
- package/dist/react/index.js +37 -38
- package/dist/react/internalContext.d.ts +17 -19
- package/dist/react/useAblo.d.ts +23 -22
- package/dist/react/useAblo.js +17 -15
- package/dist/react/useCurrentUserId.d.ts +8 -7
- package/dist/react/useCurrentUserId.js +8 -7
- package/dist/react/useErrorListener.d.ts +7 -7
- package/dist/react/useErrorListener.js +11 -12
- package/dist/react/useMutationFailureListener.d.ts +8 -8
- package/dist/react/useMutationFailureListener.js +9 -9
- package/dist/react/useMutators.d.ts +11 -11
- package/dist/react/useMutators.js +10 -4
- package/dist/react/useReactive.js +2 -3
- package/dist/react/useSyncStatus.d.ts +4 -6
- package/dist/react/useUndoScope.d.ts +7 -9
- package/dist/react/useUndoScope.js +3 -3
- package/dist/schema/coordination.d.ts +21 -25
- package/dist/schema/coordination.js +21 -25
- package/dist/schema/ddl.d.ts +43 -39
- package/dist/schema/ddl.js +75 -68
- package/dist/schema/ddlLock.d.ts +35 -0
- package/dist/schema/ddlLock.js +46 -0
- package/dist/schema/diff.d.ts +99 -61
- package/dist/schema/diff.js +43 -34
- package/dist/schema/field.d.ts +37 -42
- package/dist/schema/field.js +36 -49
- package/dist/schema/generate.d.ts +12 -12
- package/dist/schema/generate.js +12 -12
- package/dist/schema/index.d.ts +5 -4
- package/dist/schema/index.js +29 -21
- package/dist/schema/model.d.ts +121 -146
- package/dist/schema/model.js +24 -35
- package/dist/schema/openapi.d.ts +10 -9
- package/dist/schema/openapi.js +7 -1
- package/dist/schema/queries.d.ts +30 -32
- package/dist/schema/queries.js +24 -25
- package/dist/schema/relation.d.ts +89 -99
- package/dist/schema/relation.js +13 -13
- package/dist/schema/residency.d.ts +38 -0
- package/dist/schema/residency.js +30 -0
- package/dist/schema/roles.d.ts +45 -27
- package/dist/schema/roles.js +52 -21
- package/dist/schema/schema.d.ts +36 -45
- package/dist/schema/schema.js +42 -39
- package/dist/schema/select.d.ts +13 -13
- package/dist/schema/select.js +13 -13
- package/dist/schema/serialize.d.ts +36 -39
- package/dist/schema/serialize.js +27 -31
- package/dist/schema/sugar.d.ts +17 -32
- package/dist/schema/sugar.js +14 -29
- package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +27 -50
- package/dist/schema/syncDeltaRow.js +89 -0
- package/dist/schema/tenancy.d.ts +44 -46
- package/dist/schema/tenancy.js +46 -48
- package/dist/server/adapter.d.ts +58 -58
- package/dist/server/adapter.js +13 -14
- package/dist/server/commit.d.ts +60 -64
- package/dist/server/index.d.ts +9 -10
- package/dist/server/index.js +1 -1
- package/dist/server/readConfig.d.ts +70 -0
- package/dist/server/readConfig.js +8 -0
- package/dist/server/storageMode.d.ts +23 -0
- package/dist/server/storageMode.js +17 -0
- package/dist/source/adapter.d.ts +31 -26
- package/dist/source/adapter.js +10 -10
- package/dist/source/adapters/drizzle.d.ts +28 -23
- package/dist/source/adapters/drizzle.js +34 -28
- package/dist/source/adapters/kysely.d.ts +27 -25
- package/dist/source/adapters/kysely.js +28 -26
- package/dist/source/adapters/memory.d.ts +8 -7
- package/dist/source/adapters/memory.js +10 -9
- package/dist/source/adapters/prisma.d.ts +13 -12
- package/dist/source/adapters/prisma.js +27 -29
- package/dist/source/conformance.d.ts +18 -11
- package/dist/source/conformance.js +27 -19
- package/dist/source/connector.d.ts +31 -32
- package/dist/source/connector.js +30 -28
- package/dist/source/connectorProtocol.d.ts +160 -0
- package/dist/source/connectorProtocol.js +162 -0
- package/dist/source/contract.d.ts +26 -27
- package/dist/source/contract.js +28 -29
- package/dist/source/factory.d.ts +94 -0
- package/dist/source/factory.js +268 -0
- package/dist/source/index.d.ts +10 -462
- package/dist/source/index.js +17 -421
- package/dist/source/migrations.d.ts +9 -9
- package/dist/source/migrations.js +9 -9
- package/dist/source/next.d.ts +10 -11
- package/dist/source/next.js +7 -8
- package/dist/source/pushQueue.d.ts +70 -48
- package/dist/source/pushQueue.js +36 -29
- package/dist/source/signing.d.ts +88 -0
- package/dist/source/signing.js +159 -0
- package/dist/source/types.d.ts +351 -0
- package/dist/source/types.js +43 -0
- package/dist/stores/ObjectStore.d.ts +11 -12
- package/dist/stores/ObjectStore.js +34 -35
- package/dist/stores/ObjectStoreContract.d.ts +12 -15
- package/dist/stores/SyncActionStore.d.ts +8 -12
- package/dist/stores/SyncActionStore.js +77 -46
- package/dist/surface.d.ts +28 -21
- package/dist/surface.js +28 -20
- package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +37 -45
- package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +101 -80
- package/dist/sync/ConnectionManager.d.ts +47 -50
- package/dist/sync/ConnectionManager.js +74 -70
- package/dist/sync/NetworkProbe.d.ts +27 -31
- package/dist/sync/NetworkProbe.js +67 -72
- package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +49 -36
- package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +79 -54
- package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +45 -59
- package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +44 -52
- package/dist/sync/SyncWebSocket.d.ts +175 -250
- package/dist/sync/SyncWebSocket.js +431 -769
- package/dist/sync/awaitClaimGrant.d.ts +18 -18
- package/dist/sync/awaitClaimGrant.js +38 -30
- package/dist/sync/bootstrapApply.d.ts +70 -0
- package/dist/sync/bootstrapApply.js +73 -0
- package/dist/sync/commitFrames.d.ts +44 -0
- package/dist/sync/commitFrames.js +94 -0
- package/dist/sync/createClaimStream.d.ts +23 -22
- package/dist/sync/createClaimStream.js +108 -25
- package/dist/sync/createPresenceStream.d.ts +19 -18
- package/dist/sync/createPresenceStream.js +25 -26
- package/dist/sync/createSnapshot.d.ts +13 -17
- package/dist/sync/createSnapshot.js +20 -26
- package/dist/sync/credentialLifecycle.d.ts +175 -0
- package/dist/sync/credentialLifecycle.js +322 -0
- package/dist/sync/deltaPipeline.d.ts +113 -0
- package/dist/sync/deltaPipeline.js +261 -0
- package/dist/sync/groupChange.d.ts +113 -0
- package/dist/sync/groupChange.js +242 -0
- package/dist/sync/heartbeat.d.ts +63 -0
- package/dist/sync/heartbeat.js +91 -0
- package/dist/sync/participants.d.ts +27 -27
- package/dist/sync/schemas.d.ts +3 -2
- package/dist/sync/schemas.js +14 -10
- package/dist/sync/syncCursor.d.ts +40 -0
- package/dist/sync/syncCursor.js +55 -0
- package/dist/sync/syncPlan.d.ts +54 -0
- package/dist/sync/syncPlan.js +50 -0
- package/dist/sync/syncPosition.d.ts +54 -49
- package/dist/sync/syncPosition.js +57 -52
- package/dist/sync/wsFrameHandlers.d.ts +116 -0
- package/dist/sync/wsFrameHandlers.js +374 -0
- package/dist/testing/fixtures/bootstrap.d.ts +21 -17
- package/dist/testing/fixtures/bootstrap.js +12 -6
- package/dist/testing/fixtures/deltas.d.ts +31 -34
- package/dist/testing/fixtures/deltas.js +30 -33
- package/dist/testing/fixtures/models.d.ts +11 -10
- package/dist/testing/fixtures/models.js +12 -10
- package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
- package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
- package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -18
- package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +14 -11
- package/dist/testing/helpers/wait.d.ts +13 -8
- package/dist/testing/helpers/wait.js +13 -8
- package/dist/testing/index.d.ts +4 -4
- package/dist/testing/index.js +3 -3
- package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
- package/dist/testing/mocks/MockMutationExecutor.js +15 -14
- package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
- package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
- package/dist/testing/mocks/MockSyncContext.d.ts +21 -34
- package/dist/testing/mocks/MockSyncContext.js +16 -45
- package/dist/testing/mocks/MockSyncStore.d.ts +14 -14
- package/dist/testing/mocks/MockSyncStore.js +11 -11
- package/dist/testing/mocks/MockWebSocket.d.ts +28 -24
- package/dist/testing/mocks/MockWebSocket.js +22 -21
- package/dist/transactions/TransactionQueue.d.ts +190 -221
- package/dist/transactions/TransactionQueue.js +424 -822
- package/dist/transactions/TransactionStore.d.ts +20 -0
- package/dist/transactions/TransactionStore.js +53 -0
- package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
- package/dist/transactions/UnconfirmedWrites.js +104 -0
- package/dist/transactions/coalesceRules.d.ts +58 -0
- package/dist/transactions/coalesceRules.js +140 -0
- package/dist/transactions/commitPayload.d.ts +130 -0
- package/dist/transactions/commitPayload.js +143 -0
- package/dist/transactions/deltaConfirmation.d.ts +58 -0
- package/dist/transactions/deltaConfirmation.js +215 -0
- package/dist/transactions/optimisticApply.d.ts +49 -0
- package/dist/transactions/optimisticApply.js +65 -0
- package/dist/transactions/replayValidation.d.ts +99 -0
- package/dist/transactions/replayValidation.js +111 -0
- package/dist/types/global.d.ts +46 -41
- package/dist/types/global.js +20 -19
- package/dist/types/index.d.ts +74 -80
- package/dist/types/index.js +22 -27
- package/dist/types/modelData.d.ts +10 -0
- package/dist/types/modelData.js +9 -0
- package/dist/types/participant.d.ts +20 -0
- package/dist/types/participant.js +10 -0
- package/dist/types/streams.d.ts +216 -209
- package/dist/types/streams.js +7 -7
- package/dist/utils/asyncIterator.d.ts +25 -32
- package/dist/utils/asyncIterator.js +25 -32
- package/dist/utils/duration.d.ts +12 -15
- package/dist/utils/duration.js +12 -15
- package/dist/utils/mobxSetup.d.ts +53 -0
- package/dist/utils/{mobx-setup.js → mobxSetup.js} +44 -100
- package/dist/webhooks/events.d.ts +21 -16
- package/dist/webhooks/events.js +10 -8
- package/dist/webhooks/index.d.ts +5 -7
- package/dist/webhooks/index.js +5 -7
- package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
- package/dist/wire/delta.js +114 -0
- package/dist/wire/errorEnvelope.d.ts +35 -27
- package/dist/wire/errorEnvelope.js +38 -32
- package/dist/wire/frames.d.ts +150 -67
- package/dist/wire/frames.js +48 -1
- package/dist/wire/index.d.ts +18 -13
- package/dist/wire/index.js +36 -13
- package/dist/wire/listEnvelope.d.ts +16 -23
- package/dist/wire/listEnvelope.js +7 -6
- package/dist/wire/protocol.d.ts +38 -0
- package/dist/wire/protocol.js +38 -0
- package/dist/wire/protocolVersion.d.ts +60 -0
- package/dist/wire/protocolVersion.js +67 -0
- package/docs/api-keys.md +4 -3
- package/docs/coordination.md +59 -0
- package/docs/examples/existing-python-backend.md +3 -3
- package/docs/identity.md +4 -4
- package/docs/integration-guide.md +1 -1
- package/docs/react.md +1 -1
- package/docs/sessions.md +5 -7
- package/package.json +24 -21
- package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
- package/dist/ai-sdk/coordination-context.d.ts +0 -52
- package/dist/client/index.d.ts +0 -36
- package/dist/client/index.js +0 -33
- package/dist/config/index.d.ts +0 -10
- package/dist/config/index.js +0 -12
- package/dist/core/query-utils.d.ts +0 -34
- package/dist/core/query-utils.js +0 -59
- package/dist/interfaces/headless.d.ts +0 -95
- package/dist/interfaces/headless.js +0 -41
- package/dist/query/index.d.ts +0 -6
- package/dist/query/index.js +0 -5
- package/dist/realtime/index.d.ts +0 -10
- package/dist/realtime/index.js +0 -9
- package/dist/schema/plane.d.ts +0 -23
- package/dist/schema/plane.js +0 -19
- package/dist/schema/sync-delta-row.js +0 -103
- package/dist/schema/sync-delta-wire.js +0 -102
- package/dist/server/next.d.ts +0 -51
- package/dist/server/next.js +0 -47
- package/dist/server/read-config.d.ts +0 -67
- package/dist/server/read-config.js +0 -8
- package/dist/server/storage-mode.d.ts +0 -1
- package/dist/server/storage-mode.js +0 -18
- package/dist/source/connector-protocol.d.ts +0 -159
- package/dist/source/connector-protocol.js +0 -161
- package/dist/sync/OfflineFlush.d.ts +0 -9
- package/dist/sync/OfflineFlush.js +0 -22
- package/dist/sync/OfflineTransactionStore.d.ts +0 -37
- package/dist/sync/OfflineTransactionStore.js +0 -263
- package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
- package/dist/transactions/OptimisticEchoTracker.js +0 -104
- package/dist/transactions/index.d.ts +0 -16
- package/dist/transactions/index.js +0 -7
- package/dist/transactions/mutation-error-handler.d.ts +0 -5
- package/dist/transactions/mutation-error-handler.js +0 -39
- package/dist/utils/mobx-setup.d.ts +0 -42
package/dist/client/Ablo.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Ablo —
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* `Ablo` — the one-call entry point to the sync engine client. It hides the
|
|
3
|
+
* internal wiring — the object pool, local database, sync client, WebSocket,
|
|
4
|
+
* bootstrap, and offline queue — behind a single function that returns a typed
|
|
5
|
+
* client with one property per model in your schema.
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
|
-
* import { Ablo } from '@abloatai/ablo
|
|
8
|
+
* import { Ablo } from '@abloatai/ablo';
|
|
9
9
|
* import { schema } from './schema';
|
|
10
10
|
*
|
|
11
11
|
* const sync = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
|
|
@@ -18,712 +18,22 @@
|
|
|
18
18
|
* });
|
|
19
19
|
* await sync.reports.delete({ id: reportId });
|
|
20
20
|
*/
|
|
21
|
-
import type { StaleNotification, ReadDependency } from '../coordination/schema.js';
|
|
22
21
|
import type { Schema, SchemaRecord, InferModel, InferCreate } from '../schema/schema.js';
|
|
23
|
-
import type { SyncEngineConfig, SyncLogger, MutationExecutor, MutationDispatcher, SyncObservabilityProvider, SyncAnalytics, SessionErrorDetector, OnlineStatusProvider } from '../interfaces/index.js';
|
|
24
22
|
import type { ModelTarget, ModelClaim } from '../coordination/schema.js';
|
|
25
23
|
export type { ModelTarget, ModelClaim };
|
|
26
|
-
import {
|
|
24
|
+
import { InstanceCache } from '../InstanceCache.js';
|
|
27
25
|
import type { SyncStoreContract } from '../react/context.js';
|
|
28
26
|
import type { SyncWebSocket } from '../sync/SyncWebSocket.js';
|
|
29
|
-
import type { SyncGroupInput } from '../schema/roles.js';
|
|
30
27
|
import { type SyncStatus } from '../BaseSyncedStore.js';
|
|
31
|
-
import type {
|
|
32
|
-
import type { ClaimStream, ClaimWaitOptions, PresenceStream, Snapshot } from '../types/streams.js';
|
|
33
|
-
import type { Claim, HeldClaim, Duration } from '../types/streams.js';
|
|
28
|
+
import type { PresenceStream, Snapshot } from '../types/streams.js';
|
|
34
29
|
import { type AbloApi, type AbloApiClientOptions, type AbloApiClaims } from './ApiClient.js';
|
|
35
30
|
import { type AbloHttpClient, type AbloHttpClientOptions } from './httpClient.js';
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
*
|
|
43
|
-
* Re-exported from `./auth` so existing import paths (`@abloatai/ablo`)
|
|
44
|
-
* keep resolving; the canonical definition lives there alongside the
|
|
45
|
-
* resolvers that consume it.
|
|
46
|
-
*/
|
|
47
|
-
export type { ApiKeySetter } from './auth.js';
|
|
48
|
-
import type { ApiKeySetter } from './auth.js';
|
|
49
|
-
import { type AbloPersistence } from './persistence.js';
|
|
50
|
-
/**
|
|
51
|
-
* Options for `Ablo({...})`.
|
|
52
|
-
*
|
|
53
|
-
* The only required field is `schema`. The default path is one line:
|
|
54
|
-
*
|
|
55
|
-
* ```ts
|
|
56
|
-
* const ablo = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
|
|
57
|
-
* ```
|
|
58
|
-
*
|
|
59
|
-
* `apiKey` itself defaults to `process.env.ABLO_API_KEY`, so in most
|
|
60
|
-
* server setups `Ablo({ schema })` is enough. Every other field is
|
|
61
|
-
* optional tuning (timeouts, retries, custom fetch, persistence) —
|
|
62
|
-
* if you're not sure whether you need one, you don't. Reach for them
|
|
63
|
-
* the way you'd reach for the equivalent option on the Stripe / OpenAI
|
|
64
|
-
* / Anthropic clients: rarely, and deliberately.
|
|
65
|
-
*
|
|
66
|
-
* @see https://docs.abloatai.com — full option reference
|
|
67
|
-
*/
|
|
68
|
-
export interface AbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
69
|
-
/**
|
|
70
|
-
* TypeScript schema defined with `defineSchema()`. Required — it's what
|
|
71
|
-
* makes `ablo.weatherReports.update(...)` typed. This is the one field you must
|
|
72
|
-
* pass; start here.
|
|
73
|
-
*/
|
|
74
|
-
schema: Schema<S>;
|
|
75
|
-
/**
|
|
76
|
-
* API key — **the one auth field most apps set.** Server-side this is your
|
|
77
|
-
* secret `sk_` (and it defaults to `process.env['ABLO_API_KEY']`, so you
|
|
78
|
-
* usually pass nothing). A long-lived key needs no refresh; the client uses
|
|
79
|
-
* it as-is.
|
|
80
|
-
*
|
|
81
|
-
* Accepts a static string OR an async `() => Promise<string | null>` resolver
|
|
82
|
-
* — the single credential path. Use the resolver form for two cases:
|
|
83
|
-
*
|
|
84
|
-
* - **Key rotation** (server): pull a fresh `sk_`/`pk_` from a vault on each
|
|
85
|
-
* bootstrap (AWS STS, GCP IAM, Vault).
|
|
86
|
-
* - **Short-lived per-user browser** auth: return the fresh `ek_`/`rk_` bearer
|
|
87
|
-
* your backend minted for the signed-in user. The client mints once before
|
|
88
|
-
* connect, then keeps it fresh for you — a refresh timer ahead of expiry
|
|
89
|
-
* plus re-mint on OS-wake / network-online / tab-focus, and a reactive
|
|
90
|
-
* re-mint when a probe finds the key stale. You never call a refresh method
|
|
91
|
-
* (Supabase `autoRefreshToken` model).
|
|
92
|
-
*
|
|
93
|
-
* Resolver contract: resolve a token; resolve `null` when the login itself is
|
|
94
|
-
* gone (terminal → the client signs out / fails `ready()` with `session_expired`);
|
|
95
|
-
* or THROW on a transient failure (→ back off and retry, never sign out). A
|
|
96
|
-
* static string never refreshes — it is used as-is.
|
|
97
|
-
*/
|
|
98
|
-
apiKey?: string | ApiKeySetter | null | undefined;
|
|
99
|
-
/**
|
|
100
|
-
* @deprecated The direct connector lets Ablo dial INTO your Postgres and write to
|
|
101
|
-
* it — the operate-their-database posture we are moving off. Ablo is Stripe-shaped:
|
|
102
|
-
* it hosts only the transaction log (the ordered sync_deltas) + coordination, never
|
|
103
|
-
* your data; your rows always live in your own database. Use the signed Data Source
|
|
104
|
-
* endpoint instead — keep `DATABASE_URL` in your app, expose `dataSource(...)`, and
|
|
105
|
-
* let your server own the write while Ablo coordinates the sync stream. To keep the
|
|
106
|
-
* log in your infra too, self-host the engine. See
|
|
107
|
-
* docs/plans/stripe-shaped-storage-posture.md.
|
|
108
|
-
*
|
|
109
|
-
* Still honored at runtime for back-compat. SERVER-ONLY: it carries credentials, so
|
|
110
|
-
* it is never sent from the browser — constructing a client with `databaseUrl` and
|
|
111
|
-
* `dangerouslyAllowBrowser` throws. If you use it, provide a NON-superuser,
|
|
112
|
-
* non-`BYPASSRLS` role; the connector rejects privileged roles that cannot enforce RLS.
|
|
113
|
-
*/
|
|
114
|
-
databaseUrl?: string | null | undefined;
|
|
115
|
-
/**
|
|
116
|
-
* Local persistence mode. Pass `indexeddb` only when you want offline
|
|
117
|
-
* queueing and a reload-surviving browser cache.
|
|
118
|
-
*
|
|
119
|
-
* @default 'memory'
|
|
120
|
-
*/
|
|
121
|
-
persistence?: AbloPersistence;
|
|
122
|
-
/**
|
|
123
|
-
* Transport selector. `'websocket'` (default) is the live client —
|
|
124
|
-
* persistent socket, local synced pool, `onChange` subscriptions. `'http'`
|
|
125
|
-
* returns the STATELESS client for server-side actors (agents, workers,
|
|
126
|
-
* serverless): same `ablo.<model>` surface and coordination plane, but each
|
|
127
|
-
* call is one HTTP round-trip, identity rides the Bearer credential, and no
|
|
128
|
-
* socket is ever opened. With `'http'` the return type narrows to
|
|
129
|
-
* `AbloHttpClient<S>`, so stateful-only capabilities (`get`/`getAll`,
|
|
130
|
-
* `onChange`) are compile errors rather than latent runtime gaps.
|
|
131
|
-
*
|
|
132
|
-
* Note: session/credential minting (`sessions.create`) currently runs on the
|
|
133
|
-
* stateful (default) client, not the http client.
|
|
134
|
-
*
|
|
135
|
-
* @default 'websocket'
|
|
136
|
-
*/
|
|
137
|
-
transport?: 'websocket' | 'http' | undefined;
|
|
138
|
-
/**
|
|
139
|
-
* Turn Ablo's diagnostic logging on/off. `true` surfaces the `[Ablo]`
|
|
140
|
-
* coordination trace — claims requested / queued / granted / released, agent
|
|
141
|
-
* handovers, connection state — so you can SEE the human+agent coordination
|
|
142
|
-
* you built while debugging. Omitted/`false` keeps the quiet default (only
|
|
143
|
-
* warnings + errors). For a middle ground use {@link logLevel}. Env override:
|
|
144
|
-
* `ABLO_LOG_LEVEL`. Ignored if a custom logger is supplied.
|
|
145
|
-
*/
|
|
146
|
-
debug?: boolean | undefined;
|
|
147
|
-
/**
|
|
148
|
-
* Log threshold for the default `[Ablo]` logger (takes precedence over
|
|
149
|
-
* {@link debug}). `'info'` = coordination + connection events without the
|
|
150
|
-
* per-model registration firehose; `'debug'` = everything; `'warn'` (default)
|
|
151
|
-
* = warnings + errors only; `'silent'` = nothing. Env override: `ABLO_LOG_LEVEL`.
|
|
152
|
-
*/
|
|
153
|
-
logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;
|
|
154
|
-
/**
|
|
155
|
-
* Bearer auth token. Hosted-cloud consumers pass `apiKey`; self-hosted
|
|
156
|
-
* deployments may pass a bearer token minted by their own auth layer.
|
|
157
|
-
*/
|
|
158
|
-
authToken?: string | null | undefined;
|
|
159
|
-
/**
|
|
160
|
-
* Override the Ablo API base URL. Defaults to hosted production.
|
|
161
|
-
*/
|
|
162
|
-
baseURL?: string | null | undefined;
|
|
163
|
-
/** Custom fetch implementation for tests, proxies, or non-standard runtimes. */
|
|
164
|
-
fetch?: typeof fetch | undefined;
|
|
165
|
-
/** Default headers sent with every API request. */
|
|
166
|
-
defaultHeaders?: Record<string, string | null | undefined> | undefined;
|
|
167
|
-
/** Default query parameters sent with every API request. */
|
|
168
|
-
defaultQuery?: Record<string, string | undefined> | undefined;
|
|
169
|
-
/**
|
|
170
|
-
* Client-side use is disabled by default because private API keys should
|
|
171
|
-
* not ship to browsers. Set this only when the browser holds a minted
|
|
172
|
-
* session token (`ek_`/`rk_`) or you route through a controlled server proxy.
|
|
173
|
-
*/
|
|
174
|
-
dangerouslyAllowBrowser?: boolean | undefined;
|
|
175
|
-
}
|
|
176
|
-
export interface InternalAbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
177
|
-
/**
|
|
178
|
-
* API key used for authentication.
|
|
179
|
-
*
|
|
180
|
-
* Accepts a static string (`sk_live_...`) or an async function that
|
|
181
|
-
* resolves to one. Defaults to `process.env['ABLO_API_KEY']`.
|
|
182
|
-
*
|
|
183
|
-
* When a function is provided, it's invoked before each request so
|
|
184
|
-
* you can rotate or refresh credentials at runtime. The function
|
|
185
|
-
* must return a non-empty string; otherwise an `AbloAuthenticationError`
|
|
186
|
-
* is thrown. If the function throws, the error is wrapped with the
|
|
187
|
-
* original available as `cause`.
|
|
188
|
-
*
|
|
189
|
-
* Mirrors Anthropic / OpenAI / Stripe SDK shape exactly.
|
|
190
|
-
*/
|
|
191
|
-
apiKey?: string | ApiKeySetter | null | undefined;
|
|
192
|
-
/**
|
|
193
|
-
* Bearer auth token. Sent as `Authorization: Bearer <token>` on
|
|
194
|
-
* every request.
|
|
195
|
-
*
|
|
196
|
-
* Use this for self-hosted deployments where your auth layer mints
|
|
197
|
-
* cap tokens directly. Hosted-cloud consumers pass `apiKey` instead;
|
|
198
|
-
* the server handles cap-mint internally.
|
|
199
|
-
*/
|
|
200
|
-
authToken?: string | null | undefined;
|
|
201
|
-
/**
|
|
202
|
-
* Override the default base URL. Defaults to
|
|
203
|
-
* `wss://api.abloatai.com` for hosted production; pass an explicit
|
|
204
|
-
* URL for self-hosted or private deployments.
|
|
205
|
-
*/
|
|
206
|
-
baseURL?: string | null | undefined;
|
|
207
|
-
/**
|
|
208
|
-
* Custom `fetch` implementation. Defaults to `globalThis.fetch`.
|
|
209
|
-
* Override for testing, custom transports, or runtime shims.
|
|
210
|
-
*/
|
|
211
|
-
fetch?: typeof fetch | undefined;
|
|
212
|
-
/**
|
|
213
|
-
* Default headers to include with every request to the API.
|
|
214
|
-
* Removed per-request by setting the header to `null` in request
|
|
215
|
-
* options.
|
|
216
|
-
*/
|
|
217
|
-
defaultHeaders?: Record<string, string | null | undefined> | undefined;
|
|
218
|
-
/**
|
|
219
|
-
* Default query parameters to include with every request.
|
|
220
|
-
* Removed per-request by setting the param to `undefined`.
|
|
221
|
-
*/
|
|
222
|
-
defaultQuery?: Record<string, string | undefined> | undefined;
|
|
223
|
-
/**
|
|
224
|
-
* Client-side use of this SDK is disabled by default — your apiKey
|
|
225
|
-
* would ship to every visitor's network tab. Only set this to
|
|
226
|
-
* `true` if you've understood the risk and have appropriate
|
|
227
|
-
* mitigations (a minted session token, a server-side proxy, etc).
|
|
228
|
-
*/
|
|
229
|
-
dangerouslyAllowBrowser?: boolean | undefined;
|
|
230
|
-
/**
|
|
231
|
-
* TypeScript schema defined with `defineSchema()`.
|
|
232
|
-
*
|
|
233
|
-
* The root `Ablo(...)` client is schema-first so consumers get typed
|
|
234
|
-
* model clients such as `ablo.weatherReports.update(...)`. Omit `schema`
|
|
235
|
-
* only for the advanced Model / Claim / Commit client.
|
|
236
|
-
*/
|
|
237
|
-
schema: Schema<S>;
|
|
238
|
-
/**
|
|
239
|
-
* @deprecated Server derives participant kind from the apiKey's
|
|
240
|
-
* scope. Pass apiKey only; this option will be removed once the
|
|
241
|
-
* server-internal cap-mint flow lands.
|
|
242
|
-
*/
|
|
243
|
-
kind?: 'user' | 'agent' | 'system';
|
|
244
|
-
/**
|
|
245
|
-
* @deprecated Server derives user identity from the apiKey's
|
|
246
|
-
* scope (or from `Ablo-Acting-User` request header for B2B2C).
|
|
247
|
-
* Removed once Phase 3 ships.
|
|
248
|
-
*/
|
|
249
|
-
user?: {
|
|
250
|
-
id: string;
|
|
251
|
-
teamIds?: string[];
|
|
252
|
-
};
|
|
253
|
-
/**
|
|
254
|
-
* @deprecated Server derives agent identity from the apiKey's
|
|
255
|
-
* scope. Removed once Phase 3 ships.
|
|
256
|
-
*/
|
|
257
|
-
agentId?: string;
|
|
258
|
-
/**
|
|
259
|
-
* @deprecated Cap-mint moves server-internal in Phase 3. Pass
|
|
260
|
-
* `apiKey` only; the server handles capability issuance.
|
|
261
|
-
*/
|
|
262
|
-
capabilityToken?: string;
|
|
263
|
-
/** Custom logger (default: console). Supplying one bypasses {@link debug}/{@link logLevel}. */
|
|
264
|
-
logger?: SyncLogger;
|
|
265
|
-
/**
|
|
266
|
-
* Turn Ablo's diagnostic logging on/off. `true` surfaces the `[Ablo]`
|
|
267
|
-
* coordination trace — claims acquired / queued / granted / released, agent
|
|
268
|
-
* handovers, connection state — plus internal lifecycle, so you can SEE the
|
|
269
|
-
* human+agent coordination you built. Omitted/`false` keeps the quiet default
|
|
270
|
-
* (only warnings + errors). For a middle ground use {@link logLevel}.
|
|
271
|
-
* Env override: `ABLO_LOG_LEVEL`. Ignored if a custom {@link logger} is passed.
|
|
272
|
-
*/
|
|
273
|
-
debug?: boolean;
|
|
274
|
-
/**
|
|
275
|
-
* Log threshold for the default `[Ablo]` logger (takes precedence over
|
|
276
|
-
* {@link debug}). `'info'` = coordination + connection events without the
|
|
277
|
-
* per-model registration firehose; `'debug'` = everything; `'warn'` (default)
|
|
278
|
-
* = warnings + errors only; `'silent'` = nothing. Env override: `ABLO_LOG_LEVEL`.
|
|
279
|
-
*/
|
|
280
|
-
logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
281
|
-
/** ObjectPool size limit (default: 10000) */
|
|
282
|
-
maxPoolSize?: number;
|
|
283
|
-
/**
|
|
284
|
-
* Local persistence mode. Defaults to `memory` so Ablo behaves like a
|
|
285
|
-
* point solution for shared state instead of silently bolting IndexedDB
|
|
286
|
-
* durability onto every browser consumer.
|
|
287
|
-
*
|
|
288
|
-
* Pass `persistence: 'indexeddb'` only when you want offline queueing
|
|
289
|
-
* and a reload-surviving local cache in a browser.
|
|
290
|
-
*/
|
|
291
|
-
persistence?: AbloPersistence;
|
|
292
|
-
/** @deprecated Use `persistence: 'indexeddb'` for durable browser storage. */
|
|
293
|
-
offline?: boolean;
|
|
294
|
-
/**
|
|
295
|
-
* @deprecated Internal/testing escape hatch. Use `persistence` in
|
|
296
|
-
* production code. `true` maps to `memory`; `false` maps to
|
|
297
|
-
* `indexeddb` in browsers.
|
|
298
|
-
*/
|
|
299
|
-
inMemory?: boolean;
|
|
300
|
-
/**
|
|
301
|
-
* If true, initialization starts immediately in the background so
|
|
302
|
-
* `sync.reports.findMany()` works after `await sync.ready()`.
|
|
303
|
-
*
|
|
304
|
-
* If false (default), the consumer MUST call `await sync.ready()` before
|
|
305
|
-
* using the engine — any query before that returns empty results.
|
|
306
|
-
*
|
|
307
|
-
* Default: false (explicit is better — prevents silent init failures).
|
|
308
|
-
*/
|
|
309
|
-
autoStart?: boolean;
|
|
310
|
-
/**
|
|
311
|
-
* How aggressively this client should pull baseline state at
|
|
312
|
-
* startup.
|
|
313
|
-
*
|
|
314
|
-
* - `'full'`: pull every delta in the configured sync groups before
|
|
315
|
-
* `ready()` resolves. Default for `kind: 'user'`.
|
|
316
|
-
* - `'none'`: open the WS and process live deltas only — no baseline
|
|
317
|
-
* fetch. Reads round-trip via `model.retrieve()`; subscriptions
|
|
318
|
-
* populate the pool lazily via covering deltas. Default for
|
|
319
|
-
* `kind: 'agent'` because agent-worker / routine runners don't
|
|
320
|
-
* need (or want) a local replica of the org's tenant plane.
|
|
321
|
-
*/
|
|
322
|
-
bootstrapMode?: 'full' | 'none';
|
|
323
|
-
/**
|
|
324
|
-
* Custom observability provider (Sentry, Honeycomb, OTel, etc.).
|
|
325
|
-
* Default: a noop implementation that drops all breadcrumbs and spans.
|
|
326
|
-
*/
|
|
327
|
-
observability?: SyncObservabilityProvider;
|
|
328
|
-
/**
|
|
329
|
-
* Custom analytics provider (PostHog, Amplitude, Segment, etc.).
|
|
330
|
-
* Default: a noop implementation that drops all events.
|
|
331
|
-
*/
|
|
332
|
-
analytics?: SyncAnalytics;
|
|
333
|
-
/**
|
|
334
|
-
* Detect whether an error from a mutation/bootstrap response means the
|
|
335
|
-
* user's session has expired. Used to surface re-auth prompts. Default:
|
|
336
|
-
* heuristic that matches `401 Unauthorized` and a few common error shapes.
|
|
337
|
-
*/
|
|
338
|
-
sessionErrorDetector?: SessionErrorDetector;
|
|
339
|
-
/**
|
|
340
|
-
* Detect whether the browser is currently online. Default: reads
|
|
341
|
-
* `navigator.onLine` and listens to the `online`/`offline` events.
|
|
342
|
-
*/
|
|
343
|
-
onlineStatus?: OnlineStatusProvider;
|
|
344
|
-
/**
|
|
345
|
-
* Replace the built-in `MutationExecutor` (which posts a hardcoded
|
|
346
|
-
* `commit` method against `${url}/graphql`) with one that uses your own
|
|
347
|
-
* GraphQL client, auth headers, retry policy, and observability hooks.
|
|
348
|
-
*
|
|
349
|
-
* Default: a fetch-based executor that targets `${url}/graphql` and sends
|
|
350
|
-
* the configured bearer (`apiKey` / backend-minted token) as `Authorization`.
|
|
351
|
-
*/
|
|
352
|
-
mutationExecutor?: MutationExecutor;
|
|
353
|
-
/**
|
|
354
|
-
* Replace the built-in `MutationDispatcher` (used by the offline queue
|
|
355
|
-
* to replay mutations on reconnect). If you override `mutationExecutor`
|
|
356
|
-
* you almost always want to override this too so the two paths share
|
|
357
|
-
* the same auth/retry behavior.
|
|
358
|
-
*
|
|
359
|
-
* Default: a thin dispatcher that routes to the built-in executor.
|
|
360
|
-
*/
|
|
361
|
-
mutationDispatcher?: MutationDispatcher;
|
|
362
|
-
/**
|
|
363
|
-
* Partial overrides for the auto-derived `SyncEngineConfig`. Merged on
|
|
364
|
-
* top of `deriveConfigFromSchema(schema)`. Use this when you need
|
|
365
|
-
* specific `modelCreatePriority`, `batchableModels`, or
|
|
366
|
-
* `essentialFields` settings that the schema cannot express.
|
|
367
|
-
*/
|
|
368
|
-
configOverrides?: Partial<SyncEngineConfig>;
|
|
369
|
-
/**
|
|
370
|
-
* Sync groups (entity scopes) this client subscribes to. **Provisional, not
|
|
371
|
-
* deprecated** — pick the right lane: normally the server derives these from
|
|
372
|
-
* the apiKey's scope, but passing them is still REQUIRED today in any config
|
|
373
|
-
* where the key doesn't resolve them (omitting yields a `degenerate
|
|
374
|
-
* syncGroups` warning and a zero-fan-out client). Keep passing it explicitly
|
|
375
|
-
* until the server-derived path ships in Phase 3, at which point it becomes a
|
|
376
|
-
* true no-op and is removed. Build values with `syncGroup(kind, id)` from
|
|
377
|
-
* `@abloatai/ablo/schema`.
|
|
378
|
-
*/
|
|
379
|
-
syncGroups?: string[];
|
|
380
|
-
/**
|
|
381
|
-
* Override the bootstrap endpoint base URL. Use this when your sync
|
|
382
|
-
* server's HTTP API lives on a different host than the WebSocket URL.
|
|
383
|
-
*
|
|
384
|
-
* Must include the `/api` prefix — `BootstrapHelper` appends
|
|
385
|
-
* `/sync/bootstrap` directly. Example:
|
|
386
|
-
* `'http://api.example.com/api'` → `http://api.example.com/api/sync/bootstrap`.
|
|
387
|
-
*
|
|
388
|
-
* Default: `${url.replace(/^ws/, 'http')}/api`.
|
|
389
|
-
*/
|
|
390
|
-
bootstrapBaseUrl?: string;
|
|
391
|
-
/**
|
|
392
|
-
* Ablo-owned account scope. Required for Branch 3 identity resolution
|
|
393
|
-
* in `identity.ts` — without it the SDK falls through to the
|
|
394
|
-
* `/api/identity` HTTP-derived path (Branch 2).
|
|
395
|
-
*/
|
|
396
|
-
organizationId?: string;
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Operations available on each model in the sync engine.
|
|
400
|
-
*
|
|
401
|
-
* Naming aligns with Stripe / OpenAI / Anthropic conventions:
|
|
402
|
-
* `retrieve({ id })` — async single-row server read
|
|
403
|
-
* `list({ where })` — async collection server read
|
|
404
|
-
* `get(id)` / `getAll(...)` / `getCount(...)` — local graph snapshots
|
|
405
|
-
* `create({ data })` / `update({ id, data })` / `delete({ id })` — writes
|
|
406
|
-
* `claim({ id })` — durable claim handle for coordinated writes
|
|
407
|
-
*/
|
|
408
|
-
export type { LocalCountOptions, LocalReadOptions, ModelListScope, ServerReadOptions, ModelRetrieveParams, ModelCreateParams, ModelUpdateParams, ModelDeleteParams, ClaimOptions, ClaimParams, ClaimLookupParams, ClaimReorderParams, Claim, HeldClaim, ModelOperations, } from './createModelProxy.js';
|
|
409
|
-
import type { ModelOperations, ClaimOptions, ClaimParams, ClaimReadApi, AwaitedClaimMethod, ServerReadOptions } from './createModelProxy.js';
|
|
410
|
-
export type ModelOperationAction = 'create' | 'update' | 'delete' | 'archive' | 'unarchive';
|
|
411
|
-
export type CommitWait = 'queued' | 'confirmed';
|
|
412
|
-
export interface ModelRead<T = Record<string, unknown>> {
|
|
413
|
-
/**
|
|
414
|
-
* The row, or `undefined` when no row matched the id (or it's outside the
|
|
415
|
-
* caller's scope). A miss is data-absence, not an error — `retrieve` never
|
|
416
|
-
* throws "not found", mirroring the WebSocket client's `T | undefined`.
|
|
417
|
-
* Branch on it: `const deal = (await ablo.deals.retrieve({ id })).data; if (!deal) …`.
|
|
418
|
-
*/
|
|
419
|
-
readonly data: T | undefined;
|
|
420
|
-
readonly stamp: number;
|
|
421
|
-
readonly claims: readonly ModelClaim[];
|
|
422
|
-
}
|
|
423
|
-
export type IfClaimedPolicy = 'return' | 'fail';
|
|
424
|
-
export interface ClaimedOptions {
|
|
425
|
-
/**
|
|
426
|
-
* What to do when another participant has claimed the target: `return`
|
|
427
|
-
* includes active claim metadata in the response; `fail` throws
|
|
428
|
-
* `AbloClaimedError`. Waiting for a claim to clear is a claim-side concern —
|
|
429
|
-
* take `ablo.<model>.claim({ id })` (it queues fairly); reads never block.
|
|
430
|
-
*/
|
|
431
|
-
readonly ifClaimed?: IfClaimedPolicy;
|
|
432
|
-
}
|
|
433
|
-
export type { ClaimWaitOptions } from '../types/streams.js';
|
|
434
|
-
export interface ModelReadOptions extends ClaimedOptions {
|
|
435
|
-
}
|
|
436
|
-
export interface ClaimCreateOptions {
|
|
437
|
-
readonly target: ModelTarget;
|
|
438
|
-
/** Human-readable phase shown to peers — `'editing'`, `'writing'`. The same
|
|
439
|
-
* word on every claim surface. */
|
|
440
|
-
readonly reason: string;
|
|
441
|
-
readonly ttl?: Duration;
|
|
442
|
-
/**
|
|
443
|
-
* Join the server's fair FIFO queue when the target is already claimed,
|
|
444
|
-
* rather than failing immediately. `create` then resolves only once the
|
|
445
|
-
* lease is actually ours (the server pushes `claim_acquired` if the target
|
|
446
|
-
* was free, or `claim_granted` when we reach the head of the line). Without
|
|
447
|
-
* this, a contended claim throws. Used by `ablo.<model>.claim` so writers
|
|
448
|
-
* serialize instead of racing.
|
|
449
|
-
*/
|
|
450
|
-
readonly queue?: boolean;
|
|
451
|
-
/** Cap on how long to wait for a queued grant before rejecting. */
|
|
452
|
-
readonly waitTimeoutMs?: number;
|
|
453
|
-
/**
|
|
454
|
-
* Backpressure: reject with `AbloClaimedError('queue_too_deep')` instead of
|
|
455
|
-
* waiting if the queue is already `>= maxQueueDepth` when we join.
|
|
456
|
-
*/
|
|
457
|
-
readonly maxQueueDepth?: number;
|
|
458
|
-
}
|
|
459
|
-
export interface CommitOperationInput {
|
|
460
|
-
readonly action: ModelOperationAction;
|
|
461
|
-
/** The model name — matches `ablo.<model>` and the schema's `model()`. */
|
|
462
|
-
readonly model?: string;
|
|
463
|
-
readonly target?: ModelTarget;
|
|
464
|
-
readonly id?: string | null;
|
|
465
|
-
readonly data?: Record<string, unknown> | null;
|
|
466
|
-
readonly transactionId?: string | null;
|
|
467
|
-
readonly readAt?: number | null;
|
|
468
|
-
readonly onStale?: 'reject' | 'overwrite' | 'notify' | null;
|
|
469
|
-
}
|
|
470
|
-
export interface CommitCreateOptions {
|
|
471
|
-
readonly claimRef?: string | {
|
|
472
|
-
readonly id: string;
|
|
473
|
-
} | null;
|
|
474
|
-
readonly idempotencyKey?: string | null;
|
|
475
|
-
readonly readAt?: number | null;
|
|
476
|
-
readonly onStale?: 'reject' | 'overwrite' | 'notify' | null;
|
|
477
|
-
/**
|
|
478
|
-
* A claim handle from `ablo.<model>.claim({ id })` (or the HTTP claim
|
|
479
|
-
* surface). Same vocabulary as the per-model writes: the handle's
|
|
480
|
-
* snapshot watermark becomes the batch `readAt` default and `onStale`
|
|
481
|
-
* defaults to `'reject'`, so a commit that follows a claim is guarded
|
|
482
|
-
* against concurrent edits without re-stating the watermark by hand.
|
|
483
|
-
* Explicit `readAt`/`onStale` on the options win.
|
|
484
|
-
*/
|
|
485
|
-
readonly claim?: Claim<Record<string, unknown>> | null;
|
|
486
|
-
readonly operation?: CommitOperationInput;
|
|
487
|
-
readonly operations?: readonly CommitOperationInput[];
|
|
488
|
-
readonly wait?: CommitWait;
|
|
489
|
-
/**
|
|
490
|
-
* Batch-level read dependencies (the STORM "did anything I looked at change?"
|
|
491
|
-
* layer). Declare the rows (`{model,id,readAt,fields?}`) or sync groups
|
|
492
|
-
* (`{group,readAt}`, e.g. `deck:abc`) this batch was premised on; the server
|
|
493
|
-
* validates none moved since `readAt` and fires the entry's `onStale` over the
|
|
494
|
-
* batch. Distinct from the write-target `readAt` — this guards what you READ,
|
|
495
|
-
* not what you write.
|
|
496
|
-
*/
|
|
497
|
-
readonly reads?: readonly ReadDependency[] | null;
|
|
498
|
-
}
|
|
499
|
-
export interface CommitReceipt {
|
|
500
|
-
readonly id: string;
|
|
501
|
-
readonly status: CommitWait;
|
|
502
|
-
readonly lastSyncId?: number;
|
|
503
|
-
/**
|
|
504
|
-
* Stale-context notifications (notify-instead-of-abort, non-coercion). Present
|
|
505
|
-
* only when this commit guarded a write with `onStale: 'notify' and
|
|
506
|
-
* the premise moved concurrently — the conflicting field's current value,
|
|
507
|
-
* handed back as data instead of a forced `AbloStaleContextError`. The engine
|
|
508
|
-
* surfaces state; the intelligent actor (agent or human) decides how to
|
|
509
|
-
* resolve. Also fires on `conflict:notified`.
|
|
510
|
-
*/
|
|
511
|
-
readonly notifications?: readonly StaleNotification[];
|
|
512
|
-
/**
|
|
513
|
-
* Ids of UPDATE/DELETE targets in this commit that matched ZERO rows (the row
|
|
514
|
-
* doesn't exist, or is outside the caller's org). Present (non-empty) only
|
|
515
|
-
* when a write missed. Typed resource wrappers turn this into a loud
|
|
516
|
-
* `AbloNotFoundError`; a raw `commits.create` caller can inspect it directly.
|
|
517
|
-
*/
|
|
518
|
-
readonly missingIds?: readonly string[];
|
|
519
|
-
}
|
|
520
|
-
export interface CommitResource {
|
|
521
|
-
create(options: CommitCreateOptions): Promise<CommitReceipt>;
|
|
522
|
-
}
|
|
523
|
-
export interface ClaimResource extends ClaimStream {
|
|
524
|
-
create(options: ClaimCreateOptions): Promise<Claim>;
|
|
525
|
-
list(target?: Partial<ModelTarget>): readonly ModelClaim[];
|
|
526
|
-
waitFor(target: Partial<ModelTarget>, options?: ClaimWaitOptions): Promise<void>;
|
|
527
|
-
}
|
|
528
|
-
export interface ModelMutationOptions extends ClaimedOptions {
|
|
529
|
-
readonly claimRef?: string | {
|
|
530
|
-
readonly id: string;
|
|
531
|
-
} | null;
|
|
532
|
-
readonly idempotencyKey?: string | null;
|
|
533
|
-
readonly readAt?: number | null;
|
|
534
|
-
readonly onStale?: 'reject' | 'overwrite' | 'notify' | null;
|
|
535
|
-
readonly wait?: CommitWait;
|
|
536
|
-
readonly claim?: Claim | ClaimOptions | null;
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* The HTTP/stateless claim surface. Normal tools usually put `claim` directly
|
|
540
|
-
* on the write (`update({ id, data, claim })`) and let the SDK release it. Use
|
|
541
|
-
* this namespace for multi-step handles and coordination screens.
|
|
542
|
-
*
|
|
543
|
-
* Same surface as the reactive {@link ClaimApi}, but every read is a server
|
|
544
|
-
* round-trip, so `state`/`queue`/`reorder` are **awaited** here (the WebSocket
|
|
545
|
-
* client resolves them synchronously from its local pool — which is what lets
|
|
546
|
-
* `useAblo((ablo) => ablo.x.claim.state({ id }))` work inside a React render; a
|
|
547
|
-
* stateless client has no pool to read, so the `Promise` is unavoidable).
|
|
548
|
-
*
|
|
549
|
-
* Mechanically DERIVED from `ClaimReadApi` via {@link AwaitedClaimMethod} so the
|
|
550
|
-
* two transports can never drift: the ONLY difference is the uniform `Promise`
|
|
551
|
-
* wrapper that statelessness forces. `claim({ id })` is identical (already async
|
|
552
|
-
* on both); `state`/`queue`/`reorder`/`release` are the awaited form.
|
|
553
|
-
*/
|
|
554
|
-
export type HttpClaimApi<T = Record<string, unknown>> = ((params: ClaimParams<T>) => Promise<HeldClaim<T>>) & {
|
|
555
|
-
[K in keyof ClaimReadApi<T>]: AwaitedClaimMethod<ClaimReadApi<T>[K]>;
|
|
556
|
-
};
|
|
557
|
-
export interface ModelClient<T = Record<string, unknown>> {
|
|
558
|
-
/**
|
|
559
|
-
* Single-row read over HTTP. **Returns an envelope, not the bare row** — the
|
|
560
|
-
* row is on `.data`, alongside the `.stamp` watermark (for stale-context
|
|
561
|
-
* guards on the following write) and any active `.claims`. A stateless HTTP
|
|
562
|
-
* client can't synthesize the watermark from a local snapshot, so the
|
|
563
|
-
* envelope is load-bearing here (the WebSocket client's `retrieve` returns
|
|
564
|
-
* `T | undefined` because it reads from the hydrated pool).
|
|
565
|
-
*
|
|
566
|
-
* ```ts
|
|
567
|
-
* const deal = await ablo.deals.retrieve({ id });
|
|
568
|
-
* deal.data?.recommendation; // ← the row is on .data
|
|
569
|
-
* deal.stamp; // watermark — pass to the next write's readAt
|
|
570
|
-
* ```
|
|
571
|
-
*/
|
|
572
|
-
retrieve(params: ModelReadOptions & {
|
|
573
|
-
readonly id: string;
|
|
574
|
-
}): Promise<ModelRead<T>>;
|
|
575
|
-
/**
|
|
576
|
-
* Collection read over HTTP (server round-trip). Equality `where`, `orderBy`,
|
|
577
|
-
* `limit`. Present on the stateless protocol client; the store-backed
|
|
578
|
-
* `.model(name)` accessor omits it (use the typed `ablo.<model>.list` there).
|
|
579
|
-
*/
|
|
580
|
-
list?(options?: ServerReadOptions<T>): Promise<T[]>;
|
|
581
|
-
/**
|
|
582
|
-
* Create a row and return it — the confirmed, authoritative server row (with
|
|
583
|
-
* framework defaults like `createdAt`/`createdBy`), mirroring the WebSocket
|
|
584
|
-
* client's `create`. A re-create of an existing caller-supplied id is
|
|
585
|
-
* idempotent and returns the EXISTING row, not the input.
|
|
586
|
-
*/
|
|
587
|
-
create(params: ModelMutationOptions & {
|
|
588
|
-
readonly data: Record<string, unknown>;
|
|
589
|
-
readonly id?: string | null;
|
|
590
|
-
}): Promise<T>;
|
|
591
|
-
update(params: ModelMutationOptions & {
|
|
592
|
-
readonly id: string;
|
|
593
|
-
readonly data: Record<string, unknown>;
|
|
594
|
-
}): Promise<CommitReceipt>;
|
|
595
|
-
/**
|
|
596
|
-
* Update under contention with a function of the latest state —
|
|
597
|
-
* `update(id, current => next)`, the `setState(prev => next)` of the data
|
|
598
|
-
* layer. The SDK reads the freshest row, runs your updater, writes it as a
|
|
599
|
-
* compare-and-swap against the row's watermark, and re-reads + re-runs on any
|
|
600
|
-
* concurrent write. No claim, no identity, no conflict codes surface: the
|
|
601
|
-
* write either lands or throws {@link AbloContentionError} once its reconcile
|
|
602
|
-
* budget is spent. Return `null`/`undefined` from the updater to skip the
|
|
603
|
-
* write (resolves to `undefined`).
|
|
604
|
-
*/
|
|
605
|
-
update(id: string, updater: ModelUpdater<T>, options?: ContentionOptions): Promise<CommitReceipt | undefined>;
|
|
606
|
-
delete(params: ModelMutationOptions & {
|
|
607
|
-
readonly id: string;
|
|
608
|
-
}): Promise<CommitReceipt>;
|
|
609
|
-
/**
|
|
610
|
-
* Durable lease + FIFO wait-line over HTTP — coordination without a socket.
|
|
611
|
-
* Present on the stateless protocol client (`Ablo({ schema: null })` /
|
|
612
|
-
* `createAbloHttpClient`); the store-backed `.model(name)` accessor omits it
|
|
613
|
-
* (the typed `ablo.<model>.claim` proxy is the full reactive namespace there).
|
|
614
|
-
*/
|
|
615
|
-
claim?: HttpClaimApi<T>;
|
|
616
|
-
}
|
|
617
|
-
/** A single data operation a scoped **agent** session may perform on a model. */
|
|
618
|
-
export type SessionOperation = 'read' | 'create' | 'update' | 'delete';
|
|
619
|
-
/** Mint params for an **end-user** session — full data authority within the
|
|
620
|
-
* org (the Stripe `ephemeralKeys.create` / Supabase session shape). Mints an
|
|
621
|
-
* `ek_` token. `user.id` is your end user's external IdP id (becomes the
|
|
622
|
-
* session's `participantId`); Ablo does not model your users, so it's an
|
|
623
|
-
* honest string at the trust boundary. */
|
|
624
|
-
export interface CreateUserSessionParams {
|
|
625
|
-
/** Your end user. `id` becomes the token's `participantId`. */
|
|
626
|
-
user: {
|
|
627
|
-
id: string;
|
|
628
|
-
};
|
|
629
|
-
/** Mint the session into THIS organization instead of the key's own org — the
|
|
630
|
-
* Stripe Connect `Stripe-Account` pattern, for a platform serving many tenants
|
|
631
|
-
* from one backend. Requires the `sk_` to carry the `ephemeral:mint-any-org`
|
|
632
|
-
* scope; omit for the normal single-tenant case. */
|
|
633
|
-
organizationId?: string;
|
|
634
|
-
/** Sync groups this session may subscribe to — typed (`'default'` or
|
|
635
|
-
* `<namespace>:<id>`; build with `syncGroup(kind, id)` from
|
|
636
|
-
* `@abloatai/ablo/schema`). Omit for the server default:
|
|
637
|
-
* `[org:<your org>, user:<user.id>]`. */
|
|
638
|
-
syncGroups?: readonly SyncGroupInput[];
|
|
639
|
-
/** Token lifetime in seconds. Defaults to 900 (15m, the Stripe ephemeral default). */
|
|
640
|
-
ttlSeconds?: number;
|
|
641
|
-
/** Opaque identity blob echoed back to the client as `ablo.user`. */
|
|
642
|
-
userMeta?: Record<string, unknown>;
|
|
643
|
-
agent?: never;
|
|
644
|
-
can?: never;
|
|
645
|
-
}
|
|
646
|
-
/** Mint params for a scoped **agent** session — mints a restricted `rk_` token
|
|
647
|
-
* gated to exactly the operations named in `can`. `can` is typed off your
|
|
648
|
-
* schema (no magic `'task.update'` strings): `{ Task: ['update'], Deck: ['read'] }`
|
|
649
|
-
* — the SDK serializes each entry to the wire allowlist (`task.update`). */
|
|
650
|
-
export interface CreateAgentSessionParams<S extends SchemaRecord> {
|
|
651
|
-
/** Your agent. `id` becomes the token's `participantId`. */
|
|
652
|
-
agent: {
|
|
653
|
-
id: string;
|
|
654
|
-
};
|
|
655
|
-
/** Per-model operation allowlist, typed against the schema's model names. */
|
|
656
|
-
can: {
|
|
657
|
-
[M in keyof S & string]?: readonly SessionOperation[];
|
|
658
|
-
};
|
|
659
|
-
/** Sync groups this session may subscribe to — typed (`'default'` or
|
|
660
|
-
* `<namespace>:<id>`; build with `syncGroup(kind, id)` from
|
|
661
|
-
* `@abloatai/ablo/schema`). Omit for the server default: the org
|
|
662
|
-
* anchor (`org:<your org>`) + the agent's own anchor. */
|
|
663
|
-
syncGroups?: readonly SyncGroupInput[];
|
|
664
|
-
/** Token lifetime in seconds. Defaults to 900 (15m, the Stripe ephemeral default). */
|
|
665
|
-
ttlSeconds?: number;
|
|
666
|
-
/** Opaque identity blob echoed back to the client as `ablo.agent`. */
|
|
667
|
-
userMeta?: Record<string, unknown>;
|
|
668
|
-
user?: never;
|
|
669
|
-
}
|
|
670
|
-
/** Params for {@link Ablo.sessions}.create — a discriminated union: pass
|
|
671
|
-
* `{ user }` for a full-authority end-user session (`ek_`) or `{ agent, can }`
|
|
672
|
-
* for a scoped agent session (`rk_`). */
|
|
673
|
-
export type CreateSessionParams<S extends SchemaRecord> = CreateUserSessionParams | CreateAgentSessionParams<S>;
|
|
674
|
-
/** Params for {@link Ablo.agents}.create — a flattened agent descriptor (no
|
|
675
|
-
* `{ agent }` discriminator: `agents.create` only ever mints an agent). Unlike
|
|
676
|
-
* {@link CreateSessionParams} it resolves to a connected, scoped {@link Ablo}
|
|
677
|
-
* client rather than a raw token. */
|
|
678
|
-
export interface CreateAgentClientParams<S extends SchemaRecord> {
|
|
679
|
-
/** Wire participant identity (`agent:<id>`) — what claim exclusion and the
|
|
680
|
-
* FIFO queue gate on. OMIT to get a fresh `crypto.randomUUID()`: a distinct,
|
|
681
|
-
* independent participant (the default, and what you want for concurrent
|
|
682
|
-
* agents). Pass a STABLE string only when one logical agent must re-attach
|
|
683
|
-
* to its own held claims across reconnects/restarts. */
|
|
684
|
-
id?: string;
|
|
685
|
-
/** Human-readable label for logs / attribution (carried in `userMeta.name`).
|
|
686
|
-
* INDEPENDENT of `id`: two agents that share a `name` still receive distinct
|
|
687
|
-
* ids and coordinate as SEPARATE participants — `name` never derives or
|
|
688
|
-
* collapses identity. */
|
|
689
|
-
name?: string;
|
|
690
|
-
/** Per-model operation allowlist, typed against the schema's model names. */
|
|
691
|
-
can: {
|
|
692
|
-
[M in keyof S & string]?: readonly SessionOperation[];
|
|
693
|
-
};
|
|
694
|
-
/** Sync groups this agent may subscribe to — typed (`'default'` or
|
|
695
|
-
* `<namespace>:<id>`). Omit for the server default (org anchor + the
|
|
696
|
-
* agent's own anchor). */
|
|
697
|
-
syncGroups?: readonly SyncGroupInput[];
|
|
698
|
-
/** Token lifetime in seconds. Defaults to 900 (15m); the returned client
|
|
699
|
-
* auto-re-mints before expiry, so a long-running agent never handles
|
|
700
|
-
* rotation itself. */
|
|
701
|
-
ttlSeconds?: number;
|
|
702
|
-
/** Extra opaque identity blob echoed on the session scope. Merged with
|
|
703
|
-
* `name` (the `name` param wins if you also set `userMeta.name`). */
|
|
704
|
-
userMeta?: Record<string, unknown>;
|
|
705
|
-
}
|
|
706
|
-
/** A minted session token — the Stripe ephemeral-key / Supabase session
|
|
707
|
-
* resource. `token` is the secret the holder presents as its bearer. */
|
|
708
|
-
export interface AbloSession {
|
|
709
|
-
object: 'session';
|
|
710
|
-
/** Stable id of the minted credential (for revocation). */
|
|
711
|
-
id: string;
|
|
712
|
-
/** The short-lived session token — `ek_` for a `{ user }` session, `rk_`
|
|
713
|
-
* for an `{ agent }` session. Hand this to the participant's runtime. */
|
|
714
|
-
token: string;
|
|
715
|
-
/** ISO-8601 expiry. */
|
|
716
|
-
expiresAt: string;
|
|
717
|
-
organizationId: string;
|
|
718
|
-
scope: {
|
|
719
|
-
organizationId: string;
|
|
720
|
-
syncGroups: readonly string[];
|
|
721
|
-
operations: readonly string[];
|
|
722
|
-
participantKind: 'user' | 'agent' | 'system';
|
|
723
|
-
participantId: string;
|
|
724
|
-
};
|
|
725
|
-
userMeta: Record<string, unknown>;
|
|
726
|
-
}
|
|
31
|
+
import type { AbloOptions } from './options.js';
|
|
32
|
+
import type { AbloSession, CommitResource, CreateAgentClientParams, CreateSessionParams, ModelClient } from './resourceTypes.js';
|
|
33
|
+
export type { ApiKeySetter, AbloOptions, InternalAbloOptions } from './options.js';
|
|
34
|
+
export type { LocalCountOptions, LocalReadOptions, ModelListScope, ServerReadOptions, ModelRetrieveParams, ModelCreateParams, ModelUpdateParams, ModelDeleteParams, ClaimOptions, ClaimParams, ClaimLookupParams, ClaimReorderParams, Claim, ClaimHeartbeat, ClaimHeartbeatOptions, HeldClaim, ModelOperations, ModelOperationAction, CommitWait, ModelRead, IfClaimedPolicy, ClaimedOptions, ClaimWaitOptions, ModelReadOptions, ClaimCreateOptions, CommitOperationInput, CommitCreateOptions, CommitReceipt, CommitResource, ClaimResource, ModelMutationOptions, HttpClaimApi, ModelClient, SessionOperation, CreateUserSessionParams, CreateAgentSessionParams, CreateSessionParams, CreateAgentClientParams, AbloSession, } from './resourceTypes.js';
|
|
35
|
+
export { computeFKDepthPriority } from './schemaConfig.js';
|
|
36
|
+
import type { ModelOperations } from './createModelProxy.js';
|
|
727
37
|
/** The typed sync engine client — one property per model in the schema */
|
|
728
38
|
export type Ablo<S extends SchemaRecord> = {
|
|
729
39
|
readonly [K in keyof S & string]: ModelOperations<InferModel<Schema<S>, K>, InferCreate<Schema<S>, K>>;
|
|
@@ -768,31 +78,32 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
768
78
|
/** Disconnect and clean up */
|
|
769
79
|
dispose(): Promise<void>;
|
|
770
80
|
/**
|
|
771
|
-
* Replace the bearer
|
|
772
|
-
*
|
|
773
|
-
*
|
|
774
|
-
*
|
|
775
|
-
*
|
|
776
|
-
*
|
|
81
|
+
* Replace the bearer token used for the WebSocket upgrade and HTTP requests,
|
|
82
|
+
* without tearing down the engine. Use it to push a refreshed short-lived
|
|
83
|
+
* access key (an `ek_` or `rk_`) before it expires — the client's `apiKey`
|
|
84
|
+
* resolver refresh loop calls this for you. It reuses the same rotation path as
|
|
85
|
+
* the internal capability-token refresh and is safe to call before `ready()`.
|
|
86
|
+
* It also nudges a parked connection to re-probe with the new token.
|
|
777
87
|
*/
|
|
778
88
|
setAuthToken(token: string): void;
|
|
779
89
|
/**
|
|
780
90
|
* Resolve the active bearer credential this engine authenticates with — the
|
|
781
|
-
* live `ek_
|
|
782
|
-
* fresh by the `apiKey
|
|
91
|
+
* live `ek_` or `rk_` the WebSocket and HTTP transports currently carry (kept
|
|
92
|
+
* fresh by the `apiKey` resolver refresh loop), falling back to a configured
|
|
783
93
|
* API key. Returns `null` when no credential is set yet. Use it to authenticate
|
|
784
|
-
* a side-band request to the same server with the
|
|
785
|
-
*
|
|
94
|
+
* a side-band request to the same server with the token this client already
|
|
95
|
+
* holds, avoiding an extra mint round-trip.
|
|
786
96
|
*/
|
|
787
97
|
getAuthToken(): Promise<string | null>;
|
|
788
98
|
/**
|
|
789
|
-
* Register a re-mint hook for the short-lived access key. The connection
|
|
790
|
-
*
|
|
791
|
-
*
|
|
792
|
-
* login.
|
|
793
|
-
* `null` when the login itself is gone (
|
|
794
|
-
* failure (
|
|
795
|
-
* from a function `apiKey`. Safe to call
|
|
99
|
+
* Register a re-mint hook for the short-lived access key. The connection layer
|
|
100
|
+
* calls it when it finds the key stale (a `credential_stale` probe) or on an
|
|
101
|
+
* external nudge; the hook mints a fresh `ek_` or `rk_` from the still-valid
|
|
102
|
+
* login. It follows the same contract as the `apiKey` resolver: resolve a
|
|
103
|
+
* token, resolve `null` when the login itself is gone (which signs the user
|
|
104
|
+
* out), or throw on a transient failure (which backs off without signing out).
|
|
105
|
+
* The client wires this automatically from a function `apiKey`. Safe to call
|
|
106
|
+
* before `ready()`.
|
|
796
107
|
*/
|
|
797
108
|
setCredentialRefresher(refresher: (() => Promise<string | null>) | null): void;
|
|
798
109
|
/**
|
|
@@ -804,21 +115,19 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
804
115
|
*/
|
|
805
116
|
nudgeReconnect(): void;
|
|
806
117
|
/**
|
|
807
|
-
* Mint a short-lived, scoped
|
|
808
|
-
*
|
|
809
|
-
*
|
|
810
|
-
*
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
* The browser must NEVER see the `sk_` key — only the per-user session token.
|
|
118
|
+
* Mint a short-lived, scoped session token for one end user. Call this on your
|
|
119
|
+
* backend, where the `sk_` secret key lives, then hand the returned `token` to
|
|
120
|
+
* that user's browser — typically through a token route the browser's `apiKey`
|
|
121
|
+
* resolver fetches. The browser presents the token as its bearer, and the
|
|
122
|
+
* server verifies it. The browser must never see the `sk_` key, only the
|
|
123
|
+
* per-user session token.
|
|
815
124
|
*
|
|
816
|
-
* Pass `{ user: { id } }` for a full-authority end-user session
|
|
817
|
-
* `
|
|
818
|
-
* row)
|
|
819
|
-
*
|
|
820
|
-
*
|
|
821
|
-
*
|
|
125
|
+
* Pass `{ user: { id } }` for a full-authority end-user session, which mints an
|
|
126
|
+
* `ek_` and attributes writes to a user (recorded as `actor_kind` on the delta
|
|
127
|
+
* row). Pass `{ agent: { id }, can: { tasks: ['update'] } }` for a scoped agent
|
|
128
|
+
* session, which mints an `rk_`; `can` is typed against your schema's model
|
|
129
|
+
* names. This always authenticates with the original `sk_`, never the client's
|
|
130
|
+
* exchanged sync credential.
|
|
822
131
|
*/
|
|
823
132
|
sessions: {
|
|
824
133
|
create(params: CreateSessionParams<S>): Promise<AbloSession>;
|
|
@@ -839,15 +148,16 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
839
148
|
* await agent.dispose(); // when the agent is done
|
|
840
149
|
* ```
|
|
841
150
|
*
|
|
842
|
-
* Server-side only
|
|
843
|
-
* throws `AbloAuthenticationError` in the browser. The returned client
|
|
844
|
-
* its own auto-refreshing `rk_`, so a long run never hits token expiry,
|
|
845
|
-
* the `sk_` never leaves this process. Each call is a
|
|
846
|
-
* default (omit `id`
|
|
847
|
-
* behind one another on a contended row — `name` is display only and
|
|
848
|
-
* collapses identity. Humans don't get a server-built client
|
|
849
|
-
* token via `sessions.create({ user })`.
|
|
850
|
-
* or a stable re-attachable id
|
|
151
|
+
* Server-side only: it requires the `sk_` secret key (like `sessions.create`)
|
|
152
|
+
* and throws `AbloAuthenticationError` in the browser. The returned client
|
|
153
|
+
* holds its own auto-refreshing `rk_`, so a long run never hits token expiry,
|
|
154
|
+
* and the `sk_` never leaves this process. Each call is a distinct participant
|
|
155
|
+
* by default (omit `id` for a fresh uuid), so even two agents sharing a `name`
|
|
156
|
+
* queue behind one another on a contended row — `name` is display only and
|
|
157
|
+
* never collapses identity. Humans don't get a server-built client; ship them a
|
|
158
|
+
* token via `sessions.create({ user })`. If you need the raw token for
|
|
159
|
+
* revocation, or a stable re-attachable id, use `sessions.create({ agent })`
|
|
160
|
+
* or pass `id`.
|
|
851
161
|
*/
|
|
852
162
|
agents: {
|
|
853
163
|
create(params: CreateAgentClientParams<S>): Promise<Ablo<S>>;
|
|
@@ -935,14 +245,14 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
935
245
|
/** The underlying schema */
|
|
936
246
|
readonly schema: Schema<S>;
|
|
937
247
|
/**
|
|
938
|
-
*
|
|
939
|
-
*
|
|
940
|
-
*
|
|
941
|
-
*
|
|
942
|
-
*
|
|
248
|
+
* A real-time presence livestream — who else is connected on this engine's
|
|
249
|
+
* sync groups, what they're doing, and a write surface for announcing this
|
|
250
|
+
* user's own activity. It rides the engine's existing WebSocket; opening a
|
|
251
|
+
* participant for presence does not open a second socket. See
|
|
252
|
+
* {@link PresenceStream}.
|
|
943
253
|
*
|
|
944
|
-
*
|
|
945
|
-
*
|
|
254
|
+
* The reference is stable for the engine's lifetime — the underlying connection
|
|
255
|
+
* is rotated on `dispose()`, but this object stays the same.
|
|
946
256
|
*/
|
|
947
257
|
readonly presence: PresenceStream;
|
|
948
258
|
/**
|
|
@@ -960,7 +270,7 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
960
270
|
* Capture a context-staleness watermark over a set of entities.
|
|
961
271
|
* Returns a flat snapshot with `stamp` (thread into writes as
|
|
962
272
|
* `readAt`), `signal` (aborts on any captured-entity delta), and
|
|
963
|
-
* `onChange` (callback form). Reads from the engine's
|
|
273
|
+
* `onChange` (callback form). Reads from the engine's InstanceCache;
|
|
964
274
|
* subscription is on the engine's existing transport.
|
|
965
275
|
*
|
|
966
276
|
* Use before an LLM call to prevent the model from completing
|
|
@@ -970,68 +280,21 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
970
280
|
* await streamText({ messages, signal: snap.signal });
|
|
971
281
|
* ```
|
|
972
282
|
*/
|
|
973
|
-
snapshot<ModelName extends keyof S & string>(entities:
|
|
974
|
-
readonly [M in ModelName]: string | readonly string[];
|
|
975
|
-
}): Snapshot<Schema<S>, ModelName>;
|
|
283
|
+
snapshot<ModelName extends keyof S & string>(entities: Readonly<Record<ModelName, string | readonly string[]>>): Snapshot<Schema<S>, ModelName>;
|
|
976
284
|
/**
|
|
977
|
-
* The internal
|
|
978
|
-
* SyncContext.Provider so the SDK's useModel/useModels/useMutations
|
|
979
|
-
* can
|
|
285
|
+
* The internal store. It implements {@link SyncStoreContract} — pass it to
|
|
286
|
+
* `SyncContext.Provider` so the SDK's `useModel` / `useModels` / `useMutations`
|
|
287
|
+
* hooks can reach it.
|
|
980
288
|
*/
|
|
981
289
|
readonly _store: SyncStoreContract;
|
|
982
|
-
/** The
|
|
983
|
-
readonly _pool:
|
|
290
|
+
/** The InstanceCache — for demand loaders and direct pool operations. */
|
|
291
|
+
readonly _pool: InstanceCache;
|
|
984
292
|
/**
|
|
985
293
|
* The SyncWebSocket handle — for collaboration events (slide selection,
|
|
986
294
|
* cursor broadcast). Null until the engine connects.
|
|
987
295
|
*/
|
|
988
296
|
readonly _ws: SyncWebSocket | null;
|
|
989
297
|
};
|
|
990
|
-
/**
|
|
991
|
-
* Compute a create-priority map from schema `belongsTo` relations using
|
|
992
|
-
* Tarjan's strongly-connected-components algorithm.
|
|
993
|
-
*
|
|
994
|
-
* The FK graph has an edge `child → parent` for every `belongsTo`. Tarjan
|
|
995
|
-
* runs a single linear DFS that simultaneously (a) detects cycles by
|
|
996
|
-
* grouping mutually-reachable nodes into SCCs and (b) emits those SCCs
|
|
997
|
-
* in reverse topological order of the condensation graph. In this edge
|
|
998
|
-
* convention a "sink" SCC has no outgoing edges — i.e. no parents — so
|
|
999
|
-
* it is an *FK root* (`organizations`, `themes`, etc.). Tarjan emits
|
|
1000
|
-
* roots first and leaves last, exactly the order in which rows must be
|
|
1001
|
-
* inserted to satisfy FK constraints.
|
|
1002
|
-
*
|
|
1003
|
-
* Priorities are assigned by emit order: SCC #0 → 10, SCC #1 → 20, …
|
|
1004
|
-
* Members of the same SCC share a priority, so insertion order wins the
|
|
1005
|
-
* tiebreak inside a cycle (this matters for cyclic schemas like
|
|
1006
|
-
* `slideDecks ↔ layouts`, where one direction is the user's chosen
|
|
1007
|
-
* "soft" edge — only the consumer's mutator sequence knows which one).
|
|
1008
|
-
*
|
|
1009
|
-
* This algorithm is iteration-order-independent: starting the DFS from
|
|
1010
|
-
* any node yields the same SCC partitioning, and SCCs always come out
|
|
1011
|
-
* in valid topological order. The previous DFS-with-memoization
|
|
1012
|
-
* heuristic broke under cycles by treating the back-edge as depth 0,
|
|
1013
|
-
* which made priorities depend on which node the walk happened to
|
|
1014
|
-
* enter the cycle at.
|
|
1015
|
-
*
|
|
1016
|
-
* Schema authors can mark one side of a cycle with
|
|
1017
|
-
* `belongsTo(target, fk, { defer: true })`. Those edges are excluded
|
|
1018
|
-
* from the dependency graph entirely, which deterministically breaks
|
|
1019
|
-
* the cycle and turns the SCC into a chain — the marked child gets a
|
|
1020
|
-
* strictly higher priority than its parent instead of being tied with
|
|
1021
|
-
* it. Pair with a Postgres `DEFERRABLE INITIALLY DEFERRED` constraint
|
|
1022
|
-
* if you want the database side of the cycle to also relax. See
|
|
1023
|
-
* {@link BelongsToOptions.defer}.
|
|
1024
|
-
*
|
|
1025
|
-
* The returned map is keyed by {@link ModelDef.typename} (falling back
|
|
1026
|
-
* to the schema key), because that is what `Model.getModelName()`
|
|
1027
|
-
* returns at transaction time — keying by schema key would silently
|
|
1028
|
-
* miss the lookup and every model would fall through to
|
|
1029
|
-
* `defaultCreatePriority`.
|
|
1030
|
-
*
|
|
1031
|
-
* Reference: Tarjan, R. (1972), "Depth-first search and linear graph
|
|
1032
|
-
* algorithms." Linear in V + E.
|
|
1033
|
-
*/
|
|
1034
|
-
export declare function computeFKDepthPriority(schema: Schema): ReadonlyMap<string, number>;
|
|
1035
298
|
/**
|
|
1036
299
|
* Create a sync engine client in one call.
|
|
1037
300
|
*
|
|
@@ -1042,6 +305,14 @@ export declare function computeFKDepthPriority(schema: Schema): ReadonlyMap<stri
|
|
|
1042
305
|
* await sync.weatherReports.create({ location: 'Stockholm', status: 'pending' });
|
|
1043
306
|
* ```
|
|
1044
307
|
*
|
|
308
|
+
* In the browser (or any client that shouldn't hold a secret key), point
|
|
309
|
+
* `authEndpoint` at your session-mint route instead — the SDK fetches it, keeps the
|
|
310
|
+
* short-lived token fresh, and re-mints on expiry:
|
|
311
|
+
*
|
|
312
|
+
* ```ts
|
|
313
|
+
* const ablo = Ablo({ schema, authEndpoint: '/api/ablo-session' });
|
|
314
|
+
* ```
|
|
315
|
+
*
|
|
1045
316
|
* Pass `transport: 'http'` for the stateless server-side client (agents,
|
|
1046
317
|
* workers, serverless) — same `ablo.<model>` surface, no socket:
|
|
1047
318
|
*
|
|
@@ -1063,22 +334,20 @@ import type * as _Tx from '../mutators/Transaction.js';
|
|
|
1063
334
|
import type * as _Undo from '../mutators/UndoManager.js';
|
|
1064
335
|
import type * as _SchemaTypes from '../schema/schema.js';
|
|
1065
336
|
/**
|
|
1066
|
-
*
|
|
1067
|
-
*
|
|
1068
|
-
* Locked rules — apply uniformly to every future addition:
|
|
337
|
+
* The canonical type namespace.
|
|
1069
338
|
*
|
|
1070
|
-
*
|
|
1071
|
-
* 2. Sub-namespace ONLY when (a) 4+ types share a single conceptual
|
|
1072
|
-
* prefix, AND (b) names read better with the prefix (`Conflict.Kind`
|
|
1073
|
-
* over `ConflictKind`). If the cluster is heterogeneous (streams +
|
|
1074
|
-
* data + handles), keep flat.
|
|
1075
|
-
* 3. Only types a consumer would write `: Ablo.X` for. Inferred-only
|
|
1076
|
-
* types stay un-exported.
|
|
1077
|
-
* 4. Wire shapes never on `Ablo.*`. Engine vocabulary only.
|
|
1078
|
-
* 5. Advanced / framework-integration types stay internal unless they
|
|
1079
|
-
* graduate into one of the public subpaths.
|
|
339
|
+
* Rules applied uniformly to every addition:
|
|
1080
340
|
*
|
|
1081
|
-
*
|
|
341
|
+
* 1. Flat by default. `Ablo.X`. Fewest dots wins.
|
|
342
|
+
* 2. Sub-namespace only when (a) four or more types share a single conceptual
|
|
343
|
+
* prefix and (b) the names read better with it (`Conflict.Kind` over
|
|
344
|
+
* `ConflictKind`). If the cluster is heterogeneous (streams, data, handles),
|
|
345
|
+
* keep it flat.
|
|
346
|
+
* 3. Only types a consumer would write `: Ablo.X` for. Inferred-only types stay
|
|
347
|
+
* unexported.
|
|
348
|
+
* 4. Wire shapes never appear on `Ablo.*` — engine vocabulary only.
|
|
349
|
+
* 5. Advanced or framework-integration types stay internal unless they graduate
|
|
350
|
+
* into one of the public subpaths.
|
|
1082
351
|
*/
|
|
1083
352
|
export declare namespace Ablo {
|
|
1084
353
|
type Options<S extends SchemaRecord = SchemaRecord> = AbloOptions<S>;
|
|
@@ -1091,8 +360,8 @@ export declare namespace Ablo {
|
|
|
1091
360
|
type CapabilityRevocation = import('./ApiClient.js').CapabilityRevocation;
|
|
1092
361
|
type CapabilityRotateOptions = import('./ApiClient.js').CapabilityRotateOptions;
|
|
1093
362
|
type RotatedCapability = import('./ApiClient.js').RotatedCapability;
|
|
1094
|
-
type IfClaimedPolicy = import('./
|
|
1095
|
-
type ClaimedOptions = import('./
|
|
363
|
+
type IfClaimedPolicy = import('./resourceTypes.js').IfClaimedPolicy;
|
|
364
|
+
type ClaimedOptions = import('./resourceTypes.js').ClaimedOptions;
|
|
1096
365
|
type ClaimTarget = _Streams.ClaimTarget;
|
|
1097
366
|
type PresenceTarget = _Streams.PresenceTarget;
|
|
1098
367
|
type TargetRange = _Streams.TargetRange;
|
|
@@ -1104,6 +373,8 @@ export declare namespace Ablo {
|
|
|
1104
373
|
type Claim = _Streams.Claim;
|
|
1105
374
|
type ClaimRejection = _Streams.ClaimRejection;
|
|
1106
375
|
type ClaimLost = _Streams.ClaimLost;
|
|
376
|
+
type ClaimHeartbeat = _Streams.ClaimHeartbeat;
|
|
377
|
+
type ClaimHeartbeatOptions = _Streams.ClaimHeartbeatOptions;
|
|
1107
378
|
type Snapshot<TSchema extends _SchemaTypes.Schema = _SchemaTypes.Schema, K extends keyof TSchema['models'] = keyof TSchema['models']> = _Streams.Snapshot<TSchema, K>;
|
|
1108
379
|
namespace Auth {
|
|
1109
380
|
type Actor = _Streams.ParticipantRef;
|
|
@@ -1130,26 +401,26 @@ export declare namespace Ablo {
|
|
|
1130
401
|
type Axis = _Policy.ConflictAxis;
|
|
1131
402
|
}
|
|
1132
403
|
namespace Commit {
|
|
1133
|
-
type Wait = import('./
|
|
1134
|
-
type OperationAction = import('./
|
|
1135
|
-
type OperationInput = import('./
|
|
1136
|
-
type CreateOptions = import('./
|
|
1137
|
-
type Receipt = import('./
|
|
1138
|
-
type Client = import('./
|
|
404
|
+
type Wait = import('./resourceTypes.js').CommitWait;
|
|
405
|
+
type OperationAction = import('./resourceTypes.js').ModelOperationAction;
|
|
406
|
+
type OperationInput = import('./resourceTypes.js').CommitOperationInput;
|
|
407
|
+
type CreateOptions = import('./resourceTypes.js').CommitCreateOptions;
|
|
408
|
+
type Receipt = import('./resourceTypes.js').CommitReceipt;
|
|
409
|
+
type Client = import('./resourceTypes.js').CommitResource;
|
|
1139
410
|
}
|
|
1140
411
|
namespace Claim {
|
|
1141
|
-
type Handle = import('./
|
|
1142
|
-
type CreateOptions = import('./
|
|
1143
|
-
type WaitOptions = import('./
|
|
1144
|
-
type Client = import('./
|
|
412
|
+
type Handle = import('./resourceTypes.js').Claim;
|
|
413
|
+
type CreateOptions = import('./resourceTypes.js').ClaimCreateOptions;
|
|
414
|
+
type WaitOptions = import('./resourceTypes.js').ClaimWaitOptions;
|
|
415
|
+
type Client = import('./resourceTypes.js').ClaimResource;
|
|
1145
416
|
}
|
|
1146
417
|
namespace Model {
|
|
1147
|
-
type Target = import('./
|
|
1148
|
-
type Claim = import('./
|
|
1149
|
-
type Read<T = Record<string, unknown>> = import('./
|
|
1150
|
-
type Client<T = Record<string, unknown>> = import('./
|
|
1151
|
-
type ReadOptions = import('./
|
|
1152
|
-
type MutationOptions = import('./
|
|
418
|
+
type Target = import('./resourceTypes.js').ModelTarget;
|
|
419
|
+
type Claim = import('./resourceTypes.js').ModelClaim;
|
|
420
|
+
type Read<T = Record<string, unknown>> = import('./resourceTypes.js').ModelRead<T>;
|
|
421
|
+
type Client<T = Record<string, unknown>> = import('./resourceTypes.js').ModelClient<T>;
|
|
422
|
+
type ReadOptions = import('./resourceTypes.js').ModelReadOptions;
|
|
423
|
+
type MutationOptions = import('./resourceTypes.js').ModelMutationOptions;
|
|
1153
424
|
}
|
|
1154
425
|
namespace Source {
|
|
1155
426
|
type Operation = import('../source/index.js').SourceOperation;
|