@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/auth.d.ts
CHANGED
|
@@ -1,39 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Authentication and URL resolution for the `Ablo()` client.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* sequence of named decisions rather than a stream of `??`-chains.
|
|
4
|
+
* Each function here makes one decision: it resolves a configuration value with
|
|
5
|
+
* the right precedence, or fails with an actionable message. Together they let
|
|
6
|
+
* the client constructor read as a sequence of named steps rather than a chain
|
|
7
|
+
* of fallbacks.
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* explicit
|
|
9
|
+
* The environment surface is deliberately small: `ABLO_API_KEY` is the only
|
|
10
|
+
* value read from the environment. Every other routing or authentication
|
|
11
|
+
* override is an explicit option, so an app never picks up hidden behavior from
|
|
12
|
+
* a stray environment variable.
|
|
13
13
|
*/
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* from `./Ablo` so existing import paths work; defined here so this module
|
|
20
|
-
* has no circular dependency back to `Ablo.ts`.
|
|
21
|
-
*
|
|
22
|
-
* Contract: resolve a token; resolve `null` when the login itself is gone
|
|
23
|
-
* (terminal → the credential lifecycle treats this as `session_expired` and
|
|
24
|
-
* signs out); or THROW on a transient failure (→ back off and retry, never
|
|
25
|
-
* sign out). A long-lived static `apiKey` string needs none of this — it is
|
|
26
|
-
* used as-is. This is the single credential resolver the SDK supports.
|
|
15
|
+
* The credential-resolver callable type. It is defined alongside
|
|
16
|
+
* {@link createEndpointCredentialResolver} in `./credentialEndpoint` and
|
|
17
|
+
* re-exported here so importers of this module keep working. See that module
|
|
18
|
+
* for the full contract.
|
|
27
19
|
*/
|
|
28
|
-
|
|
20
|
+
import type { ApiKeySetter } from './credentialEndpoint.js';
|
|
21
|
+
export type { ApiKeySetter };
|
|
29
22
|
export interface AuthResolveInput {
|
|
30
23
|
/**
|
|
31
|
-
* The full options
|
|
32
|
-
*
|
|
33
|
-
*
|
|
24
|
+
* The full set of options the caller passed to the client constructor. Each
|
|
25
|
+
* resolver reads only the fields it needs; passing the whole object avoids
|
|
26
|
+
* threading many separate parameters through every helper.
|
|
34
27
|
*/
|
|
35
28
|
readonly options: {
|
|
36
29
|
readonly apiKey?: string | ApiKeySetter | null;
|
|
30
|
+
readonly authEndpoint?: string | ApiKeySetter | null;
|
|
37
31
|
readonly authToken?: string | null;
|
|
38
32
|
readonly baseURL?: string | null;
|
|
39
33
|
readonly databaseUrl?: string | null;
|
|
@@ -69,40 +63,41 @@ export interface CliKeyMismatch {
|
|
|
69
63
|
readonly kind: 'mode_mismatch' | 'key_override';
|
|
70
64
|
readonly message: string;
|
|
71
65
|
}
|
|
72
|
-
/** Infer sandbox
|
|
66
|
+
/** Infer the sandbox or production mode from an Ablo key's prefix. */
|
|
73
67
|
export declare function modeFromApiKey(key: string): CliMode | undefined;
|
|
74
68
|
export declare function describeCliKeyMismatch(configured: StaticApiKey, cli: CliCredentialSnapshot): CliKeyMismatch | null;
|
|
75
69
|
/**
|
|
76
|
-
*
|
|
70
|
+
* Resolves the Postgres connection string for the direct-connection option, or
|
|
71
|
+
* `null` when none was given.
|
|
77
72
|
*
|
|
78
|
-
* `databaseUrl` is
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
73
|
+
* `databaseUrl` is opt-in: the client registers a dedicated database only when
|
|
74
|
+
* the caller passes it explicitly. It is never read from
|
|
75
|
+
* `process.env.DATABASE_URL`, because this module treats `ABLO_API_KEY` as the
|
|
76
|
+
* one environment fallback — an app's `DATABASE_URL`, commonly set for other
|
|
77
|
+
* tools, must not silently switch the client into connection-string mode. The
|
|
78
|
+
* default path leaves `DATABASE_URL` untouched and reads through `dataSource(...)`
|
|
79
|
+
* instead, so this returns `null`. {@link warnIfDatabaseUrlEnvIgnored} nudges a
|
|
80
|
+
* caller who set the environment variable but omitted the option.
|
|
86
81
|
*/
|
|
87
82
|
export declare function resolveDatabaseUrl(input: AuthResolveInput): string | null;
|
|
88
83
|
export declare function warnIfDatabaseUrlEnvIgnored(input: AuthResolveInput, warn?: (message: string) => void): void;
|
|
89
84
|
export declare function warnIfDatabaseUrlDeprecated(input: AuthResolveInput, warn?: (message: string) => void): void;
|
|
90
85
|
export declare function warnIfCliKeyMismatch(input: AuthResolveInput, warn?: (message: string) => void): Promise<void>;
|
|
91
|
-
export
|
|
92
|
-
export declare const ABLO_HOSTED_HTTP_BASE_URL = "https://api.abloatai.com";
|
|
93
|
-
export declare const ABLO_DEFAULT_BASE_URL = "https://api.abloatai.com";
|
|
86
|
+
export { ABLO_HOSTED_API_DOMAIN, ABLO_HOSTED_HTTP_BASE_URL, ABLO_DEFAULT_BASE_URL } from './hostedEndpoints.js';
|
|
94
87
|
/**
|
|
95
|
-
*
|
|
96
|
-
* URLs pass through unchanged; only
|
|
88
|
+
* Normalizes older hosted host names to the current public API domain.
|
|
89
|
+
* Self-hosted or custom URLs pass through unchanged; only the retired
|
|
90
|
+
* first-party host names are rewritten.
|
|
97
91
|
*/
|
|
98
92
|
export declare function normalizeAbloHostedBaseUrl(rawUrl: string): string;
|
|
99
93
|
export declare function resolveBaseURL(input: AuthResolveInput): string;
|
|
100
94
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
95
|
+
* Guards against using a secret `apiKey` in a browser. A secret key is
|
|
96
|
+
* server-side only by default: shipping an `sk_live_...` key to a browser would
|
|
97
|
+
* expose it in every visitor's network tab. Callers opt in explicitly when the
|
|
98
|
+
* browser instead holds a minted session token (`ek_`/`rk_`) or routes through a
|
|
99
|
+
* server proxy. Throws {@link AbloAuthenticationError} when a secret key is
|
|
100
|
+
* detected in a browser without opt-in.
|
|
106
101
|
*/
|
|
107
102
|
export declare function assertBrowserSafety(input: {
|
|
108
103
|
apiKey: string | ApiKeySetter | null;
|
|
@@ -110,27 +105,23 @@ export declare function assertBrowserSafety(input: {
|
|
|
110
105
|
dangerouslyAllowBrowser: boolean | undefined;
|
|
111
106
|
}): void;
|
|
112
107
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* between requests. Returns `null` when no key
|
|
116
|
-
*
|
|
117
|
-
* Mirrors Anthropic's pattern of supporting both a static string and
|
|
118
|
-
* a callable for credential rotation.
|
|
108
|
+
* Resolves an {@link ApiKeySetter} callable to its current string value, or
|
|
109
|
+
* returns a plain string key as-is. Called at request time so a rotating
|
|
110
|
+
* credential picks up new values between requests. Returns `null` when no key
|
|
111
|
+
* was configured.
|
|
119
112
|
*/
|
|
120
113
|
export declare function resolveApiKeyValue(apiKey: string | ApiKeySetter | null): Promise<string | null>;
|
|
121
114
|
/**
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* so it lives here as a single source of truth.
|
|
115
|
+
* Translates a WebSocket URL into the matching HTTP API base URL, defaulting to
|
|
116
|
+
* `${url}/api` when the caller has not overridden `bootstrapBaseUrl`. The
|
|
117
|
+
* bootstrap helper, the hydration coordinator, the credential-exchange flow, and
|
|
118
|
+
* the identity flow all derive their base URL through this one function, so the
|
|
119
|
+
* derivation stays consistent across them.
|
|
128
120
|
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
121
|
+
* When both `wss://` and `https://` are valid, the ws-to-http rewrite preserves
|
|
122
|
+
* the protocol family: ws becomes http and wss becomes https.
|
|
131
123
|
*/
|
|
132
124
|
export declare function resolveBootstrapBaseUrl(input: {
|
|
133
125
|
readonly url: string;
|
|
134
126
|
readonly bootstrapBaseUrl?: string;
|
|
135
127
|
}): string;
|
|
136
|
-
export {};
|
package/dist/client/auth.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Authentication and URL resolution for the `Ablo()` client.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* sequence of named decisions rather than a stream of `??`-chains.
|
|
4
|
+
* Each function here makes one decision: it resolves a configuration value with
|
|
5
|
+
* the right precedence, or fails with an actionable message. Together they let
|
|
6
|
+
* the client constructor read as a sequence of named steps rather than a chain
|
|
7
|
+
* of fallbacks.
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* explicit
|
|
9
|
+
* The environment surface is deliberately small: `ABLO_API_KEY` is the only
|
|
10
|
+
* value read from the environment. Every other routing or authentication
|
|
11
|
+
* override is an explicit option, so an app never picks up hidden behavior from
|
|
12
|
+
* a stray environment variable.
|
|
13
13
|
*/
|
|
14
|
-
import { AbloAuthenticationError } from '../errors.js';
|
|
14
|
+
import { AbloAuthenticationError, AbloValidationError } from '../errors.js';
|
|
15
15
|
import { classifyCredentialKind } from '../auth/credentialPolicy.js';
|
|
16
|
+
import { ABLO_HOSTED_API_DOMAIN, ABLO_DEFAULT_BASE_URL } from './hostedEndpoints.js';
|
|
17
|
+
import { isCredentialEndpoint, createEndpointCredentialResolver } from './credentialEndpoint.js';
|
|
16
18
|
/**
|
|
17
19
|
* Read `process.env` defensively. Works in browser (where `process`
|
|
18
20
|
* is undefined), Node, and edge runtimes that expose a partial
|
|
@@ -23,7 +25,36 @@ export function readProcessEnv() {
|
|
|
23
25
|
return maybeGlobal.process?.env ?? {};
|
|
24
26
|
}
|
|
25
27
|
export function resolveApiKey(input) {
|
|
26
|
-
|
|
28
|
+
// `authEndpoint` is the option that names a session-mint route: a URL the
|
|
29
|
+
// client exchanges for a short-lived token, or an async resolver for custom
|
|
30
|
+
// exchanges. It is resolved into an `ApiKeySetter` here — the single point
|
|
31
|
+
// shared by every client variant (WebSocket, HTTP, and protocol clients) — so
|
|
32
|
+
// every downstream consumer sees the same resolver and the credential
|
|
33
|
+
// lifecycle drives renewal off it.
|
|
34
|
+
const endpoint = input.options.authEndpoint;
|
|
35
|
+
const configured = input.options.apiKey;
|
|
36
|
+
if (endpoint != null) {
|
|
37
|
+
if (configured != null) {
|
|
38
|
+
throw new AbloValidationError('Ablo: pass either `apiKey` (a key the process holds) or `authEndpoint` ' +
|
|
39
|
+
'(a route that mints the token) — not both; the client cannot know ' +
|
|
40
|
+
'which credential to use.', { code: 'invalid_options', param: 'authEndpoint' });
|
|
41
|
+
}
|
|
42
|
+
if (typeof endpoint === 'function')
|
|
43
|
+
return endpoint;
|
|
44
|
+
if (!isCredentialEndpoint(endpoint)) {
|
|
45
|
+
throw new AbloValidationError('`authEndpoint` expects a URL or path (e.g. \'/api/ablo-session\') or an ' +
|
|
46
|
+
'async resolver — a key string belongs in `apiKey`.', { code: 'invalid_options', param: 'authEndpoint' });
|
|
47
|
+
}
|
|
48
|
+
return createEndpointCredentialResolver(endpoint);
|
|
49
|
+
}
|
|
50
|
+
// `apiKey` also accepts the endpoint-string form directly, detected the same
|
|
51
|
+
// way — key strings are prefixed (`sk_`/`ek_`/`rk_`), so the two shapes never
|
|
52
|
+
// collide. Only the explicit option is treated this way: an `ABLO_API_KEY`
|
|
53
|
+
// environment value is always a literal key, never an endpoint.
|
|
54
|
+
if (typeof configured === 'string' && isCredentialEndpoint(configured)) {
|
|
55
|
+
return createEndpointCredentialResolver(configured);
|
|
56
|
+
}
|
|
57
|
+
return configured ?? input.env.ABLO_API_KEY ?? null;
|
|
27
58
|
}
|
|
28
59
|
export function resolveAuthToken(input) {
|
|
29
60
|
return input.options.authToken ?? null;
|
|
@@ -31,7 +62,7 @@ export function resolveAuthToken(input) {
|
|
|
31
62
|
function keyPrefix(key) {
|
|
32
63
|
return `${key.slice(0, 12)}…`;
|
|
33
64
|
}
|
|
34
|
-
/** Infer sandbox
|
|
65
|
+
/** Infer the sandbox or production mode from an Ablo key's prefix. */
|
|
35
66
|
export function modeFromApiKey(key) {
|
|
36
67
|
if (/^(sk|rk)_test_/.test(key))
|
|
37
68
|
return 'sandbox';
|
|
@@ -41,6 +72,10 @@ export function modeFromApiKey(key) {
|
|
|
41
72
|
}
|
|
42
73
|
function resolveStaticApiKey(input) {
|
|
43
74
|
if (typeof input.options.apiKey === 'string') {
|
|
75
|
+
// An endpoint-string `apiKey` is not a key — it never participates in
|
|
76
|
+
// CLI-mode mismatch checks (its minted tokens carry the mode instead).
|
|
77
|
+
if (isCredentialEndpoint(input.options.apiKey))
|
|
78
|
+
return null;
|
|
44
79
|
return { key: input.options.apiKey, source: 'option' };
|
|
45
80
|
}
|
|
46
81
|
if (input.options.apiKey !== undefined && input.options.apiKey !== null) {
|
|
@@ -189,39 +224,38 @@ export function describeCliKeyMismatch(configured, cli) {
|
|
|
189
224
|
return null;
|
|
190
225
|
}
|
|
191
226
|
/**
|
|
192
|
-
*
|
|
227
|
+
* Resolves the Postgres connection string for the direct-connection option, or
|
|
228
|
+
* `null` when none was given.
|
|
193
229
|
*
|
|
194
|
-
* `databaseUrl` is
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
230
|
+
* `databaseUrl` is opt-in: the client registers a dedicated database only when
|
|
231
|
+
* the caller passes it explicitly. It is never read from
|
|
232
|
+
* `process.env.DATABASE_URL`, because this module treats `ABLO_API_KEY` as the
|
|
233
|
+
* one environment fallback — an app's `DATABASE_URL`, commonly set for other
|
|
234
|
+
* tools, must not silently switch the client into connection-string mode. The
|
|
235
|
+
* default path leaves `DATABASE_URL` untouched and reads through `dataSource(...)`
|
|
236
|
+
* instead, so this returns `null`. {@link warnIfDatabaseUrlEnvIgnored} nudges a
|
|
237
|
+
* caller who set the environment variable but omitted the option.
|
|
202
238
|
*/
|
|
203
239
|
export function resolveDatabaseUrl(input) {
|
|
204
240
|
return input.options.databaseUrl ?? null;
|
|
205
241
|
}
|
|
206
242
|
/**
|
|
207
|
-
*
|
|
243
|
+
* Warns once when `DATABASE_URL` is set in the environment but `databaseUrl` was
|
|
244
|
+
* not passed as an option.
|
|
208
245
|
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
* (the `transport: 'api'` client has none).
|
|
246
|
+
* The client does not adopt `process.env.DATABASE_URL` on its own, because that
|
|
247
|
+
* value is commonly set for other tools and switching the client into
|
|
248
|
+
* connection-string mode behind the caller's back is surprising — and on
|
|
249
|
+
* localhost it would try to register a database the hosted service cannot reach.
|
|
250
|
+
* This warning points the developer at the explicit option instead. It fires at
|
|
251
|
+
* most once per process and falls back to `console.warn` when no logger is
|
|
252
|
+
* supplied.
|
|
217
253
|
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
* false positive. This is the first-party hosted app's exact shape, where the
|
|
224
|
-
* stray nudge otherwise reaches end-user desktop logs.
|
|
254
|
+
* The warning is skipped entirely when an `apiKey` resolves (from the option or
|
|
255
|
+
* `ABLO_API_KEY`): that caller has chosen the hosted, token-based transport,
|
|
256
|
+
* which is separate from the direct `databaseUrl` connection. A `DATABASE_URL`
|
|
257
|
+
* present in that environment belongs to unrelated infrastructure, not an omitted
|
|
258
|
+
* option, so warning would be a false positive.
|
|
225
259
|
*/
|
|
226
260
|
let warnedDatabaseUrlEnvIgnored = false;
|
|
227
261
|
export function warnIfDatabaseUrlEnvIgnored(input, warn) {
|
|
@@ -246,19 +280,18 @@ export function warnIfDatabaseUrlEnvIgnored(input, warn) {
|
|
|
246
280
|
console.warn('[Ablo]', message);
|
|
247
281
|
}
|
|
248
282
|
/**
|
|
249
|
-
*
|
|
283
|
+
* Warns once when the deprecated `databaseUrl` option is used.
|
|
250
284
|
*
|
|
251
|
-
* `databaseUrl`
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
* credentials never leave it. See docs/plans/stripe-shaped-storage-posture.md.
|
|
285
|
+
* Passing `databaseUrl` opens a connection pool directly into your Postgres and
|
|
286
|
+
* writes to it. That option is deprecated. Ablo is designed to host only the
|
|
287
|
+
* ordered transaction log (the `sync_deltas` table) and coordination state,
|
|
288
|
+
* never your rows — your data stays in your own database. The supported path is
|
|
289
|
+
* a signed data-source endpoint (`dataSource(...)`), where your app owns the
|
|
290
|
+
* write and your database credentials never leave it.
|
|
258
291
|
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
* logger is supplied
|
|
292
|
+
* The option still works at runtime so existing integrations keep running. This
|
|
293
|
+
* warning fires at most once per process and falls back to `console.warn` when
|
|
294
|
+
* no logger is supplied.
|
|
262
295
|
*/
|
|
263
296
|
let warnedDatabaseUrlDeprecated = false;
|
|
264
297
|
export function warnIfDatabaseUrlDeprecated(input, warn) {
|
|
@@ -299,9 +332,9 @@ export async function warnIfCliKeyMismatch(input, warn) {
|
|
|
299
332
|
else if (typeof console !== 'undefined')
|
|
300
333
|
console.warn('[Ablo]', mismatch.message);
|
|
301
334
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
export
|
|
335
|
+
// Declared in `./hostedEndpoints`, the single source of the hosted domain, and
|
|
336
|
+
// re-exported here so existing import paths keep working.
|
|
337
|
+
export { ABLO_HOSTED_API_DOMAIN, ABLO_HOSTED_HTTP_BASE_URL, ABLO_DEFAULT_BASE_URL } from './hostedEndpoints.js';
|
|
305
338
|
const LEGACY_HOSTED_API_HOSTS = new Set([
|
|
306
339
|
'mesh.ablo.finance',
|
|
307
340
|
'mesh-staging.ablo.finance',
|
|
@@ -309,29 +342,29 @@ const LEGACY_HOSTED_API_HOSTS = new Set([
|
|
|
309
342
|
'sync-staging.ablo.finance',
|
|
310
343
|
]);
|
|
311
344
|
/**
|
|
312
|
-
*
|
|
313
|
-
* URLs pass through unchanged; only
|
|
345
|
+
* Normalizes older hosted host names to the current public API domain.
|
|
346
|
+
* Self-hosted or custom URLs pass through unchanged; only the retired
|
|
347
|
+
* first-party host names are rewritten.
|
|
314
348
|
*/
|
|
315
349
|
export function normalizeAbloHostedBaseUrl(rawUrl) {
|
|
316
350
|
const trimmed = rawUrl.trim();
|
|
317
351
|
if (!trimmed)
|
|
318
352
|
return trimmed;
|
|
319
|
-
// A scheme-less value (e.g. `api-staging.abloatai.com`) is
|
|
320
|
-
// `new URL()` throws on it, and
|
|
321
|
-
// the current page — producing
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
// preserved untouched.
|
|
353
|
+
// A scheme-less value (e.g. `api-staging.abloatai.com`) is treated as a
|
|
354
|
+
// relative URL: `new URL()` throws on it, and a later `fetch` would resolve it
|
|
355
|
+
// against the current page — producing a 404 from the app's own origin.
|
|
356
|
+
// Prepending a scheme makes the base absolute. `https` matches
|
|
357
|
+
// {@link ABLO_HOSTED_HTTP_BASE_URL}; the socket layer derives `wss` from it.
|
|
358
|
+
// An existing scheme (ws, wss, http, or https) is preserved untouched.
|
|
326
359
|
const schemed = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
|
|
327
360
|
try {
|
|
328
361
|
const url = new URL(schemed);
|
|
329
|
-
// Canonicalize the scheme to the HTTP family
|
|
330
|
-
//
|
|
331
|
-
//
|
|
332
|
-
//
|
|
333
|
-
//
|
|
334
|
-
//
|
|
362
|
+
// Canonicalize the scheme to the HTTP family: accept all four schemes
|
|
363
|
+
// (http, https, ws, wss), normalize at this single entry point, and let
|
|
364
|
+
// each layer derive its own protocol (the socket layer maps http to ws and
|
|
365
|
+
// https to wss; fetch uses the URL as-is). Without this, a `ws://` base URL
|
|
366
|
+
// reaches HTTP consumers un-normalized and the client fails at startup
|
|
367
|
+
// instead of connecting.
|
|
335
368
|
if (url.protocol === 'ws:')
|
|
336
369
|
url.protocol = 'http:';
|
|
337
370
|
if (url.protocol === 'wss:')
|
|
@@ -352,11 +385,12 @@ export function resolveBaseURL(input) {
|
|
|
352
385
|
return normalizeAbloHostedBaseUrl(input.options.baseURL ?? ABLO_DEFAULT_BASE_URL);
|
|
353
386
|
}
|
|
354
387
|
/**
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
388
|
+
* Guards against using a secret `apiKey` in a browser. A secret key is
|
|
389
|
+
* server-side only by default: shipping an `sk_live_...` key to a browser would
|
|
390
|
+
* expose it in every visitor's network tab. Callers opt in explicitly when the
|
|
391
|
+
* browser instead holds a minted session token (`ek_`/`rk_`) or routes through a
|
|
392
|
+
* server proxy. Throws {@link AbloAuthenticationError} when a secret key is
|
|
393
|
+
* detected in a browser without opt-in.
|
|
360
394
|
*/
|
|
361
395
|
export function assertBrowserSafety(input) {
|
|
362
396
|
const inBrowser = typeof window !== 'undefined';
|
|
@@ -371,9 +405,9 @@ export function assertBrowserSafety(input) {
|
|
|
371
405
|
'`dangerouslyAllowBrowser` option to `true`, e.g.,\n\n' +
|
|
372
406
|
' Ablo({ schema, apiKey, dangerouslyAllowBrowser: true });\n', { code: 'browser_apikey_blocked' });
|
|
373
407
|
}
|
|
374
|
-
// `databaseUrl` carries
|
|
375
|
-
// `dangerouslyAllowBrowser` does not override
|
|
376
|
-
// a server-side runtime.
|
|
408
|
+
// `databaseUrl` carries database credentials and is never browser-safe, so
|
|
409
|
+
// `dangerouslyAllowBrowser` does not override this check. Register your
|
|
410
|
+
// database from a server-side runtime.
|
|
377
411
|
if (inBrowser && typeof input.databaseUrl === 'string' && input.databaseUrl.length > 0) {
|
|
378
412
|
throw new AbloAuthenticationError('Ablo `databaseUrl` cannot be used in a browser-like environment — it ' +
|
|
379
413
|
'carries your database credentials. Initialize the client with ' +
|
|
@@ -381,12 +415,10 @@ export function assertBrowserSafety(input) {
|
|
|
381
415
|
}
|
|
382
416
|
}
|
|
383
417
|
/**
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
* between requests. Returns `null` when no key
|
|
387
|
-
*
|
|
388
|
-
* Mirrors Anthropic's pattern of supporting both a static string and
|
|
389
|
-
* a callable for credential rotation.
|
|
418
|
+
* Resolves an {@link ApiKeySetter} callable to its current string value, or
|
|
419
|
+
* returns a plain string key as-is. Called at request time so a rotating
|
|
420
|
+
* credential picks up new values between requests. Returns `null` when no key
|
|
421
|
+
* was configured.
|
|
390
422
|
*/
|
|
391
423
|
export async function resolveApiKeyValue(apiKey) {
|
|
392
424
|
if (apiKey == null)
|
|
@@ -396,44 +428,39 @@ export async function resolveApiKeyValue(apiKey) {
|
|
|
396
428
|
return apiKey;
|
|
397
429
|
}
|
|
398
430
|
/**
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
* so it lives here as a single source of truth.
|
|
431
|
+
* Translates a WebSocket URL into the matching HTTP API base URL, defaulting to
|
|
432
|
+
* `${url}/api` when the caller has not overridden `bootstrapBaseUrl`. The
|
|
433
|
+
* bootstrap helper, the hydration coordinator, the credential-exchange flow, and
|
|
434
|
+
* the identity flow all derive their base URL through this one function, so the
|
|
435
|
+
* derivation stays consistent across them.
|
|
405
436
|
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
437
|
+
* When both `wss://` and `https://` are valid, the ws-to-http rewrite preserves
|
|
438
|
+
* the protocol family: ws becomes http and wss becomes https.
|
|
408
439
|
*/
|
|
409
440
|
export function resolveBootstrapBaseUrl(input) {
|
|
410
441
|
if (input.bootstrapBaseUrl) {
|
|
411
|
-
// Coerce ws/wss
|
|
412
|
-
// used for HTTP fetches (identity
|
|
413
|
-
// the browser `fetch` rejects ws
|
|
414
|
-
//
|
|
415
|
-
//
|
|
416
|
-
//
|
|
417
|
-
// faceplanting at fetch time. The derive branch below already does this;
|
|
418
|
-
// the override branch silently skipped it.
|
|
442
|
+
// Coerce ws/wss to http/https on the override path as well. This base URL is
|
|
443
|
+
// used for HTTP fetches (identity resolution, credential exchange, and
|
|
444
|
+
// bootstrap), and the browser `fetch` rejects ws and wss schemes outright.
|
|
445
|
+
// The override can legitimately arrive with a WebSocket scheme when a caller
|
|
446
|
+
// derives it as `${baseUrl}/api` from a WebSocket base URL, so normalize it
|
|
447
|
+
// here rather than failing at fetch time.
|
|
419
448
|
return ensureApiSuffix(normalizeAbloHostedBaseUrl(input.bootstrapBaseUrl).replace(/^ws/, 'http'));
|
|
420
449
|
}
|
|
421
450
|
const url = normalizeAbloHostedBaseUrl(input.url);
|
|
422
451
|
return ensureApiSuffix(url.replace(/^ws/, 'http'));
|
|
423
452
|
}
|
|
424
453
|
/**
|
|
425
|
-
*
|
|
426
|
-
*
|
|
454
|
+
* Ensures the HTTP base ends in the `/api` route segment that every endpoint is
|
|
455
|
+
* mounted under.
|
|
427
456
|
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
* to a single trailing `/api` here is always correct — and idempotent for
|
|
436
|
-
* callers who already include it.
|
|
457
|
+
* A hosted deployment that sets a custom `baseURL` or `bootstrapBaseUrl` (a
|
|
458
|
+
* custom subdomain, a staging host, and so on) without the `/api` suffix would
|
|
459
|
+
* send every credential exchange to `…/auth/capability` instead of
|
|
460
|
+
* `…/api/auth/capability`, producing a 404 that surfaces as `exchange_failed`.
|
|
461
|
+
* Since the client builds routes relative to this base and no valid deployment
|
|
462
|
+
* serves them from the root, appending a single trailing `/api` here is always
|
|
463
|
+
* correct, and it is idempotent for callers who already include it.
|
|
437
464
|
*/
|
|
438
465
|
function ensureApiSuffix(httpBase) {
|
|
439
466
|
const trimmed = httpBase.replace(/\/+$/, '');
|
|
@@ -446,8 +473,8 @@ function ensureApiSuffix(httpBase) {
|
|
|
446
473
|
return u.toString().replace(/\/+$/, '');
|
|
447
474
|
}
|
|
448
475
|
catch {
|
|
449
|
-
// Should be unreachable
|
|
450
|
-
// absolute URL
|
|
451
|
-
return
|
|
476
|
+
// Should be unreachable after `normalizeAbloHostedBaseUrl`, which yields an
|
|
477
|
+
// absolute URL, but fall back to a string check rather than throwing.
|
|
478
|
+
return trimmed.endsWith("/api") ? trimmed : `${trimmed}/api`;
|
|
452
479
|
}
|
|
453
480
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The auto-heartbeat loop behind `claim({ id, heartbeat: true })` — one
|
|
3
|
+
* implementation shared by both transports (the WebSocket claim stream and the
|
|
4
|
+
* HTTP `ApiClient`), so the cadence and failure semantics cannot drift.
|
|
5
|
+
*
|
|
6
|
+
* A beat is the "still working" signal that keeps a lease alive for the
|
|
7
|
+
* duration of real work. The loop's failure handling follows the lease-system
|
|
8
|
+
* convention (SQS visibility heartbeats, Kubernetes leases): a beat that fails
|
|
9
|
+
* for a transient reason — the network blipped, the server was briefly
|
|
10
|
+
* unavailable — is simply retried on the next tick, because the lease has
|
|
11
|
+
* runway to spare by construction (the default cadence is a third of the TTL,
|
|
12
|
+
* so two consecutive beats can fail before the lease is even at risk). Only a
|
|
13
|
+
* definitive answer from the server — the lease lapsed and may have been
|
|
14
|
+
* granted to the next in line ({@link AbloClaimedError}) — stops the loop and
|
|
15
|
+
* surfaces the loss, because for a caller with no push channel the failed beat
|
|
16
|
+
* IS the loss notification.
|
|
17
|
+
*/
|
|
18
|
+
import { AbloClaimedError } from '../errors.js';
|
|
19
|
+
import type { ClaimHeartbeat, ClaimHeartbeatOptions, Duration } from '../types/streams.js';
|
|
20
|
+
/**
|
|
21
|
+
* Normalize the public `heartbeat(options?)` argument — a bare Duration is
|
|
22
|
+
* shorthand for `{ ttl }`. Shared by both transports' handle assembly so the
|
|
23
|
+
* shorthand cannot drift.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveHeartbeatOptions(input: Duration | ClaimHeartbeatOptions | undefined): ClaimHeartbeatOptions;
|
|
26
|
+
/**
|
|
27
|
+
* The beat cadence for a lease of `ttlMs`: an explicit duration when the
|
|
28
|
+
* caller set one, otherwise a third of the TTL (floored at 1s) — the
|
|
29
|
+
* DynamoDB-lock-client rule, leaving two missed beats of runway before the
|
|
30
|
+
* lease is at risk while keeping crash recovery within one beat window.
|
|
31
|
+
*/
|
|
32
|
+
export declare function heartbeatCadenceMs(ttlMs: number, heartbeat: true | Duration): number;
|
|
33
|
+
export interface ClaimHeartbeatLoopOptions {
|
|
34
|
+
/** Send one beat; resolves while the lease is still ours. */
|
|
35
|
+
beat(): Promise<ClaimHeartbeat>;
|
|
36
|
+
/** Cadence between beats. Callers default this to a third of the TTL. */
|
|
37
|
+
intervalMs: number;
|
|
38
|
+
/**
|
|
39
|
+
* Called once when a beat comes back with a definitive loss — the lease
|
|
40
|
+
* expired or was taken. The loop has already stopped by the time this runs.
|
|
41
|
+
*/
|
|
42
|
+
onLost?(error: AbloClaimedError): void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Start beating. Returns a stop function; callers stop the loop when the
|
|
46
|
+
* claim is released (all held-claim assembly sites tie this to `release`).
|
|
47
|
+
* Beats never overlap: a tick that fires while the previous beat is still
|
|
48
|
+
* in flight is skipped rather than stacked.
|
|
49
|
+
*/
|
|
50
|
+
export declare function startClaimHeartbeatLoop(options: ClaimHeartbeatLoopOptions): () => void;
|