@digitaldefiance/node-express-suite 4.21.1 → 4.22.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.
- package/package.json +2 -3
- package/src/controllers/user.d.ts.map +1 -1
- package/src/controllers/user.js +12 -5
- package/src/controllers/user.js.map +1 -1
- package/src/environment.d.ts +13 -1
- package/src/environment.d.ts.map +1 -1
- package/src/environment.js +48 -14
- package/src/environment.js.map +1 -1
- package/src/interfaces/database-init-result-tx.d.ts +27 -0
- package/src/interfaces/database-init-result-tx.d.ts.map +1 -0
- package/src/interfaces/database-init-result-tx.js +3 -0
- package/src/interfaces/database-init-result-tx.js.map +1 -0
- package/src/interfaces/environment.d.ts +13 -1
- package/src/interfaces/environment.d.ts.map +1 -1
- package/src/interfaces/index.d.ts +1 -0
- package/src/interfaces/index.d.ts.map +1 -1
- package/src/interfaces/index.js +1 -0
- package/src/interfaces/index.js.map +1 -1
- package/src/routers/app.d.ts +71 -22
- package/src/routers/app.d.ts.map +1 -1
- package/src/routers/app.js +103 -105
- package/src/routers/app.js.map +1 -1
- package/src/routers/router-config.d.ts +1 -6
- package/src/routers/router-config.d.ts.map +1 -1
- package/src/routers/router-config.js +1 -1
- package/src/routers/router-config.js.map +1 -1
- package/src/services/database-initialization.d.ts.map +1 -1
- package/src/services/database-initialization.js +15 -6
- package/src/services/database-initialization.js.map +1 -1
- package/src/services/user.d.ts +1 -1
- package/src/services/user.d.ts.map +1 -1
- package/src/services/user.js +36 -12
- package/src/services/user.js.map +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Contains all environment variables, database configuration, and user credentials.
|
|
4
4
|
* @module interfaces/environment
|
|
5
5
|
*/
|
|
6
|
-
import { SecureBuffer, SecureString } from '@digitaldefiance/ecies-lib';
|
|
6
|
+
import { EmailString, SecureBuffer, SecureString } from '@digitaldefiance/ecies-lib';
|
|
7
7
|
import { BackupCode } from '../backup-code';
|
|
8
8
|
import { IMongoEnvironment } from './environment-mongo';
|
|
9
9
|
import type { PlatformID } from '@digitaldefiance/node-ecies-lib';
|
|
@@ -88,6 +88,10 @@ export interface IEnvironment<TID extends PlatformID = Buffer> {
|
|
|
88
88
|
* For other databases, set DATABASE_URI in the environment.
|
|
89
89
|
*/
|
|
90
90
|
databaseUri?: string;
|
|
91
|
+
/**
|
|
92
|
+
* The email address of the admin user
|
|
93
|
+
*/
|
|
94
|
+
adminEmail: EmailString;
|
|
91
95
|
/**
|
|
92
96
|
* Mnemonic for the admin user
|
|
93
97
|
*/
|
|
@@ -116,6 +120,10 @@ export interface IEnvironment<TID extends PlatformID = Buffer> {
|
|
|
116
120
|
* Backup codes for the admin user
|
|
117
121
|
*/
|
|
118
122
|
adminBackupCodes?: BackupCode[];
|
|
123
|
+
/**
|
|
124
|
+
* The email address of the member user
|
|
125
|
+
*/
|
|
126
|
+
memberEmail: EmailString;
|
|
119
127
|
/**
|
|
120
128
|
* Mnemonic for the member user
|
|
121
129
|
*/
|
|
@@ -144,6 +152,10 @@ export interface IEnvironment<TID extends PlatformID = Buffer> {
|
|
|
144
152
|
* Backup codes for the member user
|
|
145
153
|
*/
|
|
146
154
|
memberBackupCodes?: BackupCode[];
|
|
155
|
+
/**
|
|
156
|
+
* The email address of the system user
|
|
157
|
+
*/
|
|
158
|
+
systemEmail: EmailString;
|
|
147
159
|
/**
|
|
148
160
|
* Mnemonic for the system user
|
|
149
161
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/interfaces/environment.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/interfaces/environment.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACb,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;;GAIG;AACH,MAAM,WAAW,YAAY,CAAC,GAAG,SAAS,UAAU,GAAG,MAAM;IAC3D;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,aAAa,EAAE,OAAO,CAAC;IACvB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,gBAAgB,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,UAAU,EAAE,WAAW,CAAC;IACxB;;OAEG;IACH,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B;;OAEG;IACH,OAAO,CAAC,EAAE,GAAG,CAAC;IACd;;OAEG;IACH,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB;;OAEG;IACH,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B;;OAEG;IACH,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB;;OAEG;IACH,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB;;OAEG;IACH,gBAAgB,CAAC,EAAE,UAAU,EAAE,CAAC;IAChC;;OAEG;IACH,WAAW,EAAE,WAAW,CAAC;IACzB;;OAEG;IACH,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B;;OAEG;IACH,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf;;OAEG;IACH,eAAe,CAAC,EAAE,IAAI,CAAC;IACvB;;OAEG;IACH,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B;;OAEG;IACH,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB;;OAEG;IACH,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB;;OAEG;IACH,iBAAiB,CAAC,EAAE,UAAU,EAAE,CAAC;IACjC;;OAEG;IACH,WAAW,EAAE,WAAW,CAAC;IACzB;;OAEG;IACH,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B;;OAEG;IACH,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf;;OAEG;IACH,eAAe,CAAC,EAAE,IAAI,CAAC;IACvB;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;OAEG;IACH,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B;;OAEG;IACH,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB;;OAEG;IACH,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB;;OAEG;IACH,iBAAiB,CAAC,EAAE,UAAU,EAAE,CAAC;IACjC;;OAEG;IACH,kBAAkB,EAAE,YAAY,CAAC;IACjC;;OAEG;IACH,qBAAqB,EAAE,YAAY,CAAC;IACpC;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,UAAU,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,WAAW,EAAE,kBAAkB,CAAC;CACjC"}
|
|
@@ -17,6 +17,7 @@ export * from './controller-config';
|
|
|
17
17
|
export * from './create-user-basics';
|
|
18
18
|
export * from './csp-config';
|
|
19
19
|
export * from './csp-definition';
|
|
20
|
+
export * from './database-init-result-tx';
|
|
20
21
|
export * from './db-init-result';
|
|
21
22
|
export * from './discriminator-collections';
|
|
22
23
|
export * from './email-service';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/interfaces/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AAEjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yCAAyC,CAAC;AACxD,cAAc,wBAAwB,CAAC;AACvC,cAAc,uCAAuC,CAAC;AACtD,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,UAAU,CAAC;AACzB,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/interfaces/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AAEjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yCAAyC,CAAC;AACxD,cAAc,wBAAwB,CAAC;AACvC,cAAc,uCAAuC,CAAC;AACtD,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,UAAU,CAAC;AACzB,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC"}
|
package/src/interfaces/index.js
CHANGED
|
@@ -20,6 +20,7 @@ tslib_1.__exportStar(require("./controller-config"), exports);
|
|
|
20
20
|
tslib_1.__exportStar(require("./create-user-basics"), exports);
|
|
21
21
|
tslib_1.__exportStar(require("./csp-config"), exports);
|
|
22
22
|
tslib_1.__exportStar(require("./csp-definition"), exports);
|
|
23
|
+
tslib_1.__exportStar(require("./database-init-result-tx"), exports);
|
|
23
24
|
tslib_1.__exportStar(require("./db-init-result"), exports);
|
|
24
25
|
tslib_1.__exportStar(require("./discriminator-collections"), exports);
|
|
25
26
|
tslib_1.__exportStar(require("./email-service"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/interfaces/index.ts"],"names":[],"mappings":";;;AAAA,oEAA0C;AAC1C,2DAAiC;AAEjC,+DAAqC;AACrC,kFAAwD;AACxD,iEAAuC;AACvC,gFAAsD;AACtD,0DAAgC;AAChC,wDAA8B;AAC9B,oEAA0C;AAC1C,8DAAoC;AACpC,8DAAoC;AACpC,4DAAkC;AAClC,4DAAkC;AAClC,4DAAkC;AAClC,sDAA4B;AAC5B,8DAAoC;AACpC,+DAAqC;AACrC,uDAA6B;AAC7B,2DAAiC;AACjC,2DAAiC;AACjC,sEAA4C;AAC5C,0DAAgC;AAChC,wDAA8B;AAC9B,8DAAoC;AACpC,uDAA6B;AAC7B,yDAA+B;AAC/B,qEAA2C;AAC3C,uDAA6B;AAC7B,8DAAoC;AACpC,gEAAsC;AACtC,mDAAyB;AACzB,yDAA+B;AAC/B,oDAA0B;AAC1B,oDAA0B;AAC1B,yDAA+B;AAC/B,iEAAuC;AACvC,mDAAyB;AACzB,+DAAqC;AACrC,iEAAuC;AACvC,yEAA+C;AAC/C,2DAAiC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/interfaces/index.ts"],"names":[],"mappings":";;;AAAA,oEAA0C;AAC1C,2DAAiC;AAEjC,+DAAqC;AACrC,kFAAwD;AACxD,iEAAuC;AACvC,gFAAsD;AACtD,0DAAgC;AAChC,wDAA8B;AAC9B,oEAA0C;AAC1C,8DAAoC;AACpC,8DAAoC;AACpC,4DAAkC;AAClC,4DAAkC;AAClC,4DAAkC;AAClC,sDAA4B;AAC5B,8DAAoC;AACpC,+DAAqC;AACrC,uDAA6B;AAC7B,2DAAiC;AACjC,oEAA0C;AAC1C,2DAAiC;AACjC,sEAA4C;AAC5C,0DAAgC;AAChC,wDAA8B;AAC9B,8DAAoC;AACpC,uDAA6B;AAC7B,yDAA+B;AAC/B,qEAA2C;AAC3C,uDAA6B;AAC7B,8DAAoC;AACpC,gEAAsC;AACtC,mDAAyB;AACzB,yDAA+B;AAC/B,oDAA0B;AAC1B,oDAA0B;AAC1B,yDAA+B;AAC/B,iEAAuC;AACvC,mDAAyB;AACzB,+DAAqC;AACrC,iEAAuC;AACvC,yEAA+C;AAC/C,2DAAiC"}
|
package/src/routers/app.d.ts
CHANGED
|
@@ -1,21 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Application router for serving React frontend and API routes.
|
|
3
|
-
* Handles static file serving,
|
|
3
|
+
* Handles static file serving, HTML template injection, and catch-all routing.
|
|
4
|
+
*
|
|
5
|
+
* Instead of EJS templates, this router reads the bundler-generated index.html
|
|
6
|
+
* directly and injects runtime values (CSP nonce, app config, title, etc.)
|
|
7
|
+
* via string replacement. This is bundler-agnostic — Vite, webpack, esbuild
|
|
8
|
+
* output all just works because the bundler wrote the index.html.
|
|
9
|
+
*
|
|
10
|
+
* Subclasses override getIndexLocals() to provide app-specific values
|
|
11
|
+
* and getIndexReplacements() for custom string replacements.
|
|
12
|
+
*
|
|
4
13
|
* @module routers/app
|
|
5
14
|
*/
|
|
6
15
|
import { Application, NextFunction, Request, Response } from 'express';
|
|
7
16
|
import { IApplication } from '../interfaces/application';
|
|
8
17
|
import { BaseRouter } from './base';
|
|
9
18
|
import type { PlatformID } from '@digitaldefiance/node-ecies-lib';
|
|
19
|
+
/**
|
|
20
|
+
* Runtime values available for index.html injection.
|
|
21
|
+
* Subclasses extend this via getIndexLocals().
|
|
22
|
+
*/
|
|
23
|
+
export interface IndexLocals {
|
|
24
|
+
/** CSP nonce for script tags */
|
|
25
|
+
cspNonce: string;
|
|
26
|
+
/** Page title */
|
|
27
|
+
title: string;
|
|
28
|
+
/** Site tagline */
|
|
29
|
+
tagline: string;
|
|
30
|
+
/** Site description */
|
|
31
|
+
description: string;
|
|
32
|
+
/** Full server URL (protocol + host + port) */
|
|
33
|
+
server: string;
|
|
34
|
+
/** Configured site URL */
|
|
35
|
+
siteUrl: string;
|
|
36
|
+
/** Base href for the app */
|
|
37
|
+
baseHref: string;
|
|
38
|
+
/** Request hostname */
|
|
39
|
+
hostname: string;
|
|
40
|
+
/** Site title (alias) */
|
|
41
|
+
siteTitle: string;
|
|
42
|
+
/** Additional app-specific values */
|
|
43
|
+
[key: string]: unknown;
|
|
44
|
+
}
|
|
10
45
|
/**
|
|
11
46
|
* Application router for serving React frontend and API routes.
|
|
12
|
-
* Sets up static file serving,
|
|
47
|
+
* Sets up static file serving, HTML injection, and catch-all routing for SPA.
|
|
48
|
+
*
|
|
49
|
+
* The index.html served to clients is the one produced by the bundler (Vite, etc.).
|
|
50
|
+
* Runtime values are injected via string replacement rather than a template engine.
|
|
51
|
+
*
|
|
13
52
|
* @template TID Platform-specific ID type
|
|
14
53
|
* @template TApplication Application instance type
|
|
15
54
|
*/
|
|
16
55
|
export declare class AppRouter<TID extends PlatformID = Buffer, TApplication extends IApplication<TID> = IApplication<TID>> {
|
|
17
|
-
/** Path to EJS views directory */
|
|
18
|
-
protected readonly viewsPath: string;
|
|
19
56
|
/** Path to index.html file */
|
|
20
57
|
protected readonly indexPath: string;
|
|
21
58
|
/** Path to assets directory */
|
|
@@ -26,6 +63,8 @@ export declare class AppRouter<TID extends PlatformID = Buffer, TApplication ext
|
|
|
26
63
|
protected readonly apiRouter: BaseRouter<TID, TApplication>;
|
|
27
64
|
/** Application instance */
|
|
28
65
|
protected readonly application: TApplication;
|
|
66
|
+
/** Cached index.html template read from the React dist directory. */
|
|
67
|
+
private indexHtmlTemplate;
|
|
29
68
|
/**
|
|
30
69
|
* Creates a new application router instance.
|
|
31
70
|
* Validates and resolves all paths to prevent directory traversal attacks.
|
|
@@ -41,36 +80,46 @@ export declare class AppRouter<TID extends PlatformID = Buffer, TApplication ext
|
|
|
41
80
|
*/
|
|
42
81
|
getAssetFilename(assetDir: string, pattern: RegExp): string | undefined;
|
|
43
82
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* @
|
|
48
|
-
* @returns Object containing base template variables
|
|
83
|
+
* Reads and caches the bundler-generated index.html from reactDistDir.
|
|
84
|
+
* In development mode, the file is re-read on every request to support
|
|
85
|
+
* rebuilds without server restart.
|
|
86
|
+
* @returns The HTML string, or null if the file doesn't exist.
|
|
49
87
|
*/
|
|
50
|
-
protected
|
|
88
|
+
protected getIndexHtmlTemplate(): string | null;
|
|
51
89
|
/**
|
|
52
|
-
*
|
|
90
|
+
* Gets the base locals for index.html injection.
|
|
91
|
+
* Subclasses should override this to add app-specific values.
|
|
53
92
|
* @param req Express request
|
|
54
93
|
* @param res Express response
|
|
55
|
-
* @
|
|
56
|
-
* @param template Template name to render
|
|
57
|
-
* @param locals Template variables
|
|
94
|
+
* @returns Object containing template variables
|
|
58
95
|
*/
|
|
59
|
-
protected
|
|
96
|
+
protected getIndexLocals(req: Request, res: Response): IndexLocals;
|
|
60
97
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
98
|
+
* Applies runtime replacements to the index.html template.
|
|
99
|
+
* Override this in subclasses to add app-specific replacements
|
|
100
|
+
* (e.g. Font Awesome kit injection, additional meta tags).
|
|
101
|
+
*
|
|
102
|
+
* The base implementation handles:
|
|
103
|
+
* 1. Title injection
|
|
104
|
+
* 2. APP_CONFIG placeholder replacement
|
|
105
|
+
* 3. CSP nonce injection on all script tags
|
|
106
|
+
*
|
|
107
|
+
* @param html The raw index.html string
|
|
108
|
+
* @param locals The locals from getIndexLocals()
|
|
109
|
+
* @returns The transformed HTML string
|
|
65
110
|
*/
|
|
66
|
-
protected
|
|
111
|
+
protected applyIndexReplacements(html: string, locals: IndexLocals): string;
|
|
67
112
|
/**
|
|
68
|
-
* Override to register additional routes
|
|
113
|
+
* Override to register additional routes before the index catch-all.
|
|
69
114
|
* @param app Express application
|
|
70
115
|
*/
|
|
71
116
|
protected registerAdditionalRenderHooks(app: Application): void;
|
|
72
117
|
/**
|
|
73
|
-
* Renders the index.html page with injected
|
|
118
|
+
* Renders the index.html page with injected runtime values.
|
|
119
|
+
*
|
|
120
|
+
* Reads the bundler-generated index.html, calls getIndexLocals() for
|
|
121
|
+
* template variables, then applyIndexReplacements() for string injection.
|
|
122
|
+
*
|
|
74
123
|
* @param req Express request
|
|
75
124
|
* @param res Express response
|
|
76
125
|
* @param next Express next function
|
package/src/routers/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/routers/app.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/routers/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,OAAO,EACL,WAAW,EAEX,YAAY,EACZ,OAAO,EACP,QAAQ,EACT,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAElE;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,qBAAa,SAAS,CACpB,GAAG,SAAS,UAAU,GAAG,MAAM,EAC/B,YAAY,SAAS,YAAY,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC;IAE1D,8BAA8B;IAC9B,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IACrC,+BAA+B;IAC/B,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IACrC,2CAA2C;IAC3C,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAExC,0BAA0B;IAC1B,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC5D,2BAA2B;IAC3B,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC;IAE7C,qEAAqE;IACrE,OAAO,CAAC,iBAAiB,CAAuB;IAEhD;;;;;OAKG;gBACS,SAAS,EAAE,UAAU,CAAC,GAAG,EAAE,YAAY,CAAC;IA0CpD;;;;;OAKG;IACI,gBAAgB,CACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,MAAM,GAAG,SAAS;IAarB;;;;;OAKG;IACH,SAAS,CAAC,oBAAoB,IAAI,MAAM,GAAG,IAAI;IAgB/C;;;;;;OAMG;IACH,SAAS,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,WAAW;IAyBlE;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,MAAM;IAiC3E;;;OAGG;IACH,SAAS,CAAC,6BAA6B,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI;IAI/D;;;;;;;;;OASG;IACI,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI;IAiBzE;;;;;OAKG;IACI,IAAI,CAAC,GAAG,EAAE,WAAW;CA0G7B"}
|
package/src/routers/app.js
CHANGED
|
@@ -1,36 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* @fileoverview Application router for serving React frontend and API routes.
|
|
4
|
-
* Handles static file serving,
|
|
4
|
+
* Handles static file serving, HTML template injection, and catch-all routing.
|
|
5
|
+
*
|
|
6
|
+
* Instead of EJS templates, this router reads the bundler-generated index.html
|
|
7
|
+
* directly and injects runtime values (CSP nonce, app config, title, etc.)
|
|
8
|
+
* via string replacement. This is bundler-agnostic — Vite, webpack, esbuild
|
|
9
|
+
* output all just works because the bundler wrote the index.html.
|
|
10
|
+
*
|
|
11
|
+
* Subclasses override getIndexLocals() to provide app-specific values
|
|
12
|
+
* and getIndexReplacements() for custom string replacements.
|
|
13
|
+
*
|
|
5
14
|
* @module routers/app
|
|
6
15
|
*/
|
|
7
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
17
|
exports.AppRouter = void 0;
|
|
9
|
-
const tslib_1 = require("tslib");
|
|
10
18
|
const i18n_lib_1 = require("@digitaldefiance/i18n-lib");
|
|
11
19
|
const suite_core_lib_1 = require("@digitaldefiance/suite-core-lib");
|
|
12
|
-
const ejs_1 = tslib_1.__importDefault(require("ejs"));
|
|
13
20
|
const express_1 = require("express");
|
|
14
21
|
const fs_1 = require("fs");
|
|
15
22
|
const path_1 = require("path");
|
|
16
23
|
const utils_1 = require("../utils");
|
|
17
|
-
/**
|
|
18
|
-
* Dummy function to ensure EJS is included in the bundle.
|
|
19
|
-
* @private
|
|
20
|
-
*/
|
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
22
|
-
function keepEJS() {
|
|
23
|
-
ejs_1.default.compile(''); // Compile an empty string, doesn't generate anything meaningful
|
|
24
|
-
}
|
|
25
24
|
/**
|
|
26
25
|
* Application router for serving React frontend and API routes.
|
|
27
|
-
* Sets up static file serving,
|
|
26
|
+
* Sets up static file serving, HTML injection, and catch-all routing for SPA.
|
|
27
|
+
*
|
|
28
|
+
* The index.html served to clients is the one produced by the bundler (Vite, etc.).
|
|
29
|
+
* Runtime values are injected via string replacement rather than a template engine.
|
|
30
|
+
*
|
|
28
31
|
* @template TID Platform-specific ID type
|
|
29
32
|
* @template TApplication Application instance type
|
|
30
33
|
*/
|
|
31
34
|
class AppRouter {
|
|
32
|
-
/** Path to EJS views directory */
|
|
33
|
-
viewsPath;
|
|
34
35
|
/** Path to index.html file */
|
|
35
36
|
indexPath;
|
|
36
37
|
/** Path to assets directory */
|
|
@@ -41,6 +42,8 @@ class AppRouter {
|
|
|
41
42
|
apiRouter;
|
|
42
43
|
/** Application instance */
|
|
43
44
|
application;
|
|
45
|
+
/** Cached index.html template read from the React dist directory. */
|
|
46
|
+
indexHtmlTemplate = null;
|
|
44
47
|
/**
|
|
45
48
|
* Creates a new application router instance.
|
|
46
49
|
* Validates and resolves all paths to prevent directory traversal attacks.
|
|
@@ -55,13 +58,6 @@ class AppRouter {
|
|
|
55
58
|
this.application.environment.reactDistDir.includes('..')) {
|
|
56
59
|
throw new suite_core_lib_1.TranslatableSuiteError(suite_core_lib_1.SuiteCoreStringKey.Error_InvalidPathContainsParentDirectoryReference);
|
|
57
60
|
}
|
|
58
|
-
const normalizedApiDistDir = (0, path_1.resolve)(this.application.environment.apiDistDir);
|
|
59
|
-
const viewsPath = (0, path_1.resolve)(normalizedApiDistDir, 'views');
|
|
60
|
-
if (!viewsPath.startsWith(normalizedApiDistDir + path_1.sep) &&
|
|
61
|
-
viewsPath !== normalizedApiDistDir) {
|
|
62
|
-
throw new suite_core_lib_1.TranslatableSuiteError(suite_core_lib_1.SuiteCoreStringKey.Error_InvalidViewsPathEscapesBaseDirectory);
|
|
63
|
-
}
|
|
64
|
-
this.viewsPath = viewsPath;
|
|
65
61
|
const normalizedReactDistDir = (0, path_1.resolve)(this.application.environment.reactDistDir);
|
|
66
62
|
this.reactDistDir = normalizedReactDistDir;
|
|
67
63
|
const indexPath = (0, path_1.resolve)(normalizedReactDistDir, 'index.html');
|
|
@@ -86,11 +82,7 @@ class AppRouter {
|
|
|
86
82
|
getAssetFilename(assetDir, pattern) {
|
|
87
83
|
try {
|
|
88
84
|
// Prevent path traversal by validating assetDir is within expected directory
|
|
89
|
-
|
|
90
|
-
if (
|
|
91
|
-
// amazonq-ignore-next-line
|
|
92
|
-
assetDir.includes('..') ||
|
|
93
|
-
!assetDir.startsWith(this.reactDistDir)) {
|
|
85
|
+
if (assetDir.includes('..') || !assetDir.startsWith(this.reactDistDir)) {
|
|
94
86
|
return undefined;
|
|
95
87
|
}
|
|
96
88
|
const files = (0, fs_1.readdirSync)(assetDir, 'utf8');
|
|
@@ -101,110 +93,114 @@ class AppRouter {
|
|
|
101
93
|
}
|
|
102
94
|
}
|
|
103
95
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
96
|
+
* Reads and caches the bundler-generated index.html from reactDistDir.
|
|
97
|
+
* In development mode, the file is re-read on every request to support
|
|
98
|
+
* rebuilds without server restart.
|
|
99
|
+
* @returns The HTML string, or null if the file doesn't exist.
|
|
100
|
+
*/
|
|
101
|
+
getIndexHtmlTemplate() {
|
|
102
|
+
// In production, cache the template
|
|
103
|
+
if (this.indexHtmlTemplate !== null) {
|
|
104
|
+
return this.indexHtmlTemplate;
|
|
105
|
+
}
|
|
106
|
+
if (!(0, fs_1.existsSync)(this.indexPath)) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const html = (0, fs_1.readFileSync)(this.indexPath, 'utf8');
|
|
110
|
+
// Only cache in production
|
|
111
|
+
if (this.application.environment.production) {
|
|
112
|
+
this.indexHtmlTemplate = html;
|
|
113
|
+
}
|
|
114
|
+
return html;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Gets the base locals for index.html injection.
|
|
118
|
+
* Subclasses should override this to add app-specific values.
|
|
106
119
|
* @param req Express request
|
|
107
120
|
* @param res Express response
|
|
108
|
-
* @returns Object containing
|
|
121
|
+
* @returns Object containing template variables
|
|
109
122
|
*/
|
|
110
|
-
|
|
123
|
+
getIndexLocals(req, res) {
|
|
111
124
|
const SiteName = this.application.constants.Site;
|
|
112
125
|
const SiteTagline = this.application.constants.SiteTagline;
|
|
113
126
|
const SiteDescription = this.application.constants.SiteDescription;
|
|
114
127
|
const hostname = req.hostname;
|
|
115
|
-
const
|
|
116
|
-
|
|
128
|
+
const port = req.socket.localPort;
|
|
129
|
+
const server = (port === 443 && req.protocol === 'https') ||
|
|
130
|
+
(port === 80 && req.protocol === 'http')
|
|
117
131
|
? `${req.protocol}://${hostname}`
|
|
118
|
-
: `${req.protocol}://${hostname}:${
|
|
132
|
+
: `${req.protocol}://${hostname}:${port}`;
|
|
119
133
|
return {
|
|
120
|
-
cspNonce: res.locals['cspNonce'],
|
|
134
|
+
cspNonce: res.locals['cspNonce'] || '',
|
|
121
135
|
title: SiteName,
|
|
122
136
|
tagline: SiteTagline,
|
|
123
137
|
description: SiteDescription,
|
|
124
138
|
server,
|
|
125
|
-
siteUrl: this.apiRouter.application.environment.serverUrl,
|
|
139
|
+
siteUrl: this.apiRouter.application.environment.serverUrl || server,
|
|
126
140
|
baseHref: this.apiRouter.application.environment.basePath,
|
|
127
141
|
hostname,
|
|
128
142
|
siteTitle: SiteName,
|
|
129
143
|
};
|
|
130
144
|
}
|
|
131
145
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
146
|
+
* Applies runtime replacements to the index.html template.
|
|
147
|
+
* Override this in subclasses to add app-specific replacements
|
|
148
|
+
* (e.g. Font Awesome kit injection, additional meta tags).
|
|
149
|
+
*
|
|
150
|
+
* The base implementation handles:
|
|
151
|
+
* 1. Title injection
|
|
152
|
+
* 2. APP_CONFIG placeholder replacement
|
|
153
|
+
* 3. CSP nonce injection on all script tags
|
|
154
|
+
*
|
|
155
|
+
* @param html The raw index.html string
|
|
156
|
+
* @param locals The locals from getIndexLocals()
|
|
157
|
+
* @returns The transformed HTML string
|
|
138
158
|
*/
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
159
|
+
applyIndexReplacements(html, locals) {
|
|
160
|
+
let result = html;
|
|
161
|
+
// 1. Inject title
|
|
162
|
+
result = result.replace(/<title>[^<]*<\/title>/, `<title>${locals.title}</title>`);
|
|
163
|
+
// 2. Replace the APP_CONFIG placeholder with real runtime values
|
|
164
|
+
// The index.html should contain: window.APP_CONFIG = window.APP_CONFIG || {};
|
|
165
|
+
result = result.replace(/window\.APP_CONFIG\s*=\s*window\.APP_CONFIG\s*\|\|\s*\{\s*\}\s*;?/, `window.APP_CONFIG = ${JSON.stringify({
|
|
166
|
+
apiUrl: `${locals.siteUrl}/api`,
|
|
167
|
+
serverUrl: locals.siteUrl,
|
|
168
|
+
hostname: locals.hostname,
|
|
169
|
+
siteTitle: locals.title,
|
|
170
|
+
server: locals.server,
|
|
171
|
+
})};`);
|
|
172
|
+
// 3. Inject CSP nonce on all <script> tags that don't already have one
|
|
173
|
+
if (locals.cspNonce) {
|
|
174
|
+
result = result.replace(/<script(?![^>]*nonce)/g, `<script nonce="${locals.cspNonce}"`);
|
|
143
175
|
}
|
|
144
|
-
|
|
145
|
-
(0, utils_1.debugLog)(this.apiRouter.application.environment.debug, 'log', `Rendering view "${template}" for ${sanitizedUrl}`);
|
|
146
|
-
res.render(template, locals, (err, html) => {
|
|
147
|
-
if (err) {
|
|
148
|
-
const errMsg = err && typeof err === 'object' && 'message' in err
|
|
149
|
-
? String(err.message).replace(/[\r\n]/g, ' ')
|
|
150
|
-
: 'Unknown error';
|
|
151
|
-
console.error('Error rendering: ' + errMsg);
|
|
152
|
-
const normalizedError = err instanceof Error ? err : new Error(errMsg);
|
|
153
|
-
if (!res.headersSent) {
|
|
154
|
-
res.status(500).send('An error occurred');
|
|
155
|
-
}
|
|
156
|
-
next(normalizedError);
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
if (!html) {
|
|
160
|
-
next(new Error(`Rendered template "${template}" returned empty HTML`));
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
(0, utils_1.debugLog)(this.apiRouter.application.environment.debug, 'log', `Rendered view "${template}" for ${sanitizedUrl}`);
|
|
164
|
-
res.send(html);
|
|
165
|
-
});
|
|
176
|
+
return result;
|
|
166
177
|
}
|
|
167
178
|
/**
|
|
168
|
-
*
|
|
169
|
-
* @param template Template name to render
|
|
170
|
-
* @param localsFactory Optional function to generate additional locals
|
|
171
|
-
* @returns Express middleware function
|
|
172
|
-
*/
|
|
173
|
-
createViewRenderer(template, localsFactory) {
|
|
174
|
-
return (req, res, next) => {
|
|
175
|
-
const baseLocals = this.getBaseViewLocals(req, res);
|
|
176
|
-
const extraLocals = localsFactory ? localsFactory(req, res) : {};
|
|
177
|
-
this.renderTemplate(req, res, next, template, {
|
|
178
|
-
...baseLocals,
|
|
179
|
-
...extraLocals,
|
|
180
|
-
});
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Override to register additional routes (e.g. other EJS pages) before the index catch-all.
|
|
179
|
+
* Override to register additional routes before the index catch-all.
|
|
185
180
|
* @param app Express application
|
|
186
181
|
*/
|
|
187
182
|
registerAdditionalRenderHooks(app) {
|
|
188
183
|
void app;
|
|
189
184
|
}
|
|
190
185
|
/**
|
|
191
|
-
* Renders the index.html page with injected
|
|
186
|
+
* Renders the index.html page with injected runtime values.
|
|
187
|
+
*
|
|
188
|
+
* Reads the bundler-generated index.html, calls getIndexLocals() for
|
|
189
|
+
* template variables, then applyIndexReplacements() for string injection.
|
|
190
|
+
*
|
|
192
191
|
* @param req Express request
|
|
193
192
|
* @param res Express response
|
|
194
193
|
* @param next Express next function
|
|
195
194
|
*/
|
|
196
195
|
renderIndex(req, res, next) {
|
|
197
|
-
|
|
198
|
-
|
|
196
|
+
const template = this.getIndexHtmlTemplate();
|
|
197
|
+
if (!template) {
|
|
198
|
+
next(new suite_core_lib_1.TranslatableSuiteError(suite_core_lib_1.SuiteCoreStringKey.Error_ReactIndexHtmlNotFoundInDistDirectory));
|
|
199
|
+
return;
|
|
199
200
|
}
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
...this.getBaseViewLocals(req, res),
|
|
204
|
-
jsFile: jsFile ? `assets/${jsFile}` : undefined,
|
|
205
|
-
cssFile: cssFile ? `assets/${cssFile}` : undefined,
|
|
206
|
-
};
|
|
207
|
-
this.renderTemplate(req, res, next, 'index', locals);
|
|
201
|
+
const locals = this.getIndexLocals(req, res);
|
|
202
|
+
const html = this.applyIndexReplacements(template, locals);
|
|
203
|
+
res.type('html').send(html);
|
|
208
204
|
}
|
|
209
205
|
/**
|
|
210
206
|
* Initializes the application router with all routes and middleware.
|
|
@@ -243,18 +239,18 @@ class AppRouter {
|
|
|
243
239
|
});
|
|
244
240
|
}
|
|
245
241
|
app.use('/api', this.apiRouter.router);
|
|
246
|
-
app.set('views', this.viewsPath);
|
|
247
|
-
app.set('view engine', 'ejs');
|
|
248
242
|
// Serve static files from the React app build directory (validated in constructor)
|
|
249
243
|
app.use('/assets', (0, express_1.static)(this.assetsDir));
|
|
250
244
|
const serveStaticWithLogging = (0, express_1.static)(this.reactDistDir);
|
|
251
245
|
app.use('/static/js', (0, express_1.static)(this.reactDistDir));
|
|
252
246
|
app.use((req, res, next) => {
|
|
253
|
-
if (req.url === '/'
|
|
247
|
+
if (req.url === '/' ||
|
|
248
|
+
req.url.startsWith('/api/') ||
|
|
249
|
+
req.url === '/api') {
|
|
254
250
|
next();
|
|
255
251
|
return;
|
|
256
252
|
}
|
|
257
|
-
(0, utils_1.debugLog)(this.apiRouter.application.environment.debug, 'log',
|
|
253
|
+
(0, utils_1.debugLog)(this.apiRouter.application.environment.debug, 'log', (0, suite_core_lib_1.getSuiteCoreTranslation)(suite_core_lib_1.SuiteCoreStringKey.Debug_TryingToServeStaticFor, { url: (req.url || '').replace(/[\r\n]/g, ' ') }));
|
|
258
254
|
if (req.url.endsWith('.js')) {
|
|
259
255
|
res.type('application/javascript');
|
|
260
256
|
}
|
|
@@ -263,19 +259,21 @@ class AppRouter {
|
|
|
263
259
|
const sanitizedErr = err instanceof Error
|
|
264
260
|
? err.message.replace(/[\r\n]/g, ' ')
|
|
265
261
|
: String(err).replace(/[\r\n]/g, ' ');
|
|
266
|
-
(0, utils_1.debugLog)(this.apiRouter.application.environment.debug, 'error',
|
|
262
|
+
(0, utils_1.debugLog)(this.apiRouter.application.environment.debug, 'error', (0, suite_core_lib_1.getSuiteCoreTranslation)(suite_core_lib_1.SuiteCoreStringKey.Debug_ErrorServingStaticFile, { error: sanitizedErr }));
|
|
267
263
|
(0, utils_1.handleError)(err, res, utils_1.sendApiMessageResponse, next);
|
|
268
264
|
return;
|
|
269
265
|
}
|
|
270
266
|
next();
|
|
271
267
|
});
|
|
272
268
|
});
|
|
273
|
-
// The "catchall" handler: for any request that doesn't
|
|
274
|
-
// match one above, send back React's index.html file.
|
|
275
|
-
// app.get('*', (req, res) => {
|
|
276
|
-
// res.sendFile(path.join(__dirname,'..', '..', '..', 'myapp-react', 'index.html'));
|
|
277
|
-
// });
|
|
278
269
|
this.registerAdditionalRenderHooks(app);
|
|
270
|
+
// Return 404 JSON for unmatched API routes instead of rendering the SPA
|
|
271
|
+
app.use('/api', (req, res) => {
|
|
272
|
+
res.status(404).json({
|
|
273
|
+
message: (0, suite_core_lib_1.getSuiteCoreTranslation)(suite_core_lib_1.SuiteCoreStringKey.Error_ApiRouteNotFound),
|
|
274
|
+
path: `/api${req.url}`,
|
|
275
|
+
});
|
|
276
|
+
});
|
|
279
277
|
app.use((req, res, next) => {
|
|
280
278
|
this.renderIndex(req, res, next);
|
|
281
279
|
});
|
package/src/routers/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/routers/app.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/routers/app.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Router configuration interface and defaults.
|
|
3
|
-
* Defines configuration options for router setup including static paths
|
|
3
|
+
* Defines configuration options for router setup including static paths and middleware.
|
|
4
4
|
* @module routers/router-config
|
|
5
5
|
*/
|
|
6
6
|
import { RequestHandler } from 'express';
|
|
@@ -13,11 +13,6 @@ export interface RouterConfig {
|
|
|
13
13
|
prefix: string;
|
|
14
14
|
directory: string;
|
|
15
15
|
}>;
|
|
16
|
-
/** View engine configuration with name and views path */
|
|
17
|
-
viewEngine?: {
|
|
18
|
-
name: string;
|
|
19
|
-
viewsPath: string;
|
|
20
|
-
};
|
|
21
16
|
/** Array of middleware functions to apply */
|
|
22
17
|
middleware?: RequestHandler[];
|
|
23
18
|
/** CORS configuration options */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router-config.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/routers/router-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,
|
|
1
|
+
{"version":3,"file":"router-config.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/routers/router-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,6CAA6C;IAC7C,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,iCAAiC;IACjC,IAAI,CAAC,EAAE;QACL,iCAAiC;QACjC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC3B,mCAAmC;QACnC,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,CAAC;CACH;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,YAGjC,CAAC"}
|