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