@fanvue/builder-sdk 0.4.0 → 0.5.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 +284 -0
- package/dist/bridge/index.d.ts +1 -1
- package/dist/bridge/index.js +2 -2
- package/dist/{bridge-CGVtI3hr.js → bridge-QnF7P4Co.js} +2 -2
- package/dist/{bridge-CGVtI3hr.js.map → bridge-QnF7P4Co.js.map} +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +3 -3
- package/dist/{core-BqdYUMrJ.js → core-BhKiA55a.js} +1318 -9
- package/dist/core-BhKiA55a.js.map +1 -0
- package/dist/index-C3CXrRiw.d.ts +1412 -0
- package/dist/index-C3CXrRiw.d.ts.map +1 -0
- package/dist/{index-BRDYLBlc.d.ts → index-CEFYZtlb.d.ts} +2 -2
- package/dist/{index-BRDYLBlc.d.ts.map → index-CEFYZtlb.d.ts.map} +1 -1
- package/dist/{index-Dr-mZ0qP.d.ts → index-cf3ZMnLJ.d.ts} +26 -2
- package/dist/index-cf3ZMnLJ.d.ts.map +1 -0
- package/dist/index-v_6Z4Q0u.d.ts +84 -0
- package/dist/index-v_6Z4Q0u.d.ts.map +1 -0
- package/dist/{schemas-DbyHF7Xi.js → index.cjs-teGsk6HB.js} +1058 -977
- package/dist/index.cjs-teGsk6HB.js.map +1 -0
- package/dist/nextjs/embedded-app/index.d.ts +2 -2
- package/dist/nextjs/embedded-app/index.js +3 -3
- package/dist/nextjs/off-platform/index.d.ts +3 -3
- package/dist/nextjs/off-platform/index.d.ts.map +1 -1
- package/dist/nextjs/off-platform/index.js +4 -4
- package/dist/nextjs/off-platform/index.js.map +1 -1
- package/dist/nextjs-CvVhtMdb.js +144 -0
- package/dist/nextjs-CvVhtMdb.js.map +1 -0
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +3 -3
- package/package.json +1 -1
- package/dist/core-BqdYUMrJ.js.map +0 -1
- package/dist/index-C4ewLil3.d.ts +0 -48
- package/dist/index-C4ewLil3.d.ts.map +0 -1
- package/dist/index-ClbZoV_Z.d.ts +0 -420
- package/dist/index-ClbZoV_Z.d.ts.map +0 -1
- package/dist/index-Dr-mZ0qP.d.ts.map +0 -1
- package/dist/nextjs-B5Tqgt_n.js +0 -80
- package/dist/nextjs-B5Tqgt_n.js.map +0 -1
- package/dist/schemas-DbyHF7Xi.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-BhKiA55a.js","names":["z.enum","z.object","z.string","z.preprocess","z.url","z.looseObject","z.string","z\n .array","z.array","z.union","z.object","z\n .looseObject","z.object","z.literal","z.string","z.enum","z.discriminatedUnion","z.object","z.number","z.boolean","z.string","z.array","encoder","decoder","z.object","z.string","z.number","z.boolean","z\n .object","oauth.generateRandomCodeVerifier","oauth.calculatePKCECodeChallenge","oauth.generateRandomState","encode","jwk.isJWK","jwk.isSecretJWK","invalidKeyInput","jwk.isPrivateJWK","jwk.isPublicJWK","b64u","encode","#payload","#payload","#protectedHeader","#unprotectedHeader","b64u","encode","#flattened","#jwt","#protectedHeader","oauth.generateRandomCodeVerifier","oauth.calculatePKCECodeChallenge","oauth.generateRandomState"],"sources":["../src/core/constants.ts","../src/core/contracts/access-mode.ts","../src/core/defaults.ts","../src/core/contracts/env.ts","../src/core/contracts/errors.ts","../src/core/contracts/experience-protocol.ts","../src/core/contracts/pagination.ts","../node_modules/.pnpm/oauth4webapi@3.8.5/node_modules/oauth4webapi/build/index.js","../src/core/json.ts","../src/core/schemas.ts","../src/core/oauth.ts","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/buffer_utils.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/base64.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/util/base64url.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/crypto_key.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/invalid_key_input.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/util/errors.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/is_key_like.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/helpers.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/type_checks.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/signing.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/jwk_to_key.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/normalize_key.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/validate_crit.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/validate_algorithms.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/check_key_type.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/jws/flattened/verify.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/jws/compact/verify.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/lib/jwt_claims_set.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/jwt/verify.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/jws/flattened/sign.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/jws/compact/sign.js","../node_modules/.pnpm/jose@6.2.1/node_modules/jose/dist/webapi/jwt/sign.js","../src/core/session.ts","../src/core/embedded.ts","../src/core/client.ts","../src/core/machine-auth/machine-auth.ts","../src/core/observability/email.ts","../src/core/observability/uuid.ts","../src/core/observability/log-fields.ts","../src/core/observability/readiness.ts","../src/core/observability/sentry-scrubber.ts"],"sourcesContent":["/** The `Bearer ` token prefix (includes trailing space). */\nexport const BEARER_PREFIX = 'Bearer ' as const;\n\n/** Response header carrying a refreshed session JWT back to the client. */\nexport const HEADER_UPDATED_SESSION = 'X-Updated-Session' as const;\n","/**\n * Experience access modes and the entitlement reasons the platform reports\n * alongside them.\n *\n * The platform's own identifier for this enum is `AccessMode`;\n * {@link FanvueAccessMode} is the SDK alias, named so it does not collide with\n * an app's own access-mode types.\n */\n\nimport { z } from 'zod';\n\n/**\n * Access modes an experience can propose or carry on Fanvue.\n *\n * - `FREE` — visible and playable by anyone.\n * - `SUBSCRIPTION` — requires an active subscription to the creator.\n * - `PAID` — requires a one-off purchase.\n * - `HIDDEN` — reachable only through a share grant, never listed.\n */\nexport const FANVUE_ACCESS_MODES = ['FREE', 'SUBSCRIPTION', 'PAID', 'HIDDEN'] as const;\n\n/** An experience access mode. */\nexport type FanvueAccessMode = (typeof FANVUE_ACCESS_MODES)[number];\n\n/** Zod schema for {@link FanvueAccessMode}. */\nexport const FanvueAccessModeSchema = z.enum(FANVUE_ACCESS_MODES);\n\n/**\n * Every reason the platform reports when a fan **is** entitled to an\n * experience, as emitted by fanguard's `resolveExperienceAccess`.\n *\n * Documented for completeness and for exhaustive logging/analytics; apps should\n * branch on `entitlement.isEntitled` rather than on a specific reason, because\n * this list grows without an API version bump.\n *\n * - `owner` — the requester is the creator who owns the experience.\n * - `entitled_via_free`, `free` — the experience is `FREE`.\n * - `entitled_via_subscription`, `subscribed` — active creator subscription.\n * - `entitled_via_share` — reached through a share grant.\n * - `purchased` — one-off purchase of the experience.\n * - `app_subscribed` — subscription to the app itself.\n * - `purchased_before_mode_change`, `app_subscribed_before_mode_change` —\n * entitlement grandfathered from before the creator changed the access mode.\n * - `hidden_token_exchange` — the documented exemption to the fail-closed rule:\n * a `HIDDEN` experience exchanges its token without a prior grant.\n */\nexport const EXPERIENCE_ENTITLED_REASONS = [\n 'owner',\n 'entitled_via_free',\n 'entitled_via_share',\n 'entitled_via_subscription',\n 'free',\n 'subscribed',\n 'purchased',\n 'app_subscribed',\n 'purchased_before_mode_change',\n 'app_subscribed_before_mode_change',\n 'hidden_token_exchange',\n] as const;\n\n/**\n * A reason the platform reports for an entitled exchange.\n *\n * Open-ended (`string & {}`) for forward compatibility: the platform can add a\n * reason at any time, and an app must not break on one it has not seen.\n */\nexport type ExperienceEntitledReason = (typeof EXPERIENCE_ENTITLED_REASONS)[number] | (string & {});\n\n/**\n * Every reason the platform reports when a fan is **denied** an experience.\n *\n * These are the only three values fanguard emits today; the type stays open for\n * forward compatibility.\n */\nexport const EXPERIENCE_DENIAL_REASONS = [\n 'not_subscribed',\n 'not_purchased',\n 'no_share_grant',\n] as const;\n\n/**\n * A reason the platform reports for a denied exchange.\n *\n * Open-ended (`string & {}`) so a newly added reason narrows to `null` in\n * {@link accessModeFromDenialReason} instead of failing to type-check.\n */\nexport type ExperienceDenialReason = (typeof EXPERIENCE_DENIAL_REASONS)[number] | (string & {});\n\n/**\n * Recovers the access mode a denied experience must be in, from the denial\n * reason.\n *\n * The token exchange fails closed: an unentitled fan gets a 403 carrying only a\n * denial `reason`, and the experience payload — with it the access mode — is\n * withheld. Mapping the reason back is the only way a locked screen can show\n * the right copy (\"subscribe\" vs \"buy\" vs \"ask for the link\"). An unrecognised\n * reason maps to `null`, meaning \"show the generic locked copy\".\n *\n * @param reason - The `reason` field from the platform's 403 body.\n * @returns The implied access mode, or `null` when the reason is unrecognised.\n * @example\n * accessModeFromDenialReason('not_subscribed'); // 'SUBSCRIPTION'\n * accessModeFromDenialReason('not_purchased'); // 'PAID'\n * accessModeFromDenialReason('no_share_grant'); // 'HIDDEN'\n * accessModeFromDenialReason('something_new'); // null\n */\nexport function accessModeFromDenialReason(\n reason: ExperienceDenialReason,\n): FanvueAccessMode | null {\n switch (reason) {\n case 'not_subscribed':\n return 'SUBSCRIPTION';\n case 'not_purchased':\n return 'PAID';\n case 'no_share_grant':\n return 'HIDDEN';\n default:\n return null;\n }\n}\n","/** Default OAuth scopes requested during authorization. */\nexport const DEFAULT_SCOPES = 'openid offline_access offline' as const;\n\n/** Default OAuth issuer URL for Fanvue authentication. */\nexport const DEFAULT_ISSUER_URL = 'https://auth.fanvue.com' as const;\n\n/** Default base URL for the Fanvue API. */\nexport const DEFAULT_API_BASE_URL = 'https://api.fanvue.com' as const;\n\n/** Default base URL for the Fanvue platform (embedded authorize-on-behalf). */\nexport const DEFAULT_PLATFORM_URL = 'https://www.fanvue.com' as const;\n\n/** The Fanvue API version header value sent with every request. */\nexport const API_VERSION = '2025-06-26' as const;\n\n/**\n * Validates that a URL belongs to the `fanvue.com` domain.\n *\n * @param url - The URL string to validate.\n * @throws If the URL is malformed or its hostname is not `fanvue.com`\n * (or a subdomain of it).\n */\nexport function assertFanvueDomain(url: string): void {\n let hostname: string;\n try {\n hostname = new URL(url).hostname;\n } catch {\n throw new Error(`Invalid apiBaseUrl: \"${url}\" is not a valid URL.`);\n }\n if (hostname !== 'fanvue.com' && !hostname.endsWith('.fanvue.com')) {\n throw new Error(\n `Invalid apiBaseUrl: \"${url}\" must be a fanvue.com domain (e.g. https://api.fanvue.com).`,\n );\n }\n}\n","/**\n * The canonical `FANVUE_*` environment contract.\n *\n * Every app that embeds on Fanvue reads the same nine variables and, before\n * this module, validated them with nine slightly different schemas — one repo\n * had two incompatible ones in the same process, each with its own cache, so\n * whichever accessor ran first froze its own view of `process.env`.\n *\n * Two deliberate properties, both inherited from the app that got them right:\n *\n * - **Lazily parsed and cached.** A build must succeed without secrets, so\n * nothing is read at import time; a bad value surfaces as a runtime failure on\n * first use rather than at boot.\n * - **Credentials are schema-optional.** `FANVUE_APP_UUID`, `FANVUE_CLIENT_ID`,\n * `FANVUE_CLIENT_SECRET` and `FANVUE_OAUTH_REDIRECT_URI` default to `\"\"`\n * instead of being required, so a preview deploy or a local checkout boots\n * without them. {@link isFanvueConfigured} is the separate, explicit check\n * callers run before touching an OAuth path.\n */\n\nimport { z } from 'zod';\n\nimport {\n API_VERSION,\n DEFAULT_API_BASE_URL,\n DEFAULT_ISSUER_URL,\n DEFAULT_PLATFORM_URL,\n} from '../defaults.js';\n\n/**\n * Treats a blank string as unset.\n *\n * `.env` templates ship lines like `FANVUE_API_BASE_URL=`, and a platform\n * dashboard saves an emptied field as `\"\"` rather than deleting it. For a\n * variable with a real default, blank must mean \"use the default\" — a literal\n * empty base URL would turn every request into a relative fetch.\n */\nfunction blankToUndefined(value: unknown): unknown {\n return typeof value === 'string' && value.trim() === '' ? undefined : value;\n}\n\n/**\n * Zod schema for the `FANVUE_*` environment contract.\n *\n * - `FANVUE_APP_UUID` — the app's UUID on Fanvue. Checked against the `appUuid`\n * an exchanged experience token carries, so a token minted for another app is\n * rejected. Defaults to `\"\"`.\n * - `FANVUE_CLIENT_ID` / `FANVUE_CLIENT_SECRET` / `FANVUE_OAUTH_REDIRECT_URI` —\n * OAuth client credentials. Default to `\"\"`; see {@link isFanvueConfigured}.\n * - `FANVUE_API_BASE_URL` — bare origin of the Fanvue API (no `/v0` suffix).\n * Blank falls back to the default.\n * - `FANVUE_AUTH_BASE_URL` — origin of the Fanvue authorization server. Blank\n * falls back to the default.\n * - `FANVUE_WEB_ORIGIN` — origin of the Fanvue web shell. The only variable\n * with real URL validation, because it is concatenated into hrefs a creator\n * or fan clicks: a schemeless value ships a dead link. Blank falls back to\n * the default. Note this does not constrain the scheme.\n * - `FANVUE_API_VERSION` — value sent as `X-Fanvue-API-Version`. Blank falls\n * back to the default.\n * - `FANVUE_EXPERIENCE_URL_TEMPLATE` — optional operator override for\n * per-experience share links. Empty means \"derive the URL\".\n */\nexport const FanvueEnvSchema = z.object({\n FANVUE_APP_UUID: z.string().default(''),\n FANVUE_CLIENT_ID: z.string().default(''),\n FANVUE_CLIENT_SECRET: z.string().default(''),\n FANVUE_OAUTH_REDIRECT_URI: z.string().default(''),\n FANVUE_API_BASE_URL: z.preprocess(blankToUndefined, z.string().default(DEFAULT_API_BASE_URL)),\n FANVUE_AUTH_BASE_URL: z.preprocess(blankToUndefined, z.string().default(DEFAULT_ISSUER_URL)),\n FANVUE_WEB_ORIGIN: z.preprocess(blankToUndefined, z.url().default(DEFAULT_PLATFORM_URL)),\n FANVUE_API_VERSION: z.preprocess(blankToUndefined, z.string().default(API_VERSION)),\n FANVUE_EXPERIENCE_URL_TEMPLATE: z.string().default(''),\n});\n\n/** The validated `FANVUE_*` environment. */\nexport type FanvueEnv = z.infer<typeof FanvueEnvSchema>;\n\n/** A read-only view of an environment variable bag. */\nexport type EnvSource = Readonly<Record<string, string | undefined>>;\n\n/**\n * Validates an environment bag against {@link FanvueEnvSchema}.\n *\n * Pure and uncached — takes the environment as a parameter so it is unit\n * testable. Prefer {@link fanvueEnv} in application code.\n *\n * @param source - The variables to validate.\n * @returns The validated environment.\n * @throws If a present value fails validation (today: a non-URL\n * `FANVUE_WEB_ORIGIN`).\n */\nexport function parseFanvueEnv(source: EnvSource): FanvueEnv {\n return FanvueEnvSchema.parse(source);\n}\n\nlet cachedEnv: FanvueEnv | null = null;\nconst warnedFlags = new Set<string>();\n\n/**\n * Returns the validated `FANVUE_*` environment, parsing `process.env` on first\n * use and caching the result.\n *\n * @returns The validated environment.\n * @throws If a present value fails validation.\n * @example\n * const baseUrl = fanvueEnv().FANVUE_API_BASE_URL;\n */\nexport function fanvueEnv(): FanvueEnv {\n if (cachedEnv === null) {\n cachedEnv = parseFanvueEnv(process.env);\n }\n return cachedEnv;\n}\n\n/**\n * Clears every piece of memoised state in this module: the {@link fanvueEnv}\n * cache and {@link flagEnabled}'s warned-flag set.\n *\n * Intended for tests, which mutate `process.env` between cases and would\n * otherwise see whichever value the first case happened to freeze. The warn-once\n * set is cleared for the same reason — left in place, whether a case sees the\n * warning depends on which case ran first.\n */\nexport function resetFanvueEnvCache(): void {\n cachedEnv = null;\n warnedFlags.clear();\n}\n\n/**\n * Whether the four Fanvue credential variables are all set.\n *\n * Covers exactly the values OAuth configuration requires, because config\n * creation throws on a missing one and an uncaught throw in a route surfaces as\n * a 500. Call this first and return a \"not configured\" response instead.\n *\n * @param env - The environment to check. Defaults to the cached\n * {@link fanvueEnv}.\n * @returns `true` when app UUID, client id, client secret and redirect URI are\n * all non-blank. Whitespace-only counts as unset, matching how the schema\n * treats blank values everywhere else in this module.\n * @example\n * if (!isFanvueConfigured()) {\n * return Response.json({ error: { code: 'fanvue_not_configured', message: '…' } }, { status: 503 });\n * }\n */\nexport function isFanvueConfigured(env: FanvueEnv = fanvueEnv()): boolean {\n return (\n env.FANVUE_APP_UUID.trim() !== '' &&\n env.FANVUE_CLIENT_ID.trim() !== '' &&\n env.FANVUE_CLIENT_SECRET.trim() !== '' &&\n env.FANVUE_OAUTH_REDIRECT_URI.trim() !== ''\n );\n}\n\n/**\n * Reads a boolean environment flag.\n *\n * A strict `=== \"true\"` is how one app's `MCP_ENABLED=\"TRUE\"` switched a whole\n * subsystem off in staging: every route answered 404 and the value looked\n * correct in the dashboard. A flag that fails closed on a casing typo and says\n * nothing costs more than one that is simply off, because there is no signal to\n * find. So surrounding whitespace and case do not matter, and a value that\n * still cannot be read as a boolean is warned about **once per flag name** and\n * treated as off — off is the safe answer, but not a silent one.\n *\n * @param name - The environment variable name.\n * @param source - The variables to read from. Defaults to `process.env`.\n * @returns `true` only for `\"true\"` (after trimming and lowercasing).\n * @see {@link resetFanvueEnvCache} to clear the warned-flag set between tests.\n * @example\n * flagEnabled('MY_APP_DEV_MODE'); // reads process.env.MY_APP_DEV_MODE\n * flagEnabled('MY_APP_DEV_MODE', { MY_APP_DEV_MODE: ' TRUE ' }); // true\n */\nexport function flagEnabled(name: string, source: EnvSource = process.env): boolean {\n const raw = source[name];\n const value = (raw ?? '').trim().toLowerCase();\n if (value === 'true') return true;\n if (value !== 'false' && value !== '' && !warnedFlags.has(name)) {\n warnedFlags.add(name);\n console.warn(\n `${name} is set to ${JSON.stringify(raw)}, which is not true or false. Treating it as off.`,\n );\n }\n return false;\n}\n","/**\n * Error contracts: the shapes the Fanvue API puts on the wire, the envelope an\n * app puts on its own responses, and the codes that travel between them.\n *\n * The platform has **no single error envelope**. Four shapes are in production\n * use, and a machine-readable `reason` rides alongside the human text on the\n * experience-exchange 403 — losing it collapses \"this fan is not entitled\" into\n * \"this token belongs to another app\". {@link parseFanvueErrorBody} normalises\n * all four into one struct without discarding `reason`.\n */\n\nimport { z } from 'zod';\n\n/**\n * `{ message }` — 404s, contactability rejections, invalid creator UUIDs, and\n * the experience-exchange 403 (which adds `reason`). `code` appears on\n * bulk-media per-item errors.\n */\nexport const FanvueMessageErrorBodySchema = z.looseObject({\n message: z.string(),\n reason: z.string().nullish().catch(null),\n code: z.string().nullish().catch(null),\n});\n\n/**\n * `{ error }` — 401/403/500/503 and upstream tRPC failures, where `error` is the\n * human text; and `{ error, message }` — version and age-verification failures,\n * where `error` is a machine-readable code and `message` the human text.\n */\nexport const FanvueErrorFieldBodySchema = z.looseObject({\n error: z.string(),\n message: z.string().nullish().catch(null),\n reason: z.string().nullish().catch(null),\n});\n\n/** `{ errors: [{ code, message }] }` — Zod request-validation failures. */\nexport const FanvueIssueListErrorBodySchema = z.looseObject({\n errors: z\n .array(z.looseObject({ code: z.string().nullish().catch(null), message: z.string() }))\n .min(1),\n});\n\n/** `{ errors: [\"Invalid page: too small\"] }` — the pagination middleware. */\nexport const FanvueStringListErrorBodySchema = z.looseObject({\n errors: z.array(z.string()).min(1),\n});\n\n/**\n * Any of the four documented Fanvue API error bodies.\n *\n * Member order matters: the `errors` array shapes are tried first because they\n * carry no `message`/`error` key of their own, then `{ error }` (which may also\n * carry a `message`), then `{ message }` alone. Exported for callers that want\n * to validate a body in one step; {@link parseFanvueErrorBody} tries the members\n * individually so that one unreadable field cannot cost the whole body.\n */\nexport const FanvueErrorBodySchema = z.union([\n FanvueStringListErrorBodySchema,\n FanvueIssueListErrorBodySchema,\n FanvueErrorFieldBodySchema,\n FanvueMessageErrorBodySchema,\n]);\n\n/** A parsed Fanvue API error body, before normalisation. */\nexport type FanvueErrorBody = z.infer<typeof FanvueErrorBodySchema>;\n\n/**\n * A Fanvue API error body reduced to the three fields a caller can act on.\n *\n * @property message - Human-readable text for logs and debugging. Empty string\n * when the body carried none; callers substitute their own generic message\n * (which is what an end user should see — never upstream text).\n * @property reason - The machine-readable reason, when the platform sent one.\n * Load-bearing on the experience exchange: a 403 **with** a reason is an\n * entitlement refusal, a bare 403 is an app-binding mismatch.\n * @property code - The machine-readable code, when the platform sent one.\n */\nexport type NormalisedFanvueError = {\n message: string;\n reason: string | null;\n code: string | null;\n};\n\n/**\n * Normalises any Fanvue API error body into {@link NormalisedFanvueError}.\n *\n * Never throws and never inspects the HTTP status: a body it cannot read yields\n * an empty `message`, which the transport replaces with its own status-derived\n * text. Multiple validation issues are joined with `; ` so a single log line\n * carries all of them.\n *\n * The `{ error }` shape is disambiguated by whether a `message` sits next to it:\n * `{ error: 'age_verification_required', message: 'Verify…' }` puts the code in\n * `code` and the text in `message`, while a bare `{ error: 'Unauthorized' }` is\n * treated as text only.\n *\n * @param body - A parsed JSON body (or anything at all).\n * @returns The normalised error fields.\n * @example\n * parseFanvueErrorBody({ message: 'Fan is not entitled', reason: 'not_subscribed' });\n * // { message: 'Fan is not entitled', reason: 'not_subscribed', code: null }\n * parseFanvueErrorBody({ errors: [{ code: 'invalid_type', message: 'Expected string' }] });\n * // { message: 'Expected string', reason: null, code: 'invalid_type' }\n * parseFanvueErrorBody('<html>502</html>');\n * // { message: '', reason: null, code: null }\n */\nexport function parseFanvueErrorBody(body: unknown): NormalisedFanvueError {\n const stringList = FanvueStringListErrorBodySchema.safeParse(body);\n if (stringList.success) {\n return { message: stringList.data.errors.join('; '), reason: null, code: null };\n }\n\n const issueList = FanvueIssueListErrorBodySchema.safeParse(body);\n if (issueList.success) {\n const issues = issueList.data.errors;\n return {\n message: issues.map((issue) => issue.message).join('; '),\n reason: null,\n code: issues.find((issue) => typeof issue.code === 'string')?.code ?? null,\n };\n }\n\n const errorField = FanvueErrorFieldBodySchema.safeParse(body);\n if (errorField.success) {\n const { error, message, reason } = errorField.data;\n return {\n message: message ?? error,\n reason: reason ?? null,\n code: typeof message === 'string' ? error : null,\n };\n }\n\n const messageBody = FanvueMessageErrorBodySchema.safeParse(body);\n if (messageBody.success) {\n return {\n message: messageBody.data.message,\n reason: messageBody.data.reason ?? null,\n code: messageBody.data.code ?? null,\n };\n }\n\n return { message: '', reason: null, code: null };\n}\n\n/**\n * Zod schema for an app's own error envelope: `{ error: { code, message } }`.\n *\n * Every Fanvue app helper produces this shape and every client parses it, so it\n * is a contract rather than a convention. The `message` is what an end user\n * reads — upstream and internal text belongs in the log, never in this body.\n */\nexport const AppErrorEnvelopeSchema = z.object({\n error: z.object({\n code: z.string().min(1),\n message: z.string(),\n }),\n});\n\n/** An app's error response body. */\nexport type AppErrorEnvelope = z.infer<typeof AppErrorEnvelopeSchema>;\n\n/**\n * Canonical app-facing error codes for Fanvue-grant failures.\n *\n * - `fanvue_reconnect_required` (401) — the stored Fanvue grant is missing or\n * dead. The creator must reopen the app from Fanvue.\n * - `fanvue_permission_denied` (403) — the grant is alive but lacks the scope\n * for this capability. Reconnecting re-consents the new scope.\n * - `fanvue_api_error` (502) — the Fanvue API failed for any other reason.\n */\nexport const FANVUE_APP_ERROR_CODES = {\n reconnectRequired: 'fanvue_reconnect_required',\n permissionDenied: 'fanvue_permission_denied',\n apiError: 'fanvue_api_error',\n} as const;\n\n/** One of the canonical app-facing Fanvue error codes. */\nexport type FanvueAppErrorCode =\n (typeof FANVUE_APP_ERROR_CODES)[keyof typeof FANVUE_APP_ERROR_CODES];\n\n/**\n * The two 401 codes that mean the **Fanvue grant** is gone while the **app\n * session** is still valid.\n *\n * A client that treats every 401 as session expiry signs the creator out of a\n * working session and offers \"Reload\" — the one action that cannot restore a\n * missing grant. Check membership of this set before running expiry handling,\n * and route these to a reconnect prompt instead.\n *\n * @example\n * if (status === 401 && !NON_SESSION_401_CODES.has(code)) {\n * onSessionExpired();\n * }\n */\nexport const NON_SESSION_401_CODES: ReadonlySet<string> = new Set([\n FANVUE_APP_ERROR_CODES.reconnectRequired,\n FANVUE_APP_ERROR_CODES.permissionDenied,\n]);\n\n/**\n * Zod schema for an OAuth 2.0 error response body, normalised to camelCase.\n *\n * Only `error` and `error_description` are kept. Hydra also returns\n * `error_hint` and `error_debug`, which can echo request details back and have\n * no place in an app's own error path.\n */\nexport const OAuthErrorBodySchema = z\n .looseObject({\n error: z.string().min(1),\n error_description: z.string().nullish(),\n })\n .transform((raw) => ({\n error: raw.error,\n errorDescription: raw.error_description ?? null,\n }));\n\n/**\n * An OAuth 2.0 error response body.\n *\n * @property error - The RFC 6749 error code (`invalid_grant`, `invalid_client`,\n * `invalid_scope`, …). This is the distinction that tells a dead refresh token\n * apart from bad client credentials.\n * @property errorDescription - The provider's human-readable description, or\n * `null`. For logs and debugging only.\n */\nexport type OAuthErrorBody = z.infer<typeof OAuthErrorBodySchema>;\n","/**\n * The `fanvue:experience:*` postMessage protocol between an embedded app and\n * the Fanvue web shell (Eden).\n *\n * Publishing is Fanvue-mediated: the app's backend mints an opaque request\n * token from the Fanvue API (`POST /v0/experiences/request-token`, scope\n * `write:experience`), the iframe posts `{ type, token }` to the parent\n * window, Fanvue verifies the token server-side and shows its native\n * \"Configure Experience\" modal, then replies with a result message. An app\n * never mutates Fanvue experience state directly.\n *\n * This module is the wire contract only — schemas, type guards and origin\n * validation. The browser bridge that drives the handshake (timeouts, escalation\n * to `window.top`, listener cleanup) lives outside this module.\n */\n\nimport { z } from 'zod';\n\n/** Message type an app posts to request the publish modal. */\nexport const PUBLISH_REQUEST_MESSAGE = 'fanvue:experience:publish-request' as const;\n\n/** Message type Fanvue posts back with the outcome of a publish request. */\nexport const PUBLISH_RESULT_MESSAGE = 'fanvue:experience:publish-result' as const;\n\n/** Message type an app posts to request the unpublish confirmation. */\nexport const UNPUBLISH_REQUEST_MESSAGE = 'fanvue:experience:unpublish-request' as const;\n\n/** Message type Fanvue posts back with the outcome of an unpublish request. */\nexport const UNPUBLISH_RESULT_MESSAGE = 'fanvue:experience:unpublish-result' as const;\n\n/**\n * Every message type in the protocol, in request/result pairs.\n *\n * Useful for filtering an incoming `MessageEvent` before schema validation.\n */\nexport const EXPERIENCE_MESSAGE_TYPES = [\n PUBLISH_REQUEST_MESSAGE,\n PUBLISH_RESULT_MESSAGE,\n UNPUBLISH_REQUEST_MESSAGE,\n UNPUBLISH_RESULT_MESSAGE,\n] as const;\n\n/** One of the four `fanvue:experience:*` message types. */\nexport type ExperienceMessageType = (typeof EXPERIENCE_MESSAGE_TYPES)[number];\n\n/**\n * Zod schema for the app → Fanvue publish request.\n *\n * `token` is the opaque request token minted by\n * `POST /v0/experiences/request-token` with `action: \"publish\"`.\n */\nexport const PublishRequestMessageSchema = z.object({\n type: z.literal(PUBLISH_REQUEST_MESSAGE),\n token: z.string().min(1),\n});\n\n/** The app → Fanvue publish request message. */\nexport type PublishRequestMessage = z.infer<typeof PublishRequestMessageSchema>;\n\n/**\n * Zod schema for the app → Fanvue unpublish request.\n *\n * `token` is the opaque request token minted by\n * `POST /v0/experiences/request-token` with `action: \"unpublish\"`.\n */\nexport const UnpublishRequestMessageSchema = z.object({\n type: z.literal(UNPUBLISH_REQUEST_MESSAGE),\n token: z.string().min(1),\n});\n\n/** The app → Fanvue unpublish request message. */\nexport type UnpublishRequestMessage = z.infer<typeof UnpublishRequestMessageSchema>;\n\n/**\n * Zod schema for the Fanvue → app publish result.\n *\n * `experienceId` is optional rather than nullable because it mirrors the wire\n * shape: Fanvue omits the key entirely when the creator cancels. `cancelled`\n * covers both a dismissed modal and a server-side rejection of the request\n * token — the two are not distinguishable from this side.\n *\n * Any string is accepted, including `\"\"`. A receiver must not reject an\n * otherwise well-formed result over a useless id: from the app's side a rejected\n * message is indistinguishable from no reply at all, so a publish that did\n * happen would hang until the bridge timed out. Treat a falsy `experienceId` the\n * way an absent one is treated.\n */\nexport const PublishResultMessageSchema = z.object({\n type: z.literal(PUBLISH_RESULT_MESSAGE),\n status: z.enum(['published', 'cancelled']),\n experienceId: z.string().optional(),\n});\n\n/** The Fanvue → app publish result message. */\nexport type PublishResultMessage = z.infer<typeof PublishResultMessageSchema>;\n\n/** Zod schema for the Fanvue → app unpublish result. */\nexport const UnpublishResultMessageSchema = z.object({\n type: z.literal(UNPUBLISH_RESULT_MESSAGE),\n status: z.enum(['unpublished', 'cancelled']),\n});\n\n/** The Fanvue → app unpublish result message. */\nexport type UnpublishResultMessage = z.infer<typeof UnpublishResultMessageSchema>;\n\n/**\n * Zod schema for any message in the protocol, discriminated on `type`.\n *\n * @example\n * const parsed = ExperienceMessageSchema.safeParse(event.data);\n * if (parsed.success && parsed.data.type === PUBLISH_RESULT_MESSAGE) {\n * // parsed.data is a PublishResultMessage\n * }\n */\nexport const ExperienceMessageSchema = z.discriminatedUnion('type', [\n PublishRequestMessageSchema,\n PublishResultMessageSchema,\n UnpublishRequestMessageSchema,\n UnpublishResultMessageSchema,\n]);\n\n/** Any message in the `fanvue:experience:*` protocol. */\nexport type ExperienceMessage = z.infer<typeof ExperienceMessageSchema>;\n\n/**\n * Narrows unknown `MessageEvent` data to a {@link PublishResultMessage}.\n *\n * @param value - The raw `event.data` from a `message` event.\n * @returns `true` when the value validates against the publish-result schema.\n * @example\n * if (isPublishResultMessage(event.data) && isFanvueOrigin(event.origin)) {\n * settle(event.data);\n * }\n */\nexport function isPublishResultMessage(value: unknown): value is PublishResultMessage {\n return PublishResultMessageSchema.safeParse(value).success;\n}\n\n/**\n * Narrows unknown `MessageEvent` data to an {@link UnpublishResultMessage}.\n *\n * @param value - The raw `event.data` from a `message` event.\n * @returns `true` when the value validates against the unpublish-result schema.\n */\nexport function isUnpublishResultMessage(value: unknown): value is UnpublishResultMessage {\n return UnpublishResultMessageSchema.safeParse(value).success;\n}\n\n/**\n * Whether an origin belongs to the Fanvue web shell.\n *\n * Mirrors the `frame-ancestors 'self' https://fanvue.com https://*.fanvue.com`\n * CSP allowlist every embedded app ships. Eden posts its replies with\n * `targetOrigin: \"*\"`, so validating `event.origin` on receipt is the only\n * app-side control against a sibling frame forging a publish success. Requires\n * `https:` — a plaintext origin is never Fanvue.\n *\n * @param origin - The `event.origin` of an incoming message.\n * @returns `true` for `https://fanvue.com` and any `https://*.fanvue.com` host.\n * @example\n * isFanvueOrigin('https://www.fanvue.com'); // true\n * isFanvueOrigin('http://fanvue.com'); // false (not https)\n * isFanvueOrigin('https://fanvue.com.evil.test'); // false\n */\nexport function isFanvueOrigin(origin: string): boolean {\n let protocol: string;\n let hostname: string;\n try {\n ({ protocol, hostname } = new URL(origin));\n } catch {\n return false;\n }\n return protocol === 'https:' && (hostname === 'fanvue.com' || hostname.endsWith('.fanvue.com'));\n}\n","/**\n * Shared pagination fragments for the Fanvue API.\n *\n * The platform ships three conventions and every resource module has to pick\n * one, so the fragments live here rather than being re-declared per resource:\n *\n * 1. **Offset** (`v0`) — `?page=&size=`, response `{ data, pagination }`.\n * 2. **Cursor** (`v1` keyset and some `v0` routes) — response\n * `{ data, nextCursor, total }`, where `total` is `null` on large keyset\n * lists and absent entirely on the `v0` cursor routes.\n * 3. **Hybrid** (`GET /v0/subscribers`) — offset plus an optional `nextCursor`,\n * which is `null` when sorting by name.\n *\n * This module is schemas and clamping only. The async-iterator helper that\n * walks pages while respecting rate-limit headers is a separate concern and\n * ships with the transport.\n */\n\nimport { z } from 'zod';\n\n/**\n * Largest `size` the platform accepts on an offset-paginated route.\n *\n * The API responds `400` above this, so callers clamp client-side (see\n * {@link clampPageSize}) rather than turning an over-large request into a\n * failure the caller cannot act on.\n */\nexport const MAX_PAGE_SIZE = 50;\n\n/** The platform's default `size` when the query parameter is omitted. */\nexport const DEFAULT_PAGE_SIZE = 15;\n\n/**\n * Clamps a requested page size into the platform's accepted range.\n *\n * Non-finite and non-integer inputs fall back to {@link DEFAULT_PAGE_SIZE}\n * rather than being rounded, because a fractional `size` is a caller bug and\n * the platform would reject it.\n *\n * @param requested - The page size a caller asked for.\n * @returns An integer in `[1, MAX_PAGE_SIZE]`.\n * @example\n * clampPageSize(200); // 50\n * clampPageSize(0); // 1\n * clampPageSize(NaN); // 15\n */\nexport function clampPageSize(requested: number): number {\n if (!Number.isInteger(requested)) return DEFAULT_PAGE_SIZE;\n if (requested < 1) return 1;\n return Math.min(requested, MAX_PAGE_SIZE);\n}\n\n/**\n * Zod schema for the `pagination` object on offset-paginated `v0` responses.\n *\n * `size` is the number of items actually returned, not the requested page size\n * (styx builds it as `data.length`), and `hasMore` is the only reliable\n * end-of-list signal — the platform does not send a total on most routes.\n *\n * `size` therefore allows `0`: paging past the end returns `{ data: [], size: 0 }`,\n * which is a well-formed response and must not fail validation. The `1..50`\n * bound belongs to the *request* parameter — see {@link clampPageSize}.\n */\nexport const OffsetPaginationSchema = z.object({\n page: z.number().int().min(1),\n size: z.number().int().min(0),\n hasMore: z.boolean(),\n});\n\n/** The `pagination` object on an offset-paginated response. */\nexport type OffsetPagination = z.infer<typeof OffsetPaginationSchema>;\n\n/**\n * Zod schema for `GET /v0/subscribers`' hybrid pagination.\n *\n * Offset fields plus a keyset cursor that is `null` when the caller sorts by\n * name (that ordering cannot be resumed from a cursor).\n */\nexport const HybridPaginationSchema = OffsetPaginationSchema.extend({\n nextCursor: z.string().nullable(),\n});\n\n/** The `pagination` object on the hybrid `v0` subscribers response. */\nexport type HybridPagination = z.infer<typeof HybridPaginationSchema>;\n\n/**\n * Builds the response schema for an offset-paginated list of `item`.\n *\n * @param item - Schema for a single row of `data`.\n * @returns A schema for `{ data, pagination }`.\n * @example\n * const SubscribersPageSchema = offsetPageSchema(SubscriberSchema);\n * const page = SubscribersPageSchema.parse(body);\n * page.pagination.hasMore; // boolean\n */\nexport function offsetPageSchema<TItem extends z.ZodType>(\n item: TItem,\n): z.ZodObject<{ data: z.ZodArray<TItem>; pagination: typeof OffsetPaginationSchema }> {\n return z.object({\n data: z.array(item),\n pagination: OffsetPaginationSchema,\n });\n}\n\n/**\n * Builds the response schema for a cursor-paginated list of `item`.\n *\n * `nextCursor` is `null` on the last page. Cursors are opaque and pin the\n * sort, filters and creator they were minted for, so they cannot be replayed\n * against a different query.\n *\n * `total` is the third field of the platform's `v1` keyset envelope\n * (`{ data, nextCursor, total }`): the platform sends a number only where a\n * count is free or cheap, `null` on large keyset lists (the count is the\n * expensive query keyset avoids), and the older `v0` cursor routes omit the\n * key entirely. All three normalise to `total: null` or a number here, so a\n * caller never branches on \"absent vs null\".\n *\n * @param item - Schema for a single row of `data`.\n * @returns A schema for `{ data, nextCursor, total }`.\n * @example\n * const PaymentsPageSchema = cursorPageSchema(CheckoutPaymentSchema);\n * const page = PaymentsPageSchema.parse(body);\n * const done = page.nextCursor === null;\n */\nexport function cursorPageSchema<TItem extends z.ZodType>(\n item: TItem,\n): z.ZodObject<{\n data: z.ZodArray<TItem>;\n nextCursor: z.ZodNullable<z.ZodString>;\n total: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;\n}> {\n return z.object({\n data: z.array(item),\n nextCursor: z.string().nullable(),\n total: z.number().nullable().default(null),\n });\n}\n","let USER_AGENT;\nif (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {\n const NAME = 'oauth4webapi';\n const VERSION = 'v3.8.5';\n USER_AGENT = `${NAME}/${VERSION}`;\n}\nfunction looseInstanceOf(input, expected) {\n if (input == null) {\n return false;\n }\n try {\n return (input instanceof expected ||\n Object.getPrototypeOf(input)[Symbol.toStringTag] === expected.prototype[Symbol.toStringTag]);\n }\n catch {\n return false;\n }\n}\nconst ERR_INVALID_ARG_VALUE = 'ERR_INVALID_ARG_VALUE';\nconst ERR_INVALID_ARG_TYPE = 'ERR_INVALID_ARG_TYPE';\nfunction CodedTypeError(message, code, cause) {\n const err = new TypeError(message, { cause });\n Object.assign(err, { code });\n return err;\n}\nexport const allowInsecureRequests = Symbol();\nexport const clockSkew = Symbol();\nexport const clockTolerance = Symbol();\nexport const customFetch = Symbol();\nexport const modifyAssertion = Symbol();\nexport const jweDecrypt = Symbol();\nexport const jwksCache = Symbol();\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\nfunction buf(input) {\n if (typeof input === 'string') {\n return encoder.encode(input);\n }\n return decoder.decode(input);\n}\nlet encodeBase64Url;\nif (Uint8Array.prototype.toBase64) {\n encodeBase64Url = (input) => {\n if (input instanceof ArrayBuffer) {\n input = new Uint8Array(input);\n }\n return input.toBase64({ alphabet: 'base64url', omitPadding: true });\n };\n}\nelse {\n const CHUNK_SIZE = 0x8000;\n encodeBase64Url = (input) => {\n if (input instanceof ArrayBuffer) {\n input = new Uint8Array(input);\n }\n const arr = [];\n for (let i = 0; i < input.byteLength; i += CHUNK_SIZE) {\n arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));\n }\n return btoa(arr.join('')).replace(/=/g, '').replace(/\\+/g, '-').replace(/\\//g, '_');\n };\n}\nlet decodeBase64Url;\nif (Uint8Array.fromBase64) {\n decodeBase64Url = (input) => {\n try {\n return Uint8Array.fromBase64(input, { alphabet: 'base64url' });\n }\n catch (cause) {\n throw CodedTypeError('The input to be decoded is not correctly encoded.', ERR_INVALID_ARG_VALUE, cause);\n }\n };\n}\nelse {\n decodeBase64Url = (input) => {\n try {\n const binary = atob(input.replace(/-/g, '+').replace(/_/g, '/').replace(/\\s/g, ''));\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n }\n catch (cause) {\n throw CodedTypeError('The input to be decoded is not correctly encoded.', ERR_INVALID_ARG_VALUE, cause);\n }\n };\n}\nfunction b64u(input) {\n if (typeof input === 'string') {\n return decodeBase64Url(input);\n }\n return encodeBase64Url(input);\n}\nexport class UnsupportedOperationError extends Error {\n code;\n constructor(message, options) {\n super(message, options);\n this.name = this.constructor.name;\n this.code = UNSUPPORTED_OPERATION;\n Error.captureStackTrace?.(this, this.constructor);\n }\n}\nexport class OperationProcessingError extends Error {\n code;\n constructor(message, options) {\n super(message, options);\n this.name = this.constructor.name;\n if (options?.code) {\n this.code = options?.code;\n }\n Error.captureStackTrace?.(this, this.constructor);\n }\n}\nfunction OPE(message, code, cause) {\n return new OperationProcessingError(message, { code, cause });\n}\nasync function calculateJwkThumbprint(jwk) {\n let components;\n switch (jwk.kty) {\n case 'EC':\n components = {\n crv: jwk.crv,\n kty: jwk.kty,\n x: jwk.x,\n y: jwk.y,\n };\n break;\n case 'OKP':\n components = {\n crv: jwk.crv,\n kty: jwk.kty,\n x: jwk.x,\n };\n break;\n case 'AKP':\n components = {\n alg: jwk.alg,\n kty: jwk.kty,\n pub: jwk.pub,\n };\n break;\n case 'RSA':\n components = {\n e: jwk.e,\n kty: jwk.kty,\n n: jwk.n,\n };\n break;\n default:\n throw new UnsupportedOperationError('unsupported JWK key type', { cause: jwk });\n }\n return b64u(await crypto.subtle.digest('SHA-256', buf(JSON.stringify(components))));\n}\nfunction assertCryptoKey(key, it) {\n if (!(key instanceof CryptoKey)) {\n throw CodedTypeError(`${it} must be a CryptoKey`, ERR_INVALID_ARG_TYPE);\n }\n}\nfunction assertPrivateKey(key, it) {\n assertCryptoKey(key, it);\n if (key.type !== 'private') {\n throw CodedTypeError(`${it} must be a private CryptoKey`, ERR_INVALID_ARG_VALUE);\n }\n}\nfunction assertPublicKey(key, it) {\n assertCryptoKey(key, it);\n if (key.type !== 'public') {\n throw CodedTypeError(`${it} must be a public CryptoKey`, ERR_INVALID_ARG_VALUE);\n }\n}\nfunction normalizeTyp(value) {\n return value.toLowerCase().replace(/^application\\//, '');\n}\nfunction isJsonObject(input) {\n if (input === null || typeof input !== 'object' || Array.isArray(input)) {\n return false;\n }\n return true;\n}\nfunction prepareHeaders(input) {\n if (looseInstanceOf(input, Headers)) {\n input = Object.fromEntries(input.entries());\n }\n const headers = new Headers(input ?? {});\n if (USER_AGENT && !headers.has('user-agent')) {\n headers.set('user-agent', USER_AGENT);\n }\n if (headers.has('authorization')) {\n throw CodedTypeError('\"options.headers\" must not include the \"authorization\" header name', ERR_INVALID_ARG_VALUE);\n }\n return headers;\n}\nfunction signal(url, value) {\n if (value !== undefined) {\n if (typeof value === 'function') {\n value = value(url.href);\n }\n if (!(value instanceof AbortSignal)) {\n throw CodedTypeError('\"options.signal\" must return or be an instance of AbortSignal', ERR_INVALID_ARG_TYPE);\n }\n return value;\n }\n return undefined;\n}\nfunction replaceDoubleSlash(pathname) {\n if (pathname.includes('//')) {\n return pathname.replace('//', '/');\n }\n return pathname;\n}\nfunction prependWellKnown(url, wellKnown, allowTerminatingSlash = false) {\n if (url.pathname === '/') {\n url.pathname = wellKnown;\n }\n else {\n url.pathname = replaceDoubleSlash(`${wellKnown}/${allowTerminatingSlash ? url.pathname : url.pathname.replace(/(\\/)$/, '')}`);\n }\n return url;\n}\nfunction appendWellKnown(url, wellKnown) {\n url.pathname = replaceDoubleSlash(`${url.pathname}/${wellKnown}`);\n return url;\n}\nasync function performDiscovery(input, urlName, transform, options) {\n if (!(input instanceof URL)) {\n throw CodedTypeError(`\"${urlName}\" must be an instance of URL`, ERR_INVALID_ARG_TYPE);\n }\n checkProtocol(input, options?.[allowInsecureRequests] !== true);\n const url = transform(new URL(input.href));\n const headers = prepareHeaders(options?.headers);\n headers.set('accept', 'application/json');\n return (options?.[customFetch] || fetch)(url.href, {\n body: undefined,\n headers: Object.fromEntries(headers.entries()),\n method: 'GET',\n redirect: 'manual',\n signal: signal(url, options?.signal),\n });\n}\nexport async function discoveryRequest(issuerIdentifier, options) {\n return performDiscovery(issuerIdentifier, 'issuerIdentifier', (url) => {\n switch (options?.algorithm) {\n case undefined:\n case 'oidc':\n appendWellKnown(url, '.well-known/openid-configuration');\n break;\n case 'oauth2':\n prependWellKnown(url, '.well-known/oauth-authorization-server');\n break;\n default:\n throw CodedTypeError('\"options.algorithm\" must be \"oidc\" (default), or \"oauth2\"', ERR_INVALID_ARG_VALUE);\n }\n return url;\n }, options);\n}\nfunction assertNumber(input, allow0, it, code, cause) {\n try {\n if (typeof input !== 'number' || !Number.isFinite(input)) {\n throw CodedTypeError(`${it} must be a number`, ERR_INVALID_ARG_TYPE, cause);\n }\n if (input > 0)\n return;\n if (allow0) {\n if (input !== 0) {\n throw CodedTypeError(`${it} must be a non-negative number`, ERR_INVALID_ARG_VALUE, cause);\n }\n return;\n }\n throw CodedTypeError(`${it} must be a positive number`, ERR_INVALID_ARG_VALUE, cause);\n }\n catch (err) {\n if (code) {\n throw OPE(err.message, code, cause);\n }\n throw err;\n }\n}\nfunction assertString(input, it, code, cause) {\n try {\n if (typeof input !== 'string') {\n throw CodedTypeError(`${it} must be a string`, ERR_INVALID_ARG_TYPE, cause);\n }\n if (input.length === 0) {\n throw CodedTypeError(`${it} must not be empty`, ERR_INVALID_ARG_VALUE, cause);\n }\n }\n catch (err) {\n if (code) {\n throw OPE(err.message, code, cause);\n }\n throw err;\n }\n}\nexport async function processDiscoveryResponse(expectedIssuerIdentifier, response) {\n const expected = expectedIssuerIdentifier;\n if (!(expected instanceof URL) && expected !== _nodiscoverycheck) {\n throw CodedTypeError('\"expectedIssuerIdentifier\" must be an instance of URL', ERR_INVALID_ARG_TYPE);\n }\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n if (response.status !== 200) {\n throw OPE('\"response\" is not a conform Authorization Server Metadata response (unexpected HTTP status code)', RESPONSE_IS_NOT_CONFORM, response);\n }\n assertReadableResponse(response);\n const json = await getResponseJsonBody(response);\n assertString(json.issuer, '\"response\" body \"issuer\" property', INVALID_RESPONSE, { body: json });\n if (expected !== _nodiscoverycheck && new URL(json.issuer).href !== expected.href) {\n throw OPE('\"response\" body \"issuer\" property does not match the expected value', JSON_ATTRIBUTE_COMPARISON, { expected: expected.href, body: json, attribute: 'issuer' });\n }\n return json;\n}\nfunction assertApplicationJson(response) {\n assertContentType(response, 'application/json');\n}\nfunction notJson(response, ...types) {\n let msg = '\"response\" content-type must be ';\n if (types.length > 2) {\n const last = types.pop();\n msg += `${types.join(', ')}, or ${last}`;\n }\n else if (types.length === 2) {\n msg += `${types[0]} or ${types[1]}`;\n }\n else {\n msg += types[0];\n }\n return OPE(msg, RESPONSE_IS_NOT_JSON, response);\n}\nfunction assertContentTypes(response, ...types) {\n if (!types.includes(getContentType(response))) {\n throw notJson(response, ...types);\n }\n}\nfunction assertContentType(response, contentType) {\n if (getContentType(response) !== contentType) {\n throw notJson(response, contentType);\n }\n}\nfunction randomBytes() {\n return b64u(crypto.getRandomValues(new Uint8Array(32)));\n}\nexport function generateRandomCodeVerifier() {\n return randomBytes();\n}\nexport function generateRandomState() {\n return randomBytes();\n}\nexport function generateRandomNonce() {\n return randomBytes();\n}\nexport async function calculatePKCECodeChallenge(codeVerifier) {\n assertString(codeVerifier, 'codeVerifier');\n return b64u(await crypto.subtle.digest('SHA-256', buf(codeVerifier)));\n}\nfunction getKeyAndKid(input) {\n if (input instanceof CryptoKey) {\n return { key: input };\n }\n if (!(input?.key instanceof CryptoKey)) {\n return {};\n }\n if (input.kid !== undefined) {\n assertString(input.kid, '\"kid\"');\n }\n return {\n key: input.key,\n kid: input.kid,\n };\n}\nfunction psAlg(key) {\n switch (key.algorithm.hash.name) {\n case 'SHA-256':\n return 'PS256';\n case 'SHA-384':\n return 'PS384';\n case 'SHA-512':\n return 'PS512';\n default:\n throw new UnsupportedOperationError('unsupported RsaHashedKeyAlgorithm hash name', {\n cause: key,\n });\n }\n}\nfunction rsAlg(key) {\n switch (key.algorithm.hash.name) {\n case 'SHA-256':\n return 'RS256';\n case 'SHA-384':\n return 'RS384';\n case 'SHA-512':\n return 'RS512';\n default:\n throw new UnsupportedOperationError('unsupported RsaHashedKeyAlgorithm hash name', {\n cause: key,\n });\n }\n}\nfunction esAlg(key) {\n switch (key.algorithm.namedCurve) {\n case 'P-256':\n return 'ES256';\n case 'P-384':\n return 'ES384';\n case 'P-521':\n return 'ES512';\n default:\n throw new UnsupportedOperationError('unsupported EcKeyAlgorithm namedCurve', { cause: key });\n }\n}\nfunction keyToJws(key) {\n switch (key.algorithm.name) {\n case 'RSA-PSS':\n return psAlg(key);\n case 'RSASSA-PKCS1-v1_5':\n return rsAlg(key);\n case 'ECDSA':\n return esAlg(key);\n case 'Ed25519':\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87':\n return key.algorithm.name;\n case 'EdDSA':\n return 'Ed25519';\n default:\n throw new UnsupportedOperationError('unsupported CryptoKey algorithm name', { cause: key });\n }\n}\nfunction getClockSkew(client) {\n const skew = client?.[clockSkew];\n return typeof skew === 'number' && Number.isFinite(skew) ? skew : 0;\n}\nfunction getClockTolerance(client) {\n const tolerance = client?.[clockTolerance];\n return typeof tolerance === 'number' && Number.isFinite(tolerance) && Math.sign(tolerance) !== -1\n ? tolerance\n : 30;\n}\nfunction epochTime() {\n return Math.floor(Date.now() / 1000);\n}\nfunction assertAs(as) {\n if (typeof as !== 'object' || as === null) {\n throw CodedTypeError('\"as\" must be an object', ERR_INVALID_ARG_TYPE);\n }\n assertString(as.issuer, '\"as.issuer\"');\n}\nfunction assertClient(client) {\n if (typeof client !== 'object' || client === null) {\n throw CodedTypeError('\"client\" must be an object', ERR_INVALID_ARG_TYPE);\n }\n assertString(client.client_id, '\"client.client_id\"');\n}\nfunction formUrlEncode(token) {\n return encodeURIComponent(token).replace(/(?:[-_.!~*'()]|%20)/g, (substring) => {\n switch (substring) {\n case '-':\n case '_':\n case '.':\n case '!':\n case '~':\n case '*':\n case \"'\":\n case '(':\n case ')':\n return `%${substring.charCodeAt(0).toString(16).toUpperCase()}`;\n case '%20':\n return '+';\n default:\n throw new Error();\n }\n });\n}\nexport function ClientSecretPost(clientSecret) {\n assertString(clientSecret, '\"clientSecret\"');\n return (_as, client, body, _headers) => {\n body.set('client_id', client.client_id);\n body.set('client_secret', clientSecret);\n };\n}\nexport function ClientSecretBasic(clientSecret) {\n assertString(clientSecret, '\"clientSecret\"');\n return (_as, client, _body, headers) => {\n const username = formUrlEncode(client.client_id);\n const password = formUrlEncode(clientSecret);\n const credentials = btoa(`${username}:${password}`);\n headers.set('authorization', `Basic ${credentials}`);\n };\n}\nfunction clientAssertionPayload(as, client) {\n const now = epochTime() + getClockSkew(client);\n return {\n jti: randomBytes(),\n aud: as.issuer,\n exp: now + 60,\n iat: now,\n nbf: now,\n iss: client.client_id,\n sub: client.client_id,\n };\n}\nexport function PrivateKeyJwt(clientPrivateKey, options) {\n const { key, kid } = getKeyAndKid(clientPrivateKey);\n assertPrivateKey(key, '\"clientPrivateKey.key\"');\n return async (as, client, body, _headers) => {\n const header = { alg: keyToJws(key), kid };\n const payload = clientAssertionPayload(as, client);\n options?.[modifyAssertion]?.(header, payload);\n body.set('client_id', client.client_id);\n body.set('client_assertion_type', 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer');\n body.set('client_assertion', await signJwt(header, payload, key));\n };\n}\nexport function ClientSecretJwt(clientSecret, options) {\n assertString(clientSecret, '\"clientSecret\"');\n const modify = options?.[modifyAssertion];\n let key;\n return async (as, client, body, _headers) => {\n key ||= await crypto.subtle.importKey('raw', buf(clientSecret), { hash: 'SHA-256', name: 'HMAC' }, false, ['sign']);\n const header = { alg: 'HS256' };\n const payload = clientAssertionPayload(as, client);\n modify?.(header, payload);\n const data = `${b64u(buf(JSON.stringify(header)))}.${b64u(buf(JSON.stringify(payload)))}`;\n const hmac = await crypto.subtle.sign(key.algorithm, key, buf(data));\n body.set('client_id', client.client_id);\n body.set('client_assertion_type', 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer');\n body.set('client_assertion', `${data}.${b64u(new Uint8Array(hmac))}`);\n };\n}\nexport function None() {\n return (_as, client, body, _headers) => {\n body.set('client_id', client.client_id);\n };\n}\nexport function TlsClientAuth() {\n return None();\n}\nasync function signJwt(header, payload, key) {\n if (!key.usages.includes('sign')) {\n throw CodedTypeError('CryptoKey instances used for signing assertions must include \"sign\" in their \"usages\"', ERR_INVALID_ARG_VALUE);\n }\n const input = `${b64u(buf(JSON.stringify(header)))}.${b64u(buf(JSON.stringify(payload)))}`;\n const signature = b64u(await crypto.subtle.sign(keyToSubtle(key), key, buf(input)));\n return `${input}.${signature}`;\n}\nexport async function issueRequestObject(as, client, parameters, privateKey, options) {\n assertAs(as);\n assertClient(client);\n parameters = new URLSearchParams(parameters);\n const { key, kid } = getKeyAndKid(privateKey);\n assertPrivateKey(key, '\"privateKey.key\"');\n parameters.set('client_id', client.client_id);\n const now = epochTime() + getClockSkew(client);\n const claims = {\n ...Object.fromEntries(parameters.entries()),\n jti: randomBytes(),\n aud: as.issuer,\n exp: now + 60,\n iat: now,\n nbf: now,\n iss: client.client_id,\n };\n let resource;\n if (parameters.has('resource') &&\n (resource = parameters.getAll('resource')) &&\n resource.length > 1) {\n claims.resource = resource;\n }\n {\n let value = parameters.get('max_age');\n if (value !== null) {\n claims.max_age = parseInt(value, 10);\n assertNumber(claims.max_age, true, '\"max_age\" parameter');\n }\n }\n {\n let value = parameters.get('claims');\n if (value !== null) {\n try {\n claims.claims = JSON.parse(value);\n }\n catch (cause) {\n throw OPE('failed to parse the \"claims\" parameter as JSON', PARSE_ERROR, cause);\n }\n if (!isJsonObject(claims.claims)) {\n throw CodedTypeError('\"claims\" parameter must be a JSON with a top level object', ERR_INVALID_ARG_VALUE);\n }\n }\n }\n {\n let value = parameters.get('authorization_details');\n if (value !== null) {\n try {\n claims.authorization_details = JSON.parse(value);\n }\n catch (cause) {\n throw OPE('failed to parse the \"authorization_details\" parameter as JSON', PARSE_ERROR, cause);\n }\n if (!Array.isArray(claims.authorization_details)) {\n throw CodedTypeError('\"authorization_details\" parameter must be a JSON with a top level array', ERR_INVALID_ARG_VALUE);\n }\n }\n }\n const header = {\n alg: keyToJws(key),\n typ: 'oauth-authz-req+jwt',\n kid,\n };\n options?.[modifyAssertion]?.(header, claims);\n return signJwt(header, claims, key);\n}\nlet jwkCache;\nasync function getSetPublicJwkCache(key, alg) {\n const { kty, e, n, x, y, crv, pub } = await crypto.subtle.exportKey('jwk', key);\n const jwk = { kty, e, n, x, y, crv, pub };\n if (kty === 'AKP')\n jwk.alg = alg;\n jwkCache.set(key, jwk);\n return jwk;\n}\nasync function publicJwk(key, alg) {\n jwkCache ||= new WeakMap();\n return jwkCache.get(key) || getSetPublicJwkCache(key, alg);\n}\nconst URLParse = URL.parse\n ?\n (url, base) => URL.parse(url, base)\n : (url, base) => {\n try {\n return new URL(url, base);\n }\n catch {\n return null;\n }\n };\nexport function checkProtocol(url, enforceHttps) {\n if (enforceHttps && url.protocol !== 'https:') {\n throw OPE('only requests to HTTPS are allowed', HTTP_REQUEST_FORBIDDEN, url);\n }\n if (url.protocol !== 'https:' && url.protocol !== 'http:') {\n throw OPE('only HTTP and HTTPS requests are allowed', REQUEST_PROTOCOL_FORBIDDEN, url);\n }\n}\nfunction validateEndpoint(value, endpoint, useMtlsAlias, enforceHttps) {\n let url;\n if (typeof value !== 'string' || !(url = URLParse(value))) {\n throw OPE(`authorization server metadata does not contain a valid ${useMtlsAlias ? `\"as.mtls_endpoint_aliases.${endpoint}\"` : `\"as.${endpoint}\"`}`, value === undefined ? MISSING_SERVER_METADATA : INVALID_SERVER_METADATA, { attribute: useMtlsAlias ? `mtls_endpoint_aliases.${endpoint}` : endpoint });\n }\n checkProtocol(url, enforceHttps);\n return url;\n}\nexport function resolveEndpoint(as, endpoint, useMtlsAlias, enforceHttps) {\n if (useMtlsAlias && as.mtls_endpoint_aliases && endpoint in as.mtls_endpoint_aliases) {\n return validateEndpoint(as.mtls_endpoint_aliases[endpoint], endpoint, useMtlsAlias, enforceHttps);\n }\n return validateEndpoint(as[endpoint], endpoint, useMtlsAlias, enforceHttps);\n}\nexport async function pushedAuthorizationRequest(as, client, clientAuthentication, parameters, options) {\n assertAs(as);\n assertClient(client);\n const url = resolveEndpoint(as, 'pushed_authorization_request_endpoint', client.use_mtls_endpoint_aliases, options?.[allowInsecureRequests] !== true);\n const body = new URLSearchParams(parameters);\n body.set('client_id', client.client_id);\n const headers = prepareHeaders(options?.headers);\n headers.set('accept', 'application/json');\n if (options?.DPoP !== undefined) {\n assertDPoP(options.DPoP);\n await options.DPoP.addProof(url, headers, 'POST');\n }\n const response = await authenticatedRequest(as, client, clientAuthentication, url, body, headers, options);\n options?.DPoP?.cacheNonce(response, url);\n return response;\n}\nclass DPoPHandler {\n #header;\n #privateKey;\n #publicKey;\n #clockSkew;\n #modifyAssertion;\n #map;\n #jkt;\n constructor(client, keyPair, options) {\n assertPrivateKey(keyPair?.privateKey, '\"DPoP.privateKey\"');\n assertPublicKey(keyPair?.publicKey, '\"DPoP.publicKey\"');\n if (!keyPair.publicKey.extractable) {\n throw CodedTypeError('\"DPoP.publicKey.extractable\" must be true', ERR_INVALID_ARG_VALUE);\n }\n this.#modifyAssertion = options?.[modifyAssertion];\n this.#clockSkew = getClockSkew(client);\n this.#privateKey = keyPair.privateKey;\n this.#publicKey = keyPair.publicKey;\n branded.add(this);\n }\n #get(key) {\n this.#map ||= new Map();\n let item = this.#map.get(key);\n if (item) {\n this.#map.delete(key);\n this.#map.set(key, item);\n }\n return item;\n }\n #set(key, val) {\n this.#map ||= new Map();\n this.#map.delete(key);\n if (this.#map.size === 100) {\n this.#map.delete(this.#map.keys().next().value);\n }\n this.#map.set(key, val);\n }\n async calculateThumbprint() {\n if (!this.#jkt) {\n const jwk = await crypto.subtle.exportKey('jwk', this.#publicKey);\n this.#jkt ||= await calculateJwkThumbprint(jwk);\n }\n return this.#jkt;\n }\n async addProof(url, headers, htm, accessToken) {\n const alg = keyToJws(this.#privateKey);\n this.#header ||= {\n alg,\n typ: 'dpop+jwt',\n jwk: await publicJwk(this.#publicKey, alg),\n };\n const nonce = this.#get(url.origin);\n const now = epochTime() + this.#clockSkew;\n const payload = {\n iat: now,\n jti: randomBytes(),\n htm,\n nonce,\n htu: `${url.origin}${url.pathname}`,\n ath: accessToken\n ? b64u(await crypto.subtle.digest('SHA-256', buf(accessToken)))\n : undefined,\n };\n this.#modifyAssertion?.(this.#header, payload);\n headers.set('dpop', await signJwt(this.#header, payload, this.#privateKey));\n }\n cacheNonce(response, url) {\n try {\n const nonce = response.headers.get('dpop-nonce');\n if (nonce) {\n this.#set(url.origin, nonce);\n }\n }\n catch { }\n }\n}\nexport function isDPoPNonceError(err) {\n if (err instanceof WWWAuthenticateChallengeError) {\n const { 0: challenge, length } = err.cause;\n return (length === 1 && challenge.scheme === 'dpop' && challenge.parameters.error === 'use_dpop_nonce');\n }\n if (err instanceof ResponseBodyError) {\n return err.error === 'use_dpop_nonce';\n }\n return false;\n}\nexport function DPoP(client, keyPair, options) {\n return new DPoPHandler(client, keyPair, options);\n}\nexport class ResponseBodyError extends Error {\n cause;\n code;\n error;\n status;\n error_description;\n response;\n constructor(message, options) {\n super(message, options);\n this.name = this.constructor.name;\n this.code = RESPONSE_BODY_ERROR;\n this.cause = options.cause;\n this.error = options.cause.error;\n this.status = options.response.status;\n this.error_description = options.cause.error_description;\n Object.defineProperty(this, 'response', { enumerable: false, value: options.response });\n Error.captureStackTrace?.(this, this.constructor);\n }\n}\nexport class AuthorizationResponseError extends Error {\n cause;\n code;\n error;\n error_description;\n constructor(message, options) {\n super(message, options);\n this.name = this.constructor.name;\n this.code = AUTHORIZATION_RESPONSE_ERROR;\n this.cause = options.cause;\n this.error = options.cause.get('error');\n this.error_description = options.cause.get('error_description') ?? undefined;\n Error.captureStackTrace?.(this, this.constructor);\n }\n}\nexport class WWWAuthenticateChallengeError extends Error {\n cause;\n code;\n response;\n status;\n constructor(message, options) {\n super(message, options);\n this.name = this.constructor.name;\n this.code = WWW_AUTHENTICATE_CHALLENGE;\n this.cause = options.cause;\n this.status = options.response.status;\n this.response = options.response;\n Object.defineProperty(this, 'response', { enumerable: false });\n Error.captureStackTrace?.(this, this.constructor);\n }\n}\nconst tokenMatch = \"[a-zA-Z0-9!#$%&\\\\'\\\\*\\\\+\\\\-\\\\.\\\\^_`\\\\|~]+\";\nconst token68Match = '[a-zA-Z0-9\\\\-\\\\._\\\\~\\\\+\\\\/]+={0,2}';\nconst quotedMatch = '\"((?:[^\"\\\\\\\\]|\\\\\\\\[\\\\s\\\\S])*)\"';\nconst quotedParamMatcher = '(' + tokenMatch + ')\\\\s*=\\\\s*' + quotedMatch;\nconst paramMatcher = '(' + tokenMatch + ')\\\\s*=\\\\s*(' + tokenMatch + ')';\nconst schemeRE = new RegExp('^[,\\\\s]*(' + tokenMatch + ')');\nconst quotedParamRE = new RegExp('^[,\\\\s]*' + quotedParamMatcher + '[,\\\\s]*(.*)');\nconst unquotedParamRE = new RegExp('^[,\\\\s]*' + paramMatcher + '[,\\\\s]*(.*)');\nconst token68ParamRE = new RegExp('^(' + token68Match + ')(?:$|[,\\\\s])(.*)');\nfunction parseWwwAuthenticateChallenges(response) {\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n const header = response.headers.get('www-authenticate');\n if (header === null) {\n return undefined;\n }\n const challenges = [];\n let rest = header;\n while (rest) {\n let match = rest.match(schemeRE);\n const scheme = match?.['1'].toLowerCase();\n if (!scheme) {\n return undefined;\n }\n const afterScheme = rest.substring(match[0].length);\n if (afterScheme && !afterScheme.match(/^[\\s,]/)) {\n return undefined;\n }\n const spaceMatch = afterScheme.match(/^\\s+(.*)$/);\n const hasParameters = !!spaceMatch;\n rest = spaceMatch ? spaceMatch[1] : undefined;\n const parameters = {};\n let token68;\n if (hasParameters) {\n while (rest) {\n let key;\n let value;\n if ((match = rest.match(quotedParamRE))) {\n ;\n [, key, value, rest] = match;\n if (value.includes('\\\\')) {\n try {\n value = JSON.parse(`\"${value}\"`);\n }\n catch { }\n }\n parameters[key.toLowerCase()] = value;\n continue;\n }\n if ((match = rest.match(unquotedParamRE))) {\n ;\n [, key, value, rest] = match;\n parameters[key.toLowerCase()] = value;\n continue;\n }\n if ((match = rest.match(token68ParamRE))) {\n if (Object.keys(parameters).length) {\n break;\n }\n ;\n [, token68, rest] = match;\n break;\n }\n return undefined;\n }\n }\n else {\n rest = afterScheme || undefined;\n }\n const challenge = { scheme, parameters };\n if (token68) {\n challenge.token68 = token68;\n }\n challenges.push(challenge);\n }\n if (!challenges.length) {\n return undefined;\n }\n return challenges;\n}\nexport async function processPushedAuthorizationResponse(as, client, response) {\n assertAs(as);\n assertClient(client);\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n await checkOAuthBodyError(response, 201, 'Pushed Authorization Request Endpoint');\n assertReadableResponse(response);\n const json = await getResponseJsonBody(response);\n assertString(json.request_uri, '\"response\" body \"request_uri\" property', INVALID_RESPONSE, {\n body: json,\n });\n let expiresIn = typeof json.expires_in !== 'number' ? parseFloat(json.expires_in) : json.expires_in;\n assertNumber(expiresIn, true, '\"response\" body \"expires_in\" property', INVALID_RESPONSE, {\n body: json,\n });\n json.expires_in = expiresIn;\n return json;\n}\nasync function parseOAuthResponseErrorBody(response) {\n if (response.status > 399 && response.status < 500) {\n assertReadableResponse(response);\n assertApplicationJson(response);\n try {\n const json = await response.clone().json();\n if (isJsonObject(json) && typeof json.error === 'string' && json.error.length) {\n return json;\n }\n }\n catch { }\n }\n return undefined;\n}\nasync function checkOAuthBodyError(response, expected, label) {\n if (response.status !== expected) {\n checkAuthenticationChallenges(response);\n let err;\n if ((err = await parseOAuthResponseErrorBody(response))) {\n await response.body?.cancel();\n throw new ResponseBodyError('server responded with an error in the response body', {\n cause: err,\n response,\n });\n }\n throw OPE(`\"response\" is not a conform ${label} response (unexpected HTTP status code)`, RESPONSE_IS_NOT_CONFORM, response);\n }\n}\nfunction assertDPoP(option) {\n if (!branded.has(option)) {\n throw CodedTypeError('\"options.DPoP\" is not a valid DPoPHandle', ERR_INVALID_ARG_VALUE);\n }\n}\nasync function resourceRequest(accessToken, method, url, headers, body, options) {\n assertString(accessToken, '\"accessToken\"');\n if (!(url instanceof URL)) {\n throw CodedTypeError('\"url\" must be an instance of URL', ERR_INVALID_ARG_TYPE);\n }\n checkProtocol(url, options?.[allowInsecureRequests] !== true);\n headers = prepareHeaders(headers);\n if (options?.DPoP) {\n assertDPoP(options.DPoP);\n await options.DPoP.addProof(url, headers, method.toUpperCase(), accessToken);\n }\n headers.set('authorization', `${headers.has('dpop') ? 'DPoP' : 'Bearer'} ${accessToken}`);\n const response = await (options?.[customFetch] || fetch)(url.href, {\n duplex: looseInstanceOf(body, ReadableStream) ? 'half' : undefined,\n body,\n headers: Object.fromEntries(headers.entries()),\n method,\n redirect: 'manual',\n signal: signal(url, options?.signal),\n });\n options?.DPoP?.cacheNonce(response, url);\n return response;\n}\nexport async function protectedResourceRequest(accessToken, method, url, headers, body, options) {\n const response = await resourceRequest(accessToken, method, url, headers, body, options);\n checkAuthenticationChallenges(response);\n return response;\n}\nexport async function userInfoRequest(as, client, accessToken, options) {\n assertAs(as);\n assertClient(client);\n const url = resolveEndpoint(as, 'userinfo_endpoint', client.use_mtls_endpoint_aliases, options?.[allowInsecureRequests] !== true);\n const headers = prepareHeaders(options?.headers);\n if (client.userinfo_signed_response_alg) {\n headers.set('accept', 'application/jwt');\n }\n else {\n headers.set('accept', 'application/json');\n headers.append('accept', 'application/jwt');\n }\n return resourceRequest(accessToken, 'GET', url, headers, null, {\n ...options,\n [clockSkew]: getClockSkew(client),\n });\n}\nlet jwksMap;\nfunction setJwksCache(as, jwks, uat, cache) {\n jwksMap ||= new WeakMap();\n jwksMap.set(as, {\n jwks,\n uat,\n get age() {\n return epochTime() - this.uat;\n },\n });\n if (cache) {\n Object.assign(cache, { jwks: structuredClone(jwks), uat });\n }\n}\nfunction isFreshJwksCache(input) {\n if (typeof input !== 'object' || input === null) {\n return false;\n }\n if (!('uat' in input) || typeof input.uat !== 'number' || epochTime() - input.uat >= 300) {\n return false;\n }\n if (!('jwks' in input) ||\n !isJsonObject(input.jwks) ||\n !Array.isArray(input.jwks.keys) ||\n !Array.prototype.every.call(input.jwks.keys, isJsonObject)) {\n return false;\n }\n return true;\n}\nfunction clearJwksCache(as, cache) {\n jwksMap?.delete(as);\n delete cache?.jwks;\n delete cache?.uat;\n}\nasync function getPublicSigKeyFromIssuerJwksUri(as, options, header) {\n const { alg, kid } = header;\n checkSupportedJwsAlg(header);\n if (!jwksMap?.has(as) && isFreshJwksCache(options?.[jwksCache])) {\n setJwksCache(as, options?.[jwksCache].jwks, options?.[jwksCache].uat);\n }\n let jwks;\n let age;\n if (jwksMap?.has(as)) {\n ;\n ({ jwks, age } = jwksMap.get(as));\n if (age >= 300) {\n clearJwksCache(as, options?.[jwksCache]);\n return getPublicSigKeyFromIssuerJwksUri(as, options, header);\n }\n }\n else {\n jwks = await jwksRequest(as, options).then(processJwksResponse);\n age = 0;\n setJwksCache(as, jwks, epochTime(), options?.[jwksCache]);\n }\n let kty;\n switch (alg.slice(0, 2)) {\n case 'RS':\n case 'PS':\n kty = 'RSA';\n break;\n case 'ES':\n kty = 'EC';\n break;\n case 'Ed':\n kty = 'OKP';\n break;\n case 'ML':\n kty = 'AKP';\n break;\n default:\n throw new UnsupportedOperationError('unsupported JWS algorithm', { cause: { alg } });\n }\n const candidates = jwks.keys.filter((jwk) => {\n if (jwk.kty !== kty) {\n return false;\n }\n if (kid !== undefined && kid !== jwk.kid) {\n return false;\n }\n if (jwk.alg !== undefined && alg !== jwk.alg) {\n return false;\n }\n if (jwk.use !== undefined && jwk.use !== 'sig') {\n return false;\n }\n if (jwk.key_ops?.includes('verify') === false) {\n return false;\n }\n switch (true) {\n case alg === 'ES256' && jwk.crv !== 'P-256':\n case alg === 'ES384' && jwk.crv !== 'P-384':\n case alg === 'ES512' && jwk.crv !== 'P-521':\n case alg === 'Ed25519' && jwk.crv !== 'Ed25519':\n case alg === 'EdDSA' && jwk.crv !== 'Ed25519':\n return false;\n }\n return true;\n });\n const { 0: jwk, length } = candidates;\n if (!length) {\n if (age >= 60) {\n clearJwksCache(as, options?.[jwksCache]);\n return getPublicSigKeyFromIssuerJwksUri(as, options, header);\n }\n throw OPE('error when selecting a JWT verification key, no applicable keys found', KEY_SELECTION, { header, candidates, jwks_uri: new URL(as.jwks_uri) });\n }\n if (length !== 1) {\n throw OPE('error when selecting a JWT verification key, multiple applicable keys found, a \"kid\" JWT Header Parameter is required', KEY_SELECTION, { header, candidates, jwks_uri: new URL(as.jwks_uri) });\n }\n return importJwk(alg, jwk);\n}\nexport const skipSubjectCheck = Symbol();\nexport function getContentType(input) {\n return input.headers.get('content-type')?.split(';')[0];\n}\nexport async function processUserInfoResponse(as, client, expectedSubject, response, options) {\n assertAs(as);\n assertClient(client);\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n checkAuthenticationChallenges(response);\n if (response.status !== 200) {\n throw OPE('\"response\" is not a conform UserInfo Endpoint response (unexpected HTTP status code)', RESPONSE_IS_NOT_CONFORM, response);\n }\n assertReadableResponse(response);\n let json;\n if (getContentType(response) === 'application/jwt') {\n const { claims, jwt } = await validateJwt(await response.text(), checkSigningAlgorithm.bind(undefined, client.userinfo_signed_response_alg, as.userinfo_signing_alg_values_supported, undefined), getClockSkew(client), getClockTolerance(client), options?.[jweDecrypt])\n .then(validateOptionalAudience.bind(undefined, client.client_id))\n .then(validateOptionalIssuer.bind(undefined, as));\n jwtRefs.set(response, jwt);\n json = claims;\n }\n else {\n if (client.userinfo_signed_response_alg) {\n throw OPE('JWT UserInfo Response expected', JWT_USERINFO_EXPECTED, response);\n }\n json = await getResponseJsonBody(response);\n }\n assertString(json.sub, '\"response\" body \"sub\" property', INVALID_RESPONSE, { body: json });\n switch (expectedSubject) {\n case skipSubjectCheck:\n break;\n default:\n assertString(expectedSubject, '\"expectedSubject\"');\n if (json.sub !== expectedSubject) {\n throw OPE('unexpected \"response\" body \"sub\" property value', JSON_ATTRIBUTE_COMPARISON, {\n expected: expectedSubject,\n body: json,\n attribute: 'sub',\n });\n }\n }\n return json;\n}\nasync function authenticatedRequest(as, client, clientAuthentication, url, body, headers, options) {\n await clientAuthentication(as, client, body, headers);\n headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');\n return (options?.[customFetch] || fetch)(url.href, {\n body,\n headers: Object.fromEntries(headers.entries()),\n method: 'POST',\n redirect: 'manual',\n signal: signal(url, options?.signal),\n });\n}\nasync function tokenEndpointRequest(as, client, clientAuthentication, grantType, parameters, options) {\n const url = resolveEndpoint(as, 'token_endpoint', client.use_mtls_endpoint_aliases, options?.[allowInsecureRequests] !== true);\n parameters.set('grant_type', grantType);\n const headers = prepareHeaders(options?.headers);\n headers.set('accept', 'application/json');\n if (options?.DPoP !== undefined) {\n assertDPoP(options.DPoP);\n await options.DPoP.addProof(url, headers, 'POST');\n }\n const response = await authenticatedRequest(as, client, clientAuthentication, url, parameters, headers, options);\n options?.DPoP?.cacheNonce(response, url);\n return response;\n}\nexport async function refreshTokenGrantRequest(as, client, clientAuthentication, refreshToken, options) {\n assertAs(as);\n assertClient(client);\n assertString(refreshToken, '\"refreshToken\"');\n const parameters = new URLSearchParams(options?.additionalParameters);\n parameters.set('refresh_token', refreshToken);\n return tokenEndpointRequest(as, client, clientAuthentication, 'refresh_token', parameters, options);\n}\nconst idTokenClaims = new WeakMap();\nconst jwtRefs = new WeakMap();\nexport function getValidatedIdTokenClaims(ref) {\n if (!ref.id_token) {\n return undefined;\n }\n const claims = idTokenClaims.get(ref);\n if (!claims) {\n throw CodedTypeError('\"ref\" was already garbage collected or did not resolve from the proper sources', ERR_INVALID_ARG_VALUE);\n }\n return claims;\n}\nexport async function validateApplicationLevelSignature(as, ref, options) {\n assertAs(as);\n if (!jwtRefs.has(ref)) {\n throw CodedTypeError('\"ref\" does not contain a processed JWT Response to verify the signature of', ERR_INVALID_ARG_VALUE);\n }\n const { 0: protectedHeader, 1: payload, 2: encodedSignature } = jwtRefs.get(ref).split('.');\n const header = JSON.parse(buf(b64u(protectedHeader)));\n if (header.alg.startsWith('HS')) {\n throw new UnsupportedOperationError('unsupported JWS algorithm', { cause: { alg: header.alg } });\n }\n let key;\n key = await getPublicSigKeyFromIssuerJwksUri(as, options, header);\n await validateJwsSignature(protectedHeader, payload, key, b64u(encodedSignature));\n}\nasync function processGenericAccessTokenResponse(as, client, response, additionalRequiredIdTokenClaims, decryptFn, recognizedTokenTypes) {\n assertAs(as);\n assertClient(client);\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n await checkOAuthBodyError(response, 200, 'Token Endpoint');\n assertReadableResponse(response);\n const json = await getResponseJsonBody(response);\n assertString(json.access_token, '\"response\" body \"access_token\" property', INVALID_RESPONSE, {\n body: json,\n });\n assertString(json.token_type, '\"response\" body \"token_type\" property', INVALID_RESPONSE, {\n body: json,\n });\n json.token_type = json.token_type.toLowerCase();\n if (json.expires_in !== undefined) {\n let expiresIn = typeof json.expires_in !== 'number' ? parseFloat(json.expires_in) : json.expires_in;\n assertNumber(expiresIn, true, '\"response\" body \"expires_in\" property', INVALID_RESPONSE, {\n body: json,\n });\n json.expires_in = expiresIn;\n }\n if (json.refresh_token !== undefined) {\n assertString(json.refresh_token, '\"response\" body \"refresh_token\" property', INVALID_RESPONSE, {\n body: json,\n });\n }\n if (json.scope !== undefined && typeof json.scope !== 'string') {\n throw OPE('\"response\" body \"scope\" property must be a string', INVALID_RESPONSE, { body: json });\n }\n if (json.id_token !== undefined) {\n assertString(json.id_token, '\"response\" body \"id_token\" property', INVALID_RESPONSE, {\n body: json,\n });\n const requiredClaims = ['aud', 'exp', 'iat', 'iss', 'sub'];\n if (client.require_auth_time === true) {\n requiredClaims.push('auth_time');\n }\n if (client.default_max_age !== undefined) {\n assertNumber(client.default_max_age, true, '\"client.default_max_age\"');\n requiredClaims.push('auth_time');\n }\n if (additionalRequiredIdTokenClaims?.length) {\n requiredClaims.push(...additionalRequiredIdTokenClaims);\n }\n const { claims, jwt } = await validateJwt(json.id_token, checkSigningAlgorithm.bind(undefined, client.id_token_signed_response_alg, as.id_token_signing_alg_values_supported, 'RS256'), getClockSkew(client), getClockTolerance(client), decryptFn)\n .then(validatePresence.bind(undefined, requiredClaims))\n .then(validateIssuer.bind(undefined, as))\n .then(validateAudience.bind(undefined, client.client_id));\n if (Array.isArray(claims.aud) && claims.aud.length !== 1) {\n if (claims.azp === undefined) {\n throw OPE('ID Token \"aud\" (audience) claim includes additional untrusted audiences', JWT_CLAIM_COMPARISON, { claims, claim: 'aud' });\n }\n if (claims.azp !== client.client_id) {\n throw OPE('unexpected ID Token \"azp\" (authorized party) claim value', JWT_CLAIM_COMPARISON, { expected: client.client_id, claims, claim: 'azp' });\n }\n }\n if (claims.auth_time !== undefined) {\n assertNumber(claims.auth_time, true, 'ID Token \"auth_time\" (authentication time)', INVALID_RESPONSE, { claims });\n }\n jwtRefs.set(response, jwt);\n idTokenClaims.set(json, claims);\n }\n if (recognizedTokenTypes?.[json.token_type] !== undefined) {\n recognizedTokenTypes[json.token_type](response, json);\n }\n else if (json.token_type !== 'dpop' && json.token_type !== 'bearer') {\n throw new UnsupportedOperationError('unsupported `token_type` value', { cause: { body: json } });\n }\n return json;\n}\nfunction checkAuthenticationChallenges(response) {\n let challenges;\n if ((challenges = parseWwwAuthenticateChallenges(response))) {\n throw new WWWAuthenticateChallengeError('server responded with a challenge in the WWW-Authenticate HTTP Header', { cause: challenges, response });\n }\n}\nexport async function processRefreshTokenResponse(as, client, response, options) {\n return processGenericAccessTokenResponse(as, client, response, undefined, options?.[jweDecrypt], options?.recognizedTokenTypes);\n}\nfunction validateOptionalAudience(expected, result) {\n if (result.claims.aud !== undefined) {\n return validateAudience(expected, result);\n }\n return result;\n}\nfunction validateAudience(expected, result) {\n if (Array.isArray(result.claims.aud)) {\n if (!result.claims.aud.includes(expected)) {\n throw OPE('unexpected JWT \"aud\" (audience) claim value', JWT_CLAIM_COMPARISON, {\n expected,\n claims: result.claims,\n claim: 'aud',\n });\n }\n }\n else if (result.claims.aud !== expected) {\n throw OPE('unexpected JWT \"aud\" (audience) claim value', JWT_CLAIM_COMPARISON, {\n expected,\n claims: result.claims,\n claim: 'aud',\n });\n }\n return result;\n}\nfunction validateOptionalIssuer(as, result) {\n if (result.claims.iss !== undefined) {\n return validateIssuer(as, result);\n }\n return result;\n}\nfunction validateIssuer(as, result) {\n const expected = as[_expectedIssuer]?.(result) ?? as.issuer;\n if (result.claims.iss !== expected) {\n throw OPE('unexpected JWT \"iss\" (issuer) claim value', JWT_CLAIM_COMPARISON, {\n expected,\n claims: result.claims,\n claim: 'iss',\n });\n }\n return result;\n}\nconst branded = new WeakSet();\nfunction brand(searchParams) {\n branded.add(searchParams);\n return searchParams;\n}\nexport const nopkce = Symbol();\nexport async function authorizationCodeGrantRequest(as, client, clientAuthentication, callbackParameters, redirectUri, codeVerifier, options) {\n assertAs(as);\n assertClient(client);\n if (!branded.has(callbackParameters)) {\n throw CodedTypeError('\"callbackParameters\" must be an instance of URLSearchParams obtained from \"validateAuthResponse()\", or \"validateJwtAuthResponse()', ERR_INVALID_ARG_VALUE);\n }\n assertString(redirectUri, '\"redirectUri\"');\n const code = getURLSearchParameter(callbackParameters, 'code');\n if (!code) {\n throw OPE('no authorization code in \"callbackParameters\"', INVALID_RESPONSE);\n }\n const parameters = new URLSearchParams(options?.additionalParameters);\n parameters.set('redirect_uri', redirectUri);\n parameters.set('code', code);\n if (codeVerifier !== nopkce) {\n assertString(codeVerifier, '\"codeVerifier\"');\n parameters.set('code_verifier', codeVerifier);\n }\n return tokenEndpointRequest(as, client, clientAuthentication, 'authorization_code', parameters, options);\n}\nconst jwtClaimNames = {\n aud: 'audience',\n c_hash: 'code hash',\n client_id: 'client id',\n exp: 'expiration time',\n iat: 'issued at',\n iss: 'issuer',\n jti: 'jwt id',\n nonce: 'nonce',\n s_hash: 'state hash',\n sub: 'subject',\n ath: 'access token hash',\n htm: 'http method',\n htu: 'http uri',\n cnf: 'confirmation',\n auth_time: 'authentication time',\n};\nfunction validatePresence(required, result) {\n for (const claim of required) {\n if (result.claims[claim] === undefined) {\n throw OPE(`JWT \"${claim}\" (${jwtClaimNames[claim]}) claim missing`, INVALID_RESPONSE, {\n claims: result.claims,\n });\n }\n }\n return result;\n}\nexport const expectNoNonce = Symbol();\nexport const skipAuthTimeCheck = Symbol();\nexport async function processAuthorizationCodeResponse(as, client, response, options) {\n if (typeof options?.expectedNonce === 'string' ||\n typeof options?.maxAge === 'number' ||\n options?.requireIdToken) {\n return processAuthorizationCodeOpenIDResponse(as, client, response, options.expectedNonce, options.maxAge, options[jweDecrypt], options.recognizedTokenTypes);\n }\n return processAuthorizationCodeOAuth2Response(as, client, response, options?.[jweDecrypt], options?.recognizedTokenTypes);\n}\nasync function processAuthorizationCodeOpenIDResponse(as, client, response, expectedNonce, maxAge, decryptFn, recognizedTokenTypes) {\n const additionalRequiredClaims = [];\n switch (expectedNonce) {\n case undefined:\n expectedNonce = expectNoNonce;\n break;\n case expectNoNonce:\n break;\n default:\n assertString(expectedNonce, '\"expectedNonce\" argument');\n additionalRequiredClaims.push('nonce');\n }\n maxAge ??= client.default_max_age;\n switch (maxAge) {\n case undefined:\n maxAge = skipAuthTimeCheck;\n break;\n case skipAuthTimeCheck:\n break;\n default:\n assertNumber(maxAge, true, '\"maxAge\" argument');\n additionalRequiredClaims.push('auth_time');\n }\n const result = await processGenericAccessTokenResponse(as, client, response, additionalRequiredClaims, decryptFn, recognizedTokenTypes);\n assertString(result.id_token, '\"response\" body \"id_token\" property', INVALID_RESPONSE, {\n body: result,\n });\n const claims = getValidatedIdTokenClaims(result);\n if (maxAge !== skipAuthTimeCheck) {\n const now = epochTime() + getClockSkew(client);\n const tolerance = getClockTolerance(client);\n if (claims.auth_time + maxAge < now - tolerance) {\n throw OPE('too much time has elapsed since the last End-User authentication', JWT_TIMESTAMP_CHECK, { claims, now, tolerance, claim: 'auth_time' });\n }\n }\n if (expectedNonce === expectNoNonce) {\n if (claims.nonce !== undefined) {\n throw OPE('unexpected ID Token \"nonce\" claim value', JWT_CLAIM_COMPARISON, {\n expected: undefined,\n claims,\n claim: 'nonce',\n });\n }\n }\n else if (claims.nonce !== expectedNonce) {\n throw OPE('unexpected ID Token \"nonce\" claim value', JWT_CLAIM_COMPARISON, {\n expected: expectedNonce,\n claims,\n claim: 'nonce',\n });\n }\n return result;\n}\nasync function processAuthorizationCodeOAuth2Response(as, client, response, decryptFn, recognizedTokenTypes) {\n const result = await processGenericAccessTokenResponse(as, client, response, undefined, decryptFn, recognizedTokenTypes);\n const claims = getValidatedIdTokenClaims(result);\n if (claims) {\n if (client.default_max_age !== undefined) {\n assertNumber(client.default_max_age, true, '\"client.default_max_age\"');\n const now = epochTime() + getClockSkew(client);\n const tolerance = getClockTolerance(client);\n if (claims.auth_time + client.default_max_age < now - tolerance) {\n throw OPE('too much time has elapsed since the last End-User authentication', JWT_TIMESTAMP_CHECK, { claims, now, tolerance, claim: 'auth_time' });\n }\n }\n if (claims.nonce !== undefined) {\n throw OPE('unexpected ID Token \"nonce\" claim value', JWT_CLAIM_COMPARISON, {\n expected: undefined,\n claims,\n claim: 'nonce',\n });\n }\n }\n return result;\n}\nexport const WWW_AUTHENTICATE_CHALLENGE = 'OAUTH_WWW_AUTHENTICATE_CHALLENGE';\nexport const RESPONSE_BODY_ERROR = 'OAUTH_RESPONSE_BODY_ERROR';\nexport const UNSUPPORTED_OPERATION = 'OAUTH_UNSUPPORTED_OPERATION';\nexport const AUTHORIZATION_RESPONSE_ERROR = 'OAUTH_AUTHORIZATION_RESPONSE_ERROR';\nexport const JWT_USERINFO_EXPECTED = 'OAUTH_JWT_USERINFO_EXPECTED';\nexport const PARSE_ERROR = 'OAUTH_PARSE_ERROR';\nexport const INVALID_RESPONSE = 'OAUTH_INVALID_RESPONSE';\nexport const INVALID_REQUEST = 'OAUTH_INVALID_REQUEST';\nexport const RESPONSE_IS_NOT_JSON = 'OAUTH_RESPONSE_IS_NOT_JSON';\nexport const RESPONSE_IS_NOT_CONFORM = 'OAUTH_RESPONSE_IS_NOT_CONFORM';\nexport const HTTP_REQUEST_FORBIDDEN = 'OAUTH_HTTP_REQUEST_FORBIDDEN';\nexport const REQUEST_PROTOCOL_FORBIDDEN = 'OAUTH_REQUEST_PROTOCOL_FORBIDDEN';\nexport const JWT_TIMESTAMP_CHECK = 'OAUTH_JWT_TIMESTAMP_CHECK_FAILED';\nexport const JWT_CLAIM_COMPARISON = 'OAUTH_JWT_CLAIM_COMPARISON_FAILED';\nexport const JSON_ATTRIBUTE_COMPARISON = 'OAUTH_JSON_ATTRIBUTE_COMPARISON_FAILED';\nexport const KEY_SELECTION = 'OAUTH_KEY_SELECTION_FAILED';\nexport const MISSING_SERVER_METADATA = 'OAUTH_MISSING_SERVER_METADATA';\nexport const INVALID_SERVER_METADATA = 'OAUTH_INVALID_SERVER_METADATA';\nfunction checkJwtType(expected, result) {\n if (typeof result.header.typ !== 'string' || normalizeTyp(result.header.typ) !== expected) {\n throw OPE('unexpected JWT \"typ\" header parameter value', INVALID_RESPONSE, {\n header: result.header,\n });\n }\n return result;\n}\nexport async function clientCredentialsGrantRequest(as, client, clientAuthentication, parameters, options) {\n assertAs(as);\n assertClient(client);\n return tokenEndpointRequest(as, client, clientAuthentication, 'client_credentials', new URLSearchParams(parameters), options);\n}\nexport async function genericTokenEndpointRequest(as, client, clientAuthentication, grantType, parameters, options) {\n assertAs(as);\n assertClient(client);\n assertString(grantType, '\"grantType\"');\n return tokenEndpointRequest(as, client, clientAuthentication, grantType, new URLSearchParams(parameters), options);\n}\nexport async function processGenericTokenEndpointResponse(as, client, response, options) {\n return processGenericAccessTokenResponse(as, client, response, undefined, options?.[jweDecrypt], options?.recognizedTokenTypes);\n}\nexport async function processClientCredentialsResponse(as, client, response, options) {\n return processGenericAccessTokenResponse(as, client, response, undefined, options?.[jweDecrypt], options?.recognizedTokenTypes);\n}\nexport async function revocationRequest(as, client, clientAuthentication, token, options) {\n assertAs(as);\n assertClient(client);\n assertString(token, '\"token\"');\n const url = resolveEndpoint(as, 'revocation_endpoint', client.use_mtls_endpoint_aliases, options?.[allowInsecureRequests] !== true);\n const body = new URLSearchParams(options?.additionalParameters);\n body.set('token', token);\n const headers = prepareHeaders(options?.headers);\n headers.delete('accept');\n return authenticatedRequest(as, client, clientAuthentication, url, body, headers, options);\n}\nexport async function processRevocationResponse(response) {\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n await checkOAuthBodyError(response, 200, 'Revocation Endpoint');\n return undefined;\n}\nfunction assertReadableResponse(response) {\n if (response.bodyUsed) {\n throw CodedTypeError('\"response\" body has been used already', ERR_INVALID_ARG_VALUE);\n }\n}\nexport async function introspectionRequest(as, client, clientAuthentication, token, options) {\n assertAs(as);\n assertClient(client);\n assertString(token, '\"token\"');\n const url = resolveEndpoint(as, 'introspection_endpoint', client.use_mtls_endpoint_aliases, options?.[allowInsecureRequests] !== true);\n const body = new URLSearchParams(options?.additionalParameters);\n body.set('token', token);\n const headers = prepareHeaders(options?.headers);\n if (options?.requestJwtResponse ?? client.introspection_signed_response_alg) {\n headers.set('accept', 'application/token-introspection+jwt');\n }\n else {\n headers.set('accept', 'application/json');\n }\n return authenticatedRequest(as, client, clientAuthentication, url, body, headers, options);\n}\nexport async function processIntrospectionResponse(as, client, response, options) {\n assertAs(as);\n assertClient(client);\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n await checkOAuthBodyError(response, 200, 'Introspection Endpoint');\n let json;\n if (getContentType(response) === 'application/token-introspection+jwt') {\n assertReadableResponse(response);\n const { claims, jwt } = await validateJwt(await response.text(), checkSigningAlgorithm.bind(undefined, client.introspection_signed_response_alg, as.introspection_signing_alg_values_supported, 'RS256'), getClockSkew(client), getClockTolerance(client), options?.[jweDecrypt])\n .then(checkJwtType.bind(undefined, 'token-introspection+jwt'))\n .then(validatePresence.bind(undefined, ['aud', 'iat', 'iss']))\n .then(validateIssuer.bind(undefined, as))\n .then(validateAudience.bind(undefined, client.client_id));\n jwtRefs.set(response, jwt);\n if (!isJsonObject(claims.token_introspection)) {\n throw OPE('JWT \"token_introspection\" claim must be a JSON object', INVALID_RESPONSE, {\n claims,\n });\n }\n json = claims.token_introspection;\n }\n else {\n assertReadableResponse(response);\n json = await getResponseJsonBody(response);\n }\n if (typeof json.active !== 'boolean') {\n throw OPE('\"response\" body \"active\" property must be a boolean', INVALID_RESPONSE, {\n body: json,\n });\n }\n return json;\n}\nasync function jwksRequest(as, options) {\n assertAs(as);\n const url = resolveEndpoint(as, 'jwks_uri', false, options?.[allowInsecureRequests] !== true);\n const headers = prepareHeaders(options?.headers);\n headers.set('accept', 'application/json');\n headers.append('accept', 'application/jwk-set+json');\n return (options?.[customFetch] || fetch)(url.href, {\n body: undefined,\n headers: Object.fromEntries(headers.entries()),\n method: 'GET',\n redirect: 'manual',\n signal: signal(url, options?.signal),\n });\n}\nasync function processJwksResponse(response) {\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n if (response.status !== 200) {\n throw OPE('\"response\" is not a conform JSON Web Key Set response (unexpected HTTP status code)', RESPONSE_IS_NOT_CONFORM, response);\n }\n assertReadableResponse(response);\n const json = await getResponseJsonBody(response, (response) => assertContentTypes(response, 'application/json', 'application/jwk-set+json'));\n if (!Array.isArray(json.keys)) {\n throw OPE('\"response\" body \"keys\" property must be an array', INVALID_RESPONSE, { body: json });\n }\n if (!Array.prototype.every.call(json.keys, isJsonObject)) {\n throw OPE('\"response\" body \"keys\" property members must be JWK formatted objects', INVALID_RESPONSE, { body: json });\n }\n return json;\n}\nfunction supported(alg) {\n switch (alg) {\n case 'PS256':\n case 'ES256':\n case 'RS256':\n case 'PS384':\n case 'ES384':\n case 'RS384':\n case 'PS512':\n case 'ES512':\n case 'RS512':\n case 'Ed25519':\n case 'EdDSA':\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87':\n return true;\n default:\n return false;\n }\n}\nfunction checkSupportedJwsAlg(header) {\n if (!supported(header.alg)) {\n throw new UnsupportedOperationError('unsupported JWS \"alg\" identifier', {\n cause: { alg: header.alg },\n });\n }\n}\nfunction checkRsaKeyAlgorithm(key) {\n const { algorithm } = key;\n if (typeof algorithm.modulusLength !== 'number' || algorithm.modulusLength < 2048) {\n throw new UnsupportedOperationError(`unsupported ${algorithm.name} modulusLength`, {\n cause: key,\n });\n }\n}\nfunction ecdsaHashName(key) {\n const { algorithm } = key;\n switch (algorithm.namedCurve) {\n case 'P-256':\n return 'SHA-256';\n case 'P-384':\n return 'SHA-384';\n case 'P-521':\n return 'SHA-512';\n default:\n throw new UnsupportedOperationError('unsupported ECDSA namedCurve', { cause: key });\n }\n}\nfunction keyToSubtle(key) {\n switch (key.algorithm.name) {\n case 'ECDSA':\n return {\n name: key.algorithm.name,\n hash: ecdsaHashName(key),\n };\n case 'RSA-PSS': {\n checkRsaKeyAlgorithm(key);\n switch (key.algorithm.hash.name) {\n case 'SHA-256':\n case 'SHA-384':\n case 'SHA-512':\n return {\n name: key.algorithm.name,\n saltLength: parseInt(key.algorithm.hash.name.slice(-3), 10) >> 3,\n };\n default:\n throw new UnsupportedOperationError('unsupported RSA-PSS hash name', { cause: key });\n }\n }\n case 'RSASSA-PKCS1-v1_5':\n checkRsaKeyAlgorithm(key);\n return key.algorithm.name;\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87':\n case 'Ed25519':\n return key.algorithm.name;\n }\n throw new UnsupportedOperationError('unsupported CryptoKey algorithm name', { cause: key });\n}\nasync function validateJwsSignature(protectedHeader, payload, key, signature) {\n const data = buf(`${protectedHeader}.${payload}`);\n const algorithm = keyToSubtle(key);\n const verified = await crypto.subtle.verify(algorithm, key, signature, data);\n if (!verified) {\n throw OPE('JWT signature verification failed', INVALID_RESPONSE, {\n key,\n data,\n signature,\n algorithm,\n });\n }\n}\nasync function validateJwt(jws, checkAlg, clockSkew, clockTolerance, decryptJwt) {\n let { 0: protectedHeader, 1: payload, length } = jws.split('.');\n if (length === 5) {\n if (decryptJwt !== undefined) {\n jws = await decryptJwt(jws);\n ({ 0: protectedHeader, 1: payload, length } = jws.split('.'));\n }\n else {\n throw new UnsupportedOperationError('JWE decryption is not configured', { cause: jws });\n }\n }\n if (length !== 3) {\n throw OPE('Invalid JWT', INVALID_RESPONSE, jws);\n }\n let header;\n try {\n header = JSON.parse(buf(b64u(protectedHeader)));\n }\n catch (cause) {\n throw OPE('failed to parse JWT Header body as base64url encoded JSON', PARSE_ERROR, cause);\n }\n if (!isJsonObject(header)) {\n throw OPE('JWT Header must be a top level object', INVALID_RESPONSE, jws);\n }\n checkAlg(header);\n if (header.crit !== undefined) {\n throw new UnsupportedOperationError('no JWT \"crit\" header parameter extensions are supported', {\n cause: { header },\n });\n }\n let claims;\n try {\n claims = JSON.parse(buf(b64u(payload)));\n }\n catch (cause) {\n throw OPE('failed to parse JWT Payload body as base64url encoded JSON', PARSE_ERROR, cause);\n }\n if (!isJsonObject(claims)) {\n throw OPE('JWT Payload must be a top level object', INVALID_RESPONSE, jws);\n }\n const now = epochTime() + clockSkew;\n if (claims.exp !== undefined) {\n if (typeof claims.exp !== 'number') {\n throw OPE('unexpected JWT \"exp\" (expiration time) claim type', INVALID_RESPONSE, { claims });\n }\n if (claims.exp <= now - clockTolerance) {\n throw OPE('unexpected JWT \"exp\" (expiration time) claim value, expiration is past current timestamp', JWT_TIMESTAMP_CHECK, { claims, now, tolerance: clockTolerance, claim: 'exp' });\n }\n }\n if (claims.iat !== undefined) {\n if (typeof claims.iat !== 'number') {\n throw OPE('unexpected JWT \"iat\" (issued at) claim type', INVALID_RESPONSE, { claims });\n }\n }\n if (claims.iss !== undefined) {\n if (typeof claims.iss !== 'string') {\n throw OPE('unexpected JWT \"iss\" (issuer) claim type', INVALID_RESPONSE, { claims });\n }\n }\n if (claims.nbf !== undefined) {\n if (typeof claims.nbf !== 'number') {\n throw OPE('unexpected JWT \"nbf\" (not before) claim type', INVALID_RESPONSE, { claims });\n }\n if (claims.nbf > now + clockTolerance) {\n throw OPE('unexpected JWT \"nbf\" (not before) claim value', JWT_TIMESTAMP_CHECK, {\n claims,\n now,\n tolerance: clockTolerance,\n claim: 'nbf',\n });\n }\n }\n if (claims.aud !== undefined) {\n if (typeof claims.aud !== 'string' && !Array.isArray(claims.aud)) {\n throw OPE('unexpected JWT \"aud\" (audience) claim type', INVALID_RESPONSE, { claims });\n }\n }\n return { header, claims, jwt: jws };\n}\nexport async function validateJwtAuthResponse(as, client, parameters, expectedState, options) {\n assertAs(as);\n assertClient(client);\n if (parameters instanceof URL) {\n parameters = parameters.searchParams;\n }\n if (!(parameters instanceof URLSearchParams)) {\n throw CodedTypeError('\"parameters\" must be an instance of URLSearchParams, or URL', ERR_INVALID_ARG_TYPE);\n }\n const response = getURLSearchParameter(parameters, 'response');\n if (!response) {\n throw OPE('\"parameters\" does not contain a JARM response', INVALID_RESPONSE);\n }\n const { claims, header, jwt } = await validateJwt(response, checkSigningAlgorithm.bind(undefined, client.authorization_signed_response_alg, as.authorization_signing_alg_values_supported, 'RS256'), getClockSkew(client), getClockTolerance(client), options?.[jweDecrypt])\n .then(validatePresence.bind(undefined, ['aud', 'exp', 'iss']))\n .then(validateIssuer.bind(undefined, as))\n .then(validateAudience.bind(undefined, client.client_id));\n const { 0: protectedHeader, 1: payload, 2: encodedSignature } = jwt.split('.');\n const signature = b64u(encodedSignature);\n const key = await getPublicSigKeyFromIssuerJwksUri(as, options, header);\n await validateJwsSignature(protectedHeader, payload, key, signature);\n const result = new URLSearchParams();\n for (const [key, value] of Object.entries(claims)) {\n if (typeof value === 'string' && key !== 'aud') {\n result.set(key, value);\n }\n }\n return validateAuthResponse(as, client, result, expectedState);\n}\nasync function idTokenHash(data, header, claimName) {\n let algorithm;\n switch (header.alg) {\n case 'RS256':\n case 'PS256':\n case 'ES256':\n algorithm = 'SHA-256';\n break;\n case 'RS384':\n case 'PS384':\n case 'ES384':\n algorithm = 'SHA-384';\n break;\n case 'RS512':\n case 'PS512':\n case 'ES512':\n case 'Ed25519':\n case 'EdDSA':\n algorithm = 'SHA-512';\n break;\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87':\n algorithm = { name: 'cSHAKE256', length: 512, outputLength: 512 };\n break;\n default:\n throw new UnsupportedOperationError(`unsupported JWS algorithm for ${claimName} calculation`, { cause: { alg: header.alg } });\n }\n const digest = await crypto.subtle.digest(algorithm, buf(data));\n return b64u(digest.slice(0, digest.byteLength / 2));\n}\nasync function idTokenHashMatches(data, actual, header, claimName) {\n const expected = await idTokenHash(data, header, claimName);\n return actual === expected;\n}\nexport async function validateDetachedSignatureResponse(as, client, parameters, expectedNonce, expectedState, maxAge, options) {\n return validateHybridResponse(as, client, parameters, expectedNonce, expectedState, maxAge, options, true);\n}\nexport async function validateCodeIdTokenResponse(as, client, parameters, expectedNonce, expectedState, maxAge, options) {\n return validateHybridResponse(as, client, parameters, expectedNonce, expectedState, maxAge, options, false);\n}\nasync function consumeStream(request) {\n if (request.bodyUsed) {\n throw CodedTypeError('form_post Request instances must contain a readable body', ERR_INVALID_ARG_VALUE, { cause: request });\n }\n return request.text();\n}\nexport async function formPostResponse(request) {\n if (request.method !== 'POST') {\n throw CodedTypeError('form_post responses are expected to use the POST method', ERR_INVALID_ARG_VALUE, { cause: request });\n }\n if (getContentType(request) !== 'application/x-www-form-urlencoded') {\n throw CodedTypeError('form_post responses are expected to use the application/x-www-form-urlencoded content-type', ERR_INVALID_ARG_VALUE, { cause: request });\n }\n return consumeStream(request);\n}\nasync function validateHybridResponse(as, client, parameters, expectedNonce, expectedState, maxAge, options, fapi) {\n assertAs(as);\n assertClient(client);\n if (parameters instanceof URL) {\n if (!parameters.hash.length) {\n throw CodedTypeError('\"parameters\" as an instance of URL must contain a hash (fragment) with the Authorization Response parameters', ERR_INVALID_ARG_VALUE);\n }\n parameters = new URLSearchParams(parameters.hash.slice(1));\n }\n else if (looseInstanceOf(parameters, Request)) {\n parameters = new URLSearchParams(await formPostResponse(parameters));\n }\n else if (parameters instanceof URLSearchParams) {\n parameters = new URLSearchParams(parameters);\n }\n else {\n throw CodedTypeError('\"parameters\" must be an instance of URLSearchParams, URL, or Response', ERR_INVALID_ARG_TYPE);\n }\n const id_token = getURLSearchParameter(parameters, 'id_token');\n parameters.delete('id_token');\n switch (expectedState) {\n case undefined:\n case expectNoState:\n break;\n default:\n assertString(expectedState, '\"expectedState\" argument');\n }\n const result = validateAuthResponse({\n ...as,\n authorization_response_iss_parameter_supported: false,\n }, client, parameters, expectedState);\n if (!id_token) {\n throw OPE('\"parameters\" does not contain an ID Token', INVALID_RESPONSE);\n }\n const code = getURLSearchParameter(parameters, 'code');\n if (!code) {\n throw OPE('\"parameters\" does not contain an Authorization Code', INVALID_RESPONSE);\n }\n const requiredClaims = [\n 'aud',\n 'exp',\n 'iat',\n 'iss',\n 'sub',\n 'nonce',\n 'c_hash',\n ];\n const state = parameters.get('state');\n if (fapi && (typeof expectedState === 'string' || state !== null)) {\n requiredClaims.push('s_hash');\n }\n if (maxAge !== undefined) {\n assertNumber(maxAge, true, '\"maxAge\" argument');\n }\n else if (client.default_max_age !== undefined) {\n assertNumber(client.default_max_age, true, '\"client.default_max_age\"');\n }\n maxAge ??= client.default_max_age ?? skipAuthTimeCheck;\n if (client.require_auth_time || maxAge !== skipAuthTimeCheck) {\n requiredClaims.push('auth_time');\n }\n const { claims, header, jwt } = await validateJwt(id_token, checkSigningAlgorithm.bind(undefined, client.id_token_signed_response_alg, as.id_token_signing_alg_values_supported, 'RS256'), getClockSkew(client), getClockTolerance(client), options?.[jweDecrypt])\n .then(validatePresence.bind(undefined, requiredClaims))\n .then(validateIssuer.bind(undefined, as))\n .then(validateAudience.bind(undefined, client.client_id));\n const clockSkew = getClockSkew(client);\n const now = epochTime() + clockSkew;\n if (claims.iat < now - 3600) {\n throw OPE('unexpected JWT \"iat\" (issued at) claim value, it is too far in the past', JWT_TIMESTAMP_CHECK, { now, claims, claim: 'iat' });\n }\n assertString(claims.c_hash, 'ID Token \"c_hash\" (code hash) claim value', INVALID_RESPONSE, {\n claims,\n });\n if (claims.auth_time !== undefined) {\n assertNumber(claims.auth_time, true, 'ID Token \"auth_time\" (authentication time)', INVALID_RESPONSE, { claims });\n }\n if (maxAge !== skipAuthTimeCheck) {\n const now = epochTime() + getClockSkew(client);\n const tolerance = getClockTolerance(client);\n if (claims.auth_time + maxAge < now - tolerance) {\n throw OPE('too much time has elapsed since the last End-User authentication', JWT_TIMESTAMP_CHECK, { claims, now, tolerance, claim: 'auth_time' });\n }\n }\n assertString(expectedNonce, '\"expectedNonce\" argument');\n if (claims.nonce !== expectedNonce) {\n throw OPE('unexpected ID Token \"nonce\" claim value', JWT_CLAIM_COMPARISON, {\n expected: expectedNonce,\n claims,\n claim: 'nonce',\n });\n }\n if (Array.isArray(claims.aud) && claims.aud.length !== 1) {\n if (claims.azp === undefined) {\n throw OPE('ID Token \"aud\" (audience) claim includes additional untrusted audiences', JWT_CLAIM_COMPARISON, { claims, claim: 'aud' });\n }\n if (claims.azp !== client.client_id) {\n throw OPE('unexpected ID Token \"azp\" (authorized party) claim value', JWT_CLAIM_COMPARISON, {\n expected: client.client_id,\n claims,\n claim: 'azp',\n });\n }\n }\n const { 0: protectedHeader, 1: payload, 2: encodedSignature } = jwt.split('.');\n const signature = b64u(encodedSignature);\n const key = await getPublicSigKeyFromIssuerJwksUri(as, options, header);\n await validateJwsSignature(protectedHeader, payload, key, signature);\n if ((await idTokenHashMatches(code, claims.c_hash, header, 'c_hash')) !== true) {\n throw OPE('invalid ID Token \"c_hash\" (code hash) claim value', JWT_CLAIM_COMPARISON, {\n code,\n alg: header.alg,\n claim: 'c_hash',\n claims,\n });\n }\n if ((fapi && state !== null) || claims.s_hash !== undefined) {\n assertString(claims.s_hash, 'ID Token \"s_hash\" (state hash) claim value', INVALID_RESPONSE, {\n claims,\n });\n assertString(state, '\"state\" response parameter', INVALID_RESPONSE, { parameters });\n if ((await idTokenHashMatches(state, claims.s_hash, header, 's_hash')) !== true) {\n throw OPE('invalid ID Token \"s_hash\" (state hash) claim value', JWT_CLAIM_COMPARISON, {\n state,\n alg: header.alg,\n claim: 's_hash',\n claims,\n });\n }\n }\n return result;\n}\nfunction checkSigningAlgorithm(client, issuer, fallback, header) {\n if (client !== undefined) {\n if (typeof client === 'string' ? header.alg !== client : !client.includes(header.alg)) {\n throw OPE('unexpected JWT \"alg\" header parameter', INVALID_RESPONSE, {\n header,\n expected: client,\n reason: 'client configuration',\n });\n }\n return;\n }\n if (Array.isArray(issuer)) {\n if (!issuer.includes(header.alg)) {\n throw OPE('unexpected JWT \"alg\" header parameter', INVALID_RESPONSE, {\n header,\n expected: issuer,\n reason: 'authorization server metadata',\n });\n }\n return;\n }\n if (fallback !== undefined) {\n if (typeof fallback === 'string'\n ? header.alg !== fallback\n : typeof fallback === 'function'\n ? !fallback(header.alg)\n : !fallback.includes(header.alg)) {\n throw OPE('unexpected JWT \"alg\" header parameter', INVALID_RESPONSE, {\n header,\n expected: fallback,\n reason: 'default value',\n });\n }\n return;\n }\n throw OPE('missing client or server configuration to verify used JWT \"alg\" header parameter', undefined, { client, issuer, fallback });\n}\nfunction getURLSearchParameter(parameters, name) {\n const { 0: value, length } = parameters.getAll(name);\n if (length > 1) {\n throw OPE(`\"${name}\" parameter must be provided only once`, INVALID_RESPONSE);\n }\n return value;\n}\nexport const skipStateCheck = Symbol();\nexport const expectNoState = Symbol();\nexport function validateAuthResponse(as, client, parameters, expectedState) {\n assertAs(as);\n assertClient(client);\n if (parameters instanceof URL) {\n parameters = parameters.searchParams;\n }\n if (!(parameters instanceof URLSearchParams)) {\n throw CodedTypeError('\"parameters\" must be an instance of URLSearchParams, or URL', ERR_INVALID_ARG_TYPE);\n }\n if (getURLSearchParameter(parameters, 'response')) {\n throw OPE('\"parameters\" contains a JARM response, use validateJwtAuthResponse() instead of validateAuthResponse()', INVALID_RESPONSE, { parameters });\n }\n const iss = getURLSearchParameter(parameters, 'iss');\n const state = getURLSearchParameter(parameters, 'state');\n if (!iss && as.authorization_response_iss_parameter_supported) {\n throw OPE('response parameter \"iss\" (issuer) missing', INVALID_RESPONSE, { parameters });\n }\n if (iss && iss !== as.issuer) {\n throw OPE('unexpected \"iss\" (issuer) response parameter value', INVALID_RESPONSE, {\n expected: as.issuer,\n parameters,\n });\n }\n switch (expectedState) {\n case undefined:\n case expectNoState:\n if (state !== undefined) {\n throw OPE('unexpected \"state\" response parameter encountered', INVALID_RESPONSE, {\n expected: undefined,\n parameters,\n });\n }\n break;\n case skipStateCheck:\n break;\n default:\n assertString(expectedState, '\"expectedState\" argument');\n if (state !== expectedState) {\n throw OPE(state === undefined\n ? 'response parameter \"state\" missing'\n : 'unexpected \"state\" response parameter value', INVALID_RESPONSE, { expected: expectedState, parameters });\n }\n }\n const error = getURLSearchParameter(parameters, 'error');\n if (error) {\n throw new AuthorizationResponseError('authorization response from the server is an error', {\n cause: parameters,\n });\n }\n const id_token = getURLSearchParameter(parameters, 'id_token');\n const token = getURLSearchParameter(parameters, 'token');\n if (id_token !== undefined || token !== undefined) {\n throw new UnsupportedOperationError('implicit and hybrid flows are not supported');\n }\n return brand(new URLSearchParams(parameters));\n}\nfunction algToSubtle(alg) {\n switch (alg) {\n case 'PS256':\n case 'PS384':\n case 'PS512':\n return { name: 'RSA-PSS', hash: `SHA-${alg.slice(-3)}` };\n case 'RS256':\n case 'RS384':\n case 'RS512':\n return { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${alg.slice(-3)}` };\n case 'ES256':\n case 'ES384':\n return { name: 'ECDSA', namedCurve: `P-${alg.slice(-3)}` };\n case 'ES512':\n return { name: 'ECDSA', namedCurve: 'P-521' };\n case 'EdDSA':\n return 'Ed25519';\n case 'Ed25519':\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87':\n return alg;\n default:\n throw new UnsupportedOperationError('unsupported JWS algorithm', { cause: { alg } });\n }\n}\nasync function importJwk(alg, jwk) {\n const { ext, key_ops, use, ...key } = jwk;\n return crypto.subtle.importKey('jwk', key, algToSubtle(alg), true, ['verify']);\n}\nexport async function deviceAuthorizationRequest(as, client, clientAuthentication, parameters, options) {\n assertAs(as);\n assertClient(client);\n const url = resolveEndpoint(as, 'device_authorization_endpoint', client.use_mtls_endpoint_aliases, options?.[allowInsecureRequests] !== true);\n const body = new URLSearchParams(parameters);\n body.set('client_id', client.client_id);\n const headers = prepareHeaders(options?.headers);\n headers.set('accept', 'application/json');\n return authenticatedRequest(as, client, clientAuthentication, url, body, headers, options);\n}\nexport async function processDeviceAuthorizationResponse(as, client, response) {\n assertAs(as);\n assertClient(client);\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n await checkOAuthBodyError(response, 200, 'Device Authorization Endpoint');\n assertReadableResponse(response);\n const json = await getResponseJsonBody(response);\n assertString(json.device_code, '\"response\" body \"device_code\" property', INVALID_RESPONSE, {\n body: json,\n });\n assertString(json.user_code, '\"response\" body \"user_code\" property', INVALID_RESPONSE, {\n body: json,\n });\n assertString(json.verification_uri, '\"response\" body \"verification_uri\" property', INVALID_RESPONSE, { body: json });\n let expiresIn = typeof json.expires_in !== 'number' ? parseFloat(json.expires_in) : json.expires_in;\n assertNumber(expiresIn, true, '\"response\" body \"expires_in\" property', INVALID_RESPONSE, {\n body: json,\n });\n json.expires_in = expiresIn;\n if (json.verification_uri_complete !== undefined) {\n assertString(json.verification_uri_complete, '\"response\" body \"verification_uri_complete\" property', INVALID_RESPONSE, { body: json });\n }\n if (json.interval !== undefined) {\n assertNumber(json.interval, false, '\"response\" body \"interval\" property', INVALID_RESPONSE, {\n body: json,\n });\n }\n return json;\n}\nexport async function deviceCodeGrantRequest(as, client, clientAuthentication, deviceCode, options) {\n assertAs(as);\n assertClient(client);\n assertString(deviceCode, '\"deviceCode\"');\n const parameters = new URLSearchParams(options?.additionalParameters);\n parameters.set('device_code', deviceCode);\n return tokenEndpointRequest(as, client, clientAuthentication, 'urn:ietf:params:oauth:grant-type:device_code', parameters, options);\n}\nexport async function processDeviceCodeResponse(as, client, response, options) {\n return processGenericAccessTokenResponse(as, client, response, undefined, options?.[jweDecrypt], options?.recognizedTokenTypes);\n}\nexport async function generateKeyPair(alg, options) {\n assertString(alg, '\"alg\"');\n const algorithm = algToSubtle(alg);\n if (alg.startsWith('PS') || alg.startsWith('RS')) {\n Object.assign(algorithm, {\n modulusLength: options?.modulusLength ?? 2048,\n publicExponent: new Uint8Array([0x01, 0x00, 0x01]),\n });\n }\n return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, [\n 'sign',\n 'verify',\n ]);\n}\nfunction normalizeHtu(htu) {\n const url = new URL(htu);\n url.search = '';\n url.hash = '';\n return url.href;\n}\nasync function validateDPoP(request, accessToken, accessTokenClaims, options) {\n const headerValue = request.headers.get('dpop');\n if (headerValue === null) {\n throw OPE('operation indicated DPoP use but the request has no DPoP HTTP Header', INVALID_REQUEST, { headers: request.headers });\n }\n if (request.headers.get('authorization')?.toLowerCase().startsWith('dpop ') === false) {\n throw OPE(`operation indicated DPoP use but the request's Authorization HTTP Header scheme is not DPoP`, INVALID_REQUEST, { headers: request.headers });\n }\n if (typeof accessTokenClaims.cnf?.jkt !== 'string') {\n throw OPE('operation indicated DPoP use but the JWT Access Token has no jkt confirmation claim', INVALID_REQUEST, { claims: accessTokenClaims });\n }\n const clockSkew = getClockSkew(options);\n const proof = await validateJwt(headerValue, checkSigningAlgorithm.bind(undefined, options?.signingAlgorithms, undefined, supported), clockSkew, getClockTolerance(options), undefined)\n .then(checkJwtType.bind(undefined, 'dpop+jwt'))\n .then(validatePresence.bind(undefined, ['iat', 'jti', 'ath', 'htm', 'htu']));\n const now = epochTime() + clockSkew;\n const diff = Math.abs(now - proof.claims.iat);\n if (diff > 300) {\n throw OPE('DPoP Proof iat is not recent enough', JWT_TIMESTAMP_CHECK, {\n now,\n claims: proof.claims,\n claim: 'iat',\n });\n }\n if (proof.claims.htm !== request.method) {\n throw OPE('DPoP Proof htm mismatch', JWT_CLAIM_COMPARISON, {\n expected: request.method,\n claims: proof.claims,\n claim: 'htm',\n });\n }\n if (typeof proof.claims.htu !== 'string' ||\n normalizeHtu(proof.claims.htu) !== normalizeHtu(request.url)) {\n throw OPE('DPoP Proof htu mismatch', JWT_CLAIM_COMPARISON, {\n expected: normalizeHtu(request.url),\n claims: proof.claims,\n claim: 'htu',\n });\n }\n {\n const expected = b64u(await crypto.subtle.digest('SHA-256', buf(accessToken)));\n if (proof.claims.ath !== expected) {\n throw OPE('DPoP Proof ath mismatch', JWT_CLAIM_COMPARISON, {\n expected,\n claims: proof.claims,\n claim: 'ath',\n });\n }\n }\n {\n const expected = await calculateJwkThumbprint(proof.header.jwk);\n if (accessTokenClaims.cnf.jkt !== expected) {\n throw OPE('JWT Access Token confirmation mismatch', JWT_CLAIM_COMPARISON, {\n expected,\n claims: accessTokenClaims,\n claim: 'cnf.jkt',\n });\n }\n }\n const { 0: protectedHeader, 1: payload, 2: encodedSignature } = headerValue.split('.');\n const signature = b64u(encodedSignature);\n const { jwk, alg } = proof.header;\n if (!jwk) {\n throw OPE('DPoP Proof is missing the jwk header parameter', INVALID_REQUEST, {\n header: proof.header,\n });\n }\n const key = await importJwk(alg, jwk);\n if (key.type !== 'public') {\n throw OPE('DPoP Proof jwk header parameter must contain a public key', INVALID_REQUEST, {\n header: proof.header,\n });\n }\n await validateJwsSignature(protectedHeader, payload, key, signature);\n}\nexport async function validateJwtAccessToken(as, request, expectedAudience, options) {\n assertAs(as);\n if (!looseInstanceOf(request, Request)) {\n throw CodedTypeError('\"request\" must be an instance of Request', ERR_INVALID_ARG_TYPE);\n }\n assertString(expectedAudience, '\"expectedAudience\"');\n const authorization = request.headers.get('authorization');\n if (authorization === null) {\n throw OPE('\"request\" is missing an Authorization HTTP Header', INVALID_REQUEST, {\n headers: request.headers,\n });\n }\n let { 0: scheme, 1: accessToken, length } = authorization.split(' ');\n scheme = scheme.toLowerCase();\n switch (scheme) {\n case 'dpop':\n case 'bearer':\n break;\n default:\n throw new UnsupportedOperationError('unsupported Authorization HTTP Header scheme', {\n cause: { headers: request.headers },\n });\n }\n if (length !== 2) {\n throw OPE('invalid Authorization HTTP Header format', INVALID_REQUEST, {\n headers: request.headers,\n });\n }\n const requiredClaims = [\n 'iss',\n 'exp',\n 'aud',\n 'sub',\n 'iat',\n 'jti',\n 'client_id',\n ];\n if (options?.requireDPoP || scheme === 'dpop' || request.headers.has('dpop')) {\n requiredClaims.push('cnf');\n }\n const { claims, header } = await validateJwt(accessToken, checkSigningAlgorithm.bind(undefined, options?.signingAlgorithms, undefined, supported), getClockSkew(options), getClockTolerance(options), undefined)\n .then(checkJwtType.bind(undefined, 'at+jwt'))\n .then(validatePresence.bind(undefined, requiredClaims))\n .then(validateIssuer.bind(undefined, as))\n .then(validateAudience.bind(undefined, expectedAudience))\n .catch(reassignRSCode);\n for (const claim of ['client_id', 'jti', 'sub']) {\n if (typeof claims[claim] !== 'string') {\n throw OPE(`unexpected JWT \"${claim}\" claim type`, INVALID_REQUEST, { claims });\n }\n }\n if ('cnf' in claims) {\n if (!isJsonObject(claims.cnf)) {\n throw OPE('unexpected JWT \"cnf\" (confirmation) claim value', INVALID_REQUEST, { claims });\n }\n const { 0: cnf, length } = Object.keys(claims.cnf);\n if (length) {\n if (length !== 1) {\n throw new UnsupportedOperationError('multiple confirmation claims are not supported', {\n cause: { claims },\n });\n }\n if (cnf !== 'jkt') {\n throw new UnsupportedOperationError('unsupported JWT Confirmation method', {\n cause: { claims },\n });\n }\n }\n }\n const { 0: protectedHeader, 1: payload, 2: encodedSignature } = accessToken.split('.');\n const signature = b64u(encodedSignature);\n const key = await getPublicSigKeyFromIssuerJwksUri(as, options, header);\n await validateJwsSignature(protectedHeader, payload, key, signature);\n if (options?.requireDPoP ||\n scheme === 'dpop' ||\n claims.cnf?.jkt !== undefined ||\n request.headers.has('dpop')) {\n await validateDPoP(request, accessToken, claims, options).catch(reassignRSCode);\n }\n return claims;\n}\nfunction reassignRSCode(err) {\n if (err instanceof OperationProcessingError && err?.code === INVALID_REQUEST) {\n err.code = INVALID_RESPONSE;\n }\n throw err;\n}\nexport async function backchannelAuthenticationRequest(as, client, clientAuthentication, parameters, options) {\n assertAs(as);\n assertClient(client);\n const url = resolveEndpoint(as, 'backchannel_authentication_endpoint', client.use_mtls_endpoint_aliases, options?.[allowInsecureRequests] !== true);\n const body = new URLSearchParams(parameters);\n body.set('client_id', client.client_id);\n const headers = prepareHeaders(options?.headers);\n headers.set('accept', 'application/json');\n return authenticatedRequest(as, client, clientAuthentication, url, body, headers, options);\n}\nexport async function processBackchannelAuthenticationResponse(as, client, response) {\n assertAs(as);\n assertClient(client);\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n await checkOAuthBodyError(response, 200, 'Backchannel Authentication Endpoint');\n assertReadableResponse(response);\n const json = await getResponseJsonBody(response);\n assertString(json.auth_req_id, '\"response\" body \"auth_req_id\" property', INVALID_RESPONSE, {\n body: json,\n });\n let expiresIn = typeof json.expires_in !== 'number' ? parseFloat(json.expires_in) : json.expires_in;\n assertNumber(expiresIn, true, '\"response\" body \"expires_in\" property', INVALID_RESPONSE, {\n body: json,\n });\n json.expires_in = expiresIn;\n if (json.interval !== undefined) {\n assertNumber(json.interval, false, '\"response\" body \"interval\" property', INVALID_RESPONSE, {\n body: json,\n });\n }\n return json;\n}\nexport async function backchannelAuthenticationGrantRequest(as, client, clientAuthentication, authReqId, options) {\n assertAs(as);\n assertClient(client);\n assertString(authReqId, '\"authReqId\"');\n const parameters = new URLSearchParams(options?.additionalParameters);\n parameters.set('auth_req_id', authReqId);\n return tokenEndpointRequest(as, client, clientAuthentication, 'urn:openid:params:grant-type:ciba', parameters, options);\n}\nexport async function processBackchannelAuthenticationGrantResponse(as, client, response, options) {\n return processGenericAccessTokenResponse(as, client, response, undefined, options?.[jweDecrypt], options?.recognizedTokenTypes);\n}\nexport async function dynamicClientRegistrationRequest(as, metadata, options) {\n assertAs(as);\n const url = resolveEndpoint(as, 'registration_endpoint', metadata.use_mtls_endpoint_aliases, options?.[allowInsecureRequests] !== true);\n const headers = prepareHeaders(options?.headers);\n headers.set('accept', 'application/json');\n headers.set('content-type', 'application/json');\n const method = 'POST';\n if (options?.DPoP) {\n assertDPoP(options.DPoP);\n await options.DPoP.addProof(url, headers, method, options.initialAccessToken);\n }\n if (options?.initialAccessToken) {\n headers.set('authorization', `${headers.has('dpop') ? 'DPoP' : 'Bearer'} ${options.initialAccessToken}`);\n }\n const response = await (options?.[customFetch] || fetch)(url.href, {\n body: JSON.stringify(metadata),\n headers: Object.fromEntries(headers.entries()),\n method,\n redirect: 'manual',\n signal: signal(url, options?.signal),\n });\n options?.DPoP?.cacheNonce(response, url);\n return response;\n}\nexport async function processDynamicClientRegistrationResponse(response) {\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n await checkOAuthBodyError(response, 201, 'Dynamic Client Registration Endpoint');\n assertReadableResponse(response);\n const json = await getResponseJsonBody(response);\n assertString(json.client_id, '\"response\" body \"client_id\" property', INVALID_RESPONSE, {\n body: json,\n });\n if (json.client_secret !== undefined) {\n assertString(json.client_secret, '\"response\" body \"client_secret\" property', INVALID_RESPONSE, {\n body: json,\n });\n }\n if (json.client_secret) {\n assertNumber(json.client_secret_expires_at, true, '\"response\" body \"client_secret_expires_at\" property', INVALID_RESPONSE, {\n body: json,\n });\n }\n return json;\n}\nexport async function resourceDiscoveryRequest(resourceIdentifier, options) {\n return performDiscovery(resourceIdentifier, 'resourceIdentifier', (url) => {\n prependWellKnown(url, '.well-known/oauth-protected-resource', true);\n return url;\n }, options);\n}\nexport async function processResourceDiscoveryResponse(expectedResourceIdentifier, response) {\n const expected = expectedResourceIdentifier;\n if (!(expected instanceof URL) && expected !== _nodiscoverycheck) {\n throw CodedTypeError('\"expectedResourceIdentifier\" must be an instance of URL', ERR_INVALID_ARG_TYPE);\n }\n if (!looseInstanceOf(response, Response)) {\n throw CodedTypeError('\"response\" must be an instance of Response', ERR_INVALID_ARG_TYPE);\n }\n if (response.status !== 200) {\n throw OPE('\"response\" is not a conform Resource Server Metadata response (unexpected HTTP status code)', RESPONSE_IS_NOT_CONFORM, response);\n }\n assertReadableResponse(response);\n const json = await getResponseJsonBody(response);\n assertString(json.resource, '\"response\" body \"resource\" property', INVALID_RESPONSE, {\n body: json,\n });\n if (expected !== _nodiscoverycheck && new URL(json.resource).href !== expected.href) {\n throw OPE('\"response\" body \"resource\" property does not match the expected value', JSON_ATTRIBUTE_COMPARISON, { expected: expected.href, body: json, attribute: 'resource' });\n }\n return json;\n}\nasync function getResponseJsonBody(response, check = assertApplicationJson) {\n let json;\n try {\n json = await response.json();\n }\n catch (cause) {\n check(response);\n throw OPE('failed to parse \"response\" body as JSON', PARSE_ERROR, cause);\n }\n if (!isJsonObject(json)) {\n throw OPE('\"response\" body must be a top level object', INVALID_RESPONSE, { body: json });\n }\n return json;\n}\nexport const _nopkce = nopkce;\nexport const _nodiscoverycheck = Symbol();\nexport const _expectedIssuer = Symbol();\n//# sourceMappingURL=index.js.map","import { ok, err } from 'neverthrow';\n\nimport type { JsonParseError } from './types.js';\nimport type { Result } from 'neverthrow';\n\nconst ERROR_RAW_TEXT_MAX_LENGTH = 500;\n\n/**\n * Safely parses a JSON string, returning a `Result` instead of throwing.\n *\n * @param text - The raw text to parse as JSON.\n * @returns `ok(parsed)` on success, or `err({ code, rawText, message })` on failure.\n */\nexport function safeJsonParse(text: string): Result<unknown, JsonParseError> {\n try {\n return ok(JSON.parse(text) as unknown);\n } catch (e) {\n return err({\n code: 'JSON_PARSE_ERROR',\n rawText:\n text.length > ERROR_RAW_TEXT_MAX_LENGTH\n ? text.slice(0, ERROR_RAW_TEXT_MAX_LENGTH) + '...'\n : text,\n message: e instanceof Error ? e.message : 'Failed to parse JSON',\n });\n }\n}\n","import { z } from 'zod';\n\n/** Zod schema for the raw token response from the OAuth token endpoint. */\nexport const TokenResponseSchema = z.object({\n access_token: z.string(),\n refresh_token: z.string().nullable().optional().default(null),\n expires_in: z.number(),\n token_type: z.string(),\n scope: z.string().nullable().optional().default(null),\n id_token: z.string().nullable().optional().default(null),\n});\n\n/** Zod schema for a Fanvue user profile. */\nexport const FanvueUserSchema = z.object({\n uuid: z.string(),\n email: z.string(),\n handle: z.string(),\n displayName: z.string(),\n isCreator: z.boolean(),\n avatarUrl: z.string().nullable(),\n bannerUrl: z.string().nullable(),\n createdAt: z.string(),\n updatedAt: z.string().nullable(),\n});\n\n/** Zod schema for the authorize-on-behalf response from the Fanvue platform. */\nexport const AuthorizeOnBehalfResponseSchema = z.object({\n code: z.string(),\n state: z.string(),\n});\n\n/** Zod schema for the session JWT payload. */\nexport const SessionPayloadSchema = z\n .object({\n accessToken: z.string(),\n refreshToken: z.string().nullable(),\n expiresAt: z.number(),\n tokenType: z.string().nullable(),\n scope: z.string().nullable(),\n idToken: z.string().nullable(),\n userUuid: z.string(),\n handle: z.string(),\n displayName: z.string(),\n isCreator: z.boolean(),\n avatarUrl: z.string().nullable(),\n })\n .passthrough();\n","import { ok, err } from 'neverthrow';\nimport * as oauth from 'oauth4webapi';\n\nimport { OAuthErrorBodySchema } from './contracts/errors.js';\nimport { DEFAULT_SCOPES, DEFAULT_ISSUER_URL } from './defaults.js';\nimport { safeJsonParse } from './json.js';\nimport { TokenResponseSchema } from './schemas.js';\n\nimport type { OAuthErrorBody } from './contracts/errors.js';\nimport type { OAuthConfig, TokenResponse, OAuthError } from './types.js';\nimport type { Result } from 'neverthrow';\n\nconst CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded';\nconst OAUTH_TOKEN_ENDPOINT = '/oauth2/token';\n\n/**\n * Reads the authorization server's error body off a failed token response.\n *\n * The status line alone cannot separate a retired refresh token from bad client\n * credentials — both are `400` — so the body is worth keeping. Any failure to\n * read or validate it yields `null`: a missing diagnostic must never replace the\n * error it was attached to. Only `error` and `error_description` survive; the\n * provider's hint/debug fields can echo request details back.\n */\nasync function readOAuthErrorBody(response: Response): Promise<OAuthErrorBody | null> {\n let text: string;\n try {\n text = await response.text();\n } catch {\n return null;\n }\n\n const parsed = safeJsonParse(text);\n if (parsed.isErr()) return null;\n\n const validated = OAuthErrorBodySchema.safeParse(parsed.value);\n return validated.success ? validated.data : null;\n}\n\n/**\n * Builds an OAuth 2.0 authorization URL with PKCE parameters.\n *\n * @param config - The OAuth configuration.\n * @param opts - Optional overrides. Pass `state` to use a deterministic state value.\n * @returns The authorization URL, the PKCE code verifier, and the state parameter.\n */\nexport async function createAuthorizationUrl(\n config: OAuthConfig,\n opts: { state: string | null } | null = null,\n): Promise<{ url: URL; codeVerifier: string; state: string }> {\n const codeVerifier = oauth.generateRandomCodeVerifier();\n const codeChallenge = await oauth.calculatePKCECodeChallenge(codeVerifier);\n const state = opts?.state ?? oauth.generateRandomState();\n\n const issuerUrl = config.issuerUrl ?? DEFAULT_ISSUER_URL;\n const scope =\n config.scopes !== null ? `${DEFAULT_SCOPES} ${config.scopes}`.trim() : DEFAULT_SCOPES;\n\n const url = new URL(`${issuerUrl}/oauth2/auth`);\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('client_id', config.clientId);\n url.searchParams.set('redirect_uri', config.redirectUri);\n url.searchParams.set('scope', scope);\n url.searchParams.set('state', state);\n url.searchParams.set('code_challenge', codeChallenge);\n url.searchParams.set('code_challenge_method', 'S256');\n\n if (config.responseMode !== null) {\n url.searchParams.set('response_mode', config.responseMode);\n }\n if (config.prompt !== null) {\n url.searchParams.set('prompt', config.prompt);\n }\n\n return { url, codeVerifier, state };\n}\n\n/**\n * Exchanges an authorization code for tokens using the OAuth token endpoint.\n *\n * @param config - The OAuth configuration.\n * @param opts - The authorization code, PKCE code verifier, and optional redirect URI override.\n * @returns A `Result` containing `TokenResponse` on success or `OAuthError` on\n * failure. A `TOKEN_EXCHANGE_FAILED` error carries the authorization server's\n * own `oauthError` body when it sent a readable one.\n */\nexport async function exchangeCodeForToken(\n config: OAuthConfig,\n opts: { code: string; codeVerifier: string; redirectUri: string | null },\n): Promise<Result<TokenResponse, OAuthError>> {\n const issuerUrl = config.issuerUrl ?? DEFAULT_ISSUER_URL;\n\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code: opts.code,\n redirect_uri: opts.redirectUri ?? config.redirectUri,\n client_id: config.clientId,\n code_verifier: opts.codeVerifier,\n });\n\n let response: Response;\n try {\n response = await fetch(`${issuerUrl}${OAUTH_TOKEN_ENDPOINT}`, {\n method: 'POST',\n headers: {\n 'Content-Type': CONTENT_TYPE_FORM_URLENCODED,\n Authorization: `Basic ${btoa(`${config.clientId}:${config.clientSecret}`)}`,\n },\n body,\n });\n } catch (error) {\n return err({\n code: 'TOKEN_EXCHANGE_FAILED',\n statusCode: 0,\n message: `Network error during token exchange: ${error instanceof Error ? error.message : String(error)}`,\n oauthError: null,\n });\n }\n\n if (!response.ok) {\n return err({\n code: 'TOKEN_EXCHANGE_FAILED',\n statusCode: response.status,\n message: `Token exchange failed: ${response.status} ${response.statusText}`,\n oauthError: await readOAuthErrorBody(response),\n });\n }\n\n const text = await response.text();\n const parseResult = safeJsonParse(text);\n if (parseResult.isErr()) {\n const { rawText, message } = parseResult.error;\n return err({ code: 'OAUTH_JSON_PARSE_ERROR', rawText, message });\n }\n\n const validated = TokenResponseSchema.safeParse(parseResult.value);\n if (!validated.success) {\n return err({ code: 'OAUTH_VALIDATION_ERROR', message: validated.error.message });\n }\n\n return ok(validated.data);\n}\n\n/**\n * Refreshes an access token using a refresh token.\n *\n * @param config - The OAuth configuration.\n * @param refreshToken - The refresh token to use.\n * @returns A `Result` containing `TokenResponse` on success or `OAuthError` on\n * failure. A `TOKEN_REFRESH_FAILED` error carries the authorization server's\n * own `oauthError` body when it sent a readable one — `invalid_grant` there\n * means the stored refresh token is retired and the creator must reconnect.\n */\nexport async function refreshAccessToken(\n config: OAuthConfig,\n refreshToken: string,\n): Promise<Result<TokenResponse, OAuthError>> {\n const issuerUrl = config.issuerUrl ?? DEFAULT_ISSUER_URL;\n\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: config.clientId,\n });\n\n let response: Response;\n try {\n response = await fetch(`${issuerUrl}${OAUTH_TOKEN_ENDPOINT}`, {\n method: 'POST',\n headers: {\n 'Content-Type': CONTENT_TYPE_FORM_URLENCODED,\n Authorization: `Basic ${btoa(`${config.clientId}:${config.clientSecret}`)}`,\n },\n body,\n });\n } catch (error) {\n return err({\n code: 'TOKEN_REFRESH_FAILED',\n statusCode: 0,\n message: `Network error during token refresh: ${error instanceof Error ? error.message : String(error)}`,\n oauthError: null,\n });\n }\n\n if (!response.ok) {\n return err({\n code: 'TOKEN_REFRESH_FAILED',\n statusCode: response.status,\n message: `Token refresh failed: ${response.status} ${response.statusText}`,\n oauthError: await readOAuthErrorBody(response),\n });\n }\n\n const text = await response.text();\n const parseResult = safeJsonParse(text);\n if (parseResult.isErr()) {\n const { rawText, message } = parseResult.error;\n return err({ code: 'OAUTH_JSON_PARSE_ERROR', rawText, message });\n }\n\n const validated = TokenResponseSchema.safeParse(parseResult.value);\n if (!validated.success) {\n return err({ code: 'OAUTH_VALIDATION_ERROR', message: validated.error.message });\n }\n\n return ok(validated.data);\n}\n","export const encoder = new TextEncoder();\nexport const decoder = new TextDecoder();\nconst MAX_INT32 = 2 ** 32;\nexport function concat(...buffers) {\n const size = buffers.reduce((acc, { length }) => acc + length, 0);\n const buf = new Uint8Array(size);\n let i = 0;\n for (const buffer of buffers) {\n buf.set(buffer, i);\n i += buffer.length;\n }\n return buf;\n}\nfunction writeUInt32BE(buf, value, offset) {\n if (value < 0 || value >= MAX_INT32) {\n throw new RangeError(`value must be >= 0 and <= ${MAX_INT32 - 1}. Received ${value}`);\n }\n buf.set([value >>> 24, value >>> 16, value >>> 8, value & 0xff], offset);\n}\nexport function uint64be(value) {\n const high = Math.floor(value / MAX_INT32);\n const low = value % MAX_INT32;\n const buf = new Uint8Array(8);\n writeUInt32BE(buf, high, 0);\n writeUInt32BE(buf, low, 4);\n return buf;\n}\nexport function uint32be(value) {\n const buf = new Uint8Array(4);\n writeUInt32BE(buf, value);\n return buf;\n}\nexport function encode(string) {\n const bytes = new Uint8Array(string.length);\n for (let i = 0; i < string.length; i++) {\n const code = string.charCodeAt(i);\n if (code > 127) {\n throw new TypeError('non-ASCII string encountered in encode()');\n }\n bytes[i] = code;\n }\n return bytes;\n}\n","export function encodeBase64(input) {\n if (Uint8Array.prototype.toBase64) {\n return input.toBase64();\n }\n const CHUNK_SIZE = 0x8000;\n const arr = [];\n for (let i = 0; i < input.length; i += CHUNK_SIZE) {\n arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));\n }\n return btoa(arr.join(''));\n}\nexport function decodeBase64(encoded) {\n if (Uint8Array.fromBase64) {\n return Uint8Array.fromBase64(encoded);\n }\n const binary = atob(encoded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n","import { encoder, decoder } from '../lib/buffer_utils.js';\nimport { encodeBase64, decodeBase64 } from '../lib/base64.js';\nexport function decode(input) {\n if (Uint8Array.fromBase64) {\n return Uint8Array.fromBase64(typeof input === 'string' ? input : decoder.decode(input), {\n alphabet: 'base64url',\n });\n }\n let encoded = input;\n if (encoded instanceof Uint8Array) {\n encoded = decoder.decode(encoded);\n }\n encoded = encoded.replace(/-/g, '+').replace(/_/g, '/');\n try {\n return decodeBase64(encoded);\n }\n catch {\n throw new TypeError('The input to be decoded is not correctly encoded.');\n }\n}\nexport function encode(input) {\n let unencoded = input;\n if (typeof unencoded === 'string') {\n unencoded = encoder.encode(unencoded);\n }\n if (Uint8Array.prototype.toBase64) {\n return unencoded.toBase64({ alphabet: 'base64url', omitPadding: true });\n }\n return encodeBase64(unencoded).replace(/=/g, '').replace(/\\+/g, '-').replace(/\\//g, '_');\n}\n","const unusable = (name, prop = 'algorithm.name') => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);\nconst isAlgorithm = (algorithm, name) => algorithm.name === name;\nfunction getHashLength(hash) {\n return parseInt(hash.name.slice(4), 10);\n}\nfunction checkHashLength(algorithm, expected) {\n const actual = getHashLength(algorithm.hash);\n if (actual !== expected)\n throw unusable(`SHA-${expected}`, 'algorithm.hash');\n}\nfunction getNamedCurve(alg) {\n switch (alg) {\n case 'ES256':\n return 'P-256';\n case 'ES384':\n return 'P-384';\n case 'ES512':\n return 'P-521';\n default:\n throw new Error('unreachable');\n }\n}\nfunction checkUsage(key, usage) {\n if (usage && !key.usages.includes(usage)) {\n throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);\n }\n}\nexport function checkSigCryptoKey(key, alg, usage) {\n switch (alg) {\n case 'HS256':\n case 'HS384':\n case 'HS512': {\n if (!isAlgorithm(key.algorithm, 'HMAC'))\n throw unusable('HMAC');\n checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));\n break;\n }\n case 'RS256':\n case 'RS384':\n case 'RS512': {\n if (!isAlgorithm(key.algorithm, 'RSASSA-PKCS1-v1_5'))\n throw unusable('RSASSA-PKCS1-v1_5');\n checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));\n break;\n }\n case 'PS256':\n case 'PS384':\n case 'PS512': {\n if (!isAlgorithm(key.algorithm, 'RSA-PSS'))\n throw unusable('RSA-PSS');\n checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));\n break;\n }\n case 'Ed25519':\n case 'EdDSA': {\n if (!isAlgorithm(key.algorithm, 'Ed25519'))\n throw unusable('Ed25519');\n break;\n }\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87': {\n if (!isAlgorithm(key.algorithm, alg))\n throw unusable(alg);\n break;\n }\n case 'ES256':\n case 'ES384':\n case 'ES512': {\n if (!isAlgorithm(key.algorithm, 'ECDSA'))\n throw unusable('ECDSA');\n const expected = getNamedCurve(alg);\n const actual = key.algorithm.namedCurve;\n if (actual !== expected)\n throw unusable(expected, 'algorithm.namedCurve');\n break;\n }\n default:\n throw new TypeError('CryptoKey does not support this operation');\n }\n checkUsage(key, usage);\n}\nexport function checkEncCryptoKey(key, alg, usage) {\n switch (alg) {\n case 'A128GCM':\n case 'A192GCM':\n case 'A256GCM': {\n if (!isAlgorithm(key.algorithm, 'AES-GCM'))\n throw unusable('AES-GCM');\n const expected = parseInt(alg.slice(1, 4), 10);\n const actual = key.algorithm.length;\n if (actual !== expected)\n throw unusable(expected, 'algorithm.length');\n break;\n }\n case 'A128KW':\n case 'A192KW':\n case 'A256KW': {\n if (!isAlgorithm(key.algorithm, 'AES-KW'))\n throw unusable('AES-KW');\n const expected = parseInt(alg.slice(1, 4), 10);\n const actual = key.algorithm.length;\n if (actual !== expected)\n throw unusable(expected, 'algorithm.length');\n break;\n }\n case 'ECDH': {\n switch (key.algorithm.name) {\n case 'ECDH':\n case 'X25519':\n break;\n default:\n throw unusable('ECDH or X25519');\n }\n break;\n }\n case 'PBES2-HS256+A128KW':\n case 'PBES2-HS384+A192KW':\n case 'PBES2-HS512+A256KW':\n if (!isAlgorithm(key.algorithm, 'PBKDF2'))\n throw unusable('PBKDF2');\n break;\n case 'RSA-OAEP':\n case 'RSA-OAEP-256':\n case 'RSA-OAEP-384':\n case 'RSA-OAEP-512': {\n if (!isAlgorithm(key.algorithm, 'RSA-OAEP'))\n throw unusable('RSA-OAEP');\n checkHashLength(key.algorithm, parseInt(alg.slice(9), 10) || 1);\n break;\n }\n default:\n throw new TypeError('CryptoKey does not support this operation');\n }\n checkUsage(key, usage);\n}\n","function message(msg, actual, ...types) {\n types = types.filter(Boolean);\n if (types.length > 2) {\n const last = types.pop();\n msg += `one of type ${types.join(', ')}, or ${last}.`;\n }\n else if (types.length === 2) {\n msg += `one of type ${types[0]} or ${types[1]}.`;\n }\n else {\n msg += `of type ${types[0]}.`;\n }\n if (actual == null) {\n msg += ` Received ${actual}`;\n }\n else if (typeof actual === 'function' && actual.name) {\n msg += ` Received function ${actual.name}`;\n }\n else if (typeof actual === 'object' && actual != null) {\n if (actual.constructor?.name) {\n msg += ` Received an instance of ${actual.constructor.name}`;\n }\n }\n return msg;\n}\nexport const invalidKeyInput = (actual, ...types) => message('Key must be ', actual, ...types);\nexport const withAlg = (alg, actual, ...types) => message(`Key for the ${alg} algorithm must be `, actual, ...types);\n","export class JOSEError extends Error {\n static code = 'ERR_JOSE_GENERIC';\n code = 'ERR_JOSE_GENERIC';\n constructor(message, options) {\n super(message, options);\n this.name = this.constructor.name;\n Error.captureStackTrace?.(this, this.constructor);\n }\n}\nexport class JWTClaimValidationFailed extends JOSEError {\n static code = 'ERR_JWT_CLAIM_VALIDATION_FAILED';\n code = 'ERR_JWT_CLAIM_VALIDATION_FAILED';\n claim;\n reason;\n payload;\n constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {\n super(message, { cause: { claim, reason, payload } });\n this.claim = claim;\n this.reason = reason;\n this.payload = payload;\n }\n}\nexport class JWTExpired extends JOSEError {\n static code = 'ERR_JWT_EXPIRED';\n code = 'ERR_JWT_EXPIRED';\n claim;\n reason;\n payload;\n constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {\n super(message, { cause: { claim, reason, payload } });\n this.claim = claim;\n this.reason = reason;\n this.payload = payload;\n }\n}\nexport class JOSEAlgNotAllowed extends JOSEError {\n static code = 'ERR_JOSE_ALG_NOT_ALLOWED';\n code = 'ERR_JOSE_ALG_NOT_ALLOWED';\n}\nexport class JOSENotSupported extends JOSEError {\n static code = 'ERR_JOSE_NOT_SUPPORTED';\n code = 'ERR_JOSE_NOT_SUPPORTED';\n}\nexport class JWEDecryptionFailed extends JOSEError {\n static code = 'ERR_JWE_DECRYPTION_FAILED';\n code = 'ERR_JWE_DECRYPTION_FAILED';\n constructor(message = 'decryption operation failed', options) {\n super(message, options);\n }\n}\nexport class JWEInvalid extends JOSEError {\n static code = 'ERR_JWE_INVALID';\n code = 'ERR_JWE_INVALID';\n}\nexport class JWSInvalid extends JOSEError {\n static code = 'ERR_JWS_INVALID';\n code = 'ERR_JWS_INVALID';\n}\nexport class JWTInvalid extends JOSEError {\n static code = 'ERR_JWT_INVALID';\n code = 'ERR_JWT_INVALID';\n}\nexport class JWKInvalid extends JOSEError {\n static code = 'ERR_JWK_INVALID';\n code = 'ERR_JWK_INVALID';\n}\nexport class JWKSInvalid extends JOSEError {\n static code = 'ERR_JWKS_INVALID';\n code = 'ERR_JWKS_INVALID';\n}\nexport class JWKSNoMatchingKey extends JOSEError {\n static code = 'ERR_JWKS_NO_MATCHING_KEY';\n code = 'ERR_JWKS_NO_MATCHING_KEY';\n constructor(message = 'no applicable key found in the JSON Web Key Set', options) {\n super(message, options);\n }\n}\nexport class JWKSMultipleMatchingKeys extends JOSEError {\n [Symbol.asyncIterator];\n static code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS';\n code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS';\n constructor(message = 'multiple matching keys found in the JSON Web Key Set', options) {\n super(message, options);\n }\n}\nexport class JWKSTimeout extends JOSEError {\n static code = 'ERR_JWKS_TIMEOUT';\n code = 'ERR_JWKS_TIMEOUT';\n constructor(message = 'request timed out', options) {\n super(message, options);\n }\n}\nexport class JWSSignatureVerificationFailed extends JOSEError {\n static code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';\n code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';\n constructor(message = 'signature verification failed', options) {\n super(message, options);\n }\n}\n","export function assertCryptoKey(key) {\n if (!isCryptoKey(key)) {\n throw new Error('CryptoKey instance expected');\n }\n}\nexport const isCryptoKey = (key) => {\n if (key?.[Symbol.toStringTag] === 'CryptoKey')\n return true;\n try {\n return key instanceof CryptoKey;\n }\n catch {\n return false;\n }\n};\nexport const isKeyObject = (key) => key?.[Symbol.toStringTag] === 'KeyObject';\nexport const isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);\n","import { decode } from '../util/base64url.js';\nexport const unprotected = Symbol();\nexport function assertNotSet(value, name) {\n if (value) {\n throw new TypeError(`${name} can only be called once`);\n }\n}\nexport function decodeBase64url(value, label, ErrorClass) {\n try {\n return decode(value);\n }\n catch {\n throw new ErrorClass(`Failed to base64url decode the ${label}`);\n }\n}\nexport async function digest(algorithm, data) {\n const subtleDigest = `SHA-${algorithm.slice(-3)}`;\n return new Uint8Array(await crypto.subtle.digest(subtleDigest, data));\n}\n","const isObjectLike = (value) => typeof value === 'object' && value !== null;\nexport function isObject(input) {\n if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') {\n return false;\n }\n if (Object.getPrototypeOf(input) === null) {\n return true;\n }\n let proto = input;\n while (Object.getPrototypeOf(proto) !== null) {\n proto = Object.getPrototypeOf(proto);\n }\n return Object.getPrototypeOf(input) === proto;\n}\nexport function isDisjoint(...headers) {\n const sources = headers.filter(Boolean);\n if (sources.length === 0 || sources.length === 1) {\n return true;\n }\n let acc;\n for (const header of sources) {\n const parameters = Object.keys(header);\n if (!acc || acc.size === 0) {\n acc = new Set(parameters);\n continue;\n }\n for (const parameter of parameters) {\n if (acc.has(parameter)) {\n return false;\n }\n acc.add(parameter);\n }\n }\n return true;\n}\nexport const isJWK = (key) => isObject(key) && typeof key.kty === 'string';\nexport const isPrivateJWK = (key) => key.kty !== 'oct' &&\n ((key.kty === 'AKP' && typeof key.priv === 'string') || typeof key.d === 'string');\nexport const isPublicJWK = (key) => key.kty !== 'oct' && key.d === undefined && key.priv === undefined;\nexport const isSecretJWK = (key) => key.kty === 'oct' && typeof key.k === 'string';\n","import { JOSENotSupported } from '../util/errors.js';\nimport { checkSigCryptoKey } from './crypto_key.js';\nimport { invalidKeyInput } from './invalid_key_input.js';\nexport function checkKeyLength(alg, key) {\n if (alg.startsWith('RS') || alg.startsWith('PS')) {\n const { modulusLength } = key.algorithm;\n if (typeof modulusLength !== 'number' || modulusLength < 2048) {\n throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);\n }\n }\n}\nfunction subtleAlgorithm(alg, algorithm) {\n const hash = `SHA-${alg.slice(-3)}`;\n switch (alg) {\n case 'HS256':\n case 'HS384':\n case 'HS512':\n return { hash, name: 'HMAC' };\n case 'PS256':\n case 'PS384':\n case 'PS512':\n return { hash, name: 'RSA-PSS', saltLength: parseInt(alg.slice(-3), 10) >> 3 };\n case 'RS256':\n case 'RS384':\n case 'RS512':\n return { hash, name: 'RSASSA-PKCS1-v1_5' };\n case 'ES256':\n case 'ES384':\n case 'ES512':\n return { hash, name: 'ECDSA', namedCurve: algorithm.namedCurve };\n case 'Ed25519':\n case 'EdDSA':\n return { name: 'Ed25519' };\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87':\n return { name: alg };\n default:\n throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);\n }\n}\nasync function getSigKey(alg, key, usage) {\n if (key instanceof Uint8Array) {\n if (!alg.startsWith('HS')) {\n throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));\n }\n return crypto.subtle.importKey('raw', key, { hash: `SHA-${alg.slice(-3)}`, name: 'HMAC' }, false, [usage]);\n }\n checkSigCryptoKey(key, alg, usage);\n return key;\n}\nexport async function sign(alg, key, data) {\n const cryptoKey = await getSigKey(alg, key, 'sign');\n checkKeyLength(alg, cryptoKey);\n const signature = await crypto.subtle.sign(subtleAlgorithm(alg, cryptoKey.algorithm), cryptoKey, data);\n return new Uint8Array(signature);\n}\nexport async function verify(alg, key, signature, data) {\n const cryptoKey = await getSigKey(alg, key, 'verify');\n checkKeyLength(alg, cryptoKey);\n const algorithm = subtleAlgorithm(alg, cryptoKey.algorithm);\n try {\n return await crypto.subtle.verify(algorithm, cryptoKey, signature, data);\n }\n catch {\n return false;\n }\n}\n","import { JOSENotSupported } from '../util/errors.js';\nconst unsupportedAlg = 'Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value';\nfunction subtleMapping(jwk) {\n let algorithm;\n let keyUsages;\n switch (jwk.kty) {\n case 'AKP': {\n switch (jwk.alg) {\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87':\n algorithm = { name: jwk.alg };\n keyUsages = jwk.priv ? ['sign'] : ['verify'];\n break;\n default:\n throw new JOSENotSupported(unsupportedAlg);\n }\n break;\n }\n case 'RSA': {\n switch (jwk.alg) {\n case 'PS256':\n case 'PS384':\n case 'PS512':\n algorithm = { name: 'RSA-PSS', hash: `SHA-${jwk.alg.slice(-3)}` };\n keyUsages = jwk.d ? ['sign'] : ['verify'];\n break;\n case 'RS256':\n case 'RS384':\n case 'RS512':\n algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${jwk.alg.slice(-3)}` };\n keyUsages = jwk.d ? ['sign'] : ['verify'];\n break;\n case 'RSA-OAEP':\n case 'RSA-OAEP-256':\n case 'RSA-OAEP-384':\n case 'RSA-OAEP-512':\n algorithm = {\n name: 'RSA-OAEP',\n hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`,\n };\n keyUsages = jwk.d ? ['decrypt', 'unwrapKey'] : ['encrypt', 'wrapKey'];\n break;\n default:\n throw new JOSENotSupported(unsupportedAlg);\n }\n break;\n }\n case 'EC': {\n switch (jwk.alg) {\n case 'ES256':\n case 'ES384':\n case 'ES512':\n algorithm = {\n name: 'ECDSA',\n namedCurve: { ES256: 'P-256', ES384: 'P-384', ES512: 'P-521' }[jwk.alg],\n };\n keyUsages = jwk.d ? ['sign'] : ['verify'];\n break;\n case 'ECDH-ES':\n case 'ECDH-ES+A128KW':\n case 'ECDH-ES+A192KW':\n case 'ECDH-ES+A256KW':\n algorithm = { name: 'ECDH', namedCurve: jwk.crv };\n keyUsages = jwk.d ? ['deriveBits'] : [];\n break;\n default:\n throw new JOSENotSupported(unsupportedAlg);\n }\n break;\n }\n case 'OKP': {\n switch (jwk.alg) {\n case 'Ed25519':\n case 'EdDSA':\n algorithm = { name: 'Ed25519' };\n keyUsages = jwk.d ? ['sign'] : ['verify'];\n break;\n case 'ECDH-ES':\n case 'ECDH-ES+A128KW':\n case 'ECDH-ES+A192KW':\n case 'ECDH-ES+A256KW':\n algorithm = { name: jwk.crv };\n keyUsages = jwk.d ? ['deriveBits'] : [];\n break;\n default:\n throw new JOSENotSupported(unsupportedAlg);\n }\n break;\n }\n default:\n throw new JOSENotSupported('Invalid or unsupported JWK \"kty\" (Key Type) Parameter value');\n }\n return { algorithm, keyUsages };\n}\nexport async function jwkToKey(jwk) {\n if (!jwk.alg) {\n throw new TypeError('\"alg\" argument is required when \"jwk.alg\" is not present');\n }\n const { algorithm, keyUsages } = subtleMapping(jwk);\n const keyData = { ...jwk };\n if (keyData.kty !== 'AKP') {\n delete keyData.alg;\n }\n delete keyData.use;\n return crypto.subtle.importKey('jwk', keyData, algorithm, jwk.ext ?? (jwk.d || jwk.priv ? false : true), jwk.key_ops ?? keyUsages);\n}\n","import { isJWK } from './type_checks.js';\nimport { decode } from '../util/base64url.js';\nimport { jwkToKey } from './jwk_to_key.js';\nimport { isCryptoKey, isKeyObject } from './is_key_like.js';\nconst unusableForAlg = 'given KeyObject instance cannot be used for this algorithm';\nlet cache;\nconst handleJWK = async (key, jwk, alg, freeze = false) => {\n cache ||= new WeakMap();\n let cached = cache.get(key);\n if (cached?.[alg]) {\n return cached[alg];\n }\n const cryptoKey = await jwkToKey({ ...jwk, alg });\n if (freeze)\n Object.freeze(key);\n if (!cached) {\n cache.set(key, { [alg]: cryptoKey });\n }\n else {\n cached[alg] = cryptoKey;\n }\n return cryptoKey;\n};\nconst handleKeyObject = (keyObject, alg) => {\n cache ||= new WeakMap();\n let cached = cache.get(keyObject);\n if (cached?.[alg]) {\n return cached[alg];\n }\n const isPublic = keyObject.type === 'public';\n const extractable = isPublic ? true : false;\n let cryptoKey;\n if (keyObject.asymmetricKeyType === 'x25519') {\n switch (alg) {\n case 'ECDH-ES':\n case 'ECDH-ES+A128KW':\n case 'ECDH-ES+A192KW':\n case 'ECDH-ES+A256KW':\n break;\n default:\n throw new TypeError(unusableForAlg);\n }\n cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, isPublic ? [] : ['deriveBits']);\n }\n if (keyObject.asymmetricKeyType === 'ed25519') {\n if (alg !== 'EdDSA' && alg !== 'Ed25519') {\n throw new TypeError(unusableForAlg);\n }\n cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [\n isPublic ? 'verify' : 'sign',\n ]);\n }\n switch (keyObject.asymmetricKeyType) {\n case 'ml-dsa-44':\n case 'ml-dsa-65':\n case 'ml-dsa-87': {\n if (alg !== keyObject.asymmetricKeyType.toUpperCase()) {\n throw new TypeError(unusableForAlg);\n }\n cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [\n isPublic ? 'verify' : 'sign',\n ]);\n }\n }\n if (keyObject.asymmetricKeyType === 'rsa') {\n let hash;\n switch (alg) {\n case 'RSA-OAEP':\n hash = 'SHA-1';\n break;\n case 'RS256':\n case 'PS256':\n case 'RSA-OAEP-256':\n hash = 'SHA-256';\n break;\n case 'RS384':\n case 'PS384':\n case 'RSA-OAEP-384':\n hash = 'SHA-384';\n break;\n case 'RS512':\n case 'PS512':\n case 'RSA-OAEP-512':\n hash = 'SHA-512';\n break;\n default:\n throw new TypeError(unusableForAlg);\n }\n if (alg.startsWith('RSA-OAEP')) {\n return keyObject.toCryptoKey({\n name: 'RSA-OAEP',\n hash,\n }, extractable, isPublic ? ['encrypt'] : ['decrypt']);\n }\n cryptoKey = keyObject.toCryptoKey({\n name: alg.startsWith('PS') ? 'RSA-PSS' : 'RSASSA-PKCS1-v1_5',\n hash,\n }, extractable, [isPublic ? 'verify' : 'sign']);\n }\n if (keyObject.asymmetricKeyType === 'ec') {\n const nist = new Map([\n ['prime256v1', 'P-256'],\n ['secp384r1', 'P-384'],\n ['secp521r1', 'P-521'],\n ]);\n const namedCurve = nist.get(keyObject.asymmetricKeyDetails?.namedCurve);\n if (!namedCurve) {\n throw new TypeError(unusableForAlg);\n }\n const expectedCurve = { ES256: 'P-256', ES384: 'P-384', ES512: 'P-521' };\n if (expectedCurve[alg] && namedCurve === expectedCurve[alg]) {\n cryptoKey = keyObject.toCryptoKey({\n name: 'ECDSA',\n namedCurve,\n }, extractable, [isPublic ? 'verify' : 'sign']);\n }\n if (alg.startsWith('ECDH-ES')) {\n cryptoKey = keyObject.toCryptoKey({\n name: 'ECDH',\n namedCurve,\n }, extractable, isPublic ? [] : ['deriveBits']);\n }\n }\n if (!cryptoKey) {\n throw new TypeError(unusableForAlg);\n }\n if (!cached) {\n cache.set(keyObject, { [alg]: cryptoKey });\n }\n else {\n cached[alg] = cryptoKey;\n }\n return cryptoKey;\n};\nexport async function normalizeKey(key, alg) {\n if (key instanceof Uint8Array) {\n return key;\n }\n if (isCryptoKey(key)) {\n return key;\n }\n if (isKeyObject(key)) {\n if (key.type === 'secret') {\n return key.export();\n }\n if ('toCryptoKey' in key && typeof key.toCryptoKey === 'function') {\n try {\n return handleKeyObject(key, alg);\n }\n catch (err) {\n if (err instanceof TypeError) {\n throw err;\n }\n }\n }\n let jwk = key.export({ format: 'jwk' });\n return handleJWK(key, jwk, alg);\n }\n if (isJWK(key)) {\n if (key.k) {\n return decode(key.k);\n }\n return handleJWK(key, key, alg, true);\n }\n throw new Error('unreachable');\n}\n","import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.js';\nexport function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {\n if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined) {\n throw new Err('\"crit\" (Critical) Header Parameter MUST be integrity protected');\n }\n if (!protectedHeader || protectedHeader.crit === undefined) {\n return new Set();\n }\n if (!Array.isArray(protectedHeader.crit) ||\n protectedHeader.crit.length === 0 ||\n protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) {\n throw new Err('\"crit\" (Critical) Header Parameter MUST be an array of non-empty strings when present');\n }\n let recognized;\n if (recognizedOption !== undefined) {\n recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]);\n }\n else {\n recognized = recognizedDefault;\n }\n for (const parameter of protectedHeader.crit) {\n if (!recognized.has(parameter)) {\n throw new JOSENotSupported(`Extension Header Parameter \"${parameter}\" is not recognized`);\n }\n if (joseHeader[parameter] === undefined) {\n throw new Err(`Extension Header Parameter \"${parameter}\" is missing`);\n }\n if (recognized.get(parameter) && protectedHeader[parameter] === undefined) {\n throw new Err(`Extension Header Parameter \"${parameter}\" MUST be integrity protected`);\n }\n }\n return new Set(protectedHeader.crit);\n}\n","export function validateAlgorithms(option, algorithms) {\n if (algorithms !== undefined &&\n (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== 'string'))) {\n throw new TypeError(`\"${option}\" option must be an array of strings`);\n }\n if (!algorithms) {\n return undefined;\n }\n return new Set(algorithms);\n}\n","import { withAlg as invalidKeyInput } from './invalid_key_input.js';\nimport { isKeyLike } from './is_key_like.js';\nimport * as jwk from './type_checks.js';\nconst tag = (key) => key?.[Symbol.toStringTag];\nconst jwkMatchesOp = (alg, key, usage) => {\n if (key.use !== undefined) {\n let expected;\n switch (usage) {\n case 'sign':\n case 'verify':\n expected = 'sig';\n break;\n case 'encrypt':\n case 'decrypt':\n expected = 'enc';\n break;\n }\n if (key.use !== expected) {\n throw new TypeError(`Invalid key for this operation, its \"use\" must be \"${expected}\" when present`);\n }\n }\n if (key.alg !== undefined && key.alg !== alg) {\n throw new TypeError(`Invalid key for this operation, its \"alg\" must be \"${alg}\" when present`);\n }\n if (Array.isArray(key.key_ops)) {\n let expectedKeyOp;\n switch (true) {\n case usage === 'sign' || usage === 'verify':\n case alg === 'dir':\n case alg.includes('CBC-HS'):\n expectedKeyOp = usage;\n break;\n case alg.startsWith('PBES2'):\n expectedKeyOp = 'deriveBits';\n break;\n case /^A\\d{3}(?:GCM)?(?:KW)?$/.test(alg):\n if (!alg.includes('GCM') && alg.endsWith('KW')) {\n expectedKeyOp = usage === 'encrypt' ? 'wrapKey' : 'unwrapKey';\n }\n else {\n expectedKeyOp = usage;\n }\n break;\n case usage === 'encrypt' && alg.startsWith('RSA'):\n expectedKeyOp = 'wrapKey';\n break;\n case usage === 'decrypt':\n expectedKeyOp = alg.startsWith('RSA') ? 'unwrapKey' : 'deriveBits';\n break;\n }\n if (expectedKeyOp && key.key_ops?.includes?.(expectedKeyOp) === false) {\n throw new TypeError(`Invalid key for this operation, its \"key_ops\" must include \"${expectedKeyOp}\" when present`);\n }\n }\n return true;\n};\nconst symmetricTypeCheck = (alg, key, usage) => {\n if (key instanceof Uint8Array)\n return;\n if (jwk.isJWK(key)) {\n if (jwk.isSecretJWK(key) && jwkMatchesOp(alg, key, usage))\n return;\n throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK \"kty\" (Key Type) equal to \"oct\" and the JWK \"k\" (Key Value) present`);\n }\n if (!isKeyLike(key)) {\n throw new TypeError(invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key', 'Uint8Array'));\n }\n if (key.type !== 'secret') {\n throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type \"secret\"`);\n }\n};\nconst asymmetricTypeCheck = (alg, key, usage) => {\n if (jwk.isJWK(key)) {\n switch (usage) {\n case 'decrypt':\n case 'sign':\n if (jwk.isPrivateJWK(key) && jwkMatchesOp(alg, key, usage))\n return;\n throw new TypeError(`JSON Web Key for this operation must be a private JWK`);\n case 'encrypt':\n case 'verify':\n if (jwk.isPublicJWK(key) && jwkMatchesOp(alg, key, usage))\n return;\n throw new TypeError(`JSON Web Key for this operation must be a public JWK`);\n }\n }\n if (!isKeyLike(key)) {\n throw new TypeError(invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));\n }\n if (key.type === 'secret') {\n throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type \"secret\"`);\n }\n if (key.type === 'public') {\n switch (usage) {\n case 'sign':\n throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type \"private\"`);\n case 'decrypt':\n throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type \"private\"`);\n }\n }\n if (key.type === 'private') {\n switch (usage) {\n case 'verify':\n throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type \"public\"`);\n case 'encrypt':\n throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type \"public\"`);\n }\n }\n};\nexport function checkKeyType(alg, key, usage) {\n switch (alg.substring(0, 2)) {\n case 'A1':\n case 'A2':\n case 'di':\n case 'HS':\n case 'PB':\n symmetricTypeCheck(alg, key, usage);\n break;\n default:\n asymmetricTypeCheck(alg, key, usage);\n }\n}\n","import { decode as b64u } from '../../util/base64url.js';\nimport { verify } from '../../lib/signing.js';\nimport { JOSEAlgNotAllowed, JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.js';\nimport { concat, encoder, decoder, encode } from '../../lib/buffer_utils.js';\nimport { decodeBase64url } from '../../lib/helpers.js';\nimport { isDisjoint } from '../../lib/type_checks.js';\nimport { isObject } from '../../lib/type_checks.js';\nimport { checkKeyType } from '../../lib/check_key_type.js';\nimport { validateCrit } from '../../lib/validate_crit.js';\nimport { validateAlgorithms } from '../../lib/validate_algorithms.js';\nimport { normalizeKey } from '../../lib/normalize_key.js';\nexport async function flattenedVerify(jws, key, options) {\n if (!isObject(jws)) {\n throw new JWSInvalid('Flattened JWS must be an object');\n }\n if (jws.protected === undefined && jws.header === undefined) {\n throw new JWSInvalid('Flattened JWS must have either of the \"protected\" or \"header\" members');\n }\n if (jws.protected !== undefined && typeof jws.protected !== 'string') {\n throw new JWSInvalid('JWS Protected Header incorrect type');\n }\n if (jws.payload === undefined) {\n throw new JWSInvalid('JWS Payload missing');\n }\n if (typeof jws.signature !== 'string') {\n throw new JWSInvalid('JWS Signature missing or incorrect type');\n }\n if (jws.header !== undefined && !isObject(jws.header)) {\n throw new JWSInvalid('JWS Unprotected Header incorrect type');\n }\n let parsedProt = {};\n if (jws.protected) {\n try {\n const protectedHeader = b64u(jws.protected);\n parsedProt = JSON.parse(decoder.decode(protectedHeader));\n }\n catch {\n throw new JWSInvalid('JWS Protected Header is invalid');\n }\n }\n if (!isDisjoint(parsedProt, jws.header)) {\n throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint');\n }\n const joseHeader = {\n ...parsedProt,\n ...jws.header,\n };\n const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options?.crit, parsedProt, joseHeader);\n let b64 = true;\n if (extensions.has('b64')) {\n b64 = parsedProt.b64;\n if (typeof b64 !== 'boolean') {\n throw new JWSInvalid('The \"b64\" (base64url-encode payload) Header Parameter must be a boolean');\n }\n }\n const { alg } = joseHeader;\n if (typeof alg !== 'string' || !alg) {\n throw new JWSInvalid('JWS \"alg\" (Algorithm) Header Parameter missing or invalid');\n }\n const algorithms = options && validateAlgorithms('algorithms', options.algorithms);\n if (algorithms && !algorithms.has(alg)) {\n throw new JOSEAlgNotAllowed('\"alg\" (Algorithm) Header Parameter value not allowed');\n }\n if (b64) {\n if (typeof jws.payload !== 'string') {\n throw new JWSInvalid('JWS Payload must be a string');\n }\n }\n else if (typeof jws.payload !== 'string' && !(jws.payload instanceof Uint8Array)) {\n throw new JWSInvalid('JWS Payload must be a string or an Uint8Array instance');\n }\n let resolvedKey = false;\n if (typeof key === 'function') {\n key = await key(parsedProt, jws);\n resolvedKey = true;\n }\n checkKeyType(alg, key, 'verify');\n const data = concat(jws.protected !== undefined ? encode(jws.protected) : new Uint8Array(), encode('.'), typeof jws.payload === 'string'\n ? b64\n ? encode(jws.payload)\n : encoder.encode(jws.payload)\n : jws.payload);\n const signature = decodeBase64url(jws.signature, 'signature', JWSInvalid);\n const k = await normalizeKey(key, alg);\n const verified = await verify(alg, k, signature, data);\n if (!verified) {\n throw new JWSSignatureVerificationFailed();\n }\n let payload;\n if (b64) {\n payload = decodeBase64url(jws.payload, 'payload', JWSInvalid);\n }\n else if (typeof jws.payload === 'string') {\n payload = encoder.encode(jws.payload);\n }\n else {\n payload = jws.payload;\n }\n const result = { payload };\n if (jws.protected !== undefined) {\n result.protectedHeader = parsedProt;\n }\n if (jws.header !== undefined) {\n result.unprotectedHeader = jws.header;\n }\n if (resolvedKey) {\n return { ...result, key: k };\n }\n return result;\n}\n","import { flattenedVerify } from '../flattened/verify.js';\nimport { JWSInvalid } from '../../util/errors.js';\nimport { decoder } from '../../lib/buffer_utils.js';\nexport async function compactVerify(jws, key, options) {\n if (jws instanceof Uint8Array) {\n jws = decoder.decode(jws);\n }\n if (typeof jws !== 'string') {\n throw new JWSInvalid('Compact JWS must be a string or Uint8Array');\n }\n const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.');\n if (length !== 3) {\n throw new JWSInvalid('Invalid Compact JWS');\n }\n const verified = await flattenedVerify({ payload, protected: protectedHeader, signature }, key, options);\n const result = { payload: verified.payload, protectedHeader: verified.protectedHeader };\n if (typeof key === 'function') {\n return { ...result, key: verified.key };\n }\n return result;\n}\n","import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from '../util/errors.js';\nimport { encoder, decoder } from './buffer_utils.js';\nimport { isObject } from './type_checks.js';\nconst epoch = (date) => Math.floor(date.getTime() / 1000);\nconst minute = 60;\nconst hour = minute * 60;\nconst day = hour * 24;\nconst week = day * 7;\nconst year = day * 365.25;\nconst REGEX = /^(\\+|\\-)? ?(\\d+|\\d+\\.\\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;\nexport function secs(str) {\n const matched = REGEX.exec(str);\n if (!matched || (matched[4] && matched[1])) {\n throw new TypeError('Invalid time period format');\n }\n const value = parseFloat(matched[2]);\n const unit = matched[3].toLowerCase();\n let numericDate;\n switch (unit) {\n case 'sec':\n case 'secs':\n case 'second':\n case 'seconds':\n case 's':\n numericDate = Math.round(value);\n break;\n case 'minute':\n case 'minutes':\n case 'min':\n case 'mins':\n case 'm':\n numericDate = Math.round(value * minute);\n break;\n case 'hour':\n case 'hours':\n case 'hr':\n case 'hrs':\n case 'h':\n numericDate = Math.round(value * hour);\n break;\n case 'day':\n case 'days':\n case 'd':\n numericDate = Math.round(value * day);\n break;\n case 'week':\n case 'weeks':\n case 'w':\n numericDate = Math.round(value * week);\n break;\n default:\n numericDate = Math.round(value * year);\n break;\n }\n if (matched[1] === '-' || matched[4] === 'ago') {\n return -numericDate;\n }\n return numericDate;\n}\nfunction validateInput(label, input) {\n if (!Number.isFinite(input)) {\n throw new TypeError(`Invalid ${label} input`);\n }\n return input;\n}\nconst normalizeTyp = (value) => {\n if (value.includes('/')) {\n return value.toLowerCase();\n }\n return `application/${value.toLowerCase()}`;\n};\nconst checkAudiencePresence = (audPayload, audOption) => {\n if (typeof audPayload === 'string') {\n return audOption.includes(audPayload);\n }\n if (Array.isArray(audPayload)) {\n return audOption.some(Set.prototype.has.bind(new Set(audPayload)));\n }\n return false;\n};\nexport function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {\n let payload;\n try {\n payload = JSON.parse(decoder.decode(encodedPayload));\n }\n catch {\n }\n if (!isObject(payload)) {\n throw new JWTInvalid('JWT Claims Set must be a top-level JSON object');\n }\n const { typ } = options;\n if (typ &&\n (typeof protectedHeader.typ !== 'string' ||\n normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {\n throw new JWTClaimValidationFailed('unexpected \"typ\" JWT header value', payload, 'typ', 'check_failed');\n }\n const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;\n const presenceCheck = [...requiredClaims];\n if (maxTokenAge !== undefined)\n presenceCheck.push('iat');\n if (audience !== undefined)\n presenceCheck.push('aud');\n if (subject !== undefined)\n presenceCheck.push('sub');\n if (issuer !== undefined)\n presenceCheck.push('iss');\n for (const claim of new Set(presenceCheck.reverse())) {\n if (!(claim in payload)) {\n throw new JWTClaimValidationFailed(`missing required \"${claim}\" claim`, payload, claim, 'missing');\n }\n }\n if (issuer &&\n !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {\n throw new JWTClaimValidationFailed('unexpected \"iss\" claim value', payload, 'iss', 'check_failed');\n }\n if (subject && payload.sub !== subject) {\n throw new JWTClaimValidationFailed('unexpected \"sub\" claim value', payload, 'sub', 'check_failed');\n }\n if (audience &&\n !checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) {\n throw new JWTClaimValidationFailed('unexpected \"aud\" claim value', payload, 'aud', 'check_failed');\n }\n let tolerance;\n switch (typeof options.clockTolerance) {\n case 'string':\n tolerance = secs(options.clockTolerance);\n break;\n case 'number':\n tolerance = options.clockTolerance;\n break;\n case 'undefined':\n tolerance = 0;\n break;\n default:\n throw new TypeError('Invalid clockTolerance option type');\n }\n const { currentDate } = options;\n const now = epoch(currentDate || new Date());\n if ((payload.iat !== undefined || maxTokenAge) && typeof payload.iat !== 'number') {\n throw new JWTClaimValidationFailed('\"iat\" claim must be a number', payload, 'iat', 'invalid');\n }\n if (payload.nbf !== undefined) {\n if (typeof payload.nbf !== 'number') {\n throw new JWTClaimValidationFailed('\"nbf\" claim must be a number', payload, 'nbf', 'invalid');\n }\n if (payload.nbf > now + tolerance) {\n throw new JWTClaimValidationFailed('\"nbf\" claim timestamp check failed', payload, 'nbf', 'check_failed');\n }\n }\n if (payload.exp !== undefined) {\n if (typeof payload.exp !== 'number') {\n throw new JWTClaimValidationFailed('\"exp\" claim must be a number', payload, 'exp', 'invalid');\n }\n if (payload.exp <= now - tolerance) {\n throw new JWTExpired('\"exp\" claim timestamp check failed', payload, 'exp', 'check_failed');\n }\n }\n if (maxTokenAge) {\n const age = now - payload.iat;\n const max = typeof maxTokenAge === 'number' ? maxTokenAge : secs(maxTokenAge);\n if (age - tolerance > max) {\n throw new JWTExpired('\"iat\" claim timestamp check failed (too far in the past)', payload, 'iat', 'check_failed');\n }\n if (age < 0 - tolerance) {\n throw new JWTClaimValidationFailed('\"iat\" claim timestamp check failed (it should be in the past)', payload, 'iat', 'check_failed');\n }\n }\n return payload;\n}\nexport class JWTClaimsBuilder {\n #payload;\n constructor(payload) {\n if (!isObject(payload)) {\n throw new TypeError('JWT Claims Set MUST be an object');\n }\n this.#payload = structuredClone(payload);\n }\n data() {\n return encoder.encode(JSON.stringify(this.#payload));\n }\n get iss() {\n return this.#payload.iss;\n }\n set iss(value) {\n this.#payload.iss = value;\n }\n get sub() {\n return this.#payload.sub;\n }\n set sub(value) {\n this.#payload.sub = value;\n }\n get aud() {\n return this.#payload.aud;\n }\n set aud(value) {\n this.#payload.aud = value;\n }\n set jti(value) {\n this.#payload.jti = value;\n }\n set nbf(value) {\n if (typeof value === 'number') {\n this.#payload.nbf = validateInput('setNotBefore', value);\n }\n else if (value instanceof Date) {\n this.#payload.nbf = validateInput('setNotBefore', epoch(value));\n }\n else {\n this.#payload.nbf = epoch(new Date()) + secs(value);\n }\n }\n set exp(value) {\n if (typeof value === 'number') {\n this.#payload.exp = validateInput('setExpirationTime', value);\n }\n else if (value instanceof Date) {\n this.#payload.exp = validateInput('setExpirationTime', epoch(value));\n }\n else {\n this.#payload.exp = epoch(new Date()) + secs(value);\n }\n }\n set iat(value) {\n if (value === undefined) {\n this.#payload.iat = epoch(new Date());\n }\n else if (value instanceof Date) {\n this.#payload.iat = validateInput('setIssuedAt', epoch(value));\n }\n else if (typeof value === 'string') {\n this.#payload.iat = validateInput('setIssuedAt', epoch(new Date()) + secs(value));\n }\n else {\n this.#payload.iat = validateInput('setIssuedAt', value);\n }\n }\n}\n","import { compactVerify } from '../jws/compact/verify.js';\nimport { validateClaimsSet } from '../lib/jwt_claims_set.js';\nimport { JWTInvalid } from '../util/errors.js';\nexport async function jwtVerify(jwt, key, options) {\n const verified = await compactVerify(jwt, key, options);\n if (verified.protectedHeader.crit?.includes('b64') && verified.protectedHeader.b64 === false) {\n throw new JWTInvalid('JWTs MUST NOT use unencoded payload');\n }\n const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);\n const result = { payload, protectedHeader: verified.protectedHeader };\n if (typeof key === 'function') {\n return { ...result, key: verified.key };\n }\n return result;\n}\n","import { encode as b64u } from '../../util/base64url.js';\nimport { sign } from '../../lib/signing.js';\nimport { isDisjoint } from '../../lib/type_checks.js';\nimport { JWSInvalid } from '../../util/errors.js';\nimport { concat, encode } from '../../lib/buffer_utils.js';\nimport { checkKeyType } from '../../lib/check_key_type.js';\nimport { validateCrit } from '../../lib/validate_crit.js';\nimport { normalizeKey } from '../../lib/normalize_key.js';\nimport { assertNotSet } from '../../lib/helpers.js';\nexport class FlattenedSign {\n #payload;\n #protectedHeader;\n #unprotectedHeader;\n constructor(payload) {\n if (!(payload instanceof Uint8Array)) {\n throw new TypeError('payload must be an instance of Uint8Array');\n }\n this.#payload = payload;\n }\n setProtectedHeader(protectedHeader) {\n assertNotSet(this.#protectedHeader, 'setProtectedHeader');\n this.#protectedHeader = protectedHeader;\n return this;\n }\n setUnprotectedHeader(unprotectedHeader) {\n assertNotSet(this.#unprotectedHeader, 'setUnprotectedHeader');\n this.#unprotectedHeader = unprotectedHeader;\n return this;\n }\n async sign(key, options) {\n if (!this.#protectedHeader && !this.#unprotectedHeader) {\n throw new JWSInvalid('either setProtectedHeader or setUnprotectedHeader must be called before #sign()');\n }\n if (!isDisjoint(this.#protectedHeader, this.#unprotectedHeader)) {\n throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint');\n }\n const joseHeader = {\n ...this.#protectedHeader,\n ...this.#unprotectedHeader,\n };\n const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options?.crit, this.#protectedHeader, joseHeader);\n let b64 = true;\n if (extensions.has('b64')) {\n b64 = this.#protectedHeader.b64;\n if (typeof b64 !== 'boolean') {\n throw new JWSInvalid('The \"b64\" (base64url-encode payload) Header Parameter must be a boolean');\n }\n }\n const { alg } = joseHeader;\n if (typeof alg !== 'string' || !alg) {\n throw new JWSInvalid('JWS \"alg\" (Algorithm) Header Parameter missing or invalid');\n }\n checkKeyType(alg, key, 'sign');\n let payloadS;\n let payloadB;\n if (b64) {\n payloadS = b64u(this.#payload);\n payloadB = encode(payloadS);\n }\n else {\n payloadB = this.#payload;\n payloadS = '';\n }\n let protectedHeaderString;\n let protectedHeaderBytes;\n if (this.#protectedHeader) {\n protectedHeaderString = b64u(JSON.stringify(this.#protectedHeader));\n protectedHeaderBytes = encode(protectedHeaderString);\n }\n else {\n protectedHeaderString = '';\n protectedHeaderBytes = new Uint8Array();\n }\n const data = concat(protectedHeaderBytes, encode('.'), payloadB);\n const k = await normalizeKey(key, alg);\n const signature = await sign(alg, k, data);\n const jws = {\n signature: b64u(signature),\n payload: payloadS,\n };\n if (this.#unprotectedHeader) {\n jws.header = this.#unprotectedHeader;\n }\n if (this.#protectedHeader) {\n jws.protected = protectedHeaderString;\n }\n return jws;\n }\n}\n","import { FlattenedSign } from '../flattened/sign.js';\nexport class CompactSign {\n #flattened;\n constructor(payload) {\n this.#flattened = new FlattenedSign(payload);\n }\n setProtectedHeader(protectedHeader) {\n this.#flattened.setProtectedHeader(protectedHeader);\n return this;\n }\n async sign(key, options) {\n const jws = await this.#flattened.sign(key, options);\n if (jws.payload === undefined) {\n throw new TypeError('use the flattened module for creating JWS with b64: false');\n }\n return `${jws.protected}.${jws.payload}.${jws.signature}`;\n }\n}\n","import { CompactSign } from '../jws/compact/sign.js';\nimport { JWTInvalid } from '../util/errors.js';\nimport { JWTClaimsBuilder } from '../lib/jwt_claims_set.js';\nexport class SignJWT {\n #protectedHeader;\n #jwt;\n constructor(payload = {}) {\n this.#jwt = new JWTClaimsBuilder(payload);\n }\n setIssuer(issuer) {\n this.#jwt.iss = issuer;\n return this;\n }\n setSubject(subject) {\n this.#jwt.sub = subject;\n return this;\n }\n setAudience(audience) {\n this.#jwt.aud = audience;\n return this;\n }\n setJti(jwtId) {\n this.#jwt.jti = jwtId;\n return this;\n }\n setNotBefore(input) {\n this.#jwt.nbf = input;\n return this;\n }\n setExpirationTime(input) {\n this.#jwt.exp = input;\n return this;\n }\n setIssuedAt(input) {\n this.#jwt.iat = input;\n return this;\n }\n setProtectedHeader(protectedHeader) {\n this.#protectedHeader = protectedHeader;\n return this;\n }\n async sign(key, options) {\n const sig = new CompactSign(this.#jwt.data());\n sig.setProtectedHeader(this.#protectedHeader);\n if (Array.isArray(this.#protectedHeader?.crit) &&\n this.#protectedHeader.crit.includes('b64') &&\n this.#protectedHeader.b64 === false) {\n throw new JWTInvalid('JWTs MUST NOT use unencoded payload');\n }\n return sig.sign(key, options);\n }\n}\n","import { SignJWT, jwtVerify } from 'jose';\nimport { ok, err, type Result } from 'neverthrow';\n\nimport { SessionPayloadSchema } from './schemas.js';\n\nimport type { SessionPayload, SessionVerifyError } from './types.js';\nimport type { JWTPayload } from 'jose';\n\n/**\n * Creates a signed JWT containing the given session payload.\n *\n * @param secret - The secret key used to sign the JWT.\n * @param payload - The session data to embed in the token.\n * @param expiresIn - How long until the token expires (e.g., `\"30d\"`), or `null` for the default (`\"30d\"`).\n * @returns The signed JWT string.\n */\nexport async function createSessionJwt(\n secret: string,\n payload: SessionPayload,\n expiresIn: string | null = null,\n): Promise<string> {\n const key = new TextEncoder().encode(secret);\n\n return new SignJWT({ ...payload } as JWTPayload)\n .setProtectedHeader({ alg: 'HS256' })\n .setIssuedAt()\n .setExpirationTime(expiresIn ?? '30d')\n .sign(key);\n}\n\n/**\n * Verifies a session JWT and returns the validated session payload.\n *\n * @param secret - The secret key used to verify the JWT signature.\n * @param token - The JWT string to verify.\n * @returns A {@link Result} containing the validated {@link SessionPayload}, or a {@link SessionVerifyError}.\n */\nexport async function verifySessionJwt(\n secret: string,\n token: string,\n): Promise<Result<SessionPayload, SessionVerifyError>> {\n const key = new TextEncoder().encode(secret);\n\n let payload: JWTPayload;\n try {\n const verified = await jwtVerify(token, key);\n payload = verified.payload;\n } catch (e) {\n return err({\n code: 'JWT_VERIFY_FAILED',\n message: e instanceof Error ? e.message : 'JWT verification failed',\n });\n }\n\n const parsed = SessionPayloadSchema.safeParse(payload);\n if (!parsed.success) {\n return err({\n code: 'SESSION_VALIDATION_ERROR',\n message: parsed.error.message,\n });\n }\n\n return ok(parsed.data);\n}\n","import { ok, err } from 'neverthrow';\nimport * as oauth from 'oauth4webapi';\n\nimport { DEFAULT_PLATFORM_URL } from './defaults.js';\nimport { safeJsonParse } from './json.js';\nimport { exchangeCodeForToken } from './oauth.js';\nimport { AuthorizeOnBehalfResponseSchema } from './schemas.js';\n\nimport type { EmbeddedAuthConfig, EmbeddedAuthError, OAuthError, TokenResponse } from './types.js';\nimport type { Result } from 'neverthrow';\n\nconst AUTHORIZE_ON_BEHALF_PATH = '/api/v1/app-integrations/authorize-on-behalf';\nconst SESSION_TOKEN_QUERY_PARAM = 'token';\nconst THEME_QUERY_PARAM = 'theme';\n\n/**\n * The creator's active colour scheme, as resolved by Fanvue.\n *\n * Fanvue resolves a creator's \"system\" preference to the scheme actually being\n * rendered, so this is always a definite value — never `'system'`.\n */\nexport type FanvueTheme = 'light' | 'dark';\n\n/**\n * Extracts the embedded session token from a URL.\n *\n * When Fanvue opens an embedded app, it loads the app's embed URL with a\n * short-lived session token appended as a `?token=` query parameter.\n *\n * @param url - The URL to read the token from (e.g. `window.location.href`).\n * @returns The session token, or `null` when absent or the URL is malformed.\n */\nexport function getSessionTokenFromUrl(url: string | URL): string | null {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n const token = parsed.searchParams.get(SESSION_TOKEN_QUERY_PARAM);\n return token !== null && token.length > 0 ? token : null;\n}\n\n/**\n * Extracts the creator's active colour scheme from a URL.\n *\n * When Fanvue opens an embedded app, it appends the creator's resolved colour\n * scheme as a `?theme=` query parameter (`light` or `dark`), letting the app\n * theme-match Fanvue.\n *\n * @param url - The URL to read the theme from (e.g. `window.location.href`).\n * @returns The {@link FanvueTheme}, or `null` when absent, unrecognised, or the\n * URL is malformed (e.g. the app was opened outside Fanvue).\n */\nexport function getThemeFromUrl(url: string | URL): FanvueTheme | null {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n const theme = parsed.searchParams.get(THEME_QUERY_PARAM);\n return theme === 'light' || theme === 'dark' ? theme : null;\n}\n\n/**\n * Requests an authorization code from the Fanvue platform on behalf of the\n * creator currently using the embedded app.\n *\n * This is the \"authorize\" half of the delegated flow: the platform verifies\n * the session token, runs the OAuth authorize as the creator, and returns the\n * resulting authorization code. The PKCE verifier and client secret never\n * leave the caller — only the challenge is sent.\n *\n * Most apps should use {@link exchangeSessionToken}, which composes this with\n * the code exchange.\n *\n * @param config - The embedded auth configuration.\n * @param sessionToken - The short-lived session token received in the iframe.\n * @param opts - The PKCE code challenge and state to bind the code to.\n * @returns A `Result` containing the authorization code on success or\n * {@link EmbeddedAuthError} on failure.\n */\nexport async function requestAuthorizationCodeOnBehalf(\n config: EmbeddedAuthConfig,\n sessionToken: string,\n opts: { codeChallenge: string; state: string },\n): Promise<Result<{ code: string }, EmbeddedAuthError>> {\n const platformUrl = config.platformUrl ?? DEFAULT_PLATFORM_URL;\n\n let response: Response;\n try {\n response = await fetch(`${platformUrl}${AUTHORIZE_ON_BEHALF_PATH}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${sessionToken}`,\n },\n body: JSON.stringify({\n code_challenge: opts.codeChallenge,\n code_challenge_method: 'S256',\n state: opts.state,\n }),\n });\n } catch (error) {\n return err({\n code: 'AUTHORIZE_ON_BEHALF_FAILED',\n statusCode: 0,\n message: `Network error during authorize-on-behalf: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n\n if (response.status === 401) {\n return err({\n code: 'SESSION_TOKEN_REJECTED',\n statusCode: response.status,\n message:\n 'The platform rejected the session token. Session tokens expire after ~60 seconds — reopen the embedded surface to receive a fresh one.',\n });\n }\n\n if (response.status === 403) {\n return err({\n code: 'CONSENT_REQUIRED',\n statusCode: response.status,\n message:\n 'The creator has not approved (or has revoked) consent for this app. Consent is granted on the Fanvue consent screen when the surface is opened.',\n });\n }\n\n if (!response.ok) {\n return err({\n code: 'AUTHORIZE_ON_BEHALF_FAILED',\n statusCode: response.status,\n message: `authorize-on-behalf failed: ${response.status} ${response.statusText}`,\n });\n }\n\n const text = await response.text();\n const parseResult = safeJsonParse(text);\n if (parseResult.isErr()) {\n const { rawText, message } = parseResult.error;\n return err({ code: 'EMBEDDED_JSON_PARSE_ERROR', rawText, message });\n }\n\n const validated = AuthorizeOnBehalfResponseSchema.safeParse(parseResult.value);\n if (!validated.success) {\n return err({ code: 'EMBEDDED_VALIDATION_ERROR', message: validated.error.message });\n }\n\n if (validated.data.state !== opts.state) {\n return err({\n code: 'AUTHORIZE_STATE_MISMATCH',\n message: 'authorize-on-behalf returned a different state than was sent.',\n });\n }\n\n return ok({ code: validated.data.code });\n}\n\n/**\n * Exchanges an embedded session token for OAuth access and refresh tokens.\n *\n * Runs the complete delegated authorize-on-behalf flow:\n *\n * 1. Generates a PKCE verifier/challenge pair and a random `state`.\n * 2. Asks the Fanvue platform to authorize as the creator\n * ({@link requestAuthorizationCodeOnBehalf}).\n * 3. Exchanges the returned code at the token endpoint using the client\n * secret and PKCE verifier.\n *\n * Must run server-side: it uses the client secret. The session token should\n * be used promptly — it expires after ~60 seconds.\n *\n * @param config - The embedded auth configuration. `redirectUri` must be a\n * redirect URI registered on the OAuth client (it is never visited; it only\n * binds the authorization code).\n * @param sessionToken - The short-lived session token received in the iframe.\n * @returns A `Result` containing {@link TokenResponse} on success or an\n * {@link EmbeddedAuthError} / {@link OAuthError} on failure.\n */\nexport async function exchangeSessionToken(\n config: EmbeddedAuthConfig,\n sessionToken: string,\n): Promise<Result<TokenResponse, EmbeddedAuthError | OAuthError>> {\n const codeVerifier = oauth.generateRandomCodeVerifier();\n const codeChallenge = await oauth.calculatePKCECodeChallenge(codeVerifier);\n const state = oauth.generateRandomState();\n\n const codeResult = await requestAuthorizationCodeOnBehalf(config, sessionToken, {\n codeChallenge,\n state,\n });\n if (codeResult.isErr()) {\n return err(codeResult.error);\n }\n\n return exchangeCodeForToken(config, {\n code: codeResult.value.code,\n codeVerifier,\n redirectUri: null,\n });\n}\n","import { ok, err } from 'neverthrow';\n\nimport { DEFAULT_API_BASE_URL, API_VERSION, assertFanvueDomain } from './defaults.js';\nimport { safeJsonParse } from './json.js';\nimport { FanvueUserSchema } from './schemas.js';\n\nimport type { FanvueUser, ApiError } from './types.js';\nimport type { Result } from 'neverthrow';\n\n/**\n * A client for making authenticated requests to the Fanvue API.\n */\nexport interface FanvueClient {\n /**\n * Fetches the currently authenticated user's profile.\n *\n * @returns A `Result` containing the {@link FanvueUser} on success or `ApiError` on failure.\n */\n getCurrentUser(): Promise<Result<FanvueUser, ApiError>>;\n}\n\n/**\n * Creates a new {@link FanvueClient} for making authenticated requests to the Fanvue API.\n *\n * @param accessToken - The OAuth access token to authenticate requests.\n * @param apiBaseUrl - The base URL for the Fanvue API, or `null` to use the default.\n * @returns A {@link FanvueClient} instance.\n */\nexport function createFanvueClient(accessToken: string, apiBaseUrl: string | null): FanvueClient {\n if (apiBaseUrl != null) assertFanvueDomain(apiBaseUrl);\n const baseUrl = apiBaseUrl ?? DEFAULT_API_BASE_URL;\n\n async function fetchApi(path: string): Promise<Result<unknown, ApiError>> {\n let response: Response;\n try {\n response = await fetch(`${baseUrl}${path}`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'X-Fanvue-API-Version': API_VERSION,\n },\n });\n } catch (error) {\n return err({\n code: 'API_REQUEST_FAILED',\n statusCode: 0,\n message: `Network error: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n\n if (!response.ok) {\n return err({\n code: 'API_REQUEST_FAILED',\n statusCode: response.status,\n message: `API request failed: ${response.status} ${response.statusText}`,\n });\n }\n\n const text = await response.text();\n const parseResult = safeJsonParse(text);\n if (parseResult.isErr()) {\n const { rawText, message } = parseResult.error;\n return err({ code: 'API_JSON_PARSE_ERROR', rawText, message });\n }\n\n return ok(parseResult.value);\n }\n\n async function getCurrentUser(): Promise<Result<FanvueUser, ApiError>> {\n const result = await fetchApi('/users/me');\n if (result.isErr()) return err(result.error);\n\n const validated = FanvueUserSchema.safeParse(result.value);\n if (!validated.success) {\n return err({ code: 'API_VALIDATION_ERROR', message: validated.error.message });\n }\n\n return ok(validated.data);\n }\n\n return { getCurrentUser };\n}\n","/**\n * The outcome of authenticating a machine (cron / queue) request.\n *\n * `not_configured` is a separate arm on purpose: a deployment with no usable\n * credential has an operator problem, not an attacker, and the two must map to\n * different HTTP statuses (503 vs 401). Collapsing them hides a broken deploy\n * behind what looks like ordinary auth noise, and tells a caller to retry with\n * better credentials when no credential could ever work.\n */\nexport type MachineAuthResult =\n | { status: 'authorized' }\n | { status: 'unauthorized' }\n | { status: 'not_configured' };\n\n/**\n * A pluggable signed-request strategy — the second way a machine request can\n * authenticate itself.\n *\n * Implemented by the app so the SDK takes no queue-provider dependency. The\n * verifier owns its own key material and rotation; it must return `false`\n * (never throw) when it cannot verify, though a throw is caught and treated as\n * a failure regardless.\n */\nexport interface SignedRequestVerifier {\n /**\n * @param request - The incoming request, whose URL and headers are usually\n * part of the signed material.\n * @param rawBody - The exact bytes received. Never a reserialized body: a\n * round-trip through `JSON.parse`/`stringify` changes whitespace and key\n * order and invalidates the signature.\n * @returns Whether the signature is authentic.\n */\n verify: (request: Request, rawBody: Uint8Array) => Promise<boolean>;\n}\n\n/**\n * Credentials and strategies available to {@link requireMachineAuth}.\n */\nexport interface MachineAuthOptions {\n /**\n * Shared bearer secret (the `CRON_SECRET` pattern). `null` when unset. A\n * secret shorter than {@link MINIMUM_BEARER_SECRET_LENGTH} is treated as\n * unset rather than compared.\n */\n bearerSecret: string | null;\n /** Signed-request strategy, or `null` when the app plugs none in. */\n signedRequestVerifier: SignedRequestVerifier | null;\n /**\n * The exact request bytes, required by {@link signedRequestVerifier}. `null`\n * is allowed (and reads as an empty body) when no verifier is configured.\n */\n rawBody: Uint8Array | null;\n}\n\n/**\n * Shortest bearer secret the SDK will compare against.\n *\n * A cron endpoint is reachable by anyone on the internet and its secret is\n * never rotated by a user, so a guessable one is a standing invitation. Below\n * this length the secret is treated as absent — the endpoint reports\n * `not_configured` instead of quietly accepting a weak credential.\n */\nexport const MINIMUM_BEARER_SECRET_LENGTH = 32;\n\n/**\n * The `Bearer` auth scheme and its separating whitespace.\n *\n * Case-insensitive because RFC 7235 defines auth scheme names as\n * case-insensitive — `bearer` is as valid on the wire as `Bearer`. Non-global,\n * so the shared instance carries no `lastIndex` between calls.\n */\nconst BEARER_SCHEME_PATTERN = /^bearer[ \\t]+/i;\n\nconst textEncoder = new TextEncoder();\n\n/**\n * Compares two strings in time independent of their content.\n *\n * Hand-rolled rather than `node:crypto`'s `timingSafeEqual` because\n * `src/core` must stay runtime-agnostic — it is also imported by browser and\n * edge bundles, which a `node:crypto` import would break. This is a byte\n * comparison, not a cryptographic primitive: every byte is XOR-accumulated with\n * no early exit, and the length check happens before any comparison (an\n * unavoidable leak of length, matching `timingSafeEqual`'s own precondition).\n */\nfunction constantTimeTextEqual(left: string, right: string): boolean {\n const leftBytes = textEncoder.encode(left);\n const rightBytes = textEncoder.encode(right);\n if (leftBytes.byteLength !== rightBytes.byteLength) {\n return false;\n }\n let difference = 0;\n for (let index = 0; index < leftBytes.byteLength; index += 1) {\n difference |= (leftBytes[index] ?? 0) ^ (rightBytes[index] ?? 0);\n }\n return difference === 0;\n}\n\n/**\n * Reads the bearer credential from an `Authorization` header.\n *\n * The scheme is required: a bare secret in the header is rejected, so a client\n * that forgets the scheme fails loudly rather than working by accident against\n * one deployment and not another. The scheme name itself is matched\n * case-insensitively, per RFC 7235 — rejecting `bearer` would be a lie about\n * what the header means.\n */\nfunction bearerToken(request: Request): string | null {\n const header = request.headers.get('authorization');\n if (header === null) {\n return null;\n }\n const scheme = BEARER_SCHEME_PATTERN.exec(header);\n if (scheme === null) {\n return null;\n }\n return header.slice(scheme[0].length);\n}\n\nasync function verifiesSignature(\n request: Request,\n verifier: SignedRequestVerifier,\n rawBody: Uint8Array | null,\n): Promise<boolean> {\n try {\n return await verifier.verify(request, rawBody ?? new Uint8Array(0));\n } catch {\n return false;\n }\n}\n\n/**\n * Authenticates a machine-invoked route (cron tick, queue drain, sweeper).\n *\n * Two strategies, tried in order, either of which is sufficient:\n *\n * 1. a shared bearer secret compared in constant time, and\n * 2. an app-supplied {@link SignedRequestVerifier}.\n *\n * Deny by default. When neither strategy is usable — no verifier and a missing\n * or too-short `bearerSecret` — the result is `not_configured`, which the\n * caller should surface as 503; `unauthorized` (401) means a strategy was\n * available and the request failed it.\n *\n * Web-standard `Request` only, so this works unchanged in a Next.js route\n * handler, a Node server and an edge function.\n *\n * @param request - The incoming machine request.\n * @param options - Available credentials and strategies.\n * @returns The discriminated {@link MachineAuthResult}.\n * @example\n * // Bearer-only cron route.\n * const auth = await requireMachineAuth(request, {\n * bearerSecret: process.env.CRON_SECRET ?? null,\n * signedRequestVerifier: null,\n * rawBody: null,\n * });\n * if (auth.status === 'not_configured') return new Response(null, { status: 503 });\n * if (auth.status === 'unauthorized') return new Response(null, { status: 401 });\n * @example\n * // Queue drain that also accepts QStash-signed deliveries. `@upstash/qstash`\n * // is intentionally NOT a dependency of this package — the app owns it:\n * //\n * // import { Receiver } from '@upstash/qstash';\n * //\n * // const qstashVerifier: SignedRequestVerifier = {\n * // verify: async (request, rawBody) => {\n * // const signature = request.headers.get('upstash-signature');\n * // const currentSigningKey = process.env.QSTASH_CURRENT_SIGNING_KEY;\n * // const nextSigningKey = process.env.QSTASH_NEXT_SIGNING_KEY;\n * // if (!signature || !currentSigningKey || !nextSigningKey) return false;\n * // return new Receiver({ currentSigningKey, nextSigningKey }).verify({\n * // signature,\n * // body: new TextDecoder().decode(rawBody),\n * // url: request.url,\n * // upstashRegion: request.headers.get('upstash-region') ?? undefined,\n * // });\n * // },\n * // };\n * //\n * // Pass the raw bytes, never a reparsed body:\n * const rawBody = new Uint8Array(await request.arrayBuffer());\n * const auth = await requireMachineAuth(request, {\n * bearerSecret: process.env.CRON_SECRET ?? null,\n * signedRequestVerifier: qstashVerifier,\n * rawBody,\n * });\n */\nexport async function requireMachineAuth(\n request: Request,\n options: MachineAuthOptions,\n): Promise<MachineAuthResult> {\n const { bearerSecret, signedRequestVerifier, rawBody } = options;\n const usableSecret =\n bearerSecret !== null && bearerSecret.length >= MINIMUM_BEARER_SECRET_LENGTH\n ? bearerSecret\n : null;\n\n if (usableSecret === null && signedRequestVerifier === null) {\n return { status: 'not_configured' };\n }\n\n if (usableSecret !== null) {\n const provided = bearerToken(request);\n if (provided !== null && constantTimeTextEqual(provided, usableSecret)) {\n return { status: 'authorized' };\n }\n }\n\n if (signedRequestVerifier !== null) {\n if (await verifiesSignature(request, signedRequestVerifier, rawBody)) {\n return { status: 'authorized' };\n }\n }\n\n return { status: 'unauthorized' };\n}\n\n/**\n * Clamps a caller-supplied batch size to a safe positive bound.\n *\n * Machine routes take `?limit=` to let an operator drain faster, which is also\n * an unauthenticated-shaped lever on database load, so the value is bounded\n * rather than trusted. Anything unparseable, non-integer, zero or negative\n * falls back to the default; the default itself is capped by `max`, so a\n * misconfigured default cannot exceed the ceiling either.\n *\n * The result is always a positive safe integer, even when `defaultSize` or\n * `max` is itself invalid (non-integer, zero or negative): a query builder\n * handed a negative limit can interpret it as \"no limit\" — the exact fail-open\n * this function exists to prevent — so a misconfigured constant degrades to a\n * batch size of 1, never to an unbounded one.\n *\n * @param requested - Raw query value, e.g. `searchParams.get('limit')`.\n * @param defaultSize - Size to use when `requested` is absent or invalid.\n * @param max - Hard ceiling.\n * @returns A positive safe integer batch size.\n * @example\n * boundedBatchSize(null, 20, 100); // 20\n * boundedBatchSize('0', 20, 100); // 20\n * boundedBatchSize('1000', 20, 100); // 100\n */\nexport function boundedBatchSize(\n requested: string | null,\n defaultSize: number,\n max: number,\n): number {\n const ceiling = Number.isSafeInteger(max) && max >= 1 ? max : 1;\n const fallback =\n Number.isSafeInteger(defaultSize) && defaultSize >= 1 ? Math.min(defaultSize, ceiling) : 1;\n if (requested === null) {\n return fallback;\n }\n const parsed = Number(requested);\n if (!Number.isSafeInteger(parsed) || parsed < 1) {\n return fallback;\n }\n return Math.min(parsed, ceiling);\n}\n","/**\n * An email address, as a pattern source.\n *\n * Deliberately loose rather than RFC 5322: redaction must fail closed, so\n * anything shaped like `local@domain.tld` is treated as an address. The TLD is\n * required to be alphabetic so version-shaped strings (`jose@6.0.11`) and\n * `host:port` fragments are not mistaken for addresses.\n */\nconst EMAIL_SOURCE = '[a-z0-9._%+-]+@[a-z0-9.-]+\\\\.[a-z]{2,}';\n\n/**\n * Matches an email address anywhere in a string.\n *\n * Non-global, so `.test()` is stateless and safe to share.\n *\n * @internal\n */\nexport const EMAIL_PATTERN = new RegExp(EMAIL_SOURCE, 'i');\n\n/**\n * The global variant of {@link EMAIL_PATTERN}, for replacing every address\n * inside a string. Only ever used with `String.prototype.replace`, which\n * resets `lastIndex`, so the shared instance cannot carry state between calls.\n *\n * @internal\n */\nexport const EMAIL_PATTERN_GLOBAL = new RegExp(EMAIL_SOURCE, 'gi');\n\n/**\n * The placeholder substituted for a redacted email address.\n *\n * @internal\n */\nexport const REDACTED_EMAIL = '[redacted-email]';\n","/**\n * The canonical 8-4-4-4-12 hex grouping of a UUID, as a pattern source.\n *\n * Deliberately broader than RFC 4122's grammar: both the version nibble and the\n * variant nibble accept any hex digit. The apps this was lifted from pinned the\n * version to `[1-5]` and the variant to `[89ab]`, which would silently let a\n * UUIDv7 identifier through unredacted. Platform records are v4 today\n * (`gen_random_uuid()` / `crypto.randomUUID()`), and the platform's own schemas\n * validate ids version-agnostically (`z.uuid()`), so nothing guarantees v4\n * forever. Redaction must fail closed, so anything shaped like a UUID is\n * treated as one.\n */\nconst UUID_BODY = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}';\n\n/**\n * Boundaries around {@link UUID_BODY}.\n *\n * A `\\b` word boundary is deliberately NOT used on the left: `_` is a word\n * character, so `\\b` refuses to match the UUID in `creator_5d5658d4-…` and the\n * identifier survives redaction. The boundary that actually matters is \"not\n * preceded / followed by another hex digit\", which keeps a longer hex run from\n * being mistaken for a UUID while still redacting a prefixed or suffixed one.\n */\nconst NOT_HEX_BEFORE = '(^|[^0-9a-f])';\nconst NOT_HEX_AFTER = '(?![0-9a-f])';\n\n/** The one pattern source both exported regexes are built from. */\nconst UUID_SOURCE = `${NOT_HEX_BEFORE}${UUID_BODY}${NOT_HEX_AFTER}`;\n\n/**\n * Matches a canonically-formatted UUID anywhere in a string.\n *\n * Non-global, so `.test()` is stateless and safe to share.\n *\n * @internal\n */\nexport const UUID_PATTERN = new RegExp(UUID_SOURCE, 'i');\n\n/**\n * The global variant of {@link UUID_PATTERN}, for replacing every UUID inside a\n * string rather than testing for one.\n *\n * Group 1 is whatever preceded the UUID and must be re-emitted by the\n * replacement, hence {@link REDACTED_UUID_REPLACEMENT}. Only ever used with\n * `String.prototype.replace`, which resets `lastIndex`, so the shared instance\n * cannot carry state between calls.\n *\n * @internal\n */\nexport const UUID_PATTERN_GLOBAL = new RegExp(UUID_SOURCE, 'gi');\n\n/**\n * The placeholder substituted for a redacted UUID.\n *\n * @internal\n */\nexport const REDACTED_UUID = '[redacted-uuid]';\n\n/**\n * The replacement string to pair with {@link UUID_PATTERN_GLOBAL}: re-emits the\n * captured preceding character, then the placeholder.\n *\n * @internal\n */\nexport const REDACTED_UUID_REPLACEMENT = `$1${REDACTED_UUID}`;\n","import { EMAIL_PATTERN, REDACTED_EMAIL } from './email.js';\nimport { REDACTED_UUID, UUID_PATTERN } from './uuid.js';\n\n/**\n * The log levels a structured event can be emitted at.\n */\nexport type LogLevel = 'info' | 'warn' | 'error';\n\n/**\n * A scalar that is safe to place in a log line.\n *\n * Objects and arrays are deliberately absent: an allowlisted key whose value is\n * a structure would smuggle un-reviewed fields (an Error, a token bag, a whole\n * request) past the allowlist, so those values are dropped rather than\n * serialised.\n */\nexport type SafeLogValue = string | number | boolean | null;\n\n/**\n * Filters an arbitrary field bag down to the fields that are safe to log.\n *\n * Created by {@link createSafeLogFields}.\n */\nexport type SafeLogFields = (fields?: Record<string, unknown>) => Record<string, SafeLogValue>;\n\n/**\n * Emits one structured, allowlisted log event.\n *\n * Created by {@link createLogEvent}.\n */\nexport type LogEvent = (level: LogLevel, event: string, fields?: Record<string, unknown>) => void;\n\n/**\n * The subset of `console` a {@link LogEvent} writes to. Injectable so the\n * privacy behaviour can be asserted in tests.\n */\nexport interface LogSink {\n info: (...args: readonly unknown[]) => void;\n warn: (...args: readonly unknown[]) => void;\n error: (...args: readonly unknown[]) => void;\n}\n\n/**\n * Options for {@link createLogEvent}.\n */\nexport interface LogEventOptions {\n /** Prefix written before the payload, e.g. `'[my-app]'`. */\n prefix: string;\n /** Allowlist to apply. Defaults to `createSafeLogFields()`. */\n safeLogFields: SafeLogFields;\n /** Where lines are written. Defaults to the global `console`. */\n sink: LogSink;\n}\n\n/**\n * The generic Fanvue log keys every app shares.\n *\n * Anything app-specific (a wheel id, a bounty id, a claim status) is added per\n * app via `createSafeLogFields(['wheelId', ...])`.\n */\nexport const BASE_ALLOWED_LOG_KEYS: readonly string[] = [\n 'cause',\n 'code',\n 'creatorId',\n 'errorName',\n 'httpStatus',\n 'reason',\n 'retryCount',\n 'status',\n];\n\n/**\n * Builds an allowlisting log-field filter.\n *\n * The returned function is the only sanctioned way to get caller-supplied\n * fields into a log line. It fails closed in three independent ways:\n *\n * 1. A key that is not allowlisted is dropped entirely (so a new field cannot\n * reach the logs until someone adds it to the list on purpose).\n * 2. A value that is not `string | number | boolean | null` is dropped — an\n * `Error`, a response body or a token bag is never serialised, even under an\n * allowlisted key.\n * 3. An allowlisted string value containing a UUID becomes `'[redacted-uuid]'`\n * (platform UUIDs identify real people; any version matches, including v7 —\n * see `UUID_PATTERN`), and one containing an email address becomes\n * `'[redacted-email]'`. The whole value is replaced, not just the match,\n * because the surrounding text is usually the same identifier restated.\n *\n * `undefined` values are dropped rather than logged as `undefined`.\n *\n * @param extraAllowedKeys - App-specific keys to allow in addition to\n * {@link BASE_ALLOWED_LOG_KEYS}.\n * @returns A `safeLogFields(fields)` filter.\n * @example\n * const safeLogFields = createSafeLogFields(['wheelId']);\n * safeLogFields({ wheelId: 'wheel_1', retryCount: 2, accessToken: 'secret' });\n * // => { wheelId: 'wheel_1', retryCount: 2 }\n */\nexport function createSafeLogFields(extraAllowedKeys: readonly string[] = []): SafeLogFields {\n const allowed = new Set<string>([...BASE_ALLOWED_LOG_KEYS, ...extraAllowedKeys]);\n\n return function safeLogFields(\n fields: Record<string, unknown> = {},\n ): Record<string, SafeLogValue> {\n const safe: Record<string, SafeLogValue> = {};\n for (const [key, value] of Object.entries(fields)) {\n if (!allowed.has(key) || value === undefined) {\n continue;\n }\n if (typeof value === 'string') {\n if (UUID_PATTERN.test(value)) {\n safe[key] = REDACTED_UUID;\n } else if (EMAIL_PATTERN.test(value)) {\n safe[key] = REDACTED_EMAIL;\n } else {\n safe[key] = value;\n }\n continue;\n }\n if (value === null || typeof value === 'number' || typeof value === 'boolean') {\n safe[key] = value;\n }\n }\n return safe;\n };\n}\n\n/**\n * Reads a loggable name out of an unknown thrown value.\n *\n * Only the class name is returned — never `error.message`, which routinely\n * carries the very data the allowlist exists to keep out of the logs (upstream\n * response bodies, signed URLs, secrets embedded in connection strings).\n *\n * @param error - Any caught value.\n * @returns The `Error` subclass name, or the `typeof` of a non-Error throw.\n * @example\n * errorName(new TypeError('secret=abc')); // 'TypeError'\n * errorName('boom'); // 'string'\n */\nexport function errorName(error: unknown): string {\n return error instanceof Error ? error.name : typeof error;\n}\n\n/**\n * Builds a structured event logger over an allowlist.\n *\n * The emitted shape is `prefix` followed by `{ event, ...safeFields }`, matching\n * the convention the apps already log in, so existing log-based dashboards keep\n * working after the lift.\n *\n * @param options - Prefix, allowlist and sink overrides. Every field is\n * optional; the defaults are `'[fanvue]'`, `createSafeLogFields()` and the\n * global `console`.\n * @returns A `logEvent(level, event, fields)` function.\n * @example\n * const logEvent = createLogEvent({ prefix: '[spinwheel]' });\n * logEvent('warn', 'exchange.retry', { httpStatus: 503, retryCount: 1 });\n * // [spinwheel] { event: 'exchange.retry', httpStatus: 503, retryCount: 1 }\n */\nexport function createLogEvent(options?: Partial<LogEventOptions>): LogEvent {\n const prefix = options?.prefix ?? '[fanvue]';\n const safeLogFields = options?.safeLogFields ?? createSafeLogFields();\n const sink = options?.sink ?? console;\n\n return function logEvent(\n level: LogLevel,\n event: string,\n fields: Record<string, unknown> = {},\n ): void {\n const payload = { event, ...safeLogFields(fields) };\n if (level === 'error') {\n sink.error(prefix, payload);\n return;\n }\n if (level === 'warn') {\n sink.warn(prefix, payload);\n return;\n }\n sink.info(prefix, payload);\n };\n}\n\n/**\n * A ready-made {@link LogEvent} over the base allowlist, prefixed `[fanvue]`.\n *\n * Use {@link createLogEvent} instead when the app has its own prefix or extra\n * allowlisted keys.\n *\n * @example\n * logEvent('error', 'session.exchange_failed', { errorName: errorName(err) });\n */\nexport const logEvent: LogEvent = createLogEvent();\n","/**\n * One named configuration check.\n */\nexport interface ReadinessCheck {\n /** Stable machine-readable check name, e.g. `'fanvue_oauth'`. */\n name: string;\n /** Whether the check passes. */\n ready: boolean;\n /** Why it fails, or `null` when it passes. Never contains a secret value. */\n detail: string | null;\n}\n\n/** The environment shape the checks read, so `process.env` is never read directly. */\nexport type ReadinessEnv = Readonly<Record<string, string | undefined>>;\n\n/**\n * The four OAuth credential variables an embedded Fanvue app needs before it\n * can complete a creator connection.\n */\nconst FANVUE_OAUTH_VARS: readonly string[] = [\n 'FANVUE_APP_UUID',\n 'FANVUE_CLIENT_ID',\n 'FANVUE_CLIENT_SECRET',\n 'FANVUE_OAUTH_REDIRECT_URI',\n];\n\n/**\n * The app's own public base URL, checked for an https origin.\n *\n * `FANVUE_APP_BASE_URL` is the SDK-prefixed name; `APP_BASE_URL` is accepted\n * because the apps this was lifted from already set it.\n */\nconst APP_BASE_URL_VARS: readonly string[] = ['FANVUE_APP_BASE_URL', 'APP_BASE_URL'];\n\nfunction firstSetValue(env: ReadinessEnv, names: readonly string[]): string | null {\n for (const name of names) {\n const value = env[name];\n if (value !== undefined && value.length > 0) {\n return value;\n }\n }\n return null;\n}\n\nfunction isHttpsUrl(value: string | null): boolean {\n if (value === null) {\n return false;\n }\n try {\n return new URL(value).protocol === 'https:';\n } catch {\n return false;\n }\n}\n\n/**\n * Reports whether the generic Fanvue configuration an embedded app depends on\n * is present, as a list of named checks suitable for a `/api/readyz` body.\n *\n * Pure by construction — the environment is a parameter, so a deployment's\n * readiness can be asserted in tests without mutating `process.env`. Two\n * checks:\n *\n * - `app_url` — the app's public base URL is set and https. Fanvue refuses to\n * embed a non-https origin, so an http (or unset) value means creators would\n * see an empty frame rather than an error.\n * - `fanvue_oauth` — all four OAuth credential variables are present. The\n * detail names the missing variables, never their values.\n *\n * Provider-specific checks are deliberately out of scope: webhook signature\n * readiness belongs to the webhooks module (which owns the contract), and\n * queue/cron credentials belong to whichever machine-auth strategy the app\n * plugs in.\n *\n * @param env - Environment to read. Defaults to `process.env`; on a runtime\n * with no `process` global (browser, some edge workers) it defaults to an\n * empty environment, so the probe reports not-ready instead of throwing a\n * `ReferenceError`.\n * @returns One {@link ReadinessCheck} per generic concern, in a stable order.\n * @example\n * const checks = configurationReadiness();\n * const ready = checks.every((check) => check.ready);\n * return Response.json({ ready, checks }, { status: ready ? 200 : 503 });\n */\nexport function configurationReadiness(\n env: ReadinessEnv = typeof process === 'undefined' ? {} : process.env,\n): readonly ReadinessCheck[] {\n const appBaseUrl = firstSetValue(env, APP_BASE_URL_VARS);\n const appUrlReady = isHttpsUrl(appBaseUrl);\n const missingOauthVars = FANVUE_OAUTH_VARS.filter((name) => {\n const value = env[name];\n return value === undefined || value.length === 0;\n });\n\n return [\n {\n name: 'app_url',\n ready: appUrlReady,\n detail: appUrlReady ? null : `set ${APP_BASE_URL_VARS[0]} to an https:// origin`,\n },\n {\n name: 'fanvue_oauth',\n ready: missingOauthVars.length === 0,\n detail: missingOauthVars.length === 0 ? null : `missing ${missingOauthVars.join(', ')}`,\n },\n ];\n}\n","import { EMAIL_PATTERN_GLOBAL, REDACTED_EMAIL } from './email.js';\nimport { REDACTED_UUID_REPLACEMENT, UUID_PATTERN_GLOBAL } from './uuid.js';\n\n/**\n * A `beforeSend`-compatible scrubber.\n *\n * Generic in the event type so it satisfies Sentry's `beforeSend` option\n * without this package importing `@sentry/*` — the returned function is\n * structurally assignable to `(event, hint) => event | null`.\n */\nexport type SentryScrubber = <T>(event: T) => T;\n\n/**\n * Key-name fragments whose values are never allowed to reach an error tracker.\n *\n * Matched as a substring, case-insensitively, so `Authorization`,\n * `authorizationHeader`, `x-authorization`, `x-api-key` and `apiKey` all hit.\n * Substring matching over-redacts on purpose (`emailSent`, `iphoneModel`) —\n * losing a benign field fails closed, letting a credential or a fan's contact\n * detail through does not. Anything app-specific (`prizedetail`, `fanhmac`,\n * `seed`, …) is added per app via the `extraSensitiveKeyPattern` argument.\n */\nexport const BASE_SENSITIVE_KEY_PATTERN =\n /(authorization|cookie|token|secret|password|signedurl|api[-_]?key|credential|email|phone|ip[-_]?address)/i;\n\n/** The placeholder substituted for a value under a sensitive key. */\nconst REDACTED = '[redacted]';\n\n/**\n * The placeholder substituted for an object already visited anywhere in this\n * event.\n *\n * The guard is per-event rather than per-branch, so a value referenced twice\n * shows as `[circular]` the second time even when there is no cycle. That is\n * deliberate: it bounds the work to one visit per node, which a branch-scoped\n * guard would not (a shallow object graph that shares children can be walked an\n * exponential number of times), and it matches how Sentry's own `normalize`\n * memoises. Same reasoning, same trade-off.\n */\nconst CIRCULAR = '[circular]';\n\n/** The placeholder substituted for a property whose getter threw. */\nconst UNREADABLE = '[unreadable]';\n\n/** The placeholder substituted for a node nested deeper than {@link MAX_DEPTH}. */\nconst TOO_DEEP = '[max-depth]';\n\n/**\n * How far into an event the scrubber will walk.\n *\n * Recursion has to be bounded: an event can carry an arbitrarily nested object\n * (a linked list, a parsed AST, a deeply chained `cause`), and blowing the call\n * stack inside `beforeSend` turns a scrub into a thrown `RangeError` — the event\n * is lost and the throw surfaces wherever Sentry was invoked. Anything deeper is\n * replaced rather than traversed, which fails closed: an untraversed subtree\n * cannot leak. Generous next to Sentry's own default normalisation depth of 3.\n */\nconst MAX_DEPTH = 32;\n\n/**\n * Merges the base sensitive-key pattern with an app-supplied one.\n *\n * The result is rebuilt from `source` with only the `i` flag so a caller\n * passing a `/g` pattern cannot make matching stateful (a shared `lastIndex`\n * would make redaction depend on call order — i.e. fail open intermittently).\n */\nfunction mergeSensitiveKeyPattern(extra: RegExp | null): RegExp {\n if (extra === null) {\n return BASE_SENSITIVE_KEY_PATTERN;\n }\n return new RegExp(`(?:${BASE_SENSITIVE_KEY_PATTERN.source})|(?:${extra.source})`, 'i');\n}\n\n/**\n * Removes the credential-bearing parts of anything that parses as a URL.\n *\n * The whole query string goes, not named parameters — signed media URLs carry\n * their credential in parameters whose names differ per provider, so an\n * allowlist there would fail open. The fragment and the userinfo go for the same\n * reason: an OAuth redirect puts `access_token` in the fragment, and a\n * connection string puts the password in `user:pass@`, so keying redaction on\n * the query alone would leak both.\n *\n * A string that parses as a URL but carries none of those parts is returned\n * unchanged, so an ordinary log line that happens to look like a non-special URI\n * (`'note: something happened'`) is not mangled.\n */\nfunction stripUrlCredentials(value: string): string {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return value;\n }\n if (url.search === '' && url.hash === '' && url.username === '' && url.password === '') {\n return value;\n }\n // Cleared on the parsed URL and reserialised rather than rebuilt from\n // `origin` + `pathname`: `origin` is the string 'null' for a non-special\n // scheme (mailto:, postgres:), so rebuilding drops the host it was hiding.\n url.search = '';\n url.hash = '';\n url.username = '';\n url.password = '';\n return `${url.toString()}?${REDACTED}`;\n}\n\n/**\n * Scrubs a string value: strips every UUID, then removes the credential-bearing\n * parts of anything that parses as a URL, then strips every email address.\n *\n * Emails go last so an address that survives URL stripping — a `mailto:` path,\n * a verification link's path segment — is still caught. A fan's email is PII in\n * its own right, and error messages routinely embed one (`user x@y.com not\n * found`).\n */\nfunction scrubString(value: string): string {\n const withoutUuids = value.replace(UUID_PATTERN_GLOBAL, REDACTED_UUID_REPLACEMENT);\n return stripUrlCredentials(withoutUuids).replace(EMAIL_PATTERN_GLOBAL, REDACTED_EMAIL);\n}\n\n/**\n * Reads one property without letting a throwing getter abort the whole scrub.\n *\n * Sentry events routinely carry app objects, and a getter that throws (a lazy\n * field, a revoked proxy, a Vue/Mobx observable read outside its scope) would\n * otherwise propagate out of `beforeSend`.\n */\nfunction readProperty(source: object, key: PropertyKey): unknown {\n try {\n return Reflect.get(source, key);\n } catch {\n return UNREADABLE;\n }\n}\n\nfunction scrubValue(\n value: unknown,\n key: string,\n sensitiveKeyPattern: RegExp,\n seen: WeakSet<object>,\n depth: number,\n): unknown {\n if (sensitiveKeyPattern.test(key)) {\n return REDACTED;\n }\n if (typeof value === 'string') {\n return scrubString(value);\n }\n if (value === null || typeof value !== 'object') {\n return value;\n }\n if (seen.has(value)) {\n return CIRCULAR;\n }\n if (depth >= MAX_DEPTH) {\n return TOO_DEEP;\n }\n seen.add(value);\n if (Array.isArray(value)) {\n const items: unknown[] = [];\n for (let index = 0; index < value.length; index += 1) {\n const item = readProperty(value, index);\n items.push(scrubValue(item, key, sensitiveKeyPattern, seen, depth + 1));\n }\n return items;\n }\n const scrubbed: Record<string, unknown> = {};\n for (const childKey of Object.keys(value)) {\n const child = readProperty(value, childKey);\n scrubbed[childKey] = scrubValue(child, childKey, sensitiveKeyPattern, seen, depth + 1);\n }\n return scrubbed;\n}\n\n/**\n * Builds a recursive `beforeSend` scrubber for Sentry (or any error tracker\n * with the same hook shape).\n *\n * Four redaction rules, applied to every node of the event:\n *\n * - a key matching {@link BASE_SENSITIVE_KEY_PATTERN} (or the app's extra\n * pattern) has its value replaced with `'[redacted]'`, whatever its type;\n * - every UUID inside a string becomes `'[redacted-uuid]'` — any version,\n * including v7;\n * - a string that parses as a URL keeps its origin and path but loses its query\n * string, fragment and userinfo;\n * - every email address inside a string becomes `'[redacted-email]'`.\n *\n * Bounded and total by construction, because a `beforeSend` that throws loses\n * the event and raises inside the caller: repeat visits yield `'[circular]'`\n * (`WeakSet`), nodes past a depth of 32 yield `'[max-depth]'`, and a property\n * whose getter throws yields `'[unreadable]'`. Each of those fails closed — an\n * untraversed value cannot leak.\n *\n * Deliberately dependency-free: the event is typed structurally, so the privacy\n * behaviour is unit-testable without a Sentry client and this package takes no\n * dependency on `@sentry/*`.\n *\n * @param extraSensitiveKeyPattern - Extra key fragments to redact, merged with\n * the base pattern. Its flags are ignored; matching is always\n * case-insensitive and stateless.\n * @returns A function suitable for `Sentry.init({ beforeSend })`.\n * @example\n * Sentry.init({\n * dsn,\n * enabled: Boolean(dsn),\n * beforeSend: createSentryScrubber(/(prizedetail|fanhmac|seed)/i),\n * });\n */\nexport function createSentryScrubber(\n extraSensitiveKeyPattern: RegExp | null = null,\n): SentryScrubber {\n const sensitiveKeyPattern = mergeSensitiveKeyPattern(extraSensitiveKeyPattern);\n\n return function scrubSentryEvent<T>(event: T): T {\n return scrubValue(event, '', sensitiveKeyPattern, new WeakSet<object>(), 0) as T;\n };\n}\n"],"x_google_ignoreList":[7,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32],"mappings":"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"}
|