@digitaldefiance/express-suite-starter 4.19.11 → 4.20.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 (107) hide show
  1. package/README.md +185 -0
  2. package/config/presets/brightstack.json +90 -0
  3. package/dist/src/core/interfaces/devcontainer-config.interface.d.ts +1 -0
  4. package/dist/src/core/interfaces/devcontainer-config.interface.d.ts.map +1 -1
  5. package/dist/src/core/interfaces/generator-config.interface.d.ts +1 -0
  6. package/dist/src/core/interfaces/generator-config.interface.d.ts.map +1 -1
  7. package/dist/src/core/interfaces/validation-issue.interface.d.ts +1 -1
  8. package/dist/src/core/interfaces/validation-issue.interface.d.ts.map +1 -1
  9. package/dist/src/core/programmatic-generator.d.ts +4 -0
  10. package/dist/src/core/programmatic-generator.d.ts.map +1 -1
  11. package/dist/src/core/programmatic-generator.js +45 -12
  12. package/dist/src/core/programmatic-generator.js.map +1 -1
  13. package/dist/src/core/validators/post-generation-validator.d.ts +22 -1
  14. package/dist/src/core/validators/post-generation-validator.d.ts.map +1 -1
  15. package/dist/src/core/validators/post-generation-validator.js +127 -0
  16. package/dist/src/core/validators/post-generation-validator.js.map +1 -1
  17. package/dist/src/generate-monorepo.d.ts.map +1 -1
  18. package/dist/src/generate-monorepo.js +129 -45
  19. package/dist/src/generate-monorepo.js.map +1 -1
  20. package/dist/src/i18n/starter-string-key.d.ts +13 -1
  21. package/dist/src/i18n/starter-string-key.d.ts.map +1 -1
  22. package/dist/src/i18n/starter-string-key.js +17 -0
  23. package/dist/src/i18n/starter-string-key.js.map +1 -1
  24. package/dist/src/i18n/strings/de.d.ts.map +1 -1
  25. package/dist/src/i18n/strings/de.js +17 -0
  26. package/dist/src/i18n/strings/de.js.map +1 -1
  27. package/dist/src/i18n/strings/en-gb.d.ts +12 -0
  28. package/dist/src/i18n/strings/en-gb.d.ts.map +1 -1
  29. package/dist/src/i18n/strings/en-us.d.ts.map +1 -1
  30. package/dist/src/i18n/strings/en-us.js +17 -0
  31. package/dist/src/i18n/strings/en-us.js.map +1 -1
  32. package/dist/src/i18n/strings/es.d.ts.map +1 -1
  33. package/dist/src/i18n/strings/es.js +17 -0
  34. package/dist/src/i18n/strings/es.js.map +1 -1
  35. package/dist/src/i18n/strings/fr.d.ts.map +1 -1
  36. package/dist/src/i18n/strings/fr.js +17 -0
  37. package/dist/src/i18n/strings/fr.js.map +1 -1
  38. package/dist/src/i18n/strings/ja.d.ts.map +1 -1
  39. package/dist/src/i18n/strings/ja.js +17 -0
  40. package/dist/src/i18n/strings/ja.js.map +1 -1
  41. package/dist/src/i18n/strings/uk.d.ts.map +1 -1
  42. package/dist/src/i18n/strings/uk.js +17 -0
  43. package/dist/src/i18n/strings/uk.js.map +1 -1
  44. package/dist/src/i18n/strings/zh-cn.d.ts.map +1 -1
  45. package/dist/src/i18n/strings/zh-cn.js +17 -0
  46. package/dist/src/i18n/strings/zh-cn.js.map +1 -1
  47. package/dist/src/i18n/translations-all.d.ts +12 -0
  48. package/dist/src/i18n/translations-all.d.ts.map +1 -1
  49. package/package.json +2 -1
  50. package/scaffolding/api-brightstack/.env.example.mustache +47 -0
  51. package/scaffolding/api-brightstack/src/main.ts.mustache +20 -0
  52. package/scaffolding/api-lib-brightstack/src/index.ts +9 -0
  53. package/scaffolding/api-lib-brightstack/src/lib/application.ts +85 -0
  54. package/scaffolding/api-lib-brightstack/src/lib/collections/index.ts +13 -0
  55. package/scaffolding/api-lib-brightstack/src/lib/documents/user.ts +22 -0
  56. package/scaffolding/api-lib-brightstack/src/lib/environment.ts +55 -0
  57. package/scaffolding/api-lib-brightstack/src/lib/routers/api.ts +164 -0
  58. package/scaffolding/api-lib-brightstack/src/lib/routers/app.ts +32 -0
  59. package/scaffolding/api-lib-brightstack/src/lib/routers/base.ts +22 -0
  60. package/scaffolding/api-lib-brightstack/src/lib/routers/index.ts +2 -0
  61. package/scaffolding/api-lib-brightstack/src/lib/schemas/index.ts +2 -0
  62. package/scaffolding/api-lib-brightstack/src/lib/schemas/schema.ts +28 -0
  63. package/scaffolding/api-lib-brightstack/src/lib/schemas/user.ts +26 -0
  64. package/scaffolding/api-lib-brightstack/src/lib/services/email.ts +108 -0
  65. package/scaffolding/api-lib-brightstack/src/lib/shared-types.ts +149 -0
  66. package/scaffolding/api-lib-mern/src/lib/constants.ts.mustache +10 -0
  67. package/scaffolding/api-lib-mern/src/lib/documents/index.ts +1 -0
  68. package/scaffolding/api-lib-mern/src/lib/interfaces/constants.ts +9 -0
  69. package/scaffolding/api-lib-mern/src/lib/interfaces/environment-aws.ts +7 -0
  70. package/scaffolding/api-lib-mern/src/lib/interfaces/environment.ts +10 -0
  71. package/scaffolding/api-lib-mern/src/lib/middlewares.ts.mustache +113 -0
  72. package/scaffolding/api-lib-mern/src/lib/services/index.ts +1 -0
  73. package/scaffolding/api-mern/src/assets/.gitkeep +0 -0
  74. package/scaffolding/api-mern/src/views/index.ejs +34 -0
  75. package/scaffolding/inituserdb-brightstack/.env.example.mustache +13 -0
  76. package/scaffolding/inituserdb-brightstack/src/main.ts.mustache +195 -0
  77. /package/scaffolding/{api → api-brightstack}/src/assets/.gitkeep +0 -0
  78. /package/scaffolding/{api → api-brightstack}/src/views/index.ejs +0 -0
  79. /package/scaffolding/{api-lib → api-lib-brightstack}/src/lib/constants.ts.mustache +0 -0
  80. /package/scaffolding/{api-lib → api-lib-brightstack}/src/lib/documents/index.ts +0 -0
  81. /package/scaffolding/{api-lib → api-lib-brightstack}/src/lib/interfaces/constants.ts +0 -0
  82. /package/scaffolding/{api-lib → api-lib-brightstack}/src/lib/interfaces/environment-aws.ts +0 -0
  83. /package/scaffolding/{api-lib → api-lib-brightstack}/src/lib/interfaces/environment.ts +0 -0
  84. /package/scaffolding/{api-lib → api-lib-brightstack}/src/lib/middlewares.ts.mustache +0 -0
  85. /package/scaffolding/{api-lib → api-lib-brightstack}/src/lib/services/index.ts +0 -0
  86. /package/scaffolding/{api-lib → api-lib-mern}/src/index.ts +0 -0
  87. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/application.ts +0 -0
  88. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/documents/user.ts +0 -0
  89. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/environment.ts +0 -0
  90. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/models/email-token.ts +0 -0
  91. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/models/mnemonic.ts +0 -0
  92. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/models/role.ts +0 -0
  93. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/models/used-direct-login-token.ts +0 -0
  94. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/models/user-role.ts +0 -0
  95. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/models/user.ts +0 -0
  96. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/routers/api.ts +0 -0
  97. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/routers/app.ts +0 -0
  98. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/routers/index.ts +0 -0
  99. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/schemas/index.ts +0 -0
  100. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/schemas/schema.ts +0 -0
  101. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/schemas/user.ts +0 -0
  102. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/services/email.ts +0 -0
  103. /package/scaffolding/{api-lib → api-lib-mern}/src/lib/shared-types.ts +0 -0
  104. /package/scaffolding/{api → api-mern}/.env.example.mustache +0 -0
  105. /package/scaffolding/{api → api-mern}/src/main.ts.mustache +0 -0
  106. /package/scaffolding/{inituserdb → inituserdb-mern}/.env.example.mustache +0 -0
  107. /package/scaffolding/{inituserdb → inituserdb-mern}/src/main.ts.mustache +0 -0
@@ -0,0 +1,113 @@
1
+ import { AppConstants } from '{{namespace}}/lib';
2
+ import cors from 'cors';
3
+ import { randomBytes } from 'crypto';
4
+ import {
5
+ Application,
6
+ json,
7
+ NextFunction,
8
+ Request,
9
+ Response,
10
+ urlencoded,
11
+ } from 'express';
12
+ import helmet from 'helmet';
13
+ import { IncomingMessage, ServerResponse } from 'http';
14
+
15
+ /**
16
+ * CORS whitelist
17
+ */
18
+ const corsWhitelist = [
19
+ /^https?:\/\/localhost:(3000|3443|4200)$/,
20
+ new RegExp(
21
+ `^https?:\\/\\/${AppConstants.SiteHostname.replace(
22
+ /[.*+?^${}()|[\]\\]/g,
23
+ '\\$&'
24
+ )}$`
25
+ ),
26
+ ];
27
+
28
+ /**
29
+ * CORS options delegate
30
+ * @param req - CORS request
31
+ * @param callback - Callback function
32
+ */
33
+ const corsOptionsDelegate = (
34
+ req: cors.CorsRequest,
35
+ callback: (
36
+ error: Error | null,
37
+ options: cors.CorsOptions | undefined,
38
+ ) => void,
39
+ ) => {
40
+ let corsOptions: cors.CorsOptions;
41
+ const origin = req.headers.origin;
42
+ if (
43
+ origin &&
44
+ corsWhitelist.find((w) => {
45
+ if (w instanceof RegExp) {
46
+ return w.test(origin);
47
+ } else {
48
+ return w === origin;
49
+ }
50
+ })
51
+ ) {
52
+ corsOptions = { origin: true };
53
+ } else {
54
+ corsOptions = { origin: false };
55
+ }
56
+ callback(null, corsOptions);
57
+ };
58
+
59
+ /**
60
+ * Initialize the middleware
61
+ * @param app - Express application
62
+ */
63
+ export const initMiddleware = (app: Application): void => {
64
+ // Helmet helps you secure your Express apps by setting various HTTP headers
65
+ // CSP nonce
66
+ app.use((req: Request, res: Response, next: NextFunction) => {
67
+ res.locals['cspNonce'] = randomBytes(32).toString('hex');
68
+ next();
69
+ });
70
+ app.use(
71
+ helmet({
72
+ contentSecurityPolicy: {
73
+ directives: {
74
+ defaultSrc: ["'self'"],
75
+ imgSrc: ["'self'", 'https://flagcdn.com', 'data:', 'blob:'],
76
+ connectSrc: [
77
+ "'self'",
78
+ 'http://localhost:3000',
79
+ 'https://localhost:3000',
80
+ 'http://localhost:4200',
81
+ 'https://localhost:4200',
82
+ 'https://localhost:3443',
83
+ `http://${AppConstants.SiteHostname}`,
84
+ `https://${AppConstants.SiteHostname}`,
85
+ ],
86
+ scriptSrc: [
87
+ "'self'",
88
+ //"'unsafe-inline'",
89
+ "'strict-dynamic'",
90
+ (req: IncomingMessage, res: ServerResponse) =>
91
+ `'nonce-${(res as Response).locals['cspNonce']}'`,
92
+ ],
93
+ styleSrc: [
94
+ "'self'",
95
+ "'unsafe-inline'",
96
+ 'https://fonts.googleapis.com',
97
+ ],
98
+ fontSrc: [
99
+ "'self'",
100
+ 'https://fonts.gstatic.com',
101
+ ],
102
+ frameSrc: ["'self'"],
103
+ },
104
+ },
105
+ }),
106
+ );
107
+ // Enable CORS
108
+ app.use(cors(corsOptionsDelegate));
109
+ // Parse incoming requests with JSON payloads
110
+ app.use(json());
111
+ // Parse incoming requests with urlencoded payloads
112
+ app.use(urlencoded({ extended: true }));
113
+ }
@@ -0,0 +1 @@
1
+ export * from './email';
File without changes
@@ -0,0 +1,34 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title><%= title %></title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <link rel="icon" type="image/x-icon" href="/assets/favicon.ico" />
8
+ <script nonce="<%= cspNonce %>"></script>
9
+ <base href="<%= baseHref %>" />
10
+
11
+ <script nonce="<%= cspNonce %>">
12
+ window.APP_CONFIG = {
13
+ hostname: '<%= hostname %>',
14
+ siteTitle: '<%= title %>',
15
+ server: '<%= server %>',
16
+ };
17
+ </script>
18
+ <% if (cssFile) { %>
19
+ <link rel="stylesheet" href="<%= cssFile %>" />
20
+ <% } %>
21
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
22
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
23
+ <link
24
+ href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap"
25
+ rel="stylesheet"
26
+ />
27
+ </head>
28
+ <body>
29
+ <div id="root"></div>
30
+ <% if (jsFile) { %>
31
+ <script nonce="<%= cspNonce %>" type="module" src="<%= jsFile %>"></script>
32
+ <% } %>
33
+ </body>
34
+ </html>
@@ -0,0 +1,13 @@
1
+ BRIGHTCHAIN_BLOCKSTORE_PATH={{blockStorePath}}
2
+ BRIGHTCHAIN_BLOCKSIZE_BYTES=1048576
3
+ BRIGHTCHAIN_BLOCKSTORE_TYPE=disk
4
+ USE_MEMORY_DOCSTORE={{useMemoryDocstore}}
5
+ DEV_DATABASE={{devDatabase}}
6
+ MEMBER_POOL_NAME=BrightChain
7
+ JWT_SECRET={{jwtSecret}}
8
+ API_DIST_DIR=/workspaces/{{workspaceName}}/dist/{{prefix}}-api
9
+ REACT_DIST_DIR=/workspaces/{{workspaceName}}/dist/{{prefix}}-react
10
+ DEBUG=true
11
+ DETAILED_DEBUG=true
12
+ MNEMONIC_ENCRYPTION_KEY={{mnemonicEncryptionKey}}
13
+ MNEMONIC_HMAC_SECRET={{mnemonicHmacSecret}}
@@ -0,0 +1,195 @@
1
+ import {
2
+ brightchainDatabaseInit,
3
+ BrightDbApplication,
4
+ BrightDbEnvironment,
5
+ } from '@brightchain/node-express-suite';
6
+ import { Constants as AppConstants } from '{{namespace}}/api-lib';
7
+ import { GlobalActiveContext, IActiveContext } from '@digitaldefiance/i18n-lib';
8
+ import { IECIESConfig } from '@digitaldefiance/ecies-lib';
9
+ import { ECIESService } from '@digitaldefiance/node-ecies-lib';
10
+ import {
11
+ CoreLanguageCode,
12
+ } from '@digitaldefiance/i18n-lib';
13
+ import { getSuiteCoreTranslation, SuiteCoreStringKey } from '@digitaldefiance/suite-core-lib';
14
+ import { randomBytes } from 'crypto';
15
+ import { join } from 'path';
16
+ import { rm } from 'fs/promises';
17
+
18
+ // Simple debugLog implementation
19
+ function debugLog(debug: boolean, type: 'log' | 'warn' | 'error', ...args: any[]): void {
20
+ if (debug) {
21
+ console[type](...args);
22
+ }
23
+ }
24
+
25
+ async function main() {
26
+ const context = GlobalActiveContext.getInstance<CoreLanguageCode, IActiveContext<CoreLanguageCode>>();
27
+ context.languageContextSpace = 'admin';
28
+
29
+ const config: IECIESConfig = {
30
+ curveName: AppConstants.ECIES.CURVE_NAME,
31
+ primaryKeyDerivationPath: AppConstants.ECIES.PRIMARY_KEY_DERIVATION_PATH,
32
+ mnemonicStrength: AppConstants.ECIES.MNEMONIC_STRENGTH,
33
+ symmetricAlgorithm: AppConstants.ECIES.SYMMETRIC_ALGORITHM_CONFIGURATION,
34
+ symmetricKeyBits: AppConstants.ECIES.SYMMETRIC.KEY_BITS,
35
+ symmetricKeyMode: AppConstants.ECIES.SYMMETRIC.MODE,
36
+ };
37
+ const eciesService = new ECIESService(config);
38
+ if (process.argv.includes('--gen-system-user-mnemonic')) {
39
+ const mnemonic = eciesService.generateNewMnemonic();
40
+ process.env.ADMIN_MNEMONIC = mnemonic.value;
41
+ console.log(
42
+ `ADMIN_MNEMONIC="${mnemonic.value}"\n`,
43
+ getSuiteCoreTranslation(
44
+ SuiteCoreStringKey.Admin_MakeSureToSetItInEnv,
45
+ ),
46
+ );
47
+ }
48
+ if (process.argv.includes('--gen-member-user-mnemonic')) {
49
+ const mnemonic = eciesService.generateNewMnemonic();
50
+ process.env.MEMBER_MNEMONIC = mnemonic.value;
51
+ console.log(
52
+ `MEMBER_MNEMONIC="${mnemonic.value}"\n`,
53
+ getSuiteCoreTranslation(
54
+ SuiteCoreStringKey.Admin_MakeSureToSetItInEnv,
55
+ ),
56
+ );
57
+ }
58
+ if (process.argv.includes('--gen-mnemonic-hmac-secret')) {
59
+ const mnemonicHmacSecret = randomBytes(32).toString('hex');
60
+ process.env.MNEMONIC_HMAC_SECRET = mnemonicHmacSecret;
61
+ console.log(
62
+ `MNEMONIC_HMAC_SECRET="${mnemonicHmacSecret}"\n`,
63
+ getSuiteCoreTranslation(
64
+ SuiteCoreStringKey.Admin_MakeSureToSetItInEnv,
65
+ ),
66
+ );
67
+ }
68
+ if (process.argv.includes('--gen-mnemonic-encryption-key')) {
69
+ const mnemonicEncryptionKey = randomBytes(32).toString('hex');
70
+ process.env.MNEMONIC_ENCRYPTION_KEY = mnemonicEncryptionKey;
71
+ console.log(
72
+ `MNEMONIC_ENCRYPTION_KEY="${mnemonicEncryptionKey}"\n`,
73
+ getSuiteCoreTranslation(
74
+ SuiteCoreStringKey.Admin_MakeSureToSetItInEnv,
75
+ ),
76
+ );
77
+ }
78
+
79
+ const envDir = join(
80
+ BrightDbApplication.distDir,
81
+ '{{prefix}}-inituserdb',
82
+ '.env',
83
+ );
84
+ const env = new BrightDbEnvironment(envDir, true);
85
+
86
+ const shouldDrop = process.argv.includes('--drop');
87
+
88
+ // If --drop is requested, clear the block store path directory
89
+ if (shouldDrop && env.blockStorePath) {
90
+ debugLog(
91
+ env.detailedDebug,
92
+ 'log',
93
+ `Clearing block store directory: ${env.blockStorePath}`,
94
+ );
95
+ try {
96
+ await rm(env.blockStorePath, { recursive: true, force: true });
97
+ debugLog(
98
+ env.detailedDebug,
99
+ 'log',
100
+ getSuiteCoreTranslation(SuiteCoreStringKey.Admin_DatabaseDropped),
101
+ );
102
+ await new Promise((resolve) => setTimeout(resolve, 1000));
103
+ debugLog(
104
+ env.detailedDebug,
105
+ 'log',
106
+ getSuiteCoreTranslation(SuiteCoreStringKey.Admin_ProceedingToDbInitialization),
107
+ );
108
+ } catch (err) {
109
+ debugLog(
110
+ env.detailedDebug,
111
+ 'error',
112
+ getSuiteCoreTranslation(SuiteCoreStringKey.Admin_Error_FailedToDropDatabase),
113
+ err,
114
+ );
115
+ process.exit(2);
116
+ }
117
+ } else if (shouldDrop && !env.blockStorePath) {
118
+ debugLog(
119
+ env.detailedDebug,
120
+ 'log',
121
+ 'In-memory mode: --drop is a no-op (data is ephemeral)',
122
+ );
123
+ }
124
+
125
+ debugLog(
126
+ env.detailedDebug,
127
+ 'log',
128
+ getSuiteCoreTranslation(SuiteCoreStringKey.Admin_StartingDbInitialization),
129
+ );
130
+
131
+ let exitCode = 1;
132
+
133
+ const result = await brightchainDatabaseInit(env);
134
+
135
+ if (result.success && result.backend) {
136
+ debugLog(
137
+ env.debug,
138
+ 'log',
139
+ getSuiteCoreTranslation(
140
+ SuiteCoreStringKey.Admin_UserDatabaseInitialized,
141
+ ),
142
+ );
143
+
144
+ if (env.detailedDebug) {
145
+ console.log('Block store initialized successfully');
146
+ console.log(` Block store type: ${env.blockStoreType}`);
147
+ if (env.blockStorePath) {
148
+ console.log(` Block store path: ${env.blockStorePath}`);
149
+ }
150
+ console.log(` Member pool name: ${env.memberPoolName}`);
151
+ }
152
+
153
+ // Handle --setEnv flag to write credentials to .env file
154
+ if (process.argv.includes('--setEnv')) {
155
+ const apiEnvPath = join(
156
+ BrightDbApplication.distDir,
157
+ '..', // Go up from dist
158
+ '{{prefix}}-api',
159
+ '.env',
160
+ );
161
+ debugLog(
162
+ env.detailedDebug,
163
+ 'log',
164
+ `Writing environment to: ${apiEnvPath}`,
165
+ );
166
+ }
167
+
168
+ // Disconnect the BrightDb instance
169
+ if (result.backend.db) {
170
+ await result.backend.db.disconnect();
171
+ }
172
+
173
+ exitCode = 0;
174
+ } else {
175
+ console.error(
176
+ getSuiteCoreTranslation(
177
+ SuiteCoreStringKey.Admin_Error_FailedToInitializeUserDatabase,
178
+ ),
179
+ result.error,
180
+ );
181
+ exitCode++;
182
+ }
183
+
184
+ process.exit(exitCode);
185
+ }
186
+
187
+ main().catch((err) => {
188
+ console.error(
189
+ getSuiteCoreTranslation(
190
+ SuiteCoreStringKey.Admin_Error_UnhandledErrorInMain,
191
+ ),
192
+ err,
193
+ );
194
+ process.exit(1);
195
+ });