routup 3.0.0 → 3.1.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 +629 -377
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +620 -370
- 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 +6 -6
- 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.cjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var http = require('@ebec/http');
|
|
4
3
|
var smob = require('smob');
|
|
5
4
|
var buffer = require('buffer');
|
|
6
5
|
var uncrypto = require('uncrypto');
|
|
@@ -8,17 +7,18 @@ var proxyAddr = require('proxy-addr');
|
|
|
8
7
|
var mimeExplorer = require('mime-explorer');
|
|
9
8
|
var Negotiator = require('negotiator');
|
|
10
9
|
var readableStream = require('readable-stream');
|
|
10
|
+
var http = require('@ebec/http');
|
|
11
11
|
var pathToRegexp = require('path-to-regexp');
|
|
12
12
|
|
|
13
13
|
exports.MethodName = void 0;
|
|
14
14
|
(function(MethodName) {
|
|
15
|
-
MethodName["GET"] = "
|
|
16
|
-
MethodName["POST"] = "
|
|
17
|
-
MethodName["PUT"] = "
|
|
18
|
-
MethodName["PATCH"] = "
|
|
19
|
-
MethodName["DELETE"] = "
|
|
20
|
-
MethodName["OPTIONS"] = "
|
|
21
|
-
MethodName["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";
|
|
22
22
|
})(exports.MethodName || (exports.MethodName = {}));
|
|
23
23
|
exports.HeaderName = void 0;
|
|
24
24
|
(function(HeaderName) {
|
|
@@ -53,32 +53,6 @@ exports.HeaderName = void 0;
|
|
|
53
53
|
HeaderName["X_FORWARDED_PROTO"] = "x-forwarded-proto";
|
|
54
54
|
})(exports.HeaderName || (exports.HeaderName = {}));
|
|
55
55
|
|
|
56
|
-
class ErrorProxy extends http.HTTPError {
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function isError(input) {
|
|
60
|
-
return input instanceof ErrorProxy;
|
|
61
|
-
}
|
|
62
|
-
|
|
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;
|
|
73
|
-
}
|
|
74
|
-
if (typeof input === 'string') {
|
|
75
|
-
return new ErrorProxy(input);
|
|
76
|
-
}
|
|
77
|
-
return new ErrorProxy({
|
|
78
|
-
cause: input
|
|
79
|
-
}, input);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
56
|
function isRequestCacheable(req, modifiedTime) {
|
|
83
57
|
const modifiedSince = req.headers[exports.HeaderName.IF_MODIFIED_SINCE];
|
|
84
58
|
if (!modifiedSince) {
|
|
@@ -209,33 +183,6 @@ function setRequestHeader(req, name, value) {
|
|
|
209
183
|
return cookiesStrings;
|
|
210
184
|
}
|
|
211
185
|
|
|
212
|
-
function transformHeaderToTuples(key, value) {
|
|
213
|
-
const output = [];
|
|
214
|
-
if (Array.isArray(value)) {
|
|
215
|
-
for(let j = 0; j < value.length; j++){
|
|
216
|
-
output.push([
|
|
217
|
-
key,
|
|
218
|
-
value[j]
|
|
219
|
-
]);
|
|
220
|
-
}
|
|
221
|
-
} else if (value !== undefined) {
|
|
222
|
-
output.push([
|
|
223
|
-
key,
|
|
224
|
-
String(value)
|
|
225
|
-
]);
|
|
226
|
-
}
|
|
227
|
-
return output;
|
|
228
|
-
}
|
|
229
|
-
function transformHeadersToTuples(input) {
|
|
230
|
-
const output = [];
|
|
231
|
-
const keys = Object.keys(input);
|
|
232
|
-
for(let i = 0; i < keys.length; i++){
|
|
233
|
-
const key = keys[i].toLowerCase();
|
|
234
|
-
output.push(...transformHeaderToTuples(key, input[key]));
|
|
235
|
-
}
|
|
236
|
-
return output;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
186
|
function isObject(item) {
|
|
240
187
|
return !!item && typeof item === 'object' && !Array.isArray(item);
|
|
241
188
|
}
|
|
@@ -348,6 +295,15 @@ function getCharsetForMimeType(type) {
|
|
|
348
295
|
return undefined;
|
|
349
296
|
}
|
|
350
297
|
|
|
298
|
+
function toMethodName(input, alt) {
|
|
299
|
+
if (input) {
|
|
300
|
+
return input.toUpperCase();
|
|
301
|
+
}
|
|
302
|
+
return alt;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const nextPlaceholder = (_err)=>{};
|
|
306
|
+
|
|
351
307
|
/**
|
|
352
308
|
* Based on https://github.com/unjs/pathe v1.1.1 (055f50a6f1131f4e5c56cf259dd8816168fba329)
|
|
353
309
|
*/ function normalizeWindowsPath(input = '') {
|
|
@@ -751,6 +707,35 @@ function createRequest(context) {
|
|
|
751
707
|
return readable;
|
|
752
708
|
}
|
|
753
709
|
|
|
710
|
+
class RoutupError extends http.HTTPError {
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
function isError(input) {
|
|
714
|
+
return input instanceof RoutupError;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* Create an internal error object by
|
|
719
|
+
* - an existing error (accessible via cause property)
|
|
720
|
+
* - options
|
|
721
|
+
* - message
|
|
722
|
+
*
|
|
723
|
+
* @param input
|
|
724
|
+
*/ function createError(input) {
|
|
725
|
+
if (isError(input)) {
|
|
726
|
+
return input;
|
|
727
|
+
}
|
|
728
|
+
if (typeof input === 'string') {
|
|
729
|
+
return new RoutupError(input);
|
|
730
|
+
}
|
|
731
|
+
if (!isObject(input)) {
|
|
732
|
+
return new RoutupError();
|
|
733
|
+
}
|
|
734
|
+
return new RoutupError({
|
|
735
|
+
cause: input
|
|
736
|
+
}, input);
|
|
737
|
+
}
|
|
738
|
+
|
|
754
739
|
function setResponseCacheHeaders(res, options) {
|
|
755
740
|
options = options || {};
|
|
756
741
|
const cacheControls = [
|
|
@@ -906,7 +891,7 @@ async function send(res, chunk) {
|
|
|
906
891
|
const etagFn = findRouterOption('etag', useRequestRouterPath(res.req));
|
|
907
892
|
const chunkHash = await etagFn(chunk, encoding, len);
|
|
908
893
|
if (isResponseGone(res)) {
|
|
909
|
-
return
|
|
894
|
+
return;
|
|
910
895
|
}
|
|
911
896
|
if (typeof chunkHash === 'string') {
|
|
912
897
|
res.setHeader(exports.HeaderName.ETag, chunkHash);
|
|
@@ -927,23 +912,22 @@ async function send(res, chunk) {
|
|
|
927
912
|
res.removeHeader(exports.HeaderName.TRANSFER_ENCODING);
|
|
928
913
|
}
|
|
929
914
|
if (isResponseGone(res)) {
|
|
930
|
-
return
|
|
915
|
+
return;
|
|
931
916
|
}
|
|
932
|
-
if (res.req.method === 'HEAD') {
|
|
917
|
+
if (res.req.method === 'HEAD' || res.req.method === 'head') {
|
|
933
918
|
// skip body for HEAD
|
|
934
919
|
res.end();
|
|
935
|
-
return
|
|
920
|
+
return;
|
|
936
921
|
}
|
|
937
922
|
if (typeof chunk === 'undefined' || chunk === null) {
|
|
938
923
|
res.end();
|
|
939
|
-
return
|
|
924
|
+
return;
|
|
940
925
|
}
|
|
941
926
|
if (typeof encoding !== 'undefined') {
|
|
942
927
|
res.end(chunk, encoding);
|
|
943
|
-
return
|
|
928
|
+
return;
|
|
944
929
|
}
|
|
945
930
|
res.end(chunk);
|
|
946
|
-
return Promise.resolve();
|
|
947
931
|
}
|
|
948
932
|
|
|
949
933
|
function sendAccepted(res, chunk) {
|
|
@@ -1089,7 +1073,7 @@ function sendRedirect(res, location, statusCode = 302) {
|
|
|
1089
1073
|
return send(res, html);
|
|
1090
1074
|
}
|
|
1091
1075
|
|
|
1092
|
-
function sendWebResponse(res, webResponse) {
|
|
1076
|
+
async function sendWebResponse(res, webResponse) {
|
|
1093
1077
|
if (webResponse.redirected) {
|
|
1094
1078
|
res.setHeader(exports.HeaderName.LOCATION, webResponse.url);
|
|
1095
1079
|
}
|
|
@@ -1107,15 +1091,16 @@ function sendWebResponse(res, webResponse) {
|
|
|
1107
1091
|
}
|
|
1108
1092
|
});
|
|
1109
1093
|
if (webResponse.body) {
|
|
1110
|
-
|
|
1094
|
+
await sendStream(res, webResponse.body);
|
|
1095
|
+
return Promise.resolve();
|
|
1111
1096
|
}
|
|
1112
1097
|
res.end();
|
|
1113
1098
|
return Promise.resolve();
|
|
1114
1099
|
}
|
|
1115
1100
|
|
|
1116
|
-
function sendWebBlob(res, blob) {
|
|
1101
|
+
async function sendWebBlob(res, blob) {
|
|
1117
1102
|
setResponseHeaderContentType(res, blob.type);
|
|
1118
|
-
|
|
1103
|
+
await sendStream(res, blob.stream());
|
|
1119
1104
|
}
|
|
1120
1105
|
|
|
1121
1106
|
function createResponse(request) {
|
|
@@ -1263,84 +1248,130 @@ function createResponse(request) {
|
|
|
1263
1248
|
return writable;
|
|
1264
1249
|
}
|
|
1265
1250
|
|
|
1266
|
-
function
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
params: input.params || {},
|
|
1270
|
-
path: input.path || '/',
|
|
1271
|
-
routerPath: []
|
|
1272
|
-
};
|
|
1273
|
-
}
|
|
1274
|
-
function cloneDispatcherMeta(input) {
|
|
1275
|
-
return {
|
|
1276
|
-
path: input.path,
|
|
1277
|
-
mountPath: input.mountPath,
|
|
1278
|
-
error: input.error,
|
|
1279
|
-
routerPath: [
|
|
1280
|
-
...input.routerPath
|
|
1281
|
-
],
|
|
1282
|
-
params: cloneDispatcherMetaParams(input.params)
|
|
1283
|
-
};
|
|
1284
|
-
}
|
|
1285
|
-
function cloneDispatcherMetaParams(input) {
|
|
1286
|
-
if (typeof input === 'undefined') {
|
|
1287
|
-
return {};
|
|
1251
|
+
async function sendData(event, chunk) {
|
|
1252
|
+
if (chunk instanceof Error) {
|
|
1253
|
+
return Promise.reject(createError(chunk));
|
|
1288
1254
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
return
|
|
1255
|
+
if (isStream(chunk)) {
|
|
1256
|
+
await sendStream(event.response, chunk);
|
|
1257
|
+
return Promise.resolve();
|
|
1292
1258
|
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1259
|
+
if (isWebBlob(chunk)) {
|
|
1260
|
+
await sendWebBlob(event.response, chunk);
|
|
1261
|
+
return Promise.resolve();
|
|
1296
1262
|
}
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
if (!t1 && !t2) {
|
|
1301
|
-
return {};
|
|
1263
|
+
if (isWebResponse(chunk)) {
|
|
1264
|
+
await sendWebResponse(event.response, chunk);
|
|
1265
|
+
return Promise.resolve();
|
|
1302
1266
|
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1267
|
+
return send(event.response, chunk);
|
|
1268
|
+
}
|
|
1269
|
+
function dispatch(event, target) {
|
|
1270
|
+
setRequestParams(event.request, event.params);
|
|
1271
|
+
setRequestMountPath(event.request, event.mountPath);
|
|
1272
|
+
setRequestRouterPath(event.request, event.routerPath);
|
|
1273
|
+
return new Promise((resolve, reject)=>{
|
|
1274
|
+
let handled = false;
|
|
1275
|
+
const unsubscribe = ()=>{
|
|
1276
|
+
event.response.off('close', done);
|
|
1277
|
+
event.response.off('error', done);
|
|
1278
|
+
};
|
|
1279
|
+
const shutdown = (dispatched, err)=>{
|
|
1280
|
+
if (handled) {
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
handled = true;
|
|
1284
|
+
unsubscribe();
|
|
1285
|
+
if (err) {
|
|
1286
|
+
reject(createError(err));
|
|
1287
|
+
} else {
|
|
1288
|
+
resolve(dispatched);
|
|
1289
|
+
}
|
|
1290
|
+
};
|
|
1291
|
+
const done = (err)=>shutdown(true, err);
|
|
1292
|
+
const next = (err)=>shutdown(false, err);
|
|
1293
|
+
event.response.once('close', done);
|
|
1294
|
+
event.response.once('error', done);
|
|
1295
|
+
const handle = async (data)=>{
|
|
1296
|
+
if (typeof data === 'undefined' || handled) {
|
|
1297
|
+
return false;
|
|
1298
|
+
}
|
|
1299
|
+
handled = true;
|
|
1300
|
+
unsubscribe();
|
|
1301
|
+
if (!event.dispatched) {
|
|
1302
|
+
await sendData(event, data);
|
|
1303
|
+
}
|
|
1304
|
+
return true;
|
|
1305
|
+
};
|
|
1306
|
+
try {
|
|
1307
|
+
const output = target(next);
|
|
1308
|
+
if (isPromise(output)) {
|
|
1309
|
+
output.then((r)=>handle(r)).then((resolved)=>{
|
|
1310
|
+
if (resolved) {
|
|
1311
|
+
resolve(true);
|
|
1312
|
+
}
|
|
1313
|
+
}).catch((e)=>reject(createError(e)));
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
Promise.resolve().then(()=>handle(output)).then((resolved)=>{
|
|
1317
|
+
if (resolved) {
|
|
1318
|
+
resolve(true);
|
|
1319
|
+
}
|
|
1320
|
+
}).catch((e)=>reject(createError(e)));
|
|
1321
|
+
} catch (error) {
|
|
1322
|
+
next(error);
|
|
1323
|
+
}
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
function isDispatcherErrorEvent(event) {
|
|
1328
|
+
return typeof event.error !== 'undefined';
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
class DispatchEvent {
|
|
1332
|
+
get dispatched() {
|
|
1333
|
+
return this._dispatched || this.response.writableEnded || this.response.headersSent;
|
|
1305
1334
|
}
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
return t1;
|
|
1335
|
+
set dispatched(value) {
|
|
1336
|
+
this._dispatched = value;
|
|
1309
1337
|
}
|
|
1310
|
-
|
|
1311
|
-
|
|
1338
|
+
constructor(context){
|
|
1339
|
+
this.request = context.request;
|
|
1340
|
+
this.response = context.response;
|
|
1341
|
+
this.method = context.method || exports.MethodName.GET;
|
|
1342
|
+
this.methodsAllowed = [];
|
|
1343
|
+
this.mountPath = '/';
|
|
1344
|
+
this.params = {};
|
|
1345
|
+
this.path = context.path || '/';
|
|
1346
|
+
this.routerPath = [];
|
|
1347
|
+
this.next = nextPlaceholder;
|
|
1312
1348
|
}
|
|
1313
|
-
return t1;
|
|
1314
1349
|
}
|
|
1315
1350
|
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
if (
|
|
1333
|
-
|
|
1334
|
-
res.statusCode = e.statusCode;
|
|
1335
|
-
if (e.statusMessage) {
|
|
1336
|
-
res.statusMessage = e.statusMessage;
|
|
1337
|
-
}
|
|
1338
|
-
} else {
|
|
1339
|
-
res.statusCode = 500;
|
|
1340
|
-
}
|
|
1341
|
-
res.end();
|
|
1351
|
+
class DispatchErrorEvent extends DispatchEvent {
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
async function dispatchNodeRequest(router, request, response) {
|
|
1355
|
+
const event = new DispatchEvent({
|
|
1356
|
+
request,
|
|
1357
|
+
response,
|
|
1358
|
+
path: useRequestPath(request),
|
|
1359
|
+
method: toMethodName(request.method, exports.MethodName.GET)
|
|
1360
|
+
});
|
|
1361
|
+
await router.dispatch(event);
|
|
1362
|
+
if (event.dispatched) {
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
if (event.error) {
|
|
1366
|
+
event.response.statusCode = event.error.statusCode;
|
|
1367
|
+
if (event.error.statusMessage) {
|
|
1368
|
+
event.response.statusMessage = event.error.statusMessage;
|
|
1342
1369
|
}
|
|
1370
|
+
event.response.end();
|
|
1371
|
+
return;
|
|
1343
1372
|
}
|
|
1373
|
+
event.response.statusCode = 404;
|
|
1374
|
+
event.response.end();
|
|
1344
1375
|
}
|
|
1345
1376
|
function createNodeDispatcher(router) {
|
|
1346
1377
|
return (req, res)=>{
|
|
@@ -1349,10 +1380,38 @@ function createNodeDispatcher(router) {
|
|
|
1349
1380
|
};
|
|
1350
1381
|
}
|
|
1351
1382
|
|
|
1352
|
-
|
|
1383
|
+
function transformHeaderToTuples(key, value) {
|
|
1384
|
+
const output = [];
|
|
1385
|
+
if (Array.isArray(value)) {
|
|
1386
|
+
for(let j = 0; j < value.length; j++){
|
|
1387
|
+
output.push([
|
|
1388
|
+
key,
|
|
1389
|
+
value[j]
|
|
1390
|
+
]);
|
|
1391
|
+
}
|
|
1392
|
+
} else if (value !== undefined) {
|
|
1393
|
+
output.push([
|
|
1394
|
+
key,
|
|
1395
|
+
String(value)
|
|
1396
|
+
]);
|
|
1397
|
+
}
|
|
1398
|
+
return output;
|
|
1399
|
+
}
|
|
1400
|
+
function transformHeadersToTuples(input) {
|
|
1401
|
+
const output = [];
|
|
1402
|
+
const keys = Object.keys(input);
|
|
1403
|
+
for(let i = 0; i < keys.length; i++){
|
|
1404
|
+
const key = keys[i].toLowerCase();
|
|
1405
|
+
output.push(...transformHeaderToTuples(key, input[key]));
|
|
1406
|
+
}
|
|
1407
|
+
return output;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
async function dispatchRawRequest(router, request) {
|
|
1411
|
+
const method = toMethodName(request.method, exports.MethodName.GET);
|
|
1353
1412
|
const req = createRequest({
|
|
1354
1413
|
url: request.path,
|
|
1355
|
-
method
|
|
1414
|
+
method,
|
|
1356
1415
|
body: request.body,
|
|
1357
1416
|
headers: request.headers
|
|
1358
1417
|
});
|
|
@@ -1377,52 +1436,45 @@ async function dispatchRawRequest(router, request, options = {}) {
|
|
|
1377
1436
|
headers: getHeaders(),
|
|
1378
1437
|
body: res.body
|
|
1379
1438
|
});
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
status: 404
|
|
1392
|
-
});
|
|
1393
|
-
} catch (e) {
|
|
1394
|
-
if (options.throwOnError) {
|
|
1395
|
-
throw e;
|
|
1396
|
-
}
|
|
1397
|
-
if (isError(e)) {
|
|
1398
|
-
return createRawResponse({
|
|
1399
|
-
status: e.statusCode,
|
|
1400
|
-
statusMessage: e.statusMessage
|
|
1401
|
-
});
|
|
1402
|
-
}
|
|
1439
|
+
const event = new DispatchEvent({
|
|
1440
|
+
request: req,
|
|
1441
|
+
response: res,
|
|
1442
|
+
path: request.path,
|
|
1443
|
+
method
|
|
1444
|
+
});
|
|
1445
|
+
await router.dispatch(event);
|
|
1446
|
+
if (event.dispatched) {
|
|
1447
|
+
return createRawResponse();
|
|
1448
|
+
}
|
|
1449
|
+
if (event.error) {
|
|
1403
1450
|
return createRawResponse({
|
|
1404
|
-
status:
|
|
1451
|
+
status: event.error.statusCode,
|
|
1452
|
+
statusMessage: event.error.statusMessage
|
|
1405
1453
|
});
|
|
1406
1454
|
}
|
|
1455
|
+
return createRawResponse({
|
|
1456
|
+
status: 404
|
|
1457
|
+
});
|
|
1407
1458
|
}
|
|
1408
1459
|
function createRawDispatcher(router) {
|
|
1409
1460
|
return async (request)=>dispatchRawRequest(router, request);
|
|
1410
1461
|
}
|
|
1411
1462
|
|
|
1412
|
-
async function dispatchWebRequest(router, request
|
|
1463
|
+
async function dispatchWebRequest(router, request) {
|
|
1413
1464
|
const url = new URL(request.url);
|
|
1414
1465
|
const headers = {};
|
|
1415
1466
|
request.headers.forEach((value, key)=>{
|
|
1416
1467
|
headers[key] = value;
|
|
1417
1468
|
});
|
|
1469
|
+
const method = toMethodName(request.method, exports.MethodName.GET);
|
|
1418
1470
|
const res = await dispatchRawRequest(router, {
|
|
1419
|
-
method
|
|
1471
|
+
method,
|
|
1420
1472
|
path: url.pathname + url.search,
|
|
1421
1473
|
headers,
|
|
1422
1474
|
body: request.body
|
|
1423
|
-
}
|
|
1475
|
+
});
|
|
1424
1476
|
let body;
|
|
1425
|
-
if (
|
|
1477
|
+
if (method === exports.MethodName.HEAD || res.status === 304 || res.status === 101 || res.status === 204 || res.status === 205) {
|
|
1426
1478
|
body = null;
|
|
1427
1479
|
} else {
|
|
1428
1480
|
body = res.body;
|
|
@@ -1442,35 +1494,98 @@ exports.HandlerType = void 0;
|
|
|
1442
1494
|
HandlerType["CORE"] = "core";
|
|
1443
1495
|
HandlerType["ERROR"] = "error";
|
|
1444
1496
|
})(exports.HandlerType || (exports.HandlerType = {}));
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1497
|
+
const HandlerSymbol = Symbol.for('Handler');
|
|
1498
|
+
|
|
1499
|
+
var HookName;
|
|
1500
|
+
(function(HookName) {
|
|
1501
|
+
HookName["ERROR"] = "error";
|
|
1502
|
+
HookName["DISPATCH_START"] = "dispatchStart";
|
|
1503
|
+
HookName["DISPATCH_END"] = "dispatchEnd";
|
|
1504
|
+
HookName["CHILD_MATCH"] = "childMatch";
|
|
1505
|
+
HookName["CHILD_DISPATCH_BEFORE"] = "childDispatchBefore";
|
|
1506
|
+
HookName["CHILD_DISPATCH_AFTER"] = "childDispatchAfter";
|
|
1507
|
+
})(HookName || (HookName = {}));
|
|
1508
|
+
|
|
1509
|
+
class HookManager {
|
|
1510
|
+
// --------------------------------------------------
|
|
1511
|
+
addListener(name, fn) {
|
|
1512
|
+
this.items[name] = this.items[name] || [];
|
|
1513
|
+
this.items[name].push(fn);
|
|
1514
|
+
return ()=>{
|
|
1515
|
+
this.removeListener(name, fn);
|
|
1451
1516
|
};
|
|
1452
1517
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1518
|
+
removeListener(name, fn) {
|
|
1519
|
+
if (!this.items[name]) {
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
if (typeof fn === 'undefined') {
|
|
1523
|
+
delete this.items[name];
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
if (typeof fn === 'function') {
|
|
1527
|
+
const index = this.items[name].indexOf(fn);
|
|
1528
|
+
if (index !== -1) {
|
|
1529
|
+
this.items[name].splice(index, 1);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
if (this.items[name].length === 0) {
|
|
1533
|
+
delete this.items[name];
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
// --------------------------------------------------
|
|
1537
|
+
/**
|
|
1538
|
+
* @throws RoutupError
|
|
1539
|
+
*
|
|
1540
|
+
* @param name
|
|
1541
|
+
* @param event
|
|
1542
|
+
*/ async trigger(name, event) {
|
|
1543
|
+
if (!this.items[name] || this.items[name].length === 0) {
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
try {
|
|
1547
|
+
for(let i = 0; i < this.items[name].length; i++){
|
|
1548
|
+
const hook = this.items[name][i];
|
|
1549
|
+
event.dispatched = await dispatch(event, (next)=>Promise.resolve().then(()=>{
|
|
1550
|
+
event.next = next;
|
|
1551
|
+
return this.triggerListener(name, event, hook);
|
|
1552
|
+
}).catch((err)=>next(err)));
|
|
1553
|
+
event.next = nextPlaceholder;
|
|
1554
|
+
if (event.dispatched) {
|
|
1555
|
+
if (event.error) {
|
|
1556
|
+
event.error = undefined;
|
|
1557
|
+
}
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
} catch (e) {
|
|
1562
|
+
event.error = e;
|
|
1563
|
+
if (!this.isErrorListenerHook(name)) {
|
|
1564
|
+
await this.trigger(HookName.ERROR, event);
|
|
1565
|
+
if (event.dispatched) {
|
|
1566
|
+
if (event.error) {
|
|
1567
|
+
event.error = undefined;
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
triggerListener(name, event, listener) {
|
|
1574
|
+
if (this.isErrorListenerHook(name)) {
|
|
1575
|
+
if (isDispatcherErrorEvent(event)) {
|
|
1576
|
+
return listener(event);
|
|
1577
|
+
}
|
|
1578
|
+
return undefined;
|
|
1579
|
+
}
|
|
1580
|
+
return listener(event);
|
|
1581
|
+
}
|
|
1582
|
+
isErrorListenerHook(input) {
|
|
1583
|
+
return input === HookName.ERROR;
|
|
1584
|
+
}
|
|
1585
|
+
// --------------------------------------------------
|
|
1586
|
+
constructor(){
|
|
1587
|
+
this.items = {};
|
|
1465
1588
|
}
|
|
1466
|
-
return {
|
|
1467
|
-
type: exports.HandlerType.ERROR,
|
|
1468
|
-
...input
|
|
1469
|
-
};
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1472
|
-
function isHandler(input) {
|
|
1473
|
-
return isObject(input) && typeof input.fn === 'function' && typeof input.type === 'string';
|
|
1474
1589
|
}
|
|
1475
1590
|
|
|
1476
1591
|
function decodeParam(val) {
|
|
@@ -1528,93 +1643,59 @@ function isPath(input) {
|
|
|
1528
1643
|
return typeof input === 'string' || input instanceof RegExp;
|
|
1529
1644
|
}
|
|
1530
1645
|
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
class Layer {
|
|
1646
|
+
class Handler {
|
|
1534
1647
|
// --------------------------------------------------
|
|
1535
1648
|
get type() {
|
|
1536
|
-
return this.
|
|
1649
|
+
return this.config.type;
|
|
1537
1650
|
}
|
|
1538
1651
|
get path() {
|
|
1539
|
-
return this.
|
|
1652
|
+
return this.config.path;
|
|
1540
1653
|
}
|
|
1541
1654
|
get method() {
|
|
1542
|
-
|
|
1655
|
+
if (this._method || !this.config.method) {
|
|
1656
|
+
return this._method;
|
|
1657
|
+
}
|
|
1658
|
+
this._method = toMethodName(this.config.method);
|
|
1659
|
+
return this._method;
|
|
1543
1660
|
}
|
|
1544
1661
|
// --------------------------------------------------
|
|
1545
|
-
dispatch(event
|
|
1662
|
+
async dispatch(event) {
|
|
1546
1663
|
if (this.pathMatcher) {
|
|
1547
|
-
const pathMatch = this.pathMatcher.exec(
|
|
1664
|
+
const pathMatch = this.pathMatcher.exec(event.path);
|
|
1548
1665
|
if (pathMatch) {
|
|
1549
|
-
|
|
1666
|
+
event.params = {
|
|
1667
|
+
...event.params,
|
|
1668
|
+
...pathMatch.params
|
|
1669
|
+
};
|
|
1550
1670
|
}
|
|
1551
1671
|
}
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
const shutdown = (dispatched, err)=>{
|
|
1562
|
-
if (handled) {
|
|
1563
|
-
return;
|
|
1564
|
-
}
|
|
1565
|
-
handled = true;
|
|
1566
|
-
unsubscribe();
|
|
1567
|
-
if (err) {
|
|
1568
|
-
reject(createError(err));
|
|
1569
|
-
} else {
|
|
1570
|
-
resolve(dispatched);
|
|
1571
|
-
}
|
|
1572
|
-
};
|
|
1573
|
-
const onFinished = (err)=>shutdown(true, err);
|
|
1574
|
-
const onNext = (err)=>shutdown(false, err);
|
|
1575
|
-
event.res.once('close', onFinished);
|
|
1576
|
-
event.res.once('error', onFinished);
|
|
1577
|
-
const handle = (data)=>{
|
|
1578
|
-
if (typeof data === 'undefined' || handled) {
|
|
1579
|
-
return Promise.resolve();
|
|
1580
|
-
}
|
|
1581
|
-
handled = true;
|
|
1582
|
-
unsubscribe();
|
|
1583
|
-
return this.sendOutput(event.res, data).then(()=>resolve(true)).catch((e)=>reject(createError(e)));
|
|
1584
|
-
};
|
|
1585
|
-
try {
|
|
1586
|
-
let output;
|
|
1587
|
-
if (this.handler.type === exports.HandlerType.ERROR) {
|
|
1588
|
-
if (meta.error) {
|
|
1589
|
-
output = this.handler.fn(meta.error, event.req, event.res, onNext);
|
|
1672
|
+
await this.hookManager.trigger(HookName.CHILD_DISPATCH_BEFORE, event);
|
|
1673
|
+
if (event.dispatched) {
|
|
1674
|
+
return Promise.resolve();
|
|
1675
|
+
}
|
|
1676
|
+
try {
|
|
1677
|
+
event.dispatched = await dispatch(event, (done)=>{
|
|
1678
|
+
if (this.config.type === exports.HandlerType.ERROR) {
|
|
1679
|
+
if (event.error) {
|
|
1680
|
+
return this.config.fn(event.error, event.request, event.response, done);
|
|
1590
1681
|
}
|
|
1591
1682
|
} else {
|
|
1592
|
-
|
|
1683
|
+
return this.config.fn(event.request, event.response, done);
|
|
1593
1684
|
}
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1685
|
+
return undefined;
|
|
1686
|
+
});
|
|
1687
|
+
} catch (e) {
|
|
1688
|
+
if (isError(e)) {
|
|
1689
|
+
event.error = e;
|
|
1690
|
+
await this.hookManager.trigger(HookName.ERROR, event);
|
|
1691
|
+
if (event.dispatched) {
|
|
1692
|
+
event.error = undefined;
|
|
1693
|
+
} else {
|
|
1694
|
+
throw e;
|
|
1597
1695
|
}
|
|
1598
|
-
Promise.resolve().then(()=>handle(output)).catch((e)=>reject(createError(e)));
|
|
1599
|
-
} catch (error) {
|
|
1600
|
-
onNext(error);
|
|
1601
1696
|
}
|
|
1602
|
-
});
|
|
1603
|
-
}
|
|
1604
|
-
sendOutput(res, input) {
|
|
1605
|
-
if (input instanceof Error) {
|
|
1606
|
-
return Promise.reject(createError(input));
|
|
1607
|
-
}
|
|
1608
|
-
if (isStream(input)) {
|
|
1609
|
-
return sendStream(res, input);
|
|
1610
1697
|
}
|
|
1611
|
-
|
|
1612
|
-
return sendWebBlob(res, input);
|
|
1613
|
-
}
|
|
1614
|
-
if (isWebResponse(input)) {
|
|
1615
|
-
return sendWebResponse(res, input);
|
|
1616
|
-
}
|
|
1617
|
-
return send(res, input);
|
|
1698
|
+
return this.hookManager.trigger(HookName.CHILD_DISPATCH_AFTER, event);
|
|
1618
1699
|
}
|
|
1619
1700
|
// --------------------------------------------------
|
|
1620
1701
|
matchPath(path) {
|
|
@@ -1623,30 +1704,81 @@ class Layer {
|
|
|
1623
1704
|
}
|
|
1624
1705
|
return this.pathMatcher.test(path);
|
|
1625
1706
|
}
|
|
1707
|
+
setPath(path) {
|
|
1708
|
+
if (typeof path === 'string') {
|
|
1709
|
+
path = withLeadingSlash(path);
|
|
1710
|
+
}
|
|
1711
|
+
this.config.path = path;
|
|
1712
|
+
if (typeof path === 'undefined') {
|
|
1713
|
+
this.pathMatcher = undefined;
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
this.pathMatcher = new PathMatcher(path, {
|
|
1717
|
+
end: !!this.config.method
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
// --------------------------------------------------
|
|
1626
1721
|
matchMethod(method) {
|
|
1627
|
-
|
|
1628
|
-
|
|
1722
|
+
return !this.method || method === this.method || method === exports.MethodName.HEAD && this.method === exports.MethodName.GET;
|
|
1723
|
+
}
|
|
1724
|
+
setMethod(input) {
|
|
1725
|
+
const method = toMethodName(input);
|
|
1726
|
+
this.config.method = method;
|
|
1727
|
+
this._method = method;
|
|
1728
|
+
}
|
|
1729
|
+
// --------------------------------------------------
|
|
1730
|
+
mountHooks() {
|
|
1731
|
+
if (this.config.onBefore) {
|
|
1732
|
+
this.hookManager.addListener(HookName.CHILD_DISPATCH_BEFORE, this.config.onBefore);
|
|
1629
1733
|
}
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1734
|
+
if (this.config.onAfter) {
|
|
1735
|
+
this.hookManager.addListener(HookName.CHILD_DISPATCH_AFTER, this.config.onAfter);
|
|
1736
|
+
}
|
|
1737
|
+
if (this.config.onError) {
|
|
1738
|
+
this.hookManager.addListener(HookName.ERROR, this.config.onError);
|
|
1633
1739
|
}
|
|
1634
|
-
return name === exports.MethodName.HEAD && this.method === exports.MethodName.GET;
|
|
1635
1740
|
}
|
|
1636
1741
|
// --------------------------------------------------
|
|
1637
1742
|
constructor(handler){
|
|
1638
|
-
this['@instanceof'] =
|
|
1639
|
-
this.
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
});
|
|
1644
|
-
}
|
|
1743
|
+
this['@instanceof'] = HandlerSymbol;
|
|
1744
|
+
this.config = handler;
|
|
1745
|
+
this.hookManager = new HookManager();
|
|
1746
|
+
this.mountHooks();
|
|
1747
|
+
this.setPath(handler.path);
|
|
1645
1748
|
}
|
|
1646
1749
|
}
|
|
1647
1750
|
|
|
1648
|
-
function
|
|
1649
|
-
|
|
1751
|
+
function coreHandler(input) {
|
|
1752
|
+
if (typeof input === 'function') {
|
|
1753
|
+
return new Handler({
|
|
1754
|
+
type: exports.HandlerType.CORE,
|
|
1755
|
+
fn: input
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1758
|
+
return new Handler({
|
|
1759
|
+
type: exports.HandlerType.CORE,
|
|
1760
|
+
...input
|
|
1761
|
+
});
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
function errorHandler(input) {
|
|
1765
|
+
if (typeof input === 'function') {
|
|
1766
|
+
return new Handler({
|
|
1767
|
+
type: exports.HandlerType.ERROR,
|
|
1768
|
+
fn: input
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
return new Handler({
|
|
1772
|
+
type: exports.HandlerType.ERROR,
|
|
1773
|
+
...input
|
|
1774
|
+
});
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
function isHandlerConfig(input) {
|
|
1778
|
+
return isObject(input) && typeof input.fn === 'function' && typeof input.type === 'string';
|
|
1779
|
+
}
|
|
1780
|
+
function isHandler(input) {
|
|
1781
|
+
return isInstance(input, HandlerSymbol);
|
|
1650
1782
|
}
|
|
1651
1783
|
|
|
1652
1784
|
function isPlugin(input) {
|
|
@@ -1670,6 +1802,15 @@ function transformRouterOptions(input) {
|
|
|
1670
1802
|
}
|
|
1671
1803
|
|
|
1672
1804
|
const RouterSymbol = Symbol.for('Router');
|
|
1805
|
+
var RouterPipelineStep;
|
|
1806
|
+
(function(RouterPipelineStep) {
|
|
1807
|
+
RouterPipelineStep[RouterPipelineStep["START"] = 0] = "START";
|
|
1808
|
+
RouterPipelineStep[RouterPipelineStep["LOOKUP"] = 1] = "LOOKUP";
|
|
1809
|
+
RouterPipelineStep[RouterPipelineStep["CHILD_BEFORE"] = 2] = "CHILD_BEFORE";
|
|
1810
|
+
RouterPipelineStep[RouterPipelineStep["CHILD_DISPATCH"] = 3] = "CHILD_DISPATCH";
|
|
1811
|
+
RouterPipelineStep[RouterPipelineStep["CHILD_AFTER"] = 4] = "CHILD_AFTER";
|
|
1812
|
+
RouterPipelineStep[RouterPipelineStep["FINISH"] = 5] = "FINISH";
|
|
1813
|
+
})(RouterPipelineStep || (RouterPipelineStep = {}));
|
|
1673
1814
|
|
|
1674
1815
|
let nextId = 0;
|
|
1675
1816
|
function generateRouterID() {
|
|
@@ -1681,102 +1822,187 @@ function isRouterInstance(input) {
|
|
|
1681
1822
|
|
|
1682
1823
|
class Router {
|
|
1683
1824
|
// --------------------------------------------------
|
|
1825
|
+
matchPath(path) {
|
|
1826
|
+
if (this.pathMatcher) {
|
|
1827
|
+
return this.pathMatcher.test(path);
|
|
1828
|
+
}
|
|
1829
|
+
return true;
|
|
1830
|
+
}
|
|
1684
1831
|
setPath(value) {
|
|
1685
|
-
if (value === '/' ||
|
|
1832
|
+
if (value === '/' || typeof value === 'undefined') {
|
|
1833
|
+
this.pathMatcher = undefined;
|
|
1686
1834
|
return;
|
|
1687
1835
|
}
|
|
1688
|
-
let path;
|
|
1689
1836
|
if (typeof value === 'string') {
|
|
1690
|
-
|
|
1837
|
+
this.pathMatcher = new PathMatcher(withLeadingSlash(withoutTrailingSlash(`${value}`)), {
|
|
1838
|
+
end: false
|
|
1839
|
+
});
|
|
1691
1840
|
} else {
|
|
1692
|
-
|
|
1841
|
+
this.pathMatcher = new PathMatcher(value, {
|
|
1842
|
+
end: false
|
|
1843
|
+
});
|
|
1693
1844
|
}
|
|
1694
|
-
this.pathMatcher = new PathMatcher(path, {
|
|
1695
|
-
end: false
|
|
1696
|
-
});
|
|
1697
1845
|
}
|
|
1698
1846
|
// --------------------------------------------------
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1847
|
+
async executePipelineStep(context) {
|
|
1848
|
+
switch(context.step){
|
|
1849
|
+
case RouterPipelineStep.START:
|
|
1850
|
+
{
|
|
1851
|
+
return this.executePipelineStepStart(context);
|
|
1852
|
+
}
|
|
1853
|
+
case RouterPipelineStep.LOOKUP:
|
|
1854
|
+
{
|
|
1855
|
+
return this.executePipelineStepLookup(context);
|
|
1856
|
+
}
|
|
1857
|
+
case RouterPipelineStep.CHILD_BEFORE:
|
|
1858
|
+
{
|
|
1859
|
+
return this.executePipelineStepChildBefore(context);
|
|
1860
|
+
}
|
|
1861
|
+
case RouterPipelineStep.CHILD_DISPATCH:
|
|
1862
|
+
{
|
|
1863
|
+
return this.executePipelineStepChildDispatch(context);
|
|
1864
|
+
}
|
|
1865
|
+
case RouterPipelineStep.CHILD_AFTER:
|
|
1866
|
+
{
|
|
1867
|
+
return this.executePipelineStepChildAfter(context);
|
|
1868
|
+
}
|
|
1869
|
+
case RouterPipelineStep.FINISH:
|
|
1870
|
+
default:
|
|
1871
|
+
{
|
|
1872
|
+
return this.executePipelineStepFinish(context);
|
|
1873
|
+
}
|
|
1702
1874
|
}
|
|
1703
|
-
return true;
|
|
1704
1875
|
}
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
meta.mountPath = cleanDoubleSlashes(`${meta.mountPath}/${output.path}`);
|
|
1712
|
-
if (meta.path === output.path) {
|
|
1713
|
-
meta.path = '/';
|
|
1714
|
-
} else {
|
|
1715
|
-
meta.path = withLeadingSlash(meta.path.substring(output.path.length));
|
|
1716
|
-
}
|
|
1717
|
-
meta.params = {
|
|
1718
|
-
...meta.params,
|
|
1719
|
-
...output.params
|
|
1720
|
-
};
|
|
1876
|
+
async executePipelineStepStart(context) {
|
|
1877
|
+
return this.hookManager.trigger(HookName.DISPATCH_START, context.event).then(()=>{
|
|
1878
|
+
if (context.event.dispatched) {
|
|
1879
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1880
|
+
} else {
|
|
1881
|
+
context.step++;
|
|
1721
1882
|
}
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1883
|
+
return this.executePipelineStep(context);
|
|
1884
|
+
});
|
|
1885
|
+
}
|
|
1886
|
+
async executePipelineStepLookup(context) {
|
|
1887
|
+
if (context.event.dispatched || context.stackIndex >= this.stack.length) {
|
|
1888
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1889
|
+
return this.executePipelineStep(context);
|
|
1890
|
+
}
|
|
1891
|
+
let match;
|
|
1892
|
+
const item = this.stack[context.stackIndex];
|
|
1893
|
+
if (isHandler(item)) {
|
|
1894
|
+
if (context.event.error && item.type === exports.HandlerType.CORE || !context.event.error && item.type === exports.HandlerType.ERROR) {
|
|
1895
|
+
context.stackIndex++;
|
|
1896
|
+
return this.executePipelineStepLookup(context);
|
|
1897
|
+
}
|
|
1898
|
+
match = item.matchPath(context.event.path);
|
|
1899
|
+
if (match) {
|
|
1900
|
+
if (item.method) {
|
|
1901
|
+
context.event.methodsAllowed.push(item.method);
|
|
1733
1902
|
}
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
if (
|
|
1737
|
-
|
|
1738
|
-
}
|
|
1739
|
-
|
|
1740
|
-
allowedMethods.push(item.method);
|
|
1903
|
+
if (item.matchMethod(context.event.method)) {
|
|
1904
|
+
await this.hookManager.trigger(HookName.CHILD_MATCH, context.event);
|
|
1905
|
+
if (context.event.dispatched) {
|
|
1906
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1907
|
+
} else {
|
|
1908
|
+
context.step++;
|
|
1741
1909
|
}
|
|
1910
|
+
return this.executePipelineStep(context);
|
|
1742
1911
|
}
|
|
1743
|
-
} else if (isRouterInstance(item)) {
|
|
1744
|
-
match = item.matchPath(meta.path);
|
|
1745
1912
|
}
|
|
1746
|
-
|
|
1747
|
-
|
|
1913
|
+
context.stackIndex++;
|
|
1914
|
+
return this.executePipelineStepLookup(context);
|
|
1915
|
+
}
|
|
1916
|
+
match = item.matchPath(context.event.path);
|
|
1917
|
+
if (match) {
|
|
1918
|
+
await this.hookManager.trigger(HookName.CHILD_MATCH, context.event);
|
|
1919
|
+
if (context.event.dispatched) {
|
|
1920
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1921
|
+
} else {
|
|
1922
|
+
context.step++;
|
|
1748
1923
|
}
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1924
|
+
return this.executePipelineStep(context);
|
|
1925
|
+
}
|
|
1926
|
+
context.stackIndex++;
|
|
1927
|
+
return this.executePipelineStepLookup(context);
|
|
1928
|
+
}
|
|
1929
|
+
async executePipelineStepChildBefore(context) {
|
|
1930
|
+
return this.hookManager.trigger(HookName.CHILD_DISPATCH_BEFORE, context.event).then(()=>{
|
|
1931
|
+
if (context.event.dispatched) {
|
|
1932
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1933
|
+
} else {
|
|
1934
|
+
context.step++;
|
|
1752
1935
|
}
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1936
|
+
return this.executePipelineStep(context);
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1939
|
+
async executePipelineStepChildAfter(context) {
|
|
1940
|
+
return this.hookManager.trigger(HookName.CHILD_DISPATCH_AFTER, context.event).then(()=>{
|
|
1941
|
+
if (context.event.dispatched) {
|
|
1942
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1943
|
+
} else {
|
|
1944
|
+
context.step = RouterPipelineStep.LOOKUP;
|
|
1762
1945
|
}
|
|
1946
|
+
return this.executePipelineStep(context);
|
|
1947
|
+
});
|
|
1948
|
+
}
|
|
1949
|
+
async executePipelineStepChildDispatch(context) {
|
|
1950
|
+
if (context.event.dispatched || typeof this.stack[context.stackIndex] === 'undefined') {
|
|
1951
|
+
context.step = RouterPipelineStep.FINISH;
|
|
1952
|
+
return this.executePipelineStep(context);
|
|
1953
|
+
}
|
|
1954
|
+
try {
|
|
1955
|
+
await this.stack[context.stackIndex].dispatch(context.event);
|
|
1956
|
+
} catch (e) {
|
|
1957
|
+
context.event.error = e;
|
|
1958
|
+
await this.hookManager.trigger(HookName.ERROR, context.event);
|
|
1763
1959
|
}
|
|
1764
|
-
|
|
1765
|
-
|
|
1960
|
+
context.stackIndex++;
|
|
1961
|
+
context.step++;
|
|
1962
|
+
return this.executePipelineStep(context);
|
|
1963
|
+
}
|
|
1964
|
+
async executePipelineStepFinish(context) {
|
|
1965
|
+
if (context.event.error || context.event.dispatched) {
|
|
1966
|
+
return this.hookManager.trigger(HookName.DISPATCH_END, context.event);
|
|
1766
1967
|
}
|
|
1767
|
-
if (event.
|
|
1768
|
-
if (
|
|
1769
|
-
|
|
1968
|
+
if (!context.event.dispatched && context.event.routerPath.length === 1 && context.event.method && context.event.method === exports.MethodName.OPTIONS) {
|
|
1969
|
+
if (context.event.methodsAllowed.indexOf(exports.MethodName.GET) !== -1) {
|
|
1970
|
+
context.event.methodsAllowed.push(exports.MethodName.HEAD);
|
|
1770
1971
|
}
|
|
1771
|
-
smob.distinctArray(
|
|
1772
|
-
const options =
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1972
|
+
smob.distinctArray(context.event.methodsAllowed);
|
|
1973
|
+
const options = context.event.methodsAllowed.map((key)=>key.toUpperCase()).join(',');
|
|
1974
|
+
context.event.response.setHeader(exports.HeaderName.ALLOW, options);
|
|
1975
|
+
await send(context.event.response, options);
|
|
1976
|
+
context.event.dispatched = true;
|
|
1977
|
+
}
|
|
1978
|
+
return this.hookManager.trigger(HookName.DISPATCH_END, context.event);
|
|
1979
|
+
}
|
|
1980
|
+
// --------------------------------------------------
|
|
1981
|
+
async dispatch(event) {
|
|
1982
|
+
if (this.pathMatcher) {
|
|
1983
|
+
const output = this.pathMatcher.exec(event.path);
|
|
1984
|
+
if (typeof output !== 'undefined') {
|
|
1985
|
+
event.mountPath = cleanDoubleSlashes(`${event.mountPath}/${output.path}`);
|
|
1986
|
+
if (event.path === output.path) {
|
|
1987
|
+
event.path = '/';
|
|
1988
|
+
} else {
|
|
1989
|
+
event.path = withLeadingSlash(event.path.substring(output.path.length));
|
|
1990
|
+
}
|
|
1991
|
+
event.params = {
|
|
1992
|
+
...event.params,
|
|
1993
|
+
...output.params
|
|
1994
|
+
};
|
|
1776
1995
|
}
|
|
1777
|
-
return true;
|
|
1778
1996
|
}
|
|
1779
|
-
|
|
1997
|
+
const context = {
|
|
1998
|
+
step: RouterPipelineStep.START,
|
|
1999
|
+
event,
|
|
2000
|
+
stackIndex: 0
|
|
2001
|
+
};
|
|
2002
|
+
event.routerPath.push(this.id);
|
|
2003
|
+
return this.executePipelineStepStart(context).then(()=>{
|
|
2004
|
+
context.event.routerPath.pop();
|
|
2005
|
+
});
|
|
1780
2006
|
}
|
|
1781
2007
|
delete(...input) {
|
|
1782
2008
|
this.useForMethod(exports.MethodName.DELETE, ...input);
|
|
@@ -1808,33 +2034,40 @@ class Router {
|
|
|
1808
2034
|
}
|
|
1809
2035
|
// --------------------------------------------------
|
|
1810
2036
|
useForMethod(method, ...input) {
|
|
1811
|
-
|
|
1812
|
-
method
|
|
1813
|
-
};
|
|
2037
|
+
let path;
|
|
1814
2038
|
for(let i = 0; i < input.length; i++){
|
|
1815
2039
|
const element = input[i];
|
|
1816
2040
|
if (isPath(element)) {
|
|
1817
|
-
|
|
2041
|
+
path = element;
|
|
1818
2042
|
continue;
|
|
1819
2043
|
}
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
2044
|
+
if (isHandlerConfig(element)) {
|
|
2045
|
+
if (path) {
|
|
2046
|
+
element.path = path;
|
|
2047
|
+
}
|
|
2048
|
+
element.method = method;
|
|
2049
|
+
this.use(element);
|
|
2050
|
+
continue;
|
|
2051
|
+
}
|
|
2052
|
+
if (isHandler(element)) {
|
|
2053
|
+
if (path) {
|
|
2054
|
+
element.setPath(path);
|
|
2055
|
+
}
|
|
2056
|
+
element.setMethod(method);
|
|
2057
|
+
this.use(element);
|
|
2058
|
+
}
|
|
1824
2059
|
}
|
|
1825
2060
|
}
|
|
1826
2061
|
use(...input) {
|
|
1827
|
-
const modifyPath = (input)=>{
|
|
1828
|
-
if (typeof input === 'string') {
|
|
1829
|
-
return withLeadingSlash(input);
|
|
1830
|
-
}
|
|
1831
|
-
return input;
|
|
1832
|
-
};
|
|
1833
2062
|
let path;
|
|
1834
2063
|
for(let i = 0; i < input.length; i++){
|
|
1835
2064
|
const item = input[i];
|
|
1836
2065
|
if (isPath(item)) {
|
|
1837
|
-
|
|
2066
|
+
if (typeof item === 'string') {
|
|
2067
|
+
path = withLeadingSlash(item);
|
|
2068
|
+
} else {
|
|
2069
|
+
path = item;
|
|
2070
|
+
}
|
|
1838
2071
|
continue;
|
|
1839
2072
|
}
|
|
1840
2073
|
if (isRouterInstance(item)) {
|
|
@@ -1844,9 +2077,14 @@ class Router {
|
|
|
1844
2077
|
this.stack.push(item);
|
|
1845
2078
|
continue;
|
|
1846
2079
|
}
|
|
2080
|
+
if (isHandlerConfig(item)) {
|
|
2081
|
+
item.path = path || item.path;
|
|
2082
|
+
this.stack.push(new Handler(item));
|
|
2083
|
+
continue;
|
|
2084
|
+
}
|
|
1847
2085
|
if (isHandler(item)) {
|
|
1848
|
-
item.path
|
|
1849
|
-
this.stack.push(
|
|
2086
|
+
item.setPath(path || item.path);
|
|
2087
|
+
this.stack.push(item);
|
|
1850
2088
|
continue;
|
|
1851
2089
|
}
|
|
1852
2090
|
if (isPlugin(item)) {
|
|
@@ -1875,6 +2113,17 @@ class Router {
|
|
|
1875
2113
|
}
|
|
1876
2114
|
return this;
|
|
1877
2115
|
}
|
|
2116
|
+
on(name, fn) {
|
|
2117
|
+
return this.hookManager.addListener(name, fn);
|
|
2118
|
+
}
|
|
2119
|
+
off(name, fn) {
|
|
2120
|
+
if (typeof fn === 'undefined') {
|
|
2121
|
+
this.hookManager.removeListener(name);
|
|
2122
|
+
return this;
|
|
2123
|
+
}
|
|
2124
|
+
this.hookManager.removeListener(name, fn);
|
|
2125
|
+
return this;
|
|
2126
|
+
}
|
|
1878
2127
|
// --------------------------------------------------
|
|
1879
2128
|
constructor(options = {}){
|
|
1880
2129
|
this['@instanceof'] = RouterSymbol;
|
|
@@ -1885,20 +2134,21 @@ class Router {
|
|
|
1885
2134
|
*/ this.stack = [];
|
|
1886
2135
|
this.id = generateRouterID();
|
|
1887
2136
|
this.name = options.name;
|
|
2137
|
+
this.hookManager = new HookManager();
|
|
1888
2138
|
this.setPath(options.path);
|
|
1889
2139
|
setRouterOptions(this.id, transformRouterOptions(options));
|
|
1890
2140
|
}
|
|
1891
2141
|
}
|
|
1892
2142
|
|
|
1893
|
-
exports.
|
|
1894
|
-
exports.
|
|
2143
|
+
exports.DispatchErrorEvent = DispatchErrorEvent;
|
|
2144
|
+
exports.DispatchEvent = DispatchEvent;
|
|
2145
|
+
exports.Handler = Handler;
|
|
2146
|
+
exports.HandlerSymbol = HandlerSymbol;
|
|
1895
2147
|
exports.PathMatcher = PathMatcher;
|
|
1896
2148
|
exports.Router = Router;
|
|
2149
|
+
exports.RoutupError = RoutupError;
|
|
1897
2150
|
exports.appendResponseHeader = appendResponseHeader;
|
|
1898
2151
|
exports.appendResponseHeaderDirective = appendResponseHeaderDirective;
|
|
1899
|
-
exports.buildDispatcherMeta = buildDispatcherMeta;
|
|
1900
|
-
exports.cloneDispatcherMeta = cloneDispatcherMeta;
|
|
1901
|
-
exports.cloneDispatcherMetaParams = cloneDispatcherMetaParams;
|
|
1902
2152
|
exports.coreHandler = coreHandler;
|
|
1903
2153
|
exports.createError = createError;
|
|
1904
2154
|
exports.createNodeDispatcher = createNodeDispatcher;
|
|
@@ -1906,6 +2156,7 @@ exports.createRawDispatcher = createRawDispatcher;
|
|
|
1906
2156
|
exports.createRequest = createRequest;
|
|
1907
2157
|
exports.createResponse = createResponse;
|
|
1908
2158
|
exports.createWebDispatcher = createWebDispatcher;
|
|
2159
|
+
exports.dispatch = dispatch;
|
|
1909
2160
|
exports.dispatchNodeRequest = dispatchNodeRequest;
|
|
1910
2161
|
exports.dispatchRawRequest = dispatchRawRequest;
|
|
1911
2162
|
exports.dispatchWebRequest = dispatchWebRequest;
|
|
@@ -1922,16 +2173,15 @@ exports.getRequestHeader = getRequestHeader;
|
|
|
1922
2173
|
exports.getRequestHostName = getRequestHostName;
|
|
1923
2174
|
exports.getRequestIP = getRequestIP;
|
|
1924
2175
|
exports.getRequestProtocol = getRequestProtocol;
|
|
2176
|
+
exports.isDispatcherErrorEvent = isDispatcherErrorEvent;
|
|
1925
2177
|
exports.isError = isError;
|
|
1926
2178
|
exports.isHandler = isHandler;
|
|
1927
|
-
exports.
|
|
2179
|
+
exports.isHandlerConfig = isHandlerConfig;
|
|
1928
2180
|
exports.isPath = isPath;
|
|
1929
2181
|
exports.isPlugin = isPlugin;
|
|
1930
2182
|
exports.isRequestCacheable = isRequestCacheable;
|
|
1931
2183
|
exports.isResponseGone = isResponseGone;
|
|
1932
|
-
exports.isRouterInstance = isRouterInstance;
|
|
1933
2184
|
exports.matchRequestContentType = matchRequestContentType;
|
|
1934
|
-
exports.mergeDispatcherMetaParams = mergeDispatcherMetaParams;
|
|
1935
2185
|
exports.send = send;
|
|
1936
2186
|
exports.sendAccepted = sendAccepted;
|
|
1937
2187
|
exports.sendCreated = sendCreated;
|
|
@@ -1951,6 +2201,8 @@ exports.setResponseCacheHeaders = setResponseCacheHeaders;
|
|
|
1951
2201
|
exports.setResponseContentTypeByFileName = setResponseContentTypeByFileName;
|
|
1952
2202
|
exports.setResponseHeaderAttachment = setResponseHeaderAttachment;
|
|
1953
2203
|
exports.setResponseHeaderContentType = setResponseHeaderContentType;
|
|
2204
|
+
exports.transformHeaderToTuples = transformHeaderToTuples;
|
|
2205
|
+
exports.transformHeadersToTuples = transformHeadersToTuples;
|
|
1954
2206
|
exports.unsetRequestEnv = unsetRequestEnv;
|
|
1955
2207
|
exports.useRequestEnv = useRequestEnv;
|
|
1956
2208
|
exports.useRequestMountPath = useRequestMountPath;
|