express-generator-typescript 1.10.1 → 2.0.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.
Files changed (119) hide show
  1. package/README.md +37 -25
  2. package/bin/cli.js +2 -15
  3. package/lib/cli.js +1 -15
  4. package/lib/express-generator-typescript.js +15 -23
  5. package/lib/project-files/.eslintrc.json +15 -2
  6. package/lib/project-files/build.ts +2 -2
  7. package/lib/project-files/package.json +15 -5
  8. package/lib/project-files/spec/nodemon.json +1 -1
  9. package/lib/{auth-proj → project-files}/spec/support/login-agent.ts +0 -0
  10. package/lib/{auth-proj → project-files}/spec/tests/auth.spec.ts +18 -32
  11. package/lib/project-files/spec/tests/users.spec.ts +31 -22
  12. package/lib/project-files/spec/types/supertest/index.d.ts +14 -0
  13. package/lib/project-files/src/models/user-model.ts +17 -2
  14. package/lib/project-files/src/pre-start/env/development.env +9 -0
  15. package/lib/project-files/src/pre-start/env/production.env +10 -0
  16. package/lib/project-files/src/pre-start/env/test.env +9 -0
  17. package/lib/{auth-proj → project-files}/src/public/scripts/http.js +0 -0
  18. package/lib/{auth-proj → project-files}/src/public/scripts/login.js +0 -0
  19. package/lib/{auth-proj → project-files}/src/public/scripts/users.js +0 -0
  20. package/lib/{auth-proj → project-files}/src/public/stylesheets/login.css +0 -0
  21. package/lib/{auth-proj → project-files}/src/public/stylesheets/users.css +0 -0
  22. package/lib/project-files/src/repos/user-repo.ts +7 -7
  23. package/lib/project-files/src/routes/api.ts +9 -6
  24. package/lib/{auth-proj → project-files}/src/routes/auth-router.ts +11 -4
  25. package/lib/{auth-proj → project-files}/src/routes/middleware.ts +7 -8
  26. package/lib/project-files/src/routes/user-router.ts +12 -16
  27. package/lib/project-files/src/server.ts +82 -73
  28. package/lib/{auth-proj → project-files}/src/services/auth-service.ts +0 -0
  29. package/lib/project-files/src/services/user-service.ts +8 -8
  30. package/lib/project-files/src/shared/env-vars.ts +18 -0
  31. package/lib/project-files/src/shared/errors.ts +11 -0
  32. package/lib/project-files/src/types/express/index.d.ts +27 -5
  33. package/lib/{auth-proj → project-files}/src/util/jwt-util.ts +4 -9
  34. package/lib/{auth-proj → project-files}/src/views/login.html +0 -0
  35. package/lib/{auth-proj → project-files}/src/views/users.html +0 -0
  36. package/lib/project-files/tsconfig.json +3 -0
  37. package/package.json +1 -1
  38. package/chat-screenshot.png +0 -0
  39. package/lib/auth-proj/.eslintignore +0 -1
  40. package/lib/auth-proj/.eslintrc.json +0 -27
  41. package/lib/auth-proj/build.ts +0 -64
  42. package/lib/auth-proj/gitignore +0 -3
  43. package/lib/auth-proj/package.json +0 -73
  44. package/lib/auth-proj/spec/index.ts +0 -57
  45. package/lib/auth-proj/spec/loadEnv.ts +0 -10
  46. package/lib/auth-proj/spec/nodemon.json +0 -6
  47. package/lib/auth-proj/spec/support/jasmine.json +0 -11
  48. package/lib/auth-proj/spec/tests/users.spec.ts +0 -283
  49. package/lib/auth-proj/src/index.ts +0 -14
  50. package/lib/auth-proj/src/models/user-model.ts +0 -56
  51. package/lib/auth-proj/src/pre-start/env/development.env +0 -23
  52. package/lib/auth-proj/src/pre-start/env/production.env +0 -24
  53. package/lib/auth-proj/src/pre-start/env/test.env +0 -23
  54. package/lib/auth-proj/src/pre-start/index.ts +0 -28
  55. package/lib/auth-proj/src/repos/database.json +0 -1
  56. package/lib/auth-proj/src/repos/mock-orm.ts +0 -41
  57. package/lib/auth-proj/src/repos/user-repo.ts +0 -88
  58. package/lib/auth-proj/src/routes/api.ts +0 -17
  59. package/lib/auth-proj/src/routes/user-router.ts +0 -78
  60. package/lib/auth-proj/src/server.ts +0 -82
  61. package/lib/auth-proj/src/services/user-service.ts +0 -52
  62. package/lib/auth-proj/src/shared/env-vars.ts +0 -20
  63. package/lib/auth-proj/src/shared/errors.ts +0 -45
  64. package/lib/auth-proj/src/shared/functions.ts +0 -18
  65. package/lib/auth-proj/src/types/express/index.d.ts +0 -23
  66. package/lib/auth-proj/tsconfig.json +0 -100
  67. package/lib/auth-proj/tsconfig.prod.json +0 -11
  68. package/lib/project-files/src/public/scripts/index.js +0 -183
  69. package/lib/project-files/src/public/stylesheets/style.css +0 -33
  70. package/lib/project-files/src/views/index.html +0 -31
  71. package/lib/socket-io/.eslintignore +0 -1
  72. package/lib/socket-io/.eslintrc.json +0 -27
  73. package/lib/socket-io/build.ts +0 -64
  74. package/lib/socket-io/gitignore +0 -3
  75. package/lib/socket-io/package.json +0 -75
  76. package/lib/socket-io/spec/index.ts +0 -57
  77. package/lib/socket-io/spec/loadEnv.ts +0 -10
  78. package/lib/socket-io/spec/nodemon.json +0 -6
  79. package/lib/socket-io/spec/support/jasmine.json +0 -11
  80. package/lib/socket-io/spec/support/login-agent.ts +0 -49
  81. package/lib/socket-io/spec/tests/auth.spec.ts +0 -159
  82. package/lib/socket-io/spec/tests/chat.spec.ts +0 -150
  83. package/lib/socket-io/spec/tests/users.spec.ts +0 -283
  84. package/lib/socket-io/src/index.ts +0 -14
  85. package/lib/socket-io/src/models/user-model.ts +0 -56
  86. package/lib/socket-io/src/pre-start/env/development.env +0 -23
  87. package/lib/socket-io/src/pre-start/env/production.env +0 -24
  88. package/lib/socket-io/src/pre-start/env/test.env +0 -23
  89. package/lib/socket-io/src/pre-start/index.ts +0 -28
  90. package/lib/socket-io/src/public/scripts/chat.js +0 -87
  91. package/lib/socket-io/src/public/scripts/http.js +0 -24
  92. package/lib/socket-io/src/public/scripts/index.js +0 -16
  93. package/lib/socket-io/src/public/scripts/login.js +0 -17
  94. package/lib/socket-io/src/public/scripts/users.js +0 -148
  95. package/lib/socket-io/src/public/stylesheets/chat.css +0 -43
  96. package/lib/socket-io/src/public/stylesheets/index.css +0 -13
  97. package/lib/socket-io/src/public/stylesheets/login.css +0 -20
  98. package/lib/socket-io/src/public/stylesheets/users.css +0 -40
  99. package/lib/socket-io/src/repos/database.json +0 -38
  100. package/lib/socket-io/src/repos/mock-orm.ts +0 -41
  101. package/lib/socket-io/src/repos/user-repo.ts +0 -88
  102. package/lib/socket-io/src/routes/api.ts +0 -19
  103. package/lib/socket-io/src/routes/auth-router.ts +0 -67
  104. package/lib/socket-io/src/routes/chat-router.ts +0 -88
  105. package/lib/socket-io/src/routes/middleware.ts +0 -55
  106. package/lib/socket-io/src/routes/user-router.ts +0 -76
  107. package/lib/socket-io/src/server.ts +0 -100
  108. package/lib/socket-io/src/services/auth-service.ts +0 -38
  109. package/lib/socket-io/src/services/user-service.ts +0 -52
  110. package/lib/socket-io/src/shared/env-vars.ts +0 -20
  111. package/lib/socket-io/src/shared/errors.ts +0 -56
  112. package/lib/socket-io/src/shared/functions.ts +0 -18
  113. package/lib/socket-io/src/types/express/index.d.ts +0 -23
  114. package/lib/socket-io/src/util/jwt-util.ts +0 -52
  115. package/lib/socket-io/src/views/chat.html +0 -51
  116. package/lib/socket-io/src/views/login.html +0 -35
  117. package/lib/socket-io/src/views/users.html +0 -47
  118. package/lib/socket-io/tsconfig.json +0 -100
  119. package/lib/socket-io/tsconfig.prod.json +0 -11
package/README.md CHANGED
@@ -36,24 +36,11 @@ and `_moduleAliases` in _package.json_ if you want to add/edit the relative path
36
36
 
37
37
  ## Sample-project
38
38
 
39
- When you run _express-generator-typescript_, it sets up a very simple application with routes for
39
+ When you run _express-generator-typescript_, it sets up a simple application with routes for
40
40
  adding, updating, deleting, and fetching user objects. This is just to demonstrate how routing is done
41
- with express.
42
-
43
- If you want a fully-secure application, you can pass the `--with-auth` option and you will have an
44
- application which requires you to login before calling APIs on user objects. The app is
41
+ with express. You will have to login before calling APIs on user objects. The app is
45
42
  configured with production quality client-side security and uses signed-cookies and jsonwebtokens
46
- to store user-session data. If you're new to web-development and still learning about securing websites,
47
- I highly encourage to use this option.
48
-
49
- To have a chat app within your application, use the `--socket-io` option. This option will include
50
- everything from the `--with-auth` option, plus will create a mini-chat app which displays the
51
- sender name for the message of whoever the logged in user is. Without a login user we can't display
52
- a sender name, that's why the `--socket-io` option must used in conjunction with `--with-auth`.
53
- To create a socket-io sample app, you can pass `--socket-io` or `--with-auth --socket-io`; it won't
54
- make a difference.
55
-
56
- <img alt='chat-screenshot' src='https://github.com/seanpmaxwell/express-generator-typescript/raw/master/chat-screenshot.png' border='0'>
43
+ to store user-session data.
57
44
 
58
45
 
59
46
  ## Installation
@@ -75,14 +62,12 @@ Create the app:
75
62
 
76
63
  ```bash
77
64
  $ npx express-generator-typescript "project name (default is express-gen-ts)"
78
- with all options
79
- $ npx express-generator-typescript --with-auth --socket-io --use-yarn "project name (default is express-gen-ts)"
80
65
  ```
81
66
 
82
67
  Start your express-generator-typescript app in development mode at `http://localhost:3000/`:
83
68
 
84
69
  ```bash
85
- $ cd "project name" && npm run start:dev
70
+ $ cd "project name" && npm run dev
86
71
  ```
87
72
 
88
73
 
@@ -106,6 +91,34 @@ This is located under `nodemonConfig:` in `package.json` for the server and `./s
106
91
  unit-testing. For the `exec` property, replace `ts-node` with `node --inspect -r ts-node/register`.
107
92
 
108
93
 
94
+ ## If you don't want authentication:
95
+
96
+ In previous version of __express-generator-typescript__ you could disregard authentication through the
97
+ command line options. But maintaining two separate project folders which contained and didn't contain
98
+ authentication started to get messy.
99
+
100
+ - Remove following modules from `package.json`:
101
+ - `jsonwebtoken`
102
+ - `@types/jsonwebtoken`
103
+ - `bcrypt`
104
+ - `@types/bcrypt`
105
+
106
+ - Delete the files:
107
+ - `src/routes/middleware.ts`
108
+ - `src/routes/auth-router.ts`
109
+ - `spec/tests/auth.spec.ts`
110
+ - `spec/support/login-agent.ts`
111
+ - `public/scripts/login.js`
112
+ - `public/stylesheets/login.css`
113
+ - `public/views/login.html`
114
+
115
+ - Update the files:
116
+ - In `src/routes/api`, delete the line: `apiRouter.use('/auth', authRouter);` and
117
+ remove the `adminMw,` from line 12. Remove the `adminMw` and `authRouter` imports as well.
118
+ - In `spec/tests/users.spec.ts`, remove all lines containing `loginAgent` and `setCookie`
119
+ - In `public/views/users.html` remove the `Logout` button.
120
+
121
+
109
122
  ## Note for VS-Code users
110
123
 
111
124
  A lot of users have asked about _launch.json_ configurations for running this in VS-Code, so
@@ -136,13 +149,12 @@ VS-Code.
136
149
 
137
150
  ## Note for windows users
138
151
 
139
- If you use the `--with-auth` option and are on Windows, the `bcrypt` module tends to be fussy. To
140
- use this module on Windows you need to make sure you have the node Windows build tools installed.
141
- I don't want to post instructions because they might change frequently. I would search the Microsoft
142
- docs on how to setup Node for Windows. To be able to debug in VSCODE on windows I also had to install
143
- the `node-gyp` module globally as well.
152
+ If you are on Windows, the `bcrypt` module tends to be fussy. To use this module on Windows you
153
+ need to make sure you have the node Windows build tools installed. I don't want to post instructions
154
+ because they might change frequently. I would search the Microsoft docs on how to setup Node for Windows.
155
+ To be able to debug in VSCODE on windows I also had to install the `node-gyp` module globally as well.
144
156
 
145
- Happy web-deving :)
157
+ Happy web deving :)
146
158
 
147
159
 
148
160
 
package/bin/cli.js CHANGED
@@ -15,34 +15,21 @@ const expressGenTs = require('../lib/express-generator-typescript');
15
15
  // const opts = processOptions(process.argv.slice(2));
16
16
  // Process options
17
17
  let destination = 'express-gen-ts';
18
- let withAuth = false;
19
18
  let useYarn = false;
20
- let useSocketIo = false;
21
19
  const args = process.argv.slice(2);
22
20
  let idx = -1;
23
- idx = args.indexOf('--with-auth');
24
- if (idx > -1) {
25
- withAuth = true;
26
- args.splice(idx, 1);
27
- }
28
21
  idx = args.indexOf('--use-yarn');
29
22
  if (idx > -1) {
30
23
  useYarn = true;
31
24
  args.splice(idx, 1);
32
25
  }
33
- idx = args.indexOf('--socket-io');
34
- if (idx > -1) {
35
- useSocketIo = true;
36
- withAuth = true;
37
- args.splice(idx, 1);
38
- }
39
26
  if (args.length > 0) {
40
27
  destination = args[0];
41
28
  }
42
29
  destination = path.join(process.cwd(), destination);
43
30
  // Creating new project finished
44
- expressGenTs(destination, withAuth, useYarn, useSocketIo).then(() => {
31
+ expressGenTs(destination, useYarn).then(() => {
45
32
  console.log('Project setup complete!');
46
33
  });
47
- })();
34
+ })();
48
35
 
package/lib/cli.js CHANGED
@@ -10,39 +10,25 @@ const path = require('path');
10
10
  const expressGenTs = require('../lib/express-generator-typescript');
11
11
 
12
12
 
13
- // Start
14
13
  (() => {
15
14
  console.log('Setting up new Express/TypeScript project...');
16
15
  // const opts = processOptions(process.argv.slice(2));
17
16
  // Process options
18
17
  let destination = 'express-gen-ts';
19
- let withAuth = false;
20
18
  let useYarn = false;
21
- let useSocketIo = false;
22
19
  const args = process.argv.slice(2);
23
20
  let idx = -1;
24
- idx = args.indexOf('--with-auth');
25
- if (idx > -1) {
26
- withAuth = true;
27
- args.splice(idx, 1);
28
- }
29
21
  idx = args.indexOf('--use-yarn');
30
22
  if (idx > -1) {
31
23
  useYarn = true;
32
24
  args.splice(idx, 1);
33
25
  }
34
- idx = args.indexOf('--socket-io');
35
- if (idx > -1) {
36
- useSocketIo = true;
37
- withAuth = true;
38
- args.splice(idx, 1);
39
- }
40
26
  if (args.length > 0) {
41
27
  destination = args[0];
42
28
  }
43
29
  destination = path.join(process.cwd(), destination);
44
30
  // Creating new project finished
45
- expressGenTs(destination, withAuth, useYarn, useSocketIo).then(() => {
31
+ expressGenTs(destination, useYarn).then(() => {
46
32
  console.log('Project setup complete!');
47
33
  });
48
34
  })();
@@ -13,8 +13,12 @@ const fs = require('fs');
13
13
 
14
14
  // **** Variables **** //
15
15
 
16
+ const prjFolder = './project-files';
17
+
16
18
  const ncpOpts = {
17
- filter: new RegExp('^(?!.*(node_modules|package-lock.json)).*$'),
19
+ filter: (fileName) => {
20
+ return !(fileName === 'package-lock.json' || fileName === 'node_modules');
21
+ },
18
22
  };
19
23
 
20
24
 
@@ -23,12 +27,12 @@ const ncpOpts = {
23
27
  /**
24
28
  * Entry point
25
29
  */
26
- async function expressGenTs(destination, withAuth, useYarn, useSocketIo) {
30
+ async function expressGenTs(destination, useYarn) {
27
31
  try {
28
- await copyProjectFiles(destination, withAuth, useSocketIo);
32
+ await copyProjectFiles(destination);
29
33
  updatePackageJson(destination);
30
34
  await renameGitigoreFile(destination);
31
- const depStrings = getDepStrings(withAuth, useSocketIo);
35
+ const depStrings = getDepStrings();
32
36
  downloadNodeModules(destination, depStrings, useYarn);
33
37
  } catch (err) {
34
38
  console.error(err);
@@ -38,17 +42,10 @@ async function expressGenTs(destination, withAuth, useYarn, useSocketIo) {
38
42
  /**
39
43
  * Copy project files
40
44
  */
41
- function copyProjectFiles(destination, withAuth, useSocketIo) {
42
- let prjFolder = './project-files';
43
- if (useSocketIo) {
44
- prjFolder = './socket-io';
45
- } else if (withAuth) {
46
- prjFolder = './auth-proj';
47
- }
45
+ function copyProjectFiles(destination) {
48
46
  const source = path.join(__dirname, prjFolder);
49
- // Return
50
47
  return new Promise((res, rej) => {
51
- ncp.limit = 32;
48
+ ncp.limit = 16;
52
49
  return ncp(source, destination, ncpOpts, (err) => {
53
50
  return (!!err ? rej(err) : res());
54
51
  });
@@ -81,21 +78,16 @@ function renameGitigoreFile(destination) {
81
78
  /**
82
79
  * Setup dependency strings. This way gets you the latest version of everything.
83
80
  */
84
- function getDepStrings(withAuth, useSocketIo) {
81
+ function getDepStrings() {
85
82
  let dependencies = 'express dotenv http-status-codes morgan cookie-parser jet-logger ' +
86
- 'module-alias command-line-args express-async-errors helmet jsonfile';
83
+ 'module-alias command-line-args express-async-errors helmet jsonfile bcrypt ' +
84
+ 'jsonwebtoken';
87
85
  let devDependencies = 'ts-node typescript nodemon find jasmine supertest ' +
88
86
  '@types/node @types/express @types/jasmine @types/find @types/morgan ' +
89
87
  '@types/cookie-parser @types/supertest fs-extra tsconfig-paths @types/jsonfile ' +
90
88
  '@types/command-line-args @typescript-eslint/eslint-plugin @typescript-eslint/parser ' +
91
- 'eslint @types/fs-extra';
92
- if (withAuth || useSocketIo) {
93
- dependencies += ' bcrypt randomstring jsonwebtoken';
94
- devDependencies += ' @types/bcrypt @types/randomstring @types/jsonwebtoken';
95
- }
96
- if (useSocketIo) {
97
- dependencies += ' socket.io socket.io-client';
98
- }
89
+ 'eslint @types/fs-extra @types/bcrypt @types/jsonwebtoken ' +
90
+ 'eslint-plugin-node';
99
91
  // Return
100
92
  return { dependencies, devDependencies };
101
93
  }
@@ -6,7 +6,8 @@
6
6
  "extends": [
7
7
  "eslint:recommended",
8
8
  "plugin:@typescript-eslint/recommended",
9
- "plugin:@typescript-eslint/recommended-requiring-type-checking"
9
+ "plugin:@typescript-eslint/recommended-requiring-type-checking",
10
+ "plugin:node/recommended"
10
11
  ],
11
12
  "parserOptions": {
12
13
  "project": "./tsconfig.json"
@@ -22,6 +23,18 @@
22
23
  "no-extra-boolean-cast": 0,
23
24
  "semi": 1,
24
25
  "@typescript-eslint/no-misused-promises": 0,
25
- "@typescript-eslint/no-floating-promises": 0
26
+ "@typescript-eslint/no-floating-promises": 0,
27
+ "node/no-process-env": 1,
28
+ "node/no-unsupported-features/es-syntax": [
29
+ "error",
30
+ { "ignores" : ["modules"] }
31
+ ],
32
+ "node/no-missing-import": 0,
33
+ "node/no-unpublished-import": 0
34
+ },
35
+ "settings": {
36
+ "node": {
37
+ "tryExtensions": [".js", ".json", ".node", ".ts"]
38
+ }
26
39
  }
27
40
  }
@@ -36,7 +36,7 @@ function remove(loc: string): Promise<void> {
36
36
  }
37
37
 
38
38
  /**
39
- * Copy file
39
+ * Copy file.
40
40
  */
41
41
  function copy(src: string, dest: string): Promise<void> {
42
42
  return new Promise((res, rej) => {
@@ -47,7 +47,7 @@ function copy(src: string, dest: string): Promise<void> {
47
47
  }
48
48
 
49
49
  /**
50
- * Execute system command
50
+ * Do command line command.
51
51
  */
52
52
  function exec(cmd: string, loc: string): Promise<void> {
53
53
  return new Promise((res, rej) => {
@@ -1,13 +1,14 @@
1
1
  {
2
- "name": "express-gen-ts",
2
+ "name": "express-typescript-example",
3
3
  "version": "0.0.0",
4
4
  "scripts": {
5
5
  "build": "npx ts-node build.ts",
6
- "lint": "eslint . --ext .ts",
6
+ "lint": "npx eslint --ext .ts src/",
7
+ "lint:tests": "npx eslint --ext .ts spec/",
7
8
  "start": "node -r module-alias/register ./dist --env=production",
8
9
  "dev": "nodemon",
9
10
  "test": "nodemon --config ./spec/nodemon.json",
10
- "test:no-reloading": "npx ts-node -r tsconfig-paths/register ./spec"
11
+ "test:no-reloading": "npx ts-node --files -r tsconfig-paths/register ./spec"
11
12
  },
12
13
  "nodemonConfig": {
13
14
  "watch": [
@@ -17,7 +18,7 @@
17
18
  "ignore": [
18
19
  "src/public"
19
20
  ],
20
- "exec": "./node_modules/.bin/ts-node -r tsconfig-paths/register ./src"
21
+ "exec": "./node_modules/.bin/ts-node --files -r tsconfig-paths/register ./src"
21
22
  },
22
23
  "_moduleAliases": {
23
24
  "@services": "dist/services",
@@ -25,9 +26,14 @@
25
26
  "@entities": "dist/entities",
26
27
  "@shared": "dist/shared",
27
28
  "@server": "dist/server",
28
- "@routes": "dist/routes"
29
+ "@routes": "dist/routes",
30
+ "@util": "dist/util"
31
+ },
32
+ "engines": {
33
+ "node": ">=8.10.0"
29
34
  },
30
35
  "dependencies": {
36
+ "bcrypt": "^5.0.1",
31
37
  "command-line-args": "^5.2.1",
32
38
  "cookie-parser": "^1.4.6",
33
39
  "dotenv": "^16.0.2",
@@ -37,10 +43,12 @@
37
43
  "http-status-codes": "^2.2.0",
38
44
  "jet-logger": "^1.2.3",
39
45
  "jsonfile": "^6.1.0",
46
+ "jsonwebtoken": "^8.5.1",
40
47
  "module-alias": "^2.2.2",
41
48
  "morgan": "^1.10.0"
42
49
  },
43
50
  "devDependencies": {
51
+ "@types/bcrypt": "^5.0.0",
44
52
  "@types/command-line-args": "^5.2.0",
45
53
  "@types/cookie-parser": "^1.4.3",
46
54
  "@types/express": "^4.17.13",
@@ -48,12 +56,14 @@
48
56
  "@types/fs-extra": "^9.0.13",
49
57
  "@types/jasmine": "^4.3.0",
50
58
  "@types/jsonfile": "^6.1.0",
59
+ "@types/jsonwebtoken": "^8.5.9",
51
60
  "@types/morgan": "^1.9.3",
52
61
  "@types/node": "^18.7.14",
53
62
  "@types/supertest": "^2.0.12",
54
63
  "@typescript-eslint/eslint-plugin": "^5.36.1",
55
64
  "@typescript-eslint/parser": "^5.36.1",
56
65
  "eslint": "^8.23.0",
66
+ "eslint-plugin-node": "^11.1.0",
57
67
  "find": "^0.3.0",
58
68
  "fs-extra": "^10.1.0",
59
69
  "jasmine": "^4.3.0",
@@ -2,5 +2,5 @@
2
2
  "watch": ["spec"],
3
3
  "ext": "spec.ts",
4
4
  "ignore": ["spec/support"],
5
- "exec": "./node_modules/.bin/ts-node -r tsconfig-paths/register ./spec"
5
+ "exec": "./node_modules/.bin/ts-node --files -r tsconfig-paths/register ./spec"
6
6
  }
@@ -31,7 +31,13 @@ const msgs = {
31
31
  fallbackErr: `should return a response with a status of ${BAD_REQUEST} and a json with an error
32
32
  for all other bad responses.`,
33
33
  goodLogout: `should return a response with a status of ${OK}.`,
34
- }
34
+ } as const;
35
+
36
+ // Login credentials
37
+ const loginCreds = {
38
+ email: 'jsmith@gmail.com',
39
+ password: 'Password@1',
40
+ } as const;
35
41
 
36
42
 
37
43
  // **** Types **** //
@@ -60,35 +66,25 @@ describe('auth-router', () => {
60
66
 
61
67
  // Good login
62
68
  it(msgs.goodLogin, (done) => {
63
- // Setup Dummy Data
64
- const creds = {
65
- email: 'jsmith@gmail.com',
66
- password: 'Password@1',
67
- };
68
69
  const role = UserRoles.Standard;
69
- const pwdHash = hashPwd(creds.password);
70
- const loginUser = User.new('john smith', creds.email, role, pwdHash);
70
+ const pwdHash = hashPwd(loginCreds.password);
71
+ const loginUser = User.new('john smith', loginCreds.email, role, pwdHash);
71
72
  spyOn(userRepo, 'getOne').and.returnValue(Promise.resolve(loginUser));
72
73
  // Call API
73
- callApi(creds)
74
+ callApi(loginCreds)
74
75
  .end((err: Error, res: Response) => {
75
76
  pErr(err);
76
77
  expect(res.status).toBe(OK);
77
- expect(res.headers['set-cookie'][0]).toContain(envVars.cookieProps.key);
78
+ const cookie = res.headers['set-cookie'][0];
79
+ expect(cookie).toContain(envVars.cookieProps.key);
78
80
  done();
79
81
  });
80
82
  });
81
83
 
82
84
  // Email not found error
83
85
  it(msgs.emailNotFound, (done) => {
84
- // Setup Dummy Data
85
- const creds = {
86
- email: 'jsmith@gmail.com',
87
- password: 'Password@1',
88
- };
89
86
  spyOn(userRepo, 'getOne').and.returnValue(Promise.resolve(null));
90
- // Call API
91
- callApi(creds)
87
+ callApi(loginCreds)
92
88
  .end((err: Error, res: Response) => {
93
89
  pErr(err);
94
90
  expect(res.status).toBe(UNAUTHORIZED);
@@ -99,17 +95,12 @@ describe('auth-router', () => {
99
95
 
100
96
  // Password failed
101
97
  it(msgs.pwdFailed, (done) => {
102
- // Setup Dummy Data
103
- const creds = {
104
- email: 'jsmith@gmail.com',
105
- password: 'someBadPassword',
106
- };
107
98
  const role = UserRoles.Standard;
108
- const pwdHash = hashPwd('Password@1');
109
- const loginUser = User.new('john smith', creds.email, role, pwdHash);
99
+ const pwdHash = hashPwd('bad password');
100
+ const loginUser = User.new('john smith', loginCreds.email, role, pwdHash);
110
101
  spyOn(userRepo, 'getOne').and.returnValue(Promise.resolve(loginUser));
111
102
  // Call API
112
- callApi(creds)
103
+ callApi(loginCreds)
113
104
  .end((err: Error, res: Response) => {
114
105
  pErr(err);
115
106
  expect(res.status).toBe(UNAUTHORIZED);
@@ -120,14 +111,8 @@ describe('auth-router', () => {
120
111
 
121
112
  // Fallback error
122
113
  it(msgs.fallbackErr, (done) => {
123
- // Setup Dummy Data
124
- const creds = {
125
- email: 'jsmith@gmail.com',
126
- password: 'someBadPassword',
127
- };
128
114
  spyOn(userRepo, 'getOne').and.throwError('Database query failed.');
129
- // Call API
130
- callApi(creds)
115
+ callApi(loginCreds)
131
116
  .end((err: Error, res: Response) => {
132
117
  pErr(err);
133
118
  expect(res.status).toBe(BAD_REQUEST);
@@ -140,6 +125,7 @@ describe('auth-router', () => {
140
125
  // Test logout
141
126
  describe(`"GET:${logoutPath}"`, () => {
142
127
 
128
+ // Successful logout
143
129
  it(msgs.goodLogout, (done) => {
144
130
  agent.get(logoutPath)
145
131
  .end((err: Error, res: Response) => {
@@ -7,6 +7,7 @@ import userRepo from '@repos/user-repo';
7
7
  import User, { IUser } from '@models/user-model';
8
8
  import { pErr } from '@shared/functions';
9
9
  import { p as userPaths } from '@routes/user-router';
10
+ import loginAgent from '../support/login-agent';
10
11
  import { ParamMissingError, UserNotFoundError } from '@shared/errors';
11
12
 
12
13
 
@@ -72,33 +73,40 @@ type TReqBody = string | object | undefined;
72
73
  describe('user-router', () => {
73
74
 
74
75
  let agent: SuperTest<Test>;
76
+ let jwtCookie: string;
75
77
 
76
78
 
77
79
  // Run before all tests
78
80
  beforeAll((done) => {
79
81
  agent = supertest.agent(app);
80
- done();
82
+ loginAgent.login(agent, (cookie: string) => {
83
+ jwtCookie = cookie;
84
+ done();
85
+ });
81
86
  });
82
87
 
83
- // Test get users
88
+ // Test get users
84
89
  describe(`"GET:${getUsersPath}"`, () => {
85
90
 
91
+ const callApi = () =>
92
+ agent.get(getUsersPath)
93
+ .set('Cookie', jwtCookie);
94
+
86
95
  // Get all users
87
96
  it(msgs.getUsersSuccess, (done) => {
88
97
  const ret = Promise.resolve([...dummyGetAllUsers]);
89
98
  spyOn(userRepo, 'getAll').and.returnValue(ret);
90
99
  // Call API
91
- agent.get(getUsersPath)
92
- .end((err: Error, res: Response) => {
93
- pErr(err);
94
- expect(res.status).toBe(OK);
95
- // Caste instance-objects to 'User' objects
96
- const respUsers = res.body.users;
97
- const retUsers: IUser[] = respUsers.map((user: IUser) => User.copy(user));
98
- expect(retUsers).toEqual(dummyGetAllUsers);
99
- expect(res.body.error).toBeUndefined();
100
- done();
101
- });
100
+ callApi().end((err: Error, res: Response) => {
101
+ pErr(err);
102
+ expect(res.status).toBe(OK);
103
+ // Caste instance-objects to 'User' objects
104
+ const respUsers = res.body.users;
105
+ const retUsers = respUsers.map((user: IUser) => User.copy(user));
106
+ expect(retUsers).toEqual(dummyGetAllUsers);
107
+ expect(res.body.error).toBeUndefined();
108
+ done();
109
+ });
102
110
  });
103
111
 
104
112
  // Get all users bad
@@ -106,7 +114,7 @@ describe('user-router', () => {
106
114
  const errMsg = 'Could not fetch users.';
107
115
  spyOn(userRepo, 'getAll').and.throwError(errMsg);
108
116
  // Call API
109
- agent.get(getUsersPath)
117
+ callApi()
110
118
  .end((err: Error, res: Response) => {
111
119
  pErr(err);
112
120
  expect(res.status).toBe(BAD_REQUEST);
@@ -119,9 +127,10 @@ describe('user-router', () => {
119
127
  // Test add user
120
128
  describe(`"POST:${addUsersPath}"`, () => {
121
129
 
130
+ // Consts
122
131
  const callApi = (reqBody: TReqBody) => {
123
- return agent
124
- .post(addUsersPath)
132
+ return agent.post(addUsersPath)
133
+ .set('Cookie', jwtCookie)
125
134
  .type('form').send(reqBody);
126
135
  };
127
136
 
@@ -166,11 +175,10 @@ describe('user-router', () => {
166
175
  // Test update users
167
176
  describe(`"PUT:${updateUserPath}"`, () => {
168
177
 
169
- const callApi = (reqBody: TReqBody) => {
170
- return agent.put(updateUserPath)
171
- .type('form')
172
- .send(reqBody);
173
- };
178
+ const callApi = (reqBody: TReqBody) =>
179
+ agent.put(updateUserPath)
180
+ .set('Cookie', jwtCookie)
181
+ .type('form').send(reqBody);
174
182
 
175
183
  // Test updating a user success
176
184
  it(msgs.updateSuccess, (done) => {
@@ -229,7 +237,8 @@ describe('user-router', () => {
229
237
 
230
238
  const callApi = (id: number) => {
231
239
  const path = deleteUserPath.replace(':id', id.toString());
232
- return agent.delete(path);
240
+ return agent.delete(path)
241
+ .set('Cookie', jwtCookie);
233
242
  };
234
243
 
235
244
  // Delete user successful
@@ -0,0 +1,14 @@
1
+ import { IUser } from '@models/user-model';
2
+ import 'supertest';
3
+
4
+
5
+ declare module 'supertest' {
6
+
7
+ export interface Response {
8
+ headers: Record<string, string | string[]>;
9
+ body: {
10
+ error: string;
11
+ users: IUser[]
12
+ };
13
+ }
14
+ }
@@ -1,10 +1,16 @@
1
1
  // **** Types **** //
2
2
 
3
- // User schema
3
+ export enum UserRoles {
4
+ Standard,
5
+ Admin,
6
+ }
7
+
4
8
  export interface IUser {
5
9
  id: number;
6
10
  name: string;
7
11
  email: string;
12
+ pwdHash: string;
13
+ role: UserRoles;
8
14
  }
9
15
 
10
16
 
@@ -13,11 +19,18 @@ export interface IUser {
13
19
  /**
14
20
  * Get a new User object.
15
21
  */
16
- function _new(name: string, email: string): IUser {
22
+ function _new(
23
+ name: string,
24
+ email: string,
25
+ role?: UserRoles,
26
+ pwdHash?: string,
27
+ ): IUser {
17
28
  return {
18
29
  id: -1,
19
30
  email,
20
31
  name,
32
+ role: (role ?? UserRoles.Standard),
33
+ pwdHash: (pwdHash ?? ''),
21
34
  };
22
35
  }
23
36
 
@@ -29,6 +42,8 @@ function copy(user: IUser): IUser {
29
42
  id: user.id,
30
43
  email: user.email,
31
44
  name: user.name,
45
+ role: user.role,
46
+ pwdHash: user.pwdHash,
32
47
  };
33
48
  }
34
49
 
@@ -12,3 +12,12 @@ JET_LOGGER_MODE=CONSOLE
12
12
  JET_LOGGER_FILEPATH=jet-logger.log
13
13
  JET_LOGGER_TIMESTAMP=TRUE
14
14
  JET_LOGGER_FORMAT=LINE
15
+
16
+ ## Authentication ##
17
+ COOKIE_DOMAIN=localhost
18
+ COOKIE_PATH=/
19
+ SECURE_COOKIE=false
20
+ JWT_SECRET=xxxxxxxxxxxxxx
21
+ COOKIE_SECRET=xxxxxxxxxxxxxx
22
+ # expires in 3 days
23
+ COOKIE_EXP=259200000