nodester 0.0.1 → 0.0.2
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 +33 -39
- package/lib/application/index.js +110 -38
- package/lib/constants/Operations.js +23 -0
- package/lib/controllers/methods/index.js +194 -0
- package/lib/controllers/mixins/index.js +222 -0
- package/lib/database/connection.js +34 -0
- package/lib/database/migration.js +42 -0
- package/lib/database/utils.js +19 -0
- package/lib/enums/Enum.js +16 -0
- package/lib/facades/methods/index.js +173 -0
- package/lib/facades/mixins/index.js +111 -0
- package/lib/factories/errors/CustomError.js +7 -5
- package/lib/factories/responses/html.js +7 -2
- package/lib/factories/responses/rest.js +110 -0
- package/lib/http/codes/index.js +157 -0
- package/lib/{application/http → http}/request.js +6 -30
- package/lib/{application/http → http}/response.js +20 -53
- package/lib/middlewares/etag/index.js +62 -0
- package/lib/middlewares/ql/sequelize/index.js +34 -0
- package/lib/middlewares/ql/sequelize/interpreter/ModelsTree.js +121 -0
- package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +456 -0
- package/lib/models/associate.js +17 -0
- package/lib/models/define.js +56 -14
- package/lib/models/mixins.js +100 -78
- package/lib/params/Params.js +37 -0
- package/lib/queries/Colander.js +84 -0
- package/lib/queries/NodesterQueryParams.js +139 -0
- package/lib/queries/traverse.js +311 -0
- package/lib/router/handlers.util.js +61 -0
- package/lib/router/index.js +386 -0
- package/lib/router/route.js +124 -0
- package/lib/router/routes.util.js +66 -0
- package/lib/stacks/MarkersStack.js +35 -0
- package/lib/{application → stacks}/MiddlewareStack.js +47 -13
- package/lib/utils/path.util.js +3 -1
- package/lib/utils/types.util.js +51 -1
- package/lib/validators/dates.js +25 -0
- package/lib/validators/numbers.js +14 -0
- package/package.json +31 -4
- package/tests/index.test.js +7 -2
- package/tests/nql.test.js +277 -0
- package/docs/App.md +0 -13
- package/docs/Queries.md +0 -61
- package/docs/Readme.md +0 -2
- package/docs/Routing.md +0 -34
- package/examples/goal/index.js +0 -23
- package/examples/rest/index.js +0 -25
- package/examples/rest/node_modules/.package-lock.json +0 -40
- package/examples/rest/package-lock.json +0 -72
- package/examples/rest/package.json +0 -14
- package/lib/constants/ConstantsEnum.js +0 -13
- package/lib/controllers/Controller.js +0 -474
- package/lib/controllers/JWTController.js +0 -240
- package/lib/controllers/ServiceController.js +0 -109
- package/lib/controllers/WebController.js +0 -75
- package/lib/facades/Facade.js +0 -388
- package/lib/facades/FacadeParams.js +0 -11
- package/lib/facades/ServiceFacade.js +0 -17
- package/lib/facades/jwt.facade.js +0 -273
- package/lib/factories/responses/api.js +0 -90
- package/lib/models/DisabledRefreshToken.js +0 -68
- package/lib/models/Extractor.js +0 -320
- package/lib/routers/Default/index.js +0 -143
- package/lib/routers/Default/layer.js +0 -50
- package/lib/routers/Main/index.js +0 -10
- package/lib/routers/Roles/index.js +0 -81
- package/lib/utils/params.util.js +0 -19
- /package/lib/{application/http → http}/utils.js +0 -0
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
// Boilerplate JWT facade.
|
|
2
|
-
const standardJWTFacade = require('nodester/facades/jwt.facade');
|
|
3
|
-
// Data extractor:
|
|
4
|
-
const Extractor = require('nodester/models/Extractor');
|
|
5
|
-
// Reponse protocol generator.
|
|
6
|
-
const APIResponseFactory = require('nodester/factories/responses/api');
|
|
7
|
-
// Utils:
|
|
8
|
-
const { lowerCase } = require('nodester/utils/strings.util');
|
|
9
|
-
const Params = require('nodester/utils/params.util');
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
module.exports = class JWTController {
|
|
13
|
-
constructor({
|
|
14
|
-
jwtFacade,
|
|
15
|
-
apiResponseFactory,
|
|
16
|
-
}) {
|
|
17
|
-
|
|
18
|
-
this.facade = jwtFacade ?? standardJWTFacade;
|
|
19
|
-
this.name = 'JWTController';
|
|
20
|
-
|
|
21
|
-
// Init standard API response factory.
|
|
22
|
-
const standardAPIResponseFactory = new APIResponseFactory();
|
|
23
|
-
|
|
24
|
-
// Set response factory:
|
|
25
|
-
this.createOKResponse = apiResponseFactory?.createOKResponse ??
|
|
26
|
-
standardAPIResponseFactory.createOKResponse.bind(standardAPIResponseFactory);
|
|
27
|
-
this.createErrorResponse = apiResponseFactory?.createErrorResponse ??
|
|
28
|
-
standardAPIResponseFactory.createErrorResponse.bind(standardAPIResponseFactory);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
processError(error, req, res) {
|
|
32
|
-
// Default error message.
|
|
33
|
-
let errorMessage = error?.message ?? 'Internal server error';
|
|
34
|
-
// Default HTTP status code.
|
|
35
|
-
let statusCode = error?.status ?? error?.statusCode ?? 500;
|
|
36
|
-
// Error response object.
|
|
37
|
-
let errorResponse = {};
|
|
38
|
-
|
|
39
|
-
switch(error.name) {
|
|
40
|
-
case('Unauthorized'): {
|
|
41
|
-
statusCode = 406;
|
|
42
|
-
errorResponse.details = { message: 'Email or password are incorrect.' };
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
case('ValidationError'): {
|
|
46
|
-
statusCode = 402;
|
|
47
|
-
errorResponse.details = { message: 'Invalid email OR password input.' };
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
case('InvalidToken'): {
|
|
51
|
-
statusCode = 401;
|
|
52
|
-
errorResponse.details = { message: 'Invalid token or token expired.' };
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
case('UserNotFound'): {
|
|
56
|
-
statusCode = 400;
|
|
57
|
-
errorResponse.details = { message: "Such user doesn't exist." };
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
default: {
|
|
61
|
-
errorResponse.details = { message: 'Could not process request.' };
|
|
62
|
-
break;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Send error response with provided status code.
|
|
67
|
-
return this.createErrorResponse({
|
|
68
|
-
res,
|
|
69
|
-
error: {
|
|
70
|
-
...errorResponse,
|
|
71
|
-
code: statusCode
|
|
72
|
-
},
|
|
73
|
-
status: statusCode
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async login(req, res) {
|
|
78
|
-
try {
|
|
79
|
-
// Extract request input:
|
|
80
|
-
const {
|
|
81
|
-
email,
|
|
82
|
-
password,
|
|
83
|
-
role,
|
|
84
|
-
} = Params(req.body, {
|
|
85
|
-
email: null,
|
|
86
|
-
password: null,
|
|
87
|
-
role: 'user',
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
if (!email|| !password) {
|
|
91
|
-
// If bad input, throw ValidationError:
|
|
92
|
-
const err = new Error('Invalid email OR password input');
|
|
93
|
-
err.name = 'ValidationError';
|
|
94
|
-
throw err;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Lowercase email.
|
|
98
|
-
const _email = lowerCase(email);
|
|
99
|
-
|
|
100
|
-
const params = {
|
|
101
|
-
email: _email,
|
|
102
|
-
password,
|
|
103
|
-
role
|
|
104
|
-
};
|
|
105
|
-
const result = await this.facade.login(params);
|
|
106
|
-
|
|
107
|
-
// Everything's fine, send response.
|
|
108
|
-
return this.createOKResponse({
|
|
109
|
-
res,
|
|
110
|
-
content: { ...result }
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
catch(error) {
|
|
114
|
-
console.error(`${ this.name }.login error:`, error);
|
|
115
|
-
return this.processError(error, req, res);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async validate(req, res) {
|
|
120
|
-
try {
|
|
121
|
-
const token = this.facade.service.extractTokenFromRequest(req);
|
|
122
|
-
|
|
123
|
-
// Validate token against local seed.
|
|
124
|
-
await this.facade.service.verifyAccessToken(token);
|
|
125
|
-
|
|
126
|
-
// Everything's fine, send response.
|
|
127
|
-
return this.createOKResponse({
|
|
128
|
-
res,
|
|
129
|
-
content: {
|
|
130
|
-
isValid: true,
|
|
131
|
-
message: "Valid Token"
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
catch(error) {
|
|
136
|
-
console.error("JWTController.validate error: ", error);
|
|
137
|
-
|
|
138
|
-
// In any error case, we send token not valid:
|
|
139
|
-
// Create custom error with name InvalidToken.
|
|
140
|
-
const err = new Error('Invalid Token!');
|
|
141
|
-
err.name = 'InvalidToken';
|
|
142
|
-
return this.processError(err, req, res);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async refresh(req, res) {
|
|
147
|
-
try {
|
|
148
|
-
const refreshToken = this.facade.service.extractRefreshTokenFromRequest(req);
|
|
149
|
-
|
|
150
|
-
// Validate token against local seed.
|
|
151
|
-
const parsedToken = await this.facade.service.verifyRefreshToken(refreshToken);
|
|
152
|
-
|
|
153
|
-
// Everything's ok, issue new one.
|
|
154
|
-
const accessToken = await this.facade.refreshAccessToken({
|
|
155
|
-
refreshToken: refreshToken,
|
|
156
|
-
parsedRefreshToken: parsedToken
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
return this.createOKResponse({
|
|
160
|
-
res,
|
|
161
|
-
content: {
|
|
162
|
-
token: accessToken
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
catch(error) {
|
|
167
|
-
console.error(`${ this.name }.refresh error:`, error);
|
|
168
|
-
|
|
169
|
-
// In any error case, we send token not valid:
|
|
170
|
-
// Create custom error with name InvalidToken.
|
|
171
|
-
const err = new Error('Invalid Token!');
|
|
172
|
-
err.name = 'InvalidToken';
|
|
173
|
-
return this.processError(err, req, res);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
async disableRefreshToken(req, res) {
|
|
178
|
-
try {
|
|
179
|
-
const refreshToken = this.facade.service.extractRefreshTokenFromRequest(req);
|
|
180
|
-
|
|
181
|
-
// Validate refreshToken against local seed.
|
|
182
|
-
const parsedToken = await this.facade.service.verifyRefreshToken(refreshToken);
|
|
183
|
-
|
|
184
|
-
const createdStatus = await this.facade.disableRefreshToken({ refreshToken, parsedToken });
|
|
185
|
-
|
|
186
|
-
return this.createOKResponse({
|
|
187
|
-
res,
|
|
188
|
-
content: {
|
|
189
|
-
success: createdStatus,
|
|
190
|
-
disabled: createdStatus
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
catch(error) {
|
|
195
|
-
console.error(`${ this.name }.disableRefreshToken error:`, error);
|
|
196
|
-
|
|
197
|
-
// In any error case, we send token not valid:
|
|
198
|
-
// Create custom error with name InvalidToken.
|
|
199
|
-
const err = new Error('Invalid Token!');
|
|
200
|
-
err.name = 'InvalidToken';
|
|
201
|
-
return this.processError(err, req, res);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async logout(req, res) {
|
|
206
|
-
try {
|
|
207
|
-
const refreshToken = this.facade.service.extractRefreshTokenFromRequest(req);
|
|
208
|
-
|
|
209
|
-
if (!refreshToken) {
|
|
210
|
-
const err = new Error('No refreshToken found');
|
|
211
|
-
err.name = 'Unauthorized';
|
|
212
|
-
err.status = 401;
|
|
213
|
-
throw err;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Verifys and parses token. On failed validation will throw error.
|
|
217
|
-
const parsedToken = await this.facade.service.verifyRefreshToken(refreshToken);
|
|
218
|
-
|
|
219
|
-
// Everything's ok, destroy token.
|
|
220
|
-
const { status } = await this.facade.disableRefreshToken({ refreshToken, parsedToken });
|
|
221
|
-
|
|
222
|
-
return this.createOKResponse({
|
|
223
|
-
res,
|
|
224
|
-
content: {
|
|
225
|
-
status: status,
|
|
226
|
-
loggedIn: status === true
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
catch(error) {
|
|
231
|
-
console.error(`${ this.name }.logout error:`, error);
|
|
232
|
-
|
|
233
|
-
// In any error case, we send token not valid:
|
|
234
|
-
// Create custom error with name InvalidToken.
|
|
235
|
-
const err = new Error('Invalid Token!');
|
|
236
|
-
err.name = 'InvalidToken';
|
|
237
|
-
return this.processError(err, req, res);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
// Query preprocessor.
|
|
2
|
-
const QueryPreprocessor = require('nodester/preprocessors/QueryPreprocessor');
|
|
3
|
-
// Reponse protocol generator.
|
|
4
|
-
const APIResponseFactory = require('nodester/factories/responses/api');
|
|
5
|
-
// Custom error.
|
|
6
|
-
const { Err } = require('nodester/factories/errors');
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
module.exports = class ServiceController {
|
|
10
|
-
constructor({
|
|
11
|
-
name,
|
|
12
|
-
queryPreprocessor,
|
|
13
|
-
apiResponseFactory,
|
|
14
|
-
}) {
|
|
15
|
-
if (!name) {
|
|
16
|
-
const err = new Err();
|
|
17
|
-
err.details = 'Argument "name" is required';
|
|
18
|
-
throw err;
|
|
19
|
-
}
|
|
20
|
-
// Set private name of this controller.
|
|
21
|
-
this.name = name;
|
|
22
|
-
|
|
23
|
-
// Set preprocessors:
|
|
24
|
-
this.queryPreprocessor = queryPreprocessor ?? new QueryPreprocessor();
|
|
25
|
-
// TODO: body preprocessor.
|
|
26
|
-
|
|
27
|
-
// Init standard API response factory.
|
|
28
|
-
const standardAPIResponseFactory = new APIResponseFactory();
|
|
29
|
-
// Set response factory:
|
|
30
|
-
this.createOKResponse = apiResponseFactory?.createOKResponse ??
|
|
31
|
-
standardAPIResponseFactory.createOKResponse.bind(standardAPIResponseFactory);
|
|
32
|
-
this.createErrorResponse = apiResponseFactory?.createErrorResponse ??
|
|
33
|
-
standardAPIResponseFactory.createErrorResponse.bind(standardAPIResponseFactory);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
processError(error, req, res) {
|
|
37
|
-
// Default error message.
|
|
38
|
-
let errorMessage = error?.message ?? 'Internal server error';
|
|
39
|
-
// Default HTTP status code.
|
|
40
|
-
let statusCode = error?.status ?? error?.statusCode ?? 500;
|
|
41
|
-
// Error response object.
|
|
42
|
-
let errorResponse = {};
|
|
43
|
-
|
|
44
|
-
switch(error.name) {
|
|
45
|
-
case('NotFound'): {
|
|
46
|
-
statusCode = 404;
|
|
47
|
-
errorResponse.details = { message: errorMessage };
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
case('ValidationError'): {
|
|
51
|
-
statusCode = 406;
|
|
52
|
-
errorResponse.details = error?.details;
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
case('ConflictError'): {
|
|
56
|
-
statusCode = 409;
|
|
57
|
-
errorResponse.details = error?.details ?? error?.message;
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
case('SequelizeUniqueConstraintError'): {
|
|
61
|
-
statusCode = 409;
|
|
62
|
-
errorResponse.details = error?.errors;
|
|
63
|
-
break;
|
|
64
|
-
}
|
|
65
|
-
case('InternalValidationError'): {
|
|
66
|
-
statusCode = 500;
|
|
67
|
-
errorResponse.details = { message: 'Error' };
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
default: {
|
|
71
|
-
errorResponse.details = { message: errorMessage };
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Send error response with provided status code.
|
|
77
|
-
return this.createErrorResponse({
|
|
78
|
-
res,
|
|
79
|
-
error: {
|
|
80
|
-
...errorResponse,
|
|
81
|
-
code: statusCode
|
|
82
|
-
},
|
|
83
|
-
status: statusCode
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Preprocessors:
|
|
88
|
-
async extractQuery(req, res) {
|
|
89
|
-
try {
|
|
90
|
-
// Extract role.
|
|
91
|
-
const role = req?.token?.parsed?.role ?? 'visitor';
|
|
92
|
-
|
|
93
|
-
// Extract query:
|
|
94
|
-
const query = await this.queryPreprocessor.extract(
|
|
95
|
-
req,
|
|
96
|
-
role,
|
|
97
|
-
);
|
|
98
|
-
const { includes } = req.query;
|
|
99
|
-
|
|
100
|
-
return Promise.resolve({
|
|
101
|
-
query,
|
|
102
|
-
includes,
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
catch(error) {
|
|
106
|
-
return Promise.reject(error);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
// Data extractor:
|
|
2
|
-
const Extractor = require('nodester/models/Extractor');
|
|
3
|
-
// Query preprocessor.
|
|
4
|
-
const QueryPreprocessor = require('nodester/preprocessors/QueryPreprocessor');
|
|
5
|
-
// Reponse protocol generator.
|
|
6
|
-
const WebResponseFactory = require('nodester/factories/responses/html');
|
|
7
|
-
// Custom error.
|
|
8
|
-
const { Err } = require('nodester/factories/errors');
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
module.exports = class Controller {
|
|
12
|
-
constructor({
|
|
13
|
-
modelFacade,
|
|
14
|
-
queryPreprocessor,
|
|
15
|
-
webResponseFactory,
|
|
16
|
-
|
|
17
|
-
// Options.
|
|
18
|
-
withFiles,
|
|
19
|
-
}) {
|
|
20
|
-
if (!modelFacade) {
|
|
21
|
-
throw new Error('"modelFacade" argument is invalid.');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Main model.
|
|
25
|
-
const model = modelFacade?.model;
|
|
26
|
-
|
|
27
|
-
// Set main services & utils:
|
|
28
|
-
this.extractor = new Extractor(model, { withFiles: !!withFiles });
|
|
29
|
-
this.facade = modelFacade;
|
|
30
|
-
|
|
31
|
-
// Set preprocessors:
|
|
32
|
-
// TODO: includes preprocessor.
|
|
33
|
-
this.queryPreprocessor = queryPreprocessor ?? new QueryPreprocessor();
|
|
34
|
-
// TODO: body preprocessor.
|
|
35
|
-
|
|
36
|
-
// Extract plural name of model.
|
|
37
|
-
const modelPluralName = model?.options?.name?.plural;
|
|
38
|
-
// Set private name of this controller.
|
|
39
|
-
this.name = `${modelPluralName ?? '_INVALID_NAME_'}Controller`;
|
|
40
|
-
|
|
41
|
-
// Init standard Web response factory.
|
|
42
|
-
const standardWebResponseFactory = new WebResponseFactory();
|
|
43
|
-
// Set response factory:
|
|
44
|
-
this.createOKResponse = webResponseFactory?.createOKResponse ??
|
|
45
|
-
standardWebResponseFactory.createOKResponse.bind(standardWebResponseFactory);
|
|
46
|
-
this.createErrorResponse = webResponseFactory?.createErrorResponse ??
|
|
47
|
-
standardWebResponseFactory.createErrorResponse.bind(standardWebResponseFactory);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// TODO: Implement CRUD.
|
|
51
|
-
|
|
52
|
-
// Preprocessors:
|
|
53
|
-
async extractQuery(req, res) {
|
|
54
|
-
try {
|
|
55
|
-
// Extract role.
|
|
56
|
-
const role = req?.token?.parsed?.role ?? 'visitor';
|
|
57
|
-
|
|
58
|
-
// Extract query:
|
|
59
|
-
const query = await this.queryPreprocessor.extract(
|
|
60
|
-
req,
|
|
61
|
-
role,
|
|
62
|
-
);
|
|
63
|
-
const { includes } = req.query;
|
|
64
|
-
|
|
65
|
-
return Promise.resolve({
|
|
66
|
-
query,
|
|
67
|
-
includes,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
catch(error) {
|
|
71
|
-
return Promise.reject(error);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
}
|