nodester 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/Readme.md +125 -0
- package/docs/App.md +13 -0
- package/docs/Queries.md +61 -0
- package/docs/Readme.md +2 -0
- package/docs/Routing.md +34 -0
- package/examples/goal/index.js +23 -0
- package/examples/rest/index.js +25 -0
- package/examples/rest/node_modules/.package-lock.json +40 -0
- package/examples/rest/package-lock.json +72 -0
- package/examples/rest/package.json +14 -0
- package/lib/application/MiddlewareStack.js +125 -0
- package/lib/application/http/request.js +462 -0
- package/lib/application/http/response.js +1107 -0
- package/lib/application/http/utils.js +254 -0
- package/lib/application/index.js +292 -0
- package/lib/constants/ConstantsEnum.js +13 -0
- package/lib/constants/ResponseFormats.js +7 -0
- package/lib/controllers/Controller.js +474 -0
- package/lib/controllers/JWTController.js +240 -0
- package/lib/controllers/ServiceController.js +109 -0
- package/lib/controllers/WebController.js +75 -0
- package/lib/facades/Facade.js +388 -0
- package/lib/facades/FacadeParams.js +11 -0
- package/lib/facades/ServiceFacade.js +17 -0
- package/lib/facades/jwt.facade.js +273 -0
- package/lib/factories/errors/CustomError.js +22 -0
- package/lib/factories/errors/index.js +9 -0
- package/lib/factories/responses/api.js +90 -0
- package/lib/factories/responses/html.js +55 -0
- package/lib/logger/console.js +24 -0
- package/lib/models/DisabledRefreshToken.js +68 -0
- package/lib/models/Extractor.js +320 -0
- package/lib/models/define.js +62 -0
- package/lib/models/mixins.js +369 -0
- package/lib/policies/Role.js +77 -0
- package/lib/policies/RoleExtracting.js +97 -0
- package/lib/preprocessors/BodyPreprocessor.js +61 -0
- package/lib/preprocessors/IncludesPreprocessor.js +55 -0
- package/lib/preprocessors/QueryPreprocessor.js +64 -0
- package/lib/routers/Default/index.js +143 -0
- package/lib/routers/Default/layer.js +50 -0
- package/lib/routers/Main/index.js +10 -0
- package/lib/routers/Roles/index.js +81 -0
- package/lib/services/includes.service.js +79 -0
- package/lib/services/jwt.service.js +147 -0
- package/lib/tools/sql.tool.js +82 -0
- package/lib/utils/dates.util.js +23 -0
- package/lib/utils/forms.util.js +22 -0
- package/lib/utils/json.util.js +49 -0
- package/lib/utils/mappers/Routes/index.js +100 -0
- package/lib/utils/mappers/Routes/utils.js +20 -0
- package/lib/utils/modelAssociations.util.js +44 -0
- package/lib/utils/objects.util.js +69 -0
- package/lib/utils/params.util.js +19 -0
- package/lib/utils/path.util.js +26 -0
- package/lib/utils/queries.util.js +240 -0
- package/lib/utils/sanitizations.util.js +111 -0
- package/lib/utils/sql.util.js +78 -0
- package/lib/utils/strings.util.js +43 -0
- package/lib/utils/types.util.js +26 -0
- package/package.json +63 -0
- package/tests/index.test.js +35 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Mark Khramko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Readme.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# nodester
|
|
2
|
+
> A robust boilerplate framework that makes iterative development easy.
|
|
3
|
+
|
|
4
|
+
## Table of Contents
|
|
5
|
+
|
|
6
|
+
- [Usage](#usage)
|
|
7
|
+
- [Extending](#extending-application-functionality)
|
|
8
|
+
- [Philosophy](#philosophy)
|
|
9
|
+
- [License](#license)
|
|
10
|
+
- [Copyright](#copyright)
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
const nodester = require('nodester');
|
|
16
|
+
const db = require('#db');
|
|
17
|
+
|
|
18
|
+
const app = new nodester();
|
|
19
|
+
app.set.database(db);
|
|
20
|
+
|
|
21
|
+
app.listen(8080, function() {
|
|
22
|
+
console.log('listening on port', app.port);
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Markers
|
|
27
|
+
|
|
28
|
+
Marker is a functional condition that returns `true | false`, based on data in request.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### Adding a Marker
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
app.add.marker('admin', (req) => req.role === 'admin');
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Using a Marker
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
app.only('admin').route('get /payments', <handler>);
|
|
42
|
+
app.only('/api').route('get /payments', <handler>);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## Router
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
app.route('get /books', function(req, res) { ... } );
|
|
50
|
+
app.route('get /books', { controlledBy: 'BooksController.getMany' } );
|
|
51
|
+
app.route('get /books/:id', { controlledBy: 'BooksController.getOne' } );
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
## Extending Application functionality
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
### Extending instance (safe way):
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
const serveStatic = require('serve-static');
|
|
62
|
+
|
|
63
|
+
const nodester = require('nodester');
|
|
64
|
+
|
|
65
|
+
const app = nodester();
|
|
66
|
+
app.extend('static', serveStatic);
|
|
67
|
+
app.static(<path_to_static_directory>);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Short:
|
|
71
|
+
```js
|
|
72
|
+
const serveStatic = require('serve-static');
|
|
73
|
+
|
|
74
|
+
const nodester = require('nodester');
|
|
75
|
+
|
|
76
|
+
const app = nodester();
|
|
77
|
+
app.extend('static', serveStatic)(<path_to_static_directory>);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Of course you might just do this:
|
|
81
|
+
```js
|
|
82
|
+
const serveStatic = require('serve-static');
|
|
83
|
+
|
|
84
|
+
const nodester = require('nodester');
|
|
85
|
+
|
|
86
|
+
const app = nodester();
|
|
87
|
+
app.static = serveStatic;
|
|
88
|
+
````
|
|
89
|
+
But you'll never know if you did override any of the app's properties or did not.
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
### Extending class:
|
|
93
|
+
|
|
94
|
+
If you really want to override properties or use `nodester` as a boilerplate, you should better extend default Application class:
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
const DefaultApplication = require('nodester');
|
|
98
|
+
|
|
99
|
+
class MyApp extends DefaultApplication {
|
|
100
|
+
constructor(opts) {
|
|
101
|
+
super(opts)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Override everything you want here...
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Don't forget to expose.
|
|
108
|
+
module.exports = MyApp;
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Philosophy
|
|
112
|
+
|
|
113
|
+
The Philosophy of `nodester` is to provide a developer with a tool that can build an app (or feature) in hours and scale it with ease for years.
|
|
114
|
+
|
|
115
|
+
### Goal
|
|
116
|
+
|
|
117
|
+
The goal of `nodester` is to be a robust boilerplate that makes iterative development easy.
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
## LICENSE
|
|
121
|
+
|
|
122
|
+
MIT
|
|
123
|
+
|
|
124
|
+
## Copyright
|
|
125
|
+
Copyright 2021-present [Mark Khramko](https://github.com/MarkKhramko)
|
package/docs/App.md
ADDED
package/docs/Queries.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# nodester Queries API
|
|
2
|
+
|
|
3
|
+
## Like value
|
|
4
|
+
|
|
5
|
+
To emulate MySQL's `like %value% ` query in URL,
|
|
6
|
+
pass `?key=like(value)` in the query.
|
|
7
|
+
|
|
8
|
+
* Example:
|
|
9
|
+
`http://localhost:5001/api/v1/countries?name=like(Engl)`
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## NotLike value
|
|
13
|
+
|
|
14
|
+
* Example:
|
|
15
|
+
`http://localhost:5001/api/v1/countries?name=notLike(Engl)`
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## Or
|
|
19
|
+
|
|
20
|
+
To emulate MySQL's `where key=value or key=value` query in URL,
|
|
21
|
+
pass `?key=or(value1,value2)` in the query.
|
|
22
|
+
* ! Note: don't use `spaces` between values.
|
|
23
|
+
|
|
24
|
+
* Example:
|
|
25
|
+
`http://localhost:5001/api/v1/countries?name=or(England,Germany)`
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## Count
|
|
29
|
+
|
|
30
|
+
MySQL's `select count(value)` query is run by default in facade's `getMany` function
|
|
31
|
+
|
|
32
|
+
* Response Example:
|
|
33
|
+
```JSON
|
|
34
|
+
{
|
|
35
|
+
"count": 10,
|
|
36
|
+
"countries": [ ... ],
|
|
37
|
+
"limit": 10,
|
|
38
|
+
"skip": 0,
|
|
39
|
+
"total_count": 195
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Order (Sorting)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
#### Top level
|
|
47
|
+
|
|
48
|
+
`order_by` & `order` arguments can be set in `query`
|
|
49
|
+
`http://localhost:5001/api/v1/countries?order_by=id&order=desc`
|
|
50
|
+
|
|
51
|
+
Above `query` will sort Countries[] by it's id.
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
#### Nested (Includes)
|
|
55
|
+
|
|
56
|
+
`http://localhost:5001/api/v1/countries?includes=cities(order_by=id&order=desc)`
|
|
57
|
+
|
|
58
|
+
Above `query` will sort Cities[] by it's id inside every Country object.
|
|
59
|
+
|
|
60
|
+
It can also do this:
|
|
61
|
+
`http://localhost:5001/api/v1/countries?includes=cities(order_by=id&order=desc).areas`
|
package/docs/Readme.md
ADDED
package/docs/Routing.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# nodester Routing
|
|
2
|
+
|
|
3
|
+
1) Extend default `nodester` router
|
|
4
|
+
```js
|
|
5
|
+
const Router = require('nodester/router');
|
|
6
|
+
|
|
7
|
+
class apiRouter extends Router {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(opts);
|
|
10
|
+
this.add.controllers(<path_to_your_controllers>);
|
|
11
|
+
this.add.controllers(<path_to_your_controllers>, { namespace: 'view' });
|
|
12
|
+
|
|
13
|
+
this.add.routes()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Root namespace is named `__root`
|
|
19
|
+
|
|
20
|
+
2) Define routes
|
|
21
|
+
```js
|
|
22
|
+
module.exports = {
|
|
23
|
+
'GET /posts': { controlledBy: 'PostsController.getMany' },
|
|
24
|
+
|
|
25
|
+
// For different namespace:
|
|
26
|
+
'GET /view/posts': { controlledBy: '@view PostsViewController.getMany' },
|
|
27
|
+
// Can also be written as:
|
|
28
|
+
'GET /view/posts': {
|
|
29
|
+
namespace: 'view',
|
|
30
|
+
controller: 'PostsViewController'
|
|
31
|
+
action: 'getMany'
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const nodester = require('nodester');
|
|
2
|
+
const db = require('#db');
|
|
3
|
+
|
|
4
|
+
// Init.
|
|
5
|
+
const app = new nodester();
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
app.set.database(db);
|
|
9
|
+
|
|
10
|
+
app.extend('static')
|
|
11
|
+
|
|
12
|
+
app.static(<path/>);
|
|
13
|
+
|
|
14
|
+
// Markers.
|
|
15
|
+
app.add.marker('admin', (req)=>req.token.role === 'admin');
|
|
16
|
+
|
|
17
|
+
// Using Markers.
|
|
18
|
+
app.only('admin')
|
|
19
|
+
.route('get /payments', (req, res, next) => {});
|
|
20
|
+
|
|
21
|
+
app.listen(8080, function() {
|
|
22
|
+
console.log('listening on port', app.port);
|
|
23
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const Nodester = require('nodester');
|
|
2
|
+
|
|
3
|
+
// Init.
|
|
4
|
+
const app = new Nodester();
|
|
5
|
+
|
|
6
|
+
// app.setDatabase();
|
|
7
|
+
// app.set('database');
|
|
8
|
+
|
|
9
|
+
// app.add('marker', 'GET_M', (req)=>req.method === 'GET');
|
|
10
|
+
|
|
11
|
+
app.add.middleware((req, res, next)=>{
|
|
12
|
+
console.log('1st');
|
|
13
|
+
|
|
14
|
+
res.setHeader("Content-type", "text/html");
|
|
15
|
+
res.write("Hello!<br/>...my friend");
|
|
16
|
+
res.end();
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
app.beforeStart(()=>{
|
|
20
|
+
console.log('Before start passed!');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
app.listen(8080, function() {
|
|
24
|
+
console.log('listening on port', app.port);
|
|
25
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nodester-example-rest",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"lockfileVersion": 2,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"../..": {
|
|
8
|
+
"version": "0.6.1",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"accepts": "^1.3.8",
|
|
12
|
+
"content-disposition": "^0.5.4",
|
|
13
|
+
"content-type": "^1.0.5",
|
|
14
|
+
"cookie": "^0.5.0",
|
|
15
|
+
"cookie-signature": "^1.2.0",
|
|
16
|
+
"debug": "^4.3.4",
|
|
17
|
+
"finalhandler": "^1.2.0",
|
|
18
|
+
"formidable": "^1.2.6",
|
|
19
|
+
"inflection": "^2.0.1",
|
|
20
|
+
"proxy-addr": "^2.0.7",
|
|
21
|
+
"qs": "^6.11.0",
|
|
22
|
+
"sequelize": "^6.6.5",
|
|
23
|
+
"serve-static": "^1.15.0",
|
|
24
|
+
"slugify": "^1.6.5",
|
|
25
|
+
"type-is": "^1.6.18",
|
|
26
|
+
"vary": "^1.1.2"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"jest": "^29.4.2"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">= 12.17.0"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"node_modules/nodester": {
|
|
36
|
+
"resolved": "../..",
|
|
37
|
+
"link": true
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nodester-example-rest",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"lockfileVersion": 2,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "nodester-example-rest",
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"nodester": "file:../../"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"../..": {
|
|
16
|
+
"version": "0.6.1",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"accepts": "^1.3.8",
|
|
20
|
+
"content-disposition": "^0.5.4",
|
|
21
|
+
"content-type": "^1.0.5",
|
|
22
|
+
"cookie": "^0.5.0",
|
|
23
|
+
"cookie-signature": "^1.2.0",
|
|
24
|
+
"debug": "^4.3.4",
|
|
25
|
+
"finalhandler": "^1.2.0",
|
|
26
|
+
"formidable": "^1.2.6",
|
|
27
|
+
"inflection": "^2.0.1",
|
|
28
|
+
"proxy-addr": "^2.0.7",
|
|
29
|
+
"qs": "^6.11.0",
|
|
30
|
+
"sequelize": "^6.6.5",
|
|
31
|
+
"serve-static": "^1.15.0",
|
|
32
|
+
"slugify": "^1.6.5",
|
|
33
|
+
"type-is": "^1.6.18",
|
|
34
|
+
"vary": "^1.1.2"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"jest": "^29.4.2"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">= 12.17.0"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"node_modules/nodester": {
|
|
44
|
+
"resolved": "../..",
|
|
45
|
+
"link": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"nodester": {
|
|
50
|
+
"version": "file:../..",
|
|
51
|
+
"requires": {
|
|
52
|
+
"accepts": "^1.3.8",
|
|
53
|
+
"content-disposition": "^0.5.4",
|
|
54
|
+
"content-type": "^1.0.5",
|
|
55
|
+
"cookie": "^0.5.0",
|
|
56
|
+
"cookie-signature": "^1.2.0",
|
|
57
|
+
"debug": "^4.3.4",
|
|
58
|
+
"finalhandler": "^1.2.0",
|
|
59
|
+
"formidable": "^1.2.6",
|
|
60
|
+
"inflection": "^2.0.1",
|
|
61
|
+
"jest": "^29.4.2",
|
|
62
|
+
"proxy-addr": "^2.0.7",
|
|
63
|
+
"qs": "^6.11.0",
|
|
64
|
+
"sequelize": "^6.6.5",
|
|
65
|
+
"serve-static": "^1.15.0",
|
|
66
|
+
"slugify": "^1.6.5",
|
|
67
|
+
"type-is": "^1.6.18",
|
|
68
|
+
"vary": "^1.1.2"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nodester-example-rest",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"author": "Mark Khramko",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"nodester": "file:../../"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
const finalhandler = require('finalhandler');
|
|
2
|
+
const consl = require('../logger/console');
|
|
3
|
+
const debug = require('debug')('nodester:MiddlewareStack');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
module.exports = class MiddlewareStack {
|
|
7
|
+
constructor() {
|
|
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
|
+
|
|
14
|
+
|
|
15
|
+
const env = process.env.NODE_ENV || 'development';
|
|
16
|
+
// Final middleware & error handler.
|
|
17
|
+
this.finalhandler = (req, res) => finalhandler(req, res, {
|
|
18
|
+
env: env,
|
|
19
|
+
onerror: consl.error.bind(this)
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Add the given middleware `fn` to the stack.
|
|
26
|
+
*
|
|
27
|
+
* @param {Function} fn
|
|
28
|
+
* @return {Integer} index of new middleware
|
|
29
|
+
*
|
|
30
|
+
* @api public
|
|
31
|
+
*/
|
|
32
|
+
add(fn) {
|
|
33
|
+
if (this.isLocked) {
|
|
34
|
+
const err = new Error(`Can't add more middlewares while stack is locked.`);
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (typeof fn !== 'function') {
|
|
39
|
+
const err = new TypeError('middleware must be a function!');
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const index = this.middlewares.push(fn);
|
|
44
|
+
debug(`added middleware (${ index })`);
|
|
45
|
+
return index;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Removes middleware at index.
|
|
51
|
+
*
|
|
52
|
+
* @param {Integer} index
|
|
53
|
+
* @return {MiddlewareStack} self
|
|
54
|
+
*
|
|
55
|
+
* @api public
|
|
56
|
+
*/
|
|
57
|
+
remove(index=-1) {
|
|
58
|
+
if (this.isLocked) {
|
|
59
|
+
const err = new Error(`Can't remove middlewares while stack is locked.`);
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (isNaN(index)) {
|
|
64
|
+
const err = new TypeError('"index" must be an Integer!');
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.middlewares.splice(middlewareIndex, 1);
|
|
69
|
+
debug(`removed middleware (${ index })`);
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
/*
|
|
75
|
+
* Prepare stack for processing.
|
|
76
|
+
*
|
|
77
|
+
* @api public
|
|
78
|
+
*/
|
|
79
|
+
lock() {
|
|
80
|
+
// Add final handler to the stack.
|
|
81
|
+
this.add((req, res)=>this.finalhandler(req, res)());
|
|
82
|
+
|
|
83
|
+
// Stack is ready.
|
|
84
|
+
this.isLocked = true;
|
|
85
|
+
|
|
86
|
+
debug(`stack is locked`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
/*
|
|
91
|
+
* Unlocks stack.
|
|
92
|
+
*
|
|
93
|
+
* @api public
|
|
94
|
+
*/
|
|
95
|
+
unlock() {
|
|
96
|
+
this.isLocked = false;
|
|
97
|
+
this.middlewares.pop();
|
|
98
|
+
|
|
99
|
+
debug(`stack is unlocked`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
/*
|
|
104
|
+
* Start chain.
|
|
105
|
+
*
|
|
106
|
+
* @api public
|
|
107
|
+
*/
|
|
108
|
+
process(req, res) {
|
|
109
|
+
let middlewareOffset = -1;
|
|
110
|
+
|
|
111
|
+
const next = (...args) => {
|
|
112
|
+
middlewareOffset += 1;
|
|
113
|
+
const fn = this.middlewares[middlewareOffset];
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
return fn.call(null, req, res, next, ...args);
|
|
117
|
+
}
|
|
118
|
+
catch(error) {
|
|
119
|
+
return this.finalhandler(req, res)(error);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return next();
|
|
124
|
+
}
|
|
125
|
+
}
|