@canopy-io/node 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +61 -4
- package/dist/index.cjs +288 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1819 -277
- package/dist/index.d.ts +1819 -277
- package/dist/index.js +288 -68
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/strings.ts","../src/client.ts","../src/pagination.ts","../src/resources/assignments.ts","../src/resources/identities.ts","../src/schema.ts","../src/resources/organizations.ts","../src/resources/permissions.ts","../src/resources/roles.ts","../src/canopy.ts","../src/authorizer.ts","../src/status.ts","../src/verify.ts","../src/webhooks.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 but `token.jwks_unavailable` means the same thing to an\n * HTTP caller, 401; that one means the keys could not be read, so the token may\n * be good and the answer is 503. {@link tokenErrorStatus} maps them.\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 * - `token.type_not_allowed` — a principal type the verifier does not accept\n * (see `allowedTypes`)\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","/**\n * `value` without its trailing slashes.\n *\n * A loop rather than `replace(/\\/+$/, \"\")`: that pattern backtracks on a long\n * run of slashes followed by anything else, which a code scanner rightly\n * flags, and a loop costs one pass whatever the input.\n */\nexport function withoutTrailingSlashes(value: string): string {\n let end = value.length;\n\n while (end > 0 && value[end - 1] === \"/\") {\n end -= 1;\n }\n\n return value.slice(0, end);\n}\n","import {\n CanopyConnectionError,\n CanopyError,\n type CanopyErrorBody,\n} from \"./errors.js\";\nimport { withoutTrailingSlashes } from \"./strings.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 = withoutTrailingSlashes(options.baseUrl ?? DEFAULT_BASE_URL);\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 /**\n * Takes the identity out of this key's Environment: its membership here is\n * deactivated and its role assignments here are dropped. The identity and\n * its access to other Environments are untouched. Deactivating an identity\n * everywhere is an Account-level action, not available to an\n * Environment-scoped key.\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 * 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 /**\n * Every session the identity holds that is neither revoked nor expired,\n * newest first: when and where it was signed in, when it expires, and the\n * organization it is acting in. Read it back after a revoke to confirm,\n * from your own side, that a sign-out took.\n *\n * Paginated (20 per page by default, `take` up to 100), so this returns a\n * `Paginator`: iterate it for every session, or call `.first()` for the\n * newest. The list takes `page` and `take` only; its order is fixed.\n *\n * ```ts\n * for await (const session of canopy.identities.sessions(id)) { … }\n * ```\n */\n sessions(\n id: string,\n query: QueryParams<\"ApiIdentitiesController_listIdentitySessions\"> = {},\n ): Paginator<IdentitySessionItem> {\n return paginate<IdentitySessionItem>(\n (params) =>\n this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}/sessions`,\n { query: params },\n ),\n { ...query },\n );\n }\n\n /**\n * Ends one session and leaves the identity's others signed in. `sessionId`\n * is the session's `id` from `sessions`: its current refresh token, which\n * changes on every refresh, so read it shortly before revoking.\n */\n revokeSession(id: string, sessionId: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/identities/${encodeURIComponent(id)}/sessions/${encodeURIComponent(sessionId)}`,\n );\n }\n\n /**\n * Ends every session the identity holds, so the next refresh on any device\n * fails and the person signs in again. Access tokens already issued keep\n * working until their short lifetime runs out. For a suspected compromise;\n * `delete` also takes the identity out of this Environment.\n */\n revokeSessions(id: string): Promise<void> {\n return this.client.request(\n \"POST\",\n `/api/v1/identities/${encodeURIComponent(id)}/sessions/revoke`,\n );\n }\n}\n\nexport type IdentityItem = ItemOf<\n ResponseBody<\"ApiIdentitiesController_listIdentities\">\n>;\n\n/** One live session from an identity's sessions. */\nexport type IdentitySessionItem = ItemOf<\n ResponseBody<\"ApiIdentitiesController_listIdentitySessions\">\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 { 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 * Tenant organizations: one per business customer, a role per membership,\n * each with its own authentication policy and identity provider. Every\n * call here needs the Environment's organizations container switched on.\n */\nexport class Organizations {\n constructor(private readonly client: CanopyClient) {}\n\n list(\n query: QueryParams<\"ApiOrganizationsController_listOrganizations\"> = {},\n ): Paginator<OrganizationItem> {\n return paginate<OrganizationItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/organizations\", {\n query: params,\n }),\n { ...query },\n );\n }\n\n get(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationsController_getOrganization\">> {\n return this.client.request(\"GET\", `/api/v1/organizations/${enc(id)}`);\n }\n\n create(\n input: RequestBody<\"ApiOrganizationsController_createOrganization\">,\n ): Promise<ResponseBody<\"ApiOrganizationsController_createOrganization\">> {\n return this.client.request(\"POST\", \"/api/v1/organizations\", {\n body: input,\n });\n }\n\n /**\n * Pass `ifMatch` with the organization'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<\"ApiOrganizationsController_updateOrganization\">,\n options: ConcurrencyOptions = {},\n ): Promise<ResponseBody<\"ApiOrganizationsController_updateOrganization\">> {\n return this.client.request(\"PATCH\", `/api/v1/organizations/${enc(id)}`, {\n body: input,\n ...withConcurrency(options),\n });\n }\n\n /**\n * Removes the organization with its memberships, pending invitations,\n * policy, connection bindings, and the tree beneath it. Member identities\n * survive.\n */\n delete(id: string, options: ConcurrencyOptions = {}): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}`,\n withConcurrency(options),\n );\n }\n\n /** Empties the container: every organization goes, the step before switching it off. */\n deleteAll(): Promise<void> {\n return this.client.request(\"DELETE\", \"/api/v1/organizations\");\n }\n\n // ── Members: one role per member, held inside the organization only ──\n\n listMembers(\n id: string,\n query: QueryParams<\"ApiOrganizationsController_listMembers\"> = {},\n ): Paginator<OrganizationMemberItem> {\n return paginate<OrganizationMemberItem>(\n (params) =>\n this.client.request(\"GET\", `/api/v1/organizations/${enc(id)}/members`, {\n query: params,\n }),\n { ...query },\n );\n }\n\n addMember(\n id: string,\n input: RequestBody<\"ApiOrganizationsController_addMember\">,\n ): Promise<ResponseBody<\"ApiOrganizationsController_addMember\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/members`,\n { body: input },\n );\n }\n\n changeMemberRole(\n id: string,\n identityId: string,\n input: RequestBody<\"ApiOrganizationsController_changeMemberRole\">,\n ): Promise<ResponseBody<\"ApiOrganizationsController_changeMemberRole\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/organizations/${enc(id)}/members/${enc(identityId)}`,\n { body: input },\n );\n }\n\n /** Revokes that organization's one role; the identity and its other memberships are untouched. */\n removeMember(id: string, identityId: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/members/${enc(identityId)}`,\n );\n }\n\n /**\n * Clears a member's second factor, for one who lost their authenticator:\n * their factors, recovery codes and remembered devices go, and they enrol\n * again at their next sign-in. Sessions already open are left alone. The\n * identity must be a member of the organization.\n */\n resetMemberMfa(id: string, identityId: string): Promise<void> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/members/${enc(identityId)}/mfa/reset`,\n );\n }\n\n // ── Invitations: pending membership, carrying the role the recipient will hold ──\n\n listInvites(\n id: string,\n query: QueryParams<\"ApiOrganizationsController_listInvites\"> = {},\n ): Paginator<OrganizationInviteItem> {\n return paginate<OrganizationInviteItem>(\n (params) =>\n this.client.request(\"GET\", `/api/v1/organizations/${enc(id)}/invites`, {\n query: params,\n }),\n { ...query },\n );\n }\n\n createInvite(\n id: string,\n input: RequestBody<\"ApiOrganizationsController_createInvite\">,\n ): Promise<ResponseBody<\"ApiOrganizationsController_createInvite\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/invites`,\n { body: input },\n );\n }\n\n revokeInvite(id: string, inviteId: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/invites/${enc(inviteId)}`,\n );\n }\n\n // ── Policy: the organization's tightening of the Environment's sign-in rules ──\n\n /**\n * The organization's own values (null inherits), the Environment baseline\n * they tighten from, and the effective policy its members sign in under.\n */\n getPolicy(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationsController_getPolicy\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/policy`,\n );\n }\n\n /**\n * Can only tighten the Environment: a value that would loosen it answers\n * 400 `organization.policy_loosens`. Pass `ifMatch` with the policy's\n * `version` (0 until the organization sets one) for a safe\n * read-modify-write.\n */\n updatePolicy(\n id: string,\n input: RequestBody<\"ApiOrganizationsController_updatePolicy\">,\n options: ConcurrencyOptions = {},\n ): Promise<ResponseBody<\"ApiOrganizationsController_updatePolicy\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/organizations/${enc(id)}/policy`,\n { body: input, ...withConcurrency(options) },\n );\n }\n\n // ── SSO: the organization's own identity provider ──\n\n listSsoConnections(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationsController_listSsoConnections\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/sso-connections`,\n );\n }\n\n /**\n * Sign-ins through the connection then land in this organization, joining\n * as a member with `default_role_id`. The connection must already be bound\n * to the organization's Environment, and a connection binds to one\n * organization per Environment.\n */\n bindSsoConnection(\n id: string,\n input: RequestBody<\"ApiOrganizationsController_bindSsoConnection\">,\n ): Promise<ResponseBody<\"ApiOrganizationsController_bindSsoConnection\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/sso-connections`,\n { body: input },\n );\n }\n\n unbindSsoConnection(id: string, connectionId: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/sso-connections/${enc(connectionId)}`,\n );\n }\n\n // ── Directory sync: the organization's own SCIM connection ──\n\n /**\n * The roles this organization's identity provider may grant, and the one\n * people arrive with. An empty list means directory sync is not open for\n * the organization.\n */\n listDirectoryGrantableRoles(\n id: string,\n ): Promise<\n ResponseBody<\"ApiOrganizationDirectoryController_listGrantableRoles\">\n > {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/directory/grantable-roles`,\n );\n }\n\n /**\n * Replace the list in one act, which is how directory sync is opened for\n * an organization. Exactly one role is `default_role_id`, the one people\n * arrive with. Withdrawing a role unmaps the groups naming it and keeps\n * their members in the organization. An empty list removes the\n * organization's own list: it then holds the Environment's list when one\n * is set, and otherwise directory sync closes for it, which is refused\n * while a directory is connected. Your API key only: an organization\n * admin's token can read the list but is refused changing it.\n */\n setDirectoryGrantableRoles(\n id: string,\n input: RequestBody<\"ApiOrganizationDirectoryController_setGrantableRoles\">,\n ): Promise<\n ResponseBody<\"ApiOrganizationDirectoryController_setGrantableRoles\">\n > {\n return this.client.request(\n \"PUT\",\n `/api/v1/organizations/${enc(id)}/directory/grantable-roles`,\n { body: input },\n );\n }\n\n /**\n * The organization's directory, its full SCIM base URL, and the roles it\n * may grant. `id` is null until a directory is connected.\n */\n getDirectory(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_get\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/directory`,\n );\n }\n\n /** Connect a directory. Refused until the organization's roles are set. */\n createDirectory(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_create\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/directory`,\n );\n }\n\n /**\n * End the connection. The people it provisioned keep their accounts and\n * their membership; what ends is the provider's ability to push.\n */\n removeDirectory(id: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/directory`,\n );\n }\n\n listDirectoryTokens(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_listTokens\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/directory/tokens`,\n );\n }\n\n /**\n * The raw token is in this answer and nowhere else, alongside the full\n * base URL the identity provider's connector needs with it.\n */\n mintDirectoryToken(\n id: string,\n input: RequestBody<\"ApiOrganizationDirectoryController_mintToken\"> = {},\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_mintToken\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/directory/tokens`,\n { body: input },\n );\n }\n\n /**\n * A replacement token, shown once. The old one keeps working for a short\n * overlap, so the provider can be moved across without an outage.\n */\n rotateDirectoryToken(\n id: string,\n tokenId: string,\n input: RequestBody<\"ApiOrganizationDirectoryController_rotateToken\"> = {},\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_rotateToken\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/directory/tokens/${enc(tokenId)}/rotate`,\n { body: input },\n );\n }\n\n revokeDirectoryToken(id: string, tokenId: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/directory/tokens/${enc(tokenId)}`,\n );\n }\n\n /** The organization's own provisioning events, newest first. */\n listDirectoryActivity(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_activity\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/directory/activity`,\n );\n }\n\n /**\n * The groups the provider has pushed, each with its role mapping.\n *\n * Paginated (20 per page by default, `take` up to 100), so this returns a\n * `Paginator`. Sorted by display name unless `sort_by: \"created\"`; `q`\n * searches display names and external ids.\n *\n * ```ts\n * for await (const group of canopy.organizations.listDirectoryGroups(id)) { … }\n * ```\n */\n listDirectoryGroups(\n id: string,\n query: QueryParams<\"ApiOrganizationDirectoryGroupsController_list\"> = {},\n ): Paginator<OrganizationDirectoryGroupItem> {\n return paginate<OrganizationDirectoryGroupItem>(\n (params) =>\n this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/directory/groups`,\n { query: params },\n ),\n { ...query },\n );\n }\n\n /**\n * Grant a listed role to every member of a pushed group, at the\n * organization. A role not on the organization's list is refused with\n * `scim.role_not_grantable`.\n */\n mapDirectoryGroup(\n id: string,\n groupId: string,\n input: RequestBody<\"ApiOrganizationDirectoryGroupsController_map\">,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryGroupsController_map\">> {\n return this.client.request(\n \"PUT\",\n `/api/v1/organizations/${enc(id)}/directory/groups/${enc(groupId)}/mapping`,\n { body: input },\n );\n }\n\n /** Members fall back to the arrival role and stay in the organization. */\n unmapDirectoryGroup(\n id: string,\n groupId: string,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryGroupsController_unmap\">> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/directory/groups/${enc(groupId)}/mapping`,\n );\n }\n}\n\nexport type OrganizationItem = ItemOf<\n ResponseBody<\"ApiOrganizationsController_listOrganizations\">\n>;\nexport type OrganizationMemberItem = ItemOf<\n ResponseBody<\"ApiOrganizationsController_listMembers\">\n>;\nexport type OrganizationInviteItem = ItemOf<\n ResponseBody<\"ApiOrganizationsController_listInvites\">\n>;\n/** One pushed group from an organization's directory. */\nexport type OrganizationDirectoryGroupItem = ItemOf<\n ResponseBody<\"ApiOrganizationDirectoryGroupsController_list\">\n>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n\nfunction enc(segment: string): string {\n return encodeURIComponent(segment);\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 * One request carries between 1 and 100 checks. More is refused with a\n * `400` (`CanopyError`, `statusCode` 400) and nothing is evaluated, so split\n * a larger set into batches of 100.\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 { Organizations } from \"./resources/organizations.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 102 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 readonly organizations: Organizations;\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 this.organizations = new Organizations(this.client);\n }\n}\n","import type {\n CanopyClient,\n ConditionalResult,\n RequestOptions,\n} from \"./client.js\";\nimport { CanopyAuthorizerError } from \"./errors.js\";\nimport { paginate, type PageParams } from \"./pagination.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 * The longest a held answer may be kept: five minutes. `ttlMs` is the delay\n * between an access change and it taking effect, and Canopy promises that\n * delay is short, so a longer value is refused rather than honoured.\n */\nexport const MAX_TTL_MS = 300_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\n/**\n * The page size every read here asks for: the largest the API serves, so a\n * walk makes the fewest calls it can.\n */\nconst PAGE_SIZE = 100;\n\n/**\n * Pages a single read may take before it stops: a million rows at\n * {@link PAGE_SIZE}. Far past any real hierarchy; it exists so a server that\n * keeps promising another page cannot hold a read open forever.\n */\nconst MAX_PAGES = 10_000;\n\n/**\n * Walks of the hierarchy a refresh may make while the hierarchy keeps\n * changing under it. A walk over several pages is confirmed afterwards (see\n * `fetchTree`); a walk that cannot be confirmed this many times running is\n * kept anyway, without a validator, so the next refresh reads it in full.\n */\nconst MAX_TREE_WALKS = 3;\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 * **At most {@link MAX_TTL_MS} (five minutes).** A longer value, a negative\n * one or a non-number throws when the authorizer is created, rather than\n * quietly stretching how long a revoked user keeps access.\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 /** Reads of an identity's grant roots, one per refresh however many pages it took. */\n grantFetches: number;\n /** Page requests those reads made: at least one per read, one more per further 100 grants. */\n grantPages: number;\n /** Reads of the hierarchy, one per refresh, including revalidations. */\n treeRequests: number;\n /**\n * Page requests those reads made: one for a revalidation the server answers\n * `304`, otherwise one per page of 100 nodes, plus the request that confirms\n * a walk of several pages was not torn by a change made during it.\n */\n treePages: 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 * One page of grant roots, read off the generated operation rather than\n * restated here: one row per permission and node it was granted at.\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 GrantPage = ResponseBody<\"ApiIdentitiesController_getIdentityGrants\">;\ntype GrantRow = GrantPage[\"items\"][number];\n\n/**\n * One page of the hierarchy as parent edges, read off the generated\n * operation, ordered by node id.\n *\n * Deliberately not the node list. `GET /api/v1/nodes` answers what a\n * dashboard renders — names, statuses, access flags, per-node counts — and a\n * walk upward reads none of it. Measured at 50,000 nodes that is 18.6 MB\n * against 5.0 MB, on a read every consuming process makes at startup.\n */\ntype ParentPage = ResponseBody<\"ApiNodesController_listNodeParents\">;\ntype ParentEdge = ParentPage[\"items\"][number];\n\n/**\n * The versions of Canopy's authorization model this authorizer understands.\n *\n * The grants and parents responses name the model their rows describe. Canopy\n * raises the version when a change makes a walk up the tree answer\n * differently for the same rows (a deny that narrows a grant, a root that no\n * longer reaches every descendant). An authorizer that walked on regardless\n * would allow what the API has started to deny, so a version not listed here\n * is refused, and the fix is upgrading this package.\n */\nconst KNOWN_MODEL_VERSIONS: ReadonlySet<number> = new Set([1]);\n\n/** A page as served, once its model version is known to be understood. */\nfunction understood<T extends { model_version: number }>(\n page: T,\n path: string,\n): T {\n if (!KNOWN_MODEL_VERSIONS.has(page.model_version)) {\n throw new CanopyAuthorizerError(\n \"authorizer.model_version_unknown\",\n `${path} describes authorization model version ${page.model_version}, which this version of @canopy-io/node does not understand. ` +\n `It knows ${[...KNOWN_MODEL_VERSIONS].join(\", \")}. Upgrade @canopy-io/node; until then this authorizer cannot decide, rather than guess.`,\n );\n }\n\n return page;\n}\n\nconst GRANTS_PATH = (identityId: string): string =>\n `/api/v1/identities/${encodeURIComponent(identityId)}/grants`;\n\nconst PARENTS_PATH = \"/api/v1/nodes/parents\";\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 grantPages: 0,\n treeRequests: 0,\n treePages: 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\n if (\n !Number.isFinite(this.ttlMs) ||\n this.ttlMs < 0 ||\n this.ttlMs > MAX_TTL_MS\n ) {\n throw new RangeError(\n `ttlMs must be between 0 and ${MAX_TTL_MS} (five minutes); got ${String(this.ttlMs)}. ` +\n \"It is how long a revoked user keeps access, so it is capped.\",\n );\n }\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 role deactivated or reactivated, a node moved). A\n * deactivated role grants nothing to anyone holding it, so until the cache\n * is cleared or expires, its holders keep being allowed locally.\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/parents` answers the hierarchy scoped to the\n // caller, and a credential that cannot read it 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 /**\n * Every page of the identity's grant roots, folded into permission → nodes.\n *\n * Each row is one permission at one node, so a permission granted at three\n * nodes arrives as three rows, possibly on different pages. Stopping after\n * the first page would under-report what the identity holds: a false deny,\n * the safe direction, but a wrong answer all the same.\n */\n private async fetchGrantRoots(\n identityId: string,\n ): Promise<Map<string, Set<string>>> {\n this.stats.grantFetches += 1;\n\n const path = GRANTS_PATH(identityId);\n const rows = paginate<GrantRow>(\n (query) => {\n this.stats.grantPages += 1;\n\n return this.client\n .request<GrantPage>(\"GET\", path, {\n ...this.readOptions,\n query,\n })\n .then((page) => understood(page, path));\n },\n { page: 1, take: PAGE_SIZE },\n { maxPages: MAX_PAGES },\n );\n\n const roots = new Map<string, Set<string>>();\n\n for await (const row of rows) {\n const nodes = roots.get(row.permission);\n\n if (nodes) {\n nodes.add(row.node_id);\n } else {\n roots.set(row.permission, new Set([row.node_id]));\n }\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 * The edges come a page at a time, so only the first page is conditional:\n * its validator covers the whole hierarchy, and a `304` to it means no page\n * has changed. On a `200` the remaining pages are read plainly and the map\n * is rebuilt from every page.\n *\n * A walk over several pages is not one snapshot. A node added or removed\n * between two page reads shifts the rows under the offset, so a row can be\n * skipped, which would leave a node out of the map until the next refresh.\n * So the walk is confirmed by asking for the first page again with the\n * validator it came with: a `304` proves nothing changed while the pages\n * were read. A `200` is a fresh first page, and the walk starts again from\n * it, up to {@link MAX_TREE_WALKS} times.\n */\n private async fetchTree(): Promise<Map<string, string | null>> {\n this.stats.treeRequests += 1;\n\n const held = this.tree;\n\n let first = await this.parentsFirstPage(held?.etag ?? undefined);\n\n if (!first.modified) {\n if (held) {\n this.stats.treeNotModified += 1;\n this.tree = { ...held, expiresAt: this.now() + this.ttlMs };\n\n return held.parents;\n }\n\n // A `304` to a request that carried no validator has nothing to keep.\n return this.keepTree([], null);\n }\n\n for (let walk = 1; ; walk++) {\n const edges = await this.parentsRemainingPages(first.data);\n\n // One page is one response, so it cannot have been torn; without a\n // validator there is nothing to confirm with.\n if (!spansPages(first.data) || first.etag === null) {\n return this.keepTree(edges, first.etag);\n }\n\n const confirm = await this.parentsFirstPage(first.etag);\n\n if (!confirm.modified) {\n return this.keepTree(edges, first.etag);\n }\n\n if (walk >= MAX_TREE_WALKS) {\n // Still changing. Keep the latest walk, but with no validator, so the\n // next refresh reads every page again rather than revalidating a map\n // that may be missing a node.\n return this.keepTree(edges, null);\n }\n\n first = confirm;\n }\n }\n\n private parentsFirstPage(\n etag: string | undefined,\n ): Promise<ConditionalResult<ParentPage>> {\n this.stats.treePages += 1;\n\n return this.client\n .requestConditional<ParentPage>(\"GET\", PARENTS_PATH, etag, {\n ...this.readOptions,\n query: { page: 1, take: PAGE_SIZE },\n })\n .then((result) => {\n // A `304` carries no body; it confirms edges already checked.\n if (result.modified) {\n understood(result.data, PARENTS_PATH);\n }\n\n return result;\n });\n }\n\n /** The first page's edges followed by every later page's. */\n private async parentsRemainingPages(\n first: ParentPage,\n ): Promise<ParentEdge[]> {\n const edges: ParentEdge[] = [...first.items];\n\n if (!spansPages(first)) {\n return edges;\n }\n\n const rest = paginate<ParentEdge>(\n (query: PageParams) => {\n this.stats.treePages += 1;\n\n return this.client\n .request<ParentPage>(\"GET\", PARENTS_PATH, {\n ...this.readOptions,\n query,\n })\n .then((page) => understood(page, PARENTS_PATH));\n },\n { page: first.pagination.page + 1, take: PAGE_SIZE },\n { maxPages: MAX_PAGES - 1 },\n );\n\n for await (const page of rest.pages()) {\n for (const edge of page.items) {\n edges.push(edge);\n }\n }\n\n return edges;\n }\n\n private keepTree(\n edges: ParentEdge[],\n etag: string | null,\n ): Map<string, string | null> {\n // One string per node. A parsed response holds each id twice, once as\n // its own node's `id` and again, as a separate copy, in every child's\n // `parent_node_id`; storing those copies doubled the cache. So the\n // parent is stored as the node's own `id` string, found through a map\n // of every page's ids first, since a parent may arrive after its\n // children, on a later page. The lookup map is gone once this returns.\n const ids = new Map<string, string>();\n\n for (const edge of edges) {\n ids.set(edge.id, edge.id);\n }\n\n const parents = new Map<string, string | null>();\n\n for (const edge of edges) {\n const parent = edge.parent_node_id ?? null;\n\n parents.set(\n edge.id,\n parent === null ? null : (ids.get(parent) ?? parent),\n );\n }\n\n this.tree = {\n parents,\n etag,\n expiresAt: this.now() + this.ttlMs,\n };\n\n return parents;\n }\n}\n\n/**\n * Whether a first page says more follow. An empty page ends the walk however\n * the server describes it, as the paginator's own loop does.\n */\nfunction spansPages(first: ParentPage): boolean {\n return first.pagination.has_next_page && first.items.length > 0;\n}\n","import {\n isCanopyAuthorizerError,\n isCanopyError,\n isCanopyTokenError,\n} from \"./errors.js\";\n\n/**\n * The HTTP answer a failure should become, for code that verifies tokens or\n * authorizes requests outside the NestJS guards (Express, Fastify, a worker).\n * The guards use the same mapping, so every integration answers alike.\n */\nexport interface FailureStatus {\n status: number;\n /** A message safe to send to the caller; the detail stays on the error. */\n message: string;\n}\n\n/**\n * The answer for a failed {@link TokenVerifier.verify}: `401` when the token is\n * at fault, `503` when the signing keys could not be read and the token may be\n * perfectly good.\n *\n * The difference matters. A client reads `401` as \"your token is stale\",\n * discards a valid one and asks for another, which aims a refresh storm at an\n * issuer that is already down, and an outage that only emits 4xx is invisible\n * to anything watching for 5xx.\n *\n * Anything that is not a token error is returned as `500`: it is a bug, not a\n * verdict on the token.\n */\nexport function tokenErrorStatus(error: unknown): FailureStatus {\n if (!isCanopyTokenError(error)) {\n return { status: 500, message: \"Authentication could not be checked.\" };\n }\n\n if (error.code === \"token.jwks_unavailable\") {\n return {\n status: 503,\n message: \"Authentication is temporarily unavailable.\",\n };\n }\n\n return { status: 401, message: \"Invalid or expired access token.\" };\n}\n\n/**\n * The answer for a failed authorization check ({@link LocalAuthorizer.evaluate}\n * or a {@link Canopy} call that decides access). Every branch denies; they say\n * different things so an incident is diagnosable:\n *\n * - `500` when the authorizer cannot see far enough to decide (a credential\n * that cannot read the hierarchy), when Canopy rejected our own credential,\n * when the endpoint is not served (an SDK newer than the API), or on a 4xx\n * nobody anticipated. No retry fixes these.\n * - `503` when Canopy did not answer, or answered 429 or 5xx.\n * - `403` when Canopy answered that the identity is not in this Environment.\n */\nexport function authorizationErrorStatus(error: unknown): FailureStatus {\n if (isCanopyAuthorizerError(error)) {\n return {\n status: 500,\n message: `Authorization is misconfigured: ${error.message}`,\n };\n }\n\n if (!isCanopyError(error)) {\n return {\n status: 503,\n message: \"Authorization is temporarily unavailable.\",\n };\n }\n\n if (error.isAuthFailure) {\n return {\n status: 500,\n message:\n \"Authorization is misconfigured. Check the Canopy API key and its scopes.\",\n };\n }\n\n // A 404 with no error code is the framework's own \"no such route\": this\n // Canopy does not serve the endpoint the authorizer reads.\n if (error.statusCode === 404 && error.code === null) {\n return {\n status: 500,\n message:\n `Authorization is misconfigured: ${error.request.method} ${error.request.path} is not served by this Canopy. ` +\n \"The SDK requires an API that exposes the identity grants endpoint.\",\n };\n }\n\n // A 404 with a code is a real answer: the identity is not in this\n // Environment. Deny, and say nothing about what was missing.\n if (error.statusCode === 404) {\n return { status: 403, message: \"Could not evaluate the permission.\" };\n }\n\n if (error.isRateLimited || error.statusCode >= 500) {\n return {\n status: 503,\n message: \"Authorization is temporarily unavailable.\",\n };\n }\n\n return { status: 500, message: \"Authorization could not be evaluated.\" };\n}\n","import { CanopyTokenError } from \"./errors.js\";\nimport { withoutTrailingSlashes } from \"./strings.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 * environmentId: process.env.CANOPY_ENVIRONMENT_ID,\n * });\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 origin. Matches the client's default base URL. */\nconst HOSTED_ORIGIN = \"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\n/**\n * The issuer a verifier accepts: the hosted Environment's, or the one named.\n * There is no default, because every Environment is its own issuer and a\n * guess would reject every real token.\n */\nfunction resolveIssuer(options: TokenVerifierOptions): string {\n const { environmentId, issuer } = options;\n\n if (environmentId && issuer) {\n throw new TypeError(\n \"TokenVerifier takes environmentId or issuer, not both.\",\n );\n }\n\n if (issuer) {\n return withoutTrailingSlashes(issuer);\n }\n\n if (environmentId) {\n return `${HOSTED_ORIGIN}/environments/${environmentId}`;\n }\n\n throw new TypeError(\n \"TokenVerifier needs environmentId (the Environment your tokens come from) \" +\n \"or, on a custom auth domain or self-hosted instance, issuer.\",\n );\n}\n\nexport interface TokenVerifierOptions {\n /**\n * The Environment whose tokens are accepted. Every Environment is its own\n * issuer with its own signing keys, at\n * `https://auth.canopy-io.com/environments/<id>`, so on hosted Canopy this is\n * all verification needs. A token from any other Environment fails.\n *\n * Set exactly one of `environmentId` and `issuer`; the constructor throws\n * with neither or both.\n */\n environmentId?: string;\n\n /**\n * The issuer whose tokens are accepted, matched against `iss` exactly. Set it\n * instead of `environmentId` on a custom auth domain (`https://auth.acme.com`)\n * or a self-hosted instance (`<origin>/environments/<id>`).\n *\n * Pointed at the wrong issuer, verification fails closed: a token is\n * rejected, never mistakenly 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 /**\n * The principal types accepted, matched against the `type` claim. Defaults to\n * `[\"identity\"]`: the people who sign in to your application.\n *\n * Canopy also signs tokens for its own administrators (`user`), its staff\n * (`platform`) and, for some flows, API keys (`api_key`), all with the same\n * keys and issuer. A backend that serves your end users should accept none\n * of them, so they are refused unless you name them here.\n */\n allowedTypes?: ReadonlyArray<CanopyTokenClaims[\"type\"]>;\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 /**\n * How the session was proven: `pwd`, `otp`, or `sso`, plus `mfa` once a\n * second factor was verified. Identity tokens carry it; check for `mfa`\n * before allowing a sensitive action.\n */\n amr?: string[];\n /**\n * The organization this session is acting in — present only on identity\n * tokens from an Environment with the organizations container on, for an\n * identity that belongs to at least one organization. Always minted\n * together with `org_role`; read the pair through {@link orgContext}\n * rather than separately.\n */\n org_id?: string;\n /** The name of the single role the identity holds in `org_id`. */\n org_role?: string;\n [claim: string]: unknown;\n}\n\n/**\n * The organization context a verified token carries: which organization the\n * session is acting in, and the one role it holds there.\n */\nexport interface CanopyOrgContext {\n /** The organization's id — also a hierarchy node id, usable as `node_id`. */\n orgId: string;\n /** The role's name (not its id): what `org_role` carries. */\n orgRole: string;\n}\n\n/**\n * The organization context of a verified token, or `null` when it has none.\n *\n * `null` is an ordinary answer, not a failure: it is every token from an\n * Environment without the organizations container on, and every identity\n * that belongs to no organization yet. Branch on it rather than on the raw claims —\n * Canopy mints `org_id` and `org_role` together, and this helper refuses a\n * half-present pair instead of letting one claim be read as though the other\n * were there.\n *\n * ```ts\n * const claims = await verifier.verify(token);\n * const org = orgContext(claims);\n *\n * if (org) {\n * // acting inside org.orgId as org.orgRole\n * }\n * ```\n */\nexport function orgContext(claims: CanopyTokenClaims): CanopyOrgContext | null {\n const { org_id, org_role } = claims;\n\n if (\n typeof org_id !== \"string\" ||\n org_id === \"\" ||\n typeof org_role !== \"string\" ||\n org_role === \"\"\n ) {\n return null;\n }\n\n return { orgId: org_id, orgRole: org_role };\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 allowedTypes: ReadonlySet<string>;\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 /** Whether the latest read of the key set failed, for an unknown `kid`. */\n private lastFetchFailed = false;\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 = resolveIssuer(options);\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 this.allowedTypes = new Set(options.allowedTypes ?? [\"identity\"]);\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 (!this.allowedTypes.has(claims.type)) {\n throw new CanopyTokenError(\n \"token.type_not_allowed\",\n `Token is for a \"${claims.type}\" principal; this verifier accepts ${[\n ...this.allowedTypes,\n ]\n .map((type) => `\"${type}\"`)\n .join(\", \")}. Set \\`allowedTypes\\` to accept another.`,\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 try {\n await this.refreshKeys();\n } catch (error) {\n // Stale is not invalid. Keys that verified tokens a minute ago still\n // verify them while the issuer is unreachable; failing here would\n // turn an issuer outage into a 503 for every working session, every\n // time the floor lets another attempt through. With nothing cached\n // there is nothing to fall back on, so the failure stands.\n if (this.keys.size === 0) {\n throw error;\n }\n }\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 // The key set could not be read, so whether this `kid` exists is unknown:\n // a token signed after a rotation is as likely as a forged one. Saying the\n // key does not exist would turn an outage into a 401 for good tokens.\n if (this.lastFetchFailed) {\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Signing keys at ${this.jwksUri} could not be read to look up kid \"${kid}\".`,\n );\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 try {\n await this.readKeys();\n this.lastFetchFailed = false;\n } catch (error) {\n this.lastFetchFailed = true;\n throw error;\n }\n }\n\n private async readKeys(): Promise<void> {\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","import type { components } from \"./generated/types.js\";\n\n/**\n * Typed webhook deliveries.\n *\n * Canopy publishes one schema per webhook event, named `Webhook…Event`, each\n * the shared envelope narrowed to that event's name, `resource_type` and\n * `metadata`. These types read them straight out of the generated document,\n * so a handler is written against the contract rather than against\n * deliveries it happened to capture, and `npm run generate` brings in any\n * field the API adds.\n *\n * app.post(\"/webhooks/canopy\", (req, res) => {\n * const delivery = req.body as WebhookDelivery;\n *\n * if (isWebhookEvent(delivery, \"organization.member.added\")) {\n * delivery.data.metadata.identity_id; // string\n * }\n * });\n *\n * `GET /api/v1/webhooks/event-types` names each event's schema in\n * `payload_schema`, which is the name to look up in `Schema<…>`.\n */\n\n/** The name of every published delivery schema. */\ntype WebhookSchemaName = Extract<\n keyof components[\"schemas\"],\n `Webhook${string}Event`\n>;\n\n/** A delivery of any webhook event: `{ event, data }`. */\nexport type WebhookDelivery = components[\"schemas\"][WebhookSchemaName];\n\n/** Every event a subscription can receive. */\nexport type WebhookEventName = WebhookDelivery[\"event\"];\n\n/**\n * The delivery of one event, e.g. `WebhookEvent<\"assignment.created\">`.\n * Its `data.metadata` carries exactly the fields that event sends, with the\n * ones every delivery includes required and the rest optional.\n */\nexport type WebhookEvent<Name extends WebhookEventName> = Extract<\n WebhookDelivery,\n { event: Name }\n>;\n\n/** The `data` object of one event's delivery. */\nexport type WebhookEventData<Name extends WebhookEventName> =\n WebhookEvent<Name>[\"data\"];\n\n/**\n * Narrow a delivery to one event by its name. A type guard rather than a\n * switch over `delivery.event`, so a handler for one event reads that\n * event's `metadata` without a cast.\n */\nexport function isWebhookEvent<Name extends WebhookEventName>(\n delivery: WebhookDelivery,\n name: Name,\n): delivery is WebhookEvent<Name> {\n return delivery.event === name;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/strings.ts","../src/client.ts","../src/pagination.ts","../src/schema.ts","../src/resources/assignments.ts","../src/resources/identities.ts","../src/resources/organizations.ts","../src/resources/permissions.ts","../src/resources/roles.ts","../src/canopy.ts","../src/authorizer.ts","../src/status.ts","../src/verify.ts","../src/webhooks.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 but `token.jwks_unavailable` means the same thing to an\n * HTTP caller, 401; that one means the keys could not be read, so the token may\n * be good and the answer is 503. {@link tokenErrorStatus} maps them.\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 * - `token.type_not_allowed` — a principal type the verifier does not accept\n * (see `allowedTypes`)\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","/**\n * `value` without its trailing slashes.\n *\n * A loop rather than `replace(/\\/+$/, \"\")`: that pattern backtracks on a long\n * run of slashes followed by anything else, which a code scanner rightly\n * flags, and a loop costs one pass whatever the input.\n */\nexport function withoutTrailingSlashes(value: string): string {\n let end = value.length;\n\n while (end > 0 && value[end - 1] === \"/\") {\n end -= 1;\n }\n\n return value.slice(0, end);\n}\n","import {\n CanopyConnectionError,\n CanopyError,\n type CanopyErrorBody,\n} from \"./errors.js\";\nimport { withoutTrailingSlashes } from \"./strings.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 = withoutTrailingSlashes(options.baseUrl ?? DEFAULT_BASE_URL);\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 { 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 { 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 * 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 /**\n * Change the role or the window of a grant. Pass the `version` the\n * assignment was read with as `ifMatch`; a stale one answers 409\n * `assignment.version_mismatch` rather than overwriting a newer change.\n */\n update(\n id: string,\n input: RequestBody<\"ApiAssignmentsController_updateAssignment\">,\n options: ConcurrencyOptions = {},\n ): Promise<ResponseBody<\"ApiAssignmentsController_updateAssignment\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/assignments/${encodeURIComponent(id)}`,\n { body: input, ...withConcurrency(options) },\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 /**\n * Takes the identity out of this key's Environment: its membership here is\n * deactivated and its role assignments here are dropped. The identity and\n * its access to other Environments are untouched. Deactivating an identity\n * everywhere is an Account-level action, not available to an\n * Environment-scoped key.\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 * 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 query: QueryParams<\"ApiIdentitiesController_getIdentityPermissions\"> = {},\n ): Promise<ResponseBody<\"ApiIdentitiesController_getIdentityPermissions\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}/permissions`,\n { query: { ...query } },\n );\n }\n\n /**\n * Where the identity may act with one permission, answered by Canopy for a\n * list query: the minimal grant roots, and every node beneath them up to\n * `max_nodes` (null past it, with `complete: false`), or `env_wide` when a\n * root is the Environment's own root and no filter is needed.\n *\n * `LocalAuthorizer.accessibleNodes` answers the same question from its\n * cache without a call; this is the fresh answer, and the one for a process\n * that does not run the authorizer.\n */\n accessibleNodes(\n id: string,\n query: QueryParams<\"ApiIdentitiesController_getIdentityAccessibleNodes\">,\n ): Promise<\n ResponseBody<\"ApiIdentitiesController_getIdentityAccessibleNodes\">\n > {\n return this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}/accessible-nodes`,\n { query: { ...query } },\n );\n }\n\n /**\n * Every session the identity holds that is neither revoked nor expired,\n * newest first: when and where it was signed in, when it expires, and the\n * organization it is acting in. Read it back after a revoke to confirm,\n * from your own side, that a sign-out took.\n *\n * Paginated (20 per page by default, `take` up to 100), so this returns a\n * `Paginator`: iterate it for every session, or call `.first()` for the\n * newest. The list takes `page` and `take` only; its order is fixed.\n *\n * ```ts\n * for await (const session of canopy.identities.sessions(id)) { … }\n * ```\n */\n sessions(\n id: string,\n query: QueryParams<\"ApiIdentitiesController_listIdentitySessions\"> = {},\n ): Paginator<IdentitySessionItem> {\n return paginate<IdentitySessionItem>(\n (params) =>\n this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}/sessions`,\n { query: params },\n ),\n { ...query },\n );\n }\n\n /**\n * Ends one session and leaves the identity's others signed in. `sessionId`\n * is the session's `id` from `sessions`: its current refresh token, which\n * changes on every refresh, so read it shortly before revoking.\n */\n revokeSession(id: string, sessionId: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/identities/${encodeURIComponent(id)}/sessions/${encodeURIComponent(sessionId)}`,\n );\n }\n\n /**\n * Ends every session the identity holds, so the next refresh on any device\n * fails and the person signs in again. Access tokens already issued keep\n * working until their short lifetime runs out. For a suspected compromise;\n * `delete` also takes the identity out of this Environment.\n */\n revokeSessions(id: string): Promise<void> {\n return this.client.request(\n \"POST\",\n `/api/v1/identities/${encodeURIComponent(id)}/sessions/revoke`,\n );\n }\n}\n\nexport type IdentityItem = ItemOf<\n ResponseBody<\"ApiIdentitiesController_listIdentities\">\n>;\n\n/** One live session from an identity's sessions. */\nexport type IdentitySessionItem = ItemOf<\n ResponseBody<\"ApiIdentitiesController_listIdentitySessions\">\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 { 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 * Tenant organizations: one per business customer, membership apart from\n * the roles held inside it, each with its own authentication policy and identity provider. Every\n * call here needs the Environment's organizations container switched on.\n */\nexport class Organizations {\n constructor(private readonly client: CanopyClient) {}\n\n list(\n query: QueryParams<\"ApiOrganizationsController_listOrganizations\"> = {},\n ): Paginator<OrganizationItem> {\n return paginate<OrganizationItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/organizations\", {\n query: params,\n }),\n { ...query },\n );\n }\n\n get(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationsController_getOrganization\">> {\n return this.client.request(\"GET\", `/api/v1/organizations/${enc(id)}`);\n }\n\n create(\n input: RequestBody<\"ApiOrganizationsController_createOrganization\">,\n ): Promise<ResponseBody<\"ApiOrganizationsController_createOrganization\">> {\n return this.client.request(\"POST\", \"/api/v1/organizations\", {\n body: input,\n });\n }\n\n /**\n * Pass `ifMatch` with the organization'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<\"ApiOrganizationsController_updateOrganization\">,\n options: ConcurrencyOptions = {},\n ): Promise<ResponseBody<\"ApiOrganizationsController_updateOrganization\">> {\n return this.client.request(\"PATCH\", `/api/v1/organizations/${enc(id)}`, {\n body: input,\n ...withConcurrency(options),\n });\n }\n\n /**\n * Removes the organization with its memberships, pending invitations,\n * policy, connection bindings, and the tree beneath it. Member identities\n * survive.\n */\n delete(id: string, options: ConcurrencyOptions = {}): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}`,\n withConcurrency(options),\n );\n }\n\n /** Empties the container: every organization goes, the step before switching it off. */\n deleteAll(): Promise<void> {\n return this.client.request(\"DELETE\", \"/api/v1/organizations\");\n }\n\n // ── Members: admission to the organization, apart from the roles held in it ──\n\n listMembers(\n id: string,\n query: QueryParams<\"ApiOrganizationsController_listMembers\"> = {},\n ): Paginator<OrganizationMemberItem> {\n return paginate<OrganizationMemberItem>(\n (params) =>\n this.client.request(\"GET\", `/api/v1/organizations/${enc(id)}/members`, {\n query: params,\n }),\n { ...query },\n );\n }\n\n addMember(\n id: string,\n input: RequestBody<\"ApiOrganizationsController_addMember\">,\n ): Promise<ResponseBody<\"ApiOrganizationsController_addMember\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/members`,\n { body: input },\n );\n }\n\n /**\n * Deactivates the membership and revokes every role the member holds at\n * the organization's nodes; the identity and its other memberships are\n * untouched. A role in the organization is changed through the\n * organization's assignment routes, not here.\n */\n removeMember(id: string, identityId: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/members/${enc(identityId)}`,\n );\n }\n\n /**\n * Clears a member's second factor, for one who lost their authenticator:\n * their factors, recovery codes and remembered devices go, and they enrol\n * again at their next sign-in. Sessions already open are left alone. The\n * identity must be a member of the organization.\n */\n resetMemberMfa(id: string, identityId: string): Promise<void> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/members/${enc(identityId)}/mfa/reset`,\n );\n }\n\n // ── Invitations: pending membership, carrying the role the recipient will hold ──\n\n listInvites(\n id: string,\n query: QueryParams<\"ApiOrganizationsController_listInvites\"> = {},\n ): Paginator<OrganizationInviteItem> {\n return paginate<OrganizationInviteItem>(\n (params) =>\n this.client.request(\"GET\", `/api/v1/organizations/${enc(id)}/invites`, {\n query: params,\n }),\n { ...query },\n );\n }\n\n createInvite(\n id: string,\n input: RequestBody<\"ApiOrganizationsController_createInvite\">,\n ): Promise<ResponseBody<\"ApiOrganizationsController_createInvite\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/invites`,\n { body: input },\n );\n }\n\n revokeInvite(id: string, inviteId: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/invites/${enc(inviteId)}`,\n );\n }\n\n // ── Policy: the organization's tightening of the Environment's sign-in rules ──\n\n /**\n * The organization's own values (null inherits), the Environment baseline\n * they tighten from, and the effective policy its members sign in under.\n */\n getPolicy(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationsController_getPolicy\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/policy`,\n );\n }\n\n /**\n * Can only tighten the Environment: a value that would loosen it answers\n * 400 `organization.policy_loosens`. Pass `ifMatch` with the policy's\n * `version` (0 until the organization sets one) for a safe\n * read-modify-write.\n */\n updatePolicy(\n id: string,\n input: RequestBody<\"ApiOrganizationsController_updatePolicy\">,\n options: ConcurrencyOptions = {},\n ): Promise<ResponseBody<\"ApiOrganizationsController_updatePolicy\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/organizations/${enc(id)}/policy`,\n { body: input, ...withConcurrency(options) },\n );\n }\n\n // ── SSO: the organization's own identity provider ──\n\n listSsoConnections(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationsController_listSsoConnections\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/sso-connections`,\n );\n }\n\n /**\n * Sign-ins through the connection then land in this organization, joining\n * as a member with `default_role_id`. The connection must already be bound\n * to the organization's Environment, and a connection binds to one\n * organization per Environment.\n */\n bindSsoConnection(\n id: string,\n input: RequestBody<\"ApiOrganizationsController_bindSsoConnection\">,\n ): Promise<ResponseBody<\"ApiOrganizationsController_bindSsoConnection\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/sso-connections`,\n { body: input },\n );\n }\n\n unbindSsoConnection(id: string, connectionId: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/sso-connections/${enc(connectionId)}`,\n );\n }\n\n // ── Directory sync: the organization's own SCIM connection ──\n\n /**\n * The roles this organization's identity provider may grant, and the one\n * people arrive with. An empty list means directory sync is not open for\n * the organization.\n */\n listDirectoryGrantableRoles(\n id: string,\n ): Promise<\n ResponseBody<\"ApiOrganizationDirectoryController_listGrantableRoles\">\n > {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/directory/grantable-roles`,\n );\n }\n\n /**\n * Replace the list in one act, which is how directory sync is opened for\n * an organization. Exactly one role is `default_role_id`, the one people\n * arrive with. Withdrawing a role unmaps the groups naming it and keeps\n * their members in the organization. An empty list removes the\n * organization's own list: it then holds the Environment's list when one\n * is set, and otherwise directory sync closes for it, which is refused\n * while a directory is connected. Your API key only: an organization\n * admin's token can read the list but is refused changing it.\n */\n setDirectoryGrantableRoles(\n id: string,\n input: RequestBody<\"ApiOrganizationDirectoryController_setGrantableRoles\">,\n ): Promise<\n ResponseBody<\"ApiOrganizationDirectoryController_setGrantableRoles\">\n > {\n return this.client.request(\n \"PUT\",\n `/api/v1/organizations/${enc(id)}/directory/grantable-roles`,\n { body: input },\n );\n }\n\n /**\n * The organization's directory, its full SCIM base URL, and the roles it\n * may grant. `id` is null until a directory is connected.\n */\n getDirectory(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_get\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/directory`,\n );\n }\n\n /** Connect a directory. Refused until the organization's roles are set. */\n createDirectory(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_create\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/directory`,\n );\n }\n\n /**\n * End the connection. The people it provisioned keep their accounts and\n * their membership; what ends is the provider's ability to push.\n */\n removeDirectory(id: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/directory`,\n );\n }\n\n listDirectoryTokens(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_listTokens\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/directory/tokens`,\n );\n }\n\n /**\n * The raw token is in this answer and nowhere else, alongside the full\n * base URL the identity provider's connector needs with it.\n */\n mintDirectoryToken(\n id: string,\n input: RequestBody<\"ApiOrganizationDirectoryController_mintToken\"> = {},\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_mintToken\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/directory/tokens`,\n { body: input },\n );\n }\n\n /**\n * A replacement token, shown once. The old one keeps working for a short\n * overlap, so the provider can be moved across without an outage.\n */\n rotateDirectoryToken(\n id: string,\n tokenId: string,\n input: RequestBody<\"ApiOrganizationDirectoryController_rotateToken\"> = {},\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_rotateToken\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/organizations/${enc(id)}/directory/tokens/${enc(tokenId)}/rotate`,\n { body: input },\n );\n }\n\n revokeDirectoryToken(id: string, tokenId: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/directory/tokens/${enc(tokenId)}`,\n );\n }\n\n /** The organization's own provisioning events, newest first. */\n listDirectoryActivity(\n id: string,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryController_activity\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/directory/activity`,\n );\n }\n\n /**\n * The groups the provider has pushed, each with its role mapping.\n *\n * Paginated (20 per page by default, `take` up to 100), so this returns a\n * `Paginator`. Sorted by display name unless `sort_by: \"created\"`; `q`\n * searches display names and external ids.\n *\n * ```ts\n * for await (const group of canopy.organizations.listDirectoryGroups(id)) { … }\n * ```\n */\n listDirectoryGroups(\n id: string,\n query: QueryParams<\"ApiOrganizationDirectoryGroupsController_list\"> = {},\n ): Paginator<OrganizationDirectoryGroupItem> {\n return paginate<OrganizationDirectoryGroupItem>(\n (params) =>\n this.client.request(\n \"GET\",\n `/api/v1/organizations/${enc(id)}/directory/groups`,\n { query: params },\n ),\n { ...query },\n );\n }\n\n /**\n * Grant a listed role to every member of a pushed group, at the\n * organization. A role not on the organization's list is refused with\n * `scim.role_not_grantable`.\n */\n mapDirectoryGroup(\n id: string,\n groupId: string,\n input: RequestBody<\"ApiOrganizationDirectoryGroupsController_map\">,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryGroupsController_map\">> {\n return this.client.request(\n \"PUT\",\n `/api/v1/organizations/${enc(id)}/directory/groups/${enc(groupId)}/mapping`,\n { body: input },\n );\n }\n\n /** Members fall back to the arrival role and stay in the organization. */\n unmapDirectoryGroup(\n id: string,\n groupId: string,\n ): Promise<ResponseBody<\"ApiOrganizationDirectoryGroupsController_unmap\">> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/organizations/${enc(id)}/directory/groups/${enc(groupId)}/mapping`,\n );\n }\n}\n\nexport type OrganizationItem = ItemOf<\n ResponseBody<\"ApiOrganizationsController_listOrganizations\">\n>;\nexport type OrganizationMemberItem = ItemOf<\n ResponseBody<\"ApiOrganizationsController_listMembers\">\n>;\nexport type OrganizationInviteItem = ItemOf<\n ResponseBody<\"ApiOrganizationsController_listInvites\">\n>;\n/** One pushed group from an organization's directory. */\nexport type OrganizationDirectoryGroupItem = ItemOf<\n ResponseBody<\"ApiOrganizationDirectoryGroupsController_list\">\n>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n\nfunction enc(segment: string): string {\n return encodeURIComponent(segment);\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 * One request carries between 1 and 100 checks. More is refused with a\n * `400` (`CanopyError`, `statusCode` 400) and nothing is evaluated, so split\n * a larger set into batches of 100.\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 { Organizations } from \"./resources/organizations.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 102 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 readonly organizations: Organizations;\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 this.organizations = new Organizations(this.client);\n }\n}\n","import type {\n CanopyClient,\n ConditionalResult,\n RequestOptions,\n} from \"./client.js\";\nimport { CanopyAuthorizerError } from \"./errors.js\";\nimport { paginate, type PageParams } from \"./pagination.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, each with\n * the window it is in effect for\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 in effect. Both are held for at most `ttlMs`, which is therefore the\n * delay between an access change and it taking effect; a grant whose window\n * opens or closes sooner than that is re-read at the boundary.\n */\n\nconst DEFAULT_TTL_MS = 60_000;\n\n/**\n * The longest a held answer may be kept: five minutes. `ttlMs` is the delay\n * between an access change and it taking effect, and Canopy promises that\n * delay is short, so a longer value is refused rather than honoured.\n */\nexport const MAX_TTL_MS = 300_000;\n\n/**\n * The largest node set `accessibleNodes` builds unless told otherwise. Past\n * it the answer carries the roots alone, and the caller filters against its\n * own closure table or materialised path instead of an `IN (...)` list.\n */\nexport const DEFAULT_MAX_NODES = 10_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\n/**\n * The page size every read here asks for: the largest the API serves, so a\n * walk makes the fewest calls it can.\n */\nconst PAGE_SIZE = 100;\n\n/**\n * Pages a single read may take before it stops: a million rows at\n * {@link PAGE_SIZE}. Far past any real hierarchy; it exists so a server that\n * keeps promising another page cannot hold a read open forever.\n */\nconst MAX_PAGES = 10_000;\n\n/**\n * Walks of the hierarchy a refresh may make while the hierarchy keeps\n * changing under it. A walk over several pages is confirmed afterwards (see\n * `fetchTree`); a walk that cannot be confirmed this many times running is\n * kept anyway, without a validator, so the next refresh reads it in full.\n */\nconst MAX_TREE_WALKS = 3;\n\n/**\n * Why a check was denied, as far as the grant roots and the tree can say.\n *\n * - `permission_not_held`: no assignment grants the permission anywhere, in\n * effect or not.\n * - `outside_grants`: it is granted, but at no node on the lineage of the\n * node asked about.\n * - `expired`: a grant that would answer has ended, and none is in effect.\n * - `not_yet_effective`: a grant that would answer has not begun, and none\n * is in effect.\n * - `node_missing`: a `node` check named no node, which is a denial rather\n * than an error, because a request whose subject cannot be established\n * must not pass.\n */\nexport type LocalDenialReason =\n | \"permission_not_held\"\n | \"outside_grants\"\n | \"expired\"\n | \"not_yet_effective\"\n | \"node_missing\";\n\n/** The answer to a check: the verdict, and why when it is no. */\nexport interface LocalDecision {\n allowed: boolean;\n reason: LocalDenialReason | null;\n}\n\n/** What a decision hook receives, after the verdict is in. */\nexport interface LocalDecisionEvent {\n query: LocalAuthorizationQuery;\n decision: LocalDecision;\n /** How long the check took, reads included. */\n durationMs: number;\n}\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 * **At most {@link MAX_TTL_MS} (five minutes).** A longer value, a negative\n * one or a non-number throws when the authorizer is created, rather than\n * quietly stretching how long a revoked user keeps access.\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 /**\n * The largest node set {@link LocalAuthorizer.accessibleNodes} builds\n * unless a call says otherwise. Defaults to {@link DEFAULT_MAX_NODES}.\n */\n maxNodes?: number;\n\n /**\n * Called after every decision, allowed or not, with the question and the\n * answer. Never awaited and never allowed to fail the check: a hook that\n * throws is ignored. For audit trails and metrics.\n */\n onDecision?: (event: LocalDecisionEvent) => void;\n\n /** Called after every denial, the same way. For alerting on refusals. */\n onDenied?: (event: LocalDecisionEvent) => void;\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\n/** Where an identity may act with one permission, shaped for a list query. */\nexport interface AccessibleNodes {\n /**\n * The nodes the permission is granted at, in effect now, that no other\n * such node already covers. Each reaches everything beneath it.\n */\n roots: string[];\n /**\n * Every node beneath the roots, the roots included, for an `IN (...)`\n * filter. Null when `envWide`, or when the set would exceed the cap.\n */\n nodes: Set<string> | null;\n /** False when the set exceeded the cap and `nodes` was not built. */\n complete: boolean;\n /**\n * True when a root is the Environment's own root: every node qualifies, so\n * a list needs no filter at all.\n */\n envWide: boolean;\n}\n\nexport interface LocalAuthorizerStats {\n /** Reads of an identity's grant roots, one per refresh however many pages it took. */\n grantFetches: number;\n /** Page requests those reads made: at least one per read, one more per further 100 grants. */\n grantPages: number;\n /** Reads of the hierarchy, one per refresh, including revalidations. */\n treeRequests: number;\n /**\n * Page requests those reads made: one for a revalidation the server answers\n * `304`, otherwise one per page of 100 nodes, plus the request that confirms\n * a walk of several pages was not torn by a change made during it.\n */\n treePages: number;\n /** Revalidations the server answered `304`, so no tree was transferred. */\n treeNotModified: number;\n}\n\n/** One grant root with the window it is in effect for, as epoch milliseconds. */\ninterface GrantWindow {\n node: string;\n from: number | null;\n to: number | null;\n}\n\n/** Permission → every root it was granted at, in effect or not. */\ntype GrantRoots = Map<string, GrantWindow[]>;\n\ninterface GrantEntry {\n roots: GrantRoots;\n expiresAt: number;\n}\n\ninterface TreeEntry {\n parents: Map<string, string | null>;\n /** Node → its children, for expanding a root through its descendants. */\n children: Map<string, string[]>;\n etag: string | null;\n expiresAt: number;\n}\n\n/**\n * One page of grant roots, read off the generated operation rather than\n * restated here: one row per permission, node and assignment window.\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 GrantPage = ResponseBody<\"ApiIdentitiesController_getIdentityGrants\">;\ntype GrantRow = GrantPage[\"items\"][number];\n\n/**\n * One page of the hierarchy as parent edges, read off the generated\n * operation, ordered by node id.\n *\n * Deliberately not the node list. `GET /api/v1/nodes` answers what a\n * dashboard renders — names, statuses, access flags, per-node counts — and a\n * walk upward reads none of it. Measured at 50,000 nodes that is 18.6 MB\n * against 5.0 MB, on a read every consuming process makes at startup.\n */\ntype ParentPage = ResponseBody<\"ApiNodesController_listNodeParents\">;\ntype ParentEdge = ParentPage[\"items\"][number];\n\n/**\n * The versions of Canopy's authorization model this authorizer understands.\n *\n * The grants and parents responses name the model their rows describe. Canopy\n * raises the version when a change makes a walk up the tree answer\n * differently for the same rows (a deny that narrows a grant, a root that no\n * longer reaches every descendant). An authorizer that walked on regardless\n * would allow what the API has started to deny, so a version not listed here\n * is refused, and the fix is upgrading this package.\n */\nconst KNOWN_MODEL_VERSIONS: ReadonlySet<number> = new Set([1]);\n\n/** A page as served, once its model version is known to be understood. */\nfunction understood<T extends { model_version: number }>(\n page: T,\n path: string,\n): T {\n if (!KNOWN_MODEL_VERSIONS.has(page.model_version)) {\n throw new CanopyAuthorizerError(\n \"authorizer.model_version_unknown\",\n `${path} describes authorization model version ${page.model_version}, which this version of @canopy-io/node does not understand. ` +\n `It knows ${[...KNOWN_MODEL_VERSIONS].join(\", \")}. Upgrade @canopy-io/node; until then this authorizer cannot decide, rather than guess.`,\n );\n }\n\n return page;\n}\n\nconst GRANTS_PATH = (identityId: string): string =>\n `/api/v1/identities/${encodeURIComponent(identityId)}/grants`;\n\nconst PARENTS_PATH = \"/api/v1/nodes/parents\";\n\n/** Whether a grant window is in effect at `now`. */\nfunction inEffect(window: GrantWindow, now: number): boolean {\n return (\n (window.from === null || window.from <= now) &&\n (window.to === null || window.to > now)\n );\n}\n\n/** The denial a set of windows that could answer, none in effect, explains. */\nfunction reasonAmong(\n windows: GrantWindow[],\n now: number,\n): \"expired\" | \"not_yet_effective\" {\n return windows.some((window) => window.to !== null && window.to <= now)\n ? \"expired\"\n : \"not_yet_effective\";\n}\n\nexport class LocalAuthorizer {\n private readonly client: CanopyClient;\n private readonly ttlMs: number;\n private readonly maxNodes: number;\n private readonly now: () => number;\n private readonly readOptions: RequestOptions;\n private readonly onDecision:\n ((event: LocalDecisionEvent) => void) | undefined;\n private readonly onDenied: ((event: LocalDecisionEvent) => void) | undefined;\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<string, Promise<GrantRoots>>();\n private pendingTree: Promise<TreeEntry> | undefined;\n\n private stats: LocalAuthorizerStats = {\n grantFetches: 0,\n grantPages: 0,\n treeRequests: 0,\n treePages: 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\n if (\n !Number.isFinite(this.ttlMs) ||\n this.ttlMs < 0 ||\n this.ttlMs > MAX_TTL_MS\n ) {\n throw new RangeError(\n `ttlMs must be between 0 and ${MAX_TTL_MS} (five minutes); got ${String(this.ttlMs)}. ` +\n \"It is how long a revoked user keeps access, so it is capped.\",\n );\n }\n\n this.maxNodes = options.maxNodes ?? DEFAULT_MAX_NODES;\n\n if (!Number.isInteger(this.maxNodes) || this.maxNodes < 1) {\n throw new RangeError(\n `maxNodes must be a positive integer; got ${String(this.maxNodes)}.`,\n );\n }\n\n this.now = options.now ?? (() => Date.now());\n this.onDecision = options.onDecision;\n this.onDenied = options.onDenied;\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, and why not when it does not.\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<LocalDecision> {\n const started = this.now();\n const decided = (decision: LocalDecision): LocalDecision => {\n this.announce({\n query,\n decision,\n durationMs: Math.max(0, this.now() - started),\n });\n\n return decision;\n };\n\n if (!options.signal) {\n return decided(await 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])\n .then(decided)\n .finally(() => {\n if (onAbort) {\n signal.removeEventListener(\"abort\", onAbort);\n }\n });\n }\n\n /**\n * The nodes the identity holds the permission at, in effect now, reduced to\n * the ones no other such node already covers, and whether one of them is\n * the Environment's root. The roots alone are enough for an application\n * that keeps a closure table or a materialised path: it filters by \"beneath\n * one of these\" without an expanded set.\n *\n * Reads the tree, since minimality and `envWide` are questions about it; a\n * root the readable hierarchy does not contain raises\n * `authorizer.hierarchy_incomplete`, as a check at such a node does.\n */\n async grantRoots(\n identityId: string,\n permission: string,\n ): Promise<{ roots: string[]; envWide: boolean }> {\n const now = this.now();\n const held = (await this.grantRootsFor(identityId)).get(permission) ?? [];\n const granted = new Set(\n held.filter((window) => inEffect(window, now)).map((w) => w.node),\n );\n\n if (granted.size === 0) {\n return { roots: [], envWide: false };\n }\n\n const { parents } = await this.treeEntry();\n const roots: string[] = [];\n let envWide = false;\n\n for (const node of granted) {\n if (!parents.has(node)) {\n throw this.hierarchyIncomplete(node);\n }\n\n if (parents.get(node) === null) {\n envWide = true;\n }\n\n let covered = false;\n let depth = 0;\n\n for (\n let current = parents.get(node);\n current && depth < MAX_WALK_DEPTH;\n current = parents.get(current), depth += 1\n ) {\n if (granted.has(current)) {\n covered = true;\n\n break;\n }\n }\n\n if (!covered) {\n roots.push(node);\n }\n }\n\n return { roots, envWide };\n }\n\n /**\n * Where the identity may act with the permission, as the set a list query\n * filters by: {@link grantRoots} expanded through their descendants, up to\n * `maxNodes` (the authorizer's default unless given here).\n *\n * Past the cap `nodes` is null and `complete` false: the set is too large\n * to be worth an `IN (...)` list, and the caller filters by `roots`\n * instead. An `envWide` answer carries no set either, since every node\n * qualifies and a filter would only slow the query down.\n *\n * Computed from the same cached grant roots and tree a check uses, so a\n * list filtered by it and the check on a write cannot disagree, and it goes\n * stale on the same `ttlMs`.\n */\n async accessibleNodes(\n identityId: string,\n permission: string,\n options: { maxNodes?: number } = {},\n ): Promise<AccessibleNodes> {\n const cap = options.maxNodes ?? this.maxNodes;\n const { roots, envWide } = await this.grantRoots(identityId, permission);\n\n if (envWide) {\n return { roots, envWide: true, nodes: null, complete: true };\n }\n\n if (roots.length === 0) {\n return { roots, envWide: false, nodes: new Set(), complete: true };\n }\n\n const { children } = await this.treeEntry();\n const nodes = new Set<string>();\n const pending = [...roots];\n\n while (pending.length > 0) {\n const node = pending.pop() as string;\n\n if (nodes.has(node)) {\n continue;\n }\n\n nodes.add(node);\n\n if (nodes.size > cap) {\n return { roots, envWide: false, nodes: null, complete: false };\n }\n\n for (const child of children.get(node) ?? []) {\n pending.push(child);\n }\n }\n\n return { roots, envWide: false, nodes, complete: true };\n }\n\n /**\n * Every permission the identity holds at the node, by grant or by\n * inheritance: the list a screen renders its controls from, answered from\n * the same cached grant roots and tree a check uses.\n */\n async permissionsAt(identityId: string, nodeId: string): Promise<string[]> {\n const answers = await this.permissionsAtMany(identityId, [nodeId]);\n\n return answers.get(nodeId) ?? [];\n }\n\n /**\n * {@link permissionsAt} for several nodes at once, as node → permissions:\n * the rows of a list each with their own controls, answered from one read\n * of the grant roots and one walk per node.\n */\n async permissionsAtMany(\n identityId: string,\n nodeIds: readonly string[],\n ): Promise<Map<string, string[]>> {\n const now = this.now();\n const roots = await this.grantRootsFor(identityId);\n const answers = new Map<string, string[]>();\n\n for (const nodeId of new Set(nodeIds)) {\n const path = await this.lineageOf(nodeId);\n const held: string[] = [];\n\n for (const [permission, windows] of roots) {\n if (\n windows.some(\n (window) => path.has(window.node) && inEffect(window, now),\n )\n ) {\n held.push(permission);\n }\n }\n\n answers.set(nodeId, held.sort());\n }\n\n return answers;\n }\n\n private async decide(query: LocalAuthorizationQuery): Promise<LocalDecision> {\n const now = this.now();\n const held = (await this.grantRootsFor(query.identity_id)).get(\n query.permission,\n );\n\n if (!held || held.length === 0) {\n return { allowed: false, reason: \"permission_not_held\" };\n }\n\n if ((query.scope ?? \"node\") === \"app_wide\") {\n return held.some((window) => inEffect(window, now))\n ? { allowed: true, reason: null }\n : { allowed: false, reason: reasonAmong(held, now) };\n }\n\n if (!query.node_id) {\n return { allowed: false, reason: \"node_missing\" };\n }\n\n // A grant in effect at the node itself needs no tree at all, which also\n // means an unreachable hierarchy cannot deny a direct grant.\n if (\n held.some(\n (window) => window.node === query.node_id && inEffect(window, now),\n )\n ) {\n return { allowed: true, reason: null };\n }\n\n const path = await this.lineageOf(query.node_id);\n const reachable = held.filter((window) => path.has(window.node));\n\n if (reachable.some((window) => inEffect(window, now))) {\n return { allowed: true, reason: null };\n }\n\n if (reachable.length === 0) {\n return { allowed: false, reason: \"outside_grants\" };\n }\n\n return { allowed: false, reason: reasonAmong(reachable, now) };\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 role deactivated or reactivated, a node moved). A\n * deactivated role grants nothing to anyone holding it, so until the cache\n * is cleared or expires, its holders keep being allowed locally.\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 /** Fire the decision hooks, after the verdict and without waiting on them. */\n private announce(event: LocalDecisionEvent): void {\n for (const hook of [\n this.onDecision,\n event.decision.allowed ? undefined : this.onDenied,\n ]) {\n if (!hook) {\n continue;\n }\n\n try {\n hook(event);\n } catch {\n // A hook is observation. Its failure must not become a denial, an\n // allow, or an error the caller sees.\n }\n }\n }\n\n /** The node and its ancestors, from the tree this client can read. */\n private async lineageOf(nodeId: string): Promise<Set<string>> {\n const { parents } = await this.treeEntry();\n\n // The hierarchy we hold has to actually contain the node being asked\n // about. `GET /api/v1/nodes/parents` answers the hierarchy scoped to the\n // caller, and a credential that cannot read it gets an empty one — with a\n // `200`, so nothing looks wrong. Walking off the end of that map would\n // answer as if the node had no ancestors, which reads as \"this identity\n // lacks the permission here\" when the truth is that we cannot see far\n // 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 this.hierarchyIncomplete(nodeId);\n }\n\n const path = new Set<string>([nodeId]);\n let current = parents.get(nodeId);\n let depth = 0;\n\n while (current && depth < MAX_WALK_DEPTH) {\n path.add(current);\n current = parents.get(current);\n depth += 1;\n }\n\n return path;\n }\n\n private hierarchyIncomplete(nodeId: string): CanopyAuthorizerError {\n return 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 private async grantRootsFor(identityId: string): Promise<GrantRoots> {\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 /**\n * Every page of the identity's grant roots, with their windows, folded\n * into permission → roots.\n *\n * Each row is one permission at one node for one assignment, so a\n * permission granted at three nodes arrives as three rows, possibly on\n * different pages. Stopping after the first page would under-report what\n * the identity holds: a false deny, the safe direction, but a wrong answer\n * all the same.\n *\n * Rows outside their window are kept: they are what lets a denial say\n * `expired` or `not_yet_effective`, and the entry expires at the nearest\n * window boundary when that comes before the TTL, so a grant takes effect\n * or ends on time rather than up to `ttlMs` late.\n */\n private async fetchGrantRoots(identityId: string): Promise<GrantRoots> {\n this.stats.grantFetches += 1;\n\n const path = GRANTS_PATH(identityId);\n const rows = paginate<GrantRow>(\n (query) => {\n this.stats.grantPages += 1;\n\n return this.client\n .request<GrantPage>(\"GET\", path, {\n ...this.readOptions,\n query: { ...query, include: \"windows\" },\n })\n .then((page) => understood(page, path));\n },\n { page: 1, take: PAGE_SIZE },\n { maxPages: MAX_PAGES },\n );\n\n const roots: GrantRoots = new Map();\n const now = this.now();\n let boundary = Number.POSITIVE_INFINITY;\n\n for await (const row of rows) {\n const window: GrantWindow = {\n node: row.node_id,\n from: row.effective_from ? Date.parse(row.effective_from) : null,\n to: row.effective_to ? Date.parse(row.effective_to) : null,\n };\n\n for (const edge of [window.from, window.to]) {\n if (edge !== null && edge > now && edge < boundary) {\n boundary = edge;\n }\n }\n\n const windows = roots.get(row.permission);\n\n if (windows) {\n windows.push(window);\n } else {\n roots.set(row.permission, [window]);\n }\n }\n\n this.grants.set(identityId, {\n roots,\n expiresAt: Math.min(now + this.ttlMs, boundary),\n });\n\n return roots;\n }\n\n private async treeEntry(): Promise<TreeEntry> {\n if (this.tree && this.tree.expiresAt > this.now()) {\n return this.tree;\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 * The edges come a page at a time, so only the first page is conditional:\n * its validator covers the whole hierarchy, and a `304` to it means no page\n * has changed. On a `200` the remaining pages are read plainly and the map\n * is rebuilt from every page.\n *\n * A walk over several pages is not one snapshot. A node added or removed\n * between two page reads shifts the rows under the offset, so a row can be\n * skipped, which would leave a node out of the map until the next refresh.\n * So the walk is confirmed by asking for the first page again with the\n * validator it came with: a `304` proves nothing changed while the pages\n * were read. A `200` is a fresh first page, and the walk starts again from\n * it, up to {@link MAX_TREE_WALKS} times.\n */\n private async fetchTree(): Promise<TreeEntry> {\n this.stats.treeRequests += 1;\n\n const held = this.tree;\n\n let first = await this.parentsFirstPage(held?.etag ?? undefined);\n\n if (!first.modified) {\n if (held) {\n this.stats.treeNotModified += 1;\n this.tree = { ...held, expiresAt: this.now() + this.ttlMs };\n\n return this.tree;\n }\n\n // A `304` to a request that carried no validator has nothing to keep.\n return this.keepTree([], null);\n }\n\n for (let walk = 1; ; walk++) {\n const edges = await this.parentsRemainingPages(first.data);\n\n // One page is one response, so it cannot have been torn; without a\n // validator there is nothing to confirm with.\n if (!spansPages(first.data) || first.etag === null) {\n return this.keepTree(edges, first.etag);\n }\n\n const confirm = await this.parentsFirstPage(first.etag);\n\n if (!confirm.modified) {\n return this.keepTree(edges, first.etag);\n }\n\n if (walk >= MAX_TREE_WALKS) {\n // Still changing. Keep the latest walk, but with no validator, so the\n // next refresh reads every page again rather than revalidating a map\n // that may be missing a node.\n return this.keepTree(edges, null);\n }\n\n first = confirm;\n }\n }\n\n private parentsFirstPage(\n etag: string | undefined,\n ): Promise<ConditionalResult<ParentPage>> {\n this.stats.treePages += 1;\n\n return this.client\n .requestConditional<ParentPage>(\"GET\", PARENTS_PATH, etag, {\n ...this.readOptions,\n query: { page: 1, take: PAGE_SIZE },\n })\n .then((result) => {\n // A `304` carries no body; it confirms edges already checked.\n if (result.modified) {\n understood(result.data, PARENTS_PATH);\n }\n\n return result;\n });\n }\n\n /** The first page's edges followed by every later page's. */\n private async parentsRemainingPages(\n first: ParentPage,\n ): Promise<ParentEdge[]> {\n const edges: ParentEdge[] = [...first.items];\n\n if (!spansPages(first)) {\n return edges;\n }\n\n const rest = paginate<ParentEdge>(\n (query: PageParams) => {\n this.stats.treePages += 1;\n\n return this.client\n .request<ParentPage>(\"GET\", PARENTS_PATH, {\n ...this.readOptions,\n query,\n })\n .then((page) => understood(page, PARENTS_PATH));\n },\n { page: first.pagination.page + 1, take: PAGE_SIZE },\n { maxPages: MAX_PAGES - 1 },\n );\n\n for await (const page of rest.pages()) {\n for (const edge of page.items) {\n edges.push(edge);\n }\n }\n\n return edges;\n }\n\n private keepTree(edges: ParentEdge[], etag: string | null): TreeEntry {\n // One string per node. A parsed response holds each id twice, once as\n // its own node's `id` and again, as a separate copy, in every child's\n // `parent_node_id`; storing those copies doubled the cache. So the\n // parent is stored as the node's own `id` string, found through a map\n // of every page's ids first, since a parent may arrive after its\n // children, on a later page. The lookup map is gone once this returns.\n const ids = new Map<string, string>();\n\n for (const edge of edges) {\n ids.set(edge.id, edge.id);\n }\n\n const parents = new Map<string, string | null>();\n const children = new Map<string, string[]>();\n\n for (const edge of edges) {\n const parent =\n edge.parent_node_id === null || edge.parent_node_id === undefined\n ? null\n : (ids.get(edge.parent_node_id) ?? edge.parent_node_id);\n\n parents.set(edge.id, parent);\n\n if (parent !== null) {\n const siblings = children.get(parent);\n\n if (siblings) {\n siblings.push(edge.id);\n } else {\n children.set(parent, [edge.id]);\n }\n }\n }\n\n this.tree = {\n parents,\n children,\n etag,\n expiresAt: this.now() + this.ttlMs,\n };\n\n return this.tree;\n }\n}\n\n/**\n * Whether a first page says more follow. An empty page ends the walk however\n * the server describes it, as the paginator's own loop does.\n */\nfunction spansPages(first: ParentPage): boolean {\n return first.pagination.has_next_page && first.items.length > 0;\n}\n","import {\n isCanopyAuthorizerError,\n isCanopyError,\n isCanopyTokenError,\n} from \"./errors.js\";\n\n/**\n * The HTTP answer a failure should become, for code that verifies tokens or\n * authorizes requests outside the NestJS guards (Express, Fastify, a worker).\n * The guards use the same mapping, so every integration answers alike.\n */\nexport interface FailureStatus {\n status: number;\n /** A message safe to send to the caller; the detail stays on the error. */\n message: string;\n}\n\n/**\n * The answer for a failed {@link TokenVerifier.verify}: `401` when the token is\n * at fault, `503` when the signing keys could not be read and the token may be\n * perfectly good.\n *\n * The difference matters. A client reads `401` as \"your token is stale\",\n * discards a valid one and asks for another, which aims a refresh storm at an\n * issuer that is already down, and an outage that only emits 4xx is invisible\n * to anything watching for 5xx.\n *\n * Anything that is not a token error is returned as `500`: it is a bug, not a\n * verdict on the token.\n */\nexport function tokenErrorStatus(error: unknown): FailureStatus {\n if (!isCanopyTokenError(error)) {\n return { status: 500, message: \"Authentication could not be checked.\" };\n }\n\n if (error.code === \"token.jwks_unavailable\") {\n return {\n status: 503,\n message: \"Authentication is temporarily unavailable.\",\n };\n }\n\n return { status: 401, message: \"Invalid or expired access token.\" };\n}\n\n/**\n * The answer for a failed authorization check ({@link LocalAuthorizer.evaluate}\n * or a {@link Canopy} call that decides access). Every branch denies; they say\n * different things so an incident is diagnosable:\n *\n * - `500` when the authorizer cannot see far enough to decide (a credential\n * that cannot read the hierarchy), when Canopy rejected our own credential,\n * when the endpoint is not served (an SDK newer than the API), or on a 4xx\n * nobody anticipated. No retry fixes these.\n * - `503` when Canopy did not answer, or answered 429 or 5xx.\n * - `403` when Canopy answered that the identity is not in this Environment.\n */\nexport function authorizationErrorStatus(error: unknown): FailureStatus {\n if (isCanopyAuthorizerError(error)) {\n return {\n status: 500,\n message: `Authorization is misconfigured: ${error.message}`,\n };\n }\n\n if (!isCanopyError(error)) {\n return {\n status: 503,\n message: \"Authorization is temporarily unavailable.\",\n };\n }\n\n if (error.isAuthFailure) {\n return {\n status: 500,\n message:\n \"Authorization is misconfigured. Check the Canopy API key and its scopes.\",\n };\n }\n\n // A 404 with no error code is the framework's own \"no such route\": this\n // Canopy does not serve the endpoint the authorizer reads.\n if (error.statusCode === 404 && error.code === null) {\n return {\n status: 500,\n message:\n `Authorization is misconfigured: ${error.request.method} ${error.request.path} is not served by this Canopy. ` +\n \"The SDK requires an API that exposes the identity grants endpoint.\",\n };\n }\n\n // A 404 with a code is a real answer: the identity is not in this\n // Environment. Deny, and say nothing about what was missing.\n if (error.statusCode === 404) {\n return { status: 403, message: \"Could not evaluate the permission.\" };\n }\n\n if (error.isRateLimited || error.statusCode >= 500) {\n return {\n status: 503,\n message: \"Authorization is temporarily unavailable.\",\n };\n }\n\n return { status: 500, message: \"Authorization could not be evaluated.\" };\n}\n","import { CanopyTokenError } from \"./errors.js\";\nimport { withoutTrailingSlashes } from \"./strings.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 * environmentId: process.env.CANOPY_ENVIRONMENT_ID,\n * });\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 origin. Matches the client's default base URL. */\nconst HOSTED_ORIGIN = \"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\n/**\n * The issuer a verifier accepts: the hosted Environment's, or the one named.\n * There is no default, because every Environment is its own issuer and a\n * guess would reject every real token.\n */\nfunction resolveIssuer(options: TokenVerifierOptions): string {\n const { environmentId, issuer } = options;\n\n if (environmentId && issuer) {\n throw new TypeError(\n \"TokenVerifier takes environmentId or issuer, not both.\",\n );\n }\n\n if (issuer) {\n return withoutTrailingSlashes(issuer);\n }\n\n if (environmentId) {\n return `${HOSTED_ORIGIN}/environments/${environmentId}`;\n }\n\n throw new TypeError(\n \"TokenVerifier needs environmentId (the Environment your tokens come from) \" +\n \"or, on a custom auth domain or self-hosted instance, issuer.\",\n );\n}\n\nexport interface TokenVerifierOptions {\n /**\n * The Environment whose tokens are accepted. Every Environment is its own\n * issuer with its own signing keys, at\n * `https://auth.canopy-io.com/environments/<id>`, so on hosted Canopy this is\n * all verification needs. A token from any other Environment fails.\n *\n * Set exactly one of `environmentId` and `issuer`; the constructor throws\n * with neither or both.\n */\n environmentId?: string;\n\n /**\n * The issuer whose tokens are accepted, matched against `iss` exactly. Set it\n * instead of `environmentId` on a custom auth domain (`https://auth.acme.com`)\n * or a self-hosted instance (`<origin>/environments/<id>`).\n *\n * Pointed at the wrong issuer, verification fails closed: a token is\n * rejected, never mistakenly 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 /**\n * The principal types accepted, matched against the `type` claim. Defaults to\n * `[\"identity\"]`: the people who sign in to your application.\n *\n * Canopy also signs tokens for its own administrators (`user`), its staff\n * (`platform`) and, for some flows, API keys (`api_key`), all with the same\n * keys and issuer. A backend that serves your end users should accept none\n * of them, so they are refused unless you name them here.\n */\n allowedTypes?: ReadonlyArray<CanopyTokenClaims[\"type\"]>;\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 /**\n * How the session was proven: `pwd`, `otp`, or `sso`, plus `mfa` once a\n * second factor was verified. Identity tokens carry it; check for `mfa`\n * before allowing a sensitive action.\n */\n amr?: string[];\n /**\n * The organization this session is acting in — present only on identity\n * tokens from an Environment with the organizations container on, for an\n * identity that belongs to at least one organization. Always minted\n * together with `org_roles`; read the pair through {@link orgContext}\n * rather than separately.\n */\n org_id?: string;\n /**\n * The names of the roles the identity holds at the organization's own node,\n * sorted; empty for a member who holds none there. Membership is admission,\n * not a role: a member may hold roles only beneath the organization, or\n * none at all.\n */\n org_roles?: string[];\n [claim: string]: unknown;\n}\n\n/**\n * The organization context a verified token carries: which organization the\n * session is acting in, and the roles it holds at that organization's node.\n */\nexport interface CanopyOrgContext {\n /** The organization's id — also a hierarchy node id, usable as `node_id`. */\n orgId: string;\n /** The roles' names (not ids) held at the organization node: what `org_roles` carries. Empty for a member holding none there. */\n orgRoles: string[];\n}\n\n/**\n * The organization context of a verified token, or `null` when it has none.\n *\n * `null` is an ordinary answer, not a failure: it is every token from an\n * Environment without the organizations container on, and every identity\n * that belongs to no organization yet. Branch on it rather than on the raw claims —\n * Canopy mints `org_id` and `org_roles` together, and this helper refuses a\n * half-present pair instead of letting one claim be read as though the other\n * were there. An empty `orgRoles` is a member of the organization holding no\n * role at its node; authorize such a session by evaluating, never by the\n * list's length.\n *\n * ```ts\n * const claims = await verifier.verify(token);\n * const org = orgContext(claims);\n *\n * if (org) {\n * // acting inside org.orgId, holding org.orgRoles at its node\n * }\n * ```\n */\nexport function orgContext(claims: CanopyTokenClaims): CanopyOrgContext | null {\n const { org_id, org_roles } = claims;\n\n if (\n typeof org_id !== \"string\" ||\n org_id === \"\" ||\n !Array.isArray(org_roles) ||\n org_roles.some((role) => typeof role !== \"string\" || role === \"\")\n ) {\n return null;\n }\n\n return { orgId: org_id, orgRoles: [...org_roles] };\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 allowedTypes: ReadonlySet<string>;\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 /** Whether the latest read of the key set failed, for an unknown `kid`. */\n private lastFetchFailed = false;\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 = resolveIssuer(options);\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 this.allowedTypes = new Set(options.allowedTypes ?? [\"identity\"]);\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 (!this.allowedTypes.has(claims.type)) {\n throw new CanopyTokenError(\n \"token.type_not_allowed\",\n `Token is for a \"${claims.type}\" principal; this verifier accepts ${[\n ...this.allowedTypes,\n ]\n .map((type) => `\"${type}\"`)\n .join(\", \")}. Set \\`allowedTypes\\` to accept another.`,\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 try {\n await this.refreshKeys();\n } catch (error) {\n // Stale is not invalid. Keys that verified tokens a minute ago still\n // verify them while the issuer is unreachable; failing here would\n // turn an issuer outage into a 503 for every working session, every\n // time the floor lets another attempt through. With nothing cached\n // there is nothing to fall back on, so the failure stands.\n if (this.keys.size === 0) {\n throw error;\n }\n }\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 // The key set could not be read, so whether this `kid` exists is unknown:\n // a token signed after a rotation is as likely as a forged one. Saying the\n // key does not exist would turn an outage into a 401 for good tokens.\n if (this.lastFetchFailed) {\n throw new CanopyTokenError(\n \"token.jwks_unavailable\",\n `Signing keys at ${this.jwksUri} could not be read to look up kid \"${kid}\".`,\n );\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 try {\n await this.readKeys();\n this.lastFetchFailed = false;\n } catch (error) {\n this.lastFetchFailed = true;\n throw error;\n }\n }\n\n private async readKeys(): Promise<void> {\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","import type { components } from \"./generated/types.js\";\n\n/**\n * Typed webhook deliveries.\n *\n * Canopy publishes one schema per webhook event, named `Webhook…Event`, each\n * the shared envelope narrowed to that event's name, `resource_type` and\n * `metadata`. These types read them straight out of the generated document,\n * so a handler is written against the contract rather than against\n * deliveries it happened to capture, and `npm run generate` brings in any\n * field the API adds.\n *\n * app.post(\"/webhooks/canopy\", (req, res) => {\n * const delivery = req.body as WebhookDelivery;\n *\n * if (isWebhookEvent(delivery, \"organization.member.added\")) {\n * delivery.data.metadata.identity_id; // string\n * }\n * });\n *\n * `GET /api/v1/webhooks/event-types` names each event's schema in\n * `payload_schema`, which is the name to look up in `Schema<…>`.\n */\n\n/** The name of every published delivery schema. */\ntype WebhookSchemaName = Extract<\n keyof components[\"schemas\"],\n `Webhook${string}Event`\n>;\n\n/** A delivery of any webhook event: `{ event, data }`. */\nexport type WebhookDelivery = components[\"schemas\"][WebhookSchemaName];\n\n/** Every event a subscription can receive. */\nexport type WebhookEventName = WebhookDelivery[\"event\"];\n\n/**\n * The delivery of one event, e.g. `WebhookEvent<\"assignment.created\">`.\n * Its `data.metadata` carries exactly the fields that event sends, with the\n * ones every delivery includes required and the rest optional.\n */\nexport type WebhookEvent<Name extends WebhookEventName> = Extract<\n WebhookDelivery,\n { event: Name }\n>;\n\n/** The `data` object of one event's delivery. */\nexport type WebhookEventData<Name extends WebhookEventName> =\n WebhookEvent<Name>[\"data\"];\n\n/**\n * Narrow a delivery to one event by its name. A type guard rather than a\n * switch over `delivery.event`, so a handler for one event reads that\n * event's `metadata` without a cast.\n */\nexport function isWebhookEvent<Name extends WebhookEventName>(\n delivery: WebhookDelivery,\n name: Name,\n): delivery is WebhookEvent<Name> {\n return delivery.event === name;\n}\n"]}
|