express-generator-typescript 1.10.2 → 1.10.3

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.
@@ -1,5 +1,5 @@
1
1
  import { Router } from 'express';
2
- import { adminMw } from './middleware';
2
+ import { authMw } from './middleware';
3
3
  import authRouter from './auth-router';
4
4
  import userRouter from './user-router';
5
5
 
@@ -9,7 +9,7 @@ const apiRouter = Router();
9
9
 
10
10
  // Add api routes
11
11
  apiRouter.use('/auth', authRouter);
12
- apiRouter.use('/users', adminMw, userRouter);
12
+ apiRouter.use('/users', authMw, userRouter);
13
13
 
14
14
 
15
15
  // **** Export default **** //
@@ -4,6 +4,15 @@ import StatusCodes from 'http-status-codes';
4
4
  import authService from '@services/auth-service';
5
5
  import { ParamMissingError } from '@shared/errors';
6
6
  import envVars from 'src/shared/env-vars';
7
+ import { IReq } from 'src/types/express';
8
+
9
+
10
+ // **** Types **** //
11
+
12
+ interface ILogin {
13
+ email: string;
14
+ password: string;
15
+ }
7
16
 
8
17
 
9
18
  // **** Variables **** //
@@ -24,7 +33,7 @@ export const p = {
24
33
  /**
25
34
  * Login a user.
26
35
  */
27
- router.post(p.login, async (req: Request, res: Response) => {
36
+ router.post(p.login, async (req: IReq<ILogin>, res: Response) => {
28
37
  // Check email and password present
29
38
  const { email, password } = req.body;
30
39
  if (!email || !password) {
@@ -2,8 +2,8 @@ import StatusCodes from 'http-status-codes';
2
2
  import { Request, Response, NextFunction } from 'express';
3
3
  import { JwtPayload } from 'jsonwebtoken';
4
4
 
5
- import { IUser, UserRoles } from '@models/user-model';
6
- import envVars from 'src/shared/env-vars';
5
+ import envVars from '@shared/env-vars';
6
+ import { IUser } from '@models/user-model';
7
7
  import jwtUtil from '@util/jwt-util';
8
8
 
9
9
 
@@ -26,26 +26,24 @@ export interface ISessionUser extends JwtPayload {
26
26
  // **** Functions **** //
27
27
 
28
28
  /**
29
- * Middleware to verify if user is an admin.
29
+ * Middleware to verify if user logged in.
30
30
  */
31
- export async function adminMw(req: Request, res: Response, next: NextFunction) {
32
- // Try
31
+ export async function authMw(req: Request, res: Response, next: NextFunction) {
33
32
  try {
34
- // Extract the token
33
+ // Get json-web-token
35
34
  const jwt = req.signedCookies[envVars.cookieProps.key];
36
35
  if (!jwt) {
37
36
  throw Error(jwtNotPresentErr);
38
37
  }
39
38
  // Make sure user role is an admin
40
- const clientData = await jwtUtil.decode(jwt);
41
- if (typeof clientData === 'object' && clientData.role === UserRoles.Admin) {
42
- res.locals.sessionUser = clientData as ISessionUser;
39
+ const clientData = await jwtUtil.decode<ISessionUser>(jwt);
40
+ if (!!clientData) {
41
+ res.locals.sessionUser = clientData;
43
42
  next();
44
43
  } else {
45
44
  throw Error(jwtNotPresentErr);
46
45
  }
47
- // Catch
48
- } catch (err: unknown) {
46
+ } catch (err) {
49
47
  let error;
50
48
  if (typeof err === 'string') {
51
49
  error = err;
@@ -55,4 +53,3 @@ export async function adminMw(req: Request, res: Response, next: NextFunction) {
55
53
  return res.status(UNAUTHORIZED).json({ error });
56
54
  }
57
55
  }
58
-
@@ -3,6 +3,8 @@ import { Request, Response, Router } from 'express';
3
3
 
4
4
  import userService from '@services/user-service';
5
5
  import { ParamMissingError } from '@shared/errors';
6
+ import { IReq } from 'src/types/express';
7
+ import { IUser } from '@models/user-model';
6
8
 
7
9
 
8
10
  // **** Variables **** //
@@ -33,7 +35,7 @@ router.get(p.get, async (_: Request, res: Response) => {
33
35
  /**
34
36
  * Add one user.
35
37
  */
36
- router.post(p.add, async (req: Request, res: Response) => {
38
+ router.post(p.add, async (req: IReq<{user: IUser}>, res: Response) => {
37
39
  const { user } = req.body;
38
40
  // Check param
39
41
  if (!user) {
@@ -47,7 +49,7 @@ router.post(p.add, async (req: Request, res: Response) => {
47
49
  /**
48
50
  * Update one user.
49
51
  */
50
- router.put(p.update, async (req: Request, res: Response) => {
52
+ router.put(p.update, async (req: IReq<{user: IUser}>, res: Response) => {
51
53
  const { user } = req.body;
52
54
  // Check param
53
55
  if (!user) {
@@ -1,18 +1,15 @@
1
- import { IUser } from '@models/user-model';
1
+ import * as e from 'express';
2
+ import 'express';
3
+
2
4
  import { ISessionUser } from '@routes/middleware';
3
5
 
4
6
 
7
+ // **** Declaration Merging **** //
8
+
5
9
  declare module 'express' {
6
10
 
7
- export interface Request {
8
- signedCookies: Record<string, string>,
9
- body: {
10
- user?: IUser
11
- email?: string;
12
- password?: string;
13
- message?: string;
14
- socketId?: string;
15
- };
11
+ export interface Request {
12
+ signedCookies: Record<string, string>;
16
13
  }
17
14
 
18
15
  export interface Response {
@@ -21,3 +18,15 @@ declare module 'express' {
21
18
  };
22
19
  }
23
20
  }
21
+
22
+
23
+ // **** Generics for Request Object **** //
24
+
25
+ export interface IReq<T> extends e.Request {
26
+ body: T;
27
+ }
28
+
29
+ export interface IReqQuery<T extends Query, U = void> extends e.Request {
30
+ query: T;
31
+ body?: U;
32
+ }
@@ -1,23 +1,17 @@
1
+ import randomString from 'randomstring';
1
2
  import jsonwebtoken, { JwtPayload } from 'jsonwebtoken';
2
- import envVars from '../shared/env-vars';
3
3
 
4
4
 
5
5
  // **** Variables **** //
6
6
 
7
7
  // Errors
8
8
  const errors = {
9
- validation: 'JSON-web-token validation failed.',
9
+ validation: 'JSON-web-token validation failed.',
10
10
  } as const;
11
11
 
12
- // Options
13
- const options = {
14
- expiresIn: envVars.jwt.exp,
15
- };
16
-
17
-
18
- // **** Types **** //
19
-
20
- type TDecoded = string | JwtPayload | undefined;
12
+ // Misc
13
+ const secret = (process.env.JWT_SECRET || randomString.generate(100));
14
+ const options = {expiresIn: process.env.COOKIE_EXP};
21
15
 
22
16
 
23
17
  // **** Functions **** //
@@ -27,8 +21,8 @@ type TDecoded = string | JwtPayload | undefined;
27
21
  */
28
22
  function sign(data: JwtPayload): Promise<string> {
29
23
  return new Promise((resolve, reject) => {
30
- jsonwebtoken.sign(data, envVars.jwt.secret, options, (err, token) => {
31
- err ? reject(err) : resolve(token || '');
24
+ jsonwebtoken.sign(data, secret, options, (err, token) => {
25
+ return err ? reject(err) : resolve(token || '');
32
26
  });
33
27
  });
34
28
  }
@@ -36,10 +30,10 @@ function sign(data: JwtPayload): Promise<string> {
36
30
  /**
37
31
  * Decrypt JWT and extract client data.
38
32
  */
39
- function decode(jwt: string): Promise<TDecoded> {
33
+ function decode<T>(jwt: string): Promise<T> {
40
34
  return new Promise((res, rej) => {
41
- jsonwebtoken.verify(jwt, envVars.jwt.secret, (err, decoded) => {
42
- return err ? rej(errors.validation) : res(decoded);
35
+ jsonwebtoken.verify(jwt, secret, (err, decoded) => {
36
+ return err ? rej(errors.validation) : res(decoded as T);
43
37
  });
44
38
  });
45
39
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  // User schema
4
4
  export interface IUser {
5
- id: number;
5
+ id?: number;
6
6
  name: string;
7
7
  email: string;
8
8
  }
@@ -3,6 +3,8 @@ import { Request, Response, Router } from 'express';
3
3
 
4
4
  import userService from '@services/user-service';
5
5
  import { ParamMissingError } from '@shared/errors';
6
+ import { IReq } from 'src/types/express';
7
+ import { IUser } from '@models/user-model';
6
8
 
7
9
 
8
10
  // **** Variables **** //
@@ -33,7 +35,7 @@ router.get(p.get, async (_: Request, res: Response) => {
33
35
  /**
34
36
  * Add one user
35
37
  */
36
- router.post(p.add, async (req: Request, res: Response) => {
38
+ router.post(p.add, async (req: IReq<{user: IUser}>, res: Response) => {
37
39
  const { user } = req.body;
38
40
  // Check param
39
41
  if (!user) {
@@ -47,7 +49,7 @@ router.post(p.add, async (req: Request, res: Response) => {
47
49
  /**
48
50
  * Update one user
49
51
  */
50
- router.put(p.update, async (req: Request, res: Response) => {
52
+ router.put(p.update, async (req: IReq<{user: IUser}>, res: Response) => {
51
53
  const { user } = req.body;
52
54
  // Check param
53
55
  if (!user) {
@@ -23,7 +23,7 @@ function addOne(user: IUser): Promise<void> {
23
23
  * Update one user
24
24
  */
25
25
  async function updateOne(user: IUser): Promise<void> {
26
- const persists = await userRepo.persists(user.id);
26
+ const persists = await userRepo.persists(user.id ?? -1);
27
27
  if (!persists) {
28
28
  throw new UserNotFoundError();
29
29
  }
@@ -1,12 +1,12 @@
1
- import { IUser } from "@models/user-model";
1
+ import * as e from 'express';
2
+ import { Query } from 'express-serve-static-core';
2
3
 
3
4
 
4
- declare module 'express' {
5
- export interface Request {
6
- body: {
7
- user?: IUser
8
- email?: string;
9
- };
10
- }
5
+ export interface IReq<T> extends e.Request {
6
+ body: T;
11
7
  }
12
8
 
9
+ export interface IReqQuery<T extends Query, U = void> extends e.Request {
10
+ query: T;
11
+ body?: U;
12
+ }
@@ -1,8 +1,10 @@
1
+ import { Request, Response, Router } from 'express';
2
+ import StatusCodes from 'http-status-codes';
1
3
 
2
4
  import authService from '@services/auth-service';
5
+ import envVars from '@shared/env-vars';
3
6
  import { ParamMissingError } from '@shared/errors';
4
- import { Request, Response, Router } from 'express';
5
- import StatusCodes from 'http-status-codes';
7
+ import { IReq } from 'src/types/express';
6
8
 
7
9
 
8
10
  // **** Variables **** //
@@ -17,19 +19,13 @@ export const p = {
17
19
  logout: '/logout',
18
20
  } as const;
19
21
 
20
- // Cookie Properties
21
- export const cookieProps = Object.freeze({
22
- key: 'ExpressGeneratorTs',
23
- secret: process.env.COOKIE_SECRET,
24
- options: {
25
- httpOnly: true,
26
- signed: true,
27
- path: (process.env.COOKIE_PATH),
28
- maxAge: Number(process.env.COOKIE_EXP),
29
- domain: (process.env.COOKIE_DOMAIN),
30
- secure: (process.env.SECURE_COOKIE === 'true'),
31
- },
32
- });
22
+
23
+ // **** Types **** //
24
+
25
+ interface ILoginReq {
26
+ email: string;
27
+ password: string;
28
+ }
33
29
 
34
30
 
35
31
  // **** Routes **** //
@@ -37,7 +33,7 @@ export const cookieProps = Object.freeze({
37
33
  /**
38
34
  * Login a user.
39
35
  */
40
- router.post(p.login, async (req: Request, res: Response) => {
36
+ router.post(p.login, async (req: IReq<ILoginReq>, res: Response) => {
41
37
  // Check email and password present
42
38
  const { email, password } = req.body;
43
39
  if (!(email && password)) {
@@ -46,7 +42,7 @@ router.post(p.login, async (req: Request, res: Response) => {
46
42
  // Get jwt
47
43
  const jwt = await authService.login(email, password);
48
44
  // Add jwt to cookie
49
- const { key, options } = cookieProps;
45
+ const { key, options } = envVars.cookieProps;
50
46
  res.cookie(key, jwt, options);
51
47
  // Return
52
48
  return res.status(OK).end();
@@ -56,7 +52,7 @@ router.post(p.login, async (req: Request, res: Response) => {
56
52
  * Logout the user.
57
53
  */
58
54
  router.get(p.logout, (_: Request, res: Response) => {
59
- const { key, options } = cookieProps;
55
+ const { key, options } = envVars.cookieProps;
60
56
  res.clearCookie(key, options);
61
57
  return res.status(OK).end();
62
58
  });
@@ -3,6 +3,7 @@ import StatusCodes from 'http-status-codes';
3
3
  import { Router, Request, Response } from 'express';
4
4
 
5
5
  import { ParamMissingError, RoomNotFoundError } from '@shared/errors';
6
+ import { IReq } from 'src/types/express';
6
7
 
7
8
 
8
9
  // **** Variables **** //
@@ -20,6 +21,14 @@ export const p = {
20
21
  export const socketRoomName = 'jet-logger-chat-room';
21
22
 
22
23
 
24
+ // **** Types **** //
25
+
26
+ interface IPostMsg {
27
+ message: string;
28
+ socketId: string;
29
+ }
30
+
31
+
23
32
  // **** Routes **** //
24
33
 
25
34
  /**
@@ -45,7 +54,7 @@ router.get(p.connect, async (req: Request, res: Response) => {
45
54
  /**
46
55
  * Send a chat message.
47
56
  */
48
- router.post(p.emit, (req: Request, res: Response) => {
57
+ router.post(p.emit, (req: IReq<IPostMsg>, res: Response) => {
49
58
  const { sessionUser } = res.locals;
50
59
  const { message, socketId } = req.body;
51
60
  // Check params
@@ -2,7 +2,7 @@ import StatusCodes from 'http-status-codes';
2
2
  import { Request, Response, NextFunction } from 'express';
3
3
  import { JwtPayload } from 'jsonwebtoken';
4
4
 
5
- import { cookieProps } from '@routes/auth-router';
5
+ import envVars from '@shared/env-vars';
6
6
  import { IUser } from '@models/user-model';
7
7
  import jwtUtil from '@util/jwt-util';
8
8
 
@@ -26,19 +26,19 @@ export interface ISessionUser extends JwtPayload {
26
26
  // **** Functions **** //
27
27
 
28
28
  /**
29
- * Middleware to verify if user is an admin.
29
+ * Middleware to verify if user is logged in.
30
30
  */
31
31
  export async function authMw(req: Request, res: Response, next: NextFunction) {
32
32
  try {
33
33
  // Get json-web-token
34
- const jwt = req.signedCookies[cookieProps.key];
34
+ const jwt = req.signedCookies[envVars.cookieProps.key];
35
35
  if (!jwt) {
36
36
  throw Error(jwtNotPresentErr);
37
37
  }
38
38
  // Make sure user role is an admin
39
- const clientData = await jwtUtil.decode(jwt);
40
- if (!!clientData && typeof clientData !== 'string') {
41
- res.locals.sessionUser = clientData as ISessionUser;
39
+ const clientData = await jwtUtil.decode<ISessionUser>(jwt);
40
+ if (!!clientData) {
41
+ res.locals.sessionUser = clientData;
42
42
  next();
43
43
  } else {
44
44
  throw Error(jwtNotPresentErr);
@@ -3,6 +3,8 @@ import { Request, Response, Router } from 'express';
3
3
 
4
4
  import userService from '@services/user-service';
5
5
  import { ParamMissingError } from '@shared/errors';
6
+ import { IReq } from 'src/types/express';
7
+ import { IUser } from '@models/user-model';
6
8
 
7
9
 
8
10
  // **** Variables **** //
@@ -33,7 +35,7 @@ router.get(p.get, async (_: Request, res: Response) => {
33
35
  /**
34
36
  * Add one user.
35
37
  */
36
- router.post(p.add, async (req: Request, res: Response) => {
38
+ router.post(p.add, async (req: IReq<{user: IUser}>, res: Response) => {
37
39
  const { user } = req.body;
38
40
  if (!user) {
39
41
  throw new ParamMissingError();
@@ -46,7 +48,7 @@ router.post(p.add, async (req: Request, res: Response) => {
46
48
  /**
47
49
  * Update one user.
48
50
  */
49
- router.put(p.update, async (req: Request, res: Response) => {
51
+ router.put(p.update, async (req: IReq<{user: IUser}>, res: Response) => {
50
52
  const { user } = req.body;
51
53
  if (!user) {
52
54
  throw new ParamMissingError();
@@ -56,7 +58,6 @@ router.put(p.update, async (req: Request, res: Response) => {
56
58
  return res.status(OK).end();
57
59
  });
58
60
 
59
-
60
61
  /**
61
62
  * Delete one user.
62
63
  */
@@ -1,18 +1,17 @@
1
- import { IUser } from '@models/user-model';
1
+ import 'express';
2
+ import * as e from 'express';
3
+ import { Query } from 'express-serve-static-core';
4
+
2
5
  import { ISessionUser } from '@routes/middleware';
3
6
 
4
7
 
8
+
9
+ // **** Declaration Merging **** //
10
+
5
11
  declare module 'express' {
6
12
 
7
- export interface Request {
8
- signedCookies: Record<string, string>,
9
- body: {
10
- user?: IUser
11
- email?: string;
12
- password?: string;
13
- message?: string;
14
- socketId?: string;
15
- };
13
+ export interface Request {
14
+ signedCookies: Record<string, string>;
16
15
  }
17
16
 
18
17
  export interface Response {
@@ -20,4 +19,16 @@ declare module 'express' {
20
19
  sessionUser: ISessionUser;
21
20
  };
22
21
  }
23
- }
22
+ }
23
+
24
+
25
+ // **** Generics for Request Object **** //
26
+
27
+ export interface IReq<T> extends e.Request {
28
+ body: T;
29
+ }
30
+
31
+ export interface IReqQuery<T extends Query, U = void> extends e.Request {
32
+ query: T;
33
+ body?: U;
34
+ }
@@ -14,11 +14,6 @@ const secret = (process.env.JWT_SECRET || randomString.generate(100));
14
14
  const options = {expiresIn: process.env.COOKIE_EXP};
15
15
 
16
16
 
17
- // **** Types **** //
18
-
19
- type TDecoded = string | JwtPayload | undefined;
20
-
21
-
22
17
  // **** Functions **** //
23
18
 
24
19
  /**
@@ -27,7 +22,7 @@ type TDecoded = string | JwtPayload | undefined;
27
22
  function sign(data: JwtPayload): Promise<string> {
28
23
  return new Promise((resolve, reject) => {
29
24
  jsonwebtoken.sign(data, secret, options, (err, token) => {
30
- err ? reject(err) : resolve(token || '');
25
+ return err ? reject(err) : resolve(token || '');
31
26
  });
32
27
  });
33
28
  }
@@ -35,10 +30,10 @@ function sign(data: JwtPayload): Promise<string> {
35
30
  /**
36
31
  * Decrypt JWT and extract client data.
37
32
  */
38
- function decode(jwt: string): Promise<TDecoded> {
33
+ function decode<T>(jwt: string): Promise<T> {
39
34
  return new Promise((res, rej) => {
40
35
  jsonwebtoken.verify(jwt, secret, (err, decoded) => {
41
- return err ? rej(errors.validation) : res(decoded);
36
+ return err ? rej(errors.validation) : res(decoded as T);
42
37
  });
43
38
  });
44
39
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-generator-typescript",
3
- "version": "1.10.2",
3
+ "version": "1.10.3",
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",