routup 3.0.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/dist/adapters/node/module.d.ts +7 -0
- package/dist/{utils → adapters/raw}/header.d.ts +1 -1
- package/dist/{layer → adapters/raw}/index.d.ts +1 -1
- package/dist/adapters/raw/module.d.ts +4 -0
- package/dist/{dispatcher/adapters → adapters}/raw/type.d.ts +1 -1
- package/dist/adapters/web/module.d.ts +4 -0
- package/dist/constants.d.ts +7 -7
- package/dist/dispatcher/event/dispatch.d.ts +4 -0
- package/dist/dispatcher/event/error.d.ts +5 -0
- package/dist/dispatcher/event/index.d.ts +5 -0
- package/dist/dispatcher/event/is.d.ts +3 -0
- package/dist/dispatcher/event/module.d.ts +56 -0
- package/dist/dispatcher/event/types.d.ts +9 -0
- package/dist/dispatcher/index.d.ts +1 -2
- package/dist/dispatcher/type.d.ts +2 -30
- package/dist/error/create.d.ts +3 -3
- package/dist/error/is.d.ts +2 -2
- package/dist/error/module.d.ts +1 -1
- package/dist/handler/constants.d.ts +1 -0
- package/dist/handler/core/define.d.ts +4 -3
- package/dist/handler/core/types.d.ts +3 -3
- package/dist/handler/error/define.d.ts +4 -3
- package/dist/handler/error/types.d.ts +5 -5
- package/dist/handler/index.d.ts +1 -0
- package/dist/handler/is.d.ts +3 -1
- package/dist/handler/module.d.ts +23 -0
- package/dist/handler/types-base.d.ts +6 -2
- package/dist/handler/types.d.ts +3 -4
- package/dist/hook/constants.d.ts +8 -0
- package/dist/hook/index.d.ts +3 -0
- package/dist/hook/module.d.ts +19 -0
- package/dist/hook/types.d.ts +5 -0
- package/dist/index.cjs +701 -450
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +692 -443
- package/dist/index.mjs.map +1 -1
- package/dist/response/helpers/send-web-blob.d.ts +1 -1
- package/dist/response/helpers/send-web-response.d.ts +1 -1
- package/dist/router/constants.d.ts +8 -0
- package/dist/router/index.d.ts +0 -1
- package/dist/router/module.d.ts +56 -24
- package/dist/router/types.d.ts +7 -0
- package/dist/types.d.ts +1 -0
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/method.d.ts +3 -0
- package/dist/utils/next.d.ts +2 -0
- package/package.json +15 -15
- package/dist/dispatcher/adapters/node/module.d.ts +0 -7
- package/dist/dispatcher/adapters/raw/module.d.ts +0 -4
- package/dist/dispatcher/adapters/web/index.d.ts +0 -2
- package/dist/dispatcher/adapters/web/module.d.ts +0 -5
- package/dist/dispatcher/utils.d.ts +0 -5
- package/dist/layer/constants.d.ts +0 -1
- package/dist/layer/module.d.ts +0 -17
- package/dist/layer/type.d.ts +0 -8
- package/dist/layer/utils.d.ts +0 -2
- /package/dist/{dispatcher/adapters → adapters}/index.d.ts +0 -0
- /package/dist/{dispatcher/adapters → adapters}/node/index.d.ts +0 -0
- /package/dist/{dispatcher/adapters/raw → adapters/web}/index.d.ts +0 -0
- /package/dist/{dispatcher/adapters → adapters}/web/type.d.ts +0 -0
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { HTTPError } from '@ebec/http';
|
|
2
1
|
import { merge, hasOwnProperty, distinctArray } from 'smob';
|
|
3
2
|
import { Buffer } from 'buffer';
|
|
4
3
|
import { subtle } from 'uncrypto';
|
|
@@ -6,17 +5,18 @@ import { compile, all } from 'proxy-addr';
|
|
|
6
5
|
import { getType, get } from 'mime-explorer';
|
|
7
6
|
import Negotiator from 'negotiator';
|
|
8
7
|
import { Readable, Writable } from 'readable-stream';
|
|
8
|
+
import { HTTPError } from '@ebec/http';
|
|
9
9
|
import { pathToRegexp } from 'path-to-regexp';
|
|
10
10
|
|
|
11
11
|
var MethodName;
|
|
12
12
|
(function(MethodName) {
|
|
13
|
-
MethodName["GET"] = "
|
|
14
|
-
MethodName["POST"] = "
|
|
15
|
-
MethodName["PUT"] = "
|
|
16
|
-
MethodName["PATCH"] = "
|
|
17
|
-
MethodName["DELETE"] = "
|
|
18
|
-
MethodName["OPTIONS"] = "
|
|
19
|
-
MethodName["HEAD"] = "
|
|
13
|
+
MethodName["GET"] = "GET";
|
|
14
|
+
MethodName["POST"] = "POST";
|
|
15
|
+
MethodName["PUT"] = "PUT";
|
|
16
|
+
MethodName["PATCH"] = "PATCH";
|
|
17
|
+
MethodName["DELETE"] = "DELETE";
|
|
18
|
+
MethodName["OPTIONS"] = "OPTIONS";
|
|
19
|
+
MethodName["HEAD"] = "HEAD";
|
|
20
20
|
})(MethodName || (MethodName = {}));
|
|
21
21
|
var HeaderName;
|
|
22
22
|
(function(HeaderName) {
|
|
@@ -51,32 +51,6 @@ var HeaderName;
|
|
|
51
51
|
HeaderName["X_FORWARDED_PROTO"] = "x-forwarded-proto";
|
|
52
52
|
})(HeaderName || (HeaderName = {}));
|
|
53
53
|
|
|
54
|
-
class ErrorProxy extends HTTPError {
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function isError(input) {
|
|
58
|
-
return input instanceof ErrorProxy;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Create an error proxy by
|
|
63
|
-
* - an existing error (accessible via cause property)
|
|
64
|
-
* - options
|
|
65
|
-
* - message
|
|
66
|
-
*
|
|
67
|
-
* @param input
|
|
68
|
-
*/ function createError(input) {
|
|
69
|
-
if (isError(input)) {
|
|
70
|
-
return input;
|
|
71
|
-
}
|
|
72
|
-
if (typeof input === 'string') {
|
|
73
|
-
return new ErrorProxy(input);
|
|
74
|
-
}
|
|
75
|
-
return new ErrorProxy({
|
|
76
|
-
cause: input
|
|
77
|
-
}, input);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
54
|
function isRequestCacheable(req, modifiedTime) {
|
|
81
55
|
const modifiedSince = req.headers[HeaderName.IF_MODIFIED_SINCE];
|
|
82
56
|
if (!modifiedSince) {
|
|
@@ -207,33 +181,6 @@ function setRequestHeader(req, name, value) {
|
|
|
207
181
|
return cookiesStrings;
|
|
208
182
|
}
|
|
209
183
|
|
|
210
|
-
function transformHeaderToTuples(key, value) {
|
|
211
|
-
const output = [];
|
|
212
|
-
if (Array.isArray(value)) {
|
|
213
|
-
for(let j = 0; j < value.length; j++){
|
|
214
|
-
output.push([
|
|
215
|
-
key,
|
|
216
|
-
value[j]
|
|
217
|
-
]);
|
|
218
|
-
}
|
|
219
|
-
} else if (value !== undefined) {
|
|
220
|
-
output.push([
|
|
221
|
-
key,
|
|
222
|
-
String(value)
|
|
223
|
-
]);
|
|
224
|
-
}
|
|
225
|
-
return output;
|
|
226
|
-
}
|
|
227
|
-
function transformHeadersToTuples(input) {
|
|
228
|
-
const output = [];
|
|
229
|
-
const keys = Object.keys(input);
|
|
230
|
-
for(let i = 0; i < keys.length; i++){
|
|
231
|
-
const key = keys[i].toLowerCase();
|
|
232
|
-
output.push(...transformHeaderToTuples(key, input[key]));
|
|
233
|
-
}
|
|
234
|
-
return output;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
184
|
function isObject(item) {
|
|
238
185
|
return !!item && typeof item === 'object' && !Array.isArray(item);
|
|
239
186
|
}
|
|
@@ -346,6 +293,15 @@ function getCharsetForMimeType(type) {
|
|
|
346
293
|
return undefined;
|
|
347
294
|
}
|
|
348
295
|
|
|
296
|
+
function toMethodName(input, alt) {
|
|
297
|
+
if (input) {
|
|
298
|
+
return input.toUpperCase();
|
|
299
|
+
}
|
|
300
|
+
return alt;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const nextPlaceholder = (_err)=>{};
|
|
304
|
+
|
|
349
305
|
/**
|
|
350
306
|
* Based on https://github.com/unjs/pathe v1.1.1 (055f50a6f1131f4e5c56cf259dd8816168fba329)
|
|
351
307
|
*/ function normalizeWindowsPath(input = '') {
|
|
@@ -749,6 +705,35 @@ function createRequest(context) {
|
|
|
749
705
|
return readable;
|
|
750
706
|
}
|
|
751
707
|
|
|
708
|
+
class RoutupError extends HTTPError {
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function isError(input) {
|
|
712
|
+
return input instanceof RoutupError;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Create an internal error object by
|
|
717
|
+
* - an existing error (accessible via cause property)
|
|
718
|
+
* - options
|
|
719
|
+
* - message
|
|
720
|
+
*
|
|
721
|
+
* @param input
|
|
722
|
+
*/ function createError(input) {
|
|
723
|
+
if (isError(input)) {
|
|
724
|
+
return input;
|
|
725
|
+
}
|
|
726
|
+
if (typeof input === 'string') {
|
|
727
|
+
return new RoutupError(input);
|
|
728
|
+
}
|
|
729
|
+
if (!isObject(input)) {
|
|
730
|
+
return new RoutupError();
|
|
731
|
+
}
|
|
732
|
+
return new RoutupError({
|
|
733
|
+
cause: input
|
|
734
|
+
}, input);
|
|
735
|
+
}
|
|
736
|
+
|
|
752
737
|
function setResponseCacheHeaders(res, options) {
|
|
753
738
|
options = options || {};
|
|
754
739
|
const cacheControls = [
|
|
@@ -857,6 +842,78 @@ function setResponseHeaderContentType(res, input, ifNotExists) {
|
|
|
857
842
|
}
|
|
858
843
|
}
|
|
859
844
|
|
|
845
|
+
async function sendStream(res, stream, next) {
|
|
846
|
+
if (isWebStream(stream)) {
|
|
847
|
+
return stream.pipeTo(new WritableStream({
|
|
848
|
+
write (chunk) {
|
|
849
|
+
res.write(chunk);
|
|
850
|
+
}
|
|
851
|
+
})).then(()=>{
|
|
852
|
+
if (next) {
|
|
853
|
+
return next();
|
|
854
|
+
}
|
|
855
|
+
res.end();
|
|
856
|
+
return Promise.resolve();
|
|
857
|
+
}).catch((err)=>{
|
|
858
|
+
if (next) {
|
|
859
|
+
return next(err);
|
|
860
|
+
}
|
|
861
|
+
return Promise.reject(err);
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
return new Promise((resolve, reject)=>{
|
|
865
|
+
stream.on('open', ()=>{
|
|
866
|
+
stream.pipe(res);
|
|
867
|
+
});
|
|
868
|
+
/* istanbul ignore next */ stream.on('error', (err)=>{
|
|
869
|
+
if (next) {
|
|
870
|
+
Promise.resolve().then(()=>next(err)).then(()=>resolve()).catch((e)=>reject(e));
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
res.end();
|
|
874
|
+
reject(err);
|
|
875
|
+
});
|
|
876
|
+
stream.on('close', ()=>{
|
|
877
|
+
if (next) {
|
|
878
|
+
Promise.resolve().then(()=>next()).then(()=>resolve()).catch((e)=>reject(e));
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
res.end();
|
|
882
|
+
resolve();
|
|
883
|
+
});
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
async function sendWebBlob(res, blob) {
|
|
888
|
+
setResponseHeaderContentType(res, blob.type);
|
|
889
|
+
await sendStream(res, blob.stream());
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
async function sendWebResponse(res, webResponse) {
|
|
893
|
+
if (webResponse.redirected) {
|
|
894
|
+
res.setHeader(HeaderName.LOCATION, webResponse.url);
|
|
895
|
+
}
|
|
896
|
+
if (webResponse.status) {
|
|
897
|
+
res.statusCode = webResponse.status;
|
|
898
|
+
}
|
|
899
|
+
if (webResponse.statusText) {
|
|
900
|
+
res.statusMessage = webResponse.statusText;
|
|
901
|
+
}
|
|
902
|
+
webResponse.headers.forEach((value, key)=>{
|
|
903
|
+
if (key === HeaderName.SET_COOKIE) {
|
|
904
|
+
res.appendHeader(key, splitCookiesString(value));
|
|
905
|
+
} else {
|
|
906
|
+
res.setHeader(key, value);
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
if (webResponse.body) {
|
|
910
|
+
await sendStream(res, webResponse.body);
|
|
911
|
+
return Promise.resolve();
|
|
912
|
+
}
|
|
913
|
+
res.end();
|
|
914
|
+
return Promise.resolve();
|
|
915
|
+
}
|
|
916
|
+
|
|
860
917
|
async function send(res, chunk) {
|
|
861
918
|
switch(typeof chunk){
|
|
862
919
|
case 'string':
|
|
@@ -868,11 +925,28 @@ async function send(res, chunk) {
|
|
|
868
925
|
case 'number':
|
|
869
926
|
case 'object':
|
|
870
927
|
{
|
|
871
|
-
if (
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
928
|
+
if (chunk !== null) {
|
|
929
|
+
if (chunk instanceof Error) {
|
|
930
|
+
throw chunk;
|
|
931
|
+
}
|
|
932
|
+
if (isStream(chunk)) {
|
|
933
|
+
await sendStream(res, chunk);
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
if (isWebBlob(chunk)) {
|
|
937
|
+
await sendWebBlob(res, chunk);
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
if (isWebResponse(chunk)) {
|
|
941
|
+
await sendWebResponse(res, chunk);
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
if (Buffer.isBuffer(chunk)) {
|
|
945
|
+
setResponseHeaderContentType(res, 'bin', true);
|
|
946
|
+
} else {
|
|
947
|
+
chunk = JSON.stringify(chunk);
|
|
948
|
+
setResponseHeaderContentType(res, 'application/json', true);
|
|
949
|
+
}
|
|
876
950
|
}
|
|
877
951
|
break;
|
|
878
952
|
}
|
|
@@ -904,7 +978,7 @@ async function send(res, chunk) {
|
|
|
904
978
|
const etagFn = findRouterOption('etag', useRequestRouterPath(res.req));
|
|
905
979
|
const chunkHash = await etagFn(chunk, encoding, len);
|
|
906
980
|
if (isResponseGone(res)) {
|
|
907
|
-
return
|
|
981
|
+
return;
|
|
908
982
|
}
|
|
909
983
|
if (typeof chunkHash === 'string') {
|
|
910
984
|
res.setHeader(HeaderName.ETag, chunkHash);
|
|
@@ -925,23 +999,22 @@ async function send(res, chunk) {
|
|
|
925
999
|
res.removeHeader(HeaderName.TRANSFER_ENCODING);
|
|
926
1000
|
}
|
|
927
1001
|
if (isResponseGone(res)) {
|
|
928
|
-
return
|
|
1002
|
+
return;
|
|
929
1003
|
}
|
|
930
|
-
if (res.req.method === 'HEAD') {
|
|
1004
|
+
if (res.req.method === 'HEAD' || res.req.method === 'head') {
|
|
931
1005
|
// skip body for HEAD
|
|
932
1006
|
res.end();
|
|
933
|
-
return
|
|
1007
|
+
return;
|
|
934
1008
|
}
|
|
935
1009
|
if (typeof chunk === 'undefined' || chunk === null) {
|
|
936
1010
|
res.end();
|
|
937
|
-
return
|
|
1011
|
+
return;
|
|
938
1012
|
}
|
|
939
1013
|
if (typeof encoding !== 'undefined') {
|
|
940
1014
|
res.end(chunk, encoding);
|
|
941
|
-
return
|
|
1015
|
+
return;
|
|
942
1016
|
}
|
|
943
1017
|
res.end(chunk);
|
|
944
|
-
return Promise.resolve();
|
|
945
1018
|
}
|
|
946
1019
|
|
|
947
1020
|
function sendAccepted(res, chunk) {
|
|
@@ -956,48 +1029,6 @@ function sendCreated(res, chunk) {
|
|
|
956
1029
|
return send(res, chunk);
|
|
957
1030
|
}
|
|
958
1031
|
|
|
959
|
-
async function sendStream(res, stream, next) {
|
|
960
|
-
if (isWebStream(stream)) {
|
|
961
|
-
return stream.pipeTo(new WritableStream({
|
|
962
|
-
write (chunk) {
|
|
963
|
-
res.write(chunk);
|
|
964
|
-
}
|
|
965
|
-
})).then(()=>{
|
|
966
|
-
if (next) {
|
|
967
|
-
return next();
|
|
968
|
-
}
|
|
969
|
-
res.end();
|
|
970
|
-
return Promise.resolve();
|
|
971
|
-
}).catch((err)=>{
|
|
972
|
-
if (next) {
|
|
973
|
-
return next(err);
|
|
974
|
-
}
|
|
975
|
-
return Promise.reject(err);
|
|
976
|
-
});
|
|
977
|
-
}
|
|
978
|
-
return new Promise((resolve, reject)=>{
|
|
979
|
-
stream.on('open', ()=>{
|
|
980
|
-
stream.pipe(res);
|
|
981
|
-
});
|
|
982
|
-
/* istanbul ignore next */ stream.on('error', (err)=>{
|
|
983
|
-
if (next) {
|
|
984
|
-
Promise.resolve().then(()=>next(err)).then(()=>resolve()).catch((e)=>reject(e));
|
|
985
|
-
return;
|
|
986
|
-
}
|
|
987
|
-
res.end();
|
|
988
|
-
reject(err);
|
|
989
|
-
});
|
|
990
|
-
stream.on('close', ()=>{
|
|
991
|
-
if (next) {
|
|
992
|
-
Promise.resolve().then(()=>next()).then(()=>resolve()).catch((e)=>reject(e));
|
|
993
|
-
return;
|
|
994
|
-
}
|
|
995
|
-
res.end();
|
|
996
|
-
resolve();
|
|
997
|
-
});
|
|
998
|
-
});
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
1032
|
async function sendFile(res, options, next) {
|
|
1002
1033
|
let stats;
|
|
1003
1034
|
try {
|
|
@@ -1087,35 +1118,6 @@ function sendRedirect(res, location, statusCode = 302) {
|
|
|
1087
1118
|
return send(res, html);
|
|
1088
1119
|
}
|
|
1089
1120
|
|
|
1090
|
-
function sendWebResponse(res, webResponse) {
|
|
1091
|
-
if (webResponse.redirected) {
|
|
1092
|
-
res.setHeader(HeaderName.LOCATION, webResponse.url);
|
|
1093
|
-
}
|
|
1094
|
-
if (webResponse.status) {
|
|
1095
|
-
res.statusCode = webResponse.status;
|
|
1096
|
-
}
|
|
1097
|
-
if (webResponse.statusText) {
|
|
1098
|
-
res.statusMessage = webResponse.statusText;
|
|
1099
|
-
}
|
|
1100
|
-
webResponse.headers.forEach((value, key)=>{
|
|
1101
|
-
if (key === HeaderName.SET_COOKIE) {
|
|
1102
|
-
res.appendHeader(key, splitCookiesString(value));
|
|
1103
|
-
} else {
|
|
1104
|
-
res.setHeader(key, value);
|
|
1105
|
-
}
|
|
1106
|
-
});
|
|
1107
|
-
if (webResponse.body) {
|
|
1108
|
-
return sendStream(res, webResponse.body);
|
|
1109
|
-
}
|
|
1110
|
-
res.end();
|
|
1111
|
-
return Promise.resolve();
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
function sendWebBlob(res, blob) {
|
|
1115
|
-
setResponseHeaderContentType(res, blob.type);
|
|
1116
|
-
return sendStream(res, blob.stream());
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
1121
|
function createResponse(request) {
|
|
1120
1122
|
let output;
|
|
1121
1123
|
let encoding;
|
|
@@ -1261,84 +1263,112 @@ function createResponse(request) {
|
|
|
1261
1263
|
return writable;
|
|
1262
1264
|
}
|
|
1263
1265
|
|
|
1264
|
-
function
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1266
|
+
function dispatch(event, target) {
|
|
1267
|
+
setRequestParams(event.request, event.params);
|
|
1268
|
+
setRequestMountPath(event.request, event.mountPath);
|
|
1269
|
+
setRequestRouterPath(event.request, event.routerPath);
|
|
1270
|
+
return new Promise((resolve, reject)=>{
|
|
1271
|
+
let handled = false;
|
|
1272
|
+
const unsubscribe = ()=>{
|
|
1273
|
+
event.response.off('close', done);
|
|
1274
|
+
event.response.off('error', done);
|
|
1275
|
+
};
|
|
1276
|
+
const shutdown = (dispatched, err)=>{
|
|
1277
|
+
if (handled) {
|
|
1278
|
+
return;
|
|
1279
|
+
}
|
|
1280
|
+
handled = true;
|
|
1281
|
+
unsubscribe();
|
|
1282
|
+
if (err) {
|
|
1283
|
+
reject(createError(err));
|
|
1284
|
+
} else {
|
|
1285
|
+
resolve(dispatched);
|
|
1286
|
+
}
|
|
1287
|
+
};
|
|
1288
|
+
const done = (err)=>shutdown(true, err);
|
|
1289
|
+
const next = (err)=>shutdown(false, err);
|
|
1290
|
+
event.response.once('close', done);
|
|
1291
|
+
event.response.once('error', done);
|
|
1292
|
+
const handle = async (data)=>{
|
|
1293
|
+
if (typeof data === 'undefined' || handled) {
|
|
1294
|
+
return false;
|
|
1295
|
+
}
|
|
1296
|
+
handled = true;
|
|
1297
|
+
unsubscribe();
|
|
1298
|
+
if (!event.dispatched) {
|
|
1299
|
+
await send(event.response, data);
|
|
1300
|
+
}
|
|
1301
|
+
return true;
|
|
1302
|
+
};
|
|
1303
|
+
try {
|
|
1304
|
+
const output = target(next);
|
|
1305
|
+
if (isPromise(output)) {
|
|
1306
|
+
output.then((r)=>handle(r)).then((resolved)=>{
|
|
1307
|
+
if (resolved) {
|
|
1308
|
+
resolve(true);
|
|
1309
|
+
}
|
|
1310
|
+
}).catch((e)=>reject(createError(e)));
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
Promise.resolve().then(()=>handle(output)).then((resolved)=>{
|
|
1314
|
+
if (resolved) {
|
|
1315
|
+
resolve(true);
|
|
1316
|
+
}
|
|
1317
|
+
}).catch((e)=>reject(createError(e)));
|
|
1318
|
+
} catch (error) {
|
|
1319
|
+
next(error);
|
|
1320
|
+
}
|
|
1321
|
+
});
|
|
1271
1322
|
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
mountPath: input.mountPath,
|
|
1276
|
-
error: input.error,
|
|
1277
|
-
routerPath: [
|
|
1278
|
-
...input.routerPath
|
|
1279
|
-
],
|
|
1280
|
-
params: cloneDispatcherMetaParams(input.params)
|
|
1281
|
-
};
|
|
1323
|
+
|
|
1324
|
+
function isDispatcherErrorEvent(event) {
|
|
1325
|
+
return typeof event.error !== 'undefined';
|
|
1282
1326
|
}
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1327
|
+
|
|
1328
|
+
class DispatchEvent {
|
|
1329
|
+
get dispatched() {
|
|
1330
|
+
return this._dispatched || this.response.writableEnded || this.response.headersSent;
|
|
1286
1331
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
return {};
|
|
1332
|
+
set dispatched(value) {
|
|
1333
|
+
this._dispatched = value;
|
|
1290
1334
|
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1335
|
+
constructor(context){
|
|
1336
|
+
this.request = context.request;
|
|
1337
|
+
this.response = context.response;
|
|
1338
|
+
this.method = context.method || MethodName.GET;
|
|
1339
|
+
this.methodsAllowed = [];
|
|
1340
|
+
this.mountPath = '/';
|
|
1341
|
+
this.params = {};
|
|
1342
|
+
this.path = context.path || '/';
|
|
1343
|
+
this.routerPath = [];
|
|
1344
|
+
this.next = nextPlaceholder;
|
|
1294
1345
|
}
|
|
1295
|
-
return output;
|
|
1296
1346
|
}
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
return {};
|
|
1300
|
-
}
|
|
1301
|
-
if (!t1 || !t2) {
|
|
1302
|
-
return t1 || t2;
|
|
1303
|
-
}
|
|
1304
|
-
const keys = Object.keys(t2);
|
|
1305
|
-
if (keys.length === 0) {
|
|
1306
|
-
return t1;
|
|
1307
|
-
}
|
|
1308
|
-
for(let i = 0; i < keys.length; i++){
|
|
1309
|
-
t1[keys[i]] = t2[keys[i]];
|
|
1310
|
-
}
|
|
1311
|
-
return t1;
|
|
1347
|
+
|
|
1348
|
+
class DispatchErrorEvent extends DispatchEvent {
|
|
1312
1349
|
}
|
|
1313
1350
|
|
|
1314
|
-
async function dispatchNodeRequest(router,
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
} catch (e) {
|
|
1330
|
-
if (!isResponseGone(res)) {
|
|
1331
|
-
if (isError(e)) {
|
|
1332
|
-
res.statusCode = e.statusCode;
|
|
1333
|
-
if (e.statusMessage) {
|
|
1334
|
-
res.statusMessage = e.statusMessage;
|
|
1335
|
-
}
|
|
1336
|
-
} else {
|
|
1337
|
-
res.statusCode = 500;
|
|
1338
|
-
}
|
|
1339
|
-
res.end();
|
|
1351
|
+
async function dispatchNodeRequest(router, request, response) {
|
|
1352
|
+
const event = new DispatchEvent({
|
|
1353
|
+
request,
|
|
1354
|
+
response,
|
|
1355
|
+
path: useRequestPath(request),
|
|
1356
|
+
method: toMethodName(request.method, MethodName.GET)
|
|
1357
|
+
});
|
|
1358
|
+
await router.dispatch(event);
|
|
1359
|
+
if (event.dispatched) {
|
|
1360
|
+
return;
|
|
1361
|
+
}
|
|
1362
|
+
if (event.error) {
|
|
1363
|
+
event.response.statusCode = event.error.statusCode;
|
|
1364
|
+
if (event.error.statusMessage) {
|
|
1365
|
+
event.response.statusMessage = event.error.statusMessage;
|
|
1340
1366
|
}
|
|
1367
|
+
event.response.end();
|
|
1368
|
+
return;
|
|
1341
1369
|
}
|
|
1370
|
+
event.response.statusCode = 404;
|
|
1371
|
+
event.response.end();
|
|
1342
1372
|
}
|
|
1343
1373
|
function createNodeDispatcher(router) {
|
|
1344
1374
|
return (req, res)=>{
|
|
@@ -1347,10 +1377,38 @@ function createNodeDispatcher(router) {
|
|
|
1347
1377
|
};
|
|
1348
1378
|
}
|
|
1349
1379
|
|
|
1350
|
-
|
|
1380
|
+
function transformHeaderToTuples(key, value) {
|
|
1381
|
+
const output = [];
|
|
1382
|
+
if (Array.isArray(value)) {
|
|
1383
|
+
for(let j = 0; j < value.length; j++){
|
|
1384
|
+
output.push([
|
|
1385
|
+
key,
|
|
1386
|
+
value[j]
|
|
1387
|
+
]);
|
|
1388
|
+
}
|
|
1389
|
+
} else if (value !== undefined) {
|
|
1390
|
+
output.push([
|
|
1391
|
+
key,
|
|
1392
|
+
String(value)
|
|
1393
|
+
]);
|
|
1394
|
+
}
|
|
1395
|
+
return output;
|
|
1396
|
+
}
|
|
1397
|
+
function transformHeadersToTuples(input) {
|
|
1398
|
+
const output = [];
|
|
1399
|
+
const keys = Object.keys(input);
|
|
1400
|
+
for(let i = 0; i < keys.length; i++){
|
|
1401
|
+
const key = keys[i].toLowerCase();
|
|
1402
|
+
output.push(...transformHeaderToTuples(key, input[key]));
|
|
1403
|
+
}
|
|
1404
|
+
return output;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
async function dispatchRawRequest(router, request) {
|
|
1408
|
+
const method = toMethodName(request.method, MethodName.GET);
|
|
1351
1409
|
const req = createRequest({
|
|
1352
1410
|
url: request.path,
|
|
1353
|
-
method
|
|
1411
|
+
method,
|
|
1354
1412
|
body: request.body,
|
|
1355
1413
|
headers: request.headers
|
|
1356
1414
|
});
|
|
@@ -1375,52 +1433,45 @@ async function dispatchRawRequest(router, request, options = {}) {
|
|
|
1375
1433
|
headers: getHeaders(),
|
|
1376
1434
|
body: res.body
|
|
1377
1435
|
});
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
status: 404
|
|
1390
|
-
});
|
|
1391
|
-
} catch (e) {
|
|
1392
|
-
if (options.throwOnError) {
|
|
1393
|
-
throw e;
|
|
1394
|
-
}
|
|
1395
|
-
if (isError(e)) {
|
|
1396
|
-
return createRawResponse({
|
|
1397
|
-
status: e.statusCode,
|
|
1398
|
-
statusMessage: e.statusMessage
|
|
1399
|
-
});
|
|
1400
|
-
}
|
|
1436
|
+
const event = new DispatchEvent({
|
|
1437
|
+
request: req,
|
|
1438
|
+
response: res,
|
|
1439
|
+
path: request.path,
|
|
1440
|
+
method
|
|
1441
|
+
});
|
|
1442
|
+
await router.dispatch(event);
|
|
1443
|
+
if (event.dispatched) {
|
|
1444
|
+
return createRawResponse();
|
|
1445
|
+
}
|
|
1446
|
+
if (event.error) {
|
|
1401
1447
|
return createRawResponse({
|
|
1402
|
-
status:
|
|
1448
|
+
status: event.error.statusCode,
|
|
1449
|
+
statusMessage: event.error.statusMessage
|
|
1403
1450
|
});
|
|
1404
1451
|
}
|
|
1452
|
+
return createRawResponse({
|
|
1453
|
+
status: 404
|
|
1454
|
+
});
|
|
1405
1455
|
}
|
|
1406
1456
|
function createRawDispatcher(router) {
|
|
1407
1457
|
return async (request)=>dispatchRawRequest(router, request);
|
|
1408
1458
|
}
|
|
1409
1459
|
|
|
1410
|
-
async function dispatchWebRequest(router, request
|
|
1460
|
+
async function dispatchWebRequest(router, request) {
|
|
1411
1461
|
const url = new URL(request.url);
|
|
1412
1462
|
const headers = {};
|
|
1413
1463
|
request.headers.forEach((value, key)=>{
|
|
1414
1464
|
headers[key] = value;
|
|
1415
1465
|
});
|
|
1466
|
+
const method = toMethodName(request.method, MethodName.GET);
|
|
1416
1467
|
const res = await dispatchRawRequest(router, {
|
|
1417
|
-
method
|
|
1468
|
+
method,
|
|
1418
1469
|
path: url.pathname + url.search,
|
|
1419
1470
|
headers,
|
|
1420
1471
|
body: request.body
|
|
1421
|
-
}
|
|
1472
|
+
});
|
|
1422
1473
|
let body;
|
|
1423
|
-
if (
|
|
1474
|
+
if (method === MethodName.HEAD || res.status === 304 || res.status === 101 || res.status === 204 || res.status === 205) {
|
|
1424
1475
|
body = null;
|
|
1425
1476
|
} else {
|
|
1426
1477
|
body = res.body;
|
|
@@ -1440,35 +1491,98 @@ var HandlerType;
|
|
|
1440
1491
|
HandlerType["CORE"] = "core";
|
|
1441
1492
|
HandlerType["ERROR"] = "error";
|
|
1442
1493
|
})(HandlerType || (HandlerType = {}));
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1494
|
+
const HandlerSymbol = Symbol.for('Handler');
|
|
1495
|
+
|
|
1496
|
+
var HookName;
|
|
1497
|
+
(function(HookName) {
|
|
1498
|
+
HookName["ERROR"] = "error";
|
|
1499
|
+
HookName["DISPATCH_START"] = "dispatchStart";
|
|
1500
|
+
HookName["DISPATCH_END"] = "dispatchEnd";
|
|
1501
|
+
HookName["CHILD_MATCH"] = "childMatch";
|
|
1502
|
+
HookName["CHILD_DISPATCH_BEFORE"] = "childDispatchBefore";
|
|
1503
|
+
HookName["CHILD_DISPATCH_AFTER"] = "childDispatchAfter";
|
|
1504
|
+
})(HookName || (HookName = {}));
|
|
1505
|
+
|
|
1506
|
+
class HookManager {
|
|
1507
|
+
// --------------------------------------------------
|
|
1508
|
+
addListener(name, fn) {
|
|
1509
|
+
this.items[name] = this.items[name] || [];
|
|
1510
|
+
this.items[name].push(fn);
|
|
1511
|
+
return ()=>{
|
|
1512
|
+
this.removeListener(name, fn);
|
|
1449
1513
|
};
|
|
1450
1514
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1515
|
+
removeListener(name, fn) {
|
|
1516
|
+
if (!this.items[name]) {
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
if (typeof fn === 'undefined') {
|
|
1520
|
+
delete this.items[name];
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
if (typeof fn === 'function') {
|
|
1524
|
+
const index = this.items[name].indexOf(fn);
|
|
1525
|
+
if (index !== -1) {
|
|
1526
|
+
this.items[name].splice(index, 1);
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
if (this.items[name].length === 0) {
|
|
1530
|
+
delete this.items[name];
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
// --------------------------------------------------
|
|
1534
|
+
/**
|
|
1535
|
+
* @throws RoutupError
|
|
1536
|
+
*
|
|
1537
|
+
* @param name
|
|
1538
|
+
* @param event
|
|
1539
|
+
*/ async trigger(name, event) {
|
|
1540
|
+
if (!this.items[name] || this.items[name].length === 0) {
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
try {
|
|
1544
|
+
for(let i = 0; i < this.items[name].length; i++){
|
|
1545
|
+
const hook = this.items[name][i];
|
|
1546
|
+
event.dispatched = await dispatch(event, (next)=>Promise.resolve().then(()=>{
|
|
1547
|
+
event.next = next;
|
|
1548
|
+
return this.triggerListener(name, event, hook);
|
|
1549
|
+
}).catch((err)=>next(err)));
|
|
1550
|
+
event.next = nextPlaceholder;
|
|
1551
|
+
if (event.dispatched) {
|
|
1552
|
+
if (event.error) {
|
|
1553
|
+
event.error = undefined;
|
|
1554
|
+
}
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
} catch (e) {
|
|
1559
|
+
event.error = e;
|
|
1560
|
+
if (!this.isErrorListenerHook(name)) {
|
|
1561
|
+
await this.trigger(HookName.ERROR, event);
|
|
1562
|
+
if (event.dispatched) {
|
|
1563
|
+
if (event.error) {
|
|
1564
|
+
event.error = undefined;
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
triggerListener(name, event, listener) {
|
|
1571
|
+
if (this.isErrorListenerHook(name)) {
|
|
1572
|
+
if (isDispatcherErrorEvent(event)) {
|
|
1573
|
+
return listener(event);
|
|
1574
|
+
}
|
|
1575
|
+
return undefined;
|
|
1576
|
+
}
|
|
1577
|
+
return listener(event);
|
|
1578
|
+
}
|
|
1579
|
+
isErrorListenerHook(input) {
|
|
1580
|
+
return input === HookName.ERROR;
|
|
1581
|
+
}
|
|
1582
|
+
// --------------------------------------------------
|
|
1583
|
+
constructor(){
|
|
1584
|
+
this.items = {};
|
|
1463
1585
|
}
|
|
1464
|
-
return {
|
|
1465
|
-
type: HandlerType.ERROR,
|
|
1466
|
-
...input
|
|
1467
|
-
};
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
function isHandler(input) {
|
|
1471
|
-
return isObject(input) && typeof input.fn === 'function' && typeof input.type === 'string';
|
|
1472
1586
|
}
|
|
1473
1587
|
|
|
1474
1588
|
function decodeParam(val) {
|
|
@@ -1526,93 +1640,59 @@ function isPath(input) {
|
|
|
1526
1640
|
return typeof input === 'string' || input instanceof RegExp;
|
|
1527
1641
|
}
|
|
1528
1642
|
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
class Layer {
|
|
1643
|
+
class Handler {
|
|
1532
1644
|
// --------------------------------------------------
|
|
1533
1645
|
get type() {
|
|
1534
|
-
return this.
|
|
1646
|
+
return this.config.type;
|
|
1535
1647
|
}
|
|
1536
1648
|
get path() {
|
|
1537
|
-
return this.
|
|
1649
|
+
return this.config.path;
|
|
1538
1650
|
}
|
|
1539
1651
|
get method() {
|
|
1540
|
-
|
|
1652
|
+
if (this._method || !this.config.method) {
|
|
1653
|
+
return this._method;
|
|
1654
|
+
}
|
|
1655
|
+
this._method = toMethodName(this.config.method);
|
|
1656
|
+
return this._method;
|
|
1541
1657
|
}
|
|
1542
1658
|
// --------------------------------------------------
|
|
1543
|
-
dispatch(event
|
|
1659
|
+
async dispatch(event) {
|
|
1544
1660
|
if (this.pathMatcher) {
|
|
1545
|
-
const pathMatch = this.pathMatcher.exec(
|
|
1661
|
+
const pathMatch = this.pathMatcher.exec(event.path);
|
|
1546
1662
|
if (pathMatch) {
|
|
1547
|
-
|
|
1663
|
+
event.params = {
|
|
1664
|
+
...event.params,
|
|
1665
|
+
...pathMatch.params
|
|
1666
|
+
};
|
|
1548
1667
|
}
|
|
1549
1668
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
const shutdown = (dispatched, err)=>{
|
|
1560
|
-
if (handled) {
|
|
1561
|
-
return;
|
|
1562
|
-
}
|
|
1563
|
-
handled = true;
|
|
1564
|
-
unsubscribe();
|
|
1565
|
-
if (err) {
|
|
1566
|
-
reject(createError(err));
|
|
1567
|
-
} else {
|
|
1568
|
-
resolve(dispatched);
|
|
1569
|
-
}
|
|
1570
|
-
};
|
|
1571
|
-
const onFinished = (err)=>shutdown(true, err);
|
|
1572
|
-
const onNext = (err)=>shutdown(false, err);
|
|
1573
|
-
event.res.once('close', onFinished);
|
|
1574
|
-
event.res.once('error', onFinished);
|
|
1575
|
-
const handle = (data)=>{
|
|
1576
|
-
if (typeof data === 'undefined' || handled) {
|
|
1577
|
-
return Promise.resolve();
|
|
1578
|
-
}
|
|
1579
|
-
handled = true;
|
|
1580
|
-
unsubscribe();
|
|
1581
|
-
return this.sendOutput(event.res, data).then(()=>resolve(true)).catch((e)=>reject(createError(e)));
|
|
1582
|
-
};
|
|
1583
|
-
try {
|
|
1584
|
-
let output;
|
|
1585
|
-
if (this.handler.type === HandlerType.ERROR) {
|
|
1586
|
-
if (meta.error) {
|
|
1587
|
-
output = this.handler.fn(meta.error, event.req, event.res, onNext);
|
|
1669
|
+
await this.hookManager.trigger(HookName.CHILD_DISPATCH_BEFORE, event);
|
|
1670
|
+
if (event.dispatched) {
|
|
1671
|
+
return Promise.resolve();
|
|
1672
|
+
}
|
|
1673
|
+
try {
|
|
1674
|
+
event.dispatched = await dispatch(event, (done)=>{
|
|
1675
|
+
if (this.config.type === HandlerType.ERROR) {
|
|
1676
|
+
if (event.error) {
|
|
1677
|
+
return this.config.fn(event.error, event.request, event.response, done);
|
|
1588
1678
|
}
|
|
1589
1679
|
} else {
|
|
1590
|
-
|
|
1680
|
+
return this.config.fn(event.request, event.response, done);
|
|
1591
1681
|
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1682
|
+
return undefined;
|
|
1683
|
+
});
|
|
1684
|
+
} catch (e) {
|
|
1685
|
+
if (isError(e)) {
|
|
1686
|
+
event.error = e;
|
|
1687
|
+
await this.hookManager.trigger(HookName.ERROR, event);
|
|
1688
|
+
if (event.dispatched) {
|
|
1689
|
+
event.error = undefined;
|
|
1690
|
+
} else {
|
|
1691
|
+
throw e;
|
|
1595
1692
|
}
|
|
1596
|
-
Promise.resolve().then(()=>handle(output)).catch((e)=>reject(createError(e)));
|
|
1597
|
-
} catch (error) {
|
|
1598
|
-
onNext(error);
|
|
1599
1693
|
}
|
|
1600
|
-
});
|
|
1601
|
-
}
|
|
1602
|
-
sendOutput(res, input) {
|
|
1603
|
-
if (input instanceof Error) {
|
|
1604
|
-
return Promise.reject(createError(input));
|
|
1605
|
-
}
|
|
1606
|
-
if (isStream(input)) {
|
|
1607
|
-
return sendStream(res, input);
|
|
1608
|
-
}
|
|
1609
|
-
if (isWebBlob(input)) {
|
|
1610
|
-
return sendWebBlob(res, input);
|
|
1611
|
-
}
|
|
1612
|
-
if (isWebResponse(input)) {
|
|
1613
|
-
return sendWebResponse(res, input);
|
|
1614
1694
|
}
|
|
1615
|
-
return
|
|
1695
|
+
return this.hookManager.trigger(HookName.CHILD_DISPATCH_AFTER, event);
|
|
1616
1696
|
}
|
|
1617
1697
|
// --------------------------------------------------
|
|
1618
1698
|
matchPath(path) {
|
|
@@ -1621,30 +1701,81 @@ class Layer {
|
|
|
1621
1701
|
}
|
|
1622
1702
|
return this.pathMatcher.test(path);
|
|
1623
1703
|
}
|
|
1704
|
+
setPath(path) {
|
|
1705
|
+
if (typeof path === 'string') {
|
|
1706
|
+
path = withLeadingSlash(path);
|
|
1707
|
+
}
|
|
1708
|
+
this.config.path = path;
|
|
1709
|
+
if (typeof path === 'undefined') {
|
|
1710
|
+
this.pathMatcher = undefined;
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
this.pathMatcher = new PathMatcher(path, {
|
|
1714
|
+
end: !!this.config.method
|
|
1715
|
+
});
|
|
1716
|
+
}
|
|
1717
|
+
// --------------------------------------------------
|
|
1624
1718
|
matchMethod(method) {
|
|
1625
|
-
|
|
1626
|
-
|
|
1719
|
+
return !this.method || method === this.method || method === MethodName.HEAD && this.method === MethodName.GET;
|
|
1720
|
+
}
|
|
1721
|
+
setMethod(input) {
|
|
1722
|
+
const method = toMethodName(input);
|
|
1723
|
+
this.config.method = method;
|
|
1724
|
+
this._method = method;
|
|
1725
|
+
}
|
|
1726
|
+
// --------------------------------------------------
|
|
1727
|
+
mountHooks() {
|
|
1728
|
+
if (this.config.onBefore) {
|
|
1729
|
+
this.hookManager.addListener(HookName.CHILD_DISPATCH_BEFORE, this.config.onBefore);
|
|
1627
1730
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1731
|
+
if (this.config.onAfter) {
|
|
1732
|
+
this.hookManager.addListener(HookName.CHILD_DISPATCH_AFTER, this.config.onAfter);
|
|
1733
|
+
}
|
|
1734
|
+
if (this.config.onError) {
|
|
1735
|
+
this.hookManager.addListener(HookName.ERROR, this.config.onError);
|
|
1631
1736
|
}
|
|
1632
|
-
return name === MethodName.HEAD && this.method === MethodName.GET;
|
|
1633
1737
|
}
|
|
1634
1738
|
// --------------------------------------------------
|
|
1635
1739
|
constructor(handler){
|
|
1636
|
-
this['@instanceof'] =
|
|
1637
|
-
this.
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1740
|
+
this['@instanceof'] = HandlerSymbol;
|
|
1741
|
+
this.config = handler;
|
|
1742
|
+
this.hookManager = new HookManager();
|
|
1743
|
+
this.mountHooks();
|
|
1744
|
+
this.setPath(handler.path);
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
function coreHandler(input) {
|
|
1749
|
+
if (typeof input === 'function') {
|
|
1750
|
+
return new Handler({
|
|
1751
|
+
type: HandlerType.CORE,
|
|
1752
|
+
fn: input
|
|
1753
|
+
});
|
|
1754
|
+
}
|
|
1755
|
+
return new Handler({
|
|
1756
|
+
type: HandlerType.CORE,
|
|
1757
|
+
...input
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
function errorHandler(input) {
|
|
1762
|
+
if (typeof input === 'function') {
|
|
1763
|
+
return new Handler({
|
|
1764
|
+
type: HandlerType.ERROR,
|
|
1765
|
+
fn: input
|
|
1766
|
+
});
|
|
1643
1767
|
}
|
|
1768
|
+
return new Handler({
|
|
1769
|
+
type: HandlerType.ERROR,
|
|
1770
|
+
...input
|
|
1771
|
+
});
|
|
1644
1772
|
}
|
|
1645
1773
|
|
|
1646
|
-
function
|
|
1647
|
-
return
|
|
1774
|
+
function isHandlerConfig(input) {
|
|
1775
|
+
return isObject(input) && typeof input.fn === 'function' && typeof input.type === 'string';
|
|
1776
|
+
}
|
|
1777
|
+
function isHandler(input) {
|
|
1778
|
+
return isInstance(input, HandlerSymbol);
|
|
1648
1779
|
}
|
|
1649
1780
|
|
|
1650
1781
|
function isPlugin(input) {
|
|
@@ -1668,6 +1799,15 @@ function transformRouterOptions(input) {
|
|
|
1668
1799
|
}
|
|
1669
1800
|
|
|
1670
1801
|
const RouterSymbol = Symbol.for('Router');
|
|
1802
|
+
var RouterPipelineStep;
|
|
1803
|
+
(function(RouterPipelineStep) {
|
|
1804
|
+
RouterPipelineStep[RouterPipelineStep["START"] = 0] = "START";
|
|
1805
|
+
RouterPipelineStep[RouterPipelineStep["LOOKUP"] = 1] = "LOOKUP";
|
|
1806
|
+
RouterPipelineStep[RouterPipelineStep["CHILD_BEFORE"] = 2] = "CHILD_BEFORE";
|
|
1807
|
+
RouterPipelineStep[RouterPipelineStep["CHILD_DISPATCH"] = 3] = "CHILD_DISPATCH";
|
|
1808
|
+
RouterPipelineStep[RouterPipelineStep["CHILD_AFTER"] = 4] = "CHILD_AFTER";
|
|
1809
|
+
RouterPipelineStep[RouterPipelineStep["FINISH"] = 5] = "FINISH";
|
|
1810
|
+
})(RouterPipelineStep || (RouterPipelineStep = {}));
|
|
1671
1811
|
|
|
1672
1812
|
let nextId = 0;
|
|
1673
1813
|
function generateRouterID() {
|
|
@@ -1679,102 +1819,187 @@ function isRouterInstance(input) {
|
|
|
1679
1819
|
|
|
1680
1820
|
class Router {
|
|
1681
1821
|
// --------------------------------------------------
|
|
1822
|
+
matchPath(path) {
|
|
1823
|
+
if (this.pathMatcher) {
|
|
1824
|
+
return this.pathMatcher.test(path);
|
|
1825
|
+
}
|
|
1826
|
+
return true;
|
|
1827
|
+
}
|
|
1682
1828
|
setPath(value) {
|
|
1683
|
-
if (value === '/' ||
|
|
1829
|
+
if (value === '/' || typeof value === 'undefined') {
|
|
1830
|
+
this.pathMatcher = undefined;
|
|
1684
1831
|
return;
|
|
1685
1832
|
}
|
|
1686
|
-
let path;
|
|
1687
1833
|
if (typeof value === 'string') {
|
|
1688
|
-
|
|
1834
|
+
this.pathMatcher = new PathMatcher(withLeadingSlash(withoutTrailingSlash(`${value}`)), {
|
|
1835
|
+
end: false
|
|
1836
|
+
});
|
|
1689
1837
|
} else {
|
|
1690
|
-
|
|
1838
|
+
this.pathMatcher = new PathMatcher(value, {
|
|
1839
|
+
end: false
|
|
1840
|
+
});
|
|
1691
1841
|
}
|
|
1692
|
-
this.pathMatcher = new PathMatcher(path, {
|
|
1693
|
-
end: false
|
|
1694
|
-
});
|
|
1695
1842
|
}
|
|
1696
1843
|
// --------------------------------------------------
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1844
|
+
async executePipelineStep(context) {
|
|
1845
|
+
switch(context.step){
|
|
1846
|
+
case RouterPipelineStep.START:
|
|
1847
|
+
{
|
|
1848
|
+
return this.executePipelineStepStart(context);
|
|
1849
|
+
}
|
|
1850
|
+
case RouterPipelineStep.LOOKUP:
|
|
1851
|
+
{
|
|
1852
|
+
return this.executePipelineStepLookup(context);
|
|
1853
|
+
}
|
|
1854
|
+
case RouterPipelineStep.CHILD_BEFORE:
|
|
1855
|
+
{
|
|
1856
|
+
return this.executePipelineStepChildBefore(context);
|
|
1857
|
+
}
|
|
1858
|
+
case RouterPipelineStep.CHILD_DISPATCH:
|
|
1859
|
+
{
|
|
1860
|
+
return this.executePipelineStepChildDispatch(context);
|
|
1861
|
+
}
|
|
1862
|
+
case RouterPipelineStep.CHILD_AFTER:
|
|
1863
|
+
{
|
|
1864
|
+
return this.executePipelineStepChildAfter(context);
|
|
1865
|
+
}
|
|
1866
|
+
case RouterPipelineStep.FINISH:
|
|
1867
|
+
default:
|
|
1868
|
+
{
|
|
1869
|
+
return this.executePipelineStepFinish(context);
|
|
1870
|
+
}
|
|
1700
1871
|
}
|
|
1701
|
-
return true;
|
|
1702
1872
|
}
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
meta.mountPath = cleanDoubleSlashes(`${meta.mountPath}/${output.path}`);
|
|
1710
|
-
if (meta.path === output.path) {
|
|
1711
|
-
meta.path = '/';
|
|
1712
|
-
} else {
|
|
1713
|
-
meta.path = withLeadingSlash(meta.path.substring(output.path.length));
|
|
1714
|
-
}
|
|
1715
|
-
meta.params = {
|
|
1716
|
-
...meta.params,
|
|
1717
|
-
...output.params
|
|
1718
|
-
};
|
|
1873
|
+
async executePipelineStepStart(context) {
|
|
1874
|
+
return this.hookManager.trigger(HookName.DISPATCH_START, context.event).then(()=>{
|
|
1875
|
+
if (context.event.dispatched) {
|
|
1876
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1877
|
+
} else {
|
|
1878
|
+
context.step++;
|
|
1719
1879
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1880
|
+
return this.executePipelineStep(context);
|
|
1881
|
+
});
|
|
1882
|
+
}
|
|
1883
|
+
async executePipelineStepLookup(context) {
|
|
1884
|
+
if (context.event.dispatched || context.stackIndex >= this.stack.length) {
|
|
1885
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1886
|
+
return this.executePipelineStep(context);
|
|
1887
|
+
}
|
|
1888
|
+
let match;
|
|
1889
|
+
const item = this.stack[context.stackIndex];
|
|
1890
|
+
if (isHandler(item)) {
|
|
1891
|
+
if (context.event.error && item.type === HandlerType.CORE || !context.event.error && item.type === HandlerType.ERROR) {
|
|
1892
|
+
context.stackIndex++;
|
|
1893
|
+
return this.executePipelineStepLookup(context);
|
|
1894
|
+
}
|
|
1895
|
+
match = item.matchPath(context.event.path);
|
|
1896
|
+
if (match) {
|
|
1897
|
+
if (item.method) {
|
|
1898
|
+
context.event.methodsAllowed.push(item.method);
|
|
1731
1899
|
}
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
if (
|
|
1735
|
-
|
|
1736
|
-
}
|
|
1737
|
-
|
|
1738
|
-
allowedMethods.push(item.method);
|
|
1900
|
+
if (item.matchMethod(context.event.method)) {
|
|
1901
|
+
await this.hookManager.trigger(HookName.CHILD_MATCH, context.event);
|
|
1902
|
+
if (context.event.dispatched) {
|
|
1903
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1904
|
+
} else {
|
|
1905
|
+
context.step++;
|
|
1739
1906
|
}
|
|
1907
|
+
return this.executePipelineStep(context);
|
|
1740
1908
|
}
|
|
1741
|
-
} else if (isRouterInstance(item)) {
|
|
1742
|
-
match = item.matchPath(meta.path);
|
|
1743
1909
|
}
|
|
1744
|
-
|
|
1745
|
-
|
|
1910
|
+
context.stackIndex++;
|
|
1911
|
+
return this.executePipelineStepLookup(context);
|
|
1912
|
+
}
|
|
1913
|
+
match = item.matchPath(context.event.path);
|
|
1914
|
+
if (match) {
|
|
1915
|
+
await this.hookManager.trigger(HookName.CHILD_MATCH, context.event);
|
|
1916
|
+
if (context.event.dispatched) {
|
|
1917
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1918
|
+
} else {
|
|
1919
|
+
context.step++;
|
|
1746
1920
|
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1921
|
+
return this.executePipelineStep(context);
|
|
1922
|
+
}
|
|
1923
|
+
context.stackIndex++;
|
|
1924
|
+
return this.executePipelineStepLookup(context);
|
|
1925
|
+
}
|
|
1926
|
+
async executePipelineStepChildBefore(context) {
|
|
1927
|
+
return this.hookManager.trigger(HookName.CHILD_DISPATCH_BEFORE, context.event).then(()=>{
|
|
1928
|
+
if (context.event.dispatched) {
|
|
1929
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1930
|
+
} else {
|
|
1931
|
+
context.step++;
|
|
1750
1932
|
}
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1933
|
+
return this.executePipelineStep(context);
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
async executePipelineStepChildAfter(context) {
|
|
1937
|
+
return this.hookManager.trigger(HookName.CHILD_DISPATCH_AFTER, context.event).then(()=>{
|
|
1938
|
+
if (context.event.dispatched) {
|
|
1939
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1940
|
+
} else {
|
|
1941
|
+
context.step = RouterPipelineStep.LOOKUP;
|
|
1760
1942
|
}
|
|
1943
|
+
return this.executePipelineStep(context);
|
|
1944
|
+
});
|
|
1945
|
+
}
|
|
1946
|
+
async executePipelineStepChildDispatch(context) {
|
|
1947
|
+
if (context.event.dispatched || typeof this.stack[context.stackIndex] === 'undefined') {
|
|
1948
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1949
|
+
return this.executePipelineStep(context);
|
|
1950
|
+
}
|
|
1951
|
+
try {
|
|
1952
|
+
await this.stack[context.stackIndex].dispatch(context.event);
|
|
1953
|
+
} catch (e) {
|
|
1954
|
+
context.event.error = e;
|
|
1955
|
+
await this.hookManager.trigger(HookName.ERROR, context.event);
|
|
1761
1956
|
}
|
|
1762
|
-
|
|
1763
|
-
|
|
1957
|
+
context.stackIndex++;
|
|
1958
|
+
context.step++;
|
|
1959
|
+
return this.executePipelineStep(context);
|
|
1960
|
+
}
|
|
1961
|
+
async executePipelineStepFinish(context) {
|
|
1962
|
+
if (context.event.error || context.event.dispatched) {
|
|
1963
|
+
return this.hookManager.trigger(HookName.DISPATCH_END, context.event);
|
|
1764
1964
|
}
|
|
1765
|
-
if (event.
|
|
1766
|
-
if (
|
|
1767
|
-
|
|
1965
|
+
if (!context.event.dispatched && context.event.routerPath.length === 1 && context.event.method && context.event.method === MethodName.OPTIONS) {
|
|
1966
|
+
if (context.event.methodsAllowed.indexOf(MethodName.GET) !== -1) {
|
|
1967
|
+
context.event.methodsAllowed.push(MethodName.HEAD);
|
|
1768
1968
|
}
|
|
1769
|
-
distinctArray(
|
|
1770
|
-
const options =
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1969
|
+
distinctArray(context.event.methodsAllowed);
|
|
1970
|
+
const options = context.event.methodsAllowed.map((key)=>key.toUpperCase()).join(',');
|
|
1971
|
+
context.event.response.setHeader(HeaderName.ALLOW, options);
|
|
1972
|
+
await send(context.event.response, options);
|
|
1973
|
+
context.event.dispatched = true;
|
|
1974
|
+
}
|
|
1975
|
+
return this.hookManager.trigger(HookName.DISPATCH_END, context.event);
|
|
1976
|
+
}
|
|
1977
|
+
// --------------------------------------------------
|
|
1978
|
+
async dispatch(event) {
|
|
1979
|
+
if (this.pathMatcher) {
|
|
1980
|
+
const output = this.pathMatcher.exec(event.path);
|
|
1981
|
+
if (typeof output !== 'undefined') {
|
|
1982
|
+
event.mountPath = cleanDoubleSlashes(`${event.mountPath}/${output.path}`);
|
|
1983
|
+
if (event.path === output.path) {
|
|
1984
|
+
event.path = '/';
|
|
1985
|
+
} else {
|
|
1986
|
+
event.path = withLeadingSlash(event.path.substring(output.path.length));
|
|
1987
|
+
}
|
|
1988
|
+
event.params = {
|
|
1989
|
+
...event.params,
|
|
1990
|
+
...output.params
|
|
1991
|
+
};
|
|
1774
1992
|
}
|
|
1775
|
-
return true;
|
|
1776
1993
|
}
|
|
1777
|
-
|
|
1994
|
+
const context = {
|
|
1995
|
+
step: RouterPipelineStep.START,
|
|
1996
|
+
event,
|
|
1997
|
+
stackIndex: 0
|
|
1998
|
+
};
|
|
1999
|
+
event.routerPath.push(this.id);
|
|
2000
|
+
return this.executePipelineStepStart(context).then(()=>{
|
|
2001
|
+
context.event.routerPath.pop();
|
|
2002
|
+
});
|
|
1778
2003
|
}
|
|
1779
2004
|
delete(...input) {
|
|
1780
2005
|
this.useForMethod(MethodName.DELETE, ...input);
|
|
@@ -1806,33 +2031,40 @@ class Router {
|
|
|
1806
2031
|
}
|
|
1807
2032
|
// --------------------------------------------------
|
|
1808
2033
|
useForMethod(method, ...input) {
|
|
1809
|
-
|
|
1810
|
-
method
|
|
1811
|
-
};
|
|
2034
|
+
let path;
|
|
1812
2035
|
for(let i = 0; i < input.length; i++){
|
|
1813
2036
|
const element = input[i];
|
|
1814
2037
|
if (isPath(element)) {
|
|
1815
|
-
|
|
2038
|
+
path = element;
|
|
1816
2039
|
continue;
|
|
1817
2040
|
}
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
2041
|
+
if (isHandlerConfig(element)) {
|
|
2042
|
+
if (path) {
|
|
2043
|
+
element.path = path;
|
|
2044
|
+
}
|
|
2045
|
+
element.method = method;
|
|
2046
|
+
this.use(element);
|
|
2047
|
+
continue;
|
|
2048
|
+
}
|
|
2049
|
+
if (isHandler(element)) {
|
|
2050
|
+
if (path) {
|
|
2051
|
+
element.setPath(path);
|
|
2052
|
+
}
|
|
2053
|
+
element.setMethod(method);
|
|
2054
|
+
this.use(element);
|
|
2055
|
+
}
|
|
1822
2056
|
}
|
|
1823
2057
|
}
|
|
1824
2058
|
use(...input) {
|
|
1825
|
-
const modifyPath = (input)=>{
|
|
1826
|
-
if (typeof input === 'string') {
|
|
1827
|
-
return withLeadingSlash(input);
|
|
1828
|
-
}
|
|
1829
|
-
return input;
|
|
1830
|
-
};
|
|
1831
2059
|
let path;
|
|
1832
2060
|
for(let i = 0; i < input.length; i++){
|
|
1833
2061
|
const item = input[i];
|
|
1834
2062
|
if (isPath(item)) {
|
|
1835
|
-
|
|
2063
|
+
if (typeof item === 'string') {
|
|
2064
|
+
path = withLeadingSlash(item);
|
|
2065
|
+
} else {
|
|
2066
|
+
path = item;
|
|
2067
|
+
}
|
|
1836
2068
|
continue;
|
|
1837
2069
|
}
|
|
1838
2070
|
if (isRouterInstance(item)) {
|
|
@@ -1842,9 +2074,14 @@ class Router {
|
|
|
1842
2074
|
this.stack.push(item);
|
|
1843
2075
|
continue;
|
|
1844
2076
|
}
|
|
2077
|
+
if (isHandlerConfig(item)) {
|
|
2078
|
+
item.path = path || item.path;
|
|
2079
|
+
this.stack.push(new Handler(item));
|
|
2080
|
+
continue;
|
|
2081
|
+
}
|
|
1845
2082
|
if (isHandler(item)) {
|
|
1846
|
-
item.path
|
|
1847
|
-
this.stack.push(
|
|
2083
|
+
item.setPath(path || item.path);
|
|
2084
|
+
this.stack.push(item);
|
|
1848
2085
|
continue;
|
|
1849
2086
|
}
|
|
1850
2087
|
if (isPlugin(item)) {
|
|
@@ -1873,6 +2110,17 @@ class Router {
|
|
|
1873
2110
|
}
|
|
1874
2111
|
return this;
|
|
1875
2112
|
}
|
|
2113
|
+
on(name, fn) {
|
|
2114
|
+
return this.hookManager.addListener(name, fn);
|
|
2115
|
+
}
|
|
2116
|
+
off(name, fn) {
|
|
2117
|
+
if (typeof fn === 'undefined') {
|
|
2118
|
+
this.hookManager.removeListener(name);
|
|
2119
|
+
return this;
|
|
2120
|
+
}
|
|
2121
|
+
this.hookManager.removeListener(name, fn);
|
|
2122
|
+
return this;
|
|
2123
|
+
}
|
|
1876
2124
|
// --------------------------------------------------
|
|
1877
2125
|
constructor(options = {}){
|
|
1878
2126
|
this['@instanceof'] = RouterSymbol;
|
|
@@ -1883,10 +2131,11 @@ class Router {
|
|
|
1883
2131
|
*/ this.stack = [];
|
|
1884
2132
|
this.id = generateRouterID();
|
|
1885
2133
|
this.name = options.name;
|
|
2134
|
+
this.hookManager = new HookManager();
|
|
1886
2135
|
this.setPath(options.path);
|
|
1887
2136
|
setRouterOptions(this.id, transformRouterOptions(options));
|
|
1888
2137
|
}
|
|
1889
2138
|
}
|
|
1890
2139
|
|
|
1891
|
-
export {
|
|
2140
|
+
export { DispatchErrorEvent, DispatchEvent, Handler, HandlerSymbol, HandlerType, HeaderName, MethodName, PathMatcher, Router, RoutupError, appendResponseHeader, appendResponseHeaderDirective, coreHandler, createError, createNodeDispatcher, createRawDispatcher, createRequest, createResponse, createWebDispatcher, dispatch, dispatchNodeRequest, dispatchRawRequest, dispatchWebRequest, errorHandler, getRequestAcceptableCharset, getRequestAcceptableCharsets, getRequestAcceptableContentType, getRequestAcceptableContentTypes, getRequestAcceptableEncoding, getRequestAcceptableEncodings, getRequestAcceptableLanguage, getRequestAcceptableLanguages, getRequestHeader, getRequestHostName, getRequestIP, getRequestProtocol, isDispatcherErrorEvent, isError, isHandler, isHandlerConfig, isPath, isPlugin, isRequestCacheable, isResponseGone, matchRequestContentType, send, sendAccepted, sendCreated, sendFile, sendFormat, sendRedirect, sendStream, sendWebBlob, sendWebResponse, setRequestEnv, setRequestHeader, setRequestMountPath, setRequestParam, setRequestParams, setRequestRouterPath, setResponseCacheHeaders, setResponseContentTypeByFileName, setResponseHeaderAttachment, setResponseHeaderContentType, transformHeaderToTuples, transformHeadersToTuples, unsetRequestEnv, useRequestEnv, useRequestMountPath, useRequestNegotiator, useRequestParam, useRequestParams, useRequestPath, useRequestRouterPath };
|
|
1892
2141
|
//# sourceMappingURL=index.mjs.map
|