@abloatai/ablo 0.3.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/CHANGELOG.md +208 -0
- package/LICENSE +201 -0
- package/NOTICE +12 -0
- package/README.md +230 -0
- package/dist/BaseSyncedStore.d.ts +709 -0
- package/dist/BaseSyncedStore.js +1843 -0
- package/dist/Database.d.ts +344 -0
- package/dist/Database.js +1259 -0
- package/dist/LazyReferenceCollection.d.ts +181 -0
- package/dist/LazyReferenceCollection.js +460 -0
- package/dist/Model.d.ts +339 -0
- package/dist/Model.js +715 -0
- package/dist/ModelRegistry.d.ts +200 -0
- package/dist/ModelRegistry.js +535 -0
- package/dist/NetworkMonitor.d.ts +27 -0
- package/dist/NetworkMonitor.js +73 -0
- package/dist/ObjectPool.d.ts +202 -0
- package/dist/ObjectPool.js +1106 -0
- package/dist/SyncClient.d.ts +489 -0
- package/dist/SyncClient.js +1555 -0
- package/dist/SyncEngineContext.d.ts +46 -0
- package/dist/SyncEngineContext.js +74 -0
- package/dist/adapters/alwaysOnline.d.ts +16 -0
- package/dist/adapters/alwaysOnline.js +19 -0
- package/dist/adapters/inMemoryStorage.d.ts +30 -0
- package/dist/adapters/inMemoryStorage.js +94 -0
- package/dist/agent/Agent.d.ts +358 -0
- package/dist/agent/Agent.js +500 -0
- package/dist/agent/index.d.ts +115 -0
- package/dist/agent/index.js +128 -0
- package/dist/agent/session.d.ts +90 -0
- package/dist/agent/session.js +156 -0
- package/dist/agent/types.d.ts +73 -0
- package/dist/agent/types.js +10 -0
- package/dist/ai-sdk/coordination-context.d.ts +51 -0
- package/dist/ai-sdk/coordination-context.js +107 -0
- package/dist/ai-sdk/index.d.ts +68 -0
- package/dist/ai-sdk/index.js +68 -0
- package/dist/ai-sdk/intent-broadcast.d.ts +77 -0
- package/dist/ai-sdk/intent-broadcast.js +72 -0
- package/dist/ai-sdk/wrap.d.ts +67 -0
- package/dist/ai-sdk/wrap.js +45 -0
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.js +9 -0
- package/dist/auth/index.d.ts +137 -0
- package/dist/auth/index.js +246 -0
- package/dist/client/Ablo.d.ts +835 -0
- package/dist/client/Ablo.js +1440 -0
- package/dist/client/ApiClient.d.ts +200 -0
- package/dist/client/ApiClient.js +659 -0
- package/dist/client/auth.d.ts +79 -0
- package/dist/client/auth.js +81 -0
- package/dist/client/createInternalComponents.d.ts +44 -0
- package/dist/client/createInternalComponents.js +88 -0
- package/dist/client/createModelProxy.d.ts +152 -0
- package/dist/client/createModelProxy.js +199 -0
- package/dist/client/identity.d.ts +63 -0
- package/dist/client/identity.js +156 -0
- package/dist/client/index.d.ts +36 -0
- package/dist/client/index.js +33 -0
- package/dist/client/persistence.d.ts +7 -0
- package/dist/client/persistence.js +11 -0
- package/dist/client/validateAbloOptions.d.ts +42 -0
- package/dist/client/validateAbloOptions.js +43 -0
- package/dist/config/index.d.ts +10 -0
- package/dist/config/index.js +12 -0
- package/dist/context.d.ts +27 -0
- package/dist/context.js +58 -0
- package/dist/core/DatabaseManager.d.ts +108 -0
- package/dist/core/DatabaseManager.js +361 -0
- package/dist/core/QueryProcessor.d.ts +77 -0
- package/dist/core/QueryProcessor.js +262 -0
- package/dist/core/QueryView.d.ts +64 -0
- package/dist/core/QueryView.js +219 -0
- package/dist/core/StoreManager.d.ts +131 -0
- package/dist/core/StoreManager.js +334 -0
- package/dist/core/ViewRegistry.d.ts +20 -0
- package/dist/core/ViewRegistry.js +55 -0
- package/dist/core/index.d.ts +34 -0
- package/dist/core/index.js +59 -0
- package/dist/core/openIDBWithTimeout.d.ts +27 -0
- package/dist/core/openIDBWithTimeout.js +63 -0
- package/dist/core/query-utils.d.ts +37 -0
- package/dist/core/query-utils.js +60 -0
- package/dist/errors.d.ts +235 -0
- package/dist/errors.js +243 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +82 -0
- package/dist/interfaces/headless.d.ts +95 -0
- package/dist/interfaces/headless.js +41 -0
- package/dist/interfaces/index.d.ts +321 -0
- package/dist/interfaces/index.js +8 -0
- package/dist/mutators/RecordingTransaction.d.ts +36 -0
- package/dist/mutators/RecordingTransaction.js +216 -0
- package/dist/mutators/Transaction.d.ts +48 -0
- package/dist/mutators/Transaction.js +64 -0
- package/dist/mutators/UndoManager.d.ts +114 -0
- package/dist/mutators/UndoManager.js +143 -0
- package/dist/mutators/defineMutators.d.ts +55 -0
- package/dist/mutators/defineMutators.js +28 -0
- package/dist/policy/index.d.ts +19 -0
- package/dist/policy/index.js +18 -0
- package/dist/policy/types.d.ts +74 -0
- package/dist/policy/types.js +17 -0
- package/dist/principal.d.ts +44 -0
- package/dist/principal.js +49 -0
- package/dist/query/client.d.ts +43 -0
- package/dist/query/client.js +84 -0
- package/dist/query/index.d.ts +6 -0
- package/dist/query/index.js +5 -0
- package/dist/query/types.d.ts +143 -0
- package/dist/query/types.js +36 -0
- package/dist/react/AbloProvider.d.ts +205 -0
- package/dist/react/AbloProvider.js +398 -0
- package/dist/react/ClientSideSuspense.d.ts +36 -0
- package/dist/react/ClientSideSuspense.js +17 -0
- package/dist/react/DefaultFallback.d.ts +24 -0
- package/dist/react/DefaultFallback.js +43 -0
- package/dist/react/SyncGroupProvider.d.ts +19 -0
- package/dist/react/SyncGroupProvider.js +44 -0
- package/dist/react/context.d.ts +161 -0
- package/dist/react/context.js +35 -0
- package/dist/react/index.d.ts +64 -0
- package/dist/react/index.js +73 -0
- package/dist/react/internalContext.d.ts +35 -0
- package/dist/react/internalContext.js +3 -0
- package/dist/react/useAblo.d.ts +72 -0
- package/dist/react/useAblo.js +63 -0
- package/dist/react/useCurrentUserId.d.ts +21 -0
- package/dist/react/useCurrentUserId.js +33 -0
- package/dist/react/useErrorListener.d.ts +20 -0
- package/dist/react/useErrorListener.js +39 -0
- package/dist/react/useIntent.d.ts +29 -0
- package/dist/react/useIntent.js +42 -0
- package/dist/react/useMutate.d.ts +83 -0
- package/dist/react/useMutate.js +122 -0
- package/dist/react/useMutationFailureListener.d.ts +26 -0
- package/dist/react/useMutationFailureListener.js +38 -0
- package/dist/react/useMutators.d.ts +56 -0
- package/dist/react/useMutators.js +66 -0
- package/dist/react/usePresence.d.ts +32 -0
- package/dist/react/usePresence.js +41 -0
- package/dist/react/useQuery.d.ts +123 -0
- package/dist/react/useQuery.js +145 -0
- package/dist/react/useReactive.d.ts +35 -0
- package/dist/react/useReactive.js +111 -0
- package/dist/react/useReader.d.ts +69 -0
- package/dist/react/useReader.js +73 -0
- package/dist/react/useSyncStatus.d.ts +61 -0
- package/dist/react/useSyncStatus.js +76 -0
- package/dist/react/useUndoScope.d.ts +36 -0
- package/dist/react/useUndoScope.js +73 -0
- package/dist/realtime/index.d.ts +10 -0
- package/dist/realtime/index.js +9 -0
- package/dist/schema/field.d.ts +134 -0
- package/dist/schema/field.js +264 -0
- package/dist/schema/index.d.ts +29 -0
- package/dist/schema/index.js +38 -0
- package/dist/schema/model.d.ts +326 -0
- package/dist/schema/model.js +89 -0
- package/dist/schema/queries.d.ts +203 -0
- package/dist/schema/queries.js +145 -0
- package/dist/schema/relation.d.ts +172 -0
- package/dist/schema/relation.js +104 -0
- package/dist/schema/schema.d.ts +259 -0
- package/dist/schema/schema.js +188 -0
- package/dist/schema/sugar.d.ts +129 -0
- package/dist/schema/sugar.js +94 -0
- package/dist/source/index.d.ts +423 -0
- package/dist/source/index.js +320 -0
- package/dist/source/pushQueue.d.ts +112 -0
- package/dist/source/pushQueue.js +249 -0
- package/dist/stores/ObjectStore.d.ts +103 -0
- package/dist/stores/ObjectStore.js +371 -0
- package/dist/stores/ObjectStoreContract.d.ts +39 -0
- package/dist/stores/ObjectStoreContract.js +1 -0
- package/dist/stores/SyncActionStore.d.ts +101 -0
- package/dist/stores/SyncActionStore.js +481 -0
- package/dist/sync/BootstrapHelper.d.ts +127 -0
- package/dist/sync/BootstrapHelper.js +434 -0
- package/dist/sync/ConnectionManager.d.ts +136 -0
- package/dist/sync/ConnectionManager.js +465 -0
- package/dist/sync/HydrationCoordinator.d.ts +137 -0
- package/dist/sync/HydrationCoordinator.js +468 -0
- package/dist/sync/NetworkProbe.d.ts +43 -0
- package/dist/sync/NetworkProbe.js +113 -0
- package/dist/sync/OfflineFlush.d.ts +9 -0
- package/dist/sync/OfflineFlush.js +22 -0
- package/dist/sync/OfflineTransactionStore.d.ts +37 -0
- package/dist/sync/OfflineTransactionStore.js +263 -0
- package/dist/sync/SyncWebSocket.d.ts +663 -0
- package/dist/sync/SyncWebSocket.js +1336 -0
- package/dist/sync/createIntentStream.d.ts +33 -0
- package/dist/sync/createIntentStream.js +243 -0
- package/dist/sync/createPresenceStream.d.ts +46 -0
- package/dist/sync/createPresenceStream.js +192 -0
- package/dist/sync/createSnapshot.d.ts +33 -0
- package/dist/sync/createSnapshot.js +124 -0
- package/dist/sync/participants.d.ts +114 -0
- package/dist/sync/participants.js +336 -0
- package/dist/sync/schemas.d.ts +79 -0
- package/dist/sync/schemas.js +78 -0
- package/dist/testing/fixtures/bootstrap.d.ts +45 -0
- package/dist/testing/fixtures/bootstrap.js +53 -0
- package/dist/testing/fixtures/deltas.d.ts +86 -0
- package/dist/testing/fixtures/deltas.js +139 -0
- package/dist/testing/fixtures/models.d.ts +82 -0
- package/dist/testing/fixtures/models.js +270 -0
- package/dist/testing/helpers/react-wrapper.d.ts +66 -0
- package/dist/testing/helpers/react-wrapper.js +64 -0
- package/dist/testing/helpers/sync-engine-harness.d.ts +55 -0
- package/dist/testing/helpers/sync-engine-harness.js +70 -0
- package/dist/testing/helpers/wait.d.ts +25 -0
- package/dist/testing/helpers/wait.js +44 -0
- package/dist/testing/index.d.ts +21 -0
- package/dist/testing/index.js +32 -0
- package/dist/testing/mocks/MockMutationExecutor.d.ts +65 -0
- package/dist/testing/mocks/MockMutationExecutor.js +139 -0
- package/dist/testing/mocks/MockNetworkMonitor.d.ts +20 -0
- package/dist/testing/mocks/MockNetworkMonitor.js +46 -0
- package/dist/testing/mocks/MockSyncContext.d.ts +64 -0
- package/dist/testing/mocks/MockSyncContext.js +100 -0
- package/dist/testing/mocks/MockSyncStore.d.ts +88 -0
- package/dist/testing/mocks/MockSyncStore.js +171 -0
- package/dist/testing/mocks/MockWebSocket.d.ts +66 -0
- package/dist/testing/mocks/MockWebSocket.js +117 -0
- package/dist/transactions/OptimisticEchoTracker.d.ts +82 -0
- package/dist/transactions/OptimisticEchoTracker.js +104 -0
- package/dist/transactions/TransactionQueue.d.ts +499 -0
- package/dist/transactions/TransactionQueue.js +1895 -0
- package/dist/transactions/index.d.ts +16 -0
- package/dist/transactions/index.js +7 -0
- package/dist/transactions/mutation-error-handler.d.ts +5 -0
- package/dist/transactions/mutation-error-handler.js +39 -0
- package/dist/types/global.d.ts +107 -0
- package/dist/types/global.js +38 -0
- package/dist/types/index.d.ts +241 -0
- package/dist/types/index.js +70 -0
- package/dist/types/streams.d.ts +495 -0
- package/dist/types/streams.js +11 -0
- package/dist/utils/asyncIterator.d.ts +41 -0
- package/dist/utils/asyncIterator.js +142 -0
- package/dist/utils/duration.d.ts +28 -0
- package/dist/utils/duration.js +47 -0
- package/dist/utils/mobx-setup.d.ts +42 -0
- package/dist/utils/mobx-setup.js +381 -0
- package/docs/api-keys.md +24 -0
- package/docs/api.md +230 -0
- package/docs/audit.md +81 -0
- package/docs/capabilities.md +163 -0
- package/docs/client-behavior.md +202 -0
- package/docs/data-sources.md +214 -0
- package/docs/examples/agent-human.md +84 -0
- package/docs/examples/ai-sdk-tool.md +92 -0
- package/docs/examples/existing-python-backend.md +249 -0
- package/docs/examples/nextjs.md +88 -0
- package/docs/examples/server-agent.md +86 -0
- package/docs/guarantees.md +148 -0
- package/docs/index.md +97 -0
- package/docs/integration-guide.md +493 -0
- package/docs/interaction-model.md +140 -0
- package/docs/mcp/claude-code.md +43 -0
- package/docs/mcp/cursor.md +53 -0
- package/docs/mcp/windsurf.md +46 -0
- package/docs/mcp.md +59 -0
- package/docs/quickstart.md +152 -0
- package/docs/react.md +115 -0
- package/docs/roadmap.md +45 -0
- package/examples/README.md +54 -0
- package/examples/data-source/README.md +102 -0
- package/examples/data-source/ablo-driver.ts +89 -0
- package/examples/data-source/customer-server.ts +208 -0
- package/examples/data-source/run.ts +101 -0
- package/examples/data-source/schema.ts +25 -0
- package/examples/quickstart.ts +54 -0
- package/examples/tsconfig.json +16 -0
- package/llms.txt +143 -0
- package/package.json +147 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Participant identity + scope resolution for `Ablo()`.
|
|
3
|
+
*
|
|
4
|
+
* Three branches, mirroring the three auth paths the SDK supports:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Hosted-cloud** — caller passed `apiKey`. SDK exchanges it
|
|
7
|
+
* server-side for a capability token + scope blob, then sets
|
|
8
|
+
* up a refresh scheduler that re-mints transparently before
|
|
9
|
+
* expiry.
|
|
10
|
+
* 2. **Self-derived** — caller passed an authToken / capability
|
|
11
|
+
* token but the SDK doesn't yet know the identity. Calls
|
|
12
|
+
* `resolveIdentity` against the bootstrap endpoint to recover
|
|
13
|
+
* `participantId` + scope from the token.
|
|
14
|
+
* 3. **Legacy explicit** — self-hosted callers that pass
|
|
15
|
+
* `organizationId` + `user.id` (or `agentId`) directly. No
|
|
16
|
+
* server round-trip; SDK trusts the caller.
|
|
17
|
+
*
|
|
18
|
+
* Extracted from `Ablo.ts` so each branch is testable in isolation
|
|
19
|
+
* and the constructor body reads as a single named call rather than
|
|
20
|
+
* a 100+-line if/elif/else with three different side-effect chains.
|
|
21
|
+
*/
|
|
22
|
+
import { type RefreshScheduler } from '../auth/index.js';
|
|
23
|
+
import type { BootstrapHelper } from '../sync/BootstrapHelper.js';
|
|
24
|
+
import type { SyncLogger } from '../interfaces/index.js';
|
|
25
|
+
import type { ApiKeySetter } from './auth.js';
|
|
26
|
+
export interface IdentityResolveInput {
|
|
27
|
+
readonly options: {
|
|
28
|
+
readonly capabilityToken?: string;
|
|
29
|
+
readonly bootstrapBaseUrl?: string;
|
|
30
|
+
readonly user?: {
|
|
31
|
+
id: string;
|
|
32
|
+
teamIds?: string[];
|
|
33
|
+
};
|
|
34
|
+
readonly agentId?: string;
|
|
35
|
+
readonly syncGroups?: string[];
|
|
36
|
+
};
|
|
37
|
+
readonly internalOptions: {
|
|
38
|
+
readonly organizationId?: string;
|
|
39
|
+
};
|
|
40
|
+
readonly url: string;
|
|
41
|
+
readonly kind: 'user' | 'agent' | 'system';
|
|
42
|
+
readonly configuredApiKey: string | ApiKeySetter | null;
|
|
43
|
+
readonly configuredAuthToken: string | null;
|
|
44
|
+
readonly bootstrapHelper: BootstrapHelper;
|
|
45
|
+
readonly logger: SyncLogger;
|
|
46
|
+
/**
|
|
47
|
+
* Called when the hosted-cloud refresh scheduler rotates the
|
|
48
|
+
* capability token — caller forwards the new token to the live
|
|
49
|
+
* WebSocket via `ws.setCapabilityToken(...)`.
|
|
50
|
+
*/
|
|
51
|
+
readonly applyRotatedToken: (token: string) => void;
|
|
52
|
+
}
|
|
53
|
+
export interface ResolvedIdentity {
|
|
54
|
+
readonly userId: string;
|
|
55
|
+
readonly accountScope: string;
|
|
56
|
+
readonly teamIds: string[] | undefined;
|
|
57
|
+
readonly capabilityToken: string | undefined;
|
|
58
|
+
readonly syncGroups: readonly string[] | undefined;
|
|
59
|
+
readonly participantKind: 'user' | 'agent' | 'system';
|
|
60
|
+
/** Non-null on the hosted-cloud path; caller stores it for shutdown. */
|
|
61
|
+
readonly refreshScheduler: RefreshScheduler | null;
|
|
62
|
+
}
|
|
63
|
+
export declare function resolveParticipantIdentity(input: IdentityResolveInput): Promise<ResolvedIdentity>;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Participant identity + scope resolution for `Ablo()`.
|
|
3
|
+
*
|
|
4
|
+
* Three branches, mirroring the three auth paths the SDK supports:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Hosted-cloud** — caller passed `apiKey`. SDK exchanges it
|
|
7
|
+
* server-side for a capability token + scope blob, then sets
|
|
8
|
+
* up a refresh scheduler that re-mints transparently before
|
|
9
|
+
* expiry.
|
|
10
|
+
* 2. **Self-derived** — caller passed an authToken / capability
|
|
11
|
+
* token but the SDK doesn't yet know the identity. Calls
|
|
12
|
+
* `resolveIdentity` against the bootstrap endpoint to recover
|
|
13
|
+
* `participantId` + scope from the token.
|
|
14
|
+
* 3. **Legacy explicit** — self-hosted callers that pass
|
|
15
|
+
* `organizationId` + `user.id` (or `agentId`) directly. No
|
|
16
|
+
* server round-trip; SDK trusts the caller.
|
|
17
|
+
*
|
|
18
|
+
* Extracted from `Ablo.ts` so each branch is testable in isolation
|
|
19
|
+
* and the constructor body reads as a single named call rather than
|
|
20
|
+
* a 100+-line if/elif/else with three different side-effect chains.
|
|
21
|
+
*/
|
|
22
|
+
import { AbloAuthenticationError } from '../errors.js';
|
|
23
|
+
import { exchangeApiKey } from '../auth/index.js';
|
|
24
|
+
import { resolveIdentity } from '../auth/index.js';
|
|
25
|
+
import { createRefreshScheduler, } from '../auth/index.js';
|
|
26
|
+
import { resolveApiKeyValue } from './auth.js';
|
|
27
|
+
export async function resolveParticipantIdentity(input) {
|
|
28
|
+
const { options, internalOptions, url, kind, configuredApiKey, configuredAuthToken, bootstrapHelper, logger, applyRotatedToken, } = input;
|
|
29
|
+
const apiKeyValue = await resolveApiKeyValue(configuredApiKey);
|
|
30
|
+
const initialCapToken = options.capabilityToken ?? configuredAuthToken ?? undefined;
|
|
31
|
+
// Branch 1: hosted-cloud (apiKey only, no caller-supplied capability token)
|
|
32
|
+
if (apiKeyValue && !options.capabilityToken) {
|
|
33
|
+
return resolveHosted({
|
|
34
|
+
apiKeyValue,
|
|
35
|
+
configuredApiKey,
|
|
36
|
+
url,
|
|
37
|
+
kind,
|
|
38
|
+
options,
|
|
39
|
+
bootstrapHelper,
|
|
40
|
+
logger,
|
|
41
|
+
applyRotatedToken,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
// Branch 2: self-derived (capability token present, identity unknown)
|
|
45
|
+
if (!internalOptions.organizationId ||
|
|
46
|
+
(kind === 'agent' ? !options.agentId : !options.user?.id)) {
|
|
47
|
+
const baseUrl = options.bootstrapBaseUrl ?? `${url.replace(/^ws/, 'http')}/api`;
|
|
48
|
+
const identity = await resolveIdentity({
|
|
49
|
+
baseUrl,
|
|
50
|
+
authToken: initialCapToken,
|
|
51
|
+
});
|
|
52
|
+
// Merge caller-passed syncGroups with server-resolved ones rather
|
|
53
|
+
// than letting the server's response silently overwrite. Browser
|
|
54
|
+
// consumers (apps/web's SyncEngineProvider) compose
|
|
55
|
+
// `['default', 'org:${orgId}', 'user:${userId}', ...team:]` from
|
|
56
|
+
// the resolved session and pass it via `<AbloProvider syncGroups>`;
|
|
57
|
+
// before this merge, Branch 2 dropped that set on the floor in
|
|
58
|
+
// favor of `/auth/identity`'s response, which is empty for
|
|
59
|
+
// cookie-auth users today (apps/sync-server/src/routes/auth.ts only
|
|
60
|
+
// populates from `effectiveSyncGroups`, the cap-narrowed list).
|
|
61
|
+
// Empty syncGroups → server bootstrap falls back to `['default']`
|
|
62
|
+
// → no deltas fan out → live updates appear only on hard reload.
|
|
63
|
+
const callerGroups = options.syncGroups ?? [];
|
|
64
|
+
const mergedSyncGroups = callerGroups.length > 0
|
|
65
|
+
? [...new Set([...callerGroups, ...identity.syncGroups])]
|
|
66
|
+
: identity.syncGroups;
|
|
67
|
+
bootstrapHelper.setCacheScope(identity.accountScope);
|
|
68
|
+
bootstrapHelper.setSyncGroups(mergedSyncGroups);
|
|
69
|
+
bootstrapHelper.setAuthToken(initialCapToken);
|
|
70
|
+
return {
|
|
71
|
+
userId: identity.participantId,
|
|
72
|
+
accountScope: identity.accountScope,
|
|
73
|
+
teamIds: undefined,
|
|
74
|
+
capabilityToken: initialCapToken,
|
|
75
|
+
syncGroups: mergedSyncGroups,
|
|
76
|
+
participantKind: identity.participantKind,
|
|
77
|
+
refreshScheduler: null,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// Branch 3: legacy explicit (self-hosted, pre-Phase-3 — caller knows
|
|
81
|
+
// its own organizationId + user/agentId).
|
|
82
|
+
const userId = kind === 'agent' ? options.agentId : options.user.id;
|
|
83
|
+
const accountScope = internalOptions.organizationId;
|
|
84
|
+
bootstrapHelper.setCacheScope(accountScope);
|
|
85
|
+
bootstrapHelper.setSyncGroups(options.syncGroups);
|
|
86
|
+
bootstrapHelper.setAuthToken(initialCapToken);
|
|
87
|
+
return {
|
|
88
|
+
userId,
|
|
89
|
+
accountScope,
|
|
90
|
+
teamIds: kind === 'user' ? options.user?.teamIds : undefined,
|
|
91
|
+
capabilityToken: initialCapToken,
|
|
92
|
+
syncGroups: options.syncGroups,
|
|
93
|
+
participantKind: kind,
|
|
94
|
+
refreshScheduler: null,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async function resolveHosted(input) {
|
|
98
|
+
// Pure managed-cloud shape: `Ablo({schema, apiKey})`. Server returns
|
|
99
|
+
// scope + userMeta; SDK populates internals.
|
|
100
|
+
const baseUrl = input.options.bootstrapBaseUrl ??
|
|
101
|
+
`${input.url.replace(/^ws/, 'http')}/api`;
|
|
102
|
+
const exchangeArgs = {
|
|
103
|
+
baseUrl,
|
|
104
|
+
participantKind: (input.kind === 'agent' ? 'agent' : 'system'),
|
|
105
|
+
participantId: input.options.agentId ?? input.options.user?.id,
|
|
106
|
+
wideScope: true,
|
|
107
|
+
ttlSeconds: 3600,
|
|
108
|
+
};
|
|
109
|
+
const exchange = await exchangeApiKey({
|
|
110
|
+
...exchangeArgs,
|
|
111
|
+
apiKey: input.apiKeyValue,
|
|
112
|
+
});
|
|
113
|
+
input.bootstrapHelper.setCacheScope(exchange.scope.organizationId);
|
|
114
|
+
input.bootstrapHelper.setSyncGroups(exchange.scope.syncGroups);
|
|
115
|
+
input.bootstrapHelper.setAuthToken(exchange.token);
|
|
116
|
+
// Cap tokens have a server-set TTL (3600s by default). Without
|
|
117
|
+
// proactive refresh the WS would either get force-closed at expiry
|
|
118
|
+
// or fail its next reconnect with 401. The scheduler re-mints
|
|
119
|
+
// transparently before that fires; the consumer never sees the
|
|
120
|
+
// rotation. Rationale + tradeoffs in
|
|
121
|
+
// `packages/sync-engine/src/auth/refreshScheduler.ts`
|
|
122
|
+
const refreshScheduler = createRefreshScheduler({
|
|
123
|
+
initialExpiresAtMs: Date.parse(exchange.expiresAt),
|
|
124
|
+
refresh: async () => {
|
|
125
|
+
// Read the apiKey fresh each time — supports the ApiKeySetter
|
|
126
|
+
// (rotating credentials) shape.
|
|
127
|
+
const freshApiKey = await resolveApiKeyValue(input.configuredApiKey);
|
|
128
|
+
if (!freshApiKey) {
|
|
129
|
+
throw new AbloAuthenticationError('apiKey unavailable during refresh', { code: 'apikey_missing' });
|
|
130
|
+
}
|
|
131
|
+
const next = await exchangeApiKey({
|
|
132
|
+
...exchangeArgs,
|
|
133
|
+
apiKey: freshApiKey,
|
|
134
|
+
});
|
|
135
|
+
input.bootstrapHelper.setAuthToken(next.token);
|
|
136
|
+
input.applyRotatedToken(next.token);
|
|
137
|
+
return { expiresAtMs: Date.parse(next.expiresAt) };
|
|
138
|
+
},
|
|
139
|
+
onError: (err) => {
|
|
140
|
+
input.logger.warn('cap token refresh failed; will retry', {
|
|
141
|
+
error: err.message,
|
|
142
|
+
});
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
return {
|
|
146
|
+
userId: exchange.scope.participantId,
|
|
147
|
+
accountScope: exchange.scope.organizationId,
|
|
148
|
+
// teamIds isn't needed because the server already encoded
|
|
149
|
+
// team-level access into scope.syncGroups.
|
|
150
|
+
teamIds: undefined,
|
|
151
|
+
capabilityToken: exchange.token,
|
|
152
|
+
syncGroups: exchange.scope.syncGroups,
|
|
153
|
+
participantKind: input.kind,
|
|
154
|
+
refreshScheduler,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ablo/sync-engine/client — Consumer API
|
|
3
|
+
*
|
|
4
|
+
* The one-liner entry point for external consumers.
|
|
5
|
+
*
|
|
6
|
+
* `Ablo({ apiKey })` is the stateless HTTP API client. Add `schema`
|
|
7
|
+
* when you want the realtime sync engine with typed model proxies.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { Ablo } from '@ablo/sync-engine/client';
|
|
11
|
+
* import { schema } from './schema';
|
|
12
|
+
*
|
|
13
|
+
* const ablo = Ablo({
|
|
14
|
+
* schema,
|
|
15
|
+
* apiKey: process.env.ABLO_API_KEY,
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* const tasks = ablo.tasks.list({ where: { status: 'todo' } });
|
|
19
|
+
* await ablo.tasks.create({ title: 'New task' });
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* For headless agents (workers, bots), pass `kind: 'agent'` plus a
|
|
23
|
+
* Biscuit `capabilityToken`:
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* const bot = Ablo({
|
|
27
|
+
* schema,
|
|
28
|
+
* apiKey: process.env.ABLO_API_KEY,
|
|
29
|
+
* kind: 'agent',
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export { Ablo, computeFKDepthPriority, type AbloOptions, type InternalAbloOptions, type BusyOptions, type BusyPolicy, type IntentWaitOptions, type ModelCountOptions, type ModelListOptions, type ModelListScope, type ModelLoadOptions, type ModelOperations, type ResourceReadOptions, } from './Ablo.js';
|
|
34
|
+
export type { AbloPersistence } from './persistence.js';
|
|
35
|
+
export type { AbloApi, AbloApiClientOptions, AbloApiIntents, Agent, AgentIntentInput, AgentIntentOptions, AgentOptions, AgentResourceClient, AgentResourceReadOptions, AgentResourceMutationOptions, AgentRunContext, AgentRunDone, AgentRunFailed, AgentRunCancelled, AgentRunOptions, AgentRunResult, AgentRunStatus, Capability, CapabilityCreateOptions, CapabilityParticipantKind, CapabilityRecord, CapabilityResource, CapabilityRevocation, CapabilityScope, Task, TaskCloseOptions, TaskCloseResult, TaskCreateOptions, TaskResource, } from './ApiClient.js';
|
|
36
|
+
export type { EngineParticipant, JoinedParticipant, ParticipantJoinOptions, ParticipantManager, ParticipantScope, ParticipantStatus, ScopedIntents, ScopedPresence, } from '../sync/participants.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ablo/sync-engine/client — Consumer API
|
|
3
|
+
*
|
|
4
|
+
* The one-liner entry point for external consumers.
|
|
5
|
+
*
|
|
6
|
+
* `Ablo({ apiKey })` is the stateless HTTP API client. Add `schema`
|
|
7
|
+
* when you want the realtime sync engine with typed model proxies.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { Ablo } from '@ablo/sync-engine/client';
|
|
11
|
+
* import { schema } from './schema';
|
|
12
|
+
*
|
|
13
|
+
* const ablo = Ablo({
|
|
14
|
+
* schema,
|
|
15
|
+
* apiKey: process.env.ABLO_API_KEY,
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* const tasks = ablo.tasks.list({ where: { status: 'todo' } });
|
|
19
|
+
* await ablo.tasks.create({ title: 'New task' });
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* For headless agents (workers, bots), pass `kind: 'agent'` plus a
|
|
23
|
+
* Biscuit `capabilityToken`:
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* const bot = Ablo({
|
|
27
|
+
* schema,
|
|
28
|
+
* apiKey: process.env.ABLO_API_KEY,
|
|
29
|
+
* kind: 'agent',
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export { Ablo, computeFKDepthPriority, } from './Ablo.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type AbloPersistence = 'volatile' | 'indexeddb';
|
|
2
|
+
export interface PersistenceOptions {
|
|
3
|
+
readonly persistence?: AbloPersistence | undefined;
|
|
4
|
+
readonly inMemory?: boolean | undefined;
|
|
5
|
+
readonly offline?: boolean | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare function shouldUseInMemoryPersistence(options: PersistenceOptions): boolean;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function shouldUseInMemoryPersistence(options) {
|
|
2
|
+
if (typeof window === 'undefined')
|
|
3
|
+
return true;
|
|
4
|
+
if (options.persistence)
|
|
5
|
+
return options.persistence === 'volatile';
|
|
6
|
+
if (typeof options.inMemory === 'boolean')
|
|
7
|
+
return options.inMemory;
|
|
8
|
+
if (options.offline === true)
|
|
9
|
+
return false;
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Up-front validation of `AbloOptions`. Returns the first error
|
|
3
|
+
* encountered or null if all checks pass — caller writes the error
|
|
4
|
+
* into `store.syncStatus` so consumers see it through the existing
|
|
5
|
+
* status surface rather than catching it at the call site.
|
|
6
|
+
*
|
|
7
|
+
* Extracted from `Ablo.ts` (which was ~2300 LOC of constructor wiring)
|
|
8
|
+
* so the validation rules are readable in isolation. The order of
|
|
9
|
+
* checks matters: missing `url` is checked before identity options
|
|
10
|
+
* because the error messages reference URLs and would mislead if a
|
|
11
|
+
* URL was actually present.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Minimal subset of `AbloOptions` the validator actually inspects.
|
|
15
|
+
* Defined here as its own interface so the validator doesn't pull
|
|
16
|
+
* the whole 200+-line `AbloOptions` type — and to avoid a circular
|
|
17
|
+
* import with `Ablo.ts`. Fields are kept structurally identical to
|
|
18
|
+
* `AbloOptions` so a real options object satisfies this shape.
|
|
19
|
+
*/
|
|
20
|
+
export interface ValidatableAbloOptions {
|
|
21
|
+
readonly schema?: {
|
|
22
|
+
readonly models?: Record<string, unknown>;
|
|
23
|
+
} | null;
|
|
24
|
+
readonly kind?: 'user' | 'agent' | 'system';
|
|
25
|
+
readonly user?: {
|
|
26
|
+
readonly id?: string;
|
|
27
|
+
} | undefined;
|
|
28
|
+
readonly agentId?: string | undefined;
|
|
29
|
+
readonly capabilityToken?: string | undefined;
|
|
30
|
+
}
|
|
31
|
+
export interface ValidateAbloOptionsInput {
|
|
32
|
+
readonly options: ValidatableAbloOptions;
|
|
33
|
+
readonly url: string;
|
|
34
|
+
/**
|
|
35
|
+
* Truthy when an API key was supplied (string or callable). The
|
|
36
|
+
* validator only inspects presence, never the value, so the input
|
|
37
|
+
* shape stays loose to accept whatever the caller resolved.
|
|
38
|
+
*/
|
|
39
|
+
readonly configuredApiKey: unknown;
|
|
40
|
+
readonly configuredAuthToken: unknown;
|
|
41
|
+
}
|
|
42
|
+
export declare function validateAbloOptions(input: ValidateAbloOptionsInput): Error | null;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Up-front validation of `AbloOptions`. Returns the first error
|
|
3
|
+
* encountered or null if all checks pass — caller writes the error
|
|
4
|
+
* into `store.syncStatus` so consumers see it through the existing
|
|
5
|
+
* status surface rather than catching it at the call site.
|
|
6
|
+
*
|
|
7
|
+
* Extracted from `Ablo.ts` (which was ~2300 LOC of constructor wiring)
|
|
8
|
+
* so the validation rules are readable in isolation. The order of
|
|
9
|
+
* checks matters: missing `url` is checked before identity options
|
|
10
|
+
* because the error messages reference URLs and would mislead if a
|
|
11
|
+
* URL was actually present.
|
|
12
|
+
*/
|
|
13
|
+
export function validateAbloOptions(input) {
|
|
14
|
+
const { options, url, configuredApiKey, configuredAuthToken } = input;
|
|
15
|
+
const kind = options.kind ?? 'user';
|
|
16
|
+
if (!url) {
|
|
17
|
+
return new Error('Ablo: `url` is required. Pass the sync server URL, e.g. ' +
|
|
18
|
+
`Ablo({ baseURL: 'wss://sync.ablo.dev', schema, user })`);
|
|
19
|
+
}
|
|
20
|
+
// Schema is optional for the resource-first API:
|
|
21
|
+
// Ablo({ apiKey }).resource('clauses').retrieve(...)
|
|
22
|
+
// Passing a schema only enables typed model sugar (`ablo.tasks.update(...)`).
|
|
23
|
+
if (!configuredApiKey &&
|
|
24
|
+
!configuredAuthToken &&
|
|
25
|
+
!options.capabilityToken &&
|
|
26
|
+
kind === 'user' &&
|
|
27
|
+
options.user &&
|
|
28
|
+
!options.user.id) {
|
|
29
|
+
return new Error('Ablo: `user.id` must be a non-empty string when `user` is provided.');
|
|
30
|
+
}
|
|
31
|
+
if (!configuredApiKey && !configuredAuthToken && kind === 'agent' && !options.agentId) {
|
|
32
|
+
return new Error('Ablo: provide either `apiKey` or `agentId` for `kind: "agent"`. ' +
|
|
33
|
+
'Hosted-cloud consumers pass `apiKey` and the server derives the ' +
|
|
34
|
+
'agent identity from its scope; self-hosted passes `agentId` + ' +
|
|
35
|
+
'`capabilityToken` directly.');
|
|
36
|
+
}
|
|
37
|
+
if (!configuredApiKey && !configuredAuthToken && kind === 'agent' && !options.capabilityToken) {
|
|
38
|
+
return new Error('Ablo: provide either `apiKey` (hosted cloud — SDK exchanges internally) ' +
|
|
39
|
+
'or `capabilityToken` (self-hosted — your auth layer mints + hands in). ' +
|
|
40
|
+
'See https://ablo.dev/docs/api-keys for the full pattern.');
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ablo/sync-engine/config — App initialization
|
|
3
|
+
*
|
|
4
|
+
* One-time setup at app boot. Provides DI interface types
|
|
5
|
+
* and the initSyncEngine() function to wire real implementations.
|
|
6
|
+
*/
|
|
7
|
+
export { initSyncEngine, resetSyncEngine, isSyncEngineInitialized } from '../context.js';
|
|
8
|
+
export { noopLogger, noopObservability, noopAnalytics, browserOnlineStatus, defaultSessionErrorDetector, emptyConfig, type SyncEngineContext, } from '../SyncEngineContext.js';
|
|
9
|
+
export type { SyncEngineConfig, SyncLogger, SyncObservabilityProvider, SyncAnalytics, MutationExecutor, MutationDispatcher, SessionErrorDetector, OnlineStatusProvider, CommitResult, MutationOperation, BreadcrumbLevel, SyncBreadcrumbCategory, TransactionFailureDetails, BootstrapFailureDetails, WebSocketErrorDetails, RollbackDetails, SpanAttributes, } from '../interfaces/index.js';
|
|
10
|
+
export { SyncSessionError } from '../errors.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ablo/sync-engine/config — App initialization
|
|
3
|
+
*
|
|
4
|
+
* One-time setup at app boot. Provides DI interface types
|
|
5
|
+
* and the initSyncEngine() function to wire real implementations.
|
|
6
|
+
*/
|
|
7
|
+
// Context lifecycle
|
|
8
|
+
export { initSyncEngine, resetSyncEngine, isSyncEngineInitialized } from '../context.js';
|
|
9
|
+
// Context type + no-op defaults (for testing or gradual adoption)
|
|
10
|
+
export { noopLogger, noopObservability, noopAnalytics, browserOnlineStatus, defaultSessionErrorDetector, emptyConfig, } from '../SyncEngineContext.js';
|
|
11
|
+
// Errors
|
|
12
|
+
export { SyncSessionError } from '../errors.js';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level context accessor
|
|
3
|
+
*
|
|
4
|
+
* Set once during SDK initialization via `initSyncEngine(context)`.
|
|
5
|
+
* All internal SDK files access dependencies through `getContext()`.
|
|
6
|
+
* This avoids threading context through every constructor.
|
|
7
|
+
*/
|
|
8
|
+
import type { SyncEngineContext } from './SyncEngineContext.js';
|
|
9
|
+
/**
|
|
10
|
+
* Initialize the sync engine with application-provided dependencies.
|
|
11
|
+
* Must be called before any sync engine operations.
|
|
12
|
+
*/
|
|
13
|
+
export declare function initSyncEngine(context: SyncEngineContext): void;
|
|
14
|
+
/**
|
|
15
|
+
* Get the current sync engine context.
|
|
16
|
+
* Returns a safe fallback with no-op implementations if not yet initialized,
|
|
17
|
+
* so SDK files can import at module load time without crashing.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getContext(): SyncEngineContext;
|
|
20
|
+
/**
|
|
21
|
+
* Check if the sync engine has been initialized.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isSyncEngineInitialized(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Reset context (for testing or cleanup).
|
|
26
|
+
*/
|
|
27
|
+
export declare function resetSyncEngine(): void;
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level context accessor
|
|
3
|
+
*
|
|
4
|
+
* Set once during SDK initialization via `initSyncEngine(context)`.
|
|
5
|
+
* All internal SDK files access dependencies through `getContext()`.
|
|
6
|
+
* This avoids threading context through every constructor.
|
|
7
|
+
*/
|
|
8
|
+
import { noopLogger, noopObservability, browserOnlineStatus, defaultSessionErrorDetector, emptyConfig, } from './SyncEngineContext.js';
|
|
9
|
+
let _context = null;
|
|
10
|
+
/**
|
|
11
|
+
* Initialize the sync engine with application-provided dependencies.
|
|
12
|
+
* Must be called before any sync engine operations.
|
|
13
|
+
*/
|
|
14
|
+
export function initSyncEngine(context) {
|
|
15
|
+
_context = context;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get the current sync engine context.
|
|
19
|
+
* Returns a safe fallback with no-op implementations if not yet initialized,
|
|
20
|
+
* so SDK files can import at module load time without crashing.
|
|
21
|
+
*/
|
|
22
|
+
export function getContext() {
|
|
23
|
+
if (!_context) {
|
|
24
|
+
return _fallback;
|
|
25
|
+
}
|
|
26
|
+
return _context;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if the sync engine has been initialized.
|
|
30
|
+
*/
|
|
31
|
+
export function isSyncEngineInitialized() {
|
|
32
|
+
return _context !== null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Reset context (for testing or cleanup).
|
|
36
|
+
*/
|
|
37
|
+
export function resetSyncEngine() {
|
|
38
|
+
_context = null;
|
|
39
|
+
}
|
|
40
|
+
/** Fallback context with no-op implementations */
|
|
41
|
+
const _fallback = {
|
|
42
|
+
logger: noopLogger,
|
|
43
|
+
observability: noopObservability,
|
|
44
|
+
onlineStatus: browserOnlineStatus,
|
|
45
|
+
sessionErrorDetector: defaultSessionErrorDetector,
|
|
46
|
+
config: emptyConfig,
|
|
47
|
+
mutationExecutor: {
|
|
48
|
+
commit: () => Promise.resolve({ lastSyncId: 0 }),
|
|
49
|
+
executeCreate: () => Promise.resolve(),
|
|
50
|
+
executeUpdate: () => Promise.resolve(null),
|
|
51
|
+
executeDelete: () => Promise.resolve(),
|
|
52
|
+
executeArchive: () => Promise.resolve(),
|
|
53
|
+
executeUnarchive: () => Promise.resolve(),
|
|
54
|
+
},
|
|
55
|
+
mutationDispatcher: {
|
|
56
|
+
dispatch: () => Promise.resolve(),
|
|
57
|
+
},
|
|
58
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ablo Sync Engine - Database Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages the two-tier database architecture:
|
|
5
|
+
* 1. ablo_databases - Metadata about workspace databases
|
|
6
|
+
* 2. ablo_(hash) - Workspace-specific data storage
|
|
7
|
+
*
|
|
8
|
+
* Follows Ablo's architecture for database management.
|
|
9
|
+
*/
|
|
10
|
+
export interface DatabaseInfo {
|
|
11
|
+
name: string;
|
|
12
|
+
userId: string;
|
|
13
|
+
workspaceId: string;
|
|
14
|
+
schemaHash: string;
|
|
15
|
+
schemaVersion: number;
|
|
16
|
+
userVersion?: number;
|
|
17
|
+
createdAt: Date;
|
|
18
|
+
updatedAt: Date;
|
|
19
|
+
}
|
|
20
|
+
export interface WorkspaceMetadata {
|
|
21
|
+
lastSyncId: number;
|
|
22
|
+
firstSyncId: number;
|
|
23
|
+
backendDatabaseVersion: number;
|
|
24
|
+
subscribedSyncGroups: string[];
|
|
25
|
+
updatedAt: Date;
|
|
26
|
+
schemaHash?: string;
|
|
27
|
+
syncGroups?: string[];
|
|
28
|
+
versions?: Record<string, number>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* DatabaseManager - Manages Ablo's two-tier database architecture
|
|
32
|
+
*
|
|
33
|
+
* Key responsibilities:
|
|
34
|
+
* - Manages ablo_databases (database registry)
|
|
35
|
+
* - Creates workspace-specific databases (ablo_hash)
|
|
36
|
+
* - Handles database migration and versioning
|
|
37
|
+
* - Provides database info and metadata management
|
|
38
|
+
*/
|
|
39
|
+
export declare class DatabaseManager {
|
|
40
|
+
private metaDb;
|
|
41
|
+
private readonly metaDbName;
|
|
42
|
+
constructor();
|
|
43
|
+
/**
|
|
44
|
+
* Initialize the meta database (ablo_databases)
|
|
45
|
+
*/
|
|
46
|
+
initializeMetaDatabase(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Calculate database info for a user/workspace combination
|
|
49
|
+
*/
|
|
50
|
+
calculateDatabaseInfo(userId: string, workspaceId: string, userVersion?: number): Promise<DatabaseInfo>;
|
|
51
|
+
/**
|
|
52
|
+
* Generate deterministic database name
|
|
53
|
+
*/
|
|
54
|
+
private generateDatabaseName;
|
|
55
|
+
/**
|
|
56
|
+
* Register database info in ablo_databases
|
|
57
|
+
*/
|
|
58
|
+
registerDatabase(info: DatabaseInfo): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Get database info by name
|
|
61
|
+
*/
|
|
62
|
+
getDatabaseInfo(name: string): Promise<DatabaseInfo | null>;
|
|
63
|
+
/**
|
|
64
|
+
* Get all databases for a user
|
|
65
|
+
*/
|
|
66
|
+
getDatabasesForUser(userId: string): Promise<DatabaseInfo[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Open workspace-specific database
|
|
69
|
+
*/
|
|
70
|
+
openWorkspaceDatabase(dbInfo: DatabaseInfo, createStoresFn?: (db: IDBDatabase, tx: IDBTransaction) => Promise<void>): Promise<IDBDatabase>;
|
|
71
|
+
/**
|
|
72
|
+
* Read workspace metadata from __meta table
|
|
73
|
+
*/
|
|
74
|
+
getWorkspaceMetadata(db: IDBDatabase): Promise<WorkspaceMetadata | null>;
|
|
75
|
+
/**
|
|
76
|
+
* Write workspace metadata to __meta table
|
|
77
|
+
*/
|
|
78
|
+
setWorkspaceMetadata(db: IDBDatabase, metadata: WorkspaceMetadata): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Check if a model is persisted (all instances loaded)
|
|
81
|
+
*/
|
|
82
|
+
isModelPersisted(db: IDBDatabase, modelName: string): Promise<boolean>;
|
|
83
|
+
/**
|
|
84
|
+
* Mark a model as persisted
|
|
85
|
+
*/
|
|
86
|
+
setModelPersisted(db: IDBDatabase, modelName: string, persisted: boolean): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Get all model persistence states
|
|
89
|
+
*/
|
|
90
|
+
getAllModelPersistenceStates(db: IDBDatabase): Promise<Record<string, boolean>>;
|
|
91
|
+
/**
|
|
92
|
+
* Delete a workspace database
|
|
93
|
+
*/
|
|
94
|
+
deleteWorkspaceDatabase(dbInfo: DatabaseInfo): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Get comprehensive database statistics
|
|
97
|
+
*/
|
|
98
|
+
getDatabaseStatistics(): Promise<{
|
|
99
|
+
metaDatabaseSize: number;
|
|
100
|
+
totalWorkspaceDatabases: number;
|
|
101
|
+
databasesByUser: Record<string, number>;
|
|
102
|
+
schemaVersions: Record<string, number>;
|
|
103
|
+
}>;
|
|
104
|
+
/**
|
|
105
|
+
* Close all database connections
|
|
106
|
+
*/
|
|
107
|
+
close(): Promise<void>;
|
|
108
|
+
}
|