From af63c184a5269fc3e22af6ba391cdd178099aad8 Mon Sep 17 00:00:00 2001 From: Igor Suvorov Date: Sun, 14 Jan 2024 23:14:38 +0300 Subject: [PATCH] feat(config): improve ConfigService --- libs/auth/package.json | 2 - libs/auth/src/AuthController.ts | 2 +- libs/config/src/ConfigModule.ts | 45 +++++++++++++++++++++ libs/config/src/ConfigService.ts | 15 +++++++ libs/config/src/config.ts | 45 --------------------- libs/config/src/getConfig.ts | 21 ++++++++++ libs/config/src/index.ts | 10 ++++- libs/config/src/loadConfigEnvs.ts | 19 +++++++++ libs/config/src/types.ts | 1 + libs/upload/package.json | 4 +- libs/upload/src/UploadService.ts | 2 +- pnpm-lock.yaml | 65 ++++++++----------------------- 12 files changed, 131 insertions(+), 100 deletions(-) create mode 100644 libs/config/src/ConfigModule.ts create mode 100644 libs/config/src/ConfigService.ts delete mode 100644 libs/config/src/config.ts create mode 100644 libs/config/src/getConfig.ts create mode 100644 libs/config/src/loadConfigEnvs.ts create mode 100644 libs/config/src/types.ts diff --git a/libs/auth/package.json b/libs/auth/package.json index 9bdbfa614..25de0c354 100644 --- a/libs/auth/package.json +++ b/libs/auth/package.json @@ -30,7 +30,6 @@ "@mikro-orm/nestjs": "^5.2.3", "@nestjs-modules/mailer": "^1.10.3", "@nestjs/common": "^10.3.0", - "@nestjs/config": "^3.0.0", "@nestjs/core": "^10.3.0", "@nestlib/config": "workspace:^", "@types/express": "^4.17.17", @@ -43,7 +42,6 @@ "@mikro-orm/nestjs": "^5.2.2", "@nestjs-modules/mailer": "^1.9.1", "@nestjs/common": "*", - "@nestjs/config": "*", "@nestjs/core": "*", "@nestlib/config": "*" }, diff --git a/libs/auth/src/AuthController.ts b/libs/auth/src/AuthController.ts index 892d6e2e1..b286ac172 100644 --- a/libs/auth/src/AuthController.ts +++ b/libs/auth/src/AuthController.ts @@ -15,8 +15,8 @@ import { UsePipes, ValidationPipe, } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; import { MailerService } from '@nestjs-modules/mailer'; +import { ConfigService } from '@nestlib/config'; import { ErrorInterceptor, ResponseInterceptor } from '@nestlib/interceptors'; import { AuthRole } from './AuthDecorator'; diff --git a/libs/config/src/ConfigModule.ts b/libs/config/src/ConfigModule.ts new file mode 100644 index 000000000..b39e183c0 --- /dev/null +++ b/libs/config/src/ConfigModule.ts @@ -0,0 +1,45 @@ +import { DynamicModule, Module } from '@nestjs/common'; +import { + ConfigModule as NestConfigModule, + ConfigService as NestConfigService, +} from '@nestjs/config'; + +// import { ConfigModule } from '@nestlib/config'; +import { ConfigService } from './ConfigService'; +import { loadConfigEnvs } from './loadConfigEnvs'; + +@Module({ + // import: [], + // controllers: [AuthController], + // providers: [CryptoService, AuthOtpService, AuthService], + // exports: [ConfigService], +}) +export class ConfigModule { + static forRoot(): DynamicModule { + const rootDir = process.cwd(); + const envFiles = ['.env', '../.env', '../../.env'].map((f) => `${rootDir}/${f}`); + const configEnvs = [ + '.env.js', + '.env.json', + '../.env.js', + '../.env.json', + '../../.env.js', + '../../.env.json', + ].map((f) => `${rootDir}/${f}`); + // console.log('[CnfModule]', { envFiles, configEnvs }); + return { + imports: [ + NestConfigModule.forRoot({ envFilePath: envFiles }), + NestConfigModule.forRoot(loadConfigEnvs(['process.env.ENV_JSON', ...configEnvs])), + // ConfigModule.forRoot(loadConfigEnvs(['process.env.ENV_JSON', ...configEnvs])), + ], + module: ConfigModule, + // controllers: [AuthController], + providers: [ConfigService, NestConfigService], + exports: [ConfigService, NestConfigService], + }; + } + static getExports() { + return [ConfigService, NestConfigService]; + } +} diff --git a/libs/config/src/ConfigService.ts b/libs/config/src/ConfigService.ts new file mode 100644 index 000000000..716c74722 --- /dev/null +++ b/libs/config/src/ConfigService.ts @@ -0,0 +1,15 @@ +import { Injectable } from '@nestjs/common'; +import { ConfigService as NestConfigService } from '@nestjs/config'; + +@Injectable() +export class ConfigService { + constructor(private configService: NestConfigService) {} + get(key: string) { + const res = this.configService.get(key); + // console.log('ConfigService.get', { key }, res); + // console.log('configService', this.configService); + return res; + } +} + +export default ConfigService; diff --git a/libs/config/src/config.ts b/libs/config/src/config.ts deleted file mode 100644 index d76548d3b..000000000 --- a/libs/config/src/config.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* eslint-disable no-unreachable-loop */ -// https://docs.nestjs.com/techniques/configuration - -import { pick } from '@lsk4/algos'; -import { Err } from '@lsk4/err'; -import { - ConfigModule as NestConfigModule, - ConfigService as NestConfigService, -} from '@nestjs/config'; - -import { getEnvConfig } from './getEnvConfig'; - -export const ConfigModule = NestConfigModule; -export const ConfigService = NestConfigService; - -const get = (obj: any, key: string) => (key ? obj[key] : obj); -type PropsFn = (res: Record) => Record; - -export const loadConfigEnvs = (path: string | string[], keyOrFn?: string | PropsFn) => ({ - load: [ - () => { - const config = getEnvConfig(path); - if (typeof keyOrFn === 'function') return keyOrFn(config); - if (!keyOrFn) return config; - return get(config, keyOrFn); - }, - ], - isGlobal: true, - expandVariables: true, -}); - -export const getConfig = (path: string, fields?: string[] | PropsFn) => ({ - imports: [ConfigModule], - useFactory: (configService: NestConfigService) => { - const res = configService.get(path); - if (!res) { - throw new Err(`!config: ${path}`, { path }); - return null; - } - if (Array.isArray(fields)) return pick(res, fields); - if (typeof fields === 'function') return fields(res); - return res; - }, - inject: [ConfigService], -}); diff --git a/libs/config/src/getConfig.ts b/libs/config/src/getConfig.ts new file mode 100644 index 000000000..074b509d0 --- /dev/null +++ b/libs/config/src/getConfig.ts @@ -0,0 +1,21 @@ +import { pick } from '@lsk4/algos'; +import { Err } from '@lsk4/err'; +import { ConfigService as NestConfigService } from '@nestjs/config'; + +// ConfigService +import { ConfigModule } from './ConfigModule'; +import { PropsFn } from './types'; + +export const getConfig = (path: string, fields?: string[] | PropsFn) => ({ + imports: [ConfigModule], + useFactory: (configService: NestConfigService) => { + const res = configService.get(path); + if (!res) throw new Err(`!config: ${path}`, { path }); + if (Array.isArray(fields)) return pick(res, fields); + if (typeof fields === 'function') return fields(res); + return res; + }, + inject: [NestConfigService], +}); + +export default getConfig; diff --git a/libs/config/src/index.ts b/libs/config/src/index.ts index 4a145e004..4f4b88cf5 100644 --- a/libs/config/src/index.ts +++ b/libs/config/src/index.ts @@ -1,2 +1,10 @@ +/* eslint-disable no-unreachable-loop */ +// https://docs.nestjs.com/techniques/configuration + +// export * from './config'; +export * from './ConfigService'; +export * from './ConfigModule'; +export * from './getConfig'; export * from './getEnvConfig'; -export * from './config'; +export * from './loadConfigEnvs'; +export * from './types'; diff --git a/libs/config/src/loadConfigEnvs.ts b/libs/config/src/loadConfigEnvs.ts new file mode 100644 index 000000000..951e66101 --- /dev/null +++ b/libs/config/src/loadConfigEnvs.ts @@ -0,0 +1,19 @@ +import { getEnvConfig } from './getEnvConfig'; +import { PropsFn } from './types'; + +const get = (obj: any, key: string) => (key ? obj[key] : obj); + +export const loadConfigEnvs = (path: string | string[], keyOrFn?: string | PropsFn) => ({ + load: [ + () => { + const config = getEnvConfig(path); + if (typeof keyOrFn === 'function') return keyOrFn(config); + if (!keyOrFn) return config; + return get(config, keyOrFn); + }, + ], + isGlobal: true, + expandVariables: true, +}); + +export default loadConfigEnvs; diff --git a/libs/config/src/types.ts b/libs/config/src/types.ts new file mode 100644 index 000000000..0e9cedaff --- /dev/null +++ b/libs/config/src/types.ts @@ -0,0 +1 @@ +export type PropsFn = (res: Record) => Record; diff --git a/libs/upload/package.json b/libs/upload/package.json index 9470d0292..860161bee 100644 --- a/libs/upload/package.json +++ b/libs/upload/package.json @@ -15,16 +15,16 @@ "@aws-sdk/client-s3": "^3.490.0", "@aws-sdk/s3-request-presigner": "^3.490.0", "@lsk4/err": "^4.5.0", + "@nestlib/config": "workspace:^", "aws-sdk": "^2.1535.0", "fishbird": "^1.1.8" }, "devDependencies": { - "@nestjs/config": "^3.0.0", + "@nestjs/common": "^10.3.0", "nestjs-s3": "^2.0.1" }, "peerDependencies": { "@nestjs/common": "*", - "@nestjs/config": "*", "nestjs-s3": "*" }, "//": "///////////========================/////////========================/////////========================//////////", diff --git a/libs/upload/src/UploadService.ts b/libs/upload/src/UploadService.ts index 5a4b10708..8cc309aa4 100644 --- a/libs/upload/src/UploadService.ts +++ b/libs/upload/src/UploadService.ts @@ -2,7 +2,7 @@ import { GetObjectCommand } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; import { Err } from '@lsk4/err'; import { Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; +import { ConfigService } from '@nestlib/config'; import { S3 } from 'aws-sdk'; import { map } from 'fishbird'; import { InjectS3 } from 'nestjs-s3'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8d832cee6..f4ee3cfc4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -102,10 +102,7 @@ importers: version: 1.10.3(@nestjs/common@10.3.0)(@nestjs/core@10.3.0)(nodemailer@6.9.8) '@nestjs/common': specifier: ^10.3.0 - version: 10.3.0(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) - '@nestjs/config': - specifier: ^3.0.0 - version: 3.1.1(@nestjs/common@10.3.0)(reflect-metadata@0.1.14) + version: 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) '@nestjs/core': specifier: ^10.3.0 version: 10.3.0(@nestjs/common@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1) @@ -324,9 +321,9 @@ importers: '@lsk4/err': specifier: ^4.5.0 version: 4.5.0 - '@nestjs/common': - specifier: '*' - version: 10.3.0(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestlib/config': + specifier: workspace:^ + version: link:../config aws-sdk: specifier: ^2.1535.0 version: 2.1535.0 @@ -334,9 +331,9 @@ importers: specifier: ^1.1.8 version: 1.1.8 devDependencies: - '@nestjs/config': - specifier: ^3.0.0 - version: 3.1.1(@nestjs/common@10.3.0)(reflect-metadata@0.1.14) + '@nestjs/common': + specifier: ^10.3.0 + version: 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) nestjs-s3: specifier: ^2.0.1 version: 2.0.1(@aws-sdk/client-s3@3.490.0)(@nestjs/common@10.3.0)(@nestjs/core@10.3.0) @@ -1625,6 +1622,7 @@ packages: /@lukeed/csprng@1.1.0: resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} engines: {node: '>=8'} + dev: true /@macrobe/tsup@0.0.1(@swc/core@1.3.101)(typescript@5.3.3): resolution: {integrity: sha512-tmrG35OTJ9BDIjOxld4MV0hHdigU50h6U96/eBTlXXrU7cM25xRIKsdGcmJpY0GuxUpb9ORuY0CzL4AdlT8Azg==} @@ -1707,7 +1705,7 @@ packages: '@nestjs/core': ^8.0.0 || ^9.0.0 || ^10.0.0 dependencies: '@mikro-orm/core': 6.0.3 - '@nestjs/common': 10.3.0(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/common': 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) '@nestjs/core': 10.3.0(@nestjs/common@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1) dev: true @@ -1737,7 +1735,7 @@ packages: '@nestjs/core': '>=7.0.9' nodemailer: '>=6.4.6' dependencies: - '@nestjs/common': 10.3.0(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/common': 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) '@nestjs/core': 10.3.0(@nestjs/common@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1) css-inline: 0.11.2 glob: 10.3.10 @@ -1792,26 +1790,6 @@ packages: uid: 2.0.2 dev: true - /@nestjs/common@10.3.0(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1): - resolution: {integrity: sha512-DGv34UHsZBxCM3H5QGE2XE/+oLJzz5+714JQjBhjD9VccFlQs3LRxo/epso4l7nJIiNlZkPyIUC8WzfU/5RTsQ==} - peerDependencies: - class-transformer: '*' - class-validator: '*' - reflect-metadata: ^0.1.12 - rxjs: ^7.1.0 - peerDependenciesMeta: - class-transformer: - optional: true - class-validator: - optional: true - dependencies: - class-validator: 0.14.1 - iterare: 1.2.1 - reflect-metadata: 0.1.14 - rxjs: 7.8.1 - tslib: 2.6.2 - uid: 2.0.2 - /@nestjs/common@10.3.0(reflect-metadata@0.2.1)(rxjs@7.8.1): resolution: {integrity: sha512-DGv34UHsZBxCM3H5QGE2XE/+oLJzz5+714JQjBhjD9VccFlQs3LRxo/epso4l7nJIiNlZkPyIUC8WzfU/5RTsQ==} peerDependencies: @@ -1838,7 +1816,7 @@ packages: '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 reflect-metadata: ^0.1.13 dependencies: - '@nestjs/common': 10.3.0(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/common': 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) dotenv: 16.3.1 dotenv-expand: 10.0.0 lodash: 4.17.21 @@ -1864,7 +1842,7 @@ packages: '@nestjs/websockets': optional: true dependencies: - '@nestjs/common': 10.3.0(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/common': 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) '@nuxtjs/opencollective': 0.3.2 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -5051,7 +5029,7 @@ packages: express-session: ^1.17.1 mongodb: '>= 5.1.0 < 7' dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) express-session: 1.17.3 kruptein: 3.0.6 mongodb: 6.3.0 @@ -5317,18 +5295,6 @@ packages: ms: 2.1.3 dev: true - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: false - /debug@4.3.4(supports-color@5.5.0): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -8181,6 +8147,7 @@ packages: /iterare@1.2.1: resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} engines: {node: '>=6'} + dev: true /iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} @@ -9635,7 +9602,7 @@ packages: '@nestjs/core': '>=6.7.0' dependencies: '@aws-sdk/client-s3': 3.490.0 - '@nestjs/common': 10.3.0(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/common': 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) '@nestjs/core': 10.3.0(@nestjs/common@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1) dev: true @@ -11256,6 +11223,7 @@ packages: /reflect-metadata@0.1.14: resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==} + dev: true /reflect-metadata@0.2.1: resolution: {integrity: sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==} @@ -12538,6 +12506,7 @@ packages: engines: {node: '>=8'} dependencies: '@lukeed/csprng': 1.1.0 + dev: true /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}