routup 4.0.2 → 5.0.0-beta.0

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 +87 -134
  2. package/dist/bun.cjs +66 -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 +66 -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 +66 -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 +66 -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-9K5FcIb3.d.cts +786 -0
  27. package/dist/index-B6F5CzQy.d.mts +786 -0
  28. package/dist/node.cjs +70 -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 +66 -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-C789deGE.mjs +1599 -0
  41. package/dist/src-C789deGE.mjs.map +1 -0
  42. package/dist/src-Ca2_b8P0.cjs +1939 -0
  43. package/dist/src-Ca2_b8P0.cjs.map +1 -0
  44. package/package.json +76 -36
  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
package/dist/index.mjs DELETED
@@ -1,2235 +0,0 @@
1
- import { merge, hasOwnProperty, distinctArray } from 'smob';
2
- import { Buffer } from 'buffer';
3
- import { subtle } from 'uncrypto';
4
- import { compile, all } from 'proxy-addr';
5
- import { getType, get } from 'mime-explorer';
6
- import Negotiator from 'negotiator';
7
- import { Readable, PassThrough, Writable } from 'readable-stream';
8
- import { HTTPError } from '@ebec/http';
9
- import { pathToRegexp } from 'path-to-regexp';
10
-
11
- var MethodName = /*#__PURE__*/ function(MethodName) {
12
- MethodName["GET"] = "GET";
13
- MethodName["POST"] = "POST";
14
- MethodName["PUT"] = "PUT";
15
- MethodName["PATCH"] = "PATCH";
16
- MethodName["DELETE"] = "DELETE";
17
- MethodName["OPTIONS"] = "OPTIONS";
18
- MethodName["HEAD"] = "HEAD";
19
- return MethodName;
20
- }({});
21
- var HeaderName = /*#__PURE__*/ function(HeaderName) {
22
- HeaderName["ACCEPT"] = "accept";
23
- HeaderName["ACCEPT_CHARSET"] = "accept-charset";
24
- HeaderName["ACCEPT_ENCODING"] = "accept-encoding";
25
- HeaderName["ACCEPT_LANGUAGE"] = "accept-language";
26
- HeaderName["ACCEPT_RANGES"] = "accept-ranges";
27
- HeaderName["ALLOW"] = "allow";
28
- HeaderName["CACHE_CONTROL"] = "cache-control";
29
- HeaderName["CONTENT_DISPOSITION"] = "content-disposition";
30
- HeaderName["CONTENT_ENCODING"] = "content-encoding";
31
- HeaderName["CONTENT_LENGTH"] = "content-length";
32
- HeaderName["CONTENT_RANGE"] = "content-range";
33
- HeaderName["CONTENT_TYPE"] = "content-type";
34
- HeaderName["CONNECTION"] = "connection";
35
- HeaderName["COOKIE"] = "cookie";
36
- HeaderName["ETag"] = "etag";
37
- HeaderName["HOST"] = "host";
38
- HeaderName["IF_MODIFIED_SINCE"] = "if-modified-since";
39
- HeaderName["IF_NONE_MATCH"] = "if-none-match";
40
- HeaderName["LAST_MODIFIED"] = "last-modified";
41
- HeaderName["LOCATION"] = "location";
42
- HeaderName["RANGE"] = "range";
43
- HeaderName["RATE_LIMIT_LIMIT"] = "ratelimit-limit";
44
- HeaderName["RATE_LIMIT_REMAINING"] = "ratelimit-remaining";
45
- HeaderName["RATE_LIMIT_RESET"] = "ratelimit-reset";
46
- HeaderName["RETRY_AFTER"] = "retry-after";
47
- HeaderName["SET_COOKIE"] = "set-cookie";
48
- HeaderName["TRANSFER_ENCODING"] = "transfer-encoding";
49
- HeaderName["X_ACCEL_BUFFERING"] = "x-accel-buffering";
50
- HeaderName["X_FORWARDED_HOST"] = "x-forwarded-host";
51
- HeaderName["X_FORWARDED_FOR"] = "x-forwarded-for";
52
- HeaderName["X_FORWARDED_PROTO"] = "x-forwarded-proto";
53
- return HeaderName;
54
- }({});
55
-
56
- function isRequestCacheable(req, modifiedTime) {
57
- const modifiedSince = req.headers[HeaderName.IF_MODIFIED_SINCE];
58
- if (!modifiedSince) {
59
- return false;
60
- }
61
- modifiedTime = typeof modifiedTime === 'string' ? new Date(modifiedTime) : modifiedTime;
62
- return new Date(modifiedSince) >= modifiedTime;
63
- }
64
-
65
- /*
66
- Set-Cookie header field-values are sometimes comma joined in one string. This splits them without choking on commas
67
- that are within a single set-cookie field-value, such as in the Expires portion.
68
-
69
- This is uncommon, but explicitly allowed - see https://tools.ietf.org/html/rfc2616#section-4.2
70
- Node.js does this for every header *except* set-cookie - see https://github.com/nodejs/node/blob/d5e363b77ebaf1caf67cd7528224b651c86815c1/lib/_http_incoming.js#L128
71
- React Native's fetch does this for *every* header, including set-cookie.
72
-
73
- Based on: https://github.com/google/j2objc/commit/16820fdbc8f76ca0c33472810ce0cb03d20efe25
74
- Credits to: https://github.com/tomball for original and https://github.com/chrusart for JavaScript implementation
75
- */ function splitCookiesString(input) {
76
- if (Array.isArray(input)) {
77
- return input.flatMap((el)=>splitCookiesString(el));
78
- }
79
- if (typeof input !== 'string') {
80
- return [];
81
- }
82
- const cookiesStrings = [];
83
- let pos = 0;
84
- let start;
85
- let ch;
86
- let lastComma;
87
- let nextStart;
88
- let cookiesSeparatorFound;
89
- const skipWhitespace = ()=>{
90
- while(pos < input.length && /\s/.test(input.charAt(pos))){
91
- pos += 1;
92
- }
93
- return pos < input.length;
94
- };
95
- const notSpecialChar = ()=>{
96
- ch = input.charAt(pos);
97
- return ch !== '=' && ch !== ';' && ch !== ',';
98
- };
99
- while(pos < input.length){
100
- start = pos;
101
- cookiesSeparatorFound = false;
102
- while(skipWhitespace()){
103
- ch = input.charAt(pos);
104
- if (ch === ',') {
105
- // ',' is a cookie separator if we have later first '=', not ';' or ','
106
- lastComma = pos;
107
- pos += 1;
108
- skipWhitespace();
109
- nextStart = pos;
110
- while(pos < input.length && notSpecialChar()){
111
- pos += 1;
112
- }
113
- // currently special character
114
- if (pos < input.length && input.charAt(pos) === '=') {
115
- // we found cookies separator
116
- cookiesSeparatorFound = true;
117
- // pos is inside the next cookie, so back up and return it.
118
- pos = nextStart;
119
- cookiesStrings.push(input.substring(start, lastComma));
120
- start = pos;
121
- } else {
122
- // in param ',' or param separator ';',
123
- // we continue from that comma
124
- pos = lastComma + 1;
125
- }
126
- } else {
127
- pos += 1;
128
- }
129
- }
130
- if (!cookiesSeparatorFound || pos >= input.length) {
131
- cookiesStrings.push(input.substring(start, input.length));
132
- }
133
- }
134
- return cookiesStrings;
135
- }
136
-
137
- function isObject(item) {
138
- return !!item && typeof item === 'object' && !Array.isArray(item);
139
- }
140
- function setProperty(record, property, value) {
141
- record[property] = value;
142
- }
143
- function getProperty(req, property) {
144
- return req[property];
145
- }
146
-
147
- /**
148
- * Determine if object is a Stats object.
149
- *
150
- * @param {object} obj
151
- * @return {boolean}
152
- * @api private
153
- */ function isStatsObject(obj) {
154
- // quack quack
155
- 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';
156
- }
157
- async function sha1(str) {
158
- const enc = new TextEncoder();
159
- const hash = await subtle.digest('SHA-1', enc.encode(str));
160
- return btoa(String.fromCharCode(...new Uint8Array(hash)));
161
- }
162
- /**
163
- * Generate an ETag.
164
- */ async function generateETag(input) {
165
- if (isStatsObject(input)) {
166
- const mtime = input.mtime.getTime().toString(16);
167
- const size = input.size.toString(16);
168
- return `"${size}-${mtime}"`;
169
- }
170
- if (input.length === 0) {
171
- // fast-path empty
172
- return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
173
- }
174
- const entity = Buffer.isBuffer(input) ? input.toString('utf-8') : input;
175
- // compute hash of entity
176
- const hash = await sha1(entity);
177
- return `"${entity.length.toString(16)}-${hash.substring(0, 27)}"`;
178
- }
179
- /**
180
- * Create a simple ETag.
181
- */ async function createEtag(input, options) {
182
- options = options || {};
183
- const weak = typeof options.weak === 'boolean' ? options.weak : isStatsObject(input);
184
- // generate entity tag
185
- const tag = await generateETag(input);
186
- return weak ? `W/${tag}` : tag;
187
- }
188
-
189
- function buildEtagFn(input) {
190
- if (typeof input === 'function') {
191
- return input;
192
- }
193
- input = input ?? true;
194
- if (input === false) {
195
- return ()=>Promise.resolve(undefined);
196
- }
197
- let options = {
198
- weak: true
199
- };
200
- if (isObject(input)) {
201
- options = merge(input, options);
202
- }
203
- return async (body, encoding, size)=>{
204
- const buff = Buffer.isBuffer(body) ? body : Buffer.from(body, encoding);
205
- if (typeof options.threshold !== 'undefined') {
206
- size = size ?? Buffer.byteLength(buff);
207
- if (size <= options.threshold) {
208
- return undefined;
209
- }
210
- }
211
- return createEtag(buff, options);
212
- };
213
- }
214
-
215
- function buildTrustProxyFn(input) {
216
- if (typeof input === 'function') {
217
- return input;
218
- }
219
- if (input === true) {
220
- return ()=>true;
221
- }
222
- if (typeof input === 'number') {
223
- return (_address, hop)=>hop < input;
224
- }
225
- if (typeof input === 'string') {
226
- input = input.split(',').map((value)=>value.trim());
227
- }
228
- return compile(input || []);
229
- }
230
-
231
- function isInstance(input, sym) {
232
- if (!isObject(input)) {
233
- return false;
234
- }
235
- return input['@instanceof'] === sym;
236
- }
237
-
238
- function getMimeType(type) {
239
- if (type.indexOf('/') !== -1) {
240
- return type;
241
- }
242
- return getType(type);
243
- }
244
- function getCharsetForMimeType(type) {
245
- if (/^text\/|^application\/(javascript|json)/.test(type)) {
246
- return 'utf-8';
247
- }
248
- const meta = get(type);
249
- if (meta && meta.charset) {
250
- return meta.charset.toLowerCase();
251
- }
252
- return undefined;
253
- }
254
-
255
- function toMethodName(input, alt) {
256
- if (input) {
257
- return input.toUpperCase();
258
- }
259
- return alt;
260
- }
261
-
262
- const nextPlaceholder = (_err)=>{};
263
-
264
- /**
265
- * Based on https://github.com/unjs/pathe v1.1.1 (055f50a6f1131f4e5c56cf259dd8816168fba329)
266
- */ function normalizeWindowsPath(input = '') {
267
- if (!input || !input.includes('\\')) {
268
- return input;
269
- }
270
- return input.replace(/\\/g, '/');
271
- }
272
- const EXTNAME_RE = /.(\.[^./]+)$/;
273
- function extname(input) {
274
- const match = EXTNAME_RE.exec(normalizeWindowsPath(input));
275
- return match && match[1] || '';
276
- }
277
- function basename(input, extension) {
278
- const lastSegment = normalizeWindowsPath(input).split('/').pop();
279
- if (!lastSegment) {
280
- return input;
281
- }
282
- return lastSegment;
283
- }
284
-
285
- function isPromise(p) {
286
- return isObject(p) && (p instanceof Promise || // eslint-disable-next-line @typescript-eslint/ban-ts-comment
287
- // @ts-ignore
288
- typeof p.then === 'function');
289
- }
290
-
291
- function isNodeStream(input) {
292
- return isObject(input) && typeof input.pipe === 'function' && typeof input.read === 'function';
293
- }
294
- function isWebStream(input) {
295
- return isObject(input) && typeof input.pipeTo === 'function';
296
- }
297
- function isStream(data) {
298
- return isNodeStream(data) || isWebStream(data);
299
- }
300
-
301
- const TRAILING_SLASH_RE = /\/$|\/\?/;
302
- function hasTrailingSlash(input = '', queryParams = false) {
303
- if (!queryParams) {
304
- return input.endsWith('/');
305
- }
306
- return TRAILING_SLASH_RE.test(input);
307
- }
308
- function withoutTrailingSlash(input = '', queryParams = false) {
309
- if (!queryParams) {
310
- return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || '/';
311
- }
312
- if (!hasTrailingSlash(input, true)) {
313
- return input || '/';
314
- }
315
- const [s0, ...s] = input.split('?');
316
- return (s0.slice(0, -1) || '/') + (s.length ? `?${s.join('?')}` : '');
317
- }
318
- function hasLeadingSlash(input = '') {
319
- return input.startsWith('/');
320
- }
321
- function withLeadingSlash(input = '') {
322
- return hasLeadingSlash(input) ? input : `/${input}`;
323
- }
324
- function cleanDoubleSlashes(input = '') {
325
- if (input.indexOf('://') !== -1) {
326
- return input.split('://').map((str)=>cleanDoubleSlashes(str)).join('://');
327
- }
328
- return input.replace(/\/+/g, '/');
329
- }
330
-
331
- function isWebBlob(input) {
332
- return typeof Blob !== 'undefined' && input instanceof Blob;
333
- }
334
- function isWebResponse(input) {
335
- return typeof Response !== 'undefined' && input instanceof Response;
336
- }
337
-
338
- const symbol$4 = Symbol.for('ReqEnv');
339
- function setRequestEnv(req, key, value) {
340
- const propertyValue = getProperty(req, symbol$4);
341
- if (propertyValue) {
342
- if (typeof key === 'object') {
343
- if (value) {
344
- setProperty(req, symbol$4, merge(propertyValue, key));
345
- } else {
346
- setProperty(req, symbol$4, key);
347
- }
348
- } else {
349
- propertyValue[key] = value;
350
- setProperty(req, symbol$4, propertyValue);
351
- }
352
- return;
353
- }
354
- if (typeof key === 'object') {
355
- setProperty(req, symbol$4, key);
356
- return;
357
- }
358
- setProperty(req, symbol$4, {
359
- [key]: value
360
- });
361
- }
362
- function useRequestEnv(req, key) {
363
- const propertyValue = getProperty(req, symbol$4);
364
- if (propertyValue) {
365
- if (typeof key !== 'undefined') {
366
- return propertyValue[key];
367
- }
368
- return propertyValue;
369
- }
370
- if (typeof key !== 'undefined') {
371
- return undefined;
372
- }
373
- return {};
374
- }
375
- function unsetRequestEnv(req, key) {
376
- const propertyValue = getProperty(req, symbol$4);
377
- if (hasOwnProperty(propertyValue, key)) {
378
- delete propertyValue[key];
379
- }
380
- }
381
-
382
- function getRequestHeader(req, name) {
383
- return req.headers[name];
384
- }
385
- function setRequestHeader(req, name, value) {
386
- req.headers[name] = value;
387
- }
388
-
389
- const symbol$3 = Symbol.for('ReqNegotiator');
390
- function useRequestNegotiator(req) {
391
- let value = getProperty(req, symbol$3);
392
- if (value) {
393
- return value;
394
- }
395
- value = new Negotiator(req);
396
- setProperty(req, symbol$3, value);
397
- return value;
398
- }
399
-
400
- function getRequestAcceptableContentTypes(req) {
401
- const negotiator = useRequestNegotiator(req);
402
- return negotiator.mediaTypes();
403
- }
404
- function getRequestAcceptableContentType(req, input) {
405
- input = input || [];
406
- const items = Array.isArray(input) ? input : [
407
- input
408
- ];
409
- if (items.length === 0) {
410
- return getRequestAcceptableContentTypes(req).shift();
411
- }
412
- const header = getRequestHeader(req, HeaderName.ACCEPT);
413
- if (!header) {
414
- return items[0];
415
- }
416
- let polluted = false;
417
- const mimeTypes = [];
418
- for(let i = 0; i < items.length; i++){
419
- const mimeType = getMimeType(items[i]);
420
- if (mimeType) {
421
- mimeTypes.push(mimeType);
422
- } else {
423
- polluted = true;
424
- }
425
- }
426
- const negotiator = useRequestNegotiator(req);
427
- const matches = negotiator.mediaTypes(mimeTypes);
428
- if (matches.length > 0) {
429
- if (polluted) {
430
- return items[0];
431
- }
432
- return items[mimeTypes.indexOf(matches[0])];
433
- }
434
- return undefined;
435
- }
436
-
437
- function getRequestAcceptableCharsets(req) {
438
- const negotiator = useRequestNegotiator(req);
439
- return negotiator.charsets();
440
- }
441
- function getRequestAcceptableCharset(req, input) {
442
- input = input || [];
443
- const items = Array.isArray(input) ? input : [
444
- input
445
- ];
446
- if (items.length === 0) {
447
- return getRequestAcceptableCharsets(req).shift();
448
- }
449
- const negotiator = useRequestNegotiator(req);
450
- return negotiator.charsets(items).shift() || undefined;
451
- }
452
-
453
- function getRequestAcceptableEncodings(req) {
454
- const negotiator = useRequestNegotiator(req);
455
- return negotiator.encodings();
456
- }
457
- function getRequestAcceptableEncoding(req, input) {
458
- input = input || [];
459
- const items = Array.isArray(input) ? input : [
460
- input
461
- ];
462
- if (items.length === 0) {
463
- return getRequestAcceptableEncodings(req).shift();
464
- }
465
- const negotiator = useRequestNegotiator(req);
466
- return negotiator.encodings(items).shift() || undefined;
467
- }
468
-
469
- function getRequestAcceptableLanguages(req) {
470
- const negotiator = useRequestNegotiator(req);
471
- return negotiator.languages();
472
- }
473
- function getRequestAcceptableLanguage(req, input) {
474
- input = input || [];
475
- const items = Array.isArray(input) ? input : [
476
- input
477
- ];
478
- if (items.length === 0) {
479
- return getRequestAcceptableLanguages(req).shift();
480
- }
481
- const negotiator = useRequestNegotiator(req);
482
- return negotiator.languages(items).shift() || undefined;
483
- }
484
-
485
- function matchRequestContentType(req, contentType) {
486
- const header = getRequestHeader(req, HeaderName.CONTENT_TYPE);
487
- if (!header) {
488
- return true;
489
- }
490
- /* istanbul ignore next */ if (Array.isArray(header)) {
491
- if (header.length === 0) {
492
- return true;
493
- }
494
- return header[0] === getMimeType(contentType);
495
- }
496
- return header.split('; ').shift() === getMimeType(contentType);
497
- }
498
-
499
- const defaults = {
500
- trustProxy: ()=>false,
501
- subdomainOffset: 2,
502
- etag: buildEtagFn(),
503
- proxyIpMax: 0
504
- };
505
- const instances = {};
506
- function setRouterOptions(id, input) {
507
- instances[id] = input;
508
- }
509
- function findRouterOption(key, path) {
510
- if (!path || path.length === 0) {
511
- return defaults[key];
512
- }
513
- if (path.length > 0) {
514
- for(let i = path.length; i >= 0; i--){
515
- if (hasOwnProperty(instances, path[i]) && typeof instances[path[i]][key] !== 'undefined') {
516
- return instances[path[i]][key];
517
- }
518
- }
519
- }
520
- return defaults[key];
521
- }
522
-
523
- const routerSymbol = Symbol.for('ReqRouterID');
524
- function setRequestRouterPath(req, path) {
525
- setProperty(req, routerSymbol, path);
526
- }
527
- function useRequestRouterPath(req) {
528
- return getProperty(req, routerSymbol);
529
- }
530
-
531
- function getRequestHostName(req, options) {
532
- options = options || {};
533
- let trustProxy;
534
- if (typeof options.trustProxy !== 'undefined') {
535
- trustProxy = buildTrustProxyFn(options.trustProxy);
536
- } else {
537
- trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
538
- }
539
- let hostname = req.headers[HeaderName.X_FORWARDED_HOST];
540
- if (!hostname || !req.socket.remoteAddress || !trustProxy(req.socket.remoteAddress, 0)) {
541
- hostname = req.headers[HeaderName.HOST];
542
- } else {
543
- hostname = Array.isArray(hostname) ? hostname.pop() : hostname;
544
- if (hostname && hostname.indexOf(',') !== -1) {
545
- hostname = hostname.substring(0, hostname.indexOf(',')).trimEnd();
546
- }
547
- }
548
- if (!hostname) {
549
- return undefined;
550
- }
551
- // IPv6 literal support
552
- const offset = hostname[0] === '[' ? hostname.indexOf(']') + 1 : 0;
553
- const index = hostname.indexOf(':', offset);
554
- return index !== -1 ? hostname.substring(0, index) : hostname;
555
- }
556
-
557
- function isRequestHTTP2(req) {
558
- return typeof getRequestHeader(req, ':path') !== 'undefined' && typeof getRequestHeader(req, ':method') !== 'undefined';
559
- }
560
-
561
- function getRequestIP(req, options) {
562
- options = options || {};
563
- let trustProxy;
564
- if (typeof options.trustProxy !== 'undefined') {
565
- trustProxy = buildTrustProxyFn(options.trustProxy);
566
- } else {
567
- trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
568
- }
569
- const addrs = all(req, trustProxy);
570
- return addrs[addrs.length - 1];
571
- }
572
-
573
- const symbol$2 = Symbol.for('ReqMountPath');
574
- function useRequestMountPath(req) {
575
- return getProperty(req, symbol$2) || '/';
576
- }
577
- function setRequestMountPath(req, basePath) {
578
- setProperty(req, symbol$2, basePath);
579
- }
580
-
581
- const symbol$1 = Symbol.for('ReqParams');
582
- function useRequestParams(req) {
583
- return getProperty(req, symbol$1) || getProperty(req, 'params') || {};
584
- }
585
- function useRequestParam(req, key) {
586
- return useRequestParams(req)[key];
587
- }
588
- function setRequestParams(req, data) {
589
- setProperty(req, symbol$1, data);
590
- }
591
- function setRequestParam(req, key, value) {
592
- const params = useRequestParams(req);
593
- params[key] = value;
594
- setRequestParams(req, params);
595
- }
596
-
597
- const PathSymbol = Symbol.for('ReqPath');
598
- function useRequestPath(req) {
599
- const path = getProperty(req, 'path') || getProperty(req, PathSymbol);
600
- if (path) {
601
- return path;
602
- }
603
- if (typeof req.url === 'undefined') {
604
- return '/';
605
- }
606
- const parsed = new URL(req.url, 'http://localhost/');
607
- setProperty(req, PathSymbol, parsed.pathname);
608
- return parsed.pathname;
609
- }
610
-
611
- function getRequestProtocol(req, options) {
612
- options = options || {};
613
- let trustProxy;
614
- if (typeof options.trustProxy !== 'undefined') {
615
- trustProxy = buildTrustProxyFn(options.trustProxy);
616
- } else {
617
- trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
618
- }
619
- let protocol = options.default;
620
- /* istanbul ignore next */ if (hasOwnProperty(req.socket, 'encrypted') && !!req.socket.encrypted) {
621
- protocol = 'https';
622
- } else if (!protocol) {
623
- protocol = 'http';
624
- }
625
- if (!req.socket.remoteAddress || !trustProxy(req.socket.remoteAddress, 0)) {
626
- return protocol;
627
- }
628
- let header = req.headers[HeaderName.X_FORWARDED_PROTO];
629
- /* istanbul ignore next */ if (Array.isArray(header)) {
630
- header = header.pop();
631
- }
632
- if (!header) {
633
- return protocol;
634
- }
635
- const index = header.indexOf(',');
636
- return index !== -1 ? header.substring(0, index).trim() : header.trim();
637
- }
638
-
639
- function createRequest(context) {
640
- let readable;
641
- if (context.body) {
642
- if (isWebStream(context.body)) {
643
- readable = Readable.fromWeb(context.body);
644
- } else {
645
- readable = Readable.from(context.body);
646
- }
647
- } else {
648
- readable = new Readable();
649
- }
650
- const headers = context.headers || {};
651
- const rawHeaders = [];
652
- let keys = Object.keys(headers);
653
- for(let i = 0; i < keys.length; i++){
654
- const header = headers[keys[i]];
655
- if (Array.isArray(header)) {
656
- for(let j = 0; j < header.length; j++){
657
- rawHeaders.push(keys[i], header[j]);
658
- }
659
- } else if (typeof header === 'string') {
660
- rawHeaders.push(keys[i], header);
661
- }
662
- }
663
- const headersDistinct = {};
664
- keys = Object.keys(headers);
665
- for(let i = 0; i < keys.length; i++){
666
- const header = headers[keys[i]];
667
- if (Array.isArray(header)) {
668
- headersDistinct[keys[i]] = header;
669
- }
670
- if (typeof header === 'string') {
671
- headersDistinct[keys[i]] = [
672
- header
673
- ];
674
- }
675
- }
676
- Object.defineProperty(readable, 'connection', {
677
- get () {
678
- return {
679
- remoteAddress: '127.0.0.1'
680
- };
681
- }
682
- });
683
- Object.defineProperty(readable, 'socket', {
684
- get () {
685
- return {
686
- remoteAddress: '127.0.0.1'
687
- };
688
- }
689
- });
690
- Object.assign(readable, {
691
- aborted: false,
692
- complete: true,
693
- headers,
694
- headersDistinct,
695
- httpVersion: '1.1',
696
- httpVersionMajor: 1,
697
- httpVersionMinor: 1,
698
- method: context.method || 'GET',
699
- rawHeaders,
700
- rawTrailers: [],
701
- trailers: {},
702
- trailersDistinct: {},
703
- url: context.url || '/',
704
- setTimeout (_msecs, _callback) {
705
- return this;
706
- }
707
- });
708
- return readable;
709
- }
710
-
711
- class RoutupError extends HTTPError {
712
- }
713
-
714
- function isError(input) {
715
- return input instanceof RoutupError;
716
- }
717
-
718
- /**
719
- * Create an internal error object by
720
- * - an existing error (accessible via cause property)
721
- * - options
722
- * - message
723
- *
724
- * @param input
725
- */ function createError(input) {
726
- if (isError(input)) {
727
- return input;
728
- }
729
- if (typeof input === 'string') {
730
- return new RoutupError(input);
731
- }
732
- if (!isObject(input)) {
733
- return new RoutupError();
734
- }
735
- return new RoutupError({
736
- cause: input
737
- }, input);
738
- }
739
-
740
- function setResponseCacheHeaders(res, options) {
741
- options = options || {};
742
- const cacheControls = [
743
- 'public'
744
- ].concat(options.cacheControls || []);
745
- if (options.maxAge !== undefined) {
746
- cacheControls.push(`max-age=${+options.maxAge}`, `s-maxage=${+options.maxAge}`);
747
- }
748
- if (options.modifiedTime) {
749
- const modifiedTime = typeof options.modifiedTime === 'string' ? new Date(options.modifiedTime) : options.modifiedTime;
750
- res.setHeader('last-modified', modifiedTime.toUTCString());
751
- }
752
- res.setHeader('cache-control', cacheControls.join(', '));
753
- }
754
-
755
- const symbol = Symbol.for('ResGone');
756
- function isResponseGone(res) {
757
- if (res.headersSent || res.writableEnded) {
758
- return true;
759
- }
760
- return getProperty(res, symbol) ?? false;
761
- }
762
- function setResponseGone(res, value) {
763
- setProperty(res, symbol, value);
764
- }
765
-
766
- function serializeEventStreamMessage(message) {
767
- let result = '';
768
- if (message.id) {
769
- result += `id: ${message.id}\n`;
770
- }
771
- if (message.event) {
772
- result += `event: ${message.event}\n`;
773
- }
774
- if (typeof message.retry === 'number' && Number.isInteger(message.retry)) {
775
- result += `retry: ${message.retry}\n`;
776
- }
777
- result += `data: ${message.data}\n\n`;
778
- return result;
779
- }
780
-
781
- class EventStream {
782
- open() {
783
- this.response.req.on('close', ()=>this.end());
784
- this.response.req.on('error', (err)=>{
785
- this.emit('error', err);
786
- this.end();
787
- });
788
- this.passThrough.on('data', (chunk)=>this.response.write(chunk));
789
- this.passThrough.on('error', (err)=>{
790
- this.emit('error', err);
791
- this.end();
792
- });
793
- this.passThrough.on('close', ()=>this.end());
794
- this.response.setHeader(HeaderName.CONTENT_TYPE, 'text/event-stream');
795
- this.response.setHeader(HeaderName.CACHE_CONTROL, 'private, no-cache, no-store, no-transform, must-revalidate, max-age=0');
796
- this.response.setHeader(HeaderName.X_ACCEL_BUFFERING, 'no');
797
- if (!isRequestHTTP2(this.response.req)) {
798
- this.response.setHeader(HeaderName.CONNECTION, 'keep-alive');
799
- }
800
- this.response.statusCode = 200;
801
- }
802
- write(message) {
803
- if (typeof message === 'string') {
804
- this.write({
805
- data: message
806
- });
807
- return;
808
- }
809
- if (!this.passThrough.closed && this.passThrough.writable) {
810
- this.passThrough.write(serializeEventStreamMessage(message));
811
- }
812
- }
813
- end() {
814
- if (this.flushed) return;
815
- this.flushed = true;
816
- if (!this.passThrough.closed) {
817
- this.passThrough.end();
818
- }
819
- this.emit('close');
820
- setResponseGone(this.response, true);
821
- this.response.end();
822
- }
823
- on(event, listener) {
824
- if (typeof this.eventHandlers[event] === 'undefined') {
825
- this.eventHandlers[event] = [];
826
- }
827
- this.eventHandlers[event].push(listener);
828
- }
829
- emit(event, ...args) {
830
- if (typeof this.eventHandlers[event] === 'undefined') {
831
- return;
832
- }
833
- const listeners = this.eventHandlers[event].slice();
834
- for(let i = 0; i < listeners.length; i++){
835
- listeners[i].apply(this, args);
836
- }
837
- }
838
- constructor(response){
839
- this.response = response;
840
- this.passThrough = new PassThrough({
841
- encoding: 'utf-8'
842
- });
843
- this.flushed = false;
844
- this.eventHandlers = {};
845
- this.open();
846
- }
847
- }
848
-
849
- function createEventStream(response) {
850
- return new EventStream(response);
851
- }
852
-
853
- function appendResponseHeader(res, name, value) {
854
- let header = res.getHeader(name);
855
- if (!header) {
856
- res.setHeader(name, value);
857
- return;
858
- }
859
- if (!Array.isArray(header)) {
860
- header = [
861
- header.toString()
862
- ];
863
- }
864
- res.setHeader(name, [
865
- ...header,
866
- value
867
- ]);
868
- }
869
- function appendResponseHeaderDirective(res, name, value) {
870
- let header = res.getHeader(name);
871
- if (!header) {
872
- if (Array.isArray(value)) {
873
- res.setHeader(name, value.join('; '));
874
- return;
875
- }
876
- res.setHeader(name, value);
877
- return;
878
- }
879
- if (!Array.isArray(header)) {
880
- if (typeof header === 'string') {
881
- // split header by directive(s)
882
- header = header.split('; ');
883
- }
884
- if (typeof header === 'number') {
885
- header = [
886
- header.toString()
887
- ];
888
- }
889
- }
890
- if (Array.isArray(value)) {
891
- header.push(...value);
892
- } else {
893
- header.push(`${value}`);
894
- }
895
- header = [
896
- ...new Set(header)
897
- ];
898
- res.setHeader(name, header.join('; '));
899
- }
900
-
901
- function setResponseContentTypeByFileName(res, fileName) {
902
- const ext = extname(fileName);
903
- if (ext) {
904
- let type = getMimeType(ext.substring(1));
905
- if (type) {
906
- const charset = getCharsetForMimeType(type);
907
- if (charset) {
908
- type += `; charset=${charset}`;
909
- }
910
- res.setHeader(HeaderName.CONTENT_TYPE, type);
911
- }
912
- }
913
- }
914
-
915
- function setResponseHeaderAttachment(res, filename) {
916
- if (typeof filename === 'string') {
917
- setResponseContentTypeByFileName(res, filename);
918
- }
919
- res.setHeader(HeaderName.CONTENT_DISPOSITION, `attachment${filename ? `; filename="${filename}"` : ''}`);
920
- }
921
-
922
- function setResponseHeaderContentType(res, input, ifNotExists) {
923
- if (ifNotExists) {
924
- const header = res.getHeader(HeaderName.CONTENT_TYPE);
925
- if (header) {
926
- return;
927
- }
928
- }
929
- const contentType = getMimeType(input);
930
- if (contentType) {
931
- res.setHeader(HeaderName.CONTENT_TYPE, contentType);
932
- }
933
- }
934
-
935
- async function sendStream(res, stream, next) {
936
- if (isWebStream(stream)) {
937
- return stream.pipeTo(new WritableStream({
938
- write (chunk) {
939
- res.write(chunk);
940
- }
941
- })).then(()=>{
942
- if (next) {
943
- return next();
944
- }
945
- res.end();
946
- return Promise.resolve();
947
- }).catch((err)=>{
948
- if (next) {
949
- return next(err);
950
- }
951
- return Promise.reject(err);
952
- });
953
- }
954
- return new Promise((resolve, reject)=>{
955
- stream.on('open', ()=>{
956
- stream.pipe(res);
957
- });
958
- /* istanbul ignore next */ stream.on('error', (err)=>{
959
- if (next) {
960
- Promise.resolve().then(()=>next(err)).then(()=>resolve()).catch((e)=>reject(e));
961
- return;
962
- }
963
- res.end();
964
- reject(err);
965
- });
966
- stream.on('close', ()=>{
967
- if (next) {
968
- Promise.resolve().then(()=>next()).then(()=>resolve()).catch((e)=>reject(e));
969
- return;
970
- }
971
- res.end();
972
- resolve();
973
- });
974
- });
975
- }
976
-
977
- async function sendWebBlob(res, blob) {
978
- setResponseHeaderContentType(res, blob.type);
979
- await sendStream(res, blob.stream());
980
- }
981
-
982
- async function sendWebResponse(res, webResponse) {
983
- if (webResponse.redirected) {
984
- res.setHeader(HeaderName.LOCATION, webResponse.url);
985
- }
986
- if (webResponse.status) {
987
- res.statusCode = webResponse.status;
988
- }
989
- if (webResponse.statusText) {
990
- res.statusMessage = webResponse.statusText;
991
- }
992
- webResponse.headers.forEach((value, key)=>{
993
- if (key === HeaderName.SET_COOKIE) {
994
- res.appendHeader(key, splitCookiesString(value));
995
- } else {
996
- res.setHeader(key, value);
997
- }
998
- });
999
- if (webResponse.body) {
1000
- await sendStream(res, webResponse.body);
1001
- return Promise.resolve();
1002
- }
1003
- res.end();
1004
- return Promise.resolve();
1005
- }
1006
-
1007
- async function send(res, chunk) {
1008
- switch(typeof chunk){
1009
- case 'string':
1010
- {
1011
- setResponseHeaderContentType(res, 'html', true);
1012
- break;
1013
- }
1014
- case 'boolean':
1015
- case 'number':
1016
- case 'object':
1017
- {
1018
- if (chunk !== null) {
1019
- if (chunk instanceof Error) {
1020
- throw chunk;
1021
- }
1022
- if (isStream(chunk)) {
1023
- await sendStream(res, chunk);
1024
- return;
1025
- }
1026
- if (isWebBlob(chunk)) {
1027
- await sendWebBlob(res, chunk);
1028
- return;
1029
- }
1030
- if (isWebResponse(chunk)) {
1031
- await sendWebResponse(res, chunk);
1032
- return;
1033
- }
1034
- if (Buffer.isBuffer(chunk)) {
1035
- setResponseHeaderContentType(res, 'bin', true);
1036
- } else {
1037
- chunk = JSON.stringify(chunk);
1038
- setResponseHeaderContentType(res, 'application/json', true);
1039
- }
1040
- }
1041
- break;
1042
- }
1043
- }
1044
- let encoding;
1045
- if (typeof chunk === 'string') {
1046
- res.setHeader(HeaderName.CONTENT_ENCODING, 'utf-8');
1047
- appendResponseHeaderDirective(res, HeaderName.CONTENT_TYPE, 'charset=utf-8');
1048
- encoding = 'utf-8';
1049
- }
1050
- // populate Content-Length
1051
- let len;
1052
- if (chunk !== undefined && chunk !== null) {
1053
- if (Buffer.isBuffer(chunk)) {
1054
- // get length of Buffer
1055
- len = chunk.length;
1056
- } else if (chunk.length < 1000) {
1057
- // just calculate length when no ETag + small chunk
1058
- len = Buffer.byteLength(chunk, encoding);
1059
- } else {
1060
- // convert chunk to Buffer and calculate
1061
- chunk = Buffer.from(chunk, encoding);
1062
- encoding = undefined;
1063
- len = chunk.length;
1064
- }
1065
- res.setHeader(HeaderName.CONTENT_LENGTH, `${len}`);
1066
- }
1067
- if (typeof len !== 'undefined') {
1068
- const etagFn = findRouterOption('etag', useRequestRouterPath(res.req));
1069
- const chunkHash = await etagFn(chunk, encoding, len);
1070
- if (isResponseGone(res)) {
1071
- return;
1072
- }
1073
- if (typeof chunkHash === 'string') {
1074
- res.setHeader(HeaderName.ETag, chunkHash);
1075
- if (res.req.headers[HeaderName.IF_NONE_MATCH] === chunkHash) {
1076
- res.statusCode = 304;
1077
- }
1078
- }
1079
- }
1080
- // strip irrelevant headers
1081
- if (res.statusCode === 204 || res.statusCode === 304) {
1082
- res.removeHeader(HeaderName.CONTENT_TYPE);
1083
- res.removeHeader(HeaderName.CONTENT_LENGTH);
1084
- res.removeHeader(HeaderName.TRANSFER_ENCODING);
1085
- }
1086
- // alter headers for 205
1087
- if (res.statusCode === 205) {
1088
- res.setHeader(HeaderName.CONTENT_LENGTH, 0);
1089
- res.removeHeader(HeaderName.TRANSFER_ENCODING);
1090
- }
1091
- if (isResponseGone(res)) {
1092
- return;
1093
- }
1094
- if (res.req.method === 'HEAD' || res.req.method === 'head') {
1095
- // skip body for HEAD
1096
- res.end();
1097
- return;
1098
- }
1099
- if (typeof chunk === 'undefined' || chunk === null) {
1100
- res.end();
1101
- return;
1102
- }
1103
- if (typeof encoding !== 'undefined') {
1104
- res.end(chunk, encoding);
1105
- return;
1106
- }
1107
- res.end(chunk);
1108
- }
1109
-
1110
- function sendAccepted(res, chunk) {
1111
- res.statusCode = 202;
1112
- res.statusMessage = 'Accepted';
1113
- return send(res, chunk);
1114
- }
1115
-
1116
- function sendCreated(res, chunk) {
1117
- res.statusCode = 201;
1118
- res.statusMessage = 'Created';
1119
- return send(res, chunk);
1120
- }
1121
-
1122
- async function sendFile(res, options, next) {
1123
- let stats;
1124
- try {
1125
- stats = await options.stats();
1126
- } catch (e) {
1127
- if (next) {
1128
- return next(e);
1129
- }
1130
- if (isResponseGone(res)) {
1131
- return Promise.resolve();
1132
- }
1133
- return Promise.reject(e);
1134
- }
1135
- const name = options.name || stats.name;
1136
- if (name) {
1137
- const fileName = basename(name);
1138
- if (options.attachment) {
1139
- const dispositionHeader = res.getHeader(HeaderName.CONTENT_DISPOSITION);
1140
- if (!dispositionHeader) {
1141
- setResponseHeaderAttachment(res, fileName);
1142
- }
1143
- } else {
1144
- setResponseContentTypeByFileName(res, fileName);
1145
- }
1146
- }
1147
- const contentOptions = {};
1148
- if (stats.size) {
1149
- const rangeHeader = res.req.headers[HeaderName.RANGE];
1150
- if (rangeHeader) {
1151
- const [x, y] = rangeHeader.replace('bytes=', '').split('-');
1152
- contentOptions.end = Math.min(parseInt(y, 10) || stats.size - 1, stats.size - 1);
1153
- contentOptions.start = parseInt(x, 10) || 0;
1154
- if (contentOptions.end >= stats.size) {
1155
- contentOptions.end = stats.size - 1;
1156
- }
1157
- if (contentOptions.start >= stats.size) {
1158
- res.setHeader(HeaderName.CONTENT_RANGE, `bytes */${stats.size}`);
1159
- res.statusCode = 416;
1160
- res.end();
1161
- return Promise.resolve();
1162
- }
1163
- res.setHeader(HeaderName.CONTENT_RANGE, `bytes ${contentOptions.start}-${contentOptions.end}/${stats.size}`);
1164
- res.setHeader(HeaderName.CONTENT_LENGTH, contentOptions.end - contentOptions.start + 1);
1165
- } else {
1166
- res.setHeader(HeaderName.CONTENT_LENGTH, stats.size);
1167
- }
1168
- res.setHeader(HeaderName.ACCEPT_RANGES, 'bytes');
1169
- if (stats.mtime) {
1170
- const mtime = new Date(stats.mtime);
1171
- res.setHeader(HeaderName.LAST_MODIFIED, mtime.toUTCString());
1172
- res.setHeader(HeaderName.ETag, `W/"${stats.size}-${mtime.getTime()}"`);
1173
- }
1174
- }
1175
- try {
1176
- const content = await options.content(contentOptions);
1177
- if (isStream(content)) {
1178
- return await sendStream(res, content, next);
1179
- }
1180
- return await send(res, content);
1181
- } catch (e) {
1182
- if (next) {
1183
- return next(e);
1184
- }
1185
- if (isResponseGone(res)) {
1186
- return Promise.resolve();
1187
- }
1188
- return Promise.reject(e);
1189
- }
1190
- }
1191
-
1192
- function sendFormat(res, input) {
1193
- const { default: formatDefault, ...formats } = input;
1194
- const contentTypes = Object.keys(formats);
1195
- const contentType = getRequestAcceptableContentType(res.req, contentTypes);
1196
- if (contentType) {
1197
- formats[contentType]();
1198
- return;
1199
- }
1200
- formatDefault();
1201
- }
1202
-
1203
- function sendRedirect(res, location, statusCode = 302) {
1204
- res.statusCode = statusCode;
1205
- res.setHeader('location', location);
1206
- const encodedLoc = location.replace(/"/g, '%22');
1207
- const html = `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`;
1208
- return send(res, html);
1209
- }
1210
-
1211
- function createResponse(request) {
1212
- let output;
1213
- let encoding;
1214
- const write = (chunk, chunkEncoding, callback)=>{
1215
- if (typeof chunk !== 'undefined') {
1216
- const chunkEncoded = typeof chunk === 'string' ? Buffer.from(chunk, chunkEncoding || encoding || 'utf8') : chunk;
1217
- if (typeof output !== 'undefined') {
1218
- output = Buffer.concat([
1219
- output,
1220
- chunkEncoded
1221
- ]);
1222
- } else {
1223
- output = chunkEncoded;
1224
- }
1225
- }
1226
- encoding = chunkEncoding;
1227
- if (callback) {
1228
- callback();
1229
- }
1230
- };
1231
- const writable = new Writable({
1232
- decodeStrings: false,
1233
- write (chunk, arg2, arg3) {
1234
- const chunkEncoding = typeof arg2 === 'string' ? encoding : 'utf-8';
1235
- let cb;
1236
- if (typeof arg2 === 'function') {
1237
- cb = arg2;
1238
- } else if (typeof arg3 === 'function') {
1239
- cb = arg3;
1240
- }
1241
- write(chunk, chunkEncoding, cb);
1242
- return true;
1243
- }
1244
- });
1245
- Object.defineProperty(writable, 'body', {
1246
- get () {
1247
- if (output) {
1248
- const arrayBuffer = new ArrayBuffer(output.length);
1249
- const view = new Uint8Array(arrayBuffer);
1250
- for(let i = 0; i < output.length; ++i){
1251
- view[i] = output[i];
1252
- }
1253
- return arrayBuffer;
1254
- }
1255
- return new ArrayBuffer(0);
1256
- }
1257
- });
1258
- const headers = {};
1259
- Object.assign(writable, {
1260
- req: request,
1261
- chunkedEncoding: false,
1262
- connection: null,
1263
- headersSent: false,
1264
- sendDate: false,
1265
- shouldKeepAlive: false,
1266
- socket: null,
1267
- statusCode: 200,
1268
- statusMessage: '',
1269
- strictContentLength: false,
1270
- useChunkedEncodingByDefault: false,
1271
- finished: false,
1272
- addTrailers (_headers) {},
1273
- appendHeader (name, value) {
1274
- if (name === HeaderName.SET_COOKIE) {
1275
- value = splitCookiesString(value);
1276
- }
1277
- name = name.toLowerCase();
1278
- const current = headers[name];
1279
- const all = [
1280
- ...Array.isArray(current) ? current : [
1281
- current
1282
- ],
1283
- ...Array.isArray(value) ? value : [
1284
- value
1285
- ]
1286
- ].filter(Boolean);
1287
- headers[name] = all.length > 1 ? all : all[0];
1288
- return this;
1289
- },
1290
- assignSocket (_socket) {},
1291
- detachSocket (_socket) {},
1292
- flushHeaders () {},
1293
- getHeader (name) {
1294
- return headers[name.toLowerCase()];
1295
- },
1296
- getHeaderNames () {
1297
- return Object.keys(headers);
1298
- },
1299
- getHeaders () {
1300
- return headers;
1301
- },
1302
- hasHeader (name) {
1303
- return hasOwnProperty(headers, name.toLowerCase());
1304
- },
1305
- removeHeader (name) {
1306
- delete headers[name.toLowerCase()];
1307
- },
1308
- setHeader (name, value) {
1309
- if (name === HeaderName.SET_COOKIE && typeof value !== 'number') {
1310
- value = splitCookiesString(value);
1311
- }
1312
- headers[name.toLowerCase()] = value;
1313
- return this;
1314
- },
1315
- setHeaders (headers) {
1316
- if (headers instanceof Map) {
1317
- headers.entries().forEach(([key, value])=>{
1318
- this.setHeader(key, value);
1319
- });
1320
- return this;
1321
- }
1322
- headers.forEach((value, key)=>{
1323
- this.setHeader(key, value);
1324
- });
1325
- return this;
1326
- },
1327
- setTimeout (_msecs, _callback) {
1328
- return this;
1329
- },
1330
- writeContinue (_callback) {},
1331
- writeEarlyHints (_hints, callback) {
1332
- if (typeof callback !== 'undefined') {
1333
- callback();
1334
- }
1335
- },
1336
- writeProcessing () {},
1337
- writeHead (statusCode, arg1, arg2) {
1338
- this.statusCode = statusCode;
1339
- if (typeof arg1 === 'string') {
1340
- this.statusMessage = arg1;
1341
- arg1 = undefined;
1342
- }
1343
- const headers = arg2 || arg1;
1344
- if (headers) {
1345
- if (Array.isArray(headers)) {
1346
- for(let i = 0; i < headers.length; i++){
1347
- const keys = Object.keys(headers[i]);
1348
- for(let j = 0; j < keys.length; j++){
1349
- this.setHeader(keys[i], headers[i][keys[j]]);
1350
- }
1351
- }
1352
- } else {
1353
- const keys = Object.keys(headers);
1354
- for(let i = 0; i < keys.length; i++){
1355
- this.setHeader(keys[i], headers[keys[i]]);
1356
- }
1357
- }
1358
- }
1359
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1360
- // @ts-ignore
1361
- this.headersSent = true;
1362
- return this;
1363
- }
1364
- });
1365
- return writable;
1366
- }
1367
-
1368
- function dispatch(event, target) {
1369
- setRequestParams(event.request, event.params);
1370
- setRequestMountPath(event.request, event.mountPath);
1371
- setRequestRouterPath(event.request, event.routerPath);
1372
- return new Promise((resolve, reject)=>{
1373
- let handled = false;
1374
- const unsubscribe = ()=>{
1375
- event.response.off('close', done);
1376
- event.response.off('error', done);
1377
- };
1378
- const shutdown = (dispatched, err)=>{
1379
- if (handled) {
1380
- return;
1381
- }
1382
- handled = true;
1383
- unsubscribe();
1384
- if (err) {
1385
- reject(createError(err));
1386
- } else {
1387
- resolve(dispatched);
1388
- }
1389
- };
1390
- const done = (err)=>shutdown(true, err);
1391
- const next = (err)=>shutdown(false, err);
1392
- event.response.once('close', done);
1393
- event.response.once('error', done);
1394
- const handle = async (data)=>{
1395
- if (typeof data === 'undefined' || handled) {
1396
- return false;
1397
- }
1398
- handled = true;
1399
- unsubscribe();
1400
- if (!event.dispatched) {
1401
- await send(event.response, data);
1402
- }
1403
- return true;
1404
- };
1405
- try {
1406
- const output = target(next);
1407
- if (isPromise(output)) {
1408
- output.then((r)=>handle(r)).then((resolved)=>{
1409
- if (resolved) {
1410
- resolve(true);
1411
- }
1412
- }).catch((e)=>reject(createError(e)));
1413
- return;
1414
- }
1415
- Promise.resolve().then(()=>handle(output)).then((resolved)=>{
1416
- if (resolved) {
1417
- resolve(true);
1418
- }
1419
- }).catch((e)=>reject(createError(e)));
1420
- } catch (error) {
1421
- next(error);
1422
- }
1423
- });
1424
- }
1425
-
1426
- function isDispatcherErrorEvent(event) {
1427
- return typeof event.error !== 'undefined';
1428
- }
1429
-
1430
- class DispatchEvent {
1431
- get dispatched() {
1432
- return this._dispatched || this.response.writableEnded || this.response.headersSent;
1433
- }
1434
- set dispatched(value) {
1435
- this._dispatched = value;
1436
- }
1437
- constructor(context){
1438
- this.request = context.request;
1439
- this.response = context.response;
1440
- this.method = context.method || MethodName.GET;
1441
- this.methodsAllowed = [];
1442
- this.mountPath = '/';
1443
- this.params = {};
1444
- this.path = context.path || '/';
1445
- this.routerPath = [];
1446
- this.next = nextPlaceholder;
1447
- }
1448
- }
1449
-
1450
- class DispatchErrorEvent extends DispatchEvent {
1451
- }
1452
-
1453
- async function dispatchNodeRequest(router, request, response) {
1454
- const event = new DispatchEvent({
1455
- request,
1456
- response,
1457
- path: useRequestPath(request),
1458
- method: toMethodName(request.method, MethodName.GET)
1459
- });
1460
- await router.dispatch(event);
1461
- if (event.dispatched) {
1462
- return;
1463
- }
1464
- if (event.error) {
1465
- event.response.statusCode = event.error.statusCode;
1466
- if (event.error.statusMessage) {
1467
- event.response.statusMessage = event.error.statusMessage;
1468
- }
1469
- event.response.end();
1470
- return;
1471
- }
1472
- event.response.statusCode = 404;
1473
- event.response.end();
1474
- }
1475
- function createNodeDispatcher(router) {
1476
- return (req, res)=>{
1477
- // eslint-disable-next-line no-void
1478
- void dispatchNodeRequest(router, req, res);
1479
- };
1480
- }
1481
-
1482
- function transformHeaderToTuples(key, value) {
1483
- const output = [];
1484
- if (Array.isArray(value)) {
1485
- for(let j = 0; j < value.length; j++){
1486
- output.push([
1487
- key,
1488
- value[j]
1489
- ]);
1490
- }
1491
- } else if (value !== undefined) {
1492
- output.push([
1493
- key,
1494
- String(value)
1495
- ]);
1496
- }
1497
- return output;
1498
- }
1499
- function transformHeadersToTuples(input) {
1500
- const output = [];
1501
- const keys = Object.keys(input);
1502
- for(let i = 0; i < keys.length; i++){
1503
- const key = keys[i].toLowerCase();
1504
- output.push(...transformHeaderToTuples(key, input[key]));
1505
- }
1506
- return output;
1507
- }
1508
-
1509
- async function dispatchRawRequest(router, request) {
1510
- const method = toMethodName(request.method, MethodName.GET);
1511
- const req = createRequest({
1512
- url: request.path,
1513
- method,
1514
- body: request.body,
1515
- headers: request.headers
1516
- });
1517
- const res = createResponse(req);
1518
- const getHeaders = ()=>{
1519
- const output = {};
1520
- const headers = res.getHeaders();
1521
- const keys = Object.keys(headers);
1522
- for(let i = 0; i < keys.length; i++){
1523
- const header = headers[keys[i]];
1524
- if (typeof header === 'number') {
1525
- output[keys[i]] = `${header}`;
1526
- } else if (header) {
1527
- output[keys[i]] = header;
1528
- }
1529
- }
1530
- return output;
1531
- };
1532
- const createRawResponse = (input = {})=>({
1533
- status: input.status || res.statusCode,
1534
- statusMessage: input.statusMessage || res.statusMessage,
1535
- headers: getHeaders(),
1536
- body: res.body
1537
- });
1538
- const event = new DispatchEvent({
1539
- request: req,
1540
- response: res,
1541
- path: request.path,
1542
- method
1543
- });
1544
- await router.dispatch(event);
1545
- if (event.dispatched) {
1546
- return createRawResponse();
1547
- }
1548
- if (event.error) {
1549
- return createRawResponse({
1550
- status: event.error.statusCode,
1551
- statusMessage: event.error.statusMessage
1552
- });
1553
- }
1554
- return createRawResponse({
1555
- status: 404
1556
- });
1557
- }
1558
- function createRawDispatcher(router) {
1559
- return async (request)=>dispatchRawRequest(router, request);
1560
- }
1561
-
1562
- async function dispatchWebRequest(router, request) {
1563
- const url = new URL(request.url);
1564
- const headers = {};
1565
- request.headers.forEach((value, key)=>{
1566
- headers[key] = value;
1567
- });
1568
- const method = toMethodName(request.method, MethodName.GET);
1569
- const res = await dispatchRawRequest(router, {
1570
- method,
1571
- path: url.pathname + url.search,
1572
- headers,
1573
- body: request.body
1574
- });
1575
- let body;
1576
- if (method === MethodName.HEAD || res.status === 304 || res.status === 101 || res.status === 204 || res.status === 205) {
1577
- body = null;
1578
- } else {
1579
- body = res.body;
1580
- }
1581
- return new Response(body, {
1582
- headers: transformHeadersToTuples(res.headers),
1583
- status: res.status,
1584
- statusText: res.statusMessage
1585
- });
1586
- }
1587
- function createWebDispatcher(router) {
1588
- return async (request)=>dispatchWebRequest(router, request);
1589
- }
1590
-
1591
- var HandlerType = /*#__PURE__*/ function(HandlerType) {
1592
- HandlerType["CORE"] = "core";
1593
- HandlerType["ERROR"] = "error";
1594
- return HandlerType;
1595
- }({});
1596
- const HandlerSymbol = Symbol.for('Handler');
1597
-
1598
- var HookName = /*#__PURE__*/ function(HookName) {
1599
- HookName["ERROR"] = "error";
1600
- HookName["DISPATCH_START"] = "dispatchStart";
1601
- HookName["DISPATCH_END"] = "dispatchEnd";
1602
- HookName["CHILD_MATCH"] = "childMatch";
1603
- HookName["CHILD_DISPATCH_BEFORE"] = "childDispatchBefore";
1604
- HookName["CHILD_DISPATCH_AFTER"] = "childDispatchAfter";
1605
- return HookName;
1606
- }({});
1607
-
1608
- class HookManager {
1609
- // --------------------------------------------------
1610
- addListener(name, fn) {
1611
- this.items[name] = this.items[name] || [];
1612
- this.items[name].push(fn);
1613
- return ()=>{
1614
- this.removeListener(name, fn);
1615
- };
1616
- }
1617
- removeListener(name, fn) {
1618
- if (!this.items[name]) {
1619
- return;
1620
- }
1621
- if (typeof fn === 'undefined') {
1622
- delete this.items[name];
1623
- return;
1624
- }
1625
- if (typeof fn === 'function') {
1626
- const index = this.items[name].indexOf(fn);
1627
- if (index !== -1) {
1628
- this.items[name].splice(index, 1);
1629
- }
1630
- }
1631
- if (this.items[name].length === 0) {
1632
- delete this.items[name];
1633
- }
1634
- }
1635
- // --------------------------------------------------
1636
- /**
1637
- * @throws RoutupError
1638
- *
1639
- * @param name
1640
- * @param event
1641
- */ async trigger(name, event) {
1642
- if (!this.items[name] || this.items[name].length === 0) {
1643
- return;
1644
- }
1645
- try {
1646
- for(let i = 0; i < this.items[name].length; i++){
1647
- const hook = this.items[name][i];
1648
- event.dispatched = await dispatch(event, (next)=>Promise.resolve().then(()=>{
1649
- event.next = next;
1650
- return this.triggerListener(name, event, hook);
1651
- }).catch((err)=>next(err)));
1652
- event.next = nextPlaceholder;
1653
- if (event.dispatched) {
1654
- if (event.error) {
1655
- event.error = undefined;
1656
- }
1657
- return;
1658
- }
1659
- }
1660
- } catch (e) {
1661
- event.error = e;
1662
- if (!this.isErrorListenerHook(name)) {
1663
- await this.trigger(HookName.ERROR, event);
1664
- if (event.dispatched) {
1665
- if (event.error) {
1666
- event.error = undefined;
1667
- }
1668
- }
1669
- }
1670
- }
1671
- }
1672
- triggerListener(name, event, listener) {
1673
- if (this.isErrorListenerHook(name)) {
1674
- if (isDispatcherErrorEvent(event)) {
1675
- return listener(event);
1676
- }
1677
- return undefined;
1678
- }
1679
- return listener(event);
1680
- }
1681
- isErrorListenerHook(input) {
1682
- return input === HookName.ERROR;
1683
- }
1684
- // --------------------------------------------------
1685
- constructor(){
1686
- this.items = {};
1687
- }
1688
- }
1689
-
1690
- function decodeParam(val) {
1691
- /* istanbul ignore next */ if (typeof val !== 'string' || val.length === 0) {
1692
- return val;
1693
- }
1694
- return decodeURIComponent(val);
1695
- }
1696
- class PathMatcher {
1697
- test(path) {
1698
- return this.regexp.test(path);
1699
- }
1700
- exec(path) {
1701
- if (this.path === '/' && this.regexpOptions.end === false) {
1702
- return {
1703
- path: '/',
1704
- params: {}
1705
- };
1706
- }
1707
- if (this.path === '*') {
1708
- return {
1709
- path,
1710
- params: {
1711
- 0: decodeParam(path)
1712
- }
1713
- };
1714
- }
1715
- const match = this.regexp.exec(path);
1716
- if (!match) {
1717
- return undefined;
1718
- }
1719
- const params = {};
1720
- for(let i = 1; i < match.length; i++){
1721
- const key = this.regexpKeys[i - 1];
1722
- const prop = key.name;
1723
- const val = decodeParam(match[i]);
1724
- if (typeof val !== 'undefined') {
1725
- params[prop] = val;
1726
- }
1727
- }
1728
- return {
1729
- path: match[0],
1730
- params
1731
- };
1732
- }
1733
- constructor(path, options){
1734
- this.regexpKeys = [];
1735
- this.path = path;
1736
- this.regexpOptions = options || {};
1737
- const regexp = pathToRegexp(path, options);
1738
- this.regexp = regexp.regexp;
1739
- this.regexpKeys = regexp.keys;
1740
- }
1741
- }
1742
-
1743
- function isPath(input) {
1744
- return typeof input === 'string';
1745
- }
1746
-
1747
- class Handler {
1748
- // --------------------------------------------------
1749
- get type() {
1750
- return this.config.type;
1751
- }
1752
- get path() {
1753
- return this.config.path;
1754
- }
1755
- get method() {
1756
- if (this._method || !this.config.method) {
1757
- return this._method;
1758
- }
1759
- this._method = toMethodName(this.config.method);
1760
- return this._method;
1761
- }
1762
- // --------------------------------------------------
1763
- async dispatch(event) {
1764
- if (this.pathMatcher) {
1765
- const pathMatch = this.pathMatcher.exec(event.path);
1766
- if (pathMatch) {
1767
- event.params = {
1768
- ...event.params,
1769
- ...pathMatch.params
1770
- };
1771
- }
1772
- }
1773
- await this.hookManager.trigger(HookName.CHILD_DISPATCH_BEFORE, event);
1774
- if (event.dispatched) {
1775
- return Promise.resolve();
1776
- }
1777
- try {
1778
- event.dispatched = await dispatch(event, (done)=>{
1779
- if (this.config.type === HandlerType.ERROR) {
1780
- if (event.error) {
1781
- return this.config.fn(event.error, event.request, event.response, done);
1782
- }
1783
- } else {
1784
- return this.config.fn(event.request, event.response, done);
1785
- }
1786
- return undefined;
1787
- });
1788
- } catch (e) {
1789
- if (isError(e)) {
1790
- event.error = e;
1791
- await this.hookManager.trigger(HookName.ERROR, event);
1792
- if (event.dispatched) {
1793
- event.error = undefined;
1794
- } else {
1795
- throw e;
1796
- }
1797
- }
1798
- }
1799
- return this.hookManager.trigger(HookName.CHILD_DISPATCH_AFTER, event);
1800
- }
1801
- // --------------------------------------------------
1802
- matchPath(path) {
1803
- if (!this.pathMatcher) {
1804
- return true;
1805
- }
1806
- return this.pathMatcher.test(path);
1807
- }
1808
- setPath(path) {
1809
- if (typeof path === 'string') {
1810
- path = withLeadingSlash(path);
1811
- }
1812
- this.config.path = path;
1813
- if (typeof path === 'undefined') {
1814
- this.pathMatcher = undefined;
1815
- return;
1816
- }
1817
- this.pathMatcher = new PathMatcher(path, {
1818
- end: !!this.config.method
1819
- });
1820
- }
1821
- // --------------------------------------------------
1822
- matchMethod(method) {
1823
- return !this.method || method === this.method || method === MethodName.HEAD && this.method === MethodName.GET;
1824
- }
1825
- setMethod(input) {
1826
- const method = toMethodName(input);
1827
- this.config.method = method;
1828
- this._method = method;
1829
- }
1830
- // --------------------------------------------------
1831
- mountHooks() {
1832
- if (this.config.onBefore) {
1833
- this.hookManager.addListener(HookName.CHILD_DISPATCH_BEFORE, this.config.onBefore);
1834
- }
1835
- if (this.config.onAfter) {
1836
- this.hookManager.addListener(HookName.CHILD_DISPATCH_AFTER, this.config.onAfter);
1837
- }
1838
- if (this.config.onError) {
1839
- this.hookManager.addListener(HookName.ERROR, this.config.onError);
1840
- }
1841
- }
1842
- // --------------------------------------------------
1843
- constructor(handler){
1844
- this['@instanceof'] = HandlerSymbol;
1845
- this.config = handler;
1846
- this.hookManager = new HookManager();
1847
- this.mountHooks();
1848
- this.setPath(handler.path);
1849
- }
1850
- }
1851
-
1852
- function coreHandler(input) {
1853
- if (typeof input === 'function') {
1854
- return new Handler({
1855
- type: HandlerType.CORE,
1856
- fn: input
1857
- });
1858
- }
1859
- return new Handler({
1860
- type: HandlerType.CORE,
1861
- ...input
1862
- });
1863
- }
1864
-
1865
- function errorHandler(input) {
1866
- if (typeof input === 'function') {
1867
- return new Handler({
1868
- type: HandlerType.ERROR,
1869
- fn: input
1870
- });
1871
- }
1872
- return new Handler({
1873
- type: HandlerType.ERROR,
1874
- ...input
1875
- });
1876
- }
1877
-
1878
- function isHandlerConfig(input) {
1879
- return isObject(input) && typeof input.fn === 'function' && typeof input.type === 'string';
1880
- }
1881
- function isHandler(input) {
1882
- return isInstance(input, HandlerSymbol);
1883
- }
1884
-
1885
- function isPlugin(input) {
1886
- if (!isObject(input)) {
1887
- return false;
1888
- }
1889
- if (typeof input.name !== 'undefined' && typeof input.name !== 'string') {
1890
- return false;
1891
- }
1892
- return typeof input.install === 'function' && input.install.length === 1;
1893
- }
1894
-
1895
- function transformRouterOptions(input) {
1896
- if (typeof input.etag !== 'undefined') {
1897
- input.etag = buildEtagFn(input.etag);
1898
- }
1899
- if (typeof input.trustProxy !== 'undefined') {
1900
- input.trustProxy = buildTrustProxyFn(input.trustProxy);
1901
- }
1902
- return input;
1903
- }
1904
-
1905
- const RouterSymbol = Symbol.for('Router');
1906
- var RouterPipelineStep = /*#__PURE__*/ function(RouterPipelineStep) {
1907
- RouterPipelineStep[RouterPipelineStep["START"] = 0] = "START";
1908
- RouterPipelineStep[RouterPipelineStep["LOOKUP"] = 1] = "LOOKUP";
1909
- RouterPipelineStep[RouterPipelineStep["CHILD_BEFORE"] = 2] = "CHILD_BEFORE";
1910
- RouterPipelineStep[RouterPipelineStep["CHILD_DISPATCH"] = 3] = "CHILD_DISPATCH";
1911
- RouterPipelineStep[RouterPipelineStep["CHILD_AFTER"] = 4] = "CHILD_AFTER";
1912
- RouterPipelineStep[RouterPipelineStep["FINISH"] = 5] = "FINISH";
1913
- return RouterPipelineStep;
1914
- }({});
1915
-
1916
- let nextId = 0;
1917
- function generateRouterID() {
1918
- return ++nextId;
1919
- }
1920
- function isRouterInstance(input) {
1921
- return isInstance(input, RouterSymbol);
1922
- }
1923
-
1924
- class Router {
1925
- // --------------------------------------------------
1926
- matchPath(path) {
1927
- if (this.pathMatcher) {
1928
- return this.pathMatcher.test(path);
1929
- }
1930
- return true;
1931
- }
1932
- setPath(value) {
1933
- if (value === '/' || typeof value === 'undefined') {
1934
- this.pathMatcher = undefined;
1935
- return;
1936
- }
1937
- this.pathMatcher = new PathMatcher(withLeadingSlash(withoutTrailingSlash(`${value}`)), {
1938
- end: false
1939
- });
1940
- }
1941
- // --------------------------------------------------
1942
- async executePipelineStep(context) {
1943
- switch(context.step){
1944
- case RouterPipelineStep.START:
1945
- {
1946
- return this.executePipelineStepStart(context);
1947
- }
1948
- case RouterPipelineStep.LOOKUP:
1949
- {
1950
- return this.executePipelineStepLookup(context);
1951
- }
1952
- case RouterPipelineStep.CHILD_BEFORE:
1953
- {
1954
- return this.executePipelineStepChildBefore(context);
1955
- }
1956
- case RouterPipelineStep.CHILD_DISPATCH:
1957
- {
1958
- return this.executePipelineStepChildDispatch(context);
1959
- }
1960
- case RouterPipelineStep.CHILD_AFTER:
1961
- {
1962
- return this.executePipelineStepChildAfter(context);
1963
- }
1964
- case RouterPipelineStep.FINISH:
1965
- default:
1966
- {
1967
- return this.executePipelineStepFinish(context);
1968
- }
1969
- }
1970
- }
1971
- async executePipelineStepStart(context) {
1972
- return this.hookManager.trigger(HookName.DISPATCH_START, context.event).then(()=>{
1973
- if (context.event.dispatched) {
1974
- context.step = RouterPipelineStep.FINISH;
1975
- } else {
1976
- context.step++;
1977
- }
1978
- return this.executePipelineStep(context);
1979
- });
1980
- }
1981
- async executePipelineStepLookup(context) {
1982
- if (context.event.dispatched || context.stackIndex >= this.stack.length) {
1983
- context.step = RouterPipelineStep.FINISH;
1984
- return this.executePipelineStep(context);
1985
- }
1986
- let match;
1987
- const item = this.stack[context.stackIndex];
1988
- if (isHandler(item)) {
1989
- if (context.event.error && item.type === HandlerType.CORE || !context.event.error && item.type === HandlerType.ERROR) {
1990
- context.stackIndex++;
1991
- return this.executePipelineStepLookup(context);
1992
- }
1993
- match = item.matchPath(context.event.path);
1994
- if (match) {
1995
- if (item.method) {
1996
- context.event.methodsAllowed.push(item.method);
1997
- }
1998
- if (item.matchMethod(context.event.method)) {
1999
- await this.hookManager.trigger(HookName.CHILD_MATCH, context.event);
2000
- if (context.event.dispatched) {
2001
- context.step = RouterPipelineStep.FINISH;
2002
- } else {
2003
- context.step++;
2004
- }
2005
- return this.executePipelineStep(context);
2006
- }
2007
- }
2008
- context.stackIndex++;
2009
- return this.executePipelineStepLookup(context);
2010
- }
2011
- match = item.matchPath(context.event.path);
2012
- if (match) {
2013
- await this.hookManager.trigger(HookName.CHILD_MATCH, context.event);
2014
- if (context.event.dispatched) {
2015
- context.step = RouterPipelineStep.FINISH;
2016
- } else {
2017
- context.step++;
2018
- }
2019
- return this.executePipelineStep(context);
2020
- }
2021
- context.stackIndex++;
2022
- return this.executePipelineStepLookup(context);
2023
- }
2024
- async executePipelineStepChildBefore(context) {
2025
- return this.hookManager.trigger(HookName.CHILD_DISPATCH_BEFORE, context.event).then(()=>{
2026
- if (context.event.dispatched) {
2027
- context.step = RouterPipelineStep.FINISH;
2028
- } else {
2029
- context.step++;
2030
- }
2031
- return this.executePipelineStep(context);
2032
- });
2033
- }
2034
- async executePipelineStepChildAfter(context) {
2035
- return this.hookManager.trigger(HookName.CHILD_DISPATCH_AFTER, context.event).then(()=>{
2036
- if (context.event.dispatched) {
2037
- context.step = RouterPipelineStep.FINISH;
2038
- } else {
2039
- context.step = RouterPipelineStep.LOOKUP;
2040
- }
2041
- return this.executePipelineStep(context);
2042
- });
2043
- }
2044
- async executePipelineStepChildDispatch(context) {
2045
- if (context.event.dispatched || typeof this.stack[context.stackIndex] === 'undefined') {
2046
- context.step = RouterPipelineStep.FINISH;
2047
- return this.executePipelineStep(context);
2048
- }
2049
- try {
2050
- await this.stack[context.stackIndex].dispatch(context.event);
2051
- } catch (e) {
2052
- context.event.error = e;
2053
- await this.hookManager.trigger(HookName.ERROR, context.event);
2054
- }
2055
- context.stackIndex++;
2056
- context.step++;
2057
- return this.executePipelineStep(context);
2058
- }
2059
- async executePipelineStepFinish(context) {
2060
- if (context.event.error || context.event.dispatched) {
2061
- return this.hookManager.trigger(HookName.DISPATCH_END, context.event);
2062
- }
2063
- if (!context.event.dispatched && context.event.routerPath.length === 1 && context.event.method && context.event.method === MethodName.OPTIONS) {
2064
- if (context.event.methodsAllowed.indexOf(MethodName.GET) !== -1) {
2065
- context.event.methodsAllowed.push(MethodName.HEAD);
2066
- }
2067
- distinctArray(context.event.methodsAllowed);
2068
- const options = context.event.methodsAllowed.map((key)=>key.toUpperCase()).join(',');
2069
- context.event.response.setHeader(HeaderName.ALLOW, options);
2070
- await send(context.event.response, options);
2071
- context.event.dispatched = true;
2072
- }
2073
- return this.hookManager.trigger(HookName.DISPATCH_END, context.event);
2074
- }
2075
- // --------------------------------------------------
2076
- async dispatch(event) {
2077
- if (this.pathMatcher) {
2078
- const output = this.pathMatcher.exec(event.path);
2079
- if (typeof output !== 'undefined') {
2080
- event.mountPath = cleanDoubleSlashes(`${event.mountPath}/${output.path}`);
2081
- if (event.path === output.path) {
2082
- event.path = '/';
2083
- } else {
2084
- event.path = withLeadingSlash(event.path.substring(output.path.length));
2085
- }
2086
- event.params = {
2087
- ...event.params,
2088
- ...output.params
2089
- };
2090
- }
2091
- }
2092
- const context = {
2093
- step: RouterPipelineStep.START,
2094
- event,
2095
- stackIndex: 0
2096
- };
2097
- event.routerPath.push(this.id);
2098
- return this.executePipelineStepStart(context).then(()=>{
2099
- context.event.routerPath.pop();
2100
- });
2101
- }
2102
- delete(...input) {
2103
- this.useForMethod(MethodName.DELETE, ...input);
2104
- return this;
2105
- }
2106
- get(...input) {
2107
- this.useForMethod(MethodName.GET, ...input);
2108
- return this;
2109
- }
2110
- post(...input) {
2111
- this.useForMethod(MethodName.POST, ...input);
2112
- return this;
2113
- }
2114
- put(...input) {
2115
- this.useForMethod(MethodName.PUT, ...input);
2116
- return this;
2117
- }
2118
- patch(...input) {
2119
- this.useForMethod(MethodName.PATCH, ...input);
2120
- return this;
2121
- }
2122
- head(...input) {
2123
- this.useForMethod(MethodName.HEAD, ...input);
2124
- return this;
2125
- }
2126
- options(...input) {
2127
- this.useForMethod(MethodName.OPTIONS, ...input);
2128
- return this;
2129
- }
2130
- // --------------------------------------------------
2131
- useForMethod(method, ...input) {
2132
- let path;
2133
- for(let i = 0; i < input.length; i++){
2134
- const element = input[i];
2135
- if (isPath(element)) {
2136
- path = element;
2137
- continue;
2138
- }
2139
- if (isHandlerConfig(element)) {
2140
- if (path) {
2141
- element.path = path;
2142
- }
2143
- element.method = method;
2144
- this.use(element);
2145
- continue;
2146
- }
2147
- if (isHandler(element)) {
2148
- if (path) {
2149
- element.setPath(path);
2150
- }
2151
- element.setMethod(method);
2152
- this.use(element);
2153
- }
2154
- }
2155
- }
2156
- use(...input) {
2157
- let path;
2158
- for(let i = 0; i < input.length; i++){
2159
- const item = input[i];
2160
- if (isPath(item)) {
2161
- path = withLeadingSlash(item);
2162
- continue;
2163
- }
2164
- if (isRouterInstance(item)) {
2165
- if (path) {
2166
- item.setPath(path);
2167
- }
2168
- this.stack.push(item);
2169
- continue;
2170
- }
2171
- if (isHandlerConfig(item)) {
2172
- item.path = path || item.path;
2173
- this.stack.push(new Handler(item));
2174
- continue;
2175
- }
2176
- if (isHandler(item)) {
2177
- item.setPath(path || item.path);
2178
- this.stack.push(item);
2179
- continue;
2180
- }
2181
- if (isPlugin(item)) {
2182
- if (path) {
2183
- this.install(item, {
2184
- path
2185
- });
2186
- } else {
2187
- this.install(item);
2188
- }
2189
- }
2190
- }
2191
- return this;
2192
- }
2193
- // --------------------------------------------------
2194
- install(plugin, context = {}) {
2195
- const name = context.name || plugin.name;
2196
- const router = new Router({
2197
- name
2198
- });
2199
- plugin.install(router);
2200
- if (context.path) {
2201
- this.use(context.path, router);
2202
- } else {
2203
- this.use(router);
2204
- }
2205
- return this;
2206
- }
2207
- on(name, fn) {
2208
- return this.hookManager.addListener(name, fn);
2209
- }
2210
- off(name, fn) {
2211
- if (typeof fn === 'undefined') {
2212
- this.hookManager.removeListener(name);
2213
- return this;
2214
- }
2215
- this.hookManager.removeListener(name, fn);
2216
- return this;
2217
- }
2218
- // --------------------------------------------------
2219
- constructor(options = {}){
2220
- this['@instanceof'] = RouterSymbol;
2221
- /**
2222
- * Array of mounted layers, routes & routers.
2223
- *
2224
- * @protected
2225
- */ this.stack = [];
2226
- this.id = generateRouterID();
2227
- this.name = options.name;
2228
- this.hookManager = new HookManager();
2229
- this.setPath(options.path);
2230
- setRouterOptions(this.id, transformRouterOptions(options));
2231
- }
2232
- }
2233
-
2234
- export { DispatchErrorEvent, DispatchEvent, EventStream, Handler, HandlerSymbol, HandlerType, HeaderName, MethodName, PathMatcher, Router, RoutupError, appendResponseHeader, appendResponseHeaderDirective, coreHandler, createError, createEventStream, createNodeDispatcher, createRawDispatcher, createRequest, createResponse, createWebDispatcher, dispatch, dispatchNodeRequest, dispatchRawRequest, dispatchWebRequest, errorHandler, getRequestAcceptableCharset, getRequestAcceptableCharsets, getRequestAcceptableContentType, getRequestAcceptableContentTypes, getRequestAcceptableEncoding, getRequestAcceptableEncodings, getRequestAcceptableLanguage, getRequestAcceptableLanguages, getRequestHeader, getRequestHostName, getRequestIP, getRequestProtocol, isDispatcherErrorEvent, isError, isHandler, isHandlerConfig, isPath, isPlugin, isRequestCacheable, isRequestHTTP2, isResponseGone, matchRequestContentType, send, sendAccepted, sendCreated, sendFile, sendFormat, sendRedirect, sendStream, sendWebBlob, sendWebResponse, setRequestEnv, setRequestHeader, setRequestMountPath, setRequestParam, setRequestParams, setRequestRouterPath, setResponseCacheHeaders, setResponseContentTypeByFileName, setResponseGone, setResponseHeaderAttachment, setResponseHeaderContentType, transformHeaderToTuples, transformHeadersToTuples, unsetRequestEnv, useRequestEnv, useRequestMountPath, useRequestNegotiator, useRequestParam, useRequestParams, useRequestPath, useRequestRouterPath };
2235
- //# sourceMappingURL=index.mjs.map