@patchstack/connect 0.3.23 → 0.3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["ps-edge:ps-edge-stub", "../src/protect/safe-origin.js", "../src/protect/engine/client.js", "../src/protect/engine/request.js", "../src/protect/engine/normalizer.js", "../src/protect/engine/engine.js", "../src/pulse-token.ts", "../src/protect/engine/pulse-client.js", "../src/protect/engine/fetch.js", "../src/protect/engine/node.js", "../src/protect/egress.js", "../src/protect/defaults.js", "../src/protect/block-page.js", "../src/protect/rules/store.js", "../src/protect/rules/validate.js", "../src/protect/rules/source.js", "../src/protect/rules/refresh.js", "../src/protect/firewall-log.js", "../src/protect/supabase-guard.js", "../src/protect/runtime.js"],
4
+ "sourcesContent": ["throw new Error(\"[patchstack] this module is Node-only and unavailable on an edge runtime\");", "// Which origins this guard is willing to talk to. Both of its remote conversations are security\n// sensitive: the RULE endpoint delivers policy the engine then executes on every request (an\n// attacker-controlled endpoint could remove protection wholesale or serve a CPU-expensive ruleset), and\n// the telemetry endpoint receives the site api_key. Env/CI injection is the realistic threat, so a\n// non-default override must be https \u2014 with localhost permitted so local development and tests work.\nexport function isSafeOrigin(value) {\n try {\n const u = new URL(value);\n if (u.protocol === 'https:') return true;\n return u.protocol === 'http:' && (u.hostname === 'localhost' || u.hostname === '127.0.0.1' || u.hostname === '[::1]' || u.hostname === '::1');\n } catch {\n return false;\n }\n}\n\n/**\n * Accept `candidate` only if it is a safe origin; otherwise warn once and fall back to `fallback`.\n * @param {string|undefined} candidate @param {string} fallback @param {string} label\n */\nexport function safeBaseUrl(candidate, fallback, label) {\n if (typeof candidate !== 'string' || candidate === '') return fallback;\n if (isSafeOrigin(candidate)) return candidate;\n warnOnce(label, `[patchstack] ignoring unsafe ${label} override (${candidate}): must be https (or localhost). Using the default.`);\n return fallback;\n}\n\nconst warned = new Set();\nfunction warnOnce(key, message) {\n if (warned.has(key)) return;\n warned.add(key);\n // eslint-disable-next-line no-console\n console.warn(message);\n}\n", "import { safeBaseUrl } from '../safe-origin.js';\n\nconst DEFAULT_BASE_URL = 'https://api.patchstack.com';\nconst DEFAULT_CACHE_TTL = 300_000;\n// Randomly shorten the effective TTL by up to this fraction so many long-lived clients don't all\n// revalidate on the same tick (spreads load against the rules API).\nconst JITTER_FRACTION = 0.1;\n\n// Token-authenticated rules client. Conditional fetch (If-None-Match / 304) and the persisted\n// `etag` mirror PulseRuleClient; both are a no-op until the API emits an ETag and honors the\n// conditional request \u2014 with no ETag in the response the client behaves as before (full fetch).\nexport class PatchstackRuleClient {\n #token;\n #baseUrl;\n #cacheTtl;\n #cache = null;\n #cacheTime = null;\n #ttlEffective = 0;\n #etag;\n #timeoutMs;\n\n constructor({ token, baseUrl, cacheTtl, etag, timeoutMs } = {}) {\n // Bounded so app STARTUP can't hang on a slow API (see the boot budget in rules/source.js).\n this.#timeoutMs = Number(timeoutMs) > 0 ? Number(timeoutMs) : 30_000;\n this.#token = token ?? process.env.PATCHSTACK_WAF_TOKEN;\n this.#baseUrl = safeBaseUrl(baseUrl ?? process.env.PATCHSTACK_WAF_API_URL, DEFAULT_BASE_URL, 'rule endpoint');\n this.#cacheTtl = Number.isFinite(cacheTtl) && cacheTtl > 0 ? cacheTtl : DEFAULT_CACHE_TTL;\n this.#etag = etag ?? null;\n\n if (!this.#token) {\n throw new Error('Patchstack WAF token is required. Pass { token } or set PATCHSTACK_WAF_TOKEN env var.');\n }\n }\n\n async getRules() {\n const now = Date.now();\n\n if (this.#cache && this.#cacheTime !== null && (now - this.#cacheTime) < this.#ttlEffective) {\n return this.#cache;\n }\n\n const url = `${this.#baseUrl}/api/get-rules/3`;\n\n try {\n const headers = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.#token}`,\n 'LicenseID': '1' // Hard-coded, is never actually used but needed by the API\n };\n if (this.#etag) headers['If-None-Match'] = this.#etag;\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({}),\n signal: AbortSignal.timeout(this.#timeoutMs)\n });\n\n if (response.status === 304) {\n this.#touch(now); // revalidated \u2014 reset the clock (fresh jitter)\n return this.#cache ?? { success: true, notModified: true, etag: this.#etag, firewall: [], whitelists: [], whitelist_keys: {} };\n }\n\n if (!response.ok) {\n return {\n success: false,\n error: `API returned ${response.status}: ${response.statusText}`,\n firewall: [],\n whitelists: [],\n whitelist_keys: {}\n };\n }\n\n const data = await response.json();\n\n // A 200 that isn't a genuine rule envelope must not be treated as \"no rules\". Report failure\n // so the caller falls back to the cache / bundled rules rather than caching an empty bundle.\n if (!data || !Array.isArray(data.firewall)) {\n return { success: false, error: 'unexpected response shape (no firewall array)', firewall: [], whitelists: [], whitelist_keys: {} };\n }\n\n const result = {\n success: true,\n notModified: false,\n etag: response.headers?.get?.('etag') ?? null,\n firewall: data.firewall,\n whitelists: Array.isArray(data.whitelists) ? data.whitelists : [],\n whitelist_keys: data.whitelist_keys ?? {}\n };\n\n this.#cache = result;\n this.#etag = result.etag;\n this.#touch(now);\n\n return result;\n } catch (err) {\n return {\n success: false,\n error: err.name === 'TimeoutError'\n ? 'Request timed out'\n : err.message,\n firewall: [],\n whitelists: [],\n whitelist_keys: {}\n };\n }\n }\n\n #touch(now) {\n this.#cacheTime = now;\n this.#ttlEffective = this.#cacheTtl - Math.floor(Math.random() * this.#cacheTtl * JITTER_FRACTION);\n }\n\n clearCache() {\n this.#cache = null;\n this.#cacheTime = null;\n this.#etag = null;\n }\n}\n", "// Resolvable DATA attributes of an uploaded file part (files.<name>.<attr>). The engine only exposes\n// the raw data \u2014 WHAT counts as a malicious upload (signatures, type-vs-content mismatch) is expressed\n// in rules (see the triage-vpatch-npm skill), not hardcoded here.\nconst FILE_ATTRS = new Set(['content', 'filename', 'type']);\n\n// A captured file part is { filename, type, content }; tolerate the legacy bare-filename string.\nconst fileFilename = (f) => (f && typeof f === 'object' ? f.filename : f);\nconst fileAttribute = (f, attr) => (f && typeof f === 'object' ? f[attr] : attr === 'filename' ? f : undefined);\n\n// WinterCG-safe base64 decode: use Buffer on Node, fall back to atob/TextDecoder on\n// edge runtimes (Cloudflare Workers, Deno, Bun) where Buffer may be absent. Keeps the\n// engine hot path free of Node-only APIs (per the ADR engine-language decision).\nfunction base64DecodeUtf8(value) {\n const str = String(value);\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'base64').toString('utf-8');\n }\n const binary = atob(str);\n const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));\n return new TextDecoder().decode(bytes);\n}\n\nexport class RequestResolver {\n #req;\n #cookies;\n\n constructor(req) {\n this.#req = req;\n this.#cookies = null;\n }\n\n resolve(parameter) {\n if (!parameter || parameter === 'false') {\n return [null];\n }\n\n if (parameter === 'rules') {\n return [null];\n }\n\n if (parameter === 'raw') {\n return this.#resolveRaw();\n }\n\n if (parameter === 'all') {\n return this.#resolveAll();\n }\n\n const dotIndex = parameter.indexOf('.');\n if (dotIndex === -1) {\n return [];\n }\n\n const source = parameter.substring(0, dotIndex);\n const key = parameter.substring(dotIndex + 1);\n\n switch (source) {\n case 'get':\n return this.#resolveGet(key);\n case 'post':\n return this.#resolvePost(key);\n case 'request':\n return this.#resolveRequest(key);\n case 'cookie':\n return this.#resolveCookie(key);\n case 'server':\n return this.#resolveServer(key);\n case 'files':\n return this.#resolveFiles(key);\n case 'response':\n return this.#resolveResponse(key);\n case 'egress':\n return this.#resolveEgress(key);\n default:\n return [];\n }\n }\n\n // Response-phase sources (req._response = { status, headers, body }). Lets rules inspect\n // what the app is about to SEND \u2014 e.g. a leaked secret in the body \u2014 regardless of route.\n #resolveResponse(key) {\n const resp = this.#req._response;\n if (!resp) {\n return [];\n }\n if (key === 'status') {\n return resp.status !== undefined ? [String(resp.status)] : [];\n }\n if (key === 'body') {\n return resp.body != null && resp.body !== '' ? [resp.body] : [];\n }\n if (key === 'headers') {\n const headers = resp.headers ?? {};\n return [Object.entries(headers).map(([k, v]) => `${k}: ${v}`).join('\\n')];\n }\n if (key.startsWith('header.')) {\n const name = key.slice('header.'.length).toLowerCase();\n const value = (resp.headers ?? {})[name];\n return value !== undefined ? [value] : [];\n }\n return [];\n }\n\n // Egress-phase sources (req._egress = { url, host, method }). Lets rules inspect an\n // OUTBOUND request the app is about to make \u2014 SSRF at the egress boundary.\n #resolveEgress(key) {\n const eg = this.#req._egress;\n if (!eg) {\n return [];\n }\n if (key === 'url') return eg.url ? [eg.url] : [];\n if (key === 'host') return eg.host ? [eg.host] : [];\n if (key === 'method') return eg.method ? [eg.method] : [];\n return [];\n }\n\n applyMutations(mutations, value) {\n if (!mutations || !Array.isArray(mutations)) {\n return value;\n }\n\n let result = value;\n\n for (const mutation of mutations) {\n result = this.#applyMutation(mutation, result);\n }\n\n return result;\n }\n\n #applyMutation(mutation, value) {\n if (value === null || value === undefined) {\n return value;\n }\n\n switch (mutation) {\n case 'base64_decode':\n try {\n return base64DecodeUtf8(value);\n } catch {\n return value;\n }\n\n case 'json_decode':\n try {\n return JSON.parse(String(value));\n } catch {\n return value;\n }\n\n case 'json_encode':\n try {\n return JSON.stringify(value);\n } catch {\n return value;\n }\n\n case 'urldecode':\n try {\n return decodeURIComponent(String(value));\n } catch {\n return value;\n }\n\n case 'intval':\n return parseInt(String(value), 10) || 0;\n\n case 'getArrayValues':\n if (typeof value === 'object' && value !== null) {\n return Object.values(value);\n }\n return value;\n\n default:\n return value;\n }\n }\n\n #resolveGet(key) {\n const query = this.#req.query ?? {};\n\n if (key.endsWith('*')) {\n return this.#resolveWildcard(query, key);\n }\n\n const value = this.#getNestedValue(query, key);\n return value !== undefined ? [value] : [];\n }\n\n #resolvePost(key) {\n const body = this.#req.body ?? {};\n\n if (key.endsWith('*')) {\n return this.#resolveWildcard(body, key);\n }\n\n const value = this.#getNestedValue(body, key);\n return value !== undefined ? [value] : [];\n }\n\n #resolveRequest(key) {\n const query = this.#req.query ?? {};\n const body = this.#req.body ?? {};\n const cookies = this.#parseCookies();\n\n if (key.endsWith('*')) {\n return [\n ...this.#resolveWildcard(query, key),\n ...this.#resolveWildcard(body, key),\n ...this.#resolveWildcard(cookies, key)\n ];\n }\n\n const value = this.#getNestedValue(query, key)\n ?? this.#getNestedValue(body, key)\n ?? cookies[key];\n\n return value !== undefined ? [value] : [];\n }\n\n #resolveCookie(key) {\n const cookies = this.#parseCookies();\n\n if (key.endsWith('*')) {\n return this.#resolveWildcard(cookies, key);\n }\n\n const value = cookies[key];\n return value !== undefined ? [value] : [];\n }\n\n #resolveServer(key) {\n const req = this.#req;\n\n switch (key) {\n case 'REQUEST_URI':\n return [req.originalUrl ?? req.url ?? '/'];\n case 'REQUEST_METHOD':\n return [req.method ?? 'GET'];\n case 'HTTP_USER_AGENT':\n return req.headers?.['user-agent'] ? [req.headers['user-agent']] : [];\n case 'HTTP_REFERER':\n return req.headers?.referer ? [req.headers.referer] : [];\n case 'HTTP_HOST':\n return req.headers?.host ? [req.headers.host] : [];\n case 'REMOTE_ADDR':\n case 'ip':\n return [req.ip ?? req.socket?.remoteAddress ?? ''];\n case 'CONTENT_TYPE':\n return req.headers?.['content-type'] ? [req.headers['content-type']] : [];\n case 'CONTENT_LENGTH':\n return req.headers?.['content-length'] ? [req.headers['content-length']] : [];\n default: {\n if (key.startsWith('HTTP_')) {\n const headerName = key.substring(5).toLowerCase().replace(/_/g, '-');\n const headers = req.headers;\n // Presence, not truthiness. A header sent with an empty value IS present, and an `isset`\n // rule authored against it must see it \u2014 some bypasses are carried by the header existing\n // at all, so treating `Header:` as absent would make the rule quietly miss the shape it\n // was written for. (The named cases above keep value semantics: for host/origin/referer an\n // empty string and an absent header mean the same thing to the matchers that read them.)\n if (headers === null || typeof headers !== 'object') return [];\n return Object.prototype.hasOwnProperty.call(headers, headerName) ? [headers[headerName]] : [];\n }\n return [];\n }\n }\n }\n\n #resolveFiles(key) {\n const files = this.#req.files;\n if (!files || typeof files !== 'object') {\n return [];\n }\n\n // files.<name>.<attr> \u2014 content | filename | type. Fans out over multiple files uploaded under\n // the same field name.\n const dot = key.lastIndexOf('.');\n if (dot !== -1 && FILE_ATTRS.has(key.slice(dot + 1)) && Object.prototype.hasOwnProperty.call(files, key.slice(0, dot))) {\n const attr = key.slice(dot + 1);\n const entry = files[key.slice(0, dot)];\n const list = Array.isArray(entry) ? entry : [entry];\n const out = [];\n for (const f of list) {\n const v = fileAttribute(f, attr);\n if (v !== undefined && v !== '') out.push(v);\n }\n return out;\n }\n\n // Bare files.<name> (or wildcard) \u2192 the filename(s), preserving the legacy behavior that\n // filename-scoped rules rely on (the parser now stores a { filename, type, content } object).\n const filenamesOf = (entry) => (Array.isArray(entry) ? entry.map(fileFilename) : [fileFilename(entry)]);\n if (key.endsWith('*')) {\n const prefix = key.slice(0, -1);\n const out = [];\n for (const [k, entry] of Object.entries(files)) {\n if (k.startsWith(prefix)) out.push(...filenamesOf(entry));\n }\n return out.filter((v) => v !== undefined);\n }\n if (!Object.prototype.hasOwnProperty.call(files, key)) return [];\n return filenamesOf(files[key]).filter((v) => v !== undefined);\n }\n\n #resolveRaw() {\n // Use pre-captured raw body if available (set by normalizeRequest).\n // For string bodies, the original text is preserved verbatim.\n // For pre-parsed objects, serializeForRawDetection uses Object.getOwnPropertyNames()\n // to include __proto__ own-property keys that JSON.stringify() would silently drop.\n if (typeof this.#req._rawBody === 'string') {\n return this.#req._rawBody ? [this.#req._rawBody] : [];\n }\n\n const body = this.#req.body;\n\n if (body === undefined || body === null) {\n return [];\n }\n\n if (typeof body === 'string') {\n return [body];\n }\n\n try {\n return [JSON.stringify(body)];\n } catch {\n return [String(body)];\n }\n }\n\n #resolveAll() {\n const parts = [];\n\n const uri = this.#req.originalUrl ?? this.#req.url ?? '/';\n parts.push(uri);\n\n const queryString = uri.includes('?') ? uri.split('?')[1] : '';\n if (queryString) {\n parts.push(queryString);\n }\n\n const body = this.#req.body;\n if (body) {\n parts.push(typeof body === 'string' ? body : JSON.stringify(body));\n }\n // Also fold in the verbatim body: a body the adapter couldn't structurally parse (an unusual\n // content-type, a non-JSON payload) leaves `body` empty, but the raw text must still be matchable\n // by an `all` rule \u2014 otherwise it's only visible via `raw`.\n if (typeof this.#req._rawBody === 'string' && this.#req._rawBody) {\n parts.push(this.#req._rawBody);\n }\n\n const headers = this.#req.headers ?? {};\n const excludedHeaders = new Set([\n 'host', 'connection', 'cache-control', 'accept', 'accept-encoding',\n 'accept-language', 'priority', 'sec-ch-ua', 'sec-ch-ua-mobile',\n 'sec-ch-ua-platform', 'sec-fetch-dest', 'sec-fetch-mode',\n 'sec-fetch-site', 'sec-fetch-user', 'upgrade-insecure-requests'\n ]);\n\n for (const [name, value] of Object.entries(headers)) {\n if (!excludedHeaders.has(name)) {\n parts.push(`${name}: ${value}`);\n }\n }\n\n const cookies = this.#parseCookies();\n const cookieStr = Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join('; ');\n if (cookieStr) {\n parts.push(cookieStr);\n }\n\n return [parts.join(' ')];\n }\n\n #resolveWildcard(obj, pattern) {\n if (typeof obj !== 'object' || obj === null) {\n return [];\n }\n\n const prefix = pattern.slice(0, -1);\n const values = [];\n\n for (const [key, value] of Object.entries(obj)) {\n if (key.startsWith(prefix)) {\n values.push(value);\n }\n }\n\n return values;\n }\n\n #getNestedValue(obj, key) {\n if (typeof obj !== 'object' || obj === null) {\n return undefined;\n }\n\n // Own-property only: `key in obj` would resolve `__proto__`/`constructor`/`toString` to the\n // prototype chain, so a rule like `post.__proto__` (detecting a literal `__proto__` field) would\n // read Object.prototype instead of request data and never match. Use hasOwnProperty.\n const own = (o, k) => o !== null && typeof o === 'object' && Object.prototype.hasOwnProperty.call(o, k);\n\n if (own(obj, key)) {\n return obj[key];\n }\n\n const parts = key.split('.');\n let current = obj;\n\n for (const part of parts) {\n if (!own(current, part)) {\n return undefined;\n }\n current = current[part];\n }\n\n return current;\n }\n\n #parseCookies() {\n if (this.#cookies !== null) {\n return this.#cookies;\n }\n\n if (this.#req.cookies) {\n this.#cookies = this.#req.cookies;\n return this.#cookies;\n }\n\n const header = this.#req.headers?.cookie;\n if (!header) {\n this.#cookies = {};\n return this.#cookies;\n }\n\n const cookies = {};\n\n for (const pair of header.split(';')) {\n const eqIndex = pair.indexOf('=');\n if (eqIndex === -1) {\n continue;\n }\n const name = pair.substring(0, eqIndex).trim();\n const value = pair.substring(eqIndex + 1).trim();\n cookies[name] = value;\n }\n\n this.#cookies = cookies;\n return this.#cookies;\n }\n}\n", "/**\n * Request Normalization Pipeline\n *\n * Normalizes request data to prevent encoding-based bypass attacks.\n * This module handles URL encoding, HTML entities, SQL comments, and other\n * obfuscation techniques that attackers use to evade pattern matching.\n */\n\nconst HTML_ENTITIES = {\n '&amp;': '&',\n '&lt;': '<',\n '&gt;': '>',\n '&quot;': '\"',\n '&#39;': \"'\",\n '&apos;': \"'\",\n '&nbsp;': ' ',\n '&#x27;': \"'\",\n '&#x22;': '\"',\n '&#x3C;': '<',\n '&#x3E;': '>',\n '&#x26;': '&',\n '&#34;': '\"',\n '&#60;': '<',\n '&#62;': '>',\n '&#38;': '&'\n};\n\nconst MAX_DECODE_ITERATIONS = 5;\n\nexport function normalize(value, options = {}) {\n if (typeof value !== 'string') {\n return value;\n }\n\n const opts = {\n urlDecode: true,\n htmlDecode: true,\n sqlComments: true,\n nullBytes: true,\n whitespace: true,\n ...options\n };\n\n let result = value;\n\n if (opts.nullBytes) {\n result = removeNullBytes(result);\n }\n\n if (opts.urlDecode) {\n result = urlDecode(result);\n }\n\n if (opts.htmlDecode) {\n result = htmlEntityDecode(result);\n }\n\n if (opts.sqlComments) {\n result = removeSqlComments(result);\n }\n\n if (opts.whitespace) {\n result = normalizeWhitespace(result);\n }\n\n return result;\n}\n\nexport function urlDecode(value) {\n if (typeof value !== 'string') {\n return value;\n }\n\n let result = value;\n let previous = '';\n let iterations = 0;\n\n while (result !== previous && iterations < MAX_DECODE_ITERATIONS) {\n previous = result;\n iterations++;\n\n try {\n result = decodeURIComponent(result);\n } catch {\n result = safeUrlDecode(result);\n break;\n }\n }\n\n return result;\n}\n\nfunction safeUrlDecode(value) {\n return value.replace(/%([0-9A-Fa-f]{2})/g, (match, hex) => {\n try {\n return String.fromCharCode(parseInt(hex, 16));\n } catch {\n return match;\n }\n });\n}\n\nexport function htmlEntityDecode(value) {\n if (typeof value !== 'string') {\n return value;\n }\n\n let result = value;\n\n for (const [entity, char] of Object.entries(HTML_ENTITIES)) {\n result = result.split(entity).join(char);\n }\n\n result = result.replace(/&#(\\d+);/g, (match, code) => {\n const num = parseInt(code, 10);\n return num > 0 && num < 65536 ? String.fromCharCode(num) : match;\n });\n\n result = result.replace(/&#x([0-9A-Fa-f]+);/g, (match, hex) => {\n const num = parseInt(hex, 16);\n return num > 0 && num < 65536 ? String.fromCharCode(num) : match;\n });\n\n return result;\n}\n\nexport function removeSqlComments(value) {\n if (typeof value !== 'string') {\n return value;\n }\n\n // Collapse inline block comments to a space (the anti-obfuscation goal). We must NOT strip the\n // line-comment forms (`--\u2026`, `#\u2026`) to end-of-line: on the WAF inspection path that DELETES\n // attacker-controlled spans from the value the engine sees while the app still processes the\n // original \u2014 e.g. `#<script>\u2026` becomes empty and evades an XSS rule, though the browser still\n // runs it. Keeping the content only ever ADDS matches (more of the value is inspected), never\n // hides one. SQLi keyword detection is unaffected \u2014 the keywords remain visible.\n let result = value;\n\n result = result.replace(/\\/\\*[\\s\\S]*?\\*\\//g, ' ');\n result = result.replace(/\\/\\*![\\s\\S]*?\\*\\//g, ' ');\n\n return result;\n}\n\nexport function removeNullBytes(value) {\n if (typeof value !== 'string') {\n return value;\n }\n\n let result = value.replace(/\\x00/g, '');\n\n result = result.replace(/[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F]/g, '');\n\n return result;\n}\n\nexport function normalizeWhitespace(value) {\n if (typeof value !== 'string') {\n return value;\n }\n\n let result = value.replace(/[\\t\\r\\n\\f\\v]+/g, ' ');\n\n result = result.replace(/ {2,}/g, ' ');\n\n return result;\n}\n\nfunction serializeForRawDetection(body, visited = new Set(), isRoot = true) {\n if (body === null || body === undefined) {\n return isRoot ? '' : 'null';\n }\n\n if (typeof body === 'string') {\n return isRoot ? body : JSON.stringify(body);\n }\n\n if (typeof body !== 'object') {\n return String(body);\n }\n\n if (visited.has(body)) {\n return '[Circular]';\n }\n visited.add(body);\n\n if (Array.isArray(body)) {\n const items = body.map(item => serializeForRawDetection(item, visited, false));\n return '[' + items.join(',') + ']';\n }\n\n // Object.getOwnPropertyNames includes non-enumerable own properties, so a __proto__ key\n // set via Object.defineProperty (as modern JSON.parse may do) is included in the output.\n const keys = Object.getOwnPropertyNames(body);\n const parts = keys.map(key => {\n const val = serializeForRawDetection(body[key], visited, false);\n return JSON.stringify(key) + ':' + val;\n });\n\n return '{' + parts.join(',') + '}';\n}\n\nexport function normalizeRequest(req, options = {}) {\n // Prefer a caller-provided verbatim body string (set by the fetch/node adapters):\n // it preserves literal keys like `__proto__` that JSON.stringify drops, which is\n // what makes prototype-pollution rules on `raw` robust. Fall back to a\n // reconstruction from the parsed body (the Express path, which has no raw text).\n const rawBody = typeof req._rawBody === 'string'\n ? req._rawBody\n : serializeForRawDetection(req.body ?? null);\n\n return {\n query: normalizeObject(req.query || {}, options),\n body: normalizeObject(req.body || {}, options),\n headers: normalizeObject(req.headers || {}, options),\n url: normalize(req.url || '', options),\n originalUrl: normalize(req.originalUrl || req.url || '', options),\n _rawBody: rawBody\n };\n}\n\n// Depth bound for the recursive walk: a pathologically deep object would otherwise overflow the\n// stack, and the engine's per-rule catch would swallow that into a fail-open. Beyond the bound the\n// sub-value is left un-normalized (still matched, just in its raw form) rather than crashing.\nconst MAX_NORMALIZE_DEPTH = 200;\n\nexport function normalizeObject(value, options = {}, depth = 0) {\n if (typeof value === 'string') {\n return normalize(value, options);\n }\n\n if (depth >= MAX_NORMALIZE_DEPTH) {\n return value;\n }\n\n if (Array.isArray(value)) {\n return value.map(item => normalizeObject(item, options, depth + 1));\n }\n\n if (typeof value === 'object' && value !== null) {\n const result = {};\n\n for (const [key, val] of Object.entries(value)) {\n result[key] = normalizeObject(val, options, depth + 1);\n }\n\n return result;\n }\n\n return value;\n}\n\nexport function createMatchVariants(value) {\n if (typeof value !== 'string') {\n return [value];\n }\n\n const variants = new Set();\n\n variants.add(value);\n\n const urlDecoded = urlDecode(value);\n variants.add(urlDecoded);\n\n const htmlDecoded = htmlEntityDecode(value);\n variants.add(htmlDecoded);\n\n const bothDecoded = htmlEntityDecode(urlDecoded);\n variants.add(bothDecoded);\n\n const normalized = normalize(value);\n variants.add(normalized);\n\n variants.add(value.toLowerCase());\n variants.add(normalized.toLowerCase());\n\n return Array.from(variants);\n}\n\nexport const _testExports = {\n safeUrlDecode,\n serializeForRawDetection,\n HTML_ENTITIES,\n MAX_DECODE_ITERATIONS\n};\n", "import { RequestResolver } from './request.js';\nimport { normalizeRequest } from './normalizer.js';\n\n// Catastrophic-backtracking shapes. Broad on purpose: a group whose inner content is quantified\n// (+, *, or {n,}) and is itself quantified \u2014 (a+)+, (\\w+)+, (.*)*, ([a-z]+)*, (ab+)+ \u2014 or an\n// alternation under an outer quantifier \u2014 (a|a)*, (x|y)+. A rule matching one of these is skipped\n// (safer than hanging the event loop). The `NEST` variants allow ONE level of nested parentheses in\n// the outer group so a quantified SUBGROUP is caught too (`((ab)+)+`, `((a|b)+)*`) \u2014 the earlier\n// `[^)]*` forms stopped at the first inner `)` and missed those. `.test()` scans every start offset,\n// so deeper nestings match at an inner window too.\nconst GRP = '(?:[^()]|\\\\([^()]*\\\\))*'; // group body allowing one level of nested parens\nconst REDOS_PATTERNS = [\n /\\([^)]*[+*}][^)]*\\)\\s*[+*]/,\n /\\([^)]*\\|[^)]*\\)\\s*[+*]/,\n new RegExp('\\\\(' + GRP + '[+*}]' + GRP + '\\\\)\\\\s*[+*]'), // nested quantified subgroup\n new RegExp('\\\\(' + GRP + '\\\\|' + GRP + '\\\\)\\\\s*[+*]') // nested alternation under a quantifier\n];\n\n// Report once when a rule's regex is rejected (ReDoS-shaped or unparseable). Unlike an unknown match\n// type, a rejected regex used to fail silently \u2014 so a delivered rule protected nothing and nobody knew.\nconst warnedRejectedPatterns = new Set();\nfunction warnRejectedPatternOnce(pattern) {\n const key = String(pattern);\n if (warnedRejectedPatterns.has(key)) return;\n warnedRejectedPatterns.add(key);\n console.warn(\n `[patchstack] rule_v2 regex pattern rejected (unsafe or invalid) \u2014 condition treated as no-match. ` +\n `The rule relying on it is NOT enforced: ${key}`\n );\n}\n\n// An absurdly long pattern is either a mistake or an attack on our own matcher; compiling and running\n// it on every request is unbounded work. The rule-bundle validator rejects these upstream \u2014 this is the\n// backstop for a caller-supplied bundle that never went through it.\nconst MAX_PATTERN_LENGTH = 1000;\n\nexport function safeRegExp(pattern) {\n if (!pattern) {\n return null;\n }\n if (typeof pattern !== 'string' || pattern.length > MAX_PATTERN_LENGTH) {\n return null;\n }\n\n for (const dangerous of REDOS_PATTERNS) {\n if (dangerous.test(pattern)) {\n return null;\n }\n }\n\n const match = pattern.match(/^\\/(.+?)\\/([gimsuy]*)$/s);\n if (!match) {\n return null;\n }\n\n try {\n return new RegExp(match[1], match[2]);\n } catch {\n return null;\n }\n}\n\n// ctype_*/is_numeric compare their character-class result to the rule's expected\n// `value`. Rules are almost always written `{ \"type\": \"ctype_digit\", \"value\": false }`\n// meaning \"flag when NOT of this class\" \u2014 so the result must be compared to matchVal,\n// not returned raw. Empty/absent values never match (mirrors engine-php's `$value != ''`\n// guard), otherwise every missing parameter false-positives a `value:false` rule.\n// When `value` is not a boolean (null/omitted) the legacy default of `true` is used, so\n// existing rules that relied on the raw class check are unaffected.\nfunction ctypeResult(strValue, isClass, matchVal) {\n if (strValue === '') {\n return false;\n }\n const expected = typeof matchVal === 'boolean' ? matchVal : true;\n return isClass === expected;\n}\n\n// Walk a dot-path into a decoded object and invoke `cb({ parent, key, value })` for every leaf it\n// reaches, fanning out over arrays at EVERY segment (not just the last) \u2014 so `orders.customers.email`\n// visits the email of each customer of each order, for arbitrary-length / arbitrarily-nested arrays.\n// `cb` gets the container + key so callers can either read (match) or set (redact) the leaf.\nexport function walkLeaves(node, segments, cb) {\n if (node === null || typeof node !== 'object') return;\n if (Array.isArray(node)) {\n for (const el of node) walkLeaves(el, segments, cb);\n return;\n }\n const [head, ...rest] = segments;\n if (head === undefined || !Object.prototype.hasOwnProperty.call(node, head)) return;\n if (rest.length === 0) {\n const leaf = node[head];\n if (Array.isArray(leaf)) {\n for (let i = 0; i < leaf.length; i++) cb({ parent: leaf, key: i, value: leaf[i] });\n } else {\n cb({ parent: node, key: head, value: leaf });\n }\n } else {\n walkLeaves(node[head], rest, cb);\n }\n}\n\n// array_key_value: navigate `match.key` (a dot-path, or an array of paths) inside the decoded value\n// and run the nested `match.match` against every leaf it finds (fanning out over arrays at every\n// segment). Mirrors engine-php's recursive array_key_value handling.\nfunction arrayKeyValue(value, matchObj) {\n if (!matchObj || !matchObj.match || value === null || typeof value !== 'object') {\n return false;\n }\n const keys = Array.isArray(matchObj.key) ? matchObj.key : [matchObj.key];\n const sub = matchObj.match;\n\n for (const key of keys) {\n let matched = false;\n walkLeaves(value, String(key).split('.'), ({ value: leaf }) => {\n if (!matched && matchValue(sub.type, leaf, sub.value, sub)) matched = true;\n });\n if (matched) return true;\n }\n return false;\n}\n\n// Match types that operate on the whole container (not per-leaf): `isset` (presence) and\n// `array_in_array` / `array_key_value` (structural). Everything else is a scalar matcher that must\n// fan out over the leaves of an object/array value.\nconst WHOLE_VALUE_MATCH_TYPES = new Set(['isset', 'array_in_array', 'array_key_value']);\n\n// Iteratively collect every scalar (non-object) leaf of a structured value. Iterative + bounded\n// (depth and node caps) so a pathologically deep/large attacker payload STOPS at the bound rather\n// than throwing a RangeError that the per-rule catch would swallow into a fail-open bypass.\nfunction collectLeafValues(root, nodeCap = 20000, maxDepth = 1000) {\n const out = [];\n const stack = [[root, 0]];\n let visited = 0;\n while (stack.length) {\n const [node, depth] = stack.pop();\n if (node === null || node === undefined) continue;\n if (typeof node !== 'object') {\n out.push(node);\n continue;\n }\n if (depth >= maxDepth || visited >= nodeCap) continue;\n visited++;\n if (Array.isArray(node)) {\n for (let i = node.length - 1; i >= 0; i--) stack.push([node[i], depth + 1]);\n } else {\n for (const k of Object.keys(node)) stack.push([node[k], depth + 1]);\n }\n }\n return out;\n}\n\n// Emit a warning at most once per distinct key (keeps a persistent misconfiguration from spamming).\nconst warnedKeys = new Set();\nfunction warnOnce(key, message) {\n if (warnedKeys.has(key)) return;\n warnedKeys.add(key);\n console.warn(message);\n}\n\n// Report an unknown/removed match type once, so a rule referencing it is not silently\n// unenforced (ADR: \"unknown match type \u2192 skipped and logged, never silently passed\").\nconst warnedMatchTypes = new Set();\nfunction warnUnsupportedMatchType(type) {\n if (type == null || warnedMatchTypes.has(type)) {\n return;\n }\n warnedMatchTypes.add(type);\n console.warn(\n `[patchstack] Unsupported rule_v2 match type \"${type}\" \u2014 condition treated as no-match. ` +\n `Rules relying on it are not enforced by this engine.`\n );\n}\n\n// Internal / private / loopback / link-local / cloud-metadata host check, used by the\n// `internal_host` match type for SSRF egress rules. It CANONICALIZES the host before classifying \u2014\n// a textual/prefix check is bypassable by alternate encodings (decimal/hex/octal IPv4, expanded or\n// IPv4-mapped IPv6), which is a classic SSRF evasion. Handles localhost / *.local / GCP metadata\n// names, every IPv4 spelling inet_aton accepts, and IPv6 loopback/link-local/unique-local/mapped.\nfunction isInternalHost(hostname) {\n if (!hostname) return false;\n let host = String(hostname).toLowerCase().replace(/^\\[|\\]$/g, '');\n host = host.replace(/%[^\\]]*$/, ''); // strip an IPv6 zone id (fe80::1%eth0)\n host = host.replace(/\\.$/, ''); // strip a single trailing dot (127.0.0.1.)\n\n if (host === 'localhost' || host.endsWith('.localhost') || host.endsWith('.local')) return true;\n if (host === 'metadata.google.internal') return true;\n\n // IPv6 (contains a colon): expand to 8 groups, then classify on the canonical form.\n if (host.includes(':')) {\n const g = expandIPv6(host);\n if (!g) return false;\n const allZeroHi = g[0] === 0 && g[1] === 0 && g[2] === 0 && g[3] === 0 && g[4] === 0;\n if (allZeroHi && g[5] === 0 && g[6] === 0 && (g[7] === 0 || g[7] === 1)) return true; // ::, ::1 loopback\n if ((g[0] & 0xffc0) === 0xfe80) return true; // link-local fe80::/10\n if ((g[0] & 0xfe00) === 0xfc00) return true; // unique-local fc00::/7\n if (allZeroHi && (g[5] === 0xffff || g[5] === 0)) {\n // IPv4-mapped (::ffff:a.b.c.d) / IPv4-compatible (::a.b.c.d) \u2014 classify the embedded v4.\n return isPrivateV4Int((((g[6] << 16) >>> 0) | g[7]) >>> 0);\n }\n return false;\n }\n\n // IPv4 in any inet_aton spelling (dotted quad, shorthand, decimal, hex, octal).\n const v4 = parseIPv4ToInt(host);\n if (v4 !== null) return isPrivateV4Int(v4);\n return false;\n}\n\n// Private / loopback / link-local / this-host / CGNAT test on a 32-bit IPv4 integer.\nfunction isPrivateV4Int(n) {\n const a = (n >>> 24) & 0xff;\n const b = (n >>> 16) & 0xff;\n if (a === 127 || a === 10 || a === 0) return true; // loopback / private / this-host\n if (a === 169 && b === 254) return true; // link-local incl. 169.254.169.254 metadata\n if (a === 172 && b >= 16 && b <= 31) return true; // 172.16.0.0/12\n if (a === 192 && b === 168) return true; // 192.168.0.0/16\n if (a === 100 && b >= 64 && b <= 127) return true; // 100.64.0.0/10 CGNAT (Alibaba metadata 100.100.100.200)\n return false;\n}\n\n// inet_aton-style parse: 1\u20134 dot-separated parts, each decimal / 0x-hex / 0-octal; the final part\n// fills the remaining low bytes. Returns a uint32, or null if the host isn't a numeric IPv4 form\n// (so ordinary hostnames \u2014 which contain letters outside [0-9a-fx] or other chars \u2014 return null).\nfunction parseIPv4ToInt(host) {\n if (!/^[0-9a-fx]+(\\.[0-9a-fx]+)*$/i.test(host)) return null;\n const parts = host.split('.');\n if (parts.length > 4) return null;\n const nums = [];\n for (const p of parts) {\n let n;\n if (/^0x[0-9a-f]+$/i.test(p)) n = parseInt(p, 16);\n else if (/^0[0-7]+$/.test(p)) n = parseInt(p, 8);\n else if (/^[0-9]+$/.test(p)) n = parseInt(p, 10);\n else return null; // e.g. a bare hex like \"7f\" (not inet_aton-valid without 0x)\n if (!Number.isInteger(n) || n < 0) return null;\n nums.push(n);\n }\n const last = nums.length - 1;\n let value = 0;\n for (let i = 0; i < last; i++) {\n if (nums[i] > 0xff) return null;\n value += nums[i] * 2 ** (8 * (3 - i));\n }\n const maxLast = 2 ** (8 * (5 - nums.length)) - 1; // the final part fills the remaining low bytes\n if (nums[last] > maxLast) return null;\n value += nums[last];\n if (value < 0 || value > 0xffffffff) return null;\n return value >>> 0;\n}\n\n// Expand an IPv6 string (any `::` compression, optional embedded IPv4 tail) to 8 numeric groups,\n// or null if it isn't valid IPv6. Lets the classifier compare the canonical form, not a string prefix.\nfunction expandIPv6(host) {\n if (!host.includes(':')) return null;\n let s = host;\n // Embedded IPv4 tail (::ffff:127.0.0.1) \u2192 convert the dotted part to two hex groups.\n const lastColon = s.lastIndexOf(':');\n const tail = s.slice(lastColon + 1);\n if (tail.includes('.')) {\n const v4 = parseIPv4ToInt(tail);\n if (v4 === null) return null;\n s = s.slice(0, lastColon + 1) + ((v4 >>> 16) & 0xffff).toString(16) + ':' + (v4 & 0xffff).toString(16);\n }\n const halves = s.split('::');\n if (halves.length > 2) return null;\n const head = halves[0] ? halves[0].split(':') : [];\n const back = halves.length === 2 ? (halves[1] ? halves[1].split(':') : []) : null;\n let groups;\n if (back === null) {\n groups = head;\n } else {\n const fill = 8 - head.length - back.length;\n if (fill < 0) return null;\n groups = [...head, ...Array(fill).fill('0'), ...back];\n }\n if (groups.length !== 8) return null;\n const out = [];\n for (const g of groups) {\n if (!/^[0-9a-f]{1,4}$/i.test(g)) return null;\n out.push(parseInt(g, 16));\n }\n return out;\n}\n\n// Route/method scope for a rule's optional `when: { method, path }`. Fail-open: if the scope can't\n// be evaluated, the rule still applies (never silently suppress a rule).\nfunction ruleAppliesTo(when, resolver) {\n try {\n if (when.method) {\n const methods = (Array.isArray(when.method) ? when.method : [when.method]).map((m) => String(m).toUpperCase());\n const actual = String(resolver.resolve('server.REQUEST_METHOD')[0] ?? 'GET').toUpperCase();\n if (!methods.includes(actual)) return false;\n }\n if (when.path) {\n const uri = String(resolver.resolve('server.REQUEST_URI')[0] ?? '/');\n if (!pathMatches(String(when.path), uri.split('?')[0])) return false;\n }\n return true;\n } catch {\n return true;\n }\n}\n\n// `when.path`: an exact path, a glob with `*`, or an explicit `/regex/` (starts & ends with `/`).\nfunction pathMatches(pattern, path) {\n if (pattern.length > 2 && pattern.startsWith('/') && pattern.endsWith('/')) {\n const re = safeRegExp(pattern);\n return re ? re.test(path) : false;\n }\n if (pattern.includes('*')) {\n const re = safeRegExp('/^' + pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '[^?]*') + '$/');\n return re ? re.test(path) : false;\n }\n return path === pattern;\n}\n\n// Drop a default port so `app.com:443` and `app.com` compare equal (a real proxy shape), without\n// dropping a non-default port (so genuine cross-port stays distinguishable).\nfunction normalizeDefaultPort(host) {\n return String(host).toLowerCase().replace(/:(?:80|443)$/, '');\n}\n\n// CSRF primitive: does the request come from a different origin than its own Host? Lenient only when\n// the Origin AND Referer are TRULY ABSENT (a non-browser client). A present-but-opaque `Origin: null`\n// / empty / unparseable value is NOT same-origin \u2014 it's the sandboxed-iframe / opaque-origin signal a\n// CSRF attacker supplies, so it is treated as cross-origin.\nfunction isCrossOrigin(resolver) {\n try {\n const host = normalizeDefaultPort(String(resolver.resolve('server.HTTP_HOST')[0] ?? ''));\n if (!host) return false;\n const originRaw = resolver.resolve('server.HTTP_ORIGIN')[0];\n const hasOrigin = originRaw !== undefined && originRaw !== null;\n const src = hasOrigin ? originRaw : resolver.resolve('server.HTTP_REFERER')[0];\n if (src === undefined || src === null) return false; // both absent \u2192 lenient\n const s = String(src).trim();\n if (hasOrigin && (s === '' || s.toLowerCase() === 'null')) return true; // present but opaque \u2192 cross-origin\n const srcHost = hostFromUrl(s);\n if (srcHost === null) return hasOrigin; // present-but-unparseable Origin \u2192 treat as cross-origin\n return normalizeDefaultPort(srcHost) !== host;\n } catch {\n return false;\n }\n}\n\nfunction hostFromUrl(value) {\n try {\n return new URL(value).host.toLowerCase();\n } catch {\n return null;\n }\n}\n\n// Open-redirect primitive (response phase): a 3xx whose Location header points to a DIFFERENT origin\n// than the request's own Host. A relative Location (same-origin) never matches. Needs the request\n// Host, which the response phase threads in via reqCtx. Lenient: no Location, no request Host, or a\n// same-origin / relative target \u2192 not flagged (so it can't false-positive without the signal).\nfunction isOffOriginRedirect(resolver) {\n try {\n const status = Number(resolver.resolve('response.status')[0] ?? 0);\n if (status < 300 || status >= 400) return false;\n const location = resolver.resolve('response.header.location')[0];\n if (!location) return false;\n const host = String(resolver.resolve('server.HTTP_HOST')[0] ?? '').toLowerCase();\n if (!host) return false;\n // Resolve the Location the way a browser would before comparing hosts: strip TAB/CR/LF and\n // normalize backslashes to forward slashes (browsers do), then resolve against the request origin\n // as a base. A relative `/path` resolves to our own host (not flagged); a protocol-relative\n // `//evil.com` or backslash `/\\evil.com` resolves off-origin (flagged) \u2014 the canonical\n // open-redirect payloads that a base-less `new URL()` used to treat as \"relative & safe\".\n const loc = String(location).replace(/[\\t\\r\\n]/g, '').replace(/\\\\/g, '/');\n let target;\n try {\n target = new URL(loc, 'http://' + host).host.toLowerCase();\n } catch {\n return false; // unresolvable even with a base \u2192 not a redirect we can judge\n }\n return normalizeDefaultPort(target) !== normalizeDefaultPort(host);\n } catch {\n return false;\n }\n}\n\n// CORS-reflection primitive (response phase): the response allows credentials AND lets any origin\n// read it \u2014 either `Access-Control-Allow-Origin: *`, or it reflects the caller's own Origin (so\n// every origin is allowed) \u2014 rather than a fixed allowlisted origin. That combination lets any\n// malicious site read the authenticated response. Needs the request Origin (threaded via reqCtx).\n// Lenient: credentials not allowed, no ACAO, or a fixed (non-reflected, non-*) ACAO \u2192 not flagged.\nfunction isReflectedCorsWithCredentials(resolver) {\n try {\n const acac = String(resolver.resolve('response.header.access-control-allow-credentials')[0] ?? '').toLowerCase();\n if (acac !== 'true') return false; // only dangerous when credentials are allowed\n const acao = String(resolver.resolve('response.header.access-control-allow-origin')[0] ?? '');\n if (!acao) return false;\n if (acao === '*') return true; // wildcard + credentials\n if (acao.toLowerCase() === 'null') return true; // `null` + credentials is readable from a sandboxed iframe (Origin: null)\n const origin = String(resolver.resolve('server.HTTP_ORIGIN')[0] ?? '');\n if (!origin) return false;\n return acao === origin; // ACAO echoes the caller's Origin \u2192 any origin is allowed\n } catch {\n return false;\n }\n}\n\n// `matchObj` is the full match object; needed by types that read sibling fields\n// (array_key_value reads `key`/`match`). Optional so direct callers/tests can keep\n// using the (type, value, matchVal) signature.\nexport function matchValue(type, value, matchVal, matchObj) {\n if (value === null || value === undefined) {\n if (type === 'isset') {\n return false;\n }\n return false;\n }\n\n // Guard the coercion: String() on a pathologically deep array/object can throw RangeError\n // (stack overflow). Catching it here keeps a hostile nested value from failing the rule open.\n let strValue;\n if (typeof value === 'string') {\n strValue = value;\n } else {\n try {\n strValue = String(value);\n } catch {\n strValue = '';\n }\n }\n\n switch (type) {\n case 'equals':\n return strValue == matchVal;\n\n case 'equals_strict':\n // Type-strict by design (`'1' !== 1`). A rule that wants loose matching should use `equals`.\n return strValue === matchVal;\n\n case 'contains':\n // engine-php exposes `stripos` as an alias of `contains`.\n case 'stripos': {\n const lower = strValue.toLowerCase();\n const target = String(matchVal).toLowerCase();\n return lower.includes(target);\n }\n\n case 'not_contains': {\n const lower = strValue.toLowerCase();\n const target = String(matchVal).toLowerCase();\n return !lower.includes(target);\n }\n\n case 'regex': {\n const regex = safeRegExp(matchVal);\n if (!regex) {\n warnRejectedPatternOnce(matchVal);\n return false;\n }\n return regex.test(strValue);\n }\n\n case 'more_than':\n return Number(strValue) > Number(matchVal);\n\n case 'less_than':\n return Number(strValue) < Number(matchVal);\n\n case 'ctype_digit':\n return ctypeResult(strValue, /^\\d+$/.test(strValue), matchVal);\n\n case 'ctype_alnum':\n return ctypeResult(strValue, /^[\\w$\\u0080-\\uFFFF]+$/.test(strValue), matchVal);\n\n case 'is_numeric':\n return ctypeResult(strValue, !isNaN(strValue) && strValue.trim() !== '', matchVal);\n\n case 'isset':\n return true;\n\n case 'in_array': {\n const arr = (Array.isArray(matchVal) ? matchVal : [matchVal]).map((x) => String(x));\n return arr.includes(strValue);\n }\n\n case 'not_in_array': {\n const arr = (Array.isArray(matchVal) ? matchVal : [matchVal]).map((x) => String(x));\n return !arr.includes(strValue);\n }\n\n case 'array_in_array': {\n if (!Array.isArray(value) || !Array.isArray(matchVal)) {\n return false;\n }\n const target = matchVal.map((x) => String(x));\n return value.some((v) => target.includes(String(v)));\n }\n\n case 'hostname': {\n try {\n const url = new URL(strValue);\n return url.hostname === matchVal;\n } catch {\n return false;\n }\n }\n\n case 'internal_host':\n // SSRF egress: private / loopback / link-local / cloud-metadata destinations.\n return isInternalHost(strValue);\n\n case 'quotes':\n // engine-php exposes `inline_js_xss` as an alias of `quotes`.\n case 'inline_js_xss':\n return /['\"]/.test(strValue);\n\n case 'inline_xss':\n // Attribute-breakout heuristic: a quote AND a `>` or `=` (matches engine-php).\n return /['\"]/.test(strValue) && /[>=]/.test(strValue);\n\n case 'ctype_special': {\n // engine-php strips space, `_`, `-`, `,` then applies the alnum/unicode check,\n // and compares the result to `value` (usually false = \"flag when NOT clean\").\n const stripped = strValue.replace(/[ _\\-,]/g, '');\n return ctypeResult(strValue, /^[\\w$\u0080-\uFFFF]*$/.test(stripped), matchVal);\n }\n\n case 'array_key_value':\n // Navigate `match.key` (dot-path, or array of paths) inside the decoded value and\n // run the nested `match.match` against it \u2014 e.g. a json_decode'd body where a\n // specific key must hold a specific value.\n return arrayKeyValue(value, matchObj);\n\n // file_contains (uploaded-file content scanning) is NOT WordPress-specific, but is\n // not yet implemented in the JS engine (needs multipart body access). Kept as an\n // explicit, documented no-match rather than silently hitting `default`.\n case 'file_contains':\n return false;\n\n // WordPress-only match types (current_user_cannot, general_xss, getShortcodeAtts,\n // getBlockAtts) have been removed: they depend on WP capabilities, wp_kses_post, and\n // the shortcode/block parsers, and have no meaning in a JS app. They now fall through\n // here and are reported once instead of pretending to be a no-match.\n default:\n warnUnsupportedMatchType(type);\n return false;\n }\n}\n\nexport class RuleEngine {\n #rules;\n #whitelists;\n #whitelistKeys;\n #onError;\n #reportedErrors = new Set();\n\n constructor({ firewall = [], whitelists = [], whitelist_keys = {}, onError } = {}) {\n this.#rules = firewall;\n this.#whitelists = whitelists;\n this.#whitelistKeys = whitelist_keys;\n this.#onError = onError;\n // A whitelist with no `rule_id` suppresses EVERY rule when its (attacker-reachable) condition\n // trips \u2014 almost never intended. And `whitelist_keys` is accepted but not implemented. Warn once\n // for each so a misconfiguration that silently weakens the firewall is visible to the operator.\n if (Array.isArray(whitelists) && whitelists.some((w) => w && Array.isArray(w.rule_v2) && !w.rule_id)) {\n warnOnce(\n 'whitelist-no-rule-id',\n '[patchstack] a whitelist has no `rule_id` \u2014 it suppresses ALL rules when it matches. ' +\n 'Scope each whitelist to a specific rule_id, and key it only on values an attacker cannot set.'\n );\n }\n if (whitelist_keys && typeof whitelist_keys === 'object' && Object.keys(whitelist_keys).length > 0) {\n warnOnce('whitelist-keys-unimplemented', '[patchstack] `whitelist_keys` is not implemented and has no effect.');\n }\n }\n\n // A mitigation engine must never take down the app it protects: any error while\n // evaluating a rule is reported and the request is allowed through (fail open). A\n // malformed rule is skipped without aborting the rest of the ruleset.\n #reportError(err) {\n if (this.#onError) {\n this.#onError(err);\n return;\n }\n // Default: log once per distinct message so a persistently-broken rule doesn't\n // spam per request (never silently swallow \u2014 hosts can pass `onError` for structured logging).\n const key = err && err.message ? err.message : String(err);\n if (this.#reportedErrors.has(key)) {\n return;\n }\n this.#reportedErrors.add(key);\n console.error('[patchstack] rule evaluation error (rule skipped, request allowed):', err);\n }\n\n evaluate(req) {\n let normalizedReq;\n let resolver;\n try {\n normalizedReq = { ...req, ...normalizeRequest(req) };\n resolver = new RequestResolver(normalizedReq);\n } catch (err) {\n this.#reportError(err);\n return { blocked: false, rule: null, message: null }; // fail open\n }\n\n for (const rule of this.#rules) {\n try {\n // Route/method scope: a rule may declare `when: { method, path }` to apply only on matching\n // requests (so an auto-generated per-endpoint rule doesn't fire elsewhere).\n if (rule.when && !ruleAppliesTo(rule.when, resolver)) {\n continue;\n }\n\n const conditions = rule.rule_v2;\n\n if (!Array.isArray(conditions) || conditions.length === 0) {\n continue;\n }\n\n if (this.#evaluateRule(conditions, resolver)) {\n if (this.#isWhitelisted(normalizedReq, rule)) {\n continue;\n }\n\n return {\n blocked: true,\n rule,\n message: rule.message ?? `Blocked by Patchstack WAF rule: ${rule.title ?? rule.id}`\n };\n }\n } catch (err) {\n // Skip this rule and keep evaluating the rest \u2014 one bad rule never blocks a\n // request nor shadows the rules after it.\n this.#reportError(err);\n }\n }\n\n return { blocked: false, rule: null, message: null };\n }\n\n #evaluateRule(conditions, resolver) {\n const inclusiveConditions = conditions.filter(c => c.inclusive);\n const nonInclusiveConditions = conditions.filter(c => !c.inclusive);\n\n if (inclusiveConditions.length > 0) {\n let inclusiveHits = 0;\n\n for (const condition of inclusiveConditions) {\n if (this.#evaluateCondition(condition, resolver)) {\n inclusiveHits++;\n }\n }\n\n if (inclusiveHits === inclusiveConditions.length) {\n return true;\n }\n }\n\n for (const condition of nonInclusiveConditions) {\n if (this.#evaluateCondition(condition, resolver)) {\n return true;\n }\n }\n\n return false;\n }\n\n #evaluateCondition(condition, resolver) {\n const { parameter, match, mutations } = condition;\n\n if (parameter === 'rules' && Array.isArray(condition.rules)) {\n return this.#evaluateRule(condition.rules, resolver);\n }\n\n // `cross_origin` needs the request as a whole (Origin/Referer vs Host), not a single resolved\n // parameter \u2014 it's the CSRF primitive: true (\u2192 block) when the request comes from another origin.\n if (match && match.type === 'cross_origin') {\n return isCrossOrigin(resolver);\n }\n\n // `off_origin` (response phase): true (\u2192 block) when a 3xx redirects to a different origin than\n // the request Host \u2014 the open-redirect primitive. Like cross_origin, it needs the whole resolver.\n if (match && match.type === 'off_origin') {\n return isOffOriginRedirect(resolver);\n }\n\n // `cors_reflected` (response phase): true (\u2192 block) when the response allows credentials and\n // reflects the caller's Origin (or uses `*`) \u2014 the CORS-misconfiguration primitive. Needs the\n // whole resolver (request Origin vs response ACAO/ACAC).\n if (match && match.type === 'cors_reflected') {\n return isReflectedCorsWithCredentials(resolver);\n }\n\n // `parameter` may be an array (e.g. [\"get.action\",\"post.action\"]) \u2014 the rule_v2 format\n // uses these pervasively to mean \"any of these sources\". Resolve each and OR the\n // candidate values together. (A bare string resolves as a single source.)\n const params = Array.isArray(parameter) ? parameter : [parameter];\n const values = params.flatMap((p) => resolver.resolve(p));\n\n if (values.length === 0) {\n return false;\n }\n\n for (let value of values) {\n if (mutations) {\n value = resolver.applyMutations(mutations, value);\n }\n\n // array_key_value inspects the object as a whole (it navigates a key path),\n // so it must not go through the per-value object iteration below.\n if (match.type === 'array_key_value') {\n if (matchValue(match.type, value, match.value, match)) {\n return true;\n }\n continue;\n }\n\n // A structured (object / array-of-object) value must be inspected at every leaf: a payload\n // nested deeper than a scalar rule expects would otherwise stringify to \"[object Object]\" and\n // evade the match, while the app still reads the live value. Whole-value match types\n // (isset / array_in_array) see the container; scalar matchers fan out over all leaves.\n if (typeof value === 'object' && value !== null) {\n if (WHOLE_VALUE_MATCH_TYPES.has(match.type)) {\n if (matchValue(match.type, value, match.value, match)) return true;\n } else {\n for (const leaf of collectLeafValues(value)) {\n if (matchValue(match.type, leaf, match.value, match)) return true;\n }\n }\n continue;\n }\n\n if (matchValue(match.type, value, match.value, match)) {\n return true;\n }\n }\n\n return false;\n }\n\n #isWhitelisted(req, rule) {\n if (!this.#whitelists || this.#whitelists.length === 0) {\n return false;\n }\n\n for (const whitelist of this.#whitelists) {\n if (!Array.isArray(whitelist.rule_v2)) {\n continue;\n }\n\n if (whitelist.rule_id && whitelist.rule_id !== rule.id) {\n continue;\n }\n\n const resolver = new RequestResolver(req);\n if (this.#evaluateRule(whitelist.rule_v2, resolver)) {\n return true;\n }\n }\n\n return false;\n }\n}\n\nexport const _testExports = { matchValue, safeRegExp, isInternalHost };\n", "import type { Config } from './types.js';\n\n/**\n * Bearer tokens for the authenticated Pulse endpoints (ADR-0018).\n *\n * Deliberately separate from the block-log token flow in\n * `src/protect/firewall-log.js`: that path talks to the auth/ Lambda's\n * /oauth/token and must keep working exactly as it does today.\n */\n\nconst TOKEN_SKEW_MS = 60_000;\n\n/** Build the Pulse token URL corresponding to a manifest endpoint override. */\nexport function buildTokenUrl(manifestEndpoint: string): string {\n const url = new URL(manifestEndpoint);\n const path = url.pathname.replace(/\\/$/, '');\n url.pathname = path.endsWith('/manifest')\n ? `${path.slice(0, -'/manifest'.length)}/token`\n : '/monitor/pulse/token';\n url.search = '';\n url.hash = '';\n return url.toString();\n}\n\n/** Split the WP-format `{secret}-{oauth.id}` credential on its last hyphen. */\nexport function parsePulseAuth(credential: string): { clientId: string; clientSecret: string } | null {\n const index = credential.lastIndexOf('-');\n if (index <= 0 || index === credential.length - 1) return null;\n\n const clientId = credential.slice(index + 1);\n if (!/^\\d+$/.test(clientId)) return null;\n\n return { clientId, clientSecret: credential.slice(0, index) };\n}\n\nlet cached: { token: string; expiresAt: number } | null = null;\nlet inflight: Promise<string | null> | null = null;\n\n/** Drops the cached token. Exported for tests and for 401 handling. */\nexport function clearPulseToken(): void {\n cached = null;\n}\n\n/**\n * Resolve a bearer token for `config.pulseAuth`, exchanging one if needed.\n *\n * Returns null whenever a token cannot be obtained \u2014 no credential, a rejected\n * exchange, a network failure. Callers then send the request unauthenticated,\n * which the server still accepts while it runs dual-accept.\n */\nexport async function getPulseToken(\n config: Config,\n fetchImpl: typeof fetch = fetch,\n): Promise<string | null> {\n // Not `=== null`: Config is public, so callers can hand us an object that\n // predates this field, and an unusable credential must never throw here.\n if (typeof config.pulseAuth !== 'string' || config.pulseAuth.length === 0) return null;\n\n if (cached !== null && Date.now() < cached.expiresAt - TOKEN_SKEW_MS) {\n return cached.token;\n }\n if (inflight !== null) return inflight;\n\n const credentials = parsePulseAuth(config.pulseAuth);\n if (credentials === null) return null;\n\n inflight = (async () => {\n try {\n const response = await fetchImpl(buildTokenUrl(config.endpoint), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'User-Agent': '@patchstack/connect',\n },\n body: JSON.stringify({\n grant_type: 'client_credentials',\n client_id: credentials.clientId,\n client_secret: credentials.clientSecret,\n }),\n signal: AbortSignal.timeout(config.timeoutMs),\n });\n\n if (!response.ok) return null;\n\n const body = (await response.json()) as { access_token?: unknown; expires_in?: unknown };\n if (typeof body.access_token !== 'string' || body.access_token.length === 0) return null;\n\n const expiresIn = Number(body.expires_in);\n const ttlMs = Number.isFinite(expiresIn) && expiresIn > 0 ? expiresIn * 1000 : 3600_000;\n cached = { token: body.access_token, expiresAt: Date.now() + ttlMs };\n\n return body.access_token;\n } catch {\n return null;\n } finally {\n inflight = null;\n }\n })();\n\n return inflight;\n}\n\n/**\n * `Authorization` header for a Pulse request, or `{}` when unauthenticated.\n * Spread into an existing header object so call sites stay one line.\n */\nexport async function pulseAuthHeader(\n config: Config,\n fetchImpl: typeof fetch = fetch,\n): Promise<Record<string, string>> {\n const token = await getPulseToken(config, fetchImpl);\n return token === null ? {} : { Authorization: `Bearer ${token}` };\n}\n\n/**\n * Send a Pulse request, attaching the bearer token and retrying once if the\n * server rejects it.\n *\n * A cached token can stop being valid before it expires \u2014 the credential may\n * have been rotated or revoked meanwhile \u2014 so the server's 401 is authoritative\n * over our own clock. Without this a long-running process would keep presenting\n * a dead token until its local expiry.\n *\n * Only 401 retries: a 403 is a scope or site mismatch, which a fresh token\n * would not fix.\n */\nexport async function pulseFetch(\n config: Config,\n url: string,\n init: RequestInit,\n fetchImpl: typeof fetch = fetch,\n): Promise<Response> {\n const send = async () => {\n const auth = await pulseAuthHeader(config, fetchImpl);\n const response = await fetchImpl(url, {\n ...init,\n headers: { ...(init.headers as Record<string, string> | undefined), ...auth },\n });\n\n return { response, authenticated: auth.Authorization !== undefined };\n };\n\n const first = await send();\n\n // Retrying an unauthenticated request would just repeat it: the 401 was\n // about something other than our token.\n if (first.response.status === 401 && first.authenticated) {\n clearPulseToken();\n\n return (await send()).response;\n }\n\n return first.response;\n}\n", "import { safeBaseUrl } from '../safe-origin.js';\nimport { pulseAuthHeader } from '../../pulse-token.js';\n\nconst DEFAULT_BASE_URL = 'https://api.patchstack.com/monitor/pulse';\nconst DEFAULT_CACHE_TTL = 300_000;\n// Randomly shorten the effective TTL by up to this fraction so many long-lived clients don't all\n// revalidate on the same tick (spreads load / avoids a thundering herd against the rules API).\nconst JITTER_FRACTION = 0.1;\n\n// Per-site rules client for Pulse (npm/JS) apps. Public endpoint \u2014 the site UUID is the only\n// credential, passed in the path. Fail-open: any error returns success:false + empty rules so\n// createProtection falls back to the disk cache or the bundled rules.\n//\n// Conditional fetch: pass a prior `etag` (persisted with the last cached bundle) and the client\n// sends `If-None-Match`; a 304 returns `{ notModified: true }` so the caller reuses its cache\n// without re-downloading, and a 200 returns the new bundle plus its `etag` to persist. This is a\n// no-op until the rules API emits an ETag and honors If-None-Match \u2014 with no ETag in the response\n// the client simply behaves as before (a full fetch every refresh).\nexport class PulseRuleClient {\n #siteUuid;\n #timeoutMs;\n #baseUrl;\n #cacheTtl;\n #cache = null;\n #cacheTime = null;\n #ttlEffective = 0;\n #etag;\n #pulseAuth;\n\n constructor({ siteUuid, baseUrl, cacheTtl, etag, timeoutMs, pulseAuth } = {}) {\n // Bounded so app STARTUP can't hang on a slow API: hosted platforms fail a deploy whose health\n // check is slow, and we always have a cache/bundled fallback to boot from.\n this.#timeoutMs = Number(timeoutMs) > 0 ? Number(timeoutMs) : 30_000;\n this.#siteUuid = siteUuid ?? process.env.PATCHSTACK_SITE_UUID;\n // Rules are executed policy \u2014 refuse a plaintext remote override (see safe-origin.js).\n this.#baseUrl = safeBaseUrl(baseUrl ?? process.env.PATCHSTACK_PULSE_RULES_URL, DEFAULT_BASE_URL, 'rule endpoint');\n this.#cacheTtl = Number.isFinite(cacheTtl) && cacheTtl > 0 ? cacheTtl : DEFAULT_CACHE_TTL;\n this.#etag = etag ?? null;\n this.#pulseAuth = pulseAuth ?? null;\n if (!this.#siteUuid) {\n throw new Error('Patchstack site UUID is required. Pass { siteUuid } or set PATCHSTACK_SITE_UUID.');\n }\n }\n\n async getRules() {\n const now = Date.now();\n if (this.#cache && this.#cacheTime !== null && now - this.#cacheTime < this.#ttlEffective) {\n return this.#cache;\n }\n const url = `${this.#baseUrl}/rules/${encodeURIComponent(this.#siteUuid)}`;\n try {\n // Unauthenticated when no credential resolved, or when the exchange\n // fails \u2014 the server still accepts the UUID, and protection must never\n // hinge on getting a token.\n const headers = {\n Accept: 'application/json',\n ...(await pulseAuthHeader(\n { pulseAuth: this.#pulseAuth, endpoint: this.#baseUrl, timeoutMs: this.#timeoutMs },\n fetch,\n )),\n };\n if (this.#etag) headers['If-None-Match'] = this.#etag;\n const response = await fetch(url, { method: 'GET', headers, signal: AbortSignal.timeout(this.#timeoutMs) });\n\n if (response.status === 304) {\n this.#touch(now); // revalidated \u2014 reset the clock (fresh jitter)\n return this.#cache ?? { success: true, notModified: true, etag: this.#etag, firewall: [], whitelists: [], whitelist_keys: {} };\n }\n if (!response.ok) {\n return { success: false, error: `API returned ${response.status}`, firewall: [], whitelists: [], whitelist_keys: {} };\n }\n const data = await response.json();\n // A 200 that isn't a genuine rule envelope (schema drift, a proxy/interstitial page, an\n // {error} body) must not be treated as \"no rules\". Report failure so the caller falls back to\n // the cache / bundled rules rather than caching an empty bundle.\n if (!data || !Array.isArray(data.firewall)) {\n return { success: false, error: 'unexpected response shape (no firewall array)', firewall: [], whitelists: [], whitelist_keys: {} };\n }\n const result = {\n success: true,\n notModified: false,\n etag: response.headers?.get?.('etag') ?? null,\n firewall: data.firewall,\n whitelists: Array.isArray(data.whitelists) ? data.whitelists : [],\n whitelist_keys: data.whitelist_keys ?? {},\n ...enforcementField(data),\n };\n this.#cache = result;\n this.#etag = result.etag;\n this.#touch(now);\n return result;\n } catch (err) {\n return {\n success: false,\n error: err.name === 'TimeoutError' ? 'Request timed out' : err.message,\n firewall: [], whitelists: [], whitelist_keys: {},\n };\n }\n }\n\n #touch(now) {\n this.#cacheTime = now;\n this.#ttlEffective = this.#cacheTtl - Math.floor(Math.random() * this.#cacheTtl * JITTER_FRACTION);\n }\n\n clearCache() {\n this.#cache = null;\n this.#cacheTime = null;\n this.#etag = null;\n }\n}\n\n/** @param {unknown} data @returns {{ enforcement?: 'block'|'dry-run' }} */\nfunction enforcementField(data) {\n if (!data || typeof data !== 'object') return {};\n const v = data.enforcement ?? data.mode;\n return v === 'block' || v === 'dry-run' ? { enforcement: v } : {};\n}\n", "// Web Fetch adapter \u2014 runs the node-waf engine on any runtime where a request is a\n// WHATWG `Request` and a handler returns a `Response`: Cloudflare Workers, Bun, Deno,\n// Hono, Next.js edge, and TanStack Start's `server.ts`. This is the surface AI-builder\n// apps actually deploy to, and where require-based instrumentation can't reach.\n//\n// The engine already consumes a runtime-neutral request shape; this adapter builds that\n// shape from a `Request`, so no engine changes are needed beyond keeping the hot path\n// free of Node-only APIs.\nimport { RuleEngine } from './engine.js';\n\n// Cap how much request body we buffer for inspection. A larger body is left UNSCANNED\n// (fail-open) rather than buffered into memory \u2014 matches the node adapter's maxBodyBytes.\nconst MAX_BODY_BYTES = 1024 * 1024;\n\n// Build the engine's request shape from a WHATWG Request. The body is read from a\n// CLONE so the downstream handler still receives an intact request.\nexport async function fromFetchRequest(request, options = {}) {\n const maxBodyBytes = options.maxBodyBytes ?? MAX_BODY_BYTES;\n const url = new URL(request.url);\n const method = (request.method || 'GET').toUpperCase();\n\n const headers = {};\n request.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value;\n });\n\n const query = {};\n for (const [key, value] of url.searchParams) {\n if (key in query) {\n query[key] = Array.isArray(query[key]) ? [...query[key], value] : [query[key], value];\n } else {\n query[key] = value;\n }\n }\n\n let rawBody = '';\n if (method !== 'GET' && method !== 'HEAD') {\n rawBody = await readCappedText(request, maxBodyBytes);\n }\n\n const contentType = headers['content-type'] || '';\n let body = {};\n let files;\n if (rawBody) {\n const parsed = parseBody(rawBody, contentType);\n body = parsed.body;\n files = parsed.files;\n }\n\n const uri = url.pathname + url.search;\n const forwarded =\n headers['cf-connecting-ip'] || headers['x-forwarded-for'] || headers['x-real-ip'] || '';\n\n return {\n method,\n url: uri,\n originalUrl: uri,\n query,\n body,\n files,\n headers,\n ip: forwarded.split(',')[0].trim(),\n cookies: parseCookies(headers.cookie),\n // Verbatim body text: preserves literal keys (e.g. `__proto__`) that JSON.stringify\n // drops, so prototype-pollution rules on `raw` are robust.\n _rawBody: rawBody\n };\n}\n\n// Read a request body as text for inspection. Memory is bounded by a hard ceiling (4\u00D7 the scan\n// cap): a body whose declared Content-Length exceeds it is left UNSCANNED (fail-open). Within the\n// ceiling, an oversize body is TRUNCATED to `max` and its prefix is still scanned \u2014 so a\n// front-loaded payload is caught \u2014 rather than being discarded outright. Reads a clone so the\n// downstream handler keeps an intact body. (`max` is compared in bytes against Content-Length; the\n// prefix slice is by character, which can only over-scan a multibyte body \u2014 the safe direction.)\nasync function readCappedText(request, max) {\n // Do NOT skip scanning based on a declared Content-Length: an attacker can declare a huge length\n // (or none) to dodge inspection while sending a small exploit body. Always stream-scan the prefix\n // up to `max` (buffering is bounded to `max`; the rest is drained but not retained). Anything past\n // the cap is unscanned \u2014 the documented prefix-scan tradeoff \u2014 but the body is never skipped whole.\n let clone;\n try {\n clone = request.clone();\n } catch {\n return '';\n }\n\n // Stream the read so a body WITHOUT a Content-Length can't buffer unbounded: retain only up to the\n // scan cap (`max`) for inspection, but keep draining to completion so the original request stays\n // intact. A front-loaded payload is still caught; anything past the cap is not scanned (same\n // partial-scan tradeoff as before, now with a hard memory bound regardless of Content-Length).\n const body = clone.body;\n if (body && typeof body.getReader === 'function') {\n const reader = body.getReader();\n const chunks = [];\n let buffered = 0;\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!value || buffered >= max) continue; // keep draining, stop buffering past the cap\n const take = Math.min(value.byteLength, max - buffered);\n chunks.push(take === value.byteLength ? value : value.subarray(0, take));\n buffered += take;\n }\n } catch {\n return '';\n }\n try {\n return new TextDecoder().decode(concatChunks(chunks, buffered));\n } catch {\n return '';\n }\n }\n\n // No readable stream \u2014 fall back to text() with the post-read guard.\n try {\n const text = await clone.text();\n return text.length > max ? text.slice(0, max) : text;\n } catch {\n return '';\n }\n}\n\nfunction concatChunks(chunks, total) {\n const out = new Uint8Array(total);\n let offset = 0;\n for (const c of chunks) {\n out.set(c, offset);\n offset += c.byteLength;\n }\n return out;\n}\n\n// Minimal multipart/form-data parser: enough to expose field names + values (so `post.<field>`\n// and `raw` rules match uploads, e.g. a `__proto__` field name) and file metadata (filename via\n// `files.<field>`). We only need the textual structure, not the binary file contents.\n// Parse a request body into { body, files } for parameter-scoped rules. Content-type detection is\n// deliberately permissive: many AI-built apps `JSON.parse(await req.text())` regardless of the\n// declared type, so a JSON body arriving as `application/vnd.api+json`, `application/ld+json`,\n// `text/plain`, `application/csp-report`, or with NO content-type must still populate post.<field>\n// (otherwise a field-scoped rule silently resolves to nothing). Unrecognized/binary bodies stay `{}`\n// and are still matchable via `raw`.\nexport function parseBody(rawBody, contentType) {\n const ct = String(contentType || '').toLowerCase();\n const isJson = ct.includes('application/json') || /\\+json\\b/.test(ct);\n const isForm = ct.includes('application/x-www-form-urlencoded');\n const isMultipart = ct.includes('multipart/form-data');\n // \"ambiguous\" = a type an app commonly parses as JSON/form even though it isn't declared as such.\n const isAmbiguous = ct === '' || ct.startsWith('text/plain') || ct.includes('csp-report') || ct.includes('/json');\n\n if (isMultipart) {\n const boundary = /boundary=(\"?)([^\";]+)\\1/i.exec(contentType)?.[2];\n if (boundary) return parseMultipart(rawBody, boundary);\n return { body: {}, files: undefined };\n }\n if (isForm) {\n const body = {};\n for (const [k, v] of new URLSearchParams(rawBody)) body[k] = k in body ? [].concat(body[k], v) : v;\n return { body, files: undefined };\n }\n if (isJson || isAmbiguous) {\n try {\n const parsed = JSON.parse(rawBody);\n if (parsed && typeof parsed === 'object') return { body: parsed, files: undefined };\n } catch {\n /* not JSON \u2014 leave body empty; `raw`/`all` still see the verbatim text */\n }\n }\n return { body: {}, files: undefined };\n}\n\nexport function parseMultipart(rawBody, boundary) {\n const body = {};\n const files = {};\n for (const part of rawBody.split('--' + boundary)) {\n // Tolerate both CRLF and LF-only line endings (some clients/proxies send bare \\n).\n const sep = /\\r?\\n\\r?\\n/.exec(part);\n if (!sep) continue;\n const rawHeaders = part.slice(0, sep.index);\n const disposition = /content-disposition:[^\\r\\n]*/i.exec(rawHeaders)?.[0];\n if (!disposition) continue;\n const name = /name=\"([^\"]*)\"/i.exec(disposition)?.[1];\n if (name == null) continue;\n const content = part.slice(sep.index + sep[0].length).replace(/\\r?\\n$/, '');\n const filename = /filename=\"([^\"]*)\"/i.exec(disposition)?.[1];\n if (filename !== undefined) {\n // Capture the part's declared content-type and CONTENT (not just the filename), so rules can\n // inspect an upload's bytes (files.<name>.content) and detect a declared-vs-actual type\n // mismatch (files.<name>.mismatch). The content rides inside the already-capped rawBody.\n const partType = /content-type:\\s*([^\\r\\n;]+)/i.exec(rawHeaders)?.[1]?.trim() || '';\n const file = { filename, type: partType, content };\n files[name] = name in files ? [].concat(files[name], file) : file;\n } else {\n body[name] = name in body ? [].concat(body[name], content) : content;\n }\n }\n return { body, files };\n}\n\nfunction parseCookies(header) {\n const cookies = {};\n if (!header) {\n return cookies;\n }\n for (const pair of header.split(';')) {\n const idx = pair.indexOf('=');\n if (idx === -1) {\n continue;\n }\n cookies[pair.slice(0, idx).trim()] = pair.slice(idx + 1).trim();\n }\n return cookies;\n}\n\nfunction defaultBlockResponse(result) {\n return new Response(\n JSON.stringify({\n error: 'Blocked by Patchstack WAF',\n message: result.message,\n timestamp: new Date().toISOString()\n }),\n { status: 403, headers: { 'content-type': 'application/json' } }\n );\n}\n\n/**\n * Returns a guard `(request) => Promise<Response|null>`. A `Response` means blocked;\n * `null` means allowed \u2014 the caller should proceed to its handler. Accepts either a\n * rules bundle (`{ firewall, whitelists, whitelist_keys }`) or a `RuleEngine` instance.\n * Fails open: a rule that throws never blocks the request.\n */\nexport function createFetchMiddleware(rulesData, options = {}) {\n const engine =\n rulesData && typeof rulesData.evaluate === 'function'\n ? rulesData\n : new RuleEngine(rulesData);\n\n const guard = async (request) => {\n let req;\n let result;\n try {\n req = await fromFetchRequest(request); // shaping inside the try \u2014 a bad/relative request.url must fail open\n result = engine.evaluate(req);\n } catch (err) {\n if (options.onError) {\n options.onError(err);\n }\n return null; // fail open\n }\n\n if (result.blocked) {\n if (options.onBlock) {\n options.onBlock({\n rule: result.rule,\n message: result.message,\n request: { method: req.method, url: req.url, ip: req.ip }\n });\n }\n return (options.response || defaultBlockResponse)(result);\n }\n\n return null;\n };\n\n guard.engine = engine;\n return guard;\n}\n\n/**\n * Wrap a fetch handler so every request is screened first. One-line hook:\n * export default { fetch: wrapFetchHandler(app.fetch, rulesData) }\n */\nexport function wrapFetchHandler(handler, rulesData, options = {}) {\n const guard = createFetchMiddleware(rulesData, options);\n const wrapped = async (request, ...rest) => {\n const blocked = await guard(request);\n return blocked ?? handler(request, ...rest);\n };\n wrapped.engine = guard.engine;\n return wrapped;\n}\n", "// Raw Node.js / Connect adapter \u2014 for traditional Node servers where the request is a\n// `http.IncomingMessage` and the body is NOT already parsed (plain `http`, Connect,\n// Express without a body-parser, Fastify via its Node req). It buffers the body once,\n// builds the engine's request shape, and blocks or calls `next()`.\n//\n// This complements the Express `createMiddleware` (which assumes `req.body`/`req.query`\n// are already populated) and the Web-Fetch adapter (Workers/edge). Mount it FIRST, before\n// any body-parser \u2014 it consumes the stream and exposes the parsed body as `req.body`.\nimport { RuleEngine } from './engine.js';\nimport { parseBody } from './fetch.js';\n\n// Build the engine's request shape from a Node IncomingMessage + its raw body text.\nexport function fromNodeRequest(req, rawBody = '') {\n const method = (req.method || 'GET').toUpperCase();\n\n const headers = {};\n for (const [key, value] of Object.entries(req.headers || {})) {\n headers[key.toLowerCase()] = Array.isArray(value) ? value.join(', ') : value;\n }\n\n // An unusual Host header or req.url can make `new URL` throw; shaping must never crash the\n // request (fail-open), so fall back to a safe base.\n const host = headers.host || 'localhost';\n let url;\n try {\n url = new URL(req.url || '/', `http://${host}`);\n } catch {\n try {\n url = new URL(req.url || '/', 'http://localhost');\n } catch {\n url = new URL('http://localhost/');\n }\n }\n\n const query = {};\n for (const [key, value] of url.searchParams) {\n if (key in query) {\n query[key] = Array.isArray(query[key]) ? [...query[key], value] : [query[key], value];\n } else {\n query[key] = value;\n }\n }\n\n const contentType = headers['content-type'] || '';\n let body = {};\n let files;\n if (rawBody) {\n // Same permissive content-type handling as the fetch adapter (+json / text/plain / no-CT bodies\n // still populate post.<field>; multipart exposes field + file metadata) on a raw-Node server too.\n const parsed = parseBody(rawBody, contentType);\n body = parsed.body;\n files = parsed.files;\n }\n\n const uri = url.pathname + url.search;\n const forwarded =\n headers['cf-connecting-ip'] || headers['x-forwarded-for'] || headers['x-real-ip'] || '';\n\n return {\n method,\n url: uri,\n originalUrl: uri,\n query,\n body,\n files,\n headers,\n ip: forwarded.split(',')[0].trim() || (req.socket && req.socket.remoteAddress) || '',\n cookies: parseCookies(headers.cookie),\n // Verbatim body text: preserves literal keys (e.g. `__proto__`) that JSON.stringify drops.\n _rawBody: rawBody\n };\n}\n\nfunction parseCookies(header) {\n const cookies = {};\n if (!header) {\n return cookies;\n }\n for (const pair of header.split(';')) {\n const idx = pair.indexOf('=');\n if (idx === -1) {\n continue;\n }\n cookies[pair.slice(0, idx).trim()] = pair.slice(idx + 1).trim();\n }\n return cookies;\n}\n\nfunction defaultBlock(res, result) {\n res.statusCode = 403;\n res.setHeader('content-type', 'application/json');\n res.end(\n JSON.stringify({\n error: 'Blocked by Patchstack WAF',\n message: result.message,\n timestamp: new Date().toISOString()\n })\n );\n}\n\n/**\n * Connect/Express-style middleware `(req, res, next)` that buffers the body itself.\n * Accepts a `RuleEngine` instance or a `{ firewall, whitelists, whitelist_keys }` bundle.\n * Fails open: an engine error (or oversized body) never blocks the request.\n * Options: `{ maxBodyBytes = 1MiB, onBlock, onError, response }`.\n */\nexport function createNodeMiddleware(rulesData, options = {}) {\n const engine =\n rulesData && typeof rulesData.evaluate === 'function' ? rulesData : new RuleEngine(rulesData);\n const maxBytes = options.maxBodyBytes ?? 1024 * 1024;\n\n return function guard(req, res, next) {\n const chunks = [];\n let size = 0;\n let overflow = false;\n\n req.on('data', (chunk) => {\n size += chunk.length;\n if (size > maxBytes) {\n overflow = true;\n return;\n }\n chunks.push(chunk);\n });\n\n req.on('error', (err) => next(err));\n\n req.on('end', () => {\n let result;\n let shaped;\n try {\n const rawBody = overflow ? '' : Buffer.concat(chunks).toString('utf8');\n shaped = fromNodeRequest(req, rawBody); // shaping is inside the try too \u2014 never crash\n result = engine.evaluate(shaped);\n } catch (err) {\n if (options.onError) {\n options.onError(err);\n }\n return next(); // fail open\n }\n\n if (result.blocked) {\n if (options.onBlock) {\n options.onBlock({\n rule: result.rule,\n message: result.message,\n request: { method: shaped.method, url: shaped.url, ip: shaped.ip }\n });\n }\n return (options.response || defaultBlock)(res, result);\n }\n\n // Expose the parsed body downstream so a body-parser isn't also required.\n req.body = shaped.body;\n next();\n });\n };\n}\n", "// Egress guard MECHANISM only. Wraps the app's outbound calls so they can be screened; the\n// block DECISION is delegated to a caller-supplied `shouldBlock` predicate (which the runtime\n// builds from egress-phase rules \u2014 see defaults.js). No policy is hardcoded here.\n// WinterCG-first: always wraps the global `fetch` (Node 18+, Workers, Bun, Deno). On Node it\n// ALSO patches `node:http`/`node:https` so outbound calls made via those modules (axios, got,\n// the raw http client, \u2026) \u2014 which never touch `fetch` \u2014 are screened too.\n\n/**\n * @param {{ shouldBlock: (url:string, host:string|null, method:string)=>boolean,\n * onBlock?: (info:{url:string,host:string|null,method:string})=>void,\n * dnsScreen?: boolean,\n * lookup?: Function }} opts\n * @returns {Promise<() => void>} uninstall (restores every patched surface)\n */\nexport async function installEgressGuard({ shouldBlock, onBlock, onSkip, dnsScreen = true, lookup, allowHosts } = {}) {\n const restores = [];\n if (typeof shouldBlock !== 'function') return () => {};\n const exempt = new Set((allowHosts ?? []).map((h) => String(h).toLowerCase()));\n\n const block = (url, host, method) => {\n if (!shouldBlock(url, host, method)) return false;\n onBlock?.({ url, host, method });\n return true;\n };\n\n // DNS resolution, shared by the fetch wrapper and the node http path. Instead of trusting the\n // hostname, resolve it and check the resolved address(es). On the node path we also PIN the socket\n // to the vetted IP (no time-of-check/use gap); on fetch we can't pin without a custom undici\n // dispatcher, so we screen the resolution but a re-resolve at connect is a residual window.\n // Needs node:dns + node:net; absent on edge runtimes, where the hostname rules still apply.\n let screen = null;\n if (dnsScreen) {\n try {\n const resolveLookup = lookup ?? (await import('node:dns')).lookup;\n const { isIP } = await import('node:net');\n if (typeof resolveLookup === 'function' && typeof isIP === 'function') {\n screen = { lookup: resolveLookup, isIP, isExempt: (h) => exempt.has(String(h).toLowerCase()) };\n }\n } catch {\n screen = null; // no node:dns/net here \u2014 skip, hostname rules still apply\n }\n }\n\n // A resolver failure means the destination was NOT screened by IP \u2014 the hostname check alone let it\n // through. That's a real (if rare) coverage hole, so report it via onSkip instead of failing open\n // silently. Still fail-open: a broken resolver must not take the app's outbound traffic down.\n const skip = (reason, detail) => { try { onSkip?.({ phase: 'egress', reason, detail }); } catch { /* never affect traffic */ } };\n\n // True when a hostname resolves to a disallowed address. Fail-open: any resolver error \u2192 false.\n const resolvesToDisallowed = (url, host, method) =>\n new Promise((resolve) => {\n if (!screen) {\n // No node:dns/net here (edge runtime) or screening disabled \u2014 hostname rules only.\n if (host && dnsScreen) skip('resolver-unavailable', { host });\n return resolve(false);\n }\n if (!host || screen.isIP(host) !== 0 || screen.isExempt(host)) return resolve(false);\n try {\n screen.lookup(host, { all: true }, (err, addresses) => {\n if (err || !Array.isArray(addresses)) { skip('resolver-failed', { host }); return resolve(false); }\n for (const a of addresses) {\n const ip = a && typeof a === 'object' ? a.address : a;\n if (ip && block(url, ip, method)) return resolve(true);\n }\n resolve(false);\n });\n } catch {\n skip('resolver-failed', { host });\n resolve(false);\n }\n });\n\n // 1. global fetch \u2014 synchronous install, so it's active the instant this returns (no startup race).\n const originalFetch = globalThis.fetch;\n if (typeof originalFetch === 'function' && !originalFetch.__patchstackGuarded) {\n const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);\n const MAX_REDIRECTS = 20;\n\n // Screen one outbound URL: hostname/allowlist/literal-IP check, then a DNS-resolution check for\n // real hostnames. Throws if the destination is disallowed.\n const screenUrl = async (u, method) => {\n let host = null;\n try {\n host = new URL(u).hostname;\n } catch {\n host = null;\n }\n if (block(u, host, method) || (await resolvesToDisallowed(u, host, method))) {\n throw new Error(`Patchstack blocked an outbound request to a disallowed address: ${host ?? u}`);\n }\n };\n\n const guarded = async (input, init) => {\n let cur;\n try {\n cur = new Request(input, { ...(init || {}), redirect: 'manual' });\n } catch {\n return originalFetch(input, init); // odd input we can't normalize \u2014 fail open, don't break the caller\n }\n const callerRedirect = (init && init.redirect) || (input && input.redirect) || 'follow';\n\n let url = cur.url;\n let method = cur.method;\n await screenUrl(url, method);\n\n // Caller manages redirects itself (manual/error) \u2192 screen once, hand back the raw response.\n if (callerRedirect !== 'follow') return originalFetch(input, init);\n\n // Otherwise follow redirects ourselves so EVERY hop is screened. Native `follow` re-resolves\n // internally and would let a 3xx to an internal address slip past the initial check \u2014 SSRF via\n // an open redirect. Buffer the body once (a stream can't be re-read) so 307/308 can replay it.\n const headers = new Headers(cur.headers);\n const signal = cur.signal;\n let body = method === 'GET' || method === 'HEAD' ? undefined : await cur.clone().arrayBuffer();\n\n for (let hop = 0; ; hop++) {\n const resp = await originalFetch(\n hop === 0 ? cur : new Request(url, { method, headers, body, redirect: 'manual', signal }),\n );\n const location = REDIRECT_STATUSES.has(resp.status) ? resp.headers.get('location') : null;\n if (!location) return resp;\n if (hop >= MAX_REDIRECTS) throw new Error('Patchstack blocked an outbound request: too many redirects');\n\n const next = new URL(location, url).href;\n // Fetch redirect semantics: 303, and 301/302 on a POST, become a bodyless GET.\n if (resp.status === 303 || ((resp.status === 301 || resp.status === 302) && method === 'POST')) {\n method = 'GET';\n body = undefined;\n headers.delete('content-type');\n headers.delete('content-length');\n }\n // Drop credentials on a cross-origin hop, mirroring the browser.\n if (new URL(next).origin !== new URL(url).origin) {\n headers.delete('authorization');\n headers.delete('cookie');\n }\n await screenUrl(next, method);\n url = next;\n }\n };\n guarded.__patchstackGuarded = true;\n globalThis.fetch = guarded;\n restores.push(() => {\n if (globalThis.fetch === guarded) globalThis.fetch = originalFetch;\n });\n }\n\n // node:http / node:https \u2014 best-effort; absent on Workers/Deno-without-node (import throws).\n for (const moduleName of ['node:http', 'node:https']) {\n try {\n const mod = await import(moduleName);\n const restore = patchHttpModule(mod.default ?? mod, block, screen);\n if (restore) restores.push(restore);\n } catch {\n /* module not available on this runtime \u2014 skip */\n }\n }\n\n // WebSocket egress is intentionally NOT screened. The WebSocket constructor is synchronous, so\n // the only check possible inline is a textual hostname match \u2014 which can't offer the\n // DNS-resolution guarantee the fetch and node:http/https paths give (a name that resolves to an\n // internal address would pass). A connection-pinning dispatcher could close that, but the\n // server-side, attacker-controlled-WebSocket sink is rare, and a partial hostname-only check\n // over-promises the control. Outbound SSRF screening covers fetch + node:http/https.\n\n return () => {\n for (const restore of restores) {\n try {\n restore();\n } catch {\n /* ignore */\n }\n }\n };\n}\n\n// Wrap http(s).request/get so a blocked destination throws before the socket opens.\nfunction patchHttpModule(http, block, screen) {\n if (!http || typeof http.request !== 'function' || http.__patchstackGuarded) return null;\n const originalRequest = http.request;\n const originalGet = http.get;\n\n const wrap = (original) =>\n function (...args) {\n const target = extractHttpTarget(args);\n if (target && block(target.url, target.host, target.method)) {\n throw new Error(`Patchstack blocked an outbound request to a disallowed address: ${target.host ?? target.url}`);\n }\n // DNS screen: only for real hostnames (a literal IP was already covered by the check above),\n // and skip an explicitly allowlisted host (the operator trusts it \u2014 don't second-guess its DNS).\n if (target && screen && target.host && screen.isIP(target.host) === 0 && !screen.isExempt(target.host)) {\n try {\n args = withScreeningLookup(args, target, block, screen.lookup);\n } catch {\n /* injection failed \u2014 proceed unscreened (fail-open) */\n }\n }\n return original.apply(this, args);\n };\n\n const guardedRequest = wrap(originalRequest);\n http.request = guardedRequest;\n let guardedGet;\n if (typeof originalGet === 'function') {\n guardedGet = wrap(originalGet);\n http.get = guardedGet;\n }\n http.__patchstackGuarded = true;\n\n return () => {\n // Only restore if our wrapper is still installed \u2014 don't clobber a wrapper another library\n // (an APM agent, etc.) layered on top of us after install.\n if (http.request === guardedRequest) http.request = originalRequest;\n if (guardedGet && http.get === guardedGet) http.get = originalGet;\n delete http.__patchstackGuarded;\n };\n}\n\n// http.request accepts (url), (url, options), or (options) \u2014 with an optional trailing callback.\nfunction extractHttpTarget(args) {\n const first = args[0];\n try {\n if (typeof first === 'string' || first instanceof URL) {\n const url = new URL(String(first));\n const opts = args.find((a) => a && typeof a === 'object' && !(a instanceof URL));\n return { url: url.href, host: url.hostname, method: (opts && opts.method) || 'GET' };\n }\n if (first && typeof first === 'object') {\n // Node defaults an absent host to localhost \u2014 reflect that so the block/screen see a real target.\n const host = normalizeHost(first.hostname || first.host) || 'localhost';\n const protocol = first.protocol || 'http:';\n const port = first.port ? `:${first.port}` : '';\n const path = first.path || '/';\n return { url: `${protocol}//${host}${port}${path}`, host, method: first.method || 'GET' };\n }\n } catch {\n /* fall through */\n }\n return null;\n}\n\n// Extract the bare host from a node http(s) options `host`/`hostname`, WITHOUT mangling IPv6.\n// `[::1]:8080` \u2192 `::1`, bare `::1`/`fe80::1` \u2192 unchanged, `example.com:443` \u2192 `example.com`.\n// (isInternalHost strips brackets and matches ::1 / fe80: / fc / fd, so this must not corrupt them.)\nfunction normalizeHost(raw) {\n const host = String(raw || '').trim();\n const bracketed = /^\\[([^\\]]+)\\]/.exec(host);\n if (bracketed) return bracketed[1];\n if ((host.match(/:/g) || []).length > 1) return host; // bare IPv6 \u2014 no host:port to split\n return host.split(':')[0];\n}\n\n// Given the addresses a hostname resolved to, return the first one the policy blocks (else null).\n// Reuses the same `block` predicate as the hostname check, so egress rules + allowlist apply to\n// the resolved IP too. Exported for tests.\nexport function screenResolved(addresses, target, block) {\n for (const a of addresses || []) {\n const ip = a && typeof a === 'object' ? a.address : a;\n if (ip && block(target.url, ip, target.method)) return ip;\n }\n return null;\n}\n\n// Build a DNS `lookup` that screens every resolved address before the socket connects, then hands\n// back the vetted addresses (pinning the connection to what we checked). A blocked address errors\n// the connection; a resolver error or our own failure falls through to normal resolution (fail-open).\nfunction withScreeningLookup(args, target, block, lookup) {\n const screeningLookup = (hostname, options, callback) => {\n let opts = options;\n let cb = callback;\n if (typeof opts === 'function') {\n cb = opts;\n opts = {};\n }\n if (!opts || typeof opts !== 'object') opts = {};\n try {\n lookup(hostname, { ...opts, all: true }, (err, addresses) => {\n if (err) return cb(err);\n const list = Array.isArray(addresses) ? addresses : [];\n const blocked = screenResolved(list, target, block);\n if (blocked) {\n return cb(new Error(`Patchstack blocked an outbound request to a disallowed address: ${target.host} resolved to ${blocked}`));\n }\n if (opts.all) return cb(null, list);\n const first = list[0];\n if (!first) return cb(new Error(`Patchstack: could not resolve ${hostname}`));\n return cb(null, first.address, first.family);\n });\n } catch {\n // Our screening threw \u2014 fall back to a plain resolution so we never break a request ourselves.\n try {\n lookup(hostname, opts, cb);\n } catch {\n cb(new Error(`Patchstack: lookup failed for ${hostname}`));\n }\n }\n };\n return injectLookupOption(args, screeningLookup);\n}\n\n// Return a new args array for http(s).request with our `lookup` set on the options object (cloned,\n// never mutating the caller's object), inserting an options object when the call didn't pass one.\nfunction injectLookupOption(args, lookup) {\n const first = args[0];\n if (first && typeof first === 'object' && !(first instanceof URL)) {\n return [{ ...first, lookup }, ...args.slice(1)];\n }\n const rest = args.slice(1);\n const optIdx = rest.findIndex((a) => a && typeof a === 'object' && !(a instanceof URL));\n if (optIdx !== -1) {\n const next = [...rest];\n next[optIdx] = { ...rest[optIdx], lookup };\n return [first, ...next];\n }\n const cbIdx = rest.findIndex((a) => typeof a === 'function');\n if (cbIdx === -1) return [first, { lookup }, ...rest];\n return [first, ...rest.slice(0, cbIdx), { lookup }, ...rest.slice(cbIdx)];\n}\n", "// Default response- and egress-phase rule bundles, as JS constants (not JSON files) so\n// tsup bundles them into dist/protect.js without a copy step. These are just rules \u2014\n// override per app via createProtection({ responseRules, egressRules }) or extend by\n// adding phase-tagged rules to the delivered bundle. Patterns are high-precision\n// (low false positive): structural markers a real secret has and normal content doesn't.\n//\n// Each rule carries a `prefilter`: cheap literal anchor(s) that MUST appear in the body for the\n// regex to have any chance of matching. The response screener runs the (expensive) regex only when\n// an anchor is present (case-insensitive), so a body with no candidate \u2014 the common case \u2014 skips\n// the scan entirely. This cuts CPU/latency and shrinks the regex/ReDoS surface. (Honored by the\n// response phase once the prefilter mechanism lands; a no-op before that.)\n\n// Response phase \u2014 secret / info exposure. Default action `redact` masks only the\n// offending span and still serves the page (a legit response that leaks one key gets\n// that key masked, not withheld). Use `action: \"block\"` to withhold the whole response.\nexport const DEFAULT_RESPONSE_RULES = [\n {\n id: 'resp-private-key',\n title: 'Private key in response body',\n phase: 'response',\n category: 'secret-exposure',\n action: 'redact',\n prefilter: ['PRIVATE KEY'],\n rule_v2: [{ parameter: 'response.body', match: { type: 'regex', value: '/-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/' } }]\n },\n {\n id: 'resp-aws-access-key',\n title: 'AWS access key id in response body',\n phase: 'response',\n category: 'secret-exposure',\n action: 'redact',\n prefilter: ['AKIA', 'ASIA'],\n rule_v2: [{ parameter: 'response.body', match: { type: 'regex', value: '/\\\\b(?:AKIA|ASIA)[0-9A-Z]{16}\\\\b/' } }]\n },\n {\n id: 'resp-gcp-api-key',\n title: 'Google API key in response body',\n phase: 'response',\n category: 'secret-exposure',\n action: 'redact',\n prefilter: ['AIza'],\n rule_v2: [{ parameter: 'response.body', match: { type: 'regex', value: '/\\\\bAIza[0-9A-Za-z_-]{35}\\\\b/' } }]\n },\n {\n id: 'resp-vendor-api-key',\n title: 'Vendor API key / token in response body',\n phase: 'response',\n category: 'secret-exposure',\n action: 'redact',\n // High-signal, prefix-anchored provider tokens that never legitimately appear in a response\n // body: Stripe (sk_live_/rk_live_), GitHub (gh[opsu]_ / github_pat_), GitLab (glpat-),\n // Slack (xox[baprs]-), Anthropic (sk-ant-), Google OAuth (ya29.), npm (npm_). Trailing\n // (?![0-9A-Za-z]) instead of \\\\b since some tokens end in - / _ .\n prefilter: ['sk_live_', 'rk_live_', 'ghp_', 'gho_', 'ghs_', 'ghu_', 'github_pat_', 'glpat-', 'xox', 'sk-ant-', 'ya29.', 'npm_'],\n rule_v2: [{ parameter: 'response.body', match: { type: 'regex', value: '/\\\\b(?:sk_live_[0-9A-Za-z]{16,}|rk_live_[0-9A-Za-z]{16,}|gh[opsu]_[0-9A-Za-z]{36}|github_pat_[0-9A-Za-z_]{60,}|glpat-[0-9A-Za-z_-]{20,}|xox[baprs]-[0-9A-Za-z-]{10,}|sk-ant-[0-9A-Za-z_-]{20,}|ya29\\\\.[0-9A-Za-z_-]{20,}|npm_[0-9A-Za-z]{36})(?![0-9A-Za-z])/' } }]\n },\n {\n id: 'resp-jwt',\n title: 'JWT in response body',\n phase: 'response',\n category: 'secret-exposure',\n action: 'redact',\n prefilter: ['eyJ'],\n rule_v2: [{ parameter: 'response.body', match: { type: 'regex', value: '/\\\\beyJ[A-Za-z0-9_-]{8,}\\\\.eyJ[A-Za-z0-9_-]{8,}\\\\.[A-Za-z0-9_-]{8,}\\\\b/' } }]\n },\n {\n id: 'resp-db-connection-string',\n title: 'Database connection string with credentials in response body',\n phase: 'response',\n category: 'secret-exposure',\n action: 'redact',\n prefilter: ['mongodb', 'postgres', 'mysql', 'redis', 'amqp'],\n rule_v2: [{ parameter: 'response.body', match: { type: 'regex', value: '/\\\\b(?:mongodb(?:\\\\+srv)?|postgres(?:ql)?|mysql|redis|amqps?):\\\\/\\\\/[^\\\\s:@\\\\/]+:[^\\\\s:@\\\\/]+@/i' } }]\n },\n {\n id: 'resp-stack-trace',\n title: 'Node stack trace leaking in response body',\n phase: 'response',\n category: 'info-exposure',\n action: 'redact',\n // No prefilter: a Node stack frame has no single distinctive literal (` at ` is too common to\n // gate on). The pattern is linearly bounded per line, so it runs on every screened body.\n rule_v2: [{ parameter: 'response.body', match: { type: 'regex', value: '/\\\\n\\\\s+at\\\\s+.+\\\\(.+:\\\\d+:\\\\d+\\\\)/' } }]\n },\n {\n id: 'resp-sql-error',\n title: 'SQL / ORM error disclosure in response body',\n phase: 'response',\n category: 'info-exposure',\n action: 'redact',\n prefilter: ['SQLSTATE', 'Sequelize', 'ER_', 'ORA-', 'PG::', 'SQLITE_ERROR', 'SQL syntax'],\n rule_v2: [{ parameter: 'response.body', match: { type: 'regex', value: '/(SQLSTATE\\\\[[0-9A-Z]+\\\\]|SequelizeDatabaseError|ER_[A-Z_]+|ORA-\\\\d{5}|PG::[A-Za-z]+Error|SQLITE_ERROR|You have an error in your SQL syntax)/i' } }]\n },\n {\n id: 'resp-exception-trace',\n title: 'Backend exception / stack trace disclosure in response body',\n phase: 'response',\n category: 'info-exposure',\n action: 'redact',\n // Multi-language exception/traceback signatures a normal API response never carries:\n // Python traceback, Java \"Exception in thread\", .NET System.*Exception, JVM stack frames,\n // Go goroutine dumps. (Node `at fn (file:line:col)` frames are handled by resp-stack-trace.)\n prefilter: ['Traceback', 'Exception in thread', 'System.', 'goroutine ', '.java:', '.kt:', '.scala:', '.rb:', '.py:', '.cs:'],\n rule_v2: [{ parameter: 'response.body', match: { type: 'regex', value: '/(Traceback \\\\(most recent call last\\\\)|Exception in thread \"|System\\\\.[A-Za-z.]+Exception|\\\\bat [\\\\w.$]+\\\\([\\\\w]+\\\\.(?:java|kt|scala|rb|py|cs):\\\\d+\\\\)|goroutine \\\\d+ \\\\[)/' } }]\n }\n];\n\n// Egress phase \u2014 SSRF: block the app's outbound calls to internal / metadata addresses.\nexport const DEFAULT_EGRESS_RULES = [\n {\n id: 'egress-internal-address',\n title: 'Outbound request to an internal / metadata address (SSRF)',\n phase: 'egress',\n category: 'ssrf',\n rule_v2: [{ parameter: 'egress.host', match: { type: 'internal_host' } }]\n }\n];\n", "// Full-page \"Access Denied\" block view, ported from the Patchstack WordPress plugin's\n// sample.php. Served (instead of JSON) when a BLOCKED request is a top-level document navigation\n// rather than an XHR/fetch \u2014 so a user who browses into a blocked URL sees a branded page, while\n// programmatic clients still get JSON. Self-contained (inline CSS + base64 SVGs); exposes no WAF\n// narrative and no rule details.\n\nfunction escapeHtml(s) {\n return String(s).replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c]));\n}\n\n/** @param {{ url?: string, code?: string }} opts @returns {string} a complete HTML document */\nexport function renderBlockPage({ url = '', code = 'patchstack' } = {}) {\n const safeUrl = escapeHtml(url);\n const safeCode = escapeHtml(code || 'patchstack');\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <style type=\"text/css\">\n\t\t.access-denied,.site-url-text{letter-spacing:.01em;color:#fff}body{background:#111216}.main-container{display:flex;justify-content:center;flex-direction:column;align-items:center}.container{width:688px;height:456px;background:#1c1e22;border-radius:16px;margin-top:120px}.content{height:330px;margin:64px}.access-denied{font-family:Verdana;font-style:normal;font-weight:600;font-size:24px;line-height:32px;display:flex;align-items:center}.descp-text,.site-url{display:flex;align-items:center}.site-url{margin-top:32px;width:560px;height:64px;background:#26282c;border-radius:4px}.reason-code-text,.site-url-text{font-family:Verdana;font-style:normal;border:none;background:#26282c}.site-url-text{text-overflow: ellipsis;font-weight:400;font-size:16px;line-height:24px;margin-left:16px;width:85%}.copy-icon{width:19px;height:22px;margin-left:20px}.copy-icon:hover{cursor:pointer}.reason-code-text{font-weight:600;font-size:24px;line-height:32px;letter-spacing:.01em;color:#AFE614;margin-left:16px;width:85%}.descp-text,.return-text{font-size:16px;line-height:24px;letter-spacing:.01em;font-weight:400}.return-text:hover{color: #AFE614}.descp-text,.logoText,.return-text,.secured-text{font-family:Verdana;font-style:normal;color:#fff}.descp{margin-top:32px;width:560px}.bottom-second-containers,.bottom-text-containers{align-items:center;display:flex}.bottom-container{margin-top:40px;display:flex;width:688px}.bottom-second-containers{margin-left:auto}.arrow-vector{margin-left:20px}.return-text{text-align:center;margin-left:12.59px;text-decoration:none}.secured-text{font-weight:400;font-size:11.2px;line-height:16px;display:flex;align-items:center;letter-spacing:.02em;margin-right:8px}.logoText{font-weight:600;font-size:16px;line-height:24px;letter-spacing:.01em;flex:none;order:1;flex-grow:0}.patch-logo{width:120px}.mobile-bottom-container{margin-top:40px;width:372px;display:none}.mobile-bottom-second-containers{margin-top:64px;display:flex;margin-left:16.5px}@media only screen and (max-width:900px){.container{background:#111216;width:370px;height:auto;margin-top:0}.content{margin-left:16.5px}.descp,.site-url{width:340px}.site-url-text{font-weight:400;font-size:14.4px;line-height:20px;letter-spacing:.02em;width:80%}.copy-icon{margin-left:20px}.reason-code-text{font-size:16px;line-height:32px;letter-spacing:.02em;margin-left:16px;width:80%}.descp-text,.return-text{font-size:14.4px;line-height:20px}.descp-text{display:flex;align-items:center;letter-spacing:.02em}.bottom-container{display:none}.mobile-bottom-container{display:block}.return-text{text-align:center;letter-spacing:.01em;color:#fff;margin-left:9.73px}}\n </style>\n <title>Access Denied</title>\n</head>\n<body>\n <div class=\"main-container\">\n <div class=\"container\">\n <div class=\"content\">\n <span class=\"access-denied\">Access Denied</span>\n <div class=\"site-url\">\n <input id=\"url\" class=\"site-url-text\" type=\"text\"\n value=\"${safeUrl}\" readonly>\n <img class=\"copy-icon\" src=\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMjMiIHZpZXdCb3g9IjAgMCAxOSAyMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE0IDAuMDIzNDM3NUgwVjE2LjAyMzRIMlYyLjAyMzQ0SDE0VjAuMDIzNDM3NVpNMTkgNC4wMjM0NEg0VjIyLjAyMzRIMTlWNC4wMjM0NFpNMTcgMjAuMDIzNEg2VjYuMDIzNDRIMTdWMjAuMDIzNFoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=\" alt=\"Copy Text\" onmouseover=\"hover(this);\" onmouseout=\"unhover(this);\" onclick=\"copyText(id='url')\">\n </div>\n <div class=\"site-url\">\n <input id=\"response\" class=\"reason-code-text\" type=\"text\" value=\"${safeCode}\" readonly>\n <img class=\"copy-icon\" src=\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMjMiIHZpZXdCb3g9IjAgMCAxOSAyMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE0IDAuMDIzNDM3NUgwVjE2LjAyMzRIMlYyLjAyMzQ0SDE0VjAuMDIzNDM3NVpNMTkgNC4wMjM0NEg0VjIyLjAyMzRIMTlWNC4wMjM0NFpNMTcgMjAuMDIzNEg2VjYuMDIzNDRIMTdWMjAuMDIzNFoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=\" alt=\"Copy Text\" onmouseover=\"hover(this);\" onmouseout=\"unhover(this);\" onclick=\"copyText(id='response')\">\n </div>\n <div class=\"descp\">\n <span class=\"descp-text\">This request has been blocked by Patchstack. If this message persists and you are a legitimate user, contact the site administrator with the reference above.</span>\n </div>\n </div>\n </div>\n <div class=\"bottom-container\">\n <div class=\"bottom-text-containers\">\n <img class=\"arrow-vector\" src=\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOCIgaGVpZ2h0PSIxMyIgdmlld0JveD0iMCAwIDggMTMiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik03LjQxIDEuNDMzNDRMNiAwLjAyMzQzNzVMMCA2LjAyMzQ0TDYgMTIuMDIzNEw3LjQxIDEwLjYxMzRMMi44MyA2LjAyMzQ0TDcuNDEgMS40MzM0NFoiIGZpbGw9IiNBRkU2MTQiLz4KPC9zdmc+Cg==\" alt=\"Arrow Left\">\n <a href=\"/\" class=\"return-text\">Return to homepage</a>\n </div>\n <div class=\"bottom-second-containers\">\n <span class=\"secured-text\">This website is secured by</span>\n <a href=\"https://patchstack.com\" class=\"logoText\">\n <img class=\"patch-logo\" src=\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTg0IiBoZWlnaHQ9IjIyIiB2aWV3Qm94PSIwIDAgMTg0IDIyIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTUwLjQwMDEgMTEuNTAwOEM1MC40MDAxIDkuMTAwNzggNDkuMzAwMSA4LjEwMDc4IDQ2LjYwMDEgOC4xMDA3OEM0NC4wMDAxIDguMTAwNzggNDIuNzAwMSA5LjIwMDc4IDQyLjcwMDEgMTEuNTAwOEM0Mi43MDAxIDEzLjgwMDggNDQuMDAwMSAxNC45MDA4IDQ2LjYwMDEgMTQuOTAwOEM0OS4zMDAxIDE0LjkwMDggNTAuNDAwMSAxMy44MDA4IDUwLjQwMDEgMTEuNTAwOFpNNTMuNDAwMSAxMS41MDA4QzUzLjQwMDEgMTUuMzAwOCA1MS4zMDAxIDE3LjYwMDggNDcuNDAwMSAxNy42MDA4QzQ1LjQwMDEgMTcuNjAwOCA0My42MDAxIDE2LjUwMDggNDIuNzAwMSAxNC41MDA4VjIxLjUwMDhIMzkuNjAwMVY1LjYwMDc4SDQyLjcwMDFWOC41MDA3OEM0My42MDAxIDYuNTAwNzggNDUuNDAwMSA1LjMwMDc4IDQ3LjUwMDEgNS4zMDA3OEM1MS40MDAxIDUuMzAwNzggNTMuNDAwMSA3LjcwMDc4IDUzLjQwMDEgMTEuNTAwOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNjYuNDAwMSAxMS40OTg0QzY2LjQwMDEgOS4xOTg0NCA2NS4xMDAxIDguMDk4NDQgNjIuNTAwMSA4LjA5ODQ0QzU5LjgwMDEgOC4wOTg0NCA1OC43MDAxIDkuMDk4NDQgNTguNzAwMSAxMS40OTg0QzU4LjcwMDEgMTMuNzk4NCA1OS44MDAxIDE0Ljg5ODQgNjIuNTAwMSAxNC44OTg0QzY1LjEwMDEgMTQuODk4NCA2Ni40MDAxIDEzLjc5ODQgNjYuNDAwMSAxMS40OTg0Wk02Ni4zMDAxIDUuNTk4NDRINjkuNDAwMVYxNy4zOTg0SDY2LjMwMDFWMTQuNDk4NEM2NS40MDAxIDE2LjQ5ODQgNjMuNzAwMSAxNy42OTg0IDYxLjYwMDEgMTcuNjk4NEM1Ny43MDAxIDE3LjY5ODQgNTUuNjAwMSAxNS4yOTg0IDU1LjYwMDEgMTEuNTk4NEM1NS42MDAxIDcuNzk4NDQgNTcuNjAwMSA1LjM5ODQ0IDYxLjQwMDEgNS4zOTg0NEM2My41MDAxIDUuMzk4NDQgNjUuNDAwMSA2LjU5ODQ0IDY2LjIwMDEgOC41OTg0NFY1LjU5ODQ0SDY2LjMwMDFaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTgxLjM5OTkgOC4zSDc3LjM5OTlWMTQuN0g4MS4wOTk5VjE3LjRINzcuOTk5OUM3NS43OTk5IDE3LjQgNzQuMjk5OSAxNS45IDc0LjI5OTkgMTMuN1Y4LjNINzEuMzk5OVY1LjZINzQuMjk5OVYySDc3LjM5OTlWNS41SDgxLjM5OTlWOC4zWiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik05My42OTk5IDEyLjIwMDhMOTYuNjk5OSAxMi45MDA4Qzk1Ljk5OTkgMTYuMDAwOCA5My42OTk5IDE3LjYwMDggODkuOTk5OSAxNy42MDA4Qzg3Ljc5OTkgMTcuNjAwOCA4Ni4wOTk5IDE3LjAwMDggODQuNzk5OSAxNS45MDA4QzgzLjQ5OTkgMTQuODAwOCA4Mi44OTk5IDEzLjMwMDggODIuODk5OSAxMS41MDA4QzgyLjg5OTkgOS42MDA3OCA4My40OTk5IDguMTAwNzggODQuNzk5OSA3LjAwMDc4Qzg2LjA5OTkgNS45MDA3OCA4Ny43OTk5IDUuMzAwNzggODkuOTk5OSA1LjMwMDc4QzkzLjY5OTkgNS4zMDA3OCA5NS45OTk5IDYuOTAwNzggOTYuNjk5OSAxMC4wMDA4TDkzLjY5OTkgMTAuNzAwOEM5My4yOTk5IDguODAwNzggOTIuMjk5OSA4LjEwMDc4IDg5Ljg5OTkgOC4xMDA3OEM4Ni45OTk5IDguMTAwNzggODUuODk5OSA5LjIwMDc4IDg1Ljg5OTkgMTEuNTAwOEM4NS44OTk5IDEzLjgwMDggODYuOTk5OSAxNC45MDA4IDg5Ljg5OTkgMTQuOTAwOEM5Mi4yOTk5IDE0LjkwMDggOTMuMjk5OSAxNC4yMDA4IDkzLjY5OTkgMTIuMjAwOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTExLjggMTAuNlYxNy40SDEwOC43VjExLjJDMTA4LjcgOSAxMDcuOCA4LjEgMTA1LjkgOC4xQzEwMy42IDguMSAxMDIuNCA5LjMgMTAyLjQgMTEuN1YxNy4zSDk5LjI5OThWMC41SDEwMi40VjguM0MxMDMuMSA2LjMgMTA0LjYgNS4zIDEwNyA1LjNDMTEwLjIgNS4zIDExMS44IDcuMSAxMTEuOCAxMC42WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMTQuMSAxNC4wOTg0TDExNy4xIDEzLjI5ODRDMTE3LjQgMTQuNzk4NCAxMTguMyAxNS4yOTg0IDEyMC4yIDE1LjI5ODRDMTIxLjggMTUuMjk4NCAxMjIuNyAxNC44OTg0IDEyMi43IDE0LjA5ODRDMTIyLjcgMTMuMjk4NCAxMjIuMiAxMi45OTg0IDEyMC42IDEyLjc5ODRMMTE4LjIgMTIuNDk4NEMxMTUuOSAxMi4xOTg0IDExNC41IDEwLjg5ODQgMTE0LjUgOC45OTg0NEMxMTQuNSA2Ljc5ODQ0IDExNi41IDUuMzk4NDQgMTE5LjggNS4zOTg0NEMxMjMuMSA1LjM5ODQ0IDEyNSA2LjY5ODQ0IDEyNS41IDguODk4NDRMMTIyLjUgOS41OTg0NEMxMjIuMyA4LjA5ODQ0IDEyMS41IDcuNjk4NDQgMTE5LjkgNy42OTg0NEMxMTguNCA3LjY5ODQ0IDExNy42IDguMDk4NDQgMTE3LjYgOC44OTg0NEMxMTcuNiA5LjU5ODQ0IDExOC4xIDkuOTk4NDQgMTE5LjMgMTAuMDk4NEwxMjIuMiAxMC40OTg0QzEyNC40IDEwLjc5ODQgMTI1LjggMTEuOTk4NCAxMjUuOCAxMy44OTg0QzEyNS44IDE2LjI5ODQgMTIzLjcgMTcuNzk4NCAxMjAuMSAxNy43OTg0QzExNi43IDE3LjU5ODQgMTE0LjUgMTYuMTk4NCAxMTQuMSAxNC4wOTg0WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMzYuNyA4LjNIMTMyLjdWMTQuN0gxMzYuNFYxNy40SDEzMy4zQzEzMS4xIDE3LjQgMTI5LjYgMTUuOSAxMjkuNiAxMy43VjguM0gxMjYuN1Y1LjZIMTI5LjZWMkgxMzIuN1Y1LjVIMTM2LjdWOC4zWiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNDkuMiAxMS40OTg0QzE0OS4yIDkuMTk4NDQgMTQ3LjkgOC4wOTg0NCAxNDUuMyA4LjA5ODQ0QzE0Mi42IDguMDk4NDQgMTQxLjUgOS4wOTg0NCAxNDEuNSAxMS40OTg0QzE0MS41IDEzLjc5ODQgMTQyLjYgMTQuODk4NCAxNDUuMyAxNC44OTg0QzE0Ny45IDE0Ljg5ODQgMTQ5LjIgMTMuNzk4NCAxNDkuMiAxMS40OTg0Wk0xNDkuMSA1LjU5ODQ0SDE1Mi4yVjE3LjM5ODRIMTQ5LjFWMTQuNDk4NEMxNDguMiAxNi40OTg0IDE0Ni41IDE3LjY5ODQgMTQ0LjQgMTcuNjk4NEMxNDAuNSAxNy42OTg0IDEzOC40IDE1LjI5ODQgMTM4LjQgMTEuNTk4NEMxMzguNCA3Ljc5ODQ0IDE0MC40IDUuMzk4NDQgMTQ0LjIgNS4zOTg0NEMxNDYuMyA1LjM5ODQ0IDE0OC4yIDYuNTk4NDQgMTQ5IDguNTk4NDRWNS41OTg0NEgxNDkuMVoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTY1LjYgMTIuMjAwOEwxNjguNiAxMi45MDA4QzE2Ny45IDE2LjAwMDggMTY1LjYgMTcuNjAwOCAxNjEuOSAxNy42MDA4QzE1OS43IDE3LjYwMDggMTU4IDE3LjAwMDggMTU2LjcgMTUuOTAwOEMxNTUuNCAxNC44MDA4IDE1NC44IDEzLjMwMDggMTU0LjggMTEuNTAwOEMxNTQuOCA5LjYwMDc4IDE1NS40IDguMTAwNzggMTU2LjcgNy4wMDA3OEMxNTggNS45MDA3OCAxNTkuNyA1LjMwMDc4IDE2MS45IDUuMzAwNzhDMTY1LjYgNS4zMDA3OCAxNjcuOSA2LjkwMDc4IDE2OC42IDEwLjAwMDhMMTY1LjYgMTAuNzAwOEMxNjUuMiA4LjgwMDc4IDE2NC4yIDguMTAwNzggMTYxLjggOC4xMDA3OEMxNTguOSA4LjEwMDc4IDE1Ny44IDkuMjAwNzggMTU3LjggMTEuNTAwOEMxNTcuOCAxMy44MDA4IDE1OC45IDE0LjkwMDggMTYxLjggMTQuOTAwOEMxNjQuMSAxNC45MDA4IDE2NS4xIDE0LjIwMDggMTY1LjYgMTIuMjAwOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTgwLjI1NyAxNy40TDE3Ni42NTcgMTIuM0wxNzQuMTU3IDE0LjZWMTcuNEgxNzEuMTU3VjAuNUgxNzQuMTU3VjExLjFMMTc5Ljg1NyA1LjZIMTgzLjc1N0wxNzguNTU3IDEwLjVMMTgzLjk1NyAxNy40SDE4MC4yNTdaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTAgMjEuNTAwOEg3LjNWMTYuMzAwOEgwVjIxLjUwMDhaIiBmaWxsPSIjQUZFNjE0Ii8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNy4yOTk4IDIxLjUwMDhIMTQuNTk5OFYxNi4zMDA4SDcuMjk5OFYyMS41MDA4WiIgZmlsbD0iIzZFQkUwMCIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTE0LjYwMDEgMTYuM0gyOS4yMDAxVjAuNUgxNC42MDAxVjE2LjNaIiBmaWxsPSIjQUZFNjE0Ii8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMCAxMUgxNC42VjAuNUgwVjExWiIgZmlsbD0iIzZFQkUwMCIvPgo8L3N2Zz4K\" alt=\"Patchstack Logo\">\n\t\t\t\t</a>\n </div>\n </div>\n \n <div class=\"mobile-bottom-container\">\n <div class=\"mobile-bottom-text-containers\">\n <img class=\"arrow-vector\" src=\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOCIgaGVpZ2h0PSIxMyIgdmlld0JveD0iMCAwIDggMTMiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik03LjQxIDEuNDMzNDRMNiAwLjAyMzQzNzVMMCA2LjAyMzQ0TDYgMTIuMDIzNEw3LjQxIDEwLjYxMzRMMi44MyA2LjAyMzQ0TDcuNDEgMS40MzM0NFoiIGZpbGw9IiNBRkU2MTQiLz4KPC9zdmc+Cg==\" alt=\"Arrow Left\">\n <a href=\"/\" class=\"return-text\">Return to homepage</a>\n </div>\n <div class=\"mobile-bottom-second-containers\">\n <span class=\"secured-text\">This website is secured by</span>\n <a href=\"https://patchstack.com\" class=\"logoText\">\n <img class=\"patch-logo\" src=\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTg0IiBoZWlnaHQ9IjIyIiB2aWV3Qm94PSIwIDAgMTg0IDIyIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTUwLjQwMDEgMTEuNTAwOEM1MC40MDAxIDkuMTAwNzggNDkuMzAwMSA4LjEwMDc4IDQ2LjYwMDEgOC4xMDA3OEM0NC4wMDAxIDguMTAwNzggNDIuNzAwMSA5LjIwMDc4IDQyLjcwMDEgMTEuNTAwOEM0Mi43MDAxIDEzLjgwMDggNDQuMDAwMSAxNC45MDA4IDQ2LjYwMDEgMTQuOTAwOEM0OS4zMDAxIDE0LjkwMDggNTAuNDAwMSAxMy44MDA4IDUwLjQwMDEgMTEuNTAwOFpNNTMuNDAwMSAxMS41MDA4QzUzLjQwMDEgMTUuMzAwOCA1MS4zMDAxIDE3LjYwMDggNDcuNDAwMSAxNy42MDA4QzQ1LjQwMDEgMTcuNjAwOCA0My42MDAxIDE2LjUwMDggNDIuNzAwMSAxNC41MDA4VjIxLjUwMDhIMzkuNjAwMVY1LjYwMDc4SDQyLjcwMDFWOC41MDA3OEM0My42MDAxIDYuNTAwNzggNDUuNDAwMSA1LjMwMDc4IDQ3LjUwMDEgNS4zMDA3OEM1MS40MDAxIDUuMzAwNzggNTMuNDAwMSA3LjcwMDc4IDUzLjQwMDEgMTEuNTAwOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNjYuNDAwMSAxMS40OTg0QzY2LjQwMDEgOS4xOTg0NCA2NS4xMDAxIDguMDk4NDQgNjIuNTAwMSA4LjA5ODQ0QzU5LjgwMDEgOC4wOTg0NCA1OC43MDAxIDkuMDk4NDQgNTguNzAwMSAxMS40OTg0QzU4LjcwMDEgMTMuNzk4NCA1OS44MDAxIDE0Ljg5ODQgNjIuNTAwMSAxNC44OTg0QzY1LjEwMDEgMTQuODk4NCA2Ni40MDAxIDEzLjc5ODQgNjYuNDAwMSAxMS40OTg0Wk02Ni4zMDAxIDUuNTk4NDRINjkuNDAwMVYxNy4zOTg0SDY2LjMwMDFWMTQuNDk4NEM2NS40MDAxIDE2LjQ5ODQgNjMuNzAwMSAxNy42OTg0IDYxLjYwMDEgMTcuNjk4NEM1Ny43MDAxIDE3LjY5ODQgNTUuNjAwMSAxNS4yOTg0IDU1LjYwMDEgMTEuNTk4NEM1NS42MDAxIDcuNzk4NDQgNTcuNjAwMSA1LjM5ODQ0IDYxLjQwMDEgNS4zOTg0NEM2My41MDAxIDUuMzk4NDQgNjUuNDAwMSA2LjU5ODQ0IDY2LjIwMDEgOC41OTg0NFY1LjU5ODQ0SDY2LjMwMDFaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTgxLjM5OTkgOC4zSDc3LjM5OTlWMTQuN0g4MS4wOTk5VjE3LjRINzcuOTk5OUM3NS43OTk5IDE3LjQgNzQuMjk5OSAxNS45IDc0LjI5OTkgMTMuN1Y4LjNINzEuMzk5OVY1LjZINzQuMjk5OVYySDc3LjM5OTlWNS41SDgxLjM5OTlWOC4zWiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik05My42OTk5IDEyLjIwMDhMOTYuNjk5OSAxMi45MDA4Qzk1Ljk5OTkgMTYuMDAwOCA5My42OTk5IDE3LjYwMDggODkuOTk5OSAxNy42MDA4Qzg3Ljc5OTkgMTcuNjAwOCA4Ni4wOTk5IDE3LjAwMDggODQuNzk5OSAxNS45MDA4QzgzLjQ5OTkgMTQuODAwOCA4Mi44OTk5IDEzLjMwMDggODIuODk5OSAxMS41MDA4QzgyLjg5OTkgOS42MDA3OCA4My40OTk5IDguMTAwNzggODQuNzk5OSA3LjAwMDc4Qzg2LjA5OTkgNS45MDA3OCA4Ny43OTk5IDUuMzAwNzggODkuOTk5OSA1LjMwMDc4QzkzLjY5OTkgNS4zMDA3OCA5NS45OTk5IDYuOTAwNzggOTYuNjk5OSAxMC4wMDA4TDkzLjY5OTkgMTAuNzAwOEM5My4yOTk5IDguODAwNzggOTIuMjk5OSA4LjEwMDc4IDg5Ljg5OTkgOC4xMDA3OEM4Ni45OTk5IDguMTAwNzggODUuODk5OSA5LjIwMDc4IDg1Ljg5OTkgMTEuNTAwOEM4NS44OTk5IDEzLjgwMDggODYuOTk5OSAxNC45MDA4IDg5Ljg5OTkgMTQuOTAwOEM5Mi4yOTk5IDE0LjkwMDggOTMuMjk5OSAxNC4yMDA4IDkzLjY5OTkgMTIuMjAwOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTExLjggMTAuNlYxNy40SDEwOC43VjExLjJDMTA4LjcgOSAxMDcuOCA4LjEgMTA1LjkgOC4xQzEwMy42IDguMSAxMDIuNCA5LjMgMTAyLjQgMTEuN1YxNy4zSDk5LjI5OThWMC41SDEwMi40VjguM0MxMDMuMSA2LjMgMTA0LjYgNS4zIDEwNyA1LjNDMTEwLjIgNS4zIDExMS44IDcuMSAxMTEuOCAxMC42WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMTQuMSAxNC4wOTg0TDExNy4xIDEzLjI5ODRDMTE3LjQgMTQuNzk4NCAxMTguMyAxNS4yOTg0IDEyMC4yIDE1LjI5ODRDMTIxLjggMTUuMjk4NCAxMjIuNyAxNC44OTg0IDEyMi43IDE0LjA5ODRDMTIyLjcgMTMuMjk4NCAxMjIuMiAxMi45OTg0IDEyMC42IDEyLjc5ODRMMTE4LjIgMTIuNDk4NEMxMTUuOSAxMi4xOTg0IDExNC41IDEwLjg5ODQgMTE0LjUgOC45OTg0NEMxMTQuNSA2Ljc5ODQ0IDExNi41IDUuMzk4NDQgMTE5LjggNS4zOTg0NEMxMjMuMSA1LjM5ODQ0IDEyNSA2LjY5ODQ0IDEyNS41IDguODk4NDRMMTIyLjUgOS41OTg0NEMxMjIuMyA4LjA5ODQ0IDEyMS41IDcuNjk4NDQgMTE5LjkgNy42OTg0NEMxMTguNCA3LjY5ODQ0IDExNy42IDguMDk4NDQgMTE3LjYgOC44OTg0NEMxMTcuNiA5LjU5ODQ0IDExOC4xIDkuOTk4NDQgMTE5LjMgMTAuMDk4NEwxMjIuMiAxMC40OTg0QzEyNC40IDEwLjc5ODQgMTI1LjggMTEuOTk4NCAxMjUuOCAxMy44OTg0QzEyNS44IDE2LjI5ODQgMTIzLjcgMTcuNzk4NCAxMjAuMSAxNy43OTg0QzExNi43IDE3LjU5ODQgMTE0LjUgMTYuMTk4NCAxMTQuMSAxNC4wOTg0WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMzYuNyA4LjNIMTMyLjdWMTQuN0gxMzYuNFYxNy40SDEzMy4zQzEzMS4xIDE3LjQgMTI5LjYgMTUuOSAxMjkuNiAxMy43VjguM0gxMjYuN1Y1LjZIMTI5LjZWMkgxMzIuN1Y1LjVIMTM2LjdWOC4zWiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNDkuMiAxMS40OTg0QzE0OS4yIDkuMTk4NDQgMTQ3LjkgOC4wOTg0NCAxNDUuMyA4LjA5ODQ0QzE0Mi42IDguMDk4NDQgMTQxLjUgOS4wOTg0NCAxNDEuNSAxMS40OTg0QzE0MS41IDEzLjc5ODQgMTQyLjYgMTQuODk4NCAxNDUuMyAxNC44OTg0QzE0Ny45IDE0Ljg5ODQgMTQ5LjIgMTMuNzk4NCAxNDkuMiAxMS40OTg0Wk0xNDkuMSA1LjU5ODQ0SDE1Mi4yVjE3LjM5ODRIMTQ5LjFWMTQuNDk4NEMxNDguMiAxNi40OTg0IDE0Ni41IDE3LjY5ODQgMTQ0LjQgMTcuNjk4NEMxNDAuNSAxNy42OTg0IDEzOC40IDE1LjI5ODQgMTM4LjQgMTEuNTk4NEMxMzguNCA3Ljc5ODQ0IDE0MC40IDUuMzk4NDQgMTQ0LjIgNS4zOTg0NEMxNDYuMyA1LjM5ODQ0IDE0OC4yIDYuNTk4NDQgMTQ5IDguNTk4NDRWNS41OTg0NEgxNDkuMVoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTY1LjYgMTIuMjAwOEwxNjguNiAxMi45MDA4QzE2Ny45IDE2LjAwMDggMTY1LjYgMTcuNjAwOCAxNjEuOSAxNy42MDA4QzE1OS43IDE3LjYwMDggMTU4IDE3LjAwMDggMTU2LjcgMTUuOTAwOEMxNTUuNCAxNC44MDA4IDE1NC44IDEzLjMwMDggMTU0LjggMTEuNTAwOEMxNTQuOCA5LjYwMDc4IDE1NS40IDguMTAwNzggMTU2LjcgNy4wMDA3OEMxNTggNS45MDA3OCAxNTkuNyA1LjMwMDc4IDE2MS45IDUuMzAwNzhDMTY1LjYgNS4zMDA3OCAxNjcuOSA2LjkwMDc4IDE2OC42IDEwLjAwMDhMMTY1LjYgMTAuNzAwOEMxNjUuMiA4LjgwMDc4IDE2NC4yIDguMTAwNzggMTYxLjggOC4xMDA3OEMxNTguOSA4LjEwMDc4IDE1Ny44IDkuMjAwNzggMTU3LjggMTEuNTAwOEMxNTcuOCAxMy44MDA4IDE1OC45IDE0LjkwMDggMTYxLjggMTQuOTAwOEMxNjQuMSAxNC45MDA4IDE2NS4xIDE0LjIwMDggMTY1LjYgMTIuMjAwOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTgwLjI1NyAxNy40TDE3Ni42NTcgMTIuM0wxNzQuMTU3IDE0LjZWMTcuNEgxNzEuMTU3VjAuNUgxNzQuMTU3VjExLjFMMTc5Ljg1NyA1LjZIMTgzLjc1N0wxNzguNTU3IDEwLjVMMTgzLjk1NyAxNy40SDE4MC4yNTdaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTAgMjEuNTAwOEg3LjNWMTYuMzAwOEgwVjIxLjUwMDhaIiBmaWxsPSIjQUZFNjE0Ii8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNy4yOTk4IDIxLjUwMDhIMTQuNTk5OFYxNi4zMDA4SDcuMjk5OFYyMS41MDA4WiIgZmlsbD0iIzZFQkUwMCIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTE0LjYwMDEgMTYuM0gyOS4yMDAxVjAuNUgxNC42MDAxVjE2LjNaIiBmaWxsPSIjQUZFNjE0Ii8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMCAxMUgxNC42VjAuNUgwVjExWiIgZmlsbD0iIzZFQkUwMCIvPgo8L3N2Zz4K\" alt=\"Patchstack Logo\">\n\t\t\t\t</a>\n </div>\n </div>\n </div>\n</body>\n<script>\n function copyText(id) {\n var copyText = document.getElementById(id)\n copyText.select();\n copyText.setSelectionRange(0, 99999);\n navigator.clipboard.writeText(copyText.value);\n }\n\n function hover(element) {\n element.setAttribute('src', 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMjMiIHZpZXdCb3g9IjAgMCAxOSAyMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE0IDAuMDIzNDM3NUgwVjE2LjAyMzRIMlYyLjAyMzQ0SDE0VjAuMDIzNDM3NVpNMTkgNC4wMjM0NEg0VjIyLjAyMzRIMTlWNC4wMjM0NFpNMTcgMjAuMDIzNEg2VjYuMDIzNDRIMTdWMjAuMDIzNFoiIGZpbGw9IiNBRkU2MTQiLz4KPC9zdmc+Cg==');\n }\n\n function unhover(element) {\n element.setAttribute('src', 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMjMiIHZpZXdCb3g9IjAgMCAxOSAyMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE0IDAuMDIzNDM3NUgwVjE2LjAyMzRIMlYyLjAyMzQ0SDE0VjAuMDIzNDM3NVpNMTkgNC4wMjM0NEg0VjIyLjAyMzRIMTlWNC4wMjM0NFpNMTcgMjAuMDIzNEg2VjYuMDIzNDRIMTdWMjAuMDIzNFoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=');\n }\n</script>\n</html>`;\n}\n", "// Rule cache as a TIERED store of a `{ bundle, etag }` envelope:\n// 1. memory \u2014 always present; last-known-good within the process. Survives refreshes and is\n// the fallback when the disk isn't writable (read-only FS, sandbox).\n// 2. durable \u2014 filesystem (default, via `cacheDir`) OR a pluggable adapter (`ruleCache`, e.g.\n// a KV store for filesystem-less runtimes). Survives process restarts.\n// read: memory \u2192 durable \u2192 null. write: memory + best-effort durable. Everything is fail-open \u2014\n// a read/write error yields \"no cache\" rather than throwing.\n//\n// Node's fs/path are loaded LAZILY (dynamic import), never as a static top-level import: this module\n// is part of the WinterCG/edge-safe graph (Next edge middleware, Workers, Deno, Supabase Functions),\n// where a static `node:fs` import fails to resolve at build/load time and would take the whole guard\n// down. On those runtimes the disk tier simply reports \"no cache\" and the memory tier (or a pluggable\n// `ruleCache` adapter) carries last-known-good.\n\nlet fsMod; // memoized { readFileSync, writeFileSync, mkdirSync, join } | null (unavailable)\nasync function loadFs() {\n if (fsMod !== undefined) return fsMod;\n try {\n const [fs, path] = await Promise.all([import('node:fs'), import('node:path')]);\n fsMod = {\n readFileSync: fs.readFileSync,\n writeFileSync: fs.writeFileSync,\n mkdirSync: fs.mkdirSync,\n join: path.join,\n };\n } catch {\n fsMod = null; // no filesystem here (edge runtime) \u2014 memory/adapter tiers still work\n }\n return fsMod;\n}\n\nexport function makeStore(options = {}) {\n let mem = null;\n const durable = durableTier(options);\n return {\n async read() {\n if (mem) return mem;\n const env = await durable.read();\n if (env) mem = env;\n return env;\n },\n async write(env) {\n if (env) mem = env;\n await durable.write(env);\n },\n };\n}\n\n// The durable tier: a caller-supplied adapter wins; otherwise a disk cache under `cacheDir`; if\n// neither is configured, a no-op (memory-only \u2014 fine for a long-lived process).\nfunction durableTier(options) {\n const adapter = options.ruleCache;\n if (adapter && typeof adapter.read === 'function' && typeof adapter.write === 'function') {\n return {\n read: async () => {\n try {\n return toEnvelope(await adapter.read());\n } catch {\n return null;\n }\n },\n write: async (env) => {\n try {\n await adapter.write(env);\n } catch {\n /* best-effort */\n }\n },\n };\n }\n const dir = options.cacheDir;\n return {\n read: async () => cacheRead(dir),\n write: async (env) => cacheWrite(dir, env),\n };\n}\n\nasync function cacheWrite(dir, env) {\n if (!dir) return;\n const fs = await loadFs();\n if (!fs) return; // filesystem-less runtime \u2014 memory tier only\n try {\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(fs.join(dir, 'patchstack-rules.json'), JSON.stringify(env));\n } catch {\n /* cache is best-effort \u2014 the memory tier still holds last-known-good */\n }\n}\n\nasync function cacheRead(dir) {\n if (!dir) return null;\n const fs = await loadFs();\n if (!fs) return null;\n try {\n return toEnvelope(JSON.parse(fs.readFileSync(fs.join(dir, 'patchstack-rules.json'), 'utf8')));\n } catch {\n return null;\n }\n}\n\n// Accept the current { bundle, etag } envelope and a legacy bare bundle (pre-envelope cache files).\nexport function toEnvelope(value) {\n if (!value || typeof value !== 'object') return null;\n if (value.bundle && typeof value.bundle === 'object') {\n return { bundle: value.bundle, etag: value.etag ?? null };\n }\n if (Array.isArray(value.firewall) || Array.isArray(value.whitelists)) {\n return { bundle: value, etag: null }; // legacy bare-bundle cache file\n }\n return null;\n}\n", "// Rule-bundle validation. Delivered rules are POLICY fetched over the network, and the engine executes\n// them on every request \u2014 so an upstream compromise, a schema drift, or a mistake in the corpus could\n// otherwise hand the app unbounded work (a 50k-rule bundle, a 500-deep condition tree, a pathological\n// regex) or silently unenforceable junk.\n//\n// Two principles:\n// 1. REJECT, don't silently skip. A rule that fails validation is dropped WITH a reported reason, so\n// an unenforceable rule is visible instead of quietly protecting nothing.\n// 2. Bound everything the engine will walk: rule count, conditions per rule, nesting depth, and\n// pattern length. Caps are deliberately far above any real corpus rule.\n//\n// Fail-open in spirit: validation never throws, and a bundle whose rules are all rejected simply means\n// \"no rules\" (the app keeps serving) \u2014 never a crash.\n\nexport const LIMITS = {\n maxRules: 5000,\n maxWhitelists: 2000,\n maxConditionsPerRule: 250,\n maxNestingDepth: 12,\n maxRegexLength: 1000,\n maxValueLength: 8192,\n};\n\nconst PHASES = new Set(['request', 'response', 'egress']);\nconst ACTIONS = new Set(['block', 'redact', 'encode', 'set-header', 'remove-header', 'harden-cookie']);\n\n/**\n * Validate a delivered bundle. Returns `{ bundle, rejected }` where `bundle` contains only rules that\n * passed and `rejected` is `[{ id, reason }]` for everything dropped.\n * @param {object} bundle\n * @returns {{ bundle: object, rejected: Array<{id: string, reason: string}> }}\n */\nexport function validateBundle(bundle, opts = {}) {\n const rejected = [];\n const inFirewall = Array.isArray(bundle?.firewall) ? bundle.firewall : [];\n const inWhitelists = Array.isArray(bundle?.whitelists) ? bundle.whitelists : [];\n\n const firewall = [];\n for (const rule of inFirewall) {\n if (firewall.length >= LIMITS.maxRules) {\n rejected.push({ id: idOf(rule), reason: `bundle exceeds maxRules (${LIMITS.maxRules})` });\n continue;\n }\n const reason = ruleProblem(rule);\n if (reason) rejected.push({ id: idOf(rule), reason });\n else firewall.push(rule);\n }\n\n const whitelists = [];\n for (const wl of inWhitelists) {\n if (whitelists.length >= LIMITS.maxWhitelists) {\n rejected.push({ id: idOf(wl), reason: `bundle exceeds maxWhitelists (${LIMITS.maxWhitelists})` });\n continue;\n }\n // A whitelist SUPPRESSES rules, so a malformed one is a protection risk, not a detection risk.\n // One with no `rule_id` applies to EVERY rule \u2014 a single tripped condition disables the whole\n // firewall for that request \u2014 so it must be opted into explicitly.\n if (!opts.allowGlobalWhitelists && wl && Array.isArray(wl.rule_v2) && !wl.rule_id) {\n rejected.push({ id: idOf(wl), reason: 'whitelist has no rule_id (would suppress every rule); set allowGlobalWhitelists to permit' });\n continue;\n }\n const reason = conditionsProblem(wl?.rule_v2);\n if (reason) rejected.push({ id: idOf(wl), reason: `whitelist: ${reason}` });\n else whitelists.push(wl);\n }\n\n return {\n bundle: { ...bundle, firewall, whitelists },\n rejected,\n };\n}\n\nfunction idOf(rule) {\n const id = rule?.id ?? rule?.rule_id;\n return id === undefined || id === null ? '(unidentified)' : String(id);\n}\n\n/** @returns {string|null} a reason the rule must be dropped, or null when it's acceptable. */\nfunction ruleProblem(rule) {\n if (!rule || typeof rule !== 'object') return 'not an object';\n if (rule.phase !== undefined && !PHASES.has(rule.phase)) return `unknown phase \"${rule.phase}\"`;\n if (rule.action !== undefined && !ACTIONS.has(rule.action)) return `unknown action \"${rule.action}\"`;\n const capOverride = rule.max_bytes;\n if (capOverride !== undefined && !(Number(capOverride) > 0)) return 'max_bytes must be a positive number';\n return conditionsProblem(rule.rule_v2);\n}\n\nfunction conditionsProblem(conditions, depth = 0) {\n if (!Array.isArray(conditions)) return 'rule_v2 must be an array of conditions';\n if (conditions.length === 0) return 'rule_v2 is empty (would never match)';\n if (depth > LIMITS.maxNestingDepth) return `nesting deeper than ${LIMITS.maxNestingDepth}`;\n if (conditions.length > LIMITS.maxConditionsPerRule) {\n return `more than ${LIMITS.maxConditionsPerRule} conditions`;\n }\n for (const c of conditions) {\n if (!c || typeof c !== 'object') return 'condition is not an object';\n if (Array.isArray(c.rules)) {\n const nested = conditionsProblem(c.rules, depth + 1);\n if (nested) return nested;\n continue; // a group carries no match of its own\n }\n const m = c.match;\n if (!m || typeof m !== 'object') return 'condition has no match object';\n if (typeof m.type !== 'string' || m.type === '') return 'match.type must be a non-empty string';\n if (m.type === 'regex') {\n if (typeof m.value !== 'string') return 'regex match.value must be a string';\n if (m.value.length > LIMITS.maxRegexLength) return `regex longer than ${LIMITS.maxRegexLength} chars`;\n } else if (typeof m.value === 'string' && m.value.length > LIMITS.maxValueLength) {\n return `match.value longer than ${LIMITS.maxValueLength} chars`;\n }\n if (m.match) {\n // array_key_value nests a sub-match; count it toward depth so a chain can't be unbounded.\n const nested = conditionsProblem([{ match: m.match }], depth + 1);\n if (nested) return nested;\n }\n }\n return null;\n}\n", "// Rule source: pick where the ruleset comes from \u2014 an explicit bundle, or the live API by site\n// UUID (Pulse) or token \u2014 fetch it (conditional/If-None-Match via the persisted etag), and fall\n// back through last-known-good \u2192 bundled \u2192 empty. Fail-open: a fetch/parse error never throws.\n// The `store` (see ./store.js) is passed in so a refresh reuses the same tiered cache.\nimport { PatchstackRuleClient } from '../engine/index.js';\nimport { PulseRuleClient } from '../engine/pulse-client.js';\nimport { validateBundle } from './validate.js';\n\n// A LIVE update is accepted ATOMICALLY. Dropping individual invalid rules is fine for a bundle we\n// already trust (a cache entry, a bundled fallback), but for a fresh remote response it would let a\n// broken update REPLACE known-good policy with partial or empty policy \u2014 turning \"we validated it\" into\n// a loss of protection, and caching that loss. So: if any rule/whitelist fails validation, reject the\n// whole update, keep last-known-good, report it, and do NOT write the cache. Opt in to the old\n// behaviour with `acceptPartialBundle: true` (metrics still report every drop).\nfunction liveUpdateRejections(res, options) {\n if (options.acceptPartialBundle) return [];\n const { rejected } = validateBundle(\n { firewall: Array.isArray(res.firewall) ? res.firewall : [], whitelists: Array.isArray(res.whitelists) ? res.whitelists : [] },\n { allowGlobalWhitelists: options.allowGlobalWhitelists },\n );\n return rejected;\n}\n\nfunction reportRejections(rejected, options, label) {\n const report = options.onRuleRejected;\n for (const r of rejected) {\n if (typeof report === 'function') {\n try { report({ ...r, accepted: false }); } catch { /* reporting must never break rule loading */ }\n }\n }\n const sample = rejected.slice(0, 3).map((r) => `${r.id} (${r.reason})`).join('; ');\n options.onError?.(new Error(\n `${label}: rejected the entire update because ${rejected.length} rule(s) failed validation \u2014 ` +\n `keeping the previous ruleset and NOT caching this response: ${sample}${rejected.length > 3 ? ', \u2026' : ''}`,\n ));\n}\n\nexport async function resolveRules(options, store, ctx = {}) {\n // The INITIAL load is on the app's startup path, so the runtime gives it a short budget (see\n // bootTimeoutMs) and falls back to cache/bundled rather than delaying boot; refreshes get the full\n // budget. A timeout here is not a protection gap by itself \u2014 last-known-good still applies.\n const timeoutMs = ctx.timeoutMs;\n if (options.siteUuid) {\n const prior = await store.read(); // { bundle, etag } | null\n const client = new PulseRuleClient({ siteUuid: options.siteUuid, baseUrl: options.pulseRulesUrl, etag: prior?.etag, timeoutMs, pulseAuth: ctx.pulseAuth });\n const res = await client.getRules();\n if (res.success && res.notModified && prior?.bundle) return normalizeBundle(prior.bundle, options);\n if (res.success && !res.notModified) {\n const rejected = liveUpdateRejections(res, options);\n if (rejected.length > 0) {\n reportRejections(rejected, options, 'rule update rejected');\n if (prior?.bundle) return normalizeBundle(prior.bundle, options);\n if (options.rules) return normalizeBundle(options.rules, options);\n return emptyBundle();\n }\n const bundle = normalizeBundle(res, options);\n await store.write({ bundle, etag: res.etag ?? null });\n return bundle;\n }\n if (prior?.bundle) {\n options.onError?.(new Error(`pulse rule fetch failed (${res.error ?? 'no usable response'}); using cached bundle`));\n return normalizeBundle(prior.bundle, options);\n }\n if (options.rules) {\n options.onError?.(new Error(`pulse rule fetch failed (${res.error ?? 'no usable response'}); using bundled fallback`));\n return normalizeBundle(options.rules, options);\n }\n options.onError?.(new Error(`pulse rule fetch failed (${res.error ?? 'no usable response'}); no cache \u2014 running with no rules`));\n return emptyBundle();\n }\n\n if (options.token) {\n const prior = await store.read();\n const client = new PatchstackRuleClient({ token: options.token, baseUrl: options.baseUrl, etag: prior?.etag, timeoutMs });\n const res = await client.getRules();\n if (res.success && res.notModified && prior?.bundle) return normalizeBundle(prior.bundle, options);\n if (res.success && !res.notModified) {\n const rejected = liveUpdateRejections(res, options);\n if (rejected.length > 0) {\n reportRejections(rejected, options, 'rule update rejected');\n if (prior?.bundle) return normalizeBundle(prior.bundle, options);\n if (options.rules) return normalizeBundle(options.rules, options);\n return emptyBundle();\n }\n const bundle = normalizeBundle(res, options);\n await store.write({ bundle, etag: res.etag ?? null });\n return bundle;\n }\n if (prior?.bundle) {\n options.onError?.(new Error(`rule fetch failed (${res.error ?? 'no usable response'}); using cached bundle`));\n return normalizeBundle(prior.bundle, options);\n }\n options.onError?.(new Error(`rule fetch failed (${res.error ?? 'no usable response'}); no cache \u2014 running with no rules`));\n return emptyBundle();\n }\n\n if (options.rules) {\n return normalizeBundle(options.rules, options);\n }\n\n return emptyBundle();\n}\n\n// Every rule path (live fetch, cache, bundled fallback) funnels through here, so this is where the\n// delivered policy is VALIDATED before the engine ever executes it: bounded rule count / conditions /\n// nesting / pattern length, known phases + actions. A rule that fails is dropped with a reported reason\n// (`onRuleRejected`) rather than silently kept \u2014 an unenforceable rule must never look enforced.\nexport function normalizeBundle(b, options = {}) {\n const enforcement = b?.enforcement ?? b?.mode;\n const { bundle: checked, rejected } = validateBundle(\n {\n firewall: Array.isArray(b.firewall) ? b.firewall : [],\n whitelists: Array.isArray(b.whitelists) ? b.whitelists : [],\n },\n { allowGlobalWhitelists: options.allowGlobalWhitelists },\n );\n if (rejected.length > 0) {\n const report = options.onRuleRejected;\n if (typeof report === 'function') {\n for (const r of rejected) {\n try { report(r); } catch { /* reporting must never break rule loading */ }\n }\n } else {\n const sample = rejected.slice(0, 3).map((r) => `${r.id} (${r.reason})`).join('; ');\n // eslint-disable-next-line no-console\n console.warn(\n `[patchstack] ${rejected.length} delivered rule(s) rejected as invalid/oversized and are NOT enforced: ${sample}` +\n (rejected.length > 3 ? ', \u2026' : ''),\n );\n }\n }\n return {\n firewall: checked.firewall,\n whitelists: checked.whitelists,\n whitelist_keys: b.whitelist_keys ?? {},\n ...(enforcement === 'block' || enforcement === 'dry-run' ? { enforcement } : {}),\n };\n}\n\nexport function emptyBundle() {\n return { firewall: [], whitelists: [], whitelist_keys: {} };\n}\n", "// Rule refresh scheduling \u2014 how a long-lived guard picks up rules that become relevant after boot\n// (a dependency added mid-session, a zero-day published). Two triggers, both driving the same\n// caller-supplied `tick` (which re-fetches + hot-swaps the engines):\n// - startRefresh: a self-scheduling poll LOOP (reschedules after each tick settles, so runs never\n// overlap), with \u00B1jitter (avoid a thundering herd) and exponential backoff on consecutive\n// failures. `unref`'d \u2014 it never keeps the process alive.\n// - makeRefreshHandler: a PUSH endpoint \u2014 an authenticated fetch handler the platform/SaaS hits\n// for an immediate refresh (zero-day fast lane) instead of waiting for the next poll.\n\nconst JITTER_FRACTION = 0.1;\nconst MAX_BACKOFF_MULTIPLIER = 8; // cap consecutive-failure backoff at 8\u00D7 the base interval\n\nexport function startRefresh(tick, { refreshMs, onError } = {}) {\n let stopped = false;\n let failures = 0;\n let timer = null;\n\n const schedule = () => {\n if (stopped) return;\n const backoff = Math.min(2 ** failures, MAX_BACKOFF_MULTIPLIER);\n const jitter = 1 - Math.random() * JITTER_FRACTION; // shorten by up to 10% so clients don't align\n const delay = refreshMs * backoff * jitter;\n timer = setTimeout(run, delay);\n timer?.unref?.();\n };\n\n const run = async () => {\n if (stopped) return;\n try {\n await tick();\n failures = 0;\n } catch (err) {\n failures++;\n onError?.(err);\n }\n schedule();\n };\n\n schedule();\n return {\n stop() {\n stopped = true;\n if (timer) clearTimeout(timer);\n },\n };\n}\n\nexport function makeRefreshHandler(tick, secret) {\n return async (request) => {\n // No secret configured \u2192 the endpoint doesn't exist (never an open refresh-DoS surface).\n if (!secret) return new Response('not found', { status: 404 });\n let provided = null;\n try {\n provided = request?.headers?.get?.('x-patchstack-refresh') ?? new URL(request.url).searchParams.get('token');\n } catch {\n provided = null;\n }\n if (provided !== secret) return new Response('forbidden', { status: 403 });\n let refreshed = true;\n try {\n await tick();\n } catch {\n refreshed = false; // fail-open: report the outcome, never throw\n }\n return new Response(JSON.stringify({ refreshed }), { status: 200, headers: { 'content-type': 'application/json' } });\n };\n}\n", "import { isSafeOrigin } from './safe-origin.js';\n// Fire-and-forget reporter: Connect runtime \u2192 existing connector POST /api/logs/log\n// (same path WordPress uses). Auth: WP-style api_key (`{secret}-{oauth.id}`) \u2192\n// POST /oauth/token (client_credentials) \u2192 Bearer JWT on /api/logs/log.\n// Opt out: PATCHSTACK_TELEMETRY=off. Never put api_key in the public widget.\n\nconst DEFAULT_API_BASE = 'https://api.patchstack.com';\nconst DEFAULT_FLUSH_MS = 1000;\nconst MAX_BATCH = 50;\nconst TOKEN_SKEW_MS = 60_000;\n\n/**\n * Parse WP plugin api_key (`{secret}-{oauth.id}`) into client credentials.\n * @param {string} apiKey\n * @returns {{ clientId: string, clientSecret: string } | null}\n */\nexport function parseApiKey(apiKey) {\n if (typeof apiKey !== 'string' || apiKey.length === 0) return null;\n const idx = apiKey.lastIndexOf('-');\n if (idx <= 0 || idx === apiKey.length - 1) return null;\n const clientSecret = apiKey.slice(0, idx);\n const clientId = apiKey.slice(idx + 1);\n if (!/^\\d+$/.test(clientId) || clientSecret.length === 0) return null;\n return { clientId, clientSecret };\n}\n\n/**\n * Derive api.patchstack.com origin from a Pulse manifest/rules URL override.\n * @param {string | undefined} pulseOrManifestUrl\n */\nexport function resolveApiBase(pulseOrManifestUrl) {\n const fromEnv = typeof process !== 'undefined' ? process.env?.PATCHSTACK_API_BASE : undefined;\n if (typeof fromEnv === 'string' && fromEnv.length > 0) {\n // The site api_key is exchanged for a token against this origin, so a hostile/injected env value\n // would be a credential-exfiltration path. Require HTTPS (localhost excepted for local testing);\n // anything else falls back to the default origin rather than shipping the key off-platform.\n const candidate = fromEnv.replace(/\\/$/, '');\n if (isSafeOrigin(candidate)) return candidate;\n // eslint-disable-next-line no-console\n console.warn(\n '[patchstack] ignoring PATCHSTACK_API_BASE: block-log reporting requires an https origin ' +\n '(or localhost). Falling back to the default API origin.',\n );\n }\n if (typeof pulseOrManifestUrl === 'string' && pulseOrManifestUrl.length > 0) {\n try {\n return new URL(pulseOrManifestUrl).origin;\n } catch {\n /* fall through */\n }\n }\n const endpoint = typeof process !== 'undefined' ? process.env?.PATCHSTACK_ENDPOINT : undefined;\n if (typeof endpoint === 'string' && endpoint.length > 0) {\n try {\n return new URL(endpoint).origin;\n } catch {\n /* fall through */\n }\n }\n return DEFAULT_API_BASE;\n}\n\n/**\n * @param {{\n * apiKey: string,\n * apiBase?: string,\n * sourceHost?: string,\n * fetchImpl?: typeof fetch,\n * flushMs?: number,\n * }} opts\n */\nexport function createFirewallLogReporter(opts) {\n const creds = parseApiKey(opts.apiKey);\n if (!creds) {\n return { record() {}, flush() {}, stop() {} };\n }\n\n const apiBase = (opts.apiBase ?? DEFAULT_API_BASE).replace(/\\/$/, '');\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch;\n const flushMs = Number.isFinite(opts.flushMs) ? opts.flushMs : DEFAULT_FLUSH_MS;\n const sourceHost = typeof opts.sourceHost === 'string' ? opts.sourceHost : '';\n\n /** @type {Array<Record<string, unknown>>} */\n let queue = [];\n /** @type {ReturnType<typeof setTimeout> | null} */\n let timer = null;\n let stopped = false;\n\n /** @type {{ token: string, expiresAt: number } | null} */\n let cachedToken = null;\n /** @type {Promise<string | null> | null} */\n let tokenInflight = null;\n\n const fetchAccessToken = async () => {\n if (cachedToken && Date.now() < cachedToken.expiresAt - TOKEN_SKEW_MS) {\n return cachedToken.token;\n }\n if (tokenInflight) return tokenInflight;\n\n tokenInflight = (async () => {\n try {\n const res = await fetchImpl(`${apiBase}/oauth/token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'User-Agent': '@patchstack/connect',\n },\n body: JSON.stringify({\n grant_type: 'client_credentials',\n client_id: creds.clientId,\n client_secret: creds.clientSecret,\n }),\n });\n if (!res || !res.ok) return null;\n const body = await res.json();\n const token = body?.access_token;\n if (typeof token !== 'string' || token.length === 0) return null;\n const expiresIn = Number(body?.expires_in);\n const ttlMs = Number.isFinite(expiresIn) && expiresIn > 0 ? expiresIn * 1000 : 3600_000;\n cachedToken = { token, expiresAt: Date.now() + ttlMs };\n return token;\n } catch {\n return null;\n } finally {\n tokenInflight = null;\n }\n })();\n\n return tokenInflight;\n };\n\n const flush = () => {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n if (queue.length === 0 || typeof fetchImpl !== 'function') return;\n\n const batch = queue.splice(0, MAX_BATCH);\n void (async () => {\n const token = await fetchAccessToken();\n if (!token) return;\n\n const body = new URLSearchParams();\n body.set('type', 'firewall');\n body.set('logs', JSON.stringify(batch));\n\n try {\n const p = fetchImpl(`${apiBase}/api/logs/log`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'User-Agent': '@patchstack/connect',\n ...(sourceHost ? { 'Source-Host': sourceHost } : {}),\n },\n body,\n });\n if (p && typeof p.then === 'function') p.catch(() => {});\n } catch {\n /* ignore */\n }\n })();\n };\n\n return {\n /**\n * @param {{\n * rule?: { id?: string | number },\n * method?: string | null,\n * path?: string | null,\n * ip?: string | null,\n * userAgent?: string | null,\n * }} event\n */\n record(event) {\n if (stopped) return;\n const fid = event?.rule?.id;\n if (fid === undefined || fid === null || fid === '') return;\n\n queue.push({\n fid,\n method: event.method ?? null,\n request_uri: event.path ?? null,\n ip: event.ip ?? null,\n user_agent: event.userAgent ?? null,\n log_date: new Date().toISOString(),\n });\n\n if (queue.length >= MAX_BATCH) {\n flush();\n return;\n }\n if (!timer) timer = setTimeout(flush, flushMs);\n },\n flush,\n stop() {\n stopped = true;\n flush();\n },\n };\n}\n\n/** @returns {boolean} */\nexport function telemetryEnabled() {\n const v = typeof process !== 'undefined' ? process.env?.PATCHSTACK_TELEMETRY : undefined;\n if (v === undefined || v === '') return true;\n return !/^(0|false|off|no)$/i.test(String(v));\n}\n", "// Supabase-tunnel guard for AI-builder apps (Lovable / TanStack Start + Supabase).\n//\n// The vibe-coded app's browser talks straight to Supabase, bypassing the app's own server \u2014\n// so a normal in-app WAF never sees the data traffic. The installer patches the generated\n// Supabase client to tunnel every call through this guard (running in the app's own server /\n// Worker). The guard runs the Patchstack protection policy on the tunneled request, then\n// forwards it to Supabase \u2014 pinned to the app's own project so it can't be turned into an\n// open proxy (SSRF).\n//\n// The heavy lifting (rule evaluation, dry-run/block, fail-open) is `protection.fetchGuard()`\n// from `createProtection` \u2014 this module is just the Supabase-specific tunnel around it.\n\nexport const GUARD_PATH = '/_patchstack/guard';\n\n// Headers we must not copy verbatim when re-emitting the upstream response.\nconst HOP_BY_HOP = new Set(['content-encoding', 'content-length', 'transfer-encoding', 'connection']);\n\n/**\n * @param {object} opts\n * @param {{ fetchGuard: () => (req: Request) => Promise<Response|null> }} opts.protection a createProtection() result\n * @param {string|undefined} opts.supabaseUrl the app's Supabase project URL (server-side env) \u2014 the only allowed forward target\n * @param {typeof fetch} [opts.fetchImpl] injectable fetch (tests)\n * @returns {(request: Request) => Promise<Response>}\n */\nexport function createSupabaseGuard({ protection, supabaseUrl, fetchImpl = fetch }) {\n const guard = protection.fetchGuard();\n const allowedOrigin = supabaseUrl ? new URL(supabaseUrl).origin : null;\n\n return async function handleGuardRequest(request) {\n const target = request.headers.get('x-ps-target');\n if (!target) return new Response('patchstack: missing x-ps-target', { status: 400 });\n\n let targetUrl;\n try {\n targetUrl = new URL(target);\n } catch {\n return new Response('patchstack: invalid target', { status: 400 });\n }\n\n // SSRF pin: only ever forward to the app's own Supabase project (origin from server-side\n // env, never the client-supplied header). Anything else \u2014 internal hosts, cloud metadata,\n // a different scheme \u2014 is rejected before any outbound request.\n if (!allowedOrigin || targetUrl.protocol !== 'https:' || targetUrl.origin !== allowedOrigin) {\n return new Response('patchstack: target not allowed', { status: 403 });\n }\n\n const hasBody = request.method !== 'GET' && request.method !== 'HEAD';\n const bodyText = hasBody ? await request.text() : '';\n\n // Evaluate the tunneled call against the policy. fetchGuard returns a 403 Response when it\n // blocks (block mode + match), or null to allow (allow, or dry-run \u2014 it records via onDetect).\n const evalReq = new Request(targetUrl.toString(), {\n method: request.method,\n headers: request.headers,\n body: hasBody ? bodyText : undefined,\n });\n const blocked = await guard(evalReq);\n if (blocked) return blocked;\n\n // Allowed \u2192 forward to Supabase, server-side.\n const forwardHeaders = new Headers(request.headers);\n forwardHeaders.delete('x-ps-target');\n forwardHeaders.delete('host');\n const upstream = await fetchImpl(targetUrl.toString(), {\n method: request.method,\n headers: forwardHeaders,\n body: hasBody ? bodyText : undefined,\n redirect: 'manual',\n });\n\n const outHeaders = new Headers();\n upstream.headers.forEach((value, key) => {\n if (!HOP_BY_HOP.has(key.toLowerCase())) outHeaders.set(key, value);\n });\n const buf = await upstream.arrayBuffer();\n const forwarded = new Response(buf, { status: upstream.status, statusText: upstream.statusText, headers: outHeaders });\n\n // Response phase: screen what Supabase returned (query results can leak secrets/PII) \u2014\n // redact the offending spans / withhold, per the response rules. Fail-open if unavailable.\n return protection.screenResponse ? protection.screenResponse(forwarded) : forwarded;\n };\n}\n", "// @patchstack/protect \u2014 \"Protect = respond\".\n//\n// One entry point that composes the node-waf engine + adapters with:\n// - a rule source: an explicit bundle, or fetched from the Patchstack API (token),\n// with a disk cache so the engine keeps working on last-known-good if the API is down\n// - execution modes: 'dry-run' (detect + log, never block \u2014 the safe onramp) and 'block' (enforce).\n// This API's default is 'dry-run'. NOTE the scaffolded guard (`patchstack-connect protect`)\n// deliberately passes mode: 'block' and only drops to dry-run when PATCHSTACK_MODE=dry-run \u2014 so an\n// installed guard ENFORCES by default even though this constructor's default doesn't. Precedence:\n// PATCHSTACK_MODE env > API `enforcement` > options.mode > dry-run.\n// - fail-open everywhere: a rule/engine error never blocks (or crashes) a request. Where the guard\n// fails open *without* inspecting (body caps, live streams, binary bodies, resolver failures) it\n// is counted and reported \u2014 see `protection.coverage()` / the `onSkip` option.\n//\n// Runtime guards: .express(), .node(), .fetch(handler) / .fetchGuard() \u2014 same policy,\n// every runtime an AI builder deploys to.\n// Vendored node-waf engine (this package is self-contained \u2014 no @patchstack/node-waf dep).\nimport { RuleEngine } from './engine/index.js';\nimport { matchValue, walkLeaves, safeRegExp } from './engine/engine.js';\nimport { PulseRuleClient } from './engine/pulse-client.js';\nimport { fromFetchRequest } from './engine/fetch.js';\nimport { fromNodeRequest } from './engine/node.js';\nimport { installEgressGuard } from './egress.js';\nimport { DEFAULT_RESPONSE_RULES, DEFAULT_EGRESS_RULES } from './defaults.js';\nimport { renderBlockPage } from './block-page.js';\n// Rule lifecycle (source / tiered store / refresh) lives in ./rules/ \u2014 this file stays focused on\n// composing the engine + guards and running the three screening phases.\nimport { makeStore } from './rules/store.js';\nimport { resolveRules } from './rules/source.js';\nimport { startRefresh, makeRefreshHandler } from './rules/refresh.js';\nimport { createFirewallLogReporter, resolveApiBase, telemetryEnabled } from './firewall-log.js';\n\n// Supabase-tunnel guard for AI-builder apps (Lovable / TanStack Start + Supabase).\nexport { createSupabaseGuard, GUARD_PATH } from './supabase-guard.js';\n\n// Per-site live rule client (Pulse). Re-exported for callers/tests that want to use it directly.\nexport { PulseRuleClient };\n\n// Server-function guard. Modern Lovable apps mutate data through TanStack server functions\n// (browser \u2192 server fn \u2192 server-side Supabase client), which bypass the browser-side tunnel the\n// Supabase guard relies on. This inspects the decoded server-fn call args against the SAME policy\n// by feeding them through fetchGuard (the args become the request body, so the engine resolves\n// `post.<field>` exactly as it does for a tunneled Supabase insert). Returns a block receipt\n// { rule?, message } to throw on, or null to allow (also null in dry-run \u2014 the detection is still\n// recorded by fetchGuard). Fail-open on any error.\nexport function createServerFnGuard({ protection }) {\n const guard = protection.fetchGuard();\n return async (data) => {\n let res;\n try {\n const req = new Request('https://patchstack.local/_serverfn', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(data ?? {}),\n });\n res = await guard(req);\n } catch {\n return null; // fail open\n }\n if (!res) return null; // allowed (or dry-run)\n let body = {};\n try {\n body = await res.clone().json();\n } catch {\n /* non-JSON block response */\n }\n return { rule: body.rule, message: body.message || 'Blocked by Patchstack' };\n };\n}\n\nexport async function createProtection(options = {}) {\n const onError = options.onError;\n const userOnDetect = options.onDetect ?? defaultOnDetect;\n\n // Report enforced blocks via existing connector POST /api/logs/log (WP path).\n // Needs api_key from provision / PATCHSTACK_API_KEY / .patchstackrc.json.\n // Opt out: PATCHSTACK_TELEMETRY=off. Never embed api_key in the public widget.\n const apiKey = await resolveApiKey(options);\n const firewallLog =\n apiKey && telemetryEnabled() && options.reportFirewallLog !== false\n ? createFirewallLogReporter({\n apiKey,\n apiBase: resolveApiBase(options.pulseRulesUrl ?? options.baseUrl),\n sourceHost: options.sourceHost,\n fetchImpl: options.fetchImpl,\n })\n : null;\n\n const onDetect = (detection) => {\n userOnDetect(detection);\n if (firewallLog && detection?.mode === 'block') {\n firewallLog.record({\n rule: detection.rule,\n method: detection.method,\n path: detection.path,\n ip: detection.ip,\n userAgent: detection.userAgent,\n });\n }\n };\n\n // One tiered store (memory \u2192 filesystem/pluggable) shared by the initial load and every refresh.\n const store = makeStore(options);\n // Startup must not hang on the network: hosted platforms (Replit et al.) fail a deploy whose health\n // check is slow, and the guard can always boot from last-known-good / the bundled fallback. Refreshes\n // keep the full budget. Override with { bootTimeoutMs }.\n const bootTimeoutMs = Number(options.bootTimeoutMs) > 0 ? Number(options.bootTimeoutMs) : 5_000;\n // Resolved once and threaded through ctx: reading it is a filesystem hit on\n // runtimes that have one, and refreshes should not repeat it.\n const pulseAuth = await resolvePulseAuth(options);\n const bundle = await resolveRules(options, store, { timeoutMs: bootTimeoutMs, pulseAuth });\n // Mode is mutable so a Pulse refresh can flip dry-run \u2194 block when SaaS enables production.\n // Precedence: PATCHSTACK_MODE env (local override) > API enforcement > options.mode > dry-run.\n let mode = resolveMode(options, bundle);\n // Rule-derived runtime state. Held in `let` bindings the guard methods below close over, so a\n // refresh (see the loop near the end) can hot-swap the engines by reassigning them \u2014 the\n // egress interception and the protection object itself stay in place, no re-install.\n let requestRules;\n let responseRules;\n let egressRules;\n let screenCap; // max body we'll buffer/screen (rules can raise it)\n let engine;\n let responseRuleSet;\n let egressEngine;\n\n // Split the delivered ruleset by phase (default \"request\"), merging phase defaults +\n // per-call overrides. Detection is fully rule-driven \u2014 nothing hardcoded.\n const applyBundle = (delivered) => {\n const incoming = delivered.firewall ?? [];\n requestRules = byPhase(incoming, 'request');\n responseRules = [...(options.responseRules ?? DEFAULT_RESPONSE_RULES), ...byPhase(incoming, 'response')];\n screenCap = responseScreenCap(responseRules);\n egressRules = [...(options.egressRules ?? DEFAULT_EGRESS_RULES), ...byPhase(incoming, 'egress')];\n engine = new RuleEngine({\n firewall: requestRules,\n whitelists: delivered.whitelists,\n whitelist_keys: delivered.whitelist_keys,\n onError,\n });\n // One engine per response rule so we can find ALL matches (to redact each). `action:\n // \"redact\"` masks the offending span(s); anything else withholds the whole response.\n responseRuleSet = responseRules.map((rule) => ({\n rule,\n engine: new RuleEngine({ firewall: [rule], onError }),\n redactors: rule.action === 'redact' || rule.action === 'encode' ? extractRedactors(rule) : null,\n // A redact/encode condition that carries body-transforming mutations (base64_decode, urldecode,\n // json_decode, \u2026) detects on the DECODED body but the span redactors run on the RAW body \u2014 so\n // they mask nothing and the secret is served while the log says \"redacted\". Flag it so screenText\n // fails such a rule CLOSED (block) instead of serving a no-op redaction.\n mutatedSpan: (rule.action === 'redact' || rule.action === 'encode') && hasSpanMutations(rule),\n // Optional cheap pre-filter: literal anchor(s) that MUST appear for the (expensive) regex to\n // have any chance of matching. Lets screenText skip the full scan on bodies with no candidate \u2014\n // the common case \u2014 cutting CPU/latency and shrinking the regex/ReDoS surface. Case-insensitive.\n prefilter: Array.isArray(rule.prefilter) && rule.prefilter.length\n ? rule.prefilter.map((s) => String(s).toLowerCase())\n : null,\n }));\n egressEngine = new RuleEngine({ firewall: egressRules, onError });\n };\n\n applyBundle(bundle);\n\n // Fail-open COVERAGE. The guard deliberately passes traffic through rather than risk breaking the\n // app: an oversized request body, a response past the screening cap, a live stream, a binary body, a\n // parse failure, a DNS resolver failure. Each of those is a real hole in enforcement, and until now\n // it was SILENT \u2014 \"always-on\" read as \"always inspected\". Every such bypass is now counted and\n // reported to `onSkip`, so a host can alert on it and `protection.coverage()` can be surfaced.\n // `onSkip` is a TRUSTED SERVER callback: `detail` carries operational context (sizes, statuses,\n // outbound hostnames) for logging/alerting. Do not forward it to a client response.\n const skipCounts = Object.create(null);\n const onSkip = typeof options.onSkip === 'function' ? options.onSkip : null;\n const recordSkip = (phase, reason, detail) => {\n const key = `${phase}:${reason}`;\n skipCounts[key] = (skipCounts[key] ?? 0) + 1;\n if (onSkip) {\n try {\n onSkip({ phase, reason, detail, count: skipCounts[key] });\n } catch {\n /* a reporting callback must never affect request handling */\n }\n }\n };\n\n const maskFn =\n typeof options.maskWith === 'function'\n ? options.maskWith\n : () => (typeof options.maskWith === 'string' ? options.maskWith : '[REDACTED]');\n\n // Given a request/egress result, enforce (block mode) or just record (dry-run).\n //\n // A rule may carry its own `enforcement: 'dry-run'`, which wins over block mode for that rule alone.\n // Auto-generated rules arrive that way: their coordinate comes from best-effort static analysis, so they\n // are served to detect until a probe or a human has justified them, WITHOUT holding back the\n // hand-authored rules on the same site. A rule with no `enforcement` follows the bundle exactly as\n // before, so an older server that never sends the field behaves identically.\n const ruleMode = (rule) => (rule?.enforcement === 'dry-run' ? 'dry-run' : mode);\n\n const decide = (phase, result, block, allow, ctx = {}) => {\n if (!result || !result.blocked) return allow();\n const effectiveMode = ruleMode(result.rule);\n onDetect({\n phase,\n // The mode this detection was actually handled under, not the site's: a consumer counting blocks\n // would otherwise over-report, and the whole point of a dry-run rule is that it did not block.\n mode: effectiveMode,\n category: result.rule?.category,\n rule: result.rule,\n message: result.message,\n method: ctx.method,\n path: ctx.path,\n ip: ctx.ip,\n userAgent: ctx.userAgent,\n });\n return effectiveMode === 'block' ? block() : allow();\n };\n\n // Response phase core: screen a text body \u2192 { verdict: 'pass'|'block'|'redact', body? }.\n // redact masks matched spans; block withholds; block wins over redact. Enforcement only in\n // block mode (dry-run records via onDetect but returns 'pass').\n const screenText = (text, meta, reqCtx) => {\n let blockRule = null;\n const redactions = [];\n const headerMutations = [];\n let lowerText = null; // lazily lowercased body, only if a rule uses a prefilter\n for (const { rule, engine: re, redactors, prefilter, mutatedSpan } of responseRuleSet) {\n // Cheap pre-filter: if none of the rule's literal anchors is in the body, its regex can't\n // match \u2014 skip the full scan (the common no-secret case) before touching the engine.\n if (prefilter) {\n if (lowerText === null) lowerText = text.toLowerCase();\n if (!prefilter.some((p) => lowerText.includes(p))) continue;\n }\n let result;\n try {\n // Spread the originating request (method / originalUrl / headers) alongside the response,\n // so a response rule's `when` route/method scope resolves against the REAL request and so\n // request Host/Origin are visible to response rules \u2014 rather than the phantom empty request\n // the response phase used to build (which made `when` on a response rule inert).\n result = re.evaluate({ ...(reqCtx || {}), _response: { ...meta, body: text } });\n } catch (err) {\n onError?.(err);\n continue;\n }\n if (!result.blocked) continue;\n // Per-rule enforcement applies to every phase, not just the request. A generated response rule in\n // dry-run must not redact or withhold a body either: \"detect until justified\" is meaningless if the\n // rule still rewrites what the user sees.\n const responseMode = ruleMode(rule);\n onDetect({ phase: 'response', mode: responseMode, category: rule.category, rule, message: result.message });\n if (responseMode !== 'block') continue; // dry-run: observe only\n if (redactors && redactors.length) {\n // Span redactors on a mutation-decoded rule can't map back to the raw body \u2192 fail closed.\n const spanRedactors = redactors.filter((r) => !r.jsonPath);\n if (mutatedSpan && spanRedactors.length) {\n if (!blockRule) blockRule = rule;\n } else {\n redactions.push({ rule, redactors });\n }\n } else if (isHeaderMutation(rule.action)) headerMutations.push(rule);\n else if (!blockRule) blockRule = rule;\n }\n if (mode !== 'block' || (!blockRule && !redactions.length && !headerMutations.length)) return { verdict: 'pass' };\n if (blockRule) return { verdict: 'block' };\n let body = text;\n // Redact the offending spans in the body AND in every (string) header value \u2014 so a secret\n // that leaks in a header (Set-Cookie, an echoed X-Api-Key, \u2026) is masked too, and a rule that\n // targets `response.header.*` actually strips the header rather than just detecting it.\n const headers = { ...(meta.headers || {}) };\n for (const { rule, redactors } of redactions) {\n const mask = maskFn(rule.category);\n // action `encode` HTML-escapes the matched value in place (neutralize stored XSS at output);\n // `redact` masks it. jsonPath redactors act on a structural JSON location, span redactors on\n // text spans in the body AND header values. Apply structural first (on clean JSON), then spans.\n const transform = rule.action === 'encode' ? htmlEscape : null;\n const pathRedactors = redactors.filter((r) => r.jsonPath);\n const spanRedactors = redactors.filter((r) => !r.jsonPath);\n if (pathRedactors.length) body = applyPathRedactors(body, pathRedactors, mask, screenCap, transform);\n if (!spanRedactors.length) continue;\n body = applyRedactors(body, spanRedactors, mask, transform);\n if (transform) continue; // encoding is a body/output concern \u2014 headers aren't HTML\n for (const name of Object.keys(headers)) {\n const value = headers[name];\n if (typeof value === 'string') {\n headers[name] = applyRedactors(value, spanRedactors, mask);\n } else if (Array.isArray(value)) {\n // Multi-valued headers (Set-Cookie) \u2014 redact each entry.\n headers[name] = value.map((item) => (typeof item === 'string' ? applyRedactors(item, spanRedactors, mask) : item));\n }\n }\n }\n for (const rule of headerMutations) applyHeaderMutation(headers, rule);\n return { verdict: 'redact', body, headers };\n };\n\n // Minimal request context for the response phase: what a response rule's `when` scope and any\n // request-header reference (Host/Origin) need \u2014 method, path, and request headers. No body.\n const reqContextFromFetch = (request) => {\n try {\n const u = new URL(request.url);\n const headers = headerObject(request.headers);\n // A fetch Request doesn't expose the Host header (it's set at send time), so derive it from the\n // URL \u2014 response rules that compare origins (open-redirect / CORS) need the request Host.\n if (!headers.host) headers.host = u.host;\n return { method: request.method, originalUrl: u.pathname + u.search, headers };\n } catch {\n return undefined;\n }\n };\n const reqContextFromNode = (req) => (req ? { method: req.method, originalUrl: req.url, headers: req.headers || {} } : undefined);\n\n // Screen a fetch Response (used by .fetch() and \u2014 via protection.screenResponse \u2014 the Supabase guard).\n const screenResp = async (response, reqCtx) => {\n const read = await readTextResponse(response, screenCap);\n if (read.skip) {\n // Nothing was screened \u2014 a leak/PII rule cannot have applied. Record it (a live stream and a\n // binary body are by design; a body-cap or read failure is a coverage hole worth alerting on).\n if (read.skip !== 'not-a-response') recordSkip('response', read.skip, { status: response?.status });\n return response;\n }\n const text = read.text;\n const r = screenText(text, { status: response.status, headers: headerObject(response.headers) }, reqCtx);\n if (r.verdict === 'block') return leakResponse();\n if (r.verdict === 'redact') return rebuildResponse(response, r.body, r.headers);\n return response;\n };\n\n // Wrap a Node ServerResponse so its (buffered, text) body is screened before it's sent.\n // Opt-in (buffering can delay a streamed response); over 512 KiB it stops buffering and\n // passes through unscanned.\n const wrapNodeResponse = (res, reqCtx) => {\n const origWrite = res.write.bind(res);\n const origEnd = res.end.bind(res);\n const chunks = [];\n let size = 0;\n let overflow = false;\n const MAX = screenCap;\n const collect = (chunk, enc) => {\n if (chunk == null) return;\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, typeof enc === 'string' ? enc : 'utf8');\n size += buf.length;\n if (size > MAX) {\n // Too big to screen \u2014 abandon buffering, but FLUSH what we already captured (the head) plus\n // this chunk before switching to pass-through, so the client gets a complete body (not a\n // truncated one missing everything before the cap was hit).\n for (const c of chunks) origWrite(c);\n chunks.length = 0;\n origWrite(buf);\n overflow = true;\n recordSkip('response', 'body-cap', { bytes: size });\n return;\n }\n chunks.push(buf);\n };\n res.write = function (chunk, enc, cb) {\n if (overflow) return origWrite(chunk, enc, cb);\n collect(chunk, enc);\n if (typeof enc === 'function') enc();\n else if (typeof cb === 'function') cb();\n return true;\n };\n res.end = function (chunk, enc, cb) {\n if (typeof chunk === 'function') { cb = chunk; chunk = undefined; enc = undefined; }\n else if (typeof enc === 'function') { cb = enc; enc = undefined; }\n if (overflow) { if (chunk != null) origWrite(chunk, enc); return origEnd(cb); }\n collect(chunk, enc);\n if (overflow) return origEnd(cb); // collect just flushed head + final chunk on overflow\n const buffer = Buffer.concat(chunks);\n let ct = res.getHeader ? res.getHeader('content-type') : undefined;\n if (Array.isArray(ct)) ct = ct[0];\n const kind = screenableContentType(ct);\n // Skip live streams / binary bodies (incl. an octet-stream that sniffs as binary) \u2014 untouched.\n if (kind === 'skip' || (kind === 'sniff' && looksBinary(buffer))) {\n recordSkip('response', kind === 'skip' ? (baseContentType(ct) === 'text/event-stream' ? 'live-stream' : 'non-text-content-type') : 'binary-body');\n for (const c of chunks) origWrite(c);\n return origEnd(cb);\n }\n const text = buffer.toString('utf8');\n let r;\n try {\n r = screenText(text, { status: res.statusCode, headers: res.getHeaders ? res.getHeaders() : {} }, reqCtx);\n } catch (err) {\n onError?.(err);\n for (const c of chunks) origWrite(c);\n return origEnd(cb);\n }\n if (r.verdict === 'block') {\n res.statusCode = 500;\n try { res.setHeader('content-type', 'application/json'); } catch { /* headers sent */ }\n return origEnd(JSON.stringify({ error: 'Response withheld by Patchstack (sensitive data detected)' }), cb);\n }\n if (r.verdict === 'redact') {\n try { res.removeHeader && res.removeHeader('content-length'); } catch { /* ignore */ }\n if (r.headers && res.setHeader) {\n const current = res.getHeaders ? res.getHeaders() : {};\n for (const [name, value] of Object.entries(r.headers)) {\n // content-length was just removed (the redacted body has a new length); never re-set a\n // stale one here or the response truncates/hangs.\n if (name.toLowerCase() === 'content-length') continue;\n if (value === null || value === undefined) {\n try { res.removeHeader && res.removeHeader(name); } catch { /* ignore */ } // header-mutation removal\n } else if (Array.isArray(value)) {\n try { res.setHeader(name, value); } catch { /* ignore invalid header */ } // Set-Cookie array\n } else if (typeof value === 'string' && current[name] !== value) {\n try { res.setHeader(name, value); } catch { /* ignore invalid header */ }\n }\n }\n }\n return origEnd(r.body, cb);\n }\n for (const c of chunks) origWrite(c);\n return origEnd(cb);\n };\n };\n\n // Egress phase: is this outbound call blocked? (records detection either way)\n const allow = new Set((options.allowHosts ?? []).map((h) => String(h).toLowerCase()));\n const egressShouldBlock = (url, host, method) => {\n if (host && allow.has(host.toLowerCase())) return false;\n let result;\n try {\n result = egressEngine.evaluate({ _egress: { url, host, method } });\n } catch (err) {\n onError?.(err);\n return false;\n }\n if (!result.blocked) return false;\n // Same for egress: a dry-run rule records the outbound attempt without preventing it. Blocking a\n // request the app makes is at least as disruptive as blocking one it receives.\n const egressMode = ruleMode(result.rule);\n onDetect({ phase: 'egress', mode: egressMode, category: result.rule?.category, rule: result.rule, message: result.message });\n return egressMode === 'block';\n };\n\n const protection = {\n get mode() {\n return mode;\n },\n get rules() {\n return { request: requestRules, response: responseRules, egress: egressRules };\n },\n\n /**\n * Enforcement coverage: how often the guard FAILED OPEN rather than inspecting, keyed\n * `<phase>:<reason>` (e.g. `response:body-cap`, `request:body-cap`, `response:live-stream`,\n * `egress:resolver-failed`). \"Always-on\" is not \"always inspected\" \u2014 surface this (or pass\n * `onSkip`) so an unscreened path is visible and alertable rather than silent.\n */\n coverage() {\n return { skipped: { ...skipCounts } };\n },\n\n // Screen a fetch Response through the response-phase rules (redact/block). Used by\n // .fetch(), and by the Supabase guard on its forwarded upstream response.\n screenResponse: (response, request) => screenResp(response, request ? reqContextFromFetch(request) : undefined),\n\n // (request) => Response | null (null = allow, caller proceeds). Request phase only.\n fetchGuard() {\n return async (request) => {\n let result;\n try {\n result = engine.evaluate(await fromFetchRequest(request));\n } catch (err) {\n onError?.(err);\n return null; // fail open\n }\n return decide('request', result, () => blockResponse(result, request), () => null, fetchRequestMeta(request));\n };\n },\n\n // Wrap a fetch handler: screens the request, then the response (redact/block).\n fetch(handler) {\n const guard = protection.fetchGuard();\n return async (request, ...rest) => {\n const blocked = await guard(request);\n if (blocked) return blocked;\n const response = await handler(request, ...rest);\n return screenResp(response, reqContextFromFetch(request));\n };\n },\n\n // Express middleware (request phase; expects express-parsed req.query/req.body).\n // Pass { screenResponses: true } to also screen the outgoing response (buffers it).\n express(exprOptions = {}) {\n return (req, res, next) => {\n let result;\n try {\n result = engine.evaluate(req);\n } catch (err) {\n onError?.(err);\n if (exprOptions.screenResponses) wrapNodeResponse(res, reqContextFromNode(req));\n return next();\n }\n decide(\n 'request',\n result,\n () => {\n if (isDocumentNavigation((n) => req.headers?.[n])) {\n res.status(403).type('html').send(renderBlockPage({ url: req.originalUrl || req.url || '/', code: result?.rule?.id }));\n } else {\n res.status(403).json(blockBody(result));\n }\n },\n () => {\n if (exprOptions.screenResponses) wrapNodeResponse(res, reqContextFromNode(req));\n next();\n },\n nodeRequestMeta(req),\n );\n };\n },\n\n // Node / Connect middleware \u2014 buffers the body itself (request phase).\n // Pass { screenResponses: true } to also screen the outgoing response (buffers it).\n node(nodeOptions = {}) {\n const maxBytes = nodeOptions.maxBodyBytes ?? 1024 * 1024;\n return (req, res, next) => {\n const chunks = [];\n let size = 0;\n let overflow = false;\n req.on('data', (chunk) => {\n size += chunk.length;\n if (size > maxBytes) {\n overflow = true;\n return;\n }\n chunks.push(chunk);\n });\n req.on('error', (err) => {\n onError?.(err);\n next();\n });\n req.on('end', () => {\n if (overflow) recordSkip('request', 'body-cap', { bytes: size, limit: maxBytes });\n const rawBody = overflow ? '' : Buffer.concat(chunks).toString('utf8');\n let shaped;\n let result;\n try {\n shaped = fromNodeRequest(req, rawBody);\n result = engine.evaluate(shaped);\n } catch (err) {\n onError?.(err);\n return next();\n }\n decide(\n 'request',\n result,\n () => {\n res.statusCode = 403;\n if (isDocumentNavigation((n) => req.headers?.[n])) {\n res.setHeader('content-type', 'text/html; charset=utf-8');\n res.end(renderBlockPage({ url: req.url || '/', code: result?.rule?.id }));\n } else {\n res.setHeader('content-type', 'application/json');\n res.end(JSON.stringify(blockBody(result)));\n }\n },\n () => {\n // This guard consumed the request stream to screen it; re-expose the parsed\n // body so a downstream handler (without its own body-parser) can read it.\n if (req.body === undefined) req.body = shaped.body;\n if (nodeOptions.screenResponses) wrapNodeResponse(res, reqContextFromNode(req));\n next();\n },\n nodeRequestMeta(req),\n );\n });\n };\n },\n };\n\n // Egress interception is opt-in (it wraps the global fetch, and node:http/https on Node).\n if (options.egress) {\n protection.uninstallEgress = await installEgressGuard({\n shouldBlock: egressShouldBlock,\n onBlock: options.onEgressBlock,\n // Route egress coverage gaps (a DNS resolver failure / no resolver on this runtime) into the\n // same skip accounting as the request/response phases.\n onSkip: ({ reason, detail }) => recordSkip('egress', reason, detail),\n dnsScreen: options.screenDns !== false,\n allowHosts: options.allowHosts,\n });\n }\n\n // Live rule refresh. The guard otherwise reads its rules once, at process start \u2014 so a rule that\n // only becomes relevant after boot (a dependency added mid-session and flagged by Pulse, a\n // zero-day published) never applies until the process restarts. A refresh re-fetches and\n // hot-swaps the engines in place; the same tick can be driven by a poll loop (`refreshMs`), a\n // manual `protection.refresh()`, or an authenticated push (`protection.refreshHandler()`).\n const cwd = options.cwd ?? (typeof process !== 'undefined' ? process.cwd() : undefined);\n const live = Boolean(options.siteUuid || options.token);\n const refreshSecret = options.refreshSecret ?? (typeof process !== 'undefined' ? process.env.PATCHSTACK_REFRESH_SECRET : undefined);\n const refreshable = live && (options.refreshMs > 0 || Boolean(refreshSecret));\n\n // On the Pulse (siteUuid) path, re-post the dependency manifest before re-fetching. A targeted\n // `npm install <pkg>` fires no npm lifecycle hook, so nothing else re-scans; reporting here lets\n // the server flag a newly-added vulnerable dependency and the SAME tick's rule fetch pick up its\n // rule. Loaded once, up front, only when a refresh path is enabled \u2014 a refresh-off production\n // guard never pulls in the scan pipeline; a load/report failure never blocks the rule refresh.\n let reporter = null;\n if (refreshable && options.siteUuid && options.reportManifest !== false && cwd) {\n try {\n ({ reportManifest: reporter } = await import('./refresh-manifest.js'));\n } catch (err) {\n onError?.(err); // scan pipeline unavailable (e.g. an edge runtime) \u2014 rules still refresh\n }\n }\n\n const runRefreshTick = async () => {\n if (reporter) {\n try {\n await reporter(cwd);\n } catch (err) {\n onError?.(err); // a failed report must not stop the rule refresh\n }\n }\n const next = await resolveRules(options, store, { timeoutMs: options.refreshTimeoutMs, pulseAuth });\n mode = resolveMode(options, next);\n applyBundle(next);\n };\n\n if (live) {\n // Manual one-shot refresh (also the primitive the loop + push endpoint run).\n protection.refresh = () => runRefreshTick();\n // Authenticated push endpoint \u2014 the platform/SaaS hits it for an immediate refresh. No secret\n // configured \u2192 the handler 404s (never an open refresh trigger).\n protection.refreshHandler = () => makeRefreshHandler(runRefreshTick, refreshSecret);\n }\n\n if (options.refreshMs > 0 && live) {\n const loop = startRefresh(runRefreshTick, { refreshMs: options.refreshMs, onError });\n protection.stopRefresh = () => {\n loop.stop();\n firewallLog?.stop();\n };\n } else if (firewallLog) {\n protection.stopRefresh = () => firewallLog.stop();\n }\n\n return protection;\n}\n\n/**\n * Resolve runtime enforcement mode.\n * Precedence: PATCHSTACK_MODE env > Pulse `enforcement` on the rules bundle > options.mode > dry-run.\n */\nfunction resolveMode(options, bundle) {\n const env = typeof process !== 'undefined' ? process.env?.PATCHSTACK_MODE : undefined;\n if (env === 'block' || env === 'dry-run') return env;\n if (bundle?.enforcement === 'block' || bundle?.enforcement === 'dry-run') return bundle.enforcement;\n if (options?.mode === 'block') return 'block';\n if (options?.mode === 'dry-run') return 'dry-run';\n return 'dry-run';\n}\n\n/**\n * WP-format api_key for connector /api/logs/log. Never use the public site UUID.\n * The `.patchstackrc.json` fallback reads the filesystem, so fs/path are imported LAZILY \u2014 this\n * module must stay loadable on edge runtimes (Next edge middleware, Workers, Deno, Supabase\n * Functions), where a static `node:fs` import fails to resolve and would take the guard down.\n */\nasync function resolveApiKey(options) {\n if (typeof options?.apiKey === 'string' && options.apiKey.length > 0) return options.apiKey;\n if (typeof process !== 'undefined') {\n const fromEnv = process.env?.PATCHSTACK_API_KEY;\n if (typeof fromEnv === 'string' && fromEnv.length > 0) return fromEnv;\n }\n try {\n if (typeof process === 'undefined' || typeof process.cwd !== 'function') return undefined;\n const [{ readFileSync }, { join }] = await Promise.all([import('node:fs'), import('node:path')]);\n const cwd = options?.cwd ?? process.cwd();\n const raw = readFileSync(join(cwd, '.patchstackrc.json'), 'utf8');\n const key = JSON.parse(raw)?.apiKey;\n if (typeof key === 'string' && key.length > 0) return key;\n } catch {\n /* missing, or no filesystem on this runtime \u2014 reporting stays off */\n }\n return undefined;\n}\n\n/**\n * Credential for the authenticated rules lookup (ADR-0018). Same resolution\n * order and the same edge-runtime caution as resolveApiKey, and falls back to\n * it so guards installed before pulseAuth existed keep authenticating.\n *\n * Returning undefined is fine: the rules fetch then goes out unauthenticated,\n * which the server still accepts.\n */\nasync function resolvePulseAuth(options) {\n if (typeof options?.pulseAuth === 'string' && options.pulseAuth.length > 0) return options.pulseAuth;\n if (typeof process !== 'undefined') {\n const fromEnv = process.env?.PATCHSTACK_PULSE_AUTH;\n if (typeof fromEnv === 'string' && fromEnv.length > 0) return fromEnv;\n }\n try {\n if (typeof process === 'undefined' || typeof process.cwd !== 'function') return resolveApiKey(options);\n const [{ readFileSync }, { join }] = await Promise.all([import('node:fs'), import('node:path')]);\n const cwd = options?.cwd ?? process.cwd();\n const raw = readFileSync(join(cwd, '.patchstackrc.json'), 'utf8');\n const key = JSON.parse(raw)?.pulseAuth;\n if (typeof key === 'string' && key.length > 0) return key;\n } catch {\n /* missing, or no filesystem here \u2014 fall through to the apiKey path */\n }\n\n return resolveApiKey(options);\n}\n\n// --- phase / response helpers -------------------------------------------\n\nfunction byPhase(rules, phase) {\n return (rules ?? []).filter((r) => (r.phase ?? 'request') === phase);\n}\n\n// Classify a content-type for response screening: 'text' = screen; 'sniff' = screen only if the\n// bytes aren't binary (octet-stream is often a misdeclared JSON export/config); 'skip' = pass\n// through unscreened (live streams, known binary families). SSE is matched on the EXACT base type,\n// not a loose substring \u2014 `application/json; profile=\"event-stream\"` is not a stream.\nfunction baseContentType(ct) {\n return String(ct || '').toLowerCase().split(';')[0].trim();\n}\nfunction screenableContentType(ct) {\n const base = baseContentType(ct);\n if (base === 'text/event-stream') return 'skip'; // live token/SSE stream \u2014 never buffer\n if (base === '') return 'text';\n if (/(json|text|xml|html|javascript|csv|yaml|x-www-form-urlencoded)/.test(base)) return 'text';\n if (base === 'application/octet-stream') return 'sniff'; // maybe a text/JSON export mislabeled\n return 'skip'; // image/video/audio/font/pdf/zip/wasm/\u2026 \u2014 don't buffer binary\n}\n// Cheap binary sniff over a byte prefix: a NUL byte, or many control chars, means \"don't treat as text\".\nfunction looksBinary(bytes) {\n const n = Math.min(bytes.length, 512);\n let ctrl = 0;\n for (let i = 0; i < n; i++) {\n const b = bytes[i];\n if (b === 0) return true;\n if (b < 9 || (b > 13 && b < 32)) ctrl++;\n }\n return n > 0 && ctrl / n > 0.1;\n}\n\n// Returns { text } when the body was fully buffered for screening, or { skip: <reason> } when it was\n// NOT screened \u2014 the reason is surfaced to `onSkip`/coverage so a fail-open bypass is observable\n// instead of silent (an unscreened response is a real hole in enforcement).\nasync function readTextResponse(response, cap = DEFAULT_SCREEN_CAP) {\n if (!response || typeof response.clone !== 'function') return { skip: 'not-a-response' };\n const ct = response.headers?.get?.('content-type') || '';\n const kind = screenableContentType(ct);\n if (kind === 'skip') return { skip: baseContentType(ct) === 'text/event-stream' ? 'live-stream' : 'non-text-content-type' };\n const sniff = kind === 'sniff';\n const len = Number(response.headers?.get?.('content-length') || 0);\n if (len && len > cap) return { skip: 'body-cap' };\n let clone;\n try {\n clone = response.clone();\n } catch {\n return { skip: 'clone-failed' };\n }\n\n // Stream the read so a body WITHOUT a Content-Length can't buffer past the cap. Over the cap the\n // response is left UNSCREENED \u2014 but we keep draining the clone so the original stays intact.\n const body = clone.body;\n if (body && typeof body.getReader === 'function') {\n const reader = body.getReader();\n const chunks = [];\n let size = 0;\n let over = false;\n let sniffed = !sniff;\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!value) continue;\n if (!sniffed) {\n sniffed = true;\n if (looksBinary(value)) return { skip: 'binary-body' };\n }\n size += value.byteLength;\n if (over) continue; // keep draining, stop buffering\n if (size > cap) { over = true; continue; }\n chunks.push(value);\n }\n } catch {\n return { skip: 'read-failed' };\n }\n if (over) return { skip: 'body-cap' };\n try {\n return { text: new TextDecoder().decode(concatBytes(chunks, size)) };\n } catch {\n return { skip: 'decode-failed' };\n }\n }\n\n try {\n const text = await clone.text();\n if (text.length > cap) return { skip: 'body-cap' };\n if (sniff && looksBinary(new TextEncoder().encode(text.slice(0, 512)))) return { skip: 'binary-body' };\n return { text };\n } catch {\n return { skip: 'read-failed' };\n }\n}\n\nfunction concatBytes(chunks, total) {\n const out = new Uint8Array(total);\n let offset = 0;\n for (const c of chunks) {\n out.set(c, offset);\n offset += c.byteLength;\n }\n return out;\n}\n\nfunction headerObject(headers) {\n const out = {};\n headers?.forEach?.((v, k) => { out[k.toLowerCase()] = v; });\n // Set-Cookie is multi-valued; forEach collapses it. Recover the individual cookies so each can\n // be screened (and re-emitted) separately.\n const setCookies = headers?.getSetCookie?.();\n if (setCookies && setCookies.length) out['set-cookie'] = setCookies;\n return out;\n}\n\n// True if any of the rule's conditions carries a body-transforming mutation on a SPAN match\n// (regex/contains/stripos) \u2014 those decode the body before matching, so a span redactor derived from\n// the literal/regex can't be located in the raw body. (array_key_value structural redaction decodes\n// the JSON itself, so json_decode there is fine and doesn't count.)\nfunction hasSpanMutations(rule) {\n let found = false;\n const walk = (conds) => {\n for (const c of conds ?? []) {\n if (found) return;\n if (Array.isArray(c.rules)) walk(c.rules);\n const isSpan = c.match && (c.match.type === 'regex' || c.match.type === 'contains' || c.match.type === 'stripos');\n if (isSpan && Array.isArray(c.mutations) && c.mutations.length) found = true;\n }\n };\n walk(rule.rule_v2);\n return found;\n}\n\n// Derive redaction targets from a rule's own conditions: regex \u2192 mask every match;\n// contains/stripos \u2192 mask the literal. (Other match types can't identify a span \u2192 the\n// rule falls back to block.)\nfunction extractRedactors(rule) {\n const out = [];\n const walk = (conds) => {\n for (const c of conds ?? []) {\n if (Array.isArray(c.rules)) walk(c.rules);\n const m = c.match;\n if (!m) continue;\n if (m.type === 'regex' && typeof m.value === 'string') {\n // Route through the SAME ReDoS guard detection uses \u2014 a catastrophic redactor pattern must\n // not hang the response path (safeRegExp returns null for dangerous/invalid patterns \u2192 skip).\n const safe = safeRegExp(m.value);\n if (safe) {\n const flags = safe.flags.includes('g') ? safe.flags : safe.flags + 'g';\n try {\n out.push({ re: new RegExp(safe.source, flags) });\n } catch {\n /* skip invalid */\n }\n }\n } else if ((m.type === 'contains' || m.type === 'stripos') && m.value != null) {\n out.push({ literal: String(m.value) });\n } else if (m.type === 'array_key_value' && m.match && isBodyParam(c.parameter)) {\n // Structural redaction: mask the value at a JSON path (fanning out over arrays) rather than\n // a text span \u2014 e.g. key \"orders.customers.email\" masks that field in every array element.\n const keys = Array.isArray(m.key) ? m.key : [m.key];\n for (const key of keys) {\n out.push({ jsonPath: String(key).split('.'), condition: m.match });\n }\n }\n }\n };\n walk(rule.rule_v2);\n return out;\n}\n\n// HTML-entity escape, for the `encode` action (neutralize markup rather than mask it). NOTE: this is\n// sound only for HTML text / attribute-VALUE contexts. It does NOT neutralize a `javascript:` / `data:`\n// URI or an event-handler name (those carry no HTML metacharacters) \u2014 use `block` for a rule that\n// targets a URL/scheme context. See the rule-authoring guidance in the triage-vpatch-npm skill.\nfunction htmlEscape(str) {\n return String(str).replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[c]);\n}\n\n// `transform` (optional): map a matched span to its replacement (the `encode` action passes\n// htmlEscape). Without it, matches are replaced by the `mask` string (the `redact` action).\nfunction applyRedactors(body, redactors, mask, transform) {\n let out = body;\n for (const r of redactors) {\n if (r.re) out = out.replace(r.re, transform ? (m) => transform(m) : mask);\n else if (r.literal) {\n // Detection (matchValue for contains/stripos) is case-insensitive, so mask case-insensitively\n // too \u2014 otherwise a `contains: \"SECRET\"` redactor detects `secret` but masks nothing, serving\n // the leak while reporting a redaction. Escape the literal so it matches literally, not as regex.\n const re = new RegExp(r.literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'gi');\n out = out.replace(re, (m) => (transform ? transform(m) : mask));\n }\n }\n return out;\n}\n\n// A response-body redaction target (array_key_value masks the JSON body). A bare condition with no\n// parameter also defaults to the body.\nfunction isBodyParam(parameter) {\n return parameter == null || parameter === 'response.body' || parameter === 'raw' || parameter === 'response.raw';\n}\n\n// Build a predicate from the array_key_value nested match, so a path can be masked conditionally\n// (only leaves that match) or \u2014 with `isset` \u2014 unconditionally. Fail-closed (don't mask) on error.\nfunction conditionPredicate(condition) {\n if (!condition || !condition.type) return () => true;\n return (value) => {\n try {\n return matchValue(condition.type, value, condition.value, condition);\n } catch {\n return false;\n }\n };\n}\n\nconst DEFAULT_SCREEN_CAP = 512 * 1024;\n\n// Effective response-screening size cap for a rule set. Bodies larger than this are passed through\n// UNSCREENED (so a redact rule can't mask them \u2014 the leak/PII would slip out). A rule can raise the\n// ceiling for the whole response phase: `bypass_limit: true` removes the cap entirely (accepts the\n// memory cost on a hostile large body), or `max_bytes: <n>` raises it to n. The cap is shared (the\n// body is buffered once), so the effective cap is the MAX across all active response rules.\nfunction responseScreenCap(rules) {\n let cap = DEFAULT_SCREEN_CAP;\n for (const r of rules ?? []) {\n if (r && r.bypass_limit === true) return Infinity;\n const n = Number(r && r.max_bytes);\n if (Number.isFinite(n) && n > cap) cap = n;\n }\n return cap;\n}\n\n// Apply jsonPath redactors structurally: parse the JSON body, mask each targeted leaf (fanning out\n// over arrays at every path segment), re-serialize. Fail-open \u2014 a non-JSON / oversized / unparseable\n// body is returned unchanged, and any per-leaf error is swallowed.\nfunction applyPathRedactors(text, pathRedactors, mask, cap, transform) {\n if (!pathRedactors.length || typeof text !== 'string' || text.length > cap) return text;\n const head = text.trimStart()[0];\n if (head !== '{' && head !== '[') return text; // not a JSON object/array\n // Preserve out-of-safe-range integers across the parse\u2192stringify round-trip: JSON.parse would\n // round e.g. a 20-digit id. We quote such number tokens to a sentinel string before parsing and\n // unquote them after stringifying, so untouched big ints survive losslessly.\n const preserved = preserveBigInts(text);\n let obj;\n try {\n obj = JSON.parse(preserved);\n } catch {\n return text;\n }\n let changed = false;\n for (const r of pathRedactors) {\n const pred = conditionPredicate(r.condition);\n walkLeaves(obj, r.jsonPath, (loc) => {\n try {\n if (pred(loc.value)) {\n // `encode`: escape the leaf's own value in place; `redact`: replace it with the mask.\n loc.parent[loc.key] = transform ? transform(String(loc.value)) : mask;\n changed = true;\n }\n } catch {\n /* skip this leaf */\n }\n });\n }\n return changed ? restoreBigInts(JSON.stringify(obj)) : text;\n}\n\nconst BIGINT_OPEN = '__PSBIGINT_9c2f__';\nconst BIGINT_CLOSE = '__DNEGIB__';\n\n// Quote every out-of-safe-range integer *value* (a bare number token outside a string) into a\n// sentinel string, so JSON.parse keeps it verbatim. String-aware scan (respects \\ escapes) so a\n// number inside a string value is never touched. Plain-ASCII sentinel \u2192 survives JSON.stringify.\nfunction preserveBigInts(text) {\n let out = '';\n let inStr = false;\n for (let i = 0; i < text.length; ) {\n const ch = text[i];\n if (inStr) {\n out += ch;\n if (ch === '\\\\') { out += text[i + 1] ?? ''; i += 2; continue; }\n if (ch === '\"') inStr = false;\n i++;\n continue;\n }\n if (ch === '\"') { inStr = true; out += ch; i++; continue; }\n if (ch === '-' || (ch >= '0' && ch <= '9')) {\n let j = ch === '-' ? i + 1 : i;\n let digits = 0;\n while (j < text.length && text[j] >= '0' && text[j] <= '9') { digits++; j++; }\n const next = text[j];\n const isIntToken = digits > 0 && next !== '.' && next !== 'e' && next !== 'E';\n if (isIntToken && digits >= 16) {\n out += `\"${BIGINT_OPEN}${text.slice(i, j)}${BIGINT_CLOSE}\"`;\n } else {\n out += text.slice(i, j || i + 1);\n }\n i = j > i ? j : i + 1;\n continue;\n }\n out += ch;\n i++;\n }\n return out;\n}\n\nfunction restoreBigInts(text) {\n if (!text.includes(BIGINT_OPEN)) return text;\n return text.replace(new RegExp(`\"${BIGINT_OPEN}(-?\\\\d+)${BIGINT_CLOSE}\"`, 'g'), '$1');\n}\n\n// Response-hardening actions. Mutate the (lowercase-keyed) headers object in place; a `null` value\n// signals removal to rebuildResponse / the node path. `set-header` sets/overwrites (or `ensure`s only\n// when absent); `remove-header` strips; `harden-cookie` adds missing HttpOnly/Secure/SameSite flags.\nfunction isHeaderMutation(action) {\n return action === 'set-header' || action === 'remove-header' || action === 'harden-cookie';\n}\n\nfunction applyHeaderMutation(headers, rule) {\n if (rule.action === 'remove-header') {\n for (const name of rule.remove_headers ?? []) headers[String(name).toLowerCase()] = null;\n return;\n }\n if (rule.action === 'set-header') {\n const ensure = rule.ensure === true; // set only when the header is absent (don't clobber)\n for (const [name, value] of Object.entries(rule.set_headers ?? {})) {\n const key = String(name).toLowerCase();\n const present = headers[key] != null && headers[key] !== '';\n if (ensure && present) continue;\n headers[key] = String(value);\n }\n return;\n }\n if (rule.action === 'harden-cookie') {\n const cookie = headers['set-cookie'];\n const flags = rule.cookie_flags ?? {};\n if (Array.isArray(cookie)) {\n headers['set-cookie'] = cookie.map((c) => (typeof c === 'string' ? hardenCookie(c, flags) : c));\n } else if (typeof cookie === 'string') {\n headers['set-cookie'] = hardenCookie(cookie, flags);\n }\n }\n}\n\nfunction hardenCookie(cookie, { httpOnly = true, secure = true, sameSite = 'Lax' } = {}) {\n let out = String(cookie);\n if (httpOnly && !/;\\s*httponly/i.test(out)) out += '; HttpOnly';\n if (secure && !/;\\s*secure/i.test(out)) out += '; Secure';\n if (sameSite && !/;\\s*samesite\\s*=/i.test(out)) out += `; SameSite=${sameSite}`;\n return out;\n}\n\nfunction rebuildResponse(response, body, redactedHeaders) {\n const headers = new Headers(response.headers);\n headers.delete('content-length'); // body length changed after redaction\n if (redactedHeaders) {\n for (const [name, value] of Object.entries(redactedHeaders)) {\n if (value === null || value === undefined) {\n try { headers.delete(name); } catch { /* skip */ } // header-mutation removal\n } else if (typeof value === 'string') {\n if (headers.get(name) !== value) {\n try { headers.set(name, value); } catch { /* invalid header name \u2014 skip */ }\n }\n } else if (Array.isArray(value)) {\n // Re-emit each (possibly redacted) Set-Cookie separately (Headers collapses them otherwise).\n try {\n headers.delete(name);\n for (const item of value) headers.append(name, String(item));\n } catch { /* skip */ }\n }\n }\n }\n // Null-body statuses (204/205/304/101) must not carry a body, or the Response constructor throws.\n const nullBody = response.status === 101 || response.status === 204 || response.status === 205 || response.status === 304;\n return new Response(nullBody ? null : body, { status: response.status, statusText: response.statusText, headers });\n}\n\nfunction leakResponse() {\n return new Response(JSON.stringify({ error: 'Response withheld by Patchstack (sensitive data detected)' }), {\n status: 500,\n headers: { 'content-type': 'application/json' }\n });\n}\n\n// (rule source / tiered store moved to ./rules/source.js + ./rules/store.js)\n\n// --- responses ----------------------------------------------------------\n\n// Client-facing block text \u2014 deliberately generic: no WAF narrative, no rule title. The reason\n// detail stays in the server-side log via onDetect.\nconst BLOCK_MESSAGE = 'This request has been blocked by Patchstack.';\n\nfunction blockBody(result) {\n // Human text is masked (no WAF narrative, no rule title). The opaque rule id stays for machine\n // consumers (server-fn receipts, support reference); full rule detail lives in the server log.\n return { error: BLOCK_MESSAGE, message: BLOCK_MESSAGE, rule: result?.rule?.id };\n}\n\n// A top-level document navigation (vs an XHR/fetch)? Browsers set Sec-Fetch-Dest on navigations;\n// fall back to the Accept header. Governs whether a block returns the HTML page or JSON.\nfunction isDocumentNavigation(getHeader) {\n const dest = getHeader('sec-fetch-dest');\n if (dest) return dest === 'document';\n return (getHeader('accept') || '').includes('text/html');\n}\n\n// Request-phase block. Serves the branded HTML \"Access Denied\" page to a browser navigation, and\n// masked JSON to XHR/fetch/programmatic clients.\nfunction blockResponse(result, request) {\n if (request && isDocumentNavigation((n) => request.headers.get(n))) {\n return new Response(renderBlockPage({ url: request.url, code: result?.rule?.id }), {\n status: 403,\n headers: { 'content-type': 'text/html; charset=utf-8' },\n });\n }\n return new Response(JSON.stringify(blockBody(result)), {\n status: 403,\n headers: { 'content-type': 'application/json' },\n });\n}\n\nfunction defaultOnDetect({ phase, mode, category, rule, message }) {\n const tag = mode === 'block' ? 'BLOCK' : 'DETECT (dry-run)';\n console.warn(`[patchstack] ${tag} phase=${phase ?? 'request'} category=${category ?? '?'} rule=${rule?.id ?? '?'} ${message ?? ''}`.trim());\n}\n\n/** @param {Request} request */\nfunction fetchRequestMeta(request) {\n if (!request) return {};\n let path = null;\n try {\n path = new URL(request.url).pathname;\n } catch {\n path = typeof request.url === 'string' ? request.url : null;\n }\n return {\n method: request.method ?? null,\n path,\n ip: request.headers?.get?.('x-forwarded-for') ?? null,\n userAgent: request.headers?.get?.('user-agent') ?? null,\n };\n}\n\n/** @param {import('http').IncomingMessage & { ip?: string, originalUrl?: string }} req */\nfunction nodeRequestMeta(req) {\n if (!req) return {};\n const headers = req.headers ?? {};\n const ua = headers['user-agent'] ?? headers['User-Agent'];\n const fwd = headers['x-forwarded-for'] ?? headers['X-Forwarded-For'];\n return {\n method: req.method ?? null,\n path: req.originalUrl || req.url || null,\n ip: req.ip ?? (typeof fwd === 'string' ? fwd : null),\n userAgent: typeof ua === 'string' ? ua : Array.isArray(ua) ? ua[0] : null,\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["warnOnce", "DEFAULT_BASE_URL", "DEFAULT_CACHE_TTL", "JITTER_FRACTION", "parseCookies", "JITTER_FRACTION", "TOKEN_SKEW_MS", "allow"]
7
+ }