/** * Create a local key set from one or more key specifications. * * @param {KeySpec[]} specs * @param {LocalKeySetOptions} [options] * @returns {Promise} */ declare function createLocalKeySet(specs: KeySpec[], options?: LocalKeySetOptions): Promise; type KeySpec = { /** * algorithm identifier (e.g. 'ES256', 'EdDSA', 'RS256') */ alg: string; /** * JWK use parameter */ use?: string | undefined; /** * explicit kid — auto-generated if omitted */ kid?: string | undefined; /** * EC/OKP curve (default per kty) */ curve?: string | undefined; /** * RSA modulus length (default 2048) */ modulusLength?: number | undefined; }; type LocalKeySetOptions = { /** * how long a rotated key stays in the set for verification */ gracePeriod?: string | number | undefined; }; type KeyEntry = { kid: string; alg: string; privateJwk: Record; publicJwk: Record; createdAt: number; retiredAt?: number | undefined; }; type RotateOptions = { /** * algorithm of the key to rotate */ alg: string; /** * explicit kid for the new key */ kid?: string | undefined; /** * curve override for EC/OKP */ curve?: string | undefined; /** * RSA modulus override */ modulusLength?: number | undefined; }; type HandlerOptions = { /** * Cache-Control header value */ cacheControl?: string | undefined; }; type LocalKeySet = { toJSON: () => { keys: Record[]; }; getSigningKey: (alg?: string) => KeyEntry | null; kids: string[]; size: number; rotate: (options: RotateOptions) => Promise; addKey: (privateJwk: Record) => void; handler: (options?: HandlerOptions) => (req: unknown, res: unknown) => void; resolve: (header: { kid: string; alg?: string; }) => Promise; }; /** * @typedef {object} RemoteJWKSOptions * @property {boolean} [cache=true] enable response caching * @property {string|number} [cacheTtl='10m'] cache lifetime (ms or duration string) * @property {number} [maxCacheKeys=100] max cached KeyObjects kept in memory (LRU eviction) * @property {number} [cooldownMs=10000] min ms between refetches on kid-miss * @property {number} [timeout=5000] fetch timeout in ms * @property {boolean} [allowInsecure=false] allow http:// URIs (default https only) * @property {boolean} [staleWhileError=false] serve stale cached keys when a refetch fails * @property {AbortSignal} [signal] caller-provided AbortSignal forwarded to fetch * @property {Record} [headers] extra headers sent on the fetch request * @property {(header: { kid: string, alg?: string }, error: Error) => void} [onInvalidKey] called when a key cannot be resolved (kid not found or alg mismatch) * @property {number} [maxResponseSize=1048576] max bytes accepted from the JWKS endpoint (default 1 MB) * @property {(hostname: string, url: URL) => boolean} [allowHost] gate on the destination host; return false to refuse the URI */ /** * Create a remote JWKS resolver that fetches and caches keys from `uri`. * * The returned function has the `async (header) => KeyObject` signature * expected by `@exortek/jws` and `@exortek/jwt` verify surfaces. * * @param {string} uri The JWKS endpoint URL. * @param {RemoteJWKSOptions} [options] * @returns {((header: { kid: string, alg?: string }) => Promise) & { reload: () => Promise, cachedKids: () => string[] }} */ declare function createRemoteJWKS(uri: string, options?: RemoteJWKSOptions): ((header: { kid: string; alg?: string; }) => Promise) & { reload: () => Promise; cachedKids: () => string[]; }; type RemoteJWKSOptions = { /** * enable response caching */ cache?: boolean | undefined; /** * cache lifetime (ms or duration string) */ cacheTtl?: string | number | undefined; /** * max cached KeyObjects kept in memory (LRU eviction) */ maxCacheKeys?: number | undefined; /** * min ms between refetches on kid-miss */ cooldownMs?: number | undefined; /** * fetch timeout in ms */ timeout?: number | undefined; /** * allow http:// URIs (default https only) */ allowInsecure?: boolean | undefined; /** * serve stale cached keys when a refetch fails */ staleWhileError?: boolean | undefined; /** * caller-provided AbortSignal forwarded to fetch */ signal?: AbortSignal; /** * extra headers sent on the fetch request */ headers?: Record | undefined; /** * called when a key cannot be resolved (kid not found or alg mismatch) */ onInvalidKey?: ((header: { kid: string; alg?: string; }, error: Error) => void) | undefined; /** * max bytes accepted from the JWKS endpoint (default 1 MB) */ maxResponseSize?: number | undefined; /** * gate on the destination host; return false to refuse the URI */ allowHost?: ((hostname: string, url: URL) => boolean) | undefined; }; /** * Shared base error class — the single error structure behind every * `@exortek/*` package's `errors.js`. * * Every package keeps its own class identity with a one-liner subclass; * codes stay per-package frozen maps, status mapping is declared as a * static field: * * import { BaseError } from '@exortek/shared/errors'; * * export const ErrorCode = Object.freeze({ * INVALID_ARGUMENT: 'INVALID_ARGUMENT', * INVALID_TOKEN: 'INVALID_TOKEN', * }); * * export class JwtError extends BaseError { * static statuses = { INVALID_ARGUMENT: 400, INVALID_TOKEN: 401 }; * static defaultStatus = 500; * } * * Instances carry a stable machine-readable `code` (branch on this, * never on the message), an optional HTTP `status`, an optional * `details` object, and the standard `cause` chain. */ declare class BaseError extends Error { /** * Optional `code → HTTP status` map declared on the subclass. When * absent the instance carries no `status` at all — for HTTP-agnostic * packages like `@exortek/crypto`. * * @type {Record | undefined} */ static statuses: Record | undefined; /** * Fallback status for codes missing from `statuses`. * * @type {number} */ static defaultStatus: number; /** * @param {string} code Stable machine-readable code; branch on this. * @param {string} message Human-readable diagnostic. Free-form; may * change across versions. * @param {{ cause?: unknown, status?: number, details?: Record }} [options] */ constructor(code: string, message: string, options?: { cause?: unknown; status?: number; details?: Record; }); /** @type {string} */ code: string; /** @type {number | undefined} */ status: number | undefined; /** @type {Record | undefined} */ details: Record | undefined; } declare const ErrorCode: Readonly<{ INVALID_ARGUMENT: "INVALID_ARGUMENT"; FETCH_FAILED: "FETCH_FAILED"; KID_NOT_FOUND: "KID_NOT_FOUND"; }>; declare class JwksError extends BaseError { static statuses: { INVALID_ARGUMENT: number; FETCH_FAILED: number; KID_NOT_FOUND: number; }; } declare const jwks: Readonly<{ create: typeof createLocalKeySet; remote: typeof createRemoteJWKS; }>; export { ErrorCode, JwksError, createLocalKeySet, createRemoteJWKS, jwks };