@abloatai/transaction 0.59.2 → 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/capability.d.ts +15 -15
- package/dist/auth/capabilityLifecycle.d.ts +3 -3
- 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/auth/credentialSource.js.map +1 -1
- package/dist/auth/identity.js.map +1 -1
- package/dist/auth/schemas.d.ts +5 -5
- package/dist/auth/sessionIssuanceProtocol.d.ts +8 -8
- package/dist/auth/sessionIssuanceProtocol.d.ts.map +1 -1
- package/dist/branches.d.ts +38 -38
- package/dist/claims/contract.d.ts +27 -27
- package/dist/claims/eventContract.d.ts +18 -18
- package/dist/claims/events.d.ts +1 -1
- package/dist/claims/events.d.ts.map +1 -1
- package/dist/claims/routes.d.ts +9 -9
- package/dist/claims/routes.d.ts.map +1 -1
- package/dist/claims/trace.d.ts.map +1 -1
- package/dist/claims/trace.js.map +1 -1
- package/dist/client/ablo.d.ts +11 -8
- package/dist/client/ablo.d.ts.map +1 -1
- package/dist/client/ablo.js +5 -6
- 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 +6 -15
- package/dist/client/resources/modelOperations.d.ts.map +1 -1
- package/dist/client/resources/where.d.ts +12 -12
- package/dist/client/surface.d.ts +1 -1
- package/dist/client/surface.d.ts.map +1 -1
- package/dist/client/surface.js +2 -4
- package/dist/client/surface.js.map +1 -1
- package/dist/commit/confirmation/commitEnvelope.d.ts +7 -7
- package/dist/commit/confirmation/httpCommitEnvelope.d.ts +1 -1
- package/dist/commit/confirmation/pendingWrite.d.ts +5 -5
- package/dist/commit/contract.d.ts +249 -249
- package/dist/commit/contract.d.ts.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 +57 -101
- 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/environment.d.ts +3 -3
- package/dist/environment.d.ts.map +1 -1
- package/dist/environment.js.map +1 -1
- package/dist/errorCodes.d.ts +4 -5
- package/dist/errorCodes.d.ts.map +1 -1
- package/dist/errorCodes.js +3 -8
- package/dist/errorCodes.js.map +1 -1
- package/dist/errorObservation.d.ts +14 -14
- package/dist/errors.d.ts +11 -11
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/keys/index.d.ts +1 -1
- package/dist/keys/index.d.ts.map +1 -1
- package/dist/keys/index.js.map +1 -1
- package/dist/observation/contract.d.ts +34 -34
- package/dist/observation/feedContract.d.ts +86 -86
- package/dist/observation/persistence/syncDeltaRow.d.ts +23 -23
- package/dist/observation/persistence/syncDeltaRow.d.ts.map +1 -1
- package/dist/pricing.d.ts +12 -12
- package/dist/schema/audit.js.map +1 -1
- package/dist/schema/ddl.js.map +1 -1
- package/dist/schema/ddlLock.js.map +1 -1
- package/dist/schema/deployment/contracts.d.ts +64 -64
- package/dist/schema/deployment/index.js.map +1 -1
- package/dist/schema/deployment/reconcile.js.map +1 -1
- package/dist/schema/diff.js.map +1 -1
- package/dist/schema/field.d.ts +1 -1
- package/dist/schema/field.d.ts.map +1 -1
- package/dist/schema/loadStrategy.d.ts +2 -2
- package/dist/schema/loadStrategy.d.ts.map +1 -1
- package/dist/schema/openapi.js.map +1 -1
- package/dist/schema/relation.d.ts +3 -3
- package/dist/schema/relation.d.ts.map +1 -1
- package/dist/schema/residency.d.ts +1 -1
- package/dist/schema/roles.d.ts +1 -1
- package/dist/schema/roles.d.ts.map +1 -1
- package/dist/schema/roles.js.map +1 -1
- package/dist/schema/schema.d.ts +1 -1
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/serialize.js.map +1 -1
- package/dist/schema/sugar.d.ts.map +1 -1
- package/dist/schema/tenancy.d.ts +2 -2
- package/dist/server/storageMode.d.ts +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/source/adapters/adapterProfile.d.ts +6 -6
- package/dist/source/adapters/conformance.js.map +1 -1
- package/dist/source/adapters/contract.d.ts +14 -14
- package/dist/source/adapters/kysely.js.map +1 -1
- package/dist/source/adapters/memory.js.map +1 -1
- package/dist/source/adapters/prisma.js.map +1 -1
- package/dist/source/connector/client.d.ts.map +1 -1
- package/dist/source/connector/client.js.map +1 -1
- package/dist/source/connector/protocol.d.ts.map +1 -1
- package/dist/source/delivery/pushQueue.d.ts.map +1 -1
- package/dist/source/delivery/pushQueue.js.map +1 -1
- package/dist/source/endpoint/signing.d.ts +4 -4
- package/dist/source/endpoint/signing.d.ts.map +1 -1
- package/dist/source/outbox/contract.d.ts +4 -4
- package/dist/testing/fixtures/httpResponses.d.ts +2 -2
- package/dist/testing/fixtures/httpResponses.d.ts.map +1 -1
- package/dist/testing/fixtures/httpResponses.js.map +1 -1
- 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/connection/manager.js.map +1 -1
- package/dist/transport/connection/networkProbe.d.ts +5 -18
- package/dist/transport/connection/networkProbe.d.ts.map +1 -1
- package/dist/transport/connection/networkProbe.js.map +1 -1
- package/dist/transport/http/client.d.ts +11 -19
- package/dist/transport/http/client.d.ts.map +1 -1
- package/dist/transport/http/client.js +12 -14
- 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 +4 -10
- package/dist/transport/http/transport.d.ts.map +1 -1
- package/dist/transport/http/transport.js +9 -51
- package/dist/transport/http/transport.js.map +1 -1
- package/dist/transport/websocket/commitFrames.d.ts +1 -2
- package/dist/transport/websocket/commitFrames.d.ts.map +1 -1
- package/dist/transport/websocket/commitFrames.js.map +1 -1
- 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/heartbeat.d.ts.map +1 -1
- package/dist/transport/websocket/heartbeat.js.map +1 -1
- package/dist/transport/websocket/session.d.ts.map +1 -1
- package/dist/transport/websocket/session.js +72 -32
- package/dist/transport/websocket/session.js.map +1 -1
- package/dist/transport/websocket/sessionContract.d.ts +3 -14
- package/dist/transport/websocket/sessionContract.d.ts.map +1 -1
- package/dist/transport/websocket/transport.d.ts +5 -42
- package/dist/transport/websocket/transport.d.ts.map +1 -1
- package/dist/transport/websocket/transport.js +14 -101
- package/dist/transport/websocket/transport.js.map +1 -1
- package/dist/wire/accountResponses.d.ts +31 -31
- package/dist/wire/auth.d.ts +3 -3
- package/dist/wire/bootstrapReason.d.ts +2 -2
- package/dist/wire/dataSourceResponses.d.ts +2 -2
- package/dist/wire/dataSourceResponses.d.ts.map +1 -1
- package/dist/wire/frames.d.ts +8 -8
- package/dist/wire/inboundFrames.d.ts +53 -63
- 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/dist/wire/listEnvelope.js.map +1 -1
- package/dist/wire/modelResponses.d.ts +2 -2
- package/dist/wire/modelShape.d.ts +4 -4
- package/dist/wire/pricing.d.ts +3 -3
- package/dist/wire/protocolVersion.d.ts.map +1 -1
- package/package.json +6 -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 +15 -10
- package/src/client/resources/httpResources.ts +2 -174
- package/src/client/resources/modelOperations.ts +0 -10
- package/src/client/surface.ts +2 -4
- package/src/coordination/index.ts +2 -9
- package/src/coordination/schema.ts +7 -81
- package/src/errorCodes.ts +3 -12
- 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 +21 -31
- package/src/transport/http/options.ts +4 -1
- package/src/transport/http/transport.ts +14 -74
- package/src/transport/websocket/commitFrames.ts +0 -2
- package/src/transport/websocket/frameHandlers.ts +0 -102
- package/src/transport/websocket/session.ts +88 -33
- package/src/transport/websocket/sessionContract.ts +3 -12
- package/src/transport/websocket/transport.ts +13 -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
|
@@ -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
|
*
|
|
@@ -35,12 +34,18 @@ import type * as _Http from './resources/httpResources.js';
|
|
|
35
34
|
/**
|
|
36
35
|
* Create a coordination-layer client in one call.
|
|
37
36
|
*
|
|
38
|
-
*
|
|
39
|
-
* without changing the model, commit, or claim
|
|
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.
|
|
40
39
|
*/
|
|
41
40
|
export function Ablo<const S extends SchemaRecord>(
|
|
42
41
|
options: PublicAbloOptions<S> & { readonly transport: 'websocket' },
|
|
43
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>;
|
|
44
49
|
export function Ablo<const S extends SchemaRecord>(
|
|
45
50
|
options: PublicAbloOptions<S>,
|
|
46
51
|
): AbloHttpClient<S>;
|
|
@@ -51,10 +56,10 @@ export function Ablo<const S extends SchemaRecord>(
|
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
// ─────────────────────────────────────────────────────────────────────
|
|
54
|
-
// Ablo namespace — type access via namespace dots for
|
|
59
|
+
// Ablo namespace — type access via namespace dots for headless callers
|
|
55
60
|
// ─────────────────────────────────────────────────────────────────────
|
|
56
61
|
//
|
|
57
|
-
// The
|
|
62
|
+
// The headless subset of the type namespace the reactive package hangs off
|
|
58
63
|
// its own `Ablo` export: every entry a consumer of THIS client would write
|
|
59
64
|
// out (`Ablo.Activity`, `Ablo.Commit.Receipt`, and so on), and nothing that
|
|
60
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
|
@@ -20,13 +20,11 @@ export type PublicAbloOptions<S extends SchemaRecord = SchemaRecord> = Omit<
|
|
|
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,7 +34,7 @@ export const PUBLIC_ABLO_OPTION_KEYS = [
|
|
|
36
34
|
'commitOutboxScope',
|
|
37
35
|
'transport',
|
|
38
36
|
'timeoutMs',
|
|
39
|
-
'
|
|
37
|
+
'groups',
|
|
40
38
|
'collaborationEvents',
|
|
41
39
|
'cursorStore',
|
|
42
40
|
'cursorKey',
|
|
@@ -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
|
|
@@ -467,8 +467,8 @@ export type ClaimError = z.infer<typeof claimErrorSchema>;
|
|
|
467
467
|
* frozen, and an older server may send a word not listed here. This is the
|
|
468
468
|
* reader's side of it: a value that parses becomes the typed reason, and one
|
|
469
469
|
* that does not is simply absent rather than smuggled through as prose.
|
|
470
|
-
* {@link
|
|
471
|
-
*
|
|
470
|
+
* {@link claimLostSchema} already spells its reasons as an enum; this brings
|
|
471
|
+
* the refusals into line.
|
|
472
472
|
*/
|
|
473
473
|
export const claimEventReasonSchema = z.enum([
|
|
474
474
|
'conflict',
|
|
@@ -644,17 +644,6 @@ export const claimQueueSchema = z.object({
|
|
|
644
644
|
});
|
|
645
645
|
export type ClaimQueue = z.infer<typeof claimQueueSchema>;
|
|
646
646
|
|
|
647
|
-
/**
|
|
648
|
-
* A held claim's TTL lapsed server-side. The claim is already inactive by the
|
|
649
|
-
* time this arrives, so a consumer either re-claims with a fresh credential or
|
|
650
|
-
* accepts the drop; there is nothing to release.
|
|
651
|
-
*/
|
|
652
|
-
export const claimExpiredSchema = z.object({
|
|
653
|
-
claimId: z.string(),
|
|
654
|
-
});
|
|
655
|
-
export type ClaimExpired = z.infer<typeof claimExpiredSchema>;
|
|
656
|
-
|
|
657
|
-
|
|
658
647
|
/**
|
|
659
648
|
* The two states a claim can be observed in while it still exists.
|
|
660
649
|
*
|
|
@@ -981,20 +970,9 @@ export type ClaimHeartbeatBatchAckPayload = z.infer<
|
|
|
981
970
|
// ─────────────────────────────────────────────────────────────────────────
|
|
982
971
|
// Read interest — what a connection receives
|
|
983
972
|
//
|
|
984
|
-
//
|
|
985
|
-
//
|
|
986
|
-
//
|
|
987
|
-
// • `claim` — a PARTICIPANT claim. Adds a scope under a handle, with a
|
|
988
|
-
// TTL and an optional capability token, and announces the sender into
|
|
989
|
-
// that scope's roster. This is the frame `ablo.<model>.join(...)` sends;
|
|
990
|
-
// `release` drops it. Several may be open on one connection at once.
|
|
991
|
-
// • `update_subscription` — REPLACES the connection's whole read set. No
|
|
992
|
-
// handle, no lease, no roster entry.
|
|
993
|
-
//
|
|
994
|
-
// Both are bounded by the connection credential's grant, and both name their
|
|
995
|
-
// groups the same way, so both parse their `syncGroups` through the same
|
|
996
|
-
// element schema. Neither is the row lease — that is `claim_begin`, in the
|
|
997
|
-
// pessimistic-claims block above, which shares only a word.
|
|
973
|
+
// `update_subscription` replaces the connection's whole read set. It is
|
|
974
|
+
// bounded by the connection credential's grant and is not a row lease;
|
|
975
|
+
// row leases use `claim_begin` in the pessimistic-claims block above.
|
|
998
976
|
// ─────────────────────────────────────────────────────────────────────────
|
|
999
977
|
|
|
1000
978
|
/**
|
|
@@ -1012,67 +990,15 @@ export const MAX_FRAME_SYNC_GROUPS = 200;
|
|
|
1012
990
|
* that does not parse matches nothing, and subscribing to nothing quietly is
|
|
1013
991
|
* the failure this element type exists to prevent.
|
|
1014
992
|
*
|
|
1015
|
-
* Strict because this is untrusted client input
|
|
1016
|
-
* frames below carry the same value: when they disagreed, `claim` accepted a
|
|
1017
|
-
* malformed group that `update_subscription` refused, and the connection
|
|
1018
|
-
* ended up leased to a scope it could never receive.
|
|
993
|
+
* Strict because this is untrusted client input.
|
|
1019
994
|
*/
|
|
1020
995
|
const frameSyncGroupsSchema = z
|
|
1021
996
|
.array(syncGroupInputSchema)
|
|
1022
997
|
.max(MAX_FRAME_SYNC_GROUPS);
|
|
1023
998
|
|
|
1024
|
-
/**
|
|
1025
|
-
* The `claim` payload a client sends — the frame behind `join`.
|
|
1026
|
-
*
|
|
1027
|
-
* It opens one participant claim: the connection is added to each named
|
|
1028
|
-
* scope's fan-out under `claimId`, announced into its presence roster, and
|
|
1029
|
-
* holds that interest until `release`, the TTL lapses, or the socket closes.
|
|
1030
|
-
* The handle is client-chosen because the client must be able to `release`
|
|
1031
|
-
* the exact claim it opened while others stay open.
|
|
1032
|
-
*
|
|
1033
|
-
* This shape was, for a long time, written three times — built as a literal in
|
|
1034
|
-
* the transport, restated as an interface on the server, and read back through
|
|
1035
|
-
* a cast in the frame handler — which is how the frame came to be the only
|
|
1036
|
-
* coordination message with no runtime check on the way in.
|
|
1037
|
-
*/
|
|
1038
|
-
export const participantClaimPayloadSchema = z.object({
|
|
1039
|
-
/** Client-chosen handle. Echoed on `claim_ack`; names the claim to `release`. */
|
|
1040
|
-
claimId: z.string().min(1),
|
|
1041
|
-
syncGroups: frameSyncGroupsSchema,
|
|
1042
|
-
/**
|
|
1043
|
-
* A narrower capability to present for this claim than the connection's own.
|
|
1044
|
-
* Absent means the connection's credential governs it.
|
|
1045
|
-
*/
|
|
1046
|
-
capabilityToken: z.string().optional(),
|
|
1047
|
-
/**
|
|
1048
|
-
* Crash cleanup, in seconds. The server caps it at the capability's own TTL;
|
|
1049
|
-
* absent means the claim lives until `release` or disconnect.
|
|
1050
|
-
*/
|
|
1051
|
-
ttlSeconds: z.number().optional(),
|
|
1052
|
-
});
|
|
1053
|
-
export type ParticipantClaimPayload = z.infer<
|
|
1054
|
-
typeof participantClaimPayloadSchema
|
|
1055
|
-
>;
|
|
1056
|
-
|
|
1057
|
-
/**
|
|
1058
|
-
* The `release` payload — drop one participant claim by its handle.
|
|
1059
|
-
*
|
|
1060
|
-
* A projection of the claim it releases rather than a second object, so the
|
|
1061
|
-
* handle cannot be spelled one way when opened and another when dropped.
|
|
1062
|
-
* Idempotent by contract: the server accepts an unknown handle silently, so a
|
|
1063
|
-
* client releasing everything at shutdown never has to check what is still open.
|
|
1064
|
-
*/
|
|
1065
|
-
export const participantReleasePayloadSchema =
|
|
1066
|
-
participantClaimPayloadSchema.pick({ claimId: true });
|
|
1067
|
-
export type ParticipantReleasePayload = z.infer<
|
|
1068
|
-
typeof participantReleasePayloadSchema
|
|
1069
|
-
>;
|
|
1070
|
-
|
|
1071
999
|
/**
|
|
1072
1000
|
* The `update_subscription` payload a client sends. It replaces the
|
|
1073
|
-
* connection's read interest with the complete set of sync groups
|
|
1074
|
-
* unleased counterpart to {@link participantClaimPayloadSchema}, with no
|
|
1075
|
-
* handle, no TTL, and no roster entry.
|
|
1001
|
+
* connection's read interest with the complete set of sync groups.
|
|
1076
1002
|
*/
|
|
1077
1003
|
export const updateSubscriptionPayloadSchema = z.object({
|
|
1078
1004
|
syncGroups: frameSyncGroupsSchema,
|
package/src/errorCodes.ts
CHANGED
|
@@ -511,17 +511,13 @@ export const ERROR_CODES = {
|
|
|
511
511
|
// A claim payload that cannot be parsed is a malformed request, not
|
|
512
512
|
// contention — it is filed with `malformed_subscription` below rather than
|
|
513
513
|
// with the 409s above, so the claim category stays purely about a target
|
|
514
|
-
// being held. This is the code for a claim that fails to name its target,
|
|
515
|
-
// over either transport
|
|
516
|
-
// names scopes rather than a row but fails the same way and to the same
|
|
517
|
-
// caller. The copy covers both because the caller sees one word, `claim`, and
|
|
518
|
-
// needs to be told which shape was expected without being handed a lecture on
|
|
519
|
-
// the two frames.
|
|
514
|
+
// being held. This is the code for a row claim that fails to name its target,
|
|
515
|
+
// over either transport.
|
|
520
516
|
malformed_claim: wire(
|
|
521
517
|
'validation',
|
|
522
518
|
400,
|
|
523
519
|
false,
|
|
524
|
-
'The claim payload could not be parsed. A claim
|
|
520
|
+
'The claim payload could not be parsed. A row claim must name the model and entity it targets. Check the payload shape and resend.'
|
|
525
521
|
),
|
|
526
522
|
malformed_subscription: wire(
|
|
527
523
|
'validation',
|
|
@@ -558,11 +554,6 @@ export const ERROR_CODES = {
|
|
|
558
554
|
'claim',
|
|
559
555
|
'Claiming is unavailable on this model client. Construct it through the standard Ablo({ schema, apiKey }) client and retry.'
|
|
560
556
|
),
|
|
561
|
-
model_join_not_configured: client(
|
|
562
|
-
'claim',
|
|
563
|
-
'join() opens a presence/claim subscription and needs a live WebSocket, so it is unavailable on the HTTP transport and on model proxies built without a socket. Use the standard Ablo({ schema, apiKey }) client (default WebSocket transport).'
|
|
564
|
-
),
|
|
565
|
-
|
|
566
557
|
// ── stale context / idempotency (409) ──────────────────────────────
|
|
567
558
|
// Not retryable at the transport: the rejected request carries its frozen
|
|
568
559
|
// `readAt`, so resending the identical payload can never succeed. Recovery
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side session issuer.
|
|
3
|
+
*
|
|
4
|
+
* This is deliberately separate from `Ablo(...)`: the participant client owns
|
|
5
|
+
* schema model properties, while this client owns credential issuance and
|
|
6
|
+
* lifecycle administration. A schema model named `sessions` therefore remains
|
|
7
|
+
* available as `ablo.sessions` like every other model.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { CredentialProvider } from '../auth/credentialResult.js';
|
|
11
|
+
import {
|
|
12
|
+
assertBrowserSafety,
|
|
13
|
+
readProcessEnv,
|
|
14
|
+
rejectRemovedDatabaseUrlOption,
|
|
15
|
+
resolveApiKey,
|
|
16
|
+
resolveApiKeyValue,
|
|
17
|
+
resolveBaseURL,
|
|
18
|
+
resolveBootstrapBaseUrl,
|
|
19
|
+
warnIfCliKeyMismatch,
|
|
20
|
+
} from '../auth/apiKey.js';
|
|
21
|
+
import { modelWireNames } from '../auth/capability.js';
|
|
22
|
+
import {
|
|
23
|
+
revokeCapability,
|
|
24
|
+
rotateCapability,
|
|
25
|
+
} from '../auth/capabilityLifecycle.js';
|
|
26
|
+
import { AbloAuthenticationError } from '../errors.js';
|
|
27
|
+
import type { Schema, SchemaRecord } from '../schema/schema.js';
|
|
28
|
+
import type {
|
|
29
|
+
AbloSession,
|
|
30
|
+
CreateSessionParams,
|
|
31
|
+
RevokeSessionParams,
|
|
32
|
+
RotateSessionParams,
|
|
33
|
+
SessionRevocation,
|
|
34
|
+
SessionRotation,
|
|
35
|
+
} from './contract.js';
|
|
36
|
+
import { createSession } from './create.js';
|
|
37
|
+
import {
|
|
38
|
+
createSessionHandler,
|
|
39
|
+
type SessionHandler,
|
|
40
|
+
type SessionHandlerOptions,
|
|
41
|
+
} from './handler.js';
|
|
42
|
+
|
|
43
|
+
export interface SessionsOptions<S extends SchemaRecord> {
|
|
44
|
+
readonly schema: Schema<S>;
|
|
45
|
+
readonly apiKey?: string | CredentialProvider | null;
|
|
46
|
+
readonly baseURL?: string | null;
|
|
47
|
+
readonly bootstrapBaseUrl?: string;
|
|
48
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
49
|
+
readonly dangerouslyAllowBrowser?: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface SessionsClient<S extends SchemaRecord> {
|
|
53
|
+
create(params: CreateSessionParams<S>): Promise<AbloSession>;
|
|
54
|
+
handler<Principal>(options: SessionHandlerOptions<S, Principal>): SessionHandler;
|
|
55
|
+
revoke(params: RevokeSessionParams): Promise<SessionRevocation>;
|
|
56
|
+
rotate(params: RotateSessionParams): Promise<SessionRotation>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Construct the server-side issuer for user and agent sessions. */
|
|
60
|
+
export function Sessions<const S extends SchemaRecord>(
|
|
61
|
+
options: SessionsOptions<S>,
|
|
62
|
+
): SessionsClient<S> {
|
|
63
|
+
const env = readProcessEnv();
|
|
64
|
+
const authInput = { options, env };
|
|
65
|
+
const configuredApiKey = resolveApiKey(authInput);
|
|
66
|
+
void warnIfCliKeyMismatch(authInput);
|
|
67
|
+
rejectRemovedDatabaseUrlOption(options);
|
|
68
|
+
assertBrowserSafety({
|
|
69
|
+
apiKey: configuredApiKey,
|
|
70
|
+
dangerouslyAllowBrowser: options.dangerouslyAllowBrowser,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const baseUrl = resolveBootstrapBaseUrl({
|
|
74
|
+
url: resolveBaseURL(authInput),
|
|
75
|
+
bootstrapBaseUrl: options.bootstrapBaseUrl,
|
|
76
|
+
}).replace(/\/+$/, '');
|
|
77
|
+
const modelTypenames = modelWireNames(options.schema.models);
|
|
78
|
+
|
|
79
|
+
async function secret(): Promise<string> {
|
|
80
|
+
const apiKey = await resolveApiKeyValue(configuredApiKey);
|
|
81
|
+
if (!apiKey) {
|
|
82
|
+
throw new AbloAuthenticationError(
|
|
83
|
+
'Sessions requires a secret (sk_) API key and must be constructed on the backend.',
|
|
84
|
+
{ code: 'apikey_missing' },
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
return apiKey;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function create(params: CreateSessionParams<S>): Promise<AbloSession> {
|
|
91
|
+
return createSession(params, {
|
|
92
|
+
apiKey: await secret(),
|
|
93
|
+
baseUrl,
|
|
94
|
+
modelTypenames,
|
|
95
|
+
...(options.fetch ? { fetch: options.fetch } : {}),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
create,
|
|
101
|
+
handler: (handlerOptions) => createSessionHandler(create, handlerOptions),
|
|
102
|
+
async revoke({ id }) {
|
|
103
|
+
return revokeCapability({
|
|
104
|
+
apiKey: await secret(),
|
|
105
|
+
baseUrl,
|
|
106
|
+
id,
|
|
107
|
+
...(options.fetch ? { fetch: options.fetch } : {}),
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
async rotate({ id, graceSeconds, ttlSeconds }) {
|
|
111
|
+
return rotateCapability({
|
|
112
|
+
apiKey: await secret(),
|
|
113
|
+
baseUrl,
|
|
114
|
+
id,
|
|
115
|
+
...(graceSeconds !== undefined ? { graceSeconds } : {}),
|
|
116
|
+
...(ttlSeconds !== undefined ? { ttlSeconds } : {}),
|
|
117
|
+
...(options.fetch ? { fetch: options.fetch } : {}),
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|