express-generator-typescript 2.1.3 → 2.1.5
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/lib/project-files/spec/tests/auth.spec.ts +3 -2
- package/lib/project-files/spec/tests/users.spec.ts +7 -7
- package/lib/project-files/src/pre-start/env/development.env +1 -1
- package/lib/project-files/src/routes/api.ts +55 -7
- package/lib/project-files/src/routes/{auth-router.ts → auth-routes.ts} +7 -12
- package/lib/project-files/src/routes/middleware.ts +41 -14
- package/lib/project-files/src/routes/{user-router.ts → user-routes.ts} +9 -19
- package/lib/project-files/src/util/jwt-util.ts +1 -1
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@ import app from '@server';
|
|
|
7
7
|
import userRepo from '@repos/user-repo';
|
|
8
8
|
import envVars from '@shared/env-vars';
|
|
9
9
|
import User, { UserRoles } from '@models/user-model';
|
|
10
|
-
import
|
|
10
|
+
import authRoutes from '@routes/auth-routes';
|
|
11
11
|
import { pwdSaltRounds } from 'spec/support/login-agent';
|
|
12
12
|
import { UnauthorizedError } from '@shared/errors';
|
|
13
13
|
|
|
@@ -15,7 +15,8 @@ import { UnauthorizedError } from '@shared/errors';
|
|
|
15
15
|
// **** Variables **** //
|
|
16
16
|
|
|
17
17
|
// Misc
|
|
18
|
-
const
|
|
18
|
+
const { paths } = authRoutes,
|
|
19
|
+
authPath = ('/api' + paths.basePath),
|
|
19
20
|
loginPath = `${authPath}${paths.login}`,
|
|
20
21
|
logoutPath = `${authPath}${paths.logout}`,
|
|
21
22
|
{ BAD_REQUEST, OK, UNAUTHORIZED } = StatusCodes;
|
|
@@ -6,11 +6,10 @@ import logger from 'jet-logger';
|
|
|
6
6
|
import app from '@server';
|
|
7
7
|
import userRepo from '@repos/user-repo';
|
|
8
8
|
import User, { IUser } from '@models/user-model';
|
|
9
|
+
import userRoutes from '@routes/user-routes';
|
|
9
10
|
|
|
10
|
-
import { p as userPaths } from '@routes/user-router';
|
|
11
11
|
import {
|
|
12
12
|
ParamInvalidError,
|
|
13
|
-
// ParamMissingError,
|
|
14
13
|
UserNotFoundError,
|
|
15
14
|
ValidatorFnError,
|
|
16
15
|
} from '@shared/errors';
|
|
@@ -20,11 +19,12 @@ import loginAgent from '../support/login-agent';
|
|
|
20
19
|
// **** Variables **** //
|
|
21
20
|
|
|
22
21
|
// Misc
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
const { paths } = userRoutes,
|
|
23
|
+
usersPath = ('/api' + paths.basePath),
|
|
24
|
+
getUsersPath = `${usersPath}${paths.get}`,
|
|
25
|
+
addUsersPath = `${usersPath}${paths.add}`,
|
|
26
|
+
updateUserPath = `${usersPath}${paths.update}`,
|
|
27
|
+
deleteUserPath = `${usersPath}${paths.delete}`,
|
|
28
28
|
{ BAD_REQUEST, CREATED, OK } = StatusCodes;
|
|
29
29
|
|
|
30
30
|
// Dummy users for GET req
|
|
@@ -1,16 +1,64 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { adminMw } from './middleware';
|
|
3
2
|
|
|
4
|
-
import
|
|
5
|
-
import
|
|
3
|
+
import { adminMw, validate } from './middleware';
|
|
4
|
+
import User from '@models/user-model';
|
|
5
|
+
import authRoutes from './auth-routes';
|
|
6
|
+
import userRoutes from './user-routes';
|
|
6
7
|
|
|
7
8
|
|
|
8
|
-
// Init
|
|
9
|
+
// **** Init **** //
|
|
10
|
+
|
|
9
11
|
const apiRouter = Router();
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
// **** Setup auth routes **** //
|
|
15
|
+
|
|
16
|
+
const authRouter = Router();
|
|
17
|
+
|
|
18
|
+
// Login user
|
|
19
|
+
authRouter.post(
|
|
20
|
+
authRoutes.paths.login,
|
|
21
|
+
validate('email', 'password'),
|
|
22
|
+
authRoutes.login,
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
// Logout user
|
|
26
|
+
authRouter.get(authRoutes.paths.logout, authRoutes.logout);
|
|
27
|
+
|
|
28
|
+
// Add authRouter
|
|
29
|
+
apiRouter.use(authRoutes.paths.basePath, authRouter);
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
// **** Setup user routes **** //
|
|
33
|
+
|
|
34
|
+
const userRouter = Router();
|
|
35
|
+
|
|
36
|
+
// Get all users
|
|
37
|
+
userRouter.get(userRoutes.paths.get, userRoutes.getAll);
|
|
38
|
+
|
|
39
|
+
// Add one user
|
|
40
|
+
userRouter.post(
|
|
41
|
+
userRoutes.paths.add,
|
|
42
|
+
validate(['user', User.instanceOf]),
|
|
43
|
+
userRoutes.add,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// Update one user
|
|
47
|
+
userRouter.put(
|
|
48
|
+
userRoutes.paths.update,
|
|
49
|
+
validate(['user', User.instanceOf]),
|
|
50
|
+
userRoutes.update,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// Delete one user
|
|
54
|
+
userRouter.delete(
|
|
55
|
+
userRoutes.paths.delete,
|
|
56
|
+
validate(['id', 'number', 'params']),
|
|
57
|
+
userRoutes.delete,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Add userRouter
|
|
61
|
+
apiRouter.use(userRoutes.paths.basePath, adminMw, userRouter);
|
|
14
62
|
|
|
15
63
|
|
|
16
64
|
// **** Export default **** //
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { Router } from 'express';
|
|
2
1
|
import StatusCodes from 'http-status-codes';
|
|
3
2
|
|
|
4
3
|
import authService from '@services/auth-service';
|
|
5
4
|
import envVars from 'src/shared/env-vars';
|
|
6
5
|
import { IReq, IRes } from '@shared/types';
|
|
7
|
-
import { vld } from './middleware';
|
|
8
6
|
|
|
9
7
|
|
|
10
8
|
// **** Types **** //
|
|
@@ -21,20 +19,13 @@ interface ILoginReq {
|
|
|
21
19
|
const { OK } = StatusCodes;
|
|
22
20
|
|
|
23
21
|
// Paths
|
|
24
|
-
|
|
22
|
+
const paths = {
|
|
25
23
|
basePath: '/auth',
|
|
26
24
|
login: '/login',
|
|
27
25
|
logout: '/logout',
|
|
28
26
|
} as const;
|
|
29
27
|
|
|
30
28
|
|
|
31
|
-
// **** Setup Router **** //
|
|
32
|
-
|
|
33
|
-
const router = Router();
|
|
34
|
-
router.post(p.login, vld('email', 'password'), login);
|
|
35
|
-
router.get(p.logout, logout);
|
|
36
|
-
|
|
37
|
-
|
|
38
29
|
// **** Functions **** //
|
|
39
30
|
|
|
40
31
|
/**
|
|
@@ -60,6 +51,10 @@ function logout(_: IReq, res: IRes) {
|
|
|
60
51
|
}
|
|
61
52
|
|
|
62
53
|
|
|
63
|
-
// **** Export
|
|
54
|
+
// **** Export default **** //
|
|
64
55
|
|
|
65
|
-
export default
|
|
56
|
+
export default {
|
|
57
|
+
paths,
|
|
58
|
+
login,
|
|
59
|
+
logout,
|
|
60
|
+
} as const;
|
|
@@ -69,10 +69,10 @@ export async function adminMw(
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* array. If an array the format is:
|
|
72
|
+
* This function returns a middleware-function that validates the parameters
|
|
73
|
+
* provided. Each argument can be a string or array.
|
|
75
74
|
*
|
|
75
|
+
* If the argument is an array the format is:
|
|
76
76
|
* ['paramName', '(optional) type or validator function (default is string)',
|
|
77
77
|
* '(optional) property on "req" to extract the value from (default is body')]
|
|
78
78
|
*
|
|
@@ -85,26 +85,30 @@ export async function adminMw(
|
|
|
85
85
|
* are valid for req.query and req.params. But on req.body a number should be
|
|
86
86
|
* 'typeof toCheck === "number"'
|
|
87
87
|
*
|
|
88
|
+
* **NOTE**: For booleans, on req.body must be true or false, on req.query or
|
|
89
|
+
* req.params must be 'true' or 'false'.
|
|
90
|
+
*
|
|
88
91
|
* Sample argument: ['id', 'number'], id is the incoming variable, 'number'
|
|
89
92
|
* is the type, and body is where to extract 'id' from.
|
|
90
93
|
*
|
|
91
|
-
* Example 1:
|
|
94
|
+
* Example 1: validate('email', ['user', 'object'], ['id', 'number', 'params'])
|
|
92
95
|
* will check that 'email' is a string in req.body, that user is of type
|
|
93
96
|
* object in req.body, and that 'id' is a boolean in req.params.
|
|
94
|
-
* Example 2:
|
|
97
|
+
* Example 2: validate('password') will check that 'password' is a string on
|
|
95
98
|
* req.body.
|
|
96
|
-
* Example 3:
|
|
99
|
+
* Example 3: validate(['isAdmin', 'boolean']) will check that 'isAdmin' is a
|
|
97
100
|
* boolean on req.body
|
|
98
|
-
* Example 4:
|
|
101
|
+
* Example 4: validate(['user', isInstanceOfUser]) will check that 'user'
|
|
99
102
|
* satifies the 'isInstanceOfUser()' function.
|
|
100
|
-
* Example 5:
|
|
103
|
+
* Example 5: validate(['email']) will check that 'email' is a string in
|
|
104
|
+
* req.body,
|
|
101
105
|
*/
|
|
102
|
-
export function
|
|
106
|
+
export function validate(...params: Array<string | TParamArr>): RequestHandler {
|
|
103
107
|
return (req: Request, _: Response, next: NextFunction) => {
|
|
104
108
|
for (const param of params) {
|
|
105
109
|
// Check params
|
|
106
110
|
if (typeof param !== 'string' && !(param instanceof Array)) {
|
|
107
|
-
throw Error('
|
|
111
|
+
throw Error('"validate()" arg must be a string or array');
|
|
108
112
|
}
|
|
109
113
|
// If param is a string, make sure param is of type string on req.body
|
|
110
114
|
if (typeof param === 'string') {
|
|
@@ -137,16 +141,25 @@ export function vld(...params: Array<string | TParamArr>): RequestHandler {
|
|
|
137
141
|
const fn = param[1];
|
|
138
142
|
if (!fn(toValidate)) {
|
|
139
143
|
throw new ValidatorFnError(fn.name);
|
|
144
|
+
} else {
|
|
145
|
+
continue;
|
|
140
146
|
}
|
|
141
|
-
// If type is a number,
|
|
142
|
-
// number-strings (i.e. '1243') in req.query or req.params. But in
|
|
143
|
-
// req.body, numbers should be 'typeof toCheck === "number"'
|
|
147
|
+
// If type is a number, see note above.
|
|
144
148
|
} else if (param[1] === 'number') {
|
|
145
149
|
if (reqObjProp === 'query' || reqObjProp === 'params') {
|
|
146
150
|
if (isNaN(toValidate as number)) {
|
|
147
151
|
throw new ParamInvalidError();
|
|
148
152
|
}
|
|
149
|
-
} else if (typeof toValidate !== 'number') {
|
|
153
|
+
} else if (reqObjProp === 'body' && typeof toValidate !== 'number') {
|
|
154
|
+
throw new ParamInvalidError();
|
|
155
|
+
}
|
|
156
|
+
// If type is a boolean, see note above.
|
|
157
|
+
} else if (param[1] === 'boolean') {
|
|
158
|
+
if (reqObjProp === 'query' || reqObjProp === 'params') {
|
|
159
|
+
if (!isBool(toValidate as boolean)) {
|
|
160
|
+
throw new ParamInvalidError();
|
|
161
|
+
}
|
|
162
|
+
} else if (reqObjProp === 'body' && typeof toValidate !== 'boolean') {
|
|
150
163
|
throw new ParamInvalidError();
|
|
151
164
|
}
|
|
152
165
|
// Check the param is the provided type
|
|
@@ -158,3 +171,17 @@ export function vld(...params: Array<string | TParamArr>): RequestHandler {
|
|
|
158
171
|
next();
|
|
159
172
|
};
|
|
160
173
|
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Checks if arg is a boolean, or a string that is 'true', or 'false'.
|
|
177
|
+
*/
|
|
178
|
+
function isBool(arg: string | boolean): boolean {
|
|
179
|
+
if (typeof arg === 'boolean') {
|
|
180
|
+
return true;
|
|
181
|
+
} else if (typeof arg === 'string') {
|
|
182
|
+
arg = arg.toLowerCase();
|
|
183
|
+
return (arg === 'true' || arg === 'false');
|
|
184
|
+
} else {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import StatusCodes from 'http-status-codes';
|
|
2
|
-
import { Router } from 'express';
|
|
3
2
|
|
|
4
3
|
import userService from '@services/user-service';
|
|
5
|
-
import
|
|
4
|
+
import { IUser } from '@models/user-model';
|
|
6
5
|
import { IReq, IRes } from '@shared/types';
|
|
7
|
-
import { vld } from './middleware';
|
|
8
|
-
|
|
9
6
|
|
|
10
7
|
|
|
11
8
|
// **** Variables **** //
|
|
@@ -14,7 +11,7 @@ import { vld } from './middleware';
|
|
|
14
11
|
const { CREATED, OK } = StatusCodes;
|
|
15
12
|
|
|
16
13
|
// Paths
|
|
17
|
-
|
|
14
|
+
const paths = {
|
|
18
15
|
basePath: '/users',
|
|
19
16
|
get: '/all',
|
|
20
17
|
add: '/add',
|
|
@@ -23,19 +20,6 @@ export const p = {
|
|
|
23
20
|
} as const;
|
|
24
21
|
|
|
25
22
|
|
|
26
|
-
// **** Setup Router **** //
|
|
27
|
-
|
|
28
|
-
// Validators (place shared or really long ones here)
|
|
29
|
-
const validateUser = vld(['user', User.instanceOf]);
|
|
30
|
-
|
|
31
|
-
// Add routes to express
|
|
32
|
-
const router = Router();
|
|
33
|
-
router.get(p.get, getAll);
|
|
34
|
-
router.post(p.add, validateUser, add);
|
|
35
|
-
router.put(p.update, validateUser, update);
|
|
36
|
-
router.delete(p.delete, vld(['id', 'number', 'params']), _delete);
|
|
37
|
-
|
|
38
|
-
|
|
39
23
|
// **** Functions **** //
|
|
40
24
|
|
|
41
25
|
/**
|
|
@@ -76,4 +60,10 @@ async function _delete(req: IReq, res: IRes) {
|
|
|
76
60
|
|
|
77
61
|
// **** Export default **** //
|
|
78
62
|
|
|
79
|
-
export default
|
|
63
|
+
export default {
|
|
64
|
+
paths,
|
|
65
|
+
getAll,
|
|
66
|
+
add,
|
|
67
|
+
update,
|
|
68
|
+
delete: _delete,
|
|
69
|
+
} as const;
|
|
@@ -31,7 +31,7 @@ function sign(data: string | object | Buffer): Promise<string> {
|
|
|
31
31
|
/**
|
|
32
32
|
* Decrypt JWT and extract client data.
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
function decode<T>(jwt: string): Promise<string | undefined | T> {
|
|
35
35
|
return new Promise((res, rej) => {
|
|
36
36
|
jsonwebtoken.verify(jwt, envVars.jwt.secret, (err, decoded) => {
|
|
37
37
|
return err ? rej(errors.validation) : res(decoded as T);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-generator-typescript",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.5",
|
|
4
4
|
"description": "Generate new Express applications similar to express-generate which but sets it up to use TypeScript instead",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"express-generator-typescript": "node bin/cli.js",
|