@atlasent/sdk 2.10.0 → 2.12.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/hono.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/types.ts","../src/compat.ts","../src/retry.ts","../src/client.ts","../src/protect.ts","../src/hono.ts"],"sourcesContent":["/**\n * Error types for the AtlaSent TypeScript SDK.\n *\n * The SDK follows a fail-closed design: a clean policy DENY is\n * returned as `EvaluateResponse.decision === \"deny\"` (not thrown),\n * but any failure to confirm authorization — network, timeout,\n * bad response, invalid key, rate limit — throws an\n * {@link AtlaSentError}.\n */\n\n// ── Streaming-specific errors ─────────────────────────────────────────────────\n\n/**\n * Thrown when no SSE event arrives within the configured timeout window.\n *\n * Callers can catch this specifically to distinguish a stalled stream\n * from other network or parse failures:\n *\n * ```ts\n * catch (e) {\n * if (e instanceof StreamTimeoutError) { // reconnect or alert }\n * }\n * ```\n */\nexport class StreamTimeoutError extends Error {\n override name: string = \"StreamTimeoutError\";\n /** Timeout that was exceeded, in milliseconds. */\n readonly timeoutMs: number;\n\n constructor(timeoutMs: number) {\n super(`AtlaSent stream timed out after ${timeoutMs}ms with no event`);\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Thrown when the SSE stream closes with a partial / malformed JSON payload.\n *\n * This is a recoverable condition — the stream closed mid-JSON. The\n * caller can reconnect using the last received `Last-Event-ID` and\n * resume from where the server left off.\n *\n * ```ts\n * catch (e) {\n * if (e instanceof StreamParseError) { // log raw data, maybe reconnect }\n * }\n * ```\n */\nexport class StreamParseError extends Error {\n override name: string = \"StreamParseError\";\n /** The raw data string that failed to parse. */\n readonly rawData: string;\n\n constructor(rawData: string, cause?: unknown) {\n super(`AtlaSent stream received malformed JSON: ${rawData.slice(0, 200)}`);\n this.rawData = rawData;\n if (cause !== undefined) {\n // ES2022 cause\n (this as { cause?: unknown }).cause = cause;\n }\n }\n}\n\n/** Discriminator for {@link AtlaSentError.code}. */\nexport type AtlaSentErrorCode =\n | \"invalid_api_key\"\n | \"forbidden\"\n | \"rate_limited\"\n | \"timeout\"\n | \"network\"\n | \"bad_response\"\n | \"bad_request\"\n | \"server_error\"\n // Tenant lacks a v2_<feature> flag — server returned 404. Distinct\n // from \"forbidden\" (403 authorization denial) so callers can branch\n // on the failure mode.\n | \"feature_disabled\"\n | \"claim_evidence_incomplete\";\n\n/** Initialization options for {@link AtlaSentError}. */\nexport interface AtlaSentErrorInit {\n status?: number;\n code?: AtlaSentErrorCode;\n requestId?: string;\n retryAfterMs?: number;\n cause?: unknown;\n}\n\n/**\n * The only error type this SDK throws.\n *\n * Flat top-level properties mirror the convention used by Stripe,\n * Octokit, and Supabase. `cause` is forwarded to the standard\n * ES2022 `Error` constructor.\n */\nexport class AtlaSentError extends Error {\n // Subclasses override to their own literal (e.g. \"AtlaSentDeniedError\");\n // keep this assignable rather than pinned to a single literal.\n override name: string = \"AtlaSentError\";\n\n /** HTTP status code, when the error originated from an API response. */\n readonly status: number | undefined;\n /** Coarse category — useful for `switch` statements at call sites. */\n readonly code: AtlaSentErrorCode | undefined;\n /** Correlation ID echoed from the `X-Request-ID` header the SDK sent. */\n readonly requestId: string | undefined;\n /** Parsed `Retry-After` header value, in milliseconds. Only set for 429. */\n readonly retryAfterMs: number | undefined;\n\n constructor(message: string, init: AtlaSentErrorInit = {}) {\n super(\n message,\n init.cause !== undefined ? { cause: init.cause } : undefined,\n );\n this.status = init.status;\n this.code = init.code;\n this.requestId = init.requestId;\n this.retryAfterMs = init.retryAfterMs;\n }\n}\n\n/**\n * Outcome of a denied decision.\n *\n * `\"deny\"` is what the current `/v1-evaluate` API returns. `\"hold\"`\n * and `\"escalate\"` are reserved for forthcoming API decisions that\n * put a permit into a pending state requiring human review; the\n * union is declared now so call sites can `switch` exhaustively\n * from the start and adopt new decisions without a breaking change.\n */\nexport type AtlaSentDecision = \"deny\" | \"hold\" | \"escalate\";\n\n/**\n * Reason an already-issued permit failed verification.\n *\n * Surfaced on {@link AtlaSentDeniedError.outcome} so callers can\n * distinguish replay (`permit_consumed`) from revocation\n * (`permit_revoked`) from natural expiry (`permit_expired`) without\n * parsing {@link AtlaSentDeniedError.reason}. The set is defined by\n * `contract/vectors/permit_outcomes.json`; any new outcome MUST be\n * added there first.\n *\n * Mirrors the Python SDK's `PermitOutcome`. See\n * `atlasent/docs/REVOCATION_RUNBOOK.md` for the operator-facing\n * matrix this discriminator drives.\n */\nexport type PermitOutcome =\n | \"permit_consumed\"\n | \"permit_expired\"\n | \"permit_revoked\"\n | \"permit_not_found\";\n\nconst KNOWN_PERMIT_OUTCOMES: ReadonlySet<string> = new Set([\n \"permit_consumed\",\n \"permit_expired\",\n \"permit_revoked\",\n \"permit_not_found\",\n]);\n\n/**\n * Map a server-supplied `outcome` string to {@link PermitOutcome}.\n *\n * Returns `undefined` for `undefined`, `\"\"`, `\"verified\"`, or any\n * unrecognized value. Used at the SDK's deny boundary so we don't\n * surface mis-typed outcomes — when the server adds a new outcome\n * string, callers branching on {@link AtlaSentDeniedError.outcome}\n * see `undefined` and fall through to their generic deny path\n * rather than match an unknown literal.\n */\nexport function normalizePermitOutcome(\n raw: string | undefined,\n): PermitOutcome | undefined {\n if (raw !== undefined && KNOWN_PERMIT_OUTCOMES.has(raw)) {\n return raw as PermitOutcome;\n }\n return undefined;\n}\n\n/** Initialization options for {@link AtlaSentDeniedError}. */\nexport interface AtlaSentDeniedErrorInit {\n decision: AtlaSentDecision;\n evaluationId: string;\n reason?: string;\n requestId?: string;\n auditHash?: string;\n /**\n * When the denial came from permit verification (not policy\n * evaluation), the discriminator that distinguishes replay,\n * expiry, revocation, and missing-record failures. `undefined`\n * for evaluate-time denials.\n */\n outcome?: PermitOutcome;\n}\n\n/**\n * Thrown by {@link atlasent.protect} when the policy engine refuses\n * the action, or when a permit fails end-to-end verification.\n *\n * This is the **fail-closed boundary** of the SDK: every code path\n * that short-circuits an action because authorization was not\n * confirmed raises an `AtlaSentDeniedError`. Callers cannot silently\n * proceed on a denial by forgetting to branch on a return value.\n *\n * Extends {@link AtlaSentError} so `instanceof AtlaSentError`\n * catches denials as part of the SDK's single exception family;\n * use `instanceof AtlaSentDeniedError` to distinguish a policy\n * denial from a transport/auth error.\n */\nexport class AtlaSentDeniedError extends AtlaSentError {\n override name: string = \"AtlaSentDeniedError\";\n\n /** Policy decision — `\"deny\"` today; `\"hold\"` / `\"escalate\"` reserved. */\n readonly decision: AtlaSentDecision;\n /** Opaque permit/decision id from `/v1-evaluate`. */\n readonly evaluationId: string;\n /** Human-readable explanation from the policy engine, if provided. */\n readonly reason: string | undefined;\n /** Hash-chained audit-trail entry associated with the decision. */\n readonly auditHash: string | undefined;\n /**\n * Discriminator for permit-side denial reasons. Populated only\n * when the server reported `verified=false` from `/v1-verify-permit`;\n * `undefined` for evaluate-time denials. See {@link PermitOutcome}.\n */\n readonly outcome: PermitOutcome | undefined;\n\n constructor(init: AtlaSentDeniedErrorInit) {\n const msg = init.reason\n ? `AtlaSent ${init.decision}: ${init.reason}`\n : `AtlaSent ${init.decision}`;\n const errInit: AtlaSentErrorInit = { status: 200 };\n if (init.requestId !== undefined) errInit.requestId = init.requestId;\n super(msg, errInit);\n this.decision = init.decision;\n this.evaluationId = init.evaluationId;\n this.reason = init.reason;\n this.auditHash = init.auditHash;\n this.outcome = init.outcome;\n }\n\n // ── Outcome discriminators ───────────────────────────────────────\n // Convenience predicates that mirror the operator runbook's matrix.\n // Callers can compare `outcome` directly; these are sugar so the\n // common cases are explicit at the call site.\n\n /** `true` when the permit was explicitly revoked (D3 endpoint). */\n get isRevoked(): boolean {\n return this.outcome === \"permit_revoked\";\n }\n\n /** `true` when the permit's TTL passed before verification. */\n get isExpired(): boolean {\n return this.outcome === \"permit_expired\";\n }\n\n /**\n * `true` when the permit was already consumed by a prior verify\n * (v1 single-use replay protection).\n */\n get isConsumed(): boolean {\n return this.outcome === \"permit_consumed\";\n }\n\n /**\n * `true` when the permit id wasn't recognized server-side\n * (typo, cross-tenant lookup, or pre-issuance race).\n */\n get isNotFound(): boolean {\n return this.outcome === \"permit_not_found\";\n }\n}\n\n/** Initialization options for {@link AtlaSentEscalateError}. */\nexport interface AtlaSentEscalateErrorInit {\n requestId?: string;\n userId?: string;\n cause?: unknown;\n}\n\n/**\n * Thrown when an evaluate response carries `decision: \"escalate\"`.\n *\n * Distinct from {@link AtlaSentDeniedError} — an escalation does not\n * constitute a hard denial. It signals that the policy engine has\n * deferred the authorization decision to a human review queue.\n * Middleware and agent orchestrators should catch this specifically\n * and route the pending action to the appropriate HITL channel.\n *\n * ```ts\n * catch (e) {\n * if (e instanceof AtlaSentEscalateError) {\n * await humanReviewQueue.submit({ userId: e.userId, requestId: e.requestId });\n * }\n * }\n * ```\n *\n * Extends {@link AtlaSentError} so `instanceof AtlaSentError` catches\n * escalations alongside other SDK errors; use\n * `instanceof AtlaSentEscalateError` to branch specifically.\n */\nexport class AtlaSentEscalateError extends AtlaSentError {\n override name: string = \"AtlaSentEscalateError\";\n\n /** Always `\"escalate\"` — discriminates this error from other AtlaSent errors. */\n readonly decision = \"escalate\" as const;\n\n /** The user whose action triggered the escalation, if available. */\n readonly userId: string | undefined;\n\n constructor(message: string, opts?: AtlaSentEscalateErrorInit) {\n super(message, {\n ...(opts?.requestId !== undefined ? { requestId: opts.requestId } : {}),\n cause: opts?.cause,\n });\n this.userId = opts?.userId;\n }\n}\n\n// ── Permit revocation error (PROD-D9 continuous-authorization) ────────────────\n\n/**\n * Thrown by an SDK guard heartbeat when `GET /v1/permits/:id/valid`\n * returns `status: 'revoked'` during tool execution (PROD-D9\n * continuous-authorization lease model).\n *\n * This error is **always re-thrown** — it is never serialized as a\n * `tool-result` denial because it represents a live enforcement action,\n * not a policy evaluation at request time. Callers should treat it as\n * an immediate halt signal.\n *\n * ```ts\n * catch (e) {\n * if (e instanceof PermitRevoked) {\n * // log e.permitId and e.revocationId for incident correlation\n * await incidentLog.record({ permitId: e.permitId, revocationId: e.revocationId });\n * }\n * }\n * ```\n *\n * Guard heartbeat is configured via `permitRevalidationIntervalMs` in\n * the guard options (minimum 1000 ms). The heartbeat activates only\n * when the {@link AtlaSentClient} exposes `checkPermitValid` — i.e.\n * when `atlasent-api` has deployed `GET /v1/permits/:id/valid`.\n */\nexport class PermitRevoked extends AtlaSentError {\n override name: string = 'PermitRevoked';\n /** The id of the permit that was revoked mid-execution. */\n readonly permitId: string;\n /** The `scope_revocations.id` that triggered the revocation, when available. */\n readonly revocationId: string | undefined;\n\n constructor(permitId: string, revocationId?: string) {\n super(\n revocationId\n ? `AtlaSent: permit ${permitId} revoked (revocation: ${revocationId}) — guard heartbeat halted execution`\n : `AtlaSent: permit ${permitId} revoked — guard heartbeat halted execution`,\n );\n this.permitId = permitId;\n this.revocationId = revocationId;\n }\n}\n","/**\n * Public types for the AtlaSent TypeScript SDK.\n *\n * These shapes are deliberately minimal and 1:1 with the AtlaSent\n * authorization API. Request / response fields are camelCase on the\n * SDK side; the client handles snake_case translation on the wire.\n */\n\nimport type { AuditEventsPage, AuditExport } from \"./audit.js\";\n\n/**\n * Canonical 4-value policy decision, byte-identical to the wire.\n *\n * - `allow` — action is authorized; a Permit is issued.\n * - `deny` — action is blocked.\n * - `hold` — decision deferred (e.g. waiting on an approval signal).\n * - `escalate` — routed to a human reviewer queue.\n *\n * Pin to this type on new code.\n */\nexport type DecisionCanonical = \"allow\" | \"deny\" | \"hold\" | \"escalate\";\n\n/**\n * Decision type — unified with the canonical 4-value vocabulary.\n *\n * This type previously emitted `\"ALLOW\"` / `\"DENY\"` (uppercase, 2-value).\n * It now reflects the canonical wire values (`\"allow\" | \"deny\" | \"hold\" |\n * \"escalate\"`) so the `decision` and `decision_canonical` fields on\n * {@link EvaluateResponse} carry identical values and types.\n *\n * Backward compatibility: the SDK normalises API response values to\n * lowercase (`.toLowerCase()`) before returning them, so callers that\n * previously checked `=== \"ALLOW\"` must update to `=== \"allow\"`. The\n * canonical field `decision_canonical` is also available and was always\n * lowercase — prefer it on new code.\n *\n * Legacy uppercase input accepted by the SDK is normalised to lowercase\n * output; `\"ALLOW\"` in → `\"allow\"` out, `\"DENY\"` in → `\"deny\"` out.\n */\nexport type Decision = DecisionCanonical;\n\n/**\n * Rate-limit state parsed from the server's `X-RateLimit-*` headers.\n *\n * Present on every authenticated response (success and 429) when the\n * server emits the headers. `null` when the server doesn't — older\n * deployments, or internal endpoints that skip per-key rate limiting.\n *\n * Clients should check `remaining` and sleep until `resetAt` to\n * preemptively back off before hitting a 429.\n */\nexport interface RateLimitState {\n /** Value of `X-RateLimit-Limit` — the per-minute budget. */\n limit: number;\n /** Value of `X-RateLimit-Remaining` — unused budget in the current window. */\n remaining: number;\n /**\n * Parsed `X-RateLimit-Reset` — the UTC instant when the current\n * window's counter zeroes. Accepts either a unix-seconds integer or\n * an ISO 8601 string on the wire.\n */\n resetAt: Date;\n}\n\n/**\n * Canonical Deploy Gate V1 protected action.\n *\n * Use this constant (or its string value `\"production.deploy\"`) on all\n * new code. Server-side `action_classes.slug` was canonicalised to\n * `production.deploy` in atlasent-api PR #662 / atlasent-console\n * PR #432; the SDK default now matches.\n */\nexport const PRODUCTION_DEPLOY_ACTION = \"production.deploy\" as const;\n\n/**\n * Legacy alias for {@link PRODUCTION_DEPLOY_ACTION}.\n *\n * @deprecated since 2.3.0 — use {@link PRODUCTION_DEPLOY_ACTION}. The\n * server alias-tolerates `deployment.production` during the V1 alias\n * window, so existing callers continue to work unchanged; please\n * migrate by the next minor release.\n */\nexport const DEPLOYMENT_PRODUCTION_ACTION = \"deployment.production\" as const;\n\n// ── Deploy Gate V1 context types ──────────────────────────────────────────────\n\n/**\n * Permit claim for `production.deploy` evaluations (Rule 3).\n *\n * Pass as `permit` inside {@link DeployGateContext}.\n * The `verified` flag is set by the verify-permit service after a\n * successful `/v1-verify-permit` call — do not self-assert it.\n */\nexport interface DeployPermitClaim {\n permit_id?: string;\n environment?: string;\n action_type?: string;\n /** ISO-8601 timestamp when the permit was issued. */\n issued_at?: string;\n /** Set server-side by the verify-permit service. Do not self-assert. */\n verified?: boolean;\n}\n\n/**\n * Override claim for `production.deploy` evaluations (Rule 8).\n *\n * Both `override_reason` and `authority_basis` must be non-empty to\n * receive `OVERRIDE_APPROVED`. Missing or blank fields return `DENY_POLICY`.\n */\nexport interface DeployOverrideClaim {\n /** Human-readable reason. Required and non-empty. */\n override_reason?: string;\n /** Authoritative basis — runbook section, incident ticket, etc. Required and non-empty. */\n authority_basis?: string;\n /** Approver actor ID (audit record; does not gate the decision). */\n approver_actor_id?: string;\n}\n\n/**\n * Typed context shape for `production.deploy` evaluations.\n *\n * Pass as `context` to `protect()`, `deployGate()`, or\n * {@link AtlaSentClient.evaluate} for the Deploy Gate V1 flow.\n *\n * @example\n * ```ts\n * const permit = await atlasent.protect({\n * agent: \"deploy-bot\",\n * action: PRODUCTION_DEPLOY_ACTION,\n * context: {\n * environment: \"production\",\n * evaluation_confirmed: true,\n * actorMetadata: { role: \"deploy_engineer\" },\n * permit: {\n * permit_id: permitToken,\n * environment: \"production\",\n * action_type: PRODUCTION_DEPLOY_ACTION,\n * issued_at: new Date().toISOString(),\n * verified: true,\n * },\n * } satisfies DeployGateContext,\n * });\n * ```\n */\nexport interface DeployGateContext {\n /** Must be `\"production\"` for the production gate to apply. */\n environment?: \"production\" | \"staging\" | \"development\";\n /**\n * When `true`, all rule failures are shadowed to `allow` (fail-open).\n * Malformed-timestamp inconsistencies still escalate.\n * Use for initial rollout before locking enforcement.\n */\n pilot_mode?: boolean;\n /** Must be `true` — confirms an evaluation record exists before proceeding. */\n evaluation_confirmed?: boolean;\n /** ISO-8601 timestamp of when evaluation was confirmed. */\n evaluation_confirmed_at?: string;\n /** Actor role metadata. `role` must be one of the approved deploy roles. */\n actorMetadata?: { role?: string };\n /** Signed permit claim — required for non-pilot production deployments. */\n permit?: DeployPermitClaim;\n /** Override claim — short-circuits all rules when both fields are non-empty. */\n override?: DeployOverrideClaim;\n [key: string]: unknown;\n}\n\n/**\n * Canonical deploy gate decision codes emitted for `production.deploy`.\n *\n * Appears as `deny_code` / `matchedRuleId` on evaluation responses.\n * Pin dashboards, alerting, and routing logic to these codes — not to\n * `deny_reason` strings, which may change.\n */\nexport type DeployGateDenyCode =\n | \"ALLOW\"\n | \"DENY_POLICY\"\n | \"DENY_AUTHORITY\"\n | \"DENY_ENVIRONMENT\"\n | \"PERMIT_EXPIRED\"\n | \"VERIFY_FAILED\"\n | \"ESCALATE_REQUIRED\"\n | \"OVERRIDE_APPROVED\";\n\n/** Typed constants for {@link DeployGateDenyCode}. */\nexport const DEPLOY_GATE_CODES = Object.freeze({\n ALLOW: \"ALLOW\",\n DENY_POLICY: \"DENY_POLICY\",\n DENY_AUTHORITY: \"DENY_AUTHORITY\",\n DENY_ENVIRONMENT: \"DENY_ENVIRONMENT\",\n PERMIT_EXPIRED: \"PERMIT_EXPIRED\",\n VERIFY_FAILED: \"VERIFY_FAILED\",\n ESCALATE_REQUIRED: \"ESCALATE_REQUIRED\",\n OVERRIDE_APPROVED: \"OVERRIDE_APPROVED\",\n} satisfies Record<DeployGateDenyCode, DeployGateDenyCode>);\n\n/** Input to {@link AtlaSentClient.deployGate}. */\nexport interface DeployGateRequest {\n /** CI/repo actor performing the deployment. Defaults to `ci-deploy-bot`. */\n agent?: string;\n /** Protected action. Defaults to `production.deploy`. */\n action?:\n | typeof PRODUCTION_DEPLOY_ACTION\n | typeof DEPLOYMENT_PRODUCTION_ACTION\n | string;\n /** Typed deploy gate context for `production.deploy`. */\n context?: DeployGateContext | Record<string, unknown>;\n}\n\n/** Evidence metadata returned by {@link AtlaSentClient.deployGate}. */\nexport interface DeployGateEvidence {\n permitId?: string;\n permitHash?: string;\n auditHash?: string;\n verifiedAt?: string;\n}\n\n/** Result of the canonical Deploy Gate V1 flow. */\nexport interface DeployGateResponse {\n /** True only after evaluate allowed AND `/v1-verify-permit` verified server-side. */\n allowed: boolean;\n /** Evaluation response from `POST /v1-evaluate`, when available. */\n evaluation?: EvaluateResponse;\n /** Verification response from `POST /v1-verify-permit`, when evaluation allowed. */\n verification?: VerifyPermitResponse;\n /** Human-readable block/allow reason. */\n reason: string;\n /** Best-effort audit/evidence metadata available to the SDK. */\n evidence: DeployGateEvidence;\n}\n\n/**\n * Frozen BVS snapshot wire shape (BI4).\n * Carried in {@link EvaluateRequest}.context.bvsSnapshot when\n * the `behavior_conditioning` flag is enabled for the tenant.\n * Produced by behavior-insights GET /api/patterns/snapshot/:userId\n * and attached via `@atlasent/behavior` attachToEvaluate().\n */\nexport interface BvsSnapshot {\n user_id: string;\n /** Factor model output — keyed by BVS factor slug, value is score 0-1. */\n factors: Record<string, number>;\n /** Aggregate confidence score (0-1). Decays on a 60-day half-life. */\n confidence: number;\n /** True when the aggregate is fresh-and-thin (too few events to trust). */\n confidence_low: boolean;\n /** ISO-8601 timestamp of the compute run that produced this snapshot. */\n computed_at: string;\n}\n\n/**\n * Consent-class projection (BI5) — the privacy-safe aggregate shape that\n * third-party apps (LedgersMe, hiCoach, echobloom) receive when reading a\n * user's behavioral summary. Counts and timestamps only; no raw free-text.\n * Produced by behavior-insights `/api/patterns/summary/:userId` and fetched\n * via `@atlasent/behavior` getStateSummary(). The SDK enforces\n * {@link https://github.com/AtlaSent-Systems-Inc/atlasent-sdk | assertNoRawText}\n * client-side before returning this shape to callers.\n */\nexport interface ConsentClassProjection {\n user_id: string;\n window_start: string;\n window_end: string;\n event_count: number;\n category_counts: Partial<Record<string, number>>;\n}\n\n/** Input to {@link AtlaSentClient.evaluate}. */\nexport interface EvaluateRequest {\n /** Identifier of the calling agent (e.g. \"clinical-data-agent\"). */\n agent: string;\n /** The action being authorized (e.g. \"modify_patient_record\"). */\n action: string;\n /** Arbitrary policy context (user, environment, resource IDs). */\n context?: Record<string, unknown>;\n /**\n * When `true`, the server populates `riskEnvelope.factors` with a\n * per-factor breakdown of the weighted risk score. Omit (or `false`)\n * to keep response payloads small.\n */\n explain?: boolean;\n}\n\n/**\n * Slim permit object embedded in {@link EvaluateResponse} when the decision\n * is `\"allow\"`. Contains the essential fields needed to act on the permit\n * immediately without a separate `GET /v1/permits/:id` round-trip.\n *\n * Mirrors the `Permit` schema in atlasent-control-plane\n * `api/src/schemas/permits.ts`.\n */\nexport interface EvaluateResponsePermit {\n id: string;\n orgId: string;\n subject: string;\n scope: string;\n status: \"active\" | \"revoked\" | \"expired\";\n /** The evaluation that produced this permit. */\n evaluationId: string | null;\n issuedBy: string;\n revokedBy: string | null;\n /** ISO-8601 issuance timestamp. */\n issuedAt: string;\n revokedAt: string | null;\n expiresAt: string | null;\n metadata: Record<string, unknown> | null;\n}\n\n/** Result of {@link AtlaSentClient.evaluate}. */\nexport interface EvaluateResponse {\n /**\n * Policy decision — canonical 4-value lowercase vocabulary:\n * `\"allow\"`, `\"deny\"`, `\"hold\"`, or `\"escalate\"`.\n *\n * Previously emitted `\"ALLOW\"` / `\"DENY\"` (uppercase, 2-value);\n * the SDK now normalises all values to lowercase and passes `hold`\n * and `escalate` through rather than collapsing them to `\"DENY\"`.\n *\n * The `decision_canonical` field carries the same value and is the\n * recommended field for new code.\n */\n decision: Decision;\n /**\n * Canonical 4-value decision, byte-identical to the wire.\n *\n * One of `\"allow\"`, `\"deny\"`, `\"hold\"`, `\"escalate\"`. Branch on\n * this field on new code. `hold` and `escalate` are non-terminal\n * states that route to a human reviewer / approval signal — they\n * are not equivalent to a `deny`.\n */\n decision_canonical: DecisionCanonical;\n /**\n * Server-assigned identifier for this evaluation decision.\n *\n * Stable across retries and used as the key for proof retrieval\n * (`GET /v1/proof/:evaluationId`) and override requests. Also\n * available as the legacy `permitId` field for backward compatibility.\n */\n evaluationId: string;\n /** Opaque permit identifier, passed to {@link AtlaSentClient.verifyPermit}.\n *\n * @deprecated Prefer `evaluationId`. This field is kept for backward\n * compatibility and points to the same server-assigned ID.\n */\n permitId: string;\n /**\n * Slim permit object issued when `decision === \"allow\"`.\n * `null` on deny, hold, or escalate decisions.\n *\n * Mirrors the `Permit` schema from the control-plane.\n */\n permit: EvaluateResponsePermit | null;\n /**\n * Opaque HMAC-signed permit token issued when `decision === \"allow\"`.\n * Pass to `POST /v1/verify-permit` to verify the permit server-side.\n * `null` on deny, hold, or escalate decisions.\n */\n permitToken: string | null;\n /**\n * Machine-readable reasons emitted by the policy engine.\n *\n * The array may be empty. For deny/hold/escalate decisions the array\n * typically contains a single human-readable explanation; for allow\n * decisions it is often empty. Do not parse these strings — use\n * `decision` for branching.\n */\n reasons: string[];\n /** Human-readable explanation from the policy engine.\n *\n * @deprecated Prefer `reasons[0]` or `reasons`. This field is the\n * first element of `reasons` (or an empty string) for backward compat.\n */\n reason: string;\n /** Hash-chained audit-trail entry (21 CFR Part 11 / GxP-ready). */\n auditHash: string;\n /** ISO 8601 timestamp of the decision. */\n timestamp: string;\n /**\n * Per-key rate-limit state for this request's response, parsed from\n * `X-RateLimit-*` headers. `null` when the server didn't emit them.\n */\n rateLimit: RateLimitState | null;\n /**\n * Risk envelope summary from the policy engine. Present on all responses\n * from engine version wire-v1@1.0.0+. Provides the weighted risk score,\n * the pre/post-promotion decisions, and (when evaluate was called with\n * `explain: true`) a per-factor breakdown.\n *\n * The envelope can only raise severity — it structurally cannot soften\n * a deny to allow. When `promoted` is true the live `decision` was\n * upgraded from `engineDecision` to `envelopeDecision`.\n */\n riskEnvelope?: EvaluateRiskEnvelope;\n}\n\n/** Per-factor contribution in a {@link EvaluateRiskEnvelope}. */\nexport interface EvaluateRiskEnvelopeFactor {\n /** Factor identifier, e.g. `\"ACTION_SENSITIVITY\"`. */\n factor: string;\n /** Factor score in [0, 1]. Higher = more risk. */\n value: number;\n /** Configured weight for this factor. */\n weight: number;\n /** Human-readable explanation for the score. */\n reason: string;\n}\n\n/** Risk envelope summary returned in a top-level {@link EvaluateResponse}. */\nexport interface EvaluateRiskEnvelope {\n /** Weighted risk score in [0, 1]. Score ≥ 0.70 triggers a hold. */\n weightedScore: number;\n /** Policy engine decision before envelope promotion. */\n engineDecision: Decision;\n /** Decision resolved by the risk envelope. */\n envelopeDecision: Decision;\n /** `true` when the envelope raised the decision's severity (most-restrictive-wins). */\n promoted: boolean;\n /** Deny codes that unconditionally block regardless of score. */\n hardBlocks: string[];\n /** Per-factor breakdown. Present only when `explain: true` was passed. */\n factors?: EvaluateRiskEnvelopeFactor[];\n}\n\n/** Input to {@link AtlaSentClient.verifyPermit}. */\nexport interface VerifyPermitRequest {\n /** The permit ID returned by a prior evaluate() call. */\n permitId: string;\n /** Optional: re-state the action for cross-check with the server. */\n action?: string;\n /** Optional: re-state the agent for cross-check with the server. */\n agent?: string;\n /** Optional: re-state the context for cross-check with the server. */\n context?: Record<string, unknown>;\n /**\n * Environment of the permit being verified. Sourced from the evaluate\n * payload (context.environment → top-level environment → \"production\").\n * Required by the server for production permits as of 2026-05-14.\n * P1-1 fix: withPermit/protect now always populates this field.\n */\n environment?: string;\n /**\n * SHA-256 hex digest of the recursively key-sorted canonical JSON of the\n * original evaluate payload. Required by the server for production permits\n * as of 2026-05-14.\n * P1-5 fix: withPermit/protect now always computes and sends this field.\n */\n execution_hash?: string;\n}\n\n/**\n * Result of {@link AtlaSentClient.verifyPermit}.\n *\n * @deprecated Use {@link VerifyPermitByIdResponse} via\n * {@link AtlaSentClient.verifyPermitById} — the canonical REST surface\n * (`POST /v1/permits/{id}/verify`) returns the unified verification\n * envelope (`valid`, `verification_type`, `reason`, `verified_at`,\n * `evidence`) plus the full {@link PermitRecord} fields. Will be\n * removed in `@atlasent/sdk@3`.\n */\nexport interface VerifyPermitResponse {\n /** `true` when the permit is valid and un-revoked. */\n verified: boolean;\n /** Verification outcome string from the server. */\n outcome: string;\n /** Verification hash bound to the permit. */\n permitHash: string;\n /** ISO 8601 timestamp of the verification. */\n timestamp: string;\n /**\n * ISO-8601 expiration timestamp of the permit. `null` on pre-rollout\n * server versions that do not yet surface this field.\n */\n expiresAt: string | null;\n /**\n * Per-key rate-limit state for this request's response, parsed from\n * `X-RateLimit-*` headers. `null` when the server didn't emit them.\n */\n rateLimit: RateLimitState | null;\n}\n\n/**\n * Result of {@link AtlaSentClient.keySelf} — self-introspection of the API\n * key the client was constructed with. Returned by `GET /v1/api-key-self`.\n *\n * Never includes the raw key or its hash — introspection is intentionally\n * read-only and safe to surface in operator dashboards. Useful for:\n * - \"which key am I?\" debugging\n * - IP_NOT_ALLOWED failures — `clientIp` is the IP the server observed\n * - proactive expiry warnings — `expiresAt` is the server-stored expiry\n * (`null` means the key does not auto-expire)\n * - verifying scopes before attempting a scope-gated action\n */\nexport interface ApiKeySelfResponse {\n /** Server-side UUID of the api_keys row for this key. */\n keyId: string;\n /** Organization the key belongs to. */\n organizationId: string;\n /** \"live\" or \"test\" (or any future environment label the server introduces). */\n environment: string;\n /** Granted scopes — e.g. [\"evaluate\", \"audit.read\"]. */\n scopes: string[];\n /**\n * Per-key IP allowlist as CIDR strings (e.g. [\"10.0.0.0/8\"]). `null`\n * when the key is unrestricted.\n */\n allowedCidrs: string[] | null;\n /** Server-enforced per-minute rate limit for this key. */\n rateLimitPerMinute: number;\n /** Client IP as the server observed it (first hop of X-Forwarded-For). */\n clientIp: string | null;\n /** Server-stored expiry; `null` means the key does not auto-expire. */\n expiresAt: string | null;\n /**\n * Per-key rate-limit state for this request's response, parsed from\n * `X-RateLimit-*` headers. `null` when the server didn't emit them.\n */\n rateLimit: RateLimitState | null;\n}\n\n/**\n * Result of {@link AtlaSentClient.listAuditEvents}. Extends the raw\n * wire page with a camelCase `rateLimit` alongside the snake_case\n * wire fields — the wire shape (`events`, `total`, `next_cursor`) is\n * untouched so callers that pass it to the offline verifier get\n * byte-identical behaviour.\n */\nexport interface AuditEventsResult extends AuditEventsPage {\n /**\n * Per-key rate-limit state for this request's response, parsed from\n * `X-RateLimit-*` headers. `null` when the server didn't emit them.\n */\n rateLimit: RateLimitState | null;\n}\n\n/**\n * Filter accepted by {@link AtlaSentClient.createAuditExport}. Fields\n * are snake_case to match the server's `POST /v1-audit/exports`\n * request body; an empty object requests a full-org bundle.\n */\nexport interface AuditExportRequest {\n /** Comma-joined list of event types to include (e.g. `\"evaluate.allow,policy.updated\"`). */\n types?: string;\n /** Filter to a single actor. */\n actor_id?: string;\n /** Inclusive lower bound on `occurred_at` (ISO 8601). */\n from?: string;\n /** Inclusive upper bound on `occurred_at` (ISO 8601). */\n to?: string;\n}\n\n/**\n * Result of {@link AtlaSentClient.createAuditExport}. Extends the\n * signed bundle shape with a camelCase `rateLimit`. The signed\n * envelope fields (`export_id`, `org_id`, `chain_head_hash`,\n * `event_count`, `signed_at`, `events`, `signature`) are preserved\n * byte-for-byte so the object can be handed straight to\n * `verifyAuditBundle(bundle, keys)`.\n */\nexport interface AuditExportResult extends AuditExport {\n /**\n * Per-key rate-limit state for this request's response, parsed from\n * `X-RateLimit-*` headers. `null` when the server didn't emit them.\n */\n rateLimit: RateLimitState | null;\n}\n\n/** Constructor options for {@link AtlaSentClient}. */\nexport interface AtlaSentClientOptions {\n /** Required. Your AtlaSent API key. */\n apiKey: string;\n /** API base URL. Defaults to \"https://api.atlasent.io\". */\n baseUrl?: string;\n /** Per-request timeout in milliseconds. Defaults to 10_000. */\n timeoutMs?: number;\n /**\n * Inject a fetch implementation (primarily for testing).\n * Defaults to `globalThis.fetch`.\n */\n fetch?: typeof fetch;\n /**\n * Retry policy for transient failures (network errors, timeouts,\n * 429 rate-limit, 5xx server errors, malformed responses).\n * Omit to use the default: 4 total attempts, 2 000 ms base, 16 000 ms cap,\n * full-jitter exponential backoff matching the Python SDK schedule\n * (2 s → 4 s → 8 s → 16 s).\n * Pass `{ maxAttempts: 1 }` to disable retries entirely.\n */\n retryPolicy?: import(\"./retry.js\").RetryPolicy;\n}\n\n// ── Permit lifecycle (canonical REST shapes) ──────────────────────────────────\n\n/** Permit lifecycle status. */\nexport type PermitStatus =\n | \"issued\"\n | \"verified\"\n | \"consumed\"\n | \"expired\"\n | \"revoked\";\n\n/**\n * Wire shape of a Permit row, returned by {@link AtlaSentClient.getPermit}\n * and {@link AtlaSentClient.listPermits}. Mirrors the openapi `Permit`\n * schema.\n *\n * Revocation fields (`revoked_at`, `revoked_by`, `revoke_reason`) are\n * populated only when `status === 'revoked'`; null otherwise.\n */\nexport interface PermitRecord {\n id: string;\n org_id: string;\n actor_id: string;\n action_id: string;\n target_id?: string;\n environment?: string;\n status: PermitStatus;\n issued_at: string;\n expires_at: string;\n consumed_at?: string | null;\n revoked_at?: string | null;\n revoked_by?: string | null;\n revoke_reason?: string | null;\n signature?: string;\n payload_hash?: string | null;\n decision_id?: string | null;\n}\n\n/** Optional filters for {@link AtlaSentClient.listPermits}. */\nexport interface ListPermitsRequest {\n status?: PermitStatus;\n actorId?: string;\n actionType?: string;\n /** ISO-8601 lower bound on `created_at`. */\n from?: string;\n /** ISO-8601 upper bound on `created_at`. */\n to?: string;\n /** Page size. Server max is 500; default 50. */\n limit?: number;\n /** Pass `nextCursor` from a prior response to page forward. */\n cursor?: string;\n}\n\n/** Response from {@link AtlaSentClient.listPermits}. */\nexport interface ListPermitsResponse {\n permits: PermitRecord[];\n /** Total matching rows ignoring `limit`/`cursor`. */\n total: number;\n /** Pass on next call as `cursor`. Absent when no more rows. */\n nextCursor?: string;\n rateLimit: RateLimitState | null;\n}\n\n/** Response from {@link AtlaSentClient.getPermit}. */\nexport interface GetPermitResponse {\n permit: PermitRecord;\n rateLimit: RateLimitState | null;\n}\n\n/**\n * Response from {@link AtlaSentClient.checkPermitValid}.\n *\n * Lightweight validity snapshot returned by\n * `GET /v1/permits/{permitId}/valid`. Designed for guard heartbeat\n * polling — returns only the fields needed to determine whether to\n * abort a running permit mid-execution (via {@link PermitRevoked}).\n */\nexport interface PermitValidResponse {\n /** True iff the permit is currently valid (active). */\n valid: boolean;\n /**\n * Current lifecycle status of the permit.\n * - `\"active\"` — permit is valid and in-flight.\n * - `\"expired\"` — TTL elapsed before revocation or consumption.\n * - `\"revoked\"` — administratively revoked (see `revocation_id`).\n * - `\"consumed\"` — single-use permit already consumed.\n */\n status: \"active\" | \"expired\" | \"revoked\" | \"consumed\";\n /** ISO-8601 timestamp when the permit was revoked. Populated only when `status === \"revoked\"`. */\n revoked_at?: string;\n /** Opaque identifier of the revocation record. Populated only when `status === \"revoked\"`. */\n revocation_id?: string;\n}\n\n// ── Canonical revoke / verify (REST) ──────────────────────────────────────────\n\n/** Input for {@link AtlaSentClient.revokePermitById}. */\nexport interface RevokePermitByIdInput {\n /** Operator-supplied free-text reason. Recorded on the permit row,\n * written to the audit trail, and surfaced (truncated) on later\n * verify responses. Optional but strongly encouraged. */\n reason?: string;\n}\n\n/**\n * Response from {@link AtlaSentClient.revokePermitById}.\n *\n * Returns the updated {@link PermitRecord} with `status === 'revoked'`\n * and the populated `revoked_at` / `revoked_by` / `revoke_reason`\n * fields.\n */\nexport interface RevokePermitByIdResponse {\n permit: PermitRecord;\n rateLimit: RateLimitState | null;\n}\n\n/**\n * Response from {@link AtlaSentClient.verifyPermitById}.\n *\n * Returns the canonical verification envelope (`valid`,\n * `verification_type`, `reason`, `verified_at`, `evidence`) plus the\n * legacy {@link PermitRecord} fields preserved at the top level for\n * backward compatibility. The envelope shape matches the unified\n * verify response in atlasent-api PR #352.\n */\nexport interface VerifyPermitByIdResponse {\n /** `true` iff the permit verified — i.e. unconsumed, unexpired, and signature OK. */\n valid: boolean;\n /** Always `'permit'` on this surface. */\n verification_type: \"permit\";\n /** Operator-readable explanation when `valid` is `false`; `null` on success. */\n reason: string | null;\n /** Server clock at the moment verification ran. */\n verified_at: string;\n /** Type-specific evidence — same fields as the openapi PermitVerifyEvidence schema. */\n evidence: {\n permit_id: string;\n status: PermitStatus;\n actor_id?: string;\n action_id?: string;\n expires_at?: string;\n payload_hash?: string | null;\n decision_id?: string | null;\n };\n /** Legacy: full permit row preserved at the top level. */\n permit: PermitRecord;\n rateLimit: RateLimitState | null;\n}\n\n// ── Revoke permit ─────────────────────────────────────────────────────────────\n\n/** Input for {@link AtlaSentClient.revokePermit}. */\nexport interface RevokePermitRequest {\n /** The permit ID returned by a prior evaluate() call. */\n permitId: string;\n /** Optional human-readable reason stored in the audit log. */\n reason?: string;\n}\n\n/**\n * Result of {@link AtlaSentClient.revokePermit}.\n *\n * @deprecated Use {@link RevokePermitByIdResponse} via\n * {@link AtlaSentClient.revokePermitById} — the canonical REST surface\n * (`POST /v1/permits/{id}/revoke`) returns the full updated\n * {@link PermitRecord} with `revoked_at`/`revoked_by`/`revoke_reason`\n * populated, instead of the legacy `{revoked, permitId}` envelope.\n * Will be removed in `@atlasent/sdk@3`.\n */\nexport interface RevokePermitResponse {\n /** `true` when the permit was found and successfully revoked. */\n revoked: boolean;\n /** Echo of the revoked permit's ID. */\n permitId: string;\n /** ISO-8601 timestamp of when the revocation was recorded. `undefined` when not returned by the server. */\n revokedAt?: string | undefined;\n /** Audit hash for the revocation event. `undefined` when not returned by the server. */\n auditHash?: string | undefined;\n /** Per-key rate-limit state. `null` when the server didn't emit headers. */\n rateLimit: RateLimitState | null;\n}\n\n// ── Constraint trace (preflight) ──────────────────────────────────────────────\n\n/**\n * One stage of a single policy's constraint evaluation.\n *\n * Mirrors `ConstraintTraceStage` in\n * `atlasent-api/packages/types/src/index.ts`. Emitted by the rule\n * engine when the request URL carries `?include=constraint_trace`.\n *\n * Forward-compat: extra engine-side keys are tolerated; readers\n * should not assume this is a closed shape.\n */\nexport interface ConstraintTraceStage {\n /** Engine stage name (e.g. `\"role_check\"`, `\"context\"`). */\n readonly stage: string;\n /** Optional rule identifier; absent for wrapper stages. */\n readonly rule?: string;\n /** True iff this stage's predicate fired. */\n readonly matched: boolean;\n /** Optional human-readable note from the engine. */\n readonly detail?: string;\n /** Zero-based position within the policy's `stages` array. */\n readonly order: number;\n /** Forward-compat: tolerate unknown engine-side keys without crashing. */\n readonly [key: string]: unknown;\n}\n\n/**\n * Per-policy block of a constraint trace.\n *\n * Mirrors `ConstraintTracePolicy` in\n * `atlasent-api/packages/types/src/index.ts`. The handler iterates\n * active policies in order until first non-allow; the policy that\n * produced the outer decision has `decision !== \"allow\"`.\n */\nexport interface ConstraintTracePolicy {\n /** Stable identifier of the evaluated policy. */\n readonly policy_id: string;\n /** Policy-level decision (`\"allow\"|\"deny\"|\"hold\"|\"escalate\"`). */\n readonly decision: string;\n /** Engine-side fingerprint of the bundle row. */\n readonly fingerprint: string;\n /**\n * Optional engine-computed risk score from a `risk` rule clause.\n * Distinct from the heuristic risk score on the outer envelope.\n */\n readonly risk_score?: number;\n /** Ordered stages produced while evaluating this policy. */\n readonly stages: ReadonlyArray<ConstraintTraceStage>;\n /** Forward-compat: tolerate unknown engine-side keys. */\n readonly [key: string]: unknown;\n}\n\n/**\n * Top-level constraint trace returned by\n * `/v1-evaluate?include=constraint_trace`.\n *\n * Mirrors `ConstraintTraceResponse` in\n * `atlasent-api/packages/types/src/index.ts`. Present iff the\n * caller requested the trace; the SDK's preflight helper always\n * requests it.\n */\nexport interface ConstraintTrace {\n /** Per-policy blocks in evaluation order. */\n readonly rules_evaluated: ReadonlyArray<ConstraintTracePolicy>;\n /**\n * Policy id whose evaluation produced the outer decision. Equals\n * the outer `matched_policy_id` on non-allow paths; `undefined` on\n * a clean allow (all policies passed).\n */\n readonly matching_policy_id?: string;\n /** Forward-compat: tolerate unknown engine-side keys. */\n readonly [key: string]: unknown;\n}\n\n/**\n * Result of {@link AtlaSentClient.evaluatePreflight}.\n *\n * Wraps the regular {@link EvaluateResponse} plus the\n * {@link ConstraintTrace} returned when the request URL carries\n * `?include=constraint_trace`. The whole point of preflight is to\n * surface which stages / policies WOULD fire BEFORE pushing the\n * request onto an approval queue, so workflows can reject trivially\n * defective requests at submission time and only forward viable\n * requests to a human reviewer.\n *\n * `constraintTrace` is `null` on responses from older atlasent-api\n * deployments that do not echo the trace — forward-compatible\n * degradation.\n */\nexport interface EvaluatePreflightResponse {\n /** The regular evaluate response (decision, permitId, ...). */\n readonly evaluation: EvaluateResponse;\n /**\n * The constraint trace, or `null` when the server omitted it\n * (older atlasent-api version).\n */\n readonly constraintTrace: ConstraintTrace | null;\n}\n\n// ── Streaming evaluate ────────────────────────────────────────────────────────\n\n/**\n * Options for {@link AtlaSentClient.protectStream}.\n *\n * All fields are optional; defaults are used when omitted.\n */\nexport interface StreamOptions {\n /**\n * Optional abort signal to cancel the stream from the caller side.\n */\n signal?: AbortSignal;\n /**\n * Per-event timeout in milliseconds: if no SSE event arrives within\n * this window the stream throws {@link StreamTimeoutError}.\n * Defaults to 30 000 ms (30 s). Pass `0` to disable.\n */\n timeoutMs?: number;\n /**\n * Maximum reconnection attempts on network drop before the stream\n * gives up and throws. Defaults to 3.\n */\n maxRetries?: number;\n}\n\n/** A policy decision emitted mid-stream. */\nexport interface StreamDecisionEvent {\n type: \"decision\";\n /**\n * Policy decision — canonical 4-value lowercase vocabulary:\n * `\"allow\"`, `\"deny\"`, `\"hold\"`, or `\"escalate\"`.\n *\n * Previously emitted `\"ALLOW\"` / `\"DENY\"` (uppercase, 2-value);\n * now unified with `decision_canonical`.\n *\n * @deprecated Read `decision_canonical` instead for forward-compatible\n * branching. Both fields now carry the same value. Will be\n * removed/changed in `@atlasent/sdk@3`.\n */\n decision: Decision;\n /**\n * Canonical 4-value decision, byte-identical to the wire.\n * One of `\"allow\"`, `\"deny\"`, `\"hold\"`, `\"escalate\"`.\n */\n decision_canonical: DecisionCanonical;\n /** Opaque permit identifier for a final allow. Pass to verifyPermit. */\n permitId: string;\n /** Human-readable explanation from the policy engine. */\n reason: string;\n /** Audit hash bound to this decision. */\n auditHash: string;\n /** ISO-8601 timestamp of the decision. */\n timestamp: string;\n /** When true the stream will emit done and close after this event. */\n isFinal: boolean;\n}\n\n/** An intermediate progress hint emitted before the final decision. */\nexport interface StreamProgressEvent {\n type: \"progress\";\n /** Human-readable stage name (e.g. \"policy_loading\", \"context_enrichment\"). */\n stage: string;\n /** Additional server-defined fields — forward-compat, do not rely on shape. */\n [key: string]: unknown;\n}\n\n/** Union of all events yielded by {@link AtlaSentClient.protectStream}. */\nexport type StreamEvent = StreamDecisionEvent | StreamProgressEvent;\n\n// ── Batch evaluate ────────────────────────────────────────────────────────────\n\n/**\n * A single item in a {@link AtlaSentClient.evaluateBatch} call.\n * Same shape as {@link EvaluateRequest}.\n */\nexport interface BatchEvalItem {\n /** Identifier of the calling agent. */\n agent: string;\n /** The action being authorized. */\n action: string;\n /** Arbitrary policy context. */\n context?: Record<string, unknown>;\n}\n\n/**\n * Per-item result in an {@link EvaluateBatchResponse}.\n *\n * Success items carry `decision`, `decisionId`, `permitToken`, `auditHash`,\n * and `timestamp`. Error items (when the per-item RPC layer failed) carry\n * only `index`, `error`, and optionally `message`.\n */\nexport interface EvaluateBatchResultItem {\n /** 0-based position matching the input order. */\n index: number;\n /**\n * Policy decision for this item. Present on success items.\n * `\"allow\"`, `\"deny\"`, `\"hold\"`, or `\"escalate\"`.\n */\n decision?: DecisionCanonical;\n /** Server-assigned permit / decision identifier. */\n decisionId?: string;\n /** Opaque permit token (allow decisions only). Pass to verifyPermit(). */\n permitToken?: string | null;\n /** Machine-readable denial / hold reason. */\n reason?: string;\n /** Hash-chained audit-trail entry. */\n auditHash?: string;\n /** ISO-8601 decision timestamp. */\n timestamp?: string;\n /** Error code when the item itself failed at the RPC layer. */\n error?: string;\n /** Human-readable detail when `error` is set. */\n message?: string;\n}\n\n/**\n * Response from {@link AtlaSentClient.evaluateBatch}.\n *\n * - `items` is in the same order as the input `requests` array.\n * - `partial: true` means at least one item errored at the RPC layer\n * (not a policy deny — those are surfaced via `decision: \"deny\"` on\n * the item). Check `item.error` on items without a `decision`.\n * - `replayed: true` means the response was served from the idempotency\n * cache (a prior call with the same `batchId` completed within 24 h).\n */\nexport interface BatchEvalResponse {\n /** Server-assigned (or caller-supplied) batch identifier. */\n batchId: string;\n /** Per-item results, in input order. */\n items: EvaluateBatchResultItem[];\n /** `true` when at least one item failed at the RPC layer. */\n partial: boolean;\n /** `true` when served from the idempotency cache. */\n replayed?: boolean;\n /** Rate-limit state from the batch response headers. */\n rateLimit: RateLimitState | null;\n}\n\n// ── Decisions stream ──────────────────────────────────────────────────────────\n\n/**\n * Options for {@link AtlaSentClient.subscribeDecisions}.\n */\nexport interface SubscribeDecisionsOptions {\n /**\n * Filter to specific event types (e.g. `[\"evaluate.allow\", \"evaluate.deny\"]`).\n * Omit to receive all types.\n */\n types?: string[];\n /** Filter to a specific actor ID. */\n actorId?: string;\n /**\n * Resume from a prior event. Pass the `id` of the last received event.\n * The server replays everything after that sequence position, then\n * transitions to live polling.\n */\n lastEventId?: string;\n /**\n * Maximum session duration in seconds. The server emits `session_end`\n * and closes after this window; the caller should reconnect with the\n * last received `lastEventId`. Defaults to 1800 (30 min), max 3600 (1 h).\n */\n maxSeconds?: number;\n /** Abort signal to cancel the stream. */\n signal?: AbortSignal;\n}\n\n/**\n * A single event from {@link AtlaSentClient.subscribeDecisions}.\n *\n * The `type` field maps to the audit-event type emitted by the server\n * (e.g. `\"evaluate.allow\"`, `\"evaluate.deny\"`, `\"permit.verified\"`).\n * `\"heartbeat\"` is a synthetic type emitted by the SDK — not a server\n * event — indicating the server sent a keepalive ping.\n * `\"session_end\"` signals the server-side max-seconds limit was reached;\n * reconnect with `lastEventId` to continue.\n */\nexport interface DecisionStreamEvent {\n /** Stable server-assigned ID. Pass as `lastEventId` to resume. */\n id?: string;\n /**\n * Audit-event type, e.g. `\"evaluate.allow\"`, `\"evaluate.deny\"`,\n * `\"evaluate.hold\"`, `\"permit.verified\"`, `\"permit.revoked\"`,\n * `\"heartbeat\"`, `\"session_end\"`.\n */\n type: string;\n decision?: DecisionCanonical;\n actorId?: string;\n resourceType?: string;\n resourceId?: string;\n payload?: Record<string, unknown>;\n hash?: string;\n previousHash?: string;\n occurredAt?: string;\n}\n","/**\n * Dual-shape input bridge for the v2.0.0 wire format change.\n *\n * The v2.0.0 wire format renamed the evaluate request fields:\n * OLD: { action, agent, context, api_key }\n * NEW: { action_type, actor_id, context }\n *\n * And the response fields:\n * OLD: { permitted, decision_id }\n * NEW: { decision, permit_token }\n *\n * TypeScript callers on the old v1.x request shape receive a\n * deprecation warning and are transparently upgraded to the new\n * shape. The response compat bridge normalises the legacy\n * `permitted` boolean to `decision === \"allow\"`.\n *\n * Both shims will be removed in v3.0.0.\n */\n\n/** Legacy v1.x evaluate request shape. */\nexport interface LegacyEvaluateRequest {\n action?: string;\n agent?: string;\n context?: Record<string, unknown>;\n}\n\n/** v2.0 evaluate request shape (canonical wire format). */\nexport interface V2EvaluateRequest {\n action_type: string;\n actor_id: string;\n context?: Record<string, unknown>;\n /** Populate `risk_envelope.factors` in the response (Phase C). */\n explain?: boolean;\n}\n\n/**\n * Normalise an evaluate request from either the legacy v1.x shape\n * (`action` / `agent`) or the current v2.0 shape (`action_type` /\n * `actor_id`) into the canonical v2.0 wire format.\n *\n * When the legacy shape is detected a `console.warn` deprecation\n * notice is emitted once per call-site process lifetime. The shim\n * will be removed in v3.0.0.\n */\nexport function normalizeEvaluateRequest(\n input: LegacyEvaluateRequest | V2EvaluateRequest,\n): V2EvaluateRequest {\n // Detect legacy shape: has `action` or `agent` but NOT `action_type` /\n // `actor_id`. Both old fields are optional in the legacy interface so\n // we key on the absence of the new fields.\n if ('action' in input && !('action_type' in input)) {\n // eslint-disable-next-line no-console\n console.warn(\n '[atlasent] Deprecation: action/agent request shape is deprecated. ' +\n 'Use action_type/actor_id instead. This compatibility shim will be removed in v3.0.0.',\n );\n const legacy = input as LegacyEvaluateRequest;\n const normalized: V2EvaluateRequest = {\n action_type: legacy.action!,\n actor_id: legacy.agent!,\n };\n if (legacy.context !== undefined) normalized.context = legacy.context;\n if ((legacy as any).explain !== undefined) normalized.explain = (legacy as any).explain;\n return normalized;\n }\n return input as V2EvaluateRequest;\n}\n\n/**\n * Legacy v1.x evaluate response shape returned by older server\n * deployments.\n */\nexport interface LegacyEvaluateResponse {\n permitted?: boolean;\n decision_id?: string;\n reason?: string;\n audit_hash?: string;\n timestamp?: string;\n}\n\n/** v2.0 evaluate response shape (canonical wire format). */\nexport interface V2EvaluateResponse {\n decision: 'allow' | 'deny' | 'hold' | 'escalate';\n permit_token?: string;\n request_id?: string;\n expires_at?: string;\n denial?: { reason?: string; code?: string };\n}\n\n/**\n * Normalise an evaluate response from either the legacy v1.x shape\n * (`permitted` / `decision_id`) or the current v2.0 shape\n * (`decision` / `permit_token`) into the canonical v2.0 wire format.\n *\n * Used internally by the client to tolerate older atlasent-api\n * deployments without surfacing the impedance mismatch to callers.\n */\nexport function normalizeEvaluateResponse(\n wire: LegacyEvaluateResponse | V2EvaluateResponse,\n): V2EvaluateResponse {\n if (!('decision' in wire) && 'permitted' in wire) {\n // Legacy server — map `permitted` boolean → canonical `decision`.\n const legacy = wire as LegacyEvaluateResponse;\n const normalized: V2EvaluateResponse = {\n decision: legacy.permitted ? 'allow' : 'deny',\n };\n if (legacy.decision_id !== undefined) {\n normalized.permit_token = legacy.decision_id;\n }\n if (!legacy.permitted && legacy.reason) {\n normalized.denial = { reason: legacy.reason };\n }\n return normalized;\n }\n return wire as V2EvaluateResponse;\n}\n","/**\n * Retry-policy helpers for the AtlaSent TypeScript SDK.\n *\n * This module is **pure**: no I/O, no network, no globals beyond\n * `Math.random`. The intent is that {@link AtlaSentClient} (and any\n * caller wrapping `protect()` / `evaluate()`) can ask\n * {@link isRetryable} whether to retry a given {@link AtlaSentError},\n * then ask {@link computeBackoffMs} how long to sleep before the next\n * attempt.\n *\n * Wire-up into the client itself is intentionally deferred — see\n * ROADMAP item #7 (Post-GA). Sentry breadcrumb emission is also\n * deferred; both will land together once a transport-level retry\n * loop is wired into `client.ts`.\n *\n * Retry classification (matches the server's documented contract):\n * - `network` / `timeout` → retry (transient transport)\n * - `server_error` (HTTP 5xx) → retry\n * - `rate_limited` (HTTP 429) → retry, honour `retryAfterMs`\n * - `bad_response` → retry (likely truncated body)\n * - `invalid_api_key`/`forbidden`/`bad_request` → never retry\n *\n * Backoff: capped exponential with full jitter.\n * delay = min(maxDelayMs, baseDelayMs * 2^attempt) * random[0, 1)\n *\n * \"Full jitter\" is the AWS-recommended scheme — see\n * https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/.\n * It avoids thundering-herd retries from many SDK instances that hit\n * a 429 in the same window.\n *\n * Default schedule matches the Python SDK:\n * attempt 0 (1st retry): base 2 000 ms, jittered in [0, 2 000)\n * attempt 1 (2nd retry): base 4 000 ms, jittered in [0, 4 000)\n * attempt 2 (3rd retry): base 8 000 ms, jittered in [0, 8 000)\n * attempt 3 (4th retry): capped at 16 000 ms, jittered in [0, 16 000)\n * Total attempts (including initial): 4\n */\n\nimport { AtlaSentError, type AtlaSentErrorCode } from \"./errors.js\";\n\n/**\n * Defaults for {@link RetryPolicy}.\n *\n * Matches the Python SDK's backoff schedule:\n * 2 s → 4 s → 8 s → 16 s (4 total attempts, cap at 16 s).\n */\nexport const DEFAULT_RETRY_POLICY: Required<RetryPolicy> = {\n maxAttempts: 4,\n baseDelayMs: 2_000,\n maxDelayMs: 16_000,\n};\n\n/**\n * Caller-tunable retry policy. All fields optional; missing fields\n * fall back to {@link DEFAULT_RETRY_POLICY}.\n */\nexport interface RetryPolicy {\n /**\n * Total attempts including the first try. `1` disables retries\n * entirely. Must be `>= 1`; values below are clamped to `1`.\n */\n maxAttempts?: number;\n /**\n * Initial backoff for `attempt = 0`. Doubles per attempt up to\n * `maxDelayMs`. Must be `>= 0`.\n */\n baseDelayMs?: number;\n /**\n * Hard ceiling on the per-attempt sleep, applied **before** jitter.\n * The actual sleep is uniformly distributed in `[0, ceiling]`.\n */\n maxDelayMs?: number;\n}\n\n/**\n * Error codes the SDK considers transient. A `Set` (rather than a\n * `switch`) keeps callers free to extend the policy in the future\n * without forking this module.\n */\nconst RETRYABLE_CODES: ReadonlySet<AtlaSentErrorCode> = new Set([\n \"network\",\n \"timeout\",\n \"rate_limited\",\n \"server_error\",\n \"bad_response\",\n]);\n\n/**\n * Decide whether `err` is worth a retry. Anything that isn't an\n * {@link AtlaSentError} is treated as non-retryable — the SDK's\n * transport layer always wraps fetch failures in `AtlaSentError`,\n * so a non-AtlaSent throwable is by definition a programmer bug\n * (a bad input, an assertion in user code) and should propagate.\n */\nexport function isRetryable(err: unknown): boolean {\n if (!(err instanceof AtlaSentError)) return false;\n if (err.code === undefined) return false;\n return RETRYABLE_CODES.has(err.code);\n}\n\n/**\n * Compute how long to sleep before retry attempt `attempt`\n * (zero-indexed: `attempt = 0` is the first retry, i.e. the second\n * total request). Uses capped exponential backoff with full jitter.\n *\n * When `err` carries a `retryAfterMs` (server-provided `Retry-After`\n * header), the result is `max(retryAfterMs, jitteredDelay)` — the\n * server's hint is treated as a floor so we never retry sooner than\n * the server asked.\n *\n * @param attempt Zero-indexed retry attempt (0, 1, 2, ...). For\n * the default policy this produces delays drawn from\n * [0, 2 000), [0, 4 000), [0, 8 000), [0, 16 000).\n * @param policy Optional override of {@link DEFAULT_RETRY_POLICY}.\n * @param err Optional error whose `retryAfterMs` is honoured.\n * @param random Injectable RNG, defaults to `Math.random`. Must\n * return values in `[0, 1)` to preserve the\n * distribution.\n */\nexport function computeBackoffMs(\n attempt: number,\n policy: RetryPolicy = {},\n err?: unknown,\n random: () => number = Math.random,\n): number {\n const merged = mergePolicy(policy);\n const safeAttempt = Math.max(0, Math.floor(attempt));\n // 2^attempt grows exponentially; cap before multiplying to keep the\n // intermediate value bounded for very large `attempt`.\n const exp = Math.min(safeAttempt, 30);\n const ceiling = Math.min(merged.maxDelayMs, merged.baseDelayMs * 2 ** exp);\n const jittered = Math.floor(ceiling * clampUnit(random()));\n\n const retryAfterMs =\n err instanceof AtlaSentError && typeof err.retryAfterMs === \"number\"\n ? Math.max(0, err.retryAfterMs)\n : 0;\n\n return Math.max(retryAfterMs, jittered);\n}\n\n/**\n * Returns `true` when `attempt` (zero-indexed) is below the policy's\n * `maxAttempts - 1` ceiling — i.e. when there is still budget for at\n * least one more try after this one. Convenience wrapper so retry\n * loops read top-to-bottom:\n *\n * ```ts\n * for (let attempt = 0; ; attempt++) {\n * try { return await op(); }\n * catch (err) {\n * if (!isRetryable(err) || !hasAttemptsLeft(attempt, policy)) throw err;\n * await sleep(computeBackoffMs(attempt, policy, err));\n * }\n * }\n * ```\n */\nexport function hasAttemptsLeft(\n attempt: number,\n policy: RetryPolicy = {},\n): boolean {\n const merged = mergePolicy(policy);\n return attempt + 1 < merged.maxAttempts;\n}\n\n/**\n * Merge a partial policy with {@link DEFAULT_RETRY_POLICY} and clamp\n * each field into a sensible range. Exported for tests and for\n * callers that want to log the resolved policy.\n */\nexport function mergePolicy(policy: RetryPolicy): Required<RetryPolicy> {\n const maxAttempts = Math.max(\n 1,\n Math.floor(policy.maxAttempts ?? DEFAULT_RETRY_POLICY.maxAttempts),\n );\n const baseDelayMs = Math.max(\n 0,\n policy.baseDelayMs ?? DEFAULT_RETRY_POLICY.baseDelayMs,\n );\n const maxDelayMs = Math.max(\n baseDelayMs,\n policy.maxDelayMs ?? DEFAULT_RETRY_POLICY.maxDelayMs,\n );\n return { maxAttempts, baseDelayMs, maxDelayMs };\n}\n\n/**\n * Clamp `n` into `[0, 1)`. Defends against a misbehaving injected\n * RNG returning `NaN`, `Infinity`, or a negative number.\n */\nfunction clampUnit(n: number): number {\n if (!Number.isFinite(n)) return 0;\n if (n < 0) return 0;\n if (n >= 1) return 0.999_999_999;\n return n;\n}\n","/**\n * AtlaSent HTTP client.\n *\n * Two public methods, both backed by native `fetch`:\n * - {@link AtlaSentClient.evaluate} → POST {baseUrl}/v1-evaluate\n * - {@link AtlaSentClient.verifyPermit} → POST {baseUrl}/v1-verify-permit\n *\n * Fail-closed: a clean policy DENY is returned (not thrown), but\n * network, timeout, bad response, 4xx/5xx, and rate-limit conditions\n * all throw {@link AtlaSentError}.\n */\n\nimport type {\n AuditEventsPage,\n AuditEventsQuery,\n AuditExport,\n} from \"./audit.js\";\nimport type { ReplayDecisionResponse } from \"./replay.js\";\nimport type {\n ReplayRequest,\n ReplayResponse,\n ReplayVarianceKind,\n} from \"./replay.js\";\nimport {\n AtlaSentError,\n StreamParseError,\n StreamTimeoutError,\n type AtlaSentErrorCode,\n type AtlaSentErrorInit,\n} from \"./errors.js\";\nimport { PRODUCTION_DEPLOY_ACTION } from \"./types.js\";\nimport type {\n ApiKeySelfResponse,\n AtlaSentClientOptions,\n Decision,\n AuditEventsResult,\n AuditExportRequest,\n AuditExportResult,\n ConstraintTrace,\n DecisionCanonical,\n DecisionStreamEvent,\n DeployGateEvidence,\n DeployGateRequest,\n DeployGateResponse,\n BatchEvalItem,\n BatchEvalResponse,\n EvaluateBatchResultItem,\n EvaluatePreflightResponse,\n SubscribeDecisionsOptions,\n EvaluateRequest,\n EvaluateResponse,\n GetPermitResponse,\n ListPermitsRequest,\n ListPermitsResponse,\n PermitRecord,\n PermitValidResponse,\n RateLimitState,\n RevokePermitByIdInput,\n RevokePermitByIdResponse,\n RevokePermitRequest,\n RevokePermitResponse,\n StreamDecisionEvent,\n StreamEvent,\n StreamOptions,\n StreamProgressEvent,\n VerifyPermitByIdResponse,\n VerifyPermitRequest,\n VerifyPermitResponse,\n} from \"./types.js\";\nimport {\n normalizeEvaluateRequest,\n type LegacyEvaluateRequest,\n type V2EvaluateRequest,\n} from \"./compat.js\";\nimport {\n computeBackoffMs,\n hasAttemptsLeft,\n isRetryable,\n mergePolicy,\n type RetryPolicy,\n} from \"./retry.js\";\nimport type {\n GovernanceAgent,\n GovernanceAgentEvaluation,\n GovernanceAgentFinding,\n ListGovernanceAgentsResponse,\n ListGovernanceEvaluationsQuery,\n ListGovernanceEvaluationsResponse,\n ListGovernanceFindingsQuery,\n ListGovernanceFindingsResponse,\n} from \"./governanceAgents.js\";\nimport type {\n HitlApprovalRecord,\n HitlApproveRequest,\n HitlChainHop,\n HitlCreateRequest,\n HitlEscalateRequest,\n HitlEscalation,\n HitlRejectRequest,\n ListHitlEscalationsRequest,\n ListHitlEscalationsResponse,\n} from \"./hitl.js\";\nimport type {\n GovernanceGraphQueryType,\n GovernanceGraphQueryParams,\n GovernanceGraphQueryResponse,\n GovernanceGraphResultRow,\n} from \"./governanceGraph.js\";\nimport type { IncidentTimelineResponse } from \"./incidentReconstruction.js\";\nimport type {\n ConnectorType,\n InstallConnectorInput,\n AuthenticateConnectorInput,\n UpsertEnforcementPolicyInput,\n ListConnectorsResponse,\n InstallConnectorResponse,\n AuthenticateConnectorResponse,\n SyncConnectorResponse,\n RevokeConnectorResponse,\n RotateCredentialsResponse,\n ListEnforcementPoliciesResponse,\n UpsertEnforcementPolicyResponse,\n} from \"./connectorManagement.js\";\nimport type {\n ComputeOrgRiskOptions,\n ComputeOrgRiskResponse,\n GetLatestOrgRiskResponse,\n ListOrgRiskHistoryResponse,\n} from \"./orgRiskGraph.js\";\nimport type {\n CrossOrgPermissionCheckRequest,\n CrossOrgPermissionCheckResult,\n CrossOrgPermissionCheckListParams,\n} from \"./crossOrgPermission.js\";\nimport type {\n AnomalyResponseRule,\n AnomalyResponseEvent,\n CreateAnomalyResponseRuleRequest,\n TriggerAnomalyResponseRequest,\n} from \"./anomalyResponse.js\";\nimport type {\n BudgetExceptionRequest,\n BudgetExceptionStatus,\n CreateBudgetExceptionRequest,\n ApproveBudgetExceptionRequest,\n} from \"./budgetExceptions.js\";\nimport type {\n RegulatoryAuthorityLevel,\n RegulatoryEscalation,\n RegulatoryEscalationStatus,\n CreateRegulatoryEscalationRequest,\n} from \"./regulatoryEscalation.js\";\nimport type {\n GovernanceSignalAction,\n RecordSignalActionRequest,\n RecordSignalOutcomeRequest,\n SignalActionSummary,\n} from \"./incentiveSignalFeedback.js\";\nimport type {\n CrossOrgImpersonationGrant,\n CreateImpersonationGrantRequest,\n ImpersonationToken,\n ImpersonationValidationResult,\n} from \"./crossOrgImpersonation.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.atlasent.io\";\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst SDK_VERSION = \"2.2.0\";\n\nfunction _buildUserAgent(): string {\n const isNode =\n typeof process !== \"undefined\" &&\n typeof process?.versions?.node === \"string\";\n return isNode\n ? `@atlasent/sdk/${SDK_VERSION} node/${process.version}`\n : `@atlasent/sdk/${SDK_VERSION} browser`;\n}\n\n// Soft cap on top-level context properties. Mirrors the Python SDK\n// (atlasent.models._CONTEXT_PROPERTIES_SOFT_CAP) and the OpenAPI\n// `maxProperties: 64` declaration. The hosted API is the canonical\n// enforcer; this helper warns the developer in dev rather than\n// raising, so production traffic isn't broken on the day this ships.\nconst CONTEXT_PROPERTIES_SOFT_CAP = 64;\n\nfunction _warnOversizeContext(\n context: Record<string, unknown> | undefined,\n): void {\n if (context && Object.keys(context).length > CONTEXT_PROPERTIES_SOFT_CAP) {\n // eslint-disable-next-line no-console\n console.warn(\n `[atlasent] context has ${Object.keys(context).length} top-level keys ` +\n `(soft cap ${CONTEXT_PROPERTIES_SOFT_CAP}); the server may reject this. ` +\n \"Pack richer payloads under a single top-level key.\",\n );\n }\n}\n\n/**\n * Reject non-TLS base URLs unless the dev escape hatch is set.\n *\n * `ATLASENT_ALLOW_INSECURE_HTTP=1` (Node) or\n * `globalThis.ATLASENT_ALLOW_INSECURE_HTTP === \"1\"` (browser dev) permits\n * `http://` for local fixtures — production callers never set this.\n * Non-`http(s)` schemes (data:, file:, ...) are rejected unconditionally.\n *\n * Guards `process.env` access with an explicit `typeof` check so this\n * function is safe in browser and edge-runtime environments where\n * `process` is not defined as a global.\n */\nfunction _enforceTls(baseUrl: string): string {\n const nodeEnvValue =\n typeof process !== \"undefined\" && process.env\n ? process.env.ATLASENT_ALLOW_INSECURE_HTTP\n : undefined;\n const allow =\n nodeEnvValue === \"1\" ||\n (globalThis as { ATLASENT_ALLOW_INSECURE_HTTP?: string })\n .ATLASENT_ALLOW_INSECURE_HTTP === \"1\";\n if (allow) return baseUrl;\n let parsed: URL;\n try {\n parsed = new URL(baseUrl);\n } catch {\n throw new AtlaSentError(`Invalid baseUrl: ${baseUrl}`, {\n code: \"bad_request\",\n });\n }\n if (parsed.protocol !== \"https:\") {\n throw new AtlaSentError(\n `AtlaSent baseUrl must use https:// (got ${parsed.protocol}). ` +\n `For local development, set ATLASENT_ALLOW_INSECURE_HTTP=1.`,\n { code: \"bad_request\" },\n );\n }\n return baseUrl;\n}\n\n// API-key prefix contract per atlasent-api/_shared/auth.ts:\n// \"ask_live_<entropy>\" — production\n// \"ask_test_<entropy>\" — non-production\n// Validated client-side so a mis-pasted key (with whitespace, quotes,\n// or a leftover wrapping char) trips loudly at construction rather\n// than yielding a 401 mid-conversation.\nconst API_KEY_PATTERN = /^ask_(?:live|test)_[A-Za-z0-9_-]+$/;\n\nfunction _validateApiKey(apiKey: string): string {\n if (typeof apiKey !== \"string\" || apiKey.length === 0) {\n throw new AtlaSentError(\"apiKey is required\", { code: \"invalid_api_key\" });\n }\n if (!API_KEY_PATTERN.test(apiKey)) {\n const head = apiKey.slice(0, 8);\n throw new AtlaSentError(\n `AtlaSent apiKey does not match expected shape ` +\n `\\`ask_(live|test)_<entropy>\\` (got prefix=${JSON.stringify(head)}). ` +\n \"Check for whitespace, quotes, or trailing characters.\",\n { code: \"invalid_api_key\" },\n );\n }\n return apiKey;\n}\n\n/**\n * True when running in Node.js (or a Node-compatible server runtime that\n * exposes `process.versions.node`). False in browsers and browser-like\n * environments such as jsdom / Cloudflare Workers.\n */\nconst isNode =\n typeof process !== \"undefined\" && typeof process.versions?.node === \"string\";\n\n/**\n * Node.js version string captured at module-load time so request code\n * never accesses `process` lazily — safe even if `process` is absent\n * (browsers) or replaced after load (bundlers, test environments).\n * `null` in every non-Node runtime.\n */\nconst NODE_VERSION: string | null = isNode ? process.version : null;\n\n/**\n * Raw JSON shape received from `POST /v1-evaluate`.\n *\n * Canonical fields (per `atlasent-api/.../v1-evaluate/handler.ts`):\n * decision: \"allow\" | \"deny\" | \"hold\" | \"escalate\"\n * permit_token: string (present iff decision === \"allow\")\n * request_id: string\n * expires_at?: string\n * denial?: { reason, code }\n *\n * Legacy fields kept on the type so older atlasent-api deployments\n * (pre-handler.ts entry swap) still parse cleanly. The client below\n * checks canonical first and falls back to legacy.\n */\ninterface EvaluateWire {\n decision: \"allow\" | \"deny\" | \"hold\" | \"escalate\";\n permit_token?: string;\n request_id?: string;\n expires_at?: string;\n denial?: { reason?: string; code?: string };\n /**\n * Optional sub-object — present iff the request URL carried\n * `?include=constraint_trace`. Older atlasent-api deployments\n * omit this even when `include` was requested; the preflight\n * helper degrades to `null` in that case.\n */\n constraint_trace?: unknown;\n // Legacy passthrough.\n permitted?: boolean;\n decision_id?: string;\n reason?: string;\n audit_hash?: string;\n timestamp?: string;\n risk_envelope?: {\n weighted_score: number;\n engine_decision: string;\n envelope_decision: string;\n promoted: boolean;\n hard_blocks: string[];\n factors?: Array<{ factor: string; value: number; weight: number; reason: string }>;\n };\n}\n\ninterface EvaluateBatchWireItem {\n index: number;\n decision?: string;\n decision_id?: string;\n permit_token?: string | null;\n reason?: string | null;\n audit_entry_hash?: string;\n timestamp?: string;\n error?: string;\n message?: string;\n status?: number;\n}\n\ninterface EvaluateBatchWire {\n batch_id: string;\n items: EvaluateBatchWireItem[];\n partial?: boolean;\n replayed?: boolean;\n}\n\nfunction deployGateEvidence(input: {\n permitId?: string;\n permitHash?: string;\n auditHash?: string;\n verifiedAt?: string;\n}): DeployGateEvidence {\n const evidence: DeployGateEvidence = {};\n if (input.permitId) evidence.permitId = input.permitId;\n if (input.permitHash) evidence.permitHash = input.permitHash;\n if (input.auditHash) evidence.auditHash = input.auditHash;\n if (input.verifiedAt) evidence.verifiedAt = input.verifiedAt;\n return evidence;\n}\n\n/** Raw JSON shape received from `GET /v1-api-key-self`. */\ninterface ApiKeySelfWire {\n key_id: string;\n organization_id: string;\n environment: string;\n scopes?: string[];\n allowed_cidrs?: string[] | null;\n rate_limit_per_minute: number;\n client_ip?: string | null;\n expires_at?: string | null;\n}\n\n/**\n * Raw JSON shape received from `POST /v1-verify-permit`.\n *\n * Canonical fields:\n * valid: boolean\n * outcome: \"allow\" | \"deny\"\n * verify_error_code?: string (populated on outcome === \"deny\")\n * reason?: string\n *\n * Legacy `verified` kept for backward-compat with older deployments.\n */\ninterface VerifyPermitWire {\n valid: boolean;\n outcome: \"allow\" | \"deny\";\n verify_error_code?: string;\n reason?: string;\n expires_at?: string | null;\n // Legacy passthrough.\n verified?: boolean;\n permit_hash?: string;\n timestamp?: string;\n}\n\nexport class AtlaSentClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly timeoutMs: number;\n private readonly fetchImpl: typeof fetch;\n private readonly userAgent: string;\n private readonly retryPolicy: Required<RetryPolicy>;\n\n constructor(options: AtlaSentClientOptions) {\n if (!options.apiKey || typeof options.apiKey !== \"string\") {\n throw new AtlaSentError(\"apiKey is required\", {\n code: \"invalid_api_key\",\n });\n }\n if (typeof AbortSignal.timeout !== \"function\") {\n throw new AtlaSentError(\n \"@atlasent/sdk requires AbortSignal.timeout, which is not available in this runtime. \" +\n \"Minimum supported browsers: Chrome 103+, Firefox 100+, Safari 16+. \" +\n \"Upgrade your browser or add an AbortSignal.timeout polyfill.\",\n { code: \"network\" },\n );\n }\n this.apiKey = _validateApiKey(options.apiKey);\n this.baseUrl = _enforceTls(options.baseUrl ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n \"\",\n );\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n this.userAgent = _buildUserAgent();\n this.retryPolicy = mergePolicy(options.retryPolicy ?? {});\n }\n\n /**\n * Ask the policy engine whether an agent action is permitted.\n *\n * Accepts either the current v2.0 shape (`action_type` / `actor_id`)\n * or the legacy v1.x shape (`action` / `agent`). Legacy callers\n * receive a deprecation warning via `console.warn`; the shim is\n * handled by {@link normalizeEvaluateRequest} and will be removed\n * in v3.0.0.\n *\n * A \"deny\" is **not** thrown — it is returned in\n * `response.decision`. Network errors, invalid API key, rate\n * limits, timeouts, and malformed responses throw\n * {@link AtlaSentError}.\n */\n async evaluate(\n input: EvaluateRequest | LegacyEvaluateRequest,\n ): Promise<EvaluateResponse> {\n _warnOversizeContext(input.context);\n\n // Run the dual-shape bridge: legacy {action, agent} → {action_type, actor_id}.\n // For callers already on the current EvaluateRequest shape the bridge is a\n // transparent pass-through (no warn, no allocation).\n const normalized = normalizeEvaluateRequest(\n input as LegacyEvaluateRequest | V2EvaluateRequest,\n );\n\n const body: Record<string, unknown> = {\n action_type: normalized.action_type,\n actor_id: normalized.actor_id,\n context: normalized.context ?? {},\n };\n if (normalized.explain !== undefined) body.explain = normalized.explain;\n const { body: wire, rateLimit } = await this.post<EvaluateWire>(\n \"/v1-evaluate\",\n body,\n );\n\n // Normalise decision to lowercase canonical form. API responses may\n // arrive as uppercase (legacy deployments) or lowercase (canonical);\n // we always emit lowercase so callers can rely on a stable vocabulary.\n let decision = (\n typeof wire.decision === \"string\"\n ? wire.decision.toLowerCase()\n : wire.decision\n ) as EvaluateWire[\"decision\"] | undefined;\n\n // Tolerate both canonical {decision, permit_token} and legacy\n // {permitted, decision_id} server responses.\n if (decision === undefined && typeof wire.permitted === \"boolean\") {\n decision = wire.permitted ? \"allow\" : \"deny\";\n }\n const permitToken = wire.permit_token ?? wire.decision_id;\n\n if (\n decision !== \"allow\" &&\n decision !== \"deny\" &&\n decision !== \"hold\" &&\n decision !== \"escalate\"\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-evaluate: missing `decision` (or legacy `permitted`)\",\n { code: \"bad_response\" },\n );\n }\n if (\n decision === \"allow\" &&\n (typeof permitToken !== \"string\" || permitToken.length === 0)\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-evaluate: decision='allow' but no `permit_token` (or legacy `decision_id`)\",\n { code: \"bad_response\" },\n );\n }\n\n const reason = wire.denial?.reason ?? wire.reason ?? \"\";\n const permitId = permitToken ?? \"\";\n return {\n decision,\n decision_canonical: decision,\n evaluationId: permitId,\n permitId,\n // /v1-evaluate does not return a control-plane-shaped Permit body;\n // callers needing the full record fetch GET /v1/permits/:id.\n permit: null,\n permitToken: decision === \"allow\" ? (permitToken ?? null) : null,\n reasons: reason ? [reason] : [],\n reason,\n auditHash: wire.audit_hash ?? \"\",\n timestamp: wire.timestamp ?? \"\",\n rateLimit,\n ...(wire.risk_envelope && {\n riskEnvelope: {\n weightedScore: wire.risk_envelope.weighted_score,\n engineDecision: wire.risk_envelope.engine_decision as Decision,\n envelopeDecision: wire.risk_envelope.envelope_decision as Decision,\n promoted: wire.risk_envelope.promoted,\n hardBlocks: wire.risk_envelope.hard_blocks ?? [],\n ...(wire.risk_envelope.factors && { factors: wire.risk_envelope.factors }),\n },\n }),\n };\n }\n\n /**\n * Batch evaluate — send up to 100 decisions in a single round-trip.\n *\n * Wraps `POST /v1-evaluate-batch`. The server evaluates each item\n * against the active policy bundle and returns results in the same\n * order as the input. One rate-limit token is consumed for the\n * whole batch, and one audit-chain entry lists every included\n * decision id.\n *\n * A per-item policy `deny` is **not** thrown — it appears as\n * `item.decision === \"deny\"` in the returned items. A whole-batch\n * network error, 4xx, or 5xx throws {@link AtlaSentError}.\n *\n * Requires the `v2_batch` tenant feature flag to be enabled on the\n * org (returns 404 when off). Requires scope `evaluate:write`.\n *\n * @param requests - 1–100 evaluate items.\n * @param batchId - Optional caller-supplied UUID for idempotency.\n * A retried call with the same `batchId` and identical items\n * returns the cached response within 24 h (`replayed: true`).\n */\n async evaluateBatch(\n requests: BatchEvalItem[],\n batchId?: string,\n ): Promise<BatchEvalResponse> {\n if (!Array.isArray(requests) || requests.length === 0) {\n throw new AtlaSentError(\n \"evaluateBatch: requests must be a non-empty array\",\n { code: \"bad_request\" },\n );\n }\n if (requests.length > 100) {\n throw new AtlaSentError(\n `evaluateBatch: requests.length ${requests.length} exceeds the 100-item cap`,\n { code: \"bad_request\" },\n );\n }\n\n const wireItems = requests.map((r) => ({\n action_type: r.action,\n actor_id: r.agent,\n context: r.context ?? {},\n }));\n\n const wireBody: Record<string, unknown> = { items: wireItems };\n if (batchId) wireBody.batch_id = batchId;\n\n const { body: wire, rateLimit } = await this.post<EvaluateBatchWire>(\n \"/v1-evaluate-batch\",\n wireBody,\n );\n\n const items: EvaluateBatchResultItem[] = (wire.items ?? []).map(\n (item: EvaluateBatchWireItem) => {\n const rawDecision = typeof item.decision === \"string\"\n ? item.decision.toLowerCase()\n : undefined;\n const decision = (\n rawDecision === \"allow\" ||\n rawDecision === \"deny\" ||\n rawDecision === \"hold\" ||\n rawDecision === \"escalate\"\n ? rawDecision\n : undefined\n ) as DecisionCanonical | undefined;\n\n return {\n index: item.index,\n ...(decision !== undefined ? { decision } : {}),\n ...(item.decision_id ? { decisionId: item.decision_id } : {}),\n ...(item.permit_token != null ? { permitToken: item.permit_token } : {}),\n ...(item.reason != null ? { reason: item.reason } : {}),\n ...(item.audit_entry_hash ? { auditHash: item.audit_entry_hash } : {}),\n ...(item.timestamp ? { timestamp: item.timestamp } : {}),\n ...(item.error ? { error: item.error } : {}),\n ...(item.message ? { message: item.message } : {}),\n } satisfies EvaluateBatchResultItem;\n },\n );\n\n return {\n batchId: wire.batch_id,\n items,\n partial: wire.partial ?? false,\n ...(wire.replayed ? { replayed: wire.replayed } : {}),\n rateLimit,\n };\n }\n\n /**\n * Subscribe to a live stream of decisions for this org.\n *\n * Wraps `GET /v1-decisions-stream`. The server emits one SSE frame\n * per audit event and sends a heartbeat every 15 s. The session\n * auto-closes after `maxSeconds` (default 30 min); reconnect with\n * the last received `event.id` to resume without replaying history.\n *\n * ```ts\n * const controller = new AbortController();\n * for await (const event of client.subscribeDecisions({ signal: controller.signal })) {\n * if (event.type === \"heartbeat\") continue;\n * console.log(event.type, event.decision, event.actorId);\n * if (event.type === \"session_end\") break; // reconnect\n * }\n * ```\n *\n * Requires scope `audit:read`. Requires the `v2_decisions_stream`\n * tenant feature flag (returns 404 when off).\n */\n async *subscribeDecisions(\n opts: SubscribeDecisionsOptions = {},\n ): AsyncGenerator<DecisionStreamEvent> {\n const url = new URL(`${this.baseUrl}/v1-decisions-stream`);\n if (opts.types?.length) url.searchParams.set(\"types\", opts.types.join(\",\"));\n if (opts.actorId) url.searchParams.set(\"actor_id\", opts.actorId);\n if (opts.maxSeconds !== undefined) url.searchParams.set(\"max_seconds\", String(opts.maxSeconds));\n\n const headers: Record<string, string> = {\n Accept: \"text/event-stream\",\n Authorization: `Bearer ${this.apiKey}`,\n \"User-Agent\": this.userAgent,\n // ADR-025: declare the wire-protocol version we were built\n // against. Runtime serves this version's response shape; older\n // versions outside the compatibility window get 426.\n \"X-AtlaSent-Protocol-Version\": \"1\",\n };\n if (opts.lastEventId) headers[\"Last-Event-ID\"] = opts.lastEventId;\n\n let response: Response;\n try {\n response = await this.fetchImpl(url.toString(), {\n method: \"GET\",\n headers,\n ...(opts.signal ? { signal: opts.signal } : {}),\n });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") return;\n throw new AtlaSentError(\n `Failed to connect to decisions stream: ${err instanceof Error ? err.message : String(err)}`,\n { code: \"network\" },\n );\n }\n\n if (!response.ok) {\n const code = response.status === 401 ? \"invalid_api_key\" : \"server_error\";\n throw new AtlaSentError(\n `Decisions stream returned ${response.status}`,\n { code, status: response.status },\n );\n }\n\n if (!response.body) {\n throw new AtlaSentError(\"Decisions stream response has no body\", { code: \"bad_response\" });\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder(\"utf-8\");\n let buf = \"\";\n\n try {\n while (true) {\n let chunk: Awaited<ReturnType<typeof reader.read>>;\n try {\n chunk = await reader.read();\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") return;\n throw new AtlaSentError(\n `Decisions stream read error: ${err instanceof Error ? err.message : String(err)}`,\n { code: \"network\" },\n );\n }\n if (chunk.done) break;\n\n buf += decoder.decode(chunk.value, { stream: true });\n const rawBlocks = buf.split(\"\\n\\n\");\n buf = rawBlocks.pop() ?? \"\";\n\n for (const block of rawBlocks) {\n if (!block.trim()) continue;\n\n // SSE comment / heartbeat line (\": …\")\n if (block.trimStart().startsWith(\":\")) {\n yield { type: \"heartbeat\" };\n continue;\n }\n\n let id: string | undefined;\n let eventType = \"audit_event\";\n let dataLine = \"\";\n\n for (const line of block.split(\"\\n\")) {\n if (line.startsWith(\"id:\")) id = line.slice(3).trim();\n else if (line.startsWith(\"event:\")) eventType = line.slice(6).trim();\n else if (line.startsWith(\"data:\")) dataLine = line.slice(5).trim();\n }\n\n if (!dataLine) continue;\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(dataLine) as Record<string, unknown>;\n } catch {\n continue;\n }\n\n if (eventType === \"session_end\") {\n yield { ...(id !== undefined ? { id } : {}), type: \"session_end\", payload: parsed };\n return;\n }\n\n const decision = typeof parsed.decision === \"string\"\n ? parsed.decision.toLowerCase() as DecisionCanonical\n : undefined;\n\n yield {\n ...(id !== undefined ? { id } : {}),\n type: eventType,\n ...(decision ? { decision } : {}),\n ...(typeof parsed.actor_id === \"string\" ? { actorId: parsed.actor_id } : {}),\n ...(typeof parsed.resource_type === \"string\" ? { resourceType: parsed.resource_type } : {}),\n ...(typeof parsed.resource_id === \"string\" ? { resourceId: parsed.resource_id } : {}),\n ...(parsed.payload && typeof parsed.payload === \"object\" ? { payload: parsed.payload as Record<string, unknown> } : {}),\n ...(typeof parsed.hash === \"string\" ? { hash: parsed.hash } : {}),\n ...(typeof parsed.previous_hash === \"string\" ? { previousHash: parsed.previous_hash } : {}),\n ...(typeof parsed.occurred_at === \"string\" ? { occurredAt: parsed.occurred_at } : {}),\n } satisfies DecisionStreamEvent;\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Pre-flight evaluation that always returns the constraint trace.\n *\n * Wraps `POST /v1-evaluate?include=constraint_trace`. Use this from\n * a workflow's submission step to surface trivial defects (missing\n * fields, wrong roles, mis-set context) BEFORE pushing the request\n * onto an approval queue — only requests that would actually pass\n * make it through to a human reviewer.\n *\n * Returns an {@link EvaluatePreflightResponse} carrying the regular\n * {@link EvaluateResponse} plus the {@link ConstraintTrace}. Unlike\n * {@link evaluate}, this method does NOT mark a non-allow as a\n * thrown condition — the whole point is to inspect both the outcome\n * AND the per-policy trace, so the caller branches on\n * `result.evaluation.decision` and reads `result.constraintTrace`\n * to render the failing stages.\n *\n * The constraint-trace shape mirrors `ConstraintTraceResponse` in\n * atlasent-api (`packages/types/src/index.ts`). On older\n * atlasent-api deployments that omit the trace, `constraintTrace`\n * is `null` rather than throwing — forward-compatible degradation.\n *\n * Performance: one extra round-trip on submission. Latency is\n * comparable to {@link evaluate}; the response body is fuller\n * (includes the per-stage trace) so the wire payload is larger.\n * If the caller does not need the trace, prefer {@link evaluate}.\n */\n async evaluatePreflight(\n input: EvaluateRequest,\n ): Promise<EvaluatePreflightResponse> {\n _warnOversizeContext(input.context);\n const body = {\n action_type: input.action,\n actor_id: input.agent,\n context: input.context ?? {},\n };\n const query = new URLSearchParams({ include: \"constraint_trace\" });\n const { body: wire, rateLimit } = await this.post<EvaluateWire>(\n \"/v1-evaluate\",\n body,\n query,\n );\n\n // Normalise decision to lowercase canonical form.\n let decision = (\n typeof wire.decision === \"string\"\n ? wire.decision.toLowerCase()\n : wire.decision\n ) as EvaluateWire[\"decision\"] | undefined;\n\n if (decision === undefined && typeof wire.permitted === \"boolean\") {\n decision = wire.permitted ? \"allow\" : \"deny\";\n }\n if (\n decision !== \"allow\" &&\n decision !== \"deny\" &&\n decision !== \"hold\" &&\n decision !== \"escalate\"\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-evaluate: missing `decision` (or legacy `permitted`)\",\n { code: \"bad_response\" },\n );\n }\n const permitToken = wire.permit_token ?? wire.decision_id;\n\n const reason = wire.denial?.reason ?? wire.reason ?? \"\";\n const permitId = permitToken ?? \"\";\n const evaluation: EvaluateResponse = {\n decision,\n decision_canonical: decision,\n evaluationId: permitId,\n permitId,\n // /v1-evaluate does not return a control-plane-shaped Permit body;\n // callers needing the full record fetch GET /v1/permits/:id.\n permit: null,\n permitToken: decision === \"allow\" ? (permitToken ?? null) : null,\n reasons: reason ? [reason] : [],\n reason,\n auditHash: wire.audit_hash ?? \"\",\n timestamp: wire.timestamp ?? \"\",\n rateLimit,\n ...(wire.risk_envelope && {\n riskEnvelope: {\n weightedScore: wire.risk_envelope.weighted_score,\n engineDecision: wire.risk_envelope.engine_decision as Decision,\n envelopeDecision: wire.risk_envelope.envelope_decision as Decision,\n promoted: wire.risk_envelope.promoted,\n hardBlocks: wire.risk_envelope.hard_blocks ?? [],\n ...(wire.risk_envelope.factors && { factors: wire.risk_envelope.factors }),\n },\n }),\n };\n\n // Forward-compat: if the server omits `constraint_trace` (older\n // atlasent-api version), surface trace=null rather than throwing.\n // Unknown engine-side keys inside the trace are tolerated by the\n // ConstraintTrace interface's index signature.\n let constraintTrace: ConstraintTrace | null = null;\n if (\n wire.constraint_trace !== undefined &&\n wire.constraint_trace !== null &&\n typeof wire.constraint_trace === \"object\"\n ) {\n constraintTrace = wire.constraint_trace as ConstraintTrace;\n }\n\n return { evaluation, constraintTrace };\n }\n\n /**\n * Verify that a previously issued permit is still valid.\n *\n * @deprecated Use {@link verifyPermitById} — the canonical REST\n * surface (`POST /v1/permits/{id}/verify`) returns the unified\n * verification envelope plus the full {@link PermitRecord}, instead\n * of the legacy `{verified, outcome, permitHash}` shape this method\n * emits. Will be removed in `@atlasent/sdk@3`.\n *\n * A `verified: false` response is **not** thrown — inspect the\n * returned object. Only transport / server errors throw.\n */\n async verifyPermit(\n input: VerifyPermitRequest,\n ): Promise<VerifyPermitResponse> {\n _warnOversizeContext(input.context);\n // Canonical wire shape per handler.ts: only permit_token is required.\n // action_type / actor_id are optional cross-checks; context / api_key\n // are NOT consulted by the verify handler.\n const body: Record<string, unknown> = {\n permit_token: input.permitId,\n action_type: input.action ?? \"\",\n actor_id: input.agent ?? \"\",\n };\n if (input.environment !== undefined) {\n body.environment = input.environment;\n }\n if (input.execution_hash !== undefined) {\n body.execution_hash = input.execution_hash;\n }\n const { body: wire, rateLimit } = await this.post<VerifyPermitWire>(\n \"/v1-verify-permit\",\n body,\n );\n\n // Tolerate both canonical {valid, outcome} and legacy {verified} server\n // responses.\n const valid = typeof wire.valid === \"boolean\" ? wire.valid : wire.verified;\n if (typeof valid !== \"boolean\") {\n throw new AtlaSentError(\n \"Malformed response from /v1-verify-permit: missing `valid` (or legacy `verified`)\",\n { code: \"bad_response\" },\n );\n }\n\n return {\n verified: valid,\n outcome: wire.outcome ?? \"\",\n permitHash: wire.permit_hash ?? \"\",\n timestamp: wire.timestamp ?? \"\",\n expiresAt: wire.expires_at ?? null,\n rateLimit,\n };\n }\n\n /**\n * Run the canonical Deploy Gate V1 flow:\n * evaluate `production.deploy`, verify the issued permit server-side,\n * and return allow/block plus audit/evidence metadata.\n *\n * This helper never treats a signed/offline permit artifact as sufficient\n * authorization. Execution is allowed only when `POST /v1-evaluate` returns\n * `decision: \"allow\"` with a permit AND `POST /v1-verify-permit` returns\n * `verified: true` / `valid: true`.\n */\n async deployGate(input: DeployGateRequest = {}): Promise<DeployGateResponse> {\n const agent = input.agent ?? \"ci-deploy-bot\";\n const action = input.action ?? PRODUCTION_DEPLOY_ACTION;\n const context = input.context ?? {};\n\n const evaluation = await this.evaluate({ agent, action, context });\n if (evaluation.decision !== \"allow\") {\n return {\n allowed: false,\n evaluation,\n reason:\n evaluation.reason ||\n `Deploy Gate blocked by decision=${evaluation.decision}`,\n evidence: deployGateEvidence({\n permitId: evaluation.permitId,\n auditHash: evaluation.auditHash,\n }),\n };\n }\n\n const verification = await this.verifyPermit({\n permitId: evaluation.permitId,\n agent,\n action,\n context,\n });\n\n if (!verification.verified) {\n return {\n allowed: false,\n evaluation,\n verification,\n reason: verification.outcome\n ? `Deploy Gate blocked by permit verification outcome=${verification.outcome}`\n : \"Deploy Gate blocked because permit verification failed\",\n evidence: deployGateEvidence({\n permitId: evaluation.permitId,\n permitHash: verification.permitHash,\n auditHash: evaluation.auditHash,\n verifiedAt: verification.timestamp,\n }),\n };\n }\n\n return {\n allowed: true,\n evaluation,\n verification,\n reason: evaluation.reason || \"Deploy Gate permit verified\",\n evidence: deployGateEvidence({\n permitId: evaluation.permitId,\n permitHash: verification.permitHash,\n auditHash: evaluation.auditHash,\n verifiedAt: verification.timestamp,\n }),\n };\n }\n\n /**\n * Revoke a previously-issued permit so it can no longer pass\n * {@link verifyPermit}.\n *\n * @deprecated Use {@link revokePermitById} — the canonical REST\n * surface (`POST /v1/permits/{id}/revoke`) returns the full updated\n * {@link PermitRecord} with `revoked_at`/`revoked_by`/`revoke_reason`\n * populated, instead of the legacy `{revoked, permitId}` envelope\n * this method emits. Will be removed in `@atlasent/sdk@3`.\n *\n * Use this when an agent's action is cancelled, superseded, or\n * determined to be unauthorized after the fact. The revocation is\n * recorded in the audit log with the optional `reason`.\n *\n * Throws {@link AtlaSentError} on transport / auth failures.\n */\n async revokePermit(\n input: RevokePermitRequest,\n ): Promise<RevokePermitResponse> {\n const body = {\n decision_id: input.permitId,\n reason: input.reason ?? \"\",\n api_key: this.apiKey,\n };\n const { body: wire, rateLimit } = await this.post<{\n revoked: boolean;\n decision_id: string;\n revoked_at?: string;\n audit_hash?: string;\n }>(\"/v1-revoke-permit\", body);\n\n if (\n typeof wire.revoked !== \"boolean\" ||\n typeof wire.decision_id !== \"string\"\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-revoke-permit: missing `revoked` or `decision_id`\",\n { code: \"bad_response\" },\n );\n }\n\n return {\n revoked: wire.revoked,\n permitId: wire.decision_id,\n revokedAt: wire.revoked_at,\n auditHash: wire.audit_hash,\n rateLimit,\n };\n }\n\n /**\n * Revoke a permit through the canonical REST surface\n * (`POST /v1/permits/{permitId}/revoke`).\n *\n * Returns the full updated {@link PermitRecord} with `status === 'revoked'`\n * and `revoked_at` / `revoked_by` / `revoke_reason` populated. After\n * revocation, subsequent verify calls return `410 PERMIT_REVOKED`.\n *\n * Idempotent on `409 permit_revoked` for already-revoked permits;\n * server returns the existing revoked row in that case.\n *\n * Throws {@link AtlaSentError} on `404` (permit not in calling org),\n * `409` (already in a terminal state), `410` (expired before revoke),\n * or `429` (rate limited).\n */\n async revokePermitById(\n permitId: string,\n input: RevokePermitByIdInput = {},\n ): Promise<RevokePermitByIdResponse> {\n if (!permitId) {\n throw new AtlaSentError(\"permitId is required\", { code: \"bad_request\" });\n }\n const body: { reason?: string } = {};\n if (input.reason !== undefined) body.reason = input.reason;\n const { body: wire, rateLimit } = await this.post<PermitRecord>(\n `/v1/permits/${encodeURIComponent(permitId)}/revoke`,\n body,\n );\n return { permit: wire, rateLimit };\n }\n\n /**\n * Verify a permit through the canonical REST surface\n * (`POST /v1/permits/{permitId}/verify`).\n *\n * Returns the unified verification envelope (`valid`,\n * `verification_type: 'permit'`, `reason`, `verified_at`, `evidence`)\n * plus the full {@link PermitRecord} fields preserved at the top\n * level. The `valid` field is the contract — pin to it.\n *\n * A `valid: false` is **not** thrown when the server returns 200 with\n * a denial reason (matches the verify-shape unification on the wire);\n * it is thrown on 4xx (`404` not found, `410` expired/consumed).\n */\n async verifyPermitById(permitId: string): Promise<VerifyPermitByIdResponse> {\n if (!permitId) {\n throw new AtlaSentError(\"permitId is required\", { code: \"bad_request\" });\n }\n const { body: wire, rateLimit } = await this.post<\n VerifyPermitByIdResponse & PermitRecord\n >(`/v1/permits/${encodeURIComponent(permitId)}/verify`, {});\n // Server returns the canonical envelope merged with the Permit row\n // (allOf in openapi). Pull out the legacy permit row into `permit`\n // for callers that want it as a sub-object too.\n const { valid, verification_type, reason, verified_at, evidence, ...row } =\n wire as VerifyPermitByIdResponse & PermitRecord;\n return {\n valid,\n verification_type,\n reason,\n verified_at,\n evidence,\n permit: row as PermitRecord,\n rateLimit,\n };\n }\n\n /**\n * Get a single permit's full lifecycle state.\n *\n * Calls `GET /v1/permits/{permitId}` (the canonical REST surface).\n * Returns `status`, all timestamps, `revoked_at` / `revoked_by` /\n * `revoke_reason` (when applicable), and the bound `payload_hash`\n * / `decision_id`.\n *\n * Operator-facing introspection — answers \"what state is this permit\n * in, and why?\" without reading audit logs.\n *\n * Throws {@link AtlaSentError} on `404` (permit not in calling org)\n * or `410` (expired before retrieval).\n */\n async getPermit(permitId: string): Promise<GetPermitResponse> {\n if (!permitId) {\n throw new AtlaSentError(\"permitId is required\", { code: \"bad_request\" });\n }\n const { body: wire, rateLimit } = await this.get<PermitRecord>(\n `/v1/permits/${encodeURIComponent(permitId)}`,\n );\n return { permit: wire, rateLimit };\n }\n\n /**\n * Poll whether a permit is currently valid.\n *\n * Calls `GET /v1/permits/{permitId}/valid` — a lightweight read\n * returning only the status snapshot optimised for guard heartbeat\n * polling. Guards with `permitRevalidationIntervalMs` set race this\n * against `tool.execute()` and throw {@link PermitRevoked} when\n * `status === \"revoked\"` arrives.\n *\n * Throws {@link AtlaSentError} on transport / auth failures.\n */\n async checkPermitValid(permitId: string): Promise<PermitValidResponse> {\n if (!permitId) {\n throw new AtlaSentError(\"permitId is required\", { code: \"bad_request\" });\n }\n const { body } = await this.get<PermitValidResponse>(\n `/v1/permits/${encodeURIComponent(permitId)}/valid`,\n );\n return body;\n }\n\n /**\n * List permits issued to the calling org, most-recently-issued first.\n *\n * Calls `GET /v1/permits` (the canonical REST surface). Cursor-paged.\n * Filters narrow on server side; pagination uses the `created_at`\n * timestamp opaquely (`nextCursor`).\n *\n * Designed for incident review, debugging, and compliance\n * reconstruction.\n */\n async listPermits(\n input: ListPermitsRequest = {},\n ): Promise<ListPermitsResponse> {\n const params = new URLSearchParams();\n if (input.status) params.set(\"status\", input.status);\n if (input.actorId) params.set(\"actor_id\", input.actorId);\n if (input.actionType) params.set(\"action_type\", input.actionType);\n if (input.from) params.set(\"from\", input.from);\n if (input.to) params.set(\"to\", input.to);\n if (input.limit !== undefined) params.set(\"limit\", String(input.limit));\n if (input.cursor) params.set(\"cursor\", input.cursor);\n\n const { body: wire, rateLimit } = await this.get<{\n permits?: PermitRecord[];\n total?: number;\n next_cursor?: string;\n }>(\"/v1/permits\", params);\n\n if (!Array.isArray(wire.permits)) {\n throw new AtlaSentError(\n \"Malformed response from /v1/permits: missing `permits` array\",\n { code: \"bad_response\" },\n );\n }\n const result: ListPermitsResponse = {\n permits: wire.permits,\n total: typeof wire.total === \"number\" ? wire.total : wire.permits.length,\n rateLimit,\n };\n if (wire.next_cursor !== undefined) result.nextCursor = wire.next_cursor;\n return result;\n }\n\n /**\n * Self-introspection: ask the server to describe the API key this\n * client was constructed with. Returns the key's ID, organization,\n * environment, scopes, IP allowlist, per-minute rate limit, the\n * client IP the server observed, and the expiry (if any).\n *\n * Never includes the raw key or its hash. Safe to surface in operator\n * dashboards. Useful for `IP_NOT_ALLOWED` debugging (the server tells\n * you exactly which IP it saw) and for proactive expiry warnings.\n *\n * Throws {@link AtlaSentError} on transport / auth failures — same\n * taxonomy as {@link AtlaSentClient.evaluate}.\n */\n async keySelf(): Promise<ApiKeySelfResponse> {\n const { body: wire, rateLimit } =\n await this.get<ApiKeySelfWire>(\"/v1-api-key-self\");\n\n if (\n typeof wire.key_id !== \"string\" ||\n typeof wire.organization_id !== \"string\"\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-api-key-self: missing `key_id` or `organization_id`\",\n { code: \"bad_response\" },\n );\n }\n\n return {\n keyId: wire.key_id,\n organizationId: wire.organization_id,\n environment: wire.environment,\n scopes: wire.scopes ?? [],\n allowedCidrs: wire.allowed_cidrs ?? null,\n rateLimitPerMinute: wire.rate_limit_per_minute,\n clientIp: wire.client_ip ?? null,\n expiresAt: wire.expires_at ?? null,\n rateLimit,\n };\n }\n\n /**\n * List persisted audit events for the authenticated organization\n * (`GET /v1-audit/events`). Returned rows are wire-identical with\n * the server: snake_case field names, including `previous_hash` and\n * the `hash` chain, so the response can be fed straight into the\n * offline verifier when paired with a signed export.\n *\n * `query.types` is a comma-joined list (e.g.\n * `\"evaluate.allow,policy.updated\"`). `cursor` is the opaque\n * `next_cursor` from the prior page. All fields are optional; the\n * server defaults `limit` to 50 (capped at 500).\n *\n * Throws {@link AtlaSentError} on transport / auth failures — same\n * taxonomy as {@link AtlaSentClient.evaluate}.\n */\n async listAuditEvents(\n query: AuditEventsQuery = {},\n ): Promise<AuditEventsResult> {\n const { body: wire, rateLimit } = await this.get<AuditEventsPage>(\n \"/v1-audit/events\",\n buildAuditEventsQuery(query),\n );\n\n if (!Array.isArray(wire.events) || typeof wire.total !== \"number\") {\n throw new AtlaSentError(\n \"Malformed response from /v1-audit/events: missing `events` or `total`\",\n { code: \"bad_response\" },\n );\n }\n\n return { ...wire, rateLimit };\n }\n\n /**\n * Request a signed audit export bundle\n * (`POST /v1-audit/exports`). The returned object is wire-identical\n * with the server — `signature`, `chain_head_hash`, `events`, and\n * friends survive untouched so the bundle can be persisted to disk\n * and handed to the offline verifier (`verifyBundle` /\n * `verifyAuditBundle`) without any reshaping.\n *\n * Pass `filter.types`, `filter.from`, `filter.to`, or `filter.actor_id`\n * to narrow the export; omit for a full-org bundle. `rateLimit` is\n * attached alongside the wire fields for observability.\n *\n * Throws {@link AtlaSentError} on transport / auth failures — same\n * taxonomy as {@link AtlaSentClient.evaluate}.\n */\n async createAuditExport(\n filter: AuditExportRequest = {},\n ): Promise<AuditExportResult> {\n const { body: wire, rateLimit } = await this.post<AuditExport>(\n \"/v1-audit/exports\",\n filter,\n );\n\n if (\n typeof wire.export_id !== \"string\" ||\n typeof wire.chain_head_hash !== \"string\" ||\n !Array.isArray(wire.events)\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-audit/exports: missing `export_id`, `chain_head_hash`, or `events`\",\n { code: \"bad_response\" },\n );\n }\n\n return { ...wire, rateLimit };\n }\n\n /**\n * Re-evaluate a recorded decision against its originally-pinned policy\n * bundle and engine version, and report whether the result agrees with\n * what was recorded.\n *\n * Wraps `POST /v1-decisions-replay/:id/replay`. **Side-effect-free** — no\n * audit chain row is written and no permit is issued (per ADR-016).\n * Useful for compliance review, regression testing of bundle changes,\n * and post-incident investigation.\n *\n * Outcomes encoded in the response:\n * - `variance: \"NONE\"` — replay agrees with the original decision.\n * - `variance: \"DECISION_CHANGED\"` — same envelope, same bundle, different\n * decision. Almost always indicates non-determinism in a rule\n * (e.g. wall-clock comparison) and warrants investigation.\n * - `variance: \"ENVELOPE_DRIFT\"` — the recorded request envelope no longer\n * hashes to the recorded value. The replay short-circuits without\n * running the engine; `replay_decision` is absent. Treat as evidence\n * of substrate tamper or a recorder bug.\n *\n * Server-side 409 responses (replay refused because the engine version\n * does not accept replay, or because no bundle was pinned) surface as\n * `AtlaSentError` with `code: \"replay_not_eligible\"` — callers should\n * treat them as expected for old / un-pinned decisions, not as bugs.\n *\n * Requires the `evaluate:write` API key scope.\n *\n * @param decisionId The UUID of the recorded decision to replay.\n * Matches `execution_evaluations.request_id`.\n *\n * @example\n * ```ts\n * const result = await client.replayDecision(\"dec_abc123\");\n * if (result.variance === \"DECISION_CHANGED\") {\n * console.warn(\n * `Decision ${result.decision_id} changed on replay: ` +\n * `${result.original_decision} → ${result.replay_decision}`,\n * );\n * }\n * ```\n */\n async replayDecision(\n decisionId: string,\n ): Promise<ReplayDecisionResponse & { rateLimit: RateLimitState | null }> {\n if (typeof decisionId !== \"string\" || decisionId.length === 0) {\n throw new AtlaSentError(\"decisionId is required\", {\n code: \"bad_request\",\n });\n }\n\n const path = `/v1-decisions-replay/${encodeURIComponent(decisionId)}/replay`;\n const { body: wire, rateLimit } = await this.post<ReplayDecisionResponse>(\n path,\n {},\n );\n\n // Defensive validation. The replay endpoint is alpha (see\n // STABLE_V2_PROMOTION.md) — wire shapes can shift without a\n // deprecation cycle, so guard the contract fields callers will\n // branch on rather than trusting the cast.\n if (\n typeof wire.decision_id !== \"string\" ||\n typeof wire.original_decision !== \"string\" ||\n typeof wire.engine_version_kind !== \"string\" ||\n typeof wire.accepts_replay !== \"boolean\" ||\n typeof wire.variance !== \"string\" ||\n typeof wire.envelope_verification !== \"string\" ||\n typeof wire.replayed_at !== \"string\"\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-decisions-replay/:id/replay: missing required fields\",\n { code: \"bad_response\" },\n );\n }\n\n return { ...wire, rateLimit };\n }\n\n /**\n * ADR-015 Phase C — SDK-canonical replay runtime.\n *\n * Re-evaluates a recorded decision against its originally-pinned policy\n * bundle and engine version via `POST /v1/decisions/:id/replay`.\n * Side-effect-free server-side: no audit chain row is written and no\n * permit is issued (ADR-016 `mode: \"replay\"` sentinel).\n *\n * Differences from {@link replayDecision} (the 2.7.0 raw-wire surface):\n *\n * | | `replayDecision()` | `replay()` |\n * | --- | --- | --- |\n * | Path | `/v1-decisions-replay/:id/replay` | `/v1/decisions/:id/replay` |\n * | Variance | raw wire (`DECISION_CHANGED`) | SDK-canonical (`POLICY_DRIFT`) |\n * | 409 handling | throws `AtlaSentError` | returns `ENGINE_DRIFT` / `BUNDLE_MISSING` |\n * | Input shape | `decisionId: string` | `{ evaluationId }` |\n *\n * **Never throws on `409 replay_not_eligible`** — instead returns a\n * `ReplayResponse` with `varianceKind: \"ENGINE_DRIFT\"` (engine retired\n * beyond archival window) or `\"BUNDLE_MISSING\"` (no bundle pinned on\n * the original evaluation). Callers can always `switch` on\n * `result.varianceKind` without a try/catch.\n *\n * Fix-forward note: this method was originally landed in PR #275 but\n * dropped from the squash merge. The TS types (`ReplayResponse`,\n * `ReplayRequest`) and CHANGELOG made it through; the method itself\n * did not. Restored here to match the Python {@link\n * AtlaSentClient}.replay() that landed in atlasent-sdk@2.6.0 (Python).\n */\n async replay(input: ReplayRequest): Promise<ReplayResponse> {\n if (!input || typeof input.evaluationId !== \"string\" || input.evaluationId.length === 0) {\n throw new AtlaSentError(\"evaluationId is required\", {\n code: \"bad_request\",\n });\n }\n\n const path = `/v1/decisions/${encodeURIComponent(input.evaluationId)}/replay`;\n let wire: Record<string, unknown>;\n let rateLimit: RateLimitState | null;\n try {\n const result = await this.post<Record<string, unknown>>(path, {});\n wire = result.body;\n rateLimit = result.rateLimit;\n } catch (err) {\n if (err instanceof AtlaSentError && err.status === 409) {\n const msg = (err.message ?? \"\").toLowerCase();\n const varianceKind: ReplayVarianceKind = msg.includes(\"bundle\")\n ? \"BUNDLE_MISSING\"\n : \"ENGINE_DRIFT\";\n return {\n decisionId: input.evaluationId,\n varianceKind,\n originalDecision: \"deny\",\n acceptsReplay: false,\n replayedAt: new Date().toISOString(),\n rateLimit: null,\n };\n }\n throw err;\n }\n\n // Map raw wire variance → SDK-canonical. Unknown values default to\n // NONE per the additive-contract policy (the SDK never breaks on a\n // forward-introduced wire kind).\n const VARIANCE_MAP: Record<string, ReplayVarianceKind> = {\n NONE: \"NONE\",\n DECISION_CHANGED: \"POLICY_DRIFT\",\n ENVELOPE_DRIFT: \"ENVELOPE_DRIFT\",\n CHAIN_TAMPER: \"CHAIN_TAMPER\",\n BUNDLE_MISSING: \"BUNDLE_MISSING\",\n ENGINE_DRIFT: \"ENGINE_DRIFT\",\n };\n const rawVariance = typeof wire.variance === \"string\" ? wire.variance : \"\";\n const varianceKind: ReplayVarianceKind = VARIANCE_MAP[rawVariance] ?? \"NONE\";\n\n const replayDec = typeof wire.replay_decision === \"string\"\n ? (wire.replay_decision.toLowerCase() as DecisionCanonical)\n : undefined;\n const originalDec = (\n typeof wire.original_decision === \"string\"\n ? wire.original_decision.toLowerCase()\n : \"deny\"\n ) as DecisionCanonical;\n\n const response: ReplayResponse = {\n decisionId: typeof wire.decision_id === \"string\" ? wire.decision_id : input.evaluationId,\n varianceKind,\n originalDecision: originalDec,\n acceptsReplay: typeof wire.accepts_replay === \"boolean\" ? wire.accepts_replay : true,\n replayedAt: typeof wire.replayed_at === \"string\" ? wire.replayed_at : new Date().toISOString(),\n rateLimit,\n };\n if (typeof wire.original_deny_code === \"string\") response.originalDenyCode = wire.original_deny_code;\n if (replayDec !== undefined) response.replayedDecision = replayDec;\n if (typeof wire.replay_deny_code === \"string\") response.replayedDenyCode = wire.replay_deny_code;\n if (typeof wire.engine_version === \"string\") response.engineVersion = wire.engine_version;\n if (typeof wire.engine_version_kind === \"string\") response.engineVersionKind = wire.engine_version_kind;\n if (typeof wire.envelope_verification === \"string\") response.envelopeVerification = wire.envelope_verification;\n return response;\n }\n\n /**\n * Open a streaming evaluation session against `POST /v1-evaluate-stream`.\n *\n * Yields {@link StreamDecisionEvent} and {@link StreamProgressEvent} objects\n * as the server emits them. The iterator ends cleanly when the server sends\n * `event: done`; it throws {@link AtlaSentError} on transport errors or when\n * the server sends `event: error`.\n *\n * The final {@link StreamDecisionEvent} (isFinal: true) carries a `permitId`\n * suitable for passing to {@link verifyPermit} after the stream closes.\n *\n * Hardening:\n * - Throws {@link StreamTimeoutError} when no event arrives within\n * `opts.timeoutMs` (default 30 s). Pass `0` to disable.\n * - Retries up to `opts.maxRetries` times (default 3) with 1 s / 2 s / 4 s\n * delays on network drop (before a terminal event). Sends `Last-Event-ID`\n * on reconnect when the server has emitted event IDs.\n * - Throws {@link StreamParseError} on partial / malformed JSON rather than\n * crashing with a raw `SyntaxError`.\n * - Closes cleanly on `event: done` or a decision event with `done: true`.\n *\n * ```ts\n * for await (const event of client.protectStream({ agent, action })) {\n * if (event.type === \"decision\" && event.isFinal) {\n * await client.verifyPermit({ permitId: event.permitId });\n * }\n * }\n * ```\n */\n async *protectStream(\n input: EvaluateRequest,\n opts: StreamOptions = {},\n ): AsyncIterable<StreamEvent> {\n const streamTimeoutMs = opts.timeoutMs ?? 30_000;\n const maxRetries = opts.maxRetries ?? 3;\n\n const body = {\n action: input.action,\n agent: input.agent,\n context: input.context ?? {},\n api_key: this.apiKey,\n };\n\n const requestId = globalThis.crypto.randomUUID();\n const url = `${this.baseUrl}/v1-evaluate-stream`;\n\n let lastEventId: string | undefined;\n let retryCount = 0;\n\n while (true) {\n const headers: Record<string, string> = {\n Accept: \"text/event-stream\",\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n \"User-Agent\": this.userAgent,\n // ADR-025: wire-protocol version declared on every request.\n \"X-AtlaSent-Protocol-Version\": \"1\",\n \"X-Request-ID\": requestId,\n };\n if (lastEventId !== undefined) {\n headers[\"Last-Event-ID\"] = lastEventId;\n }\n\n const connectionTimeoutSignal = AbortSignal.timeout(this.timeoutMs);\n const signal = opts.signal\n ? (\n AbortSignal as unknown as { any(s: AbortSignal[]): AbortSignal }\n ).any([connectionTimeoutSignal, opts.signal])\n : connectionTimeoutSignal;\n\n let response: Response;\n try {\n response = await this.fetchImpl(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal,\n });\n } catch (err) {\n const mapped = mapFetchError(err, requestId);\n if (mapped.code === \"network\" && retryCount < maxRetries) {\n retryCount++;\n await sleep(1_000 * Math.pow(2, retryCount - 1)); // 1s, 2s, 4s\n continue;\n }\n throw mapped;\n }\n\n if (!response.ok) {\n throw await buildHttpError(response, requestId);\n }\n\n if (!response.body) {\n throw new AtlaSentError(\"Expected streaming body from AtlaSent API\", {\n code: \"bad_response\",\n status: response.status,\n requestId,\n });\n }\n\n let streamDone = false;\n let networkDrop = false;\n\n try {\n for await (const event of parseSseStream(\n response.body,\n requestId,\n streamTimeoutMs,\n (id) => {\n lastEventId = id;\n },\n )) {\n yield event;\n if (event.type === \"decision\" && event.isFinal) {\n streamDone = true;\n }\n }\n // parseSseStream returned normally (saw event: done or stream ended)\n streamDone = true;\n } catch (err) {\n if (err instanceof AtlaSentError && err.code === \"network\") {\n networkDrop = true;\n } else {\n throw err;\n }\n }\n\n if (streamDone) break;\n\n // Network drop before terminal event — attempt reconnect\n if (networkDrop && retryCount < maxRetries) {\n retryCount++;\n await sleep(1_000 * Math.pow(2, retryCount - 1)); // 1s, 2s, 4s\n continue;\n }\n if (networkDrop) {\n throw new AtlaSentError(\n `AtlaSent stream dropped after ${retryCount} reconnection attempts`,\n { code: \"network\", requestId },\n );\n }\n break;\n }\n }\n\n private async post<T>(\n path: string,\n body: unknown,\n query?: URLSearchParams,\n ): Promise<{ body: T; rateLimit: RateLimitState | null }> {\n return this.request<T>(path, \"POST\", body, query);\n }\n\n private async get<T>(\n path: string,\n query?: URLSearchParams,\n ): Promise<{ body: T; rateLimit: RateLimitState | null }> {\n return this.request<T>(path, \"GET\", undefined, query);\n }\n\n private async request<T>(\n path: string,\n method: \"GET\" | \"POST\",\n body: unknown,\n query: URLSearchParams | undefined,\n ): Promise<{ body: T; rateLimit: RateLimitState | null }> {\n const qs =\n query && Array.from(query).length > 0 ? `?${query.toString()}` : \"\";\n const url = `${this.baseUrl}${path}${qs}`;\n const requestId = globalThis.crypto.randomUUID();\n\n /**\n * Canonical auth header. The API also accepts X-AtlaSent-Key for legacy\n * compatibility but that path is deprecated and will be removed in a future\n * version. Always use Authorization: Bearer <api_key>.\n */\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n \"User-Agent\": this.userAgent,\n \"X-Request-ID\": requestId,\n // ADR-025: wire-protocol version declared on every request.\n \"X-AtlaSent-Protocol-Version\": \"1\",\n };\n if (method === \"POST\") headers[\"Content-Type\"] = \"application/json\";\n\n const bodyStr = method === \"POST\" ? JSON.stringify(body) : undefined;\n\n for (let attempt = 0; ; attempt++) {\n const init: RequestInit = {\n method,\n headers,\n signal: AbortSignal.timeout(this.timeoutMs),\n };\n if (bodyStr !== undefined) init.body = bodyStr;\n\n let response: Response;\n try {\n response = await this.fetchImpl(url, init);\n } catch (err) {\n const mapped = mapFetchError(err, requestId);\n if (isRetryable(mapped) && hasAttemptsLeft(attempt, this.retryPolicy)) {\n await sleep(computeBackoffMs(attempt, this.retryPolicy, mapped));\n continue;\n }\n throw mapped;\n }\n\n if (!response.ok) {\n const httpErr = await buildHttpError(response, requestId);\n if (\n isRetryable(httpErr) &&\n hasAttemptsLeft(attempt, this.retryPolicy)\n ) {\n await sleep(computeBackoffMs(attempt, this.retryPolicy, httpErr));\n continue;\n }\n throw httpErr;\n }\n\n let parsed: unknown;\n try {\n parsed = await response.json();\n } catch (err) {\n const jsonErr = new AtlaSentError(\n \"Invalid JSON response from AtlaSent API\",\n {\n code: \"bad_response\",\n status: response.status,\n requestId,\n cause: err,\n },\n );\n if (\n isRetryable(jsonErr) &&\n hasAttemptsLeft(attempt, this.retryPolicy)\n ) {\n await sleep(computeBackoffMs(attempt, this.retryPolicy, jsonErr));\n continue;\n }\n throw jsonErr;\n }\n\n if (parsed === null || typeof parsed !== \"object\") {\n const shapeErr = new AtlaSentError(\n \"Expected a JSON object from AtlaSent API\",\n {\n code: \"bad_response\",\n status: response.status,\n requestId,\n },\n );\n if (\n isRetryable(shapeErr) &&\n hasAttemptsLeft(attempt, this.retryPolicy)\n ) {\n await sleep(computeBackoffMs(attempt, this.retryPolicy, shapeErr));\n continue;\n }\n throw shapeErr;\n }\n\n return {\n body: parsed as T,\n rateLimit: parseRateLimitHeaders(response.headers),\n };\n }\n }\n\n /**\n * Open a new HITL escalation. Bridges a `hold` outcome from\n * `protect()` to the approval queue: an agent that receives a\n * `hold` decision calls this to enroll the proposed action for\n * human review. The returned escalation can then be polled with\n * `getHitlEscalation()` or driven to terminal by\n * `approveHitlEscalation()` / `rejectHitlEscalation()`.\n *\n * Quorum, pool size, fallback decision and routing inherit from\n * the server-side policy when omitted from `input`.\n *\n * Calls `POST /v1/hitl`.\n */\n async createHitlEscalation(\n input: HitlCreateRequest,\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.post<HitlEscalation>(\n \"/v1/hitl\",\n input,\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * List HITL escalations for the calling org. Defaults to\n * `status=pending`; pass `status` to query other queues\n * (`escalated`, `approved`, `rejected`, `auto_approved`,\n * `timed_out`).\n *\n * Calls `GET /v1/hitl`.\n */\n async listHitlEscalations(input: ListHitlEscalationsRequest = {}): Promise<{\n data: ListHitlEscalationsResponse;\n rateLimit: RateLimitState | null;\n }> {\n const params = new URLSearchParams();\n if (input.status) params.set(\"status\", input.status);\n if (input.agentId) params.set(\"agent_id\", input.agentId);\n if (input.assignedToUserId)\n params.set(\"assigned_to_user_id\", input.assignedToUserId);\n if (input.limit !== undefined) params.set(\"limit\", String(input.limit));\n if (input.cursor) params.set(\"cursor\", input.cursor);\n const { body, rateLimit } = await this.get<ListHitlEscalationsResponse>(\n \"/v1/hitl\",\n params,\n );\n return { data: body, rateLimit };\n }\n\n /**\n * Get a HITL escalation. The server payload includes a live\n * `quorum_progress` snapshot when the escalation is still open.\n *\n * Calls `GET /v1/hitl/:id`.\n */\n async getHitlEscalation(\n escalationId: string,\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n if (!escalationId) {\n throw new AtlaSentError(\"escalationId is required\", {\n code: \"bad_request\",\n });\n }\n const { body, rateLimit } = await this.get<HitlEscalation>(\n `/v1/hitl/${encodeURIComponent(escalationId)}`,\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * List per-approver vote rows for an escalation.\n * Calls `GET /v1/hitl/:id/approvals`.\n */\n async listHitlApprovals(escalationId: string): Promise<{\n approvals: HitlApprovalRecord[];\n rateLimit: RateLimitState | null;\n }> {\n const { body, rateLimit } = await this.get<{\n approvals: HitlApprovalRecord[];\n }>(`/v1/hitl/${encodeURIComponent(escalationId)}/approvals`);\n return { approvals: body.approvals ?? [], rateLimit };\n }\n\n /**\n * List the escalation chain hops for an escalation. Each `/escalate`\n * call appends one row.\n * Calls `GET /v1/hitl/:id/chain`.\n */\n async getHitlChain(\n escalationId: string,\n ): Promise<{ chain: HitlChainHop[]; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.get<{ chain: HitlChainHop[] }>(\n `/v1/hitl/${encodeURIComponent(escalationId)}/chain`,\n );\n return { chain: body.chain ?? [], rateLimit };\n }\n\n /**\n * Record an approve vote. Resolves the escalation only once the\n * server-side quorum count is satisfied; before that the response\n * carries a refreshed escalation row with the latest\n * `quorum_progress`.\n *\n * Calls `POST /v1/hitl/:id/approve`. The server returns 409\n * `duplicate_vote` if the same principal has already voted, and\n * 409 `already_rejected` if a concurrent reject crossed the line.\n */\n async approveHitlEscalation(\n escalationId: string,\n input: HitlApproveRequest = {},\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.post<HitlEscalation>(\n `/v1/hitl/${encodeURIComponent(escalationId)}/approve`,\n input,\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * Record a reject vote. Reject is short-circuit terminal — a single\n * reject closes the escalation regardless of how many approves have\n * accumulated.\n *\n * Calls `POST /v1/hitl/:id/reject`.\n */\n async rejectHitlEscalation(\n escalationId: string,\n input: HitlRejectRequest = {},\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.post<HitlEscalation>(\n `/v1/hitl/${encodeURIComponent(escalationId)}/reject`,\n input,\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * Re-route an open escalation to a higher tier. Bounded by the\n * escalation's `max_escalation_depth` — the server returns 409\n * `chain_exhausted` and applies the configured fallback decision\n * once the ceiling is hit.\n *\n * Calls `POST /v1/hitl/:id/escalate`.\n */\n async escalateHitlEscalation(\n escalationId: string,\n input: HitlEscalateRequest,\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.post<HitlEscalation>(\n `/v1/hitl/${encodeURIComponent(escalationId)}/escalate`,\n input,\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * Manually apply the escalation's `fallback_decision`. Useful for\n * admin recovery of a hung escalation when the cron sweeper hasn't\n * run yet, or to short-circuit a stuck flow during incident\n * response.\n *\n * Calls `POST /v1/hitl/:id/timeout`.\n */\n async timeoutHitlEscalation(\n escalationId: string,\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.post<HitlEscalation>(\n `/v1/hitl/${encodeURIComponent(escalationId)}/timeout`,\n {},\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * Run a named governance graph traversal query.\n *\n * Dispatches to `GET /v1/governance/graph/query?type=<queryType>`.\n * Each query type returns a different row shape — the return type\n * narrows automatically based on the literal `queryType` argument.\n *\n * `\"user_approvals\"` requires `params.actor_id` — the server returns\n * a 400 if it is absent.\n */\n async queryGovernanceGraph<T extends GovernanceGraphQueryType>(\n queryType: T,\n params: GovernanceGraphQueryParams = {},\n ): Promise<GovernanceGraphQueryResponse<T>> {\n const qs = new URLSearchParams({ type: queryType });\n if (params.actor_id) qs.set(\"actor_id\", params.actor_id);\n const { body, rateLimit } = await this.get<{\n query_type: T;\n results: GovernanceGraphResultRow<T>[];\n org_id: string;\n }>(\"/v1/governance/graph/query\", qs);\n return { ...body, rateLimit };\n }\n\n /**\n * Reconstruct the multi-system execution timeline for a specific incident.\n *\n * Calls `GET /v1/governance/timeline/incident/{incidentId}`. Backed\n * server-side by `reconstruct_incident_chains_v2()`, which fixes the\n * `executor_id → actor_id` bug that silently produced empty timelines\n * in the original function.\n *\n * Returns full execution rows including the §13.1 columns\n * (`delegation_chain_id`, `replay_of_execution_id`, `incident_id`,\n * `policy_version_id`, `bundle_version_id`) alongside the actor\n * timeline and evidence rows.\n */\n async getIncidentTimeline(\n incidentId: string,\n ): Promise<IncidentTimelineResponse> {\n if (!incidentId) {\n throw new AtlaSentError(\"incidentId is required\", {\n code: \"bad_request\",\n });\n }\n const { body, rateLimit } = await this.get<\n Omit<IncidentTimelineResponse, \"rateLimit\">\n >(`/v1/governance/timeline/incident/${encodeURIComponent(incidentId)}`);\n return { ...body, rateLimit };\n }\n\n // ── Connector Management ─────────────────────────────────────────────────\n\n /**\n * List connectors registered for the calling org.\n * Calls `GET /v1/governance/connectors`.\n */\n async listConnectors(\n options: { cursor?: string; limit?: number } = {},\n ): Promise<ListConnectorsResponse> {\n const params = new URLSearchParams();\n if (options.cursor) params.set(\"cursor\", options.cursor);\n if (options.limit !== undefined) params.set(\"limit\", String(options.limit));\n const { body, rateLimit } = await this.get<{\n connectors: ListConnectorsResponse[\"connectors\"];\n total: number;\n next_cursor?: string;\n }>(\"/v1/governance/connectors\", params);\n const result: ListConnectorsResponse = {\n connectors: body.connectors ?? [],\n total: body.total,\n rateLimit,\n };\n if (body.next_cursor) result.nextCursor = body.next_cursor;\n return result;\n }\n\n /**\n * Register and install a new connector for the calling org.\n * Calls `POST /v1/governance/connectors`.\n */\n async installConnector(\n input: InstallConnectorInput,\n ): Promise<InstallConnectorResponse> {\n const { body, rateLimit } = await this.post<\n InstallConnectorResponse[\"connector\"]\n >(\"/v1/governance/connectors\", input);\n return { connector: body, rateLimit };\n }\n\n /**\n * Store encrypted credentials for a connector.\n * Calls `POST /v1/governance/connectors/{id}/authenticate`.\n */\n async authenticateConnector(\n connectorId: string,\n input: AuthenticateConnectorInput,\n ): Promise<AuthenticateConnectorResponse> {\n if (!connectorId) {\n throw new AtlaSentError(\"connectorId is required\", {\n code: \"bad_request\",\n });\n }\n const { body, rateLimit } = await this.post<{\n credential_id: string;\n version: number;\n }>(\n `/v1/governance/connectors/${encodeURIComponent(connectorId)}/authenticate`,\n input,\n );\n return {\n credential_id: body.credential_id,\n version: body.version,\n rateLimit,\n };\n }\n\n /**\n * Trigger an incremental sync for a connector.\n * Calls `POST /v1/governance/connectors/{id}/sync`.\n */\n async syncConnector(connectorId: string): Promise<SyncConnectorResponse> {\n if (!connectorId) {\n throw new AtlaSentError(\"connectorId is required\", {\n code: \"bad_request\",\n });\n }\n const { body, rateLimit } = await this.post<{\n connector_id: string;\n status: SyncConnectorResponse[\"status\"];\n sync_started_at: string;\n }>(`/v1/governance/connectors/${encodeURIComponent(connectorId)}/sync`, {});\n return { ...body, rateLimit };\n }\n\n /**\n * Revoke a connector and all its associated credentials.\n * Calls `POST /v1/governance/connectors/{id}/revoke`.\n */\n async revokeConnector(\n connectorId: string,\n reason?: string,\n ): Promise<RevokeConnectorResponse> {\n if (!connectorId) {\n throw new AtlaSentError(\"connectorId is required\", {\n code: \"bad_request\",\n });\n }\n const body: { reason?: string } = {};\n if (reason !== undefined) body.reason = reason;\n const { body: wire, rateLimit } = await this.post<{\n connector_id: string;\n revoked_at: string;\n }>(\n `/v1/governance/connectors/${encodeURIComponent(connectorId)}/revoke`,\n body,\n );\n return { ...wire, rateLimit };\n }\n\n /**\n * Rotate the credentials for a connector.\n * Calls `POST /v1/governance/connectors/{id}/rotate-credentials`.\n */\n async rotateConnectorCredentials(\n connectorId: string,\n ): Promise<RotateCredentialsResponse> {\n if (!connectorId) {\n throw new AtlaSentError(\"connectorId is required\", {\n code: \"bad_request\",\n });\n }\n const { body, rateLimit } = await this.post<{\n connector_id: string;\n new_version: number;\n rotated_at: string;\n }>(\n `/v1/governance/connectors/${encodeURIComponent(connectorId)}/rotate-credentials`,\n {},\n );\n return { ...body, rateLimit };\n }\n\n /**\n * List enforcement policies for the calling org, optionally filtered by connector type.\n * Calls `GET /v1/governance/enforcement-policies`.\n */\n async listEnforcementPolicies(\n connectorType?: ConnectorType,\n ): Promise<ListEnforcementPoliciesResponse> {\n const params = new URLSearchParams();\n if (connectorType) params.set(\"connector_type\", connectorType);\n const { body, rateLimit } = await this.get<{\n policies: ListEnforcementPoliciesResponse[\"policies\"];\n total: number;\n }>(\"/v1/governance/enforcement-policies\", params);\n return { policies: body.policies ?? [], total: body.total, rateLimit };\n }\n\n /**\n * Create or update a connector enforcement policy.\n * Calls `POST /v1/governance/enforcement-policies`.\n */\n async upsertEnforcementPolicy(\n input: UpsertEnforcementPolicyInput,\n ): Promise<UpsertEnforcementPolicyResponse> {\n const { body, rateLimit } = await this.post<\n UpsertEnforcementPolicyResponse[\"policy\"]\n >(\"/v1/governance/enforcement-policies\", input);\n return { policy: body, rateLimit };\n }\n\n // ── Organizational Risk Graph ─────────────────────────────────────────────\n\n /**\n * Trigger a fresh org-level risk score computation.\n * Calls `POST /v1/governance/risk/compute`.\n */\n async computeOrgRisk(\n options: ComputeOrgRiskOptions = {},\n ): Promise<ComputeOrgRiskResponse> {\n const { body, rateLimit } = await this.post<\n ComputeOrgRiskResponse[\"score\"]\n >(\"/v1/governance/risk/compute\", options);\n return { score: body, rateLimit };\n }\n\n /**\n * Retrieve the most recently computed risk score for the calling org.\n * Calls `GET /v1/governance/risk/latest`.\n */\n async getLatestOrgRisk(): Promise<GetLatestOrgRiskResponse> {\n const { body, rateLimit } = await this.get<{\n score: GetLatestOrgRiskResponse[\"score\"];\n }>(\"/v1/governance/risk/latest\");\n return { score: body.score ?? null, rateLimit };\n }\n\n /**\n * Page through historical org risk scores, most-recent first.\n * Calls `GET /v1/governance/risk/history`.\n */\n async listOrgRiskHistory(\n options: { cursor?: string; limit?: number } = {},\n ): Promise<ListOrgRiskHistoryResponse> {\n const params = new URLSearchParams();\n if (options.cursor) params.set(\"cursor\", options.cursor);\n if (options.limit !== undefined) params.set(\"limit\", String(options.limit));\n const { body, rateLimit } = await this.get<{\n scores: ListOrgRiskHistoryResponse[\"scores\"];\n total: number;\n next_cursor?: string;\n }>(\"/v1/governance/risk/history\", params);\n const result: ListOrgRiskHistoryResponse = {\n scores: body.scores ?? [],\n total: body.total,\n rateLimit,\n };\n if (body.next_cursor) result.nextCursor = body.next_cursor;\n return result;\n }\n // ── Cross-Org Permission Negotiation ──────────────────────────────────────\n\n async checkCrossOrgPermission(\n req: CrossOrgPermissionCheckRequest,\n ): Promise<CrossOrgPermissionCheckResult> {\n const { body } = await this.post<CrossOrgPermissionCheckResult>(\n \"/v1/cross-org/permissions/check\",\n req,\n );\n return body;\n }\n\n async listCrossOrgPermissionChecks(\n params?: CrossOrgPermissionCheckListParams,\n ): Promise<CrossOrgPermissionCheckResult[]> {\n const qs = new URLSearchParams();\n if (params?.source_org_id) qs.set(\"source_org_id\", params.source_org_id);\n if (params?.target_org_id) qs.set(\"target_org_id\", params.target_org_id);\n if (params?.allowed !== undefined)\n qs.set(\"allowed\", String(params.allowed));\n if (params?.limit !== undefined) qs.set(\"limit\", String(params.limit));\n const { body } = await this.get<{\n checks: CrossOrgPermissionCheckResult[];\n }>(\"/v1/cross-org/permissions/checks\", qs);\n return body.checks ?? [];\n }\n\n // ── Anomaly Response Automation ───────────────────────────────────────────\n\n async listAnomalyResponseRules(): Promise<AnomalyResponseRule[]> {\n const { body } = await this.get<{ rules: AnomalyResponseRule[] }>(\n \"/v1/anomaly-response/rules\",\n );\n return body.rules ?? [];\n }\n\n async createAnomalyResponseRule(\n req: CreateAnomalyResponseRuleRequest,\n ): Promise<AnomalyResponseRule> {\n const { body } = await this.post<AnomalyResponseRule>(\n \"/v1/anomaly-response/rules\",\n req,\n );\n return body;\n }\n\n async updateAnomalyResponseRule(\n id: string,\n updates: Partial<CreateAnomalyResponseRuleRequest>,\n ): Promise<AnomalyResponseRule> {\n const { body } = await this.post<AnomalyResponseRule>(\n `/v1/anomaly-response/rules/${encodeURIComponent(id)}/update`,\n updates,\n );\n return body;\n }\n\n async deleteAnomalyResponseRule(id: string): Promise<void> {\n await this.post<Record<string, unknown>>(\n `/v1/anomaly-response/rules/${encodeURIComponent(id)}/delete`,\n {},\n );\n }\n\n async triggerAnomalyResponse(\n req: TriggerAnomalyResponseRequest,\n ): Promise<AnomalyResponseEvent[]> {\n const { body } = await this.post<{ events: AnomalyResponseEvent[] }>(\n \"/v1/anomaly-response/trigger\",\n req,\n );\n return body.events ?? [];\n }\n\n async listAnomalyResponseEvents(params?: {\n limit?: number;\n execution_id?: string;\n }): Promise<AnomalyResponseEvent[]> {\n const qs = new URLSearchParams();\n if (params?.execution_id) qs.set(\"execution_id\", params.execution_id);\n if (params?.limit !== undefined) qs.set(\"limit\", String(params.limit));\n const { body } = await this.get<{ events: AnomalyResponseEvent[] }>(\n \"/v1/anomaly-response/events\",\n qs,\n );\n return body.events ?? [];\n }\n\n // ── Budget Exception Workflows ────────────────────────────────────────────\n\n async listBudgetExceptions(params?: {\n status?: BudgetExceptionStatus;\n budget_policy_id?: string;\n limit?: number;\n offset?: number;\n }): Promise<BudgetExceptionRequest[]> {\n const qs = new URLSearchParams();\n if (params?.status) qs.set(\"status\", params.status);\n if (params?.budget_policy_id)\n qs.set(\"budget_policy_id\", params.budget_policy_id);\n if (params?.limit !== undefined) qs.set(\"limit\", String(params.limit));\n if (params?.offset !== undefined) qs.set(\"offset\", String(params.offset));\n const { body } = await this.get<{ exceptions: BudgetExceptionRequest[] }>(\n \"/v1/budget-exceptions\",\n qs,\n );\n return body.exceptions ?? [];\n }\n\n async getBudgetException(id: string): Promise<BudgetExceptionRequest> {\n const { body } = await this.get<BudgetExceptionRequest>(\n `/v1/budget-exceptions/${encodeURIComponent(id)}`,\n );\n return body;\n }\n\n async createBudgetException(\n req: CreateBudgetExceptionRequest,\n ): Promise<BudgetExceptionRequest> {\n const { body } = await this.post<BudgetExceptionRequest>(\n \"/v1/budget-exceptions\",\n req,\n );\n return body;\n }\n\n async approveBudgetException(\n id: string,\n req: ApproveBudgetExceptionRequest,\n ): Promise<BudgetExceptionRequest> {\n const { body } = await this.post<BudgetExceptionRequest>(\n `/v1/budget-exceptions/${encodeURIComponent(id)}/approve`,\n req,\n );\n return body;\n }\n\n async rejectBudgetException(\n id: string,\n review_notes?: string,\n ): Promise<BudgetExceptionRequest> {\n const { body } = await this.post<BudgetExceptionRequest>(\n `/v1/budget-exceptions/${encodeURIComponent(id)}/reject`,\n { review_notes },\n );\n return body;\n }\n\n async cancelBudgetException(id: string): Promise<BudgetExceptionRequest> {\n const { body } = await this.post<BudgetExceptionRequest>(\n `/v1/budget-exceptions/${encodeURIComponent(id)}/cancel`,\n {},\n );\n return body;\n }\n\n // ── Regulatory Escalation Chain ───────────────────────────────────────────\n\n async listRegulatoryAuthorityLevels(): Promise<RegulatoryAuthorityLevel[]> {\n const { body } = await this.get<{ levels: RegulatoryAuthorityLevel[] }>(\n \"/v1/regulatory/authority-levels\",\n );\n return body.levels ?? [];\n }\n\n async createRegulatoryAuthorityLevel(\n req: Omit<RegulatoryAuthorityLevel, \"id\" | \"org_id\" | \"created_at\">,\n ): Promise<RegulatoryAuthorityLevel> {\n const { body } = await this.post<RegulatoryAuthorityLevel>(\n \"/v1/regulatory/authority-levels\",\n req,\n );\n return body;\n }\n\n async listRegulatoryEscalations(params?: {\n status?: RegulatoryEscalationStatus;\n subject_type?: string;\n subject_id?: string;\n }): Promise<RegulatoryEscalation[]> {\n const qs = new URLSearchParams();\n if (params?.status) qs.set(\"status\", params.status);\n if (params?.subject_type) qs.set(\"subject_type\", params.subject_type);\n if (params?.subject_id) qs.set(\"subject_id\", params.subject_id);\n const { body } = await this.get<{ escalations: RegulatoryEscalation[] }>(\n \"/v1/regulatory/escalations\",\n qs,\n );\n return body.escalations ?? [];\n }\n\n async createRegulatoryEscalation(\n req: CreateRegulatoryEscalationRequest,\n ): Promise<RegulatoryEscalation> {\n const { body } = await this.post<RegulatoryEscalation>(\n \"/v1/regulatory/escalations\",\n req,\n );\n return body;\n }\n\n async acknowledgeRegulatoryEscalation(\n id: string,\n ): Promise<RegulatoryEscalation> {\n const { body } = await this.post<RegulatoryEscalation>(\n `/v1/regulatory/escalations/${encodeURIComponent(id)}/acknowledge`,\n {},\n );\n return body;\n }\n\n async resolveRegulatoryEscalation(\n id: string,\n resolution: string,\n resolution_details?: Record<string, unknown>,\n ): Promise<RegulatoryEscalation> {\n const { body } = await this.post<RegulatoryEscalation>(\n `/v1/regulatory/escalations/${encodeURIComponent(id)}/resolve`,\n { resolution, resolution_details },\n );\n return body;\n }\n\n async overrideRegulatoryEscalation(\n id: string,\n reason: string,\n ): Promise<RegulatoryEscalation> {\n const { body } = await this.post<RegulatoryEscalation>(\n `/v1/regulatory/escalations/${encodeURIComponent(id)}/override`,\n { reason },\n );\n return body;\n }\n\n // ── Incentive Signal Feedback Loop ────────────────────────────────────────\n\n async listSignalActions(\n signal_id: string,\n ): Promise<GovernanceSignalAction[]> {\n const { body } = await this.get<{ actions: GovernanceSignalAction[] }>(\n `/v1/governance/signals/${encodeURIComponent(signal_id)}/actions`,\n );\n return body.actions ?? [];\n }\n\n async recordSignalAction(\n signal_id: string,\n req: RecordSignalActionRequest,\n ): Promise<GovernanceSignalAction> {\n const { body } = await this.post<GovernanceSignalAction>(\n `/v1/governance/signals/${encodeURIComponent(signal_id)}/actions`,\n req,\n );\n return body;\n }\n\n async recordSignalOutcome(\n signal_id: string,\n action_id: string,\n req: RecordSignalOutcomeRequest,\n ): Promise<GovernanceSignalAction> {\n const { body } = await this.post<GovernanceSignalAction>(\n `/v1/governance/signals/${encodeURIComponent(signal_id)}/actions/${encodeURIComponent(action_id)}/outcome`,\n req,\n );\n return body;\n }\n\n async getSignalActionSummary(): Promise<SignalActionSummary> {\n const { body } = await this.get<SignalActionSummary>(\n \"/v1/governance/signals/actions/summary\",\n );\n return body;\n }\n\n // ── Cross-Org Impersonation ───────────────────────────────────────────────\n\n async listImpersonationGrants(): Promise<CrossOrgImpersonationGrant[]> {\n const { body } = await this.get<{ grants: CrossOrgImpersonationGrant[] }>(\n \"/v1/cross-org/impersonation/grants\",\n );\n return body.grants ?? [];\n }\n\n async createImpersonationGrant(\n req: CreateImpersonationGrantRequest,\n ): Promise<CrossOrgImpersonationGrant> {\n const { body } = await this.post<CrossOrgImpersonationGrant>(\n \"/v1/cross-org/impersonation/grants\",\n req,\n );\n return body;\n }\n\n async revokeImpersonationGrant(id: string): Promise<void> {\n await this.post<Record<string, unknown>>(\n `/v1/cross-org/impersonation/grants/${encodeURIComponent(id)}/revoke`,\n {},\n );\n }\n\n async issueImpersonationToken(\n grant_id: string,\n requested_duration_seconds?: number,\n ): Promise<ImpersonationToken> {\n const { body } = await this.post<ImpersonationToken>(\n `/v1/cross-org/impersonation/grants/${encodeURIComponent(grant_id)}/token`,\n { requested_duration_seconds },\n );\n return body;\n }\n\n async validateImpersonationToken(\n token: string,\n ): Promise<ImpersonationValidationResult> {\n const { body } = await this.post<ImpersonationValidationResult>(\n \"/v1/cross-org/impersonation/validate\",\n { token },\n );\n return body;\n }\n\n // ── Constrained governance agents (read surface) ──────────────────────────\n //\n // Three GETs onto the v1-governance-agents edge function. Doctrine:\n // findings produced by these endpoints are advisory signal, never\n // authority. There is no `runGovernanceAgent` method on this client —\n // invocation belongs in CI (atlasent-action `governance-agents` mode),\n // not in application code.\n\n /**\n * List the advisory governance-agent registry for the calling org.\n *\n * Calls `GET /v1/governance/agents`. The registry is reference data\n * seeded at runtime-DB migration time; every row has\n * `authority_class = \"advisory\"` and `can_authorize = false` —\n * structural invariants enforced by the schema, not policy.\n */\n async listGovernanceAgents(): Promise<GovernanceAgent[]> {\n const { body } = await this.get<ListGovernanceAgentsResponse>(\n \"/v1/governance/agents\",\n );\n return [...(body.agents ?? [])];\n }\n\n /**\n * List advisory findings emitted against one governed change.\n *\n * Calls `GET /v1/governance/findings?change_id=…[&agent_slug=…]`.\n * Returns the typed-finding rows in `created_at DESC` order, including\n * `routed_gate_id` when the finding→gate trigger linked them. Findings\n * with `can_authorize === false` (always) are advisory; rendering them\n * never satisfies a gate.\n */\n async listGovernanceFindings(\n query: ListGovernanceFindingsQuery,\n ): Promise<GovernanceAgentFinding[]> {\n if (!query?.change_id) {\n throw new AtlaSentError(\"change_id is required\", { code: \"bad_request\" });\n }\n const params = new URLSearchParams({ change_id: query.change_id });\n if (query.agent_slug) params.set(\"agent_slug\", query.agent_slug);\n const { body } = await this.get<ListGovernanceFindingsResponse>(\n \"/v1/governance/findings\",\n params,\n );\n return [...(body.findings ?? [])];\n }\n\n /**\n * List agent run records against one governed change.\n *\n * Calls `GET /v1/governance/evaluations?change_id=…[&agent_slug=…]`.\n * Returns every persisted evaluation, including `failed` / `timeout`\n * runs and `completed` runs with zero findings — the latter is the\n * positive signal \"the agent ran and found nothing\", which the UI\n * surfaces as `clear`.\n */\n async listGovernanceEvaluations(\n query: ListGovernanceEvaluationsQuery,\n ): Promise<GovernanceAgentEvaluation[]> {\n if (!query?.change_id) {\n throw new AtlaSentError(\"change_id is required\", { code: \"bad_request\" });\n }\n const params = new URLSearchParams({ change_id: query.change_id });\n if (query.agent_slug) params.set(\"agent_slug\", query.agent_slug);\n const { body } = await this.get<ListGovernanceEvaluationsResponse>(\n \"/v1/governance/evaluations\",\n params,\n );\n return [...(body.evaluations ?? [])];\n }\n}\n\n/**\n * Parse the server's `X-RateLimit-*` header triple into a typed\n * {@link RateLimitState}. Returns `null` when any of the three headers\n * is missing or unparseable — callers treat that as \"the server didn't\n * emit rate-limit state\" rather than \"the window is empty\".\n *\n * `X-RateLimit-Reset` is accepted as either unix-seconds (what the\n * AtlaSent edge functions emit today) or an ISO 8601 timestamp.\n */\nfunction parseRateLimitHeaders(headers: Headers): RateLimitState | null {\n const rawLimit = headers.get(\"x-ratelimit-limit\");\n const rawRemaining = headers.get(\"x-ratelimit-remaining\");\n const rawReset = headers.get(\"x-ratelimit-reset\");\n if (rawLimit === null || rawRemaining === null || rawReset === null) {\n return null;\n }\n const limit = Number(rawLimit);\n const remaining = Number(rawRemaining);\n if (!Number.isFinite(limit) || !Number.isFinite(remaining)) {\n return null;\n }\n const resetAt = parseResetHeader(rawReset);\n if (resetAt === null) {\n return null;\n }\n return { limit, remaining, resetAt };\n}\n\nfunction parseResetHeader(raw: string): Date | null {\n const seconds = Number(raw);\n if (Number.isFinite(seconds)) {\n // Standard shape: unix seconds. 10-digit values are in the valid\n // range ~2001–2286 so this heuristic won't confuse a tiny\n // `remaining`-like number for an epoch.\n return new Date(seconds * 1000);\n }\n const ms = Date.parse(raw);\n if (Number.isFinite(ms)) {\n return new Date(ms);\n }\n return null;\n}\n\nfunction mapFetchError(err: unknown, requestId: string): AtlaSentError {\n if (err instanceof AtlaSentError) return err;\n if (err instanceof DOMException && err.name === \"TimeoutError\") {\n return new AtlaSentError(\"Request to AtlaSent API timed out\", {\n code: \"timeout\",\n requestId,\n cause: err,\n });\n }\n if (err instanceof Error && err.name === \"AbortError\") {\n return new AtlaSentError(\"Request to AtlaSent API timed out\", {\n code: \"timeout\",\n requestId,\n cause: err,\n });\n }\n const message = err instanceof Error ? err.message : \"network error\";\n return new AtlaSentError(`Failed to reach AtlaSent API: ${message}`, {\n code: \"network\",\n requestId,\n cause: err,\n });\n}\n\nasync function buildHttpError(\n response: Response,\n requestId: string,\n): Promise<AtlaSentError> {\n const status = response.status;\n const classified = await classifyHttpStatus(response);\n const init: AtlaSentErrorInit = {\n status,\n code: classified.code,\n requestId,\n };\n if (classified.retryAfterMs !== undefined) {\n init.retryAfterMs = classified.retryAfterMs;\n }\n return new AtlaSentError(classified.message, init);\n}\n\nasync function classifyHttpStatus(response: Response): Promise<{\n message: string;\n code: AtlaSentErrorCode;\n retryAfterMs: number | undefined;\n}> {\n const status = response.status;\n const serverMessage = await readServerMessage(response);\n\n if (status === 401) {\n return {\n message: serverMessage ?? \"Invalid API key\",\n code: \"invalid_api_key\",\n retryAfterMs: undefined,\n };\n }\n if (status === 403) {\n return {\n message:\n serverMessage ?? \"Access forbidden — check your API key permissions\",\n code: \"forbidden\",\n retryAfterMs: undefined,\n };\n }\n if (status === 429) {\n return {\n message: serverMessage ?? \"Rate limited by AtlaSent API\",\n code: \"rate_limited\",\n retryAfterMs: parseRetryAfter(response.headers.get(\"retry-after\")),\n };\n }\n if (status >= 500) {\n return {\n message: serverMessage ?? `AtlaSent API returned HTTP ${status}`,\n code: \"server_error\",\n retryAfterMs: undefined,\n };\n }\n return {\n message: serverMessage ?? `AtlaSent API returned HTTP ${status}`,\n code: \"bad_request\",\n retryAfterMs: undefined,\n };\n}\n\nasync function readServerMessage(response: Response): Promise<string | null> {\n try {\n const text = await response.text();\n if (!text) return null;\n try {\n const parsed = JSON.parse(text);\n if (parsed && typeof parsed === \"object\") {\n const msg = (parsed as Record<string, unknown>).message;\n const reason = (parsed as Record<string, unknown>).reason;\n if (typeof msg === \"string\" && msg.length > 0) return msg;\n if (typeof reason === \"string\" && reason.length > 0) return reason;\n }\n } catch {\n // Fall through — treat as plain text.\n }\n return text.length > 500 ? `${text.slice(0, 500)}…` : text;\n } catch {\n return null;\n }\n}\n\n/**\n * Translate an {@link AuditEventsQuery} into `URLSearchParams`. The\n * server expects snake_case keys (`actor_id`) and accepts\n * comma-joined values for `types`; numeric `limit` serializes via\n * `String(n)`. Undefined / empty fields are dropped so the query\n * string stays minimal.\n */\nfunction buildAuditEventsQuery(query: AuditEventsQuery): URLSearchParams {\n const params = new URLSearchParams();\n if (query.types !== undefined && query.types !== \"\") {\n params.set(\"types\", query.types);\n }\n if (query.actor_id !== undefined && query.actor_id !== \"\") {\n params.set(\"actor_id\", query.actor_id);\n }\n if (query.from !== undefined && query.from !== \"\") {\n params.set(\"from\", query.from);\n }\n if (query.to !== undefined && query.to !== \"\") {\n params.set(\"to\", query.to);\n }\n if (query.limit !== undefined) {\n params.set(\"limit\", String(query.limit));\n }\n if (query.cursor !== undefined && query.cursor !== \"\") {\n params.set(\"cursor\", query.cursor);\n }\n return params;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseRetryAfter(raw: string | null): number | undefined {\n if (!raw) return undefined;\n const seconds = Number(raw);\n if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);\n const date = Date.parse(raw);\n if (Number.isFinite(date)) {\n const delta = date - Date.now();\n return delta > 0 ? delta : 0;\n }\n return undefined;\n}\n\n// ── SSE stream parser ─────────────────────────────────────────────────────────\n\n/**\n * Parse an SSE `ReadableStream<Uint8Array>` into typed {@link StreamEvent}s.\n *\n * Hardening additions over the original:\n * - Per-event timeout: if no chunk arrives within `timeoutMs` (0 = disabled),\n * throws {@link StreamTimeoutError}.\n * - Partial-JSON guard: wraps `JSON.parse` failures in {@link StreamParseError}\n * rather than letting the raw `SyntaxError` escape.\n * - Calls `onEventId` whenever the server emits an `id:` field so the caller\n * can track the `Last-Event-ID` for reconnection.\n * - Terminal detection: returns on `event: done` OR when a `decision` event\n * carries `done: true` at the top level (server-side terminal signal).\n */\nasync function* parseSseStream(\n body: ReadableStream<Uint8Array>,\n requestId: string,\n timeoutMs: number,\n onEventId: (id: string) => void,\n): AsyncIterable<StreamEvent> {\n const reader = body.getReader();\n const decoder = new TextDecoder(\"utf-8\");\n let buf = \"\";\n\n type ChunkResult =\n | { done: true; value?: undefined }\n | { done: false; value: Uint8Array };\n\n /**\n * Read the next chunk from the reader, applying a per-read timeout when\n * `timeoutMs > 0`. Returns `{ done: true }` when the stream ends, throws\n * {@link StreamTimeoutError} on timeout.\n */\n async function readChunk(): Promise<ChunkResult> {\n if (timeoutMs <= 0) {\n return reader.read() as Promise<ChunkResult>;\n }\n return new Promise<ChunkResult>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new StreamTimeoutError(timeoutMs));\n }, timeoutMs);\n (reader.read() as Promise<ChunkResult>).then(\n (result) => {\n clearTimeout(timer);\n resolve(result);\n },\n (err: unknown) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n }\n\n try {\n for (;;) {\n let done: boolean;\n let value: Uint8Array | undefined;\n try {\n const result = await readChunk();\n done = result.done;\n value = result.value;\n } catch (err) {\n if (err instanceof StreamTimeoutError) throw err;\n // Network error mid-stream: surface as AtlaSentError(network) so the\n // caller's reconnection loop can catch and retry.\n throw new AtlaSentError(\n `AtlaSent stream read failed: ${err instanceof Error ? err.message : String(err)}`,\n { code: \"network\", requestId, cause: err },\n );\n }\n\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n\n let boundary: number;\n while ((boundary = buf.indexOf(\"\\n\\n\")) !== -1) {\n const block = buf.slice(0, boundary);\n buf = buf.slice(boundary + 2);\n\n let eventType = \"message\";\n let data = \"\";\n let eventId: string | undefined;\n for (const line of block.split(\"\\n\")) {\n if (line.startsWith(\"event: \")) eventType = line.slice(7).trim();\n else if (line.startsWith(\"data: \")) data = line.slice(6);\n else if (line.startsWith(\"id: \")) eventId = line.slice(4).trim();\n else if (line.startsWith(\"id:\")) eventId = line.slice(3).trim();\n }\n\n if (eventId !== undefined) onEventId(eventId);\n\n if (!data) continue;\n if (eventType === \"done\") return;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(data);\n } catch (err) {\n throw new StreamParseError(data, err);\n }\n\n if (eventType === \"error\") {\n const e = parsed as {\n code?: string;\n message?: string;\n request_id?: string;\n };\n throw new AtlaSentError(\n e.message ?? \"Stream error from AtlaSent API\",\n {\n code: (e.code as AtlaSentErrorCode | undefined) ?? \"server_error\",\n requestId: e.request_id ?? requestId,\n },\n );\n }\n\n if (eventType === \"decision\") {\n const d = parsed as {\n permitted?: boolean;\n decision_id?: string;\n reason?: string;\n audit_hash?: string;\n timestamp?: string;\n is_final?: boolean;\n done?: boolean;\n };\n if (\n typeof d.permitted !== \"boolean\" ||\n typeof d.decision_id !== \"string\"\n ) {\n throw new AtlaSentError(\n \"Malformed decision event from AtlaSent API\",\n {\n code: \"bad_response\",\n requestId,\n },\n );\n }\n // Streaming wire uses legacy {permitted, decision_id} shape;\n // normalise to canonical lowercase decision vocabulary.\n const streamDecision = d.permitted ? \"allow\" : \"deny\";\n const isFinal = d.is_final ?? false;\n yield {\n type: \"decision\",\n decision: streamDecision,\n decision_canonical: streamDecision,\n permitId: d.decision_id,\n reason: d.reason ?? \"\",\n auditHash: d.audit_hash ?? \"\",\n timestamp: d.timestamp ?? \"\",\n isFinal,\n } satisfies StreamDecisionEvent;\n\n // Terminal: final decision OR inline done: true closes the stream.\n if (isFinal || d.done === true) return;\n } else if (eventType === \"progress\") {\n const p = parsed as Record<string, unknown>;\n yield {\n type: \"progress\",\n stage: String(p[\"stage\"] ?? \"\"),\n ...p,\n } satisfies StreamProgressEvent;\n // Server may signal terminal state via done: true on any event type.\n if ((p as Record<string, unknown>).done === true) return;\n } else {\n // Unknown event type: check for done: true as a terminal signal.\n if (\n parsed !== null &&\n typeof parsed === \"object\" &&\n (parsed as Record<string, unknown>).done === true\n ) {\n return;\n }\n }\n // Unknown event types skipped for forward compatibility.\n }\n }\n\n // Stream closed before an explicit `event: done`. If there's leftover\n // partial data in the buffer, it means the stream was cut mid-event.\n if (buf.trim().length > 0) {\n throw new StreamParseError(buf);\n }\n } finally {\n reader.releaseLock();\n }\n}\n","/**\n * `atlasent.protect(...)` — the one-call, fail-closed execution-time\n * authorization boundary.\n *\n * ```ts\n * import atlasent from \"@atlasent/sdk\";\n *\n * const permit = await atlasent.protect({\n * agent: \"deploy-bot\",\n * action: \"production.deploy\",\n * context: { commit, approver },\n * });\n * // …run the action. If we got here, AtlaSent authorized it\n * // end-to-end (evaluate + verifyPermit).\n * ```\n *\n * Unlike {@link AtlaSentClient.evaluate}, `protect` never returns a\n * denied decision. On deny, it throws {@link AtlaSentDeniedError};\n * on transport / auth / server failure it throws\n * {@link AtlaSentError}. The action cannot execute unless a valid\n * {@link Permit} is returned — this is the SDK's category boundary,\n * not a helper.\n *\n * `protectWithEvidence` is the same contract plus a signed\n * {@link DecisionReceipt} minted on the way out. Use it when you need\n * tamper-evident proof of authorization stored alongside the action\n * record (deploy logs, payment records, close workflows).\n */\n\nimport { AtlaSentClient } from \"./client.js\";\nimport type { DeployGateRequest, DeployGateResponse } from \"./types.js\";\nimport {\n AtlaSentDeniedError,\n AtlaSentError,\n normalizePermitOutcome,\n type AtlaSentDecision,\n} from \"./errors.js\";\nimport type { AtlaSentClientOptions, ConstraintTrace } from \"./types.js\";\nimport {\n buildDecisionReceiptPayload,\n buildWhyTrace,\n computeContextHash,\n signDecisionReceiptHmac,\n} from \"./evidenceEngine.js\";\nimport type {\n DecisionReceipt,\n DecisionReceiptAlgorithm,\n} from \"./evidenceEngine.js\";\n\n/** Input to {@link protect}. Same shape as `EvaluateRequest`. */\nexport interface ProtectRequest {\n agent: string;\n action: string;\n context?: Record<string, unknown>;\n}\n\n/**\n * Success return from {@link protect}. The action is authorized\n * end-to-end — evaluation allowed AND the resulting permit verified.\n */\nexport interface Permit {\n /** Opaque permit / decision identifier. */\n permitId: string;\n /** Verification hash bound to the permit. */\n permitHash: string;\n /** Audit-trail entry associated with the decision (hash-chained). */\n auditHash: string;\n /** Human-readable reason from the policy engine. */\n reason: string;\n /** ISO 8601 timestamp of the verification. */\n timestamp: string;\n /** ISO-8601 expiration timestamp of the permit. null on pre-rollout servers. */\n permitExpiresAt: string | null;\n}\n\n/** Configuration for the process-wide singleton used by {@link protect}. */\nexport interface ConfigureOptions {\n /** Overrides `ATLASENT_API_KEY` env var. */\n apiKey?: string;\n /** Overrides the default `https://api.atlasent.io`. */\n baseUrl?: string;\n /** Per-request timeout in ms. */\n timeoutMs?: number;\n /** Inject a custom fetch (primarily for tests). */\n fetch?: typeof fetch;\n /** Override the retry policy. Pass `{ maxAttempts: 1 }` to disable retries. */\n retryPolicy?: import(\"./retry.js\").RetryPolicy;\n}\n\nlet sharedClient: AtlaSentClient | null = null;\nlet overrides: ConfigureOptions = {};\n\n/**\n * Configure the singleton client used by {@link protect}. Optional —\n * if `ATLASENT_API_KEY` is set in the environment, `protect` works\n * without any configuration. Calling `configure` again replaces the\n * singleton; subsequent `protect` calls use the new settings.\n */\nexport function configure(options: ConfigureOptions): void {\n overrides = { ...overrides, ...options };\n sharedClient = null;\n}\n\n/**\n * Run the canonical Deploy Gate V1 helper using the process-wide client.\n * Defaults to action `production.deploy`; execution is allowed only after\n * server-side `/v1-evaluate` and `/v1-verify-permit` both pass.\n */\nexport async function deployGate(\n request: DeployGateRequest = {},\n): Promise<DeployGateResponse> {\n return getClient().deployGate(request);\n}\n\n/** Reset the singleton. Exported for tests; not part of the public API. */\nexport function __resetSharedClientForTests(): void {\n sharedClient = null;\n overrides = {};\n}\n\nfunction getClient(): AtlaSentClient {\n if (sharedClient) return sharedClient;\n\n // Guard process.env access so this module is safe in browser and\n // edge-runtime environments where `process` is not defined as a global.\n const envApiKey =\n typeof process !== \"undefined\" && process.env\n ? process.env.ATLASENT_API_KEY\n : undefined;\n\n const apiKey = overrides.apiKey ?? envApiKey;\n if (!apiKey) {\n throw new AtlaSentError(\n \"AtlaSent is not configured. Set ATLASENT_API_KEY in the environment, or call atlasent.configure({ apiKey }).\",\n { code: \"invalid_api_key\" },\n );\n }\n const options: AtlaSentClientOptions = { apiKey };\n if (overrides.baseUrl !== undefined) options.baseUrl = overrides.baseUrl;\n if (overrides.timeoutMs !== undefined)\n options.timeoutMs = overrides.timeoutMs;\n if (overrides.fetch !== undefined) options.fetch = overrides.fetch;\n if (overrides.retryPolicy !== undefined)\n options.retryPolicy = overrides.retryPolicy;\n sharedClient = new AtlaSentClient(options);\n return sharedClient;\n}\n\n// Mirrors the server-side ACTION_TYPE_RE in v1-evaluate/handler.ts.\nconst ACTION_TYPE_RE = /^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$/;\n\nfunction wireDecisionToDenied(serverDecision: string): AtlaSentDecision {\n // Normalise to lowercase before matching — the decision field is now\n // always lowercase from evaluate(), but defensive lower-casing here\n // handles any edge case where an older code path sends uppercase.\n const lower = serverDecision.toLowerCase();\n if (lower === \"hold\" || lower === \"escalate\") return lower;\n return \"deny\";\n}\n\n// ── Execution-hash helpers ────────────────────────────────────────────────────\n\n/**\n * Sort all object keys recursively so the JSON serialization is\n * deterministic (RFC-8785-style canonical form). Arrays are preserved\n * in insertion order; only object keys are sorted.\n */\nfunction sortKeysDeep(val: unknown): unknown {\n if (Array.isArray(val)) return val.map(sortKeysDeep);\n if (val !== null && typeof val === \"object\") {\n return Object.keys(val as object)\n .sort()\n .reduce<Record<string, unknown>>((acc, k) => {\n acc[k] = sortKeysDeep((val as Record<string, unknown>)[k]);\n return acc;\n }, {});\n }\n return val;\n}\n\n/**\n * Compute a SHA-256 hex digest of the recursively key-sorted canonical\n * JSON of `payload`. Used as `execution_hash` on the permit-consume\n * (verify) request so the server can validate the evaluate payload\n * was not tampered with between evaluate and consume.\n *\n * Falls back to `node:crypto` when `crypto.subtle` is unavailable\n * (Node < 20 without the Web Crypto global).\n */\nasync function computeExecutionHash(payload: unknown): Promise<string> {\n const sorted = sortKeysDeep(payload);\n const canonical = JSON.stringify(sorted);\n\n // Prefer the Web Crypto API (available in browsers, Node 20+,\n // Cloudflare Workers, Deno, etc.).\n if (\n typeof globalThis !== \"undefined\" &&\n globalThis.crypto?.subtle?.digest\n ) {\n const bytes = new TextEncoder().encode(canonical);\n const buf = await globalThis.crypto.subtle.digest(\"SHA-256\", bytes);\n return Array.from(new Uint8Array(buf))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n }\n\n // Fallback: node:crypto (Node < 20 or environments without crypto.subtle).\n try {\n // Dynamic import so bundlers that target browsers don't pull in\n // node internals. The `node:` prefix avoids any user-land shim.\n const { createHash } =\n await import(/* @vite-ignore */ /* webpackIgnore: true */ \"node:crypto\");\n return createHash(\"sha256\").update(canonical, \"utf8\").digest(\"hex\");\n } catch {\n // Last-resort: if neither crypto.subtle nor node:crypto is available\n // (very old Node, restricted runtime), return an empty string so the\n // verify call still proceeds — the server will reject if execution_hash\n // is required for production permits.\n // eslint-disable-next-line no-console\n console.warn(\n \"[atlasent] Could not compute execution_hash: neither crypto.subtle \" +\n \"nor node:crypto is available in this runtime.\",\n );\n return \"\";\n }\n}\n\nfunction generateReceiptId(): string {\n if (\n typeof globalThis !== \"undefined\" &&\n typeof globalThis.crypto?.randomUUID === \"function\"\n ) {\n return globalThis.crypto.randomUUID();\n }\n return `rcpt_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/**\n * Authorize an action end-to-end. On allow, returns a verified\n * {@link Permit}. On anything else, throws:\n *\n * - {@link AtlaSentDeniedError} — policy denied, or the permit\n * failed verification. Fail-closed: if this throws, the action\n * MUST NOT proceed.\n * - {@link AtlaSentError} — transport, timeout, auth, rate-limit,\n * or server error. Same fail-closed contract: do not proceed.\n */\nexport async function protect(request: ProtectRequest): Promise<Permit> {\n if (!ACTION_TYPE_RE.test(request.action)) {\n throw new AtlaSentError(\n `action must be in dot-notation format (e.g. \"production.deploy\"). Got: ${JSON.stringify(request.action)}`,\n { code: \"bad_request\" },\n );\n }\n const client = getClient();\n const evaluation = await client.evaluate(request);\n\n // decision is now canonical lowercase: \"allow\" | \"deny\" | \"hold\" | \"escalate\"\n if (evaluation.decision !== \"allow\") {\n throw new AtlaSentDeniedError({\n decision: wireDecisionToDenied(evaluation.decision),\n evaluationId: evaluation.permitId,\n reason: evaluation.reason,\n auditHash: evaluation.auditHash,\n });\n }\n\n const environment = request.context?.environment as string | undefined;\n if (!environment) {\n throw new AtlaSentError(\n 'context.environment is required. Pass the environment where this action executes (e.g. \"production\", \"staging\").',\n { code: \"bad_request\" },\n );\n }\n\n // Compute execution_hash over the original evaluate payload so\n // the server can validate integrity on permit consume.\n const evaluatePayload = {\n action_type: request.action,\n actor_id: request.agent,\n context: request.context ?? {},\n };\n const execution_hash = await computeExecutionHash(evaluatePayload);\n\n const verifyRequest: {\n permitId: string;\n agent: string;\n action: string;\n context?: Record<string, unknown>;\n environment: string;\n execution_hash?: string;\n } = {\n permitId: evaluation.permitId,\n agent: request.agent,\n action: request.action,\n environment,\n ...(execution_hash ? { execution_hash } : {}),\n };\n if (request.context !== undefined) verifyRequest.context = request.context;\n const verification = await client.verifyPermit(verifyRequest);\n\n if (!verification.verified) {\n const outcome = normalizePermitOutcome(verification.outcome);\n throw new AtlaSentDeniedError({\n decision: \"deny\",\n evaluationId: evaluation.permitId,\n reason: `Permit failed verification (${verification.outcome})`,\n auditHash: evaluation.auditHash,\n ...(outcome !== undefined && { outcome }),\n });\n }\n\n return {\n permitId: evaluation.permitId,\n permitHash: verification.permitHash,\n auditHash: evaluation.auditHash,\n reason: evaluation.reason,\n timestamp: verification.timestamp,\n permitExpiresAt: verification.expiresAt ?? null,\n };\n}\n\n// ── Evidence-enhanced protect ─────────────────────────────────────────────────\n\n/**\n * A verified {@link Permit} with an embedded signed {@link DecisionReceipt}.\n *\n * Returned by {@link protectWithEvidence}. Store `receipt` alongside\n * your action record (deploy logs, payment records, close workflows)\n * to give auditors a self-contained proof of authorization.\n */\nexport interface PermitWithEvidence extends Permit {\n /** Signed per-decision receipt. `algorithm: \"none\"` when no signing secret was supplied. */\n receipt: DecisionReceipt;\n}\n\n/** Options for {@link protectWithEvidence}. */\nexport interface ProtectWithEvidenceOptions {\n /**\n * HMAC-SHA256 signing secret. When provided, the receipt is signed\n * and can be verified offline with `verifyDecisionReceiptHmac`.\n * Recommend `process.env.ATLASENT_RECEIPT_SIGNING_SECRET`.\n */\n signingSecret?: string;\n /**\n * Registry key ID recorded on the receipt, paired with `signingSecret`.\n * Used for key rotation: store the ID alongside the receipt so\n * verifiers know which key to use.\n */\n signingKeyId?: string;\n /**\n * If you have already called `client.evaluatePreflight()` for this\n * request, pass `constraintTrace` here to populate\n * `receipt.why_trace` with the full stage-by-stage \"why\" trace.\n * When omitted, `why_trace` is `null` on the receipt.\n */\n constraintTrace?: ConstraintTrace | null;\n}\n\n/**\n * Authorize an action end-to-end and mint a signed {@link DecisionReceipt}.\n *\n * Same fail-closed contract as {@link protect} — throws\n * {@link AtlaSentDeniedError} on deny, {@link AtlaSentError} on\n * transport failure. The action MUST NOT proceed if this throws.\n *\n * On allow, returns the verified `Permit` plus a signed `DecisionReceipt`\n * that captures:\n * - The evaluation ID and decision\n * - Human-readable reasons\n * - Permit ID and hash\n * - Audit-trail hash (hash-chain link)\n * - SHA-256 of the evaluate context (tamper-evidence for the inputs)\n * - Optional \"why\" trace (pass `constraintTrace` from `evaluatePreflight`)\n *\n * ```ts\n * const { permit, receipt } = await protectWithEvidence(\n * { agent: \"deploy-bot\", action: \"production.deploy\", context },\n * {\n * signingSecret: process.env.ATLASENT_RECEIPT_SIGNING_SECRET,\n * signingKeyId: \"key-v1\",\n * },\n * );\n * // Store alongside the deployment record.\n * await db.deployments.create({ commitSha, permit, receipt });\n * ```\n */\nexport async function protectWithEvidence(\n request: ProtectRequest,\n opts: ProtectWithEvidenceOptions = {},\n): Promise<PermitWithEvidence> {\n if (!ACTION_TYPE_RE.test(request.action)) {\n throw new AtlaSentError(\n `action must be in dot-notation format (e.g. \"production.deploy\"). Got: ${JSON.stringify(request.action)}`,\n { code: \"bad_request\" },\n );\n }\n const client = getClient();\n\n // 1. Evaluate (same logic as protect()).\n const evaluation = await client.evaluate(request);\n\n if (evaluation.decision !== \"allow\") {\n throw new AtlaSentDeniedError({\n decision: wireDecisionToDenied(evaluation.decision),\n evaluationId: evaluation.permitId,\n reason: evaluation.reason,\n auditHash: evaluation.auditHash,\n });\n }\n\n // 2. Extract environment, compute execution_hash, verify permit.\n const environment = request.context?.environment as string | undefined;\n if (!environment) {\n throw new AtlaSentError(\n 'context.environment is required. Pass the environment where this action executes (e.g. \"production\", \"staging\").',\n { code: \"bad_request\" },\n );\n }\n\n const evaluatePayload = {\n action_type: request.action,\n actor_id: request.agent,\n context: request.context ?? {},\n };\n const execution_hash = await computeExecutionHash(evaluatePayload);\n\n const verifyRequest: {\n permitId: string;\n agent: string;\n action: string;\n context?: Record<string, unknown>;\n environment: string;\n execution_hash?: string;\n } = {\n permitId: evaluation.permitId,\n agent: request.agent,\n action: request.action,\n environment,\n ...(execution_hash ? { execution_hash } : {}),\n };\n if (request.context !== undefined) verifyRequest.context = request.context;\n const verification = await client.verifyPermit(verifyRequest);\n\n if (!verification.verified) {\n const outcome = normalizePermitOutcome(verification.outcome);\n throw new AtlaSentDeniedError({\n decision: \"deny\",\n evaluationId: evaluation.permitId,\n reason: `Permit failed verification (${verification.outcome})`,\n auditHash: evaluation.auditHash,\n ...(outcome !== undefined && { outcome }),\n });\n }\n\n // 3. Build the receipt.\n const contextHash = await computeContextHash(request.context ?? {});\n\n const whyTrace = buildWhyTrace(\n \"allow\",\n evaluation.reasons,\n opts.constraintTrace ?? null,\n );\n\n const issuedAt = new Date().toISOString();\n const receiptId = generateReceiptId();\n const orgId = evaluation.permit?.orgId ?? \"\";\n\n const payload = buildDecisionReceiptPayload({\n receipt_id: receiptId,\n evaluation_id: evaluation.evaluationId,\n org_id: orgId,\n decision: \"allow\",\n action: request.action,\n actor: request.agent,\n resource_type:\n (request.context?.resource_type as string | undefined) ?? null,\n resource_id:\n (request.context?.resource_id as string | undefined) ?? null,\n reasons: evaluation.reasons,\n why_summary: whyTrace.summary,\n permit_id: evaluation.permitId,\n permit_hash: verification.permitHash,\n audit_hash: evaluation.auditHash,\n context_hash: contextHash,\n issued_at: issuedAt,\n });\n\n // 4. Sign if secret is provided.\n let signature: string | null = null;\n let algorithm: DecisionReceiptAlgorithm = \"none\";\n\n if (opts.signingSecret) {\n signature = await signDecisionReceiptHmac(payload, opts.signingSecret);\n algorithm = \"hmac-sha256\";\n }\n\n const receipt: DecisionReceipt = {\n receipt_id: receiptId,\n evaluation_id: evaluation.evaluationId,\n org_id: orgId,\n decision: \"allow\",\n action: request.action,\n actor: request.agent,\n resource_type:\n (request.context?.resource_type as string | undefined) ?? null,\n resource_id:\n (request.context?.resource_id as string | undefined) ?? null,\n reasons: evaluation.reasons,\n why_trace:\n opts.constraintTrace !== undefined ? whyTrace : null,\n permit_id: evaluation.permitId,\n permit_hash: verification.permitHash,\n audit_hash: evaluation.auditHash,\n context_hash: contextHash,\n issued_at: issuedAt,\n expires_at: null,\n algorithm,\n signature,\n signing_key_id: opts.signingKeyId ?? null,\n payload,\n };\n\n return {\n permitId: evaluation.permitId,\n permitHash: verification.permitHash,\n auditHash: evaluation.auditHash,\n reason: evaluation.reason,\n timestamp: verification.timestamp,\n permitExpiresAt: verification.expiresAt ?? null,\n receipt,\n };\n}\n","/**\n * Hono middleware for AtlaSent execution-time authorization.\n *\n * ```ts\n * import { Hono } from \"hono\";\n * import { atlaSentGuard, atlaSentErrorHandler } from \"@atlasent/sdk/hono\";\n *\n * const app = new Hono();\n *\n * // One-line drop-in protection for a sensitive route.\n * app.post(\n * \"/deploy\",\n * atlaSentGuard({\n * action: \"production.deploy\",\n * agent: (c) => c.req.header(\"x-agent-id\") ?? \"anonymous\",\n * context: async (c) => ({ commit: (await c.req.json()).commit }),\n * }),\n * (c) => {\n * // If we got here, AtlaSent allowed the action end-to-end.\n * const permit = c.get(\"atlasent\");\n * return c.json({ ok: true, permitId: permit.permitId });\n * },\n * );\n *\n * // One place to map AtlaSent errors to HTTP responses.\n * app.onError(atlaSentErrorHandler());\n * ```\n *\n * The guard calls {@link protect} under the hood — same fail-closed\n * semantics. On allow, it stashes the {@link Permit} on the Hono\n * context (default key: `\"atlasent\"`) and calls `next()`. On anything\n * else, it **throws**: {@link AtlaSentDeniedError} for policy denials\n * and verification failures, {@link AtlaSentError} for transport /\n * auth / server failures. Attach {@link atlaSentErrorHandler} via\n * `app.onError(...)` to turn those into HTTP responses once, at the\n * app level, rather than wrap every guarded route.\n *\n * `hono` is an optional peer dependency — this module is only pulled\n * in when you import from the `@atlasent/sdk/hono` subpath.\n */\n\nimport type { Context, ErrorHandler, MiddlewareHandler } from \"hono\";\n\nimport { AtlaSentDeniedError, AtlaSentError } from \"./errors.js\";\nimport { protect, type Permit, type ProtectRequest } from \"./protect.js\";\n\n/** Resolver: a literal string, or a function deriving one from the request. */\ntype Resolver<T extends string | Record<string, unknown>> =\n | T\n | ((c: Context) => T | Promise<T>);\n\n/** Options for {@link atlaSentGuard}. */\nexport interface AtlaSentGuardOptions {\n /**\n * Action being authorized (e.g. `\"production.deploy\"`). A string\n * fixes the action; a function lets you derive it per-request (e.g.\n * from route params or the HTTP verb).\n */\n action: Resolver<string>;\n /**\n * Agent identifier. A string fixes the caller; a function lets you\n * read it from an auth header, JWT claim, session, etc.\n */\n agent: Resolver<string>;\n /**\n * Build the policy context dict for the decision. Defaults to `{}`.\n * Receives the Hono context so you can reach into headers, body,\n * route params, or previously-set middleware values.\n */\n context?: (\n c: Context,\n ) => Record<string, unknown> | Promise<Record<string, unknown>>;\n /**\n * Key used to stash the resulting {@link Permit} on the Hono\n * context via `c.set(...)`. Callers read it back with\n * `c.get(options.key)`. Default: `\"atlasent\"`.\n */\n key?: string;\n}\n\nconst DEFAULT_CONTEXT_KEY = \"atlasent\";\n\nasync function resolve<T>(\n value: T | ((c: Context) => T | Promise<T>),\n c: Context,\n): Promise<T> {\n return typeof value === \"function\"\n ? await (value as (c: Context) => T | Promise<T>)(c)\n : value;\n}\n\n/**\n * Hono middleware that calls {@link protect} before the wrapped\n * handler runs. On allow, stores the {@link Permit} on the context;\n * on deny or error, throws. Use {@link atlaSentErrorHandler} with\n * `app.onError(...)` to turn those throws into HTTP responses.\n */\nexport function atlaSentGuard(\n options: AtlaSentGuardOptions,\n): MiddlewareHandler {\n const contextKey = options.key ?? DEFAULT_CONTEXT_KEY;\n return async (c, next) => {\n const [agent, action, ctx] = await Promise.all([\n resolve(options.agent, c),\n resolve(options.action, c),\n options.context ? options.context(c) : Promise.resolve(undefined),\n ]);\n\n const request: ProtectRequest = { agent, action };\n if (ctx !== undefined) request.context = ctx;\n\n const permit: Permit = await protect(request);\n c.set(contextKey, permit);\n await next();\n };\n}\n\n/** Options for {@link atlaSentErrorHandler}. */\nexport interface AtlaSentErrorHandlerOptions {\n /** HTTP status returned on policy denial. Default: 403. */\n denyStatus?: 401 | 403 | 409 | 422;\n /** HTTP status returned on transport / auth / server failure. Default: 503. */\n errorStatus?: 502 | 503 | 500;\n /**\n * Hook to customize the JSON body returned on denial. Receives the\n * error; must return a JSON-serializable object. Defaults to a\n * minimal `{ error, decision, evaluationId, reason?, requestId? }`.\n */\n renderDeny?: (err: AtlaSentDeniedError) => Record<string, unknown>;\n /** Hook for transport/auth/server errors. Defaults to `{ error, code, requestId? }`. */\n renderError?: (err: AtlaSentError) => Record<string, unknown>;\n}\n\nfunction defaultRenderDeny(err: AtlaSentDeniedError): Record<string, unknown> {\n const body: Record<string, unknown> = {\n error: \"denied\",\n decision: err.decision,\n evaluationId: err.evaluationId,\n };\n if (err.reason !== undefined) body.reason = err.reason;\n if (err.requestId !== undefined) body.requestId = err.requestId;\n return body;\n}\n\nfunction defaultRenderError(err: AtlaSentError): Record<string, unknown> {\n const body: Record<string, unknown> = {\n error: \"unavailable\",\n code: err.code ?? \"unknown\",\n };\n if (err.requestId !== undefined) body.requestId = err.requestId;\n return body;\n}\n\n/**\n * Hono error handler that converts AtlaSent exceptions into\n * appropriate HTTP responses. Install once at the app level:\n *\n * ```ts\n * app.onError(atlaSentErrorHandler());\n * ```\n *\n * Non-AtlaSent errors re-throw so other `onError` chains (or Hono's\n * default 500 handler) still see them.\n */\nexport function atlaSentErrorHandler(\n options: AtlaSentErrorHandlerOptions = {},\n): ErrorHandler {\n const denyStatus = options.denyStatus ?? 403;\n const errorStatus = options.errorStatus ?? 503;\n const renderDeny = options.renderDeny ?? defaultRenderDeny;\n const renderError = options.renderError ?? defaultRenderError;\n\n return (err, c) => {\n if (err instanceof AtlaSentDeniedError) {\n return c.json(renderDeny(err), denyStatus);\n }\n if (err instanceof AtlaSentError) {\n return c.json(renderError(err), errorStatus);\n }\n throw err;\n };\n}\n\n// Re-export the types callers need in one place so the subpath is\n// self-contained.\nexport type { Permit, ProtectRequest } from \"./protect.js\";\nexport { AtlaSentDeniedError, AtlaSentError } from \"./errors.js\";\n"],"mappings":"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","names":["isNode","varianceKind","resolve"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/trustRoot.ts","../src/types.ts","../src/compat.ts","../src/retry.ts","../src/scim.ts","../src/evidence-bundle.ts","../src/auth.ts","../src/sso.ts","../src/access-governance-log.ts","../src/client.ts","../src/protect.ts","../src/hono.ts"],"sourcesContent":["/**\n * Error types for the AtlaSent TypeScript SDK.\n *\n * The SDK follows a fail-closed design: a clean policy DENY is\n * returned as `EvaluateResponse.decision === \"deny\"` (not thrown),\n * but any failure to confirm authorization — network, timeout,\n * bad response, invalid key, rate limit — throws an\n * {@link AtlaSentError}.\n */\n\n// ── Streaming-specific errors ─────────────────────────────────────────────────\n\n/**\n * Thrown when no SSE event arrives within the configured timeout window.\n *\n * Callers can catch this specifically to distinguish a stalled stream\n * from other network or parse failures:\n *\n * ```ts\n * catch (e) {\n * if (e instanceof StreamTimeoutError) { // reconnect or alert }\n * }\n * ```\n */\nexport class StreamTimeoutError extends Error {\n override name: string = \"StreamTimeoutError\";\n /** Timeout that was exceeded, in milliseconds. */\n readonly timeoutMs: number;\n\n constructor(timeoutMs: number) {\n super(`AtlaSent stream timed out after ${timeoutMs}ms with no event`);\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Thrown when the SSE stream closes with a partial / malformed JSON payload.\n *\n * This is a recoverable condition — the stream closed mid-JSON. The\n * caller can reconnect using the last received `Last-Event-ID` and\n * resume from where the server left off.\n *\n * ```ts\n * catch (e) {\n * if (e instanceof StreamParseError) { // log raw data, maybe reconnect }\n * }\n * ```\n */\nexport class StreamParseError extends Error {\n override name: string = \"StreamParseError\";\n /** The raw data string that failed to parse. */\n readonly rawData: string;\n\n constructor(rawData: string, cause?: unknown) {\n super(`AtlaSent stream received malformed JSON: ${rawData.slice(0, 200)}`);\n this.rawData = rawData;\n if (cause !== undefined) {\n // ES2022 cause\n (this as { cause?: unknown }).cause = cause;\n }\n }\n}\n\n/** Discriminator for {@link AtlaSentError.code}. */\nexport type AtlaSentErrorCode =\n | \"invalid_api_key\"\n | \"forbidden\"\n | \"rate_limited\"\n | \"timeout\"\n | \"network\"\n | \"bad_response\"\n | \"bad_request\"\n | \"server_error\"\n // Tenant lacks a v2_<feature> flag — server returned 404. Distinct\n // from \"forbidden\" (403 authorization denial) so callers can branch\n // on the failure mode.\n | \"feature_disabled\"\n | \"claim_evidence_incomplete\";\n\n/** Initialization options for {@link AtlaSentError}. */\nexport interface AtlaSentErrorInit {\n status?: number;\n code?: AtlaSentErrorCode;\n requestId?: string;\n retryAfterMs?: number;\n cause?: unknown;\n}\n\n/**\n * The only error type this SDK throws.\n *\n * Flat top-level properties mirror the convention used by Stripe,\n * Octokit, and Supabase. `cause` is forwarded to the standard\n * ES2022 `Error` constructor.\n */\nexport class AtlaSentError extends Error {\n // Subclasses override to their own literal (e.g. \"AtlaSentDeniedError\");\n // keep this assignable rather than pinned to a single literal.\n override name: string = \"AtlaSentError\";\n\n /** HTTP status code, when the error originated from an API response. */\n readonly status: number | undefined;\n /** Coarse category — useful for `switch` statements at call sites. */\n readonly code: AtlaSentErrorCode | undefined;\n /** Correlation ID echoed from the `X-Request-ID` header the SDK sent. */\n readonly requestId: string | undefined;\n /** Parsed `Retry-After` header value, in milliseconds. Only set for 429. */\n readonly retryAfterMs: number | undefined;\n\n constructor(message: string, init: AtlaSentErrorInit = {}) {\n super(\n message,\n init.cause !== undefined ? { cause: init.cause } : undefined,\n );\n this.status = init.status;\n this.code = init.code;\n this.requestId = init.requestId;\n this.retryAfterMs = init.retryAfterMs;\n }\n}\n\n/**\n * Outcome of a denied decision.\n *\n * `\"deny\"` is what the current `/v1-evaluate` API returns. `\"hold\"`\n * and `\"escalate\"` are reserved for forthcoming API decisions that\n * put a permit into a pending state requiring human review; the\n * union is declared now so call sites can `switch` exhaustively\n * from the start and adopt new decisions without a breaking change.\n */\nexport type AtlaSentDecision = \"deny\" | \"hold\" | \"escalate\";\n\n/**\n * Reason an already-issued permit failed verification.\n *\n * Surfaced on {@link AtlaSentDeniedError.outcome} so callers can\n * distinguish replay (`permit_consumed`) from revocation\n * (`permit_revoked`) from natural expiry (`permit_expired`) without\n * parsing {@link AtlaSentDeniedError.reason}. The set is defined by\n * `contract/vectors/permit_outcomes.json`; any new outcome MUST be\n * added there first.\n *\n * Mirrors the Python SDK's `PermitOutcome`. See\n * `atlasent/docs/REVOCATION_RUNBOOK.md` for the operator-facing\n * matrix this discriminator drives.\n */\nexport type PermitOutcome =\n | \"permit_consumed\"\n | \"permit_expired\"\n | \"permit_revoked\"\n | \"permit_not_found\"\n | \"permit_signing_key_revoked\";\n\nconst KNOWN_PERMIT_OUTCOMES: ReadonlySet<string> = new Set([\n \"permit_consumed\",\n \"permit_expired\",\n \"permit_revoked\",\n \"permit_not_found\",\n \"permit_signing_key_revoked\",\n]);\n\n/**\n * Map a server-supplied `outcome` string to {@link PermitOutcome}.\n *\n * Returns `undefined` for `undefined`, `\"\"`, `\"verified\"`, or any\n * unrecognized value. Used at the SDK's deny boundary so we don't\n * surface mis-typed outcomes — when the server adds a new outcome\n * string, callers branching on {@link AtlaSentDeniedError.outcome}\n * see `undefined` and fall through to their generic deny path\n * rather than match an unknown literal.\n */\nexport function normalizePermitOutcome(\n raw: string | undefined,\n): PermitOutcome | undefined {\n if (raw !== undefined && KNOWN_PERMIT_OUTCOMES.has(raw)) {\n return raw as PermitOutcome;\n }\n return undefined;\n}\n\n/** Initialization options for {@link AtlaSentDeniedError}. */\nexport interface AtlaSentDeniedErrorInit {\n decision: AtlaSentDecision;\n evaluationId: string;\n reason?: string;\n requestId?: string;\n auditHash?: string;\n /**\n * When the denial came from permit verification (not policy\n * evaluation), the discriminator that distinguishes replay,\n * expiry, revocation, and missing-record failures. `undefined`\n * for evaluate-time denials.\n */\n outcome?: PermitOutcome;\n}\n\n/**\n * Thrown by {@link atlasent.protect} when the policy engine refuses\n * the action, or when a permit fails end-to-end verification.\n *\n * This is the **fail-closed boundary** of the SDK: every code path\n * that short-circuits an action because authorization was not\n * confirmed raises an `AtlaSentDeniedError`. Callers cannot silently\n * proceed on a denial by forgetting to branch on a return value.\n *\n * Extends {@link AtlaSentError} so `instanceof AtlaSentError`\n * catches denials as part of the SDK's single exception family;\n * use `instanceof AtlaSentDeniedError` to distinguish a policy\n * denial from a transport/auth error.\n */\nexport class AtlaSentDeniedError extends AtlaSentError {\n override name: string = \"AtlaSentDeniedError\";\n\n /** Policy decision — `\"deny\"` today; `\"hold\"` / `\"escalate\"` reserved. */\n readonly decision: AtlaSentDecision;\n /** Opaque permit/decision id from `/v1-evaluate`. */\n readonly evaluationId: string;\n /** Human-readable explanation from the policy engine, if provided. */\n readonly reason: string | undefined;\n /** Hash-chained audit-trail entry associated with the decision. */\n readonly auditHash: string | undefined;\n /**\n * Discriminator for permit-side denial reasons. Populated only\n * when the server reported `verified=false` from `/v1-verify-permit`;\n * `undefined` for evaluate-time denials. See {@link PermitOutcome}.\n */\n readonly outcome: PermitOutcome | undefined;\n\n constructor(init: AtlaSentDeniedErrorInit) {\n const msg = init.reason\n ? `AtlaSent ${init.decision}: ${init.reason}`\n : `AtlaSent ${init.decision}`;\n const errInit: AtlaSentErrorInit = { status: 200 };\n if (init.requestId !== undefined) errInit.requestId = init.requestId;\n super(msg, errInit);\n this.decision = init.decision;\n this.evaluationId = init.evaluationId;\n this.reason = init.reason;\n this.auditHash = init.auditHash;\n this.outcome = init.outcome;\n }\n\n // ── Outcome discriminators ───────────────────────────────────────\n // Convenience predicates that mirror the operator runbook's matrix.\n // Callers can compare `outcome` directly; these are sugar so the\n // common cases are explicit at the call site.\n\n /** `true` when the permit was explicitly revoked (D3 endpoint). */\n get isRevoked(): boolean {\n return this.outcome === \"permit_revoked\";\n }\n\n /** `true` when the permit's TTL passed before verification. */\n get isExpired(): boolean {\n return this.outcome === \"permit_expired\";\n }\n\n /**\n * `true` when the permit was already consumed by a prior verify\n * (v1 single-use replay protection).\n */\n get isConsumed(): boolean {\n return this.outcome === \"permit_consumed\";\n }\n\n /**\n * `true` when the permit id wasn't recognized server-side\n * (typo, cross-tenant lookup, or pre-issuance race).\n */\n get isNotFound(): boolean {\n return this.outcome === \"permit_not_found\";\n }\n\n /**\n * `true` when the permit's signing key KID appears in the\n * trust-root revocation list (ADR-005 D3 R2/R3 key rotation).\n */\n get isSigningKeyRevoked(): boolean {\n return this.outcome === \"permit_signing_key_revoked\";\n }\n}\n\n/** Initialization options for {@link AtlaSentEscalateError}. */\nexport interface AtlaSentEscalateErrorInit {\n requestId?: string;\n userId?: string;\n cause?: unknown;\n}\n\n/**\n * Thrown when an evaluate response carries `decision: \"escalate\"`.\n *\n * Distinct from {@link AtlaSentDeniedError} — an escalation does not\n * constitute a hard denial. It signals that the policy engine has\n * deferred the authorization decision to a human review queue.\n * Middleware and agent orchestrators should catch this specifically\n * and route the pending action to the appropriate HITL channel.\n *\n * ```ts\n * catch (e) {\n * if (e instanceof AtlaSentEscalateError) {\n * await humanReviewQueue.submit({ userId: e.userId, requestId: e.requestId });\n * }\n * }\n * ```\n *\n * Extends {@link AtlaSentError} so `instanceof AtlaSentError` catches\n * escalations alongside other SDK errors; use\n * `instanceof AtlaSentEscalateError` to branch specifically.\n */\nexport class AtlaSentEscalateError extends AtlaSentError {\n override name: string = \"AtlaSentEscalateError\";\n\n /** Always `\"escalate\"` — discriminates this error from other AtlaSent errors. */\n readonly decision = \"escalate\" as const;\n\n /** The user whose action triggered the escalation, if available. */\n readonly userId: string | undefined;\n\n constructor(message: string, opts?: AtlaSentEscalateErrorInit) {\n super(message, {\n ...(opts?.requestId !== undefined ? { requestId: opts.requestId } : {}),\n cause: opts?.cause,\n });\n this.userId = opts?.userId;\n }\n}\n\n// ── Permit revocation error (PROD-D9 continuous-authorization) ────────────────\n\n/**\n * Thrown by an SDK guard heartbeat when `GET /v1/permits/:id/valid`\n * returns `status: 'revoked'` during tool execution (PROD-D9\n * continuous-authorization lease model).\n *\n * This error is **always re-thrown** — it is never serialized as a\n * `tool-result` denial because it represents a live enforcement action,\n * not a policy evaluation at request time. Callers should treat it as\n * an immediate halt signal.\n *\n * ```ts\n * catch (e) {\n * if (e instanceof PermitRevoked) {\n * // log e.permitId and e.revocationId for incident correlation\n * await incidentLog.record({ permitId: e.permitId, revocationId: e.revocationId });\n * }\n * }\n * ```\n *\n * Guard heartbeat is configured via `permitRevalidationIntervalMs` in\n * the guard options (minimum 1000 ms). The heartbeat activates only\n * when the {@link AtlaSentClient} exposes `checkPermitValid` — i.e.\n * when `atlasent-api` has deployed `GET /v1/permits/:id/valid`.\n */\nexport class PermitRevoked extends AtlaSentError {\n override name: string = 'PermitRevoked';\n /** The id of the permit that was revoked mid-execution. */\n readonly permitId: string;\n /** The `scope_revocations.id` that triggered the revocation, when available. */\n readonly revocationId: string | undefined;\n\n constructor(permitId: string, revocationId?: string) {\n super(\n revocationId\n ? `AtlaSent: permit ${permitId} revoked (revocation: ${revocationId}) — guard heartbeat halted execution`\n : `AtlaSent: permit ${permitId} revoked — guard heartbeat halted execution`,\n );\n this.permitId = permitId;\n this.revocationId = revocationId;\n }\n}\n\n// ── Bundle verification error (ADR-005 D3 fail-closed expiry / revocation) ────\n\n/**\n * Initialization options for {@link BundleVerificationError}.\n */\nexport interface BundleVerificationErrorInit {\n /**\n * Machine-readable reason code:\n * - `trust_snapshot_expired`: the snapshot's `valid_until` has passed\n * and `allowExpiredSnapshot` was not set.\n * - `key_revoked`: the bundle's `signing_key_id` appears in\n * `revoked_keys` of the active trust snapshot.\n * - `key_role_mismatch`: the signing key's `role` is not `\"R3_audit\"`.\n */\n reason: \"trust_snapshot_expired\" | \"key_revoked\" | \"key_role_mismatch\";\n /** ISO-8601 `valid_until` of the snapshot that caused the failure. */\n snapshotValidUntil?: string;\n /** ISO-8601 `issued_at` of the snapshot (its fetch/pin time). */\n snapshotFetchedAt?: string;\n /** Whether the snapshot came from the bundled vendor files or a live refresh. */\n snapshotSource?: \"pinned\" | \"live\";\n /** Which key id was revoked or role-mismatched, when applicable. */\n kid?: string;\n}\n\n/**\n * Thrown by {@link verifyAuditBundle} / {@link verifyBundle} when the\n * active trust-root snapshot is expired (ADR-005 D3) or the bundle's\n * signing key is revoked / has the wrong role.\n *\n * This error is **always thrown** — it is never returned as a\n * {@link BundleVerificationResult} because ADR-005 D3 requires that\n * an expired snapshot or revoked key constitutes a hard enforcement\n * action, not a soft verification failure.\n *\n * To opt out of fail-closed expiry (air-gap / offline use), pass\n * `allowExpiredSnapshot: true` to `verifyBundle`.\n */\nexport class BundleVerificationError extends AtlaSentError {\n override name = \"BundleVerificationError\";\n\n readonly reason: BundleVerificationErrorInit[\"reason\"];\n readonly snapshotValidUntil: string | undefined;\n readonly snapshotFetchedAt: string | undefined;\n readonly snapshotSource: \"pinned\" | \"live\" | undefined;\n readonly kid: string | undefined;\n\n constructor(init: BundleVerificationErrorInit) {\n super(`AtlaSent audit bundle verification failed: ${init.reason}`);\n this.reason = init.reason;\n this.snapshotValidUntil = init.snapshotValidUntil;\n this.snapshotFetchedAt = init.snapshotFetchedAt;\n this.snapshotSource = init.snapshotSource;\n this.kid = init.kid;\n }\n}\n\n","/**\n * Hybrid trust-root bootstrap and snapshot management.\n *\n * At module load, seeds from the vendor snapshot in vendor/trust-root/.\n * Optionally refreshes from https://keys.atlasent.io/.well-known/ on\n * a configurable interval (default 4h, floor 5 min per ADR-005 D2).\n * Refresh failure is silent — falls back to the in-memory snapshot.\n *\n * Snapshot expiry (valid_until) is fail-closed per ADR-005 D3:\n * checkExpiry() emits a one-time console.warn at half-life, and again\n * on expiry. verifyAuditBundle throws BundleVerificationError when\n * expired (unless allowExpiredSnapshot=true is passed).\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { resolve, dirname } from \"node:path\";\n\n// Types for the trust-root document shapes\nexport interface TrustRootKey {\n kid: string;\n role: \"R1_release\" | \"R2_permit\" | \"R3_audit\" | \"R4_pack\";\n kty: string;\n crv?: string;\n alg: string;\n x?: string;\n valid_from?: string | null;\n valid_until?: string | null;\n replaced_by?: string | null;\n revoked?: boolean;\n tenant?: string | null;\n}\n\nexport interface TrustRootRevocationEntry {\n kid: string;\n role?: string;\n revoked_at: string;\n reason?: string;\n}\n\nexport interface TrustRootSnapshot {\n /** ISO-8601 expiry of this snapshot; fail-closed when exceeded */\n valid_until: string;\n issued_at: string;\n keys: TrustRootKey[];\n revoked_keys: TrustRootRevocationEntry[];\n revoked_identities: Array<{ identity: string; revoked_at: string; reason?: string }>;\n}\n\nexport interface TrustRootManagerOptions {\n /** Override the refresh URL (default: https://keys.atlasent.io/.well-known/) */\n refreshBaseUrl?: string;\n /** Refresh interval in ms. Default: 4h. Floor: 5 min. */\n refreshIntervalMs?: number;\n /** Disable automatic background refresh. */\n disableRefresh?: boolean;\n /** Custom fetch implementation (for tests). */\n fetch?: typeof fetch;\n}\n\nconst REFRESH_INTERVAL_MS_DEFAULT = 4 * 60 * 60 * 1000; // 4 hours\nconst REFRESH_INTERVAL_MS_FLOOR = 5 * 60 * 1000; // 5 minutes\nconst KEYS_BASE_URL = \"https://keys.atlasent.io/.well-known\";\n\n// Half-life and expiry warnings: emitted once per process (ADR-005 D3).\nlet _halfLifeWarningEmitted = false;\nlet _expiredWarningEmitted = false;\n\nfunction _resetWarningFlags(): void {\n _halfLifeWarningEmitted = false;\n _expiredWarningEmitted = false;\n}\n\nexport class TrustRootManager {\n private _snapshot: TrustRootSnapshot;\n private _refreshTimer: ReturnType<typeof setInterval> | null = null;\n private readonly _opts: Required<TrustRootManagerOptions>;\n\n constructor(\n initialSnapshot: TrustRootSnapshot,\n opts: TrustRootManagerOptions = {},\n ) {\n this._snapshot = initialSnapshot;\n const intervalMs = Math.max(\n opts.refreshIntervalMs ?? REFRESH_INTERVAL_MS_DEFAULT,\n REFRESH_INTERVAL_MS_FLOOR,\n );\n this._opts = {\n refreshBaseUrl: opts.refreshBaseUrl ?? KEYS_BASE_URL,\n refreshIntervalMs: intervalMs,\n disableRefresh: opts.disableRefresh ?? false,\n fetch:\n opts.fetch ??\n (typeof globalThis !== \"undefined\" && globalThis.fetch\n ? globalThis.fetch.bind(globalThis)\n : ((_url: string) =>\n Promise.reject(new Error(\"fetch not available\"))) as typeof fetch),\n };\n if (!this._opts.disableRefresh) {\n this._scheduleRefresh();\n }\n }\n\n getSnapshot(): TrustRootSnapshot {\n return this._snapshot;\n }\n\n /**\n * Check whether the snapshot is expired, emit one-time warnings at\n * half-life and expiry. Returns \"ok\" | \"half_life\" | \"expired\".\n *\n * Emits console.warn once per process at half-life (ADR-005 D3).\n * Emits console.warn once per process on expiry.\n */\n checkExpiry(): \"ok\" | \"half_life\" | \"expired\" {\n const snap = this._snapshot;\n const now = Date.now();\n const issuedAt = new Date(snap.issued_at).getTime();\n const validUntil = new Date(snap.valid_until).getTime();\n\n if (now > validUntil) {\n if (!_expiredWarningEmitted) {\n _expiredWarningEmitted = true;\n const daysAgo = Math.floor((now - validUntil) / (24 * 60 * 60 * 1000));\n // eslint-disable-next-line no-console\n console.warn(\n `[atlasent] Trust snapshot expired ${daysAgo} day(s) ago (valid_until: ${snap.valid_until}). ` +\n \"Update to a newer SDK build or enable allowExpiredSnapshot.\",\n );\n }\n return \"expired\";\n }\n const window = validUntil - issuedAt;\n const halfLife = issuedAt + window / 2;\n if (now > halfLife) {\n if (!_halfLifeWarningEmitted) {\n _halfLifeWarningEmitted = true;\n const daysLeft = Math.floor((validUntil - now) / (24 * 60 * 60 * 1000));\n // eslint-disable-next-line no-console\n console.warn(\n `[atlasent] Trust snapshot at half-life: expires in ${daysLeft} day(s) (valid_until: ${snap.valid_until}). ` +\n \"Plan an SDK update.\",\n );\n }\n return \"half_life\";\n }\n return \"ok\";\n }\n\n /** Look up a key entry by kid. Returns undefined if not found. */\n lookupKey(kid: string): TrustRootKey | undefined {\n return this._snapshot.keys.find((k) => k.kid === kid);\n }\n\n /** Returns true if the kid appears in revoked_keys. */\n isRevoked(kid: string): boolean {\n return this._snapshot.revoked_keys.some((r) => r.kid === kid);\n }\n\n /** Replace the snapshot (e.g. after a successful refresh). */\n replaceSnapshot(next: TrustRootSnapshot): void {\n this._snapshot = next;\n }\n\n stopRefresh(): void {\n if (this._refreshTimer !== null) {\n clearInterval(this._refreshTimer);\n this._refreshTimer = null;\n }\n }\n\n private _scheduleRefresh(): void {\n this._refreshTimer = setInterval(() => {\n void this._doRefresh();\n }, this._opts.refreshIntervalMs);\n // Don't hold the process open.\n if (\n this._refreshTimer &&\n typeof this._refreshTimer === \"object\" &&\n \"unref\" in this._refreshTimer\n ) {\n (this._refreshTimer as { unref(): void }).unref();\n }\n }\n\n private async _doRefresh(): Promise<void> {\n try {\n const base = this._opts.refreshBaseUrl.replace(/\\/$/, \"\");\n const [keysRes, revocRes] = await Promise.all([\n this._opts.fetch(`${base}/atlasent-verifier-keys.json`),\n this._opts.fetch(`${base}/atlasent-revocations.json`),\n ]);\n const indexRes = await this._opts.fetch(`${base}/atlasent-trust-root.json`);\n\n if (!keysRes.ok || !revocRes.ok || !indexRes.ok) return;\n\n const [keys, revoc, index] = await Promise.all([\n keysRes.json() as Promise<{ keys: TrustRootKey[] }>,\n revocRes.json() as Promise<{\n revoked_keys: TrustRootRevocationEntry[];\n revoked_identities: unknown[];\n }>,\n indexRes.json() as Promise<{ valid_until: string; issued_at: string }>,\n ]);\n\n if (!index.valid_until || !Array.isArray(keys.keys)) return;\n\n this._snapshot = {\n valid_until: index.valid_until,\n issued_at: index.issued_at ?? this._snapshot.issued_at,\n keys: keys.keys,\n revoked_keys: revoc.revoked_keys ?? [],\n revoked_identities:\n (revoc.revoked_identities as Array<{\n identity: string;\n revoked_at: string;\n }>) ?? [],\n };\n } catch {\n // Refresh failure is silent — keep using the current snapshot.\n }\n }\n}\n\n// ─── Load the embedded (vendor) snapshot ─────────────────────────────────────\n\nfunction _loadVendorSnapshot(): TrustRootSnapshot {\n try {\n // Resolve relative to the package root. Works both when running from\n // typescript/ (dev) and from dist/ (published).\n let packageRoot: string;\n try {\n // ESM: use import.meta.url\n const thisFile = fileURLToPath(import.meta.url);\n // src/trustRoot.ts → ../../vendor/trust-root OR\n // dist/trustRoot.js → ../../vendor/trust-root\n packageRoot = resolve(dirname(thisFile), \"..\", \"..\");\n } catch {\n // CJS or bundler: fall back to __dirname if available\n packageRoot = resolve(__dirname, \"..\", \"..\");\n }\n\n const vendorDir = resolve(packageRoot, \"vendor\", \"trust-root\");\n\n const index = JSON.parse(\n readFileSync(resolve(vendorDir, \"atlasent-trust-root.json\"), \"utf8\"),\n ) as { valid_until: string; issued_at: string };\n\n const verifierKeys = JSON.parse(\n readFileSync(resolve(vendorDir, \"atlasent-verifier-keys.json\"), \"utf8\"),\n ) as { keys: TrustRootKey[] };\n\n const revocations = JSON.parse(\n readFileSync(resolve(vendorDir, \"atlasent-revocations.json\"), \"utf8\"),\n ) as {\n revoked_keys: TrustRootRevocationEntry[];\n revoked_identities: Array<{ identity: string; revoked_at: string }>;\n };\n\n return {\n valid_until: index.valid_until,\n issued_at: index.issued_at,\n keys: verifierKeys.keys ?? [],\n revoked_keys: revocations.revoked_keys ?? [],\n revoked_identities: revocations.revoked_identities ?? [],\n };\n } catch {\n // Fallback: a minimal never-expiring snapshot so the SDK degrades\n // gracefully in build environments where vendor/ is not present.\n return {\n valid_until: \"2099-01-01T00:00:00Z\",\n issued_at: \"2026-05-26T00:00:00Z\",\n keys: [],\n revoked_keys: [],\n revoked_identities: [],\n };\n }\n}\n\n// Process-global manager — created lazily.\nlet _globalManager: TrustRootManager | null = null;\n\nexport function getGlobalTrustRootManager(\n opts?: TrustRootManagerOptions,\n): TrustRootManager {\n if (!_globalManager) {\n _globalManager = new TrustRootManager(\n _loadVendorSnapshot(),\n opts ?? { disableRefresh: false },\n );\n }\n return _globalManager;\n}\n\n/** Replace the global manager (primarily for tests). */\nexport function __setGlobalTrustRootManagerForTests(\n mgr: TrustRootManager | null,\n): void {\n _globalManager = mgr;\n _resetWarningFlags();\n}\n\nexport { _resetWarningFlags as __resetWarningFlagsForTests };\n","/**\n * Public types for the AtlaSent TypeScript SDK.\n *\n * These shapes are deliberately minimal and 1:1 with the AtlaSent\n * authorization API. Request / response fields are camelCase on the\n * SDK side; the client handles snake_case translation on the wire.\n */\n\nimport type { AuditEventsPage, AuditExport } from \"./audit.js\";\n\n/**\n * Canonical 4-value policy decision, byte-identical to the wire.\n *\n * - `allow` — action is authorized; a Permit is issued.\n * - `deny` — action is blocked.\n * - `hold` — decision deferred (e.g. waiting on an approval signal).\n * - `escalate` — routed to a human reviewer queue.\n *\n * Pin to this type on new code.\n */\nexport type DecisionCanonical = \"allow\" | \"deny\" | \"hold\" | \"escalate\";\n\n/**\n * Decision type — unified with the canonical 4-value vocabulary.\n *\n * This type previously emitted `\"ALLOW\"` / `\"DENY\"` (uppercase, 2-value).\n * It now reflects the canonical wire values (`\"allow\" | \"deny\" | \"hold\" |\n * \"escalate\"`) so the `decision` and `decision_canonical` fields on\n * {@link EvaluateResponse} carry identical values and types.\n *\n * Backward compatibility: the SDK normalises API response values to\n * lowercase (`.toLowerCase()`) before returning them, so callers that\n * previously checked `=== \"ALLOW\"` must update to `=== \"allow\"`. The\n * canonical field `decision_canonical` is also available and was always\n * lowercase — prefer it on new code.\n *\n * Legacy uppercase input accepted by the SDK is normalised to lowercase\n * output; `\"ALLOW\"` in → `\"allow\"` out, `\"DENY\"` in → `\"deny\"` out.\n */\nexport type Decision = DecisionCanonical;\n\n/**\n * Rate-limit state parsed from the server's `X-RateLimit-*` headers.\n *\n * Present on every authenticated response (success and 429) when the\n * server emits the headers. `null` when the server doesn't — older\n * deployments, or internal endpoints that skip per-key rate limiting.\n *\n * Clients should check `remaining` and sleep until `resetAt` to\n * preemptively back off before hitting a 429.\n */\nexport interface RateLimitState {\n /** Value of `X-RateLimit-Limit` — the per-minute budget. */\n limit: number;\n /** Value of `X-RateLimit-Remaining` — unused budget in the current window. */\n remaining: number;\n /**\n * Parsed `X-RateLimit-Reset` — the UTC instant when the current\n * window's counter zeroes. Accepts either a unix-seconds integer or\n * an ISO 8601 string on the wire.\n */\n resetAt: Date;\n}\n\n/**\n * Canonical Deploy Gate V1 protected action.\n *\n * Use this constant (or its string value `\"production.deploy\"`) on all\n * new code. Server-side `action_classes.slug` was canonicalised to\n * `production.deploy` in atlasent-api PR #662 / atlasent-console\n * PR #432; the SDK default now matches.\n */\nexport const PRODUCTION_DEPLOY_ACTION = \"production.deploy\" as const;\n\n/**\n * Legacy alias for {@link PRODUCTION_DEPLOY_ACTION}.\n *\n * @deprecated since 2.3.0 — use {@link PRODUCTION_DEPLOY_ACTION}. The\n * server alias-tolerates `deployment.production` during the V1 alias\n * window, so existing callers continue to work unchanged; please\n * migrate by the next minor release.\n */\nexport const DEPLOYMENT_PRODUCTION_ACTION = \"deployment.production\" as const;\n\n// ── Deploy Gate V1 context types ──────────────────────────────────────────────────────\n\n/**\n * Permit claim for `production.deploy` evaluations (Rule 3).\n *\n * Pass as `permit` inside {@link DeployGateContext}.\n * The `verified` flag is set by the verify-permit service after a\n * successful `/v1-verify-permit` call — do not self-assert it.\n */\nexport interface DeployPermitClaim {\n permit_id?: string;\n environment?: string;\n action_type?: string;\n /** ISO-8601 timestamp when the permit was issued. */\n issued_at?: string;\n /** Set server-side by the verify-permit service. Do not self-assert. */\n verified?: boolean;\n}\n\n/**\n * Override claim for `production.deploy` evaluations (Rule 8).\n *\n * Both `override_reason` and `authority_basis` must be non-empty to\n * receive `OVERRIDE_APPROVED`. Missing or blank fields return `DENY_POLICY`.\n */\nexport interface DeployOverrideClaim {\n /** Human-readable reason. Required and non-empty. */\n override_reason?: string;\n /** Authoritative basis — runbook section, incident ticket, etc. Required and non-empty. */\n authority_basis?: string;\n /** Approver actor ID (audit record; does not gate the decision). */\n approver_actor_id?: string;\n}\n\n/**\n * Typed context shape for `production.deploy` evaluations.\n *\n * Pass as `context` to `protect()`, `deployGate()`, or\n * {@link AtlaSentClient.evaluate} for the Deploy Gate V1 flow.\n *\n * @example\n * ```ts\n * const permit = await atlasent.protect({\n * agent: \"deploy-bot\",\n * action: PRODUCTION_DEPLOY_ACTION,\n * context: {\n * environment: \"production\",\n * evaluation_confirmed: true,\n * actorMetadata: { role: \"deploy_engineer\" },\n * permit: {\n * permit_id: permitToken,\n * environment: \"production\",\n * action_type: PRODUCTION_DEPLOY_ACTION,\n * issued_at: new Date().toISOString(),\n * verified: true,\n * },\n * } satisfies DeployGateContext,\n * });\n * ```\n */\nexport interface DeployGateContext {\n /** Must be `\"production\"` for the production gate to apply. */\n environment?: \"production\" | \"staging\" | \"development\";\n /**\n * When `true`, all rule failures are shadowed to `allow` (fail-open).\n * Malformed-timestamp inconsistencies still escalate.\n * Use for initial rollout before locking enforcement.\n */\n pilot_mode?: boolean;\n /** Must be `true` — confirms an evaluation record exists before proceeding. */\n evaluation_confirmed?: boolean;\n /** ISO-8601 timestamp of when evaluation was confirmed. */\n evaluation_confirmed_at?: string;\n /** Actor role metadata. `role` must be one of the approved deploy roles. */\n actorMetadata?: { role?: string };\n /** Signed permit claim — required for non-pilot production deployments. */\n permit?: DeployPermitClaim;\n /** Override claim — short-circuits all rules when both fields are non-empty. */\n override?: DeployOverrideClaim;\n [key: string]: unknown;\n}\n\n/**\n * Canonical deploy gate decision codes emitted for `production.deploy`.\n *\n * Appears as `deny_code` / `matchedRuleId` on evaluation responses.\n * Pin dashboards, alerting, and routing logic to these codes — not to\n * `deny_reason` strings, which may change.\n */\nexport type DeployGateDenyCode =\n | \"ALLOW\"\n | \"DENY_POLICY\"\n | \"DENY_AUTHORITY\"\n | \"DENY_ENVIRONMENT\"\n | \"PERMIT_EXPIRED\"\n | \"VERIFY_FAILED\"\n | \"ESCALATE_REQUIRED\"\n | \"OVERRIDE_APPROVED\";\n\n/** Typed constants for {@link DeployGateDenyCode}. */\nexport const DEPLOY_GATE_CODES = Object.freeze({\n ALLOW: \"ALLOW\",\n DENY_POLICY: \"DENY_POLICY\",\n DENY_AUTHORITY: \"DENY_AUTHORITY\",\n DENY_ENVIRONMENT: \"DENY_ENVIRONMENT\",\n PERMIT_EXPIRED: \"PERMIT_EXPIRED\",\n VERIFY_FAILED: \"VERIFY_FAILED\",\n ESCALATE_REQUIRED: \"ESCALATE_REQUIRED\",\n OVERRIDE_APPROVED: \"OVERRIDE_APPROVED\",\n} satisfies Record<DeployGateDenyCode, DeployGateDenyCode>);\n\n/** Input to {@link AtlaSentClient.deployGate}. */\nexport interface DeployGateRequest {\n /** CI/repo actor performing the deployment. Defaults to `ci-deploy-bot`. */\n agent?: string;\n /** Protected action. Defaults to `production.deploy`. */\n action?:\n | typeof PRODUCTION_DEPLOY_ACTION\n | typeof DEPLOYMENT_PRODUCTION_ACTION\n | string;\n /** Typed deploy gate context for `production.deploy`. */\n context?: DeployGateContext | Record<string, unknown>;\n}\n\n/** Evidence metadata returned by {@link AtlaSentClient.deployGate}. */\nexport interface DeployGateEvidence {\n permitId?: string;\n permitHash?: string;\n auditHash?: string;\n verifiedAt?: string;\n}\n\n/** Result of the canonical Deploy Gate V1 flow. */\nexport interface DeployGateResponse {\n /** True only after evaluate allowed AND `/v1-verify-permit` verified server-side. */\n allowed: boolean;\n /** Evaluation response from `POST /v1-evaluate`, when available. */\n evaluation?: EvaluateResponse;\n /** Verification response from `POST /v1-verify-permit`, when evaluation allowed. */\n verification?: VerifyPermitResponse;\n /** Human-readable block/allow reason. */\n reason: string;\n /** Best-effort audit/evidence metadata available to the SDK. */\n evidence: DeployGateEvidence;\n}\n\n/**\n * Frozen BVS snapshot wire shape (BI4).\n * Carried in {@link EvaluateRequest}.context.bvsSnapshot when\n * the `behavior_conditioning` flag is enabled for the tenant.\n * Produced by behavior-insights GET /api/patterns/snapshot/:userId\n * and attached via `@atlasent/behavior` attachToEvaluate().\n */\nexport interface BvsSnapshot {\n user_id: string;\n /** Factor model output — keyed by BVS factor slug, value is score 0-1. */\n factors: Record<string, number>;\n /** Aggregate confidence score (0-1). Decays on a 60-day half-life. */\n confidence: number;\n /** True when the aggregate is fresh-and-thin (too few events to trust). */\n confidence_low: boolean;\n /** ISO-8601 timestamp of the compute run that produced this snapshot. */\n computed_at: string;\n}\n\n/**\n * Consent-class projection (BI5) — the privacy-safe aggregate shape that\n * third-party apps (LedgersMe, hiCoach, echobloom) receive when reading a\n * user's behavioral summary. Counts and timestamps only; no raw free-text.\n * Produced by behavior-insights `/api/patterns/summary/:userId` and fetched\n * via `@atlasent/behavior` getStateSummary(). The SDK enforces\n * {@link https://github.com/AtlaSent-Systems-Inc/atlasent-sdk | assertNoRawText}\n * client-side before returning this shape to callers.\n */\nexport interface ConsentClassProjection {\n user_id: string;\n window_start: string;\n window_end: string;\n event_count: number;\n category_counts: Partial<Record<string, number>>;\n}\n\n/**\n * Proof that a specific actor consumed a specific permit for a specific\n * action_type. Pass an array of these as `completion_proofs` on an evaluate\n * request to satisfy multi-actor quorum dependencies.\n *\n * The runtime verifies each proof via two gates (both must pass):\n * 1. A `permit_uses` row exists for `permit_id` (permit was consumed).\n * 2. An `execution_evaluations` row is bound to `actor_id` + `action_type`\n * for the same permit (actor/action binding — Codex P1 #1148 FIX #3).\n * Proofs that fail either gate are silently dropped (fail-closed).\n */\nexport interface CompletionProof {\n /** The action_type (slug) that was completed by the prior actor. */\n action_type: string;\n /** The actor who completed the action. */\n actor_id: string;\n /** The permit token (or its hash) issued when the action was permitted. */\n permit_id: string;\n}\n\n/** Input to {@link AtlaSentClient.evaluate}. */\nexport interface EvaluateRequest {\n /** Identifier of the calling agent (e.g. \"clinical-data-agent\"). */\n agent: string;\n /** The action being authorized (e.g. \"modify_patient_record\"). */\n action: string;\n /** Arbitrary policy context (user, environment, resource IDs). */\n context?: Record<string, unknown>;\n /**\n * When `true`, the server populates `riskEnvelope.factors` with a\n * per-factor breakdown of the weighted risk score. Omit (or `false`)\n * to keep response payloads small.\n */\n explain?: boolean;\n /** Deployment environment where the action executes (e.g. `\"production\"`). */\n environment?: string;\n /** Structured resource descriptor. Prefer over embedding resource info in `context`. */\n resource?: { type: string; id?: string; attributes?: Record<string, unknown> };\n /** Snapshot of the resource state before the proposed action. Enables state-transition-aware policy evaluation. */\n current_state?: { description: string; attributes?: Record<string, unknown> };\n /** Desired resource state after the action executes. */\n proposed_state?: { description: string; attributes?: Record<string, unknown> };\n /** Execution surface binding — identifies the CI/CD adapter, DB driver, or enforcement point. */\n execution_binding?: { kind: string; adapter_version?: string; resource_id?: string; enforcement_point?: string };\n /** The desired end-state the actor wants the resource to reach. Enables trajectory-aware authorization. */\n desired_state?: { description: string; attributes?: Record<string, unknown>; fingerprint?: string };\n /** Actor-proposed execution path from current_state to desired_state. The engine returns an authorized_trajectory that may differ. */\n proposed_trajectory?: {\n steps: Array<{\n step: string;\n description?: string;\n required: boolean;\n time_limit_seconds?: number;\n authorized_by?: string;\n constraints?: Record<string, unknown>;\n }>;\n description?: string;\n };\n /**\n * Multi-actor quorum completion proofs. Supply one entry per prior actor\n * whose completed action this evaluation depends on. The runtime verifies\n * each proof (consumed-permit gate + actor/action binding gate) and counts\n * only valid proofs toward quorum. Absent or empty → no quorum proofs\n * submitted (no behavioral change for non-quorum dependencies).\n */\n completion_proofs?: CompletionProof[];\n}\n\n/**\n * Slim permit object embedded in {@link EvaluateResponse} when the decision\n * is `\"allow\"`. Contains the essential fields needed to act on the permit\n * immediately without a separate `GET /v1/permits/:id` round-trip.\n *\n * Mirrors the `Permit` schema in atlasent-control-plane\n * `api/src/schemas/permits.ts`.\n */\nexport interface EvaluateResponsePermit {\n id: string;\n orgId: string;\n subject: string;\n scope: string;\n status: \"active\" | \"revoked\" | \"expired\";\n /** The evaluation that produced this permit. */\n evaluationId: string | null;\n issuedBy: string;\n revokedBy: string | null;\n /** ISO-8601 issuance timestamp. */\n issuedAt: string;\n revokedAt: string | null;\n expiresAt: string | null;\n metadata: Record<string, unknown> | null;\n}\n\n/** Result of {@link AtlaSentClient.evaluate}. */\nexport interface EvaluateResponse {\n /**\n * Policy decision — canonical 4-value lowercase vocabulary:\n * `\"allow\"`, `\"deny\"`, `\"hold\"`, or `\"escalate\"`.\n *\n * Previously emitted `\"ALLOW\"` / `\"DENY\"` (uppercase, 2-value);\n * the SDK now normalises all values to lowercase and passes `hold`\n * and `escalate` through rather than collapsing them to `\"DENY\"`.\n *\n * The `decision_canonical` field carries the same value and is the\n * recommended field for new code.\n */\n decision: Decision;\n /**\n * Canonical 4-value decision, byte-identical to the wire.\n *\n * One of `\"allow\"`, `\"deny\"`, `\"hold\"`, `\"escalate\"`. Branch on\n * this field on new code. `hold` and `escalate` are non-terminal\n * states that route to a human reviewer / approval signal — they\n * are not equivalent to a `deny`.\n */\n decision_canonical: DecisionCanonical;\n /**\n * Server-assigned identifier for this evaluation decision.\n *\n * Stable across retries and used as the key for proof retrieval\n * (`GET /v1/proof/:evaluationId`) and override requests. Also\n * available as the legacy `permitId` field for backward compatibility.\n */\n evaluationId: string;\n /** Opaque permit identifier, passed to {@link AtlaSentClient.verifyPermit}.\n *\n * @deprecated Prefer `evaluationId`. This field is kept for backward\n * compatibility and points to the same server-assigned ID.\n */\n permitId: string;\n /**\n * Slim permit object issued when `decision === \"allow\"`.\n * `null` on deny, hold, or escalate decisions.\n *\n * Mirrors the `Permit` schema from the control-plane.\n */\n permit: EvaluateResponsePermit | null;\n /**\n * Opaque HMAC-signed permit token issued when `decision === \"allow\"`.\n * Pass to `POST /v1/verify-permit` to verify the permit server-side.\n * `null` on deny, hold, or escalate decisions.\n */\n permitToken: string | null;\n /**\n * Machine-readable reasons emitted by the policy engine.\n *\n * The array may be empty. For deny/hold/escalate decisions the array\n * typically contains a single human-readable explanation; for allow\n * decisions it is often empty. Do not parse these strings — use\n * `decision` for branching.\n */\n reasons: string[];\n /** Human-readable explanation from the policy engine.\n *\n * @deprecated Prefer `reasons[0]` or `reasons`. This field is the\n * first element of `reasons` (or an empty string) for backward compat.\n */\n reason: string;\n /** Hash-chained audit-trail entry (21 CFR Part 11 / GxP-ready). */\n auditHash: string;\n /** ISO 8601 timestamp of the decision. */\n timestamp: string;\n /**\n * Per-key rate-limit state for this request's response, parsed from\n * `X-RateLimit-*` headers. `null` when the server didn't emit them.\n */\n rateLimit: RateLimitState | null;\n /**\n * Risk envelope summary from the policy engine. Present on all responses\n * from engine version wire-v1@1.0.0+. Provides the weighted risk score,\n * the pre/post-promotion decisions, and (when evaluate was called with\n * `explain: true`) a per-factor breakdown.\n *\n * The envelope can only raise severity — it structurally cannot soften\n * a deny to allow. When `promoted` is true the live `decision` was\n * upgraded from `engineDecision` to `envelopeDecision`.\n */\n riskEnvelope?: EvaluateRiskEnvelope;\n /**\n * Resolved risk class from the evaluation engine.\n * One of `\"critical\"`, `\"high\"`, `\"medium\"`, `\"low\"`.\n * Present when the risk envelope assigns a class.\n */\n riskClass?: string;\n /**\n * WHY this permit was issued — the authority kind and a reference to the\n * authorizing entity. Present on `allow` decisions when the control plane\n * attaches explicit authority provenance.\n */\n authorityBasis?: {\n kind: \"policy\" | \"approval\" | \"emergency\" | \"maintenance_window\" | \"delegation\" | \"quorum\";\n reference?: string;\n grantedBy?: string;\n rationale?: string;\n expiresAt?: string;\n };\n /**\n * ID of the HITL escalation auto-created by the control plane.\n * Present iff `decision === \"hold\"`. Poll `GET /v1/escalations/{id}`\n * for resolution status.\n */\n escalationId?: string;\n /**\n * Authorized execution trajectory returned when the engine approved a\n * `proposed_trajectory`. Present only on `allow` decisions.\n * May differ from what was proposed — the engine may add checkpoints,\n * restrict steps, or tighten time limits. Follow this trajectory exactly;\n * call `POST /v1/trajectory-verify` at each step to confirm on_trajectory.\n */\n authorized_trajectory?: {\n trajectory_id: string;\n steps: Array<{\n step: string;\n description?: string;\n required: boolean;\n time_limit_seconds?: number;\n authorized_by?: string;\n constraints?: Record<string, unknown>;\n expected_intermediate_state?: { description: string; attributes?: Record<string, unknown>; fingerprint?: string };\n }>;\n description?: string;\n forbidden_states?: Array<{ description: string; attributes?: Record<string, unknown>; fingerprint?: string }>;\n expires_at: string;\n };\n}\n\n/** Per-factor contribution in a {@link EvaluateRiskEnvelope}. */\nexport interface EvaluateRiskEnvelopeFactor {\n /** Factor identifier, e.g. `\"ACTION_SENSITIVITY\"`. */\n factor: string;\n /** Factor score in [0, 1]. Higher = more risk. */\n value: number;\n /** Configured weight for this factor. */\n weight: number;\n /** Human-readable explanation for the score. */\n reason: string;\n}\n\n/** Risk envelope summary returned in a top-level {@link EvaluateResponse}. */\nexport interface EvaluateRiskEnvelope {\n /** Weighted risk score in [0, 1]. Score ≥ 0.70 triggers a hold. */\n weightedScore: number;\n /** Policy engine decision before envelope promotion. */\n engineDecision: Decision;\n /** Decision resolved by the risk envelope. */\n envelopeDecision: Decision;\n /** `true` when the envelope raised the decision's severity (most-restrictive-wins). */\n promoted: boolean;\n /** Deny codes that unconditionally block regardless of score. */\n hardBlocks: string[];\n /** Per-factor breakdown. Present only when `explain: true` was passed. */\n factors?: EvaluateRiskEnvelopeFactor[];\n}\n\n/** Input to {@link AtlaSentClient.verifyPermit}. */\nexport interface VerifyPermitRequest {\n /** The permit ID returned by a prior evaluate() call. */\n permitId: string;\n /** Optional: re-state the action for cross-check with the server. */\n action?: string;\n /** Optional: re-state the agent for cross-check with the server. */\n agent?: string;\n /** Optional: re-state the context for cross-check with the server. */\n context?: Record<string, unknown>;\n /**\n * Environment of the permit being verified. Sourced from the evaluate\n * payload (context.environment → top-level environment → \"production\").\n * Required by the server for production permits as of 2026-05-14.\n * P1-1 fix: withPermit/protect now always populates this field.\n */\n environment?: string;\n /**\n * SHA-256 hex digest of the recursively key-sorted canonical JSON of the\n * original evaluate payload. Required by the server for production permits\n * as of 2026-05-14.\n * P1-5 fix: withPermit/protect now always computes and sends this field.\n */\n execution_hash?: string;\n}\n\n/**\n * Result of {@link AtlaSentClient.verifyPermit}.\n *\n * @deprecated Use {@link VerifyPermitByIdResponse} via\n * {@link AtlaSentClient.verifyPermitById} — the canonical REST surface\n * (`POST /v1/permits/{id}/verify`) returns the unified verification\n * envelope (`valid`, `verification_type`, `reason`, `verified_at`,\n * `evidence`) plus the full {@link PermitRecord} fields. Will be\n * removed in `@atlasent/sdk@3`.\n */\nexport interface VerifyPermitResponse {\n /** `true` when the permit is valid and un-revoked. */\n verified: boolean;\n /** Verification outcome string from the server. */\n outcome: string;\n /** Verification hash bound to the permit. */\n permitHash: string;\n /** ISO 8601 timestamp of the verification. */\n timestamp: string;\n /**\n * ISO-8601 expiration timestamp of the permit. `null` on pre-rollout\n * server versions that do not yet surface this field.\n */\n expiresAt: string | null;\n /**\n * Per-key rate-limit state for this request's response, parsed from\n * `X-RateLimit-*` headers. `null` when the server didn't emit them.\n */\n rateLimit: RateLimitState | null;\n}\n\n/**\n * Result of {@link AtlaSentClient.keySelf} — self-introspection of the API\n * key the client was constructed with. Returned by `GET /v1/api-key-self`.\n *\n * Never includes the raw key or its hash — introspection is intentionally\n * read-only and safe to surface in operator dashboards.\n */\nexport interface ApiKeySelfResponse {\n /** Server-side UUID of the api_keys row for this key. */\n keyId: string;\n /** Organization the key belongs to. */\n orgId: string;\n /** \"live\" or \"test\" (or any future environment label the server introduces). */\n environment: string;\n /** Granted scopes — e.g. [\"evaluate\", \"audit.read\"]. */\n scopes: string[];\n /**\n * Per-key IP allowlist as CIDR strings (e.g. [\"10.0.0.0/8\"]). `null`\n * when the key is unrestricted.\n */\n allowedCidrs: string[] | null;\n /** Server-enforced per-minute rate limit for this key. */\n rateLimitPerMinute: number;\n /** Client IP as the server observed it (first hop of X-Forwarded-For). */\n clientIp: string | null;\n /** Server-stored expiry; `null` means the key does not auto-expire. */\n expiresAt: string | null;\n /**\n * Per-key rate-limit state for this request's response, parsed from\n * `X-RateLimit-*` headers. `null` when the server didn't emit them.\n */\n rateLimit: RateLimitState | null;\n}\n\n/**\n * Result of {@link AtlaSentClient.listAuditEvents}. Extends the raw\n * wire page with a camelCase `rateLimit` alongside the snake_case\n * wire fields.\n */\nexport interface AuditEventsResult extends AuditEventsPage {\n rateLimit: RateLimitState | null;\n}\n\n/**\n * Filter accepted by {@link AtlaSentClient.createAuditExport}.\n */\nexport interface AuditExportRequest {\n /** Comma-joined list of event types to include. */\n types?: string;\n /** Filter to a single actor. */\n actor_id?: string;\n /** Inclusive lower bound on `occurred_at` (ISO 8601). */\n from?: string;\n /** Inclusive upper bound on `occurred_at` (ISO 8601). */\n to?: string;\n}\n\n/**\n * Result of {@link AtlaSentClient.createAuditExport}.\n */\nexport interface AuditExportResult extends AuditExport {\n rateLimit: RateLimitState | null;\n}\n\n/** Constructor options for {@link AtlaSentClient}. */\nexport interface AtlaSentClientOptions {\n /** Required. Your AtlaSent API key. */\n apiKey: string;\n /** API base URL. Defaults to \"https://api.atlasent.io\". */\n baseUrl?: string;\n /** Per-request timeout in milliseconds. Defaults to 10_000. */\n timeoutMs?: number;\n /**\n * Inject a fetch implementation (primarily for testing).\n * Defaults to `globalThis.fetch`.\n */\n fetch?: typeof fetch;\n /**\n * Retry policy for transient failures (network errors, timeouts,\n * 429 rate-limit, 5xx server errors, malformed responses).\n * Omit to use the default: 4 total attempts, 2 000 ms base, 16 000 ms cap,\n * full-jitter exponential backoff matching the Python SDK schedule\n * (2 s → 4 s → 8 s → 16 s).\n * Pass `{ maxAttempts: 1 }` to disable retries entirely.\n */\n retryPolicy?: import(\"./retry.js\").RetryPolicy;\n /**\n * Base URL for the trust-root host (default: https://keys.atlasent.io/.well-known).\n * Override for air-gapped / enterprise mirror deployments.\n * Per ADR-005 D2.\n */\n trustRootUrl?: string;\n /**\n * Trust-root snapshot refresh interval in milliseconds.\n * Default: 4 hours. Floor: 5 minutes (ADR-005 D2).\n * Set to 0 to inherit the default.\n */\n trustSnapshotRefreshMs?: number;\n}\n\n// ── Permit lifecycle (canonical REST shapes) ───────────────────────────────────────────\n\n/** Permit lifecycle status. */\nexport type PermitStatus =\n | \"issued\"\n | \"verified\"\n | \"consumed\"\n | \"expired\"\n | \"revoked\";\n\n/**\n * Wire shape of a Permit row, returned by {@link AtlaSentClient.getPermit}\n * and {@link AtlaSentClient.listPermits}.\n */\nexport interface PermitRecord {\n id: string;\n org_id: string;\n actor_id: string;\n action_id: string;\n target_id?: string;\n environment?: string;\n status: PermitStatus;\n issued_at: string;\n expires_at: string;\n consumed_at?: string | null;\n revoked_at?: string | null;\n revoked_by?: string | null;\n revoke_reason?: string | null;\n signature?: string;\n payload_hash?: string | null;\n decision_id?: string | null;\n /** SHA-256 hex of the CDO that produced this permit. P1 provisional. */\n cdo_hash?: string | null;\n}\n\n/** Optional filters for {@link AtlaSentClient.listPermits}. */\nexport interface ListPermitsRequest {\n status?: PermitStatus;\n actorId?: string;\n actionType?: string;\n from?: string;\n to?: string;\n limit?: number;\n cursor?: string;\n}\n\n/** Response from {@link AtlaSentClient.listPermits}. */\nexport interface ListPermitsResponse {\n permits: PermitRecord[];\n total: number;\n nextCursor?: string;\n rateLimit: RateLimitState | null;\n}\n\n/** Response from {@link AtlaSentClient.getPermit}. */\nexport interface GetPermitResponse {\n permit: PermitRecord;\n rateLimit: RateLimitState | null;\n}\n\n/**\n * Response from {@link AtlaSentClient.checkPermitValid}.\n */\nexport interface PermitValidResponse {\n valid: boolean;\n status: \"active\" | \"expired\" | \"revoked\" | \"consumed\";\n revoked_at?: string;\n revocation_id?: string;\n}\n\n// ── Canonical revoke / verify (REST) ──────────────────────────────────────────────────\n\n/** Input for {@link AtlaSentClient.revokePermitById}. */\nexport interface RevokePermitByIdInput {\n reason?: string;\n}\n\n/**\n * Response from {@link AtlaSentClient.revokePermitById}.\n */\nexport interface RevokePermitByIdResponse {\n permit: PermitRecord;\n rateLimit: RateLimitState | null;\n}\n\n/**\n * Response from {@link AtlaSentClient.verifyPermitById}.\n */\nexport interface VerifyPermitByIdResponse {\n valid: boolean;\n verification_type: \"permit\";\n reason: string | null;\n verified_at: string;\n evidence: {\n permit_id: string;\n status: PermitStatus;\n actor_id?: string;\n action_id?: string;\n expires_at?: string;\n payload_hash?: string | null;\n decision_id?: string | null;\n };\n permit: PermitRecord;\n rateLimit: RateLimitState | null;\n}\n\n// ── Revoke permit ─────────────────────────────────────────────────────────────────────────\n\n/** Input for {@link AtlaSentClient.revokePermit}. */\nexport interface RevokePermitRequest {\n permitId: string;\n reason?: string;\n}\n\n/**\n * Result of {@link AtlaSentClient.revokePermit}.\n *\n * @deprecated Use {@link RevokePermitByIdResponse} via\n * {@link AtlaSentClient.revokePermitById}.\n * Will be removed in `@atlasent/sdk@3`.\n */\nexport interface RevokePermitResponse {\n revoked: boolean;\n permitId: string;\n revokedAt?: string | undefined;\n auditHash?: string | undefined;\n rateLimit: RateLimitState | null;\n}\n\n// ── Constraint trace (preflight) ────────────────────────────────────────────────────────\n\nexport interface ConstraintTraceStage {\n readonly stage: string;\n readonly rule?: string;\n readonly matched: boolean;\n readonly detail?: string;\n readonly order: number;\n readonly [key: string]: unknown;\n}\n\nexport interface ConstraintTracePolicy {\n readonly policy_id: string;\n readonly decision: string;\n readonly fingerprint: string;\n readonly risk_score?: number;\n readonly stages: ReadonlyArray<ConstraintTraceStage>;\n readonly [key: string]: unknown;\n}\n\nexport interface ConstraintTrace {\n readonly rules_evaluated: ReadonlyArray<ConstraintTracePolicy>;\n readonly matching_policy_id?: string;\n readonly [key: string]: unknown;\n}\n\nexport interface EvaluatePreflightResponse {\n readonly evaluation: EvaluateResponse;\n readonly constraintTrace: ConstraintTrace | null;\n}\n\n// ── Streaming evaluate ─────────────────────────────────────────────────────────────────────\n\nexport interface StreamOptions {\n signal?: AbortSignal;\n timeoutMs?: number;\n maxRetries?: number;\n}\n\nexport interface StreamDecisionEvent {\n type: \"decision\";\n decision: Decision;\n decision_canonical: DecisionCanonical;\n permitId: string;\n reason: string;\n auditHash: string;\n timestamp: string;\n isFinal: boolean;\n}\n\nexport interface StreamProgressEvent {\n type: \"progress\";\n stage: string;\n [key: string]: unknown;\n}\n\nexport type StreamEvent = StreamDecisionEvent | StreamProgressEvent;\n\n// ── Batch evaluate ────────────────────────────────────────────────────────────────────────────\n\nexport interface BatchEvalItem {\n agent: string;\n action: string;\n context?: Record<string, unknown>;\n}\n\nexport interface EvaluateBatchResultItem {\n index: number;\n decision?: DecisionCanonical;\n decisionId?: string;\n permitToken?: string | null;\n reason?: string;\n auditHash?: string;\n timestamp?: string;\n error?: string;\n message?: string;\n}\n\nexport interface BatchEvalResponse {\n batchId: string;\n items: EvaluateBatchResultItem[];\n partial: boolean;\n replayed?: boolean;\n rateLimit: RateLimitState | null;\n}\n\n// ── Decisions stream ──────────────────────────────────────────────────────────────────────\n\nexport interface SubscribeDecisionsOptions {\n types?: string[];\n actorId?: string;\n lastEventId?: string;\n maxSeconds?: number;\n signal?: AbortSignal;\n}\n\nexport interface DecisionStreamEvent {\n id?: string;\n type: string;\n decision?: DecisionCanonical;\n actorId?: string;\n resourceType?: string;\n resourceId?: string;\n payload?: Record<string, unknown>;\n hash?: string;\n previousHash?: string;\n occurredAt?: string;\n}\n\n// ── Trajectory authorization ────────────────────────────────────────────────────────────\n\n/** Verified snapshot of resource state. */\nexport interface StateSnapshot {\n description: string;\n attributes?: Record<string, unknown>;\n /** Deterministic hash of the state (e.g. schema fingerprint, content hash). */\n fingerprint?: string;\n recorded_at?: string;\n}\n\n/** Step in an execution trajectory. */\nexport interface TrajectoryStep {\n step: string;\n description?: string;\n required: boolean;\n time_limit_seconds?: number;\n authorized_by?: string;\n constraints?: Record<string, unknown>;\n expected_intermediate_state?: StateSnapshot;\n}\n\n/** Actor-submitted trajectory proposal. */\nexport interface ProposedTrajectory {\n steps: TrajectoryStep[];\n description?: string;\n}\n\n/** Evaluation-engine-returned authorized trajectory. May differ from the proposed trajectory. */\nexport interface AuthorizedTrajectory extends ProposedTrajectory {\n trajectory_id: string;\n forbidden_states?: StateSnapshot[];\n expires_at: string;\n}\n\n/** Input to POST /v1/trajectory-verify. */\nexport interface TrajectoryVerifyRequest {\n permit_token: string;\n current_step: string;\n current_state?: StateSnapshot;\n completed_steps?: string[];\n execution_context?: Record<string, unknown>;\n}\n\n/** Response from POST /v1/trajectory-verify. */\nexport interface TrajectoryVerifyResponse {\n on_trajectory: boolean;\n trajectory_position?: number;\n trajectory_complete: boolean;\n deviation?: TrajectoryDeviationEvent;\n verified_at: string;\n}\n\n/** Deviation type for trajectory deviation events. */\nexport type TrajectoryDeviationType =\n | \"step_not_on_trajectory\"\n | \"step_out_of_sequence\"\n | \"forbidden_state_reached\"\n | \"required_step_skipped\"\n | \"time_limit_exceeded\"\n | \"constraint_violation\"\n | \"trajectory_expired\";\n\n/** Emitted when execution departs from the authorized trajectory. */\nexport interface TrajectoryDeviationEvent {\n deviation_type: TrajectoryDeviationType;\n trajectory_id: string;\n permit_id: string;\n step?: string;\n actual_state?: StateSnapshot;\n expected_state?: StateSnapshot;\n reason: string;\n detected_at: string;\n}\n\n/** Evidence artifact: authorized trajectory vs. actual execution trace. */\nexport interface ComplianceComparisonArtifact {\n version: \"compliance_comparison.v1\";\n artifact_id: string;\n authorized_transition: {\n permit_id: string;\n desired_state: StateSnapshot;\n trajectory: AuthorizedTrajectory;\n spec_signature?: string;\n };\n execution_trace: {\n executed_steps: Array<{\n step: string;\n started_at: string;\n completed_at?: string;\n outcome: \"success\" | \"failure\" | \"skipped\";\n state_after?: StateSnapshot;\n }>;\n final_state: StateSnapshot;\n trace_signature?: string;\n };\n fidelity: {\n compliant: boolean;\n /** Score in [0, 1] measuring closeness of actual to authorized trajectory. */\n fidelity_score: number;\n missing_required_steps: string[];\n unexpected_steps: string[];\n forbidden_states_reached: StateSnapshot[];\n deviation_events: TrajectoryDeviationEvent[];\n };\n artifact_hash: string;\n generated_at: string;\n}\n","/**\n * Dual-shape input bridge for the v2.0.0 wire format change.\n *\n * The v2.0.0 wire format renamed the evaluate request fields:\n * OLD: { action, agent, context, api_key }\n * NEW: { action_type, actor_id, context }\n *\n * And the response fields:\n * OLD: { permitted, decision_id }\n * NEW: { decision, permit_token }\n *\n * TypeScript callers on the old v1.x request shape receive a\n * deprecation warning and are transparently upgraded to the new\n * shape. The response compat bridge normalises the legacy\n * `permitted` boolean to `decision === \"allow\"`.\n *\n * Both shims will be removed in v3.0.0.\n */\n\n/** Legacy v1.x evaluate request shape. */\nexport interface LegacyEvaluateRequest {\n action?: string;\n agent?: string;\n context?: Record<string, unknown>;\n}\n\n/** v2.0 evaluate request shape (canonical wire format). */\nexport interface V2EvaluateRequest {\n action_type: string;\n actor_id: string;\n context?: Record<string, unknown>;\n /** Populate `risk_envelope.factors` in the response (Phase C). */\n explain?: boolean;\n /** Deployment environment where the action executes (e.g. `\"production\"`). */\n environment?: string;\n /** Structured resource descriptor. Prefer over `resource_id` for new callers. */\n resource?: { type: string; id?: string; attributes?: Record<string, unknown> };\n /** Snapshot of the resource before the proposed action. Enables state-transition-aware policy evaluation. */\n current_state?: { description: string; attributes?: Record<string, unknown> };\n /** Desired resource state after the action. */\n proposed_state?: { description: string; attributes?: Record<string, unknown> };\n /** Execution surface binding (CI/CD adapter, DB driver, etc.). */\n execution_binding?: { kind: string; adapter_version?: string; resource_id?: string; enforcement_point?: string };\n}\n\n/**\n * Normalise an evaluate request from either the legacy v1.x shape\n * (`action` / `agent`) or the current v2.0 shape (`action_type` /\n * `actor_id`) into the canonical v2.0 wire format.\n *\n * When the legacy shape is detected a `console.warn` deprecation\n * notice is emitted once per call-site process lifetime. The shim\n * will be removed in v3.0.0.\n */\nexport function normalizeEvaluateRequest(\n input: LegacyEvaluateRequest | V2EvaluateRequest,\n): V2EvaluateRequest {\n // Detect legacy shape: has `action` or `agent` but NOT `action_type` /\n // `actor_id`. Both old fields are optional in the legacy interface so\n // we key on the absence of the new fields.\n if ('action' in input && !('action_type' in input)) {\n // eslint-disable-next-line no-console\n console.warn(\n '[atlasent] Deprecation: action/agent request shape is deprecated. ' +\n 'Use action_type/actor_id instead. This compatibility shim will be removed in v3.0.0.',\n );\n const legacy = input as LegacyEvaluateRequest;\n const normalized: V2EvaluateRequest = {\n action_type: legacy.action!,\n actor_id: legacy.agent!,\n };\n if (legacy.context !== undefined) normalized.context = legacy.context;\n const l = legacy as any;\n if (l.explain !== undefined) normalized.explain = l.explain;\n if (l.environment !== undefined) normalized.environment = l.environment;\n if (l.resource !== undefined) normalized.resource = l.resource;\n if (l.current_state !== undefined) normalized.current_state = l.current_state;\n if (l.proposed_state !== undefined) normalized.proposed_state = l.proposed_state;\n if (l.execution_binding !== undefined) normalized.execution_binding = l.execution_binding;\n return normalized;\n }\n return input as V2EvaluateRequest;\n}\n\n/**\n * Legacy v1.x evaluate response shape returned by older server\n * deployments.\n */\nexport interface LegacyEvaluateResponse {\n permitted?: boolean;\n decision_id?: string;\n reason?: string;\n audit_hash?: string;\n timestamp?: string;\n}\n\n/** v2.0 evaluate response shape (canonical wire format). */\nexport interface V2EvaluateResponse {\n decision: 'allow' | 'deny' | 'hold' | 'escalate';\n permit_token?: string;\n request_id?: string;\n expires_at?: string;\n denial?: { reason?: string; code?: string };\n}\n\n/**\n * Normalise an evaluate response from either the legacy v1.x shape\n * (`permitted` / `decision_id`) or the current v2.0 shape\n * (`decision` / `permit_token`) into the canonical v2.0 wire format.\n *\n * Used internally by the client to tolerate older atlasent-api\n * deployments without surfacing the impedance mismatch to callers.\n */\nexport function normalizeEvaluateResponse(\n wire: LegacyEvaluateResponse | V2EvaluateResponse,\n): V2EvaluateResponse {\n if (!('decision' in wire) && 'permitted' in wire) {\n // Legacy server — map `permitted` boolean → canonical `decision`.\n const legacy = wire as LegacyEvaluateResponse;\n const normalized: V2EvaluateResponse = {\n decision: legacy.permitted ? 'allow' : 'deny',\n };\n if (legacy.decision_id !== undefined) {\n normalized.permit_token = legacy.decision_id;\n }\n if (!legacy.permitted && legacy.reason) {\n normalized.denial = { reason: legacy.reason };\n }\n return normalized;\n }\n return wire as V2EvaluateResponse;\n}\n","/**\n * Retry-policy helpers for the AtlaSent TypeScript SDK.\n *\n * This module is **pure**: no I/O, no network, no globals beyond\n * `Math.random`. The intent is that {@link AtlaSentClient} (and any\n * caller wrapping `protect()` / `evaluate()`) can ask\n * {@link isRetryable} whether to retry a given {@link AtlaSentError},\n * then ask {@link computeBackoffMs} how long to sleep before the next\n * attempt.\n *\n * Wire-up into the client itself is intentionally deferred — see\n * ROADMAP item #7 (Post-GA). Sentry breadcrumb emission is also\n * deferred; both will land together once a transport-level retry\n * loop is wired into `client.ts`.\n *\n * Retry classification (matches the server's documented contract):\n * - `network` / `timeout` → retry (transient transport)\n * - `server_error` (HTTP 5xx) → retry\n * - `rate_limited` (HTTP 429) → retry, honour `retryAfterMs`\n * - `bad_response` → retry (likely truncated body)\n * - `invalid_api_key`/`forbidden`/`bad_request` → never retry\n *\n * Backoff: capped exponential with full jitter.\n * delay = min(maxDelayMs, baseDelayMs * 2^attempt) * random[0, 1)\n *\n * \"Full jitter\" is the AWS-recommended scheme — see\n * https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/.\n * It avoids thundering-herd retries from many SDK instances that hit\n * a 429 in the same window.\n *\n * Default schedule:\n * attempt 0 (1st retry): base 250 ms, jittered in [0, 250)\n * attempt 1 (2nd retry): base 500 ms, jittered in [0, 500)\n * Total attempts (including initial): 3\n */\n\nimport { AtlaSentError, type AtlaSentErrorCode } from \"./errors.js\";\n\n/**\n * Defaults for {@link RetryPolicy}.\n *\n * Exponential backoff with full jitter, base 250 ms, capped at 10 s:\n * attempt 0 (1st retry): base 250 ms, jittered in [0, 250)\n * attempt 1 (2nd retry): base 500 ms, jittered in [0, 500)\n * Total attempts (including initial): 3\n */\nexport const DEFAULT_RETRY_POLICY: Required<RetryPolicy> = {\n maxAttempts: 3,\n baseDelayMs: 250,\n maxDelayMs: 10_000,\n};\n\n/**\n * Caller-tunable retry policy. All fields optional; missing fields\n * fall back to {@link DEFAULT_RETRY_POLICY}.\n */\nexport interface RetryPolicy {\n /**\n * Total attempts including the first try. `1` disables retries\n * entirely. Must be `>= 1`; values below are clamped to `1`.\n */\n maxAttempts?: number;\n /**\n * Initial backoff for `attempt = 0`. Doubles per attempt up to\n * `maxDelayMs`. Must be `>= 0`.\n */\n baseDelayMs?: number;\n /**\n * Hard ceiling on the per-attempt sleep, applied **before** jitter.\n * The actual sleep is uniformly distributed in `[0, ceiling]`.\n */\n maxDelayMs?: number;\n}\n\n/**\n * Error codes the SDK considers transient. A `Set` (rather than a\n * `switch`) keeps callers free to extend the policy in the future\n * without forking this module.\n */\nconst RETRYABLE_CODES: ReadonlySet<AtlaSentErrorCode> = new Set([\n \"network\",\n \"timeout\",\n \"rate_limited\",\n \"server_error\",\n \"bad_response\",\n]);\n\n/**\n * Decide whether `err` is worth a retry. Anything that isn't an\n * {@link AtlaSentError} is treated as non-retryable — the SDK's\n * transport layer always wraps fetch failures in `AtlaSentError`,\n * so a non-AtlaSent throwable is by definition a programmer bug\n * (a bad input, an assertion in user code) and should propagate.\n */\nexport function isRetryable(err: unknown): boolean {\n if (!(err instanceof AtlaSentError)) return false;\n if (err.code === undefined) return false;\n return RETRYABLE_CODES.has(err.code);\n}\n\n/**\n * Compute how long to sleep before retry attempt `attempt`\n * (zero-indexed: `attempt = 0` is the first retry, i.e. the second\n * total request). Uses capped exponential backoff with full jitter.\n *\n * When `err` carries a `retryAfterMs` (server-provided `Retry-After`\n * header), the result is `max(retryAfterMs, jitteredDelay)` — the\n * server's hint is treated as a floor so we never retry sooner than\n * the server asked.\n *\n * @param attempt Zero-indexed retry attempt (0, 1, 2, ...). For\n * the default policy this produces delays drawn from\n * [0, 2 000), [0, 4 000), [0, 8 000), [0, 16 000).\n * @param policy Optional override of {@link DEFAULT_RETRY_POLICY}.\n * @param err Optional error whose `retryAfterMs` is honoured.\n * @param random Injectable RNG, defaults to `Math.random`. Must\n * return values in `[0, 1)` to preserve the\n * distribution.\n */\nexport function computeBackoffMs(\n attempt: number,\n policy: RetryPolicy = {},\n err?: unknown,\n random: () => number = Math.random,\n): number {\n const merged = mergePolicy(policy);\n const safeAttempt = Math.max(0, Math.floor(attempt));\n // 2^attempt grows exponentially; cap before multiplying to keep the\n // intermediate value bounded for very large `attempt`.\n const exp = Math.min(safeAttempt, 30);\n const ceiling = Math.min(merged.maxDelayMs, merged.baseDelayMs * 2 ** exp);\n const jittered = Math.floor(ceiling * clampUnit(random()));\n\n const retryAfterMs =\n err instanceof AtlaSentError && typeof err.retryAfterMs === \"number\"\n ? Math.max(0, err.retryAfterMs)\n : 0;\n\n return Math.max(retryAfterMs, jittered);\n}\n\n/**\n * Returns `true` when `attempt` (zero-indexed) is below the policy's\n * `maxAttempts - 1` ceiling — i.e. when there is still budget for at\n * least one more try after this one. Convenience wrapper so retry\n * loops read top-to-bottom:\n *\n * ```ts\n * for (let attempt = 0; ; attempt++) {\n * try { return await op(); }\n * catch (err) {\n * if (!isRetryable(err) || !hasAttemptsLeft(attempt, policy)) throw err;\n * await sleep(computeBackoffMs(attempt, policy, err));\n * }\n * }\n * ```\n */\nexport function hasAttemptsLeft(\n attempt: number,\n policy: RetryPolicy = {},\n): boolean {\n const merged = mergePolicy(policy);\n return attempt + 1 < merged.maxAttempts;\n}\n\n/**\n * Merge a partial policy with {@link DEFAULT_RETRY_POLICY} and clamp\n * each field into a sensible range. Exported for tests and for\n * callers that want to log the resolved policy.\n */\nexport function mergePolicy(policy: RetryPolicy): Required<RetryPolicy> {\n const maxAttempts = Math.max(\n 1,\n Math.floor(policy.maxAttempts ?? DEFAULT_RETRY_POLICY.maxAttempts),\n );\n const baseDelayMs = Math.max(\n 0,\n policy.baseDelayMs ?? DEFAULT_RETRY_POLICY.baseDelayMs,\n );\n const maxDelayMs = Math.max(\n baseDelayMs,\n policy.maxDelayMs ?? DEFAULT_RETRY_POLICY.maxDelayMs,\n );\n return { maxAttempts, baseDelayMs, maxDelayMs };\n}\n\n/**\n * Clamp `n` into `[0, 1)`. Defends against a misbehaving injected\n * RNG returning `NaN`, `Infinity`, or a negative number.\n */\nfunction clampUnit(n: number): number {\n if (!Number.isFinite(n)) return 0;\n if (n < 0) return 0;\n if (n >= 1) return 0.999_999_999;\n return n;\n}\n","/**\n * SCIM 2.0 provisioning client — user and group lifecycle management.\n *\n * Wire surface: /scim/v2/* endpoints in atlasent-api (RFC 7643/7644).\n *\n * Usage:\n *\n * ```ts\n * import { AtlaSentClient } from \"@atlasent/sdk\";\n *\n * const client = new AtlaSentClient({ apiKey: \"...\" });\n *\n * const page = await client.scim.users.list({ orgId: \"org_abc\" });\n * for (const user of page.Resources) {\n * console.log(user.userName);\n * }\n *\n * const newUser = await client.scim.users.create(\"org_abc\", {\n * userName: \"alice@example.com\",\n * displayName: \"Alice Example\",\n * active: true,\n * emails: [{ value: \"alice@example.com\", primary: true }],\n * });\n * ```\n */\n\n// ─── SCIM schema URNs ─────────────────────────────────────────────────────────\n\nexport const SCIM_USER_SCHEMA =\n \"urn:ietf:params:scim:schemas:core:2.0:User\" as const;\nexport const SCIM_GROUP_SCHEMA =\n \"urn:ietf:params:scim:schemas:core:2.0:Group\" as const;\nexport const SCIM_PATCH_OP_SCHEMA =\n \"urn:ietf:params:scim:api:messages:2.0:PatchOp\" as const;\n\n// ─── SCIM resource types ──────────────────────────────────────────────────────\n\n/** SCIM email value. */\nexport interface ScimEmail {\n value: string;\n type?: string;\n primary?: boolean;\n}\n\n/** SCIM name component. */\nexport interface ScimName {\n formatted?: string;\n givenName?: string;\n familyName?: string;\n}\n\n/** Group reference embedded on a user. */\nexport interface ScimGroupRef {\n value: string;\n display?: string;\n}\n\n/** SCIM metadata block. */\nexport interface ScimMeta {\n resourceType?: string;\n created?: string;\n lastModified?: string;\n location?: string;\n version?: string;\n}\n\n/** SCIM 2.0 User resource. */\nexport interface ScimUser {\n schemas?: string[];\n id?: string;\n userName: string;\n displayName?: string;\n active?: boolean;\n emails?: ScimEmail[];\n name?: ScimName;\n groups?: ScimGroupRef[];\n meta?: ScimMeta;\n [k: string]: unknown;\n}\n\n/** Create payload for a new SCIM user. `schemas` is injected automatically. */\nexport type ScimUserCreate = Omit<ScimUser, \"id\" | \"meta\">;\n\n/** Update payload for an existing SCIM user. */\nexport type ScimUserUpdate = ScimUser;\n\n/** RFC 7644 PatchOp operation. */\nexport interface ScimPatchOp {\n op: \"add\" | \"remove\" | \"replace\";\n path?: string;\n value?: unknown;\n}\n\n/** SCIM 2.0 ListResponse envelope (generic). */\nexport interface ScimListResponse<T = unknown> {\n schemas: string[];\n totalResults: number;\n startIndex: number;\n itemsPerPage: number;\n Resources: T[];\n}\n\n/** Query parameters for SCIM list operations. */\nexport interface ScimListParams {\n /** Organisation ID (required). */\n orgId: string;\n /** SCIM filter expression, e.g. `userName eq \"alice@example.com\"`. */\n filter?: string;\n /** 1-based pagination offset. Defaults to 1 on the server. */\n startIndex?: number;\n /** Maximum results per page. Defaults to 100 on the server. */\n count?: number;\n}\n\n// ─── Sub-client interfaces ───────────────────────────────────────────────────\n\n/** Sub-client for /scim/v2/{orgId}/Users operations. */\nexport interface ScimUsersSubClient {\n /**\n * `GET /scim/v2/{orgId}/Users` — list provisioned users.\n *\n * ```ts\n * const page = await client.scim.users.list({ orgId: \"org_abc\" });\n * ```\n */\n list(params: ScimListParams): Promise<ScimListResponse<ScimUser>>;\n\n /**\n * `POST /scim/v2/{orgId}/Users` — provision a new user.\n *\n * ```ts\n * const user = await client.scim.users.create(\"org_abc\", {\n * userName: \"alice@example.com\",\n * active: true,\n * emails: [{ value: \"alice@example.com\", primary: true }],\n * });\n * ```\n */\n create(orgId: string, user: ScimUserCreate): Promise<ScimUser>;\n\n /**\n * `PUT /scim/v2/{orgId}/Users/{id}` — full replacement.\n *\n * ```ts\n * const updated = await client.scim.users.update(\"org_abc\", \"usr_123\", user);\n * ```\n */\n update(\n orgId: string,\n id: string,\n user: ScimUserUpdate,\n ): Promise<ScimUser>;\n\n /**\n * `DELETE /scim/v2/{orgId}/Users/{id}` — deprovision a user.\n *\n * ```ts\n * await client.scim.users.delete(\"org_abc\", \"usr_123\");\n * ```\n */\n delete(orgId: string, id: string): Promise<void>;\n}\n\n/** Sub-client for /scim/v2/{orgId}/Groups operations. */\nexport interface ScimGroupsSubClient {\n /** `GET /scim/v2/{orgId}/Groups` — list groups. */\n list(params: ScimListParams): Promise<ScimListResponse<Record<string, unknown>>>;\n /** `POST /scim/v2/{orgId}/Groups` — create a group. */\n create(orgId: string, group: Record<string, unknown>): Promise<Record<string, unknown>>;\n /** `DELETE /scim/v2/{orgId}/Groups/{id}` — delete a group. */\n delete(orgId: string, id: string): Promise<void>;\n}\n\n/** Top-level SCIM sub-client exposed as `client.scim`. */\nexport interface ScimSubClient {\n users: ScimUsersSubClient;\n groups: ScimGroupsSubClient;\n}\n\n// ─── Factory ─────────────────────────────────────────────────────────────────\n\ntype PostFn = <T>(\n path: string,\n body: unknown,\n query?: URLSearchParams,\n) => Promise<{ body: T }>;\n\ntype GetFn = <T>(\n path: string,\n query?: URLSearchParams,\n) => Promise<{ body: T }>;\n\ntype PutFn = <T>(\n path: string,\n body: unknown,\n) => Promise<{ body: T }>;\n\ntype DeleteFn = (path: string) => Promise<void>;\n\nfunction scimUsersPath(orgId: string): string {\n return `/scim/v2/${encodeURIComponent(orgId)}/Users`;\n}\n\nfunction scimGroupsPath(orgId: string): string {\n return `/scim/v2/${encodeURIComponent(orgId)}/Groups`;\n}\n\nfunction buildScimQuery(\n filter?: string,\n startIndex?: number,\n count?: number,\n): URLSearchParams | undefined {\n const params = new URLSearchParams();\n if (filter !== undefined) params.set(\"filter\", filter);\n if (startIndex !== undefined) params.set(\"startIndex\", String(startIndex));\n if (count !== undefined) params.set(\"count\", String(count));\n return params.size > 0 ? params : undefined;\n}\n\n/**\n * Factory that returns the SCIM sub-client bound to a host client.\n * Called internally by AtlaSentClient; not part of the public constructor API.\n */\nexport function makeScimClient(\n postFn: PostFn,\n getFn: GetFn,\n putFn: PutFn,\n deleteFn: DeleteFn,\n): ScimSubClient {\n const users: ScimUsersSubClient = {\n async list(params: ScimListParams): Promise<ScimListResponse<ScimUser>> {\n const qs = buildScimQuery(\n params.filter,\n params.startIndex,\n params.count,\n );\n const { body } = await getFn<ScimListResponse<ScimUser>>(\n scimUsersPath(params.orgId),\n qs,\n );\n return body;\n },\n\n async create(orgId: string, user: ScimUserCreate): Promise<ScimUser> {\n const payload = user.schemas\n ? user\n : { ...user, schemas: [SCIM_USER_SCHEMA] };\n const { body } = await postFn<ScimUser>(scimUsersPath(orgId), payload);\n return body;\n },\n\n async update(\n orgId: string,\n id: string,\n user: ScimUserUpdate,\n ): Promise<ScimUser> {\n const payload = user.schemas\n ? user\n : { ...user, schemas: [SCIM_USER_SCHEMA] };\n const { body } = await putFn<ScimUser>(\n `${scimUsersPath(orgId)}/${encodeURIComponent(id)}`,\n payload,\n );\n return body;\n },\n\n async delete(orgId: string, id: string): Promise<void> {\n return deleteFn(\n `${scimUsersPath(orgId)}/${encodeURIComponent(id)}`,\n );\n },\n };\n\n const groups: ScimGroupsSubClient = {\n async list(\n params: ScimListParams,\n ): Promise<ScimListResponse<Record<string, unknown>>> {\n const qs = buildScimQuery(\n params.filter,\n params.startIndex,\n params.count,\n );\n const { body } = await getFn<ScimListResponse<Record<string, unknown>>>(\n scimGroupsPath(params.orgId),\n qs,\n );\n return body;\n },\n\n async create(\n orgId: string,\n group: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n const payload =\n group[\"schemas\"] ? group : { ...group, schemas: [SCIM_GROUP_SCHEMA] };\n const { body } = await postFn<Record<string, unknown>>(\n scimGroupsPath(orgId),\n payload,\n );\n return body;\n },\n\n async delete(orgId: string, id: string): Promise<void> {\n return deleteFn(\n `${scimGroupsPath(orgId)}/${encodeURIComponent(id)}`,\n );\n },\n };\n\n return { users, groups };\n}\n","/**\n * Evidence Bundle helpers — create, retrieve, and download compliance\n * evidence bundles for incident investigations and audit export.\n *\n * Wire surface: POST/GET /v1/evidence-bundles\n *\n * Usage:\n *\n * ```ts\n * import { AtlaSentClient } from \"@atlasent/sdk\";\n *\n * const client = new AtlaSentClient({ apiKey: \"...\" });\n *\n * // Create\n * const bundle = await client.evidenceBundles.create({\n * incidentId: \"inc_abc123\",\n * includeOverrides: true,\n * });\n *\n * // Get\n * const bundle2 = await client.evidenceBundles.get(bundle.bundleId);\n *\n * // Download as JSON or PDF\n * const pdf = await client.evidenceBundles.download(bundle.bundleId, \"pdf\");\n * ```\n */\n\n/** Status of an evidence bundle. */\nexport type EvidenceBundleStatus =\n | \"pending\"\n | \"building\"\n | \"ready\"\n | \"failed\"\n | \"expired\";\n\n/** An evidence bundle record returned by the API. */\nexport interface EvidenceBundle {\n /** Server-assigned bundle identifier. */\n bundleId: string;\n /** Organisation the bundle belongs to. */\n orgId: string;\n /** Incident or investigation ID this bundle was created for. */\n incidentId: string;\n /** Current bundle status. */\n status: EvidenceBundleStatus;\n /** Permit IDs included in the bundle (empty = all permits for the incident). */\n includedPermits: string[];\n /** Whether override events are included. */\n includeOverrides: boolean;\n /** Format used when the bundle was created. */\n format: \"json\" | \"pdf\";\n /** ISO 8601 creation time. */\n createdAt: string;\n /** ISO 8601 expiration time. */\n expiresAt: string;\n /** Pre-signed download URL (populated when status is `ready`). */\n downloadUrl?: string;\n /** Free-form metadata supplied at creation. */\n metadata?: Record<string, unknown>;\n}\n\n/** Input to {@link EvidenceBundlesMixin.create}. */\nexport interface EvidenceBundleCreateParams {\n /** Incident or investigation ID for this bundle. */\n incidentId: string;\n /**\n * Optional list of specific permit IDs to include.\n * When omitted, all permits associated with the incident are included.\n */\n includedPermits?: string[];\n /**\n * When `true`, override events are embedded in the bundle.\n * Defaults to `false`.\n */\n includeOverrides?: boolean;\n}\n\n/** Query parameters for {@link EvidenceBundleSubClient.list}. */\nexport interface EvidenceBundleListParams {\n /** Filter bundles to a specific execution ID. */\n executionId?: string;\n /** Maximum number of bundles to return. */\n limit?: number;\n /** Opaque cursor from a previous list response for pagination. */\n cursor?: string;\n}\n\n/** Paginated response from {@link EvidenceBundleSubClient.list}. */\nexport interface EvidenceBundleListPage {\n /** Evidence bundles for this page. */\n bundles: EvidenceBundle[];\n /** Pass as `cursor` to `list()` to fetch the next page. `null` means no more pages. */\n nextCursor: string | null;\n}\n\n/** Wire shape for the list response. */\ninterface EvidenceBundleListWire {\n bundles: EvidenceBundleWire[];\n next_cursor?: string | null;\n}\n\n/** Wire shape returned by POST /v1/evidence-bundles. */\ninterface EvidenceBundleWire {\n bundle_id: string;\n org_id: string;\n incident_id: string;\n status: EvidenceBundleStatus;\n included_permits: string[];\n include_overrides: boolean;\n format: \"json\" | \"pdf\";\n created_at: string;\n expires_at: string;\n download_url?: string;\n metadata?: Record<string, unknown>;\n}\n\nfunction wireToBundle(w: EvidenceBundleWire): EvidenceBundle {\n return {\n bundleId: w.bundle_id,\n orgId: w.org_id,\n incidentId: w.incident_id,\n status: w.status,\n includedPermits: w.included_permits ?? [],\n includeOverrides: w.include_overrides ?? false,\n format: w.format,\n createdAt: w.created_at,\n expiresAt: w.expires_at,\n ...(w.download_url !== undefined ? { downloadUrl: w.download_url } : {}),\n ...(w.metadata !== undefined ? { metadata: w.metadata } : {}),\n };\n}\n\n/**\n * Sub-client for evidence bundle operations.\n * Accessed as `client.evidenceBundles` on {@link AtlaSentClient}.\n */\nexport interface EvidenceBundleSubClient {\n /**\n * List evidence bundles for the org, with optional filters and pagination.\n *\n * ```ts\n * const page = await client.evidenceBundles.list({ limit: 20 });\n * for (const bundle of page.bundles) { ... }\n * if (page.nextCursor) {\n * const next = await client.evidenceBundles.list({ cursor: page.nextCursor });\n * }\n * ```\n */\n list(params?: EvidenceBundleListParams): Promise<EvidenceBundleListPage>;\n\n /**\n * Create a new evidence bundle.\n *\n * ```ts\n * const bundle = await client.evidenceBundles.create({\n * incidentId: \"inc_abc123\",\n * includeOverrides: true,\n * });\n * ```\n */\n create(params: EvidenceBundleCreateParams): Promise<EvidenceBundle>;\n\n /**\n * Retrieve an evidence bundle by ID.\n *\n * ```ts\n * const bundle = await client.evidenceBundles.get(\"bnd_xyz\");\n * ```\n */\n get(bundleId: string): Promise<EvidenceBundle>;\n\n /**\n * Download the evidence bundle contents.\n *\n * @param bundleId - The bundle to download.\n * @param format - `\"json\"` (default) or `\"pdf\"`.\n * @returns Raw bytes of the downloaded file.\n *\n * ```ts\n * const pdf = await client.evidenceBundles.download(\"bnd_xyz\", \"pdf\");\n * await fs.writeFile(\"bundle.pdf\", pdf);\n * ```\n */\n download(bundleId: string, format?: \"json\" | \"pdf\"): Promise<Buffer>;\n}\n\n/**\n * Factory that returns the evidence-bundles sub-client bound to a host\n * client. Called internally by AtlaSentClient; not part of the public\n * constructor API.\n */\nexport function makeEvidenceBundleClient(\n postFn: <T>(path: string, body: unknown) => Promise<{ body: T }>,\n getFn: <T>(path: string, query?: URLSearchParams) => Promise<{ body: T }>,\n getRawFn: (path: string) => Promise<ArrayBuffer>,\n): EvidenceBundleSubClient {\n return {\n async list(params: EvidenceBundleListParams = {}): Promise<EvidenceBundleListPage> {\n const qs = new URLSearchParams();\n if (params.executionId !== undefined) qs.set(\"execution_id\", params.executionId);\n if (params.limit !== undefined) qs.set(\"limit\", String(params.limit));\n if (params.cursor !== undefined) qs.set(\"cursor\", params.cursor);\n const { body } = await getFn<EvidenceBundleListWire>(\"/v1/evidence-bundles\", qs.size > 0 ? qs : undefined);\n return {\n bundles: (body.bundles ?? []).map(wireToBundle),\n nextCursor: body.next_cursor ?? null,\n };\n },\n\n async create(params: EvidenceBundleCreateParams): Promise<EvidenceBundle> {\n const payload: Record<string, unknown> = {\n incident_id: params.incidentId,\n };\n if (params.includedPermits !== undefined) {\n payload[\"included_permits\"] = params.includedPermits;\n }\n if (params.includeOverrides !== undefined) {\n payload[\"include_overrides\"] = params.includeOverrides;\n }\n const { body } = await postFn<EvidenceBundleWire>(\n \"/v1/evidence-bundles\",\n payload,\n );\n return wireToBundle(body);\n },\n\n async get(bundleId: string): Promise<EvidenceBundle> {\n const { body } = await getFn<EvidenceBundleWire>(\n `/v1/evidence-bundles/${encodeURIComponent(bundleId)}`,\n );\n return wireToBundle(body);\n },\n\n async download(\n bundleId: string,\n format: \"json\" | \"pdf\" = \"json\",\n ): Promise<Buffer> {\n const qs = new URLSearchParams({ format });\n const raw = await getRawFn(\n `/v1/evidence-bundles/${encodeURIComponent(bundleId)}/download?${qs}`,\n );\n return Buffer.from(raw);\n },\n };\n}\n","/**\n * Auth helpers — token management and multi-IdP token refresh.\n *\n * Wire surface: /v1/auth/* endpoints in atlasent-api.\n *\n * Usage:\n *\n * ```ts\n * import { AtlaSentClient } from \"@atlasent/sdk\";\n *\n * const client = new AtlaSentClient({ apiKey: \"...\" });\n *\n * // Refresh using the default IdP\n * const tokens = await client.auth.refresh(currentRefreshToken);\n *\n * // Refresh using a specific IdP (multi-IdP orgs)\n * const tokens = await client.auth.refreshWithIdp(\"idp_okta_prod\", currentRefreshToken);\n *\n * // List IdP connections\n * const connections = await client.auth.listIdpConnections();\n * ```\n */\n\n/** A token response from the auth endpoints. */\nexport interface TokenResponse {\n accessToken: string;\n refreshToken: string;\n tokenType: string;\n expiresIn: number;\n scope?: string;\n /** IdP that issued the token (populated on multi-IdP responses). */\n idpId?: string;\n}\n\n/** Wire shape for token responses. */\ninterface TokenResponseWire {\n access_token: string;\n refresh_token: string;\n token_type: string;\n expires_in: number;\n scope?: string;\n idp_id?: string;\n}\n\nfunction wireToTokenResponse(w: TokenResponseWire): TokenResponse {\n return {\n accessToken: w.access_token,\n refreshToken: w.refresh_token,\n tokenType: w.token_type,\n expiresIn: w.expires_in,\n ...(w.scope !== undefined ? { scope: w.scope } : {}),\n ...(w.idp_id !== undefined ? { idpId: w.idp_id } : {}),\n };\n}\n\n/** An IdP connection record. */\nexport interface IdpConnection {\n id: string;\n name: string;\n provider: string;\n enabled: boolean;\n isDefault: boolean;\n domains?: string[];\n createdAt: string;\n}\n\n/** Wire shape for an IdP connection. */\ninterface IdpConnectionWire {\n id: string;\n name: string;\n provider: string;\n enabled: boolean;\n default: boolean;\n domains?: string[];\n created_at: string;\n}\n\nfunction wireToIdpConnection(w: IdpConnectionWire): IdpConnection {\n return {\n id: w.id,\n name: w.name,\n provider: w.provider,\n enabled: w.enabled,\n isDefault: w.default,\n ...(w.domains !== undefined ? { domains: w.domains } : {}),\n createdAt: w.created_at,\n };\n}\n\n/** Sub-client for token management and multi-IdP auth. */\nexport interface AuthSubClient {\n /**\n * Refresh an access token using the default IdP connection.\n *\n * ```ts\n * const tokens = await client.auth.refresh(currentRefreshToken);\n * ```\n */\n refresh(refreshToken: string): Promise<TokenResponse>;\n\n /**\n * Refresh an access token against a specific IdP connection.\n *\n * Use this in multi-IdP organisations where the caller needs to\n * specify which SSO connection to use for the token exchange.\n *\n * `idpId` corresponds to the connection ID returned by\n * `listIdpConnections()` (e.g. `\"idp_okta_prod\"`, `\"idp_entra\"`).\n *\n * ```ts\n * const tokens = await client.auth.refreshWithIdp(\n * \"idp_okta_prod\",\n * currentRefreshToken,\n * );\n * ```\n */\n refreshWithIdp(idpId: string, refreshToken: string): Promise<TokenResponse>;\n\n /**\n * List IdP connections available for this organisation.\n *\n * ```ts\n * const connections = await client.auth.listIdpConnections();\n * const primary = connections.find(c => c.isDefault);\n * ```\n */\n listIdpConnections(): Promise<IdpConnection[]>;\n}\n\n/**\n * Factory that returns the auth sub-client bound to a host client.\n * Called internally by AtlaSentClient; not part of the public constructor API.\n */\nexport function makeAuthClient(\n postFn: <T>(path: string, body: unknown) => Promise<{ body: T }>,\n getFn: <T>(path: string) => Promise<{ body: T }>,\n): AuthSubClient {\n return {\n async refresh(refreshToken: string): Promise<TokenResponse> {\n const { body } = await postFn<TokenResponseWire>(\n \"/v1/auth/token/refresh\",\n { refresh_token: refreshToken, grant_type: \"refresh_token\" },\n );\n return wireToTokenResponse(body);\n },\n\n async refreshWithIdp(\n idpId: string,\n refreshToken: string,\n ): Promise<TokenResponse> {\n const path = `/v1/auth/idp/${encodeURIComponent(idpId)}/token/refresh`;\n const { body } = await postFn<TokenResponseWire>(path, {\n refresh_token: refreshToken,\n grant_type: \"refresh_token\",\n idp_id: idpId,\n });\n return wireToTokenResponse(body);\n },\n\n async listIdpConnections(): Promise<IdpConnection[]> {\n const { body } = await getFn<{ connections: IdpConnectionWire[] }>(\n \"/v1/auth/idp-connections\",\n );\n return (body.connections ?? []).map(wireToIdpConnection);\n },\n };\n}\n","/**\n * SSO administration — connections, JIT rules, events, enforcement state\n * machine, and the `client.sso` sub-client.\n *\n * Usage:\n *\n * ```ts\n * import { AtlaSentClient } from \"@atlasent/sdk\";\n *\n * const client = new AtlaSentClient({ apiKey: \"...\" });\n *\n * const { connections } = await client.sso.listConnections();\n * const status = await client.sso.getStatus();\n * await client.sso.enforce(\"enable\");\n * ```\n */\n\n// ── Connections ───────────────────────────────────────────────────────────────\n\n/** An SSO connection record (SAML 2.0 or OIDC). */\nexport interface SsoConnection {\n id: string;\n organizationId: string;\n name: string;\n protocol: \"saml\" | \"oidc\";\n idpEntityId: string;\n metadataUrl: string | null;\n metadataXml: string | null;\n emailDomain: string | null;\n enforceForDomain: boolean;\n isActive: boolean;\n supabaseProviderId: string | null;\n createdBy: string;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Wire (snake_case) shape for SSO connection responses. */\nexport interface SsoConnectionWire {\n id: string;\n organization_id: string;\n name: string;\n protocol: \"saml\" | \"oidc\";\n idp_entity_id: string;\n metadata_url: string | null;\n metadata_xml: string | null;\n email_domain: string | null;\n enforce_for_domain: boolean;\n is_active: boolean;\n supabase_provider_id: string | null;\n created_by: string;\n created_at: string;\n updated_at: string;\n}\n\nexport function wireToSsoConnection(w: SsoConnectionWire): SsoConnection {\n return {\n id: w.id,\n organizationId: w.organization_id,\n name: w.name,\n protocol: w.protocol,\n idpEntityId: w.idp_entity_id,\n metadataUrl: w.metadata_url,\n metadataXml: w.metadata_xml,\n emailDomain: w.email_domain,\n enforceForDomain: w.enforce_for_domain,\n isActive: w.is_active,\n supabaseProviderId: w.supabase_provider_id,\n createdBy: w.created_by,\n createdAt: w.created_at,\n updatedAt: w.updated_at,\n };\n}\n\n// ── JIT provisioning rules ───────────────────────────────────────────────────\n\nexport type SsoRole = \"owner\" | \"admin\" | \"approver\" | \"member\" | \"viewer\";\n\n/** A JIT provisioning rule that maps an IdP claim to an org role. */\nexport interface SsoJitRule {\n id: string;\n connectionId: string;\n organizationId: string;\n claimAttribute: string;\n claimValue: string;\n grantedRole: SsoRole;\n precedence: number;\n isActive: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Wire (snake_case) shape for JIT rule responses. */\nexport interface SsoJitRuleWire {\n id: string;\n connection_id: string;\n organization_id: string;\n claim_attribute: string;\n claim_value: string;\n granted_role: SsoRole;\n precedence: number;\n is_active: boolean;\n created_at: string;\n updated_at: string;\n}\n\nexport function wireToSsoJitRule(w: SsoJitRuleWire): SsoJitRule {\n return {\n id: w.id,\n connectionId: w.connection_id,\n organizationId: w.organization_id,\n claimAttribute: w.claim_attribute,\n claimValue: w.claim_value,\n grantedRole: w.granted_role,\n precedence: w.precedence,\n isActive: w.is_active,\n createdAt: w.created_at,\n updatedAt: w.updated_at,\n };\n}\n\n// ── Events ───────────────────────────────────────────────────────────────────\n\n/**\n * An SSO lifecycle event — login, session, config change, break-glass, or\n * JIT provisioning.\n */\nexport interface SsoEvent {\n id: string;\n organizationId: string;\n connectionId: string | null;\n eventType: string;\n actorEmail: string | null;\n payload: Record<string, unknown>;\n occurredAt: string;\n}\n\n/** Wire (snake_case) shape for SSO event responses. */\nexport interface SsoEventWire {\n id: string;\n organization_id: string;\n connection_id: string | null;\n event_type: string;\n actor_email: string | null;\n payload: Record<string, unknown>;\n occurred_at: string;\n}\n\nexport function wireToSsoEvent(w: SsoEventWire): SsoEvent {\n return {\n id: w.id,\n organizationId: w.organization_id,\n connectionId: w.connection_id,\n eventType: w.event_type,\n actorEmail: w.actor_email,\n payload: w.payload,\n occurredAt: w.occurred_at,\n };\n}\n\n// ── Enforcement state machine ─────────────────────────────────────────────────\n\n/** Action to pass to `POST /v1/sso/enforce`. */\nexport type SsoEnforceAction = \"enable\" | \"enforce\";\n\n/**\n * Four-boolean readiness checklist returned by `GET /v1/sso/status`.\n * All four must be `true` before enforcement is safe to activate.\n */\nexport interface SsoReadiness {\n /** At least one SSO connection row exists for the org. */\n connectionConfigured: boolean;\n /** At least one connection has been activated (registered with the IdP). */\n connectionTested: boolean;\n /** Break-glass access has been configured (non-default settings). */\n breakGlassSet: boolean;\n /** No unreviewed active service API keys exist. */\n serviceApiKeysReviewed: boolean;\n}\n\n/** Wire (snake_case) shape for the readiness response. */\nexport interface SsoReadinessWire {\n connection_configured: boolean;\n connection_tested: boolean;\n break_glass_set: boolean;\n service_api_keys_reviewed: boolean;\n}\n\nexport function wireToSsoReadiness(w: SsoReadinessWire): SsoReadiness {\n return {\n connectionConfigured: w.connection_configured,\n connectionTested: w.connection_tested,\n breakGlassSet: w.break_glass_set,\n serviceApiKeysReviewed: w.service_api_keys_reviewed,\n };\n}\n\n// ── Sub-client ────────────────────────────────────────────────────────────────\n\n/** Input for creating a JIT provisioning rule. */\nexport interface SsoJitRuleInput {\n connectionId: string;\n claimAttribute: string;\n claimValue: string;\n grantedRole: SsoRole;\n precedence?: number;\n}\n\n/** Patchable fields for an existing JIT rule. */\nexport interface SsoJitRulePatch {\n claimAttribute?: string;\n claimValue?: string;\n grantedRole?: SsoRole;\n precedence?: number;\n isActive?: boolean;\n}\n\n/** Input for creating or updating an SSO connection. */\nexport interface SsoConnectionInput {\n name: string;\n protocol: \"saml\" | \"oidc\";\n idpEntityId: string;\n metadataUrl?: string | null;\n metadataXml?: string | null;\n emailDomain?: string | null;\n enforceForDomain?: boolean;\n}\n\n/** Result of `POST /v1/sso/enforce`. */\nexport interface SsoEnforceResult {\n ok: boolean;\n action: SsoEnforceAction;\n enforceSso: boolean;\n enforceSsoAt: string | null;\n}\n\ninterface SsoEnforceResultWire {\n ok: boolean;\n action: SsoEnforceAction;\n enforce_sso: boolean;\n enforce_sso_at: string | null;\n}\n\n/**\n * Sub-client for SSO administration.\n * Accessed as `client.sso` on {@link AtlaSentClient}.\n */\nexport interface SsoSubClient {\n /** List all SSO connections for the org. */\n listConnections(): Promise<{ connections: SsoConnection[] }>;\n\n /** Get a single SSO connection by ID. */\n getConnection(id: string): Promise<SsoConnection>;\n\n /** Create a new SSO connection. */\n createConnection(input: SsoConnectionInput): Promise<SsoConnection>;\n\n /** Update an existing SSO connection. */\n updateConnection(id: string, input: Partial<SsoConnectionInput>): Promise<SsoConnection>;\n\n /** Delete an SSO connection. */\n deleteConnection(id: string): Promise<void>;\n\n /** Activate (register) a connection with the IdP. */\n activateConnection(id: string): Promise<{ ok: boolean; supabaseProviderId: string | null }>;\n\n /**\n * Advance the SSO enforcement state machine.\n * `\"enable\"` → SSO enabled, not yet enforced.\n * `\"enforce\"` → SSO mandatory for all members (requires readiness checklist to pass).\n */\n enforce(action: SsoEnforceAction): Promise<SsoEnforceResult>;\n\n /** Get the four-boolean enforcement readiness checklist. */\n getStatus(): Promise<SsoReadiness>;\n\n // ── JIT provisioning rules ───────────────────────────────────────────────\n\n /** List JIT provisioning rules, optionally filtered to a single connection. */\n listJitRules(connectionId?: string): Promise<{ rules: SsoJitRule[] }>;\n\n /** Create a new JIT provisioning rule. */\n createJitRule(input: SsoJitRuleInput): Promise<SsoJitRule>;\n\n /** Update fields on an existing JIT rule. */\n patchJitRule(id: string, patch: SsoJitRulePatch): Promise<SsoJitRule>;\n\n /** Delete a JIT provisioning rule. */\n deleteJitRule(id: string): Promise<void>;\n}\n\nfunction ssoConnectionInputToWire(input: SsoConnectionInput | Partial<SsoConnectionInput>): Record<string, unknown> {\n const w: Record<string, unknown> = {};\n if (input.name !== undefined) w[\"name\"] = input.name;\n if (input.protocol !== undefined) w[\"protocol\"] = input.protocol;\n if (input.idpEntityId !== undefined) w[\"idp_entity_id\"] = input.idpEntityId;\n if (input.metadataUrl !== undefined) w[\"metadata_url\"] = input.metadataUrl;\n if (input.metadataXml !== undefined) w[\"metadata_xml\"] = input.metadataXml;\n if (input.emailDomain !== undefined) w[\"email_domain\"] = input.emailDomain;\n if (input.enforceForDomain !== undefined) w[\"enforce_for_domain\"] = input.enforceForDomain;\n return w;\n}\n\n/**\n * Factory that returns the SSO sub-client bound to a host client's transport\n * helpers. Called internally by AtlaSentClient; not part of the public API.\n */\nexport function makeSsoClient(\n getFn: <T>(path: string, query?: URLSearchParams) => Promise<{ body: T }>,\n postFn: <T>(path: string, body: unknown) => Promise<{ body: T }>,\n patchFn: <T>(path: string, body: unknown) => Promise<{ body: T }>,\n deleteFn: (path: string) => Promise<void>,\n): SsoSubClient {\n return {\n async listConnections() {\n const { body } = await getFn<{ connections: SsoConnectionWire[] }>(\"/v1/sso/connections\");\n return { connections: (body.connections ?? []).map(wireToSsoConnection) };\n },\n\n async getConnection(id: string) {\n const { body } = await getFn<SsoConnectionWire>(`/v1/sso/connections/${encodeURIComponent(id)}`);\n return wireToSsoConnection(body);\n },\n\n async createConnection(input: SsoConnectionInput) {\n const { body } = await postFn<SsoConnectionWire>(\"/v1/sso/connections\", ssoConnectionInputToWire(input));\n return wireToSsoConnection(body);\n },\n\n async updateConnection(id: string, input: Partial<SsoConnectionInput>) {\n const { body } = await patchFn<SsoConnectionWire>(\n `/v1/sso/connections/${encodeURIComponent(id)}`,\n ssoConnectionInputToWire(input),\n );\n return wireToSsoConnection(body);\n },\n\n async deleteConnection(id: string) {\n await deleteFn(`/v1/sso/connections/${encodeURIComponent(id)}`);\n },\n\n async activateConnection(id: string) {\n const { body } = await postFn<{ ok: boolean; supabase_provider_id: string | null }>(\n `/v1/sso/connections/${encodeURIComponent(id)}/activate`,\n {},\n );\n return { ok: body.ok, supabaseProviderId: body.supabase_provider_id };\n },\n\n async enforce(action: SsoEnforceAction) {\n const { body } = await postFn<SsoEnforceResultWire>(\"/v1/sso/enforce\", { action });\n return {\n ok: body.ok,\n action: body.action,\n enforceSso: body.enforce_sso,\n enforceSsoAt: body.enforce_sso_at,\n };\n },\n\n async getStatus() {\n const { body } = await getFn<{ readiness: SsoReadinessWire }>(\"/v1/sso/status\");\n return wireToSsoReadiness(body.readiness);\n },\n\n async listJitRules(connectionId?: string) {\n const qs = connectionId ? new URLSearchParams({ connection_id: connectionId }) : undefined;\n const { body } = await getFn<{ rules: SsoJitRuleWire[] }>(\"/v1/sso/jit-rules\", qs);\n return { rules: (body.rules ?? []).map(wireToSsoJitRule) };\n },\n\n async createJitRule(input: SsoJitRuleInput) {\n const payload: Record<string, unknown> = {\n connection_id: input.connectionId,\n claim_attribute: input.claimAttribute,\n claim_value: input.claimValue,\n granted_role: input.grantedRole,\n };\n if (input.precedence !== undefined) payload[\"precedence\"] = input.precedence;\n const { body } = await postFn<SsoJitRuleWire>(\"/v1/sso/jit-rules\", payload);\n return wireToSsoJitRule(body);\n },\n\n async patchJitRule(id: string, patch: SsoJitRulePatch) {\n const payload: Record<string, unknown> = {};\n if (patch.claimAttribute !== undefined) payload[\"claim_attribute\"] = patch.claimAttribute;\n if (patch.claimValue !== undefined) payload[\"claim_value\"] = patch.claimValue;\n if (patch.grantedRole !== undefined) payload[\"granted_role\"] = patch.grantedRole;\n if (patch.precedence !== undefined) payload[\"precedence\"] = patch.precedence;\n if (patch.isActive !== undefined) payload[\"is_active\"] = patch.isActive;\n const { body } = await patchFn<SsoJitRuleWire>(\n `/v1/sso/jit-rules/${encodeURIComponent(id)}`,\n payload,\n );\n return wireToSsoJitRule(body);\n },\n\n async deleteJitRule(id: string) {\n await deleteFn(`/v1/sso/jit-rules/${encodeURIComponent(id)}`);\n },\n };\n}\n","/**\n * Access Governance Log sub-client — paginated identity lifecycle events.\n *\n * Wire surface: GET /v1/access-governance-log\n *\n * Usage:\n *\n * ```ts\n * import { AtlaSentClient } from \"@atlasent/sdk\";\n *\n * const client = new AtlaSentClient({ apiKey: \"...\" });\n *\n * const page = await client.accessGovernanceLog.list({ limit: 50 });\n * for (const event of page.events) {\n * console.log(event.eventType, event.actorEmail);\n * }\n * if (page.nextCursor) {\n * const next = await client.accessGovernanceLog.list({ cursor: page.nextCursor });\n * }\n * ```\n */\n\n// ── Wire shape ────────────────────────────────────────────────────────────────\n\ninterface AccessGovernanceEventWire {\n id: string;\n event_type: string;\n org_id: string;\n actor_id: string | null;\n actor_email: string | null;\n ip_address: string | null;\n metadata: Record<string, unknown>;\n created_at: string;\n}\n\ninterface AccessGovernanceLogResponseWire {\n events: AccessGovernanceEventWire[];\n next_cursor: string | null;\n total_count: number;\n}\n\n// ── SDK shape ─────────────────────────────────────────────────────────────────\n\n/** A single identity lifecycle event from the access governance log. */\nexport interface AccessGovernanceEvent {\n id: string;\n eventType: string;\n orgId: string;\n actorId: string | null;\n actorEmail: string | null;\n ipAddress: string | null;\n metadata: Record<string, unknown>;\n createdAt: string;\n}\n\n/** A page of access governance events with cursor for the next page. */\nexport interface AccessGovernanceLogPage {\n events: AccessGovernanceEvent[];\n /** Pass as `cursor` to `list()` to fetch the next page. `null` means no more pages. */\n nextCursor: string | null;\n totalCount: number;\n}\n\n/** Query parameters for `accessGovernanceLog.list()`. */\nexport interface AccessGovernanceLogQuery {\n /** Max events to return. Default 50, max 200. */\n limit?: number;\n /** Cursor from a previous page's `nextCursor`. */\n cursor?: string;\n /** Filter by event type (e.g. `\"sso.login\"`, `\"jit.provisioned\"`). */\n eventType?: string;\n /** Filter by actor email or UUID. */\n actorId?: string;\n /** Lower bound on event timestamp (ISO 8601). */\n from?: string;\n /** Upper bound on event timestamp (ISO 8601). */\n to?: string;\n}\n\n// ── Converter ─────────────────────────────────────────────────────────────────\n\nfunction wireToEvent(w: AccessGovernanceEventWire): AccessGovernanceEvent {\n return {\n id: w.id,\n eventType: w.event_type,\n orgId: w.org_id,\n actorId: w.actor_id,\n actorEmail: w.actor_email,\n ipAddress: w.ip_address,\n metadata: w.metadata ?? {},\n createdAt: w.created_at,\n };\n}\n\n// ── Sub-client ────────────────────────────────────────────────────────────────\n\n/**\n * Sub-client for the access governance log.\n * Accessed as `client.accessGovernanceLog` on {@link AtlaSentClient}.\n */\nexport interface AccessGovernanceLogSubClient {\n /**\n * Fetch a page of identity lifecycle events for the authenticated org.\n *\n * ```ts\n * const { events, nextCursor } = await client.accessGovernanceLog.list({\n * eventType: \"sso.login\",\n * limit: 100,\n * });\n * ```\n */\n list(query?: AccessGovernanceLogQuery): Promise<AccessGovernanceLogPage>;\n}\n\n/**\n * Factory that returns the access-governance-log sub-client bound to a host\n * client's transport helpers. Called internally by AtlaSentClient.\n */\nexport function makeAccessGovernanceLogClient(\n getFn: <T>(path: string, query?: URLSearchParams) => Promise<{ body: T }>,\n): AccessGovernanceLogSubClient {\n return {\n async list(query: AccessGovernanceLogQuery = {}): Promise<AccessGovernanceLogPage> {\n const qs = new URLSearchParams();\n if (query.limit !== undefined) qs.set(\"limit\", String(query.limit));\n if (query.cursor) qs.set(\"cursor\", query.cursor);\n if (query.eventType) qs.set(\"event_type\", query.eventType);\n if (query.actorId) qs.set(\"actor_id\", query.actorId);\n if (query.from) qs.set(\"from\", query.from);\n if (query.to) qs.set(\"to\", query.to);\n\n const { body } = await getFn<AccessGovernanceLogResponseWire>(\n \"/v1/access-governance-log\",\n qs.size > 0 ? qs : undefined,\n );\n\n return {\n events: (body.events ?? []).map(wireToEvent),\n nextCursor: body.next_cursor,\n totalCount: body.total_count ?? 0,\n };\n },\n };\n}\n","/**\n * AtlaSent HTTP client.\n *\n * Two public methods, both backed by native `fetch`:\n * - {@link AtlaSentClient.evaluate} → POST {baseUrl}/v1-evaluate\n * - {@link AtlaSentClient.verifyPermit} → POST {baseUrl}/v1-verify-permit\n *\n * Fail-closed: a clean policy DENY is returned (not thrown), but\n * network, timeout, bad response, 4xx/5xx, and rate-limit conditions\n * all throw {@link AtlaSentError}.\n */\n\nimport type {\n AuditEventsPage,\n AuditEventsQuery,\n AuditExport,\n} from \"./audit.js\";\nimport type { ReplayDecisionResponse } from \"./replay.js\";\nimport type {\n ReplayRequest,\n ReplayResponse,\n ReplayVarianceKind,\n} from \"./replay.js\";\nimport {\n AtlaSentError,\n StreamParseError,\n StreamTimeoutError,\n type AtlaSentErrorCode,\n type AtlaSentErrorInit,\n} from \"./errors.js\";\nimport {\n TrustRootManager,\n getGlobalTrustRootManager,\n type TrustRootSnapshot,\n} from \"./trustRoot.js\";\nimport { PRODUCTION_DEPLOY_ACTION } from \"./types.js\";\nimport type {\n ApiKeySelfResponse,\n AtlaSentClientOptions,\n Decision,\n AuditEventsResult,\n AuditExportRequest,\n AuditExportResult,\n ConstraintTrace,\n DecisionCanonical,\n DecisionStreamEvent,\n DeployGateEvidence,\n DeployGateRequest,\n DeployGateResponse,\n BatchEvalItem,\n BatchEvalResponse,\n EvaluateBatchResultItem,\n EvaluatePreflightResponse,\n SubscribeDecisionsOptions,\n EvaluateRequest,\n EvaluateResponse,\n GetPermitResponse,\n ListPermitsRequest,\n ListPermitsResponse,\n PermitRecord,\n PermitValidResponse,\n RateLimitState,\n RevokePermitByIdInput,\n RevokePermitByIdResponse,\n RevokePermitRequest,\n RevokePermitResponse,\n StreamDecisionEvent,\n StreamEvent,\n StreamOptions,\n StreamProgressEvent,\n VerifyPermitByIdResponse,\n VerifyPermitRequest,\n VerifyPermitResponse,\n} from \"./types.js\";\nimport {\n normalizeEvaluateRequest,\n type LegacyEvaluateRequest,\n type V2EvaluateRequest,\n} from \"./compat.js\";\nimport {\n computeBackoffMs,\n hasAttemptsLeft,\n isRetryable,\n mergePolicy,\n type RetryPolicy,\n} from \"./retry.js\";\nimport type {\n GovernanceAgent,\n GovernanceAgentEvaluation,\n GovernanceAgentFinding,\n ListGovernanceAgentsResponse,\n ListGovernanceEvaluationsQuery,\n ListGovernanceEvaluationsResponse,\n ListGovernanceFindingsQuery,\n ListGovernanceFindingsResponse,\n} from \"./governanceAgents.js\";\nimport type {\n HitlApprovalRecord,\n HitlApproveRequest,\n HitlChainHop,\n HitlCreateRequest,\n HitlEscalateRequest,\n HitlEscalation,\n HitlRejectRequest,\n ListHitlEscalationsRequest,\n ListHitlEscalationsResponse,\n} from \"./hitl.js\";\nimport type {\n GovernanceGraphQueryType,\n GovernanceGraphQueryParams,\n GovernanceGraphQueryResponse,\n GovernanceGraphResultRow,\n} from \"./governanceGraph.js\";\nimport type { IncidentTimelineResponse } from \"./incidentReconstruction.js\";\nimport type {\n ConnectorType,\n InstallConnectorInput,\n AuthenticateConnectorInput,\n UpsertEnforcementPolicyInput,\n ListConnectorsResponse,\n InstallConnectorResponse,\n AuthenticateConnectorResponse,\n SyncConnectorResponse,\n RevokeConnectorResponse,\n RotateCredentialsResponse,\n ListEnforcementPoliciesResponse,\n UpsertEnforcementPolicyResponse,\n} from \"./connectorManagement.js\";\nimport type {\n ComputeOrgRiskOptions,\n ComputeOrgRiskResponse,\n GetLatestOrgRiskResponse,\n ListOrgRiskHistoryResponse,\n} from \"./orgRiskGraph.js\";\nimport type {\n CrossOrgPermissionCheckRequest,\n CrossOrgPermissionCheckResult,\n CrossOrgPermissionCheckListParams,\n} from \"./crossOrgPermission.js\";\nimport type {\n AnomalyResponseRule,\n AnomalyResponseEvent,\n CreateAnomalyResponseRuleRequest,\n TriggerAnomalyResponseRequest,\n} from \"./anomalyResponse.js\";\nimport type {\n BudgetExceptionRequest,\n BudgetExceptionStatus,\n CreateBudgetExceptionRequest,\n ApproveBudgetExceptionRequest,\n} from \"./budgetExceptions.js\";\nimport type {\n RegulatoryAuthorityLevel,\n RegulatoryEscalation,\n RegulatoryEscalationStatus,\n CreateRegulatoryEscalationRequest,\n} from \"./regulatoryEscalation.js\";\nimport type {\n GovernanceSignalAction,\n RecordSignalActionRequest,\n RecordSignalOutcomeRequest,\n SignalActionSummary,\n} from \"./incentiveSignalFeedback.js\";\nimport type {\n CrossOrgImpersonationGrant,\n CreateImpersonationGrantRequest,\n ImpersonationToken,\n ImpersonationValidationResult,\n} from \"./crossOrgImpersonation.js\";\nimport {\n makeScimClient,\n type ScimSubClient,\n} from \"./scim.js\";\nimport {\n makeEvidenceBundleClient,\n type EvidenceBundleSubClient,\n} from \"./evidence-bundle.js\";\nimport {\n makeAuthClient,\n type AuthSubClient,\n} from \"./auth.js\";\nimport {\n makeSsoClient,\n type SsoSubClient,\n} from \"./sso.js\";\nimport {\n makeAccessGovernanceLogClient,\n type AccessGovernanceLogSubClient,\n} from \"./access-governance-log.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.atlasent.io\";\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst SDK_VERSION = \"2.10.0\";\n\n/**\n * Guard flag: emit the browser-environment warning at most once per\n * module-load lifetime. Prevents console spam when many client\n * instances are constructed in the same bundle.\n */\nlet warnedBrowser = false;\nconst V1_EVALUATE_BATCH_PATH = \"/v1/evaluate/batch\";\nconst V1_EVALUATE_BATCH_LEGACY_PATH = \"/v1-evaluate-batch\";\nconst V1_EVALUATE_STREAM_PATH = \"/v1/evaluate/stream\";\nconst V1_EVALUATE_STREAM_LEGACY_PATH = \"/v1-evaluate-stream\";\n\nfunction _buildUserAgent(): string {\n const isNode =\n typeof process !== \"undefined\" &&\n typeof process?.versions?.node === \"string\";\n return isNode\n ? `@atlasent/sdk/${SDK_VERSION} node/${process.version}`\n : `@atlasent/sdk/${SDK_VERSION} browser`;\n}\n\n// Soft cap on top-level context properties. Mirrors the Python SDK\n// (atlasent.models._CONTEXT_PROPERTIES_SOFT_CAP) and the OpenAPI\n// `maxProperties: 64` declaration. The hosted API is the canonical\n// enforcer; this helper warns the developer in dev rather than\n// raising, so production traffic isn't broken on the day this ships.\nconst CONTEXT_PROPERTIES_SOFT_CAP = 64;\n\nfunction _warnOversizeContext(\n context: Record<string, unknown> | undefined,\n): void {\n if (context && Object.keys(context).length > CONTEXT_PROPERTIES_SOFT_CAP) {\n // eslint-disable-next-line no-console\n console.warn(\n `[atlasent] context has ${Object.keys(context).length} top-level keys ` +\n `(soft cap ${CONTEXT_PROPERTIES_SOFT_CAP}); the server may reject this. ` +\n \"Pack richer payloads under a single top-level key.\",\n );\n }\n}\n\n/**\n * Reject non-TLS base URLs unless the dev escape hatch is set.\n *\n * `ATLASENT_ALLOW_INSECURE_HTTP=1` (Node) or\n * `globalThis.ATLASENT_ALLOW_INSECURE_HTTP === \"1\"` (browser dev) permits\n * `http://` for local fixtures — production callers never set this.\n * Non-`http(s)` schemes (data:, file:, ...) are rejected unconditionally.\n *\n * Guards `process.env` access with an explicit `typeof` check so this\n * function is safe in browser and edge-runtime environments where\n * `process` is not defined as a global.\n */\nfunction _enforceTls(baseUrl: string): string {\n const nodeEnvValue =\n typeof process !== \"undefined\" && process.env\n ? process.env.ATLASENT_ALLOW_INSECURE_HTTP\n : undefined;\n const allow =\n nodeEnvValue === \"1\" ||\n (globalThis as { ATLASENT_ALLOW_INSECURE_HTTP?: string })\n .ATLASENT_ALLOW_INSECURE_HTTP === \"1\";\n if (allow) return baseUrl;\n let parsed: URL;\n try {\n parsed = new URL(baseUrl);\n } catch {\n throw new AtlaSentError(`Invalid baseUrl: ${baseUrl}`, {\n code: \"bad_request\",\n });\n }\n if (parsed.protocol !== \"https:\") {\n throw new AtlaSentError(\n `AtlaSent baseUrl must use https:// (got ${parsed.protocol}). ` +\n `For local development, set ATLASENT_ALLOW_INSECURE_HTTP=1.`,\n { code: \"bad_request\" },\n );\n }\n return baseUrl;\n}\n\n// API-key prefix contract per atlasent-api/_shared/auth.ts:\n// \"ask_live_<entropy>\" — production\n// \"ask_test_<entropy>\" — non-production\n// Validated client-side so a mis-pasted key (with whitespace, quotes,\n// or a leftover wrapping char) trips loudly at construction rather\n// than yielding a 401 mid-conversation.\nconst API_KEY_PATTERN = /^ask_(?:live|test)_[A-Za-z0-9_-]+$/;\n\nfunction _validateApiKey(apiKey: string): string {\n if (typeof apiKey !== \"string\" || apiKey.length === 0) {\n throw new AtlaSentError(\"apiKey is required\", { code: \"invalid_api_key\" });\n }\n if (!API_KEY_PATTERN.test(apiKey)) {\n const head = apiKey.slice(0, 8);\n throw new AtlaSentError(\n `AtlaSent apiKey does not match expected shape ` +\n `\\`ask_(live|test)_<entropy>\\` (got prefix=${JSON.stringify(head)}). ` +\n \"Check for whitespace, quotes, or trailing characters.\",\n { code: \"invalid_api_key\" },\n );\n }\n return apiKey;\n}\n\n/**\n * True when running in Node.js (or a Node-compatible server runtime that\n * exposes `process.versions.node`). False in browsers and browser-like\n * environments such as jsdom / Cloudflare Workers.\n */\nconst isNode =\n typeof process !== \"undefined\" && typeof process.versions?.node === \"string\";\n\n/**\n * Node.js version string captured at module-load time so request code\n * never accesses `process` lazily — safe even if `process` is absent\n * (browsers) or replaced after load (bundlers, test environments).\n * `null` in every non-Node runtime.\n */\nconst NODE_VERSION: string | null = isNode ? process.version : null;\n\n/**\n * Raw JSON shape received from `POST /v1-evaluate`.\n *\n * Canonical fields (per `atlasent-api/.../v1-evaluate/handler.ts`):\n * decision: \"allow\" | \"deny\" | \"hold\" | \"escalate\"\n * permit_token: string (present iff decision === \"allow\")\n * request_id: string\n * expires_at?: string\n * denial?: { reason, code }\n *\n * Legacy fields kept on the type so older atlasent-api deployments\n * (pre-handler.ts entry swap) still parse cleanly. The client below\n * checks canonical first and falls back to legacy.\n */\ninterface EvaluateWire {\n decision: \"allow\" | \"deny\" | \"hold\" | \"escalate\";\n permit_token?: string;\n request_id?: string;\n expires_at?: string;\n denial?: { reason?: string; code?: string };\n /**\n * Optional sub-object — present iff the request URL carried\n * `?include=constraint_trace`. Older atlasent-api deployments\n * omit this even when `include` was requested; the preflight\n * helper degrades to `null` in that case.\n */\n constraint_trace?: unknown;\n // Legacy passthrough.\n permitted?: boolean;\n decision_id?: string;\n reason?: string;\n audit_hash?: string;\n timestamp?: string;\n risk_envelope?: {\n weighted_score: number;\n engine_decision: string;\n envelope_decision: string;\n promoted: boolean;\n hard_blocks: string[];\n factors?: Array<{ factor: string; value: number; weight: number; reason: string }>;\n };\n // State-context response fields (control-plane v2+).\n risk_class?: string;\n authority_basis?: {\n kind: string;\n reference?: string;\n granted_by?: string;\n rationale?: string;\n expires_at?: string;\n };\n escalation_id?: string;\n}\n\ninterface EvaluateBatchWireItem {\n index: number;\n decision?: string;\n decision_id?: string;\n permit_token?: string | null;\n reason?: string | null;\n audit_entry_hash?: string;\n timestamp?: string;\n error?: string;\n message?: string;\n status?: number;\n}\n\ninterface EvaluateBatchWire {\n batch_id: string;\n items: EvaluateBatchWireItem[];\n partial?: boolean;\n replayed?: boolean;\n}\n\nfunction deployGateEvidence(input: {\n permitId?: string;\n permitHash?: string;\n auditHash?: string;\n verifiedAt?: string;\n}): DeployGateEvidence {\n const evidence: DeployGateEvidence = {};\n if (input.permitId) evidence.permitId = input.permitId;\n if (input.permitHash) evidence.permitHash = input.permitHash;\n if (input.auditHash) evidence.auditHash = input.auditHash;\n if (input.verifiedAt) evidence.verifiedAt = input.verifiedAt;\n return evidence;\n}\n\n/** Raw JSON shape received from `GET /v1-api-key-self`. */\ninterface ApiKeySelfWire {\n key_id: string;\n org_id: string;\n environment: string;\n scopes?: string[];\n allowed_cidrs?: string[] | null;\n rate_limit_per_minute: number;\n client_ip?: string | null;\n expires_at?: string | null;\n}\n\n/**\n * Raw JSON shape received from `POST /v1-verify-permit`.\n *\n * Canonical fields:\n * valid: boolean\n * outcome: \"allow\" | \"deny\"\n * verify_error_code?: string (populated on outcome === \"deny\")\n * reason?: string\n *\n * Legacy `verified` kept for backward-compat with older deployments.\n */\ninterface VerifyPermitWire {\n valid: boolean;\n outcome: \"allow\" | \"deny\";\n verify_error_code?: string;\n reason?: string;\n expires_at?: string | null;\n // Legacy passthrough.\n verified?: boolean;\n permit_hash?: string;\n timestamp?: string;\n}\n\nexport class AtlaSentClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly timeoutMs: number;\n private readonly fetchImpl: typeof fetch;\n private readonly userAgent: string;\n private readonly retryPolicy: Required<RetryPolicy>;\n\n /** SCIM 2.0 provisioning sub-client. Access as `client.scim`. */\n readonly scim: ScimSubClient;\n /** Evidence bundle sub-client. Access as `client.evidenceBundles`. */\n readonly evidenceBundles: EvidenceBundleSubClient;\n /** Auth / token management sub-client. Access as `client.auth`. */\n readonly auth: AuthSubClient;\n /** SSO administration sub-client. Access as `client.sso`. */\n readonly sso: SsoSubClient;\n /** Access governance log sub-client. Access as `client.accessGovernanceLog`. */\n readonly accessGovernanceLog: AccessGovernanceLogSubClient;\n /** Trust-root snapshot manager for this client instance. */\n readonly trustRoot: TrustRootManager;\n\n constructor(options: AtlaSentClientOptions) {\n if (!options.apiKey || typeof options.apiKey !== \"string\") {\n throw new AtlaSentError(\"apiKey is required\", {\n code: \"invalid_api_key\",\n });\n }\n if (typeof AbortSignal.timeout !== \"function\") {\n throw new AtlaSentError(\n \"@atlasent/sdk requires AbortSignal.timeout, which is not available in this runtime. \" +\n \"Minimum supported browsers: Chrome 103+, Firefox 100+, Safari 16+. \" +\n \"Upgrade your browser or add an AbortSignal.timeout polyfill.\",\n { code: \"network\" },\n );\n }\n if (\n !warnedBrowser &&\n typeof (globalThis as Record<string, unknown>)[\"window\"] !== \"undefined\" &&\n typeof process === \"undefined\"\n ) {\n warnedBrowser = true;\n // eslint-disable-next-line no-console\n console.warn(\n \"[@atlasent/sdk] Running in a browser environment. \" +\n \"API keys should not be exposed in client-side bundles. \" +\n \"Use a server-side proxy instead.\",\n );\n }\n this.apiKey = _validateApiKey(options.apiKey);\n this.baseUrl = _enforceTls(options.baseUrl ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n \"\",\n );\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n this.userAgent = _buildUserAgent();\n this.retryPolicy = mergePolicy(options.retryPolicy ?? {});\n this.scim = makeScimClient(\n (path, body, query) => this._post(path, body, query),\n (path, query) => this._get(path, query),\n (path, body) => this._put(path, body),\n (path) => this._delete(path),\n );\n this.evidenceBundles = makeEvidenceBundleClient(\n (path, body) => this._post(path, body),\n (path, query) => this._get(path, query),\n (path) => this._getRaw(path),\n );\n this.auth = makeAuthClient(\n (path, body) => this._post(path, body),\n (path) => this._get(path),\n );\n this.sso = makeSsoClient(\n (path, query) => this._get(path, query),\n (path, body) => this._post(path, body),\n (path, body) => this._patch(path, body),\n (path) => this._delete(path),\n );\n this.accessGovernanceLog = makeAccessGovernanceLogClient(\n (path, query) => this._get(path, query),\n );\n // Wire trust-root manager. Prefer custom options over the global manager\n // so clients with custom trustRootUrl or trustSnapshotRefreshMs get their\n // own manager; otherwise share the process-global singleton.\n if (options.trustRootUrl !== undefined || options.trustSnapshotRefreshMs !== undefined) {\n const globalSnap = getGlobalTrustRootManager({ disableRefresh: true }).getSnapshot();\n this.trustRoot = new TrustRootManager(globalSnap, {\n ...(options.trustRootUrl !== undefined && { refreshBaseUrl: options.trustRootUrl }),\n ...(options.trustSnapshotRefreshMs !== undefined && { refreshIntervalMs: options.trustSnapshotRefreshMs }),\n });\n } else {\n this.trustRoot = getGlobalTrustRootManager();\n }\n // Emit expiry warning once at construction time.\n this.trustRoot.checkExpiry();\n }\n\n /** Return the current trust-root snapshot (pinned or last successful refresh). */\n getTrustSnapshot(): TrustRootSnapshot {\n return this.trustRoot.getSnapshot();\n }\n\n /**\n * Ask the policy engine whether an agent action is permitted.\n *\n * Accepts either the current v2.0 shape (`action_type` / `actor_id`)\n * or the legacy v1.x shape (`action` / `agent`). Legacy callers\n * receive a deprecation warning via `console.warn`; the shim is\n * handled by {@link normalizeEvaluateRequest} and will be removed\n * in v3.0.0.\n *\n * A \"deny\" is **not** thrown — it is returned in\n * `response.decision`. Network errors, invalid API key, rate\n * limits, timeouts, and malformed responses throw\n * {@link AtlaSentError}.\n */\n async evaluate(\n input: EvaluateRequest | LegacyEvaluateRequest,\n ): Promise<EvaluateResponse> {\n _warnOversizeContext(input.context);\n\n // Run the dual-shape bridge: legacy {action, agent} → {action_type, actor_id}.\n // For callers already on the current EvaluateRequest shape the bridge is a\n // transparent pass-through (no warn, no allocation).\n const normalized = normalizeEvaluateRequest(\n input as LegacyEvaluateRequest | V2EvaluateRequest,\n );\n\n const body: Record<string, unknown> = {\n action_type: normalized.action_type,\n actor_id: normalized.actor_id,\n context: normalized.context ?? {},\n };\n if (normalized.explain !== undefined) body.explain = normalized.explain;\n if (normalized.environment !== undefined) body.environment = normalized.environment;\n if (normalized.resource !== undefined) body.resource = normalized.resource;\n if (normalized.current_state !== undefined) body.current_state = normalized.current_state;\n if (normalized.proposed_state !== undefined) body.proposed_state = normalized.proposed_state;\n if (normalized.execution_binding !== undefined) body.execution_binding = normalized.execution_binding;\n const { body: wire, rateLimit } = await this.post<EvaluateWire>(\n \"/v1-evaluate\",\n body,\n );\n\n // Normalise decision to lowercase canonical form. API responses may\n // arrive as uppercase (legacy deployments) or lowercase (canonical);\n // we always emit lowercase so callers can rely on a stable vocabulary.\n let decision = (\n typeof wire.decision === \"string\"\n ? wire.decision.toLowerCase()\n : wire.decision\n ) as EvaluateWire[\"decision\"] | undefined;\n\n // Tolerate both canonical {decision, permit_token} and legacy\n // {permitted, decision_id} server responses.\n if (decision === undefined && typeof wire.permitted === \"boolean\") {\n decision = wire.permitted ? \"allow\" : \"deny\";\n }\n const permitToken = wire.permit_token ?? wire.decision_id;\n\n if (\n decision !== \"allow\" &&\n decision !== \"deny\" &&\n decision !== \"hold\" &&\n decision !== \"escalate\"\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-evaluate: missing `decision` (or legacy `permitted`)\",\n { code: \"bad_response\" },\n );\n }\n if (\n decision === \"allow\" &&\n (typeof permitToken !== \"string\" || permitToken.length === 0)\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-evaluate: decision='allow' but no `permit_token` (or legacy `decision_id`)\",\n { code: \"bad_response\" },\n );\n }\n\n const reason = wire.denial?.reason ?? wire.reason ?? \"\";\n const permitId = permitToken ?? \"\";\n return {\n decision,\n decision_canonical: decision,\n evaluationId: permitId,\n permitId,\n // /v1-evaluate does not return a control-plane-shaped Permit body;\n // callers needing the full record fetch GET /v1/permits/:id.\n permit: null,\n permitToken: decision === \"allow\" ? (permitToken ?? null) : null,\n reasons: reason ? [reason] : [],\n reason,\n auditHash: wire.audit_hash ?? \"\",\n timestamp: wire.timestamp ?? \"\",\n rateLimit,\n ...(wire.risk_envelope && {\n riskEnvelope: {\n weightedScore: wire.risk_envelope.weighted_score,\n engineDecision: wire.risk_envelope.engine_decision as Decision,\n envelopeDecision: wire.risk_envelope.envelope_decision as Decision,\n promoted: wire.risk_envelope.promoted,\n hardBlocks: wire.risk_envelope.hard_blocks ?? [],\n ...(wire.risk_envelope.factors && { factors: wire.risk_envelope.factors }),\n },\n }),\n ...(wire.risk_class !== undefined && { riskClass: wire.risk_class }),\n ...(wire.authority_basis && {\n authorityBasis: {\n kind: wire.authority_basis.kind as NonNullable<EvaluateResponse[\"authorityBasis\"]>[\"kind\"],\n ...(wire.authority_basis.reference !== undefined && { reference: wire.authority_basis.reference }),\n ...(wire.authority_basis.granted_by !== undefined && { grantedBy: wire.authority_basis.granted_by }),\n ...(wire.authority_basis.rationale !== undefined && { rationale: wire.authority_basis.rationale }),\n ...(wire.authority_basis.expires_at !== undefined && { expiresAt: wire.authority_basis.expires_at }),\n },\n }),\n ...(wire.escalation_id !== undefined && { escalationId: wire.escalation_id }),\n };\n }\n\n /**\n * Batch evaluate — send up to 100 decisions in a single round-trip.\n *\n * Wraps `POST /v1/evaluate/batch` (with fallback to\n * `POST /v1-evaluate-batch` on older runtimes). The server evaluates each item\n * against the active policy bundle and returns results in the same\n * order as the input. One rate-limit token is consumed for the\n * whole batch, and one audit-chain entry lists every included\n * decision id.\n *\n * A per-item policy `deny` is **not** thrown — it appears as\n * `item.decision === \"deny\"` in the returned items. A whole-batch\n * network error, 4xx, or 5xx throws {@link AtlaSentError}.\n *\n * Requires the `v2_batch` tenant feature flag to be enabled on the\n * org (returns 404 when off). Requires scope `evaluate:write`.\n *\n * @param requests - 1–100 evaluate items.\n * @param batchId - Optional caller-supplied UUID for idempotency.\n * A retried call with the same `batchId` and identical items\n * returns the cached response within 24 h (`replayed: true`).\n */\n async evaluateBatch(\n requests: BatchEvalItem[],\n batchId?: string,\n ): Promise<BatchEvalResponse> {\n if (!Array.isArray(requests) || requests.length === 0) {\n throw new AtlaSentError(\n \"evaluateBatch: requests must be a non-empty array\",\n { code: \"bad_request\" },\n );\n }\n if (requests.length > 100) {\n throw new AtlaSentError(\n `evaluateBatch: requests.length ${requests.length} exceeds the 100-item cap`,\n { code: \"bad_request\" },\n );\n }\n\n const wireItems = requests.map((r) => ({\n action_type: r.action,\n actor_id: r.agent,\n context: r.context ?? {},\n }));\n\n const wireBody: Record<string, unknown> = { items: wireItems };\n if (batchId) wireBody.batch_id = batchId;\n\n const { body: wire, rateLimit } = await this.postWithPathFallback<EvaluateBatchWire>(\n V1_EVALUATE_BATCH_PATH,\n V1_EVALUATE_BATCH_LEGACY_PATH,\n wireBody,\n );\n\n const items: EvaluateBatchResultItem[] = (wire.items ?? []).map(\n (item: EvaluateBatchWireItem) => {\n const rawDecision = typeof item.decision === \"string\"\n ? item.decision.toLowerCase()\n : undefined;\n const decision = (\n rawDecision === \"allow\" ||\n rawDecision === \"deny\" ||\n rawDecision === \"hold\" ||\n rawDecision === \"escalate\"\n ? rawDecision\n : undefined\n ) as DecisionCanonical | undefined;\n\n return {\n index: item.index,\n ...(decision !== undefined ? { decision } : {}),\n ...(item.decision_id ? { decisionId: item.decision_id } : {}),\n ...(item.permit_token != null ? { permitToken: item.permit_token } : {}),\n ...(item.reason != null ? { reason: item.reason } : {}),\n ...(item.audit_entry_hash ? { auditHash: item.audit_entry_hash } : {}),\n ...(item.timestamp ? { timestamp: item.timestamp } : {}),\n ...(item.error ? { error: item.error } : {}),\n ...(item.message ? { message: item.message } : {}),\n } satisfies EvaluateBatchResultItem;\n },\n );\n\n return {\n batchId: wire.batch_id,\n items,\n partial: wire.partial ?? false,\n ...(wire.replayed ? { replayed: wire.replayed } : {}),\n rateLimit,\n };\n }\n\n /**\n * Subscribe to a live stream of decisions for this org.\n *\n * Wraps `GET /v1-decisions-stream`. The server emits one SSE frame\n * per audit event and sends a heartbeat every 15 s. The session\n * auto-closes after `maxSeconds` (default 30 min); reconnect with\n * the last received `event.id` to resume without replaying history.\n *\n * ```ts\n * const controller = new AbortController();\n * for await (const event of client.subscribeDecisions({ signal: controller.signal })) {\n * if (event.type === \"heartbeat\") continue;\n * console.log(event.type, event.decision, event.actorId);\n * if (event.type === \"session_end\") break; // reconnect\n * }\n * ```\n *\n * Requires scope `audit:read`. Requires the `v2_decisions_stream`\n * tenant feature flag (returns 404 when off).\n */\n async *subscribeDecisions(\n opts: SubscribeDecisionsOptions = {},\n ): AsyncGenerator<DecisionStreamEvent> {\n const url = new URL(`${this.baseUrl}/v1-decisions-stream`);\n if (opts.types?.length) url.searchParams.set(\"types\", opts.types.join(\",\"));\n if (opts.actorId) url.searchParams.set(\"actor_id\", opts.actorId);\n if (opts.maxSeconds !== undefined) url.searchParams.set(\"max_seconds\", String(opts.maxSeconds));\n\n const headers: Record<string, string> = {\n Accept: \"text/event-stream\",\n Authorization: `Bearer ${this.apiKey}`,\n \"User-Agent\": this.userAgent,\n // ADR-025: declare the wire-protocol version we were built\n // against. Runtime serves this version's response shape; older\n // versions outside the compatibility window get 426.\n \"X-AtlaSent-Protocol-Version\": \"1\",\n };\n if (opts.lastEventId) headers[\"Last-Event-ID\"] = opts.lastEventId;\n\n let response: Response;\n try {\n response = await this.fetchImpl(url.toString(), {\n method: \"GET\",\n headers,\n ...(opts.signal ? { signal: opts.signal } : {}),\n });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") return;\n throw new AtlaSentError(\n `Failed to connect to decisions stream: ${err instanceof Error ? err.message : String(err)}`,\n { code: \"network\" },\n );\n }\n\n if (!response.ok) {\n const code = response.status === 401 ? \"invalid_api_key\" : \"server_error\";\n throw new AtlaSentError(\n `Decisions stream returned ${response.status}`,\n { code, status: response.status },\n );\n }\n\n if (!response.body) {\n throw new AtlaSentError(\"Decisions stream response has no body\", { code: \"bad_response\" });\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder(\"utf-8\");\n let buf = \"\";\n\n try {\n while (true) {\n let chunk: Awaited<ReturnType<typeof reader.read>>;\n try {\n chunk = await reader.read();\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") return;\n throw new AtlaSentError(\n `Decisions stream read error: ${err instanceof Error ? err.message : String(err)}`,\n { code: \"network\" },\n );\n }\n if (chunk.done) break;\n\n buf += decoder.decode(chunk.value, { stream: true });\n const rawBlocks = buf.split(\"\\n\\n\");\n buf = rawBlocks.pop() ?? \"\";\n\n for (const block of rawBlocks) {\n if (!block.trim()) continue;\n\n // SSE comment / heartbeat line (\": …\")\n if (block.trimStart().startsWith(\":\")) {\n yield { type: \"heartbeat\" };\n continue;\n }\n\n let id: string | undefined;\n let eventType = \"audit_event\";\n let dataLine = \"\";\n\n for (const line of block.split(\"\\n\")) {\n if (line.startsWith(\"id:\")) id = line.slice(3).trim();\n else if (line.startsWith(\"event:\")) eventType = line.slice(6).trim();\n else if (line.startsWith(\"data:\")) dataLine = line.slice(5).trim();\n }\n\n if (!dataLine) continue;\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(dataLine) as Record<string, unknown>;\n } catch {\n continue;\n }\n\n if (eventType === \"session_end\") {\n yield { ...(id !== undefined ? { id } : {}), type: \"session_end\", payload: parsed };\n return;\n }\n\n const decision = typeof parsed.decision === \"string\"\n ? parsed.decision.toLowerCase() as DecisionCanonical\n : undefined;\n\n yield {\n ...(id !== undefined ? { id } : {}),\n type: eventType,\n ...(decision ? { decision } : {}),\n ...(typeof parsed.actor_id === \"string\" ? { actorId: parsed.actor_id } : {}),\n ...(typeof parsed.resource_type === \"string\" ? { resourceType: parsed.resource_type } : {}),\n ...(typeof parsed.resource_id === \"string\" ? { resourceId: parsed.resource_id } : {}),\n ...(parsed.payload && typeof parsed.payload === \"object\" ? { payload: parsed.payload as Record<string, unknown> } : {}),\n ...(typeof parsed.hash === \"string\" ? { hash: parsed.hash } : {}),\n ...(typeof parsed.previous_hash === \"string\" ? { previousHash: parsed.previous_hash } : {}),\n ...(typeof parsed.occurred_at === \"string\" ? { occurredAt: parsed.occurred_at } : {}),\n } satisfies DecisionStreamEvent;\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Pre-flight evaluation that always returns the constraint trace.\n *\n * Wraps `POST /v1-evaluate?include=constraint_trace`. Use this from\n * a workflow's submission step to surface trivial defects (missing\n * fields, wrong roles, mis-set context) BEFORE pushing the request\n * onto an approval queue — only requests that would actually pass\n * make it through to a human reviewer.\n *\n * Returns an {@link EvaluatePreflightResponse} carrying the regular\n * {@link EvaluateResponse} plus the {@link ConstraintTrace}. Unlike\n * {@link evaluate}, this method does NOT mark a non-allow as a\n * thrown condition — the whole point is to inspect both the outcome\n * AND the per-policy trace, so the caller branches on\n * `result.evaluation.decision` and reads `result.constraintTrace`\n * to render the failing stages.\n *\n * The constraint-trace shape mirrors `ConstraintTraceResponse` in\n * atlasent-api (`packages/types/src/index.ts`). On older\n * atlasent-api deployments that omit the trace, `constraintTrace`\n * is `null` rather than throwing — forward-compatible degradation.\n *\n * Performance: one extra round-trip on submission. Latency is\n * comparable to {@link evaluate}; the response body is fuller\n * (includes the per-stage trace) so the wire payload is larger.\n * If the caller does not need the trace, prefer {@link evaluate}.\n */\n async evaluatePreflight(\n input: EvaluateRequest,\n ): Promise<EvaluatePreflightResponse> {\n _warnOversizeContext(input.context);\n const body = {\n action_type: input.action,\n actor_id: input.agent,\n context: input.context ?? {},\n };\n const query = new URLSearchParams({ include: \"constraint_trace\" });\n const { body: wire, rateLimit } = await this.post<EvaluateWire>(\n \"/v1-evaluate\",\n body,\n query,\n );\n\n // Normalise decision to lowercase canonical form.\n let decision = (\n typeof wire.decision === \"string\"\n ? wire.decision.toLowerCase()\n : wire.decision\n ) as EvaluateWire[\"decision\"] | undefined;\n\n if (decision === undefined && typeof wire.permitted === \"boolean\") {\n decision = wire.permitted ? \"allow\" : \"deny\";\n }\n if (\n decision !== \"allow\" &&\n decision !== \"deny\" &&\n decision !== \"hold\" &&\n decision !== \"escalate\"\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-evaluate: missing `decision` (or legacy `permitted`)\",\n { code: \"bad_response\" },\n );\n }\n const permitToken = wire.permit_token ?? wire.decision_id;\n\n const reason = wire.denial?.reason ?? wire.reason ?? \"\";\n const permitId = permitToken ?? \"\";\n const evaluation: EvaluateResponse = {\n decision,\n decision_canonical: decision,\n evaluationId: permitId,\n permitId,\n // /v1-evaluate does not return a control-plane-shaped Permit body;\n // callers needing the full record fetch GET /v1/permits/:id.\n permit: null,\n permitToken: decision === \"allow\" ? (permitToken ?? null) : null,\n reasons: reason ? [reason] : [],\n reason,\n auditHash: wire.audit_hash ?? \"\",\n timestamp: wire.timestamp ?? \"\",\n rateLimit,\n ...(wire.risk_envelope && {\n riskEnvelope: {\n weightedScore: wire.risk_envelope.weighted_score,\n engineDecision: wire.risk_envelope.engine_decision as Decision,\n envelopeDecision: wire.risk_envelope.envelope_decision as Decision,\n promoted: wire.risk_envelope.promoted,\n hardBlocks: wire.risk_envelope.hard_blocks ?? [],\n ...(wire.risk_envelope.factors && { factors: wire.risk_envelope.factors }),\n },\n }),\n };\n\n // Forward-compat: if the server omits `constraint_trace` (older\n // atlasent-api version), surface trace=null rather than throwing.\n // Unknown engine-side keys inside the trace are tolerated by the\n // ConstraintTrace interface's index signature.\n let constraintTrace: ConstraintTrace | null = null;\n if (\n wire.constraint_trace !== undefined &&\n wire.constraint_trace !== null &&\n typeof wire.constraint_trace === \"object\"\n ) {\n constraintTrace = wire.constraint_trace as ConstraintTrace;\n }\n\n return { evaluation, constraintTrace };\n }\n\n /**\n * Verify that a previously issued permit is still valid.\n *\n * @deprecated Use {@link verifyPermitById} — the canonical REST\n * surface (`POST /v1/permits/{id}/verify`) returns the unified\n * verification envelope plus the full {@link PermitRecord}, instead\n * of the legacy `{verified, outcome, permitHash}` shape this method\n * emits. Will be removed in `@atlasent/sdk@3`.\n *\n * A `verified: false` response is **not** thrown — inspect the\n * returned object. Only transport / server errors throw.\n */\n async verifyPermit(\n input: VerifyPermitRequest,\n ): Promise<VerifyPermitResponse> {\n _warnOversizeContext(input.context);\n // Canonical wire shape per handler.ts: only permit_token is required.\n // action_type / actor_id are optional cross-checks; context / api_key\n // are NOT consulted by the verify handler.\n const body: Record<string, unknown> = {\n permit_token: input.permitId,\n action_type: input.action ?? \"\",\n actor_id: input.agent ?? \"\",\n };\n if (input.environment !== undefined) {\n body.environment = input.environment;\n }\n if (input.execution_hash !== undefined) {\n body.execution_hash = input.execution_hash;\n }\n const { body: wire, rateLimit } = await this.post<VerifyPermitWire>(\n \"/v1-verify-permit\",\n body,\n );\n\n // Tolerate both canonical {valid, outcome} and legacy {verified} server\n // responses.\n const valid = typeof wire.valid === \"boolean\" ? wire.valid : wire.verified;\n if (typeof valid !== \"boolean\") {\n throw new AtlaSentError(\n \"Malformed response from /v1-verify-permit: missing `valid` (or legacy `verified`)\",\n { code: \"bad_response\" },\n );\n }\n\n return {\n verified: valid,\n outcome: wire.outcome ?? \"\",\n permitHash: wire.permit_hash ?? \"\",\n timestamp: wire.timestamp ?? \"\",\n expiresAt: wire.expires_at ?? null,\n rateLimit,\n };\n }\n\n /**\n * Run the canonical Deploy Gate V1 flow:\n * evaluate `production.deploy`, verify the issued permit server-side,\n * and return allow/block plus audit/evidence metadata.\n *\n * This helper never treats a signed/offline permit artifact as sufficient\n * authorization. Execution is allowed only when `POST /v1-evaluate` returns\n * `decision: \"allow\"` with a permit AND `POST /v1-verify-permit` returns\n * `verified: true` / `valid: true`.\n */\n async deployGate(input: DeployGateRequest = {}): Promise<DeployGateResponse> {\n const agent = input.agent ?? \"ci-deploy-bot\";\n const action = input.action ?? PRODUCTION_DEPLOY_ACTION;\n const context = input.context ?? {};\n const environment =\n typeof (context as Record<string, unknown>).environment === \"string\"\n ? ((context as Record<string, unknown>).environment as string)\n : typeof (context as Record<string, unknown>).environment_name === \"string\"\n ? ((context as Record<string, unknown>).environment_name as string)\n : undefined;\n\n const evaluation = await this.evaluate({ agent, action, context });\n if (evaluation.decision !== \"allow\") {\n return {\n allowed: false,\n evaluation,\n reason:\n evaluation.reason ||\n `Deploy Gate blocked by decision=${evaluation.decision}`,\n evidence: deployGateEvidence({\n permitId: evaluation.permitId,\n auditHash: evaluation.auditHash,\n }),\n };\n }\n\n const verification = await this.verifyPermit({\n permitId: evaluation.permitId,\n agent,\n action,\n context,\n ...(environment !== undefined ? { environment } : {}),\n });\n\n if (!verification.verified) {\n return {\n allowed: false,\n evaluation,\n verification,\n reason: verification.outcome\n ? `Deploy Gate blocked by permit verification outcome=${verification.outcome}`\n : \"Deploy Gate blocked because permit verification failed\",\n evidence: deployGateEvidence({\n permitId: evaluation.permitId,\n permitHash: verification.permitHash,\n auditHash: evaluation.auditHash,\n verifiedAt: verification.timestamp,\n }),\n };\n }\n\n return {\n allowed: true,\n evaluation,\n verification,\n reason: evaluation.reason || \"Deploy Gate permit verified\",\n evidence: deployGateEvidence({\n permitId: evaluation.permitId,\n permitHash: verification.permitHash,\n auditHash: evaluation.auditHash,\n verifiedAt: verification.timestamp,\n }),\n };\n }\n\n /**\n * Revoke a previously-issued permit so it can no longer pass\n * {@link verifyPermit}.\n *\n * @deprecated Use {@link revokePermitById} — the canonical REST\n * surface (`POST /v1/permits/{id}/revoke`) returns the full updated\n * {@link PermitRecord} with `revoked_at`/`revoked_by`/`revoke_reason`\n * populated, instead of the legacy `{revoked, permitId}` envelope\n * this method emits. Will be removed in `@atlasent/sdk@3`.\n *\n * Use this when an agent's action is cancelled, superseded, or\n * determined to be unauthorized after the fact. The revocation is\n * recorded in the audit log with the optional `reason`.\n *\n * Throws {@link AtlaSentError} on transport / auth failures.\n */\n async revokePermit(\n input: RevokePermitRequest,\n ): Promise<RevokePermitResponse> {\n const body = {\n decision_id: input.permitId,\n reason: input.reason ?? \"\",\n api_key: this.apiKey,\n };\n const { body: wire, rateLimit } = await this.post<{\n revoked: boolean;\n decision_id: string;\n revoked_at?: string;\n audit_hash?: string;\n }>(\"/v1-revoke-permit\", body);\n\n if (\n typeof wire.revoked !== \"boolean\" ||\n typeof wire.decision_id !== \"string\"\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-revoke-permit: missing `revoked` or `decision_id`\",\n { code: \"bad_response\" },\n );\n }\n\n return {\n revoked: wire.revoked,\n permitId: wire.decision_id,\n revokedAt: wire.revoked_at,\n auditHash: wire.audit_hash,\n rateLimit,\n };\n }\n\n /**\n * Revoke a permit through the canonical REST surface\n * (`POST /v1/permits/{permitId}/revoke`).\n *\n * Returns the full updated {@link PermitRecord} with `status === 'revoked'`\n * and `revoked_at` / `revoked_by` / `revoke_reason` populated. After\n * revocation, subsequent verify calls return `410 PERMIT_REVOKED`.\n *\n * Idempotent on `409 permit_revoked` for already-revoked permits;\n * server returns the existing revoked row in that case.\n *\n * Throws {@link AtlaSentError} on `404` (permit not in calling org),\n * `409` (already in a terminal state), `410` (expired before revoke),\n * or `429` (rate limited).\n */\n async revokePermitById(\n permitId: string,\n input: RevokePermitByIdInput = {},\n ): Promise<RevokePermitByIdResponse> {\n if (!permitId) {\n throw new AtlaSentError(\"permitId is required\", { code: \"bad_request\" });\n }\n const body: { reason?: string } = {};\n if (input.reason !== undefined) body.reason = input.reason;\n const { body: wire, rateLimit } = await this.post<PermitRecord>(\n `/v1/permits/${encodeURIComponent(permitId)}/revoke`,\n body,\n );\n return { permit: wire, rateLimit };\n }\n\n /**\n * Verify a permit through the canonical REST surface\n * (`POST /v1/permits/{permitId}/verify`).\n *\n * Returns the unified verification envelope (`valid`,\n * `verification_type: 'permit'`, `reason`, `verified_at`, `evidence`)\n * plus the full {@link PermitRecord} fields preserved at the top\n * level. The `valid` field is the contract — pin to it.\n *\n * A `valid: false` is **not** thrown when the server returns 200 with\n * a denial reason (matches the verify-shape unification on the wire);\n * it is thrown on 4xx (`404` not found, `410` expired/consumed).\n */\n async verifyPermitById(permitId: string): Promise<VerifyPermitByIdResponse> {\n if (!permitId) {\n throw new AtlaSentError(\"permitId is required\", { code: \"bad_request\" });\n }\n const { body: wire, rateLimit } = await this.post<\n VerifyPermitByIdResponse & PermitRecord\n >(`/v1/permits/${encodeURIComponent(permitId)}/verify`, {});\n // Server returns the canonical envelope merged with the Permit row\n // (allOf in openapi). Pull out the legacy permit row into `permit`\n // for callers that want it as a sub-object too.\n const { valid, verification_type, reason, verified_at, evidence, ...row } =\n wire as VerifyPermitByIdResponse & PermitRecord;\n return {\n valid,\n verification_type,\n reason,\n verified_at,\n evidence,\n permit: row as PermitRecord,\n rateLimit,\n };\n }\n\n /**\n * Get a single permit's full lifecycle state.\n *\n * Calls `GET /v1/permits/{permitId}` (the canonical REST surface).\n * Returns `status`, all timestamps, `revoked_at` / `revoked_by` /\n * `revoke_reason` (when applicable), and the bound `payload_hash`\n * / `decision_id`.\n *\n * Operator-facing introspection — answers \"what state is this permit\n * in, and why?\" without reading audit logs.\n *\n * Throws {@link AtlaSentError} on `404` (permit not in calling org)\n * or `410` (expired before retrieval).\n */\n async getPermit(permitId: string): Promise<GetPermitResponse> {\n if (!permitId) {\n throw new AtlaSentError(\"permitId is required\", { code: \"bad_request\" });\n }\n const { body: wire, rateLimit } = await this.get<PermitRecord>(\n `/v1/permits/${encodeURIComponent(permitId)}`,\n );\n return { permit: wire, rateLimit };\n }\n\n /**\n * Poll whether a permit is currently valid.\n *\n * Calls `GET /v1/permits/{permitId}/valid` — a lightweight read\n * returning only the status snapshot optimised for guard heartbeat\n * polling. Guards with `permitRevalidationIntervalMs` set race this\n * against `tool.execute()` and throw {@link PermitRevoked} when\n * `status === \"revoked\"` arrives.\n *\n * Throws {@link AtlaSentError} on transport / auth failures.\n */\n async checkPermitValid(permitId: string): Promise<PermitValidResponse> {\n if (!permitId) {\n throw new AtlaSentError(\"permitId is required\", { code: \"bad_request\" });\n }\n const { body } = await this.get<PermitValidResponse>(\n `/v1/permits/${encodeURIComponent(permitId)}/valid`,\n );\n return body;\n }\n\n /**\n * List permits issued to the calling org, most-recently-issued first.\n *\n * Calls `GET /v1/permits` (the canonical REST surface). Cursor-paged.\n * Filters narrow on server side; pagination uses the `created_at`\n * timestamp opaquely (`nextCursor`).\n *\n * Designed for incident review, debugging, and compliance\n * reconstruction.\n */\n async listPermits(\n input: ListPermitsRequest = {},\n ): Promise<ListPermitsResponse> {\n const params = new URLSearchParams();\n if (input.status) params.set(\"status\", input.status);\n if (input.actorId) params.set(\"actor_id\", input.actorId);\n if (input.actionType) params.set(\"action_type\", input.actionType);\n if (input.from) params.set(\"from\", input.from);\n if (input.to) params.set(\"to\", input.to);\n if (input.limit !== undefined) params.set(\"limit\", String(input.limit));\n if (input.cursor) params.set(\"cursor\", input.cursor);\n\n const { body: wire, rateLimit } = await this.get<{\n permits?: PermitRecord[];\n total?: number;\n next_cursor?: string;\n }>(\"/v1/permits\", params);\n\n if (!Array.isArray(wire.permits)) {\n throw new AtlaSentError(\n \"Malformed response from /v1/permits: missing `permits` array\",\n { code: \"bad_response\" },\n );\n }\n const result: ListPermitsResponse = {\n permits: wire.permits,\n total: typeof wire.total === \"number\" ? wire.total : wire.permits.length,\n rateLimit,\n };\n if (wire.next_cursor !== undefined) result.nextCursor = wire.next_cursor;\n return result;\n }\n\n /**\n * Self-introspection: ask the server to describe the API key this\n * client was constructed with. Returns the key's ID, organization,\n * environment, scopes, IP allowlist, per-minute rate limit, the\n * client IP the server observed, and the expiry (if any).\n *\n * Never includes the raw key or its hash. Safe to surface in operator\n * dashboards. Useful for `IP_NOT_ALLOWED` debugging (the server tells\n * you exactly which IP it saw) and for proactive expiry warnings.\n *\n * Throws {@link AtlaSentError} on transport / auth failures — same\n * taxonomy as {@link AtlaSentClient.evaluate}.\n */\n async keySelf(): Promise<ApiKeySelfResponse> {\n const { body: wire, rateLimit } =\n await this.get<ApiKeySelfWire>(\"/v1-api-key-self\");\n\n if (\n typeof wire.key_id !== \"string\" ||\n typeof wire.org_id !== \"string\"\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-api-key-self: missing `key_id` or `org_id`\",\n { code: \"bad_response\" },\n );\n }\n\n return {\n keyId: wire.key_id,\n orgId: wire.org_id,\n environment: wire.environment,\n scopes: wire.scopes ?? [],\n allowedCidrs: wire.allowed_cidrs ?? null,\n rateLimitPerMinute: wire.rate_limit_per_minute,\n clientIp: wire.client_ip ?? null,\n expiresAt: wire.expires_at ?? null,\n rateLimit,\n };\n }\n\n /**\n * List persisted audit events for the authenticated organization\n * (`GET /v1-audit/events`). Returned rows are wire-identical with\n * the server: snake_case field names, including `previous_hash` and\n * the `hash` chain, so the response can be fed straight into the\n * offline verifier when paired with a signed export.\n *\n * `query.types` is a comma-joined list (e.g.\n * `\"evaluate.allow,policy.updated\"`). `cursor` is the opaque\n * `next_cursor` from the prior page. All fields are optional; the\n * server defaults `limit` to 50 (capped at 500).\n *\n * Throws {@link AtlaSentError} on transport / auth failures — same\n * taxonomy as {@link AtlaSentClient.evaluate}.\n */\n async listAuditEvents(\n query: AuditEventsQuery = {},\n ): Promise<AuditEventsResult> {\n const { body: wire, rateLimit } = await this.get<AuditEventsPage>(\n \"/v1-audit/events\",\n buildAuditEventsQuery(query),\n );\n\n if (!Array.isArray(wire.events) || typeof wire.total !== \"number\") {\n throw new AtlaSentError(\n \"Malformed response from /v1-audit/events: missing `events` or `total`\",\n { code: \"bad_response\" },\n );\n }\n\n return { ...wire, rateLimit };\n }\n\n /**\n * Request a signed audit export bundle\n * (`POST /v1-audit/exports`). The returned object is wire-identical\n * with the server — `signature`, `chain_head_hash`, `events`, and\n * friends survive untouched so the bundle can be persisted to disk\n * and handed to the offline verifier (`verifyBundle` /\n * `verifyAuditBundle`) without any reshaping.\n *\n * Pass `filter.types`, `filter.from`, `filter.to`, or `filter.actor_id`\n * to narrow the export; omit for a full-org bundle. `rateLimit` is\n * attached alongside the wire fields for observability.\n *\n * Throws {@link AtlaSentError} on transport / auth failures — same\n * taxonomy as {@link AtlaSentClient.evaluate}.\n */\n async createAuditExport(\n filter: AuditExportRequest = {},\n ): Promise<AuditExportResult> {\n const { body: wire, rateLimit } = await this.post<AuditExport>(\n \"/v1-audit/exports\",\n filter,\n );\n\n if (\n typeof wire.export_id !== \"string\" ||\n typeof wire.chain_head_hash !== \"string\" ||\n !Array.isArray(wire.events)\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-audit/exports: missing `export_id`, `chain_head_hash`, or `events`\",\n { code: \"bad_response\" },\n );\n }\n\n return { ...wire, rateLimit };\n }\n\n /**\n * Re-evaluate a recorded decision against its originally-pinned policy\n * bundle and engine version, and report whether the result agrees with\n * what was recorded.\n *\n * Wraps `POST /v1-decisions-replay/:id/replay`. **Side-effect-free** — no\n * audit chain row is written and no permit is issued (per ADR-016).\n * Useful for compliance review, regression testing of bundle changes,\n * and post-incident investigation.\n *\n * Outcomes encoded in the response:\n * - `variance: \"NONE\"` — replay agrees with the original decision.\n * - `variance: \"DECISION_CHANGED\"` — same envelope, same bundle, different\n * decision. Almost always indicates non-determinism in a rule\n * (e.g. wall-clock comparison) and warrants investigation.\n * - `variance: \"ENVELOPE_DRIFT\"` — the recorded request envelope no longer\n * hashes to the recorded value. The replay short-circuits without\n * running the engine; `replay_decision` is absent. Treat as evidence\n * of substrate tamper or a recorder bug.\n *\n * Server-side 409 responses (replay refused because the engine version\n * does not accept replay, or because no bundle was pinned) surface as\n * `AtlaSentError` with `code: \"replay_not_eligible\"` — callers should\n * treat them as expected for old / un-pinned decisions, not as bugs.\n *\n * Requires the `evaluate:write` API key scope.\n *\n * @param decisionId The UUID of the recorded decision to replay.\n * Matches `execution_evaluations.request_id`.\n *\n * @example\n * ```ts\n * const result = await client.replayDecision(\"dec_abc123\");\n * if (result.variance === \"DECISION_CHANGED\") {\n * console.warn(\n * `Decision ${result.decision_id} changed on replay: ` +\n * `${result.original_decision} → ${result.replay_decision}`,\n * );\n * }\n * ```\n */\n async replayDecision(\n decisionId: string,\n ): Promise<ReplayDecisionResponse & { rateLimit: RateLimitState | null }> {\n if (typeof decisionId !== \"string\" || decisionId.length === 0) {\n throw new AtlaSentError(\"decisionId is required\", {\n code: \"bad_request\",\n });\n }\n\n const path = `/v1-decisions-replay/${encodeURIComponent(decisionId)}/replay`;\n const { body: wire, rateLimit } = await this.post<ReplayDecisionResponse>(\n path,\n {},\n );\n\n // Defensive validation. The replay endpoint is alpha (see\n // STABLE_V2_PROMOTION.md) — wire shapes can shift without a\n // deprecation cycle, so guard the contract fields callers will\n // branch on rather than trusting the cast.\n if (\n typeof wire.decision_id !== \"string\" ||\n typeof wire.original_decision !== \"string\" ||\n typeof wire.engine_version_kind !== \"string\" ||\n typeof wire.accepts_replay !== \"boolean\" ||\n typeof wire.variance !== \"string\" ||\n typeof wire.envelope_verification !== \"string\" ||\n typeof wire.replayed_at !== \"string\"\n ) {\n throw new AtlaSentError(\n \"Malformed response from /v1-decisions-replay/:id/replay: missing required fields\",\n { code: \"bad_response\" },\n );\n }\n\n return { ...wire, rateLimit };\n }\n\n /**\n * ADR-015 Phase C — SDK-canonical replay runtime.\n *\n * Re-evaluates a recorded decision against its originally-pinned policy\n * bundle and engine version via `POST /v1/decisions/:id/replay`.\n * Side-effect-free server-side: no audit chain row is written and no\n * permit is issued (ADR-016 `mode: \"replay\"` sentinel).\n *\n * Differences from {@link replayDecision} (the 2.7.0 raw-wire surface):\n *\n * | | `replayDecision()` | `replay()` |\n * | --- | --- | --- |\n * | Path | `/v1-decisions-replay/:id/replay` | `/v1/decisions/:id/replay` |\n * | Variance | raw wire (`DECISION_CHANGED`) | SDK-canonical (`POLICY_DRIFT`) |\n * | 409 handling | throws `AtlaSentError` | returns `ENGINE_DRIFT` / `BUNDLE_MISSING` |\n * | Input shape | `decisionId: string` | `{ evaluationId }` |\n *\n * **Never throws on `409 replay_not_eligible`** — instead returns a\n * `ReplayResponse` with `varianceKind: \"ENGINE_DRIFT\"` (engine retired\n * beyond archival window) or `\"BUNDLE_MISSING\"` (no bundle pinned on\n * the original evaluation). Callers can always `switch` on\n * `result.varianceKind` without a try/catch.\n *\n * Fix-forward note: this method was originally landed in PR #275 but\n * dropped from the squash merge. The TS types (`ReplayResponse`,\n * `ReplayRequest`) and CHANGELOG made it through; the method itself\n * did not. Restored here to match the Python {@link\n * AtlaSentClient}.replay() that landed in atlasent-sdk@2.6.0 (Python).\n */\n async replay(input: ReplayRequest): Promise<ReplayResponse> {\n if (!input || typeof input.evaluationId !== \"string\" || input.evaluationId.length === 0) {\n throw new AtlaSentError(\"evaluationId is required\", {\n code: \"bad_request\",\n });\n }\n\n const path = `/v1/decisions/${encodeURIComponent(input.evaluationId)}/replay`;\n let wire: Record<string, unknown>;\n let rateLimit: RateLimitState | null;\n try {\n const result = await this.post<Record<string, unknown>>(path, {});\n wire = result.body;\n rateLimit = result.rateLimit;\n } catch (err) {\n if (err instanceof AtlaSentError && err.status === 409) {\n const msg = (err.message ?? \"\").toLowerCase();\n const varianceKind: ReplayVarianceKind = msg.includes(\"bundle\")\n ? \"BUNDLE_MISSING\"\n : \"ENGINE_DRIFT\";\n return {\n decisionId: input.evaluationId,\n varianceKind,\n originalDecision: \"deny\",\n acceptsReplay: false,\n replayedAt: new Date().toISOString(),\n rateLimit: null,\n };\n }\n throw err;\n }\n\n // Map raw wire variance → SDK-canonical. Unknown values default to\n // NONE per the additive-contract policy (the SDK never breaks on a\n // forward-introduced wire kind).\n const VARIANCE_MAP: Record<string, ReplayVarianceKind> = {\n NONE: \"NONE\",\n DECISION_CHANGED: \"POLICY_DRIFT\",\n ENVELOPE_DRIFT: \"ENVELOPE_DRIFT\",\n CHAIN_TAMPER: \"CHAIN_TAMPER\",\n BUNDLE_MISSING: \"BUNDLE_MISSING\",\n ENGINE_DRIFT: \"ENGINE_DRIFT\",\n };\n const rawVariance = typeof wire.variance === \"string\" ? wire.variance : \"\";\n const varianceKind: ReplayVarianceKind = VARIANCE_MAP[rawVariance] ?? \"NONE\";\n\n const replayDec = typeof wire.replay_decision === \"string\"\n ? (wire.replay_decision.toLowerCase() as DecisionCanonical)\n : undefined;\n const originalDec = (\n typeof wire.original_decision === \"string\"\n ? wire.original_decision.toLowerCase()\n : \"deny\"\n ) as DecisionCanonical;\n\n const response: ReplayResponse = {\n decisionId: typeof wire.decision_id === \"string\" ? wire.decision_id : input.evaluationId,\n varianceKind,\n originalDecision: originalDec,\n acceptsReplay: typeof wire.accepts_replay === \"boolean\" ? wire.accepts_replay : true,\n replayedAt: typeof wire.replayed_at === \"string\" ? wire.replayed_at : new Date().toISOString(),\n rateLimit,\n };\n if (typeof wire.original_deny_code === \"string\") response.originalDenyCode = wire.original_deny_code;\n if (replayDec !== undefined) response.replayedDecision = replayDec;\n if (typeof wire.replay_deny_code === \"string\") response.replayedDenyCode = wire.replay_deny_code;\n if (typeof wire.engine_version === \"string\") response.engineVersion = wire.engine_version;\n if (typeof wire.engine_version_kind === \"string\") response.engineVersionKind = wire.engine_version_kind;\n if (typeof wire.envelope_verification === \"string\") response.envelopeVerification = wire.envelope_verification;\n return response;\n }\n\n /**\n * Open a streaming evaluation session against `POST /v1/evaluate/stream`\n * (with fallback to `POST /v1-evaluate-stream` on older runtimes).\n *\n * Yields {@link StreamDecisionEvent} and {@link StreamProgressEvent} objects\n * as the server emits them. The iterator ends cleanly when the server sends\n * `event: done`; it throws {@link AtlaSentError} on transport errors or when\n * the server sends `event: error`.\n *\n * The final {@link StreamDecisionEvent} (isFinal: true) carries a `permitId`\n * suitable for passing to {@link verifyPermit} after the stream closes.\n *\n * Hardening:\n * - Throws {@link StreamTimeoutError} when no event arrives within\n * `opts.timeoutMs` (default 30 s). Pass `0` to disable.\n * - Retries up to `opts.maxRetries` times (default 3) with 1 s / 2 s / 4 s\n * delays on network drop (before a terminal event). Sends `Last-Event-ID`\n * on reconnect when the server has emitted event IDs.\n * - Throws {@link StreamParseError} on partial / malformed JSON rather than\n * crashing with a raw `SyntaxError`.\n * - Closes cleanly on `event: done` or a decision event with `done: true`.\n *\n * ```ts\n * for await (const event of client.protectStream({ agent, action })) {\n * if (event.type === \"decision\" && event.isFinal) {\n * await client.verifyPermit({ permitId: event.permitId });\n * }\n * }\n * ```\n */\n async *protectStream(\n input: EvaluateRequest,\n opts: StreamOptions = {},\n ): AsyncIterable<StreamEvent> {\n const streamTimeoutMs = opts.timeoutMs ?? 30_000;\n const maxRetries = opts.maxRetries ?? 3;\n\n const body = {\n action: input.action,\n agent: input.agent,\n context: input.context ?? {},\n api_key: this.apiKey,\n };\n\n const requestId = globalThis.crypto.randomUUID();\n let streamPath = V1_EVALUATE_STREAM_PATH;\n\n let lastEventId: string | undefined;\n let retryCount = 0;\n\n while (true) {\n const headers: Record<string, string> = {\n Accept: \"text/event-stream\",\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n \"User-Agent\": this.userAgent,\n // ADR-025: wire-protocol version declared on every request.\n \"X-AtlaSent-Protocol-Version\": \"1\",\n \"X-Request-ID\": requestId,\n };\n if (lastEventId !== undefined) {\n headers[\"Last-Event-ID\"] = lastEventId;\n }\n\n const connectionTimeoutSignal = AbortSignal.timeout(this.timeoutMs);\n const signal = opts.signal\n ? (\n AbortSignal as unknown as { any(s: AbortSignal[]): AbortSignal }\n ).any([connectionTimeoutSignal, opts.signal])\n : connectionTimeoutSignal;\n\n let response: Response;\n try {\n response = await this.fetchImpl(`${this.baseUrl}${streamPath}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal,\n });\n } catch (err) {\n const mapped = mapFetchError(err, requestId);\n if (mapped.code === \"network\" && retryCount < maxRetries) {\n retryCount++;\n await sleep(1_000 * Math.pow(2, retryCount - 1)); // 1s, 2s, 4s\n continue;\n }\n throw mapped;\n }\n\n if (!response.ok) {\n if (\n streamPath === V1_EVALUATE_STREAM_PATH &&\n (response.status === 404 || response.status === 405)\n ) {\n streamPath = V1_EVALUATE_STREAM_LEGACY_PATH;\n continue;\n }\n throw await buildHttpError(response, requestId);\n }\n\n if (!response.body) {\n throw new AtlaSentError(\"Expected streaming body from AtlaSent API\", {\n code: \"bad_response\",\n status: response.status,\n requestId,\n });\n }\n\n let streamDone = false;\n let networkDrop = false;\n\n try {\n for await (const event of parseSseStream(\n response.body,\n requestId,\n streamTimeoutMs,\n (id) => {\n lastEventId = id;\n },\n )) {\n yield event;\n if (event.type === \"decision\" && event.isFinal) {\n streamDone = true;\n }\n }\n // parseSseStream returned normally (saw event: done or stream ended)\n streamDone = true;\n } catch (err) {\n if (err instanceof AtlaSentError && err.code === \"network\") {\n networkDrop = true;\n } else {\n throw err;\n }\n }\n\n if (streamDone) break;\n\n // Network drop before terminal event — attempt reconnect\n if (networkDrop && retryCount < maxRetries) {\n retryCount++;\n await sleep(1_000 * Math.pow(2, retryCount - 1)); // 1s, 2s, 4s\n continue;\n }\n if (networkDrop) {\n throw new AtlaSentError(\n `AtlaSent stream dropped after ${retryCount} reconnection attempts`,\n { code: \"network\", requestId },\n );\n }\n break;\n }\n }\n\n private async post<T>(\n path: string,\n body: unknown,\n query?: URLSearchParams,\n ): Promise<{ body: T; rateLimit: RateLimitState | null }> {\n return this.request<T>(path, \"POST\", body, query);\n }\n\n private async postWithPathFallback<T>(\n primaryPath: string,\n fallbackPath: string,\n body: unknown,\n query?: URLSearchParams,\n ): Promise<{ body: T; rateLimit: RateLimitState | null }> {\n try {\n return await this.post<T>(primaryPath, body, query);\n } catch (err) {\n if (\n err instanceof AtlaSentError &&\n (err.status === 404 || err.status === 405)\n ) {\n return this.post<T>(fallbackPath, body, query);\n }\n throw err;\n }\n }\n\n private async get<T>(\n path: string,\n query?: URLSearchParams,\n ): Promise<{ body: T; rateLimit: RateLimitState | null }> {\n return this.request<T>(path, \"GET\", undefined, query);\n }\n\n private async request<T>(\n path: string,\n method: \"GET\" | \"POST\",\n body: unknown,\n query: URLSearchParams | undefined,\n ): Promise<{ body: T; rateLimit: RateLimitState | null }> {\n const qs =\n query && Array.from(query).length > 0 ? `?${query.toString()}` : \"\";\n const url = `${this.baseUrl}${path}${qs}`;\n const requestId = globalThis.crypto.randomUUID();\n\n /**\n * Canonical auth header. The API also accepts X-AtlaSent-Key for legacy\n * compatibility but that path is deprecated and will be removed in a future\n * version. Always use Authorization: Bearer <api_key>.\n */\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n \"User-Agent\": this.userAgent,\n \"X-Request-ID\": requestId,\n // ADR-025: wire-protocol version declared on every request.\n \"X-AtlaSent-Protocol-Version\": \"1\",\n };\n if (method === \"POST\") headers[\"Content-Type\"] = \"application/json\";\n\n const bodyStr = method === \"POST\" ? JSON.stringify(body) : undefined;\n\n for (let attempt = 0; ; attempt++) {\n const init: RequestInit = {\n method,\n headers,\n signal: AbortSignal.timeout(this.timeoutMs),\n };\n if (bodyStr !== undefined) init.body = bodyStr;\n\n let response: Response;\n try {\n response = await this.fetchImpl(url, init);\n } catch (err) {\n const mapped = mapFetchError(err, requestId);\n if (isRetryable(mapped) && hasAttemptsLeft(attempt, this.retryPolicy)) {\n await sleep(computeBackoffMs(attempt, this.retryPolicy, mapped));\n continue;\n }\n throw mapped;\n }\n\n if (!response.ok) {\n const httpErr = await buildHttpError(response, requestId);\n if (\n isRetryable(httpErr) &&\n hasAttemptsLeft(attempt, this.retryPolicy)\n ) {\n await sleep(computeBackoffMs(attempt, this.retryPolicy, httpErr));\n continue;\n }\n throw httpErr;\n }\n\n let parsed: unknown;\n try {\n parsed = await response.json();\n } catch (err) {\n const jsonErr = new AtlaSentError(\n \"Invalid JSON response from AtlaSent API\",\n {\n code: \"bad_response\",\n status: response.status,\n requestId,\n cause: err,\n },\n );\n if (\n isRetryable(jsonErr) &&\n hasAttemptsLeft(attempt, this.retryPolicy)\n ) {\n await sleep(computeBackoffMs(attempt, this.retryPolicy, jsonErr));\n continue;\n }\n throw jsonErr;\n }\n\n if (parsed === null || typeof parsed !== \"object\") {\n const shapeErr = new AtlaSentError(\n \"Expected a JSON object from AtlaSent API\",\n {\n code: \"bad_response\",\n status: response.status,\n requestId,\n },\n );\n if (\n isRetryable(shapeErr) &&\n hasAttemptsLeft(attempt, this.retryPolicy)\n ) {\n await sleep(computeBackoffMs(attempt, this.retryPolicy, shapeErr));\n continue;\n }\n throw shapeErr;\n }\n\n return {\n body: parsed as T,\n rateLimit: parseRateLimitHeaders(response.headers),\n };\n }\n }\n\n /**\n * Open a new HITL escalation. Bridges a `hold` outcome from\n * `protect()` to the approval queue: an agent that receives a\n * `hold` decision calls this to enroll the proposed action for\n * human review. The returned escalation can then be polled with\n * `getHitlEscalation()` or driven to terminal by\n * `approveHitlEscalation()` / `rejectHitlEscalation()`.\n *\n * Quorum, pool size, fallback decision and routing inherit from\n * the server-side policy when omitted from `input`.\n *\n * Calls `POST /v1/hitl`.\n */\n async createHitlEscalation(\n input: HitlCreateRequest,\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.post<HitlEscalation>(\n \"/v1/hitl\",\n input,\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * List HITL escalations for the calling org. Defaults to\n * `status=pending`; pass `status` to query other queues\n * (`escalated`, `approved`, `rejected`, `auto_approved`,\n * `timed_out`).\n *\n * Calls `GET /v1/hitl`.\n */\n async listHitlEscalations(input: ListHitlEscalationsRequest = {}): Promise<{\n data: ListHitlEscalationsResponse;\n rateLimit: RateLimitState | null;\n }> {\n const params = new URLSearchParams();\n if (input.status) params.set(\"status\", input.status);\n if (input.agentId) params.set(\"agent_id\", input.agentId);\n if (input.assignedToUserId)\n params.set(\"assigned_to_user_id\", input.assignedToUserId);\n if (input.limit !== undefined) params.set(\"limit\", String(input.limit));\n if (input.cursor) params.set(\"cursor\", input.cursor);\n const { body, rateLimit } = await this.get<ListHitlEscalationsResponse>(\n \"/v1/hitl\",\n params,\n );\n return { data: body, rateLimit };\n }\n\n /**\n * Get a HITL escalation. The server payload includes a live\n * `quorum_progress` snapshot when the escalation is still open.\n *\n * Calls `GET /v1/hitl/:id`.\n */\n async getHitlEscalation(\n escalationId: string,\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n if (!escalationId) {\n throw new AtlaSentError(\"escalationId is required\", {\n code: \"bad_request\",\n });\n }\n const { body, rateLimit } = await this.get<HitlEscalation>(\n `/v1/hitl/${encodeURIComponent(escalationId)}`,\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * List per-approver vote rows for an escalation.\n * Calls `GET /v1/hitl/:id/approvals`.\n */\n async listHitlApprovals(escalationId: string): Promise<{\n approvals: HitlApprovalRecord[];\n rateLimit: RateLimitState | null;\n }> {\n const { body, rateLimit } = await this.get<{\n approvals: HitlApprovalRecord[];\n }>(`/v1/hitl/${encodeURIComponent(escalationId)}/approvals`);\n return { approvals: body.approvals ?? [], rateLimit };\n }\n\n /**\n * List the escalation chain hops for an escalation. Each `/escalate`\n * call appends one row.\n * Calls `GET /v1/hitl/:id/chain`.\n */\n async getHitlChain(\n escalationId: string,\n ): Promise<{ chain: HitlChainHop[]; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.get<{ chain: HitlChainHop[] }>(\n `/v1/hitl/${encodeURIComponent(escalationId)}/chain`,\n );\n return { chain: body.chain ?? [], rateLimit };\n }\n\n /**\n * Record an approve vote. Resolves the escalation only once the\n * server-side quorum count is satisfied; before that the response\n * carries a refreshed escalation row with the latest\n * `quorum_progress`.\n *\n * Calls `POST /v1/hitl/:id/approve`. The server returns 409\n * `duplicate_vote` if the same principal has already voted, and\n * 409 `already_rejected` if a concurrent reject crossed the line.\n */\n async approveHitlEscalation(\n escalationId: string,\n input: HitlApproveRequest = {},\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.post<HitlEscalation>(\n `/v1/hitl/${encodeURIComponent(escalationId)}/approve`,\n input,\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * Record a reject vote. Reject is short-circuit terminal — a single\n * reject closes the escalation regardless of how many approves have\n * accumulated.\n *\n * Calls `POST /v1/hitl/:id/reject`.\n */\n async rejectHitlEscalation(\n escalationId: string,\n input: HitlRejectRequest = {},\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.post<HitlEscalation>(\n `/v1/hitl/${encodeURIComponent(escalationId)}/reject`,\n input,\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * Re-route an open escalation to a higher tier. Bounded by the\n * escalation's `max_escalation_depth` — the server returns 409\n * `chain_exhausted` and applies the configured fallback decision\n * once the ceiling is hit.\n *\n * Calls `POST /v1/hitl/:id/escalate`.\n */\n async escalateHitlEscalation(\n escalationId: string,\n input: HitlEscalateRequest,\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.post<HitlEscalation>(\n `/v1/hitl/${encodeURIComponent(escalationId)}/escalate`,\n input,\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * Manually apply the escalation's `fallback_decision`. Useful for\n * admin recovery of a hung escalation when the cron sweeper hasn't\n * run yet, or to short-circuit a stuck flow during incident\n * response.\n *\n * Calls `POST /v1/hitl/:id/timeout`.\n */\n async timeoutHitlEscalation(\n escalationId: string,\n ): Promise<{ escalation: HitlEscalation; rateLimit: RateLimitState | null }> {\n const { body, rateLimit } = await this.post<HitlEscalation>(\n `/v1/hitl/${encodeURIComponent(escalationId)}/timeout`,\n {},\n );\n return { escalation: body, rateLimit };\n }\n\n /**\n * Run a named governance graph traversal query.\n *\n * Dispatches to `GET /v1/governance/graph/query?type=<queryType>`.\n * Each query type returns a different row shape — the return type\n * narrows automatically based on the literal `queryType` argument.\n *\n * `\"user_approvals\"` requires `params.actor_id` — the server returns\n * a 400 if it is absent.\n */\n async queryGovernanceGraph<T extends GovernanceGraphQueryType>(\n queryType: T,\n params: GovernanceGraphQueryParams = {},\n ): Promise<GovernanceGraphQueryResponse<T>> {\n const qs = new URLSearchParams({ type: queryType });\n if (params.actor_id) qs.set(\"actor_id\", params.actor_id);\n const { body, rateLimit } = await this.get<{\n query_type: T;\n results: GovernanceGraphResultRow<T>[];\n org_id: string;\n }>(\"/v1/governance/graph/query\", qs);\n return { ...body, rateLimit };\n }\n\n /**\n * Reconstruct the multi-system execution timeline for a specific incident.\n *\n * Calls `GET /v1/governance/timeline/incident/{incidentId}`. Backed\n * server-side by `reconstruct_incident_chains_v2()`, which fixes the\n * `executor_id → actor_id` bug that silently produced empty timelines\n * in the original function.\n *\n * Returns full execution rows including the §13.1 columns\n * (`delegation_chain_id`, `replay_of_execution_id`, `incident_id`,\n * `policy_version_id`, `bundle_version_id`) alongside the actor\n * timeline and evidence rows.\n */\n async getIncidentTimeline(\n incidentId: string,\n ): Promise<IncidentTimelineResponse> {\n if (!incidentId) {\n throw new AtlaSentError(\"incidentId is required\", {\n code: \"bad_request\",\n });\n }\n const { body, rateLimit } = await this.get<\n Omit<IncidentTimelineResponse, \"rateLimit\">\n >(`/v1/governance/timeline/incident/${encodeURIComponent(incidentId)}`);\n return { ...body, rateLimit };\n }\n\n // ── Connector Management ─────────────────────────────────────────────────\n\n /**\n * List connectors registered for the calling org.\n * Calls `GET /v1/governance/connectors`.\n */\n async listConnectors(\n options: { cursor?: string; limit?: number } = {},\n ): Promise<ListConnectorsResponse> {\n const params = new URLSearchParams();\n if (options.cursor) params.set(\"cursor\", options.cursor);\n if (options.limit !== undefined) params.set(\"limit\", String(options.limit));\n const { body, rateLimit } = await this.get<{\n connectors: ListConnectorsResponse[\"connectors\"];\n total: number;\n next_cursor?: string;\n }>(\"/v1/governance/connectors\", params);\n const result: ListConnectorsResponse = {\n connectors: body.connectors ?? [],\n total: body.total,\n rateLimit,\n };\n if (body.next_cursor) result.nextCursor = body.next_cursor;\n return result;\n }\n\n /**\n * Register and install a new connector for the calling org.\n * Calls `POST /v1/governance/connectors`.\n */\n async installConnector(\n input: InstallConnectorInput,\n ): Promise<InstallConnectorResponse> {\n const { body, rateLimit } = await this.post<\n InstallConnectorResponse[\"connector\"]\n >(\"/v1/governance/connectors\", input);\n return { connector: body, rateLimit };\n }\n\n /**\n * Store encrypted credentials for a connector.\n * Calls `POST /v1/governance/connectors/{id}/authenticate`.\n */\n async authenticateConnector(\n connectorId: string,\n input: AuthenticateConnectorInput,\n ): Promise<AuthenticateConnectorResponse> {\n if (!connectorId) {\n throw new AtlaSentError(\"connectorId is required\", {\n code: \"bad_request\",\n });\n }\n const { body, rateLimit } = await this.post<{\n credential_id: string;\n version: number;\n }>(\n `/v1/governance/connectors/${encodeURIComponent(connectorId)}/authenticate`,\n input,\n );\n return {\n credential_id: body.credential_id,\n version: body.version,\n rateLimit,\n };\n }\n\n /**\n * Trigger an incremental sync for a connector.\n * Calls `POST /v1/governance/connectors/{id}/sync`.\n */\n async syncConnector(connectorId: string): Promise<SyncConnectorResponse> {\n if (!connectorId) {\n throw new AtlaSentError(\"connectorId is required\", {\n code: \"bad_request\",\n });\n }\n const { body, rateLimit } = await this.post<{\n connector_id: string;\n status: SyncConnectorResponse[\"status\"];\n sync_started_at: string;\n }>(`/v1/governance/connectors/${encodeURIComponent(connectorId)}/sync`, {});\n return { ...body, rateLimit };\n }\n\n /**\n * Revoke a connector and all its associated credentials.\n * Calls `POST /v1/governance/connectors/{id}/revoke`.\n */\n async revokeConnector(\n connectorId: string,\n reason?: string,\n ): Promise<RevokeConnectorResponse> {\n if (!connectorId) {\n throw new AtlaSentError(\"connectorId is required\", {\n code: \"bad_request\",\n });\n }\n const body: { reason?: string } = {};\n if (reason !== undefined) body.reason = reason;\n const { body: wire, rateLimit } = await this.post<{\n connector_id: string;\n revoked_at: string;\n }>(\n `/v1/governance/connectors/${encodeURIComponent(connectorId)}/revoke`,\n body,\n );\n return { ...wire, rateLimit };\n }\n\n /**\n * Rotate the credentials for a connector.\n * Calls `POST /v1/governance/connectors/{id}/rotate-credentials`.\n */\n async rotateConnectorCredentials(\n connectorId: string,\n ): Promise<RotateCredentialsResponse> {\n if (!connectorId) {\n throw new AtlaSentError(\"connectorId is required\", {\n code: \"bad_request\",\n });\n }\n const { body, rateLimit } = await this.post<{\n connector_id: string;\n new_version: number;\n rotated_at: string;\n }>(\n `/v1/governance/connectors/${encodeURIComponent(connectorId)}/rotate-credentials`,\n {},\n );\n return { ...body, rateLimit };\n }\n\n /**\n * List enforcement policies for the calling org, optionally filtered by connector type.\n * Calls `GET /v1/governance/enforcement-policies`.\n */\n async listEnforcementPolicies(\n connectorType?: ConnectorType,\n ): Promise<ListEnforcementPoliciesResponse> {\n const params = new URLSearchParams();\n if (connectorType) params.set(\"connector_type\", connectorType);\n const { body, rateLimit } = await this.get<{\n policies: ListEnforcementPoliciesResponse[\"policies\"];\n total: number;\n }>(\"/v1/governance/enforcement-policies\", params);\n return { policies: body.policies ?? [], total: body.total, rateLimit };\n }\n\n /**\n * Create or update a connector enforcement policy.\n * Calls `POST /v1/governance/enforcement-policies`.\n */\n async upsertEnforcementPolicy(\n input: UpsertEnforcementPolicyInput,\n ): Promise<UpsertEnforcementPolicyResponse> {\n const { body, rateLimit } = await this.post<\n UpsertEnforcementPolicyResponse[\"policy\"]\n >(\"/v1/governance/enforcement-policies\", input);\n return { policy: body, rateLimit };\n }\n\n // ── Organizational Risk Graph ─────────────────────────────────────────────\n\n /**\n * Trigger a fresh org-level risk score computation.\n * Calls `POST /v1/governance/risk/compute`.\n */\n async computeOrgRisk(\n options: ComputeOrgRiskOptions = {},\n ): Promise<ComputeOrgRiskResponse> {\n const { body, rateLimit } = await this.post<\n ComputeOrgRiskResponse[\"score\"]\n >(\"/v1/governance/risk/compute\", options);\n return { score: body, rateLimit };\n }\n\n /**\n * Retrieve the most recently computed risk score for the calling org.\n * Calls `GET /v1/governance/risk/latest`.\n */\n async getLatestOrgRisk(): Promise<GetLatestOrgRiskResponse> {\n const { body, rateLimit } = await this.get<{\n score: GetLatestOrgRiskResponse[\"score\"];\n }>(\"/v1/governance/risk/latest\");\n return { score: body.score ?? null, rateLimit };\n }\n\n /**\n * Page through historical org risk scores, most-recent first.\n * Calls `GET /v1/governance/risk/history`.\n */\n async listOrgRiskHistory(\n options: { cursor?: string; limit?: number } = {},\n ): Promise<ListOrgRiskHistoryResponse> {\n const params = new URLSearchParams();\n if (options.cursor) params.set(\"cursor\", options.cursor);\n if (options.limit !== undefined) params.set(\"limit\", String(options.limit));\n const { body, rateLimit } = await this.get<{\n scores: ListOrgRiskHistoryResponse[\"scores\"];\n total: number;\n next_cursor?: string;\n }>(\"/v1/governance/risk/history\", params);\n const result: ListOrgRiskHistoryResponse = {\n scores: body.scores ?? [],\n total: body.total,\n rateLimit,\n };\n if (body.next_cursor) result.nextCursor = body.next_cursor;\n return result;\n }\n // ── Cross-Org Permission Negotiation ──────────────────────────────────────\n\n async checkCrossOrgPermission(\n req: CrossOrgPermissionCheckRequest,\n ): Promise<CrossOrgPermissionCheckResult> {\n const { body } = await this.post<CrossOrgPermissionCheckResult>(\n \"/v1/cross-org/permissions/check\",\n req,\n );\n return body;\n }\n\n async listCrossOrgPermissionChecks(\n params?: CrossOrgPermissionCheckListParams,\n ): Promise<CrossOrgPermissionCheckResult[]> {\n const qs = new URLSearchParams();\n if (params?.source_org_id) qs.set(\"source_org_id\", params.source_org_id);\n if (params?.target_org_id) qs.set(\"target_org_id\", params.target_org_id);\n if (params?.allowed !== undefined)\n qs.set(\"allowed\", String(params.allowed));\n if (params?.limit !== undefined) qs.set(\"limit\", String(params.limit));\n const { body } = await this.get<{\n checks: CrossOrgPermissionCheckResult[];\n }>(\"/v1/cross-org/permissions/checks\", qs);\n return body.checks ?? [];\n }\n\n // ── Anomaly Response Automation ───────────────────────────────────────────\n\n async listAnomalyResponseRules(): Promise<AnomalyResponseRule[]> {\n const { body } = await this.get<{ rules: AnomalyResponseRule[] }>(\n \"/v1/anomaly-response/rules\",\n );\n return body.rules ?? [];\n }\n\n async createAnomalyResponseRule(\n req: CreateAnomalyResponseRuleRequest,\n ): Promise<AnomalyResponseRule> {\n const { body } = await this.post<AnomalyResponseRule>(\n \"/v1/anomaly-response/rules\",\n req,\n );\n return body;\n }\n\n async updateAnomalyResponseRule(\n id: string,\n updates: Partial<CreateAnomalyResponseRuleRequest>,\n ): Promise<AnomalyResponseRule> {\n const { body } = await this.post<AnomalyResponseRule>(\n `/v1/anomaly-response/rules/${encodeURIComponent(id)}/update`,\n updates,\n );\n return body;\n }\n\n async deleteAnomalyResponseRule(id: string): Promise<void> {\n await this.post<Record<string, unknown>>(\n `/v1/anomaly-response/rules/${encodeURIComponent(id)}/delete`,\n {},\n );\n }\n\n async triggerAnomalyResponse(\n req: TriggerAnomalyResponseRequest,\n ): Promise<AnomalyResponseEvent[]> {\n const { body } = await this.post<{ events: AnomalyResponseEvent[] }>(\n \"/v1/anomaly-response/trigger\",\n req,\n );\n return body.events ?? [];\n }\n\n async listAnomalyResponseEvents(params?: {\n limit?: number;\n execution_id?: string;\n }): Promise<AnomalyResponseEvent[]> {\n const qs = new URLSearchParams();\n if (params?.execution_id) qs.set(\"execution_id\", params.execution_id);\n if (params?.limit !== undefined) qs.set(\"limit\", String(params.limit));\n const { body } = await this.get<{ events: AnomalyResponseEvent[] }>(\n \"/v1/anomaly-response/events\",\n qs,\n );\n return body.events ?? [];\n }\n\n // ── Budget Exception Workflows ────────────────────────────────────────────\n\n async listBudgetExceptions(params?: {\n status?: BudgetExceptionStatus;\n budget_policy_id?: string;\n limit?: number;\n offset?: number;\n }): Promise<BudgetExceptionRequest[]> {\n const qs = new URLSearchParams();\n if (params?.status) qs.set(\"status\", params.status);\n if (params?.budget_policy_id)\n qs.set(\"budget_policy_id\", params.budget_policy_id);\n if (params?.limit !== undefined) qs.set(\"limit\", String(params.limit));\n if (params?.offset !== undefined) qs.set(\"offset\", String(params.offset));\n const { body } = await this.get<{ exceptions: BudgetExceptionRequest[] }>(\n \"/v1/budget-exceptions\",\n qs,\n );\n return body.exceptions ?? [];\n }\n\n async getBudgetException(id: string): Promise<BudgetExceptionRequest> {\n const { body } = await this.get<BudgetExceptionRequest>(\n `/v1/budget-exceptions/${encodeURIComponent(id)}`,\n );\n return body;\n }\n\n async createBudgetException(\n req: CreateBudgetExceptionRequest,\n ): Promise<BudgetExceptionRequest> {\n const { body } = await this.post<BudgetExceptionRequest>(\n \"/v1/budget-exceptions\",\n req,\n );\n return body;\n }\n\n async approveBudgetException(\n id: string,\n req: ApproveBudgetExceptionRequest,\n ): Promise<BudgetExceptionRequest> {\n const { body } = await this.post<BudgetExceptionRequest>(\n `/v1/budget-exceptions/${encodeURIComponent(id)}/approve`,\n req,\n );\n return body;\n }\n\n async rejectBudgetException(\n id: string,\n review_notes?: string,\n ): Promise<BudgetExceptionRequest> {\n const { body } = await this.post<BudgetExceptionRequest>(\n `/v1/budget-exceptions/${encodeURIComponent(id)}/reject`,\n { review_notes },\n );\n return body;\n }\n\n async cancelBudgetException(id: string): Promise<BudgetExceptionRequest> {\n const { body } = await this.post<BudgetExceptionRequest>(\n `/v1/budget-exceptions/${encodeURIComponent(id)}/cancel`,\n {},\n );\n return body;\n }\n\n // ── Regulatory Escalation Chain ───────────────────────────────────────────\n\n async listRegulatoryAuthorityLevels(): Promise<RegulatoryAuthorityLevel[]> {\n const { body } = await this.get<{ levels: RegulatoryAuthorityLevel[] }>(\n \"/v1/regulatory/authority-levels\",\n );\n return body.levels ?? [];\n }\n\n async createRegulatoryAuthorityLevel(\n req: Omit<RegulatoryAuthorityLevel, \"id\" | \"org_id\" | \"created_at\">,\n ): Promise<RegulatoryAuthorityLevel> {\n const { body } = await this.post<RegulatoryAuthorityLevel>(\n \"/v1/regulatory/authority-levels\",\n req,\n );\n return body;\n }\n\n async listRegulatoryEscalations(params?: {\n status?: RegulatoryEscalationStatus;\n subject_type?: string;\n subject_id?: string;\n }): Promise<RegulatoryEscalation[]> {\n const qs = new URLSearchParams();\n if (params?.status) qs.set(\"status\", params.status);\n if (params?.subject_type) qs.set(\"subject_type\", params.subject_type);\n if (params?.subject_id) qs.set(\"subject_id\", params.subject_id);\n const { body } = await this.get<{ escalations: RegulatoryEscalation[] }>(\n \"/v1/regulatory/escalations\",\n qs,\n );\n return body.escalations ?? [];\n }\n\n async createRegulatoryEscalation(\n req: CreateRegulatoryEscalationRequest,\n ): Promise<RegulatoryEscalation> {\n const { body } = await this.post<RegulatoryEscalation>(\n \"/v1/regulatory/escalations\",\n req,\n );\n return body;\n }\n\n async acknowledgeRegulatoryEscalation(\n id: string,\n ): Promise<RegulatoryEscalation> {\n const { body } = await this.post<RegulatoryEscalation>(\n `/v1/regulatory/escalations/${encodeURIComponent(id)}/acknowledge`,\n {},\n );\n return body;\n }\n\n async resolveRegulatoryEscalation(\n id: string,\n resolution: string,\n resolution_details?: Record<string, unknown>,\n ): Promise<RegulatoryEscalation> {\n const { body } = await this.post<RegulatoryEscalation>(\n `/v1/regulatory/escalations/${encodeURIComponent(id)}/resolve`,\n { resolution, resolution_details },\n );\n return body;\n }\n\n async overrideRegulatoryEscalation(\n id: string,\n reason: string,\n ): Promise<RegulatoryEscalation> {\n const { body } = await this.post<RegulatoryEscalation>(\n `/v1/regulatory/escalations/${encodeURIComponent(id)}/override`,\n { reason },\n );\n return body;\n }\n\n // ── Incentive Signal Feedback Loop ────────────────────────────────────────\n\n async listSignalActions(\n signal_id: string,\n ): Promise<GovernanceSignalAction[]> {\n const { body } = await this.get<{ actions: GovernanceSignalAction[] }>(\n `/v1/governance/signals/${encodeURIComponent(signal_id)}/actions`,\n );\n return body.actions ?? [];\n }\n\n async recordSignalAction(\n signal_id: string,\n req: RecordSignalActionRequest,\n ): Promise<GovernanceSignalAction> {\n const { body } = await this.post<GovernanceSignalAction>(\n `/v1/governance/signals/${encodeURIComponent(signal_id)}/actions`,\n req,\n );\n return body;\n }\n\n async recordSignalOutcome(\n signal_id: string,\n action_id: string,\n req: RecordSignalOutcomeRequest,\n ): Promise<GovernanceSignalAction> {\n const { body } = await this.post<GovernanceSignalAction>(\n `/v1/governance/signals/${encodeURIComponent(signal_id)}/actions/${encodeURIComponent(action_id)}/outcome`,\n req,\n );\n return body;\n }\n\n async getSignalActionSummary(): Promise<SignalActionSummary> {\n const { body } = await this.get<SignalActionSummary>(\n \"/v1/governance/signals/actions/summary\",\n );\n return body;\n }\n\n // ── Cross-Org Impersonation ───────────────────────────────────────────────\n\n async listImpersonationGrants(): Promise<CrossOrgImpersonationGrant[]> {\n const { body } = await this.get<{ grants: CrossOrgImpersonationGrant[] }>(\n \"/v1/cross-org/impersonation/grants\",\n );\n return body.grants ?? [];\n }\n\n async createImpersonationGrant(\n req: CreateImpersonationGrantRequest,\n ): Promise<CrossOrgImpersonationGrant> {\n const { body } = await this.post<CrossOrgImpersonationGrant>(\n \"/v1/cross-org/impersonation/grants\",\n req,\n );\n return body;\n }\n\n async revokeImpersonationGrant(id: string): Promise<void> {\n await this.post<Record<string, unknown>>(\n `/v1/cross-org/impersonation/grants/${encodeURIComponent(id)}/revoke`,\n {},\n );\n }\n\n async issueImpersonationToken(\n grant_id: string,\n requested_duration_seconds?: number,\n ): Promise<ImpersonationToken> {\n const { body } = await this.post<ImpersonationToken>(\n `/v1/cross-org/impersonation/grants/${encodeURIComponent(grant_id)}/token`,\n { requested_duration_seconds },\n );\n return body;\n }\n\n async validateImpersonationToken(\n token: string,\n ): Promise<ImpersonationValidationResult> {\n const { body } = await this.post<ImpersonationValidationResult>(\n \"/v1/cross-org/impersonation/validate\",\n { token },\n );\n return body;\n }\n\n // ── Constrained governance agents (read surface) ──────────────────────────\n //\n // Three GETs onto the v1-governance-agents edge function. Doctrine:\n // findings produced by these endpoints are advisory signal, never\n // authority. There is no `runGovernanceAgent` method on this client —\n // invocation belongs in CI (atlasent-action `governance-agents` mode),\n // not in application code.\n\n /**\n * List the advisory governance-agent registry for the calling org.\n *\n * Calls `GET /v1/governance/agents`. The registry is reference data\n * seeded at runtime-DB migration time; every row has\n * `authority_class = \"advisory\"` and `can_authorize = false` —\n * structural invariants enforced by the schema, not policy.\n */\n async listGovernanceAgents(): Promise<GovernanceAgent[]> {\n const { body } = await this.get<ListGovernanceAgentsResponse>(\n \"/v1/governance/agents\",\n );\n return [...(body.agents ?? [])];\n }\n\n /**\n * List advisory findings emitted against one governed change.\n *\n * Calls `GET /v1/governance/findings?change_id=…[&agent_slug=…]`.\n * Returns the typed-finding rows in `created_at DESC` order, including\n * `routed_gate_id` when the finding→gate trigger linked them. Findings\n * with `can_authorize === false` (always) are advisory; rendering them\n * never satisfies a gate.\n */\n async listGovernanceFindings(\n query: ListGovernanceFindingsQuery,\n ): Promise<GovernanceAgentFinding[]> {\n if (!query?.change_id) {\n throw new AtlaSentError(\"change_id is required\", { code: \"bad_request\" });\n }\n const params = new URLSearchParams({ change_id: query.change_id });\n if (query.agent_slug) params.set(\"agent_slug\", query.agent_slug);\n const { body } = await this.get<ListGovernanceFindingsResponse>(\n \"/v1/governance/findings\",\n params,\n );\n return [...(body.findings ?? [])];\n }\n\n /**\n * List agent run records against one governed change.\n *\n * Calls `GET /v1/governance/evaluations?change_id=…[&agent_slug=…]`.\n * Returns every persisted evaluation, including `failed` / `timeout`\n * runs and `completed` runs with zero findings — the latter is the\n * positive signal \"the agent ran and found nothing\", which the UI\n * surfaces as `clear`.\n */\n async listGovernanceEvaluations(\n query: ListGovernanceEvaluationsQuery,\n ): Promise<GovernanceAgentEvaluation[]> {\n if (!query?.change_id) {\n throw new AtlaSentError(\"change_id is required\", { code: \"bad_request\" });\n }\n const params = new URLSearchParams({ change_id: query.change_id });\n if (query.agent_slug) params.set(\"agent_slug\", query.agent_slug);\n const { body } = await this.get<ListGovernanceEvaluationsResponse>(\n \"/v1/governance/evaluations\",\n params,\n );\n return [...(body.evaluations ?? [])];\n }\n\n // ── Private adapters for sub-client factories ──────────────────────────────\n // Thin wrappers that expose the private request infrastructure to sub-client\n // factories (scim, evidenceBundles, auth) without widening the public API.\n\n private async _post<T>(\n path: string,\n body: unknown,\n query?: URLSearchParams,\n ): Promise<{ body: T }> {\n const { body: b } = await this.post<T>(path, body, query);\n return { body: b };\n }\n\n private async _get<T>(\n path: string,\n query?: URLSearchParams,\n ): Promise<{ body: T }> {\n const { body: b } = await this.get<T>(path, query);\n return { body: b };\n }\n\n private async _put<T>(path: string, body: unknown): Promise<{ body: T }> {\n return this._requestRaw<T>(path, \"PUT\", body, undefined);\n }\n\n private async _patch<T>(path: string, body: unknown): Promise<{ body: T }> {\n return this._requestRaw<T>(path, \"PATCH\", body, undefined);\n }\n\n private async _delete(path: string): Promise<void> {\n await this._requestRaw<Record<string, unknown>>(path, \"DELETE\", undefined, undefined);\n }\n\n private async _getRaw(path: string): Promise<ArrayBuffer> {\n const url = `${this.baseUrl}${path}`;\n const requestId = globalThis.crypto.randomUUID();\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n \"User-Agent\": this.userAgent,\n \"X-Request-ID\": requestId,\n \"X-AtlaSent-Protocol-Version\": \"1\",\n };\n const response = await this.fetchImpl(url, {\n method: \"GET\",\n headers,\n signal: AbortSignal.timeout(this.timeoutMs),\n });\n if (!response.ok) {\n const text = await response.text().catch(() => \"\");\n throw new AtlaSentError(`GET ${path} returned ${response.status}`, {\n code: response.status >= 500 ? \"server_error\" : \"bad_request\",\n status: response.status,\n requestId,\n });\n }\n return response.arrayBuffer();\n }\n\n private async _requestRaw<T>(\n path: string,\n method: \"PUT\" | \"PATCH\" | \"DELETE\",\n body: unknown,\n query: URLSearchParams | undefined,\n ): Promise<{ body: T }> {\n const qs =\n query && Array.from(query).length > 0 ? `?${query.toString()}` : \"\";\n const url = `${this.baseUrl}${path}${qs}`;\n const requestId = globalThis.crypto.randomUUID();\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n \"User-Agent\": this.userAgent,\n \"X-Request-ID\": requestId,\n \"X-AtlaSent-Protocol-Version\": \"1\",\n };\n if (method === \"PUT\" && body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n const init: RequestInit = { method, headers, signal: AbortSignal.timeout(this.timeoutMs) };\n if (method === \"PUT\" && body !== undefined) {\n init.body = JSON.stringify(body);\n }\n const response = await this.fetchImpl(url, init);\n if (!response.ok) {\n const text = await response.text().catch(() => \"\");\n throw new AtlaSentError(`${method} ${path} returned ${response.status}`, {\n code: response.status >= 500 ? \"server_error\" : \"bad_request\",\n status: response.status,\n requestId,\n });\n }\n if (method === \"DELETE\") {\n return { body: {} as T };\n }\n return { body: (await response.json()) as T };\n }\n}\n\n/**\n * Parse the server's `X-RateLimit-*` header triple into a typed\n * {@link RateLimitState}. Returns `null` when any of the three headers\n * is missing or unparseable — callers treat that as \"the server didn't\n * emit rate-limit state\" rather than \"the window is empty\".\n *\n * `X-RateLimit-Reset` is accepted as either unix-seconds (what the\n * AtlaSent edge functions emit today) or an ISO 8601 timestamp.\n */\nfunction parseRateLimitHeaders(headers: Headers): RateLimitState | null {\n const rawLimit = headers.get(\"x-ratelimit-limit\");\n const rawRemaining = headers.get(\"x-ratelimit-remaining\");\n const rawReset = headers.get(\"x-ratelimit-reset\");\n if (rawLimit === null || rawRemaining === null || rawReset === null) {\n return null;\n }\n const limit = Number(rawLimit);\n const remaining = Number(rawRemaining);\n if (!Number.isFinite(limit) || !Number.isFinite(remaining)) {\n return null;\n }\n const resetAt = parseResetHeader(rawReset);\n if (resetAt === null) {\n return null;\n }\n return { limit, remaining, resetAt };\n}\n\nfunction parseResetHeader(raw: string): Date | null {\n const seconds = Number(raw);\n if (Number.isFinite(seconds)) {\n // Standard shape: unix seconds. 10-digit values are in the valid\n // range ~2001–2286 so this heuristic won't confuse a tiny\n // `remaining`-like number for an epoch.\n return new Date(seconds * 1000);\n }\n const ms = Date.parse(raw);\n if (Number.isFinite(ms)) {\n return new Date(ms);\n }\n return null;\n}\n\nfunction mapFetchError(err: unknown, requestId: string): AtlaSentError {\n if (err instanceof AtlaSentError) return err;\n if (err instanceof DOMException && err.name === \"TimeoutError\") {\n return new AtlaSentError(\"Request to AtlaSent API timed out\", {\n code: \"timeout\",\n requestId,\n cause: err,\n });\n }\n if (err instanceof Error && err.name === \"AbortError\") {\n return new AtlaSentError(\"Request to AtlaSent API timed out\", {\n code: \"timeout\",\n requestId,\n cause: err,\n });\n }\n const message = err instanceof Error ? err.message : \"network error\";\n return new AtlaSentError(`Failed to reach AtlaSent API: ${message}`, {\n code: \"network\",\n requestId,\n cause: err,\n });\n}\n\nasync function buildHttpError(\n response: Response,\n requestId: string,\n): Promise<AtlaSentError> {\n const status = response.status;\n const classified = await classifyHttpStatus(response);\n const init: AtlaSentErrorInit = {\n status,\n code: classified.code,\n requestId,\n };\n if (classified.retryAfterMs !== undefined) {\n init.retryAfterMs = classified.retryAfterMs;\n }\n return new AtlaSentError(classified.message, init);\n}\n\nasync function classifyHttpStatus(response: Response): Promise<{\n message: string;\n code: AtlaSentErrorCode;\n retryAfterMs: number | undefined;\n}> {\n const status = response.status;\n const serverMessage = await readServerMessage(response);\n\n if (status === 401) {\n return {\n message: serverMessage ?? \"Invalid API key\",\n code: \"invalid_api_key\",\n retryAfterMs: undefined,\n };\n }\n if (status === 403) {\n return {\n message:\n serverMessage ?? \"Access forbidden — check your API key permissions\",\n code: \"forbidden\",\n retryAfterMs: undefined,\n };\n }\n if (status === 429) {\n return {\n message: serverMessage ?? \"Rate limited by AtlaSent API\",\n code: \"rate_limited\",\n retryAfterMs: parseRetryAfter(response.headers.get(\"retry-after\")),\n };\n }\n if (status >= 500) {\n return {\n message: serverMessage ?? `AtlaSent API returned HTTP ${status}`,\n code: \"server_error\",\n retryAfterMs: undefined,\n };\n }\n return {\n message: serverMessage ?? `AtlaSent API returned HTTP ${status}`,\n code: \"bad_request\",\n retryAfterMs: undefined,\n };\n}\n\nasync function readServerMessage(response: Response): Promise<string | null> {\n try {\n const text = await response.text();\n if (!text) return null;\n try {\n const parsed = JSON.parse(text);\n if (parsed && typeof parsed === \"object\") {\n const msg = (parsed as Record<string, unknown>).message;\n const reason = (parsed as Record<string, unknown>).reason;\n if (typeof msg === \"string\" && msg.length > 0) return msg;\n if (typeof reason === \"string\" && reason.length > 0) return reason;\n }\n } catch {\n // Fall through — treat as plain text.\n }\n return text.length > 500 ? `${text.slice(0, 500)}…` : text;\n } catch {\n return null;\n }\n}\n\n/**\n * Translate an {@link AuditEventsQuery} into `URLSearchParams`. The\n * server expects snake_case keys (`actor_id`) and accepts\n * comma-joined values for `types`; numeric `limit` serializes via\n * `String(n)`. Undefined / empty fields are dropped so the query\n * string stays minimal.\n */\nfunction buildAuditEventsQuery(query: AuditEventsQuery): URLSearchParams {\n const params = new URLSearchParams();\n if (query.types !== undefined && query.types !== \"\") {\n params.set(\"types\", query.types);\n }\n if (query.actor_id !== undefined && query.actor_id !== \"\") {\n params.set(\"actor_id\", query.actor_id);\n }\n if (query.from !== undefined && query.from !== \"\") {\n params.set(\"from\", query.from);\n }\n if (query.to !== undefined && query.to !== \"\") {\n params.set(\"to\", query.to);\n }\n if (query.limit !== undefined) {\n params.set(\"limit\", String(query.limit));\n }\n if (query.cursor !== undefined && query.cursor !== \"\") {\n params.set(\"cursor\", query.cursor);\n }\n return params;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseRetryAfter(raw: string | null): number | undefined {\n if (!raw) return undefined;\n const seconds = Number(raw);\n if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);\n const date = Date.parse(raw);\n if (Number.isFinite(date)) {\n const delta = date - Date.now();\n return delta > 0 ? delta : 0;\n }\n return undefined;\n}\n\n// ── SSE stream parser ─────────────────────────────────────────────────────────\n\n/**\n * Parse an SSE `ReadableStream<Uint8Array>` into typed {@link StreamEvent}s.\n *\n * Hardening additions over the original:\n * - Per-event timeout: if no chunk arrives within `timeoutMs` (0 = disabled),\n * throws {@link StreamTimeoutError}.\n * - Partial-JSON guard: wraps `JSON.parse` failures in {@link StreamParseError}\n * rather than letting the raw `SyntaxError` escape.\n * - Calls `onEventId` whenever the server emits an `id:` field so the caller\n * can track the `Last-Event-ID` for reconnection.\n * - Terminal detection: returns on `event: done` OR when a `decision` event\n * carries `done: true` at the top level (server-side terminal signal).\n */\nasync function* parseSseStream(\n body: ReadableStream<Uint8Array>,\n requestId: string,\n timeoutMs: number,\n onEventId: (id: string) => void,\n): AsyncIterable<StreamEvent> {\n const reader = body.getReader();\n const decoder = new TextDecoder(\"utf-8\");\n let buf = \"\";\n\n type ChunkResult =\n | { done: true; value?: undefined }\n | { done: false; value: Uint8Array };\n\n /**\n * Read the next chunk from the reader, applying a per-read timeout when\n * `timeoutMs > 0`. Returns `{ done: true }` when the stream ends, throws\n * {@link StreamTimeoutError} on timeout.\n */\n async function readChunk(): Promise<ChunkResult> {\n if (timeoutMs <= 0) {\n return reader.read() as Promise<ChunkResult>;\n }\n return new Promise<ChunkResult>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new StreamTimeoutError(timeoutMs));\n }, timeoutMs);\n (reader.read() as Promise<ChunkResult>).then(\n (result) => {\n clearTimeout(timer);\n resolve(result);\n },\n (err: unknown) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n }\n\n try {\n for (;;) {\n let done: boolean;\n let value: Uint8Array | undefined;\n try {\n const result = await readChunk();\n done = result.done;\n value = result.value;\n } catch (err) {\n if (err instanceof StreamTimeoutError) throw err;\n // Network error mid-stream: surface as AtlaSentError(network) so the\n // caller's reconnection loop can catch and retry.\n throw new AtlaSentError(\n `AtlaSent stream read failed: ${err instanceof Error ? err.message : String(err)}`,\n { code: \"network\", requestId, cause: err },\n );\n }\n\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n\n let boundary: number;\n while ((boundary = buf.indexOf(\"\\n\\n\")) !== -1) {\n const block = buf.slice(0, boundary);\n buf = buf.slice(boundary + 2);\n\n let eventType = \"message\";\n let data = \"\";\n let eventId: string | undefined;\n for (const line of block.split(\"\\n\")) {\n if (line.startsWith(\"event: \")) eventType = line.slice(7).trim();\n else if (line.startsWith(\"data: \")) data = line.slice(6);\n else if (line.startsWith(\"id: \")) eventId = line.slice(4).trim();\n else if (line.startsWith(\"id:\")) eventId = line.slice(3).trim();\n }\n\n if (eventId !== undefined) onEventId(eventId);\n\n if (!data) continue;\n if (eventType === \"done\") return;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(data);\n } catch (err) {\n throw new StreamParseError(data, err);\n }\n\n if (eventType === \"error\") {\n const e = parsed as {\n code?: string;\n message?: string;\n request_id?: string;\n };\n throw new AtlaSentError(\n e.message ?? \"Stream error from AtlaSent API\",\n {\n code: (e.code as AtlaSentErrorCode | undefined) ?? \"server_error\",\n requestId: e.request_id ?? requestId,\n },\n );\n }\n\n if (eventType === \"decision\") {\n const d = parsed as {\n permitted?: boolean;\n decision_id?: string;\n reason?: string;\n audit_hash?: string;\n timestamp?: string;\n is_final?: boolean;\n done?: boolean;\n };\n if (\n typeof d.permitted !== \"boolean\" ||\n typeof d.decision_id !== \"string\"\n ) {\n throw new AtlaSentError(\n \"Malformed decision event from AtlaSent API\",\n {\n code: \"bad_response\",\n requestId,\n },\n );\n }\n // Streaming wire uses legacy {permitted, decision_id} shape;\n // normalise to canonical lowercase decision vocabulary.\n const streamDecision = d.permitted ? \"allow\" : \"deny\";\n const isFinal = d.is_final ?? false;\n yield {\n type: \"decision\",\n decision: streamDecision,\n decision_canonical: streamDecision,\n permitId: d.decision_id,\n reason: d.reason ?? \"\",\n auditHash: d.audit_hash ?? \"\",\n timestamp: d.timestamp ?? \"\",\n isFinal,\n } satisfies StreamDecisionEvent;\n\n // Terminal: final decision OR inline done: true closes the stream.\n if (isFinal || d.done === true) return;\n } else if (eventType === \"progress\") {\n const p = parsed as Record<string, unknown>;\n yield {\n type: \"progress\",\n stage: String(p[\"stage\"] ?? \"\"),\n ...p,\n } satisfies StreamProgressEvent;\n // Server may signal terminal state via done: true on any event type.\n if ((p as Record<string, unknown>).done === true) return;\n } else {\n // Unknown event type: check for done: true as a terminal signal.\n if (\n parsed !== null &&\n typeof parsed === \"object\" &&\n (parsed as Record<string, unknown>).done === true\n ) {\n return;\n }\n }\n // Unknown event types skipped for forward compatibility.\n }\n }\n\n // Stream closed before an explicit `event: done`. If there's leftover\n // partial data in the buffer, it means the stream was cut mid-event.\n if (buf.trim().length > 0) {\n throw new StreamParseError(buf);\n }\n } finally {\n reader.releaseLock();\n }\n}\n","/**\n * `atlasent.protect(...)` — the one-call, fail-closed execution-time\n * authorization boundary.\n *\n * ```ts\n * import atlasent from \"@atlasent/sdk\";\n *\n * const permit = await atlasent.protect({\n * agent: \"deploy-bot\",\n * action: \"production.deploy\",\n * context: { commit, approver },\n * });\n * // …run the action. If we got here, AtlaSent authorized it\n * // end-to-end (evaluate + verifyPermit).\n * ```\n *\n * Unlike {@link AtlaSentClient.evaluate}, `protect` never returns a\n * denied decision. On deny, it throws {@link AtlaSentDeniedError};\n * on transport / auth / server failure it throws\n * {@link AtlaSentError}. The action cannot execute unless a valid\n * {@link Permit} is returned — this is the SDK's category boundary,\n * not a helper.\n *\n * `protectWithEvidence` is the same contract plus a signed\n * {@link DecisionReceipt} minted on the way out. Use it when you need\n * tamper-evident proof of authorization stored alongside the action\n * record (deploy logs, payment records, close workflows).\n */\n\nimport { AtlaSentClient } from \"./client.js\";\nimport type { DeployGateRequest, DeployGateResponse } from \"./types.js\";\nimport {\n AtlaSentDeniedError,\n AtlaSentError,\n BundleVerificationError,\n normalizePermitOutcome,\n type AtlaSentDecision,\n} from \"./errors.js\";\nimport { getGlobalTrustRootManager } from \"./trustRoot.js\";\nimport type { AtlaSentClientOptions, ConstraintTrace } from \"./types.js\";\nimport {\n buildDecisionReceiptPayload,\n buildWhyTrace,\n computeContextHash,\n signDecisionReceiptHmac,\n} from \"./evidenceEngine.js\";\nimport type {\n DecisionReceipt,\n DecisionReceiptAlgorithm,\n} from \"./evidenceEngine.js\";\n\n/** Input to {@link protect}. Same shape as `EvaluateRequest`. */\nexport interface ProtectRequest {\n agent: string;\n action: string;\n context?: Record<string, unknown>;\n}\n\n/**\n * Success return from {@link protect}. The action is authorized\n * end-to-end — evaluation allowed AND the resulting permit verified.\n */\nexport interface Permit {\n /** Opaque permit / decision identifier. */\n permitId: string;\n /** Verification hash bound to the permit. */\n permitHash: string;\n /** Audit-trail entry associated with the decision (hash-chained). */\n auditHash: string;\n /** Human-readable reason from the policy engine. */\n reason: string;\n /** ISO 8601 timestamp of the verification. */\n timestamp: string;\n /** ISO-8601 expiration timestamp of the permit. null on pre-rollout servers. */\n permitExpiresAt: string | null;\n}\n\n/** Configuration for the process-wide singleton used by {@link protect}. */\nexport interface ConfigureOptions {\n /** Overrides `ATLASENT_API_KEY` env var. */\n apiKey?: string;\n /** Overrides the default `https://api.atlasent.io`. */\n baseUrl?: string;\n /** Per-request timeout in ms. */\n timeoutMs?: number;\n /** Inject a custom fetch (primarily for tests). */\n fetch?: typeof fetch;\n /** Override the retry policy. Pass `{ maxAttempts: 1 }` to disable retries. */\n retryPolicy?: import(\"./retry.js\").RetryPolicy;\n}\n\nlet sharedClient: AtlaSentClient | null = null;\nlet overrides: ConfigureOptions = {};\n\n/**\n * Configure the singleton client used by {@link protect}. Optional —\n * if `ATLASENT_API_KEY` is set in the environment, `protect` works\n * without any configuration. Calling `configure` again replaces the\n * singleton; subsequent `protect` calls use the new settings.\n */\nexport function configure(options: ConfigureOptions): void {\n overrides = { ...overrides, ...options };\n sharedClient = null;\n}\n\n/**\n * Run the canonical Deploy Gate V1 helper using the process-wide client.\n * Defaults to action `production.deploy`; execution is allowed only after\n * server-side `/v1-evaluate` and `/v1-verify-permit` both pass.\n */\nexport async function deployGate(\n request: DeployGateRequest = {},\n): Promise<DeployGateResponse> {\n return getClient().deployGate(request);\n}\n\n/** Reset the singleton. Exported for tests; not part of the public API. */\nexport function __resetSharedClientForTests(): void {\n sharedClient = null;\n overrides = {};\n}\n\nfunction getClient(): AtlaSentClient {\n if (sharedClient) return sharedClient;\n\n // Guard process.env access so this module is safe in browser and\n // edge-runtime environments where `process` is not defined as a global.\n const envApiKey =\n typeof process !== \"undefined\" && process.env\n ? process.env.ATLASENT_API_KEY\n : undefined;\n\n const apiKey = overrides.apiKey ?? envApiKey;\n if (!apiKey) {\n throw new AtlaSentError(\n \"AtlaSent is not configured. Set ATLASENT_API_KEY in the environment, or call atlasent.configure({ apiKey }).\",\n { code: \"invalid_api_key\" },\n );\n }\n const options: AtlaSentClientOptions = { apiKey };\n if (overrides.baseUrl !== undefined) options.baseUrl = overrides.baseUrl;\n if (overrides.timeoutMs !== undefined)\n options.timeoutMs = overrides.timeoutMs;\n if (overrides.fetch !== undefined) options.fetch = overrides.fetch;\n if (overrides.retryPolicy !== undefined)\n options.retryPolicy = overrides.retryPolicy;\n sharedClient = new AtlaSentClient(options);\n return sharedClient;\n}\n\n// Mirrors the server-side ACTION_TYPE_RE in v1-evaluate/handler.ts.\nconst ACTION_TYPE_RE = /^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$/;\n\nfunction wireDecisionToDenied(serverDecision: string): AtlaSentDecision {\n // Normalise to lowercase before matching — the decision field is now\n // always lowercase from evaluate(), but defensive lower-casing here\n // handles any edge case where an older code path sends uppercase.\n const lower = serverDecision.toLowerCase();\n if (lower === \"hold\" || lower === \"escalate\") return lower;\n return \"deny\";\n}\n\n// ── Execution-hash helpers ────────────────────────────────────────────────────\n\n/**\n * Sort all object keys recursively so the JSON serialization is\n * deterministic (RFC-8785-style canonical form). Arrays are preserved\n * in insertion order; only object keys are sorted.\n */\nfunction sortKeysDeep(val: unknown): unknown {\n if (Array.isArray(val)) return val.map(sortKeysDeep);\n if (val !== null && typeof val === \"object\") {\n return Object.keys(val as object)\n .sort()\n .reduce<Record<string, unknown>>((acc, k) => {\n acc[k] = sortKeysDeep((val as Record<string, unknown>)[k]);\n return acc;\n }, {});\n }\n return val;\n}\n\n/**\n * Compute a SHA-256 hex digest of the recursively key-sorted canonical\n * JSON of `payload`. Used as `execution_hash` on the permit-consume\n * (verify) request so the server can validate the evaluate payload\n * was not tampered with between evaluate and consume.\n *\n * Falls back to `node:crypto` when `crypto.subtle` is unavailable\n * (Node < 20 without the Web Crypto global).\n */\nasync function computeExecutionHash(payload: unknown): Promise<string> {\n const sorted = sortKeysDeep(payload);\n const canonical = JSON.stringify(sorted);\n\n // Prefer the Web Crypto API (available in browsers, Node 20+,\n // Cloudflare Workers, Deno, etc.).\n if (\n typeof globalThis !== \"undefined\" &&\n globalThis.crypto?.subtle?.digest\n ) {\n const bytes = new TextEncoder().encode(canonical);\n const buf = await globalThis.crypto.subtle.digest(\"SHA-256\", bytes);\n return Array.from(new Uint8Array(buf))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n }\n\n // Fallback: node:crypto (Node < 20 or environments without crypto.subtle).\n try {\n // Dynamic import so bundlers that target browsers don't pull in\n // node internals. The `node:` prefix avoids any user-land shim.\n const { createHash } =\n await import(/* @vite-ignore */ /* webpackIgnore: true */ \"node:crypto\");\n return createHash(\"sha256\").update(canonical, \"utf8\").digest(\"hex\");\n } catch {\n // Last-resort: if neither crypto.subtle nor node:crypto is available\n // (very old Node, restricted runtime), return an empty string so the\n // verify call still proceeds — the server will reject if execution_hash\n // is required for production permits.\n // eslint-disable-next-line no-console\n console.warn(\n \"[atlasent] Could not compute execution_hash: neither crypto.subtle \" +\n \"nor node:crypto is available in this runtime.\",\n );\n return \"\";\n }\n}\n\nfunction generateReceiptId(): string {\n if (\n typeof globalThis !== \"undefined\" &&\n typeof globalThis.crypto?.randomUUID === \"function\"\n ) {\n return globalThis.crypto.randomUUID();\n }\n return `rcpt_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/**\n * Authorize an action end-to-end. On allow, returns a verified\n * {@link Permit}. On anything else, throws:\n *\n * - {@link AtlaSentDeniedError} — policy denied, or the permit\n * failed verification. Fail-closed: if this throws, the action\n * MUST NOT proceed.\n * - {@link AtlaSentError} — transport, timeout, auth, rate-limit,\n * or server error. Same fail-closed contract: do not proceed.\n */\nexport async function protect(request: ProtectRequest): Promise<Permit> {\n if (!ACTION_TYPE_RE.test(request.action)) {\n throw new AtlaSentError(\n `action must be in dot-notation format (e.g. \"production.deploy\"). Got: ${JSON.stringify(request.action)}`,\n { code: \"bad_request\" },\n );\n }\n // ADR-005 D3: fail-closed on expired trust snapshot. checkExpiry() also\n // emits the one-time half-life warning if >50% of validity window has elapsed.\n const trustMgr = getGlobalTrustRootManager({ disableRefresh: false });\n if (trustMgr.checkExpiry() === \"expired\") {\n const snap = trustMgr.getSnapshot();\n throw new BundleVerificationError({\n reason: \"trust_snapshot_expired\",\n snapshotValidUntil: snap.valid_until,\n snapshotFetchedAt: snap.issued_at,\n });\n }\n const client = getClient();\n const evaluation = await client.evaluate(request);\n\n // decision is now canonical lowercase: \"allow\" | \"deny\" | \"hold\" | \"escalate\"\n if (evaluation.decision !== \"allow\") {\n throw new AtlaSentDeniedError({\n decision: wireDecisionToDenied(evaluation.decision),\n evaluationId: evaluation.permitId,\n reason: evaluation.reason,\n auditHash: evaluation.auditHash,\n });\n }\n\n const environment = request.context?.environment as string | undefined;\n if (!environment) {\n throw new AtlaSentError(\n 'context.environment is required. Pass the environment where this action executes (e.g. \"production\", \"staging\").',\n { code: \"bad_request\" },\n );\n }\n\n // Compute execution_hash over the original evaluate payload so\n // the server can validate integrity on permit consume.\n const evaluatePayload = {\n action_type: request.action,\n actor_id: request.agent,\n context: request.context ?? {},\n };\n const execution_hash = await computeExecutionHash(evaluatePayload);\n\n const verifyRequest: {\n permitId: string;\n agent: string;\n action: string;\n context?: Record<string, unknown>;\n environment: string;\n execution_hash?: string;\n } = {\n permitId: evaluation.permitId,\n agent: request.agent,\n action: request.action,\n environment,\n ...(execution_hash ? { execution_hash } : {}),\n };\n if (request.context !== undefined) verifyRequest.context = request.context;\n const verification = await client.verifyPermit(verifyRequest);\n\n if (!verification.verified) {\n const outcome = normalizePermitOutcome(verification.outcome);\n throw new AtlaSentDeniedError({\n decision: \"deny\",\n evaluationId: evaluation.permitId,\n reason: `Permit failed verification (${verification.outcome})`,\n auditHash: evaluation.auditHash,\n ...(outcome !== undefined && { outcome }),\n });\n }\n\n return {\n permitId: evaluation.permitId,\n permitHash: verification.permitHash,\n auditHash: evaluation.auditHash,\n reason: evaluation.reason,\n timestamp: verification.timestamp,\n permitExpiresAt: verification.expiresAt ?? null,\n };\n}\n\n// ── Evidence-enhanced protect ─────────────────────────────────────────────────\n\n/**\n * A verified {@link Permit} with an embedded signed {@link DecisionReceipt}.\n *\n * Returned by {@link protectWithEvidence}. Store `receipt` alongside\n * your action record (deploy logs, payment records, close workflows)\n * to give auditors a self-contained proof of authorization.\n */\nexport interface PermitWithEvidence extends Permit {\n /** Signed per-decision receipt. `algorithm: \"none\"` when no signing secret was supplied. */\n receipt: DecisionReceipt;\n}\n\n/** Options for {@link protectWithEvidence}. */\nexport interface ProtectWithEvidenceOptions {\n /**\n * HMAC-SHA256 signing secret. When provided, the receipt is signed\n * and can be verified offline with `verifyDecisionReceiptHmac`.\n * Recommend `process.env.ATLASENT_RECEIPT_SIGNING_SECRET`.\n */\n signingSecret?: string;\n /**\n * Registry key ID recorded on the receipt, paired with `signingSecret`.\n * Used for key rotation: store the ID alongside the receipt so\n * verifiers know which key to use.\n */\n signingKeyId?: string;\n /**\n * If you have already called `client.evaluatePreflight()` for this\n * request, pass `constraintTrace` here to populate\n * `receipt.why_trace` with the full stage-by-stage \"why\" trace.\n * When omitted, `why_trace` is `null` on the receipt.\n */\n constraintTrace?: ConstraintTrace | null;\n}\n\n/**\n * Authorize an action end-to-end and mint a signed {@link DecisionReceipt}.\n *\n * Same fail-closed contract as {@link protect} — throws\n * {@link AtlaSentDeniedError} on deny, {@link AtlaSentError} on\n * transport failure. The action MUST NOT proceed if this throws.\n *\n * On allow, returns the verified `Permit` plus a signed `DecisionReceipt`\n * that captures:\n * - The evaluation ID and decision\n * - Human-readable reasons\n * - Permit ID and hash\n * - Audit-trail hash (hash-chain link)\n * - SHA-256 of the evaluate context (tamper-evidence for the inputs)\n * - Optional \"why\" trace (pass `constraintTrace` from `evaluatePreflight`)\n *\n * ```ts\n * const { permit, receipt } = await protectWithEvidence(\n * { agent: \"deploy-bot\", action: \"production.deploy\", context },\n * {\n * signingSecret: process.env.ATLASENT_RECEIPT_SIGNING_SECRET,\n * signingKeyId: \"key-v1\",\n * },\n * );\n * // Store alongside the deployment record.\n * await db.deployments.create({ commitSha, permit, receipt });\n * ```\n */\nexport async function protectWithEvidence(\n request: ProtectRequest,\n opts: ProtectWithEvidenceOptions = {},\n): Promise<PermitWithEvidence> {\n if (!ACTION_TYPE_RE.test(request.action)) {\n throw new AtlaSentError(\n `action must be in dot-notation format (e.g. \"production.deploy\"). Got: ${JSON.stringify(request.action)}`,\n { code: \"bad_request\" },\n );\n }\n const client = getClient();\n\n // 1. Evaluate (same logic as protect()).\n const evaluation = await client.evaluate(request);\n\n if (evaluation.decision !== \"allow\") {\n throw new AtlaSentDeniedError({\n decision: wireDecisionToDenied(evaluation.decision),\n evaluationId: evaluation.permitId,\n reason: evaluation.reason,\n auditHash: evaluation.auditHash,\n });\n }\n\n // 2. Extract environment, compute execution_hash, verify permit.\n const environment = request.context?.environment as string | undefined;\n if (!environment) {\n throw new AtlaSentError(\n 'context.environment is required. Pass the environment where this action executes (e.g. \"production\", \"staging\").',\n { code: \"bad_request\" },\n );\n }\n\n const evaluatePayload = {\n action_type: request.action,\n actor_id: request.agent,\n context: request.context ?? {},\n };\n const execution_hash = await computeExecutionHash(evaluatePayload);\n\n const verifyRequest: {\n permitId: string;\n agent: string;\n action: string;\n context?: Record<string, unknown>;\n environment: string;\n execution_hash?: string;\n } = {\n permitId: evaluation.permitId,\n agent: request.agent,\n action: request.action,\n environment,\n ...(execution_hash ? { execution_hash } : {}),\n };\n if (request.context !== undefined) verifyRequest.context = request.context;\n const verification = await client.verifyPermit(verifyRequest);\n\n if (!verification.verified) {\n const outcome = normalizePermitOutcome(verification.outcome);\n throw new AtlaSentDeniedError({\n decision: \"deny\",\n evaluationId: evaluation.permitId,\n reason: `Permit failed verification (${verification.outcome})`,\n auditHash: evaluation.auditHash,\n ...(outcome !== undefined && { outcome }),\n });\n }\n\n // 3. Build the receipt.\n const contextHash = await computeContextHash(request.context ?? {});\n\n const whyTrace = buildWhyTrace(\n \"allow\",\n evaluation.reasons,\n opts.constraintTrace ?? null,\n );\n\n const issuedAt = new Date().toISOString();\n const receiptId = generateReceiptId();\n const orgId = evaluation.permit?.orgId ?? \"\";\n\n const payload = buildDecisionReceiptPayload({\n receipt_id: receiptId,\n evaluation_id: evaluation.evaluationId,\n org_id: orgId,\n decision: \"allow\",\n action: request.action,\n actor: request.agent,\n resource_type:\n (request.context?.resource_type as string | undefined) ?? null,\n resource_id:\n (request.context?.resource_id as string | undefined) ?? null,\n reasons: evaluation.reasons,\n why_summary: whyTrace.summary,\n permit_id: evaluation.permitId,\n permit_hash: verification.permitHash,\n audit_hash: evaluation.auditHash,\n context_hash: contextHash,\n issued_at: issuedAt,\n });\n\n // 4. Sign if secret is provided.\n let signature: string | null = null;\n let algorithm: DecisionReceiptAlgorithm = \"none\";\n\n if (opts.signingSecret) {\n signature = await signDecisionReceiptHmac(payload, opts.signingSecret);\n algorithm = \"hmac-sha256\";\n }\n\n const receipt: DecisionReceipt = {\n receipt_id: receiptId,\n evaluation_id: evaluation.evaluationId,\n org_id: orgId,\n decision: \"allow\",\n action: request.action,\n actor: request.agent,\n resource_type:\n (request.context?.resource_type as string | undefined) ?? null,\n resource_id:\n (request.context?.resource_id as string | undefined) ?? null,\n reasons: evaluation.reasons,\n why_trace:\n opts.constraintTrace !== undefined ? whyTrace : null,\n permit_id: evaluation.permitId,\n permit_hash: verification.permitHash,\n audit_hash: evaluation.auditHash,\n context_hash: contextHash,\n issued_at: issuedAt,\n expires_at: null,\n algorithm,\n signature,\n signing_key_id: opts.signingKeyId ?? null,\n payload,\n };\n\n return {\n permitId: evaluation.permitId,\n permitHash: verification.permitHash,\n auditHash: evaluation.auditHash,\n reason: evaluation.reason,\n timestamp: verification.timestamp,\n permitExpiresAt: verification.expiresAt ?? null,\n receipt,\n };\n}\n","/**\n * Hono middleware for AtlaSent execution-time authorization.\n *\n * ```ts\n * import { Hono } from \"hono\";\n * import { atlaSentGuard, atlaSentErrorHandler } from \"@atlasent/sdk/hono\";\n *\n * const app = new Hono();\n *\n * // One-line drop-in protection for a sensitive route.\n * app.post(\n * \"/deploy\",\n * atlaSentGuard({\n * action: \"production.deploy\",\n * agent: (c) => c.req.header(\"x-agent-id\") ?? \"anonymous\",\n * context: async (c) => ({ commit: (await c.req.json()).commit }),\n * }),\n * (c) => {\n * // If we got here, AtlaSent allowed the action end-to-end.\n * const permit = c.get(\"atlasent\");\n * return c.json({ ok: true, permitId: permit.permitId });\n * },\n * );\n *\n * // One place to map AtlaSent errors to HTTP responses.\n * app.onError(atlaSentErrorHandler());\n * ```\n *\n * The guard calls {@link protect} under the hood — same fail-closed\n * semantics. On allow, it stashes the {@link Permit} on the Hono\n * context (default key: `\"atlasent\"`) and calls `next()`. On anything\n * else, it **throws**: {@link AtlaSentDeniedError} for policy denials\n * and verification failures, {@link AtlaSentError} for transport /\n * auth / server failures. Attach {@link atlaSentErrorHandler} via\n * `app.onError(...)` to turn those into HTTP responses once, at the\n * app level, rather than wrap every guarded route.\n *\n * `hono` is an optional peer dependency — this module is only pulled\n * in when you import from the `@atlasent/sdk/hono` subpath.\n */\n\nimport type { Context, ErrorHandler, MiddlewareHandler } from \"hono\";\n\nimport { AtlaSentDeniedError, AtlaSentError } from \"./errors.js\";\nimport { protect, type Permit, type ProtectRequest } from \"./protect.js\";\n\n/** Resolver: a literal string, or a function deriving one from the request. */\ntype Resolver<T extends string | Record<string, unknown>> =\n | T\n | ((c: Context) => T | Promise<T>);\n\n/** Options for {@link atlaSentGuard}. */\nexport interface AtlaSentGuardOptions {\n /**\n * Action being authorized (e.g. `\"production.deploy\"`). A string\n * fixes the action; a function lets you derive it per-request (e.g.\n * from route params or the HTTP verb).\n */\n action: Resolver<string>;\n /**\n * Agent identifier. A string fixes the caller; a function lets you\n * read it from an auth header, JWT claim, session, etc.\n */\n agent: Resolver<string>;\n /**\n * Build the policy context dict for the decision. Defaults to `{}`.\n * Receives the Hono context so you can reach into headers, body,\n * route params, or previously-set middleware values.\n */\n context?: (\n c: Context,\n ) => Record<string, unknown> | Promise<Record<string, unknown>>;\n /**\n * Key used to stash the resulting {@link Permit} on the Hono\n * context via `c.set(...)`. Callers read it back with\n * `c.get(options.key)`. Default: `\"atlasent\"`.\n */\n key?: string;\n}\n\nconst DEFAULT_CONTEXT_KEY = \"atlasent\";\n\nasync function resolve<T>(\n value: T | ((c: Context) => T | Promise<T>),\n c: Context,\n): Promise<T> {\n return typeof value === \"function\"\n ? await (value as (c: Context) => T | Promise<T>)(c)\n : value;\n}\n\n/**\n * Hono middleware that calls {@link protect} before the wrapped\n * handler runs. On allow, stores the {@link Permit} on the context;\n * on deny or error, throws. Use {@link atlaSentErrorHandler} with\n * `app.onError(...)` to turn those throws into HTTP responses.\n */\nexport function atlaSentGuard(\n options: AtlaSentGuardOptions,\n): MiddlewareHandler {\n const contextKey = options.key ?? DEFAULT_CONTEXT_KEY;\n return async (c, next) => {\n const [agent, action, ctx] = await Promise.all([\n resolve(options.agent, c),\n resolve(options.action, c),\n options.context ? options.context(c) : Promise.resolve(undefined),\n ]);\n\n const request: ProtectRequest = { agent, action };\n if (ctx !== undefined) request.context = ctx;\n\n const permit: Permit = await protect(request);\n c.set(contextKey, permit);\n await next();\n };\n}\n\n/** Options for {@link atlaSentErrorHandler}. */\nexport interface AtlaSentErrorHandlerOptions {\n /** HTTP status returned on policy denial. Default: 403. */\n denyStatus?: 401 | 403 | 409 | 422;\n /** HTTP status returned on transport / auth / server failure. Default: 503. */\n errorStatus?: 502 | 503 | 500;\n /**\n * Hook to customize the JSON body returned on denial. Receives the\n * error; must return a JSON-serializable object. Defaults to a\n * minimal `{ error, decision, evaluationId, reason?, requestId? }`.\n */\n renderDeny?: (err: AtlaSentDeniedError) => Record<string, unknown>;\n /** Hook for transport/auth/server errors. Defaults to `{ error, code, requestId? }`. */\n renderError?: (err: AtlaSentError) => Record<string, unknown>;\n}\n\nfunction defaultRenderDeny(err: AtlaSentDeniedError): Record<string, unknown> {\n const body: Record<string, unknown> = {\n error: \"denied\",\n decision: err.decision,\n evaluationId: err.evaluationId,\n };\n if (err.reason !== undefined) body.reason = err.reason;\n if (err.requestId !== undefined) body.requestId = err.requestId;\n return body;\n}\n\nfunction defaultRenderError(err: AtlaSentError): Record<string, unknown> {\n const body: Record<string, unknown> = {\n error: \"unavailable\",\n code: err.code ?? \"unknown\",\n };\n if (err.requestId !== undefined) body.requestId = err.requestId;\n return body;\n}\n\n/**\n * Hono error handler that converts AtlaSent exceptions into\n * appropriate HTTP responses. Install once at the app level:\n *\n * ```ts\n * app.onError(atlaSentErrorHandler());\n * ```\n *\n * Non-AtlaSent errors re-throw so other `onError` chains (or Hono's\n * default 500 handler) still see them.\n */\nexport function atlaSentErrorHandler(\n options: AtlaSentErrorHandlerOptions = {},\n): ErrorHandler {\n const denyStatus = options.denyStatus ?? 403;\n const errorStatus = options.errorStatus ?? 503;\n const renderDeny = options.renderDeny ?? defaultRenderDeny;\n const renderError = options.renderError ?? defaultRenderError;\n\n return (err, c) => {\n if (err instanceof AtlaSentDeniedError) {\n return c.json(renderDeny(err), denyStatus);\n }\n if (err instanceof AtlaSentError) {\n return c.json(renderError(err), errorStatus);\n }\n throw err;\n };\n}\n\n// Re-export the types callers need in one place so the subpath is\n// self-contained.\nexport type { Permit, ProtectRequest } from \"./protect.js\";\nexport { AtlaSentDeniedError, AtlaSentError } from \"./errors.js\";\n"],"mappings":"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","names":["isNode","varianceKind","resolve","resolve"]}