@znight/http 0.1.1 → 0.1.3

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.
Files changed (47) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +83 -32
  3. package/dist/{adapter-CGSceVEN.d.mts → adapter-J0UXFnNM.d.mts} +7 -1
  4. package/dist/compiler.d.mts +1 -1
  5. package/dist/compiler.mjs +82 -13
  6. package/dist/compiler.mjs.map +1 -1
  7. package/dist/express.d.mts +1 -1
  8. package/dist/express.mjs +3 -2
  9. package/dist/express.mjs.map +1 -1
  10. package/dist/fastify.d.mts +1 -1
  11. package/dist/fastify.mjs +254 -42
  12. package/dist/fastify.mjs.map +1 -1
  13. package/dist/hono.d.mts +1 -1
  14. package/dist/hono.mjs +272 -67
  15. package/dist/hono.mjs.map +1 -1
  16. package/dist/index.d.mts +10 -2
  17. package/dist/index.mjs +930 -278
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/{node-BUnkdSsa.mjs → node-DnYv_AMI.mjs} +4 -3
  20. package/dist/{node-BUnkdSsa.mjs.map → node-DnYv_AMI.mjs.map} +1 -1
  21. package/dist/{node-io-BY1ZDLRQ.mjs → node-io-BkdRSQeg.mjs} +151 -86
  22. package/dist/{node-io-BY1ZDLRQ.mjs.map → node-io-BkdRSQeg.mjs.map} +1 -1
  23. package/dist/node.d.mts +1 -1
  24. package/dist/node.mjs +1 -1
  25. package/dist/utils-DIWdzVht.mjs +46 -0
  26. package/dist/utils-DIWdzVht.mjs.map +1 -0
  27. package/package.json +4 -4
  28. package/src/adapter.ts +6 -0
  29. package/src/adapters/express.ts +4 -1
  30. package/src/adapters/fastify.ts +329 -44
  31. package/src/adapters/hono.ts +341 -86
  32. package/src/adapters/node-io.ts +185 -82
  33. package/src/adapters/node.ts +4 -1
  34. package/src/body.ts +31 -2
  35. package/src/coerce.ts +31 -0
  36. package/src/compiler/generate.ts +127 -22
  37. package/src/context.ts +151 -78
  38. package/src/index.ts +1 -1
  39. package/src/pipeline.ts +809 -208
  40. package/src/plugin.ts +10 -4
  41. package/src/query.ts +7 -1
  42. package/src/response.ts +6 -8
  43. package/src/serialize.ts +83 -16
  44. package/src/utils.ts +25 -2
  45. package/src/validate.ts +28 -12
  46. package/dist/utils-DCbu3a4w.mjs +0 -27
  47. package/dist/utils-DCbu3a4w.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["Buffer","DECODER","malformed","truncate","invalid","describe","NO_FILES","NO_COOKIES","ENCODER","crypto","KEYS","describe","describe","describe","ENCODER","parseRange","resolve"],"sources":["../src/multipart.ts","../src/query.ts","../src/body.ts","../src/coerce.ts","../src/cookie-settings.ts","../src/context.ts","../src/decorators.ts","../src/event-channel.ts","../src/files.ts","../src/cookie-signer.ts","../src/headers.ts","../src/option-error.ts","../src/cors.ts","../src/decisions.ts","../src/sse-parse.ts","../src/inject-sse.ts","../src/sse.ts","../src/response.ts","../src/serialize.ts","../src/tokens.ts","../src/pipeline.ts","../src/plugin-routes.ts","../src/proxy.ts","../src/security-headers.ts","../src/uploads.ts","../src/plugin.ts","../src/standard-schema.ts","../src/validate.ts"],"sourcesContent":["/**\n * Streaming `multipart/form-data` parser (RFC 7578, RFC 2046), shared by every adapter so that\n * uploads behave the same on Node.js and Bun.\n *\n * The Web-standard `Request.formData()` is not used: it buffers the whole body before parsing, has\n * no per-part limits, and its results differ between runtimes (default part type, `filename*`,\n * escaped quotes, LF line endings, parts without name). This parser reads the body as it arrives\n * and enforces the upload rules of the route (expected fields, file count, size and media type) on\n * the fly, so an invalid upload is rejected as soon as the offending part shows up. Files are\n * buffered in memory as standard `File` objects, within the limits.\n *\n * Status codes: malformed bodies, unexpected file fields and several files for a single-file field\n * → 400; a file, a field, too many files or too many parts → 413; a refused media type → 415. Errors\n * raised while the body is being read carry `connection: close` (the rest of the body is discarded).\n */\nimport type { HttpExceptionOptions } from './exceptions.ts'\nimport type { QueryRecord } from './query.ts'\n\nimport { Buffer } from 'node:buffer'\n\nimport { BadRequestException, issue, PayloadTooLargeException, UnsupportedMediaTypeException } from './exceptions.ts'\nimport { matchesMediaType, mediaTypeEssence, OCTET_STREAM } from './mime.ts'\nimport { formatByteSize } from './size.ts'\nimport { emptyRecord } from './utils.ts'\n\n/** Constraints of the files received by one upload parameter (`@UploadedFile` / `@UploadedFiles`). */\nexport interface FileRule {\n /** Field name; `undefined`: the files of every field. */\n readonly field: string | undefined\n /** `@UploadedFiles` (an array) rather than `@UploadedFile` (a single file). */\n readonly multiple: boolean\n /** Maximum size of each file, in bytes. */\n readonly maxSize: number\n /** Maximum number of files (1 for a single file). */\n readonly maxFiles: number\n /** Accepted media types (`image/png`, `image/*`); `undefined`: any. */\n readonly mimeTypes: readonly string[] | undefined\n}\n\n/** How a multipart body is read. */\nexport interface MultipartPolicy {\n /**\n * Upload rules of the route (files are only accepted in their fields: a file in another field is\n * rejected with 400, unless a rule has no field). Without rules, every file is accepted without\n * limit (but the body limit).\n */\n readonly rules: readonly FileRule[]\n /** Maximum number of parts (text fields and files). */\n readonly maxParts: number\n /** Maximum size of a text field, in bytes. */\n readonly maxFieldSize: number\n}\n\n/** A parsed multipart body. */\nexport interface MultipartResult {\n /** Text fields (repeated names → arrays), without prototype. */\n readonly fields: QueryRecord\n /** Files by field name, without prototype. */\n readonly files: Record<string, File[]>\n /** Every file, in body order. */\n readonly list: readonly File[]\n /** Every entry, in body order. */\n readonly entries: readonly (readonly [string, string | File])[]\n}\n\n/** Default maximum size of the headers of one part. */\nconst MAX_HEADER_SIZE = 16 * 1024\n/** Maximum transport padding (spaces) after a boundary delimiter. */\nconst MAX_PADDING = 256\n/** Errors raised while the body is still being read ask the client to close the connection. */\nconst CLOSE: HttpExceptionOptions = Object.freeze({ headers: Object.freeze({ connection: 'close' }) })\n\nconst CR = 13\nconst LF = 10\nconst DASH = 45\nconst SPACE = 32\nconst TAB = 9\nconst HEADER_END = Buffer.from('\\r\\n\\r\\n')\nconst EMPTY: Buffer = Buffer.alloc(0)\nconst DECODER = new TextDecoder()\n\nconst PRINTABLE = /^[\\u0020-\\u007e]*$/\n\n/**\n * A received file. Its `type` is the media type declared by the client, lower-cased (empty when it\n * contains characters outside printable ASCII), identical on every runtime (Bun's `File` adds\n * `;charset=utf-8` to some text types).\n */\nfunction createFile(chunks: Uint8Array[], name: string, type: string): File {\n const file = new File(chunks, name, { type })\n const normalized = PRINTABLE.test(type) ? type.toLowerCase() : ''\n if (file.type !== normalized) Object.defineProperty(file, 'type', { value: normalized, configurable: true })\n return file\n}\n\n/** Description of a part, from its headers. */\nexport interface PartInfo {\n readonly name: string\n /** `undefined` for text fields. */\n readonly filename: string | undefined\n readonly contentType: string | undefined\n}\n\n/** Receives the content of one part. */\nexport interface PartSink {\n data(chunk: Uint8Array): void\n end(): void\n}\n\n/** Receives the parts found by {@link MultipartParser}. */\nexport interface PartHandler {\n start(part: PartInfo): PartSink\n}\n\ntype State = 'preamble' | 'delimiter' | 'headers' | 'body' | 'done'\n\n/**\n * Incremental parser: feed it with {@link write} as chunks arrive, then call {@link end}. Errors\n * (malformed body, limits enforced by the handler) are thrown synchronously from `write`/`end`.\n */\nexport class MultipartParser {\n readonly #delimiter: Buffer\n readonly #handler: PartHandler\n readonly #maxHeaderSize: number\n /** The body is conceptually prefixed with CRLF so that every delimiter is `CRLF--boundary`. */\n #buffer: Buffer = Buffer.from('\\r\\n')\n #state: State = 'preamble'\n #sink: PartSink | undefined\n /** Bytes of the header block already searched for its end (avoids rescanning on every chunk). */\n #scanned = 0\n\n constructor(boundary: string, handler: PartHandler, maxHeaderSize: number = MAX_HEADER_SIZE) {\n this.#delimiter = Buffer.from(`\\r\\n--${boundary}`, 'latin1')\n this.#handler = handler\n this.#maxHeaderSize = maxHeaderSize\n }\n\n /** `true` once the closing delimiter was read (what follows is the epilogue, ignored). */\n get done(): boolean {\n return this.#state === 'done'\n }\n\n write(chunk: Uint8Array): void {\n if (this.#state === 'done' || chunk.byteLength === 0) return\n const view = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength)\n this.#buffer = this.#buffer.length === 0 ? view : Buffer.concat([this.#buffer, view])\n this.#process()\n }\n\n end(): void {\n if (this.#state !== 'done') throw malformed('unexpected end of the body (missing closing boundary)')\n }\n\n #process(): void {\n for (;;) {\n switch (this.#state) {\n case 'preamble': {\n const index = this.#buffer.indexOf(this.#delimiter)\n if (index === -1) {\n this.#keepTail()\n return\n }\n this.#buffer = this.#buffer.subarray(index + this.#delimiter.length)\n this.#state = 'delimiter'\n break\n }\n case 'delimiter':\n if (!this.#afterDelimiter()) return\n break\n case 'headers':\n if (!this.#headers()) return\n break\n case 'body':\n if (!this.#body()) return\n break\n default:\n return\n }\n }\n }\n\n /** After a delimiter: `--` (closing delimiter) or optional padding then CRLF (next part). */\n #afterDelimiter(): boolean {\n const buffer = this.#buffer\n if (buffer.length < 2) return false\n if (buffer[0] === DASH && buffer[1] === DASH) {\n this.#state = 'done'\n this.#buffer = EMPTY\n return false\n }\n let index = 0\n while (index < buffer.length && (buffer[index] === SPACE || buffer[index] === TAB)) index++\n if (index > MAX_PADDING) throw malformed('invalid boundary delimiter')\n if (index + 1 >= buffer.length) return false\n if (buffer[index] !== CR || buffer[index + 1] !== LF) throw malformed('invalid boundary delimiter')\n this.#buffer = buffer.subarray(index + 2)\n this.#state = 'headers'\n return true\n }\n\n #headers(): boolean {\n const buffer = this.#buffer\n if (buffer.length < 2) return false\n let end: number\n let next: number\n if (buffer[0] === CR && buffer[1] === LF) {\n end = 0\n next = 2\n } else {\n end = buffer.indexOf(HEADER_END, Math.max(0, this.#scanned - (HEADER_END.length - 1)))\n if (end === -1) {\n if (buffer.length > this.#maxHeaderSize) throw malformed('the headers of a part are too large')\n this.#scanned = buffer.length\n return false\n }\n if (end > this.#maxHeaderSize) throw malformed('the headers of a part are too large')\n next = end + 4\n }\n const part = parsePartHeaders(buffer.toString('utf8', 0, end))\n this.#scanned = 0\n this.#buffer = buffer.subarray(next)\n this.#sink = this.#handler.start(part)\n this.#state = 'body'\n return true\n }\n\n #body(): boolean {\n const buffer = this.#buffer\n const sink = this.#sink as PartSink\n const index = buffer.indexOf(this.#delimiter)\n if (index === -1) {\n // keep what may be the beginning of a delimiter\n const safe = buffer.length - (this.#delimiter.length - 1)\n if (safe > 0) {\n sink.data(buffer.subarray(0, safe))\n this.#buffer = buffer.subarray(safe)\n }\n return false\n }\n if (index > 0) sink.data(buffer.subarray(0, index))\n this.#sink = undefined\n sink.end()\n this.#buffer = buffer.subarray(index + this.#delimiter.length)\n this.#state = 'delimiter'\n return true\n }\n\n #keepTail(): void {\n const keep = this.#delimiter.length - 1\n if (this.#buffer.length > keep) this.#buffer = this.#buffer.subarray(this.#buffer.length - keep)\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Headers\n// -------------------------------------------------------------------------------------------------\n\nfunction parsePartHeaders(block: string): PartInfo {\n let disposition: string | undefined\n let contentType: string | undefined\n let current: 'content-disposition' | 'content-type' | undefined\n if (block !== '') {\n for (const line of block.split('\\r\\n')) {\n if (line.startsWith(' ') || line.startsWith('\\t')) {\n // obsolete line folding: continuation of the previous header\n if (current === 'content-disposition') disposition = `${disposition ?? ''} ${line.trim()}`\n else if (current === 'content-type') contentType = `${contentType ?? ''} ${line.trim()}`\n continue\n }\n const colon = line.indexOf(':')\n if (colon <= 0) throw malformed('invalid part header')\n const name = line.slice(0, colon).trim().toLowerCase()\n const value = line.slice(colon + 1).trim()\n current = undefined\n if (name === 'content-disposition' && disposition === undefined) {\n disposition = value\n current = name\n } else if (name === 'content-type' && contentType === undefined) {\n contentType = value\n current = name\n }\n }\n }\n if (disposition === undefined) throw malformed('a part has no Content-Disposition header')\n const { type, params } = parseParameters(disposition)\n if (type !== 'form-data') throw malformed('a part is not \"form-data\"')\n const name = params.get('name')\n if (name === undefined) throw malformed('a part has no name')\n const extended = params.get('filename*')\n const plain = params.get('filename')\n const filename = (extended === undefined ? undefined : decodeExtendedValue(extended)) ?? plain\n return {\n name: decodeFormName(name),\n filename: filename === undefined ? undefined : decodeFormName(filename),\n contentType: contentType === '' ? undefined : contentType,\n }\n}\n\n/**\n * Parses `value; key=token; key=\"quoted \\\" string\"` (Content-Disposition, Content-Type). Keys are\n * lower-cased; the first occurrence of a key wins.\n */\nexport function parseParameters(value: string): { readonly type: string; readonly params: Map<string, string> } {\n const params = new Map<string, string>()\n let index = value.indexOf(';')\n const type = (index === -1 ? value : value.slice(0, index)).trim().toLowerCase()\n while (index !== -1 && index < value.length) {\n index++ // skip ';'\n while (index < value.length && isSpace(value.charCodeAt(index))) index++\n if (index >= value.length) break\n if (value[index] === ';') continue // empty parameter\n const equals = value.indexOf('=', index)\n if (equals === -1) throw malformed(`invalid parameter in ${JSON.stringify(truncate(value))}`)\n const key = value.slice(index, equals).trim().toLowerCase()\n index = equals + 1\n while (index < value.length && isSpace(value.charCodeAt(index))) index++\n let parameter: string\n if (value[index] === '\"') {\n parameter = ''\n index++\n for (;;) {\n if (index >= value.length) throw malformed('unterminated quoted string in a part header')\n const char = value[index] as string\n if (char === '\"') {\n index++\n break\n }\n if (char === '\\\\' && (value[index + 1] === '\"' || value[index + 1] === '\\\\')) {\n parameter += value[index + 1]\n index += 2\n continue\n }\n parameter += char\n index++\n }\n while (index < value.length && isSpace(value.charCodeAt(index))) index++\n if (index < value.length && value[index] !== ';') throw malformed('invalid quoted string in a part header')\n } else {\n const next = value.indexOf(';', index)\n parameter = (next === -1 ? value.slice(index) : value.slice(index, next)).trim()\n index = next === -1 ? value.length : next\n }\n if (key !== '' && !params.has(key)) params.set(key, parameter)\n if (index >= value.length) break\n }\n return { type, params }\n}\n\nfunction isSpace(code: number): boolean {\n return code === SPACE || code === TAB\n}\n\n/** Names and filenames: browsers escape `\"`, CR and LF as `%22`, `%0D` and `%0A` (HTML standard). */\nfunction decodeFormName(value: string): string {\n return value.includes('%')\n ? value.replace(/%(22|0D|0A)/gi, (_match, hex: string) => String.fromCharCode(Number.parseInt(hex, 16)))\n : value\n}\n\n/** RFC 5987 `charset'language'percent-encoded` (`filename*`); `undefined` when it cannot be decoded. */\nfunction decodeExtendedValue(value: string): string | undefined {\n const match = /^([\\w!#$%&+^`{}~-]+)'[\\w-]*'(.*)$/.exec(value)\n if (match === null) return undefined\n const charset = (match[1] as string).toLowerCase()\n const encoded = match[2] as string\n try {\n if (charset === 'utf-8') return decodeURIComponent(encoded)\n if (charset === 'iso-8859-1') {\n return encoded.replace(/%([0-9a-f]{2})/gi, (_match, hex: string) => String.fromCharCode(Number.parseInt(hex, 16)))\n }\n } catch {\n return undefined\n }\n return undefined\n}\n\n/** The `boundary` parameter of a `multipart/form-data` content type (400 when missing or invalid). */\nexport function multipartBoundary(contentType: string): string {\n let boundary: string | undefined\n try {\n boundary = parseParameters(contentType).params.get('boundary')\n } catch {\n boundary = undefined\n }\n if (boundary === undefined || boundary === '') throw malformed('missing boundary in the content type')\n // RFC 2046: 1 to 70 printable ASCII characters\n if (boundary.length > 70 || [...boundary].some(char => char < ' ' || char > '~')) {\n throw malformed('invalid boundary in the content type')\n }\n return boundary\n}\n\n// -------------------------------------------------------------------------------------------------\n// Collecting fields and files\n// -------------------------------------------------------------------------------------------------\n\n/** Applies a {@link MultipartPolicy} to the parts and collects fields and files. */\nclass Collector implements PartHandler {\n readonly fields: QueryRecord = emptyRecord()\n readonly files: Record<string, File[]> = emptyRecord()\n readonly list: File[] = []\n readonly entries: (readonly [string, string | File])[] = []\n readonly #policy: MultipartPolicy\n readonly #named: ReadonlyMap<string, FileRule>\n readonly #any: FileRule | undefined\n readonly #counts = new Map<FileRule, number>()\n #parts = 0\n\n constructor(policy: MultipartPolicy) {\n this.#policy = policy\n const named = new Map<string, FileRule>()\n let any: FileRule | undefined\n for (const rule of policy.rules) {\n if (rule.field === undefined) any = rule\n else named.set(rule.field, rule)\n }\n this.#named = named\n this.#any = any\n }\n\n start(part: PartInfo): PartSink {\n this.#parts++\n if (this.#parts > this.#policy.maxParts) {\n throw new PayloadTooLargeException(\n `Too many parts in the multipart body (at most ${this.#policy.maxParts})`,\n { maxParts: this.#policy.maxParts },\n CLOSE,\n )\n }\n return part.filename === undefined ? this.#field(part.name) : this.#file(part, part.filename)\n }\n\n #field(name: string): PartSink {\n const limit = this.#policy.maxFieldSize\n const chunks: Uint8Array[] = []\n let size = 0\n return {\n data: chunk => {\n size += chunk.byteLength\n if (size > limit) {\n throw new PayloadTooLargeException(\n `Field ${JSON.stringify(truncate(name))} exceeds the maximum size of ${formatByteSize(limit)}`,\n { field: name, maxSize: limit },\n CLOSE,\n )\n }\n chunks.push(chunk)\n },\n end: () => {\n const value = DECODER.decode(chunks.length === 1 ? (chunks[0] as Uint8Array) : Buffer.concat(chunks))\n const existing = this.fields[name]\n if (existing === undefined) this.fields[name] = value\n else if (typeof existing === 'string') this.fields[name] = [existing, value]\n else existing.push(value)\n this.entries.push([name, value])\n },\n }\n }\n\n #file(part: PartInfo, filename: string): PartSink {\n const type = part.contentType === undefined ? OCTET_STREAM : part.contentType\n const name = part.name\n let rules: readonly FileRule[] = []\n let admitted = false\n // an empty <input type=\"file\"> is sent as an empty part without filename: it is not a file\n const admit = (): void => {\n admitted = true\n rules = this.#admit(name, type)\n }\n if (filename !== '') admit()\n const chunks: Uint8Array[] = []\n let size = 0\n return {\n data: chunk => {\n if (!admitted) admit()\n size += chunk.byteLength\n for (const rule of rules) {\n if (size > rule.maxSize) {\n throw new PayloadTooLargeException(\n `File in field ${JSON.stringify(truncate(name))} exceeds the maximum size of ${formatByteSize(rule.maxSize)}`,\n { field: name, maxSize: rule.maxSize },\n CLOSE,\n )\n }\n }\n chunks.push(chunk)\n },\n end: () => {\n if (!admitted) return\n const file = createFile(chunks, filename, type)\n const list = this.files[name]\n if (list === undefined) this.files[name] = [file]\n else list.push(file)\n this.list.push(file)\n this.entries.push([name, file])\n },\n }\n }\n\n /** Rules applying to a file of `field` (400 for an unexpected field), with count and type checks. */\n #admit(field: string, type: string): readonly FileRule[] {\n if (this.#policy.rules.length === 0) return []\n const rules: FileRule[] = []\n const named = this.#named.get(field)\n if (named !== undefined) rules.push(named)\n if (this.#any !== undefined) rules.push(this.#any)\n if (rules.length === 0) {\n const expected = [...this.#named.keys()]\n throw new BadRequestException(\n `Unexpected file field ${JSON.stringify(truncate(field))}`,\n issue(field, `Unexpected file field (expected ${expected.join(', ')})`),\n CLOSE,\n )\n }\n for (const rule of rules) {\n const count = (this.#counts.get(rule) ?? 0) + 1\n this.#counts.set(rule, count)\n if (count > rule.maxFiles) {\n const where = rule.field === undefined ? '' : ` in field ${JSON.stringify(truncate(rule.field))}`\n if (!rule.multiple) {\n throw new BadRequestException(`Expected a single file${where}`, issue(field, 'Expected a single file'), CLOSE)\n }\n throw new PayloadTooLargeException(\n `Too many files${where} (at most ${rule.maxFiles})`,\n { field, maxFiles: rule.maxFiles },\n CLOSE,\n )\n }\n if (rule.mimeTypes !== undefined && !matchesMediaType(type, rule.mimeTypes)) {\n throw new UnsupportedMediaTypeException(\n `Unsupported file type ${JSON.stringify(truncate(mediaTypeEssence(type)))} in field ${JSON.stringify(truncate(field))} (accepted: ${rule.mimeTypes.join(', ')})`,\n { field, type: mediaTypeEssence(type), accepted: rule.mimeTypes },\n CLOSE,\n )\n }\n }\n return rules\n }\n\n result(): MultipartResult {\n return { fields: this.fields, files: this.files, list: this.list, entries: this.entries }\n }\n}\n\n/**\n * Reads a multipart body from `stream` with `policy`. The stream is cancelled on error (the rest of\n * the body is discarded).\n *\n * @throws BadRequestException (400) for a malformed body, too many parts / files or an unexpected\n * file field; PayloadTooLargeException (413) for a file or field above its limit;\n * UnsupportedMediaTypeException (415) for a file of a refused type.\n */\nexport async function readMultipart(\n stream: ReadableStream<Uint8Array>,\n contentType: string,\n policy: MultipartPolicy,\n): Promise<MultipartResult> {\n const reader = stream.getReader()\n try {\n const collector = new Collector(policy)\n const parser = new MultipartParser(multipartBoundary(contentType), collector)\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n parser.write(value)\n }\n parser.end()\n return collector.result()\n } catch (error) {\n await reader.cancel(error).catch(() => undefined)\n throw error\n }\n}\n\n/** Parses a buffered multipart body (see {@link readMultipart}). */\nexport function parseMultipart(bytes: Uint8Array, contentType: string, policy: MultipartPolicy): MultipartResult {\n const collector = new Collector(policy)\n const parser = new MultipartParser(multipartBoundary(contentType), collector)\n parser.write(bytes)\n parser.end()\n return collector.result()\n}\n\n/** Converts a parse result to a `FormData` (entries in body order). */\nexport function toFormData(result: MultipartResult): FormData {\n const form = new FormData()\n for (const [name, value] of result.entries) form.append(name, value)\n return form\n}\n\nfunction malformed(reason: string): BadRequestException {\n return new BadRequestException(`Invalid multipart body: ${reason}`, undefined, CLOSE)\n}\n\nfunction truncate(value: string): string {\n return value.length > 100 ? `${value.slice(0, 100)}…` : value\n}\n","import { emptyRecord } from './utils.ts'\n\n/** Parsed query string (or `application/x-www-form-urlencoded` body): repeated keys become arrays. */\nexport type QueryRecord = Record<string, string | string[]>\n\n/**\n * Parses a query string (with or without the leading `?`) with `URLSearchParams` semantics (`+` is\n * a space, malformed `%` sequences are kept as is, invalid UTF-8 becomes U+FFFD). A key present\n * once maps to a string, a repeated key to an array of strings, in order. No nesting (`a[b]=1` is\n * the key `a[b]`). The returned object has no prototype.\n *\n * `parseQuery('?tag=a&tag=b&page=2')` → `{ tag: ['a', 'b'], page: '2' }`\n */\nexport function parseQuery(query: string): QueryRecord {\n const result = emptyRecord<string | string[]>()\n if (query === '' || query === '?') return result\n for (const [key, value] of new URLSearchParams(query)) {\n const existing = result[key]\n if (existing === undefined) result[key] = value\n else if (typeof existing === 'string') result[key] = [existing, value]\n else existing.push(value)\n }\n return result\n}\n\n/** Splits a request target (`/users?page=2`) into its raw path and raw query (without `?`). */\nexport function splitUrl(url: string): { readonly path: string; readonly query: string } {\n const index = url.indexOf('?')\n return index === -1 ? { path: url, query: '' } : { path: url.slice(0, index), query: url.slice(index + 1) }\n}\n","import { BadRequestException, UnsupportedMediaTypeException } from './exceptions.ts'\nimport { parseMultipart, toFormData } from './multipart.ts'\nimport { parseQuery } from './query.ts'\nimport { errorMessage } from './utils.ts'\n\n/** The part of `TextDecoder` used here (the global type is not declared without the DOM lib). */\ninterface Decoder {\n readonly encoding: string\n decode(input: Uint8Array): string\n}\n\nconst UTF8: Decoder = new TextDecoder('utf-8', { fatal: true })\n\n/** A parsed `content-type` header. */\nexport interface MediaType {\n /** Lower-case `type/subtype` without parameters. */\n readonly type: string\n /** Lower-case `charset` parameter, when present. */\n readonly charset: string | undefined\n}\n\n/** Parses a `content-type` header value (`application/json; charset=utf-8`). */\nexport function parseMediaType(header: string | undefined): MediaType | undefined {\n if (header === undefined) return undefined\n const separator = header.indexOf(';')\n const type = (separator === -1 ? header : header.slice(0, separator)).trim().toLowerCase()\n if (type === '') return undefined\n let charset: string | undefined\n if (separator !== -1) {\n for (const parameter of header.slice(separator + 1).split(';')) {\n const equals = parameter.indexOf('=')\n if (equals === -1) continue\n if (parameter.slice(0, equals).trim().toLowerCase() !== 'charset') continue\n charset = parameter\n .slice(equals + 1)\n .trim()\n .replace(/^\"|\"$/g, '')\n .toLowerCase()\n }\n }\n return { type, charset }\n}\n\n/** Whether `type` is a JSON media type (`application/json`, `application/problem+json`...). */\nexport function isJsonType(type: string): boolean {\n return type === 'application/json' || type.endsWith('+json')\n}\n\n/** Rejects a `content-encoding` other than `identity` with 415 (decompression is not supported). */\nexport function checkContentEncoding(contentEncoding: string | undefined): void {\n if (contentEncoding === undefined) return\n const encoding = contentEncoding.trim().toLowerCase()\n if (encoding !== '' && encoding !== 'identity') {\n throw new UnsupportedMediaTypeException(`Unsupported content encoding \"${encoding}\"`)\n }\n}\n\n/**\n * Whether request headers announce a body (RFC 9112 §6.3: `transfer-encoding`, or a non-zero\n * `content-length`).\n */\nexport function hasBody(headers: Readonly<Record<string, string | undefined>>): boolean {\n if (headers['transfer-encoding'] !== undefined) return true\n const length = headers['content-length']\n return length !== undefined && length.trim() !== '0' && length.trim() !== ''\n}\n\n/**\n * Parses a buffered request body according to its `content-type` (low-level helper; the request\n * context parses bodies itself, multipart bodies as they arrive):\n *\n * | Content type | Result |\n * | ------------------------------------- | ------------------------------------ |\n * | empty body | `undefined` |\n * | `application/json`, `*\\/*+json` | parsed JSON (400 when malformed) |\n * | `text/*` | string (charset honoured) |\n * | `application/x-www-form-urlencoded` | record (repeated keys → arrays) |\n * | `multipart/form-data` | `FormData` (every field and file) |\n * | anything else, or no content type | `Uint8Array` |\n *\n * A `content-encoding` other than `identity` is rejected with 415 (decompression is not supported).\n */\nexport function parseBody(\n bytes: Uint8Array,\n contentType: string | undefined,\n contentEncoding?: string | undefined,\n): Promise<unknown> {\n try {\n return Promise.resolve(parseBytes(bytes, contentType, contentEncoding))\n } catch (error) {\n return Promise.reject(error)\n }\n}\n\nfunction parseBytes(bytes: Uint8Array, contentType: string | undefined, contentEncoding: string | undefined): unknown {\n if (bytes.byteLength === 0) return undefined\n checkContentEncoding(contentEncoding)\n const media = parseMediaType(contentType)\n if (media === undefined) return bytes\n if (isJsonType(media.type)) {\n if (media.charset !== undefined && media.charset !== 'utf-8' && media.charset !== 'utf8') {\n throw new UnsupportedMediaTypeException(`Unsupported charset \"${media.charset}\" for JSON (use utf-8)`)\n }\n const text = decode(bytes, UTF8, 'JSON')\n try {\n return JSON.parse(text)\n } catch (error) {\n throw new BadRequestException(`Invalid JSON body: ${errorMessage(error)}`)\n }\n }\n if (media.type.startsWith('text/')) return decode(bytes, decoderFor(media.charset), 'text')\n if (media.type === 'application/x-www-form-urlencoded') return parseQuery(decode(bytes, UTF8, 'form'))\n if (media.type === 'multipart/form-data') {\n const policy = { rules: [], maxParts: Number.POSITIVE_INFINITY, maxFieldSize: Number.POSITIVE_INFINITY }\n return toFormData(parseMultipart(bytes, contentType as string, policy))\n }\n return bytes\n}\n\nfunction decoderFor(charset: string | undefined): Decoder {\n if (charset === undefined || charset === 'utf-8' || charset === 'utf8') return UTF8\n try {\n return new TextDecoder(charset as 'utf-8', { fatal: true })\n } catch {\n throw new UnsupportedMediaTypeException(`Unsupported charset \"${charset}\"`)\n }\n}\n\nfunction decode(bytes: Uint8Array, decoder: Decoder, what: string): string {\n try {\n return decoder.decode(bytes)\n } catch {\n throw new BadRequestException(`Invalid ${what} body: malformed ${decoder.encoding} data`)\n }\n}\n","import { BadRequestException } from './exceptions.ts'\n\n/**\n * Converts a raw request value (route parameter, query value, header) to `T`, or throws a\n * `400 Bad Request` naming `label` (`param \"id\"`, `query \"page\"`, `header \"x-limit\"`).\n * Called by the compiler-generated `invoke` functions.\n */\nexport type Coercer<T> = (value: unknown, label: string) => T\n\n/** The coercion helpers called by generated code (see the \"Compiler contract\" of the README). */\nexport interface Coercers {\n /** A string. Rejects missing values and repeated query values. */\n readonly string: Coercer<string>\n /** A finite decimal number (`12`, `-1.5`, `1e3`). Rejects `''`, hex, `NaN`, `Infinity`. */\n readonly number: Coercer<number>\n /** A safe integer (`42`, `-7`). */\n readonly integer: Coercer<number>\n /** `true`/`1` → `true`, `false`/`0` → `false` (case-insensitive). */\n readonly boolean: Coercer<boolean>\n /** A bigint (`123`, `-9007199254740993`). */\n readonly bigint: Coercer<bigint>\n /**\n * A `Date` from an ISO 8601 date (`2024-01-02`, UTC midnight), an ISO 8601 date-time with an\n * offset (`2024-01-02T03:04:05Z`, `2024-01-02T03:04+02:00`) or a millisecond timestamp.\n */\n readonly date: Coercer<Date>\n /** One of `values` (string or number literals, compared after coercion). */\n enum<const T extends readonly (string | number | boolean)[]>(value: unknown, label: string, values: T): T[number]\n /** An array: a single value becomes a one-element array, each item is coerced with `item`. */\n array<T>(value: unknown, label: string, item: Coercer<T>): T[]\n /** `undefined` when the value is missing, otherwise `item(value, label)`. */\n optional<T>(value: unknown, label: string, item: Coercer<T>): T | undefined\n}\n\n// unambiguous (`\\d+` and the fraction never compete for the same digits): linear time on any input\nconst NUMBER = /^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?$/\nconst INTEGER = /^[+-]?\\d+$/\n/** ISO 8601 calendar date, optionally with a time and an offset (`Z`, `+02:00`, `+0200`). */\nconst ISO_DATE =\n /^(\\d{4})-(\\d{2})-(\\d{2})(?:[Tt ](\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{1,9}))?)?(?:([Zz])|([+-])(\\d{2}):?(\\d{2}))?)?$/\n\nfunction invalid(label: string, expected: string, value: unknown): BadRequestException {\n // cookies often carry tokens: their values are never echoed\n if (label.startsWith('cookie ')) return new BadRequestException(`Invalid ${label}: expected ${expected}`)\n return new BadRequestException(`Invalid ${label}: expected ${expected}, received ${describe(value)}`)\n}\n\nfunction describe(value: unknown): string {\n if (typeof value === 'string') return JSON.stringify(value.length > 64 ? `${value.slice(0, 64)}…` : value)\n if (Array.isArray(value)) return `${value.length} values`\n return typeof value\n}\n\n/** The single raw string of a value, or a 400 (missing / repeated / not a string). */\nfunction single(value: unknown, label: string): string {\n if (typeof value === 'string') return value\n if (value === undefined || value === null) throw new BadRequestException(`Missing ${label}`)\n if (Array.isArray(value))\n throw new BadRequestException(`Invalid ${label}: expected a single value, received ${value.length}`)\n throw invalid(label, 'a string', value)\n}\n\nfunction toNumber(value: unknown, label: string): number {\n const raw = single(value, label)\n const text = raw.trim()\n if (NUMBER.test(text)) {\n const result = Number(text)\n if (Number.isFinite(result)) return result\n }\n throw invalid(label, 'a number', raw)\n}\n\nfunction toInteger(value: unknown, label: string): number {\n const raw = single(value, label)\n const text = raw.trim()\n if (INTEGER.test(text)) {\n const result = Number(text)\n if (Number.isSafeInteger(result)) return result\n }\n throw invalid(label, 'an integer', raw)\n}\n\nfunction toBoolean(value: unknown, label: string): boolean {\n const raw = single(value, label)\n switch (raw.trim().toLowerCase()) {\n case 'true':\n case '1':\n return true\n case 'false':\n case '0':\n return false\n default:\n throw invalid(label, 'a boolean (true, false, 1 or 0)', raw)\n }\n}\n\nfunction toBigint(value: unknown, label: string): bigint {\n const raw = single(value, label)\n const text = raw.trim()\n if (INTEGER.test(text)) return BigInt(text)\n throw invalid(label, 'an integer', raw)\n}\n\nfunction toDate(value: unknown, label: string): Date {\n const raw = single(value, label)\n const text = raw.trim()\n const date = INTEGER.test(text) ? new Date(Number(text)) : parseIsoDate(text)\n if (date === undefined || Number.isNaN(date.getTime())) {\n throw invalid(label, 'a date (ISO 8601 such as 2024-01-02 or 2024-01-02T10:00:00Z, or a timestamp)', raw)\n }\n return date\n}\n\nconst DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n\n/**\n * Parses an ISO 8601 date or date-time (see `Coercers.date`), `undefined` otherwise. Nothing else is\n * handed to the engine's lenient `Date` parser (`foo 2024`, `March 7`), impossible dates\n * (`2024-02-30`) are rejected instead of rolled over, and a date-time without offset is rejected\n * rather than read in the server's time zone.\n */\nfunction parseIsoDate(text: string): Date | undefined {\n const match = ISO_DATE.exec(text)\n if (match === null) return undefined\n const [, y, mo, d, h, mi, s, fraction, zulu, sign, oh, om] = match\n const year = Number(y)\n const month = Number(mo)\n const day = Number(d)\n const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)\n const days = month === 2 && leap ? 29 : DAYS_IN_MONTH[month - 1]\n if (days === undefined || day < 1 || day > days) return undefined\n const date = new Date(0)\n date.setUTCFullYear(year, month - 1, day) // years 0-99 are not shifted to 1900-1999 (Date.UTC)\n if (h === undefined) return date\n if (zulu === undefined && sign === undefined) return undefined\n const hours = Number(h)\n const minutes = Number(mi)\n const seconds = s === undefined ? 0 : Number(s)\n const offset = sign === undefined ? 0 : (sign === '-' ? -1 : 1) * (Number(oh) * 60 + Number(om))\n if (hours > 23 || minutes > 59 || seconds > 59 || Math.abs(offset) >= 24 * 60 || Number(om ?? 0) > 59) {\n return undefined\n }\n const milliseconds = fraction === undefined ? 0 : Number(fraction.slice(0, 3).padEnd(3, '0'))\n date.setUTCHours(hours, minutes - offset, seconds, milliseconds)\n return date\n}\n\nfunction toEnum<const T extends readonly (string | number | boolean)[]>(\n value: unknown,\n label: string,\n values: T,\n): T[number] {\n const raw = single(value, label)\n for (const candidate of values) {\n if (typeof candidate === 'string' ? candidate === raw : String(candidate) === raw.trim()) return candidate\n }\n throw invalid(label, `one of ${values.map(candidate => JSON.stringify(candidate)).join(', ')}`, raw)\n}\n\nfunction toArray<T>(value: unknown, label: string, item: Coercer<T>): T[] {\n if (value === undefined || value === null) throw new BadRequestException(`Missing ${label}`)\n if (!Array.isArray(value)) return [item(value, label)]\n const result = new Array<T>(value.length)\n for (let index = 0; index < value.length; index++) result[index] = item(value[index], `${label}[${index}]`)\n return result\n}\n\nfunction toOptional<T>(value: unknown, label: string, item: Coercer<T>): T | undefined {\n return value === undefined || value === null ? undefined : item(value, label)\n}\n\n/**\n * Coercion helpers used by generated `invoke` functions for typed parameters without schema:\n *\n * ```ts\n * invoke: (c, ctx) => c.list(\n * coerce.number(ctx.params['id'], 'param \"id\"'),\n * coerce.optional(ctx.query['page'], 'query \"page\"', coerce.integer),\n * coerce.array(ctx.query['tag'], 'query \"tag\"', coerce.string),\n * )\n * ```\n *\n * Every failure is a `BadRequestException` (400) whose message names the input.\n */\nexport const coerce: Coercers = Object.freeze({\n string: single,\n number: toNumber,\n integer: toInteger,\n boolean: toBoolean,\n bigint: toBigint,\n date: toDate,\n enum: toEnum,\n array: toArray,\n optional: toOptional,\n})\n","/** Cookie settings of a plugin (defaults and signing key) and the operations using them (internal). */\nimport type { CookieSigner } from './cookie-signer.ts'\n\nimport {\n type CookieDefaults,\n DEFAULT_COOKIE_OPTIONS,\n decodeCookieValue,\n encodeCookieValue,\n type ResponseCookie,\n type SerializedCookie,\n serializeResponseCookie,\n} from './cookies.ts'\n\n/** The resolved plugin option `cookies`. */\nexport interface CookieSettings {\n /** Secure defaults merged with `cookies.defaults`. */\n readonly defaults: CookieDefaults\n /** `undefined` without `cookies.secrets` (signed cookies unavailable). */\n readonly signer: CookieSigner | undefined\n}\n\n/** Settings without plugin options: the secure defaults, no signing. */\nexport const DEFAULT_COOKIE_SETTINGS: CookieSettings = Object.freeze({\n defaults: DEFAULT_COOKIE_OPTIONS,\n signer: undefined,\n})\n\n/** The error of a signed cookie used without `cookies.secrets`. */\nexport function missingSecrets(action: string): Error {\n return new Error(\n `${action}: the HttpPlugin option cookies.secrets is not set (HttpPlugin.configure({ cookies: { secrets: [...] } }))`,\n )\n}\n\n/** Serialises a response cookie with the plugin settings (`signed: true` signs with the first secret). */\nexport function serializeWith(cookie: ResponseCookie, settings: CookieSettings): SerializedCookie {\n const signer = settings.signer\n if (cookie.value !== undefined && cookie.options.signed === true && signer === undefined) {\n throw missingSecrets(`Cannot sign the cookie \"${cookie.name}\"`)\n }\n return serializeResponseCookie(cookie, settings.defaults, (name, encoded) =>\n (signer as CookieSigner).sign(name, encoded),\n )\n}\n\n/**\n * The verified value of a signed request cookie (`value` as parsed, i.e. decoded), `undefined` when\n * absent, tampered or signed with an unknown key. The value is re-encoded canonically before the\n * MAC is checked (`encode(decode(w)) === w` for every value Znight signs).\n */\nexport function verifySigned(signer: CookieSigner, name: string, value: string | undefined): string | undefined {\n if (value === undefined) return undefined\n const dot = value.lastIndexOf('.')\n if (dot === -1) return undefined\n let encoded: string\n try {\n encoded = encodeCookieValue(value.slice(0, dot))\n } catch {\n return undefined\n }\n const verified = signer.verify(name, `${encoded}${value.slice(dot)}`)\n return verified === undefined ? undefined : decodeCookieValue(verified)\n}\n\n/** The signed wire value of `value` (encoded, then signed): what a client sends back. */\nexport function signValue(signer: CookieSigner, name: string, value: string): string {\n return signer.sign(name, encodeCookieValue(value))\n}\n","import type { Token } from '@znight/core'\nimport type { AdapterRequest } from './adapter.ts'\nimport type { CookieSettings } from './cookie-settings.ts'\nimport type { ClearCookieOptions, CookieOptions, ResponseCookie, SerializedCookie } from './cookies.ts'\nimport type { HeaderValue } from './exceptions.ts'\nimport type { MultipartResult } from './multipart.ts'\nimport type { BodyPlan } from './uploads.ts'\n\nimport { checkContentEncoding, hasBody, parseBody, parseMediaType } from './body.ts'\nimport { DEFAULT_COOKIE_SETTINGS, missingSecrets, serializeWith, verifySigned } from './cookie-settings.ts'\nimport { parseCookieHeader } from './cookies.ts'\nimport { UnsupportedMediaTypeException } from './exceptions.ts'\nimport { parseMultipart, readMultipart } from './multipart.ts'\nimport { parseQuery, type QueryRecord, splitUrl } from './query.ts'\nimport { emptyRecord } from './utils.ts'\n\ndeclare const requestIdBrand: unique symbol\n\n/** Why `ctx.signal` aborted: the client left, the server shuts down, or an SSE stream reached its `maxDuration`. */\nexport type RequestAbortKind = 'client' | 'shutdown' | 'expired'\n\n/**\n * The reason of an aborted `ctx.signal`. Named `AbortError`, what `fetch`, `node:timers/promises`\n * and most libraries check.\n */\nexport class RequestAbortedError extends Error {\n override readonly name = 'AbortError'\n /** `client`: disconnected; `shutdown`: the server stops; `expired`: an SSE stream reached its `maxDuration`. */\n readonly kind: RequestAbortKind\n\n constructor(kind: RequestAbortKind) {\n super(ABORT_MESSAGES[kind])\n this.kind = kind\n }\n}\n\nconst ABORT_MESSAGES: Readonly<Record<RequestAbortKind, string>> = {\n client: 'The client disconnected',\n shutdown: 'The server is shutting down',\n expired: 'The event stream reached its maxDuration',\n}\n\n/**\n * Identifier of the current request: the incoming `x-request-id` header (see the plugin option\n * `requestIdHeader`) or a generated UUID. Injectable in request-scoped providers.\n */\nexport type RequestId = string & { readonly [requestIdBrand]: true }\n\n/** The route that matched a request. */\nexport interface HttpRouteInfo {\n /** Route method (`GET`...; the concrete method for `@All` routes). */\n readonly method: string\n /** Route pattern including the plugin prefix (`/api/users/:id`). */\n readonly path: string\n /** Controller provider token. */\n readonly controller: Token\n /** Handler method name. */\n readonly handler: string\n /**\n * Effective route metadata (`createRouteDecorator`): the controller's entries, except those of a\n * group the route decides itself, then the route's entries (the nearest decision wins).\n */\n readonly meta: Readonly<Record<string, unknown>>\n}\n\n/**\n * Adapter-neutral view of the current HTTP request, shared by guards, interceptors, exception\n * mappers and handlers (`@Ctx()`), and injectable in request-scoped providers.\n */\nexport interface HttpContext {\n readonly requestId: RequestId\n /** Upper-case method. */\n readonly method: string\n /** Raw request target (`/users/a%20b?page=2`). */\n readonly url: string\n /** Raw path, without query string (`/users/a%20b`). */\n readonly path: string\n /** Decoded route parameters (`*` holds the part matched by a trailing wildcard). */\n readonly params: Readonly<Record<string, string>>\n /** Decoded query string (repeated keys → arrays), parsed on first access. */\n readonly query: Readonly<QueryRecord>\n /** Request headers, lower-case names. */\n readonly headers: Readonly<Record<string, string | undefined>>\n /**\n * Parsed body. Populated before the interceptors for routes declaring `@Body()` or upload\n * parameters (and after {@link parseBody} resolved otherwise); `undefined` until then and for\n * empty bodies. Forms (urlencoded and multipart) are records of their text fields.\n */\n readonly body: unknown\n /**\n * Files of a `multipart/form-data` body by field name, in body order (standard `File` objects,\n * held in memory). Populated with {@link body}; empty for other bodies.\n */\n readonly files: Readonly<Record<string, readonly File[]>>\n /** The matched route, `undefined` for unmatched requests (404/405). */\n readonly route: HttpRouteInfo | undefined\n /** Per-request storage for guards, interceptors and handlers (`ctx.state.set('user', user)`). */\n readonly state: Map<string | symbol, unknown>\n /** Native request of the adapter (`IncomingMessage`, `FastifyRequest`, Express `Request`, Web `Request`). */\n readonly request: unknown\n /** Native response of the adapter (`ServerResponse`, `FastifyReply`, Express `Response`, Hono `Context`). */\n readonly response: unknown\n /** Adapter name (`node`, `fastify`, `express`, `hono`). */\n readonly adapter: string\n /**\n * Client address, when the adapter knows it. With the plugin option `trustProxy`, the address\n * found in `x-forwarded-for` behind the trusted proxies; otherwise the adapter's address (the\n * socket peer, or what Fastify / Express derive from their own proxy settings).\n */\n readonly ip: string | undefined\n /**\n * `https` when the connection uses TLS, or, behind a trusted proxy (`trustProxy`), when the\n * leftmost `x-forwarded-proto` says so; `http` otherwise.\n */\n readonly protocol: 'http' | 'https'\n /** Headers added to the response, whatever its outcome (errors included). */\n readonly responseHeaders: Readonly<Record<string, HeaderValue>>\n /** A request header (case-insensitive name). */\n header(name: string): string | undefined\n /** Sets a response header (case-insensitive name), sent with success and error responses. */\n setHeader(name: string, value: HeaderValue): void\n /** Appends a response header value (`set-cookie`...). */\n appendHeader(name: string, value: string): void\n /**\n * Request cookies (`cookie` header), parsed on first access: decoded values, the first occurrence\n * of a name wins. A prototype-less, frozen record.\n */\n readonly cookies: Readonly<Record<string, string>>\n /**\n * The verified value of a signed cookie (`@SignedCookie`), `undefined` when it is absent, tampered\n * or signed with a key that is no longer in `cookies.secrets`. Verified once per name.\n *\n * @throws Error when the plugin option `cookies.secrets` is not set.\n */\n signedCookie(name: string): string | undefined\n /**\n * Sets a cookie on the response, whatever its outcome (errors, redirects included), with the\n * secure defaults (`Path=/; Secure; HttpOnly; SameSite=Lax`, see the plugin option\n * `cookies.defaults`). A later cookie with the same name, domain and path replaces this one; a\n * cookie of the same key in an `HttpResponse` (`withCookie`) wins over it. Everything is validated\n * now (name, value, attributes, prefixes, size), so the stack trace points to the faulty call.\n *\n * @throws TypeError / RangeError for an invalid cookie; Error once the response headers were sent\n * (a running event stream).\n */\n setCookie(name: string, value: string, options?: CookieOptions): void\n /**\n * Clears a cookie (`Max-Age=0`, with the same domain and path, and the defaults: a `__Host-`\n * cookie is cleared with valid attributes).\n *\n * @throws like {@link setCookie}.\n */\n clearCookie(name: string, options?: ClearCookieOptions): void\n /** Cookies set on this response so far (`setCookie` / `clearCookie`), in order. */\n readonly responseCookies: readonly ResponseCookie[]\n /**\n * Aborted when the client disconnects before the response was written, when the response body is\n * cancelled, or when the server closes an event stream (shutdown, `maxDuration`); never after a\n * normal completion. The reason is a {@link RequestAbortedError}. Pass it to the work the request\n * starts (`fetch(url, { signal: ctx.signal })`, `setTimeout(ms, v, { signal })`). Created on first\n * access.\n */\n readonly signal: AbortSignal\n /**\n * Reads and parses the body (once): JSON (`application/json`, `+json`), text (`text/*`), forms\n * (`application/x-www-form-urlencoded` and `multipart/form-data` → record of the text fields,\n * repeated names as arrays; files in {@link files}), raw bytes otherwise; `undefined` when empty.\n * Fails with 400 (malformed), 413 (body or upload limits) or 415 (unsupported encoding, refused\n * file type, non-multipart body on an upload route).\n */\n parseBody(): Promise<unknown>\n /** The raw body bytes (once; shared with {@link parseBody}), e.g. to check a webhook signature. */\n rawBody(): Promise<Uint8Array>\n /**\n * The request body as a Web stream, read as it arrives (nothing is buffered): the escape hatch\n * for large uploads (`PUT /files/:name` piped to disk or object storage). The body limit of the\n * route still applies (`@BodyLimit`, `Infinity` to disable): past it the stream errors with a\n * `PayloadTooLargeException` (413). Exclusive with {@link rawBody} / {@link parseBody}: throws when\n * the body was already read (routes with `@Body()` or upload parameters read it before the\n * handler).\n */\n bodyStream(): ReadableStream<Uint8Array>\n}\n\n/** Implementation of {@link HttpContext} used by the pipeline (internal). */\nexport class RequestContext implements HttpContext {\n readonly requestId: RequestId\n readonly method: string\n readonly url: string\n readonly path: string\n readonly params: Readonly<Record<string, string>>\n readonly headers: Readonly<Record<string, string | undefined>>\n readonly route: HttpRouteInfo | undefined\n readonly request: unknown\n readonly response: unknown\n readonly adapter: string\n readonly ip: string | undefined\n readonly protocol: 'http' | 'https'\n readonly #source: AdapterRequest\n readonly #plan: BodyPlan\n readonly #rawQuery: string\n #query: QueryRecord | undefined\n #state: Map<string | symbol, unknown> | undefined\n #responseHeaders: Record<string, HeaderValue> | undefined\n #body: unknown\n #files: Readonly<Record<string, readonly File[]>> | undefined\n #raw: Promise<Uint8Array> | undefined\n #streamed = false\n /** Stops the body stream opened for the request, unless it was read to its end or cancelled. */\n #stopBody: (() => void) | undefined\n #parsed: Promise<unknown> | undefined\n readonly #cookieSettings: CookieSettings\n #cookies: Readonly<Record<string, string>> | undefined\n #signed: Map<string, string | undefined> | undefined\n /** Cookies set on the response, by key (name, domain, path), with their `Set-Cookie` line. */\n #jar: Map<string, { readonly cookie: ResponseCookie; readonly line: string }> | undefined\n /** The response headers were handed to the adapter (cookies can no longer be set). */\n #committed = false\n /** The request is over: later aborts are ignored. */\n #completed = false\n #abortReason: RequestAbortedError | undefined\n #abortController: AbortController | undefined\n\n constructor(\n source: AdapterRequest,\n init: {\n readonly requestId: RequestId\n readonly adapter: string\n readonly route: HttpRouteInfo | undefined\n readonly params: Readonly<Record<string, string>>\n readonly body: BodyPlan\n /** Client address and protocol (`trustProxy`); default: the adapter's `ip` and `encrypted`. */\n readonly client?: { readonly ip: string | undefined; readonly protocol: 'http' | 'https' }\n /** Cookie defaults and signing key (plugin option `cookies`); default: secure defaults, no signing. */\n readonly cookies?: CookieSettings\n },\n ) {\n this.#source = source\n this.#plan = init.body\n this.#cookieSettings = init.cookies ?? DEFAULT_COOKIE_SETTINGS\n const { path, query } = splitUrl(source.url)\n this.#rawQuery = query\n this.requestId = init.requestId\n this.method = source.method\n this.url = source.url\n this.path = path\n this.params = init.params\n this.headers = source.headers\n this.route = init.route\n this.request = source.raw\n this.response = source.rawResponse\n this.adapter = init.adapter\n const connection = source.encrypted === true ? 'https' : 'http'\n this.ip = init.client === undefined ? source.ip : init.client.ip\n this.protocol = init.client === undefined ? connection : init.client.protocol\n }\n\n get query(): Readonly<QueryRecord> {\n this.#query ??= parseQuery(this.#rawQuery)\n return this.#query\n }\n\n get state(): Map<string | symbol, unknown> {\n this.#state ??= new Map()\n return this.#state\n }\n\n get body(): unknown {\n return this.#body\n }\n\n get files(): Readonly<Record<string, readonly File[]>> {\n return this.#files ?? NO_FILES\n }\n\n /** Maximum body size of the route, in bytes. */\n get bodyLimit(): number {\n return this.#plan.limit\n }\n\n get responseHeaders(): Readonly<Record<string, HeaderValue>> {\n return this.#responseHeaders ?? EMPTY_HEADERS\n }\n\n /** Whether {@link setHeader}/{@link appendHeader} were called. */\n get hasResponseHeaders(): boolean {\n return this.#responseHeaders !== undefined\n }\n\n header(name: string): string | undefined {\n return this.headers[name.toLowerCase()]\n }\n\n setHeader(name: string, value: HeaderValue): void {\n this.#responseHeaders ??= emptyRecord()\n this.#responseHeaders[name.toLowerCase()] = typeof value === 'string' ? value : [...value]\n }\n\n appendHeader(name: string, value: string): void {\n this.#responseHeaders ??= emptyRecord()\n const key = name.toLowerCase()\n const existing = this.#responseHeaders[key]\n if (existing === undefined) this.#responseHeaders[key] = value\n else this.#responseHeaders[key] = typeof existing === 'string' ? [existing, value] : [...existing, value]\n }\n\n get cookies(): Readonly<Record<string, string>> {\n this.#cookies ??= parseCookieHeader(this.headers['cookie'])\n return this.#cookies\n }\n\n signedCookie(name: string): string | undefined {\n const signer = this.#cookieSettings.signer\n if (signer === undefined) throw missingSecrets(`Cannot read the signed cookie ${JSON.stringify(String(name))}`)\n this.#signed ??= new Map()\n if (this.#signed.has(name)) return this.#signed.get(name)\n const value = verifySigned(signer, name, this.cookies[name])\n this.#signed.set(name, value)\n return value\n }\n\n setCookie(name: string, value: string, options: CookieOptions = {}): void {\n this.#addCookie({ name, value, options })\n }\n\n clearCookie(name: string, options: ClearCookieOptions = {}): void {\n this.#addCookie({ name, value: undefined, options })\n }\n\n get responseCookies(): readonly ResponseCookie[] {\n return this.#jar === undefined ? NO_COOKIES : [...this.#jar.values()].map(entry => entry.cookie)\n }\n\n /** The `Set-Cookie` lines of {@link setCookie} / {@link clearCookie}, with their keys, in order (internal). */\n get cookieLines(): readonly SerializedCookie[] {\n return this.#jar === undefined ? [] : [...this.#jar].map(([key, entry]) => ({ key, line: entry.line }))\n }\n\n #addCookie(cookie: ResponseCookie): void {\n if (this.#committed) {\n throw new Error(\n `Cannot set cookie ${JSON.stringify(String(cookie.name))}: the response headers were already sent`,\n )\n }\n if (cookie.options === null || typeof cookie.options !== 'object') {\n throw new TypeError(`Invalid cookie ${JSON.stringify(String(cookie.name))}: options must be an object`)\n }\n const options = cookie.value === undefined ? withoutLifetime(cookie.options) : cookie.options\n const frozen: ResponseCookie = Object.freeze({\n name: cookie.name,\n value: cookie.value,\n options: Object.freeze({ ...options }),\n })\n const { key, line } = serializeWith(frozen, this.#cookieSettings)\n this.#jar ??= new Map()\n this.#jar.set(key, { cookie: frozen, line })\n }\n\n get signal(): AbortSignal {\n if (this.#abortController === undefined) {\n const controller = new AbortController()\n this.#abortController = controller\n if (this.#abortReason !== undefined) controller.abort(this.#abortReason)\n else if (!this.#completed) this.#source.onAbort?.(() => this.abort('client'))\n }\n return this.#abortController.signal\n }\n\n /** Whether {@link signal} aborted (or will be created aborted). */\n get aborted(): boolean {\n return this.#abortReason !== undefined\n }\n\n /**\n * Aborts {@link signal} with a {@link RequestAbortedError} of `kind` (internal): at most once, and\n * never once the request is over ({@link complete}).\n */\n abort(kind: RequestAbortKind): void {\n if (this.#abortReason !== undefined || this.#completed) return\n const reason = new RequestAbortedError(kind)\n this.#abortReason = reason\n this.#abortController?.abort(reason)\n }\n\n /** The response headers are handed to the adapter: cookies can no longer be set (internal). */\n commit(): void {\n this.#committed = true\n }\n\n /** The request is over (response sent or abandoned): later aborts are ignored (internal). */\n complete(): void {\n this.#completed = true\n }\n\n rawBody(): Promise<Uint8Array> {\n if (this.#raw === undefined) {\n if (this.#streamed) return Promise.reject(alreadyStreamed())\n this.#raw = this.#source.readBody(this.#plan.limit)\n }\n return this.#raw\n }\n\n bodyStream(): ReadableStream<Uint8Array> {\n if (this.#raw !== undefined || this.#streamed) throw alreadyStreamed()\n this.#streamed = true\n return this.#openBodyStream()\n }\n\n /**\n * Called by the pipeline once the request is over: a body stream that was neither read to its\n * end nor cancelled (a handler that read the first chunk, then threw) is cancelled, which makes the\n * adapter discard the rest of the body, so that the connection can serve the next request.\n */\n releaseBody(): void {\n const stop = this.#stopBody\n this.#stopBody = undefined\n stop?.()\n }\n\n /** The body as a stream (see {@link releaseBody}). */\n #openBodyStream(): ReadableStream<Uint8Array> {\n const reader = openBodyStream(this.#source, this.#plan.limit).getReader()\n let controller: ReadableStreamDefaultController<Uint8Array> | undefined\n const settle = (): void => {\n this.#stopBody = undefined\n }\n this.#stopBody = (): void => {\n reader.cancel().catch(() => undefined)\n try {\n controller?.error(new Error('The request is over: its body can no longer be read'))\n } catch {\n // already closed or errored\n }\n }\n return new ReadableStream<Uint8Array>(\n {\n start(current) {\n controller = current\n },\n async pull(current) {\n let result: Awaited<ReturnType<typeof reader.read>>\n try {\n result = await reader.read()\n } catch (error) {\n settle()\n throw error\n }\n if (result.done) {\n settle()\n current.close()\n return\n }\n current.enqueue(result.value)\n },\n cancel(reason) {\n settle()\n return reader.cancel(reason)\n },\n },\n { highWaterMark: 0 },\n )\n }\n\n parseBody(): Promise<unknown> {\n this.#parsed ??= this.#parse()\n return this.#parsed\n }\n\n async #parse(): Promise<unknown> {\n const headers = this.headers\n const contentType = headers['content-type']\n const media = parseMediaType(contentType)\n if (media?.type === 'multipart/form-data') {\n checkContentEncoding(headers['content-encoding'])\n const policy = this.#plan.multipart\n let result: MultipartResult\n if (this.#raw === undefined) {\n if (this.#streamed) throw alreadyStreamed()\n this.#streamed = true\n result = await readMultipart(this.#openBodyStream(), contentType as string, policy)\n } else {\n result = parseMultipart(await this.#raw, contentType as string, policy)\n }\n this.#files = result.files\n this.#body = result.fields\n return result.fields\n }\n if (this.#plan.upload) {\n // upload routes only accept multipart bodies (an empty body means \"no file\"); the framing\n // headers decide, the adapter only for requests without them (Web `Request`s built in memory)\n const framed = headers['content-length'] !== undefined || headers['transfer-encoding'] !== undefined\n if (!(framed ? hasBody(headers) : this.#source.hasBody?.() === true)) return undefined\n throw new UnsupportedMediaTypeException(\n `Expected a multipart/form-data body${media === undefined ? '' : ` (received ${JSON.stringify(media.type)})`}`,\n )\n }\n const bytes = await this.rawBody()\n const body = await parseBody(bytes, contentType, headers['content-encoding'])\n this.#body = body\n return body\n }\n}\n\n/** The body as a stream: the adapter's `streamBody`, or the buffered body when it has none. */\nfunction openBodyStream(source: AdapterRequest, limit: number): ReadableStream<Uint8Array> {\n if (typeof source.streamBody === 'function') return source.streamBody(limit)\n return new ReadableStream<Uint8Array>(\n {\n async pull(controller) {\n const bytes = await source.readBody(limit)\n if (bytes.byteLength > 0) controller.enqueue(bytes)\n controller.close()\n },\n },\n { highWaterMark: 0 },\n )\n}\n\nfunction alreadyStreamed(): Error {\n return new Error(\n 'The request body was already read: bodyStream() cannot be combined with rawBody(), parseBody(), @Body() or upload parameters',\n )\n}\n\n/** Clearing cookies have no lifetime of their own (`Max-Age=0`) and are never signed. */\nfunction withoutLifetime(options: ClearCookieOptions): ClearCookieOptions {\n const { maxAge: _maxAge, expires: _expires, signed: _signed, ...rest } = options as CookieOptions\n return rest\n}\n\nconst EMPTY_HEADERS: Readonly<Record<string, HeaderValue>> = Object.freeze({})\nconst NO_COOKIES: readonly ResponseCookie[] = Object.freeze([])\nconst NO_FILES: Readonly<Record<string, readonly File[]>> = Object.freeze(emptyRecord<readonly File[]>())\n","/**\n * Marker decorators of `@znight/http`. Like every Znight decorator they do nothing at runtime: the\n * compiler extension `@znight/http/compiler` reads them from the source code and generates the\n * routes (`metadata.extensions.http`). Arguments marked _static_ must be statically evaluable\n * (literals, `const` references); _value_ arguments (schemas, guards...) may also be references to\n * exported bindings. See docs/internals/architecture.md §4.6 and §5.\n */\nimport type { ClassMarker, MethodMarker, ParameterMarker, Scope } from '@znight/core'\nimport type { HttpContext } from './context.ts'\nimport type { GuardClass, HttpInterceptorClass } from './interfaces.ts'\nimport type { ByteSize } from './size.ts'\nimport type { SseOptions } from './sse.ts'\nimport type { StandardSchemaV1 } from './standard-schema.ts'\nimport type { UploadedFileOptions, UploadedFilesOptions } from './uploads.ts'\n\nfunction marker(): void {\n // intentionally empty: decorators are compile-time markers\n}\n\nconst classMarker: ClassMarker = marker\nconst methodMarker: MethodMarker = marker\nconst parameterMarker: ParameterMarker = marker\nconst classOrMethodMarker: ClassMarker & MethodMarker = marker\n\n/** Options of {@link Controller} (static). */\nexport interface ControllerOptions {\n /** Base path of every route of the controller (`/users`). Default: `/`. */\n readonly path?: string\n /** Provider scope. Default: `singleton`; `request` creates one controller per request. */\n readonly scope?: Scope\n}\n\n/**\n * Declares a controller: a provider (singleton by default) whose decorated methods are routes.\n *\n * ```ts\n * @Controller('/users')\n * export class UserController {\n * constructor(private readonly users: UserService) {}\n *\n * @Get('/:id')\n * find(@Param('id') id: number) {\n * return this.users.findById(id)\n * }\n * }\n * ```\n *\n * @param pathOrOptions static: base path, or `{ path?, scope? }`.\n */\nexport function Controller(_pathOrOptions?: string | ControllerOptions): ClassMarker {\n return classMarker\n}\n\n/** `GET` route. `path` (static) is relative to the controller path; default: the controller path. */\nexport function Get(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `POST` route (default status 201). */\nexport function Post(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `PUT` route. */\nexport function Put(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `PATCH` route. */\nexport function Patch(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `DELETE` route. */\nexport function Delete(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `HEAD` route (`GET` routes already answer `HEAD` requests). */\nexport function Head(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `OPTIONS` route (paths without one answer `OPTIONS` with `204` and an `allow` header). */\nexport function Options(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** Route for GET, HEAD, POST, PUT, PATCH, DELETE and OPTIONS (methods without a dedicated route on the same path). */\nexport function All(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/**\n * A `GET` route serving an event stream (Server-Sent Events). The handler returns an\n * `AsyncIterable`, an `Iterable` or a `ReadableStream` of `SseEvent` (`{ data, event, id, retry,\n * comment }`), or an `HttpResponse` / exception for other outcomes (204 stops `EventSource`). The\n * plugin frames the events, sends heartbeats, stops the source when the client leaves (`ctx.signal`)\n * and closes the stream gracefully on shutdown.\n *\n * ```ts\n * @Sse('/:id/events', { retry: 5_000 })\n * async events(@Param('id') id: string, @Ctx() ctx: HttpContext): Promise<AsyncIterable<SseEvent<OrderEvent>>> {\n * if ((await this.orders.find(id)) === undefined) throw new NotFoundException() // pre-flight checks first\n * return this.hub.subscribe(id, { signal: ctx.signal })\n * }\n * ```\n *\n * Prefer an `async` method returning the source over an `async *` generator: the body of a\n * generator only runs once the 200 and the headers are sent.\n *\n * @param path static: route path (relative to the controller path).\n * @param options static: `{ heartbeat?, retry?, maxDuration? }` (see `SseOptions`).\n */\nexport function Sse(path?: string, options?: SseOptions): MethodMarker\nexport function Sse(options: SseOptions): MethodMarker\nexport function Sse(_pathOrOptions?: string | SseOptions, _options?: SseOptions): MethodMarker {\n return methodMarker\n}\n\n/**\n * Injects a route parameter, coerced to the parameter type (`string`, `number`, `boolean`,\n * `bigint`, `Date`, literal unions) or validated with `schema`. Without arguments: every parameter\n * (`Record<string, string>`).\n *\n * ```ts\n * @Get('/:id')\n * find(@Param('id') id: number) {}\n * ```\n *\n * @param name static: name of a `:param` of the route path.\n * @param schema value: a Standard Schema validating the raw string (its output is injected).\n */\nexport function Param(): ParameterMarker\nexport function Param(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Param(schema: StandardSchemaV1): ParameterMarker\nexport function Param(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a query parameter (coerced to the parameter type; `T[]` accepts repeated and single\n * values; optional when the parameter is optional or has a default) or, without name, the whole\n * query (`Record<string, string | string[]>`), typically validated with a schema.\n *\n * ```ts\n * list(@Query('page') page = 1, @Query('tag') tags: string[] = []) {}\n * search(@Query(SearchQuery) query: SearchQuery) {}\n * ```\n *\n * @param name static: query key.\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function Query(): ParameterMarker\nexport function Query(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Query(schema: StandardSchemaV1): ParameterMarker\nexport function Query(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a request cookie (decoded, coerced to the parameter type like `@Headers`: `string`,\n * `number`, `boolean`, `bigint`, `Date`, literal unions, enums, branded primitives) or validated\n * with `schema`; without name, every cookie (`Record<string, string>`). An absent cookie answers 400\n * `Missing cookie \"name\"` unless the parameter is optional. Error messages never echo the value.\n *\n * ```ts\n * // a stale or forged value falls back instead of answering 400 until the cookie expires\n * export const Theme = z.enum(['light', 'dark']).catch('light')\n *\n * read(@Cookie('theme', Theme) theme: 'light' | 'dark', @Cookie('visits') visits = 0) {}\n * ```\n *\n * @param name static: cookie name (an RFC 9110 token).\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function Cookie(): ParameterMarker\nexport function Cookie(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Cookie(schema: StandardSchemaV1): ParameterMarker\nexport function Cookie(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the **verified** value of a signed cookie (set with `{ signed: true }`, plugin option\n * `cookies.secrets`): absent, tampered or signed with a retired key, the cookie does not exist\n * (400 `Missing cookie \"name\"` unless the parameter is optional). Same coercion and schema rules as\n * {@link Cookie}. A route reading a signed cookie fails the boot when `cookies.secrets` is not set.\n *\n * @param name static: cookie name.\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function SignedCookie(_name: string, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the parsed request body, validated with `schema` when given (the schema output is\n * injected: defaults, transforms, stripped keys). A non-primitive body without schema is reported\n * by the compiler (ZNIGHT017).\n *\n * @param schema value: a Standard Schema (Zod, Valibot, ArkType...).\n */\nexport function Body(_schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a request header (case-insensitive `name`, coerced to the parameter type) or, without\n * name, every header (`Record<string, string | undefined>`).\n *\n * @param name static: header name.\n */\nexport function Headers(_name?: string): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a file of a `multipart/form-data` body as a standard `File` (`name`, `type`, `size`,\n * `arrayBuffer()`, `text()`, `stream()`), held in memory. The route parses multipart bodies before\n * its interceptors, enforcing the options while the body is read: a file above `maxSize` answers\n * 413, a refused type 415, a second file in the field or a file in an undeclared field 400, a\n * missing required file 400, a non-multipart body 415. `@Body()` receives the text fields.\n *\n * ```ts\n * @Post('/avatar')\n * upload(@UploadedFile('avatar', { maxSize: '2mb', mimeTypes: ['image/png', 'image/jpeg'] }) avatar: File) {}\n *\n * @Post('/attachment')\n * attach(@UploadedFile('file') file?: File) {} // optional: undefined when absent\n * ```\n *\n * `File.name` and `File.type` are sent by the client: never trust them (see the README, \"Files\").\n *\n * @param field static: the multipart field; omitted: the single file of the body, whatever its field.\n * @param options static: `{ required?, maxSize?, mimeTypes? }`.\n */\nexport function UploadedFile(field?: string, options?: UploadedFileOptions): ParameterMarker\nexport function UploadedFile(options: UploadedFileOptions): ParameterMarker\nexport function UploadedFile(\n _fieldOrOptions?: string | UploadedFileOptions,\n _options?: UploadedFileOptions,\n): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the files of a multipart field (`File[]`, in body order), or of every field without\n * `field`. Same rules as {@link UploadedFile}; above `maxFiles` files the request answers 413. An\n * optional parameter (`files?: File[]`, `required: false`) receives an empty array when no file is\n * sent.\n *\n * ```ts\n * @Post('/documents')\n * add(@UploadedFiles('documents', { maxFiles: 5, maxSize: '20mb', mimeTypes: ['application/pdf'] }) documents: File[]) {}\n * ```\n *\n * @param field static: the multipart field; omitted: the files of every field.\n * @param options static: `{ required?, maxSize?, maxFiles?, mimeTypes? }`.\n */\nexport function UploadedFiles(field?: string, options?: UploadedFilesOptions): ParameterMarker\nexport function UploadedFiles(options: UploadedFilesOptions): ParameterMarker\nexport function UploadedFiles(\n _fieldOrOptions?: string | UploadedFilesOptions,\n _options?: UploadedFilesOptions,\n): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Sets the maximum request body size of a route, or of every route of a controller (the route wins),\n * over the plugin `bodyLimit` (and over the limit computed for upload routes). `Infinity` disables\n * the limit, e.g. for a route streaming its body with `ctx.bodyStream()`.\n *\n * ```ts\n * @Put('/files/:name')\n * @BodyLimit('5gb')\n * async store(@Param('name') name: string, @Ctx() ctx: HttpContext) {\n * await pipeline(Readable.fromWeb(ctx.bodyStream()), createWriteStream(join(DIR, safeName(name))))\n * }\n * ```\n *\n * @param size static: bytes (`10_485_760`) or a size with a unit (`'10mb'`, `'512kb'`; `kb` = 1024 bytes).\n */\nexport function BodyLimit(_size: ByteSize): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/** Injects the native request of the adapter (escape hatch; the compiler warns). */\nexport function Req(): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the native response of the adapter (escape hatch; the compiler warns). The handler then\n * writes the response itself, and must have finished when its promise settles.\n */\nexport function Res(): ParameterMarker {\n return parameterMarker\n}\n\n/** Injects the {@link HttpContext} of the request. */\nexport function Ctx(): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Sets the status of successful responses (wins over `HttpResponse.status` and the defaults).\n *\n * @param status static: an integer between 100 and 599.\n */\nexport function HttpCode(_status: number): MethodMarker {\n return methodMarker\n}\n\n/**\n * Adds a header to successful responses. Repeat the decorator for several headers.\n *\n * @param name static: header name.\n * @param value static: header value.\n */\nexport function Header(_name: string, _value: string): MethodMarker {\n return methodMarker\n}\n\n/**\n * Protects a controller (every route) or a route with guards (providers implementing\n * {@link CanActivate}). Order: global guards → controller guards → route guards, each list in\n * declaration order.\n *\n * @param guards value: guard classes.\n */\nexport function UseGuard(..._guards: [GuardClass, ...GuardClass[]]): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/**\n * Wraps a controller (every route) or a route with interceptors (providers implementing\n * {@link HttpInterceptor}). Order: global → controller → route, the first one being the outermost.\n *\n * @param interceptors value: interceptor classes.\n */\nexport function UseInterceptor(\n ..._interceptors: [HttpInterceptorClass, ...HttpInterceptorClass[]]\n): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/**\n * Validates the request body with `schema`: sugar for `@Body(schema)` on the body parameter (using\n * both is ZNIGHT005).\n *\n * @param schema value: a Standard Schema.\n */\nexport function Validate(_schema: StandardSchemaV1): MethodMarker {\n return methodMarker\n}\n\n/** Arguments of a route decorator: optional when `T` accepts `undefined` or is `true` (flag decorators). */\nexport type RouteDecoratorArgs<T> = [T] extends [true] ? [value?: T] : undefined extends T ? [value?: T] : [value: T]\n\n/** Options of {@link createRouteDecorator} (static). */\nexport interface RouteDecoratorOptions {\n /**\n * Decision group. Decorators of a group are alternatives: one per controller or route, and the\n * route's decision replaces the controller's. Default: the key (the decorator is its own group).\n * A letter followed by letters, digits, `_`, `.` or `-`.\n */\n readonly group?: string\n /**\n * Every route must carry a decision of the group: ZNIGHT023 at build time when a route has none,\n * and at boot when no guard of its chain enforces it (see {@link GuardClass}). All the decorators\n * of a group must agree. Default `false`.\n */\n readonly required?: boolean\n}\n\n/** The data part of a route decorator: what guards list in `static enforces`. */\nexport interface RouteDecoratorInfo {\n /** Key of the value in `route.meta`. */\n readonly key: string\n /** Decision group (`options.group ?? key`). */\n readonly group: string\n /** Every route must carry a decision of the group. */\n readonly required: boolean\n}\n\n/**\n * A route metadata entry given as data rather than as a decorator: the `meta` of plugin routes\n * (`[Public.meta()]`). Built by {@link RouteDecorator.meta}.\n */\nexport interface RouteMetaEntry<T = unknown> {\n readonly key: string\n readonly value: T\n /** Decision group. Default: the key. */\n readonly group?: string\n /** Default `false`. */\n readonly required?: boolean\n}\n\n/** A user-defined route metadata decorator created with {@link createRouteDecorator}. */\nexport interface RouteDecorator<T> extends RouteDecoratorInfo {\n (...args: RouteDecoratorArgs<T>): ClassMarker & MethodMarker\n /**\n * The value of the current route, if set. Reads the effective metadata: the route's decision of\n * a group wins over the controller's.\n */\n get(ctx: HttpContext): T | undefined\n /**\n * The same metadata as data (`{ key, value, group, required }`), for routes that are not compiled\n * controllers (plugin routes: `OpenApiPlugin.configure({ meta: [Public.meta()] })`). The value is\n * `true` when omitted, like `@Public()`.\n */\n meta(...args: RouteDecoratorArgs<T>): RouteMetaEntry<T>\n}\n\n/**\n * Grammar of an explicit decision group name (internal; the compiler extension has the same rule).\n * A decorator without `group` is its own group, named after its key: any non-empty key is valid.\n */\nexport const GROUP_NAME: RegExp = /^[A-Za-z][\\w.-]*$/\n\n/** `true` when `group` is a valid group of `key`: the key itself (the default) or a valid name. */\nexport function isGroupOf(group: unknown, key: string): group is string {\n return typeof group === 'string' && (group === key || GROUP_NAME.test(group))\n}\n\n/**\n * Creates a metadata decorator for controllers and routes. The compiler stores its argument\n * (`value`, statically evaluated or an exported reference; `true` when omitted) in\n * `meta[key]`, read by guards and interceptors through `ctx.route.meta` or `decorator.get(ctx)`.\n *\n * ```ts\n * export const Public = createRouteDecorator('public', { group: 'access', required: true })\n * export const Authenticated = createRouteDecorator('authenticated', { group: 'access', required: true })\n * export const Roles = createRouteDecorator<readonly string[]>('roles', { group: 'access', required: true })\n *\n * @Controller('/books')\n * @Roles(['reader']) // the decision of every route of the controller...\n * export class BookController {\n * @Get('/:id/cover')\n * @Public() // ...unless the route has its own decision of the group\n * cover() {}\n * }\n *\n * // in a guard\n * if (Public.get(ctx)) return true\n * const roles = Roles.get(ctx) ?? []\n * ```\n *\n * Decorators of one `group` are alternatives: two of them on the same class or method are\n * ZNIGHT005, and the route's decision replaces the controller's (without `group`, each decorator is\n * its own group: the route value wins over the controller value). With `required: true`, a route\n * without decision fails the build (ZNIGHT023).\n *\n * @param key static: unique metadata key.\n * @param options static: `{ group?, required? }`.\n */\nexport function createRouteDecorator<T = true>(key: string, options?: RouteDecoratorOptions): RouteDecorator<T> {\n if (typeof key !== 'string' || key === '') {\n throw new TypeError(`createRouteDecorator(): the key must be a non-empty string (received ${String(key)})`)\n }\n if (options !== undefined && (options === null || typeof options !== 'object')) {\n throw new TypeError(`createRouteDecorator('${key}'): options must be an object { group?, required? }`)\n }\n // the grammar applies to an explicit group only: without one, any key is its own group (as before groups)\n const group = options?.group ?? key\n if (!isGroupOf(group, key)) {\n throw new TypeError(\n `createRouteDecorator('${key}'): \"group\" must be a name made of letters, digits, _ . - starting with a letter (received ${String(group)})`,\n )\n }\n const required = options?.required ?? false\n if (typeof required !== 'boolean') {\n throw new TypeError(`createRouteDecorator('${key}'): \"required\" must be a boolean (received ${String(required)})`)\n }\n const decorator = (..._args: RouteDecoratorArgs<T>): ClassMarker & MethodMarker => classOrMethodMarker\n return Object.assign(decorator, {\n key,\n group,\n required,\n get: (ctx: HttpContext): T | undefined => ctx.route?.meta[key] as T | undefined,\n meta: (...args: RouteDecoratorArgs<T>): RouteMetaEntry<T> =>\n Object.freeze({ key, value: (args.length === 0 ? true : args[0]) as T, group, required }),\n })\n}\n","/**\n * `EventChannel`: a bounded bridge from push-based producers (an event bus, an `EventEmitter`, a\n * database listener) to a pull-based `AsyncIterable` (an SSE source, a GraphQL subscription), with\n * no dependency.\n */\n\n/** Options of {@link EventChannel}. */\nexport interface EventChannelOptions {\n /** Buffered items before `overflow` applies. Default: 1 000. */\n readonly capacity?: number\n /**\n * What happens when an item is pushed into a full buffer:\n * - `'drop-oldest'` (default): the oldest buffered item is discarded;\n * - `'drop-newest'`: the item is discarded (`push()` returns false);\n * - `'close'`: the item is discarded and the channel closes after the buffered items (an SSE\n * client then reconnects and resumes with `Last-Event-ID`).\n */\n readonly overflow?: 'drop-oldest' | 'drop-newest' | 'close'\n /** Closes the channel when aborted (pass `ctx.signal`). */\n readonly signal?: AbortSignal\n}\n\nconst DEFAULT_CAPACITY = 1_000\n\n/** A pending `next()`. */\ninterface Waiter<T> {\n resolve(result: IteratorResult<T>): void\n reject(error: unknown): void\n}\n\n/**\n * A bounded, single-consumer queue that is an `AsyncIterable`: producers `push()`, the consumer\n * iterates. A pending `next()` resolves with `{ done: true }` as soon as the channel closes for any\n * reason, so an SSE handler built on a channel always stops when its client leaves.\n *\n * ```ts\n * const channel = new EventChannel<SseEvent<Order>>({ capacity: 256, overflow: 'close', signal: ctx.signal })\n * const unsubscribe = bus.on('order', order => channel.push({ event: 'order', data: order }))\n * channel.onClose(unsubscribe)\n * return channel // from an @Sse handler\n * ```\n */\nexport class EventChannel<T> implements AsyncIterable<T> {\n readonly #capacity: number\n readonly #overflow: 'drop-oldest' | 'drop-newest' | 'close'\n readonly #buffer: T[] = []\n readonly #waiters: Waiter<T>[] = []\n readonly #listeners: (() => void)[] = []\n readonly #signal: AbortSignal | undefined\n #closed = false\n #failure: { readonly error: unknown } | undefined\n #iterating = false\n #onAbort: (() => void) | undefined\n\n constructor(options: EventChannelOptions = {}) {\n if (options === null || typeof options !== 'object') {\n throw new TypeError('EventChannel: options must be an object { capacity?, overflow?, signal? }')\n }\n const capacity = options.capacity ?? DEFAULT_CAPACITY\n if (!(Number.isSafeInteger(capacity) && capacity >= 1) && capacity !== Number.POSITIVE_INFINITY) {\n throw new TypeError(`EventChannel: capacity must be a positive integer (received ${String(capacity)})`)\n }\n const overflow = options.overflow ?? 'drop-oldest'\n if (overflow !== 'drop-oldest' && overflow !== 'drop-newest' && overflow !== 'close') {\n throw new TypeError(\n `EventChannel: overflow must be 'drop-oldest', 'drop-newest' or 'close' (received ${String(overflow)})`,\n )\n }\n this.#capacity = capacity\n this.#overflow = overflow\n const signal = options.signal\n this.#signal = signal\n if (signal !== undefined) {\n if (signal.aborted) {\n this.#closed = true\n } else {\n this.#onAbort = (): void => this.close()\n signal.addEventListener('abort', this.#onAbort, { once: true })\n }\n }\n }\n\n /** Buffered items. */\n get size(): number {\n return this.#buffer.length\n }\n\n /** Whether the channel no longer accepts items (closed, failed, overflowed, aborted, returned). */\n get closed(): boolean {\n return this.#closed\n }\n\n /** Buffers an item (or hands it to a waiting consumer). Returns false when it was dropped or the channel is closed. */\n push(item: T): boolean {\n if (this.#closed) return false\n const waiter = this.#waiters.shift()\n if (waiter !== undefined) {\n waiter.resolve({ done: false, value: item })\n return true\n }\n if (this.#buffer.length < this.#capacity) {\n this.#buffer.push(item)\n return true\n }\n switch (this.#overflow) {\n case 'drop-oldest':\n this.#buffer.shift()\n this.#buffer.push(item)\n return true\n case 'drop-newest':\n return false\n default:\n this.close()\n return false\n }\n }\n\n /** Ends the iteration after the buffered items. Idempotent. */\n close(): void {\n if (this.#closed) return\n this.#closed = true\n this.#settle()\n }\n\n /** Makes the iteration throw `error` after the buffered items (ignored once closed). */\n fail(error: unknown): void {\n if (this.#closed) return\n this.#failure = { error }\n this.#closed = true\n this.#settle()\n }\n\n /**\n * Calls `listener` once when the channel closes (close, fail, overflow, signal, consumer\n * `return()`); immediately when it is already closed.\n */\n onClose(listener: () => void): void {\n if (typeof listener !== 'function') throw new TypeError('EventChannel.onClose() expects a function')\n if (this.#closed) listener()\n else this.#listeners.push(listener)\n }\n\n /**\n * The iterator of the single consumer (a second call throws). Its `return()` closes the channel\n * and resolves at once, even while a `next()` waits.\n */\n [Symbol.asyncIterator](): AsyncIterator<T> {\n if (this.#iterating) throw new TypeError('EventChannel: a channel has a single consumer (already iterated)')\n this.#iterating = true\n return {\n next: (): Promise<IteratorResult<T>> => this.#next(),\n return: (): Promise<IteratorResult<T>> => {\n this.#buffer.length = 0\n this.close()\n return Promise.resolve({ done: true, value: undefined })\n },\n }\n }\n\n #next(): Promise<IteratorResult<T>> {\n if (this.#buffer.length > 0) return Promise.resolve({ done: false, value: this.#buffer.shift() as T })\n if (this.#closed) {\n const failure = this.#failure\n if (failure !== undefined) {\n this.#failure = undefined\n return Promise.reject(failure.error)\n }\n return Promise.resolve({ done: true, value: undefined })\n }\n return new Promise((resolve, reject) => this.#waiters.push({ resolve, reject }))\n }\n\n /** The channel just closed: release waiting consumers, the signal listener and notify `onClose` listeners. */\n #settle(): void {\n if (this.#onAbort !== undefined) {\n this.#signal?.removeEventListener('abort', this.#onAbort)\n this.#onAbort = undefined\n }\n // waiters only exist while the buffer is empty\n for (const waiter of this.#waiters.splice(0)) {\n const failure = this.#failure\n if (failure === undefined) {\n waiter.resolve({ done: true, value: undefined })\n } else {\n this.#failure = undefined\n waiter.reject(failure.error)\n }\n }\n for (const listener of this.#listeners.splice(0)) {\n try {\n listener()\n } catch {\n // a failing listener must not break the producer that closed the channel\n }\n }\n }\n}\n","/**\n * File downloads (`HttpResponse.file()`): files on disk (sent as lazily read, file-backed `Blob`s:\n * `fs.openAsBlob()`) or `Blob` objects, with `Content-Length`, `Content-Type`, `Last-Modified` /\n * `ETag`, conditional requests (304 / 412), single byte ranges (206 / 416) and RFC 6266\n * `Content-Disposition` headers.\n */\nimport type { HeaderValue } from './exceptions.ts'\n\nimport { openAsBlob } from 'node:fs'\nimport { realpath, stat } from 'node:fs/promises'\nimport { basename, isAbsolute, relative, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport { HttpException, NotFoundException } from './exceptions.ts'\nimport { contentTypeFor, OCTET_STREAM } from './mime.ts'\nimport { emptyRecord } from './utils.ts'\n\n/** How a file is presented to the client (`Content-Disposition`). */\nexport type ContentDispositionType = 'attachment' | 'inline'\n\n/** Options of `HttpResponse.file()`. */\nexport interface FileResponseOptions {\n /**\n * Name proposed to the client in `Content-Disposition` (any Unicode name; path separators are\n * removed). Setting it makes the response an `attachment` unless `disposition` says otherwise.\n */\n readonly filename?: string\n /**\n * Media type of the response. Default: the type of the `Blob`, else looked up from the extension\n * of `filename` / of the path (small built-in table, text types with `charset=utf-8`), else\n * `application/octet-stream`.\n */\n readonly contentType?: string\n /**\n * `attachment` (download) or `inline` (displayed by the browser). Default: `attachment` when\n * `filename` is set, otherwise no `Content-Disposition` header. Without `filename`, the file name\n * (path basename, `File.name`) is used.\n */\n readonly disposition?: ContentDispositionType\n /**\n * Directory the path is resolved in. The resolved file (symbolic links followed) must stay inside\n * it: `..` segments, absolute paths and links escaping the directory answer 404. Always set it\n * when the path comes from the request.\n */\n readonly root?: string\n /**\n * With `root`: whether files or directories whose name starts with a dot (`.env`, `.git/config`)\n * may be sent. Default: `'deny'` (404).\n */\n readonly dotfiles?: 'allow' | 'deny'\n}\n\n/**\n * The body of `HttpResponse.file()`: a file on disk or a `Blob`, resolved by the pipeline when the\n * response is sent (stat, conditional request, range).\n */\nexport class FileBody {\n /** Path (`string` / `file:` URL) or `Blob` / `File`. */\n readonly source: string | URL | Blob\n readonly options: FileResponseOptions\n\n constructor(source: string | URL | Blob, options: FileResponseOptions = {}) {\n if (typeof source !== 'string' && !(source instanceof URL) && !(source instanceof Blob)) {\n throw new TypeError('HttpResponse.file() expects a path (string or file: URL), a Blob or a File')\n }\n if (source instanceof URL && source.protocol !== 'file:') {\n throw new TypeError(`HttpResponse.file() expects a file: URL (received ${source.protocol})`)\n }\n const disposition = options.disposition\n if (disposition !== undefined && disposition !== 'attachment' && disposition !== 'inline') {\n throw new TypeError(`Invalid disposition ${JSON.stringify(disposition)} (expected \"attachment\" or \"inline\")`)\n }\n if (options.dotfiles !== undefined && options.dotfiles !== 'allow' && options.dotfiles !== 'deny') {\n throw new TypeError(`Invalid dotfiles ${JSON.stringify(options.dotfiles)} (expected \"allow\" or \"deny\")`)\n }\n this.source = source\n this.options = options\n }\n}\n\n/** Whether `value` is a {@link FileBody}. */\nexport function isFileBody(value: unknown): value is FileBody {\n return value instanceof FileBody\n}\n\n/** The request facts a file response depends on. */\nexport interface FileRequest {\n readonly method: string\n readonly headers: Readonly<Record<string, string | undefined>>\n}\n\n/** A resolved file response (before route headers and status precedence). */\nexport interface ResolvedFile {\n /** 200, 206 (range) or 304 (not modified). */\n readonly status: 200 | 206 | 304\n readonly headers: Record<string, HeaderValue>\n /**\n * The bytes to send, as a `Blob` (file-backed for files on disk: read lazily, sent with its size;\n * `sendfile` on Bun); `null` for 304, HEAD requests and empty files.\n */\n readonly body: Blob | null\n}\n\n/** Attempts to open a file whose size changes between `stat` and `openAsBlob` (concurrent writes). */\nconst OPEN_ATTEMPTS = 3\n\n/**\n * Resolves a file response for a request: opens the file, evaluates the preconditions\n * (`If-Match`, `If-Unmodified-Since` → 412; `If-None-Match`, `If-Modified-Since` → 304) and the\n * `Range` header (single range, honouring `If-Range`; 416 when unsatisfiable).\n *\n * @throws NotFoundException (404) when the file does not exist, is not a regular file or escapes `root`;\n * HttpException 412 / 416.\n */\nexport function resolveFile(file: FileBody, request: FileRequest): Promise<ResolvedFile> {\n if (!(file.source instanceof Blob)) return resolvePath(file, request)\n try {\n return Promise.resolve(resolveBlob(file, file.source, request))\n } catch (error) {\n return Promise.reject(error)\n }\n}\n\nasync function resolvePath(file: FileBody, request: FileRequest): Promise<ResolvedFile> {\n const target = await locate(file.source as string | URL, file.options.root, file.options.dotfiles !== 'allow')\n for (let attempt = 1; ; attempt++) {\n let stats: Awaited<ReturnType<typeof stat>>\n try {\n stats = await stat(target)\n } catch (error) {\n throw notFound(error)\n }\n if (!stats.isFile()) throw new NotFoundException('File not found')\n const name = basename(target)\n const plan = planResponse(\n {\n size: stats.size,\n lastModified: stats.mtimeMs,\n contentType: contentTypeOf(file.options, undefined, name),\n disposition: dispositionOf(file.options, name),\n },\n request,\n )\n if (plan.body === undefined) return { ...plan, body: null }\n let blob: Blob\n try {\n blob = await openAsBlob(target)\n } catch (error) {\n throw notFound(error)\n }\n // the file was replaced or written to since `stat`: describe the new content\n if (blob.size !== stats.size) {\n if (attempt < OPEN_ATTEMPTS) continue\n throw new Error(`The file ${name} keeps changing while being sent`)\n }\n return { ...plan, body: slice(blob, plan.body) }\n }\n}\n\nfunction resolveBlob(file: FileBody, blob: Blob, request: FileRequest): ResolvedFile {\n const name = blob instanceof File && blob.name !== '' ? blob.name : undefined\n const info: Representation = {\n size: blob.size,\n lastModified: blob instanceof File ? blob.lastModified : undefined,\n contentType: contentTypeOf(file.options, blob.type, name),\n disposition: dispositionOf(file.options, name),\n }\n const plan = planResponse(info, request)\n return { ...plan, body: plan.body === undefined ? null : slice(blob, plan.body) }\n}\n\n/** The bytes `start..end` (inclusive) of a blob (the blob itself when complete). */\nfunction slice(blob: Blob, { start, end }: ByteRange): Blob {\n return start === 0 && end === blob.size - 1 ? blob : blob.slice(start, end + 1)\n}\n\n/** Resolves the path to open, enforcing `root` (and hiding dotfiles inside it). */\nasync function locate(source: string | URL, root: string | undefined, hideDotfiles: boolean): Promise<string> {\n const path = source instanceof URL ? fileURLToPath(source) : source\n if (path === '' || path.includes('\\0')) throw new NotFoundException('File not found')\n if (root === undefined) return resolve(path)\n const base = resolve(root)\n const target = resolve(base, path)\n if (!isInside(base, target, hideDotfiles)) throw new NotFoundException('File not found')\n // symbolic links: the real file must be inside the real root\n let realBase: string\n let realTarget: string\n try {\n ;[realBase, realTarget] = await Promise.all([realpath(base), realpath(target)])\n } catch (error) {\n throw notFound(error)\n }\n if (!isInside(realBase, realTarget, hideDotfiles)) throw new NotFoundException('File not found')\n return realTarget\n}\n\nfunction isInside(base: string, target: string, hideDotfiles: boolean): boolean {\n const path = relative(base, target)\n if (path === '' || isAbsolute(path)) return false\n const segments = path.split(/[\\\\/]/)\n if (segments[0] === '..') return false\n return !hideDotfiles || !segments.some(segment => segment.startsWith('.'))\n}\n\nconst MISSING = new Set(['ENOENT', 'ENOTDIR', 'EISDIR', 'ENAMETOOLONG', 'ELOOP', 'ERR_INVALID_ARG_VALUE'])\n\nfunction notFound(error: unknown): unknown {\n const code = (error as { code?: unknown } | null)?.code\n return typeof code === 'string' && MISSING.has(code)\n ? new NotFoundException('File not found', undefined, { cause: error })\n : error\n}\n\n// -------------------------------------------------------------------------------------------------\n// Representation metadata, preconditions and ranges\n// -------------------------------------------------------------------------------------------------\n\ninterface Representation {\n readonly size: number\n /** Milliseconds since the epoch, when known. */\n readonly lastModified: number | undefined\n readonly contentType: string\n readonly disposition: string | undefined\n}\n\ninterface Plan {\n readonly status: 200 | 206 | 304\n readonly headers: Record<string, HeaderValue>\n /** Inclusive byte range to send; `undefined`: no body (304, HEAD, empty file). */\n readonly body: { readonly start: number; readonly end: number } | undefined\n}\n\nfunction planResponse(info: Representation, request: FileRequest): Plan {\n const validators = emptyRecord<HeaderValue>()\n const etag = info.lastModified === undefined ? undefined : entityTag(info.size, info.lastModified)\n const seconds = info.lastModified === undefined ? undefined : Math.floor(info.lastModified / 1000)\n if (etag !== undefined) validators['etag'] = etag\n if (seconds !== undefined) validators['last-modified'] = new Date(seconds * 1000).toUTCString()\n\n const precondition = evaluatePreconditions(request, etag, seconds)\n if (precondition === 412) throw new HttpException(412, 'Precondition Failed', undefined, { headers: validators })\n if (precondition === 304) return { status: 304, headers: validators, body: undefined }\n\n const headers = emptyRecord<HeaderValue>()\n headers['content-type'] = info.contentType\n if (info.disposition !== undefined) headers['content-disposition'] = info.disposition\n headers['accept-ranges'] = 'bytes'\n Object.assign(headers, validators)\n\n const range = request.method === 'GET' ? requestedRange(request.headers, info.size, etag, seconds) : undefined\n if (range === 'unsatisfiable') {\n throw new HttpException(416, `Range Not Satisfiable (size: ${info.size} bytes)`, undefined, {\n headers: { 'content-range': `bytes */${info.size}`, 'accept-ranges': 'bytes' },\n })\n }\n if (range !== undefined) {\n headers['content-range'] = `bytes ${range.start}-${range.end}/${info.size}`\n headers['content-length'] = String(range.end - range.start + 1)\n return { status: 206, headers, body: request.method === 'HEAD' ? undefined : range }\n }\n headers['content-length'] = String(info.size)\n const body = request.method === 'HEAD' || info.size === 0 ? undefined : { start: 0, end: info.size - 1 }\n return { status: 200, headers, body }\n}\n\n/** Strong entity tag from the size and modification time (like nginx: `\"<mtime>-<size>\"`, hex). */\nfunction entityTag(size: number, lastModified: number): string {\n return `\"${Math.floor(lastModified).toString(16)}-${size.toString(16)}\"`\n}\n\n/** RFC 9110 §13.2.2: 412, 304 or `undefined` (proceed). */\nfunction evaluatePreconditions(\n request: FileRequest,\n etag: string | undefined,\n seconds: number | undefined,\n): 304 | 412 | undefined {\n const headers = request.headers\n const safe = request.method === 'GET' || request.method === 'HEAD'\n const ifMatch = headers['if-match']\n if (ifMatch === undefined) {\n const since = httpDate(headers['if-unmodified-since'])\n if (since !== undefined && seconds !== undefined && seconds > since) return 412\n } else {\n if (!matchesEntityTag(ifMatch, etag, true)) return 412\n }\n const ifNoneMatch = headers['if-none-match']\n if (ifNoneMatch !== undefined) {\n if (matchesEntityTag(ifNoneMatch, etag, false)) return safe ? 304 : 412\n } else if (safe) {\n const since = httpDate(headers['if-modified-since'])\n if (since !== undefined && seconds !== undefined && seconds <= since) return 304\n }\n return undefined\n}\n\n/** Whether an `If-Match` / `If-None-Match` list matches `etag` (`*` matches any existing file). */\nfunction matchesEntityTag(header: string, etag: string | undefined, strong: boolean): boolean {\n if (header.trim() === '*') return true\n if (etag === undefined) return false\n for (const raw of header.split(',')) {\n const candidate = raw.trim()\n if (candidate === '') continue\n if (strong) {\n if (candidate === etag) return true\n } else if (stripWeak(candidate) === stripWeak(etag)) {\n return true\n }\n }\n return false\n}\n\nfunction stripWeak(tag: string): string {\n return tag.startsWith('W/') ? tag.slice(2) : tag\n}\n\n/** Seconds of an HTTP date, `undefined` when absent or invalid. */\nfunction httpDate(value: string | undefined): number | undefined {\n if (value === undefined) return undefined\n const time = Date.parse(value)\n return Number.isNaN(time) ? undefined : Math.floor(time / 1000)\n}\n\n/** The range to send for a `Range` header (with `If-Range`), `undefined` for the whole file. */\nfunction requestedRange(\n headers: Readonly<Record<string, string | undefined>>,\n size: number,\n etag: string | undefined,\n seconds: number | undefined,\n): ByteRange | 'unsatisfiable' | undefined {\n const header = headers['range']\n if (header === undefined) return undefined\n const ifRange = headers['if-range']?.trim()\n if (ifRange !== undefined) {\n const isTag = ifRange.startsWith('\"') || ifRange.startsWith('W/')\n // an entity tag must match strongly; a date must be the exact modification date\n const fresh = isTag\n ? etag !== undefined && ifRange === etag\n : seconds !== undefined && httpDate(ifRange) === seconds\n if (!fresh) return undefined\n }\n return parseRange(header, size)\n}\n\n/** An inclusive byte range. */\nexport interface ByteRange {\n readonly start: number\n readonly end: number\n}\n\n/**\n * Parses a `Range` header for a representation of `size` bytes. Only a single `bytes` range is\n * honoured: other units, several ranges and malformed values return `undefined` (the whole\n * representation is sent, as RFC 9110 allows); a valid range starting after the end returns\n * `'unsatisfiable'` (416).\n */\nexport function parseRange(header: string, size: number): ByteRange | 'unsatisfiable' | undefined {\n const equals = header.indexOf('=')\n if (equals === -1 || header.slice(0, equals).trim().toLowerCase() !== 'bytes') return undefined\n const spec = header.slice(equals + 1)\n if (spec.includes(',')) return undefined\n const match = /^\\s*(\\d*)\\s*-\\s*(\\d*)\\s*$/.exec(spec)\n if (match === null) return undefined\n const [, first = '', last = ''] = match\n if (first === '' && last === '') return undefined\n if (first === '') {\n const suffix = Number(last)\n if (!Number.isSafeInteger(suffix)) return undefined\n if (suffix === 0 || size === 0) return 'unsatisfiable'\n return { start: Math.max(0, size - suffix), end: size - 1 }\n }\n const start = Number(first)\n if (!Number.isSafeInteger(start)) return undefined\n if (last === '') return start >= size ? 'unsatisfiable' : { start, end: size - 1 }\n const end = Number(last)\n if (!Number.isSafeInteger(end) || end < start) return undefined\n return start >= size ? 'unsatisfiable' : { start, end: Math.min(end, size - 1) }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Headers\n// -------------------------------------------------------------------------------------------------\n\nfunction contentTypeOf(options: FileResponseOptions, blobType: string | undefined, name: string | undefined): string {\n if (options.contentType !== undefined) return options.contentType\n if (blobType !== undefined && blobType !== '') return blobType\n return (\n (options.filename === undefined ? undefined : contentTypeFor(options.filename)) ??\n (name === undefined ? undefined : contentTypeFor(name)) ??\n OCTET_STREAM\n )\n}\n\nfunction dispositionOf(options: FileResponseOptions, name: string | undefined): string | undefined {\n const type = options.disposition ?? (options.filename === undefined ? undefined : 'attachment')\n if (type === undefined) return undefined\n return contentDisposition(options.filename ?? name, type)\n}\n\n/** Characters that need no percent-encoding in an RFC 8187 `ext-value` (`attr-char`). */\nconst ATTR_CHAR = /^[A-Za-z0-9!#$&+\\-.^_`|~]$/\n\n/**\n * Builds a `Content-Disposition` header value (RFC 6266): `attachment; filename=\"report.pdf\"`, with\n * an RFC 8187 / 5987 `filename*` parameter for names that are not plain ASCII\n * (`attachment; filename=\"r_sum_.pdf\"; filename*=UTF-8''r%C3%A9sum%C3%A9.pdf`). Directory parts and\n * control characters of `filename` are removed.\n */\nexport function contentDisposition(filename?: string, type: ContentDispositionType = 'attachment'): string {\n if (type !== 'attachment' && type !== 'inline') {\n throw new TypeError(`Invalid disposition ${JSON.stringify(type)} (expected \"attachment\" or \"inline\")`)\n }\n if (filename === undefined) return type\n // biome-ignore lint/suspicious/noControlCharactersInRegex: control characters are removed on purpose\n const name = filename.replace(/^.*[\\\\/]/, '').replace(/[\\u0000-\\u001f\\u007f]/g, '')\n if (name === '') return type\n const fallback = name.replace(/[^\\u0020-\\u007e]/g, '_').replace(/%/g, '_')\n let value = `${type}; filename=\"${fallback.replace(/[\"\\\\]/g, '\\\\$&')}\"`\n if (fallback !== name) value += `; filename*=UTF-8''${encodeExtValue(name)}`\n return value\n}\n\nfunction encodeExtValue(value: string): string {\n let result = ''\n for (const byte of new TextEncoder().encode(value)) {\n const char = String.fromCharCode(byte)\n result += byte < 0x80 && ATTR_CHAR.test(char) ? char : `%${byte.toString(16).toUpperCase().padStart(2, '0')}`\n }\n return result\n}\n","/**\n * Signed cookies (RFC 0006 §4.5): HMAC-SHA256 bound to the cookie name, with key rotation. Uses\n * `node:crypto` (synchronous, Node.js and Bun): only imported by the runtime entry, never by the\n * compiler extension.\n */\nimport crypto, { createHmac, createSecretKey, type KeyObject } from 'node:crypto'\n\n/** Length of a signature: base64url of 32 bytes, without padding. */\nconst SIGNATURE_LENGTH = 43\n/** Minimum size of a secret, in bytes. */\nexport const MIN_SECRET_BYTES = 32\n\n/** A secret given to the plugin option `cookies.secrets`. */\nexport type CookieSecret = string | Uint8Array\n\nconst ENCODER = new TextEncoder()\n\n/**\n * Signs and verifies cookie values. The wire form of a signed cookie is\n * `<encoded value>.<signature>` with `signature = base64url(HMAC-SHA256(secret, \"<name>=<encoded value>\"))`:\n * the MAC covers the name, so a value of `a` replayed as `b` fails. The first secret signs, every\n * secret verifies (rotation).\n */\nexport class CookieSigner {\n readonly #keys: readonly KeyObject[]\n\n /** @param secrets validated by {@link checkSecrets} (at least one, ≥ 32 bytes each, no duplicate). */\n constructor(secrets: readonly CookieSecret[]) {\n this.#keys = secrets.map(secret => createSecretKey(toBytes(secret)))\n }\n\n /** `<encoded>.<signature>` signed with the first secret. `encoded` is an encoded cookie value. */\n sign(name: string, encoded: string): string {\n return `${encoded}.${mac(this.#keys[0] as KeyObject, name, encoded)}`\n }\n\n /**\n * The encoded value of a signed wire value, `undefined` when the signature is malformed or made\n * with none of the secrets (constant-time comparison).\n */\n verify(name: string, wire: string): string | undefined {\n const dot = wire.lastIndexOf('.')\n if (dot === -1) return undefined\n const signature = wire.slice(dot + 1)\n if (!isSignature(signature)) return undefined\n const encoded = wire.slice(0, dot)\n const given = Buffer.from(signature, 'latin1')\n for (const key of this.#keys) {\n const expected = Buffer.from(mac(key, name, encoded), 'latin1')\n // through the module object: observable in tests (equal lengths only, see isSignature)\n if (crypto.timingSafeEqual(expected, given)) return encoded\n }\n return undefined\n }\n}\n\nfunction mac(key: KeyObject, name: string, encoded: string): string {\n return createHmac('sha256', key).update(`${name}=${encoded}`).digest('base64url')\n}\n\n/** 43 characters of the base64url alphabet. */\nfunction isSignature(text: string): boolean {\n if (text.length !== SIGNATURE_LENGTH) return false\n for (let index = 0; index < text.length; index++) {\n const code = text.charCodeAt(index)\n const valid =\n (code >= 0x30 && code <= 0x39) ||\n (code >= 0x41 && code <= 0x5a) ||\n (code >= 0x61 && code <= 0x7a) ||\n code === 0x2d ||\n code === 0x5f\n if (!valid) return false\n }\n return true\n}\n\nfunction toBytes(secret: CookieSecret): Uint8Array {\n return typeof secret === 'string' ? ENCODER.encode(secret) : secret\n}\n\n/**\n * Normalises the option `cookies.secrets` to a list, or explains what is wrong with it (a secret\n * shorter than 32 bytes, a duplicate, an empty list, a value that is neither a string nor bytes).\n */\nexport function checkSecrets(\n value: unknown,\n): { readonly secrets: readonly CookieSecret[] } | { readonly problem: string } {\n const list: unknown[] = Array.isArray(value) ? value : [value]\n if (list.length === 0) return { problem: 'at least one secret' }\n const seen = new Set<string>()\n for (const [index, secret] of list.entries()) {\n if (typeof secret !== 'string' && !(secret instanceof Uint8Array)) {\n return { problem: `strings or Uint8Arrays (secret #${index} is not)` }\n }\n const bytes = toBytes(secret)\n if (bytes.byteLength < MIN_SECRET_BYTES) {\n return {\n problem: `secrets of at least ${MIN_SECRET_BYTES} bytes (secret #${index} has ${bytes.byteLength}): crypto.randomBytes(32).toString('base64url')`,\n }\n }\n const fingerprint = Buffer.from(bytes).toString('base64')\n if (seen.has(fingerprint)) return { problem: `distinct secrets (secret #${index} is a duplicate)` }\n seen.add(fingerprint)\n }\n return { secrets: list as CookieSecret[] }\n}\n","/** Validation of HTTP header names and values (internal). */\nimport type { HeaderValue } from './exceptions.ts'\n\n/** A field name: an RFC 9110 token. */\nconst NAME = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/\n\n/**\n * Characters a field value may not contain: everything but HTAB, visible ASCII, space and obs-text\n * (what Node.js `validateHeaderValue` accepts; Fetch `Headers` are less strict, Latin-1 only).\n */\nconst INVALID_VALUE = /[^\\t\\x20-\\x7e\\x80-\\xff]/\n\n/** Whether `name` is a valid header name. */\nexport function isHeaderName(name: string): boolean {\n return NAME.test(name)\n}\n\n/** Whether `value` can be sent as a header value by every adapter (no CR / LF, Latin-1 only...). */\nexport function isHeaderValue(value: string): boolean {\n return !INVALID_VALUE.test(value)\n}\n\n/**\n * The name of the first header whose name or value cannot be sent (`ctx.setHeader('x', 'a\\r\\nb')`,\n * a non Latin-1 file name...), `undefined` when every header is valid.\n */\nexport function findInvalidHeader(headers: Readonly<Record<string, HeaderValue | undefined>>): string | undefined {\n for (const name of Object.keys(headers)) {\n const value = headers[name]\n if (value === undefined) continue\n if (!NAME.test(name)) return name\n if (typeof value === 'string') {\n if (INVALID_VALUE.test(value)) return name\n } else {\n for (const item of value) if (INVALID_VALUE.test(String(item))) return name\n }\n }\n return undefined\n}\n","/** Errors of invalid `HttpPlugin` options (internal). */\nimport { ErrorCode, ZnightError } from '@znight/core'\n\n/** `ZNIGHT005: HttpPlugin: option \"<name>\" must be <expected> (received <value>)`. */\nexport function invalidOption(\n name: string,\n expected: string,\n value: unknown,\n cause?: unknown,\n hints?: readonly string[],\n): ZnightError {\n return new ZnightError(\n ErrorCode.InvalidDecorator,\n `HttpPlugin: option \"${name}\" must be ${expected} (received ${describeOption(value)})`,\n {\n ...(cause === undefined ? {} : { cause }),\n ...(hints === undefined ? {} : { hints }),\n },\n )\n}\n\n/** A short description of an option value for messages. */\nexport function describeOption(value: unknown): string {\n if (typeof value === 'function') return 'a function'\n if (value instanceof RegExp) return String(value)\n try {\n return JSON.stringify(value) ?? String(value)\n } catch {\n return typeof value\n }\n}\n","/**\n * CORS policy (RFC 0001 §5.4): option validation and the headers of preflights and replies. Pure:\n * the pipeline decides when to apply it (preflights are answered before routing and guards, the\n * same way on every adapter).\n */\nimport type { HeaderValue } from './exceptions.ts'\n\nimport { isHeaderName } from './headers.ts'\nimport { invalidOption } from './option-error.ts'\n\n/**\n * Origins allowed to read responses: `'*'` (any origin), an exact origin\n * (`'https://app.example.com'`), an anchored `RegExp` (`/^https:\\/\\/[a-z0-9-]+\\.example\\.com$/`), a\n * list of those, or a function (awaited; a function that throws or rejects denies the origin).\n */\nexport type CorsOrigin =\n | '*'\n | string\n | RegExp\n | readonly (string | RegExp)[]\n | ((origin: string) => boolean | Promise<boolean>)\n\n/** The `cors` option of `HttpPlugin.configure`. */\nexport interface CorsOptions {\n /** Allowed origins (required). */\n readonly origin: CorsOrigin\n /** `access-control-allow-credentials: true` (cookies, `Authorization`). Not with `'*'`. Default `false`. */\n readonly credentials?: boolean\n /**\n * `access-control-allow-methods` of preflights. Default: the methods routed on the requested path.\n * `'*'` (any method) is refused with `credentials`, where browsers read it as a method named `*`.\n */\n readonly methods?: readonly string[]\n /**\n * `access-control-allow-headers` of preflights. Default: the headers the browser asks for\n * (`access-control-request-headers`). `'*'` is refused with `credentials`; it covers\n * `Authorization` too (sent as `*, authorization` when the browser asks for it: browsers never let\n * `*` alone cover it).\n */\n readonly allowHeaders?: readonly string[] | '*'\n /**\n * `access-control-expose-headers` of replies. Default: the request id header (none when it is\n * `false`). `'*'` (every header) is refused with `credentials`, where browsers read it literally.\n */\n readonly exposeHeaders?: readonly string[]\n /** `access-control-max-age` of preflights, in seconds (0 to 86400). Default `600`. */\n readonly maxAge?: number\n}\n\n/** A resolved CORS policy (internal). */\nexport interface CorsPolicy {\n /** Any origin is allowed: `access-control-allow-origin: *`. */\n readonly wildcard: boolean\n /**\n * Replies get `vary: origin` (every policy but a wildcard one, whose replies all carry\n * `access-control-allow-origin: *`).\n */\n readonly varyOrigin: boolean\n readonly credentials: boolean\n /** Joined `methods`, `undefined` for the default (the methods of the path). */\n readonly methods: string | undefined\n /** Joined `allowHeaders` or `*`, `undefined` for the default (echo the request). */\n readonly allowHeaders: string | undefined\n /** Joined `exposeHeaders`, `undefined` when there are none. */\n readonly exposeHeaders: string | undefined\n readonly maxAge: string\n /** Whether `origin` (the request `origin` header) is allowed. May throw or reject: the caller denies it then. */\n allows(origin: string): boolean | Promise<boolean>\n}\n\nconst KEYS = new Set(['origin', 'credentials', 'methods', 'allowHeaders', 'exposeHeaders', 'maxAge'])\n/** RFC 9110 token (methods). */\nconst TOKEN = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/\nconst MAX_AGE_LIMIT = 86_400\nconst DEFAULT_MAX_AGE = 600\nconst PREFLIGHT_VARY = 'origin, access-control-request-method, access-control-request-headers'\n\n/** Validates the `cors` option (ZNIGHT005). `undefined` / `false`: CORS is disabled. */\nexport function resolveCors(\n options: CorsOptions | false | undefined,\n requestIdHeader: string | undefined,\n): CorsPolicy | undefined {\n if (options === undefined || options === false) return undefined\n if (options === null || typeof options !== 'object' || Array.isArray(options)) {\n throw invalidOption(\n 'cors',\n '{ origin, credentials?, methods?, allowHeaders?, exposeHeaders?, maxAge? } or false',\n options,\n )\n }\n for (const key of Object.keys(options)) {\n if (!KEYS.has(key)) {\n throw invalidOption('cors', '{ origin, credentials?, methods?, allowHeaders?, exposeHeaders?, maxAge? }', options)\n }\n }\n const credentials = options.credentials ?? false\n if (typeof credentials !== 'boolean') throw invalidOption('cors.credentials', 'a boolean', credentials)\n const origin = resolveOrigin(options.origin)\n if (credentials && origin.wildcard) {\n throw invalidOption(\n 'cors.origin',\n \"explicit origins when credentials is true (not '*')\",\n options.origin,\n undefined,\n [\"Browsers reject 'access-control-allow-origin: *' on credentialed requests: list the origins\"],\n )\n }\n const methods = tokenList('cors.methods', options.methods, TOKEN, 'HTTP method names')\n if (credentials) {\n refuseWildcard('cors.methods', options.methods, 'HTTP method names', 'a method named \"*\"')\n refuseWildcard('cors.allowHeaders', options.allowHeaders, 'header names', 'a header named \"*\"')\n refuseWildcard('cors.exposeHeaders', options.exposeHeaders, 'header names', 'a header named \"*\"')\n }\n let allowHeaders: string | undefined\n if (options.allowHeaders === '*') {\n if (credentials) {\n throw invalidOption(\n 'cors.allowHeaders',\n \"a list of header names when credentials is true (not '*')\",\n '*',\n undefined,\n [\"Browsers ignore 'access-control-allow-headers: *' on credentialed requests\"],\n )\n }\n allowHeaders = '*'\n } else {\n allowHeaders = headerList('cors.allowHeaders', options.allowHeaders)\n }\n const expose =\n options.exposeHeaders === undefined ? requestIdHeader : headerList('cors.exposeHeaders', options.exposeHeaders)\n const maxAge = options.maxAge ?? DEFAULT_MAX_AGE\n if (!Number.isInteger(maxAge) || maxAge < 0 || maxAge > MAX_AGE_LIMIT) {\n throw invalidOption('cors.maxAge', `an integer number of seconds between 0 and ${MAX_AGE_LIMIT}`, maxAge)\n }\n return Object.freeze({\n wildcard: origin.wildcard,\n varyOrigin: !origin.wildcard,\n credentials,\n methods,\n allowHeaders,\n exposeHeaders: expose === '' ? undefined : expose,\n maxAge: String(maxAge),\n allows: origin.allows,\n })\n}\n\ninterface ResolvedOrigin {\n readonly wildcard: boolean\n readonly allows: (origin: string) => boolean | Promise<boolean>\n}\n\nfunction resolveOrigin(value: CorsOrigin | undefined): ResolvedOrigin {\n if (value === undefined) {\n throw invalidOption(\n 'cors.origin',\n \"'*', an origin, an anchored RegExp, a list of them or a function\",\n value,\n undefined,\n [\"cors: { origin: 'https://app.example.com' }\"],\n )\n }\n if (typeof value === 'function') {\n return { wildcard: false, allows: value }\n }\n const items: readonly unknown[] = Array.isArray(value) ? value : [value]\n const exact = new Set<string>()\n const patterns: RegExp[] = []\n let wildcard = false\n for (const item of items) {\n if (item === '*') wildcard = true\n else if (typeof item === 'string') exact.add(checkOrigin(item))\n else if (item instanceof RegExp) patterns.push(checkPattern(item))\n else {\n throw invalidOption('cors.origin', \"'*', an origin, an anchored RegExp, a list of them or a function\", value)\n }\n }\n if (wildcard) return { wildcard: true, allows: () => true }\n return {\n wildcard: false,\n allows: (origin: string): boolean => exact.has(origin) || patterns.some(pattern => pattern.test(origin)),\n }\n}\n\n/** An origin must be written exactly as browsers send it: `scheme://host[:port]`. */\nfunction checkOrigin(value: string): string {\n if (value === 'null') {\n throw invalidOption('cors.origin', 'a real origin', value, undefined, [\n 'The \"null\" origin is shared by sandboxed iframes, local files and redirects: never trust it',\n ])\n }\n let url: URL | undefined\n try {\n url = new URL(value)\n } catch {\n url = undefined\n }\n if (url === undefined || (url.protocol !== 'http:' && url.protocol !== 'https:')) {\n throw invalidOption('cors.origin', 'an http(s) origin such as \"https://app.example.com\"', value)\n }\n if (url.origin !== value) {\n throw invalidOption(\n 'cors.origin',\n `an origin without path, trailing slash or default port (\"${url.origin}\")`,\n value,\n undefined,\n [`Write \"${url.origin}\": browsers send the origin in this exact form`],\n )\n }\n return value\n}\n\nfunction checkPattern(pattern: RegExp): RegExp {\n const source = pattern.source\n const trailingBackslashes = /\\\\*\\$$/.exec(source)?.[0].length ?? 0\n // `\\$` at the end matches a dollar sign: the pattern is not anchored\n const anchoredEnd = source.endsWith('$') && (trailingBackslashes - 1) % 2 === 0\n if (!source.startsWith('^') || !anchoredEnd) {\n throw invalidOption('cors.origin', 'a RegExp anchored with ^ and $', pattern, undefined, [\n 'Without anchors, /example\\\\.com/ also allows https://example.com.evil.net',\n ])\n }\n if (hasTopLevelAlternation(source)) {\n throw invalidOption('cors.origin', 'a RegExp anchored with ^ and $ around every alternative', pattern, undefined, [\n 'In /^a|b$/ the anchors bind to one alternative each: write /^(?:a|b)$/',\n ])\n }\n if (pattern.global || pattern.sticky) {\n throw invalidOption('cors.origin', 'a RegExp without the g or y flag (test() would be stateful)', pattern)\n }\n return pattern\n}\n\n/** Whether a pattern source has a `|` outside any group and character class. */\nfunction hasTopLevelAlternation(source: string): boolean {\n let depth = 0\n let inClass = false\n for (let index = 0; index < source.length; index++) {\n const char = source[index]\n if (char === '\\\\') {\n index++\n } else if (inClass) {\n if (char === ']') inClass = false\n } else if (char === '[') {\n inClass = true\n } else if (char === '(') {\n depth++\n } else if (char === ')') {\n depth--\n } else if (char === '|' && depth === 0) {\n return true\n }\n }\n return false\n}\n\n/** `'*'` in a list of a credentialed policy: browsers read it literally there (Fetch, CORS protocol). */\nfunction refuseWildcard(name: string, value: unknown, what: string, literal: string): void {\n if (!Array.isArray(value) || !value.includes('*')) return\n throw invalidOption(name, `a list of ${what} when credentials is true (not '*')`, value, undefined, [\n `On credentialed requests browsers read '*' as ${literal}, not as a wildcard: list the names`,\n ])\n}\n\nfunction tokenList(name: string, value: unknown, grammar: RegExp, what: string): string | undefined {\n if (value === undefined) return undefined\n if (!Array.isArray(value) || !value.every(item => typeof item === 'string' && grammar.test(item))) {\n throw invalidOption(name, `an array of ${what}`, value)\n }\n return value.join(', ')\n}\n\nfunction headerList(name: string, value: unknown): string | undefined {\n if (value === undefined) return undefined\n if (!Array.isArray(value) || !value.every(item => typeof item === 'string' && isHeaderName(item))) {\n throw invalidOption(name, 'an array of header names', value)\n }\n return value.map((item: string) => item.toLowerCase()).join(', ')\n}\n\n/**\n * Whether a request is a CORS preflight: `OPTIONS` with `origin` and\n * `access-control-request-method`.\n */\nexport function isPreflight(method: string, headers: Readonly<Record<string, string | undefined>>): boolean {\n return (\n method === 'OPTIONS' && headers['origin'] !== undefined && headers['access-control-request-method'] !== undefined\n )\n}\n\n/** Headers of a `204` preflight answer for an allowed origin. */\nexport function preflightHeaders(\n policy: CorsPolicy,\n origin: string,\n requestHeaders: Readonly<Record<string, string | undefined>>,\n allow: string,\n): Record<string, HeaderValue> {\n const headers: Record<string, HeaderValue> = {\n 'access-control-allow-origin': policy.wildcard ? '*' : origin,\n }\n if (policy.credentials) headers['access-control-allow-credentials'] = 'true'\n const methods = policy.methods ?? allow\n if (methods !== '') headers['access-control-allow-methods'] = methods\n const requested = requestedHeaders(requestHeaders['access-control-request-headers'])\n let allowHeaders = policy.allowHeaders ?? requested\n // `*` never covers Authorization (Fetch): name it when the browser asks for it\n if (allowHeaders !== undefined && requested?.split(', ').includes('authorization') === true) {\n const allowed = allowHeaders.split(', ')\n if (allowed.includes('*') && !allowed.includes('authorization')) allowHeaders = `${allowHeaders}, authorization`\n }\n if (allowHeaders !== undefined && allowHeaders !== '') headers['access-control-allow-headers'] = allowHeaders\n headers['access-control-max-age'] = policy.maxAge\n headers['allow'] = allow\n headers['vary'] = PREFLIGHT_VARY\n return headers\n}\n\n/** `access-control-request-headers` when it is a valid list of header names, lower-cased. */\nfunction requestedHeaders(value: string | undefined): string | undefined {\n if (value === undefined) return undefined\n const names: string[] = []\n for (const item of value.split(',')) {\n const name = item.trim()\n if (name === '') continue\n if (!isHeaderName(name)) return undefined\n names.push(name.toLowerCase())\n }\n return names.length === 0 ? undefined : names.join(', ')\n}\n\n/** CORS headers of a reply to an allowed origin (added when missing). */\nexport function corsReplyHeaders(policy: CorsPolicy, origin: string): Record<string, HeaderValue> {\n const headers: Record<string, HeaderValue> = { 'access-control-allow-origin': policy.wildcard ? '*' : origin }\n if (policy.credentials) headers['access-control-allow-credentials'] = 'true'\n if (policy.exposeHeaders !== undefined) headers['access-control-expose-headers'] = policy.exposeHeaders\n return headers\n}\n\n/** Adds `token` to the `vary` header, unless it (or `*`) is already listed. */\nexport function mergeVary(headers: Record<string, HeaderValue>, token: string): void {\n const existing = headers['vary']\n if (existing === undefined) {\n headers['vary'] = token\n return\n }\n const text = typeof existing === 'string' ? existing : existing.join(', ')\n const tokens = text.split(',').map(item => item.trim().toLowerCase())\n if (tokens.includes('*') || tokens.includes(token)) return\n headers['vary'] = text.trim() === '' ? token : `${text}, ${token}`\n}\n","/**\n * Route decisions (RFC 0001 §5.1, §5.2): route decorator groups as known at boot, the effective\n * metadata of a route (the nearest decision of a group wins) and the boot check of required and\n * enforced groups (ZNIGHT023).\n */\nimport type { CoreLogger } from '@znight/core'\nimport type { RouteDecoratorInfo } from './decorators.ts'\nimport type { HttpMetadata } from './metadata.ts'\n\nimport { ErrorCode, ZnightError } from '@znight/core'\n\nimport { GROUP_NAME } from './decorators.ts'\n\n/** Route metadata: key → value. */\nexport type RouteMeta = Readonly<Record<string, unknown>>\n\n/** Where a group declaration comes from (messages). */\ninterface Declaration {\n readonly group: string\n readonly required: boolean\n readonly source: string\n}\n\n/**\n * The route decorator groups of an application: the compiled `groups` metadata, completed by the\n * `enforces` declarations of the guards and the `meta` entries of plugin routes. A key absent from\n * every source is its own group, not required.\n */\nexport class RouteGroups {\n readonly #keys = new Map<string, Declaration>()\n readonly #groups = new Map<string, Declaration>()\n readonly #members = new Map<string, Set<string>>()\n\n /** Reads `metadata.extensions.http.groups` (ZNIGHT007 when malformed). */\n static fromMetadata(groups: HttpMetadata['groups']): RouteGroups {\n const result = new RouteGroups()\n if (groups === undefined) return result\n if (groups === null || typeof groups !== 'object' || Array.isArray(groups)) {\n throw malformed(`expected an object of { keys, required } (received ${describe(groups)})`)\n }\n for (const group of Object.keys(groups)) {\n const entry: unknown = groups[group]\n const { keys, required } = (entry ?? {}) as { keys?: unknown; required?: unknown }\n // a group is named explicitly (grammar) or after its single key (a decorator without group)\n const ownGroup = Array.isArray(keys) && keys.length === 1 && keys[0] === group\n if (!ownGroup && !GROUP_NAME.test(group)) throw malformed(`invalid group name ${JSON.stringify(group)}`)\n if (\n entry === null ||\n typeof entry !== 'object' ||\n !Array.isArray(keys) ||\n keys.length === 0 ||\n !keys.every(key => typeof key === 'string' && key !== '') ||\n new Set(keys).size !== keys.length ||\n typeof required !== 'boolean'\n ) {\n throw malformed(`group \"${group}\" must be { keys: [unique non-empty strings], required: boolean }`)\n }\n for (const key of keys as string[]) {\n const previous = result.#keys.get(key)\n if (previous !== undefined) {\n throw malformed(`the key \"${key}\" belongs to the groups \"${previous.group}\" and \"${group}\"`)\n }\n result.#add(key, { group, required, source: 'the compiled metadata' })\n }\n }\n return result\n }\n\n /**\n * Declares the group of a key (guard `enforces`, plugin route `meta`). A declaration that\n * contradicts an earlier one is ZNIGHT005.\n */\n declare(info: RouteDecoratorInfo, source: string): void {\n const known = this.#keys.get(info.key)\n if (known !== undefined && (known.group !== info.group || known.required !== info.required)) {\n throw conflict(\n `the route decorator \"${info.key}\" is declared with ${describeGroup(info)} by ${source} but with ${describeGroup({ key: info.key, ...known })} by ${known.source}`,\n )\n }\n const group = this.#groups.get(info.group)\n if (group !== undefined && group.required !== info.required) {\n throw conflict(\n `the \"${info.group}\" group is ${info.required ? '' : 'not '}required for \"${info.key}\" (${source}) but ${group.required ? '' : 'not '}required for ${[...(this.#members.get(info.group) ?? [])].map(key => `\"${key}\"`).join(', ')} (${group.source})`,\n )\n }\n if (known === undefined) this.#add(info.key, { group: info.group, required: info.required, source })\n }\n\n /** The group of a key (the key itself when no source declares one). */\n groupOf(key: string): string {\n return this.#keys.get(key)?.group ?? key\n }\n\n /** Groups every route must decide. */\n required(): Set<string> {\n const result = new Set<string>()\n for (const [group, declaration] of this.#groups) if (declaration.required) result.add(group)\n return result\n }\n\n /** Known keys of a group, sorted. */\n keysOf(group: string): string[] {\n return [...(this.#members.get(group) ?? [group])].sort()\n }\n\n #add(key: string, declaration: Declaration): void {\n this.#keys.set(key, declaration)\n if (!this.#groups.has(declaration.group)) this.#groups.set(declaration.group, declaration)\n let members = this.#members.get(declaration.group)\n if (members === undefined) {\n members = new Set()\n this.#members.set(declaration.group, members)\n }\n members.add(key)\n }\n}\n\nfunction describeGroup(info: { readonly key: string; readonly group: string; readonly required: boolean }): string {\n const group = info.group === info.key ? 'its own group' : `the group \"${info.group}\"`\n return info.required ? `${group} (required)` : group\n}\n\n/**\n * The effective metadata of a route: the controller's entries whose group the route does not\n * decide, then every entry of the route. Frozen.\n */\nexport function effectiveMeta(controller: RouteMeta, route: RouteMeta, groupOf: (key: string) => string): RouteMeta {\n const decided = new Set(Object.keys(route).map(groupOf))\n const result: Record<string, unknown> = {}\n for (const key of Object.keys(controller)) {\n if (!decided.has(groupOf(key))) result[key] = controller[key]\n }\n return Object.freeze(Object.assign(result, route))\n}\n\n/** The key of `meta` sharing its group with another key, as `[first, second, group]`. */\nexport function conflictingKeys(\n meta: RouteMeta,\n groupOf: (key: string) => string,\n): readonly [string, string, string] | undefined {\n const seen = new Map<string, string>()\n for (const key of Object.keys(meta)) {\n const group = groupOf(key)\n const first = seen.get(group)\n if (first !== undefined) return [first, key, group]\n seen.set(group, key)\n }\n return undefined\n}\n\n/** The groups listed by `static enforces` of a guard class (ZNIGHT005 when malformed). */\nexport function enforcedBy(guard: unknown, name: string): readonly RouteDecoratorInfo[] {\n if (typeof guard !== 'function') return []\n let enforces: unknown\n try {\n enforces = (guard as { enforces?: unknown }).enforces\n } catch (error) {\n throw invalidEnforces(name, 'reading it threw', error)\n }\n if (enforces === undefined) return []\n if (!Array.isArray(enforces))\n throw invalidEnforces(name, `expected an array of route decorators (received ${describe(enforces)})`)\n for (const entry of enforces as unknown[]) {\n const info = (typeof entry === 'function' || (typeof entry === 'object' && entry !== null) ? entry : {}) as {\n key?: unknown\n group?: unknown\n required?: unknown\n }\n if (typeof info.key !== 'string' || typeof info.group !== 'string' || typeof info.required !== 'boolean') {\n throw invalidEnforces(\n name,\n `every entry must be a route decorator ({ key, group, required }), received ${describe(entry)}`,\n )\n }\n }\n return enforces as readonly RouteDecoratorInfo[]\n}\n\nfunction invalidEnforces(name: string, reason: string, cause?: unknown): ZnightError {\n return new ZnightError(\n ErrorCode.InvalidDecorator,\n `HttpPlugin: invalid static enforces of the guard ${name}: ${reason}`,\n {\n hints: [\n 'static readonly enforces = [Public, Authenticated, Roles] (decorators created with createRouteDecorator)',\n ],\n ...(cause === undefined ? {} : { cause }),\n },\n )\n}\n\n/** A route as seen by the boot check: one per declared route (no HEAD or trailing-slash variant). */\nexport interface CheckedRoute {\n /** `GET /books (BookController.list)`. */\n readonly description: string\n /** Effective metadata. */\n readonly meta: RouteMeta\n /** Groups enforced by the guards of its chain (global, controller, route). */\n readonly enforced: ReadonlySet<string>\n /** Name of the plugin declaring the route, for plugin routes. */\n readonly plugin?: string\n}\n\n/** How the boot check reports problems. */\nexport type EnforcementMode = 'error' | 'warn'\n\n/**\n * The boot check (RFC 0001 §5.2): every route decides every required group, and every decision of\n * a required or enforced group is enforced by a guard of the route's chain. A group is enforced when\n * a guard of some chain, or a guard class of the application (`enforcers`, in a chain or not),\n * declares it: a guard registered nowhere does not make its decisions inert. Problems are reported\n * as one ZNIGHT023 error (`'error'`) or one warning per group (`'warn'`).\n */\nexport function checkDecisions(\n routes: readonly CheckedRoute[],\n groups: RouteGroups,\n mode: EnforcementMode,\n logger: CoreLogger,\n enforcers: ReadonlyMap<string, ReadonlySet<string>> = new Map(),\n): void {\n const required = groups.required()\n const known = new Set<string>(enforcers.keys())\n for (const route of routes) for (const group of route.enforced) known.add(group)\n const problems = new Map<string, { missing: string[]; unenforced: string[]; plugins: Set<string> }>()\n const problem = (group: string): { missing: string[]; unenforced: string[]; plugins: Set<string> } => {\n let entry = problems.get(group)\n if (entry === undefined) {\n entry = { missing: [], unenforced: [], plugins: new Set() }\n problems.set(group, entry)\n }\n return entry\n }\n for (const route of routes) {\n const decided = new Set(Object.keys(route.meta).map(key => groups.groupOf(key)))\n for (const group of required) {\n if (decided.has(group)) continue\n const entry = problem(group)\n entry.missing.push(route.description)\n if (route.plugin !== undefined) entry.plugins.add(route.plugin)\n }\n for (const group of decided) {\n if ((required.has(group) || known.has(group)) && !route.enforced.has(group)) {\n problem(group).unenforced.push(route.description)\n }\n }\n }\n if (problems.size === 0) return\n const messages: string[] = []\n const hints: string[] = []\n for (const group of [...problems.keys()].sort()) {\n const entry = problems.get(group) as { missing: string[]; unenforced: string[]; plugins: Set<string> }\n const keys = groups.keysOf(group)\n const parts: string[] = []\n const groupHints: string[] = []\n if (entry.missing.length > 0) {\n parts.push(\n `${count(entry.missing.length)} ${entry.missing.length === 1 ? 'has' : 'have'} no \"${group}\" decision: ${entry.missing.join(', ')}`,\n )\n groupHints.push(`Add a decision of the \"${group}\" group (${keys.join(', ')}) to the route or to its controller`)\n for (const plugin of [...entry.plugins].sort()) {\n groupHints.push(\n `Routes of the plugin \"${plugin}\" take their metadata from its options: meta: [Decorator.meta()]`,\n )\n }\n }\n if (entry.unenforced.length > 0) {\n parts.push(\n `no guard enforces the ${required.has(group) ? 'required ' : ''}\"${group}\" group on ${count(entry.unenforced.length)}: ${entry.unenforced.join(', ')}`,\n )\n const guards = [...(enforcers.get(group) ?? [])].sort()\n // a guard of the application that enforces the group, else a name for the one to write\n const example = guards[0] ?? guardName(group)\n groupHints.push(\n `Register a guard declaring \\`static enforces\\` with the decorators of the \"${group}\" group (${keys.join(', ')}), e.g. HttpPlugin.configure({ guards: [${example}] })`,\n )\n if (guards.length > 0) {\n groupHints.push(`Guards of the application enforcing the \"${group}\" group: ${guards.join(', ')}`)\n }\n }\n const message = parts.join('; ')\n if (mode === 'warn') {\n logger.warn(`HttpPlugin: ${message}`, { code: ErrorCode.MissingRouteDecision, group })\n } else {\n messages.push(message)\n hints.push(...groupHints)\n }\n }\n if (mode === 'error') {\n hints.push(\"Tests that deliberately run without guards can set enforcement: 'warn'\")\n throw new ZnightError(ErrorCode.MissingRouteDecision, `HttpPlugin: ${capitalize(messages.join('; '))}`, { hints })\n }\n}\n\nfunction count(routes: number): string {\n return routes === 1 ? '1 route' : `${routes} routes`\n}\n\nfunction capitalize(text: string): string {\n return text.charAt(0).toUpperCase() + text.slice(1)\n}\n\n/** A class name for the guard of a group: `rateLimit` → `RateLimitGuard`, `auth:public` → `AuthPublicGuard`. */\nfunction guardName(group: string): string {\n const name = group\n .split(/[^A-Za-z0-9]+/)\n .map(capitalize)\n .join('')\n .replace(/^\\d+/, '')\n return `${name === '' ? 'Decision' : name}Guard`\n}\n\nfunction malformed(reason: string): ZnightError {\n return new ZnightError(ErrorCode.InvalidRoute, `Invalid metadata.extensions.http.groups: ${reason}`)\n}\n\nfunction conflict(reason: string): ZnightError {\n return new ZnightError(ErrorCode.InvalidDecorator, `HttpPlugin: inconsistent route decorator groups: ${reason}`, {\n hints: [\n 'Every definition of a key must use the same options, and the decorators of a group must agree on required',\n 'Regenerate the metadata when createRouteDecorator options changed',\n ],\n })\n}\n\nfunction describe(value: unknown): string {\n try {\n return typeof value === 'function' ? 'a function' : (JSON.stringify(value) ?? String(value))\n } catch {\n return typeof value\n }\n}\n","/**\n * Client side of Server-Sent Events: the WHATWG \"interpreting an event stream\" algorithm over a\n * byte stream (`parseSseStream`), used by `injectSse()` and by tests over real sockets. Import-free.\n */\n\n/** A dispatched event. */\nexport interface SseMessage {\n /** Event type: `message` by default. */\n readonly event: string\n readonly data: string\n /** The last event id at dispatch time (what `EventSource` sends back as `Last-Event-ID`). */\n readonly id: string\n /** `JSON.parse(data)`. */\n json<T = unknown>(): T\n}\n\n/** An item of an event stream: an event, a comment (heartbeats are `''`) or a reconnection delay. */\nexport type SseItem =\n | ({ readonly type: 'event' } & SseMessage)\n | { readonly type: 'comment'; readonly text: string }\n | { readonly type: 'retry'; readonly retry: number }\n\n/** Options of {@link parseSseStream}. */\nexport interface ParseSseOptions {\n /** Stops reading (the body is cancelled) when aborted. */\n readonly signal?: AbortSignal\n}\n\n/**\n * Incremental parser (internal): feed it decoded text, collect the items. Follows the HTML\n * specification: CR, LF and CRLF line ends (a CR at the end of a chunk included), one leading space\n * stripped from values, `data` lines buffered and the final LF removed, `id` values containing NUL\n * ignored, `retry` accepted only as ASCII digits, the type defaulting to `message`, an event without\n * data not dispatched.\n */\nexport class SseParser {\n /** The last event id (updated when an event is dispatched, even without data). */\n lastEventId = ''\n #line = ''\n #skipLf = false\n #data = ''\n #hasData = false\n #type = ''\n #idBuffer = ''\n\n /** Parses a chunk of text; returns the items it completes. */\n push(text: string): SseItem[] {\n const items: SseItem[] = []\n let start = 0\n for (let index = 0; index < text.length; index++) {\n const code = text.charCodeAt(index)\n if (code === 0x0a && this.#skipLf) {\n // the LF of a CRLF (possibly split across chunks)\n this.#skipLf = false\n start = index + 1\n continue\n }\n this.#skipLf = false\n if (code !== 0x0a && code !== 0x0d) continue\n this.#line += text.slice(start, index)\n this.#processLine(this.#line, items)\n this.#line = ''\n start = index + 1\n if (code === 0x0d) this.#skipLf = true\n }\n if (start < text.length) this.#line += text.slice(start)\n return items\n }\n\n #processLine(line: string, items: SseItem[]): void {\n if (line === '') {\n this.#dispatch(items)\n return\n }\n const colon = line.indexOf(':')\n if (colon === 0) {\n items.push({ type: 'comment', text: line.charCodeAt(1) === 0x20 ? line.slice(2) : line.slice(1) })\n return\n }\n const field = colon === -1 ? line : line.slice(0, colon)\n let value = colon === -1 ? '' : line.slice(colon + 1)\n if (value.charCodeAt(0) === 0x20) value = value.slice(1)\n switch (field) {\n case 'event':\n this.#type = value\n break\n case 'data':\n this.#data += `${value}\\n`\n this.#hasData = true\n break\n case 'id':\n if (!value.includes('\\u0000')) this.#idBuffer = value\n break\n case 'retry':\n if (/^\\d+$/.test(value)) items.push({ type: 'retry', retry: Number(value) })\n break\n default:\n break\n }\n }\n\n #dispatch(items: SseItem[]): void {\n this.lastEventId = this.#idBuffer\n if (!this.#hasData) {\n this.#type = ''\n return\n }\n const data = this.#data.endsWith('\\n') ? this.#data.slice(0, -1) : this.#data\n const event = this.#type === '' ? 'message' : this.#type\n const id = this.lastEventId\n items.push({ type: 'event', event, data, id, json: <T = unknown>(): T => JSON.parse(data) as T })\n this.#data = ''\n this.#hasData = false\n this.#type = ''\n }\n}\n\n/**\n * Turns an event stream body (a `fetch()` response body, `injectStream().body`) into its items.\n * UTF-8 is decoded with the BOM stripped; an unterminated event at the end is discarded. Calling\n * `return()` (leaving a `for await` loop) or aborting `signal` cancels the body.\n *\n * ```ts\n * const response = await fetch(`${http.address}/orders/o-1/events`)\n * for await (const item of parseSseStream(response.body!)) {\n * if (item.type === 'event') console.log(item.event, item.json())\n * }\n * ```\n */\nexport function parseSseStream(\n body: ReadableStream<Uint8Array>,\n options: ParseSseOptions = {},\n): AsyncIterableIterator<SseItem> {\n return parseWith(new SseParser(), body, options)\n}\n\n/** {@link parseSseStream} with a given parser (internal: `injectSse()` reads its `lastEventId`). */\nexport function parseWith(\n parser: SseParser,\n body: ReadableStream<Uint8Array>,\n options: ParseSseOptions = {},\n): AsyncIterableIterator<SseItem> {\n const reader = body.getReader()\n const decoder = new TextDecoder('utf-8')\n const queue: SseItem[] = []\n let ended = false\n let cancelled: Promise<void> = Promise.resolve()\n const stop = (): void => {\n if (ended) return\n ended = true\n queue.length = 0\n cancelled = reader.cancel().catch(() => undefined)\n }\n const signal = options.signal\n if (signal !== undefined) {\n if (signal.aborted) stop()\n else signal.addEventListener('abort', stop, { once: true })\n }\n const iterator: AsyncIterableIterator<SseItem> = {\n async next(): Promise<IteratorResult<SseItem>> {\n for (;;) {\n const queued = queue.shift()\n if (queued !== undefined) return { done: false, value: queued }\n if (ended) return { done: true, value: undefined }\n let result: Awaited<ReturnType<typeof reader.read>>\n try {\n result = await reader.read()\n } catch (error) {\n if (ended) return { done: true, value: undefined }\n ended = true\n throw error\n }\n if (result.done) {\n // the decoder may hold the start of a character; an unterminated event is discarded\n parser.push(decoder.decode())\n ended = true\n signal?.removeEventListener('abort', stop)\n return { done: true, value: undefined }\n }\n if (!ended) queue.push(...parser.push(decoder.decode(result.value, { stream: true })))\n }\n },\n async return(): Promise<IteratorResult<SseItem>> {\n stop()\n signal?.removeEventListener('abort', stop)\n await cancelled\n return { done: true, value: undefined }\n },\n [Symbol.asyncIterator](): AsyncIterableIterator<SseItem> {\n return iterator\n },\n }\n return iterator\n}\n","/**\n * `injectSse()`: an in-memory `EventSource` for tests, on top of `injectStream()`. Events are read\n * only when asked for (`next()`, `take()`, iteration, `done`), so a test controls the pace of the\n * client. Opening never waits forever ({@link OPEN_TIMEOUT_MS} per step): without response headers\n * it fails (the request is aborted); without a first chunk (an `@Sse` stream sends `retry` or a\n * comment at once, a hand-written or proxied one may stay quiet) the stream is open anyway, and the\n * read goes on in the background.\n */\nimport type { InjectStreamOptions, InjectStreamRequest, InjectStreamResponse } from './adapter.ts'\nimport type { SetCookieInfo } from './cookies.ts'\n\nimport { isEventStreamType } from './adapters/shared.ts'\nimport { parseWith, type SseItem, type SseMessage, SseParser } from './sse-parse.ts'\n\n/** Options of {@link InjectSseResponse.next} and {@link InjectSseResponse.take}. */\nexport interface InjectSseWaitOptions {\n /** Maximum wait for each event (ms). Default: 2 000. */\n readonly timeoutMs?: number\n}\n\n/** The response of `injectSse()`: an event stream read in memory, like `EventSource` would. */\nexport interface InjectSseResponse extends AsyncIterable<SseMessage>, AsyncDisposable {\n readonly status: number\n readonly headers: Record<string, string | string[]>\n readonly cookies: Readonly<Record<string, SetCookieInfo>>\n /** `''` for an event stream; otherwise the whole body, read to its end (an error, a 204...). */\n readonly body: string\n /** `JSON.parse(body)`. */\n json<T = unknown>(): T\n /** The next event (comments skipped). Rejects on timeout (default 2 000 ms) or when the stream ended. */\n next(options?: InjectSseWaitOptions): Promise<SseMessage>\n /** The next `count` events (the timeout applies to each). */\n take(count: number, options?: InjectSseWaitOptions): Promise<SseMessage[]>\n /** Comments received so far (heartbeats are `''`). */\n readonly comments: readonly string[]\n /** What a browser would send as `Last-Event-ID` on reconnection. */\n readonly lastEventId: string\n /** The last `retry` received (ms). */\n readonly retry: number | undefined\n /** Resolves when the server ends the stream (reading the remaining events, which stay available to `next()`). */\n readonly done: Promise<void>\n /** Disconnects (cancels the body): the server sees a client disconnect. Idempotent. */\n close(): Promise<void>\n /** Reconnects like `EventSource`: closes this stream and sends the same request plus `last-event-id`. */\n reconnect(): Promise<InjectSseResponse>\n}\n\nconst DEFAULT_TIMEOUT_MS = 2_000\n/** How long opening waits for the response headers, then for the first chunk of an event stream (ms). */\nconst OPEN_TIMEOUT_MS = 2_000\nconst DECODER = new TextDecoder()\n\ntype InjectStream = (request: InjectStreamOptions) => Promise<InjectStreamResponse>\n\n/**\n * Opens an event stream with `injectStream` (adds `accept: text/event-stream` when absent), waiting\n * at most `openTimeoutMs` for the response headers, then at most `openTimeoutMs` for the first chunk.\n */\nexport async function openInjectSse(\n injectStream: InjectStream,\n request: InjectStreamOptions,\n openTimeoutMs: number = OPEN_TIMEOUT_MS,\n): Promise<InjectSseResponse> {\n if (request === null || typeof request !== 'object') throw new TypeError('injectSse() expects a request object')\n const headers: Record<string, string> = { ...request.headers }\n if (!Object.keys(headers).some(name => name.toLowerCase() === 'accept')) headers['accept'] = 'text/event-stream'\n const sent: InjectStreamRequest = { ...request, method: request.method ?? 'GET', headers }\n const response = await answered(injectStream, sent, openTimeoutMs)\n if (!isEventStreamType(response.headers['content-type'])) {\n const body = await readText(response.body)\n return new SseClient(injectStream, sent, response, body, openTimeoutMs)\n }\n const client = new SseClient(injectStream, sent, response, '', openTimeoutMs)\n // the first chunk makes `retry` and `comments` known at once; a quiet stream must not hang the test\n await client.ready()\n return client\n}\n\n/**\n * `injectStream(request)`, waiting at most `ms` for the response headers. Past it, the request is\n * aborted (a late response is cancelled: the server sees a client disconnect) and opening fails\n * with an error naming the request, instead of hanging the test.\n */\nasync function answered(\n injectStream: InjectStream,\n request: InjectStreamRequest,\n ms: number,\n): Promise<InjectStreamResponse> {\n const abort = new AbortController()\n const signal = request.signal === undefined ? abort.signal : AbortSignal.any([request.signal, abort.signal])\n const pending = injectStream({ ...request, signal })\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<undefined>(resolve => {\n timer = setTimeout(() => resolve(undefined), ms)\n })\n const response = await Promise.race([pending, timeout]).finally(() => clearTimeout(timer))\n if (response !== undefined) return response\n const message = `injectSse(): no response from ${describe(request)} within ${ms} ms`\n abort.abort(new Error(message))\n void pending.then(\n late => late.body.cancel().catch(() => undefined),\n () => undefined,\n )\n throw new Error(\n `${message}: the handler has not answered, or the adapter holds the response headers until the first byte of the body`,\n )\n}\n\n/** `GET /orders/o-1/events`. */\nfunction describe(request: InjectStreamRequest): string {\n return `${(request.method ?? 'GET').toUpperCase()} ${request.url}`\n}\n\nasync function readText(body: ReadableStream<Uint8Array>): Promise<string> {\n const reader = body.getReader()\n let text = ''\n for (;;) {\n const { done, value } = await reader.read()\n if (done) return text + DECODER.decode()\n text += DECODER.decode(value, { stream: true })\n }\n}\n\nclass SseClient implements InjectSseResponse {\n readonly status: number\n readonly headers: Record<string, string | string[]>\n readonly cookies: Readonly<Record<string, SetCookieInfo>>\n readonly body: string\n readonly #injectStream: InjectStream\n readonly #request: InjectStreamRequest\n readonly #openTimeoutMs: number\n readonly #parser = new SseParser()\n readonly #items: AsyncIterableIterator<SseItem> | undefined\n readonly #events: SseMessage[] = []\n readonly #comments: string[] = []\n #retry: number | undefined\n /** Whether an item (event, comment, `retry`) was read since the stream opened. */\n #received = false\n #ended: boolean\n #failure: unknown\n #reading: Promise<void> | undefined\n #closing: Promise<void> | undefined\n #draining: Promise<void> | undefined\n\n constructor(\n injectStream: InjectStream,\n request: InjectStreamRequest,\n response: InjectStreamResponse,\n body: string,\n openTimeoutMs: number,\n ) {\n this.#injectStream = injectStream\n this.#request = request\n this.#openTimeoutMs = openTimeoutMs\n this.status = response.status\n this.headers = response.headers\n this.cookies = response.cookies\n this.body = body\n const stream = isEventStreamType(response.headers['content-type'])\n this.#ended = !stream\n this.#items = stream ? parseWith(this.#parser, response.body) : undefined\n }\n\n get comments(): readonly string[] {\n return [...this.#comments]\n }\n\n get lastEventId(): string {\n return this.#parser.lastEventId\n }\n\n get retry(): number | undefined {\n return this.#retry\n }\n\n get done(): Promise<void> {\n this.#draining ??= (async (): Promise<void> => {\n while (!this.#ended) await this.#read()\n })()\n return this.#draining\n }\n\n json<T = unknown>(): T {\n return JSON.parse(this.body) as T\n }\n\n /**\n * Reads the first item (the preamble every `@Sse` stream starts with, so that `retry` is known),\n * waiting at most the open timeout: the read of a quiet stream goes on in the background.\n */\n async ready(): Promise<void> {\n await this.#readWithin(this.#openTimeoutMs)\n }\n\n async next(options: InjectSseWaitOptions = {}): Promise<SseMessage> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n if (!(timeoutMs >= 0)) throw new TypeError('injectSse(): timeoutMs must be a number ≥ 0')\n const deadline = Date.now() + timeoutMs\n for (;;) {\n const event = this.#events.shift()\n if (event !== undefined) return event\n if (this.#ended) {\n throw new Error(`injectSse(): the event stream of ${this.#describe()} ended`, {\n ...(this.#failure === undefined ? {} : { cause: this.#failure }),\n })\n }\n const remaining = deadline - Date.now()\n if (remaining <= 0 || !(await this.#readWithin(remaining))) {\n const quiet = this.#received ? '' : ' (the stream has sent nothing since it opened)'\n throw new Error(`injectSse(): no event received within ${timeoutMs} ms from ${this.#describe()}${quiet}`)\n }\n }\n }\n\n async take(count: number, options?: InjectSseWaitOptions): Promise<SseMessage[]> {\n if (!Number.isSafeInteger(count) || count < 0) throw new TypeError('injectSse(): take() expects an integer ≥ 0')\n const events: SseMessage[] = []\n while (events.length < count) events.push(await this.next(options))\n return events\n }\n\n close(): Promise<void> {\n if (this.#closing === undefined) {\n this.#ended = true\n this.#closing =\n this.#items === undefined\n ? Promise.resolve()\n : (this.#items.return?.().then(() => undefined) ?? Promise.resolve())\n }\n return this.#closing\n }\n\n async reconnect(): Promise<InjectSseResponse> {\n await this.close()\n const headers: Record<string, string> = {}\n for (const [name, value] of Object.entries(this.#request.headers ?? {})) {\n if (name.toLowerCase() !== 'last-event-id') headers[name] = value\n }\n // EventSource only sends a non-empty last event id\n if (this.lastEventId !== '') headers['last-event-id'] = this.lastEventId\n return openInjectSse(this.#injectStream, { ...this.#request, headers }, this.#openTimeoutMs)\n }\n\n [Symbol.asyncIterator](): AsyncIterator<SseMessage> {\n return {\n next: async (): Promise<IteratorResult<SseMessage>> => {\n for (;;) {\n const event = this.#events.shift()\n if (event !== undefined) return { done: false, value: event }\n if (this.#ended) return { done: true, value: undefined }\n await this.#read()\n }\n },\n return: async (): Promise<IteratorResult<SseMessage>> => {\n await this.close()\n return { done: true, value: undefined }\n },\n }\n }\n\n [Symbol.asyncDispose](): Promise<void> {\n return this.close()\n }\n\n /** Waits for the next item at most `ms` (the read goes on in the background); `false` on timeout. */\n async #readWithin(ms: number): Promise<boolean> {\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<false>(resolve => {\n timer = setTimeout(() => resolve(false), ms)\n })\n const outcome = await Promise.race([this.#read().then(() => true as const), timeout])\n clearTimeout(timer)\n return outcome\n }\n\n /** Reads one item (one read at a time, shared by concurrent callers). */\n #read(): Promise<void> {\n this.#reading ??= this.#readItem().finally(() => {\n this.#reading = undefined\n })\n return this.#reading\n }\n\n async #readItem(): Promise<void> {\n const items = this.#items\n if (items === undefined || this.#ended) return\n let result: IteratorResult<SseItem>\n try {\n result = await items.next()\n } catch (error) {\n this.#failure = error\n this.#ended = true\n return\n }\n if (result.done === true) {\n this.#ended = true\n return\n }\n const item = result.value\n this.#received = true\n if (item.type === 'comment') this.#comments.push(item.text)\n else if (item.type === 'retry') this.#retry = item.retry\n else this.#events.push({ event: item.event, data: item.data, id: item.id, json: item.json })\n }\n\n #describe(): string {\n return describe(this.#request)\n }\n}\n","/**\n * Server-Sent Events (RFC 0006 §4.6, §4.7): the event encoder, the `HttpResponse.sse()` body marker\n * and the event stream (preamble, pull loop, heartbeats, raw byte passthrough, error handling,\n * graceful close with a jittered `retry`, bounded source stop).\n */\nimport type { RequestAbortKind } from './context.ts'\n\nimport { type ContextRunner, captureContext } from './stream.ts'\n\n/** One event of an event stream. */\nexport interface SseEvent<T = unknown> {\n /** A string is sent as is; anything else goes through `JSON.stringify` (`toJSON` honoured). */\n readonly data?: T\n /** Event type (`addEventListener(type)`). The client defaults to `message`. No CR or LF. */\n readonly event?: string\n /** Last event id, echoed by the client as `Last-Event-ID`. No CR, LF or NUL. `''` resets it. */\n readonly id?: string | number\n /** Reconnection delay in ms (a safe integer ≥ 0). */\n readonly retry?: number\n /** Comment lines, ignored by `EventSource` (debugging, padding). */\n readonly comment?: string\n}\n\n/** Options of `@Sse()` and `HttpResponse.sse()`. */\nexport interface SseOptions {\n /**\n * Milliseconds without an event after which a keep-alive comment (`:`) is sent (an integer\n * from 1 000 to 2 147 483 647). `false` disables it. Default: the plugin option `sse.heartbeat`\n * (8 000).\n */\n readonly heartbeat?: number | false\n /**\n * Client reconnection delay (`retry:`, ms), sent first. Default: the plugin option `sse.retry`\n * (none: browsers use about 3 s).\n */\n readonly retry?: number\n /**\n * The server ends the stream gracefully after this many ms (load rebalancing, re-authentication):\n * `ctx.signal` aborts (`'expired'`), then the client gets a jittered `retry` and reconnects. An\n * integer from 1 000 to 2 147 483 647 (about 24.8 days, the longest timer). Default: none.\n */\n readonly maxDuration?: number\n}\n\n/**\n * What `@Sse` handlers and `HttpResponse.sse()` accept: an async iterable (async generators,\n * `EventChannel`, a Node.js `Readable` of raw bytes), an iterable (arrays, sync generators; not\n * strings) or a `ReadableStream`, of `SseEvent` objects or `Uint8Array` chunks (already-framed SSE\n * text, written as is: proxying an upstream event stream).\n */\nexport type SseSource =\n | AsyncIterable<SseEvent | Uint8Array>\n | Iterable<SseEvent>\n | ReadableStream<SseEvent | Uint8Array>\n\n/** The body of `HttpResponse.sse()`: an event source and its options (served by the plugin). */\nexport class SseBody {\n readonly source: SseSource\n readonly options: SseOptions\n\n constructor(source: SseSource, options: SseOptions = {}) {\n if (!isSseSource(source)) {\n throw new TypeError(\n 'HttpResponse.sse() expects an AsyncIterable, an Iterable or a ReadableStream of SseEvent (not a string)',\n )\n }\n checkSseOptions(options, 'HttpResponse.sse()')\n this.source = source\n this.options = options\n }\n}\n\n/** Whether `value` is an {@link SseBody}. */\nexport function isSseBody(value: unknown): value is SseBody {\n return value instanceof SseBody\n}\n\n/** Whether `value` can be served as an event stream (async iterable, non-string iterable, `ReadableStream`). */\nexport function isSseSource(value: unknown): value is SseSource {\n if (value instanceof ReadableStream) return true\n if (value === null || typeof value !== 'object') return false\n return (\n typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === 'function' ||\n typeof (value as { [Symbol.iterator]?: unknown })[Symbol.iterator] === 'function'\n )\n}\n\n/** Smallest heartbeat and `maxDuration` (ms). */\nexport const MIN_SSE_INTERVAL_MS = 1_000\n/**\n * Longest heartbeat, `maxDuration` and grace period (ms): the longest `setTimeout` delay (larger\n * ones overflow to 1 ms on Node.js and Bun, which would end every stream at once).\n */\nexport const MAX_SSE_TIMER_MS = 2_147_483_647\n\n/**\n * Checks SSE options (`HttpResponse.sse()`, hand-written metadata): `heartbeat` an integer from\n * 1 000 to 2 147 483 647 or `false`, `retry` an integer ≥ 0, `maxDuration` an integer from 1 000 to\n * 2 147 483 647, no other key.\n *\n * @throws TypeError naming `what`.\n */\nexport function checkSseOptions(options: unknown, what: string): void {\n const problem = sseOptionsProblem(options)\n if (problem !== undefined) throw new TypeError(`${what}: ${problem}`)\n}\n\n/** What is wrong with SSE options, `undefined` when they are valid. */\nexport function sseOptionsProblem(options: unknown): string | undefined {\n if (options === null || typeof options !== 'object' || Array.isArray(options)) {\n return 'options must be an object { heartbeat?, retry?, maxDuration? }'\n }\n for (const [key, value] of Object.entries(options)) {\n if (value === undefined) continue\n switch (key) {\n case 'heartbeat':\n if (value !== false && !isInteger(value, MIN_SSE_INTERVAL_MS, MAX_SSE_TIMER_MS)) {\n return `heartbeat must be an integer number of ms from ${MIN_SSE_INTERVAL_MS} to ${MAX_SSE_TIMER_MS}, or false (received ${String(value)})`\n }\n break\n case 'retry':\n if (!isInteger(value, 0)) return `retry must be an integer number of ms ≥ 0 (received ${String(value)})`\n break\n case 'maxDuration':\n if (!isInteger(value, MIN_SSE_INTERVAL_MS, MAX_SSE_TIMER_MS)) {\n return `maxDuration must be an integer number of ms from ${MIN_SSE_INTERVAL_MS} to ${MAX_SSE_TIMER_MS} (received ${String(value)})`\n }\n break\n default:\n return `unknown option \"${key}\" (options: { heartbeat?, retry?, maxDuration? })`\n }\n }\n return undefined\n}\n\nfunction isInteger(value: unknown, min: number, max = Number.MAX_SAFE_INTEGER): boolean {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= min && value <= max\n}\n\n// -------------------------------------------------------------------------------------------------\n// Encoding\n// -------------------------------------------------------------------------------------------------\n\nconst EVENT_KEYS: ReadonlySet<string> = new Set(['data', 'event', 'id', 'retry', 'comment'])\nconst LINE_BREAK = /\\r\\n|\\r|\\n/\n\n/**\n * Encodes one event (WHATWG framing): one `: <line>` per comment line, `id:`, `event:`, `retry:`,\n * then one `data: <line>` per line of the data (split on CRLF, CR and LF, so data can never inject\n * fields or end the event early), and an empty line. An `event` without `data` gets an empty\n * `data:` line (otherwise `EventSource` would not dispatch it); events with only `id`, `retry` or\n * `comment` have no data line.\n *\n * ```ts\n * encodeSseEvent({ id: 41, event: 'status', data: { status: 'paid' } })\n * // 'id: 41\\nevent: status\\ndata: {\"status\":\"paid\"}\\n\\n'\n * ```\n *\n * @throws TypeError for anything but a plain object with the keys of {@link SseEvent} (strings,\n * numbers, `null`: yield `{ data: value }`), an empty event, an `event` / `id` with CR or LF (NUL\n * for `id`), a `retry` that is not an integer ≥ 0, a `data` JSON cannot serialise.\n */\nexport function encodeSseEvent(event: SseEvent): string {\n if (event === null || typeof event !== 'object' || !isPlainObject(event)) {\n throw new TypeError(\n `Invalid SSE event: expected an object { data?, event?, id?, retry?, comment? } (received ${describe(event)}): yield { data: value }`,\n )\n }\n let defined = 0\n for (const key of Object.keys(event)) {\n if (!EVENT_KEYS.has(key)) {\n throw new TypeError(`Invalid SSE event: unknown key \"${key}\" (keys: data, event, id, retry, comment)`)\n }\n if ((event as Record<string, unknown>)[key] !== undefined) defined++\n }\n if (defined === 0) throw new TypeError('Invalid SSE event: an empty event (set data, event, id, retry or comment)')\n const { data, event: type, id, retry, comment } = event\n let text = ''\n if (comment !== undefined) {\n if (typeof comment !== 'string') throw new TypeError('Invalid SSE event: comment must be a string')\n for (const line of comment.split(LINE_BREAK)) text += line === '' ? ':\\n' : `: ${line}\\n`\n }\n if (id !== undefined) {\n const value = typeof id === 'number' && Number.isFinite(id) ? String(id) : id\n if (typeof value !== 'string' || /[\\r\\n\\0]/.test(value)) {\n throw new TypeError('Invalid SSE event: id must be a string without CR, LF or NUL, or a finite number')\n }\n text += `id: ${value}\\n`\n }\n if (type !== undefined) {\n if (typeof type !== 'string' || /[\\r\\n]/.test(type)) {\n throw new TypeError('Invalid SSE event: event must be a string without CR or LF')\n }\n text += `event: ${type}\\n`\n }\n if (retry !== undefined) {\n if (!isInteger(retry, 0)) throw new TypeError('Invalid SSE event: retry must be an integer number of ms ≥ 0')\n text += `retry: ${retry}\\n`\n }\n if (data !== undefined) {\n for (const line of dataText(data).split(LINE_BREAK)) text += `data: ${line}\\n`\n } else if (type !== undefined) {\n text += 'data: \\n'\n }\n return `${text}\\n`\n}\n\nfunction dataText(data: unknown): string {\n if (typeof data === 'string') return data\n let json: string | undefined\n try {\n json = JSON.stringify(data)\n } catch (error) {\n throw new TypeError(`Invalid SSE event: data cannot be serialised as JSON (${errorText(error)})`, { cause: error })\n }\n if (json === undefined) throw new TypeError(`Invalid SSE event: data cannot be serialised as JSON (${typeof data})`)\n return json\n}\n\nfunction isPlainObject(value: object): boolean {\n const prototype: unknown = Object.getPrototypeOf(value)\n return prototype === Object.prototype || prototype === null\n}\n\nfunction describe(value: unknown): string {\n if (value === null) return 'null'\n if (typeof value === 'string') return 'a string'\n if (Array.isArray(value)) return 'an array'\n if (value instanceof Uint8Array) return 'bytes'\n return typeof value === 'object' ? `an instance of ${value.constructor?.name ?? 'a class'}` : typeof value\n}\n\nfunction errorText(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n// -------------------------------------------------------------------------------------------------\n// The event stream\n// -------------------------------------------------------------------------------------------------\n\n/** Default reconnection delay the jitter of the final `retry` starts from (ms). */\nexport const DEFAULT_RECONNECT_MS = 3_000\n/** How long a stopped source may take before the request scope closes anyway (ms). */\nexport const SOURCE_STOP_TIMEOUT_MS = 5_000\n\nconst ENCODER = new TextEncoder()\nconst HEARTBEAT = ENCODER.encode(':\\n\\n')\n\n/** Settings of one event stream (route options resolved over the plugin options). */\nexport interface SseStreamSettings {\n /** Heartbeat interval in ms; `0` disables it. */\n readonly heartbeat: number\n /** `retry` sent first, if any. */\n readonly retry: number | undefined\n /** `maxDuration` in ms, if any. */\n readonly maxDuration: number | undefined\n /** Time the source gets to finish after a graceful close started (ms). */\n readonly graceMs: number\n /** Bound of the source stop (ms). Default: {@link SOURCE_STOP_TIMEOUT_MS}. */\n readonly stopTimeoutMs?: number\n /** Random generator of the jitter (`[0, 1)`). Default: `Math.random`. */\n readonly random?: () => number\n}\n\n/** What the stream reports to the request (its context and its logger). */\nexport interface SseHost {\n /** Aborts `ctx.signal` with `kind`. */\n abort(kind: RequestAbortKind): void\n /** Logs a failure (`The SSE stream failed`) or a warning, with the request id and path. */\n error(message: string, error: unknown): void\n warn(message: string): void\n}\n\n/** A source being read: one pull at a time. */\ninterface SourceReader {\n next(): Promise<IteratorResult<unknown>>\n stop(): Promise<unknown>\n}\n\ntype Settled =\n | { readonly kind: 'value'; readonly value: unknown }\n | { readonly kind: 'done' }\n | { readonly kind: 'error'; readonly error: unknown }\n\n/**\n * One event stream: the byte stream sent to the client and the controls of the pipeline\n * ({@link close} on shutdown or `maxDuration`). The source is read only when the client pulls\n * (backpressure); the first chunk (`retry: N` or the comment `:`) is queued at once so that every\n * adapter flushes the headers.\n */\nexport class SseSession {\n /** The bytes to send (pull-based, `highWaterMark: 0`). */\n readonly stream: ReadableStream<Uint8Array>\n readonly #source: SseSource\n readonly #settings: SseStreamSettings\n readonly #host: SseHost\n readonly #run: ContextRunner\n #reader: SourceReader | undefined\n /** The source read in progress, kept across heartbeats until its item is consumed. */\n #pending: Promise<Settled> | undefined\n /** What {@link #pending} settled with, until {@link #pull} consumes it. */\n #settled: Settled | undefined\n /** Resolves the race waiting for {@link #pending} (one at a time). */\n #onSettled: (() => void) | undefined\n #controller: ReadableStreamDefaultController<Uint8Array> | undefined\n /** `open` → `closing` (graceful close running) → `ended`. */\n #phase: 'open' | 'closing' | 'ended' = 'open'\n /** The raw bytes written so far end at an event boundary (a heartbeat may follow). */\n #atBoundary = true\n /** Raw byte scanner: the current line has content / the previous byte was a CR. */\n #lineHasContent = false\n #afterCr = false\n /** Whether the line the last CR ended was empty (an event boundary, whether a LF follows or not). */\n #crBoundary = false\n #wake: (() => void) | undefined\n #graceTimer: ReturnType<typeof setTimeout> | undefined\n #maxTimer: ReturnType<typeof setTimeout> | undefined\n #stopped: Promise<void> | undefined\n #ended: () => void = () => undefined\n /** Resolves once the stream ended (source done, failed, stopped or cancelled). */\n readonly ended: Promise<void>\n\n constructor(source: SseSource, settings: SseStreamSettings, host: SseHost) {\n this.#source = source\n this.#settings = settings\n this.#host = host\n // the source runs in the handler's async context (request scope, tracing), timers included\n this.#run = captureContext()\n this.ended = new Promise(resolve => {\n this.#ended = resolve\n })\n this.stream = new ReadableStream<Uint8Array>(\n {\n start: controller => {\n this.#controller = controller\n const retry = settings.retry\n controller.enqueue(retry === undefined ? HEARTBEAT : ENCODER.encode(`retry: ${retry}\\n\\n`))\n if (settings.maxDuration !== undefined) {\n this.#maxTimer = unref(setTimeout(() => this.close('expired'), timerDelay(settings.maxDuration)))\n }\n },\n pull: controller => this.#pull(controller),\n cancel: () => this.#cancel(),\n },\n { highWaterMark: 0 },\n )\n }\n\n /** Whether the stream is closing or over. */\n get closed(): boolean {\n return this.#phase !== 'open'\n }\n\n /**\n * Starts the graceful close (shutdown, `maxDuration`): `ctx.signal` aborts with `kind`, the source\n * may yield its final events for `graceMs`, then a jittered `retry` is sent, the source is stopped\n * and the response ends. Idempotent.\n */\n close(kind: 'shutdown' | 'expired'): void {\n if (this.#phase !== 'open') return\n this.#phase = 'closing'\n clearTimeout(this.#maxTimer)\n this.#host.abort(kind)\n this.#graceTimer = unref(setTimeout(() => void this.#endGracefully(), timerDelay(this.#settings.graceMs)))\n this.#wake?.()\n }\n\n async #pull(controller: ReadableStreamDefaultController<Uint8Array>): Promise<void> {\n for (;;) {\n if (this.#phase === 'ended') return\n this.#next()\n const heartbeat =\n this.#phase === 'open' && this.#settings.heartbeat > 0 && this.#atBoundary ? this.#settings.heartbeat : 0\n const outcome = await this.#race(heartbeat)\n // closed or cancelled while waiting\n if (this.#isEnded()) return\n if (outcome === 'heartbeat') {\n controller.enqueue(HEARTBEAT)\n return\n }\n if (outcome === 'wake') continue\n this.#pending = undefined\n this.#settled = undefined\n if (outcome.kind === 'done') {\n await this.#finish()\n return\n }\n if (outcome.kind === 'error') {\n if (!this.#isAbortError(outcome.error)) this.#host.error('The SSE stream failed', outcome.error)\n await this.#finish()\n return\n }\n const value = outcome.value\n if (value instanceof Uint8Array) {\n if (value.byteLength === 0) continue\n this.#scan(value)\n controller.enqueue(value)\n return\n }\n let encoded: string\n try {\n if (!this.#endsAtBoundary()) {\n // an event written after an unterminated raw event would merge into it\n throw new TypeError(\n 'Invalid SSE event: an SseEvent cannot follow raw bytes that do not end at an event boundary (an empty line)',\n )\n }\n encoded = encodeSseEvent(value as SseEvent)\n } catch (error) {\n this.#host.error('The SSE stream failed', error)\n await this.#finish(true)\n return\n }\n controller.enqueue(ENCODER.encode(encoded))\n this.#atBoundary = true\n this.#lineHasContent = false\n this.#afterCr = false\n return\n }\n }\n\n /**\n * Starts the next read of the source, unless one is pending (it is kept across heartbeats). The\n * read gets one reaction for its whole life, which records its outcome: a quiet source does not\n * accumulate a reaction per heartbeat.\n */\n #next(): void {\n if (this.#pending !== undefined) return\n const pending = this.#run(() => {\n try {\n return this.#readerOf().next()\n } catch (error) {\n return Promise.reject(error)\n }\n }).then(\n (result): Settled => (result.done === true ? { kind: 'done' } : { kind: 'value', value: result.value }),\n (error: unknown): Settled => ({ kind: 'error', error }),\n )\n this.#pending = pending\n void pending.then(outcome => {\n if (this.#pending !== pending) return\n this.#settled = outcome\n this.#onSettled?.()\n })\n }\n\n /** Waits for the pending item, a heartbeat delay (`0`: none) or a wake-up (close, cancel). */\n #race(heartbeat: number): Promise<Settled | 'heartbeat' | 'wake'> {\n // settled while nobody waited (after a heartbeat or a wake-up): kept until consumed\n if (this.#settled !== undefined) return Promise.resolve(this.#settled)\n return new Promise(resolve => {\n let timer: ReturnType<typeof setTimeout> | undefined\n let done = false\n const settle = (outcome: Settled | 'heartbeat' | 'wake'): void => {\n if (done) return\n done = true\n clearTimeout(timer)\n if (this.#wake === wake) this.#wake = undefined\n if (this.#onSettled === settled) this.#onSettled = undefined\n resolve(outcome)\n }\n const wake = (): void => settle('wake')\n const settled = (): void => settle(this.#settled as Settled)\n if (heartbeat > 0) timer = unref(setTimeout(() => settle('heartbeat'), timerDelay(heartbeat)))\n this.#wake = wake\n this.#onSettled = settled\n })\n }\n\n /** Tracks whether the raw bytes written so far end at an event boundary (an empty line). */\n #scan(bytes: Uint8Array): void {\n for (const byte of bytes) {\n if (byte === 0x0a && this.#afterCr) {\n // the LF of a CRLF (possibly the first byte of a chunk): the CR decided the boundary\n this.#afterCr = false\n this.#atBoundary = this.#crBoundary\n continue\n }\n this.#afterCr = byte === 0x0d\n if (byte === 0x0a || byte === 0x0d) {\n this.#atBoundary = !this.#lineHasContent\n this.#lineHasContent = false\n if (this.#afterCr) this.#crBoundary = this.#atBoundary\n } else {\n this.#lineHasContent = true\n this.#atBoundary = false\n }\n }\n // a final CR may be the first half of a CRLF: no heartbeat until the next byte tells\n if (this.#afterCr) this.#atBoundary = false\n }\n\n /**\n * Whether the bytes written so far end at an event boundary, for bytes written once the source\n * is over (the final `retry`) or replaced (an encoded event): a final CR ending an empty line\n * counts, since no raw byte will follow it.\n */\n #endsAtBoundary(): boolean {\n return this.#atBoundary || (this.#afterCr && this.#crBoundary)\n }\n\n /**\n * Ends the stream after the source: done, failed, or an invalid item (`stop`: the source is\n * stopped). During a graceful close the jittered `retry` is written first.\n */\n async #finish(stop = false): Promise<void> {\n if (this.#phase === 'ended') return\n const graceful = this.#phase === 'closing'\n this.#phase = 'ended'\n this.#clearTimers()\n const controller = this.#controller as ReadableStreamDefaultController<Uint8Array>\n // never inside an unterminated raw event (the client discards it at the end of the stream)\n if (graceful && this.#endsAtBoundary()) controller.enqueue(this.#finalRetry())\n if (stop) await this.#stop()\n try {\n controller.close()\n } catch {\n // cancelled meanwhile\n }\n this.#ended()\n }\n\n /** The grace period is over: final `retry`, the source is stopped (bounded), the response ends. */\n async #endGracefully(): Promise<void> {\n if (this.#phase !== 'closing') return\n this.#phase = 'ended'\n this.#clearTimers()\n const controller = this.#controller as ReadableStreamDefaultController<Uint8Array>\n // never inside an unterminated raw event (the client discards it at the end of the stream)\n if (this.#endsAtBoundary()) controller.enqueue(this.#finalRetry())\n this.#wake?.()\n await this.#stop()\n try {\n controller.close()\n } catch {\n // cancelled meanwhile\n }\n this.#ended()\n }\n\n /** The client disconnected (or the body was discarded: HEAD, bodyless status, invalid headers). */\n async #cancel(): Promise<void> {\n const wasEnded = this.#phase === 'ended'\n this.#phase = 'ended'\n this.#clearTimers()\n this.#host.abort('client')\n this.#wake?.()\n if (!wasEnded || this.#stopped !== undefined) await this.#stop()\n this.#ended()\n }\n\n /** `retry: R` with R drawn uniformly in [r, 2r] (spreads the reconnections of a rolling deployment). */\n #finalRetry(): Uint8Array {\n const base = this.#settings.retry ?? DEFAULT_RECONNECT_MS\n const random = this.#settings.random ?? Math.random\n return ENCODER.encode(`retry: ${Math.round(base + random() * base)}\\n\\n`)\n }\n\n /**\n * Stops the source (`return()` / `cancel()`) and waits for it at most `stopTimeoutMs`: an async\n * generator blocked in an `await` that ignores `ctx.signal` would hold the request scope forever.\n */\n #stop(): Promise<void> {\n this.#stopped ??= this.#stopBounded()\n return this.#stopped\n }\n\n async #stopBounded(): Promise<void> {\n const timeoutMs = this.#settings.stopTimeoutMs ?? SOURCE_STOP_TIMEOUT_MS\n let timer: ReturnType<typeof setTimeout> | undefined\n const stopping = this.#run(() => {\n try {\n return this.#readerOf().stop()\n } catch {\n return Promise.resolve()\n }\n }).then(\n () => 'stopped' as const,\n () => 'stopped' as const,\n )\n const timeout = new Promise<'timeout'>(resolve => {\n timer = unref(setTimeout(() => resolve('timeout'), timeoutMs))\n })\n const outcome = await Promise.race([stopping, timeout])\n clearTimeout(timer)\n if (outcome === 'timeout') {\n this.#host.warn(\n `The SSE source did not stop within ${timeoutMs} ms after its signal was aborted: make it honour ctx.signal`,\n )\n }\n }\n\n #isEnded(): boolean {\n return this.#phase === 'ended'\n }\n\n #clearTimers(): void {\n clearTimeout(this.#graceTimer)\n clearTimeout(this.#maxTimer)\n }\n\n /** An error caused by the abort of `ctx.signal` (a source honouring it): not a failure. */\n #isAbortError(error: unknown): boolean {\n return this.#phase !== 'open' && (error as { name?: unknown } | null)?.name === 'AbortError'\n }\n\n /** The reader of the source, created on first use (a never-read async generator never runs). */\n #readerOf(): SourceReader {\n this.#reader ??= readerOf(this.#source)\n return this.#reader\n }\n}\n\nfunction readerOf(source: SseSource): SourceReader {\n if (source instanceof ReadableStream) {\n const reader = source.getReader() as unknown as {\n read(): Promise<IteratorResult<unknown>>\n cancel(reason?: unknown): Promise<void>\n }\n return {\n next: () => reader.read(),\n stop: () => reader.cancel(),\n }\n }\n const asyncFactory = (source as { [Symbol.asyncIterator]?: () => AsyncIterator<unknown> })[Symbol.asyncIterator]\n if (typeof asyncFactory === 'function') {\n const iterator = asyncFactory.call(source)\n return {\n next: () => iterator.next(),\n stop: async () => {\n await iterator.return?.()\n },\n }\n }\n const iterator = (source as Iterable<unknown>)[Symbol.iterator]()\n return {\n next: () => Promise.resolve(iterator.next()),\n stop: () => Promise.resolve(iterator.return?.()),\n }\n}\n\n/** A delay `setTimeout` keeps (larger ones overflow to 1 ms): the options are validated, this is a backstop. */\nfunction timerDelay(ms: number): number {\n return Math.min(ms, MAX_SSE_TIMER_MS)\n}\n\nfunction unref<T>(timer: T): T {\n ;(timer as { unref?: () => void }).unref?.()\n return timer\n}\n","import type { HeaderValue } from './exceptions.ts'\n\nimport {\n type ClearCookieOptions,\n type CookieOptions,\n checkCookie,\n givenCookieKey,\n type ResponseCookie,\n} from './cookies.ts'\nimport { type ContentDispositionType, contentDisposition, FileBody, type FileResponseOptions } from './files.ts'\nimport { contentTypeFor, OCTET_STREAM } from './mime.ts'\nimport { SseBody, type SseOptions, type SseSource } from './sse.ts'\nimport { isValidStatus } from './status.ts'\nimport { isStreamSource, type StreamSource, toByteStream } from './stream.ts'\n\n/** Options of {@link HttpResponse.stream}. */\nexport interface StreamResponseOptions {\n /** Media type. Default: from the extension of `filename`, else `application/octet-stream`. */\n readonly contentType?: string\n /** Name proposed to the client (`Content-Disposition: attachment` unless `disposition` says otherwise). */\n readonly filename?: string\n /** `attachment` or `inline`. Default: `attachment` when `filename` is set, otherwise no header. */\n readonly disposition?: ContentDispositionType\n}\n\n/** Options of {@link HttpResponse}. */\nexport interface HttpResponseInit {\n /** Status code. Default: the route default (`@HttpCode`, 201 for POST, 204 without body, 200). */\n readonly status?: number\n /** Response headers (names are case-insensitive; arrays send the header several times). */\n readonly headers?: Readonly<Record<string, HeaderValue>>\n /** Cookies to set (see {@link HttpResponse.withCookie}), in order. */\n readonly cookies?: readonly ResponseCookie[]\n}\n\n/** Redirect statuses accepted by {@link HttpResponse.redirect}. */\nexport type RedirectStatus = 301 | 302 | 303 | 307 | 308\n\n/**\n * A handler result carrying a status and headers next to the body. The body is serialised with the\n * usual rules (objects → JSON, strings → text, bytes and streams → octet-stream).\n *\n * ```ts\n * @Post('/')\n * async create(@Body(CreateUser) input: CreateUser): Promise<HttpResponse<User>> {\n * const user = await this.users.create(input)\n * return HttpResponse.created(user, `/users/${user.id}`)\n * }\n * ```\n *\n * Status precedence: `@HttpCode` > `HttpResponse.status` > route default.\n */\nexport class HttpResponse<T = unknown> {\n readonly body: T\n readonly status: number | undefined\n readonly headers: Readonly<Record<string, HeaderValue>>\n /** Cookies set by this response (`withCookie` / `withoutCookie`), in order; they win over `ctx.setCookie()`. */\n readonly cookies: readonly ResponseCookie[]\n\n constructor(body: T, init: HttpResponseInit = {}) {\n if (init.status !== undefined && !isValidStatus(init.status)) {\n throw new RangeError(`Invalid HTTP status ${String(init.status)} (expected an integer between 100 and 599)`)\n }\n this.body = body\n this.status = init.status\n this.headers = init.headers ?? {}\n this.cookies = init.cookies === undefined ? NO_COOKIES : Object.freeze([...init.cookies])\n }\n\n /** `200 OK` with `body`. */\n static ok<T>(body: T, headers?: Readonly<Record<string, HeaderValue>>): HttpResponse<T> {\n return new HttpResponse(body, headers === undefined ? { status: 200 } : { status: 200, headers })\n }\n\n /**\n * `201 Created`, with a `location` header when given. With a body, the response is typed with it\n * (`Promise<HttpResponse<BookResponse>>` type-checks).\n */\n static created(): HttpResponse<undefined>\n static created<T>(body: T, location?: string): HttpResponse<T>\n static created<T>(body?: T, location?: string): HttpResponse<T | undefined> {\n return new HttpResponse(body, location === undefined ? { status: 201 } : { status: 201, headers: { location } })\n }\n\n /** `202 Accepted`, typed with its body when there is one. */\n static accepted(): HttpResponse<undefined>\n static accepted<T>(body: T): HttpResponse<T>\n static accepted<T>(body?: T): HttpResponse<T | undefined> {\n return new HttpResponse(body, { status: 202 })\n }\n\n /** `204 No Content`. */\n static noContent(): HttpResponse<undefined> {\n return new HttpResponse(undefined, { status: 204 })\n }\n\n /** A redirect (`302 Found` by default) to `location`. */\n static redirect(location: string, status: RedirectStatus = 302): HttpResponse<undefined> {\n return new HttpResponse(undefined, { status, headers: { location } })\n }\n\n /**\n * Sends a file from disk (`string` path or `file:` URL) or a `Blob` / `File`, streamed with\n * `Content-Length`, `Content-Type` (from the extension, see `contentTypeFor`), `Last-Modified`,\n * `ETag` and `Accept-Ranges`. Conditional requests answer 304 / 412 and single byte ranges 206\n * (416 when unsatisfiable). A missing file answers 404.\n *\n * ```ts\n * @Get('/reports/:name')\n * download(@Param('name') name: string) {\n * // `root` confines the path: '../../etc/passwd' answers 404\n * return HttpResponse.file(name, { root: REPORTS_DIR, filename: `rapport ${name}` })\n * }\n * ```\n *\n * Never pass a path built from the request without `root`.\n */\n static file(file: string | URL | Blob, options?: FileResponseOptions): HttpResponse<FileBody> {\n return new HttpResponse(new FileBody(file, options))\n }\n\n /**\n * Streams a Web `ReadableStream`, a Node.js `Readable` or an async iterable (async generator) of\n * `Uint8Array` / `string` chunks. The source is read as the client receives the data\n * (backpressure) and cancelled when the client disconnects; it runs in the request scope.\n *\n * ```ts\n * @Get('/export.csv')\n * export() {\n * return HttpResponse.stream(this.rows.csvLines(), { filename: 'export.csv' }) // text/csv; charset=utf-8\n * }\n * ```\n */\n static stream(source: StreamSource, options: StreamResponseOptions = {}): HttpResponse<ReadableStream<Uint8Array>> {\n if (!isStreamSource(source)) {\n throw new TypeError(\n 'HttpResponse.stream() expects a ReadableStream, a Node.js Readable or an async iterable of Uint8Array / string chunks',\n )\n }\n const headers: Record<string, HeaderValue> = {\n 'content-type':\n options.contentType ??\n (options.filename === undefined ? undefined : contentTypeFor(options.filename)) ??\n OCTET_STREAM,\n }\n const disposition = options.disposition ?? (options.filename === undefined ? undefined : 'attachment')\n if (disposition !== undefined) headers['content-disposition'] = contentDisposition(options.filename, disposition)\n return new HttpResponse(toByteStream(source), { headers })\n }\n\n /**\n * An event stream (Server-Sent Events) on any route and any method: `200` unless `@HttpCode` or\n * {@link withStatus} say otherwise (`EventSource` requires 200; `fetch()` clients read any status),\n * even on `POST` routes. Same source, framing and lifecycle as an `@Sse()` route.\n *\n * ```ts\n * @Post('/:id/assistant')\n * assistant(@Param('id') id: string, @Body(Prompt) prompt: Prompt, @Ctx() ctx: HttpContext) {\n * return HttpResponse.sse(this.llm.complete(id, prompt, { signal: ctx.signal }))\n * }\n * ```\n */\n static sse(source: SseSource, options?: SseOptions): HttpResponse<SseBody> {\n return new HttpResponse(new SseBody(source, options))\n }\n\n /** A copy of this response with `name` set to `value`. */\n withHeader(name: string, value: HeaderValue): HttpResponse<T> {\n return this.#copy({ headers: { ...this.headers, [name.toLowerCase()]: value } })\n }\n\n /** A copy of this response with another status. */\n withStatus(status: number): HttpResponse<T> {\n return this.#copy({ status })\n }\n\n /**\n * A copy of this response setting a cookie, with the secure defaults (`Path=/; Secure; HttpOnly;\n * SameSite=Lax`, see the plugin option `cookies.defaults`). It replaces a cookie with the same name,\n * domain and path set by `ctx.setCookie()` or an earlier `withCookie()`.\n *\n * ```ts\n * return HttpResponse.ok({ id: user.id }).withCookie('__Host-uid', user.id, { signed: true, maxAge: 8 * 3600 })\n * ```\n *\n * The name, the value, the lifetime, the domain, the path and the size are checked now; the rules\n * depending on the plugin (`secure` default with a prefix or `SameSite=None`, signing, the final\n * size) when the response is sent: a violation then answers a generic 500, logged as\n * `Invalid cookie \"name\": …`.\n *\n * @throws TypeError / RangeError for an invalid cookie.\n */\n withCookie(name: string, value: string, options: CookieOptions = {}): HttpResponse<T> {\n checkCookie(name, value, options)\n return this.#copy({ cookies: withCookie(this.cookies, { name, value, options: Object.freeze({ ...options }) }) })\n }\n\n /** A copy of this response clearing a cookie (see `ctx.clearCookie()`). */\n withoutCookie(name: string, options: ClearCookieOptions = {}): HttpResponse<T> {\n if (options === null || typeof options !== 'object') {\n throw new TypeError(`Invalid cookie ${JSON.stringify(String(name))}: options must be an object`)\n }\n const { maxAge: _maxAge, expires: _expires, signed: _signed, ...clear } = options as CookieOptions\n checkCookie(name, undefined, clear)\n return this.#copy({ cookies: withCookie(this.cookies, { name, value: undefined, options: Object.freeze(clear) }) })\n }\n\n #copy(changes: HttpResponseInit): HttpResponse<T> {\n const status = changes.status ?? this.status\n return new HttpResponse(this.body, {\n ...(status === undefined ? {} : { status }),\n headers: changes.headers ?? this.headers,\n cookies: changes.cookies ?? this.cookies,\n })\n }\n}\n\nconst NO_COOKIES: readonly ResponseCookie[] = Object.freeze([])\n\n/** `cookies` with `cookie` added, replacing (in place) a cookie of the same name, domain and path. */\nfunction withCookie(cookies: readonly ResponseCookie[], cookie: ResponseCookie): ResponseCookie[] {\n const key = givenCookieKey(cookie.name, cookie.options)\n const index = cookies.findIndex(existing => givenCookieKey(existing.name, existing.options) === key)\n if (index === -1) return [...cookies, cookie]\n const result = [...cookies]\n result[index] = cookie\n return result\n}\n\n/** Whether `value` is an {@link HttpResponse} (also across duplicated package copies). */\nexport function isHttpResponse(value: unknown): value is HttpResponse {\n return (\n value instanceof HttpResponse ||\n (value !== null &&\n typeof value === 'object' &&\n (value as { constructor?: { name?: unknown } }).constructor?.name === 'HttpResponse' &&\n 'body' in value &&\n 'headers' in value)\n )\n}\n","import type { ReplyBody } from './adapter.ts'\nimport type { ResponseCookie } from './cookies.ts'\nimport type { HeaderValue, HttpErrorBody } from './exceptions.ts'\nimport type { ResolvedFile } from './files.ts'\nimport type { HttpResponse } from './response.ts'\nimport type { SseSession } from './sse.ts'\n\nimport { Readable } from 'node:stream'\n\nimport { isFileBody } from './files.ts'\nimport { isHttpResponse } from './response.ts'\nimport { isSseBody } from './sse.ts'\nimport { isBodylessStatus } from './status.ts'\nimport { discardStream, isByteStream, toByteStream } from './stream.ts'\nimport { emptyRecord } from './utils.ts'\n\nconst ENCODER = new TextEncoder()\n\n/** Content types set by the serialiser. */\nexport const ContentType: {\n readonly json: string\n readonly text: string\n readonly bytes: string\n readonly eventStream: string\n} = Object.freeze({\n json: 'application/json; charset=utf-8',\n text: 'text/plain; charset=utf-8',\n bytes: 'application/octet-stream',\n eventStream: 'text/event-stream; charset=utf-8',\n})\n\n/** How a handler result is turned into a response. */\nexport interface SerializeOptions {\n /** Request method (`HEAD` responses have no body). */\n readonly method: string\n /** Method of the route definition (`POST` routes default to 201). */\n readonly routeMethod: string\n /** `@HttpCode` status (wins over everything but a Web `Response`). */\n readonly status: number | undefined\n /** `@Header` entries. */\n readonly headers: Readonly<Record<string, string>> | undefined\n /** Headers set on the context (`ctx.setHeader`), applied after `@Header`. */\n readonly context?: Readonly<Record<string, HeaderValue>> | undefined\n}\n\n/** A serialised response (mutable headers, merged by the pipeline). */\nexport interface SerializedReply {\n readonly status: number\n readonly headers: Record<string, HeaderValue>\n readonly body: ReplyBody\n /** Cookies of the `HttpResponse` (`withCookie`), applied by the pipeline over those of the context. */\n readonly cookies?: readonly ResponseCookie[]\n /** The event stream of the body (`@Sse`, `HttpResponse.sse()`). */\n readonly sse?: SseSession\n}\n\n/**\n * Serialises a handler result:\n *\n * - Web `Response` → sent as is (status, headers, body); `@HttpCode` / `@Header` do not apply;\n * - `HttpResponse` → its body with its status and headers;\n * - `undefined` → empty body, `204` (`201` for POST routes);\n * - `string` → `text/plain`; `Uint8Array`/`ArrayBuffer`/views → `application/octet-stream`;\n * - `ReadableStream`, Node.js `Readable`, `Blob` → streamed (`application/octet-stream` or the blob type);\n * - anything else (objects, arrays, numbers, booleans, `null`) → JSON.\n *\n * Status precedence: `@HttpCode` > `HttpResponse.status` > default (`201` for POST routes,\n * `204` without body, `200`). Header precedence: content type < `@Header` < `ctx.setHeader()` <\n * `HttpResponse.headers` (a Web `Response` keeps its own headers).\n */\nexport function serializeResult(result: unknown, options: SerializeOptions): SerializedReply {\n if (result instanceof Response) {\n const reply = fromWebResponse(result, options.method)\n if (options.context !== undefined) addMissingHeaders(reply.headers, options.context)\n return reply\n }\n let payload = result\n let status: number | undefined\n let extra: Readonly<Record<string, HeaderValue>> | undefined\n let cookies: readonly ResponseCookie[] | undefined\n if (isHttpResponse(result)) {\n payload = result.body\n status = result.status\n extra = result.headers\n cookies = cookiesOf(result)\n }\n const finalStatus = options.status ?? status ?? defaultStatus(options.routeMethod, payload)\n const headers = emptyRecord<HeaderValue>()\n const body = encode(payload, headers)\n if (options.headers !== undefined) assignHeaders(headers, options.headers)\n if (options.context !== undefined) assignHeaders(headers, options.context)\n if (extra !== undefined) assignHeaders(headers, extra)\n return withCookies(finish(finalStatus, headers, body, options.method), cookies)\n}\n\n/**\n * Serialises an event stream (`@Sse` result, `HttpResponse.sse()`): status 200 unless `@HttpCode`\n * or `HttpResponse.status` say otherwise; `cache-control: no-cache, no-transform` and\n * `x-accel-buffering: no` under `@Header`, `ctx.setHeader()` and the `HttpResponse` headers;\n * `content-type: text/event-stream; charset=utf-8` last; never `content-length` or\n * `transfer-encoding`. A `HEAD` request or a bodyless status cancels the stream before its first read.\n */\nexport function serializeSseReply(\n session: SseSession,\n response: HttpResponse | undefined,\n options: SerializeOptions,\n): SerializedReply {\n const status = options.status ?? response?.status ?? 200\n const headers = emptyRecord<HeaderValue>()\n headers['cache-control'] = 'no-cache, no-transform'\n headers['x-accel-buffering'] = 'no'\n if (options.headers !== undefined) assignHeaders(headers, options.headers)\n if (options.context !== undefined) assignHeaders(headers, options.context)\n if (response !== undefined) assignHeaders(headers, response.headers)\n headers['content-type'] = ContentType.eventStream\n delete headers['content-length']\n delete headers['transfer-encoding']\n const reply = finish(status, headers, session.stream, options.method)\n return withCookies(reply.body === null ? reply : { ...reply, sse: session }, response && cookiesOf(response))\n}\n\n/** The cookies of an `HttpResponse` (none for a copy of the class from an older package version). */\nfunction cookiesOf(response: HttpResponse): readonly ResponseCookie[] | undefined {\n const cookies = (response as { cookies?: readonly ResponseCookie[] }).cookies\n return Array.isArray(cookies) && cookies.length > 0 ? cookies : undefined\n}\n\nfunction withCookies(reply: SerializedReply, cookies: readonly ResponseCookie[] | undefined): SerializedReply {\n return cookies === undefined ? reply : { ...reply, cookies }\n}\n\n/**\n * Serialises a resolved file response (`HttpResponse.file()`): the file headers, then `@Header`,\n * `ctx.setHeader()` and the `HttpResponse` headers. 206 / 304 keep their status; a 200 follows the\n * usual precedence (`@HttpCode` > `HttpResponse.status` > 200).\n */\nexport function serializeFileReply(\n file: ResolvedFile,\n response: HttpResponse,\n options: SerializeOptions,\n): SerializedReply {\n const status = file.status === 200 ? (options.status ?? response.status ?? 200) : file.status\n const headers = emptyRecord<HeaderValue>()\n assignHeaders(headers, file.headers)\n if (options.headers !== undefined) assignHeaders(headers, options.headers)\n if (options.context !== undefined) assignHeaders(headers, options.context)\n assignHeaders(headers, response.headers)\n return withCookies(finish(status, headers, file.body, options.method), cookiesOf(response))\n}\n\n/** `201` for POST routes, otherwise `204` without payload and `200` with one. */\nfunction defaultStatus(routeMethod: string, payload: unknown): number {\n if (routeMethod === 'POST') return 201\n return payload === undefined ? 204 : 200\n}\n\n/** Serialises an error body as JSON. */\nexport function serializeError(status: number, body: HttpErrorBody | unknown, method: string): SerializedReply {\n const headers = emptyRecord<HeaderValue>()\n const encoded = encode(body, headers)\n return finish(status, headers, encoded, method)\n}\n\n/** Copies headers with lower-case names (later values win). */\nexport function assignHeaders(\n target: Record<string, HeaderValue>,\n source: Readonly<Record<string, HeaderValue>>,\n): void {\n for (const name of Object.keys(source)) {\n const value = source[name]\n if (value !== undefined) target[name.toLowerCase()] = typeof value === 'string' ? value : [...value]\n }\n}\n\n/** Adds headers that are not already present (case-insensitive). */\nexport function addMissingHeaders(\n target: Record<string, HeaderValue>,\n source: Readonly<Record<string, HeaderValue>>,\n): void {\n for (const name of Object.keys(source)) {\n const key = name.toLowerCase()\n const value = source[name]\n if (value !== undefined && target[key] === undefined) target[key] = typeof value === 'string' ? value : [...value]\n }\n}\n\nfunction finish(\n status: number,\n headers: Record<string, HeaderValue>,\n body: ReplyBody,\n method: string,\n): SerializedReply {\n if (isBodylessStatus(status)) {\n discard(body)\n delete headers['content-type']\n delete headers['content-length']\n return { status, headers, body: null }\n }\n if (method === 'HEAD') {\n discard(body)\n return { status, headers, body: null }\n }\n return { status, headers, body }\n}\n\nfunction discard(body: ReplyBody): void {\n if (body instanceof ReadableStream) discardStream(body)\n}\n\nfunction encode(payload: unknown, headers: Record<string, HeaderValue>): ReplyBody {\n if (payload === undefined) return null\n if (typeof payload === 'string') return bytes(ENCODER.encode(payload), headers, ContentType.text)\n if (payload instanceof Uint8Array) return bytes(payload, headers, ContentType.bytes)\n if (payload instanceof ArrayBuffer) return bytes(new Uint8Array(payload), headers, ContentType.bytes)\n if (ArrayBuffer.isView(payload)) {\n return bytes(new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength), headers, ContentType.bytes)\n }\n if (payload instanceof ReadableStream) {\n headers['content-type'] = ContentType.bytes\n // adapters get bytes (`ReplyBody`): string / ArrayBuffer chunks of a returned stream are converted\n return isByteStream(payload) ? (payload as ReadableStream<Uint8Array>) : toByteStream(payload)\n }\n if (payload instanceof Blob) {\n headers['content-type'] = payload.type === '' ? ContentType.bytes : payload.type\n headers['content-length'] = String(payload.size)\n return payload\n }\n if (isNodeReadable(payload)) {\n headers['content-type'] = ContentType.bytes\n return toByteStream(payload)\n }\n if (isFileBody(payload)) throw new TypeError('A file body (HttpResponse.file()) cannot be serialised here')\n if (isSseBody(payload)) throw new TypeError('An event stream (HttpResponse.sse()) cannot be serialised here')\n const json = JSON.stringify(payload)\n if (json === undefined) throw new TypeError(`Cannot serialise a ${typeof payload} as a response body`)\n return bytes(ENCODER.encode(json), headers, ContentType.json)\n}\n\nfunction bytes(data: Uint8Array, headers: Record<string, HeaderValue>, type: string): Uint8Array {\n headers['content-type'] = type\n headers['content-length'] = String(data.byteLength)\n return data\n}\n\nfunction isNodeReadable(value: unknown): value is Readable {\n return (\n value instanceof Readable ||\n (value !== null &&\n typeof value === 'object' &&\n typeof (value as { pipe?: unknown }).pipe === 'function' &&\n typeof (value as { on?: unknown }).on === 'function' &&\n typeof (value as { read?: unknown }).read === 'function')\n )\n}\n\nfunction fromWebResponse(response: Response, method: string): SerializedReply {\n const headers = emptyRecord<HeaderValue>()\n for (const [name, value] of response.headers) {\n if (name !== 'set-cookie') headers[name] = value\n }\n const cookies = response.headers.getSetCookie()\n if (cookies.length > 0) headers['set-cookie'] = cookies\n return finish(response.status, headers, response.body, method)\n}\n","import type { TypedToken } from '@znight/core'\nimport type { HttpContext, RequestId } from './context.ts'\nimport type { HttpPlugin } from './plugin.ts'\n\n/**\n * Tokens of the values `@znight/http` supplies to the container. `HttpContext` and `RequestId` are\n * request-scoped externals (declared in the package manifest): inject them in request-scoped\n * providers or through `Lazy<HttpContext>`.\n */\nexport const HttpTokens: {\n /** The {@link HttpContext} of the current request (request scope). */\n readonly Context: TypedToken<HttpContext>\n /** The id of the current request (request scope). */\n readonly RequestId: TypedToken<RequestId>\n /** The {@link HttpPlugin} instance (singleton). */\n readonly Plugin: TypedToken<HttpPlugin>\n} = Object.freeze({\n Context: '@znight/http#HttpContext',\n RequestId: '@znight/http#RequestId',\n Plugin: '@znight/http#HttpPlugin',\n})\n","import type { Container, CoreLogger, Hooks, HttpRequestEvent, Token } from '@znight/core'\nimport type { AdapterReply, AdapterRequest, ReplyBody } from './adapter.ts'\nimport type { CookieSettings } from './cookie-settings.ts'\nimport type { SerializedCookie } from './cookies.ts'\nimport type { CorsPolicy } from './cors.ts'\nimport type { CanActivate, ExceptionMapper, HttpInterceptor } from './interfaces.ts'\nimport type { HttpRouteDefinition, HttpSseDefinition } from './metadata.ts'\nimport type { TrustPolicy } from './proxy.ts'\nimport type { RouteTable } from './router.ts'\nimport type { BodyPlan } from './uploads.ts'\n\nimport { displayName } from '@znight/core'\n\nimport { isEventStreamType } from './adapters/shared.ts'\nimport { type HttpRouteInfo, RequestContext, type RequestId } from './context.ts'\nimport { DEFAULT_COOKIE_SETTINGS, serializeWith } from './cookie-settings.ts'\nimport { corsReplyHeaders, isPreflight, mergeVary, preflightHeaders } from './cors.ts'\nimport {\n BadRequestException,\n ForbiddenException,\n type HeaderValue,\n HttpException,\n isHttpException,\n MethodNotAllowedException,\n NotFoundException,\n} from './exceptions.ts'\nimport { isFileBody, resolveFile } from './files.ts'\nimport { findInvalidHeader, isHeaderValue } from './headers.ts'\nimport { decodePathValue, matchRoutePath, type RoutePath } from './path.ts'\nimport { splitUrl } from './query.ts'\nimport { HttpResponse, isHttpResponse } from './response.ts'\nimport {\n addMissingHeaders,\n assignHeaders,\n type SerializedReply,\n type SerializeOptions,\n serializeError,\n serializeFileReply,\n serializeResult,\n serializeSseReply,\n} from './serialize.ts'\nimport { isSseBody, isSseSource, type SseOptions, SseSession, type SseSource } from './sse.ts'\nimport { type ContextRunner, captureContext, discardStream, trackStream } from './stream.ts'\nimport { HttpTokens } from './tokens.ts'\nimport { emptyRecord, errorMessage } from './utils.ts'\n\n/** A dependency of the pipeline: an instance resolved at bootstrap, or a token resolved per request. */\nexport type Resolvable<T> = { readonly instance: T } | { readonly token: Token }\n\n/** Everything the pipeline needs to serve one registered route (internal). */\nexport interface RoutePlan {\n readonly definition: HttpRouteDefinition\n /** The registered path (a trailing-slash variant has an extra empty static segment). */\n readonly path: RoutePath\n readonly info: HttpRouteInfo\n readonly controller: Resolvable<object>\n readonly guards: readonly Resolvable<CanActivate>[]\n readonly interceptors: readonly Resolvable<HttpInterceptor>[]\n /** Parse the body before the interceptors (`@Body()` or upload parameters). */\n readonly parseBody: boolean\n /** Body limit and multipart rules of the route. */\n readonly body: BodyPlan\n /** Trailing-slash variant answered with a redirect to the path without its trailing slash. */\n readonly redirect?: boolean\n}\n\n/** Pipeline settings (resolved plugin options). */\nexport interface PipelineOptions {\n readonly adapter: string\n /** Body plan of unmatched requests (plugin `bodyLimit`, generic multipart rules). */\n readonly body: BodyPlan\n readonly exposeErrors: boolean\n readonly requestIdHeader: string | undefined\n readonly generateRequestId: () => string\n readonly mappers: readonly Resolvable<ExceptionMapper>[]\n /** CORS policy (`cors` option), `undefined` when disabled. */\n readonly cors?: CorsPolicy | undefined\n /** Security headers added to every reply that does not set them (`securityHeaders` option). */\n readonly securityHeaders?: Readonly<Record<string, string>>\n /** `trustProxy` policy, `undefined` when proxies are not trusted. */\n readonly trustProxy?: TrustPolicy | undefined\n /** Cookie defaults and signing key (`cookies` option). Default: secure defaults, no signing. */\n readonly cookies?: CookieSettings\n /** Event stream defaults (`sse` option). */\n readonly sse?: SseSettings\n}\n\n/** Resolved plugin option `sse`. */\nexport interface SseSettings {\n /** Heartbeat interval in ms; `0`: none. */\n readonly heartbeat: number\n /** `retry` sent first, if any. */\n readonly retry: number | undefined\n /** Time a source gets to finish after a graceful close started (ms). */\n readonly shutdownGraceMs: number\n}\n\n/** Default event stream settings. */\nexport const DEFAULT_SSE_SETTINGS: SseSettings = Object.freeze({\n heartbeat: 8_000,\n retry: undefined,\n shutdownGraceMs: 1_000,\n})\n\ntype Target =\n | { readonly kind: 'route'; readonly plan: RoutePlan }\n | { readonly kind: 'error'; readonly error: unknown }\n | { readonly kind: 'options'; readonly allow: string }\n | { readonly kind: 'redirect'; readonly location: string }\n /** A CORS preflight; `allow` is `undefined` when no route has the path (404). */\n | { readonly kind: 'preflight'; readonly allow: string | undefined }\n\n/** The CORS decision of a request (an `origin` header and a CORS policy). */\ninterface CorsDecision {\n readonly policy: CorsPolicy\n readonly origin: string\n readonly allowed: boolean\n}\n\nconst RAW = Symbol('raw response')\ntype Outcome = SerializedReply | typeof RAW\n\n/** A reply whose `HttpResponse` cookies were serialised (see `#checkCookies`). */\ntype CheckedReply = SerializedReply & { readonly cookieLines?: readonly SerializedCookie[] }\n\n/** A reply, and a promise settled once the request is over (response body sent or abandoned, scope closed). */\ninterface Served {\n readonly reply: AdapterReply\n readonly done: Promise<void>\n}\n\nconst REQUEST_ID = /^[\\w\\-.:@/+=]{1,128}$/\nconst MAX_PATH_IN_MESSAGE = 200\n\n/**\n * The request pipeline (architecture §9.1):\n * `runInScope({ HttpContext, RequestId }) → hooks.run('http:request') → guards → body → interceptors\n * → invoke → serialise`, errors being mapped to responses inside `hooks.run`.\n */\nexport class Pipeline {\n readonly #container: Container\n readonly #hooks: Hooks\n readonly #logger: CoreLogger\n readonly #options: PipelineOptions\n readonly #table: RouteTable<RoutePlan>\n #inflight = 0\n #idle: (() => void)[] = []\n /** Open event streams. */\n readonly #streams = new Set<SseSession>()\n /** Set while the server drains: responses ask clients to close their connection. */\n draining = false\n\n constructor(\n container: Container,\n hooks: Hooks,\n logger: CoreLogger,\n options: PipelineOptions,\n table: RouteTable<RoutePlan>,\n ) {\n this.#container = container\n this.#hooks = hooks\n this.#logger = logger\n this.#options = options\n this.#table = table\n }\n\n /** Number of requests being processed. */\n get inflight(): number {\n return this.#inflight\n }\n\n /** Number of open event streams. */\n get streams(): number {\n return this.#streams.size\n }\n\n /**\n * Starts the graceful close of every open event stream (`ctx.signal` aborts with `kind`, the source\n * gets `shutdownGraceMs` to finish, then the client receives a jittered `retry`).\n */\n closeStreams(kind: 'shutdown' | 'expired'): void {\n for (const session of [...this.#streams]) session.close(kind)\n }\n\n /** Resolves once no request is being processed. */\n whenIdle(): Promise<void> {\n if (this.#inflight === 0) return Promise.resolve()\n return new Promise(resolve => this.#idle.push(resolve))\n }\n\n /**\n * Handles a request routed to `plan` by the adapter. The request stays in flight (and its scope\n * open) until a streamed or file response body has been fully read or cancelled by the adapter.\n */\n async handle(plan: RoutePlan, request: AdapterRequest): Promise<AdapterReply> {\n const startTime = performance.now()\n this.#enter()\n let served: Served | undefined\n try {\n served = this.#isPreflight(request)\n ? await this.#preflight(request, startTime)\n : await this.#route(plan, request, startTime)\n return served.reply\n } finally {\n this.#leaveWhen(served)\n }\n }\n\n #route(plan: RoutePlan, request: AdapterRequest, startTime: number, rerouted = false): Promise<Served> {\n const { path, query } = splitUrl(request.url)\n const raw = matchRoutePath(plan.path, path)\n // the native router matched a path the Znight grammar rejects (e.g. an empty `:param` in Fastify)\n // or a normalised path (Hono): route the raw path with the route table instead\n if (raw === undefined) return this.#fallback(request, undefined, startTime, !rerouted)\n if (plan.redirect === true) {\n const canonical = sameOriginPath(path.slice(0, -1))\n const location = query === '' ? canonical : `${canonical}?${query}`\n return this.#serve(request, undefined, emptyRecord(), { kind: 'redirect', location }, startTime, plan.body)\n }\n const params = emptyRecord<string>()\n let malformed: string | undefined\n for (const name of Object.keys(raw)) {\n const decoded = decodePathValue(raw[name] as string)\n if (decoded === undefined) malformed ??= name\n else params[name] = decoded\n }\n const target: Target =\n malformed === undefined\n ? { kind: 'route', plan }\n : { kind: 'error', error: new BadRequestException(`Malformed URL parameter \"${malformed}\"`) }\n return this.#serve(request, plan.info, params, target, startTime, plan.body)\n }\n\n /** Handles an unmatched request (404, 405, automatic OPTIONS) or a framework error. */\n async fallback(request: AdapterRequest, error?: unknown): Promise<AdapterReply> {\n const startTime = performance.now()\n this.#enter()\n let served: Served | undefined\n try {\n served = await this.#fallback(request, error, startTime)\n return served.reply\n } finally {\n this.#leaveWhen(served)\n }\n }\n\n #fallback(request: AdapterRequest, error: unknown, startTime: number, reroute = true): Promise<Served> {\n const body = this.#options.body\n if (error !== undefined) {\n const target: Target = { kind: 'error', error: frameworkError(error) }\n return this.#serve(request, undefined, emptyRecord(), target, startTime, body)\n }\n if (this.#isPreflight(request)) return this.#preflight(request, startTime)\n const { path } = splitUrl(request.url)\n if (reroute) {\n // routing happens on the raw path: serve a route the adapter's router missed (Hono routes the\n // WHATWG-normalised URL, where `/files/%2e%2e/x` became `/x`)\n const plan = this.#table.find(request.method, path)\n if (plan !== undefined) return this.#route(plan, request, startTime, true)\n }\n const allowed = this.#table.allowedMethods(path)\n let target: Target\n if (allowed.length === 0) {\n target = { kind: 'error', error: new NotFoundException(`Cannot ${request.method} ${truncate(path)}`) }\n } else if (request.method === 'OPTIONS') {\n target = { kind: 'options', allow: allowHeader(allowed) }\n } else {\n // OPTIONS is answered automatically, hence supported (RFC 9110 §15.5.6: the same list as OPTIONS)\n target = {\n kind: 'error',\n error: new MethodNotAllowedException(\n `Method ${request.method} is not allowed on ${truncate(path)}`,\n undefined,\n {\n headers: { allow: allowHeader(allowed) },\n },\n ),\n }\n }\n return this.#serve(request, undefined, emptyRecord(), target, startTime, body)\n }\n\n /** A CORS preflight (with the `cors` option): answered without running any route. */\n #isPreflight(request: AdapterRequest): boolean {\n return this.#options.cors !== undefined && isPreflight(request.method, request.headers)\n }\n\n #preflight(request: AdapterRequest, startTime: number): Promise<Served> {\n const allowed = this.#table.allowedMethods(splitUrl(request.url).path)\n const target: Target = { kind: 'preflight', allow: allowed.length === 0 ? undefined : allowHeader(allowed) }\n return this.#serve(request, undefined, emptyRecord(), target, startTime, this.#options.body)\n }\n\n async #serve(\n request: AdapterRequest,\n route: HttpRouteInfo | undefined,\n params: Record<string, string>,\n target: Target,\n startTime: number,\n body: BodyPlan,\n ): Promise<Served> {\n const requestId = this.#requestId(request)\n const proxy = this.#options.trustProxy\n const ctx = new RequestContext(request, {\n requestId,\n adapter: this.#options.adapter,\n route,\n params,\n body,\n cookies: this.#options.cookies ?? DEFAULT_COOKIE_SETTINGS,\n ...(proxy === undefined\n ? {}\n : { client: proxy.resolve(request.remoteAddress ?? request.ip, request.headers, request.encrypted === true) }),\n })\n // an event stream requested while draining is served (guards run) with its signal already\n // aborted: a well-behaved source ends at once and the client gets a jittered retry\n if (this.draining && target.kind === 'route' && target.plan.definition.sse !== undefined) ctx.abort('shutdown')\n const event: HttpRequestEvent = {\n method: request.method,\n path: ctx.path,\n route: route?.path,\n requestId,\n headers: request.headers,\n context: ctx,\n startTime,\n responseHeaders: {},\n }\n let outcome: Outcome | undefined\n let reply: AdapterReply | undefined\n let cors: CorsDecision | undefined\n const preflight = target.kind === 'preflight'\n let replied: () => void = () => undefined\n const ready = new Promise<void>(resolve => {\n replied = resolve\n })\n // the scope (request-scoped instances) stays open until a streamed or file body has been sent or abandoned\n const done = this.#container\n .runInScope(async () => {\n let hookError: unknown\n let failed = false\n let run: ContextRunner | undefined\n if (this.#options.cors !== undefined) cors = await this.#corsDecision(request, requestId)\n try {\n await this.#hooks.run('http:request', event, async () => {\n outcome = await this.#process(ctx, target, event, cors)\n if (outcome !== RAW) outcome = this.#checkCookies(this.#checkHeaders(outcome, ctx, event), ctx, event)\n run = captureContext() // stream producers run in the context of the handler (scope, hooks)\n return outcome\n })\n } catch (error) {\n failed = true\n hookError = error\n }\n if (outcome === undefined) {\n // a wrapper failed before the request was handled, or did not call next(): answer anyway\n const error = failed ? hookError : new Error('An \"http:request\" hook wrapper did not call next()')\n event.error ??= error\n // the same checks as a handled reply: an exception mapper's HttpResponse may carry cookies\n const fallback = await this.#errorReply(error, ctx)\n outcome = this.#checkCookies(this.#checkHeaders(fallback, ctx, event), ctx, event)\n event.status = outcome.status\n } else if (failed) {\n this.#logger.error('An \"http:request\" hook wrapper failed after the request was handled', {\n err: hookError,\n requestId,\n })\n }\n if (outcome === RAW) {\n ctx.commit()\n replied()\n return\n }\n const serialized = this.#complete(outcome, ctx, event, requestId, cors, preflight)\n const body = serialized.body\n if (!(body instanceof ReadableStream || body instanceof Blob)) {\n reply = adapterReply(serialized, body)\n ctx.commit()\n replied()\n ctx.releaseBody()\n return\n }\n // files too: a file-backed Blob is read lazily, after the handler returned\n const tracked = trackStream(body, run ?? captureContext(), () => ctx.abort('client'))\n const session = serialized.sse\n reply = adapterReply(serialized, tracked.stream, body instanceof Blob ? body : undefined)\n if (session !== undefined) {\n this.#streams.add(session)\n if (this.draining) session.close('shutdown')\n }\n ctx.commit()\n replied()\n const failure = await tracked.done\n if (session !== undefined) this.#streams.delete(session)\n if (failure !== undefined) {\n this.#logger.error('The response stream failed', { err: failure, requestId, path: ctx.path })\n }\n ctx.releaseBody()\n }, [\n [HttpTokens.Context, ctx],\n [HttpTokens.RequestId, requestId],\n ])\n .then(\n () => {\n ctx.complete()\n },\n (error: unknown) => {\n ctx.complete()\n // the callback above never throws: only the disposal of request-scoped instances can fail\n this.#logger.error('Failed to dispose request-scoped providers', { err: error, requestId })\n },\n )\n await Promise.race([ready, done])\n if (outcome === RAW) {\n const status = request.rawStatus?.() ?? 200\n event.status ??= status\n this.#emit(event)\n return { reply: { status, headers: {}, body: null, raw: true }, done }\n }\n if (reply === undefined) {\n const failure = new Error('Request not handled')\n reply = this.#complete(\n serializeError(500, this.#internalBody(failure), ctx.method),\n ctx,\n event,\n requestId,\n cors,\n preflight,\n )\n event.status = 500\n }\n this.#emit(event)\n return { reply, done }\n }\n\n /**\n * Adds the headers of the `http:request` wrappers, then the framework headers (see\n * {@link #frameworkHeaders}), then checks the final headers (see {@link #checkHeaders}).\n */\n #complete(\n reply: CheckedReply,\n ctx: RequestContext,\n event: HttpRequestEvent,\n requestId: RequestId,\n cors: CorsDecision | undefined,\n preflight: boolean,\n ): SerializedReply {\n addMissingHeaders(reply.headers, event.responseHeaders)\n applyCookies(reply, ctx)\n this.#frameworkHeaders(reply.headers, requestId, cors, preflight)\n const checked = this.#checkHeaders(reply, ctx, event)\n if (checked !== reply) {\n applyCookies(checked, ctx)\n this.#frameworkHeaders(checked.headers, requestId, cors, preflight)\n }\n return checked\n }\n\n /**\n * Serialises the cookies of an `HttpResponse` (`withCookie`) with the plugin settings (defaults,\n * signing). A cookie breaking a rule that depends on them (a prefix with the `secure` default,\n * `SameSite=None` without `secure`, signing without secrets, the size after signing) turns the\n * reply into a plain 500, logged as `Invalid cookie \"x\": …` (like an invalid header).\n */\n #checkCookies(reply: SerializedReply, ctx: RequestContext, event: HttpRequestEvent): CheckedReply {\n const cookies = reply.cookies\n if (cookies === undefined || cookies.length === 0) return reply\n const settings = this.#options.cookies ?? DEFAULT_COOKIE_SETTINGS\n const lines: SerializedCookie[] = []\n try {\n for (const cookie of cookies) lines.push(serializeWith(cookie, settings))\n } catch (error) {\n if (reply.body instanceof ReadableStream) discardStream(reply.body)\n event.error = error\n event.status = 500\n this.#log(error, ctx)\n return serializeError(500, this.#internalBody(error), ctx.method)\n }\n return { ...reply, cookieLines: lines }\n }\n\n /**\n * Headers the plugin adds to every reply when nothing set them: the request id, the CORS headers\n * of an allowed origin (`vary: origin` whatever the origin) or, with a wildcard policy, of every\n * reply (`access-control-allow-origin: *` does not depend on the request, so a cached reply serves\n * CORS and non-CORS requests alike), the security headers; and `connection: close` while\n * draining.\n */\n #frameworkHeaders(\n headers: Record<string, HeaderValue>,\n requestId: RequestId,\n cors: CorsDecision | undefined,\n preflight: boolean,\n ): void {\n const header = this.#options.requestIdHeader\n if (header !== undefined && headers[header] === undefined && isHeaderValue(requestId)) headers[header] = requestId\n const policy = this.#options.cors\n if (policy !== undefined) {\n // a preflight answer carries its own CORS headers; other replies get them for allowed origins,\n // or always with a wildcard policy (with or without an origin header: no vary needed)\n if (!preflight) {\n if (policy.wildcard) addMissingHeaders(headers, corsReplyHeaders(policy, '*'))\n else if (cors?.allowed === true) addMissingHeaders(headers, corsReplyHeaders(policy, cors.origin))\n }\n if (policy.varyOrigin) mergeVary(headers, 'origin')\n }\n const security = this.#options.securityHeaders\n if (security !== undefined) addMissingHeaders(headers, security)\n if (this.draining) headers['connection'] = 'close'\n }\n\n /**\n * The CORS decision of a request carrying an `origin` header, made once before the hooks run. An\n * origin function that throws or rejects denies the origin (logged).\n */\n async #corsDecision(request: AdapterRequest, requestId: RequestId): Promise<CorsDecision | undefined> {\n const policy = this.#options.cors\n const origin = request.headers['origin']\n if (policy === undefined || origin === undefined) return undefined\n let allowed = false\n try {\n // an origin that cannot be echoed in a response header is never allowed\n allowed = isHeaderValue(origin) && (await policy.allows(origin)) === true\n } catch (error) {\n this.#logger.error('The CORS origin check failed: the origin is denied', { err: error, requestId, origin })\n }\n return { policy, origin, allowed }\n }\n\n /**\n * A reply with a header no adapter can send (`ctx.setHeader('x', 'a\\r\\nb')`, a redirect to a\n * client-provided URL with CR/LF, a non Latin-1 value...) becomes a plain 500, identical on every\n * adapter: its body is discarded (a stream is cancelled) and the error logged.\n */\n #checkHeaders(reply: SerializedReply, ctx: RequestContext, event: HttpRequestEvent): SerializedReply {\n const name = findInvalidHeader(reply.headers)\n if (name === undefined) return reply\n if (reply.body instanceof ReadableStream) discardStream(reply.body)\n const error = new TypeError(`Invalid response header ${JSON.stringify(truncate(name))}: invalid name or value`)\n event.error = error\n event.status = 500\n this.#log(error, ctx)\n return serializeError(500, this.#internalBody(error), ctx.method)\n }\n\n async #process(\n ctx: RequestContext,\n target: Target,\n event: HttpRequestEvent,\n cors: CorsDecision | undefined,\n ): Promise<Outcome> {\n try {\n switch (target.kind) {\n case 'error':\n throw target.error\n case 'preflight':\n // never runs guards, interceptors or handlers (@Options and @All routes included)\n if (target.allow === undefined) throw new NotFoundException(`Cannot OPTIONS ${truncate(ctx.path)}`)\n if (cors === undefined || !cors.allowed) throw new ForbiddenException('CORS origin not allowed')\n return this.#finish(event, {\n status: 204,\n headers: withContextHeaders(preflightHeaders(cors.policy, cors.origin, ctx.headers, target.allow), ctx),\n body: null,\n })\n case 'options':\n return this.#finish(event, {\n status: 204,\n headers: withContextHeaders({ allow: target.allow }, ctx),\n body: null,\n })\n case 'redirect':\n return this.#finish(\n event,\n serializeResult(undefined, {\n method: ctx.method,\n routeMethod: ctx.method,\n status: 308,\n headers: { location: target.location },\n }),\n )\n default:\n return await this.#invoke(ctx, target.plan, event)\n }\n } catch (error) {\n event.error = error\n const reply = await this.#errorReply(error, ctx)\n event.status = reply.status\n return reply\n }\n }\n\n async #invoke(ctx: RequestContext, plan: RoutePlan, event: HttpRequestEvent): Promise<Outcome> {\n const controller = this.#resolve(plan.controller)\n for (const guard of plan.guards) {\n const allowed = await this.#resolve(guard).canActivate(ctx)\n if (allowed !== true) throw new ForbiddenException('Forbidden resource')\n }\n if (plan.parseBody) await ctx.parseBody()\n const definition = plan.definition\n const interceptors = plan.interceptors\n let result: unknown\n if (interceptors.length === 0) {\n result = await definition.invoke(controller, ctx)\n } else {\n const chain = async (index: number): Promise<unknown> => {\n if (index === interceptors.length) return await definition.invoke(controller, ctx)\n const interceptor = this.#resolve(interceptors[index] as Resolvable<HttpInterceptor>)\n return await interceptor.intercept(ctx, () => chain(index + 1))\n }\n result = await chain(0)\n }\n if (definition.rawResponse === true && !(result instanceof Response)) return RAW\n const options: SerializeOptions = {\n method: ctx.method,\n routeMethod: definition.method,\n status: definition.status,\n headers: definition.headers,\n context: ctx.hasResponseHeaders ? ctx.responseHeaders : undefined,\n }\n const sse = definition.sse\n let reply: SerializedReply\n if (sse !== undefined && !(result instanceof Response) && !isHttpResponse(result)) {\n // an @Sse route: the (awaited) result is the event source\n if (!isSseSource(result)) {\n throw new TypeError(\n `@Sse handler ${displayName(plan.info.controller)}.${definition.handler} must return an AsyncIterable, an Iterable or a ReadableStream of SseEvent (received ${describeResult(result)})`,\n )\n }\n reply = serializeSseReply(this.#openStream(result, sseOptions(sse), ctx), undefined, options)\n } else {\n reply = await this.#serialize(result, ctx, options, sse)\n }\n return this.#finish(event, reply)\n }\n\n /** Serialises a handler (or exception mapper) result; file bodies are resolved, event streams opened. */\n async #serialize(\n result: unknown,\n ctx: RequestContext,\n options: SerializeOptions,\n route?: HttpSseDefinition,\n ): Promise<SerializedReply> {\n if (isHttpResponse(result)) {\n if (isFileBody(result.body)) return serializeFileReply(await resolveFile(result.body, ctx), result, options)\n if (isSseBody(result.body)) {\n const body = result.body\n // HttpResponse.sse() options win over the @Sse options of the route\n const merged = { ...(route === undefined ? {} : sseOptions(route)), ...definedOptions(body.options) }\n return serializeSseReply(this.#openStream(body.source, merged, ctx), result, options)\n }\n }\n return serializeResult(result, options)\n }\n\n /** An event stream reading `source` in the request (route options over the plugin `sse` option). */\n #openStream(source: SseSource, options: SseOptions, ctx: RequestContext): SseSession {\n const settings = this.#options.sse ?? DEFAULT_SSE_SETTINGS\n const heartbeat = options.heartbeat === undefined ? settings.heartbeat : options.heartbeat || 0\n const retry = options.retry ?? settings.retry\n const logger = this.#logger\n return new SseSession(\n source,\n {\n heartbeat,\n retry,\n maxDuration: options.maxDuration,\n graceMs: settings.shutdownGraceMs,\n },\n {\n abort: kind => ctx.abort(kind),\n error: (message, error) => logger.error(message, { err: error, requestId: ctx.requestId, path: ctx.path }),\n warn: message => logger.warn(message, { requestId: ctx.requestId, path: ctx.path }),\n },\n )\n }\n\n #finish(event: HttpRequestEvent, reply: SerializedReply): SerializedReply {\n event.status = reply.status\n return reply\n }\n\n /** Maps an error to a reply: exception mappers first, then the default rendering. Never throws. */\n async #errorReply(error: unknown, ctx: RequestContext): Promise<SerializedReply> {\n for (const mapper of this.#options.mappers) {\n let mapped: unknown\n try {\n mapped = await this.#resolve(mapper).map(error, ctx)\n } catch (mapperError) {\n this.#logger.error('An exception mapper failed', { err: mapperError, requestId: ctx.requestId })\n continue\n }\n if (mapped === undefined) continue\n try {\n if (isHttpResponse(mapped) && mapped.status === undefined) {\n // an error response without explicit status keeps the status of the error\n mapped = new HttpResponse(mapped.body, {\n status: isHttpException(error) ? error.status : 500,\n headers: mapped.headers,\n cookies: (mapped as { cookies?: HttpResponse['cookies'] }).cookies ?? [],\n })\n }\n if (mapped instanceof Response || isHttpResponse(mapped)) {\n return await this.#serialize(mapped, ctx, {\n method: ctx.method,\n routeMethod: ctx.method,\n status: undefined,\n headers: undefined,\n context: ctx.hasResponseHeaders ? ctx.responseHeaders : undefined,\n })\n }\n if (isHttpException(mapped)) return this.#renderException(mapped, ctx, error)\n } catch (renderError) {\n this.#logger.error('Failed to render the result of an exception mapper', {\n err: renderError,\n requestId: ctx.requestId,\n })\n continue\n }\n this.#logger.warn(\n 'An exception mapper returned an unsupported value (expected HttpException, HttpResponse, Response or undefined)',\n {\n requestId: ctx.requestId,\n },\n )\n }\n return this.#renderException(error, ctx, error)\n }\n\n #renderException(error: unknown, ctx: RequestContext, original: unknown): SerializedReply {\n let status: number\n let body: unknown\n let extra: Readonly<Record<string, HeaderValue>> | undefined\n if (isHttpException(error)) {\n status = error.status\n try {\n body = error.toBody()\n } catch (bodyError) {\n this.#log(bodyError, ctx)\n status = 500\n body = this.#internalBody(bodyError)\n }\n extra = error.headers\n if (status >= 500) this.#log(original, ctx)\n } else {\n status = 500\n body = this.#internalBody(error)\n this.#log(error, ctx)\n }\n let reply: SerializedReply\n try {\n reply = serializeError(status, body, ctx.method)\n } catch (serializeFailure) {\n this.#log(serializeFailure, ctx)\n reply = serializeError(500, this.#internalBody(serializeFailure), ctx.method)\n extra = undefined\n }\n if (ctx.hasResponseHeaders) assignHeaders(reply.headers, ctx.responseHeaders)\n if (extra !== undefined) assignHeaders(reply.headers, extra)\n return reply\n }\n\n #internalBody(error: unknown): object {\n return this.#options.exposeErrors\n ? { statusCode: 500, error: 'Internal Server Error', message: errorMessage(error) }\n : { statusCode: 500, error: 'Internal Server Error' }\n }\n\n #log(error: unknown, ctx: RequestContext): void {\n const route = ctx.route\n this.#logger.error(`Request failed: ${ctx.method} ${route?.path ?? truncate(ctx.path)}`, {\n err: error,\n requestId: ctx.requestId,\n method: ctx.method,\n path: ctx.path,\n ...(route === undefined\n ? {}\n : { route: route.path, handler: `${displayName(route.controller)}.${route.handler}` }),\n })\n }\n\n #resolve<T>(resolvable: Resolvable<T>): T {\n return 'instance' in resolvable ? resolvable.instance : (this.#container.get(resolvable.token) as T)\n }\n\n #requestId(request: AdapterRequest): RequestId {\n const header = this.#options.requestIdHeader\n if (header !== undefined) {\n const incoming = request.headers[header]\n if (incoming !== undefined && REQUEST_ID.test(incoming)) return incoming as RequestId\n }\n return this.#options.generateRequestId() as RequestId\n }\n\n #emit(event: HttpRequestEvent): void {\n if (this.#hooks.hasListeners('http:request')) this.#hooks.emit('http:request', event)\n }\n\n #enter(): void {\n this.#inflight++\n }\n\n /** Leaves once the request is over (immediately when it failed before being served). */\n #leaveWhen(served: Served | undefined): void {\n if (served === undefined) this.#leave()\n else void served.done.then(() => this.#leave())\n }\n\n #leave(): void {\n this.#inflight--\n if (this.#inflight === 0 && this.#idle.length > 0) {\n const waiting = this.#idle\n this.#idle = []\n for (const resolve of waiting) resolve()\n }\n }\n}\n\n/**\n * The reply handed to the adapter (internal fields of the serialised reply left out). A streamed\n * `text/event-stream` body is an event stream whatever produced it (`@Sse`, `HttpResponse.sse()`, a\n * proxied `fetch()` response, `HttpResponse.stream()`): the adapter sends its headers at once, even\n * before a quiet stream's first byte, and lifts idle timeouts.\n */\nfunction adapterReply(serialized: SerializedReply, body: ReplyBody, blob?: Blob): AdapterReply {\n const reply: AdapterReply = { status: serialized.status, headers: serialized.headers, body }\n if (blob !== undefined) return { ...reply, blob }\n const eventStream =\n serialized.sse !== undefined ||\n (body instanceof ReadableStream && isEventStreamType(serialized.headers['content-type']))\n return eventStream ? { ...reply, eventStream: true } : reply\n}\n\n/**\n * Appends the cookies to `set-cookie`, after the raw values (`@Header`, `ctx.setHeader()`, the\n * `HttpResponse` headers, a Web `Response`): the cookies of the context (`ctx.setCookie()`), then\n * those of the `HttpResponse`, a cookie of the same key (name, domain, path) replacing the earlier\n * one in place. One line per cookie.\n */\nfunction applyCookies(reply: CheckedReply, ctx: RequestContext): void {\n const own = reply.cookieLines ?? []\n const context = ctx.cookieLines\n if (own.length === 0 && context.length === 0) return\n const merged = new Map<string, string>()\n for (const { key, line } of context) merged.set(key, line)\n for (const { key, line } of own) merged.set(key, line)\n const existing = reply.headers['set-cookie']\n let raw: string[] = []\n if (typeof existing === 'string') raw = [existing]\n else if (existing !== undefined) raw = [...existing]\n reply.headers['set-cookie'] = [...raw, ...merged.values()]\n}\n\n/** `SseOptions` of the `sse` metadata of a route (`heartbeat: 0` disables the heartbeat). */\nfunction sseOptions(definition: HttpSseDefinition): SseOptions {\n return {\n ...(definition.heartbeat === undefined\n ? {}\n : { heartbeat: definition.heartbeat === 0 ? false : definition.heartbeat }),\n ...(definition.retry === undefined ? {} : { retry: definition.retry }),\n ...(definition.maxDuration === undefined ? {} : { maxDuration: definition.maxDuration }),\n }\n}\n\nfunction definedOptions(options: SseOptions): SseOptions {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(options)) if (value !== undefined) result[key] = value\n return result as SseOptions\n}\n\nfunction describeResult(value: unknown): string {\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n if (typeof value === 'string') return 'a string'\n if (typeof value === 'object') return `an instance of ${(value as object).constructor?.name ?? 'Object'}`\n return typeof value\n}\n\nfunction withContextHeaders(headers: Record<string, HeaderValue>, ctx: RequestContext): Record<string, HeaderValue> {\n const result = emptyRecord<HeaderValue>()\n if (ctx.hasResponseHeaders) assignHeaders(result, ctx.responseHeaders)\n assignHeaders(result, headers)\n return result\n}\n\n/** Converts an error raised by the server framework (bad URL...) to an `HttpException`. */\nfunction frameworkError(error: unknown): unknown {\n if (isHttpException(error)) return error\n const status =\n (error as { statusCode?: unknown; status?: unknown } | null)?.statusCode ??\n (error as { status?: unknown } | null)?.status\n if (typeof status === 'number' && status >= 400 && status < 500) {\n return new HttpException(status, errorMessage(error), undefined, { cause: error })\n }\n return error\n}\n\n/** `Allow` of a path: its methods and `OPTIONS`, answered automatically when no route declares it. */\nfunction allowHeader(allowed: readonly string[]): string {\n return (allowed.includes('OPTIONS') ? allowed : [...allowed, 'OPTIONS']).join(', ')\n}\n\n/**\n * A raw request path usable as a same-origin `Location`: backslashes, controls and spaces are\n * percent-encoded and leading slashes collapsed, since browsers read `/\\evil.com` or `//evil.com`\n * as another host (an open redirect through `trailingSlash: 'redirect'`).\n */\nfunction sameOriginPath(path: string): string {\n let encoded = ''\n for (const char of path) {\n const code = char.charCodeAt(0)\n encoded +=\n code <= 0x20 || code === 0x7f || char === '\\\\' ? `%${code.toString(16).toUpperCase().padStart(2, '0')}` : char\n }\n return encoded.replace(/^\\/{2,}/, '/')\n}\n\nfunction truncate(path: string): string {\n return path.length > MAX_PATH_IN_MESSAGE ? `${path.slice(0, MAX_PATH_IN_MESSAGE)}…` : path\n}\n","/**\n * Plugin routes (RFC 0002 H1): routes another plugin asks `HttpPlugin` to serve (documentation,\n * health or metrics endpoints), registered on every adapter in the same pipeline as the compiled\n * controllers.\n */\nimport type { Container, Plugin } from '@znight/core'\nimport type { HttpContext } from './context.ts'\nimport type { RouteMetaEntry } from './decorators.ts'\nimport type { HttpMethod } from './metadata.ts'\nimport type { GuardRef } from './plugin.ts'\n\nimport { ErrorCode, ZnightError } from '@znight/core'\n\nimport { isGroupOf } from './decorators.ts'\nimport { joinPaths, normalizePath, parseRoutePath, type RoutePath, RoutePathError } from './path.ts'\n\n/**\n * A route served by `HttpPlugin` on behalf of another plugin. It runs through the same pipeline as\n * controller routes: `http:request` hook, request scope, global guards, then its own `guards`, the\n * handler, the exception mappers; global interceptors do not wrap it. The handler result is\n * serialised like a controller result (`HttpResponse`, objects as JSON, strings, streams...).\n */\nexport interface PluginRoute {\n /** `GET` routes also answer `HEAD`; `ALL` registers every method without its own route. */\n readonly method: HttpMethod\n /** Path relative to the `HttpPlugin` prefix, with the controller grammar (`/openapi.json`, `/docs/_assets/*`). */\n readonly path: string\n /** Handler name, shown in `HttpPlugin.routes`, logs and errors (`document`). */\n readonly name: string\n readonly handler: (ctx: HttpContext) => unknown\n /**\n * Route metadata (`[Public.meta()]`): read by guards (`Public.get(ctx)`) and by the boot check of\n * required route decorator groups. One entry per group.\n */\n readonly meta?: readonly RouteMetaEntry[]\n /** Guards of the route (provider classes or instances), run after the global guards. */\n readonly guards?: readonly GuardRef[]\n}\n\n/** What {@link PluginHttpRoutes.httpRoutes} receives. */\nexport interface PluginHttpRoutesContext {\n /** The `HttpPlugin` prefix (`''` or `/api`), already applied to the paths of the routes. */\n readonly prefix: string\n /** The application container (initialised). */\n readonly container: Container\n}\n\n/**\n * Implemented by a plugin that serves HTTP routes. `HttpPlugin` calls `httpRoutes()` once in its\n * `onBootstrap`, after `container.init()` and whatever the plugin order, then registers the routes\n * on its adapter. A path that breaks the grammar, or that collides with another route, is ZNIGHT007\n * naming the plugin.\n *\n * ```ts\n * export class StatusPlugin implements Plugin, PluginHttpRoutes {\n * readonly name = 'status'\n * httpRoutes(): readonly PluginRoute[] {\n * return [{ method: 'GET', path: '/status', name: 'status', handler: () => ({ up: true }), meta: [Public.meta()] }]\n * }\n * }\n * ```\n */\nexport interface PluginHttpRoutes {\n httpRoutes(context: PluginHttpRoutesContext): readonly PluginRoute[]\n}\n\n/** A validated plugin route (internal). */\nexport interface CollectedPluginRoute {\n readonly plugin: string\n /** The plugin instance (the \"controller\" of the route). */\n readonly instance: object\n readonly method: HttpMethod\n /** Full path, prefix included. */\n readonly path: RoutePath\n /** Normalised path without the prefix. */\n readonly relativePath: string\n readonly name: string\n readonly handler: (ctx: HttpContext) => unknown\n readonly meta: readonly NormalizedMetaEntry[]\n readonly guards: readonly unknown[]\n}\n\n/** A plugin route metadata entry with its group (internal). */\nexport interface NormalizedMetaEntry {\n readonly key: string\n readonly value: unknown\n readonly group: string\n readonly required: boolean\n}\n\nconst METHODS: ReadonlySet<string> = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'ALL'])\n\n/** Calls `httpRoutes()` on every other plugin implementing it, in plugin order, and validates the routes. */\nexport function collectPluginRoutes(\n plugins: readonly Plugin[],\n self: Plugin,\n context: PluginHttpRoutesContext,\n): CollectedPluginRoute[] {\n const collected: CollectedPluginRoute[] = []\n for (const plugin of plugins) {\n if (plugin === self) continue\n const provider = plugin as Plugin & Partial<PluginHttpRoutes>\n if (typeof provider.httpRoutes !== 'function') continue\n const name = String(plugin.name)\n const routes: unknown = provider.httpRoutes(context)\n if (!Array.isArray(routes)) {\n throw invalid(name, `httpRoutes() must return an array of routes (received ${describe(routes)})`)\n }\n for (const route of routes as unknown[]) collected.push(validateRoute(plugin, name, route, context.prefix))\n }\n return collected\n}\n\nfunction validateRoute(instance: object, plugin: string, value: unknown, prefix: string): CollectedPluginRoute {\n if (value === null || typeof value !== 'object') throw invalid(plugin, `invalid route ${describe(value)}`)\n const route = value as Partial<PluginRoute>\n const label = `${String(route.method)} ${String(route.path)}`\n if (typeof route.name !== 'string' || route.name === '') {\n throw invalid(plugin, `the route ${label} needs a name (handler name shown in HttpPlugin.routes)`)\n }\n const where = `${label} (${route.name})`\n if (typeof route.method !== 'string' || !METHODS.has(route.method)) {\n throw invalid(plugin, `unknown method ${describe(route.method)} of the route ${where}`)\n }\n if (typeof route.handler !== 'function') throw invalid(plugin, `the route ${where} has no handler function`)\n if (typeof route.path !== 'string') throw invalid(plugin, `the route ${where} has no path`)\n let path: RoutePath\n try {\n path = parseRoutePath(joinPaths(prefix, route.path))\n } catch (error) {\n if (!(error instanceof RoutePathError)) throw error\n throw invalid(plugin, `invalid path of the route ${where}: ${error.issue.message}`, error)\n }\n const meta = route.meta ?? []\n if (!Array.isArray(meta)) throw invalid(plugin, `the meta of the route ${where} must be an array of entries`)\n const entries = (meta as unknown[]).map(entry => metaEntry(plugin, where, entry))\n const groups = new Map<string, string>()\n for (const entry of entries) {\n const other = groups.get(entry.group)\n if (other !== undefined) {\n throw invalid(\n plugin,\n `the route ${where} has two entries of the \"${entry.group}\" group (${other}, ${entry.key}): keep one`,\n )\n }\n groups.set(entry.group, entry.key)\n }\n const guards = route.guards ?? []\n if (!Array.isArray(guards)) throw invalid(plugin, `the guards of the route ${where} must be an array`)\n return {\n plugin,\n instance,\n method: route.method as HttpMethod,\n path,\n relativePath: normalizePath(route.path),\n name: route.name,\n handler: route.handler,\n meta: entries,\n guards,\n }\n}\n\nfunction metaEntry(plugin: string, where: string, value: unknown): NormalizedMetaEntry {\n const entry = (value ?? {}) as Partial<RouteMetaEntry>\n if (value === null || typeof value !== 'object' || typeof entry.key !== 'string' || entry.key === '') {\n throw invalid(plugin, `invalid meta entry ${describe(value)} of the route ${where}: expected Decorator.meta(value)`)\n }\n const group = entry.group ?? entry.key\n const required = entry.required ?? false\n if (!isGroupOf(group, entry.key) || typeof required !== 'boolean') {\n throw invalid(plugin, `invalid group of the meta entry \"${entry.key}\" of the route ${where}`)\n }\n return { key: entry.key, value: entry.value, group, required }\n}\n\nfunction invalid(plugin: string, reason: string, cause?: unknown): ZnightError {\n return new ZnightError(ErrorCode.InvalidRoute, `HttpPlugin: plugin \"${plugin}\": ${reason}`, {\n ...(cause === undefined ? {} : { cause }),\n })\n}\n\nfunction describe(value: unknown): string {\n try {\n return typeof value === 'function' ? 'a function' : (JSON.stringify(value) ?? String(value))\n } catch {\n return typeof value\n }\n}\n","/**\n * Trusted proxies (RFC 0001 §5.6): `ctx.ip` and `ctx.protocol` behind load balancers, computed the\n * same way on every adapter from the socket peer (`AdapterRequest.remoteAddress`) and the\n * `x-forwarded-for` / `x-forwarded-proto` headers. The `Forwarded` header (RFC 7239) is not read.\n */\nimport { invalidOption } from './option-error.ts'\n\n/**\n * The `trustProxy` option: `false` (default: the headers are ignored), a number of trusted hops\n * (`1`: one load balancer in front of the server), or the addresses of the trusted proxies (IPv4 /\n * IPv6 addresses, CIDR ranges and the aliases `'loopback'`, `'private'`, `'linklocal'`).\n */\nexport type TrustProxy = false | number | readonly string[]\n\n/** Client address and protocol of a request (internal). */\nexport interface ClientInfo {\n readonly ip: string | undefined\n readonly protocol: 'http' | 'https'\n}\n\n/** A resolved `trustProxy` policy (internal). */\nexport interface TrustPolicy {\n /** `ctx.ip` and `ctx.protocol` of a request. */\n resolve(\n remoteAddress: string | undefined,\n headers: Readonly<Record<string, string | undefined>>,\n encrypted: boolean,\n ): ClientInfo\n}\n\n/** A parsed address: IPv4 (4 bytes, IPv4-mapped IPv6 included) or IPv6 (16 bytes). */\ninterface Address {\n readonly bytes: readonly number[]\n /** Normalised text (`::ffff:10.0.0.1` → `10.0.0.1`). */\n readonly text: string\n}\n\ninterface Range {\n readonly bytes: readonly number[]\n readonly prefix: number\n}\n\nconst ALIASES: Readonly<Record<string, readonly string[]>> = Object.freeze({\n loopback: ['127.0.0.0/8', '::1/128'],\n private: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', 'fc00::/7'],\n linklocal: ['169.254.0.0/16', 'fe80::/10'],\n})\n\nconst TRUST_HINTS: readonly string[] = [\n 'trustProxy: 1 trusts one proxy (the socket peer); trustProxy: [\"loopback\", \"10.0.0.0/8\"] trusts these addresses',\n 'Trusting every hop would let any client choose its ctx.ip with an x-forwarded-for header',\n]\n\n/** Validates the `trustProxy` option (ZNIGHT005); `undefined` when proxies are not trusted. */\nexport function resolveTrustProxy(value: TrustProxy | undefined): TrustPolicy | undefined {\n if (value === undefined || value === false) return undefined\n if (typeof value === 'number') {\n if (!Number.isSafeInteger(value) || value < 1) {\n throw invalidOption(\n 'trustProxy',\n 'false, a number of hops (an integer >= 1) or a list of addresses',\n value,\n undefined,\n TRUST_HINTS,\n )\n }\n return hopPolicy(value)\n }\n if (!Array.isArray(value)) {\n throw invalidOption(\n 'trustProxy',\n 'false, a number of hops (an integer >= 1) or a list of addresses',\n value,\n undefined,\n TRUST_HINTS,\n )\n }\n const ranges: Range[] = []\n for (const entry of value) {\n if (typeof entry !== 'string') {\n throw invalidOption('trustProxy', 'a list of addresses, CIDR ranges or aliases', value, undefined, TRUST_HINTS)\n }\n const expanded = ALIASES[entry] ?? [entry]\n for (const item of expanded) {\n const range = parseRange(item)\n if (range === undefined) {\n throw invalidOption(\n 'trustProxy',\n `a list of IP addresses, CIDR ranges (\"10.0.0.0/8\") or aliases (\"loopback\", \"private\", \"linklocal\"); \"${entry}\" is invalid`,\n value,\n undefined,\n TRUST_HINTS,\n )\n }\n ranges.push(range)\n }\n }\n return listPolicy(ranges)\n}\n\nfunction hopPolicy(hops: number): TrustPolicy {\n return {\n resolve(remoteAddress, headers, encrypted) {\n const socket = remoteAddress === undefined ? undefined : parseAddress(remoteAddress)\n if (socket === undefined) return { ip: remoteAddress, protocol: encrypted ? 'https' : 'http' }\n let client = socket\n const chain = forwardedFor(headers)\n for (let index = 0; index < hops && index < chain.length; index++) {\n const next = parseAddress(chain[index] as string)\n if (next === undefined) break // a malformed entry stops the walk at the last valid address\n client = next\n }\n return { ip: client.text, protocol: forwardedProto(headers, encrypted) }\n },\n }\n}\n\nfunction listPolicy(ranges: readonly Range[]): TrustPolicy {\n const trusted = (address: Address): boolean => ranges.some(range => inRange(address, range))\n return {\n resolve(remoteAddress, headers, encrypted) {\n const socket = remoteAddress === undefined ? undefined : parseAddress(remoteAddress)\n if (socket === undefined) return { ip: remoteAddress, protocol: encrypted ? 'https' : 'http' }\n if (!trusted(socket)) return { ip: socket.text, protocol: encrypted ? 'https' : 'http' }\n let client = socket\n for (const entry of forwardedFor(headers)) {\n const next = parseAddress(entry)\n if (next === undefined) break\n client = next\n if (!trusted(next)) break\n }\n return { ip: client.text, protocol: forwardedProto(headers, encrypted) }\n },\n }\n}\n\n/** `x-forwarded-for` entries from right (nearest proxy) to left (client). */\nfunction forwardedFor(headers: Readonly<Record<string, string | undefined>>): string[] {\n const value = headers['x-forwarded-for']\n if (value === undefined) return []\n return value\n .split(',')\n .map(entry => entry.trim())\n .reverse()\n}\n\n/** The leftmost `x-forwarded-proto` value when it is `http` or `https`, else the connection protocol. */\nfunction forwardedProto(headers: Readonly<Record<string, string | undefined>>, encrypted: boolean): 'http' | 'https' {\n const value = headers['x-forwarded-proto']?.split(',')[0]?.trim().toLowerCase()\n if (value === 'http' || value === 'https') return value\n return encrypted ? 'https' : 'http'\n}\n\nfunction inRange(address: Address, range: Range): boolean {\n if (address.bytes.length !== range.bytes.length) return false\n let bits = range.prefix\n for (let index = 0; index < range.bytes.length && bits > 0; index++) {\n const mask = bits >= 8 ? 0xff : (0xff << (8 - bits)) & 0xff\n if (((address.bytes[index] as number) & mask) !== ((range.bytes[index] as number) & mask)) return false\n bits -= 8\n }\n return true\n}\n\n/** `10.0.0.0/8`, `fc00::/7` or a single address. */\nfunction parseRange(value: string): Range | undefined {\n const slash = value.indexOf('/')\n const address = parseAddress(slash === -1 ? value : value.slice(0, slash))\n if (address === undefined) return undefined\n const bits = address.bytes.length * 8\n if (slash === -1) return { bytes: address.bytes, prefix: bits }\n const prefixText = value.slice(slash + 1)\n if (!/^\\d{1,3}$/.test(prefixText)) return undefined\n const prefix = Number(prefixText)\n return prefix > bits ? undefined : { bytes: address.bytes, prefix }\n}\n\n/** Parses an IPv4 or IPv6 address (zone ids ignored); IPv4-mapped IPv6 addresses become IPv4. */\nexport function parseAddress(value: string): Address | undefined {\n const text = value.startsWith('[') && value.endsWith(']') ? value.slice(1, -1) : value\n const v4 = parseIPv4(text)\n if (v4 !== undefined) return { bytes: v4, text }\n const zone = text.indexOf('%')\n const v6 = parseIPv6(zone === -1 ? text : text.slice(0, zone))\n if (v6 === undefined) return undefined\n if (v6.slice(0, 10).every(byte => byte === 0) && v6[10] === 0xff && v6[11] === 0xff) {\n const bytes = v6.slice(12)\n return { bytes, text: bytes.join('.') }\n }\n return { bytes: v6, text: text.toLowerCase() }\n}\n\nfunction parseIPv4(text: string): number[] | undefined {\n const parts = text.split('.')\n if (parts.length !== 4) return undefined\n const bytes: number[] = []\n for (const part of parts) {\n if (!/^(?:0|[1-9]\\d{0,2})$/.test(part)) return undefined\n const byte = Number(part)\n if (byte > 255) return undefined\n bytes.push(byte)\n }\n return bytes\n}\n\nfunction parseIPv6(text: string): number[] | undefined {\n if (text === '' || text.length > 45) return undefined\n const halves = text.split('::')\n if (halves.length > 2) return undefined\n const groups = (part: string): number[] | undefined => {\n if (part === '') return []\n const result: number[] = []\n const items = part.split(':')\n for (let index = 0; index < items.length; index++) {\n const item = items[index] as string\n if (index === items.length - 1 && item.includes('.')) {\n const v4 = parseIPv4(item)\n if (v4 === undefined) return undefined\n result.push(((v4[0] as number) << 8) | (v4[1] as number), ((v4[2] as number) << 8) | (v4[3] as number))\n } else {\n if (!/^[0-9A-Fa-f]{1,4}$/.test(item)) return undefined\n result.push(Number.parseInt(item, 16))\n }\n }\n return result\n }\n const head = groups(halves[0] as string)\n const tail = halves.length === 2 ? groups(halves[1] as string) : []\n if (head === undefined || tail === undefined) return undefined\n const missing = 8 - head.length - tail.length\n if (halves.length === 2 ? missing < 1 : missing !== 0) return undefined\n const words = [...head, ...new Array<number>(missing).fill(0), ...tail]\n const bytes: number[] = []\n for (const word of words) bytes.push(word >> 8, word & 0xff)\n return bytes\n}\n","/**\n * Security headers (RFC 0001 §5.5): validated and computed once at boot, then added to every reply\n * (except `@Res()` raw replies) when the handler, an interceptor, an exception or a hook wrapper did\n * not set them.\n */\nimport { isHeaderValue } from './headers.ts'\nimport { invalidOption } from './option-error.ts'\n\n/** HSTS settings (`strict-transport-security`). */\nexport interface HstsOptions {\n /** `max-age`, in seconds. Default `31536000` (one year). */\n readonly maxAge?: number\n /** `includeSubDomains`. Default `true`. */\n readonly includeSubDomains?: boolean\n /** `preload` (needs `includeSubDomains` and a `maxAge` of at least one year). Default `false`. */\n readonly preload?: boolean\n}\n\n/** The `securityHeaders` option of `HttpPlugin.configure` (merged over the defaults). */\nexport interface SecurityHeadersOptions {\n /** `content-security-policy`. Default `\"default-src 'none'; frame-ancestors 'none'\"`. */\n readonly contentSecurityPolicy?: string | false\n /** `x-frame-options`. Default `'DENY'`. */\n readonly frameOptions?: 'DENY' | 'SAMEORIGIN' | false\n /** `x-content-type-options: nosniff`. Default `true`. */\n readonly noSniff?: boolean\n /** `referrer-policy` (a policy or a comma-separated fallback list). Default `'no-referrer'`. */\n readonly referrerPolicy?: string | false\n /** `strict-transport-security`. Default `false`; `true`: `max-age=31536000; includeSubDomains`. */\n readonly hsts?: boolean | HstsOptions\n /** `cross-origin-resource-policy`. Default `false`. */\n readonly crossOriginResourcePolicy?: 'same-origin' | 'same-site' | 'cross-origin' | false\n /** `cache-control` of replies that do not set one (`'no-store'` for personal data). Default `false`. */\n readonly cacheControl?: string | false\n}\n\nconst DEFAULT_CSP = \"default-src 'none'; frame-ancestors 'none'\"\nconst ONE_YEAR = 31_536_000\nconst KEYS = new Set([\n 'contentSecurityPolicy',\n 'frameOptions',\n 'noSniff',\n 'referrerPolicy',\n 'hsts',\n 'crossOriginResourcePolicy',\n 'cacheControl',\n])\nconst REFERRER_POLICIES = new Set([\n 'no-referrer',\n 'no-referrer-when-downgrade',\n 'origin',\n 'origin-when-cross-origin',\n 'same-origin',\n 'strict-origin',\n 'strict-origin-when-cross-origin',\n 'unsafe-url',\n])\nconst RESOURCE_POLICIES = new Set(['same-origin', 'same-site', 'cross-origin'])\nconst NO_HEADERS: Readonly<Record<string, string>> = Object.freeze({})\n\n/**\n * Validates the `securityHeaders` option (ZNIGHT005) and returns the headers to add, frozen\n * (`{}` when disabled).\n */\nexport function resolveSecurityHeaders(\n value: boolean | SecurityHeadersOptions | undefined,\n): Readonly<Record<string, string>> {\n if (value === false) return NO_HEADERS\n if (value !== undefined && value !== true && (value === null || typeof value !== 'object' || Array.isArray(value))) {\n throw invalidOption('securityHeaders', 'a boolean or an object of header settings', value)\n }\n const options: SecurityHeadersOptions = value === undefined || value === true ? {} : value\n for (const key of Object.keys(options)) {\n if (!KEYS.has(key)) {\n throw invalidOption('securityHeaders', `an object with ${[...KEYS].join(', ')} (unknown \"${key}\")`, options)\n }\n }\n const headers: Record<string, string> = {}\n const csp = options.contentSecurityPolicy ?? DEFAULT_CSP\n if (csp !== false) headers['content-security-policy'] = text('securityHeaders.contentSecurityPolicy', csp)\n const frame = options.frameOptions ?? 'DENY'\n if (frame !== false) {\n if (frame !== 'DENY' && frame !== 'SAMEORIGIN') {\n throw invalidOption('securityHeaders.frameOptions', '\"DENY\", \"SAMEORIGIN\" or false', frame)\n }\n headers['x-frame-options'] = frame\n }\n const noSniff = options.noSniff ?? true\n if (typeof noSniff !== 'boolean') throw invalidOption('securityHeaders.noSniff', 'a boolean', noSniff)\n if (noSniff) headers['x-content-type-options'] = 'nosniff'\n const referrer = options.referrerPolicy ?? 'no-referrer'\n if (referrer !== false) headers['referrer-policy'] = referrerPolicy(referrer)\n const hsts = strictTransportSecurity(options.hsts ?? false)\n if (hsts !== undefined) headers['strict-transport-security'] = hsts\n const corp = options.crossOriginResourcePolicy ?? false\n if (corp !== false) {\n if (typeof corp !== 'string' || !RESOURCE_POLICIES.has(corp)) {\n throw invalidOption(\n 'securityHeaders.crossOriginResourcePolicy',\n '\"same-origin\", \"same-site\", \"cross-origin\" or false',\n corp,\n )\n }\n headers['cross-origin-resource-policy'] = corp\n }\n const cacheControl = options.cacheControl ?? false\n if (cacheControl !== false) headers['cache-control'] = text('securityHeaders.cacheControl', cacheControl)\n return Object.freeze(headers)\n}\n\nfunction text(name: string, value: unknown): string {\n if (typeof value !== 'string' || value.trim() === '' || !isHeaderValue(value)) {\n throw invalidOption(name, 'a non-empty header value (or false)', value)\n }\n return value\n}\n\nfunction referrerPolicy(value: unknown): string {\n const policies = typeof value === 'string' ? value.split(',').map(item => item.trim()) : []\n if (policies.length === 0 || !policies.every(policy => REFERRER_POLICIES.has(policy))) {\n throw invalidOption(\n 'securityHeaders.referrerPolicy',\n `a referrer policy (${[...REFERRER_POLICIES].join(', ')}) or false`,\n value,\n )\n }\n return policies.join(', ')\n}\n\nfunction strictTransportSecurity(value: boolean | HstsOptions): string | undefined {\n if (value === false) return undefined\n if (value !== true && (value === null || typeof value !== 'object' || Array.isArray(value))) {\n throw invalidOption('securityHeaders.hsts', 'a boolean or { maxAge?, includeSubDomains?, preload? }', value)\n }\n const options: HstsOptions = value === true ? {} : value\n for (const key of Object.keys(options)) {\n if (key !== 'maxAge' && key !== 'includeSubDomains' && key !== 'preload') {\n throw invalidOption('securityHeaders.hsts', '{ maxAge?, includeSubDomains?, preload? }', options)\n }\n }\n const maxAge = options.maxAge ?? ONE_YEAR\n if (!Number.isSafeInteger(maxAge) || maxAge < 0) {\n throw invalidOption('securityHeaders.hsts.maxAge', 'a positive integer number of seconds', maxAge)\n }\n const includeSubDomains = options.includeSubDomains ?? true\n if (typeof includeSubDomains !== 'boolean') {\n throw invalidOption('securityHeaders.hsts.includeSubDomains', 'a boolean', includeSubDomains)\n }\n const preload = options.preload ?? false\n if (typeof preload !== 'boolean') throw invalidOption('securityHeaders.hsts.preload', 'a boolean', preload)\n if (preload && (!includeSubDomains || maxAge < ONE_YEAR)) {\n throw invalidOption(\n 'securityHeaders.hsts',\n 'includeSubDomains and a maxAge of at least 31536000 with preload',\n options,\n undefined,\n ['The HSTS preload list requires includeSubDomains and max-age >= 31536000'],\n )\n }\n return `max-age=${maxAge}${includeSubDomains ? '; includeSubDomains' : ''}${preload ? '; preload' : ''}`\n}\n","/**\n * File uploads: options of `@UploadedFile` / `@UploadedFiles`, the plugin-wide limits, the\n * `uploads` helpers used by generated `invoke` functions, and the body plan of a route (body limit\n * and multipart policy).\n */\nimport type { HttpContext } from './context.ts'\nimport type { HttpRouteDefinition, HttpUploadDefinition } from './metadata.ts'\nimport type { FileRule, MultipartPolicy } from './multipart.ts'\nimport type { ByteSize } from './size.ts'\n\nimport { BadRequestException, issue } from './exceptions.ts'\n\n/** Options of `@UploadedFile` (static: evaluated at build time). */\nexport interface UploadedFileOptions {\n /**\n * Answer 400 when no file is sent. Default: `true`, unless the parameter is optional\n * (`file?: File`, `File | undefined`).\n */\n readonly required?: boolean\n /** Maximum size of the file (`5_000_000`, `'5mb'`; `kb` = 1024 bytes). Default: plugin `uploads.maxFileSize`. */\n readonly maxSize?: ByteSize\n /**\n * Accepted media types, as declared by the client: `'image/png'`, `'image/*'`, `'*\\/*'`. Other\n * types answer 415. Default: any.\n */\n readonly mimeTypes?: readonly string[]\n}\n\n/** Options of `@UploadedFiles` (static: evaluated at build time). */\nexport interface UploadedFilesOptions extends UploadedFileOptions {\n /** Maximum number of files (413 above). Default: plugin `uploads.maxFiles`. */\n readonly maxFiles?: number\n}\n\n/** Plugin-wide upload limits (`HttpPlugin.configure({ uploads })`). */\nexport interface UploadLimits {\n /** Default maximum size of one file (`maxSize` of upload parameters). Default: `'10mb'`. */\n readonly maxFileSize?: ByteSize\n /** Default maximum number of files of `@UploadedFiles` (and of multipart bodies of other routes). Default: `10`. */\n readonly maxFiles?: number\n /** Maximum number of parts (text fields and files) of a multipart body (413 above). Default: `1000`. */\n readonly maxParts?: number\n /** Maximum size of one text field of a multipart body (413 above). Default: `'1mb'`. */\n readonly maxFieldSize?: ByteSize\n}\n\n/** {@link UploadLimits} with defaults applied, in bytes. */\nexport interface ResolvedUploadLimits {\n readonly maxFileSize: number\n readonly maxFiles: number\n readonly maxParts: number\n readonly maxFieldSize: number\n}\n\n/** Default upload limits. */\nexport const DEFAULT_UPLOAD_LIMITS: ResolvedUploadLimits = Object.freeze({\n maxFileSize: 10 * 1024 * 1024,\n maxFiles: 10,\n maxParts: 1000,\n maxFieldSize: 1024 * 1024,\n})\n\n/** How the body of a route is read (internal). */\nexport interface BodyPlan {\n /** Maximum body size in bytes (`Infinity`: no limit). */\n readonly limit: number\n /** Rules applied to `multipart/form-data` bodies. */\n readonly multipart: MultipartPolicy\n /** The route declares upload parameters: non-multipart bodies answer 415. */\n readonly upload: boolean\n}\n\n/**\n * The body plan of a route: `@BodyLimit` (`route.bodyLimit`) or, for upload routes, the sum of the\n * file limits plus the plugin `bodyLimit` (room for text fields and multipart framing), else the\n * plugin `bodyLimit`.\n */\nexport function bodyPlan(\n route: Pick<HttpRouteDefinition, 'bodyLimit' | 'uploads'>,\n bodyLimit: number,\n limits: ResolvedUploadLimits,\n): BodyPlan {\n const definitions = route.uploads ?? []\n const upload = definitions.length > 0\n const rules: FileRule[] = upload\n ? definitions.map(definition => fileRule(definition, limits))\n : [\n {\n field: undefined,\n multiple: true,\n maxSize: limits.maxFileSize,\n maxFiles: limits.maxFiles,\n mimeTypes: undefined,\n },\n ]\n let limit = route.bodyLimit\n if (limit === undefined) {\n limit = bodyLimit\n if (upload) for (const rule of rules) limit += rule.maxSize * rule.maxFiles\n }\n return { limit, upload, multipart: { rules, maxParts: limits.maxParts, maxFieldSize: limits.maxFieldSize } }\n}\n\nfunction fileRule(definition: HttpUploadDefinition, limits: ResolvedUploadLimits): FileRule {\n const multiple = definition.multiple === true\n return {\n field: definition.field,\n multiple,\n maxSize: definition.maxSize ?? limits.maxFileSize,\n maxFiles: multiple ? (definition.maxFiles ?? limits.maxFiles) : 1,\n mimeTypes: definition.mimeTypes,\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Helpers of the generated code\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Reads uploaded files from the context (`ctx.files`) in generated `invoke` functions\n * (`@UploadedFile('avatar') avatar: File` → `uploads.file(ctx, 'avatar')`). `field` `undefined`\n * means any field. Limits were enforced while the body was read; these helpers check presence.\n */\nexport interface Uploads {\n /** The file of `field`; 400 `Missing file \"field\"` when absent. */\n file(ctx: HttpContext, field: string | undefined): File\n /** The file of `field`, `undefined` when absent. */\n optionalFile(ctx: HttpContext, field: string | undefined): File | undefined\n /** The files of `field` (at least one); 400 `Missing files \"field\"` when none. */\n files(ctx: HttpContext, field: string | undefined): File[]\n /** The files of `field`, possibly none. */\n optionalFiles(ctx: HttpContext, field: string | undefined): File[]\n}\n\nconst NO_FILES: readonly File[] = Object.freeze([])\n\nfunction filesOf(ctx: HttpContext, field: string | undefined): readonly File[] {\n const files = ctx.files\n if (field !== undefined) return Object.hasOwn(files, field) ? (files[field] ?? NO_FILES) : NO_FILES\n const all: File[] = []\n for (const name of Object.keys(files)) all.push(...(files[name] ?? NO_FILES))\n return all\n}\n\nfunction missing(ctx: HttpContext, field: string | undefined, multiple: boolean): BadRequestException {\n const what = multiple ? 'files' : 'file'\n if (field === undefined) return new BadRequestException(`Missing ${what}`)\n const body = ctx.body\n if (body !== null && typeof body === 'object' && Object.hasOwn(body, field)) {\n return new BadRequestException(\n `Expected a file in field ${JSON.stringify(field)}, received a text value`,\n issue(field, 'Expected a file, received a text value'),\n )\n }\n return new BadRequestException(`Missing ${what} ${JSON.stringify(field)}`, issue(field, `Missing ${what}`))\n}\n\n/** The helpers of the generated code (`import { uploads } from '@znight/http'`). */\nexport const uploads: Uploads = Object.freeze({\n file(ctx: HttpContext, field: string | undefined): File {\n const [file] = filesOf(ctx, field)\n if (file === undefined) throw missing(ctx, field, false)\n return file\n },\n optionalFile(ctx: HttpContext, field: string | undefined): File | undefined {\n return filesOf(ctx, field)[0]\n },\n files(ctx: HttpContext, field: string | undefined): File[] {\n const files = filesOf(ctx, field)\n if (files.length === 0) throw missing(ctx, field, true)\n return [...files]\n },\n optionalFiles(ctx: HttpContext, field: string | undefined): File[] {\n return [...filesOf(ctx, field)]\n },\n})\n","import type { Container, Plugin, PluginContext, PluginOptions, ProviderKey, Token, ZnightMetadata } from '@znight/core'\nimport type {\n AdapterReply,\n HttpAdapter,\n HttpServerAddress,\n InjectRequest,\n InjectResponse,\n InjectStreamOptions,\n InjectStreamResponse,\n} from './adapter.ts'\nimport type { HttpContext } from './context.ts'\nimport type { CookieSettings } from './cookie-settings.ts'\nimport type { CookieDefaults } from './cookies.ts'\nimport type { CorsOptions, CorsPolicy } from './cors.ts'\nimport type { InjectSseResponse } from './inject-sse.ts'\nimport type {\n CanActivate,\n ExceptionMapper,\n ExceptionMapperClass,\n GuardClass,\n HttpInterceptor,\n HttpInterceptorClass,\n} from './interfaces.ts'\nimport type { HttpControllerDefinition, HttpMetadata, HttpMethod, HttpRouteDefinition } from './metadata.ts'\nimport type { CollectedPluginRoute } from './plugin-routes.ts'\nimport type { TrustPolicy, TrustProxy } from './proxy.ts'\nimport type { SecurityHeadersOptions } from './security-headers.ts'\nimport type { ByteSize } from './size.ts'\n\nimport { displayName, ErrorCode, resolveOptions, ZnightError } from '@znight/core'\n\nimport { nodeAdapter } from './adapters/node.ts'\nimport { DEFAULT_COOKIE_SETTINGS, missingSecrets, signValue } from './cookie-settings.ts'\nimport { type CookieSecret, CookieSigner, checkSecrets } from './cookie-signer.ts'\nimport { DEFAULT_COOKIE_OPTIONS, decodeCookieValue, isCookieName, serializeResponseCookie } from './cookies.ts'\nimport { resolveCors } from './cors.ts'\nimport {\n type CheckedRoute,\n checkDecisions,\n conflictingKeys,\n type EnforcementMode,\n effectiveMeta,\n enforcedBy,\n RouteGroups,\n type RouteMeta,\n} from './decisions.ts'\nimport { isHeaderName } from './headers.ts'\nimport { openInjectSse } from './inject-sse.ts'\nimport { isMediaTypePattern } from './mime.ts'\nimport { invalidOption } from './option-error.ts'\nimport { compareRoutePaths, compareStrings, joinPaths, parseRoutePath, type RoutePath, RoutePathError } from './path.ts'\nimport { DEFAULT_SSE_SETTINGS, Pipeline, type Resolvable, type RoutePlan, type SseSettings } from './pipeline.ts'\nimport { collectPluginRoutes } from './plugin-routes.ts'\nimport { resolveTrustProxy } from './proxy.ts'\nimport { RouteTable } from './router.ts'\nimport { resolveSecurityHeaders } from './security-headers.ts'\nimport { parseByteSize } from './size.ts'\nimport { MAX_SSE_TIMER_MS, MIN_SSE_INTERVAL_MS } from './sse.ts'\nimport { isValidStatus } from './status.ts'\nimport { HttpTokens } from './tokens.ts'\nimport { bodyPlan, DEFAULT_UPLOAD_LIMITS, type ResolvedUploadLimits, type UploadLimits } from './uploads.ts'\n\n/** How requests whose path ends with an extra `/` are handled. */\nexport type TrailingSlashPolicy = 'strict' | 'ignore' | 'redirect'\n\n/** A global guard: a provider class (resolved with the container) or an instance. */\nexport type GuardRef = GuardClass | CanActivate\n/** A global interceptor: a provider class or an instance. */\nexport type InterceptorRef = HttpInterceptorClass | HttpInterceptor\n/** An exception mapper: a provider class or an instance. */\nexport type ExceptionMapperRef = ExceptionMapperClass | ExceptionMapper\n\n/** Options of {@link HttpPlugin.configure}. */\nexport interface HttpPluginOptions {\n /** Server implementation. Default: `nodeAdapter()` (built-in, `node:http`). */\n readonly adapter?: HttpAdapter\n /** Port to listen on (`0` picks a free port). Default: `3000`. */\n readonly port?: number\n /** Interface to bind. Default: `0.0.0.0`. */\n readonly host?: string\n /** Path prefix of every route (`/api`). Default: none. */\n readonly prefix?: string\n /** Guards run before the controller and route guards of every route. */\n readonly guards?: readonly GuardRef[]\n /** Interceptors wrapping every route (outermost first). */\n readonly interceptors?: readonly InterceptorRef[]\n /** Error-to-response mappers, tried in order (see `ExceptionMapper`). */\n readonly exceptionMappers?: readonly ExceptionMapperRef[]\n /**\n * `strict` (default): `/users/` does not match `/users`. `ignore`: it does. `redirect`: it is\n * redirected (308) to `/users`.\n */\n readonly trailingSlash?: TrailingSlashPolicy\n /** Send the message of unexpected errors in 500 responses (development only). Default: `false`. */\n readonly exposeErrors?: boolean\n /**\n * Maximum request body size (413 above): bytes or a size with a unit (`'10mb'`; `kb` = 1024\n * bytes), `Infinity` for no limit. Routes override it with `@BodyLimit`; upload routes default to\n * the sum of their file limits plus this value. Default: 1 MiB.\n */\n readonly bodyLimit?: ByteSize\n /** Limits of multipart bodies and defaults of the upload parameters (see `UploadLimits`). */\n readonly uploads?: UploadLimits\n /**\n * Header carrying the request id: reused when the client sends a valid one (≤ 128 characters of\n * `[A-Za-z0-9_-.:@/+=]`), echoed on every response. `false`: always generate, never echo.\n * Default: `x-request-id`.\n */\n readonly requestIdHeader?: string | false\n /** Request id generator. Default: `crypto.randomUUID()`. */\n readonly generateRequestId?: () => string\n /**\n * Maximum time `onStop` waits for in-flight requests before closing the remaining connections.\n * Keep it below the application `shutdown.hookTimeoutMs`. `Infinity`: no limit of its own (the\n * application's `hookTimeoutMs` still bounds `onStop`). Default: 4 000 ms.\n */\n readonly drainTimeoutMs?: number\n /**\n * CORS: preflights are answered before routing and guards (never by a route), and replies to\n * allowed origins get `access-control-allow-origin`, identically on every adapter. Default: off.\n *\n * ```ts\n * cors: { origin: ['https://app.example.com', /^https:\\/\\/[a-z0-9-]+\\.preview\\.example\\.com$/], credentials: true }\n * ```\n */\n readonly cors?: CorsOptions | false\n /**\n * Security headers added to every reply that does not set them (`@Res()` raw replies excepted):\n * `true` (default) for the API defaults, an object merged over them, `false` for none.\n */\n readonly securityHeaders?: boolean | SecurityHeadersOptions\n /**\n * Proxies trusted for `x-forwarded-for` / `x-forwarded-proto` (`ctx.ip`, `ctx.protocol`): a number\n * of hops, or addresses, CIDR ranges and the aliases `'loopback'`, `'private'`, `'linklocal'`.\n * Default `false`: the headers are ignored and `ctx.ip` is the adapter's address.\n */\n readonly trustProxy?: TrustProxy\n /**\n * What the boot check of route decisions does when a route misses a decision of a required group,\n * or when no guard of its chain enforces its decision (ZNIGHT023): `'error'` (default) fails the\n * boot, `'warn'` logs one warning per group (tests that deliberately run without guards).\n */\n readonly enforcement?: EnforcementMode\n /** Cookies: signing keys and defaults (see {@link HttpCookieOptions}). */\n readonly cookies?: HttpCookieOptions\n /** Server-Sent Events defaults (see {@link HttpSseOptions}). */\n readonly sse?: HttpSseOptions\n}\n\n/** The plugin option `cookies`. */\nexport interface HttpCookieOptions {\n /**\n * HMAC keys of signed cookies (`@SignedCookie`, `{ signed: true }`), at least 32 bytes each: the\n * first signs, all verify (rotation: deploy `[next, current]`, wait for the longest cookie\n * lifetime, then `[next]`). Default: none (signed cookies unavailable).\n */\n readonly secrets?: string | Uint8Array | readonly (string | Uint8Array)[]\n /**\n * Defaults of every cookie set by the application, merged over the secure defaults\n * `{ path: '/', secure: true, httpOnly: true, sameSite: 'lax' }` (e.g. `{ secure: false }` for\n * plain `http://` development setups on a non-localhost host).\n */\n readonly defaults?: CookieDefaults\n}\n\n/** The plugin option `sse`. */\nexport interface HttpSseOptions {\n /** Default heartbeat (ms, an integer ≥ 1 000, or `false`). Default: 8 000. */\n readonly heartbeat?: number | false\n /** Default `retry` sent first (ms). Default: none. */\n readonly retry?: number\n /**\n * Time an event source gets to finish after `ctx.signal` aborted on shutdown or `maxDuration` (ms),\n * before the stream ends with a jittered `retry`. Must be lower than `drainTimeoutMs`. Default:\n * 1 000.\n */\n readonly shutdownGraceMs?: number\n}\n\n/** A route registered by the plugin (see {@link HttpPlugin.routes}). */\nexport interface HttpRouteSummary {\n readonly method: string\n /** Registered path, prefix included. */\n readonly path: string\n /** Controller display name, or the name of the plugin declaring the route. */\n readonly controller: string\n readonly handler: string\n /** `'controller'` for compiled routes, the plugin name for plugin routes. */\n readonly source: string\n /** Effective route metadata (the nearest decision of each group). */\n readonly meta: Readonly<Record<string, unknown>>\n /** Display names of the guards, in chain order (global, controller, route). */\n readonly guards: readonly string[]\n}\n\ninterface Resolved {\n readonly adapter: HttpAdapter\n readonly port: number\n readonly host: string\n readonly prefix: string\n readonly trailingSlash: TrailingSlashPolicy\n readonly exposeErrors: boolean\n readonly bodyLimit: number\n readonly uploads: ResolvedUploadLimits\n readonly requestIdHeader: string | undefined\n readonly generateRequestId: () => string\n readonly drainTimeoutMs: number\n readonly cors: CorsPolicy | undefined\n readonly securityHeaders: Readonly<Record<string, string>>\n readonly trustProxy: TrustPolicy | undefined\n readonly enforcement: EnforcementMode\n readonly cookies: CookieSettings\n readonly sse: SseSettings\n}\n\n/** Resolved options and the raw options they come from (memoised per application). */\ninterface ResolvedOptions {\n readonly raw: HttpPluginOptions\n readonly options: Resolved\n}\n\ninterface Runtime {\n readonly adapter: HttpAdapter\n readonly pipeline: Pipeline\n readonly options: Resolved\n readonly routes: readonly HttpRouteSummary[]\n}\n\ninterface Registration {\n readonly method: Exclude<HttpMethod, 'ALL'>\n readonly path: RoutePath\n readonly plan: RoutePlan\n /** `BookController.list`, `plugin \"openapi\" (document)`. */\n readonly label: string\n readonly source: string\n readonly guards: readonly string[]\n}\n\n/** A guard of a chain: how to resolve it, the class whose `enforces` counts, its display name. */\ninterface GuardEntry {\n readonly resolvable: Resolvable<CanActivate>\n readonly cls: unknown\n readonly name: string\n}\n\nconst DEFAULT_PORT = 3000\nconst DEFAULT_HOST = '0.0.0.0'\nconst DEFAULT_BODY_LIMIT = 1_048_576\nconst DEFAULT_DRAIN_TIMEOUT_MS = 4_000\nconst DEFAULT_REQUEST_ID_HEADER = 'x-request-id'\n/** Longest `setTimeout` delay (larger ones overflow to 1 ms). */\nconst MAX_TIMER_MS = 2_147_483_647\n/** Adapters bound to a plugin (an adapter instance serves one application). */\nconst BOUND_ADAPTERS = new WeakSet<HttpAdapter>()\nconst CONCRETE_METHODS: readonly Exclude<HttpMethod, 'ALL'>[] = [\n 'GET',\n 'HEAD',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n]\n\n/**\n * The HTTP plugin: serves the controllers compiled into `metadata.extensions.http` with the chosen\n * adapter.\n *\n * ```ts\n * const app = await Application.create({\n * metadata: __ZNIGHT_METADATA__,\n * plugins: [HttpPlugin.configure({ port: 3000, prefix: '/api' })],\n * })\n * await app.start()\n * ```\n *\n * Lifecycle: `register` declares the request-scoped externals `HttpContext` and `RequestId`;\n * `onBootstrap` resolves the options, controllers, guards and interceptors, collects the routes of\n * other plugins (`httpRoutes()`), checks route decisions and registers the routes; `onStart`\n * listens; `onStop` stops accepting connections and drains in-flight requests (`drainTimeoutMs`);\n * `onDispose` closes the server.\n */\nexport class HttpPlugin implements Plugin {\n readonly name = 'http'\n readonly #options: PluginOptions<HttpPluginOptions>\n /** Options resolved for the current application (reset in `register`). */\n #resolved: ResolvedOptions | undefined\n #container: Container | undefined\n #runtime: Runtime | undefined\n #address: HttpServerAddress | undefined\n #disposed = false\n /** Registered in an application that was not disposed yet. */\n #active = false\n\n private constructor(options: PluginOptions<HttpPluginOptions>) {\n this.#options = options\n }\n\n /**\n * Creates the plugin. `options` may be a function of the container, evaluated in `onBootstrap`:\n * `HttpPlugin.configure(c => ({ port: c.get(AppConfig).port }))`.\n */\n static configure(options: PluginOptions<HttpPluginOptions> = {}): HttpPlugin {\n return new HttpPlugin(options)\n }\n\n /** The adapter (available after `onBootstrap`). */\n get adapter(): HttpAdapter {\n return this.#require('adapter').adapter\n }\n\n /** Address of the server once listening (`String(address)` is its URL), `undefined` otherwise. */\n get address(): HttpServerAddress | undefined {\n return this.#address\n }\n\n /**\n * The path prefix of every route (`''` without prefix, `/api`), for plugins that serve routes or\n * publish URLs. Readable once the plugin is registered (before or after its `onBootstrap`; at any\n * time when the options are not a function of the container). Throws the options error when\n * the options are invalid.\n */\n get prefix(): string {\n const prefix = this.#resolve('prefix').options.prefix\n return prefix === '/' ? '' : prefix\n }\n\n /** Registered routes (after `onBootstrap`), in registration order. */\n get routes(): readonly HttpRouteSummary[] {\n return this.#runtime?.routes ?? []\n }\n\n /** Number of requests being processed. */\n get inflight(): number {\n return this.#runtime?.pipeline.inflight ?? 0\n }\n\n /** Number of open event streams (`@Sse`, `HttpResponse.sse()`): health checks, gauges, stream caps. */\n get streams(): number {\n return this.#runtime?.pipeline.streams ?? 0\n }\n\n /**\n * The signed wire value of a cookie (`<encoded value>.<signature>`, signed with the first secret of\n * `cookies.secrets`): what a browser would send back after `setCookie(name, value, { signed: true })`.\n * For gateways minting cookies and for tests. Available after `onBootstrap`.\n *\n * @throws TypeError for an invalid name or value; Error without `cookies.secrets`.\n */\n signCookie(name: string, value: string): string {\n const signer = this.#require('signCookie()').options.cookies.signer\n if (!isCookieName(name)) throw new TypeError(`Invalid cookie name ${JSON.stringify(String(name))}`)\n if (typeof value !== 'string') throw new TypeError(`The value of the cookie \"${name}\" must be a string`)\n if (signer === undefined) throw missingSecrets(`Cannot sign the cookie \"${name}\"`)\n return signValue(signer, name, value)\n }\n\n /**\n * The provider classes the plugin resolves in `onBootstrap` although no compiled metadata\n * references them: the classes of the `guards`, `interceptors` and `exceptionMappers` options\n * (instances are left out), in that order, without duplicates. `TestApp` from `@znight/testing`\n * creates them at boot with their dependencies (an async dependency cannot be created on demand);\n * pass them to `init: { only }` when restricting the boot with `Application.create()`.\n *\n * Options given as a function of the container cannot be read before the bootstrap: the result is\n * then empty. Never throws: invalid options are reported by `onBootstrap`.\n */\n initRoots(): readonly ProviderKey[] {\n const options: unknown = this.#options\n if (options === null || typeof options !== 'object') return []\n const roots = new Set<ProviderKey>()\n for (const key of GLOBAL_KEYS) {\n try {\n const refs: unknown = (options as HttpPluginOptions)[key]\n if (!Array.isArray(refs)) continue\n for (const ref of refs) {\n if (typeof ref === 'function') roots.add(ref as GuardClass)\n }\n } catch {\n // a throwing getter: reported when onBootstrap reads the option\n }\n }\n return [...roots]\n }\n\n /**\n * Sends a request in memory through the adapter and the whole pipeline (no socket; the server\n * does not need to listen). Available after `onBootstrap`.\n *\n * ```ts\n * const res = await http.inject({ method: 'POST', url: '/users', body: { name: 'Ada' } })\n * expect(res.status).toBe(201)\n * expect(res.json()).toEqual({ id: 1, name: 'Ada' })\n * ```\n */\n inject(request: InjectRequest): Promise<InjectResponse> {\n try {\n const runtime = this.#require('inject()')\n return runtime.adapter.inject(withSignedCookies(request, runtime.options.cookies, 'inject()'))\n } catch (error) {\n return Promise.reject(error)\n }\n }\n\n /**\n * Sends a request in memory and resolves at the response headers, the body being read as it is\n * produced (`body`). Cancelling `body` (or aborting `signal`) disconnects the client. Requires an\n * adapter implementing `injectStream()` (the four built-in ones do).\n */\n injectStream(request: InjectStreamOptions): Promise<InjectStreamResponse> {\n try {\n if (request === null || typeof request !== 'object')\n throw new TypeError('injectStream() expects a request object')\n const runtime = this.#require('injectStream()')\n const adapter = runtime.adapter\n if (typeof adapter.injectStream !== 'function') {\n throw new ZnightError(\n ErrorCode.LifecycleFailed,\n `HttpPlugin: the ${adapter.name} adapter does not implement injectStream()`,\n { hints: ['Use a built-in adapter (node, fastify, express, hono) or implement HttpAdapter.injectStream()'] },\n )\n }\n const sent = { ...request, method: request.method ?? 'GET' }\n return adapter.injectStream(withSignedCookies(sent, runtime.options.cookies, 'injectStream()'))\n } catch (error) {\n return Promise.reject(error)\n }\n }\n\n /**\n * Opens an event stream in memory (`accept: text/event-stream`) and reads its events like\n * `EventSource`: `next()`, `take()`, `comments`, `retry`, `lastEventId`, `reconnect()`, `close()`\n * (the server sees a client disconnect). A response that is not an event stream (404, 204...) is\n * read to its end (`body`). Resolves at the first chunk of the stream (an `@Sse` stream sends\n * `retry` or a comment at once), or after 2 000 ms for a stream that sends nothing yet; rejects,\n * naming the request (which is aborted), when no response headers arrive within 2 000 ms.\n *\n * ```ts\n * await using stream = await http.injectSse({ url: '/orders/o-1/events' })\n * const event = await stream.next() // rejects after 2 000 ms\n * expect(event.json()).toMatchObject({ status: 'paid' })\n * ```\n */\n injectSse(request: InjectStreamOptions): Promise<InjectSseResponse> {\n return openInjectSse(stream => this.injectStream(stream), request)\n }\n\n register(ctx: PluginContext): void {\n if (this.#active) {\n throw new ZnightError(ErrorCode.DuplicateProvider, 'This HttpPlugin is already used by another application', {\n hints: ['Call HttpPlugin.configure() once per application'],\n })\n }\n // an instance may serve several applications one after the other (shared test setups)\n this.#active = true\n this.#disposed = false\n this.#runtime = undefined\n this.#address = undefined\n this.#resolved = undefined\n this.#container = ctx.container\n ctx.container.registerExternal({ token: HttpTokens.Context, scope: 'request', providedBy: 'HttpPlugin' })\n ctx.container.registerExternal({ token: HttpTokens.RequestId, scope: 'request', providedBy: 'HttpPlugin' })\n ctx.container.registerValue(HttpTokens.Plugin, this)\n }\n\n onBootstrap(ctx: PluginContext): void {\n this.#container = ctx.container\n const { raw, options } = this.#resolve('onBootstrap')\n if (BOUND_ADAPTERS.has(options.adapter)) {\n throw new ZnightError(\n ErrorCode.LifecycleFailed,\n `HttpPlugin: this ${options.adapter.name} adapter instance already served an application`,\n {\n hints: [\n 'An adapter instance serves one application: create it per application, e.g. HttpPlugin.configure(() => ({ adapter: fastifyAdapter() }))',\n ],\n },\n )\n }\n BOUND_ADAPTERS.add(options.adapter)\n const table = new RouteTable<RoutePlan>()\n const pipeline = new Pipeline(\n ctx.container,\n ctx.hooks,\n ctx.logger,\n {\n adapter: options.adapter.name,\n body: bodyPlan({}, options.bodyLimit, options.uploads),\n exposeErrors: options.exposeErrors,\n requestIdHeader: options.requestIdHeader,\n generateRequestId: options.generateRequestId,\n mappers: globalRefs<ExceptionMapper>(ctx.container, ctx.metadata, raw, 'exceptionMappers'),\n cors: options.cors,\n securityHeaders: options.securityHeaders,\n trustProxy: options.trustProxy,\n cookies: options.cookies,\n sse: options.sse,\n },\n table,\n )\n const pluginRoutes = collectPluginRoutes(ctx.app.plugins, this, {\n prefix: options.prefix === '/' ? '' : options.prefix,\n container: ctx.container,\n })\n const { registrations, checked } = buildRegistrations(ctx, options, raw, pluginRoutes)\n checkDecisions(checked.routes, checked.groups, options.enforcement, ctx.logger, checked.enforcers)\n const adapter = options.adapter\n const routes: HttpRouteSummary[] = []\n for (const registration of registrations) {\n table.add(registration.method, registration.path, registration.plan)\n const plan = registration.plan\n adapter.registerRoute({\n method: registration.method,\n path: registration.path,\n handler: (request): Promise<AdapterReply> => pipeline.handle(plan, request),\n })\n routes.push(\n Object.freeze({\n method: registration.method,\n path: registration.path.path,\n controller: registration.source === 'controller' ? displayName(plan.info.controller) : registration.source,\n handler: plan.info.handler,\n source: registration.source,\n meta: plan.info.meta,\n guards: registration.guards,\n }),\n )\n }\n adapter.setFallbackHandler((request, error) => pipeline.fallback(request, error))\n this.#runtime = { adapter, pipeline, options, routes: Object.freeze(routes) }\n }\n\n async onStart(ctx: PluginContext): Promise<void> {\n const runtime = this.#require('onStart')\n runtime.pipeline.draining = false\n this.#address = await runtime.adapter.listen(runtime.options.port, runtime.options.host)\n ctx.logger.info(`HTTP server listening on ${this.#address.url}`, {\n adapter: runtime.adapter.name,\n routes: runtime.routes.length,\n })\n }\n\n async onStop(ctx: PluginContext): Promise<void> {\n const runtime = this.#runtime\n if (runtime === undefined) return\n runtime.pipeline.draining = true\n // event streams never end by themselves: let their sources finish, then send them a jittered retry\n runtime.pipeline.closeStreams('shutdown')\n const timeoutMs = runtime.options.drainTimeoutMs\n let timer: ReturnType<typeof setTimeout> | undefined\n // no timer for Infinity; larger delays than setTimeout supports are clamped (they would fire at once)\n const timeout = new Promise<'timeout'>(resolve => {\n if (timeoutMs !== Number.POSITIVE_INFINITY) {\n timer = setTimeout(() => resolve('timeout'), Math.min(timeoutMs, MAX_TIMER_MS))\n }\n })\n try {\n const drained = Promise.all([runtime.adapter.close(), runtime.pipeline.whenIdle()]).then(() => 'drained' as const)\n if ((await Promise.race([drained, timeout])) === 'timeout') {\n ctx.logger.warn(`HTTP server: closing ${runtime.pipeline.inflight} in-flight request(s) after ${timeoutMs} ms`)\n await runtime.adapter.close({ force: true })\n }\n } finally {\n clearTimeout(timer)\n this.#address = undefined\n }\n }\n\n async onDispose(): Promise<void> {\n this.#active = false\n if (this.#disposed) return\n this.#disposed = true\n const runtime = this.#runtime\n this.#address = undefined\n if (runtime !== undefined) await runtime.adapter.close({ force: true })\n }\n\n /** Resolves the options once per application (`prefix` may need them before `onBootstrap`). */\n #resolve(action: string): ResolvedOptions {\n if (this.#resolved !== undefined) return this.#resolved\n let raw: HttpPluginOptions\n if (typeof this.#options === 'function') {\n const container = this.#container\n if (container === undefined) {\n throw new ZnightError(\n ErrorCode.LifecycleFailed,\n `HttpPlugin: ${action} is only available once the plugin is registered in an application (its options are a function of the container)`,\n )\n }\n raw = resolveOptions(this.#options, container)\n } else {\n raw = this.#options\n }\n const resolved: ResolvedOptions = { raw, options: resolve(raw) }\n this.#resolved = resolved\n return resolved\n }\n\n #require(action: string): Runtime {\n if (this.#disposed) {\n throw new ZnightError(ErrorCode.LifecycleFailed, `HttpPlugin: cannot use ${action} after the application stopped`)\n }\n if (this.#runtime === undefined) {\n throw new ZnightError(\n ErrorCode.LifecycleFailed,\n `HttpPlugin: ${action} is only available once the application is created (after onBootstrap)`,\n )\n }\n return this.#runtime\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Options\n// -------------------------------------------------------------------------------------------------\n\nfunction resolve(options: HttpPluginOptions): Resolved {\n if (options === null || typeof options !== 'object') throw invalidOption('options', 'an object', options)\n const port = options.port ?? DEFAULT_PORT\n if (!Number.isInteger(port) || port < 0 || port > 65_535)\n throw invalidOption('port', 'an integer between 0 and 65535', port)\n const host = options.host ?? DEFAULT_HOST\n if (typeof host !== 'string' || host === '') throw invalidOption('host', 'a non-empty string', host)\n const prefix = options.prefix ?? ''\n if (typeof prefix !== 'string') throw invalidOption('prefix', 'a string', prefix)\n let parsedPrefix: RoutePath\n try {\n parsedPrefix = parseRoutePath(prefix)\n } catch (error) {\n throw invalidOption('prefix', 'a valid static path', prefix, error)\n }\n if (parsedPrefix.segments.some(segment => segment.kind !== 'static')) {\n throw invalidOption('prefix', 'a static path (no :param or *)', prefix)\n }\n const trailingSlash = options.trailingSlash ?? 'strict'\n if (trailingSlash !== 'strict' && trailingSlash !== 'ignore' && trailingSlash !== 'redirect') {\n throw invalidOption('trailingSlash', '\"strict\", \"ignore\" or \"redirect\"', trailingSlash)\n }\n const bodyLimit = parseByteSize(options.bodyLimit ?? DEFAULT_BODY_LIMIT)\n if (bodyLimit === undefined) {\n throw invalidOption('bodyLimit', \"a size in bytes (1048576, '10mb', Infinity)\", options.bodyLimit)\n }\n const uploads = resolveUploadLimits(options.uploads)\n const drainTimeoutMs = options.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS\n if (typeof drainTimeoutMs !== 'number' || !(drainTimeoutMs >= 0)) {\n throw invalidOption('drainTimeoutMs', 'a positive number (or Infinity)', drainTimeoutMs)\n }\n const requestIdHeader = options.requestIdHeader ?? DEFAULT_REQUEST_ID_HEADER\n if (requestIdHeader !== false && (typeof requestIdHeader !== 'string' || !isHeaderName(requestIdHeader))) {\n throw invalidOption('requestIdHeader', 'a header name or false', requestIdHeader)\n }\n const generateRequestId = options.generateRequestId ?? ((): string => crypto.randomUUID())\n if (typeof generateRequestId !== 'function') throw invalidOption('generateRequestId', 'a function', generateRequestId)\n const adapter = options.adapter ?? nodeAdapter()\n if (\n adapter === null ||\n typeof adapter !== 'object' ||\n typeof adapter.registerRoute !== 'function' ||\n typeof adapter.listen !== 'function' ||\n typeof adapter.inject !== 'function'\n ) {\n throw invalidOption('adapter', 'an HttpAdapter (nodeAdapter(), fastifyAdapter()...)', adapter)\n }\n const enforcement = options.enforcement ?? 'error'\n if (enforcement !== 'error' && enforcement !== 'warn') {\n throw invalidOption('enforcement', '\"error\" or \"warn\"', enforcement)\n }\n const resolvedRequestIdHeader = requestIdHeader === false ? undefined : requestIdHeader.toLowerCase()\n const cookies = resolveCookies(options.cookies)\n const sse = resolveSse(options.sse, drainTimeoutMs)\n return {\n adapter,\n port,\n host,\n prefix: parsedPrefix.path,\n trailingSlash,\n exposeErrors: options.exposeErrors === true,\n bodyLimit,\n uploads,\n requestIdHeader: resolvedRequestIdHeader,\n generateRequestId,\n drainTimeoutMs,\n cors: resolveCors(options.cors, resolvedRequestIdHeader),\n securityHeaders: resolveSecurityHeaders(options.securityHeaders),\n trustProxy: resolveTrustProxy(options.trustProxy),\n enforcement,\n cookies,\n sse,\n }\n}\n\nconst COOKIE_DEFAULT_KEYS = ['domain', 'path', 'secure', 'httpOnly', 'sameSite', 'partitioned', 'priority']\n\nfunction resolveCookies(value: HttpCookieOptions | undefined): CookieSettings {\n if (value === undefined) return DEFAULT_COOKIE_SETTINGS\n if (value === null || typeof value !== 'object')\n throw invalidOption('cookies', 'an object { secrets?, defaults? }', value)\n for (const key of Object.keys(value)) {\n if (key !== 'secrets' && key !== 'defaults') {\n throw invalidOption('cookies', 'an object { secrets?, defaults? }', `unknown key \"${key}\"`)\n }\n }\n let signer: CookieSigner | undefined\n if (value.secrets !== undefined) {\n const checked = checkSecrets(value.secrets)\n // never echo a secret in an error\n if ('problem' in checked) {\n throw new ZnightError(\n ErrorCode.InvalidDecorator,\n `HttpPlugin: option \"cookies.secrets\" must be ${checked.problem}`,\n {\n hints: [\"Generate secrets with crypto.randomBytes(32).toString('base64url') and load them with @Secret\"],\n },\n )\n }\n signer = new CookieSigner(checked.secrets as readonly CookieSecret[])\n }\n const given = value.defaults\n if (given !== undefined && (given === null || typeof given !== 'object' || Array.isArray(given))) {\n throw invalidOption('cookies.defaults', `an object { ${COOKIE_DEFAULT_KEYS.join('?, ')}? }`, given)\n }\n const defaults: CookieDefaults = { ...DEFAULT_COOKIE_OPTIONS }\n for (const [key, option] of Object.entries(given ?? {})) {\n if (!COOKIE_DEFAULT_KEYS.includes(key)) {\n throw invalidOption(\n 'cookies.defaults',\n `an object { ${COOKIE_DEFAULT_KEYS.join('?, ')}? }`,\n `unknown key \"${key}\"`,\n )\n }\n if (option !== undefined) (defaults as Record<string, unknown>)[key] = option\n }\n try {\n // a probe cookie checks every default and their combination (SameSite=None without Secure...)\n serializeResponseCookie({ name: 'probe', value: '', options: {} }, defaults)\n } catch (error) {\n throw invalidOption('cookies.defaults', 'valid cookie attributes', given, error, [\n error instanceof Error ? error.message.replace('Invalid cookie \"probe\": ', '') : String(error),\n ])\n }\n return Object.freeze({ defaults: Object.freeze(defaults), signer })\n}\n\nfunction resolveSse(value: HttpSseOptions | undefined, drainTimeoutMs: number): SseSettings {\n if (value === undefined) return DEFAULT_SSE_SETTINGS\n const shape = '{ heartbeat?, retry?, shutdownGraceMs? }'\n if (value === null || typeof value !== 'object') throw invalidOption('sse', `an object ${shape}`, value)\n for (const key of Object.keys(value)) {\n if (key !== 'heartbeat' && key !== 'retry' && key !== 'shutdownGraceMs') {\n throw invalidOption('sse', `an object ${shape}`, `unknown key \"${key}\"`)\n }\n }\n const heartbeat = value.heartbeat ?? DEFAULT_SSE_SETTINGS.heartbeat\n if (\n heartbeat !== false &&\n !(Number.isSafeInteger(heartbeat) && heartbeat >= MIN_SSE_INTERVAL_MS && heartbeat <= MAX_SSE_TIMER_MS)\n ) {\n throw invalidOption(\n 'sse.heartbeat',\n `an integer number of ms from ${MIN_SSE_INTERVAL_MS} to ${MAX_SSE_TIMER_MS}, or false`,\n heartbeat,\n )\n }\n const retry = value.retry\n if (retry !== undefined && !(Number.isSafeInteger(retry) && retry >= 0)) {\n throw invalidOption('sse.retry', 'an integer number of ms ≥ 0', retry)\n }\n const shutdownGraceMs = value.shutdownGraceMs ?? DEFAULT_SSE_SETTINGS.shutdownGraceMs\n if (!(Number.isSafeInteger(shutdownGraceMs) && shutdownGraceMs >= 0 && shutdownGraceMs <= MAX_SSE_TIMER_MS)) {\n throw invalidOption('sse.shutdownGraceMs', `an integer number of ms from 0 to ${MAX_SSE_TIMER_MS}`, shutdownGraceMs)\n }\n if (drainTimeoutMs !== Number.POSITIVE_INFINITY && shutdownGraceMs >= drainTimeoutMs) {\n throw invalidOption(\n 'sse.shutdownGraceMs',\n `lower than drainTimeoutMs (${drainTimeoutMs})`,\n shutdownGraceMs,\n undefined,\n [\n 'Event streams get shutdownGraceMs to finish, within the drain of in-flight requests: shutdownGraceMs < drainTimeoutMs < shutdown.hookTimeoutMs',\n ],\n )\n }\n return Object.freeze({ heartbeat: heartbeat === false ? 0 : heartbeat, retry, shutdownGraceMs })\n}\n\n/**\n * The request with its `signedCookies` signed (first secret) and merged into `cookies`: adapters\n * never receive `signedCookies`.\n */\nfunction withSignedCookies<R extends InjectRequest>(request: R, cookies: CookieSettings, action: string): R {\n if (request === null || typeof request !== 'object' || request.signedCookies === undefined) return request\n const signed = request.signedCookies\n if (signed === null || typeof signed !== 'object') throw new TypeError(`${action}: signedCookies must be an object`)\n const signer = cookies.signer\n if (signer === undefined) {\n throw new TypeError(\n `${action}: signedCookies require the HttpPlugin option cookies.secrets (HttpPlugin.configure({ cookies: { secrets: [...] } }))`,\n )\n }\n const merged: Record<string, string> = { ...request.cookies }\n for (const name of Object.keys(signed)) {\n const value = signed[name]\n if (!isCookieName(name)) throw new TypeError(`${action}: invalid signed cookie name ${JSON.stringify(name)}`)\n if (typeof value !== 'string')\n throw new TypeError(`${action}: the value of the signed cookie \"${name}\" must be a string`)\n // the decoded wire value: inject() encodes cookie values again (the encoding is canonical)\n merged[name] = decodeCookieValue(signValue(signer, name, value))\n }\n const { signedCookies: _signed, ...rest } = request\n return { ...rest, cookies: merged } as R\n}\n\nfunction resolveUploadLimits(value: UploadLimits | undefined): ResolvedUploadLimits {\n if (value === undefined) return DEFAULT_UPLOAD_LIMITS\n if (value === null || typeof value !== 'object') throw invalidOption('uploads', 'an object', value)\n const size = (key: 'maxFileSize' | 'maxFieldSize'): number => {\n const raw = value[key]\n if (raw === undefined) return DEFAULT_UPLOAD_LIMITS[key]\n const parsed = parseByteSize(raw)\n if (parsed === undefined) throw invalidOption(`uploads.${key}`, \"a size in bytes (1048576, '10mb', Infinity)\", raw)\n return parsed\n }\n const count = (key: 'maxFiles' | 'maxParts'): number => {\n const raw = value[key]\n if (raw === undefined) return DEFAULT_UPLOAD_LIMITS[key]\n if (raw !== Number.POSITIVE_INFINITY && (!Number.isSafeInteger(raw) || raw < 1)) {\n throw invalidOption(`uploads.${key}`, 'a positive integer (or Infinity)', raw)\n }\n return raw\n }\n for (const key of Object.keys(value)) {\n if (!['maxFileSize', 'maxFiles', 'maxParts', 'maxFieldSize'].includes(key)) {\n throw invalidOption('uploads', '{ maxFileSize?, maxFiles?, maxParts?, maxFieldSize? }', value)\n }\n }\n return {\n maxFileSize: size('maxFileSize'),\n maxFiles: count('maxFiles'),\n maxParts: count('maxParts'),\n maxFieldSize: size('maxFieldSize'),\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Routes\n// -------------------------------------------------------------------------------------------------\n\nfunction httpMetadata(metadata: ZnightMetadata): HttpMetadata {\n const http = metadata.extensions?.http\n if (http === undefined) return { controllers: [] }\n if (http === null || typeof http !== 'object' || !Array.isArray(http.controllers)) {\n throw new ZnightError(ErrorCode.InvalidRoute, 'Invalid metadata.extensions.http: expected { controllers: [...] }')\n }\n return http\n}\n\n/** Routes as seen by the boot check of route decisions, with the groups they are checked against. */\ninterface Checked {\n readonly routes: readonly CheckedRoute[]\n readonly groups: RouteGroups\n /** Group → the guard classes enforcing it, in a chain or not. */\n readonly enforcers: ReadonlyMap<string, ReadonlySet<string>>\n}\n\n/** A declared route (controller route or plugin route), before HEAD, `@All` and trailing-slash expansion. */\ninterface Declared {\n readonly method: HttpMethod\n readonly path: RoutePath\n readonly plan: (method: string) => RoutePlan\n readonly label: string\n readonly source: string\n readonly guards: readonly GuardEntry[]\n /** Effective metadata (available once every group is known). */\n meta(): RouteMeta\n}\n\nfunction buildRegistrations(\n ctx: PluginContext,\n options: Resolved,\n raw: HttpPluginOptions,\n pluginRoutes: readonly CollectedPluginRoute[],\n): { readonly registrations: Registration[]; readonly checked: Checked } {\n const { container, metadata } = ctx\n const http = httpMetadata(metadata)\n const groups = RouteGroups.fromMetadata(http.groups)\n const groupOf = (key: string): string => groups.groupOf(key)\n const resolvables = new Map<Token, Resolvable<unknown>>()\n const lookup = <T>(token: Token, what: string): Resolvable<T> => {\n let found = resolvables.get(token)\n if (found === undefined) {\n found = resolvable(container, metadata, token, what)\n resolvables.set(token, found)\n }\n return found as Resolvable<T>\n }\n const compiledGuard = (token: Token, what: string): GuardEntry => ({\n resolvable: lookup<CanActivate>(token, what),\n // the compiled class: a guard replaced through `overrides` in a test keeps its declaration\n cls: Object.hasOwn(metadata.providers, token) ? metadata.providers[token]?.class : undefined,\n name: displayName(token),\n })\n const globalGuards = guardEntries(container, metadata, raw.guards ?? [], ref =>\n invalidOption('guards', 'classes or objects with a canActivate() method', ref),\n )\n const globalInterceptors = globalRefs<HttpInterceptor>(container, metadata, raw, 'interceptors')\n const declared: Declared[] = []\n /** Checks run once every group is declared. */\n const pending: (() => void)[] = []\n\n for (const controller of http.controllers) {\n assertController(controller)\n const name = displayName(controller.token)\n const instance = lookup<object>(controller.token, `controller ${name}`)\n const controllerGuards = controller.guards.map(token => compiledGuard(token, `guard of ${name}`))\n const controllerInterceptors = controller.interceptors.map(token =>\n lookup<HttpInterceptor>(token, `interceptor of ${name}`),\n )\n const controllerMeta = assertMeta(controller.meta, name)\n pending.push(() => checkTargetMeta(controllerMeta, groupOf, name))\n for (const route of controller.routes) {\n const where = `${name}.${String(route?.handler)}`\n assertRoute(route, where)\n if (options.cookies.signer === undefined) {\n const signed = route.params.find(param => param?.source === 'signedCookie')\n if (signed !== undefined) {\n throw new ZnightError(\n ErrorCode.MissingConfig,\n `HttpPlugin: ${where} reads a signed cookie (@SignedCookie('${signed.name ?? ''}')) but cookies.secrets is not set`,\n {\n hints: [\n \"Set HttpPlugin.configure({ cookies: { secrets: [...] } }) with secrets of at least 32 bytes (crypto.randomBytes(32).toString('base64url'))\",\n ],\n },\n )\n }\n }\n let path: RoutePath\n try {\n path = parseRoutePath(joinPaths(options.prefix, route.fullPath))\n } catch (error) {\n if (!(error instanceof RoutePathError)) throw error\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route ${route.method} ${route.fullPath} (${where}): ${error.issue.message}`,\n { cause: error },\n )\n }\n const routeMeta = assertMeta(route.meta, where)\n const guards = [\n ...globalGuards,\n ...controllerGuards,\n ...route.guards.map(token => compiledGuard(token, `guard of ${where}`)),\n ]\n const interceptors = [\n ...globalInterceptors,\n ...controllerInterceptors,\n ...route.interceptors.map(token => lookup<HttpInterceptor>(token, `interceptor of ${where}`)),\n ]\n const body = bodyPlan(route, options.bodyLimit, options.uploads)\n const parseBody = body.upload || route.params.some(param => param.source === 'body')\n const chain = guards.map(guard => guard.resolvable)\n // computed once every group is declared (guards of every chain, plugin routes), then frozen\n let meta: RouteMeta | undefined\n const effective = (): RouteMeta => {\n meta ??= effectiveMeta(controllerMeta, routeMeta, groupOf)\n return meta\n }\n pending.push(() => checkTargetMeta(routeMeta, groupOf, where))\n declared.push({\n method: route.method,\n path,\n plan: (method: string): RoutePlan => ({\n definition: route,\n path,\n info: Object.freeze({\n method,\n path: path.path,\n controller: controller.token,\n handler: route.handler,\n meta: effective(),\n }),\n controller: instance,\n guards: chain,\n interceptors,\n parseBody,\n body,\n }),\n label: where,\n source: 'controller',\n guards,\n meta: effective,\n })\n }\n }\n\n for (const route of pluginRoutes) {\n const label = `plugin \"${route.plugin}\" (${route.name})`\n const where = `${route.method} ${route.path.path} (${route.name})`\n const guards = [\n ...globalGuards,\n ...guardEntries(\n container,\n metadata,\n route.guards,\n ref =>\n new ZnightError(\n ErrorCode.InvalidRoute,\n `HttpPlugin: plugin \"${route.plugin}\": the guards of the route ${where} must be classes or objects with a canActivate() method (received ${describeValue(ref)})`,\n ),\n ),\n ]\n const values: Record<string, unknown> = {}\n for (const entry of route.meta) {\n groups.declare(entry, `the plugin \"${route.plugin}\"`)\n values[entry.key] = entry.value\n }\n const meta: RouteMeta = Object.freeze(values)\n pending.push(() => checkTargetMeta(meta, groupOf, `the route ${where} of the plugin \"${route.plugin}\"`))\n const handler = route.handler\n const definition: HttpRouteDefinition = Object.freeze({\n method: route.method,\n path: route.relativePath,\n fullPath: route.relativePath,\n handler: route.name,\n meta,\n guards: [],\n interceptors: [],\n params: [],\n invoke: (_plugin: unknown, http: HttpContext): unknown => handler(http),\n })\n const instance: Resolvable<object> = { instance: route.instance }\n const body = bodyPlan({}, options.bodyLimit, options.uploads)\n const chain = guards.map(guard => guard.resolvable)\n const path = route.path\n declared.push({\n method: route.method,\n path,\n plan: (method: string): RoutePlan => ({\n definition,\n path,\n info: Object.freeze({ method, path: path.path, controller: route.plugin, handler: route.name, meta }),\n controller: instance,\n guards: chain,\n // global interceptors wrap controllers only (a response envelope would break a document)\n interceptors: [],\n parseBody: false,\n body,\n }),\n label,\n source: route.plugin,\n guards,\n meta: () => meta,\n })\n }\n\n // `enforces` of every guard class, read once per class. The guards of the chains declare their\n // groups; the guard classes of the application that sit in no chain only make their groups known,\n // so that a decision whose guard was forgotten everywhere (a second entrypoint, a worker, a test)\n // is still reported instead of being silently unenforced\n const enforcedGroups = new Map<unknown, ReadonlySet<string>>()\n const enforcers = new Map<string, Set<string>>()\n const readEnforces = (cls: unknown, name: string, chained: boolean): void => {\n if (enforcedGroups.has(cls)) return\n const infos = enforcedBy(cls, name)\n if (chained) for (const info of infos) groups.declare(info, `the guard ${name}`)\n enforcedGroups.set(cls, new Set(infos.map(info => info.group)))\n for (const info of infos) {\n let names = enforcers.get(info.group)\n if (names === undefined) {\n names = new Set()\n enforcers.set(info.group, names)\n }\n names.add(name)\n }\n }\n for (const route of declared) for (const guard of route.guards) readEnforces(guard.cls, guard.name, true)\n for (const token of Object.keys(metadata.providers)) {\n const cls = metadata.providers[token]?.class\n if (isGuardClass(cls)) readEnforces(cls, displayName(token), false)\n }\n for (const check of pending) check()\n const checked: CheckedRoute[] = declared.map(route => {\n const enforced = new Set<string>()\n for (const guard of route.guards) for (const group of enforcedGroups.get(guard.cls) ?? []) enforced.add(group)\n return {\n description: `${route.method} ${route.path.path} (${route.label})`,\n meta: route.meta(),\n enforced,\n ...(route.source === 'controller' ? {} : { plugin: route.source }),\n }\n })\n\n const registration = (route: Declared, method: Exclude<HttpMethod, 'ALL'>): Registration => ({\n method,\n path: route.path,\n plan: route.plan(method),\n label: route.label,\n source: route.source,\n guards: Object.freeze(route.guards.map(guard => guard.name)),\n })\n const explicit: Registration[] = []\n const catchAll: Declared[] = []\n for (const route of declared) {\n if (route.method === 'ALL') catchAll.push(route)\n else explicit.push(registration(route, route.method))\n }\n\n // explicit routes, then HEAD for GET routes, then @All routes for the methods left\n const table = new RouteTable<Registration>()\n const accepted: Registration[] = []\n const add = (candidate: Registration, duplicate: boolean): void => {\n const existing = table.add(candidate.method, candidate.path, candidate)\n if (existing === undefined) accepted.push(candidate)\n else if (duplicate) throw duplicateRoute(candidate, existing)\n }\n for (const candidate of explicit) add(candidate, true)\n for (const candidate of explicit) {\n if (candidate.method === 'GET') add({ ...candidate, method: 'HEAD' }, false)\n }\n const catchAllShapes = new Map<string, Registration>()\n for (const route of catchAll) {\n const first = registration(route, 'GET')\n const other = catchAllShapes.get(route.path.shape)\n if (other !== undefined) throw duplicateRoute(first, other)\n catchAllShapes.set(route.path.shape, first)\n for (const method of CONCRETE_METHODS) add(method === 'GET' ? first : registration(route, method), false)\n }\n\n // trailing-slash variants\n const result: Registration[] = [...accepted]\n if (options.trailingSlash !== 'strict') {\n for (const candidate of accepted) {\n const path = candidate.path\n if (path.segments.length === 0 || path.wildcard) continue\n const variant: RoutePath = {\n path: `${path.path}/`,\n segments: [...path.segments, { kind: 'static', value: '' }],\n params: path.params,\n wildcard: false,\n shape: `${path.shape}/`,\n }\n const plan: RoutePlan =\n options.trailingSlash === 'redirect'\n ? { ...candidate.plan, path: variant, redirect: true }\n : { ...candidate.plan, path: variant }\n result.push({ ...candidate, path: variant, plan })\n }\n }\n\n // HEAD first (Express answers HEAD with the first matching GET route), then most specific first\n const registrations = result.sort((a, b) => {\n const head = (a.method === 'HEAD' ? 0 : 1) - (b.method === 'HEAD' ? 0 : 1)\n if (head !== 0) return head\n return compareRoutePaths(a.path, b.path) || compareStrings(a.method, b.method)\n })\n return { registrations, checked: { routes: checked, groups, enforcers } }\n}\n\nconst EMPTY_META: RouteMeta = Object.freeze({})\n\n/** Hand-written metadata: two keys of one group on one target (ZNIGHT007). */\nfunction checkTargetMeta(meta: RouteMeta, groupOf: (key: string) => string, target: string): void {\n const conflict = conflictingKeys(meta, groupOf)\n if (conflict === undefined) return\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route metadata of ${target}: \"${conflict[0]}\" and \"${conflict[1]}\" are two decisions of the \"${conflict[2]}\" group`,\n { hints: ['The decorators of a group are alternatives: keep one per controller or route'] },\n )\n}\n\nfunction duplicateRoute(registration: Registration, existing: Registration): ZnightError {\n const plugin = registration.source === 'controller' ? existing.source : registration.source\n return new ZnightError(\n ErrorCode.InvalidRoute,\n `Duplicate route ${registration.method} ${registration.path.path}: ${registration.label} conflicts with ${existing.label} (${existing.path.path})`,\n {\n hints: [\n 'Two routes with the same method and the same path shape (parameter names aside) cannot coexist',\n ...(plugin === 'controller' ? [] : [`Change the path of the route in the options of the plugin \"${plugin}\"`]),\n ],\n },\n )\n}\n\n/** Route metadata must be a plain object (hand-written metadata). */\nfunction assertMeta(meta: unknown, where: string): RouteMeta {\n if (meta === undefined) return EMPTY_META\n if (meta === null || typeof meta !== 'object' || Array.isArray(meta)) {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route metadata of ${where}: expected an object (received ${describeValue(meta)})`,\n )\n }\n return meta as RouteMeta\n}\n\nfunction assertController(controller: HttpControllerDefinition): void {\n if (\n controller === null ||\n typeof controller !== 'object' ||\n typeof controller.token !== 'string' ||\n !Array.isArray(controller.routes) ||\n !Array.isArray(controller.guards) ||\n !Array.isArray(controller.interceptors)\n ) {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid controller definition in metadata.extensions.http: ${describeValue(controller)}`,\n )\n }\n}\n\nfunction assertRoute(route: HttpRouteDefinition, where: string): void {\n if (\n route === null ||\n typeof route !== 'object' ||\n typeof route.invoke !== 'function' ||\n typeof route.handler !== 'string'\n ) {\n throw new ZnightError(ErrorCode.InvalidRoute, `Invalid route definition ${where}: missing handler or invoke()`)\n }\n if (!(CONCRETE_METHODS as readonly string[]).includes(route.method) && route.method !== 'ALL') {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route ${where}: unknown method ${describeValue(route.method)}`,\n )\n }\n if (typeof route.fullPath !== 'string') {\n throw new ZnightError(ErrorCode.InvalidRoute, `Invalid route ${where}: missing fullPath`)\n }\n if (route.status !== undefined && !isValidStatus(route.status)) {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route ${where}: @HttpCode(${describeValue(route.status)}) is not a valid status`,\n )\n }\n if (!Array.isArray(route.guards) || !Array.isArray(route.interceptors) || !Array.isArray(route.params)) {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route ${where}: guards, interceptors and params must be arrays`,\n )\n }\n if (route.bodyLimit !== undefined && !isSize(route.bodyLimit)) {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route ${where}: bodyLimit must be a number of bytes (or Infinity), got ${describeValue(route.bodyLimit)}`,\n )\n }\n if (route.uploads !== undefined) assertUploads(route, where)\n if (route.sse !== undefined) assertSse(route, where)\n}\n\nfunction assertSse(route: HttpRouteDefinition, where: string): void {\n const sse: unknown = route.sse\n const invalid = (reason: string): ZnightError =>\n new ZnightError(ErrorCode.InvalidRoute, `Invalid route ${where}: ${reason}`, {\n hints: [\n 'sse: { heartbeat?: 0 | 1000 ≤ ms ≤ 2147483647, retry?: ms ≥ 0, maxDuration?: 1000 ≤ ms ≤ 2147483647 } on a GET route',\n ],\n })\n if (route.method !== 'GET') throw invalid(`sse is only valid on GET routes (method ${route.method})`)\n if (sse === null || typeof sse !== 'object' || Array.isArray(sse)) throw invalid('sse must be an object')\n for (const [key, value] of Object.entries(sse)) {\n if (value === undefined) continue\n const integer = typeof value === 'number' && Number.isSafeInteger(value)\n const timer = integer && value >= MIN_SSE_INTERVAL_MS && value <= MAX_SSE_TIMER_MS\n const valid =\n (key === 'heartbeat' && integer && (value === 0 || timer)) ||\n (key === 'retry' && integer && value >= 0) ||\n (key === 'maxDuration' && timer)\n if (!valid) throw invalid(`invalid sse.${key} ${describeValue(value)}`)\n }\n}\n\nfunction isSize(value: unknown): boolean {\n return value === Number.POSITIVE_INFINITY || (Number.isSafeInteger(value) && (value as number) >= 0)\n}\n\nfunction assertUploads(route: HttpRouteDefinition, where: string): void {\n const invalid = (reason: string): ZnightError =>\n new ZnightError(ErrorCode.InvalidRoute, `Invalid route ${where}: ${reason}`, {\n hints: ['uploads: [{ field?, multiple?, required?, maxSize?, maxFiles?, mimeTypes? }]'],\n })\n if (!Array.isArray(route.uploads)) throw invalid('uploads must be an array')\n const fields = new Set<string | undefined>()\n for (const upload of route.uploads) {\n if (upload === null || typeof upload !== 'object') throw invalid(`invalid upload ${describeValue(upload)}`)\n const { field, maxSize, maxFiles, mimeTypes } = upload\n if (field !== undefined && (typeof field !== 'string' || field === '')) {\n throw invalid(`invalid upload field ${describeValue(field)}`)\n }\n if (fields.has(field) || (fields.size > 0 && (field === undefined || fields.has(undefined)))) {\n throw invalid(\n field === undefined\n ? 'an upload without field (every file) cannot be combined with other uploads'\n : `several uploads for the field \"${field}\"`,\n )\n }\n fields.add(field)\n if (maxSize !== undefined && !isSize(maxSize)) throw invalid(`invalid maxSize ${describeValue(maxSize)}`)\n if (maxFiles !== undefined && (!isSize(maxFiles) || maxFiles < 1)) {\n throw invalid(`invalid maxFiles ${describeValue(maxFiles)}`)\n }\n if (\n mimeTypes !== undefined &&\n (!Array.isArray(mimeTypes) ||\n mimeTypes.length === 0 ||\n !mimeTypes.every(type => typeof type === 'string' && isMediaTypePattern(type)))\n ) {\n throw invalid(`invalid mimeTypes ${describeValue(mimeTypes)}`)\n }\n }\n}\n\nfunction describeValue(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value)\n } catch {\n return String(value)\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Provider resolution\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Singletons (and registered values) are resolved once at bootstrap; request-scoped and transient\n * providers on every request.\n */\nfunction resolvable<T>(container: Container, metadata: ZnightMetadata, token: Token, what: string): Resolvable<T> {\n const scope = Object.hasOwn(metadata.providers, token) ? metadata.providers[token]?.scope : undefined\n if (!container.has(token)) {\n throw new ZnightError(ErrorCode.MissingProvider, `HttpPlugin: the ${what} (${token}) is not a provider`, {\n hints: ['Add @Injectable() to the class (controllers are providers through @Controller())'],\n })\n }\n if (scope === 'request' || scope === 'transient') return { token }\n try {\n return { instance: container.get(token) as T }\n } catch (error) {\n if ((error as { code?: unknown } | null)?.code === ErrorCode.NoActiveScope) return { token }\n throw error\n }\n}\n\ntype GlobalKey = 'guards' | 'interceptors' | 'exceptionMappers'\nconst GLOBAL_KEYS: readonly GlobalKey[] = ['guards', 'interceptors', 'exceptionMappers']\nconst GLOBAL_METHOD: Readonly<Record<GlobalKey, string>> = {\n guards: 'canActivate',\n interceptors: 'intercept',\n exceptionMappers: 'map',\n}\nconst GLOBAL_WHAT: Readonly<Record<GlobalKey, string>> = {\n guards: 'guard',\n interceptors: 'interceptor',\n exceptionMappers: 'exception mapper',\n}\n\n/** Resolves global guards / interceptors / exception mappers given as classes or instances. */\nfunction globalRefs<T>(\n container: Container,\n metadata: ZnightMetadata,\n options: HttpPluginOptions,\n key: GlobalKey,\n): Resolvable<T>[] {\n const refs: unknown = options[key] ?? []\n if (!Array.isArray(refs)) throw invalidOption(key, 'an array', refs)\n const method = GLOBAL_METHOD[key]\n const what = GLOBAL_WHAT[key]\n return refs.map(\n (ref: unknown): Resolvable<T> =>\n resolveRef<T>(container, metadata, ref, what, method, () =>\n invalidOption(key, `classes or objects with a ${method}() method`, ref),\n ).resolvable,\n )\n}\n\n/** A provider class whose instances are guards (a `canActivate()` method on its prototype). */\nfunction isGuardClass(cls: unknown): boolean {\n if (typeof cls !== 'function') return false\n const prototype: unknown = (cls as { prototype?: unknown }).prototype\n return (\n typeof prototype === 'object' &&\n prototype !== null &&\n typeof (prototype as { canActivate?: unknown }).canActivate === 'function'\n )\n}\n\n/** Guards given as classes or instances (`guards` option, plugin routes), with their class and name. */\nfunction guardEntries(\n container: Container,\n metadata: ZnightMetadata,\n refs: unknown,\n invalid: (ref: unknown) => ZnightError,\n): GuardEntry[] {\n if (!Array.isArray(refs)) throw invalidOption('guards', 'an array', refs)\n return refs.map((ref: unknown) =>\n resolveRef<CanActivate>(container, metadata, ref, 'guard', 'canActivate', () => invalid(ref)),\n )\n}\n\nfunction resolveRef<T>(\n container: Container,\n metadata: ZnightMetadata,\n ref: unknown,\n what: string,\n method: string,\n invalid: () => ZnightError,\n): { readonly resolvable: Resolvable<T>; readonly cls: unknown; readonly name: string } {\n if (typeof ref === 'function') {\n const token = container.tokenOf(ref as GuardClass)\n if (token === undefined) {\n const name = (ref as { name?: string }).name || '<anonymous>'\n throw new ZnightError(ErrorCode.MissingProvider, `HttpPlugin: the global ${what} ${name} is not a provider`, {\n hints: ['Add @Injectable() to the class, or pass an instance'],\n })\n }\n return {\n resolvable: resolvable<T>(container, metadata, token, `global ${what}`),\n cls: ref,\n name: displayName(token),\n }\n }\n if (ref !== null && typeof ref === 'object' && typeof (ref as Record<string, unknown>)[method] === 'function') {\n const cls: unknown = (ref as { constructor?: unknown }).constructor\n const className = typeof cls === 'function' && cls !== Object ? (cls as { name?: string }).name : undefined\n return { resolvable: { instance: ref as T }, cls, name: className || `${what} instance` }\n }\n throw invalid()\n}\n","/**\n * A copy of the [Standard Schema v1](https://standardschema.dev) interface, flattened (no namespace,\n * so the file stays erasable). Every compliant library (Zod, Valibot, ArkType, Effect Schema...)\n * produces values assignable to {@link StandardSchemaV1}: no adapter and no dependency are needed.\n */\n\n/** A schema implementing the Standard Schema v1 interface. */\nexport interface StandardSchemaV1<Input = unknown, Output = Input> {\n /** The Standard Schema properties. */\n readonly '~standard': StandardSchemaV1Props<Input, Output>\n}\n\n/** The Standard Schema properties. */\nexport interface StandardSchemaV1Props<Input = unknown, Output = Input> {\n /** The version number of the standard. */\n readonly version: 1\n /** The vendor name of the schema library. */\n readonly vendor: string\n /** Validates an unknown input value (synchronously or not). */\n readonly validate: (\n value: unknown,\n options?: StandardSchemaV1Options | undefined,\n ) => StandardSchemaV1Result<Output> | Promise<StandardSchemaV1Result<Output>>\n /** Inferred types associated with the schema. */\n readonly types?: StandardSchemaV1Types<Input, Output> | undefined\n}\n\n/** Options of {@link StandardSchemaV1Props.validate}. */\nexport interface StandardSchemaV1Options {\n /** Vendor-specific parameters. */\n readonly libraryOptions?: Record<string, unknown> | undefined\n}\n\n/** Result of {@link StandardSchemaV1Props.validate}. */\nexport type StandardSchemaV1Result<Output> = StandardSchemaV1SuccessResult<Output> | StandardSchemaV1FailureResult\n\n/** Successful validation: the (possibly transformed) output value. */\nexport interface StandardSchemaV1SuccessResult<Output> {\n readonly value: Output\n readonly issues?: undefined\n}\n\n/** Failed validation. */\nexport interface StandardSchemaV1FailureResult {\n readonly issues: readonly StandardSchemaV1Issue[]\n}\n\n/** One validation issue. */\nexport interface StandardSchemaV1Issue {\n readonly message: string\n readonly path?: readonly (PropertyKey | StandardSchemaV1PathSegment)[] | undefined\n}\n\n/** A path segment of an issue. */\nexport interface StandardSchemaV1PathSegment {\n readonly key: PropertyKey\n}\n\n/** Input and output types of a schema. */\nexport interface StandardSchemaV1Types<Input = unknown, Output = Input> {\n readonly input: Input\n readonly output: Output\n}\n\n/** The input type of a schema. */\nexport type InferSchemaInput<S extends StandardSchemaV1> = NonNullable<S['~standard']['types']>['input']\n\n/** The output type of a schema (what handlers receive). */\nexport type InferSchemaOutput<S extends StandardSchemaV1> = NonNullable<S['~standard']['types']>['output']\n\n/** Whether `value` looks like a Standard Schema v1 (has a `~standard` object with a `validate` function). */\nexport function isStandardSchema(value: unknown): value is StandardSchemaV1 {\n if (value === null || (typeof value !== 'object' && typeof value !== 'function')) return false\n const props = (value as { '~standard'?: unknown })['~standard']\n return (\n props !== null &&\n typeof props === 'object' &&\n (props as { version?: unknown }).version === 1 &&\n typeof (props as { validate?: unknown }).validate === 'function'\n )\n}\n","import { ValidationException } from './exceptions.ts'\nimport {\n type InferSchemaOutput,\n isStandardSchema,\n type StandardSchemaV1,\n type StandardSchemaV1Issue,\n type StandardSchemaV1Result,\n} from './standard-schema.ts'\nimport { isThenable } from './utils.ts'\n\n/**\n * Validates `value` with a [Standard Schema](https://standardschema.dev) (Zod, Valibot, ArkType...)\n * and returns the schema **output** (defaults applied, transforms run, unknown keys stripped when\n * the schema strips them).\n *\n * Returns synchronously when the schema validates synchronously, a promise otherwise (async\n * refinements): generated code always `await`s it.\n *\n * @param location what is validated, used in the error message: `body`, `query`, `query \"page\"`,\n * `param \"id\"`, `headers`, `cookie \"sid\"`, `cookies`...\n * @throws ValidationException (400, `details: [{ path, message }]`) when the value is invalid. For\n * cookies (`cookie \"name\"`, `cookies`) the issue messages are replaced with `Invalid value`: some\n * libraries quote the received value in them (Valibot, ArkType), and cookies often carry tokens.\n * @throws TypeError when `schema` is not a Standard Schema v1 (a programming error → 500).\n */\nexport function validate<S extends StandardSchemaV1>(\n schema: S,\n value: unknown,\n location: string,\n): InferSchemaOutput<S> | Promise<InferSchemaOutput<S>> {\n if (!isStandardSchema(schema)) {\n throw new TypeError(`The schema of ${location} is not a Standard Schema v1 (missing \"~standard.validate\")`)\n }\n const result = schema['~standard'].validate(value) as\n | StandardSchemaV1Result<InferSchemaOutput<S>>\n | Promise<StandardSchemaV1Result<InferSchemaOutput<S>>>\n if (isThenable(result)) return Promise.resolve(result).then(settled => unwrap(settled, location))\n return unwrap(result, location)\n}\n\nfunction unwrap<T>(result: StandardSchemaV1Result<T>, location: string): T {\n if (result.issues !== undefined) {\n throw new ValidationException(location, isCookieLocation(location) ? result.issues.map(redact) : result.issues)\n }\n return result.value\n}\n\n/** The message of a redacted issue (cookie values are never echoed). */\nconst REDACTED = 'Invalid value'\n\nfunction isCookieLocation(location: string): boolean {\n return location === 'cookies' || location.startsWith('cookie ')\n}\n\n/**\n * The issue with the keys of its path only: its message may quote the value (`Received \"eyJ...\"`),\n * and so may the path segments of some libraries (Valibot keeps `input` and `value` there).\n */\nfunction redact(issue: StandardSchemaV1Issue): StandardSchemaV1Issue {\n if (issue.path === undefined) return { message: REDACTED }\n const path = issue.path.map(segment =>\n typeof segment === 'object' && segment !== null ? { key: segment.key } : segment,\n )\n return { message: REDACTED, path }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["Buffer","DECODER","malformed","truncate","invalid","describe","NO_FILES","NO_COOKIES","ENCODER","crypto","KEYS","describe","describe","describe","ENCODER","ENCODER","utf8","Buffer","text","Buffer","parseRange","resolve"],"sources":["../src/multipart.ts","../src/query.ts","../src/body.ts","../src/coerce.ts","../src/cookie-settings.ts","../src/context.ts","../src/decorators.ts","../src/event-channel.ts","../src/files.ts","../src/cookie-signer.ts","../src/headers.ts","../src/option-error.ts","../src/cors.ts","../src/decisions.ts","../src/sse-parse.ts","../src/inject-sse.ts","../src/sse.ts","../src/response.ts","../src/serialize.ts","../src/tokens.ts","../src/pipeline.ts","../src/plugin-routes.ts","../src/proxy.ts","../src/security-headers.ts","../src/uploads.ts","../src/plugin.ts","../src/standard-schema.ts","../src/validate.ts"],"sourcesContent":["/**\n * Streaming `multipart/form-data` parser (RFC 7578, RFC 2046), shared by every adapter so that\n * uploads behave the same on Node.js and Bun.\n *\n * The Web-standard `Request.formData()` is not used: it buffers the whole body before parsing, has\n * no per-part limits, and its results differ between runtimes (default part type, `filename*`,\n * escaped quotes, LF line endings, parts without name). This parser reads the body as it arrives\n * and enforces the upload rules of the route (expected fields, file count, size and media type) on\n * the fly, so an invalid upload is rejected as soon as the offending part shows up. Files are\n * buffered in memory as standard `File` objects, within the limits.\n *\n * Status codes: malformed bodies, unexpected file fields and several files for a single-file field\n * → 400; a file, a field, too many files or too many parts → 413; a refused media type → 415. Errors\n * raised while the body is being read carry `connection: close` (the rest of the body is discarded).\n */\nimport type { HttpExceptionOptions } from './exceptions.ts'\nimport type { QueryRecord } from './query.ts'\n\nimport { Buffer } from 'node:buffer'\n\nimport { BadRequestException, issue, PayloadTooLargeException, UnsupportedMediaTypeException } from './exceptions.ts'\nimport { matchesMediaType, mediaTypeEssence, OCTET_STREAM } from './mime.ts'\nimport { formatByteSize } from './size.ts'\nimport { emptyRecord } from './utils.ts'\n\n/** Constraints of the files received by one upload parameter (`@UploadedFile` / `@UploadedFiles`). */\nexport interface FileRule {\n /** Field name; `undefined`: the files of every field. */\n readonly field: string | undefined\n /** `@UploadedFiles` (an array) rather than `@UploadedFile` (a single file). */\n readonly multiple: boolean\n /** Maximum size of each file, in bytes. */\n readonly maxSize: number\n /** Maximum number of files (1 for a single file). */\n readonly maxFiles: number\n /** Accepted media types (`image/png`, `image/*`); `undefined`: any. */\n readonly mimeTypes: readonly string[] | undefined\n}\n\n/** How a multipart body is read. */\nexport interface MultipartPolicy {\n /**\n * Upload rules of the route (files are only accepted in their fields: a file in another field is\n * rejected with 400, unless a rule has no field). Without rules, every file is accepted without\n * limit (but the body limit).\n */\n readonly rules: readonly FileRule[]\n /** Maximum number of parts (text fields and files). */\n readonly maxParts: number\n /** Maximum size of a text field, in bytes. */\n readonly maxFieldSize: number\n}\n\n/** A parsed multipart body. */\nexport interface MultipartResult {\n /** Text fields (repeated names → arrays), without prototype. */\n readonly fields: QueryRecord\n /** Files by field name, without prototype. */\n readonly files: Record<string, File[]>\n /** Every file, in body order. */\n readonly list: readonly File[]\n /** Every entry, in body order. */\n readonly entries: readonly (readonly [string, string | File])[]\n}\n\n/** Default maximum size of the headers of one part. */\nconst MAX_HEADER_SIZE = 16 * 1024\n/** Maximum transport padding (spaces) after a boundary delimiter. */\nconst MAX_PADDING = 256\n/** Errors raised while the body is still being read ask the client to close the connection. */\nconst CLOSE: HttpExceptionOptions = Object.freeze({ headers: Object.freeze({ connection: 'close' }) })\n\nconst CR = 13\nconst LF = 10\nconst DASH = 45\nconst SPACE = 32\nconst TAB = 9\nconst HEADER_END = Buffer.from('\\r\\n\\r\\n')\nconst EMPTY: Buffer = Buffer.alloc(0)\nconst DECODER = new TextDecoder()\n\nconst PRINTABLE = /^[\\u0020-\\u007e]*$/\n\n/**\n * A received file. Its `type` is the media type declared by the client, lower-cased (empty when it\n * contains characters outside printable ASCII), identical on every runtime (Bun's `File` adds\n * `;charset=utf-8` to some text types).\n */\nfunction createFile(chunks: Uint8Array[], name: string, type: string): File {\n const file = new File(chunks, name, { type })\n const normalized = PRINTABLE.test(type) ? type.toLowerCase() : ''\n if (file.type !== normalized) Object.defineProperty(file, 'type', { value: normalized, configurable: true })\n return file\n}\n\n/** Description of a part, from its headers. */\nexport interface PartInfo {\n readonly name: string\n /** `undefined` for text fields. */\n readonly filename: string | undefined\n readonly contentType: string | undefined\n}\n\n/** Receives the content of one part. */\nexport interface PartSink {\n data(chunk: Uint8Array): void\n end(): void\n}\n\n/** Receives the parts found by {@link MultipartParser}. */\nexport interface PartHandler {\n start(part: PartInfo): PartSink\n}\n\ntype State = 'preamble' | 'delimiter' | 'headers' | 'body' | 'done'\n\n/**\n * Incremental parser: feed it with {@link write} as chunks arrive, then call {@link end}. Errors\n * (malformed body, limits enforced by the handler) are thrown synchronously from `write`/`end`.\n */\nexport class MultipartParser {\n readonly #delimiter: Buffer\n readonly #handler: PartHandler\n readonly #maxHeaderSize: number\n /** The body is conceptually prefixed with CRLF so that every delimiter is `CRLF--boundary`. */\n #buffer: Buffer = Buffer.from('\\r\\n')\n #state: State = 'preamble'\n #sink: PartSink | undefined\n /** Bytes of the header block already searched for its end (avoids rescanning on every chunk). */\n #scanned = 0\n\n constructor(boundary: string, handler: PartHandler, maxHeaderSize: number = MAX_HEADER_SIZE) {\n this.#delimiter = Buffer.from(`\\r\\n--${boundary}`, 'latin1')\n this.#handler = handler\n this.#maxHeaderSize = maxHeaderSize\n }\n\n /** `true` once the closing delimiter was read (what follows is the epilogue, ignored). */\n get done(): boolean {\n return this.#state === 'done'\n }\n\n write(chunk: Uint8Array): void {\n if (this.#state === 'done' || chunk.byteLength === 0) return\n const view = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength)\n this.#buffer = this.#buffer.length === 0 ? view : Buffer.concat([this.#buffer, view])\n this.#process()\n }\n\n end(): void {\n if (this.#state !== 'done') throw malformed('unexpected end of the body (missing closing boundary)')\n }\n\n #process(): void {\n for (;;) {\n switch (this.#state) {\n case 'preamble': {\n const index = this.#buffer.indexOf(this.#delimiter)\n if (index === -1) {\n this.#keepTail()\n return\n }\n this.#buffer = this.#buffer.subarray(index + this.#delimiter.length)\n this.#state = 'delimiter'\n break\n }\n case 'delimiter':\n if (!this.#afterDelimiter()) return\n break\n case 'headers':\n if (!this.#headers()) return\n break\n case 'body':\n if (!this.#body()) return\n break\n default:\n return\n }\n }\n }\n\n /** After a delimiter: `--` (closing delimiter) or optional padding then CRLF (next part). */\n #afterDelimiter(): boolean {\n const buffer = this.#buffer\n if (buffer.length < 2) return false\n if (buffer[0] === DASH && buffer[1] === DASH) {\n this.#state = 'done'\n this.#buffer = EMPTY\n return false\n }\n let index = 0\n while (index < buffer.length && (buffer[index] === SPACE || buffer[index] === TAB)) index++\n if (index > MAX_PADDING) throw malformed('invalid boundary delimiter')\n if (index + 1 >= buffer.length) return false\n if (buffer[index] !== CR || buffer[index + 1] !== LF) throw malformed('invalid boundary delimiter')\n this.#buffer = buffer.subarray(index + 2)\n this.#state = 'headers'\n return true\n }\n\n #headers(): boolean {\n const buffer = this.#buffer\n if (buffer.length < 2) return false\n let end: number\n let next: number\n if (buffer[0] === CR && buffer[1] === LF) {\n end = 0\n next = 2\n } else {\n end = buffer.indexOf(HEADER_END, Math.max(0, this.#scanned - (HEADER_END.length - 1)))\n if (end === -1) {\n if (buffer.length > this.#maxHeaderSize) throw malformed('the headers of a part are too large')\n this.#scanned = buffer.length\n return false\n }\n if (end > this.#maxHeaderSize) throw malformed('the headers of a part are too large')\n next = end + 4\n }\n const part = parsePartHeaders(buffer.toString('utf8', 0, end))\n this.#scanned = 0\n this.#buffer = buffer.subarray(next)\n this.#sink = this.#handler.start(part)\n this.#state = 'body'\n return true\n }\n\n #body(): boolean {\n const buffer = this.#buffer\n const sink = this.#sink as PartSink\n const index = buffer.indexOf(this.#delimiter)\n if (index === -1) {\n // keep what may be the beginning of a delimiter\n const safe = buffer.length - (this.#delimiter.length - 1)\n if (safe > 0) {\n sink.data(buffer.subarray(0, safe))\n this.#buffer = buffer.subarray(safe)\n }\n return false\n }\n if (index > 0) sink.data(buffer.subarray(0, index))\n this.#sink = undefined\n sink.end()\n this.#buffer = buffer.subarray(index + this.#delimiter.length)\n this.#state = 'delimiter'\n return true\n }\n\n #keepTail(): void {\n const keep = this.#delimiter.length - 1\n if (this.#buffer.length > keep) this.#buffer = this.#buffer.subarray(this.#buffer.length - keep)\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Headers\n// -------------------------------------------------------------------------------------------------\n\nfunction parsePartHeaders(block: string): PartInfo {\n let disposition: string | undefined\n let contentType: string | undefined\n let current: 'content-disposition' | 'content-type' | undefined\n if (block !== '') {\n for (const line of block.split('\\r\\n')) {\n if (line.startsWith(' ') || line.startsWith('\\t')) {\n // obsolete line folding: continuation of the previous header\n if (current === 'content-disposition') disposition = `${disposition ?? ''} ${line.trim()}`\n else if (current === 'content-type') contentType = `${contentType ?? ''} ${line.trim()}`\n continue\n }\n const colon = line.indexOf(':')\n if (colon <= 0) throw malformed('invalid part header')\n const name = line.slice(0, colon).trim().toLowerCase()\n const value = line.slice(colon + 1).trim()\n current = undefined\n if (name === 'content-disposition' && disposition === undefined) {\n disposition = value\n current = name\n } else if (name === 'content-type' && contentType === undefined) {\n contentType = value\n current = name\n }\n }\n }\n if (disposition === undefined) throw malformed('a part has no Content-Disposition header')\n const { type, params } = parseParameters(disposition)\n if (type !== 'form-data') throw malformed('a part is not \"form-data\"')\n const name = params.get('name')\n if (name === undefined) throw malformed('a part has no name')\n const extended = params.get('filename*')\n const plain = params.get('filename')\n const filename = (extended === undefined ? undefined : decodeExtendedValue(extended)) ?? plain\n return {\n name: decodeFormName(name),\n filename: filename === undefined ? undefined : decodeFormName(filename),\n contentType: contentType === '' ? undefined : contentType,\n }\n}\n\n/**\n * Parses `value; key=token; key=\"quoted \\\" string\"` (Content-Disposition, Content-Type). Keys are\n * lower-cased; the first occurrence of a key wins.\n */\nexport function parseParameters(value: string): { readonly type: string; readonly params: Map<string, string> } {\n const params = new Map<string, string>()\n let index = value.indexOf(';')\n const type = (index === -1 ? value : value.slice(0, index)).trim().toLowerCase()\n while (index !== -1 && index < value.length) {\n index++ // skip ';'\n while (index < value.length && isSpace(value.charCodeAt(index))) index++\n if (index >= value.length) break\n if (value[index] === ';') continue // empty parameter\n const equals = value.indexOf('=', index)\n if (equals === -1) throw malformed(`invalid parameter in ${JSON.stringify(truncate(value))}`)\n const key = value.slice(index, equals).trim().toLowerCase()\n index = equals + 1\n while (index < value.length && isSpace(value.charCodeAt(index))) index++\n let parameter: string\n if (value[index] === '\"') {\n parameter = ''\n index++\n for (;;) {\n if (index >= value.length) throw malformed('unterminated quoted string in a part header')\n const char = value[index] as string\n if (char === '\"') {\n index++\n break\n }\n if (char === '\\\\' && (value[index + 1] === '\"' || value[index + 1] === '\\\\')) {\n parameter += value[index + 1]\n index += 2\n continue\n }\n parameter += char\n index++\n }\n while (index < value.length && isSpace(value.charCodeAt(index))) index++\n if (index < value.length && value[index] !== ';') throw malformed('invalid quoted string in a part header')\n } else {\n const next = value.indexOf(';', index)\n parameter = (next === -1 ? value.slice(index) : value.slice(index, next)).trim()\n index = next === -1 ? value.length : next\n }\n if (key !== '' && !params.has(key)) params.set(key, parameter)\n if (index >= value.length) break\n }\n return { type, params }\n}\n\nfunction isSpace(code: number): boolean {\n return code === SPACE || code === TAB\n}\n\n/** Names and filenames: browsers escape `\"`, CR and LF as `%22`, `%0D` and `%0A` (HTML standard). */\nfunction decodeFormName(value: string): string {\n return value.includes('%')\n ? value.replace(/%(22|0D|0A)/gi, (_match, hex: string) => String.fromCharCode(Number.parseInt(hex, 16)))\n : value\n}\n\n/** RFC 5987 `charset'language'percent-encoded` (`filename*`); `undefined` when it cannot be decoded. */\nfunction decodeExtendedValue(value: string): string | undefined {\n const match = /^([\\w!#$%&+^`{}~-]+)'[\\w-]*'(.*)$/.exec(value)\n if (match === null) return undefined\n const charset = (match[1] as string).toLowerCase()\n const encoded = match[2] as string\n try {\n if (charset === 'utf-8') return decodeURIComponent(encoded)\n if (charset === 'iso-8859-1') {\n return encoded.replace(/%([0-9a-f]{2})/gi, (_match, hex: string) => String.fromCharCode(Number.parseInt(hex, 16)))\n }\n } catch {\n return undefined\n }\n return undefined\n}\n\n/** The `boundary` parameter of a `multipart/form-data` content type (400 when missing or invalid). */\nexport function multipartBoundary(contentType: string): string {\n let boundary: string | undefined\n try {\n boundary = parseParameters(contentType).params.get('boundary')\n } catch {\n boundary = undefined\n }\n if (boundary === undefined || boundary === '') throw malformed('missing boundary in the content type')\n // RFC 2046: 1 to 70 printable ASCII characters\n if (boundary.length > 70 || [...boundary].some(char => char < ' ' || char > '~')) {\n throw malformed('invalid boundary in the content type')\n }\n return boundary\n}\n\n// -------------------------------------------------------------------------------------------------\n// Collecting fields and files\n// -------------------------------------------------------------------------------------------------\n\n/** Applies a {@link MultipartPolicy} to the parts and collects fields and files. */\nclass Collector implements PartHandler {\n readonly fields: QueryRecord = emptyRecord()\n readonly files: Record<string, File[]> = emptyRecord()\n readonly list: File[] = []\n readonly entries: (readonly [string, string | File])[] = []\n readonly #policy: MultipartPolicy\n readonly #named: ReadonlyMap<string, FileRule>\n readonly #any: FileRule | undefined\n readonly #counts = new Map<FileRule, number>()\n #parts = 0\n\n constructor(policy: MultipartPolicy) {\n this.#policy = policy\n const named = new Map<string, FileRule>()\n let any: FileRule | undefined\n for (const rule of policy.rules) {\n if (rule.field === undefined) any = rule\n else named.set(rule.field, rule)\n }\n this.#named = named\n this.#any = any\n }\n\n start(part: PartInfo): PartSink {\n this.#parts++\n if (this.#parts > this.#policy.maxParts) {\n throw new PayloadTooLargeException(\n `Too many parts in the multipart body (at most ${this.#policy.maxParts})`,\n { maxParts: this.#policy.maxParts },\n CLOSE,\n )\n }\n return part.filename === undefined ? this.#field(part.name) : this.#file(part, part.filename)\n }\n\n #field(name: string): PartSink {\n const limit = this.#policy.maxFieldSize\n const chunks: Uint8Array[] = []\n let size = 0\n return {\n data: chunk => {\n size += chunk.byteLength\n if (size > limit) {\n throw new PayloadTooLargeException(\n `Field ${JSON.stringify(truncate(name))} exceeds the maximum size of ${formatByteSize(limit)}`,\n { field: name, maxSize: limit },\n CLOSE,\n )\n }\n chunks.push(chunk)\n },\n end: () => {\n const value = DECODER.decode(chunks.length === 1 ? (chunks[0] as Uint8Array) : Buffer.concat(chunks))\n const existing = this.fields[name]\n if (existing === undefined) this.fields[name] = value\n else if (typeof existing === 'string') this.fields[name] = [existing, value]\n else existing.push(value)\n this.entries.push([name, value])\n },\n }\n }\n\n #file(part: PartInfo, filename: string): PartSink {\n const type = part.contentType === undefined ? OCTET_STREAM : part.contentType\n const name = part.name\n let rules: readonly FileRule[] = []\n let admitted = false\n // an empty <input type=\"file\"> is sent as an empty part without filename: it is not a file\n const admit = (): void => {\n admitted = true\n rules = this.#admit(name, type)\n }\n if (filename !== '') admit()\n const chunks: Uint8Array[] = []\n let size = 0\n return {\n data: chunk => {\n if (!admitted) admit()\n size += chunk.byteLength\n for (const rule of rules) {\n if (size > rule.maxSize) {\n throw new PayloadTooLargeException(\n `File in field ${JSON.stringify(truncate(name))} exceeds the maximum size of ${formatByteSize(rule.maxSize)}`,\n { field: name, maxSize: rule.maxSize },\n CLOSE,\n )\n }\n }\n chunks.push(chunk)\n },\n end: () => {\n if (!admitted) return\n const file = createFile(chunks, filename, type)\n const list = this.files[name]\n if (list === undefined) this.files[name] = [file]\n else list.push(file)\n this.list.push(file)\n this.entries.push([name, file])\n },\n }\n }\n\n /** Rules applying to a file of `field` (400 for an unexpected field), with count and type checks. */\n #admit(field: string, type: string): readonly FileRule[] {\n if (this.#policy.rules.length === 0) return []\n const rules: FileRule[] = []\n const named = this.#named.get(field)\n if (named !== undefined) rules.push(named)\n if (this.#any !== undefined) rules.push(this.#any)\n if (rules.length === 0) {\n const expected = [...this.#named.keys()]\n throw new BadRequestException(\n `Unexpected file field ${JSON.stringify(truncate(field))}`,\n issue(field, `Unexpected file field (expected ${expected.join(', ')})`),\n CLOSE,\n )\n }\n for (const rule of rules) {\n const count = (this.#counts.get(rule) ?? 0) + 1\n this.#counts.set(rule, count)\n if (count > rule.maxFiles) {\n const where = rule.field === undefined ? '' : ` in field ${JSON.stringify(truncate(rule.field))}`\n if (!rule.multiple) {\n throw new BadRequestException(`Expected a single file${where}`, issue(field, 'Expected a single file'), CLOSE)\n }\n throw new PayloadTooLargeException(\n `Too many files${where} (at most ${rule.maxFiles})`,\n { field, maxFiles: rule.maxFiles },\n CLOSE,\n )\n }\n if (rule.mimeTypes !== undefined && !matchesMediaType(type, rule.mimeTypes)) {\n throw new UnsupportedMediaTypeException(\n `Unsupported file type ${JSON.stringify(truncate(mediaTypeEssence(type)))} in field ${JSON.stringify(truncate(field))} (accepted: ${rule.mimeTypes.join(', ')})`,\n { field, type: mediaTypeEssence(type), accepted: rule.mimeTypes },\n CLOSE,\n )\n }\n }\n return rules\n }\n\n result(): MultipartResult {\n return { fields: this.fields, files: this.files, list: this.list, entries: this.entries }\n }\n}\n\n/**\n * Reads a multipart body from `stream` with `policy`. The stream is cancelled on error (the rest of\n * the body is discarded).\n *\n * @throws BadRequestException (400) for a malformed body, too many parts / files or an unexpected\n * file field; PayloadTooLargeException (413) for a file or field above its limit;\n * UnsupportedMediaTypeException (415) for a file of a refused type.\n */\nexport async function readMultipart(\n stream: ReadableStream<Uint8Array>,\n contentType: string,\n policy: MultipartPolicy,\n): Promise<MultipartResult> {\n const reader = stream.getReader()\n try {\n const collector = new Collector(policy)\n const parser = new MultipartParser(multipartBoundary(contentType), collector)\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n parser.write(value)\n }\n parser.end()\n return collector.result()\n } catch (error) {\n await reader.cancel(error).catch(() => undefined)\n throw error\n }\n}\n\n/** Parses a buffered multipart body (see {@link readMultipart}). */\nexport function parseMultipart(bytes: Uint8Array, contentType: string, policy: MultipartPolicy): MultipartResult {\n const collector = new Collector(policy)\n const parser = new MultipartParser(multipartBoundary(contentType), collector)\n parser.write(bytes)\n parser.end()\n return collector.result()\n}\n\n/** Converts a parse result to a `FormData` (entries in body order). */\nexport function toFormData(result: MultipartResult): FormData {\n const form = new FormData()\n for (const [name, value] of result.entries) form.append(name, value)\n return form\n}\n\nfunction malformed(reason: string): BadRequestException {\n return new BadRequestException(`Invalid multipart body: ${reason}`, undefined, CLOSE)\n}\n\nfunction truncate(value: string): string {\n return value.length > 100 ? `${value.slice(0, 100)}…` : value\n}\n","import { emptyRecord } from './utils.ts'\n\n/** Parsed query string (or `application/x-www-form-urlencoded` body): repeated keys become arrays. */\nexport type QueryRecord = Record<string, string | string[]>\n\n/**\n * Parses a query string (with or without the leading `?`) with `URLSearchParams` semantics (`+` is\n * a space, malformed `%` sequences are kept as is, invalid UTF-8 becomes U+FFFD). A key present\n * once maps to a string, a repeated key to an array of strings, in order. No nesting (`a[b]=1` is\n * the key `a[b]`). The returned object has no prototype.\n *\n * `parseQuery('?tag=a&tag=b&page=2')` → `{ tag: ['a', 'b'], page: '2' }`\n */\nexport function parseQuery(query: string): QueryRecord {\n const result = emptyRecord<string | string[]>()\n if (query === '' || query === '?') return result\n for (const [key, value] of new URLSearchParams(query)) {\n const existing = result[key]\n if (existing === undefined) result[key] = value\n else if (typeof existing === 'string') result[key] = [existing, value]\n else existing.push(value)\n }\n return result\n}\n\n/** A request target split into its raw path and raw query string (without `?`). */\nexport interface RequestTarget {\n readonly path: string\n readonly query: string\n}\n\n/** Splits a request target (`/users?page=2`) into its raw path and raw query (without `?`). */\nexport function splitUrl(url: string): RequestTarget {\n const index = url.indexOf('?')\n return index === -1 ? { path: url, query: '' } : { path: url.slice(0, index), query: url.slice(index + 1) }\n}\n","import { BadRequestException, UnsupportedMediaTypeException } from './exceptions.ts'\nimport { parseMultipart, toFormData } from './multipart.ts'\nimport { parseQuery } from './query.ts'\nimport { errorMessage } from './utils.ts'\n\n/** The part of `TextDecoder` used here (the global type is not declared without the DOM lib). */\ninterface Decoder {\n readonly encoding: string\n decode(input: Uint8Array): string\n}\n\nconst UTF8: Decoder = new TextDecoder('utf-8', { fatal: true })\n\n/** A parsed `content-type` header. */\nexport interface MediaType {\n /** Lower-case `type/subtype` without parameters. */\n readonly type: string\n /** Lower-case `charset` parameter, when present. */\n readonly charset: string | undefined\n}\n\n/**\n * Parsed `content-type` values: an application receives a handful of them, parsed twice per request\n * with a body (request context, then {@link parseBody}). Bounded, since clients choose the values:\n * cleared when full.\n */\nconst MEDIA_TYPES = new Map<string, MediaType>()\nconst MEDIA_TYPES_MAX = 64\n\n/** Parses a `content-type` header value (`application/json; charset=utf-8`). */\nexport function parseMediaType(header: string | undefined): MediaType | undefined {\n if (header === undefined) return undefined\n // the most common value, compared faster than hashed\n if (header === 'application/json') return { type: 'application/json', charset: undefined }\n const cached = MEDIA_TYPES.get(header)\n // a fresh object, as when parsing (callers own the result)\n if (cached !== undefined) return { type: cached.type, charset: cached.charset }\n const media = parseUncached(header)\n if (media === undefined) return undefined\n if (MEDIA_TYPES.size === MEDIA_TYPES_MAX) MEDIA_TYPES.clear()\n MEDIA_TYPES.set(header, media)\n return { type: media.type, charset: media.charset }\n}\n\nfunction parseUncached(header: string): MediaType | undefined {\n const separator = header.indexOf(';')\n const type = (separator === -1 ? header : header.slice(0, separator)).trim().toLowerCase()\n if (type === '') return undefined\n let charset: string | undefined\n if (separator !== -1) {\n for (const parameter of header.slice(separator + 1).split(';')) {\n const equals = parameter.indexOf('=')\n if (equals === -1) continue\n if (parameter.slice(0, equals).trim().toLowerCase() !== 'charset') continue\n charset = parameter\n .slice(equals + 1)\n .trim()\n .replace(/^\"|\"$/g, '')\n .toLowerCase()\n }\n }\n return { type, charset }\n}\n\n/** Whether `type` is a JSON media type (`application/json`, `application/problem+json`...). */\nexport function isJsonType(type: string): boolean {\n return type === 'application/json' || type.endsWith('+json')\n}\n\n/** Rejects a `content-encoding` other than `identity` with 415 (decompression is not supported). */\nexport function checkContentEncoding(contentEncoding: string | undefined): void {\n if (contentEncoding === undefined) return\n const encoding = contentEncoding.trim().toLowerCase()\n if (encoding !== '' && encoding !== 'identity') {\n throw new UnsupportedMediaTypeException(`Unsupported content encoding \"${encoding}\"`)\n }\n}\n\n/**\n * Whether request headers announce a body (RFC 9112 §6.3: `transfer-encoding`, or a non-zero\n * `content-length`).\n */\nexport function hasBody(headers: Readonly<Record<string, string | undefined>>): boolean {\n if (headers['transfer-encoding'] !== undefined) return true\n const length = headers['content-length']\n return length !== undefined && length.trim() !== '0' && length.trim() !== ''\n}\n\n/**\n * Parses a buffered request body according to its `content-type` (low-level helper; the request\n * context parses bodies itself, multipart bodies as they arrive):\n *\n * | Content type | Result |\n * | ------------------------------------- | ------------------------------------ |\n * | empty body | `undefined` |\n * | `application/json`, `*\\/*+json` | parsed JSON (400 when malformed) |\n * | `text/*` | string (charset honoured) |\n * | `application/x-www-form-urlencoded` | record (repeated keys → arrays) |\n * | `multipart/form-data` | `FormData` (every field and file) |\n * | anything else, or no content type | `Uint8Array` |\n *\n * A `content-encoding` other than `identity` is rejected with 415 (decompression is not supported).\n */\nexport function parseBody(\n bytes: Uint8Array,\n contentType: string | undefined,\n contentEncoding?: string | undefined,\n): Promise<unknown> {\n try {\n return Promise.resolve(parseBodyBytes(bytes, contentType, contentEncoding))\n } catch (error) {\n return Promise.reject(error)\n }\n}\n\n/**\n * {@link parseBody} without the promise: returns the parsed body or throws its `HttpException`\n * (internal: the request context parses the buffered body with it, without an extra microtask).\n */\nexport function parseBodyBytes(\n bytes: Uint8Array,\n contentType: string | undefined,\n contentEncoding: string | undefined,\n): unknown {\n if (bytes.byteLength === 0) return undefined\n checkContentEncoding(contentEncoding)\n const media = parseMediaType(contentType)\n if (media === undefined) return bytes\n if (isJsonType(media.type)) {\n if (media.charset !== undefined && media.charset !== 'utf-8' && media.charset !== 'utf8') {\n throw new UnsupportedMediaTypeException(`Unsupported charset \"${media.charset}\" for JSON (use utf-8)`)\n }\n const text = decode(bytes, UTF8, 'JSON')\n try {\n return JSON.parse(text)\n } catch (error) {\n throw new BadRequestException(`Invalid JSON body: ${errorMessage(error)}`)\n }\n }\n if (media.type.startsWith('text/')) return decode(bytes, decoderFor(media.charset), 'text')\n if (media.type === 'application/x-www-form-urlencoded') return parseQuery(decode(bytes, UTF8, 'form'))\n if (media.type === 'multipart/form-data') {\n const policy = { rules: [], maxParts: Number.POSITIVE_INFINITY, maxFieldSize: Number.POSITIVE_INFINITY }\n return toFormData(parseMultipart(bytes, contentType as string, policy))\n }\n return bytes\n}\n\nfunction decoderFor(charset: string | undefined): Decoder {\n if (charset === undefined || charset === 'utf-8' || charset === 'utf8') return UTF8\n try {\n return new TextDecoder(charset as 'utf-8', { fatal: true })\n } catch {\n throw new UnsupportedMediaTypeException(`Unsupported charset \"${charset}\"`)\n }\n}\n\nfunction decode(bytes: Uint8Array, decoder: Decoder, what: string): string {\n try {\n return decoder.decode(bytes)\n } catch {\n throw new BadRequestException(`Invalid ${what} body: malformed ${decoder.encoding} data`)\n }\n}\n","import { BadRequestException } from './exceptions.ts'\n\n/**\n * Converts a raw request value (route parameter, query value, header) to `T`, or throws a\n * `400 Bad Request` naming `label` (`param \"id\"`, `query \"page\"`, `header \"x-limit\"`).\n * Called by the compiler-generated `invoke` functions.\n */\nexport type Coercer<T> = (value: unknown, label: string) => T\n\n/** The coercion helpers called by generated code (see the \"Compiler contract\" of the README). */\nexport interface Coercers {\n /** A string. Rejects missing values and repeated query values. */\n readonly string: Coercer<string>\n /** A finite decimal number (`12`, `-1.5`, `1e3`). Rejects `''`, hex, `NaN`, `Infinity`. */\n readonly number: Coercer<number>\n /** A safe integer (`42`, `-7`). */\n readonly integer: Coercer<number>\n /** `true`/`1` → `true`, `false`/`0` → `false` (case-insensitive). */\n readonly boolean: Coercer<boolean>\n /** A bigint (`123`, `-9007199254740993`). */\n readonly bigint: Coercer<bigint>\n /**\n * A `Date` from an ISO 8601 date (`2024-01-02`, UTC midnight), an ISO 8601 date-time with an\n * offset (`2024-01-02T03:04:05Z`, `2024-01-02T03:04+02:00`) or a millisecond timestamp.\n */\n readonly date: Coercer<Date>\n /** One of `values` (string or number literals, compared after coercion). */\n enum<const T extends readonly (string | number | boolean)[]>(value: unknown, label: string, values: T): T[number]\n /** An array: a single value becomes a one-element array, each item is coerced with `item`. */\n array<T>(value: unknown, label: string, item: Coercer<T>): T[]\n /** `undefined` when the value is missing, otherwise `item(value, label)`. */\n optional<T>(value: unknown, label: string, item: Coercer<T>): T | undefined\n}\n\n// unambiguous (`\\d+` and the fraction never compete for the same digits): linear time on any input\nconst NUMBER = /^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?$/\nconst INTEGER = /^[+-]?\\d+$/\n/** ISO 8601 calendar date, optionally with a time and an offset (`Z`, `+02:00`, `+0200`). */\nconst ISO_DATE =\n /^(\\d{4})-(\\d{2})-(\\d{2})(?:[Tt ](\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{1,9}))?)?(?:([Zz])|([+-])(\\d{2}):?(\\d{2}))?)?$/\n\nfunction invalid(label: string, expected: string, value: unknown): BadRequestException {\n // cookies often carry tokens: their values are never echoed\n if (label.startsWith('cookie ')) return new BadRequestException(`Invalid ${label}: expected ${expected}`)\n return new BadRequestException(`Invalid ${label}: expected ${expected}, received ${describe(value)}`)\n}\n\nfunction describe(value: unknown): string {\n if (typeof value === 'string') return JSON.stringify(value.length > 64 ? `${value.slice(0, 64)}…` : value)\n if (Array.isArray(value)) return `${value.length} values`\n return typeof value\n}\n\n/** The single raw string of a value, or a 400 (missing / repeated / not a string). */\nfunction single(value: unknown, label: string): string {\n if (typeof value === 'string') return value\n if (value === undefined || value === null) throw new BadRequestException(`Missing ${label}`)\n if (Array.isArray(value))\n throw new BadRequestException(`Invalid ${label}: expected a single value, received ${value.length}`)\n throw invalid(label, 'a string', value)\n}\n\n/** Longest run of decimal digits whose value is exact without parsing (`999999999999999` < 2^53). */\nconst MAX_FAST_DIGITS = 15\n\n/**\n * The value of `text` when it is 1 to 15 ASCII decimal digits (the common `/users/42`), `-1`\n * otherwise. The same number as `Number(text)` for such a string, without the regular expression,\n * the trim and the parse of the general path.\n */\nfunction digitsValue(text: string): number {\n const length = text.length\n if (length === 0 || length > MAX_FAST_DIGITS) return -1\n let result = 0\n for (let index = 0; index < length; index++) {\n const digit = text.charCodeAt(index) - 48\n if (digit < 0 || digit > 9) return -1\n result = result * 10 + digit\n }\n return result\n}\n\nfunction toNumber(value: unknown, label: string): number {\n if (typeof value === 'string') {\n const digits = digitsValue(value)\n if (digits !== -1) return digits\n }\n const raw = single(value, label)\n const text = raw.trim()\n if (NUMBER.test(text)) {\n const result = Number(text)\n if (Number.isFinite(result)) return result\n }\n throw invalid(label, 'a number', raw)\n}\n\nfunction toInteger(value: unknown, label: string): number {\n if (typeof value === 'string') {\n const digits = digitsValue(value)\n if (digits !== -1) return digits\n }\n const raw = single(value, label)\n const text = raw.trim()\n if (INTEGER.test(text)) {\n const result = Number(text)\n if (Number.isSafeInteger(result)) return result\n }\n throw invalid(label, 'an integer', raw)\n}\n\nfunction toBoolean(value: unknown, label: string): boolean {\n // the canonical spellings, without the trim and the lower-casing of the general path\n if (value === 'true' || value === '1') return true\n if (value === 'false' || value === '0') return false\n const raw = single(value, label)\n switch (raw.trim().toLowerCase()) {\n case 'true':\n case '1':\n return true\n case 'false':\n case '0':\n return false\n default:\n throw invalid(label, 'a boolean (true, false, 1 or 0)', raw)\n }\n}\n\nfunction toBigint(value: unknown, label: string): bigint {\n const raw = single(value, label)\n const text = raw.trim()\n if (INTEGER.test(text)) return BigInt(text)\n throw invalid(label, 'an integer', raw)\n}\n\nfunction toDate(value: unknown, label: string): Date {\n const raw = single(value, label)\n const text = raw.trim()\n const date = INTEGER.test(text) ? new Date(Number(text)) : parseIsoDate(text)\n if (date === undefined || Number.isNaN(date.getTime())) {\n throw invalid(label, 'a date (ISO 8601 such as 2024-01-02 or 2024-01-02T10:00:00Z, or a timestamp)', raw)\n }\n return date\n}\n\nconst DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n\n/**\n * Parses an ISO 8601 date or date-time (see `Coercers.date`), `undefined` otherwise. Nothing else is\n * handed to the engine's lenient `Date` parser (`foo 2024`, `March 7`), impossible dates\n * (`2024-02-30`) are rejected instead of rolled over, and a date-time without offset is rejected\n * rather than read in the server's time zone.\n */\nfunction parseIsoDate(text: string): Date | undefined {\n const match = ISO_DATE.exec(text)\n if (match === null) return undefined\n const [, y, mo, d, h, mi, s, fraction, zulu, sign, oh, om] = match\n const year = Number(y)\n const month = Number(mo)\n const day = Number(d)\n const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)\n const days = month === 2 && leap ? 29 : DAYS_IN_MONTH[month - 1]\n if (days === undefined || day < 1 || day > days) return undefined\n const date = new Date(0)\n date.setUTCFullYear(year, month - 1, day) // years 0-99 are not shifted to 1900-1999 (Date.UTC)\n if (h === undefined) return date\n if (zulu === undefined && sign === undefined) return undefined\n const hours = Number(h)\n const minutes = Number(mi)\n const seconds = s === undefined ? 0 : Number(s)\n const offset = sign === undefined ? 0 : (sign === '-' ? -1 : 1) * (Number(oh) * 60 + Number(om))\n if (hours > 23 || minutes > 59 || seconds > 59 || Math.abs(offset) >= 24 * 60 || Number(om ?? 0) > 59) {\n return undefined\n }\n const milliseconds = fraction === undefined ? 0 : Number(fraction.slice(0, 3).padEnd(3, '0'))\n date.setUTCHours(hours, minutes - offset, seconds, milliseconds)\n return date\n}\n\nfunction toEnum<const T extends readonly (string | number | boolean)[]>(\n value: unknown,\n label: string,\n values: T,\n): T[number] {\n const raw = single(value, label)\n for (const candidate of values) {\n if (typeof candidate === 'string' ? candidate === raw : String(candidate) === raw.trim()) return candidate\n }\n throw invalid(label, `one of ${values.map(candidate => JSON.stringify(candidate)).join(', ')}`, raw)\n}\n\nfunction toArray<T>(value: unknown, label: string, item: Coercer<T>): T[] {\n if (value === undefined || value === null) throw new BadRequestException(`Missing ${label}`)\n if (!Array.isArray(value)) return [item(value, label)]\n const result = new Array<T>(value.length)\n for (let index = 0; index < value.length; index++) result[index] = item(value[index], `${label}[${index}]`)\n return result\n}\n\nfunction toOptional<T>(value: unknown, label: string, item: Coercer<T>): T | undefined {\n return value === undefined || value === null ? undefined : item(value, label)\n}\n\n/**\n * Coercion helpers used by generated `invoke` functions for typed parameters without schema:\n *\n * ```ts\n * invoke: (c, ctx) => c.list(\n * coerce.number(ctx.params['id'], 'param \"id\"'),\n * coerce.optional(ctx.query['page'], 'query \"page\"', coerce.integer),\n * coerce.array(ctx.query['tag'], 'query \"tag\"', coerce.string),\n * )\n * ```\n *\n * Every failure is a `BadRequestException` (400) whose message names the input.\n */\nexport const coerce: Coercers = Object.freeze({\n string: single,\n number: toNumber,\n integer: toInteger,\n boolean: toBoolean,\n bigint: toBigint,\n date: toDate,\n enum: toEnum,\n array: toArray,\n optional: toOptional,\n})\n","/** Cookie settings of a plugin (defaults and signing key) and the operations using them (internal). */\nimport type { CookieSigner } from './cookie-signer.ts'\n\nimport {\n type CookieDefaults,\n DEFAULT_COOKIE_OPTIONS,\n decodeCookieValue,\n encodeCookieValue,\n type ResponseCookie,\n type SerializedCookie,\n serializeResponseCookie,\n} from './cookies.ts'\n\n/** The resolved plugin option `cookies`. */\nexport interface CookieSettings {\n /** Secure defaults merged with `cookies.defaults`. */\n readonly defaults: CookieDefaults\n /** `undefined` without `cookies.secrets` (signed cookies unavailable). */\n readonly signer: CookieSigner | undefined\n}\n\n/** Settings without plugin options: the secure defaults, no signing. */\nexport const DEFAULT_COOKIE_SETTINGS: CookieSettings = Object.freeze({\n defaults: DEFAULT_COOKIE_OPTIONS,\n signer: undefined,\n})\n\n/** The error of a signed cookie used without `cookies.secrets`. */\nexport function missingSecrets(action: string): Error {\n return new Error(\n `${action}: the HttpPlugin option cookies.secrets is not set (HttpPlugin.configure({ cookies: { secrets: [...] } }))`,\n )\n}\n\n/** Serialises a response cookie with the plugin settings (`signed: true` signs with the first secret). */\nexport function serializeWith(cookie: ResponseCookie, settings: CookieSettings): SerializedCookie {\n const signer = settings.signer\n if (cookie.value !== undefined && cookie.options.signed === true && signer === undefined) {\n throw missingSecrets(`Cannot sign the cookie \"${cookie.name}\"`)\n }\n return serializeResponseCookie(cookie, settings.defaults, (name, encoded) =>\n (signer as CookieSigner).sign(name, encoded),\n )\n}\n\n/**\n * The verified value of a signed request cookie (`value` as parsed, i.e. decoded), `undefined` when\n * absent, tampered or signed with an unknown key. The value is re-encoded canonically before the\n * MAC is checked (`encode(decode(w)) === w` for every value Znight signs).\n */\nexport function verifySigned(signer: CookieSigner, name: string, value: string | undefined): string | undefined {\n if (value === undefined) return undefined\n const dot = value.lastIndexOf('.')\n if (dot === -1) return undefined\n let encoded: string\n try {\n encoded = encodeCookieValue(value.slice(0, dot))\n } catch {\n return undefined\n }\n const verified = signer.verify(name, `${encoded}${value.slice(dot)}`)\n return verified === undefined ? undefined : decodeCookieValue(verified)\n}\n\n/** The signed wire value of `value` (encoded, then signed): what a client sends back. */\nexport function signValue(signer: CookieSigner, name: string, value: string): string {\n return signer.sign(name, encodeCookieValue(value))\n}\n","import type { Token } from '@znight/core'\nimport type { AdapterRequest } from './adapter.ts'\nimport type { CookieSettings } from './cookie-settings.ts'\nimport type { ClearCookieOptions, CookieOptions, ResponseCookie, SerializedCookie } from './cookies.ts'\nimport type { HeaderValue } from './exceptions.ts'\nimport type { MultipartResult } from './multipart.ts'\nimport type { BodyPlan } from './uploads.ts'\n\nimport { checkContentEncoding, hasBody, parseBodyBytes, parseMediaType } from './body.ts'\nimport { DEFAULT_COOKIE_SETTINGS, missingSecrets, serializeWith, verifySigned } from './cookie-settings.ts'\nimport { parseCookieHeader } from './cookies.ts'\nimport { UnsupportedMediaTypeException } from './exceptions.ts'\nimport { parseMultipart, readMultipart } from './multipart.ts'\nimport { parseQuery, type QueryRecord, type RequestTarget, splitUrl } from './query.ts'\nimport { emptyRecord } from './utils.ts'\n\ndeclare const requestIdBrand: unique symbol\n\n/** Why `ctx.signal` aborted: the client left, the server shuts down, or an SSE stream reached its `maxDuration`. */\nexport type RequestAbortKind = 'client' | 'shutdown' | 'expired'\n\n/**\n * The reason of an aborted `ctx.signal`. Named `AbortError`, what `fetch`, `node:timers/promises`\n * and most libraries check.\n */\nexport class RequestAbortedError extends Error {\n override readonly name = 'AbortError'\n /** `client`: disconnected; `shutdown`: the server stops; `expired`: an SSE stream reached its `maxDuration`. */\n readonly kind: RequestAbortKind\n\n constructor(kind: RequestAbortKind) {\n super(ABORT_MESSAGES[kind])\n this.kind = kind\n }\n}\n\nconst ABORT_MESSAGES: Readonly<Record<RequestAbortKind, string>> = {\n client: 'The client disconnected',\n shutdown: 'The server is shutting down',\n expired: 'The event stream reached its maxDuration',\n}\n\n/**\n * Identifier of the current request: the incoming `x-request-id` header (see the plugin option\n * `requestIdHeader`) or a generated UUID. Injectable in request-scoped providers.\n */\nexport type RequestId = string & { readonly [requestIdBrand]: true }\n\n/** The route that matched a request. */\nexport interface HttpRouteInfo {\n /** Route method (`GET`...; the concrete method for `@All` routes). */\n readonly method: string\n /** Route pattern including the plugin prefix (`/api/users/:id`). */\n readonly path: string\n /** Controller provider token. */\n readonly controller: Token\n /** Handler method name. */\n readonly handler: string\n /**\n * Effective route metadata (`createRouteDecorator`): the controller's entries, except those of a\n * group the route decides itself, then the route's entries (the nearest decision wins).\n */\n readonly meta: Readonly<Record<string, unknown>>\n}\n\n/**\n * Adapter-neutral view of the current HTTP request, shared by guards, interceptors, exception\n * mappers and handlers (`@Ctx()`), and injectable in request-scoped providers.\n */\nexport interface HttpContext {\n readonly requestId: RequestId\n /** Upper-case method. */\n readonly method: string\n /** Raw request target (`/users/a%20b?page=2`). */\n readonly url: string\n /** Raw path, without query string (`/users/a%20b`). */\n readonly path: string\n /** Decoded route parameters (`*` holds the part matched by a trailing wildcard). */\n readonly params: Readonly<Record<string, string>>\n /** Decoded query string (repeated keys → arrays), parsed on first access. */\n readonly query: Readonly<QueryRecord>\n /** Request headers, lower-case names. */\n readonly headers: Readonly<Record<string, string | undefined>>\n /**\n * Parsed body. Populated before the interceptors for routes declaring `@Body()` or upload\n * parameters (and after {@link parseBody} resolved otherwise); `undefined` until then and for\n * empty bodies. Forms (urlencoded and multipart) are records of their text fields.\n */\n readonly body: unknown\n /**\n * Files of a `multipart/form-data` body by field name, in body order (standard `File` objects,\n * held in memory). Populated with {@link body}; empty for other bodies.\n */\n readonly files: Readonly<Record<string, readonly File[]>>\n /** The matched route, `undefined` for unmatched requests (404/405). */\n readonly route: HttpRouteInfo | undefined\n /** Per-request storage for guards, interceptors and handlers (`ctx.state.set('user', user)`). */\n readonly state: Map<string | symbol, unknown>\n /** Native request of the adapter (`IncomingMessage`, `FastifyRequest`, Express `Request`, Web `Request`). */\n readonly request: unknown\n /** Native response of the adapter (`ServerResponse`, `FastifyReply`, Express `Response`, Hono `Context`). */\n readonly response: unknown\n /** Adapter name (`node`, `fastify`, `express`, `hono`). */\n readonly adapter: string\n /**\n * Client address, when the adapter knows it. With the plugin option `trustProxy`, the address\n * found in `x-forwarded-for` behind the trusted proxies; otherwise the adapter's address (the\n * socket peer, or what Fastify / Express derive from their own proxy settings).\n */\n readonly ip: string | undefined\n /**\n * `https` when the connection uses TLS, or, behind a trusted proxy (`trustProxy`), when the\n * leftmost `x-forwarded-proto` says so; `http` otherwise.\n */\n readonly protocol: 'http' | 'https'\n /** Headers added to the response, whatever its outcome (errors included). */\n readonly responseHeaders: Readonly<Record<string, HeaderValue>>\n /** A request header (case-insensitive name). */\n header(name: string): string | undefined\n /** Sets a response header (case-insensitive name), sent with success and error responses. */\n setHeader(name: string, value: HeaderValue): void\n /** Appends a response header value (`set-cookie`...). */\n appendHeader(name: string, value: string): void\n /**\n * Request cookies (`cookie` header), parsed on first access: decoded values, the first occurrence\n * of a name wins. A prototype-less, frozen record.\n */\n readonly cookies: Readonly<Record<string, string>>\n /**\n * The verified value of a signed cookie (`@SignedCookie`), `undefined` when it is absent, tampered\n * or signed with a key that is no longer in `cookies.secrets`. Verified once per name.\n *\n * @throws Error when the plugin option `cookies.secrets` is not set.\n */\n signedCookie(name: string): string | undefined\n /**\n * Sets a cookie on the response, whatever its outcome (errors, redirects included), with the\n * secure defaults (`Path=/; Secure; HttpOnly; SameSite=Lax`, see the plugin option\n * `cookies.defaults`). A later cookie with the same name, domain and path replaces this one; a\n * cookie of the same key in an `HttpResponse` (`withCookie`) wins over it. Everything is validated\n * now (name, value, attributes, prefixes, size), so the stack trace points to the faulty call.\n *\n * @throws TypeError / RangeError for an invalid cookie; Error once the response headers were sent\n * (a running event stream).\n */\n setCookie(name: string, value: string, options?: CookieOptions): void\n /**\n * Clears a cookie (`Max-Age=0`, with the same domain and path, and the defaults: a `__Host-`\n * cookie is cleared with valid attributes).\n *\n * @throws like {@link setCookie}.\n */\n clearCookie(name: string, options?: ClearCookieOptions): void\n /** Cookies set on this response so far (`setCookie` / `clearCookie`), in order. */\n readonly responseCookies: readonly ResponseCookie[]\n /**\n * Aborted when the client disconnects before the response was written, when the response body is\n * cancelled, or when the server closes an event stream (shutdown, `maxDuration`); never after a\n * normal completion. The reason is a {@link RequestAbortedError}. Pass it to the work the request\n * starts (`fetch(url, { signal: ctx.signal })`, `setTimeout(ms, v, { signal })`). Created on first\n * access.\n */\n readonly signal: AbortSignal\n /**\n * Reads and parses the body (once): JSON (`application/json`, `+json`), text (`text/*`), forms\n * (`application/x-www-form-urlencoded` and `multipart/form-data` → record of the text fields,\n * repeated names as arrays; files in {@link files}), raw bytes otherwise; `undefined` when empty.\n * Fails with 400 (malformed), 413 (body or upload limits) or 415 (unsupported encoding, refused\n * file type, non-multipart body on an upload route).\n */\n parseBody(): Promise<unknown>\n /** The raw body bytes (once; shared with {@link parseBody}), e.g. to check a webhook signature. */\n rawBody(): Promise<Uint8Array>\n /**\n * The request body as a Web stream, read as it arrives (nothing is buffered): the escape hatch\n * for large uploads (`PUT /files/:name` piped to disk or object storage). The body limit of the\n * route still applies (`@BodyLimit`, `Infinity` to disable): past it the stream errors with a\n * `PayloadTooLargeException` (413). Exclusive with {@link rawBody} / {@link parseBody}: throws when\n * the body was already read (routes with `@Body()` or upload parameters read it before the\n * handler).\n */\n bodyStream(): ReadableStream<Uint8Array>\n}\n\n/** What {@link RequestContext.of} needs to create a context. */\nexport interface RequestContextInit {\n readonly requestId: RequestId\n readonly adapter: string\n /** `source.url` split (default: split here). */\n readonly url?: RequestTarget\n readonly route: HttpRouteInfo | undefined\n readonly params: Readonly<Record<string, string>>\n readonly body: BodyPlan\n /** Client address and protocol (`trustProxy`); default: the adapter's `ip` and `encrypted`. */\n readonly client?: RequestClient | undefined\n /** Cookie defaults and signing key (plugin option `cookies`); default: secure defaults, no signing. */\n readonly cookies?: CookieSettings\n}\n\n/** The client of a request behind trusted proxies (`trustProxy`). */\nexport interface RequestClient {\n readonly ip: string | undefined\n readonly protocol: 'http' | 'https'\n}\n\n/**\n * The state of a request context that most requests never need (parsed query, `ctx.state`, body,\n * request cookies, abort signal), created on first use: a context is created for every request.\n */\nclass ContextState {\n query: QueryRecord | undefined = undefined\n state: Map<string | symbol, unknown> | undefined = undefined\n body: unknown = undefined\n files: Readonly<Record<string, readonly File[]>> | undefined = undefined\n raw: Promise<Uint8Array> | undefined = undefined\n streamed = false\n /** Stops the body stream opened for the request, unless it was read to its end or cancelled. */\n stopBody: (() => void) | undefined = undefined\n parsed: Promise<unknown> | undefined = undefined\n cookies: Readonly<Record<string, string>> | undefined = undefined\n signed: Map<string, string | undefined> | undefined = undefined\n abortReason: RequestAbortedError | undefined = undefined\n abortController: AbortController | undefined = undefined\n}\n\n/** Implementation of {@link HttpContext} used by the pipeline (internal). */\nexport class RequestContext implements HttpContext {\n readonly requestId: RequestId\n readonly method: string\n readonly url: string\n readonly path: string\n readonly params: Readonly<Record<string, string>>\n readonly headers: Readonly<Record<string, string | undefined>>\n readonly route: HttpRouteInfo | undefined\n readonly request: unknown\n readonly response: unknown\n readonly adapter: string\n readonly ip: string | undefined\n readonly protocol: 'http' | 'https'\n readonly #source: AdapterRequest\n readonly #plan: BodyPlan\n readonly #rawQuery: string\n readonly #cookieSettings: CookieSettings\n #responseHeaders: Record<string, HeaderValue> | undefined = undefined\n /** Cookies set on the response, by key (name, domain, path), with their `Set-Cookie` line. */\n #jar: Map<string, { readonly cookie: ResponseCookie; readonly line: string }> | undefined = undefined\n /** The response headers were handed to the adapter (cookies can no longer be set). */\n #committed = false\n /** The request is over: later aborts are ignored. */\n #completed = false\n #more: ContextState | undefined = undefined\n\n /** `path` and `query`: `source.url` split; `client`: see {@link RequestContextInit.client}. */\n constructor(\n source: AdapterRequest,\n requestId: RequestId,\n adapter: string,\n path: string,\n query: string,\n route: HttpRouteInfo | undefined,\n params: Readonly<Record<string, string>>,\n body: BodyPlan,\n cookies: CookieSettings,\n client: RequestClient | undefined,\n ) {\n this.#source = source\n this.#plan = body\n this.#cookieSettings = cookies\n this.#rawQuery = query\n this.requestId = requestId\n this.method = source.method\n this.url = source.url\n this.path = path\n this.params = params\n this.headers = source.headers\n this.route = route\n this.request = source.raw\n this.response = source.rawResponse\n this.adapter = adapter\n if (client === undefined) {\n this.ip = source.ip\n this.protocol = source.encrypted === true ? 'https' : 'http'\n } else {\n this.ip = client.ip\n this.protocol = client.protocol\n }\n }\n\n /** A context from named settings (defaults: `source.url` split, secure cookie defaults, the adapter's client). */\n static of(source: AdapterRequest, init: RequestContextInit): RequestContext {\n const { path, query } = init.url ?? splitUrl(source.url)\n return new RequestContext(\n source,\n init.requestId,\n init.adapter,\n path,\n query,\n init.route,\n init.params,\n init.body,\n init.cookies ?? DEFAULT_COOKIE_SETTINGS,\n init.client,\n )\n }\n\n /** The state created on first use. */\n get #extra(): ContextState {\n this.#more ??= new ContextState()\n return this.#more\n }\n\n get query(): Readonly<QueryRecord> {\n const state = this.#extra\n state.query ??= parseQuery(this.#rawQuery)\n return state.query\n }\n\n get state(): Map<string | symbol, unknown> {\n const state = this.#extra\n state.state ??= new Map()\n return state.state\n }\n\n get body(): unknown {\n return this.#more?.body\n }\n\n get files(): Readonly<Record<string, readonly File[]>> {\n return this.#more?.files ?? NO_FILES\n }\n\n /** Maximum body size of the route, in bytes. */\n get bodyLimit(): number {\n return this.#plan.limit\n }\n\n get responseHeaders(): Readonly<Record<string, HeaderValue>> {\n return this.#responseHeaders ?? EMPTY_HEADERS\n }\n\n /** Whether {@link setHeader}/{@link appendHeader} were called. */\n get hasResponseHeaders(): boolean {\n return this.#responseHeaders !== undefined\n }\n\n header(name: string): string | undefined {\n return this.headers[name.toLowerCase()]\n }\n\n setHeader(name: string, value: HeaderValue): void {\n this.#responseHeaders ??= emptyRecord()\n this.#responseHeaders[name.toLowerCase()] = typeof value === 'string' ? value : [...value]\n }\n\n appendHeader(name: string, value: string): void {\n this.#responseHeaders ??= emptyRecord()\n const key = name.toLowerCase()\n const existing = this.#responseHeaders[key]\n if (existing === undefined) this.#responseHeaders[key] = value\n else this.#responseHeaders[key] = typeof existing === 'string' ? [existing, value] : [...existing, value]\n }\n\n get cookies(): Readonly<Record<string, string>> {\n const state = this.#extra\n state.cookies ??= parseCookieHeader(this.headers['cookie'])\n return state.cookies\n }\n\n signedCookie(name: string): string | undefined {\n const signer = this.#cookieSettings.signer\n if (signer === undefined) throw missingSecrets(`Cannot read the signed cookie ${JSON.stringify(String(name))}`)\n const state = this.#extra\n state.signed ??= new Map()\n if (state.signed.has(name)) return state.signed.get(name)\n const value = verifySigned(signer, name, this.cookies[name])\n state.signed.set(name, value)\n return value\n }\n\n setCookie(name: string, value: string, options: CookieOptions = {}): void {\n this.#addCookie({ name, value, options })\n }\n\n clearCookie(name: string, options: ClearCookieOptions = {}): void {\n this.#addCookie({ name, value: undefined, options })\n }\n\n get responseCookies(): readonly ResponseCookie[] {\n return this.#jar === undefined ? NO_COOKIES : [...this.#jar.values()].map(entry => entry.cookie)\n }\n\n /** Whether {@link setCookie} / {@link clearCookie} were called (internal). */\n get hasCookies(): boolean {\n return this.#jar !== undefined\n }\n\n /** The `Set-Cookie` lines of {@link setCookie} / {@link clearCookie}, with their keys, in order (internal). */\n get cookieLines(): readonly SerializedCookie[] {\n return this.#jar === undefined ? NO_LINES : [...this.#jar].map(([key, entry]) => ({ key, line: entry.line }))\n }\n\n #addCookie(cookie: ResponseCookie): void {\n if (this.#committed) {\n throw new Error(\n `Cannot set cookie ${JSON.stringify(String(cookie.name))}: the response headers were already sent`,\n )\n }\n if (cookie.options === null || typeof cookie.options !== 'object') {\n throw new TypeError(`Invalid cookie ${JSON.stringify(String(cookie.name))}: options must be an object`)\n }\n const options = cookie.value === undefined ? withoutLifetime(cookie.options) : cookie.options\n const frozen: ResponseCookie = Object.freeze({\n name: cookie.name,\n value: cookie.value,\n options: Object.freeze({ ...options }),\n })\n const { key, line } = serializeWith(frozen, this.#cookieSettings)\n this.#jar ??= new Map()\n this.#jar.set(key, { cookie: frozen, line })\n }\n\n get signal(): AbortSignal {\n const state = this.#extra\n if (state.abortController === undefined) {\n const controller = new AbortController()\n state.abortController = controller\n if (state.abortReason !== undefined) controller.abort(state.abortReason)\n else if (!this.#completed) this.#source.onAbort?.(() => this.abort('client'))\n }\n return state.abortController.signal\n }\n\n /** Whether {@link signal} aborted (or will be created aborted). */\n get aborted(): boolean {\n return this.#more?.abortReason !== undefined\n }\n\n /**\n * Aborts {@link signal} with a {@link RequestAbortedError} of `kind` (internal): at most once, and\n * never once the request is over ({@link complete}).\n */\n abort(kind: RequestAbortKind): void {\n if (this.#more?.abortReason !== undefined || this.#completed) return\n const reason = new RequestAbortedError(kind)\n const state = this.#extra\n state.abortReason = reason\n state.abortController?.abort(reason)\n }\n\n /** The response headers are handed to the adapter: cookies can no longer be set (internal). */\n commit(): void {\n this.#committed = true\n }\n\n /** The request is over (response sent or abandoned): later aborts are ignored (internal). */\n complete(): void {\n this.#completed = true\n }\n\n rawBody(): Promise<Uint8Array> {\n const state = this.#extra\n if (state.raw === undefined) {\n if (state.streamed) return Promise.reject(alreadyStreamed())\n state.raw = this.#source.readBody(this.#plan.limit)\n }\n return state.raw\n }\n\n bodyStream(): ReadableStream<Uint8Array> {\n const state = this.#extra\n if (state.raw !== undefined || state.streamed) throw alreadyStreamed()\n state.streamed = true\n return this.#openBodyStream()\n }\n\n /**\n * Called by the pipeline once the request is over: a body stream that was neither read to its\n * end nor cancelled (a handler that read the first chunk, then threw) is cancelled, which makes the\n * adapter discard the rest of the body, so that the connection can serve the next request.\n */\n releaseBody(): void {\n const state = this.#more\n if (state === undefined) return\n const stop = state.stopBody\n state.stopBody = undefined\n stop?.()\n }\n\n /** The body as a stream (see {@link releaseBody}). */\n #openBodyStream(): ReadableStream<Uint8Array> {\n const reader = openBodyStream(this.#source, this.#plan.limit).getReader()\n const state = this.#extra\n let controller: ReadableStreamDefaultController<Uint8Array> | undefined\n const settle = (): void => {\n state.stopBody = undefined\n }\n state.stopBody = (): void => {\n reader.cancel().catch(() => undefined)\n try {\n controller?.error(new Error('The request is over: its body can no longer be read'))\n } catch {\n // already closed or errored\n }\n }\n return new ReadableStream<Uint8Array>(\n {\n start(current) {\n controller = current\n },\n async pull(current) {\n let result: Awaited<ReturnType<typeof reader.read>>\n try {\n result = await reader.read()\n } catch (error) {\n settle()\n throw error\n }\n if (result.done) {\n settle()\n current.close()\n return\n }\n current.enqueue(result.value)\n },\n cancel(reason) {\n settle()\n return reader.cancel(reason)\n },\n },\n { highWaterMark: 0 },\n )\n }\n\n parseBody(): Promise<unknown> {\n const state = this.#extra\n state.parsed ??= this.#parse()\n return state.parsed\n }\n\n async #parse(): Promise<unknown> {\n const headers = this.headers\n const contentType = headers['content-type']\n const media = parseMediaType(contentType)\n const state = this.#extra\n if (media?.type === 'multipart/form-data') {\n checkContentEncoding(headers['content-encoding'])\n const policy = this.#plan.multipart\n let result: MultipartResult\n if (state.raw === undefined) {\n if (state.streamed) throw alreadyStreamed()\n state.streamed = true\n result = await readMultipart(this.#openBodyStream(), contentType as string, policy)\n } else {\n result = parseMultipart(await state.raw, contentType as string, policy)\n }\n state.files = result.files\n state.body = result.fields\n return result.fields\n }\n if (this.#plan.upload) {\n // upload routes only accept multipart bodies (an empty body means \"no file\"); the framing\n // headers decide, the adapter only for requests without them (Web `Request`s built in memory)\n const framed = headers['content-length'] !== undefined || headers['transfer-encoding'] !== undefined\n if (!(framed ? hasBody(headers) : this.#source.hasBody?.() === true)) return undefined\n throw new UnsupportedMediaTypeException(\n `Expected a multipart/form-data body${media === undefined ? '' : ` (received ${JSON.stringify(media.type)})`}`,\n )\n }\n const bytes = await this.rawBody()\n const body = parseBodyBytes(bytes, contentType, headers['content-encoding'])\n state.body = body\n return body\n }\n}\n\n/** The body as a stream: the adapter's `streamBody`, or the buffered body when it has none. */\nfunction openBodyStream(source: AdapterRequest, limit: number): ReadableStream<Uint8Array> {\n if (typeof source.streamBody === 'function') return source.streamBody(limit)\n return new ReadableStream<Uint8Array>(\n {\n async pull(controller) {\n const bytes = await source.readBody(limit)\n if (bytes.byteLength > 0) controller.enqueue(bytes)\n controller.close()\n },\n },\n { highWaterMark: 0 },\n )\n}\n\nfunction alreadyStreamed(): Error {\n return new Error(\n 'The request body was already read: bodyStream() cannot be combined with rawBody(), parseBody(), @Body() or upload parameters',\n )\n}\n\n/** Clearing cookies have no lifetime of their own (`Max-Age=0`) and are never signed. */\nfunction withoutLifetime(options: ClearCookieOptions): ClearCookieOptions {\n const { maxAge: _maxAge, expires: _expires, signed: _signed, ...rest } = options as CookieOptions\n return rest\n}\n\nconst EMPTY_HEADERS: Readonly<Record<string, HeaderValue>> = Object.freeze({})\nconst NO_COOKIES: readonly ResponseCookie[] = Object.freeze([])\nconst NO_LINES: readonly SerializedCookie[] = Object.freeze([])\nconst NO_FILES: Readonly<Record<string, readonly File[]>> = Object.freeze(emptyRecord<readonly File[]>())\n","/**\n * Marker decorators of `@znight/http`. Like every Znight decorator they do nothing at runtime: the\n * compiler extension `@znight/http/compiler` reads them from the source code and generates the\n * routes (`metadata.extensions.http`). Arguments marked _static_ must be statically evaluable\n * (literals, `const` references); _value_ arguments (schemas, guards...) may also be references to\n * exported bindings. See docs/internals/architecture.md §4.6 and §5.\n */\nimport type { ClassMarker, MethodMarker, ParameterMarker, Scope } from '@znight/core'\nimport type { HttpContext } from './context.ts'\nimport type { GuardClass, HttpInterceptorClass } from './interfaces.ts'\nimport type { ByteSize } from './size.ts'\nimport type { SseOptions } from './sse.ts'\nimport type { StandardSchemaV1 } from './standard-schema.ts'\nimport type { UploadedFileOptions, UploadedFilesOptions } from './uploads.ts'\n\nfunction marker(): void {\n // intentionally empty: decorators are compile-time markers\n}\n\nconst classMarker: ClassMarker = marker\nconst methodMarker: MethodMarker = marker\nconst parameterMarker: ParameterMarker = marker\nconst classOrMethodMarker: ClassMarker & MethodMarker = marker\n\n/** Options of {@link Controller} (static). */\nexport interface ControllerOptions {\n /** Base path of every route of the controller (`/users`). Default: `/`. */\n readonly path?: string\n /** Provider scope. Default: `singleton`; `request` creates one controller per request. */\n readonly scope?: Scope\n}\n\n/**\n * Declares a controller: a provider (singleton by default) whose decorated methods are routes.\n *\n * ```ts\n * @Controller('/users')\n * export class UserController {\n * constructor(private readonly users: UserService) {}\n *\n * @Get('/:id')\n * find(@Param('id') id: number) {\n * return this.users.findById(id)\n * }\n * }\n * ```\n *\n * @param pathOrOptions static: base path, or `{ path?, scope? }`.\n */\nexport function Controller(_pathOrOptions?: string | ControllerOptions): ClassMarker {\n return classMarker\n}\n\n/** `GET` route. `path` (static) is relative to the controller path; default: the controller path. */\nexport function Get(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `POST` route (default status 201). */\nexport function Post(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `PUT` route. */\nexport function Put(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `PATCH` route. */\nexport function Patch(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `DELETE` route. */\nexport function Delete(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `HEAD` route (`GET` routes already answer `HEAD` requests). */\nexport function Head(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `OPTIONS` route (paths without one answer `OPTIONS` with `204` and an `allow` header). */\nexport function Options(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** Route for GET, HEAD, POST, PUT, PATCH, DELETE and OPTIONS (methods without a dedicated route on the same path). */\nexport function All(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/**\n * A `GET` route serving an event stream (Server-Sent Events). The handler returns an\n * `AsyncIterable`, an `Iterable` or a `ReadableStream` of `SseEvent` (`{ data, event, id, retry,\n * comment }`), or an `HttpResponse` / exception for other outcomes (204 stops `EventSource`). The\n * plugin frames the events, sends heartbeats, stops the source when the client leaves (`ctx.signal`)\n * and closes the stream gracefully on shutdown.\n *\n * ```ts\n * @Sse('/:id/events', { retry: 5_000 })\n * async events(@Param('id') id: string, @Ctx() ctx: HttpContext): Promise<AsyncIterable<SseEvent<OrderEvent>>> {\n * if ((await this.orders.find(id)) === undefined) throw new NotFoundException() // pre-flight checks first\n * return this.hub.subscribe(id, { signal: ctx.signal })\n * }\n * ```\n *\n * Prefer an `async` method returning the source over an `async *` generator: the body of a\n * generator only runs once the 200 and the headers are sent.\n *\n * @param path static: route path (relative to the controller path).\n * @param options static: `{ heartbeat?, retry?, maxDuration? }` (see `SseOptions`).\n */\nexport function Sse(path?: string, options?: SseOptions): MethodMarker\nexport function Sse(options: SseOptions): MethodMarker\nexport function Sse(_pathOrOptions?: string | SseOptions, _options?: SseOptions): MethodMarker {\n return methodMarker\n}\n\n/**\n * Injects a route parameter, coerced to the parameter type (`string`, `number`, `boolean`,\n * `bigint`, `Date`, literal unions) or validated with `schema`. Without arguments: every parameter\n * (`Record<string, string>`).\n *\n * ```ts\n * @Get('/:id')\n * find(@Param('id') id: number) {}\n * ```\n *\n * @param name static: name of a `:param` of the route path.\n * @param schema value: a Standard Schema validating the raw string (its output is injected).\n */\nexport function Param(): ParameterMarker\nexport function Param(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Param(schema: StandardSchemaV1): ParameterMarker\nexport function Param(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a query parameter (coerced to the parameter type; `T[]` accepts repeated and single\n * values; optional when the parameter is optional or has a default) or, without name, the whole\n * query (`Record<string, string | string[]>`), typically validated with a schema.\n *\n * ```ts\n * list(@Query('page') page = 1, @Query('tag') tags: string[] = []) {}\n * search(@Query(SearchQuery) query: SearchQuery) {}\n * ```\n *\n * @param name static: query key.\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function Query(): ParameterMarker\nexport function Query(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Query(schema: StandardSchemaV1): ParameterMarker\nexport function Query(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a request cookie (decoded, coerced to the parameter type like `@Headers`: `string`,\n * `number`, `boolean`, `bigint`, `Date`, literal unions, enums, branded primitives) or validated\n * with `schema`; without name, every cookie (`Record<string, string>`). An absent cookie answers 400\n * `Missing cookie \"name\"` unless the parameter is optional. Error messages never echo the value.\n *\n * ```ts\n * // a stale or forged value falls back instead of answering 400 until the cookie expires\n * export const Theme = z.enum(['light', 'dark']).catch('light')\n *\n * read(@Cookie('theme', Theme) theme: 'light' | 'dark', @Cookie('visits') visits = 0) {}\n * ```\n *\n * @param name static: cookie name (an RFC 9110 token).\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function Cookie(): ParameterMarker\nexport function Cookie(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Cookie(schema: StandardSchemaV1): ParameterMarker\nexport function Cookie(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the **verified** value of a signed cookie (set with `{ signed: true }`, plugin option\n * `cookies.secrets`): absent, tampered or signed with a retired key, the cookie does not exist\n * (400 `Missing cookie \"name\"` unless the parameter is optional). Same coercion and schema rules as\n * {@link Cookie}. A route reading a signed cookie fails the boot when `cookies.secrets` is not set.\n *\n * @param name static: cookie name.\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function SignedCookie(_name: string, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the parsed request body, validated with `schema` when given (the schema output is\n * injected: defaults, transforms, stripped keys). A non-primitive body without schema is reported\n * by the compiler (ZNIGHT017).\n *\n * @param schema value: a Standard Schema (Zod, Valibot, ArkType...).\n */\nexport function Body(_schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a request header (case-insensitive `name`, coerced to the parameter type) or, without\n * name, every header (`Record<string, string | undefined>`).\n *\n * @param name static: header name.\n */\nexport function Headers(_name?: string): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a file of a `multipart/form-data` body as a standard `File` (`name`, `type`, `size`,\n * `arrayBuffer()`, `text()`, `stream()`), held in memory. The route parses multipart bodies before\n * its interceptors, enforcing the options while the body is read: a file above `maxSize` answers\n * 413, a refused type 415, a second file in the field or a file in an undeclared field 400, a\n * missing required file 400, a non-multipart body 415. `@Body()` receives the text fields.\n *\n * ```ts\n * @Post('/avatar')\n * upload(@UploadedFile('avatar', { maxSize: '2mb', mimeTypes: ['image/png', 'image/jpeg'] }) avatar: File) {}\n *\n * @Post('/attachment')\n * attach(@UploadedFile('file') file?: File) {} // optional: undefined when absent\n * ```\n *\n * `File.name` and `File.type` are sent by the client: never trust them (see the README, \"Files\").\n *\n * @param field static: the multipart field; omitted: the single file of the body, whatever its field.\n * @param options static: `{ required?, maxSize?, mimeTypes? }`.\n */\nexport function UploadedFile(field?: string, options?: UploadedFileOptions): ParameterMarker\nexport function UploadedFile(options: UploadedFileOptions): ParameterMarker\nexport function UploadedFile(\n _fieldOrOptions?: string | UploadedFileOptions,\n _options?: UploadedFileOptions,\n): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the files of a multipart field (`File[]`, in body order), or of every field without\n * `field`. Same rules as {@link UploadedFile}; above `maxFiles` files the request answers 413. An\n * optional parameter (`files?: File[]`, `required: false`) receives an empty array when no file is\n * sent.\n *\n * ```ts\n * @Post('/documents')\n * add(@UploadedFiles('documents', { maxFiles: 5, maxSize: '20mb', mimeTypes: ['application/pdf'] }) documents: File[]) {}\n * ```\n *\n * @param field static: the multipart field; omitted: the files of every field.\n * @param options static: `{ required?, maxSize?, maxFiles?, mimeTypes? }`.\n */\nexport function UploadedFiles(field?: string, options?: UploadedFilesOptions): ParameterMarker\nexport function UploadedFiles(options: UploadedFilesOptions): ParameterMarker\nexport function UploadedFiles(\n _fieldOrOptions?: string | UploadedFilesOptions,\n _options?: UploadedFilesOptions,\n): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Sets the maximum request body size of a route, or of every route of a controller (the route wins),\n * over the plugin `bodyLimit` (and over the limit computed for upload routes). `Infinity` disables\n * the limit, e.g. for a route streaming its body with `ctx.bodyStream()`.\n *\n * ```ts\n * @Put('/files/:name')\n * @BodyLimit('5gb')\n * async store(@Param('name') name: string, @Ctx() ctx: HttpContext) {\n * await pipeline(Readable.fromWeb(ctx.bodyStream()), createWriteStream(join(DIR, safeName(name))))\n * }\n * ```\n *\n * @param size static: bytes (`10_485_760`) or a size with a unit (`'10mb'`, `'512kb'`; `kb` = 1024 bytes).\n */\nexport function BodyLimit(_size: ByteSize): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/** Injects the native request of the adapter (escape hatch; the compiler warns). */\nexport function Req(): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the native response of the adapter (escape hatch; the compiler warns). The handler then\n * writes the response itself, and must have finished when its promise settles.\n */\nexport function Res(): ParameterMarker {\n return parameterMarker\n}\n\n/** Injects the {@link HttpContext} of the request. */\nexport function Ctx(): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Sets the status of successful responses (wins over `HttpResponse.status` and the defaults).\n *\n * @param status static: an integer between 100 and 599.\n */\nexport function HttpCode(_status: number): MethodMarker {\n return methodMarker\n}\n\n/**\n * Adds a header to successful responses. Repeat the decorator for several headers.\n *\n * @param name static: header name.\n * @param value static: header value.\n */\nexport function Header(_name: string, _value: string): MethodMarker {\n return methodMarker\n}\n\n/**\n * Protects a controller (every route) or a route with guards (providers implementing\n * {@link CanActivate}). Order: global guards → controller guards → route guards, each list in\n * declaration order.\n *\n * @param guards value: guard classes.\n */\nexport function UseGuard(..._guards: [GuardClass, ...GuardClass[]]): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/**\n * Wraps a controller (every route) or a route with interceptors (providers implementing\n * {@link HttpInterceptor}). Order: global → controller → route, the first one being the outermost.\n *\n * @param interceptors value: interceptor classes.\n */\nexport function UseInterceptor(\n ..._interceptors: [HttpInterceptorClass, ...HttpInterceptorClass[]]\n): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/**\n * Validates the request body with `schema`: sugar for `@Body(schema)` on the body parameter (using\n * both is ZNIGHT005).\n *\n * @param schema value: a Standard Schema.\n */\nexport function Validate(_schema: StandardSchemaV1): MethodMarker {\n return methodMarker\n}\n\n/** Arguments of a route decorator: optional when `T` accepts `undefined` or is `true` (flag decorators). */\nexport type RouteDecoratorArgs<T> = [T] extends [true] ? [value?: T] : undefined extends T ? [value?: T] : [value: T]\n\n/** Options of {@link createRouteDecorator} (static). */\nexport interface RouteDecoratorOptions {\n /**\n * Decision group. Decorators of a group are alternatives: one per controller or route, and the\n * route's decision replaces the controller's. Default: the key (the decorator is its own group).\n * A letter followed by letters, digits, `_`, `.` or `-`.\n */\n readonly group?: string\n /**\n * Every route must carry a decision of the group: ZNIGHT023 at build time when a route has none,\n * and at boot when no guard of its chain enforces it (see {@link GuardClass}). All the decorators\n * of a group must agree. Default `false`.\n */\n readonly required?: boolean\n}\n\n/** The data part of a route decorator: what guards list in `static enforces`. */\nexport interface RouteDecoratorInfo {\n /** Key of the value in `route.meta`. */\n readonly key: string\n /** Decision group (`options.group ?? key`). */\n readonly group: string\n /** Every route must carry a decision of the group. */\n readonly required: boolean\n}\n\n/**\n * A route metadata entry given as data rather than as a decorator: the `meta` of plugin routes\n * (`[Public.meta()]`). Built by {@link RouteDecorator.meta}.\n */\nexport interface RouteMetaEntry<T = unknown> {\n readonly key: string\n readonly value: T\n /** Decision group. Default: the key. */\n readonly group?: string\n /** Default `false`. */\n readonly required?: boolean\n}\n\n/** A user-defined route metadata decorator created with {@link createRouteDecorator}. */\nexport interface RouteDecorator<T> extends RouteDecoratorInfo {\n (...args: RouteDecoratorArgs<T>): ClassMarker & MethodMarker\n /**\n * The value of the current route, if set. Reads the effective metadata: the route's decision of\n * a group wins over the controller's.\n */\n get(ctx: HttpContext): T | undefined\n /**\n * The same metadata as data (`{ key, value, group, required }`), for routes that are not compiled\n * controllers (plugin routes: `OpenApiPlugin.configure({ meta: [Public.meta()] })`). The value is\n * `true` when omitted, like `@Public()`.\n */\n meta(...args: RouteDecoratorArgs<T>): RouteMetaEntry<T>\n}\n\n/**\n * Grammar of an explicit decision group name (internal; the compiler extension has the same rule).\n * A decorator without `group` is its own group, named after its key: any non-empty key is valid.\n */\nexport const GROUP_NAME: RegExp = /^[A-Za-z][\\w.-]*$/\n\n/** `true` when `group` is a valid group of `key`: the key itself (the default) or a valid name. */\nexport function isGroupOf(group: unknown, key: string): group is string {\n return typeof group === 'string' && (group === key || GROUP_NAME.test(group))\n}\n\n/**\n * Creates a metadata decorator for controllers and routes. The compiler stores its argument\n * (`value`, statically evaluated or an exported reference; `true` when omitted) in\n * `meta[key]`, read by guards and interceptors through `ctx.route.meta` or `decorator.get(ctx)`.\n *\n * ```ts\n * export const Public = createRouteDecorator('public', { group: 'access', required: true })\n * export const Authenticated = createRouteDecorator('authenticated', { group: 'access', required: true })\n * export const Roles = createRouteDecorator<readonly string[]>('roles', { group: 'access', required: true })\n *\n * @Controller('/books')\n * @Roles(['reader']) // the decision of every route of the controller...\n * export class BookController {\n * @Get('/:id/cover')\n * @Public() // ...unless the route has its own decision of the group\n * cover() {}\n * }\n *\n * // in a guard\n * if (Public.get(ctx)) return true\n * const roles = Roles.get(ctx) ?? []\n * ```\n *\n * Decorators of one `group` are alternatives: two of them on the same class or method are\n * ZNIGHT005, and the route's decision replaces the controller's (without `group`, each decorator is\n * its own group: the route value wins over the controller value). With `required: true`, a route\n * without decision fails the build (ZNIGHT023).\n *\n * @param key static: unique metadata key.\n * @param options static: `{ group?, required? }`.\n */\nexport function createRouteDecorator<T = true>(key: string, options?: RouteDecoratorOptions): RouteDecorator<T> {\n if (typeof key !== 'string' || key === '') {\n throw new TypeError(`createRouteDecorator(): the key must be a non-empty string (received ${String(key)})`)\n }\n if (options !== undefined && (options === null || typeof options !== 'object')) {\n throw new TypeError(`createRouteDecorator('${key}'): options must be an object { group?, required? }`)\n }\n // the grammar applies to an explicit group only: without one, any key is its own group (as before groups)\n const group = options?.group ?? key\n if (!isGroupOf(group, key)) {\n throw new TypeError(\n `createRouteDecorator('${key}'): \"group\" must be a name made of letters, digits, _ . - starting with a letter (received ${String(group)})`,\n )\n }\n const required = options?.required ?? false\n if (typeof required !== 'boolean') {\n throw new TypeError(`createRouteDecorator('${key}'): \"required\" must be a boolean (received ${String(required)})`)\n }\n const decorator = (..._args: RouteDecoratorArgs<T>): ClassMarker & MethodMarker => classOrMethodMarker\n return Object.assign(decorator, {\n key,\n group,\n required,\n get: (ctx: HttpContext): T | undefined => ctx.route?.meta[key] as T | undefined,\n meta: (...args: RouteDecoratorArgs<T>): RouteMetaEntry<T> =>\n Object.freeze({ key, value: (args.length === 0 ? true : args[0]) as T, group, required }),\n })\n}\n","/**\n * `EventChannel`: a bounded bridge from push-based producers (an event bus, an `EventEmitter`, a\n * database listener) to a pull-based `AsyncIterable` (an SSE source, a GraphQL subscription), with\n * no dependency.\n */\n\n/** Options of {@link EventChannel}. */\nexport interface EventChannelOptions {\n /** Buffered items before `overflow` applies. Default: 1 000. */\n readonly capacity?: number\n /**\n * What happens when an item is pushed into a full buffer:\n * - `'drop-oldest'` (default): the oldest buffered item is discarded;\n * - `'drop-newest'`: the item is discarded (`push()` returns false);\n * - `'close'`: the item is discarded and the channel closes after the buffered items (an SSE\n * client then reconnects and resumes with `Last-Event-ID`).\n */\n readonly overflow?: 'drop-oldest' | 'drop-newest' | 'close'\n /** Closes the channel when aborted (pass `ctx.signal`). */\n readonly signal?: AbortSignal\n}\n\nconst DEFAULT_CAPACITY = 1_000\n\n/** A pending `next()`. */\ninterface Waiter<T> {\n resolve(result: IteratorResult<T>): void\n reject(error: unknown): void\n}\n\n/**\n * A bounded, single-consumer queue that is an `AsyncIterable`: producers `push()`, the consumer\n * iterates. A pending `next()` resolves with `{ done: true }` as soon as the channel closes for any\n * reason, so an SSE handler built on a channel always stops when its client leaves.\n *\n * ```ts\n * const channel = new EventChannel<SseEvent<Order>>({ capacity: 256, overflow: 'close', signal: ctx.signal })\n * const unsubscribe = bus.on('order', order => channel.push({ event: 'order', data: order }))\n * channel.onClose(unsubscribe)\n * return channel // from an @Sse handler\n * ```\n */\nexport class EventChannel<T> implements AsyncIterable<T> {\n readonly #capacity: number\n readonly #overflow: 'drop-oldest' | 'drop-newest' | 'close'\n readonly #buffer: T[] = []\n readonly #waiters: Waiter<T>[] = []\n readonly #listeners: (() => void)[] = []\n readonly #signal: AbortSignal | undefined\n #closed = false\n #failure: { readonly error: unknown } | undefined\n #iterating = false\n #onAbort: (() => void) | undefined\n\n constructor(options: EventChannelOptions = {}) {\n if (options === null || typeof options !== 'object') {\n throw new TypeError('EventChannel: options must be an object { capacity?, overflow?, signal? }')\n }\n const capacity = options.capacity ?? DEFAULT_CAPACITY\n if (!(Number.isSafeInteger(capacity) && capacity >= 1) && capacity !== Number.POSITIVE_INFINITY) {\n throw new TypeError(`EventChannel: capacity must be a positive integer (received ${String(capacity)})`)\n }\n const overflow = options.overflow ?? 'drop-oldest'\n if (overflow !== 'drop-oldest' && overflow !== 'drop-newest' && overflow !== 'close') {\n throw new TypeError(\n `EventChannel: overflow must be 'drop-oldest', 'drop-newest' or 'close' (received ${String(overflow)})`,\n )\n }\n this.#capacity = capacity\n this.#overflow = overflow\n const signal = options.signal\n this.#signal = signal\n if (signal !== undefined) {\n if (signal.aborted) {\n this.#closed = true\n } else {\n this.#onAbort = (): void => this.close()\n signal.addEventListener('abort', this.#onAbort, { once: true })\n }\n }\n }\n\n /** Buffered items. */\n get size(): number {\n return this.#buffer.length\n }\n\n /** Whether the channel no longer accepts items (closed, failed, overflowed, aborted, returned). */\n get closed(): boolean {\n return this.#closed\n }\n\n /** Buffers an item (or hands it to a waiting consumer). Returns false when it was dropped or the channel is closed. */\n push(item: T): boolean {\n if (this.#closed) return false\n const waiter = this.#waiters.shift()\n if (waiter !== undefined) {\n waiter.resolve({ done: false, value: item })\n return true\n }\n if (this.#buffer.length < this.#capacity) {\n this.#buffer.push(item)\n return true\n }\n switch (this.#overflow) {\n case 'drop-oldest':\n this.#buffer.shift()\n this.#buffer.push(item)\n return true\n case 'drop-newest':\n return false\n default:\n this.close()\n return false\n }\n }\n\n /** Ends the iteration after the buffered items. Idempotent. */\n close(): void {\n if (this.#closed) return\n this.#closed = true\n this.#settle()\n }\n\n /** Makes the iteration throw `error` after the buffered items (ignored once closed). */\n fail(error: unknown): void {\n if (this.#closed) return\n this.#failure = { error }\n this.#closed = true\n this.#settle()\n }\n\n /**\n * Calls `listener` once when the channel closes (close, fail, overflow, signal, consumer\n * `return()`); immediately when it is already closed.\n */\n onClose(listener: () => void): void {\n if (typeof listener !== 'function') throw new TypeError('EventChannel.onClose() expects a function')\n if (this.#closed) listener()\n else this.#listeners.push(listener)\n }\n\n /**\n * The iterator of the single consumer (a second call throws). Its `return()` closes the channel\n * and resolves at once, even while a `next()` waits.\n */\n [Symbol.asyncIterator](): AsyncIterator<T> {\n if (this.#iterating) throw new TypeError('EventChannel: a channel has a single consumer (already iterated)')\n this.#iterating = true\n return {\n next: (): Promise<IteratorResult<T>> => this.#next(),\n return: (): Promise<IteratorResult<T>> => {\n this.#buffer.length = 0\n this.close()\n return Promise.resolve({ done: true, value: undefined })\n },\n }\n }\n\n #next(): Promise<IteratorResult<T>> {\n if (this.#buffer.length > 0) return Promise.resolve({ done: false, value: this.#buffer.shift() as T })\n if (this.#closed) {\n const failure = this.#failure\n if (failure !== undefined) {\n this.#failure = undefined\n return Promise.reject(failure.error)\n }\n return Promise.resolve({ done: true, value: undefined })\n }\n return new Promise((resolve, reject) => this.#waiters.push({ resolve, reject }))\n }\n\n /** The channel just closed: release waiting consumers, the signal listener and notify `onClose` listeners. */\n #settle(): void {\n if (this.#onAbort !== undefined) {\n this.#signal?.removeEventListener('abort', this.#onAbort)\n this.#onAbort = undefined\n }\n // waiters only exist while the buffer is empty\n for (const waiter of this.#waiters.splice(0)) {\n const failure = this.#failure\n if (failure === undefined) {\n waiter.resolve({ done: true, value: undefined })\n } else {\n this.#failure = undefined\n waiter.reject(failure.error)\n }\n }\n for (const listener of this.#listeners.splice(0)) {\n try {\n listener()\n } catch {\n // a failing listener must not break the producer that closed the channel\n }\n }\n }\n}\n","/**\n * File downloads (`HttpResponse.file()`): files on disk (sent as lazily read, file-backed `Blob`s:\n * `fs.openAsBlob()`) or `Blob` objects, with `Content-Length`, `Content-Type`, `Last-Modified` /\n * `ETag`, conditional requests (304 / 412), single byte ranges (206 / 416) and RFC 6266\n * `Content-Disposition` headers.\n */\nimport type { HeaderValue } from './exceptions.ts'\n\nimport { openAsBlob } from 'node:fs'\nimport { realpath, stat } from 'node:fs/promises'\nimport { basename, isAbsolute, relative, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport { HttpException, NotFoundException } from './exceptions.ts'\nimport { contentTypeFor, OCTET_STREAM } from './mime.ts'\nimport { emptyRecord } from './utils.ts'\n\n/** How a file is presented to the client (`Content-Disposition`). */\nexport type ContentDispositionType = 'attachment' | 'inline'\n\n/** Options of `HttpResponse.file()`. */\nexport interface FileResponseOptions {\n /**\n * Name proposed to the client in `Content-Disposition` (any Unicode name; path separators are\n * removed). Setting it makes the response an `attachment` unless `disposition` says otherwise.\n */\n readonly filename?: string\n /**\n * Media type of the response. Default: the type of the `Blob`, else looked up from the extension\n * of `filename` / of the path (small built-in table, text types with `charset=utf-8`), else\n * `application/octet-stream`.\n */\n readonly contentType?: string\n /**\n * `attachment` (download) or `inline` (displayed by the browser). Default: `attachment` when\n * `filename` is set, otherwise no `Content-Disposition` header. Without `filename`, the file name\n * (path basename, `File.name`) is used.\n */\n readonly disposition?: ContentDispositionType\n /**\n * Directory the path is resolved in. The resolved file (symbolic links followed) must stay inside\n * it: `..` segments, absolute paths and links escaping the directory answer 404. Always set it\n * when the path comes from the request.\n */\n readonly root?: string\n /**\n * With `root`: whether files or directories whose name starts with a dot (`.env`, `.git/config`)\n * may be sent. Default: `'deny'` (404).\n */\n readonly dotfiles?: 'allow' | 'deny'\n}\n\n/**\n * The body of `HttpResponse.file()`: a file on disk or a `Blob`, resolved by the pipeline when the\n * response is sent (stat, conditional request, range).\n */\nexport class FileBody {\n /** Path (`string` / `file:` URL) or `Blob` / `File`. */\n readonly source: string | URL | Blob\n readonly options: FileResponseOptions\n\n constructor(source: string | URL | Blob, options: FileResponseOptions = {}) {\n if (typeof source !== 'string' && !(source instanceof URL) && !(source instanceof Blob)) {\n throw new TypeError('HttpResponse.file() expects a path (string or file: URL), a Blob or a File')\n }\n if (source instanceof URL && source.protocol !== 'file:') {\n throw new TypeError(`HttpResponse.file() expects a file: URL (received ${source.protocol})`)\n }\n const disposition = options.disposition\n if (disposition !== undefined && disposition !== 'attachment' && disposition !== 'inline') {\n throw new TypeError(`Invalid disposition ${JSON.stringify(disposition)} (expected \"attachment\" or \"inline\")`)\n }\n if (options.dotfiles !== undefined && options.dotfiles !== 'allow' && options.dotfiles !== 'deny') {\n throw new TypeError(`Invalid dotfiles ${JSON.stringify(options.dotfiles)} (expected \"allow\" or \"deny\")`)\n }\n this.source = source\n this.options = options\n }\n}\n\n/** Whether `value` is a {@link FileBody}. */\nexport function isFileBody(value: unknown): value is FileBody {\n return value instanceof FileBody\n}\n\n/** The request facts a file response depends on. */\nexport interface FileRequest {\n readonly method: string\n readonly headers: Readonly<Record<string, string | undefined>>\n}\n\n/** A resolved file response (before route headers and status precedence). */\nexport interface ResolvedFile {\n /** 200, 206 (range) or 304 (not modified). */\n readonly status: 200 | 206 | 304\n readonly headers: Record<string, HeaderValue>\n /**\n * The bytes to send, as a `Blob` (file-backed for files on disk: read lazily, sent with its size;\n * `sendfile` on Bun); `null` for 304, HEAD requests and empty files.\n */\n readonly body: Blob | null\n}\n\n/** Attempts to open a file whose size changes between `stat` and `openAsBlob` (concurrent writes). */\nconst OPEN_ATTEMPTS = 3\n\n/**\n * Resolves a file response for a request: opens the file, evaluates the preconditions\n * (`If-Match`, `If-Unmodified-Since` → 412; `If-None-Match`, `If-Modified-Since` → 304) and the\n * `Range` header (single range, honouring `If-Range`; 416 when unsatisfiable).\n *\n * @throws NotFoundException (404) when the file does not exist, is not a regular file or escapes `root`;\n * HttpException 412 / 416.\n */\nexport function resolveFile(file: FileBody, request: FileRequest): Promise<ResolvedFile> {\n if (!(file.source instanceof Blob)) return resolvePath(file, request)\n try {\n return Promise.resolve(resolveBlob(file, file.source, request))\n } catch (error) {\n return Promise.reject(error)\n }\n}\n\nasync function resolvePath(file: FileBody, request: FileRequest): Promise<ResolvedFile> {\n const target = await locate(file.source as string | URL, file.options.root, file.options.dotfiles !== 'allow')\n for (let attempt = 1; ; attempt++) {\n let stats: Awaited<ReturnType<typeof stat>>\n try {\n stats = await stat(target)\n } catch (error) {\n throw notFound(error)\n }\n if (!stats.isFile()) throw new NotFoundException('File not found')\n const name = basename(target)\n const plan = planResponse(\n {\n size: stats.size,\n lastModified: stats.mtimeMs,\n contentType: contentTypeOf(file.options, undefined, name),\n disposition: dispositionOf(file.options, name),\n },\n request,\n )\n if (plan.body === undefined) return { ...plan, body: null }\n let blob: Blob\n try {\n blob = await openAsBlob(target)\n } catch (error) {\n throw notFound(error)\n }\n // the file was replaced or written to since `stat`: describe the new content\n if (blob.size !== stats.size) {\n if (attempt < OPEN_ATTEMPTS) continue\n throw new Error(`The file ${name} keeps changing while being sent`)\n }\n return { ...plan, body: slice(blob, plan.body) }\n }\n}\n\nfunction resolveBlob(file: FileBody, blob: Blob, request: FileRequest): ResolvedFile {\n const name = blob instanceof File && blob.name !== '' ? blob.name : undefined\n const info: Representation = {\n size: blob.size,\n lastModified: blob instanceof File ? blob.lastModified : undefined,\n contentType: contentTypeOf(file.options, blob.type, name),\n disposition: dispositionOf(file.options, name),\n }\n const plan = planResponse(info, request)\n return { ...plan, body: plan.body === undefined ? null : slice(blob, plan.body) }\n}\n\n/** The bytes `start..end` (inclusive) of a blob (the blob itself when complete). */\nfunction slice(blob: Blob, { start, end }: ByteRange): Blob {\n return start === 0 && end === blob.size - 1 ? blob : blob.slice(start, end + 1)\n}\n\n/** Resolves the path to open, enforcing `root` (and hiding dotfiles inside it). */\nasync function locate(source: string | URL, root: string | undefined, hideDotfiles: boolean): Promise<string> {\n const path = source instanceof URL ? fileURLToPath(source) : source\n if (path === '' || path.includes('\\0')) throw new NotFoundException('File not found')\n if (root === undefined) return resolve(path)\n const base = resolve(root)\n const target = resolve(base, path)\n if (!isInside(base, target, hideDotfiles)) throw new NotFoundException('File not found')\n // symbolic links: the real file must be inside the real root\n let realBase: string\n let realTarget: string\n try {\n ;[realBase, realTarget] = await Promise.all([realpath(base), realpath(target)])\n } catch (error) {\n throw notFound(error)\n }\n if (!isInside(realBase, realTarget, hideDotfiles)) throw new NotFoundException('File not found')\n return realTarget\n}\n\nfunction isInside(base: string, target: string, hideDotfiles: boolean): boolean {\n const path = relative(base, target)\n if (path === '' || isAbsolute(path)) return false\n const segments = path.split(/[\\\\/]/)\n if (segments[0] === '..') return false\n return !hideDotfiles || !segments.some(segment => segment.startsWith('.'))\n}\n\nconst MISSING = new Set(['ENOENT', 'ENOTDIR', 'EISDIR', 'ENAMETOOLONG', 'ELOOP', 'ERR_INVALID_ARG_VALUE'])\n\nfunction notFound(error: unknown): unknown {\n const code = (error as { code?: unknown } | null)?.code\n return typeof code === 'string' && MISSING.has(code)\n ? new NotFoundException('File not found', undefined, { cause: error })\n : error\n}\n\n// -------------------------------------------------------------------------------------------------\n// Representation metadata, preconditions and ranges\n// -------------------------------------------------------------------------------------------------\n\ninterface Representation {\n readonly size: number\n /** Milliseconds since the epoch, when known. */\n readonly lastModified: number | undefined\n readonly contentType: string\n readonly disposition: string | undefined\n}\n\ninterface Plan {\n readonly status: 200 | 206 | 304\n readonly headers: Record<string, HeaderValue>\n /** Inclusive byte range to send; `undefined`: no body (304, HEAD, empty file). */\n readonly body: { readonly start: number; readonly end: number } | undefined\n}\n\nfunction planResponse(info: Representation, request: FileRequest): Plan {\n const validators = emptyRecord<HeaderValue>()\n const etag = info.lastModified === undefined ? undefined : entityTag(info.size, info.lastModified)\n const seconds = info.lastModified === undefined ? undefined : Math.floor(info.lastModified / 1000)\n if (etag !== undefined) validators['etag'] = etag\n if (seconds !== undefined) validators['last-modified'] = new Date(seconds * 1000).toUTCString()\n\n const precondition = evaluatePreconditions(request, etag, seconds)\n if (precondition === 412) throw new HttpException(412, 'Precondition Failed', undefined, { headers: validators })\n if (precondition === 304) return { status: 304, headers: validators, body: undefined }\n\n const headers = emptyRecord<HeaderValue>()\n headers['content-type'] = info.contentType\n if (info.disposition !== undefined) headers['content-disposition'] = info.disposition\n headers['accept-ranges'] = 'bytes'\n Object.assign(headers, validators)\n\n const range = request.method === 'GET' ? requestedRange(request.headers, info.size, etag, seconds) : undefined\n if (range === 'unsatisfiable') {\n throw new HttpException(416, `Range Not Satisfiable (size: ${info.size} bytes)`, undefined, {\n headers: { 'content-range': `bytes */${info.size}`, 'accept-ranges': 'bytes' },\n })\n }\n if (range !== undefined) {\n headers['content-range'] = `bytes ${range.start}-${range.end}/${info.size}`\n headers['content-length'] = String(range.end - range.start + 1)\n return { status: 206, headers, body: request.method === 'HEAD' ? undefined : range }\n }\n headers['content-length'] = String(info.size)\n const body = request.method === 'HEAD' || info.size === 0 ? undefined : { start: 0, end: info.size - 1 }\n return { status: 200, headers, body }\n}\n\n/** Strong entity tag from the size and modification time (like nginx: `\"<mtime>-<size>\"`, hex). */\nfunction entityTag(size: number, lastModified: number): string {\n return `\"${Math.floor(lastModified).toString(16)}-${size.toString(16)}\"`\n}\n\n/** RFC 9110 §13.2.2: 412, 304 or `undefined` (proceed). */\nfunction evaluatePreconditions(\n request: FileRequest,\n etag: string | undefined,\n seconds: number | undefined,\n): 304 | 412 | undefined {\n const headers = request.headers\n const safe = request.method === 'GET' || request.method === 'HEAD'\n const ifMatch = headers['if-match']\n if (ifMatch === undefined) {\n const since = httpDate(headers['if-unmodified-since'])\n if (since !== undefined && seconds !== undefined && seconds > since) return 412\n } else {\n if (!matchesEntityTag(ifMatch, etag, true)) return 412\n }\n const ifNoneMatch = headers['if-none-match']\n if (ifNoneMatch !== undefined) {\n if (matchesEntityTag(ifNoneMatch, etag, false)) return safe ? 304 : 412\n } else if (safe) {\n const since = httpDate(headers['if-modified-since'])\n if (since !== undefined && seconds !== undefined && seconds <= since) return 304\n }\n return undefined\n}\n\n/** Whether an `If-Match` / `If-None-Match` list matches `etag` (`*` matches any existing file). */\nfunction matchesEntityTag(header: string, etag: string | undefined, strong: boolean): boolean {\n if (header.trim() === '*') return true\n if (etag === undefined) return false\n for (const raw of header.split(',')) {\n const candidate = raw.trim()\n if (candidate === '') continue\n if (strong) {\n if (candidate === etag) return true\n } else if (stripWeak(candidate) === stripWeak(etag)) {\n return true\n }\n }\n return false\n}\n\nfunction stripWeak(tag: string): string {\n return tag.startsWith('W/') ? tag.slice(2) : tag\n}\n\n/** Seconds of an HTTP date, `undefined` when absent or invalid. */\nfunction httpDate(value: string | undefined): number | undefined {\n if (value === undefined) return undefined\n const time = Date.parse(value)\n return Number.isNaN(time) ? undefined : Math.floor(time / 1000)\n}\n\n/** The range to send for a `Range` header (with `If-Range`), `undefined` for the whole file. */\nfunction requestedRange(\n headers: Readonly<Record<string, string | undefined>>,\n size: number,\n etag: string | undefined,\n seconds: number | undefined,\n): ByteRange | 'unsatisfiable' | undefined {\n const header = headers['range']\n if (header === undefined) return undefined\n const ifRange = headers['if-range']?.trim()\n if (ifRange !== undefined) {\n const isTag = ifRange.startsWith('\"') || ifRange.startsWith('W/')\n // an entity tag must match strongly; a date must be the exact modification date\n const fresh = isTag\n ? etag !== undefined && ifRange === etag\n : seconds !== undefined && httpDate(ifRange) === seconds\n if (!fresh) return undefined\n }\n return parseRange(header, size)\n}\n\n/** An inclusive byte range. */\nexport interface ByteRange {\n readonly start: number\n readonly end: number\n}\n\n/**\n * Parses a `Range` header for a representation of `size` bytes. Only a single `bytes` range is\n * honoured: other units, several ranges and malformed values return `undefined` (the whole\n * representation is sent, as RFC 9110 allows); a valid range starting after the end returns\n * `'unsatisfiable'` (416).\n */\nexport function parseRange(header: string, size: number): ByteRange | 'unsatisfiable' | undefined {\n const equals = header.indexOf('=')\n if (equals === -1 || header.slice(0, equals).trim().toLowerCase() !== 'bytes') return undefined\n const spec = header.slice(equals + 1)\n if (spec.includes(',')) return undefined\n const match = /^\\s*(\\d*)\\s*-\\s*(\\d*)\\s*$/.exec(spec)\n if (match === null) return undefined\n const [, first = '', last = ''] = match\n if (first === '' && last === '') return undefined\n if (first === '') {\n const suffix = Number(last)\n if (!Number.isSafeInteger(suffix)) return undefined\n if (suffix === 0 || size === 0) return 'unsatisfiable'\n return { start: Math.max(0, size - suffix), end: size - 1 }\n }\n const start = Number(first)\n if (!Number.isSafeInteger(start)) return undefined\n if (last === '') return start >= size ? 'unsatisfiable' : { start, end: size - 1 }\n const end = Number(last)\n if (!Number.isSafeInteger(end) || end < start) return undefined\n return start >= size ? 'unsatisfiable' : { start, end: Math.min(end, size - 1) }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Headers\n// -------------------------------------------------------------------------------------------------\n\nfunction contentTypeOf(options: FileResponseOptions, blobType: string | undefined, name: string | undefined): string {\n if (options.contentType !== undefined) return options.contentType\n if (blobType !== undefined && blobType !== '') return blobType\n return (\n (options.filename === undefined ? undefined : contentTypeFor(options.filename)) ??\n (name === undefined ? undefined : contentTypeFor(name)) ??\n OCTET_STREAM\n )\n}\n\nfunction dispositionOf(options: FileResponseOptions, name: string | undefined): string | undefined {\n const type = options.disposition ?? (options.filename === undefined ? undefined : 'attachment')\n if (type === undefined) return undefined\n return contentDisposition(options.filename ?? name, type)\n}\n\n/** Characters that need no percent-encoding in an RFC 8187 `ext-value` (`attr-char`). */\nconst ATTR_CHAR = /^[A-Za-z0-9!#$&+\\-.^_`|~]$/\n\n/**\n * Builds a `Content-Disposition` header value (RFC 6266): `attachment; filename=\"report.pdf\"`, with\n * an RFC 8187 / 5987 `filename*` parameter for names that are not plain ASCII\n * (`attachment; filename=\"r_sum_.pdf\"; filename*=UTF-8''r%C3%A9sum%C3%A9.pdf`). Directory parts and\n * control characters of `filename` are removed.\n */\nexport function contentDisposition(filename?: string, type: ContentDispositionType = 'attachment'): string {\n if (type !== 'attachment' && type !== 'inline') {\n throw new TypeError(`Invalid disposition ${JSON.stringify(type)} (expected \"attachment\" or \"inline\")`)\n }\n if (filename === undefined) return type\n // biome-ignore lint/suspicious/noControlCharactersInRegex: control characters are removed on purpose\n const name = filename.replace(/^.*[\\\\/]/, '').replace(/[\\u0000-\\u001f\\u007f]/g, '')\n if (name === '') return type\n const fallback = name.replace(/[^\\u0020-\\u007e]/g, '_').replace(/%/g, '_')\n let value = `${type}; filename=\"${fallback.replace(/[\"\\\\]/g, '\\\\$&')}\"`\n if (fallback !== name) value += `; filename*=UTF-8''${encodeExtValue(name)}`\n return value\n}\n\nfunction encodeExtValue(value: string): string {\n let result = ''\n for (const byte of new TextEncoder().encode(value)) {\n const char = String.fromCharCode(byte)\n result += byte < 0x80 && ATTR_CHAR.test(char) ? char : `%${byte.toString(16).toUpperCase().padStart(2, '0')}`\n }\n return result\n}\n","/**\n * Signed cookies (RFC 0006 §4.5): HMAC-SHA256 bound to the cookie name, with key rotation. Uses\n * `node:crypto` (synchronous, Node.js and Bun): only imported by the runtime entry, never by the\n * compiler extension.\n */\nimport crypto, { createHmac, createSecretKey, type KeyObject } from 'node:crypto'\n\n/** Length of a signature: base64url of 32 bytes, without padding. */\nconst SIGNATURE_LENGTH = 43\n/** Minimum size of a secret, in bytes. */\nexport const MIN_SECRET_BYTES = 32\n\n/** A secret given to the plugin option `cookies.secrets`. */\nexport type CookieSecret = string | Uint8Array\n\nconst ENCODER = new TextEncoder()\n\n/**\n * Signs and verifies cookie values. The wire form of a signed cookie is\n * `<encoded value>.<signature>` with `signature = base64url(HMAC-SHA256(secret, \"<name>=<encoded value>\"))`:\n * the MAC covers the name, so a value of `a` replayed as `b` fails. The first secret signs, every\n * secret verifies (rotation).\n */\nexport class CookieSigner {\n readonly #keys: readonly KeyObject[]\n\n /** @param secrets validated by {@link checkSecrets} (at least one, ≥ 32 bytes each, no duplicate). */\n constructor(secrets: readonly CookieSecret[]) {\n this.#keys = secrets.map(secret => createSecretKey(toBytes(secret)))\n }\n\n /** `<encoded>.<signature>` signed with the first secret. `encoded` is an encoded cookie value. */\n sign(name: string, encoded: string): string {\n return `${encoded}.${mac(this.#keys[0] as KeyObject, name, encoded)}`\n }\n\n /**\n * The encoded value of a signed wire value, `undefined` when the signature is malformed or made\n * with none of the secrets (constant-time comparison).\n */\n verify(name: string, wire: string): string | undefined {\n const dot = wire.lastIndexOf('.')\n if (dot === -1) return undefined\n const signature = wire.slice(dot + 1)\n if (!isSignature(signature)) return undefined\n const encoded = wire.slice(0, dot)\n const given = Buffer.from(signature, 'latin1')\n for (const key of this.#keys) {\n const expected = Buffer.from(mac(key, name, encoded), 'latin1')\n // through the module object: observable in tests (equal lengths only, see isSignature)\n if (crypto.timingSafeEqual(expected, given)) return encoded\n }\n return undefined\n }\n}\n\nfunction mac(key: KeyObject, name: string, encoded: string): string {\n return createHmac('sha256', key).update(`${name}=${encoded}`).digest('base64url')\n}\n\n/** 43 characters of the base64url alphabet. */\nfunction isSignature(text: string): boolean {\n if (text.length !== SIGNATURE_LENGTH) return false\n for (let index = 0; index < text.length; index++) {\n const code = text.charCodeAt(index)\n const valid =\n (code >= 0x30 && code <= 0x39) ||\n (code >= 0x41 && code <= 0x5a) ||\n (code >= 0x61 && code <= 0x7a) ||\n code === 0x2d ||\n code === 0x5f\n if (!valid) return false\n }\n return true\n}\n\nfunction toBytes(secret: CookieSecret): Uint8Array {\n return typeof secret === 'string' ? ENCODER.encode(secret) : secret\n}\n\n/**\n * Normalises the option `cookies.secrets` to a list, or explains what is wrong with it (a secret\n * shorter than 32 bytes, a duplicate, an empty list, a value that is neither a string nor bytes).\n */\nexport function checkSecrets(\n value: unknown,\n): { readonly secrets: readonly CookieSecret[] } | { readonly problem: string } {\n const list: unknown[] = Array.isArray(value) ? value : [value]\n if (list.length === 0) return { problem: 'at least one secret' }\n const seen = new Set<string>()\n for (const [index, secret] of list.entries()) {\n if (typeof secret !== 'string' && !(secret instanceof Uint8Array)) {\n return { problem: `strings or Uint8Arrays (secret #${index} is not)` }\n }\n const bytes = toBytes(secret)\n if (bytes.byteLength < MIN_SECRET_BYTES) {\n return {\n problem: `secrets of at least ${MIN_SECRET_BYTES} bytes (secret #${index} has ${bytes.byteLength}): crypto.randomBytes(32).toString('base64url')`,\n }\n }\n const fingerprint = Buffer.from(bytes).toString('base64')\n if (seen.has(fingerprint)) return { problem: `distinct secrets (secret #${index} is a duplicate)` }\n seen.add(fingerprint)\n }\n return { secrets: list as CookieSecret[] }\n}\n","/** Validation of HTTP header names and values (internal). */\nimport type { HeaderValue } from './exceptions.ts'\n\n/** A field name: an RFC 9110 token. */\nconst NAME = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/\n\n/**\n * Characters a field value may not contain: everything but HTAB, visible ASCII, space and obs-text\n * (what Node.js `validateHeaderValue` accepts; Fetch `Headers` are less strict, Latin-1 only).\n */\nconst INVALID_VALUE = /[^\\t\\x20-\\x7e\\x80-\\xff]/\n\n/** Whether `name` is a valid header name. */\nexport function isHeaderName(name: string): boolean {\n return NAME.test(name)\n}\n\n/** Whether `value` can be sent as a header value by every adapter (no CR / LF, Latin-1 only...). */\nexport function isHeaderValue(value: string): boolean {\n return !INVALID_VALUE.test(value)\n}\n\n/**\n * The name of the first header whose name or value cannot be sent (`ctx.setHeader('x', 'a\\r\\nb')`,\n * a non Latin-1 file name...), `undefined` when every header is valid.\n */\nexport function findInvalidHeader(headers: Readonly<Record<string, HeaderValue | undefined>>): string | undefined {\n for (const name of Object.keys(headers)) {\n const value = headers[name]\n if (value === undefined) continue\n if (!NAME.test(name)) return name\n if (typeof value === 'string') {\n if (INVALID_VALUE.test(value)) return name\n } else {\n for (const item of value) if (INVALID_VALUE.test(String(item))) return name\n }\n }\n return undefined\n}\n","/** Errors of invalid `HttpPlugin` options (internal). */\nimport { ErrorCode, ZnightError } from '@znight/core'\n\n/** `ZNIGHT005: HttpPlugin: option \"<name>\" must be <expected> (received <value>)`. */\nexport function invalidOption(\n name: string,\n expected: string,\n value: unknown,\n cause?: unknown,\n hints?: readonly string[],\n): ZnightError {\n return new ZnightError(\n ErrorCode.InvalidDecorator,\n `HttpPlugin: option \"${name}\" must be ${expected} (received ${describeOption(value)})`,\n {\n ...(cause === undefined ? {} : { cause }),\n ...(hints === undefined ? {} : { hints }),\n },\n )\n}\n\n/** A short description of an option value for messages. */\nexport function describeOption(value: unknown): string {\n if (typeof value === 'function') return 'a function'\n if (value instanceof RegExp) return String(value)\n try {\n return JSON.stringify(value) ?? String(value)\n } catch {\n return typeof value\n }\n}\n","/**\n * CORS policy (RFC 0001 §5.4): option validation and the headers of preflights and replies. Pure:\n * the pipeline decides when to apply it (preflights are answered before routing and guards, the\n * same way on every adapter).\n */\nimport type { HeaderValue } from './exceptions.ts'\n\nimport { isHeaderName } from './headers.ts'\nimport { invalidOption } from './option-error.ts'\n\n/**\n * Origins allowed to read responses: `'*'` (any origin), an exact origin\n * (`'https://app.example.com'`), an anchored `RegExp` (`/^https:\\/\\/[a-z0-9-]+\\.example\\.com$/`), a\n * list of those, or a function (awaited; a function that throws or rejects denies the origin).\n */\nexport type CorsOrigin =\n | '*'\n | string\n | RegExp\n | readonly (string | RegExp)[]\n | ((origin: string) => boolean | Promise<boolean>)\n\n/** The `cors` option of `HttpPlugin.configure`. */\nexport interface CorsOptions {\n /** Allowed origins (required). */\n readonly origin: CorsOrigin\n /** `access-control-allow-credentials: true` (cookies, `Authorization`). Not with `'*'`. Default `false`. */\n readonly credentials?: boolean\n /**\n * `access-control-allow-methods` of preflights. Default: the methods routed on the requested path.\n * `'*'` (any method) is refused with `credentials`, where browsers read it as a method named `*`.\n */\n readonly methods?: readonly string[]\n /**\n * `access-control-allow-headers` of preflights. Default: the headers the browser asks for\n * (`access-control-request-headers`). `'*'` is refused with `credentials`; it covers\n * `Authorization` too (sent as `*, authorization` when the browser asks for it: browsers never let\n * `*` alone cover it).\n */\n readonly allowHeaders?: readonly string[] | '*'\n /**\n * `access-control-expose-headers` of replies. Default: the request id header (none when it is\n * `false`). `'*'` (every header) is refused with `credentials`, where browsers read it literally.\n */\n readonly exposeHeaders?: readonly string[]\n /** `access-control-max-age` of preflights, in seconds (0 to 86400). Default `600`. */\n readonly maxAge?: number\n}\n\n/** A resolved CORS policy (internal). */\nexport interface CorsPolicy {\n /** Any origin is allowed: `access-control-allow-origin: *`. */\n readonly wildcard: boolean\n /**\n * Replies get `vary: origin` (every policy but a wildcard one, whose replies all carry\n * `access-control-allow-origin: *`).\n */\n readonly varyOrigin: boolean\n readonly credentials: boolean\n /** Joined `methods`, `undefined` for the default (the methods of the path). */\n readonly methods: string | undefined\n /** Joined `allowHeaders` or `*`, `undefined` for the default (echo the request). */\n readonly allowHeaders: string | undefined\n /** Joined `exposeHeaders`, `undefined` when there are none. */\n readonly exposeHeaders: string | undefined\n readonly maxAge: string\n /** Whether `origin` (the request `origin` header) is allowed. May throw or reject: the caller denies it then. */\n allows(origin: string): boolean | Promise<boolean>\n}\n\nconst KEYS = new Set(['origin', 'credentials', 'methods', 'allowHeaders', 'exposeHeaders', 'maxAge'])\n/** RFC 9110 token (methods). */\nconst TOKEN = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/\nconst MAX_AGE_LIMIT = 86_400\nconst DEFAULT_MAX_AGE = 600\nconst PREFLIGHT_VARY = 'origin, access-control-request-method, access-control-request-headers'\n\n/** Validates the `cors` option (ZNIGHT005). `undefined` / `false`: CORS is disabled. */\nexport function resolveCors(\n options: CorsOptions | false | undefined,\n requestIdHeader: string | undefined,\n): CorsPolicy | undefined {\n if (options === undefined || options === false) return undefined\n if (options === null || typeof options !== 'object' || Array.isArray(options)) {\n throw invalidOption(\n 'cors',\n '{ origin, credentials?, methods?, allowHeaders?, exposeHeaders?, maxAge? } or false',\n options,\n )\n }\n for (const key of Object.keys(options)) {\n if (!KEYS.has(key)) {\n throw invalidOption('cors', '{ origin, credentials?, methods?, allowHeaders?, exposeHeaders?, maxAge? }', options)\n }\n }\n const credentials = options.credentials ?? false\n if (typeof credentials !== 'boolean') throw invalidOption('cors.credentials', 'a boolean', credentials)\n const origin = resolveOrigin(options.origin)\n if (credentials && origin.wildcard) {\n throw invalidOption(\n 'cors.origin',\n \"explicit origins when credentials is true (not '*')\",\n options.origin,\n undefined,\n [\"Browsers reject 'access-control-allow-origin: *' on credentialed requests: list the origins\"],\n )\n }\n const methods = tokenList('cors.methods', options.methods, TOKEN, 'HTTP method names')\n if (credentials) {\n refuseWildcard('cors.methods', options.methods, 'HTTP method names', 'a method named \"*\"')\n refuseWildcard('cors.allowHeaders', options.allowHeaders, 'header names', 'a header named \"*\"')\n refuseWildcard('cors.exposeHeaders', options.exposeHeaders, 'header names', 'a header named \"*\"')\n }\n let allowHeaders: string | undefined\n if (options.allowHeaders === '*') {\n if (credentials) {\n throw invalidOption(\n 'cors.allowHeaders',\n \"a list of header names when credentials is true (not '*')\",\n '*',\n undefined,\n [\"Browsers ignore 'access-control-allow-headers: *' on credentialed requests\"],\n )\n }\n allowHeaders = '*'\n } else {\n allowHeaders = headerList('cors.allowHeaders', options.allowHeaders)\n }\n const expose =\n options.exposeHeaders === undefined ? requestIdHeader : headerList('cors.exposeHeaders', options.exposeHeaders)\n const maxAge = options.maxAge ?? DEFAULT_MAX_AGE\n if (!Number.isInteger(maxAge) || maxAge < 0 || maxAge > MAX_AGE_LIMIT) {\n throw invalidOption('cors.maxAge', `an integer number of seconds between 0 and ${MAX_AGE_LIMIT}`, maxAge)\n }\n return Object.freeze({\n wildcard: origin.wildcard,\n varyOrigin: !origin.wildcard,\n credentials,\n methods,\n allowHeaders,\n exposeHeaders: expose === '' ? undefined : expose,\n maxAge: String(maxAge),\n allows: origin.allows,\n })\n}\n\ninterface ResolvedOrigin {\n readonly wildcard: boolean\n readonly allows: (origin: string) => boolean | Promise<boolean>\n}\n\nfunction resolveOrigin(value: CorsOrigin | undefined): ResolvedOrigin {\n if (value === undefined) {\n throw invalidOption(\n 'cors.origin',\n \"'*', an origin, an anchored RegExp, a list of them or a function\",\n value,\n undefined,\n [\"cors: { origin: 'https://app.example.com' }\"],\n )\n }\n if (typeof value === 'function') {\n return { wildcard: false, allows: value }\n }\n const items: readonly unknown[] = Array.isArray(value) ? value : [value]\n const exact = new Set<string>()\n const patterns: RegExp[] = []\n let wildcard = false\n for (const item of items) {\n if (item === '*') wildcard = true\n else if (typeof item === 'string') exact.add(checkOrigin(item))\n else if (item instanceof RegExp) patterns.push(checkPattern(item))\n else {\n throw invalidOption('cors.origin', \"'*', an origin, an anchored RegExp, a list of them or a function\", value)\n }\n }\n if (wildcard) return { wildcard: true, allows: () => true }\n return {\n wildcard: false,\n allows: (origin: string): boolean => exact.has(origin) || patterns.some(pattern => pattern.test(origin)),\n }\n}\n\n/** An origin must be written exactly as browsers send it: `scheme://host[:port]`. */\nfunction checkOrigin(value: string): string {\n if (value === 'null') {\n throw invalidOption('cors.origin', 'a real origin', value, undefined, [\n 'The \"null\" origin is shared by sandboxed iframes, local files and redirects: never trust it',\n ])\n }\n let url: URL | undefined\n try {\n url = new URL(value)\n } catch {\n url = undefined\n }\n if (url === undefined || (url.protocol !== 'http:' && url.protocol !== 'https:')) {\n throw invalidOption('cors.origin', 'an http(s) origin such as \"https://app.example.com\"', value)\n }\n if (url.origin !== value) {\n throw invalidOption(\n 'cors.origin',\n `an origin without path, trailing slash or default port (\"${url.origin}\")`,\n value,\n undefined,\n [`Write \"${url.origin}\": browsers send the origin in this exact form`],\n )\n }\n return value\n}\n\nfunction checkPattern(pattern: RegExp): RegExp {\n const source = pattern.source\n const trailingBackslashes = /\\\\*\\$$/.exec(source)?.[0].length ?? 0\n // `\\$` at the end matches a dollar sign: the pattern is not anchored\n const anchoredEnd = source.endsWith('$') && (trailingBackslashes - 1) % 2 === 0\n if (!source.startsWith('^') || !anchoredEnd) {\n throw invalidOption('cors.origin', 'a RegExp anchored with ^ and $', pattern, undefined, [\n 'Without anchors, /example\\\\.com/ also allows https://example.com.evil.net',\n ])\n }\n if (hasTopLevelAlternation(source)) {\n throw invalidOption('cors.origin', 'a RegExp anchored with ^ and $ around every alternative', pattern, undefined, [\n 'In /^a|b$/ the anchors bind to one alternative each: write /^(?:a|b)$/',\n ])\n }\n if (pattern.global || pattern.sticky) {\n throw invalidOption('cors.origin', 'a RegExp without the g or y flag (test() would be stateful)', pattern)\n }\n return pattern\n}\n\n/** Whether a pattern source has a `|` outside any group and character class. */\nfunction hasTopLevelAlternation(source: string): boolean {\n let depth = 0\n let inClass = false\n for (let index = 0; index < source.length; index++) {\n const char = source[index]\n if (char === '\\\\') {\n index++\n } else if (inClass) {\n if (char === ']') inClass = false\n } else if (char === '[') {\n inClass = true\n } else if (char === '(') {\n depth++\n } else if (char === ')') {\n depth--\n } else if (char === '|' && depth === 0) {\n return true\n }\n }\n return false\n}\n\n/** `'*'` in a list of a credentialed policy: browsers read it literally there (Fetch, CORS protocol). */\nfunction refuseWildcard(name: string, value: unknown, what: string, literal: string): void {\n if (!Array.isArray(value) || !value.includes('*')) return\n throw invalidOption(name, `a list of ${what} when credentials is true (not '*')`, value, undefined, [\n `On credentialed requests browsers read '*' as ${literal}, not as a wildcard: list the names`,\n ])\n}\n\nfunction tokenList(name: string, value: unknown, grammar: RegExp, what: string): string | undefined {\n if (value === undefined) return undefined\n if (!Array.isArray(value) || !value.every(item => typeof item === 'string' && grammar.test(item))) {\n throw invalidOption(name, `an array of ${what}`, value)\n }\n return value.join(', ')\n}\n\nfunction headerList(name: string, value: unknown): string | undefined {\n if (value === undefined) return undefined\n if (!Array.isArray(value) || !value.every(item => typeof item === 'string' && isHeaderName(item))) {\n throw invalidOption(name, 'an array of header names', value)\n }\n return value.map((item: string) => item.toLowerCase()).join(', ')\n}\n\n/**\n * Whether a request is a CORS preflight: `OPTIONS` with `origin` and\n * `access-control-request-method`.\n */\nexport function isPreflight(method: string, headers: Readonly<Record<string, string | undefined>>): boolean {\n return (\n method === 'OPTIONS' && headers['origin'] !== undefined && headers['access-control-request-method'] !== undefined\n )\n}\n\n/** Headers of a `204` preflight answer for an allowed origin. */\nexport function preflightHeaders(\n policy: CorsPolicy,\n origin: string,\n requestHeaders: Readonly<Record<string, string | undefined>>,\n allow: string,\n): Record<string, HeaderValue> {\n const headers: Record<string, HeaderValue> = {\n 'access-control-allow-origin': policy.wildcard ? '*' : origin,\n }\n if (policy.credentials) headers['access-control-allow-credentials'] = 'true'\n const methods = policy.methods ?? allow\n if (methods !== '') headers['access-control-allow-methods'] = methods\n const requested = requestedHeaders(requestHeaders['access-control-request-headers'])\n let allowHeaders = policy.allowHeaders ?? requested\n // `*` never covers Authorization (Fetch): name it when the browser asks for it\n if (allowHeaders !== undefined && requested?.split(', ').includes('authorization') === true) {\n const allowed = allowHeaders.split(', ')\n if (allowed.includes('*') && !allowed.includes('authorization')) allowHeaders = `${allowHeaders}, authorization`\n }\n if (allowHeaders !== undefined && allowHeaders !== '') headers['access-control-allow-headers'] = allowHeaders\n headers['access-control-max-age'] = policy.maxAge\n headers['allow'] = allow\n headers['vary'] = PREFLIGHT_VARY\n return headers\n}\n\n/** `access-control-request-headers` when it is a valid list of header names, lower-cased. */\nfunction requestedHeaders(value: string | undefined): string | undefined {\n if (value === undefined) return undefined\n const names: string[] = []\n for (const item of value.split(',')) {\n const name = item.trim()\n if (name === '') continue\n if (!isHeaderName(name)) return undefined\n names.push(name.toLowerCase())\n }\n return names.length === 0 ? undefined : names.join(', ')\n}\n\n/** CORS headers of a reply to an allowed origin (added when missing). */\nexport function corsReplyHeaders(policy: CorsPolicy, origin: string): Record<string, HeaderValue> {\n const headers: Record<string, HeaderValue> = { 'access-control-allow-origin': policy.wildcard ? '*' : origin }\n if (policy.credentials) headers['access-control-allow-credentials'] = 'true'\n if (policy.exposeHeaders !== undefined) headers['access-control-expose-headers'] = policy.exposeHeaders\n return headers\n}\n\n/** Adds `token` to the `vary` header, unless it (or `*`) is already listed. */\nexport function mergeVary(headers: Record<string, HeaderValue>, token: string): void {\n const existing = headers['vary']\n if (existing === undefined) {\n headers['vary'] = token\n return\n }\n const text = typeof existing === 'string' ? existing : existing.join(', ')\n const tokens = text.split(',').map(item => item.trim().toLowerCase())\n if (tokens.includes('*') || tokens.includes(token)) return\n headers['vary'] = text.trim() === '' ? token : `${text}, ${token}`\n}\n","/**\n * Route decisions (RFC 0001 §5.1, §5.2): route decorator groups as known at boot, the effective\n * metadata of a route (the nearest decision of a group wins) and the boot check of required and\n * enforced groups (ZNIGHT023).\n */\nimport type { CoreLogger } from '@znight/core'\nimport type { RouteDecoratorInfo } from './decorators.ts'\nimport type { HttpMetadata } from './metadata.ts'\n\nimport { ErrorCode, ZnightError } from '@znight/core'\n\nimport { GROUP_NAME } from './decorators.ts'\n\n/** Route metadata: key → value. */\nexport type RouteMeta = Readonly<Record<string, unknown>>\n\n/** Where a group declaration comes from (messages). */\ninterface Declaration {\n readonly group: string\n readonly required: boolean\n readonly source: string\n}\n\n/**\n * The route decorator groups of an application: the compiled `groups` metadata, completed by the\n * `enforces` declarations of the guards and the `meta` entries of plugin routes. A key absent from\n * every source is its own group, not required.\n */\nexport class RouteGroups {\n readonly #keys = new Map<string, Declaration>()\n readonly #groups = new Map<string, Declaration>()\n readonly #members = new Map<string, Set<string>>()\n\n /** Reads `metadata.extensions.http.groups` (ZNIGHT007 when malformed). */\n static fromMetadata(groups: HttpMetadata['groups']): RouteGroups {\n const result = new RouteGroups()\n if (groups === undefined) return result\n if (groups === null || typeof groups !== 'object' || Array.isArray(groups)) {\n throw malformed(`expected an object of { keys, required } (received ${describe(groups)})`)\n }\n for (const group of Object.keys(groups)) {\n const entry: unknown = groups[group]\n const { keys, required } = (entry ?? {}) as { keys?: unknown; required?: unknown }\n // a group is named explicitly (grammar) or after its single key (a decorator without group)\n const ownGroup = Array.isArray(keys) && keys.length === 1 && keys[0] === group\n if (!ownGroup && !GROUP_NAME.test(group)) throw malformed(`invalid group name ${JSON.stringify(group)}`)\n if (\n entry === null ||\n typeof entry !== 'object' ||\n !Array.isArray(keys) ||\n keys.length === 0 ||\n !keys.every(key => typeof key === 'string' && key !== '') ||\n new Set(keys).size !== keys.length ||\n typeof required !== 'boolean'\n ) {\n throw malformed(`group \"${group}\" must be { keys: [unique non-empty strings], required: boolean }`)\n }\n for (const key of keys as string[]) {\n const previous = result.#keys.get(key)\n if (previous !== undefined) {\n throw malformed(`the key \"${key}\" belongs to the groups \"${previous.group}\" and \"${group}\"`)\n }\n result.#add(key, { group, required, source: 'the compiled metadata' })\n }\n }\n return result\n }\n\n /**\n * Declares the group of a key (guard `enforces`, plugin route `meta`). A declaration that\n * contradicts an earlier one is ZNIGHT005.\n */\n declare(info: RouteDecoratorInfo, source: string): void {\n const known = this.#keys.get(info.key)\n if (known !== undefined && (known.group !== info.group || known.required !== info.required)) {\n throw conflict(\n `the route decorator \"${info.key}\" is declared with ${describeGroup(info)} by ${source} but with ${describeGroup({ key: info.key, ...known })} by ${known.source}`,\n )\n }\n const group = this.#groups.get(info.group)\n if (group !== undefined && group.required !== info.required) {\n throw conflict(\n `the \"${info.group}\" group is ${info.required ? '' : 'not '}required for \"${info.key}\" (${source}) but ${group.required ? '' : 'not '}required for ${[...(this.#members.get(info.group) ?? [])].map(key => `\"${key}\"`).join(', ')} (${group.source})`,\n )\n }\n if (known === undefined) this.#add(info.key, { group: info.group, required: info.required, source })\n }\n\n /** The group of a key (the key itself when no source declares one). */\n groupOf(key: string): string {\n return this.#keys.get(key)?.group ?? key\n }\n\n /** Groups every route must decide. */\n required(): Set<string> {\n const result = new Set<string>()\n for (const [group, declaration] of this.#groups) if (declaration.required) result.add(group)\n return result\n }\n\n /** Known keys of a group, sorted. */\n keysOf(group: string): string[] {\n return [...(this.#members.get(group) ?? [group])].sort()\n }\n\n #add(key: string, declaration: Declaration): void {\n this.#keys.set(key, declaration)\n if (!this.#groups.has(declaration.group)) this.#groups.set(declaration.group, declaration)\n let members = this.#members.get(declaration.group)\n if (members === undefined) {\n members = new Set()\n this.#members.set(declaration.group, members)\n }\n members.add(key)\n }\n}\n\nfunction describeGroup(info: { readonly key: string; readonly group: string; readonly required: boolean }): string {\n const group = info.group === info.key ? 'its own group' : `the group \"${info.group}\"`\n return info.required ? `${group} (required)` : group\n}\n\n/**\n * The effective metadata of a route: the controller's entries whose group the route does not\n * decide, then every entry of the route. Frozen.\n */\nexport function effectiveMeta(controller: RouteMeta, route: RouteMeta, groupOf: (key: string) => string): RouteMeta {\n const decided = new Set(Object.keys(route).map(groupOf))\n const result: Record<string, unknown> = {}\n for (const key of Object.keys(controller)) {\n if (!decided.has(groupOf(key))) result[key] = controller[key]\n }\n return Object.freeze(Object.assign(result, route))\n}\n\n/** The key of `meta` sharing its group with another key, as `[first, second, group]`. */\nexport function conflictingKeys(\n meta: RouteMeta,\n groupOf: (key: string) => string,\n): readonly [string, string, string] | undefined {\n const seen = new Map<string, string>()\n for (const key of Object.keys(meta)) {\n const group = groupOf(key)\n const first = seen.get(group)\n if (first !== undefined) return [first, key, group]\n seen.set(group, key)\n }\n return undefined\n}\n\n/** The groups listed by `static enforces` of a guard class (ZNIGHT005 when malformed). */\nexport function enforcedBy(guard: unknown, name: string): readonly RouteDecoratorInfo[] {\n if (typeof guard !== 'function') return []\n let enforces: unknown\n try {\n enforces = (guard as { enforces?: unknown }).enforces\n } catch (error) {\n throw invalidEnforces(name, 'reading it threw', error)\n }\n if (enforces === undefined) return []\n if (!Array.isArray(enforces))\n throw invalidEnforces(name, `expected an array of route decorators (received ${describe(enforces)})`)\n for (const entry of enforces as unknown[]) {\n const info = (typeof entry === 'function' || (typeof entry === 'object' && entry !== null) ? entry : {}) as {\n key?: unknown\n group?: unknown\n required?: unknown\n }\n if (typeof info.key !== 'string' || typeof info.group !== 'string' || typeof info.required !== 'boolean') {\n throw invalidEnforces(\n name,\n `every entry must be a route decorator ({ key, group, required }), received ${describe(entry)}`,\n )\n }\n }\n return enforces as readonly RouteDecoratorInfo[]\n}\n\nfunction invalidEnforces(name: string, reason: string, cause?: unknown): ZnightError {\n return new ZnightError(\n ErrorCode.InvalidDecorator,\n `HttpPlugin: invalid static enforces of the guard ${name}: ${reason}`,\n {\n hints: [\n 'static readonly enforces = [Public, Authenticated, Roles] (decorators created with createRouteDecorator)',\n ],\n ...(cause === undefined ? {} : { cause }),\n },\n )\n}\n\n/** A route as seen by the boot check: one per declared route (no HEAD or trailing-slash variant). */\nexport interface CheckedRoute {\n /** `GET /books (BookController.list)`. */\n readonly description: string\n /** Effective metadata. */\n readonly meta: RouteMeta\n /** Groups enforced by the guards of its chain (global, controller, route). */\n readonly enforced: ReadonlySet<string>\n /** Name of the plugin declaring the route, for plugin routes. */\n readonly plugin?: string\n}\n\n/** How the boot check reports problems. */\nexport type EnforcementMode = 'error' | 'warn'\n\n/**\n * The boot check (RFC 0001 §5.2): every route decides every required group, and every decision of\n * a required or enforced group is enforced by a guard of the route's chain. A group is enforced when\n * a guard of some chain, or a guard class of the application (`enforcers`, in a chain or not),\n * declares it: a guard registered nowhere does not make its decisions inert. Problems are reported\n * as one ZNIGHT023 error (`'error'`) or one warning per group (`'warn'`).\n */\nexport function checkDecisions(\n routes: readonly CheckedRoute[],\n groups: RouteGroups,\n mode: EnforcementMode,\n logger: CoreLogger,\n enforcers: ReadonlyMap<string, ReadonlySet<string>> = new Map(),\n): void {\n const required = groups.required()\n const known = new Set<string>(enforcers.keys())\n for (const route of routes) for (const group of route.enforced) known.add(group)\n const problems = new Map<string, { missing: string[]; unenforced: string[]; plugins: Set<string> }>()\n const problem = (group: string): { missing: string[]; unenforced: string[]; plugins: Set<string> } => {\n let entry = problems.get(group)\n if (entry === undefined) {\n entry = { missing: [], unenforced: [], plugins: new Set() }\n problems.set(group, entry)\n }\n return entry\n }\n for (const route of routes) {\n const decided = new Set(Object.keys(route.meta).map(key => groups.groupOf(key)))\n for (const group of required) {\n if (decided.has(group)) continue\n const entry = problem(group)\n entry.missing.push(route.description)\n if (route.plugin !== undefined) entry.plugins.add(route.plugin)\n }\n for (const group of decided) {\n if ((required.has(group) || known.has(group)) && !route.enforced.has(group)) {\n problem(group).unenforced.push(route.description)\n }\n }\n }\n if (problems.size === 0) return\n const messages: string[] = []\n const hints: string[] = []\n for (const group of [...problems.keys()].sort()) {\n const entry = problems.get(group) as { missing: string[]; unenforced: string[]; plugins: Set<string> }\n const keys = groups.keysOf(group)\n const parts: string[] = []\n const groupHints: string[] = []\n if (entry.missing.length > 0) {\n parts.push(\n `${count(entry.missing.length)} ${entry.missing.length === 1 ? 'has' : 'have'} no \"${group}\" decision: ${entry.missing.join(', ')}`,\n )\n groupHints.push(`Add a decision of the \"${group}\" group (${keys.join(', ')}) to the route or to its controller`)\n for (const plugin of [...entry.plugins].sort()) {\n groupHints.push(\n `Routes of the plugin \"${plugin}\" take their metadata from its options: meta: [Decorator.meta()]`,\n )\n }\n }\n if (entry.unenforced.length > 0) {\n parts.push(\n `no guard enforces the ${required.has(group) ? 'required ' : ''}\"${group}\" group on ${count(entry.unenforced.length)}: ${entry.unenforced.join(', ')}`,\n )\n const guards = [...(enforcers.get(group) ?? [])].sort()\n // a guard of the application that enforces the group, else a name for the one to write\n const example = guards[0] ?? guardName(group)\n groupHints.push(\n `Register a guard declaring \\`static enforces\\` with the decorators of the \"${group}\" group (${keys.join(', ')}), e.g. HttpPlugin.configure({ guards: [${example}] })`,\n )\n if (guards.length > 0) {\n groupHints.push(`Guards of the application enforcing the \"${group}\" group: ${guards.join(', ')}`)\n }\n }\n const message = parts.join('; ')\n if (mode === 'warn') {\n logger.warn(`HttpPlugin: ${message}`, { code: ErrorCode.MissingRouteDecision, group })\n } else {\n messages.push(message)\n hints.push(...groupHints)\n }\n }\n if (mode === 'error') {\n hints.push(\"Tests that deliberately run without guards can set enforcement: 'warn'\")\n throw new ZnightError(ErrorCode.MissingRouteDecision, `HttpPlugin: ${capitalize(messages.join('; '))}`, { hints })\n }\n}\n\nfunction count(routes: number): string {\n return routes === 1 ? '1 route' : `${routes} routes`\n}\n\nfunction capitalize(text: string): string {\n return text.charAt(0).toUpperCase() + text.slice(1)\n}\n\n/** A class name for the guard of a group: `rateLimit` → `RateLimitGuard`, `auth:public` → `AuthPublicGuard`. */\nfunction guardName(group: string): string {\n const name = group\n .split(/[^A-Za-z0-9]+/)\n .map(capitalize)\n .join('')\n .replace(/^\\d+/, '')\n return `${name === '' ? 'Decision' : name}Guard`\n}\n\nfunction malformed(reason: string): ZnightError {\n return new ZnightError(ErrorCode.InvalidRoute, `Invalid metadata.extensions.http.groups: ${reason}`)\n}\n\nfunction conflict(reason: string): ZnightError {\n return new ZnightError(ErrorCode.InvalidDecorator, `HttpPlugin: inconsistent route decorator groups: ${reason}`, {\n hints: [\n 'Every definition of a key must use the same options, and the decorators of a group must agree on required',\n 'Regenerate the metadata when createRouteDecorator options changed',\n ],\n })\n}\n\nfunction describe(value: unknown): string {\n try {\n return typeof value === 'function' ? 'a function' : (JSON.stringify(value) ?? String(value))\n } catch {\n return typeof value\n }\n}\n","/**\n * Client side of Server-Sent Events: the WHATWG \"interpreting an event stream\" algorithm over a\n * byte stream (`parseSseStream`), used by `injectSse()` and by tests over real sockets. Import-free.\n */\n\n/** A dispatched event. */\nexport interface SseMessage {\n /** Event type: `message` by default. */\n readonly event: string\n readonly data: string\n /** The last event id at dispatch time (what `EventSource` sends back as `Last-Event-ID`). */\n readonly id: string\n /** `JSON.parse(data)`. */\n json<T = unknown>(): T\n}\n\n/** An item of an event stream: an event, a comment (heartbeats are `''`) or a reconnection delay. */\nexport type SseItem =\n | ({ readonly type: 'event' } & SseMessage)\n | { readonly type: 'comment'; readonly text: string }\n | { readonly type: 'retry'; readonly retry: number }\n\n/** Options of {@link parseSseStream}. */\nexport interface ParseSseOptions {\n /** Stops reading (the body is cancelled) when aborted. */\n readonly signal?: AbortSignal\n}\n\n/**\n * Incremental parser (internal): feed it decoded text, collect the items. Follows the HTML\n * specification: CR, LF and CRLF line ends (a CR at the end of a chunk included), one leading space\n * stripped from values, `data` lines buffered and the final LF removed, `id` values containing NUL\n * ignored, `retry` accepted only as ASCII digits, the type defaulting to `message`, an event without\n * data not dispatched.\n */\nexport class SseParser {\n /** The last event id (updated when an event is dispatched, even without data). */\n lastEventId = ''\n #line = ''\n #skipLf = false\n #data = ''\n #hasData = false\n #type = ''\n #idBuffer = ''\n\n /** Parses a chunk of text; returns the items it completes. */\n push(text: string): SseItem[] {\n const items: SseItem[] = []\n let start = 0\n for (let index = 0; index < text.length; index++) {\n const code = text.charCodeAt(index)\n if (code === 0x0a && this.#skipLf) {\n // the LF of a CRLF (possibly split across chunks)\n this.#skipLf = false\n start = index + 1\n continue\n }\n this.#skipLf = false\n if (code !== 0x0a && code !== 0x0d) continue\n this.#line += text.slice(start, index)\n this.#processLine(this.#line, items)\n this.#line = ''\n start = index + 1\n if (code === 0x0d) this.#skipLf = true\n }\n if (start < text.length) this.#line += text.slice(start)\n return items\n }\n\n #processLine(line: string, items: SseItem[]): void {\n if (line === '') {\n this.#dispatch(items)\n return\n }\n const colon = line.indexOf(':')\n if (colon === 0) {\n items.push({ type: 'comment', text: line.charCodeAt(1) === 0x20 ? line.slice(2) : line.slice(1) })\n return\n }\n const field = colon === -1 ? line : line.slice(0, colon)\n let value = colon === -1 ? '' : line.slice(colon + 1)\n if (value.charCodeAt(0) === 0x20) value = value.slice(1)\n switch (field) {\n case 'event':\n this.#type = value\n break\n case 'data':\n this.#data += `${value}\\n`\n this.#hasData = true\n break\n case 'id':\n if (!value.includes('\\u0000')) this.#idBuffer = value\n break\n case 'retry':\n if (/^\\d+$/.test(value)) items.push({ type: 'retry', retry: Number(value) })\n break\n default:\n break\n }\n }\n\n #dispatch(items: SseItem[]): void {\n this.lastEventId = this.#idBuffer\n if (!this.#hasData) {\n this.#type = ''\n return\n }\n const data = this.#data.endsWith('\\n') ? this.#data.slice(0, -1) : this.#data\n const event = this.#type === '' ? 'message' : this.#type\n const id = this.lastEventId\n items.push({ type: 'event', event, data, id, json: <T = unknown>(): T => JSON.parse(data) as T })\n this.#data = ''\n this.#hasData = false\n this.#type = ''\n }\n}\n\n/**\n * Turns an event stream body (a `fetch()` response body, `injectStream().body`) into its items.\n * UTF-8 is decoded with the BOM stripped; an unterminated event at the end is discarded. Calling\n * `return()` (leaving a `for await` loop) or aborting `signal` cancels the body.\n *\n * ```ts\n * const response = await fetch(`${http.address}/orders/o-1/events`)\n * for await (const item of parseSseStream(response.body!)) {\n * if (item.type === 'event') console.log(item.event, item.json())\n * }\n * ```\n */\nexport function parseSseStream(\n body: ReadableStream<Uint8Array>,\n options: ParseSseOptions = {},\n): AsyncIterableIterator<SseItem> {\n return parseWith(new SseParser(), body, options)\n}\n\n/** {@link parseSseStream} with a given parser (internal: `injectSse()` reads its `lastEventId`). */\nexport function parseWith(\n parser: SseParser,\n body: ReadableStream<Uint8Array>,\n options: ParseSseOptions = {},\n): AsyncIterableIterator<SseItem> {\n const reader = body.getReader()\n const decoder = new TextDecoder('utf-8')\n const queue: SseItem[] = []\n let ended = false\n let cancelled: Promise<void> = Promise.resolve()\n const stop = (): void => {\n if (ended) return\n ended = true\n queue.length = 0\n cancelled = reader.cancel().catch(() => undefined)\n }\n const signal = options.signal\n if (signal !== undefined) {\n if (signal.aborted) stop()\n else signal.addEventListener('abort', stop, { once: true })\n }\n const iterator: AsyncIterableIterator<SseItem> = {\n async next(): Promise<IteratorResult<SseItem>> {\n for (;;) {\n const queued = queue.shift()\n if (queued !== undefined) return { done: false, value: queued }\n if (ended) return { done: true, value: undefined }\n let result: Awaited<ReturnType<typeof reader.read>>\n try {\n result = await reader.read()\n } catch (error) {\n if (ended) return { done: true, value: undefined }\n ended = true\n throw error\n }\n if (result.done) {\n // the decoder may hold the start of a character; an unterminated event is discarded\n parser.push(decoder.decode())\n ended = true\n signal?.removeEventListener('abort', stop)\n return { done: true, value: undefined }\n }\n if (!ended) queue.push(...parser.push(decoder.decode(result.value, { stream: true })))\n }\n },\n async return(): Promise<IteratorResult<SseItem>> {\n stop()\n signal?.removeEventListener('abort', stop)\n await cancelled\n return { done: true, value: undefined }\n },\n [Symbol.asyncIterator](): AsyncIterableIterator<SseItem> {\n return iterator\n },\n }\n return iterator\n}\n","/**\n * `injectSse()`: an in-memory `EventSource` for tests, on top of `injectStream()`. Events are read\n * only when asked for (`next()`, `take()`, iteration, `done`), so a test controls the pace of the\n * client. Opening never waits forever ({@link OPEN_TIMEOUT_MS} per step): without response headers\n * it fails (the request is aborted); without a first chunk (an `@Sse` stream sends `retry` or a\n * comment at once, a hand-written or proxied one may stay quiet) the stream is open anyway, and the\n * read goes on in the background.\n */\nimport type { InjectStreamOptions, InjectStreamRequest, InjectStreamResponse } from './adapter.ts'\nimport type { SetCookieInfo } from './cookies.ts'\n\nimport { isEventStreamType } from './adapters/shared.ts'\nimport { parseWith, type SseItem, type SseMessage, SseParser } from './sse-parse.ts'\n\n/** Options of {@link InjectSseResponse.next} and {@link InjectSseResponse.take}. */\nexport interface InjectSseWaitOptions {\n /** Maximum wait for each event (ms). Default: 2 000. */\n readonly timeoutMs?: number\n}\n\n/** The response of `injectSse()`: an event stream read in memory, like `EventSource` would. */\nexport interface InjectSseResponse extends AsyncIterable<SseMessage>, AsyncDisposable {\n readonly status: number\n readonly headers: Record<string, string | string[]>\n readonly cookies: Readonly<Record<string, SetCookieInfo>>\n /** `''` for an event stream; otherwise the whole body, read to its end (an error, a 204...). */\n readonly body: string\n /** `JSON.parse(body)`. */\n json<T = unknown>(): T\n /** The next event (comments skipped). Rejects on timeout (default 2 000 ms) or when the stream ended. */\n next(options?: InjectSseWaitOptions): Promise<SseMessage>\n /** The next `count` events (the timeout applies to each). */\n take(count: number, options?: InjectSseWaitOptions): Promise<SseMessage[]>\n /** Comments received so far (heartbeats are `''`). */\n readonly comments: readonly string[]\n /** What a browser would send as `Last-Event-ID` on reconnection. */\n readonly lastEventId: string\n /** The last `retry` received (ms). */\n readonly retry: number | undefined\n /** Resolves when the server ends the stream (reading the remaining events, which stay available to `next()`). */\n readonly done: Promise<void>\n /** Disconnects (cancels the body): the server sees a client disconnect. Idempotent. */\n close(): Promise<void>\n /** Reconnects like `EventSource`: closes this stream and sends the same request plus `last-event-id`. */\n reconnect(): Promise<InjectSseResponse>\n}\n\nconst DEFAULT_TIMEOUT_MS = 2_000\n/** How long opening waits for the response headers, then for the first chunk of an event stream (ms). */\nconst OPEN_TIMEOUT_MS = 2_000\nconst DECODER = new TextDecoder()\n\ntype InjectStream = (request: InjectStreamOptions) => Promise<InjectStreamResponse>\n\n/**\n * Opens an event stream with `injectStream` (adds `accept: text/event-stream` when absent), waiting\n * at most `openTimeoutMs` for the response headers, then at most `openTimeoutMs` for the first chunk.\n */\nexport async function openInjectSse(\n injectStream: InjectStream,\n request: InjectStreamOptions,\n openTimeoutMs: number = OPEN_TIMEOUT_MS,\n): Promise<InjectSseResponse> {\n if (request === null || typeof request !== 'object') throw new TypeError('injectSse() expects a request object')\n const headers: Record<string, string> = { ...request.headers }\n if (!Object.keys(headers).some(name => name.toLowerCase() === 'accept')) headers['accept'] = 'text/event-stream'\n const sent: InjectStreamRequest = { ...request, method: request.method ?? 'GET', headers }\n const response = await answered(injectStream, sent, openTimeoutMs)\n if (!isEventStreamType(response.headers['content-type'])) {\n const body = await readText(response.body)\n return new SseClient(injectStream, sent, response, body, openTimeoutMs)\n }\n const client = new SseClient(injectStream, sent, response, '', openTimeoutMs)\n // the first chunk makes `retry` and `comments` known at once; a quiet stream must not hang the test\n await client.ready()\n return client\n}\n\n/**\n * `injectStream(request)`, waiting at most `ms` for the response headers. Past it, the request is\n * aborted (a late response is cancelled: the server sees a client disconnect) and opening fails\n * with an error naming the request, instead of hanging the test.\n */\nasync function answered(\n injectStream: InjectStream,\n request: InjectStreamRequest,\n ms: number,\n): Promise<InjectStreamResponse> {\n const abort = new AbortController()\n const signal = request.signal === undefined ? abort.signal : AbortSignal.any([request.signal, abort.signal])\n const pending = injectStream({ ...request, signal })\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<undefined>(resolve => {\n timer = setTimeout(() => resolve(undefined), ms)\n })\n const response = await Promise.race([pending, timeout]).finally(() => clearTimeout(timer))\n if (response !== undefined) return response\n const message = `injectSse(): no response from ${describe(request)} within ${ms} ms`\n abort.abort(new Error(message))\n void pending.then(\n late => late.body.cancel().catch(() => undefined),\n () => undefined,\n )\n throw new Error(\n `${message}: the handler has not answered, or the adapter holds the response headers until the first byte of the body`,\n )\n}\n\n/** `GET /orders/o-1/events`. */\nfunction describe(request: InjectStreamRequest): string {\n return `${(request.method ?? 'GET').toUpperCase()} ${request.url}`\n}\n\nasync function readText(body: ReadableStream<Uint8Array>): Promise<string> {\n const reader = body.getReader()\n let text = ''\n for (;;) {\n const { done, value } = await reader.read()\n if (done) return text + DECODER.decode()\n text += DECODER.decode(value, { stream: true })\n }\n}\n\nclass SseClient implements InjectSseResponse {\n readonly status: number\n readonly headers: Record<string, string | string[]>\n readonly cookies: Readonly<Record<string, SetCookieInfo>>\n readonly body: string\n readonly #injectStream: InjectStream\n readonly #request: InjectStreamRequest\n readonly #openTimeoutMs: number\n readonly #parser = new SseParser()\n readonly #items: AsyncIterableIterator<SseItem> | undefined\n readonly #events: SseMessage[] = []\n readonly #comments: string[] = []\n #retry: number | undefined\n /** Whether an item (event, comment, `retry`) was read since the stream opened. */\n #received = false\n #ended: boolean\n #failure: unknown\n #reading: Promise<void> | undefined\n #closing: Promise<void> | undefined\n #draining: Promise<void> | undefined\n\n constructor(\n injectStream: InjectStream,\n request: InjectStreamRequest,\n response: InjectStreamResponse,\n body: string,\n openTimeoutMs: number,\n ) {\n this.#injectStream = injectStream\n this.#request = request\n this.#openTimeoutMs = openTimeoutMs\n this.status = response.status\n this.headers = response.headers\n this.cookies = response.cookies\n this.body = body\n const stream = isEventStreamType(response.headers['content-type'])\n this.#ended = !stream\n this.#items = stream ? parseWith(this.#parser, response.body) : undefined\n }\n\n get comments(): readonly string[] {\n return [...this.#comments]\n }\n\n get lastEventId(): string {\n return this.#parser.lastEventId\n }\n\n get retry(): number | undefined {\n return this.#retry\n }\n\n get done(): Promise<void> {\n this.#draining ??= (async (): Promise<void> => {\n while (!this.#ended) await this.#read()\n })()\n return this.#draining\n }\n\n json<T = unknown>(): T {\n return JSON.parse(this.body) as T\n }\n\n /**\n * Reads the first item (the preamble every `@Sse` stream starts with, so that `retry` is known),\n * waiting at most the open timeout: the read of a quiet stream goes on in the background.\n */\n async ready(): Promise<void> {\n await this.#readWithin(this.#openTimeoutMs)\n }\n\n async next(options: InjectSseWaitOptions = {}): Promise<SseMessage> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n if (!(timeoutMs >= 0)) throw new TypeError('injectSse(): timeoutMs must be a number ≥ 0')\n const deadline = Date.now() + timeoutMs\n for (;;) {\n const event = this.#events.shift()\n if (event !== undefined) return event\n if (this.#ended) {\n throw new Error(`injectSse(): the event stream of ${this.#describe()} ended`, {\n ...(this.#failure === undefined ? {} : { cause: this.#failure }),\n })\n }\n const remaining = deadline - Date.now()\n if (remaining <= 0 || !(await this.#readWithin(remaining))) {\n const quiet = this.#received ? '' : ' (the stream has sent nothing since it opened)'\n throw new Error(`injectSse(): no event received within ${timeoutMs} ms from ${this.#describe()}${quiet}`)\n }\n }\n }\n\n async take(count: number, options?: InjectSseWaitOptions): Promise<SseMessage[]> {\n if (!Number.isSafeInteger(count) || count < 0) throw new TypeError('injectSse(): take() expects an integer ≥ 0')\n const events: SseMessage[] = []\n while (events.length < count) events.push(await this.next(options))\n return events\n }\n\n close(): Promise<void> {\n if (this.#closing === undefined) {\n this.#ended = true\n this.#closing =\n this.#items === undefined\n ? Promise.resolve()\n : (this.#items.return?.().then(() => undefined) ?? Promise.resolve())\n }\n return this.#closing\n }\n\n async reconnect(): Promise<InjectSseResponse> {\n await this.close()\n const headers: Record<string, string> = {}\n for (const [name, value] of Object.entries(this.#request.headers ?? {})) {\n if (name.toLowerCase() !== 'last-event-id') headers[name] = value\n }\n // EventSource only sends a non-empty last event id\n if (this.lastEventId !== '') headers['last-event-id'] = this.lastEventId\n return openInjectSse(this.#injectStream, { ...this.#request, headers }, this.#openTimeoutMs)\n }\n\n [Symbol.asyncIterator](): AsyncIterator<SseMessage> {\n return {\n next: async (): Promise<IteratorResult<SseMessage>> => {\n for (;;) {\n const event = this.#events.shift()\n if (event !== undefined) return { done: false, value: event }\n if (this.#ended) return { done: true, value: undefined }\n await this.#read()\n }\n },\n return: async (): Promise<IteratorResult<SseMessage>> => {\n await this.close()\n return { done: true, value: undefined }\n },\n }\n }\n\n [Symbol.asyncDispose](): Promise<void> {\n return this.close()\n }\n\n /** Waits for the next item at most `ms` (the read goes on in the background); `false` on timeout. */\n async #readWithin(ms: number): Promise<boolean> {\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<false>(resolve => {\n timer = setTimeout(() => resolve(false), ms)\n })\n const outcome = await Promise.race([this.#read().then(() => true as const), timeout])\n clearTimeout(timer)\n return outcome\n }\n\n /** Reads one item (one read at a time, shared by concurrent callers). */\n #read(): Promise<void> {\n this.#reading ??= this.#readItem().finally(() => {\n this.#reading = undefined\n })\n return this.#reading\n }\n\n async #readItem(): Promise<void> {\n const items = this.#items\n if (items === undefined || this.#ended) return\n let result: IteratorResult<SseItem>\n try {\n result = await items.next()\n } catch (error) {\n this.#failure = error\n this.#ended = true\n return\n }\n if (result.done === true) {\n this.#ended = true\n return\n }\n const item = result.value\n this.#received = true\n if (item.type === 'comment') this.#comments.push(item.text)\n else if (item.type === 'retry') this.#retry = item.retry\n else this.#events.push({ event: item.event, data: item.data, id: item.id, json: item.json })\n }\n\n #describe(): string {\n return describe(this.#request)\n }\n}\n","/**\n * Server-Sent Events (RFC 0006 §4.6, §4.7): the event encoder, the `HttpResponse.sse()` body marker\n * and the event stream (preamble, pull loop, heartbeats, raw byte passthrough, error handling,\n * graceful close with a jittered `retry`, bounded source stop).\n */\nimport type { RequestAbortKind } from './context.ts'\n\nimport { type ContextRunner, captureContext } from './stream.ts'\n\n/** One event of an event stream. */\nexport interface SseEvent<T = unknown> {\n /** A string is sent as is; anything else goes through `JSON.stringify` (`toJSON` honoured). */\n readonly data?: T\n /** Event type (`addEventListener(type)`). The client defaults to `message`. No CR or LF. */\n readonly event?: string\n /** Last event id, echoed by the client as `Last-Event-ID`. No CR, LF or NUL. `''` resets it. */\n readonly id?: string | number\n /** Reconnection delay in ms (a safe integer ≥ 0). */\n readonly retry?: number\n /** Comment lines, ignored by `EventSource` (debugging, padding). */\n readonly comment?: string\n}\n\n/** Options of `@Sse()` and `HttpResponse.sse()`. */\nexport interface SseOptions {\n /**\n * Milliseconds without an event after which a keep-alive comment (`:`) is sent (an integer\n * from 1 000 to 2 147 483 647). `false` disables it. Default: the plugin option `sse.heartbeat`\n * (8 000).\n */\n readonly heartbeat?: number | false\n /**\n * Client reconnection delay (`retry:`, ms), sent first. Default: the plugin option `sse.retry`\n * (none: browsers use about 3 s).\n */\n readonly retry?: number\n /**\n * The server ends the stream gracefully after this many ms (load rebalancing, re-authentication):\n * `ctx.signal` aborts (`'expired'`), then the client gets a jittered `retry` and reconnects. An\n * integer from 1 000 to 2 147 483 647 (about 24.8 days, the longest timer). Default: none.\n */\n readonly maxDuration?: number\n}\n\n/**\n * What `@Sse` handlers and `HttpResponse.sse()` accept: an async iterable (async generators,\n * `EventChannel`, a Node.js `Readable` of raw bytes), an iterable (arrays, sync generators; not\n * strings) or a `ReadableStream`, of `SseEvent` objects or `Uint8Array` chunks (already-framed SSE\n * text, written as is: proxying an upstream event stream).\n */\nexport type SseSource =\n | AsyncIterable<SseEvent | Uint8Array>\n | Iterable<SseEvent>\n | ReadableStream<SseEvent | Uint8Array>\n\n/** The body of `HttpResponse.sse()`: an event source and its options (served by the plugin). */\nexport class SseBody {\n readonly source: SseSource\n readonly options: SseOptions\n\n constructor(source: SseSource, options: SseOptions = {}) {\n if (!isSseSource(source)) {\n throw new TypeError(\n 'HttpResponse.sse() expects an AsyncIterable, an Iterable or a ReadableStream of SseEvent (not a string)',\n )\n }\n checkSseOptions(options, 'HttpResponse.sse()')\n this.source = source\n this.options = options\n }\n}\n\n/** Whether `value` is an {@link SseBody}. */\nexport function isSseBody(value: unknown): value is SseBody {\n return value instanceof SseBody\n}\n\n/** Whether `value` can be served as an event stream (async iterable, non-string iterable, `ReadableStream`). */\nexport function isSseSource(value: unknown): value is SseSource {\n if (value instanceof ReadableStream) return true\n if (value === null || typeof value !== 'object') return false\n return (\n typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === 'function' ||\n typeof (value as { [Symbol.iterator]?: unknown })[Symbol.iterator] === 'function'\n )\n}\n\n/** Smallest heartbeat and `maxDuration` (ms). */\nexport const MIN_SSE_INTERVAL_MS = 1_000\n/**\n * Longest heartbeat, `maxDuration` and grace period (ms): the longest `setTimeout` delay (larger\n * ones overflow to 1 ms on Node.js and Bun, which would end every stream at once).\n */\nexport const MAX_SSE_TIMER_MS = 2_147_483_647\n\n/**\n * Checks SSE options (`HttpResponse.sse()`, hand-written metadata): `heartbeat` an integer from\n * 1 000 to 2 147 483 647 or `false`, `retry` an integer ≥ 0, `maxDuration` an integer from 1 000 to\n * 2 147 483 647, no other key.\n *\n * @throws TypeError naming `what`.\n */\nexport function checkSseOptions(options: unknown, what: string): void {\n const problem = sseOptionsProblem(options)\n if (problem !== undefined) throw new TypeError(`${what}: ${problem}`)\n}\n\n/** What is wrong with SSE options, `undefined` when they are valid. */\nexport function sseOptionsProblem(options: unknown): string | undefined {\n if (options === null || typeof options !== 'object' || Array.isArray(options)) {\n return 'options must be an object { heartbeat?, retry?, maxDuration? }'\n }\n for (const [key, value] of Object.entries(options)) {\n if (value === undefined) continue\n switch (key) {\n case 'heartbeat':\n if (value !== false && !isInteger(value, MIN_SSE_INTERVAL_MS, MAX_SSE_TIMER_MS)) {\n return `heartbeat must be an integer number of ms from ${MIN_SSE_INTERVAL_MS} to ${MAX_SSE_TIMER_MS}, or false (received ${String(value)})`\n }\n break\n case 'retry':\n if (!isInteger(value, 0)) return `retry must be an integer number of ms ≥ 0 (received ${String(value)})`\n break\n case 'maxDuration':\n if (!isInteger(value, MIN_SSE_INTERVAL_MS, MAX_SSE_TIMER_MS)) {\n return `maxDuration must be an integer number of ms from ${MIN_SSE_INTERVAL_MS} to ${MAX_SSE_TIMER_MS} (received ${String(value)})`\n }\n break\n default:\n return `unknown option \"${key}\" (options: { heartbeat?, retry?, maxDuration? })`\n }\n }\n return undefined\n}\n\nfunction isInteger(value: unknown, min: number, max = Number.MAX_SAFE_INTEGER): boolean {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= min && value <= max\n}\n\n// -------------------------------------------------------------------------------------------------\n// Encoding\n// -------------------------------------------------------------------------------------------------\n\nconst EVENT_KEYS: ReadonlySet<string> = new Set(['data', 'event', 'id', 'retry', 'comment'])\nconst LINE_BREAK = /\\r\\n|\\r|\\n/\n\n/**\n * Encodes one event (WHATWG framing): one `: <line>` per comment line, `id:`, `event:`, `retry:`,\n * then one `data: <line>` per line of the data (split on CRLF, CR and LF, so data can never inject\n * fields or end the event early), and an empty line. An `event` without `data` gets an empty\n * `data:` line (otherwise `EventSource` would not dispatch it); events with only `id`, `retry` or\n * `comment` have no data line.\n *\n * ```ts\n * encodeSseEvent({ id: 41, event: 'status', data: { status: 'paid' } })\n * // 'id: 41\\nevent: status\\ndata: {\"status\":\"paid\"}\\n\\n'\n * ```\n *\n * @throws TypeError for anything but a plain object with the keys of {@link SseEvent} (strings,\n * numbers, `null`: yield `{ data: value }`), an empty event, an `event` / `id` with CR or LF (NUL\n * for `id`), a `retry` that is not an integer ≥ 0, a `data` JSON cannot serialise.\n */\nexport function encodeSseEvent(event: SseEvent): string {\n if (event === null || typeof event !== 'object' || !isPlainObject(event)) {\n throw new TypeError(\n `Invalid SSE event: expected an object { data?, event?, id?, retry?, comment? } (received ${describe(event)}): yield { data: value }`,\n )\n }\n let defined = 0\n for (const key of Object.keys(event)) {\n if (!EVENT_KEYS.has(key)) {\n throw new TypeError(`Invalid SSE event: unknown key \"${key}\" (keys: data, event, id, retry, comment)`)\n }\n if ((event as Record<string, unknown>)[key] !== undefined) defined++\n }\n if (defined === 0) throw new TypeError('Invalid SSE event: an empty event (set data, event, id, retry or comment)')\n const { data, event: type, id, retry, comment } = event\n let text = ''\n if (comment !== undefined) {\n if (typeof comment !== 'string') throw new TypeError('Invalid SSE event: comment must be a string')\n for (const line of comment.split(LINE_BREAK)) text += line === '' ? ':\\n' : `: ${line}\\n`\n }\n if (id !== undefined) {\n const value = typeof id === 'number' && Number.isFinite(id) ? String(id) : id\n if (typeof value !== 'string' || /[\\r\\n\\0]/.test(value)) {\n throw new TypeError('Invalid SSE event: id must be a string without CR, LF or NUL, or a finite number')\n }\n text += `id: ${value}\\n`\n }\n if (type !== undefined) {\n if (typeof type !== 'string' || /[\\r\\n]/.test(type)) {\n throw new TypeError('Invalid SSE event: event must be a string without CR or LF')\n }\n text += `event: ${type}\\n`\n }\n if (retry !== undefined) {\n if (!isInteger(retry, 0)) throw new TypeError('Invalid SSE event: retry must be an integer number of ms ≥ 0')\n text += `retry: ${retry}\\n`\n }\n if (data !== undefined) {\n for (const line of dataText(data).split(LINE_BREAK)) text += `data: ${line}\\n`\n } else if (type !== undefined) {\n text += 'data: \\n'\n }\n return `${text}\\n`\n}\n\nfunction dataText(data: unknown): string {\n if (typeof data === 'string') return data\n let json: string | undefined\n try {\n json = JSON.stringify(data)\n } catch (error) {\n throw new TypeError(`Invalid SSE event: data cannot be serialised as JSON (${errorText(error)})`, { cause: error })\n }\n if (json === undefined) throw new TypeError(`Invalid SSE event: data cannot be serialised as JSON (${typeof data})`)\n return json\n}\n\nfunction isPlainObject(value: object): boolean {\n const prototype: unknown = Object.getPrototypeOf(value)\n return prototype === Object.prototype || prototype === null\n}\n\nfunction describe(value: unknown): string {\n if (value === null) return 'null'\n if (typeof value === 'string') return 'a string'\n if (Array.isArray(value)) return 'an array'\n if (value instanceof Uint8Array) return 'bytes'\n return typeof value === 'object' ? `an instance of ${value.constructor?.name ?? 'a class'}` : typeof value\n}\n\nfunction errorText(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n// -------------------------------------------------------------------------------------------------\n// The event stream\n// -------------------------------------------------------------------------------------------------\n\n/** Default reconnection delay the jitter of the final `retry` starts from (ms). */\nexport const DEFAULT_RECONNECT_MS = 3_000\n/** How long a stopped source may take before the request scope closes anyway (ms). */\nexport const SOURCE_STOP_TIMEOUT_MS = 5_000\n\nconst ENCODER = new TextEncoder()\nconst HEARTBEAT = ENCODER.encode(':\\n\\n')\n\n/** Settings of one event stream (route options resolved over the plugin options). */\nexport interface SseStreamSettings {\n /** Heartbeat interval in ms; `0` disables it. */\n readonly heartbeat: number\n /** `retry` sent first, if any. */\n readonly retry: number | undefined\n /** `maxDuration` in ms, if any. */\n readonly maxDuration: number | undefined\n /** Time the source gets to finish after a graceful close started (ms). */\n readonly graceMs: number\n /** Bound of the source stop (ms). Default: {@link SOURCE_STOP_TIMEOUT_MS}. */\n readonly stopTimeoutMs?: number\n /** Random generator of the jitter (`[0, 1)`). Default: `Math.random`. */\n readonly random?: () => number\n}\n\n/** What the stream reports to the request (its context and its logger). */\nexport interface SseHost {\n /** Aborts `ctx.signal` with `kind`. */\n abort(kind: RequestAbortKind): void\n /** Logs a failure (`The SSE stream failed`) or a warning, with the request id and path. */\n error(message: string, error: unknown): void\n warn(message: string): void\n}\n\n/** A source being read: one pull at a time. */\ninterface SourceReader {\n next(): Promise<IteratorResult<unknown>>\n stop(): Promise<unknown>\n}\n\ntype Settled =\n | { readonly kind: 'value'; readonly value: unknown }\n | { readonly kind: 'done' }\n | { readonly kind: 'error'; readonly error: unknown }\n\n/**\n * One event stream: the byte stream sent to the client and the controls of the pipeline\n * ({@link close} on shutdown or `maxDuration`). The source is read only when the client pulls\n * (backpressure); the first chunk (`retry: N` or the comment `:`) is queued at once so that every\n * adapter flushes the headers.\n */\nexport class SseSession {\n /** The bytes to send (pull-based, `highWaterMark: 0`). */\n readonly stream: ReadableStream<Uint8Array>\n readonly #source: SseSource\n readonly #settings: SseStreamSettings\n readonly #host: SseHost\n readonly #run: ContextRunner\n #reader: SourceReader | undefined\n /** The source read in progress, kept across heartbeats until its item is consumed. */\n #pending: Promise<Settled> | undefined\n /** What {@link #pending} settled with, until {@link #pull} consumes it. */\n #settled: Settled | undefined\n /** Resolves the race waiting for {@link #pending} (one at a time). */\n #onSettled: (() => void) | undefined\n #controller: ReadableStreamDefaultController<Uint8Array> | undefined\n /** `open` → `closing` (graceful close running) → `ended`. */\n #phase: 'open' | 'closing' | 'ended' = 'open'\n /** The raw bytes written so far end at an event boundary (a heartbeat may follow). */\n #atBoundary = true\n /** Raw byte scanner: the current line has content / the previous byte was a CR. */\n #lineHasContent = false\n #afterCr = false\n /** Whether the line the last CR ended was empty (an event boundary, whether a LF follows or not). */\n #crBoundary = false\n #wake: (() => void) | undefined\n #graceTimer: ReturnType<typeof setTimeout> | undefined\n #maxTimer: ReturnType<typeof setTimeout> | undefined\n #stopped: Promise<void> | undefined\n #ended: () => void = () => undefined\n /** Resolves once the stream ended (source done, failed, stopped or cancelled). */\n readonly ended: Promise<void>\n\n constructor(source: SseSource, settings: SseStreamSettings, host: SseHost) {\n this.#source = source\n this.#settings = settings\n this.#host = host\n // the source runs in the handler's async context (request scope, tracing), timers included\n this.#run = captureContext()\n this.ended = new Promise(resolve => {\n this.#ended = resolve\n })\n this.stream = new ReadableStream<Uint8Array>(\n {\n start: controller => {\n this.#controller = controller\n const retry = settings.retry\n controller.enqueue(retry === undefined ? HEARTBEAT : ENCODER.encode(`retry: ${retry}\\n\\n`))\n if (settings.maxDuration !== undefined) {\n this.#maxTimer = unref(setTimeout(() => this.close('expired'), timerDelay(settings.maxDuration)))\n }\n },\n pull: controller => this.#pull(controller),\n cancel: () => this.#cancel(),\n },\n { highWaterMark: 0 },\n )\n }\n\n /** Whether the stream is closing or over. */\n get closed(): boolean {\n return this.#phase !== 'open'\n }\n\n /**\n * Starts the graceful close (shutdown, `maxDuration`): `ctx.signal` aborts with `kind`, the source\n * may yield its final events for `graceMs`, then a jittered `retry` is sent, the source is stopped\n * and the response ends. Idempotent.\n */\n close(kind: 'shutdown' | 'expired'): void {\n if (this.#phase !== 'open') return\n this.#phase = 'closing'\n clearTimeout(this.#maxTimer)\n this.#host.abort(kind)\n this.#graceTimer = unref(setTimeout(() => void this.#endGracefully(), timerDelay(this.#settings.graceMs)))\n this.#wake?.()\n }\n\n async #pull(controller: ReadableStreamDefaultController<Uint8Array>): Promise<void> {\n for (;;) {\n if (this.#phase === 'ended') return\n this.#next()\n const heartbeat =\n this.#phase === 'open' && this.#settings.heartbeat > 0 && this.#atBoundary ? this.#settings.heartbeat : 0\n const outcome = await this.#race(heartbeat)\n // closed or cancelled while waiting\n if (this.#isEnded()) return\n if (outcome === 'heartbeat') {\n controller.enqueue(HEARTBEAT)\n return\n }\n if (outcome === 'wake') continue\n this.#pending = undefined\n this.#settled = undefined\n if (outcome.kind === 'done') {\n await this.#finish()\n return\n }\n if (outcome.kind === 'error') {\n if (!this.#isAbortError(outcome.error)) this.#host.error('The SSE stream failed', outcome.error)\n await this.#finish()\n return\n }\n const value = outcome.value\n if (value instanceof Uint8Array) {\n if (value.byteLength === 0) continue\n this.#scan(value)\n controller.enqueue(value)\n return\n }\n let encoded: string\n try {\n if (!this.#endsAtBoundary()) {\n // an event written after an unterminated raw event would merge into it\n throw new TypeError(\n 'Invalid SSE event: an SseEvent cannot follow raw bytes that do not end at an event boundary (an empty line)',\n )\n }\n encoded = encodeSseEvent(value as SseEvent)\n } catch (error) {\n this.#host.error('The SSE stream failed', error)\n await this.#finish(true)\n return\n }\n controller.enqueue(ENCODER.encode(encoded))\n this.#atBoundary = true\n this.#lineHasContent = false\n this.#afterCr = false\n return\n }\n }\n\n /**\n * Starts the next read of the source, unless one is pending (it is kept across heartbeats). The\n * read gets one reaction for its whole life, which records its outcome: a quiet source does not\n * accumulate a reaction per heartbeat.\n */\n #next(): void {\n if (this.#pending !== undefined) return\n const pending = this.#run(() => {\n try {\n return this.#readerOf().next()\n } catch (error) {\n return Promise.reject(error)\n }\n }).then(\n (result): Settled => (result.done === true ? { kind: 'done' } : { kind: 'value', value: result.value }),\n (error: unknown): Settled => ({ kind: 'error', error }),\n )\n this.#pending = pending\n void pending.then(outcome => {\n if (this.#pending !== pending) return\n this.#settled = outcome\n this.#onSettled?.()\n })\n }\n\n /** Waits for the pending item, a heartbeat delay (`0`: none) or a wake-up (close, cancel). */\n #race(heartbeat: number): Promise<Settled | 'heartbeat' | 'wake'> {\n // settled while nobody waited (after a heartbeat or a wake-up): kept until consumed\n if (this.#settled !== undefined) return Promise.resolve(this.#settled)\n return new Promise(resolve => {\n let timer: ReturnType<typeof setTimeout> | undefined\n let done = false\n const settle = (outcome: Settled | 'heartbeat' | 'wake'): void => {\n if (done) return\n done = true\n clearTimeout(timer)\n if (this.#wake === wake) this.#wake = undefined\n if (this.#onSettled === settled) this.#onSettled = undefined\n resolve(outcome)\n }\n const wake = (): void => settle('wake')\n const settled = (): void => settle(this.#settled as Settled)\n if (heartbeat > 0) timer = unref(setTimeout(() => settle('heartbeat'), timerDelay(heartbeat)))\n this.#wake = wake\n this.#onSettled = settled\n })\n }\n\n /** Tracks whether the raw bytes written so far end at an event boundary (an empty line). */\n #scan(bytes: Uint8Array): void {\n for (const byte of bytes) {\n if (byte === 0x0a && this.#afterCr) {\n // the LF of a CRLF (possibly the first byte of a chunk): the CR decided the boundary\n this.#afterCr = false\n this.#atBoundary = this.#crBoundary\n continue\n }\n this.#afterCr = byte === 0x0d\n if (byte === 0x0a || byte === 0x0d) {\n this.#atBoundary = !this.#lineHasContent\n this.#lineHasContent = false\n if (this.#afterCr) this.#crBoundary = this.#atBoundary\n } else {\n this.#lineHasContent = true\n this.#atBoundary = false\n }\n }\n // a final CR may be the first half of a CRLF: no heartbeat until the next byte tells\n if (this.#afterCr) this.#atBoundary = false\n }\n\n /**\n * Whether the bytes written so far end at an event boundary, for bytes written once the source\n * is over (the final `retry`) or replaced (an encoded event): a final CR ending an empty line\n * counts, since no raw byte will follow it.\n */\n #endsAtBoundary(): boolean {\n return this.#atBoundary || (this.#afterCr && this.#crBoundary)\n }\n\n /**\n * Ends the stream after the source: done, failed, or an invalid item (`stop`: the source is\n * stopped). During a graceful close the jittered `retry` is written first.\n */\n async #finish(stop = false): Promise<void> {\n if (this.#phase === 'ended') return\n const graceful = this.#phase === 'closing'\n this.#phase = 'ended'\n this.#clearTimers()\n const controller = this.#controller as ReadableStreamDefaultController<Uint8Array>\n // never inside an unterminated raw event (the client discards it at the end of the stream)\n if (graceful && this.#endsAtBoundary()) controller.enqueue(this.#finalRetry())\n if (stop) await this.#stop()\n try {\n controller.close()\n } catch {\n // cancelled meanwhile\n }\n this.#ended()\n }\n\n /** The grace period is over: final `retry`, the source is stopped (bounded), the response ends. */\n async #endGracefully(): Promise<void> {\n if (this.#phase !== 'closing') return\n this.#phase = 'ended'\n this.#clearTimers()\n const controller = this.#controller as ReadableStreamDefaultController<Uint8Array>\n // never inside an unterminated raw event (the client discards it at the end of the stream)\n if (this.#endsAtBoundary()) controller.enqueue(this.#finalRetry())\n this.#wake?.()\n await this.#stop()\n try {\n controller.close()\n } catch {\n // cancelled meanwhile\n }\n this.#ended()\n }\n\n /** The client disconnected (or the body was discarded: HEAD, bodyless status, invalid headers). */\n async #cancel(): Promise<void> {\n const wasEnded = this.#phase === 'ended'\n this.#phase = 'ended'\n this.#clearTimers()\n this.#host.abort('client')\n this.#wake?.()\n if (!wasEnded || this.#stopped !== undefined) await this.#stop()\n this.#ended()\n }\n\n /** `retry: R` with R drawn uniformly in [r, 2r] (spreads the reconnections of a rolling deployment). */\n #finalRetry(): Uint8Array {\n const base = this.#settings.retry ?? DEFAULT_RECONNECT_MS\n const random = this.#settings.random ?? Math.random\n return ENCODER.encode(`retry: ${Math.round(base + random() * base)}\\n\\n`)\n }\n\n /**\n * Stops the source (`return()` / `cancel()`) and waits for it at most `stopTimeoutMs`: an async\n * generator blocked in an `await` that ignores `ctx.signal` would hold the request scope forever.\n */\n #stop(): Promise<void> {\n this.#stopped ??= this.#stopBounded()\n return this.#stopped\n }\n\n async #stopBounded(): Promise<void> {\n const timeoutMs = this.#settings.stopTimeoutMs ?? SOURCE_STOP_TIMEOUT_MS\n let timer: ReturnType<typeof setTimeout> | undefined\n const stopping = this.#run(() => {\n try {\n return this.#readerOf().stop()\n } catch {\n return Promise.resolve()\n }\n }).then(\n () => 'stopped' as const,\n () => 'stopped' as const,\n )\n const timeout = new Promise<'timeout'>(resolve => {\n timer = unref(setTimeout(() => resolve('timeout'), timeoutMs))\n })\n const outcome = await Promise.race([stopping, timeout])\n clearTimeout(timer)\n if (outcome === 'timeout') {\n this.#host.warn(\n `The SSE source did not stop within ${timeoutMs} ms after its signal was aborted: make it honour ctx.signal`,\n )\n }\n }\n\n #isEnded(): boolean {\n return this.#phase === 'ended'\n }\n\n #clearTimers(): void {\n clearTimeout(this.#graceTimer)\n clearTimeout(this.#maxTimer)\n }\n\n /** An error caused by the abort of `ctx.signal` (a source honouring it): not a failure. */\n #isAbortError(error: unknown): boolean {\n return this.#phase !== 'open' && (error as { name?: unknown } | null)?.name === 'AbortError'\n }\n\n /** The reader of the source, created on first use (a never-read async generator never runs). */\n #readerOf(): SourceReader {\n this.#reader ??= readerOf(this.#source)\n return this.#reader\n }\n}\n\nfunction readerOf(source: SseSource): SourceReader {\n if (source instanceof ReadableStream) {\n const reader = source.getReader() as unknown as {\n read(): Promise<IteratorResult<unknown>>\n cancel(reason?: unknown): Promise<void>\n }\n return {\n next: () => reader.read(),\n stop: () => reader.cancel(),\n }\n }\n const asyncFactory = (source as { [Symbol.asyncIterator]?: () => AsyncIterator<unknown> })[Symbol.asyncIterator]\n if (typeof asyncFactory === 'function') {\n const iterator = asyncFactory.call(source)\n return {\n next: () => iterator.next(),\n stop: async () => {\n await iterator.return?.()\n },\n }\n }\n const iterator = (source as Iterable<unknown>)[Symbol.iterator]()\n return {\n next: () => Promise.resolve(iterator.next()),\n stop: () => Promise.resolve(iterator.return?.()),\n }\n}\n\n/** A delay `setTimeout` keeps (larger ones overflow to 1 ms): the options are validated, this is a backstop. */\nfunction timerDelay(ms: number): number {\n return Math.min(ms, MAX_SSE_TIMER_MS)\n}\n\nfunction unref<T>(timer: T): T {\n ;(timer as { unref?: () => void }).unref?.()\n return timer\n}\n","import type { HeaderValue } from './exceptions.ts'\n\nimport {\n type ClearCookieOptions,\n type CookieOptions,\n checkCookie,\n givenCookieKey,\n type ResponseCookie,\n} from './cookies.ts'\nimport { type ContentDispositionType, contentDisposition, FileBody, type FileResponseOptions } from './files.ts'\nimport { contentTypeFor, OCTET_STREAM } from './mime.ts'\nimport { SseBody, type SseOptions, type SseSource } from './sse.ts'\nimport { isValidStatus } from './status.ts'\nimport { isStreamSource, type StreamSource, toByteStream } from './stream.ts'\n\n/** Options of {@link HttpResponse.stream}. */\nexport interface StreamResponseOptions {\n /** Media type. Default: from the extension of `filename`, else `application/octet-stream`. */\n readonly contentType?: string\n /** Name proposed to the client (`Content-Disposition: attachment` unless `disposition` says otherwise). */\n readonly filename?: string\n /** `attachment` or `inline`. Default: `attachment` when `filename` is set, otherwise no header. */\n readonly disposition?: ContentDispositionType\n}\n\n/** Options of {@link HttpResponse}. */\nexport interface HttpResponseInit {\n /** Status code. Default: the route default (`@HttpCode`, 201 for POST, 204 without body, 200). */\n readonly status?: number\n /** Response headers (names are case-insensitive; arrays send the header several times). */\n readonly headers?: Readonly<Record<string, HeaderValue>>\n /** Cookies to set (see {@link HttpResponse.withCookie}), in order. */\n readonly cookies?: readonly ResponseCookie[]\n}\n\n/** Redirect statuses accepted by {@link HttpResponse.redirect}. */\nexport type RedirectStatus = 301 | 302 | 303 | 307 | 308\n\n/**\n * A handler result carrying a status and headers next to the body. The body is serialised with the\n * usual rules (objects → JSON, strings → text, bytes and streams → octet-stream).\n *\n * ```ts\n * @Post('/')\n * async create(@Body(CreateUser) input: CreateUser): Promise<HttpResponse<User>> {\n * const user = await this.users.create(input)\n * return HttpResponse.created(user, `/users/${user.id}`)\n * }\n * ```\n *\n * Status precedence: `@HttpCode` > `HttpResponse.status` > route default.\n */\nexport class HttpResponse<T = unknown> {\n readonly body: T\n readonly status: number | undefined\n readonly headers: Readonly<Record<string, HeaderValue>>\n /** Cookies set by this response (`withCookie` / `withoutCookie`), in order; they win over `ctx.setCookie()`. */\n readonly cookies: readonly ResponseCookie[]\n\n constructor(body: T, init: HttpResponseInit = {}) {\n if (init.status !== undefined && !isValidStatus(init.status)) {\n throw new RangeError(`Invalid HTTP status ${String(init.status)} (expected an integer between 100 and 599)`)\n }\n this.body = body\n this.status = init.status\n this.headers = init.headers ?? {}\n this.cookies = init.cookies === undefined ? NO_COOKIES : Object.freeze([...init.cookies])\n }\n\n /** `200 OK` with `body`. */\n static ok<T>(body: T, headers?: Readonly<Record<string, HeaderValue>>): HttpResponse<T> {\n return new HttpResponse(body, headers === undefined ? { status: 200 } : { status: 200, headers })\n }\n\n /**\n * `201 Created`, with a `location` header when given. With a body, the response is typed with it\n * (`Promise<HttpResponse<BookResponse>>` type-checks).\n */\n static created(): HttpResponse<undefined>\n static created<T>(body: T, location?: string): HttpResponse<T>\n static created<T>(body?: T, location?: string): HttpResponse<T | undefined> {\n return new HttpResponse(body, location === undefined ? { status: 201 } : { status: 201, headers: { location } })\n }\n\n /** `202 Accepted`, typed with its body when there is one. */\n static accepted(): HttpResponse<undefined>\n static accepted<T>(body: T): HttpResponse<T>\n static accepted<T>(body?: T): HttpResponse<T | undefined> {\n return new HttpResponse(body, { status: 202 })\n }\n\n /** `204 No Content`. */\n static noContent(): HttpResponse<undefined> {\n return new HttpResponse(undefined, { status: 204 })\n }\n\n /** A redirect (`302 Found` by default) to `location`. */\n static redirect(location: string, status: RedirectStatus = 302): HttpResponse<undefined> {\n return new HttpResponse(undefined, { status, headers: { location } })\n }\n\n /**\n * Sends a file from disk (`string` path or `file:` URL) or a `Blob` / `File`, streamed with\n * `Content-Length`, `Content-Type` (from the extension, see `contentTypeFor`), `Last-Modified`,\n * `ETag` and `Accept-Ranges`. Conditional requests answer 304 / 412 and single byte ranges 206\n * (416 when unsatisfiable). A missing file answers 404.\n *\n * ```ts\n * @Get('/reports/:name')\n * download(@Param('name') name: string) {\n * // `root` confines the path: '../../etc/passwd' answers 404\n * return HttpResponse.file(name, { root: REPORTS_DIR, filename: `rapport ${name}` })\n * }\n * ```\n *\n * Never pass a path built from the request without `root`.\n */\n static file(file: string | URL | Blob, options?: FileResponseOptions): HttpResponse<FileBody> {\n return new HttpResponse(new FileBody(file, options))\n }\n\n /**\n * Streams a Web `ReadableStream`, a Node.js `Readable` or an async iterable (async generator) of\n * `Uint8Array` / `string` chunks. The source is read as the client receives the data\n * (backpressure) and cancelled when the client disconnects; it runs in the request scope.\n *\n * ```ts\n * @Get('/export.csv')\n * export() {\n * return HttpResponse.stream(this.rows.csvLines(), { filename: 'export.csv' }) // text/csv; charset=utf-8\n * }\n * ```\n */\n static stream(source: StreamSource, options: StreamResponseOptions = {}): HttpResponse<ReadableStream<Uint8Array>> {\n if (!isStreamSource(source)) {\n throw new TypeError(\n 'HttpResponse.stream() expects a ReadableStream, a Node.js Readable or an async iterable of Uint8Array / string chunks',\n )\n }\n const headers: Record<string, HeaderValue> = {\n 'content-type':\n options.contentType ??\n (options.filename === undefined ? undefined : contentTypeFor(options.filename)) ??\n OCTET_STREAM,\n }\n const disposition = options.disposition ?? (options.filename === undefined ? undefined : 'attachment')\n if (disposition !== undefined) headers['content-disposition'] = contentDisposition(options.filename, disposition)\n return new HttpResponse(toByteStream(source), { headers })\n }\n\n /**\n * An event stream (Server-Sent Events) on any route and any method: `200` unless `@HttpCode` or\n * {@link withStatus} say otherwise (`EventSource` requires 200; `fetch()` clients read any status),\n * even on `POST` routes. Same source, framing and lifecycle as an `@Sse()` route.\n *\n * ```ts\n * @Post('/:id/assistant')\n * assistant(@Param('id') id: string, @Body(Prompt) prompt: Prompt, @Ctx() ctx: HttpContext) {\n * return HttpResponse.sse(this.llm.complete(id, prompt, { signal: ctx.signal }))\n * }\n * ```\n */\n static sse(source: SseSource, options?: SseOptions): HttpResponse<SseBody> {\n return new HttpResponse(new SseBody(source, options))\n }\n\n /** A copy of this response with `name` set to `value`. */\n withHeader(name: string, value: HeaderValue): HttpResponse<T> {\n return this.#copy({ headers: { ...this.headers, [name.toLowerCase()]: value } })\n }\n\n /** A copy of this response with another status. */\n withStatus(status: number): HttpResponse<T> {\n return this.#copy({ status })\n }\n\n /**\n * A copy of this response setting a cookie, with the secure defaults (`Path=/; Secure; HttpOnly;\n * SameSite=Lax`, see the plugin option `cookies.defaults`). It replaces a cookie with the same name,\n * domain and path set by `ctx.setCookie()` or an earlier `withCookie()`.\n *\n * ```ts\n * return HttpResponse.ok({ id: user.id }).withCookie('__Host-uid', user.id, { signed: true, maxAge: 8 * 3600 })\n * ```\n *\n * The name, the value, the lifetime, the domain, the path and the size are checked now; the rules\n * depending on the plugin (`secure` default with a prefix or `SameSite=None`, signing, the final\n * size) when the response is sent: a violation then answers a generic 500, logged as\n * `Invalid cookie \"name\": …`.\n *\n * @throws TypeError / RangeError for an invalid cookie.\n */\n withCookie(name: string, value: string, options: CookieOptions = {}): HttpResponse<T> {\n checkCookie(name, value, options)\n return this.#copy({ cookies: withCookie(this.cookies, { name, value, options: Object.freeze({ ...options }) }) })\n }\n\n /** A copy of this response clearing a cookie (see `ctx.clearCookie()`). */\n withoutCookie(name: string, options: ClearCookieOptions = {}): HttpResponse<T> {\n if (options === null || typeof options !== 'object') {\n throw new TypeError(`Invalid cookie ${JSON.stringify(String(name))}: options must be an object`)\n }\n const { maxAge: _maxAge, expires: _expires, signed: _signed, ...clear } = options as CookieOptions\n checkCookie(name, undefined, clear)\n return this.#copy({ cookies: withCookie(this.cookies, { name, value: undefined, options: Object.freeze(clear) }) })\n }\n\n #copy(changes: HttpResponseInit): HttpResponse<T> {\n const status = changes.status ?? this.status\n return new HttpResponse(this.body, {\n ...(status === undefined ? {} : { status }),\n headers: changes.headers ?? this.headers,\n cookies: changes.cookies ?? this.cookies,\n })\n }\n}\n\nconst NO_COOKIES: readonly ResponseCookie[] = Object.freeze([])\n\n/** `cookies` with `cookie` added, replacing (in place) a cookie of the same name, domain and path. */\nfunction withCookie(cookies: readonly ResponseCookie[], cookie: ResponseCookie): ResponseCookie[] {\n const key = givenCookieKey(cookie.name, cookie.options)\n const index = cookies.findIndex(existing => givenCookieKey(existing.name, existing.options) === key)\n if (index === -1) return [...cookies, cookie]\n const result = [...cookies]\n result[index] = cookie\n return result\n}\n\n/** Whether `value` is an {@link HttpResponse} (also across duplicated package copies). */\nexport function isHttpResponse(value: unknown): value is HttpResponse {\n if (value instanceof HttpResponse) return true\n if (value === null || typeof value !== 'object') return false\n const type = (value as { constructor?: { name?: unknown } }).constructor\n // object literals and arrays (most handler results): reading a function's name is slow\n if (type === Object || type === Array) return false\n return type?.name === 'HttpResponse' && 'body' in value && 'headers' in value\n}\n","import type { ReplyBody } from './adapter.ts'\nimport type { ResponseCookie } from './cookies.ts'\nimport type { HeaderValue, HttpErrorBody } from './exceptions.ts'\nimport type { ResolvedFile } from './files.ts'\nimport type { HttpResponse } from './response.ts'\nimport type { SseSession } from './sse.ts'\n\nimport { Buffer } from 'node:buffer'\nimport { Readable } from 'node:stream'\n\nimport { isFileBody } from './files.ts'\nimport { isHttpResponse } from './response.ts'\nimport { isSseBody } from './sse.ts'\nimport { isBodylessStatus } from './status.ts'\nimport { discardStream, isByteStream, toByteStream } from './stream.ts'\nimport { fastRecord, isBun } from './utils.ts'\n\nconst ENCODER = new TextEncoder()\n\n/**\n * UTF-8 encoding of a text body: a pooled `Buffer` (a `Uint8Array`) is several times cheaper than\n * `TextEncoder` on Node.js, `TextEncoder` is the fastest on Bun.\n */\nconst utf8: (text: string) => Uint8Array = isBun() ? text => ENCODER.encode(text) : text => Buffer.from(text, 'utf8')\n\n/** Content types set by the serialiser. */\nexport const ContentType: {\n readonly json: string\n readonly text: string\n readonly bytes: string\n readonly eventStream: string\n} = Object.freeze({\n json: 'application/json; charset=utf-8',\n text: 'text/plain; charset=utf-8',\n bytes: 'application/octet-stream',\n eventStream: 'text/event-stream; charset=utf-8',\n})\n\n/** How a handler result is turned into a response. */\nexport interface SerializeOptions {\n /** Request method (`HEAD` responses have no body). */\n readonly method: string\n /** Method of the route definition (`POST` routes default to 201). */\n readonly routeMethod: string\n /** `@HttpCode` status (wins over everything but a Web `Response`). */\n readonly status: number | undefined\n /** `@Header` entries. */\n readonly headers: Readonly<Record<string, string>> | undefined\n /** Headers set on the context (`ctx.setHeader`), applied after `@Header`. */\n readonly context?: Readonly<Record<string, HeaderValue>> | undefined\n}\n\n/** A serialised response (mutable headers, merged by the pipeline). */\nexport interface SerializedReply {\n readonly status: number\n readonly headers: Record<string, HeaderValue>\n readonly body: ReplyBody\n /** The text `body` encodes, for a body serialised from a string (JSON, text). */\n readonly text?: string\n /** Only the serialiser set the headers (content type and length): they are valid by construction. */\n readonly ownHeaders?: boolean\n /** Cookies of the `HttpResponse` (`withCookie`), applied by the pipeline over those of the context. */\n readonly cookies?: readonly ResponseCookie[]\n /** The event stream of the body (`@Sse`, `HttpResponse.sse()`). */\n readonly sse?: SseSession\n}\n\n/**\n * Serialises a handler result:\n *\n * - Web `Response` → sent as is (status, headers, body); `@HttpCode` / `@Header` do not apply;\n * - `HttpResponse` → its body with its status and headers;\n * - `undefined` → empty body, `204` (`201` for POST routes);\n * - `string` → `text/plain`; `Uint8Array`/`ArrayBuffer`/views → `application/octet-stream`;\n * - `ReadableStream`, Node.js `Readable`, `Blob` → streamed (`application/octet-stream` or the blob type);\n * - anything else (objects, arrays, numbers, booleans, `null`) → JSON.\n *\n * Status precedence: `@HttpCode` > `HttpResponse.status` > default (`201` for POST routes,\n * `204` without body, `200`). Header precedence: content type < `@Header` < `ctx.setHeader()` <\n * `HttpResponse.headers` (a Web `Response` keeps its own headers).\n */\nexport function serializeResult(result: unknown, options: SerializeOptions): SerializedReply {\n if (result instanceof Response) {\n const reply = fromWebResponse(result, options.method)\n if (options.context !== undefined) addMissingHeaders(reply.headers, options.context)\n return reply\n }\n let payload = result\n let status: number | undefined\n let extra: Readonly<Record<string, HeaderValue>> | undefined\n let cookies: readonly ResponseCookie[] | undefined\n if (isHttpResponse(result)) {\n payload = result.body\n status = result.status\n extra = result.headers\n cookies = cookiesOf(result)\n }\n const finalStatus = options.status ?? status ?? defaultStatus(options.routeMethod, payload)\n const headers = fastRecord<HeaderValue>()\n const encoded = encode(payload, headers)\n let body: ReplyBody\n let text: string | undefined\n if (typeof encoded === 'string') {\n text = encoded\n body = encodeText(encoded, headers, sendsBody(finalStatus, options.method))\n } else {\n body = encoded\n }\n let own = true\n if (options.headers !== undefined) {\n assignHeaders(headers, options.headers)\n own = false\n }\n if (options.context !== undefined) {\n assignHeaders(headers, options.context)\n own = false\n }\n if (extra !== undefined) {\n assignHeaders(headers, extra)\n own = false\n }\n return withCookies(finish(finalStatus, headers, body, options.method, text, own), cookies)\n}\n\n/**\n * Serialises an event stream (`@Sse` result, `HttpResponse.sse()`): status 200 unless `@HttpCode`\n * or `HttpResponse.status` say otherwise; `cache-control: no-cache, no-transform` and\n * `x-accel-buffering: no` under `@Header`, `ctx.setHeader()` and the `HttpResponse` headers;\n * `content-type: text/event-stream; charset=utf-8` last; never `content-length` or\n * `transfer-encoding`. A `HEAD` request or a bodyless status cancels the stream before its first read.\n */\nexport function serializeSseReply(\n session: SseSession,\n response: HttpResponse | undefined,\n options: SerializeOptions,\n): SerializedReply {\n const status = options.status ?? response?.status ?? 200\n const headers = fastRecord<HeaderValue>()\n headers['cache-control'] = 'no-cache, no-transform'\n headers['x-accel-buffering'] = 'no'\n if (options.headers !== undefined) assignHeaders(headers, options.headers)\n if (options.context !== undefined) assignHeaders(headers, options.context)\n if (response !== undefined) assignHeaders(headers, response.headers)\n headers['content-type'] = ContentType.eventStream\n delete headers['content-length']\n delete headers['transfer-encoding']\n const reply = finish(status, headers, session.stream, options.method)\n return withCookies(reply.body === null ? reply : { ...reply, sse: session }, response && cookiesOf(response))\n}\n\n/** The cookies of an `HttpResponse` (none for a copy of the class from an older package version). */\nfunction cookiesOf(response: HttpResponse): readonly ResponseCookie[] | undefined {\n const cookies = (response as { cookies?: readonly ResponseCookie[] }).cookies\n return Array.isArray(cookies) && cookies.length > 0 ? cookies : undefined\n}\n\nfunction withCookies(reply: SerializedReply, cookies: readonly ResponseCookie[] | undefined): SerializedReply {\n return cookies === undefined ? reply : { ...reply, cookies }\n}\n\n/**\n * Serialises a resolved file response (`HttpResponse.file()`): the file headers, then `@Header`,\n * `ctx.setHeader()` and the `HttpResponse` headers. 206 / 304 keep their status; a 200 follows the\n * usual precedence (`@HttpCode` > `HttpResponse.status` > 200).\n */\nexport function serializeFileReply(\n file: ResolvedFile,\n response: HttpResponse,\n options: SerializeOptions,\n): SerializedReply {\n const status = file.status === 200 ? (options.status ?? response.status ?? 200) : file.status\n const headers = fastRecord<HeaderValue>()\n assignHeaders(headers, file.headers)\n if (options.headers !== undefined) assignHeaders(headers, options.headers)\n if (options.context !== undefined) assignHeaders(headers, options.context)\n assignHeaders(headers, response.headers)\n return withCookies(finish(status, headers, file.body, options.method), cookiesOf(response))\n}\n\n/** `201` for POST routes, otherwise `204` without payload and `200` with one. */\nfunction defaultStatus(routeMethod: string, payload: unknown): number {\n if (routeMethod === 'POST') return 201\n return payload === undefined ? 204 : 200\n}\n\n/** Serialises an error body as JSON. */\nexport function serializeError(status: number, body: HttpErrorBody | unknown, method: string): SerializedReply {\n const headers = fastRecord<HeaderValue>()\n const encoded = encode(body, headers)\n if (typeof encoded !== 'string') return finish(status, headers, encoded, method)\n return finish(status, headers, encodeText(encoded, headers, sendsBody(status, method)), method, encoded)\n}\n\n/** Copies headers with lower-case names (later values win). */\nexport function assignHeaders(\n target: Record<string, HeaderValue>,\n source: Readonly<Record<string, HeaderValue>>,\n): void {\n for (const name of Object.keys(source)) {\n const value = source[name]\n if (value !== undefined) target[name.toLowerCase()] = typeof value === 'string' ? value : [...value]\n }\n}\n\n/** Adds headers that are not already present (case-insensitive). */\nexport function addMissingHeaders(\n target: Record<string, HeaderValue>,\n source: Readonly<Record<string, HeaderValue>>,\n): void {\n for (const name of Object.keys(source)) {\n const key = name.toLowerCase()\n const value = source[name]\n if (value !== undefined && target[key] === undefined) target[key] = typeof value === 'string' ? value : [...value]\n }\n}\n\n/**\n * The reply of a body: `text` is the string `body` encodes (see {@link encodeText}). `own`: only\n * {@link encode} set `headers`, which are then valid for a text body.\n */\nfunction finish(\n status: number,\n headers: Record<string, HeaderValue>,\n body: ReplyBody,\n method: string,\n text?: string,\n own = false,\n): SerializedReply {\n if (isBodylessStatus(status)) {\n discard(body)\n delete headers['content-type']\n delete headers['content-length']\n return { status, headers, body: null }\n }\n if (method === 'HEAD') {\n discard(body)\n return { status, headers, body: null }\n }\n if (text === undefined) return { status, headers, body }\n return own ? { status, headers, body, text, ownHeaders: true } : { status, headers, body, text }\n}\n\nfunction discard(body: ReplyBody): void {\n if (body instanceof ReadableStream) discardStream(body)\n}\n\n/** Whether a reply with this status, to this method, carries its body (see {@link finish}). */\nfunction sendsBody(status: number, method: string): boolean {\n return method !== 'HEAD' && !isBodylessStatus(status)\n}\n\n/**\n * Sets the `content-length` of a text body (right after its `content-type`, before the route\n * headers) and returns its UTF-8 bytes: their length is the header, a lone surrogate counting as\n * U+FFFD. `null` when the reply sends no body (`HEAD`, bodyless status): nothing is encoded then,\n * `Buffer.byteLength` counts the same bytes.\n */\nfunction encodeText(text: string, headers: Record<string, HeaderValue>, sent: boolean): Uint8Array | null {\n if (!sent) {\n headers['content-length'] = String(Buffer.byteLength(text, 'utf8'))\n return null\n }\n const bytes = utf8(text)\n headers['content-length'] = String(bytes.byteLength)\n return bytes\n}\n\n/**\n * The body of a payload, its `content-type` and, for bytes, its `content-length` set in `headers`.\n * Text (a string, JSON) is returned as a string: {@link encodeText} sets its length and encodes it.\n */\nfunction encode(payload: unknown, headers: Record<string, HeaderValue>): ReplyBody | string {\n if (payload === undefined) return null\n if (typeof payload === 'string') return text(payload, headers, ContentType.text)\n if (payload instanceof Uint8Array) return bytes(payload, headers, ContentType.bytes)\n if (payload instanceof ArrayBuffer) return bytes(new Uint8Array(payload), headers, ContentType.bytes)\n if (ArrayBuffer.isView(payload)) {\n return bytes(new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength), headers, ContentType.bytes)\n }\n if (payload instanceof ReadableStream) {\n headers['content-type'] = ContentType.bytes\n // adapters get bytes (`ReplyBody`): string / ArrayBuffer chunks of a returned stream are converted\n return isByteStream(payload) ? (payload as ReadableStream<Uint8Array>) : toByteStream(payload)\n }\n if (payload instanceof Blob) {\n headers['content-type'] = payload.type === '' ? ContentType.bytes : payload.type\n headers['content-length'] = String(payload.size)\n return payload\n }\n if (isNodeReadable(payload)) {\n headers['content-type'] = ContentType.bytes\n return toByteStream(payload)\n }\n if (isFileBody(payload)) throw new TypeError('A file body (HttpResponse.file()) cannot be serialised here')\n if (isSseBody(payload)) throw new TypeError('An event stream (HttpResponse.sse()) cannot be serialised here')\n const json = JSON.stringify(payload)\n if (json === undefined) throw new TypeError(`Cannot serialise a ${typeof payload} as a response body`)\n return text(json, headers, ContentType.json)\n}\n\nfunction bytes(data: Uint8Array, headers: Record<string, HeaderValue>, type: string): Uint8Array {\n headers['content-type'] = type\n headers['content-length'] = String(data.byteLength)\n return data\n}\n\nfunction text(data: string, headers: Record<string, HeaderValue>, type: string): string {\n headers['content-type'] = type\n return data\n}\n\nfunction isNodeReadable(value: unknown): value is Readable {\n return (\n value instanceof Readable ||\n (value !== null &&\n typeof value === 'object' &&\n typeof (value as { pipe?: unknown }).pipe === 'function' &&\n typeof (value as { on?: unknown }).on === 'function' &&\n typeof (value as { read?: unknown }).read === 'function')\n )\n}\n\nfunction fromWebResponse(response: Response, method: string): SerializedReply {\n const headers = fastRecord<HeaderValue>()\n for (const [name, value] of response.headers) {\n if (name !== 'set-cookie') headers[name] = value\n }\n const cookies = response.headers.getSetCookie()\n if (cookies.length > 0) headers['set-cookie'] = cookies\n return finish(response.status, headers, response.body, method)\n}\n","import type { TypedToken } from '@znight/core'\nimport type { HttpContext, RequestId } from './context.ts'\nimport type { HttpPlugin } from './plugin.ts'\n\n/**\n * Tokens of the values `@znight/http` supplies to the container. `HttpContext` and `RequestId` are\n * request-scoped externals (declared in the package manifest): inject them in request-scoped\n * providers or through `Lazy<HttpContext>`.\n */\nexport const HttpTokens: {\n /** The {@link HttpContext} of the current request (request scope). */\n readonly Context: TypedToken<HttpContext>\n /** The id of the current request (request scope). */\n readonly RequestId: TypedToken<RequestId>\n /** The {@link HttpPlugin} instance (singleton). */\n readonly Plugin: TypedToken<HttpPlugin>\n} = Object.freeze({\n Context: '@znight/http#HttpContext',\n RequestId: '@znight/http#RequestId',\n Plugin: '@znight/http#HttpPlugin',\n})\n","import type { Container, CoreLogger, Hooks, HttpRequestEvent, OpenedScope, Token } from '@znight/core'\nimport type { AdapterHandler, AdapterReply, AdapterRequest, ReplyBody } from './adapter.ts'\nimport type { CookieSettings } from './cookie-settings.ts'\nimport type { SerializedCookie } from './cookies.ts'\nimport type { CorsPolicy } from './cors.ts'\nimport type { CanActivate, ExceptionMapper, HttpInterceptor } from './interfaces.ts'\nimport type { HttpRouteDefinition, HttpSseDefinition } from './metadata.ts'\nimport type { TrustPolicy } from './proxy.ts'\nimport type { RouteTable } from './router.ts'\nimport type { BodyPlan } from './uploads.ts'\n\nimport { Buffer } from 'node:buffer'\nimport { displayName } from '@znight/core'\n\nimport { isEventStreamType } from './adapters/shared.ts'\nimport { type HttpRouteInfo, RequestContext, type RequestId } from './context.ts'\nimport { DEFAULT_COOKIE_SETTINGS, serializeWith } from './cookie-settings.ts'\nimport { corsReplyHeaders, isPreflight, mergeVary, preflightHeaders } from './cors.ts'\nimport {\n BadRequestException,\n ForbiddenException,\n type HeaderValue,\n HttpException,\n isHttpException,\n MethodNotAllowedException,\n NotFoundException,\n} from './exceptions.ts'\nimport { isFileBody, resolveFile } from './files.ts'\nimport { findInvalidHeader, isHeaderValue } from './headers.ts'\nimport { decodePathValue, matchRoutePath, type RoutePath, type RouteSegment, WILDCARD_PARAM } from './path.ts'\nimport { type RequestTarget, splitUrl } from './query.ts'\nimport { HttpResponse, isHttpResponse } from './response.ts'\nimport {\n addMissingHeaders,\n assignHeaders,\n ContentType,\n type SerializedReply,\n type SerializeOptions,\n serializeError,\n serializeFileReply,\n serializeResult,\n serializeSseReply,\n} from './serialize.ts'\nimport { isSseBody, isSseSource, type SseOptions, SseSession, type SseSource } from './sse.ts'\nimport { isBodylessStatus } from './status.ts'\nimport { type ContextRunner, captureContext, discardStream, trackStream } from './stream.ts'\nimport { HttpTokens } from './tokens.ts'\nimport { emptyRecord, errorMessage, isBun, isThenable } from './utils.ts'\n\n/** A dependency of the pipeline: an instance resolved at bootstrap, or a token resolved per request. */\nexport type Resolvable<T> = { readonly instance: T } | { readonly token: Token }\n\n/** Everything the pipeline needs to serve one registered route (internal). */\nexport interface RoutePlan {\n readonly definition: HttpRouteDefinition\n /** The registered path (a trailing-slash variant has an extra empty static segment). */\n readonly path: RoutePath\n readonly info: HttpRouteInfo\n readonly controller: Resolvable<object>\n readonly guards: readonly Resolvable<CanActivate>[]\n readonly interceptors: readonly Resolvable<HttpInterceptor>[]\n /** Parse the body before the interceptors (`@Body()` or upload parameters). */\n readonly parseBody: boolean\n /** Body limit and multipart rules of the route. */\n readonly body: BodyPlan\n /** Trailing-slash variant answered with a redirect to the path without its trailing slash. */\n readonly redirect?: boolean\n}\n\n/** Pipeline settings (resolved plugin options). */\nexport interface PipelineOptions {\n readonly adapter: string\n /** Body plan of unmatched requests (plugin `bodyLimit`, generic multipart rules). */\n readonly body: BodyPlan\n readonly exposeErrors: boolean\n readonly requestIdHeader: string | undefined\n readonly generateRequestId: () => string\n readonly mappers: readonly Resolvable<ExceptionMapper>[]\n /** CORS policy (`cors` option), `undefined` when disabled. */\n readonly cors?: CorsPolicy | undefined\n /** Security headers added to every reply that does not set them (`securityHeaders` option). */\n readonly securityHeaders?: Readonly<Record<string, string>>\n /** `trustProxy` policy, `undefined` when proxies are not trusted. */\n readonly trustProxy?: TrustPolicy | undefined\n /** Cookie defaults and signing key (`cookies` option). Default: secure defaults, no signing. */\n readonly cookies?: CookieSettings\n /** Event stream defaults (`sse` option). */\n readonly sse?: SseSettings\n}\n\n/** Resolved plugin option `sse`. */\nexport interface SseSettings {\n /** Heartbeat interval in ms; `0`: none. */\n readonly heartbeat: number\n /** `retry` sent first, if any. */\n readonly retry: number | undefined\n /** Time a source gets to finish after a graceful close started (ms). */\n readonly shutdownGraceMs: number\n}\n\n/** Default event stream settings. */\nexport const DEFAULT_SSE_SETTINGS: SseSettings = Object.freeze({\n heartbeat: 8_000,\n retry: undefined,\n shutdownGraceMs: 1_000,\n})\n\ntype Target =\n | { readonly kind: 'route'; readonly plan: RoutePlan }\n | { readonly kind: 'error'; readonly error: unknown }\n | { readonly kind: 'options'; readonly allow: string }\n | { readonly kind: 'redirect'; readonly location: string }\n /** A CORS preflight; `allow` is `undefined` when no route has the path (404). */\n | { readonly kind: 'preflight'; readonly allow: string | undefined }\n\n/** The CORS decision of a request (an `origin` header and a CORS policy). */\ninterface CorsDecision {\n readonly policy: CorsPolicy\n readonly origin: string\n readonly allowed: boolean\n}\n\nconst RAW = Symbol('raw response')\ntype Outcome = SerializedReply | typeof RAW\n\n/** A reply whose `HttpResponse` cookies were serialised (see `#checkCookies`). */\ntype CheckedReply = SerializedReply & { readonly cookieLines?: readonly SerializedCookie[] }\n\nconst REQUEST_ID = /^[\\w\\-.:@/+=]{1,128}$/\n\nconst MAX_PATH_IN_MESSAGE = 200\n\n/** The default request id generator: a random UUID (version 4, like `crypto.randomUUID()`). */\nexport function randomRequestId(): string {\n return uuid()\n}\n\n/** Random bytes of the next UUIDs (Node.js), refilled every {@link UUID_BATCH} ids. */\nconst UUID_BATCH = 128\nconst uuidPool = new Uint8Array(16 * UUID_BATCH)\nlet uuidOffset = uuidPool.length\n/** The text of the last UUID, its dashes in place. */\nconst uuidText = Buffer.alloc(36, 0x2d)\n/** The two lower-case hexadecimal digits of each byte, as character codes. */\nconst HEX_CODES = new Uint8Array(512)\nfor (let byte = 0; byte < 256; byte++) {\n const digits = byte.toString(16).padStart(2, '0')\n HEX_CODES[byte * 2] = digits.charCodeAt(0)\n HEX_CODES[byte * 2 + 1] = digits.charCodeAt(1)\n}\n\nfunction putHex(position: number, byte: number): void {\n uuidText[position] = HEX_CODES[byte * 2] as number\n uuidText[position + 1] = HEX_CODES[byte * 2 + 1] as number\n}\n\n/**\n * A random version 4 UUID written from a pool of random bytes (`crypto.getRandomValues`), as Node.js\n * does, but read as one flat string: `crypto.randomUUID()` returns a concatenation of 20 pieces that\n * is flattened again when the header is written, which makes it about twice as slow.\n */\nfunction pooledUuid(): string {\n if (uuidOffset === uuidPool.length) {\n crypto.getRandomValues(uuidPool)\n uuidOffset = 0\n }\n const pool = uuidPool\n const at = uuidOffset\n uuidOffset = at + 16\n putHex(0, pool[at] as number)\n putHex(2, pool[at + 1] as number)\n putHex(4, pool[at + 2] as number)\n putHex(6, pool[at + 3] as number)\n putHex(9, pool[at + 4] as number)\n putHex(11, pool[at + 5] as number)\n putHex(14, ((pool[at + 6] as number) & 0x0f) | 0x40)\n putHex(16, pool[at + 7] as number)\n putHex(19, ((pool[at + 8] as number) & 0x3f) | 0x80)\n putHex(21, pool[at + 9] as number)\n putHex(24, pool[at + 10] as number)\n putHex(26, pool[at + 11] as number)\n putHex(28, pool[at + 12] as number)\n putHex(30, pool[at + 13] as number)\n putHex(32, pool[at + 14] as number)\n putHex(34, pool[at + 15] as number)\n return readUuidText()\n}\n\n/**\n * The text of {@link uuidText}: Node.js `Buffer#latin1Slice` (what `toString('latin1')` calls after\n * checking its arguments) when present.\n */\nconst readUuidText: () => string =\n typeof (uuidText as { latin1Slice?: unknown }).latin1Slice === 'function'\n ? () => (uuidText as unknown as { latin1Slice(start: number, end: number): string }).latin1Slice(0, 36)\n : () => uuidText.toString('latin1', 0, 36)\n\n/** UUID generator: Bun's native `crypto.randomUUID()` is the fastest there. */\nconst uuid: () => string = isBun() ? () => crypto.randomUUID() : pooledUuid\n\n/**\n * The request pipeline (architecture §9.1):\n * `runInScope({ HttpContext, RequestId }) → hooks.run('http:request') → guards → body → interceptors\n * → invoke → serialise`, errors being mapped to responses inside `hooks.run`.\n */\nexport class Pipeline {\n readonly #container: Container\n readonly #hooks: Hooks\n readonly #logger: CoreLogger\n readonly #options: PipelineOptions\n readonly #table: RouteTable<RoutePlan>\n /** The `securityHeaders` option as entries (lower-case names, values validated at boot). */\n readonly #securityHeaders: readonly (readonly [string, string])[]\n /** Every request id can be sent: an incoming one matched `REQUEST_ID`, the generated ones are UUIDs. */\n readonly #validIds: boolean\n /**\n * The headers of a JSON reply of the fast lane, in their final order (content type and length,\n * then the framework headers, see {@link #frameworkHeaders}): copied, then completed with the\n * length and the request id.\n */\n readonly #jsonHeaders: Readonly<Record<string, HeaderValue>>\n /** The request id header of {@link #jsonHeaders}, `undefined` when the reply has none. */\n readonly #jsonIdHeader: string | undefined\n /** The headers of a reply without body of the fast lane (the framework headers, see {@link #jsonHeaders}). */\n readonly #emptyHeaders: Readonly<Record<string, HeaderValue>>\n /** The request id header of {@link #emptyHeaders}, `undefined` when the reply has none. */\n readonly #emptyIdHeader: string | undefined\n /** Whether {@link #jsonHeaders} and {@link #emptyHeaders} hold every framework header (see {@link #fastRoute}). */\n readonly #fastHeaders: boolean\n /** The `cookies` option (secure defaults, no signing, when not set). */\n readonly #cookies: CookieSettings\n #inflight = 0\n #idle: (() => void)[] = []\n /** Open event streams. */\n readonly #streams = new Set<SseSession>()\n /** Set while the server drains: responses ask clients to close their connection. */\n draining = false\n\n constructor(\n container: Container,\n hooks: Hooks,\n logger: CoreLogger,\n options: PipelineOptions,\n table: RouteTable<RoutePlan>,\n ) {\n this.#container = container\n this.#hooks = hooks\n this.#logger = logger\n this.#options = options\n this.#table = table\n this.#validIds = options.generateRequestId === randomRequestId\n this.#cookies = options.cookies ?? DEFAULT_COOKIE_SETTINGS\n this.#securityHeaders = Object.entries(options.securityHeaders ?? {}).map(\n ([name, value]) => [name.toLowerCase(), value] as const,\n )\n // what #complete adds to the headers of serializeResult for a JSON value or no value (no CORS,\n // not draining), with a placeholder where the request id goes\n const placeholder = '-' as RequestId\n const idHeader = options.requestIdHeader\n // plain objects: a spread copies them several times faster than a record without prototype\n const json: Record<string, HeaderValue> = { 'content-type': ContentType.json, 'content-length': '0' }\n this.#frameworkHeaders(json, placeholder, undefined, false)\n this.#jsonHeaders = json\n this.#jsonIdHeader = idHeader !== undefined && json[idHeader] === placeholder ? idHeader : undefined\n const empty: Record<string, HeaderValue> = {}\n this.#frameworkHeaders(empty, placeholder, undefined, false)\n this.#emptyHeaders = empty\n this.#emptyIdHeader = idHeader !== undefined && empty[idHeader] === placeholder ? idHeader : undefined\n // a header named like a property of Object.prototype (`__proto__`, `constructor`...) is not an own\n // property of these plain objects: such options take the general pipeline\n this.#fastHeaders =\n (idHeader === undefined || !(idHeader in Object.prototype)) &&\n this.#securityHeaders.every(([name]) => !(name in Object.prototype))\n }\n\n /** Number of requests being processed. */\n get inflight(): number {\n return this.#inflight\n }\n\n /** Number of open event streams. */\n get streams(): number {\n return this.#streams.size\n }\n\n /**\n * Starts the graceful close of every open event stream (`ctx.signal` aborts with `kind`, the source\n * gets `shutdownGraceMs` to finish, then the client receives a jittered `retry`).\n */\n closeStreams(kind: 'shutdown' | 'expired'): void {\n for (const session of [...this.#streams]) session.close(kind)\n }\n\n /** Resolves once no request is being processed. */\n whenIdle(): Promise<void> {\n if (this.#inflight === 0) return Promise.resolve()\n return new Promise(resolve => this.#idle.push(resolve))\n }\n\n /**\n * The adapter handler of a route: {@link handle}, or a fast lane for the routes that need no\n * guard, interceptor, event stream, raw response nor `@Header` when CORS is off (see\n * {@link #fast}).\n */\n handler(plan: RoutePlan): AdapterHandler {\n const route = this.#fastRoute(plan)\n if (route === undefined) return request => this.handle(plan, request)\n return request => this.#fast(route, request)\n }\n\n /** The fast lane of a route, `undefined` when the route needs the general pipeline. */\n #fastRoute(plan: RoutePlan): FastRoute | undefined {\n const definition = plan.definition\n if (\n !this.#fastHeaders ||\n this.#options.cors !== undefined ||\n plan.redirect === true ||\n plan.guards.length > 0 ||\n plan.interceptors.length > 0 ||\n definition.sse !== undefined ||\n definition.rawResponse === true ||\n definition.headers !== undefined ||\n definition.method === 'ALL'\n ) {\n return undefined\n }\n // the statuses of serializeResult: `@HttpCode` > 201 for POST routes > 200 (JSON) or 204 (none)\n const post = definition.method === 'POST'\n const json = definition.status ?? (post ? 201 : 200)\n return {\n plan,\n target: { kind: 'route', plan },\n method: definition.method,\n // a HEAD reply has no body: JSON results of an explicit `@Head` route take the general pipeline\n jsonStatus: definition.method === 'HEAD' || isBodylessStatus(json) ? undefined : json,\n emptyStatus: definition.status ?? (post ? 201 : 204),\n }\n }\n\n /**\n * The fast lane: what {@link handle} does for a route of {@link #fastRoute}, decided once instead\n * of per request, without promises while the route stays synchronous. A request takes it when no\n * `http:request` wrapper nor listener is registered, the server is not draining and its method\n * is the route's (not a `HEAD` served by a `GET` route); a plain object or array returned by the\n * handler is serialised as JSON, and `undefined` answered without body, with the headers in their\n * final order (a template precomputed at boot).\n * A thenable result is awaited in the lane (see {@link #fastAsync}). Anything else — a malformed\n * path (before the request starts), a thrown error or a rejection, an `HttpResponse`, a `Response`\n * or any other result, headers or cookies set through the context — continues in the general\n * pipeline, in the same request scope, with the same outcome.\n */\n #fast(route: FastRoute, request: AdapterRequest): Promise<AdapterReply> {\n const plan = route.plan\n const hooks = this.#hooks\n if (\n this.draining ||\n request.method !== route.method ||\n hooks.hasWrappers('http:request') ||\n hooks.hasListeners('http:request')\n ) {\n return this.handle(plan, request)\n }\n const url = request.url\n const mark = url.indexOf('?')\n const path = mark === -1 ? url : url.slice(0, mark)\n const params = routeParams(plan.path, path)\n // an unusual path (see #route): nothing started yet, the general pipeline handles it\n if (params === undefined) return this.handle(plan, request)\n this.#enter()\n let ctx: RequestContext\n try {\n const query = mark === -1 ? '' : url.slice(mark + 1)\n ctx = this.#context(request, this.#requestId(request), path, query, plan.info, params, plan.body)\n } catch (error) {\n this.#leave()\n return Promise.reject(error)\n }\n const scope = this.#container.openScope([\n [HttpTokens.Context, ctx],\n [HttpTokens.RequestId, ctx.requestId],\n ])\n const done = scope.run(this.#fastRun, route, request, ctx)\n if (done instanceof Exchange) {\n ;(done.done as Promise<void>).then(\n () => this.#end(done, scope, undefined),\n (error: unknown) => this.#end(done, scope, error),\n )\n if (!hooks.hasListeners('http:request')) return done.replied\n done.tracked = true\n return this.#emitted(done)\n }\n const closing = scope.close()\n if (closing === undefined) {\n ctx.complete()\n this.#leave()\n } else {\n const x = new Exchange(request, ctx, ctx.requestId, route.target)\n x.answer(done)\n closing.then(\n () => this.#over(x),\n (error: unknown) => this.#disposalFailed(x, error),\n )\n }\n // a listener registered while the handler ran (listeners are checked once the scope callback paused)\n if (!hooks.hasListeners('http:request')) return Promise.resolve(done)\n const event = requestEvent(request, ctx, performance.now())\n event.status = done.status\n return Promise.resolve(done).then(reply => {\n hooks.emit('http:request', event)\n return reply\n })\n }\n\n /**\n * The fast lane in the request scope: the reply when the handler answered synchronously with a\n * plain JSON value or `undefined`, otherwise the exchange finishing the request (see {@link #fast}).\n */\n readonly #fastRun = (route: FastRoute, request: AdapterRequest, ctx: RequestContext): AdapterReply | Exchange => {\n const plan = route.plan\n if (plan.parseBody) return this.#fastLater(route, request, ctx, NO_RESULT)\n let result: unknown\n let reply: AdapterReply | undefined\n try {\n result = plan.definition.invoke(this.#resolve(plan.controller), ctx)\n if (isThenable(result)) return this.#fastLater(route, request, ctx, result)\n reply = this.#fastReply(route, ctx, result)\n } catch (error) {\n const x = new Exchange(request, ctx, ctx.requestId, route.target)\n x.done = this.#respond(x, () => this.#failed(error, ctx, x.event))\n return x\n }\n if (reply !== undefined) {\n ctx.commit()\n ctx.releaseBody()\n return reply\n }\n const x = new Exchange(request, ctx, ctx.requestId, route.target)\n x.done = this.#respond(x, () => this.#settle(ctx, plan, x.event, result))\n return x\n }\n\n /** The fast lane of a route with a body to read or a handler that returned a thenable. */\n #fastLater(route: FastRoute, request: AdapterRequest, ctx: RequestContext, result: unknown): Exchange {\n const x = new Exchange(request, ctx, ctx.requestId, route.target)\n x.done = this.#fastAsync(x, route, result)\n return x\n }\n\n /**\n * The asynchronous part of the fast lane, in the request scope: the body read (`result` is\n * {@link NO_RESULT}) and the handler run, or the thenable it returned awaited. Never rejects.\n */\n async #fastAsync(x: Exchange, route: FastRoute, pending: unknown): Promise<void> {\n const ctx = x.ctx\n const plan = route.plan\n let result = pending\n let reply: AdapterReply | undefined\n try {\n if (result === NO_RESULT) {\n const controller = this.#resolve(plan.controller)\n await ctx.parseBody()\n result = plan.definition.invoke(controller, ctx)\n }\n if (isThenable(result)) result = await result\n reply = this.#fastReply(route, ctx, result)\n } catch (error) {\n await this.#respond(x, () => this.#failed(error, ctx, x.event))\n return\n }\n if (reply === undefined) {\n const value = result\n await this.#respond(x, () => this.#settle(ctx, plan, x.event, value))\n return\n }\n ctx.commit()\n ctx.releaseBody()\n // a listener registered since the request started gets a complete event\n if (x.tracked) x.event.status = reply.status\n x.answer(reply)\n }\n\n /**\n * The reply of a plain JSON value (see {@link isPlainJson}) or of `undefined`: what\n * `serializeResult` and {@link #complete} produce for it, the headers in their final order.\n * `undefined` when the result or the context needs the general pipeline. Throws like\n * `JSON.stringify`.\n */\n #fastReply(route: FastRoute, ctx: RequestContext, result: unknown): AdapterReply | undefined {\n const status = result === undefined ? route.emptyStatus : route.jsonStatus\n // draining since the request started (`connection: close`, see #frameworkHeaders)\n if (status === undefined || ctx.hasResponseHeaders || ctx.hasCookies || this.draining) return undefined\n const requestId = ctx.requestId\n // a custom generator's id that cannot be sent is left out (see #frameworkHeaders)\n if (!this.#validIds && !isHeaderValue(requestId)) return undefined\n if (result === undefined) {\n const headers: Record<string, HeaderValue> = { ...this.#emptyHeaders }\n const idHeader = this.#emptyIdHeader\n if (idHeader !== undefined) headers[idHeader] = requestId\n return { status, headers, body: null }\n }\n if (!isPlainJson(result)) return undefined\n const json = JSON.stringify(result)\n if (json === undefined) throw new TypeError(`Cannot serialise a ${typeof result} as a response body`)\n const headers: Record<string, HeaderValue> = { ...this.#jsonHeaders }\n // encoded once, its length from the bytes (see serialize.ts encodeText)\n const body = utf8(json)\n headers['content-length'] = String(body.byteLength)\n const idHeader = this.#jsonIdHeader\n if (idHeader !== undefined) headers[idHeader] = requestId\n return { status, headers, body, text: json }\n }\n\n /** Ends a fast-lane request once its asynchronous part settled: its scope is closed, then it is over. */\n #end(x: Exchange, scope: OpenedScope, error: unknown): void {\n const closing = scope.close()\n if (error !== undefined) {\n // like runInScope: the scope closes, then the failure is reported (#respond never rejects)\n const report = (): void => this.#disposalFailed(x, error)\n if (closing === undefined) report()\n else closing.then(report, report)\n return\n }\n if (closing === undefined) this.#over(x)\n else\n closing.then(\n () => this.#over(x),\n (failure: unknown) => this.#disposalFailed(x, failure),\n )\n }\n\n #disposalFailed(x: Exchange, error: unknown): void {\n this.#over(x)\n this.#logger.error('Failed to dispose request-scoped providers', { err: error, requestId: x.requestId })\n }\n\n /**\n * Handles a request routed to `plan` by the adapter. The request stays in flight (and its scope\n * open) until a streamed or file response body has been fully read or cancelled by the adapter.\n */\n handle(plan: RoutePlan, request: AdapterRequest): Promise<AdapterReply> {\n const startTime = performance.now()\n try {\n return this.#isPreflight(request) ? this.#preflight(request, startTime) : this.#route(plan, request, startTime)\n } catch (error) {\n return Promise.reject(error)\n }\n }\n\n #route(plan: RoutePlan, request: AdapterRequest, startTime: number, rerouted = false): Promise<AdapterReply> {\n const url = splitUrl(request.url)\n const raw = matchRoutePath(plan.path, url.path)\n // the native router matched a path the Znight grammar rejects (e.g. an empty `:param` in Fastify)\n // or a normalised path (Hono): route the raw path with the route table instead\n if (raw === undefined) return this.#fallback(request, undefined, startTime, !rerouted)\n if (plan.redirect === true) {\n const canonical = sameOriginPath(url.path.slice(0, -1))\n const location = url.query === '' ? canonical : `${canonical}?${url.query}`\n const target: Target = { kind: 'redirect', location }\n return this.#serve(request, url, undefined, emptyRecord(), target, startTime, plan.body)\n }\n const params = emptyRecord<string>()\n let malformed: string | undefined\n for (const name of Object.keys(raw)) {\n const decoded = decodePathValue(raw[name] as string)\n if (decoded === undefined) malformed ??= name\n else params[name] = decoded\n }\n const target: Target =\n malformed === undefined\n ? { kind: 'route', plan }\n : { kind: 'error', error: new BadRequestException(`Malformed URL parameter \"${malformed}\"`) }\n return this.#serve(request, url, plan.info, params, target, startTime, plan.body)\n }\n\n /** Handles an unmatched request (404, 405, automatic OPTIONS) or a framework error. */\n fallback(request: AdapterRequest, error?: unknown): Promise<AdapterReply> {\n const startTime = performance.now()\n try {\n return this.#fallback(request, error, startTime)\n } catch (failure) {\n return Promise.reject(failure)\n }\n }\n\n #fallback(request: AdapterRequest, error: unknown, startTime: number, reroute = true): Promise<AdapterReply> {\n const body = this.#options.body\n if (error !== undefined) {\n const target: Target = { kind: 'error', error: frameworkError(error) }\n return this.#serve(request, splitUrl(request.url), undefined, emptyRecord(), target, startTime, body)\n }\n if (this.#isPreflight(request)) return this.#preflight(request, startTime)\n const url = splitUrl(request.url)\n const path = url.path\n if (reroute) {\n // routing happens on the raw path: serve a route the adapter's router missed (Hono routes the\n // WHATWG-normalised URL, where `/files/%2e%2e/x` became `/x`)\n const plan = this.#table.find(request.method, path)\n if (plan !== undefined) return this.#route(plan, request, startTime, true)\n }\n const allowed = this.#table.allowedMethods(path)\n let target: Target\n if (allowed.length === 0) {\n target = { kind: 'error', error: new NotFoundException(`Cannot ${request.method} ${truncate(path)}`) }\n } else if (request.method === 'OPTIONS') {\n target = { kind: 'options', allow: allowHeader(allowed) }\n } else {\n // OPTIONS is answered automatically, hence supported (RFC 9110 §15.5.6: the same list as OPTIONS)\n target = {\n kind: 'error',\n error: new MethodNotAllowedException(\n `Method ${request.method} is not allowed on ${truncate(path)}`,\n undefined,\n {\n headers: { allow: allowHeader(allowed) },\n },\n ),\n }\n }\n return this.#serve(request, url, undefined, emptyRecord(), target, startTime, body)\n }\n\n /** A CORS preflight (with the `cors` option): answered without running any route. */\n #isPreflight(request: AdapterRequest): boolean {\n return this.#options.cors !== undefined && isPreflight(request.method, request.headers)\n }\n\n #preflight(request: AdapterRequest, startTime: number): Promise<AdapterReply> {\n const url = splitUrl(request.url)\n const allowed = this.#table.allowedMethods(url.path)\n const target: Target = { kind: 'preflight', allow: allowed.length === 0 ? undefined : allowHeader(allowed) }\n return this.#serve(request, url, undefined, emptyRecord(), target, startTime, this.#options.body)\n }\n\n #serve(\n request: AdapterRequest,\n url: RequestTarget,\n route: HttpRouteInfo | undefined,\n params: Record<string, string>,\n target: Target,\n startTime: number,\n body: BodyPlan,\n ): Promise<AdapterReply> {\n this.#enter()\n let x: Exchange\n try {\n const requestId = this.#requestId(request)\n const ctx = this.#context(request, requestId, url.path, url.query, route, params, body)\n // an event stream requested while draining is served (guards run) with its signal already\n // aborted: a well-behaved source ends at once and the client gets a jittered retry\n if (this.draining && target.kind === 'route' && target.plan.definition.sse !== undefined) ctx.abort('shutdown')\n x = new Exchange(request, ctx, requestId, target, startTime)\n } catch (error) {\n // failed before its scope opened (a request id generator that throws...)\n this.#leave()\n return Promise.reject(error)\n }\n // the scope (request-scoped instances) stays open until a streamed or file body has been sent or abandoned\n this.#container\n .runInScope(\n () => this.#respond(x, undefined),\n [\n [HttpTokens.Context, x.ctx],\n [HttpTokens.RequestId, x.requestId],\n ],\n )\n .then(\n () => this.#over(x),\n (error: unknown) => {\n this.#over(x)\n // #respond never rejects: only the disposal of request-scoped instances can fail\n this.#logger.error('Failed to dispose request-scoped providers', { err: error, requestId: x.requestId })\n },\n )\n // listeners run once the reply is ready, before the adapter gets it, out of the request scope\n return this.#hooks.hasListeners('http:request') ? this.#emitted(x) : x.replied\n }\n\n /** The reply of a request once the `http:request` listeners saw its event. */\n #emitted(x: Exchange): Promise<AdapterReply> {\n return x.replied.then(reply => {\n this.#hooks.emit('http:request', x.event)\n return reply\n })\n }\n\n /** The request context of a request (internal). */\n #context(\n request: AdapterRequest,\n requestId: RequestId,\n path: string,\n query: string,\n route: HttpRouteInfo | undefined,\n params: Record<string, string>,\n body: BodyPlan,\n ): RequestContext {\n const proxy = this.#options.trustProxy\n return new RequestContext(\n request,\n requestId,\n this.#options.adapter,\n path,\n query,\n route,\n params,\n body,\n this.#cookies,\n proxy === undefined\n ? undefined\n : proxy.resolve(request.remoteAddress ?? request.ip, request.headers, request.encrypted === true),\n )\n }\n\n /**\n * Answers a request in its scope: its outcome (`process`, or the target of the exchange after the\n * CORS decision and through the `http:request` wrappers), checked, completed and handed to the\n * adapter; a streamed body is then tracked until it was sent or abandoned. Never rejects.\n * `process` is given by the fast lane, which decided at the start of the request that no wrapper\n * applies and that CORS is off.\n */\n async #respond(x: Exchange, process: (() => Outcome | Promise<Outcome>) | undefined): Promise<void> {\n const ctx = x.ctx\n const requestId = x.requestId\n const event = x.event\n let outcome: Outcome | undefined\n let hookError: unknown\n let failed = false\n let run: ContextRunner | undefined\n // only a wrapper can change a reply between its checks below and the adapter\n let recheck = false\n let work = process\n if (work === undefined) {\n if (this.#options.cors !== undefined) x.cors = await this.#corsDecision(x.request, requestId)\n recheck = this.#hooks.hasWrappers('http:request')\n const target = x.target\n work = () => this.#process(ctx, target, event, x.cors)\n }\n try {\n if (recheck) {\n const inner = work\n await this.#hooks.run('http:request', event, async () => {\n outcome = this.#checked(await inner(), ctx, event)\n // stream producers run in the context of the handler (scope, wrappers)\n if (outcome !== RAW && isStreamed(outcome.body)) run = captureContext()\n return outcome\n })\n } else {\n // what hooks.run() does without wrappers, in the same async context\n outcome = this.#checked(await work(), ctx, event)\n }\n } catch (error) {\n failed = true\n hookError = error\n }\n if (outcome === undefined) {\n // a wrapper failed before the request was handled, or did not call next(): answer anyway\n const error = failed ? hookError : new Error('An \"http:request\" hook wrapper did not call next()')\n event.error ??= error\n // the same checks as a handled reply: an exception mapper's HttpResponse may carry cookies\n const fallback = await this.#errorReply(error, ctx)\n outcome = this.#checkCookies(this.#checkHeaders(fallback, ctx, event), ctx, event)\n event.status = outcome.status\n recheck = true\n } else if (failed) {\n this.#logger.error('An \"http:request\" hook wrapper failed after the request was handled', {\n err: hookError,\n requestId,\n })\n }\n if (outcome === RAW) {\n ctx.commit()\n const status = x.request.rawStatus?.() ?? 200\n event.status ??= status\n x.answer({ status, headers: {}, body: null, raw: true })\n return\n }\n const serialized = this.#complete(outcome, ctx, event, requestId, x.cors, x.preflight, recheck)\n const body = serialized.body\n if (!isStreamed(body)) {\n const reply = adapterReply(serialized, body)\n ctx.commit()\n ctx.releaseBody()\n x.answer(reply)\n return\n }\n // files too: a file-backed Blob is read lazily, after the handler returned\n const tracked = trackStream(body, run ?? captureContext(), () => ctx.abort('client'))\n const session = serialized.sse\n const reply = adapterReply(serialized, tracked.stream, body instanceof Blob ? body : undefined)\n if (session !== undefined) {\n this.#streams.add(session)\n if (this.draining) session.close('shutdown')\n }\n ctx.commit()\n x.answer(reply)\n const failure = await tracked.done\n if (session !== undefined) this.#streams.delete(session)\n if (failure !== undefined) {\n this.#logger.error('The response stream failed', { err: failure, requestId, path: ctx.path })\n }\n ctx.releaseBody()\n }\n\n /** The request is over (response body sent or abandoned, scope closed). */\n #over(x: Exchange): void {\n const ctx = x.ctx\n ctx.complete()\n try {\n if (!x.answered) {\n const failure = new Error('Request not handled')\n const reply = serializeError(500, this.#internalBody(failure), ctx.method)\n const completed = this.#complete(reply, ctx, x.event, x.requestId, x.cors, x.preflight, true)\n x.event.status = 500\n x.answer(completed)\n }\n } catch (error) {\n x.fail(error)\n } finally {\n this.#leave()\n }\n }\n\n /**\n * Adds the headers of the `http:request` wrappers, then the framework headers (see\n * {@link #frameworkHeaders}). When wrappers ran (`recheck`), checks the final headers again (see\n * {@link #checkHeaders}): the reply was checked before, and the cookies and framework headers are\n * valid by construction.\n */\n #complete(\n reply: CheckedReply,\n ctx: RequestContext,\n event: HttpRequestEvent,\n requestId: RequestId,\n cors: CorsDecision | undefined,\n preflight: boolean,\n recheck: boolean,\n ): SerializedReply {\n addMissingHeaders(reply.headers, event.responseHeaders)\n applyCookies(reply, ctx)\n this.#frameworkHeaders(reply.headers, requestId, cors, preflight)\n if (!recheck) return reply\n const checked = this.#checkHeaders(reply, ctx, event)\n if (checked !== reply) {\n applyCookies(checked, ctx)\n this.#frameworkHeaders(checked.headers, requestId, cors, preflight)\n }\n return checked\n }\n\n /** Checks the headers (unless only the serialiser set them), then the cookies of a reply. */\n #checked(outcome: Outcome, ctx: RequestContext, event: HttpRequestEvent): Outcome {\n if (outcome === RAW) return outcome\n const checked = outcome.ownHeaders === true ? outcome : this.#checkHeaders(outcome, ctx, event)\n return this.#checkCookies(checked, ctx, event)\n }\n\n /**\n * Serialises the cookies of an `HttpResponse` (`withCookie`) with the plugin settings (defaults,\n * signing). A cookie breaking a rule that depends on them (a prefix with the `secure` default,\n * `SameSite=None` without `secure`, signing without secrets, the size after signing) turns the\n * reply into a plain 500, logged as `Invalid cookie \"x\": …` (like an invalid header).\n */\n #checkCookies(reply: SerializedReply, ctx: RequestContext, event: HttpRequestEvent): CheckedReply {\n const cookies = reply.cookies\n if (cookies === undefined || cookies.length === 0) return reply\n const settings = this.#cookies\n const lines: SerializedCookie[] = []\n try {\n for (const cookie of cookies) lines.push(serializeWith(cookie, settings))\n } catch (error) {\n if (reply.body instanceof ReadableStream) discardStream(reply.body)\n event.error = error\n event.status = 500\n this.#log(error, ctx)\n return serializeError(500, this.#internalBody(error), ctx.method)\n }\n return { ...reply, cookieLines: lines }\n }\n\n /**\n * Headers the plugin adds to every reply when nothing set them: the request id, the CORS headers\n * of an allowed origin (`vary: origin` whatever the origin) or, with a wildcard policy, of every\n * reply (`access-control-allow-origin: *` does not depend on the request, so a cached reply serves\n * CORS and non-CORS requests alike), the security headers; and `connection: close` while\n * draining.\n */\n #frameworkHeaders(\n headers: Record<string, HeaderValue>,\n requestId: RequestId,\n cors: CorsDecision | undefined,\n preflight: boolean,\n ): void {\n const header = this.#options.requestIdHeader\n if (header !== undefined && headers[header] === undefined && (this.#validIds || isHeaderValue(requestId))) {\n headers[header] = requestId\n }\n const policy = this.#options.cors\n if (policy !== undefined) {\n // a preflight answer carries its own CORS headers; other replies get them for allowed origins,\n // or always with a wildcard policy (with or without an origin header: no vary needed)\n if (!preflight) {\n if (policy.wildcard) addMissingHeaders(headers, corsReplyHeaders(policy, '*'))\n else if (cors?.allowed === true) addMissingHeaders(headers, corsReplyHeaders(policy, cors.origin))\n }\n if (policy.varyOrigin) mergeVary(headers, 'origin')\n }\n for (const [name, value] of this.#securityHeaders) if (headers[name] === undefined) headers[name] = value\n if (this.draining) headers['connection'] = 'close'\n }\n\n /**\n * The CORS decision of a request carrying an `origin` header, made once before the hooks run. An\n * origin function that throws or rejects denies the origin (logged).\n */\n async #corsDecision(request: AdapterRequest, requestId: RequestId): Promise<CorsDecision | undefined> {\n const policy = this.#options.cors\n const origin = request.headers['origin']\n if (policy === undefined || origin === undefined) return undefined\n let allowed = false\n try {\n // an origin that cannot be echoed in a response header is never allowed\n allowed = isHeaderValue(origin) && (await policy.allows(origin)) === true\n } catch (error) {\n this.#logger.error('The CORS origin check failed: the origin is denied', { err: error, requestId, origin })\n }\n return { policy, origin, allowed }\n }\n\n /**\n * A reply with a header no adapter can send (`ctx.setHeader('x', 'a\\r\\nb')`, a redirect to a\n * client-provided URL with CR/LF, a non Latin-1 value...) becomes a plain 500, identical on every\n * adapter: its body is discarded (a stream is cancelled) and the error logged.\n */\n #checkHeaders(reply: SerializedReply, ctx: RequestContext, event: HttpRequestEvent): SerializedReply {\n const name = findInvalidHeader(reply.headers)\n if (name === undefined) return reply\n if (reply.body instanceof ReadableStream) discardStream(reply.body)\n const error = new TypeError(`Invalid response header ${JSON.stringify(truncate(name))}: invalid name or value`)\n event.error = error\n event.status = 500\n this.#log(error, ctx)\n return serializeError(500, this.#internalBody(error), ctx.method)\n }\n\n /** The outcome of a request: its route run, or a reply of the framework. Never rejects (errors are mapped). */\n #process(\n ctx: RequestContext,\n target: Target,\n event: HttpRequestEvent,\n cors: CorsDecision | undefined,\n ): Promise<Outcome> {\n return target.kind === 'route' ? this.#invoke(ctx, target.plan, event) : this.#answer(ctx, target, event, cors)\n }\n\n /** Answers a request without running a route. Never rejects. */\n async #answer(\n ctx: RequestContext,\n target: Exclude<Target, { readonly kind: 'route' }>,\n event: HttpRequestEvent,\n cors: CorsDecision | undefined,\n ): Promise<SerializedReply> {\n try {\n switch (target.kind) {\n case 'error':\n throw target.error\n case 'preflight':\n // never runs guards, interceptors or handlers (@Options and @All routes included)\n if (target.allow === undefined) throw new NotFoundException(`Cannot OPTIONS ${truncate(ctx.path)}`)\n if (cors === undefined || !cors.allowed) throw new ForbiddenException('CORS origin not allowed')\n return this.#finish(event, {\n status: 204,\n headers: withContextHeaders(preflightHeaders(cors.policy, cors.origin, ctx.headers, target.allow), ctx),\n body: null,\n })\n case 'options':\n return this.#finish(event, {\n status: 204,\n headers: withContextHeaders({ allow: target.allow }, ctx),\n body: null,\n })\n case 'redirect':\n return this.#finish(\n event,\n serializeResult(undefined, {\n method: ctx.method,\n routeMethod: ctx.method,\n status: 308,\n headers: { location: target.location },\n }),\n )\n }\n } catch (error) {\n return await this.#failed(error, ctx, event)\n }\n }\n\n /** The reply of an error (see {@link #errorReply}), recorded on the event. */\n async #failed(error: unknown, ctx: RequestContext, event: HttpRequestEvent): Promise<SerializedReply> {\n event.error = error\n const reply = await this.#errorReply(error, ctx)\n event.status = reply.status\n return reply\n }\n\n /** Runs a route: guards, body, interceptors, handler, serialisation. Never rejects (errors are mapped). */\n async #invoke(ctx: RequestContext, plan: RoutePlan, event: HttpRequestEvent): Promise<Outcome> {\n let result: unknown\n try {\n const controller = this.#resolve(plan.controller)\n for (const guard of plan.guards) {\n const allowed = await this.#resolve(guard).canActivate(ctx)\n if (allowed !== true) throw new ForbiddenException('Forbidden resource')\n }\n if (plan.parseBody) await ctx.parseBody()\n const definition = plan.definition\n const interceptors = plan.interceptors\n if (interceptors.length === 0) {\n result = definition.invoke(controller, ctx)\n } else {\n const chain = async (index: number): Promise<unknown> => {\n if (index === interceptors.length) return await definition.invoke(controller, ctx)\n const interceptor = this.#resolve(interceptors[index] as Resolvable<HttpInterceptor>)\n return await interceptor.intercept(ctx, () => chain(index + 1))\n }\n result = chain(0)\n }\n } catch (error) {\n return await this.#failed(error, ctx, event)\n }\n const settled = this.#settle(ctx, plan, event, result)\n return settled instanceof Promise ? await settled : settled\n }\n\n /**\n * The rest of {@link #invoke} once the handler (and its interceptors) returned `result`: awaited\n * when it is a thenable, then serialised. Never throws nor rejects (errors are mapped).\n */\n #settle(ctx: RequestContext, plan: RoutePlan, event: HttpRequestEvent, result: unknown): Outcome | Promise<Outcome> {\n if (isThenable(result)) return this.#settleLater(ctx, plan, event, result)\n try {\n const outcome = this.#outcome(ctx, plan, event, result)\n return outcome instanceof Promise ? outcome.catch(error => this.#failed(error, ctx, event)) : outcome\n } catch (error) {\n return this.#failed(error, ctx, event)\n }\n }\n\n async #settleLater(\n ctx: RequestContext,\n plan: RoutePlan,\n event: HttpRequestEvent,\n pending: PromiseLike<unknown>,\n ): Promise<Outcome> {\n let result: unknown\n try {\n result = await pending\n } catch (error) {\n return await this.#failed(error, ctx, event)\n }\n const settled = this.#settle(ctx, plan, event, result)\n return settled instanceof Promise ? await settled : settled\n }\n\n /**\n * The outcome of a handler result: `RAW` for a `@Res()` route, otherwise its reply (files resolved,\n * event streams opened: only an `HttpResponse` may need an asynchronous step). Throws (or rejects)\n * when the result cannot be served.\n */\n #outcome(ctx: RequestContext, plan: RoutePlan, event: HttpRequestEvent, result: unknown): Outcome | Promise<Outcome> {\n const definition = plan.definition\n if (definition.rawResponse === true && !(result instanceof Response)) return RAW\n const options: SerializeOptions = {\n method: ctx.method,\n routeMethod: definition.method,\n status: definition.status,\n headers: definition.headers,\n context: ctx.hasResponseHeaders ? ctx.responseHeaders : undefined,\n }\n const sse = definition.sse\n if (sse !== undefined && !(result instanceof Response) && !isHttpResponse(result)) {\n // an @Sse route: the (awaited) result is the event source\n if (!isSseSource(result)) {\n throw new TypeError(\n `@Sse handler ${displayName(plan.info.controller)}.${definition.handler} must return an AsyncIterable, an Iterable or a ReadableStream of SseEvent (received ${describeResult(result)})`,\n )\n }\n return this.#finish(event, serializeSseReply(this.#openStream(result, sseOptions(sse), ctx), undefined, options))\n }\n if (!isHttpResponse(result)) return this.#finish(event, serializeResult(result, options))\n return this.#serialize(result, ctx, options, sse).then(reply => this.#finish(event, reply))\n }\n\n /** Serialises a handler (or exception mapper) result; file bodies are resolved, event streams opened. */\n async #serialize(\n result: unknown,\n ctx: RequestContext,\n options: SerializeOptions,\n route?: HttpSseDefinition,\n ): Promise<SerializedReply> {\n if (isHttpResponse(result)) {\n if (isFileBody(result.body)) return serializeFileReply(await resolveFile(result.body, ctx), result, options)\n if (isSseBody(result.body)) {\n const body = result.body\n // HttpResponse.sse() options win over the @Sse options of the route\n const merged = { ...(route === undefined ? {} : sseOptions(route)), ...definedOptions(body.options) }\n return serializeSseReply(this.#openStream(body.source, merged, ctx), result, options)\n }\n }\n return serializeResult(result, options)\n }\n\n /** An event stream reading `source` in the request (route options over the plugin `sse` option). */\n #openStream(source: SseSource, options: SseOptions, ctx: RequestContext): SseSession {\n const settings = this.#options.sse ?? DEFAULT_SSE_SETTINGS\n const heartbeat = options.heartbeat === undefined ? settings.heartbeat : options.heartbeat || 0\n const retry = options.retry ?? settings.retry\n const logger = this.#logger\n return new SseSession(\n source,\n {\n heartbeat,\n retry,\n maxDuration: options.maxDuration,\n graceMs: settings.shutdownGraceMs,\n },\n {\n abort: kind => ctx.abort(kind),\n error: (message, error) => logger.error(message, { err: error, requestId: ctx.requestId, path: ctx.path }),\n warn: message => logger.warn(message, { requestId: ctx.requestId, path: ctx.path }),\n },\n )\n }\n\n #finish(event: HttpRequestEvent, reply: SerializedReply): SerializedReply {\n event.status = reply.status\n return reply\n }\n\n /** Maps an error to a reply: exception mappers first, then the default rendering. Never throws. */\n async #errorReply(error: unknown, ctx: RequestContext): Promise<SerializedReply> {\n for (const mapper of this.#options.mappers) {\n let mapped: unknown\n try {\n mapped = await this.#resolve(mapper).map(error, ctx)\n } catch (mapperError) {\n this.#logger.error('An exception mapper failed', { err: mapperError, requestId: ctx.requestId })\n continue\n }\n if (mapped === undefined) continue\n try {\n if (isHttpResponse(mapped) && mapped.status === undefined) {\n // an error response without explicit status keeps the status of the error\n mapped = new HttpResponse(mapped.body, {\n status: isHttpException(error) ? error.status : 500,\n headers: mapped.headers,\n cookies: (mapped as { cookies?: HttpResponse['cookies'] }).cookies ?? [],\n })\n }\n if (mapped instanceof Response || isHttpResponse(mapped)) {\n return await this.#serialize(mapped, ctx, {\n method: ctx.method,\n routeMethod: ctx.method,\n status: undefined,\n headers: undefined,\n context: ctx.hasResponseHeaders ? ctx.responseHeaders : undefined,\n })\n }\n if (isHttpException(mapped)) return this.#renderException(mapped, ctx, error)\n } catch (renderError) {\n this.#logger.error('Failed to render the result of an exception mapper', {\n err: renderError,\n requestId: ctx.requestId,\n })\n continue\n }\n this.#logger.warn(\n 'An exception mapper returned an unsupported value (expected HttpException, HttpResponse, Response or undefined)',\n {\n requestId: ctx.requestId,\n },\n )\n }\n return this.#renderException(error, ctx, error)\n }\n\n #renderException(error: unknown, ctx: RequestContext, original: unknown): SerializedReply {\n let status: number\n let body: unknown\n let extra: Readonly<Record<string, HeaderValue>> | undefined\n if (isHttpException(error)) {\n status = error.status\n try {\n body = error.toBody()\n } catch (bodyError) {\n this.#log(bodyError, ctx)\n status = 500\n body = this.#internalBody(bodyError)\n }\n extra = error.headers\n if (status >= 500) this.#log(original, ctx)\n } else {\n status = 500\n body = this.#internalBody(error)\n this.#log(error, ctx)\n }\n let reply: SerializedReply\n try {\n reply = serializeError(status, body, ctx.method)\n } catch (serializeFailure) {\n this.#log(serializeFailure, ctx)\n reply = serializeError(500, this.#internalBody(serializeFailure), ctx.method)\n extra = undefined\n }\n if (ctx.hasResponseHeaders) assignHeaders(reply.headers, ctx.responseHeaders)\n if (extra !== undefined) assignHeaders(reply.headers, extra)\n return reply\n }\n\n #internalBody(error: unknown): object {\n return this.#options.exposeErrors\n ? { statusCode: 500, error: 'Internal Server Error', message: errorMessage(error) }\n : { statusCode: 500, error: 'Internal Server Error' }\n }\n\n #log(error: unknown, ctx: RequestContext): void {\n const route = ctx.route\n this.#logger.error(`Request failed: ${ctx.method} ${route?.path ?? truncate(ctx.path)}`, {\n err: error,\n requestId: ctx.requestId,\n method: ctx.method,\n path: ctx.path,\n ...(route === undefined\n ? {}\n : { route: route.path, handler: `${displayName(route.controller)}.${route.handler}` }),\n })\n }\n\n #resolve<T>(resolvable: Resolvable<T>): T {\n return 'instance' in resolvable ? resolvable.instance : (this.#container.get(resolvable.token) as T)\n }\n\n #requestId(request: AdapterRequest): RequestId {\n const header = this.#options.requestIdHeader\n if (header !== undefined) {\n const incoming = request.headers[header]\n if (incoming !== undefined && REQUEST_ID.test(incoming)) return incoming as RequestId\n }\n return this.#options.generateRequestId() as RequestId\n }\n\n #enter(): void {\n this.#inflight++\n }\n\n #leave(): void {\n this.#inflight--\n if (this.#inflight === 0 && this.#idle.length > 0) {\n const waiting = this.#idle\n this.#idle = []\n for (const resolve of waiting) resolve()\n }\n }\n}\n\n/** A route served by the fast lane (see `Pipeline.handler`), decided at boot. */\ninterface FastRoute {\n readonly plan: RoutePlan\n readonly target: Target\n /** The method of the route definition (requests of another method take the general pipeline). */\n readonly method: string\n /** The status of a JSON reply, `undefined` when it has no body (such replies take the general pipeline). */\n readonly jsonStatus: number | undefined\n /** The status of a reply without value (`undefined` returned). */\n readonly emptyStatus: number\n}\n\n/** `#fastAsync` reads the body and runs the handler. */\nconst NO_RESULT: unique symbol = Symbol('no result')\n\n/** A request being answered (internal): its context, its target and the promise of its reply. */\nclass Exchange {\n readonly request: AdapterRequest\n readonly ctx: RequestContext\n readonly requestId: RequestId\n readonly target: Target\n readonly preflight: boolean\n readonly replied: Promise<AdapterReply>\n cors: CorsDecision | undefined = undefined\n answered = false\n /** The `http:request` listeners will see the event (fast lane: keep its status). */\n tracked = false\n /** The asynchronous part of a fast-lane request (never rejects). */\n done: Promise<void> | undefined = undefined\n readonly #resolve: (reply: AdapterReply) => void\n readonly #reject: (error: unknown) => void\n #event: HttpRequestEvent | undefined\n\n /** `startTime`: the event is created now (general pipeline); otherwise when first needed (fast lane). */\n constructor(request: AdapterRequest, ctx: RequestContext, requestId: RequestId, target: Target, startTime?: number) {\n this.request = request\n this.ctx = ctx\n this.requestId = requestId\n this.target = target\n this.preflight = target.kind === 'preflight'\n let resolve: ((reply: AdapterReply) => void) | undefined\n let reject: ((error: unknown) => void) | undefined\n this.replied = new Promise<AdapterReply>((onReply, onError) => {\n resolve = onReply\n reject = onError\n })\n this.#resolve = resolve as (reply: AdapterReply) => void\n this.#reject = reject as (error: unknown) => void\n if (startTime !== undefined) this.#event = requestEvent(request, ctx, startTime)\n }\n\n /**\n * The `http:request` event. The fast lane creates it when the general pipeline takes over: no\n * hook saw the request start, so its `startTime` is not observed.\n */\n get event(): HttpRequestEvent {\n this.#event ??= requestEvent(this.request, this.ctx, performance.now())\n return this.#event\n }\n\n answer(reply: AdapterReply): void {\n this.answered = true\n this.#resolve(reply)\n }\n\n fail(error: unknown): void {\n this.#reject(error)\n }\n}\n\n/** The `http:request` event of a request. */\nfunction requestEvent(request: AdapterRequest, ctx: RequestContext, startTime: number): HttpRequestEvent {\n return {\n method: request.method,\n path: ctx.path,\n route: ctx.route?.path,\n requestId: ctx.requestId,\n headers: request.headers,\n context: ctx,\n startTime,\n responseHeaders: {},\n }\n}\n\n/**\n * The decoded parameters of a raw request path matched against a route, in one pass: what\n * `matchRoutePath` then `decodePathValue` (see `Pipeline.#route`) give for a path they accept.\n * `undefined` when the path does not match or a value is not valid percent-encoding: the general\n * pipeline then answers it (a reroute, a 400).\n */\nfunction routeParams(route: RoutePath, path: string): Record<string, string> | undefined {\n if (path.charCodeAt(0) !== 47 /* / */) return undefined\n const params = emptyRecord<string>()\n const segments = route.segments\n const last = segments.length - 1\n if (last === -1) return path === '/' ? params : undefined\n let position = 1\n for (let index = 0; index <= last; index++) {\n const segment = segments[index] as RouteSegment\n if (segment.kind === 'wildcard') {\n const rest = decodePathValue(path.slice(position))\n if (rest === undefined) return undefined\n params[WILDCARD_PARAM] = rest\n return params\n }\n const slash = path.indexOf('/', position)\n const end = slash === -1 ? path.length : slash\n if (segment.kind === 'static') {\n const value = segment.value\n if (end - position !== value.length || !path.startsWith(value, position)) return undefined\n } else {\n if (end === position) return undefined\n const decoded = decodePathValue(path.slice(position, end))\n if (decoded === undefined) return undefined\n params[segment.name] = decoded\n }\n if (index === last) return end === path.length ? params : undefined\n if (slash === -1) return undefined\n position = slash + 1\n }\n return params\n}\n\n/**\n * A value the fast lane serialises as JSON: a plain object or array (its own prototype and\n * constructor), not duck-typed as a Node.js stream. Anything `serializeResult` could treat otherwise\n * (`HttpResponse`, `Response`, bytes, streams, `Blob`, strings, `undefined`...) is not.\n */\nfunction isPlainJson(value: unknown): value is object {\n if (value === null || typeof value !== 'object') return false\n const prototype: unknown = Object.getPrototypeOf(value)\n const ctor = (value as { constructor?: unknown }).constructor\n if (prototype === Object.prototype) {\n if (ctor !== Object) return false\n } else if (prototype !== Array.prototype || ctor !== Array) {\n return false\n }\n return typeof (value as { pipe?: unknown }).pipe !== 'function'\n}\n\nconst ENCODER = new TextEncoder()\n\n/** UTF-8 encoding of a text body, like the serialiser (a pooled `Buffer` on Node.js, `TextEncoder` on Bun). */\nconst utf8: (text: string) => Uint8Array = isBun() ? text => ENCODER.encode(text) : text => Buffer.from(text, 'utf8')\n\n/**\n * The reply handed to the adapter (internal fields of the serialised reply left out). A streamed\n * `text/event-stream` body is an event stream whatever produced it (`@Sse`, `HttpResponse.sse()`, a\n * proxied `fetch()` response, `HttpResponse.stream()`): the adapter sends its headers at once, even\n * before a quiet stream's first byte, and lifts idle timeouts.\n */\nfunction adapterReply(serialized: SerializedReply, body: ReplyBody, blob?: Blob): AdapterReply {\n const text = serialized.text\n if (text !== undefined) return { status: serialized.status, headers: serialized.headers, body, text }\n const reply: AdapterReply = { status: serialized.status, headers: serialized.headers, body }\n if (blob !== undefined) return { ...reply, blob }\n const eventStream =\n serialized.sse !== undefined ||\n (body instanceof ReadableStream && isEventStreamType(serialized.headers['content-type']))\n return eventStream ? { ...reply, eventStream: true } : reply\n}\n\n/**\n * Appends the cookies to `set-cookie`, after the raw values (`@Header`, `ctx.setHeader()`, the\n * `HttpResponse` headers, a Web `Response`): the cookies of the context (`ctx.setCookie()`), then\n * those of the `HttpResponse`, a cookie of the same key (name, domain, path) replacing the earlier\n * one in place. One line per cookie.\n */\nfunction applyCookies(reply: CheckedReply, ctx: RequestContext): void {\n const own = reply.cookieLines ?? NO_COOKIE_LINES\n const context = ctx.cookieLines\n if (own.length === 0 && context.length === 0) return\n const merged = new Map<string, string>()\n for (const { key, line } of context) merged.set(key, line)\n for (const { key, line } of own) merged.set(key, line)\n const existing = reply.headers['set-cookie']\n let raw: string[] = []\n if (typeof existing === 'string') raw = [existing]\n else if (existing !== undefined) raw = [...existing]\n reply.headers['set-cookie'] = [...raw, ...merged.values()]\n}\n\nconst NO_COOKIE_LINES: readonly SerializedCookie[] = Object.freeze([])\n\n/** Whether a reply body is streamed (a file is read through a stream too). */\nfunction isStreamed(body: ReplyBody): body is ReadableStream<Uint8Array> | Blob {\n return body instanceof ReadableStream || body instanceof Blob\n}\n\n/** `SseOptions` of the `sse` metadata of a route (`heartbeat: 0` disables the heartbeat). */\nfunction sseOptions(definition: HttpSseDefinition): SseOptions {\n return {\n ...(definition.heartbeat === undefined\n ? {}\n : { heartbeat: definition.heartbeat === 0 ? false : definition.heartbeat }),\n ...(definition.retry === undefined ? {} : { retry: definition.retry }),\n ...(definition.maxDuration === undefined ? {} : { maxDuration: definition.maxDuration }),\n }\n}\n\nfunction definedOptions(options: SseOptions): SseOptions {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(options)) if (value !== undefined) result[key] = value\n return result as SseOptions\n}\n\nfunction describeResult(value: unknown): string {\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n if (typeof value === 'string') return 'a string'\n if (typeof value === 'object') return `an instance of ${(value as object).constructor?.name ?? 'Object'}`\n return typeof value\n}\n\nfunction withContextHeaders(headers: Record<string, HeaderValue>, ctx: RequestContext): Record<string, HeaderValue> {\n const result = emptyRecord<HeaderValue>()\n if (ctx.hasResponseHeaders) assignHeaders(result, ctx.responseHeaders)\n assignHeaders(result, headers)\n return result\n}\n\n/** Converts an error raised by the server framework (bad URL...) to an `HttpException`. */\nfunction frameworkError(error: unknown): unknown {\n if (isHttpException(error)) return error\n const status =\n (error as { statusCode?: unknown; status?: unknown } | null)?.statusCode ??\n (error as { status?: unknown } | null)?.status\n if (typeof status === 'number' && status >= 400 && status < 500) {\n return new HttpException(status, errorMessage(error), undefined, { cause: error })\n }\n return error\n}\n\n/** `Allow` of a path: its methods and `OPTIONS`, answered automatically when no route declares it. */\nfunction allowHeader(allowed: readonly string[]): string {\n return (allowed.includes('OPTIONS') ? allowed : [...allowed, 'OPTIONS']).join(', ')\n}\n\n/**\n * A raw request path usable as a same-origin `Location`: backslashes, controls and spaces are\n * percent-encoded and leading slashes collapsed, since browsers read `/\\evil.com` or `//evil.com`\n * as another host (an open redirect through `trailingSlash: 'redirect'`).\n */\nfunction sameOriginPath(path: string): string {\n let encoded = ''\n for (const char of path) {\n const code = char.charCodeAt(0)\n encoded +=\n code <= 0x20 || code === 0x7f || char === '\\\\' ? `%${code.toString(16).toUpperCase().padStart(2, '0')}` : char\n }\n return encoded.replace(/^\\/{2,}/, '/')\n}\n\nfunction truncate(path: string): string {\n return path.length > MAX_PATH_IN_MESSAGE ? `${path.slice(0, MAX_PATH_IN_MESSAGE)}…` : path\n}\n","/**\n * Plugin routes (RFC 0002 H1): routes another plugin asks `HttpPlugin` to serve (documentation,\n * health or metrics endpoints), registered on every adapter in the same pipeline as the compiled\n * controllers.\n */\nimport type { Container, Plugin } from '@znight/core'\nimport type { HttpContext } from './context.ts'\nimport type { RouteMetaEntry } from './decorators.ts'\nimport type { HttpMethod } from './metadata.ts'\nimport type { GuardRef } from './plugin.ts'\n\nimport { ErrorCode, ZnightError } from '@znight/core'\n\nimport { isGroupOf } from './decorators.ts'\nimport { joinPaths, normalizePath, parseRoutePath, type RoutePath, RoutePathError } from './path.ts'\n\n/**\n * A route served by `HttpPlugin` on behalf of another plugin. It runs through the same pipeline as\n * controller routes: `http:request` hook, request scope, global guards, then its own `guards`, the\n * handler, the exception mappers; global interceptors do not wrap it. The handler result is\n * serialised like a controller result (`HttpResponse`, objects as JSON, strings, streams...).\n */\nexport interface PluginRoute {\n /** `GET` routes also answer `HEAD`; `ALL` registers every method without its own route. */\n readonly method: HttpMethod\n /** Path relative to the `HttpPlugin` prefix, with the controller grammar (`/openapi.json`, `/docs/_assets/*`). */\n readonly path: string\n /** Handler name, shown in `HttpPlugin.routes`, logs and errors (`document`). */\n readonly name: string\n readonly handler: (ctx: HttpContext) => unknown\n /**\n * Route metadata (`[Public.meta()]`): read by guards (`Public.get(ctx)`) and by the boot check of\n * required route decorator groups. One entry per group.\n */\n readonly meta?: readonly RouteMetaEntry[]\n /** Guards of the route (provider classes or instances), run after the global guards. */\n readonly guards?: readonly GuardRef[]\n}\n\n/** What {@link PluginHttpRoutes.httpRoutes} receives. */\nexport interface PluginHttpRoutesContext {\n /** The `HttpPlugin` prefix (`''` or `/api`), already applied to the paths of the routes. */\n readonly prefix: string\n /** The application container (initialised). */\n readonly container: Container\n}\n\n/**\n * Implemented by a plugin that serves HTTP routes. `HttpPlugin` calls `httpRoutes()` once in its\n * `onBootstrap`, after `container.init()` and whatever the plugin order, then registers the routes\n * on its adapter. A path that breaks the grammar, or that collides with another route, is ZNIGHT007\n * naming the plugin.\n *\n * ```ts\n * export class StatusPlugin implements Plugin, PluginHttpRoutes {\n * readonly name = 'status'\n * httpRoutes(): readonly PluginRoute[] {\n * return [{ method: 'GET', path: '/status', name: 'status', handler: () => ({ up: true }), meta: [Public.meta()] }]\n * }\n * }\n * ```\n */\nexport interface PluginHttpRoutes {\n httpRoutes(context: PluginHttpRoutesContext): readonly PluginRoute[]\n}\n\n/** A validated plugin route (internal). */\nexport interface CollectedPluginRoute {\n readonly plugin: string\n /** The plugin instance (the \"controller\" of the route). */\n readonly instance: object\n readonly method: HttpMethod\n /** Full path, prefix included. */\n readonly path: RoutePath\n /** Normalised path without the prefix. */\n readonly relativePath: string\n readonly name: string\n readonly handler: (ctx: HttpContext) => unknown\n readonly meta: readonly NormalizedMetaEntry[]\n readonly guards: readonly unknown[]\n}\n\n/** A plugin route metadata entry with its group (internal). */\nexport interface NormalizedMetaEntry {\n readonly key: string\n readonly value: unknown\n readonly group: string\n readonly required: boolean\n}\n\nconst METHODS: ReadonlySet<string> = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'ALL'])\n\n/** Calls `httpRoutes()` on every other plugin implementing it, in plugin order, and validates the routes. */\nexport function collectPluginRoutes(\n plugins: readonly Plugin[],\n self: Plugin,\n context: PluginHttpRoutesContext,\n): CollectedPluginRoute[] {\n const collected: CollectedPluginRoute[] = []\n for (const plugin of plugins) {\n if (plugin === self) continue\n const provider = plugin as Plugin & Partial<PluginHttpRoutes>\n if (typeof provider.httpRoutes !== 'function') continue\n const name = String(plugin.name)\n const routes: unknown = provider.httpRoutes(context)\n if (!Array.isArray(routes)) {\n throw invalid(name, `httpRoutes() must return an array of routes (received ${describe(routes)})`)\n }\n for (const route of routes as unknown[]) collected.push(validateRoute(plugin, name, route, context.prefix))\n }\n return collected\n}\n\nfunction validateRoute(instance: object, plugin: string, value: unknown, prefix: string): CollectedPluginRoute {\n if (value === null || typeof value !== 'object') throw invalid(plugin, `invalid route ${describe(value)}`)\n const route = value as Partial<PluginRoute>\n const label = `${String(route.method)} ${String(route.path)}`\n if (typeof route.name !== 'string' || route.name === '') {\n throw invalid(plugin, `the route ${label} needs a name (handler name shown in HttpPlugin.routes)`)\n }\n const where = `${label} (${route.name})`\n if (typeof route.method !== 'string' || !METHODS.has(route.method)) {\n throw invalid(plugin, `unknown method ${describe(route.method)} of the route ${where}`)\n }\n if (typeof route.handler !== 'function') throw invalid(plugin, `the route ${where} has no handler function`)\n if (typeof route.path !== 'string') throw invalid(plugin, `the route ${where} has no path`)\n let path: RoutePath\n try {\n path = parseRoutePath(joinPaths(prefix, route.path))\n } catch (error) {\n if (!(error instanceof RoutePathError)) throw error\n throw invalid(plugin, `invalid path of the route ${where}: ${error.issue.message}`, error)\n }\n const meta = route.meta ?? []\n if (!Array.isArray(meta)) throw invalid(plugin, `the meta of the route ${where} must be an array of entries`)\n const entries = (meta as unknown[]).map(entry => metaEntry(plugin, where, entry))\n const groups = new Map<string, string>()\n for (const entry of entries) {\n const other = groups.get(entry.group)\n if (other !== undefined) {\n throw invalid(\n plugin,\n `the route ${where} has two entries of the \"${entry.group}\" group (${other}, ${entry.key}): keep one`,\n )\n }\n groups.set(entry.group, entry.key)\n }\n const guards = route.guards ?? []\n if (!Array.isArray(guards)) throw invalid(plugin, `the guards of the route ${where} must be an array`)\n return {\n plugin,\n instance,\n method: route.method as HttpMethod,\n path,\n relativePath: normalizePath(route.path),\n name: route.name,\n handler: route.handler,\n meta: entries,\n guards,\n }\n}\n\nfunction metaEntry(plugin: string, where: string, value: unknown): NormalizedMetaEntry {\n const entry = (value ?? {}) as Partial<RouteMetaEntry>\n if (value === null || typeof value !== 'object' || typeof entry.key !== 'string' || entry.key === '') {\n throw invalid(plugin, `invalid meta entry ${describe(value)} of the route ${where}: expected Decorator.meta(value)`)\n }\n const group = entry.group ?? entry.key\n const required = entry.required ?? false\n if (!isGroupOf(group, entry.key) || typeof required !== 'boolean') {\n throw invalid(plugin, `invalid group of the meta entry \"${entry.key}\" of the route ${where}`)\n }\n return { key: entry.key, value: entry.value, group, required }\n}\n\nfunction invalid(plugin: string, reason: string, cause?: unknown): ZnightError {\n return new ZnightError(ErrorCode.InvalidRoute, `HttpPlugin: plugin \"${plugin}\": ${reason}`, {\n ...(cause === undefined ? {} : { cause }),\n })\n}\n\nfunction describe(value: unknown): string {\n try {\n return typeof value === 'function' ? 'a function' : (JSON.stringify(value) ?? String(value))\n } catch {\n return typeof value\n }\n}\n","/**\n * Trusted proxies (RFC 0001 §5.6): `ctx.ip` and `ctx.protocol` behind load balancers, computed the\n * same way on every adapter from the socket peer (`AdapterRequest.remoteAddress`) and the\n * `x-forwarded-for` / `x-forwarded-proto` headers. The `Forwarded` header (RFC 7239) is not read.\n */\nimport { invalidOption } from './option-error.ts'\n\n/**\n * The `trustProxy` option: `false` (default: the headers are ignored), a number of trusted hops\n * (`1`: one load balancer in front of the server), or the addresses of the trusted proxies (IPv4 /\n * IPv6 addresses, CIDR ranges and the aliases `'loopback'`, `'private'`, `'linklocal'`).\n */\nexport type TrustProxy = false | number | readonly string[]\n\n/** Client address and protocol of a request (internal). */\nexport interface ClientInfo {\n readonly ip: string | undefined\n readonly protocol: 'http' | 'https'\n}\n\n/** A resolved `trustProxy` policy (internal). */\nexport interface TrustPolicy {\n /** `ctx.ip` and `ctx.protocol` of a request. */\n resolve(\n remoteAddress: string | undefined,\n headers: Readonly<Record<string, string | undefined>>,\n encrypted: boolean,\n ): ClientInfo\n}\n\n/** A parsed address: IPv4 (4 bytes, IPv4-mapped IPv6 included) or IPv6 (16 bytes). */\ninterface Address {\n readonly bytes: readonly number[]\n /** Normalised text (`::ffff:10.0.0.1` → `10.0.0.1`). */\n readonly text: string\n}\n\ninterface Range {\n readonly bytes: readonly number[]\n readonly prefix: number\n}\n\nconst ALIASES: Readonly<Record<string, readonly string[]>> = Object.freeze({\n loopback: ['127.0.0.0/8', '::1/128'],\n private: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', 'fc00::/7'],\n linklocal: ['169.254.0.0/16', 'fe80::/10'],\n})\n\nconst TRUST_HINTS: readonly string[] = [\n 'trustProxy: 1 trusts one proxy (the socket peer); trustProxy: [\"loopback\", \"10.0.0.0/8\"] trusts these addresses',\n 'Trusting every hop would let any client choose its ctx.ip with an x-forwarded-for header',\n]\n\n/** Validates the `trustProxy` option (ZNIGHT005); `undefined` when proxies are not trusted. */\nexport function resolveTrustProxy(value: TrustProxy | undefined): TrustPolicy | undefined {\n if (value === undefined || value === false) return undefined\n if (typeof value === 'number') {\n if (!Number.isSafeInteger(value) || value < 1) {\n throw invalidOption(\n 'trustProxy',\n 'false, a number of hops (an integer >= 1) or a list of addresses',\n value,\n undefined,\n TRUST_HINTS,\n )\n }\n return hopPolicy(value)\n }\n if (!Array.isArray(value)) {\n throw invalidOption(\n 'trustProxy',\n 'false, a number of hops (an integer >= 1) or a list of addresses',\n value,\n undefined,\n TRUST_HINTS,\n )\n }\n const ranges: Range[] = []\n for (const entry of value) {\n if (typeof entry !== 'string') {\n throw invalidOption('trustProxy', 'a list of addresses, CIDR ranges or aliases', value, undefined, TRUST_HINTS)\n }\n const expanded = ALIASES[entry] ?? [entry]\n for (const item of expanded) {\n const range = parseRange(item)\n if (range === undefined) {\n throw invalidOption(\n 'trustProxy',\n `a list of IP addresses, CIDR ranges (\"10.0.0.0/8\") or aliases (\"loopback\", \"private\", \"linklocal\"); \"${entry}\" is invalid`,\n value,\n undefined,\n TRUST_HINTS,\n )\n }\n ranges.push(range)\n }\n }\n return listPolicy(ranges)\n}\n\nfunction hopPolicy(hops: number): TrustPolicy {\n return {\n resolve(remoteAddress, headers, encrypted) {\n const socket = remoteAddress === undefined ? undefined : parseAddress(remoteAddress)\n if (socket === undefined) return { ip: remoteAddress, protocol: encrypted ? 'https' : 'http' }\n let client = socket\n const chain = forwardedFor(headers)\n for (let index = 0; index < hops && index < chain.length; index++) {\n const next = parseAddress(chain[index] as string)\n if (next === undefined) break // a malformed entry stops the walk at the last valid address\n client = next\n }\n return { ip: client.text, protocol: forwardedProto(headers, encrypted) }\n },\n }\n}\n\nfunction listPolicy(ranges: readonly Range[]): TrustPolicy {\n const trusted = (address: Address): boolean => ranges.some(range => inRange(address, range))\n return {\n resolve(remoteAddress, headers, encrypted) {\n const socket = remoteAddress === undefined ? undefined : parseAddress(remoteAddress)\n if (socket === undefined) return { ip: remoteAddress, protocol: encrypted ? 'https' : 'http' }\n if (!trusted(socket)) return { ip: socket.text, protocol: encrypted ? 'https' : 'http' }\n let client = socket\n for (const entry of forwardedFor(headers)) {\n const next = parseAddress(entry)\n if (next === undefined) break\n client = next\n if (!trusted(next)) break\n }\n return { ip: client.text, protocol: forwardedProto(headers, encrypted) }\n },\n }\n}\n\n/** `x-forwarded-for` entries from right (nearest proxy) to left (client). */\nfunction forwardedFor(headers: Readonly<Record<string, string | undefined>>): string[] {\n const value = headers['x-forwarded-for']\n if (value === undefined) return []\n return value\n .split(',')\n .map(entry => entry.trim())\n .reverse()\n}\n\n/** The leftmost `x-forwarded-proto` value when it is `http` or `https`, else the connection protocol. */\nfunction forwardedProto(headers: Readonly<Record<string, string | undefined>>, encrypted: boolean): 'http' | 'https' {\n const value = headers['x-forwarded-proto']?.split(',')[0]?.trim().toLowerCase()\n if (value === 'http' || value === 'https') return value\n return encrypted ? 'https' : 'http'\n}\n\nfunction inRange(address: Address, range: Range): boolean {\n if (address.bytes.length !== range.bytes.length) return false\n let bits = range.prefix\n for (let index = 0; index < range.bytes.length && bits > 0; index++) {\n const mask = bits >= 8 ? 0xff : (0xff << (8 - bits)) & 0xff\n if (((address.bytes[index] as number) & mask) !== ((range.bytes[index] as number) & mask)) return false\n bits -= 8\n }\n return true\n}\n\n/** `10.0.0.0/8`, `fc00::/7` or a single address. */\nfunction parseRange(value: string): Range | undefined {\n const slash = value.indexOf('/')\n const address = parseAddress(slash === -1 ? value : value.slice(0, slash))\n if (address === undefined) return undefined\n const bits = address.bytes.length * 8\n if (slash === -1) return { bytes: address.bytes, prefix: bits }\n const prefixText = value.slice(slash + 1)\n if (!/^\\d{1,3}$/.test(prefixText)) return undefined\n const prefix = Number(prefixText)\n return prefix > bits ? undefined : { bytes: address.bytes, prefix }\n}\n\n/** Parses an IPv4 or IPv6 address (zone ids ignored); IPv4-mapped IPv6 addresses become IPv4. */\nexport function parseAddress(value: string): Address | undefined {\n const text = value.startsWith('[') && value.endsWith(']') ? value.slice(1, -1) : value\n const v4 = parseIPv4(text)\n if (v4 !== undefined) return { bytes: v4, text }\n const zone = text.indexOf('%')\n const v6 = parseIPv6(zone === -1 ? text : text.slice(0, zone))\n if (v6 === undefined) return undefined\n if (v6.slice(0, 10).every(byte => byte === 0) && v6[10] === 0xff && v6[11] === 0xff) {\n const bytes = v6.slice(12)\n return { bytes, text: bytes.join('.') }\n }\n return { bytes: v6, text: text.toLowerCase() }\n}\n\nfunction parseIPv4(text: string): number[] | undefined {\n const parts = text.split('.')\n if (parts.length !== 4) return undefined\n const bytes: number[] = []\n for (const part of parts) {\n if (!/^(?:0|[1-9]\\d{0,2})$/.test(part)) return undefined\n const byte = Number(part)\n if (byte > 255) return undefined\n bytes.push(byte)\n }\n return bytes\n}\n\nfunction parseIPv6(text: string): number[] | undefined {\n if (text === '' || text.length > 45) return undefined\n const halves = text.split('::')\n if (halves.length > 2) return undefined\n const groups = (part: string): number[] | undefined => {\n if (part === '') return []\n const result: number[] = []\n const items = part.split(':')\n for (let index = 0; index < items.length; index++) {\n const item = items[index] as string\n if (index === items.length - 1 && item.includes('.')) {\n const v4 = parseIPv4(item)\n if (v4 === undefined) return undefined\n result.push(((v4[0] as number) << 8) | (v4[1] as number), ((v4[2] as number) << 8) | (v4[3] as number))\n } else {\n if (!/^[0-9A-Fa-f]{1,4}$/.test(item)) return undefined\n result.push(Number.parseInt(item, 16))\n }\n }\n return result\n }\n const head = groups(halves[0] as string)\n const tail = halves.length === 2 ? groups(halves[1] as string) : []\n if (head === undefined || tail === undefined) return undefined\n const missing = 8 - head.length - tail.length\n if (halves.length === 2 ? missing < 1 : missing !== 0) return undefined\n const words = [...head, ...new Array<number>(missing).fill(0), ...tail]\n const bytes: number[] = []\n for (const word of words) bytes.push(word >> 8, word & 0xff)\n return bytes\n}\n","/**\n * Security headers (RFC 0001 §5.5): validated and computed once at boot, then added to every reply\n * (except `@Res()` raw replies) when the handler, an interceptor, an exception or a hook wrapper did\n * not set them.\n */\nimport { isHeaderValue } from './headers.ts'\nimport { invalidOption } from './option-error.ts'\n\n/** HSTS settings (`strict-transport-security`). */\nexport interface HstsOptions {\n /** `max-age`, in seconds. Default `31536000` (one year). */\n readonly maxAge?: number\n /** `includeSubDomains`. Default `true`. */\n readonly includeSubDomains?: boolean\n /** `preload` (needs `includeSubDomains` and a `maxAge` of at least one year). Default `false`. */\n readonly preload?: boolean\n}\n\n/** The `securityHeaders` option of `HttpPlugin.configure` (merged over the defaults). */\nexport interface SecurityHeadersOptions {\n /** `content-security-policy`. Default `\"default-src 'none'; frame-ancestors 'none'\"`. */\n readonly contentSecurityPolicy?: string | false\n /** `x-frame-options`. Default `'DENY'`. */\n readonly frameOptions?: 'DENY' | 'SAMEORIGIN' | false\n /** `x-content-type-options: nosniff`. Default `true`. */\n readonly noSniff?: boolean\n /** `referrer-policy` (a policy or a comma-separated fallback list). Default `'no-referrer'`. */\n readonly referrerPolicy?: string | false\n /** `strict-transport-security`. Default `false`; `true`: `max-age=31536000; includeSubDomains`. */\n readonly hsts?: boolean | HstsOptions\n /** `cross-origin-resource-policy`. Default `false`. */\n readonly crossOriginResourcePolicy?: 'same-origin' | 'same-site' | 'cross-origin' | false\n /** `cache-control` of replies that do not set one (`'no-store'` for personal data). Default `false`. */\n readonly cacheControl?: string | false\n}\n\nconst DEFAULT_CSP = \"default-src 'none'; frame-ancestors 'none'\"\nconst ONE_YEAR = 31_536_000\nconst KEYS = new Set([\n 'contentSecurityPolicy',\n 'frameOptions',\n 'noSniff',\n 'referrerPolicy',\n 'hsts',\n 'crossOriginResourcePolicy',\n 'cacheControl',\n])\nconst REFERRER_POLICIES = new Set([\n 'no-referrer',\n 'no-referrer-when-downgrade',\n 'origin',\n 'origin-when-cross-origin',\n 'same-origin',\n 'strict-origin',\n 'strict-origin-when-cross-origin',\n 'unsafe-url',\n])\nconst RESOURCE_POLICIES = new Set(['same-origin', 'same-site', 'cross-origin'])\nconst NO_HEADERS: Readonly<Record<string, string>> = Object.freeze({})\n\n/**\n * Validates the `securityHeaders` option (ZNIGHT005) and returns the headers to add, frozen\n * (`{}` when disabled).\n */\nexport function resolveSecurityHeaders(\n value: boolean | SecurityHeadersOptions | undefined,\n): Readonly<Record<string, string>> {\n if (value === false) return NO_HEADERS\n if (value !== undefined && value !== true && (value === null || typeof value !== 'object' || Array.isArray(value))) {\n throw invalidOption('securityHeaders', 'a boolean or an object of header settings', value)\n }\n const options: SecurityHeadersOptions = value === undefined || value === true ? {} : value\n for (const key of Object.keys(options)) {\n if (!KEYS.has(key)) {\n throw invalidOption('securityHeaders', `an object with ${[...KEYS].join(', ')} (unknown \"${key}\")`, options)\n }\n }\n const headers: Record<string, string> = {}\n const csp = options.contentSecurityPolicy ?? DEFAULT_CSP\n if (csp !== false) headers['content-security-policy'] = text('securityHeaders.contentSecurityPolicy', csp)\n const frame = options.frameOptions ?? 'DENY'\n if (frame !== false) {\n if (frame !== 'DENY' && frame !== 'SAMEORIGIN') {\n throw invalidOption('securityHeaders.frameOptions', '\"DENY\", \"SAMEORIGIN\" or false', frame)\n }\n headers['x-frame-options'] = frame\n }\n const noSniff = options.noSniff ?? true\n if (typeof noSniff !== 'boolean') throw invalidOption('securityHeaders.noSniff', 'a boolean', noSniff)\n if (noSniff) headers['x-content-type-options'] = 'nosniff'\n const referrer = options.referrerPolicy ?? 'no-referrer'\n if (referrer !== false) headers['referrer-policy'] = referrerPolicy(referrer)\n const hsts = strictTransportSecurity(options.hsts ?? false)\n if (hsts !== undefined) headers['strict-transport-security'] = hsts\n const corp = options.crossOriginResourcePolicy ?? false\n if (corp !== false) {\n if (typeof corp !== 'string' || !RESOURCE_POLICIES.has(corp)) {\n throw invalidOption(\n 'securityHeaders.crossOriginResourcePolicy',\n '\"same-origin\", \"same-site\", \"cross-origin\" or false',\n corp,\n )\n }\n headers['cross-origin-resource-policy'] = corp\n }\n const cacheControl = options.cacheControl ?? false\n if (cacheControl !== false) headers['cache-control'] = text('securityHeaders.cacheControl', cacheControl)\n return Object.freeze(headers)\n}\n\nfunction text(name: string, value: unknown): string {\n if (typeof value !== 'string' || value.trim() === '' || !isHeaderValue(value)) {\n throw invalidOption(name, 'a non-empty header value (or false)', value)\n }\n return value\n}\n\nfunction referrerPolicy(value: unknown): string {\n const policies = typeof value === 'string' ? value.split(',').map(item => item.trim()) : []\n if (policies.length === 0 || !policies.every(policy => REFERRER_POLICIES.has(policy))) {\n throw invalidOption(\n 'securityHeaders.referrerPolicy',\n `a referrer policy (${[...REFERRER_POLICIES].join(', ')}) or false`,\n value,\n )\n }\n return policies.join(', ')\n}\n\nfunction strictTransportSecurity(value: boolean | HstsOptions): string | undefined {\n if (value === false) return undefined\n if (value !== true && (value === null || typeof value !== 'object' || Array.isArray(value))) {\n throw invalidOption('securityHeaders.hsts', 'a boolean or { maxAge?, includeSubDomains?, preload? }', value)\n }\n const options: HstsOptions = value === true ? {} : value\n for (const key of Object.keys(options)) {\n if (key !== 'maxAge' && key !== 'includeSubDomains' && key !== 'preload') {\n throw invalidOption('securityHeaders.hsts', '{ maxAge?, includeSubDomains?, preload? }', options)\n }\n }\n const maxAge = options.maxAge ?? ONE_YEAR\n if (!Number.isSafeInteger(maxAge) || maxAge < 0) {\n throw invalidOption('securityHeaders.hsts.maxAge', 'a positive integer number of seconds', maxAge)\n }\n const includeSubDomains = options.includeSubDomains ?? true\n if (typeof includeSubDomains !== 'boolean') {\n throw invalidOption('securityHeaders.hsts.includeSubDomains', 'a boolean', includeSubDomains)\n }\n const preload = options.preload ?? false\n if (typeof preload !== 'boolean') throw invalidOption('securityHeaders.hsts.preload', 'a boolean', preload)\n if (preload && (!includeSubDomains || maxAge < ONE_YEAR)) {\n throw invalidOption(\n 'securityHeaders.hsts',\n 'includeSubDomains and a maxAge of at least 31536000 with preload',\n options,\n undefined,\n ['The HSTS preload list requires includeSubDomains and max-age >= 31536000'],\n )\n }\n return `max-age=${maxAge}${includeSubDomains ? '; includeSubDomains' : ''}${preload ? '; preload' : ''}`\n}\n","/**\n * File uploads: options of `@UploadedFile` / `@UploadedFiles`, the plugin-wide limits, the\n * `uploads` helpers used by generated `invoke` functions, and the body plan of a route (body limit\n * and multipart policy).\n */\nimport type { HttpContext } from './context.ts'\nimport type { HttpRouteDefinition, HttpUploadDefinition } from './metadata.ts'\nimport type { FileRule, MultipartPolicy } from './multipart.ts'\nimport type { ByteSize } from './size.ts'\n\nimport { BadRequestException, issue } from './exceptions.ts'\n\n/** Options of `@UploadedFile` (static: evaluated at build time). */\nexport interface UploadedFileOptions {\n /**\n * Answer 400 when no file is sent. Default: `true`, unless the parameter is optional\n * (`file?: File`, `File | undefined`).\n */\n readonly required?: boolean\n /** Maximum size of the file (`5_000_000`, `'5mb'`; `kb` = 1024 bytes). Default: plugin `uploads.maxFileSize`. */\n readonly maxSize?: ByteSize\n /**\n * Accepted media types, as declared by the client: `'image/png'`, `'image/*'`, `'*\\/*'`. Other\n * types answer 415. Default: any.\n */\n readonly mimeTypes?: readonly string[]\n}\n\n/** Options of `@UploadedFiles` (static: evaluated at build time). */\nexport interface UploadedFilesOptions extends UploadedFileOptions {\n /** Maximum number of files (413 above). Default: plugin `uploads.maxFiles`. */\n readonly maxFiles?: number\n}\n\n/** Plugin-wide upload limits (`HttpPlugin.configure({ uploads })`). */\nexport interface UploadLimits {\n /** Default maximum size of one file (`maxSize` of upload parameters). Default: `'10mb'`. */\n readonly maxFileSize?: ByteSize\n /** Default maximum number of files of `@UploadedFiles` (and of multipart bodies of other routes). Default: `10`. */\n readonly maxFiles?: number\n /** Maximum number of parts (text fields and files) of a multipart body (413 above). Default: `1000`. */\n readonly maxParts?: number\n /** Maximum size of one text field of a multipart body (413 above). Default: `'1mb'`. */\n readonly maxFieldSize?: ByteSize\n}\n\n/** {@link UploadLimits} with defaults applied, in bytes. */\nexport interface ResolvedUploadLimits {\n readonly maxFileSize: number\n readonly maxFiles: number\n readonly maxParts: number\n readonly maxFieldSize: number\n}\n\n/** Default upload limits. */\nexport const DEFAULT_UPLOAD_LIMITS: ResolvedUploadLimits = Object.freeze({\n maxFileSize: 10 * 1024 * 1024,\n maxFiles: 10,\n maxParts: 1000,\n maxFieldSize: 1024 * 1024,\n})\n\n/** How the body of a route is read (internal). */\nexport interface BodyPlan {\n /** Maximum body size in bytes (`Infinity`: no limit). */\n readonly limit: number\n /** Rules applied to `multipart/form-data` bodies. */\n readonly multipart: MultipartPolicy\n /** The route declares upload parameters: non-multipart bodies answer 415. */\n readonly upload: boolean\n}\n\n/**\n * The body plan of a route: `@BodyLimit` (`route.bodyLimit`) or, for upload routes, the sum of the\n * file limits plus the plugin `bodyLimit` (room for text fields and multipart framing), else the\n * plugin `bodyLimit`.\n */\nexport function bodyPlan(\n route: Pick<HttpRouteDefinition, 'bodyLimit' | 'uploads'>,\n bodyLimit: number,\n limits: ResolvedUploadLimits,\n): BodyPlan {\n const definitions = route.uploads ?? []\n const upload = definitions.length > 0\n const rules: FileRule[] = upload\n ? definitions.map(definition => fileRule(definition, limits))\n : [\n {\n field: undefined,\n multiple: true,\n maxSize: limits.maxFileSize,\n maxFiles: limits.maxFiles,\n mimeTypes: undefined,\n },\n ]\n let limit = route.bodyLimit\n if (limit === undefined) {\n limit = bodyLimit\n if (upload) for (const rule of rules) limit += rule.maxSize * rule.maxFiles\n }\n return { limit, upload, multipart: { rules, maxParts: limits.maxParts, maxFieldSize: limits.maxFieldSize } }\n}\n\nfunction fileRule(definition: HttpUploadDefinition, limits: ResolvedUploadLimits): FileRule {\n const multiple = definition.multiple === true\n return {\n field: definition.field,\n multiple,\n maxSize: definition.maxSize ?? limits.maxFileSize,\n maxFiles: multiple ? (definition.maxFiles ?? limits.maxFiles) : 1,\n mimeTypes: definition.mimeTypes,\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Helpers of the generated code\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Reads uploaded files from the context (`ctx.files`) in generated `invoke` functions\n * (`@UploadedFile('avatar') avatar: File` → `uploads.file(ctx, 'avatar')`). `field` `undefined`\n * means any field. Limits were enforced while the body was read; these helpers check presence.\n */\nexport interface Uploads {\n /** The file of `field`; 400 `Missing file \"field\"` when absent. */\n file(ctx: HttpContext, field: string | undefined): File\n /** The file of `field`, `undefined` when absent. */\n optionalFile(ctx: HttpContext, field: string | undefined): File | undefined\n /** The files of `field` (at least one); 400 `Missing files \"field\"` when none. */\n files(ctx: HttpContext, field: string | undefined): File[]\n /** The files of `field`, possibly none. */\n optionalFiles(ctx: HttpContext, field: string | undefined): File[]\n}\n\nconst NO_FILES: readonly File[] = Object.freeze([])\n\nfunction filesOf(ctx: HttpContext, field: string | undefined): readonly File[] {\n const files = ctx.files\n if (field !== undefined) return Object.hasOwn(files, field) ? (files[field] ?? NO_FILES) : NO_FILES\n const all: File[] = []\n for (const name of Object.keys(files)) all.push(...(files[name] ?? NO_FILES))\n return all\n}\n\nfunction missing(ctx: HttpContext, field: string | undefined, multiple: boolean): BadRequestException {\n const what = multiple ? 'files' : 'file'\n if (field === undefined) return new BadRequestException(`Missing ${what}`)\n const body = ctx.body\n if (body !== null && typeof body === 'object' && Object.hasOwn(body, field)) {\n return new BadRequestException(\n `Expected a file in field ${JSON.stringify(field)}, received a text value`,\n issue(field, 'Expected a file, received a text value'),\n )\n }\n return new BadRequestException(`Missing ${what} ${JSON.stringify(field)}`, issue(field, `Missing ${what}`))\n}\n\n/** The helpers of the generated code (`import { uploads } from '@znight/http'`). */\nexport const uploads: Uploads = Object.freeze({\n file(ctx: HttpContext, field: string | undefined): File {\n const [file] = filesOf(ctx, field)\n if (file === undefined) throw missing(ctx, field, false)\n return file\n },\n optionalFile(ctx: HttpContext, field: string | undefined): File | undefined {\n return filesOf(ctx, field)[0]\n },\n files(ctx: HttpContext, field: string | undefined): File[] {\n const files = filesOf(ctx, field)\n if (files.length === 0) throw missing(ctx, field, true)\n return [...files]\n },\n optionalFiles(ctx: HttpContext, field: string | undefined): File[] {\n return [...filesOf(ctx, field)]\n },\n})\n","import type { Container, Plugin, PluginContext, PluginOptions, ProviderKey, Token, ZnightMetadata } from '@znight/core'\nimport type {\n HttpAdapter,\n HttpServerAddress,\n InjectRequest,\n InjectResponse,\n InjectStreamOptions,\n InjectStreamResponse,\n} from './adapter.ts'\nimport type { HttpContext } from './context.ts'\nimport type { CookieSettings } from './cookie-settings.ts'\nimport type { CookieDefaults } from './cookies.ts'\nimport type { CorsOptions, CorsPolicy } from './cors.ts'\nimport type { InjectSseResponse } from './inject-sse.ts'\nimport type {\n CanActivate,\n ExceptionMapper,\n ExceptionMapperClass,\n GuardClass,\n HttpInterceptor,\n HttpInterceptorClass,\n} from './interfaces.ts'\nimport type { HttpControllerDefinition, HttpMetadata, HttpMethod, HttpRouteDefinition } from './metadata.ts'\nimport type { CollectedPluginRoute } from './plugin-routes.ts'\nimport type { TrustPolicy, TrustProxy } from './proxy.ts'\nimport type { SecurityHeadersOptions } from './security-headers.ts'\nimport type { ByteSize } from './size.ts'\n\nimport { displayName, ErrorCode, resolveOptions, ZnightError } from '@znight/core'\n\nimport { nodeAdapter } from './adapters/node.ts'\nimport { DEFAULT_COOKIE_SETTINGS, missingSecrets, signValue } from './cookie-settings.ts'\nimport { type CookieSecret, CookieSigner, checkSecrets } from './cookie-signer.ts'\nimport { DEFAULT_COOKIE_OPTIONS, decodeCookieValue, isCookieName, serializeResponseCookie } from './cookies.ts'\nimport { resolveCors } from './cors.ts'\nimport {\n type CheckedRoute,\n checkDecisions,\n conflictingKeys,\n type EnforcementMode,\n effectiveMeta,\n enforcedBy,\n RouteGroups,\n type RouteMeta,\n} from './decisions.ts'\nimport { isHeaderName } from './headers.ts'\nimport { openInjectSse } from './inject-sse.ts'\nimport { isMediaTypePattern } from './mime.ts'\nimport { invalidOption } from './option-error.ts'\nimport { compareRoutePaths, compareStrings, joinPaths, parseRoutePath, type RoutePath, RoutePathError } from './path.ts'\nimport {\n DEFAULT_SSE_SETTINGS,\n Pipeline,\n type Resolvable,\n type RoutePlan,\n randomRequestId,\n type SseSettings,\n} from './pipeline.ts'\nimport { collectPluginRoutes } from './plugin-routes.ts'\nimport { resolveTrustProxy } from './proxy.ts'\nimport { RouteTable } from './router.ts'\nimport { resolveSecurityHeaders } from './security-headers.ts'\nimport { parseByteSize } from './size.ts'\nimport { MAX_SSE_TIMER_MS, MIN_SSE_INTERVAL_MS } from './sse.ts'\nimport { isValidStatus } from './status.ts'\nimport { HttpTokens } from './tokens.ts'\nimport { bodyPlan, DEFAULT_UPLOAD_LIMITS, type ResolvedUploadLimits, type UploadLimits } from './uploads.ts'\n\n/** How requests whose path ends with an extra `/` are handled. */\nexport type TrailingSlashPolicy = 'strict' | 'ignore' | 'redirect'\n\n/** A global guard: a provider class (resolved with the container) or an instance. */\nexport type GuardRef = GuardClass | CanActivate\n/** A global interceptor: a provider class or an instance. */\nexport type InterceptorRef = HttpInterceptorClass | HttpInterceptor\n/** An exception mapper: a provider class or an instance. */\nexport type ExceptionMapperRef = ExceptionMapperClass | ExceptionMapper\n\n/** Options of {@link HttpPlugin.configure}. */\nexport interface HttpPluginOptions {\n /** Server implementation. Default: `nodeAdapter()` (built-in, `node:http`). */\n readonly adapter?: HttpAdapter\n /** Port to listen on (`0` picks a free port). Default: `3000`. */\n readonly port?: number\n /** Interface to bind. Default: `0.0.0.0`. */\n readonly host?: string\n /** Path prefix of every route (`/api`). Default: none. */\n readonly prefix?: string\n /** Guards run before the controller and route guards of every route. */\n readonly guards?: readonly GuardRef[]\n /** Interceptors wrapping every route (outermost first). */\n readonly interceptors?: readonly InterceptorRef[]\n /** Error-to-response mappers, tried in order (see `ExceptionMapper`). */\n readonly exceptionMappers?: readonly ExceptionMapperRef[]\n /**\n * `strict` (default): `/users/` does not match `/users`. `ignore`: it does. `redirect`: it is\n * redirected (308) to `/users`.\n */\n readonly trailingSlash?: TrailingSlashPolicy\n /** Send the message of unexpected errors in 500 responses (development only). Default: `false`. */\n readonly exposeErrors?: boolean\n /**\n * Maximum request body size (413 above): bytes or a size with a unit (`'10mb'`; `kb` = 1024\n * bytes), `Infinity` for no limit. Routes override it with `@BodyLimit`; upload routes default to\n * the sum of their file limits plus this value. Default: 1 MiB.\n */\n readonly bodyLimit?: ByteSize\n /** Limits of multipart bodies and defaults of the upload parameters (see `UploadLimits`). */\n readonly uploads?: UploadLimits\n /**\n * Header carrying the request id: reused when the client sends a valid one (≤ 128 characters of\n * `[A-Za-z0-9_-.:@/+=]`), echoed on every response. `false`: always generate, never echo.\n * Default: `x-request-id`.\n */\n readonly requestIdHeader?: string | false\n /** Request id generator. Default: `crypto.randomUUID()`. */\n readonly generateRequestId?: () => string\n /**\n * Maximum time `onStop` waits for in-flight requests before closing the remaining connections.\n * Keep it below the application `shutdown.hookTimeoutMs`. `Infinity`: no limit of its own (the\n * application's `hookTimeoutMs` still bounds `onStop`). Default: 4 000 ms.\n */\n readonly drainTimeoutMs?: number\n /**\n * CORS: preflights are answered before routing and guards (never by a route), and replies to\n * allowed origins get `access-control-allow-origin`, identically on every adapter. Default: off.\n *\n * ```ts\n * cors: { origin: ['https://app.example.com', /^https:\\/\\/[a-z0-9-]+\\.preview\\.example\\.com$/], credentials: true }\n * ```\n */\n readonly cors?: CorsOptions | false\n /**\n * Security headers added to every reply that does not set them (`@Res()` raw replies excepted):\n * `true` (default) for the API defaults, an object merged over them, `false` for none.\n */\n readonly securityHeaders?: boolean | SecurityHeadersOptions\n /**\n * Proxies trusted for `x-forwarded-for` / `x-forwarded-proto` (`ctx.ip`, `ctx.protocol`): a number\n * of hops, or addresses, CIDR ranges and the aliases `'loopback'`, `'private'`, `'linklocal'`.\n * Default `false`: the headers are ignored and `ctx.ip` is the adapter's address.\n */\n readonly trustProxy?: TrustProxy\n /**\n * What the boot check of route decisions does when a route misses a decision of a required group,\n * or when no guard of its chain enforces its decision (ZNIGHT023): `'error'` (default) fails the\n * boot, `'warn'` logs one warning per group (tests that deliberately run without guards).\n */\n readonly enforcement?: EnforcementMode\n /** Cookies: signing keys and defaults (see {@link HttpCookieOptions}). */\n readonly cookies?: HttpCookieOptions\n /** Server-Sent Events defaults (see {@link HttpSseOptions}). */\n readonly sse?: HttpSseOptions\n}\n\n/** The plugin option `cookies`. */\nexport interface HttpCookieOptions {\n /**\n * HMAC keys of signed cookies (`@SignedCookie`, `{ signed: true }`), at least 32 bytes each: the\n * first signs, all verify (rotation: deploy `[next, current]`, wait for the longest cookie\n * lifetime, then `[next]`). Default: none (signed cookies unavailable).\n */\n readonly secrets?: string | Uint8Array | readonly (string | Uint8Array)[]\n /**\n * Defaults of every cookie set by the application, merged over the secure defaults\n * `{ path: '/', secure: true, httpOnly: true, sameSite: 'lax' }` (e.g. `{ secure: false }` for\n * plain `http://` development setups on a non-localhost host).\n */\n readonly defaults?: CookieDefaults\n}\n\n/** The plugin option `sse`. */\nexport interface HttpSseOptions {\n /** Default heartbeat (ms, an integer ≥ 1 000, or `false`). Default: 8 000. */\n readonly heartbeat?: number | false\n /** Default `retry` sent first (ms). Default: none. */\n readonly retry?: number\n /**\n * Time an event source gets to finish after `ctx.signal` aborted on shutdown or `maxDuration` (ms),\n * before the stream ends with a jittered `retry`. Must be lower than `drainTimeoutMs`. Default:\n * 1 000.\n */\n readonly shutdownGraceMs?: number\n}\n\n/** A route registered by the plugin (see {@link HttpPlugin.routes}). */\nexport interface HttpRouteSummary {\n readonly method: string\n /** Registered path, prefix included. */\n readonly path: string\n /** Controller display name, or the name of the plugin declaring the route. */\n readonly controller: string\n readonly handler: string\n /** `'controller'` for compiled routes, the plugin name for plugin routes. */\n readonly source: string\n /** Effective route metadata (the nearest decision of each group). */\n readonly meta: Readonly<Record<string, unknown>>\n /** Display names of the guards, in chain order (global, controller, route). */\n readonly guards: readonly string[]\n}\n\ninterface Resolved {\n readonly adapter: HttpAdapter\n readonly port: number\n readonly host: string\n readonly prefix: string\n readonly trailingSlash: TrailingSlashPolicy\n readonly exposeErrors: boolean\n readonly bodyLimit: number\n readonly uploads: ResolvedUploadLimits\n readonly requestIdHeader: string | undefined\n readonly generateRequestId: () => string\n readonly drainTimeoutMs: number\n readonly cors: CorsPolicy | undefined\n readonly securityHeaders: Readonly<Record<string, string>>\n readonly trustProxy: TrustPolicy | undefined\n readonly enforcement: EnforcementMode\n readonly cookies: CookieSettings\n readonly sse: SseSettings\n}\n\n/** Resolved options and the raw options they come from (memoised per application). */\ninterface ResolvedOptions {\n readonly raw: HttpPluginOptions\n readonly options: Resolved\n}\n\ninterface Runtime {\n readonly adapter: HttpAdapter\n readonly pipeline: Pipeline\n readonly options: Resolved\n readonly routes: readonly HttpRouteSummary[]\n}\n\ninterface Registration {\n readonly method: Exclude<HttpMethod, 'ALL'>\n readonly path: RoutePath\n readonly plan: RoutePlan\n /** `BookController.list`, `plugin \"openapi\" (document)`. */\n readonly label: string\n readonly source: string\n readonly guards: readonly string[]\n}\n\n/** A guard of a chain: how to resolve it, the class whose `enforces` counts, its display name. */\ninterface GuardEntry {\n readonly resolvable: Resolvable<CanActivate>\n readonly cls: unknown\n readonly name: string\n}\n\nconst DEFAULT_PORT = 3000\nconst DEFAULT_HOST = '0.0.0.0'\nconst DEFAULT_BODY_LIMIT = 1_048_576\nconst DEFAULT_DRAIN_TIMEOUT_MS = 4_000\nconst DEFAULT_REQUEST_ID_HEADER = 'x-request-id'\n/** Longest `setTimeout` delay (larger ones overflow to 1 ms). */\nconst MAX_TIMER_MS = 2_147_483_647\n/** Adapters bound to a plugin (an adapter instance serves one application). */\nconst BOUND_ADAPTERS = new WeakSet<HttpAdapter>()\nconst CONCRETE_METHODS: readonly Exclude<HttpMethod, 'ALL'>[] = [\n 'GET',\n 'HEAD',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n]\n\n/**\n * The HTTP plugin: serves the controllers compiled into `metadata.extensions.http` with the chosen\n * adapter.\n *\n * ```ts\n * const app = await Application.create({\n * metadata: __ZNIGHT_METADATA__,\n * plugins: [HttpPlugin.configure({ port: 3000, prefix: '/api' })],\n * })\n * await app.start()\n * ```\n *\n * Lifecycle: `register` declares the request-scoped externals `HttpContext` and `RequestId`;\n * `onBootstrap` resolves the options, controllers, guards and interceptors, collects the routes of\n * other plugins (`httpRoutes()`), checks route decisions and registers the routes; `onStart`\n * listens; `onStop` stops accepting connections and drains in-flight requests (`drainTimeoutMs`);\n * `onDispose` closes the server.\n */\nexport class HttpPlugin implements Plugin {\n readonly name = 'http'\n readonly #options: PluginOptions<HttpPluginOptions>\n /** Options resolved for the current application (reset in `register`). */\n #resolved: ResolvedOptions | undefined\n #container: Container | undefined\n #runtime: Runtime | undefined\n #address: HttpServerAddress | undefined\n #disposed = false\n /** Registered in an application that was not disposed yet. */\n #active = false\n\n private constructor(options: PluginOptions<HttpPluginOptions>) {\n this.#options = options\n }\n\n /**\n * Creates the plugin. `options` may be a function of the container, evaluated in `onBootstrap`:\n * `HttpPlugin.configure(c => ({ port: c.get(AppConfig).port }))`.\n */\n static configure(options: PluginOptions<HttpPluginOptions> = {}): HttpPlugin {\n return new HttpPlugin(options)\n }\n\n /** The adapter (available after `onBootstrap`). */\n get adapter(): HttpAdapter {\n return this.#require('adapter').adapter\n }\n\n /** Address of the server once listening (`String(address)` is its URL), `undefined` otherwise. */\n get address(): HttpServerAddress | undefined {\n return this.#address\n }\n\n /**\n * The path prefix of every route (`''` without prefix, `/api`), for plugins that serve routes or\n * publish URLs. Readable once the plugin is registered (before or after its `onBootstrap`; at any\n * time when the options are not a function of the container). Throws the options error when\n * the options are invalid.\n */\n get prefix(): string {\n const prefix = this.#resolve('prefix').options.prefix\n return prefix === '/' ? '' : prefix\n }\n\n /** Registered routes (after `onBootstrap`), in registration order. */\n get routes(): readonly HttpRouteSummary[] {\n return this.#runtime?.routes ?? []\n }\n\n /** Number of requests being processed. */\n get inflight(): number {\n return this.#runtime?.pipeline.inflight ?? 0\n }\n\n /** Number of open event streams (`@Sse`, `HttpResponse.sse()`): health checks, gauges, stream caps. */\n get streams(): number {\n return this.#runtime?.pipeline.streams ?? 0\n }\n\n /**\n * The signed wire value of a cookie (`<encoded value>.<signature>`, signed with the first secret of\n * `cookies.secrets`): what a browser would send back after `setCookie(name, value, { signed: true })`.\n * For gateways minting cookies and for tests. Available after `onBootstrap`.\n *\n * @throws TypeError for an invalid name or value; Error without `cookies.secrets`.\n */\n signCookie(name: string, value: string): string {\n const signer = this.#require('signCookie()').options.cookies.signer\n if (!isCookieName(name)) throw new TypeError(`Invalid cookie name ${JSON.stringify(String(name))}`)\n if (typeof value !== 'string') throw new TypeError(`The value of the cookie \"${name}\" must be a string`)\n if (signer === undefined) throw missingSecrets(`Cannot sign the cookie \"${name}\"`)\n return signValue(signer, name, value)\n }\n\n /**\n * The provider classes the plugin resolves in `onBootstrap` although no compiled metadata\n * references them: the classes of the `guards`, `interceptors` and `exceptionMappers` options\n * (instances are left out), in that order, without duplicates. `TestApp` from `@znight/testing`\n * creates them at boot with their dependencies (an async dependency cannot be created on demand);\n * pass them to `init: { only }` when restricting the boot with `Application.create()`.\n *\n * Options given as a function of the container cannot be read before the bootstrap: the result is\n * then empty. Never throws: invalid options are reported by `onBootstrap`.\n */\n initRoots(): readonly ProviderKey[] {\n const options: unknown = this.#options\n if (options === null || typeof options !== 'object') return []\n const roots = new Set<ProviderKey>()\n for (const key of GLOBAL_KEYS) {\n try {\n const refs: unknown = (options as HttpPluginOptions)[key]\n if (!Array.isArray(refs)) continue\n for (const ref of refs) {\n if (typeof ref === 'function') roots.add(ref as GuardClass)\n }\n } catch {\n // a throwing getter: reported when onBootstrap reads the option\n }\n }\n return [...roots]\n }\n\n /**\n * Sends a request in memory through the adapter and the whole pipeline (no socket; the server\n * does not need to listen). Available after `onBootstrap`.\n *\n * ```ts\n * const res = await http.inject({ method: 'POST', url: '/users', body: { name: 'Ada' } })\n * expect(res.status).toBe(201)\n * expect(res.json()).toEqual({ id: 1, name: 'Ada' })\n * ```\n */\n inject(request: InjectRequest): Promise<InjectResponse> {\n try {\n const runtime = this.#require('inject()')\n return runtime.adapter.inject(withSignedCookies(request, runtime.options.cookies, 'inject()'))\n } catch (error) {\n return Promise.reject(error)\n }\n }\n\n /**\n * Sends a request in memory and resolves at the response headers, the body being read as it is\n * produced (`body`). Cancelling `body` (or aborting `signal`) disconnects the client. Requires an\n * adapter implementing `injectStream()` (the four built-in ones do).\n */\n injectStream(request: InjectStreamOptions): Promise<InjectStreamResponse> {\n try {\n if (request === null || typeof request !== 'object')\n throw new TypeError('injectStream() expects a request object')\n const runtime = this.#require('injectStream()')\n const adapter = runtime.adapter\n if (typeof adapter.injectStream !== 'function') {\n throw new ZnightError(\n ErrorCode.LifecycleFailed,\n `HttpPlugin: the ${adapter.name} adapter does not implement injectStream()`,\n { hints: ['Use a built-in adapter (node, fastify, express, hono) or implement HttpAdapter.injectStream()'] },\n )\n }\n const sent = { ...request, method: request.method ?? 'GET' }\n return adapter.injectStream(withSignedCookies(sent, runtime.options.cookies, 'injectStream()'))\n } catch (error) {\n return Promise.reject(error)\n }\n }\n\n /**\n * Opens an event stream in memory (`accept: text/event-stream`) and reads its events like\n * `EventSource`: `next()`, `take()`, `comments`, `retry`, `lastEventId`, `reconnect()`, `close()`\n * (the server sees a client disconnect). A response that is not an event stream (404, 204...) is\n * read to its end (`body`). Resolves at the first chunk of the stream (an `@Sse` stream sends\n * `retry` or a comment at once), or after 2 000 ms for a stream that sends nothing yet; rejects,\n * naming the request (which is aborted), when no response headers arrive within 2 000 ms.\n *\n * ```ts\n * await using stream = await http.injectSse({ url: '/orders/o-1/events' })\n * const event = await stream.next() // rejects after 2 000 ms\n * expect(event.json()).toMatchObject({ status: 'paid' })\n * ```\n */\n injectSse(request: InjectStreamOptions): Promise<InjectSseResponse> {\n return openInjectSse(stream => this.injectStream(stream), request)\n }\n\n register(ctx: PluginContext): void {\n if (this.#active) {\n throw new ZnightError(ErrorCode.DuplicateProvider, 'This HttpPlugin is already used by another application', {\n hints: ['Call HttpPlugin.configure() once per application'],\n })\n }\n // an instance may serve several applications one after the other (shared test setups)\n this.#active = true\n this.#disposed = false\n this.#runtime = undefined\n this.#address = undefined\n this.#resolved = undefined\n this.#container = ctx.container\n ctx.container.registerExternal({ token: HttpTokens.Context, scope: 'request', providedBy: 'HttpPlugin' })\n ctx.container.registerExternal({ token: HttpTokens.RequestId, scope: 'request', providedBy: 'HttpPlugin' })\n ctx.container.registerValue(HttpTokens.Plugin, this)\n }\n\n onBootstrap(ctx: PluginContext): void {\n this.#container = ctx.container\n const { raw, options } = this.#resolve('onBootstrap')\n if (BOUND_ADAPTERS.has(options.adapter)) {\n throw new ZnightError(\n ErrorCode.LifecycleFailed,\n `HttpPlugin: this ${options.adapter.name} adapter instance already served an application`,\n {\n hints: [\n 'An adapter instance serves one application: create it per application, e.g. HttpPlugin.configure(() => ({ adapter: fastifyAdapter() }))',\n ],\n },\n )\n }\n BOUND_ADAPTERS.add(options.adapter)\n const table = new RouteTable<RoutePlan>()\n const pipeline = new Pipeline(\n ctx.container,\n ctx.hooks,\n ctx.logger,\n {\n adapter: options.adapter.name,\n body: bodyPlan({}, options.bodyLimit, options.uploads),\n exposeErrors: options.exposeErrors,\n requestIdHeader: options.requestIdHeader,\n generateRequestId: options.generateRequestId,\n mappers: globalRefs<ExceptionMapper>(ctx.container, ctx.metadata, raw, 'exceptionMappers'),\n cors: options.cors,\n securityHeaders: options.securityHeaders,\n trustProxy: options.trustProxy,\n cookies: options.cookies,\n sse: options.sse,\n },\n table,\n )\n const pluginRoutes = collectPluginRoutes(ctx.app.plugins, this, {\n prefix: options.prefix === '/' ? '' : options.prefix,\n container: ctx.container,\n })\n const { registrations, checked } = buildRegistrations(ctx, options, raw, pluginRoutes)\n checkDecisions(checked.routes, checked.groups, options.enforcement, ctx.logger, checked.enforcers)\n const adapter = options.adapter\n const routes: HttpRouteSummary[] = []\n for (const registration of registrations) {\n table.add(registration.method, registration.path, registration.plan)\n const plan = registration.plan\n adapter.registerRoute({\n method: registration.method,\n path: registration.path,\n handler: pipeline.handler(plan),\n })\n routes.push(\n Object.freeze({\n method: registration.method,\n path: registration.path.path,\n controller: registration.source === 'controller' ? displayName(plan.info.controller) : registration.source,\n handler: plan.info.handler,\n source: registration.source,\n meta: plan.info.meta,\n guards: registration.guards,\n }),\n )\n }\n adapter.setFallbackHandler((request, error) => pipeline.fallback(request, error))\n this.#runtime = { adapter, pipeline, options, routes: Object.freeze(routes) }\n }\n\n async onStart(ctx: PluginContext): Promise<void> {\n const runtime = this.#require('onStart')\n runtime.pipeline.draining = false\n this.#address = await runtime.adapter.listen(runtime.options.port, runtime.options.host)\n ctx.logger.info(`HTTP server listening on ${this.#address.url}`, {\n adapter: runtime.adapter.name,\n routes: runtime.routes.length,\n })\n }\n\n async onStop(ctx: PluginContext): Promise<void> {\n const runtime = this.#runtime\n if (runtime === undefined) return\n runtime.pipeline.draining = true\n // event streams never end by themselves: let their sources finish, then send them a jittered retry\n runtime.pipeline.closeStreams('shutdown')\n const timeoutMs = runtime.options.drainTimeoutMs\n let timer: ReturnType<typeof setTimeout> | undefined\n // no timer for Infinity; larger delays than setTimeout supports are clamped (they would fire at once)\n const timeout = new Promise<'timeout'>(resolve => {\n if (timeoutMs !== Number.POSITIVE_INFINITY) {\n timer = setTimeout(() => resolve('timeout'), Math.min(timeoutMs, MAX_TIMER_MS))\n }\n })\n try {\n const drained = Promise.all([runtime.adapter.close(), runtime.pipeline.whenIdle()]).then(() => 'drained' as const)\n if ((await Promise.race([drained, timeout])) === 'timeout') {\n ctx.logger.warn(`HTTP server: closing ${runtime.pipeline.inflight} in-flight request(s) after ${timeoutMs} ms`)\n await runtime.adapter.close({ force: true })\n }\n } finally {\n clearTimeout(timer)\n this.#address = undefined\n }\n }\n\n async onDispose(): Promise<void> {\n this.#active = false\n if (this.#disposed) return\n this.#disposed = true\n const runtime = this.#runtime\n this.#address = undefined\n if (runtime !== undefined) await runtime.adapter.close({ force: true })\n }\n\n /** Resolves the options once per application (`prefix` may need them before `onBootstrap`). */\n #resolve(action: string): ResolvedOptions {\n if (this.#resolved !== undefined) return this.#resolved\n let raw: HttpPluginOptions\n if (typeof this.#options === 'function') {\n const container = this.#container\n if (container === undefined) {\n throw new ZnightError(\n ErrorCode.LifecycleFailed,\n `HttpPlugin: ${action} is only available once the plugin is registered in an application (its options are a function of the container)`,\n )\n }\n raw = resolveOptions(this.#options, container)\n } else {\n raw = this.#options\n }\n const resolved: ResolvedOptions = { raw, options: resolve(raw) }\n this.#resolved = resolved\n return resolved\n }\n\n #require(action: string): Runtime {\n if (this.#disposed) {\n throw new ZnightError(ErrorCode.LifecycleFailed, `HttpPlugin: cannot use ${action} after the application stopped`)\n }\n if (this.#runtime === undefined) {\n throw new ZnightError(\n ErrorCode.LifecycleFailed,\n `HttpPlugin: ${action} is only available once the application is created (after onBootstrap)`,\n )\n }\n return this.#runtime\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Options\n// -------------------------------------------------------------------------------------------------\n\nfunction resolve(options: HttpPluginOptions): Resolved {\n if (options === null || typeof options !== 'object') throw invalidOption('options', 'an object', options)\n const port = options.port ?? DEFAULT_PORT\n if (!Number.isInteger(port) || port < 0 || port > 65_535)\n throw invalidOption('port', 'an integer between 0 and 65535', port)\n const host = options.host ?? DEFAULT_HOST\n if (typeof host !== 'string' || host === '') throw invalidOption('host', 'a non-empty string', host)\n const prefix = options.prefix ?? ''\n if (typeof prefix !== 'string') throw invalidOption('prefix', 'a string', prefix)\n let parsedPrefix: RoutePath\n try {\n parsedPrefix = parseRoutePath(prefix)\n } catch (error) {\n throw invalidOption('prefix', 'a valid static path', prefix, error)\n }\n if (parsedPrefix.segments.some(segment => segment.kind !== 'static')) {\n throw invalidOption('prefix', 'a static path (no :param or *)', prefix)\n }\n const trailingSlash = options.trailingSlash ?? 'strict'\n if (trailingSlash !== 'strict' && trailingSlash !== 'ignore' && trailingSlash !== 'redirect') {\n throw invalidOption('trailingSlash', '\"strict\", \"ignore\" or \"redirect\"', trailingSlash)\n }\n const bodyLimit = parseByteSize(options.bodyLimit ?? DEFAULT_BODY_LIMIT)\n if (bodyLimit === undefined) {\n throw invalidOption('bodyLimit', \"a size in bytes (1048576, '10mb', Infinity)\", options.bodyLimit)\n }\n const uploads = resolveUploadLimits(options.uploads)\n const drainTimeoutMs = options.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS\n if (typeof drainTimeoutMs !== 'number' || !(drainTimeoutMs >= 0)) {\n throw invalidOption('drainTimeoutMs', 'a positive number (or Infinity)', drainTimeoutMs)\n }\n const requestIdHeader = options.requestIdHeader ?? DEFAULT_REQUEST_ID_HEADER\n if (requestIdHeader !== false && (typeof requestIdHeader !== 'string' || !isHeaderName(requestIdHeader))) {\n throw invalidOption('requestIdHeader', 'a header name or false', requestIdHeader)\n }\n const generateRequestId = options.generateRequestId ?? randomRequestId\n if (typeof generateRequestId !== 'function') throw invalidOption('generateRequestId', 'a function', generateRequestId)\n const adapter = options.adapter ?? nodeAdapter()\n if (\n adapter === null ||\n typeof adapter !== 'object' ||\n typeof adapter.registerRoute !== 'function' ||\n typeof adapter.listen !== 'function' ||\n typeof adapter.inject !== 'function'\n ) {\n throw invalidOption('adapter', 'an HttpAdapter (nodeAdapter(), fastifyAdapter()...)', adapter)\n }\n const enforcement = options.enforcement ?? 'error'\n if (enforcement !== 'error' && enforcement !== 'warn') {\n throw invalidOption('enforcement', '\"error\" or \"warn\"', enforcement)\n }\n const resolvedRequestIdHeader = requestIdHeader === false ? undefined : requestIdHeader.toLowerCase()\n const cookies = resolveCookies(options.cookies)\n const sse = resolveSse(options.sse, drainTimeoutMs)\n return {\n adapter,\n port,\n host,\n prefix: parsedPrefix.path,\n trailingSlash,\n exposeErrors: options.exposeErrors === true,\n bodyLimit,\n uploads,\n requestIdHeader: resolvedRequestIdHeader,\n generateRequestId,\n drainTimeoutMs,\n cors: resolveCors(options.cors, resolvedRequestIdHeader),\n securityHeaders: resolveSecurityHeaders(options.securityHeaders),\n trustProxy: resolveTrustProxy(options.trustProxy),\n enforcement,\n cookies,\n sse,\n }\n}\n\nconst COOKIE_DEFAULT_KEYS = ['domain', 'path', 'secure', 'httpOnly', 'sameSite', 'partitioned', 'priority']\n\nfunction resolveCookies(value: HttpCookieOptions | undefined): CookieSettings {\n if (value === undefined) return DEFAULT_COOKIE_SETTINGS\n if (value === null || typeof value !== 'object')\n throw invalidOption('cookies', 'an object { secrets?, defaults? }', value)\n for (const key of Object.keys(value)) {\n if (key !== 'secrets' && key !== 'defaults') {\n throw invalidOption('cookies', 'an object { secrets?, defaults? }', `unknown key \"${key}\"`)\n }\n }\n let signer: CookieSigner | undefined\n if (value.secrets !== undefined) {\n const checked = checkSecrets(value.secrets)\n // never echo a secret in an error\n if ('problem' in checked) {\n throw new ZnightError(\n ErrorCode.InvalidDecorator,\n `HttpPlugin: option \"cookies.secrets\" must be ${checked.problem}`,\n {\n hints: [\"Generate secrets with crypto.randomBytes(32).toString('base64url') and load them with @Secret\"],\n },\n )\n }\n signer = new CookieSigner(checked.secrets as readonly CookieSecret[])\n }\n const given = value.defaults\n if (given !== undefined && (given === null || typeof given !== 'object' || Array.isArray(given))) {\n throw invalidOption('cookies.defaults', `an object { ${COOKIE_DEFAULT_KEYS.join('?, ')}? }`, given)\n }\n const defaults: CookieDefaults = { ...DEFAULT_COOKIE_OPTIONS }\n for (const [key, option] of Object.entries(given ?? {})) {\n if (!COOKIE_DEFAULT_KEYS.includes(key)) {\n throw invalidOption(\n 'cookies.defaults',\n `an object { ${COOKIE_DEFAULT_KEYS.join('?, ')}? }`,\n `unknown key \"${key}\"`,\n )\n }\n if (option !== undefined) (defaults as Record<string, unknown>)[key] = option\n }\n try {\n // a probe cookie checks every default and their combination (SameSite=None without Secure...)\n serializeResponseCookie({ name: 'probe', value: '', options: {} }, defaults)\n } catch (error) {\n throw invalidOption('cookies.defaults', 'valid cookie attributes', given, error, [\n error instanceof Error ? error.message.replace('Invalid cookie \"probe\": ', '') : String(error),\n ])\n }\n return Object.freeze({ defaults: Object.freeze(defaults), signer })\n}\n\nfunction resolveSse(value: HttpSseOptions | undefined, drainTimeoutMs: number): SseSettings {\n if (value === undefined) return DEFAULT_SSE_SETTINGS\n const shape = '{ heartbeat?, retry?, shutdownGraceMs? }'\n if (value === null || typeof value !== 'object') throw invalidOption('sse', `an object ${shape}`, value)\n for (const key of Object.keys(value)) {\n if (key !== 'heartbeat' && key !== 'retry' && key !== 'shutdownGraceMs') {\n throw invalidOption('sse', `an object ${shape}`, `unknown key \"${key}\"`)\n }\n }\n const heartbeat = value.heartbeat ?? DEFAULT_SSE_SETTINGS.heartbeat\n if (\n heartbeat !== false &&\n !(Number.isSafeInteger(heartbeat) && heartbeat >= MIN_SSE_INTERVAL_MS && heartbeat <= MAX_SSE_TIMER_MS)\n ) {\n throw invalidOption(\n 'sse.heartbeat',\n `an integer number of ms from ${MIN_SSE_INTERVAL_MS} to ${MAX_SSE_TIMER_MS}, or false`,\n heartbeat,\n )\n }\n const retry = value.retry\n if (retry !== undefined && !(Number.isSafeInteger(retry) && retry >= 0)) {\n throw invalidOption('sse.retry', 'an integer number of ms ≥ 0', retry)\n }\n const shutdownGraceMs = value.shutdownGraceMs ?? DEFAULT_SSE_SETTINGS.shutdownGraceMs\n if (!(Number.isSafeInteger(shutdownGraceMs) && shutdownGraceMs >= 0 && shutdownGraceMs <= MAX_SSE_TIMER_MS)) {\n throw invalidOption('sse.shutdownGraceMs', `an integer number of ms from 0 to ${MAX_SSE_TIMER_MS}`, shutdownGraceMs)\n }\n if (drainTimeoutMs !== Number.POSITIVE_INFINITY && shutdownGraceMs >= drainTimeoutMs) {\n throw invalidOption(\n 'sse.shutdownGraceMs',\n `lower than drainTimeoutMs (${drainTimeoutMs})`,\n shutdownGraceMs,\n undefined,\n [\n 'Event streams get shutdownGraceMs to finish, within the drain of in-flight requests: shutdownGraceMs < drainTimeoutMs < shutdown.hookTimeoutMs',\n ],\n )\n }\n return Object.freeze({ heartbeat: heartbeat === false ? 0 : heartbeat, retry, shutdownGraceMs })\n}\n\n/**\n * The request with its `signedCookies` signed (first secret) and merged into `cookies`: adapters\n * never receive `signedCookies`.\n */\nfunction withSignedCookies<R extends InjectRequest>(request: R, cookies: CookieSettings, action: string): R {\n if (request === null || typeof request !== 'object' || request.signedCookies === undefined) return request\n const signed = request.signedCookies\n if (signed === null || typeof signed !== 'object') throw new TypeError(`${action}: signedCookies must be an object`)\n const signer = cookies.signer\n if (signer === undefined) {\n throw new TypeError(\n `${action}: signedCookies require the HttpPlugin option cookies.secrets (HttpPlugin.configure({ cookies: { secrets: [...] } }))`,\n )\n }\n const merged: Record<string, string> = { ...request.cookies }\n for (const name of Object.keys(signed)) {\n const value = signed[name]\n if (!isCookieName(name)) throw new TypeError(`${action}: invalid signed cookie name ${JSON.stringify(name)}`)\n if (typeof value !== 'string')\n throw new TypeError(`${action}: the value of the signed cookie \"${name}\" must be a string`)\n // the decoded wire value: inject() encodes cookie values again (the encoding is canonical)\n merged[name] = decodeCookieValue(signValue(signer, name, value))\n }\n const { signedCookies: _signed, ...rest } = request\n return { ...rest, cookies: merged } as R\n}\n\nfunction resolveUploadLimits(value: UploadLimits | undefined): ResolvedUploadLimits {\n if (value === undefined) return DEFAULT_UPLOAD_LIMITS\n if (value === null || typeof value !== 'object') throw invalidOption('uploads', 'an object', value)\n const size = (key: 'maxFileSize' | 'maxFieldSize'): number => {\n const raw = value[key]\n if (raw === undefined) return DEFAULT_UPLOAD_LIMITS[key]\n const parsed = parseByteSize(raw)\n if (parsed === undefined) throw invalidOption(`uploads.${key}`, \"a size in bytes (1048576, '10mb', Infinity)\", raw)\n return parsed\n }\n const count = (key: 'maxFiles' | 'maxParts'): number => {\n const raw = value[key]\n if (raw === undefined) return DEFAULT_UPLOAD_LIMITS[key]\n if (raw !== Number.POSITIVE_INFINITY && (!Number.isSafeInteger(raw) || raw < 1)) {\n throw invalidOption(`uploads.${key}`, 'a positive integer (or Infinity)', raw)\n }\n return raw\n }\n for (const key of Object.keys(value)) {\n if (!['maxFileSize', 'maxFiles', 'maxParts', 'maxFieldSize'].includes(key)) {\n throw invalidOption('uploads', '{ maxFileSize?, maxFiles?, maxParts?, maxFieldSize? }', value)\n }\n }\n return {\n maxFileSize: size('maxFileSize'),\n maxFiles: count('maxFiles'),\n maxParts: count('maxParts'),\n maxFieldSize: size('maxFieldSize'),\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Routes\n// -------------------------------------------------------------------------------------------------\n\nfunction httpMetadata(metadata: ZnightMetadata): HttpMetadata {\n const http = metadata.extensions?.http\n if (http === undefined) return { controllers: [] }\n if (http === null || typeof http !== 'object' || !Array.isArray(http.controllers)) {\n throw new ZnightError(ErrorCode.InvalidRoute, 'Invalid metadata.extensions.http: expected { controllers: [...] }')\n }\n return http\n}\n\n/** Routes as seen by the boot check of route decisions, with the groups they are checked against. */\ninterface Checked {\n readonly routes: readonly CheckedRoute[]\n readonly groups: RouteGroups\n /** Group → the guard classes enforcing it, in a chain or not. */\n readonly enforcers: ReadonlyMap<string, ReadonlySet<string>>\n}\n\n/** A declared route (controller route or plugin route), before HEAD, `@All` and trailing-slash expansion. */\ninterface Declared {\n readonly method: HttpMethod\n readonly path: RoutePath\n readonly plan: (method: string) => RoutePlan\n readonly label: string\n readonly source: string\n readonly guards: readonly GuardEntry[]\n /** Effective metadata (available once every group is known). */\n meta(): RouteMeta\n}\n\nfunction buildRegistrations(\n ctx: PluginContext,\n options: Resolved,\n raw: HttpPluginOptions,\n pluginRoutes: readonly CollectedPluginRoute[],\n): { readonly registrations: Registration[]; readonly checked: Checked } {\n const { container, metadata } = ctx\n const http = httpMetadata(metadata)\n const groups = RouteGroups.fromMetadata(http.groups)\n const groupOf = (key: string): string => groups.groupOf(key)\n const resolvables = new Map<Token, Resolvable<unknown>>()\n const lookup = <T>(token: Token, what: string): Resolvable<T> => {\n let found = resolvables.get(token)\n if (found === undefined) {\n found = resolvable(container, metadata, token, what)\n resolvables.set(token, found)\n }\n return found as Resolvable<T>\n }\n const compiledGuard = (token: Token, what: string): GuardEntry => ({\n resolvable: lookup<CanActivate>(token, what),\n // the compiled class: a guard replaced through `overrides` in a test keeps its declaration\n cls: Object.hasOwn(metadata.providers, token) ? metadata.providers[token]?.class : undefined,\n name: displayName(token),\n })\n const globalGuards = guardEntries(container, metadata, raw.guards ?? [], ref =>\n invalidOption('guards', 'classes or objects with a canActivate() method', ref),\n )\n const globalInterceptors = globalRefs<HttpInterceptor>(container, metadata, raw, 'interceptors')\n const declared: Declared[] = []\n /** Checks run once every group is declared. */\n const pending: (() => void)[] = []\n\n for (const controller of http.controllers) {\n assertController(controller)\n const name = displayName(controller.token)\n const instance = lookup<object>(controller.token, `controller ${name}`)\n const controllerGuards = controller.guards.map(token => compiledGuard(token, `guard of ${name}`))\n const controllerInterceptors = controller.interceptors.map(token =>\n lookup<HttpInterceptor>(token, `interceptor of ${name}`),\n )\n const controllerMeta = assertMeta(controller.meta, name)\n pending.push(() => checkTargetMeta(controllerMeta, groupOf, name))\n for (const route of controller.routes) {\n const where = `${name}.${String(route?.handler)}`\n assertRoute(route, where)\n if (options.cookies.signer === undefined) {\n const signed = route.params.find(param => param?.source === 'signedCookie')\n if (signed !== undefined) {\n throw new ZnightError(\n ErrorCode.MissingConfig,\n `HttpPlugin: ${where} reads a signed cookie (@SignedCookie('${signed.name ?? ''}')) but cookies.secrets is not set`,\n {\n hints: [\n \"Set HttpPlugin.configure({ cookies: { secrets: [...] } }) with secrets of at least 32 bytes (crypto.randomBytes(32).toString('base64url'))\",\n ],\n },\n )\n }\n }\n let path: RoutePath\n try {\n path = parseRoutePath(joinPaths(options.prefix, route.fullPath))\n } catch (error) {\n if (!(error instanceof RoutePathError)) throw error\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route ${route.method} ${route.fullPath} (${where}): ${error.issue.message}`,\n { cause: error },\n )\n }\n const routeMeta = assertMeta(route.meta, where)\n const guards = [\n ...globalGuards,\n ...controllerGuards,\n ...route.guards.map(token => compiledGuard(token, `guard of ${where}`)),\n ]\n const interceptors = [\n ...globalInterceptors,\n ...controllerInterceptors,\n ...route.interceptors.map(token => lookup<HttpInterceptor>(token, `interceptor of ${where}`)),\n ]\n const body = bodyPlan(route, options.bodyLimit, options.uploads)\n const parseBody = body.upload || route.params.some(param => param.source === 'body')\n const chain = guards.map(guard => guard.resolvable)\n // computed once every group is declared (guards of every chain, plugin routes), then frozen\n let meta: RouteMeta | undefined\n const effective = (): RouteMeta => {\n meta ??= effectiveMeta(controllerMeta, routeMeta, groupOf)\n return meta\n }\n pending.push(() => checkTargetMeta(routeMeta, groupOf, where))\n declared.push({\n method: route.method,\n path,\n plan: (method: string): RoutePlan => ({\n definition: route,\n path,\n info: Object.freeze({\n method,\n path: path.path,\n controller: controller.token,\n handler: route.handler,\n meta: effective(),\n }),\n controller: instance,\n guards: chain,\n interceptors,\n parseBody,\n body,\n }),\n label: where,\n source: 'controller',\n guards,\n meta: effective,\n })\n }\n }\n\n for (const route of pluginRoutes) {\n const label = `plugin \"${route.plugin}\" (${route.name})`\n const where = `${route.method} ${route.path.path} (${route.name})`\n const guards = [\n ...globalGuards,\n ...guardEntries(\n container,\n metadata,\n route.guards,\n ref =>\n new ZnightError(\n ErrorCode.InvalidRoute,\n `HttpPlugin: plugin \"${route.plugin}\": the guards of the route ${where} must be classes or objects with a canActivate() method (received ${describeValue(ref)})`,\n ),\n ),\n ]\n const values: Record<string, unknown> = {}\n for (const entry of route.meta) {\n groups.declare(entry, `the plugin \"${route.plugin}\"`)\n values[entry.key] = entry.value\n }\n const meta: RouteMeta = Object.freeze(values)\n pending.push(() => checkTargetMeta(meta, groupOf, `the route ${where} of the plugin \"${route.plugin}\"`))\n const handler = route.handler\n const definition: HttpRouteDefinition = Object.freeze({\n method: route.method,\n path: route.relativePath,\n fullPath: route.relativePath,\n handler: route.name,\n meta,\n guards: [],\n interceptors: [],\n params: [],\n invoke: (_plugin: unknown, http: HttpContext): unknown => handler(http),\n })\n const instance: Resolvable<object> = { instance: route.instance }\n const body = bodyPlan({}, options.bodyLimit, options.uploads)\n const chain = guards.map(guard => guard.resolvable)\n const path = route.path\n declared.push({\n method: route.method,\n path,\n plan: (method: string): RoutePlan => ({\n definition,\n path,\n info: Object.freeze({ method, path: path.path, controller: route.plugin, handler: route.name, meta }),\n controller: instance,\n guards: chain,\n // global interceptors wrap controllers only (a response envelope would break a document)\n interceptors: [],\n parseBody: false,\n body,\n }),\n label,\n source: route.plugin,\n guards,\n meta: () => meta,\n })\n }\n\n // `enforces` of every guard class, read once per class. The guards of the chains declare their\n // groups; the guard classes of the application that sit in no chain only make their groups known,\n // so that a decision whose guard was forgotten everywhere (a second entrypoint, a worker, a test)\n // is still reported instead of being silently unenforced\n const enforcedGroups = new Map<unknown, ReadonlySet<string>>()\n const enforcers = new Map<string, Set<string>>()\n const readEnforces = (cls: unknown, name: string, chained: boolean): void => {\n if (enforcedGroups.has(cls)) return\n const infos = enforcedBy(cls, name)\n if (chained) for (const info of infos) groups.declare(info, `the guard ${name}`)\n enforcedGroups.set(cls, new Set(infos.map(info => info.group)))\n for (const info of infos) {\n let names = enforcers.get(info.group)\n if (names === undefined) {\n names = new Set()\n enforcers.set(info.group, names)\n }\n names.add(name)\n }\n }\n for (const route of declared) for (const guard of route.guards) readEnforces(guard.cls, guard.name, true)\n for (const token of Object.keys(metadata.providers)) {\n const cls = metadata.providers[token]?.class\n if (isGuardClass(cls)) readEnforces(cls, displayName(token), false)\n }\n for (const check of pending) check()\n const checked: CheckedRoute[] = declared.map(route => {\n const enforced = new Set<string>()\n for (const guard of route.guards) for (const group of enforcedGroups.get(guard.cls) ?? []) enforced.add(group)\n return {\n description: `${route.method} ${route.path.path} (${route.label})`,\n meta: route.meta(),\n enforced,\n ...(route.source === 'controller' ? {} : { plugin: route.source }),\n }\n })\n\n const registration = (route: Declared, method: Exclude<HttpMethod, 'ALL'>): Registration => ({\n method,\n path: route.path,\n plan: route.plan(method),\n label: route.label,\n source: route.source,\n guards: Object.freeze(route.guards.map(guard => guard.name)),\n })\n const explicit: Registration[] = []\n const catchAll: Declared[] = []\n for (const route of declared) {\n if (route.method === 'ALL') catchAll.push(route)\n else explicit.push(registration(route, route.method))\n }\n\n // explicit routes, then HEAD for GET routes, then @All routes for the methods left\n const table = new RouteTable<Registration>()\n const accepted: Registration[] = []\n const add = (candidate: Registration, duplicate: boolean): void => {\n const existing = table.add(candidate.method, candidate.path, candidate)\n if (existing === undefined) accepted.push(candidate)\n else if (duplicate) throw duplicateRoute(candidate, existing)\n }\n for (const candidate of explicit) add(candidate, true)\n for (const candidate of explicit) {\n if (candidate.method === 'GET') add({ ...candidate, method: 'HEAD' }, false)\n }\n const catchAllShapes = new Map<string, Registration>()\n for (const route of catchAll) {\n const first = registration(route, 'GET')\n const other = catchAllShapes.get(route.path.shape)\n if (other !== undefined) throw duplicateRoute(first, other)\n catchAllShapes.set(route.path.shape, first)\n for (const method of CONCRETE_METHODS) add(method === 'GET' ? first : registration(route, method), false)\n }\n\n // trailing-slash variants\n const result: Registration[] = [...accepted]\n if (options.trailingSlash !== 'strict') {\n for (const candidate of accepted) {\n const path = candidate.path\n if (path.segments.length === 0 || path.wildcard) continue\n const variant: RoutePath = {\n path: `${path.path}/`,\n segments: [...path.segments, { kind: 'static', value: '' }],\n params: path.params,\n wildcard: false,\n shape: `${path.shape}/`,\n }\n const plan: RoutePlan =\n options.trailingSlash === 'redirect'\n ? { ...candidate.plan, path: variant, redirect: true }\n : { ...candidate.plan, path: variant }\n result.push({ ...candidate, path: variant, plan })\n }\n }\n\n // HEAD first (Express answers HEAD with the first matching GET route), then most specific first\n const registrations = result.sort((a, b) => {\n const head = (a.method === 'HEAD' ? 0 : 1) - (b.method === 'HEAD' ? 0 : 1)\n if (head !== 0) return head\n return compareRoutePaths(a.path, b.path) || compareStrings(a.method, b.method)\n })\n return { registrations, checked: { routes: checked, groups, enforcers } }\n}\n\nconst EMPTY_META: RouteMeta = Object.freeze({})\n\n/** Hand-written metadata: two keys of one group on one target (ZNIGHT007). */\nfunction checkTargetMeta(meta: RouteMeta, groupOf: (key: string) => string, target: string): void {\n const conflict = conflictingKeys(meta, groupOf)\n if (conflict === undefined) return\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route metadata of ${target}: \"${conflict[0]}\" and \"${conflict[1]}\" are two decisions of the \"${conflict[2]}\" group`,\n { hints: ['The decorators of a group are alternatives: keep one per controller or route'] },\n )\n}\n\nfunction duplicateRoute(registration: Registration, existing: Registration): ZnightError {\n const plugin = registration.source === 'controller' ? existing.source : registration.source\n return new ZnightError(\n ErrorCode.InvalidRoute,\n `Duplicate route ${registration.method} ${registration.path.path}: ${registration.label} conflicts with ${existing.label} (${existing.path.path})`,\n {\n hints: [\n 'Two routes with the same method and the same path shape (parameter names aside) cannot coexist',\n ...(plugin === 'controller' ? [] : [`Change the path of the route in the options of the plugin \"${plugin}\"`]),\n ],\n },\n )\n}\n\n/** Route metadata must be a plain object (hand-written metadata). */\nfunction assertMeta(meta: unknown, where: string): RouteMeta {\n if (meta === undefined) return EMPTY_META\n if (meta === null || typeof meta !== 'object' || Array.isArray(meta)) {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route metadata of ${where}: expected an object (received ${describeValue(meta)})`,\n )\n }\n return meta as RouteMeta\n}\n\nfunction assertController(controller: HttpControllerDefinition): void {\n if (\n controller === null ||\n typeof controller !== 'object' ||\n typeof controller.token !== 'string' ||\n !Array.isArray(controller.routes) ||\n !Array.isArray(controller.guards) ||\n !Array.isArray(controller.interceptors)\n ) {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid controller definition in metadata.extensions.http: ${describeValue(controller)}`,\n )\n }\n}\n\nfunction assertRoute(route: HttpRouteDefinition, where: string): void {\n if (\n route === null ||\n typeof route !== 'object' ||\n typeof route.invoke !== 'function' ||\n typeof route.handler !== 'string'\n ) {\n throw new ZnightError(ErrorCode.InvalidRoute, `Invalid route definition ${where}: missing handler or invoke()`)\n }\n if (!(CONCRETE_METHODS as readonly string[]).includes(route.method) && route.method !== 'ALL') {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route ${where}: unknown method ${describeValue(route.method)}`,\n )\n }\n if (typeof route.fullPath !== 'string') {\n throw new ZnightError(ErrorCode.InvalidRoute, `Invalid route ${where}: missing fullPath`)\n }\n if (route.status !== undefined && !isValidStatus(route.status)) {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route ${where}: @HttpCode(${describeValue(route.status)}) is not a valid status`,\n )\n }\n if (!Array.isArray(route.guards) || !Array.isArray(route.interceptors) || !Array.isArray(route.params)) {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route ${where}: guards, interceptors and params must be arrays`,\n )\n }\n if (route.bodyLimit !== undefined && !isSize(route.bodyLimit)) {\n throw new ZnightError(\n ErrorCode.InvalidRoute,\n `Invalid route ${where}: bodyLimit must be a number of bytes (or Infinity), got ${describeValue(route.bodyLimit)}`,\n )\n }\n if (route.uploads !== undefined) assertUploads(route, where)\n if (route.sse !== undefined) assertSse(route, where)\n}\n\nfunction assertSse(route: HttpRouteDefinition, where: string): void {\n const sse: unknown = route.sse\n const invalid = (reason: string): ZnightError =>\n new ZnightError(ErrorCode.InvalidRoute, `Invalid route ${where}: ${reason}`, {\n hints: [\n 'sse: { heartbeat?: 0 | 1000 ≤ ms ≤ 2147483647, retry?: ms ≥ 0, maxDuration?: 1000 ≤ ms ≤ 2147483647 } on a GET route',\n ],\n })\n if (route.method !== 'GET') throw invalid(`sse is only valid on GET routes (method ${route.method})`)\n if (sse === null || typeof sse !== 'object' || Array.isArray(sse)) throw invalid('sse must be an object')\n for (const [key, value] of Object.entries(sse)) {\n if (value === undefined) continue\n const integer = typeof value === 'number' && Number.isSafeInteger(value)\n const timer = integer && value >= MIN_SSE_INTERVAL_MS && value <= MAX_SSE_TIMER_MS\n const valid =\n (key === 'heartbeat' && integer && (value === 0 || timer)) ||\n (key === 'retry' && integer && value >= 0) ||\n (key === 'maxDuration' && timer)\n if (!valid) throw invalid(`invalid sse.${key} ${describeValue(value)}`)\n }\n}\n\nfunction isSize(value: unknown): boolean {\n return value === Number.POSITIVE_INFINITY || (Number.isSafeInteger(value) && (value as number) >= 0)\n}\n\nfunction assertUploads(route: HttpRouteDefinition, where: string): void {\n const invalid = (reason: string): ZnightError =>\n new ZnightError(ErrorCode.InvalidRoute, `Invalid route ${where}: ${reason}`, {\n hints: ['uploads: [{ field?, multiple?, required?, maxSize?, maxFiles?, mimeTypes? }]'],\n })\n if (!Array.isArray(route.uploads)) throw invalid('uploads must be an array')\n const fields = new Set<string | undefined>()\n for (const upload of route.uploads) {\n if (upload === null || typeof upload !== 'object') throw invalid(`invalid upload ${describeValue(upload)}`)\n const { field, maxSize, maxFiles, mimeTypes } = upload\n if (field !== undefined && (typeof field !== 'string' || field === '')) {\n throw invalid(`invalid upload field ${describeValue(field)}`)\n }\n if (fields.has(field) || (fields.size > 0 && (field === undefined || fields.has(undefined)))) {\n throw invalid(\n field === undefined\n ? 'an upload without field (every file) cannot be combined with other uploads'\n : `several uploads for the field \"${field}\"`,\n )\n }\n fields.add(field)\n if (maxSize !== undefined && !isSize(maxSize)) throw invalid(`invalid maxSize ${describeValue(maxSize)}`)\n if (maxFiles !== undefined && (!isSize(maxFiles) || maxFiles < 1)) {\n throw invalid(`invalid maxFiles ${describeValue(maxFiles)}`)\n }\n if (\n mimeTypes !== undefined &&\n (!Array.isArray(mimeTypes) ||\n mimeTypes.length === 0 ||\n !mimeTypes.every(type => typeof type === 'string' && isMediaTypePattern(type)))\n ) {\n throw invalid(`invalid mimeTypes ${describeValue(mimeTypes)}`)\n }\n }\n}\n\nfunction describeValue(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value)\n } catch {\n return String(value)\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Provider resolution\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Singletons (and registered values) are resolved once at bootstrap; request-scoped and transient\n * providers on every request.\n */\nfunction resolvable<T>(container: Container, metadata: ZnightMetadata, token: Token, what: string): Resolvable<T> {\n const scope = Object.hasOwn(metadata.providers, token) ? metadata.providers[token]?.scope : undefined\n if (!container.has(token)) {\n throw new ZnightError(ErrorCode.MissingProvider, `HttpPlugin: the ${what} (${token}) is not a provider`, {\n hints: ['Add @Injectable() to the class (controllers are providers through @Controller())'],\n })\n }\n if (scope === 'request' || scope === 'transient') return { token }\n try {\n return { instance: container.get(token) as T }\n } catch (error) {\n if ((error as { code?: unknown } | null)?.code === ErrorCode.NoActiveScope) return { token }\n throw error\n }\n}\n\ntype GlobalKey = 'guards' | 'interceptors' | 'exceptionMappers'\nconst GLOBAL_KEYS: readonly GlobalKey[] = ['guards', 'interceptors', 'exceptionMappers']\nconst GLOBAL_METHOD: Readonly<Record<GlobalKey, string>> = {\n guards: 'canActivate',\n interceptors: 'intercept',\n exceptionMappers: 'map',\n}\nconst GLOBAL_WHAT: Readonly<Record<GlobalKey, string>> = {\n guards: 'guard',\n interceptors: 'interceptor',\n exceptionMappers: 'exception mapper',\n}\n\n/** Resolves global guards / interceptors / exception mappers given as classes or instances. */\nfunction globalRefs<T>(\n container: Container,\n metadata: ZnightMetadata,\n options: HttpPluginOptions,\n key: GlobalKey,\n): Resolvable<T>[] {\n const refs: unknown = options[key] ?? []\n if (!Array.isArray(refs)) throw invalidOption(key, 'an array', refs)\n const method = GLOBAL_METHOD[key]\n const what = GLOBAL_WHAT[key]\n return refs.map(\n (ref: unknown): Resolvable<T> =>\n resolveRef<T>(container, metadata, ref, what, method, () =>\n invalidOption(key, `classes or objects with a ${method}() method`, ref),\n ).resolvable,\n )\n}\n\n/** A provider class whose instances are guards (a `canActivate()` method on its prototype). */\nfunction isGuardClass(cls: unknown): boolean {\n if (typeof cls !== 'function') return false\n const prototype: unknown = (cls as { prototype?: unknown }).prototype\n return (\n typeof prototype === 'object' &&\n prototype !== null &&\n typeof (prototype as { canActivate?: unknown }).canActivate === 'function'\n )\n}\n\n/** Guards given as classes or instances (`guards` option, plugin routes), with their class and name. */\nfunction guardEntries(\n container: Container,\n metadata: ZnightMetadata,\n refs: unknown,\n invalid: (ref: unknown) => ZnightError,\n): GuardEntry[] {\n if (!Array.isArray(refs)) throw invalidOption('guards', 'an array', refs)\n return refs.map((ref: unknown) =>\n resolveRef<CanActivate>(container, metadata, ref, 'guard', 'canActivate', () => invalid(ref)),\n )\n}\n\nfunction resolveRef<T>(\n container: Container,\n metadata: ZnightMetadata,\n ref: unknown,\n what: string,\n method: string,\n invalid: () => ZnightError,\n): { readonly resolvable: Resolvable<T>; readonly cls: unknown; readonly name: string } {\n if (typeof ref === 'function') {\n const token = container.tokenOf(ref as GuardClass)\n if (token === undefined) {\n const name = (ref as { name?: string }).name || '<anonymous>'\n throw new ZnightError(ErrorCode.MissingProvider, `HttpPlugin: the global ${what} ${name} is not a provider`, {\n hints: ['Add @Injectable() to the class, or pass an instance'],\n })\n }\n return {\n resolvable: resolvable<T>(container, metadata, token, `global ${what}`),\n cls: ref,\n name: displayName(token),\n }\n }\n if (ref !== null && typeof ref === 'object' && typeof (ref as Record<string, unknown>)[method] === 'function') {\n const cls: unknown = (ref as { constructor?: unknown }).constructor\n const className = typeof cls === 'function' && cls !== Object ? (cls as { name?: string }).name : undefined\n return { resolvable: { instance: ref as T }, cls, name: className || `${what} instance` }\n }\n throw invalid()\n}\n","/**\n * A copy of the [Standard Schema v1](https://standardschema.dev) interface, flattened (no namespace,\n * so the file stays erasable). Every compliant library (Zod, Valibot, ArkType, Effect Schema...)\n * produces values assignable to {@link StandardSchemaV1}: no adapter and no dependency are needed.\n */\n\n/** A schema implementing the Standard Schema v1 interface. */\nexport interface StandardSchemaV1<Input = unknown, Output = Input> {\n /** The Standard Schema properties. */\n readonly '~standard': StandardSchemaV1Props<Input, Output>\n}\n\n/** The Standard Schema properties. */\nexport interface StandardSchemaV1Props<Input = unknown, Output = Input> {\n /** The version number of the standard. */\n readonly version: 1\n /** The vendor name of the schema library. */\n readonly vendor: string\n /** Validates an unknown input value (synchronously or not). */\n readonly validate: (\n value: unknown,\n options?: StandardSchemaV1Options | undefined,\n ) => StandardSchemaV1Result<Output> | Promise<StandardSchemaV1Result<Output>>\n /** Inferred types associated with the schema. */\n readonly types?: StandardSchemaV1Types<Input, Output> | undefined\n}\n\n/** Options of {@link StandardSchemaV1Props.validate}. */\nexport interface StandardSchemaV1Options {\n /** Vendor-specific parameters. */\n readonly libraryOptions?: Record<string, unknown> | undefined\n}\n\n/** Result of {@link StandardSchemaV1Props.validate}. */\nexport type StandardSchemaV1Result<Output> = StandardSchemaV1SuccessResult<Output> | StandardSchemaV1FailureResult\n\n/** Successful validation: the (possibly transformed) output value. */\nexport interface StandardSchemaV1SuccessResult<Output> {\n readonly value: Output\n readonly issues?: undefined\n}\n\n/** Failed validation. */\nexport interface StandardSchemaV1FailureResult {\n readonly issues: readonly StandardSchemaV1Issue[]\n}\n\n/** One validation issue. */\nexport interface StandardSchemaV1Issue {\n readonly message: string\n readonly path?: readonly (PropertyKey | StandardSchemaV1PathSegment)[] | undefined\n}\n\n/** A path segment of an issue. */\nexport interface StandardSchemaV1PathSegment {\n readonly key: PropertyKey\n}\n\n/** Input and output types of a schema. */\nexport interface StandardSchemaV1Types<Input = unknown, Output = Input> {\n readonly input: Input\n readonly output: Output\n}\n\n/** The input type of a schema. */\nexport type InferSchemaInput<S extends StandardSchemaV1> = NonNullable<S['~standard']['types']>['input']\n\n/** The output type of a schema (what handlers receive). */\nexport type InferSchemaOutput<S extends StandardSchemaV1> = NonNullable<S['~standard']['types']>['output']\n\n/** Whether `value` looks like a Standard Schema v1 (has a `~standard` object with a `validate` function). */\nexport function isStandardSchema(value: unknown): value is StandardSchemaV1 {\n if (value === null || (typeof value !== 'object' && typeof value !== 'function')) return false\n const props = (value as { '~standard'?: unknown })['~standard']\n return (\n props !== null &&\n typeof props === 'object' &&\n (props as { version?: unknown }).version === 1 &&\n typeof (props as { validate?: unknown }).validate === 'function'\n )\n}\n","import type {\n InferSchemaOutput,\n StandardSchemaV1,\n StandardSchemaV1Issue,\n StandardSchemaV1Props,\n StandardSchemaV1Result,\n} from './standard-schema.ts'\n\nimport { ValidationException } from './exceptions.ts'\nimport { isThenable } from './utils.ts'\n\n/**\n * Whether `value` is a promise-like object (has a callable `then`). Called by the generated\n * `invoke` functions on the result of {@link validate} (README, \"Compiler contract\").\n */\nexport { isThenable } from './utils.ts'\n\n/**\n * Validates `value` with a [Standard Schema](https://standardschema.dev) (Zod, Valibot, ArkType...)\n * and returns the schema **output** (defaults applied, transforms run, unknown keys stripped when\n * the schema strips them).\n *\n * Returns synchronously when the schema validates synchronously, a promise otherwise (async\n * refinements): generated code calls the handler directly with the value, and `await`s the value\n * when it is a thenable (`isThenable`).\n *\n * @param location what is validated, used in the error message: `body`, `query`, `query \"page\"`,\n * `param \"id\"`, `headers`, `cookie \"sid\"`, `cookies`...\n * @throws ValidationException (400, `details: [{ path, message }]`) when the value is invalid. For\n * cookies (`cookie \"name\"`, `cookies`) the issue messages are replaced with `Invalid value`: some\n * libraries quote the received value in them (Valibot, ArkType), and cookies often carry tokens.\n * @throws TypeError when `schema` is not a Standard Schema v1 (a programming error → 500).\n */\nexport function validate<S extends StandardSchemaV1>(\n schema: S,\n value: unknown,\n location: string,\n): InferSchemaOutput<S> | Promise<InferSchemaOutput<S>> {\n // `~standard` is read once (the same checks as `isStandardSchema`)\n const props =\n schema !== null && (typeof schema === 'object' || typeof schema === 'function')\n ? (schema as { readonly '~standard'?: unknown })['~standard']\n : undefined\n if (\n props === null ||\n typeof props !== 'object' ||\n (props as { readonly version?: unknown }).version !== 1 ||\n typeof (props as { readonly validate?: unknown }).validate !== 'function'\n ) {\n throw new TypeError(`The schema of ${location} is not a Standard Schema v1 (missing \"~standard.validate\")`)\n }\n const result = (props as StandardSchemaV1Props<unknown, InferSchemaOutput<S>>).validate(value)\n if (isThenable(result)) return Promise.resolve(result).then(settled => unwrap(settled, location))\n return unwrap(result, location)\n}\n\nfunction unwrap<T>(result: StandardSchemaV1Result<T>, location: string): T {\n if (result.issues !== undefined) {\n throw new ValidationException(location, isCookieLocation(location) ? result.issues.map(redact) : result.issues)\n }\n return result.value\n}\n\n/** The message of a redacted issue (cookie values are never echoed). */\nconst REDACTED = 'Invalid value'\n\nfunction isCookieLocation(location: string): boolean {\n return location === 'cookies' || location.startsWith('cookie ')\n}\n\n/**\n * The issue with the keys of its path only: its message may quote the value (`Received \"eyJ...\"`),\n * and so may the path segments of some libraries (Valibot keeps `input` and `value` there).\n */\nfunction redact(issue: StandardSchemaV1Issue): StandardSchemaV1Issue {\n if (issue.path === undefined) return { message: REDACTED }\n const path = issue.path.map(segment =>\n typeof segment === 'object' && segment !== null ? { key: segment.key } : segment,\n )\n return { message: REDACTED, path }\n}\n"],"mappings":"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"}