routup 6.0.0-beta.0 → 6.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-BfsqxIfL.mjs","names":[],"sources":["../src/cache/lru.ts","../src/constants.ts","../src/event/module.ts","../src/response/helpers/cache.ts","../src/error/module.ts","../src/response/helpers/event-stream/utils.ts","../src/response/helpers/event-stream/module.ts","../src/utils/accepts-json.ts","../src/utils/header.ts","../src/utils/etag/module.ts","../src/utils/object.ts","../src/utils/etag/utils.ts","../src/utils/trust-proxy/module.ts","../src/utils/mime.ts","../src/utils/method.ts","../src/utils/path.ts","../src/utils/promise.ts","../src/utils/url.ts","../src/response/helpers/header.ts","../src/response/helpers/utils.ts","../src/response/helpers/header-disposition.ts","../src/response/helpers/header-content-type.ts","../src/error/is.ts","../src/error/create.ts","../src/response/to-response.ts","../src/response/helpers/send-accepted.ts","../src/response/helpers/send-created.ts","../src/response/helpers/send-file.ts","../src/request/helpers/header.ts","../src/request/helpers/negotiator.ts","../src/request/helpers/header-accept.ts","../src/response/helpers/send-format.ts","../src/response/helpers/send-redirect.ts","../src/response/helpers/send-stream.ts","../src/dispatcher/module.ts","../src/handler/constants.ts","../src/handler/module.ts","../src/handler/core/define.ts","../src/handler/error/define.ts","../src/handler/adapters/node/define.ts","../src/handler/adapters/web/is.ts","../src/handler/adapters/web/define.ts","../src/handler/is.ts","../src/handler/utils.ts","../src/request/helpers/cache.ts","../src/request/helpers/header-accept-charset.ts","../src/request/helpers/header-accept-encoding.ts","../src/request/helpers/header-accept-language.ts","../src/request/helpers/header-content-type.ts","../src/request/helpers/hostname.ts","../src/request/helpers/ip.ts","../src/request/helpers/protocol.ts","../src/path/matcher.ts","../src/path/utils.ts","../src/plugin/error/constants.ts","../src/plugin/error/is.ts","../src/plugin/error/module.ts","../src/plugin/error/sub/already-installed.ts","../src/plugin/error/sub/install.ts","../src/plugin/error/sub/not-installed.ts","../src/plugin/is.ts","../src/router/utils.ts","../src/router/linear/module.ts","../src/router/trie/parser.ts","../src/router/trie/node.ts","../src/router/trie/module.ts","../src/router/smart/module.ts","../src/app/options.ts","../src/app/constants.ts","../src/app/check.ts","../src/app/module.ts"],"sourcesContent":["import QuickLRU from 'quick-lru';\nimport type { ICache } from './types.ts';\n\nexport type LruCacheOptions = {\n /**\n * Maximum number of entries before the least-recently-used entry\n * is evicted on `set`. Default: `1024`.\n */\n maxSize?: number;\n};\n\nconst DEFAULT_MAX_SIZE = 1024;\n\n/**\n * Default `ICache` implementation — a bounded LRU backed by\n * [`quick-lru`](https://github.com/sindresorhus/quick-lru). Picked for\n * its small footprint (~1kB), ESM-only build (matches routup), and\n * stable API.\n *\n * For TTL, size-based eviction, or dispose hooks, write your own\n * `ICache` (e.g. wrapping `lru-cache`) and pass it via the router's\n * `BaseRouterOptions.cache` slot.\n */\nexport class LruCache<V> implements ICache<V> {\n protected inner: QuickLRU<string, V>;\n\n constructor(options: LruCacheOptions = {}) {\n this.inner = new QuickLRU<string, V>({ maxSize: options.maxSize ?? DEFAULT_MAX_SIZE });\n }\n\n get(key: string): V | undefined {\n return this.inner.get(key);\n }\n\n set(key: string, value: V): void {\n this.inner.set(key, value);\n }\n\n delete(key: string): void {\n this.inner.delete(key);\n }\n\n clear(): void {\n this.inner.clear();\n }\n}\n","export const MethodName = {\n GET: 'GET',\n POST: 'POST',\n PUT: 'PUT',\n PATCH: 'PATCH',\n DELETE: 'DELETE',\n OPTIONS: 'OPTIONS',\n HEAD: 'HEAD',\n} as const;\n\nexport type MethodName = typeof MethodName[keyof typeof MethodName];\n\n/**\n * `MethodName` plus the open-enum escape hatch for non-standard\n * methods (`PROPFIND`, `MKCOL`, custom verbs). The `(string & {})`\n * intersection is structurally identical to `string` but TypeScript\n * doesn't collapse the union — so callers still get autocomplete\n * for the canonical methods while remaining free to pass anything.\n */\nexport type MethodNameLike = MethodName | (string & {});\n\nexport const HeaderName = {\n ACCEPT: 'accept',\n ACCEPT_CHARSET: 'accept-charset',\n ACCEPT_ENCODING: 'accept-encoding',\n ACCEPT_LANGUAGE: 'accept-language',\n ACCEPT_RANGES: 'accept-ranges',\n ALLOW: 'allow',\n CACHE_CONTROL: 'cache-control',\n CONTENT_DISPOSITION: 'content-disposition',\n CONTENT_ENCODING: 'content-encoding',\n CONTENT_LENGTH: 'content-length',\n CONTENT_RANGE: 'content-range',\n CONTENT_TYPE: 'content-type',\n CONNECTION: 'connection',\n COOKIE: 'cookie',\n ETag: 'etag',\n HOST: 'host',\n IF_MODIFIED_SINCE: 'if-modified-since',\n IF_NONE_MATCH: 'if-none-match',\n LAST_MODIFIED: 'last-modified',\n LOCATION: 'location',\n RANGE: 'range',\n RATE_LIMIT_LIMIT: 'ratelimit-limit',\n RATE_LIMIT_REMAINING: 'ratelimit-remaining',\n RATE_LIMIT_RESET: 'ratelimit-reset',\n RETRY_AFTER: 'retry-after',\n SET_COOKIE: 'set-cookie',\n TRANSFER_ENCODING: 'transfer-encoding',\n X_ACCEL_BUFFERING: 'x-accel-buffering',\n X_FORWARDED_HOST: 'x-forwarded-host',\n X_FORWARDED_FOR: 'x-forwarded-for',\n X_FORWARDED_PROTO: 'x-forwarded-proto',\n} as const;\n\nexport type HeaderName = typeof HeaderName[keyof typeof HeaderName];\n","import type { AppOptions } from '../app/types.ts';\nimport type { MethodNameLike } from '../constants.ts';\nimport type {\n AppRequest,\n AppResponse,\n IAppEvent,\n} from './types.ts';\n\nexport type AppEventCreateContext = {\n request: AppRequest;\n params: Record<string, string | undefined>;\n path: string;\n method: MethodNameLike;\n mountPath: string;\n headers: Headers;\n searchParams: URLSearchParams;\n response: AppResponse;\n store: Record<string | symbol, unknown>;\n signal: AbortSignal;\n appOptions: Readonly<AppOptions>;\n next: (event: IAppEvent, error?: Error) => Promise<Response | undefined>;\n};\n\nexport class AppEvent implements IAppEvent {\n readonly request: AppRequest;\n\n readonly params: Record<string, string | undefined>;\n\n readonly path: string;\n\n readonly method: MethodNameLike;\n\n readonly mountPath: string;\n\n readonly headers: Headers;\n\n readonly searchParams: URLSearchParams;\n\n readonly response: AppResponse;\n\n readonly store: Record<string | symbol, unknown>;\n\n readonly signal: AbortSignal;\n\n readonly appOptions: Readonly<AppOptions>;\n\n protected _context: AppEventCreateContext;\n\n protected _nextCalled = false;\n\n protected _nextResult: Promise<Response | undefined> | undefined;\n\n protected _nextCalledDeferred: {\n promise: Promise<void>,\n resolve: () => void,\n } | undefined;\n\n constructor(context: AppEventCreateContext) {\n this._context = context;\n this.request = context.request;\n this.params = context.params;\n this.path = context.path;\n this.method = context.method;\n this.mountPath = context.mountPath;\n this.headers = context.headers;\n this.searchParams = context.searchParams;\n this.response = context.response;\n this.store = context.store;\n this.signal = context.signal;\n this.appOptions = context.appOptions;\n }\n\n get nextCalled(): boolean {\n return this._nextCalled;\n }\n\n get nextResult(): Promise<Response | undefined> | undefined {\n return this._nextResult;\n }\n\n whenNextCalled(): Promise<void> {\n if (!this._nextCalledDeferred) {\n let resolve!: () => void;\n const promise = new Promise<void>((r) => { resolve = r; });\n this._nextCalledDeferred = { promise, resolve };\n\n if (this._nextCalled) {\n resolve();\n }\n }\n\n return this._nextCalledDeferred.promise;\n }\n\n async next(error?: Error): Promise<Response | undefined> {\n if (this._nextCalled) {\n return this._nextResult;\n }\n\n this._nextCalled = true;\n this._nextResult = this._context.next(this, error);\n\n if (this._nextCalledDeferred) {\n this._nextCalledDeferred.resolve();\n }\n\n return this._nextResult;\n }\n}\n","import type { IAppEvent } from '../../event/index.ts';\n\nexport type ResponseCacheHeadersOptions = {\n maxAge?: number,\n modifiedTime?: string | Date,\n cacheControls?: string[]\n};\n\nexport function setResponseCacheHeaders(event: IAppEvent, options?: ResponseCacheHeadersOptions) {\n options = options || {};\n\n const cacheControls = ['public'].concat(options.cacheControls || []);\n\n if (options.maxAge !== undefined) {\n cacheControls.push(`max-age=${+options.maxAge}`, `s-maxage=${+options.maxAge}`);\n }\n\n if (options.modifiedTime) {\n const modifiedTime = typeof options.modifiedTime === 'string' ?\n new Date(options.modifiedTime) :\n options.modifiedTime;\n\n event.response.headers.set('last-modified', modifiedTime.toUTCString());\n }\n\n event.response.headers.set('cache-control', cacheControls.join(', '));\n}\n","import { markInstanceof } from '@ebec/core';\nimport { HTTPError } from '@ebec/http';\nimport type { HTTPErrorInput } from '@ebec/http';\n\nexport type { HTTPErrorInput };\n\nexport const ErrorSymbol = Symbol.for('AppError');\n\nexport class AppError extends HTTPError {\n constructor(input: HTTPErrorInput = {}) {\n super(input);\n this.name = 'AppError';\n markInstanceof(this, ErrorSymbol);\n }\n}\n","import type { EventStreamMessage } from './types.ts';\n\nfunction stripNewlines(value: string) : string {\n return value.replace(/[\\r\\n]/g, '');\n}\n\nexport function serializeEventStreamMessage(message: EventStreamMessage): string {\n let result = '';\n\n if (message.id) {\n result += `id: ${stripNewlines(message.id)}\\n`;\n }\n\n if (message.event) {\n result += `event: ${stripNewlines(message.event)}\\n`;\n }\n\n if (\n typeof message.retry === 'number' &&\n Number.isInteger(message.retry)\n ) {\n result += `retry: ${message.retry}\\n`;\n }\n\n const lines = message.data.replace(/\\r/g, '').split('\\n');\n for (const line of lines) {\n result += `data: ${line}\\n`;\n }\n result += '\\n';\n\n return result;\n}\n","import { HeaderName } from '../../../constants.ts';\nimport type { IAppEvent } from '../../../event/index.ts';\nimport { AppError } from '../../../error/module.ts';\nimport type { EventStreamMessage } from './types.ts';\nimport { serializeEventStreamMessage } from './utils.ts';\n\nexport type EventStreamOptions = {\n maxMessageSize?: number,\n};\n\nexport type EventStreamHandle = {\n write(message: string | EventStreamMessage): boolean;\n end(): void;\n response: Response;\n};\n\nexport function createEventStream(\n event: IAppEvent,\n options?: EventStreamOptions,\n): EventStreamHandle {\n if (options?.maxMessageSize !== undefined) {\n if (!Number.isInteger(options.maxMessageSize) || options.maxMessageSize < 0) {\n throw new AppError('maxMessageSize must be a non-negative integer.');\n }\n }\n\n let controller: ReadableStreamDefaultController<Uint8Array>;\n let closed = false;\n const encoder = new TextEncoder();\n\n const stream = new ReadableStream<Uint8Array>({\n start(ctrl) {\n controller = ctrl;\n },\n cancel() {\n closed = true;\n },\n });\n\n const headers = new Headers(event.response.headers);\n headers.set(HeaderName.CONTENT_TYPE, 'text/event-stream');\n headers.set(HeaderName.CACHE_CONTROL, 'private, no-cache, no-store, no-transform, must-revalidate, max-age=0');\n headers.set(HeaderName.X_ACCEL_BUFFERING, 'no');\n headers.set(HeaderName.CONNECTION, 'keep-alive');\n\n const response = new Response(stream, {\n status: event.response.status,\n headers,\n });\n\n const handle: EventStreamHandle = {\n write(message: string | EventStreamMessage): boolean {\n if (closed) return false;\n\n if (typeof message === 'string') {\n return handle.write({ data: message });\n }\n\n const serialized = serializeEventStreamMessage(message);\n\n if (options?.maxMessageSize !== undefined) {\n const serializedSize = encoder.encode(serialized).byteLength;\n if (serializedSize > options.maxMessageSize) {\n return false;\n }\n }\n\n controller.enqueue(encoder.encode(serialized));\n return true;\n },\n\n end(): void {\n if (closed) return;\n\n closed = true;\n controller.close();\n },\n\n response,\n };\n\n return handle;\n}\n","/**\n * Check if the request accepts JSON responses.\n *\n * Parses the `Accept` header per RFC 7231 (media ranges + quality\n * params) rather than substring-matching, so:\n * - `application/json-seq` does NOT count as accepting `application/json`\n * - `application/json;q=0` is treated as an explicit rejection\n *\n * Returns true if no Accept header is present (API-first default).\n */\nexport function acceptsJson(request: Request): boolean {\n const accept = request.headers.get('accept');\n if (!accept) {\n return true;\n }\n\n return accept\n .toLowerCase()\n .split(',')\n .some((entry) => {\n const parts = entry.split(';').map((part) => part.trim());\n const mediaRange = parts[0]!;\n // Split each parameter on `=` and trim both halves so\n // `q=0`, `q = 0`, and `q =0` are all recognized as q=0.\n const qParam = parts.slice(1)\n .map((param) => param.split('=').map((s) => s.trim()))\n .find(([key]) => key === 'q');\n const q = qParam ? Number.parseFloat(qParam[1] ?? '') : 1;\n if (!Number.isFinite(q) || q <= 0) {\n return false;\n }\n\n return mediaRange === '*/*' ||\n mediaRange === 'application/*' ||\n mediaRange === 'application/json' ||\n mediaRange.endsWith('+json');\n });\n}\n","export function sanitizeHeaderValue(value: string) : string {\n return value.replace(/[\\r\\n]/g, '');\n}","import { subtle } from 'uncrypto';\nimport type { EtagOptions } from './types.ts';\n\nasync function sha1(str: string) : Promise<string> {\n const enc = new TextEncoder();\n const hash = await subtle.digest('SHA-1', enc.encode(str));\n\n return btoa(String.fromCharCode(...new Uint8Array(hash)));\n}\n\n/**\n * Generate an ETag.\n */\nexport async function generateETag(input: string) : Promise<string> {\n if (input.length === 0) {\n // fast-path empty\n return '\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\"';\n }\n\n const hash = await sha1(input);\n\n return `\"${input.length.toString(16)}-${hash.substring(0, 27)}\"`;\n}\n\n/**\n * Create a simple ETag.\n */\nexport async function createEtag(\n input: string,\n options: EtagOptions = {},\n) : Promise<string> {\n // generate entity tag\n const tag = await generateETag(input);\n\n return options.weak ?\n `W/${tag}` :\n tag;\n}\n","export function isObject(item: unknown) : item is Record<string, any> {\n return (\n !!item &&\n typeof item === 'object' &&\n !Array.isArray(item)\n );\n}\n\nexport function setProperty(\n record: Record<PropertyKey, any>,\n property: PropertyKey,\n value: any,\n): void {\n (record as any)[property] = value;\n}\n\nexport function getProperty<T = any>(\n req: Record<PropertyKey, any>,\n property: PropertyKey,\n): T {\n return (req as any)[property];\n}\n","import { merge } from 'smob';\nimport { isObject } from '../object.ts';\nimport { createEtag } from './module.ts';\nimport type { EtagFn, EtagOptions } from './types.ts';\n\nconst textEncoder = /* @__PURE__ */ new TextEncoder();\n\nexport function buildEtagFn(input?: boolean | EtagOptions | EtagFn) : EtagFn {\n if (typeof input === 'function') {\n return input;\n }\n\n input = input ?? true;\n\n if (input === false) {\n return () => Promise.resolve(undefined);\n }\n\n let options : EtagOptions = { weak: true };\n\n if (isObject(input)) {\n options = merge(input, options);\n }\n\n return async (body: string, size?: number) => {\n if (typeof options.threshold !== 'undefined') {\n const measured = size ?? textEncoder.encode(body).byteLength;\n\n if (measured <= options.threshold) {\n return undefined;\n }\n }\n\n return createEtag(body, options);\n };\n}\n\n/**\n * Default `EtagFn` used by `toResponse()` when `appOptions.etag` is\n * undefined. Module-scoped so we don't allocate per-request and so\n * all consumers share the same closure.\n *\n * `appOptions.etag === null` (explicitly disabled by the user)\n * remains distinct: consumers must check `=== undefined`, not\n * `== null`, before falling back to this default.\n */\nexport const DEFAULT_ETAG_FN: EtagFn = buildEtagFn();\n","import { compile } from 'proxy-addr';\nimport type { TrustProxyFn } from './type.ts';\n\nexport function buildTrustProxyFn(\n input?: boolean | number | string | string[] | TrustProxyFn,\n) : TrustProxyFn {\n if (typeof input === 'function') {\n return input;\n }\n\n if (input === true) {\n return () => true;\n }\n\n if (typeof input === 'number') {\n return (_address, hop) => hop < (input as number);\n }\n\n if (typeof input === 'string') {\n input = input.split(',')\n .map((value) => value.trim());\n }\n\n return compile(input || []);\n}\n\n/**\n * Default `TrustProxyFn` used by request helpers when neither the\n * call's `options.trustProxy` nor `event.appOptions.trustProxy` is\n * set. Trusts no addresses — the conservative default.\n *\n * Module-scoped so all helpers share the same reference and we don't\n * allocate per-request.\n */\nexport const DEFAULT_TRUST_PROXY: TrustProxyFn = buildTrustProxyFn();\n","import { get, getType } from 'mime-explorer';\n\nexport function getMimeType(type: string) : string | undefined {\n if (type.includes('/')) {\n return type;\n }\n\n return getType(type);\n}\n\nexport function getCharsetForMimeType(type: string) : string | undefined {\n if ((/^text\\/|^application\\/(javascript|json)/).test(type)) {\n return 'utf-8';\n }\n\n const meta = get(type);\n if (\n meta &&\n meta.charset\n ) {\n return meta.charset.toLowerCase();\n }\n\n return undefined;\n}\n","import type { MethodName } from '../constants.ts';\n\nexport function toMethodName(input: string | undefined) : MethodName | undefined;\nexport function toMethodName(input: string | undefined, alt: MethodName) : MethodName;\nexport function toMethodName(\n input?: string,\n alt?: MethodName,\n) : MethodName | undefined {\n if (input) {\n return input.toUpperCase() as MethodName;\n }\n\n return alt;\n}\n","/**\n * Based on https://github.com/unjs/pathe v1.1.1 (055f50a6f1131f4e5c56cf259dd8816168fba329)\n */\n\nfunction normalizeWindowsPath(input = '') {\n if (!input || !input.includes('\\\\')) {\n return input;\n }\n\n return input.replace(/\\\\/g, '/');\n}\n\nconst EXTNAME_RE = /.(\\.[^./]+)$/;\nexport function extname(input: string) {\n const match = EXTNAME_RE.exec(normalizeWindowsPath(input));\n return (match && match[1]) || '';\n}\n\nexport function basename(input: string, extension? :string) {\n const lastSegment = normalizeWindowsPath(input)\n .split('/')\n .pop();\n\n if (!lastSegment) {\n return input;\n }\n\n return extension && lastSegment.endsWith(extension) ?\n lastSegment.slice(0, -extension.length) :\n lastSegment;\n}\n","import { isObject } from './object.ts';\n\nexport function isPromise(p: unknown) : p is Promise<unknown> {\n return isObject(p) &&\n (\n p instanceof Promise ||\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n typeof p.then === 'function'\n );\n}\n","const TRAILING_SLASH_RE = /\\/$|\\/\\?/;\n\nexport function hasTrailingSlash(input = '', queryParams = false): boolean {\n if (!queryParams) {\n return input.endsWith('/');\n }\n\n return TRAILING_SLASH_RE.test(input);\n}\n\nexport function withoutTrailingSlash(input = '', queryParams = false): string {\n if (!queryParams) {\n return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || '/';\n }\n\n if (!hasTrailingSlash(input, true)) {\n return input || '/';\n }\n\n const [s0, ...s] = input.split('?');\n\n return (s0!.slice(0, -1) || '/') + (s.length ? `?${s.join('?')}` : '');\n}\n\nexport function withTrailingSlash(input = '', queryParams = false): string {\n if (!queryParams) {\n return input.endsWith('/') ? input : (`${input}/`);\n }\n\n if (hasTrailingSlash(input, true)) {\n return input || '/';\n }\n\n const [s0, ...s] = input.split('?');\n return `${s0}/${s.length ? `?${s.join('?')}` : ''}`;\n}\n\nexport function hasLeadingSlash(input = ''): boolean {\n return input.startsWith('/');\n}\n\nexport function withoutLeadingSlash(input = ''): string {\n return (hasLeadingSlash(input) ? input.substring(1) : input) || '/';\n}\n\nexport function withLeadingSlash(input = ''): string {\n return hasLeadingSlash(input) ? input : `/${input}`;\n}\n\nexport function cleanDoubleSlashes(input = ''): string {\n if (input.includes('://')) {\n return input.split('://')\n .map((str) => cleanDoubleSlashes(str))\n .join('://');\n }\n\n return input.replace(/\\/+/g, '/');\n}\n\n/**\n * Concatenate path parts into a single mount path.\n *\n * - Drops `undefined` and empty parts.\n * - A lone `'/'` part still contributes (so `joinPaths('/')` returns\n * `'/'`, distinguishing \"match the root exactly\" from \"no path\").\n * - Returns `undefined` when every part is missing — callers\n * interpret this as \"no path\" (always-match middleware).\n * - Joins remaining parts with `/`, normalizes the leading slash,\n * collapses any inner `//`, and trims a trailing slash on results\n * longer than `/`.\n *\n * Used at registration time to fold a handler / router's intrinsic\n * path into the mount path so the active `IRouter` is the\n * only place that builds path matchers.\n */\nexport function joinPaths(...parts: Array<string | undefined>): string | undefined {\n const kept: string[] = [];\n for (const part of parts) {\n if (typeof part !== 'string' || part === '') {\n continue;\n }\n kept.push(part);\n }\n if (kept.length === 0) {\n return undefined;\n }\n const normalized = cleanDoubleSlashes(withLeadingSlash(kept.join('/')));\n if (normalized.length > 1 && normalized.endsWith('/')) {\n return normalized.slice(0, -1);\n }\n return normalized;\n}\n","import { sanitizeHeaderValue } from '../../utils/index.ts';\nimport type { IAppEvent } from '../../event/index.ts';\n\nexport function appendResponseHeader(\n event: IAppEvent,\n name: string,\n value: string | string[],\n) {\n const { headers } = event.response;\n\n if (Array.isArray(value)) {\n for (const v of value) {\n headers.append(name, sanitizeHeaderValue(v));\n }\n } else {\n headers.append(name, sanitizeHeaderValue(value));\n }\n}\n\nexport function appendResponseHeaderDirective(\n event: IAppEvent,\n name: string,\n value: string | string[],\n) {\n const { headers } = event.response;\n const existing = headers.get(name);\n\n if (!existing) {\n if (Array.isArray(value)) {\n headers.set(name, sanitizeHeaderValue(value.join('; ')));\n } else {\n headers.set(name, sanitizeHeaderValue(value));\n }\n return;\n }\n\n const directives = existing.split('; ');\n\n if (Array.isArray(value)) {\n directives.push(...value);\n } else {\n directives.push(value);\n }\n\n const unique = [...new Set(directives)];\n\n headers.set(name, sanitizeHeaderValue(unique.join('; ')));\n}\n","import { HeaderName } from '../../constants.ts';\nimport { extname, getCharsetForMimeType, getMimeType } from '../../utils/index.ts';\nimport type { IAppEvent } from '../../event/index.ts';\n\nexport function setResponseContentTypeByFileName(event: IAppEvent, fileName: string) {\n const ext = extname(fileName);\n if (ext) {\n let type = getMimeType(ext.substring(1));\n if (type) {\n const charset = getCharsetForMimeType(type);\n if (charset) {\n type += `; charset=${charset}`;\n }\n event.response.headers.set(HeaderName.CONTENT_TYPE, type);\n }\n }\n}\n","import { HeaderName } from '../../constants.ts';\nimport type { IAppEvent } from '../../event/index.ts';\nimport { setResponseContentTypeByFileName } from './utils.ts';\n\n// eslint-disable-next-line no-control-regex\nconst ENCODE_URL_ATTR_CHAR_REGEXP = /[\\x00-\\x20\"'()*,/:;<=>?@[\\\\\\]{}\\x7f]/g;\nconst NON_ASCII_REGEXP = /[^\\x20-\\x7e]/g;\nconst QUOTE_REGEXP = /[\\\\\"]/g;\nconst HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/;\nconst ASCII_TEXT_REGEXP = /^[\\x20-\\x7e]+$/;\nconst TOKEN_REGEXP = /^[!#$%&'*+.0-9A-Z^_`a-z|~-]+$/;\n\nfunction pencode(char: string): string {\n return `%${char.charCodeAt(0).toString(16).toUpperCase()}`;\n}\n\nfunction quoteString(value: string): string {\n return `\"${value.replace(QUOTE_REGEXP, '\\\\$&')}\"`;\n}\n\nfunction getAscii(value: string): string {\n return value.replace(NON_ASCII_REGEXP, '?');\n}\n\nfunction encodeExtended(value: string): string {\n return encodeURIComponent(value).replace(ENCODE_URL_ATTR_CHAR_REGEXP, pencode);\n}\n\nfunction formatFilename(value: string): string {\n if (TOKEN_REGEXP.test(value)) {\n return `filename=${value}`;\n }\n return `filename=${quoteString(value)}`;\n}\n\nfunction setDisposition(\n event: IAppEvent,\n type: 'attachment' | 'inline',\n filename?: string,\n) {\n let disposition: string = type;\n\n if (typeof filename === 'string') {\n setResponseContentTypeByFileName(event, filename);\n\n const isAsciiSafe = ASCII_TEXT_REGEXP.test(filename) &&\n !HEX_ESCAPE_REGEXP.test(filename);\n\n if (isAsciiSafe) {\n disposition += `; ${formatFilename(filename)}`;\n } else {\n disposition += `; ${formatFilename(getAscii(filename))}`;\n disposition += `; filename*=UTF-8''${encodeExtended(filename)}`;\n }\n }\n\n event.response.headers.set(\n HeaderName.CONTENT_DISPOSITION,\n disposition,\n );\n}\n\nexport function setResponseHeaderAttachment(event: IAppEvent, filename?: string) {\n setDisposition(event, 'attachment', filename);\n}\n\nexport function setResponseHeaderInline(event: IAppEvent, filename?: string) {\n setDisposition(event, 'inline', filename);\n}\n","import { HeaderName } from '../../constants.ts';\nimport { getMimeType } from '../../utils/index.ts';\nimport type { IAppEvent } from '../../event/index.ts';\n\nexport function setResponseHeaderContentType(event: IAppEvent, input: string, ifNotExists?: boolean) {\n if (ifNotExists) {\n const header = event.response.headers.get(HeaderName.CONTENT_TYPE);\n if (header) {\n return;\n }\n }\n\n const contentType = getMimeType(input);\n if (contentType) {\n event.response.headers.set(HeaderName.CONTENT_TYPE, contentType);\n }\n}\n","import { hasInstanceof } from '@ebec/core';\nimport type { AppError } from './module.ts';\nimport { ErrorSymbol } from './module.ts';\n\nexport function isError(input: unknown) : input is AppError {\n return hasInstanceof(input, ErrorSymbol);\n}\n","import { isHTTPError } from '@ebec/http';\nimport type { HTTPErrorInput } from '@ebec/http';\nimport { isObject } from '../utils/index.ts';\nimport { isError } from './is.ts';\nimport { AppError } from './module.ts';\n\nfunction isNativeError(input: unknown): input is Error {\n return isObject(input) &&\n typeof (input as Record<string, unknown>).message === 'string' &&\n typeof (input as Record<string, unknown>).name === 'string';\n}\n\n/**\n * Create an internal error object by\n * - an existing AppError (returned as-is)\n * - an HTTPError (wrapped into a AppError preserving status)\n * - an Error (wrapped preserving message and cause)\n * - an options object (status, message, etc.)\n * - a message string\n *\n * @param input\n */\nexport function createError(input: HTTPErrorInput | unknown) : AppError {\n if (isError(input)) {\n return input;\n }\n\n if (typeof input === 'string') {\n return new AppError(input);\n }\n\n if (isHTTPError(input)) {\n return new AppError({\n message: input.message,\n code: input.code,\n status: input.status,\n redirectURL: input.redirectURL,\n cause: input,\n });\n }\n\n if (isNativeError(input)) {\n return new AppError({\n message: input.message,\n cause: input,\n });\n }\n\n if (!isObject(input)) {\n return new AppError();\n }\n\n const options = { ...input as Record<string, unknown> };\n if (options.cause === undefined) {\n options.cause = input;\n }\n\n return new AppError(options as HTTPErrorInput);\n}\n\n","import { createError } from '../error/create.ts';\nimport type { IAppEvent } from '../event/index.ts';\nimport { DEFAULT_ETAG_FN } from '../utils/etag/utils.ts';\nimport type { EtagFn } from '../utils/etag/types.ts';\n\nfunction stripWeakPrefix(etag: string): string {\n return etag.startsWith('W/') ? etag.slice(2) : etag;\n}\n\n/**\n * Resolve the effective etag fn for this request. `null` means the\n * user explicitly disabled ETag; `undefined` means the option was\n * never set, and we apply the framework default. Anything else is the\n * user's own fn.\n */\nfunction effectiveEtagFn(event: IAppEvent): EtagFn | null {\n const opt = event.appOptions.etag;\n if (opt === null) return null;\n if (typeof opt === 'undefined') return DEFAULT_ETAG_FN;\n return opt;\n}\n\n/**\n * Compute an ETag and conditionally return a 304, or set the header and\n * return undefined to let the caller emit the full response. Always\n * async because the ETag generator may be async (and typically is, via\n * `uncrypto`).\n */\nasync function applyEtag(\n body: string,\n event: IAppEvent,\n headers: Headers,\n): Promise<Response | undefined> {\n // The `null` short-circuit is handled by the caller so this\n // function isn't even invoked on the hot path.\n const etagFn = effectiveEtagFn(event);\n if (!etagFn) {\n return undefined;\n }\n\n const etag = await etagFn(body);\n if (!etag) {\n return undefined;\n }\n\n headers.set('etag', etag);\n\n const ifNoneMatch = event.headers.get('if-none-match');\n if (ifNoneMatch && (ifNoneMatch === '*' || ifNoneMatch.split(',').some((t) => stripWeakPrefix(t.trim()) === stripWeakPrefix(etag)))) {\n return new Response(null, {\n status: 304,\n headers,\n });\n }\n\n return undefined;\n}\n\n/**\n * Convert a handler's return value into a Web `Response`.\n *\n * Returns synchronously for the common cases (string, JSON object,\n * binary, stream, blob) when ETag generation is disabled. Returns a\n * `Promise` when an ETag must be computed (the generator is async).\n *\n * Callers that want the async return uniformly can `await` the result\n * — `await` on a non-Promise still works but pays a microtask hop.\n * The App fast path branches on `instanceof Promise` to keep the\n * sync return truly sync.\n */\nexport function toResponse(\n value: unknown,\n event: IAppEvent,\n): Response | undefined | Promise<Response | undefined> {\n // Cheap nullish checks first.\n if (value === undefined) {\n return undefined;\n }\n\n if (value === null) {\n return new Response(null, {\n status: event.response.status,\n headers: event.response.headers,\n });\n }\n\n // typeof gate avoids running `instanceof` against every Web\n // class for the common JSON-object case. Strings and primitives\n // (number/boolean) take their dedicated branches; objects fall\n // through to a single `instanceof Response` check + JSON.\n const t = typeof value;\n\n if (t === 'string') {\n const { status, headers } = event.response;\n if (!headers.has('content-type')) {\n headers.set('content-type', 'text/plain; charset=utf-8');\n }\n\n // null is \"explicitly disabled\"; undefined falls back to the\n // default fn. Either truthy fn or undefined → run applyEtag.\n if (event.appOptions.etag !== null) {\n return applyEtag(value as string, event, headers)\n .then((cached) => cached ?? new Response(value as string, {\n status,\n headers,\n }));\n }\n\n return new Response(value as string, {\n status,\n headers,\n });\n }\n\n if (\n t === 'object' &&\n !Array.isArray(value)\n ) {\n // The handler's return value is structurally an object.\n // Order checks by frequency: Response > JSON object > rare\n // binary types. The hot path (JSON object) takes exactly\n // one `instanceof Response` check before reaching the JSON\n // serializer.\n if (value instanceof Response) {\n return value;\n }\n\n const { status, headers } = event.response;\n\n // Binary / streaming bodies. Each branch is a single\n // instanceof + dedicated Response construction.\n if (value instanceof ArrayBuffer || value instanceof Uint8Array) {\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/octet-stream');\n }\n return new Response(value as BodyInit, {\n status,\n headers,\n });\n }\n\n if (value instanceof ReadableStream) {\n return new Response(value, {\n status,\n headers,\n });\n }\n\n if (value instanceof Blob) {\n if (!headers.has('content-type')) {\n headers.set('content-type', value.type || 'application/octet-stream');\n }\n return new Response(value, {\n status,\n headers,\n });\n }\n }\n\n const { status, headers } = event.response;\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json; charset=utf-8');\n }\n\n let json: string;\n try {\n json = JSON.stringify(value);\n } catch (e) {\n throw createError({\n message: 'JSON serialization failed',\n status: 500,\n cause: e,\n });\n }\n\n if (event.appOptions.etag !== null) {\n return applyEtag(json, event, headers)\n .then((cached) => cached ?? new Response(json, {\n status,\n headers,\n }));\n }\n\n return new Response(json, {\n status,\n headers,\n });\n}\n","import type { IAppEvent } from '../../event/index.ts';\nimport { toResponse } from '../to-response.ts';\n\nexport async function sendAccepted(event: IAppEvent, data?: unknown): Promise<Response> {\n event.response.status = 202;\n\n return await toResponse(data ?? '', event) as Response;\n}\n","import type { IAppEvent } from '../../event/index.ts';\nimport { toResponse } from '../to-response.ts';\n\nexport async function sendCreated(event: IAppEvent, data?: unknown): Promise<Response> {\n event.response.status = 201;\n\n return await toResponse(data ?? '', event) as Response;\n}\n","import { HeaderName } from '../../constants.ts';\nimport { basename } from '../../utils/index.ts';\nimport type { IAppEvent } from '../../event/index.ts';\nimport { setResponseHeaderAttachment, setResponseHeaderInline } from './header-disposition.ts';\nimport { setResponseContentTypeByFileName } from './utils.ts';\n\nexport type SendFileContentOptions = {\n end?: number,\n start?: number;\n};\n\n/**\n * File metadata used by {@link sendFile}. All fields are optional, but each\n * missing field disables related response features:\n *\n * - `size` — without it, range requests, `Accept-Ranges`, `Content-Length`,\n * `ETag`, and `Last-Modified` are all omitted (the response is sent\n * without HTTP-level caching or seekability).\n * - `mtime` — without it, `Last-Modified` is omitted and the `ETag` is not\n * emitted (`ETag` requires both `size` and `mtime`).\n * - `name` — falls back to `SendFileOptions.name` when set; if both are\n * missing, no `Content-Disposition` or extension-derived\n * `Content-Type` is set.\n */\nexport type SendFileStats = {\n size?: number,\n mtime?: Date | number | string,\n name?: string\n};\n\nexport type SendFileDisposition = 'attachment' | 'inline';\n\nexport type SendFileContent = ReadableStream | ArrayBuffer | Uint8Array;\nexport type SendFileOptions = {\n stats: (() => Promise<SendFileStats> | SendFileStats) | SendFileStats,\n content: (options: SendFileContentOptions) => Promise<SendFileContent> | SendFileContent,\n /**\n * @deprecated Use `disposition: 'attachment'` instead. Kept for backwards\n * compatibility — when `disposition` is set, it takes precedence.\n */\n attachment?: boolean,\n disposition?: SendFileDisposition,\n name?: string\n};\n\nexport async function sendFile(\n event: IAppEvent,\n options: SendFileOptions,\n) : Promise<Response> {\n let stats : SendFileStats;\n if (typeof options.stats === 'function') {\n stats = await options.stats();\n } else {\n stats = options.stats;\n }\n\n const name = options.name || stats.name;\n const { headers } = event.response;\n\n const disposition = options.disposition ?? (options.attachment ? 'attachment' : undefined);\n\n if (name) {\n const fileName = basename(name);\n\n if (disposition) {\n const dispositionHeader = headers.get(HeaderName.CONTENT_DISPOSITION);\n if (!dispositionHeader) {\n if (disposition === 'inline') {\n setResponseHeaderInline(event, fileName);\n } else {\n setResponseHeaderAttachment(event, fileName);\n }\n }\n } else {\n setResponseContentTypeByFileName(event, fileName);\n }\n }\n\n const contentOptions : SendFileContentOptions = {};\n let statusCode = event.response.status;\n\n if (stats.size) {\n const rangeHeader = event.headers.get(HeaderName.RANGE);\n if (rangeHeader) {\n const [x, y] = rangeHeader.replace('bytes=', '')\n .split('-') as [string, string];\n\n const parsedStart = Number.parseInt(x, 10);\n const parsedEnd = Number.parseInt(y, 10);\n\n contentOptions.start = Number.isFinite(parsedStart) && parsedStart >= 0 ? parsedStart : 0;\n contentOptions.end = Number.isFinite(parsedEnd) && parsedEnd >= 0 ?\n Math.min(parsedEnd, stats.size - 1) :\n stats.size - 1;\n\n if (\n contentOptions.start >= stats.size ||\n contentOptions.start > contentOptions.end\n ) {\n const rangeHeaders = new Headers(headers);\n rangeHeaders.set(HeaderName.CONTENT_RANGE, `bytes */${stats.size}`);\n return new Response(null, {\n status: 416,\n headers: rangeHeaders,\n });\n }\n\n headers.set(HeaderName.CONTENT_RANGE, `bytes ${contentOptions.start}-${contentOptions.end}/${stats.size}`);\n headers.set(HeaderName.CONTENT_LENGTH, `${contentOptions.end - contentOptions.start + 1}`);\n statusCode = 206;\n } else {\n headers.set(HeaderName.CONTENT_LENGTH, `${stats.size}`);\n }\n\n headers.set(HeaderName.ACCEPT_RANGES, 'bytes');\n\n if (stats.mtime) {\n const mtime = new Date(stats.mtime);\n headers.set(HeaderName.LAST_MODIFIED, mtime.toUTCString());\n headers.set(HeaderName.ETag, `W/\"${stats.size}-${mtime.getTime()}\"`);\n }\n }\n\n const content = await options.content(contentOptions);\n\n return new Response(content as BodyInit, {\n status: statusCode,\n headers,\n });\n}\n","import type { IAppEvent } from '../../event/index.ts';\n\nexport function getRequestHeader(\n event: IAppEvent,\n name: string,\n) : string | null {\n return event.headers.get(name);\n}\n","import Negotiator from 'negotiator';\n\nimport type { IAppEvent } from '../../event/index.ts';\n\nconst NEGOTIATOR_KEY = Symbol.for('routup:negotiator');\n\nfunction headersToPlainObject(headers: Headers) : Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n}\n\nexport function useRequestNegotiator(event: IAppEvent) : Negotiator {\n let value = event.store[NEGOTIATOR_KEY] as Negotiator | undefined;\n if (value) {\n return value;\n }\n\n value = new Negotiator({ headers: headersToPlainObject(event.headers) });\n event.store[NEGOTIATOR_KEY] = value;\n return value;\n}\n","import { HeaderName } from '../../constants.ts';\nimport { getMimeType } from '../../utils/index.ts';\nimport type { IAppEvent } from '../../event/index.ts';\nimport { getRequestHeader } from './header.ts';\nimport { useRequestNegotiator } from './negotiator.ts';\n\nexport function getRequestAcceptableContentTypes(event: IAppEvent) : string[] {\n const negotiator = useRequestNegotiator(event);\n\n return negotiator.mediaTypes();\n}\n\nexport function getRequestAcceptableContentType(event: IAppEvent, input?: string | string[]) : string | undefined {\n input = input || [];\n\n const items = Array.isArray(input) ? input : [input];\n\n if (items.length === 0) {\n return getRequestAcceptableContentTypes(event).shift();\n }\n\n const header = getRequestHeader(event, HeaderName.ACCEPT);\n if (!header) {\n return items[0];\n }\n\n let polluted = false;\n const mimeTypes : string[] = [];\n for (const item of items) {\n const mimeType = getMimeType(item);\n if (mimeType) {\n mimeTypes.push(mimeType);\n } else {\n polluted = true;\n }\n }\n\n const negotiator = useRequestNegotiator(event);\n const matches = negotiator.mediaTypes(mimeTypes);\n if (matches.length > 0) {\n if (polluted) {\n return items[0];\n }\n\n return items[mimeTypes.indexOf(matches[0]!)];\n }\n\n return undefined;\n}\n","import { getRequestAcceptableContentType } from '../../request/helpers/header-accept.ts';\nimport type { IAppEvent } from '../../event/index.ts';\n\ntype ResponseFormatHandler = () => Response | unknown;\n\ntype ResponseFormats = {\n default: ResponseFormatHandler,\n [key: string]: ResponseFormatHandler,\n};\n\nexport function sendFormat(event: IAppEvent, input: ResponseFormats): Response | unknown | undefined {\n const {\n default: formatDefault,\n ...formats\n } = input;\n\n const contentTypes = Object.keys(formats);\n\n if (contentTypes.length === 0) {\n return formatDefault();\n }\n\n const contentType = getRequestAcceptableContentType(event, contentTypes);\n if (contentType && formats[contentType]) {\n return formats[contentType]();\n }\n\n return formatDefault();\n}\n","import { AppError } from '../../error/module.ts';\nimport { sanitizeHeaderValue } from '../../utils/index.ts';\nimport type { IAppEvent } from '../../event/index.ts';\n\nfunction escapeHtml(str: string) : string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\nfunction isAllowedRedirectUrl(location: string) : boolean {\n // Block protocol-relative URLs (e.g. //evil.com)\n if (location.startsWith('//')) {\n return false;\n }\n\n if (location.startsWith('/') || location.startsWith('.')) {\n return true;\n }\n\n try {\n const url = new URL(location);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return true;\n }\n}\n\nexport function sendRedirect(event: IAppEvent, location: string, statusCode = 302): Response {\n if (!isAllowedRedirectUrl(location)) {\n throw new AppError({\n status: 400,\n message: 'Invalid redirect URL scheme.',\n });\n }\n\n const sanitizedLocation = sanitizeHeaderValue(location);\n const escapedLoc = escapeHtml(location);\n const html = `<!DOCTYPE html><html><head><meta http-equiv=\"refresh\" content=\"0; url=${escapedLoc}\"></head></html>`;\n\n const headers = new Headers(event.response.headers);\n headers.set('location', sanitizedLocation);\n headers.set('content-type', 'text/html; charset=utf-8');\n headers.delete('content-length');\n\n const response = new Response(html, {\n status: statusCode,\n headers,\n });\n\n return response;\n}\n","import type { IAppEvent } from '../../event/index.ts';\n\nexport function sendStream(event: IAppEvent, stream: ReadableStream): Response {\n const {\n status,\n headers,\n } = event.response;\n\n return new Response(stream, {\n status,\n headers,\n });\n}\n","import { FastURL } from 'srvx';\nimport type { AppError } from '../error/module.ts';\nimport { AppEvent } from '../event/module.ts';\nimport type {\n AppRequest,\n AppResponse,\n IAppEvent,\n NextFn,\n} from '../event/types.ts';\nimport { toResponse } from '../response/index.ts';\nimport type { AppOptions } from '../app/types.ts';\nimport type { MethodNameLike } from '../constants.ts';\nimport type { IDispatcherEvent } from './types.ts';\n\n\nexport class DispatcherEvent implements IDispatcherEvent {\n readonly request: AppRequest;\n\n params: Record<string, string | undefined>;\n\n path: string;\n\n readonly method: MethodNameLike;\n\n /**\n * Collected allowed methods (for OPTIONS).\n */\n methodsAllowed: Set<string>;\n\n mountPath: string;\n\n error?: AppError;\n\n /**\n * Options of the App currently dispatching this event. Set on\n * entry to `App.dispatch` and restored on exit so re-entrant\n * dispatch calls leave the caller's view intact. Initialized to\n * `{}` so consumers reading before any dispatch get a valid\n * (empty) shape.\n */\n appOptions: Readonly<AppOptions>;\n\n /**\n * `true` while an `App.dispatch` call is on the stack for this\n * event. `App.dispatch` reads this on entry to derive `isRoot`\n * and writes it on entry/exit so re-entrant calls behave\n * correctly.\n */\n isDispatching: boolean;\n\n protected _dispatched: boolean;\n\n protected _response?: AppResponse;\n\n protected _store?: Record<string | symbol, unknown>;\n\n /**\n * Cached parsed URL (avoids double-parsing).\n */\n protected _url: InstanceType<typeof FastURL>;\n\n /**\n * Continuation function for middleware onion model.\n */\n protected _next?: (event: IAppEvent, error?: Error) => Promise<Response | undefined>;\n\n protected _signal?: AbortSignal;\n\n protected _signalCleanup?: () => void;\n\n /**\n * Whether _next has already been called (guard against double-invocation).\n */\n protected _nextCalled: boolean;\n\n /**\n * The cached result of the next handler.\n */\n protected _nextResult?: Promise<Response | undefined>;\n\n // ------------------------------------------------------------------------\n\n constructor(request: AppRequest) {\n this.request = request;\n this._url = new FastURL(request.url);\n this.method = request.method;\n this.path = this._url.pathname;\n this.mountPath = '/';\n this.params = {};\n this.appOptions = {};\n this.isDispatching = false;\n this.methodsAllowed = new Set();\n this._dispatched = false;\n this._nextCalled = false;\n }\n\n // ------------------------------------------------------------------------\n\n get response(): AppResponse {\n if (!this._response) {\n this._response = { status: 200, headers: new Headers() };\n }\n\n return this._response;\n }\n\n get signal(): AbortSignal {\n if (!this._signal) {\n this._signal = this.request.signal;\n }\n\n return this._signal;\n }\n\n set signal(value: AbortSignal) {\n // Clean up listeners from a previous merge\n if (this._signalCleanup) {\n this._signalCleanup();\n this._signalCleanup = undefined;\n }\n\n if (value === this.request.signal) {\n this._signal = value;\n return;\n }\n\n const controller = new AbortController();\n const abort = (e?: Event) => {\n const reason = e?.target instanceof AbortSignal ?\n e.target.reason :\n undefined;\n this.request.signal.removeEventListener('abort', abort);\n value.removeEventListener('abort', abort);\n controller.abort(reason);\n };\n\n if (this.request.signal.aborted || value.aborted) {\n const reason = this.request.signal.aborted ?\n this.request.signal.reason :\n value.reason;\n controller.abort(reason);\n } else {\n this.request.signal.addEventListener('abort', abort, { once: true });\n value.addEventListener('abort', abort, { once: true });\n this._signalCleanup = () => {\n this.request.signal.removeEventListener('abort', abort);\n value.removeEventListener('abort', abort);\n };\n }\n\n this._signal = controller.signal;\n }\n\n get dispatched(): boolean {\n return this._dispatched;\n }\n\n set dispatched(value: boolean) {\n this._dispatched = value;\n }\n\n // ------------------------------------------------------------------------\n\n protected async next(event: IAppEvent, error?: Error): Promise<Response | undefined> {\n if (this._nextCalled) {\n return this._nextResult;\n }\n this._nextCalled = true;\n\n if (this._next) {\n this._nextResult = this._next(event, error);\n }\n\n return this._nextResult;\n }\n\n setNext(fn?: NextFn): void {\n if (fn) {\n this._next = async (event, error?: Error) => {\n const result = await fn(error);\n return toResponse(result, event);\n };\n } else {\n this._next = undefined;\n }\n\n this._nextCalled = false;\n this._nextResult = undefined;\n }\n\n // ------------------------------------------------------------------------\n\n build(signal?: AbortSignal): AppEvent {\n return new AppEvent({\n request: this.request,\n params: this.params,\n path: this.path,\n method: this.method,\n mountPath: this.mountPath,\n headers: this.request.headers,\n searchParams: new URLSearchParams(this._url.search),\n response: this.response,\n store: this.store,\n signal: signal ?? this.signal,\n appOptions: this.appOptions,\n next: (event: IAppEvent, error?: Error) => this.next(event, error),\n });\n }\n\n // ------------------------------------------------------------------------\n\n protected get store(): Record<string | symbol, unknown> {\n if (!this._store) {\n this._store = Object.create(null) as Record<string | symbol, unknown>;\n }\n\n return this._store!;\n }\n}\n","export const HandlerType = {\n CORE: 'core',\n ERROR: 'error',\n} as const;\n\nexport type HandlerType = typeof HandlerType[keyof typeof HandlerType];\n\nexport const HandlerSymbol = Symbol.for('Handler');\n","import { markInstanceof } from '@ebec/core';\nimport type { MethodName } from '../constants.ts';\nimport type { IDispatcher, IDispatcherEvent } from '../dispatcher/index.ts';\nimport { createError, isError } from '../error/index.ts';\nimport type { IAppEvent } from '../event/index.ts';\nimport { toResponse } from '../response/index.ts';\nimport type { AppOptions } from '../app/types.ts';\nimport { isPromise, toMethodName, withLeadingSlash } from '../utils/index.ts';\nimport { HandlerSymbol, HandlerType } from './constants.ts';\nimport type { HandlerOptions } from './types.ts';\n\nexport class Handler implements IDispatcher {\n protected config: HandlerOptions;\n\n readonly method: MethodName | undefined;\n\n // --------------------------------------------------\n\n constructor(handler: HandlerOptions) {\n this.config = handler;\n\n if (typeof handler.path === 'string') {\n this.config.path = withLeadingSlash(handler.path);\n }\n\n this.method = this.config.method ? toMethodName(this.config.method) : undefined;\n\n markInstanceof(this, HandlerSymbol);\n }\n\n // --------------------------------------------------\n\n get type() {\n return this.config.type;\n }\n\n get path() {\n return this.config.path;\n }\n\n // --------------------------------------------------\n\n async dispatch(event: IDispatcherEvent): Promise<Response | undefined> {\n let response: Response | undefined;\n // Hoisted so the outer catch can forward it to `onError` and\n // so the outer finally can release the parent-signal abort\n // listener even when `onBefore` / `event.build()` throws —\n // the inner try/finally that used to own this cleanup was\n // unreachable from those throw sites.\n let handlerEvent: IAppEvent | undefined;\n let cleanupParentListener: (() => void) | undefined;\n\n try {\n // Read router options directly from the dispatcher event so we\n // can decide on the per-handler timeout without first wrapping\n // into a AppEvent — saves a `build()` allocation on the\n // common no-timeout path.\n const effectiveTimeout = this.resolveTimeout(event.appOptions);\n\n // When a per-handler timeout is active, create a child AbortController\n // linked to the parent signal so the handler's signal aborts on timeout\n let childController: AbortController | undefined;\n\n if (effectiveTimeout) {\n const parentSignal = event.signal;\n childController = new AbortController();\n\n if (parentSignal.aborted) {\n childController.abort(parentSignal.reason);\n } else {\n const onAbort = () => childController!.abort(parentSignal.reason);\n parentSignal.addEventListener('abort', onAbort, { once: true });\n cleanupParentListener = () => parentSignal.removeEventListener('abort', onAbort);\n }\n }\n\n // Build the handler event exactly once — with the child signal\n // when a timeout is configured, otherwise inheriting the\n // dispatcher's own signal.\n handlerEvent = childController ?\n event.build(childController.signal) :\n event.build();\n\n // ERROR handlers with no pending error are a no-op — and\n // the onBefore/onAfter callbacks are too (no `fn` ran, so\n // there's nothing to bracket).\n const skipFn = this.config.type === HandlerType.ERROR && !event.error;\n\n if (!skipFn && this.config.onBefore) {\n await this.config.onBefore(handlerEvent);\n }\n\n let invocation: unknown;\n if (skipFn) {\n // invocation stays undefined; falls through to toResponse(undefined) → undefined.\n } else if (this.config.type === HandlerType.ERROR) {\n const { fn } = this.config;\n invocation = fn(event.error!, handlerEvent);\n } else {\n const { fn } = this.config;\n invocation = fn(handlerEvent);\n }\n\n let result: unknown;\n if (skipFn) {\n // no-op\n } else if (effectiveTimeout) {\n // Race the (possibly-async) invocation against the timeout.\n result = await this.executeWithTimeout(\n () => this.resolveHandlerResult(invocation, handlerEvent!),\n effectiveTimeout,\n childController,\n );\n } else if (isPromise(invocation)) {\n // Async handler return — await once. If it resolves\n // to undefined, fall back to the async resolver\n // (waits for `next()` or abort).\n const awaited = await invocation;\n\n result = typeof awaited === 'undefined' ?\n await this.resolveHandlerResult(undefined, handlerEvent) :\n awaited;\n } else if (typeof invocation === 'undefined') {\n // Sync undefined: defer to async resolver — handler\n // may invoke `next()` later from a callback.\n result = await this.resolveHandlerResult(undefined, handlerEvent);\n } else {\n // Sync non-undefined: zero internal microtasks.\n result = invocation;\n }\n\n // `toResponse` returns sync when no ETag is configured —\n // avoid an unconditional `await` to save a microtask.\n const toResp = toResponse(result, handlerEvent);\n response = isPromise(toResp) ?\n await toResp :\n toResp;\n\n if (response) {\n event.dispatched = true;\n // ERROR handler resolved the pending error — clear it\n // so parent pipelines don't observe a stale error.\n if (this.config.type === HandlerType.ERROR && event.error) {\n event.error = undefined;\n }\n }\n\n if (!skipFn && this.config.onAfter) {\n await this.config.onAfter(handlerEvent, response);\n }\n } catch (e) {\n event.error = isError(e) ? e : createError(e);\n\n // Fire `onError` even if the error came from `onBefore`\n // or `onAfter` — it is the handler-scoped error hook.\n // `event.build()` is the fallback when the throw landed\n // before we built `handlerEvent`.\n if (this.config.onError) {\n try {\n await this.config.onError(event.error, handlerEvent ?? event.build());\n } catch (innerErr) {\n event.error = isError(innerErr) ? innerErr : createError(innerErr);\n }\n }\n\n throw event.error;\n } finally {\n if (cleanupParentListener) {\n cleanupParentListener();\n }\n }\n\n return response;\n }\n\n // --------------------------------------------------\n\n /**\n * Resolve a handler's return value into the final value handed to `toResponse`.\n *\n * Contract:\n * - non-undefined value → return as-is (becomes the response)\n * - `undefined` + `event.next()` was called → forward downstream result\n * - `undefined` + `event.next()` not yet called → wait until either `next()` is\n * invoked (e.g. from an async callback) or `signal` aborts. A global or\n * per-handler timeout aborts `signal` and surfaces as 408. With no timeout\n * configured and no eventual `next()` call, the request hangs by design.\n */\n protected async resolveHandlerResult(\n invocation: unknown | Promise<unknown>,\n handlerEvent: IAppEvent,\n ): Promise<unknown> {\n const value = await invocation;\n if (typeof value !== 'undefined') {\n return value;\n }\n\n if (handlerEvent.nextCalled) {\n return handlerEvent.nextResult;\n }\n\n const { signal } = handlerEvent;\n\n if (signal.aborted) {\n throw createError({ status: 408, message: 'Request Timeout' });\n }\n\n return new Promise<unknown>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener('abort', onAbort);\n reject(createError({\n status: 408,\n message: 'Request Timeout',\n }));\n };\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n handlerEvent.whenNextCalled().then(() => {\n signal.removeEventListener('abort', onAbort);\n resolve(handlerEvent.nextResult);\n });\n });\n }\n\n protected async executeWithTimeout(\n fn: () => unknown | Promise<unknown>,\n effectiveTimeout: number | undefined,\n controller?: AbortController,\n ): Promise<unknown> {\n if (!effectiveTimeout) {\n return fn();\n }\n\n let timerId: ReturnType<typeof setTimeout> | undefined;\n\n try {\n return await Promise.race([\n fn(),\n new Promise<never>((_, reject) => {\n timerId = setTimeout(() => {\n if (controller) {\n controller.abort();\n }\n reject(createError({\n status: 408,\n message: 'Request Timeout',\n }));\n }, effectiveTimeout);\n }),\n ]);\n } finally {\n clearTimeout(timerId);\n }\n }\n\n protected resolveTimeout(appOptions: AppOptions): number | undefined {\n const routerDefault = appOptions.handlerTimeout;\n const handlerOverride = this.config.timeout;\n\n if (!routerDefault && !handlerOverride) {\n return undefined;\n }\n\n if (!routerDefault) {\n return handlerOverride;\n }\n\n if (!handlerOverride) {\n return routerDefault;\n }\n\n if (appOptions.handlerTimeoutOverridable) {\n return handlerOverride;\n }\n\n return Math.min(routerDefault, handlerOverride);\n }\n}\n","import { HandlerType } from '../constants.ts';\nimport { Handler } from '../module.ts';\nimport type {\n CoreHandler,\n CoreHandlerOptions,\n} from './types.ts';\n\n/**\n * Create a request handler.\n *\n * @param input - Handler function `(event) => value` or options object `{ fn, path?, method? }`\n *\n * @example\n * ```typescript\n * // Shorthand — function only\n * router.get('/', defineCoreHandler((event) => 'Hello'));\n *\n * // Verbose — with path and method\n * router.use(defineCoreHandler({\n * path: '/users/:id',\n * method: 'GET',\n * fn: (event) => ({ id: event.params.id }),\n * }));\n * ```\n */\nexport function defineCoreHandler(input: Omit<CoreHandlerOptions, | 'type'>) : Handler;\n\nexport function defineCoreHandler(input: CoreHandler) : Handler;\n\nexport function defineCoreHandler(input: any) : Handler {\n if (typeof input === 'function') {\n return new Handler({\n type: HandlerType.CORE,\n fn: input,\n });\n }\n\n return new Handler({\n type: HandlerType.CORE,\n ...input,\n });\n}\n","import { HandlerType } from '../constants.ts';\nimport { Handler } from '../module.ts';\nimport type {\n ErrorHandler,\n ErrorHandlerOptions,\n} from './types.ts';\n\n/**\n * Create an error handler.\n *\n * Error handlers receive errors thrown by preceding handlers in the pipeline.\n *\n * @param input - Handler function `(error, event) => value` or options object `{ fn, path? }`\n *\n * @example\n * ```typescript\n * router.use(defineErrorHandler((error, event) => {\n * return { message: error.message };\n * }));\n * ```\n */\nexport function defineErrorHandler(input: Omit<ErrorHandlerOptions, 'type'>) : Handler;\n\nexport function defineErrorHandler(input: ErrorHandler) : Handler;\nexport function defineErrorHandler(input: any) : Handler {\n if (typeof input === 'function') {\n return new Handler({\n type: HandlerType.ERROR,\n fn: input,\n });\n }\n\n return new Handler({\n type: HandlerType.ERROR,\n ...input,\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { IAppEvent } from '../../../event/index.ts';\nimport { AppError } from '../../../error/module.ts';\nimport { defineCoreHandler } from '../../core/index.ts';\nimport type { Handler } from '../../module.ts';\nimport type { CoreHandler } from '../../core/types.ts';\nimport type { NodeHandler, NodeMiddleware } from './types.ts';\n\nconst kHandled = /* @__PURE__ */ Symbol('handled');\n\nfunction callHandler(\n handler: NodeHandler,\n req: IncomingMessage,\n res: ServerResponse,\n): Promise<typeof kHandled | void> {\n return new Promise((resolve, reject) => {\n let settled = false;\n\n const onClose = () => settle(kHandled);\n const onFinish = () => settle(kHandled);\n const onError = (error: Error) => fail(error);\n\n function cleanup() {\n res.removeListener('close', onClose);\n res.removeListener('finish', onFinish);\n res.removeListener('error', onError);\n }\n\n function settle(value: typeof kHandled | void) {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(value);\n }\n\n function fail(error: unknown) {\n if (settled) return;\n settled = true;\n cleanup();\n reject(error);\n }\n\n res.once('close', onClose);\n res.once('finish', onFinish);\n res.once('error', onError);\n\n try {\n Promise.resolve(handler(req, res))\n .then(() => settle(kHandled))\n .catch(fail);\n } catch (error) {\n fail(error);\n }\n });\n}\n\nfunction callMiddleware(\n handler: NodeMiddleware,\n req: IncomingMessage,\n res: ServerResponse,\n): Promise<typeof kHandled | void> {\n return new Promise((resolve, reject) => {\n let settled = false;\n\n const onClose = () => settle(kHandled);\n const onFinish = () => settle(kHandled);\n const onError = (error: Error) => fail(error);\n\n function cleanup() {\n res.removeListener('close', onClose);\n res.removeListener('finish', onFinish);\n res.removeListener('error', onError);\n }\n\n function settle(value: typeof kHandled | void) {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(value);\n }\n\n function fail(error: unknown) {\n if (settled) return;\n settled = true;\n cleanup();\n reject(error);\n }\n\n res.once('close', onClose);\n res.once('finish', onFinish);\n res.once('error', onError);\n\n try {\n Promise.resolve(\n handler(req, res, (error) => {\n if (error) {\n fail(error);\n } else {\n settle(res.writableEnded || res.destroyed ? kHandled : undefined);\n }\n }),\n ).catch(fail);\n } catch (error) {\n fail(error);\n }\n });\n}\n\nfunction createNodeBridge(handler: NodeHandler | NodeMiddleware, isMiddleware: boolean): Handler {\n if (typeof handler !== 'function') {\n throw new AppError('fromNodeHandler/fromNodeMiddleware expects a function.');\n }\n\n return defineCoreHandler({\n fn: (async (event: IAppEvent) => {\n const node = event.request.runtime?.node;\n if (!node?.req || !node?.res) {\n throw new AppError('fromNodeHandler/fromNodeMiddleware requires a Node.js runtime.');\n }\n\n const req = node.req as unknown as IncomingMessage;\n const res = node.res as unknown as ServerResponse;\n\n const result = isMiddleware ?\n await callMiddleware(handler as NodeMiddleware, req, res) :\n await callHandler(handler as NodeHandler, req, res);\n\n if (result === kHandled) {\n return null;\n }\n\n return event.next();\n }) as CoreHandler,\n });\n}\n\n/**\n * Wraps a Node.js `(req, res)` handler for use in the routup pipeline.\n *\n * @example\n * ```typescript\n * import { fromNodeHandler } from 'routup/node';\n *\n * router.use(fromNodeHandler((req, res) => {\n * res.end('Hello');\n * }));\n * ```\n */\nexport function fromNodeHandler(handler: NodeHandler): Handler {\n return createNodeBridge(handler, false);\n}\n\n/**\n * Wraps a Node.js `(req, res, next)` middleware for use in the routup pipeline.\n *\n * @example\n * ```typescript\n * import cors from 'cors';\n * import { fromNodeMiddleware } from 'routup/node';\n *\n * router.use(fromNodeMiddleware(cors()));\n * ```\n */\nexport function fromNodeMiddleware(handler: NodeMiddleware): Handler {\n return createNodeBridge(handler, true);\n}\n","import { isObject } from '../../../utils/index.ts';\nimport type { WebHandler, WebHandlerProvider } from './types.ts';\n\nexport function isWebHandlerProvider(input: unknown): input is WebHandlerProvider {\n return isObject(input) &&\n typeof input.fetch === 'function';\n}\n\nexport function isWebHandler(input: unknown): input is WebHandler {\n return typeof input === 'function';\n}\n","import type { IAppEvent } from '../../../event/index.ts';\nimport { AppError } from '../../../error/index.ts';\nimport { defineCoreHandler } from '../../core/index.ts';\nimport type { Handler } from '../../module.ts';\nimport { isWebHandlerProvider } from './is.ts';\nimport type { WebHandler, WebHandlerProvider } from './types.ts';\n\n/**\n * Create a handler from a Web Fetch API-compatible function or object.\n *\n * Wraps an external app (e.g. Hono, another App) so it can be mounted\n * via `router.use()`. The original request is passed through as-is.\n *\n * @param input - Fetch function `(request) => Response` or object with a `fetch` method\n *\n * @experimental\n *\n * @example\n * ```ts\n * // Mount an object with a fetch method\n * router.use('/api', fromWebHandler(honoApp));\n *\n * // Mount a plain fetch function\n * router.use('/proxy', fromWebHandler((req) => fetch(req)));\n * ```\n */\nexport function fromWebHandler(input: WebHandler) : Handler;\n\nexport function fromWebHandler(input: WebHandlerProvider) : Handler;\n\nexport function fromWebHandler(input: any) : Handler {\n if (isWebHandlerProvider(input)) {\n return fromWebHandler(input.fetch.bind(input));\n }\n\n if (typeof input !== 'function') {\n throw new AppError('fromWebHandler expects a function or an object with a fetch method.');\n }\n\n return defineCoreHandler({ fn: (event: IAppEvent) => input(event.request) });\n}\n","import { hasInstanceof } from '@ebec/core';\nimport { isObject } from '../utils/index.ts';\nimport { HandlerSymbol } from './constants.ts';\nimport type { Handler } from './module.ts';\nimport type { HandlerOptions } from './types.ts';\n\nexport function isHandlerOptions(input: unknown) : input is HandlerOptions {\n return isObject(input) &&\n typeof input.fn === 'function' &&\n typeof input.type === 'string';\n}\n\nexport function isHandler(input: unknown): input is Handler {\n return hasInstanceof(input, HandlerSymbol);\n}\n\n","import { MethodName } from '../constants.ts';\n\n/**\n * Match a request method against a handler's bound method.\n *\n * - When the handler has no method bound, matches every request method.\n * - Otherwise matches when the request method is the same.\n * - HEAD requests additionally match GET handlers.\n */\nexport function matchHandlerMethod(\n handlerMethod: MethodName | undefined,\n requestMethod: MethodName,\n): boolean {\n return !handlerMethod ||\n requestMethod === handlerMethod ||\n (requestMethod === MethodName.HEAD && handlerMethod === MethodName.GET);\n}\n","import { HeaderName } from '../../constants.ts';\n\nimport type { IAppEvent } from '../../event/index.ts';\n\nexport function isRequestCacheable(event: IAppEvent, modifiedTime: string | Date) : boolean {\n const modifiedSince = event.headers.get(HeaderName.IF_MODIFIED_SINCE);\n if (!modifiedSince) {\n return false;\n }\n\n modifiedTime = typeof modifiedTime === 'string' ?\n new Date(modifiedTime) :\n modifiedTime;\n\n const sinceDate = new Date(modifiedSince);\n if (Number.isNaN(sinceDate.getTime()) || Number.isNaN(modifiedTime.getTime())) {\n return false;\n }\n\n return sinceDate >= modifiedTime;\n}\n","import type { IAppEvent } from '../../event/index.ts';\nimport { useRequestNegotiator } from './negotiator.ts';\n\nexport function getRequestAcceptableCharsets(event: IAppEvent) : string[] {\n const negotiator = useRequestNegotiator(event);\n\n return negotiator.charsets();\n}\n\nexport function getRequestAcceptableCharset(event: IAppEvent, input: string | string[]) : string | undefined {\n input = input || [];\n\n const items = Array.isArray(input) ? input : [input];\n\n if (items.length === 0) {\n return getRequestAcceptableCharsets(event).shift();\n }\n\n const negotiator = useRequestNegotiator(event);\n return negotiator.charsets(items).shift() || undefined;\n}\n","import type { IAppEvent } from '../../event/index.ts';\nimport { useRequestNegotiator } from './negotiator.ts';\n\nexport function getRequestAcceptableEncodings(event: IAppEvent) : string[] {\n const negotiator = useRequestNegotiator(event);\n return negotiator.encodings();\n}\n\nexport function getRequestAcceptableEncoding(event: IAppEvent, input: string | string[]) : string | undefined {\n input = input || [];\n\n const items = Array.isArray(input) ? input : [input];\n\n if (items.length === 0) {\n return getRequestAcceptableEncodings(event).shift();\n }\n\n const negotiator = useRequestNegotiator(event);\n return negotiator.encodings(items).shift() || undefined;\n}\n","import type { IAppEvent } from '../../event/index.ts';\nimport { useRequestNegotiator } from './negotiator.ts';\n\nexport function getRequestAcceptableLanguages(event: IAppEvent) : string[] {\n const negotiator = useRequestNegotiator(event);\n return negotiator.languages();\n}\n\nexport function getRequestAcceptableLanguage(event: IAppEvent, input?: string | string[]) : string | undefined {\n input = input || [];\n\n const items = Array.isArray(input) ? input : [input];\n\n if (items.length === 0) {\n return getRequestAcceptableLanguages(event).shift();\n }\n\n const negotiator = useRequestNegotiator(event);\n return negotiator.languages(items).shift() || undefined;\n}\n","import { HeaderName } from '../../constants.ts';\nimport { getMimeType } from '../../utils/index.ts';\nimport type { IAppEvent } from '../../event/index.ts';\nimport { getRequestHeader } from './header.ts';\n\nexport function matchRequestContentType(event: IAppEvent, contentType: string) : boolean {\n const header = getRequestHeader(event, HeaderName.CONTENT_TYPE);\n if (!header) {\n return true;\n }\n\n return header.split(';')[0]!.trim() === getMimeType(contentType);\n}\n","import { HeaderName } from '../../constants.ts';\nimport type { TrustProxyFn, TrustProxyInput } from '../../utils/index.ts';\nimport { DEFAULT_TRUST_PROXY, buildTrustProxyFn } from '../../utils/index.ts';\nimport type { IAppEvent } from '../../event/index.ts';\n\nexport type RequestHostNameOptions = {\n trustProxy?: TrustProxyInput,\n};\n\nexport function getRequestHostName(event: IAppEvent, options: RequestHostNameOptions = {}) : string | undefined {\n let trustProxy : TrustProxyFn;\n if (typeof options.trustProxy !== 'undefined') {\n trustProxy = buildTrustProxyFn(options.trustProxy);\n } else {\n trustProxy = event.appOptions.trustProxy ?? DEFAULT_TRUST_PROXY;\n }\n\n let hostname = event.headers.get(HeaderName.X_FORWARDED_HOST);\n if (!hostname || !event.request.ip || !trustProxy(event.request.ip, 0)) {\n hostname = event.headers.get(HeaderName.HOST);\n } else if (hostname && hostname.includes(',')) {\n hostname = hostname.substring(0, hostname.indexOf(',')).trimEnd();\n }\n\n if (!hostname) {\n return undefined;\n }\n\n // IPv6 literal support\n const offset = hostname[0] === '[' ?\n hostname.indexOf(']') + 1 :\n 0;\n const index = hostname.indexOf(':', offset);\n\n const result = index !== -1 ?\n hostname.substring(0, index) :\n hostname;\n\n // Reject hostnames with obviously invalid characters\n // eslint-disable-next-line no-control-regex\n if (/[\\x00-\\x1F\\x7F\\s/@\\\\]/.test(result)) {\n return undefined;\n }\n\n return result;\n}\n","import { HeaderName } from '../../constants.ts';\nimport type { IAppEvent } from '../../event/index.ts';\nimport type { TrustProxyFn, TrustProxyInput } from '../../utils/index.ts';\nimport { DEFAULT_TRUST_PROXY, buildTrustProxyFn } from '../../utils/index.ts';\n\nexport type RequestIpOptions = {\n trustProxy?: TrustProxyInput,\n};\n\n/**\n * Get the client IP address from the request.\n *\n * When `trustProxy` is configured, walks the `X-Forwarded-For` chain\n * and returns the rightmost untrusted address (the actual client IP).\n * Falls back to `event.request.ip` (the direct connection IP).\n */\nexport function getRequestIP(event: IAppEvent, options: RequestIpOptions = {}) : string | undefined {\n let trustProxy : TrustProxyFn;\n if (typeof options.trustProxy !== 'undefined') {\n trustProxy = buildTrustProxyFn(options.trustProxy);\n } else {\n trustProxy = event.appOptions.trustProxy ?? DEFAULT_TRUST_PROXY;\n }\n\n const socketAddr = event.request.ip;\n if (!socketAddr) {\n return undefined;\n }\n\n // Build address list: [socket IP, ...forwarded addresses (rightmost first)]\n const forwarded = event.headers.get(HeaderName.X_FORWARDED_FOR);\n const addrs: string[] = [socketAddr];\n\n if (forwarded) {\n const parts = forwarded.split(',');\n for (let i = parts.length - 1; i >= 0; i--) {\n const addr = parts[i]!.trim();\n if (addr) {\n addrs.push(addr);\n }\n }\n }\n\n // Walk from socket (leftmost) to client (rightmost),\n // stopping at the first untrusted address\n for (let i = 0; i < addrs.length - 1; i++) {\n if (!trustProxy(addrs[i]!, i)) {\n return addrs[i];\n }\n }\n\n // All proxies trusted — return the original client (last in chain)\n return addrs[addrs.length - 1];\n}\n","import { HeaderName } from '../../constants.ts';\nimport type { TrustProxyFn, TrustProxyInput } from '../../utils/index.ts';\nimport { DEFAULT_TRUST_PROXY, buildTrustProxyFn } from '../../utils/index.ts';\nimport type { IAppEvent } from '../../event/index.ts';\n\nexport type RequestProtocolOptions = {\n trustProxy?: TrustProxyInput,\n default?: string,\n};\n\nexport function getRequestProtocol(\n event: IAppEvent,\n options: RequestProtocolOptions = {},\n) : string {\n let trustProxy : TrustProxyFn;\n if (typeof options.trustProxy !== 'undefined') {\n trustProxy = buildTrustProxyFn(options.trustProxy);\n } else {\n trustProxy = event.appOptions.trustProxy ?? DEFAULT_TRUST_PROXY;\n }\n\n // Derive protocol from the request URL scheme\n let protocol : string;\n try {\n const url = new URL(event.request.url);\n if (url.protocol === 'https:') {\n protocol = 'https';\n } else {\n protocol = 'http';\n }\n } catch {\n protocol = options.default || 'http';\n }\n\n if (!event.request.ip || !trustProxy(event.request.ip, 0)) {\n return protocol;\n }\n\n const header = event.headers.get(HeaderName.X_FORWARDED_PROTO);\n if (!header) {\n return protocol;\n }\n\n const index = header.indexOf(',');\n\n const forwarded = index !== -1 ?\n header.substring(0, index).trim().toLowerCase() :\n header.trim().toLowerCase();\n\n if (forwarded === 'http' || forwarded === 'https') {\n return forwarded;\n }\n\n return protocol;\n}\n","import type { Key } from 'path-to-regexp';\nimport { pathToRegexp } from 'path-to-regexp';\nimport type {\n IPathMatcher,\n Path,\n PathMatcherExecResult,\n PathMatcherOptions,\n} from './type.ts';\n\nfunction decodeParam(val: unknown) {\n /* istanbul ignore next */\n if (typeof val !== 'string' || val.length === 0) {\n return val;\n }\n\n try {\n return decodeURIComponent(val);\n } catch {\n return val;\n }\n}\n\nexport class PathMatcher implements IPathMatcher {\n protected path: Path;\n\n protected regexp : RegExp;\n\n protected regexpKeys : Key[] = [];\n\n protected regexpOptions: PathMatcherOptions;\n\n constructor(path: Path, options?: PathMatcherOptions) {\n this.path = path;\n\n this.regexpOptions = options || {};\n const regexp = pathToRegexp(path, options);\n\n this.regexp = regexp.regexp;\n this.regexpKeys = regexp.keys;\n }\n\n test(path: string) : boolean {\n return this.regexp.test(path);\n }\n\n exec(path: string) : PathMatcherExecResult | undefined {\n if (\n this.path === '/' &&\n this.regexpOptions.end === false\n ) {\n return {\n path: '/',\n params: Object.create(null),\n };\n }\n\n const match = this.regexp.exec(path);\n\n if (!match) {\n return undefined;\n }\n\n const params : Record<string, unknown> = Object.create(null);\n\n for (let i = 1; i < match.length; i++) {\n const key = this.regexpKeys[i - 1];\n if (!key) continue;\n const prop = key.name;\n const val = decodeParam(match[i]);\n\n if (typeof val !== 'undefined') {\n params[prop] = val;\n }\n }\n\n return {\n path: match[0],\n params,\n };\n }\n}\n","import type { Path } from './type.ts';\n\nexport function isPath(input: unknown): input is Path {\n return typeof input === 'string';\n}\n","export const PluginErrorCode = {\n PLUGIN: 'PLUGIN',\n NOT_INSTALLED: 'PLUGIN_NOT_INSTALLED',\n ALREADY_INSTALLED: 'PLUGIN_ALREADY_INSTALLED',\n INSTALL: 'PLUGIN_INSTALL',\n} as const;\n\nexport type PluginErrorCode = typeof PluginErrorCode[keyof typeof PluginErrorCode];\n","import { isError } from '../../error/is.ts';\nimport { PluginErrorCode } from './constants.ts';\nimport type { PluginError } from './module.ts';\n\nconst PLUGIN_ERROR_CODES = new Set<string>(Object.values(PluginErrorCode));\n\nexport function isPluginError(input: unknown): input is PluginError {\n if (!isError(input)) {\n return false;\n }\n\n return PLUGIN_ERROR_CODES.has(input.code);\n}\n","import type { HTTPErrorInput } from '@ebec/http';\nimport { AppError } from '../../error/module.ts';\nimport { PluginErrorCode } from './constants.ts';\n\nexport class PluginError extends AppError {\n constructor(input: HTTPErrorInput = {}) {\n const options = typeof input === 'string' ? { message: input } : { ...(input as object) };\n if (!('code' in options) || !(options as Record<string, unknown>).code) {\n (options as Record<string, unknown>).code = PluginErrorCode.PLUGIN;\n }\n super(options as HTTPErrorInput);\n this.name = 'PluginError';\n }\n}\n","import { PluginErrorCode } from '../constants.ts';\nimport { PluginError } from '../module.ts';\n\nexport class PluginAlreadyInstalledError extends PluginError {\n public readonly pluginName: string;\n\n constructor(pluginName: string) {\n super({\n message: `Plugin \"${pluginName}\" is already installed on this router.`,\n code: PluginErrorCode.ALREADY_INSTALLED,\n });\n this.name = 'PluginAlreadyInstalledError';\n this.pluginName = pluginName;\n }\n}\n","import { PluginErrorCode } from '../constants.ts';\nimport { PluginError } from '../module.ts';\n\nexport class PluginInstallError extends PluginError {\n public readonly pluginName: string;\n\n constructor(pluginName: string, cause?: Error) {\n super({\n message: `Failed to install plugin \"${pluginName}\".`,\n code: PluginErrorCode.INSTALL,\n cause,\n });\n this.name = 'PluginInstallError';\n this.pluginName = pluginName;\n }\n}\n","import { PluginErrorCode } from '../constants.ts';\nimport { PluginError } from '../module.ts';\n\nexport class PluginNotInstalledError extends PluginError {\n public readonly pluginName: string;\n\n public readonly helperName: string;\n\n constructor(pluginName: string, helperName: string) {\n super({\n message: `${helperName}() requires the \"${pluginName}\" plugin. ` +\n `Register it with: router.use(${pluginName}())`,\n code: PluginErrorCode.NOT_INSTALLED,\n });\n this.name = 'PluginNotInstalledError';\n this.pluginName = pluginName;\n this.helperName = helperName;\n }\n}\n","import { isObject } from '../utils/index.ts';\nimport type { Plugin } from './types.ts';\n\nexport function isPlugin(input: unknown): input is Plugin {\n if (!isObject(input)) {\n return false;\n }\n\n if (\n typeof input.name !== 'undefined' &&\n typeof input.name !== 'string'\n ) {\n return false;\n }\n\n return typeof input.install === 'function' &&\n input.install.length === 1;\n}\n","import { PathMatcher } from '../path/index.ts';\nimport type { IPathMatcher } from '../path/index.ts';\nimport type { ObjectLiteral, Route } from '../types.ts';\n\n/**\n * Build a path-to-regexp-backed `PathMatcher` for the route's mount\n * path, applying the exact-vs-prefix convention every router should\n * agree on:\n *\n * - `route.method !== undefined` → exact match (method-bound route)\n * - `route.method === undefined` → prefix match (middleware / nested\n * app)\n *\n * Returns `undefined` when the route has no mount path — middleware\n * registered without a path matches every request.\n *\n * Routers are free to ignore this helper and build their own match\n * mechanism (radix tree, single aggregated regex, etc.) — it's\n * provided as a convenience for routers that want path-to-regexp\n * semantics with minimal boilerplate.\n */\nexport function buildRoutePathMatcher<T extends ObjectLiteral = ObjectLiteral>(\n route: Route<T>,\n): IPathMatcher | undefined {\n if (typeof route.path === 'undefined') {\n return undefined;\n }\n\n const end = typeof route.method !== 'undefined';\n\n // For prefix matchers a lone '/' contributes nothing useful (it\n // matches every URL), so skip building it. Exact matchers must\n // honor '/' — `app.get('/', …)` matches the root only.\n if (!end && route.path === '/') {\n return undefined;\n }\n\n return new PathMatcher(route.path, { end });\n}\n","import type { ICache } from '../../cache/index.ts';\nimport type { MethodNameLike } from '../../constants.ts';\nimport type { IPathMatcher } from '../../path/index.ts';\nimport type { ObjectLiteral, Route, RouteMatch } from '../../types.ts';\nimport type { BaseRouterOptions, IRouter } from '../types.ts';\nimport { buildRoutePathMatcher } from '../utils.ts';\n\n/**\n * Default router — walks registered routes linearly per request and\n * runs each route's mount-level matcher (built via `buildRoutePathMatcher`,\n * path-to-regexp-backed). Routes without a mount path (mount-less\n * middleware / nested apps registered via `.use(handler)`) match every\n * request directly — there is no per-route `matchPath()` fallback.\n *\n * Behaviour-preserving wrapper around the previous in-line stack walk\n * in `executePipelineStepLookup`. The matcher allocations live here\n * (not on the registered route), so routers using a different matching\n * strategy (radix tree, aggregated regex, …) can ignore this file\n * entirely.\n *\n * Optional per-router lookup cache: pass an `ICache` via\n * `BaseRouterOptions.cache` to skip the linear walk on repeated\n * requests for the same path. Default is no caching.\n */\nexport class LinearRouter<T extends ObjectLiteral = ObjectLiteral> implements IRouter<T> {\n protected _routes: Route<T>[];\n\n protected _matchers: (IPathMatcher | undefined)[];\n\n protected cache?: ICache<readonly RouteMatch<T>[]>;\n\n constructor(options: BaseRouterOptions<T> = {}) {\n this._routes = [];\n this._matchers = [];\n this.cache = options.cache;\n }\n\n add(route: Route<T>): void {\n this._routes.push(route);\n this._matchers.push(buildRoutePathMatcher(route));\n // A new route can change the match set for any cached path —\n // drop the whole cache. Conservative; per-path invalidation\n // would require knowing which paths the new route can match.\n this.cache?.clear();\n }\n\n lookup(path: string, _method?: MethodNameLike): readonly RouteMatch<T>[] {\n // LinearRouter ignores `method`: the dispatcher's own\n // `matchHandlerMethod` check runs on every returned candidate\n // anyway, so we simply emit every path-matching route and let\n // the call site discriminate. Method-aware routers (TrieRouter)\n // narrow at lookup time for the per-request perf win.\n const cached = this.cache?.get(path);\n if (typeof cached !== 'undefined') {\n return cached;\n }\n\n const matches: RouteMatch<T>[] = [];\n\n for (let i = 0; i < this._routes.length; i++) {\n const route = this._routes[i]!;\n const matcher = this._matchers[i];\n\n if (matcher) {\n const output = matcher.exec(path);\n if (typeof output === 'undefined') {\n continue;\n }\n matches.push({\n route,\n index: i,\n params: output.params,\n path: output.path,\n });\n continue;\n }\n\n // No matcher → route has no mount path (middleware /\n // mount-less router). Matches every request.\n matches.push({\n route,\n index: i,\n // Prototype-less for symmetry with TrieRouter — avoids\n // `__proto__` / `hasOwnProperty` shadowing if user\n // code does `'foo' in match.params`.\n params: Object.create(null) as Record<string, string | undefined>,\n });\n }\n\n this.cache?.set(path, matches);\n return matches;\n }\n}\n","import type { Segment } from './types.ts';\n\n/**\n * Trie-native path parser.\n *\n * Replaces the call-out to `path-to-regexp` for the syntax surface\n * the trie advertises:\n *\n * - Static segments: `users`, `v1`\n * - Named params: `:id`, `:slug`\n * - Optional params: `:id?` (T2 — expanded to two variants)\n * - Optional groups: `{...}` (T2 — expanded to two variants)\n * - Bare splat: `*` (matches the rest of the path)\n * - Named splat: `*rest`\n *\n * Returns a list of `Segment[]` *variants* — one path string can\n * expand into multiple route variants when it contains optional\n * markers. The trie inserts every variant with the same registration\n * `index` so they dedupe naturally on the candidate list.\n *\n * Returns `null` when the path uses syntax outside this surface\n * (compound segments `/files/:n.ext`, escape sequences `\\:`, regex\n * constraints, splat-not-last, …). The caller falls back to the\n * universal bucket so correctness is preserved via path-to-regexp.\n *\n * Variant cap: nested optional groups expand combinatorially. The\n * parser caps the variant count at `MAX_VARIANTS` and falls back to\n * the universal bucket above that — registration-time explosion\n * isn't worth the lookup-time win on degenerate paths.\n */\n\nconst MAX_VARIANTS = 16;\n\nconst PARAM_NAME = /^[a-zA-Z_]\\w*$/;\n\ntype ParamToken = {\n kind: 'param';\n name: string;\n optional: boolean;\n};\n\ntype Token = { kind: 'literal'; value: string } |\n ParamToken |\n { kind: 'splat'; name: string } |\n { kind: 'groupOpen' } |\n { kind: 'groupClose' };\n\n/**\n * Tokenize a single path segment (the substring between two `/`).\n * Returns `null` if the segment uses syntax we don't handle.\n *\n * Each segment must yield exactly one token — compound segments\n * (`/files/:n.ext`, `/users-:id`) produce multiple tokens and so\n * trip this check, falling back to the universal bucket.\n */\nfunction tokenizeSegment(segment: string): Token | null {\n if (segment === '') {\n return null;\n }\n\n if (segment === '*') {\n return { kind: 'splat', name: '*' };\n }\n\n if (segment.charAt(0) === '*') {\n const rest = segment.slice(1);\n if (PARAM_NAME.test(rest)) {\n return { kind: 'splat', name: rest };\n }\n return null;\n }\n\n if (segment.charAt(0) === ':') {\n const optional = segment.charAt(segment.length - 1) === '?';\n const nameRaw = optional ? segment.slice(1, -1) : segment.slice(1);\n if (PARAM_NAME.test(nameRaw)) {\n return {\n kind: 'param',\n name: nameRaw,\n optional,\n };\n }\n return null;\n }\n\n // Plain static segment — only allow URL-safe characters. A\n // segment with a `:` mid-string (compound) trips here too.\n if (/^[a-zA-Z0-9_\\-.~%]+$/.test(segment)) {\n return { kind: 'literal', value: segment };\n }\n\n return null;\n}\n\n/**\n * Tokenize the full path into a token stream, recognizing slash-\n * spanning optional groups (`/users{/edit/:id}`).\n *\n * The group-open marker is emitted in place of the leading `/`\n * inside `{...}`; group-close before the trailing `}`. The walker\n * later expands by either keeping the run between markers or\n * dropping it.\n */\nfunction tokenizePath(path: string): Token[] | null {\n const trimmed = path.charAt(0) === '/' ? path.slice(1) : path;\n if (trimmed === '') {\n return [];\n }\n\n const tokens: Token[] = [];\n let i = 0;\n const n = trimmed.length;\n\n while (i < n) {\n if (trimmed.charAt(i) === '{') {\n // Find matching `}` (no nesting support — fall back if\n // we see a nested `{` before the close).\n let close = -1;\n for (let j = i + 1; j < n; j++) {\n const c = trimmed.charAt(j);\n if (c === '{') {\n return null;\n }\n if (c === '}') {\n close = j;\n break;\n }\n }\n if (close === -1) {\n return null;\n }\n const inner = trimmed.slice(i + 1, close);\n // Inner must start with `/` so the group is slash-spanning\n // (matches path-to-regexp v8's `{/segment}` shape).\n if (inner.charAt(0) !== '/') {\n return null;\n }\n // What follows the closing `}` must end the segment —\n // either end-of-path, a `/` separator, or another `{`\n // group. Anything else (e.g. `/a{/b}c`) is compound\n // syntax the trie can't represent; fall back to the\n // universal bucket so path-to-regexp can handle it.\n const after = close + 1 < n ? trimmed.charAt(close + 1) : '';\n if (after !== '' && after !== '/' && after !== '{') {\n return null;\n }\n tokens.push({ kind: 'groupOpen' });\n const innerTokens = tokenizePath(inner);\n if (innerTokens === null) {\n return null;\n }\n for (const t of innerTokens) {\n tokens.push(t);\n }\n tokens.push({ kind: 'groupClose' });\n i = close + 1;\n continue;\n }\n\n // Read until next `/` or `{`.\n let segEnd = i;\n while (segEnd < n) {\n const c = trimmed.charAt(segEnd);\n if (c === '/' || c === '{') {\n break;\n }\n segEnd++;\n }\n const segment = trimmed.slice(i, segEnd);\n if (segment !== '') {\n const token = tokenizeSegment(segment);\n if (token === null) {\n return null;\n }\n tokens.push(token);\n }\n i = segEnd;\n if (i < n && trimmed.charAt(i) === '/') {\n i++; // skip the separator\n }\n }\n\n return tokens;\n}\n\n/**\n * Expand the token stream into one or more concrete `Token[]`\n * variants by:\n * 1. Splitting `groupOpen` … `groupClose` runs into a \"with run\"\n * and a \"without run\" choice (one optional group → ×2 variants).\n * 2. Splitting `param.optional = true` into a \"with\" and \"without\"\n * choice (one `:id?` → ×2 variants).\n *\n * Caps at `MAX_VARIANTS` — beyond that, returns `null` so the path\n * falls back to the universal bucket.\n *\n * Returns `Token[][]` (not `Segment[][]`) so the recursive\n * group-expansion can splice inner variants back into the outer\n * token stream without a lossy round-trip through `Segment`.\n * `parsePath` does the final `Token → Segment` projection.\n */\nfunction expand(tokens: Token[]): Token[][] | null {\n let variants: Token[][] = [[]];\n\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i]!;\n\n if (token.kind === 'groupOpen') {\n // Find matching `groupClose`. Nested groups already\n // rejected at tokenize time so this is one level deep.\n let depth = 1;\n let close = -1;\n for (let j = i + 1; j < tokens.length; j++) {\n const t = tokens[j]!;\n if (t.kind === 'groupOpen') depth++;\n else if (t.kind === 'groupClose') {\n depth--;\n if (depth === 0) {\n close = j;\n break;\n }\n }\n }\n if (close === -1) {\n return null;\n }\n const inner = tokens.slice(i + 1, close);\n const expandedInner = expand(inner);\n if (expandedInner === null) {\n return null;\n }\n // Two choices for this run: keep without, or splice in\n // each inner variant. Cap-check before each push so\n // we never exceed `MAX_VARIANTS`.\n const next: Token[][] = [];\n for (const v of variants) {\n if (next.length >= MAX_VARIANTS) {\n return null;\n }\n next.push(v.slice());\n for (const innerVariant of expandedInner) {\n if (next.length >= MAX_VARIANTS) {\n return null;\n }\n next.push(v.concat(innerVariant));\n }\n }\n variants = next;\n i = close;\n continue;\n }\n\n if (token.kind === 'param' && token.optional) {\n const stripped: Token = {\n kind: 'param',\n name: token.name,\n optional: false,\n };\n const next: Token[][] = [];\n for (const v of variants) {\n if (next.length >= MAX_VARIANTS) {\n return null;\n }\n next.push(v.slice());\n if (next.length >= MAX_VARIANTS) {\n return null;\n }\n next.push(v.concat([stripped]));\n }\n variants = next;\n continue;\n }\n\n for (const v of variants) {\n v.push(token);\n }\n }\n\n return variants;\n}\n\nfunction tokenToSegment(t: Token): Segment | null {\n if (t.kind === 'literal') return { kind: 'static', value: t.value };\n if (t.kind === 'param') return { kind: 'param', name: t.name };\n if (t.kind === 'splat') return { kind: 'splat', name: t.name };\n // groupOpen/groupClose should be consumed by `expand`; if any\n // leak through, the path is malformed.\n return null;\n}\n\n/**\n * Stable, structural identity for a variant — used to drop duplicate\n * expansions like `/users{/:id?}` (which produces the bare-`/users`\n * variant twice: once from the \"without group\" branch and once from\n * the \"with group, without optional param\" branch).\n */\nfunction variantKey(segs: Segment[]): string {\n let out = '';\n for (const s of segs) {\n if (s.kind === 'static') out += `/s:${s.value}`;\n else if (s.kind === 'param') out += `/p:${s.name}`;\n else out += `/*:${s.name}`;\n }\n return out;\n}\n\nexport function parsePath(path: string): Segment[][] | null {\n const tokens = tokenizePath(path);\n if (tokens === null) {\n return null;\n }\n const variants = expand(tokens);\n if (variants === null) {\n return null;\n }\n\n const result: Segment[][] = [];\n const seen = new Set<string>();\n\n for (const v of variants) {\n const segs: Segment[] = [];\n for (const t of v) {\n const s = tokenToSegment(t);\n if (s === null) {\n return null;\n }\n segs.push(s);\n }\n\n // Splat must be the terminal segment in any variant —\n // otherwise the trie's `insertIntoTrie` would silently drop\n // every segment after the splat (T3 dropped the\n // `matcher.exec` confirm pass that previously caught this).\n // Fall back to the universal bucket so path-to-regexp can\n // handle the route honestly.\n for (let i = 0; i < segs.length - 1; i++) {\n if (segs[i]!.kind === 'splat') {\n return null;\n }\n }\n\n const key = variantKey(segs);\n if (seen.has(key)) {\n continue;\n }\n seen.add(key);\n result.push(segs);\n }\n return result;\n}\n","import type { ObjectLiteral } from '../../types.ts';\nimport type { MethodBuckets, TrieNode } from './types.ts';\n\nexport function createMethodBuckets<T extends ObjectLiteral = ObjectLiteral>(): MethodBuckets<T> {\n return Object.create(null) as MethodBuckets<T>;\n}\n\nexport function createTrieNode<T extends ObjectLiteral = ObjectLiteral>(): TrieNode<T> {\n return {\n staticChildren: new Map(),\n splatRoutes: createMethodBuckets<T>(),\n exactRoutes: createMethodBuckets<T>(),\n prefixRoutes: [],\n };\n}\n","import { MethodName } from '../../constants.ts';\nimport type { MethodNameLike } from '../../constants.ts';\nimport type { ICache } from '../../cache/index.ts';\nimport type { ObjectLiteral, Route, RouteMatch } from '../../types.ts';\nimport type { BaseRouterOptions, IRouter } from '../types.ts';\nimport { buildRoutePathMatcher } from '../utils.ts';\nimport type {\n IndexedRoute,\n MethodBuckets,\n ParamCapture,\n Segment,\n TrieNode,\n} from './types.ts';\nimport { parsePath } from './parser.ts';\n\nimport { createTrieNode } from './node.ts';\n\nfunction decodeOrRaw(s: string): string {\n try {\n return decodeURIComponent(s);\n } catch {\n return s;\n }\n}\n\n/**\n * Build a `params` object from a request's pre-split segments using\n * the variant's pre-computed `ParamCapture[]`. No regex execution —\n * each capture is one indexed read from `segments` (and a join for\n * splats). Replaces the `matcher.exec` confirm pass for trie-walked\n * routes (T3).\n */\nfunction extractTrieParams(\n segments: string[],\n indexMap: ParamCapture[],\n): Record<string, string | undefined> {\n const out = Object.create(null) as Record<string, string | undefined>;\n for (const cap of indexMap) {\n if (cap.kind === 'segment') {\n out[cap.name] = decodeOrRaw(segments[cap.depth]!);\n } else {\n // Splat: capture every remaining segment, joined with '/'.\n const slice = segments.slice(cap.depth).join('/');\n out[cap.name] = decodeOrRaw(slice);\n }\n }\n return out;\n}\n\n/**\n * Compute `match.path` (the matched-prefix string) from the request's\n * segments and the variant's recorded depth.\n *\n * - Non-splat variants: prefix = `segments[0..matchDepth].join('/')` —\n * exactly what the variant consumed (request length = variant\n * length for exact, request length ≥ variant length for prefix).\n * - Splat variants: the splat absorbed every remaining segment, so\n * the matched prefix is the entire request path. This mirrors what\n * `path-to-regexp`'s `output.path` would have returned pre-Phase-2\n * for `/files/*rest` matching `/files/a/b` (`/files/a/b`, not\n * `/files`).\n */\nfunction trieMatchedPath(\n segments: string[],\n matchDepth: number,\n splatTerminated: boolean,\n): string {\n const upTo = splatTerminated ? segments.length : matchDepth;\n if (upTo === 0) {\n return '/';\n }\n return `/${segments.slice(0, upTo).join('/')}`;\n}\n\n/**\n * Pre-compute the `ParamCapture[]` for a variant's segments. Walk\n * the segments in order; emit one entry per `param` segment and a\n * terminal one for `splat` (always last). Static segments are\n * structurally consumed by the trie walk; they don't appear here.\n */\nfunction buildParamsIndexMap(segments: Segment[]): ParamCapture[] {\n const out: ParamCapture[] = [];\n for (const [i, seg] of segments.entries()) {\n if (seg.kind === 'param') {\n out.push({\n kind: 'segment',\n depth: i,\n name: seg.name,\n });\n } else if (seg.kind === 'splat') {\n out.push({\n kind: 'splat',\n depth: i,\n name: seg.name,\n });\n // Splats are always last in a variant — the trie parser\n // emits at most one per variant.\n break;\n }\n }\n return out;\n}\n\n/**\n * Decide which method buckets a given request method should pull\n * from. Always includes `''` (method-agnostic). For HEAD also\n * includes GET (per `matchHandlerMethod`). For OPTIONS or no-method\n * lookups, returns `null` to signal \"emit every bucket\" — needed so\n * `event.methodsAllowed` is populated for OPTIONS auto-Allow and so\n * `IRouter.lookup(path)` (no method) keeps returning a complete\n * candidate set.\n */\nfunction methodBucketKeys(method: MethodNameLike | undefined): readonly string[] | null {\n if (typeof method === 'undefined' || method === MethodName.OPTIONS) {\n return null;\n }\n if (method === MethodName.HEAD) {\n return ['', MethodName.HEAD, MethodName.GET];\n }\n return ['', method];\n}\n\nfunction emitBucket<T extends ObjectLiteral>(\n buckets: MethodBuckets<T>,\n method: MethodNameLike | undefined,\n out: IndexedRoute<T>[],\n): void {\n const keys = methodBucketKeys(method);\n if (keys === null) {\n for (const k in buckets) {\n const list = buckets[k]!;\n for (const r of list) out.push(r);\n }\n return;\n }\n for (const k of keys) {\n const list = buckets[k];\n if (!list) continue;\n for (const r of list) out.push(r);\n }\n}\n\nfunction hasAnyBucket<T extends ObjectLiteral>(buckets: MethodBuckets<T>): boolean {\n // eslint-disable-next-line no-unreachable-loop\n for (const _k in buckets) {\n return true;\n }\n return false;\n}\n\nfunction pushIntoBucket<T extends ObjectLiteral>(\n buckets: MethodBuckets<T>,\n methodKey: string,\n route: IndexedRoute<T>,\n): void {\n const bucket = buckets[methodKey];\n if (bucket) {\n bucket.push(route);\n } else {\n buckets[methodKey] = [route];\n }\n}\n\n/**\n * Radix-trie router — registers routes into a per-segment tree at\n * `add()` time and walks the tree at `lookup()` to collect\n * candidates by structure rather than by linear scan.\n *\n * Inspired by Hono's `TrieRouter` and rou3. The trie handles\n * routup's path vocabulary directly via its own parser\n * (`./parser.ts`):\n *\n * - Static segments (`/users`)\n * - Named params (`:id`)\n * - Optional params (`:id?`) — expanded to two route variants at\n * registration (T2)\n * - Optional groups (`/users{/edit}`) — same expansion strategy\n * - Bare and named splats (`/files/*`, `/files/*rest`)\n *\n * Per-leaf storage is bucketed by HTTP method (T4) so lookup\n * narrows to the request method's bucket(s) instead of emitting\n * every entry at the leaf and letting the dispatcher's filter\n * discard mismatches.\n *\n * Param extraction is `paramsIndexMap`-driven (T3): a pre-built\n * `Array<{ depth, name }>` per variant lets `extractTrieParams`\n * read params straight from the request's pre-split segments — no\n * regex execution per match.\n *\n * Paths the trie parser doesn't handle (compound segments like\n * `/files/:n.ext`, escape sequences `\\:`, regex constraints) and\n * empty/root paths fall through to the `universal` bucket. That\n * bucket still uses `path-to-regexp` via `buildRoutePathMatcher`,\n * so correctness is preserved.\n *\n * Pure-static-spine fast path (`shortCircuit`): when the request\n * walks a static spine with no param/splat/prefix siblings on any\n * traversed node, the leaf's `exactRoutes` (filtered to the request\n * method's buckets) is the full answer — no need to walk the param\n * branch or collect prefix candidates at intermediate nodes.\n */\nexport class TrieRouter<T extends ObjectLiteral = ObjectLiteral> implements IRouter<T> {\n /**\n * Monotonic counter assigned as the registration `index` on each\n * route — the dispatch loop uses it to preserve registration\n * order across the candidate list. App owns the canonical\n * `Route<T>[]` list (Plan 019); the trie no longer keeps a\n * parallel copy.\n */\n protected _routeCount: number;\n\n protected root: TrieNode<T>;\n\n /**\n * Routes that bypass the trie — registered with no path, with\n * the root path `/`, or with a path containing syntax the\n * parser doesn't recognise. Walked linearly on every lookup,\n * merged into the result in registration order.\n */\n protected universal: IndexedRoute<T>[];\n\n protected cache?: ICache<readonly RouteMatch<T>[]>;\n\n constructor(options: BaseRouterOptions<T> = {}) {\n this._routeCount = 0;\n this.root = createTrieNode<T>();\n this.universal = [];\n this.cache = options.cache;\n }\n\n add(route: Route<T>): void {\n const index = this._routeCount++;\n\n // Empty/root paths bypass the trie. We still build a matcher\n // — `buildRoutePathMatcher` returns one only for the cases\n // that actually need confirmation:\n // - `app.get('/', h)` (exact match) → matcher rejects\n // non-`/` requests so the route doesn't promiscuously\n // match every path.\n // - `app.use('/', mw)` / `app.use(mw)` (prefix or no path)\n // → returns `undefined`; the lookup loop treats the\n // route as \"matches every request\" via the no-matcher\n // branch, which is exactly what middleware wants.\n if (typeof route.path !== 'string' || route.path === '' || route.path === '/') {\n this.universal.push({\n route,\n index,\n matcher: buildRoutePathMatcher(route),\n });\n this.cache?.clear();\n return;\n }\n\n const variants = parsePath(route.path);\n if (variants === null) {\n // Trie parser doesn't handle this syntax (compound\n // segments like `/files/:n.ext`, escape sequences,\n // splat-not-last, …). Fall back to path-to-regexp.\n this.universal.push({\n route,\n index,\n matcher: buildRoutePathMatcher(route),\n });\n this.cache?.clear();\n return;\n }\n\n // Each variant becomes an `IndexedRoute` sharing the same\n // registration `index` so the candidate dedupe keeps them\n // collapsed to one match per request.\n for (const segments of variants) {\n this.insertIntoTrie(segments, route, index);\n }\n this.cache?.clear();\n }\n\n lookup(path: string, method?: MethodNameLike): readonly RouteMatch<T>[] {\n // Cache key includes the method bucket — different methods at\n // the same path now resolve to different candidate sets, so\n // sharing a cache entry across methods would leak matches.\n const cacheKey = `${method ?? ''}\\t${path}`;\n const cached = this.cache?.get(cacheKey);\n if (typeof cached !== 'undefined') {\n return cached;\n }\n\n const candidates: IndexedRoute<T>[] = [];\n\n for (const u of this.universal) {\n candidates.push(u);\n }\n\n const segments = this.parseRequestPath(path);\n const shortCircuit = this.shortCircuit(segments, method);\n if (shortCircuit !== null) {\n for (const c of shortCircuit) {\n candidates.push(c);\n }\n } else {\n this.walk(this.root, segments, 0, candidates, method);\n }\n\n // Sort primarily by registration `index` (preserves dispatch\n // order across the candidate list). When multiple variants\n // of one route match the same request — e.g. a prefix\n // `use('/api/:version?', child)` whose `/api` and\n // `/api/:version` variants both fire for `/api/v1/...` —\n // we pick the *most specific* one (greatest `matchDepth`),\n // so the more-derived variant's `params` and `match.path`\n // win over the bare-prefix variant. Universal-bucket\n // candidates have no `matchDepth`; treat as -1 so a trie\n // variant of the same route wins (in practice they don't\n // overlap — a route is in either bucket).\n candidates.sort((a, b) => {\n if (a.index !== b.index) return a.index - b.index;\n const ad = a.matchDepth ?? -1;\n const bd = b.matchDepth ?? -1;\n return bd - ad;\n });\n\n const matches: RouteMatch<T>[] = [];\n let lastIndex = -1; // dedupe — multiple variants of one route share `index`\n for (const candidate of candidates) {\n const {\n route,\n index,\n matcher,\n paramsIndexMap,\n matchDepth,\n } = candidate;\n\n if (index === lastIndex) {\n continue;\n }\n\n if (matcher) {\n // Universal-bucket route: still uses path-to-regexp.\n const output = matcher.exec(path);\n if (typeof output === 'undefined') {\n continue;\n }\n matches.push({\n route,\n index,\n params: this.assignParams(output.params),\n path: output.path,\n });\n lastIndex = index;\n continue;\n }\n\n if (paramsIndexMap && typeof matchDepth === 'number') {\n // Trie-walked route: extract params from the request\n // segments using the pre-built index map. No regex.\n matches.push({\n route,\n index,\n params: extractTrieParams(segments, paramsIndexMap),\n path: trieMatchedPath(segments, matchDepth, candidate.splatTerminated === true),\n });\n lastIndex = index;\n continue;\n }\n\n // Universal-bucket route with no matcher (empty / root path).\n matches.push({\n route,\n index,\n params: Object.create(null) as Record<string, string | undefined>,\n });\n lastIndex = index;\n }\n\n this.cache?.set(cacheKey, matches);\n return matches;\n }\n\n /**\n * T1: returns the pre-computed candidate list when the request's\n * static spine has no param sibling, no prefix routes, and no\n * splats along the way. The leaf node's `exactRoutes` (filtered\n * to the request method's buckets) is then the complete answer —\n * no need to walk the param branch or collect prefix/splat\n * candidates from intermediate nodes. When any branch is\n * encountered, returns `null` and the caller falls through to\n * the regular `walk`.\n */\n protected shortCircuit(segments: string[], method: MethodNameLike | undefined): IndexedRoute<T>[] | null {\n let node = this.root;\n\n for (const segment of segments) {\n // Any branch at this node disqualifies the fast path: a\n // param-child might match the current segment, a splat\n // would fire, and prefix routes would belong in the\n // result. All of these need the full walk.\n if (node.paramChild || hasAnyBucket(node.splatRoutes) || node.prefixRoutes.length > 0) {\n return null;\n }\n\n const child = node.staticChildren.get(segment!);\n if (!child) {\n return null;\n }\n node = child;\n }\n\n if (node.paramChild || hasAnyBucket(node.splatRoutes) || node.prefixRoutes.length > 0) {\n return null;\n }\n\n // Pure static spine reached the leaf — `exactRoutes` (for the\n // request method's relevant buckets) is the complete answer.\n const out: IndexedRoute<T>[] = [];\n emitBucket(node.exactRoutes, method, out);\n return out;\n }\n\n protected parseRequestPath(path: string): string[] {\n const trimmed = path.charAt(0) === '/' ? path.slice(1) : path;\n if (trimmed === '') {\n return [];\n }\n const parts = trimmed.split('/');\n const result: string[] = [];\n for (const part of parts) {\n if (part !== '') {\n result.push(part);\n }\n }\n return result;\n }\n\n protected insertIntoTrie(segments: Segment[], route: Route<T>, index: number): void {\n let node = this.root;\n const exact = this.isExactMatchRoute(route);\n const methodKey = route.method ?? '';\n const paramsIndexMap = buildParamsIndexMap(segments);\n\n for (const [i, segment] of segments.entries()) {\n const seg = segment!;\n\n if (seg.kind === 'splat') {\n // Splat consumes the rest of the request path. The\n // splat segment itself doesn't create a trie child\n // node — it lives on the *current* node. So\n // `matchDepth` is the number of segments matched\n // before the splat (== current trie depth == `i`,\n // the splat's index in the variant).\n pushIntoBucket(node.splatRoutes, methodKey, {\n route,\n index,\n paramsIndexMap,\n matchDepth: i,\n splatTerminated: true,\n });\n return;\n }\n\n if (seg.kind === 'param') {\n if (!node.paramChild) {\n node.paramChild = createTrieNode();\n }\n node = node.paramChild;\n continue;\n }\n\n let child = node.staticChildren.get(seg.value);\n if (!child) {\n child = createTrieNode();\n node.staticChildren.set(seg.value, child);\n }\n node = child;\n }\n\n const indexed: IndexedRoute<T> = {\n route,\n index,\n paramsIndexMap,\n matchDepth: segments.length,\n };\n\n if (exact) {\n pushIntoBucket(node.exactRoutes, methodKey, indexed);\n } else {\n // Prefix routes (middleware / mounted apps) stay flat —\n // they're method-agnostic by design.\n node.prefixRoutes.push(indexed);\n }\n }\n\n protected walk(\n node: TrieNode<T>,\n segments: string[],\n depth: number,\n collected: IndexedRoute<T>[],\n method: MethodNameLike | undefined,\n ): void {\n // Splats at this depth match any request path that reaches here.\n emitBucket(node.splatRoutes, method, collected);\n\n if (depth === segments.length) {\n // Request path is fully consumed at this node: collect\n // both exact-match and prefix-match routes that ended here.\n emitBucket(node.exactRoutes, method, collected);\n for (const p of node.prefixRoutes) {\n collected.push(p);\n }\n return;\n }\n\n // Going deeper — prefix routes at this node match any\n // continuation (middleware / nested apps).\n for (const p of node.prefixRoutes) {\n collected.push(p);\n }\n\n const seg = segments[depth]!;\n\n const staticChild = node.staticChildren.get(seg);\n if (staticChild) {\n this.walk(staticChild, segments, depth + 1, collected, method);\n }\n\n if (node.paramChild) {\n this.walk(node.paramChild, segments, depth + 1, collected, method);\n }\n }\n\n protected isExactMatchRoute(route: Route<T>): boolean {\n return typeof route.method !== 'undefined';\n }\n\n /**\n * T5: copy params onto a prototype-less object so downstream\n * lookups skip prototype-chain traversal and avoid `__proto__` /\n * `hasOwnProperty` shadowing from user-controlled segment values.\n */\n protected assignParams(\n source: Record<string, string | undefined>,\n ): Record<string, string | undefined> {\n const out = Object.create(null) as Record<string, string | undefined>;\n for (const k in source) {\n if (Object.prototype.hasOwnProperty.call(source, k)) {\n out[k] = source[k];\n }\n }\n return out;\n }\n}\n","import type { ICache } from '../../cache/index.ts';\nimport type { ObjectLiteral, Route, RouteMatch } from '../../types.ts';\nimport { LinearRouter } from '../linear/index.ts';\nimport { TrieRouter } from '../trie/index.ts';\nimport type { BaseRouterOptions, IRouter } from '../types.ts';\n\n/**\n * Default crossover. Empirically `LinearRouter` wins for small route\n * counts (no per-request trie walk overhead, no static-spine setup);\n * `TrieRouter` wins past ~30 entries on typical workloads. Override\n * via `SmartRouterOptions.threshold` when a benchmark says otherwise\n * for your route shape.\n */\nconst DEFAULT_THRESHOLD = 30;\n\nexport type SmartRouterOptions<T extends ObjectLiteral = ObjectLiteral> = BaseRouterOptions<T> & {\n /**\n * Route count at or above which `SmartRouter` switches from\n * `LinearRouter` (faster at small N) to `TrieRouter` (faster\n * at large N). Default `30`.\n */\n threshold?: number;\n};\n\n/**\n * Auto-selecting router. Accumulates registered routes in a pending\n * buffer; on the first `lookup()` call, picks `LinearRouter` or\n * `TrieRouter` based on the registered route count and replays the\n * pending list onto the chosen inner router. Every subsequent call\n * — `add`, `lookup` — forwards to the inner.\n *\n * Use this when you don't want to commit to a router family up-front\n * (e.g. a library that registers a variable number of routes\n * depending on configuration). For known workloads, prefer the\n * concrete router — `SmartRouter` adds one indirection per call.\n *\n * Inspired by Hono's `SmartRouter` (which auto-selects across more\n * candidates including `RegExpRouter`); ours covers the only choice\n * that matters in routup today: linear-vs-trie at the registration-\n * size crossover.\n */\nexport class SmartRouter<T extends ObjectLiteral = ObjectLiteral> implements IRouter<T> {\n protected inner?: IRouter<T>;\n\n protected pending: Route<T>[] = [];\n\n protected readonly threshold: number;\n\n /**\n * Cache handed off to whichever inner router gets chosen. Stays\n * `undefined` if the user didn't configure one.\n */\n protected readonly cache?: ICache<readonly RouteMatch<T>[]>;\n\n constructor(options: SmartRouterOptions<T> = {}) {\n this.threshold = options.threshold ?? DEFAULT_THRESHOLD;\n this.cache = options.cache;\n }\n\n add(route: Route<T>): void {\n if (this.inner) {\n this.inner.add(route);\n return;\n }\n this.pending.push(route);\n }\n\n lookup(path: string, method?: string): readonly RouteMatch<T>[] {\n if (!this.inner) {\n this.inner = this.choose();\n for (const r of this.pending) {\n this.inner.add(r);\n }\n this.pending = [];\n }\n return this.inner.lookup(path, method);\n }\n\n /**\n * Pick the inner router based on the registered route count.\n * `LinearRouter` for tiny tables, `TrieRouter` past the\n * configured threshold.\n *\n * @protected\n */\n protected choose(): IRouter<T> {\n if (this.pending.length < this.threshold) {\n return new LinearRouter<T>({ cache: this.cache });\n }\n return new TrieRouter<T>({ cache: this.cache });\n }\n}\n","import {\n type EtagFn,\n type TrustProxyFn,\n buildEtagFn,\n buildTrustProxyFn,\n} from '../utils/index.ts';\nimport type { AppOptions, AppOptionsInput } from './types.ts';\n\nexport function normalizeAppOptions(input: AppOptionsInput): AppOptions {\n let etag : EtagFn | null | undefined;\n if (typeof input.etag !== 'undefined') {\n // Keep `false` (and `null` from already-normalized options\n // being re-spread) as the literal `null` sentinel so\n // toResponse() can synchronously skip the ETag path. A truthy\n // no-op fn (the previous behavior) forced an `await\n // applyEtag(...)` microtask hop on every request.\n if (input.etag === null || input.etag === false) {\n etag = null;\n } else {\n etag = buildEtagFn(input.etag);\n }\n }\n\n let trustProxy : TrustProxyFn | undefined;\n if (typeof input.trustProxy !== 'undefined') {\n trustProxy = buildTrustProxyFn(input.trustProxy);\n }\n\n if (typeof input.timeout !== 'undefined') {\n if (\n !Number.isFinite(input.timeout) ||\n input.timeout <= 0\n ) {\n delete input.timeout;\n }\n }\n\n if (typeof input.handlerTimeout !== 'undefined') {\n if (\n !Number.isFinite(input.handlerTimeout) ||\n input.handlerTimeout <= 0\n ) {\n delete input.handlerTimeout;\n }\n }\n\n return {\n ...input,\n etag,\n trustProxy,\n };\n}\n","export const AppSymbol = Symbol.for('App');\n","import { hasInstanceof } from '@ebec/core';\nimport { AppSymbol } from './constants.ts';\nimport type { App } from './module.ts';\n\nexport function isAppInstance(input: unknown): input is App {\n return hasInstanceof(input, AppSymbol);\n}\n\n","import { markInstanceof } from '@ebec/core';\nimport { HeaderName, MethodName } from '../constants.ts';\nimport { DispatcherEvent } from '../dispatcher/index.ts';\nimport type { IDispatcherEvent } from '../dispatcher/index.ts';\nimport type { AppRequest } from '../event/index.ts';\nimport { createError } from '../error/index.ts';\nimport {\n Handler,\n type HandlerOptions,\n HandlerType,\n isHandler,\n isHandlerOptions,\n matchHandlerMethod,\n} from '../handler/index.ts';\nimport type { Path } from '../path/index.ts';\nimport { isPath } from '../path/index.ts';\nimport type { Plugin, PluginInstallContext } from '../plugin/index.ts';\nimport {\n PluginAlreadyInstalledError,\n isPlugin,\n} from '../plugin/index.ts';\nimport { normalizeAppOptions } from './options.ts';\nimport {\n acceptsJson,\n joinPaths,\n withLeadingSlash,\n} from '../utils/index.ts';\nimport { AppSymbol } from './constants.ts';\nimport { LinearRouter } from '../router/linear/index.ts';\nimport type { IRouter } from '../router/types.ts';\nimport type {\n AppContext,\n AppOptions,\n IApp,\n} from './types.ts';\nimport { isAppInstance } from './check.ts';\nimport type { Route, RouteMatch } from '../types.ts';\n\n/**\n * Merge resolver-supplied path params into `event.params` *only* when\n * `match.params` actually has keys. Skipping the object spread on the\n * empty-params path (every static route, every middleware match) saves\n * an allocation per match — the hottest path in static-route apps.\n */\nfunction mergeMatchParams(\n event: IDispatcherEvent,\n matchParams: Record<string, string | undefined>,\n): void {\n // Cheap emptiness probe — short-circuits on the first own key.\n let hasKeys = false;\n // eslint-disable-next-line no-unreachable-loop\n for (const _k in matchParams) {\n hasKeys = true;\n break;\n }\n if (!hasKeys) {\n return;\n }\n event.params = {\n ...event.params,\n ...matchParams,\n };\n}\n\nexport class App implements IApp {\n /**\n * A label for the App instance.\n */\n readonly name?: string;\n\n /**\n * Registration-time path prefix for entries registered on this\n * App. Local to this instance — never inherited from a parent.\n *\n * @protected\n */\n protected _path?: Path;\n\n /**\n * Pluggable router (route table) — owns the \"which entries match\n * this path?\" lookup. Defaults to `LinearRouter` (walks entries\n * linearly per request); swap in via `AppContext.router`\n * for a radix/trie implementation on apps with many routes.\n *\n * @protected\n */\n protected router: IRouter<Handler>;\n\n /**\n * Normalized options for this App instance.\n *\n * Frozen on construction — once published to `event.appOptions`\n * it is shared across all requests, and a handler must not be\n * able to mutate router-global state.\n */\n protected _options: Readonly<AppOptions>;\n\n /**\n * Registry of installed plugins (name → version) on this App.\n *\n * Read by `use(otherApp)` (via the public `plugins` getter) so\n * plugin registries merge into the parent at flatten time —\n * `parent.hasPlugin('foo')` then reflects plugins installed on\n * apps mounted into it.\n *\n * @protected\n */\n protected _plugins: Map<string, string | undefined>;\n\n /**\n * Every route registered on this App, in registration order.\n *\n * Read by `use(otherApp)` to snapshot routes at flatten time.\n * Late mutations to `_routes` after a flatten do not propagate.\n */\n protected _routes: Route<Handler>[] = [];\n\n // --------------------------------------------------\n\n constructor(input: AppContext = {}) {\n this.name = input.name;\n this._path = input.path;\n\n this._plugins = new Map<string, string | undefined>();\n this.router = input.router ?? new LinearRouter<Handler>();\n\n this._options = Object.freeze(normalizeAppOptions(input.options ?? {}));\n\n markInstanceof(this, AppSymbol);\n }\n\n // --------------------------------------------------\n\n /**\n * Public read of the canonical route list. Used by `use(child)`\n * to snapshot the child's routes at flatten time. Returned\n * as `readonly` — callers must not mutate.\n */\n get routes(): readonly Route<Handler>[] {\n return this._routes;\n }\n\n /**\n * Public read of the installed-plugin registry. Used by\n * `use(child)` to merge child plugins into the parent at\n * flatten time. Returned as `ReadonlyMap` — callers must not\n * mutate; go through `use(plugin)` to install.\n */\n get plugins(): ReadonlyMap<string, string | undefined> {\n return this._plugins;\n }\n\n /**\n * Register a route with the active router and record it on the\n * App so `setRouter` / `use(child)` can read the canonical list\n * back.\n *\n * @protected\n */\n protected register(route: Route<Handler>): void {\n this.router.add(route);\n this._routes.push(route);\n }\n\n /**\n * Swap the active router. Replays every previously-registered\n * route onto the new router so lookups stay correct.\n *\n * Useful for picking a router after route shape is known (e.g.\n * a SmartRouter-style decision), or for testing alternatives\n * mid-flight without rebuilding the App. Any cache the previous\n * router carried is dropped along with it.\n */\n setRouter(router: IRouter<Handler>): void {\n for (const route of this._routes) {\n router.add(route);\n }\n this.router = router;\n }\n\n // --------------------------------------------------\n\n /**\n * Public entry point — creates a DispatcherEvent from the request,\n * runs the pipeline, and returns a Response (with 404/500 fallbacks).\n */\n async fetch(request: AppRequest): Promise<Response> {\n const event = new DispatcherEvent(request);\n\n let response: Response | undefined;\n\n try {\n const timeoutMs = this._options.timeout;\n\n if (timeoutMs) {\n const controller = new AbortController();\n event.signal = controller.signal;\n\n let timerId: ReturnType<typeof setTimeout> | undefined;\n\n try {\n response = await Promise.race([\n this.dispatch(event),\n new Promise<never>((_, reject) => {\n timerId = setTimeout(() => {\n controller.abort();\n reject(createError({\n status: 408,\n message: 'Request Timeout',\n }));\n }, timeoutMs);\n }),\n ]);\n } finally {\n clearTimeout(timerId);\n }\n } else {\n response = await this.dispatch(event);\n }\n } catch (e) {\n event.error = createError(e);\n }\n\n if (response) {\n return response;\n }\n\n if (event.error) {\n return this.buildFallbackResponse(\n request,\n event,\n event.error.status || 500,\n event.error.message,\n );\n }\n\n return this.buildFallbackResponse(request, event, 404, 'Not Found');\n }\n\n protected buildFallbackResponse(request: AppRequest, event: IDispatcherEvent, status: number, message: string): Response {\n const headers = new Headers(event.response.headers);\n\n if (acceptsJson(request)) {\n headers.set('content-type', 'application/json; charset=utf-8');\n return new Response(JSON.stringify({ status, message }), {\n status,\n headers,\n });\n }\n\n headers.set('content-type', 'text/plain; charset=utf-8');\n return new Response(message, {\n status,\n headers,\n });\n }\n\n // --------------------------------------------------\n\n async dispatch(\n event: IDispatcherEvent,\n ): Promise<Response | undefined> {\n const savedPath = event.path;\n const savedMountPath = event.mountPath;\n const savedParams = event.params;\n const savedAppOptions = event.appOptions;\n const wasDispatching = event.isDispatching;\n\n const isRoot = !wasDispatching;\n\n event.appOptions = this._options;\n event.isDispatching = true;\n\n let response: Response | undefined;\n\n try {\n const matches = this.router.lookup(event.path, event.method);\n response = await this.runMatches(event, matches, event.path, 0);\n\n // OPTIONS auto-Allow synthesis — runs only on the root and\n // only when no handler produced a response or an error.\n if (\n !event.error &&\n !event.dispatched &&\n isRoot &&\n event.method === MethodName.OPTIONS\n ) {\n if (event.methodsAllowed.has(MethodName.GET)) {\n event.methodsAllowed.add(MethodName.HEAD);\n }\n\n const options = [...event.methodsAllowed]\n .map((key) => key.toUpperCase())\n .join(',');\n\n const optionsHeaders = new Headers(event.response.headers);\n optionsHeaders.set(HeaderName.ALLOW, options);\n response = new Response(options, {\n status: event.response.status || 200,\n headers: optionsHeaders,\n });\n\n event.dispatched = true;\n }\n } finally {\n event.appOptions = savedAppOptions;\n event.isDispatching = wasDispatching;\n\n // Restore routing state when this App did not produce a\n // response, so a re-entrant dispatch caller (anyone\n // invoking another App's `dispatch` on the same event\n // afterwards) sees its own pre-dispatch state.\n if (!event.dispatched) {\n event.path = savedPath;\n event.mountPath = savedMountPath;\n event.params = savedParams;\n }\n }\n\n return response;\n }\n\n /**\n * Walk the matched routes for the current event, dispatching each\n * handler in order. Re-entered (recursively) from the `setNext`\n * continuation so `event.next()` resumes from the next match.\n */\n protected async runMatches(\n event: IDispatcherEvent,\n matches: readonly RouteMatch<Handler>[],\n matchesPath: string,\n startIndex: number,\n ): Promise<Response | undefined> {\n let i = startIndex;\n let response: Response | undefined;\n\n while (!event.dispatched && i < matches.length) {\n const match = matches[i]!;\n const handler = match.route.data;\n\n // Skip handlers that don't fit the current error state:\n // CORE handlers only run when no error is pending;\n // ERROR handlers only run when one is.\n if (\n (event.error && handler.type === HandlerType.CORE) ||\n (!event.error && handler.type === HandlerType.ERROR)\n ) {\n i++;\n continue;\n }\n\n const { method } = match.route;\n\n if (method) {\n event.methodsAllowed.add(method);\n }\n\n if (!matchHandlerMethod(method, event.method as MethodName)) {\n i++;\n continue;\n }\n\n mergeMatchParams(event, match.params);\n\n // Surface the matched prefix as `event.mountPath` for the\n // duration of this handler so static-asset / mount-aware\n // helpers can strip it off `event.path`. Save and restore\n // around the dispatch so siblings see their own prefixes.\n const savedMountPath = event.mountPath;\n if (typeof match.path === 'string') {\n event.mountPath = match.path;\n }\n\n const capturedMatches = matches;\n const capturedMatchesPath = matchesPath;\n const nextIndex = i + 1;\n\n event.setNext(async (error?: Error) => {\n if (error) {\n event.error = createError(error);\n }\n\n // If the handler mutated `event.path` before calling\n // next(), the captured matches are stale — refresh on\n // the new path. Otherwise resume from the next match.\n const pathChanged = event.path !== capturedMatchesPath;\n const nextMatches = pathChanged ?\n this.router.lookup(event.path, event.method) :\n capturedMatches;\n const nextMatchesPath = pathChanged ? event.path : capturedMatchesPath;\n const nextStart = pathChanged ? 0 : nextIndex;\n\n return this.runMatches(event, nextMatches, nextMatchesPath, nextStart);\n });\n\n try {\n const dispatchResponse = await handler.dispatch(event);\n\n if (dispatchResponse) {\n response = dispatchResponse;\n event.dispatched = true;\n }\n } catch (e) {\n event.error = createError(e);\n // Fall through to the next match — could be an error\n // handler registered later in the chain.\n } finally {\n event.mountPath = savedMountPath;\n }\n\n i++;\n }\n\n return response;\n }\n\n // --------------------------------------------------\n\n delete(...handlers: (Handler | HandlerOptions)[]): this;\n\n delete(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;\n\n delete(...input: (Path | Handler | HandlerOptions)[]): this {\n this.useForMethod(MethodName.DELETE, ...input);\n\n return this;\n }\n\n get(...handlers: (Handler | HandlerOptions)[]): this;\n\n get(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;\n\n get(...input: (Path | Handler | HandlerOptions)[]): this {\n this.useForMethod(MethodName.GET, ...input);\n\n return this;\n }\n\n post(...handlers: (Handler | HandlerOptions)[]): this;\n\n post(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;\n\n post(...input: (Path | Handler | HandlerOptions)[]): this {\n this.useForMethod(MethodName.POST, ...input);\n\n return this;\n }\n\n put(...handlers: (Handler | HandlerOptions)[]): this;\n\n put(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;\n\n put(...input: (Path | Handler | HandlerOptions)[]): this {\n this.useForMethod(MethodName.PUT, ...input);\n\n return this;\n }\n\n patch(...handlers: (Handler | HandlerOptions)[]): this;\n\n patch(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;\n\n patch(...input: (Path | Handler | HandlerOptions)[]): this {\n this.useForMethod(MethodName.PATCH, ...input);\n\n return this;\n }\n\n head(...handlers: (Handler | HandlerOptions)[]): this;\n\n head(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;\n\n head(...input: (Path | Handler | HandlerOptions)[]): this {\n this.useForMethod(MethodName.HEAD, ...input);\n\n return this;\n }\n\n options(...handlers: (Handler | HandlerOptions)[]): this;\n\n options(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;\n\n options(...input: (Path | Handler | HandlerOptions)[]): this {\n this.useForMethod(MethodName.OPTIONS, ...input);\n\n return this;\n }\n\n // --------------------------------------------------\n\n protected useForMethod(\n method: MethodName,\n ...input: (Path | Handler | HandlerOptions)[]\n ) {\n let path: Path | undefined;\n\n for (const element of input) {\n if (isPath(element)) {\n path = element;\n continue;\n }\n\n let handler: Handler;\n // Check isHandler (instanceof brand) BEFORE isHandlerOptions\n // (structural). Handler exposes `fn` and `type` as fields and\n // would otherwise match the structural check and get wrapped\n // into a fresh Handler with an empty config.\n if (isHandler(element)) {\n handler = element;\n } else if (isHandlerOptions(element)) {\n // Construct a fresh Handler from a copy of the options so the\n // user's options object is never mutated.\n handler = new Handler({\n ...element,\n method,\n });\n } else {\n continue;\n }\n\n this.register({\n path: joinPaths(this._path, path, handler.path),\n method,\n data: handler,\n });\n }\n }\n\n // --------------------------------------------------\n\n use(app: IApp): this;\n\n use(handler: Handler | HandlerOptions): this;\n\n use(plugin: Plugin): this;\n\n use(path: Path, app: IApp): this;\n\n use(path: Path, handler: Handler | HandlerOptions): this;\n\n use(path: Path, plugin: Plugin): this;\n\n use(...input: unknown[]): this {\n let path: Path | undefined;\n for (const item of input) {\n if (isPath(item)) {\n path = withLeadingSlash(item);\n continue;\n }\n\n if (isAppInstance(item)) {\n this.flatten(item, path);\n continue;\n }\n\n // Check isHandler (instanceof brand) BEFORE isHandlerOptions\n // (structural) — see useForMethod for the same reasoning.\n if (isHandler(item)) {\n this.register({\n path: joinPaths(this._path, path, item.path),\n method: item.method,\n data: item,\n });\n continue;\n }\n\n if (isHandlerOptions(item)) {\n const handler = new Handler({ ...item });\n\n this.register({\n path: joinPaths(this._path, path, handler.path),\n method: handler.method,\n data: handler,\n });\n continue;\n }\n\n if (isPlugin(item)) {\n if (path) {\n this.install(item, { path });\n } else {\n this.install(item);\n }\n }\n }\n\n return this;\n }\n\n /**\n * Snapshot a child App's routes and plugin registry into this\n * one. Each route's path is prefixed with `this._path`, the\n * supplied mount `path`, and the route's own path (in that\n * order); the resulting entry is registered on this App's\n * router. The child app is not retained — late mutations on it\n * after this call do not propagate.\n *\n * @protected\n */\n protected flatten(child: App, path: Path | undefined): void {\n // Validate plugin conflicts up front so we never half-merge\n // — first-conflict-wins would leave `this._plugins` with a\n // partial view of the child's registry.\n for (const name of child.plugins.keys()) {\n if (this._plugins.has(name)) {\n throw new PluginAlreadyInstalledError(name);\n }\n }\n\n for (const [name, version] of child.plugins) {\n this._plugins.set(name, version);\n }\n\n // Snapshot routes. The router's `add()` is responsible for\n // any cache invalidation it carries.\n for (const route of child.routes) {\n this.register({\n path: joinPaths(this._path, path, route.path),\n method: route.method,\n data: route.data,\n });\n }\n }\n\n // --------------------------------------------------\n\n /**\n * Check if a plugin with the given name is installed on this App.\n */\n hasPlugin(name: string): boolean {\n return this._plugins.has(name);\n }\n\n /**\n * Get the version of an installed plugin by name, or `undefined`\n * if the plugin is not installed.\n */\n getPluginVersion(name: string): string | undefined {\n return this._plugins.get(name);\n }\n\n // --------------------------------------------------\n\n protected install(\n plugin: Plugin,\n context: PluginInstallContext = {},\n ): this {\n if (this._plugins.has(plugin.name)) {\n throw new PluginAlreadyInstalledError(plugin.name);\n }\n\n // Give the plugin its own App to install into so it can\n // freely call `app.use(...)` / `app.get(...)` etc. without\n // having to know whether the caller passed a path. We then\n // mount this scratch app, which flattens its routes onto\n // `this` and discards it.\n const scratch = new App({ name: plugin.name });\n plugin.install(scratch);\n\n if (context.path) {\n this.use(context.path, scratch);\n } else {\n this.use(scratch);\n }\n\n this._plugins.set(plugin.name, plugin.version);\n\n return this;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "routup",
3
- "version": "6.0.0-beta.0",
3
+ "version": "6.0.0-beta.2",
4
4
  "type": "module",
5
5
  "description": "Routup is a minimalistic http based routing framework.",
6
6
  "exports": {