routup 2.0.0 → 3.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +88 -35
  2. package/dist/dispatcher/adapters/node/module.d.ts +2 -1
  3. package/dist/dispatcher/type.d.ts +8 -6
  4. package/dist/dispatcher/utils.d.ts +2 -1
  5. package/dist/error/create.d.ts +11 -0
  6. package/dist/error/index.d.ts +3 -0
  7. package/dist/error/is.d.ts +2 -0
  8. package/dist/error/module.d.ts +3 -0
  9. package/dist/handler/constants.d.ts +4 -0
  10. package/dist/handler/core/define.d.ts +3 -0
  11. package/dist/handler/core/index.d.ts +2 -0
  12. package/dist/handler/core/types.d.ts +10 -0
  13. package/dist/handler/error/define.d.ts +3 -0
  14. package/dist/handler/error/index.d.ts +2 -0
  15. package/dist/handler/error/types.d.ts +11 -0
  16. package/dist/handler/index.d.ts +6 -0
  17. package/dist/handler/is.d.ts +2 -0
  18. package/dist/handler/types-base.d.ts +6 -0
  19. package/dist/handler/types.d.ts +5 -0
  20. package/dist/index.cjs +732 -695
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.ts +3 -1
  23. package/dist/index.mjs +724 -693
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/layer/constants.d.ts +1 -0
  26. package/dist/layer/module.d.ts +9 -7
  27. package/dist/layer/type.d.ts +6 -3
  28. package/dist/layer/utils.d.ts +1 -1
  29. package/dist/path/matcher.d.ts +4 -4
  30. package/dist/plugin/index.d.ts +2 -0
  31. package/dist/plugin/is.d.ts +2 -0
  32. package/dist/plugin/types.d.ts +32 -0
  33. package/dist/request/helpers/body.d.ts +1 -1
  34. package/dist/request/helpers/cache.d.ts +1 -1
  35. package/dist/request/helpers/cookie.d.ts +1 -1
  36. package/dist/request/helpers/env.d.ts +1 -1
  37. package/dist/request/helpers/header-accept-charset.d.ts +1 -1
  38. package/dist/request/helpers/header-accept-language.d.ts +1 -1
  39. package/dist/request/helpers/header-accept.d.ts +1 -1
  40. package/dist/request/helpers/header-content-type.d.ts +1 -1
  41. package/dist/request/helpers/header.d.ts +1 -1
  42. package/dist/request/helpers/hostname.d.ts +1 -1
  43. package/dist/request/helpers/ip.d.ts +1 -1
  44. package/dist/request/helpers/mount-path.d.ts +1 -1
  45. package/dist/request/helpers/negotiator.d.ts +1 -1
  46. package/dist/request/helpers/params.d.ts +1 -1
  47. package/dist/request/helpers/path.d.ts +1 -1
  48. package/dist/request/helpers/protocol.d.ts +1 -1
  49. package/dist/request/helpers/query.d.ts +1 -1
  50. package/dist/request/helpers/router.d.ts +3 -3
  51. package/dist/request/types.d.ts +4 -0
  52. package/dist/response/helpers/cache.d.ts +1 -1
  53. package/dist/response/helpers/gone.d.ts +1 -1
  54. package/dist/response/helpers/header-attachment.d.ts +1 -1
  55. package/dist/response/helpers/header-content-type.d.ts +1 -1
  56. package/dist/response/helpers/header.d.ts +1 -1
  57. package/dist/response/helpers/send-accepted.d.ts +1 -1
  58. package/dist/response/helpers/send-created.d.ts +1 -1
  59. package/dist/response/helpers/send-file.d.ts +1 -1
  60. package/dist/response/helpers/send-format.d.ts +1 -1
  61. package/dist/response/helpers/send-redirect.d.ts +1 -1
  62. package/dist/response/helpers/send-stream.d.ts +2 -1
  63. package/dist/response/helpers/send-web-blob.d.ts +2 -1
  64. package/dist/response/helpers/send-web-response.d.ts +2 -1
  65. package/dist/response/helpers/send.d.ts +1 -1
  66. package/dist/response/helpers/utils.d.ts +1 -1
  67. package/dist/response/index.d.ts +1 -0
  68. package/dist/response/module.d.ts +2 -1
  69. package/dist/response/types.d.ts +4 -0
  70. package/dist/router/constants.d.ts +1 -0
  71. package/dist/router/index.d.ts +1 -0
  72. package/dist/router/module.d.ts +26 -23
  73. package/dist/router/utils.d.ts +2 -0
  74. package/dist/router-options/module.d.ts +1 -1
  75. package/dist/router-options/type.d.ts +3 -12
  76. package/dist/types.d.ts +0 -9
  77. package/dist/utils/is-instance.d.ts +1 -1
  78. package/package.json +15 -14
  79. package/dist/error.d.ts +0 -1
  80. package/dist/route/index.d.ts +0 -3
  81. package/dist/route/module.d.ts +0 -28
  82. package/dist/route/type.d.ts +0 -6
  83. package/dist/route/utils.d.ts +0 -2
package/dist/index.cjs CHANGED
@@ -1,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ var http = require('@ebec/http');
4
+ var smob = require('smob');
3
5
  var buffer = require('buffer');
4
6
  var uncrypto = require('uncrypto');
5
- var smob = require('smob');
6
7
  var proxyAddr = require('proxy-addr');
7
8
  var mimeExplorer = require('mime-explorer');
8
9
  var Negotiator = require('negotiator');
@@ -11,119 +12,71 @@ var pathToRegexp = require('path-to-regexp');
11
12
 
12
13
  exports.MethodName = void 0;
13
14
  (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';
15
+ MethodName["GET"] = "get";
16
+ MethodName["POST"] = "post";
17
+ MethodName["PUT"] = "put";
18
+ MethodName["PATCH"] = "patch";
19
+ MethodName["DELETE"] = "delete";
20
+ MethodName["OPTIONS"] = "options";
21
+ MethodName["HEAD"] = "head";
21
22
  })(exports.MethodName || (exports.MethodName = {}));
22
23
  exports.HeaderName = void 0;
23
24
  (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["COOKIE"] = 'cookie';
37
- HeaderName["ETag"] = 'etag';
38
- HeaderName["HOST"] = 'host';
39
- HeaderName["IF_MODIFIED_SINCE"] = 'if-modified-since';
40
- HeaderName["IF_NONE_MATCH"] = 'if-none-match';
41
- HeaderName["LAST_MODIFIED"] = 'last-modified';
42
- HeaderName["LOCATION"] = 'location';
43
- HeaderName["RANGE"] = 'range';
44
- HeaderName["RATE_LIMIT_LIMIT"] = 'ratelimit-limit';
45
- HeaderName["RATE_LIMIT_REMAINING"] = 'ratelimit-remaining';
46
- HeaderName["RATE_LIMIT_RESET"] = 'ratelimit-reset';
47
- HeaderName["RETRY_AFTER"] = 'retry-after';
48
- HeaderName["SET_COOKIE"] = 'set-cookie';
49
- HeaderName["TRANSFER_ENCODING"] = 'transfer-encoding';
50
- HeaderName["X_FORWARDED_HOST"] = 'x-forwarded-host';
51
- HeaderName["X_FORWARDED_FOR"] = 'x-forwarded-for';
52
- HeaderName["X_FORWARDED_PROTO"] = 'x-forwarded-proto';
25
+ HeaderName["ACCEPT"] = "accept";
26
+ HeaderName["ACCEPT_CHARSET"] = "accept-charset";
27
+ HeaderName["ACCEPT_ENCODING"] = "accept-encoding";
28
+ HeaderName["ACCEPT_LANGUAGE"] = "accept-language";
29
+ HeaderName["ACCEPT_RANGES"] = "accept-ranges";
30
+ HeaderName["ALLOW"] = "allow";
31
+ HeaderName["CACHE_CONTROL"] = "cache-control";
32
+ HeaderName["CONTENT_DISPOSITION"] = "content-disposition";
33
+ HeaderName["CONTENT_ENCODING"] = "content-encoding";
34
+ HeaderName["CONTENT_LENGTH"] = "content-length";
35
+ HeaderName["CONTENT_RANGE"] = "content-range";
36
+ HeaderName["CONTENT_TYPE"] = "content-type";
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_FORWARDED_HOST"] = "x-forwarded-host";
52
+ HeaderName["X_FORWARDED_FOR"] = "x-forwarded-for";
53
+ HeaderName["X_FORWARDED_PROTO"] = "x-forwarded-proto";
53
54
  })(exports.HeaderName || (exports.HeaderName = {}));
54
55
 
55
- function setResponseCacheHeaders(res, options) {
56
- options = options || {};
57
- const cacheControls = [
58
- 'public'
59
- ].concat(options.cacheControls || []);
60
- if (options.maxAge !== undefined) {
61
- cacheControls.push(`max-age=${+options.maxAge}`, `s-maxage=${+options.maxAge}`);
62
- }
63
- if (options.modifiedTime) {
64
- const modifiedTime = typeof options.modifiedTime === 'string' ? new Date(options.modifiedTime) : options.modifiedTime;
65
- res.setHeader('last-modified', modifiedTime.toUTCString());
66
- }
67
- res.setHeader('cache-control', cacheControls.join(', '));
56
+ class ErrorProxy extends http.HTTPError {
68
57
  }
69
58
 
70
- const GoneSymbol = Symbol.for('ResGone');
71
- function isResponseGone(res) {
72
- if (res.headersSent || res.writableEnded) {
73
- return true;
74
- }
75
- if (GoneSymbol in res) {
76
- return res[GoneSymbol];
77
- }
78
- return false;
59
+ function isError(input) {
60
+ return input instanceof ErrorProxy;
79
61
  }
80
62
 
81
- function appendResponseHeader(res, name, value) {
82
- let header = res.getHeader(name);
83
- if (!header) {
84
- res.setHeader(name, value);
85
- return;
86
- }
87
- if (!Array.isArray(header)) {
88
- header = [
89
- header.toString()
90
- ];
91
- }
92
- res.setHeader(name, [
93
- ...header,
94
- value
95
- ]);
96
- }
97
- function appendResponseHeaderDirective(res, name, value) {
98
- let header = res.getHeader(name);
99
- if (!header) {
100
- if (Array.isArray(value)) {
101
- res.setHeader(name, value.join('; '));
102
- return;
103
- }
104
- res.setHeader(name, value);
105
- return;
106
- }
107
- if (!Array.isArray(header)) {
108
- if (typeof header === 'string') {
109
- // split header by directive(s)
110
- header = header.split('; ');
111
- }
112
- if (typeof header === 'number') {
113
- header = [
114
- header.toString()
115
- ];
116
- }
63
+ /**
64
+ * Create an error proxy by
65
+ * - an existing error (accessible via cause property)
66
+ * - options
67
+ * - message
68
+ *
69
+ * @param input
70
+ */ function createError(input) {
71
+ if (isError(input)) {
72
+ return input;
117
73
  }
118
- if (Array.isArray(value)) {
119
- header.push(...value);
120
- } else {
121
- header.push(`${value}`);
74
+ if (typeof input === 'string') {
75
+ return new ErrorProxy(input);
122
76
  }
123
- header = [
124
- ...new Set(header)
125
- ];
126
- res.setHeader(name, header.join('; '));
77
+ return new ErrorProxy({
78
+ cause: input
79
+ }, input);
127
80
  }
128
81
 
129
82
  /*
@@ -313,8 +266,11 @@ function buildTrustProxyFn(input) {
313
266
  return proxyAddr.compile(input || []);
314
267
  }
315
268
 
316
- function isInstance(input, name) {
317
- return isObject(input) && input['@instanceof'] === Symbol.for(name);
269
+ function isInstance(input, sym) {
270
+ if (!isObject(input)) {
271
+ return false;
272
+ }
273
+ return input['@instanceof'] === sym;
318
274
  }
319
275
 
320
276
  function getMimeType(type) {
@@ -395,7 +351,10 @@ function withLeadingSlash(input = '') {
395
351
  return hasLeadingSlash(input) ? input : `/${input}`;
396
352
  }
397
353
  function cleanDoubleSlashes(input = '') {
398
- return input.split('://').map((str)=>str.replace(/\/{2,}/g, '/')).join('://');
354
+ if (input.indexOf('://') !== -1) {
355
+ return input.split('://').map((str)=>cleanDoubleSlashes(str)).join('://');
356
+ }
357
+ return input.replace(/\/+/g, '/');
399
358
  }
400
359
 
401
360
  function isWebBlob(input) {
@@ -405,67 +364,6 @@ function isWebResponse(input) {
405
364
  return typeof Response !== 'undefined' && input instanceof Response;
406
365
  }
407
366
 
408
- function setResponseContentTypeByFileName(res, fileName) {
409
- const ext = extname(fileName);
410
- if (ext) {
411
- let type = getMimeType(ext.substring(1));
412
- if (type) {
413
- const charset = getCharsetForMimeType(type);
414
- if (charset) {
415
- type += `; charset=${charset}`;
416
- }
417
- res.setHeader(exports.HeaderName.CONTENT_TYPE, type);
418
- }
419
- }
420
- }
421
-
422
- function setResponseHeaderAttachment(res, filename) {
423
- if (typeof filename === 'string') {
424
- setResponseContentTypeByFileName(res, filename);
425
- }
426
- res.setHeader(exports.HeaderName.CONTENT_DISPOSITION, `attachment${filename ? `; filename="${filename}"` : ''}`);
427
- }
428
-
429
- function setResponseHeaderContentType(res, input, ifNotExists) {
430
- if (ifNotExists) {
431
- const header = res.getHeader(exports.HeaderName.CONTENT_TYPE);
432
- if (header) {
433
- return;
434
- }
435
- }
436
- const contentType = getMimeType(input);
437
- if (contentType) {
438
- res.setHeader(exports.HeaderName.CONTENT_TYPE, contentType);
439
- }
440
- }
441
-
442
- const defaults = {
443
- trustProxy: ()=>false,
444
- subdomainOffset: 2,
445
- etag: buildEtagFn(),
446
- proxyIpMax: 0
447
- };
448
- const instances = {};
449
- function setRouterOptions(id, input) {
450
- instances[id] = input;
451
- }
452
- function findRouterOption(key, id) {
453
- if (!id) {
454
- return defaults[key];
455
- }
456
- const ids = Array.isArray(id) ? id : [
457
- id
458
- ];
459
- if (ids.length > 0) {
460
- for(let i = ids.length; i >= 0; i--){
461
- if (smob.hasOwnProperty(instances, ids[i]) && typeof instances[ids[i]][key] !== 'undefined') {
462
- return instances[ids[i]][key];
463
- }
464
- }
465
- }
466
- return defaults[key];
467
- }
468
-
469
367
  const BodySymbol = Symbol.for('ReqBody');
470
368
  function useRequestBody(req, key) {
471
369
  let body;
@@ -727,11 +625,35 @@ function matchRequestContentType(req, contentType) {
727
625
  return header.split('; ').shift() === getMimeType(contentType);
728
626
  }
729
627
 
628
+ const defaults = {
629
+ trustProxy: ()=>false,
630
+ subdomainOffset: 2,
631
+ etag: buildEtagFn(),
632
+ proxyIpMax: 0
633
+ };
634
+ const instances = {};
635
+ function setRouterOptions(id, input) {
636
+ instances[id] = input;
637
+ }
638
+ function findRouterOption(key, path) {
639
+ if (!path || path.length === 0) {
640
+ return defaults[key];
641
+ }
642
+ if (path.length > 0) {
643
+ for(let i = path.length; i >= 0; i--){
644
+ if (smob.hasOwnProperty(instances, path[i]) && typeof instances[path[i]][key] !== 'undefined') {
645
+ return instances[path[i]][key];
646
+ }
647
+ }
648
+ }
649
+ return defaults[key];
650
+ }
651
+
730
652
  const routerSymbol = Symbol.for('ReqRouterID');
731
- function setRequestRouterIds(req, ids) {
732
- req[routerSymbol] = ids;
653
+ function setRequestRouterPath(req, path) {
654
+ req[routerSymbol] = path;
733
655
  }
734
- function useRequestRouterIds(req) {
656
+ function useRequestRouterPath(req) {
735
657
  if (routerSymbol in req) {
736
658
  return req[routerSymbol];
737
659
  }
@@ -744,7 +666,7 @@ function getRequestHostName(req, options) {
744
666
  if (typeof options.trustProxy !== 'undefined') {
745
667
  trustProxy = buildTrustProxyFn(options.trustProxy);
746
668
  } else {
747
- trustProxy = findRouterOption('trustProxy', useRequestRouterIds(req));
669
+ trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
748
670
  }
749
671
  let hostname = req.headers[exports.HeaderName.X_FORWARDED_HOST];
750
672
  if (!hostname || !req.socket.remoteAddress || !trustProxy(req.socket.remoteAddress, 0)) {
@@ -770,7 +692,7 @@ function getRequestIP(req, options) {
770
692
  if (typeof options.trustProxy !== 'undefined') {
771
693
  trustProxy = buildTrustProxyFn(options.trustProxy);
772
694
  } else {
773
- trustProxy = findRouterOption('trustProxy', useRequestRouterIds(req));
695
+ trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
774
696
  }
775
697
  const addrs = proxyAddr.all(req, trustProxy);
776
698
  return addrs[addrs.length - 1];
@@ -831,7 +753,7 @@ function getRequestProtocol(req, options) {
831
753
  if (typeof options.trustProxy !== 'undefined') {
832
754
  trustProxy = buildTrustProxyFn(options.trustProxy);
833
755
  } else {
834
- trustProxy = findRouterOption('trustProxy', useRequestRouterIds(req));
756
+ trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
835
757
  }
836
758
  let protocol = options.default;
837
759
  /* istanbul ignore next */ if (smob.hasOwnProperty(req.socket, 'encrypted') && !!req.socket.encrypted) {
@@ -899,100 +821,280 @@ function extendRequestQuery(req, key, value) {
899
821
  setRequestQuery(req, key, value);
900
822
  }
901
823
 
902
- async function send(res, chunk) {
903
- switch(typeof chunk){
904
- case 'string':
905
- {
906
- setResponseHeaderContentType(res, 'html', true);
907
- break;
908
- }
909
- case 'boolean':
910
- case 'number':
911
- case 'object':
912
- {
913
- if (chunk === null) {
914
- chunk = '';
915
- } else if (buffer.Buffer.isBuffer(chunk)) {
916
- setResponseHeaderContentType(res, 'bin', true);
917
- } else {
918
- chunk = JSON.stringify(chunk);
919
- setResponseHeaderContentType(res, 'application/json', true);
920
- }
921
- break;
922
- }
923
- }
924
- let encoding;
925
- if (typeof chunk === 'string') {
926
- res.setHeader(exports.HeaderName.CONTENT_ENCODING, 'utf-8');
927
- appendResponseHeaderDirective(res, exports.HeaderName.CONTENT_TYPE, 'charset=utf-8');
928
- encoding = 'utf-8';
929
- }
930
- // populate Content-Length
931
- let len;
932
- if (chunk !== undefined) {
933
- if (buffer.Buffer.isBuffer(chunk)) {
934
- // get length of Buffer
935
- len = chunk.length;
936
- } else if (chunk.length < 1000) {
937
- // just calculate length when no ETag + small chunk
938
- len = buffer.Buffer.byteLength(chunk, encoding);
824
+ function createRequest(context) {
825
+ let readable;
826
+ if (context.body) {
827
+ if (isWebStream(context.body)) {
828
+ readable = readableStream.Readable.fromWeb(context.body);
939
829
  } else {
940
- // convert chunk to Buffer and calculate
941
- chunk = buffer.Buffer.from(chunk, encoding);
942
- encoding = undefined;
943
- len = chunk.length;
830
+ readable = readableStream.Readable.from(context.body);
944
831
  }
945
- res.setHeader(exports.HeaderName.CONTENT_LENGTH, `${len}`);
832
+ } else {
833
+ readable = new readableStream.Readable();
946
834
  }
947
- if (typeof len !== 'undefined') {
948
- const etagFn = findRouterOption('etag', useRequestRouterIds(res.req));
949
- const chunkHash = await etagFn(chunk, encoding, len);
950
- if (isResponseGone(res)) {
951
- return Promise.resolve();
952
- }
953
- if (typeof chunkHash === 'string') {
954
- res.setHeader(exports.HeaderName.ETag, chunkHash);
955
- if (res.req.headers[exports.HeaderName.IF_NONE_MATCH] === chunkHash) {
956
- res.statusCode = 304;
835
+ const headers = context.headers || {};
836
+ const rawHeaders = [];
837
+ let keys = Object.keys(headers);
838
+ for(let i = 0; i < keys.length; i++){
839
+ const header = headers[keys[i]];
840
+ if (Array.isArray(header)) {
841
+ for(let j = 0; j < header.length; j++){
842
+ rawHeaders.push(keys[i], header[j]);
957
843
  }
844
+ } else if (typeof header === 'string') {
845
+ rawHeaders.push(keys[i], header);
958
846
  }
959
847
  }
960
- // strip irrelevant headers
961
- if (res.statusCode === 204 || res.statusCode === 304) {
962
- res.removeHeader(exports.HeaderName.CONTENT_TYPE);
963
- res.removeHeader(exports.HeaderName.CONTENT_LENGTH);
964
- res.removeHeader(exports.HeaderName.TRANSFER_ENCODING);
965
- chunk = '';
966
- }
967
- // alter headers for 205
968
- if (res.statusCode === 205) {
969
- res.setHeader(exports.HeaderName.CONTENT_LENGTH, 0);
970
- res.removeHeader(exports.HeaderName.TRANSFER_ENCODING);
971
- chunk = '';
972
- }
973
- if (isResponseGone(res)) {
974
- return Promise.resolve();
975
- }
976
- if (res.req.method === 'HEAD') {
977
- // skip body for HEAD
978
- res.end();
979
- return Promise.resolve();
980
- }
981
- if (typeof encoding !== 'undefined') {
982
- res.end(chunk, encoding);
983
- return Promise.resolve();
848
+ const headersDistinct = {};
849
+ keys = Object.keys(headers);
850
+ for(let i = 0; i < keys.length; i++){
851
+ const header = headers[keys[i]];
852
+ if (Array.isArray(header)) {
853
+ headersDistinct[keys[i]] = header;
854
+ }
855
+ if (typeof header === 'string') {
856
+ headersDistinct[keys[i]] = [
857
+ header
858
+ ];
859
+ }
984
860
  }
985
- res.end(chunk);
986
- return Promise.resolve();
987
- }
988
-
989
- function sendAccepted(res, chunk) {
990
- res.statusCode = 202;
991
- res.statusMessage = 'Accepted';
992
- return send(res, chunk);
993
- }
994
-
995
- function sendCreated(res, chunk) {
861
+ Object.defineProperty(readable, 'connection', {
862
+ get () {
863
+ return {
864
+ remoteAddress: '127.0.0.1'
865
+ };
866
+ }
867
+ });
868
+ Object.defineProperty(readable, 'socket', {
869
+ get () {
870
+ return {
871
+ remoteAddress: '127.0.0.1'
872
+ };
873
+ }
874
+ });
875
+ Object.assign(readable, {
876
+ aborted: false,
877
+ complete: true,
878
+ headers,
879
+ headersDistinct,
880
+ httpVersion: '1.1',
881
+ httpVersionMajor: 1,
882
+ httpVersionMinor: 1,
883
+ method: context.method || 'GET',
884
+ rawHeaders,
885
+ rawTrailers: [],
886
+ trailers: {},
887
+ trailersDistinct: {},
888
+ url: context.url || '/',
889
+ setTimeout (_msecs, _callback) {
890
+ return this;
891
+ }
892
+ });
893
+ return readable;
894
+ }
895
+
896
+ function setResponseCacheHeaders(res, options) {
897
+ options = options || {};
898
+ const cacheControls = [
899
+ 'public'
900
+ ].concat(options.cacheControls || []);
901
+ if (options.maxAge !== undefined) {
902
+ cacheControls.push(`max-age=${+options.maxAge}`, `s-maxage=${+options.maxAge}`);
903
+ }
904
+ if (options.modifiedTime) {
905
+ const modifiedTime = typeof options.modifiedTime === 'string' ? new Date(options.modifiedTime) : options.modifiedTime;
906
+ res.setHeader('last-modified', modifiedTime.toUTCString());
907
+ }
908
+ res.setHeader('cache-control', cacheControls.join(', '));
909
+ }
910
+
911
+ const GoneSymbol = Symbol.for('ResGone');
912
+ function isResponseGone(res) {
913
+ if (res.headersSent || res.writableEnded) {
914
+ return true;
915
+ }
916
+ if (GoneSymbol in res) {
917
+ return res[GoneSymbol];
918
+ }
919
+ return false;
920
+ }
921
+
922
+ function appendResponseHeader(res, name, value) {
923
+ let header = res.getHeader(name);
924
+ if (!header) {
925
+ res.setHeader(name, value);
926
+ return;
927
+ }
928
+ if (!Array.isArray(header)) {
929
+ header = [
930
+ header.toString()
931
+ ];
932
+ }
933
+ res.setHeader(name, [
934
+ ...header,
935
+ value
936
+ ]);
937
+ }
938
+ function appendResponseHeaderDirective(res, name, value) {
939
+ let header = res.getHeader(name);
940
+ if (!header) {
941
+ if (Array.isArray(value)) {
942
+ res.setHeader(name, value.join('; '));
943
+ return;
944
+ }
945
+ res.setHeader(name, value);
946
+ return;
947
+ }
948
+ if (!Array.isArray(header)) {
949
+ if (typeof header === 'string') {
950
+ // split header by directive(s)
951
+ header = header.split('; ');
952
+ }
953
+ if (typeof header === 'number') {
954
+ header = [
955
+ header.toString()
956
+ ];
957
+ }
958
+ }
959
+ if (Array.isArray(value)) {
960
+ header.push(...value);
961
+ } else {
962
+ header.push(`${value}`);
963
+ }
964
+ header = [
965
+ ...new Set(header)
966
+ ];
967
+ res.setHeader(name, header.join('; '));
968
+ }
969
+
970
+ function setResponseContentTypeByFileName(res, fileName) {
971
+ const ext = extname(fileName);
972
+ if (ext) {
973
+ let type = getMimeType(ext.substring(1));
974
+ if (type) {
975
+ const charset = getCharsetForMimeType(type);
976
+ if (charset) {
977
+ type += `; charset=${charset}`;
978
+ }
979
+ res.setHeader(exports.HeaderName.CONTENT_TYPE, type);
980
+ }
981
+ }
982
+ }
983
+
984
+ function setResponseHeaderAttachment(res, filename) {
985
+ if (typeof filename === 'string') {
986
+ setResponseContentTypeByFileName(res, filename);
987
+ }
988
+ res.setHeader(exports.HeaderName.CONTENT_DISPOSITION, `attachment${filename ? `; filename="${filename}"` : ''}`);
989
+ }
990
+
991
+ function setResponseHeaderContentType(res, input, ifNotExists) {
992
+ if (ifNotExists) {
993
+ const header = res.getHeader(exports.HeaderName.CONTENT_TYPE);
994
+ if (header) {
995
+ return;
996
+ }
997
+ }
998
+ const contentType = getMimeType(input);
999
+ if (contentType) {
1000
+ res.setHeader(exports.HeaderName.CONTENT_TYPE, contentType);
1001
+ }
1002
+ }
1003
+
1004
+ async function send(res, chunk) {
1005
+ switch(typeof chunk){
1006
+ case 'string':
1007
+ {
1008
+ setResponseHeaderContentType(res, 'html', true);
1009
+ break;
1010
+ }
1011
+ case 'boolean':
1012
+ case 'number':
1013
+ case 'object':
1014
+ {
1015
+ if (buffer.Buffer.isBuffer(chunk)) {
1016
+ setResponseHeaderContentType(res, 'bin', true);
1017
+ } else if (chunk !== null) {
1018
+ chunk = JSON.stringify(chunk);
1019
+ setResponseHeaderContentType(res, 'application/json', true);
1020
+ }
1021
+ break;
1022
+ }
1023
+ }
1024
+ let encoding;
1025
+ if (typeof chunk === 'string') {
1026
+ res.setHeader(exports.HeaderName.CONTENT_ENCODING, 'utf-8');
1027
+ appendResponseHeaderDirective(res, exports.HeaderName.CONTENT_TYPE, 'charset=utf-8');
1028
+ encoding = 'utf-8';
1029
+ }
1030
+ // populate Content-Length
1031
+ let len;
1032
+ if (chunk !== undefined && chunk !== null) {
1033
+ if (buffer.Buffer.isBuffer(chunk)) {
1034
+ // get length of Buffer
1035
+ len = chunk.length;
1036
+ } else if (chunk.length < 1000) {
1037
+ // just calculate length when no ETag + small chunk
1038
+ len = buffer.Buffer.byteLength(chunk, encoding);
1039
+ } else {
1040
+ // convert chunk to Buffer and calculate
1041
+ chunk = buffer.Buffer.from(chunk, encoding);
1042
+ encoding = undefined;
1043
+ len = chunk.length;
1044
+ }
1045
+ res.setHeader(exports.HeaderName.CONTENT_LENGTH, `${len}`);
1046
+ }
1047
+ if (typeof len !== 'undefined') {
1048
+ const etagFn = findRouterOption('etag', useRequestRouterPath(res.req));
1049
+ const chunkHash = await etagFn(chunk, encoding, len);
1050
+ if (isResponseGone(res)) {
1051
+ return Promise.resolve();
1052
+ }
1053
+ if (typeof chunkHash === 'string') {
1054
+ res.setHeader(exports.HeaderName.ETag, chunkHash);
1055
+ if (res.req.headers[exports.HeaderName.IF_NONE_MATCH] === chunkHash) {
1056
+ res.statusCode = 304;
1057
+ }
1058
+ }
1059
+ }
1060
+ // strip irrelevant headers
1061
+ if (res.statusCode === 204 || res.statusCode === 304) {
1062
+ res.removeHeader(exports.HeaderName.CONTENT_TYPE);
1063
+ res.removeHeader(exports.HeaderName.CONTENT_LENGTH);
1064
+ res.removeHeader(exports.HeaderName.TRANSFER_ENCODING);
1065
+ }
1066
+ // alter headers for 205
1067
+ if (res.statusCode === 205) {
1068
+ res.setHeader(exports.HeaderName.CONTENT_LENGTH, 0);
1069
+ res.removeHeader(exports.HeaderName.TRANSFER_ENCODING);
1070
+ }
1071
+ if (isResponseGone(res)) {
1072
+ return Promise.resolve();
1073
+ }
1074
+ if (res.req.method === 'HEAD') {
1075
+ // skip body for HEAD
1076
+ res.end();
1077
+ return Promise.resolve();
1078
+ }
1079
+ if (typeof chunk === 'undefined' || chunk === null) {
1080
+ res.end();
1081
+ return Promise.resolve();
1082
+ }
1083
+ if (typeof encoding !== 'undefined') {
1084
+ res.end(chunk, encoding);
1085
+ return Promise.resolve();
1086
+ }
1087
+ res.end(chunk);
1088
+ return Promise.resolve();
1089
+ }
1090
+
1091
+ function sendAccepted(res, chunk) {
1092
+ res.statusCode = 202;
1093
+ res.statusMessage = 'Accepted';
1094
+ return send(res, chunk);
1095
+ }
1096
+
1097
+ function sendCreated(res, chunk) {
996
1098
  res.statusCode = 201;
997
1099
  res.statusMessage = 'Created';
998
1100
  return send(res, chunk);
@@ -1303,99 +1405,90 @@ function createResponse(request) {
1303
1405
  return writable;
1304
1406
  }
1305
1407
 
1306
- async function dispatchNodeRequest(router, req, res) {
1307
- try {
1308
- const dispatched = await router.dispatch({
1309
- req,
1310
- res
1311
- });
1312
- if (dispatched) {
1313
- return;
1314
- }
1315
- if (!isResponseGone(res)) {
1316
- res.statusCode = 404;
1317
- res.end();
1318
- }
1319
- } catch (e) {
1320
- if (!isResponseGone(res)) {
1321
- res.statusCode = 500;
1322
- res.end();
1323
- }
1324
- }
1325
- }
1326
- function createNodeDispatcher(router) {
1327
- return (req, res)=>{
1328
- // eslint-disable-next-line no-void
1329
- void dispatchNodeRequest(router, req, res);
1408
+ function buildDispatcherMeta(input) {
1409
+ return {
1410
+ mountPath: input.mountPath || '/',
1411
+ params: input.params || {},
1412
+ path: input.path || '/',
1413
+ routerPath: []
1330
1414
  };
1331
1415
  }
1332
-
1333
- function createRequest(context) {
1334
- let readable;
1335
- if (context.body) {
1336
- if (isWebStream(context.body)) {
1337
- readable = readableStream.Readable.fromWeb(context.body);
1338
- } else {
1339
- readable = readableStream.Readable.from(context.body);
1340
- }
1341
- } else {
1342
- readable = new readableStream.Readable();
1416
+ function cloneDispatcherMeta(input) {
1417
+ return {
1418
+ path: input.path,
1419
+ mountPath: input.mountPath,
1420
+ error: input.error,
1421
+ routerPath: [
1422
+ ...input.routerPath
1423
+ ],
1424
+ params: cloneDispatcherMetaParams(input.params)
1425
+ };
1426
+ }
1427
+ function cloneDispatcherMetaParams(input) {
1428
+ if (typeof input === 'undefined') {
1429
+ return {};
1343
1430
  }
1344
- const headers = context.headers || {};
1345
- const rawHeaders = [];
1346
- let keys = Object.keys(headers);
1431
+ const keys = Object.keys(input);
1432
+ if (keys.length === 0) {
1433
+ return {};
1434
+ }
1435
+ const output = {};
1347
1436
  for(let i = 0; i < keys.length; i++){
1348
- const header = headers[keys[i]];
1349
- if (Array.isArray(header)) {
1350
- for(let j = 0; j < header.length; j++){
1351
- rawHeaders.push(keys[i], header[j]);
1352
- }
1353
- } else if (typeof header === 'string') {
1354
- rawHeaders.push(keys[i], header);
1355
- }
1437
+ output[keys[i]] = input[keys[i]];
1438
+ }
1439
+ return output;
1440
+ }
1441
+ function mergeDispatcherMetaParams(t1, t2) {
1442
+ if (!t1 && !t2) {
1443
+ return {};
1444
+ }
1445
+ if (!t1 || !t2) {
1446
+ return t1 || t2;
1447
+ }
1448
+ const keys = Object.keys(t2);
1449
+ if (keys.length === 0) {
1450
+ return t1;
1356
1451
  }
1357
- const headersDistinct = {};
1358
- keys = Object.keys(headers);
1359
1452
  for(let i = 0; i < keys.length; i++){
1360
- const header = headers[keys[i]];
1361
- if (Array.isArray(header)) {
1362
- headersDistinct[keys[i]] = header;
1363
- }
1364
- if (typeof header === 'string') {
1365
- headersDistinct[keys[i]] = [
1366
- header
1367
- ];
1368
- }
1453
+ t1[keys[i]] = t2[keys[i]];
1369
1454
  }
1370
- Object.defineProperty(readable, 'connection', {
1371
- get () {
1372
- return {};
1455
+ return t1;
1456
+ }
1457
+
1458
+ async function dispatchNodeRequest(router, req, res) {
1459
+ try {
1460
+ const dispatched = await router.dispatch({
1461
+ req,
1462
+ res
1463
+ }, buildDispatcherMeta({
1464
+ path: useRequestPath(req)
1465
+ }));
1466
+ if (dispatched) {
1467
+ return;
1373
1468
  }
1374
- });
1375
- Object.defineProperty(readable, 'socket', {
1376
- get () {
1377
- return {};
1469
+ if (!isResponseGone(res)) {
1470
+ res.statusCode = 404;
1471
+ res.end();
1378
1472
  }
1379
- });
1380
- Object.assign(readable, {
1381
- aborted: false,
1382
- complete: true,
1383
- headers,
1384
- headersDistinct,
1385
- httpVersion: '1.1',
1386
- httpVersionMajor: 1,
1387
- httpVersionMinor: 1,
1388
- method: context.method || 'GET',
1389
- rawHeaders,
1390
- rawTrailers: [],
1391
- trailers: {},
1392
- trailersDistinct: {},
1393
- url: context.url || '/',
1394
- setTimeout (_msecs, _callback) {
1395
- return this;
1473
+ } catch (e) {
1474
+ if (!isResponseGone(res)) {
1475
+ if (isError(e)) {
1476
+ res.statusCode = e.statusCode;
1477
+ if (e.statusMessage) {
1478
+ res.statusMessage = e.statusMessage;
1479
+ }
1480
+ } else {
1481
+ res.statusCode = 500;
1482
+ }
1483
+ res.end();
1396
1484
  }
1397
- });
1398
- return readable;
1485
+ }
1486
+ }
1487
+ function createNodeDispatcher(router) {
1488
+ return (req, res)=>{
1489
+ // eslint-disable-next-line no-void
1490
+ void dispatchNodeRequest(router, req, res);
1491
+ };
1399
1492
  }
1400
1493
 
1401
1494
  async function dispatchRawRequest(router, request, options = {}) {
@@ -1420,33 +1513,38 @@ async function dispatchRawRequest(router, request, options = {}) {
1420
1513
  }
1421
1514
  return output;
1422
1515
  };
1516
+ const createRawResponse = (input = {})=>({
1517
+ status: input.status || res.statusCode,
1518
+ statusMessage: input.statusMessage || res.statusMessage,
1519
+ headers: getHeaders(),
1520
+ body: res.body
1521
+ });
1423
1522
  try {
1424
1523
  const dispatched = await router.dispatch({
1425
1524
  req,
1426
1525
  res
1427
- });
1526
+ }, buildDispatcherMeta({
1527
+ path: useRequestPath(req)
1528
+ }));
1428
1529
  if (dispatched) {
1429
- return {
1430
- status: res.statusCode,
1431
- statusMessage: res.statusMessage,
1432
- headers: getHeaders(),
1433
- body: res.body
1434
- };
1530
+ return createRawResponse();
1435
1531
  }
1436
- return {
1437
- status: 404,
1438
- headers: getHeaders(),
1439
- body: res.body
1440
- };
1532
+ return createRawResponse({
1533
+ status: 404
1534
+ });
1441
1535
  } catch (e) {
1442
1536
  if (options.throwOnError) {
1443
1537
  throw e;
1444
1538
  }
1445
- return {
1446
- status: 500,
1447
- headers: getHeaders(),
1448
- body: res.body
1449
- };
1539
+ if (isError(e)) {
1540
+ return createRawResponse({
1541
+ status: e.statusCode,
1542
+ statusMessage: e.statusMessage
1543
+ });
1544
+ }
1545
+ return createRawResponse({
1546
+ status: 500
1547
+ });
1450
1548
  }
1451
1549
  }
1452
1550
  function createRawDispatcher(router) {
@@ -1481,54 +1579,40 @@ function createWebDispatcher(router) {
1481
1579
  return async (request)=>dispatchWebRequest(router, request);
1482
1580
  }
1483
1581
 
1484
- function cloneDispatcherMeta(input) {
1485
- if (!input) {
1486
- return {};
1582
+ exports.HandlerType = void 0;
1583
+ (function(HandlerType) {
1584
+ HandlerType["CORE"] = "core";
1585
+ HandlerType["ERROR"] = "error";
1586
+ })(exports.HandlerType || (exports.HandlerType = {}));
1587
+
1588
+ function coreHandler(input) {
1589
+ if (typeof input === 'function') {
1590
+ return {
1591
+ type: exports.HandlerType.CORE,
1592
+ fn: input
1593
+ };
1487
1594
  }
1488
1595
  return {
1489
- path: input.path,
1490
- mountPath: input.mountPath,
1491
- error: input.error,
1492
- routerIds: [
1493
- ...input.routerIds || []
1494
- ],
1495
- params: cloneDispatcherMetaParams(input.params)
1596
+ type: exports.HandlerType.CORE,
1597
+ ...input
1496
1598
  };
1497
1599
  }
1498
- function cloneDispatcherMetaParams(input) {
1499
- if (typeof input === 'undefined') {
1500
- return {};
1501
- }
1502
- const keys = Object.keys(input);
1503
- const output = {};
1504
- for(let i = 0; i < keys.length; i++){
1505
- output[keys[i]] = input[keys[i]];
1506
- }
1507
- return output;
1508
- }
1509
- function mergeDispatcherMetaParams(t1, t2) {
1510
- if (!t1 && !t2) {
1511
- return {};
1512
- }
1513
- if (!t1 || !t2) {
1514
- return t1 || t2;
1515
- }
1516
- const keys = Object.keys(t2);
1517
- for(let i = 0; i < keys.length; i++){
1518
- t1[keys[i]] = t2[keys[i]];
1600
+
1601
+ function errorHandler(input) {
1602
+ if (typeof input === 'function') {
1603
+ return {
1604
+ type: exports.HandlerType.ERROR,
1605
+ fn: input
1606
+ };
1519
1607
  }
1520
- return t1;
1608
+ return {
1609
+ type: exports.HandlerType.ERROR,
1610
+ ...input
1611
+ };
1521
1612
  }
1522
1613
 
1523
- function createError(input) {
1524
- if (input instanceof Error) {
1525
- return input;
1526
- }
1527
- const error = new Error();
1528
- if (typeof input.message === 'string') {
1529
- error.message = input.message;
1530
- }
1531
- return error;
1614
+ function isHandler(input) {
1615
+ return isObject(input) && typeof input.fn === 'function' && typeof input.type === 'string';
1532
1616
  }
1533
1617
 
1534
1618
  function decodeParam(val) {
@@ -1539,56 +1623,46 @@ function decodeParam(val) {
1539
1623
  }
1540
1624
  class PathMatcher {
1541
1625
  test(path) {
1542
- const fastSlash = this.path === '/' && this.regexpOptions.end === false;
1543
- if (fastSlash) {
1544
- return true;
1545
- }
1546
1626
  return this.regexp.test(path);
1547
1627
  }
1548
1628
  exec(path) {
1549
- let match = null;
1550
- const fastSlash = this.path === '/' && this.regexpOptions.end === false;
1551
- if (fastSlash) {
1629
+ if (this.path === '/' && this.regexpOptions.end === false) {
1552
1630
  return {
1553
1631
  path: '/',
1554
1632
  params: {}
1555
1633
  };
1556
1634
  }
1557
- match = this.regexp.exec(path);
1558
- if (!match) {
1559
- return undefined;
1560
- }
1561
- if (this.path instanceof RegExp) {
1635
+ if (this.path === '*') {
1562
1636
  return {
1563
1637
  path,
1564
1638
  params: {
1565
- 0: decodeParam(match[0])
1639
+ 0: decodeParam(path)
1566
1640
  }
1567
1641
  };
1568
1642
  }
1569
- const output = {};
1643
+ const match = this.regexp.exec(path);
1644
+ if (!match) {
1645
+ return undefined;
1646
+ }
1647
+ const params = {};
1570
1648
  for(let i = 1; i < match.length; i++){
1571
1649
  const key = this.regexpKeys[i - 1];
1572
1650
  const prop = key.name;
1573
1651
  const val = decodeParam(match[i]);
1574
1652
  if (typeof val !== 'undefined') {
1575
- output[prop] = val;
1653
+ params[prop] = val;
1576
1654
  }
1577
1655
  }
1578
1656
  return {
1579
1657
  path: match[0],
1580
- params: output
1658
+ params
1581
1659
  };
1582
1660
  }
1583
1661
  constructor(path, options){
1584
1662
  this.regexpKeys = [];
1585
1663
  this.path = path;
1586
1664
  this.regexpOptions = options || {};
1587
- if (path instanceof RegExp) {
1588
- this.regexp = path;
1589
- } else {
1590
- this.regexp = pathToRegexp.pathToRegexp(path, this.regexpKeys, options);
1591
- }
1665
+ this.regexp = pathToRegexp.pathToRegexp(path, this.regexpKeys, options);
1592
1666
  }
1593
1667
  }
1594
1668
 
@@ -1596,27 +1670,33 @@ function isPath(input) {
1596
1670
  return typeof input === 'string' || input instanceof RegExp;
1597
1671
  }
1598
1672
 
1673
+ const LayerSymbol = Symbol.for('Layer');
1674
+
1599
1675
  class Layer {
1600
1676
  // --------------------------------------------------
1601
- isError() {
1602
- return this.fn.length === 4;
1677
+ get type() {
1678
+ return this.handler.type;
1679
+ }
1680
+ get path() {
1681
+ return this.handler.path;
1682
+ }
1683
+ get method() {
1684
+ return this.handler.method ? this.handler.method.toLowerCase() : undefined;
1603
1685
  }
1604
1686
  // --------------------------------------------------
1605
1687
  dispatch(event, meta) {
1606
- setRequestParams(event.req, meta.params || {});
1607
- setRequestMountPath(event.req, meta.mountPath || '/');
1608
- setRequestRouterIds(event.req, meta.routerIds || []);
1609
- if (this.fn.length !== 4 && meta.error || this.fn.length === 4 && !meta.error) {
1610
- return Promise.reject(meta.error);
1688
+ if (this.pathMatcher) {
1689
+ const pathMatch = this.pathMatcher.exec(meta.path);
1690
+ if (pathMatch) {
1691
+ meta.params = mergeDispatcherMetaParams(meta.params, pathMatch.params);
1692
+ }
1611
1693
  }
1612
- const timeout = findRouterOption('timeout', meta.routerIds);
1694
+ setRequestParams(event.req, meta.params);
1695
+ setRequestMountPath(event.req, meta.mountPath);
1696
+ setRequestRouterPath(event.req, meta.routerPath);
1613
1697
  return new Promise((resolve, reject)=>{
1614
- let timeoutInstance;
1615
1698
  let handled = false;
1616
1699
  const unsubscribe = ()=>{
1617
- if (timeoutInstance) {
1618
- clearTimeout(timeoutInstance);
1619
- }
1620
1700
  event.res.off('close', onFinished);
1621
1701
  event.res.off('error', onFinished);
1622
1702
  };
@@ -1636,30 +1716,23 @@ class Layer {
1636
1716
  const onNext = (err)=>shutdown(false, err);
1637
1717
  event.res.once('close', onFinished);
1638
1718
  event.res.once('error', onFinished);
1639
- if (timeout) {
1640
- timeoutInstance = setTimeout(()=>{
1641
- handled = true;
1642
- unsubscribe();
1643
- event.res.statusCode = 504;
1644
- event.res.statusMessage = 'Gateway Timeout';
1645
- event.res.end();
1646
- }, timeout);
1647
- }
1719
+ const handle = (data)=>{
1720
+ if (typeof data === 'undefined' || handled) {
1721
+ return Promise.resolve();
1722
+ }
1723
+ handled = true;
1724
+ unsubscribe();
1725
+ return this.sendOutput(event.res, data).then(()=>resolve(true)).catch((e)=>reject(createError(e)));
1726
+ };
1648
1727
  try {
1649
1728
  let output;
1650
- if (meta.error) {
1651
- output = this.fn(meta.error, event.req, event.res, onNext);
1729
+ if (this.handler.type === exports.HandlerType.ERROR) {
1730
+ if (meta.error) {
1731
+ output = this.handler.fn(meta.error, event.req, event.res, onNext);
1732
+ }
1652
1733
  } else {
1653
- output = this.fn(event.req, event.res, onNext);
1734
+ output = this.handler.fn(event.req, event.res, onNext);
1654
1735
  }
1655
- const handle = (data)=>{
1656
- if (typeof data === 'undefined' || handled) {
1657
- return Promise.resolve();
1658
- }
1659
- handled = true;
1660
- unsubscribe();
1661
- return this.sendOutput(event.res, data).then(()=>resolve(true)).catch((e)=>reject(createError(e)));
1662
- };
1663
1736
  if (isPromise(output)) {
1664
1737
  output.then((r)=>handle(r)).catch((e)=>reject(createError(e)));
1665
1738
  return;
@@ -1672,7 +1745,7 @@ class Layer {
1672
1745
  }
1673
1746
  sendOutput(res, input) {
1674
1747
  if (input instanceof Error) {
1675
- return Promise.reject(input);
1748
+ return Promise.reject(createError(input));
1676
1749
  }
1677
1750
  if (isStream(input)) {
1678
1751
  return sendStream(res, input);
@@ -1687,143 +1760,45 @@ class Layer {
1687
1760
  }
1688
1761
  // --------------------------------------------------
1689
1762
  matchPath(path) {
1763
+ if (!this.pathMatcher) {
1764
+ return true;
1765
+ }
1690
1766
  return this.pathMatcher.test(path);
1691
1767
  }
1692
- exec(path) {
1693
- return this.pathMatcher.exec(path);
1768
+ matchMethod(method) {
1769
+ if (!this.method) {
1770
+ return true;
1771
+ }
1772
+ const name = method.toLowerCase();
1773
+ if (name === this.method) {
1774
+ return true;
1775
+ }
1776
+ return name === exports.MethodName.HEAD && this.method === exports.MethodName.GET;
1694
1777
  }
1695
1778
  // --------------------------------------------------
1696
- constructor(options, fn){
1697
- this['@instanceof'] = Symbol.for('Layer');
1698
- this.pathMatcher = new PathMatcher(options.path, options.pathMatcher);
1699
- this.fn = fn;
1779
+ constructor(handler){
1780
+ this['@instanceof'] = LayerSymbol;
1781
+ this.handler = handler;
1782
+ if (handler.path) {
1783
+ this.pathMatcher = new PathMatcher(handler.path, {
1784
+ end: !!handler.method
1785
+ });
1786
+ }
1700
1787
  }
1701
1788
  }
1702
1789
 
1703
1790
  function isLayerInstance(input) {
1704
- if (input instanceof Layer) {
1705
- return true;
1706
- }
1707
- return isInstance(input, 'Layer');
1791
+ return isInstance(input, LayerSymbol);
1708
1792
  }
1709
1793
 
1710
- class Route {
1711
- // --------------------------------------------------
1712
- matchPath(path) {
1713
- return this.pathMatcher.test(path);
1714
- }
1715
- matchMethod(method) {
1716
- let name = method.toLowerCase();
1717
- if (name === exports.MethodName.HEAD && !smob.hasOwnProperty(this.layers, name)) {
1718
- name = exports.MethodName.GET;
1719
- }
1720
- return Object.prototype.hasOwnProperty.call(this.layers, name);
1721
- }
1722
- // --------------------------------------------------
1723
- getMethods() {
1724
- const keys = Object.keys(this.layers);
1725
- if (smob.hasOwnProperty(this.layers, exports.MethodName.GET) && !smob.hasOwnProperty(this.layers, exports.MethodName.HEAD)) {
1726
- keys.push(exports.MethodName.HEAD);
1727
- }
1728
- return keys;
1729
- }
1730
- // --------------------------------------------------
1731
- async dispatch(event, meta) {
1732
- /* istanbul ignore next */ if (!event.req.method) {
1733
- return false;
1734
- }
1735
- let name = event.req.method.toLowerCase();
1736
- if (name === exports.MethodName.HEAD && !smob.hasOwnProperty(this.layers, name)) {
1737
- name = exports.MethodName.GET;
1738
- }
1739
- const layers = this.layers[name];
1740
- /* istanbul ignore next */ if (typeof layers === 'undefined' || layers.length === 0 || typeof meta.path === 'undefined') {
1741
- return false;
1742
- }
1743
- const layerMeta = cloneDispatcherMeta(meta);
1744
- const output = this.pathMatcher.exec(meta.path);
1745
- if (output) {
1746
- layerMeta.params = mergeDispatcherMetaParams(layerMeta.params, output.params);
1747
- }
1748
- let err;
1749
- for(let i = 0; i < layers.length; i++){
1750
- const layer = layers[i];
1751
- if (err && !layer.isError()) {
1752
- continue;
1753
- }
1754
- try {
1755
- const dispatched = await layer.dispatch(event, {
1756
- ...layerMeta
1757
- });
1758
- if (dispatched) {
1759
- return true;
1760
- }
1761
- } catch (e) {
1762
- if (e instanceof Error) {
1763
- err = e;
1764
- }
1765
- }
1766
- }
1767
- if (err) {
1768
- throw err;
1769
- }
1794
+ function isPluginInstallContext(input) {
1795
+ if (!isObject(input) || !isObject(input.options)) {
1770
1796
  return false;
1771
1797
  }
1772
- // --------------------------------------------------
1773
- register(method, ...handlers) {
1774
- this.layers[method] = [];
1775
- for(let i = 0; i < handlers.length; i++){
1776
- const layer = new Layer({
1777
- path: this.path,
1778
- pathMatcher: this.pathMatcherOptions
1779
- }, handlers[i]);
1780
- this.layers[method].push(layer);
1781
- }
1782
- }
1783
- get(...handlers) {
1784
- return this.register(exports.MethodName.GET, ...handlers);
1785
- }
1786
- post(...handlers) {
1787
- return this.register(exports.MethodName.POST, ...handlers);
1788
- }
1789
- put(...handlers) {
1790
- return this.register(exports.MethodName.PUT, ...handlers);
1791
- }
1792
- patch(...handlers) {
1793
- return this.register(exports.MethodName.PATCH, ...handlers);
1794
- }
1795
- delete(...handlers) {
1796
- return this.register(exports.MethodName.DELETE, ...handlers);
1797
- }
1798
- head(...handlers) {
1799
- return this.register(exports.MethodName.HEAD, ...handlers);
1800
- }
1801
- options(...handlers) {
1802
- return this.register(exports.MethodName.OPTIONS, ...handlers);
1803
- }
1804
- // --------------------------------------------------
1805
- isStrictPath() {
1806
- return typeof this.path !== 'string' || this.path !== '/' && this.path.length !== 0;
1807
- }
1808
- // --------------------------------------------------
1809
- constructor(options){
1810
- this['@instanceof'] = Symbol.for('Route');
1811
- this.layers = {};
1812
- this.path = options.path;
1813
- this.pathMatcherOptions = {
1814
- end: true,
1815
- strict: this.isStrictPath(),
1816
- ...options.pathMatcher
1817
- };
1818
- this.pathMatcher = new PathMatcher(this.path, this.pathMatcherOptions);
1819
- }
1820
- }
1821
-
1822
- function isRouteInstance(input) {
1823
- if (input instanceof Route) {
1824
- return true;
1798
+ if (typeof input.name !== 'undefined' && typeof input.name !== 'string') {
1799
+ return false;
1825
1800
  }
1826
- return isInstance(input, 'Route');
1801
+ return typeof input.path === 'undefined' || isPath(input.path);
1827
1802
  }
1828
1803
 
1829
1804
  function transformRouterOptions(input) {
@@ -1836,17 +1811,16 @@ function transformRouterOptions(input) {
1836
1811
  return input;
1837
1812
  }
1838
1813
 
1814
+ const RouterSymbol = Symbol.for('Router');
1815
+
1839
1816
  let nextId = 0;
1840
1817
  function generateRouterID() {
1841
1818
  return ++nextId;
1842
1819
  }
1843
-
1844
1820
  function isRouterInstance(input) {
1845
- if (input instanceof Router) {
1846
- return true;
1847
- }
1848
- return isInstance(input, 'Router');
1821
+ return isInstance(input, RouterSymbol);
1849
1822
  }
1823
+
1850
1824
  class Router {
1851
1825
  // --------------------------------------------------
1852
1826
  setPath(value) {
@@ -1860,9 +1834,7 @@ class Router {
1860
1834
  path = value;
1861
1835
  }
1862
1836
  this.pathMatcher = new PathMatcher(path, {
1863
- end: false,
1864
- sensitive: false,
1865
- ...this.pathMatcherOptions ? this.pathMatcherOptions : {}
1837
+ end: false
1866
1838
  });
1867
1839
  }
1868
1840
  // --------------------------------------------------
@@ -1873,78 +1845,60 @@ class Router {
1873
1845
  return true;
1874
1846
  }
1875
1847
  // --------------------------------------------------
1876
- async dispatch(event, meta = {}) {
1848
+ async dispatch(event, meta) {
1877
1849
  const allowedMethods = [];
1878
- let path = meta.path || useRequestPath(event.req);
1879
1850
  if (this.pathMatcher) {
1880
- const output = this.pathMatcher.exec(path);
1851
+ const output = this.pathMatcher.exec(meta.path);
1881
1852
  if (typeof output !== 'undefined') {
1882
- meta.mountPath = cleanDoubleSlashes(`${meta.mountPath || ''}/${output.path}`);
1883
- if (path === output.path) {
1884
- path = '/';
1853
+ meta.mountPath = cleanDoubleSlashes(`${meta.mountPath}/${output.path}`);
1854
+ if (meta.path === output.path) {
1855
+ meta.path = '/';
1885
1856
  } else {
1886
- path = withLeadingSlash(path.substring(output.path.length));
1857
+ meta.path = withLeadingSlash(meta.path.substring(output.path.length));
1887
1858
  }
1888
- meta.params = smob.merge(meta.params || {}, output.params);
1859
+ meta.params = {
1860
+ ...meta.params,
1861
+ ...output.params
1862
+ };
1889
1863
  }
1890
1864
  }
1891
- meta.path = path;
1892
- if (meta.routerIds) {
1893
- meta.routerIds.push(this.id);
1894
- } else {
1895
- meta.routerIds = [
1896
- this.id
1897
- ];
1898
- }
1899
- if (!meta.mountPath) {
1900
- meta.mountPath = '/';
1901
- }
1865
+ meta.routerPath.push(this.id);
1902
1866
  let err;
1903
- let layer;
1867
+ let item;
1868
+ let itemMeta;
1904
1869
  let match = false;
1905
1870
  for(let i = 0; i < this.stack.length; i++){
1906
- layer = this.stack[i];
1907
- if (layer instanceof Layer) {
1908
- if (!layer.isError() && err) {
1871
+ item = this.stack[i];
1872
+ if (isLayerInstance(item)) {
1873
+ if (item.type !== exports.HandlerType.ERROR && err) {
1909
1874
  continue;
1910
1875
  }
1911
- match = layer.matchPath(path);
1912
- }
1913
- if (isRouterInstance(layer)) {
1914
- match = layer.matchPath(path);
1915
- }
1916
- if (isRouteInstance(layer)) {
1917
- match = layer.matchPath(path);
1918
- if (event.req.method && !layer.matchMethod(event.req.method)) {
1919
- match = false;
1920
- if (event.req.method.toLowerCase() === exports.MethodName.OPTIONS) {
1921
- allowedMethods.push(...layer.getMethods());
1876
+ match = item.matchPath(meta.path);
1877
+ if (match && event.req.method) {
1878
+ if (!item.matchMethod(event.req.method)) {
1879
+ match = false;
1880
+ }
1881
+ if (item.method) {
1882
+ allowedMethods.push(item.method);
1922
1883
  }
1923
1884
  }
1885
+ } else if (isRouterInstance(item)) {
1886
+ match = item.matchPath(meta.path);
1924
1887
  }
1925
1888
  if (!match) {
1926
1889
  continue;
1927
1890
  }
1928
- const layerMeta = cloneDispatcherMeta(meta);
1929
- if (isLayerInstance(layer)) {
1930
- const output = layer.exec(path);
1931
- if (output) {
1932
- layerMeta.params = mergeDispatcherMetaParams(layerMeta.params, output.params);
1933
- layerMeta.mountPath = cleanDoubleSlashes(`${layerMeta.mountPath || ''}/${output.path}`);
1934
- }
1935
- if (err) {
1936
- layerMeta.error = err;
1937
- }
1938
- } else if (err) {
1939
- continue;
1891
+ itemMeta = cloneDispatcherMeta(meta);
1892
+ if (err) {
1893
+ itemMeta.error = err;
1940
1894
  }
1941
1895
  try {
1942
- const dispatched = await layer.dispatch(event, layerMeta);
1896
+ const dispatched = await item.dispatch(event, itemMeta);
1943
1897
  if (dispatched) {
1944
1898
  return true;
1945
1899
  }
1946
1900
  } catch (e) {
1947
- if (e instanceof Error) {
1901
+ if (isError(e)) {
1948
1902
  err = e;
1949
1903
  }
1950
1904
  }
@@ -1953,7 +1907,11 @@ class Router {
1953
1907
  throw err;
1954
1908
  }
1955
1909
  if (event.req.method && event.req.method.toLowerCase() === exports.MethodName.OPTIONS) {
1956
- const options = smob.distinctArray(allowedMethods).map((key)=>key.toUpperCase()).join(',');
1910
+ if (allowedMethods.indexOf(exports.MethodName.GET) !== -1) {
1911
+ allowedMethods.push(exports.MethodName.HEAD);
1912
+ }
1913
+ smob.distinctArray(allowedMethods);
1914
+ const options = allowedMethods.map((key)=>key.toUpperCase()).join(',');
1957
1915
  if (!isResponseGone(event.res)) {
1958
1916
  event.res.setHeader(exports.HeaderName.ALLOW, options);
1959
1917
  await send(event.res, options);
@@ -1962,71 +1920,128 @@ class Router {
1962
1920
  }
1963
1921
  return false;
1964
1922
  }
1965
- // --------------------------------------------------
1966
- route(path) {
1967
- if (typeof path === 'string' && path.length > 0) {
1968
- path = withLeadingSlash(path);
1923
+ delete(path, handler) {
1924
+ if (isPath(path)) {
1925
+ this.use({
1926
+ ...handler,
1927
+ method: exports.MethodName.DELETE,
1928
+ path
1929
+ });
1930
+ return this;
1969
1931
  }
1970
- const index = this.stack.findIndex((item)=>isRouteInstance(item) && item.path === path);
1971
- if (index !== -1) {
1972
- return this.stack[index];
1973
- }
1974
- const route = new Route({
1975
- path,
1976
- pathMatcher: {
1977
- ...this.pathMatcherOptions ? {
1978
- sensitive: this.pathMatcherOptions.sensitive
1979
- } : {}
1980
- }
1932
+ this.use({
1933
+ ...path,
1934
+ method: exports.MethodName.DELETE
1981
1935
  });
1982
- this.stack.push(route);
1983
- return route;
1984
- }
1985
- delete(path, ...handlers) {
1986
- const route = this.route(path);
1987
- route.delete(...handlers);
1988
1936
  return this;
1989
1937
  }
1990
- get(path, ...handlers) {
1991
- const route = this.route(path);
1992
- route.get(...handlers);
1938
+ get(path, handler) {
1939
+ if (isPath(path)) {
1940
+ this.use({
1941
+ ...handler,
1942
+ method: exports.MethodName.GET,
1943
+ path
1944
+ });
1945
+ return this;
1946
+ }
1947
+ this.use({
1948
+ ...path,
1949
+ method: exports.MethodName.GET
1950
+ });
1993
1951
  return this;
1994
1952
  }
1995
- post(path, ...handlers) {
1996
- const route = this.route(path);
1997
- route.post(...handlers);
1953
+ post(path, handler) {
1954
+ if (isPath(path)) {
1955
+ this.use({
1956
+ ...handler,
1957
+ method: exports.MethodName.POST,
1958
+ path
1959
+ });
1960
+ return this;
1961
+ }
1962
+ this.use({
1963
+ ...path,
1964
+ method: exports.MethodName.POST
1965
+ });
1998
1966
  return this;
1999
1967
  }
2000
- put(path, ...handlers) {
2001
- const route = this.route(path);
2002
- route.put(...handlers);
1968
+ put(path, handler) {
1969
+ if (isPath(path)) {
1970
+ this.use({
1971
+ ...handler,
1972
+ method: exports.MethodName.PUT,
1973
+ path
1974
+ });
1975
+ return this;
1976
+ }
1977
+ this.use({
1978
+ ...path,
1979
+ method: exports.MethodName.PUT
1980
+ });
2003
1981
  return this;
2004
1982
  }
2005
- patch(path, ...handlers) {
2006
- const route = this.route(path);
2007
- route.patch(...handlers);
1983
+ patch(path, handler) {
1984
+ if (isPath(path)) {
1985
+ this.use({
1986
+ ...handler,
1987
+ method: exports.MethodName.PATCH,
1988
+ path
1989
+ });
1990
+ return this;
1991
+ }
1992
+ this.use({
1993
+ ...path,
1994
+ method: exports.MethodName.PATCH
1995
+ });
2008
1996
  return this;
2009
1997
  }
2010
- head(path, ...handlers) {
2011
- const route = this.route(path);
2012
- route.head(...handlers);
1998
+ head(path, handler) {
1999
+ if (isPath(path)) {
2000
+ this.use({
2001
+ ...handler,
2002
+ method: exports.MethodName.HEAD,
2003
+ path
2004
+ });
2005
+ return this;
2006
+ }
2007
+ this.use({
2008
+ ...path,
2009
+ method: exports.MethodName.HEAD
2010
+ });
2013
2011
  return this;
2014
2012
  }
2015
- options(path, ...handlers) {
2016
- const route = this.route(path);
2017
- route.options(...handlers);
2013
+ options(path, handler) {
2014
+ if (isPath(path)) {
2015
+ this.use({
2016
+ ...handler,
2017
+ method: exports.MethodName.OPTIONS,
2018
+ path
2019
+ });
2020
+ return this;
2021
+ }
2022
+ this.use({
2023
+ ...path,
2024
+ method: exports.MethodName.OPTIONS
2025
+ });
2018
2026
  return this;
2019
2027
  }
2020
2028
  use(...input) {
2021
2029
  /* istanbul ignore next */ if (input.length === 0) {
2022
2030
  return this;
2023
2031
  }
2032
+ const modifyPath = (input)=>{
2033
+ if (typeof input === 'string') {
2034
+ return withLeadingSlash(input);
2035
+ }
2036
+ return input;
2037
+ };
2024
2038
  let path;
2025
- if (isPath(input[0])) {
2026
- path = input.shift();
2027
- }
2028
2039
  for(let i = 0; i < input.length; i++){
2029
2040
  const item = input[i];
2041
+ if (isPath(item)) {
2042
+ path = modifyPath(item);
2043
+ continue;
2044
+ }
2030
2045
  if (isRouterInstance(item)) {
2031
2046
  if (path) {
2032
2047
  item.setPath(path);
@@ -2034,44 +2049,63 @@ class Router {
2034
2049
  this.stack.push(item);
2035
2050
  continue;
2036
2051
  }
2037
- if (typeof item === 'function') {
2038
- this.stack.push(new Layer({
2039
- path: path || '/',
2040
- pathMatcher: {
2041
- strict: false,
2042
- end: false,
2043
- ...this.pathMatcherOptions ? {
2044
- sensitive: this.pathMatcherOptions.sensitive
2045
- } : {}
2046
- }
2047
- }, item));
2052
+ if (isHandler(item)) {
2053
+ item.path = path || modifyPath(item.path);
2054
+ this.stack.push(new Layer(item));
2048
2055
  }
2049
2056
  }
2050
2057
  return this;
2051
2058
  }
2052
2059
  // --------------------------------------------------
2060
+ install(plugin, context) {
2061
+ if (isPluginInstallContext(context)) {
2062
+ const name = context.name || plugin.name;
2063
+ if (context.path) {
2064
+ const router = new Router({
2065
+ name
2066
+ });
2067
+ plugin.install(router, context.options);
2068
+ this.use(context.path, router);
2069
+ return this;
2070
+ }
2071
+ plugin.install(this, context.options);
2072
+ return this;
2073
+ }
2074
+ plugin.install(this, context);
2075
+ return this;
2076
+ }
2077
+ uninstall(name) {
2078
+ const index = this.stack.findIndex((el)=>isRouterInstance(el) && el.name === name);
2079
+ if (index !== -1) {
2080
+ this.stack.splice(index, 1);
2081
+ }
2082
+ }
2083
+ // --------------------------------------------------
2053
2084
  constructor(options = {}){
2054
- this['@instanceof'] = Symbol.for('Router');
2085
+ this['@instanceof'] = RouterSymbol;
2055
2086
  /**
2056
2087
  * Array of mounted layers, routes & routers.
2057
2088
  *
2058
2089
  * @protected
2059
2090
  */ this.stack = [];
2060
2091
  this.id = generateRouterID();
2061
- this.pathMatcherOptions = options.pathMatcher;
2092
+ this.name = options.name;
2062
2093
  this.setPath(options.path);
2063
2094
  setRouterOptions(this.id, transformRouterOptions(options));
2064
2095
  }
2065
2096
  }
2066
2097
 
2098
+ exports.ErrorProxy = ErrorProxy;
2067
2099
  exports.Layer = Layer;
2068
2100
  exports.PathMatcher = PathMatcher;
2069
- exports.Route = Route;
2070
2101
  exports.Router = Router;
2071
2102
  exports.appendResponseHeader = appendResponseHeader;
2072
2103
  exports.appendResponseHeaderDirective = appendResponseHeaderDirective;
2104
+ exports.buildDispatcherMeta = buildDispatcherMeta;
2073
2105
  exports.cloneDispatcherMeta = cloneDispatcherMeta;
2074
2106
  exports.cloneDispatcherMetaParams = cloneDispatcherMetaParams;
2107
+ exports.coreHandler = coreHandler;
2108
+ exports.createError = createError;
2075
2109
  exports.createNodeDispatcher = createNodeDispatcher;
2076
2110
  exports.createRawDispatcher = createRawDispatcher;
2077
2111
  exports.createRequest = createRequest;
@@ -2080,6 +2114,7 @@ exports.createWebDispatcher = createWebDispatcher;
2080
2114
  exports.dispatchNodeRequest = dispatchNodeRequest;
2081
2115
  exports.dispatchRawRequest = dispatchRawRequest;
2082
2116
  exports.dispatchWebRequest = dispatchWebRequest;
2117
+ exports.errorHandler = errorHandler;
2083
2118
  exports.extendRequestBody = extendRequestBody;
2084
2119
  exports.extendRequestCookies = extendRequestCookies;
2085
2120
  exports.extendRequestQuery = extendRequestQuery;
@@ -2098,11 +2133,13 @@ exports.getRequestProtocol = getRequestProtocol;
2098
2133
  exports.hasRequestBody = hasRequestBody;
2099
2134
  exports.hasRequestCookies = hasRequestCookies;
2100
2135
  exports.hasRequestQuery = hasRequestQuery;
2136
+ exports.isError = isError;
2137
+ exports.isHandler = isHandler;
2101
2138
  exports.isLayerInstance = isLayerInstance;
2102
2139
  exports.isPath = isPath;
2140
+ exports.isPluginInstallContext = isPluginInstallContext;
2103
2141
  exports.isRequestCacheable = isRequestCacheable;
2104
2142
  exports.isResponseGone = isResponseGone;
2105
- exports.isRouteInstance = isRouteInstance;
2106
2143
  exports.isRouterInstance = isRouterInstance;
2107
2144
  exports.matchRequestContentType = matchRequestContentType;
2108
2145
  exports.mergeDispatcherMetaParams = mergeDispatcherMetaParams;
@@ -2123,7 +2160,7 @@ exports.setRequestMountPath = setRequestMountPath;
2123
2160
  exports.setRequestParam = setRequestParam;
2124
2161
  exports.setRequestParams = setRequestParams;
2125
2162
  exports.setRequestQuery = setRequestQuery;
2126
- exports.setRequestRouterIds = setRequestRouterIds;
2163
+ exports.setRequestRouterPath = setRequestRouterPath;
2127
2164
  exports.setResponseCacheHeaders = setResponseCacheHeaders;
2128
2165
  exports.setResponseContentTypeByFileName = setResponseContentTypeByFileName;
2129
2166
  exports.setResponseHeaderAttachment = setResponseHeaderAttachment;
@@ -2139,5 +2176,5 @@ exports.useRequestParam = useRequestParam;
2139
2176
  exports.useRequestParams = useRequestParams;
2140
2177
  exports.useRequestPath = useRequestPath;
2141
2178
  exports.useRequestQuery = useRequestQuery;
2142
- exports.useRequestRouterIds = useRequestRouterIds;
2179
+ exports.useRequestRouterPath = useRequestRouterPath;
2143
2180
  //# sourceMappingURL=index.cjs.map