nodester 0.1.4 → 0.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 +16 -55
- package/lib/application/index.js +174 -63
- package/lib/body/extract.js +89 -0
- package/lib/constants/Bounds.js +15 -0
- package/lib/constants/Clauses.js +13 -0
- package/lib/constants/ResponseFormats.js +2 -2
- package/lib/controllers/methods/index.js +7 -0
- package/lib/controllers/mixins/index.js +36 -36
- package/lib/database/connection.js +6 -0
- package/lib/database/migration.js +14 -4
- package/lib/facades/methods/index.js +16 -16
- package/lib/facades/mixins/index.js +67 -13
- package/lib/factories/responses/rest.js +25 -13
- package/lib/http/codes/descriptions.js +82 -0
- package/lib/http/codes/index.js +70 -145
- package/lib/http/codes/symbols.js +82 -0
- package/lib/http/{request.js → request/index.js} +53 -75
- package/lib/http/request/utils.js +27 -0
- package/lib/http/response/headers.js +138 -0
- package/lib/http/response/index.js +248 -0
- package/lib/http/response/utils.js +38 -0
- package/lib/middlewares/SearchParams/index.js +25 -0
- package/lib/middlewares/cookies/index.js +44 -0
- package/lib/middlewares/etag/index.js +32 -15
- package/lib/middlewares/formidable/index.js +30 -25
- package/lib/middlewares/ql/sequelize/index.js +13 -4
- package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +4 -3
- package/lib/middlewares/render/index.js +62 -0
- package/lib/models/associate.js +25 -1
- package/lib/models/define.js +26 -19
- package/lib/models/mixins.js +8 -1
- package/lib/{queries → query}/traverse.js +118 -77
- package/lib/router/handlers.util.js +1 -0
- package/lib/router/index.js +194 -99
- package/lib/router/markers.js +7 -0
- package/lib/router/route.js +5 -0
- package/lib/router/routes.util.js +16 -14
- package/lib/router/utils.js +7 -0
- package/lib/stacks/MarkersStack.js +41 -3
- package/lib/stacks/MiddlewaresStack.js +200 -0
- package/lib/structures/Enum.js +46 -0
- package/lib/structures/Filter.js +156 -0
- package/lib/structures/Params.js +55 -0
- package/lib/tools/sql.tool.js +7 -0
- package/lib/utils/objects.util.js +31 -24
- package/lib/utils/sanitizations.util.js +10 -4
- package/lib/validators/arguments.js +68 -0
- package/lib/validators/dates.js +7 -0
- package/lib/validators/numbers.js +7 -0
- package/package.json +20 -10
- package/lib/database/utils.js +0 -19
- package/lib/enums/Enum.js +0 -16
- package/lib/http/response.js +0 -1074
- package/lib/http/utils.js +0 -254
- package/lib/params/Params.js +0 -37
- package/lib/policies/Role.js +0 -77
- package/lib/policies/RoleExtracting.js +0 -97
- package/lib/preprocessors/BodyPreprocessor.js +0 -61
- package/lib/queries/Colander.js +0 -107
- package/lib/queries/NodesterQueryParams.js +0 -145
- package/lib/services/includes.service.js +0 -79
- package/lib/services/jwt.service.js +0 -147
- package/lib/stacks/MiddlewareStack.js +0 -159
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* /nodester
|
|
3
|
-
* MIT Licensed
|
|
4
|
-
*/
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
|
-
// Dictionary of unsafe characters:
|
|
8
|
-
const NOT_ALLOWED = [
|
|
9
|
-
'{',
|
|
10
|
-
'}',
|
|
11
|
-
// `\`,
|
|
12
|
-
'^',
|
|
13
|
-
'~',
|
|
14
|
-
'[',
|
|
15
|
-
']',
|
|
16
|
-
'`'
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
const util = require('util');
|
|
20
|
-
|
|
21
|
-
/*
|
|
22
|
-
* NodesterQueryParams is a ready-to-use replacement for URLSearchParams.
|
|
23
|
-
* The only difference is that NodesterQueryParams
|
|
24
|
-
* respects nested "&" during parsing.
|
|
25
|
-
*/
|
|
26
|
-
module.exports = class NodesterQueryParams {
|
|
27
|
-
constructor(queryString='') {
|
|
28
|
-
// Type validateion:
|
|
29
|
-
if (typeof queryString !== 'string') {
|
|
30
|
-
const err = new TypeError(`'query' must be a String.`);
|
|
31
|
-
throw err;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// You never know if it's encoded or not.
|
|
35
|
-
const decoded = decodeURI(queryString);
|
|
36
|
-
|
|
37
|
-
// Indicates, how deep the char is inside different ().
|
|
38
|
-
let deep = 0;
|
|
39
|
-
|
|
40
|
-
const paramLevels = {};
|
|
41
|
-
|
|
42
|
-
// Current query parameter.
|
|
43
|
-
let param = '';
|
|
44
|
-
|
|
45
|
-
// Current query token.
|
|
46
|
-
let token = '';
|
|
47
|
-
|
|
48
|
-
this._map = new Map();
|
|
49
|
-
|
|
50
|
-
for (let i=0; i < decoded.length; i++) {
|
|
51
|
-
const char = decoded[i];
|
|
52
|
-
|
|
53
|
-
// Validate char:
|
|
54
|
-
if (NOT_ALLOWED.indexOf(char) > -1) {
|
|
55
|
-
const err = new TypeError(`Invalid query token at ${ i }: '${ char }'`);
|
|
56
|
-
throw err;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (char === '(') {
|
|
60
|
-
// Error If there is nothing behind:
|
|
61
|
-
if (param.length === 0) {
|
|
62
|
-
const err = new TypeError(`Invalid query token at ${ i }: '${ char }'`);
|
|
63
|
-
throw err;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// If not special token, go deeper:
|
|
67
|
-
if (['and', 'or', 'xor', 'not', '!', '|', 'like'].indexOf(token) === -1) {
|
|
68
|
-
this.append(param, token);
|
|
69
|
-
deep++;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// will set ( in token later.
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (char === ')') {
|
|
76
|
-
// If sub-level:
|
|
77
|
-
if (deep > 0) {
|
|
78
|
-
deep--
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// & can mean the end of key=value pair:
|
|
83
|
-
if (char === '&') {
|
|
84
|
-
// If top-level:
|
|
85
|
-
if (deep === 0) {
|
|
86
|
-
this.append(param, token);
|
|
87
|
-
param = '';
|
|
88
|
-
token = '';
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// If sub-level do nothing.
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// = can mean the end of param name:
|
|
96
|
-
if (char === '=') {
|
|
97
|
-
// If top-level:
|
|
98
|
-
if (deep === 0) {
|
|
99
|
-
param = token;
|
|
100
|
-
token = '';
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Continue building token:
|
|
105
|
-
if (char !== '=' || deep > 0 ) {
|
|
106
|
-
token += char;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// If last char:
|
|
110
|
-
if (i === decoded.length-1) {
|
|
111
|
-
// Validate:
|
|
112
|
-
if (deep > 0) {
|
|
113
|
-
const err = new TypeError(`Missing ')' at ${ i }`);
|
|
114
|
-
throw err;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
this.append(param, token);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
append(...args) {
|
|
123
|
-
return this._map.set(...args);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
get(...args) {
|
|
127
|
-
return this._map.get(...args);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
delete(...args) {
|
|
131
|
-
return this._map.delete(...args);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
entries(...args) {
|
|
135
|
-
return this._map.entries(...args);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
toString() {
|
|
139
|
-
return this._map.toString();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
[util.inspect.custom](depth, opts) {
|
|
143
|
-
return this._map;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
splitByComma,
|
|
3
|
-
splitByDot
|
|
4
|
-
} = require('nodester/utils/strings.util');
|
|
5
|
-
// Query util.
|
|
6
|
-
const {
|
|
7
|
-
hasSubIncludesQuery,
|
|
8
|
-
cutSubIncludesQuery,
|
|
9
|
-
parseSubIncludesQuery
|
|
10
|
-
} = require('nodester/utils/queries.util');
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
module.exports = {
|
|
14
|
-
parseIncludesQuery: _parseIncludesQuery
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function _parseIncludesQuery(
|
|
18
|
-
modelDefinition,
|
|
19
|
-
includesQueryString
|
|
20
|
-
) {
|
|
21
|
-
const associationAndSubs = splitByComma(includesQueryString);
|
|
22
|
-
const allowedAssociations = Object.keys(modelDefinition.associations);
|
|
23
|
-
|
|
24
|
-
associationAndSubs.forEach((a) => {
|
|
25
|
-
let association = a.split('.')[0];
|
|
26
|
-
|
|
27
|
-
if (hasSubIncludesQuery(association)) {
|
|
28
|
-
const [ nestedQuery, _association ] = cutSubIncludesQuery(association);
|
|
29
|
-
association = _association;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (allowedAssociations.indexOf(association) === -1) {
|
|
33
|
-
const err = new Error(`Association with name "${ association }" doesn't exist on this model.`);
|
|
34
|
-
err.name = 'NotFound';
|
|
35
|
-
throw err;
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const result = associationAndSubs.map(associationAndSubsString => _parseSubIncludes(associationAndSubsString));
|
|
40
|
-
|
|
41
|
-
return result;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function _parseSubIncludes(associationAndSubsString) {
|
|
45
|
-
const associationAndSubs = splitByDot(associationAndSubsString);
|
|
46
|
-
|
|
47
|
-
// If association has SubIncludes:
|
|
48
|
-
if (associationAndSubs?.length > 0) {
|
|
49
|
-
const clearAssociation = associationAndSubs[0];
|
|
50
|
-
const subs = associationAndSubs.splice(1, associationAndSubs.length - 1);
|
|
51
|
-
|
|
52
|
-
if (subs.length > 0) {
|
|
53
|
-
const result = {
|
|
54
|
-
association: clearAssociation,
|
|
55
|
-
include: [ _parseSubIncludes(subs.join('.')) ]
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
_parseSubIncludesQueryIfPresent(result);
|
|
59
|
-
|
|
60
|
-
return result;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// By default just return association.
|
|
65
|
-
const result = { association: associationAndSubsString };
|
|
66
|
-
_parseSubIncludesQueryIfPresent(result);
|
|
67
|
-
return result;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function _parseSubIncludesQueryIfPresent(resultQuery) {
|
|
71
|
-
if (hasSubIncludesQuery(resultQuery.association)) {
|
|
72
|
-
const [ nestedQuery, clearAssociation ] = cutSubIncludesQuery(resultQuery.association);
|
|
73
|
-
|
|
74
|
-
resultQuery.association = clearAssociation;
|
|
75
|
-
parseSubIncludesQuery(clearAssociation, nestedQuery, resultQuery);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return resultQuery;
|
|
79
|
-
}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
// Format of token: "Authorization: Bearer [token]".
|
|
2
|
-
const ACCESS_TOKEN_NAME = 'Authorization';
|
|
3
|
-
const REFRESH_TOKEN_NAME = 'x-refresh-token';
|
|
4
|
-
// JWT module.
|
|
5
|
-
const jwt = require('jsonwebtoken');
|
|
6
|
-
// Utils.
|
|
7
|
-
const { addSeconds } = require('nodester/utils/dates.util');
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
module.exports = class JWTService {
|
|
11
|
-
constructor(
|
|
12
|
-
accessTokenConfigs,
|
|
13
|
-
refreshTokenConfigs
|
|
14
|
-
) {
|
|
15
|
-
if (!accessTokenConfigs || !refreshTokenConfigs){
|
|
16
|
-
throw new Error('"accessTokenConfigs" and "refreshTokenConfigs" are required arguments.');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
this.accessTokenConfigs = { ...accessTokenConfigs };
|
|
20
|
-
this.refreshTokenConfigs = { ...refreshTokenConfigs };
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
extractTokenFromRequest(request) {
|
|
24
|
-
let token;
|
|
25
|
-
|
|
26
|
-
if (request.header(ACCESS_TOKEN_NAME)) {
|
|
27
|
-
token = this._parseAccessToken(
|
|
28
|
-
request.header(ACCESS_TOKEN_NAME)
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
else if (request.cookies[ACCESS_TOKEN_NAME]) {
|
|
32
|
-
token = this._parseAccessToken(
|
|
33
|
-
request.cookies[ACCESS_TOKEN_NAME]
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
// Check token in query:
|
|
37
|
-
else if (!!request.query.token) {
|
|
38
|
-
token = request.query.token;
|
|
39
|
-
delete request.body.token;
|
|
40
|
-
}
|
|
41
|
-
// Check token in body:
|
|
42
|
-
else if (!!request.body.token) {
|
|
43
|
-
token = request.body.token;
|
|
44
|
-
delete request.query.token;
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
const err = new Error(`No ${ACCESS_TOKEN_NAME} was found`);
|
|
48
|
-
err.name = 'NoToken';
|
|
49
|
-
err.details = { message:err.message };
|
|
50
|
-
throw err;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return token;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
extractRefreshTokenFromRequest(request) {
|
|
57
|
-
let token;
|
|
58
|
-
|
|
59
|
-
if (request.header(REFRESH_TOKEN_NAME)) {
|
|
60
|
-
token = request.header(REFRESH_TOKEN_NAME);
|
|
61
|
-
}
|
|
62
|
-
else if (request.cookies[REFRESH_TOKEN_NAME]) {
|
|
63
|
-
token = request.cookies[REFRESH_TOKEN_NAME];
|
|
64
|
-
}
|
|
65
|
-
// Check token in query:
|
|
66
|
-
else if (!!request.query.token) {
|
|
67
|
-
token = request.query.token;
|
|
68
|
-
delete request.body.token;
|
|
69
|
-
}
|
|
70
|
-
// Check token in body:
|
|
71
|
-
else if (!!request.body.token) {
|
|
72
|
-
token = request.body.token;
|
|
73
|
-
delete request.query.token;
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
const err = new Error(`No ${REFRESH_TOKEN_NAME} was found`);
|
|
77
|
-
err.name = 'NoToken';
|
|
78
|
-
err.details = { message:err.message };
|
|
79
|
-
throw err;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return token;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
issueAccessToken(payload) {
|
|
86
|
-
const { secret, expiresIn } = this.accessTokenConfigs;
|
|
87
|
-
return this._issueToken({ payload, secret, expiresIn });
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
issueRefreshToken(payload) {
|
|
91
|
-
const { secret, expiresIn } = this.refreshTokenConfigs;
|
|
92
|
-
return this._issueToken({ payload, secret, expiresIn });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
verifyAccessToken(token) {
|
|
96
|
-
const { secret } = this.accessTokenConfigs;
|
|
97
|
-
return this._verifyToken({ token, secret });
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
verifyRefreshToken(token) {
|
|
101
|
-
const { secret } = this.refreshTokenConfigs;
|
|
102
|
-
return this._verifyToken({ token, secret });
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async _issueToken({ payload, secret, expiresIn }) {
|
|
106
|
-
try {
|
|
107
|
-
const token = jwt.sign(payload, secret, { expiresIn });
|
|
108
|
-
const expirationDateValue = (addSeconds(new Date(), expiresIn/1000)).valueOf();
|
|
109
|
-
|
|
110
|
-
const fullToken = { token, expiresIn, expirationDateValue };
|
|
111
|
-
return Promise.resolve(fullToken);
|
|
112
|
-
}
|
|
113
|
-
catch(error) {
|
|
114
|
-
return Promise.reject(error);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async _verifyToken({ token, secret }) {
|
|
119
|
-
try {
|
|
120
|
-
const parsedToken = await jwt.verify(token, secret, {});
|
|
121
|
-
return Promise.resolve(parsedToken);
|
|
122
|
-
}
|
|
123
|
-
catch(error) {
|
|
124
|
-
const err = new Error('Invalid signature.');
|
|
125
|
-
err.name = 'ValidationError';
|
|
126
|
-
return Promise.reject(err);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
_parseAccessToken(token) {
|
|
131
|
-
let parsed = '';
|
|
132
|
-
|
|
133
|
-
const parts = token.split(' ');
|
|
134
|
-
|
|
135
|
-
if (parts.length === 2 && /^Bearer$/.test(parts[0])) {
|
|
136
|
-
parsed = parts[1];
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
const err = new Error(`Format for ${ACCESS_TOKEN_NAME}: Bearer [token]`);
|
|
140
|
-
err.name = 'InvalidFormat';
|
|
141
|
-
err.details = { message: err.message };
|
|
142
|
-
throw err;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return parsed;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
const finalhandler = require('finalhandler');
|
|
2
|
-
const consl = require('nodester/loggers/console');
|
|
3
|
-
const debug = require('debug')('nodester:MiddlewareStack');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
module.exports = class MiddlewareStack {
|
|
7
|
-
constructor(opts={}) {
|
|
8
|
-
// This array MUST stay flat!
|
|
9
|
-
this.middlewares = [];
|
|
10
|
-
|
|
11
|
-
// Indicates whether we can add more middlewares or no.
|
|
12
|
-
this.isLocked = false;
|
|
13
|
-
this.finalhandlerEnabled = !!opts.finalhandlerEnabled;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const env = process.env.NODE_ENV || 'development';
|
|
17
|
-
// Final middleware & error handler.
|
|
18
|
-
this.finalhandler = (req, res) => finalhandler(req, res, {
|
|
19
|
-
env: env,
|
|
20
|
-
onerror: consl.error.bind(this)
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Add the given middleware `fn` to the stack.
|
|
27
|
-
*
|
|
28
|
-
* @param {Function} fn
|
|
29
|
-
* @param {Integer} index (0 or undefined)
|
|
30
|
-
* @return {Integer} index of new middleware
|
|
31
|
-
*
|
|
32
|
-
* @api public
|
|
33
|
-
*/
|
|
34
|
-
add(fn, index) {
|
|
35
|
-
if (this.isLocked) {
|
|
36
|
-
const err = new Error(`Can't add more middlewares while stack is locked.`);
|
|
37
|
-
throw err;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (typeof fn !== 'function') {
|
|
41
|
-
const err = new TypeError('middleware must be a function!');
|
|
42
|
-
throw err;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (!!index && isNaN(index)) {
|
|
46
|
-
const err = new TypeError('"index" must be an Integer!');
|
|
47
|
-
throw err;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let pushedIndex = -1;
|
|
51
|
-
|
|
52
|
-
if (index === 0) {
|
|
53
|
-
this.middlewares.unshift(fn);
|
|
54
|
-
pushedIndex = 0;
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
pushedIndex = this.middlewares.push(fn);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
debug(`added middleware (${ pushedIndex })`);
|
|
61
|
-
return pushedIndex;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Removes middleware at index.
|
|
67
|
-
*
|
|
68
|
-
* @param {Integer} index
|
|
69
|
-
* @return {MiddlewareStack} self
|
|
70
|
-
*
|
|
71
|
-
* @api public
|
|
72
|
-
*/
|
|
73
|
-
remove(index=-1) {
|
|
74
|
-
if (this.isLocked) {
|
|
75
|
-
const err = new Error(`Can't remove middlewares while stack is locked.`);
|
|
76
|
-
throw err;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (isNaN(index)) {
|
|
80
|
-
const err = new TypeError('"index" must be an Integer!');
|
|
81
|
-
throw err;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
this.middlewares.splice(index, 1);
|
|
85
|
-
debug(`removed middleware (${ index })`);
|
|
86
|
-
return this;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
/*
|
|
91
|
-
* Prepare stack for processing.
|
|
92
|
-
*
|
|
93
|
-
* @api public
|
|
94
|
-
*/
|
|
95
|
-
lock() {
|
|
96
|
-
if (this.finalhandlerEnabled) {
|
|
97
|
-
// Add final handler to the stack.
|
|
98
|
-
this.add((req, res)=>this.finalhandler(req, res)());
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Stack is ready.
|
|
102
|
-
this.isLocked = true;
|
|
103
|
-
|
|
104
|
-
debug(`stack is locked`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
/*
|
|
109
|
-
* Unlocks stack.
|
|
110
|
-
*
|
|
111
|
-
* @api public
|
|
112
|
-
*/
|
|
113
|
-
unlock() {
|
|
114
|
-
this.isLocked = false;
|
|
115
|
-
|
|
116
|
-
if (this.finalhandlerEnabled) {
|
|
117
|
-
this.middlewares.pop();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
debug(`stack is unlocked`);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
/*
|
|
125
|
-
* Start chain.
|
|
126
|
-
*
|
|
127
|
-
* @api public
|
|
128
|
-
*/
|
|
129
|
-
process(req, res, next) {
|
|
130
|
-
let middlewareOffset = -1;
|
|
131
|
-
|
|
132
|
-
const _next = (...args) => {
|
|
133
|
-
middlewareOffset += 1;
|
|
134
|
-
const fn = this.middlewares[middlewareOffset];
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
if (!fn && !next) {
|
|
138
|
-
const err = new TypeError(`Handler for ${ req.method } ${ req.url } is not defined.`);
|
|
139
|
-
throw err;
|
|
140
|
-
}
|
|
141
|
-
else if (!fn && !!next) {
|
|
142
|
-
return next.call(null, req, res, next, ...args);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return fn.call(null, req, res, _next, ...args);
|
|
146
|
-
}
|
|
147
|
-
catch(error) {
|
|
148
|
-
return this.finalhandler(req, res)(error);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return _next();
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
get length() {
|
|
157
|
-
return this.middlewares.length;
|
|
158
|
-
}
|
|
159
|
-
}
|