@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.
Files changed (160) hide show
  1. package/coverage/src/app.ts.html +349 -0
  2. package/coverage/src/common/configProvider/configProvider.module.ts.html +160 -0
  3. package/coverage/src/common/configProvider/configProvider.service.ts.html +658 -0
  4. package/coverage/src/common/configProvider/index.html +146 -0
  5. package/coverage/src/common/configProvider/index.ts.html +94 -0
  6. package/coverage/src/common/definitions/common.constants.ts.html +160 -0
  7. package/coverage/src/common/definitions/common.errors.ts.html +124 -0
  8. package/coverage/src/common/definitions/index.html +146 -0
  9. package/coverage/src/common/definitions/index.ts.html +94 -0
  10. package/coverage/src/common/utils/index.html +131 -0
  11. package/coverage/src/common/utils/index.ts.html +88 -0
  12. package/coverage/src/common/utils/utils.loadDynamicModules.ts.html +265 -0
  13. package/coverage/src/domain/entityService/domain.entity.service.ts.html +784 -0
  14. package/coverage/src/domain/entityService/index.html +131 -0
  15. package/coverage/src/domain/entityService/index.ts.html +91 -0
  16. package/coverage/src/index.html +116 -0
  17. package/coverage/src/persistance/entityService/index.html +131 -0
  18. package/coverage/src/persistance/entityService/index.ts.html +91 -0
  19. package/coverage/src/persistance/entityService/persistance.entity.service.ts.html +268 -0
  20. package/dist/app.d.ts +10 -9
  21. package/dist/app.js +30 -15
  22. package/dist/app.js.map +1 -1
  23. package/dist/common/configProvider/configProvider.definitions.d.ts +158 -21
  24. package/dist/common/configProvider/configProvider.definitions.js +22 -8
  25. package/dist/common/configProvider/configProvider.definitions.js.map +1 -1
  26. package/dist/common/configProvider/configProvider.module.js +13 -2
  27. package/dist/common/configProvider/configProvider.module.js.map +1 -1
  28. package/dist/common/configProvider/configProvider.service.js +23 -20
  29. package/dist/common/configProvider/configProvider.service.js.map +1 -1
  30. package/dist/common/definitions/common.constants.d.ts +2 -1
  31. package/dist/common/definitions/common.constants.js +1 -0
  32. package/dist/common/definitions/common.constants.js.map +1 -1
  33. package/dist/common/logger/index.d.ts +3 -0
  34. package/dist/common/logger/index.js +20 -0
  35. package/dist/common/logger/index.js.map +1 -0
  36. package/dist/common/logger/logger.definitions.d.ts +4 -0
  37. package/dist/common/logger/logger.definitions.js +3 -0
  38. package/dist/common/logger/logger.definitions.js.map +1 -0
  39. package/dist/common/logger/logger.module.d.ts +5 -0
  40. package/dist/common/logger/logger.module.js +34 -0
  41. package/dist/common/logger/logger.module.js.map +1 -0
  42. package/dist/common/logger/logger.service.d.ts +6 -0
  43. package/dist/common/logger/logger.service.js +56 -0
  44. package/dist/common/logger/logger.service.js.map +1 -0
  45. package/dist/common/utils/base64UrlEncode/base64UrlEncode.method.d.ts +1 -0
  46. package/dist/common/utils/base64UrlEncode/base64UrlEncode.method.js +9 -0
  47. package/dist/common/utils/base64UrlEncode/base64UrlEncode.method.js.map +1 -0
  48. package/dist/common/utils/base64UrlEncode/index.d.ts +1 -0
  49. package/dist/{persistance/entityService → common/utils/base64UrlEncode}/index.js +1 -2
  50. package/dist/common/utils/base64UrlEncode/index.js.map +1 -0
  51. package/dist/common/utils/getNested/getNested.definitions.d.ts +4 -0
  52. package/dist/common/utils/getNested/getNested.definitions.js +3 -0
  53. package/dist/common/utils/getNested/getNested.definitions.js.map +1 -0
  54. package/dist/common/utils/getNested/getNested.method.d.ts +6 -0
  55. package/dist/common/utils/getNested/getNested.method.js +88 -0
  56. package/dist/common/utils/getNested/getNested.method.js.map +1 -0
  57. package/dist/common/utils/getNested/index.d.ts +2 -0
  58. package/dist/common/utils/getNested/index.js +19 -0
  59. package/dist/common/utils/getNested/index.js.map +1 -0
  60. package/dist/common/utils/httpRequest/httpRequest.definitions.d.ts +19 -0
  61. package/dist/common/utils/httpRequest/httpRequest.definitions.js +3 -0
  62. package/dist/common/utils/httpRequest/httpRequest.definitions.js.map +1 -0
  63. package/dist/common/utils/httpRequest/httpRequest.method.d.ts +2 -0
  64. package/dist/common/utils/httpRequest/httpRequest.method.js +56 -0
  65. package/dist/common/utils/httpRequest/httpRequest.method.js.map +1 -0
  66. package/dist/common/utils/httpRequest/index.d.ts +2 -0
  67. package/dist/common/utils/httpRequest/index.js +19 -0
  68. package/dist/common/utils/httpRequest/index.js.map +1 -0
  69. package/dist/common/utils/index.d.ts +5 -1
  70. package/dist/common/utils/index.js +5 -1
  71. package/dist/common/utils/index.js.map +1 -1
  72. package/dist/common/utils/loadDynamicModules/index.d.ts +1 -0
  73. package/dist/common/utils/loadDynamicModules/index.js +18 -0
  74. package/dist/common/utils/loadDynamicModules/index.js.map +1 -0
  75. package/dist/common/utils/{utils.loadDynamicModules.d.ts → loadDynamicModules/utils.loadDynamicModules.d.ts} +1 -1
  76. package/dist/common/utils/loadDynamicModules/utils.loadDynamicModules.js.map +1 -0
  77. package/dist/common/utils/setNested/index.d.ts +2 -0
  78. package/dist/common/utils/setNested/index.js +19 -0
  79. package/dist/common/utils/setNested/index.js.map +1 -0
  80. package/dist/common/utils/setNested/setNested.definitions.d.ts +4 -0
  81. package/dist/common/utils/setNested/setNested.definitions.js +3 -0
  82. package/dist/common/utils/setNested/setNested.definitions.js.map +1 -0
  83. package/dist/common/utils/setNested/setNested.method.d.ts +2 -0
  84. package/dist/common/utils/setNested/setNested.method.js +70 -0
  85. package/dist/common/utils/setNested/setNested.method.js.map +1 -0
  86. package/dist/data/entityService/data.entity.service.d.ts +19 -0
  87. package/dist/data/entityService/data.entity.service.definitions.d.ts +117 -0
  88. package/dist/data/entityService/data.entity.service.definitions.js +28 -0
  89. package/dist/data/entityService/data.entity.service.definitions.js.map +1 -0
  90. package/dist/{persistance/entityService/persistance.entity.service.js → data/entityService/data.entity.service.js} +42 -9
  91. package/dist/data/entityService/data.entity.service.js.map +1 -0
  92. package/dist/data/entityService/index.d.ts +2 -0
  93. package/dist/data/entityService/index.js +19 -0
  94. package/dist/data/entityService/index.js.map +1 -0
  95. package/dist/domain/entityService/domain.entity.service.d.ts +30 -13
  96. package/dist/domain/entityService/domain.entity.service.definitions.d.ts +26 -19
  97. package/dist/domain/entityService/domain.entity.service.definitions.js +6 -6
  98. package/dist/domain/entityService/domain.entity.service.definitions.js.map +1 -1
  99. package/dist/domain/entityService/domain.entity.service.js +78 -69
  100. package/dist/domain/entityService/domain.entity.service.js.map +1 -1
  101. package/dist/index.d.ts +2 -1
  102. package/dist/index.js +2 -1
  103. package/dist/index.js.map +1 -1
  104. package/dist/scripts/generateDatasourceFiles.d.ts +1 -0
  105. package/dist/scripts/generateDatasourceFiles.js +94 -0
  106. package/dist/scripts/generateDatasourceFiles.js.map +1 -0
  107. package/package.json +17 -9
  108. package/src/app.spec.ts +138 -0
  109. package/src/app.ts +120 -0
  110. package/src/common/configProvider/configProvider.definitions.ts +444 -0
  111. package/src/common/configProvider/configProvider.module.spec.ts +90 -0
  112. package/src/common/configProvider/configProvider.module.ts +25 -0
  113. package/src/common/configProvider/configProvider.service.spec.ts +206 -0
  114. package/src/common/configProvider/configProvider.service.ts +204 -0
  115. package/src/common/configProvider/index.ts +3 -0
  116. package/src/common/definitions/common.constants.ts +27 -0
  117. package/src/common/definitions/common.definitions.ts +13 -0
  118. package/src/common/definitions/common.errors.ts +13 -0
  119. package/src/common/definitions/index.ts +3 -0
  120. package/src/common/logger/index.ts +3 -0
  121. package/src/common/logger/logger.definitions.ts +5 -0
  122. package/src/common/logger/logger.module.ts +21 -0
  123. package/src/common/logger/logger.service.ts +40 -0
  124. package/src/common/utils/base64UrlEncode/base64UrlEncode.method.ts +4 -0
  125. package/src/common/utils/base64UrlEncode/index.ts +1 -0
  126. package/src/common/utils/getNested/getNested.definitions.ts +4 -0
  127. package/src/common/utils/getNested/getNested.method.ts +108 -0
  128. package/src/common/utils/getNested/getNested.spec.ts +151 -0
  129. package/src/common/utils/getNested/index.ts +2 -0
  130. package/src/common/utils/httpRequest/httpRequest.definitions.ts +22 -0
  131. package/src/common/utils/httpRequest/httpRequest.method.ts +46 -0
  132. package/src/common/utils/httpRequest/index.ts +2 -0
  133. package/src/common/utils/index.ts +5 -0
  134. package/src/common/utils/loadDynamicModules/index.ts +1 -0
  135. package/src/common/utils/loadDynamicModules/utils.loadDynamicModules.spec.ts +111 -0
  136. package/src/common/utils/loadDynamicModules/utils.loadDynamicModules.ts +69 -0
  137. package/src/common/utils/setNested/index.ts +2 -0
  138. package/src/common/utils/setNested/setNested.definitions.ts +4 -0
  139. package/src/common/utils/setNested/setNested.method.ts +83 -0
  140. package/src/common/utils/setNested/setNested.spec.ts +184 -0
  141. package/src/data/entityService/data.entity.service.definitions.ts +154 -0
  142. package/src/data/entityService/data.entity.service.spec.ts +112 -0
  143. package/src/data/entityService/data.entity.service.ts +147 -0
  144. package/src/data/entityService/index.ts +2 -0
  145. package/src/domain/entityService/domain.entity.service.definitions.ts +142 -0
  146. package/src/domain/entityService/domain.entity.service.spec.ts +126 -0
  147. package/src/domain/entityService/domain.entity.service.ts +424 -0
  148. package/src/domain/entityService/index.ts +2 -0
  149. package/src/index.ts +7 -0
  150. package/src/scripts/generateDatasourceFiles.ts +59 -0
  151. package/src/vitest.config.ts +9 -0
  152. package/dist/common/utils/utils.loadDynamicModules.js.map +0 -1
  153. package/dist/persistance/entityService/index.d.ts +0 -2
  154. package/dist/persistance/entityService/index.js.map +0 -1
  155. package/dist/persistance/entityService/persistance.entity.service.d.ts +0 -11
  156. package/dist/persistance/entityService/persistance.entity.service.definitions.d.ts +0 -76
  157. package/dist/persistance/entityService/persistance.entity.service.definitions.js +0 -23
  158. package/dist/persistance/entityService/persistance.entity.service.definitions.js.map +0 -1
  159. package/dist/persistance/entityService/persistance.entity.service.js.map +0 -1
  160. /package/dist/common/utils/{utils.loadDynamicModules.js → loadDynamicModules/utils.loadDynamicModules.js} +0 -0
@@ -0,0 +1,138 @@
1
+ import * as path from 'path';
2
+
3
+ import { INestApplication, Module, NestModule } from '@nestjs/common';
4
+ import { afterEach, describe, expect, it, vi } from 'vitest';
5
+
6
+ import {
7
+ APP_CONFIG_FROM_ENV_KEYS,
8
+ AppEnvironment,
9
+ ConfigProviderModule,
10
+ ConfigProviderService,
11
+ NodeCApp,
12
+ NodeCAppStartOptions
13
+ } from './index';
14
+
15
+ const BASE_PATH = path.join(__dirname, '../test');
16
+
17
+ const appModuleOptions = {
18
+ appConfigs: {
19
+ appConfigCommon: {
20
+ general: {
21
+ projectName: 'TestProject',
22
+ projectRootPath: BASE_PATH,
23
+ projectVersion: '1.0.0'
24
+ },
25
+ api: { test: {} },
26
+ domain: {},
27
+ data: { db: { type: 'mysql', extra: 'foo' }, notADb: { type: 'unsupported' } }
28
+ },
29
+ appConfigProfileLocal: {
30
+ general: { environment: AppEnvironment.Local }
31
+ }
32
+ },
33
+ envKeys: APP_CONFIG_FROM_ENV_KEYS,
34
+ envKeysParentNames: {
35
+ API: {
36
+ children: { TEST: 'test' },
37
+ name: 'api'
38
+ }
39
+ }
40
+ };
41
+
42
+ @Module({})
43
+ class TestAPIModule {}
44
+
45
+ @Module({
46
+ imports: [ConfigProviderModule.register(appModuleOptions)]
47
+ })
48
+ class AppModule {}
49
+
50
+ @Module({
51
+ imports: [ConfigProviderModule.register(appModuleOptions), TestAPIModule]
52
+ })
53
+ class AppModuleWithAPI {}
54
+
55
+ @Module({
56
+ imports: [
57
+ ConfigProviderModule.register({
58
+ ...appModuleOptions,
59
+ envKeys: { API: { HTTP: { HOST: 'hostname', PORT: 'port' } } },
60
+ envKeysParentNames: { API: { children: { TEST: 'test' }, name: 'api' } }
61
+ }),
62
+ TestAPIModule
63
+ ]
64
+ })
65
+ class AppModuleWithAPIStartable {}
66
+
67
+ describe('NodeCApp.start', () => {
68
+ let apps: INestApplication<unknown>[];
69
+ process.env.NODE_ENV = 'local';
70
+ afterEach(() => {
71
+ apps?.forEach(app => app.close());
72
+ });
73
+ it('should start apps without options (no loadConfigOptions, no apiModulesOptions)', async () => {
74
+ const apps = await NodeCApp.start([AppModule] as unknown as NestModule[]);
75
+ expect(apps).toHaveLength(1);
76
+ });
77
+ it('should call loadConfig and generateOrmconfig when loadConfigOptions and generateOrmConfig are provided', async () => {
78
+ const generateOrmconfigSpy = vi.spyOn(ConfigProviderService, 'generateOrmconfig');
79
+ const loadConfigSpy = vi.spyOn(ConfigProviderService, 'loadConfig');
80
+ const options: NodeCAppStartOptions = {
81
+ generateOrmConfig: true,
82
+ generateOrmConfigModuleOptions: {
83
+ db: {
84
+ entitiesPathInModule: 'entities',
85
+ migrationsPathInModule: 'migrations',
86
+ modulePathInProject: 'src/data/db'
87
+ }
88
+ },
89
+ loadConfigOptions: appModuleOptions
90
+ };
91
+ apps = await NodeCApp.start([AppModule] as unknown as NestModule[], options);
92
+ // The loadConfig method should be called once with the provided options.
93
+ expect(loadConfigSpy).toHaveBeenCalledTimes(2);
94
+ // For each key in data (here just 1 - "db"), generateOrmconfig should be called.
95
+ expect(generateOrmconfigSpy).toHaveBeenCalledTimes(1);
96
+ expect(apps).toHaveLength(1);
97
+ });
98
+ it('should call loadConfig and generateOrmconfig when loadConfigOptions and generateOrmConfig are provided, but generateOrmConfigModuleOptions are not provided', async () => {
99
+ const generateOrmconfigSpy = vi.spyOn(ConfigProviderService, 'generateOrmconfig');
100
+ const loadConfigSpy = vi.spyOn(ConfigProviderService, 'loadConfig');
101
+ const options: NodeCAppStartOptions = {
102
+ generateOrmConfig: true,
103
+ loadConfigOptions: appModuleOptions
104
+ };
105
+ generateOrmconfigSpy.mockClear();
106
+ loadConfigSpy.mockClear();
107
+ apps = await NodeCApp.start([AppModule] as unknown as NestModule[], options);
108
+ // The loadConfig method should be called once with the provided options.
109
+ expect(loadConfigSpy).toHaveBeenCalledTimes(2);
110
+ // For each key in data (here just 1 - "db"), generateOrmconfig should be called.
111
+ expect(generateOrmconfigSpy).toHaveBeenCalledTimes(1);
112
+ expect(apps).toHaveLength(1);
113
+ });
114
+ it('should configure API server for a module with matching apiModulesOptions', async () => {
115
+ // Provide an apiModulesOptions mapping module index "1" to "test".
116
+ const options: NodeCAppStartOptions = {
117
+ apiModulesOptions: [{ appModuleIndex: 1, apiModuleName: 'test' }],
118
+ loadConfigOptions: {
119
+ appConfigs: appModuleOptions.appConfigs,
120
+ envKeys: { API: { TEST: { HOST: 'hostname', PORT: 'port' } } },
121
+ envKeysParentNames: { API: { children: { TEST: 'test' }, name: 'api' } }
122
+ }
123
+ };
124
+ // Call start with two modules.
125
+ apps = await NodeCApp.start([AppModule, AppModuleWithAPIStartable] as unknown as NestModule[], options);
126
+ expect(apps).toHaveLength(2);
127
+ const response = await fetch('http://localhost:3000');
128
+ expect(response.status).toEqual(404);
129
+ });
130
+ it('should not call app.listen if the API config lacks hostname or port', async () => {
131
+ const options: NodeCAppStartOptions = {
132
+ apiModulesOptions: [{ appModuleIndex: 0, apiModuleName: 'users' }]
133
+ };
134
+ apps = await NodeCApp.start([AppModule, AppModuleWithAPI] as unknown as NestModule[], options);
135
+ expect(apps).toHaveLength(2);
136
+ await expect(fetch('http://localhost:3000')).rejects.toThrow('fetch failed');
137
+ });
138
+ });
package/src/app.ts ADDED
@@ -0,0 +1,120 @@
1
+ import { DynamicModule, INestApplication } from '@nestjs/common';
2
+ import { NestFactory } from '@nestjs/core';
3
+
4
+ import {
5
+ AppConfig,
6
+ AppConfigDataRDB,
7
+ ConfigProviderModuleOptions,
8
+ ConfigProviderService,
9
+ RDBType
10
+ } from './common/configProvider';
11
+ import { LoggerService } from './common/logger';
12
+
13
+ export interface NodeCAppGenerateOrmConfigModuleOptions {
14
+ [moduleName: string]: {
15
+ entitiesPathInModule: string;
16
+ migrationsPathInModule: string;
17
+ modulePathInProject: string;
18
+ };
19
+ }
20
+
21
+ export interface NodeCAppStartOptions {
22
+ apiModulesOptions?: { appModuleIndex: number; apiModuleName: string }[];
23
+ generateOrmConfig?: boolean;
24
+ generateOrmConfigModuleOptions?: NodeCAppGenerateOrmConfigModuleOptions;
25
+ loadConfigOptions?: ConfigProviderModuleOptions;
26
+ }
27
+
28
+ export class NodeCApp {
29
+ // TODO: start each server in a different process
30
+ static async start(
31
+ appModules: DynamicModule[],
32
+ options?: NodeCAppStartOptions
33
+ ): Promise<INestApplication<unknown>[]> {
34
+ console.info(`[Node-C]: Launching ${appModules.length} applications...`);
35
+ const { apiModulesOptions, generateOrmConfig, generateOrmConfigModuleOptions, loadConfigOptions } = options || {};
36
+ const apiModulesOptionsMap = new Map<string, string>();
37
+ const apps: INestApplication<unknown>[] = [];
38
+ let config: AppConfig | undefined;
39
+ // generate the ormconfig.json files for the RDB data modules that use TypeOrm, such as MySQL and PostgreSQL
40
+ if (loadConfigOptions) {
41
+ console.info('[Node-C]: Loading configurations...');
42
+ const { appConfigs, ...otherOptions } = loadConfigOptions;
43
+ config = await ConfigProviderService.loadConfig(appConfigs, otherOptions);
44
+ if (generateOrmConfig) {
45
+ const moduleOptionsPerName = generateOrmConfigModuleOptions || {};
46
+ const { data } = config;
47
+ for (const moduleName in data) {
48
+ const { type } = data[moduleName] as AppConfigDataRDB;
49
+ if (type === RDBType.ClickHouse || !Object.values(RDBType).includes(type as RDBType)) {
50
+ continue;
51
+ }
52
+ await ConfigProviderService.generateOrmconfig(config, {
53
+ ...(moduleOptionsPerName[moduleName] || {
54
+ entitiesPathInModule: 'entities',
55
+ migrationsPathInModule: 'migrations',
56
+ modulePathInProject: `src/data/${moduleName}`,
57
+ seedsPathInModule: 'seeds'
58
+ }),
59
+ moduleName
60
+ });
61
+ }
62
+ }
63
+ console.info('[Node-C]: Configurations loaded.');
64
+ }
65
+ if (apiModulesOptions && apiModulesOptions.length) {
66
+ apiModulesOptions.forEach(item => {
67
+ apiModulesOptionsMap.set(`${item.appModuleIndex}`, item.apiModuleName);
68
+ });
69
+ }
70
+ for (const i in appModules) {
71
+ console.info(`[Node-C]: Preparing app module no. ${i}...`);
72
+ // create the nest app from the module
73
+ const apiModuleName = apiModulesOptionsMap.get(i);
74
+ if (!apiModuleName) {
75
+ console.info(`[Node-C][${i}]: No api module found. Creating standalone app...`);
76
+ const app = await NestFactory.createApplicationContext(appModules[i]);
77
+ app.useLogger(app.get(LoggerService));
78
+ apps.push(app as INestApplication);
79
+ console.info(`[Node-C][${i}]: Standalone created successfully.`);
80
+ continue;
81
+ }
82
+ console.info(`[Node-C][${i}]: Api module found. Creating network app...`);
83
+ const app = await NestFactory.create(appModules[i], { bodyParser: false });
84
+ app.useLogger(app.get(LoggerService));
85
+ console.info(`[Node-C]: Created a network app for module no ${i} (API module name "${apiModuleName}").`);
86
+ // TODO: starting the network app will potentially cause problems, so we can't rely on the config being loaded after the app
87
+ if (!config) {
88
+ config = app.get(ConfigProviderService).config;
89
+ }
90
+ const { api: apiConfigs } = config;
91
+ const apiConfig = apiConfigs[apiModuleName];
92
+ // start an API server, if requested in the options
93
+ if (apiConfig) {
94
+ const { hostname, port } = apiConfig;
95
+ if (hostname && port) {
96
+ console.info(`[Node-C][${i}/${apiModuleName}]: Starting listeners...`);
97
+ // TODO: move the following app.set and app.use to the http module
98
+ // eslint-disable-next-line no-unused-vars
99
+ (app as unknown as { set: (...args: unknown[]) => void }).set('query parser', 'extended');
100
+ app.use((req: { query: unknown }, _res: unknown, next: () => void) => {
101
+ Object.defineProperty(req, 'query', {
102
+ ...Object.getOwnPropertyDescriptor(req, 'query'),
103
+ value: req.query,
104
+ writable: true
105
+ });
106
+ next();
107
+ });
108
+ await app.listen(port as number, hostname as string);
109
+ console.info(`[NODE-C][${i}/${apiModuleName}] Server listening at ${hostname}:${port}.`);
110
+ } else {
111
+ console.info(`[Node-C][${i}/${apiModuleName}]: No listener configuration found.`);
112
+ }
113
+ } else {
114
+ console.info(`[Node-C][${i}/${apiModuleName}]: No API config found.`);
115
+ }
116
+ apps.push(app as INestApplication);
117
+ }
118
+ return apps;
119
+ }
120
+ }
@@ -0,0 +1,444 @@
1
+ import { GenericObject, HttpMethod } from '../definitions';
2
+
3
+ /*
4
+ * This object contains the names of the fields within the modules, by module category.
5
+ */
6
+ export const APP_CONFIG_FROM_ENV_KEYS: AppConfigFromEnvKeys = {
7
+ API: {
8
+ HTTP: {
9
+ API_KEY: 'apiKey',
10
+ API_SECRET: 'apiSecret',
11
+ API_SECRET_ALGORITHM: 'apiSecretAlgorithm',
12
+ HOSTNAME: 'hostname',
13
+ PORT: 'port'
14
+ },
15
+ REST: {
16
+ API_KEY: 'apiKey',
17
+ API_SECRET: 'apiSecret',
18
+ API_SECRET_ALGORITHM: 'apiSecretAlgorithm',
19
+ HOSTNAME: 'hostname',
20
+ PORT: 'port'
21
+ }
22
+ },
23
+ DOMAIN: {
24
+ IAM: {
25
+ JWT_ACCESS_SECRET: 'jwtAccessSecret',
26
+ JWT_REFRESH_SECRET: 'jwtRefreshSecret'
27
+ }
28
+ },
29
+ DATA: {
30
+ NOSQL: {
31
+ HOST: 'host',
32
+ PASSWORD: 'password',
33
+ SENTINEL_PASSWORD: 'sentinelPassword',
34
+ PORT: 'port',
35
+ USER: 'user'
36
+ },
37
+ RDB: {
38
+ DATABASE_NAME: 'database',
39
+ HOST: 'host',
40
+ PASSWORD: 'password',
41
+ PORT: 'port',
42
+ USER: 'user'
43
+ }
44
+ }
45
+ };
46
+
47
+ /*
48
+ * This object contains the names of the module categories and the modules themselves.
49
+ * The module names here are examples, corresponding to the object above.
50
+ * In order for this to work, each module in the .env files should have a key ending with
51
+ * _MODULE_TYPE, whose value correesponds to the values define in the 'children' here.
52
+ */
53
+ export const APP_CONFIG_FROM_ENV_KEYS_PARENT_NAMES: AppConfigFromEnvKeysParentNames = {
54
+ API: {
55
+ children: {
56
+ HTTP: 'http',
57
+ REST: 'rest'
58
+ },
59
+ name: 'api'
60
+ },
61
+ DOMAIN: {
62
+ children: {
63
+ IAM: 'iam'
64
+ },
65
+ name: 'domain'
66
+ },
67
+ DATA: {
68
+ children: {
69
+ DB: 'db',
70
+ REDIS: 'redis',
71
+ VALKEY: 'valkey'
72
+ },
73
+ name: 'data'
74
+ }
75
+ };
76
+
77
+ type AppConfigIntermediate = AppConfigCommon & AppConfigProfile & AppConfigFromEnv;
78
+ export type AppConfig = AppConfigIntermediate & Required<Pick<AppConfigIntermediate, 'api'>>;
79
+ type AppConfigAPIHTTPIntermediate = AppConfigCommonAPIHTTP & AppConfigFromEnvAPIHTTP;
80
+ export type AppConfigAPIHTTP = AppConfigAPIHTTPIntermediate &
81
+ Required<Pick<AppConfigAPIHTTPIntermediate, 'allowedOrigins' | 'anonymousAccessRoutes' | 'hostname' | 'port'>>;
82
+ export type AppConfigAPIREST = AppConfigCommonAPIREST & AppConfigFromEnvAPIREST;
83
+
84
+ export type AppConfigDomainIAM = AppConfigCommonDomainIAM & AppConfigFromEnvDomainIAM & AppConfigProfileDomainIAM;
85
+
86
+ export enum AppConfigDomainIAMAuthenticationStep {
87
+ // eslint-disable-next-line no-unused-vars
88
+ Complete = 'complete',
89
+ // eslint-disable-next-line no-unused-vars
90
+ Initiate = 'initiate'
91
+ }
92
+
93
+ export type AppConfigDataNoSQL = AppConfigCommonDataNoSQL & AppConfigFromEnvDataNoSQL & AppConfigProfileDataNoSQL;
94
+ export type AppConfigDataRDB = AppConfigCommonDataClickHouse &
95
+ AppConfigCommonDataRDB &
96
+ AppConfigCommonDataClickHouse &
97
+ AppConfigFromEnvDataRDB &
98
+ AppConfigProfileDataClickHouse &
99
+ AppConfigProfileDataRDB;
100
+
101
+ /*
102
+ * Config data held in the common config file.
103
+ */
104
+
105
+ export interface AppConfigCommon {
106
+ api?: { [apiName: string]: GenericObject | AppConfigCommonAPIHTTP | AppConfigCommonAPIREST };
107
+ domain: { [domainName: string]: GenericObject | AppConfigCommonDomainIAM };
108
+ general: {
109
+ projectName: string;
110
+ projectRootPath: string;
111
+ projectVersion: string;
112
+ };
113
+ data: {
114
+ [moduleName: string]:
115
+ | GenericObject
116
+ | AppConfigCommonDataClickHouse
117
+ | AppConfigCommonDataNoSQL
118
+ | AppConfigCommonDataRDB;
119
+ };
120
+ }
121
+
122
+ export interface AppConfigCommonAPIHTTP {
123
+ allowedOrigins?: string[];
124
+ anonymousAccessRoutes?: Record<string, HttpMethod[]>;
125
+ endpointSecurityMode?: EndpointSecurityMode;
126
+ hostname?: string;
127
+ port?: number;
128
+ }
129
+ export type AppConfigCommonAPIREST = AppConfigCommonAPIHTTP;
130
+
131
+ export interface AppConfigCommonDomainIAM {
132
+ accessTokenExpiryTimeInMinutes?: number;
133
+ authServiceSettings?: GenericObject<{
134
+ secretKey?: {
135
+ secretKeyHMACAlgorithm?: string;
136
+ };
137
+ oauth2?: {
138
+ accessTokenAudiences?: string[];
139
+ accessTokenEmailField?: string;
140
+ accessTokenGrantUrl?: string;
141
+ authorizationUrl?: string;
142
+ codeChallengeMethod: string; // code_challenge_method
143
+ defaultScope?: string;
144
+ issuerUri?: string;
145
+ redirectUri?: string; // redirect_uri
146
+ verifyTokensLocally?: boolean;
147
+ };
148
+ processExternalTokensOnVerify?: boolean;
149
+ steps: AppConfigCommonDomainIAMAuthServiceConfigStepSettings;
150
+ }>;
151
+ defaultUserIdentifierField: string;
152
+ refreshTokenExpiryTimeInMinutes?: number;
153
+ }
154
+
155
+ export interface AppConfigCommonDomainIAMAuthServiceConfigBaseStepSettings {
156
+ findUser?: boolean;
157
+ findUserBeforeAuth?: boolean;
158
+ stepResultPublicFields?: string[];
159
+ validWithoutUser?: boolean;
160
+ }
161
+
162
+ export interface AppConfigCommonDomainIAMAuthServiceConfigCacheSettings {
163
+ cacheFieldName: string;
164
+ inputFieldName: string;
165
+ }
166
+
167
+ export interface AppConfigCommonDomainIAMAuthServiceConfigCachePopulationSettings {
168
+ data?: boolean | AppConfigCommonDomainIAMAuthServiceConfigCacheSettings[];
169
+ options?: boolean | AppConfigCommonDomainIAMAuthServiceConfigCacheSettings[];
170
+ result?: boolean | AppConfigCommonDomainIAMAuthServiceConfigCacheSettings[];
171
+ }
172
+
173
+ export interface AppConfigCommonDomainIAMAuthServiceConfigCacheUsageSettings {
174
+ data?: AppConfigCommonDomainIAMAuthServiceConfigCacheUsageSettingsItem;
175
+ options?: AppConfigCommonDomainIAMAuthServiceConfigCacheUsageSettingsItem;
176
+ result?: AppConfigCommonDomainIAMAuthServiceConfigCacheUsageSettingsItem;
177
+ }
178
+
179
+ export interface AppConfigCommonDomainIAMAuthServiceConfigCacheUsageSettingsItem {
180
+ overwrite?: boolean;
181
+ use: boolean;
182
+ }
183
+
184
+ export interface AppConfigCommonDomainIAMAuthServiceConfigCompleteSettings extends AppConfigCommonDomainIAMAuthServiceConfigBaseStepSettings {
185
+ authReturnsTokens?: boolean;
186
+ cache?: {
187
+ settings: AppConfigCommonDomainIAMAuthServiceConfigCacheSettings;
188
+ use?: AppConfigCommonDomainIAMAuthServiceConfigCacheUsageSettings;
189
+ };
190
+ createUser?: boolean;
191
+ decodeReturnedTokens?: boolean;
192
+ findUserInAuthResultBy?: { userFieldName: string; resultFieldName: string };
193
+ useReturnedTokens?: boolean;
194
+ }
195
+
196
+ export interface AppConfigCommonDomainIAMAuthServiceConfigInitiateSettings extends AppConfigCommonDomainIAMAuthServiceConfigBaseStepSettings {
197
+ cache?: {
198
+ populate?: AppConfigCommonDomainIAMAuthServiceConfigCachePopulationSettings;
199
+ settings: AppConfigCommonDomainIAMAuthServiceConfigCacheSettings;
200
+ };
201
+ }
202
+
203
+ export interface AppConfigCommonDomainIAMAuthServiceConfigStepSettings {
204
+ [AppConfigDomainIAMAuthenticationStep.Complete]: AppConfigCommonDomainIAMAuthServiceConfigCompleteSettings;
205
+ [AppConfigDomainIAMAuthenticationStep.Initiate]: AppConfigCommonDomainIAMAuthServiceConfigInitiateSettings;
206
+ }
207
+
208
+ export type AppConfigCommonData = {
209
+ failOnConnectionError?: boolean;
210
+ settingsPerEntity?: Record<string, AppConfigCommonDataEntityServiceSettings>;
211
+ } & AppConfigCommonDataEntityServiceSettings;
212
+
213
+ export interface AppConfigCommonDataEntityServiceSettings {
214
+ processFiltersAllowedFieldsEnabled?: boolean;
215
+ processInputAllowedFieldsEnabled?: boolean;
216
+ }
217
+
218
+ export interface AppConfigCommonDataClickHouse extends AppConfigCommonData {
219
+ application?: string;
220
+ requestTimeout?: number;
221
+ type: RDBType;
222
+ useHostParam?: boolean;
223
+ }
224
+
225
+ export interface AppConfigCommonDataNoSQL extends AppConfigCommonData {
226
+ clusterMode?: boolean;
227
+ defaultIndividualSearchEnabled?: boolean;
228
+ defaultTTL?: number;
229
+ sentinelMasterName?: string;
230
+ sentinelMode?: boolean;
231
+ sentinelRole?: 'master' | 'slave';
232
+ storeDelimiter?: string;
233
+ storeKey: string;
234
+ settingsPerEntity?: Record<string, AppConfigCommonDataNoSQLEntityServiceSettings>;
235
+ type: NoSQLType;
236
+ useHashmap?: boolean;
237
+ usePasswordForSentinelPassword?: boolean;
238
+ validationSettings?: AppConfigCommonDataNoSQLValidationSettings;
239
+ }
240
+
241
+ export interface AppConfigCommonDataNoSQLEntityServiceSettings extends AppConfigCommonDataEntityServiceSettings {
242
+ defaultIndividualSearchEnabled?: boolean;
243
+ ttl?: number;
244
+ validationSettings?: AppConfigCommonDataNoSQLValidationSettings;
245
+ }
246
+
247
+ export interface AppConfigCommonDataNoSQLValidationSettings {
248
+ throwErrorOnExtraProperies?: boolean;
249
+ isEnabled?: boolean;
250
+ whitelistProperties?: boolean;
251
+ }
252
+
253
+ export interface AppConfigCommonDataRDB extends AppConfigCommonData {
254
+ connectionName: string;
255
+ type: RDBType;
256
+ }
257
+
258
+ /*
259
+ * Config data coming from env files.
260
+ */
261
+
262
+ export interface AppConfigFromEnv {
263
+ api?: { [apiName: string]: GenericObject | AppConfigFromEnvAPIHTTP | AppConfigFromEnvAPIREST };
264
+ domain?: { [domainName: string]: GenericObject | AppConfigFromEnvDomainIAM };
265
+ data?: {
266
+ [moduleName: string]: GenericObject | AppConfigFromEnvDataNoSQL | AppConfigFromEnvDataRDB;
267
+ };
268
+ }
269
+
270
+ export interface AppConfigFromEnvAPIHTTP extends AppConfigCommonAPIHTTP {
271
+ apiKey?: string;
272
+ apiSecret?: string;
273
+ apiSecretAlgorithm?: string;
274
+ }
275
+
276
+ export type AppConfigFromEnvAPIREST = AppConfigFromEnvAPIHTTP;
277
+
278
+ export interface AppConfigFromEnvDomainIAM {
279
+ jwtAccessSecret: string;
280
+ jwtRefreshSecret: string;
281
+ authServiceSettings?: GenericObject<{
282
+ secretKey?: {
283
+ hashingSecret?: string;
284
+ };
285
+ oauth2?: {
286
+ clientId: string; // client_id
287
+ clientSecret: string; // client_secret
288
+ };
289
+ }>;
290
+ }
291
+
292
+ export interface AppConfigFromEnvKeys {
293
+ [moduleCategory: string]: {
294
+ [moduleType: string]: Record<string, string>;
295
+ };
296
+ }
297
+
298
+ export interface AppConfigFromEnvKeysParentNames {
299
+ [moduleCategory: string]: {
300
+ children: Record<string, string>;
301
+ name: string;
302
+ };
303
+ }
304
+
305
+ export interface AppConfigFromEnvDataNoSQL {
306
+ host: string;
307
+ password: string;
308
+ port: number;
309
+ sentinelPassword?: string;
310
+ user?: string;
311
+ }
312
+
313
+ export interface AppConfigFromEnvDataRDB {
314
+ database: string;
315
+ host: string;
316
+ password: string;
317
+ port: number;
318
+ user: string;
319
+ }
320
+
321
+ /*
322
+ * Config data coming from configProfile files.
323
+ */
324
+
325
+ export interface AppConfigProfile {
326
+ api?: { [apiName: string]: GenericObject | AppConfigProfileAPIHTTP | AppConfigProfileAPIREST };
327
+ domain?: { [domainName: string]: GenericObject | AppConfigProfileDomainIAM };
328
+ general: {
329
+ environment: AppEnvironment;
330
+ projectName?: string;
331
+ projectVersion?: string;
332
+ };
333
+ data?: {
334
+ [dataModuleName: string]:
335
+ | GenericObject
336
+ | AppConfigProfileDataClickHouse
337
+ | AppConfigProfileDataNoSQL
338
+ | AppConfigProfileDataRDB;
339
+ };
340
+ }
341
+
342
+ export type AppConfigProfileAPIHTTP = AppConfigCommonAPIHTTP;
343
+ export type AppConfigProfileAPIREST = AppConfigProfileAPIHTTP;
344
+
345
+ export interface AppConfigProfileDomainIAM {
346
+ accessTokenExpiryTimeInMinutes?: number;
347
+ authServiceSettings?: GenericObject<{
348
+ oauth2?: {
349
+ accessTokenAudiences?: string[];
350
+ accessTokenEmailField?: string;
351
+ accessTokenGrantUrl?: string;
352
+ authorizationUrl?: string;
353
+ codeChallengeMethod: string; // code_challenge_method
354
+ defaultScope?: string;
355
+ issuerUri?: string;
356
+ redirectUri?: string; // redirect_uri
357
+ verifyTokensLocally?: boolean;
358
+ };
359
+ processExternalTokensOnVerify?: boolean;
360
+ }>;
361
+ refreshTokenExpiryTimeInMinutes?: number;
362
+ }
363
+
364
+ export type AppConfigProfileDataClickHouse = AppConfigCommonDataClickHouse & {
365
+ protocol?: string;
366
+ };
367
+ export type AppConfigProfileDataNoSQL = AppConfigCommonDataNoSQL;
368
+ export type AppConfigProfileDataRDB = AppConfigCommonDataRDB & {
369
+ typeormExtraOptions?: GenericObject;
370
+ };
371
+
372
+ export enum AppEnvironment {
373
+ // eslint-disable-next-line no-unused-vars
374
+ Development = 'development',
375
+ // eslint-disable-next-line no-unused-vars
376
+ Local = 'local',
377
+ // eslint-disable-next-line no-unused-vars
378
+ Production = 'production',
379
+ // eslint-disable-next-line no-unused-vars
380
+ Staging = 'staging',
381
+ // eslint-disable-next-line no-unused-vars
382
+ Test = 'endToEndTests'
383
+ }
384
+
385
+ /*
386
+ * Other config-related definitions.
387
+ */
388
+
389
+ export interface ConfigProviderModuleOptions extends LoadConfigOptions {
390
+ appConfigs: LoadConfigAppConfigs;
391
+ }
392
+
393
+ // TODO: figure out how to move this to the Domain-IAM package
394
+ export enum EndpointSecurityMode {
395
+ // eslint-disable-next-line no-unused-vars
396
+ Lax = 'lax',
397
+ // eslint-disable-next-line no-unused-vars
398
+ Strict = 'strict'
399
+ }
400
+
401
+ export interface GenerateOrmconfigOptions {
402
+ entitiesPathInModule: string;
403
+ migrationsPathInModule: string;
404
+ moduleName: string;
405
+ modulePathInProject: string;
406
+ seedsPathInModule?: string;
407
+ }
408
+
409
+ // TODO: figure out how to move this to the Redis package
410
+ export enum NoSQLType {
411
+ // eslint-disable-next-line no-unused-vars
412
+ Redis = 'redis',
413
+ // eslint-disable-next-line no-unused-vars
414
+ Valkey = 'valkey'
415
+ }
416
+
417
+ // TODO: figure out how to move this to the RDB package
418
+ export enum RDBType {
419
+ // eslint-disable-next-line no-unused-vars
420
+ Aurora = 'aurora',
421
+ // eslint-disable-next-line no-unused-vars
422
+ ClickHouse = 'clickhouse',
423
+ // eslint-disable-next-line no-unused-vars
424
+ MySQL = 'mysql',
425
+ // eslint-disable-next-line no-unused-vars
426
+ PG = 'postgres'
427
+ }
428
+
429
+ export type LoadConfigAppConfigs<
430
+ AppConfigCommonType extends AppConfigCommon = AppConfigCommon,
431
+ AppConfigProfileType extends AppConfigProfile = AppConfigProfile
432
+ > =
433
+ | {
434
+ appConfigCommon: AppConfigCommonType;
435
+ }
436
+ | GenericObject<AppConfigProfileType>;
437
+
438
+ export interface LoadConfigOptions {
439
+ envKeys?: AppConfigFromEnvKeys;
440
+ envKeysParentNames?: AppConfigFromEnvKeysParentNames;
441
+ envName?: AppEnvironment;
442
+ useEnvFile?: boolean;
443
+ useEnvFileWithPriority?: boolean;
444
+ }