node-server-engine 1.10.15 → 1.11.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 (45) hide show
  1. package/README.md +200 -1
  2. package/dist/entities/PubSub/handleMessage/handleMessage.js +1 -1
  3. package/dist/entities/PubSub/handleMessage/handleMessage.js.map +1 -1
  4. package/dist/entities/Redis/Redis.d.ts +66 -24
  5. package/dist/entities/Redis/Redis.js +272 -144
  6. package/dist/entities/Redis/Redis.js.map +1 -1
  7. package/dist/entities/Redis/index.d.ts +1 -1
  8. package/dist/entities/Redis/index.js +10 -38
  9. package/dist/entities/Redis/index.js.map +1 -1
  10. package/dist/entities/SecretManager/SecretManager.d.ts +87 -0
  11. package/dist/entities/SecretManager/SecretManager.js +385 -0
  12. package/dist/entities/SecretManager/SecretManager.js.map +1 -0
  13. package/dist/entities/SecretManager/SecretManager.types.d.ts +71 -0
  14. package/dist/entities/SecretManager/SecretManager.types.js +2 -0
  15. package/dist/entities/SecretManager/SecretManager.types.js.map +1 -0
  16. package/dist/entities/SecretManager/index.d.ts +2 -0
  17. package/dist/entities/SecretManager/index.js +28 -0
  18. package/dist/entities/SecretManager/index.js.map +1 -0
  19. package/dist/entities/Sequelize/Sequelize.js +5 -3
  20. package/dist/entities/Sequelize/Sequelize.js.map +1 -1
  21. package/dist/entities/Server/Server.d.ts +2 -0
  22. package/dist/entities/Server/Server.js +9 -0
  23. package/dist/entities/Server/Server.js.map +1 -1
  24. package/dist/entities/Server/Server.types.d.ts +3 -0
  25. package/dist/entities/Server/Server.types.js.map +1 -1
  26. package/dist/entities/index.d.ts +1 -0
  27. package/dist/entities/index.js +11 -0
  28. package/dist/entities/index.js.map +1 -1
  29. package/dist/middleware/requestMetrics/requestMetrics.js +15 -5
  30. package/dist/middleware/requestMetrics/requestMetrics.js.map +1 -1
  31. package/dist/utils/index.d.ts +0 -1
  32. package/dist/utils/index.js +0 -11
  33. package/dist/utils/index.js.map +1 -1
  34. package/dist/utils/jwt/jwt.js +25 -2
  35. package/dist/utils/jwt/jwt.js.map +1 -1
  36. package/package.json +1 -1
  37. package/dist/utils/secretManager/index.d.ts +0 -2
  38. package/dist/utils/secretManager/index.js +0 -28
  39. package/dist/utils/secretManager/index.js.map +0 -1
  40. package/dist/utils/secretManager/secretLoader.d.ts +0 -8
  41. package/dist/utils/secretManager/secretLoader.js +0 -68
  42. package/dist/utils/secretManager/secretLoader.js.map +0 -1
  43. package/dist/utils/secretManager/secretResolver.d.ts +0 -5
  44. package/dist/utils/secretManager/secretResolver.js +0 -41
  45. package/dist/utils/secretManager/secretResolver.js.map +0 -1
@@ -0,0 +1,385 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.SecretManager = void 0;
8
+ var _secretManager = require("@google-cloud/secret-manager");
9
+ var _promises = _interopRequireDefault(require("fs/promises"));
10
+ var _path = _interopRequireDefault(require("path"));
11
+ var _os = _interopRequireDefault(require("os"));
12
+ var _EngineError = require("../EngineError");
13
+ var _LifecycleController = require("../LifecycleController");
14
+ var _report = require("../../utils/report");
15
+ const namespace = 'engine:SecretManager';
16
+
17
+ /**
18
+ * Generic GCP Secret Manager wrapper for managing application secrets
19
+ * Provides methods for loading secrets at startup, runtime fetching, and cleanup
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // Initialize with configuration
24
+ * await SecretManager.init({
25
+ * enabled: true,
26
+ * projectId: 'my-project',
27
+ * prefix: 'my-service',
28
+ * secrets: ['DB_PASSWORD', { name: 'PRIVATE_KEY', type: 'file' }]
29
+ * });
30
+ *
31
+ * // Get a cached secret
32
+ * const password = SecretManager.getSecret('DB_PASSWORD');
33
+ *
34
+ * // Fetch a secret on-demand
35
+ * const apiKey = await SecretManager.fetchSecret('API_KEY');
36
+ * ```
37
+ */
38
+ const SecretManager = exports.SecretManager = {
39
+ /** Singleton client instance */
40
+ client: undefined,
41
+ /** Configuration options */
42
+ options: undefined,
43
+ /** Cache of loaded secrets */
44
+ secretCache: new Map(),
45
+ /** Temporary files created by Secret Manager */
46
+ tempFiles: [],
47
+ /**
48
+ * Initialize the Secret Manager
49
+ * @param config - Secret Manager configuration options
50
+ * @returns Promise with load results
51
+ */
52
+ async init(config = {}) {
53
+ (0, _report.reportDebug)({
54
+ namespace,
55
+ message: 'Initializing Secret Manager'
56
+ });
57
+
58
+ // Set default options
59
+ this.options = {
60
+ enabled: process.env.NODE_ENV === 'production',
61
+ projectId: process.env.GCP_PROJECT_ID,
62
+ cache: true,
63
+ fallbackToEnv: true,
64
+ tempDir: _os.default.tmpdir(),
65
+ ...config
66
+ };
67
+
68
+ // Skip if disabled
69
+ if (!this.options.enabled) {
70
+ (0, _report.reportInfo)({
71
+ message: 'Secret Manager disabled - using environment variables',
72
+ data: {
73
+ nodeEnv: process.env.NODE_ENV
74
+ }
75
+ });
76
+ return {
77
+ loaded: 0,
78
+ failed: 0,
79
+ fallback: 0,
80
+ details: []
81
+ };
82
+ }
83
+
84
+ // Validate configuration
85
+ if (!this.options.projectId) {
86
+ throw new _EngineError.EngineError({
87
+ message: 'GCP_PROJECT_ID is required when Secret Manager is enabled'
88
+ });
89
+ }
90
+
91
+ // Create client
92
+ this.client = new _secretManager.SecretManagerServiceClient();
93
+
94
+ // Register for shutdown
95
+ _LifecycleController.LifecycleController.register({
96
+ shutdown: () => this.shutdown()
97
+ });
98
+
99
+ // Load secrets
100
+ const result = await this.loadSecrets(this.options);
101
+ (0, _report.reportInfo)({
102
+ message: 'Secret Manager initialized',
103
+ data: {
104
+ loaded: result.loaded,
105
+ failed: result.failed,
106
+ fallback: result.fallback
107
+ }
108
+ });
109
+ return result;
110
+ },
111
+ /**
112
+ * Load secrets from Secret Manager
113
+ * @private
114
+ */
115
+ async loadSecrets(config) {
116
+ const result = {
117
+ loaded: 0,
118
+ failed: 0,
119
+ fallback: 0,
120
+ details: []
121
+ };
122
+ if (!config.secrets || config.secrets.length === 0) {
123
+ (0, _report.reportInfo)('No secrets configured to load');
124
+ return result;
125
+ }
126
+
127
+ // Normalize secret configurations
128
+ const secretConfigs = config.secrets.map(this.normalizeSecretConfig);
129
+
130
+ // Load each secret
131
+ for (const secretConfig of secretConfigs) {
132
+ try {
133
+ const loaded = await this.loadSecret(secretConfig, config);
134
+ if (loaded) {
135
+ result.loaded++;
136
+ result.details.push({
137
+ name: loaded.name,
138
+ type: loaded.config.type,
139
+ source: 'secret-manager',
140
+ filePath: loaded.filePath
141
+ });
142
+
143
+ // Cache if enabled
144
+ if (config.cache) {
145
+ this.secretCache.set(loaded.name, loaded);
146
+ }
147
+ }
148
+ } catch (error) {
149
+ (0, _report.reportError)(error);
150
+
151
+ // Try fallback
152
+ if (config.fallbackToEnv && process.env[secretConfig.targetEnvVar || secretConfig.name]) {
153
+ result.fallback++;
154
+ result.details.push({
155
+ name: secretConfig.name,
156
+ type: secretConfig.type,
157
+ source: 'fallback'
158
+ });
159
+ (0, _report.reportInfo)(`Using fallback value for secret: ${secretConfig.name}`);
160
+ } else {
161
+ result.failed++;
162
+ (0, _report.reportError)(new _EngineError.EngineError({
163
+ message: `Failed to load secret: ${secretConfig.name}`,
164
+ data: {
165
+ error: error.message
166
+ }
167
+ }));
168
+ }
169
+ }
170
+ }
171
+ return result;
172
+ },
173
+ /**
174
+ * Load a single secret from Secret Manager
175
+ * @private
176
+ */
177
+ async loadSecret(config, globalConfig) {
178
+ if (!this.client || !globalConfig.projectId) {
179
+ throw new _EngineError.EngineError({
180
+ message: 'Secret Manager not initialized'
181
+ });
182
+ }
183
+
184
+ // Build secret name with prefix (unless it's a common secret)
185
+ const secretName = config.common || !globalConfig.prefix ? config.name : `${globalConfig.prefix}-${config.name}`;
186
+ const version = config.version || 'latest';
187
+ const name = `projects/${globalConfig.projectId}/secrets/${secretName}/versions/${version}`;
188
+ (0, _report.reportDebug)({
189
+ namespace,
190
+ message: `Loading secret: ${secretName}`,
191
+ data: {
192
+ version,
193
+ type: config.type,
194
+ common: config.common
195
+ }
196
+ });
197
+ try {
198
+ // Access the secret
199
+ const [response] = await this.client.accessSecretVersion({
200
+ name
201
+ });
202
+ if (!response.payload?.data) {
203
+ throw new _EngineError.EngineError({
204
+ message: `Secret ${secretName} has no data`
205
+ });
206
+ }
207
+
208
+ // Convert to string
209
+ const secretValue = response.payload.data.toString('utf8');
210
+ const loaded = {
211
+ name: config.name,
212
+ value: secretValue,
213
+ config
214
+ };
215
+
216
+ // Handle based on type
217
+ if (config.type === 'env') {
218
+ // Set environment variable
219
+ const envVarName = config.targetEnvVar || config.name;
220
+ process.env[envVarName] = secretValue;
221
+ (0, _report.reportDebug)({
222
+ namespace,
223
+ message: `Set environment variable: ${envVarName}`
224
+ });
225
+ } else if (config.type === 'file') {
226
+ // Write to temp file
227
+ const filename = config.filename || config.name;
228
+ const filePath = _path.default.join(globalConfig.tempDir, filename);
229
+ await _promises.default.writeFile(filePath, secretValue, {
230
+ mode: config.mode || 0o600
231
+ });
232
+ loaded.filePath = filePath;
233
+ this.tempFiles.push(filePath);
234
+
235
+ // Update environment variable to point to file
236
+ const envVarName = config.targetEnvVar || `${config.name}_PATH`;
237
+ process.env[envVarName] = filePath;
238
+ (0, _report.reportDebug)({
239
+ namespace,
240
+ message: `Wrote secret to file: ${filePath}`,
241
+ data: {
242
+ envVar: envVarName
243
+ }
244
+ });
245
+ }
246
+ return loaded;
247
+ } catch (error) {
248
+ if (error.code === 5) {
249
+ // NOT_FOUND error
250
+ (0, _report.reportInfo)(`Secret not found in Secret Manager: ${secretName}`);
251
+ }
252
+ throw error;
253
+ }
254
+ },
255
+ /**
256
+ * Normalize secret configuration
257
+ * @private
258
+ */
259
+ normalizeSecretConfig(input) {
260
+ if (typeof input === 'string') {
261
+ // Simple string becomes an env type secret
262
+ return {
263
+ name: input,
264
+ type: 'env'
265
+ };
266
+ }
267
+ return input;
268
+ },
269
+ /**
270
+ * Get a secret value from cache (if caching is enabled)
271
+ * @param name - Secret name
272
+ * @returns Secret value or undefined
273
+ */
274
+ getSecret(name) {
275
+ const cached = this.secretCache.get(name);
276
+ if (cached) {
277
+ return cached.value;
278
+ }
279
+
280
+ // Fallback to environment variable
281
+ return process.env[name];
282
+ },
283
+ /**
284
+ * Get secret from Secret Manager on-demand (useful for runtime secret rotation)
285
+ * @param name - Secret name
286
+ * @param version - Secret version (default: 'latest')
287
+ * @returns Promise with secret value
288
+ */
289
+ async fetchSecret(name, version = 'latest') {
290
+ if (!this.client || !this.options?.projectId) {
291
+ throw new _EngineError.EngineError({
292
+ message: 'Secret Manager not initialized'
293
+ });
294
+ }
295
+ const secretName = this.options.prefix ? `${this.options.prefix}-${name}` : name;
296
+ const secretPath = `projects/${this.options.projectId}/secrets/${secretName}/versions/${version}`;
297
+ const [response] = await this.client.accessSecretVersion({
298
+ name: secretPath
299
+ });
300
+ if (!response.payload?.data) {
301
+ throw new _EngineError.EngineError({
302
+ message: `Secret ${secretName} has no data`
303
+ });
304
+ }
305
+ return response.payload.data.toString('utf8');
306
+ },
307
+ /**
308
+ * Reload all secrets (useful for secret rotation)
309
+ * @returns Promise with reload results
310
+ */
311
+ async reload() {
312
+ (0, _report.reportInfo)({
313
+ message: 'Reloading secrets from Secret Manager'
314
+ });
315
+ if (!this.options) {
316
+ throw new _EngineError.EngineError({
317
+ message: 'Secret Manager not initialized'
318
+ });
319
+ }
320
+
321
+ // Clear cache
322
+ this.secretCache.clear();
323
+
324
+ // Reload secrets
325
+ return this.loadSecrets(this.options);
326
+ },
327
+ /**
328
+ * Shutdown Secret Manager and cleanup
329
+ * @returns Promise that resolves when cleanup is complete
330
+ */
331
+ async shutdown() {
332
+ (0, _report.reportDebug)({
333
+ namespace,
334
+ message: 'Shutting down Secret Manager'
335
+ });
336
+
337
+ // Delete temporary files
338
+ for (const filePath of this.tempFiles) {
339
+ try {
340
+ await _promises.default.unlink(filePath);
341
+ (0, _report.reportDebug)({
342
+ namespace,
343
+ message: `Deleted temporary file: ${filePath}`
344
+ });
345
+ } catch {
346
+ (0, _report.reportInfo)(`Failed to delete temporary file: ${filePath}`);
347
+ }
348
+ }
349
+ this.tempFiles.length = 0;
350
+ this.secretCache.clear();
351
+
352
+ // Close client
353
+ if (this.client) {
354
+ await this.client.close();
355
+ this.client = undefined;
356
+ }
357
+ this.options = undefined;
358
+ (0, _report.reportDebug)({
359
+ namespace,
360
+ message: 'Secret Manager shut down'
361
+ });
362
+ },
363
+ /**
364
+ * Check if Secret Manager is initialized
365
+ * @returns True if initialized
366
+ */
367
+ isInitialized() {
368
+ return this.client !== undefined;
369
+ },
370
+ /**
371
+ * Get current configuration (without sensitive data)
372
+ * @returns Configuration object or undefined
373
+ */
374
+ getConfig() {
375
+ if (!this.options) return undefined;
376
+ return {
377
+ enabled: this.options.enabled,
378
+ projectId: this.options.projectId,
379
+ prefix: this.options.prefix,
380
+ cache: this.options.cache,
381
+ fallbackToEnv: this.options.fallbackToEnv
382
+ };
383
+ }
384
+ };
385
+ //# sourceMappingURL=SecretManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecretManager.js","names":["_secretManager","require","_promises","_interopRequireDefault","_path","_os","_EngineError","_LifecycleController","_report","namespace","SecretManager","exports","client","undefined","options","secretCache","Map","tempFiles","init","config","reportDebug","message","enabled","process","env","NODE_ENV","projectId","GCP_PROJECT_ID","cache","fallbackToEnv","tempDir","os","tmpdir","reportInfo","data","nodeEnv","loaded","failed","fallback","details","EngineError","SecretManagerServiceClient","LifecycleController","register","shutdown","result","loadSecrets","secrets","length","secretConfigs","map","normalizeSecretConfig","secretConfig","loadSecret","push","name","type","source","filePath","set","error","reportError","targetEnvVar","globalConfig","secretName","common","prefix","version","response","accessSecretVersion","payload","secretValue","toString","value","envVarName","filename","path","join","fs","writeFile","mode","envVar","code","input","getSecret","cached","get","fetchSecret","secretPath","reload","clear","unlink","close","isInitialized","getConfig"],"sources":["../../../src/entities/SecretManager/SecretManager.ts"],"sourcesContent":["import { SecretManagerServiceClient } from '@google-cloud/secret-manager';\nimport fs from 'fs/promises';\nimport path from 'path';\nimport os from 'os';\nimport {\n SecretManagerOptions,\n SecretConfig,\n LoadedSecret,\n SecretLoadResult\n} from './SecretManager.types';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { reportDebug, reportInfo, reportError } from 'utils/report';\n\nconst namespace = 'engine:SecretManager';\n\n/**\n * Generic GCP Secret Manager wrapper for managing application secrets\n * Provides methods for loading secrets at startup, runtime fetching, and cleanup\n * \n * @example\n * ```typescript\n * // Initialize with configuration\n * await SecretManager.init({\n * enabled: true,\n * projectId: 'my-project',\n * prefix: 'my-service',\n * secrets: ['DB_PASSWORD', { name: 'PRIVATE_KEY', type: 'file' }]\n * });\n * \n * // Get a cached secret\n * const password = SecretManager.getSecret('DB_PASSWORD');\n * \n * // Fetch a secret on-demand\n * const apiKey = await SecretManager.fetchSecret('API_KEY');\n * ```\n */\nexport const SecretManager = {\n /** Singleton client instance */\n client: undefined as SecretManagerServiceClient | undefined,\n\n /** Configuration options */\n options: undefined as SecretManagerOptions | undefined,\n\n /** Cache of loaded secrets */\n secretCache: new Map<string, LoadedSecret>(),\n\n /** Temporary files created by Secret Manager */\n tempFiles: [] as string[],\n\n /**\n * Initialize the Secret Manager\n * @param config - Secret Manager configuration options\n * @returns Promise with load results\n */\n async init(config: SecretManagerOptions = {}): Promise<SecretLoadResult> {\n reportDebug({ namespace, message: 'Initializing Secret Manager' });\n\n // Set default options\n this.options = {\n enabled: process.env.NODE_ENV === 'production',\n projectId: process.env.GCP_PROJECT_ID,\n cache: true,\n fallbackToEnv: true,\n tempDir: os.tmpdir(),\n ...config\n };\n\n // Skip if disabled\n if (!this.options.enabled) {\n reportInfo({\n message: 'Secret Manager disabled - using environment variables',\n data: { nodeEnv: process.env.NODE_ENV }\n });\n return {\n loaded: 0,\n failed: 0,\n fallback: 0,\n details: []\n };\n }\n\n // Validate configuration\n if (!this.options.projectId) {\n throw new EngineError({\n message: 'GCP_PROJECT_ID is required when Secret Manager is enabled'\n });\n }\n\n // Create client\n this.client = new SecretManagerServiceClient();\n\n // Register for shutdown\n LifecycleController.register({ shutdown: () => this.shutdown() });\n\n // Load secrets\n const result = await this.loadSecrets(this.options);\n\n reportInfo({\n message: 'Secret Manager initialized',\n data: {\n loaded: result.loaded,\n failed: result.failed,\n fallback: result.fallback\n }\n });\n\n return result;\n },\n\n /**\n * Load secrets from Secret Manager\n * @private\n */\n async loadSecrets(config: SecretManagerOptions): Promise<SecretLoadResult> {\n const result: SecretLoadResult = {\n loaded: 0,\n failed: 0,\n fallback: 0,\n details: []\n };\n\n if (!config.secrets || config.secrets.length === 0) {\n reportInfo('No secrets configured to load');\n return result;\n }\n\n // Normalize secret configurations\n const secretConfigs: SecretConfig[] = config.secrets.map(this.normalizeSecretConfig);\n\n // Load each secret\n for (const secretConfig of secretConfigs) {\n try {\n const loaded = await this.loadSecret(secretConfig, config);\n \n if (loaded) {\n result.loaded++;\n result.details.push({\n name: loaded.name,\n type: loaded.config.type,\n source: 'secret-manager',\n filePath: loaded.filePath\n });\n\n // Cache if enabled\n if (config.cache) {\n this.secretCache.set(loaded.name, loaded);\n }\n }\n } catch (error) {\n reportError(error);\n \n // Try fallback\n if (config.fallbackToEnv && process.env[secretConfig.targetEnvVar || secretConfig.name]) {\n result.fallback++;\n result.details.push({\n name: secretConfig.name,\n type: secretConfig.type,\n source: 'fallback'\n });\n reportInfo(`Using fallback value for secret: ${secretConfig.name}`);\n } else {\n result.failed++;\n reportError(new EngineError({\n message: `Failed to load secret: ${secretConfig.name}`,\n data: { error: (error as Error).message }\n }));\n }\n }\n }\n\n return result;\n },\n\n /**\n * Load a single secret from Secret Manager\n * @private\n */\n async loadSecret(\n config: SecretConfig,\n globalConfig: SecretManagerOptions\n ): Promise<LoadedSecret | null> {\n if (!this.client || !globalConfig.projectId) {\n throw new EngineError({ message: 'Secret Manager not initialized' });\n }\n\n // Build secret name with prefix (unless it's a common secret)\n const secretName = config.common || !globalConfig.prefix\n ? config.name\n : `${globalConfig.prefix}-${config.name}`;\n\n const version = config.version || 'latest';\n const name = `projects/${globalConfig.projectId}/secrets/${secretName}/versions/${version}`;\n\n reportDebug({\n namespace,\n message: `Loading secret: ${secretName}`,\n data: { version, type: config.type, common: config.common }\n });\n\n try {\n // Access the secret\n const [response] = await this.client.accessSecretVersion({ name });\n \n if (!response.payload?.data) {\n throw new EngineError({\n message: `Secret ${secretName} has no data`\n });\n }\n\n // Convert to string\n const secretValue = response.payload.data.toString('utf8');\n\n const loaded: LoadedSecret = {\n name: config.name,\n value: secretValue,\n config\n };\n\n // Handle based on type\n if (config.type === 'env') {\n // Set environment variable\n const envVarName = config.targetEnvVar || config.name;\n process.env[envVarName] = secretValue;\n \n reportDebug({\n namespace,\n message: `Set environment variable: ${envVarName}`\n });\n } else if (config.type === 'file') {\n // Write to temp file\n const filename = config.filename || config.name;\n const filePath = path.join(globalConfig.tempDir!, filename);\n \n await fs.writeFile(filePath, secretValue, {\n mode: config.mode || 0o600\n });\n \n loaded.filePath = filePath;\n this.tempFiles.push(filePath);\n\n // Update environment variable to point to file\n const envVarName = config.targetEnvVar || `${config.name}_PATH`;\n process.env[envVarName] = filePath;\n \n reportDebug({\n namespace,\n message: `Wrote secret to file: ${filePath}`,\n data: { envVar: envVarName }\n });\n }\n\n return loaded;\n } catch (error) {\n if ((error as { code?: number }).code === 5) {\n // NOT_FOUND error\n reportInfo(`Secret not found in Secret Manager: ${secretName}`);\n }\n throw error;\n }\n },\n\n /**\n * Normalize secret configuration\n * @private\n */\n normalizeSecretConfig(input: SecretConfig | string): SecretConfig {\n if (typeof input === 'string') {\n // Simple string becomes an env type secret\n return {\n name: input,\n type: 'env'\n };\n }\n return input;\n },\n\n /**\n * Get a secret value from cache (if caching is enabled)\n * @param name - Secret name\n * @returns Secret value or undefined\n */\n getSecret(name: string): string | undefined {\n const cached = this.secretCache.get(name);\n if (cached) {\n return cached.value;\n }\n \n // Fallback to environment variable\n return process.env[name];\n },\n\n /**\n * Get secret from Secret Manager on-demand (useful for runtime secret rotation)\n * @param name - Secret name\n * @param version - Secret version (default: 'latest')\n * @returns Promise with secret value\n */\n async fetchSecret(\n name: string,\n version: string = 'latest'\n ): Promise<string> {\n if (!this.client || !this.options?.projectId) {\n throw new EngineError({ message: 'Secret Manager not initialized' });\n }\n\n const secretName = this.options.prefix ? `${this.options.prefix}-${name}` : name;\n const secretPath = `projects/${this.options.projectId}/secrets/${secretName}/versions/${version}`;\n\n const [response] = await this.client.accessSecretVersion({ name: secretPath });\n \n if (!response.payload?.data) {\n throw new EngineError({ message: `Secret ${secretName} has no data` });\n }\n\n return response.payload.data.toString('utf8');\n },\n\n /**\n * Reload all secrets (useful for secret rotation)\n * @returns Promise with reload results\n */\n async reload(): Promise<SecretLoadResult> {\n reportInfo({ message: 'Reloading secrets from Secret Manager' });\n \n if (!this.options) {\n throw new EngineError({ message: 'Secret Manager not initialized' });\n }\n\n // Clear cache\n this.secretCache.clear();\n\n // Reload secrets\n return this.loadSecrets(this.options);\n },\n\n /**\n * Shutdown Secret Manager and cleanup\n * @returns Promise that resolves when cleanup is complete\n */\n async shutdown(): Promise<void> {\n reportDebug({ namespace, message: 'Shutting down Secret Manager' });\n\n // Delete temporary files\n for (const filePath of this.tempFiles) {\n try {\n await fs.unlink(filePath);\n reportDebug({\n namespace,\n message: `Deleted temporary file: ${filePath}`\n });\n } catch {\n reportInfo(`Failed to delete temporary file: ${filePath}`);\n }\n }\n\n this.tempFiles.length = 0;\n this.secretCache.clear();\n\n // Close client\n if (this.client) {\n await this.client.close();\n this.client = undefined;\n }\n\n this.options = undefined;\n \n reportDebug({ namespace, message: 'Secret Manager shut down' });\n },\n\n /**\n * Check if Secret Manager is initialized\n * @returns True if initialized\n */\n isInitialized(): boolean {\n return this.client !== undefined;\n },\n\n /**\n * Get current configuration (without sensitive data)\n * @returns Configuration object or undefined\n */\n getConfig(): Partial<SecretManagerOptions> | undefined {\n if (!this.options) return undefined;\n \n return {\n enabled: this.options.enabled,\n projectId: this.options.projectId,\n prefix: this.options.prefix,\n cache: this.options.cache,\n fallbackToEnv: this.options.fallbackToEnv\n };\n }\n};\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Configuration for a single secret to be loaded
3
+ */
4
+ export interface SecretConfig {
5
+ /** Name of the secret in Secret Manager (without prefix) */
6
+ name: string;
7
+ /** Type of secret - 'env' for environment variable, 'file' for file-based secret */
8
+ type: 'env' | 'file';
9
+ /** Target environment variable name (defaults to secret name) */
10
+ targetEnvVar?: string;
11
+ /** For file type: filename to write (optional, uses secret name if not provided) */
12
+ filename?: string;
13
+ /** For file type: file permissions in octal (default: 0o600 for security) */
14
+ mode?: number;
15
+ /** Version of the secret to fetch (default: 'latest') */
16
+ version?: string;
17
+ /** Common secret shared across all services (no prefix) - e.g., PRIVATE_KEY, JWKS */
18
+ common?: boolean;
19
+ }
20
+ /**
21
+ * Options for initializing Secret Manager
22
+ */
23
+ export interface SecretManagerOptions {
24
+ /** Enable Secret Manager (default: true in production, false otherwise) */
25
+ enabled?: boolean;
26
+ /** GCP project ID */
27
+ projectId?: string;
28
+ /** Prefix for secret names (e.g., 'omg-identity-service') */
29
+ prefix?: string;
30
+ /** List of secrets to load */
31
+ secrets?: Array<SecretConfig | string>;
32
+ /** Load all secrets matching the prefix */
33
+ loadAll?: boolean;
34
+ /** Cache secrets in memory after loading */
35
+ cache?: boolean;
36
+ /** Fall back to process.env if secret not found in Secret Manager */
37
+ fallbackToEnv?: boolean;
38
+ /** Directory to write file-based secrets (default: OS temp directory) */
39
+ tempDir?: string;
40
+ }
41
+ /**
42
+ * Internal representation of a loaded secret
43
+ */
44
+ export interface LoadedSecret {
45
+ /** Secret name */
46
+ name: string;
47
+ /** Secret value (string content) */
48
+ value: string;
49
+ /** Configuration used to load this secret */
50
+ config: SecretConfig;
51
+ /** Path to file if written to disk */
52
+ filePath?: string;
53
+ }
54
+ /**
55
+ * Result of secret loading operation
56
+ */
57
+ export interface SecretLoadResult {
58
+ /** Number of secrets successfully loaded */
59
+ loaded: number;
60
+ /** Number of secrets failed to load */
61
+ failed: number;
62
+ /** Number of secrets using fallback values */
63
+ fallback: number;
64
+ /** Details of loaded secrets (without values for security) */
65
+ details: Array<{
66
+ name: string;
67
+ type: 'env' | 'file';
68
+ source: 'secret-manager' | 'fallback';
69
+ filePath?: string;
70
+ }>;
71
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=SecretManager.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecretManager.types.js","names":[],"sources":["../../../src/entities/SecretManager/SecretManager.types.ts"],"sourcesContent":["/**\n * Configuration for a single secret to be loaded\n */\nexport interface SecretConfig {\n /** Name of the secret in Secret Manager (without prefix) */\n name: string;\n /** Type of secret - 'env' for environment variable, 'file' for file-based secret */\n type: 'env' | 'file';\n /** Target environment variable name (defaults to secret name) */\n targetEnvVar?: string;\n /** For file type: filename to write (optional, uses secret name if not provided) */\n filename?: string;\n /** For file type: file permissions in octal (default: 0o600 for security) */\n mode?: number;\n /** Version of the secret to fetch (default: 'latest') */\n version?: string;\n /** Common secret shared across all services (no prefix) - e.g., PRIVATE_KEY, JWKS */\n common?: boolean;\n}\n\n/**\n * Options for initializing Secret Manager\n */\nexport interface SecretManagerOptions {\n /** Enable Secret Manager (default: true in production, false otherwise) */\n enabled?: boolean;\n /** GCP project ID */\n projectId?: string;\n /** Prefix for secret names (e.g., 'omg-identity-service') */\n prefix?: string;\n /** List of secrets to load */\n secrets?: Array<SecretConfig | string>;\n /** Load all secrets matching the prefix */\n loadAll?: boolean;\n /** Cache secrets in memory after loading */\n cache?: boolean;\n /** Fall back to process.env if secret not found in Secret Manager */\n fallbackToEnv?: boolean;\n /** Directory to write file-based secrets (default: OS temp directory) */\n tempDir?: string;\n}\n\n/**\n * Internal representation of a loaded secret\n */\nexport interface LoadedSecret {\n /** Secret name */\n name: string;\n /** Secret value (string content) */\n value: string;\n /** Configuration used to load this secret */\n config: SecretConfig;\n /** Path to file if written to disk */\n filePath?: string;\n}\n\n/**\n * Result of secret loading operation\n */\nexport interface SecretLoadResult {\n /** Number of secrets successfully loaded */\n loaded: number;\n /** Number of secrets failed to load */\n failed: number;\n /** Number of secrets using fallback values */\n fallback: number;\n /** Details of loaded secrets (without values for security) */\n details: Array<{\n name: string;\n type: 'env' | 'file';\n source: 'secret-manager' | 'fallback';\n filePath?: string;\n }>;\n}\n"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ export * from './SecretManager';
2
+ export * from './SecretManager.types';
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _SecretManager = require("./SecretManager");
7
+ Object.keys(_SecretManager).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _SecretManager[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _SecretManager[key];
14
+ }
15
+ });
16
+ });
17
+ var _SecretManager2 = require("./SecretManager.types");
18
+ Object.keys(_SecretManager2).forEach(function (key) {
19
+ if (key === "default" || key === "__esModule") return;
20
+ if (key in exports && exports[key] === _SecretManager2[key]) return;
21
+ Object.defineProperty(exports, key, {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _SecretManager2[key];
25
+ }
26
+ });
27
+ });
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["_SecretManager","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_SecretManager2"],"sources":["../../../src/entities/SecretManager/index.ts"],"sourcesContent":["export * from './SecretManager';\nexport * from './SecretManager.types';\n"],"mappings":";;;;;AAAA,IAAAA,cAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,cAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,cAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,cAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,eAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,eAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,eAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,eAAA,CAAAL,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
@@ -123,12 +123,14 @@ function addModels(models) {
123
123
  sequelizeClient.addHook('afterFind', result => {
124
124
  if (!result) return;
125
125
  const convertToPlain = instance => {
126
- if (!instance || !instance.toJSON) return instance;
127
- const plain = instance.toJSON();
126
+ if (!instance || typeof instance !== 'object') return instance;
127
+ const modelInstance = instance;
128
+ if (!modelInstance.toJSON) return instance;
129
+ const plain = modelInstance.toJSON();
128
130
  // Copy the plain object properties back to the instance
129
131
  // This makes property access work without .toJSON() in compiled code
130
132
  Object.keys(plain).forEach(key => {
131
- instance[key] = plain[key];
133
+ modelInstance[key] = plain[key];
132
134
  });
133
135
  };
134
136
  if (Array.isArray(result)) {
@@ -1 +1 @@
1
- {"version":3,"file":"Sequelize.js","names":["_sequelizeTypescript","require","_Sequelize","_interopRequireDefault","_Sequelize2","_EngineError","_LifecycleController","_report","sequelizeClient","exports","sequelize","Proxy","get","target","property","init","shutdown","addModels","EngineError","message","reportInfo","data","host","process","env","SQL_HOST","database","SQL_DB","user","SQL_USER","port","SQL_PORT","dialect","SQL_TYPE","isUnixSocket","startsWith","createSequelizeClient","NODE_ENV","authenticate","getDialect","err","reportError","error","Error","String","stack","undefined","LifecycleController","register","close","console","models","addHook","result","convertToPlain","instance","toJSON","plain","Object","keys","forEach","key","Array","isArray","sync","Sequelize","storage","logging","validateSequelizeEnvironment","username","dbConfig","poolMax","pool","max","poolMin","min","SQL_PASSWORD"],"sources":["../../../src/entities/Sequelize/Sequelize.ts"],"sourcesContent":["import { Sequelize, ModelCtor } from 'sequelize-typescript';\nimport dbConfig from './Sequelize.config';\nimport { Sequelize as SequelizeInterface } from './Sequelize.types';\nimport { validateSequelizeEnvironment } from './Sequelize.validate';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { reportInfo, reportError } from 'utils/report';\n\nexport let sequelizeClient: undefined | Sequelize;\n\n/**\n * We use a proxy to extend the Sequelize behavior and allow initialization of the client only when needed while keeping the same interface\n */\nexport const sequelize = new Proxy<SequelizeInterface>(\n // Due to how we do the proxying, we are forced to ignore ts-errors, we could never create an object that respects the interface properly\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n {},\n {\n get: function (target, property): unknown {\n if (property === 'init') return init;\n if (property === 'shutdown') return shutdown;\n if (property === 'addModels') return addModels;\n // Create the sequelize client if it does not exist\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n // Call the function on the sequelize client\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n return sequelizeClient[property] as unknown;\n }\n }\n);\n\n/** On init create client and connect */\nexport async function init(): Promise<void> {\n // Ignore if already initialized\n if (sequelizeClient) return;\n \n reportInfo({\n message: 'Initializing Sequelize client',\n data: {\n host: process.env.SQL_HOST,\n database: process.env.SQL_DB,\n user: process.env.SQL_USER,\n port: process.env.SQL_PORT,\n dialect: process.env.SQL_TYPE || 'postgres',\n isUnixSocket: process.env.SQL_HOST?.startsWith('/')\n }\n });\n \n sequelizeClient = createSequelizeClient();\n \n // In test environment, authentication happens automatically with SQLite\n // For other environments, authenticate and log the result\n if (process.env.NODE_ENV !== 'test') {\n reportInfo({\n message: 'Starting database authentication'\n });\n\n try {\n await sequelizeClient.authenticate();\n reportInfo({ \n message: 'Connected to database successfully',\n data: {\n host: process.env.SQL_HOST,\n database: process.env.SQL_DB,\n dialect: sequelizeClient?.getDialect()\n }\n });\n } catch (err) {\n reportError({\n message: 'Failed to connect to database',\n data: {\n error: err instanceof Error ? err.message : String(err),\n stack: err instanceof Error ? err.stack : undefined,\n host: process.env.SQL_HOST,\n database: process.env.SQL_DB,\n user: process.env.SQL_USER,\n port: process.env.SQL_PORT\n }\n });\n if (err instanceof Error) {\n reportError(err);\n }\n throw err;\n }\n }\n \n LifecycleController.register(sequelize);\n}\n\n/** On shutdown close connection and clear client */\nexport async function shutdown(): Promise<void> {\n if (sequelizeClient) {\n try {\n // For SQLite, just close the client (closing connection manager first causes SQLITE_MISUSE)\n // For other dialects, sequelize.close() handles everything properly\n await sequelizeClient.close();\n } catch (error) {\n // Ignore errors during shutdown\n if (process.env.NODE_ENV !== 'test') {\n console.error('Error closing sequelize client:', error);\n }\n }\n }\n sequelizeClient = undefined;\n}\n\nexport function addModels(models: Array<ModelCtor>): void {\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n sequelizeClient.addModels(models);\n \n // Override toJSON behavior globally to ensure consistency between dev and prod\n // In dev (ts-node), property access works directly on instances\n // In prod (compiled), we need explicit serialization\n // This hook intercepts all afterFind results and converts them to plain objects\n sequelizeClient.addHook('afterFind', (result) => {\n if (!result) return;\n \n const convertToPlain = (instance: any) => {\n if (!instance || !instance.toJSON) return instance;\n const plain = instance.toJSON();\n // Copy the plain object properties back to the instance\n // This makes property access work without .toJSON() in compiled code\n Object.keys(plain).forEach(key => {\n instance[key] = plain[key];\n });\n };\n \n if (Array.isArray(result)) {\n result.forEach(convertToPlain);\n } else {\n convertToPlain(result);\n }\n });\n \n sequelizeClient.sync();\n}\n\n/** Create Sequelize client */\nexport function createSequelizeClient(): Sequelize {\n // Use in-memory SQLite for test environment to avoid real database connections\n if (process.env.NODE_ENV === 'test') {\n return new Sequelize({\n dialect: 'sqlite',\n storage: ':memory:',\n logging: false\n });\n }\n \n // Throw an error if there is no host initial\n validateSequelizeEnvironment();\n \n reportInfo({\n message: 'Creating Sequelize client with config',\n data: {\n database: process.env.SQL_DB,\n username: process.env.SQL_USER,\n host: process.env.SQL_HOST,\n port: dbConfig.port,\n dialect: dbConfig.dialect,\n isUnixSocket: process.env.SQL_HOST?.startsWith('/'),\n poolMax: dbConfig.pool?.max,\n poolMin: dbConfig.pool?.min\n }\n });\n \n return new Sequelize(\n process.env.SQL_DB as string,\n process.env.SQL_USER as string,\n process.env.SQL_PASSWORD as string,\n dbConfig\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"Sequelize.js","names":["_sequelizeTypescript","require","_Sequelize","_interopRequireDefault","_Sequelize2","_EngineError","_LifecycleController","_report","sequelizeClient","exports","sequelize","Proxy","get","target","property","init","shutdown","addModels","EngineError","message","reportInfo","data","host","process","env","SQL_HOST","database","SQL_DB","user","SQL_USER","port","SQL_PORT","dialect","SQL_TYPE","isUnixSocket","startsWith","createSequelizeClient","NODE_ENV","authenticate","getDialect","err","reportError","error","Error","String","stack","undefined","LifecycleController","register","close","console","models","addHook","result","convertToPlain","instance","modelInstance","toJSON","plain","Object","keys","forEach","key","Array","isArray","sync","Sequelize","storage","logging","validateSequelizeEnvironment","username","dbConfig","poolMax","pool","max","poolMin","min","SQL_PASSWORD"],"sources":["../../../src/entities/Sequelize/Sequelize.ts"],"sourcesContent":["import { Sequelize, ModelCtor } from 'sequelize-typescript';\nimport dbConfig from './Sequelize.config';\nimport { Sequelize as SequelizeInterface } from './Sequelize.types';\nimport { validateSequelizeEnvironment } from './Sequelize.validate';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { reportInfo, reportError } from 'utils/report';\n\nexport let sequelizeClient: undefined | Sequelize;\n\n/**\n * We use a proxy to extend the Sequelize behavior and allow initialization of the client only when needed while keeping the same interface\n */\nexport const sequelize = new Proxy<SequelizeInterface>(\n // Due to how we do the proxying, we are forced to ignore ts-errors, we could never create an object that respects the interface properly\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n {},\n {\n get: function (target, property): unknown {\n if (property === 'init') return init;\n if (property === 'shutdown') return shutdown;\n if (property === 'addModels') return addModels;\n // Create the sequelize client if it does not exist\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n // Call the function on the sequelize client\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n return sequelizeClient[property] as unknown;\n }\n }\n);\n\n/** On init create client and connect */\nexport async function init(): Promise<void> {\n // Ignore if already initialized\n if (sequelizeClient) return;\n \n reportInfo({\n message: 'Initializing Sequelize client',\n data: {\n host: process.env.SQL_HOST,\n database: process.env.SQL_DB,\n user: process.env.SQL_USER,\n port: process.env.SQL_PORT,\n dialect: process.env.SQL_TYPE || 'postgres',\n isUnixSocket: process.env.SQL_HOST?.startsWith('/')\n }\n });\n \n sequelizeClient = createSequelizeClient();\n \n // In test environment, authentication happens automatically with SQLite\n // For other environments, authenticate and log the result\n if (process.env.NODE_ENV !== 'test') {\n reportInfo({\n message: 'Starting database authentication'\n });\n\n try {\n await sequelizeClient.authenticate();\n reportInfo({ \n message: 'Connected to database successfully',\n data: {\n host: process.env.SQL_HOST,\n database: process.env.SQL_DB,\n dialect: sequelizeClient?.getDialect()\n }\n });\n } catch (err) {\n reportError({\n message: 'Failed to connect to database',\n data: {\n error: err instanceof Error ? err.message : String(err),\n stack: err instanceof Error ? err.stack : undefined,\n host: process.env.SQL_HOST,\n database: process.env.SQL_DB,\n user: process.env.SQL_USER,\n port: process.env.SQL_PORT\n }\n });\n if (err instanceof Error) {\n reportError(err);\n }\n throw err;\n }\n }\n \n LifecycleController.register(sequelize);\n}\n\n/** On shutdown close connection and clear client */\nexport async function shutdown(): Promise<void> {\n if (sequelizeClient) {\n try {\n // For SQLite, just close the client (closing connection manager first causes SQLITE_MISUSE)\n // For other dialects, sequelize.close() handles everything properly\n await sequelizeClient.close();\n } catch (error) {\n // Ignore errors during shutdown\n if (process.env.NODE_ENV !== 'test') {\n console.error('Error closing sequelize client:', error);\n }\n }\n }\n sequelizeClient = undefined;\n}\n\nexport function addModels(models: Array<ModelCtor>): void {\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n sequelizeClient.addModels(models);\n \n // Override toJSON behavior globally to ensure consistency between dev and prod\n // In dev (ts-node), property access works directly on instances\n // In prod (compiled), we need explicit serialization\n // This hook intercepts all afterFind results and converts them to plain objects\n sequelizeClient.addHook('afterFind', (result) => {\n if (!result) return;\n \n const convertToPlain = (instance: unknown) => {\n if (!instance || typeof instance !== 'object') return instance;\n const modelInstance = instance as { toJSON?: () => Record<string, unknown> } & Record<string, unknown>;\n if (!modelInstance.toJSON) return instance;\n const plain = modelInstance.toJSON();\n // Copy the plain object properties back to the instance\n // This makes property access work without .toJSON() in compiled code\n Object.keys(plain).forEach(key => {\n modelInstance[key] = plain[key];\n });\n };\n \n if (Array.isArray(result)) {\n result.forEach(convertToPlain);\n } else {\n convertToPlain(result);\n }\n });\n \n sequelizeClient.sync();\n}\n\n/** Create Sequelize client */\nexport function createSequelizeClient(): Sequelize {\n // Use in-memory SQLite for test environment to avoid real database connections\n if (process.env.NODE_ENV === 'test') {\n return new Sequelize({\n dialect: 'sqlite',\n storage: ':memory:',\n logging: false\n });\n }\n \n // Throw an error if there is no host initial\n validateSequelizeEnvironment();\n \n reportInfo({\n message: 'Creating Sequelize client with config',\n data: {\n database: process.env.SQL_DB,\n username: process.env.SQL_USER,\n host: process.env.SQL_HOST,\n port: dbConfig.port,\n dialect: dbConfig.dialect,\n isUnixSocket: process.env.SQL_HOST?.startsWith('/'),\n poolMax: dbConfig.pool?.max,\n poolMin: dbConfig.pool?.min\n }\n });\n \n return new Sequelize(\n process.env.SQL_DB as string,\n process.env.SQL_USER as string,\n process.env.SQL_PASSWORD as string,\n dbConfig\n );\n}\n"],"mappings":"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","ignoreList":[]}
@@ -28,6 +28,8 @@ export declare class Server {
28
28
  private cron?;
29
29
  /** Global auth related configuration */
30
30
  private auth;
31
+ /** Secret Manager configuration */
32
+ private secretManagerConfig?;
31
33
  /** WebSocket server instance, if configured */
32
34
  private wss?;
33
35
  /** Abort controller that handles signals for the server */