@abloatai/transaction 0.59.1 → 0.60.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/dist/auth/apiKey.d.ts +10 -11
- package/dist/auth/apiKey.d.ts.map +1 -1
- package/dist/auth/apiKey.js +15 -29
- package/dist/auth/apiKey.js.map +1 -1
- package/dist/auth/browserCredentialSafety.js +1 -1
- package/dist/auth/browserCredentialSafety.js.map +1 -1
- package/dist/auth/capabilityLifecycle.d.ts +1 -1
- package/dist/auth/capabilityLifecycle.d.ts.map +1 -1
- package/dist/auth/capabilityLifecycle.js +2 -1
- package/dist/auth/capabilityLifecycle.js.map +1 -1
- package/dist/auth/credentialEndpoint.js +1 -1
- package/dist/auth/credentialEndpoint.js.map +1 -1
- package/dist/auth/credentialResult.d.ts +2 -1
- package/dist/auth/credentialResult.d.ts.map +1 -1
- package/dist/auth/credentialResult.js.map +1 -1
- package/dist/claims/events.d.ts +1 -1
- package/dist/claims/events.d.ts.map +1 -1
- package/dist/client/ablo.d.ts +15 -11
- package/dist/client/ablo.d.ts.map +1 -1
- package/dist/client/ablo.js +5 -14
- package/dist/client/ablo.js.map +1 -1
- package/dist/client/resources/httpResources.d.ts +1 -169
- package/dist/client/resources/httpResources.d.ts.map +1 -1
- package/dist/client/resources/httpResources.js +1 -1
- package/dist/client/resources/httpResources.js.map +1 -1
- package/dist/client/resources/modelOperations.d.ts +0 -9
- package/dist/client/resources/modelOperations.d.ts.map +1 -1
- package/dist/client/surface.d.ts +2 -2
- package/dist/client/surface.d.ts.map +1 -1
- package/dist/client/surface.js +8 -3
- package/dist/client/surface.js.map +1 -1
- package/dist/commit/contract.d.ts +10 -10
- package/dist/commit/recordRuntime.d.ts +3 -2
- package/dist/commit/recordRuntime.d.ts.map +1 -1
- package/dist/commit/recordRuntime.js +1 -0
- package/dist/commit/recordRuntime.js.map +1 -1
- package/dist/coordination/index.d.ts +2 -2
- package/dist/coordination/index.d.ts.map +1 -1
- package/dist/coordination/index.js +3 -4
- package/dist/coordination/index.js.map +1 -1
- package/dist/coordination/schema.d.ts +3 -47
- package/dist/coordination/schema.d.ts.map +1 -1
- package/dist/coordination/schema.js +7 -69
- package/dist/coordination/schema.js.map +1 -1
- package/dist/errorCodes.d.ts +2 -2
- package/dist/errorCodes.d.ts.map +1 -1
- package/dist/errorCodes.js +5 -9
- package/dist/errorCodes.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +16 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/sessions/client.d.ts +29 -0
- package/dist/sessions/client.d.ts.map +1 -0
- package/dist/sessions/client.js +69 -0
- package/dist/sessions/client.js.map +1 -0
- package/dist/sessions/contract.d.ts +97 -0
- package/dist/sessions/contract.d.ts.map +1 -0
- package/dist/sessions/contract.js +5 -0
- package/dist/sessions/contract.js.map +1 -0
- package/dist/{auth/sessionMint.d.ts → sessions/create.d.ts} +4 -4
- package/dist/sessions/create.d.ts.map +1 -0
- package/dist/{auth/sessionMint.js → sessions/create.js} +11 -10
- package/dist/sessions/create.js.map +1 -0
- package/dist/sessions/handler.d.ts +23 -0
- package/dist/sessions/handler.d.ts.map +1 -0
- package/dist/sessions/handler.js +55 -0
- package/dist/sessions/handler.js.map +1 -0
- package/dist/sessions/index.d.ts +14 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/sessions/index.js +14 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/{transport/connection/credentialLifecycle.d.ts → sessions/lifecycle.d.ts} +6 -6
- package/dist/sessions/lifecycle.d.ts.map +1 -0
- package/dist/{transport/connection/credentialLifecycle.js → sessions/lifecycle.js} +5 -5
- package/dist/sessions/lifecycle.js.map +1 -0
- package/dist/sessions/source.d.ts +24 -0
- package/dist/sessions/source.d.ts.map +1 -0
- package/dist/sessions/source.js +56 -0
- package/dist/sessions/source.js.map +1 -0
- package/dist/transport/connection/index.d.ts +0 -1
- package/dist/transport/connection/index.d.ts.map +1 -1
- package/dist/transport/connection/index.js +0 -1
- package/dist/transport/connection/index.js.map +1 -1
- package/dist/transport/connection/manager.d.ts +1 -1
- package/dist/transport/connection/manager.d.ts.map +1 -1
- package/dist/transport/http/client.d.ts +44 -16
- package/dist/transport/http/client.d.ts.map +1 -1
- package/dist/transport/http/client.js +125 -12
- package/dist/transport/http/client.js.map +1 -1
- package/dist/transport/http/options.d.ts +4 -1
- package/dist/transport/http/options.d.ts.map +1 -1
- package/dist/transport/http/transport.d.ts +25 -10
- package/dist/transport/http/transport.d.ts.map +1 -1
- package/dist/transport/http/transport.js +102 -56
- package/dist/transport/http/transport.js.map +1 -1
- package/dist/transport/websocket/commitFrames.d.ts +5 -5
- package/dist/transport/websocket/commitFrames.d.ts.map +1 -1
- package/dist/transport/websocket/commitFrames.js +1 -0
- package/dist/transport/websocket/commitFrames.js.map +1 -1
- package/dist/transport/websocket/contextSubscription.d.ts +6 -0
- package/dist/transport/websocket/contextSubscription.d.ts.map +1 -0
- package/dist/transport/websocket/contextSubscription.js +45 -0
- package/dist/transport/websocket/contextSubscription.js.map +1 -0
- package/dist/transport/websocket/frameHandlers.d.ts +0 -14
- package/dist/transport/websocket/frameHandlers.d.ts.map +1 -1
- package/dist/transport/websocket/frameHandlers.js +1 -71
- package/dist/transport/websocket/frameHandlers.js.map +1 -1
- package/dist/transport/websocket/session.d.ts +4 -0
- package/dist/transport/websocket/session.d.ts.map +1 -0
- package/dist/transport/websocket/session.js +425 -0
- package/dist/transport/websocket/session.js.map +1 -0
- package/dist/transport/websocket/sessionContract.d.ts +78 -0
- package/dist/transport/websocket/sessionContract.d.ts.map +1 -0
- package/dist/transport/websocket/sessionContract.js +2 -0
- package/dist/transport/websocket/sessionContract.js.map +1 -0
- package/dist/transport/websocket/transport.d.ts +27 -42
- package/dist/transport/websocket/transport.d.ts.map +1 -1
- package/dist/transport/websocket/transport.js +77 -102
- package/dist/transport/websocket/transport.js.map +1 -1
- package/dist/wire/inboundFrames.d.ts +0 -10
- package/dist/wire/inboundFrames.d.ts.map +1 -1
- package/dist/wire/inboundFrames.js +1 -6
- package/dist/wire/inboundFrames.js.map +1 -1
- package/package.json +7 -1
- package/src/auth/apiKey.ts +25 -44
- package/src/auth/browserCredentialSafety.ts +1 -1
- package/src/auth/capabilityLifecycle.ts +3 -2
- package/src/auth/credentialEndpoint.ts +1 -1
- package/src/auth/credentialResult.ts +2 -0
- package/src/claims/events.ts +1 -2
- package/src/client/ablo.ts +23 -13
- package/src/client/resources/httpResources.ts +2 -174
- package/src/client/resources/modelOperations.ts +0 -10
- package/src/client/surface.ts +9 -4
- package/src/commit/recordRuntime.ts +4 -2
- package/src/coordination/index.ts +2 -9
- package/src/coordination/schema.ts +7 -81
- package/src/errorCodes.ts +8 -13
- package/src/errors.ts +18 -1
- package/src/index.ts +1 -0
- package/src/sessions/client.ts +121 -0
- package/src/sessions/contract.ts +116 -0
- package/src/{auth/sessionMint.ts → sessions/create.ts} +13 -12
- package/src/sessions/handler.ts +96 -0
- package/src/sessions/index.ts +13 -0
- package/src/{transport/connection/credentialLifecycle.ts → sessions/lifecycle.ts} +5 -5
- package/src/sessions/source.ts +94 -0
- package/src/transport/connection/index.ts +0 -1
- package/src/transport/connection/manager.ts +1 -1
- package/src/transport/http/client.ts +183 -26
- package/src/transport/http/options.ts +4 -1
- package/src/transport/http/transport.ts +140 -78
- package/src/transport/websocket/commitFrames.ts +5 -5
- package/src/transport/websocket/contextSubscription.ts +55 -0
- package/src/transport/websocket/frameHandlers.ts +0 -102
- package/src/transport/websocket/session.ts +522 -0
- package/src/transport/websocket/sessionContract.ts +106 -0
- package/src/transport/websocket/transport.ts +85 -137
- package/src/wire/inboundFrames.ts +0 -6
- package/dist/auth/sessionMint.d.ts.map +0 -1
- package/dist/auth/sessionMint.js.map +0 -1
- package/dist/transport/connection/credentialLifecycle.d.ts.map +0 -1
- package/dist/transport/connection/credentialLifecycle.js.map +0 -1
package/src/auth/apiKey.ts
CHANGED
|
@@ -17,15 +17,18 @@ import { classifyCredentialKind } from './credentialKind.js';
|
|
|
17
17
|
import { ABLO_DEFAULT_BASE_URL } from './hostedEndpoints.js';
|
|
18
18
|
import { normalizeAbloBaseUrl } from './baseUrl.js';
|
|
19
19
|
import type { KeyEnvironment } from '../environment.js';
|
|
20
|
-
import { isCredentialEndpoint
|
|
20
|
+
import { isCredentialEndpoint } from './credentialEndpoint.js';
|
|
21
21
|
import {
|
|
22
22
|
credentialToken,
|
|
23
23
|
type CredentialProvider,
|
|
24
|
+
type CredentialProviderResult,
|
|
24
25
|
} from './credentialResult.js';
|
|
26
|
+
import type { SessionSource } from '../sessions/contract.js';
|
|
25
27
|
import {
|
|
26
28
|
assertBrowserSafety,
|
|
27
29
|
protectBrowserCredentialProvider,
|
|
28
30
|
} from './browserCredentialSafety.js';
|
|
31
|
+
import { resolveSessionCredential } from '../sessions/source.js';
|
|
29
32
|
export { assertBrowserSafety };
|
|
30
33
|
|
|
31
34
|
/**
|
|
@@ -40,22 +43,18 @@ export type { CredentialProvider } from './credentialResult.js';
|
|
|
40
43
|
* The client options that decide a credential.
|
|
41
44
|
*
|
|
42
45
|
* This is the ONE declaration of that set. The resolvers below read it, and the
|
|
43
|
-
* transport configs that accept these options derive from it rather than
|
|
44
|
-
* the fields again
|
|
45
|
-
* runtime, named in an error message, and absent from the type a caller writes
|
|
46
|
-
* against.
|
|
46
|
+
* transport configs that accept these options derive from it rather than
|
|
47
|
+
* listing the fields again.
|
|
47
48
|
*/
|
|
48
49
|
export interface AuthClientOptions {
|
|
49
50
|
readonly apiKey?: string | CredentialProvider | null;
|
|
50
|
-
/** A
|
|
51
|
-
readonly
|
|
51
|
+
/** A scoped session, its renewal provider, or a browser session endpoint. */
|
|
52
|
+
readonly session?: SessionSource | null;
|
|
52
53
|
/** A token the caller already has, used as-is. */
|
|
53
54
|
readonly authToken?: string | null;
|
|
54
55
|
readonly baseURL?: string | null;
|
|
55
56
|
readonly dangerouslyAllowBrowser?: boolean;
|
|
56
57
|
readonly fetch?: typeof globalThis.fetch;
|
|
57
|
-
readonly authTimeoutMs?: number;
|
|
58
|
-
readonly allowCrossOriginAuthEndpoint?: boolean;
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
export interface AuthResolveInput {
|
|
@@ -83,45 +82,20 @@ export function readProcessEnv(): Record<string, string | undefined> {
|
|
|
83
82
|
export function resolveApiKey(
|
|
84
83
|
input: AuthResolveInput,
|
|
85
84
|
): string | CredentialProvider | null {
|
|
86
|
-
// `authEndpoint` is the option that names a session-mint route: a URL the
|
|
87
|
-
// client exchanges for a short-lived token, or an async resolver for custom
|
|
88
|
-
// exchanges. It is resolved into a `CredentialProvider` here — the single point
|
|
89
|
-
// shared by every client variant (WebSocket, HTTP, and protocol clients) — so
|
|
90
|
-
// every downstream consumer sees the same resolver and the credential
|
|
91
|
-
// lifecycle drives renewal off it.
|
|
92
|
-
const endpoint = input.options.authEndpoint;
|
|
93
85
|
const configured = input.options.apiKey;
|
|
94
|
-
|
|
95
|
-
|
|
86
|
+
const session = input.options.session;
|
|
87
|
+
if (session != null) {
|
|
88
|
+
if (configured != null || input.options.authToken != null) {
|
|
96
89
|
throw new AbloValidationError(
|
|
97
|
-
'Ablo: pass
|
|
98
|
-
|
|
99
|
-
'which credential to use.',
|
|
100
|
-
{ code: 'invalid_options', param: 'authEndpoint' },
|
|
90
|
+
'Ablo: pass `session`, `apiKey`, or `authToken` — not more than one.',
|
|
91
|
+
{ code: 'invalid_options', param: 'session' },
|
|
101
92
|
);
|
|
102
93
|
}
|
|
103
|
-
|
|
104
|
-
return protectBrowserCredentialProvider(
|
|
105
|
-
endpoint,
|
|
106
|
-
input.options.dangerouslyAllowBrowser,
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
if (!isCredentialEndpoint(endpoint)) {
|
|
110
|
-
throw new AbloValidationError(
|
|
111
|
-
'`authEndpoint` expects a URL or path (e.g. \'/api/ablo-session\') or an ' +
|
|
112
|
-
'async resolver — a key string belongs in `apiKey`.',
|
|
113
|
-
{ code: 'invalid_options', param: 'authEndpoint' },
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
return protectBrowserCredentialProvider(createEndpointCredentialResolver(endpoint, {
|
|
117
|
-
fetch: input.options.fetch,
|
|
118
|
-
timeoutMs: input.options.authTimeoutMs,
|
|
119
|
-
allowCrossOrigin: input.options.allowCrossOriginAuthEndpoint,
|
|
120
|
-
}), input.options.dangerouslyAllowBrowser);
|
|
94
|
+
return resolveSessionCredential(session, input.options);
|
|
121
95
|
}
|
|
122
96
|
if (typeof configured === 'string' && isCredentialEndpoint(configured)) {
|
|
123
97
|
throw new AbloValidationError(
|
|
124
|
-
'`apiKey`
|
|
98
|
+
'`apiKey` does not accept an endpoint. Use `session: { endpoint }`.',
|
|
125
99
|
{ code: 'invalid_options', param: 'apiKey' },
|
|
126
100
|
);
|
|
127
101
|
}
|
|
@@ -139,8 +113,8 @@ export function resolveApiKey(
|
|
|
139
113
|
* needs: an async `() => token | null`, or `null` when auth is static — a plain
|
|
140
114
|
* long-lived key string with no refresh, which is the common case.
|
|
141
115
|
*
|
|
142
|
-
*
|
|
143
|
-
* SDK then drives the whole credential lifecycle
|
|
116
|
+
* A renewable session or browser session endpoint resolves to a credential
|
|
117
|
+
* provider, and the SDK then drives the whole credential lifecycle
|
|
144
118
|
* from it: mint-before-connect, the proactive refresh timer with its
|
|
145
119
|
* wake/online/focus re-mint, and the reactive `credential_stale` re-mint. The
|
|
146
120
|
* resolver follows the provider contract end to end: resolve a token,
|
|
@@ -434,8 +408,15 @@ export function rejectRemovedDatabaseUrlOption(options: object): void {
|
|
|
434
408
|
export async function resolveApiKeyValue(
|
|
435
409
|
apiKey: string | CredentialProvider | null,
|
|
436
410
|
): Promise<string | null> {
|
|
411
|
+
return credentialToken(await resolveCredentialValue(apiKey));
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/** Resolve without discarding session expiry metadata needed by live clients. */
|
|
415
|
+
export async function resolveCredentialValue(
|
|
416
|
+
apiKey: string | CredentialProvider | null,
|
|
417
|
+
): Promise<CredentialProviderResult> {
|
|
437
418
|
if (apiKey == null) return null;
|
|
438
|
-
if (typeof apiKey === 'function') return
|
|
419
|
+
if (typeof apiKey === 'function') return apiKey();
|
|
439
420
|
return apiKey;
|
|
440
421
|
}
|
|
441
422
|
|
|
@@ -42,7 +42,7 @@ export function protectBrowserCredentialProvider(
|
|
|
42
42
|
function throwBrowserSecretError(): never {
|
|
43
43
|
throw new AbloAuthenticationError(
|
|
44
44
|
'A secret `sk_` credential reached the browser. Keep it server-side and ' +
|
|
45
|
-
'configure the browser with `
|
|
45
|
+
'configure the browser with `session: { endpoint }` instead.',
|
|
46
46
|
{ code: 'browser_apikey_blocked' },
|
|
47
47
|
);
|
|
48
48
|
}
|
|
@@ -9,7 +9,8 @@ import type {
|
|
|
9
9
|
RotateSessionParams,
|
|
10
10
|
SessionRevocation,
|
|
11
11
|
SessionRotation,
|
|
12
|
-
} from '../
|
|
12
|
+
} from '../sessions/contract.js';
|
|
13
|
+
import { sessionScope } from '../sessions/contract.js';
|
|
13
14
|
|
|
14
15
|
export const sessionRevocationResponseSchema = z.object({
|
|
15
16
|
id: z.string().min(1),
|
|
@@ -166,7 +167,7 @@ export async function rotateCapability(
|
|
|
166
167
|
token: parsed.data.token,
|
|
167
168
|
expiresAt: parsed.data.expiresAt,
|
|
168
169
|
organizationId: parsed.data.organizationId,
|
|
169
|
-
scope: parsed.data.scope,
|
|
170
|
+
scope: sessionScope(parsed.data.scope),
|
|
170
171
|
rotatedFrom: {
|
|
171
172
|
id: parsed.data.rotatedFrom.capabilityId,
|
|
172
173
|
expiresAt: parsed.data.rotatedFrom.expiresAt,
|
|
@@ -23,7 +23,7 @@ function assertEndpointOrigin(endpoint: string, allowCrossOrigin: boolean): void
|
|
|
23
23
|
if (endpointOrigin !== window.location.origin) {
|
|
24
24
|
throw new Error(
|
|
25
25
|
'credential endpoint must be same-origin; set ' +
|
|
26
|
-
'`
|
|
26
|
+
'`session.allowCrossOrigin: true` only after configuring CORS and CSRF protection',
|
|
27
27
|
);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { CredentialEndpointSuccess } from './credentialEndpointProtocol.js';
|
|
2
|
+
import type { SessionCredential } from '../sessions/contract.js';
|
|
2
3
|
|
|
3
4
|
export type CredentialProviderResult =
|
|
4
5
|
| string
|
|
5
6
|
| CredentialEndpointSuccess
|
|
7
|
+
| SessionCredential
|
|
6
8
|
| null;
|
|
7
9
|
|
|
8
10
|
/** Rotating secret provider or short-lived browser credential provider. */
|
package/src/claims/events.ts
CHANGED
package/src/client/ablo.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `Ablo` — the entry point to the coordination layer.
|
|
3
3
|
*
|
|
4
|
-
* The factory constructs the
|
|
5
|
-
* claims
|
|
6
|
-
*
|
|
7
|
-
* identity and
|
|
8
|
-
* server-side actor installs: an agent, a worker, a cron job, a route handler.
|
|
4
|
+
* The factory constructs the headless client: typed model resources, commits,
|
|
5
|
+
* and claims. API-key clients use request/response HTTP.
|
|
6
|
+
* Session clients use one reconnecting WebSocket by default; the session is
|
|
7
|
+
* the scoped identity and outlives any individual socket connection.
|
|
9
8
|
*
|
|
10
9
|
* ```ts
|
|
11
10
|
* import { Ablo } from '@abloatai/ablo';
|
|
12
11
|
* import { schema } from '../schema';
|
|
13
12
|
*
|
|
14
|
-
* const ablo = Ablo({ schema, apiKey: process.env.ABLO_API_KEY
|
|
13
|
+
* const ablo = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
|
|
15
14
|
* await ablo.items.update({ id: itemId, data: { status: 'done' } });
|
|
16
15
|
* ```
|
|
17
16
|
*
|
|
@@ -23,6 +22,7 @@
|
|
|
23
22
|
import {
|
|
24
23
|
createAbloHttpClient,
|
|
25
24
|
type AbloHttpClient,
|
|
25
|
+
type AbloWebSocketClient,
|
|
26
26
|
} from '../transport/http/client.js';
|
|
27
27
|
import type { SchemaRecord } from '../schema/schema.js';
|
|
28
28
|
import type { PublicAbloOptions } from './surface.js';
|
|
@@ -34,22 +34,32 @@ import type * as _Http from './resources/httpResources.js';
|
|
|
34
34
|
/**
|
|
35
35
|
* Create a coordination-layer client in one call.
|
|
36
36
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* factory and may be omitted. The duplex transport joins this slot when the
|
|
40
|
-
* socket carve lands (ADR 0016, follow-up 3a).
|
|
37
|
+
* Transport follows identity by default: API keys use HTTP and sessions use a
|
|
38
|
+
* reconnecting WebSocket without changing the model, commit, or claim API.
|
|
41
39
|
*/
|
|
40
|
+
export function Ablo<const S extends SchemaRecord>(
|
|
41
|
+
options: PublicAbloOptions<S> & { readonly transport: 'websocket' },
|
|
42
|
+
): AbloWebSocketClient<S>;
|
|
43
|
+
export function Ablo<const S extends SchemaRecord>(
|
|
44
|
+
options: PublicAbloOptions<S> & {
|
|
45
|
+
readonly session: NonNullable<PublicAbloOptions<S>['session']>;
|
|
46
|
+
readonly transport?: undefined;
|
|
47
|
+
},
|
|
48
|
+
): AbloWebSocketClient<S>;
|
|
49
|
+
export function Ablo<const S extends SchemaRecord>(
|
|
50
|
+
options: PublicAbloOptions<S>,
|
|
51
|
+
): AbloHttpClient<S>;
|
|
42
52
|
export function Ablo<const S extends SchemaRecord>(
|
|
43
53
|
options: PublicAbloOptions<S>,
|
|
44
|
-
): AbloHttpClient<S> {
|
|
54
|
+
): AbloHttpClient<S> | AbloWebSocketClient<S> {
|
|
45
55
|
return createAbloHttpClient(options);
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
// ─────────────────────────────────────────────────────────────────────
|
|
49
|
-
// Ablo namespace — type access via namespace dots for
|
|
59
|
+
// Ablo namespace — type access via namespace dots for headless callers
|
|
50
60
|
// ─────────────────────────────────────────────────────────────────────
|
|
51
61
|
//
|
|
52
|
-
// The
|
|
62
|
+
// The headless subset of the type namespace the reactive package hangs off
|
|
53
63
|
// its own `Ablo` export: every entry a consumer of THIS client would write
|
|
54
64
|
// out (`Ablo.Activity`, `Ablo.Commit.Receipt`, and so on), and nothing that
|
|
55
65
|
// needs a store or a socket behind it. The
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared resource types for the typed clients and private HTTP transport.
|
|
3
|
-
* the commit and claim shapes,
|
|
3
|
+
* the commit and claim shapes, and the
|
|
4
4
|
* {@link HttpClaimApi} derivation. This module holds only types and has no runtime
|
|
5
5
|
* imports.
|
|
6
6
|
*/
|
|
@@ -38,15 +38,9 @@ import type { ModelTarget, ModelClaim } from '../../coordination/schema.js';
|
|
|
38
38
|
export type { ModelTarget, ModelClaim };
|
|
39
39
|
import type { ResolveClaimMeta } from '../../types/global.js';
|
|
40
40
|
import type { ParticipantKind } from '../../types/participant.js';
|
|
41
|
-
import type { SchemaRecord } from '../../schema/schema.js';
|
|
42
|
-
import type { SyncGroupInput } from '../../schema/roles.js';
|
|
43
41
|
// The capability vocabulary — `auth/capability.ts` owns what a grant is on both
|
|
44
42
|
// axes, and these params are the surface a developer declares it through.
|
|
45
|
-
import type {
|
|
46
|
-
CapabilityCan,
|
|
47
|
-
CapabilityOperation,
|
|
48
|
-
EffectiveAuthority,
|
|
49
|
-
} from '../../auth/capability.js';
|
|
43
|
+
import type { EffectiveAuthority } from '../../auth/capability.js';
|
|
50
44
|
import type {
|
|
51
45
|
Claim,
|
|
52
46
|
ClaimStream,
|
|
@@ -496,169 +490,3 @@ export interface HttpTransportModel<
|
|
|
496
490
|
*/
|
|
497
491
|
claim: HttpClaimApi<T, Fields>;
|
|
498
492
|
}
|
|
499
|
-
|
|
500
|
-
/** A single data operation a scoped **agent** session may perform on a model.
|
|
501
|
-
* The SDK-facing name for {@link CapabilityOperation}; the vocabulary itself is
|
|
502
|
-
* declared once, as a schema, in `auth/capability.ts`. */
|
|
503
|
-
export type SessionOperation = CapabilityOperation;
|
|
504
|
-
|
|
505
|
-
/** Parameters for minting an end-user session. Mints an `ek_` token.
|
|
506
|
-
* `user.id` is your end user's id from your
|
|
507
|
-
* own identity provider and becomes the session's `participantId`; Ablo does not
|
|
508
|
-
* model your users, so it is treated as an opaque string at the trust boundary. */
|
|
509
|
-
export interface CreateUserSessionParams<S extends SchemaRecord> {
|
|
510
|
-
/** Your end user. `id` becomes the token's `participantId`. */
|
|
511
|
-
user: { id: string };
|
|
512
|
-
/** Mint the session into this organization instead of the key's own — for a
|
|
513
|
-
* platform that serves many tenants from one backend. Requires the `sk_` key to
|
|
514
|
-
* carry the `organization:act-as` scope; omit it for the normal
|
|
515
|
-
* single-tenant case. */
|
|
516
|
-
organizationId?: string;
|
|
517
|
-
/** Resolve this session's schema from a shared project while its data stays
|
|
518
|
-
* scoped to `organizationId`. Cross-organization mints default to the
|
|
519
|
-
* platform key's own project, so most platforms can omit this. Specify it
|
|
520
|
-
* only to override that default. Requires `organization:act-as`. */
|
|
521
|
-
schemaProject?: {
|
|
522
|
-
organizationId: string;
|
|
523
|
-
projectId: string;
|
|
524
|
-
};
|
|
525
|
-
/** Sync groups this session may subscribe to — typed (`'default'` or
|
|
526
|
-
* `<namespace>:<id>`; build with `syncGroup(kind, id)` from
|
|
527
|
-
* `@abloatai/transaction/schema`). Omit for the server default:
|
|
528
|
-
* `[org:<your org>, user:<user.id>]`. */
|
|
529
|
-
syncGroups?: readonly SyncGroupInput[];
|
|
530
|
-
/** Required least-privilege grant. */
|
|
531
|
-
can: CapabilityCan<S>;
|
|
532
|
-
/** Token lifetime in seconds. Defaults to 900 (15 minutes). */
|
|
533
|
-
ttlSeconds?: number;
|
|
534
|
-
/** Opaque identity blob echoed back to the client as `ablo.user`. */
|
|
535
|
-
userMeta?: Record<string, unknown>;
|
|
536
|
-
agent?: never;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
/** Mint params for a scoped **agent** session — mints a restricted `rk_` token
|
|
540
|
-
* gated to exactly the operations named in `can`. `can` is typed off your
|
|
541
|
-
* schema (no magic `'item.update'` strings): `{ Item: ['update'], Report: ['read'] }`
|
|
542
|
-
* — the SDK serializes each entry to the wire allowlist (`item.update`). */
|
|
543
|
-
export interface CreateAgentSessionParams<S extends SchemaRecord> {
|
|
544
|
-
/** Your agent. `id` becomes the token's `participantId`. */
|
|
545
|
-
agent: { id: string };
|
|
546
|
-
/** The authenticated person who started this agent run. The backend holding
|
|
547
|
-
* the secret key attests this identity, and every resulting delta records
|
|
548
|
-
* the agent as actor plus this user as `onBehalfOf`. Persist the user id on
|
|
549
|
-
* durable work before enqueueing it so a later worker can supply it here. */
|
|
550
|
-
onBehalfOf?: { readonly user: { readonly id: string } };
|
|
551
|
-
/** Per-model operation allowlist, typed against the schema's model names. */
|
|
552
|
-
can: CapabilityCan<S>;
|
|
553
|
-
/** Sync groups this session may subscribe to — typed (`'default'` or
|
|
554
|
-
* `<namespace>:<id>`; build with `syncGroup(kind, id)` from
|
|
555
|
-
* `@abloatai/transaction/schema`). Omit for the server default: the org
|
|
556
|
-
* anchor (`org:<your org>`) + the agent's own anchor. */
|
|
557
|
-
syncGroups?: readonly SyncGroupInput[];
|
|
558
|
-
/** Token lifetime in seconds. Defaults to 900 (15 minutes). */
|
|
559
|
-
ttlSeconds?: number;
|
|
560
|
-
/** Opaque identity blob echoed back to the client as `ablo.agent`. */
|
|
561
|
-
userMeta?: Record<string, unknown>;
|
|
562
|
-
user?: never;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
/** Params for {@link Ablo.sessions}.create — a discriminated union: pass
|
|
566
|
-
* `{ user, can }` for an end-user session (`ek_`) or `{ agent, can }`
|
|
567
|
-
* for a scoped agent session (`rk_`). */
|
|
568
|
-
export type CreateSessionParams<S extends SchemaRecord> =
|
|
569
|
-
| CreateUserSessionParams<S>
|
|
570
|
-
| CreateAgentSessionParams<S>;
|
|
571
|
-
|
|
572
|
-
/** Params for {@link Ablo.agents}.create — a flattened agent descriptor (no
|
|
573
|
-
* `{ agent }` discriminator: `agents.create` only ever mints an agent). Unlike
|
|
574
|
-
* {@link CreateSessionParams} it resolves to a connected, scoped {@link Ablo}
|
|
575
|
-
* client rather than a raw token. */
|
|
576
|
-
export interface CreateAgentClientParams<S extends SchemaRecord> {
|
|
577
|
-
/** The wire participant identity (`agent:<id>`) that claim exclusion and the
|
|
578
|
-
* FIFO queue gate on. Omit it to get a fresh random id — a distinct, independent
|
|
579
|
-
* participant, which is the default and what you want for concurrent agents.
|
|
580
|
-
* Pass a stable string only when one logical agent must re-attach to its own
|
|
581
|
-
* held claims across reconnects or restarts. */
|
|
582
|
-
id?: string;
|
|
583
|
-
/** The authenticated person who started this run. Preserving it on durable
|
|
584
|
-
* work and supplying it here gives every write dual-principal attribution. */
|
|
585
|
-
onBehalfOf?: { readonly user: { readonly id: string } };
|
|
586
|
-
/** A human-readable label for logs and attribution (carried in `userMeta.name`).
|
|
587
|
-
* It is independent of `id`: two agents that share a `name` still receive
|
|
588
|
-
* distinct ids and coordinate as separate participants — `name` never derives or
|
|
589
|
-
* collapses identity. */
|
|
590
|
-
name?: string;
|
|
591
|
-
/** Per-model operation allowlist, typed against the schema's model names. */
|
|
592
|
-
can: CapabilityCan<S>;
|
|
593
|
-
/** Sync groups this agent may subscribe to — typed (`'default'` or
|
|
594
|
-
* `<namespace>:<id>`). Omit for the server default (org anchor + the
|
|
595
|
-
* agent's own anchor). */
|
|
596
|
-
syncGroups?: readonly SyncGroupInput[];
|
|
597
|
-
/** Token lifetime in seconds. Defaults to 900 (15 minutes); the returned client
|
|
598
|
-
* re-mints before expiry, so a long-running agent never handles rotation
|
|
599
|
-
* itself. */
|
|
600
|
-
ttlSeconds?: number;
|
|
601
|
-
/** Extra opaque identity blob echoed on the session scope. Merged with
|
|
602
|
-
* `name` (the `name` param wins if you also set `userMeta.name`). */
|
|
603
|
-
userMeta?: Record<string, unknown>;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
/** A minted session. `token` is the secret the holder presents as its bearer. */
|
|
607
|
-
export interface AbloSession {
|
|
608
|
-
object: 'session';
|
|
609
|
-
/** Stable id of the minted credential (for revocation). */
|
|
610
|
-
id: string;
|
|
611
|
-
/** The short-lived session token — `ek_` for a `{ user }` session, `rk_`
|
|
612
|
-
* for an `{ agent }` session. Hand this to the participant's runtime. */
|
|
613
|
-
token: string;
|
|
614
|
-
/** ISO-8601 expiry. */
|
|
615
|
-
expiresAt: string;
|
|
616
|
-
organizationId: string;
|
|
617
|
-
/** The grant this token carries, on both axes — the same shape the key row
|
|
618
|
-
* stores and the gates enforce. */
|
|
619
|
-
scope: EffectiveAuthority;
|
|
620
|
-
userMeta: Record<string, unknown>;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
/** Result of revoking a user or agent session. */
|
|
624
|
-
export interface SessionRevocation {
|
|
625
|
-
id: string;
|
|
626
|
-
deleted: true;
|
|
627
|
-
activeSessionsClosed: number;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
/** Rotation-with-overlap result for an agent session. */
|
|
631
|
-
export interface SessionRotation {
|
|
632
|
-
id: string;
|
|
633
|
-
token: string;
|
|
634
|
-
expiresAt: string | null;
|
|
635
|
-
organizationId: string;
|
|
636
|
-
scope: EffectiveAuthority;
|
|
637
|
-
rotatedFrom: {
|
|
638
|
-
id: string;
|
|
639
|
-
expiresAt: string;
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
export interface RevokeSessionParams {
|
|
644
|
-
id: string;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
export interface RotateSessionParams {
|
|
648
|
-
id: string;
|
|
649
|
-
/** How long the previous token remains valid. Defaults to 24 hours. */
|
|
650
|
-
graceSeconds?: number;
|
|
651
|
-
/** Optional lifetime for the replacement token. */
|
|
652
|
-
ttlSeconds?: number;
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
export interface SessionResource<S extends SchemaRecord> {
|
|
656
|
-
create(params: CreateSessionParams<S>): Promise<AbloSession>;
|
|
657
|
-
/** Immediately revoke an `ek_` or `rk_` session and close live connections. */
|
|
658
|
-
revoke(params: RevokeSessionParams): Promise<SessionRevocation>;
|
|
659
|
-
/**
|
|
660
|
-
* Rotate an agent `rk_` session with an overlap window. Browser `ek_`
|
|
661
|
-
* sessions rotate through their `authEndpoint` instead.
|
|
662
|
-
*/
|
|
663
|
-
rotate(params: RotateSessionParams): Promise<SessionRotation>;
|
|
664
|
-
}
|
|
@@ -623,13 +623,3 @@ export interface ModelDeleteParams<T, Fields = T>
|
|
|
623
623
|
readonly id: string;
|
|
624
624
|
readonly claim?: Claim<T> | ClaimTargetOptions<Fields> | null;
|
|
625
625
|
}
|
|
626
|
-
|
|
627
|
-
/** Options for the WebSocket-only `ablo.<model>.join(ids, options?)`. */
|
|
628
|
-
export interface JoinOptions {
|
|
629
|
-
/**
|
|
630
|
-
* Lease TTL for the underlying presence claim — the participant
|
|
631
|
-
* auto-releases after this if the holder dies. Compact duration string
|
|
632
|
-
* (`'5m'`) or ms number, mirroring the claim `ttl`.
|
|
633
|
-
*/
|
|
634
|
-
ttl?: Duration;
|
|
635
|
-
}
|
package/src/client/surface.ts
CHANGED
|
@@ -14,19 +14,17 @@ export type PublicAbloOptions<S extends SchemaRecord = SchemaRecord> = Omit<
|
|
|
14
14
|
AbloHttpClientOptions<S>,
|
|
15
15
|
'onCommitReceipt' | 'transport'
|
|
16
16
|
> & {
|
|
17
|
-
readonly transport?: 'http';
|
|
17
|
+
readonly transport?: 'http' | 'websocket';
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
export const PUBLIC_ABLO_OPTION_KEYS = [
|
|
21
21
|
'schema',
|
|
22
22
|
'apiKey',
|
|
23
|
-
'
|
|
23
|
+
'session',
|
|
24
24
|
'authToken',
|
|
25
25
|
'baseURL',
|
|
26
26
|
'dangerouslyAllowBrowser',
|
|
27
27
|
'fetch',
|
|
28
|
-
'authTimeoutMs',
|
|
29
|
-
'allowCrossOriginAuthEndpoint',
|
|
30
28
|
'bootstrapBaseUrl',
|
|
31
29
|
'defaultHeaders',
|
|
32
30
|
'defaultQuery',
|
|
@@ -36,6 +34,13 @@ export const PUBLIC_ABLO_OPTION_KEYS = [
|
|
|
36
34
|
'commitOutboxScope',
|
|
37
35
|
'transport',
|
|
38
36
|
'timeoutMs',
|
|
37
|
+
'groups',
|
|
38
|
+
'collaborationEvents',
|
|
39
|
+
'cursorStore',
|
|
40
|
+
'cursorKey',
|
|
41
|
+
'reconnectDelay',
|
|
42
|
+
'maxReconnectDelay',
|
|
43
|
+
'connectTimeoutMs',
|
|
39
44
|
] as const;
|
|
40
45
|
|
|
41
46
|
type Equal<A, B> =
|
|
@@ -21,8 +21,9 @@ interface WebSocketCommitObservation {
|
|
|
21
21
|
readonly operations: readonly {
|
|
22
22
|
readonly type: string;
|
|
23
23
|
readonly model: string;
|
|
24
|
-
readonly id: string;
|
|
25
|
-
readonly input?: Record<string, unknown
|
|
24
|
+
readonly id: string | null;
|
|
25
|
+
readonly input?: Record<string, unknown> | null;
|
|
26
|
+
readonly where?: Record<string, unknown> | null;
|
|
26
27
|
readonly claimId?: string | null;
|
|
27
28
|
readonly readAt?: number | null;
|
|
28
29
|
readonly fenceToken?: number | null;
|
|
@@ -149,6 +150,7 @@ export function recordWebSocketCommitReceipt(
|
|
|
149
150
|
model: operation.model,
|
|
150
151
|
id: operation.id,
|
|
151
152
|
...(operation.input ? { data: operation.input } : {}),
|
|
153
|
+
...(operation.where ? { where: operation.where } : {}),
|
|
152
154
|
...(operation.claimId ? { claimId: operation.claimId } : {}),
|
|
153
155
|
...(typeof operation.readAt === 'number' ? { readAt: operation.readAt } : {}),
|
|
154
156
|
...(typeof operation.fenceToken === 'number'
|
|
@@ -41,7 +41,6 @@ export {
|
|
|
41
41
|
claimQueuedSchema,
|
|
42
42
|
claimQueueSchema,
|
|
43
43
|
claimQueueEntrySchema,
|
|
44
|
-
claimExpiredSchema,
|
|
45
44
|
claimEventReasonSchema,
|
|
46
45
|
modelTargetSchema,
|
|
47
46
|
// The one claim record, and the peer-visible projection of it.
|
|
@@ -55,11 +54,8 @@ export {
|
|
|
55
54
|
claimHeartbeatAckPayloadSchema,
|
|
56
55
|
claimHeartbeatBatchPayloadSchema,
|
|
57
56
|
claimHeartbeatBatchAckPayloadSchema,
|
|
58
|
-
// Read interest — what a connection receives
|
|
59
|
-
// the frames behind `join`) and unleased (`update_subscription`).
|
|
57
|
+
// Read interest — what a connection receives.
|
|
60
58
|
MAX_FRAME_SYNC_GROUPS,
|
|
61
|
-
participantClaimPayloadSchema,
|
|
62
|
-
participantReleasePayloadSchema,
|
|
63
59
|
updateSubscriptionPayloadSchema,
|
|
64
60
|
subscriptionAckPayloadSchema,
|
|
65
61
|
// Commit operation — carries the optimistic write-guard
|
|
@@ -96,7 +92,6 @@ export type {
|
|
|
96
92
|
ClaimQueued,
|
|
97
93
|
ClaimQueue,
|
|
98
94
|
ClaimQueueEntry,
|
|
99
|
-
ClaimExpired,
|
|
100
95
|
ClaimEventReason,
|
|
101
96
|
ModelTarget,
|
|
102
97
|
ClaimRecord,
|
|
@@ -109,9 +104,7 @@ export type {
|
|
|
109
104
|
ClaimHeartbeatAckPayload,
|
|
110
105
|
ClaimHeartbeatBatchPayload,
|
|
111
106
|
ClaimHeartbeatBatchAckPayload,
|
|
112
|
-
// Read interest
|
|
113
|
-
ParticipantClaimPayload,
|
|
114
|
-
ParticipantReleasePayload,
|
|
107
|
+
// Read interest
|
|
115
108
|
UpdateSubscriptionPayload,
|
|
116
109
|
SubscriptionAckPayload,
|
|
117
110
|
// Commit operation — carries the optimistic write-guard
|