@kleora-io/node 0.0.0 → 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.
- package/README.md +322 -5
- package/dist/index.cjs +1057 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +18954 -0
- package/dist/index.d.ts +18954 -0
- package/dist/index.js +1021 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/environment.ts","../src/version.ts","../src/jwks.ts","../src/verify.ts","../src/problem.ts","../src/middleware.ts","../src/management.ts","../src/account.ts","../src/portal.ts"],"names":["problem","DEFAULT_TIMEOUT_MS"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The error hierarchy every Kleora SDK shares.\n *\n * The same shapes `@kleora-io/browser` exports, because an application\n * that uses both packages should be able to branch on one taxonomy: a\n * `KleoraError` base carrying a machine-readable `code`, `TokenError` with\n * six shared token codes, `EnvironmentMismatch` for a sandbox\n * credential pointed at production, and `ApiError` for an RFC 9457 problem\n * document. Messages are English and written for developers.\n *\n * They are declared here rather than imported from the browser package on\n * purpose: `instanceof` is the way an application tells these apart, and two\n * copies of one class in a dependency graph make `instanceof` lie. The two\n * packages are installed independently and neither depends on the other, so a\n * shared class would be exactly that hazard.\n */\n\n/** Base class for everything this package throws. */\nexport class KleoraError extends Error {\n readonly code: string\n\n constructor(code: string, message: string, options?: ErrorOptions) {\n super(message, options)\n this.name = 'KleoraError'\n this.code = code\n }\n}\n\n/**\n * Codes for a token that cannot be trusted.\n *\n * Unlike the browser SDK, this package does verify signatures, so every one\n * of the six shared codes can be raised here. Two more are added, and neither\n * is an invention of convenience:\n *\n * - `invalid_type` — the JWS header's `typ` is not `at+jwt`. RFC 9068 §4\n * requires a resource server to check it, and the platform writes it into\n * every header it mints. Without a code\n * of its own an ID token presented as an access token would report as\n * `malformed`, which reads as \"not a JWT\" and is not what happened.\n * - `issuer_unavailable` — the JWKS endpoint could not be read at all\n * (refused, timed out, non-2xx, unparseable). Folding this into\n * `unknown_kid` would force a middleware to answer 401 for an\n * outage: every caller is then told its token is bad and re-authenticates\n * against the issuer that is already down. A distinct code is what lets\n * the middleware answer 503 instead.\n */\nexport type TokenErrorCode =\n | 'expired'\n | 'invalid_signature'\n | 'invalid_type'\n | 'issuer_mismatch'\n | 'audience_mismatch'\n | 'unknown_kid'\n | 'issuer_unavailable'\n | 'malformed'\n\n/** A token failed verification. */\nexport class TokenError extends KleoraError {\n declare readonly code: TokenErrorCode\n\n constructor(code: TokenErrorCode, message: string, options?: ErrorOptions) {\n super(code, message, options)\n this.name = 'TokenError'\n }\n}\n\n/**\n * No credential was presented at all.\n *\n * The middlewares answer this with a 401 the same way they answer a\n * `TokenError`, but the two are distinct facts and an application that logs\n * them wants to tell \"no `Authorization` header\" from \"a token that did not\n * verify\".\n */\nexport class LoginRequired extends KleoraError {\n constructor(message: string) {\n super('login_required', message)\n this.name = 'LoginRequired'\n }\n}\n\n/**\n * A sandbox credential was mixed with production configuration or the\n * reverse. Thrown before any request\n * carrying the credential is sent.\n */\nexport class EnvironmentMismatch extends KleoraError {\n constructor(message: string) {\n super('environment_mismatch', message)\n this.name = 'EnvironmentMismatch'\n }\n}\n\n/**\n * What `ApiError`'s four fields have no room for, carried alongside them.\n *\n * The same shape `@kleora-io/nuxt` attaches under `problem`, so code that handles one handles the\n * other: the document as it arrived — extension members such as `request_id`\n * and `title` included — plus the two headers a caller cannot recover once\n * the response is gone.\n */\nexport interface ProblemDetails {\n /** The RFC 9457 document as it arrived, extension members included. */\n document: Record<string, unknown>\n /** `Retry-After` in seconds, falling back to the document's `retry_after`. */\n retryAfter: number | null\n /** `Idempotency-Replayed`: `true`, `unavailable`, or absent. */\n idempotencyReplayed: string | null\n}\n\n/**\n * An RFC 9457 problem document from the management API.\n *\n * `type` is the slug a caller branches on — the management API's documented set is\n * the whole set, so a client can name an error before its\n * endpoint exists.\n */\nexport class ApiError extends KleoraError {\n readonly type: string\n readonly status: number\n readonly detail: string | undefined\n readonly errors: unknown[] | undefined\n readonly problem: ProblemDetails\n /**\n * The correlation id of the response that failed.\n *\n * The one field a support conversation needs: it is what ties the error a\n * customer pasted to the request in our logs. Read from the document's\n * `request_id` first and from the `X-Request-Id` response header otherwise,\n * because the header is all there is when the body is not a problem document\n * — an intermediary's HTML 502 — or when the deployment answering predates\n * the member. `undefined` only when neither carried one.\n */\n readonly requestId: string | undefined\n\n constructor(\n type: string,\n status: number,\n detail: string | undefined,\n errors: unknown[] | undefined,\n problem: ProblemDetails,\n requestId?: string,\n ) {\n super('api_error', detail ?? type)\n this.name = 'ApiError'\n this.type = type\n this.status = status\n this.detail = detail\n this.errors = errors\n this.problem = problem\n this.requestId = requestId\n }\n}\n","/**\n * Environment classification, shared by the verifier and the management\n * client.\n *\n * An environment is classified from its host alone: the host's **first** DNS\n * label ends in `-sandbox`, or it is production. That is the same rule\n * `@kleora-io/browser` and `kleora` (Python) apply, and it has to\n * be, because the two ends of one deployment must agree about which\n * environment a host names.\n */\n\nimport { EnvironmentMismatch, KleoraError } from './errors.js'\n\nexport type EnvironmentKind = 'sandbox' | 'production'\n\n/** A sandbox issuer's first label is its App's slug plus this. */\nconst SANDBOX_SUFFIX = '-sandbox'\n\n/**\n * A `:port` on the end of a host. `URL.host` carries one and `URL.hostname`\n * does not, and both reach `classify`; stripping it here — as\n * the Python SDK does — is what makes `acme-sandbox.example.com`\n * and `acme-sandbox.example.com:8443` the same question.\n */\nconst PORT_SUFFIX = /:\\d+$/\n\n/**\n * `sandbox` when the host's first DNS label ends in `-sandbox`, `production`\n * otherwise. Case-insensitive, and any `:port` is ignored.\n *\n * **The one rule, for every SDK.** `@kleora-io/browser` and\n * `kleora` (Python) implement this same\n * test, and all three carry the same table of boundary cases in their tests.\n *\n * It is the inverse of how the platform mints an issuer: it builds\n * `{slug}.{base}` for production and `{slug}-sandbox.{base}` for sandbox, an\n * App slug is a *single* DNS label, and no slug may end in `-sandbox` — so the first label ends in `-sandbox` if and\n * only if the environment is, for any base domain, scheme or port.\n *\n * Until 2026-11 the rule was \"the second label is `sandbox`\",\n * because sandbox issuers were `{slug}.sandbox.{base}`; that shape is minted\n * nowhere any more. Before that it was a substring test for\n * `.sandbox.`, which a base domain carrying the label —\n * `corp.sandbox.internal`, say, whose *production* issuer is\n * `acme.corp.sandbox.internal` — reads as sandbox. Anchoring the test to the\n * one label the platform controls is what keeps the guard from relaxing: a\n * base domain never reaches the first label, so `acme.corp-sandbox.internal`\n * is production here.\n */\nexport function classify(host: string): EnvironmentKind {\n const first = host.toLowerCase().replace(PORT_SUFFIX, '').split('.')[0] ?? ''\n return first.length > SANDBOX_SUFFIX.length && first.endsWith(SANDBOX_SUFFIX)\n ? 'sandbox'\n : 'production'\n}\n\n/** Parse and refuse anything that is not an absolute `http`/`https` URL. */\nexport function parseAbsolute(name: string, value: string): URL {\n const complaint = `${name} must be an absolute http(s) URL, got '${value}'`\n let url: URL\n try {\n url = new URL(value)\n } catch {\n throw new KleoraError('invalid_configuration', complaint)\n }\n if (url.protocol !== 'https:' && url.protocol !== 'http:') {\n throw new KleoraError('invalid_configuration', complaint)\n }\n return url\n}\n\n/** The prefix an API key of this kind carries. */\nexport const KEY_PREFIXES: Record<EnvironmentKind, string> = {\n production: 'kl_live_',\n sandbox: 'kl_test_',\n}\n\n/**\n * The environment an API key belongs to, from its prefix alone.\n *\n * `null` for anything that is neither prefix: the caller reports that as a\n * configuration error rather than guessing, because a key whose environment\n * cannot be read is a key the guard cannot check.\n */\nexport function classifyKey(apiKey: string): EnvironmentKind | null {\n if (apiKey.startsWith(KEY_PREFIXES.production)) return 'production'\n if (apiKey.startsWith(KEY_PREFIXES.sandbox)) return 'sandbox'\n return null\n}\n\n/**\n * The part of an API key that may be written down.\n *\n * The literal prefix plus the first 8 random\n * characters, which is exactly what the API stores as `prefix` and shows in\n * lists — so a redacted value here matches a log line there.\n */\nexport function redactKey(apiKey: string): string {\n const kind = classifyKey(apiKey)\n if (kind === null) return '[redacted]'\n return apiKey.slice(0, KEY_PREFIXES[kind].length + 8)\n}\n\n/**\n * Refuse a key whose prefix names the other environment.\n *\n * A key whose prefix says nothing is refused too, rather than waved through:\n * a guard that no-ops on \"I cannot tell\" fails open, and this one exists\n * precisely to stop a credential reaching the wrong environment. Unreachable\n * from `ManagementClient`, whose constructor rejects such a key first, but\n * this function is exported and must not be the weak link if it is called\n * from anywhere else.\n */\nexport function assertKeyMatches(\n apiKey: string,\n kind: EnvironmentKind,\n what: string,\n): void {\n const keyKind = classifyKey(apiKey)\n if (keyKind === null) {\n throw new KleoraError(\n 'invalid_configuration',\n `the API key does not start with '${KEY_PREFIXES.production}' or ` +\n `'${KEY_PREFIXES.sandbox}', so the environment it belongs to cannot be checked`,\n )\n }\n if (keyKind !== kind) {\n throw new EnvironmentMismatch(\n `the API key ${redactKey(apiKey)} is a ${keyKind} key but ${what} is ` +\n `${kind}; sandbox and production must not be mixed`,\n )\n }\n}\n","/**\n * The version this package reports in `User-Agent`.\n *\n * A literal rather than an import of `package.json`: the package ships an ESM\n * and a CJS build, and a JSON import is spelled differently in each. A unit\n * test asserts it equals the manifest, so the two cannot drift.\n */\nexport const VERSION = '0.1.0'\n\n/** `kleora-{package}/{version}`, the value every request sends. */\nexport const USER_AGENT = `kleora-node/${VERSION}`\n","/**\n * The JWKS cache.\n *\n * Three rules, and they exist for three different reasons:\n *\n * - **TTL from the document.** The issuer publishes `Cache-Control:\n * max-age=300` on `/.well-known/jwks.json`, and honouring\n * the header rather than a constant means a deployment that shortens the\n * window does not need every SDK republished to be obeyed.\n * - **A 60 s refetch floor.** An unknown `kid` is the only thing that forces\n * a fetch outside the TTL, and it arrives from whoever sends the token. A\n * floor is what stops a stream of forged `kid`s from turning one verifier\n * into a load generator against its own issuer.\n * - **Stale serving to 2 × TTL.** A JWKS endpoint that is briefly down must\n * not take every API of every customer down with it. Past 2 × TTL the keys\n * are old enough that a rotation could have completed unseen, so the cache\n * fails closed instead.\n * - **A 5 s timeout on every fetch.** Matching the Python SDK's\n * `DEFAULT_TIMEOUT`. Without one the only bound is undici's 300 s header\n * timeout, and because a refresh is coalesced every verification arriving\n * during that window awaits the *same* hung promise — one blackholed issuer\n * would hold every request slot in a customer's API for five minutes.\n * - **A `User-Agent` on the request.** `kleora-node/{version}`, the\n * same value the management client sends and the same shape every other SDK\n * sends. It is the only thing that lets an\n * operator reading an issuer's access log tell an SDK's key fetch from a\n * scraper, which is the first question asked about traffic nobody can\n * account for. A rule one SDK ignores is not a rule.\n * - **Every failure becomes a `TokenError`.** A refused connection, a\n * timeout, a non-2xx and a body that is not a JWK Set all leave here as\n * `issuer_unavailable`, never as a raw `TypeError` or `SyntaxError`. A\n * caller that catches the taxonomy has to be able to catch an outage, and a\n * middleware has to be able to tell an outage from a bad token.\n */\n\nimport { importJWK, type JWK } from 'jose'\n\nimport { TokenError } from './errors.js'\nimport type { VerificationKey } from './types.js'\nimport { USER_AGENT } from './version.js'\n\n/** The document's default lifetime when it names none, in seconds. */\nexport const DEFAULT_TTL_SECONDS = 300\n\n/** The shortest interval between two fetches of one issuer's keys, in seconds. */\nexport const MIN_REFETCH_SECONDS = 60\n\n/** How many multiples of the TTL a stale set may still answer for. */\nexport const STALE_MULTIPLIER = 2\n\n/** How long one JWKS request may take, in milliseconds (Python: 5.0 s). */\nexport const DEFAULT_TIMEOUT_MS = 5_000\n\n/**\n * A clock that no wall-clock correction can move backwards.\n *\n * Every number this cache compares is an *interval* — the age of the set, the\n * distance to the last attempt — and `Date.now` is the wrong source for those:\n * an NTP step backwards makes `now() - lastAttempt` negative, so the refetch\n * floor stays shut for the length of the step and a genuinely rotated `kid`\n * cannot be fetched; a step forward expires the set early. The Python SDK uses\n * `time.monotonic` for exactly this reason.\n */\nconst monotonic = (): number => performance.now()\n\nexport interface JwksCacheOptions {\n /** `fetch`, for tests and for a caller with its own agent. */\n fetch?: typeof globalThis.fetch\n /**\n * The clock, in milliseconds, monotonic by default. Injectable so that the\n * tests can walk past the 60 s floor and the 2 × TTL stale window without\n * sleeping through them; nothing else has a reason to pass it.\n */\n now?: () => number\n /** Overrides the TTL the document asks for. Seconds. */\n ttl?: number\n /** Overrides the refetch floor. Seconds. */\n minRefetchInterval?: number\n /** How long one request may take, in milliseconds. Default 5000. */\n timeout?: number\n}\n\ninterface KeySet {\n keys: Map<string, JWK>\n /** When the set arrived. */\n at: number\n /** The lifetime the document asked for, in milliseconds. */\n ttl: number\n}\n\n/** One issuer's published keys, cached under the rules above. */\nexport class JwksCache {\n readonly url: string\n\n private readonly doFetch: typeof globalThis.fetch\n private readonly now: () => number\n private readonly ttlOverride: number | undefined\n private readonly floor: number\n private readonly timeout: number\n\n private set: KeySet | null = null\n /** When a fetch was last *attempted*, successful or not. */\n private lastAttempt: number | null = null\n /** When a fetch last failed, or `null` if the last one succeeded. */\n private lastFailure: number | null = null\n /** Why it last failed, so `get` can report the outage rather than guess. */\n private lastError: TokenError | null = null\n /** In-flight fetch, so concurrent verifications share one request. */\n private inFlight: Promise<void> | null = null\n private imported = new Map<string, VerificationKey>()\n\n /** Fetches performed, for the tests that count them. */\n fetches = 0\n\n constructor(issuer: string, options: JwksCacheOptions = {}) {\n this.url = new URL('/.well-known/jwks.json', issuer).href\n this.doFetch = options.fetch ?? globalThis.fetch\n this.now = options.now ?? monotonic\n this.ttlOverride = options.ttl === undefined ? undefined : options.ttl * 1000\n this.floor = (options.minRefetchInterval ?? MIN_REFETCH_SECONDS) * 1000\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS\n }\n\n /**\n * The key `kid` names, refetching within the rules above.\n *\n * Throws `TokenError('unknown_kid')` when the issuer does not publish it —\n * which is also the answer when the endpoint is unreachable and the cached\n * set is past 2 × TTL, because at that point the SDK cannot tell an\n * unpublished key from an unfetchable one and must fail closed.\n */\n async get(kid: string): Promise<VerificationKey> {\n if (this.set === null) {\n // Nothing cached: a failure here is the caller's failure. There is no\n // stale set to fall back to and no key to answer with.\n await this.refresh()\n } else if (this.age() >= this.set.ttl && this.mayRetry()) {\n await this.refreshQuietly()\n }\n\n if (this.lookup(kid) === undefined && this.mayRefetch()) {\n await this.refreshQuietly()\n }\n\n const jwk = this.lookup(kid)\n if (jwk === undefined) {\n // Two different facts, and a middleware answers them with two different\n // statuses. \"The document does not list this key\" is a bad token (401);\n // \"there is no document I am allowed to trust\" is the issuer being\n // unreachable (503). The cached set is the discriminator: while it is\n // usable — inside 2 × TTL — its contents are an answer, and past that it\n // is not, so whatever went wrong reaching the endpoint is the answer.\n if (!this.usable()) {\n throw (\n this.lastError ??\n new TokenError('issuer_unavailable', `${this.url} could not be read`)\n )\n }\n throw new TokenError(\n 'unknown_kid',\n `the issuer at ${this.url} publishes no key with kid '${kid}'`,\n )\n }\n\n const cached = this.imported.get(kid)\n if (cached !== undefined) return cached\n const key = await importJWK(jwk, 'ES256')\n this.imported.set(kid, key)\n return key\n }\n\n /** Whether the cached set may still answer at all. */\n private usable(): boolean {\n return this.set !== null && this.age() < this.set.ttl * STALE_MULTIPLIER\n }\n\n private lookup(kid: string): JWK | undefined {\n return this.usable() ? this.set?.keys.get(kid) : undefined\n }\n\n private age(): number {\n return this.set === null ? Number.POSITIVE_INFINITY : this.now() - this.set.at\n }\n\n /**\n * Whether an unknown `kid` may force a fetch.\n *\n * The floor counts from the last *attempt*, not the last success: an issuer\n * that is answering 500 would otherwise be refetched on every token, and\n * the whole point of the floor is that whoever sends the token does not get\n * to decide how often this process calls its issuer.\n */\n private mayRefetch(): boolean {\n return this.lastAttempt === null || this.now() - this.lastAttempt >= this.floor\n }\n\n /**\n * Whether an expired TTL may be refreshed.\n *\n * The document's `max-age` is the issuer's own instruction and is obeyed as\n * given, floor or no floor — a deployment that publishes `max-age=30` means\n * thirty seconds. What is throttled is *retrying a failure*: an endpoint\n * that is down would otherwise be asked once per verification for as long\n * as the stale window lasts.\n */\n private mayRetry(): boolean {\n return this.lastFailure === null || this.now() - this.lastFailure >= this.floor\n }\n\n /** Refresh, tolerating a failure. The callers decide whether to try. */\n private async refreshQuietly(): Promise<void> {\n try {\n await this.refresh()\n } catch {\n // Deliberately swallowed: `usable()` decides whether the stale set may\n // still answer, and `get` raises `unknown_kid` when it may not. The\n // caller of a verification wants the token's verdict, not the JWKS\n // endpoint's HTTP status.\n }\n }\n\n private async refresh(): Promise<void> {\n // One request even when twenty requests arrive at once with the same\n // rotated `kid`; without this the floor would be the only thing between\n // a cold start and a thundering herd.\n this.inFlight ??= this.fetchKeys().finally(() => {\n this.inFlight = null\n })\n await this.inFlight\n }\n\n private async fetchKeys(): Promise<void> {\n this.lastAttempt = this.now()\n this.lastFailure = this.lastAttempt\n this.fetches += 1\n try {\n const response = await this.doFetch(this.url, {\n headers: { Accept: 'application/json', 'User-Agent': USER_AGENT },\n // Bounded here rather than left to the runtime: undici's default is\n // 300 s, and a coalesced refresh makes that every concurrent\n // verification's wait, not just the first one's.\n signal: AbortSignal.timeout(this.timeout),\n })\n if (!response.ok) {\n throw new TokenError(\n 'issuer_unavailable',\n `${this.url} answered ${String(response.status)}`,\n )\n }\n const document: unknown = await response.json()\n const keys = new Map<string, JWK>()\n if (typeof document === 'object' && document !== null) {\n const listed = (document as { keys?: unknown }).keys\n if (Array.isArray(listed)) {\n for (const entry of listed as JWK[]) {\n if (typeof entry.kid === 'string') keys.set(entry.kid, entry)\n }\n }\n }\n if (keys.size === 0) {\n throw new TokenError('issuer_unavailable', `${this.url} published no usable key`)\n }\n this.set = { keys, at: this.now(), ttl: this.ttlOverride ?? maxAge(response) }\n this.lastFailure = null\n this.lastError = null\n // A rotation can retire a `kid` this cache has already imported, and a\n // retired key must stop answering when it leaves the document.\n for (const kid of [...this.imported.keys()]) {\n if (!keys.has(kid)) this.imported.delete(kid)\n }\n } catch (cause) {\n // Everything: a refused connection and a timeout arrive as `TypeError`\n // and `DOMException`, an unparseable body as `SyntaxError`, and none of\n // those is in the taxonomy a caller catches. They leave as one code.\n const error =\n cause instanceof TokenError\n ? cause\n : new TokenError('issuer_unavailable', `${this.url} could not be read: ${reason(cause)}`, {\n cause,\n })\n this.lastError = error\n throw error\n }\n }\n}\n\n/**\n * The document's own lifetime, in milliseconds.\n *\n * `max-age` from `Cache-Control`, ignoring a `no-store`/`no-cache` document\n * by falling back to the default rather than refetching per token — the floor\n * would throttle that anyway, and a JWKS marked uncacheable is a\n * misconfiguration, not an instruction worth obeying at that cost.\n */\nfunction maxAge(response: Response): number {\n const header = response.headers.get('cache-control')\n const match = header === null ? null : /(?:^|[\\s,])max-age\\s*=\\s*(\\d+)/i.exec(header)\n const seconds = match?.[1] === undefined ? Number.NaN : Number(match[1])\n return (Number.isFinite(seconds) && seconds > 0 ? seconds : DEFAULT_TTL_SECONDS) * 1000\n}\n\n/** A short, safe description of whatever `fetch` threw. */\nfunction reason(cause: unknown): string {\n if (cause instanceof Error) {\n // `AbortSignal.timeout` rejects with a `TimeoutError` DOMException, whose\n // message is the unhelpful \"The operation was aborted\"; name it properly.\n return cause.name === 'TimeoutError' ? 'the request timed out' : cause.message\n }\n return 'unknown error'\n}\n\n/**\n * The process-wide cache, one per issuer, keyed by\n * `{issuer}/.well-known/jwks.json`.\n *\n * `verifyAccessToken` reaches for this when the caller passes no cache, which\n * is what makes the common case — a middleware verifying every request —\n * fetch once every five minutes rather than once per request.\n */\nconst caches = new Map<string, JwksCache>()\n\n/**\n * The shared cache for `issuer`, created on first use.\n *\n * **Only the first call's `options` apply.** A later call for the same issuer\n * gets the cache that already exists, configured the way the first caller\n * configured it — merging them would mean one caller's 5 s timeout silently\n * became another's, which is worse than a documented first-writer-wins. A\n * caller that needs its own settings should construct a `JwksCache` directly\n * and pass it as `VerifyOptions.jwks`.\n */\nexport function jwksFor(issuer: string, options: JwksCacheOptions = {}): JwksCache {\n const url = new URL('/.well-known/jwks.json', issuer).href\n let cache = caches.get(url)\n if (cache === undefined) {\n cache = new JwksCache(issuer, options)\n caches.set(url, cache)\n }\n return cache\n}\n\n/** Forget every shared cache. For tests, and for a long-lived process's tests. */\nexport function clearJwksCaches(): void {\n caches.clear()\n}\n","/**\n * Access-token verification.\n *\n * Everything is local: the signature against the issuer's published keys and\n * every claim against the configuration. `/oauth/userinfo` is never called —\n * a verification that made a network round trip per request would put the\n * issuer in the path of every one of a customer's API calls, and the claims\n * are already in the token.\n */\n\nimport { compactVerify, decodeProtectedHeader } from 'jose'\n\nimport { classify, parseAbsolute } from './environment.js'\nimport { EnvironmentMismatch, LoginRequired, KleoraError, TokenError } from './errors.js'\nimport { jwksFor, type JwksCacheOptions } from './jwks.js'\nimport type { AuthenticatableRequest, Claims, JwksResolver, VerifyOptions } from './types.js'\n\n/** The clock skew allowed on `exp` and `iat`, in seconds. */\nexport const CLOCK_TOLERANCE_SECONDS = 60\n\n/** The one algorithm this platform signs with. */\nconst ALGORITHM = 'ES256'\n\n/**\n * The media type RFC 9068 §2.1 gives an access token, in the two spellings\n * §4 says a resource server must accept.\n *\n * The platform writes `typ: at+jwt` into every access-token header it mints,\n * so checking it costs a correct token nothing.\n * It matters because it is the *only* thing that structurally separates an\n * access token from an ID token signed by the same key. Today an ID token is\n * turned away because `parseClaims` demands `client_id`, `env`, `jti` and\n * `scope`, which an ID token happens not to carry; that is an accident, and\n * adding `jti` to the ID token for replay protection would silently end it.\n */\nconst ACCESS_TOKEN_TYPES = new Set(['at+jwt', 'application/at+jwt'])\n\nconst BEARER = /^Bearer +(?<token>[^\\s]+)$/i\n\n/**\n * Verify `token` and return its claims.\n *\n * The order of the checks is deliberate, and it matters for what a caller is\n * told: a token that fails the signature never has its claims reported on,\n * and a token from another issuer is `issuer_mismatch` rather than\n * `audience_mismatch` even though both are wrong.\n */\nexport async function verifyAccessToken(\n token: string,\n options: VerifyOptions,\n): Promise<Claims> {\n const issuer = parseAbsolute('issuer', options.issuer)\n // Compared without a trailing slash, the way `jwksFor` already keys the\n // cache (jwks.ts) and the way the Python SDK compares: \"exactly, no trailing\n // slash\" describes the *stored* issuer, and a configuration\n // that copied one in should not verify under one SDK and fail under the\n // other. The token's own `iss` is still matched exactly.\n const expectedIssuer = trimTrailingSlash(options.issuer)\n const tolerance = clockTolerance(options)\n const keys = options.jwks ?? resolverFor(options)\n\n const header = readHeader(token)\n if (header.alg !== ALGORITHM) {\n throw new TokenError(\n 'malformed',\n `the token is signed with '${String(header.alg)}'; this issuer signs ${ALGORITHM} only`,\n )\n }\n // Before the key is fetched and long before a claim is read: an ID token or\n // a DPoP proof must not get as far as having its claims inspected.\n const typ = typeof header.typ === 'string' ? header.typ.toLowerCase() : null\n if (typ === null || !ACCESS_TOKEN_TYPES.has(typ)) {\n throw new TokenError(\n 'invalid_type',\n `the token header's typ is ${typ === null ? 'absent or not a string' : `'${typ}'`}; ` +\n `an access token is 'at+jwt' (RFC 9068 §2.1)`,\n )\n }\n if (typeof header.kid !== 'string' || header.kid === '') {\n throw new TokenError('malformed', 'the token header names no kid')\n }\n\n // Resolving the key can itself fail with `unknown_kid`, which is the right\n // verdict: a token naming a key the issuer does not publish is a token this\n // issuer did not sign.\n const key = await keys.get(header.kid)\n\n let payload: string\n try {\n const verified = await compactVerify(token, key, { algorithms: [ALGORITHM] })\n payload = new TextDecoder().decode(verified.payload)\n } catch (cause) {\n throw new TokenError('invalid_signature', `the token's signature does not verify`, {\n cause,\n })\n }\n\n const claims = parseClaims(payload)\n\n if (claims.iss !== expectedIssuer) {\n throw new TokenError(\n 'issuer_mismatch',\n `the token's iss is '${claims.iss}', expected '${expectedIssuer}'`,\n )\n }\n if (!claims.aud.includes(options.audience)) {\n throw new TokenError(\n 'audience_mismatch',\n `the token's aud ${JSON.stringify(claims.aud)} does not contain '${options.audience}'`,\n )\n }\n\n const now = Math.floor((options.now?.() ?? Date.now()) / 1000)\n if (now > claims.exp + tolerance) {\n throw new TokenError(\n 'expired',\n `the token expired at ${String(claims.exp)}, now ${String(now)} ` +\n `(clock tolerance ${String(tolerance)}s)`,\n )\n }\n if (claims.iat > now + tolerance) {\n throw new TokenError(\n 'expired',\n `the token was issued at ${String(claims.iat)}, in the future of ${String(now)} ` +\n `(clock tolerance ${String(tolerance)}s)`,\n )\n }\n\n const kind = classify(issuer.host)\n if (claims.env !== kind) {\n throw new EnvironmentMismatch(\n `the token's env claim is '${claims.env}' but the issuer '${options.issuer}' is ${kind}`,\n )\n }\n\n return claims\n}\n\n/**\n * Framework-free authentication: read the bearer token off a request-like\n * object and verify it.\n *\n * The parameter is structural — `{ headers: { authorization } }` — so it\n * accepts an express `Request`, a fastify `FastifyRequest`, a Node\n * `IncomingMessage` and a plain object without this package depending on any\n * of them (no framework at runtime).\n */\nexport async function authenticate(\n request: AuthenticatableRequest,\n options: VerifyOptions,\n): Promise<Claims> {\n return verifyAccessToken(bearerOf(request), options)\n}\n\n/** The token in `Authorization: Bearer …`, or `LoginRequired`. */\nexport function bearerOf(request: AuthenticatableRequest): string {\n const header = request.headers.authorization\n if (typeof header !== 'string' || header.trim() === '') {\n throw new LoginRequired('the request carries no Authorization header')\n }\n const token = BEARER.exec(header.trim())?.groups?.['token']\n if (token === undefined) {\n throw new LoginRequired('the Authorization header is not a Bearer credential')\n }\n return token\n}\n\n/** The shared cache for this issuer, carrying the caller's `fetch` if any. */\nfunction resolverFor(options: VerifyOptions): JwksResolver {\n const cacheOptions: JwksCacheOptions = {}\n if (options.fetch !== undefined) cacheOptions.fetch = options.fetch\n return jwksFor(options.issuer, cacheOptions)\n}\n\n/** Trailing slashes off an issuer, so `https://x/` and `https://x` agree. */\nexport function trimTrailingSlash(value: string): string {\n return value.replace(/\\/+$/, '')\n}\n\n/**\n * The tolerance to apply, refusing a value that would quietly disable a check.\n *\n * A negative number tightens expiry past what the caller can have meant, and\n * `Infinity` accepts a token that expired last year. Both are configuration\n * errors and are reported as such rather than obeyed.\n */\nfunction clockTolerance(options: VerifyOptions): number {\n const value = options.clockTolerance ?? CLOCK_TOLERANCE_SECONDS\n if (!Number.isFinite(value) || value < 0) {\n throw new KleoraError(\n 'invalid_configuration',\n `clockTolerance must be a finite number of seconds >= 0, got ${String(value)}`,\n )\n }\n return value\n}\n\n/**\n * Refuse a configuration that cannot verify anything, as a configuration\n * error rather than as a failed verification.\n *\n * The middlewares call this when they are *built*, so a service started with\n * `KLEORA_ISSUER` unset fails at boot with a message naming the variable —\n * instead of answering 401 to every request and logging nothing, which looks\n * to an operator like a fleet of bad credentials rather than a missing\n * environment variable.\n */\nexport function assertVerifyOptions(options: VerifyOptions): void {\n parseAbsolute('issuer', options.issuer)\n if (typeof options.audience !== 'string' || options.audience === '') {\n throw new KleoraError(\n 'invalid_configuration',\n 'audience must be a non-empty string: the environment\\'s api_audience, ' +\n 'or the client id when it declares none',\n )\n }\n clockTolerance(options)\n}\n\nfunction readHeader(token: string): { alg?: unknown; kid?: unknown; typ?: unknown } {\n try {\n return decodeProtectedHeader(token)\n } catch (cause) {\n throw new TokenError('malformed', 'the token is not a compact JWS', { cause })\n }\n}\n\n/** The payload as `Claims`, refusing anything the platform always mints. */\nfunction parseClaims(payload: string): Claims {\n let document: unknown\n try {\n document = JSON.parse(payload)\n } catch (cause) {\n throw new TokenError('malformed', 'the token payload is not JSON', { cause })\n }\n if (typeof document !== 'object' || document === null || Array.isArray(document)) {\n throw new TokenError('malformed', 'the token payload is not a JSON object')\n }\n const claims = document as Record<string, unknown>\n\n // `aud` is an array on this platform and always has been, but RFC 7519 allows the single\n // string, and a verifier that refused it would fail on a token no other\n // verifier objects to.\n const audience = claims['aud']\n const aud =\n typeof audience === 'string'\n ? [audience]\n : Array.isArray(audience) && audience.every((entry) => typeof entry === 'string')\n ? audience\n : null\n\n const required = {\n iss: string(claims['iss']),\n sub: string(claims['sub']),\n jti: string(claims['jti']),\n client_id: string(claims['client_id']),\n scope: string(claims['scope']),\n exp: integer(claims['exp']),\n iat: integer(claims['iat']),\n }\n const env = claims['env']\n const missing = Object.entries(required)\n .filter(([, value]) => value === null)\n .map(([name]) => name)\n if (aud === null) missing.push('aud')\n if (env !== 'sandbox' && env !== 'production') missing.push('env')\n if (missing.length > 0) {\n throw new TokenError(\n 'malformed',\n `the token is missing or misdeclares: ${missing.sort().join(', ')}`,\n )\n }\n\n return {\n ...claims,\n iss: required.iss as string,\n sub: required.sub as string,\n aud: aud as string[],\n exp: required.exp as number,\n iat: required.iat as number,\n jti: required.jti as string,\n client_id: required.client_id as string,\n scope: required.scope as string,\n env: env as Claims['env'],\n roles: stringList(claims['roles']),\n permissions: stringList(claims['permissions']),\n amr: stringList(claims['amr']),\n }\n}\n\nconst string = (value: unknown): string | null => (typeof value === 'string' ? value : null)\n\nconst integer = (value: unknown): number | null =>\n typeof value === 'number' && Number.isFinite(value) ? value : null\n\n/** `[]` for an absent list: `roles` and `permissions` are never absent in\n * practice, and a caller checking membership should not have to test for it. */\nconst stringList = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : []\n","/**\n * RFC 9457 problem documents, written rather than parsed.\n *\n * The middlewares protect a *customer's* API, not ours, so nothing here is\n * required by the management API's contract. They use its vocabulary anyway:\n * an application that puts Kleora in\n * front of its own endpoints gets one error shape across both surfaces, and\n * `insufficient-permission` means the same thing on either side of the call.\n */\n\n/** The namespace every problem slug of the management API lives under. */\nexport const PROBLEM_BASE = 'https://kleora.io/problems/'\n\nexport interface Problem {\n type: string\n title: string\n status: number\n detail: string\n}\n\nconst TITLES: Record<string, string> = {\n unauthenticated: 'Authentication required',\n 'insufficient-permission': 'Permission denied',\n 'issuer-unavailable': 'Identity provider unavailable',\n}\n\n/** The document for one slug. */\nexport function problem(slug: string, status: number, detail: string): Problem {\n return {\n type: `${PROBLEM_BASE}${slug}`,\n title: TITLES[slug] ?? slug,\n status,\n detail,\n }\n}\n\n/**\n * What a framework's response object has to be able to do for this package\n * to answer through it.\n *\n * Two shapes, because express and fastify spell all three of \"set a status\",\n * \"set a header\" and \"send JSON\" differently, and depending on either\n * package's types here would put a framework in this package's published\n * type surface (no web framework at runtime).\n */\nexport interface ExpressLikeResponse {\n status(code: number): unknown\n setHeader(name: string, value: string): unknown\n json(body: unknown): unknown\n}\n\nexport interface FastifyLikeReply {\n code(status: number): unknown\n header(name: string, value: string): unknown\n type(value: string): unknown\n send(body: unknown): unknown\n}\n\nexport type ProblemResponse = ExpressLikeResponse | FastifyLikeReply\n\nconst isFastify = (response: ProblemResponse): response is FastifyLikeReply =>\n typeof (response as FastifyLikeReply).code === 'function'\n\n/**\n * Answer with `document`, in whichever framework's dialect `response` speaks.\n *\n * `WWW-Authenticate` on a 401 is RFC 6750 §3, as on the management API;\n * a client that cannot tell \"no credential\" from \"wrong credential\" without\n * it will retry the wrong thing.\n */\nexport function sendProblem(\n response: ProblemResponse,\n document: Problem,\n headers: Record<string, string> = {},\n): void {\n const all = {\n 'Content-Type': 'application/problem+json',\n ...(document.status === 401 ? { 'WWW-Authenticate': 'Bearer' } : {}),\n ...headers,\n }\n if (isFastify(response)) {\n response.code(document.status)\n for (const [name, value] of Object.entries(all)) {\n if (name === 'Content-Type') response.type(value)\n else response.header(name, value)\n }\n response.send(document)\n return\n }\n response.status(document.status)\n for (const [name, value] of Object.entries(all)) response.setHeader(name, value)\n response.json(document)\n}\n","/**\n * The express middleware, the fastify plugin and `requirePermission`.\n *\n * None of the three imports a framework. Each parameter is described\n * structurally — what the middleware actually reads and writes — so that\n * installing this package pulls in no web server, its published types name\n * none, and the same `requirePermission` serves as an express middleware and\n * a fastify `preHandler`. The frameworks are optional peer dependencies for\n * exactly this reason.\n *\n * The three answers these give are deliberately three, not one:\n *\n * | Cause | Answer |\n * | --- | --- |\n * | No credential, or one that does not verify | 401 `unauthenticated` |\n * | The issuer's JWKS could not be read at all | 503 `issuer-unavailable` |\n * | This service is misconfigured | 500, through the application's own handler |\n *\n * Collapsing them — which is what answering 401 to all three does — makes an\n * outage and a missing environment variable look to an operator like a fleet\n * of bad credentials, and tells every client to discard its token and\n * re-authenticate against the issuer that is already down.\n */\n\nimport type { Claims, VerifyOptions } from './types.js'\nimport { LoginRequired, TokenError } from './errors.js'\nimport {\n problem,\n sendProblem,\n type ExpressLikeResponse,\n type FastifyLikeReply,\n type Problem,\n type ProblemResponse,\n} from './problem.js'\nimport { assertVerifyOptions, authenticate } from './verify.js'\n\n/** What both middlewares need: the verifier's options, plus somewhere to log. */\nexport interface MiddlewareOptions extends VerifyOptions {\n /**\n * Where a refusal's reason and an internal failure go.\n *\n * The 401 body says only that the request was not authenticated — the same\n * answer for an absent header as for an expired token, because the\n * difference is of no use to a caller that does not already hold a valid\n * token and of every use to one probing. The reason still has to reach\n * somebody, so it comes here. Without a logger, refusals are silent and\n * internal failures still reach `console.error`: a 500 nobody logged is\n * worse than a noisy log.\n */\n logger?: (error: unknown) => void\n}\n\n/** A request after the middleware has run. */\nexport interface KleoraRequest {\n headers: {\n authorization?: string | undefined\n [name: string]: unknown\n }\n /** The verified claims. Present only once the middleware has admitted the request. */\n kleora?: Claims\n}\n\n/**\n * `req.kleora`, for express's own `Request` type.\n *\n * Without this the example in this package's README does not compile: `kleora` is not a member of\n * express's `Request`, so a TypeScript caller had to write the augmentation\n * itself or reach for `as any`, which is the opposite of what a typed SDK is\n * for. The Nuxt package ships its augmentations; this is the same courtesy.\n *\n * **It costs no dependency.** `Express` is a *global namespace* that\n * `@types/express-serve-static-core` merges into `Request`, so declaring into\n * it resolves nothing and imports nothing: with express installed the member\n * appears on `req`, and without it the namespace is an unused global. That is\n * why this is safe to ship from the main entry, where the older reasoning —\n * \"declaring it would put express and fastify into the published types\" —\n * conflated it with the fastify half, which genuinely cannot be shipped here.\n * `declare module 'fastify'` in a module file is a module *augmentation*:\n * TypeScript resolves the name, and a consumer without fastify installed gets\n * `TS2664` out of our own `.d.ts`. Fastify users add three lines, and the\n * README has them.\n *\n * **Optional, and it has to be.** A request that has not been through the\n * middleware genuinely has no claims. A non-optional declaration would let a\n * route that forgot `app.use(kleora(...))` compile and then read a property\n * of `undefined` at runtime — the same mistake `requirePermission` answers 401\n * rather than 403 to avoid.\n */\ndeclare global {\n // `@types/express` merges `Express.Request`; a module declaration cannot\n // express that, so the namespace is the only spelling there is.\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n /**\n * The verified claims, once the middleware has admitted this request.\n *\n * `undefined` on a route the middleware never ran on — which is a\n * configuration mistake rather than an anonymous caller, since an\n * unverifiable token is answered 401 and never reaches a handler.\n */\n kleora?: Claims\n }\n }\n}\n\n/**\n * `next`/`done`, in the one shape both frameworks' own types satisfy.\n *\n * `Error` rather than `unknown`: fastify types its `done` as `(err?: Error)`\n * and a parameter position is contravariant, so a wider type here would make\n * `requirePermission` unusable as a `preHandler` — which is half of what\n * it is for.\n */\ntype Next = (error?: Error) => void\n\n/** What `admit` decided. */\ntype Verdict =\n | { kind: 'ok' }\n | { kind: 'answered' }\n /** Not this request's fault: the service cannot verify anything right now. */\n | { kind: 'internal'; error: unknown }\n\n/** The detail every 401 carries, whatever the reason was. */\nconst UNAUTHENTICATED = 'the request could not be authenticated'\n\n/**\n * The problem document for a refusal, or `null` when the failure is ours.\n *\n * A `TokenError` and a `LoginRequired` are both about the credential and are\n * both 401. `issuer_unavailable` is the one `TokenError` that is not about the\n * credential at all — the issuer's key set could not be read, so nothing could\n * be judged — and answering it 401 would be a lie with consequences. Anything\n * else is a bug or a misconfiguration in this service, and is not a status\n * this package gets to choose.\n */\nfunction refusal(error: unknown): Problem | null {\n if (error instanceof TokenError && error.code === 'issuer_unavailable') {\n return problem(\n 'issuer-unavailable',\n 503,\n 'the identity provider could not be reached to verify this token',\n )\n }\n if (error instanceof TokenError || error instanceof LoginRequired) {\n return problem('unauthenticated', 401, UNAUTHENTICATED)\n }\n return null\n}\n\n/** Log through the caller's logger, or to `console.error` when it must not be lost. */\nfunction report(options: MiddlewareOptions, error: unknown, mustLog: boolean): void {\n if (options.logger !== undefined) {\n try {\n options.logger(error)\n } catch {\n // A logger that throws must not become the failure; there is nowhere\n // left to report that to.\n }\n return\n }\n if (mustLog) console.error('[@kleora-io/node]', error)\n}\n\nconst asError = (error: unknown): Error =>\n error instanceof Error ? error : new Error(String(error))\n\n/**\n * Express middleware: verify the bearer token, set `req.kleora`, or answer.\n *\n * ```ts\n * import { express as kleora } from '@kleora-io/node'\n * app.use(kleora({ issuer: process.env.KLEORA_ISSUER!, audience: 'https://api.example.com' }))\n * ```\n *\n * Throws at *this* call — not per request — when the options cannot verify\n * anything.\n */\nexport function express(\n options: MiddlewareOptions,\n): (request: KleoraRequest, response: ExpressLikeResponse, next: Next) => void {\n assertVerifyOptions(options)\n return (request, response, next) => {\n void admit(request, response, options)\n .then(\n (verdict) => {\n if (verdict.kind === 'ok') next()\n else if (verdict.kind === 'internal') next(asError(verdict.error))\n },\n (error: unknown) => {\n // `admit` answers rather than throws, so reaching here means the\n // response object itself failed. Hand it on and let the application\n // decide; the `catch` below is what keeps a second failure from\n // reaching Node's unhandled-rejection handler.\n report(options, error, true)\n next(asError(error))\n },\n )\n .catch((error: unknown) => {\n // `next()` threw — an error handler of the application's own, or a\n // response already sent. Nothing here can answer any more, and an\n // unattached rejection would take the worker down under Node's\n // default `--unhandled-rejections=throw`.\n report(options, error, true)\n })\n }\n}\n\n/**\n * Fastify plugin: an `onRequest` hook doing what the express middleware does,\n * decorating `request.kleora`.\n *\n * `skip-override` is fastify's own marker for \"do not encapsulate me\" — the\n * same thing `fastify-plugin` sets. Without it the hook would apply only to\n * routes registered inside this plugin, which is never what a caller\n * registering an authentication plugin at the root means, and adding a\n * dependency to set one symbol is not worth it.\n */\nexport function fastify(options: MiddlewareOptions): FastifyPluginLike {\n assertVerifyOptions(options)\n const plugin = (instance: FastifyLikeInstance): Promise<void> => {\n instance.decorateRequest('kleora', null)\n instance.addHook('onRequest', async (request, reply) => {\n const verdict = await admit(request, reply, options)\n if (verdict.kind === 'internal') {\n report(options, verdict.error, true)\n // Fastify's own error handler turns this into a 500. Answering it\n // here would mean this package choosing a body for somebody else's\n // bug.\n throw asError(verdict.error)\n }\n // Returning the reply is how a fastify 5 hook says \"I have answered;\n // stop the lifecycle here\". Resolving with `undefined` continues it,\n // which is what an admitted request wants.\n return verdict.kind === 'ok' ? undefined : reply\n })\n return Promise.resolve()\n }\n return Object.assign(plugin, { [Symbol.for('skip-override')]: true })\n}\n\n/** Verify and decorate, or answer. */\nasync function admit(\n request: KleoraRequest,\n response: ProblemResponse,\n options: MiddlewareOptions,\n): Promise<Verdict> {\n let claims: Claims\n try {\n claims = await authenticate(request, options)\n } catch (error) {\n const document = refusal(error)\n if (document === null) return { kind: 'internal', error }\n // The reason, once, where an operator can read it — the body says only\n // that the request was refused.\n report(options, error, false)\n try {\n sendProblem(response, document)\n } catch (failure) {\n // The response could not be written: another middleware answered first\n // and called `next()` anyway, or the connection is gone. There is\n // nothing left to say to the client, and throwing from here would only\n // trade a stale response for a dead worker.\n report(options, failure, true)\n }\n return { kind: 'answered' }\n }\n request.kleora = claims\n return { kind: 'ok' }\n}\n\n/**\n * Refuse a request whose claims do not carry `name`.\n *\n * Works as an express middleware and as a fastify `preHandler`: both call it\n * with `(request, response, next)`, and `sendProblem` writes through\n * whichever of the two response objects it was handed.\n *\n * A request that reaches this without `request.kleora` is 401, not 403 —\n * an unauthenticated caller is not a caller lacking a permission, and a route\n * that forgot the authentication middleware must not read as a permissions\n * problem.\n */\nexport function requirePermission(\n name: string,\n): (request: KleoraRequest, response: ProblemResponse, next?: Next) => void {\n return (request, response, next) => {\n const claims = request.kleora\n if (claims === undefined || claims === null) {\n sendProblem(response, problem('unauthenticated', 401, UNAUTHENTICATED))\n return\n }\n if (!claims.permissions.includes(name)) {\n sendProblem(\n response,\n problem(\n 'insufficient-permission',\n 403,\n claims.permissions_truncated === true\n ? `the token does not carry the permission '${name}'. Its permissions claim was ` +\n `truncated at 200 entries, so this may be a permission the user does hold but ` +\n `the token could not carry; coarser roles are the fix.`\n : `the token does not carry the permission '${name}'`,\n ),\n )\n return\n }\n next?.()\n }\n}\n\n/** The two members of a fastify instance this plugin uses. */\nexport interface FastifyLikeInstance {\n decorateRequest(name: string, value: unknown): unknown\n addHook(\n name: 'onRequest',\n hook: (request: KleoraRequest, reply: FastifyLikeReply) => Promise<unknown>,\n ): unknown\n}\n\n/** The plugin shape `fastify.register` accepts. */\nexport type FastifyPluginLike = (\n instance: FastifyLikeInstance,\n options: Record<string, unknown>,\n) => Promise<void>\n","/**\n * The management client: a thin typed `fetch` wrapper over the generated\n * paths that adds auth, problem parsing and the environment guard.\n *\n * `./generated/management.ts` is the only description of what the surface\n * looks like — every path, every body, every response envelope. Nothing here\n * restates a schema, and nothing here is a hand-written method per endpoint:\n * a method per endpoint is a second copy of the document that goes stale\n * silently, and the CI diff that guards the generated tree cannot see it.\n * What is left is the part a generator cannot know — the credential, the\n * error shape and the environment guard.\n */\n\nimport type { paths } from './generated/management.js'\nimport {\n assertKeyMatches,\n classify,\n classifyKey,\n parseAbsolute,\n redactKey,\n type EnvironmentKind,\n} from './environment.js'\nimport { ApiError, EnvironmentMismatch, KleoraError, type ProblemDetails } from './errors.js'\nimport { USER_AGENT } from './version.js'\n\n/** Where the management API lives. */\nexport const DEFAULT_BASE_URL = 'https://api.kleora.io'\n\n/** The prefix every generated path already carries. */\nconst PREFIX = '/api/v1'\n\n/** How long one management request may take, in ms (Python: 10.0 s). */\nexport const DEFAULT_TIMEOUT_MS = 10_000\n\nexport type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\n/** The paths this document declares an `M` operation for. */\nexport type PathsWith<M extends HttpMethod> = {\n [P in keyof paths]: undefined extends paths[P][M] ? never : P\n}[keyof paths]\n\ntype Op<P extends keyof paths, M extends HttpMethod> = paths[P][M]\n\ntype PathParamsOf<O> = O extends { parameters: { path: infer T } } ? T : never\ntype QueryOf<O> = O extends { parameters: { query?: infer T } } ? NonNullable<T> : never\ntype BodyOf<O> = O extends { requestBody: { content: { 'application/json': infer T } } }\n ? T\n : O extends { requestBody?: { content: { 'application/json': infer T } } }\n ? T | undefined\n : never\n\n/**\n * What a 2xx answers with.\n *\n * `204` is `void`: the delete and revoke endpoints answer with no body at\n * all, and typing them `unknown` would push every caller into a check that\n * can only ever fail.\n */\ntype SuccessOf<O> = O extends { responses: infer R }\n ? R extends { 200: { content: { 'application/json': infer T } } }\n ? T\n : R extends { 201: { content: { 'application/json': infer T } } }\n ? T\n : R extends { 204: unknown }\n ? void\n : unknown\n : unknown\n\n/** Per-request options that are not part of the document. */\nexport interface CallOptions {\n /**\n * Forwarded as `X-Request-Id`. The server generates one\n * when absent, so this is for a caller that already has a correlation id of\n * its own.\n */\n requestId?: string\n /** `Idempotency-Key` for a `POST`. */\n idempotencyKey?: string\n signal?: AbortSignal\n}\n\ntype Args<O> = CallOptions &\n ([PathParamsOf<O>] extends [never] ? unknown : { path: PathParamsOf<O> }) &\n ([QueryOf<O>] extends [never] ? unknown : { query?: QueryOf<O> }) &\n ([BodyOf<O>] extends [never]\n ? unknown\n : undefined extends BodyOf<O>\n ? { body?: BodyOf<O> }\n : { body: BodyOf<O> })\n\n/** `args` is optional exactly when nothing in it is required. */\ntype ArgsTuple<O> = Record<never, never> extends Args<O> ? [args?: Args<O>] : [args: Args<O>]\n\nexport interface ManagementClientOptions {\n /** `kl_live_…` or `kl_test_…`. Never logged. */\n apiKey: string\n /**\n * The API's origin. A value ending in `/api/v1` is accepted and trimmed,\n * because that is how `NUXT_PUBLIC_API_BASE` spells it and a caller reading\n * one environment variable should not have to know that the generated paths\n * carry the prefix themselves.\n */\n baseUrl?: string\n /**\n * The issuer this key is expected to belong to. Optional, and worth\n * setting: it is what turns a copy-pasted production key in a sandbox\n * deployment into an `EnvironmentMismatch` instead of a successful write to\n * the wrong environment.\n */\n issuer?: string\n fetch?: typeof globalThis.fetch\n /**\n * How long one request may take, in milliseconds. Default 10 000, matching\n * the Python SDK. It bounds the guard's `GET /me` too — and that one matters\n * most, because every method awaits the guard, so one hung `/me` would\n * otherwise block every call this client will ever make.\n */\n timeout?: number\n}\n\n/** The environment `GET /me` reports for an API key. */\nexport interface KeyEnvironment {\n id: string\n kind: EnvironmentKind\n issuer: string\n app?: { id: string; slug: string }\n}\n\n/**\n * A typed `fetch` over the management API.\n *\n * ```ts\n * const client = new ManagementClient({ apiKey, issuer: 'https://acme-sandbox.kleora.eu' })\n * const apps = await client.get('/api/v1/apps', { query: { limit: 10 } })\n * ```\n */\nexport class ManagementClient {\n readonly baseUrl: string\n readonly issuer: string | null\n\n readonly #apiKey: string\n readonly #fetch: typeof globalThis.fetch\n readonly #timeout: number\n /** The guard, run at most once; a rejection is remembered and re-thrown. */\n #guard: Promise<void> | null = null\n #environment: KeyEnvironment | null = null\n\n constructor(options: ManagementClientOptions) {\n if (classifyKey(options.apiKey) === null) {\n throw new KleoraError(\n 'invalid_configuration',\n `apiKey must start with 'kl_live_' or 'kl_test_'`,\n )\n }\n this.#apiKey = options.apiKey\n this.#fetch = options.fetch ?? globalThis.fetch\n this.#timeout = options.timeout ?? DEFAULT_TIMEOUT_MS\n // Validated for the same reason `issuer` is: a base without a scheme\n // would otherwise surface as a raw `TypeError` from `new URL` on the\n // first call, and `http://` would ship the API key in clear with no\n // complaint at all. Both are configuration errors and belong here.\n this.baseUrl = normaliseBase(parseAbsolute('baseUrl', options.baseUrl ?? DEFAULT_BASE_URL).href)\n this.issuer = options.issuer === undefined ? null : trimSlash(options.issuer)\n if (options.issuer !== undefined) {\n // Parsed for its side effect too: a malformed issuer must be a\n // configuration error now, not a confusing comparison failure inside the\n // guard.\n const parsed = parseAbsolute('issuer', options.issuer)\n // The environment guard: `EnvironmentMismatch` is\n // raised at construction when `issuer` is configured, because the key\n // prefix can be checked against it with no network call at all — so the\n // object a `kl_test_` key aimed at production would produce never exists,\n // and there is no window in which something holds it and has not called\n // anything yet. `kleora` (Python) draws the line in the\n // same place; without an `issuer` there is nothing local to compare against\n // and the guard still defers to the first call's `GET /me`.\n assertKeyMatches(\n options.apiKey,\n classify(parsed.host),\n `the configured issuer '${this.issuer}'`,\n )\n }\n }\n\n /** The key's environment, once the guard has read it. `null` before that. */\n get environment(): KeyEnvironment | null {\n return this.#environment\n }\n\n get<P extends PathsWith<'get'>>(\n path: P,\n ...args: ArgsTuple<Op<P, 'get'>>\n ): Promise<SuccessOf<Op<P, 'get'>>> {\n return this.#call('GET', path, args[0])\n }\n\n post<P extends PathsWith<'post'>>(\n path: P,\n ...args: ArgsTuple<Op<P, 'post'>>\n ): Promise<SuccessOf<Op<P, 'post'>>> {\n return this.#call('POST', path, args[0])\n }\n\n put<P extends PathsWith<'put'>>(\n path: P,\n ...args: ArgsTuple<Op<P, 'put'>>\n ): Promise<SuccessOf<Op<P, 'put'>>> {\n return this.#call('PUT', path, args[0])\n }\n\n patch<P extends PathsWith<'patch'>>(\n path: P,\n ...args: ArgsTuple<Op<P, 'patch'>>\n ): Promise<SuccessOf<Op<P, 'patch'>>> {\n return this.#call('PATCH', path, args[0])\n }\n\n delete<P extends PathsWith<'delete'>>(\n path: P,\n ...args: ArgsTuple<Op<P, 'delete'>>\n ): Promise<SuccessOf<Op<P, 'delete'>>> {\n return this.#call('DELETE', path, args[0])\n }\n\n /** The prefix, and nothing else. The key itself never leaves this object. */\n toString(): string {\n return `ManagementClient(${redactKey(this.#apiKey)} @ ${this.baseUrl})`\n }\n\n toJSON(): Record<string, unknown> {\n return { apiKey: redactKey(this.#apiKey), baseUrl: this.baseUrl, issuer: this.issuer }\n }\n\n /** `console.log(client)` and `util.inspect` see the same redaction. */\n [Symbol.for('nodejs.util.inspect.custom')](): string {\n return this.toString()\n }\n\n async #call<T>(method: string, path: string, args: RawArgs | undefined): Promise<T> {\n await this.#ensureGuarded(args)\n return this.#send<T>(method, path, args)\n }\n\n /**\n * The environment guard.\n *\n * The remote half. The local half — key prefix against the configured issuer\n * — already ran in the constructor, which is what \"no request with the key is\n * sent\" means for a sandbox key aimed at production. This is\n * one `GET /me`, and it is the authority: the prefix says which *kind* of\n * environment the key belongs to, and only the server says which environment\n * that is.\n */\n #ensureGuarded(args: RawArgs | undefined): Promise<void> {\n this.#guard ??= this.#runGuard(args).catch((error: unknown) => {\n // Only a mismatch is remembered. A mismatch is a fact about the\n // configuration and will not fix itself, so re-deriving it on every call\n // would be a pointless `GET /me` per call. Anything else — a 503, a\n // dropped connection, a timeout — is a moment, and remembering the\n // rejected promise would let one bad second at start-up poison the\n // client for the life of the process. The Python SDK draws the line in\n // the same place.\n if (!(error instanceof EnvironmentMismatch)) this.#guard = null\n throw error\n })\n return this.#guard\n }\n\n async #runGuard(args: RawArgs | undefined): Promise<void> {\n // The caller's correlation id travels with the request made on its\n // behalf: the guard's `GET /me` is part of the call that triggered it, and\n // is the request most likely to be the one an operator is looking for.\n const me = await this.#send<{ environment?: KeyEnvironment | null }>(\n 'GET',\n `${PREFIX}/me`,\n args?.requestId === undefined ? {} : { requestId: args.requestId },\n )\n const environment = me.environment ?? null\n if (environment === null) {\n // Only an `api_key` principal has an environment, and this client only\n // ever holds an API key — so this is a surface that answered something\n // this client cannot check rather than a configuration to accept.\n throw new EnvironmentMismatch(\n `GET ${PREFIX}/me reported no environment for ${redactKey(this.#apiKey)}`,\n )\n }\n\n assertKeyMatches(this.#apiKey, environment.kind, `its environment '${environment.issuer}'`)\n if (this.issuer !== null && trimSlash(environment.issuer) !== this.issuer) {\n throw new EnvironmentMismatch(\n `the key belongs to '${environment.issuer}' but the client was configured ` +\n `with issuer '${this.issuer}'`,\n )\n }\n this.#environment = environment\n }\n\n async #send<T>(method: string, path: string, args: RawArgs | undefined): Promise<T> {\n const url = new URL(this.baseUrl + expand(path, args?.path))\n for (const [name, value] of queryEntries(args?.query)) url.searchParams.append(name, value)\n\n const headers: Record<string, string> = {\n Accept: 'application/json, application/problem+json',\n Authorization: `Bearer ${this.#apiKey}`,\n 'User-Agent': USER_AGENT,\n }\n if (args?.requestId !== undefined) headers['X-Request-Id'] = args.requestId\n if (args?.idempotencyKey !== undefined) headers['Idempotency-Key'] = args.idempotencyKey\n if (args?.body !== undefined) headers['Content-Type'] = 'application/json'\n\n const response = await this.#fetch(url, {\n method,\n headers,\n ...(args?.body === undefined ? {} : { body: JSON.stringify(args.body) }),\n signal: deadline(this.#timeout, args?.signal),\n })\n\n if (!response.ok) throw await toApiError(response)\n if (response.status === 204) return undefined as T\n const text = await response.text()\n return (text === '' ? undefined : JSON.parse(text)) as T\n }\n}\n\ninterface RawArgs extends CallOptions {\n path?: Record<string, string>\n query?: Record<string, unknown>\n body?: unknown\n}\n\n/** `https://api.example/api/v1/` and `https://api.example` mean the same thing. */\nfunction normaliseBase(value: string): string {\n const trimmed = trimSlash(value)\n return trimmed.endsWith(PREFIX) ? trimmed.slice(0, -PREFIX.length) : trimmed\n}\n\nconst trimSlash = (value: string): string => value.replace(/\\/+$/, '')\n\n/**\n * The caller's own cancellation, if any, and the client's timeout.\n *\n * `AbortSignal.any` rather than replacing one with the other: a caller that\n * passed a `signal` still wants its own cancellation to work, and a caller\n * that passed none still gets a bound.\n */\nfunction deadline(timeout: number, signal: AbortSignal | undefined): AbortSignal {\n const own = AbortSignal.timeout(timeout)\n return signal === undefined ? own : AbortSignal.any([signal, own])\n}\n\n/** Substitute `{name}` with the caller's path parameters. */\nfunction expand(path: string, params: Record<string, string> | undefined): string {\n return path.replace(/\\{([^}]+)\\}/g, (_, name: string) => {\n const value = params?.[name]\n if (value === undefined || value === null) {\n throw new KleoraError(\n 'invalid_request',\n `${path} needs the path parameter '${name}'`,\n )\n }\n return encodeURIComponent(String(value))\n })\n}\n\n/**\n * Query parameters, dropping the absent ones.\n *\n * `null` and `undefined` are both dropped rather than serialised: the\n * document types several filters `string | null` for \"no filter\", and\n * `?slug=null` would be a filter for the literal text.\n */\nfunction queryEntries(query: Record<string, unknown> | undefined): [string, string][] {\n const entries: [string, string][] = []\n for (const [name, value] of Object.entries(query ?? {})) {\n if (value === undefined || value === null) continue\n for (const item of Array.isArray(value) ? (value as unknown[]) : [value]) {\n // Only the three primitive kinds the document declares for a query\n // parameter. Anything else has no unambiguous query form, and\n // `String(…)` on an object would silently send `[object Object]`.\n if (typeof item === 'string') entries.push([name, item])\n else if (typeof item === 'number' || typeof item === 'boolean') {\n entries.push([name, String(item)])\n }\n }\n }\n return entries\n}\n\n/** An RFC 9457 response as an `ApiError`. */\nexport async function toApiError(response: Response): Promise<ApiError> {\n let document: Record<string, unknown> = {}\n try {\n const body: unknown = await response.json()\n if (typeof body === 'object' && body !== null && !Array.isArray(body)) {\n document = body as Record<string, unknown>\n }\n } catch {\n // A body that is not JSON — a proxy's HTML error page, an empty 502 —\n // still has to become an `ApiError`, because the status is the fact the\n // caller needs and a parse failure would hide it behind a SyntaxError.\n }\n const errors = document['errors']\n const problem: ProblemDetails = {\n document,\n retryAfter: retryAfterOf(response, document),\n idempotencyReplayed: response.headers.get('idempotency-replayed'),\n }\n return new ApiError(\n typeof document['type'] === 'string' ? document['type'] : 'about:blank',\n response.status,\n typeof document['detail'] === 'string'\n ? document['detail']\n : response.statusText === ''\n ? undefined\n : response.statusText,\n Array.isArray(errors) ? (errors as unknown[]) : undefined,\n problem,\n requestIdOf(response, document),\n )\n}\n\n/**\n * The response's correlation id: the document's member, then the header.\n *\n * Body first because it is the value this surface put there deliberately, and\n * the two agree — one middleware assigns the id and the renderer reads it back\n * The header is the fallback for everything\n * the body cannot answer for: a 502 an intermediary wrote, a deployment older\n * than the member.\n */\nfunction requestIdOf(response: Response, document: Record<string, unknown>): string | undefined {\n const fromDocument = document['request_id']\n if (typeof fromDocument === 'string' && fromDocument !== '') return fromDocument\n return response.headers.get('x-request-id') ?? undefined\n}\n\n/**\n * `Retry-After` as whole seconds, falling back to the document's own field.\n *\n * RFC 9110 §10.2.3 allows both forms and this surface only ever sends\n * delta-seconds, but a proxy in front of it may rewrite a 429 or a 503 with an\n * HTTP-date, and a client that read that as \"no advice\" would retry\n * immediately into the same limit.\n */\nfunction retryAfterOf(response: Response, document: Record<string, unknown>): number | null {\n const raw = response.headers.get('retry-after')\n const trimmed = raw?.trim() ?? ''\n if (trimmed !== '') {\n const seconds = Number(trimmed)\n if (Number.isFinite(seconds) && seconds >= 0) return Math.round(seconds)\n const at = Date.parse(trimmed)\n if (Number.isFinite(at)) return Math.max(0, Math.round((at - Date.now()) / 1000))\n }\n const fromDocument = document['retry_after']\n return typeof fromDocument === 'number' && Number.isFinite(fromDocument) ? fromDocument : null\n}\n","/**\n * The end-user self-service API, typed, for a Node backend.\n *\n * `/account/v1/*` on the issuer host, called with **the signed-in person's own\n * access token** — typically the bearer a request to your own API arrived with,\n * which `verifyAccessToken` has already checked. It is not an API key and\n * there is no administrative form of this client: the operator's surface is\n * `ManagementClient`.\n *\n * Two things have to be true, and neither is this package's to decide:\n *\n * 1. **The Client lists `self_service` in `allowed_scopes`** — the consent\n * (there is no consent screen). A Client that has not opted in cannot be granted the scope.\n * 2. **The token carries `self_service`**, because the application asked for it\n * when signing the person in. Without it every call answers\n * `403 insufficient-scope`.\n *\n * Operations marked **sensitive** answer `401 reauth-required` unless the\n * person has re-authenticated in the last five minutes (`reauthenticate`).\n * Registering a passkey and linking a provider identity cannot be done from a\n * customer's origin at all; send the person to `accountPortalUrl` for those.\n *\n * ```ts\n * import { AccountClient } from '@kleora-io/node'\n * const account = new AccountClient({ issuer, accessToken: bearer })\n * const profile = await account.getProfile()\n * ```\n */\n\nimport { parseAbsolute } from './environment.js'\nimport { KleoraError } from './errors.js'\nimport type { components } from './generated/account.js'\nimport { toApiError } from './management.js'\nimport { USER_AGENT } from './version.js'\n\ntype Schemas = components['schemas']\n\nexport type AccountProfile = Schemas['ProfileOut']\nexport type AccountProfileChanges = Schemas['ProfilePatch']\nexport type AccountEmail = Schemas['EmailOut']\nexport type AccountEmailSent = Schemas['ResendOut']\nexport type AccountPasswordPolicy = Schemas['PasswordPolicyOut']\nexport type AccountReauthentication = Schemas['ReauthOut']\nexport type AccountSession = Schemas['SessionOut']\nexport type AccountSessionPage = Schemas['SessionPage']\nexport type AccountSessionsRevoked = Schemas['RevokedOut']\nexport type AccountMfa = Schemas['MfaOut']\nexport type AccountTotpEnrollment = Schemas['EnrollStartOut']\nexport type AccountRecoveryCodes = Schemas['RecoveryCodesOut']\nexport type AccountPasskeys = Schemas['PasskeysOut']\nexport type AccountIdentities = Schemas['IdentitiesOut']\nexport type AccountSettings = Schemas['UserSettingsDocument']\nexport type AccountSetting = Schemas['UserSettingDocument']\nexport type AccountSettingValue = Schemas['UserSettingValue']\nexport type AccountPortal = Schemas['PortalOut']\nexport type AccountDeletion = Schemas['DeletionOut']\n\n/** A default a request is bounded by, as `ManagementClient`'s is. */\nexport const DEFAULT_ACCOUNT_TIMEOUT_MS = 10_000\n\nexport interface AccountClientOptions {\n /** The Environment's issuer, e.g. `https://acme.kleora.eu`. */\n issuer: string\n /**\n * The person's access token, or a function returning one (called per\n * request). Never logged, and shown by `toString`/`inspect` as nothing.\n */\n accessToken: string | (() => string | Promise<string>)\n /** Per-request deadline in milliseconds. Default 10 s. */\n timeout?: number\n /** A `fetch` of the caller's own — an agent, a proxy, a test double. */\n fetch?: typeof globalThis.fetch\n}\n\nexport interface ListSessionsOptions {\n /** 1–200; the server's default is 50. */\n limit?: number\n /** `next_cursor` from the previous page. */\n cursor?: string\n}\n\nexport interface ChangePasswordOptions {\n /** Required when the person has a password (`has_password`). */\n currentPassword?: string\n newPassword: string\n}\n\ninterface Call {\n query?: Record<string, string | number | undefined>\n body?: unknown\n anonymous?: boolean\n}\n\nconst id = (value: string): string => encodeURIComponent(value)\n\n/** Every `/account/v1/*` operation, named for what it does. */\nexport class AccountClient {\n /** `{issuer}/account/v1`. */\n readonly baseUrl: string\n\n readonly #accessToken: AccountClientOptions['accessToken']\n readonly #fetch: typeof globalThis.fetch\n readonly #timeout: number\n\n constructor(options: AccountClientOptions) {\n const issuer = parseAbsolute('issuer', options.issuer)\n if (options.accessToken === '') {\n throw new KleoraError('invalid_configuration', 'accessToken must not be empty')\n }\n this.baseUrl = `${issuer.href.replace(/\\/+$/, '')}/account/v1`\n this.#accessToken = options.accessToken\n this.#fetch = options.fetch ?? globalThis.fetch\n this.#timeout = options.timeout ?? DEFAULT_ACCOUNT_TIMEOUT_MS\n }\n\n /** `GET /profile`. */\n getProfile(): Promise<AccountProfile> {\n return this.#send('GET', '/profile')\n }\n\n /** `PATCH /profile` — name, locale, picture; `null` clears one. */\n updateProfile(changes: AccountProfileChanges): Promise<AccountProfile> {\n return this.#send('PATCH', '/profile', { body: changes })\n }\n\n /** `GET /email`. */\n getEmail(): Promise<AccountEmail> {\n return this.#send('GET', '/email')\n }\n\n /** `POST /email` — mails a confirmation link to the new address. **Sensitive.** */\n requestEmailChange(email: string): Promise<AccountEmailSent> {\n return this.#send('POST', '/email', { body: { email } })\n }\n\n /** `POST /email/confirm` — the token from that link. */\n confirmEmailChange(token: string): Promise<void> {\n return this.#send('POST', '/email/confirm', { body: { token } })\n }\n\n /** `POST /email/resend`. */\n resendVerificationEmail(): Promise<AccountEmailSent> {\n return this.#send('POST', '/email/resend')\n }\n\n /** `GET /password` — whether there is one, and the Environment's policy. */\n getPasswordPolicy(): Promise<AccountPasswordPolicy> {\n return this.#send('GET', '/password')\n }\n\n /** `POST /password` — change it, or set one for a person who has none. **Sensitive.** */\n changePassword(options: ChangePasswordOptions): Promise<void> {\n return this.#send('POST', '/password', {\n body: {\n new_password: options.newPassword,\n ...(options.currentPassword === undefined ? {} : { current_password: options.currentPassword }),\n },\n })\n }\n\n /** `GET /reauth` — what this person can re-authenticate with. */\n getReauthentication(): Promise<AccountReauthentication> {\n return this.#send('GET', '/reauth')\n }\n\n /** `POST /reauth` — a password; opens the five-minute window. */\n reauthenticate(password: string): Promise<void> {\n return this.#send('POST', '/reauth', { body: { password } })\n }\n\n /** `GET /sessions` — live sessions, newest first, one cursor page. */\n listSessions(options: ListSessionsOptions = {}): Promise<AccountSessionPage> {\n return this.#send('GET', '/sessions', { query: { limit: options.limit, cursor: options.cursor } })\n }\n\n /** `DELETE /sessions/{id}`. */\n revokeSession(sessionId: string): Promise<void> {\n return this.#send('DELETE', `/sessions/${id(sessionId)}`)\n }\n\n /** `POST /sessions/revoke-others` — every live session but this token's. */\n revokeOtherSessions(): Promise<AccountSessionsRevoked> {\n return this.#send('POST', '/sessions/revoke-others')\n }\n\n /** `GET /mfa`. */\n listMfaFactors(): Promise<AccountMfa> {\n return this.#send('GET', '/mfa')\n }\n\n /** `POST /mfa/enroll/start`. **Sensitive.** */\n startTotpEnrollment(): Promise<AccountTotpEnrollment> {\n return this.#send('POST', '/mfa/enroll/start')\n }\n\n /** `POST /mfa/enroll/confirm` — answers the recovery codes, once. **Sensitive.** */\n confirmTotpEnrollment(code: string): Promise<AccountRecoveryCodes> {\n return this.#send('POST', '/mfa/enroll/confirm', { body: { code } })\n }\n\n /** `DELETE /mfa/{id}`. **Sensitive.** */\n removeMfaFactor(factorId: string): Promise<void> {\n return this.#send('DELETE', `/mfa/${id(factorId)}`)\n }\n\n /** `POST /mfa/recovery/regenerate`. **Sensitive.** */\n regenerateRecoveryCodes(): Promise<AccountRecoveryCodes> {\n return this.#send('POST', '/mfa/recovery/regenerate')\n }\n\n /** `GET /passkeys`. */\n listPasskeys(): Promise<AccountPasskeys> {\n return this.#send('GET', '/passkeys')\n }\n\n /** `DELETE /passkeys/{id}`. **Sensitive.** */\n removePasskey(passkeyId: string): Promise<void> {\n return this.#send('DELETE', `/passkeys/${id(passkeyId)}`)\n }\n\n /** `GET /identities`. */\n listIdentities(): Promise<AccountIdentities> {\n return this.#send('GET', '/identities')\n }\n\n /** `DELETE /identities/{id}`. **Sensitive.** */\n unlinkIdentity(identityId: string): Promise<void> {\n return this.#send('DELETE', `/identities/${id(identityId)}`)\n }\n\n /** `GET /settings`. */\n listSettings(): Promise<AccountSettings> {\n return this.#send('GET', '/settings')\n }\n\n /** `PUT /settings/{key}`. */\n setSetting(key: string, value: AccountSettingValue): Promise<AccountSetting> {\n return this.#send('PUT', `/settings/${id(key)}`, { body: { value } })\n }\n\n /** `DELETE /settings/{key}` — back to the definition's default. */\n resetSetting(key: string): Promise<void> {\n return this.#send('DELETE', `/settings/${id(key)}`)\n }\n\n /** `GET /portal` — the hosted portal's entry URL and the sections offered. */\n getPortal(): Promise<AccountPortal> {\n return this.#send('GET', '/portal')\n }\n\n /** `POST /deletion` — deleted permanently after 7 days, cancellable until then. **Sensitive.** */\n requestDeletion(): Promise<AccountDeletion> {\n return this.#send('POST', '/deletion')\n }\n\n /** `DELETE /deletion` — the emailed cancellation token; the one anonymous operation. */\n cancelDeletion(token: string): Promise<void> {\n return this.#send('DELETE', '/deletion', { body: { token }, anonymous: true })\n }\n\n toString(): string {\n return `AccountClient(${this.baseUrl})`\n }\n\n toJSON(): { baseUrl: string } {\n return { baseUrl: this.baseUrl }\n }\n\n [Symbol.for('nodejs.util.inspect.custom')](): string {\n return this.toString()\n }\n\n async #token(): Promise<string> {\n const token =\n typeof this.#accessToken === 'function' ? await this.#accessToken() : this.#accessToken\n if (token === '') throw new KleoraError('invalid_configuration', 'accessToken returned an empty token')\n return token\n }\n\n async #send<T>(method: string, path: string, call: Call = {}): Promise<T> {\n const url = new URL(this.baseUrl + path)\n for (const [name, value] of Object.entries(call.query ?? {})) {\n if (value !== undefined) url.searchParams.set(name, String(value))\n }\n const headers: Record<string, string> = {\n Accept: 'application/json, application/problem+json',\n 'User-Agent': USER_AGENT,\n }\n if (call.anonymous !== true) headers['Authorization'] = `Bearer ${await this.#token()}`\n if (call.body !== undefined) headers['Content-Type'] = 'application/json'\n\n const response = await this.#fetch(url, {\n method,\n headers,\n ...(call.body === undefined ? {} : { body: JSON.stringify(call.body) }),\n signal: AbortSignal.timeout(this.#timeout),\n })\n if (!response.ok) throw await toApiError(response)\n if (response.status === 204) return undefined as T\n const text = await response.text()\n return (text === '' ? undefined : JSON.parse(text)) as T\n }\n}\n","/**\n * The hosted account portal's URL.\n *\n * For a server rendering the link into a page:\n * `accountPortalUrl({ issuer, clientId, section?, returnTo? })`, a pure\n * function. The same rules as `@kleora-io/browser`'s, written again rather\n * than imported, because no SDK depends on another.\n *\n * ```\n * {issuer}/account[/{section}]?client_id={client_id}&return_to={url}\n * ```\n *\n * **The portal is offered only for a Client whose `allowed_scopes` include\n * `self_service`** (that list is the consent,\n * because there is no consent screen). For any other Client this URL still\n * opens, and every portal page says \"Managing your account here is not offered\n * for {app}\" instead of its content. Nothing here can tell the two apart: the\n * URL is a pure function of its inputs, and whether the named Client offers the\n * portal is the issuer's to decide when the page loads.\n *\n * Link it as a new tab or a top-level navigation and **never a frame**: every\n * issuer document refuses to be framed (`frame-ancestors 'none'`).\n */\n\nimport { parseAbsolute } from './environment.js'\nimport { KleoraError } from './errors.js'\n\n/**\n * The portal's sections, in the order the portal lists them. The\n * `PortalSection` enum of `openapi/account-v1.json`; `test/portal.test.ts` holds the two equal.\n *\n * `danger` exists only where the Environment offers self-deletion; linking to\n * it elsewhere lands on the portal's own not-found page, which is the issuer's\n * answer rather than one this package can know in advance.\n */\nexport const ACCOUNT_PORTAL_SECTIONS = [\n 'profile',\n 'password',\n 'security',\n 'sessions',\n 'danger',\n] as const\n\nexport type AccountPortalSection = (typeof ACCOUNT_PORTAL_SECTIONS)[number]\n\nexport interface AccountPortalUrlOptions {\n /** The Environment's issuer, e.g. `https://acme.kleora.eu`. */\n issuer: string\n /**\n * The Client the portal is opened for. Its `allowed_scopes` decide whether\n * the portal is offered, and its `post_logout_redirect_uris` whether\n * `returnTo` becomes a link.\n */\n clientId: string\n /** A section to open at; the portal home when absent. */\n section?: AccountPortalSection\n /**\n * Where the portal's \"back to the application\" link points. Must be an\n * absolute `http`/`https` URL with no fragment and no userinfo, or\n * `KleoraError('invalid_configuration')`. The issuer honours it only when it\n * equals one of the Client's `post_logout_redirect_uris` exactly, and\n * otherwise renders no return link at all — that membership is the issuer's\n * to check, and this package cannot know the list.\n */\n returnTo?: string\n}\n\nconst invalid = (message: string): KleoraError => new KleoraError('invalid_configuration', message)\n\n/**\n * Refuse a `returnTo` of the wrong *shape*.\n *\n * The platform's own three rules for a registered URI: absolute `http`/`https`,\n * no fragment, no userinfo. A value breaking one of them can never equal a\n * registered `post_logout_redirect_uris` entry, so the issuer would silently\n * drop the link; saying so here, at the call, is the difference between a\n * developer's error and a missing link nobody notices.\n */\nfunction assertReturnTo(value: string): void {\n const url = parseAbsolute('returnTo', value)\n if (url.hash !== '' || value.includes('#')) {\n throw invalid(`returnTo must not carry a fragment, got '${value}'`)\n }\n if (url.username !== '' || url.password !== '') {\n throw invalid(`returnTo must not carry userinfo, got '${value}'`)\n }\n}\n\nfunction assertSection(section: string): void {\n if (!(ACCOUNT_PORTAL_SECTIONS as readonly string[]).includes(section)) {\n throw invalid(\n `section must be one of ${ACCOUNT_PORTAL_SECTIONS.join(', ')}; got '${section}'`,\n )\n }\n}\n\n/**\n * The account portal's URL — a pure function, no request.\n *\n * Works only for a Client that lists `self_service` in `allowed_scopes`; for\n * any other the portal renders its \"not offered\" sentence (see the module\n * comment).\n */\nexport function accountPortalUrl(options: AccountPortalUrlOptions): string {\n const issuer = parseAbsolute('issuer', options.issuer)\n if (options.clientId.length === 0) {\n throw invalid('clientId must not be empty')\n }\n if (options.section !== undefined) assertSection(options.section)\n if (options.returnTo !== undefined) assertReturnTo(options.returnTo)\n\n // The issuer's own path is kept (none is minted with one, but a trailing\n // slash is a typo, not a different place) and the portal's appended to it.\n const base = issuer.href.replace(/\\/+$/, '')\n const path = options.section === undefined ? '/account' : `/account/${options.section}`\n const url = new URL(base + path)\n url.searchParams.set('client_id', options.clientId)\n if (options.returnTo !== undefined) url.searchParams.set('return_to', options.returnTo)\n return url.href\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,18 +1,77 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kleora-io/node",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Kleora Node SDK — access-token verification, JWKS cache, express and fastify middlewares, and the typed management client.",
|
|
5
6
|
"license": "Apache-2.0",
|
|
6
7
|
"homepage": "https://kleora.io",
|
|
7
8
|
"repository": {
|
|
8
9
|
"type": "git",
|
|
9
10
|
"url": "git+https://github.com/kleora-io/kleora-node.git"
|
|
10
11
|
},
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
],
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/kleora-io/kleora-node/issues"
|
|
14
|
+
},
|
|
15
15
|
"publishConfig": {
|
|
16
16
|
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=20"
|
|
21
|
+
},
|
|
22
|
+
"packageManager": "pnpm@11.24.0",
|
|
23
|
+
"main": "./dist/index.cjs",
|
|
24
|
+
"module": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
|
+
"require": "./dist/index.cjs"
|
|
31
|
+
},
|
|
32
|
+
"./package.json": "./package.json"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"LICENSE",
|
|
37
|
+
"README.md"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"generate:client": "node scripts/generate-client.mjs",
|
|
41
|
+
"build": "tsup",
|
|
42
|
+
"prepare": "tsup",
|
|
43
|
+
"lint": "eslint .",
|
|
44
|
+
"lint:fix": "eslint . --fix",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"test:watch": "vitest"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"jose": "^6.2.10"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"express": "^5.0.0",
|
|
54
|
+
"fastify": "^5.0.0"
|
|
55
|
+
},
|
|
56
|
+
"peerDependenciesMeta": {
|
|
57
|
+
"express": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"fastify": {
|
|
61
|
+
"optional": true
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@eslint/js": "^10.0.1",
|
|
66
|
+
"@types/express": "^5.0.6",
|
|
67
|
+
"@types/node": "^24.10.0",
|
|
68
|
+
"eslint": "^10.0.0",
|
|
69
|
+
"express": "^5.2.1",
|
|
70
|
+
"fastify": "^5.12.1",
|
|
71
|
+
"openapi-typescript": "^7.13.0",
|
|
72
|
+
"tsup": "^8.5.1",
|
|
73
|
+
"typescript": "^5.9.3",
|
|
74
|
+
"typescript-eslint": "^8.68.0",
|
|
75
|
+
"vitest": "^4.1.11"
|
|
17
76
|
}
|
|
18
77
|
}
|