routup 4.1.0 → 5.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/README.md +89 -136
  2. package/dist/bun.cjs +69 -0
  3. package/dist/bun.cjs.map +1 -0
  4. package/dist/bun.d.cts +8 -0
  5. package/dist/bun.d.mts +8 -0
  6. package/dist/bun.mjs +13 -0
  7. package/dist/bun.mjs.map +1 -0
  8. package/dist/cloudflare.cjs +69 -0
  9. package/dist/cloudflare.cjs.map +1 -0
  10. package/dist/cloudflare.d.cts +8 -0
  11. package/dist/cloudflare.d.mts +8 -0
  12. package/dist/cloudflare.mjs +13 -0
  13. package/dist/cloudflare.mjs.map +1 -0
  14. package/dist/deno.cjs +69 -0
  15. package/dist/deno.cjs.map +1 -0
  16. package/dist/deno.d.cts +8 -0
  17. package/dist/deno.d.mts +8 -0
  18. package/dist/deno.mjs +13 -0
  19. package/dist/deno.mjs.map +1 -0
  20. package/dist/generic.cjs +69 -0
  21. package/dist/generic.cjs.map +1 -0
  22. package/dist/generic.d.cts +8 -0
  23. package/dist/generic.d.mts +8 -0
  24. package/dist/generic.mjs +13 -0
  25. package/dist/generic.mjs.map +1 -0
  26. package/dist/index-DN3wy86V.d.mts +841 -0
  27. package/dist/index-Dm50O_sj.d.cts +841 -0
  28. package/dist/node.cjs +73 -0
  29. package/dist/node.cjs.map +1 -0
  30. package/dist/node.d.cts +11 -0
  31. package/dist/node.d.mts +11 -0
  32. package/dist/node.mjs +16 -0
  33. package/dist/node.mjs.map +1 -0
  34. package/dist/service-worker.cjs +69 -0
  35. package/dist/service-worker.cjs.map +1 -0
  36. package/dist/service-worker.d.cts +10 -0
  37. package/dist/service-worker.d.mts +10 -0
  38. package/dist/service-worker.mjs +13 -0
  39. package/dist/service-worker.mjs.map +1 -0
  40. package/dist/src-CpLmo5Po.mjs +1602 -0
  41. package/dist/src-CpLmo5Po.mjs.map +1 -0
  42. package/dist/src-D_4IPMmD.cjs +1960 -0
  43. package/dist/src-D_4IPMmD.cjs.map +1 -0
  44. package/package.json +75 -34
  45. package/dist/adapters/index.d.ts +0 -3
  46. package/dist/adapters/node/index.d.ts +0 -1
  47. package/dist/adapters/node/module.d.ts +0 -6
  48. package/dist/adapters/raw/header.d.ts +0 -3
  49. package/dist/adapters/raw/index.d.ts +0 -3
  50. package/dist/adapters/raw/module.d.ts +0 -4
  51. package/dist/adapters/raw/type.d.ts +0 -18
  52. package/dist/adapters/web/index.d.ts +0 -2
  53. package/dist/adapters/web/module.d.ts +0 -4
  54. package/dist/adapters/web/type.d.ts +0 -3
  55. package/dist/constants.d.ts +0 -42
  56. package/dist/dispatcher/event/dispatch.d.ts +0 -4
  57. package/dist/dispatcher/event/error.d.ts +0 -5
  58. package/dist/dispatcher/event/index.d.ts +0 -5
  59. package/dist/dispatcher/event/is.d.ts +0 -3
  60. package/dist/dispatcher/event/module.d.ts +0 -56
  61. package/dist/dispatcher/event/types.d.ts +0 -9
  62. package/dist/dispatcher/index.d.ts +0 -2
  63. package/dist/dispatcher/type.d.ts +0 -4
  64. package/dist/error/create.d.ts +0 -11
  65. package/dist/error/index.d.ts +0 -3
  66. package/dist/error/is.d.ts +0 -2
  67. package/dist/error/module.d.ts +0 -3
  68. package/dist/handler/constants.d.ts +0 -5
  69. package/dist/handler/core/define.d.ts +0 -4
  70. package/dist/handler/core/index.d.ts +0 -2
  71. package/dist/handler/core/types.d.ts +0 -10
  72. package/dist/handler/error/define.d.ts +0 -4
  73. package/dist/handler/error/index.d.ts +0 -2
  74. package/dist/handler/error/types.d.ts +0 -11
  75. package/dist/handler/index.d.ts +0 -7
  76. package/dist/handler/is.d.ts +0 -4
  77. package/dist/handler/module.d.ts +0 -23
  78. package/dist/handler/types-base.d.ts +0 -10
  79. package/dist/handler/types.d.ts +0 -4
  80. package/dist/hook/constants.d.ts +0 -8
  81. package/dist/hook/index.d.ts +0 -3
  82. package/dist/hook/module.d.ts +0 -19
  83. package/dist/hook/types.d.ts +0 -5
  84. package/dist/index.cjs +0 -2314
  85. package/dist/index.cjs.map +0 -1
  86. package/dist/index.d.ts +0 -11
  87. package/dist/index.mjs +0 -2235
  88. package/dist/index.mjs.map +0 -1
  89. package/dist/path/index.d.ts +0 -3
  90. package/dist/path/matcher.d.ts +0 -11
  91. package/dist/path/type.d.ts +0 -7
  92. package/dist/path/utils.d.ts +0 -2
  93. package/dist/plugin/index.d.ts +0 -2
  94. package/dist/plugin/is.d.ts +0 -2
  95. package/dist/plugin/types.d.ts +0 -23
  96. package/dist/request/helpers/cache.d.ts +0 -2
  97. package/dist/request/helpers/env.d.ts +0 -6
  98. package/dist/request/helpers/header-accept-charset.d.ts +0 -3
  99. package/dist/request/helpers/header-accept-encoding.d.ts +0 -3
  100. package/dist/request/helpers/header-accept-language.d.ts +0 -3
  101. package/dist/request/helpers/header-accept.d.ts +0 -3
  102. package/dist/request/helpers/header-content-type.d.ts +0 -2
  103. package/dist/request/helpers/header.d.ts +0 -4
  104. package/dist/request/helpers/hostname.d.ts +0 -7
  105. package/dist/request/helpers/http2.d.ts +0 -2
  106. package/dist/request/helpers/index.d.ts +0 -17
  107. package/dist/request/helpers/ip.d.ts +0 -7
  108. package/dist/request/helpers/mount-path.d.ts +0 -3
  109. package/dist/request/helpers/negotiator.d.ts +0 -3
  110. package/dist/request/helpers/params.d.ts +0 -5
  111. package/dist/request/helpers/path.d.ts +0 -2
  112. package/dist/request/helpers/protocol.d.ts +0 -8
  113. package/dist/request/helpers/router.d.ts +0 -3
  114. package/dist/request/index.d.ts +0 -3
  115. package/dist/request/module.d.ts +0 -3
  116. package/dist/request/types.d.ts +0 -12
  117. package/dist/response/helpers/cache.d.ts +0 -7
  118. package/dist/response/helpers/event-stream/factory.d.ts +0 -3
  119. package/dist/response/helpers/event-stream/index.d.ts +0 -2
  120. package/dist/response/helpers/event-stream/module.d.ts +0 -17
  121. package/dist/response/helpers/event-stream/types.d.ts +0 -24
  122. package/dist/response/helpers/event-stream/utils.d.ts +0 -2
  123. package/dist/response/helpers/gone.d.ts +0 -3
  124. package/dist/response/helpers/header-attachment.d.ts +0 -2
  125. package/dist/response/helpers/header-content-type.d.ts +0 -2
  126. package/dist/response/helpers/header.d.ts +0 -4
  127. package/dist/response/helpers/index.d.ts +0 -16
  128. package/dist/response/helpers/send-accepted.d.ts +0 -2
  129. package/dist/response/helpers/send-created.d.ts +0 -2
  130. package/dist/response/helpers/send-file.d.ts +0 -17
  131. package/dist/response/helpers/send-format.d.ts +0 -7
  132. package/dist/response/helpers/send-redirect.d.ts +0 -2
  133. package/dist/response/helpers/send-stream.d.ts +0 -3
  134. package/dist/response/helpers/send-web-blob.d.ts +0 -3
  135. package/dist/response/helpers/send-web-response.d.ts +0 -3
  136. package/dist/response/helpers/send.d.ts +0 -2
  137. package/dist/response/helpers/utils.d.ts +0 -2
  138. package/dist/response/index.d.ts +0 -3
  139. package/dist/response/module.d.ts +0 -3
  140. package/dist/response/types.d.ts +0 -3
  141. package/dist/router/constants.d.ts +0 -9
  142. package/dist/router/index.d.ts +0 -1
  143. package/dist/router/module.d.ts +0 -89
  144. package/dist/router/types.d.ts +0 -7
  145. package/dist/router/utils.d.ts +0 -3
  146. package/dist/router-options/index.d.ts +0 -2
  147. package/dist/router-options/module.d.ts +0 -4
  148. package/dist/router-options/transform.d.ts +0 -2
  149. package/dist/router-options/type.d.ts +0 -41
  150. package/dist/types.d.ts +0 -9
  151. package/dist/utils/cookie.d.ts +0 -1
  152. package/dist/utils/etag/index.d.ts +0 -3
  153. package/dist/utils/etag/module.d.ts +0 -11
  154. package/dist/utils/etag/type.d.ts +0 -15
  155. package/dist/utils/etag/utils.d.ts +0 -2
  156. package/dist/utils/index.d.ts +0 -13
  157. package/dist/utils/is-instance.d.ts +0 -1
  158. package/dist/utils/method.d.ts +0 -3
  159. package/dist/utils/mime.d.ts +0 -2
  160. package/dist/utils/next.d.ts +0 -2
  161. package/dist/utils/object.d.ts +0 -3
  162. package/dist/utils/path.d.ts +0 -5
  163. package/dist/utils/promise.d.ts +0 -1
  164. package/dist/utils/stream.d.ts +0 -6
  165. package/dist/utils/trust-proxy/index.d.ts +0 -2
  166. package/dist/utils/trust-proxy/module.d.ts +0 -2
  167. package/dist/utils/trust-proxy/type.d.ts +0 -2
  168. package/dist/utils/url.d.ts +0 -7
  169. package/dist/utils/web.d.ts +0 -3
@@ -0,0 +1,1960 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+ //#endregion
23
+ let _ebec_http = require("@ebec/http");
24
+ let node_buffer = require("node:buffer");
25
+ let uncrypto = require("uncrypto");
26
+ let smob = require("smob");
27
+ let proxy_addr = require("proxy-addr");
28
+ let mime_explorer = require("mime-explorer");
29
+ let srvx = require("srvx");
30
+ let path_to_regexp = require("path-to-regexp");
31
+ let negotiator = require("negotiator");
32
+ negotiator = __toESM(negotiator);
33
+ //#region src/constants.ts
34
+ let MethodName = /* @__PURE__ */ function(MethodName) {
35
+ MethodName["GET"] = "GET";
36
+ MethodName["POST"] = "POST";
37
+ MethodName["PUT"] = "PUT";
38
+ MethodName["PATCH"] = "PATCH";
39
+ MethodName["DELETE"] = "DELETE";
40
+ MethodName["OPTIONS"] = "OPTIONS";
41
+ MethodName["HEAD"] = "HEAD";
42
+ return MethodName;
43
+ }({});
44
+ let HeaderName = /* @__PURE__ */ function(HeaderName) {
45
+ HeaderName["ACCEPT"] = "accept";
46
+ HeaderName["ACCEPT_CHARSET"] = "accept-charset";
47
+ HeaderName["ACCEPT_ENCODING"] = "accept-encoding";
48
+ HeaderName["ACCEPT_LANGUAGE"] = "accept-language";
49
+ HeaderName["ACCEPT_RANGES"] = "accept-ranges";
50
+ HeaderName["ALLOW"] = "allow";
51
+ HeaderName["CACHE_CONTROL"] = "cache-control";
52
+ HeaderName["CONTENT_DISPOSITION"] = "content-disposition";
53
+ HeaderName["CONTENT_ENCODING"] = "content-encoding";
54
+ HeaderName["CONTENT_LENGTH"] = "content-length";
55
+ HeaderName["CONTENT_RANGE"] = "content-range";
56
+ HeaderName["CONTENT_TYPE"] = "content-type";
57
+ HeaderName["CONNECTION"] = "connection";
58
+ HeaderName["COOKIE"] = "cookie";
59
+ HeaderName["ETag"] = "etag";
60
+ HeaderName["HOST"] = "host";
61
+ HeaderName["IF_MODIFIED_SINCE"] = "if-modified-since";
62
+ HeaderName["IF_NONE_MATCH"] = "if-none-match";
63
+ HeaderName["LAST_MODIFIED"] = "last-modified";
64
+ HeaderName["LOCATION"] = "location";
65
+ HeaderName["RANGE"] = "range";
66
+ HeaderName["RATE_LIMIT_LIMIT"] = "ratelimit-limit";
67
+ HeaderName["RATE_LIMIT_REMAINING"] = "ratelimit-remaining";
68
+ HeaderName["RATE_LIMIT_RESET"] = "ratelimit-reset";
69
+ HeaderName["RETRY_AFTER"] = "retry-after";
70
+ HeaderName["SET_COOKIE"] = "set-cookie";
71
+ HeaderName["TRANSFER_ENCODING"] = "transfer-encoding";
72
+ HeaderName["X_ACCEL_BUFFERING"] = "x-accel-buffering";
73
+ HeaderName["X_FORWARDED_HOST"] = "x-forwarded-host";
74
+ HeaderName["X_FORWARDED_FOR"] = "x-forwarded-for";
75
+ HeaderName["X_FORWARDED_PROTO"] = "x-forwarded-proto";
76
+ return HeaderName;
77
+ }({});
78
+ //#endregion
79
+ //#region src/utils/header.ts
80
+ function sanitizeHeaderValue(value) {
81
+ return value.replace(/[\r\n]/g, "");
82
+ }
83
+ //#endregion
84
+ //#region src/utils/object.ts
85
+ function isObject(item) {
86
+ return !!item && typeof item === "object" && !Array.isArray(item);
87
+ }
88
+ //#endregion
89
+ //#region src/utils/etag/module.ts
90
+ /**
91
+ * Determine if object is a Stats object.
92
+ *
93
+ * @param {object} obj
94
+ * @return {boolean}
95
+ * @api private
96
+ */
97
+ function isStatsObject(obj) {
98
+ return isObject(obj) && "ctime" in obj && Object.prototype.toString.call(obj.ctime) === "[object Date]" && "mtime" in obj && Object.prototype.toString.call(obj.mtime) === "[object Date]" && "ino" in obj && typeof obj.ino === "number" && "size" in obj && typeof obj.size === "number";
99
+ }
100
+ async function sha1(str) {
101
+ const enc = new TextEncoder();
102
+ const hash = await uncrypto.subtle.digest("SHA-1", enc.encode(str));
103
+ return btoa(String.fromCharCode(...new Uint8Array(hash)));
104
+ }
105
+ /**
106
+ * Generate an ETag.
107
+ */
108
+ async function generateETag(input) {
109
+ if (isStatsObject(input)) {
110
+ const mtime = input.mtime.getTime().toString(16);
111
+ return `"${input.size.toString(16)}-${mtime}"`;
112
+ }
113
+ if (input.length === 0) return "\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\"";
114
+ const entity = node_buffer.Buffer.isBuffer(input) ? input.toString("utf-8") : input;
115
+ const hash = await sha1(entity);
116
+ return `"${entity.length.toString(16)}-${hash.substring(0, 27)}"`;
117
+ }
118
+ /**
119
+ * Create a simple ETag.
120
+ */
121
+ async function createEtag(input, options) {
122
+ options = options || {};
123
+ const weak = typeof options.weak === "boolean" ? options.weak : isStatsObject(input);
124
+ const tag = await generateETag(input);
125
+ return weak ? `W/${tag}` : tag;
126
+ }
127
+ //#endregion
128
+ //#region src/utils/etag/utils.ts
129
+ function buildEtagFn(input) {
130
+ if (typeof input === "function") return input;
131
+ input = input ?? true;
132
+ if (input === false) return () => Promise.resolve(void 0);
133
+ let options = { weak: true };
134
+ if (isObject(input)) options = (0, smob.merge)(input, options);
135
+ return async (body, encoding, size) => {
136
+ const buff = node_buffer.Buffer.isBuffer(body) ? body : node_buffer.Buffer.from(body, encoding);
137
+ if (typeof options.threshold !== "undefined") {
138
+ size = size ?? node_buffer.Buffer.byteLength(buff);
139
+ if (size <= options.threshold) return;
140
+ }
141
+ return createEtag(buff, options);
142
+ };
143
+ }
144
+ //#endregion
145
+ //#region src/utils/trust-proxy/module.ts
146
+ function buildTrustProxyFn(input) {
147
+ if (typeof input === "function") return input;
148
+ if (input === true) return () => true;
149
+ if (typeof input === "number") return (_address, hop) => hop < input;
150
+ if (typeof input === "string") input = input.split(",").map((value) => value.trim());
151
+ return (0, proxy_addr.compile)(input || []);
152
+ }
153
+ //#endregion
154
+ //#region src/utils/is-instance.ts
155
+ function isInstance(input, sym) {
156
+ if (!isObject(input)) return false;
157
+ return input["@instanceof"] === sym;
158
+ }
159
+ //#endregion
160
+ //#region src/utils/mime.ts
161
+ function getMimeType(type) {
162
+ if (type.includes("/")) return type;
163
+ return (0, mime_explorer.getType)(type);
164
+ }
165
+ function getCharsetForMimeType(type) {
166
+ if (/^text\/|^application\/(javascript|json)/.test(type)) return "utf-8";
167
+ const meta = (0, mime_explorer.get)(type);
168
+ if (meta && meta.charset) return meta.charset.toLowerCase();
169
+ }
170
+ //#endregion
171
+ //#region src/utils/method.ts
172
+ function toMethodName(input, alt) {
173
+ if (input) return input.toUpperCase();
174
+ return alt;
175
+ }
176
+ //#endregion
177
+ //#region src/utils/path.ts
178
+ /**
179
+ * Based on https://github.com/unjs/pathe v1.1.1 (055f50a6f1131f4e5c56cf259dd8816168fba329)
180
+ */
181
+ function normalizeWindowsPath(input = "") {
182
+ if (!input || !input.includes("\\")) return input;
183
+ return input.replace(/\\/g, "/");
184
+ }
185
+ const EXTNAME_RE = /.(\.[^./]+)$/;
186
+ function extname(input) {
187
+ const match = EXTNAME_RE.exec(normalizeWindowsPath(input));
188
+ return match && match[1] || "";
189
+ }
190
+ function basename(input, extension) {
191
+ const lastSegment = normalizeWindowsPath(input).split("/").pop();
192
+ if (!lastSegment) return input;
193
+ return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
194
+ }
195
+ //#endregion
196
+ //#region src/utils/url.ts
197
+ const TRAILING_SLASH_RE = /\/$|\/\?/;
198
+ function hasTrailingSlash(input = "", queryParams = false) {
199
+ if (!queryParams) return input.endsWith("/");
200
+ return TRAILING_SLASH_RE.test(input);
201
+ }
202
+ function withoutTrailingSlash(input = "", queryParams = false) {
203
+ if (!queryParams) return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || "/";
204
+ if (!hasTrailingSlash(input, true)) return input || "/";
205
+ const [s0, ...s] = input.split("?");
206
+ return (s0.slice(0, -1) || "/") + (s.length ? `?${s.join("?")}` : "");
207
+ }
208
+ function hasLeadingSlash(input = "") {
209
+ return input.startsWith("/");
210
+ }
211
+ function withLeadingSlash(input = "") {
212
+ return hasLeadingSlash(input) ? input : `/${input}`;
213
+ }
214
+ function cleanDoubleSlashes(input = "") {
215
+ if (input.includes("://")) return input.split("://").map((str) => cleanDoubleSlashes(str)).join("://");
216
+ return input.replace(/\/+/g, "/");
217
+ }
218
+ //#endregion
219
+ //#region src/error/is.ts
220
+ function isError(input) {
221
+ if (!(0, _ebec_http.isHTTPError)(input)) return false;
222
+ return input.name === "RoutupError";
223
+ }
224
+ //#endregion
225
+ //#region src/error/module.ts
226
+ var RoutupError = class extends _ebec_http.HTTPError {
227
+ constructor(input = {}) {
228
+ super(input);
229
+ this.name = "RoutupError";
230
+ }
231
+ };
232
+ //#endregion
233
+ //#region src/error/create.ts
234
+ function isNativeError(input) {
235
+ return isObject(input) && typeof input.message === "string" && typeof input.name === "string";
236
+ }
237
+ /**
238
+ * Create an internal error object by
239
+ * - an existing RoutupError (returned as-is)
240
+ * - an HTTPError (wrapped into a RoutupError preserving status)
241
+ * - an Error (wrapped preserving message and cause)
242
+ * - an options object (statusCode, statusMessage, etc.)
243
+ * - a message string
244
+ *
245
+ * @param input
246
+ */
247
+ function createError(input) {
248
+ if (isError(input)) return input;
249
+ if (typeof input === "string") return new RoutupError(input);
250
+ if ((0, _ebec_http.isHTTPError)(input)) return new RoutupError({
251
+ message: input.message,
252
+ code: input.code,
253
+ statusCode: input.statusCode,
254
+ statusMessage: input.statusMessage,
255
+ redirectURL: input.redirectURL,
256
+ cause: input
257
+ });
258
+ if (isNativeError(input)) return new RoutupError({
259
+ message: input.message,
260
+ cause: input
261
+ });
262
+ if (!isObject(input)) return new RoutupError();
263
+ const options = { ...input };
264
+ if (options.cause === void 0) options.cause = input;
265
+ return new RoutupError(options);
266
+ }
267
+ //#endregion
268
+ //#region src/event/module.ts
269
+ var RoutupEvent = class {
270
+ request;
271
+ params;
272
+ path;
273
+ method;
274
+ mountPath;
275
+ error;
276
+ routerPath;
277
+ /**
278
+ * Collected allowed methods (for OPTIONS).
279
+ */
280
+ methodsAllowed;
281
+ store;
282
+ _dispatched;
283
+ _response;
284
+ /**
285
+ * Cached parsed URL (avoids double-parsing).
286
+ */
287
+ _url;
288
+ _searchParams;
289
+ /**
290
+ * Continuation function for middleware onion model.
291
+ */
292
+ _next;
293
+ /**
294
+ * Whether _next has already been called (guard against double-invocation).
295
+ */
296
+ _nextCalled;
297
+ /**
298
+ * The cached result of the next handler.
299
+ */
300
+ _nextResult;
301
+ constructor(request) {
302
+ this.request = request;
303
+ this._url = new srvx.FastURL(request.url);
304
+ this.method = request.method;
305
+ this.path = this._url.pathname;
306
+ this.mountPath = "/";
307
+ this.params = {};
308
+ this.routerPath = [];
309
+ this.methodsAllowed = [];
310
+ this.store = Object.create(null);
311
+ this._dispatched = false;
312
+ this._nextCalled = false;
313
+ }
314
+ get headers() {
315
+ return this.request.headers;
316
+ }
317
+ get searchParams() {
318
+ if (!this._searchParams) this._searchParams = new URLSearchParams(this._url.search);
319
+ return this._searchParams;
320
+ }
321
+ get response() {
322
+ if (!this._response) this._response = {
323
+ status: 200,
324
+ headers: new Headers()
325
+ };
326
+ return this._response;
327
+ }
328
+ get dispatched() {
329
+ return this._dispatched;
330
+ }
331
+ set dispatched(value) {
332
+ this._dispatched = value;
333
+ }
334
+ async next() {
335
+ if (this._nextCalled) return this._nextResult;
336
+ this._nextCalled = true;
337
+ if (this._next) this._nextResult = this._next();
338
+ return this._nextResult;
339
+ }
340
+ };
341
+ //#endregion
342
+ //#region src/handler/constants.ts
343
+ let HandlerType = /* @__PURE__ */ function(HandlerType) {
344
+ HandlerType["CORE"] = "core";
345
+ HandlerType["ERROR"] = "error";
346
+ return HandlerType;
347
+ }({});
348
+ const HandlerSymbol = /* @__PURE__ */ Symbol.for("Handler");
349
+ //#endregion
350
+ //#region src/hook/constants.ts
351
+ let HookName = /* @__PURE__ */ function(HookName) {
352
+ HookName["REQUEST"] = "request";
353
+ HookName["RESPONSE"] = "response";
354
+ HookName["ERROR"] = "error";
355
+ HookName["CHILD_MATCH"] = "childMatch";
356
+ HookName["CHILD_DISPATCH_BEFORE"] = "childDispatchBefore";
357
+ HookName["CHILD_DISPATCH_AFTER"] = "childDispatchAfter";
358
+ return HookName;
359
+ }({});
360
+ //#endregion
361
+ //#region src/hook/module.ts
362
+ var HookManager = class {
363
+ items;
364
+ constructor() {
365
+ this.items = {};
366
+ }
367
+ addListener(name, fn) {
368
+ this.items[name] = this.items[name] || [];
369
+ this.items[name].push(fn);
370
+ return () => {
371
+ this.removeListener(name, fn);
372
+ };
373
+ }
374
+ removeListener(name, fn) {
375
+ if (!this.items[name]) return;
376
+ if (typeof fn === "undefined") {
377
+ delete this.items[name];
378
+ return;
379
+ }
380
+ if (typeof fn === "function") {
381
+ const index = this.items[name].indexOf(fn);
382
+ if (index !== -1) this.items[name].splice(index, 1);
383
+ }
384
+ if (this.items[name].length === 0) delete this.items[name];
385
+ }
386
+ async trigger(name, event) {
387
+ if (!this.items[name] || this.items[name].length === 0) return;
388
+ try {
389
+ for (let i = 0; i < this.items[name].length; i++) {
390
+ const listener = this.items[name][i];
391
+ await this.triggerListener(name, event, listener);
392
+ if (event.dispatched) {
393
+ if (event.error) event.error = void 0;
394
+ return;
395
+ }
396
+ }
397
+ } catch (e) {
398
+ event.error = e;
399
+ if (!this.isErrorListenerHook(name)) {
400
+ await this.trigger(HookName.ERROR, event);
401
+ if (event.dispatched) {
402
+ if (event.error) event.error = void 0;
403
+ }
404
+ }
405
+ }
406
+ }
407
+ triggerListener(name, event, listener) {
408
+ if (this.isErrorListenerHook(name)) {
409
+ if (event.error) return listener(event);
410
+ return;
411
+ }
412
+ return listener(event);
413
+ }
414
+ isErrorListenerHook(input) {
415
+ return input === HookName.ERROR;
416
+ }
417
+ };
418
+ //#endregion
419
+ //#region src/path/matcher.ts
420
+ function decodeParam(val) {
421
+ /* istanbul ignore next */
422
+ if (typeof val !== "string" || val.length === 0) return val;
423
+ try {
424
+ return decodeURIComponent(val);
425
+ } catch {
426
+ return val;
427
+ }
428
+ }
429
+ var PathMatcher = class {
430
+ path;
431
+ regexp;
432
+ regexpKeys = [];
433
+ regexpOptions;
434
+ constructor(path, options) {
435
+ this.path = path;
436
+ this.regexpOptions = options || {};
437
+ const regexp = (0, path_to_regexp.pathToRegexp)(path, options);
438
+ this.regexp = regexp.regexp;
439
+ this.regexpKeys = regexp.keys;
440
+ }
441
+ test(path) {
442
+ return this.regexp.test(path);
443
+ }
444
+ exec(path) {
445
+ if (this.path === "/" && this.regexpOptions.end === false) return {
446
+ path: "/",
447
+ params: Object.create(null)
448
+ };
449
+ const match = this.regexp.exec(path);
450
+ if (!match) return;
451
+ const params = Object.create(null);
452
+ for (let i = 1; i < match.length; i++) {
453
+ const key = this.regexpKeys[i - 1];
454
+ if (!key) continue;
455
+ const prop = key.name;
456
+ const val = decodeParam(match[i]);
457
+ if (typeof val !== "undefined") params[prop] = val;
458
+ }
459
+ return {
460
+ path: match[0],
461
+ params
462
+ };
463
+ }
464
+ };
465
+ //#endregion
466
+ //#region src/path/utils.ts
467
+ function isPath(input) {
468
+ return typeof input === "string";
469
+ }
470
+ //#endregion
471
+ //#region src/response/helpers/cache.ts
472
+ function setResponseCacheHeaders(event, options) {
473
+ options = options || {};
474
+ const cacheControls = ["public"].concat(options.cacheControls || []);
475
+ if (options.maxAge !== void 0) cacheControls.push(`max-age=${+options.maxAge}`, `s-maxage=${+options.maxAge}`);
476
+ if (options.modifiedTime) {
477
+ const modifiedTime = typeof options.modifiedTime === "string" ? new Date(options.modifiedTime) : options.modifiedTime;
478
+ event.response.headers.set("last-modified", modifiedTime.toUTCString());
479
+ }
480
+ event.response.headers.set("cache-control", cacheControls.join(", "));
481
+ }
482
+ //#endregion
483
+ //#region src/response/helpers/event-stream/utils.ts
484
+ function stripNewlines(value) {
485
+ return value.replace(/[\r\n]/g, "");
486
+ }
487
+ function serializeEventStreamMessage(message) {
488
+ let result = "";
489
+ if (message.id) result += `id: ${stripNewlines(message.id)}\n`;
490
+ if (message.event) result += `event: ${stripNewlines(message.event)}\n`;
491
+ if (typeof message.retry === "number" && Number.isInteger(message.retry)) result += `retry: ${message.retry}\n`;
492
+ const lines = message.data.replace(/\r/g, "").split("\n");
493
+ for (const line of lines) result += `data: ${line}\n`;
494
+ result += "\n";
495
+ return result;
496
+ }
497
+ //#endregion
498
+ //#region src/response/helpers/event-stream/module.ts
499
+ function createEventStream(event, options) {
500
+ if (options?.maxMessageSize !== void 0) {
501
+ if (!Number.isInteger(options.maxMessageSize) || options.maxMessageSize < 0) throw new RoutupError("maxMessageSize must be a non-negative integer.");
502
+ }
503
+ let controller;
504
+ let closed = false;
505
+ const encoder = new TextEncoder();
506
+ const stream = new ReadableStream({
507
+ start(ctrl) {
508
+ controller = ctrl;
509
+ },
510
+ cancel() {
511
+ closed = true;
512
+ }
513
+ });
514
+ const headers = new Headers(event.response.headers);
515
+ headers.set(HeaderName.CONTENT_TYPE, "text/event-stream");
516
+ headers.set(HeaderName.CACHE_CONTROL, "private, no-cache, no-store, no-transform, must-revalidate, max-age=0");
517
+ headers.set(HeaderName.X_ACCEL_BUFFERING, "no");
518
+ headers.set(HeaderName.CONNECTION, "keep-alive");
519
+ const handle = {
520
+ write(message) {
521
+ if (closed) return;
522
+ if (typeof message === "string") {
523
+ handle.write({ data: message });
524
+ return;
525
+ }
526
+ const serialized = serializeEventStreamMessage(message);
527
+ if (options?.maxMessageSize !== void 0) {
528
+ if (encoder.encode(serialized).byteLength > options.maxMessageSize) return;
529
+ }
530
+ controller.enqueue(encoder.encode(serialized));
531
+ },
532
+ end() {
533
+ if (closed) return;
534
+ closed = true;
535
+ controller.close();
536
+ },
537
+ response: new Response(stream, {
538
+ status: event.response.status,
539
+ statusText: event.response.statusText,
540
+ headers
541
+ })
542
+ };
543
+ return handle;
544
+ }
545
+ //#endregion
546
+ //#region src/response/helpers/gone.ts
547
+ function isResponseGone(event) {
548
+ return event.dispatched;
549
+ }
550
+ function setResponseGone(event) {
551
+ event.dispatched = true;
552
+ }
553
+ //#endregion
554
+ //#region src/response/helpers/header.ts
555
+ function appendResponseHeader(event, name, value) {
556
+ const { headers } = event.response;
557
+ if (Array.isArray(value)) for (const v of value) headers.append(name, sanitizeHeaderValue(v));
558
+ else headers.append(name, sanitizeHeaderValue(value));
559
+ }
560
+ function appendResponseHeaderDirective(event, name, value) {
561
+ const { headers } = event.response;
562
+ const existing = headers.get(name);
563
+ if (!existing) {
564
+ if (Array.isArray(value)) headers.set(name, sanitizeHeaderValue(value.join("; ")));
565
+ else headers.set(name, sanitizeHeaderValue(value));
566
+ return;
567
+ }
568
+ const directives = existing.split("; ");
569
+ if (Array.isArray(value)) directives.push(...value);
570
+ else directives.push(value);
571
+ const unique = [...new Set(directives)];
572
+ headers.set(name, sanitizeHeaderValue(unique.join("; ")));
573
+ }
574
+ //#endregion
575
+ //#region src/response/helpers/utils.ts
576
+ function setResponseContentTypeByFileName(event, fileName) {
577
+ const ext = extname(fileName);
578
+ if (ext) {
579
+ let type = getMimeType(ext.substring(1));
580
+ if (type) {
581
+ const charset = getCharsetForMimeType(type);
582
+ if (charset) type += `; charset=${charset}`;
583
+ event.response.headers.set(HeaderName.CONTENT_TYPE, type);
584
+ }
585
+ }
586
+ }
587
+ //#endregion
588
+ //#region src/response/helpers/header-attachment.ts
589
+ function sanitizeFilename(filename) {
590
+ return filename.replace(/[\r\n]/g, "");
591
+ }
592
+ function toAsciiFilename(filename) {
593
+ return filename.replace(/[^\x20-\x7E]/g, "").replace(/"/g, "\\\"");
594
+ }
595
+ function encodeRfc5987(filename) {
596
+ return encodeURIComponent(filename).replace(/['()]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`).replace(/\*/g, "%2A");
597
+ }
598
+ function setResponseHeaderAttachment(event, filename) {
599
+ if (typeof filename === "string") setResponseContentTypeByFileName(event, filename);
600
+ let disposition = "attachment";
601
+ if (filename) {
602
+ const sanitized = sanitizeFilename(filename);
603
+ const ascii = toAsciiFilename(sanitized);
604
+ disposition += `; filename="${ascii}"`;
605
+ disposition += `; filename*=UTF-8''${encodeRfc5987(sanitized)}`;
606
+ }
607
+ event.response.headers.set(HeaderName.CONTENT_DISPOSITION, disposition);
608
+ }
609
+ //#endregion
610
+ //#region src/response/helpers/header-content-type.ts
611
+ function setResponseHeaderContentType(event, input, ifNotExists) {
612
+ if (ifNotExists) {
613
+ if (event.response.headers.get(HeaderName.CONTENT_TYPE)) return;
614
+ }
615
+ const contentType = getMimeType(input);
616
+ if (contentType) event.response.headers.set(HeaderName.CONTENT_TYPE, contentType);
617
+ }
618
+ //#endregion
619
+ //#region src/router-options/module.ts
620
+ const defaults = {
621
+ trustProxy: () => false,
622
+ subdomainOffset: 2,
623
+ etag: buildEtagFn(),
624
+ proxyIpMax: 0
625
+ };
626
+ const instances = {};
627
+ function setRouterOptions(id, input) {
628
+ instances[id] = input;
629
+ }
630
+ function findRouterOption(key, path) {
631
+ if (!path || path.length === 0) return defaults[key];
632
+ if (path.length > 0) for (let i = path.length; i >= 0; i--) {
633
+ const segment = path[i];
634
+ if (segment !== void 0 && (0, smob.hasOwnProperty)(instances, segment) && typeof instances[segment][key] !== "undefined") return instances[segment][key];
635
+ }
636
+ return defaults[key];
637
+ }
638
+ //#endregion
639
+ //#region src/response/to-response.ts
640
+ function stripWeakPrefix(etag) {
641
+ return etag.startsWith("W/") ? etag.slice(2) : etag;
642
+ }
643
+ async function applyEtag(body, event, headers) {
644
+ const etagFn = findRouterOption("etag", event.routerPath);
645
+ if (!etagFn) return void 0;
646
+ const etag = await etagFn(body);
647
+ if (!etag) return void 0;
648
+ headers.set("etag", etag);
649
+ const ifNoneMatch = event.headers.get("if-none-match");
650
+ if (ifNoneMatch && (ifNoneMatch === "*" || ifNoneMatch.split(",").some((t) => stripWeakPrefix(t.trim()) === stripWeakPrefix(etag)))) return new Response(null, {
651
+ status: 304,
652
+ headers
653
+ });
654
+ }
655
+ async function toResponse(value, event) {
656
+ if (value === void 0) return;
657
+ if (value === null) return new Response(null, {
658
+ status: event.response.status,
659
+ statusText: event.response.statusText,
660
+ headers: event.response.headers
661
+ });
662
+ if (value instanceof Response) return value;
663
+ const { status, headers, statusText } = event.response;
664
+ if (typeof value === "string") {
665
+ if (!headers.has("content-type")) headers.set("content-type", "text/plain; charset=utf-8");
666
+ const cached = await applyEtag(value, event, headers);
667
+ if (cached) return cached;
668
+ return new Response(value, {
669
+ status,
670
+ statusText,
671
+ headers
672
+ });
673
+ }
674
+ if (value instanceof ArrayBuffer || value instanceof Uint8Array) {
675
+ if (!headers.has("content-type")) headers.set("content-type", "application/octet-stream");
676
+ return new Response(value, {
677
+ status,
678
+ statusText,
679
+ headers
680
+ });
681
+ }
682
+ if (value instanceof ReadableStream) return new Response(value, {
683
+ status,
684
+ statusText,
685
+ headers
686
+ });
687
+ if (value instanceof Blob) {
688
+ if (!headers.has("content-type")) headers.set("content-type", value.type || "application/octet-stream");
689
+ return new Response(value, {
690
+ status,
691
+ statusText,
692
+ headers
693
+ });
694
+ }
695
+ if (!headers.has("content-type")) headers.set("content-type", "application/json; charset=utf-8");
696
+ const json = JSON.stringify(value);
697
+ const cached = await applyEtag(json, event, headers);
698
+ if (cached) return cached;
699
+ return new Response(json, {
700
+ status,
701
+ statusText,
702
+ headers
703
+ });
704
+ }
705
+ //#endregion
706
+ //#region src/response/helpers/send-accepted.ts
707
+ async function sendAccepted(event, data) {
708
+ event.response.status = 202;
709
+ event.response.statusText = "Accepted";
710
+ event.dispatched = true;
711
+ return await toResponse(data ?? "", event);
712
+ }
713
+ //#endregion
714
+ //#region src/response/helpers/send-created.ts
715
+ async function sendCreated(event, data) {
716
+ event.response.status = 201;
717
+ event.response.statusText = "Created";
718
+ event.dispatched = true;
719
+ return await toResponse(data ?? "", event);
720
+ }
721
+ //#endregion
722
+ //#region src/response/helpers/send-file.ts
723
+ async function sendFile(event, options) {
724
+ const stats = await options.stats();
725
+ const name = options.name || stats.name;
726
+ const { headers } = event.response;
727
+ if (name) {
728
+ const fileName = basename(name);
729
+ if (options.attachment) {
730
+ if (!headers.get(HeaderName.CONTENT_DISPOSITION)) setResponseHeaderAttachment(event, fileName);
731
+ } else setResponseContentTypeByFileName(event, fileName);
732
+ }
733
+ const contentOptions = {};
734
+ let statusCode = event.response.status;
735
+ if (stats.size) {
736
+ const rangeHeader = event.headers.get(HeaderName.RANGE);
737
+ if (rangeHeader) {
738
+ const [x, y] = rangeHeader.replace("bytes=", "").split("-");
739
+ const parsedStart = Number.parseInt(x, 10);
740
+ const parsedEnd = Number.parseInt(y, 10);
741
+ contentOptions.start = Number.isFinite(parsedStart) && parsedStart >= 0 ? parsedStart : 0;
742
+ contentOptions.end = Number.isFinite(parsedEnd) && parsedEnd >= 0 ? Math.min(parsedEnd, stats.size - 1) : stats.size - 1;
743
+ if (contentOptions.start >= stats.size || contentOptions.start > contentOptions.end) {
744
+ event.dispatched = true;
745
+ const rangeHeaders = new Headers(headers);
746
+ rangeHeaders.set(HeaderName.CONTENT_RANGE, `bytes */${stats.size}`);
747
+ return new Response(null, {
748
+ status: 416,
749
+ statusText: event.response.statusText,
750
+ headers: rangeHeaders
751
+ });
752
+ }
753
+ headers.set(HeaderName.CONTENT_RANGE, `bytes ${contentOptions.start}-${contentOptions.end}/${stats.size}`);
754
+ headers.set(HeaderName.CONTENT_LENGTH, `${contentOptions.end - contentOptions.start + 1}`);
755
+ statusCode = 206;
756
+ } else headers.set(HeaderName.CONTENT_LENGTH, `${stats.size}`);
757
+ headers.set(HeaderName.ACCEPT_RANGES, "bytes");
758
+ if (stats.mtime) {
759
+ const mtime = new Date(stats.mtime);
760
+ headers.set(HeaderName.LAST_MODIFIED, mtime.toUTCString());
761
+ headers.set(HeaderName.ETag, `W/"${stats.size}-${mtime.getTime()}"`);
762
+ }
763
+ }
764
+ const content = await options.content(contentOptions);
765
+ event.dispatched = true;
766
+ return new Response(content, {
767
+ status: statusCode,
768
+ statusText: event.response.statusText,
769
+ headers
770
+ });
771
+ }
772
+ //#endregion
773
+ //#region src/request/helpers/header.ts
774
+ function getRequestHeader(event, name) {
775
+ return event.headers.get(name);
776
+ }
777
+ //#endregion
778
+ //#region src/request/helpers/negotiator.ts
779
+ const NEGOTIATOR_KEY = /* @__PURE__ */ Symbol.for("routup:negotiator");
780
+ function headersToPlainObject(headers) {
781
+ const result = {};
782
+ headers.forEach((value, key) => {
783
+ result[key] = value;
784
+ });
785
+ return result;
786
+ }
787
+ function useRequestNegotiator(event) {
788
+ let value = event.store[NEGOTIATOR_KEY];
789
+ if (value) return value;
790
+ value = new negotiator.default({ headers: headersToPlainObject(event.headers) });
791
+ event.store[NEGOTIATOR_KEY] = value;
792
+ return value;
793
+ }
794
+ //#endregion
795
+ //#region src/request/helpers/header-accept.ts
796
+ function getRequestAcceptableContentTypes(event) {
797
+ return useRequestNegotiator(event).mediaTypes();
798
+ }
799
+ function getRequestAcceptableContentType(event, input) {
800
+ input = input || [];
801
+ const items = Array.isArray(input) ? input : [input];
802
+ if (items.length === 0) return getRequestAcceptableContentTypes(event).shift();
803
+ if (!getRequestHeader(event, HeaderName.ACCEPT)) return items[0];
804
+ let polluted = false;
805
+ const mimeTypes = [];
806
+ for (const item of items) {
807
+ const mimeType = getMimeType(item);
808
+ if (mimeType) mimeTypes.push(mimeType);
809
+ else polluted = true;
810
+ }
811
+ const matches = useRequestNegotiator(event).mediaTypes(mimeTypes);
812
+ if (matches.length > 0) {
813
+ if (polluted) return items[0];
814
+ return items[mimeTypes.indexOf(matches[0])];
815
+ }
816
+ }
817
+ //#endregion
818
+ //#region src/response/helpers/send-format.ts
819
+ function sendFormat(event, input) {
820
+ const { default: formatDefault, ...formats } = input;
821
+ const contentTypes = Object.keys(formats);
822
+ if (contentTypes.length === 0) return formatDefault();
823
+ const contentType = getRequestAcceptableContentType(event, contentTypes);
824
+ if (contentType && formats[contentType]) return formats[contentType]();
825
+ return formatDefault();
826
+ }
827
+ //#endregion
828
+ //#region src/response/helpers/send-redirect.ts
829
+ function escapeHtml(str) {
830
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
831
+ }
832
+ function isAllowedRedirectUrl(location) {
833
+ if (location.startsWith("//")) return false;
834
+ if (location.startsWith("/") || location.startsWith(".")) return true;
835
+ try {
836
+ const url = new URL(location);
837
+ return url.protocol === "http:" || url.protocol === "https:";
838
+ } catch {
839
+ return true;
840
+ }
841
+ }
842
+ function sendRedirect(event, location, statusCode = 302) {
843
+ if (!isAllowedRedirectUrl(location)) throw new RoutupError({
844
+ statusCode: 400,
845
+ statusMessage: "Invalid redirect URL scheme."
846
+ });
847
+ const sanitizedLocation = sanitizeHeaderValue(location);
848
+ const html = `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${escapeHtml(location)}"></head></html>`;
849
+ const headers = new Headers(event.response.headers);
850
+ headers.set("location", sanitizedLocation);
851
+ headers.set("content-type", "text/html; charset=utf-8");
852
+ headers.delete("content-length");
853
+ const response = new Response(html, {
854
+ status: statusCode,
855
+ statusText: event.response.statusText,
856
+ headers
857
+ });
858
+ event.dispatched = true;
859
+ return response;
860
+ }
861
+ //#endregion
862
+ //#region src/response/helpers/send-stream.ts
863
+ function sendStream(event, stream) {
864
+ event.dispatched = true;
865
+ const { status, statusText, headers } = event.response;
866
+ return new Response(stream, {
867
+ status,
868
+ statusText,
869
+ headers
870
+ });
871
+ }
872
+ //#endregion
873
+ //#region src/handler/module.ts
874
+ var Handler = class {
875
+ "@instanceof" = HandlerSymbol;
876
+ config;
877
+ hookManager;
878
+ pathMatcher;
879
+ _method;
880
+ constructor(handler) {
881
+ this.config = handler;
882
+ this.hookManager = new HookManager();
883
+ this.mountHooks();
884
+ this.setPath(handler.path);
885
+ }
886
+ get type() {
887
+ return this.config.type;
888
+ }
889
+ get path() {
890
+ return this.config.path;
891
+ }
892
+ get method() {
893
+ if (this._method || !this.config.method) return this._method;
894
+ this._method = toMethodName(this.config.method);
895
+ return this._method;
896
+ }
897
+ async dispatch(event) {
898
+ if (this.pathMatcher) {
899
+ const pathMatch = this.pathMatcher.exec(event.path);
900
+ if (pathMatch) event.params = {
901
+ ...event.params,
902
+ ...pathMatch.params
903
+ };
904
+ }
905
+ await this.hookManager.trigger(HookName.CHILD_DISPATCH_BEFORE, event);
906
+ if (event.dispatched) return;
907
+ let response;
908
+ try {
909
+ let result;
910
+ if (this.config.type === HandlerType.ERROR) {
911
+ if (event.error) result = await this.config.fn(event.error, event);
912
+ } else result = await this.config.fn(event);
913
+ response = await toResponse(result, event);
914
+ if (response) event.dispatched = true;
915
+ } catch (e) {
916
+ event.error = isError(e) ? e : createError(e);
917
+ await this.hookManager.trigger(HookName.ERROR, event);
918
+ if (event.dispatched) event.error = void 0;
919
+ else throw event.error;
920
+ }
921
+ await this.hookManager.trigger(HookName.CHILD_DISPATCH_AFTER, event);
922
+ return response;
923
+ }
924
+ matchPath(path) {
925
+ if (!this.pathMatcher) return true;
926
+ return this.pathMatcher.test(path);
927
+ }
928
+ setPath(path) {
929
+ if (typeof path === "string") path = withLeadingSlash(path);
930
+ this.config.path = path;
931
+ if (typeof path === "undefined") {
932
+ this.pathMatcher = void 0;
933
+ return;
934
+ }
935
+ this.pathMatcher = new PathMatcher(path, { end: !!this.config.method });
936
+ }
937
+ matchMethod(method) {
938
+ return !this.method || method === this.method || method === MethodName.HEAD && this.method === MethodName.GET;
939
+ }
940
+ setMethod(input) {
941
+ const method = toMethodName(input);
942
+ this.config.method = method;
943
+ this._method = method;
944
+ }
945
+ mountHooks() {
946
+ if (this.config.onBefore) this.hookManager.addListener(HookName.CHILD_DISPATCH_BEFORE, this.config.onBefore);
947
+ if (this.config.onAfter) this.hookManager.addListener(HookName.CHILD_DISPATCH_AFTER, this.config.onAfter);
948
+ if (this.config.onError) this.hookManager.addListener(HookName.ERROR, this.config.onError);
949
+ }
950
+ };
951
+ //#endregion
952
+ //#region src/handler/core/define.ts
953
+ function defineCoreHandler(input) {
954
+ if (typeof input === "function") return new Handler({
955
+ type: HandlerType.CORE,
956
+ fn: input
957
+ });
958
+ return new Handler({
959
+ type: HandlerType.CORE,
960
+ ...input
961
+ });
962
+ }
963
+ //#endregion
964
+ //#region src/handler/error/define.ts
965
+ function defineErrorHandler(input) {
966
+ if (typeof input === "function") return new Handler({
967
+ type: HandlerType.ERROR,
968
+ fn: input
969
+ });
970
+ return new Handler({
971
+ type: HandlerType.ERROR,
972
+ ...input
973
+ });
974
+ }
975
+ //#endregion
976
+ //#region src/handler/adapters/node/define.ts
977
+ const kHandled = /* @__PURE__ */ Symbol("handled");
978
+ function callHandler(handler, req, res) {
979
+ return new Promise((resolve, reject) => {
980
+ let settled = false;
981
+ const onClose = () => settle(kHandled);
982
+ const onFinish = () => settle(kHandled);
983
+ const onError = (error) => fail(error);
984
+ function cleanup() {
985
+ res.removeListener("close", onClose);
986
+ res.removeListener("finish", onFinish);
987
+ res.removeListener("error", onError);
988
+ }
989
+ function settle(value) {
990
+ if (settled) return;
991
+ settled = true;
992
+ cleanup();
993
+ resolve(value);
994
+ }
995
+ function fail(error) {
996
+ if (settled) return;
997
+ settled = true;
998
+ cleanup();
999
+ reject(error);
1000
+ }
1001
+ res.once("close", onClose);
1002
+ res.once("finish", onFinish);
1003
+ res.once("error", onError);
1004
+ try {
1005
+ Promise.resolve(handler(req, res)).then(() => settle(kHandled)).catch(fail);
1006
+ } catch (error) {
1007
+ fail(error);
1008
+ }
1009
+ });
1010
+ }
1011
+ function callMiddleware(handler, req, res) {
1012
+ return new Promise((resolve, reject) => {
1013
+ let settled = false;
1014
+ const onClose = () => settle(kHandled);
1015
+ const onFinish = () => settle(kHandled);
1016
+ const onError = (error) => fail(error);
1017
+ function cleanup() {
1018
+ res.removeListener("close", onClose);
1019
+ res.removeListener("finish", onFinish);
1020
+ res.removeListener("error", onError);
1021
+ }
1022
+ function settle(value) {
1023
+ if (settled) return;
1024
+ settled = true;
1025
+ cleanup();
1026
+ resolve(value);
1027
+ }
1028
+ function fail(error) {
1029
+ if (settled) return;
1030
+ settled = true;
1031
+ cleanup();
1032
+ reject(error);
1033
+ }
1034
+ res.once("close", onClose);
1035
+ res.once("finish", onFinish);
1036
+ res.once("error", onError);
1037
+ try {
1038
+ Promise.resolve(handler(req, res, (error) => {
1039
+ if (error) fail(error);
1040
+ else settle(res.writableEnded || res.destroyed ? kHandled : void 0);
1041
+ })).catch(fail);
1042
+ } catch (error) {
1043
+ fail(error);
1044
+ }
1045
+ });
1046
+ }
1047
+ function createNodeBridge(handler, isMiddleware) {
1048
+ if (typeof handler !== "function") throw new RoutupError("fromNodeHandler/fromNodeMiddleware expects a function.");
1049
+ return defineCoreHandler({ fn: (async (event) => {
1050
+ const node = event.request.runtime?.node;
1051
+ if (!node?.req || !node?.res) throw new RoutupError("fromNodeHandler/fromNodeMiddleware requires a Node.js runtime.");
1052
+ const req = node.req;
1053
+ const res = node.res;
1054
+ if ((isMiddleware ? await callMiddleware(handler, req, res) : await callHandler(handler, req, res)) === kHandled) event.dispatched = true;
1055
+ }) });
1056
+ }
1057
+ /**
1058
+ * Wraps a Node.js `(req, res)` handler for use in the routup pipeline.
1059
+ *
1060
+ * @example
1061
+ * ```typescript
1062
+ * import { fromNodeHandler } from 'routup/node';
1063
+ *
1064
+ * router.use(fromNodeHandler((req, res) => {
1065
+ * res.end('Hello');
1066
+ * }));
1067
+ * ```
1068
+ */
1069
+ function fromNodeHandler(handler) {
1070
+ return createNodeBridge(handler, false);
1071
+ }
1072
+ /**
1073
+ * Wraps a Node.js `(req, res, next)` middleware for use in the routup pipeline.
1074
+ *
1075
+ * @example
1076
+ * ```typescript
1077
+ * import cors from 'cors';
1078
+ * import { fromNodeMiddleware } from 'routup/node';
1079
+ *
1080
+ * router.use(fromNodeMiddleware(cors()));
1081
+ * ```
1082
+ */
1083
+ function fromNodeMiddleware(handler) {
1084
+ return createNodeBridge(handler, true);
1085
+ }
1086
+ //#endregion
1087
+ //#region src/handler/adapters/web/is.ts
1088
+ function isWebHandlerProvider(input) {
1089
+ return isObject(input) && typeof input.fetch === "function";
1090
+ }
1091
+ function isWebHandler(input) {
1092
+ return typeof input === "function";
1093
+ }
1094
+ //#endregion
1095
+ //#region src/handler/adapters/web/define.ts
1096
+ function fromWebHandler(input) {
1097
+ if (isWebHandlerProvider(input)) return fromWebHandler(input.fetch.bind(input));
1098
+ if (typeof input !== "function") throw new RoutupError("fromWebHandler expects a function or an object with a fetch method.");
1099
+ return defineCoreHandler({ fn: (event) => input(event.request) });
1100
+ }
1101
+ //#endregion
1102
+ //#region src/handler/is.ts
1103
+ function isHandlerOptions(input) {
1104
+ return isObject(input) && typeof input.fn === "function" && typeof input.type === "string";
1105
+ }
1106
+ function isHandler(input) {
1107
+ return isInstance(input, HandlerSymbol);
1108
+ }
1109
+ //#endregion
1110
+ //#region src/request/helpers/body.ts
1111
+ const BODY_KEY = /* @__PURE__ */ Symbol.for("routup:body");
1112
+ /**
1113
+ * Read and parse the request body.
1114
+ *
1115
+ * - `application/x-www-form-urlencoded` → plain object (duplicate keys become arrays)
1116
+ * - `application/json` or other → attempts JSON parse, returns undefined on failure
1117
+ *
1118
+ * The result is cached on the event store — calling `readBody()` multiple
1119
+ * times returns the same parsed result.
1120
+ *
1121
+ * For binary or streaming access, use `event.request.arrayBuffer()`,
1122
+ * `event.request.blob()`, or `event.request.body` directly.
1123
+ *
1124
+ * @experimental
1125
+ */
1126
+ async function readBody(event) {
1127
+ if (BODY_KEY in event.store) return event.store[BODY_KEY];
1128
+ const text = await event.request.text();
1129
+ let result;
1130
+ if ((event.headers.get("content-type") || "").includes("application/x-www-form-urlencoded")) result = parseURLEncodedBody(text);
1131
+ else try {
1132
+ result = JSON.parse(text);
1133
+ } catch {
1134
+ result = void 0;
1135
+ }
1136
+ event.store[BODY_KEY] = result;
1137
+ return result;
1138
+ }
1139
+ function parseURLEncodedBody(body) {
1140
+ const form = new URLSearchParams(body);
1141
+ const parsed = Object.create(null);
1142
+ for (const [key, value] of form.entries()) {
1143
+ const existing = parsed[key];
1144
+ if (existing !== void 0) if (Array.isArray(existing)) existing.push(value);
1145
+ else parsed[key] = [existing, value];
1146
+ else parsed[key] = value;
1147
+ }
1148
+ return parsed;
1149
+ }
1150
+ //#endregion
1151
+ //#region src/request/helpers/cache.ts
1152
+ function isRequestCacheable(event, modifiedTime) {
1153
+ const modifiedSince = event.headers.get(HeaderName.IF_MODIFIED_SINCE);
1154
+ if (!modifiedSince) return false;
1155
+ modifiedTime = typeof modifiedTime === "string" ? new Date(modifiedTime) : modifiedTime;
1156
+ const sinceDate = new Date(modifiedSince);
1157
+ if (Number.isNaN(sinceDate.getTime()) || Number.isNaN(modifiedTime.getTime())) return false;
1158
+ return sinceDate >= modifiedTime;
1159
+ }
1160
+ //#endregion
1161
+ //#region src/request/helpers/header-accept-charset.ts
1162
+ function getRequestAcceptableCharsets(event) {
1163
+ return useRequestNegotiator(event).charsets();
1164
+ }
1165
+ function getRequestAcceptableCharset(event, input) {
1166
+ input = input || [];
1167
+ const items = Array.isArray(input) ? input : [input];
1168
+ if (items.length === 0) return getRequestAcceptableCharsets(event).shift();
1169
+ return useRequestNegotiator(event).charsets(items).shift() || void 0;
1170
+ }
1171
+ //#endregion
1172
+ //#region src/request/helpers/header-accept-encoding.ts
1173
+ function getRequestAcceptableEncodings(event) {
1174
+ return useRequestNegotiator(event).encodings();
1175
+ }
1176
+ function getRequestAcceptableEncoding(event, input) {
1177
+ input = input || [];
1178
+ const items = Array.isArray(input) ? input : [input];
1179
+ if (items.length === 0) return getRequestAcceptableEncodings(event).shift();
1180
+ return useRequestNegotiator(event).encodings(items).shift() || void 0;
1181
+ }
1182
+ //#endregion
1183
+ //#region src/request/helpers/header-accept-language.ts
1184
+ function getRequestAcceptableLanguages(event) {
1185
+ return useRequestNegotiator(event).languages();
1186
+ }
1187
+ function getRequestAcceptableLanguage(event, input) {
1188
+ input = input || [];
1189
+ const items = Array.isArray(input) ? input : [input];
1190
+ if (items.length === 0) return getRequestAcceptableLanguages(event).shift();
1191
+ return useRequestNegotiator(event).languages(items).shift() || void 0;
1192
+ }
1193
+ //#endregion
1194
+ //#region src/request/helpers/header-content-type.ts
1195
+ function matchRequestContentType(event, contentType) {
1196
+ const header = getRequestHeader(event, HeaderName.CONTENT_TYPE);
1197
+ if (!header) return true;
1198
+ return header.split(";")[0].trim() === getMimeType(contentType);
1199
+ }
1200
+ //#endregion
1201
+ //#region src/request/helpers/hostname.ts
1202
+ function getRequestHostName(event, options = {}) {
1203
+ let trustProxy;
1204
+ if (typeof options.trustProxy !== "undefined") trustProxy = buildTrustProxyFn(options.trustProxy);
1205
+ else trustProxy = findRouterOption("trustProxy", event.routerPath);
1206
+ let hostname = event.headers.get(HeaderName.X_FORWARDED_HOST);
1207
+ if (!hostname || !event.request.ip || !trustProxy(event.request.ip, 0)) hostname = event.headers.get(HeaderName.HOST);
1208
+ else if (hostname && hostname.includes(",")) hostname = hostname.substring(0, hostname.indexOf(",")).trimEnd();
1209
+ if (!hostname) return;
1210
+ const offset = hostname[0] === "[" ? hostname.indexOf("]") + 1 : 0;
1211
+ const index = hostname.indexOf(":", offset);
1212
+ const result = index !== -1 ? hostname.substring(0, index) : hostname;
1213
+ if (/[\x00-\x1F\x7F\s/@\\]/.test(result)) return;
1214
+ return result;
1215
+ }
1216
+ //#endregion
1217
+ //#region src/request/helpers/ip.ts
1218
+ function getRequestIP(event, options = {}) {
1219
+ if (options.trustProxy) {
1220
+ const forwarded = event.headers.get(HeaderName.X_FORWARDED_FOR);
1221
+ if (forwarded) {
1222
+ const first = forwarded.split(",")[0];
1223
+ if (first) return first.trim();
1224
+ }
1225
+ }
1226
+ const request = event.request;
1227
+ if (request.ip) return request.ip;
1228
+ }
1229
+ //#endregion
1230
+ //#region src/request/helpers/protocol.ts
1231
+ function getRequestProtocol(event, options = {}) {
1232
+ let trustProxy;
1233
+ if (typeof options.trustProxy !== "undefined") trustProxy = buildTrustProxyFn(options.trustProxy);
1234
+ else trustProxy = findRouterOption("trustProxy", event.routerPath);
1235
+ let protocol;
1236
+ try {
1237
+ if (new URL(event.request.url).protocol === "https:") protocol = "https";
1238
+ else protocol = "http";
1239
+ } catch {
1240
+ protocol = options.default || "http";
1241
+ }
1242
+ if (!event.request.ip || !trustProxy(event.request.ip, 0)) return protocol;
1243
+ const header = event.headers.get(HeaderName.X_FORWARDED_PROTO);
1244
+ if (!header) return protocol;
1245
+ const index = header.indexOf(",");
1246
+ const forwarded = index !== -1 ? header.substring(0, index).trim().toLowerCase() : header.trim().toLowerCase();
1247
+ if (forwarded === "http" || forwarded === "https") return forwarded;
1248
+ return protocol;
1249
+ }
1250
+ //#endregion
1251
+ //#region src/plugin/is.ts
1252
+ function isPlugin(input) {
1253
+ if (!isObject(input)) return false;
1254
+ if (typeof input.name !== "undefined" && typeof input.name !== "string") return false;
1255
+ return typeof input.install === "function" && input.install.length === 1;
1256
+ }
1257
+ //#endregion
1258
+ //#region src/router-options/normalize.ts
1259
+ function normalizeRouterOptions(input) {
1260
+ if (typeof input.etag !== "undefined") input.etag = buildEtagFn(input.etag);
1261
+ if (typeof input.trustProxy !== "undefined") input.trustProxy = buildTrustProxyFn(input.trustProxy);
1262
+ return input;
1263
+ }
1264
+ //#endregion
1265
+ //#region src/router/constants.ts
1266
+ const RouterSymbol = /* @__PURE__ */ Symbol.for("Router");
1267
+ let RouterPipelineStep = /* @__PURE__ */ function(RouterPipelineStep) {
1268
+ RouterPipelineStep[RouterPipelineStep["START"] = 0] = "START";
1269
+ RouterPipelineStep[RouterPipelineStep["LOOKUP"] = 1] = "LOOKUP";
1270
+ RouterPipelineStep[RouterPipelineStep["CHILD_BEFORE"] = 2] = "CHILD_BEFORE";
1271
+ RouterPipelineStep[RouterPipelineStep["CHILD_DISPATCH"] = 3] = "CHILD_DISPATCH";
1272
+ RouterPipelineStep[RouterPipelineStep["CHILD_AFTER"] = 4] = "CHILD_AFTER";
1273
+ RouterPipelineStep[RouterPipelineStep["FINISH"] = 5] = "FINISH";
1274
+ return RouterPipelineStep;
1275
+ }({});
1276
+ //#endregion
1277
+ //#region src/router/utils.ts
1278
+ let nextId = 0;
1279
+ function generateRouterID() {
1280
+ return ++nextId;
1281
+ }
1282
+ function isRouterInstance(input) {
1283
+ return isInstance(input, RouterSymbol);
1284
+ }
1285
+ /**
1286
+ * Check if the request accepts JSON responses.
1287
+ * Matches application/json and +json suffixes (e.g. application/vnd.api+json).
1288
+ * Returns true if no Accept header is present (API-first default).
1289
+ */
1290
+ function acceptsJson(request) {
1291
+ const accept = request.headers.get("accept");
1292
+ if (!accept) return true;
1293
+ return accept.includes("application/json") || accept.includes("+json") || accept.includes("*/*");
1294
+ }
1295
+ //#endregion
1296
+ //#region src/router/module.ts
1297
+ var Router = class Router {
1298
+ "@instanceof" = RouterSymbol;
1299
+ /**
1300
+ * An identifier for the router instance.
1301
+ */
1302
+ id;
1303
+ /**
1304
+ * A label for the router instance.
1305
+ */
1306
+ name;
1307
+ /**
1308
+ * Array of mounted layers, routes & routers.
1309
+ *
1310
+ * @protected
1311
+ */
1312
+ stack = [];
1313
+ /**
1314
+ * Path matcher for the current mount path.
1315
+ *
1316
+ * @protected
1317
+ */
1318
+ pathMatcher;
1319
+ /**
1320
+ * A hook manager.
1321
+ *
1322
+ * @protected
1323
+ */
1324
+ hookManager;
1325
+ constructor(options = {}) {
1326
+ this.id = generateRouterID();
1327
+ this.name = options.name;
1328
+ this.hookManager = new HookManager();
1329
+ this.setPath(options.path);
1330
+ setRouterOptions(this.id, normalizeRouterOptions(options));
1331
+ }
1332
+ matchPath(path) {
1333
+ if (this.pathMatcher) return this.pathMatcher.test(path);
1334
+ return true;
1335
+ }
1336
+ setPath(value) {
1337
+ if (value === "/" || typeof value === "undefined") {
1338
+ this.pathMatcher = void 0;
1339
+ return;
1340
+ }
1341
+ this.pathMatcher = new PathMatcher(withLeadingSlash(withoutTrailingSlash(`${value}`)), { end: false });
1342
+ }
1343
+ /**
1344
+ * Public entry point — creates a RoutupEvent from the request,
1345
+ * runs the pipeline, and returns a Response (with 404/500 fallbacks).
1346
+ */
1347
+ async fetch(request) {
1348
+ const event = new RoutupEvent(request);
1349
+ let response;
1350
+ try {
1351
+ response = await this.dispatch(event);
1352
+ } catch (e) {
1353
+ event.error = createError(e);
1354
+ }
1355
+ if (response) return response;
1356
+ if (event.error) {
1357
+ const status = event.error.statusCode || 500;
1358
+ const message = event.error.statusMessage || "Internal Server Error";
1359
+ return this.buildFallbackResponse(request, event, status, message);
1360
+ }
1361
+ return this.buildFallbackResponse(request, event, 404, "Not Found");
1362
+ }
1363
+ buildFallbackResponse(request, event, status, message) {
1364
+ const headers = new Headers(event.response.headers);
1365
+ if (acceptsJson(request)) {
1366
+ headers.set("content-type", "application/json; charset=utf-8");
1367
+ return new Response(JSON.stringify({
1368
+ status,
1369
+ message
1370
+ }), {
1371
+ status,
1372
+ statusText: message,
1373
+ headers
1374
+ });
1375
+ }
1376
+ headers.set("content-type", "text/plain; charset=utf-8");
1377
+ return new Response(message, {
1378
+ status,
1379
+ statusText: message,
1380
+ headers
1381
+ });
1382
+ }
1383
+ async executePipelineStep(context) {
1384
+ switch (context.step) {
1385
+ case RouterPipelineStep.START: return this.executePipelineStepStart(context);
1386
+ case RouterPipelineStep.LOOKUP: return this.executePipelineStepLookup(context);
1387
+ case RouterPipelineStep.CHILD_BEFORE: return this.executePipelineStepChildBefore(context);
1388
+ case RouterPipelineStep.CHILD_DISPATCH: return this.executePipelineStepChildDispatch(context);
1389
+ case RouterPipelineStep.CHILD_AFTER: return this.executePipelineStepChildAfter(context);
1390
+ case RouterPipelineStep.FINISH:
1391
+ default: return this.executePipelineStepFinish(context);
1392
+ }
1393
+ }
1394
+ async executePipelineStepStart(context) {
1395
+ await this.hookManager.trigger(HookName.REQUEST, context.event);
1396
+ if (context.event.dispatched) context.step = RouterPipelineStep.FINISH;
1397
+ else context.step = RouterPipelineStep.LOOKUP;
1398
+ return this.executePipelineStep(context);
1399
+ }
1400
+ async executePipelineStepLookup(context) {
1401
+ while (!context.event.dispatched && context.stackIndex < this.stack.length) {
1402
+ const item = this.stack[context.stackIndex];
1403
+ if (isHandler(item)) {
1404
+ if (context.event.error && item.type === HandlerType.CORE || !context.event.error && item.type === HandlerType.ERROR) {
1405
+ context.stackIndex++;
1406
+ continue;
1407
+ }
1408
+ if (item.matchPath(context.event.path)) {
1409
+ if (item.method) context.event.methodsAllowed.push(item.method);
1410
+ if (item.matchMethod(context.event.method)) {
1411
+ await this.hookManager.trigger(HookName.CHILD_MATCH, context.event);
1412
+ if (context.event.dispatched) context.step = RouterPipelineStep.FINISH;
1413
+ else context.step = RouterPipelineStep.CHILD_BEFORE;
1414
+ return this.executePipelineStep(context);
1415
+ }
1416
+ }
1417
+ context.stackIndex++;
1418
+ continue;
1419
+ }
1420
+ if (item.matchPath(context.event.path)) {
1421
+ await this.hookManager.trigger(HookName.CHILD_MATCH, context.event);
1422
+ if (context.event.dispatched) context.step = RouterPipelineStep.FINISH;
1423
+ else context.step = RouterPipelineStep.CHILD_BEFORE;
1424
+ return this.executePipelineStep(context);
1425
+ }
1426
+ context.stackIndex++;
1427
+ }
1428
+ context.step = RouterPipelineStep.FINISH;
1429
+ return this.executePipelineStep(context);
1430
+ }
1431
+ async executePipelineStepChildBefore(context) {
1432
+ await this.hookManager.trigger(HookName.CHILD_DISPATCH_BEFORE, context.event);
1433
+ if (context.event.dispatched) context.step = RouterPipelineStep.FINISH;
1434
+ else context.step = RouterPipelineStep.CHILD_DISPATCH;
1435
+ return this.executePipelineStep(context);
1436
+ }
1437
+ async executePipelineStepChildAfter(context) {
1438
+ await this.hookManager.trigger(HookName.CHILD_DISPATCH_AFTER, context.event);
1439
+ if (context.event.dispatched) context.step = RouterPipelineStep.FINISH;
1440
+ else context.step = RouterPipelineStep.LOOKUP;
1441
+ return this.executePipelineStep(context);
1442
+ }
1443
+ async executePipelineStepChildDispatch(context) {
1444
+ if (context.event.dispatched || typeof this.stack[context.stackIndex] === "undefined") {
1445
+ context.step = RouterPipelineStep.FINISH;
1446
+ return this.executePipelineStep(context);
1447
+ }
1448
+ const item = this.stack[context.stackIndex];
1449
+ const { event } = context;
1450
+ const savedNext = event._next;
1451
+ const savedNextCalled = event._nextCalled;
1452
+ try {
1453
+ event._nextCalled = false;
1454
+ event._next = async () => {
1455
+ const nextContext = {
1456
+ step: RouterPipelineStep.LOOKUP,
1457
+ event,
1458
+ stackIndex: context.stackIndex + 1,
1459
+ response: void 0
1460
+ };
1461
+ event.routerPath.push(this.id);
1462
+ try {
1463
+ await this.executePipelineStep(nextContext);
1464
+ } finally {
1465
+ event.routerPath.pop();
1466
+ }
1467
+ return nextContext.response;
1468
+ };
1469
+ const response = await item.dispatch(event);
1470
+ if (response) {
1471
+ context.response = response;
1472
+ event.dispatched = true;
1473
+ }
1474
+ } catch (e) {
1475
+ event.error = createError(e);
1476
+ await this.hookManager.trigger(HookName.ERROR, event);
1477
+ } finally {
1478
+ event._next = savedNext;
1479
+ event._nextCalled = savedNextCalled;
1480
+ }
1481
+ context.stackIndex++;
1482
+ context.step = RouterPipelineStep.CHILD_AFTER;
1483
+ return this.executePipelineStep(context);
1484
+ }
1485
+ async executePipelineStepFinish(context) {
1486
+ if (context.event.error || context.event.dispatched) return this.hookManager.trigger(HookName.RESPONSE, context.event);
1487
+ if (!context.event.dispatched && context.event.routerPath.length === 1 && context.event.method && context.event.method === MethodName.OPTIONS) {
1488
+ if (context.event.methodsAllowed.includes(MethodName.GET)) context.event.methodsAllowed.push(MethodName.HEAD);
1489
+ (0, smob.distinctArray)(context.event.methodsAllowed);
1490
+ const options = context.event.methodsAllowed.map((key) => key.toUpperCase()).join(",");
1491
+ const optionsHeaders = new Headers(context.event.response.headers);
1492
+ optionsHeaders.set(HeaderName.ALLOW, options);
1493
+ context.response = new Response(options, {
1494
+ status: context.event.response.status || 200,
1495
+ statusText: context.event.response.statusText,
1496
+ headers: optionsHeaders
1497
+ });
1498
+ context.event.dispatched = true;
1499
+ }
1500
+ return this.hookManager.trigger(HookName.RESPONSE, context.event);
1501
+ }
1502
+ async dispatch(event) {
1503
+ if (this.pathMatcher) {
1504
+ const output = this.pathMatcher.exec(event.path);
1505
+ if (typeof output !== "undefined") {
1506
+ event.mountPath = cleanDoubleSlashes(`${event.mountPath}/${output.path}`);
1507
+ if (event.path === output.path) event.path = "/";
1508
+ else event.path = withLeadingSlash(event.path.substring(output.path.length));
1509
+ event.params = {
1510
+ ...event.params,
1511
+ ...output.params
1512
+ };
1513
+ }
1514
+ }
1515
+ const context = {
1516
+ step: RouterPipelineStep.START,
1517
+ event,
1518
+ stackIndex: 0
1519
+ };
1520
+ event.routerPath.push(this.id);
1521
+ try {
1522
+ await this.executePipelineStep(context);
1523
+ } finally {
1524
+ event.routerPath.pop();
1525
+ }
1526
+ return context.response;
1527
+ }
1528
+ delete(...input) {
1529
+ this.useForMethod(MethodName.DELETE, ...input);
1530
+ return this;
1531
+ }
1532
+ get(...input) {
1533
+ this.useForMethod(MethodName.GET, ...input);
1534
+ return this;
1535
+ }
1536
+ post(...input) {
1537
+ this.useForMethod(MethodName.POST, ...input);
1538
+ return this;
1539
+ }
1540
+ put(...input) {
1541
+ this.useForMethod(MethodName.PUT, ...input);
1542
+ return this;
1543
+ }
1544
+ patch(...input) {
1545
+ this.useForMethod(MethodName.PATCH, ...input);
1546
+ return this;
1547
+ }
1548
+ head(...input) {
1549
+ this.useForMethod(MethodName.HEAD, ...input);
1550
+ return this;
1551
+ }
1552
+ options(...input) {
1553
+ this.useForMethod(MethodName.OPTIONS, ...input);
1554
+ return this;
1555
+ }
1556
+ useForMethod(method, ...input) {
1557
+ let path;
1558
+ for (const element of input) {
1559
+ if (isPath(element)) {
1560
+ path = element;
1561
+ continue;
1562
+ }
1563
+ if (isHandlerOptions(element)) {
1564
+ if (path) element.path = path;
1565
+ element.method = method;
1566
+ this.use(element);
1567
+ continue;
1568
+ }
1569
+ if (isHandler(element)) {
1570
+ if (path) element.setPath(path);
1571
+ element.setMethod(method);
1572
+ this.use(element);
1573
+ }
1574
+ }
1575
+ }
1576
+ use(...input) {
1577
+ let path;
1578
+ for (const item of input) {
1579
+ if (isPath(item)) {
1580
+ path = withLeadingSlash(item);
1581
+ continue;
1582
+ }
1583
+ if (isRouterInstance(item)) {
1584
+ if (path) item.setPath(path);
1585
+ this.stack.push(item);
1586
+ continue;
1587
+ }
1588
+ if (isHandlerOptions(item)) {
1589
+ item.path = path || item.path;
1590
+ this.stack.push(new Handler(item));
1591
+ continue;
1592
+ }
1593
+ if (isHandler(item)) {
1594
+ item.setPath(path || item.path);
1595
+ this.stack.push(item);
1596
+ continue;
1597
+ }
1598
+ if (isPlugin(item)) if (path) this.install(item, { path });
1599
+ else this.install(item);
1600
+ }
1601
+ return this;
1602
+ }
1603
+ install(plugin, context = {}) {
1604
+ const router = new Router({ name: context.name || plugin.name });
1605
+ plugin.install(router);
1606
+ if (context.path) this.use(context.path, router);
1607
+ else this.use(router);
1608
+ return this;
1609
+ }
1610
+ on(name, fn) {
1611
+ return this.hookManager.addListener(name, fn);
1612
+ }
1613
+ off(name, fn) {
1614
+ if (typeof fn === "undefined") {
1615
+ this.hookManager.removeListener(name);
1616
+ return this;
1617
+ }
1618
+ this.hookManager.removeListener(name, fn);
1619
+ return this;
1620
+ }
1621
+ };
1622
+ //#endregion
1623
+ Object.defineProperty(exports, "Handler", {
1624
+ enumerable: true,
1625
+ get: function() {
1626
+ return Handler;
1627
+ }
1628
+ });
1629
+ Object.defineProperty(exports, "HandlerSymbol", {
1630
+ enumerable: true,
1631
+ get: function() {
1632
+ return HandlerSymbol;
1633
+ }
1634
+ });
1635
+ Object.defineProperty(exports, "HandlerType", {
1636
+ enumerable: true,
1637
+ get: function() {
1638
+ return HandlerType;
1639
+ }
1640
+ });
1641
+ Object.defineProperty(exports, "HeaderName", {
1642
+ enumerable: true,
1643
+ get: function() {
1644
+ return HeaderName;
1645
+ }
1646
+ });
1647
+ Object.defineProperty(exports, "MethodName", {
1648
+ enumerable: true,
1649
+ get: function() {
1650
+ return MethodName;
1651
+ }
1652
+ });
1653
+ Object.defineProperty(exports, "PathMatcher", {
1654
+ enumerable: true,
1655
+ get: function() {
1656
+ return PathMatcher;
1657
+ }
1658
+ });
1659
+ Object.defineProperty(exports, "Router", {
1660
+ enumerable: true,
1661
+ get: function() {
1662
+ return Router;
1663
+ }
1664
+ });
1665
+ Object.defineProperty(exports, "RoutupError", {
1666
+ enumerable: true,
1667
+ get: function() {
1668
+ return RoutupError;
1669
+ }
1670
+ });
1671
+ Object.defineProperty(exports, "RoutupEvent", {
1672
+ enumerable: true,
1673
+ get: function() {
1674
+ return RoutupEvent;
1675
+ }
1676
+ });
1677
+ Object.defineProperty(exports, "__toESM", {
1678
+ enumerable: true,
1679
+ get: function() {
1680
+ return __toESM;
1681
+ }
1682
+ });
1683
+ Object.defineProperty(exports, "appendResponseHeader", {
1684
+ enumerable: true,
1685
+ get: function() {
1686
+ return appendResponseHeader;
1687
+ }
1688
+ });
1689
+ Object.defineProperty(exports, "appendResponseHeaderDirective", {
1690
+ enumerable: true,
1691
+ get: function() {
1692
+ return appendResponseHeaderDirective;
1693
+ }
1694
+ });
1695
+ Object.defineProperty(exports, "createError", {
1696
+ enumerable: true,
1697
+ get: function() {
1698
+ return createError;
1699
+ }
1700
+ });
1701
+ Object.defineProperty(exports, "createEventStream", {
1702
+ enumerable: true,
1703
+ get: function() {
1704
+ return createEventStream;
1705
+ }
1706
+ });
1707
+ Object.defineProperty(exports, "defineCoreHandler", {
1708
+ enumerable: true,
1709
+ get: function() {
1710
+ return defineCoreHandler;
1711
+ }
1712
+ });
1713
+ Object.defineProperty(exports, "defineErrorHandler", {
1714
+ enumerable: true,
1715
+ get: function() {
1716
+ return defineErrorHandler;
1717
+ }
1718
+ });
1719
+ Object.defineProperty(exports, "fromNodeHandler", {
1720
+ enumerable: true,
1721
+ get: function() {
1722
+ return fromNodeHandler;
1723
+ }
1724
+ });
1725
+ Object.defineProperty(exports, "fromNodeMiddleware", {
1726
+ enumerable: true,
1727
+ get: function() {
1728
+ return fromNodeMiddleware;
1729
+ }
1730
+ });
1731
+ Object.defineProperty(exports, "fromWebHandler", {
1732
+ enumerable: true,
1733
+ get: function() {
1734
+ return fromWebHandler;
1735
+ }
1736
+ });
1737
+ Object.defineProperty(exports, "getRequestAcceptableCharset", {
1738
+ enumerable: true,
1739
+ get: function() {
1740
+ return getRequestAcceptableCharset;
1741
+ }
1742
+ });
1743
+ Object.defineProperty(exports, "getRequestAcceptableCharsets", {
1744
+ enumerable: true,
1745
+ get: function() {
1746
+ return getRequestAcceptableCharsets;
1747
+ }
1748
+ });
1749
+ Object.defineProperty(exports, "getRequestAcceptableContentType", {
1750
+ enumerable: true,
1751
+ get: function() {
1752
+ return getRequestAcceptableContentType;
1753
+ }
1754
+ });
1755
+ Object.defineProperty(exports, "getRequestAcceptableContentTypes", {
1756
+ enumerable: true,
1757
+ get: function() {
1758
+ return getRequestAcceptableContentTypes;
1759
+ }
1760
+ });
1761
+ Object.defineProperty(exports, "getRequestAcceptableEncoding", {
1762
+ enumerable: true,
1763
+ get: function() {
1764
+ return getRequestAcceptableEncoding;
1765
+ }
1766
+ });
1767
+ Object.defineProperty(exports, "getRequestAcceptableEncodings", {
1768
+ enumerable: true,
1769
+ get: function() {
1770
+ return getRequestAcceptableEncodings;
1771
+ }
1772
+ });
1773
+ Object.defineProperty(exports, "getRequestAcceptableLanguage", {
1774
+ enumerable: true,
1775
+ get: function() {
1776
+ return getRequestAcceptableLanguage;
1777
+ }
1778
+ });
1779
+ Object.defineProperty(exports, "getRequestAcceptableLanguages", {
1780
+ enumerable: true,
1781
+ get: function() {
1782
+ return getRequestAcceptableLanguages;
1783
+ }
1784
+ });
1785
+ Object.defineProperty(exports, "getRequestHeader", {
1786
+ enumerable: true,
1787
+ get: function() {
1788
+ return getRequestHeader;
1789
+ }
1790
+ });
1791
+ Object.defineProperty(exports, "getRequestHostName", {
1792
+ enumerable: true,
1793
+ get: function() {
1794
+ return getRequestHostName;
1795
+ }
1796
+ });
1797
+ Object.defineProperty(exports, "getRequestIP", {
1798
+ enumerable: true,
1799
+ get: function() {
1800
+ return getRequestIP;
1801
+ }
1802
+ });
1803
+ Object.defineProperty(exports, "getRequestProtocol", {
1804
+ enumerable: true,
1805
+ get: function() {
1806
+ return getRequestProtocol;
1807
+ }
1808
+ });
1809
+ Object.defineProperty(exports, "isError", {
1810
+ enumerable: true,
1811
+ get: function() {
1812
+ return isError;
1813
+ }
1814
+ });
1815
+ Object.defineProperty(exports, "isHandler", {
1816
+ enumerable: true,
1817
+ get: function() {
1818
+ return isHandler;
1819
+ }
1820
+ });
1821
+ Object.defineProperty(exports, "isHandlerOptions", {
1822
+ enumerable: true,
1823
+ get: function() {
1824
+ return isHandlerOptions;
1825
+ }
1826
+ });
1827
+ Object.defineProperty(exports, "isPath", {
1828
+ enumerable: true,
1829
+ get: function() {
1830
+ return isPath;
1831
+ }
1832
+ });
1833
+ Object.defineProperty(exports, "isPlugin", {
1834
+ enumerable: true,
1835
+ get: function() {
1836
+ return isPlugin;
1837
+ }
1838
+ });
1839
+ Object.defineProperty(exports, "isRequestCacheable", {
1840
+ enumerable: true,
1841
+ get: function() {
1842
+ return isRequestCacheable;
1843
+ }
1844
+ });
1845
+ Object.defineProperty(exports, "isResponseGone", {
1846
+ enumerable: true,
1847
+ get: function() {
1848
+ return isResponseGone;
1849
+ }
1850
+ });
1851
+ Object.defineProperty(exports, "isWebHandler", {
1852
+ enumerable: true,
1853
+ get: function() {
1854
+ return isWebHandler;
1855
+ }
1856
+ });
1857
+ Object.defineProperty(exports, "isWebHandlerProvider", {
1858
+ enumerable: true,
1859
+ get: function() {
1860
+ return isWebHandlerProvider;
1861
+ }
1862
+ });
1863
+ Object.defineProperty(exports, "matchRequestContentType", {
1864
+ enumerable: true,
1865
+ get: function() {
1866
+ return matchRequestContentType;
1867
+ }
1868
+ });
1869
+ Object.defineProperty(exports, "readBody", {
1870
+ enumerable: true,
1871
+ get: function() {
1872
+ return readBody;
1873
+ }
1874
+ });
1875
+ Object.defineProperty(exports, "sendAccepted", {
1876
+ enumerable: true,
1877
+ get: function() {
1878
+ return sendAccepted;
1879
+ }
1880
+ });
1881
+ Object.defineProperty(exports, "sendCreated", {
1882
+ enumerable: true,
1883
+ get: function() {
1884
+ return sendCreated;
1885
+ }
1886
+ });
1887
+ Object.defineProperty(exports, "sendFile", {
1888
+ enumerable: true,
1889
+ get: function() {
1890
+ return sendFile;
1891
+ }
1892
+ });
1893
+ Object.defineProperty(exports, "sendFormat", {
1894
+ enumerable: true,
1895
+ get: function() {
1896
+ return sendFormat;
1897
+ }
1898
+ });
1899
+ Object.defineProperty(exports, "sendRedirect", {
1900
+ enumerable: true,
1901
+ get: function() {
1902
+ return sendRedirect;
1903
+ }
1904
+ });
1905
+ Object.defineProperty(exports, "sendStream", {
1906
+ enumerable: true,
1907
+ get: function() {
1908
+ return sendStream;
1909
+ }
1910
+ });
1911
+ Object.defineProperty(exports, "serializeEventStreamMessage", {
1912
+ enumerable: true,
1913
+ get: function() {
1914
+ return serializeEventStreamMessage;
1915
+ }
1916
+ });
1917
+ Object.defineProperty(exports, "setResponseCacheHeaders", {
1918
+ enumerable: true,
1919
+ get: function() {
1920
+ return setResponseCacheHeaders;
1921
+ }
1922
+ });
1923
+ Object.defineProperty(exports, "setResponseContentTypeByFileName", {
1924
+ enumerable: true,
1925
+ get: function() {
1926
+ return setResponseContentTypeByFileName;
1927
+ }
1928
+ });
1929
+ Object.defineProperty(exports, "setResponseGone", {
1930
+ enumerable: true,
1931
+ get: function() {
1932
+ return setResponseGone;
1933
+ }
1934
+ });
1935
+ Object.defineProperty(exports, "setResponseHeaderAttachment", {
1936
+ enumerable: true,
1937
+ get: function() {
1938
+ return setResponseHeaderAttachment;
1939
+ }
1940
+ });
1941
+ Object.defineProperty(exports, "setResponseHeaderContentType", {
1942
+ enumerable: true,
1943
+ get: function() {
1944
+ return setResponseHeaderContentType;
1945
+ }
1946
+ });
1947
+ Object.defineProperty(exports, "toResponse", {
1948
+ enumerable: true,
1949
+ get: function() {
1950
+ return toResponse;
1951
+ }
1952
+ });
1953
+ Object.defineProperty(exports, "useRequestNegotiator", {
1954
+ enumerable: true,
1955
+ get: function() {
1956
+ return useRequestNegotiator;
1957
+ }
1958
+ });
1959
+
1960
+ //# sourceMappingURL=src-D_4IPMmD.cjs.map