/** * `operator.session` — the hosted/browser control-plane **session** surface * (gateway v1.78 `passkey-principals-onboarding`). The write-capable human * principal: log in (email magic-link / passkey / Google / GitHub), manage the * session (whoami / refresh / revoke), enrol a passkey, run a step-up ceremony, * and manage authenticators + recovery codes. * * Reached as `r.operator.session.*`. Distinct from the read-only operator * overview session (`r.operator.deviceStart`/`overview`) and from the CLI * loopback-PKCE write-login (`r.operator.buildCliAuthorizeUrl`/`exchangeCliToken`, * which is the headless variant of this same browser ceremony). All three are * the one human principal; this group is the browser/console front door that the * hosted login pages and `@run402/sdk` consumers call. * * Isomorphic — no Node APIs. The token model mirrors {@link Operator.overview}: * the public *mint* methods (`email`/`verifyEmail`/`passkey*`/`consumeRecoveryCode`) * send no auth (the body or the magic-link token IS the credential); the * *session-bound* methods take `opts.token` to send the `control_plane_session` * bearer explicitly, and fall back to the credential provider's default auth * (e.g. {@link controlPlaneSessionCredentials} or a SIWX wallet) when omitted. * * WebAuthn option/assertion payloads are opaque passthroughs (`unknown`) — the * browser runs the actual ceremony; a headless client cannot. * * High-stakes writes (invite, membership, handoff, delete) require a **fresh * passkey** — a magic-link/OAuth session does NOT satisfy step-up, so the * gateway returns {@link StepUpRequiredError}; `stepUpOptions`/`stepUpVerify` * are how a long-lived session re-establishes that freshness. */ import type { Client } from "../kernel.js"; import type { ControlPlaneSession } from "./operator.js"; import type { Principal, OrgMembership } from "./org.types.js"; /** OAuth identity providers bridged for control-plane login. */ export type ControlPlaneOAuthProvider = "google" | "github"; /** Generic, non-enumerating response from {@link OperatorSession.email}. */ export interface MagicLinkSendResult { status: string; message: string; [key: string]: unknown; } /** * Result of {@link OperatorSession.consumeRecoveryCode} — a minted session that * cannot perform high-stakes ops until a passkey is enrolled * (`must_enroll_passkey: true`). Recovery `amr` never satisfies step-up. */ export interface RecoveryConsumeResult extends ControlPlaneSession { must_enroll_passkey?: boolean; note?: string; } /** * Result of {@link OperatorSession.whoami} (`GET /agent/v1/control-plane/session`) * — the live session's principal, every org membership (newly-active rows here * are the auto-claimed invites), and the freshness substrate (`amr` + per-AMR * `amr_times`) the step-up gate reads. Forward-compatible. */ export interface ControlPlaneWhoAmI { principal: Principal; memberships: OrgMembership[]; /** Auth methods satisfied on this session, e.g. `["passkey"]`. */ amr: string[]; /** Per-AMR last-proven time (epoch ms or ISO), the step-up freshness source. */ amr_times?: Record; [key: string]: unknown; } /** Result of {@link OperatorSession.refresh} (`POST …/session/refresh`). */ export interface ControlPlaneRefreshResult { control_plane_session_token: string; token_type?: string; expires_in?: number; [key: string]: unknown; } /** WebAuthn options envelope (`{ options }`) — opaque; handed to the browser. */ export interface WebAuthnOptionsResult { options: unknown; [key: string]: unknown; } /** Result of {@link OperatorSession.enrollPasskeyVerify}. */ export interface EnrollPasskeyResult { status: string; credential_id: string; [key: string]: unknown; } /** Result of {@link OperatorSession.stepUpVerify}. */ export interface StepUpVerifyResult { status: string; stepped_up: boolean; [key: string]: unknown; } /** Result of {@link OperatorSession.issueRecoveryCodes} — shown ONCE. */ export interface RecoveryCodesResult { status: string; recovery_codes: string[]; note?: string; [key: string]: unknown; } /** One active authenticator (no secret material). Forward-compatible. */ export interface Authenticator { id: string; kind: string; /** Provider-side subject hint (e.g. masked email / credential label); absent when unset. */ subject_hint?: string; /** ISO-8601 enrollment time. */ added_at?: string; /** ISO-8601 last-use time; absent when never used. */ last_used_at?: string; [key: string]: unknown; } /** Result of {@link OperatorSession.revokeAuthenticator}. */ export interface AuthenticatorRevokeResult { status: string; kind: string; [key: string]: unknown; } /** Options bag carrying the optional `control_plane_session` bearer. */ export interface SessionTokenOpts { /** * The `control_plane_session` bearer. When omitted, the request falls back to * the credential provider's default auth (e.g. {@link controlPlaneSessionCredentials}). */ token?: string; } export declare class OperatorSession { private readonly client; constructor(client: Client); /** * Send a control-plane sign-in magic link to `email` * (`POST /agent/v1/control-plane/session/email`). Non-enumerating: an * identical response whether or not the email can sign in. Rate-limited. */ email(input: { email: string; }): Promise; /** * Exchange a magic-link token for a control-plane session * (`POST …/session/email/verify`). Verifies the email, resolves/creates the * principal, **auto-claims any pending invites**, and mints the session * (`amr: ["email"]`). */ verifyEmail(input: { token: string; }): Promise; /** * Get WebAuthn login options for an email's passkeys * (`POST …/session/passkey/options`). Opaque — pass `options` to the browser's * `navigator.credentials.get`. */ passkeyOptions(input: { email: string; }): Promise; /** * Verify a WebAuthn assertion and mint a session (`amr: ["passkey"]`) * (`POST …/session/passkey/verify`). `response` is the opaque assertion from * the browser. */ passkeyVerify(input: { email: string; response: unknown; }): Promise; /** * Build the browser OAuth start URL for `provider` * (`GET …/oauth/:provider/start`). Pure — no network. Open it in a browser; * the gateway 302s to the provider, then the callback lands on the console * with the session token in the URL fragment. * * Note: the live bridge can return `503` until the gateway provisions the * provider's `CONTROL_PLANE_{GOOGLE,GITHUB}_*` client credentials. */ oauthUrl(provider: ControlPlaneOAuthProvider): string; /** * Run the recovery-code ceremony (`POST …/recovery/consume`). Mints a session * with `amr: ["recovery_code"]` which **cannot** do high-stakes ops * (`must_enroll_passkey: true`) — enrol a passkey to restore full access. */ consumeRecoveryCode(input: { code: string; }): Promise; /** * Resolve the current session's principal + memberships + freshness * (`GET /agent/v1/control-plane/session`). The `memberships` reflect any * invites auto-claimed at login. */ whoami(opts?: SessionTokenOpts): Promise; /** Rotate the access token (`POST …/session/refresh`). */ refresh(opts?: SessionTokenOpts): Promise; /** Sign out — revoke the session server-side (`POST …/session/revoke`). Idempotent. */ revoke(opts?: SessionTokenOpts): Promise<{ status: string; [key: string]: unknown; }>; /** WebAuthn registration options for a new passkey (`POST …/passkey/enroll/options`). */ enrollPasskeyOptions(opts?: SessionTokenOpts): Promise; /** Verify a passkey registration (`POST …/passkey/enroll/verify`). `label` names the authenticator. */ enrollPasskeyVerify(input: { response: unknown; label?: string | null; } & SessionTokenOpts): Promise; /** * WebAuthn step-up options for a high-stakes op (`POST …/step-up/options`). * `opClass` binds the elevation, e.g. `"org.invite"` / `"org.membership"` / * `"project.transfer"` (see {@link StepUpRequiredError.requiredAmr}). */ stepUpOptions(input?: { opClass?: string; } & SessionTokenOpts): Promise; /** * Verify a step-up assertion (`POST …/step-up/verify`) → refreshes session * passkey-freshness and records an action-bound elevation when `opClass` (and * optionally `objectKind`/`objectId`) are given. Retry the gated write after. */ stepUpVerify(input: { response: unknown; opClass?: string; objectKind?: string | null; objectId?: string | null; } & SessionTokenOpts): Promise; /** (Re)issue recovery codes — shown ONCE (`POST …/recovery/issue`). */ issueRecoveryCodes(opts?: SessionTokenOpts): Promise; /** List my active authenticators — no secret material (`GET …/authenticators`). */ listAuthenticators(opts?: SessionTokenOpts): Promise; /** * Revoke an authenticator (`DELETE …/authenticators/:id`). Step-up enforced; * the gateway refuses to remove the last passkey of a sole org owner * (`OWNER_NEEDS_PASSKEY`). */ revokeAuthenticator(input: { id: string; } & SessionTokenOpts): Promise; /** * My own source-access key + wrapper set, ciphertext included * (`GET /agent/v1/source-access/wrappers`) — the states/scheme read behind * `run402 source-access status`. Principal-scoped structurally: only the * caller's own wrappers ever come back. Enrollment/activation/revocation * are console ceremonies (WebAuthn); this SDK surface is read-only. */ sourceAccessWrappers(opts?: SessionTokenOpts): Promise; /** * Export my versioned member recovery bundle * (`GET /agent/v1/source-access/recovery-bundle`, format * `r402s-member-recovery-bundle/v1`) — key identity + every ACTIVE wrapper * ciphertext. A server-side wrapper row alone is NOT offline backup; this * bundle kept in the member's own storage (separately from the source * recovery code) is what `r402s-recover` opens with no run402 server. The * gateway stamps the export as recovery-posture evidence. */ sourceAccessRecoveryBundle(opts?: SessionTokenOpts): Promise; } /** One wrapper row as `GET /agent/v1/source-access/wrappers` returns it. */ export interface SourceAccessWrapper { wrapper_id: string; encryption_key_id: string; kind: "webauthn_prf" | "recovery_code"; state: "pending" | "active" | "revoked"; format_version: string; credential_subject: string | null; wrapper_ciphertext: string; blob_sha256: string; created_at: string; activated_at: string | null; } export interface SourceAccessWrappersResult { principal_id: string; /** Null when the principal has never enrolled a source-access key. */ encryption_key: { encryption_key_id: string; ek_fingerprint: string; public_key: string; suite: string; custody_scheme: string; state: string; created_at: string; } | null; wrappers: SourceAccessWrapper[]; } /** `r402s-member-recovery-bundle/v1` exactly as the gateway returns it (see the node-side `GitvaultMemberRecoveryBundle` for the recover-input twin). */ export interface SourceAccessRecoveryBundleResult { format: "r402s-member-recovery-bundle/v1"; exported_at: string; principal_id: string; encryption_key_id: string; ek_fingerprint: string; public_key: string; suite: string; custody_scheme: string; wrappers: Array>; note: string; } //# sourceMappingURL=operator-session.d.ts.map