routup 0.14.2 → 1.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +9 -3
  2. package/dist/config/index.d.ts +2 -0
  3. package/dist/config/module.d.ts +8 -0
  4. package/dist/config/type.d.ts +34 -0
  5. package/dist/constants.d.ts +39 -0
  6. package/dist/handler/index.d.ts +0 -1
  7. package/dist/handler/utils.d.ts +1 -2
  8. package/dist/helpers/index.d.ts +3 -0
  9. package/dist/helpers/request/body.d.ts +5 -0
  10. package/dist/helpers/request/cache.d.ts +2 -0
  11. package/dist/helpers/request/cookie.d.ts +8 -0
  12. package/dist/helpers/request/env.d.ts +6 -0
  13. package/dist/helpers/request/header-accept-charset.d.ts +3 -0
  14. package/dist/helpers/request/header-accept-encoding.d.ts +4 -0
  15. package/dist/helpers/request/header-accept-language.d.ts +3 -0
  16. package/dist/helpers/request/header-accept.d.ts +3 -0
  17. package/dist/helpers/request/header-content-type.d.ts +2 -0
  18. package/dist/helpers/request/header.d.ts +5 -0
  19. package/dist/helpers/request/hostname.d.ts +7 -0
  20. package/dist/helpers/request/index.d.ts +18 -0
  21. package/dist/helpers/request/ip.d.ts +7 -0
  22. package/dist/helpers/request/mount-path.d.ts +3 -0
  23. package/dist/helpers/request/negotiator.d.ts +3 -0
  24. package/dist/helpers/request/params.d.ts +5 -0
  25. package/dist/helpers/request/path.d.ts +2 -0
  26. package/dist/helpers/request/protocol.d.ts +8 -0
  27. package/dist/helpers/request/query.d.ts +8 -0
  28. package/dist/helpers/response/cache.d.ts +7 -0
  29. package/dist/helpers/response/header-attachment.d.ts +2 -0
  30. package/dist/helpers/response/header-content-type.d.ts +2 -0
  31. package/dist/helpers/response/header.d.ts +5 -0
  32. package/dist/helpers/response/index.d.ts +12 -0
  33. package/dist/helpers/response/send-accepted.d.ts +2 -0
  34. package/dist/helpers/response/send-created.d.ts +2 -0
  35. package/dist/helpers/response/send-file.d.ts +9 -0
  36. package/dist/helpers/response/send-format.d.ts +6 -0
  37. package/dist/helpers/response/send-redirect.d.ts +2 -0
  38. package/dist/helpers/response/send-stream.d.ts +4 -0
  39. package/dist/helpers/response/send.d.ts +2 -0
  40. package/dist/helpers/response/utils.d.ts +3 -0
  41. package/dist/helpers/type.d.ts +3 -0
  42. package/dist/index.cjs +1085 -35
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.d.ts +3 -2
  45. package/dist/index.mjs +991 -4
  46. package/dist/index.mjs.map +1 -1
  47. package/dist/layer/index.d.ts +0 -1
  48. package/dist/layer/module.d.ts +1 -3
  49. package/dist/layer/type.d.ts +0 -1
  50. package/dist/layer/utils.d.ts +0 -1
  51. package/dist/path/index.d.ts +0 -1
  52. package/dist/path/matcher.d.ts +0 -1
  53. package/dist/path/type.d.ts +0 -1
  54. package/dist/route/index.d.ts +0 -1
  55. package/dist/route/module.d.ts +2 -4
  56. package/dist/route/type.d.ts +0 -1
  57. package/dist/route/utils.d.ts +0 -1
  58. package/dist/router/index.d.ts +0 -1
  59. package/dist/router/module.d.ts +1 -3
  60. package/dist/router/type.d.ts +0 -1
  61. package/dist/type.d.ts +9 -1
  62. package/dist/utils/etag/index.d.ts +2 -0
  63. package/dist/utils/etag/module.d.ts +12 -0
  64. package/dist/utils/etag/type.d.ts +16 -0
  65. package/dist/utils/etag/utils.d.ts +2 -0
  66. package/dist/utils/index.d.ts +5 -1
  67. package/dist/utils/is-instance.d.ts +0 -1
  68. package/dist/utils/mime.d.ts +2 -0
  69. package/dist/utils/object.d.ts +1 -0
  70. package/dist/utils/path.d.ts +0 -1
  71. package/dist/utils/promise.d.ts +0 -1
  72. package/dist/utils/request.d.ts +1 -2
  73. package/dist/utils/trust-proxy/index.d.ts +2 -0
  74. package/dist/utils/trust-proxy/module.d.ts +2 -0
  75. package/dist/utils/trust-proxy/type.d.ts +2 -0
  76. package/dist/utils/url.d.ts +7 -0
  77. package/package.json +30 -13
  78. package/dist/handler/index.d.ts.map +0 -1
  79. package/dist/handler/utils.d.ts.map +0 -1
  80. package/dist/index.d.ts.map +0 -1
  81. package/dist/layer/index.d.ts.map +0 -1
  82. package/dist/layer/module.d.ts.map +0 -1
  83. package/dist/layer/type.d.ts.map +0 -1
  84. package/dist/layer/utils.d.ts.map +0 -1
  85. package/dist/path/index.d.ts.map +0 -1
  86. package/dist/path/matcher.d.ts.map +0 -1
  87. package/dist/path/type.d.ts.map +0 -1
  88. package/dist/route/index.d.ts.map +0 -1
  89. package/dist/route/module.d.ts.map +0 -1
  90. package/dist/route/type.d.ts.map +0 -1
  91. package/dist/route/utils.d.ts.map +0 -1
  92. package/dist/router/index.d.ts.map +0 -1
  93. package/dist/router/module.d.ts.map +0 -1
  94. package/dist/router/type.d.ts.map +0 -1
  95. package/dist/type.d.ts.map +0 -1
  96. package/dist/utils/index.d.ts.map +0 -1
  97. package/dist/utils/is-instance.d.ts.map +0 -1
  98. package/dist/utils/path.d.ts.map +0 -1
  99. package/dist/utils/promise.d.ts.map +0 -1
  100. package/dist/utils/request.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,10 +1,110 @@
1
- import { send, setRequestParams, setRequestMountPath, Method, withLeadingSlash, withoutTrailingSlash, useRequestPath, cleanDoubleSlashes, HeaderName } from '@routup/core';
2
- export * from '@routup/core';
3
- import { isObject, hasOwnProperty, merge, mergeArrays } from 'smob';
1
+ import { Continu } from 'continu';
2
+ import process from 'node:process';
3
+ import zod from 'zod';
4
+ import { merge, hasOwnProperty, mergeArrays } from 'smob';
5
+ import crypto from 'node:crypto';
6
+ import { Stats, stat, createReadStream } from 'node:fs';
7
+ import proxyAddr from 'proxy-addr';
8
+ import { getType, get } from 'mime-explorer';
4
9
  import { GatewayTimeoutErrorOptions, BadRequestError } from '@ebec/http';
10
+ import Negotiator from 'negotiator';
11
+ import { URL } from 'node:url';
12
+ import path from 'node:path';
5
13
  import { pathToRegexp } from 'path-to-regexp';
6
14
  import { createServer } from 'node:http';
7
15
 
16
+ /*
17
+ * Copyright (c) 2022-2023.
18
+ * Author Peter Placzek (tada5hi)
19
+ * For the full copyright and license information,
20
+ * view the LICENSE file that was distributed with this source code.
21
+ */ function isObject(item) {
22
+ return !!item && typeof item === 'object' && !Array.isArray(item);
23
+ }
24
+
25
+ /**
26
+ * Determine if object is a Stats object.
27
+ *
28
+ * @param {object} obj
29
+ * @return {boolean}
30
+ * @api private
31
+ */ function isStatsObject(obj) {
32
+ // genuine fs.Stats
33
+ if (typeof Stats === 'function' && obj instanceof Stats) {
34
+ return true;
35
+ }
36
+ // quack quack
37
+ return !!obj && typeof obj === 'object' && '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';
38
+ }
39
+ /**
40
+ * Generate an ETag.
41
+ */ function generateETag(input) {
42
+ if (isStatsObject(input)) {
43
+ const mtime = input.mtime.getTime().toString(16);
44
+ const size = input.size.toString(16);
45
+ return `"${size}-${mtime}"`;
46
+ }
47
+ if (input.length === 0) {
48
+ // fast-path empty
49
+ return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
50
+ }
51
+ const entity = Buffer.isBuffer(input) ? input.toString('utf-8') : input;
52
+ // compute hash of entity
53
+ const hash = crypto.createHash('sha1').update(entity, 'utf8').digest('base64').substring(0, 27);
54
+ return `"${entity.length.toString(16)}-${hash}"`;
55
+ }
56
+ /**
57
+ * Create a simple ETag.
58
+ */ function createEtag(input, options) {
59
+ options = options || {};
60
+ const weak = typeof options.weak === 'boolean' ? options.weak : isStatsObject(input);
61
+ // generate entity tag
62
+ const tag = generateETag(input);
63
+ return weak ? `W/${tag}` : tag;
64
+ }
65
+
66
+ function buildEtagFn(input) {
67
+ if (typeof input === 'function') {
68
+ return input;
69
+ }
70
+ input = input ?? true;
71
+ if (input === false) {
72
+ return ()=>undefined;
73
+ }
74
+ let options = {
75
+ weak: true
76
+ };
77
+ if (isObject(input)) {
78
+ options = merge(input, options);
79
+ }
80
+ return (body, encoding, size)=>{
81
+ const buff = Buffer.isBuffer(body) ? body : Buffer.from(body, encoding);
82
+ if (typeof options.threshold !== 'undefined') {
83
+ size = size ?? Buffer.byteLength(buff);
84
+ if (size <= options.threshold) {
85
+ return undefined;
86
+ }
87
+ }
88
+ return createEtag(buff, options);
89
+ };
90
+ }
91
+
92
+ function buildTrustProxyFn(input) {
93
+ if (typeof input === 'function') {
94
+ return input;
95
+ }
96
+ if (input === true) {
97
+ return ()=>true;
98
+ }
99
+ if (typeof input === 'number') {
100
+ return (_address, hop)=>hop < input;
101
+ }
102
+ if (typeof input === 'string') {
103
+ input = input.split(',').map((value)=>value.trim());
104
+ }
105
+ return proxyAddr.compile(input || []);
106
+ }
107
+
8
108
  /*
9
109
  * Copyright (c) 2022-2022.
10
110
  * Author Peter Placzek (tada5hi)
@@ -14,6 +114,23 @@ import { createServer } from 'node:http';
14
114
  return typeof input === 'object' && input !== null && input['@instanceof'] === Symbol.for(name);
15
115
  }
16
116
 
117
+ function getMimeType(type) {
118
+ if (type.indexOf('/') !== -1) {
119
+ return type;
120
+ }
121
+ return getType(type);
122
+ }
123
+ function getCharsetForMimeType(type) {
124
+ if (/^text\/|^application\/(javascript|json)/.test(type)) {
125
+ return 'utf-8';
126
+ }
127
+ const meta = get(type);
128
+ if (meta && meta.charset) {
129
+ return meta.charset.toLowerCase();
130
+ }
131
+ return undefined;
132
+ }
133
+
17
134
  /*
18
135
  * Copyright (c) 2022.
19
136
  * Author Peter Placzek (tada5hi)
@@ -49,6 +166,876 @@ function isPromise(p) {
49
166
  });
50
167
  }
51
168
 
169
+ /*
170
+ * Copyright (c) 2022-2023.
171
+ * Author Peter Placzek (tada5hi)
172
+ * For the full copyright and license information,
173
+ * view the LICENSE file that was distributed with this source code.
174
+ */ const TRAILING_SLASH_RE = /\/$|\/\?/;
175
+ function hasTrailingSlash(input = '', queryParams = false) {
176
+ if (!queryParams) {
177
+ return input.endsWith('/');
178
+ }
179
+ return TRAILING_SLASH_RE.test(input);
180
+ }
181
+ function withoutTrailingSlash(input = '', queryParams = false) {
182
+ if (!queryParams) {
183
+ return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || '/';
184
+ }
185
+ if (!hasTrailingSlash(input, true)) {
186
+ return input || '/';
187
+ }
188
+ const [s0, ...s] = input.split('?');
189
+ return (s0.slice(0, -1) || '/') + (s.length ? `?${s.join('?')}` : '');
190
+ }
191
+ function withTrailingSlash(input = '', queryParams = false) {
192
+ if (!queryParams) {
193
+ return input.endsWith('/') ? input : `${input}/`;
194
+ }
195
+ if (hasTrailingSlash(input, true)) {
196
+ return input || '/';
197
+ }
198
+ const [s0, ...s] = input.split('?');
199
+ return `${s0}/${s.length ? `?${s.join('?')}` : ''}`;
200
+ }
201
+ function hasLeadingSlash(input = '') {
202
+ return input.startsWith('/');
203
+ }
204
+ function withoutLeadingSlash(input = '') {
205
+ return (hasLeadingSlash(input) ? input.substr(1) : input) || '/';
206
+ }
207
+ function withLeadingSlash(input = '') {
208
+ return hasLeadingSlash(input) ? input : `/${input}`;
209
+ }
210
+ function cleanDoubleSlashes(input = '') {
211
+ return input.split('://').map((str)=>str.replace(/\/{2,}/g, '/')).join('://');
212
+ }
213
+
214
+ let instance;
215
+ function buildConfig() {
216
+ return new Continu({
217
+ defaults: {
218
+ env: process.env.NODE_ENV || 'development',
219
+ trustProxy: ()=>false,
220
+ subdomainOffset: 2,
221
+ etag: buildEtagFn(),
222
+ proxyIpMax: 0
223
+ },
224
+ transformers: {
225
+ etag: (value)=>buildEtagFn(value),
226
+ trustProxy: (value)=>buildTrustProxyFn(value)
227
+ },
228
+ validators: {
229
+ env: (value)=>zod.string().safeParse(value),
230
+ trustProxy: (value)=>zod.any().safeParse(value),
231
+ subdomainOffset: (value)=>zod.number().nonnegative().safeParse(value),
232
+ etag: (value)=>zod.any().safeParse(value),
233
+ proxyIpMax: (value)=>zod.number().nonnegative().safeParse(value)
234
+ }
235
+ });
236
+ }
237
+ function useConfig() {
238
+ if (typeof instance !== 'undefined') {
239
+ return instance;
240
+ }
241
+ instance = buildConfig();
242
+ return instance;
243
+ }
244
+ function setConfig(config) {
245
+ instance = config;
246
+ }
247
+ function setConfigOption(key, value) {
248
+ const config = useConfig();
249
+ config.setRaw(key, value);
250
+ return config.get();
251
+ }
252
+ function getConfigOption(key) {
253
+ const config = useConfig();
254
+ return config.get(key);
255
+ }
256
+
257
+ /*
258
+ * Copyright (c) 2022-2023.
259
+ * Author Peter Placzek (tada5hi)
260
+ * For the full copyright and license information,
261
+ * view the LICENSE file that was distributed with this source code.
262
+ */ var Method;
263
+ (function(Method) {
264
+ Method["GET"] = 'get';
265
+ Method["POST"] = 'post';
266
+ Method["PUT"] = 'put';
267
+ Method["PATCH"] = 'patch';
268
+ Method["DELETE"] = 'delete';
269
+ Method["OPTIONS"] = 'options';
270
+ Method["HEAD"] = 'head';
271
+ })(Method || (Method = {}));
272
+ var HeaderName;
273
+ (function(HeaderName) {
274
+ HeaderName["ACCEPT"] = 'accept';
275
+ HeaderName["ACCEPT_CHARSET"] = 'accept-charset';
276
+ HeaderName["ACCEPT_ENCODING"] = 'accept-encoding';
277
+ HeaderName["ACCEPT_LANGUAGE"] = 'accept-language';
278
+ HeaderName["ACCEPT_RANGES"] = 'accept-ranges';
279
+ HeaderName["ALLOW"] = 'allow';
280
+ HeaderName["CACHE_CONTROL"] = 'cache-control';
281
+ HeaderName["CONTENT_DISPOSITION"] = 'content-disposition';
282
+ HeaderName["CONTENT_ENCODING"] = 'content-encoding';
283
+ HeaderName["CONTENT_LENGTH"] = 'content-length';
284
+ HeaderName["CONTENT_RANGE"] = 'content-range';
285
+ HeaderName["CONTENT_TYPE"] = 'content-type';
286
+ HeaderName["COOKIE"] = 'cookie';
287
+ HeaderName["ETag"] = 'etag';
288
+ HeaderName["HOST"] = 'host';
289
+ HeaderName["IF_NONE_MATCH"] = 'if-none-match';
290
+ HeaderName["LAST_MODIFIED"] = 'last-modified';
291
+ HeaderName["LOCATION"] = 'location';
292
+ HeaderName["RANGE"] = 'range';
293
+ HeaderName["RATE_LIMIT_LIMIT"] = 'ratelimit-limit';
294
+ HeaderName["RATE_LIMIT_REMAINING"] = 'ratelimit-remaining';
295
+ HeaderName["RATE_LIMIT_RESET"] = 'ratelimit-reset';
296
+ HeaderName["RETRY_AFTER"] = 'retry-after';
297
+ HeaderName["SET_COOKIE"] = 'set-cookie';
298
+ HeaderName["TRANSFER_ENCODING"] = 'transfer-encoding';
299
+ HeaderName["X_FORWARDED_HOST"] = 'x-forwarded-host';
300
+ HeaderName["X_FORWARDED_FOR"] = 'x-forwarded-for';
301
+ HeaderName["X_FORWARDED_PROTO"] = 'x-forwarded-proto';
302
+ })(HeaderName || (HeaderName = {}));
303
+
304
+ const BodySymbol = Symbol.for('ReqBody');
305
+ function useRequestBody(req, key) {
306
+ let body;
307
+ /* istanbul ignore next */ if ('body' in req) {
308
+ body = req.body;
309
+ }
310
+ if (BodySymbol in req) {
311
+ if (body) {
312
+ body = merge({}, req[BodySymbol], body);
313
+ } else {
314
+ body = req[BodySymbol];
315
+ }
316
+ }
317
+ if (body) {
318
+ if (typeof key === 'string') {
319
+ return body[key];
320
+ }
321
+ return body;
322
+ }
323
+ return typeof key === 'string' ? undefined : {};
324
+ }
325
+ function setRequestBody(req, key, value) {
326
+ if (BodySymbol in req) {
327
+ if (typeof key === 'object') {
328
+ if (value) {
329
+ req[BodySymbol] = merge(req[BodySymbol], key);
330
+ } else {
331
+ req[BodySymbol] = key;
332
+ }
333
+ } else {
334
+ req[BodySymbol][key] = value;
335
+ }
336
+ return;
337
+ }
338
+ if (typeof key === 'object') {
339
+ req[BodySymbol] = key;
340
+ return;
341
+ }
342
+ req[BodySymbol] = {
343
+ [key]: value
344
+ };
345
+ }
346
+
347
+ /*
348
+ * Copyright (c) 2022.
349
+ * Author Peter Placzek (tada5hi)
350
+ * For the full copyright and license information,
351
+ * view the LICENSE file that was distributed with this source code.
352
+ */ function isRequestCacheable(req, modifiedTime) {
353
+ const modifiedSince = req.headers['if-modified-since'];
354
+ if (!modifiedSince) {
355
+ return false;
356
+ }
357
+ modifiedTime = typeof modifiedTime === 'string' ? new Date(modifiedTime) : modifiedTime;
358
+ return new Date(modifiedSince) >= modifiedTime;
359
+ }
360
+
361
+ const CookieSymbol = Symbol.for('ReqCookie');
362
+ let requestFn$1;
363
+ function setRequestCookieFn(fn) {
364
+ requestFn$1 = fn;
365
+ }
366
+ function useRequestCookies(req) {
367
+ if (!(CookieSymbol in req) && typeof requestFn$1 !== 'undefined') {
368
+ req[CookieSymbol] = requestFn$1(req);
369
+ }
370
+ if (CookieSymbol in req) {
371
+ return req[CookieSymbol];
372
+ }
373
+ return {};
374
+ }
375
+ function hasRequestCookies(req) {
376
+ return CookieSymbol in req && isObject(req[CookieSymbol]);
377
+ }
378
+ function useRequestCookie(req, name) {
379
+ return useRequestCookies(req)[name];
380
+ }
381
+ function setRequestCookies(req, record, mergeIt) {
382
+ if (CookieSymbol in req) {
383
+ if (mergeIt) {
384
+ req[CookieSymbol] = merge(req[CookieSymbol], record);
385
+ }
386
+ return;
387
+ }
388
+ req[CookieSymbol] = record;
389
+ }
390
+
391
+ const envSymbol = Symbol.for('ReqEnv');
392
+ function setRequestEnv(req, key, value) {
393
+ if (envSymbol in req) {
394
+ if (typeof key === 'object') {
395
+ if (value) {
396
+ req[envSymbol] = merge(req[envSymbol], key);
397
+ } else {
398
+ req[envSymbol] = key;
399
+ }
400
+ } else {
401
+ req[envSymbol][key] = value;
402
+ }
403
+ return;
404
+ }
405
+ if (typeof key === 'object') {
406
+ req[envSymbol] = key;
407
+ return;
408
+ }
409
+ req[envSymbol] = {
410
+ [key]: value
411
+ };
412
+ }
413
+ function useRequestEnv(req, key) {
414
+ if (envSymbol in req) {
415
+ if (typeof key === 'string') {
416
+ return req[envSymbol][key];
417
+ }
418
+ return req[envSymbol];
419
+ }
420
+ if (typeof key === 'string') {
421
+ return undefined;
422
+ }
423
+ return {};
424
+ }
425
+ function unsetRequestEnv(req, key) {
426
+ if (envSymbol in req) {
427
+ if (hasOwnProperty(req[envSymbol], key)) {
428
+ delete req[envSymbol][key];
429
+ }
430
+ }
431
+ }
432
+
433
+ /*
434
+ * Copyright (c) 2022.
435
+ * Author Peter Placzek (tada5hi)
436
+ * For the full copyright and license information,
437
+ * view the LICENSE file that was distributed with this source code.
438
+ */ function getRequestHeader(req, name) {
439
+ return req.headers[name];
440
+ }
441
+ function setRequestHeader(req, name, value) {
442
+ req.headers[name] = value;
443
+ }
444
+
445
+ const NegotiatorSymbol = Symbol.for('ReqNegotiator');
446
+ function useRequestNegotiator(req) {
447
+ if (NegotiatorSymbol in req) {
448
+ return req[NegotiatorSymbol];
449
+ }
450
+ return new Negotiator(req);
451
+ }
452
+
453
+ function getRequestAcceptableContentTypes(req) {
454
+ const negotiator = useRequestNegotiator(req);
455
+ return negotiator.mediaTypes();
456
+ }
457
+ function getRequestAcceptableContentType(req, input) {
458
+ input = input || [];
459
+ const items = Array.isArray(input) ? input : [
460
+ input
461
+ ];
462
+ if (items.length === 0) {
463
+ return getRequestAcceptableContentTypes(req).shift();
464
+ }
465
+ const header = getRequestHeader(req, HeaderName.ACCEPT);
466
+ if (!header) {
467
+ return items[0];
468
+ }
469
+ let polluted = false;
470
+ const mimeTypes = [];
471
+ for(let i = 0; i < items.length; i++){
472
+ const mimeType = getMimeType(items[i]);
473
+ if (mimeType) {
474
+ mimeTypes.push(mimeType);
475
+ } else {
476
+ polluted = true;
477
+ }
478
+ }
479
+ const negotiator = useRequestNegotiator(req);
480
+ const matches = negotiator.mediaTypes(mimeTypes);
481
+ if (matches.length > 0) {
482
+ if (polluted) {
483
+ return items[0];
484
+ }
485
+ return items[mimeTypes.indexOf(matches[0])];
486
+ }
487
+ return undefined;
488
+ }
489
+
490
+ function getRequestAcceptableCharsets(req) {
491
+ const negotiator = useRequestNegotiator(req);
492
+ return negotiator.charsets();
493
+ }
494
+ function getRequestAcceptableCharset(req, input) {
495
+ input = input || [];
496
+ const items = Array.isArray(input) ? input : [
497
+ input
498
+ ];
499
+ if (items.length === 0) {
500
+ return getRequestAcceptableCharsets(req).shift();
501
+ }
502
+ const negotiator = useRequestNegotiator(req);
503
+ return negotiator.charsets(items).shift() || undefined;
504
+ }
505
+
506
+ function getRequestAcceptableEncodings(req) {
507
+ const negotiator = useRequestNegotiator(req);
508
+ return negotiator.encodings();
509
+ }
510
+ function getRequestAcceptableEncoding(req, input) {
511
+ input = input || [];
512
+ const items = Array.isArray(input) ? input : [
513
+ input
514
+ ];
515
+ if (items.length === 0) {
516
+ return getRequestAcceptableEncodings(req).shift();
517
+ }
518
+ const negotiator = useRequestNegotiator(req);
519
+ return negotiator.encodings(items).shift() || undefined;
520
+ }
521
+
522
+ function getRequestAcceptableLanguages(req) {
523
+ const negotiator = useRequestNegotiator(req);
524
+ return negotiator.languages();
525
+ }
526
+ function getRequestAcceptableLanguage(req, input) {
527
+ input = input || [];
528
+ const items = Array.isArray(input) ? input : [
529
+ input
530
+ ];
531
+ if (items.length === 0) {
532
+ return getRequestAcceptableLanguages(req).shift();
533
+ }
534
+ const negotiator = useRequestNegotiator(req);
535
+ return negotiator.languages(items).shift() || undefined;
536
+ }
537
+
538
+ function matchRequestContentType(req, contentType) {
539
+ const header = getRequestHeader(req, HeaderName.CONTENT_TYPE);
540
+ if (!header) {
541
+ return true;
542
+ }
543
+ /* istanbul ignore next */ if (Array.isArray(header)) {
544
+ if (header.length === 0) {
545
+ return true;
546
+ }
547
+ return header[0] === getMimeType(contentType);
548
+ }
549
+ return header.split('; ').shift() === getMimeType(contentType);
550
+ }
551
+
552
+ function getRequestHostName(req, options) {
553
+ options = options || {};
554
+ let trustProxy;
555
+ if (typeof options.trustProxy !== 'undefined') {
556
+ trustProxy = buildTrustProxyFn(options.trustProxy);
557
+ } else {
558
+ const config = useConfig();
559
+ trustProxy = config.get('trustProxy');
560
+ }
561
+ let hostname = req.headers[HeaderName.X_FORWARDED_HOST];
562
+ if (!hostname || !req.socket.remoteAddress || !trustProxy(req.socket.remoteAddress, 0)) {
563
+ hostname = req.headers[HeaderName.HOST];
564
+ } else {
565
+ hostname = Array.isArray(hostname) ? hostname.pop() : hostname;
566
+ if (hostname && hostname.indexOf(',') !== -1) {
567
+ hostname = hostname.substring(0, hostname.indexOf(',')).trimEnd();
568
+ }
569
+ }
570
+ if (!hostname) {
571
+ return undefined;
572
+ }
573
+ // IPv6 literal support
574
+ const offset = hostname[0] === '[' ? hostname.indexOf(']') + 1 : 0;
575
+ const index = hostname.indexOf(':', offset);
576
+ return index !== -1 ? hostname.substring(0, index) : hostname;
577
+ }
578
+
579
+ function getRequestIP(req, options) {
580
+ options = options || {};
581
+ let trustProxy;
582
+ if (typeof options.trustProxy !== 'undefined') {
583
+ trustProxy = buildTrustProxyFn(options.trustProxy);
584
+ } else {
585
+ const config = useConfig();
586
+ trustProxy = config.get('trustProxy');
587
+ }
588
+ return proxyAddr(req, trustProxy);
589
+ }
590
+
591
+ /*
592
+ * Copyright (c) 2022.
593
+ * Author Peter Placzek (tada5hi)
594
+ * For the full copyright and license information,
595
+ * view the LICENSE file that was distributed with this source code.
596
+ */ const ReqMountPathSymbol = Symbol.for('ReqMountPath');
597
+ function useRequestMountPath(req) {
598
+ if (ReqMountPathSymbol in req) {
599
+ return req[ReqMountPathSymbol];
600
+ }
601
+ return '/';
602
+ }
603
+ function setRequestMountPath(req, basePath) {
604
+ req[ReqMountPathSymbol] = basePath;
605
+ }
606
+
607
+ /*
608
+ * Copyright (c) 2022.
609
+ * Author Peter Placzek (tada5hi)
610
+ * For the full copyright and license information,
611
+ * view the LICENSE file that was distributed with this source code.
612
+ */ const ParamsSymbol = Symbol.for('ReqParams');
613
+ function useRequestParams(req) {
614
+ if ('params' in req) {
615
+ return req.params;
616
+ }
617
+ if (ParamsSymbol in req) {
618
+ return req[ParamsSymbol];
619
+ }
620
+ return {};
621
+ }
622
+ function useRequestParam(req, key) {
623
+ return useRequestParams(req)[key];
624
+ }
625
+ function setRequestParams(req, data) {
626
+ req[ParamsSymbol] = data;
627
+ }
628
+ function setRequestParam(req, key, value) {
629
+ const params = useRequestParams(req);
630
+ params[key] = value;
631
+ setRequestParams(req, params);
632
+ }
633
+
634
+ function useRequestPath(req) {
635
+ if ('path' in req) {
636
+ return req.path;
637
+ }
638
+ if (typeof req.url === 'undefined') {
639
+ return '/';
640
+ }
641
+ const parsed = new URL(req.url, 'http://localhost/');
642
+ return parsed.pathname;
643
+ }
644
+
645
+ function getRequestProtocol(req, options) {
646
+ options = options || {};
647
+ let trustProxy;
648
+ if (typeof options.trustProxy !== 'undefined') {
649
+ trustProxy = buildTrustProxyFn(options.trustProxy);
650
+ } else {
651
+ const config = useConfig();
652
+ trustProxy = config.get('trustProxy');
653
+ }
654
+ let protocol = options.default;
655
+ /* istanbul ignore next */ if (hasOwnProperty(req.socket, 'encrypted') && !!req.socket.encrypted) {
656
+ protocol = 'https';
657
+ } else if (!protocol) {
658
+ protocol = 'http';
659
+ }
660
+ if (!req.socket.remoteAddress || !trustProxy(req.socket.remoteAddress, 0)) {
661
+ return protocol;
662
+ }
663
+ let header = req.headers[HeaderName.X_FORWARDED_PROTO];
664
+ /* istanbul ignore next */ if (Array.isArray(header)) {
665
+ header = header.pop();
666
+ }
667
+ if (!header) {
668
+ return protocol;
669
+ }
670
+ const index = header.indexOf(',');
671
+ return index !== -1 ? header.substring(0, index).trim() : header.trim();
672
+ }
673
+
674
+ const QuerySymbol = Symbol.for('ReqQuery');
675
+ let requestFn;
676
+ function setRequestQueryFn(fn) {
677
+ requestFn = fn;
678
+ }
679
+ function useRequestQuery(req, key) {
680
+ /* istanbul ignore if */ if ('query' in req) {
681
+ if (typeof key === 'string') {
682
+ return req.query[key];
683
+ }
684
+ return req.query;
685
+ }
686
+ if (!(QuerySymbol in req) && typeof requestFn !== 'undefined') {
687
+ req[QuerySymbol] = requestFn(req);
688
+ }
689
+ if (QuerySymbol in req) {
690
+ if (typeof key === 'string') {
691
+ return req[QuerySymbol][key];
692
+ }
693
+ return req[QuerySymbol];
694
+ }
695
+ return {};
696
+ }
697
+ function hasRequestQuery(req) {
698
+ return QuerySymbol in req && isObject(req[QuerySymbol]);
699
+ }
700
+ function setRequestQuery(req, key, value) {
701
+ if (QuerySymbol in req) {
702
+ if (typeof key === 'object') {
703
+ if (value) {
704
+ req[QuerySymbol] = merge(req[QuerySymbol], key);
705
+ } else {
706
+ req[QuerySymbol] = key;
707
+ }
708
+ } else {
709
+ req[QuerySymbol][key] = value;
710
+ }
711
+ return;
712
+ }
713
+ if (typeof key === 'object') {
714
+ req[QuerySymbol] = key;
715
+ return;
716
+ }
717
+ req[QuerySymbol] = {
718
+ [key]: value
719
+ };
720
+ }
721
+
722
+ /*
723
+ * Copyright (c) 2022.
724
+ * Author Peter Placzek (tada5hi)
725
+ * For the full copyright and license information,
726
+ * view the LICENSE file that was distributed with this source code.
727
+ */ function setResponseCacheHeaders(res, options) {
728
+ options = options || {};
729
+ const cacheControls = [
730
+ 'public'
731
+ ].concat(options.cacheControls || []);
732
+ if (options.maxAge !== undefined) {
733
+ cacheControls.push(`max-age=${+options.maxAge}`, `s-maxage=${+options.maxAge}`);
734
+ }
735
+ if (options.modifiedTime) {
736
+ const modifiedTime = typeof options.modifiedTime === 'string' ? new Date(options.modifiedTime) : options.modifiedTime;
737
+ res.setHeader('last-modified', modifiedTime.toUTCString());
738
+ }
739
+ res.setHeader('cache-control', cacheControls.join(', '));
740
+ }
741
+
742
+ /*
743
+ * Copyright (c) 2022.
744
+ * Author Peter Placzek (tada5hi)
745
+ * For the full copyright and license information,
746
+ * view the LICENSE file that was distributed with this source code.
747
+ */ function appendResponseHeader(res, name, value) {
748
+ let header = res.getHeader(name);
749
+ if (!header) {
750
+ res.setHeader(name, value);
751
+ return;
752
+ }
753
+ if (!Array.isArray(header)) {
754
+ header = [
755
+ header.toString()
756
+ ];
757
+ }
758
+ res.setHeader(name, [
759
+ ...header,
760
+ value
761
+ ]);
762
+ }
763
+ function appendResponseHeaderDirective(res, name, value) {
764
+ let header = res.getHeader(name);
765
+ if (!header) {
766
+ if (Array.isArray(value)) {
767
+ res.setHeader(name, value.join('; '));
768
+ return;
769
+ }
770
+ res.setHeader(name, value);
771
+ return;
772
+ }
773
+ if (!Array.isArray(header)) {
774
+ if (typeof header === 'string') {
775
+ // split header by directive(s)
776
+ header = header.split('; ');
777
+ }
778
+ if (typeof header === 'number') {
779
+ header = [
780
+ header.toString()
781
+ ];
782
+ }
783
+ }
784
+ if (Array.isArray(value)) {
785
+ header.push(...value);
786
+ } else {
787
+ header.push(`${value}`);
788
+ }
789
+ header = [
790
+ ...new Set(header)
791
+ ];
792
+ res.setHeader(name, header.join('; '));
793
+ }
794
+
795
+ function setResponseContentTypeByFileName(res, fileName) {
796
+ const ext = path.extname(fileName);
797
+ if (ext) {
798
+ let type = getMimeType(ext.substring(1));
799
+ if (type) {
800
+ const charset = getCharsetForMimeType(type);
801
+ if (charset) {
802
+ type += `; charset=${charset}`;
803
+ }
804
+ res.setHeader(HeaderName.CONTENT_TYPE, type);
805
+ }
806
+ }
807
+ }
808
+ function onResponseFinished(res, cb) {
809
+ let called;
810
+ const callCallback = (err)=>{
811
+ if (called) return;
812
+ called = true;
813
+ cb(err);
814
+ };
815
+ res.on('finish', async ()=>{
816
+ callCallback();
817
+ });
818
+ res.on('close', async ()=>{
819
+ callCallback();
820
+ });
821
+ res.on('error', async (err)=>{
822
+ callCallback(err);
823
+ });
824
+ }
825
+
826
+ function setResponseHeaderAttachment(res, filename) {
827
+ if (typeof filename === 'string') {
828
+ setResponseContentTypeByFileName(res, filename);
829
+ }
830
+ res.setHeader(HeaderName.CONTENT_DISPOSITION, `attachment${filename ? `; filename="${filename}"` : ''}`);
831
+ }
832
+
833
+ function setResponseHeaderContentType(res, input, ifNotExists) {
834
+ if (ifNotExists) {
835
+ const header = res.getHeader(HeaderName.CONTENT_TYPE);
836
+ if (header) {
837
+ return;
838
+ }
839
+ }
840
+ const contentType = getMimeType(input);
841
+ if (contentType) {
842
+ res.setHeader(HeaderName.CONTENT_TYPE, contentType);
843
+ }
844
+ }
845
+
846
+ function send(res, chunk) {
847
+ switch(typeof chunk){
848
+ case 'string':
849
+ {
850
+ setResponseHeaderContentType(res, 'html', true);
851
+ break;
852
+ }
853
+ case 'boolean':
854
+ case 'number':
855
+ case 'object':
856
+ {
857
+ if (chunk === null) {
858
+ chunk = '';
859
+ } else if (Buffer.isBuffer(chunk)) {
860
+ setResponseHeaderContentType(res, 'bin', true);
861
+ } else {
862
+ chunk = JSON.stringify(chunk);
863
+ setResponseHeaderContentType(res, 'application/json', true);
864
+ }
865
+ break;
866
+ }
867
+ }
868
+ let encoding;
869
+ if (typeof chunk === 'string') {
870
+ res.setHeader(HeaderName.CONTENT_ENCODING, 'utf-8');
871
+ appendResponseHeaderDirective(res, HeaderName.CONTENT_TYPE, 'charset=utf-8');
872
+ encoding = 'utf-8';
873
+ }
874
+ // populate Content-Length
875
+ let len;
876
+ if (chunk !== undefined) {
877
+ if (Buffer.isBuffer(chunk)) {
878
+ // get length of Buffer
879
+ len = chunk.length;
880
+ } else if (chunk.length < 1000) {
881
+ // just calculate length when no ETag + small chunk
882
+ len = Buffer.byteLength(chunk, encoding);
883
+ } else {
884
+ // convert chunk to Buffer and calculate
885
+ chunk = Buffer.from(chunk, encoding);
886
+ encoding = undefined;
887
+ len = chunk.length;
888
+ }
889
+ res.setHeader(HeaderName.CONTENT_LENGTH, `${len}`);
890
+ }
891
+ const config = useConfig();
892
+ const etagFn = config.get('etag');
893
+ if (typeof len !== 'undefined') {
894
+ const chunkHash = etagFn(chunk, encoding, len);
895
+ if (typeof chunkHash === 'string') {
896
+ res.setHeader(HeaderName.ETag, chunkHash);
897
+ if (res.req.headers[HeaderName.IF_NONE_MATCH] === chunkHash) {
898
+ res.statusCode = 304;
899
+ }
900
+ }
901
+ }
902
+ // strip irrelevant headers
903
+ if (res.statusCode === 204 || res.statusCode === 304) {
904
+ res.removeHeader(HeaderName.CONTENT_TYPE);
905
+ res.removeHeader(HeaderName.CONTENT_LENGTH);
906
+ res.removeHeader(HeaderName.TRANSFER_ENCODING);
907
+ chunk = '';
908
+ }
909
+ // alter headers for 205
910
+ if (res.statusCode === 205) {
911
+ res.setHeader(HeaderName.CONTENT_LENGTH, 0);
912
+ res.removeHeader(HeaderName.TRANSFER_ENCODING);
913
+ chunk = '';
914
+ }
915
+ if (res.req.method === 'HEAD') {
916
+ // skip body for HEAD
917
+ res.end();
918
+ return;
919
+ }
920
+ if (typeof encoding !== 'undefined') {
921
+ res.end(chunk, encoding);
922
+ return;
923
+ }
924
+ res.end(chunk);
925
+ }
926
+
927
+ function sendAccepted(res, chunk) {
928
+ res.statusCode = 202;
929
+ res.statusMessage = 'Accepted';
930
+ return send(res, chunk);
931
+ }
932
+
933
+ function sendCreated(res, chunk) {
934
+ res.statusCode = 201;
935
+ res.statusMessage = 'Created';
936
+ return send(res, chunk);
937
+ }
938
+
939
+ /*
940
+ * Copyright (c) 2022.
941
+ * Author Peter Placzek (tada5hi)
942
+ * For the full copyright and license information,
943
+ * view the LICENSE file that was distributed with this source code.
944
+ */ function sendStream(res, stream, fn) {
945
+ stream.on('open', ()=>{
946
+ stream.pipe(res);
947
+ });
948
+ stream.on('error', (err)=>{
949
+ if (typeof fn === 'function') {
950
+ fn(err);
951
+ } else {
952
+ res.statusCode = 400;
953
+ res.end();
954
+ }
955
+ });
956
+ stream.on('close', ()=>{
957
+ if (typeof fn === 'function') {
958
+ fn();
959
+ } else {
960
+ res.end();
961
+ }
962
+ });
963
+ }
964
+
965
+ function resolveStats(options, cb) {
966
+ if (options.stats) {
967
+ cb(null, options.stats);
968
+ return;
969
+ }
970
+ stat(options.filePath, (err, stats)=>cb(err, stats));
971
+ }
972
+ function sendFile(res, filePath, fn) {
973
+ let options;
974
+ if (typeof filePath === 'string') {
975
+ options = {
976
+ filePath
977
+ };
978
+ } else {
979
+ options = filePath;
980
+ }
981
+ const fileName = path.basename(options.filePath);
982
+ if (options.attachment) {
983
+ const dispositionHeader = res.getHeader(HeaderName.CONTENT_DISPOSITION);
984
+ if (!dispositionHeader) {
985
+ setResponseHeaderAttachment(res, fileName);
986
+ }
987
+ } else {
988
+ setResponseContentTypeByFileName(res, fileName);
989
+ }
990
+ resolveStats(options, (err, stats)=>{
991
+ if (err) {
992
+ if (typeof fn === 'function') {
993
+ fn(err);
994
+ } else {
995
+ res.statusCode = 404;
996
+ res.end();
997
+ }
998
+ return;
999
+ }
1000
+ const streamOptions = {};
1001
+ const rangeHeader = res.req.headers[HeaderName.RANGE];
1002
+ if (rangeHeader) {
1003
+ const [x, y] = rangeHeader.replace('bytes=', '').split('-');
1004
+ streamOptions.end = Math.min(parseInt(y, 10) || stats.size - 1, stats.size - 1);
1005
+ streamOptions.start = parseInt(x, 10) || 0;
1006
+ if (streamOptions.start >= stats.size || streamOptions.end >= stats.size) {
1007
+ res.setHeader(HeaderName.CONTENT_RANGE, `bytes */${stats.size}`);
1008
+ res.statusCode = 416;
1009
+ res.end();
1010
+ return;
1011
+ }
1012
+ res.setHeader(HeaderName.CONTENT_RANGE, `bytes ${streamOptions.start}-${streamOptions.end}/${stats.size}`);
1013
+ res.setHeader(HeaderName.CONTENT_LENGTH, streamOptions.end - streamOptions.start + 1);
1014
+ } else {
1015
+ res.setHeader(HeaderName.CONTENT_LENGTH, stats.size);
1016
+ }
1017
+ res.setHeader(HeaderName.ACCEPT_RANGES, 'bytes');
1018
+ res.setHeader(HeaderName.LAST_MODIFIED, stats.mtime.toUTCString());
1019
+ res.setHeader(HeaderName.ETag, `W/"${stats.size}-${stats.mtime.getTime()}"`);
1020
+ sendStream(res, createReadStream(options?.filePath, streamOptions), fn);
1021
+ });
1022
+ }
1023
+
1024
+ /*
1025
+ * Copyright (c) 2022.
1026
+ * Author Peter Placzek (tada5hi)
1027
+ * For the full copyright and license information,
1028
+ * view the LICENSE file that was distributed with this source code.
1029
+ */ function sendFormat(_res, _format) {}
1030
+
1031
+ function sendRedirect(res, location, statusCode = 302) {
1032
+ res.statusCode = statusCode;
1033
+ res.setHeader('location', location);
1034
+ const encodedLoc = location.replace(/"/g, '%22');
1035
+ const html = `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`;
1036
+ return send(res, html);
1037
+ }
1038
+
52
1039
  function processHandlerExecutionOutput(res, next, output) {
53
1040
  if (isPromise(output)) {
54
1041
  output.then((r)=>{
@@ -557,5 +1544,5 @@ class Router {
557
1544
  }
558
1545
  }
559
1546
 
560
- export { Layer, PathMatcher, Route, Router, createRequestTimeout, isInstance, isLayerInstance, isPath, isPromise, isRouteInstance, isRouterInstance, processHandlerExecutionOutput };
1547
+ export { HeaderName, Layer, Method, PathMatcher, Route, Router, appendResponseHeader, appendResponseHeaderDirective, buildConfig, buildEtagFn, buildTrustProxyFn, cleanDoubleSlashes, createRequestTimeout, getCharsetForMimeType, getConfigOption, getMimeType, getRequestAcceptableCharset, getRequestAcceptableCharsets, getRequestAcceptableContentType, getRequestAcceptableContentTypes, getRequestAcceptableEncoding, getRequestAcceptableEncodings, getRequestAcceptableLanguage, getRequestAcceptableLanguages, getRequestHeader, getRequestHostName, getRequestIP, getRequestProtocol, hasLeadingSlash, hasRequestCookies, hasRequestQuery, hasTrailingSlash, isInstance, isLayerInstance, isObject, isPath, isPromise, isRequestCacheable, isRouteInstance, isRouterInstance, matchRequestContentType, onResponseFinished, processHandlerExecutionOutput, send, sendAccepted, sendCreated, sendFile, sendFormat, sendRedirect, sendStream, setConfig, setConfigOption, setRequestBody, setRequestCookieFn, setRequestCookies, setRequestEnv, setRequestHeader, setRequestMountPath, setRequestParam, setRequestParams, setRequestQuery, setRequestQueryFn, setResponseCacheHeaders, setResponseContentTypeByFileName, setResponseHeaderAttachment, setResponseHeaderContentType, unsetRequestEnv, useConfig, useRequestBody, useRequestCookie, useRequestCookies, useRequestEnv, useRequestMountPath, useRequestNegotiator, useRequestParam, useRequestParams, useRequestPath, useRequestQuery, withLeadingSlash, withTrailingSlash, withoutLeadingSlash, withoutTrailingSlash };
561
1548
  //# sourceMappingURL=index.mjs.map