/** * Error hierarchy for the Run402 SDK. Every failure throws a subclass of * {@link Run402Error}. Consumers (MCP handlers, CLI commands, user functions) * translate these into their native error shapes at the edge. * * Branch on {@link Run402Error.kind} (or the exported `is*` type guards) rather * than `instanceof`. Discriminator-based checks survive duplicate SDK installs, * bundler chunk splits, ESM/CJS interop, and V8-isolate realm boundaries — * any setting where a class object's identity might differ from the consumer's * own class object reference. `instanceof X` continues to work for callers * holding a single SDK copy (back-compat); the guards are the recommended path. */ /** * Stable string discriminator on every {@link Run402Error} subclass. Use this * (or the exported `is*` guards) to branch on errors safely across SDK copies * and realms — value comparison, no class-identity dependency. */ export type Run402ErrorKind = "payment_required" | "project_not_found" | "unauthorized" | "not_authorized" | "api_error" | "network_error" | "payment_attempt_error" | "payment_buyer_error" | "local_error" | "deploy_error" | "transfer_freeze" | "step_up_required" | "operator_approval_required"; /** * Quota-denial scope discriminator (v1.46+). Indicates whether a quota-related * denial was enforced against the pooled organization total (`"organization"`) * or against an orphan project whose organization row has been purged but * cascade has not yet run (`"project"`). Lifted from `details.scope` on the * gateway envelope; absent for errors unrelated to quota. */ export type Run402QuotaScope = "organization" | "project"; export declare abstract class Run402Error extends Error { /** * Structural brand. Always `true` on any {@link Run402Error} subclass * instance, regardless of which SDK copy created it. The exported * {@link isRun402Error} guard checks this field instead of `instanceof`, * so cross-realm and cross-bundle errors still match. */ readonly isRun402Error: true; /** * Stable string discriminator. Branch on `e.kind === "..."` (or the * exported subclass guards) rather than `e instanceof X`. Equality on * `kind` survives duplicate SDK copies and cross-realm errors. */ abstract readonly kind: Run402ErrorKind; /** HTTP status, or null for local/network failures that produced no response. */ readonly status: number | null; /** * Parsed response body, or null when no body was received. Holds the raw * gateway envelope, so additive fields not lifted onto typed properties stay * reachable here — notably `correlated_platform_incident` * (`{ id, subsystem, status: "ongoing" | "resolved" }`), present ONLY while * an OPEN platform incident correlates with this error's `code` (a `poll` * action also rides in {@link nextActions}). It is a CORRELATION, not an * exoneration: the platform states it was degraded when the call failed and * leaves the judgment to you. Treat it as a strong signal to poll the events * feed (`r.events.list`) before debugging your own code; the follow-up * `platform_incident` feed event carries the project's real failed-invocation * count once the incident resolves. */ readonly body: unknown; /** Short verb phrase identifying the attempted operation (e.g. "provisioning project"). */ readonly context: string; /** Canonical machine-readable Run402 error code, when the gateway provided one. */ readonly code?: string; /** High-level error category, e.g. lifecycle, deploy, auth. */ readonly category?: string; /** Whether the same request may succeed later. */ readonly retryable?: boolean; /** Whether repeating the same request should avoid duplicating/corrupting a mutation. */ readonly safeToRetry?: boolean; /** Gateway-known mutation progress for failed mutating operations. */ readonly mutationState?: string; /** Trace id suitable for support/debugging. */ readonly traceId?: string; /** Canonical structured context. Preserved by reference from the response body. */ readonly details?: unknown; /** Advisory next actions (gateway-authored or SDK-synthesized). Rendering them must not execute them. */ readonly nextActions?: NextAction[]; /** * Quota-denial scope (v1.46+). `"organization"` for pooled organization * denials; `"project"` for the orphan fallback (project whose organization * row was purged but cascade has not yet run). Lifted from * `details.scope` when the gateway returned it. Undefined for errors * that are not quota-related. */ readonly quotaScope?: Run402QuotaScope; constructor(message: string, status: number | null, body: unknown, context: string); /** * Canonical structured envelope for `JSON.stringify`. Without this, an * `Error` instance serializes as `"{}"` (its built-in fields are * non-enumerable), losing every structured detail an agent needs for * triage. Subclasses with extra fields (e.g. {@link Run402DeployError}) * override and spread `super.toJSON()`. */ toJSON(): Record; } /** * HTTP 402 — a genuine protocol payment challenge (x402 or a successor * rail): insufficient balance, or a priced quote that must be paid before * the request can proceed. style.md reserves 402 for exactly this; quota, * lifecycle (frozen/dormant lease expiry), and budget-cap denials return * 403 instead with their own canonical `code` (see the api-error-envelope * `HTTP 402 is reserved for protocol payment challenges` requirement). */ export declare class PaymentRequired extends Run402Error { static readonly DEFAULT_CODE = "PAYMENT_REQUIRED"; static readonly DEFAULT_CATEGORY = "payment_required"; static readonly DEFAULT_RETRYABLE = false; readonly kind: "payment_required"; } /** Project ID is not present in the credential provider (local miss) or the gateway returned 404. */ export declare class ProjectNotFound extends Run402Error { static readonly DEFAULT_CODE = "PROJECT_NOT_FOUND"; static readonly DEFAULT_CATEGORY = "not_found"; static readonly DEFAULT_RETRYABLE = false; readonly kind: "project_not_found"; readonly projectId: string; constructor(projectId: string, context: string, status?: number | null, body?: unknown); } /** * HTTP 401 or 403 — the generic denial bucket: authentication missing, * invalid, or insufficient for the operation. Also the fallback for any * other 403 that isn't one of the more specific subclasses below (e.g. * `NOT_AUTHORIZED`, `STEP_UP_REQUIRED`) — since 402 is reserved for * genuine payment challenges, this now also covers non-payment 403 denials * such as quota (`QUOTA_EXCEEDED`), lifecycle (`PROJECT_FROZEN` / * `PROJECT_DORMANT`), and delegate spend-cap denials. Check `body.code` (or * use `formatCanonicalErrorContext`-style parsing) to distinguish these * from a true auth failure. */ export declare class Unauthorized extends Run402Error { static readonly DEFAULT_CODE = "UNAUTHORIZED"; static readonly DEFAULT_CATEGORY = "auth"; static readonly DEFAULT_RETRYABLE = false; readonly kind: "unauthorized"; } /** * HTTP 403 `NOT_AUTHORIZED` — the org-owned control plane (gateway v1.77+) * denied a control-plane action. A wallet *authenticates* (SIWX resolves it to * a principal); *authorization* is an org (organization) membership in the * role lattice `owner > admin > developer > billing > viewer`, or a per-project * grant for agent/CI principals — never `wallet_address == signer`. High-stakes * ops (delete, transfer-of-ownership, membership change) require an active * `owner` membership. * * Distinct from {@link Unauthorized} (authentication missing/invalid): here the * caller IS authenticated but lacks the required role/capability, so the fix is * to obtain access (a membership/grant), not to re-authenticate. The gateway * returns 403 — never 404 — even when the project does not exist, so existence * is not leaked to a non-authorized caller (surfaced as `reason: * "project_not_found"`). Branch on `kind === "not_authorized"` (or * {@link isNotAuthorized}). */ export declare class NotAuthorizedError extends Run402Error { static readonly DEFAULT_CODE = "NOT_AUTHORIZED"; static readonly DEFAULT_CATEGORY = "auth"; static readonly DEFAULT_RETRYABLE = false; readonly kind: "not_authorized"; /** The control-plane action that was denied, when the gateway named one. */ readonly action: string | null; /** Org role required for the action (e.g. `"owner"`), or null when the denial is capability-based. */ readonly requiredRole: string | null; /** Per-project capability required (e.g. `"deploy"`), or null when the denial is role-based. */ readonly requiredCapability: string | null; /** * Why authorization failed. Known values: `"member"` (no active membership), * `"grant"` (no per-project grant), `"forbidden"` (role/grant too low), and * `"project_not_found"` (returned as 403 to avoid leaking existence). Future * strings pass through unchanged. */ readonly reason: string | null; constructor(message: string, status: number, body: unknown, context: string); toJSON(): Record; } /** Any other non-2xx HTTP response from the gateway. */ export declare class ApiError extends Run402Error { static readonly DEFAULT_CODE = "API_ERROR"; static readonly DEFAULT_CATEGORY = "api"; static readonly DEFAULT_RETRYABLE = false; readonly kind: "api_error"; } /** The underlying `fetch` threw before producing a response (DNS, connection reset, offline). */ export declare class NetworkError extends Run402Error { static readonly DEFAULT_CODE = "NETWORK_ERROR"; static readonly DEFAULT_CATEGORY = "network"; static readonly DEFAULT_RETRYABLE = true; readonly kind: "network_error"; readonly cause: unknown; constructor(message: string, cause: unknown, context: string); } /** * Phase of an automatic x402 payment attempt. `initial_request` and * `payment_signing` occur before a payment-bearing request is dispatched; * `payment_submission` and `payment_response` are at/after that boundary. */ export type PaymentAttemptPhase = "initial_request" | "challenge_received" | "payment_signing" | "payment_submission" | "payment_response"; export type PaymentAttemptMutationState = "not_started" | "in_progress" | "completed" | "ambiguous"; export declare class PaymentAttemptError extends Run402Error { readonly kind: "payment_attempt_error"; readonly code: string; readonly phase: PaymentAttemptPhase; readonly paymentAttemptId: string; readonly providerStarted: boolean; readonly responseStatus: number | null; readonly retryable: boolean; readonly safeToRetry: boolean; readonly mutationState: PaymentAttemptMutationState; readonly cause: unknown; constructor(init: { code: string; category?: "network" | "payment"; transportCode?: string; message: string; phase: PaymentAttemptPhase; paymentAttemptId: string; providerStarted: boolean; responseStatus?: number | null; mutationState: PaymentAttemptMutationState; safeToRetry: boolean; /** Operational retryability; defaults to safeToRetry. */ retryable?: boolean; nextActions?: NextAction[]; cause: unknown; request?: { method: string; origin: string | null; path_sha256: string | null; }; }); toJSON(): Record; } /** Local/filesystem error — input validation, missing path, unreadable dir. No HTTP involved. */ export declare class LocalError extends Run402Error { static readonly DEFAULT_CODE = "LOCAL_ERROR"; static readonly DEFAULT_CATEGORY = "local"; static readonly DEFAULT_RETRYABLE = false; readonly kind: "local_error"; readonly cause?: unknown; /** * @param message Human-readable error message. * @param context Short verb phrase identifying the operation (used for triage). * @param opts Optional. Pass a raw `unknown` for back-compat (treated as `cause`), * or an options bag `{ cause?, code?, details?, next_actions? }` to thread a stable error * `code` (mirrors a gateway error code so client-side validators throw with * the same `code` field consumers branch on). */ constructor(message: string, context: string, opts?: unknown | { cause?: unknown; code?: string; details?: unknown; next_actions?: unknown[]; }); } /** Local credential-cache miss — the project may exist, but no cached keys are available locally. */ export declare class ProjectCredentialNotFound extends LocalError { readonly projectId: string; constructor(projectId: string, context: string, details?: Record); } export declare const PROJECT_CREDENTIAL_ERROR_CODES: readonly ["PROJECT_CREDENTIAL_NOT_FOUND", "PROJECT_CREDENTIAL_INVALID", "PROJECT_CREDENTIAL_EXPIRED", "PROJECT_CREDENTIAL_PROJECT_MISMATCH"]; export type ProjectCredentialErrorCode = typeof PROJECT_CREDENTIAL_ERROR_CODES[number]; /** * Deploy-state-machine failure surfaced from the v2 deploy flow. Carries the * structured error envelope the gateway returns alongside the operation * snapshot — phase, resource, retryability, and an optional remediation hint. * * The `code` enumerates the gateway's deploy error codes; consumers may * switch on it to decide whether to retry, prompt the user for payment, ask * for a fix, or escalate. Unknown codes from a newer gateway pass through * verbatim — callers should treat unrecognized values as opaque. */ export type Run402DeployErrorCode = "MIGRATION_FAILED" | "MIGRATION_CHECKSUM_MISMATCH" | "MIGRATION_SQL_NOT_FOUND" | "BASE_RELEASE_CONFLICT" | "PAYMENT_REQUIRED" | "SUBDOMAIN_MULTI_NOT_SUPPORTED" | "SCHEMA_SETTLE_TIMEOUT" | "ACTIVATION_FAILED" | "STORAGE_UNAVAILABLE" | "SITE_STAGE_FAILED" | "FUNCTION_BUILD_FAILED" | "CONTENT_UPLOAD_FAILED" | "INVALID_SPEC" | "OPERATION_NOT_FOUND" | "PLAN_NOT_FOUND" | "MIGRATE_GATE_ACTIVE" | "NOT_RESUMABLE" | "INVALID_STATE" | "RESUME_FAILED" | "INTERNAL_ERROR" | "NETWORK_ERROR" | "PROJECT_NOT_FOUND" | (string & {}); export interface Run402DeployErrorFix { action: string; path?: string; [key: string]: unknown; } export declare class Run402DeployError extends Run402Error { readonly kind: "deploy_error"; readonly code: Run402DeployErrorCode; readonly phase: string | null; readonly resource: string | null; readonly retryable: boolean; readonly operationId: string | null; readonly planId: string | null; readonly fix: Run402DeployErrorFix | null; readonly logs: string[] | null; readonly rolledBack: boolean; readonly attempts?: number; readonly maxRetries?: number; readonly lastRetryCode?: Run402DeployErrorCode; constructor(message: string, init: { code: Run402DeployErrorCode; phase?: string | null; resource?: string | null; retryable?: boolean; operationId?: string | null; planId?: string | null; fix?: Run402DeployErrorFix | null; logs?: string[] | null; rolledBack?: boolean; attempts?: number; maxRetries?: number; lastRetryCode?: Run402DeployErrorCode; status?: number | null; body?: unknown; context: string; }); toJSON(): Record; } /** * Project has a pending transfer (v1.59+). Gateway returns 409 with * `code: "PROJECT_HAS_PENDING_TRANSFER"` from the transfer-freeze middleware * mounted on owner-side mutations (deploy, secrets, custom domains, function * CRUD, scheduled-function changes, mailbox config, CI bindings, project * rename, etc.). The pending transfer must be accepted, cancelled, or * allowed to expire (72h) before owner-side mutations resume. * * The error carries `transferId` (when the gateway resolved it) and * `cancelPath` lifted from `next_actions[].path`, so callers can present an * actionable resolution path. `previewPath` mirrors the view-transfer * next_action when present. */ export declare class TransferFreezeError extends Run402Error { static readonly DEFAULT_CODE = "PROJECT_HAS_PENDING_TRANSFER"; static readonly DEFAULT_CATEGORY = "validation"; static readonly DEFAULT_RETRYABLE = false; readonly kind: "transfer_freeze"; /** The pending transfer id when the gateway resolved one. */ readonly transferId: string | null; /** API path to cancel the pending transfer (e.g. `/agent/v1/transfers//cancel`). */ readonly cancelPath: string | null; /** API path to view the pending transfer preview. */ readonly previewPath: string | null; readonly projectId: string | null; constructor(message: string, status: number, body: unknown, context: string); } /** * Known `type` values for a {@link NextAction}. The gateway set (style.md * §Errors) extended with the client-side bootstrap verbs `create_project` and * `initialize_wallet`, plus `operator_approve` (synthesized for WRITE_AUTH), * and `claim_org_slug` / `claim_repo_name` (named addressing onboarding, * repo-first-onramp follow-up — `run402 repos create` points here when the * owning org has no slug yet, or has one but this project's address-form * name was not claimed). `push_repo`, `verify_refs`, `submit_gc`, * `use_moved_command`, and `access_repair_pending` are repo-surface- * consolidation's own additions — see `cli/lib/repos.mjs` for where each is * emitted. `configure_mirror` (gitvault-mirror-default) rides `repos create`'s * result beside the recovery receipt — the customer-owned mirror taught at * vault birth. `sync_writers` / `request_writer_sync` (gitvault-multi-writer * rev 47, D10) are the writer dimension's own pair — `sync_writers` rides * `POST /orgs/v1/:org_id/members`'s own gateway response (the caller's next * `org members add`/`repos access sync` admits a just-added member as a * writer on every vault it can reach); `request_writer_sync` is CLIENT- * constructed (`GitvaultVault#assertCallerIsWriter`, task 5.8) when a local * push pre-check refuses because this session's own key is not (or is no * longer) an admitted writer. * Tolerates unknown future gateway types via the `(string & {})` fallback. */ export type NextActionType = "retry" | "poll" | "reconcile_payment" | "authenticate" | "submit_payment" | "renew_tier" | "check_usage" | "resume_deploy" | "edit_request" | "edit_migration" | "create_project" | "initialize_wallet" | "deploy" | "operator_approve" | "contact_support" | "gitvault_policy_required" | "claim_org_slug" | "claim_repo_name" | "push_repo" | "create_nested_repo" | "verify_refs" | "submit_gc" | "use_moved_command" | "access_repair_pending" | "configure_mirror" | "resume_handoff" | "revoke_handoff" | "remove_member" | "sync_writers" | "request_writer_sync" | "join_invite" | "revoke_invite" | "wait_room" | "send_room_message" | "create_manifest" | "create_file" | "check_manifest" | "run_in_directory" | "commit_changes" | "claim_subdomain"; /** * A single advisory "what to do next" entry. Mirrors the gateway's * `next_actions[]` shape (`{ type, method?, path?, auth?, why? }`) extended with * `command` — the literal CLI invocation — for client-side, CLI-resolvable * actions. Rendering an action must never execute it. */ export interface NextAction { type: NextActionType | (string & {}); /** Literal CLI invocation for client-side, CLI-resolvable actions. */ command?: string; method?: string; path?: string; auth?: string; why?: string; [key: string]: unknown; } /** * HTTP 403 `STEP_UP_REQUIRED` — the gateway requires a fresh, same-client * step-up (a recent `passkey` AMR) before this high-stakes control-plane * operation (delete / transfer / membership / invite / payment drain·rotate) * may proceed. A `device_flow`-minted session can never satisfy it; the caller * must complete the challenge at {@link challengeUrl} (e.g. via * `run402 operator login --step-up`) on the same client and retry. * * Typed fields are lifted from the gateway `details` envelope; the same * remediation pointer is also present in {@link Run402Error.nextActions} as an * `authenticate` action. */ export declare class StepUpRequiredError extends Run402Error { static readonly DEFAULT_CODE = "STEP_UP_REQUIRED"; static readonly DEFAULT_CATEGORY = "auth"; static readonly DEFAULT_RETRYABLE = false; readonly kind: "step_up_required"; /** AMRs that would satisfy the step-up (e.g. `["passkey"]`). Empty when the gateway omitted it. */ readonly requiredAmr: string[]; /** Max age in seconds the satisfying auth may be; null when the gateway omitted it. */ readonly maxAgeSeconds: number | null; /** Where to run the step-up challenge; null when the gateway omitted it. */ readonly challengeUrl: string | null; /** Why the step-up was demanded (e.g. `"device_flow_forbidden"`); null when absent. */ readonly reason: string | null; constructor(message: string, status: number, body: unknown, context: string); toJSON(): Record; } /** * HTTP 403 — a wallet-less human (control-plane session) write needs a * passkey-fresh **operator approval** scoped to a specific `(capability, * target)`. Maps the gateway codes `WRITE_AUTH_REQUIRED` (no approval), * `WRITE_AUTH_BINDING_MISMATCH` (cached approval targeted the wrong org/project), * and `WRITE_AUTH_SESSION_INVALID` (stale approval). * * The gateway envelope is bare, so the SDK synthesizes a fully-resolved * remediation from the failing request's capability+target: read * {@link approveCommand} (e.g. `run402 operator approve --action project.deploy * --project prj_x`) or the structured {@link nextActions}. The SIWX wallet path * never triggers this. Never catch-and-swallow — surface the command to the * human/agent. Branch on `kind === "operator_approval_required"` (or * {@link isOperatorApprovalRequired}). */ export declare class OperatorApprovalRequiredError extends Run402Error { static readonly DEFAULT_CODE = "WRITE_AUTH_REQUIRED"; static readonly DEFAULT_CATEGORY = "auth"; static readonly DEFAULT_RETRYABLE = false; readonly kind: "operator_approval_required"; /** The principal class the approval belongs to. Always `"operator"` (the human). */ readonly principal: "operator"; /** The gateway write capability needing approval, when known from the request. */ readonly capability: string | null; /** The capability's target (`{ org_id }` or `{ project_id }`), when known. */ readonly target: { org_id?: string; project_id?: string; } | null; /** Fully-resolved CLI command that mints the missing approval, or null if unresolvable. */ readonly approveCommand: string | null; constructor(message: string, status: number, body: unknown, context: string, meta?: { capability?: string | null; target?: { org_id?: string; project_id?: string; } | null; }); toJSON(): Record; } /** True if `e` is any {@link Run402Error} subclass instance, regardless of which SDK copy created it. */ export declare function isRun402Error(e: unknown): e is Run402Error; /** True if `e` is a {@link PaymentRequired}. Survives duplicate SDK copies and realms. */ export declare function isPaymentRequired(e: unknown): e is PaymentRequired; /** True if `e` is a {@link ProjectNotFound}. */ export declare function isProjectNotFound(e: unknown): e is ProjectNotFound; /** True if `e` is a local project credential-cache miss. */ export declare function isProjectCredentialNotFound(e: unknown): e is ProjectCredentialNotFound; /** True if `e` carries any stable project-credential error code. */ export declare function isProjectCredentialError(e: unknown): e is Run402Error & { code: ProjectCredentialErrorCode; }; /** True if cached or supplied project credentials were rejected as invalid. */ export declare function isProjectCredentialInvalid(e: unknown): e is Run402Error & { code: "PROJECT_CREDENTIAL_INVALID"; }; /** True if cached or supplied project credentials were rejected as expired. */ export declare function isProjectCredentialExpired(e: unknown): e is Run402Error & { code: "PROJECT_CREDENTIAL_EXPIRED"; }; /** True if service-key auth was supplied for a different explicit project id. */ export declare function isProjectCredentialProjectMismatch(e: unknown): e is Run402Error & { code: "PROJECT_CREDENTIAL_PROJECT_MISMATCH"; }; /** True if `e` is an {@link Unauthorized}. */ export declare function isUnauthorized(e: unknown): e is Unauthorized; /** True if `e` is a {@link NotAuthorizedError} (org-owned control-plane denial, gateway v1.77+). */ export declare function isNotAuthorized(e: unknown): e is NotAuthorizedError; /** True if `e` is an {@link ApiError}. */ export declare function isApiError(e: unknown): e is ApiError; /** True if `e` is a {@link NetworkError}. */ export declare function isNetworkError(e: unknown): e is NetworkError; /** True if `e` is a phase-aware automatic x402 payment failure. */ export declare function isPaymentAttemptError(e: unknown): e is PaymentAttemptError; /** True if `e` is a {@link LocalError}. */ export declare function isLocalError(e: unknown): e is LocalError; /** True if `e` is a {@link Run402DeployError}. */ export declare function isDeployError(e: unknown): e is Run402DeployError; /** True if `e` is a {@link TransferFreezeError}. */ export declare function isTransferFreezeError(e: unknown): e is TransferFreezeError; /** True if `e` is a {@link StepUpRequiredError}. Survives duplicate SDK copies and realms. */ export declare function isStepUpRequired(e: unknown): e is StepUpRequiredError; /** True if `e` is an {@link OperatorApprovalRequiredError} (wallet-less write needs a passkey approval). */ export declare function isOperatorApprovalRequired(e: unknown): e is OperatorApprovalRequiredError; /** * Extract the v1.46+ quota-denial scope from an error. Returns `"organization"` * for pooled denials, `"project"` for the orphan fallback, or `undefined` * when the error is not quota-related (or originated from a pre-v1.46 * gateway that did not set `details.scope`). Safe to call with `unknown`. */ export declare function getQuotaScope(e: unknown): Run402QuotaScope | undefined; /** * Canonical "should I retry this?" policy. Returns true when `e` is a * {@link Run402Error} AND any of: * - `e.retryable === true` (gateway flagged it) * - `e.kind === "network_error"` (fetch never produced a response) * - `e.status` is 408 (Request Timeout), 425 (Too Early), or 429 (Too Many * Requests) * - `e.status` is a 5xx server error * * `safeToRetry` is deliberately NOT sufficient by itself: it means a repeated * mutation should not duplicate/corrupt state, not that the request can succeed * without a lifecycle/payment/auth action first. * * Returns false for non-Run402 errors so it can be safely called with * `unknown` from a catch block. Used as the default `retryIf` in * {@link withRetry}. */ export declare function isRetryableRun402Error(e: unknown): boolean; //# sourceMappingURL=errors.d.ts.map