@node-c/core 1.0.0-alpha9 → 1.0.0-beta1
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/coverage/src/app.ts.html +349 -0
- package/coverage/src/common/configProvider/configProvider.module.ts.html +160 -0
- package/coverage/src/common/configProvider/configProvider.service.ts.html +658 -0
- package/coverage/src/common/configProvider/index.html +146 -0
- package/coverage/src/common/configProvider/index.ts.html +94 -0
- package/coverage/src/common/definitions/common.constants.ts.html +160 -0
- package/coverage/src/common/definitions/common.errors.ts.html +124 -0
- package/coverage/src/common/definitions/index.html +146 -0
- package/coverage/src/common/definitions/index.ts.html +94 -0
- package/coverage/src/common/utils/index.html +131 -0
- package/coverage/src/common/utils/index.ts.html +88 -0
- package/coverage/src/common/utils/utils.loadDynamicModules.ts.html +265 -0
- package/coverage/src/domain/entityService/domain.entity.service.ts.html +784 -0
- package/coverage/src/domain/entityService/index.html +131 -0
- package/coverage/src/domain/entityService/index.ts.html +91 -0
- package/coverage/src/index.html +116 -0
- package/coverage/src/persistance/entityService/index.html +131 -0
- package/coverage/src/persistance/entityService/index.ts.html +91 -0
- package/coverage/src/persistance/entityService/persistance.entity.service.ts.html +268 -0
- package/dist/app.d.ts +10 -9
- package/dist/app.js +30 -15
- package/dist/app.js.map +1 -1
- package/dist/common/configProvider/configProvider.definitions.d.ts +158 -21
- package/dist/common/configProvider/configProvider.definitions.js +22 -8
- package/dist/common/configProvider/configProvider.definitions.js.map +1 -1
- package/dist/common/configProvider/configProvider.module.js +13 -2
- package/dist/common/configProvider/configProvider.module.js.map +1 -1
- package/dist/common/configProvider/configProvider.service.js +23 -20
- package/dist/common/configProvider/configProvider.service.js.map +1 -1
- package/dist/common/definitions/common.constants.d.ts +2 -1
- package/dist/common/definitions/common.constants.js +1 -0
- package/dist/common/definitions/common.constants.js.map +1 -1
- package/dist/common/logger/index.d.ts +3 -0
- package/dist/common/logger/index.js +20 -0
- package/dist/common/logger/index.js.map +1 -0
- package/dist/common/logger/logger.definitions.d.ts +4 -0
- package/dist/common/logger/logger.definitions.js +3 -0
- package/dist/common/logger/logger.definitions.js.map +1 -0
- package/dist/common/logger/logger.module.d.ts +5 -0
- package/dist/common/logger/logger.module.js +34 -0
- package/dist/common/logger/logger.module.js.map +1 -0
- package/dist/common/logger/logger.service.d.ts +6 -0
- package/dist/common/logger/logger.service.js +56 -0
- package/dist/common/logger/logger.service.js.map +1 -0
- package/dist/common/utils/base64UrlEncode/base64UrlEncode.method.d.ts +1 -0
- package/dist/common/utils/base64UrlEncode/base64UrlEncode.method.js +9 -0
- package/dist/common/utils/base64UrlEncode/base64UrlEncode.method.js.map +1 -0
- package/dist/common/utils/base64UrlEncode/index.d.ts +1 -0
- package/dist/{persistance/entityService → common/utils/base64UrlEncode}/index.js +1 -2
- package/dist/common/utils/base64UrlEncode/index.js.map +1 -0
- package/dist/common/utils/getNested/getNested.definitions.d.ts +4 -0
- package/dist/common/utils/getNested/getNested.definitions.js +3 -0
- package/dist/common/utils/getNested/getNested.definitions.js.map +1 -0
- package/dist/common/utils/getNested/getNested.method.d.ts +6 -0
- package/dist/common/utils/getNested/getNested.method.js +88 -0
- package/dist/common/utils/getNested/getNested.method.js.map +1 -0
- package/dist/common/utils/getNested/index.d.ts +2 -0
- package/dist/common/utils/getNested/index.js +19 -0
- package/dist/common/utils/getNested/index.js.map +1 -0
- package/dist/common/utils/httpRequest/httpRequest.definitions.d.ts +19 -0
- package/dist/common/utils/httpRequest/httpRequest.definitions.js +3 -0
- package/dist/common/utils/httpRequest/httpRequest.definitions.js.map +1 -0
- package/dist/common/utils/httpRequest/httpRequest.method.d.ts +2 -0
- package/dist/common/utils/httpRequest/httpRequest.method.js +56 -0
- package/dist/common/utils/httpRequest/httpRequest.method.js.map +1 -0
- package/dist/common/utils/httpRequest/index.d.ts +2 -0
- package/dist/common/utils/httpRequest/index.js +19 -0
- package/dist/common/utils/httpRequest/index.js.map +1 -0
- package/dist/common/utils/index.d.ts +5 -1
- package/dist/common/utils/index.js +5 -1
- package/dist/common/utils/index.js.map +1 -1
- package/dist/common/utils/loadDynamicModules/index.d.ts +1 -0
- package/dist/common/utils/loadDynamicModules/index.js +18 -0
- package/dist/common/utils/loadDynamicModules/index.js.map +1 -0
- package/dist/common/utils/{utils.loadDynamicModules.d.ts → loadDynamicModules/utils.loadDynamicModules.d.ts} +1 -1
- package/dist/common/utils/loadDynamicModules/utils.loadDynamicModules.js.map +1 -0
- package/dist/common/utils/setNested/index.d.ts +2 -0
- package/dist/common/utils/setNested/index.js +19 -0
- package/dist/common/utils/setNested/index.js.map +1 -0
- package/dist/common/utils/setNested/setNested.definitions.d.ts +4 -0
- package/dist/common/utils/setNested/setNested.definitions.js +3 -0
- package/dist/common/utils/setNested/setNested.definitions.js.map +1 -0
- package/dist/common/utils/setNested/setNested.method.d.ts +2 -0
- package/dist/common/utils/setNested/setNested.method.js +70 -0
- package/dist/common/utils/setNested/setNested.method.js.map +1 -0
- package/dist/data/entityService/data.entity.service.d.ts +19 -0
- package/dist/data/entityService/data.entity.service.definitions.d.ts +117 -0
- package/dist/data/entityService/data.entity.service.definitions.js +28 -0
- package/dist/data/entityService/data.entity.service.definitions.js.map +1 -0
- package/dist/{persistance/entityService/persistance.entity.service.js → data/entityService/data.entity.service.js} +42 -9
- package/dist/data/entityService/data.entity.service.js.map +1 -0
- package/dist/data/entityService/index.d.ts +2 -0
- package/dist/data/entityService/index.js +19 -0
- package/dist/data/entityService/index.js.map +1 -0
- package/dist/domain/entityService/domain.entity.service.d.ts +30 -13
- package/dist/domain/entityService/domain.entity.service.definitions.d.ts +26 -19
- package/dist/domain/entityService/domain.entity.service.definitions.js +6 -6
- package/dist/domain/entityService/domain.entity.service.definitions.js.map +1 -1
- package/dist/domain/entityService/domain.entity.service.js +78 -69
- package/dist/domain/entityService/domain.entity.service.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/scripts/generateDatasourceFiles.d.ts +1 -0
- package/dist/scripts/generateDatasourceFiles.js +94 -0
- package/dist/scripts/generateDatasourceFiles.js.map +1 -0
- package/package.json +17 -9
- package/src/app.spec.ts +138 -0
- package/src/app.ts +120 -0
- package/src/common/configProvider/configProvider.definitions.ts +444 -0
- package/src/common/configProvider/configProvider.module.spec.ts +90 -0
- package/src/common/configProvider/configProvider.module.ts +25 -0
- package/src/common/configProvider/configProvider.service.spec.ts +206 -0
- package/src/common/configProvider/configProvider.service.ts +204 -0
- package/src/common/configProvider/index.ts +3 -0
- package/src/common/definitions/common.constants.ts +27 -0
- package/src/common/definitions/common.definitions.ts +13 -0
- package/src/common/definitions/common.errors.ts +13 -0
- package/src/common/definitions/index.ts +3 -0
- package/src/common/logger/index.ts +3 -0
- package/src/common/logger/logger.definitions.ts +5 -0
- package/src/common/logger/logger.module.ts +21 -0
- package/src/common/logger/logger.service.ts +40 -0
- package/src/common/utils/base64UrlEncode/base64UrlEncode.method.ts +4 -0
- package/src/common/utils/base64UrlEncode/index.ts +1 -0
- package/src/common/utils/getNested/getNested.definitions.ts +4 -0
- package/src/common/utils/getNested/getNested.method.ts +108 -0
- package/src/common/utils/getNested/getNested.spec.ts +151 -0
- package/src/common/utils/getNested/index.ts +2 -0
- package/src/common/utils/httpRequest/httpRequest.definitions.ts +22 -0
- package/src/common/utils/httpRequest/httpRequest.method.ts +46 -0
- package/src/common/utils/httpRequest/index.ts +2 -0
- package/src/common/utils/index.ts +5 -0
- package/src/common/utils/loadDynamicModules/index.ts +1 -0
- package/src/common/utils/loadDynamicModules/utils.loadDynamicModules.spec.ts +111 -0
- package/src/common/utils/loadDynamicModules/utils.loadDynamicModules.ts +69 -0
- package/src/common/utils/setNested/index.ts +2 -0
- package/src/common/utils/setNested/setNested.definitions.ts +4 -0
- package/src/common/utils/setNested/setNested.method.ts +83 -0
- package/src/common/utils/setNested/setNested.spec.ts +184 -0
- package/src/data/entityService/data.entity.service.definitions.ts +154 -0
- package/src/data/entityService/data.entity.service.spec.ts +112 -0
- package/src/data/entityService/data.entity.service.ts +147 -0
- package/src/data/entityService/index.ts +2 -0
- package/src/domain/entityService/domain.entity.service.definitions.ts +142 -0
- package/src/domain/entityService/domain.entity.service.spec.ts +126 -0
- package/src/domain/entityService/domain.entity.service.ts +424 -0
- package/src/domain/entityService/index.ts +2 -0
- package/src/index.ts +7 -0
- package/src/scripts/generateDatasourceFiles.ts +59 -0
- package/src/vitest.config.ts +9 -0
- package/dist/common/utils/utils.loadDynamicModules.js.map +0 -1
- package/dist/persistance/entityService/index.d.ts +0 -2
- package/dist/persistance/entityService/index.js.map +0 -1
- package/dist/persistance/entityService/persistance.entity.service.d.ts +0 -11
- package/dist/persistance/entityService/persistance.entity.service.definitions.d.ts +0 -76
- package/dist/persistance/entityService/persistance.entity.service.definitions.js +0 -23
- package/dist/persistance/entityService/persistance.entity.service.definitions.js.map +0 -1
- package/dist/persistance/entityService/persistance.entity.service.js.map +0 -1
- /package/dist/common/utils/{utils.loadDynamicModules.js → loadDynamicModules/utils.loadDynamicModules.js} +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { AppConfig, AppEnvironment, ConfigProviderModuleOptions } from './configProvider.definitions';
|
|
4
|
+
import { ConfigProviderModule } from './configProvider.module';
|
|
5
|
+
import { ConfigProviderService } from './configProvider.service';
|
|
6
|
+
|
|
7
|
+
import { Constants } from '../definitions';
|
|
8
|
+
|
|
9
|
+
// Helper type predicate: checks if a provider is a factory provider for a given token.
|
|
10
|
+
function isFactoryProvider<T, U>(
|
|
11
|
+
provider: unknown,
|
|
12
|
+
token: T
|
|
13
|
+
): provider is { provide: T; useFactory: () => Promise<U> } {
|
|
14
|
+
if (typeof provider !== 'object' || provider === null) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const p = provider as { provide?: T; useFactory?: unknown };
|
|
18
|
+
return p.provide === token && typeof p.useFactory === 'function';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('ConfigProviderModule', () => {
|
|
22
|
+
// Create a fake AppConfig with full type information.
|
|
23
|
+
const fakeAppConfig: AppConfig = {
|
|
24
|
+
api: {},
|
|
25
|
+
domain: {},
|
|
26
|
+
general: {
|
|
27
|
+
environment: AppEnvironment.Local,
|
|
28
|
+
projectName: 'TestProject',
|
|
29
|
+
projectRootPath: '/fake/path',
|
|
30
|
+
projectVersion: '1.0.0'
|
|
31
|
+
},
|
|
32
|
+
data: {}
|
|
33
|
+
};
|
|
34
|
+
const fakeEnvKeys = {
|
|
35
|
+
API: {
|
|
36
|
+
HTTP: { HOST: 'hostname', PORT: 'port' }
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const fakeEnvKeysParentNames = {
|
|
40
|
+
API: {
|
|
41
|
+
children: { TEST: 'test' },
|
|
42
|
+
name: 'api'
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const fakeModuleOptions: ConfigProviderModuleOptions = {
|
|
46
|
+
appConfigs: { appConfigCommon: fakeAppConfig },
|
|
47
|
+
envKeys: fakeEnvKeys,
|
|
48
|
+
envKeysParentNames: fakeEnvKeysParentNames
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
describe('register()', () => {
|
|
52
|
+
it('should return a dynamic module with proper configuration', async () => {
|
|
53
|
+
// Spy on loadConfig so that the factory returns our fake config.
|
|
54
|
+
const loadConfigSpy = vi.spyOn(ConfigProviderService, 'loadConfig').mockResolvedValue(fakeAppConfig);
|
|
55
|
+
const dynamicModule = ConfigProviderModule.register(fakeModuleOptions);
|
|
56
|
+
// Verify dynamic module properties.
|
|
57
|
+
expect(dynamicModule.global).toBe(true);
|
|
58
|
+
expect(dynamicModule.module).toBe(ConfigProviderModule);
|
|
59
|
+
expect(dynamicModule.providers).toEqual(
|
|
60
|
+
expect.arrayContaining([expect.objectContaining({ provide: Constants.CONFIG }), ConfigProviderService])
|
|
61
|
+
);
|
|
62
|
+
expect(dynamicModule.exports).toEqual([Constants.CONFIG, ConfigProviderService]);
|
|
63
|
+
// Locate the provider with the injection token.
|
|
64
|
+
const configProvider = dynamicModule.providers?.find(p =>
|
|
65
|
+
isFactoryProvider<Constants, AppConfig>(p, Constants.CONFIG)
|
|
66
|
+
) as unknown as { useFactory: () => Promise<ConfigProviderService> };
|
|
67
|
+
expect(configProvider).toBeDefined();
|
|
68
|
+
// Call the useFactory and verify it returns the fake config.
|
|
69
|
+
const producedConfig = await configProvider.useFactory();
|
|
70
|
+
expect(producedConfig).toEqual(fakeAppConfig);
|
|
71
|
+
expect(loadConfigSpy).toHaveBeenCalledWith(
|
|
72
|
+
{ appConfigCommon: fakeAppConfig },
|
|
73
|
+
{
|
|
74
|
+
envKeys: fakeEnvKeys,
|
|
75
|
+
envKeysParentNames: fakeEnvKeysParentNames
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
it('should propagate errors from the loadConfig factory', async () => {
|
|
80
|
+
const error = new Error('Load config failed');
|
|
81
|
+
vi.spyOn(ConfigProviderService, 'loadConfig').mockRejectedValue(error);
|
|
82
|
+
const dynamicModule = ConfigProviderModule.register(fakeModuleOptions);
|
|
83
|
+
const configProvider = dynamicModule.providers?.find(p =>
|
|
84
|
+
isFactoryProvider<Constants, AppConfig>(p, Constants.CONFIG)
|
|
85
|
+
) as unknown as { useFactory: () => Promise<ConfigProviderService> };
|
|
86
|
+
expect(configProvider).toBeDefined();
|
|
87
|
+
await expect(configProvider.useFactory()).rejects.toThrow('Load config failed');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { DynamicModule, Module } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { ConfigProviderModuleOptions } from './configProvider.definitions';
|
|
4
|
+
import { ConfigProviderService } from './configProvider.service';
|
|
5
|
+
|
|
6
|
+
import { Constants } from '../definitions';
|
|
7
|
+
|
|
8
|
+
@Module({})
|
|
9
|
+
export class ConfigProviderModule {
|
|
10
|
+
static register(options: ConfigProviderModuleOptions): DynamicModule {
|
|
11
|
+
const { appConfigs, ...otherOptions } = options;
|
|
12
|
+
return {
|
|
13
|
+
global: true,
|
|
14
|
+
module: ConfigProviderModule,
|
|
15
|
+
providers: [
|
|
16
|
+
{
|
|
17
|
+
provide: Constants.CONFIG,
|
|
18
|
+
useFactory: async () => await ConfigProviderService.loadConfig(appConfigs, { ...otherOptions })
|
|
19
|
+
},
|
|
20
|
+
ConfigProviderService
|
|
21
|
+
],
|
|
22
|
+
exports: [Constants.CONFIG, ConfigProviderService]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
import im from 'immutable';
|
|
5
|
+
import { mergeDeepRight } from 'ramda';
|
|
6
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
AppConfig,
|
|
10
|
+
AppConfigCommon,
|
|
11
|
+
AppEnvironment,
|
|
12
|
+
GenerateOrmconfigOptions,
|
|
13
|
+
LoadConfigAppConfigs
|
|
14
|
+
} from './configProvider.definitions';
|
|
15
|
+
import { ConfigProviderService } from './configProvider.service';
|
|
16
|
+
|
|
17
|
+
const BASE_PATH = path.join(__dirname, '../../../test');
|
|
18
|
+
|
|
19
|
+
describe('ConfigProviderService', () => {
|
|
20
|
+
describe('constructor', () => {
|
|
21
|
+
it('should assign the passed config to the service', () => {
|
|
22
|
+
const fakeConfig: AppConfig = {
|
|
23
|
+
api: {},
|
|
24
|
+
domain: {},
|
|
25
|
+
general: {
|
|
26
|
+
environment: AppEnvironment.Local,
|
|
27
|
+
projectName: 'TestProject',
|
|
28
|
+
projectRootPath: '/some/path',
|
|
29
|
+
projectVersion: '1.0.0'
|
|
30
|
+
},
|
|
31
|
+
data: {}
|
|
32
|
+
};
|
|
33
|
+
const service = new ConfigProviderService(fakeConfig);
|
|
34
|
+
expect(service.config).toEqual(fakeConfig);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// generateOrmconfig
|
|
39
|
+
describe('generateOrmconfig', () => {
|
|
40
|
+
const defaultFakeModuleName = 'db';
|
|
41
|
+
const defaultFakeOptions: GenerateOrmconfigOptions = {
|
|
42
|
+
entitiesPathInModule: 'entities',
|
|
43
|
+
migrationsPathInModule: 'migrations',
|
|
44
|
+
moduleName: defaultFakeModuleName,
|
|
45
|
+
modulePathInProject: 'src/data/db'
|
|
46
|
+
};
|
|
47
|
+
const defaultFakeConfig: AppConfig = {
|
|
48
|
+
api: {},
|
|
49
|
+
domain: {},
|
|
50
|
+
general: {
|
|
51
|
+
environment: AppEnvironment.Local,
|
|
52
|
+
projectName: 'TestProject',
|
|
53
|
+
projectRootPath: BASE_PATH,
|
|
54
|
+
projectVersion: '1.0.0'
|
|
55
|
+
},
|
|
56
|
+
data: {
|
|
57
|
+
[defaultFakeModuleName]: { type: 'mysql', extra: 'foo' }
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
let fakeModuleName: string;
|
|
61
|
+
let fakeOptions: GenerateOrmconfigOptions;
|
|
62
|
+
let fakeConfig: AppConfig;
|
|
63
|
+
let entitiesDirPath: string;
|
|
64
|
+
let migrationsPath: string;
|
|
65
|
+
let ormConfigPath: string;
|
|
66
|
+
// clean up before each test
|
|
67
|
+
beforeEach(async () => {
|
|
68
|
+
fakeModuleName = defaultFakeModuleName;
|
|
69
|
+
fakeOptions = im.fromJS(defaultFakeOptions).toJS() as unknown as GenerateOrmconfigOptions;
|
|
70
|
+
fakeConfig = im.fromJS(defaultFakeConfig).toJS() as unknown as AppConfig;
|
|
71
|
+
entitiesDirPath = path.join(BASE_PATH, fakeOptions.modulePathInProject, fakeOptions.entitiesPathInModule);
|
|
72
|
+
migrationsPath = path.join(BASE_PATH, fakeOptions.modulePathInProject, fakeOptions.migrationsPathInModule);
|
|
73
|
+
ormConfigPath = path.join(BASE_PATH, `ormconfig-${fakeModuleName}.json`);
|
|
74
|
+
try {
|
|
75
|
+
await fs.unlink(ormConfigPath);
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
77
|
+
} catch (_e: unknown) {}
|
|
78
|
+
});
|
|
79
|
+
it('should generate ormconfig file with entities and subscribers arrays correctly', async () => {
|
|
80
|
+
await ConfigProviderService.generateOrmconfig(fakeConfig, fakeOptions);
|
|
81
|
+
const expectedEntities = [
|
|
82
|
+
path.join(entitiesDirPath, 'orders', 'orders.entity.ts'),
|
|
83
|
+
path.join(entitiesDirPath, 'users', 'users.entity.ts')
|
|
84
|
+
];
|
|
85
|
+
const expectedSubscribers = [
|
|
86
|
+
path.join(entitiesDirPath, 'orders', 'orders.subscriber.ts'),
|
|
87
|
+
path.join(entitiesDirPath, 'users', 'users.subscriber.ts')
|
|
88
|
+
];
|
|
89
|
+
const expectedMergedConfig = mergeDeepRight(fakeConfig.data[fakeModuleName], {
|
|
90
|
+
entities: expectedEntities,
|
|
91
|
+
subscribers: expectedSubscribers,
|
|
92
|
+
migrations: [`${migrationsPath}/**/*.ts`],
|
|
93
|
+
cli: { migrationsDir: migrationsPath }
|
|
94
|
+
});
|
|
95
|
+
expect((await fs.readFile(ormConfigPath)).toString()).toEqual(JSON.stringify(expectedMergedConfig));
|
|
96
|
+
});
|
|
97
|
+
it('should handle case with empty entities directory (no folders)', async () => {
|
|
98
|
+
fakeOptions.entitiesPathInModule = 'entitiesEmpty';
|
|
99
|
+
await ConfigProviderService.generateOrmconfig(fakeConfig, fakeOptions);
|
|
100
|
+
const expectedMergedConfig = mergeDeepRight(fakeConfig.data[fakeModuleName], {
|
|
101
|
+
entities: [],
|
|
102
|
+
subscribers: [],
|
|
103
|
+
migrations: [`${migrationsPath}/**/*.ts`],
|
|
104
|
+
cli: { migrationsDir: migrationsPath }
|
|
105
|
+
});
|
|
106
|
+
expect((await fs.readFile(ormConfigPath)).toString()).toEqual(JSON.stringify(expectedMergedConfig));
|
|
107
|
+
});
|
|
108
|
+
it('should ignore files that do not match entity or subscriber patterns', async () => {
|
|
109
|
+
await ConfigProviderService.generateOrmconfig(fakeConfig, fakeOptions);
|
|
110
|
+
const writtenConfig = JSON.parse((await fs.readFile(ormConfigPath)).toString());
|
|
111
|
+
expect(writtenConfig.entities).toEqual(
|
|
112
|
+
expect.arrayContaining([
|
|
113
|
+
path.join(entitiesDirPath, 'users', 'users.entity.ts'),
|
|
114
|
+
path.join(entitiesDirPath, 'orders', 'orders.entity.ts')
|
|
115
|
+
])
|
|
116
|
+
);
|
|
117
|
+
expect(writtenConfig.entities).not.toEqual(
|
|
118
|
+
expect.arrayContaining([
|
|
119
|
+
path.join(entitiesDirPath, 'misc', 'note.txt'),
|
|
120
|
+
path.join(entitiesDirPath, 'misc', 'helper.ts')
|
|
121
|
+
])
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
it('should propagate error if fs.readdir fails', async () => {
|
|
125
|
+
fakeOptions.entitiesPathInModule = 'entitiesNotExistent';
|
|
126
|
+
await expect(ConfigProviderService.generateOrmconfig(fakeConfig, fakeOptions)).rejects.toThrow('ENOENT');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// loadConfig
|
|
131
|
+
describe('loadConfig', () => {
|
|
132
|
+
const defaultAppConfigs: LoadConfigAppConfigs = {
|
|
133
|
+
appConfigCommon: {
|
|
134
|
+
general: {
|
|
135
|
+
projectName: 'TestProject',
|
|
136
|
+
projectRootPath: BASE_PATH,
|
|
137
|
+
projectVersion: '1.0.0'
|
|
138
|
+
},
|
|
139
|
+
api: {
|
|
140
|
+
test: {}
|
|
141
|
+
},
|
|
142
|
+
domain: {},
|
|
143
|
+
data: {}
|
|
144
|
+
},
|
|
145
|
+
appConfigProfileLocal: {
|
|
146
|
+
general: { environment: AppEnvironment.Local }
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const defaultEnvKeys = {
|
|
150
|
+
API: {
|
|
151
|
+
HTTP: { HOST: 'hostname', PORT: 'port' }
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const defaultEnvKeysParentNames = {
|
|
155
|
+
API: {
|
|
156
|
+
children: { TEST: 'test' },
|
|
157
|
+
name: 'api'
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
let appConfigs: LoadConfigAppConfigs;
|
|
161
|
+
|
|
162
|
+
beforeEach(() => {
|
|
163
|
+
process.env.NODE_ENV = 'local';
|
|
164
|
+
appConfigs = im.fromJS(defaultAppConfigs).toJS() as unknown as LoadConfigAppConfigs;
|
|
165
|
+
});
|
|
166
|
+
it('should load and merge configuration from env file and populate nested values', async () => {
|
|
167
|
+
delete process.env['NODE_ENV'];
|
|
168
|
+
const loadedConfig = await ConfigProviderService.loadConfig(appConfigs, {
|
|
169
|
+
envKeys: defaultEnvKeys,
|
|
170
|
+
envKeysParentNames: defaultEnvKeysParentNames
|
|
171
|
+
});
|
|
172
|
+
expect(loadedConfig.general.environment).toBe('local');
|
|
173
|
+
expect(loadedConfig.api).toBeDefined();
|
|
174
|
+
expect(loadedConfig.api.rest).toBeUndefined();
|
|
175
|
+
expect(loadedConfig.api.test).toBeDefined();
|
|
176
|
+
expect(loadedConfig.api.test.hostname).toBe('127.0.0.1');
|
|
177
|
+
expect(loadedConfig.api.test.port).toBe('3000');
|
|
178
|
+
});
|
|
179
|
+
it('should use default envKeys and envKeysParentNames if options not provided', async () => {
|
|
180
|
+
appConfigs.appConfigCommon.api!.rest = {};
|
|
181
|
+
const loadedConfig = await ConfigProviderService.loadConfig(appConfigs);
|
|
182
|
+
expect(loadedConfig.general.environment).toBe('local');
|
|
183
|
+
expect(loadedConfig.api.rest).toBeDefined();
|
|
184
|
+
expect(loadedConfig.api.rest.hostname).toBe('localhost');
|
|
185
|
+
expect(loadedConfig.api.test.hostname).toBeUndefined();
|
|
186
|
+
});
|
|
187
|
+
it('should throw an error if the .env file is missing', async () => {
|
|
188
|
+
(appConfigs.appConfigCommon as AppConfigCommon).general.projectRootPath = '/fake/path';
|
|
189
|
+
await expect(
|
|
190
|
+
ConfigProviderService.loadConfig(appConfigs, {
|
|
191
|
+
envKeys: defaultEnvKeys,
|
|
192
|
+
envKeysParentNames: defaultEnvKeysParentNames
|
|
193
|
+
})
|
|
194
|
+
).rejects.toThrow('ENOENT');
|
|
195
|
+
});
|
|
196
|
+
it('should skip env keys that do not match expected pattern', async () => {
|
|
197
|
+
const loadedConfig = await ConfigProviderService.loadConfig(appConfigs, {
|
|
198
|
+
envKeys: defaultEnvKeys,
|
|
199
|
+
envKeysParentNames: defaultEnvKeysParentNames
|
|
200
|
+
});
|
|
201
|
+
expect(loadedConfig.api.test.hostname).toBe('127.0.0.1');
|
|
202
|
+
expect(loadedConfig.api.test.port).toBe('3000');
|
|
203
|
+
expect(loadedConfig.api.something).toBeUndefined();
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
});
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
5
|
+
import dotenv from 'dotenv';
|
|
6
|
+
import ld from 'lodash';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
APP_CONFIG_FROM_ENV_KEYS as APP_CONFIG_FROM_ENV_KEYS_DEFAULT,
|
|
10
|
+
APP_CONFIG_FROM_ENV_KEYS_PARENT_NAMES as APP_CONFIG_FROM_ENV_KEYS_PARENT_NAMES_DEFAULT,
|
|
11
|
+
AppConfigDataRDB,
|
|
12
|
+
AppConfig as AppConfigDefault,
|
|
13
|
+
AppEnvironment,
|
|
14
|
+
GenerateOrmconfigOptions,
|
|
15
|
+
LoadConfigAppConfigs,
|
|
16
|
+
LoadConfigOptions,
|
|
17
|
+
RDBType
|
|
18
|
+
} from './configProvider.definitions';
|
|
19
|
+
|
|
20
|
+
import { Constants } from '../definitions';
|
|
21
|
+
import { setNested } from '../utils';
|
|
22
|
+
|
|
23
|
+
@Injectable()
|
|
24
|
+
export class ConfigProviderService<AppConfig extends AppConfigDefault = AppConfigDefault> {
|
|
25
|
+
constructor(
|
|
26
|
+
@Inject(Constants.CONFIG)
|
|
27
|
+
// eslint-disable-next-line no-unused-vars
|
|
28
|
+
public config: AppConfig
|
|
29
|
+
) {}
|
|
30
|
+
|
|
31
|
+
// TODO: consider moving this into the data-rdb package
|
|
32
|
+
static async generateOrmconfig<AppConfig extends AppConfigDefault = AppConfigDefault>(
|
|
33
|
+
config: AppConfig,
|
|
34
|
+
options: GenerateOrmconfigOptions
|
|
35
|
+
): Promise<void> {
|
|
36
|
+
const {
|
|
37
|
+
general: { environment, projectRootPath },
|
|
38
|
+
data
|
|
39
|
+
} = config;
|
|
40
|
+
const { entitiesPathInModule, migrationsPathInModule, moduleName, modulePathInProject, seedsPathInModule } =
|
|
41
|
+
options;
|
|
42
|
+
const entitiesDirPath = path.join(projectRootPath, modulePathInProject, entitiesPathInModule);
|
|
43
|
+
const entitiesDirData = await fs.readdir(entitiesDirPath);
|
|
44
|
+
const entities: string[] = [];
|
|
45
|
+
const migrationsPath = path.join(projectRootPath, modulePathInProject, migrationsPathInModule);
|
|
46
|
+
const moduleConfig = data[moduleName] as AppConfigDataRDB;
|
|
47
|
+
const subscribers: string[] = [];
|
|
48
|
+
for (const i in entitiesDirData) {
|
|
49
|
+
const entityName = entitiesDirData[i];
|
|
50
|
+
if (entityName.match(/^base$/)) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const entityFolderPath = path.join(entitiesDirPath, entityName);
|
|
54
|
+
const entityFolderChildItemStat = await fs.lstat(entityFolderPath);
|
|
55
|
+
if (!entityFolderChildItemStat.isDirectory()) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const entityFolderData = await fs.readdir(entityFolderPath);
|
|
59
|
+
for (const j in entityFolderData) {
|
|
60
|
+
const entityFolderFileName = entityFolderData[j];
|
|
61
|
+
if (entityFolderFileName.match(/\.entity\./)) {
|
|
62
|
+
entities.push(path.join(entityFolderPath, entityFolderFileName));
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (entityFolderFileName.match(/\.subscriber\./)) {
|
|
66
|
+
subscribers.push(path.join(entityFolderPath, entityFolderFileName));
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// write the ORM Config file
|
|
72
|
+
const ormconfigMigrations: string[] = [`${migrationsPath}/**/*.ts`];
|
|
73
|
+
if (seedsPathInModule) {
|
|
74
|
+
const baseSeedsPath = path.join(projectRootPath, modulePathInProject, seedsPathInModule);
|
|
75
|
+
ormconfigMigrations.push(`${baseSeedsPath}/common/**/*.ts`);
|
|
76
|
+
}
|
|
77
|
+
await fs.writeFile(
|
|
78
|
+
path.join(projectRootPath, `ormconfig-${moduleName}-${environment}.json`),
|
|
79
|
+
JSON.stringify(
|
|
80
|
+
ld.merge(data[moduleName], {
|
|
81
|
+
cli: {
|
|
82
|
+
migrationsDir: migrationsPath
|
|
83
|
+
},
|
|
84
|
+
entities: [...entities],
|
|
85
|
+
migrations: ormconfigMigrations,
|
|
86
|
+
name: moduleConfig.connectionName,
|
|
87
|
+
synchronize: moduleConfig.type === RDBType.Aurora ? true : false,
|
|
88
|
+
subscribers: [...subscribers],
|
|
89
|
+
type: moduleConfig.type === RDBType.Aurora ? RDBType.MySQL : moduleConfig.type,
|
|
90
|
+
...(moduleConfig.typeormExtraOptions || {})
|
|
91
|
+
})
|
|
92
|
+
)
|
|
93
|
+
);
|
|
94
|
+
// write the Datasource file
|
|
95
|
+
const entitiesPathInProject = path.join(modulePathInProject, entitiesPathInModule);
|
|
96
|
+
await fs.writeFile(
|
|
97
|
+
path.join(projectRootPath, `datasource-${moduleName}-${environment}.ts`),
|
|
98
|
+
"import { loadDynamicModules } from '@node-c/core';\n" +
|
|
99
|
+
'\n' +
|
|
100
|
+
"import { DataSource } from 'typeorm';\n" +
|
|
101
|
+
'\n' +
|
|
102
|
+
`import * as FolderData from './${entitiesPathInProject}';\n` +
|
|
103
|
+
'\n' +
|
|
104
|
+
'const { entities } = loadDynamicModules(FolderData);\n' +
|
|
105
|
+
'\n' +
|
|
106
|
+
'export default new DataSource({\n' +
|
|
107
|
+
` database: '${moduleConfig.database}',\n` +
|
|
108
|
+
' entities: entities as unknown as string[],\n' +
|
|
109
|
+
` host: '${moduleConfig.host}',\n` +
|
|
110
|
+
' logging: false,\n' +
|
|
111
|
+
` migrations: [${ormconfigMigrations.map(item => `'${item.replace(projectRootPath.replace(/\/$/, ''), '.')}'`).join(', ')}],\n` +
|
|
112
|
+
` name: '${moduleConfig.connectionName}',\n` +
|
|
113
|
+
` password: '${moduleConfig.password}',\n` +
|
|
114
|
+
` port: ${moduleConfig.port},\n` +
|
|
115
|
+
' subscribers: [],\n' +
|
|
116
|
+
` synchronize: ${moduleConfig.type === RDBType.Aurora ? true : false},\n` +
|
|
117
|
+
` type: '${moduleConfig.type === RDBType.Aurora ? RDBType.MySQL : moduleConfig.type}',\n` +
|
|
118
|
+
` username: '${moduleConfig.user}'\n` +
|
|
119
|
+
'});\n'
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// TODO: logging about invalid config values
|
|
124
|
+
static async loadConfig<AppConfig extends AppConfigDefault = AppConfigDefault>(
|
|
125
|
+
appConfigs: LoadConfigAppConfigs,
|
|
126
|
+
options?: LoadConfigOptions
|
|
127
|
+
): Promise<AppConfig> {
|
|
128
|
+
const { useEnvFile, useEnvFileWithPriority, ...optionsData } = options || ({} as LoadConfigOptions);
|
|
129
|
+
const envKeys = optionsData.envKeys || APP_CONFIG_FROM_ENV_KEYS_DEFAULT;
|
|
130
|
+
const envKeysParentNames = optionsData.envKeysParentNames || APP_CONFIG_FROM_ENV_KEYS_PARENT_NAMES_DEFAULT;
|
|
131
|
+
const processEnv = process.env;
|
|
132
|
+
const envName = optionsData.envName || (processEnv['NODE_ENV'] as AppEnvironment) || AppEnvironment.Local;
|
|
133
|
+
const config = ld.merge(
|
|
134
|
+
appConfigs.appConfigCommon,
|
|
135
|
+
appConfigs[
|
|
136
|
+
`appConfigProfile${envName.charAt(0).toUpperCase()}${envName.substring(
|
|
137
|
+
1,
|
|
138
|
+
envName.length
|
|
139
|
+
)}` as keyof typeof appConfigs
|
|
140
|
+
]
|
|
141
|
+
) as AppConfig;
|
|
142
|
+
const moduleNamesByCategoryAndType: {
|
|
143
|
+
[moduleCategory: string]: { [moduleType: string]: string[] };
|
|
144
|
+
} = {};
|
|
145
|
+
const moduleTypesRegex = new RegExp(`^((${Object.keys(envKeys).join(')|(')}))_`);
|
|
146
|
+
config.general.environment = envName;
|
|
147
|
+
let envVars: Record<string, unknown> = processEnv;
|
|
148
|
+
if (useEnvFile) {
|
|
149
|
+
// populate the data from the .env file into the config object
|
|
150
|
+
const envVarsFromFile = dotenv.parse(
|
|
151
|
+
(await fs.readFile(path.join(config.general.projectRootPath, `envFiles/.${envName}.env`))).toString()
|
|
152
|
+
);
|
|
153
|
+
if (useEnvFileWithPriority) {
|
|
154
|
+
envVars = ld.merge(envVars, envVarsFromFile);
|
|
155
|
+
} else {
|
|
156
|
+
envVars = ld.merge(envVarsFromFile, envVars);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// first pass - create a list of modules by name and map them by module type
|
|
160
|
+
for (const envKey in envVars) {
|
|
161
|
+
const [, moduleCategory] = envKey.match(moduleTypesRegex) || [];
|
|
162
|
+
if (!moduleCategory) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const [, moduleName] = envKey.match(new RegExp(`^${moduleCategory}_(.+)_MODULE_TYPE$`)) || [];
|
|
166
|
+
if (!moduleName) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const moduleFields = envKeys[moduleCategory as keyof typeof envKeys];
|
|
170
|
+
const moduleType = envVars[envKey] as keyof typeof moduleFields;
|
|
171
|
+
if (!moduleFields[moduleType]) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (!moduleNamesByCategoryAndType[moduleCategory]) {
|
|
175
|
+
moduleNamesByCategoryAndType[moduleCategory] = {};
|
|
176
|
+
}
|
|
177
|
+
if (!moduleNamesByCategoryAndType[moduleCategory][moduleType]) {
|
|
178
|
+
moduleNamesByCategoryAndType[moduleCategory][moduleType] = [];
|
|
179
|
+
}
|
|
180
|
+
moduleNamesByCategoryAndType[moduleCategory][moduleType].push(moduleName);
|
|
181
|
+
}
|
|
182
|
+
// second pass - actually go through the env vars and populate them in the config accordingly
|
|
183
|
+
for (const moduleCategory in moduleNamesByCategoryAndType) {
|
|
184
|
+
const { children: moduleConfigKeysForCategory, name: categoryConfigKey } = envKeysParentNames[moduleCategory];
|
|
185
|
+
const moduleFieldsForCategory = envKeys[moduleCategory as keyof typeof envKeys];
|
|
186
|
+
const moduleNamesByType = moduleNamesByCategoryAndType[moduleCategory];
|
|
187
|
+
for (const moduleType in moduleNamesByType) {
|
|
188
|
+
const moduleFieldsForType = moduleFieldsForCategory[
|
|
189
|
+
moduleType as keyof typeof moduleFieldsForCategory
|
|
190
|
+
] as Record<string, string>;
|
|
191
|
+
const moduleNames = moduleNamesByType[moduleType];
|
|
192
|
+
moduleNames.forEach(moduleName => {
|
|
193
|
+
const moduleConfigKey = moduleConfigKeysForCategory[moduleName];
|
|
194
|
+
for (const fieldName in moduleFieldsForType) {
|
|
195
|
+
const configKey = `${categoryConfigKey}.${moduleConfigKey}.${moduleFieldsForType[fieldName]}`;
|
|
196
|
+
const envKey = `${moduleCategory}_${moduleName}_${fieldName}`;
|
|
197
|
+
setNested(config, configKey, envVars[envKey]);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return config;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export enum Constants {
|
|
2
|
+
// eslint-disable-next-line no-unused-vars
|
|
3
|
+
API_MODULE_NAME = 'API_MODULE_NAME',
|
|
4
|
+
// eslint-disable-next-line no-unused-vars
|
|
5
|
+
CONFIG = 'CONFIG',
|
|
6
|
+
// eslint-disable-next-line no-unused-vars
|
|
7
|
+
DOMAIN_MODULE_NAME = 'DOMAIN_MODULE_NAME',
|
|
8
|
+
// eslint-disable-next-line no-unused-vars
|
|
9
|
+
DATA_MODULE_NAME = 'DATA_MODULE_NAME'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export enum HttpMethod {
|
|
13
|
+
// eslint-disable-next-line no-unused-vars
|
|
14
|
+
DELETE = 'delete',
|
|
15
|
+
// eslint-disable-next-line no-unused-vars
|
|
16
|
+
GET = 'get',
|
|
17
|
+
// eslint-disable-next-line no-unused-vars
|
|
18
|
+
HEAD = 'head',
|
|
19
|
+
// eslint-disable-next-line no-unused-vars
|
|
20
|
+
OPTIONS = 'options',
|
|
21
|
+
// eslint-disable-next-line no-unused-vars
|
|
22
|
+
PATCH = 'patch',
|
|
23
|
+
// eslint-disable-next-line no-unused-vars
|
|
24
|
+
POST = 'post',
|
|
25
|
+
// eslint-disable-next-line no-unused-vars
|
|
26
|
+
PUT = 'put'
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface GenericObject<Values = unknown> {
|
|
2
|
+
[fieldName: string]: Values;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export class GenericObjectClass<Values = unknown> implements GenericObject<Values> {
|
|
6
|
+
[fieldName: string]: Values;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type GenericObjectType<Type> =
|
|
10
|
+
| {
|
|
11
|
+
new (): Type;
|
|
12
|
+
}
|
|
13
|
+
| ((..._args: unknown[]) => unknown);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { GenericObject } from './common.definitions';
|
|
2
|
+
|
|
3
|
+
export class ApplicationError implements Error {
|
|
4
|
+
data?: { errorCode?: number } | GenericObject;
|
|
5
|
+
message: string;
|
|
6
|
+
name: string;
|
|
7
|
+
|
|
8
|
+
constructor(message: string, data?: GenericObject) {
|
|
9
|
+
this.message = message;
|
|
10
|
+
this.name = 'ApplicationError';
|
|
11
|
+
this.data = data || {};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DynamicModule, Module } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import ld from 'lodash';
|
|
4
|
+
import { LoggerModule as PinoLoggerModule } from 'nestjs-pino';
|
|
5
|
+
|
|
6
|
+
import { LoggerModuleOptions } from './logger.definitions';
|
|
7
|
+
import { DEFAULT_PINO_PARAMS, LoggerService } from './logger.service';
|
|
8
|
+
|
|
9
|
+
@Module({})
|
|
10
|
+
export class LoggerModule {
|
|
11
|
+
static register(options?: LoggerModuleOptions): DynamicModule {
|
|
12
|
+
const { pinoParams } = options || {};
|
|
13
|
+
return {
|
|
14
|
+
global: true,
|
|
15
|
+
module: LoggerModule,
|
|
16
|
+
imports: [PinoLoggerModule.forRoot(ld.merge(DEFAULT_PINO_PARAMS, pinoParams || {}))],
|
|
17
|
+
providers: [LoggerService],
|
|
18
|
+
exports: [LoggerService]
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
|
|
3
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
4
|
+
|
|
5
|
+
import { Logger, PARAMS_PROVIDER_TOKEN, Params, PinoLogger } from 'nestjs-pino';
|
|
6
|
+
import { v4 as uuid } from 'uuid';
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_PINO_PARAMS: Params = {
|
|
9
|
+
pinoHttp: {
|
|
10
|
+
// autoLogging: false,
|
|
11
|
+
genReqId: () => uuid(),
|
|
12
|
+
quietReqLogger: true,
|
|
13
|
+
quietResLogger: true,
|
|
14
|
+
transport: {
|
|
15
|
+
targets: [
|
|
16
|
+
{
|
|
17
|
+
options: { destination: path.resolve(process.cwd(), 'logs/app_logs.txt'), sync: false },
|
|
18
|
+
target: 'pino/file'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
// level: 'info',
|
|
22
|
+
options: { destination: 1, sync: false },
|
|
23
|
+
target: 'pino-pretty'
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
@Injectable()
|
|
31
|
+
export class LoggerService extends Logger {
|
|
32
|
+
constructor(logger: PinoLogger, @Inject(PARAMS_PROVIDER_TOKEN) params: Params) {
|
|
33
|
+
super(logger, params);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
info(...args: unknown[]): void {
|
|
37
|
+
// eslint-disable-next-line prefer-spread
|
|
38
|
+
this.logger.info.apply(this, args as [unknown, string, ...unknown[]]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export const base64UrlEncode = (buffer: ArrayBuffer | string): string => {
|
|
2
|
+
const actualBuffer = typeof buffer === 'string' ? Buffer.from(buffer, 'utf-8') : Buffer.from(buffer);
|
|
3
|
+
return actualBuffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
|
4
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './base64UrlEncode.method';
|