@lenne.tech/nest-server 10.7.0 → 10.8.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "10.7.0",
3
+ "version": "10.8.0",
4
4
  "description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
5
5
  "keywords": [
6
6
  "node",
@@ -67,14 +67,14 @@
67
67
  "@lenne.tech/mongoose-gridfs": "1.4.2",
68
68
  "@lenne.tech/multer-gridfs-storage": "5.0.6",
69
69
  "@nestjs/apollo": "12.2.2",
70
- "@nestjs/common": "10.4.13",
71
- "@nestjs/core": "10.4.13",
70
+ "@nestjs/common": "10.4.15",
71
+ "@nestjs/core": "10.4.15",
72
72
  "@nestjs/graphql": "12.2.2",
73
73
  "@nestjs/jwt": "10.2.0",
74
74
  "@nestjs/mongoose": "10.1.0",
75
75
  "@nestjs/passport": "10.0.3",
76
- "@nestjs/platform-express": "10.4.13",
77
- "@nestjs/schedule": "4.1.1",
76
+ "@nestjs/platform-express": "10.4.15",
77
+ "@nestjs/schedule": "4.1.2",
78
78
  "@nestjs/terminus": "10.2.3",
79
79
  "apollo-server-core": "3.13.0",
80
80
  "apollo-server-express": "3.13.0",
@@ -83,6 +83,7 @@
83
83
  "class-validator": "0.14.1",
84
84
  "compression": "1.7.5",
85
85
  "cookie-parser": "1.4.7",
86
+ "dotenv": "16.4.7",
86
87
  "ejs": "3.1.10",
87
88
  "graphql": "16.9.0",
88
89
  "graphql-query-complexity": "1.0.0",
@@ -110,11 +111,11 @@
110
111
  "@babel/plugin-proposal-private-methods": "7.18.6",
111
112
  "@compodoc/compodoc": "1.1.26",
112
113
  "@lenne.tech/eslint-config-ts": "0.0.16",
113
- "@nestjs/cli": "10.4.8",
114
+ "@nestjs/cli": "10.4.9",
114
115
  "@nestjs/schematics": "10.2.3",
115
- "@nestjs/testing": "10.4.13",
116
+ "@nestjs/testing": "10.4.15",
116
117
  "@swc/cli": "0.5.2",
117
- "@swc/core": "1.10.0",
118
+ "@swc/core": "1.10.1",
118
119
  "@swc/jest": "0.2.37",
119
120
  "@types/compression": "1.7.5",
120
121
  "@types/cookie-parser": "1.4.8",
package/src/config.env.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  import { CronExpression } from '@nestjs/schedule';
2
+ import * as dotenv from 'dotenv';
2
3
  import { join } from 'path';
3
4
 
4
- import { merge } from './core/common/helpers/config.helper';
5
+ import { getEnvironmentConfig } from './core/common/helpers/config.helper';
5
6
  import { IServerOptions } from './core/common/interfaces/server-options.interface';
6
7
 
7
8
  /**
8
9
  * Configuration for the different environments
9
10
  */
11
+ dotenv.config();
10
12
  const config: { [env: string]: IServerOptions } = {
11
13
  // ===========================================================================
12
14
  // Development environment
@@ -330,47 +332,6 @@ const config: { [env: string]: IServerOptions } = {
330
332
  };
331
333
 
332
334
  /**
333
- * Environment specific config
334
- *
335
- * default: local
335
+ * Export config merged with other configs and environment variables as default
336
336
  */
337
- const env = process.env['NODE' + '_ENV'] || 'local';
338
- const envConfig = config[env] || config.local;
339
- console.info(`Configured for: ${envConfig.env}${env !== envConfig.env ? ` (requested: ${env})` : ''}`);
340
- // Merge with localConfig (e.g. config.json)
341
- if (envConfig.loadLocalConfig) {
342
- let localConfig;
343
- if (typeof envConfig.loadLocalConfig === 'string') {
344
- import(envConfig.loadLocalConfig)
345
- .then((loadedConfig) => {
346
- localConfig = loadedConfig.default || loadedConfig;
347
- merge(envConfig, localConfig);
348
- })
349
- .catch(() => {
350
- console.info(`Configuration ${envConfig.loadLocalConfig} not found!`);
351
- });
352
- } else {
353
- // get config from src directory
354
- import(join(__dirname, 'config.json'))
355
- .then((loadedConfig) => {
356
- localConfig = loadedConfig.default || loadedConfig;
357
- merge(envConfig, localConfig);
358
- })
359
- .catch(() => {
360
- // if not found try to find in project directory
361
- import(join(__dirname, '..', 'config.json'))
362
- .then((loadedConfig) => {
363
- localConfig = loadedConfig.default || loadedConfig;
364
- merge(envConfig, localConfig);
365
- })
366
- .catch(() => {
367
- console.info('No local config.json found!');
368
- });
369
- });
370
- }
371
- }
372
-
373
- /**
374
- * Export envConfig as default
375
- */
376
- export default envConfig;
337
+ export default getEnvironmentConfig({ config });
@@ -1,3 +1,6 @@
1
+ import * as dotenv from 'dotenv';
2
+ import { join } from 'path';
3
+
1
4
  import _ = require('lodash');
2
5
 
3
6
  /**
@@ -46,3 +49,128 @@ export function merge(obj: Record<string, any>, ...sources: any[]): any {
46
49
  }
47
50
  });
48
51
  }
52
+
53
+ /**
54
+ * Get environment configuration (deeply merged into config object set via options)
55
+ *
56
+ * The configuration is extended via deep merge in the following order:
57
+ * 1. config[env] (if set)
58
+ * 2.
59
+ *
60
+ * @param options options for processing
61
+ * @param options.config config object with different environments as main keys (see config.env.ts) to merge environment configurations into (default: {})
62
+ * @param options.defaultEnv default environment to use if no NODE_ENV is set (default: 'local')
63
+ */
64
+ export function getEnvironmentConfig(options: { config?: Record<string, any>; defaultEnv?: string }) {
65
+ const { config, defaultEnv } = {
66
+ config: {},
67
+ defaultEnv: 'local',
68
+ ...options,
69
+ };
70
+
71
+ dotenv.config();
72
+ const env = process.env['NODE' + '_ENV'] || defaultEnv;
73
+ const envConfig = config[env] || config.local || {};
74
+
75
+ // Merge with localConfig (e.g. config.json)
76
+ if (envConfig.loadLocalConfig) {
77
+ let localConfig: Record<string, any>;
78
+ if (typeof envConfig.loadLocalConfig === 'string') {
79
+ import(envConfig.loadLocalConfig)
80
+ .then((loadedConfig) => {
81
+ localConfig = loadedConfig.default || loadedConfig;
82
+ merge(envConfig, localConfig);
83
+ })
84
+ .catch(() => {
85
+ console.info(`Configuration ${envConfig.loadLocalConfig} not found!`);
86
+ });
87
+ } else {
88
+ // get config from src directory
89
+ import(join(__dirname, 'config.json'))
90
+ .then((loadedConfig) => {
91
+ localConfig = loadedConfig.default || loadedConfig;
92
+ merge(envConfig, localConfig);
93
+ })
94
+ .catch(() => {
95
+ // if not found try to find in project directory
96
+ import(join(__dirname, '..', 'config.json'))
97
+ .then((loadedConfig) => {
98
+ localConfig = loadedConfig.default || loadedConfig;
99
+ merge(envConfig, localConfig);
100
+ })
101
+ .catch(() => {
102
+ console.info('No local config.json found!');
103
+ });
104
+ });
105
+ }
106
+ }
107
+
108
+ // .env handling via dotenv
109
+ if (process.env['NEST_SERVER_CONFIG']) {
110
+ try {
111
+ const dotEnvConfig = JSON.parse(process.env['NEST_SERVER_CONFIG']);
112
+ if (dotEnvConfig && Object.keys(dotEnvConfig).length > 0) {
113
+ merge(envConfig, dotEnvConfig);
114
+ console.info('NEST_SERVER_CONFIG used from .env');
115
+ }
116
+ } catch (e) {
117
+ console.error('Error parsing NEST_SERVER_CONFIG from .env: ', e);
118
+ console.error(
119
+ 'Maybe the JSON is invalid? Please check the value of NEST_SERVER_CONFIG in .env file (e.g. via https://jsonlint.com/)',
120
+ );
121
+ }
122
+ }
123
+
124
+ // Merge with environment variables
125
+ const environmentObject = getEnvironmentObject();
126
+ const environmentObjectKeyCount = Object.keys(environmentObject).length;
127
+ if (environmentObjectKeyCount > 0) {
128
+ merge(envConfig, environmentObject);
129
+ console.info(
130
+ `Environment object from the environment integrated into the configuration with ${environmentObjectKeyCount} keys`,
131
+ );
132
+ }
133
+
134
+ console.info(`Configured for: ${envConfig.env}${env !== envConfig.env ? ` (requested: ${env})` : ''}`);
135
+ return envConfig;
136
+ }
137
+
138
+ /**
139
+ * Get environment object from environment variables
140
+ */
141
+ export function getEnvironmentObject(options?: { prefix?: string; processEnv?: Record<string, number | string> }) {
142
+ const config = {
143
+ prefix: 'NSC__',
144
+ processEnv: process.env,
145
+ ...options,
146
+ };
147
+ const output = {};
148
+
149
+ Object.entries(config.processEnv)
150
+ .filter(([key]) => key.startsWith(config.prefix))
151
+ .forEach(([key, value]) => {
152
+ // Remove prefix from key
153
+ const adjustedKey = key.slice(config.prefix?.length || 0);
154
+
155
+ // Convert key to path
156
+ const path = adjustedKey.split('__').map(part =>
157
+ part
158
+ .split('_')
159
+ .map((s, i) => (i === 0 ? s.toLowerCase() : s[0].toUpperCase() + s.slice(1).toLowerCase()))
160
+ .join(''),
161
+ );
162
+
163
+ // Set value in output object
164
+ let current = output;
165
+ for (let i = 0; i < path.length; i++) {
166
+ const segment = path[i];
167
+ if (i === path.length - 1) {
168
+ current[segment] = value;
169
+ } else {
170
+ current = current[segment] = current[segment] || {};
171
+ }
172
+ }
173
+ });
174
+
175
+ return output;
176
+ }
@@ -91,7 +91,7 @@ export interface ServiceOptions {
91
91
  select?: Record<string, boolean | number | object> | string | string[];
92
92
 
93
93
  // Add updateBy and/or createBy user ID into input after check
94
- // If falsy: input data will not be changed
95
- // If truly (default): updatedBy and/or createdBy (when create mode is activated) will be set if current user is available
94
+ // If falsy (default): input data will not be changed
95
+ // If truly: updatedBy and/or createdBy (when create mode is activated) will be set if current user is available
96
96
  setCreateOrUpdateUserId?: boolean;
97
97
  }
@@ -96,7 +96,7 @@ export abstract class ModuleService<T extends CoreModel = any> {
96
96
  prepareOutput: {},
97
97
  processFieldSelection: {},
98
98
  pubSub: true,
99
- setCreateOrUpdateUserId: true,
99
+ setCreateOrUpdateUserId: false,
100
100
  ...(options?.serviceOptions || {}),
101
101
  };
102
102