/** * `writeApproval` — the passkey-signed, target-scoped credential a person * signed in on the command line needs to provision, deploy, or write secrets * without a wallet. Reached as `r.writeApproval.*`. * * The ceremony: {@link WriteApproval.requestChallenge} opens a passkey approval * scoped to one `(action, target)` and returns a same-origin `confirm_url`; the * person approves with their passkey in the browser; the confirm page redirects * to the CLI's `127.0.0.1` loopback with a one-time `code`; * {@link WriteApproval.exchangeClaimCode} (PKCE) mints the token. The token is * sent as `X-Run402-Write-Approval: Bearer ` beside the * sign-in session bearer, and dies with that session. A write approval never * satisfies step-up. * * Isomorphic seams — the loopback server and PKCE generation live in the Node * CLI (`run402 approve`). */ import type { Client } from "../kernel.js"; import type { WriteApprovalCapability } from "../credentials.js"; /** Input to {@link WriteApproval.requestChallenge}. */ export interface WriteApprovalChallengeInput { /** The capability to approve. Determines whether `orgId` or `projectId` is required. */ action: WriteApprovalCapability; /** Required for `org.project.create`. */ orgId?: string; /** Required for the project-scoped capabilities (`project.deploy`, `project.secret.write`, …). */ projectId?: string; /** The CLI's loopback redirect, e.g. `http://127.0.0.1:54321/callback`. */ cliRedirectUri: string; /** PKCE S256 challenge = base64url(sha256(verifier)). */ codeChallenge: string; /** Opaque CSRF state echoed back on the loopback redirect. */ state: string; /** * The sign-in session bearer. Falls back to the client's default auth when * omitted — pass it explicitly unless the client was constructed with * sign-in session credentials. */ token?: string; } /** Result of {@link WriteApproval.requestChallenge}. Forward-compatible. */ export interface WriteApprovalChallengeResult { challenge_id: string; confirm_url: string; expires_at?: string; action?: string; org_id?: string | null; project_id?: string | null; delivery?: "cli_loopback" | "postmessage" | (string & {}); [key: string]: unknown; } /** Input to {@link WriteApproval.exchangeClaimCode}. */ export interface WriteApprovalClaimInput { /** Authorization code received on the loopback redirect. */ code: string; /** The PKCE verifier whose hash was sent as `codeChallenge`. */ codeVerifier: string; /** Must match the `state` used at challenge time. */ state: string; } /** One write approval's metadata as the gateway reports it (never the token). */ export interface WriteApprovalSessionInfo { write_approval_session_id: string; authenticator_class?: string; org_id?: string | null; project_id?: string | null; capabilities?: string[]; risk_ceiling?: string; /** ISO-8601 idle expiry — the token's usable life. */ idle_expires_at?: string; /** ISO-8601 absolute expiry. */ absolute_expires_at?: string; [key: string]: unknown; } /** Minted write-approval token payload, returned ONCE. Forward-compatible. */ export interface WriteApprovalTokenResult { write_approval_token: string; /** Always `"write_approval"`. */ token_type?: string; /** Always `"X-Run402-Write-Approval"`. */ header?: string; session?: WriteApprovalSessionInfo | null; [key: string]: unknown; } export declare class WriteApproval { private readonly client; constructor(client: Client); /** * Open a scoped approval (`POST /agent/v1/control-plane/write-approval/challenges`). * Carries the sign-in session bearer; a `device`-grade session is refused. */ requestChallenge(input: WriteApprovalChallengeInput): Promise; /** * Exchange the loopback claim `code` (+ PKCE verifier + `state`) for the * write-approval token (`POST …/write-approval/cli/token`). No `redirect_uri` * — it is bound at challenge time. Unauthenticated (code + verifier are the * credential); the minted token is still bound to the issuing sign-in session. */ exchangeClaimCode(input: WriteApprovalClaimInput): Promise; } //# sourceMappingURL=write-approval.d.ts.map