express-generator-typescript 2.8.1 → 2.9.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/README.md +198 -18
- package/bin/cli.js +91 -32
- package/lib/express-generator-typescript.js +125 -151
- package/lib/{project-files → template}/.prettierignore +2 -4
- package/lib/template/README.md +50 -0
- package/lib/template/bs-config.js +8 -0
- package/lib/{project-files → template}/config/.env.development +4 -6
- package/lib/{project-files → template}/config/.env.production +4 -5
- package/lib/{project-files → template}/config/.env.test +4 -5
- package/lib/{project-files → template}/eslint.config.ts +4 -0
- package/lib/template/gitignore +10 -0
- package/lib/{project-files → template}/package.json +31 -36
- package/lib/{project-files → template}/src/common/constants/HttpStatusCodes.ts +12 -8
- package/lib/template/src/common/constants/Paths.ts +22 -0
- package/lib/template/src/common/constants/env-inv.ts +31 -0
- package/lib/template/src/common/types/utility-types.ts +5 -0
- package/lib/template/src/common/utils/date-utils.ts +29 -0
- package/lib/template/src/common/utils/route-errors.ts +37 -0
- package/lib/template/src/main.ts +24 -0
- package/lib/template/src/models/User.model.ts +95 -0
- package/lib/template/src/models/common/types.ts +10 -0
- package/lib/template/src/public/scripts/http.js +25 -0
- package/lib/template/src/public/scripts/lib/bootstrap.bundle.min.js +4229 -0
- package/lib/template/src/public/scripts/renderUsers.js +90 -0
- package/lib/template/src/public/scripts/users.js +142 -0
- package/lib/template/src/public/stylesheets/lib/bootstrap.min.css +11798 -0
- package/lib/template/src/repos/MockOrm.ts +71 -0
- package/lib/{project-files → template}/src/repos/UserRepo.ts +21 -35
- package/lib/template/src/repos/common/database.json +28 -0
- package/lib/{project-files → template}/src/routes/UserRoutes.ts +15 -18
- package/lib/template/src/routes/apiRouter.ts +28 -0
- package/lib/template/src/routes/common/express-types.ts +9 -0
- package/lib/template/src/routes/common/parseReq.ts +23 -0
- package/lib/template/src/server.ts +78 -0
- package/lib/template/src/services/UserService.ts +66 -0
- package/lib/{project-files → template}/src/views/users.html +13 -6
- package/lib/{project-files → template}/tests/common/comparators.ts +6 -6
- package/lib/template/tests/common/supertest-types.ts +11 -0
- package/lib/template/tests/frontend.test.ts +33 -0
- package/lib/template/tests/support/agent.ts +23 -0
- package/lib/template/tests/users.test.ts +205 -0
- package/lib/{project-files → template}/tsconfig.json +1 -3
- package/lib/{project-files → template}/tsconfig.prod.json +3 -9
- package/lib/{project-files → template}/vitest.config.mts +2 -0
- package/package.json +65 -52
- package/lib/cli.js +0 -33
- package/lib/project-files/README.md +0 -39
- package/lib/project-files/gitignore +0 -4
- package/lib/project-files/src/common/constants/Paths.ts +0 -15
- package/lib/project-files/src/common/constants/env.ts +0 -28
- package/lib/project-files/src/common/types/structure-utils.ts +0 -2
- package/lib/project-files/src/common/utils/number-utils.ts +0 -10
- package/lib/project-files/src/common/utils/route-errors.ts +0 -35
- package/lib/project-files/src/common/utils/validators.ts +0 -14
- package/lib/project-files/src/main.ts +0 -24
- package/lib/project-files/src/models/User.model.ts +0 -72
- package/lib/project-files/src/models/common/types.ts +0 -4
- package/lib/project-files/src/public/stylesheets/lib/bootstrap.min.css +0 -6
- package/lib/project-files/src/repos/MockOrm.ts +0 -63
- package/lib/project-files/src/repos/common/database.json +0 -1
- package/lib/project-files/src/repos/common/database.test.json +0 -1
- package/lib/project-files/src/routes/apiRouter.ts +0 -28
- package/lib/project-files/src/routes/common/express-types.ts +0 -8
- package/lib/project-files/src/routes/common/parseReq.ts +0 -19
- package/lib/project-files/src/server.ts +0 -73
- package/lib/project-files/src/services/UserService.ts +0 -64
- package/lib/project-files/tests/common/error-utils.ts +0 -25
- package/lib/project-files/tests/common/supertest-types.ts +0 -15
- package/lib/project-files/tests/support/agent.ts +0 -23
- package/lib/project-files/tests/users.test.ts +0 -131
- /package/lib/{project-files → template}/.prettierrc.json +0 -0
- /package/lib/{project-files → template}/src/public/stylesheets/users.css +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
## About
|
|
2
|
+
|
|
3
|
+
This project was created with [express-generator-typescript](https://github.com/seanpmaxwell/express-generator-typescript). It requires Node.js 22.12 or newer.
|
|
4
|
+
|
|
5
|
+
<p align="center">· · ·</p>
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Available Scripts
|
|
9
|
+
|
|
10
|
+
### `npm run install:clean`
|
|
11
|
+
|
|
12
|
+
Remove the existing `node_modules/` folder, `package-lock.json`, and reinstall all library modules.
|
|
13
|
+
|
|
14
|
+
### `npm run dev`
|
|
15
|
+
|
|
16
|
+
Run the server in development with hot reloading and browser refresh (see `package.json` for all `npm run dev` variations)<br/>
|
|
17
|
+
|
|
18
|
+
**IMPORTANT** development mode uses `swc` for performance reasons which DOES NOT check for typescript errors. Run `npm run typecheck` to check for type errors. NOTE: you should use your IDE to prevent most type errors.
|
|
19
|
+
|
|
20
|
+
### `npm test`
|
|
21
|
+
|
|
22
|
+
Run unit-tests with <a href="https://vitest.dev/guide/">vitest</a>.
|
|
23
|
+
|
|
24
|
+
### `npm run lint`
|
|
25
|
+
|
|
26
|
+
Check for linting errors.
|
|
27
|
+
|
|
28
|
+
### `npm run format`
|
|
29
|
+
|
|
30
|
+
Format `src/` and `tests/` with prettier.
|
|
31
|
+
|
|
32
|
+
### `npm run build`
|
|
33
|
+
|
|
34
|
+
Build the project for production.
|
|
35
|
+
|
|
36
|
+
### `npm start`
|
|
37
|
+
|
|
38
|
+
Run the production build (Must be built first).
|
|
39
|
+
|
|
40
|
+
### `npm run typecheck`
|
|
41
|
+
|
|
42
|
+
Check for typescript errors.
|
|
43
|
+
|
|
44
|
+
<p align="center">· · ·</p>
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
## Additional Notes
|
|
48
|
+
|
|
49
|
+
- `config/.env.production` is listed in `.gitignore` so production secrets don't get committed. Keep it out of version control and provide its values through your deployment tooling.
|
|
50
|
+
- The database is a JSON file (`src/repos/common/database.json`, or `dist/repos/common/database.json` in production) meant only for the demo. It's created automatically if missing and isn't safe for concurrent writes, so replace `src/repos/MockOrm.ts` with a real database before going to production.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
proxy: "http://localhost:3000/", // The address where your Express app runs
|
|
3
|
+
open: true, // Avoid reopening the browser on every nodemon restart
|
|
4
|
+
port: 3001, // The port BrowserSync will run on
|
|
5
|
+
files: ["src/**/*.*"], // Files to watch
|
|
6
|
+
ignore: ['**/node_modules/**', '**/repos/**/*.json'],
|
|
7
|
+
reloadDelay: 500, // Wait for nodemon to restart
|
|
8
|
+
};
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
# ---- Environment
|
|
2
2
|
NODE_ENV=development
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# ---- Server
|
|
6
6
|
PORT=3000
|
|
7
|
-
HOST=localhost
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
# ---- Setup jet-logger
|
|
11
10
|
JET_LOGGER_MODE=console
|
|
12
11
|
JET_LOGGER_FILEPATH=jet-logger.log
|
|
13
|
-
|
|
12
|
+
JET_LOGGER_SHOW_TIME=true
|
|
14
13
|
JET_LOGGER_FORMAT=line
|
|
15
|
-
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
# ---- Environment
|
|
2
2
|
NODE_ENV=production
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# ---- Server
|
|
6
6
|
PORT=8081
|
|
7
|
-
HOST=localhost
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
# ---- Setup jet-logger
|
|
11
10
|
JET_LOGGER_MODE=file
|
|
12
11
|
JET_LOGGER_FILEPATH=jet-logger.log
|
|
13
|
-
|
|
12
|
+
JET_LOGGER_SHOW_TIME=true
|
|
14
13
|
JET_LOGGER_FORMAT=line
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
# ---- Environment
|
|
2
2
|
NODE_ENV=test
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# ---- Server
|
|
6
6
|
PORT=4000
|
|
7
|
-
HOST=localhost
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
# ---- Setup `jet-logger`
|
|
11
10
|
JET_LOGGER_MODE=console
|
|
12
11
|
JET_LOGGER_FILEPATH=jet-logger.log
|
|
13
|
-
|
|
12
|
+
JET_LOGGER_SHOW_TIME=true
|
|
14
13
|
JET_LOGGER_FORMAT=line
|
|
@@ -4,6 +4,10 @@ import n from 'eslint-plugin-n';
|
|
|
4
4
|
import { defineConfig, globalIgnores } from 'eslint/config';
|
|
5
5
|
import tseslint from 'typescript-eslint';
|
|
6
6
|
|
|
7
|
+
// ========================================================================= //
|
|
8
|
+
// EXPORT //
|
|
9
|
+
// ========================================================================= //
|
|
10
|
+
|
|
7
11
|
export default defineConfig([
|
|
8
12
|
// global ignores
|
|
9
13
|
globalIgnores(['**/dist/**', '**/public/**/lib/**']),
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-typescript-example",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"scripts": {
|
|
5
|
-
"build": "shx rm -rf dist && npm run lint && tsc --project tsconfig.prod.json && npm run build:copy-static
|
|
5
|
+
"build": "shx rm -rf dist && npm run lint && tsc --project tsconfig.prod.json && npm run build:copy-static",
|
|
6
6
|
"build:copy-static": "shx mkdir -p dist/public dist/views && shx cp -r src/public/* dist/public && shx cp -r src/views/* dist/views",
|
|
7
|
-
"
|
|
8
|
-
"clean-install": "rm -rf ./node_modules && rm -r package-lock.json && npm i",
|
|
7
|
+
"install:clean": "shx rm -rf ./node_modules package-lock.json && npm i",
|
|
9
8
|
"dev:basic": "cross-env DOTENV_CONFIG_PATH=./config/.env.development ts-node ./src/main",
|
|
10
9
|
"dev:watch": "nodemon --exec \"npm run dev:basic\" --watch ./src --ext .ts",
|
|
11
10
|
"dev": "concurrently \"npm run dev:watch\" \"npm run sync\"",
|
|
@@ -14,59 +13,55 @@
|
|
|
14
13
|
"start": "cross-env DOTENV_CONFIG_PATH=./config/.env.production node -r dotenv/config -r module-alias/register ./dist/main.js",
|
|
15
14
|
"sync": "delay 1s && browser-sync start --config bs-config.js",
|
|
16
15
|
"test": "cross-env NODE_ENV=test vitest",
|
|
17
|
-
"
|
|
16
|
+
"typecheck": "tsc -b --noEmit"
|
|
18
17
|
},
|
|
19
18
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
19
|
+
"node": ">=22.12.0"
|
|
21
20
|
},
|
|
22
21
|
"_moduleAliases": {
|
|
23
22
|
"@src": "dist"
|
|
24
23
|
},
|
|
25
24
|
"dependencies": {
|
|
26
|
-
"cookie-parser": "^1.4.7",
|
|
27
25
|
"cross-env": "^10.1.0",
|
|
28
|
-
"
|
|
29
|
-
"dotenv": "^17.2.3",
|
|
26
|
+
"dotenv": "^18.0.4",
|
|
30
27
|
"express": "^5.2.1",
|
|
31
|
-
"helmet": "^8.
|
|
28
|
+
"helmet": "^8.3.0",
|
|
32
29
|
"jet-env": "^1.1.6",
|
|
33
|
-
"jet-
|
|
34
|
-
"jet-
|
|
30
|
+
"jet-id": "^1.3.1",
|
|
31
|
+
"jet-logger": "3.0.0",
|
|
32
|
+
"jet-paths": "^4.0.2",
|
|
35
33
|
"jet-validators": "^2.3.1",
|
|
36
|
-
"jsonfile": "^6.2.
|
|
37
|
-
"module-alias": "^2.
|
|
38
|
-
"morgan": "^1.
|
|
39
|
-
"tspo": "^1.0.7"
|
|
34
|
+
"jsonfile": "^6.2.1",
|
|
35
|
+
"module-alias": "^2.3.4",
|
|
36
|
+
"morgan": "^1.12.1"
|
|
40
37
|
},
|
|
41
38
|
"devDependencies": {
|
|
42
|
-
"@eslint/js": "^
|
|
43
|
-
"@swc/core": "^1.
|
|
39
|
+
"@eslint/js": "^10.0.1",
|
|
40
|
+
"@swc/core": "^1.16.2",
|
|
44
41
|
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
|
45
|
-
"@types/
|
|
46
|
-
"@types/find": "^0.2.4",
|
|
47
|
-
"@types/fs-extra": "^11.0.4",
|
|
42
|
+
"@types/express": "^5.0.6",
|
|
48
43
|
"@types/jsonfile": "^6.1.4",
|
|
49
|
-
"@types/module-alias": "^2.0.4",
|
|
50
44
|
"@types/morgan": "^1.9.10",
|
|
51
|
-
"@types/node": "^
|
|
52
|
-
"@types/supertest": "^
|
|
45
|
+
"@types/node": "^26.6.2",
|
|
46
|
+
"@types/supertest": "^7.2.1",
|
|
53
47
|
"browser-sync": "^3.0.4",
|
|
54
|
-
"concurrently": "^
|
|
48
|
+
"concurrently": "^10.0.5",
|
|
55
49
|
"delay-cli": "^3.0.0",
|
|
56
|
-
"eslint": "^
|
|
50
|
+
"eslint": "^10.11.0",
|
|
57
51
|
"eslint-config-prettier": "^10.1.8",
|
|
58
|
-
"eslint-plugin-n": "^
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"nodemon": "^3.1.11",
|
|
63
|
-
"prettier": "^3.8.0",
|
|
52
|
+
"eslint-plugin-n": "^18.3.0",
|
|
53
|
+
"jiti": "^2.7.0",
|
|
54
|
+
"nodemon": "^3.1.14",
|
|
55
|
+
"prettier": "^3.9.9",
|
|
64
56
|
"shx": "^0.4.0",
|
|
65
|
-
"supertest": "^7.
|
|
57
|
+
"supertest": "^7.3.0",
|
|
66
58
|
"ts-node": "^10.9.2",
|
|
67
59
|
"tsconfig-paths": "^4.2.0",
|
|
68
|
-
"typescript": "^
|
|
69
|
-
"typescript-eslint": "^8.
|
|
70
|
-
"vitest": "^
|
|
60
|
+
"typescript": "^6.0.3",
|
|
61
|
+
"typescript-eslint": "^8.70.1",
|
|
62
|
+
"vitest": "^5.0.2"
|
|
63
|
+
},
|
|
64
|
+
"allowScripts": {
|
|
65
|
+
"@swc/core@1.16.2": true
|
|
71
66
|
}
|
|
72
67
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import { ValueOf } from '../types/utility-types';
|
|
1
2
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { ValueOf } from "../types/structure-utils";
|
|
3
|
+
// ========================================================================= //
|
|
4
|
+
// CONSTANTS //
|
|
5
|
+
// ========================================================================= //
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* Hypertext Transfer Protocol (HTTP) response status codes.
|
|
@@ -386,9 +385,14 @@ const HttpStatusCodes = {
|
|
|
386
385
|
NETWORK_AUTHENTICATION_REQUIRED: 511,
|
|
387
386
|
} as const;
|
|
388
387
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
388
|
+
// ========================================================================= //
|
|
389
|
+
// TYPES //
|
|
390
|
+
// ========================================================================= //
|
|
392
391
|
|
|
393
392
|
type HttpStatusCodes = ValueOf<typeof HttpStatusCodes>;
|
|
393
|
+
|
|
394
|
+
// ========================================================================= //
|
|
395
|
+
// EXPORT //
|
|
396
|
+
// ========================================================================= //
|
|
397
|
+
|
|
394
398
|
export default HttpStatusCodes;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import jetPaths from 'jet-paths';
|
|
2
|
+
|
|
3
|
+
// ========================================================================= //
|
|
4
|
+
// CONSTANTS //
|
|
5
|
+
// ========================================================================= //
|
|
6
|
+
|
|
7
|
+
const Paths = jetPaths({
|
|
8
|
+
_: '/api',
|
|
9
|
+
Users: {
|
|
10
|
+
_: '/users',
|
|
11
|
+
Get: '/all',
|
|
12
|
+
Add: '/add',
|
|
13
|
+
Update: '/update',
|
|
14
|
+
Delete: '/delete',
|
|
15
|
+
},
|
|
16
|
+
} as const);
|
|
17
|
+
|
|
18
|
+
// ========================================================================= //
|
|
19
|
+
// EXPORT //
|
|
20
|
+
// ========================================================================= //
|
|
21
|
+
|
|
22
|
+
export default Paths;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import jetEnv, { num } from 'jet-env';
|
|
2
|
+
import { ValueOf } from '../types/utility-types';
|
|
3
|
+
|
|
4
|
+
// ========================================================================= //
|
|
5
|
+
// CONSTANTS //
|
|
6
|
+
// ========================================================================= //
|
|
7
|
+
|
|
8
|
+
// NOTE: These need to match the names of your ".env" files
|
|
9
|
+
export const NodeEnvs = {
|
|
10
|
+
DEV: 'development',
|
|
11
|
+
TEST: 'test',
|
|
12
|
+
PRODUCTION: 'production',
|
|
13
|
+
} as const;
|
|
14
|
+
export type NodeEnvs = ValueOf<typeof NodeEnvs>;
|
|
15
|
+
|
|
16
|
+
// ========================================================================= //
|
|
17
|
+
// EXEC //
|
|
18
|
+
// ========================================================================= //
|
|
19
|
+
|
|
20
|
+
// Setup the is `NodeEnvs` validator
|
|
21
|
+
const isNodeEnv = (() => {
|
|
22
|
+
const vals = Object.values(NodeEnvs);
|
|
23
|
+
const valsFin = vals.map((item) => item.toLowerCase());
|
|
24
|
+
const set = new Set(valsFin);
|
|
25
|
+
return (val: unknown): val is NodeEnvs => set.has(val as NodeEnvs);
|
|
26
|
+
})();
|
|
27
|
+
|
|
28
|
+
export const EnvVars = jetEnv({
|
|
29
|
+
NodeEnv: isNodeEnv,
|
|
30
|
+
Port: num,
|
|
31
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// ========================================================================= //
|
|
2
|
+
// TYPES //
|
|
3
|
+
// ========================================================================= //
|
|
4
|
+
|
|
5
|
+
export type ISOString =
|
|
6
|
+
`${number}-${number}-${number}T${number}:${number}:${number}${string}`;
|
|
7
|
+
|
|
8
|
+
// ========================================================================= //
|
|
9
|
+
// FUNCTIONS //
|
|
10
|
+
// ========================================================================= //
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Return the current-date (or a provided date) as an ISOString.
|
|
14
|
+
*/
|
|
15
|
+
export function getISOString(date = new Date()): ISOString {
|
|
16
|
+
return date.toISOString() as ISOString;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validate an ISOString.
|
|
21
|
+
*/
|
|
22
|
+
export function isISOString(value: unknown): value is ISOString {
|
|
23
|
+
try {
|
|
24
|
+
const date = new Date(value as string);
|
|
25
|
+
return !isNaN(date.getTime()) && date.toISOString() === value;
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ParseError } from 'jet-validators/utils';
|
|
2
|
+
|
|
3
|
+
import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
|
|
4
|
+
|
|
5
|
+
// ========================================================================= //
|
|
6
|
+
// CLASSES //
|
|
7
|
+
// ========================================================================= //
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Error with status code and message. `errors` (optional) is sent to the
|
|
11
|
+
* client alongside the message.
|
|
12
|
+
*/
|
|
13
|
+
export class RouteError extends Error {
|
|
14
|
+
public status: HttpStatusCodes;
|
|
15
|
+
public errors?: unknown[];
|
|
16
|
+
|
|
17
|
+
public constructor(
|
|
18
|
+
status: HttpStatusCodes,
|
|
19
|
+
message: string,
|
|
20
|
+
errors?: unknown[],
|
|
21
|
+
) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.status = status;
|
|
24
|
+
this.errors = errors;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Request data failed schema validation.
|
|
30
|
+
*/
|
|
31
|
+
export class ValidationError extends RouteError {
|
|
32
|
+
public static MESSAGE = 'Request validation failed.';
|
|
33
|
+
|
|
34
|
+
public constructor(errors: ParseError[]) {
|
|
35
|
+
super(HttpStatusCodes.BAD_REQUEST, ValidationError.MESSAGE, errors);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import logger from 'jet-logger';
|
|
2
|
+
|
|
3
|
+
import { EnvVars } from './common/constants/env-inv';
|
|
4
|
+
import server from './server';
|
|
5
|
+
|
|
6
|
+
// ========================================================================= //
|
|
7
|
+
// CONSTANTS //
|
|
8
|
+
// ========================================================================= //
|
|
9
|
+
|
|
10
|
+
const SERVER_START_MESSAGE =
|
|
11
|
+
'Express server started on port: ' + EnvVars.Port.toString();
|
|
12
|
+
|
|
13
|
+
// ========================================================================= //
|
|
14
|
+
// EXEC //
|
|
15
|
+
// ========================================================================= //
|
|
16
|
+
|
|
17
|
+
// Start the server
|
|
18
|
+
server.listen(EnvVars.Port, (err) => {
|
|
19
|
+
if (!!err) {
|
|
20
|
+
logger.err(err.message);
|
|
21
|
+
} else {
|
|
22
|
+
logger.info(SERVER_START_MESSAGE);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import jetid from 'jet-id';
|
|
2
|
+
import { isNonEmptyString, isString } from 'jet-validators';
|
|
3
|
+
import { parseObject, Schema, testObject } from 'jet-validators/utils';
|
|
4
|
+
|
|
5
|
+
import { getISOString, isISOString } from '@src/common/utils/date-utils';
|
|
6
|
+
|
|
7
|
+
import { Entity } from './common/types';
|
|
8
|
+
|
|
9
|
+
// ========================================================================= //
|
|
10
|
+
// CONSTANTS //
|
|
11
|
+
// ========================================================================= //
|
|
12
|
+
|
|
13
|
+
const GetDefaults = (): IUser => ({
|
|
14
|
+
id: jetid(),
|
|
15
|
+
name: '',
|
|
16
|
+
email: '',
|
|
17
|
+
created: getISOString(),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const schema: Schema<IUser> = {
|
|
21
|
+
id: isUserId,
|
|
22
|
+
name: isString,
|
|
23
|
+
email: isString,
|
|
24
|
+
created: isISOString,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// ========================================================================= //
|
|
28
|
+
// TYPES //
|
|
29
|
+
// ========================================================================= //
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @entity users
|
|
33
|
+
*/
|
|
34
|
+
export interface IUser extends Entity {
|
|
35
|
+
name: string;
|
|
36
|
+
email: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Fields a client supplies when creating a user; the server sets the rest.
|
|
41
|
+
*/
|
|
42
|
+
export type IUserInput = Pick<IUser, 'name' | 'email'>;
|
|
43
|
+
|
|
44
|
+
// ========================================================================= //
|
|
45
|
+
// FUNCTIONS //
|
|
46
|
+
// ========================================================================= //
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Validate the `User` schema.
|
|
50
|
+
*/
|
|
51
|
+
const parseUser = parseObject<IUser>(schema);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* For the APIs make sure the right fields are complete
|
|
55
|
+
*/
|
|
56
|
+
const isCompleteUser = testObject<IUser>({
|
|
57
|
+
...schema,
|
|
58
|
+
name: isNonEmptyString,
|
|
59
|
+
email: isNonEmptyString,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Validate the fields a client sends to create a user.
|
|
64
|
+
*/
|
|
65
|
+
const isUserInput = testObject<IUserInput>({
|
|
66
|
+
name: isNonEmptyString,
|
|
67
|
+
email: isNonEmptyString,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Test if an id is a valid user id.
|
|
72
|
+
*/
|
|
73
|
+
function isUserId(val: unknown): val is string {
|
|
74
|
+
return jetid.test(val);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* New user object.
|
|
79
|
+
*/
|
|
80
|
+
function new_(user?: Partial<IUser>): IUser {
|
|
81
|
+
return parseUser({ ...GetDefaults(), ...user }, (errors) => {
|
|
82
|
+
throw new Error('Setup new user failed ' + JSON.stringify(errors, null, 2));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ========================================================================= //
|
|
87
|
+
// EXPORT //
|
|
88
|
+
// ========================================================================= //
|
|
89
|
+
|
|
90
|
+
export default {
|
|
91
|
+
new: new_,
|
|
92
|
+
isId: isUserId,
|
|
93
|
+
isComplete: isCompleteUser,
|
|
94
|
+
isInput: isUserInput,
|
|
95
|
+
} as const;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ISOString } from "@src/common/utils/date-utils";
|
|
2
|
+
|
|
3
|
+
// ========================================================================= //
|
|
4
|
+
// TYPES //
|
|
5
|
+
// ========================================================================= //
|
|
6
|
+
|
|
7
|
+
export interface Entity {
|
|
8
|
+
id: string; // @PK
|
|
9
|
+
created: ISOString; // @audit
|
|
10
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
var Http = (() => {
|
|
2
|
+
// Setup request for json
|
|
3
|
+
var getOptions = (verb, data) => {
|
|
4
|
+
var options = {
|
|
5
|
+
dataType: 'json',
|
|
6
|
+
method: verb,
|
|
7
|
+
headers: {
|
|
8
|
+
Accept: 'application/json',
|
|
9
|
+
'Content-Type': 'application/json',
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
if (!!data) {
|
|
13
|
+
options.body = JSON.stringify(data);
|
|
14
|
+
}
|
|
15
|
+
return options;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Set Http methods
|
|
19
|
+
return {
|
|
20
|
+
get: (path) => fetch(path, getOptions('GET')),
|
|
21
|
+
post: (path, data) => fetch(path, getOptions('POST', data)),
|
|
22
|
+
put: (path, data) => fetch(path, getOptions('PUT', data)),
|
|
23
|
+
delete: (path) => fetch(path, getOptions('DELETE')),
|
|
24
|
+
};
|
|
25
|
+
})();
|