express-generator-typescript 2.9.0 → 3.0.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.
Files changed (37) hide show
  1. package/README.md +196 -17
  2. package/lib/template/README.md +33 -15
  3. package/lib/template/package.json +13 -24
  4. package/lib/template/src/common/{utils → classes}/route-errors.ts +1 -1
  5. package/lib/template/src/common/constants/HttpStatusCodes.ts +7 -2
  6. package/lib/template/src/common/constants/{env.ts → env-inv.ts} +13 -9
  7. package/lib/template/src/common/utils/dev-only.ts +25 -0
  8. package/lib/template/src/entities/User/_internal/validators.ts +47 -0
  9. package/lib/template/src/entities/User/index.ts +2 -0
  10. package/lib/template/src/entities/User/module.ts +63 -0
  11. package/lib/template/src/entities/User/types.ts +18 -0
  12. package/lib/template/src/{models → entities}/common/types.ts +1 -1
  13. package/lib/template/src/main.ts +1 -1
  14. package/lib/template/src/public/scripts/HttpClient.js +59 -0
  15. package/lib/template/src/public/scripts/renderUsers.js +43 -5
  16. package/lib/template/src/public/scripts/users.js +75 -14
  17. package/lib/template/src/repos/MockOrm.ts +4 -4
  18. package/lib/template/src/repos/UserRepo.ts +6 -6
  19. package/lib/template/src/repos/common/database.json +2 -2
  20. package/lib/template/src/routes/UserRoutes.ts +2 -2
  21. package/lib/template/src/routes/common/express-types.ts +1 -1
  22. package/lib/template/src/routes/common/parseReq.ts +2 -2
  23. package/lib/template/src/server.ts +17 -5
  24. package/lib/template/src/services/UserService.ts +6 -6
  25. package/lib/template/src/views/users.html +1 -1
  26. package/lib/template/tests/common/comparators.ts +3 -3
  27. package/lib/template/tests/common/supertest-types.ts +2 -2
  28. package/lib/template/tests/frontend.test.ts +1 -1
  29. package/lib/template/tests/support/agent.ts +2 -2
  30. package/lib/template/tests/users.test.ts +11 -11
  31. package/lib/template/tsconfig.json +9 -10
  32. package/lib/template/tsconfig.prod.json +13 -4
  33. package/lib/template/{vitest.config.mts → vitest.config.ts} +6 -4
  34. package/package.json +1 -5
  35. package/lib/template/bs-config.js +0 -8
  36. package/lib/template/src/models/User.model.ts +0 -95
  37. package/lib/template/src/public/scripts/http.js +0 -25
package/README.md CHANGED
@@ -1,17 +1,196 @@
1
- <p align="center">
2
- <img alt="express-generator-typescript" src="https://github.com/seanpmaxwell/express-generator-typescript/raw/main/assets/express-typescript.png" width="420">
3
- </p>
4
-
5
- # express-generator-typescript
6
-
7
- [![npm version](https://img.shields.io/npm/v/express-generator-typescript?logo=npm&label=npm)](https://www.npmjs.com/package/express-generator-typescript)
8
- [![npm downloads](https://img.shields.io/npm/dm/express-generator-typescript?color=orange)](https://www.npmjs.com/package/express-generator-typescript)
9
- [![License](https://img.shields.io/npm/l/express-generator-typescript)](https://github.com/seanpmaxwell/express-generator-typescript/blob/main/LICENSE)
10
-
11
- Command line tool which generates production-ready express templates with TypeScript baked in. Spin up a web server in seconds that follows the [TypeScript best practices](https://github.com/seanpmaxwell/Typescript-Best-Practices/blob/main/README.md).
12
- <br/>
13
-
14
-
15
- ## Documenation
16
-
17
- Please refer to the official <a href="https://github.com/seanpmaxwell/express-generator-typescript">github repo</a> for the most up-to-date documentation.
1
+ <p align="center">
2
+ <img alt="express-generator-typescript" src="https://github.com/seanpmaxwell/express-generator-typescript/raw/main/assets/express-typescript.png" width="420">
3
+ </p>
4
+
5
+ # express-generator-typescript
6
+
7
+ [![npm version](https://img.shields.io/npm/v/express-generator-typescript?logo=npm&label=npm)](https://www.npmjs.com/package/express-generator-typescript)
8
+ [![npm downloads](https://img.shields.io/npm/dm/express-generator-typescript?color=orange)](https://www.npmjs.com/package/express-generator-typescript)
9
+ [![License](https://img.shields.io/npm/l/express-generator-typescript)](https://github.com/seanpmaxwell/express-generator-typescript/blob/main/LICENSE)
10
+
11
+ A command-line tool that generates production-ready Express projects with TypeScript built in. Spin up a web server in seconds that follows the [TypeScript best practices](https://github.com/seanpmaxwell/Typescript-Best-Practices).
12
+
13
+ <p align="center">· · ·</p>
14
+
15
+ ## 🧭 Overview
16
+
17
+ `express-generator-typescript` works like the classic `express-generator` package, but the project it creates is fully set up for TypeScript. You get strict typing, linting, hot reloading, testing, and production builds, with defaults aimed at APIs. The project is an ES module and comes with an `@src/*` import alias, so imports stay clean as the app grows.
18
+
19
+ <p align="center">· · ·</p>
20
+
21
+ ## ✨ Features
22
+
23
+ - **TypeScript-first** – strict compiler settings, linting, and sensible tsconfig defaults, ready to go.
24
+ - **Built for APIs** – ideal for SPAs, mobile backends, or services.
25
+ - **Fast development** – runs TypeScript directly with tsx (no build step), restarts the server when you change it, and refreshes the browser when you change front-end files. Vitest, ESLint, and production builds are included.
26
+ - **Path aliases** – import from `@src/*` anywhere. It works in development, tests, and production builds.
27
+ - **Lean dependencies** – no view engine, ORM, or UI layer; only the essentials for Express + TypeScript.
28
+
29
+ <p align="center">· · ·</p>
30
+
31
+ ## 📦 Installation
32
+
33
+ Requires Node.js 22.12 or newer.
34
+
35
+ ```bash
36
+ npx express-generator-typescript
37
+ # or install globally
38
+ npm install -g express-generator-typescript
39
+ ```
40
+
41
+ <p align="center">· · ·</p>
42
+
43
+ ## ⚡ Quick Start
44
+
45
+ ```bash
46
+ # generate a project (defaults to express-gen-ts)
47
+ npx express-generator-typescript my-api
48
+
49
+ cd my-api
50
+
51
+ # start developing at http://localhost:3000
52
+ npm run dev
53
+ ```
54
+
55
+ <p align="center">· · ·</p>
56
+
57
+ ## 🖥️ CLI Options
58
+
59
+ | Option | Description |
60
+ | ----------------- | ------------------------------------------------------------------ |
61
+ | `project name` | Folder to create. Defaults to `express-gen-ts`. |
62
+ | `--use-yarn` | Install dependencies with Yarn instead of npm. |
63
+ | `--force` | Write into a folder that isn't empty. Files with the same name are overwritten. |
64
+ | `-h`, `--help` | Show usage. |
65
+ | `-v`, `--version` | Show the generator version. |
66
+
67
+ > Without `--force`, the generator won't write into a folder that already has files in it, so it can't overwrite your work by accident.
68
+
69
+ <p align="center">· · ·</p>
70
+
71
+ ## 🧩 Generated Template
72
+
73
+ The generated project is a small CRUD app for a `User` record. It shows how to structure models, services, and routes in Express + TypeScript. Linting, formatting, building, and hot reloading are all set up for you.
74
+
75
+ ### Available `package.json` Scripts
76
+
77
+ - `npm run dev` – Run the server in development with live reload and browser refresh.
78
+ - `npm test` – Run the tests with Vitest.
79
+ - `npm test -- users.test.ts` – Run a single test file.
80
+ - `npm run lint` – Check the code with ESLint.
81
+ - `npm run format` – Format the code with Prettier.
82
+ - `npm run build` – Build the project for production.
83
+ - `npm start` – Run the production build.
84
+ - `npm run typecheck` – Check for TypeScript errors without building.
85
+ - `npm run install:clean` – Delete `node_modules` and the lockfile, then reinstall.
86
+
87
+ ### Architecture
88
+
89
+ The app uses a **layered** architecture, which suits a small CRUD app. If you plan to grow it, consider switching to a **domain-based** layout. The [Typescript Best Practices README](https://github.com/seanpmaxwell/Typescript-Best-Practices/tree/main?tab=readme-ov-file#architecture) explains both patterns.
90
+
91
+ Layers explained:
92
+ ```yml
93
+ - src/ <-- Source code
94
+ - common/
95
+ - constants/
96
+ - Paths.ts <-- Single source of truth for all API routes
97
+ - routes/ <-- Read and validate values from Express requests; send responses
98
+ - services/ <-- Business logic (where everything comes together)
99
+ - repos/ <-- Talk to the database
100
+ - models/ <-- Describe and handle database records
101
+ - tests/ <-- Tests
102
+ ```
103
+
104
+ <p align="center">· · ·</p>
105
+
106
+ ## Notes for VS Code users
107
+
108
+ <details>
109
+ <summary>Format on save</summary>
110
+
111
+ The generated project uses ESLint for linting and Prettier for formatting. To format on save, install the Prettier extension for VS Code and set it as the default formatter in `.vscode/settings.json`:
112
+
113
+ ```json
114
+ // .vscode/settings.json
115
+ {
116
+ "editor.minimap.enabled": false,
117
+ "editor.rulers": [80],
118
+ "editor.tabSize": 2,
119
+
120
+ "workbench.sideBar.location": "right",
121
+ "workbench.editor.empty.hint": "hidden",
122
+
123
+ // Formatting: Prettier only
124
+ "editor.formatOnSave": true,
125
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
126
+
127
+ // ESLint: linting only (NO formatting)
128
+ "eslint.format.enable": false,
129
+ "eslint.nodePath": "node_modules",
130
+ "eslint.validate": ["javascript", "typescript", "typescriptreact"],
131
+
132
+ // Run ESLint fixes (non-formatting) on save
133
+ "editor.codeActionsOnSave": {
134
+ "source.fixAll.eslint": "explicit"
135
+ },
136
+
137
+ // Language overrides (keep Prettier)
138
+ "[javascript]": {
139
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
140
+ },
141
+ "[typescript]": {
142
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
143
+ },
144
+ "[json]": {
145
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
146
+ },
147
+
148
+ // JSDoc noise reduction
149
+ "javascript.suggest.completeJSDocs": false,
150
+ "javascript.suggest.jsdoc.generateReturns": false,
151
+ "typescript.suggest.completeJSDocs": false,
152
+ "typescript.suggest.jsdoc.generateReturns": false
153
+ }
154
+ ```
155
+
156
+ </details>
157
+
158
+ <details>
159
+ <summary>Debugging</summary>
160
+
161
+ To debug with breakpoints in VS Code, start the app or tests from `.vscode/launch.json`:
162
+
163
+ ```json
164
+ // .vscode/launch.json
165
+ {
166
+ "version": "0.2.0",
167
+ "configurations": [
168
+ {
169
+ "name": "Dev",
170
+ "type": "node",
171
+ "request": "launch",
172
+ "runtimeExecutable": "npm",
173
+ "runtimeArgs": ["run", "dev"],
174
+ "skipFiles": ["<node_internals>/**"],
175
+ "console": "integratedTerminal"
176
+ },
177
+ {
178
+ "name": "Test - Vitest",
179
+ "type": "node",
180
+ "request": "launch",
181
+ "runtimeExecutable": "npm",
182
+ "runtimeArgs": ["run", "test"],
183
+ "skipFiles": ["<node_internals>/**"],
184
+ "console": "integratedTerminal"
185
+ }
186
+ ]
187
+ }
188
+ ```
189
+
190
+ </details>
191
+
192
+ <p align="center">· · ·</p>
193
+
194
+ ## 📄 License
195
+
196
+ MIT © [seanpmaxwell1](LICENSE)
@@ -2,32 +2,29 @@
2
2
 
3
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
4
 
5
- <p align="center">· · ·</p>
5
+ The original template follows the [TypeScript best practices](https://github.com/seanpmaxwell/Typescript-Best-Practices).
6
6
 
7
+ <p align="center">· · ·</p>
7
8
 
8
9
  ## Available Scripts
9
10
 
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`
11
+ ### `npm run dev`
15
12
 
16
- Run the server in development with hot reloading and browser refresh (see `package.json` for all `npm run dev` variations)<br/>
13
+ Run the server in development at http://localhost:3000. The server restarts when you change server code, and the browser refreshes when you change server code or anything in `src/public` or `src/views`.
17
14
 
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.
15
+ > **Note:** development mode runs your `.ts` files directly with `tsx`, which doesn't check for TypeScript errors. Run `npm run typecheck` to check for them, and let your editor catch most of them as you work.
19
16
 
20
17
  ### `npm test`
21
18
 
22
- Run unit-tests with <a href="https://vitest.dev/guide/">vitest</a>.
19
+ Run the tests with [Vitest](https://vitest.dev/guide/).
23
20
 
24
21
  ### `npm run lint`
25
22
 
26
- Check for linting errors.
23
+ Check the code with ESLint.
27
24
 
28
25
  ### `npm run format`
29
26
 
30
- Format `src/` and `tests/` with prettier.
27
+ Format `src/` and `tests/` with Prettier.
31
28
 
32
29
  ### `npm run build`
33
30
 
@@ -35,16 +32,37 @@ Build the project for production.
35
32
 
36
33
  ### `npm start`
37
34
 
38
- Run the production build (Must be built first).
35
+ Run the production build. Run `npm run build` first.
39
36
 
40
37
  ### `npm run typecheck`
41
38
 
42
- Check for typescript errors.
39
+ Check for TypeScript errors without building.
40
+
41
+ ### `npm run install:clean`
42
+
43
+ Delete `node_modules/` and `package-lock.json`, then reinstall all dependencies.
43
44
 
44
45
  <p align="center">· · ·</p>
45
46
 
47
+ ## Tech Stack
48
+
49
+ - **Language**: [TypeScript](https://www.typescriptlang.org/) (strict mode, ES modules)
50
+ - **Web server framework**: [Express](https://expressjs.com/en/) (v5)
51
+ - **Security headers**: [helmet](https://helmet.js.org/) (production only)
52
+ - **Logging**
53
+ - **Request logging**: [morgan](https://github.com/expressjs/morgan) (development only)
54
+ - **General logging**: [jet-logger](https://github.com/seanpmaxwell/jet-logger)
55
+ - **Validation**: [jet-validators](https://github.com/seanpmaxwell/jet-validators)
56
+ - **Environment variables**: [dotenv](https://github.com/motdotla/dotenv) loads `config/.env.*`, and [jet-env](https://github.com/seanpmaxwell/jet-env) validates them
57
+ - **Reloading**: [tsx](https://tsx.hirok.io) (`tsx watch` restarts the server) and [livereload](https://github.com/napcs/node-livereload) + [connect-livereload](https://github.com/intesso/connect-livereload) (refreshes the browser)
58
+ - **Testing**: [Vitest](https://vitest.dev) + [Supertest](https://github.com/ladjs/supertest)
59
+ - **Linting**: [ESLint](https://eslint.org) with [typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint) and [eslint-plugin-n](https://github.com/eslint-community/eslint-plugin-n)
60
+ - **Formatting**: [Prettier](https://prettier.io) with [@trivago/prettier-plugin-sort-imports](https://github.com/trivago/prettier-plugin-sort-imports)
61
+ - **Building**: `tsc` + [tsc-alias](https://github.com/justkey007/tsc-alias) (rewrites `@src/*` imports in `dist/`)
62
+
63
+ <p align="center">· · ·</p>
46
64
 
47
65
  ## Additional Notes
48
66
 
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.
67
+ - `config/.env.production` is in `.gitignore` so production secrets don't get committed. Keep it out of version control and supply its values through your deployment tooling.
68
+ - The database is a JSON file meant only for the demo: `src/repos/common/database.json` in development, or `dist/repos/common/database.json` in production. It's created automatically if missing, but it isn't safe for simultaneous writes. Replace `src/repos/MockOrm.ts` with a real database before going to production.
@@ -1,26 +1,21 @@
1
1
  {
2
2
  "name": "express-typescript-example",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
+ "type": "module",
4
5
  "scripts": {
5
- "build": "shx rm -rf dist && npm run lint && tsc --project tsconfig.prod.json && npm run build:copy-static",
6
+ "build": "shx rm -rf dist && npm run lint && tsc --project tsconfig.prod.json && tsc-alias -p tsconfig.prod.json && npm run build:copy-static",
6
7
  "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
  "install:clean": "shx rm -rf ./node_modules package-lock.json && npm i",
8
- "dev:basic": "cross-env DOTENV_CONFIG_PATH=./config/.env.development ts-node ./src/main",
9
- "dev:watch": "nodemon --exec \"npm run dev:basic\" --watch ./src --ext .ts",
10
- "dev": "concurrently \"npm run dev:watch\" \"npm run sync\"",
9
+ "dev": "cross-env DOTENV_CONFIG_PATH=./config/.env.development tsx watch --import dotenv/config ./src/main.ts",
11
10
  "lint": "eslint .",
12
11
  "format": "prettier --write .",
13
- "start": "cross-env DOTENV_CONFIG_PATH=./config/.env.production node -r dotenv/config -r module-alias/register ./dist/main.js",
14
- "sync": "delay 1s && browser-sync start --config bs-config.js",
12
+ "start": "cross-env DOTENV_CONFIG_PATH=./config/.env.production node --import dotenv/config ./dist/main.js",
15
13
  "test": "cross-env NODE_ENV=test vitest",
16
14
  "typecheck": "tsc -b --noEmit"
17
15
  },
18
16
  "engines": {
19
17
  "node": ">=22.12.0"
20
18
  },
21
- "_moduleAliases": {
22
- "@src": "dist"
23
- },
24
19
  "dependencies": {
25
20
  "cross-env": "^10.1.0",
26
21
  "dotenv": "^18.0.4",
@@ -29,40 +24,34 @@
29
24
  "jet-env": "^1.1.6",
30
25
  "jet-id": "^1.3.1",
31
26
  "jet-logger": "3.0.0",
32
- "jet-paths": "^4.0.1",
27
+ "jet-paths": "^4.0.2",
33
28
  "jet-validators": "^2.3.1",
34
29
  "jsonfile": "^6.2.1",
35
- "module-alias": "^2.3.4",
36
- "morgan": "^1.12.1",
37
- "tspo": "^1.0.7"
30
+ "morgan": "^1.12.1"
38
31
  },
39
32
  "devDependencies": {
40
33
  "@eslint/js": "^10.0.1",
41
- "@swc/core": "^1.16.2",
42
34
  "@trivago/prettier-plugin-sort-imports": "^6.0.2",
35
+ "@types/connect-livereload": "^0.6.3",
43
36
  "@types/express": "^5.0.6",
44
37
  "@types/jsonfile": "^6.1.4",
38
+ "@types/livereload": "^0.9.5",
45
39
  "@types/morgan": "^1.9.10",
46
40
  "@types/node": "^26.6.2",
47
41
  "@types/supertest": "^7.2.1",
48
- "browser-sync": "^3.0.4",
49
- "concurrently": "^10.0.5",
50
- "delay-cli": "^3.0.0",
42
+ "connect-livereload": "^0.6.1",
51
43
  "eslint": "^10.11.0",
52
44
  "eslint-config-prettier": "^10.1.8",
53
45
  "eslint-plugin-n": "^18.3.0",
54
46
  "jiti": "^2.7.0",
55
- "nodemon": "^3.1.14",
47
+ "livereload": "^0.10.3",
56
48
  "prettier": "^3.9.9",
57
49
  "shx": "^0.4.0",
58
50
  "supertest": "^7.3.0",
59
- "ts-node": "^10.9.2",
60
- "tsconfig-paths": "^4.2.0",
51
+ "tsc-alias": "^1.9.5",
52
+ "tsx": "^4.23.15",
61
53
  "typescript": "^6.0.3",
62
54
  "typescript-eslint": "^8.70.1",
63
55
  "vitest": "^5.0.2"
64
- },
65
- "allowScripts": {
66
- "@swc/core@1.16.2": true
67
56
  }
68
57
  }
@@ -1,4 +1,4 @@
1
- import { ParseError } from 'jet-validators/utils';
1
+ import type { ParseError } from 'jet-validators/utils';
2
2
 
3
3
  import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
4
4
 
@@ -1,4 +1,4 @@
1
- import { ValueOf } from '../types/utility-types';
1
+ import type { ValueOf } from '../types/utility-types';
2
2
 
3
3
  // ========================================================================= //
4
4
  // CONSTANTS //
@@ -386,8 +386,13 @@ const HttpStatusCodes = {
386
386
  } as const;
387
387
 
388
388
  // ========================================================================= //
389
- // EXPORT //
389
+ // TYPES //
390
390
  // ========================================================================= //
391
391
 
392
392
  type HttpStatusCodes = ValueOf<typeof HttpStatusCodes>;
393
+
394
+ // ========================================================================= //
395
+ // EXPORT //
396
+ // ========================================================================= //
397
+
393
398
  export default HttpStatusCodes;
@@ -1,5 +1,6 @@
1
1
  import jetEnv, { num } from 'jet-env';
2
- import tspo from 'tspo';
2
+
3
+ import type { ValueOf } from '../types/utility-types';
3
4
 
4
5
  // ========================================================================= //
5
6
  // CONSTANTS //
@@ -11,18 +12,21 @@ export const NodeEnvs = {
11
12
  TEST: 'test',
12
13
  PRODUCTION: 'production',
13
14
  } as const;
15
+ export type NodeEnvs = ValueOf<typeof NodeEnvs>;
14
16
 
15
17
  // ========================================================================= //
16
18
  // EXEC //
17
19
  // ========================================================================= //
18
20
 
19
- const EnvVars = jetEnv({
20
- NodeEnv: (v) => tspo.isValue(NodeEnvs, v),
21
+ // Setup the is `NodeEnvs` validator
22
+ const isNodeEnv = (() => {
23
+ const vals = Object.values(NodeEnvs);
24
+ const valsFin = vals.map((item) => item.toLowerCase());
25
+ const set = new Set(valsFin);
26
+ return (val: unknown): val is NodeEnvs => set.has(val as NodeEnvs);
27
+ })();
28
+
29
+ export const EnvVars = jetEnv({
30
+ NodeEnv: isNodeEnv,
21
31
  Port: num,
22
32
  });
23
-
24
- // ========================================================================= //
25
- // EXPORT //
26
- // ========================================================================= //
27
-
28
- export default EnvVars;
@@ -0,0 +1,25 @@
1
+ import connectLiveReload from 'connect-livereload';
2
+ import type { Express } from 'express';
3
+ import livereload from 'livereload';
4
+
5
+ // ========================================================================= //
6
+ // FUNCTIONS //
7
+ // ========================================================================= //
8
+
9
+ /**
10
+ * Development only: refresh the browser when front-end files change, and
11
+ * after `tsx watch` restarts the server for a TypeScript change.
12
+ *
13
+ * Must be registered before the routes that serve html so the reload script
14
+ * gets injected into those pages.
15
+ */
16
+ export function setupLiveReload(app: Express, watchDirs: string[]): void {
17
+ const server = livereload.createServer();
18
+ server.watch(watchDirs);
19
+ // A new process means the backend just restarted; reload once the browser
20
+ // reconnects so it picks up the new server code.
21
+ server.server.once('connection', () => {
22
+ setTimeout(() => server.refresh('/'), 100);
23
+ });
24
+ app.use(connectLiveReload());
25
+ }
@@ -0,0 +1,47 @@
1
+ import jetid from 'jet-id';
2
+ import { isNonEmptyString, isString } from 'jet-validators';
3
+ import { parseObject, type Schema, testObject } from 'jet-validators/utils';
4
+
5
+ import { isISOString } from '@src/common/utils/date-utils';
6
+
7
+ import type { UserEntity, UserInput } from '../types';
8
+
9
+ // ========================================================================= //
10
+ // FUNCTIONS //
11
+ // ========================================================================= //
12
+
13
+ const schema: Schema<UserEntity> = {
14
+ id: isUserId,
15
+ name: isString,
16
+ email: isString,
17
+ created: isISOString,
18
+ };
19
+
20
+ /**
21
+ * Validate the `User` schema.
22
+ */
23
+ export const parseUser = parseObject<UserEntity>(schema);
24
+
25
+ /**
26
+ * For the APIs make sure the right fields are complete
27
+ */
28
+ export const isCompleteUser = testObject<UserEntity>({
29
+ ...schema,
30
+ name: isNonEmptyString,
31
+ email: isNonEmptyString,
32
+ });
33
+
34
+ /**
35
+ * Validate the fields a client sends to create a user.
36
+ */
37
+ export const isUserInput = testObject<UserInput>({
38
+ name: isNonEmptyString,
39
+ email: isNonEmptyString,
40
+ });
41
+
42
+ /**
43
+ * Test if an id is a valid user id.
44
+ */
45
+ export function isUserId(val: unknown): val is string {
46
+ return jetid.test(val);
47
+ }
@@ -0,0 +1,2 @@
1
+ export { default as default } from './module';
2
+ export type { UserEntity, UserInput } from './types';
@@ -0,0 +1,63 @@
1
+ import jetid from 'jet-id';
2
+
3
+ import { getISOString, type ISOString } from '@src/common/utils/date-utils';
4
+
5
+ import {
6
+ isCompleteUser,
7
+ isUserId,
8
+ isUserInput,
9
+ parseUser,
10
+ } from './_internal/validators';
11
+ import type { UserEntity } from './types';
12
+
13
+ // ========================================================================= //
14
+ // FUNCTIONS //
15
+ // ========================================================================= //
16
+
17
+ /**
18
+ * Get a new `UserEntity` object with default values.
19
+ */
20
+ function getDefaults(): UserEntity {
21
+ return {
22
+ id: jetid(),
23
+ name: '',
24
+ email: '',
25
+ created: getISOString(),
26
+ };
27
+ }
28
+
29
+ /**
30
+ * Factory-function.
31
+ *
32
+ * Create a `UserEntity` from a partial or `undefined`
33
+ */
34
+ function create(user?: Partial<UserEntity>): UserEntity {
35
+ return parseUser({ ...getDefaults(), ...user }, (errors) => {
36
+ throw new Error('Setup new user failed ' + JSON.stringify(errors, null, 2));
37
+ });
38
+ }
39
+
40
+ /**
41
+ * Factory-function.
42
+ *
43
+ * Create a `UserEntity` from individual properties
44
+ */
45
+ function of(name: string, email?: string, created?: ISOString): UserEntity {
46
+ const retVal = getDefaults();
47
+ if (name) retVal.name = name;
48
+ if (email) retVal.email = email;
49
+ if (created) retVal.created = created;
50
+ return retVal;
51
+ }
52
+
53
+ // ========================================================================= //
54
+ // EXPORT //
55
+ // ========================================================================= //
56
+
57
+ export default {
58
+ of,
59
+ create,
60
+ isId: isUserId,
61
+ isComplete: isCompleteUser,
62
+ isInput: isUserInput,
63
+ } as const;
@@ -0,0 +1,18 @@
1
+ import type { Entity } from '@src/entities/common/types';
2
+
3
+ // ========================================================================= //
4
+ // TYPES //
5
+ // ========================================================================= //
6
+
7
+ /**
8
+ * @entity `users`
9
+ */
10
+ export interface UserEntity extends Entity {
11
+ name: string;
12
+ email: string;
13
+ }
14
+
15
+ /**
16
+ * Fields a client supplies when creating a user; the server sets the rest.
17
+ */
18
+ export type UserInput = Pick<UserEntity, 'name' | 'email'>;
@@ -1,4 +1,4 @@
1
- import { ISOString } from "@src/common/utils/date-utils";
1
+ import type { ISOString } from '@src/common/utils/date-utils';
2
2
 
3
3
  // ========================================================================= //
4
4
  // TYPES //
@@ -1,6 +1,6 @@
1
1
  import logger from 'jet-logger';
2
2
 
3
- import EnvVars from './common/constants/env';
3
+ import { EnvVars } from './common/constants/env-inv';
4
4
  import server from './server';
5
5
 
6
6
  // ========================================================================= //