@canopy-io/node 0.1.1 → 0.2.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/pagination.ts","../src/resources/assignments.ts","../src/resources/identities.ts","../src/schema.ts","../src/resources/permissions.ts","../src/resources/roles.ts","../src/canopy.ts","../src/authorizer.ts","../src/verify.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Everything this client throws.\n *\n * Three classes, because callers act on the distinction: `CanopyError` means\n * the API answered and said no, `CanopyConnectionError` means it never\n * answered, and `CanopyTokenError` means a token failed local verification\n * without anything being asked of the API at all. The first is a decision you\n * may need to surface to a user; the second is usually worth retrying or\n * alerting on; the third is a 401 for the caller who presented the token.\n */\n\n/** The `error` object inside Canopy's error envelope. */\nexport interface CanopyErrorBody {\n statusCode: number;\n /**\n * Stable machine-readable code, e.g. `rbac.assignment_conflict`. Null on\n * framework-level failures such as a validation 400, where `details` carries\n * the specifics instead.\n */\n code: string | null;\n message: string;\n timestamp?: string;\n path?: string;\n method?: string;\n /** Field-level validation messages, present on a 400. */\n details?: string[];\n /** Structured payload for specific codes — a version conflict carries the current row. */\n data?: unknown;\n}\n\n/**\n * The API returned a non-2xx response.\n *\n * Branch on `code` rather than `message`: the code is a contract, the message\n * is prose that may be reworded.\n */\nexport class CanopyError extends Error {\n override readonly name = \"CanopyError\";\n readonly statusCode: number;\n readonly code: string | null;\n readonly details: string[] | undefined;\n readonly data: unknown;\n /** The path and method that failed, for logging. */\n readonly request: { method: string; path: string };\n /**\n * How long to wait before retrying, in milliseconds, when the server said so\n * via `Retry-After` — populated on a 429, and on any other response that\n * carries the header. Undefined when the server gave no guidance.\n */\n readonly retryAfterMs: number | undefined;\n\n constructor(\n body: CanopyErrorBody,\n request: { method: string; path: string },\n retryAfterMs?: number,\n ) {\n super(body.message);\n\n this.statusCode = body.statusCode;\n this.code = body.code;\n this.details = body.details;\n this.data = body.data;\n this.request = request;\n this.retryAfterMs = retryAfterMs;\n }\n\n /** A 429. `retryAfterMs` is populated when the server said how long to wait. */\n get isRateLimited(): boolean {\n return this.statusCode === 429;\n }\n\n /** 401 or 403 — the credential is wrong or not permitted here. */\n get isAuthFailure(): boolean {\n return this.statusCode === 401 || this.statusCode === 403;\n }\n}\n\n/**\n * The request never produced a response — DNS failure, connection reset, or a\n * timeout.\n *\n * Not this: a caller's own cancellation. Aborting the `signal` passed to a\n * request rejects with that abort (`AbortError`, or whatever `signal.reason`\n * holds) and is never retried, because the caller stopping is an intent rather\n * than a failure to report.\n *\n * Kept separate from `CanopyError` because there is no status code and no\n * server opinion to report: nothing is known about whether the operation\n * happened, which matters for anything non-idempotent.\n */\nexport class CanopyConnectionError extends Error {\n override readonly name = \"CanopyConnectionError\";\n readonly request: { method: string; path: string };\n\n constructor(\n message: string,\n request: { method: string; path: string },\n options?: { cause?: unknown },\n ) {\n super(message, options);\n\n this.request = request;\n }\n}\n\n/**\n * A token failed verification.\n *\n * Separate from `CanopyError` because nothing was asked of the API: the token\n * was checked here, against keys already held. There is no status code to\n * report and no server opinion to relay — the decision was local, which is the\n * whole point of verifying a signature rather than calling an endpoint.\n *\n * Branch on `code`; it follows the same dot-notation contract as the API's own\n * codes. Every one of them means the same thing to an HTTP caller — 401 — so\n * the code is for your logs and your tests, not usually for the response.\n */\nexport class CanopyTokenError extends Error {\n override readonly name = \"CanopyTokenError\";\n\n /**\n * One of:\n *\n * - `token.malformed` — not a JWS, or a segment would not decode\n * - `token.unsupported_algorithm` — not RS256; Canopy issues only RS256\n * - `token.key_not_found` — no published key matches the token's `kid`\n * - `token.jwks_unavailable` — the key set could not be fetched or parsed\n * - `token.signature_invalid` — signature does not match the signing key\n * - `token.expired` / `token.not_yet_valid` — outside its validity window\n * - `token.issuer_mismatch` — `iss` is not the configured issuer\n * - `token.audience_mismatch` — `aud` does not include the configured audience\n * - `token.audience_unverified` — token has an `aud` but none was configured\n * - `token.preauth_not_allowed` — a pre-auth token, which grants no access\n */\n readonly code: string;\n\n constructor(code: string, message: string, options?: { cause?: unknown }) {\n super(message, options);\n\n this.code = code;\n }\n}\n\n/**\n * The local authorizer could not answer, and must not pretend otherwise.\n *\n * Distinct from a denial. It is raised when the data a decision needs is not\n * merely absent but *unreadable* — most often a credential that cannot read the\n * hierarchy, which comes back as an empty tree rather than an error. Denying\n * there would be a silent, total false-deny on every node-scoped route while\n * every response still looked healthy.\n *\n * No retry fixes it, so callers should treat it as a misconfiguration rather\n * than an outage.\n */\nexport class CanopyAuthorizerError extends Error {\n override readonly name = \"CanopyAuthorizerError\";\n readonly code: string;\n\n constructor(code: string, message: string, options?: { cause?: unknown }) {\n super(message, options);\n\n this.code = code;\n }\n}\n\nexport function isCanopyAuthorizerError(\n error: unknown,\n): error is CanopyAuthorizerError {\n return error instanceof Error && error.name === \"CanopyAuthorizerError\";\n}\n\n/** Narrowing helper that survives bundling and duplicate copies of the package. */\nexport function isCanopyError(error: unknown): error is CanopyError {\n return error instanceof Error && error.name === \"CanopyError\";\n}\n\nexport function isCanopyConnectionError(\n error: unknown,\n): error is CanopyConnectionError {\n return error instanceof Error && error.name === \"CanopyConnectionError\";\n}\n\nexport function isCanopyTokenError(error: unknown): error is CanopyTokenError {\n return error instanceof Error && error.name === \"CanopyTokenError\";\n}\n","import {\n CanopyConnectionError,\n CanopyError,\n type CanopyErrorBody,\n} from \"./errors.js\";\n\n/**\n * Offset pagination — the default across the API.\n */\nexport interface OffsetPagination {\n page: number;\n take: number;\n item_count: number;\n page_count: number;\n has_previous_page: boolean;\n has_next_page: boolean;\n}\n\n/**\n * Cursor pagination — used by append-heavy feeds (the audit log) where an\n * offset window drifts under concurrent writes.\n *\n * The envelope is identical to the offset case; only this object differs,\n * which is precisely why hand-written pagination loops break on one of them.\n */\nexport interface CursorPagination {\n next_cursor: string | null;\n}\n\nexport type Pagination = OffsetPagination | CursorPagination;\n\nexport function isCursorPagination(\n pagination: Pagination,\n): pagination is CursorPagination {\n return \"next_cursor\" in pagination;\n}\n\n/** A collection response, paginated or not. */\n/**\n * The answer to a conditional read.\n *\n * A discriminated union rather than an optional body, so a caller cannot\n * mistake \"nothing changed\" for \"changed to nothing\" — the two are opposite\n * instructions to whatever is holding the cached copy.\n */\nexport type ConditionalResult<T> =\n { modified: true; data: T; etag: string | null } | { modified: false };\n\nexport interface Collection<T> {\n items: T[];\n pagination?: Pagination;\n}\n\n/** A 207 partial-success response from a bulk endpoint. */\nexport interface PartialSuccess<T> {\n summary: { total: number; succeeded: number; failed: number };\n results: {\n index: number;\n status: \"success\" | \"error\";\n code: number;\n data?: T;\n input?: unknown;\n error?: { code: string | null; message: string };\n }[];\n}\n\nexport interface CanopyClientOptions {\n /**\n * Server-to-server credential (`cnpy_…`), sent as `X-API-Key`. Never ship\n * one to a browser: it carries whatever scopes it was issued with.\n */\n apiKey?: string;\n /** Identity or portal JWT, sent as `Authorization: Bearer`. */\n accessToken?: string;\n /** Defaults to Canopy's hosted API. Set this for a self-hosted instance. */\n baseUrl?: string;\n /** Per-attempt deadline. Defaults to 30s; 0 disables. */\n timeoutMs?: number;\n /** Retries after the first attempt. Defaults to 2. */\n maxRetries?: number;\n /**\n * Ceiling on a single wait between attempts. Defaults to 30s.\n *\n * The server's `Retry-After` is honoured up to this, then clamped. Without a\n * cap the wait is whatever a response header asks for, which sits outside\n * `timeoutMs` and can hold a caller far longer than its own budget allows.\n */\n maxBackoffMs?: number;\n /** Extra headers on every request. */\n headers?: Record<string, string>;\n /** Injectable for tests and for runtimes with a non-global fetch. */\n fetch?: typeof globalThis.fetch;\n}\n\nexport interface RequestOptions {\n query?: Record<string, string | number | boolean | undefined | null>;\n body?: unknown;\n signal?: AbortSignal;\n /**\n * Per-attempt deadline for this call only, overriding the client-wide\n * `timeoutMs`. 0 disables it.\n *\n * The client-wide default suits administrative CRUD. A latency-critical call\n * on a request path — an authorization check on every inbound request — wants\n * a much tighter one, because the total time at risk is this deadline times\n * the attempts, and it is spent holding an inbound request open.\n */\n timeoutMs?: number;\n /**\n * Retries after the first attempt for this call only, overriding the\n * client-wide `maxRetries`. 0 disables retrying.\n *\n * Set this together with `timeoutMs` when a call needs a bounded worst case:\n * the two multiply. A deadline alone still permits `maxRetries + 1` of them\n * back to back, which is the difference between a slow call and a request\n * held open long past the point the answer was useful.\n */\n maxRetries?: number;\n /**\n * Ceiling on a single wait between attempts, for this call only.\n *\n * Set it alongside `timeoutMs` and `maxRetries` when a call needs a real\n * worst case: the deadline bounds an attempt, `maxRetries` bounds how many,\n * and this bounds the waiting in between — which a server's `Retry-After`\n * would otherwise control.\n */\n maxBackoffMs?: number;\n /**\n * Headers for this call only, overriding the client-wide `headers`.\n *\n * This is how the per-request protocol headers are sent: `If-Match`, carrying\n * a resource's current `version` for optimistic concurrency (a stale value\n * answers 409), and `Idempotency-Key`, which makes a replayed bulk create\n * return the original result instead of creating rows twice.\n *\n * The credential is not overridable this way — auth is settled by the client.\n */\n headers?: Record<string, string>;\n /**\n * Declares this call safe to repeat, which allows retrying a 5xx.\n *\n * Needed because the generated types carry no idempotency marker, so the\n * spec cannot drive this. GET, HEAD, PUT and DELETE are treated as\n * idempotent by HTTP definition; POST is not, and a blind retry there can\n * create a second role assignment or a second invitation.\n *\n * Set it where a POST is a read in disguise — the permission evaluations\n * take a body and so must be POSTs, but they compute an answer and write\n * nothing. Do not set it on anything that creates.\n */\n idempotent?: boolean;\n}\n\n/**\n * The per-call knobs a resource method accepts.\n *\n * Deliberately excludes `body` and `query`, which the method itself owns, and\n * `idempotent`, which is a property of the endpoint rather than the call site.\n */\nexport type CallOptions = Pick<\n RequestOptions,\n \"signal\" | \"timeoutMs\" | \"maxRetries\" | \"maxBackoffMs\" | \"headers\"\n>;\n\nconst DEFAULT_BASE_URL = \"https://auth.canopy-io.com\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst DEFAULT_MAX_BACKOFF_MS = 30_000;\n\n/** Idempotent by HTTP definition (RFC 9110 §9.2.2). */\nconst IDEMPOTENT_METHODS = new Set([\"GET\", \"HEAD\", \"PUT\", \"DELETE\"]);\n\n/** `304`. A success for a conditional read, and not a 2xx. */\nconst NOT_MODIFIED = 304;\n\n/**\n * The transport every resource is built on: one place that knows how to\n * authenticate, unwrap Canopy's response envelope, turn a failure into a typed\n * error, and decide whether repeating a request is safe.\n *\n * Deliberately dependency-free — `fetch` only — so the same client runs on\n * Node 18+, in browsers, on Workers and on Deno.\n */\nexport class CanopyClient {\n private readonly baseUrl: string;\n private readonly timeoutMs: number;\n private readonly maxRetries: number;\n private readonly maxBackoffMs: number;\n private readonly authHeaders: Record<string, string>;\n private readonly extraHeaders: Record<string, string>;\n private readonly fetchImpl: typeof globalThis.fetch;\n\n constructor(options: CanopyClientOptions = {}) {\n if (!options.apiKey && !options.accessToken) {\n throw new TypeError(\n \"CanopyClient requires either `apiKey` (server-to-server) or `accessToken` (a user or identity JWT).\",\n );\n }\n\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.maxBackoffMs = options.maxBackoffMs ?? DEFAULT_MAX_BACKOFF_MS;\n this.extraHeaders = options.headers ?? {};\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n\n if (typeof this.fetchImpl !== \"function\") {\n throw new TypeError(\n \"No `fetch` available. Node 18+ provides one; on older runtimes pass `fetch` explicitly.\",\n );\n }\n\n this.authHeaders = options.apiKey\n ? { \"X-API-Key\": options.apiKey }\n : { Authorization: `Bearer ${options.accessToken ?? \"\"}` };\n }\n\n /**\n * Issue a request and return the payload with the envelope removed.\n *\n * `{ data }` → the resource\n * `{ items, pagination }` → the whole object, so pagination survives\n * `{ summary, results }` → the whole object\n * 204 → undefined\n *\n * Non-2xx throws `CanopyError`; a request that never completed throws\n * `CanopyConnectionError`.\n */\n async request<T>(\n method: string,\n path: string,\n options: RequestOptions = {},\n ): Promise<T> {\n const response = await this.perform(method, path, options);\n\n return this.unwrap<T>(response, method.toUpperCase(), path);\n }\n\n /**\n * A conditional read: send the validator you already hold, and find out\n * whether anything changed.\n *\n * The sibling of `If-Match`, which this client already sends for optimistic\n * concurrency. `304 Not Modified` is a *success* — it means the copy you\n * have is current — but it is not a 2xx, so `request` would raise it as an\n * error. Hence a separate entry point with a return type that says which\n * happened rather than one that has to be inspected.\n *\n * Use it to hold something expensive and revalidate cheaply — the hierarchy\n * behind local authorization is the case this exists for.\n */\n async requestConditional<T>(\n method: string,\n path: string,\n etag: string | undefined,\n options: RequestOptions = {},\n ): Promise<ConditionalResult<T>> {\n const conditional: RequestOptions = etag\n ? { ...options, headers: { ...options.headers, \"If-None-Match\": etag } }\n : options;\n\n const response = await this.perform(\n method,\n path,\n conditional,\n (status) => status === NOT_MODIFIED || (status >= 200 && status < 300),\n );\n\n if (response.status === NOT_MODIFIED) {\n return { modified: false };\n }\n\n return {\n modified: true,\n data: await this.unwrap<T>(response, method.toUpperCase(), path),\n etag: response.headers.get(\"etag\"),\n };\n }\n\n /**\n * Everything up to the response: retries, backoff, cancellation and the\n * status check, without deciding what the body means.\n *\n * Split out so a conditional read can accept `304` where an ordinary one\n * must not, rather than either duplicating the retry policy or teaching\n * `unwrap` about statuses that carry no body.\n */\n private async perform(\n method: string,\n path: string,\n options: RequestOptions = {},\n accept: (status: number) => boolean = (status) =>\n status >= 200 && status < 300,\n ): Promise<Response> {\n const url = this.buildUrl(path, options.query);\n const upper = method.toUpperCase();\n const retryable = options.idempotent ?? IDEMPOTENT_METHODS.has(upper);\n const maxRetries = options.maxRetries ?? this.maxRetries;\n const maxBackoffMs = options.maxBackoffMs ?? this.maxBackoffMs;\n\n // Cancelled before it began: never reach the network at all. Relying on\n // `fetch` to reject an aborted signal would still cost the call.\n throwIfAborted(options.signal);\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n await delay(\n backoffMs(attempt, lastError, maxBackoffMs),\n options.signal,\n );\n\n // Abort during the backoff window: stop here rather than spending an\n // attempt on a request the caller no longer wants.\n throwIfAborted(options.signal);\n }\n\n try {\n const response = await this.send(upper, url, options);\n\n if (this.shouldRetry(response.status, retryable, attempt, maxRetries)) {\n lastError = await this.toError(response, upper, path);\n continue;\n }\n\n if (!accept(response.status)) {\n throw await this.toError(response, upper, path);\n }\n\n return response;\n } catch (error) {\n // A typed API error is the server's answer, not a transport problem —\n // it is never retried here, only by the branch above.\n if (error instanceof CanopyError) {\n throw error;\n }\n\n lastError = error;\n\n // A caller's abort is a deliberate cancellation, not a transport\n // hiccup: never retry it, and surface the abort itself rather than a\n // generic connection error. The per-attempt timeout uses a separate\n // internal controller, so `options.signal` is aborted only when the\n // caller asked to stop — a timeout still falls through to the retry\n // logic below.\n throwIfAborted(options.signal);\n\n // Nothing is known about whether a non-idempotent request took effect,\n // so it must not be repeated.\n if (!retryable || attempt === maxRetries) {\n throw new CanopyConnectionError(\n `${upper} ${path} failed: ${describe(error)}`,\n { method: upper, path },\n { cause: error },\n );\n }\n }\n }\n\n // Loop exits only via return or throw; this satisfies the type checker and\n // would indicate a logic error if it were ever reached.\n throw new CanopyConnectionError(\n `${upper} ${path} exhausted ${maxRetries + 1} attempts`,\n { method: upper, path },\n { cause: lastError },\n );\n }\n\n private shouldRetry(\n status: number,\n retryable: boolean,\n attempt: number,\n maxRetries: number,\n ): boolean {\n if (attempt >= maxRetries) {\n return false;\n }\n\n // 429 means the request was refused before doing anything, so repeating it\n // is safe regardless of method.\n if (status === 429) {\n return true;\n }\n\n return status >= 500 && retryable;\n }\n\n private async send(\n method: string,\n url: string,\n options: RequestOptions,\n ): Promise<Response> {\n const controller = new AbortController();\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const timer =\n timeoutMs > 0\n ? setTimeout(() => controller.abort(), timeoutMs)\n : undefined;\n\n // Forward a caller's abort without requiring AbortSignal.any, which is not\n // available on every runtime this package supports. A signal that is\n // already aborted would never re-fire the event, so honour it up front.\n const onAbort = () => controller.abort();\n\n if (options.signal?.aborted) {\n controller.abort();\n }\n\n options.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n ...this.extraHeaders,\n };\n\n if (options.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n // Per-request headers beat the client-wide defaults, but the credential is\n // applied last so no call site can accidentally send a different one.\n Object.assign(headers, options.headers, this.authHeaders);\n\n // Built conditionally rather than passing `body: undefined`, which\n // `exactOptionalPropertyTypes` rejects and which some runtimes treat as a\n // body on GET.\n const init: RequestInit = { method, headers, signal: controller.signal };\n\n if (options.body !== undefined) {\n init.body = JSON.stringify(options.body);\n }\n\n try {\n return await this.fetchImpl(url, init);\n } finally {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n\n options.signal?.removeEventListener(\"abort\", onAbort);\n }\n }\n\n private buildUrl(path: string, query: RequestOptions[\"query\"]): string {\n const url = new URL(\n path.startsWith(\"/\") ? path : `/${path}`,\n `${this.baseUrl}/`,\n );\n\n for (const [key, value] of Object.entries(query ?? {})) {\n // Absent and null are both \"no filter\" — sending `?take=null` would be\n // a validation error rather than a default.\n if (value === undefined || value === null) {\n continue;\n }\n\n url.searchParams.set(key, String(value));\n }\n\n return url.toString();\n }\n\n private async unwrap<T>(\n response: Response,\n method: string,\n path: string,\n ): Promise<T> {\n if (response.status === 204) {\n return undefined as T;\n }\n\n const text = await response.text();\n\n if (text === \"\") {\n return undefined as T;\n }\n\n let parsed: Record<string, unknown>;\n\n try {\n parsed = JSON.parse(text) as Record<string, unknown>;\n } catch {\n // A 2xx with a body that is not JSON — usually a proxy or gateway that\n // answered instead of the API. The connection succeeded, so this is not a\n // CanopyConnectionError; report it as the malformed API response it is.\n throw new CanopyError(\n {\n statusCode: response.status,\n code: null,\n message: `${method} ${path} returned ${response.status} with a body that is not JSON.`,\n },\n { method, path },\n );\n }\n\n // `{ data }` is the single-resource envelope; everything else is returned\n // whole, because its extra keys (pagination, summary) are the point.\n if (parsed && typeof parsed === \"object\" && \"data\" in parsed) {\n return parsed[\"data\"] as T;\n }\n\n return parsed as T;\n }\n\n private async toError(\n response: Response,\n method: string,\n path: string,\n ): Promise<CanopyError> {\n const retryAfter = parseRetryAfter(response.headers.get(\"retry-after\"));\n let body: CanopyErrorBody = {\n statusCode: response.status,\n code: null,\n message: `${response.status} ${response.statusText}`.trim(),\n };\n\n try {\n const parsed = JSON.parse(await response.text()) as {\n error?: CanopyErrorBody;\n };\n\n if (parsed.error) {\n body = {\n ...parsed.error,\n statusCode: parsed.error.statusCode ?? response.status,\n };\n }\n } catch {\n // A non-JSON body (a proxy's HTML error page) leaves the status-derived\n // message above, which is more useful than the raw markup.\n }\n\n return new CanopyError(body, { method, path }, retryAfter ?? undefined);\n }\n}\n\n/** `Retry-After` is either seconds or an HTTP date. */\nfunction parseRetryAfter(header: string | null): number | null {\n if (!header) {\n return null;\n }\n\n const seconds = Number(header);\n\n if (Number.isFinite(seconds)) {\n return Math.max(0, seconds * 1000);\n }\n\n const date = Date.parse(header);\n\n if (Number.isNaN(date)) {\n return null;\n }\n\n return Math.max(0, date - Date.now());\n}\n\n/**\n * Exponential backoff with jitter, but the server's own `Retry-After` wins —\n * it knows when the window resets and we are guessing.\n *\n * Jitter matters when many workers hit the same limit at once: without it they\n * all wake together and rate-limit each other again.\n */\nfunction backoffMs(\n attempt: number,\n lastError: unknown,\n maxBackoffMs: number,\n): number {\n const advised =\n lastError && typeof lastError === \"object\" && \"retryAfterMs\" in lastError\n ? Number(lastError.retryAfterMs)\n : NaN;\n\n if (Number.isFinite(advised)) {\n // Capped, because this number comes off a response header and is otherwise\n // unbounded: a `Retry-After: 120` would hold the caller for two minutes,\n // outside any per-attempt deadline. Waiting less than advised risks another\n // 429, which is a retry we are already budgeted for; waiting the full\n // amount risks a request pinned open for as long as the header says.\n return Math.min(advised, maxBackoffMs);\n }\n\n const base = 250 * 2 ** (attempt - 1);\n\n return Math.min(base + Math.random() * base, maxBackoffMs);\n}\n\n/**\n * Stop immediately if the caller has cancelled, surfacing their own reason.\n *\n * `AbortSignal.throwIfAborted` would do this, but it is not available on every\n * runtime this package supports, and neither is a guaranteed `reason`.\n */\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (!signal?.aborted) {\n return;\n }\n\n throw (\n signal.reason ??\n new DOMException(\"This operation was aborted\", \"AbortError\")\n );\n}\n\n/**\n * Wait, but stop early if the caller cancels.\n *\n * A plain timer would hold the wait to completion and only notice the abort\n * afterwards — and with a server-advised `Retry-After` that wait can be far\n * longer than any per-attempt deadline, so \"cancelled\" would mean \"cancelled,\n * in a minute\". Resolving early lets the caller's abort be observed at once;\n * the throw itself stays with `throwIfAborted`.\n */\nfunction delay(ms: number, signal: AbortSignal | undefined): Promise<void> {\n if (signal?.aborted) {\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n // Held in one object because a timer implementation may invoke its callback\n // synchronously — a test double often does. `finish` would then run before\n // the handle exists, so it reads the handle through `state` rather than\n // closing over a binding that is not assigned yet, and `settled` keeps the\n // abort listener from outliving a wait that already finished.\n const state: {\n timer?: ReturnType<typeof setTimeout>;\n settled: boolean;\n } = { settled: false };\n\n const finish = () => {\n if (state.settled) {\n return;\n }\n\n state.settled = true;\n\n if (state.timer !== undefined) {\n clearTimeout(state.timer);\n }\n\n signal?.removeEventListener(\"abort\", finish);\n resolve();\n };\n\n state.timer = setTimeout(finish, ms);\n\n if (!state.settled) {\n signal?.addEventListener(\"abort\", finish, { once: true });\n }\n });\n}\n\nfunction describe(error: unknown): string {\n if (error instanceof Error) {\n // A caller's abort is rethrown before it reaches here, so an AbortError at\n // this point came from the per-attempt timeout.\n return error.name === \"AbortError\" ? \"timed out\" : error.message;\n }\n\n return String(error);\n}\n","import { type Collection, isCursorPagination } from \"./client.js\";\n\n/** Query parameters for one page request. */\nexport type PageParams = Record<\n string,\n string | number | boolean | undefined | null\n>;\n\n/** Fetches a single page. Supplied by each resource. */\nexport type PageFetcher<T> = (params: PageParams) => Promise<Collection<T>>;\n\nexport interface PaginateOptions {\n /** Stop after this many pages. Guards against a server that never ends. */\n maxPages?: number;\n}\n\nconst DEFAULT_MAX_PAGES = 1_000;\n\n/**\n * Walks a paginated endpoint without the caller knowing which pagination style\n * it uses.\n *\n * This exists because the two styles are indistinguishable at the top level:\n * both answer `{ items, pagination }`. Offset carries\n * `page`/`has_next_page`; cursor carries `next_cursor`. The audit log is\n * cursor-paginated and everything else is offset, so a hand-written loop works\n * against one and silently reads only the first page of the other — or loops\n * forever.\n *\n * The style is inferred from the first response rather than declared, so a\n * resource does not have to restate what the server already says. Only the\n * cursor or page parameter is managed here; page size stays whatever the\n * caller passed, because the two styles even name that differently (`take` for\n * offset, `limit` for the cursor feeds).\n */\nexport class Paginator<T> implements AsyncIterable<T> {\n private readonly fetchPage: PageFetcher<T>;\n private readonly initial: PageParams;\n private readonly maxPages: number;\n\n constructor(\n fetchPage: PageFetcher<T>,\n initial: PageParams = {},\n options: PaginateOptions = {},\n ) {\n this.fetchPage = fetchPage;\n this.initial = initial;\n this.maxPages = options.maxPages ?? DEFAULT_MAX_PAGES;\n }\n\n /** Every item across every page. */\n async *[Symbol.asyncIterator](): AsyncIterator<T> {\n for await (const page of this.pages()) {\n for (const item of page.items) {\n yield item;\n }\n }\n }\n\n /**\n * Page by page, for callers that need the pagination metadata or want to\n * process in batches rather than item by item.\n */\n async *pages(): AsyncGenerator<Collection<T>> {\n let params: PageParams = { ...this.initial };\n let seenCursor: string | null = null;\n let pageCount = 0;\n\n for (;;) {\n const page = await this.fetchPage(params);\n\n pageCount++;\n\n yield page;\n\n const pagination = page.pagination;\n\n // No pagination object at all: an unpaginated `{ items }` collection.\n if (!pagination) {\n return;\n }\n\n // A server that keeps promising more while returning nothing would spin\n // forever; the empty page is the honest end of the feed.\n if (page.items.length === 0) {\n return;\n }\n\n if (pageCount >= this.maxPages) {\n return;\n }\n\n if (isCursorPagination(pagination)) {\n const next = pagination.next_cursor;\n\n if (next === null || next === seenCursor) {\n // Null is the documented end. An unchanged cursor means the server\n // is not advancing, which would otherwise be an infinite loop.\n return;\n }\n\n seenCursor = next;\n params = { ...params, cursor: next };\n\n continue;\n }\n\n if (!pagination.has_next_page) {\n return;\n }\n\n params = { ...params, page: pagination.page + 1 };\n }\n }\n\n /**\n * Collect everything into an array.\n *\n * Bounded on purpose: an unbounded drain of an audit log will exhaust memory\n * on a busy account, so the cap is a parameter rather than a footnote. Use\n * the iterator for large feeds.\n */\n async all(max = 10_000): Promise<T[]> {\n const collected: T[] = [];\n\n for await (const item of this) {\n collected.push(item);\n\n if (collected.length >= max) {\n break;\n }\n }\n\n return collected;\n }\n\n /** The first item, or undefined. Stops after one page. */\n async first(): Promise<T | undefined> {\n for await (const item of this) {\n return item;\n }\n\n return undefined;\n }\n}\n\n/** Convenience wrapper so resources read as `paginate(fetch, params)`. */\nexport function paginate<T>(\n fetchPage: PageFetcher<T>,\n initial: PageParams = {},\n options: PaginateOptions = {},\n): Paginator<T> {\n return new Paginator(fetchPage, initial, options);\n}\n","import type { CanopyClient } from \"../client.js\";\nimport { paginate, type Paginator } from \"../pagination.js\";\nimport type { QueryParams, RequestBody, ResponseBody } from \"../schema.js\";\n\n/**\n * Role grants: which identity holds which role, at which node.\n *\n * A grant at a node applies to every descendant, which is what makes one\n * assignment cover a whole branch.\n */\nexport class Assignments {\n constructor(private readonly client: CanopyClient) {}\n\n /** Every assignment in the Application, across all nodes. */\n list(\n query: QueryParams<\"ApiAssignmentsController_listAppWideAssignments\"> = {},\n ): Paginator<AssignmentItem> {\n return paginate<AssignmentItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/assignments/app-wide\", {\n query: params,\n }),\n { ...query },\n );\n }\n\n /**\n * Grant a role at a node.\n *\n * Not retried automatically on a 5xx: a repeat could create a second grant,\n * and the server cannot tell the two apart. If the call fails without an\n * answer, read the current assignments before retrying.\n */\n create(\n input: RequestBody<\"ApiAssignmentsController_assignRole\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_assignRole\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments\", { body: input });\n }\n\n update(\n id: string,\n input: RequestBody<\"ApiAssignmentsController_updateAssignment\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_updateAssignment\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/assignments/${encodeURIComponent(id)}`,\n { body: input },\n );\n }\n\n delete(id: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/assignments/${encodeURIComponent(id)}`,\n );\n }\n\n /**\n * Grant many at once. Answers 207 with a per-item result rather than failing\n * the batch, so inspect `results` — a 2xx here does not mean every grant\n * succeeded.\n */\n bulkCreate(\n input: RequestBody<\"ApiAssignmentsController_bulkCreate\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_bulkCreate\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments/bulk-create\", {\n body: input,\n });\n }\n\n /** Same partial-success contract as `bulkCreate`. */\n bulkRemove(\n input: RequestBody<\"ApiAssignmentsController_bulkRemove\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_bulkRemove\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments/bulk-remove\", {\n body: input,\n });\n }\n\n /** Same partial-success contract as `bulkCreate`. */\n bulkChangeRole(\n input: RequestBody<\"ApiAssignmentsController_bulkChangeRole\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_bulkChangeRole\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments/bulk-change-role\", {\n body: input,\n });\n }\n}\n\nexport type AssignmentItem = ItemOf<\n ResponseBody<\"ApiAssignmentsController_listAppWideAssignments\">\n>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n","import type { CanopyClient } from \"../client.js\";\nimport { paginate, type Paginator } from \"../pagination.js\";\nimport type { QueryParams, RequestBody, ResponseBody } from \"../schema.js\";\n\n/** The end users of your application. */\nexport class Identities {\n constructor(private readonly client: CanopyClient) {}\n\n list(\n query: QueryParams<\"ApiIdentitiesController_listIdentities\"> = {},\n ): Paginator<IdentityItem> {\n return paginate<IdentityItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/identities\", { query: params }),\n { ...query },\n );\n }\n\n get(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_getIdentity\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}`,\n );\n }\n\n create(\n input: RequestBody<\"ApiIdentitiesController_createIdentity\">,\n ): Promise<ResponseBody<\"ApiIdentitiesController_createIdentity\">> {\n return this.client.request(\"POST\", \"/api/v1/identities\", { body: input });\n }\n\n update(\n id: string,\n input: RequestBody<\"ApiIdentitiesController_updateIdentity\">,\n ): Promise<ResponseBody<\"ApiIdentitiesController_updateIdentity\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/identities/${encodeURIComponent(id)}`,\n { body: input },\n );\n }\n\n delete(id: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/identities/${encodeURIComponent(id)}`,\n );\n }\n\n /**\n * Deactivation is the reversible counterpart to `delete` — sessions are\n * revoked and sign-in refused, but the identity and its assignments survive.\n * Prefer it for offboarding you may need to undo.\n */\n deactivate(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_deactivateIdentity\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/identities/${encodeURIComponent(id)}/deactivate`,\n );\n }\n\n activate(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_activateIdentity\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/identities/${encodeURIComponent(id)}/activate`,\n );\n }\n\n /**\n * Every role this identity holds, and where — across all pages.\n *\n * Paginated (20 per page by default), so this returns a `Paginator` rather\n * than one response. Reading a single page here would under-report what an\n * identity can do, which is the dangerous direction to be wrong in.\n *\n * ```ts\n * for await (const assignment of canopy.identities.assignments(id)) { … }\n * ```\n */\n assignments(\n id: string,\n query: QueryParams<\"ApiIdentitiesController_getIdentityAssignments\"> = {},\n ): Paginator<IdentityAssignmentItem> {\n return paginate<IdentityAssignmentItem>(\n (params) =>\n this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}/assignments`,\n { query: params },\n ),\n { ...query },\n );\n }\n\n /**\n * The permissions this identity effectively holds, inheritance resolved.\n *\n * For enforcing a single check, use `permissions.evaluate` — it answers one\n * question at the node that matters. This is for showing a person what\n * someone can do.\n */\n permissions(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_getIdentityPermissions\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}/permissions`,\n );\n }\n}\n\nexport type IdentityItem = ItemOf<\n ResponseBody<\"ApiIdentitiesController_listIdentities\">\n>;\n\n/** One role grant from an identity's assignments collection. */\nexport type IdentityAssignmentItem = ItemOf<\n ResponseBody<\"ApiIdentitiesController_getIdentityAssignments\">\n>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n","import type { components, operations } from \"./generated/types.js\";\n\n/**\n * Type plumbing that pulls request and response shapes straight out of the\n * generated operations.\n *\n * Every resource method is typed through these rather than by hand-writing an\n * interface. That is the whole discipline of this package: if the API adds a\n * required field, `npm run generate` brings it in and the call site stops\n * compiling. A hand-written mirror would keep compiling and start lying.\n */\n\n/** Any operation id in the public API. */\nexport type OperationId = keyof operations;\n\n/** The JSON request body an operation accepts, or `never` if it takes none. */\nexport type RequestBody<Id extends OperationId> = operations[Id] extends {\n requestBody: { content: { \"application/json\": infer Body } };\n}\n ? Body\n : operations[Id] extends {\n requestBody?: { content: { \"application/json\": infer Body } };\n }\n ? Body\n : never;\n\n/**\n * The JSON payload of an operation's success response, with Canopy's envelope\n * already removed — `{ data }` unwrapped, collections left whole — matching\n * what `CanopyClient.request` actually returns.\n */\nexport type ResponseBody<Id extends OperationId> = Unwrap<SuccessJson<Id>>;\n\ntype SuccessJson<Id extends OperationId> =\n operations[Id][\"responses\"] extends infer Responses\n ? Responses extends Record<string, unknown>\n ? SuccessOf<Responses>\n : never\n : never;\n\n// 200, 201 and 207 are the success codes this API returns; 204 carries nothing.\ntype SuccessOf<Responses> = Responses extends {\n 200: { content: { \"application/json\": infer Json } };\n}\n ? Json\n : Responses extends { 201: { content: { \"application/json\": infer Json } } }\n ? Json\n : Responses extends { 207: { content: { \"application/json\": infer Json } } }\n ? Json\n : undefined;\n\n/** Mirrors the envelope handling in `CanopyClient.request`. */\ntype Unwrap<Json> = Json extends { data: infer Data } ? Data : Json;\n\n/** Query parameters an operation accepts, when it declares any. */\nexport type QueryParams<Id extends OperationId> = operations[Id] extends {\n parameters: { query?: infer Query };\n}\n ? NonNullable<Query>\n : Record<string, never>;\n\n/** Shorthand for a named schema, e.g. `Schema<\"EvaluateResponseDto\">`. */\nexport type Schema<Name extends keyof components[\"schemas\"]> =\n components[\"schemas\"][Name];\n\n/**\n * Optimistic concurrency, on the operations whose spec declares `If-Match`.\n *\n * Pass the `version` you read off the resource. If someone else has changed it\n * since, the API answers 409 rather than letting the write silently clobber\n * theirs — so this is how a read-modify-write is made safe.\n */\nexport interface ConcurrencyOptions {\n ifMatch?: string;\n}\n\n/**\n * The `If-Match` header for a call that supports it, shaped to be spread into\n * `RequestOptions`.\n *\n * Spreadable rather than returning `headers: undefined`, which\n * `exactOptionalPropertyTypes` rejects — an absent property and one explicitly\n * set to undefined are not the same thing here.\n */\nexport function withConcurrency(\n options: ConcurrencyOptions = {},\n): { headers: Record<string, string> } | Record<string, never> {\n if (options.ifMatch === undefined) {\n return {};\n }\n\n return { headers: { \"If-Match\": options.ifMatch } };\n}\n","import type { CallOptions, CanopyClient } from \"../client.js\";\nimport { paginate, type Paginator } from \"../pagination.js\";\nimport { withConcurrency } from \"../schema.js\";\nimport type {\n ConcurrencyOptions,\n QueryParams,\n RequestBody,\n ResponseBody,\n} from \"../schema.js\";\n\n/**\n * Permissions, and the authorization decision itself.\n *\n * `evaluate` is the call an integrator makes on every request, so it is the one\n * worth reading first.\n */\nexport class Permissions {\n constructor(private readonly client: CanopyClient) {}\n\n /**\n * Ask whether an identity holds a permission.\n *\n * With `scope: \"node\"` the engine walks the node's lineage, so a permission\n * granted on an ancestor is inherited at `node_id`. With `scope: \"app_wide\"`\n * it answers the coarse \"anywhere in this Application\" question and returns\n * `effective_node_id: null` — that answer must never be used to guard a\n * resource that belongs to a specific node, which is why the scope is a\n * required field rather than a default.\n *\n * This runs on the request path, so it is the call most worth passing\n * `signal` and a tight `timeoutMs` to: without them a slow answer here holds\n * an inbound request open for the client-wide deadline on every attempt.\n */\n evaluate(\n input: RequestBody<\"ApiPermissionsController_evaluate\">,\n options: CallOptions = {},\n ): Promise<ResponseBody<\"ApiPermissionsController_evaluate\">> {\n return this.client.request(\"POST\", \"/api/v1/permissions/evaluate\", {\n body: input,\n // A POST only because the question travels in a body; it computes a\n // decision and writes nothing, so repeating it is safe — and this is the\n // call least able to afford giving up on a transient 5xx.\n idempotent: true,\n ...options,\n });\n }\n\n /**\n * Evaluate many decisions in one round trip.\n *\n * Prefer this to a loop over `evaluate` when rendering a screen: the checks\n * are answered together instead of paying request latency for each.\n */\n evaluateBulk(\n input: RequestBody<\"ApiPermissionsController_evaluateBulk\">,\n options: CallOptions = {},\n ): Promise<ResponseBody<\"ApiPermissionsController_evaluateBulk\">> {\n return this.client.request(\"POST\", \"/api/v1/permissions/evaluate/bulk\", {\n body: input,\n /** Read-only, like `evaluate`. */\n idempotent: true,\n ...options,\n });\n }\n\n /**\n * The same decision with its reasoning — which role granted it, which node\n * it was inherited from. For debugging an unexpected allow or deny, not for\n * the enforcement path.\n */\n explain(\n input: RequestBody<\"ApiPermissionsController_explain\">,\n options: CallOptions = {},\n ): Promise<ResponseBody<\"ApiPermissionsController_explain\">> {\n return this.client.request(\"POST\", \"/api/v1/permissions/evaluate/explain\", {\n body: input,\n /** Read-only, like `evaluate`. */\n idempotent: true,\n ...options,\n });\n }\n\n /** Every permission in the Environment, page by page. */\n list(\n query: QueryParams<\"ApiPermissionsController_listPermissions\"> = {},\n ): Paginator<PermissionItem> {\n return paginate<PermissionItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/permissions\", { query: params }),\n { ...query },\n );\n }\n\n get(\n id: string,\n ): Promise<ResponseBody<\"ApiPermissionsController_getPermission\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/permissions/${encodeURIComponent(id)}`,\n );\n }\n\n /** Define permissions. The request takes a batch, not a single key. */\n create(\n input: RequestBody<\"ApiPermissionsController_createPermissions\">,\n ): Promise<ResponseBody<\"ApiPermissionsController_createPermissions\">> {\n return this.client.request(\"POST\", \"/api/v1/permissions\", { body: input });\n }\n\n /**\n * Pass `ifMatch` with the permission's current `version` to make a\n * read-modify-write safe — a concurrent edit answers 409 instead of being\n * silently overwritten.\n */\n update(\n id: string,\n input: RequestBody<\"ApiPermissionsController_updatePermission\">,\n options: ConcurrencyOptions = {},\n ): Promise<ResponseBody<\"ApiPermissionsController_updatePermission\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/permissions/${encodeURIComponent(id)}`,\n { body: input, ...withConcurrency(options) },\n );\n }\n\n delete(id: string, options: ConcurrencyOptions = {}): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/permissions/${encodeURIComponent(id)}`,\n withConcurrency(options),\n );\n }\n}\n\n/**\n * One item from the permissions collection.\n *\n * Read off the list response rather than named directly, so it follows the\n * spec instead of being a second declaration of it.\n */\nexport type PermissionItem = ItemOf<\n ResponseBody<\"ApiPermissionsController_listPermissions\">\n>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n","import type { CanopyClient } from \"../client.js\";\nimport { paginate, type Paginator } from \"../pagination.js\";\nimport { withConcurrency } from \"../schema.js\";\nimport type {\n ConcurrencyOptions,\n QueryParams,\n RequestBody,\n ResponseBody,\n} from \"../schema.js\";\n\n/** Named bundles of permissions. */\nexport class Roles {\n constructor(private readonly client: CanopyClient) {}\n\n list(\n query: QueryParams<\"ApiRolesController_listRoles\"> = {},\n ): Paginator<RoleItem> {\n return paginate<RoleItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/roles\", { query: params }),\n { ...query },\n );\n }\n\n get(id: string): Promise<ResponseBody<\"ApiRolesController_getRole\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/roles/${encodeURIComponent(id)}`,\n );\n }\n\n create(\n input: RequestBody<\"ApiRolesController_createRole\">,\n ): Promise<ResponseBody<\"ApiRolesController_createRole\">> {\n return this.client.request(\"POST\", \"/api/v1/roles\", { body: input });\n }\n\n /**\n * Pass `ifMatch` with the role's current `version` to make a\n * read-modify-write safe — a concurrent edit answers 409 instead of being\n * silently overwritten.\n */\n update(\n id: string,\n input: RequestBody<\"ApiRolesController_updateRole\">,\n options: ConcurrencyOptions = {},\n ): Promise<ResponseBody<\"ApiRolesController_updateRole\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/roles/${encodeURIComponent(id)}`,\n { body: input, ...withConcurrency(options) },\n );\n }\n\n delete(id: string, options: ConcurrencyOptions = {}): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/roles/${encodeURIComponent(id)}`,\n withConcurrency(options),\n );\n }\n\n permissions(\n id: string,\n ): Promise<ResponseBody<\"ApiRolesController_getRolePermissions\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/roles/${encodeURIComponent(id)}/permissions`,\n );\n }\n\n /**\n * Replaces the role's permissions wholesale — this is a PUT, so anything\n * absent from `input` is removed. Read `permissions` first if you mean to add.\n */\n setPermissions(\n id: string,\n input: RequestBody<\"ApiRolesController_setRolePermissions\">,\n ): Promise<ResponseBody<\"ApiRolesController_setRolePermissions\">> {\n return this.client.request(\n \"PUT\",\n `/api/v1/roles/${encodeURIComponent(id)}/permissions`,\n { body: input },\n );\n }\n}\n\nexport type RoleItem = ItemOf<ResponseBody<\"ApiRolesController_listRoles\">>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n","import { CanopyClient, type CanopyClientOptions } from \"./client.js\";\nimport { Assignments } from \"./resources/assignments.js\";\nimport { Identities } from \"./resources/identities.js\";\nimport { Permissions } from \"./resources/permissions.js\";\nimport { Roles } from \"./resources/roles.js\";\n\n/**\n * The entry point most callers want.\n *\n * ```ts\n * const canopy = new Canopy({ apiKey: process.env.CANOPY_API_KEY });\n *\n * const { allowed } = await canopy.permissions.evaluate({\n * identity_id: identityId,\n * permission: \"documents.read\",\n * scope: \"node\",\n * node_id: nodeId,\n * });\n * ```\n *\n * `client` is public because the wrapped resources cover the paths integrators\n * hit most, not all 81 operations. Anything not wrapped is still reachable —\n * `canopy.client.request(\"GET\", \"/api/v1/audit-events\")` — with the same\n * envelope handling, typed errors and retry policy, so no endpoint is a dead\n * end while the ergonomic surface catches up.\n */\nexport class Canopy {\n readonly client: CanopyClient;\n readonly permissions: Permissions;\n readonly identities: Identities;\n readonly roles: Roles;\n readonly assignments: Assignments;\n\n constructor(options: CanopyClientOptions) {\n this.client = new CanopyClient(options);\n this.permissions = new Permissions(this.client);\n this.identities = new Identities(this.client);\n this.roles = new Roles(this.client);\n this.assignments = new Assignments(this.client);\n }\n}\n","import type { CanopyClient, RequestOptions } from \"./client.js\";\nimport { CanopyAuthorizerError } from \"./errors.js\";\nimport type { ResponseBody } from \"./schema.js\";\n\n/**\n * Answers permission checks in-process instead of asking Canopy each time.\n *\n * The inversion this rests on: rather than asking \"may this identity act\n * *here*\" per request, ask \"*where* may it act\" once. Canopy answers with the\n * nodes each permission was granted at — the grant roots, deliberately not\n * expanded through their descendants, because a grant already means \"this node\n * and everything beneath it\". Expanding would restate the hierarchy once per\n * identity, and would be largest for the near-root grants administrators hold.\n *\n * So two things are cached, split by what they depend on:\n *\n * - grant roots, per identity — small, a handful of assignments\n * - the hierarchy, once per process — shared, since its shape does not\n * depend on who is asking\n *\n * and a check becomes a walk up from the node in question looking for a grant\n * root. Both are held for at most `ttlMs`, which is therefore the delay\n * between an access change and it taking effect.\n */\n\nconst DEFAULT_TTL_MS = 60_000;\n\n/**\n * A tree deep enough to hit this is malformed. The server bounds depth with\n * the hierarchy schema, but a client walking a structure it was handed should\n * not loop forever if that assumption ever fails.\n */\nconst MAX_WALK_DEPTH = 256;\n\nexport interface LocalAuthorizerOptions {\n /**\n * How long grant roots and the hierarchy are reused, in milliseconds.\n * Defaults to 60s.\n *\n * This is a staleness budget, not a performance dial. Shortening it makes\n * revocation take effect sooner and costs more calls — and below the gap\n * between a user's requests it stops saving anything at all, because every\n * request finds the cache expired and refetches. Human-paced traffic has\n * multi-second gaps, so a value of a few seconds can cost full price for no\n * benefit.\n *\n * **`0` disables caching**, reading fresh on every check. That is the escape\n * for a caller who cannot accept a stale allow at all — it costs a round trip\n * per request, which is what this class exists to avoid, so reach for it\n * knowingly rather than as a default.\n */\n ttlMs?: number;\n\n /**\n * Per-attempt deadline for the reads this class makes.\n *\n * A cache hit costs nothing, but a miss happens on the request path and\n * holds an inbound request open exactly as a per-request check used to — so\n * the bound still matters, it just applies far less often.\n */\n timeoutMs?: number;\n\n /** Retries for those reads. */\n maxRetries?: number;\n\n /** Injectable clock, for tests. */\n now?: () => number;\n}\n\nexport interface LocalAuthorizationQuery {\n identity_id: string;\n permission: string;\n /** Defaults to `node`, which is the strict question. */\n scope?: \"node\" | \"app_wide\";\n node_id?: string;\n}\n\nexport interface LocalAuthorizerStats {\n /** Calls made to read an identity's grant roots. */\n grantFetches: number;\n /** Calls made to read the hierarchy, including revalidations. */\n treeRequests: number;\n /** Revalidations the server answered `304`, so no tree was transferred. */\n treeNotModified: number;\n}\n\ninterface GrantEntry {\n roots: Map<string, Set<string>>;\n expiresAt: number;\n}\n\ninterface TreeEntry {\n parents: Map<string, string | null>;\n etag: string | null;\n expiresAt: number;\n}\n\n/**\n * The grant map, read off the generated operation rather than restated here.\n *\n * Load-bearing beyond tidiness: typing this through the spec is what stops the\n * package building against a Canopy that does not serve the endpoint. A\n * hand-written shape compiles happily and then 404s on every guarded request\n * at runtime, which the guard turns into a blanket `403` — a failure no test\n * with a faked endpoint can see.\n */\ntype GrantMap = ResponseBody<\"ApiIdentitiesController_getIdentityGrants\">;\n\n/**\n * The hierarchy as parent edges, read off the generated operation.\n *\n * Deliberately not the tree. `GET /api/v1/nodes` answers what a dashboard\n * renders — names, statuses, access flags, per-node counts — and a walk upward\n * reads none of it. Measured at 50,000 nodes that is 18.6 MB against 5.0 MB,\n * on a read every consuming process makes at startup.\n */\ntype ParentEdges = ResponseBody<\"ApiNodesController_listNodeParents\">;\n\nexport class LocalAuthorizer {\n private readonly client: CanopyClient;\n private readonly ttlMs: number;\n private readonly now: () => number;\n private readonly readOptions: RequestOptions;\n\n private readonly grants = new Map<string, GrantEntry>();\n private tree: TreeEntry | undefined;\n\n /**\n * In-flight reads, so concurrent requests for the same thing share one call.\n *\n * Without this a cold start under load fans out: a hundred simultaneous\n * requests for one identity would each miss the cache and each fetch, which\n * is the per-request traffic this class exists to remove, concentrated into\n * the worst possible moment.\n */\n private readonly pendingGrants = new Map<\n string,\n Promise<Map<string, Set<string>>>\n >();\n private pendingTree: Promise<Map<string, string | null>> | undefined;\n\n private stats: LocalAuthorizerStats = {\n grantFetches: 0,\n treeRequests: 0,\n treeNotModified: 0,\n };\n\n constructor(client: CanopyClient, options: LocalAuthorizerOptions = {}) {\n this.client = client;\n this.ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;\n this.now = options.now ?? (() => Date.now());\n\n this.readOptions = {\n ...(options.timeoutMs === undefined\n ? {}\n : { timeoutMs: options.timeoutMs }),\n ...(options.maxRetries === undefined\n ? {}\n : { maxRetries: options.maxRetries, maxBackoffMs: options.timeoutMs }),\n };\n }\n\n /**\n * Whether the identity holds the permission.\n *\n * Shaped like the API's own evaluate so a caller can swap one for the other.\n * A `node` check with no node is a denial rather than an error: a request\n * whose subject cannot be established is exactly the one that must not pass.\n */\n async evaluate(\n query: LocalAuthorizationQuery,\n options: { signal?: AbortSignal } = {},\n ): Promise<{ allowed: boolean }> {\n if (!options.signal) {\n return this.decide(query);\n }\n\n // Raced rather than passed down. A read in flight may be shared with other\n // requests — that sharing is the point of the dedup — so cancelling it\n // because *this* caller hung up would abort a fetch the others are still\n // waiting on. Racing ends this call and leaves theirs alone; the fetch runs\n // to completion and warms the cache either way.\n const signal = options.signal;\n\n let onAbort: (() => void) | undefined;\n\n const aborted = new Promise<never>((_resolve, reject) => {\n const fail = (): void => {\n // `reason` is whatever the caller passed to `abort()`, which need not\n // be an Error. Keep it when it is, so the original cause survives.\n reject(\n signal.reason instanceof Error\n ? signal.reason\n : new Error(String(signal.reason ?? \"aborted\")),\n );\n };\n\n if (signal.aborted) {\n fail();\n\n return;\n }\n\n onAbort = fail;\n signal.addEventListener(\"abort\", fail, { once: true });\n });\n\n // Removed however the race ends, not only when it aborts. `once: true`\n // detaches a listener after it *fires*, which is the case that does not\n // need cleaning up; the common one — the decision winning — would otherwise\n // leave a listener attached for the life of the signal. Harmless for a\n // per-request controller, a leak for any longer-lived one a caller passes.\n return Promise.race([this.decide(query), aborted]).finally(() => {\n if (onAbort) {\n signal.removeEventListener(\"abort\", onAbort);\n }\n });\n }\n\n private async decide(\n query: LocalAuthorizationQuery,\n ): Promise<{ allowed: boolean }> {\n const roots = await this.grantRootsFor(query.identity_id);\n const granted = roots.get(query.permission);\n\n if (!granted || granted.size === 0) {\n return { allowed: false };\n }\n\n if ((query.scope ?? \"node\") === \"app_wide\") {\n return { allowed: true };\n }\n\n if (!query.node_id) {\n return { allowed: false };\n }\n\n return { allowed: await this.holdsAtNode(granted, query.node_id) };\n }\n\n /** Counters for observability — how much traffic the cache is actually saving. */\n snapshot(): LocalAuthorizerStats {\n return { ...this.stats };\n }\n\n /**\n * Drop everything held. Not needed in normal operation, where entries expire\n * on their own; useful in tests and after a known change.\n */\n invalidate(): void {\n this.grants.clear();\n this.tree = undefined;\n }\n\n /** Climb from `nodeId` and look for a grant root among its ancestors. */\n private async holdsAtNode(\n granted: Set<string>,\n nodeId: string,\n ): Promise<boolean> {\n // Checked before walking, so a grant at the node itself needs no tree at\n // all — which also means an unreachable hierarchy cannot deny a direct\n // grant that was already resolved.\n if (granted.has(nodeId)) {\n return true;\n }\n\n const parents = await this.parents();\n\n // The hierarchy we hold has to actually contain the node being asked\n // about. `GET /api/v1/nodes` answers a tree scoped to the caller, and a\n // credential that cannot read the hierarchy gets an empty one — with a\n // `200`, so nothing looks wrong. Walking off the end of that map would\n // return `false`, which reads as \"this identity lacks the permission\n // here\" when the truth is that we cannot see far enough to say.\n //\n // Denying would be a silent, total false-deny on every node-scoped route.\n // Undecidable is not denied, so this is raised rather than answered.\n if (!parents.has(nodeId)) {\n throw new CanopyAuthorizerError(\n \"authorizer.hierarchy_incomplete\",\n `The hierarchy this client can read does not contain node \"${nodeId}\", so authorization at that node cannot be decided. ` +\n \"A scoped API key needs the `hierarchy.view` scope to read the tree.\",\n );\n }\n\n let current = parents.get(nodeId);\n let depth = 0;\n\n while (current && depth < MAX_WALK_DEPTH) {\n if (granted.has(current)) {\n return true;\n }\n\n current = parents.get(current);\n depth += 1;\n }\n\n return false;\n }\n\n private async grantRootsFor(\n identityId: string,\n ): Promise<Map<string, Set<string>>> {\n const cached = this.grants.get(identityId);\n\n if (cached && cached.expiresAt > this.now()) {\n return cached.roots;\n }\n\n const pending = this.pendingGrants.get(identityId);\n\n if (pending) {\n return pending;\n }\n\n const read = this.fetchGrantRoots(identityId).finally(() => {\n this.pendingGrants.delete(identityId);\n });\n\n this.pendingGrants.set(identityId, read);\n\n return read;\n }\n\n private async fetchGrantRoots(\n identityId: string,\n ): Promise<Map<string, Set<string>>> {\n this.stats.grantFetches += 1;\n\n const response = await this.client.request<GrantMap>(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(identityId)}/grants`,\n this.readOptions,\n );\n\n const roots = new Map<string, Set<string>>();\n\n for (const row of response.items ?? []) {\n roots.set(row.permission, new Set(row.nodes));\n }\n\n this.grants.set(identityId, {\n roots,\n expiresAt: this.now() + this.ttlMs,\n });\n\n return roots;\n }\n\n private async parents(): Promise<Map<string, string | null>> {\n if (this.tree && this.tree.expiresAt > this.now()) {\n return this.tree.parents;\n }\n\n if (this.pendingTree) {\n return this.pendingTree;\n }\n\n const read = this.fetchTree().finally(() => {\n this.pendingTree = undefined;\n });\n\n this.pendingTree = read;\n\n return read;\n }\n\n /**\n * Revalidate rather than re-read. The hierarchy is the expensive half and\n * the one that changes least, so the common case is a `304` and no transfer\n * at all — the tree stays in memory and only its expiry moves.\n */\n private async fetchTree(): Promise<Map<string, string | null>> {\n this.stats.treeRequests += 1;\n\n const held = this.tree;\n\n const result = await this.client.requestConditional<ParentEdges>(\n \"GET\",\n \"/api/v1/nodes/parents\",\n held?.etag ?? undefined,\n this.readOptions,\n );\n\n if (!result.modified && held) {\n this.stats.treeNotModified += 1;\n this.tree = { ...held, expiresAt: this.now() + this.ttlMs };\n\n return held.parents;\n }\n\n const parents = new Map<string, string | null>();\n\n if (result.modified) {\n for (const edge of result.data.items) {\n parents.set(edge.id, edge.parent_node_id ?? null);\n }\n }\n\n this.tree = {\n parents,\n etag: result.modified ? result.etag : (held?.etag ?? null),\n expiresAt: this.now() + this.ttlMs,\n };\n\n return parents;\n }\n}\n","import { CanopyTokenError } from \"./errors.js\";\n\n/**\n * Local verification of a Canopy access token.\n *\n * Canopy signs access tokens with RS256 and publishes the matching public keys\n * at `/.well-known/jwks.json`, so a token can be checked entirely in-process:\n * fetch the keys once, then every verification after that is a signature check\n * with no network call. This is why authentication does not cost a round trip\n * the way an authorization check does.\n *\n * Verification is the part of an integration that is easiest to get subtly\n * wrong — accepting `alg: none`, trusting `kid` without bounding refetches,\n * skipping `aud` when the token carries one, treating a pre-auth token as a\n * session. Each of those is handled here so a caller does not have to know\n * they exist.\n *\n * ```ts\n * const verifier = new TokenVerifier();\n * const claims = await verifier.verify(token);\n * ```\n *\n * Deliberately standalone rather than a member of {@link Canopy}: that client\n * requires an API key or an access token, and a backend that only checks\n * logins holds neither.\n */\n\n/** Canopy's hosted issuer. Matches the client's default base URL. */\nconst DEFAULT_ISSUER = \"https://auth.canopy-io.com\";\n\n/** How long a fetched key set is reused before being refreshed. */\nconst DEFAULT_JWKS_CACHE_MAX_AGE_MS = 10 * 60 * 1000;\n\n/**\n * Floor between JWKS fetches triggered by an unknown `kid`.\n *\n * Key rotation means an unrecognised `kid` is sometimes legitimate, so a miss\n * has to be able to refetch. Left unbounded, that is also a free amplifier: a\n * forged token carrying a random `kid` would make this process call the issuer\n * once per request. The floor keeps rotation working while capping the damage\n * at one fetch per interval.\n */\nconst DEFAULT_JWKS_MIN_REFETCH_INTERVAL_MS = 30 * 1000;\n\n/**\n * Deadline for one JWKS read.\n *\n * Verification happens on the request path, so an unbounded read here is an\n * unbounded inbound request: an issuer that accepts the connection and then\n * goes quiet would hold every caller that needs a key, indefinitely.\n */\nconst DEFAULT_JWKS_TIMEOUT_MS = 5_000;\n\n/** The principal kinds a Canopy token may claim to be. */\nconst PRINCIPAL_TYPES = new Set([\"user\", \"identity\", \"api_key\", \"platform\"]);\n\n/**\n * Leeway applied to time-based claims, for ordinary clock drift between the\n * issuer and this machine. Seconds, not minutes: a generous window here\n * extends the life of a token that should have expired.\n */\nconst DEFAULT_CLOCK_TOLERANCE_SEC = 60;\n\nexport interface TokenVerifierOptions {\n /**\n * The issuer whose tokens are accepted, matched against `iss` exactly.\n * Defaults to Canopy's hosted issuer; set it for a self-hosted instance.\n *\n * Safe to default because it fails closed: pointed at the wrong issuer, a\n * token is rejected rather than accepted.\n */\n issuer?: string;\n\n /**\n * Required audience, matched against `aud`.\n *\n * Hosted Login (OAuth) tokens carry `aud` — your client id — and Direct API\n * identity tokens do not. Verifying an OAuth token without setting this\n * throws rather than ignoring the claim, because `aud` is what stops a token\n * minted for one client being replayed at another.\n */\n audience?: string;\n\n /** Where the signing keys live. Defaults to `${issuer}/.well-known/jwks.json`. */\n jwksUri?: string;\n\n /** How long a fetched key set is reused. Defaults to 10 minutes. */\n jwksCacheMaxAgeMs?: number;\n\n /** Floor between refetches provoked by an unknown `kid`. Defaults to 30s. */\n jwksMinRefetchIntervalMs?: number;\n\n /** Leeway on `exp` and `nbf`, in seconds. Defaults to 60. */\n clockToleranceSec?: number;\n\n /**\n * Accept pre-auth tokens. Defaults to `false`, and should stay false unless\n * you are building an account picker.\n *\n * A pre-auth token is a genuine, correctly-signed Canopy token issued\n * partway through a multi-account login: the person proved their password\n * but has not yet chosen an Account, so the token carries no Account context\n * and grants nothing. Accepting one as a session is a privilege escalation,\n * and it is the failure a hand-rolled verifier is most likely to miss —\n * every signature check passes.\n */\n allowPreAuthTokens?: boolean;\n\n /**\n * Deadline for a single JWKS read, in milliseconds. Defaults to 5s.\n *\n * Without one, an issuer that accepts a connection and then never answers\n * holds every inbound request that needs a key — the verification sits on the\n * request path, so an unbounded read there is an unbounded request.\n */\n jwksTimeoutMs?: number;\n\n /** Injectable for tests and for runtimes with a non-global fetch. */\n fetch?: typeof globalThis.fetch;\n}\n\n/**\n * The claims Canopy puts in an access token.\n *\n * Named claims are the ones the API guarantees; the index signature keeps\n * anything added later reachable without a version bump.\n */\nexport interface CanopyTokenClaims {\n /** The identity or user this token acts as. */\n sub: string;\n /** Which kind of principal `sub` is. */\n type: \"user\" | \"identity\" | \"api_key\" | \"platform\";\n iss: string;\n exp: number;\n iat?: number;\n nbf?: number;\n aud?: string | string[];\n account_id?: string;\n application_id?: string;\n /** Identity tokens carry this; admin tokens deliberately omit it. */\n environment_id?: string;\n account_slug?: string;\n application_slug?: string;\n environment_slug?: string;\n /** Present only on a pre-auth token — see `allowPreAuthTokens`. */\n token_type?: \"preauth\";\n console_access?: \"granted\" | \"none\";\n /** Emitted only when the `permissions` OAuth scope was granted. */\n permissions?: string[];\n /** True when `permissions` was truncated; query the API for the full set. */\n permissions_overflow?: boolean;\n [claim: string]: unknown;\n}\n\ninterface JwksKey {\n kid?: string;\n kty?: string;\n alg?: string;\n use?: string;\n n?: string;\n e?: string;\n}\n\ninterface JwtHeader {\n alg?: string;\n kid?: string;\n typ?: string;\n}\n\n/** base64url → bytes, without assuming Buffer (this runs in workers too). */\nfunction decodeBase64Url(value: string): Uint8Array<ArrayBuffer> {\n const padded = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(padded.padEnd(Math.ceil(padded.length / 4) * 4, \"=\"));\n const bytes = new Uint8Array(new ArrayBuffer(binary.length));\n\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n\n return bytes;\n}\n\nfunction decodeJsonSegment(segment: string, what: string): unknown {\n try {\n return JSON.parse(new TextDecoder().decode(decodeBase64Url(segment)));\n } catch (cause) {\n throw new CanopyTokenError(\n \"token.malformed\",\n `Token ${what} is not valid base64url-encoded JSON.`,\n { cause },\n );\n }\n}\n\nexport class TokenVerifier {\n private readonly issuer: string;\n private readonly audience: string | undefined;\n private readonly jwksUri: string;\n private readonly jwksCacheMaxAgeMs: number;\n private readonly jwksMinRefetchIntervalMs: number;\n private readonly jwksTimeoutMs: number;\n private readonly clockToleranceSec: number;\n private readonly allowPreAuthTokens: boolean;\n private readonly fetchImpl: typeof globalThis.fetch;\n\n /** Imported keys by `kid`, so a repeat verification skips the import cost. */\n private keys = new Map<string, CryptoKey>();\n private keysFetchedAt = 0;\n private lastFetchAttemptAt = 0;\n /** In-flight fetch, so a burst of requests triggers one call, not N. */\n private inFlight: Promise<void> | null = null;\n\n constructor(options: TokenVerifierOptions = {}) {\n this.issuer = (options.issuer ?? DEFAULT_ISSUER).replace(/\\/+$/, \"\");\n this.audience = options.audience;\n this.jwksUri = options.jwksUri ?? `${this.issuer}/.well-known/jwks.json`;\n this.jwksCacheMaxAgeMs =\n options.jwksCacheMaxAgeMs ?? DEFAULT_JWKS_CACHE_MAX_AGE_MS;\n this.jwksMinRefetchIntervalMs =\n options.jwksMinRefetchIntervalMs ?? DEFAULT_JWKS_MIN_REFETCH_INTERVAL_MS;\n this.jwksTimeoutMs = options.jwksTimeoutMs ?? DEFAULT_JWKS_TIMEOUT_MS;\n this.clockToleranceSec =\n options.clockToleranceSec ?? DEFAULT_CLOCK_TOLERANCE_SEC;\n this.allowPreAuthTokens = options.allowPreAuthTokens ?? false;\n\n const boundFetch = options.fetch ?? globalThis.fetch;\n\n if (typeof boundFetch !== \"function\") {\n throw new TypeError(\n \"TokenVerifier requires a fetch implementation. Pass `fetch` on Node runtimes without a global one.\",\n );\n }\n\n this.fetchImpl = boundFetch.bind(globalThis);\n }\n\n /**\n * Verify a token and return its claims. Throws {@link CanopyTokenError} on\n * anything short of a full pass — branch on `error.code`.\n *\n * Order matters: the signature is checked before any claim is believed, so\n * nothing downstream ever reads an unverified payload.\n */\n async verify(token: string): Promise<CanopyTokenClaims> {\n const parts = token.split(\".\");\n\n if (parts.length !== 3) {\n throw new CanopyTokenError(\n \"token.malformed\",\n \"Token is not a three-part JWS.\",\n );\n }\n\n const [encodedHeader, encodedPayload, encodedSignature] = parts as [\n string,\n string,\n string,\n ];\n\n const header = decodeJsonSegment(encodedHeader, \"header\") as JwtHeader;\n\n // Pinned, not merely checked: accepting whatever `alg` the token names is\n // how `none` and HMAC-key-confusion attacks get in.\n if (header.alg !== \"RS256\") {\n throw new CanopyTokenError(\n \"token.unsupported_algorithm\",\n `Token is signed with \"${header.alg ?? \"none\"}\"; Canopy issues RS256.`,\n );\n }\n\n const key = await this.resolveKey(header.kid);\n const signed = new TextEncoder().encode(\n `${encodedHeader}.${encodedPayload}`,\n );\n\n let signatureValid: boolean;\n\n try {\n signatureValid = await crypto.subtle.verify(\n \"RSASSA-PKCS1-v1_5\",\n key,\n decodeBase64Url(encodedSignature),\n signed,\n );\n } catch (cause) {\n throw new CanopyTokenError(\n \"token.malformed\",\n \"Token signature is not decodable.\",\n { cause },\n );\n }\n\n if (!signatureValid) {\n throw new CanopyTokenError(\n \"token.signature_invalid\",\n \"Token signature does not match Canopy's signing key.\",\n );\n }\n\n const claims = decodeJsonSegment(\n encodedPayload,\n \"payload\",\n ) as CanopyTokenClaims;\n\n this.assertClaims(claims);\n\n return claims;\n }\n\n /** Everything checked after the signature is known good. */\n private assertClaims(claims: CanopyTokenClaims): void {\n // Checked, not assumed. The claims arrive as parsed JSON and are cast to\n // this interface, so anything the interface declares but nobody verifies is\n // a promise the type makes and the runtime does not keep. `sub` is the\n // whole point of a verified token — a caller reads it to decide who is\n // acting — and a `string` that is actually `undefined` is worse than a\n // rejected token, because it looks like an answer.\n if (typeof claims.sub !== \"string\" || claims.sub === \"\") {\n throw new CanopyTokenError(\n \"token.malformed\",\n \"Token has no `sub` claim, so it identifies no one.\",\n );\n }\n\n // Same reasoning. `type` narrows to four values, and code branches on it;\n // a fifth would flow through a `switch` as though it were one of them.\n if (!PRINCIPAL_TYPES.has(claims.type)) {\n throw new CanopyTokenError(\n \"token.malformed\",\n `Token has an unrecognised \\`type\\` claim: ${JSON.stringify(claims.type)}.`,\n );\n }\n\n if (claims.iss !== this.issuer) {\n throw new CanopyTokenError(\n \"token.issuer_mismatch\",\n `Token was issued by \"${String(claims.iss)}\", not \"${this.issuer}\".`,\n );\n }\n\n const now = Math.floor(Date.now() / 1000);\n\n if (typeof claims.exp !== \"number\") {\n throw new CanopyTokenError(\n \"token.malformed\",\n \"Token has no `exp` claim.\",\n );\n }\n\n if (now > claims.exp + this.clockToleranceSec) {\n throw new CanopyTokenError(\"token.expired\", \"Token has expired.\");\n }\n\n if (\n typeof claims.nbf === \"number\" &&\n now < claims.nbf - this.clockToleranceSec\n ) {\n throw new CanopyTokenError(\n \"token.not_yet_valid\",\n \"Token is not valid yet.\",\n );\n }\n\n this.assertAudience(claims);\n\n if (claims.token_type === \"preauth\" && !this.allowPreAuthTokens) {\n throw new CanopyTokenError(\n \"token.preauth_not_allowed\",\n \"This is a pre-auth token: the user authenticated but has not selected an Account, so it grants no access. \" +\n \"Set `allowPreAuthTokens: true` only if you are building the account picker.\",\n );\n }\n }\n\n /**\n * `aud` is checked when either side mentions it.\n *\n * The case worth stating: a token carries `aud` but the verifier was not\n * configured with one. That is not \"no audience to check\" — it is an OAuth\n * token being verified by something that never said which client it is, and\n * ignoring it would accept a token minted for a different client. So it\n * throws and names the option.\n */\n private assertAudience(claims: CanopyTokenClaims): void {\n const audiences =\n claims.aud === undefined\n ? []\n : Array.isArray(claims.aud)\n ? claims.aud\n : [claims.aud];\n\n if (this.audience === undefined) {\n if (audiences.length > 0) {\n throw new CanopyTokenError(\n \"token.audience_unverified\",\n \"Token carries an `aud` claim but the verifier has no `audience` configured. \" +\n \"Set `audience` to your OAuth client id; Direct API tokens carry no audience and need no option.\",\n );\n }\n\n return;\n }\n\n if (!audiences.includes(this.audience)) {\n throw new CanopyTokenError(\n \"token.audience_mismatch\",\n `Token audience does not include \"${this.audience}\".`,\n );\n }\n }\n\n /**\n * The signing key for a `kid`, fetching the key set when it is stale or when\n * the `kid` is unknown — the latter is how key rotation is picked up\n * mid-process, bounded by `jwksMinRefetchIntervalMs`.\n */\n private async resolveKey(kid: string | undefined): Promise<CryptoKey> {\n if (kid === undefined) {\n throw new CanopyTokenError(\n \"token.malformed\",\n \"Token header has no `kid`, so its signing key cannot be identified.\",\n );\n }\n\n const stale = Date.now() - this.keysFetchedAt > this.jwksCacheMaxAgeMs;\n\n if (this.keys.size === 0 || stale) {\n // Floored like the rotation branch below, and for the same reason. With\n // no floor here, a key set that cannot be loaded — issuer down, or the\n // very first fetch failed — leaves `keys` empty, and every inbound\n // request takes this branch and issues its own outbound fetch. That is\n // one amplified request per caller, on an unauthenticated path, aimed at\n // the issuer precisely while it is already unwell.\n //\n // `lastFetchAttemptAt` starts at 0, so a genuine cold start is never\n // delayed by this — only a retry after a recent attempt is.\n if (this.shouldRefresh()) {\n await this.refreshKeys();\n } else if (this.keys.size === 0) {\n // Backing off with nothing cached: say so, rather than falling through\n // to `key_not_found`, which would claim the key set was read and\n // lacked this `kid`.\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Signing keys at ${this.jwksUri} are unavailable; backing off before retrying.`,\n );\n }\n }\n\n const cached = this.keys.get(kid);\n\n if (cached) {\n return cached;\n }\n\n // Unknown kid: possibly a rotation, possibly a forged header. Refetch at\n // most once per interval so the second case cannot amplify.\n if (this.shouldRefresh()) {\n await this.refreshKeys();\n }\n\n const rotated = this.keys.get(kid);\n\n if (rotated) {\n return rotated;\n }\n\n throw new CanopyTokenError(\n \"token.key_not_found\",\n `No signing key matches kid \"${kid}\".`,\n );\n }\n\n /**\n * Whether to await a key-set refresh.\n *\n * Two ways to qualify, and the first matters as much as the second. A read\n * already in flight is joined regardless of the floor: it costs no extra\n * outbound request, and it is what lets a concurrent burst share one fetch\n * instead of one caller winning and the rest being turned away.\n *\n * Otherwise the floor applies — the same one for every refetch path, so they\n * cannot drift into having different amplification properties.\n */\n private shouldRefresh(): boolean {\n if (this.inFlight) {\n return true;\n }\n\n return (\n Date.now() - this.lastFetchAttemptAt >= this.jwksMinRefetchIntervalMs\n );\n }\n\n private async refreshKeys(): Promise<void> {\n // Collapse a burst: concurrent requests await one fetch rather than each\n // issuing their own.\n this.inFlight ??= this.fetchKeys().finally(() => {\n this.inFlight = null;\n });\n\n await this.inFlight;\n }\n\n private async fetchKeys(): Promise<void> {\n this.lastFetchAttemptAt = Date.now();\n\n let response: Response;\n\n // Bounded: an issuer that accepts the connection and then never answers\n // would otherwise hold this request, and every request waiting on the same\n // in-flight read, for as long as it stays quiet.\n const controller = new AbortController();\n const timer =\n this.jwksTimeoutMs > 0\n ? setTimeout(() => controller.abort(), this.jwksTimeoutMs)\n : undefined;\n\n try {\n response = await this.fetchImpl(this.jwksUri, {\n headers: { accept: \"application/json\" },\n signal: controller.signal,\n });\n } catch (cause) {\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Could not reach the signing keys at ${this.jwksUri}.`,\n { cause },\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!response.ok) {\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Signing keys at ${this.jwksUri} returned HTTP ${response.status}.`,\n );\n }\n\n let document: { keys?: JwksKey[] };\n\n try {\n document = (await response.json()) as { keys?: JwksKey[] };\n } catch (cause) {\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Signing keys at ${this.jwksUri} were not valid JSON.`,\n { cause },\n );\n }\n\n const imported = new Map<string, CryptoKey>();\n\n for (const jwk of document.keys ?? []) {\n if (\n jwk.kty !== \"RSA\" ||\n jwk.kid === undefined ||\n jwk.n === undefined ||\n jwk.e === undefined\n ) {\n continue;\n }\n\n if (jwk.alg !== undefined && jwk.alg !== \"RS256\") {\n continue;\n }\n\n try {\n imported.set(\n jwk.kid,\n await crypto.subtle.importKey(\n \"jwk\",\n { kty: \"RSA\", n: jwk.n, e: jwk.e, alg: \"RS256\", ext: true },\n { name: \"RSASSA-PKCS1-v1_5\", hash: \"SHA-256\" },\n false,\n [\"verify\"],\n ),\n );\n } catch {\n // One unusable key must not blind the verifier to the others.\n continue;\n }\n }\n\n if (imported.size === 0) {\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Signing keys at ${this.jwksUri} contained no usable RS256 key.`,\n );\n }\n\n this.keys = imported;\n this.keysFetchedAt = Date.now();\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/pagination.ts","../src/resources/assignments.ts","../src/resources/identities.ts","../src/schema.ts","../src/resources/permissions.ts","../src/resources/roles.ts","../src/canopy.ts","../src/authorizer.ts","../src/verify.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Everything this client throws.\n *\n * Three classes, because callers act on the distinction: `CanopyError` means\n * the API answered and said no, `CanopyConnectionError` means it never\n * answered, and `CanopyTokenError` means a token failed local verification\n * without anything being asked of the API at all. The first is a decision you\n * may need to surface to a user; the second is usually worth retrying or\n * alerting on; the third is a 401 for the caller who presented the token.\n */\n\n/** The `error` object inside Canopy's error envelope. */\nexport interface CanopyErrorBody {\n statusCode: number;\n /**\n * Stable machine-readable code, e.g. `rbac.assignment_conflict`. Null on\n * framework-level failures such as a validation 400, where `details` carries\n * the specifics instead.\n */\n code: string | null;\n message: string;\n timestamp?: string;\n path?: string;\n method?: string;\n /** Field-level validation messages, present on a 400. */\n details?: string[];\n /** Structured payload for specific codes — a version conflict carries the current row. */\n data?: unknown;\n}\n\n/**\n * The API returned a non-2xx response.\n *\n * Branch on `code` rather than `message`: the code is a contract, the message\n * is prose that may be reworded.\n */\nexport class CanopyError extends Error {\n override readonly name = \"CanopyError\";\n readonly statusCode: number;\n readonly code: string | null;\n readonly details: string[] | undefined;\n readonly data: unknown;\n /** The path and method that failed, for logging. */\n readonly request: { method: string; path: string };\n /**\n * How long to wait before retrying, in milliseconds, when the server said so\n * via `Retry-After` — populated on a 429, and on any other response that\n * carries the header. Undefined when the server gave no guidance.\n */\n readonly retryAfterMs: number | undefined;\n\n constructor(\n body: CanopyErrorBody,\n request: { method: string; path: string },\n retryAfterMs?: number,\n ) {\n super(body.message);\n\n this.statusCode = body.statusCode;\n this.code = body.code;\n this.details = body.details;\n this.data = body.data;\n this.request = request;\n this.retryAfterMs = retryAfterMs;\n }\n\n /** A 429. `retryAfterMs` is populated when the server said how long to wait. */\n get isRateLimited(): boolean {\n return this.statusCode === 429;\n }\n\n /** 401 or 403 — the credential is wrong or not permitted here. */\n get isAuthFailure(): boolean {\n return this.statusCode === 401 || this.statusCode === 403;\n }\n}\n\n/**\n * The request never produced a response — DNS failure, connection reset, or a\n * timeout.\n *\n * Not this: a caller's own cancellation. Aborting the `signal` passed to a\n * request rejects with that abort (`AbortError`, or whatever `signal.reason`\n * holds) and is never retried, because the caller stopping is an intent rather\n * than a failure to report.\n *\n * Kept separate from `CanopyError` because there is no status code and no\n * server opinion to report: nothing is known about whether the operation\n * happened, which matters for anything non-idempotent.\n */\nexport class CanopyConnectionError extends Error {\n override readonly name = \"CanopyConnectionError\";\n readonly request: { method: string; path: string };\n\n constructor(\n message: string,\n request: { method: string; path: string },\n options?: { cause?: unknown },\n ) {\n super(message, options);\n\n this.request = request;\n }\n}\n\n/**\n * A token failed verification.\n *\n * Separate from `CanopyError` because nothing was asked of the API: the token\n * was checked here, against keys already held. There is no status code to\n * report and no server opinion to relay — the decision was local, which is the\n * whole point of verifying a signature rather than calling an endpoint.\n *\n * Branch on `code`; it follows the same dot-notation contract as the API's own\n * codes. Every one of them means the same thing to an HTTP caller — 401 — so\n * the code is for your logs and your tests, not usually for the response.\n */\nexport class CanopyTokenError extends Error {\n override readonly name = \"CanopyTokenError\";\n\n /**\n * One of:\n *\n * - `token.malformed` — not a JWS, or a segment would not decode\n * - `token.unsupported_algorithm` — not RS256; Canopy issues only RS256\n * - `token.key_not_found` — no published key matches the token's `kid`\n * - `token.jwks_unavailable` — the key set could not be fetched or parsed\n * - `token.signature_invalid` — signature does not match the signing key\n * - `token.expired` / `token.not_yet_valid` — outside its validity window\n * - `token.issuer_mismatch` — `iss` is not the configured issuer\n * - `token.audience_mismatch` — `aud` does not include the configured audience\n * - `token.audience_unverified` — token has an `aud` but none was configured\n * - `token.preauth_not_allowed` — a pre-auth token, which grants no access\n */\n readonly code: string;\n\n constructor(code: string, message: string, options?: { cause?: unknown }) {\n super(message, options);\n\n this.code = code;\n }\n}\n\n/**\n * The local authorizer could not answer, and must not pretend otherwise.\n *\n * Distinct from a denial. It is raised when the data a decision needs is not\n * merely absent but *unreadable* — most often a credential that cannot read the\n * hierarchy, which comes back as an empty tree rather than an error. Denying\n * there would be a silent, total false-deny on every node-scoped route while\n * every response still looked healthy.\n *\n * No retry fixes it, so callers should treat it as a misconfiguration rather\n * than an outage.\n */\nexport class CanopyAuthorizerError extends Error {\n override readonly name = \"CanopyAuthorizerError\";\n readonly code: string;\n\n constructor(code: string, message: string, options?: { cause?: unknown }) {\n super(message, options);\n\n this.code = code;\n }\n}\n\nexport function isCanopyAuthorizerError(\n error: unknown,\n): error is CanopyAuthorizerError {\n return error instanceof Error && error.name === \"CanopyAuthorizerError\";\n}\n\n/** Narrowing helper that survives bundling and duplicate copies of the package. */\nexport function isCanopyError(error: unknown): error is CanopyError {\n return error instanceof Error && error.name === \"CanopyError\";\n}\n\nexport function isCanopyConnectionError(\n error: unknown,\n): error is CanopyConnectionError {\n return error instanceof Error && error.name === \"CanopyConnectionError\";\n}\n\nexport function isCanopyTokenError(error: unknown): error is CanopyTokenError {\n return error instanceof Error && error.name === \"CanopyTokenError\";\n}\n","import {\n CanopyConnectionError,\n CanopyError,\n type CanopyErrorBody,\n} from \"./errors.js\";\n\n/**\n * Offset pagination — the default across the API.\n */\nexport interface OffsetPagination {\n page: number;\n take: number;\n item_count: number;\n page_count: number;\n has_previous_page: boolean;\n has_next_page: boolean;\n}\n\n/**\n * Cursor pagination — used by append-heavy feeds (the audit log) where an\n * offset window drifts under concurrent writes.\n *\n * The envelope is identical to the offset case; only this object differs,\n * which is precisely why hand-written pagination loops break on one of them.\n */\nexport interface CursorPagination {\n next_cursor: string | null;\n}\n\nexport type Pagination = OffsetPagination | CursorPagination;\n\nexport function isCursorPagination(\n pagination: Pagination,\n): pagination is CursorPagination {\n return \"next_cursor\" in pagination;\n}\n\n/** A collection response, paginated or not. */\n/**\n * The answer to a conditional read.\n *\n * A discriminated union rather than an optional body, so a caller cannot\n * mistake \"nothing changed\" for \"changed to nothing\" — the two are opposite\n * instructions to whatever is holding the cached copy.\n */\nexport type ConditionalResult<T> =\n { modified: true; data: T; etag: string | null } | { modified: false };\n\nexport interface Collection<T> {\n items: T[];\n pagination?: Pagination;\n}\n\n/** A 207 partial-success response from a bulk endpoint. */\nexport interface PartialSuccess<T> {\n summary: { total: number; succeeded: number; failed: number };\n results: {\n index: number;\n status: \"success\" | \"error\";\n code: number;\n data?: T;\n input?: unknown;\n error?: { code: string | null; message: string };\n }[];\n}\n\nexport interface CanopyClientOptions {\n /**\n * Server-to-server credential (`cnpy_…`), sent as `X-API-Key`. Never ship\n * one to a browser: it carries whatever scopes it was issued with.\n */\n apiKey?: string;\n /** Identity or portal JWT, sent as `Authorization: Bearer`. */\n accessToken?: string;\n /** Defaults to Canopy's hosted API. Set this for a self-hosted instance. */\n baseUrl?: string;\n /** Per-attempt deadline. Defaults to 30s; 0 disables. */\n timeoutMs?: number;\n /** Retries after the first attempt. Defaults to 2. */\n maxRetries?: number;\n /**\n * Ceiling on a single wait between attempts. Defaults to 30s.\n *\n * The server's `Retry-After` is honoured up to this, then clamped. Without a\n * cap the wait is whatever a response header asks for, which sits outside\n * `timeoutMs` and can hold a caller far longer than its own budget allows.\n */\n maxBackoffMs?: number;\n /** Extra headers on every request. */\n headers?: Record<string, string>;\n /** Injectable for tests and for runtimes with a non-global fetch. */\n fetch?: typeof globalThis.fetch;\n}\n\nexport interface RequestOptions {\n query?: Record<string, string | number | boolean | undefined | null>;\n body?: unknown;\n signal?: AbortSignal;\n /**\n * Per-attempt deadline for this call only, overriding the client-wide\n * `timeoutMs`. 0 disables it.\n *\n * The client-wide default suits administrative CRUD. A latency-critical call\n * on a request path — an authorization check on every inbound request — wants\n * a much tighter one, because the total time at risk is this deadline times\n * the attempts, and it is spent holding an inbound request open.\n */\n timeoutMs?: number;\n /**\n * Retries after the first attempt for this call only, overriding the\n * client-wide `maxRetries`. 0 disables retrying.\n *\n * Set this together with `timeoutMs` when a call needs a bounded worst case:\n * the two multiply. A deadline alone still permits `maxRetries + 1` of them\n * back to back, which is the difference between a slow call and a request\n * held open long past the point the answer was useful.\n */\n maxRetries?: number;\n /**\n * Ceiling on a single wait between attempts, for this call only.\n *\n * Set it alongside `timeoutMs` and `maxRetries` when a call needs a real\n * worst case: the deadline bounds an attempt, `maxRetries` bounds how many,\n * and this bounds the waiting in between — which a server's `Retry-After`\n * would otherwise control.\n */\n maxBackoffMs?: number;\n /**\n * Headers for this call only, overriding the client-wide `headers`.\n *\n * This is how the per-request protocol headers are sent: `If-Match`, carrying\n * a resource's current `version` for optimistic concurrency (a stale value\n * answers 409), and `Idempotency-Key`, which makes a replayed bulk create\n * return the original result instead of creating rows twice.\n *\n * The credential is not overridable this way — auth is settled by the client.\n */\n headers?: Record<string, string>;\n /**\n * Declares this call safe to repeat, which allows retrying a 5xx.\n *\n * Needed because the generated types carry no idempotency marker, so the\n * spec cannot drive this. GET, HEAD, PUT and DELETE are treated as\n * idempotent by HTTP definition; POST is not, and a blind retry there can\n * create a second role assignment or a second invitation.\n *\n * Set it where a POST is a read in disguise — the permission evaluations\n * take a body and so must be POSTs, but they compute an answer and write\n * nothing. Do not set it on anything that creates.\n */\n idempotent?: boolean;\n}\n\n/**\n * The per-call knobs a resource method accepts.\n *\n * Deliberately excludes `body` and `query`, which the method itself owns, and\n * `idempotent`, which is a property of the endpoint rather than the call site.\n */\nexport type CallOptions = Pick<\n RequestOptions,\n \"signal\" | \"timeoutMs\" | \"maxRetries\" | \"maxBackoffMs\" | \"headers\"\n>;\n\nconst DEFAULT_BASE_URL = \"https://auth.canopy-io.com\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst DEFAULT_MAX_BACKOFF_MS = 30_000;\n\n/** Idempotent by HTTP definition (RFC 9110 §9.2.2). */\nconst IDEMPOTENT_METHODS = new Set([\"GET\", \"HEAD\", \"PUT\", \"DELETE\"]);\n\n/** `304`. A success for a conditional read, and not a 2xx. */\nconst NOT_MODIFIED = 304;\n\n/**\n * The transport every resource is built on: one place that knows how to\n * authenticate, unwrap Canopy's response envelope, turn a failure into a typed\n * error, and decide whether repeating a request is safe.\n *\n * Deliberately dependency-free — `fetch` only — so the same client runs on\n * Node 18+, in browsers, on Workers and on Deno.\n */\nexport class CanopyClient {\n private readonly baseUrl: string;\n private readonly timeoutMs: number;\n private readonly maxRetries: number;\n private readonly maxBackoffMs: number;\n private readonly authHeaders: Record<string, string>;\n private readonly extraHeaders: Record<string, string>;\n private readonly fetchImpl: typeof globalThis.fetch;\n\n constructor(options: CanopyClientOptions = {}) {\n if (!options.apiKey && !options.accessToken) {\n throw new TypeError(\n \"CanopyClient requires either `apiKey` (server-to-server) or `accessToken` (a user or identity JWT).\",\n );\n }\n\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.maxBackoffMs = options.maxBackoffMs ?? DEFAULT_MAX_BACKOFF_MS;\n this.extraHeaders = options.headers ?? {};\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n\n if (typeof this.fetchImpl !== \"function\") {\n throw new TypeError(\n \"No `fetch` available. Node 18+ provides one; on older runtimes pass `fetch` explicitly.\",\n );\n }\n\n this.authHeaders = options.apiKey\n ? { \"X-API-Key\": options.apiKey }\n : { Authorization: `Bearer ${options.accessToken ?? \"\"}` };\n }\n\n /**\n * Issue a request and return the payload with the envelope removed.\n *\n * `{ data }` → the resource\n * `{ items, pagination }` → the whole object, so pagination survives\n * `{ summary, results }` → the whole object\n * 204 → undefined\n *\n * Non-2xx throws `CanopyError`; a request that never completed throws\n * `CanopyConnectionError`.\n */\n async request<T>(\n method: string,\n path: string,\n options: RequestOptions = {},\n ): Promise<T> {\n const response = await this.perform(method, path, options);\n\n return this.unwrap<T>(response, method.toUpperCase(), path);\n }\n\n /**\n * A conditional read: send the validator you already hold, and find out\n * whether anything changed.\n *\n * The sibling of `If-Match`, which this client already sends for optimistic\n * concurrency. `304 Not Modified` is a *success* — it means the copy you\n * have is current — but it is not a 2xx, so `request` would raise it as an\n * error. Hence a separate entry point with a return type that says which\n * happened rather than one that has to be inspected.\n *\n * Use it to hold something expensive and revalidate cheaply — the hierarchy\n * behind local authorization is the case this exists for.\n */\n async requestConditional<T>(\n method: string,\n path: string,\n etag: string | undefined,\n options: RequestOptions = {},\n ): Promise<ConditionalResult<T>> {\n const conditional: RequestOptions = etag\n ? { ...options, headers: { ...options.headers, \"If-None-Match\": etag } }\n : options;\n\n const response = await this.perform(\n method,\n path,\n conditional,\n (status) => status === NOT_MODIFIED || (status >= 200 && status < 300),\n );\n\n if (response.status === NOT_MODIFIED) {\n return { modified: false };\n }\n\n return {\n modified: true,\n data: await this.unwrap<T>(response, method.toUpperCase(), path),\n etag: response.headers.get(\"etag\"),\n };\n }\n\n /**\n * Everything up to the response: retries, backoff, cancellation and the\n * status check, without deciding what the body means.\n *\n * Split out so a conditional read can accept `304` where an ordinary one\n * must not, rather than either duplicating the retry policy or teaching\n * `unwrap` about statuses that carry no body.\n */\n private async perform(\n method: string,\n path: string,\n options: RequestOptions = {},\n accept: (status: number) => boolean = (status) =>\n status >= 200 && status < 300,\n ): Promise<Response> {\n const url = this.buildUrl(path, options.query);\n const upper = method.toUpperCase();\n const retryable = options.idempotent ?? IDEMPOTENT_METHODS.has(upper);\n const maxRetries = options.maxRetries ?? this.maxRetries;\n const maxBackoffMs = options.maxBackoffMs ?? this.maxBackoffMs;\n\n // Cancelled before it began: never reach the network at all. Relying on\n // `fetch` to reject an aborted signal would still cost the call.\n throwIfAborted(options.signal);\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n await delay(\n backoffMs(attempt, lastError, maxBackoffMs),\n options.signal,\n );\n\n // Abort during the backoff window: stop here rather than spending an\n // attempt on a request the caller no longer wants.\n throwIfAborted(options.signal);\n }\n\n try {\n const response = await this.send(upper, url, options);\n\n if (this.shouldRetry(response.status, retryable, attempt, maxRetries)) {\n lastError = await this.toError(response, upper, path);\n continue;\n }\n\n if (!accept(response.status)) {\n throw await this.toError(response, upper, path);\n }\n\n return response;\n } catch (error) {\n // A typed API error is the server's answer, not a transport problem —\n // it is never retried here, only by the branch above.\n if (error instanceof CanopyError) {\n throw error;\n }\n\n lastError = error;\n\n // A caller's abort is a deliberate cancellation, not a transport\n // hiccup: never retry it, and surface the abort itself rather than a\n // generic connection error. The per-attempt timeout uses a separate\n // internal controller, so `options.signal` is aborted only when the\n // caller asked to stop — a timeout still falls through to the retry\n // logic below.\n throwIfAborted(options.signal);\n\n // Nothing is known about whether a non-idempotent request took effect,\n // so it must not be repeated.\n if (!retryable || attempt === maxRetries) {\n throw new CanopyConnectionError(\n `${upper} ${path} failed: ${describe(error)}`,\n { method: upper, path },\n { cause: error },\n );\n }\n }\n }\n\n // Loop exits only via return or throw; this satisfies the type checker and\n // would indicate a logic error if it were ever reached.\n throw new CanopyConnectionError(\n `${upper} ${path} exhausted ${maxRetries + 1} attempts`,\n { method: upper, path },\n { cause: lastError },\n );\n }\n\n private shouldRetry(\n status: number,\n retryable: boolean,\n attempt: number,\n maxRetries: number,\n ): boolean {\n if (attempt >= maxRetries) {\n return false;\n }\n\n // 429 means the request was refused before doing anything, so repeating it\n // is safe regardless of method.\n if (status === 429) {\n return true;\n }\n\n return status >= 500 && retryable;\n }\n\n private async send(\n method: string,\n url: string,\n options: RequestOptions,\n ): Promise<Response> {\n const controller = new AbortController();\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const timer =\n timeoutMs > 0\n ? setTimeout(() => controller.abort(), timeoutMs)\n : undefined;\n\n // Forward a caller's abort without requiring AbortSignal.any, which is not\n // available on every runtime this package supports. A signal that is\n // already aborted would never re-fire the event, so honour it up front.\n const onAbort = () => controller.abort();\n\n if (options.signal?.aborted) {\n controller.abort();\n }\n\n options.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n ...this.extraHeaders,\n };\n\n if (options.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n // Per-request headers beat the client-wide defaults, but the credential is\n // applied last so no call site can accidentally send a different one.\n Object.assign(headers, options.headers, this.authHeaders);\n\n // Built conditionally rather than passing `body: undefined`, which\n // `exactOptionalPropertyTypes` rejects and which some runtimes treat as a\n // body on GET.\n const init: RequestInit = { method, headers, signal: controller.signal };\n\n if (options.body !== undefined) {\n init.body = JSON.stringify(options.body);\n }\n\n try {\n return await this.fetchImpl(url, init);\n } finally {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n\n options.signal?.removeEventListener(\"abort\", onAbort);\n }\n }\n\n private buildUrl(path: string, query: RequestOptions[\"query\"]): string {\n const url = new URL(\n path.startsWith(\"/\") ? path : `/${path}`,\n `${this.baseUrl}/`,\n );\n\n for (const [key, value] of Object.entries(query ?? {})) {\n // Absent and null are both \"no filter\" — sending `?take=null` would be\n // a validation error rather than a default.\n if (value === undefined || value === null) {\n continue;\n }\n\n url.searchParams.set(key, String(value));\n }\n\n return url.toString();\n }\n\n private async unwrap<T>(\n response: Response,\n method: string,\n path: string,\n ): Promise<T> {\n if (response.status === 204) {\n return undefined as T;\n }\n\n const text = await response.text();\n\n if (text === \"\") {\n return undefined as T;\n }\n\n let parsed: Record<string, unknown>;\n\n try {\n parsed = JSON.parse(text) as Record<string, unknown>;\n } catch {\n // A 2xx with a body that is not JSON — usually a proxy or gateway that\n // answered instead of the API. The connection succeeded, so this is not a\n // CanopyConnectionError; report it as the malformed API response it is.\n throw new CanopyError(\n {\n statusCode: response.status,\n code: null,\n message: `${method} ${path} returned ${response.status} with a body that is not JSON.`,\n },\n { method, path },\n );\n }\n\n // `{ data }` is the single-resource envelope; everything else is returned\n // whole, because its extra keys (pagination, summary) are the point.\n if (parsed && typeof parsed === \"object\" && \"data\" in parsed) {\n return parsed[\"data\"] as T;\n }\n\n return parsed as T;\n }\n\n private async toError(\n response: Response,\n method: string,\n path: string,\n ): Promise<CanopyError> {\n const retryAfter = parseRetryAfter(response.headers.get(\"retry-after\"));\n let body: CanopyErrorBody = {\n statusCode: response.status,\n code: null,\n message: `${response.status} ${response.statusText}`.trim(),\n };\n\n try {\n const parsed = JSON.parse(await response.text()) as {\n error?: CanopyErrorBody;\n };\n\n if (parsed.error) {\n body = {\n ...parsed.error,\n statusCode: parsed.error.statusCode ?? response.status,\n };\n }\n } catch {\n // A non-JSON body (a proxy's HTML error page) leaves the status-derived\n // message above, which is more useful than the raw markup.\n }\n\n return new CanopyError(body, { method, path }, retryAfter ?? undefined);\n }\n}\n\n/** `Retry-After` is either seconds or an HTTP date. */\nfunction parseRetryAfter(header: string | null): number | null {\n if (!header) {\n return null;\n }\n\n const seconds = Number(header);\n\n if (Number.isFinite(seconds)) {\n return Math.max(0, seconds * 1000);\n }\n\n const date = Date.parse(header);\n\n if (Number.isNaN(date)) {\n return null;\n }\n\n return Math.max(0, date - Date.now());\n}\n\n/**\n * Exponential backoff with jitter, but the server's own `Retry-After` wins —\n * it knows when the window resets and we are guessing.\n *\n * Jitter matters when many workers hit the same limit at once: without it they\n * all wake together and rate-limit each other again.\n */\nfunction backoffMs(\n attempt: number,\n lastError: unknown,\n maxBackoffMs: number,\n): number {\n const advised =\n lastError && typeof lastError === \"object\" && \"retryAfterMs\" in lastError\n ? Number(lastError.retryAfterMs)\n : NaN;\n\n if (Number.isFinite(advised)) {\n // Capped, because this number comes off a response header and is otherwise\n // unbounded: a `Retry-After: 120` would hold the caller for two minutes,\n // outside any per-attempt deadline. Waiting less than advised risks another\n // 429, which is a retry we are already budgeted for; waiting the full\n // amount risks a request pinned open for as long as the header says.\n return Math.min(advised, maxBackoffMs);\n }\n\n const base = 250 * 2 ** (attempt - 1);\n\n return Math.min(base + Math.random() * base, maxBackoffMs);\n}\n\n/**\n * Stop immediately if the caller has cancelled, surfacing their own reason.\n *\n * `AbortSignal.throwIfAborted` would do this, but it is not available on every\n * runtime this package supports, and neither is a guaranteed `reason`.\n */\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (!signal?.aborted) {\n return;\n }\n\n throw (\n signal.reason ??\n new DOMException(\"This operation was aborted\", \"AbortError\")\n );\n}\n\n/**\n * Wait, but stop early if the caller cancels.\n *\n * A plain timer would hold the wait to completion and only notice the abort\n * afterwards — and with a server-advised `Retry-After` that wait can be far\n * longer than any per-attempt deadline, so \"cancelled\" would mean \"cancelled,\n * in a minute\". Resolving early lets the caller's abort be observed at once;\n * the throw itself stays with `throwIfAborted`.\n */\nfunction delay(ms: number, signal: AbortSignal | undefined): Promise<void> {\n if (signal?.aborted) {\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n // Held in one object because a timer implementation may invoke its callback\n // synchronously — a test double often does. `finish` would then run before\n // the handle exists, so it reads the handle through `state` rather than\n // closing over a binding that is not assigned yet, and `settled` keeps the\n // abort listener from outliving a wait that already finished.\n const state: {\n timer?: ReturnType<typeof setTimeout>;\n settled: boolean;\n } = { settled: false };\n\n const finish = () => {\n if (state.settled) {\n return;\n }\n\n state.settled = true;\n\n if (state.timer !== undefined) {\n clearTimeout(state.timer);\n }\n\n signal?.removeEventListener(\"abort\", finish);\n resolve();\n };\n\n state.timer = setTimeout(finish, ms);\n\n if (!state.settled) {\n signal?.addEventListener(\"abort\", finish, { once: true });\n }\n });\n}\n\nfunction describe(error: unknown): string {\n if (error instanceof Error) {\n // A caller's abort is rethrown before it reaches here, so an AbortError at\n // this point came from the per-attempt timeout.\n return error.name === \"AbortError\" ? \"timed out\" : error.message;\n }\n\n return String(error);\n}\n","import { type Collection, isCursorPagination } from \"./client.js\";\n\n/** Query parameters for one page request. */\nexport type PageParams = Record<\n string,\n string | number | boolean | undefined | null\n>;\n\n/** Fetches a single page. Supplied by each resource. */\nexport type PageFetcher<T> = (params: PageParams) => Promise<Collection<T>>;\n\nexport interface PaginateOptions {\n /** Stop after this many pages. Guards against a server that never ends. */\n maxPages?: number;\n}\n\nconst DEFAULT_MAX_PAGES = 1_000;\n\n/**\n * Walks a paginated endpoint without the caller knowing which pagination style\n * it uses.\n *\n * This exists because the two styles are indistinguishable at the top level:\n * both answer `{ items, pagination }`. Offset carries\n * `page`/`has_next_page`; cursor carries `next_cursor`. The audit log is\n * cursor-paginated and everything else is offset, so a hand-written loop works\n * against one and silently reads only the first page of the other — or loops\n * forever.\n *\n * The style is inferred from the first response rather than declared, so a\n * resource does not have to restate what the server already says. Only the\n * cursor or page parameter is managed here; page size stays whatever the\n * caller passed, because the two styles even name that differently (`take` for\n * offset, `limit` for the cursor feeds).\n */\nexport class Paginator<T> implements AsyncIterable<T> {\n private readonly fetchPage: PageFetcher<T>;\n private readonly initial: PageParams;\n private readonly maxPages: number;\n\n constructor(\n fetchPage: PageFetcher<T>,\n initial: PageParams = {},\n options: PaginateOptions = {},\n ) {\n this.fetchPage = fetchPage;\n this.initial = initial;\n this.maxPages = options.maxPages ?? DEFAULT_MAX_PAGES;\n }\n\n /** Every item across every page. */\n async *[Symbol.asyncIterator](): AsyncIterator<T> {\n for await (const page of this.pages()) {\n for (const item of page.items) {\n yield item;\n }\n }\n }\n\n /**\n * Page by page, for callers that need the pagination metadata or want to\n * process in batches rather than item by item.\n */\n async *pages(): AsyncGenerator<Collection<T>> {\n let params: PageParams = { ...this.initial };\n let seenCursor: string | null = null;\n let pageCount = 0;\n\n for (;;) {\n const page = await this.fetchPage(params);\n\n pageCount++;\n\n yield page;\n\n const pagination = page.pagination;\n\n // No pagination object at all: an unpaginated `{ items }` collection.\n if (!pagination) {\n return;\n }\n\n // A server that keeps promising more while returning nothing would spin\n // forever; the empty page is the honest end of the feed.\n if (page.items.length === 0) {\n return;\n }\n\n if (pageCount >= this.maxPages) {\n return;\n }\n\n if (isCursorPagination(pagination)) {\n const next = pagination.next_cursor;\n\n if (next === null || next === seenCursor) {\n // Null is the documented end. An unchanged cursor means the server\n // is not advancing, which would otherwise be an infinite loop.\n return;\n }\n\n seenCursor = next;\n params = { ...params, cursor: next };\n\n continue;\n }\n\n if (!pagination.has_next_page) {\n return;\n }\n\n params = { ...params, page: pagination.page + 1 };\n }\n }\n\n /**\n * Collect everything into an array.\n *\n * Bounded on purpose: an unbounded drain of an audit log will exhaust memory\n * on a busy account, so the cap is a parameter rather than a footnote. Use\n * the iterator for large feeds.\n */\n async all(max = 10_000): Promise<T[]> {\n const collected: T[] = [];\n\n for await (const item of this) {\n collected.push(item);\n\n if (collected.length >= max) {\n break;\n }\n }\n\n return collected;\n }\n\n /** The first item, or undefined. Stops after one page. */\n async first(): Promise<T | undefined> {\n for await (const item of this) {\n return item;\n }\n\n return undefined;\n }\n}\n\n/** Convenience wrapper so resources read as `paginate(fetch, params)`. */\nexport function paginate<T>(\n fetchPage: PageFetcher<T>,\n initial: PageParams = {},\n options: PaginateOptions = {},\n): Paginator<T> {\n return new Paginator(fetchPage, initial, options);\n}\n","import type { CanopyClient } from \"../client.js\";\nimport { paginate, type Paginator } from \"../pagination.js\";\nimport type { QueryParams, RequestBody, ResponseBody } from \"../schema.js\";\n\n/**\n * Role grants: which identity holds which role, at which node.\n *\n * A grant at a node applies to every descendant, which is what makes one\n * assignment cover a whole branch.\n */\nexport class Assignments {\n constructor(private readonly client: CanopyClient) {}\n\n /** Every assignment in the Application, across all nodes. */\n list(\n query: QueryParams<\"ApiAssignmentsController_listAppWideAssignments\"> = {},\n ): Paginator<AssignmentItem> {\n return paginate<AssignmentItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/assignments/app-wide\", {\n query: params,\n }),\n { ...query },\n );\n }\n\n /**\n * Grant a role at a node.\n *\n * Not retried automatically on a 5xx: a repeat could create a second grant,\n * and the server cannot tell the two apart. If the call fails without an\n * answer, read the current assignments before retrying.\n */\n create(\n input: RequestBody<\"ApiAssignmentsController_assignRole\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_assignRole\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments\", { body: input });\n }\n\n update(\n id: string,\n input: RequestBody<\"ApiAssignmentsController_updateAssignment\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_updateAssignment\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/assignments/${encodeURIComponent(id)}`,\n { body: input },\n );\n }\n\n delete(id: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/assignments/${encodeURIComponent(id)}`,\n );\n }\n\n /**\n * Grant many at once. Answers 207 with a per-item result rather than failing\n * the batch, so inspect `results` — a 2xx here does not mean every grant\n * succeeded.\n */\n bulkCreate(\n input: RequestBody<\"ApiAssignmentsController_bulkCreate\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_bulkCreate\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments/bulk-create\", {\n body: input,\n });\n }\n\n /** Same partial-success contract as `bulkCreate`. */\n bulkRemove(\n input: RequestBody<\"ApiAssignmentsController_bulkRemove\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_bulkRemove\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments/bulk-remove\", {\n body: input,\n });\n }\n\n /** Same partial-success contract as `bulkCreate`. */\n bulkChangeRole(\n input: RequestBody<\"ApiAssignmentsController_bulkChangeRole\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_bulkChangeRole\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments/bulk-change-role\", {\n body: input,\n });\n }\n}\n\nexport type AssignmentItem = ItemOf<\n ResponseBody<\"ApiAssignmentsController_listAppWideAssignments\">\n>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n","import type { CanopyClient } from \"../client.js\";\nimport { paginate, type Paginator } from \"../pagination.js\";\nimport type { QueryParams, RequestBody, ResponseBody } from \"../schema.js\";\n\n/** The end users of your application. */\nexport class Identities {\n constructor(private readonly client: CanopyClient) {}\n\n list(\n query: QueryParams<\"ApiIdentitiesController_listIdentities\"> = {},\n ): Paginator<IdentityItem> {\n return paginate<IdentityItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/identities\", { query: params }),\n { ...query },\n );\n }\n\n get(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_getIdentity\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}`,\n );\n }\n\n create(\n input: RequestBody<\"ApiIdentitiesController_createIdentity\">,\n ): Promise<ResponseBody<\"ApiIdentitiesController_createIdentity\">> {\n return this.client.request(\"POST\", \"/api/v1/identities\", { body: input });\n }\n\n update(\n id: string,\n input: RequestBody<\"ApiIdentitiesController_updateIdentity\">,\n ): Promise<ResponseBody<\"ApiIdentitiesController_updateIdentity\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/identities/${encodeURIComponent(id)}`,\n { body: input },\n );\n }\n\n delete(id: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/identities/${encodeURIComponent(id)}`,\n );\n }\n\n /**\n * Deactivation is the reversible counterpart to `delete` — sessions are\n * revoked and sign-in refused, but the identity and its assignments survive.\n * Prefer it for offboarding you may need to undo.\n */\n deactivate(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_deactivateIdentity\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/identities/${encodeURIComponent(id)}/deactivate`,\n );\n }\n\n activate(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_activateIdentity\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/identities/${encodeURIComponent(id)}/activate`,\n );\n }\n\n /**\n * Every role this identity holds, and where — across all pages.\n *\n * Paginated (20 per page by default), so this returns a `Paginator` rather\n * than one response. Reading a single page here would under-report what an\n * identity can do, which is the dangerous direction to be wrong in.\n *\n * ```ts\n * for await (const assignment of canopy.identities.assignments(id)) { … }\n * ```\n */\n assignments(\n id: string,\n query: QueryParams<\"ApiIdentitiesController_getIdentityAssignments\"> = {},\n ): Paginator<IdentityAssignmentItem> {\n return paginate<IdentityAssignmentItem>(\n (params) =>\n this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}/assignments`,\n { query: params },\n ),\n { ...query },\n );\n }\n\n /**\n * The permissions this identity effectively holds, inheritance resolved.\n *\n * For enforcing a single check, use `permissions.evaluate` — it answers one\n * question at the node that matters. This is for showing a person what\n * someone can do.\n */\n permissions(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_getIdentityPermissions\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}/permissions`,\n );\n }\n}\n\nexport type IdentityItem = ItemOf<\n ResponseBody<\"ApiIdentitiesController_listIdentities\">\n>;\n\n/** One role grant from an identity's assignments collection. */\nexport type IdentityAssignmentItem = ItemOf<\n ResponseBody<\"ApiIdentitiesController_getIdentityAssignments\">\n>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n","import type { components, operations } from \"./generated/types.js\";\n\n/**\n * Type plumbing that pulls request and response shapes straight out of the\n * generated operations.\n *\n * Every resource method is typed through these rather than by hand-writing an\n * interface. That is the whole discipline of this package: if the API adds a\n * required field, `npm run generate` brings it in and the call site stops\n * compiling. A hand-written mirror would keep compiling and start lying.\n */\n\n/** Any operation id in the public API. */\nexport type OperationId = keyof operations;\n\n/** The JSON request body an operation accepts, or `never` if it takes none. */\nexport type RequestBody<Id extends OperationId> = operations[Id] extends {\n requestBody: { content: { \"application/json\": infer Body } };\n}\n ? Body\n : operations[Id] extends {\n requestBody?: { content: { \"application/json\": infer Body } };\n }\n ? Body\n : never;\n\n/**\n * The JSON payload of an operation's success response, with Canopy's envelope\n * already removed — `{ data }` unwrapped, collections left whole — matching\n * what `CanopyClient.request` actually returns.\n */\nexport type ResponseBody<Id extends OperationId> = Unwrap<SuccessJson<Id>>;\n\ntype SuccessJson<Id extends OperationId> =\n operations[Id][\"responses\"] extends infer Responses\n ? Responses extends Record<string, unknown>\n ? SuccessOf<Responses>\n : never\n : never;\n\n// 200, 201 and 207 are the success codes this API returns; 204 carries nothing.\ntype SuccessOf<Responses> = Responses extends {\n 200: { content: { \"application/json\": infer Json } };\n}\n ? Json\n : Responses extends { 201: { content: { \"application/json\": infer Json } } }\n ? Json\n : Responses extends { 207: { content: { \"application/json\": infer Json } } }\n ? Json\n : undefined;\n\n/** Mirrors the envelope handling in `CanopyClient.request`. */\ntype Unwrap<Json> = Json extends { data: infer Data } ? Data : Json;\n\n/** Query parameters an operation accepts, when it declares any. */\nexport type QueryParams<Id extends OperationId> = operations[Id] extends {\n parameters: { query?: infer Query };\n}\n ? NonNullable<Query>\n : Record<string, never>;\n\n/** Shorthand for a named schema, e.g. `Schema<\"EvaluateResponseDto\">`. */\nexport type Schema<Name extends keyof components[\"schemas\"]> =\n components[\"schemas\"][Name];\n\n/**\n * Optimistic concurrency, on the operations whose spec declares `If-Match`.\n *\n * Pass the `version` you read off the resource. If someone else has changed it\n * since, the API answers 409 rather than letting the write silently clobber\n * theirs — so this is how a read-modify-write is made safe.\n */\nexport interface ConcurrencyOptions {\n ifMatch?: string;\n}\n\n/**\n * The `If-Match` header for a call that supports it, shaped to be spread into\n * `RequestOptions`.\n *\n * Spreadable rather than returning `headers: undefined`, which\n * `exactOptionalPropertyTypes` rejects — an absent property and one explicitly\n * set to undefined are not the same thing here.\n */\nexport function withConcurrency(\n options: ConcurrencyOptions = {},\n): { headers: Record<string, string> } | Record<string, never> {\n if (options.ifMatch === undefined) {\n return {};\n }\n\n return { headers: { \"If-Match\": options.ifMatch } };\n}\n","import type { CallOptions, CanopyClient } from \"../client.js\";\nimport { paginate, type Paginator } from \"../pagination.js\";\nimport { withConcurrency } from \"../schema.js\";\nimport type {\n ConcurrencyOptions,\n QueryParams,\n RequestBody,\n ResponseBody,\n} from \"../schema.js\";\n\n/**\n * Permissions, and the authorization decision itself.\n *\n * `evaluate` is the call an integrator makes on every request, so it is the one\n * worth reading first.\n */\nexport class Permissions {\n constructor(private readonly client: CanopyClient) {}\n\n /**\n * Ask whether an identity holds a permission.\n *\n * With `scope: \"node\"` the engine walks the node's lineage, so a permission\n * granted on an ancestor is inherited at `node_id`. With `scope: \"app_wide\"`\n * it answers the coarse \"anywhere in this Application\" question and returns\n * `effective_node_id: null` — that answer must never be used to guard a\n * resource that belongs to a specific node, which is why the scope is a\n * required field rather than a default.\n *\n * This runs on the request path, so it is the call most worth passing\n * `signal` and a tight `timeoutMs` to: without them a slow answer here holds\n * an inbound request open for the client-wide deadline on every attempt.\n */\n evaluate(\n input: RequestBody<\"ApiPermissionsController_evaluate\">,\n options: CallOptions = {},\n ): Promise<ResponseBody<\"ApiPermissionsController_evaluate\">> {\n return this.client.request(\"POST\", \"/api/v1/permissions/evaluate\", {\n body: input,\n // A POST only because the question travels in a body; it computes a\n // decision and writes nothing, so repeating it is safe — and this is the\n // call least able to afford giving up on a transient 5xx.\n idempotent: true,\n ...options,\n });\n }\n\n /**\n * Evaluate many decisions in one round trip.\n *\n * Prefer this to a loop over `evaluate` when rendering a screen: the checks\n * are answered together instead of paying request latency for each.\n */\n evaluateBulk(\n input: RequestBody<\"ApiPermissionsController_evaluateBulk\">,\n options: CallOptions = {},\n ): Promise<ResponseBody<\"ApiPermissionsController_evaluateBulk\">> {\n return this.client.request(\"POST\", \"/api/v1/permissions/evaluate/bulk\", {\n body: input,\n /** Read-only, like `evaluate`. */\n idempotent: true,\n ...options,\n });\n }\n\n /**\n * The same decision with its reasoning — which role granted it, which node\n * it was inherited from. For debugging an unexpected allow or deny, not for\n * the enforcement path.\n */\n explain(\n input: RequestBody<\"ApiPermissionsController_explain\">,\n options: CallOptions = {},\n ): Promise<ResponseBody<\"ApiPermissionsController_explain\">> {\n return this.client.request(\"POST\", \"/api/v1/permissions/evaluate/explain\", {\n body: input,\n /** Read-only, like `evaluate`. */\n idempotent: true,\n ...options,\n });\n }\n\n /** Every permission in the Environment, page by page. */\n list(\n query: QueryParams<\"ApiPermissionsController_listPermissions\"> = {},\n ): Paginator<PermissionItem> {\n return paginate<PermissionItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/permissions\", { query: params }),\n { ...query },\n );\n }\n\n get(\n id: string,\n ): Promise<ResponseBody<\"ApiPermissionsController_getPermission\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/permissions/${encodeURIComponent(id)}`,\n );\n }\n\n /** Define permissions. The request takes a batch, not a single key. */\n create(\n input: RequestBody<\"ApiPermissionsController_createPermissions\">,\n ): Promise<ResponseBody<\"ApiPermissionsController_createPermissions\">> {\n return this.client.request(\"POST\", \"/api/v1/permissions\", { body: input });\n }\n\n /**\n * Pass `ifMatch` with the permission's current `version` to make a\n * read-modify-write safe — a concurrent edit answers 409 instead of being\n * silently overwritten.\n */\n update(\n id: string,\n input: RequestBody<\"ApiPermissionsController_updatePermission\">,\n options: ConcurrencyOptions = {},\n ): Promise<ResponseBody<\"ApiPermissionsController_updatePermission\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/permissions/${encodeURIComponent(id)}`,\n { body: input, ...withConcurrency(options) },\n );\n }\n\n delete(id: string, options: ConcurrencyOptions = {}): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/permissions/${encodeURIComponent(id)}`,\n withConcurrency(options),\n );\n }\n}\n\n/**\n * One item from the permissions collection.\n *\n * Read off the list response rather than named directly, so it follows the\n * spec instead of being a second declaration of it.\n */\nexport type PermissionItem = ItemOf<\n ResponseBody<\"ApiPermissionsController_listPermissions\">\n>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n","import type { CanopyClient } from \"../client.js\";\nimport { paginate, type Paginator } from \"../pagination.js\";\nimport { withConcurrency } from \"../schema.js\";\nimport type {\n ConcurrencyOptions,\n QueryParams,\n RequestBody,\n ResponseBody,\n} from \"../schema.js\";\n\n/** Named bundles of permissions. */\nexport class Roles {\n constructor(private readonly client: CanopyClient) {}\n\n list(\n query: QueryParams<\"ApiRolesController_listRoles\"> = {},\n ): Paginator<RoleItem> {\n return paginate<RoleItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/roles\", { query: params }),\n { ...query },\n );\n }\n\n get(id: string): Promise<ResponseBody<\"ApiRolesController_getRole\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/roles/${encodeURIComponent(id)}`,\n );\n }\n\n create(\n input: RequestBody<\"ApiRolesController_createRole\">,\n ): Promise<ResponseBody<\"ApiRolesController_createRole\">> {\n return this.client.request(\"POST\", \"/api/v1/roles\", { body: input });\n }\n\n /**\n * Pass `ifMatch` with the role's current `version` to make a\n * read-modify-write safe — a concurrent edit answers 409 instead of being\n * silently overwritten.\n */\n update(\n id: string,\n input: RequestBody<\"ApiRolesController_updateRole\">,\n options: ConcurrencyOptions = {},\n ): Promise<ResponseBody<\"ApiRolesController_updateRole\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/roles/${encodeURIComponent(id)}`,\n { body: input, ...withConcurrency(options) },\n );\n }\n\n delete(id: string, options: ConcurrencyOptions = {}): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/roles/${encodeURIComponent(id)}`,\n withConcurrency(options),\n );\n }\n\n permissions(\n id: string,\n ): Promise<ResponseBody<\"ApiRolesController_getRolePermissions\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/roles/${encodeURIComponent(id)}/permissions`,\n );\n }\n\n /**\n * Replaces the role's permissions wholesale — this is a PUT, so anything\n * absent from `input` is removed. Read `permissions` first if you mean to add.\n */\n setPermissions(\n id: string,\n input: RequestBody<\"ApiRolesController_setRolePermissions\">,\n ): Promise<ResponseBody<\"ApiRolesController_setRolePermissions\">> {\n return this.client.request(\n \"PUT\",\n `/api/v1/roles/${encodeURIComponent(id)}/permissions`,\n { body: input },\n );\n }\n}\n\nexport type RoleItem = ItemOf<ResponseBody<\"ApiRolesController_listRoles\">>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n","import { CanopyClient, type CanopyClientOptions } from \"./client.js\";\nimport { Assignments } from \"./resources/assignments.js\";\nimport { Identities } from \"./resources/identities.js\";\nimport { Permissions } from \"./resources/permissions.js\";\nimport { Roles } from \"./resources/roles.js\";\n\n/**\n * The entry point most callers want.\n *\n * ```ts\n * const canopy = new Canopy({ apiKey: process.env.CANOPY_API_KEY });\n *\n * const { allowed } = await canopy.permissions.evaluate({\n * identity_id: identityId,\n * permission: \"documents.read\",\n * scope: \"node\",\n * node_id: nodeId,\n * });\n * ```\n *\n * `client` is public because the wrapped resources cover the paths integrators\n * hit most, not all 81 operations. Anything not wrapped is still reachable —\n * `canopy.client.request(\"GET\", \"/api/v1/audit-events\")` — with the same\n * envelope handling, typed errors and retry policy, so no endpoint is a dead\n * end while the ergonomic surface catches up.\n */\nexport class Canopy {\n readonly client: CanopyClient;\n readonly permissions: Permissions;\n readonly identities: Identities;\n readonly roles: Roles;\n readonly assignments: Assignments;\n\n constructor(options: CanopyClientOptions) {\n this.client = new CanopyClient(options);\n this.permissions = new Permissions(this.client);\n this.identities = new Identities(this.client);\n this.roles = new Roles(this.client);\n this.assignments = new Assignments(this.client);\n }\n}\n","import type { CanopyClient, RequestOptions } from \"./client.js\";\nimport { CanopyAuthorizerError } from \"./errors.js\";\nimport type { ResponseBody } from \"./schema.js\";\n\n/**\n * Answers permission checks in-process instead of asking Canopy each time.\n *\n * The inversion this rests on: rather than asking \"may this identity act\n * *here*\" per request, ask \"*where* may it act\" once. Canopy answers with the\n * nodes each permission was granted at — the grant roots, deliberately not\n * expanded through their descendants, because a grant already means \"this node\n * and everything beneath it\". Expanding would restate the hierarchy once per\n * identity, and would be largest for the near-root grants administrators hold.\n *\n * So two things are cached, split by what they depend on:\n *\n * - grant roots, per identity — small, a handful of assignments\n * - the hierarchy, once per process — shared, since its shape does not\n * depend on who is asking\n *\n * and a check becomes a walk up from the node in question looking for a grant\n * root. Both are held for at most `ttlMs`, which is therefore the delay\n * between an access change and it taking effect.\n */\n\nconst DEFAULT_TTL_MS = 60_000;\n\n/**\n * A tree deep enough to hit this is malformed. The server bounds depth with\n * the hierarchy schema, but a client walking a structure it was handed should\n * not loop forever if that assumption ever fails.\n */\nconst MAX_WALK_DEPTH = 256;\n\nexport interface LocalAuthorizerOptions {\n /**\n * How long grant roots and the hierarchy are reused, in milliseconds.\n * Defaults to 60s.\n *\n * This is a staleness budget, not a performance dial. Shortening it makes\n * revocation take effect sooner and costs more calls — and below the gap\n * between a user's requests it stops saving anything at all, because every\n * request finds the cache expired and refetches. Human-paced traffic has\n * multi-second gaps, so a value of a few seconds can cost full price for no\n * benefit.\n *\n * **`0` disables caching**, reading fresh on every check. That is the escape\n * for a caller who cannot accept a stale allow at all — it costs a round trip\n * per request, which is what this class exists to avoid, so reach for it\n * knowingly rather than as a default.\n */\n ttlMs?: number;\n\n /**\n * Per-attempt deadline for the reads this class makes.\n *\n * A cache hit costs nothing, but a miss happens on the request path and\n * holds an inbound request open exactly as a per-request check used to — so\n * the bound still matters, it just applies far less often.\n */\n timeoutMs?: number;\n\n /** Retries for those reads. */\n maxRetries?: number;\n\n /** Injectable clock, for tests. */\n now?: () => number;\n}\n\nexport interface LocalAuthorizationQuery {\n identity_id: string;\n permission: string;\n /** Defaults to `node`, which is the strict question. */\n scope?: \"node\" | \"app_wide\";\n node_id?: string;\n}\n\nexport interface LocalAuthorizerStats {\n /** Calls made to read an identity's grant roots. */\n grantFetches: number;\n /** Calls made to read the hierarchy, including revalidations. */\n treeRequests: number;\n /** Revalidations the server answered `304`, so no tree was transferred. */\n treeNotModified: number;\n}\n\ninterface GrantEntry {\n roots: Map<string, Set<string>>;\n expiresAt: number;\n}\n\ninterface TreeEntry {\n parents: Map<string, string | null>;\n etag: string | null;\n expiresAt: number;\n}\n\n/**\n * The grant map, read off the generated operation rather than restated here.\n *\n * Load-bearing beyond tidiness: typing this through the spec is what stops the\n * package building against a Canopy that does not serve the endpoint. A\n * hand-written shape compiles happily and then 404s on every guarded request\n * at runtime, which the guard turns into a blanket `403` — a failure no test\n * with a faked endpoint can see.\n */\ntype GrantMap = ResponseBody<\"ApiIdentitiesController_getIdentityGrants\">;\n\n/**\n * The hierarchy as parent edges, read off the generated operation.\n *\n * Deliberately not the tree. `GET /api/v1/nodes` answers what a dashboard\n * renders — names, statuses, access flags, per-node counts — and a walk upward\n * reads none of it. Measured at 50,000 nodes that is 18.6 MB against 5.0 MB,\n * on a read every consuming process makes at startup.\n */\ntype ParentEdges = ResponseBody<\"ApiNodesController_listNodeParents\">;\n\nexport class LocalAuthorizer {\n private readonly client: CanopyClient;\n private readonly ttlMs: number;\n private readonly now: () => number;\n private readonly readOptions: RequestOptions;\n\n private readonly grants = new Map<string, GrantEntry>();\n private tree: TreeEntry | undefined;\n\n /**\n * In-flight reads, so concurrent requests for the same thing share one call.\n *\n * Without this a cold start under load fans out: a hundred simultaneous\n * requests for one identity would each miss the cache and each fetch, which\n * is the per-request traffic this class exists to remove, concentrated into\n * the worst possible moment.\n */\n private readonly pendingGrants = new Map<\n string,\n Promise<Map<string, Set<string>>>\n >();\n private pendingTree: Promise<Map<string, string | null>> | undefined;\n\n private stats: LocalAuthorizerStats = {\n grantFetches: 0,\n treeRequests: 0,\n treeNotModified: 0,\n };\n\n constructor(client: CanopyClient, options: LocalAuthorizerOptions = {}) {\n this.client = client;\n this.ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;\n this.now = options.now ?? (() => Date.now());\n\n this.readOptions = {\n ...(options.timeoutMs === undefined\n ? {}\n : { timeoutMs: options.timeoutMs }),\n ...(options.maxRetries === undefined\n ? {}\n : { maxRetries: options.maxRetries, maxBackoffMs: options.timeoutMs }),\n };\n }\n\n /**\n * Whether the identity holds the permission.\n *\n * Shaped like the API's own evaluate so a caller can swap one for the other.\n * A `node` check with no node is a denial rather than an error: a request\n * whose subject cannot be established is exactly the one that must not pass.\n */\n async evaluate(\n query: LocalAuthorizationQuery,\n options: { signal?: AbortSignal } = {},\n ): Promise<{ allowed: boolean }> {\n if (!options.signal) {\n return this.decide(query);\n }\n\n // Raced rather than passed down. A read in flight may be shared with other\n // requests — that sharing is the point of the dedup — so cancelling it\n // because *this* caller hung up would abort a fetch the others are still\n // waiting on. Racing ends this call and leaves theirs alone; the fetch runs\n // to completion and warms the cache either way.\n const signal = options.signal;\n\n let onAbort: (() => void) | undefined;\n\n const aborted = new Promise<never>((_resolve, reject) => {\n const fail = (): void => {\n // `reason` is whatever the caller passed to `abort()`, which need not\n // be an Error. Keep it when it is, so the original cause survives.\n reject(\n signal.reason instanceof Error\n ? signal.reason\n : new Error(String(signal.reason ?? \"aborted\")),\n );\n };\n\n if (signal.aborted) {\n fail();\n\n return;\n }\n\n onAbort = fail;\n signal.addEventListener(\"abort\", fail, { once: true });\n });\n\n // Removed however the race ends, not only when it aborts. `once: true`\n // detaches a listener after it *fires*, which is the case that does not\n // need cleaning up; the common one — the decision winning — would otherwise\n // leave a listener attached for the life of the signal. Harmless for a\n // per-request controller, a leak for any longer-lived one a caller passes.\n return Promise.race([this.decide(query), aborted]).finally(() => {\n if (onAbort) {\n signal.removeEventListener(\"abort\", onAbort);\n }\n });\n }\n\n private async decide(\n query: LocalAuthorizationQuery,\n ): Promise<{ allowed: boolean }> {\n const roots = await this.grantRootsFor(query.identity_id);\n const granted = roots.get(query.permission);\n\n if (!granted || granted.size === 0) {\n return { allowed: false };\n }\n\n if ((query.scope ?? \"node\") === \"app_wide\") {\n return { allowed: true };\n }\n\n if (!query.node_id) {\n return { allowed: false };\n }\n\n return { allowed: await this.holdsAtNode(granted, query.node_id) };\n }\n\n /** Counters for observability — how much traffic the cache is actually saving. */\n snapshot(): LocalAuthorizerStats {\n return { ...this.stats };\n }\n\n /**\n * Drop what is held so the next evaluate refetches.\n *\n * With an `identityId`, only that identity's grants are dropped — the\n * cached hierarchy and every other identity's entries stay warm. This is\n * the shape an assignment webhook wants: the event names the identity\n * whose authority moved, and nothing else needs to pay a refetch for it.\n *\n * With no argument, everything goes: grants and the hierarchy tree. Not\n * needed in normal operation, where entries expire on their own; useful in\n * tests and after a change whose reach you cannot name (a role's\n * permissions edited, a node moved).\n *\n * Multi-instance honesty: an invalidation reaches THIS process only. A\n * webhook lands on one instance behind a load balancer; the others serve\n * their cached grants until their own TTL expires. Unless the app fans the\n * event out over its own pub/sub, the fleet-wide revocation guarantee is\n * the TTL, and webhook-driven invalidation is a latency optimization on\n * top of it — size the TTL to the revocation latency you can promise.\n */\n invalidate(identityId?: string): void {\n if (identityId !== undefined) {\n this.grants.delete(identityId);\n\n return;\n }\n\n this.grants.clear();\n this.tree = undefined;\n }\n\n /** Climb from `nodeId` and look for a grant root among its ancestors. */\n private async holdsAtNode(\n granted: Set<string>,\n nodeId: string,\n ): Promise<boolean> {\n // Checked before walking, so a grant at the node itself needs no tree at\n // all — which also means an unreachable hierarchy cannot deny a direct\n // grant that was already resolved.\n if (granted.has(nodeId)) {\n return true;\n }\n\n const parents = await this.parents();\n\n // The hierarchy we hold has to actually contain the node being asked\n // about. `GET /api/v1/nodes` answers a tree scoped to the caller, and a\n // credential that cannot read the hierarchy gets an empty one — with a\n // `200`, so nothing looks wrong. Walking off the end of that map would\n // return `false`, which reads as \"this identity lacks the permission\n // here\" when the truth is that we cannot see far enough to say.\n //\n // Denying would be a silent, total false-deny on every node-scoped route.\n // Undecidable is not denied, so this is raised rather than answered.\n if (!parents.has(nodeId)) {\n throw new CanopyAuthorizerError(\n \"authorizer.hierarchy_incomplete\",\n `The hierarchy this client can read does not contain node \"${nodeId}\", so authorization at that node cannot be decided. ` +\n \"A scoped API key needs the `hierarchy.view` scope to read the tree.\",\n );\n }\n\n let current = parents.get(nodeId);\n let depth = 0;\n\n while (current && depth < MAX_WALK_DEPTH) {\n if (granted.has(current)) {\n return true;\n }\n\n current = parents.get(current);\n depth += 1;\n }\n\n return false;\n }\n\n private async grantRootsFor(\n identityId: string,\n ): Promise<Map<string, Set<string>>> {\n const cached = this.grants.get(identityId);\n\n if (cached && cached.expiresAt > this.now()) {\n return cached.roots;\n }\n\n const pending = this.pendingGrants.get(identityId);\n\n if (pending) {\n return pending;\n }\n\n const read = this.fetchGrantRoots(identityId).finally(() => {\n this.pendingGrants.delete(identityId);\n });\n\n this.pendingGrants.set(identityId, read);\n\n return read;\n }\n\n private async fetchGrantRoots(\n identityId: string,\n ): Promise<Map<string, Set<string>>> {\n this.stats.grantFetches += 1;\n\n const response = await this.client.request<GrantMap>(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(identityId)}/grants`,\n this.readOptions,\n );\n\n const roots = new Map<string, Set<string>>();\n\n for (const row of response.items ?? []) {\n roots.set(row.permission, new Set(row.nodes));\n }\n\n this.grants.set(identityId, {\n roots,\n expiresAt: this.now() + this.ttlMs,\n });\n\n return roots;\n }\n\n private async parents(): Promise<Map<string, string | null>> {\n if (this.tree && this.tree.expiresAt > this.now()) {\n return this.tree.parents;\n }\n\n if (this.pendingTree) {\n return this.pendingTree;\n }\n\n const read = this.fetchTree().finally(() => {\n this.pendingTree = undefined;\n });\n\n this.pendingTree = read;\n\n return read;\n }\n\n /**\n * Revalidate rather than re-read. The hierarchy is the expensive half and\n * the one that changes least, so the common case is a `304` and no transfer\n * at all — the tree stays in memory and only its expiry moves.\n */\n private async fetchTree(): Promise<Map<string, string | null>> {\n this.stats.treeRequests += 1;\n\n const held = this.tree;\n\n const result = await this.client.requestConditional<ParentEdges>(\n \"GET\",\n \"/api/v1/nodes/parents\",\n held?.etag ?? undefined,\n this.readOptions,\n );\n\n if (!result.modified && held) {\n this.stats.treeNotModified += 1;\n this.tree = { ...held, expiresAt: this.now() + this.ttlMs };\n\n return held.parents;\n }\n\n const parents = new Map<string, string | null>();\n\n if (result.modified) {\n for (const edge of result.data.items) {\n parents.set(edge.id, edge.parent_node_id ?? null);\n }\n }\n\n this.tree = {\n parents,\n etag: result.modified ? result.etag : (held?.etag ?? null),\n expiresAt: this.now() + this.ttlMs,\n };\n\n return parents;\n }\n}\n","import { CanopyTokenError } from \"./errors.js\";\n\n/**\n * Local verification of a Canopy access token.\n *\n * Canopy signs access tokens with RS256 and publishes the matching public keys\n * at `/.well-known/jwks.json`, so a token can be checked entirely in-process:\n * fetch the keys once, then every verification after that is a signature check\n * with no network call. This is why authentication does not cost a round trip\n * the way an authorization check does.\n *\n * Verification is the part of an integration that is easiest to get subtly\n * wrong — accepting `alg: none`, trusting `kid` without bounding refetches,\n * skipping `aud` when the token carries one, treating a pre-auth token as a\n * session. Each of those is handled here so a caller does not have to know\n * they exist.\n *\n * ```ts\n * const verifier = new TokenVerifier();\n * const claims = await verifier.verify(token);\n * ```\n *\n * Deliberately standalone rather than a member of {@link Canopy}: that client\n * requires an API key or an access token, and a backend that only checks\n * logins holds neither.\n */\n\n/** Canopy's hosted issuer. Matches the client's default base URL. */\nconst DEFAULT_ISSUER = \"https://auth.canopy-io.com\";\n\n/** How long a fetched key set is reused before being refreshed. */\nconst DEFAULT_JWKS_CACHE_MAX_AGE_MS = 10 * 60 * 1000;\n\n/**\n * Floor between JWKS fetches triggered by an unknown `kid`.\n *\n * Key rotation means an unrecognised `kid` is sometimes legitimate, so a miss\n * has to be able to refetch. Left unbounded, that is also a free amplifier: a\n * forged token carrying a random `kid` would make this process call the issuer\n * once per request. The floor keeps rotation working while capping the damage\n * at one fetch per interval.\n */\nconst DEFAULT_JWKS_MIN_REFETCH_INTERVAL_MS = 30 * 1000;\n\n/**\n * Deadline for one JWKS read.\n *\n * Verification happens on the request path, so an unbounded read here is an\n * unbounded inbound request: an issuer that accepts the connection and then\n * goes quiet would hold every caller that needs a key, indefinitely.\n */\nconst DEFAULT_JWKS_TIMEOUT_MS = 5_000;\n\n/** The principal kinds a Canopy token may claim to be. */\nconst PRINCIPAL_TYPES = new Set([\"user\", \"identity\", \"api_key\", \"platform\"]);\n\n/**\n * Leeway applied to time-based claims, for ordinary clock drift between the\n * issuer and this machine. Seconds, not minutes: a generous window here\n * extends the life of a token that should have expired.\n */\nconst DEFAULT_CLOCK_TOLERANCE_SEC = 60;\n\nexport interface TokenVerifierOptions {\n /**\n * The issuer whose tokens are accepted, matched against `iss` exactly.\n * Defaults to Canopy's hosted issuer; set it for a self-hosted instance.\n *\n * Safe to default because it fails closed: pointed at the wrong issuer, a\n * token is rejected rather than accepted.\n */\n issuer?: string;\n\n /**\n * Required audience, matched against `aud`.\n *\n * Hosted Login (OAuth) tokens carry `aud` — your client id — and Direct API\n * identity tokens do not. Verifying an OAuth token without setting this\n * throws rather than ignoring the claim, because `aud` is what stops a token\n * minted for one client being replayed at another.\n */\n audience?: string;\n\n /** Where the signing keys live. Defaults to `${issuer}/.well-known/jwks.json`. */\n jwksUri?: string;\n\n /** How long a fetched key set is reused. Defaults to 10 minutes. */\n jwksCacheMaxAgeMs?: number;\n\n /** Floor between refetches provoked by an unknown `kid`. Defaults to 30s. */\n jwksMinRefetchIntervalMs?: number;\n\n /** Leeway on `exp` and `nbf`, in seconds. Defaults to 60. */\n clockToleranceSec?: number;\n\n /**\n * Accept pre-auth tokens. Defaults to `false`, and should stay false unless\n * you are building an account picker.\n *\n * A pre-auth token is a genuine, correctly-signed Canopy token issued\n * partway through a multi-account login: the person proved their password\n * but has not yet chosen an Account, so the token carries no Account context\n * and grants nothing. Accepting one as a session is a privilege escalation,\n * and it is the failure a hand-rolled verifier is most likely to miss —\n * every signature check passes.\n */\n allowPreAuthTokens?: boolean;\n\n /**\n * Deadline for a single JWKS read, in milliseconds. Defaults to 5s.\n *\n * Without one, an issuer that accepts a connection and then never answers\n * holds every inbound request that needs a key — the verification sits on the\n * request path, so an unbounded read there is an unbounded request.\n */\n jwksTimeoutMs?: number;\n\n /** Injectable for tests and for runtimes with a non-global fetch. */\n fetch?: typeof globalThis.fetch;\n}\n\n/**\n * The claims Canopy puts in an access token.\n *\n * Named claims are the ones the API guarantees; the index signature keeps\n * anything added later reachable without a version bump.\n */\nexport interface CanopyTokenClaims {\n /** The identity or user this token acts as. */\n sub: string;\n /** Which kind of principal `sub` is. */\n type: \"user\" | \"identity\" | \"api_key\" | \"platform\";\n iss: string;\n exp: number;\n iat?: number;\n nbf?: number;\n aud?: string | string[];\n account_id?: string;\n application_id?: string;\n /** Identity tokens carry this; admin tokens deliberately omit it. */\n environment_id?: string;\n account_slug?: string;\n application_slug?: string;\n environment_slug?: string;\n /** Present only on a pre-auth token — see `allowPreAuthTokens`. */\n token_type?: \"preauth\";\n console_access?: \"granted\" | \"none\";\n /** Emitted only when the `permissions` OAuth scope was granted. */\n permissions?: string[];\n /** True when `permissions` was truncated; query the API for the full set. */\n permissions_overflow?: boolean;\n [claim: string]: unknown;\n}\n\ninterface JwksKey {\n kid?: string;\n kty?: string;\n alg?: string;\n use?: string;\n n?: string;\n e?: string;\n}\n\ninterface JwtHeader {\n alg?: string;\n kid?: string;\n typ?: string;\n}\n\n/** base64url → bytes, without assuming Buffer (this runs in workers too). */\nfunction decodeBase64Url(value: string): Uint8Array<ArrayBuffer> {\n const padded = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(padded.padEnd(Math.ceil(padded.length / 4) * 4, \"=\"));\n const bytes = new Uint8Array(new ArrayBuffer(binary.length));\n\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n\n return bytes;\n}\n\nfunction decodeJsonSegment(segment: string, what: string): unknown {\n try {\n return JSON.parse(new TextDecoder().decode(decodeBase64Url(segment)));\n } catch (cause) {\n throw new CanopyTokenError(\n \"token.malformed\",\n `Token ${what} is not valid base64url-encoded JSON.`,\n { cause },\n );\n }\n}\n\nexport class TokenVerifier {\n private readonly issuer: string;\n private readonly audience: string | undefined;\n private readonly jwksUri: string;\n private readonly jwksCacheMaxAgeMs: number;\n private readonly jwksMinRefetchIntervalMs: number;\n private readonly jwksTimeoutMs: number;\n private readonly clockToleranceSec: number;\n private readonly allowPreAuthTokens: boolean;\n private readonly fetchImpl: typeof globalThis.fetch;\n\n /** Imported keys by `kid`, so a repeat verification skips the import cost. */\n private keys = new Map<string, CryptoKey>();\n private keysFetchedAt = 0;\n private lastFetchAttemptAt = 0;\n /** In-flight fetch, so a burst of requests triggers one call, not N. */\n private inFlight: Promise<void> | null = null;\n\n constructor(options: TokenVerifierOptions = {}) {\n this.issuer = (options.issuer ?? DEFAULT_ISSUER).replace(/\\/+$/, \"\");\n this.audience = options.audience;\n this.jwksUri = options.jwksUri ?? `${this.issuer}/.well-known/jwks.json`;\n this.jwksCacheMaxAgeMs =\n options.jwksCacheMaxAgeMs ?? DEFAULT_JWKS_CACHE_MAX_AGE_MS;\n this.jwksMinRefetchIntervalMs =\n options.jwksMinRefetchIntervalMs ?? DEFAULT_JWKS_MIN_REFETCH_INTERVAL_MS;\n this.jwksTimeoutMs = options.jwksTimeoutMs ?? DEFAULT_JWKS_TIMEOUT_MS;\n this.clockToleranceSec =\n options.clockToleranceSec ?? DEFAULT_CLOCK_TOLERANCE_SEC;\n this.allowPreAuthTokens = options.allowPreAuthTokens ?? false;\n\n const boundFetch = options.fetch ?? globalThis.fetch;\n\n if (typeof boundFetch !== \"function\") {\n throw new TypeError(\n \"TokenVerifier requires a fetch implementation. Pass `fetch` on Node runtimes without a global one.\",\n );\n }\n\n this.fetchImpl = boundFetch.bind(globalThis);\n }\n\n /**\n * Verify a token and return its claims. Throws {@link CanopyTokenError} on\n * anything short of a full pass — branch on `error.code`.\n *\n * Order matters: the signature is checked before any claim is believed, so\n * nothing downstream ever reads an unverified payload.\n */\n async verify(token: string): Promise<CanopyTokenClaims> {\n const parts = token.split(\".\");\n\n if (parts.length !== 3) {\n throw new CanopyTokenError(\n \"token.malformed\",\n \"Token is not a three-part JWS.\",\n );\n }\n\n const [encodedHeader, encodedPayload, encodedSignature] = parts as [\n string,\n string,\n string,\n ];\n\n const header = decodeJsonSegment(encodedHeader, \"header\") as JwtHeader;\n\n // Pinned, not merely checked: accepting whatever `alg` the token names is\n // how `none` and HMAC-key-confusion attacks get in.\n if (header.alg !== \"RS256\") {\n throw new CanopyTokenError(\n \"token.unsupported_algorithm\",\n `Token is signed with \"${header.alg ?? \"none\"}\"; Canopy issues RS256.`,\n );\n }\n\n const key = await this.resolveKey(header.kid);\n const signed = new TextEncoder().encode(\n `${encodedHeader}.${encodedPayload}`,\n );\n\n let signatureValid: boolean;\n\n try {\n signatureValid = await crypto.subtle.verify(\n \"RSASSA-PKCS1-v1_5\",\n key,\n decodeBase64Url(encodedSignature),\n signed,\n );\n } catch (cause) {\n throw new CanopyTokenError(\n \"token.malformed\",\n \"Token signature is not decodable.\",\n { cause },\n );\n }\n\n if (!signatureValid) {\n throw new CanopyTokenError(\n \"token.signature_invalid\",\n \"Token signature does not match Canopy's signing key.\",\n );\n }\n\n const claims = decodeJsonSegment(\n encodedPayload,\n \"payload\",\n ) as CanopyTokenClaims;\n\n this.assertClaims(claims);\n\n return claims;\n }\n\n /** Everything checked after the signature is known good. */\n private assertClaims(claims: CanopyTokenClaims): void {\n // Checked, not assumed. The claims arrive as parsed JSON and are cast to\n // this interface, so anything the interface declares but nobody verifies is\n // a promise the type makes and the runtime does not keep. `sub` is the\n // whole point of a verified token — a caller reads it to decide who is\n // acting — and a `string` that is actually `undefined` is worse than a\n // rejected token, because it looks like an answer.\n if (typeof claims.sub !== \"string\" || claims.sub === \"\") {\n throw new CanopyTokenError(\n \"token.malformed\",\n \"Token has no `sub` claim, so it identifies no one.\",\n );\n }\n\n // Same reasoning. `type` narrows to four values, and code branches on it;\n // a fifth would flow through a `switch` as though it were one of them.\n if (!PRINCIPAL_TYPES.has(claims.type)) {\n throw new CanopyTokenError(\n \"token.malformed\",\n `Token has an unrecognised \\`type\\` claim: ${JSON.stringify(claims.type)}.`,\n );\n }\n\n if (claims.iss !== this.issuer) {\n throw new CanopyTokenError(\n \"token.issuer_mismatch\",\n `Token was issued by \"${String(claims.iss)}\", not \"${this.issuer}\".`,\n );\n }\n\n const now = Math.floor(Date.now() / 1000);\n\n if (typeof claims.exp !== \"number\") {\n throw new CanopyTokenError(\n \"token.malformed\",\n \"Token has no `exp` claim.\",\n );\n }\n\n if (now > claims.exp + this.clockToleranceSec) {\n throw new CanopyTokenError(\"token.expired\", \"Token has expired.\");\n }\n\n if (\n typeof claims.nbf === \"number\" &&\n now < claims.nbf - this.clockToleranceSec\n ) {\n throw new CanopyTokenError(\n \"token.not_yet_valid\",\n \"Token is not valid yet.\",\n );\n }\n\n this.assertAudience(claims);\n\n if (claims.token_type === \"preauth\" && !this.allowPreAuthTokens) {\n throw new CanopyTokenError(\n \"token.preauth_not_allowed\",\n \"This is a pre-auth token: the user authenticated but has not selected an Account, so it grants no access. \" +\n \"Set `allowPreAuthTokens: true` only if you are building the account picker.\",\n );\n }\n }\n\n /**\n * `aud` is checked when either side mentions it.\n *\n * The case worth stating: a token carries `aud` but the verifier was not\n * configured with one. That is not \"no audience to check\" — it is an OAuth\n * token being verified by something that never said which client it is, and\n * ignoring it would accept a token minted for a different client. So it\n * throws and names the option.\n */\n private assertAudience(claims: CanopyTokenClaims): void {\n const audiences =\n claims.aud === undefined\n ? []\n : Array.isArray(claims.aud)\n ? claims.aud\n : [claims.aud];\n\n if (this.audience === undefined) {\n if (audiences.length > 0) {\n throw new CanopyTokenError(\n \"token.audience_unverified\",\n \"Token carries an `aud` claim but the verifier has no `audience` configured. \" +\n \"Set `audience` to your OAuth client id; Direct API tokens carry no audience and need no option.\",\n );\n }\n\n return;\n }\n\n if (!audiences.includes(this.audience)) {\n throw new CanopyTokenError(\n \"token.audience_mismatch\",\n `Token audience does not include \"${this.audience}\".`,\n );\n }\n }\n\n /**\n * The signing key for a `kid`, fetching the key set when it is stale or when\n * the `kid` is unknown — the latter is how key rotation is picked up\n * mid-process, bounded by `jwksMinRefetchIntervalMs`.\n */\n private async resolveKey(kid: string | undefined): Promise<CryptoKey> {\n if (kid === undefined) {\n throw new CanopyTokenError(\n \"token.malformed\",\n \"Token header has no `kid`, so its signing key cannot be identified.\",\n );\n }\n\n const stale = Date.now() - this.keysFetchedAt > this.jwksCacheMaxAgeMs;\n\n if (this.keys.size === 0 || stale) {\n // Floored like the rotation branch below, and for the same reason. With\n // no floor here, a key set that cannot be loaded — issuer down, or the\n // very first fetch failed — leaves `keys` empty, and every inbound\n // request takes this branch and issues its own outbound fetch. That is\n // one amplified request per caller, on an unauthenticated path, aimed at\n // the issuer precisely while it is already unwell.\n //\n // `lastFetchAttemptAt` starts at 0, so a genuine cold start is never\n // delayed by this — only a retry after a recent attempt is.\n if (this.shouldRefresh()) {\n await this.refreshKeys();\n } else if (this.keys.size === 0) {\n // Backing off with nothing cached: say so, rather than falling through\n // to `key_not_found`, which would claim the key set was read and\n // lacked this `kid`.\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Signing keys at ${this.jwksUri} are unavailable; backing off before retrying.`,\n );\n }\n }\n\n const cached = this.keys.get(kid);\n\n if (cached) {\n return cached;\n }\n\n // Unknown kid: possibly a rotation, possibly a forged header. Refetch at\n // most once per interval so the second case cannot amplify.\n if (this.shouldRefresh()) {\n await this.refreshKeys();\n }\n\n const rotated = this.keys.get(kid);\n\n if (rotated) {\n return rotated;\n }\n\n throw new CanopyTokenError(\n \"token.key_not_found\",\n `No signing key matches kid \"${kid}\".`,\n );\n }\n\n /**\n * Whether to await a key-set refresh.\n *\n * Two ways to qualify, and the first matters as much as the second. A read\n * already in flight is joined regardless of the floor: it costs no extra\n * outbound request, and it is what lets a concurrent burst share one fetch\n * instead of one caller winning and the rest being turned away.\n *\n * Otherwise the floor applies — the same one for every refetch path, so they\n * cannot drift into having different amplification properties.\n */\n private shouldRefresh(): boolean {\n if (this.inFlight) {\n return true;\n }\n\n return (\n Date.now() - this.lastFetchAttemptAt >= this.jwksMinRefetchIntervalMs\n );\n }\n\n private async refreshKeys(): Promise<void> {\n // Collapse a burst: concurrent requests await one fetch rather than each\n // issuing their own.\n this.inFlight ??= this.fetchKeys().finally(() => {\n this.inFlight = null;\n });\n\n await this.inFlight;\n }\n\n private async fetchKeys(): Promise<void> {\n this.lastFetchAttemptAt = Date.now();\n\n let response: Response;\n\n // Bounded: an issuer that accepts the connection and then never answers\n // would otherwise hold this request, and every request waiting on the same\n // in-flight read, for as long as it stays quiet.\n const controller = new AbortController();\n const timer =\n this.jwksTimeoutMs > 0\n ? setTimeout(() => controller.abort(), this.jwksTimeoutMs)\n : undefined;\n\n try {\n response = await this.fetchImpl(this.jwksUri, {\n headers: { accept: \"application/json\" },\n signal: controller.signal,\n });\n } catch (cause) {\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Could not reach the signing keys at ${this.jwksUri}.`,\n { cause },\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!response.ok) {\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Signing keys at ${this.jwksUri} returned HTTP ${response.status}.`,\n );\n }\n\n let document: { keys?: JwksKey[] };\n\n try {\n document = (await response.json()) as { keys?: JwksKey[] };\n } catch (cause) {\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Signing keys at ${this.jwksUri} were not valid JSON.`,\n { cause },\n );\n }\n\n const imported = new Map<string, CryptoKey>();\n\n for (const jwk of document.keys ?? []) {\n if (\n jwk.kty !== \"RSA\" ||\n jwk.kid === undefined ||\n jwk.n === undefined ||\n jwk.e === undefined\n ) {\n continue;\n }\n\n if (jwk.alg !== undefined && jwk.alg !== \"RS256\") {\n continue;\n }\n\n try {\n imported.set(\n jwk.kid,\n await crypto.subtle.importKey(\n \"jwk\",\n { kty: \"RSA\", n: jwk.n, e: jwk.e, alg: \"RS256\", ext: true },\n { name: \"RSASSA-PKCS1-v1_5\", hash: \"SHA-256\" },\n false,\n [\"verify\"],\n ),\n );\n } catch {\n // One unusable key must not blind the verifier to the others.\n continue;\n }\n }\n\n if (imported.size === 0) {\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Signing keys at ${this.jwksUri} contained no usable RS256 key.`,\n );\n }\n\n this.keys = imported;\n this.keysFetchedAt = Date.now();\n }\n}\n"]}