@canopy-io/node 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/pagination.ts","../src/resources/assignments.ts","../src/resources/identities.ts","../src/resources/permissions.ts","../src/resources/roles.ts","../src/canopy.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Everything this client throws.\n *\n * Two classes, because callers act on the distinction: `CanopyError` means the\n * API answered and said no, `CanopyConnectionError` means it never answered.\n * The first is a decision you may need to surface to a user; the second is\n * usually worth retrying or alerting on.\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 constructor(\n body: CanopyErrorBody,\n request: { method: string; path: string },\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 }\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,\n * timeout, or an aborted signal.\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/** 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","import {\n CanopyConnectionError,\n CanopyError,\n type CanopyErrorBody,\n} from \"./errors.js\";\n\n/**\n * Offset pagination — the default across the API.\n */\nexport interface OffsetPagination {\n page: number;\n take: number;\n item_count: number;\n page_count: number;\n has_previous_page: boolean;\n has_next_page: boolean;\n}\n\n/**\n * Cursor pagination — used by append-heavy feeds (the audit log) where an\n * offset window drifts under concurrent writes.\n *\n * The envelope is identical to the offset case; only this object differs,\n * which is precisely why hand-written pagination loops break on one of them.\n */\nexport interface CursorPagination {\n next_cursor: string | null;\n}\n\nexport type Pagination = OffsetPagination | CursorPagination;\n\nexport function isCursorPagination(\n pagination: Pagination,\n): pagination is CursorPagination {\n return \"next_cursor\" in pagination;\n}\n\n/** A collection response, paginated or not. */\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 /** 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 * Declares this call safe to repeat, which allows retrying a 5xx.\n *\n * Needed because the OpenAPI document only marks one operation\n * `x-canopy-idempotent`, so the spec cannot drive this. GET, HEAD, PUT and\n * DELETE are treated as idempotent by HTTP definition; POST is not, and a\n * blind retry there can create a second role assignment or a second\n * invitation. Set this only when the endpoint genuinely tolerates a repeat.\n */\n idempotent?: boolean;\n}\n\nconst DEFAULT_BASE_URL = \"https://auth.canopy-io.com\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_RETRIES = 2;\n\n/** Idempotent by HTTP definition (RFC 9110 §9.2.2). */\nconst IDEMPOTENT_METHODS = new Set([\"GET\", \"HEAD\", \"PUT\", \"DELETE\"]);\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 authHeaders: Record<string, string>;\n private readonly extraHeaders: Record<string, string>;\n private readonly fetchImpl: typeof globalThis.fetch;\n\n constructor(options: CanopyClientOptions = {}) {\n if (!options.apiKey && !options.accessToken) {\n throw new TypeError(\n \"CanopyClient requires either `apiKey` (server-to-server) or `accessToken` (a user or identity JWT).\",\n );\n }\n\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.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 url = this.buildUrl(path, options.query);\n const upper = method.toUpperCase();\n const retryable = options.idempotent ?? IDEMPOTENT_METHODS.has(upper);\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n await delay(backoffMs(attempt, lastError));\n }\n\n try {\n const response = await this.send(upper, url, options);\n\n if (this.shouldRetry(response.status, retryable, attempt)) {\n lastError = await this.toError(response, upper, path);\n continue;\n }\n\n if (!response.ok) {\n throw await this.toError(response, upper, path);\n }\n\n return await this.unwrap<T>(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 // Nothing is known about whether a non-idempotent request took effect,\n // so it must not be repeated.\n if (!retryable || attempt === this.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 ${this.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 ): boolean {\n if (attempt >= this.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 timer =\n this.timeoutMs > 0\n ? setTimeout(() => controller.abort(), this.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.\n const onAbort = () => controller.abort();\n\n options.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n ...this.extraHeaders,\n ...this.authHeaders,\n };\n\n if (options.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n }\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>(response: Response): 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 const parsed = JSON.parse(text) as Record<string, unknown>;\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 const error = new CanopyError(body, { method, path });\n\n if (retryAfter !== null) {\n Object.defineProperty(error, \"retryAfterMs\", {\n value: retryAfter,\n enumerable: true,\n });\n }\n\n return error;\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(attempt: number, lastError: unknown): number {\n const advised =\n lastError && typeof lastError === \"object\" && \"retryAfterMs\" in lastError\n ? Number((lastError as { retryAfterMs: unknown }).retryAfterMs)\n : NaN;\n\n if (Number.isFinite(advised)) {\n return advised;\n }\n\n const base = 250 * 2 ** (attempt - 1);\n\n return base + Math.random() * base;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction describe(error: unknown): string {\n if (error instanceof Error) {\n return error.name === \"AbortError\" ? \"timed out or aborted\" : error.message;\n }\n\n return String(error);\n}\n","import { type Collection, isCursorPagination } from \"./client.js\";\n\n/** Query parameters for one page request. */\nexport type PageParams = Record<\n string,\n string | number | boolean | undefined | null\n>;\n\n/** Fetches a single page. Supplied by each resource. */\nexport type PageFetcher<T> = (params: PageParams) => Promise<Collection<T>>;\n\nexport interface PaginateOptions {\n /** Stop after this many pages. Guards against a server that never ends. */\n maxPages?: number;\n}\n\nconst DEFAULT_MAX_PAGES = 1_000;\n\n/**\n * Walks a paginated endpoint without the caller knowing which pagination style\n * it uses.\n *\n * This exists because the two styles are indistinguishable at the top level:\n * both answer `{ items, pagination }`. Offset carries\n * `page`/`has_next_page`; cursor carries `next_cursor`. The audit log is\n * cursor-paginated and everything else is offset, so a hand-written loop works\n * against one and silently reads only the first page of the other — or loops\n * forever.\n *\n * The style is inferred from the first response rather than declared, so a\n * resource does not have to restate what the server already says. Only the\n * cursor or page parameter is managed here; page size stays whatever the\n * caller passed, because the two styles even name that differently (`take` for\n * offset, `limit` for the cursor feeds).\n */\nexport class Paginator<T> implements AsyncIterable<T> {\n private readonly fetchPage: PageFetcher<T>;\n private readonly initial: PageParams;\n private readonly maxPages: number;\n\n constructor(\n fetchPage: PageFetcher<T>,\n initial: PageParams = {},\n options: PaginateOptions = {},\n ) {\n this.fetchPage = fetchPage;\n this.initial = initial;\n this.maxPages = options.maxPages ?? DEFAULT_MAX_PAGES;\n }\n\n /** Every item across every page. */\n async *[Symbol.asyncIterator](): AsyncIterator<T> {\n for await (const page of this.pages()) {\n for (const item of page.items) {\n yield item;\n }\n }\n }\n\n /**\n * Page by page, for callers that need the pagination metadata or want to\n * process in batches rather than item by item.\n */\n async *pages(): AsyncGenerator<Collection<T>> {\n let params: PageParams = { ...this.initial };\n let seenCursor: string | null = null;\n let pageCount = 0;\n\n for (;;) {\n const page = await this.fetchPage(params);\n\n pageCount++;\n\n yield page;\n\n const pagination = page.pagination;\n\n // No pagination object at all: an unpaginated `{ items }` collection.\n if (!pagination) {\n return;\n }\n\n // A server that keeps promising more while returning nothing would spin\n // forever; the empty page is the honest end of the feed.\n if (page.items.length === 0) {\n return;\n }\n\n if (pageCount >= this.maxPages) {\n return;\n }\n\n if (isCursorPagination(pagination)) {\n const next = pagination.next_cursor;\n\n if (next === null || next === seenCursor) {\n // Null is the documented end. An unchanged cursor means the server\n // is not advancing, which would otherwise be an infinite loop.\n return;\n }\n\n seenCursor = next;\n params = { ...params, cursor: next };\n\n continue;\n }\n\n if (!pagination.has_next_page) {\n return;\n }\n\n params = { ...params, page: pagination.page + 1 };\n }\n }\n\n /**\n * Collect everything into an array.\n *\n * Bounded on purpose: an unbounded drain of an audit log will exhaust memory\n * on a busy account, so the cap is a parameter rather than a footnote. Use\n * the iterator for large feeds.\n */\n async all(max = 10_000): Promise<T[]> {\n const collected: T[] = [];\n\n for await (const item of this) {\n collected.push(item);\n\n if (collected.length >= max) {\n break;\n }\n }\n\n return collected;\n }\n\n /** The first item, or undefined. Stops after one page. */\n async first(): Promise<T | undefined> {\n for await (const item of this) {\n return item;\n }\n\n return undefined;\n }\n}\n\n/** Convenience wrapper so resources read as `paginate(fetch, params)`. */\nexport function paginate<T>(\n fetchPage: PageFetcher<T>,\n initial: PageParams = {},\n options: PaginateOptions = {},\n): Paginator<T> {\n return new Paginator(fetchPage, initial, options);\n}\n","import type { CanopyClient } from \"../client.js\";\nimport { paginate, type Paginator } from \"../pagination.js\";\nimport type { QueryParams, RequestBody, ResponseBody } from \"../schema.js\";\n\n/**\n * Role grants: which identity holds which role, at which node.\n *\n * A grant at a node applies to every descendant, which is what makes one\n * assignment cover a whole branch.\n */\nexport class Assignments {\n constructor(private readonly client: CanopyClient) {}\n\n /** Every assignment in the Application, across all nodes. */\n list(\n query: QueryParams<\"ApiAssignmentsController_listAppWideAssignments\"> = {},\n ): Paginator<AssignmentItem> {\n return paginate<AssignmentItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/assignments/app-wide\", {\n query: params,\n }),\n { ...query },\n );\n }\n\n /**\n * Grant a role at a node.\n *\n * Not retried automatically on a 5xx: a repeat could create a second grant,\n * and the server cannot tell the two apart. If the call fails without an\n * answer, read the current assignments before retrying.\n */\n create(\n input: RequestBody<\"ApiAssignmentsController_assignRole\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_assignRole\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments\", { body: input });\n }\n\n update(\n id: string,\n input: RequestBody<\"ApiAssignmentsController_updateAssignment\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_updateAssignment\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/assignments/${encodeURIComponent(id)}`,\n { body: input },\n );\n }\n\n delete(id: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/assignments/${encodeURIComponent(id)}`,\n );\n }\n\n /**\n * Grant many at once. Answers 207 with a per-item result rather than failing\n * the batch, so inspect `results` — a 2xx here does not mean every grant\n * succeeded.\n */\n bulkCreate(\n input: RequestBody<\"ApiAssignmentsController_bulkCreate\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_bulkCreate\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments/bulk-create\", {\n body: input,\n });\n }\n\n /** Same partial-success contract as `bulkCreate`. */\n bulkRemove(\n input: RequestBody<\"ApiAssignmentsController_bulkRemove\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_bulkRemove\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments/bulk-remove\", {\n body: input,\n });\n }\n\n /** Same partial-success contract as `bulkCreate`. */\n bulkChangeRole(\n input: RequestBody<\"ApiAssignmentsController_bulkChangeRole\">,\n ): Promise<ResponseBody<\"ApiAssignmentsController_bulkChangeRole\">> {\n return this.client.request(\"POST\", \"/api/v1/assignments/bulk-change-role\", {\n body: input,\n });\n }\n}\n\nexport type AssignmentItem = ItemOf<\n ResponseBody<\"ApiAssignmentsController_listAppWideAssignments\">\n>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n","import type { CanopyClient } from \"../client.js\";\nimport { paginate, type Paginator } from \"../pagination.js\";\nimport type { QueryParams, RequestBody, ResponseBody } from \"../schema.js\";\n\n/** The end users of your application. */\nexport class Identities {\n constructor(private readonly client: CanopyClient) {}\n\n list(\n query: QueryParams<\"ApiIdentitiesController_listIdentities\"> = {},\n ): Paginator<IdentityItem> {\n return paginate<IdentityItem>(\n (params) =>\n this.client.request(\"GET\", \"/api/v1/identities\", { query: params }),\n { ...query },\n );\n }\n\n get(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_getIdentity\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}`,\n );\n }\n\n create(\n input: RequestBody<\"ApiIdentitiesController_createIdentity\">,\n ): Promise<ResponseBody<\"ApiIdentitiesController_createIdentity\">> {\n return this.client.request(\"POST\", \"/api/v1/identities\", { body: input });\n }\n\n update(\n id: string,\n input: RequestBody<\"ApiIdentitiesController_updateIdentity\">,\n ): Promise<ResponseBody<\"ApiIdentitiesController_updateIdentity\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/identities/${encodeURIComponent(id)}`,\n { body: input },\n );\n }\n\n delete(id: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/identities/${encodeURIComponent(id)}`,\n );\n }\n\n /**\n * Deactivation is the reversible counterpart to `delete` — sessions are\n * revoked and sign-in refused, but the identity and its assignments survive.\n * Prefer it for offboarding you may need to undo.\n */\n deactivate(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_deactivateIdentity\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/identities/${encodeURIComponent(id)}/deactivate`,\n );\n }\n\n activate(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_activateIdentity\">> {\n return this.client.request(\n \"POST\",\n `/api/v1/identities/${encodeURIComponent(id)}/activate`,\n );\n }\n\n /** Every role this identity holds, and where. */\n assignments(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_getIdentityAssignments\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}/assignments`,\n );\n }\n\n /**\n * The permissions this identity effectively holds, inheritance resolved.\n *\n * For enforcing a single check, use `permissions.evaluate` — it answers one\n * question at the node that matters. This is for showing a person what\n * someone can do.\n */\n permissions(\n id: string,\n ): Promise<ResponseBody<\"ApiIdentitiesController_getIdentityPermissions\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/identities/${encodeURIComponent(id)}/permissions`,\n );\n }\n}\n\nexport type IdentityItem = ItemOf<\n ResponseBody<\"ApiIdentitiesController_listIdentities\">\n>;\n\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/**\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 evaluate(\n input: RequestBody<\"ApiPermissionsController_evaluate\">,\n ): Promise<ResponseBody<\"ApiPermissionsController_evaluate\">> {\n return this.client.request(\"POST\", \"/api/v1/permissions/evaluate\", {\n body: input,\n });\n }\n\n /**\n * Evaluate many decisions in one round trip.\n *\n * Prefer this to a loop over `evaluate` when rendering a screen: the checks\n * are answered together instead of paying request latency for each.\n */\n evaluateBulk(\n input: RequestBody<\"ApiPermissionsController_evaluateBulk\">,\n ): Promise<ResponseBody<\"ApiPermissionsController_evaluateBulk\">> {\n return this.client.request(\"POST\", \"/api/v1/permissions/evaluate/bulk\", {\n body: input,\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 ): Promise<ResponseBody<\"ApiPermissionsController_explain\">> {\n return this.client.request(\"POST\", \"/api/v1/permissions/evaluate/explain\", {\n body: input,\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 update(\n id: string,\n input: RequestBody<\"ApiPermissionsController_updatePermission\">,\n ): Promise<ResponseBody<\"ApiPermissionsController_updatePermission\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/permissions/${encodeURIComponent(id)}`,\n { body: input },\n );\n }\n\n delete(id: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/permissions/${encodeURIComponent(id)}`,\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 type { QueryParams, RequestBody, ResponseBody } 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 update(\n id: string,\n input: RequestBody<\"ApiRolesController_updateRole\">,\n ): Promise<ResponseBody<\"ApiRolesController_updateRole\">> {\n return this.client.request(\n \"PATCH\",\n `/api/v1/roles/${encodeURIComponent(id)}`,\n { body: input },\n );\n }\n\n delete(id: string): Promise<void> {\n return this.client.request(\n \"DELETE\",\n `/api/v1/roles/${encodeURIComponent(id)}`,\n );\n }\n\n permissions(\n id: string,\n ): Promise<ResponseBody<\"ApiRolesController_getRolePermissions\">> {\n return this.client.request(\n \"GET\",\n `/api/v1/roles/${encodeURIComponent(id)}/permissions`,\n );\n }\n\n /**\n * Replaces the role's permissions wholesale — this is a PUT, so anything\n * absent from `input` is removed. Read `permissions` first if you mean to add.\n */\n setPermissions(\n id: string,\n input: RequestBody<\"ApiRolesController_setRolePermissions\">,\n ): Promise<ResponseBody<\"ApiRolesController_setRolePermissions\">> {\n return this.client.request(\n \"PUT\",\n `/api/v1/roles/${encodeURIComponent(id)}/permissions`,\n { body: input },\n );\n }\n}\n\nexport type RoleItem = ItemOf<ResponseBody<\"ApiRolesController_listRoles\">>;\n\ntype ItemOf<T> = T extends { items: (infer Item)[] } ? Item : never;\n","import { CanopyClient, type CanopyClientOptions } from \"./client.js\";\nimport { Assignments } from \"./resources/assignments.js\";\nimport { Identities } from \"./resources/identities.js\";\nimport { Permissions } from \"./resources/permissions.js\";\nimport { Roles } from \"./resources/roles.js\";\n\n/**\n * The entry point most callers want.\n *\n * ```ts\n * const canopy = new Canopy({ apiKey: process.env.CANOPY_API_KEY });\n *\n * const { allowed } = await canopy.permissions.evaluate({\n * identity_id: identityId,\n * permission: \"documents.read\",\n * scope: \"node\",\n * node_id: nodeId,\n * });\n * ```\n *\n * `client` is public because the wrapped resources cover the paths integrators\n * hit most, not all 81 operations. Anything not wrapped is still reachable —\n * `canopy.client.request(\"GET\", \"/api/v1/audit-events\")` — with the same\n * envelope handling, typed errors and retry policy, so no endpoint is a dead\n * end while the ergonomic surface catches up.\n */\nexport class Canopy {\n readonly client: CanopyClient;\n readonly permissions: Permissions;\n readonly identities: Identities;\n readonly roles: Roles;\n readonly assignments: Assignments;\n\n constructor(options: CanopyClientOptions) {\n this.client = new CanopyClient(options);\n this.permissions = new Permissions(this.client);\n this.identities = new Identities(this.client);\n this.roles = new Roles(this.client);\n this.assignments = new Assignments(this.client);\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@canopy-io/node",
3
+ "version": "0.1.0",
4
+ "description": "Official TypeScript SDK for Canopy — hierarchical identity and access management.",
5
+ "license": "MIT",
6
+ "author": "Canopy Identity Inc.",
7
+ "homepage": "https://github.com/canopy-identity/canopy-node#readme",
8
+ "bugs": "https://github.com/canopy-identity/canopy-node/issues",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/canopy-identity/canopy-node.git"
12
+ },
13
+ "keywords": [
14
+ "canopy",
15
+ "authorization",
16
+ "rbac",
17
+ "iam",
18
+ "permissions",
19
+ "identity",
20
+ "sdk"
21
+ ],
22
+ "type": "module",
23
+ "sideEffects": false,
24
+ "main": "./dist/index.cjs",
25
+ "module": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js",
31
+ "require": "./dist/index.cjs"
32
+ },
33
+ "./package.json": "./package.json"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "engines": {
41
+ "node": ">=18"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "scripts": {
47
+ "build": "tsup",
48
+ "typecheck": "tsc --noEmit",
49
+ "test": "vitest run",
50
+ "test:watch": "vitest",
51
+ "lint": "eslint .",
52
+ "lint:fix": "eslint . --fix",
53
+ "format": "prettier --write .",
54
+ "format:check": "prettier --check .",
55
+ "generate": "tsx scripts/generate-types.ts",
56
+ "generate:check": "tsx scripts/generate-types.ts --check",
57
+ "verify": "npm run lint && npm run typecheck && npm run generate:check && npm run test && npm run build",
58
+ "changeset": "changeset",
59
+ "release": "npm run build && changeset publish"
60
+ },
61
+ "volta": {
62
+ "node": "20.19.0",
63
+ "npm": "10.8.2"
64
+ },
65
+ "devDependencies": {
66
+ "@changesets/cli": "^2.31.1",
67
+ "@eslint/js": "^9.39.2",
68
+ "@types/node": "^22.20.1",
69
+ "eslint": "^9.39.2",
70
+ "openapi-typescript": "^7.13.0",
71
+ "prettier": "^3.6.2",
72
+ "tsup": "^8.5.1",
73
+ "tsx": "^4.23.1",
74
+ "typescript": "^5.9.3",
75
+ "typescript-eslint": "^8.54.0",
76
+ "vitest": "^4.0.18"
77
+ }
78
+ }