Sign In

@peac/contracts

Package Overview
Dependencies
Maintainers
1
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@peac/contracts - npm Package Compare versions

Comparing version
0.15.1
to
0.15.2
+31
dist/issuer-origin.d.ts
/**
* Canonical issuer-origin allowlist check.
*
* Surfaces use this helper to decide whether a receipt or TAP issuer origin is
* configured as trusted. The comparison is intentionally origin-based
* (scheme + host + port), not host-only, and fails closed for malformed inputs.
*
* Runtime-neutral by construction: it uses only the standard URL API and runs
* unchanged on Node, Workers, Deno, and Bun. It performs no DNS resolution, no
* network access, and no private-IP checks; outbound-fetch SSRF protection is a
* separate fetch-layer concern.
*/
/**
* Returns true iff `candidate` matches an entry in `allowlist` by https origin.
*
* Comparison is by URL origin (scheme + host + port); a default `:443` is
* normalized away by the `URL` API, a non-default port must match exactly, and
* a scheme mismatch (e.g. an `http:` candidate against an `https:` entry) never
* matches.
*
* Fails closed:
* - an empty allowlist returns false;
* - a candidate that is not a parseable absolute https URL, or that carries
* userinfo or control characters, returns false;
* - a malformed or non-https allowlist entry is skipped (it never matches) but
* does not prevent a later valid entry from matching.
*
* There is no wildcard, suffix, regex, or raw-string fallback matching.
*/
export declare function isAllowedIssuerOrigin(candidate: string, allowlist: readonly string[]): boolean;
//# sourceMappingURL=issuer-origin.d.ts.map
{"version":3,"file":"issuer-origin.d.ts","sourceRoot":"","sources":["../src/issuer-origin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA6CH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAW9F"}
+1
-0

@@ -25,2 +25,3 @@ /**

readonly TAP_KEY_NOT_FOUND: "E_TAP_KEY_NOT_FOUND";
readonly TAP_KEYID_INVALID: "E_TAP_KEYID_INVALID";
readonly TAP_NONCE_REPLAY: "E_TAP_NONCE_REPLAY";

@@ -27,0 +28,0 @@ readonly TAP_REPLAY_PROTECTION_REQUIRED: "E_TAP_REPLAY_PROTECTION_REQUIRED";

+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"codes.d.ts","sourceRoot":"","sources":["../src/codes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;CA6BxB,CAAC;AAEX;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,OAAO,qBAAqB,CAAC,CAAC"}
{"version":3,"file":"codes.d.ts","sourceRoot":"","sources":["../src/codes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;CA8BxB,CAAC;AAEX;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,OAAO,qBAAqB,CAAC,CAAC"}

@@ -17,2 +17,3 @@ 'use strict';

TAP_KEY_NOT_FOUND: "E_TAP_KEY_NOT_FOUND",
TAP_KEYID_INVALID: "E_TAP_KEYID_INVALID",
// Replay error (409 - Conflict)

@@ -30,2 +31,43 @@ TAP_NONCE_REPLAY: "E_TAP_NONCE_REPLAY",

// src/issuer-origin.ts
function hasAsciiControl(value) {
for (let index = 0; index < value.length; index += 1) {
const code = value.charCodeAt(index);
if (code <= 31 || code === 127) {
return true;
}
}
return false;
}
function toHttpsOrigin(value) {
if (value.trim() !== value || hasAsciiControl(value)) {
return null;
}
let url;
try {
url = new URL(value);
} catch {
return null;
}
if (url.protocol !== "https:") {
return null;
}
if (url.username !== "" || url.password !== "") {
return null;
}
return url.origin;
}
function isAllowedIssuerOrigin(candidate, allowlist) {
const candidateOrigin = toHttpsOrigin(candidate);
if (candidateOrigin === null) {
return false;
}
for (const entry of allowlist) {
if (toHttpsOrigin(entry) === candidateOrigin) {
return true;
}
}
return false;
}
// src/internal/error-codes.ts

@@ -47,2 +89,3 @@ var VALUES = Object.values(CANONICAL_ERROR_CODES);

[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: 401,
[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: 401,
[CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: 401,

@@ -72,2 +115,3 @@ // 400 - Client errors (malformed)

[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: "Key Not Found",
[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: "Invalid Key ID",
[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: "Nonce Replay Detected",

@@ -146,2 +190,7 @@ [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: "Replay Protection Required",

},
[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: {
status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID],
title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID],
defaultDetail: "TAP keyid must be an absolute https URL identifying the issuer."
},
[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: {

@@ -195,2 +244,3 @@ status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY],

exports.getStatusForCode = getStatusForCode;
exports.isAllowedIssuerOrigin = isAllowedIssuerOrigin;
exports.isPeacErrorCode = isPeacErrorCode;

@@ -197,0 +247,0 @@ exports.problemTypeFor = problemTypeFor;

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/codes.ts","../src/internal/error-codes.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Canonical PEAC error codes.\n *\n * This is the single source of truth for error code values.\n * All other modules import from here to avoid circular dependencies.\n */\n\n/**\n * Canonical PEAC error codes.\n *\n * Format: E_<CATEGORY>_<ERROR>\n *\n * All error codes use the E_ prefix for consistency with RFC/IETF error code conventions.\n */\nexport const CANONICAL_ERROR_CODES = {\n // Receipt errors (402 - Payment Required)\n RECEIPT_MISSING: 'E_RECEIPT_MISSING',\n RECEIPT_INVALID: 'E_RECEIPT_INVALID',\n RECEIPT_EXPIRED: 'E_RECEIPT_EXPIRED',\n\n // TAP errors (401 - Authentication)\n TAP_SIGNATURE_MISSING: 'E_TAP_SIGNATURE_MISSING',\n TAP_SIGNATURE_INVALID: 'E_TAP_SIGNATURE_INVALID',\n TAP_TIME_INVALID: 'E_TAP_TIME_INVALID',\n TAP_WINDOW_TOO_LARGE: 'E_TAP_WINDOW_TOO_LARGE',\n TAP_TAG_UNKNOWN: 'E_TAP_TAG_UNKNOWN',\n TAP_ALGORITHM_INVALID: 'E_TAP_ALGORITHM_INVALID',\n TAP_KEY_NOT_FOUND: 'E_TAP_KEY_NOT_FOUND',\n\n // Replay error (409 - Conflict)\n TAP_NONCE_REPLAY: 'E_TAP_NONCE_REPLAY',\n\n // Replay protection required (401 - requires config change)\n TAP_REPLAY_PROTECTION_REQUIRED: 'E_TAP_REPLAY_PROTECTION_REQUIRED',\n\n // Issuer errors (403 - Forbidden)\n ISSUER_NOT_ALLOWED: 'E_ISSUER_NOT_ALLOWED',\n\n // Configuration errors (500 - Server misconfiguration)\n CONFIG_ISSUER_ALLOWLIST_REQUIRED: 'E_CONFIG_ISSUER_ALLOWLIST_REQUIRED',\n\n // Internal errors (500)\n INTERNAL_ERROR: 'E_INTERNAL_ERROR',\n} as const;\n\n/**\n * PEAC error code type (union of all canonical error codes).\n *\n * Use this type for compile-time safety when handling error codes.\n */\nexport type PeacErrorCode = (typeof CANONICAL_ERROR_CODES)[keyof typeof CANONICAL_ERROR_CODES];\n","/**\n * Internal error code utilities.\n *\n * @internal - Not part of public API. Consumers should import from `@peac/contracts`.\n */\n\nimport { CANONICAL_ERROR_CODES, type PeacErrorCode } from '../codes.js';\n\n/**\n * Set of all canonical PEAC error codes for O(1) validation.\n *\n * Typed as ReadonlySet to prevent accidental mutation.\n *\n * @internal\n */\nconst VALUES = Object.values(CANONICAL_ERROR_CODES) as PeacErrorCode[];\nexport const PEAC_ERROR_CODE_SET: ReadonlySet<PeacErrorCode> = new Set(VALUES);\n","/**\n * PEAC Canonical Contracts\n *\n * Single source of truth for error codes, HTTP status mappings, and verification mode behavior.\n * All surface implementations MUST import from this package to prevent drift.\n *\n * @packageDocumentation\n */\n\n// Re-export canonical error codes from internal module (avoids circular dependencies)\nexport { CANONICAL_ERROR_CODES, type PeacErrorCode } from './codes.js';\nimport { CANONICAL_ERROR_CODES, type PeacErrorCode } from './codes.js';\n\n/**\n * Base URI for RFC 9457 Problem Details type field.\n */\nexport const PROBLEM_TYPE_BASE = 'https://www.peacprotocol.org/problems';\n\n/**\n * Canonical HTTP status code mappings.\n *\n * Status code semantics:\n * - 400: Client error (malformed request, invalid parameters)\n * - 401: Authentication required (missing/invalid credentials)\n * - 402: Payment Required (reserved for PEAC receipt payment flows)\n * - 403: Forbidden (authenticated but not authorized)\n * - 409: Conflict (replay detection - request conflicts with previous state)\n * - 500: Server error (configuration, internal failure)\n */\nexport const CANONICAL_STATUS_MAPPINGS: Record<PeacErrorCode, number> = {\n // 402 - Payment Required (reserved for payment flows)\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: 402,\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: 402,\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: 402,\n\n // 401 - Authentication errors\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: 401,\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: 401,\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: 401,\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: 401,\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: 401,\n\n // 400 - Client errors (malformed)\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: 400,\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: 400,\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: 400,\n\n // 403 - Forbidden (issuer not in allowlist)\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: 403,\n\n // 409 - Conflict (replay detected)\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: 409,\n\n // 500 - Server errors\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: 500,\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: 500,\n};\n\n/**\n * Canonical error titles for RFC 9457 Problem Details.\n */\nexport const CANONICAL_TITLES: Record<PeacErrorCode, string> = {\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: 'Payment Required',\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: 'Invalid Receipt',\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: 'Receipt Expired',\n\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: 'Signature Missing',\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: 'Invalid Signature',\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: 'Invalid Signature Time',\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: 'Signature Window Too Large',\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: 'Unknown TAP Tag',\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: 'Invalid Algorithm',\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: 'Key Not Found',\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: 'Nonce Replay Detected',\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: 'Replay Protection Required',\n\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: 'Issuer Not Allowed',\n\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: 'Configuration Error',\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: 'Internal Server Error',\n};\n\n/**\n * Verification mode.\n *\n * Determines behavior when TAP headers are missing:\n * - tap_only: Missing TAP → 401 + E_TAP_SIGNATURE_MISSING (authentication required)\n * - receipt_or_tap: Missing TAP → 402 + E_RECEIPT_MISSING (payment remedy)\n */\nexport type VerificationMode = 'tap_only' | 'receipt_or_tap';\n\n/**\n * Handler action type.\n *\n * Determines how the handler should respond:\n * - error: Authentication/authorization error\n * - challenge: Payment challenge (402 only)\n * - pass: Bypass verification (bypass paths)\n * - forward: Verification succeeded, forward request\n */\nexport type HandlerAction = 'error' | 'challenge' | 'pass' | 'forward';\n\n/**\n * Mode behavior for missing TAP headers.\n */\nexport interface ModeBehavior {\n /** HTTP status code */\n status: number;\n /** PEAC error code */\n code: PeacErrorCode;\n /** Handler action */\n action: HandlerAction;\n}\n\n/**\n * Verification mode behavior contract.\n *\n * Defines expected HTTP status, error code, and action when no TAP headers are present.\n * This is the canonical source of truth for mode-based behavior.\n */\nexport const MODE_BEHAVIOR: Record<VerificationMode, ModeBehavior> = {\n receipt_or_tap: {\n status: 402,\n code: CANONICAL_ERROR_CODES.RECEIPT_MISSING,\n action: 'challenge',\n },\n tap_only: {\n status: 401,\n code: CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING,\n action: 'error',\n },\n} as const;\n\n/**\n * HTTP status codes that require WWW-Authenticate header.\n *\n * Per v0.9.27 decision: WWW-Authenticate is sent on both 401 (auth required) and 402 (payment remedy).\n */\nexport const WWW_AUTHENTICATE_STATUSES = [401, 402] as const;\n\n/**\n * Get RFC 9457 Problem Details type URI for an error code.\n *\n * @param code - PEAC error code\n * @returns Problem Details type URI (e.g., \"https://www.peacprotocol.org/problems/E_TAP_SIGNATURE_MISSING\")\n */\nexport function problemTypeFor(code: PeacErrorCode): string {\n return `${PROBLEM_TYPE_BASE}/${code}`;\n}\n\n/**\n * Error catalog entry.\n */\nexport interface ErrorCatalogEntry {\n /** HTTP status code */\n status: number;\n /** RFC 9457 title */\n title: string;\n /** Default detail message (can be overridden at runtime) */\n defaultDetail?: string;\n}\n\n/**\n * Error catalog with HTTP status, title, and default detail for each error code.\n *\n * Use this for constructing RFC 9457 Problem Details responses.\n */\nexport const ERROR_CATALOG: Record<PeacErrorCode, ErrorCatalogEntry> = {\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_MISSING],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_MISSING],\n defaultDetail: 'A valid PEAC receipt is required to access this resource.',\n },\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_INVALID],\n defaultDetail: 'The provided receipt is invalid.',\n },\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_EXPIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_EXPIRED],\n defaultDetail: 'The provided receipt has expired.',\n },\n\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING],\n defaultDetail: 'TAP signature headers are required.',\n },\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID],\n defaultDetail: 'TAP signature verification failed.',\n },\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_TIME_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_TIME_INVALID],\n defaultDetail: 'TAP signature time is invalid.',\n },\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE],\n defaultDetail: 'TAP signature time window exceeds maximum allowed.',\n },\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN],\n defaultDetail: 'Unknown TAP tag in signature.',\n },\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID],\n defaultDetail: 'TAP signature algorithm is invalid.',\n },\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND],\n defaultDetail: 'TAP signing key not found.',\n },\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY],\n defaultDetail: 'Nonce replay detected.',\n },\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED],\n defaultDetail:\n 'Replay protection required but not configured. Set UNSAFE_ALLOW_NO_REPLAY=true to bypass (UNSAFE for production).',\n },\n\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED],\n defaultDetail: 'Issuer not in allowlist.',\n },\n\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED],\n defaultDetail:\n 'Worker misconfigured: ISSUER_ALLOWLIST is required. Set UNSAFE_ALLOW_ANY_ISSUER=true to bypass (UNSAFE for production).',\n },\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.INTERNAL_ERROR],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.INTERNAL_ERROR],\n defaultDetail: 'An internal server error occurred.',\n },\n};\n\n/**\n * Get HTTP status code for a PEAC error code.\n *\n * @param code - PEAC error code\n * @returns HTTP status code\n */\nexport function getStatusForCode(code: PeacErrorCode): number {\n return CANONICAL_STATUS_MAPPINGS[code];\n}\n\n/**\n * Check if HTTP status requires WWW-Authenticate header.\n *\n * @param status - HTTP status code\n * @returns true if WWW-Authenticate header is required\n */\nexport function requiresWwwAuthenticate(status: number): boolean {\n return WWW_AUTHENTICATE_STATUSES.includes(status as 401 | 402);\n}\n\n/**\n * Build canonical WWW-Authenticate header value.\n *\n * Format: PEAC realm=\"<realm>\", error=\"<code>\", error_uri=\"<uri>\"\n *\n * @param code - PEAC error code\n * @param realm - Authentication realm (default: \"peac\")\n * @returns Canonical WWW-Authenticate header value\n */\nexport function buildWwwAuthenticate(code: PeacErrorCode, realm = 'peac'): string {\n return `PEAC realm=\"${realm}\", error=\"${code}\", error_uri=\"${problemTypeFor(code)}\"`;\n}\n\n/**\n * Valid PEAC HTTP status codes.\n *\n * All status codes that can be returned by PEAC verification handlers.\n */\nexport type PeacHttpStatus = 400 | 401 | 402 | 403 | 409 | 500;\n\n// Internal Set import - NOT re-exported\nimport { PEAC_ERROR_CODE_SET } from './internal/error-codes.js';\n\n/**\n * Type guard to check if a value is a valid PEAC error code.\n *\n * Uses O(1) Set lookup for performance.\n *\n * @param x - Value to check\n * @returns true if x is a valid PeacErrorCode\n *\n * @example\n * ```typescript\n * if (isPeacErrorCode(code)) {\n * // TypeScript now knows code is PeacErrorCode\n * const status = getStatusForCode(code);\n * }\n * ```\n */\nexport function isPeacErrorCode(x: unknown): x is PeacErrorCode {\n return typeof x === 'string' && PEAC_ERROR_CODE_SET.has(x as PeacErrorCode);\n}\n"]}
{"version":3,"sources":["../src/codes.ts","../src/issuer-origin.ts","../src/internal/error-codes.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Canonical PEAC error codes.\n *\n * This is the single source of truth for error code values.\n * All other modules import from here to avoid circular dependencies.\n */\n\n/**\n * Canonical PEAC error codes.\n *\n * Format: E_<CATEGORY>_<ERROR>\n *\n * All error codes use the E_ prefix for consistency with RFC/IETF error code conventions.\n */\nexport const CANONICAL_ERROR_CODES = {\n // Receipt errors (402 - Payment Required)\n RECEIPT_MISSING: 'E_RECEIPT_MISSING',\n RECEIPT_INVALID: 'E_RECEIPT_INVALID',\n RECEIPT_EXPIRED: 'E_RECEIPT_EXPIRED',\n\n // TAP errors (401 - Authentication)\n TAP_SIGNATURE_MISSING: 'E_TAP_SIGNATURE_MISSING',\n TAP_SIGNATURE_INVALID: 'E_TAP_SIGNATURE_INVALID',\n TAP_TIME_INVALID: 'E_TAP_TIME_INVALID',\n TAP_WINDOW_TOO_LARGE: 'E_TAP_WINDOW_TOO_LARGE',\n TAP_TAG_UNKNOWN: 'E_TAP_TAG_UNKNOWN',\n TAP_ALGORITHM_INVALID: 'E_TAP_ALGORITHM_INVALID',\n TAP_KEY_NOT_FOUND: 'E_TAP_KEY_NOT_FOUND',\n TAP_KEYID_INVALID: 'E_TAP_KEYID_INVALID',\n\n // Replay error (409 - Conflict)\n TAP_NONCE_REPLAY: 'E_TAP_NONCE_REPLAY',\n\n // Replay protection required (401 - requires config change)\n TAP_REPLAY_PROTECTION_REQUIRED: 'E_TAP_REPLAY_PROTECTION_REQUIRED',\n\n // Issuer errors (403 - Forbidden)\n ISSUER_NOT_ALLOWED: 'E_ISSUER_NOT_ALLOWED',\n\n // Configuration errors (500 - Server misconfiguration)\n CONFIG_ISSUER_ALLOWLIST_REQUIRED: 'E_CONFIG_ISSUER_ALLOWLIST_REQUIRED',\n\n // Internal errors (500)\n INTERNAL_ERROR: 'E_INTERNAL_ERROR',\n} as const;\n\n/**\n * PEAC error code type (union of all canonical error codes).\n *\n * Use this type for compile-time safety when handling error codes.\n */\nexport type PeacErrorCode = (typeof CANONICAL_ERROR_CODES)[keyof typeof CANONICAL_ERROR_CODES];\n","/**\n * Canonical issuer-origin allowlist check.\n *\n * Surfaces use this helper to decide whether a receipt or TAP issuer origin is\n * configured as trusted. The comparison is intentionally origin-based\n * (scheme + host + port), not host-only, and fails closed for malformed inputs.\n *\n * Runtime-neutral by construction: it uses only the standard URL API and runs\n * unchanged on Node, Workers, Deno, and Bun. It performs no DNS resolution, no\n * network access, and no private-IP checks; outbound-fetch SSRF protection is a\n * separate fetch-layer concern.\n */\n\n// True if the string contains an ASCII control character (C0 range or DEL).\n// Used to reject smuggled control characters that the URL API might otherwise\n// strip during parsing. Implemented as a code-unit scan rather than a regex\n// escape range to keep this security-sensitive source free of escape sequences.\nfunction hasAsciiControl(value: string): boolean {\n for (let index = 0; index < value.length; index += 1) {\n const code = value.charCodeAt(index);\n if (code <= 0x1f || code === 0x7f) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Normalize a value to its https origin, or null if it is not an acceptable\n * issuer origin. Acceptable means: no surrounding or embedded ASCII control\n * characters or whitespace, a parseable absolute URL, the `https:` scheme, and\n * no userinfo (username/password). Path, query, and fragment are not part of an\n * origin and are ignored.\n */\nfunction toHttpsOrigin(value: string): string | null {\n // Reject surrounding whitespace and embedded ASCII control characters before\n // parsing. The URL API would otherwise strip some of these, which could let a\n // padded or smuggled-control-character entry compare equal to a clean one.\n if (value.trim() !== value || hasAsciiControl(value)) {\n return null;\n }\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return null;\n }\n if (url.protocol !== 'https:') {\n return null;\n }\n if (url.username !== '' || url.password !== '') {\n return null;\n }\n return url.origin;\n}\n\n/**\n * Returns true iff `candidate` matches an entry in `allowlist` by https origin.\n *\n * Comparison is by URL origin (scheme + host + port); a default `:443` is\n * normalized away by the `URL` API, a non-default port must match exactly, and\n * a scheme mismatch (e.g. an `http:` candidate against an `https:` entry) never\n * matches.\n *\n * Fails closed:\n * - an empty allowlist returns false;\n * - a candidate that is not a parseable absolute https URL, or that carries\n * userinfo or control characters, returns false;\n * - a malformed or non-https allowlist entry is skipped (it never matches) but\n * does not prevent a later valid entry from matching.\n *\n * There is no wildcard, suffix, regex, or raw-string fallback matching.\n */\nexport function isAllowedIssuerOrigin(candidate: string, allowlist: readonly string[]): boolean {\n const candidateOrigin = toHttpsOrigin(candidate);\n if (candidateOrigin === null) {\n return false;\n }\n for (const entry of allowlist) {\n if (toHttpsOrigin(entry) === candidateOrigin) {\n return true;\n }\n }\n return false;\n}\n","/**\n * Internal error code utilities.\n *\n * @internal - Not part of public API. Consumers should import from `@peac/contracts`.\n */\n\nimport { CANONICAL_ERROR_CODES, type PeacErrorCode } from '../codes.js';\n\n/**\n * Set of all canonical PEAC error codes for O(1) validation.\n *\n * Typed as ReadonlySet to prevent accidental mutation.\n *\n * @internal\n */\nconst VALUES = Object.values(CANONICAL_ERROR_CODES) as PeacErrorCode[];\nexport const PEAC_ERROR_CODE_SET: ReadonlySet<PeacErrorCode> = new Set(VALUES);\n","/**\n * PEAC Canonical Contracts\n *\n * Single source of truth for error codes, HTTP status mappings, and verification mode behavior.\n * All surface implementations MUST import from this package to prevent drift.\n *\n * @packageDocumentation\n */\n\n// Re-export canonical error codes from internal module (avoids circular dependencies)\nexport { CANONICAL_ERROR_CODES, type PeacErrorCode } from './codes.js';\nimport { CANONICAL_ERROR_CODES, type PeacErrorCode } from './codes.js';\n\n// Canonical issuer-origin allowlist check shared across surfaces.\nexport { isAllowedIssuerOrigin } from './issuer-origin.js';\n\n/**\n * Base URI for RFC 9457 Problem Details type field.\n */\nexport const PROBLEM_TYPE_BASE = 'https://www.peacprotocol.org/problems';\n\n/**\n * Canonical HTTP status code mappings.\n *\n * Status code semantics:\n * - 400: Client error (malformed request, invalid parameters)\n * - 401: Authentication required (missing/invalid credentials)\n * - 402: Payment Required (reserved for PEAC receipt payment flows)\n * - 403: Forbidden (authenticated but not authorized)\n * - 409: Conflict (replay detection - request conflicts with previous state)\n * - 500: Server error (configuration, internal failure)\n */\nexport const CANONICAL_STATUS_MAPPINGS: Record<PeacErrorCode, number> = {\n // 402 - Payment Required (reserved for payment flows)\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: 402,\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: 402,\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: 402,\n\n // 401 - Authentication errors\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: 401,\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: 401,\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: 401,\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: 401,\n [CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: 401,\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: 401,\n\n // 400 - Client errors (malformed)\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: 400,\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: 400,\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: 400,\n\n // 403 - Forbidden (issuer not in allowlist)\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: 403,\n\n // 409 - Conflict (replay detected)\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: 409,\n\n // 500 - Server errors\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: 500,\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: 500,\n};\n\n/**\n * Canonical error titles for RFC 9457 Problem Details.\n */\nexport const CANONICAL_TITLES: Record<PeacErrorCode, string> = {\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: 'Payment Required',\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: 'Invalid Receipt',\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: 'Receipt Expired',\n\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: 'Signature Missing',\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: 'Invalid Signature',\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: 'Invalid Signature Time',\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: 'Signature Window Too Large',\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: 'Unknown TAP Tag',\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: 'Invalid Algorithm',\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: 'Key Not Found',\n [CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: 'Invalid Key ID',\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: 'Nonce Replay Detected',\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: 'Replay Protection Required',\n\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: 'Issuer Not Allowed',\n\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: 'Configuration Error',\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: 'Internal Server Error',\n};\n\n/**\n * Verification mode.\n *\n * Determines behavior when TAP headers are missing:\n * - tap_only: Missing TAP → 401 + E_TAP_SIGNATURE_MISSING (authentication required)\n * - receipt_or_tap: Missing TAP → 402 + E_RECEIPT_MISSING (payment remedy)\n */\nexport type VerificationMode = 'tap_only' | 'receipt_or_tap';\n\n/**\n * Handler action type.\n *\n * Determines how the handler should respond:\n * - error: Authentication/authorization error\n * - challenge: Payment challenge (402 only)\n * - pass: Bypass verification (bypass paths)\n * - forward: Verification succeeded, forward request\n */\nexport type HandlerAction = 'error' | 'challenge' | 'pass' | 'forward';\n\n/**\n * Mode behavior for missing TAP headers.\n */\nexport interface ModeBehavior {\n /** HTTP status code */\n status: number;\n /** PEAC error code */\n code: PeacErrorCode;\n /** Handler action */\n action: HandlerAction;\n}\n\n/**\n * Verification mode behavior contract.\n *\n * Defines expected HTTP status, error code, and action when no TAP headers are present.\n * This is the canonical source of truth for mode-based behavior.\n */\nexport const MODE_BEHAVIOR: Record<VerificationMode, ModeBehavior> = {\n receipt_or_tap: {\n status: 402,\n code: CANONICAL_ERROR_CODES.RECEIPT_MISSING,\n action: 'challenge',\n },\n tap_only: {\n status: 401,\n code: CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING,\n action: 'error',\n },\n} as const;\n\n/**\n * HTTP status codes that require WWW-Authenticate header.\n *\n * Per v0.9.27 decision: WWW-Authenticate is sent on both 401 (auth required) and 402 (payment remedy).\n */\nexport const WWW_AUTHENTICATE_STATUSES = [401, 402] as const;\n\n/**\n * Get RFC 9457 Problem Details type URI for an error code.\n *\n * @param code - PEAC error code\n * @returns Problem Details type URI (e.g., \"https://www.peacprotocol.org/problems/E_TAP_SIGNATURE_MISSING\")\n */\nexport function problemTypeFor(code: PeacErrorCode): string {\n return `${PROBLEM_TYPE_BASE}/${code}`;\n}\n\n/**\n * Error catalog entry.\n */\nexport interface ErrorCatalogEntry {\n /** HTTP status code */\n status: number;\n /** RFC 9457 title */\n title: string;\n /** Default detail message (can be overridden at runtime) */\n defaultDetail?: string;\n}\n\n/**\n * Error catalog with HTTP status, title, and default detail for each error code.\n *\n * Use this for constructing RFC 9457 Problem Details responses.\n */\nexport const ERROR_CATALOG: Record<PeacErrorCode, ErrorCatalogEntry> = {\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_MISSING],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_MISSING],\n defaultDetail: 'A valid PEAC receipt is required to access this resource.',\n },\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_INVALID],\n defaultDetail: 'The provided receipt is invalid.',\n },\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_EXPIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_EXPIRED],\n defaultDetail: 'The provided receipt has expired.',\n },\n\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING],\n defaultDetail: 'TAP signature headers are required.',\n },\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID],\n defaultDetail: 'TAP signature verification failed.',\n },\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_TIME_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_TIME_INVALID],\n defaultDetail: 'TAP signature time is invalid.',\n },\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE],\n defaultDetail: 'TAP signature time window exceeds maximum allowed.',\n },\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN],\n defaultDetail: 'Unknown TAP tag in signature.',\n },\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID],\n defaultDetail: 'TAP signature algorithm is invalid.',\n },\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND],\n defaultDetail: 'TAP signing key not found.',\n },\n [CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID],\n defaultDetail: 'TAP keyid must be an absolute https URL identifying the issuer.',\n },\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY],\n defaultDetail: 'Nonce replay detected.',\n },\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED],\n defaultDetail:\n 'Replay protection required but not configured. Set UNSAFE_ALLOW_NO_REPLAY=true to bypass (UNSAFE for production).',\n },\n\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED],\n defaultDetail: 'Issuer not in allowlist.',\n },\n\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED],\n defaultDetail:\n 'Worker misconfigured: ISSUER_ALLOWLIST is required. Set UNSAFE_ALLOW_ANY_ISSUER=true to bypass (UNSAFE for production).',\n },\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.INTERNAL_ERROR],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.INTERNAL_ERROR],\n defaultDetail: 'An internal server error occurred.',\n },\n};\n\n/**\n * Get HTTP status code for a PEAC error code.\n *\n * @param code - PEAC error code\n * @returns HTTP status code\n */\nexport function getStatusForCode(code: PeacErrorCode): number {\n return CANONICAL_STATUS_MAPPINGS[code];\n}\n\n/**\n * Check if HTTP status requires WWW-Authenticate header.\n *\n * @param status - HTTP status code\n * @returns true if WWW-Authenticate header is required\n */\nexport function requiresWwwAuthenticate(status: number): boolean {\n return WWW_AUTHENTICATE_STATUSES.includes(status as 401 | 402);\n}\n\n/**\n * Build canonical WWW-Authenticate header value.\n *\n * Format: PEAC realm=\"<realm>\", error=\"<code>\", error_uri=\"<uri>\"\n *\n * @param code - PEAC error code\n * @param realm - Authentication realm (default: \"peac\")\n * @returns Canonical WWW-Authenticate header value\n */\nexport function buildWwwAuthenticate(code: PeacErrorCode, realm = 'peac'): string {\n return `PEAC realm=\"${realm}\", error=\"${code}\", error_uri=\"${problemTypeFor(code)}\"`;\n}\n\n/**\n * Valid PEAC HTTP status codes.\n *\n * All status codes that can be returned by PEAC verification handlers.\n */\nexport type PeacHttpStatus = 400 | 401 | 402 | 403 | 409 | 500;\n\n// Internal Set import - NOT re-exported\nimport { PEAC_ERROR_CODE_SET } from './internal/error-codes.js';\n\n/**\n * Type guard to check if a value is a valid PEAC error code.\n *\n * Uses O(1) Set lookup for performance.\n *\n * @param x - Value to check\n * @returns true if x is a valid PeacErrorCode\n *\n * @example\n * ```typescript\n * if (isPeacErrorCode(code)) {\n * // TypeScript now knows code is PeacErrorCode\n * const status = getStatusForCode(code);\n * }\n * ```\n */\nexport function isPeacErrorCode(x: unknown): x is PeacErrorCode {\n return typeof x === 'string' && PEAC_ERROR_CODE_SET.has(x as PeacErrorCode);\n}\n"]}

@@ -11,2 +11,3 @@ /**

import { type PeacErrorCode } from './codes.js';
export { isAllowedIssuerOrigin } from './issuer-origin.js';
/**

@@ -13,0 +14,0 @@ * Base URI for RFC 9457 Problem Details type field.

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,qBAAqB,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvE;;GAEG;AACH,eAAO,MAAM,iBAAiB,0CAA0C,CAAC;AAEzE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CA2BnE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAmB1D,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,gBAAgB,CAAC;AAE7D;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,IAAI,EAAE,aAAa,CAAC;IACpB,qBAAqB;IACrB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,gBAAgB,EAAE,YAAY,CAWvD,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,qBAAsB,CAAC;AAE7D;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAE1D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,iBAAiB,CAiFlE,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,SAAS,GAAG,MAAM,CAEhF;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAK/D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,aAAa,CAE9D"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,qBAAqB,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAGvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;GAEG;AACH,eAAO,MAAM,iBAAiB,0CAA0C,CAAC;AAEzE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CA4BnE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAoB1D,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,gBAAgB,CAAC;AAE7D;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,IAAI,EAAE,aAAa,CAAC;IACpB,qBAAqB;IACrB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,gBAAgB,EAAE,YAAY,CAWvD,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,qBAAsB,CAAC;AAE7D;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAE1D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,iBAAiB,CAsFlE,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,SAAS,GAAG,MAAM,CAEhF;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAK/D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,aAAa,CAE9D"}

@@ -15,2 +15,3 @@ // src/codes.ts

TAP_KEY_NOT_FOUND: "E_TAP_KEY_NOT_FOUND",
TAP_KEYID_INVALID: "E_TAP_KEYID_INVALID",
// Replay error (409 - Conflict)

@@ -28,2 +29,43 @@ TAP_NONCE_REPLAY: "E_TAP_NONCE_REPLAY",

// src/issuer-origin.ts
function hasAsciiControl(value) {
for (let index = 0; index < value.length; index += 1) {
const code = value.charCodeAt(index);
if (code <= 31 || code === 127) {
return true;
}
}
return false;
}
function toHttpsOrigin(value) {
if (value.trim() !== value || hasAsciiControl(value)) {
return null;
}
let url;
try {
url = new URL(value);
} catch {
return null;
}
if (url.protocol !== "https:") {
return null;
}
if (url.username !== "" || url.password !== "") {
return null;
}
return url.origin;
}
function isAllowedIssuerOrigin(candidate, allowlist) {
const candidateOrigin = toHttpsOrigin(candidate);
if (candidateOrigin === null) {
return false;
}
for (const entry of allowlist) {
if (toHttpsOrigin(entry) === candidateOrigin) {
return true;
}
}
return false;
}
// src/internal/error-codes.ts

@@ -45,2 +87,3 @@ var VALUES = Object.values(CANONICAL_ERROR_CODES);

[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: 401,
[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: 401,
[CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: 401,

@@ -70,2 +113,3 @@ // 400 - Client errors (malformed)

[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: "Key Not Found",
[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: "Invalid Key ID",
[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: "Nonce Replay Detected",

@@ -144,2 +188,7 @@ [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: "Replay Protection Required",

},
[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: {
status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID],
title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID],
defaultDetail: "TAP keyid must be an absolute https URL identifying the issuer."
},
[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: {

@@ -184,4 +233,4 @@ status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY],

export { CANONICAL_ERROR_CODES, CANONICAL_STATUS_MAPPINGS, CANONICAL_TITLES, ERROR_CATALOG, MODE_BEHAVIOR, PROBLEM_TYPE_BASE, WWW_AUTHENTICATE_STATUSES, buildWwwAuthenticate, getStatusForCode, isPeacErrorCode, problemTypeFor, requiresWwwAuthenticate };
export { CANONICAL_ERROR_CODES, CANONICAL_STATUS_MAPPINGS, CANONICAL_TITLES, ERROR_CATALOG, MODE_BEHAVIOR, PROBLEM_TYPE_BASE, WWW_AUTHENTICATE_STATUSES, buildWwwAuthenticate, getStatusForCode, isAllowedIssuerOrigin, isPeacErrorCode, problemTypeFor, requiresWwwAuthenticate };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/codes.ts","../src/internal/error-codes.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Canonical PEAC error codes.\n *\n * This is the single source of truth for error code values.\n * All other modules import from here to avoid circular dependencies.\n */\n\n/**\n * Canonical PEAC error codes.\n *\n * Format: E_<CATEGORY>_<ERROR>\n *\n * All error codes use the E_ prefix for consistency with RFC/IETF error code conventions.\n */\nexport const CANONICAL_ERROR_CODES = {\n // Receipt errors (402 - Payment Required)\n RECEIPT_MISSING: 'E_RECEIPT_MISSING',\n RECEIPT_INVALID: 'E_RECEIPT_INVALID',\n RECEIPT_EXPIRED: 'E_RECEIPT_EXPIRED',\n\n // TAP errors (401 - Authentication)\n TAP_SIGNATURE_MISSING: 'E_TAP_SIGNATURE_MISSING',\n TAP_SIGNATURE_INVALID: 'E_TAP_SIGNATURE_INVALID',\n TAP_TIME_INVALID: 'E_TAP_TIME_INVALID',\n TAP_WINDOW_TOO_LARGE: 'E_TAP_WINDOW_TOO_LARGE',\n TAP_TAG_UNKNOWN: 'E_TAP_TAG_UNKNOWN',\n TAP_ALGORITHM_INVALID: 'E_TAP_ALGORITHM_INVALID',\n TAP_KEY_NOT_FOUND: 'E_TAP_KEY_NOT_FOUND',\n\n // Replay error (409 - Conflict)\n TAP_NONCE_REPLAY: 'E_TAP_NONCE_REPLAY',\n\n // Replay protection required (401 - requires config change)\n TAP_REPLAY_PROTECTION_REQUIRED: 'E_TAP_REPLAY_PROTECTION_REQUIRED',\n\n // Issuer errors (403 - Forbidden)\n ISSUER_NOT_ALLOWED: 'E_ISSUER_NOT_ALLOWED',\n\n // Configuration errors (500 - Server misconfiguration)\n CONFIG_ISSUER_ALLOWLIST_REQUIRED: 'E_CONFIG_ISSUER_ALLOWLIST_REQUIRED',\n\n // Internal errors (500)\n INTERNAL_ERROR: 'E_INTERNAL_ERROR',\n} as const;\n\n/**\n * PEAC error code type (union of all canonical error codes).\n *\n * Use this type for compile-time safety when handling error codes.\n */\nexport type PeacErrorCode = (typeof CANONICAL_ERROR_CODES)[keyof typeof CANONICAL_ERROR_CODES];\n","/**\n * Internal error code utilities.\n *\n * @internal - Not part of public API. Consumers should import from `@peac/contracts`.\n */\n\nimport { CANONICAL_ERROR_CODES, type PeacErrorCode } from '../codes.js';\n\n/**\n * Set of all canonical PEAC error codes for O(1) validation.\n *\n * Typed as ReadonlySet to prevent accidental mutation.\n *\n * @internal\n */\nconst VALUES = Object.values(CANONICAL_ERROR_CODES) as PeacErrorCode[];\nexport const PEAC_ERROR_CODE_SET: ReadonlySet<PeacErrorCode> = new Set(VALUES);\n","/**\n * PEAC Canonical Contracts\n *\n * Single source of truth for error codes, HTTP status mappings, and verification mode behavior.\n * All surface implementations MUST import from this package to prevent drift.\n *\n * @packageDocumentation\n */\n\n// Re-export canonical error codes from internal module (avoids circular dependencies)\nexport { CANONICAL_ERROR_CODES, type PeacErrorCode } from './codes.js';\nimport { CANONICAL_ERROR_CODES, type PeacErrorCode } from './codes.js';\n\n/**\n * Base URI for RFC 9457 Problem Details type field.\n */\nexport const PROBLEM_TYPE_BASE = 'https://www.peacprotocol.org/problems';\n\n/**\n * Canonical HTTP status code mappings.\n *\n * Status code semantics:\n * - 400: Client error (malformed request, invalid parameters)\n * - 401: Authentication required (missing/invalid credentials)\n * - 402: Payment Required (reserved for PEAC receipt payment flows)\n * - 403: Forbidden (authenticated but not authorized)\n * - 409: Conflict (replay detection - request conflicts with previous state)\n * - 500: Server error (configuration, internal failure)\n */\nexport const CANONICAL_STATUS_MAPPINGS: Record<PeacErrorCode, number> = {\n // 402 - Payment Required (reserved for payment flows)\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: 402,\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: 402,\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: 402,\n\n // 401 - Authentication errors\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: 401,\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: 401,\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: 401,\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: 401,\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: 401,\n\n // 400 - Client errors (malformed)\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: 400,\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: 400,\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: 400,\n\n // 403 - Forbidden (issuer not in allowlist)\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: 403,\n\n // 409 - Conflict (replay detected)\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: 409,\n\n // 500 - Server errors\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: 500,\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: 500,\n};\n\n/**\n * Canonical error titles for RFC 9457 Problem Details.\n */\nexport const CANONICAL_TITLES: Record<PeacErrorCode, string> = {\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: 'Payment Required',\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: 'Invalid Receipt',\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: 'Receipt Expired',\n\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: 'Signature Missing',\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: 'Invalid Signature',\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: 'Invalid Signature Time',\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: 'Signature Window Too Large',\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: 'Unknown TAP Tag',\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: 'Invalid Algorithm',\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: 'Key Not Found',\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: 'Nonce Replay Detected',\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: 'Replay Protection Required',\n\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: 'Issuer Not Allowed',\n\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: 'Configuration Error',\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: 'Internal Server Error',\n};\n\n/**\n * Verification mode.\n *\n * Determines behavior when TAP headers are missing:\n * - tap_only: Missing TAP → 401 + E_TAP_SIGNATURE_MISSING (authentication required)\n * - receipt_or_tap: Missing TAP → 402 + E_RECEIPT_MISSING (payment remedy)\n */\nexport type VerificationMode = 'tap_only' | 'receipt_or_tap';\n\n/**\n * Handler action type.\n *\n * Determines how the handler should respond:\n * - error: Authentication/authorization error\n * - challenge: Payment challenge (402 only)\n * - pass: Bypass verification (bypass paths)\n * - forward: Verification succeeded, forward request\n */\nexport type HandlerAction = 'error' | 'challenge' | 'pass' | 'forward';\n\n/**\n * Mode behavior for missing TAP headers.\n */\nexport interface ModeBehavior {\n /** HTTP status code */\n status: number;\n /** PEAC error code */\n code: PeacErrorCode;\n /** Handler action */\n action: HandlerAction;\n}\n\n/**\n * Verification mode behavior contract.\n *\n * Defines expected HTTP status, error code, and action when no TAP headers are present.\n * This is the canonical source of truth for mode-based behavior.\n */\nexport const MODE_BEHAVIOR: Record<VerificationMode, ModeBehavior> = {\n receipt_or_tap: {\n status: 402,\n code: CANONICAL_ERROR_CODES.RECEIPT_MISSING,\n action: 'challenge',\n },\n tap_only: {\n status: 401,\n code: CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING,\n action: 'error',\n },\n} as const;\n\n/**\n * HTTP status codes that require WWW-Authenticate header.\n *\n * Per v0.9.27 decision: WWW-Authenticate is sent on both 401 (auth required) and 402 (payment remedy).\n */\nexport const WWW_AUTHENTICATE_STATUSES = [401, 402] as const;\n\n/**\n * Get RFC 9457 Problem Details type URI for an error code.\n *\n * @param code - PEAC error code\n * @returns Problem Details type URI (e.g., \"https://www.peacprotocol.org/problems/E_TAP_SIGNATURE_MISSING\")\n */\nexport function problemTypeFor(code: PeacErrorCode): string {\n return `${PROBLEM_TYPE_BASE}/${code}`;\n}\n\n/**\n * Error catalog entry.\n */\nexport interface ErrorCatalogEntry {\n /** HTTP status code */\n status: number;\n /** RFC 9457 title */\n title: string;\n /** Default detail message (can be overridden at runtime) */\n defaultDetail?: string;\n}\n\n/**\n * Error catalog with HTTP status, title, and default detail for each error code.\n *\n * Use this for constructing RFC 9457 Problem Details responses.\n */\nexport const ERROR_CATALOG: Record<PeacErrorCode, ErrorCatalogEntry> = {\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_MISSING],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_MISSING],\n defaultDetail: 'A valid PEAC receipt is required to access this resource.',\n },\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_INVALID],\n defaultDetail: 'The provided receipt is invalid.',\n },\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_EXPIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_EXPIRED],\n defaultDetail: 'The provided receipt has expired.',\n },\n\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING],\n defaultDetail: 'TAP signature headers are required.',\n },\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID],\n defaultDetail: 'TAP signature verification failed.',\n },\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_TIME_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_TIME_INVALID],\n defaultDetail: 'TAP signature time is invalid.',\n },\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE],\n defaultDetail: 'TAP signature time window exceeds maximum allowed.',\n },\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN],\n defaultDetail: 'Unknown TAP tag in signature.',\n },\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID],\n defaultDetail: 'TAP signature algorithm is invalid.',\n },\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND],\n defaultDetail: 'TAP signing key not found.',\n },\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY],\n defaultDetail: 'Nonce replay detected.',\n },\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED],\n defaultDetail:\n 'Replay protection required but not configured. Set UNSAFE_ALLOW_NO_REPLAY=true to bypass (UNSAFE for production).',\n },\n\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED],\n defaultDetail: 'Issuer not in allowlist.',\n },\n\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED],\n defaultDetail:\n 'Worker misconfigured: ISSUER_ALLOWLIST is required. Set UNSAFE_ALLOW_ANY_ISSUER=true to bypass (UNSAFE for production).',\n },\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.INTERNAL_ERROR],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.INTERNAL_ERROR],\n defaultDetail: 'An internal server error occurred.',\n },\n};\n\n/**\n * Get HTTP status code for a PEAC error code.\n *\n * @param code - PEAC error code\n * @returns HTTP status code\n */\nexport function getStatusForCode(code: PeacErrorCode): number {\n return CANONICAL_STATUS_MAPPINGS[code];\n}\n\n/**\n * Check if HTTP status requires WWW-Authenticate header.\n *\n * @param status - HTTP status code\n * @returns true if WWW-Authenticate header is required\n */\nexport function requiresWwwAuthenticate(status: number): boolean {\n return WWW_AUTHENTICATE_STATUSES.includes(status as 401 | 402);\n}\n\n/**\n * Build canonical WWW-Authenticate header value.\n *\n * Format: PEAC realm=\"<realm>\", error=\"<code>\", error_uri=\"<uri>\"\n *\n * @param code - PEAC error code\n * @param realm - Authentication realm (default: \"peac\")\n * @returns Canonical WWW-Authenticate header value\n */\nexport function buildWwwAuthenticate(code: PeacErrorCode, realm = 'peac'): string {\n return `PEAC realm=\"${realm}\", error=\"${code}\", error_uri=\"${problemTypeFor(code)}\"`;\n}\n\n/**\n * Valid PEAC HTTP status codes.\n *\n * All status codes that can be returned by PEAC verification handlers.\n */\nexport type PeacHttpStatus = 400 | 401 | 402 | 403 | 409 | 500;\n\n// Internal Set import - NOT re-exported\nimport { PEAC_ERROR_CODE_SET } from './internal/error-codes.js';\n\n/**\n * Type guard to check if a value is a valid PEAC error code.\n *\n * Uses O(1) Set lookup for performance.\n *\n * @param x - Value to check\n * @returns true if x is a valid PeacErrorCode\n *\n * @example\n * ```typescript\n * if (isPeacErrorCode(code)) {\n * // TypeScript now knows code is PeacErrorCode\n * const status = getStatusForCode(code);\n * }\n * ```\n */\nexport function isPeacErrorCode(x: unknown): x is PeacErrorCode {\n return typeof x === 'string' && PEAC_ERROR_CODE_SET.has(x as PeacErrorCode);\n}\n"]}
{"version":3,"sources":["../src/codes.ts","../src/issuer-origin.ts","../src/internal/error-codes.ts","../src/index.ts"],"names":[],"mappings":";AAcO,IAAM,qBAAA,GAAwB;AAAA;AAAA,EAEnC,eAAA,EAAiB,mBAAA;AAAA,EACjB,eAAA,EAAiB,mBAAA;AAAA,EACjB,eAAA,EAAiB,mBAAA;AAAA;AAAA,EAGjB,qBAAA,EAAuB,yBAAA;AAAA,EACvB,qBAAA,EAAuB,yBAAA;AAAA,EACvB,gBAAA,EAAkB,oBAAA;AAAA,EAClB,oBAAA,EAAsB,wBAAA;AAAA,EACtB,eAAA,EAAiB,mBAAA;AAAA,EACjB,qBAAA,EAAuB,yBAAA;AAAA,EACvB,iBAAA,EAAmB,qBAAA;AAAA,EACnB,iBAAA,EAAmB,qBAAA;AAAA;AAAA,EAGnB,gBAAA,EAAkB,oBAAA;AAAA;AAAA,EAGlB,8BAAA,EAAgC,kCAAA;AAAA;AAAA,EAGhC,kBAAA,EAAoB,sBAAA;AAAA;AAAA,EAGpB,gCAAA,EAAkC,oCAAA;AAAA;AAAA,EAGlC,cAAA,EAAgB;AAClB;;;AC3BA,SAAS,gBAAgB,KAAA,EAAwB;AAC/C,EAAA,KAAA,IAAS,QAAQ,CAAA,EAAG,KAAA,GAAQ,KAAA,CAAM,MAAA,EAAQ,SAAS,CAAA,EAAG;AACpD,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,UAAA,CAAW,KAAK,CAAA;AACnC,IAAA,IAAI,IAAA,IAAQ,EAAA,IAAQ,IAAA,KAAS,GAAA,EAAM;AACjC,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AASA,SAAS,cAAc,KAAA,EAA8B;AAInD,EAAA,IAAI,MAAM,IAAA,EAAK,KAAM,KAAA,IAAS,eAAA,CAAgB,KAAK,CAAA,EAAG;AACpD,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,IAAI,IAAI,KAAK,CAAA;AAAA,EACrB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,GAAA,CAAI,aAAa,QAAA,EAAU;AAC7B,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,GAAA,CAAI,QAAA,KAAa,EAAA,IAAM,GAAA,CAAI,aAAa,EAAA,EAAI;AAC9C,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,GAAA,CAAI,MAAA;AACb;AAmBO,SAAS,qBAAA,CAAsB,WAAmB,SAAA,EAAuC;AAC9F,EAAA,MAAM,eAAA,GAAkB,cAAc,SAAS,CAAA;AAC/C,EAAA,IAAI,oBAAoB,IAAA,EAAM;AAC5B,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,KAAA,MAAW,SAAS,SAAA,EAAW;AAC7B,IAAA,IAAI,aAAA,CAAc,KAAK,CAAA,KAAM,eAAA,EAAiB;AAC5C,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;;;ACrEA,IAAM,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,qBAAqB,CAAA;AAC3C,IAAM,mBAAA,GAAkD,IAAI,GAAA,CAAI,MAAM,CAAA;;;ACGtE,IAAM,iBAAA,GAAoB;AAa1B,IAAM,yBAAA,GAA2D;AAAA;AAAA,EAEtE,CAAC,qBAAA,CAAsB,eAAe,GAAG,GAAA;AAAA,EACzC,CAAC,qBAAA,CAAsB,eAAe,GAAG,GAAA;AAAA,EACzC,CAAC,qBAAA,CAAsB,eAAe,GAAG,GAAA;AAAA;AAAA,EAGzC,CAAC,qBAAA,CAAsB,qBAAqB,GAAG,GAAA;AAAA,EAC/C,CAAC,qBAAA,CAAsB,qBAAqB,GAAG,GAAA;AAAA,EAC/C,CAAC,qBAAA,CAAsB,gBAAgB,GAAG,GAAA;AAAA,EAC1C,CAAC,qBAAA,CAAsB,iBAAiB,GAAG,GAAA;AAAA,EAC3C,CAAC,qBAAA,CAAsB,iBAAiB,GAAG,GAAA;AAAA,EAC3C,CAAC,qBAAA,CAAsB,8BAA8B,GAAG,GAAA;AAAA;AAAA,EAGxD,CAAC,qBAAA,CAAsB,oBAAoB,GAAG,GAAA;AAAA,EAC9C,CAAC,qBAAA,CAAsB,eAAe,GAAG,GAAA;AAAA,EACzC,CAAC,qBAAA,CAAsB,qBAAqB,GAAG,GAAA;AAAA;AAAA,EAG/C,CAAC,qBAAA,CAAsB,kBAAkB,GAAG,GAAA;AAAA;AAAA,EAG5C,CAAC,qBAAA,CAAsB,gBAAgB,GAAG,GAAA;AAAA;AAAA,EAG1C,CAAC,qBAAA,CAAsB,gCAAgC,GAAG,GAAA;AAAA,EAC1D,CAAC,qBAAA,CAAsB,cAAc,GAAG;AAC1C;AAKO,IAAM,gBAAA,GAAkD;AAAA,EAC7D,CAAC,qBAAA,CAAsB,eAAe,GAAG,kBAAA;AAAA,EACzC,CAAC,qBAAA,CAAsB,eAAe,GAAG,iBAAA;AAAA,EACzC,CAAC,qBAAA,CAAsB,eAAe,GAAG,iBAAA;AAAA,EAEzC,CAAC,qBAAA,CAAsB,qBAAqB,GAAG,mBAAA;AAAA,EAC/C,CAAC,qBAAA,CAAsB,qBAAqB,GAAG,mBAAA;AAAA,EAC/C,CAAC,qBAAA,CAAsB,gBAAgB,GAAG,wBAAA;AAAA,EAC1C,CAAC,qBAAA,CAAsB,oBAAoB,GAAG,4BAAA;AAAA,EAC9C,CAAC,qBAAA,CAAsB,eAAe,GAAG,iBAAA;AAAA,EACzC,CAAC,qBAAA,CAAsB,qBAAqB,GAAG,mBAAA;AAAA,EAC/C,CAAC,qBAAA,CAAsB,iBAAiB,GAAG,eAAA;AAAA,EAC3C,CAAC,qBAAA,CAAsB,iBAAiB,GAAG,gBAAA;AAAA,EAC3C,CAAC,qBAAA,CAAsB,gBAAgB,GAAG,uBAAA;AAAA,EAC1C,CAAC,qBAAA,CAAsB,8BAA8B,GAAG,4BAAA;AAAA,EAExD,CAAC,qBAAA,CAAsB,kBAAkB,GAAG,oBAAA;AAAA,EAE5C,CAAC,qBAAA,CAAsB,gCAAgC,GAAG,qBAAA;AAAA,EAC1D,CAAC,qBAAA,CAAsB,cAAc,GAAG;AAC1C;AAwCO,IAAM,aAAA,GAAwD;AAAA,EACnE,cAAA,EAAgB;AAAA,IACd,MAAA,EAAQ,GAAA;AAAA,IACR,MAAM,qBAAA,CAAsB,eAAA;AAAA,IAC5B,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,QAAA,EAAU;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,MAAM,qBAAA,CAAsB,qBAAA;AAAA,IAC5B,MAAA,EAAQ;AAAA;AAEZ;AAOO,IAAM,yBAAA,GAA4B,CAAC,GAAA,EAAK,GAAG;AAQ3C,SAAS,eAAe,IAAA,EAA6B;AAC1D,EAAA,OAAO,CAAA,EAAG,iBAAiB,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AACrC;AAmBO,IAAM,aAAA,GAA0D;AAAA,EACrE,CAAC,qBAAA,CAAsB,eAAe,GAAG;AAAA,IACvC,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,eAAe,CAAA;AAAA,IACvE,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,eAAe,CAAA;AAAA,IAC7D,aAAA,EAAe;AAAA,GACjB;AAAA,EACA,CAAC,qBAAA,CAAsB,eAAe,GAAG;AAAA,IACvC,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,eAAe,CAAA;AAAA,IACvE,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,eAAe,CAAA;AAAA,IAC7D,aAAA,EAAe;AAAA,GACjB;AAAA,EACA,CAAC,qBAAA,CAAsB,eAAe,GAAG;AAAA,IACvC,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,eAAe,CAAA;AAAA,IACvE,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,eAAe,CAAA;AAAA,IAC7D,aAAA,EAAe;AAAA,GACjB;AAAA,EAEA,CAAC,qBAAA,CAAsB,qBAAqB,GAAG;AAAA,IAC7C,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,qBAAqB,CAAA;AAAA,IAC7E,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,qBAAqB,CAAA;AAAA,IACnE,aAAA,EAAe;AAAA,GACjB;AAAA,EACA,CAAC,qBAAA,CAAsB,qBAAqB,GAAG;AAAA,IAC7C,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,qBAAqB,CAAA;AAAA,IAC7E,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,qBAAqB,CAAA;AAAA,IACnE,aAAA,EAAe;AAAA,GACjB;AAAA,EACA,CAAC,qBAAA,CAAsB,gBAAgB,GAAG;AAAA,IACxC,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,gBAAgB,CAAA;AAAA,IACxE,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,gBAAgB,CAAA;AAAA,IAC9D,aAAA,EAAe;AAAA,GACjB;AAAA,EACA,CAAC,qBAAA,CAAsB,oBAAoB,GAAG;AAAA,IAC5C,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,oBAAoB,CAAA;AAAA,IAC5E,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,oBAAoB,CAAA;AAAA,IAClE,aAAA,EAAe;AAAA,GACjB;AAAA,EACA,CAAC,qBAAA,CAAsB,eAAe,GAAG;AAAA,IACvC,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,eAAe,CAAA;AAAA,IACvE,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,eAAe,CAAA;AAAA,IAC7D,aAAA,EAAe;AAAA,GACjB;AAAA,EACA,CAAC,qBAAA,CAAsB,qBAAqB,GAAG;AAAA,IAC7C,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,qBAAqB,CAAA;AAAA,IAC7E,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,qBAAqB,CAAA;AAAA,IACnE,aAAA,EAAe;AAAA,GACjB;AAAA,EACA,CAAC,qBAAA,CAAsB,iBAAiB,GAAG;AAAA,IACzC,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,iBAAiB,CAAA;AAAA,IACzE,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,iBAAiB,CAAA;AAAA,IAC/D,aAAA,EAAe;AAAA,GACjB;AAAA,EACA,CAAC,qBAAA,CAAsB,iBAAiB,GAAG;AAAA,IACzC,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,iBAAiB,CAAA;AAAA,IACzE,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,iBAAiB,CAAA;AAAA,IAC/D,aAAA,EAAe;AAAA,GACjB;AAAA,EACA,CAAC,qBAAA,CAAsB,gBAAgB,GAAG;AAAA,IACxC,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,gBAAgB,CAAA;AAAA,IACxE,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,gBAAgB,CAAA;AAAA,IAC9D,aAAA,EAAe;AAAA,GACjB;AAAA,EACA,CAAC,qBAAA,CAAsB,8BAA8B,GAAG;AAAA,IACtD,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,8BAA8B,CAAA;AAAA,IACtF,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,8BAA8B,CAAA;AAAA,IAC5E,aAAA,EACE;AAAA,GACJ;AAAA,EAEA,CAAC,qBAAA,CAAsB,kBAAkB,GAAG;AAAA,IAC1C,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,kBAAkB,CAAA;AAAA,IAC1E,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,kBAAkB,CAAA;AAAA,IAChE,aAAA,EAAe;AAAA,GACjB;AAAA,EAEA,CAAC,qBAAA,CAAsB,gCAAgC,GAAG;AAAA,IACxD,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,gCAAgC,CAAA;AAAA,IACxF,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,gCAAgC,CAAA;AAAA,IAC9E,aAAA,EACE;AAAA,GACJ;AAAA,EACA,CAAC,qBAAA,CAAsB,cAAc,GAAG;AAAA,IACtC,MAAA,EAAQ,yBAAA,CAA0B,qBAAA,CAAsB,cAAc,CAAA;AAAA,IACtE,KAAA,EAAO,gBAAA,CAAiB,qBAAA,CAAsB,cAAc,CAAA;AAAA,IAC5D,aAAA,EAAe;AAAA;AAEnB;AAQO,SAAS,iBAAiB,IAAA,EAA6B;AAC5D,EAAA,OAAO,0BAA0B,IAAI,CAAA;AACvC;AAQO,SAAS,wBAAwB,MAAA,EAAyB;AAC/D,EAAA,OAAO,yBAAA,CAA0B,SAAS,MAAmB,CAAA;AAC/D;AAWO,SAAS,oBAAA,CAAqB,IAAA,EAAqB,KAAA,GAAQ,MAAA,EAAgB;AAChF,EAAA,OAAO,eAAe,KAAK,CAAA,UAAA,EAAa,IAAI,CAAA,cAAA,EAAiB,cAAA,CAAe,IAAI,CAAC,CAAA,CAAA,CAAA;AACnF;AA4BO,SAAS,gBAAgB,CAAA,EAAgC;AAC9D,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,IAAY,mBAAA,CAAoB,IAAI,CAAkB,CAAA;AAC5E","file":"index.js","sourcesContent":["/**\n * Canonical PEAC error codes.\n *\n * This is the single source of truth for error code values.\n * All other modules import from here to avoid circular dependencies.\n */\n\n/**\n * Canonical PEAC error codes.\n *\n * Format: E_<CATEGORY>_<ERROR>\n *\n * All error codes use the E_ prefix for consistency with RFC/IETF error code conventions.\n */\nexport const CANONICAL_ERROR_CODES = {\n // Receipt errors (402 - Payment Required)\n RECEIPT_MISSING: 'E_RECEIPT_MISSING',\n RECEIPT_INVALID: 'E_RECEIPT_INVALID',\n RECEIPT_EXPIRED: 'E_RECEIPT_EXPIRED',\n\n // TAP errors (401 - Authentication)\n TAP_SIGNATURE_MISSING: 'E_TAP_SIGNATURE_MISSING',\n TAP_SIGNATURE_INVALID: 'E_TAP_SIGNATURE_INVALID',\n TAP_TIME_INVALID: 'E_TAP_TIME_INVALID',\n TAP_WINDOW_TOO_LARGE: 'E_TAP_WINDOW_TOO_LARGE',\n TAP_TAG_UNKNOWN: 'E_TAP_TAG_UNKNOWN',\n TAP_ALGORITHM_INVALID: 'E_TAP_ALGORITHM_INVALID',\n TAP_KEY_NOT_FOUND: 'E_TAP_KEY_NOT_FOUND',\n TAP_KEYID_INVALID: 'E_TAP_KEYID_INVALID',\n\n // Replay error (409 - Conflict)\n TAP_NONCE_REPLAY: 'E_TAP_NONCE_REPLAY',\n\n // Replay protection required (401 - requires config change)\n TAP_REPLAY_PROTECTION_REQUIRED: 'E_TAP_REPLAY_PROTECTION_REQUIRED',\n\n // Issuer errors (403 - Forbidden)\n ISSUER_NOT_ALLOWED: 'E_ISSUER_NOT_ALLOWED',\n\n // Configuration errors (500 - Server misconfiguration)\n CONFIG_ISSUER_ALLOWLIST_REQUIRED: 'E_CONFIG_ISSUER_ALLOWLIST_REQUIRED',\n\n // Internal errors (500)\n INTERNAL_ERROR: 'E_INTERNAL_ERROR',\n} as const;\n\n/**\n * PEAC error code type (union of all canonical error codes).\n *\n * Use this type for compile-time safety when handling error codes.\n */\nexport type PeacErrorCode = (typeof CANONICAL_ERROR_CODES)[keyof typeof CANONICAL_ERROR_CODES];\n","/**\n * Canonical issuer-origin allowlist check.\n *\n * Surfaces use this helper to decide whether a receipt or TAP issuer origin is\n * configured as trusted. The comparison is intentionally origin-based\n * (scheme + host + port), not host-only, and fails closed for malformed inputs.\n *\n * Runtime-neutral by construction: it uses only the standard URL API and runs\n * unchanged on Node, Workers, Deno, and Bun. It performs no DNS resolution, no\n * network access, and no private-IP checks; outbound-fetch SSRF protection is a\n * separate fetch-layer concern.\n */\n\n// True if the string contains an ASCII control character (C0 range or DEL).\n// Used to reject smuggled control characters that the URL API might otherwise\n// strip during parsing. Implemented as a code-unit scan rather than a regex\n// escape range to keep this security-sensitive source free of escape sequences.\nfunction hasAsciiControl(value: string): boolean {\n for (let index = 0; index < value.length; index += 1) {\n const code = value.charCodeAt(index);\n if (code <= 0x1f || code === 0x7f) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Normalize a value to its https origin, or null if it is not an acceptable\n * issuer origin. Acceptable means: no surrounding or embedded ASCII control\n * characters or whitespace, a parseable absolute URL, the `https:` scheme, and\n * no userinfo (username/password). Path, query, and fragment are not part of an\n * origin and are ignored.\n */\nfunction toHttpsOrigin(value: string): string | null {\n // Reject surrounding whitespace and embedded ASCII control characters before\n // parsing. The URL API would otherwise strip some of these, which could let a\n // padded or smuggled-control-character entry compare equal to a clean one.\n if (value.trim() !== value || hasAsciiControl(value)) {\n return null;\n }\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return null;\n }\n if (url.protocol !== 'https:') {\n return null;\n }\n if (url.username !== '' || url.password !== '') {\n return null;\n }\n return url.origin;\n}\n\n/**\n * Returns true iff `candidate` matches an entry in `allowlist` by https origin.\n *\n * Comparison is by URL origin (scheme + host + port); a default `:443` is\n * normalized away by the `URL` API, a non-default port must match exactly, and\n * a scheme mismatch (e.g. an `http:` candidate against an `https:` entry) never\n * matches.\n *\n * Fails closed:\n * - an empty allowlist returns false;\n * - a candidate that is not a parseable absolute https URL, or that carries\n * userinfo or control characters, returns false;\n * - a malformed or non-https allowlist entry is skipped (it never matches) but\n * does not prevent a later valid entry from matching.\n *\n * There is no wildcard, suffix, regex, or raw-string fallback matching.\n */\nexport function isAllowedIssuerOrigin(candidate: string, allowlist: readonly string[]): boolean {\n const candidateOrigin = toHttpsOrigin(candidate);\n if (candidateOrigin === null) {\n return false;\n }\n for (const entry of allowlist) {\n if (toHttpsOrigin(entry) === candidateOrigin) {\n return true;\n }\n }\n return false;\n}\n","/**\n * Internal error code utilities.\n *\n * @internal - Not part of public API. Consumers should import from `@peac/contracts`.\n */\n\nimport { CANONICAL_ERROR_CODES, type PeacErrorCode } from '../codes.js';\n\n/**\n * Set of all canonical PEAC error codes for O(1) validation.\n *\n * Typed as ReadonlySet to prevent accidental mutation.\n *\n * @internal\n */\nconst VALUES = Object.values(CANONICAL_ERROR_CODES) as PeacErrorCode[];\nexport const PEAC_ERROR_CODE_SET: ReadonlySet<PeacErrorCode> = new Set(VALUES);\n","/**\n * PEAC Canonical Contracts\n *\n * Single source of truth for error codes, HTTP status mappings, and verification mode behavior.\n * All surface implementations MUST import from this package to prevent drift.\n *\n * @packageDocumentation\n */\n\n// Re-export canonical error codes from internal module (avoids circular dependencies)\nexport { CANONICAL_ERROR_CODES, type PeacErrorCode } from './codes.js';\nimport { CANONICAL_ERROR_CODES, type PeacErrorCode } from './codes.js';\n\n// Canonical issuer-origin allowlist check shared across surfaces.\nexport { isAllowedIssuerOrigin } from './issuer-origin.js';\n\n/**\n * Base URI for RFC 9457 Problem Details type field.\n */\nexport const PROBLEM_TYPE_BASE = 'https://www.peacprotocol.org/problems';\n\n/**\n * Canonical HTTP status code mappings.\n *\n * Status code semantics:\n * - 400: Client error (malformed request, invalid parameters)\n * - 401: Authentication required (missing/invalid credentials)\n * - 402: Payment Required (reserved for PEAC receipt payment flows)\n * - 403: Forbidden (authenticated but not authorized)\n * - 409: Conflict (replay detection - request conflicts with previous state)\n * - 500: Server error (configuration, internal failure)\n */\nexport const CANONICAL_STATUS_MAPPINGS: Record<PeacErrorCode, number> = {\n // 402 - Payment Required (reserved for payment flows)\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: 402,\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: 402,\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: 402,\n\n // 401 - Authentication errors\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: 401,\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: 401,\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: 401,\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: 401,\n [CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: 401,\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: 401,\n\n // 400 - Client errors (malformed)\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: 400,\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: 400,\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: 400,\n\n // 403 - Forbidden (issuer not in allowlist)\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: 403,\n\n // 409 - Conflict (replay detected)\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: 409,\n\n // 500 - Server errors\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: 500,\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: 500,\n};\n\n/**\n * Canonical error titles for RFC 9457 Problem Details.\n */\nexport const CANONICAL_TITLES: Record<PeacErrorCode, string> = {\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: 'Payment Required',\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: 'Invalid Receipt',\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: 'Receipt Expired',\n\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: 'Signature Missing',\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: 'Invalid Signature',\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: 'Invalid Signature Time',\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: 'Signature Window Too Large',\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: 'Unknown TAP Tag',\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: 'Invalid Algorithm',\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: 'Key Not Found',\n [CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: 'Invalid Key ID',\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: 'Nonce Replay Detected',\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: 'Replay Protection Required',\n\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: 'Issuer Not Allowed',\n\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: 'Configuration Error',\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: 'Internal Server Error',\n};\n\n/**\n * Verification mode.\n *\n * Determines behavior when TAP headers are missing:\n * - tap_only: Missing TAP → 401 + E_TAP_SIGNATURE_MISSING (authentication required)\n * - receipt_or_tap: Missing TAP → 402 + E_RECEIPT_MISSING (payment remedy)\n */\nexport type VerificationMode = 'tap_only' | 'receipt_or_tap';\n\n/**\n * Handler action type.\n *\n * Determines how the handler should respond:\n * - error: Authentication/authorization error\n * - challenge: Payment challenge (402 only)\n * - pass: Bypass verification (bypass paths)\n * - forward: Verification succeeded, forward request\n */\nexport type HandlerAction = 'error' | 'challenge' | 'pass' | 'forward';\n\n/**\n * Mode behavior for missing TAP headers.\n */\nexport interface ModeBehavior {\n /** HTTP status code */\n status: number;\n /** PEAC error code */\n code: PeacErrorCode;\n /** Handler action */\n action: HandlerAction;\n}\n\n/**\n * Verification mode behavior contract.\n *\n * Defines expected HTTP status, error code, and action when no TAP headers are present.\n * This is the canonical source of truth for mode-based behavior.\n */\nexport const MODE_BEHAVIOR: Record<VerificationMode, ModeBehavior> = {\n receipt_or_tap: {\n status: 402,\n code: CANONICAL_ERROR_CODES.RECEIPT_MISSING,\n action: 'challenge',\n },\n tap_only: {\n status: 401,\n code: CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING,\n action: 'error',\n },\n} as const;\n\n/**\n * HTTP status codes that require WWW-Authenticate header.\n *\n * Per v0.9.27 decision: WWW-Authenticate is sent on both 401 (auth required) and 402 (payment remedy).\n */\nexport const WWW_AUTHENTICATE_STATUSES = [401, 402] as const;\n\n/**\n * Get RFC 9457 Problem Details type URI for an error code.\n *\n * @param code - PEAC error code\n * @returns Problem Details type URI (e.g., \"https://www.peacprotocol.org/problems/E_TAP_SIGNATURE_MISSING\")\n */\nexport function problemTypeFor(code: PeacErrorCode): string {\n return `${PROBLEM_TYPE_BASE}/${code}`;\n}\n\n/**\n * Error catalog entry.\n */\nexport interface ErrorCatalogEntry {\n /** HTTP status code */\n status: number;\n /** RFC 9457 title */\n title: string;\n /** Default detail message (can be overridden at runtime) */\n defaultDetail?: string;\n}\n\n/**\n * Error catalog with HTTP status, title, and default detail for each error code.\n *\n * Use this for constructing RFC 9457 Problem Details responses.\n */\nexport const ERROR_CATALOG: Record<PeacErrorCode, ErrorCatalogEntry> = {\n [CANONICAL_ERROR_CODES.RECEIPT_MISSING]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_MISSING],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_MISSING],\n defaultDetail: 'A valid PEAC receipt is required to access this resource.',\n },\n [CANONICAL_ERROR_CODES.RECEIPT_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_INVALID],\n defaultDetail: 'The provided receipt is invalid.',\n },\n [CANONICAL_ERROR_CODES.RECEIPT_EXPIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.RECEIPT_EXPIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.RECEIPT_EXPIRED],\n defaultDetail: 'The provided receipt has expired.',\n },\n\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_SIGNATURE_MISSING],\n defaultDetail: 'TAP signature headers are required.',\n },\n [CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_SIGNATURE_INVALID],\n defaultDetail: 'TAP signature verification failed.',\n },\n [CANONICAL_ERROR_CODES.TAP_TIME_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_TIME_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_TIME_INVALID],\n defaultDetail: 'TAP signature time is invalid.',\n },\n [CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_WINDOW_TOO_LARGE],\n defaultDetail: 'TAP signature time window exceeds maximum allowed.',\n },\n [CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_TAG_UNKNOWN],\n defaultDetail: 'Unknown TAP tag in signature.',\n },\n [CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_ALGORITHM_INVALID],\n defaultDetail: 'TAP signature algorithm is invalid.',\n },\n [CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_KEY_NOT_FOUND],\n defaultDetail: 'TAP signing key not found.',\n },\n [CANONICAL_ERROR_CODES.TAP_KEYID_INVALID]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_KEYID_INVALID],\n defaultDetail: 'TAP keyid must be an absolute https URL identifying the issuer.',\n },\n [CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_NONCE_REPLAY],\n defaultDetail: 'Nonce replay detected.',\n },\n [CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.TAP_REPLAY_PROTECTION_REQUIRED],\n defaultDetail:\n 'Replay protection required but not configured. Set UNSAFE_ALLOW_NO_REPLAY=true to bypass (UNSAFE for production).',\n },\n\n [CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.ISSUER_NOT_ALLOWED],\n defaultDetail: 'Issuer not in allowlist.',\n },\n\n [CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.CONFIG_ISSUER_ALLOWLIST_REQUIRED],\n defaultDetail:\n 'Worker misconfigured: ISSUER_ALLOWLIST is required. Set UNSAFE_ALLOW_ANY_ISSUER=true to bypass (UNSAFE for production).',\n },\n [CANONICAL_ERROR_CODES.INTERNAL_ERROR]: {\n status: CANONICAL_STATUS_MAPPINGS[CANONICAL_ERROR_CODES.INTERNAL_ERROR],\n title: CANONICAL_TITLES[CANONICAL_ERROR_CODES.INTERNAL_ERROR],\n defaultDetail: 'An internal server error occurred.',\n },\n};\n\n/**\n * Get HTTP status code for a PEAC error code.\n *\n * @param code - PEAC error code\n * @returns HTTP status code\n */\nexport function getStatusForCode(code: PeacErrorCode): number {\n return CANONICAL_STATUS_MAPPINGS[code];\n}\n\n/**\n * Check if HTTP status requires WWW-Authenticate header.\n *\n * @param status - HTTP status code\n * @returns true if WWW-Authenticate header is required\n */\nexport function requiresWwwAuthenticate(status: number): boolean {\n return WWW_AUTHENTICATE_STATUSES.includes(status as 401 | 402);\n}\n\n/**\n * Build canonical WWW-Authenticate header value.\n *\n * Format: PEAC realm=\"<realm>\", error=\"<code>\", error_uri=\"<uri>\"\n *\n * @param code - PEAC error code\n * @param realm - Authentication realm (default: \"peac\")\n * @returns Canonical WWW-Authenticate header value\n */\nexport function buildWwwAuthenticate(code: PeacErrorCode, realm = 'peac'): string {\n return `PEAC realm=\"${realm}\", error=\"${code}\", error_uri=\"${problemTypeFor(code)}\"`;\n}\n\n/**\n * Valid PEAC HTTP status codes.\n *\n * All status codes that can be returned by PEAC verification handlers.\n */\nexport type PeacHttpStatus = 400 | 401 | 402 | 403 | 409 | 500;\n\n// Internal Set import - NOT re-exported\nimport { PEAC_ERROR_CODE_SET } from './internal/error-codes.js';\n\n/**\n * Type guard to check if a value is a valid PEAC error code.\n *\n * Uses O(1) Set lookup for performance.\n *\n * @param x - Value to check\n * @returns true if x is a valid PeacErrorCode\n *\n * @example\n * ```typescript\n * if (isPeacErrorCode(code)) {\n * // TypeScript now knows code is PeacErrorCode\n * const status = getStatusForCode(code);\n * }\n * ```\n */\nexport function isPeacErrorCode(x: unknown): x is PeacErrorCode {\n return typeof x === 'string' && PEAC_ERROR_CODE_SET.has(x as PeacErrorCode);\n}\n"]}
{
"name": "@peac/contracts",
"version": "0.15.1",
"version": "0.15.2",
"description": "PEAC canonical error codes and verification mode contracts",

@@ -5,0 +5,0 @@ "type": "module",