import { A as __toESM, C as httpResponseSerializer, D as __commonJSMin, E as debug_default, O as __exportAll, S as httpRequest, _ as RouteResource, b as httpExceptionHandler, c as mime$1, d as serializeCookie, g as RouteGroup, h as trustProxy, i as getPreviousUrl, k as __require, l as parseRoute, m as toRoutesJSON, n as createSignedURL, p as safeDecodeURI, r as encodeUrl, v as BriskRoute, x as httpMiddleware, y as Route } from "./helpers-34vHGLnE.js";
import { n as findRoute, t as createURL } from "./helpers-BiaeWsBP.js";
import { createUrlBuilder } from "./src/client/url_builder.js";
import { parse, stringify } from "@poppinss/qs";
import { Exception, RuntimeException, createError } from "@poppinss/utils/exception";
import { inspect } from "node:util";
import { parse as parse$1 } from "cookie-es";
import matchit from "@poppinss/matchit";
import string from "@poppinss/utils/string";
import { moduleCaller, moduleImporter } from "@adonisjs/fold";
import Macroable from "@poppinss/macroable";
import is from "@sindresorhus/is";
import Middleware from "@poppinss/middleware";
import onFinished from "on-finished";
import fresh from "fresh";
import typeIs from "type-is";
import { isIP } from "node:net";
import proxyaddr from "proxy-addr";
import { MessageBuilder, safeEqual } from "@poppinss/utils";
import lodash from "@poppinss/utils/lodash";
import base64 from "@poppinss/utils/base64";
import etag from "etag";
import vary from "vary";
import destroy from "destroy";
import { extname } from "node:path";
import { Buffer } from "node:buffer";
import { stat } from "node:fs/promises";
import { createReadStream } from "node:fs";
import contentDisposition from "content-disposition";
import { Readable } from "node:stream";
import { AsyncLocalStorage } from "node:async_hooks";
import { safeStringify } from "@poppinss/utils/json";
//#region src/qs.ts
/**
* Query string parser that provides methods to parse and stringify query strings.
*
* This class wraps the popular 'qs' package with configurable options for parsing
* and stringifying query parameters. It allows customization of array handling,
* depth limits, and encoding behavior.
*
* @example
* ```ts
* const qs = new Qs({
*   parse: { depth: 5, arrayLimit: 20 },
*   stringify: { encode: false, skipNulls: true }
* })
*
* const parsed = qs.parse('users[0][name]=john&users[0][age]=25')
* const stringified = qs.stringify({ users: [{ name: 'john', age: 25 }] })
* ```
*/
var Qs = class {
	/**
	* Configuration object containing parse and stringify options for query strings
	*/
	#config;
	/**
	* Creates a new query string parser instance with the provided configuration
	* @param config - Configuration object with parse and stringify options
	*/
	constructor(config) {
		this.#config = config;
	}
	/**
	* Parses a query string into a JavaScript object using the configured options
	* @param value - Query string to parse (e.g., "foo=bar&baz=qux")
	* @returns Parsed object representation of the query string
	*/
	parse = (value) => {
		return parse(value, this.#config.parse);
	};
	/**
	* Converts a JavaScript object into a query string using the configured options
	* @param value - Object to convert to query string
	* @returns Stringified query string representation of the object
	*/
	stringify = (value) => {
		return stringify(value, this.#config.stringify);
	};
};
//#endregion
//#region src/errors.ts
var errors_exports = /* @__PURE__ */ __exportAll({
	E_CANNOT_LOOKUP_ROUTE: () => E_CANNOT_LOOKUP_ROUTE,
	E_HTTP_EXCEPTION: () => E_HTTP_EXCEPTION,
	E_HTTP_REQUEST_ABORTED: () => E_HTTP_REQUEST_ABORTED,
	E_ROUTE_NOT_FOUND: () => E_ROUTE_NOT_FOUND
});
/**
* Thrown when unable to find a matching route for the given request.
*
* This error is raised when the router cannot match the incoming HTTP method
* and URL pattern to any registered route in the application.
*
* @example
* ```ts
* throw new E_ROUTE_NOT_FOUND(['GET', '/nonexistent'])
* ```
*/
const E_ROUTE_NOT_FOUND = createError("Cannot %s:%s", "E_ROUTE_NOT_FOUND", 404);
/**
* Thrown when unable to lookup a route by its identifier.
*
* This error occurs when trying to generate URLs or find routes using
* a route name, pattern, or controller reference that doesn't exist.
*
* @example
* ```ts
* throw new E_CANNOT_LOOKUP_ROUTE(['nonexistent.route'])
* ```
*/
const E_CANNOT_LOOKUP_ROUTE = createError("Cannot lookup route \"%s\"", "E_CANNOT_LOOKUP_ROUTE", 500);
/**
* A generic HTTP exception for converting errors to HTTP responses.
*
* This class provides a standardized way to create HTTP exceptions with
* specific status codes and response bodies. It handles various input types
* including strings, objects, and null/undefined values.
*
* @example
* ```ts
* throw E_HTTP_EXCEPTION.invoke('Not found', 404)
* throw E_HTTP_EXCEPTION.invoke({ error: 'Invalid data' }, 422)
* ```
*/
const E_HTTP_EXCEPTION = class HttpException extends Exception {
	body;
	static code = "E_HTTP_EXCEPTION";
	/**
	* Creates and returns an instance of the HttpException class.
	*
	* @param body - The response body (string, object, or null/undefined)
	* @param status - HTTP status code for the response
	* @param code - Optional error code (defaults to 'E_HTTP_EXCEPTION')
	*
	* @example
	* ```ts
	* const error = HttpException.invoke('Resource not found', 404)
	* const error2 = HttpException.invoke({ message: 'Validation failed' }, 422)
	* ```
	*/
	static invoke(body, status, code = "E_HTTP_EXCEPTION") {
		if (body === null || body === void 0) {
			const error = new this("HTTP Exception", {
				status,
				code
			});
			error.body = "Internal server error";
			return error;
		}
		if (typeof body === "object") {
			const error = new this(body.message || "HTTP Exception", {
				status,
				code
			});
			error.body = body;
			return error;
		}
		const error = new this(body, {
			status,
			code
		});
		error.body = body;
		return error;
	}
};
/**
* Thrown when the "response.abort" method is called.
*
* This exception is used to immediately terminate request processing
* and send a response. It includes a built-in handler that automatically
* sends the appropriate status and body to the client.
*
* @example
* ```ts
* throw new E_HTTP_REQUEST_ABORTED()
* ```
*/
const E_HTTP_REQUEST_ABORTED = class AbortException extends E_HTTP_EXCEPTION {
	handle(error, ctx) {
		ctx.response.status(error.status).send(error.body);
	}
};
//#endregion
//#region src/redirect.ts
/**
* Provides a fluent API for constructing HTTP redirect responses.
*
* The Redirect class allows you to build redirects with custom status codes,
* query string forwarding, and route-based URL generation. It supports both
* direct URL redirects and route-based redirects using registered route names.
*
* @example
* ```ts
* // Basic redirect
* return response.redirect('https://example.com')
*
* // Redirect to a route
* return response.redirect().toRoute('users.show', { id: 1 })
*
* // Redirect with status code and query string
* return response.redirect()
*   .status(301)
*   .withQs({ utm_source: 'newsletter' })
*   .toPath('/dashboard')
* ```
*/
var Redirect = class extends Macroable {
	/**
	* HTTP context reference, set by the response when creating
	* the redirect instance during request handling.
	*/
	ctx;
	/**
	* Array of allowed hosts for referrer-based redirects.
	* When empty, only the request's own host is allowed.
	*/
	allowedHosts;
	/**
	* Flag indicating whether to forward the existing query string from the current request
	*/
	#forwardQueryString = false;
	/**
	* HTTP status code to use for the redirect response (defaults to 302)
	*/
	#statusCode = 302;
	/**
	* Custom query string parameters to include in the redirect URL
	*/
	#queryString = {};
	/**
	* Reference to the Node.js incoming HTTP request
	*/
	#request;
	/**
	* Reference to the AdonisJS response instance
	*/
	#response;
	/**
	* Reference to the AdonisJS router instance for URL building
	*/
	#router;
	/**
	* Query string parser instance
	*/
	#qs;
	/**
	* Creates a new Redirect instance for handling HTTP redirects
	* @param request - Node.js incoming HTTP request
	* @param response - AdonisJS response instance
	* @param router - AdonisJS router instance
	* @param qs - Query string parser instance
	* @param config - Redirect configuration
	*/
	constructor(request, response, router, qs, config) {
		super();
		this.#request = request;
		this.#response = response;
		this.#router = router;
		this.#qs = qs;
		this.allowedHosts = config.allowedHosts;
		this.#forwardQueryString = config.forwardQueryString;
	}
	/**
	* Sends the redirect response by setting required headers and status code
	* @param url - Target URL for redirection
	* @param query - Query string parameters to append
	*/
	#sendResponse(url, query) {
		const stringified = this.#qs.stringify(query);
		url = stringified ? `${url}?${stringified}` : url;
		debug_default("redirecting to url \"%s\"", url);
		this.#response.location(encodeUrl(url));
		this.#response.safeStatus(this.#statusCode);
		this.#response.type("text/plain; charset=utf-8");
		this.#response.send(`Redirecting to ${url}`);
	}
	/**
	* Returns the previous URL for redirect back. By default reads
	* the `Referer` header and validates the host.
	*
	* Since `Redirect` extends `Macroable`, this method can be overridden
	* to implement custom logic such as session-based previous URL
	* resolution.
	*
	* @param fallback - URL to return when no valid previous URL is found
	*/
	getPreviousUrl(fallback) {
		if (!this.ctx) throw new RuntimeException("Cannot resolve the previous URL. The \"Redirect\" class has no reference to the HTTP context");
		return getPreviousUrl(this.ctx.request, this.allowedHosts, fallback);
	}
	/**
	* Sets a custom HTTP status code for the redirect response
	* @param statusCode - HTTP status code to use (e.g., 301, 302, 307)
	* @returns {this} The Redirect instance for method chaining
	*/
	status(statusCode) {
		this.#statusCode = statusCode;
		return this;
	}
	/**
	* Clears any query string values previously added using the withQs method
	* @returns {this} The Redirect instance for method chaining
	*/
	clearQs() {
		this.#forwardQueryString = false;
		this.#queryString = {};
		return this;
	}
	withQs(name, value) {
		if (typeof name === "undefined") {
			this.#forwardQueryString = true;
			return this;
		}
		if (typeof name === "boolean") {
			this.#forwardQueryString = name;
			return this;
		}
		if (typeof name === "string") {
			this.#queryString[name] = value;
			return this;
		}
		Object.assign(this.#queryString, name);
		return this;
	}
	/**
	* Redirects to the previous URL resolved via `getPreviousUrl`.
	*
	* @param fallback - URL to redirect to when no valid previous URL is found
	*/
	back(fallback = "/") {
		let query = {};
		const previousUrl = this.getPreviousUrl(fallback);
		const url = safeDecodeURI(previousUrl, false);
		debug_default("previous url \"%s\"", previousUrl);
		debug_default("previous base url \"%s\"", url.pathname);
		/**
		* Parse query string from the previous url
		*/
		if (this.#forwardQueryString) query = this.#qs.parse(url.query || "");
		/**
		* Append custom query string
		*/
		Object.assign(query, this.#queryString);
		/**
		* Redirect
		*/
		this.#sendResponse(url.pathname || "", query);
	}
	/**
	* Redirects to a route using its identifier (name, pattern, or handler reference)
	* @param args - Route identifier, parameters, and options for URL building
	*/
	toRoute(...args) {
		const [identifier, params, options] = args;
		if (options && options.qs) {
			this.withQs(options.qs);
			options.qs = void 0;
		}
		const url = this.#router.urlBuilder.urlFor(identifier, params, options);
		return this.toPath(url);
	}
	/**
	* Redirects to a specific URL path
	* @param url - Target URL path for redirection
	*/
	toPath(url) {
		let query = {};
		/**
		* Extract query string from the current URL
		*/
		if (this.#forwardQueryString) query = this.#qs.parse(safeDecodeURI(this.#request.url, false).query || "");
		/**
		* Assign custom query string
		*/
		Object.assign(query, this.#queryString);
		/**
		* Redirect
		*/
		this.#sendResponse(url, query);
	}
};
//#endregion
//#region node_modules/negotiator/lib/charset.js
/**
* negotiator
* Copyright(c) 2012 Isaac Z. Schlueter
* Copyright(c) 2014 Federico Romero
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
var require_charset = /* @__PURE__ */ __commonJSMin(((exports, module) => {
	/**
	* Module exports.
	* @public
	*/
	module.exports = preferredCharsets;
	module.exports.preferredCharsets = preferredCharsets;
	/**
	* Module variables.
	* @private
	*/
	var simpleCharsetRegExp = /^\s*([^\s;]+)\s*(?:;(.*))?$/;
	/**
	* Parse the Accept-Charset header.
	* @private
	*/
	function parseAcceptCharset(accept) {
		var accepts = accept.split(",");
		for (var i = 0, j = 0; i < accepts.length; i++) {
			var charset = parseCharset(accepts[i].trim(), i);
			if (charset) accepts[j++] = charset;
		}
		accepts.length = j;
		return accepts;
	}
	/**
	* Parse a charset from the Accept-Charset header.
	* @private
	*/
	function parseCharset(str, i) {
		var match = simpleCharsetRegExp.exec(str);
		if (!match) return null;
		var charset = match[1];
		var q = 1;
		if (match[2]) {
			var params = match[2].split(";");
			for (var j = 0; j < params.length; j++) {
				var p = params[j].trim().split("=");
				if (p[0] === "q") {
					q = parseFloat(p[1]);
					break;
				}
			}
		}
		return {
			charset,
			q,
			i
		};
	}
	/**
	* Get the priority of a charset.
	* @private
	*/
	function getCharsetPriority(charset, accepted, index) {
		var priority = {
			o: -1,
			q: 0,
			s: 0
		};
		for (var i = 0; i < accepted.length; i++) {
			var spec = specify(charset, accepted[i], index);
			if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) priority = spec;
		}
		return priority;
	}
	/**
	* Get the specificity of the charset.
	* @private
	*/
	function specify(charset, spec, index) {
		var s = 0;
		if (spec.charset.toLowerCase() === charset.toLowerCase()) s |= 1;
		else if (spec.charset !== "*") return null;
		return {
			i: index,
			o: spec.i,
			q: spec.q,
			s
		};
	}
	/**
	* Get the preferred charsets from an Accept-Charset header.
	* @public
	*/
	function preferredCharsets(accept, provided) {
		var accepts = parseAcceptCharset(accept === void 0 ? "*" : accept || "");
		if (!provided) return accepts.filter(isQuality).sort(compareSpecs).map(getFullCharset);
		var priorities = provided.map(function getPriority(type, index) {
			return getCharsetPriority(type, accepts, index);
		});
		return priorities.filter(isQuality).sort(compareSpecs).map(function getCharset(priority) {
			return provided[priorities.indexOf(priority)];
		});
	}
	/**
	* Compare two specs.
	* @private
	*/
	function compareSpecs(a, b) {
		return b.q - a.q || b.s - a.s || a.o - b.o || a.i - b.i || 0;
	}
	/**
	* Get full charset string.
	* @private
	*/
	function getFullCharset(spec) {
		return spec.charset;
	}
	/**
	* Check if a spec has any quality.
	* @private
	*/
	function isQuality(spec) {
		return spec.q > 0;
	}
}));
//#endregion
//#region node_modules/negotiator/lib/encoding.js
/**
* negotiator
* Copyright(c) 2012 Isaac Z. Schlueter
* Copyright(c) 2014 Federico Romero
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
var require_encoding = /* @__PURE__ */ __commonJSMin(((exports, module) => {
	/**
	* Module exports.
	* @public
	*/
	module.exports = preferredEncodings;
	module.exports.preferredEncodings = preferredEncodings;
	/**
	* Module variables.
	* @private
	*/
	var simpleEncodingRegExp = /^\s*([^\s;]+)\s*(?:;(.*))?$/;
	/**
	* Parse the Accept-Encoding header.
	* @private
	*/
	function parseAcceptEncoding(accept) {
		var accepts = accept.split(",");
		var hasIdentity = false;
		var minQuality = 1;
		for (var i = 0, j = 0; i < accepts.length; i++) {
			var encoding = parseEncoding(accepts[i].trim(), i);
			if (encoding) {
				accepts[j++] = encoding;
				hasIdentity = hasIdentity || specify("identity", encoding);
				minQuality = Math.min(minQuality, encoding.q || 1);
			}
		}
		if (!hasIdentity) accepts[j++] = {
			encoding: "identity",
			q: minQuality,
			i
		};
		accepts.length = j;
		return accepts;
	}
	/**
	* Parse an encoding from the Accept-Encoding header.
	* @private
	*/
	function parseEncoding(str, i) {
		var match = simpleEncodingRegExp.exec(str);
		if (!match) return null;
		var encoding = match[1];
		var q = 1;
		if (match[2]) {
			var params = match[2].split(";");
			for (var j = 0; j < params.length; j++) {
				var p = params[j].trim().split("=");
				if (p[0] === "q") {
					q = parseFloat(p[1]);
					break;
				}
			}
		}
		return {
			encoding,
			q,
			i
		};
	}
	/**
	* Get the priority of an encoding.
	* @private
	*/
	function getEncodingPriority(encoding, accepted, index) {
		var priority = {
			o: -1,
			q: 0,
			s: 0
		};
		for (var i = 0; i < accepted.length; i++) {
			var spec = specify(encoding, accepted[i], index);
			if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) priority = spec;
		}
		return priority;
	}
	/**
	* Get the specificity of the encoding.
	* @private
	*/
	function specify(encoding, spec, index) {
		var s = 0;
		if (spec.encoding.toLowerCase() === encoding.toLowerCase()) s |= 1;
		else if (spec.encoding !== "*") return null;
		return {
			i: index,
			o: spec.i,
			q: spec.q,
			s
		};
	}
	/**
	* Get the preferred encodings from an Accept-Encoding header.
	* @public
	*/
	function preferredEncodings(accept, provided) {
		var accepts = parseAcceptEncoding(accept || "");
		if (!provided) return accepts.filter(isQuality).sort(compareSpecs).map(getFullEncoding);
		var priorities = provided.map(function getPriority(type, index) {
			return getEncodingPriority(type, accepts, index);
		});
		return priorities.filter(isQuality).sort(compareSpecs).map(function getEncoding(priority) {
			return provided[priorities.indexOf(priority)];
		});
	}
	/**
	* Compare two specs.
	* @private
	*/
	function compareSpecs(a, b) {
		return b.q - a.q || b.s - a.s || a.o - b.o || a.i - b.i || 0;
	}
	/**
	* Get full encoding string.
	* @private
	*/
	function getFullEncoding(spec) {
		return spec.encoding;
	}
	/**
	* Check if a spec has any quality.
	* @private
	*/
	function isQuality(spec) {
		return spec.q > 0;
	}
}));
//#endregion
//#region node_modules/negotiator/lib/language.js
/**
* negotiator
* Copyright(c) 2012 Isaac Z. Schlueter
* Copyright(c) 2014 Federico Romero
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
var require_language = /* @__PURE__ */ __commonJSMin(((exports, module) => {
	/**
	* Module exports.
	* @public
	*/
	module.exports = preferredLanguages;
	module.exports.preferredLanguages = preferredLanguages;
	/**
	* Module variables.
	* @private
	*/
	var simpleLanguageRegExp = /^\s*([^\s\-;]+)(?:-([^\s;]+))?\s*(?:;(.*))?$/;
	/**
	* Parse the Accept-Language header.
	* @private
	*/
	function parseAcceptLanguage(accept) {
		var accepts = accept.split(",");
		for (var i = 0, j = 0; i < accepts.length; i++) {
			var language = parseLanguage(accepts[i].trim(), i);
			if (language) accepts[j++] = language;
		}
		accepts.length = j;
		return accepts;
	}
	/**
	* Parse a language from the Accept-Language header.
	* @private
	*/
	function parseLanguage(str, i) {
		var match = simpleLanguageRegExp.exec(str);
		if (!match) return null;
		var prefix = match[1];
		var suffix = match[2];
		var full = prefix;
		if (suffix) full += "-" + suffix;
		var q = 1;
		if (match[3]) {
			var params = match[3].split(";");
			for (var j = 0; j < params.length; j++) {
				var p = params[j].split("=");
				if (p[0] === "q") q = parseFloat(p[1]);
			}
		}
		return {
			prefix,
			suffix,
			q,
			i,
			full
		};
	}
	/**
	* Get the priority of a language.
	* @private
	*/
	function getLanguagePriority(language, accepted, index) {
		var priority = {
			o: -1,
			q: 0,
			s: 0
		};
		for (var i = 0; i < accepted.length; i++) {
			var spec = specify(language, accepted[i], index);
			if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) priority = spec;
		}
		return priority;
	}
	/**
	* Get the specificity of the language.
	* @private
	*/
	function specify(language, spec, index) {
		var p = parseLanguage(language);
		if (!p) return null;
		var s = 0;
		if (spec.full.toLowerCase() === p.full.toLowerCase()) s |= 4;
		else if (spec.prefix.toLowerCase() === p.full.toLowerCase()) s |= 2;
		else if (spec.full.toLowerCase() === p.prefix.toLowerCase()) s |= 1;
		else if (spec.full !== "*") return null;
		return {
			i: index,
			o: spec.i,
			q: spec.q,
			s
		};
	}
	/**
	* Get the preferred languages from an Accept-Language header.
	* @public
	*/
	function preferredLanguages(accept, provided) {
		var accepts = parseAcceptLanguage(accept === void 0 ? "*" : accept || "");
		if (!provided) return accepts.filter(isQuality).sort(compareSpecs).map(getFullLanguage);
		var priorities = provided.map(function getPriority(type, index) {
			return getLanguagePriority(type, accepts, index);
		});
		return priorities.filter(isQuality).sort(compareSpecs).map(function getLanguage(priority) {
			return provided[priorities.indexOf(priority)];
		});
	}
	/**
	* Compare two specs.
	* @private
	*/
	function compareSpecs(a, b) {
		return b.q - a.q || b.s - a.s || a.o - b.o || a.i - b.i || 0;
	}
	/**
	* Get full language string.
	* @private
	*/
	function getFullLanguage(spec) {
		return spec.full;
	}
	/**
	* Check if a spec has any quality.
	* @private
	*/
	function isQuality(spec) {
		return spec.q > 0;
	}
}));
//#endregion
//#region node_modules/negotiator/lib/mediaType.js
/**
* negotiator
* Copyright(c) 2012 Isaac Z. Schlueter
* Copyright(c) 2014 Federico Romero
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
var require_mediaType = /* @__PURE__ */ __commonJSMin(((exports, module) => {
	/**
	* Module exports.
	* @public
	*/
	module.exports = preferredMediaTypes;
	module.exports.preferredMediaTypes = preferredMediaTypes;
	/**
	* Module variables.
	* @private
	*/
	var simpleMediaTypeRegExp = /^\s*([^\s\/;]+)\/([^;\s]+)\s*(?:;(.*))?$/;
	/**
	* Parse the Accept header.
	* @private
	*/
	function parseAccept(accept) {
		var accepts = splitMediaTypes(accept);
		for (var i = 0, j = 0; i < accepts.length; i++) {
			var mediaType = parseMediaType(accepts[i].trim(), i);
			if (mediaType) accepts[j++] = mediaType;
		}
		accepts.length = j;
		return accepts;
	}
	/**
	* Parse a media type from the Accept header.
	* @private
	*/
	function parseMediaType(str, i) {
		var match = simpleMediaTypeRegExp.exec(str);
		if (!match) return null;
		var params = Object.create(null);
		var q = 1;
		var subtype = match[2];
		var type = match[1];
		if (match[3]) {
			var kvps = splitParameters(match[3]).map(splitKeyValuePair);
			for (var j = 0; j < kvps.length; j++) {
				var pair = kvps[j];
				var key = pair[0].toLowerCase();
				var val = pair[1];
				var value = val && val[0] === "\"" && val[val.length - 1] === "\"" ? val.substr(1, val.length - 2) : val;
				if (key === "q") {
					q = parseFloat(value);
					break;
				}
				params[key] = value;
			}
		}
		return {
			type,
			subtype,
			params,
			q,
			i
		};
	}
	/**
	* Get the priority of a media type.
	* @private
	*/
	function getMediaTypePriority(type, accepted, index) {
		var priority = {
			o: -1,
			q: 0,
			s: 0
		};
		for (var i = 0; i < accepted.length; i++) {
			var spec = specify(type, accepted[i], index);
			if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) priority = spec;
		}
		return priority;
	}
	/**
	* Get the specificity of the media type.
	* @private
	*/
	function specify(type, spec, index) {
		var p = parseMediaType(type);
		var s = 0;
		if (!p) return null;
		if (spec.type.toLowerCase() == p.type.toLowerCase()) s |= 4;
		else if (spec.type != "*") return null;
		if (spec.subtype.toLowerCase() == p.subtype.toLowerCase()) s |= 2;
		else if (spec.subtype != "*") return null;
		var keys = Object.keys(spec.params);
		if (keys.length > 0) if (keys.every(function(k) {
			return spec.params[k] == "*" || (spec.params[k] || "").toLowerCase() == (p.params[k] || "").toLowerCase();
		})) s |= 1;
		else return null;
		return {
			i: index,
			o: spec.i,
			q: spec.q,
			s
		};
	}
	/**
	* Get the preferred media types from an Accept header.
	* @public
	*/
	function preferredMediaTypes(accept, provided) {
		var accepts = parseAccept(accept === void 0 ? "*/*" : accept || "");
		if (!provided) return accepts.filter(isQuality).sort(compareSpecs).map(getFullType);
		var priorities = provided.map(function getPriority(type, index) {
			return getMediaTypePriority(type, accepts, index);
		});
		return priorities.filter(isQuality).sort(compareSpecs).map(function getType(priority) {
			return provided[priorities.indexOf(priority)];
		});
	}
	/**
	* Compare two specs.
	* @private
	*/
	function compareSpecs(a, b) {
		return b.q - a.q || b.s - a.s || a.o - b.o || a.i - b.i || 0;
	}
	/**
	* Get full type string.
	* @private
	*/
	function getFullType(spec) {
		return spec.type + "/" + spec.subtype;
	}
	/**
	* Check if a spec has any quality.
	* @private
	*/
	function isQuality(spec) {
		return spec.q > 0;
	}
	/**
	* Count the number of quotes in a string.
	* @private
	*/
	function quoteCount(string) {
		var count = 0;
		var index = 0;
		while ((index = string.indexOf("\"", index)) !== -1) {
			count++;
			index++;
		}
		return count;
	}
	/**
	* Split a key value pair.
	* @private
	*/
	function splitKeyValuePair(str) {
		var index = str.indexOf("=");
		var key;
		var val;
		if (index === -1) key = str;
		else {
			key = str.substr(0, index);
			val = str.substr(index + 1);
		}
		return [key, val];
	}
	/**
	* Split an Accept header into media types.
	* @private
	*/
	function splitMediaTypes(accept) {
		var accepts = accept.split(",");
		for (var i = 1, j = 0; i < accepts.length; i++) if (quoteCount(accepts[j]) % 2 == 0) accepts[++j] = accepts[i];
		else accepts[j] += "," + accepts[i];
		accepts.length = j + 1;
		return accepts;
	}
	/**
	* Split a string of parameters.
	* @private
	*/
	function splitParameters(str) {
		var parameters = str.split(";");
		for (var i = 1, j = 0; i < parameters.length; i++) if (quoteCount(parameters[j]) % 2 == 0) parameters[++j] = parameters[i];
		else parameters[j] += ";" + parameters[i];
		parameters.length = j + 1;
		for (var i = 0; i < parameters.length; i++) parameters[i] = parameters[i].trim();
		return parameters;
	}
}));
//#endregion
//#region node_modules/negotiator/index.js
/*!
* negotiator
* Copyright(c) 2012 Federico Romero
* Copyright(c) 2012-2014 Isaac Z. Schlueter
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
var require_negotiator = /* @__PURE__ */ __commonJSMin(((exports, module) => {
	var preferredCharsets = require_charset();
	var preferredEncodings = require_encoding();
	var preferredLanguages = require_language();
	var preferredMediaTypes = require_mediaType();
	/**
	* Module exports.
	* @public
	*/
	module.exports = Negotiator;
	module.exports.Negotiator = Negotiator;
	/**
	* Create a Negotiator instance from a request.
	* @param {object} request
	* @public
	*/
	function Negotiator(request) {
		if (!(this instanceof Negotiator)) return new Negotiator(request);
		this.request = request;
	}
	Negotiator.prototype.charset = function charset(available) {
		var set = this.charsets(available);
		return set && set[0];
	};
	Negotiator.prototype.charsets = function charsets(available) {
		return preferredCharsets(this.request.headers["accept-charset"], available);
	};
	Negotiator.prototype.encoding = function encoding(available) {
		var set = this.encodings(available);
		return set && set[0];
	};
	Negotiator.prototype.encodings = function encodings(available) {
		return preferredEncodings(this.request.headers["accept-encoding"], available);
	};
	Negotiator.prototype.language = function language(available) {
		var set = this.languages(available);
		return set && set[0];
	};
	Negotiator.prototype.languages = function languages(available) {
		return preferredLanguages(this.request.headers["accept-language"], available);
	};
	Negotiator.prototype.mediaType = function mediaType(available) {
		var set = this.mediaTypes(available);
		return set && set[0];
	};
	Negotiator.prototype.mediaTypes = function mediaTypes(available) {
		return preferredMediaTypes(this.request.headers.accept, available);
	};
	Negotiator.prototype.preferredCharset = Negotiator.prototype.charset;
	Negotiator.prototype.preferredCharsets = Negotiator.prototype.charsets;
	Negotiator.prototype.preferredEncoding = Negotiator.prototype.encoding;
	Negotiator.prototype.preferredEncodings = Negotiator.prototype.encodings;
	Negotiator.prototype.preferredLanguage = Negotiator.prototype.language;
	Negotiator.prototype.preferredLanguages = Negotiator.prototype.languages;
	Negotiator.prototype.preferredMediaType = Negotiator.prototype.mediaType;
	Negotiator.prototype.preferredMediaTypes = Negotiator.prototype.mediaTypes;
}));
/*!
* accepts
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
//#endregion
//#region src/cookies/drivers/plain.ts
var import_accepts = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
	/**
	* Module dependencies.
	* @private
	*/
	var Negotiator = require_negotiator();
	var mime = __require("mime-types");
	/**
	* Module exports.
	* @public
	*/
	module.exports = Accepts;
	/**
	* Create a new Accepts object for the given req.
	*
	* @param {object} req
	* @public
	*/
	function Accepts(req) {
		if (!(this instanceof Accepts)) return new Accepts(req);
		this.headers = req.headers;
		this.negotiator = new Negotiator(req);
	}
	/**
	* Check if the given `type(s)` is acceptable, returning
	* the best match when true, otherwise `undefined`, in which
	* case you should respond with 406 "Not Acceptable".
	*
	* The `type` value may be a single mime type string
	* such as "application/json", the extension name
	* such as "json" or an array `["json", "html", "text/plain"]`. When a list
	* or array is given the _best_ match, if any is returned.
	*
	* Examples:
	*
	*     // Accept: text/html
	*     this.types('html');
	*     // => "html"
	*
	*     // Accept: text/*, application/json
	*     this.types('html');
	*     // => "html"
	*     this.types('text/html');
	*     // => "text/html"
	*     this.types('json', 'text');
	*     // => "json"
	*     this.types('application/json');
	*     // => "application/json"
	*
	*     // Accept: text/*, application/json
	*     this.types('image/png');
	*     this.types('png');
	*     // => undefined
	*
	*     // Accept: text/*;q=.5, application/json
	*     this.types(['html', 'json']);
	*     this.types('html', 'json');
	*     // => "json"
	*
	* @param {String|Array} types...
	* @return {String|Array|Boolean}
	* @public
	*/
	Accepts.prototype.type = Accepts.prototype.types = function(types_) {
		var types = types_;
		if (types && !Array.isArray(types)) {
			types = new Array(arguments.length);
			for (var i = 0; i < types.length; i++) types[i] = arguments[i];
		}
		if (!types || types.length === 0) return this.negotiator.mediaTypes();
		if (!this.headers.accept) return types[0];
		var mimes = types.map(extToMime);
		var first = this.negotiator.mediaTypes(mimes.filter(validMime))[0];
		return first ? types[mimes.indexOf(first)] : false;
	};
	/**
	* Return accepted encodings or best fit based on `encodings`.
	*
	* Given `Accept-Encoding: gzip, deflate`
	* an array sorted by quality is returned:
	*
	*     ['gzip', 'deflate']
	*
	* @param {String|Array} encodings...
	* @return {String|Array}
	* @public
	*/
	Accepts.prototype.encoding = Accepts.prototype.encodings = function(encodings_) {
		var encodings = encodings_;
		if (encodings && !Array.isArray(encodings)) {
			encodings = new Array(arguments.length);
			for (var i = 0; i < encodings.length; i++) encodings[i] = arguments[i];
		}
		if (!encodings || encodings.length === 0) return this.negotiator.encodings();
		return this.negotiator.encodings(encodings)[0] || false;
	};
	/**
	* Return accepted charsets or best fit based on `charsets`.
	*
	* Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`
	* an array sorted by quality is returned:
	*
	*     ['utf-8', 'utf-7', 'iso-8859-1']
	*
	* @param {String|Array} charsets...
	* @return {String|Array}
	* @public
	*/
	Accepts.prototype.charset = Accepts.prototype.charsets = function(charsets_) {
		var charsets = charsets_;
		if (charsets && !Array.isArray(charsets)) {
			charsets = new Array(arguments.length);
			for (var i = 0; i < charsets.length; i++) charsets[i] = arguments[i];
		}
		if (!charsets || charsets.length === 0) return this.negotiator.charsets();
		return this.negotiator.charsets(charsets)[0] || false;
	};
	/**
	* Return accepted languages or best fit based on `langs`.
	*
	* Given `Accept-Language: en;q=0.8, es, pt`
	* an array sorted by quality is returned:
	*
	*     ['es', 'pt', 'en']
	*
	* @param {String|Array} langs...
	* @return {Array|String}
	* @public
	*/
	Accepts.prototype.lang = Accepts.prototype.langs = Accepts.prototype.language = Accepts.prototype.languages = function(languages_) {
		var languages = languages_;
		if (languages && !Array.isArray(languages)) {
			languages = new Array(arguments.length);
			for (var i = 0; i < languages.length; i++) languages[i] = arguments[i];
		}
		if (!languages || languages.length === 0) return this.negotiator.languages();
		return this.negotiator.languages(languages)[0] || false;
	};
	/**
	* Convert extnames to mime.
	*
	* @param {String} type
	* @return {String}
	* @private
	*/
	function extToMime(type) {
		return type.indexOf("/") === -1 ? mime.lookup(type) : type;
	}
	/**
	* Check if mime is valid.
	*
	* @param {String} type
	* @return {String}
	* @private
	*/
	function validMime(type) {
		return typeof type === "string";
	}
})))(), 1);
/**
* Encodes a value into a base64 url encoded string to
* be set as cookie
*
* @param value - The value to encode
* @returns The encoded cookie string or null if value is null/undefined
*/
function pack$2(value) {
	if (value === void 0 || value === null) return null;
	return base64.urlEncode(new MessageBuilder().build(value));
}
/**
* Returns true when this `unpack` method of this module can attempt
* to unpack the encode value.
*
* @param encodedValue - The encoded value to check
* @returns True if the value can be unpacked by this module
*/
function canUnpack$2(encodedValue) {
	return typeof encodedValue === "string";
}
/**
* Attempts to unpack the value by decoding it. Make sure to call, `canUnpack`
* before calling this method
*
* @param encodedValue - The encoded value to decode
* @returns The decoded value or null if decoding fails
*/
function unpack$2(encodedValue) {
	return new MessageBuilder().verify(base64.urlDecode(encodedValue, "utf-8", false));
}
//#endregion
//#region src/cookies/drivers/signed.ts
/**
* Signs a value to be shared as a cookie. The signed output has a
* hash to verify tampering with the original value
*
* @param key - The cookie key used for signing
* @param value - The value to sign
* @param encryption - The encryption instance
* @returns The signed cookie string or null if value is null/undefined
*/
function pack$1(key, value, encryption) {
	if (value === void 0 || value === null) return null;
	return `s:${encryption.getMessageVerifier().sign(value, void 0, key)}`;
}
/**
* Returns a boolean, if the unpack method from this module can attempt
* to unpack the signed value.
*
* @param signedValue - The signed value to check
* @returns True if the value can be unpacked by this module
*/
function canUnpack$1(signedValue) {
	return typeof signedValue === "string" && signedValue.substring(0, 2) === "s:";
}
/**
* Attempts to unpack the signed value. Make sure to call `canUnpack` before
* calling this method.
*
* @param key - The cookie key used for verification
* @param signedValue - The signed value to verify and unpack
* @param encryption - The encryption instance
* @returns The original value or null if verification fails
*/
function unpack$1(key, signedValue, encryption) {
	const value = signedValue.slice(2);
	if (!value) return null;
	return encryption.getMessageVerifier().unsign(value, key);
}
//#endregion
//#region src/cookies/drivers/encrypted.ts
/**
* Encrypt a value to be set as cookie
*
* @param key - The cookie key used for encryption
* @param value - The value to encrypt
* @param encryption - The encryption instance
* @returns The encrypted cookie string or null if value is null/undefined
*/
function pack(key, value, encryption) {
	if (value === void 0 || value === null) return null;
	return `e:${encryption.encrypt(value, void 0, key)}`;
}
/**
* Returns a boolean, if the unpack method from this module can attempt
* to unpack encrypted value.
*
* @param encryptedValue - The encrypted value to check
* @returns True if the value can be unpacked by this module
*/
function canUnpack(encryptedValue) {
	return typeof encryptedValue === "string" && encryptedValue.substring(0, 2) === "e:";
}
/**
* Attempts to unpack the encrypted cookie value. Returns null, when fails to do so.
* Only call this method, when `canUnpack` returns true, otherwise runtime
* exceptions can be raised.
*
* @param key - The cookie key used for decryption
* @param encryptedValue - The encrypted value to decrypt
* @param encryption - The encryption instance
* @returns The decrypted value or null if decryption fails
*/
function unpack(key, encryptedValue, encryption) {
	const value = encryptedValue.slice(2);
	if (!value) return null;
	return encryption.decrypt(value, key);
}
//#endregion
//#region src/cookies/client.ts
/**
* Cookie client provides a unified API for parsing and setting AdonisJS cookies on the client side.
*
* This class handles different types of cookies including plain, signed, and encrypted cookies.
* It provides methods to encode/decode cookies for client-side operations and parse server responses.
*
* @example
* ```ts
* const client = new CookieClient(encryption)
*
* // Encrypt a cookie value
* const encrypted = client.encrypt('sessionId', 'abc123')
*
* // Parse a cookie from server response
* const value = client.parse('sessionId', cookieValue)
* ```
*/
var CookieClient = class {
	/**
	* Private encryption instance used for signing and encrypting cookies
	*/
	#encryption;
	/**
	* Create a new instance of CookieClient
	*
	* @param encryption - The encryption instance for cookie operations
	*/
	constructor(encryption) {
		this.#encryption = encryption;
	}
	/**
	* Encrypt a key value pair to be sent in the cookie header
	*
	* @param key - The cookie key
	* @param value - The value to encrypt
	* @returns The encrypted cookie string or null if encryption fails
	*/
	encrypt(key, value) {
		return pack(key, value, this.#encryption);
	}
	/**
	* Sign a key value pair to be sent in the cookie header
	*
	* @param key - The cookie key
	* @param value - The value to sign
	* @returns The signed cookie string or null if signing fails
	*/
	sign(key, value) {
		return pack$1(key, value, this.#encryption);
	}
	/**
	* Encode a key value pair to be sent in the cookie header
	*
	* @param _ - Unused key parameter
	* @param value - The value to encode
	* @param stringify - Whether to stringify the value before encoding
	* @returns The encoded cookie string or null if encoding fails
	*/
	encode(_, value, stringify = true) {
		return stringify ? pack$2(value) : value;
	}
	/**
	* Unsign a signed cookie value
	*
	* @param key - The cookie key
	* @param value - The signed cookie value to unsign
	* @returns The original value if valid signature, null otherwise
	*/
	unsign(key, value) {
		return canUnpack$1(value) ? unpack$1(key, value, this.#encryption) : null;
	}
	/**
	* Decrypt an encrypted cookie value
	*
	* @param key - The cookie key
	* @param value - The encrypted cookie value to decrypt
	* @returns The decrypted value or null if decryption fails
	*/
	decrypt(key, value) {
		return canUnpack(value) ? unpack(key, value, this.#encryption) : null;
	}
	/**
	* Decode an encoded cookie value
	*
	* @param _ - Unused key parameter
	* @param value - The encoded cookie value to decode
	* @param stringified - Whether the value was stringified during encoding
	* @returns The decoded value or null if decoding fails
	*/
	decode(_, value, stringified = true) {
		if (!stringified) return value;
		return canUnpack$2(value) ? unpack$2(value) : null;
	}
	/**
	* Parse a cookie value by attempting to decrypt, unsign, or decode it.
	*
	* This method tries different unpacking strategies in order:
	* 1. Unsign if it's a signed cookie
	* 2. Decrypt if it's an encrypted cookie
	* 3. Decode if it's a plain encoded cookie
	*
	* @param key - The cookie key
	* @param value - The cookie value to parse
	*
	* @example
	* ```ts
	* const parsed = client.parse('session', 'e30.abc123def')
	* // Returns the original value if successfully parsed
	* ```
	*/
	parse(key, value) {
		/**
		* Unsign signed cookie
		*/
		if (canUnpack$1(value)) return unpack$1(key, value, this.#encryption);
		/**
		* Decrypted encrypted cookie
		*/
		if (canUnpack(value)) return unpack(key, value, this.#encryption);
		/**
		* Decode encoded cookie
		*/
		if (canUnpack$2(value)) return unpack$2(value);
	}
};
//#endregion
//#region src/cookies/parser.ts
/**
* Cookie parser parses the HTTP `cookie` header and collects all cookies
* inside an object of `key-value` pair, but doesn't attempt to decrypt
* or unsign or decode the individual values.
*
* The cookie values are lazily decrypted, or unsigned to avoid unncessary
* processing, which infact can be used as a means to burden the server
* by sending too many cookies which even doesn't belongs to the
* server.
*/
var CookieParser = class {
	/**
	* Cookie client instance for handling cookie operations
	*/
	#client;
	/**
	* A copy of cached cookies, they are cached during a request after
	* initial decoding, unsigning or decrypting.
	*/
	#cachedCookies = {
		signedCookies: {},
		plainCookies: {},
		encryptedCookies: {}
	};
	/**
	* An object of key-value pair collected by parsing
	* the request cookie header.
	*/
	#cookies;
	/**
	* Create a new instance of CookieParser
	*
	* @param cookieHeader - The raw cookie header string from the request
	* @param encryption - The encryption instance for cookie operations
	*/
	constructor(cookieHeader, encryption) {
		this.#client = new CookieClient(encryption);
		this.#cookies = this.#parse(cookieHeader);
	}
	/**
	* Parses the request `cookie` header
	*
	* @param cookieHeader - The cookie header string to parse
	* @returns Parsed cookies as key-value pairs
	*/
	#parse(cookieHeader) {
		if (!cookieHeader) return {};
		return parse$1(cookieHeader);
	}
	/**
	* Generic method to get a cookie value from cache or parse it.
	* This method handles the common pattern of checking the cache,
	* parsing the value if not cached, and caching the result.
	*
	* @param key - The cookie key to lookup
	* @param cacheKey - The cache bucket to use
	* @param parser - Function to parse the raw cookie value
	* @returns The parsed cookie value or null if parsing fails
	*/
	#getCachedOrParse(key, cacheKey, parser) {
		const value = this.#cookies[key];
		if (value === null || value === void 0) return null;
		const cache = this.#cachedCookies[cacheKey];
		if (cache[key] !== void 0) return cache[key];
		const parsed = parser(value);
		if (parsed !== null) cache[key] = parsed;
		return parsed;
	}
	/**
	* Attempts to decode a cookie by the name. When calling this method,
	* you are assuming that the cookie was just stringified in the first
	* place and not signed or encrypted.
	*
	* @param key - The cookie key to decode
	* @param stringified - Whether the cookie value was stringified
	* @returns The decoded cookie value or null if decoding fails
	*/
	decode(key, stringified = true) {
		return this.#getCachedOrParse(key, "plainCookies", (value) => this.#client.decode(key, value, stringified));
	}
	/**
	* Attempts to unsign a cookie by the name. When calling this method,
	* you are assuming that the cookie was signed in the first place.
	*
	* @param key - The cookie key to unsign
	* @returns The original cookie value or null if unsigning fails
	*/
	unsign(key) {
		return this.#getCachedOrParse(key, "signedCookies", (value) => this.#client.unsign(key, value));
	}
	/**
	* Attempts to decrypt a cookie by the name. When calling this method,
	* you are assuming that the cookie was encrypted in the first place.
	*
	* @param key - The cookie key to decrypt
	* @returns The decrypted cookie value or null if decryption fails
	*/
	decrypt(key) {
		return this.#getCachedOrParse(key, "encryptedCookies", (value) => this.#client.decrypt(key, value));
	}
	/**
	* Returns an object of cookies key-value pair. Do note, the
	* cookies are not decoded, unsigned or decrypted inside this
	* list.
	*
	* @returns Raw cookies as key-value pairs
	*/
	list() {
		return this.#cookies;
	}
};
//#endregion
//#region src/request.ts
/**
* HTTP Request class exposes the interface to consistently read values
* related to a given HTTP request. The class is wrapper over
* [IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
* and has extended API.
*
* You can access the original [IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
* using `request.request` property.
*/
var HttpRequest = class extends Macroable {
	request;
	response;
	/**
	* Query string parser
	*/
	#qsParser;
	/**
	* Encryption module to verify signed URLs and unsign/decrypt
	* cookies
	*/
	#encryption;
	/**
	* Request config
	*/
	#config;
	/**
	* Request body set using `setBody` method
	*/
	#requestBody = {};
	/**
	* A merged copy of `request body` and `querystring`
	*/
	#requestData = {};
	/**
	* Original merged copy of `request body` and `querystring`.
	* Further mutation to this object are not allowed
	*/
	#originalRequestData = {};
	/**
	* Parsed query string
	*/
	#requestQs = {};
	/**
	* Raw request body as text
	*/
	#rawRequestBody;
	/**
	* Cached copy of `accepts` fn to do content
	* negotiation.
	*/
	#lazyAccepts;
	/**
	* Copy of lazily parsed signed and plain cookies.
	*/
	#cookieParser;
	/**
	* Parsed URL with query string stored as a string and decode flag
	*/
	parsedUrl;
	/**
	* HTTP context reference - creates a circular reference when set by the context
	*/
	ctx;
	/**
	* Creates a new Request instance wrapping the native Node.js HTTP request
	* @param request - Native Node.js incoming message instance
	* @param response - Native Node.js server response instance
	* @param encryption - Encryption module for cookie and URL signing
	* @param config - Request configuration options
	* @param qsParser - Query string parser instance
	*/
	constructor(request, response, encryption, config, qsParser) {
		super();
		this.request = request;
		this.response = response;
		this.#qsParser = qsParser;
		this.#config = config;
		this.#encryption = encryption;
		this.parsedUrl = safeDecodeURI(request.url, false);
		this.#parseQueryString();
	}
	/**
	* Parses the query string from the parsed URL and updates internal state.
	*
	* This method extracts query parameters from the URL and merges them into
	* the request data object, also creating a frozen copy for original data reference.
	*/
	#parseQueryString() {
		if (this.parsedUrl.query) {
			this.updateQs(this.#qsParser.parse(this.parsedUrl.query));
			this.#originalRequestData = { ...this.#requestData };
		}
	}
	/**
	* Initiates the cookie parser lazily when first needed.
	*
	* Creates a CookieParser instance with the current request's cookie header
	* and the configured encryption service for handling signed/encrypted cookies.
	*/
	#initiateCookieParser() {
		if (!this.#cookieParser) this.#cookieParser = new CookieParser(this.header("cookie"), this.#encryption);
	}
	/**
	* Lazily initiates the `accepts` module for content negotiation.
	*
	* Creates an accepts instance that parses the request headers only when
	* one of the content-negotiation methods (like accepts, acceptsLanguages) are used.
	* This improves performance by avoiding unnecessary header parsing.
	*/
	#initiateAccepts() {
		this.#lazyAccepts = this.#lazyAccepts || (0, import_accepts.default)(this.request);
	}
	/**
	* Returns the request ID from the `x-request-id` header.
	*
	* If the header doesn't exist and request ID generation is enabled,
	* a new UUID will be generated and added to the request headers.
	*
	* @example
	* ```ts
	* const requestId = request.id()
	* console.log(requestId) // '550e8400-e29b-41d4-a716-446655440000'
	* ```
	*/
	id() {
		let requestId = this.header("x-request-id");
		if (!requestId && this.#config.generateRequestId) {
			requestId = this.#config.createRequestId();
			this.request.headers["x-request-id"] = requestId;
		}
		return requestId;
	}
	/**
	* Set initial request body. A copy of the input will be maintained as the original
	* request body. Since the request body and query string is subject to mutations, we
	* keep one original reference to flash old data (whenever required).
	*
	* This method is supposed to be invoked by the body parser and must be called only
	* once. For further mutations make use of `updateBody` method.
	* @param body - Parsed request body data
	* @returns {void}
	*/
	setInitialBody(body) {
		if (this.#originalRequestData && Object.isFrozen(this.#originalRequestData)) throw new Error("Cannot re-set initial body. Use \"request.updateBody\" instead");
		this.updateBody(body);
		this.#originalRequestData = Object.freeze(lodash.cloneDeep(this.#requestData));
	}
	/**
	* Update the request body with new data object. The `all` property
	* will be re-computed by merging the query string and request
	* body.
	* @param body - New request body data to set
	* @returns {void}
	*/
	updateBody(body) {
		this.#requestBody = body;
		this.#requestData = {
			...this.#requestBody,
			...this.#requestQs
		};
	}
	/**
	* Update the request raw body. Bodyparser sets this when unable to parse
	* the request body or when request is multipart/form-data.
	* @param rawBody - Raw request body as string
	* @returns {void}
	*/
	updateRawBody(rawBody) {
		this.#rawRequestBody = rawBody;
	}
	/**
	* Update the query string with the new data object. The `all` property
	* will be re-computed by merging the query and the request body.
	* @param data - New query string data to set
	* @returns {void}
	*/
	updateQs(data) {
		this.#requestQs = data;
		this.#requestData = {
			...this.#requestBody,
			...this.#requestQs
		};
	}
	/**
	* Returns route params
	* @returns {Record<string, any>} Object containing route parameters
	*/
	params() {
		return this.ctx?.params || {};
	}
	/**
	* Returns the query string object by reference
	* @returns {Record<string, any>} Object containing parsed query string parameters
	*/
	qs() {
		return this.#requestQs;
	}
	/**
	* Returns reference to the request body
	* @returns {Record<string, any>} Object containing parsed request body
	*/
	body() {
		return this.#requestBody;
	}
	/**
	* Returns reference to the merged copy of request body
	* and query string
	* @returns {Record<string, any>} Object containing merged request body and query parameters
	*/
	all() {
		return this.#requestData;
	}
	/**
	* Returns reference to the merged copy of original request
	* query string and body
	* @returns {Record<string, any>} Object containing original merged request data
	*/
	original() {
		return this.#originalRequestData;
	}
	/**
	* Returns the request raw body (if exists), or returns `null`.
	*
	* Ideally you must be dealing with the parsed body accessed using [[input]], [[all]] or
	* [[post]] methods. The `raw` body is always a string.
	* @returns {string | null} Raw request body as string or null if not set
	*/
	raw() {
		return this.#rawRequestBody || null;
	}
	/**
	* Returns value for a given key from the request body or query string.
	* The `defaultValue` is used when original value is `undefined`.
	*
	* @example
	* ```js
	* request.input('username')
	*
	* // with default value
	* request.input('username', 'virk')
	* ```
	* @param key - Key to lookup in request data
	* @param defaultValue - Default value when key is not found
	* @returns Value from request data or default value
	*/
	input(key, defaultValue) {
		return lodash.get(this.#requestData, key, defaultValue);
	}
	/**
	* Returns value for a given key from route params
	*
	* @example
	* ```js
	* request.param('id')
	*
	* // with default value
	* request.param('id', 1)
	* ```
	* @param key - Parameter key to lookup
	* @param defaultValue - Default value when parameter is not found
	* @returns Value from route parameters or default value
	*/
	param(key, defaultValue) {
		return lodash.get(this.params(), key, defaultValue);
	}
	/**
	* Get everything from the request body except the given keys.
	*
	* @example
	* ```js
	* request.except(['_csrf'])
	* ```
	* @param keys - Array of keys to exclude from the result
	* @returns {Record<string, any>} Object with all request data except specified keys
	*/
	except(keys) {
		return lodash.omit(this.#requestData, keys);
	}
	/**
	* Get value for specified keys.
	*
	* @example
	* ```js
	* request.only(['username', 'age'])
	* ```
	* @param keys - Array of keys to include in the result
	* @returns {{ [K in T]: any }} Object with only the specified keys from request data
	*/
	only(keys) {
		return lodash.pick(this.#requestData, keys);
	}
	/**
	* Returns the HTTP request method. This is the original
	* request method. For spoofed request method, make
	* use of [[method]].
	*
	* @example
	* ```js
	* request.intended()
	* ```
	* @returns {string} Original HTTP method from the request
	*/
	intended() {
		return this.request.method;
	}
	/**
	* Returns the request HTTP method by taking method spoofing into account.
	*
	* Method spoofing works when all of the following are true.
	*
	* 1. `app.http.allowMethodSpoofing` config value is true.
	* 2. request query string has `_method`.
	* 3. The [[intended]] request method is `POST`.
	*
	* @example
	* ```js
	* request.method()
	* ```
	* @returns {string} HTTP method (potentially spoofed)
	*/
	method() {
		if (this.#config.allowMethodSpoofing && this.intended() === "POST") return this.input("_method", this.intended()).toUpperCase();
		return this.intended();
	}
	/**
	* Returns a copy of headers as an object
	* @returns {IncomingHttpHeaders} Object containing all HTTP headers
	*/
	headers() {
		return this.request.headers;
	}
	/**
	* Returns value for a given header key. The default value is
	* used when original value is `undefined`.
	* @param key - Header name to lookup
	* @param defaultValue - Default value when header is not found
	* @returns {string | undefined} Header value or default value if not found
	*/
	header(key, defaultValue) {
		key = key.toLowerCase();
		const headers = this.headers();
		switch (key) {
			case "referer":
			case "referrer": return headers.referrer || headers.referer || defaultValue;
			default: return headers[key] || defaultValue;
		}
	}
	/**
	* Returns the ip address of the user. This method is optimize to fetch
	* ip address even when running your AdonisJs app behind a proxy.
	*
	* You can also define your own custom function to compute the ip address by
	* defining `app.http.getIp` as a function inside the config file.
	*
	* ```js
	* {
	*   http: {
	*     getIp (request) {
	*       // I am using nginx as a proxy server and want to trust 'x-real-ip'
	*       return request.header('x-real-ip')
	*     }
	*   }
	* }
	* ```
	*
	* You can control the behavior of trusting the proxy values by defining it
	* inside the `config/app.js` file.
	*
	* ```js
	* {
	*   http: {
	*    trustProxy: '127.0.0.1'
	*   }
	* }
	* ```
	*
	* The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
	* @returns {string} Client IP address
	*/
	ip() {
		const ipFn = this.#config.getIp;
		if (typeof ipFn === "function") return ipFn(this, () => proxyaddr(this.request, this.#config.trustProxy));
		return proxyaddr(this.request, this.#config.trustProxy);
	}
	/**
	* Returns an array of ip addresses from most to least trusted one.
	* This method is optimize to fetch ip address even when running
	* your AdonisJs app behind a proxy.
	*
	* You can control the behavior of trusting the proxy values by defining it
	* inside the `config/app.js` file.
	*
	* ```js
	* {
	*   http: {
	*    trustProxy: '127.0.0.1'
	*   }
	* }
	* ```
	*
	* The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
	* @returns {string[]} Array of IP addresses from most to least trusted
	*/
	ips() {
		return proxyaddr.all(this.request, this.#config.trustProxy);
	}
	/**
	* Returns the request protocol by checking for the URL protocol or
	* `X-Forwarded-Proto` header.
	*
	* If the `trust` is evaluated to `false`, then URL protocol is returned,
	* otherwise `X-Forwarded-Proto` header is used (if exists).
	*
	* You can control the behavior of trusting the proxy values by defining it
	* inside the `config/app.js` file.
	*
	* ```js
	* {
	*   http: {
	*    trustProxy: '127.0.0.1'
	*   }
	* }
	* ```
	*
	* The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
	* @returns {string} Request protocol ('http' or 'https')
	*/
	protocol() {
		if ("encrypted" in this.request.socket) return "https";
		if (trustProxy(this.request.socket.remoteAddress, this.#config.trustProxy)) {
			const forwardedProtocol = this.header("X-Forwarded-Proto");
			return forwardedProtocol ? forwardedProtocol.split(/\s*,\s*/)[0] : "http";
		}
		return "http";
	}
	/**
	* Returns a boolean telling if request is served over `https`
	* or not. Check [[protocol]] method to know how protocol is
	* fetched.
	* @returns {boolean} True if request is served over HTTPS
	*/
	secure() {
		return this.protocol() === "https";
	}
	/**
	* Returns the request host. If proxy headers are trusted, then
	* `X-Forwarded-Host` is given priority over the `Host` header.
	*
	* You can control the behavior of trusting the proxy values by defining it
	* inside the `config/app.js` file.
	*
	* ```js
	* {
	*   http: {
	*    trustProxy: '127.0.0.1'
	*   }
	* }
	* ```
	*
	* The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
	* @returns {string | null} Request host or null if not found
	*/
	host() {
		let host = this.header("host");
		if (trustProxy(this.request.socket.remoteAddress, this.#config.trustProxy)) host = this.header("X-Forwarded-Host") || host;
		if (!host) return null;
		return host;
	}
	/**
	* Returns the HTTP/2 `:authority` pseudo-header, falling back to the
	* `Host` header when `:authority` is not present.
	*
	* Use this when you need a protocol-agnostic value for the request's
	* authority (host[:port]) — for example, when validating redirect
	* targets against the current request's origin.
	*
	* Unlike [[host]], this method does not consult `X-Forwarded-Host`
	* and is not affected by the `trustProxy` config, because no proxy
	* convention exists for forwarding the original `:authority`.
	*
	* @returns {string | null} The authority value or null if neither header is present
	*/
	authority() {
		return this.header(":authority") || this.host() || null;
	}
	/**
	* Returns the request hostname. If proxy headers are trusted, then
	* `X-Forwarded-Host` is given priority over the `Host` header.
	*
	* You can control the behavior of trusting the proxy values by defining it
	* inside the `config/app.js` file.
	*
	* ```js
	* {
	*   http: {
	*    trustProxy: '127.0.0.1'
	*   }
	* }
	* ```
	*
	* The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
	* @returns {string | null} Request hostname (without port) or null if not found
	*/
	hostname() {
		const host = this.host();
		if (!host) return null;
		const offset = host[0] === "[" ? host.indexOf("]") + 1 : 0;
		const index = host.indexOf(":", offset);
		return index !== -1 ? host.substring(0, index) : host;
	}
	/**
	* Returns an array of subdomains for the given host. An empty array is
	* returned if [[hostname]] is `null` or is an IP address.
	*
	* Also `www` is not considered as a subdomain
	* @returns {string[]} Array of subdomains (excluding www)
	*/
	subdomains() {
		const hostname = this.hostname();
		if (!hostname || isIP(hostname)) return [];
		const offset = this.#config.subdomainOffset;
		const subdomains = hostname.split(".").reverse().slice(offset);
		if (subdomains[subdomains.length - 1] === "www") subdomains.splice(subdomains.length - 1, 1);
		return subdomains;
	}
	/**
	* Returns a boolean telling, if request `X-Requested-With === 'xmlhttprequest'`
	* or not.
	* @returns {boolean} True if request is an AJAX request
	*/
	ajax() {
		return this.header("X-Requested-With", "").toLowerCase() === "xmlhttprequest";
	}
	/**
	* Returns a boolean telling, if request has `X-Pjax` header
	* set or not
	* @returns {boolean} True if request is a PJAX request
	*/
	pjax() {
		return !!this.header("X-Pjax");
	}
	/**
	* Returns a boolean telling, if the request is a speculative prefetch
	* (or prerender) request rather than a real navigation.
	*
	* Browsers advertise speculative intent via the Speculation Rules
	* `Sec-Purpose` header (e.g. `prefetch` or `prefetch;prerender`). Older
	* clients use the legacy `X-Moz` header, and libraries like Inertia.js
	* set the `Purpose` header. All three are checked.
	*
	* Use this to skip one-shot side effects (analytics, view counters,
	* single-use token rotation, etc.) that should only run on a real visit.
	*
	* @returns {boolean} True if the request is a speculative prefetch request
	*/
	prefetch() {
		return this.header("Sec-Purpose", "").toLowerCase().includes("prefetch") || this.header("Purpose", "").toLowerCase() === "prefetch" || this.header("X-Moz", "").toLowerCase() === "prefetch";
	}
	/**
	* Returns the request relative URL.
	*
	* @example
	* ```js
	* request.url()
	*
	* // include query string
	* request.url(true)
	* ```
	* @param includeQueryString - Whether to include query string in the URL
	* @returns {string} Request pathname, optionally with query string
	*/
	url(includeQueryString) {
		const pathname = this.parsedUrl.pathname;
		return includeQueryString && this.parsedUrl.query ? `${pathname}?${this.parsedUrl.query}` : pathname;
	}
	/**
	* Returns the complete HTTP url by combining
	* [[protocol]]://[[hostname]]/[[url]]
	*
	* @example
	* ```js
	* request.completeUrl()
	*
	* // include query string
	* request.completeUrl(true)
	* ```
	* @param includeQueryString - Whether to include query string in the URL
	* @returns {string} Complete URL including protocol and host
	*/
	completeUrl(includeQueryString) {
		return `${this.protocol()}://${this.host()}${this.url(includeQueryString)}`;
	}
	/**
	* Returns the previous URL from the `Referer` header, validated against
	* the request's `Host` header and an optional list of allowed hosts.
	*
	* The referrer is accepted when its host matches the request's `Host`
	* header or is listed in `allowedHosts`. Otherwise the `fallback`
	* value is returned.
	*
	* @param allowedHosts - Array of allowed referrer hosts
	* @param fallback - URL to return when referrer is missing or invalid
	*/
	getPreviousUrl(allowedHosts, fallback = "/") {
		return getPreviousUrl(this, allowedHosts, fallback);
	}
	/**
	* Find if the current HTTP request is for the given route or the routes
	* @param routeIdentifier - Route name, pattern, or handler reference to match
	* @returns {boolean} True if the request matches any of the given route identifiers
	*/
	matchesRoute(routeIdentifier) {
		/**
		* The context is missing inside the HTTP server hooks.
		*/
		if (!this.ctx || !this.ctx.route) return false;
		const route = this.ctx.route;
		/**
		* Search the identifier(s) against the route "pattern", "name" and the route handler
		*/
		return !!(Array.isArray(routeIdentifier) ? routeIdentifier : [routeIdentifier]).find((identifier) => {
			if (route.pattern === identifier || route.name === identifier) return true;
			if (typeof route.handler === "function") return false;
			return route.handler.reference === identifier;
		});
	}
	/**
	* Returns the best matching content type of the request by
	* matching against the given types.
	*
	* The content type is picked from the `content-type` header and request
	* must have body.
	*
	* The method response highly depends upon the types array values. Described below:
	*
	* | Type(s) | Return value |
	* |----------|---------------|
	* | ['json'] | json |
	* | ['application/*'] | application/json |
	* | ['vnd+json'] | application/json |
	*
	* @example
	* ```js
	* const bodyType = request.is(['json', 'xml'])
	*
	* if (bodyType === 'json') {
	*  // process JSON
	* }
	*
	* if (bodyType === 'xml') {
	*  // process XML
	* }
	* ```
	* @param types - Array of content types to match against
	* @returns {string | null} Best matching content type or null if no match
	*/
	is(types) {
		return typeIs(this.request, types) || null;
	}
	/**
	* Returns the best type using `Accept` header and
	* by matching it against the given types.
	*
	* If nothing is matched, then `null` will be returned
	*
	* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
	* docs too.
	*
	* @example
	* ```js
	* switch (request.accepts(['json', 'html'])) {
	*   case 'json':
	*     return response.json(user)
	*   case 'html':
	*     return view.render('user', { user })
	*   default:
	*     // decide yourself
	* }
	* ```
	* @param types - Array of types to match against Accept header
	* @returns {T | null} Best matching accept type or null if no match
	*/
	accepts(types) {
		this.#initiateAccepts();
		return this.#lazyAccepts.type(types) || null;
	}
	/**
	* Return the types that the request accepts, in the order of the
	* client's preference (most preferred first).
	*
	* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
	* docs too.
	* @returns {string[]} Array of accepted types in preference order
	*/
	types() {
		this.#initiateAccepts();
		return this.#lazyAccepts.types();
	}
	/**
	* Returns the best language using `Accept-language` header
	* and by matching it against the given languages.
	*
	* If nothing is matched, then `null` will be returned
	*
	* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
	* docs too.
	*
	* @example
	* ```js
	* switch (request.language(['fr', 'de'])) {
	*   case 'fr':
	*     return view.render('about', { lang: 'fr' })
	*   case 'de':
	*     return view.render('about', { lang: 'de' })
	*   default:
	*     return view.render('about', { lang: 'en' })
	* }
	* ```
	* @param languages - Array of languages to match against Accept-Language header
	* @returns {T | null} Best matching language or null if no match
	*/
	language(languages) {
		this.#initiateAccepts();
		return this.#lazyAccepts.language(languages) || null;
	}
	/**
	* Return the languages that the request accepts, in the order of the
	* client's preference (most preferred first).
	*
	* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
	* docs too.
	* @returns {string[]} Array of accepted languages in preference order
	*/
	languages() {
		this.#initiateAccepts();
		return this.#lazyAccepts.languages();
	}
	/**
	* Returns the best charset using `Accept-charset` header
	* and by matching it against the given charsets.
	*
	* If nothing is matched, then `null` will be returned
	*
	* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
	* docs too.
	*
	* @example
	* ```js
	* switch (request.charset(['utf-8', 'ISO-8859-1'])) {
	*   case 'utf-8':
	*     // make utf-8 friendly response
	*   case 'ISO-8859-1':
	*     // make ISO-8859-1 friendly response
	* }
	* ```
	* @param charsets - Array of charsets to match against Accept-Charset header
	* @returns {T | null} Best matching charset or null if no match
	*/
	charset(charsets) {
		this.#initiateAccepts();
		return this.#lazyAccepts.charset(charsets) || null;
	}
	/**
	* Return the charsets that the request accepts, in the order of the
	* client's preference (most preferred first).
	*
	* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
	* docs too.
	* @returns {string[]} Array of accepted charsets in preference order
	*/
	charsets() {
		this.#initiateAccepts();
		return this.#lazyAccepts.charsets();
	}
	/**
	* Returns the best encoding using `Accept-encoding` header
	* and by matching it against the given encodings.
	*
	* If nothing is matched, then `null` will be returned
	*
	* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
	* docs too.
	* @param encodings - Array of encodings to match against Accept-Encoding header
	* @returns {T | null} Best matching encoding or null if no match
	*/
	encoding(encodings) {
		this.#initiateAccepts();
		return this.#lazyAccepts.encoding(encodings) || null;
	}
	/**
	* Return the encodings that the request accepts, in the order of the
	* client's preference (most preferred first).
	*
	* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
	* docs too.
	* @returns {string[]} Array of accepted encodings in preference order
	*/
	encodings() {
		this.#initiateAccepts();
		return this.#lazyAccepts.encodings();
	}
	/**
	* Returns a boolean telling if request has body
	* @returns {boolean} True if request contains a body
	*/
	hasBody() {
		return typeIs.hasBody(this.request);
	}
	/**
	* Returns a boolean telling if the new response etag evaluates same
	* as the request header `if-none-match`. In case of `true`, the
	* server must return `304` response, telling the browser to
	* use the client cache.
	*
	* You won't have to deal with this method directly, since AdonisJs will
	* handle this for you when `http.etag = true` inside `config/app.js` file.
	*
	* However, this is how you can use it manually.
	*
	* ```js
	* const responseBody = view.render('some-view')
	*
	* // sets the HTTP etag header for response
	* response.setEtag(responseBody)
	*
	* if (request.fresh()) {
	*   response.sendStatus(304)
	* } else {
	*   response.send(responseBody)
	* }
	* ```
	* @returns {boolean} True if client cache is fresh (should return 304)
	*/
	fresh() {
		if (!["GET", "HEAD"].includes(this.intended())) return false;
		const status = this.response.statusCode;
		if (status >= 200 && status < 300 || status === 304) return fresh(this.headers(), this.response.getHeaders());
		return false;
	}
	/**
	* Opposite of [[fresh]]
	* @returns {boolean} True if client cache is stale (should send new response)
	*/
	stale() {
		return !this.fresh();
	}
	/**
	* Returns all parsed and signed cookies. Signed cookies ensures
	* that their value isn't tampered.
	* @returns {{ [key: string]: any }} Object containing all parsed cookies
	*/
	cookiesList() {
		this.#initiateCookieParser();
		return this.#cookieParser.list();
	}
	/**
	* Returns value for a given key from signed cookies. Optional
	* defaultValue is returned when actual value is undefined.
	* @param key - Cookie name to lookup
	* @param defaultValue - Default value when cookie is not found
	* @returns Cookie value or default value if not found
	*/
	cookie(key, defaultValue) {
		this.#initiateCookieParser();
		return this.#cookieParser.unsign(key) || defaultValue;
	}
	/**
	* Returns value for a given key from encrypted cookies. Optional
	* defaultValue is returned when actual value is undefined.
	* @param key - Cookie name to lookup
	* @param defaultValue - Default value when cookie is not found
	* @returns Decrypted cookie value or default value if not found
	*/
	encryptedCookie(key, defaultValue) {
		this.#initiateCookieParser();
		return this.#cookieParser.decrypt(key) || defaultValue;
	}
	plainCookie(key, defaultValueOrOptions, encoded) {
		this.#initiateCookieParser();
		if (is.object(defaultValueOrOptions)) return this.#cookieParser.decode(key, defaultValueOrOptions?.encoded) || defaultValueOrOptions.defaultValue;
		return this.#cookieParser.decode(key, encoded) || defaultValueOrOptions;
	}
	/**
	* Returns a boolean telling if a signed url has a valid signature
	* or not.
	* @param purpose - Optional purpose for signature verification
	* @returns {boolean} True if the signed URL has a valid signature
	*/
	hasValidSignature(purpose) {
		const { signature, ...rest } = this.qs();
		if (!signature) return false;
		const signedUrl = this.#encryption.getMessageVerifier().unsign(signature, purpose);
		if (!signedUrl) return false;
		const queryString = this.#qsParser.stringify(rest);
		return queryString ? safeEqual(signedUrl, `${this.url()}?${queryString}`) : safeEqual(signedUrl, this.url());
	}
	/**
	* Serializes request to JSON format
	* @returns Object representation of the request
	*/
	serialize() {
		return {
			id: this.id(),
			url: this.url(),
			query: this.parsedUrl.query,
			body: this.all(),
			params: this.params(),
			headers: this.headers(),
			method: this.method(),
			protocol: this.protocol(),
			cookies: this.cookiesList(),
			hostname: this.hostname(),
			ip: this.ip(),
			subdomains: this.ctx?.subdomains || {}
		};
	}
	/**
	* toJSON copy of the request
	* @returns JSON representation of the request
	*/
	toJSON() {
		return this.serialize();
	}
};
//#endregion
//#region src/router/store.ts
/**
* Store class is used to store a list of routes, along side with their tokens
* to match the URLs.
*
* ```ts
* const store = new Store()
*
* store.add({
*  pattern: 'posts/:id',
*  handler: function onRoute () {},
*  middleware: [],
*  matchers: {
*    id: '^[0-9]$+'
*  },
*  meta: {},
*  methods: ['GET']
* })
*
* store.match('posts/1', 'GET')
* ```
*/
var RoutesStore = class {
	/**
	* A flag to know if routes for explicit domains
	* have been registered
	*/
	usingDomains = false;
	/**
	* Tree of registered routes and their matchit tokens
	*/
	tree = {
		tokens: [],
		domains: {}
	};
	/**
	* Returns the domain node for a given domain.
	*/
	#getDomainNode(domain) {
		if (!this.tree.domains[domain]) {
			this.tree.tokens.push(parseRoute(domain));
			this.tree.domains[domain] = {};
		}
		return this.tree.domains[domain];
	}
	/**
	* Returns the method node for a given domain and method.
	*/
	#getMethodNode(domain, method) {
		const domainNode = this.#getDomainNode(domain);
		if (!domainNode[method]) domainNode[method] = {
			tokens: [],
			routes: {},
			routeKeys: {}
		};
		return domainNode[method];
	}
	/**
	* Collects route params
	*/
	#collectRouteParams(route, tokens) {
		const collectedParams = /* @__PURE__ */ new Set();
		for (let token of tokens) if ([1, 3].includes(token.type)) if (collectedParams.has(token.val)) throw new RuntimeException(`Duplicate param "${token.val}" found in "${route.pattern}"`);
		else collectedParams.add(token.val);
		const params = [...collectedParams];
		collectedParams.clear();
		return params;
	}
	/**
	* Register route for a given domain and method
	*/
	#registerRoute(domain, method, tokens, route) {
		const methodRoutes = this.#getMethodNode(domain, method);
		if (methodRoutes.routes[route.pattern]) throw new RuntimeException(`Duplicate route found. "${method}: ${route.pattern}" route already exists`);
		if (debug_default.enabled) {
			debug_default("registering route to the store %O", route);
			debug_default("route middleware %O", route.middleware.all().entries());
		}
		methodRoutes.tokens.push(tokens);
		methodRoutes.routes[route.pattern] = route;
		methodRoutes.routeKeys[route.pattern] = domain !== "root" ? `${domain}-${method}-${route.pattern}` : `${method}-${route.pattern}`;
	}
	/**
	* Add a route to the store
	*
	* ```ts
	* store.add({
	*   pattern: 'post/:id',
	*   methods: ['GET'],
	*   matchers: {},
	*   meta: {},
	*   handler: function handler () {
	*   }
	* })
	* ```
	* @param route - The route to add to the store
	* @returns Current RoutesStore instance for method chaining
	*/
	add(route) {
		/**
		* Set flag when a custom domain is used
		*/
		if (route.domain !== "root") this.usingDomains = true;
		/**
		* Create route node object for persistence
		*/
		const routeNode = { ...route };
		/**
		* Set route params
		*/
		routeNode.meta.params = this.#collectRouteParams(routeNode, route.tokens);
		/**
		* Register route for every method
		*/
		route.methods.forEach((method) => {
			this.#registerRoute(route.domain, method, route.tokens, routeNode);
		});
		return this;
	}
	/**
	* Matches the url, method and optionally domain to pull the matching
	* route. `null` is returned when unable to match the URL against
	* registered routes.
	*
	* The domain parameter has to be a registered pattern and not the fully
	* qualified runtime domain. You must call `matchDomain` first to fetch
	* the pattern for qualified domain
	* @param url - The URL to match
	* @param method - HTTP method
	* @param shouldDecodeParam - Whether to decode parameters
	* @param domain - Optional domain tokens and hostname
	* @returns Matched route or null if no match found
	*/
	match(url, method, shouldDecodeParam, domain) {
		const domainName = domain?.tokens[0]?.old || "root";
		if (!this.tree.domains[domainName]) return null;
		const matchedMethod = this.tree.domains[domainName][method];
		if (!matchedMethod) return null;
		const matchedRoute = matchit.match(url, matchedMethod.tokens);
		if (!matchedRoute.length) return null;
		const route = matchedMethod.routes[matchedRoute[0].old];
		return {
			route,
			routeKey: matchedMethod.routeKeys[route.pattern],
			params: matchit.exec(url, matchedRoute, shouldDecodeParam),
			subdomains: domain?.hostname ? matchit.exec(domain.hostname, domain.tokens) : {}
		};
	}
	/**
	* Match hostname against registered domains.
	* @param hostname - The hostname to match
	* @returns Array of matched domain tokens
	*/
	matchDomain(hostname) {
		if (!hostname || !this.usingDomains) return [];
		return matchit.match(hostname, this.tree.tokens);
	}
};
//#endregion
//#region src/router/legacy/url_builder.ts
/**
* URL builder class is used to create URIs for pre-registered
* routes.
*
* ```ts
* const builder = new UrlBuilder(encryption, routeFinder)
*
* builder
*  .qs({ sort: 'id' })
*  .params([category.id])
*  .make('categories.posts.index')
* ```
*
* @deprecated Instead use "@adonisjs/core/services/url_builder" instead
*/
var UrlBuilder = class {
	/**
	* The parameters to apply on the route
	*/
	#params = {};
	/**
	* Query string to append to the route
	*/
	#qs = {};
	/**
	* Should we perform the route lookup or just build the
	* given pattern as it is.
	*/
	#shouldPerformLookup = true;
	/**
	* BaseURL to append to the constructored URL
	*/
	#baseUrl;
	/**
	* Route finder for finding route pattern
	*/
	#router;
	/**
	* Domain to use for URL generation
	*/
	#domain;
	/**
	* Creates a new UrlBuilder instance
	* @param router - The router instance
	* @param domain - Optional domain for URL generation
	*/
	constructor(router, domain) {
		this.#router = router;
		this.#domain = domain;
	}
	/**
	* Prefix a custom base URL to the final URI
	* @deprecated Instead use "@adonisjs/core/services/url_builder" instead
	*/
	prefixUrl(url) {
		this.#baseUrl = url;
		return this;
	}
	/**
	* Disable route lookup. Calling this method considers
	* the "identifier" as the route pattern
	* @deprecated Instead use "@adonisjs/core/services/url_builder" instead
	*/
	disableRouteLookup() {
		this.#shouldPerformLookup = false;
		return this;
	}
	/**
	* Append query string to the final URI
	* @deprecated Instead use "@adonisjs/core/services/url_builder" instead
	*/
	qs(queryString) {
		if (!queryString) return this;
		this.#qs = queryString;
		return this;
	}
	/**
	* Specify params to apply to the route pattern
	* @deprecated Instead use "@adonisjs/core/services/url_builder" instead
	*/
	params(params) {
		if (!params) return this;
		this.#params = params;
		return this;
	}
	/**
	* Generate URL for the given route identifier. The identifier can be the
	* route name, controller.method name or the route pattern
	* itself.
	*
	* @deprecated Instead use "@adonisjs/core/services/url_builder" instead
	* @param identifier - Route identifier to generate URL for
	* @returns Generated URL string
	*/
	make(identifier) {
		return this.#router.makeUrl(identifier, this.#params, {
			prefixUrl: this.#baseUrl,
			disableRouteLookup: !this.#shouldPerformLookup,
			domain: this.#domain,
			qs: this.#qs
		});
	}
	/**
	* Generate a signed URL for the given route identifier. The identifier can be the
	* route name, controller.method name or the route pattern
	* itself.
	*
	* @deprecated Instead use "@adonisjs/core/services/url_builder" instead
	*
	*/
	makeSigned(identifier, options) {
		return this.#router.makeSignedUrl(identifier, this.#params, {
			prefixUrl: this.#baseUrl,
			disableRouteLookup: !this.#shouldPerformLookup,
			domain: this.#domain,
			qs: this.#qs,
			...options
		});
	}
};
//#endregion
//#region src/router/matchers.ts
/**
* Shortcut methods for commonly used route matchers
*/
var RouteMatchers = class extends Macroable {
	/**
	* Enforce value to be a number and also casts it to number data
	* type
	* @returns Route matcher configuration for numeric values
	*/
	number() {
		return {
			match: /^[0-9]+$/,
			cast: (value) => Number(value)
		};
	}
	/**
	* Enforce value to be formatted as uuid
	* @returns Route matcher configuration for UUID values
	*/
	uuid() {
		return {
			match: /^[0-9a-zA-F]{8}-[0-9a-zA-F]{4}-[0-9a-zA-F]{4}-[0-9a-zA-F]{4}-[0-9a-zA-F]{12}$/,
			cast: (value) => value.toLowerCase()
		};
	}
	/**
	* Enforce value to be formatted as slug
	* @returns Route matcher configuration for slug values
	*/
	slug() {
		return { match: /^[^\s-_](?!.*?[-_]{2,})([a-z0-9-\\]{1,})[^\s]*[^-_\s]$/ };
	}
};
//#endregion
//#region src/define_middleware.ts
/**
* Converts a middleware name and its lazy import to a factory function.
*
* The returned function can be used to reference the middleware with different
* arguments every time, creating a parsed middleware object that contains all
* necessary metadata for execution.
*
* @param name - The name of the middleware
* @param middleware - Lazy import reference to the middleware class
*/
function middlewareReferenceBuilder(name, middleware) {
	const handler = moduleImporter(middleware, "handle").toHandleMethod();
	return function(...args) {
		return {
			...handler,
			name,
			reference: middleware,
			args: args[0]
		};
	};
}
/**
* Define a collection of named middleware that can be referenced by name in routes and route groups.
*
* This function converts a collection of middleware classes into factory functions that can be
* called with arguments to create middleware references. Each middleware in the collection
* becomes available as a typed function that preserves the middleware's argument signature.
*
* @param collection - Object mapping middleware names to their lazy import references
*
* @example
* ```ts
* const namedMiddleware = defineNamedMiddleware({
*   auth: () => import('./middleware/auth.ts'),
*   throttle: () => import('./middleware/throttle.ts')
* })
*
* // Usage in routes
* router.get('/dashboard', [namedMiddleware.auth(), handler])
* router.get('/api/data', [namedMiddleware.throttle({ max: 100 }), handler])
* ```
*/
function defineNamedMiddleware(collection) {
	return Object.keys(collection).reduce((result, key) => {
		result[key] = middlewareReferenceBuilder(key, collection[key]);
		return result;
	}, {});
}
//#endregion
//#region src/router/signed_url_builder.ts
/**
* Creates the URLBuilder helper for making signed URLs
* @param router - The router instance
* @param encryption - Encryption service for signing URLs
* @param searchParamsStringifier - Function to stringify query string parameters
* @returns URL builder function for creating signed URLs
*/
function createSignedUrlBuilder(router, encryption, searchParamsStringifier) {
	let domainsList;
	function createSignedUrlForRoute(identifier, params, options, method) {
		if (!domainsList) domainsList = Object.keys(router.toJSON()).filter((domain) => domain !== "root");
		const domain = domainsList.find((name) => identifier.startsWith(`${name}@`));
		const routeIdentifier = domain ? identifier.replace(new RegExp(`^${domain}@`), "") : identifier;
		const route = router.findOrFail(routeIdentifier, domain, method, true);
		return createSignedURL(route.name ?? route.pattern, route.tokens, searchParamsStringifier, encryption, params, options);
	}
	const signedRoute = function route(...[identifier, params, options]) {
		return createSignedUrlForRoute(identifier, params, options);
	};
	signedRoute.get = function routeGet(...[identifier, params, options]) {
		const method = "GET";
		const url = createSignedUrlForRoute(identifier, params, options, method);
		return {
			url,
			method,
			toString() {
				return url;
			},
			form: {
				action: url,
				method
			}
		};
	};
	signedRoute.post = function routePost(...[identifier, params, options]) {
		const method = "POST";
		const url = createSignedUrlForRoute(identifier, params, options, method);
		return {
			url,
			method,
			toString() {
				return url;
			},
			form: {
				action: url,
				method
			}
		};
	};
	signedRoute.put = function routePut(...[identifier, params, options]) {
		const method = "PUT";
		const url = createSignedUrlForRoute(identifier, params, options, method);
		return {
			url,
			method,
			toString() {
				return url;
			},
			form: {
				action: url,
				method
			}
		};
	};
	signedRoute.patch = function routePatch(...[identifier, params, options]) {
		const method = "PATCH";
		const url = createSignedUrlForRoute(identifier, params, options, method);
		return {
			url,
			method,
			toString() {
				return url;
			},
			form: {
				action: url,
				method
			}
		};
	};
	signedRoute.delete = function routeDelete(...[identifier, params, options]) {
		const method = "DELETE";
		const url = createSignedUrlForRoute(identifier, params, options, method);
		return {
			url,
			method,
			toString() {
				return url;
			},
			form: {
				action: url,
				method
			}
		};
	};
	signedRoute.method = function routeGet(method, ...[identifier, params, options]) {
		const url = createSignedUrlForRoute(identifier, params, options, method);
		return {
			url,
			method,
			toString() {
				return url;
			},
			form: {
				action: url,
				method
			}
		};
	};
	return signedRoute;
}
//#endregion
//#region src/router/main.ts
/**
* Router class exposes a unified API to register new routes, group them or
* create route resources.
*
* ```ts
* const router = new Router()
*
* router.get('/', async function () {
*   // handle request
* })
* ```
*/
var Router = class extends Macroable {
	/**
	* Flag to avoid re-comitting routes to the store
	*/
	#commited = false;
	/**
	* Application is needed to resolve string based controller expressions
	*/
	#app;
	/**
	* Store with tokenized routes
	*/
	#store = new RoutesStore();
	/**
	* Encryption for making signed URLs
	*/
	#encryption;
	/**
	* Global matchers to test route params against regular expressions.
	*/
	#globalMatchers = {};
	/**
	* Middleware store to be shared with the routes
	*/
	#middleware = [];
	/**
	* A boolean to tell the router that a group is in
	* open state right now
	*/
	#openedGroups = [];
	/**
	* Collection of routes to be committed with the store, including
	* route resource and route group.
	*/
	#routesToBeCommitted = [];
	/**
	* A flag to know if routes for explicit domains have been registered.
	* The boolean is computed after calling the "commit" method.
	*/
	usingDomains = false;
	/**
	* Shortcut methods for commonly used route matchers
	*/
	matchers = new RouteMatchers();
	/**
	* Check if routes have been committed to the store. Once
	* routes are committed, defining new set of routes will
	* have no impact
	*/
	get commited() {
		return this.#commited;
	}
	/**
	* Query string parser for making URLs
	*/
	qs;
	/**
	* The URLBuilder offers a type-safe API for creating URL for pre-registered
	* routes or the route patterns.
	*
	* We recommend using the URLBuilder over the "makeUrl" and "makeSignedUrl"
	* methods.
	*/
	urlBuilder;
	/**
	* List of route references kept for lookup.
	*/
	routes = {};
	/**
	* Creates a new Router instance
	* @param app - The AdonisJS application instance
	* @param encryption - Encryption service for signed URLs
	* @param qsParser - Query string parser for URL generation
	*/
	constructor(app, encryption, qsParser) {
		super();
		this.#app = app;
		this.#encryption = encryption;
		this.qs = qsParser;
		this.urlBuilder = {
			urlFor: createUrlBuilder(() => this.toJSON(), this.qs.stringify),
			signedUrlFor: createSignedUrlBuilder(this, this.#encryption, this.qs.stringify)
		};
	}
	/**
	* Register route JSON payload
	*/
	register(route) {
		this.routes[route.domain] = this.routes[route.domain] || [];
		this.routes[route.domain].push(route);
	}
	/**
	* Push a give router entity to the list of routes or the
	* recently opened group.
	*/
	#pushToRoutes(entity) {
		const openedGroup = this.#openedGroups[this.#openedGroups.length - 1];
		if (openedGroup) {
			openedGroup.routes.push(entity);
			return;
		}
		this.#routesToBeCommitted.push(entity);
	}
	/**
	* Parses the route pattern
	* @param pattern - The route pattern to parse
	* @param matchers - Optional route matchers
	*/
	parsePattern(pattern, matchers) {
		return parseRoute(pattern, matchers);
	}
	/**
	* Define an array of middleware to use on all the routes.
	* Calling this method multiple times pushes to the
	* existing list of middleware
	* @param middleware - Array of middleware classes to apply globally
	* @returns Current Router instance for method chaining
	*/
	use(middleware) {
		middleware.forEach((one) => this.#middleware.push({
			reference: one,
			...moduleImporter(one, "handle").toHandleMethod()
		}));
		return this;
	}
	/**
	* Define a collection of named middleware. The defined collection is
	* not registered anywhere, but instead converted in a new collection
	* of functions you can apply on the routes, or router groups.
	* @param collection - Object mapping middleware names to middleware classes
	* @returns Named middleware functions
	*/
	named(collection) {
		return defineNamedMiddleware(collection);
	}
	/**
	* Add route for a given pattern and methods
	* @param pattern - The route pattern
	* @param methods - Array of HTTP methods
	* @param handler - Route handler (function, string, or controller tuple)
	* @returns The created route instance
	*/
	route(pattern, methods, handler) {
		const route = new Route(this.#app, this.#middleware, {
			pattern,
			methods,
			handler,
			globalMatchers: this.#globalMatchers
		});
		this.#pushToRoutes(route);
		return route;
	}
	/**
	* Define a route that handles all common HTTP methods
	* @param pattern - The route pattern
	* @param handler - Route handler (function, string, or controller tuple)
	* @returns The created route instance
	*/
	any(pattern, handler) {
		return this.route(pattern, [
			"HEAD",
			"OPTIONS",
			"GET",
			"POST",
			"PUT",
			"PATCH",
			"DELETE"
		], handler);
	}
	/**
	* Define `GET` route
	* @param pattern - The route pattern
	* @param handler - Route handler (function, string, or controller tuple)
	* @returns The created route instance
	*/
	get(pattern, handler) {
		return this.route(pattern, ["GET", "HEAD"], handler);
	}
	/**
	* Define `POST` route
	* @param pattern - The route pattern
	* @param handler - Route handler (function, string, or controller tuple)
	* @returns The created route instance
	*/
	post(pattern, handler) {
		return this.route(pattern, ["POST"], handler);
	}
	/**
	* Define `PUT` route
	* @param pattern - The route pattern
	* @param handler - Route handler (function, string, or controller tuple)
	* @returns The created route instance
	*/
	put(pattern, handler) {
		return this.route(pattern, ["PUT"], handler);
	}
	/**
	* Define `PATCH` route
	* @param pattern - The route pattern
	* @param handler - Route handler (function, string, or controller tuple)
	* @returns The created route instance
	*/
	patch(pattern, handler) {
		return this.route(pattern, ["PATCH"], handler);
	}
	/**
	* Define `DELETE` route
	* @param pattern - The route pattern
	* @param handler - Route handler (function, string, or controller tuple)
	* @returns The created route instance
	*/
	delete(pattern, handler) {
		return this.route(pattern, ["DELETE"], handler);
	}
	/**
	* Creates a group of routes. A route group can apply transforms
	* to routes in bulk
	* @param callback - Function that defines routes within the group
	* @returns The created route group instance
	*/
	group(callback) {
		const group = new RouteGroup([]);
		/**
		* Track group
		*/
		this.#pushToRoutes(group);
		this.#openedGroups.push(group);
		callback();
		this.#openedGroups.pop();
		return group;
	}
	/**
	* Registers a route resource with conventional set of routes
	* @param resource - The resource name
	* @param controller - Controller to handle the resource
	* @returns The created route resource instance
	*/
	resource(resource, controller) {
		const resourceInstance = new RouteResource(this.#app, this.#middleware, {
			resource,
			controller,
			shallow: false,
			globalMatchers: this.#globalMatchers
		});
		this.#pushToRoutes(resourceInstance);
		return resourceInstance;
	}
	/**
	* Register a route resource with shallow nested routes.
	* @param resource - The resource name
	* @param controller - Controller to handle the resource
	* @returns The created route resource instance
	*/
	shallowResource(resource, controller) {
		const resourceInstance = new RouteResource(this.#app, this.#middleware, {
			resource,
			controller,
			shallow: true,
			globalMatchers: this.#globalMatchers
		});
		this.#pushToRoutes(resourceInstance);
		return resourceInstance;
	}
	/**
	* Returns a brisk route instance for a given URL pattern
	* @param pattern - The route pattern
	* @returns The created brisk route instance
	*/
	on(pattern) {
		const briskRoute = new BriskRoute(this.#app, this.#middleware, {
			pattern,
			globalMatchers: this.#globalMatchers
		});
		this.#pushToRoutes(briskRoute);
		return briskRoute;
	}
	/**
	* Define matcher for a given param. The global params are applied
	* on all the routes (unless overridden at the route level).
	* @param param - The parameter name to match
	* @param matcher - The matcher pattern (RegExp, string, or RouteMatcher)
	* @returns Current Router instance for method chaining
	*/
	where(param, matcher) {
		if (typeof matcher === "string") this.#globalMatchers[param] = { match: new RegExp(matcher) };
		else if (is.regExp(matcher)) this.#globalMatchers[param] = { match: matcher };
		else this.#globalMatchers[param] = matcher;
		return this;
	}
	/**
	* Commit routes to the store. The router is freezed after the
	* commit method is called.
	*/
	commit() {
		if (this.#commited) return;
		debug_default("Committing routes to the routes store");
		const routeNamesByDomain = /* @__PURE__ */ new Map();
		toRoutesJSON(this.#routesToBeCommitted).forEach((route) => {
			if (!routeNamesByDomain.has(route.domain)) routeNamesByDomain.set(route.domain, /* @__PURE__ */ new Set());
			const routeNames = routeNamesByDomain.get(route.domain);
			if (route.name && routeNames.has(route.name)) throw new RuntimeException(`A route with name "${route.name}" already exists. It may happen when two routes use the same controller, so make sure to give explicit names to these routes`);
			if (route.name) routeNames.add(route.name);
			/**
			* Register the route with the lookup store
			*/
			this.register(route);
			this.#store.add(route);
		});
		routeNamesByDomain.clear();
		this.usingDomains = this.#store.usingDomains;
		this.#routesToBeCommitted = [];
		this.#globalMatchers = {};
		this.#middleware = [];
		this.#openedGroups = [];
		this.#commited = true;
	}
	/**
	* Finds a route by its identifier. The identifier can be the
	* route name, controller.method name or the route pattern
	* itself.
	*
	* When "disableLegacyLookup" is set, the lookup will be performed
	* only using the route name
	* @param routeIdentifier - Route name, pattern, or controller reference
	* @param domain - Optional domain to search within
	* @param method - Optional HTTP method to filter by
	* @param disableLegacyLookup - Whether to disable legacy lookup strategies
	* @returns Found route or null if not found
	*/
	find(routeIdentifier, domain, method, disableLegacyLookup) {
		return findRoute(this.routes, routeIdentifier, domain, method, disableLegacyLookup);
	}
	/**
	* Finds a route by its identifier. The identifier can be the
	* route name, controller.method name or the route pattern
	* itself.
	*
	* An error is raised when unable to find the route.
	*
	* When "disableLegacyLookup" is set, the lookup will be performed
	* only using the route name
	* @param routeIdentifier - Route name, pattern, or controller reference
	* @param domain - Optional domain to search within
	* @param method - Optional HTTP method to filter by
	* @param disableLegacyLookup - Whether to disable legacy lookup strategies
	* @returns Found route
	* @throws Error when route is not found
	*/
	findOrFail(routeIdentifier, domain, method, disableLegacyLookup) {
		const route = this.find(routeIdentifier, domain, method, disableLegacyLookup);
		if (!route) {
			if (method) throw new Error(`Cannot lookup route "${routeIdentifier}" for method "${method}"`);
			throw new Error(`Cannot lookup route "${routeIdentifier}"`);
		}
		return route;
	}
	/**
	* Check if a route exists. The identifier can be the
	* route name, controller.method name or the route pattern
	* itself.
	*
	* When "followLookupStrategy" is enabled, the lookup will be performed
	* on the basis of the lookup strategy enabled via the "lookupStrategies"
	* method. The default lookupStrategy is "name" and "pattern".
	* @param routeIdentifier - Route name, pattern, or controller reference
	* @param domain - Optional domain to search within
	* @param method - Optional HTTP method to filter by
	* @param followLookupStrategy - Whether to follow the configured lookup strategy
	* @returns True if route exists, false otherwise
	*/
	has(routeIdentifier, domain, method, followLookupStrategy) {
		return !!this.find(routeIdentifier, domain, method, followLookupStrategy);
	}
	/**
	* Returns a list of routes grouped by their domain names
	* @returns Object mapping domain names to route arrays
	*/
	toJSON() {
		return this.routes;
	}
	/**
	* Generates types for the URL builder. These types must
	* be written inside a file for the URL builder to
	* pick them up.
	* @param indentation - Indentation level for generated types
	* @returns Generated TypeScript types as string
	*/
	generateTypes(indentation = 0) {
		const routesList = {};
		/**
		* Tracks a route within the routesList
		*/
		function trackRoute(route, domain) {
			let params = [];
			let paramsTuple = [];
			let hasRequiredParams = false;
			/**
			* Looping over tokens to build the params object and
			* the params tuple
			*/
			for (let token of route.tokens) if (token.type === 1) {
				hasRequiredParams = true;
				params.push(`'${token.val}': ParamValue`);
				paramsTuple.push("ParamValue");
			} else if (token.type === 3) {
				params.push(`'${token.val}'?: ParamValue`);
				paramsTuple.push("ParamValue?");
			} else if (token.type === 2) {
				hasRequiredParams = true;
				params.push(`'*': ParamValue[]`);
				paramsTuple.push("...ParamValue[]");
				break;
			}
			route.methods.forEach((method) => {
				routesList["ALL"] = routesList["ALL"] ?? {};
				routesList[method] = routesList[method] ?? {};
				const identifiers = [];
				/**
				* Tracking route by its name. In case the same route already exists, we
				* will prefix the domain to the route name to create a unique identifier.
				*/
				if (route.name) identifiers.push(domain && routesList[method][route.name] ? `${domain}@${route.name}` : route.name);
				identifiers.forEach((identifier) => {
					routesList["ALL"][identifier] = {
						params,
						paramsTuple,
						hasRequiredParams
					};
					routesList[method][identifier] = {
						params,
						paramsTuple,
						hasRequiredParams
					};
				});
			});
		}
		const domains = Object.keys(this.routes).filter((domain) => domain !== "root");
		/**
		* Create routes list for all the domains. However, the root routes should
		* be registered first so that they do not have any domain prefix in case
		* of a naming conflict.
		*/
		this.routes["root"]?.forEach((route) => trackRoute.bind(this)(route));
		domains.forEach((domain) => this.routes[domain].forEach((route) => trackRoute.bind(this)(route, domain)));
		return {
			imports: [],
			types: ["type ParamValue = string | number | bigint | boolean"],
			routes: Object.keys(routesList).reduce((result, method) => {
				result.push(`${" ".repeat(indentation)}${method}: {`);
				Object.keys(routesList[method]).forEach((identifier) => {
					const key = `'${identifier}'`;
					const { paramsTuple, hasRequiredParams, params } = routesList[method][identifier];
					const dictName = hasRequiredParams ? "params" : "params?";
					const tupleName = hasRequiredParams ? "paramsTuple" : "paramsTuple?";
					const dictValue = `{${params.join(",")}}`;
					const value = `{ ${tupleName}: ${`[${paramsTuple?.join(",")}]`}; ${dictName}: ${dictValue} }`;
					result.push(`${" ".repeat(indentation + 2)}${key}: ${value}`);
				});
				result.push(`${" ".repeat(indentation)}}`);
				return result;
			}, []).join("\n")
		};
	}
	/**
	* Find route for a given URL, method and optionally domain
	* @param uri - The URI to match
	* @param method - HTTP method
	* @param shouldDecodeParam - Whether to decode parameters
	* @param hostname - Optional hostname for domain matching
	* @returns Matched route or null if no match found
	*/
	match(uri, method, shouldDecodeParam, hostname) {
		const matchingDomain = this.#store.matchDomain(hostname);
		return matchingDomain.length ? this.#store.match(uri, method, shouldDecodeParam, {
			tokens: matchingDomain,
			hostname
		}) : this.#store.match(uri, method, shouldDecodeParam);
	}
	/**
	* Create URL builder instance.
	* @deprecated Instead use "@adonisjs/core/services/url_builder" instead
	*/
	builder() {
		return new UrlBuilder(this);
	}
	/**
	* Create URL builder instance for a given domain.
	* @deprecated
	*
	* Instead use "@adonisjs/core/services/url_builder"
	*/
	builderForDomain(domain) {
		return new UrlBuilder(this, domain);
	}
	/**
	* Make URL to a pre-registered route
	*
	* @deprecated
	* Instead use "@adonisjs/core/services/url_builder"
	*/
	makeUrl(routeIdentifier, params, options) {
		const normalizedOptions = Object.assign({}, options);
		if (options?.disableRouteLookup) return createURL(routeIdentifier, parseRoute(routeIdentifier), this.qs.stringify, params, options);
		const route = this.findOrFail(routeIdentifier, normalizedOptions.domain);
		return createURL(route.name ?? route.pattern, route.tokens, this.qs.stringify, params, options);
	}
	/**
	* Makes a signed URL to a pre-registered route.
	*
	* @deprecated
	* Instead use "@adonisjs/core/services/url_builder"
	*/
	makeSignedUrl(routeIdentifier, params, options) {
		const normalizedOptions = Object.assign({}, options);
		if (options?.disableRouteLookup) return createSignedURL(routeIdentifier, parseRoute(routeIdentifier), this.qs.stringify, this.#encryption, params, options);
		const route = this.findOrFail(routeIdentifier, normalizedOptions.domain);
		return createSignedURL(route.name ?? route.pattern, route.tokens, this.qs.stringify, this.#encryption, params, options);
	}
};
//#endregion
//#region src/response_status.ts
/**
* Standard HTTP response status codes organized as a constant object.
*
* This object provides named constants for all standard HTTP status codes,
* making code more readable and less error-prone when setting response statuses.
* The naming follows PascalCase convention for consistency with TypeScript conventions.
*
* @example
* ```ts
* response.status(ResponseStatus.NotFound)
* response.status(ResponseStatus.InternalServerError)
* response.status(ResponseStatus.Created)
* ```
*/
const ResponseStatus = {
	Continue: 100,
	SwitchingProtocols: 101,
	Processing: 102,
	EarlyHints: 103,
	Ok: 200,
	Created: 201,
	Accepted: 202,
	NonAuthoritativeInformation: 203,
	NoContent: 204,
	ResetContent: 205,
	PartialContent: 206,
	MultiStatus: 207,
	AlreadyReported: 208,
	IMUsed: 226,
	MultipleChoices: 300,
	MovedPermanently: 301,
	Found: 302,
	SeeOther: 303,
	NotModified: 304,
	UseProxy: 305,
	TemporaryRedirect: 307,
	PermanentRedirect: 308,
	BadRequest: 400,
	Unauthorized: 401,
	PaymentRequired: 402,
	Forbidden: 403,
	NotFound: 404,
	MethodNotAllowed: 405,
	NotAcceptable: 406,
	ProxyAuthenticationRequired: 407,
	RequestTimeout: 408,
	Conflict: 409,
	Gone: 410,
	LengthRequired: 411,
	PreconditionFailed: 412,
	PayloadTooLarge: 413,
	URITooLong: 414,
	UnsupportedMediaType: 415,
	RangeNotSatisfiable: 416,
	ExpectationFailed: 417,
	ImATeapot: 418,
	MisdirectedRequest: 421,
	UnprocessableEntity: 422,
	Locked: 423,
	FailedDependency: 424,
	TooEarly: 425,
	UpgradeRequired: 426,
	PreconditionRequired: 428,
	TooManyRequests: 429,
	RequestHeaderFieldsTooLarge: 431,
	UnavailableForLegalReasons: 451,
	InternalServerError: 500,
	NotImplemented: 501,
	BadGateway: 502,
	ServiceUnavailable: 503,
	GatewayTimeout: 504,
	HTTPVersionNotSupported: 505,
	VariantAlsoNegotiates: 506,
	InsufficientStorage: 507,
	LoopDetected: 508,
	NotExtended: 510,
	NetworkAuthenticationRequired: 511
};
//#endregion
//#region src/cookies/serializer.ts
/**
* Cookies serializer is used to serialize a value to be set on the `Set-Cookie`
* header. You can `encode`, `sign` on `encrypt` cookies using the serializer
* and then set them individually using the `set-cookie` header.
*/
var CookieSerializer = class {
	/**
	* Cookie client instance for handling cookie operations
	*/
	#client;
	/**
	* Create a new instance of CookieSerializer
	*
	* @param encryption - The encryption instance for cookie operations
	*/
	constructor(encryption) {
		this.#client = new CookieClient(encryption);
	}
	/**
	* Encodes value as a plain cookie. By default, the plain value will be converted
	* to a string using "JSON.stringify" method and then encoded as a base64 string.
	*
	* You can disable cookie stringifaction by setting `options.stringify = false`.
	*
	* ```ts
	*  serializer.encode('name', 'virk')
	*  serializer.encode('name', 'virk', { stringify: false })
	* ```
	*
	* @param key - The cookie key
	* @param value - The value to encode
	* @param options - Cookie encoding options
	* @returns The serialized cookie string or null if encoding fails
	*/
	encode(key, value, options) {
		const stringify = options?.stringify ?? options?.encode;
		const packedValue = this.#client.encode(key, value, stringify);
		if (packedValue === null || packedValue === void 0) return null;
		return serializeCookie(key, packedValue, options);
	}
	/**
	* Sign a key-value pair to a signed cookie. The signed value has a
	* verification hash attached to it to detect data tampering.
	*
	* @param key - The cookie key
	* @param value - The value to sign
	* @param options - Cookie options
	* @returns The serialized signed cookie string or null if signing fails
	*/
	sign(key, value, options) {
		const packedValue = this.#client.sign(key, value);
		if (packedValue === null) return null;
		return serializeCookie(key, packedValue, options);
	}
	/**
	* Encrypts a key-value pair to an encrypted cookie.
	*
	* @param key - The cookie key
	* @param value - The value to encrypt
	* @param options - Cookie options
	* @returns The serialized encrypted cookie string or null if encryption fails
	*/
	encrypt(key, value, options) {
		const packedValue = this.#client.encrypt(key, value);
		if (packedValue === null) return null;
		return serializeCookie(key, packedValue, options);
	}
};
//#endregion
//#region src/response.ts
const CACHEABLE_HTTP_METHODS = ["GET", "HEAD"];
const DATA_TYPES = {
	buffer: "buffer",
	regexp: "regexp",
	date: "date",
	object: "object",
	number: "number",
	boolean: "boolean",
	string: "string",
	bigint: "bigint"
};
const CONTENT_TYPES = {
	text: "text/plain; charset=utf-8",
	html: "text/html; charset=utf-8",
	script: "application/octet-stream; charset=utf-8",
	json: "application/json; charset=utf-8"
};
/**
* The Response class provides a fluent API for constructing HTTP responses.
*
* It wraps Node.js ServerResponse and streamlines the process of writing
* response body, setting headers, handling cookies, redirects, and streaming.
*
* @example
* ```ts
* response.status(200).json({ message: 'Hello World' })
* response.redirect('/dashboard')
* response.download('/path/to/file.pdf')
* ```
*/
var HttpResponse = class extends Macroable {
	request;
	response;
	/**
	* Query string parser instance used for URL manipulation
	*/
	#qs;
	/**
	* Collection of outgoing HTTP headers to be sent with the response
	*/
	#headers = {};
	/**
	* Flag indicating whether an explicit status code has been set
	*/
	#hasExplicitStatus = false;
	/**
	* Cookie serializer instance for handling cookie encryption, signing, and encoding
	*/
	#cookieSerializer;
	/**
	* Router instance used for generating redirect URLs from route definitions
	*/
	#router;
	/**
	* Configuration object containing response-related settings
	*/
	#config;
	/**
	* Indicates whether the response has any content (body, stream, or file) ready to be sent
	*/
	get hasLazyBody() {
		return !!(this.lazyBody.content || this.lazyBody.fileToStream || this.lazyBody.stream);
	}
	/**
	* Indicates whether the response has non-stream content set
	*/
	get hasContent() {
		return !!this.lazyBody.content;
	}
	/**
	* Indicates whether the response body is set as a readable stream
	*/
	get hasStream() {
		return !!this.lazyBody.stream;
	}
	/**
	* Indicates whether the response is configured to stream a file
	*/
	get hasFileToStream() {
		return !!this.lazyBody.fileToStream;
	}
	/**
	* The response content data
	*/
	get content() {
		return this.lazyBody.content;
	}
	/**
	* The readable stream instance configured for the response
	*/
	get outgoingStream() {
		return this.lazyBody.stream?.[0];
	}
	/**
	* Configuration for file streaming including path and etag generation flag
	*/
	get fileToStream() {
		return this.lazyBody.fileToStream ? {
			path: this.lazyBody.fileToStream[0],
			generateEtag: this.lazyBody.fileToStream[1]
		} : void 0;
	}
	/**
	* Lazy body container that holds response content until ready to send.
	* Contains different types of response data: content, stream, or fileToStream.
	*/
	lazyBody = {};
	/**
	* HTTP context reference (creates circular dependency with HttpContext)
	*/
	ctx;
	/**
	* Creates a new Response instance
	*
	* @param request - Node.js IncomingMessage instance
	* @param response - Node.js ServerResponse instance
	* @param encryption - Encryption service for cookie handling
	* @param config - Response configuration settings
	* @param router - Router instance for URL generation
	* @param qs - Query string parser
	*/
	constructor(request, response, encryption, config, router, qs) {
		super();
		this.request = request;
		this.response = response;
		this.#qs = qs;
		this.#config = config;
		this.#router = router;
		this.#cookieSerializer = new CookieSerializer(encryption);
	}
	/**
	* Indicates whether the response has been completely sent
	*/
	get finished() {
		return this.response.writableFinished;
	}
	/**
	* Indicates whether response headers have been sent to the client
	*/
	get headersSent() {
		return this.response.headersSent;
	}
	/**
	* Indicates whether the response is still pending (headers and body can still be modified)
	*/
	get isPending() {
		return !this.headersSent && !this.finished;
	}
	/**
	* Normalizes header value to a string or an array of strings
	*
	* @param value - The header value to normalize
	* @returns Normalized header value
	*/
	#castHeaderValue(value) {
		return Array.isArray(value) ? value.map(String) : String(value);
	}
	/**
	* Ends the response by flushing headers and writing body
	*
	* @param body - Optional response body
	* @param statusCode - Optional status code
	*/
	#endResponse(body, statusCode) {
		this.writeHead(statusCode);
		this.response.end(body, null, null);
	}
	/**
	* Writes the response body with appropriate headers and content type detection
	*
	* Automatically sets:
	* - Content-Type based on content analysis
	* - Content-Length header
	* - ETag header (if enabled)
	* - Status code 204 for empty bodies
	*
	* @param content - The response content
	* @param generateEtag - Whether to generate ETag header
	* @param jsonpCallbackName - Optional JSONP callback name
	*/
	writeBody(content, generateEtag, jsonpCallbackName) {
		const hasEmptyBody = content === null || content === void 0 || content === "";
		/**
		* Set status to "204" when body is empty. The `safeStatus` method only
		* sets the status when no explicit status has been set already
		*/
		if (hasEmptyBody) this.safeStatus(204);
		const statusCode = this.response.statusCode;
		/**
		* Do not process body when status code is less than 200 or is 204 or 304. As per
		* https://tools.ietf.org/html/rfc7230#section-3.3.2
		*/
		if (statusCode && (statusCode < ResponseStatus.Ok || statusCode === ResponseStatus.NoContent || statusCode === ResponseStatus.NotModified)) {
			this.removeHeader("Content-Type");
			this.removeHeader("Content-Length");
			this.removeHeader("Transfer-Encoding");
			this.#endResponse();
			return;
		}
		/**
		* Body is empty and status code is not "204", "304" and neither under 200.
		*/
		if (hasEmptyBody) {
			this.removeHeader("Content-Length");
			this.#endResponse();
			return;
		}
		/**
		* Javascript data type for the content. We only handle a subset
		* of data types.
		*/
		let contentType;
		const dataType = typeof content;
		if (dataType === DATA_TYPES.string) contentType = content.trimStart().startsWith("<") ? CONTENT_TYPES.html : CONTENT_TYPES.text;
		else if (content instanceof Uint8Array) contentType = CONTENT_TYPES.script;
		else if (content instanceof RegExp) {
			content = String(content);
			contentType = CONTENT_TYPES.text;
		} else if (content instanceof Date) {
			content = content.toISOString();
			contentType = CONTENT_TYPES.text;
		} else if (dataType === "object") {
			content = this.#config.serializeJSON(content);
			contentType = CONTENT_TYPES.json;
		} else if (dataType === DATA_TYPES.number || dataType === DATA_TYPES.boolean || dataType === DATA_TYPES.bigint) {
			content = String(content);
			contentType = CONTENT_TYPES.text;
		} else throw new RuntimeException(`Cannot serialize "${dataType}" to HTTP response`);
		if (jsonpCallbackName) {
			content = content.replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
			content = `/**/ typeof ${jsonpCallbackName} === 'function' && ${jsonpCallbackName}(${content});`;
		}
		if (generateEtag) this.setEtag(content);
		/**
		* End response when cache is fresh
		*/
		if (generateEtag && this.fresh()) {
			this.removeHeader("Content-Type");
			this.removeHeader("Content-Length");
			this.removeHeader("Transfer-Encoding");
			this.#endResponse(null, ResponseStatus.NotModified);
			return;
		}
		this.header("Content-Length", Buffer.byteLength(content));
		/**
		* ----------------------------------------
		* SET CONTENT-TYPE HEADER
		* ----------------------------------------
		*
		* - If it is a JSONP response, then we always set the content type
		*   to "text/javascript"
		*
		* - String are checked for HTML and "text/plain" or "text/html" is set
		*   accordingly.
		*
		* - "text/plain"  is set for "numbers" and "booleans" and "dates"
		*
		* - "application/octet-stream" is set for buffers
		*
		* - "application/json" is set for objects and arrays
		*/
		if (jsonpCallbackName) {
			this.header("X-Content-Type-Options", "nosniff");
			this.safeHeader("Content-Type", "text/javascript; charset=utf-8");
		} else this.safeHeader("Content-type", contentType);
		this.#endResponse(content);
	}
	/**
	* Streams the response body and handles error cleanup
	*
	* Manages stream lifecycle including:
	* - Error handling with custom callbacks
	* - Proper stream cleanup to prevent memory leaks
	* - Response finalization
	*
	* @param body - The readable stream to pipe
	* @param errorCallback - Optional custom error handler
	* @returns Promise that resolves when streaming is complete
	*/
	streamBody(body, errorCallback) {
		const readable = body instanceof ReadableStream ? Readable.fromWeb(body) : body;
		return new Promise((resolve) => {
			let finished = false;
			readable.on("error", (error) => {
				/* c8 ignore next 3 */
				if (finished) return;
				finished = true;
				destroy(readable);
				this.type("text");
				if (!this.headersSent) if (typeof errorCallback === "function") this.#endResponse(...errorCallback(error));
				else this.#endResponse(error.code === "ENOENT" ? "File not found" : "Cannot process file", error.code === "ENOENT" ? ResponseStatus.NotFound : ResponseStatus.InternalServerError);
				else this.response.destroy();
				resolve();
			});
			readable.on("end", () => {
				if (!this.headersSent) this.#endResponse();
				resolve();
			});
			onFinished(this.response, () => {
				finished = true;
				destroy(readable);
			});
			this.relayHeaders();
			readable.pipe(this.response);
		});
	}
	/**
	* Streams a file for download with proper headers and caching support
	*
	* Sets appropriate headers:
	* - Last-Modified based on file stats
	* - Content-Type based on file extension
	* - Content-Length from file size
	* - ETag (if enabled)
	*
	* Handles HEAD requests and cache validation (304 responses).
	*
	* @param filePath - Path to the file to stream
	* @param generateEtag - Whether to generate ETag header
	* @param errorCallback - Optional custom error handler
	*/
	async streamFileForDownload(filePath, generateEtag, errorCallback) {
		try {
			const stats = await stat(filePath);
			if (!stats || !stats.isFile()) throw new TypeError("response.download only accepts path to a file");
			this.header("Last-Modified", stats.mtime.toUTCString());
			this.type(extname(filePath));
			if (generateEtag) this.setEtag(stats, true);
			if (this.request.method === "HEAD") {
				this.#endResponse(null, generateEtag && this.fresh() ? ResponseStatus.NotModified : ResponseStatus.Ok);
				return;
			}
			if (generateEtag && this.fresh()) {
				this.#endResponse(null, ResponseStatus.NotModified);
				return;
			}
			this.header("Content-length", stats.size);
			return this.streamBody(createReadStream(filePath), errorCallback);
		} catch (error) {
			this.type("text");
			this.removeHeader("Etag");
			if (typeof errorCallback === "function") this.#endResponse(...errorCallback(error));
			else this.#endResponse(error.code === "ENOENT" ? "File not found" : "Cannot process file", error.code === "ENOENT" ? ResponseStatus.NotFound : ResponseStatus.InternalServerError);
		}
	}
	/**
	* Registers a callback to be called when the response is finished
	*
	* The callback is executed when the response has been completely sent.
	* Uses the "on-finished" package internally.
	*
	* @param callback - Function to call when response is finished
	*/
	onFinish(callback) {
		onFinished(this.response, callback);
	}
	/**
	* Transfers all buffered headers to the underlying Node.js response object
	*/
	relayHeaders() {
		if (!this.headersSent) for (let key in this.#headers) {
			const value = this.#headers[key];
			if (value) this.response.setHeader(key, value);
		}
	}
	/**
	* Writes the response status code and headers
	*
	* @param statusCode - Optional status code to set
	* @returns The Response instance for chaining
	*/
	writeHead(statusCode) {
		this.response.writeHead(statusCode || this.response.statusCode, this.#headers);
		return this;
	}
	/**
	* Gets the value of a response header
	*
	* @param key - Header name
	* @returns The header value
	*/
	getHeader(key) {
		const value = this.#headers[key.toLowerCase()];
		return value === void 0 ? this.response.getHeader(key) : value;
	}
	/**
	* Gets all response headers as an object
	*
	* @returns Object containing all headers
	*/
	getHeaders() {
		return {
			...this.response.getHeaders(),
			...this.#headers
		};
	}
	/**
	* Sets a response header (replaces existing value)
	*
	* @param key - Header name
	* @param value - Header value (ignored if null/undefined)
	* @returns The Response instance for chaining
	*
	* @example
	* ```ts
	* response.header('Content-Type', 'application/json')
	* ```
	*/
	header(key, value) {
		if (value === null || value === void 0) return this;
		this.#headers[key.toLowerCase()] = this.#castHeaderValue(value);
		return this;
	}
	/**
	* Appends a value to an existing response header
	*
	* @param key - Header name
	* @param value - Header value to append (ignored if null/undefined)
	* @returns The Response instance for chaining
	*
	* @example
	* ```ts
	* response.append('Set-Cookie', 'session=abc123')
	* ```
	*/
	append(key, value) {
		if (value === null || value === void 0) return this;
		key = key.toLowerCase();
		let existingHeader = this.getHeader(key);
		let casted = this.#castHeaderValue(value);
		/**
		* If there isn't any header, then setHeader right
		* away
		*/
		if (!existingHeader) {
			this.#headers[key] = casted;
			return this;
		}
		existingHeader = this.#castHeaderValue(existingHeader);
		casted = Array.isArray(existingHeader) ? existingHeader.concat(casted) : [existingHeader].concat(casted);
		this.#headers[key] = casted;
		return this;
	}
	/**
	* Sets a header only if it doesn't already exist
	*
	* @param key - Header name
	* @param value - Header value
	* @returns The Response instance for chaining
	*/
	safeHeader(key, value) {
		if (!this.getHeader(key)) this.header(key, value);
		return this;
	}
	/**
	* Removes a response header
	*
	* @param key - Header name to remove
	* @returns The Response instance for chaining
	*/
	removeHeader(key) {
		key = key.toLowerCase();
		this.response.removeHeader(key);
		if (this.#headers[key]) delete this.#headers[key.toLowerCase()];
		return this;
	}
	/**
	* Gets the current response status code
	*
	* @returns The HTTP status code
	*/
	getStatus() {
		return this.response.statusCode;
	}
	/**
	* Sets the response status code
	*
	* @param code - HTTP status code
	* @returns The Response instance for chaining
	*/
	status(code) {
		this.#hasExplicitStatus = true;
		this.response.statusCode = code;
		return this;
	}
	/**
	* Sets the status code only if not explicitly set already
	*
	* @param code - HTTP status code
	* @returns The Response instance for chaining
	*/
	safeStatus(code) {
		if (this.#hasExplicitStatus) return this;
		this.status(code);
		return this;
	}
	/**
	* Sets the Content-Type header based on mime type lookup
	*
	* @param type - File extension or mime type
	* @param charset - Optional character encoding
	* @returns The Response instance for chaining
	*
	* @example
	* ```ts
	* response.type('.json') // Content-Type: application/json
	* response.type('html', 'utf-8') // Content-Type: text/html; charset=utf-8
	* ```
	*/
	type(type, charset) {
		type = charset ? `${type}; charset=${charset}` : type;
		this.header("Content-Type", mime$1.contentType(type));
		return this;
	}
	/**
	* Sets the Vary HTTP header for cache control
	*
	* @param field - Header field name(s) to vary on
	* @returns The Response instance for chaining
	*/
	vary(field) {
		vary(this.response, field);
		return this;
	}
	/**
	* Sets the ETag header by computing a hash from the response body
	*
	* @param body - The response body to hash
	* @param weak - Whether to generate a weak ETag
	* @returns The Response instance for chaining
	*/
	setEtag(body, weak = false) {
		this.header("Etag", etag(body, { weak }));
		return this;
	}
	/**
	* Sets the X-Request-Id header by copying from the incoming request
	*
	* @returns The Response instance for chaining
	*/
	setRequestId() {
		const requestId = this.request.headers["x-request-id"];
		if (requestId) this.header("X-Request-Id", requestId);
		return this;
	}
	/**
	* Checks if the response is fresh (client cache is valid)
	*
	* Compares ETags and modified dates between request and response
	* to determine if a 304 Not Modified response should be sent.
	*
	* @returns True if client cache is fresh, false otherwise
	*
	* @example
	* ```ts
	* response.setEtag(content)
	* if (response.fresh()) {
	*   response.status(304).send(null)
	* } else {
	*   response.send(content)
	* }
	* ```
	*/
	fresh() {
		if (this.request.method && !CACHEABLE_HTTP_METHODS.includes(this.request.method)) return false;
		const status = this.response.statusCode;
		if (status >= ResponseStatus.Ok && status < ResponseStatus.MultipleChoices || status === ResponseStatus.NotModified) return fresh(this.request.headers, this.#headers);
		return false;
	}
	/**
	* Gets the response body content
	*
	* @returns The response body or null if not set or is a stream
	*/
	getBody() {
		if (this.lazyBody.content) return this.lazyBody.content[0];
		return null;
	}
	/**
	* Sends the response body with optional ETag generation
	*
	* @param body - The response body
	* @param generateEtag - Whether to generate ETag header (defaults to config)
	*/
	send(body, generateEtag = this.#config.etag) {
		if (body instanceof Response) {
			body.headers.forEach((value, key) => this.header(key, value));
			this.safeStatus(body.status);
			if (body.body) this.stream(body.body);
			return;
		}
		this.lazyBody.content = [body, generateEtag];
	}
	/**
	* Sends a JSON response (alias for send)
	*
	* @param body - The response body to serialize as JSON
	* @param generateEtag - Whether to generate ETag header
	*/
	json(body, generateEtag = this.#config.etag) {
		return this.send(body, generateEtag);
	}
	/**
	* Sends a JSONP response with callback wrapping
	*
	* Callback name resolution priority:
	* 1. Explicit callbackName parameter
	* 2. Query string parameter
	* 3. Config value
	* 4. Default "callback"
	*
	* @param body - The response body
	* @param callbackName - JSONP callback function name
	* @param generateEtag - Whether to generate ETag header
	*/
	jsonp(body, callbackName = this.#config.jsonpCallbackName, generateEtag = this.#config.etag) {
		this.lazyBody.content = [
			body,
			generateEtag,
			callbackName
		];
	}
	/**
	* Pipes a readable stream to the response with graceful error handling
	*
	* @param body - The readable stream to pipe
	* @param errorCallback - Optional custom error handler
	*
	* @example
	* ```ts
	* // Auto error handling
	* response.stream(fs.createReadStream('file.txt'))
	*
	* // Custom error handling
	* response.stream(stream, (error) => {
	*   return error.code === 'ENOENT' ? ['Not found', 404] : ['Error', 500]
	* })
	* ```
	*/
	stream(body, errorCallback) {
		if (body instanceof ReadableStream === false && (typeof body.pipe !== "function" || !body.readable || typeof body.read !== "function")) throw new TypeError("response.stream accepts a readable stream only");
		this.lazyBody.stream = [body, errorCallback];
	}
	/**
	* Downloads a file by streaming it with appropriate headers
	*
	* Automatically sets:
	* - Content-Type from file extension
	* - Content-Length from file size
	* - Last-Modified from file stats
	* - ETag (if enabled)
	*
	* @param filePath - Path to the file to download
	* @param generateEtag - Whether to generate ETag header
	* @param errorCallback - Optional custom error handler
	*
	* @example
	* ```ts
	* response.download('/path/to/file.pdf')
	* response.download('/images/photo.jpg', true, (err) => ['Custom error', 500])
	* ```
	*/
	download(filePath, generateEtag = this.#config.etag, errorCallback) {
		this.lazyBody.fileToStream = [
			filePath,
			generateEtag,
			errorCallback
		];
	}
	/**
	* Forces file download by setting Content-Disposition header
	*
	* @param filePath - Path to the file to download
	* @param name - Optional filename for download (defaults to original filename)
	* @param disposition - Content-Disposition type (defaults to 'attachment')
	* @param generateEtag - Whether to generate ETag header
	* @param errorCallback - Optional custom error handler
	*/
	attachment(filePath, name, disposition, generateEtag, errorCallback) {
		name = name || filePath;
		this.header("Content-Disposition", contentDisposition(name, { type: disposition }));
		return this.download(filePath, generateEtag, errorCallback);
	}
	/**
	* Sets the Location header for redirects
	*
	* @param url - The URL to redirect to
	* @returns The Response instance for chaining
	*
	* @example
	* ```ts
	* response.location('/dashboard')
	* ```
	*/
	location(url) {
		this.header("Location", url);
		return this;
	}
	redirect(path, forwardQueryString = false, statusCode = ResponseStatus.Found) {
		const handler = new Redirect(this.request, this, this.#router, this.#qs, this.#config.redirect);
		handler.ctx = this.ctx;
		if (forwardQueryString) handler.withQs();
		if (path === "back") return handler.status(statusCode).back();
		if (path) return handler.status(statusCode).toPath(path);
		return handler;
	}
	/**
	* Aborts the request with a custom response body and status code
	*
	* @param body - Response body for the aborted request
	* @param status - HTTP status code (defaults to 400)
	* @throws Always throws an HTTP exception
	*/
	abort(body, status) {
		throw E_HTTP_REQUEST_ABORTED.invoke(body, status || ResponseStatus.BadRequest);
	}
	/**
	* Conditionally aborts the request if the condition is truthy
	*
	* @param condition - Condition to evaluate
	* @param body - Response body for the aborted request
	* @param status - HTTP status code (defaults to 400)
	*/
	abortIf(condition, body, status) {
		if (condition) this.abort(body, status);
	}
	/**
	* Conditionally aborts the request if the condition is falsy
	*
	* @param condition - Condition to evaluate
	* @param body - Response body for the aborted request
	* @param status - HTTP status code (defaults to 400)
	*/
	abortUnless(condition, body, status) {
		if (!condition) this.abort(body, status);
	}
	/**
	* Sets a signed cookie in the response
	*
	* @param key - Cookie name
	* @param value - Cookie value
	* @param options - Cookie options (overrides config defaults)
	* @returns The Response instance for chaining
	*/
	cookie(key, value, options) {
		options = Object.assign({}, this.#config.cookie, options);
		const serialized = this.#cookieSerializer.sign(key, value, options);
		if (!serialized) return this;
		this.append("set-cookie", serialized);
		return this;
	}
	/**
	* Sets an encrypted cookie in the response
	*
	* @param key - Cookie name
	* @param value - Cookie value
	* @param options - Cookie options (overrides config defaults)
	* @returns The Response instance for chaining
	*/
	encryptedCookie(key, value, options) {
		options = Object.assign({}, this.#config.cookie, options);
		const serialized = this.#cookieSerializer.encrypt(key, value, options);
		if (!serialized) return this;
		this.append("set-cookie", serialized);
		return this;
	}
	/**
	* Sets a plain (unsigned/unencrypted) cookie in the response
	*
	* @param key - Cookie name
	* @param value - Cookie value
	* @param options - Cookie options including encode flag
	* @returns The Response instance for chaining
	*/
	plainCookie(key, value, options) {
		options = Object.assign({}, this.#config.cookie, options);
		const serialized = this.#cookieSerializer.encode(key, value, options);
		if (!serialized) return this;
		this.append("set-cookie", serialized);
		return this;
	}
	/**
	* Clears an existing cookie by setting it to expire
	*
	* @param key - Cookie name to clear
	* @param options - Cookie options (should match original cookie options)
	* @returns The Response instance for chaining
	*/
	clearCookie(key, options) {
		options = Object.assign({}, this.#config.cookie, options);
		options.expires = /* @__PURE__ */ new Date(1);
		options.maxAge = -1;
		const serialized = this.#cookieSerializer.encode(key, "", {
			...options,
			encode: false
		});
		this.append("set-cookie", serialized);
		return this;
	}
	/**
	* Finalizes and sends the response
	*
	* Writes the buffered body (content, stream, or file) to the client.
	* This method is idempotent - calling it multiple times has no effect.
	*/
	finish() {
		if (!this.isPending) return;
		this.setRequestId();
		/**
		* Handle text based response
		*/
		if (this.content) {
			httpResponseSerializer.traceSync(this.writeBody, void 0, this, ...this.content);
			return;
		}
		/**
		* Handle stream based response
		*/
		if (this.lazyBody.stream) {
			this.streamBody(...this.lazyBody.stream);
			return;
		}
		/**
		* Handle file streaming response
		*/
		if (this.lazyBody.fileToStream) {
			this.streamFileForDownload(...this.lazyBody.fileToStream);
			return;
		}
		this.#endResponse();
	}
	/**
	* Sends a 100 Continue response
	*/
	continue() {
		this.status(ResponseStatus.Continue);
		return this.send(null, false);
	}
	/**
	* Sends a 101 Switching Protocols response
	*/
	switchingProtocols() {
		this.status(ResponseStatus.SwitchingProtocols);
		return this.send(null, false);
	}
	/**
	* Sends a 200 OK response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	ok(body, generateEtag) {
		this.status(ResponseStatus.Ok);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 201 Created response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	created(body, generateEtag) {
		this.status(ResponseStatus.Created);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 202 Accepted response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	accepted(body, generateEtag) {
		this.status(ResponseStatus.Accepted);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 203 Non-Authoritative Information response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	nonAuthoritativeInformation(body, generateEtag) {
		this.status(ResponseStatus.NonAuthoritativeInformation);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 204 No Content response
	*/
	noContent() {
		this.status(ResponseStatus.NoContent);
		return this.send(null, false);
	}
	/**
	* Sends a 205 Reset Content response
	*/
	resetContent() {
		this.status(ResponseStatus.ResetContent);
		return this.send(null, false);
	}
	/**
	* Sends a 206 Partial Content response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	partialContent(body, generateEtag) {
		this.status(ResponseStatus.PartialContent);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 300 Multiple Choices response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	multipleChoices(body, generateEtag) {
		this.status(ResponseStatus.MultipleChoices);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 301 Moved Permanently response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	movedPermanently(body, generateEtag) {
		this.status(ResponseStatus.MovedPermanently);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 302 Found (Moved Temporarily) response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	movedTemporarily(body, generateEtag) {
		this.status(ResponseStatus.Found);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 303 See Other response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	seeOther(body, generateEtag) {
		this.status(ResponseStatus.SeeOther);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 304 Not Modified response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	notModified(body, generateEtag) {
		this.status(ResponseStatus.NotModified);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 305 Use Proxy response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	useProxy(body, generateEtag) {
		this.status(ResponseStatus.UseProxy);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 307 Temporary Redirect response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	temporaryRedirect(body, generateEtag) {
		this.status(ResponseStatus.TemporaryRedirect);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 400 Bad Request response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	badRequest(body, generateEtag) {
		this.status(ResponseStatus.BadRequest);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 401 Unauthorized response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	unauthorized(body, generateEtag) {
		this.status(ResponseStatus.Unauthorized);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 402 Payment Required response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	paymentRequired(body, generateEtag) {
		this.status(ResponseStatus.PaymentRequired);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 403 Forbidden response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	forbidden(body, generateEtag) {
		this.status(ResponseStatus.Forbidden);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 404 Not Found response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	notFound(body, generateEtag) {
		this.status(ResponseStatus.NotFound);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 405 Method Not Allowed response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	methodNotAllowed(body, generateEtag) {
		this.status(ResponseStatus.MethodNotAllowed);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 406 Not Acceptable response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	notAcceptable(body, generateEtag) {
		this.status(ResponseStatus.NotAcceptable);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 407 Proxy Authentication Required response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	proxyAuthenticationRequired(body, generateEtag) {
		this.status(ResponseStatus.ProxyAuthenticationRequired);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 408 Request Timeout response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	requestTimeout(body, generateEtag) {
		this.status(ResponseStatus.RequestTimeout);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 409 Conflict response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	conflict(body, generateEtag) {
		this.status(ResponseStatus.Conflict);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 410 Gone response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	gone(body, generateEtag) {
		this.status(ResponseStatus.Gone);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 411 Length Required response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	lengthRequired(body, generateEtag) {
		this.status(ResponseStatus.LengthRequired);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 412 Precondition Failed response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	preconditionFailed(body, generateEtag) {
		this.status(ResponseStatus.PreconditionFailed);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 413 Payload Too Large response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	requestEntityTooLarge(body, generateEtag) {
		this.status(ResponseStatus.PayloadTooLarge);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 414 URI Too Long response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	requestUriTooLong(body, generateEtag) {
		this.status(ResponseStatus.URITooLong);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 415 Unsupported Media Type response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	unsupportedMediaType(body, generateEtag) {
		this.status(ResponseStatus.UnsupportedMediaType);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 416 Range Not Satisfiable response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	requestedRangeNotSatisfiable(body, generateEtag) {
		this.status(ResponseStatus.RangeNotSatisfiable);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 417 Expectation Failed response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	expectationFailed(body, generateEtag) {
		this.status(ResponseStatus.ExpectationFailed);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 422 Unprocessable Entity response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	unprocessableEntity(body, generateEtag) {
		this.status(ResponseStatus.UnprocessableEntity);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 429 Too Many Requests response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	tooManyRequests(body, generateEtag) {
		this.status(ResponseStatus.TooManyRequests);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 500 Internal Server Error response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	internalServerError(body, generateEtag) {
		this.status(ResponseStatus.InternalServerError);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 501 Not Implemented response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	notImplemented(body, generateEtag) {
		this.status(ResponseStatus.NotImplemented);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 502 Bad Gateway response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	badGateway(body, generateEtag) {
		this.status(ResponseStatus.BadGateway);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 503 Service Unavailable response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	serviceUnavailable(body, generateEtag) {
		this.status(ResponseStatus.ServiceUnavailable);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 504 Gateway Timeout response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	gatewayTimeout(body, generateEtag) {
		this.status(ResponseStatus.GatewayTimeout);
		return this.send(body, generateEtag);
	}
	/**
	* Sends a 505 HTTP Version Not Supported response
	*
	* @param body - Response body
	* @param generateEtag - Whether to generate ETag header
	*/
	httpVersionNotSupported(body, generateEtag) {
		this.status(ResponseStatus.HTTPVersionNotSupported);
		return this.send(body, generateEtag);
	}
};
//#endregion
//#region src/http_context/local_storage.ts
/**
* Async local storage for HTTP context
*/
/**
* Async local storage for HTTP context
*/
const asyncLocalStorage = {
	isEnabled: false,
	storage: null,
	create() {
		this.isEnabled = true;
		this.storage = new AsyncLocalStorage();
		return this.storage;
	},
	destroy() {
		this.isEnabled = false;
		this.storage = null;
	}
};
//#endregion
//#region src/http_context/main.ts
/**
* HTTP context encapsulates all properties and services for a given HTTP request.
*
* The HttpContext class serves as the central hub for request-specific data and services.
* It provides access to the request, response, route information, container resolver,
* and logger instances. The context can be extended using macros and getters for
* application-specific functionality.
*
* @example
* ```ts
* export default class UsersController {
*   async show({ request, response, params }: HttpContext) {
*     const user = await User.find(params.id)
*     return response.json(user)
*   }
* }
* ```
*/
var HttpContext = class extends Macroable {
	request;
	response;
	logger;
	containerResolver;
	/**
	* Indicates whether async local storage is enabled for HTTP requests.
	*
	* When enabled, the HTTP context is automatically available within the
	* scope of request processing through static methods like get() and getOrFail().
	*/
	static get usingAsyncLocalStorage() {
		return asyncLocalStorage.isEnabled;
	}
	/**
	* Get access to the current HTTP context from async local storage.
	*
	* This method is only available when async local storage is enabled.
	* Returns null if called outside of an HTTP request context.
	*
	* @example
	* ```ts
	* const ctx = HttpContext.get()
	* if (ctx) {
	*   console.log(ctx.request.url())
	* }
	* ```
	*/
	static get() {
		if (!this.usingAsyncLocalStorage || !asyncLocalStorage.storage) return null;
		return asyncLocalStorage.storage.getStore() || null;
	}
	/**
	* Get the HttpContext instance or raise an exception if not available.
	*
	* This method is useful when you need guaranteed access to the HTTP context
	* and want to fail fast if it's not available.
	*
	* @throws RuntimeException when async local storage is disabled or context is unavailable
	*
	* @example
	* ```ts
	* const ctx = HttpContext.getOrFail()
	* const userId = ctx.request.input('user_id')
	* ```
	*/
	static getOrFail() {
		/**
		* Localstorage is not enabled
		*/
		if (!this.usingAsyncLocalStorage || !asyncLocalStorage.storage) throw new RuntimeException("HTTP context is not available. Enable \"useAsyncLocalStorage\" inside \"config/app.ts\" file");
		const store = this.get();
		if (!store) throw new RuntimeException("Http context is not available outside of an HTTP request");
		return store;
	}
	/**
	* Run a method outside of the HTTP context scope.
	*
	* This method allows you to execute code that should not have access to
	* the current HTTP context from async local storage. Useful for background
	* tasks or operations that should be context-independent.
	*
	* @param callback - Function to execute outside the context
	* @param args - Arguments to pass to the callback
	*
	* @example
	* ```ts
	* HttpContext.runOutsideContext(() => {
	*   // This code cannot access HttpContext.get()
	*   performBackgroundTask()
	* })
	* ```
	*/
	static runOutsideContext(callback, ...args) {
		if (!asyncLocalStorage.storage) return callback(...args);
		return asyncLocalStorage.storage.exit(callback, ...args);
	}
	/**
	* Reference to the current route. Not available inside
	* server middleware
	*/
	route;
	/**
	* A unique key for the current route
	*/
	routeKey;
	/**
	* Route params
	*/
	params = {};
	/**
	* Route subdomains
	*/
	subdomains = {};
	/**
	* Creates a new HttpContext instance
	*
	* @param {HttpRequest} request - The HTTP request instance
	* @param {HttpResponse} response - The HTTP response instance
	* @param {Logger} logger - The logger instance
	* @param {ContainerResolver<any>} containerResolver - The IoC container resolver
	*/
	constructor(request, response, logger, containerResolver) {
		super();
		this.request = request;
		this.response = response;
		this.logger = logger;
		this.containerResolver = containerResolver;
		this.request.ctx = this;
		this.response.ctx = this;
	}
	/**
	* A helper to see top level properties on the context object
	*/
	/* c8 ignore next 3 */
	inspect() {
		return inspect(this, false, 1, true);
	}
};
//#endregion
//#region src/server/factories/route_finder.ts
/**
* Creates a route finder function that matches HTTP requests to registered routes
*
* This factory function returns a route handler that:
* - Matches incoming requests against registered routes
* - Extracts route parameters and subdomains
* - Executes the matched route's handler and middleware
* - Throws E_ROUTE_NOT_FOUND error for unmatched requests
*
* @param router - Router instance containing registered routes
* @param resolver - Container resolver for dependency injection
* @param ctx - HTTP context containing request/response data
* @param errorResponder - Error handler for route execution errors
* @returns Route execution function
*/
function routeFinder(router, resolver, ctx, errorResponder) {
	/**
	* Finds and executes a matching route for the current request
	*
	* @returns Promise that resolves when route execution completes or rejects with route not found error
	*/
	return function() {
		const url = ctx.request.url();
		const method = ctx.request.method();
		const hostname = router.usingDomains ? ctx.request.hostname() : void 0;
		const route = router.match(url, method, ctx.request.parsedUrl.shouldDecodeParam, hostname);
		if (route) {
			ctx.params = route.params;
			ctx.subdomains = route.subdomains;
			ctx.route = route.route;
			ctx.routeKey = route.routeKey;
			return route.route.execute(route.route, resolver, ctx, errorResponder);
		}
		return Promise.reject(new E_ROUTE_NOT_FOUND([method, url]));
	};
}
//#endregion
//#region src/server/factories/write_response.ts
/**
* Creates a response writer function that finalizes HTTP responses with error handling
*
* This factory function returns a response finalizer that:
* - Calls the response.finish() method to send the response
* - Catches serialization errors and sends a 500 error response
* - Logs fatal errors for debugging and monitoring
*
* @param ctx - HTTP context containing the response to finalize
* @returns Response finalization function
*/
function writeResponse(ctx) {
	/**
	* Finalizes the HTTP response by writing it to the socket with error handling
	*/
	return function() {
		try {
			ctx.response.finish();
		} catch (error) {
			ctx.logger.fatal({ err: error }, "Response serialization failed");
			ctx.response.internalServerError(error.message);
			ctx.response.finish();
		}
	};
}
//#endregion
//#region src/server/factories/middleware_handler.ts
/**
* Creates a middleware execution handler that invokes middleware functions with tracing support
*
* This factory function returns a middleware execution handler that:
* - Executes middleware with debug logging
* - Provides distributed tracing through tracing channels
* - Passes the container resolver, HTTP context, and next function to middleware
*
* @param resolver - Container resolver for dependency injection
* @param ctx - HTTP context containing request/response data
* @returns Middleware execution function
*/
function middlewareHandler(resolver, ctx) {
	/**
	* Executes a single middleware function with tracing and debug logging
	*
	* @param fn - Parsed middleware configuration with handle method
	* @param next - Next function to call the next middleware in the stack
	* @returns Promise that resolves when middleware execution completes
	*/
	return function(fn, next) {
		debug_default("executing middleware %s", fn.name);
		return httpMiddleware.tracePromise(fn.handle, httpMiddleware.hasSubscribers ? { middleware: fn } : void 0, void 0, resolver, ctx, next);
	};
}
//#endregion
//#region src/server/main.ts
/**
* The Server class provides the core HTTP server implementation for AdonisJS.
*
* It handles incoming HTTP requests by processing them through middleware pipelines,
* routing them to appropriate handlers, and managing response generation. The server
* supports custom error handling, middleware registration, and various Node.js HTTP
* server configurations.
*
* @example
* ```ts
* const server = new Server(app, encryption, emitter, logger, config)
* server.use([AuthMiddleware, CorsMiddleware])
* server.errorHandler(() => import('./error_handler.ts'))
* await server.boot()
*
* http.createServer(server.handle.bind(server))
* ```
*/
var Server = class {
	/**
	* Flag indicating whether the server has been booted and initialized
	*/
	#booted = false;
	/**
	* Built-in fallback error handler used when no custom handler is registered
	*/
	#defaultErrorHandler = {
		report() {},
		handle(error, ctx) {
			ctx.response.status(error.status || 500).send(error.message || "Internal server error");
		}
	};
	/**
	* Logger instance for server-level logging (child loggers are created per request)
	*/
	#logger;
	/**
	* Lazy import reference to the custom error handler class
	*/
	#errorHandler;
	/**
	* Active error handler instance (either custom or default)
	*/
	#resolvedErrorHandler = this.#defaultErrorHandler;
	/**
	* Event emitter for HTTP server lifecycle events
	*/
	#emitter;
	/**
	* AdonisJS application instance providing IoC container and configuration
	*/
	#app;
	/**
	* Encryption service for secure cookie handling and data encryption
	*/
	#encryption;
	/**
	* Server configuration settings including timeouts, middleware options, etc.
	*/
	#config;
	/**
	* Query string parser instance for URL parameter processing
	*/
	#qsParser;
	/**
	* Compiled middleware stack that executes on every incoming HTTP request
	*/
	#serverMiddlewareStack;
	/**
	* Router instance responsible for route registration and matching
	*/
	#router;
	/**
	* Reference to the underlying Node.js HTTP or HTTPS server instance
	*/
	#nodeHttpServer;
	/**
	* Collection of registered global middleware before compilation
	*/
	#middleware = [];
	/**
	* Error responder function that handles exceptions in middleware and routes.
	* Reports errors and delegates handling to the configured error handler.
	*/
	#requestErrorResponder = async (error, ctx) => {
		await this.#resolvedErrorHandler.report(error, ctx);
		return httpExceptionHandler.tracePromise(this.#resolvedErrorHandler.handle, void 0, this.#resolvedErrorHandler, error, ctx);
	};
	/**
	* Indicates whether the server has completed its boot process
	*/
	get booted() {
		return this.#booted;
	}
	/**
	* Indicates whether async local storage is enabled for request context
	*/
	get usingAsyncLocalStorage() {
		return asyncLocalStorage.isEnabled;
	}
	/**
	* Creates a new Server instance
	*
	* @param app - AdonisJS application instance
	* @param encryption - Encryption service for secure operations
	* @param emitter - Event emitter for server lifecycle events
	* @param logger - Logger instance for server operations
	* @param config - Server configuration settings
	*/
	constructor(app, encryption, emitter, logger, config) {
		this.#app = app;
		this.#emitter = emitter;
		this.#config = config;
		this.#logger = logger;
		this.#encryption = encryption;
		this.#qsParser = new Qs(this.#config.qs);
		this.#router = new Router(this.#app, this.#encryption, this.#qsParser);
		this.#createAsyncLocalStore();
		debug_default("server config: %O", this.#config);
	}
	/**
	* Initializes or destroys async local storage based on configuration
	*/
	#createAsyncLocalStore() {
		if (this.#config.useAsyncLocalStorage) {
			debug_default("creating ALS store for HTTP context");
			asyncLocalStorage.create();
		} else asyncLocalStorage.destroy();
	}
	/**
	* Compiles registered middleware into a frozen middleware stack for execution
	*/
	#createServerMiddlewareStack() {
		this.#serverMiddlewareStack = new Middleware();
		this.#middleware.forEach((middleware) => this.#serverMiddlewareStack.add(middleware));
		this.#serverMiddlewareStack.freeze();
		this.#middleware = [];
	}
	/**
	* Processes an HTTP request through the middleware pipeline and routing
	*
	* @param ctx - HTTP context containing request/response objects
	* @param resolver - Container resolver for dependency injection
	* @returns Promise that resolves when request processing is complete
	*/
	#handleRequest(ctx, resolver) {
		return this.#serverMiddlewareStack.runner().errorHandler((error) => this.#requestErrorResponder(error, ctx)).finalHandler(routeFinder(this.#router, resolver, ctx, this.#requestErrorResponder)).run(middlewareHandler(resolver, ctx)).catch((error) => {
			ctx.logger.fatal({ err: error }, "Exception raised by error handler");
			return this.#defaultErrorHandler.handle(error, ctx);
		}).finally(writeResponse(ctx));
	}
	/**
	* Creates a testing middleware pipeline for unit/integration testing
	*
	* @param middleware - Array of middleware classes to include in pipeline
	* @returns TestingMiddlewarePipeline instance for test execution
	*/
	pipeline(middleware) {
		const middlewareStack = new Middleware();
		middleware.forEach((one) => {
			middlewareStack.add({
				reference: one,
				...moduleCaller(one, "handle").toHandleMethod()
			});
		});
		middlewareStack.freeze();
		const stackRunner = middlewareStack.runner();
		return {
			finalHandler(handler) {
				stackRunner.finalHandler(handler);
				return this;
			},
			errorHandler(handler) {
				stackRunner.errorHandler(handler);
				return this;
			},
			run(ctx) {
				return stackRunner.run((handler, next) => {
					return handler.handle(ctx.containerResolver, ctx, next);
				});
			}
		};
	}
	/**
	* Registers global middleware to run on all incoming HTTP requests
	*
	* @param middleware - Array of lazy-imported middleware classes
	* @returns The Server instance for method chaining
	*/
	use(middleware) {
		middleware.forEach((one) => this.#middleware.push({
			reference: one,
			...moduleImporter(one, "handle").toHandleMethod()
		}));
		return this;
	}
	/**
	* Registers a custom error handler for HTTP request processing
	*
	* @param handler - Lazy import of the error handler class
	* @returns The Server instance for method chaining
	*/
	errorHandler(handler) {
		this.#errorHandler = handler;
		return this;
	}
	/**
	* Initializes the server by compiling middleware, committing routes, and resolving handlers
	*
	* Performs the following operations:
	* - Compiles the middleware stack
	* - Commits registered routes to the router
	* - Resolves and instantiates the custom error handler
	*/
	async boot() {
		if (this.#booted) return;
		debug_default("booting HTTP server");
		/**
		* Creates the middleware stack for the server
		*/
		this.#createServerMiddlewareStack();
		/**
		* Commit routes
		*/
		this.#router.commit();
		/**
		* Register custom error handler
		*/
		if (this.#errorHandler) {
			if (debug_default.enabled) debug_default("using custom error handler \"%s\"", this.#errorHandler);
			const moduleExports = await this.#errorHandler();
			this.#resolvedErrorHandler = await this.#app.container.make(moduleExports.default);
		}
		this.#booted = true;
	}
	/**
	* Configures the underlying Node.js HTTP/HTTPS server with timeout settings
	*
	* @param server - Node.js HTTP or HTTPS server instance
	*/
	setNodeServer(server) {
		server.timeout = this.#config.timeout ?? server.timeout;
		server.keepAliveTimeout = this.#config.keepAliveTimeout ?? server.keepAliveTimeout;
		server.headersTimeout = this.#config.headersTimeout ?? server.headersTimeout;
		server.requestTimeout = this.#config.requestTimeout ?? server.requestTimeout;
		this.#nodeHttpServer = server;
	}
	/**
	* Gets the underlying Node.js HTTP/HTTPS server instance
	*
	* @returns The configured server instance or undefined if not set
	*/
	getNodeServer() {
		return this.#nodeHttpServer;
	}
	/**
	* Gets the router instance used for route registration and matching
	*
	* @returns The Router instance
	*/
	getRouter() {
		return this.#router;
	}
	/**
	* Creates a Request instance from Node.js request/response objects
	*
	* @param req - Node.js IncomingMessage
	* @param res - Node.js ServerResponse
	* @returns New Request instance
	*/
	createRequest(req, res) {
		return new HttpRequest(req, res, this.#encryption, this.#config, this.#qsParser);
	}
	/**
	* Creates a Response instance from Node.js request/response objects
	*
	* @param req - Node.js IncomingMessage
	* @param res - Node.js ServerResponse
	* @returns New Response instance
	*/
	createResponse(req, res) {
		return new HttpResponse(req, res, this.#encryption, this.#config, this.#router, this.#qsParser);
	}
	/**
	* Creates an HttpContext instance with request-specific logger
	*
	* @param request - Request instance
	* @param response - Response instance
	* @param resolver - Container resolver for dependency injection
	* @returns New HttpContext instance
	*/
	createHttpContext(request, response, resolver) {
		return new HttpContext(request, response, this.#logger.child({ request_id: request.id() }), resolver);
	}
	/**
	* Gets the list of registered global middleware
	*
	* @returns Array of parsed global middleware
	*/
	getMiddlewareList() {
		return this.#serverMiddlewareStack ? Array.from(this.#serverMiddlewareStack.all()) : [...this.#middleware];
	}
	/**
	* Handles an incoming HTTP request by creating context and processing through pipeline
	*
	* @param req - Node.js IncomingMessage
	* @param res - Node.js ServerResponse
	* @returns Promise that resolves when request processing is complete
	*/
	handle(req, res) {
		/**
		* Reject requests with malformed URIs (e.g. invalid UTF-8
		* percent-encoded sequences like %C0%80) before they
		* enter the middleware pipeline.
		*/
		let request;
		try {
			request = this.createRequest(req, res);
		} catch (error) {
			if (error instanceof URIError) {
				this.#config.onBadUrl(req, res);
				return;
			}
			throw error;
		}
		const startTime = this.#emitter.hasListeners("http:request_completed") ? process.hrtime() : null;
		/**
		* Creating essential instances
		*/
		const resolver = this.#app.container.createResolver();
		const ctx = this.createHttpContext(request, this.createResponse(req, res), resolver);
		/**
		* Emit event when listening for the request_finished event
		*/
		if (startTime) onFinished(res, () => {
			this.#emitter.emit("http:request_completed", {
				ctx,
				duration: process.hrtime(startTime)
			});
		});
		/**
		* Handle request
		*/
		if (this.usingAsyncLocalStorage) return asyncLocalStorage.storage.run(ctx, () => httpRequest.tracePromise(this.#handleRequest, httpRequest.hasSubscribers ? { ctx } : void 0, this, ctx, resolver));
		return httpRequest.tracePromise(this.#handleRequest, httpRequest.hasSubscribers ? { ctx } : void 0, this, ctx, resolver);
	}
};
//#endregion
//#region src/define_config.ts
/**
* Define configuration for the HTTP server with sensible defaults.
*
* This function merges user-provided configuration with default values,
* normalizes certain properties (like cookie maxAge and trustProxy settings),
* and returns a complete ServerConfig object.
*
* @param config - User-defined server configuration options
*
* @example
* ```ts
* const config = defineConfig({
*   trustProxy: true,
*   cookie: {
*     maxAge: '7d',
*     secure: false
*   },
*   etag: true
* })
* ```
*/
function defineConfig(config) {
	const { trustProxy, ...rest } = config;
	const defaults = {
		allowMethodSpoofing: false,
		trustProxy: proxyaddr.compile("loopback"),
		subdomainOffset: 2,
		generateRequestId: !!config.createRequestId,
		createRequestId() {
			return crypto.randomUUID();
		},
		serializeJSON: safeStringify,
		useAsyncLocalStorage: false,
		etag: false,
		jsonpCallbackName: "callback",
		redirect: {
			allowedHosts: [],
			forwardQueryString: false
		},
		cookie: {
			maxAge: "2h",
			path: "/",
			httpOnly: true,
			secure: true,
			sameSite: "lax"
		},
		onBadUrl(_req, res) {
			res.writeHead(400, { "Content-Type": "text/plain" });
			res.end("Bad Request");
		},
		qs: {
			parse: {
				depth: 5,
				parameterLimit: 1e3,
				allowSparse: false,
				arrayLimit: 20,
				comma: true
			},
			stringify: {
				encode: true,
				encodeValuesOnly: false,
				arrayFormat: "indices",
				skipNulls: false
			}
		}
	};
	const normalizedConfig = lodash.merge({}, defaults, rest);
	/**
	* Normalizing maxAge property on cookies to be a number in
	* seconds
	*/
	if (normalizedConfig.cookie.maxAge) normalizedConfig.cookie.maxAge = string.seconds.parse(normalizedConfig.cookie.maxAge);
	/**
	* Normalizing trust proxy setting to allow boolean and
	* string values
	*/
	if (typeof trustProxy === "boolean") {
		const tpValue = trustProxy;
		normalizedConfig.trustProxy = (_, __) => tpValue;
	} else if (typeof trustProxy === "string") {
		const tpValue = trustProxy;
		normalizedConfig.trustProxy = proxyaddr.compile(tpValue);
	} else if (trustProxy) normalizedConfig.trustProxy = trustProxy;
	return normalizedConfig;
}
//#endregion
export { Qs as _, CookieSerializer as a, HttpRequest as c, Redirect as d, E_CANNOT_LOOKUP_ROUTE as f, errors_exports as g, E_ROUTE_NOT_FOUND as h, HttpResponse as i, CookieParser as l, E_HTTP_REQUEST_ABORTED as m, Server as n, ResponseStatus as o, E_HTTP_EXCEPTION as p, HttpContext as r, Router as s, defineConfig as t, CookieClient as u };
