@itgorillaz/configify 1.1.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/.prettierrc +4 -0
- package/LICENSE +21 -0
- package/README.md +281 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/src/configify.module.d.ts +12 -0
- package/dist/src/configify.module.js +120 -0
- package/dist/src/configify.module.js.map +1 -0
- package/dist/src/configuration/configuration-options.interface.d.ts +11 -0
- package/dist/src/configuration/configuration-options.interface.js +9 -0
- package/dist/src/configuration/configuration-options.interface.js.map +1 -0
- package/dist/src/configuration/configuration-parser.interface.d.ts +3 -0
- package/dist/src/configuration/configuration-parser.interface.js +3 -0
- package/dist/src/configuration/configuration-parser.interface.js.map +1 -0
- package/dist/src/configuration/configuration-providers.interface.d.ts +5 -0
- package/dist/src/configuration/configuration-providers.interface.js +3 -0
- package/dist/src/configuration/configuration-providers.interface.js.map +1 -0
- package/dist/src/configuration/configuration.registry.d.ts +9 -0
- package/dist/src/configuration/configuration.registry.js +25 -0
- package/dist/src/configuration/configuration.registry.js.map +1 -0
- package/dist/src/configuration/index.d.ts +6 -0
- package/dist/src/configuration/index.js +23 -0
- package/dist/src/configuration/index.js.map +1 -0
- package/dist/src/configuration/parsers/configuration-parser.factory.d.ts +7 -0
- package/dist/src/configuration/parsers/configuration-parser.factory.js +27 -0
- package/dist/src/configuration/parsers/configuration-parser.factory.js.map +1 -0
- package/dist/src/configuration/parsers/dotenv-configuration.parser.d.ts +4 -0
- package/dist/src/configuration/parsers/dotenv-configuration.parser.js +12 -0
- package/dist/src/configuration/parsers/dotenv-configuration.parser.js.map +1 -0
- package/dist/src/configuration/parsers/index.d.ts +4 -0
- package/dist/src/configuration/parsers/index.js +21 -0
- package/dist/src/configuration/parsers/index.js.map +1 -0
- package/dist/src/configuration/parsers/json-configuration.parser.d.ts +4 -0
- package/dist/src/configuration/parsers/json-configuration.parser.js +11 -0
- package/dist/src/configuration/parsers/json-configuration.parser.js.map +1 -0
- package/dist/src/configuration/parsers/yaml-configuration.parser.d.ts +4 -0
- package/dist/src/configuration/parsers/yaml-configuration.parser.js +12 -0
- package/dist/src/configuration/parsers/yaml-configuration.parser.js.map +1 -0
- package/dist/src/configuration/resolvers/aws/index.d.ts +2 -0
- package/dist/src/configuration/resolvers/aws/index.js +19 -0
- package/dist/src/configuration/resolvers/aws/index.js.map +1 -0
- package/dist/src/configuration/resolvers/aws/parameter-store-configuration.resolver.d.ts +12 -0
- package/dist/src/configuration/resolvers/aws/parameter-store-configuration.resolver.js +61 -0
- package/dist/src/configuration/resolvers/aws/parameter-store-configuration.resolver.js.map +1 -0
- package/dist/src/configuration/resolvers/aws/secrets-manager-configuration.resolver.d.ts +12 -0
- package/dist/src/configuration/resolvers/aws/secrets-manager-configuration.resolver.js +59 -0
- package/dist/src/configuration/resolvers/aws/secrets-manager-configuration.resolver.js.map +1 -0
- package/dist/src/configuration/resolvers/configuration-resolver.interface.d.ts +3 -0
- package/dist/src/configuration/resolvers/configuration-resolver.interface.js +3 -0
- package/dist/src/configuration/resolvers/configuration-resolver.interface.js.map +1 -0
- package/dist/src/configuration/resolvers/index.d.ts +3 -0
- package/dist/src/configuration/resolvers/index.js +20 -0
- package/dist/src/configuration/resolvers/index.js.map +1 -0
- package/dist/src/configuration/resolvers/resolved-value.interface.d.ts +7 -0
- package/dist/src/configuration/resolvers/resolved-value.interface.js +3 -0
- package/dist/src/configuration/resolvers/resolved-value.interface.js.map +1 -0
- package/dist/src/decorators/configuration.decorator.d.ts +2 -0
- package/dist/src/decorators/configuration.decorator.js +13 -0
- package/dist/src/decorators/configuration.decorator.js.map +1 -0
- package/dist/src/decorators/index.d.ts +2 -0
- package/dist/src/decorators/index.js +19 -0
- package/dist/src/decorators/index.js.map +1 -0
- package/dist/src/decorators/value.decorator.d.ts +10 -0
- package/dist/src/decorators/value.decorator.js +14 -0
- package/dist/src/decorators/value.decorator.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +19 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/interpolation/variables.d.ts +9 -0
- package/dist/src/interpolation/variables.js +37 -0
- package/dist/src/interpolation/variables.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/index.d.ts +1 -0
- package/index.js +6 -0
- package/index.ts +1 -0
- package/nest-cli.json +8 -0
- package/package.json +82 -0
- package/src/configify.module.ts +241 -0
- package/src/configuration/configuration-options.interface.ts +51 -0
- package/src/configuration/configuration-parser.interface.ts +15 -0
- package/src/configuration/configuration-providers.interface.ts +9 -0
- package/src/configuration/configuration.registry.ts +70 -0
- package/src/configuration/index.ts +6 -0
- package/src/configuration/parsers/configuration-parser.factory.ts +53 -0
- package/src/configuration/parsers/dotenv-configuration.parser.ts +18 -0
- package/src/configuration/parsers/index.ts +4 -0
- package/src/configuration/parsers/json-configuration.parser.ts +17 -0
- package/src/configuration/parsers/yaml-configuration.parser.ts +18 -0
- package/src/configuration/resolvers/aws/index.ts +2 -0
- package/src/configuration/resolvers/aws/parameter-store-configuration.resolver.ts +115 -0
- package/src/configuration/resolvers/aws/secrets-manager-configuration.resolver.ts +117 -0
- package/src/configuration/resolvers/configuration-resolver.interface.ts +11 -0
- package/src/configuration/resolvers/index.ts +3 -0
- package/src/configuration/resolvers/resolved-value.interface.ts +10 -0
- package/src/decorators/configuration.decorator.ts +26 -0
- package/src/decorators/index.ts +2 -0
- package/src/decorators/value.decorator.ts +47 -0
- package/src/index.ts +2 -0
- package/src/interpolation/variables.ts +101 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +21 -0
package/index.js
ADDED
package/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './src';
|
package/nest-cli.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@itgorillaz/configify",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "NestJS Config on Steroids",
|
|
5
|
+
"author": "tommelo",
|
|
6
|
+
"private": false,
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/it-gorillaz/configify.git"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"nestjs",
|
|
14
|
+
"config",
|
|
15
|
+
"yml",
|
|
16
|
+
".env"
|
|
17
|
+
],
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/it-gorillaz/configify/issues"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/it-gorillaz/configify#readme",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "nest build",
|
|
24
|
+
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
25
|
+
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
|
26
|
+
"test": "jest --config ./test/jest.config.json --coverage --silent=false --verbose --runInBand"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"dotenv": "^16.3.1",
|
|
30
|
+
"js-yaml": "^4.1.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@aws-sdk/client-secrets-manager": "^3.454.0",
|
|
34
|
+
"@aws-sdk/client-ssm": "^3.461.0",
|
|
35
|
+
"@nestjs/common": "^9.0.0 || ^10.0.0",
|
|
36
|
+
"@nestjs/core": "^9.0.0 || ^10.0.0",
|
|
37
|
+
"class-validator": "^0.14.0",
|
|
38
|
+
"reflect-metadata": "^0.1.13 || ^0.2.0",
|
|
39
|
+
"rxjs": "^7.2.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@nestjs/cli": "^10.3.2",
|
|
43
|
+
"@nestjs/schematics": "^10.1.1",
|
|
44
|
+
"@nestjs/testing": "^10.3.7",
|
|
45
|
+
"@types/jest": "29.5.12",
|
|
46
|
+
"@types/js-yaml": "^4.0.9",
|
|
47
|
+
"@types/node": "20.12.2",
|
|
48
|
+
"@types/supertest": "^6.0.2",
|
|
49
|
+
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
|
50
|
+
"@typescript-eslint/parser": "^7.4.0",
|
|
51
|
+
"eslint": "^8.0.1",
|
|
52
|
+
"eslint-config-prettier": "^9.1.0",
|
|
53
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
54
|
+
"jest": "29.7.0",
|
|
55
|
+
"prettier": "^3.2.5",
|
|
56
|
+
"prettier-plugin-organize-imports": "^3.2.4",
|
|
57
|
+
"source-map-support": "^0.5.20",
|
|
58
|
+
"supertest": "^6.1.3",
|
|
59
|
+
"ts-jest": "29.1.2",
|
|
60
|
+
"ts-loader": "^9.2.3",
|
|
61
|
+
"ts-node": "^10.0.0",
|
|
62
|
+
"tsconfig-paths": "4.2.0",
|
|
63
|
+
"typescript": "^5.4.3"
|
|
64
|
+
},
|
|
65
|
+
"jest": {
|
|
66
|
+
"moduleFileExtensions": [
|
|
67
|
+
"js",
|
|
68
|
+
"json",
|
|
69
|
+
"ts"
|
|
70
|
+
],
|
|
71
|
+
"rootDir": "src",
|
|
72
|
+
"testRegex": ".*\\.spec\\.ts$",
|
|
73
|
+
"transform": {
|
|
74
|
+
"^.+\\.(t|j)s$": "ts-jest"
|
|
75
|
+
},
|
|
76
|
+
"collectCoverageFrom": [
|
|
77
|
+
"**/*.(t|j)s"
|
|
78
|
+
],
|
|
79
|
+
"coverageDirectory": "../coverage",
|
|
80
|
+
"testEnvironment": "node"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { SecretsManagerClient } from '@aws-sdk/client-secrets-manager';
|
|
2
|
+
import { SSMClient } from '@aws-sdk/client-ssm';
|
|
3
|
+
import { DynamicModule, Module, Provider } from '@nestjs/common';
|
|
4
|
+
import { validateSync } from 'class-validator';
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import { resolve } from 'path';
|
|
7
|
+
import {
|
|
8
|
+
AwsSecretsManagerConfigurationResolver,
|
|
9
|
+
ConfigfyModuleOptions,
|
|
10
|
+
ConfigurationParserFactory,
|
|
11
|
+
ConfigurationProviders,
|
|
12
|
+
ConfigurationRegistry,
|
|
13
|
+
DefaultConfigfyModuleOptions,
|
|
14
|
+
} from './configuration';
|
|
15
|
+
import { AwsParameterStoreConfigurationResolver } from './configuration/resolvers/aws/parameter-store-configuration.resolver';
|
|
16
|
+
import { Variables } from './interpolation/variables';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The configify module.
|
|
20
|
+
* A NestJS configuration module on steroids.
|
|
21
|
+
*
|
|
22
|
+
* This module provides out of the box configuration files parsing,
|
|
23
|
+
* remote secrets fetching, variables expansion and configuration validation.
|
|
24
|
+
*
|
|
25
|
+
* The lifecycle of the module consists of:
|
|
26
|
+
* - Reading configuration files
|
|
27
|
+
* - Resolving remote secrets
|
|
28
|
+
* - Expanding variables
|
|
29
|
+
* - Creating object instances decored with Configuration and assigning its values
|
|
30
|
+
* - Validating the configuration instance
|
|
31
|
+
*
|
|
32
|
+
* All the configuration set to the configuration files will be assigned to the process.env object
|
|
33
|
+
*/
|
|
34
|
+
@Module({})
|
|
35
|
+
export class ConfigifyModule {
|
|
36
|
+
/**
|
|
37
|
+
* The default configuration files.
|
|
38
|
+
* If no configuration files are provided this module will
|
|
39
|
+
* lookup at a .env, application.yml and an application.json files
|
|
40
|
+
* at the root path of the project.
|
|
41
|
+
*/
|
|
42
|
+
private static readonly DEFAULT_CONFIG_FILES = [
|
|
43
|
+
resolve(process.cwd(), '.env'),
|
|
44
|
+
resolve(process.cwd(), 'application.yml'),
|
|
45
|
+
resolve(process.cwd(), 'application.json'),
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The remote secrets resolvers pipeline.
|
|
50
|
+
* This module currently supports resolving secrets on
|
|
51
|
+
* AWS Secrets Manager and AWS Parameters Store.
|
|
52
|
+
*/
|
|
53
|
+
private static readonly SECRETS_RESOLVER_PIPELINE = [
|
|
54
|
+
(options: ConfigfyModuleOptions) =>
|
|
55
|
+
new AwsSecretsManagerConfigurationResolver(
|
|
56
|
+
options.secretsManagerClient || new SecretsManagerClient(),
|
|
57
|
+
),
|
|
58
|
+
|
|
59
|
+
(options: ConfigfyModuleOptions) =>
|
|
60
|
+
new AwsParameterStoreConfigurationResolver(
|
|
61
|
+
options.ssmClient || new SSMClient(),
|
|
62
|
+
),
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Creates the configfy dynamic module.
|
|
67
|
+
*
|
|
68
|
+
* The module will manage the instance of all classes decorated the Configuration decorator,
|
|
69
|
+
* meaning, the module will instanciate and associate the value to attributes according to the
|
|
70
|
+
* keys provided by the Value decorator.
|
|
71
|
+
*
|
|
72
|
+
* The configuration key pair values will also be available on process.env object.
|
|
73
|
+
*
|
|
74
|
+
* @param { ConfigfyModuleOptions } options The module config options
|
|
75
|
+
* @returns { DynamicModule } module The configy module
|
|
76
|
+
*/
|
|
77
|
+
static async forRootAsync(
|
|
78
|
+
options: ConfigfyModuleOptions = {},
|
|
79
|
+
): Promise<DynamicModule> {
|
|
80
|
+
const settings = { ...options, ...DefaultConfigfyModuleOptions };
|
|
81
|
+
const files = this.resolveConfigurationFiles(settings.configFilePath);
|
|
82
|
+
|
|
83
|
+
const envVars = settings.ignoreEnvVars ? {} : process.env;
|
|
84
|
+
const fromFile = settings.ignoreConfigFile
|
|
85
|
+
? {}
|
|
86
|
+
: this.parseConfigurationFiles(files);
|
|
87
|
+
|
|
88
|
+
const container = { ...envVars, ...fromFile };
|
|
89
|
+
const secrets = await this.runSecretsResolverPipeline(container, settings);
|
|
90
|
+
const configuration = { ...container, ...secrets };
|
|
91
|
+
|
|
92
|
+
if (settings.expandConfig) {
|
|
93
|
+
const expanded = Variables.expand(configuration);
|
|
94
|
+
Object.assign(configuration, expanded);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
Object.assign(process.env, configuration);
|
|
98
|
+
|
|
99
|
+
const { exports, providers } = this.buildConfigurationProviders();
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
exports,
|
|
103
|
+
providers,
|
|
104
|
+
global: true,
|
|
105
|
+
module: ConfigifyModule,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Runs the secrets resolver pipeline.
|
|
111
|
+
*
|
|
112
|
+
* @param {Record<string, any>} config the configuration object
|
|
113
|
+
* @param {ConfigfyModuleOptions} options the module options
|
|
114
|
+
* @returns {Promise<Record<string, any>>} the resolved secrets
|
|
115
|
+
*/
|
|
116
|
+
private static async runSecretsResolverPipeline(
|
|
117
|
+
config: Record<string, any>,
|
|
118
|
+
options: ConfigfyModuleOptions,
|
|
119
|
+
): Promise<Record<string, any>> {
|
|
120
|
+
const secrets = {};
|
|
121
|
+
for (const buildResolver of this.SECRETS_RESOLVER_PIPELINE) {
|
|
122
|
+
const resolver = buildResolver(options);
|
|
123
|
+
const result = await resolver.resolve(config);
|
|
124
|
+
Object.assign(secrets, result);
|
|
125
|
+
}
|
|
126
|
+
return secrets;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Creates the configuration module providers.
|
|
131
|
+
* It creates the configuration instances, assign its value
|
|
132
|
+
* and perform the object validation.
|
|
133
|
+
*
|
|
134
|
+
* @returns {ConfigurationProviders} the module configuration providers
|
|
135
|
+
*/
|
|
136
|
+
private static buildConfigurationProviders(): ConfigurationProviders {
|
|
137
|
+
const exports = [];
|
|
138
|
+
const providers: Provider[] = [];
|
|
139
|
+
|
|
140
|
+
const registry = ConfigurationRegistry.getRegistry();
|
|
141
|
+
for (const ConfigType of registry) {
|
|
142
|
+
const instance = new ConfigType();
|
|
143
|
+
|
|
144
|
+
const attributes =
|
|
145
|
+
ConfigurationRegistry.getValueDecoratedAttributes(instance);
|
|
146
|
+
|
|
147
|
+
for (const attribute of attributes) {
|
|
148
|
+
const metadata = ConfigurationRegistry.getValueDecoratedKey(
|
|
149
|
+
instance,
|
|
150
|
+
attribute,
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const parse = metadata.options?.parse;
|
|
154
|
+
const value = parse
|
|
155
|
+
? parse(process.env[metadata.key])
|
|
156
|
+
: process.env[metadata.key];
|
|
157
|
+
|
|
158
|
+
instance[attribute] = value;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const errors = validateSync(instance);
|
|
162
|
+
if (errors && errors.length) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`validation constraints violated:\n${errors
|
|
165
|
+
.map((e) =>
|
|
166
|
+
JSON.stringify(
|
|
167
|
+
{ attribute: e.property, constraints: e.constraints },
|
|
168
|
+
null,
|
|
169
|
+
2,
|
|
170
|
+
),
|
|
171
|
+
)
|
|
172
|
+
.join('\n')}`,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
exports.push(ConfigType);
|
|
177
|
+
providers.push({ provide: ConfigType, useValue: instance });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return { exports, providers };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Flattens a nested object into an one level key value pair object
|
|
185
|
+
*
|
|
186
|
+
* @param {object} source the source object
|
|
187
|
+
* @param {string[]} path the key path
|
|
188
|
+
* @param {Record<string, any>} target the target object
|
|
189
|
+
*/
|
|
190
|
+
private static flattenObjectKeys(
|
|
191
|
+
source: any,
|
|
192
|
+
path: string[] = [],
|
|
193
|
+
target: Record<string, any> = {},
|
|
194
|
+
) {
|
|
195
|
+
if (typeof source === 'object') {
|
|
196
|
+
for (const key in source) {
|
|
197
|
+
this.flattenObjectKeys(source[key], [...path, key], target);
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
target[path.join('.')] = source;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Parses configuration files and assign its contents to a configuration object.
|
|
206
|
+
*
|
|
207
|
+
* @param {string[]} files the configuration file paths
|
|
208
|
+
* @returns {object} the object representation of the configuration files
|
|
209
|
+
*/
|
|
210
|
+
private static parseConfigurationFiles(files: string[]): Record<string, any> {
|
|
211
|
+
const kv = {};
|
|
212
|
+
const config = {};
|
|
213
|
+
|
|
214
|
+
for (const file of files) {
|
|
215
|
+
const parser = ConfigurationParserFactory.getParser(file);
|
|
216
|
+
const parsed = parser.parse(file);
|
|
217
|
+
Object.assign(config, parsed);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
this.flattenObjectKeys(config, [], kv);
|
|
221
|
+
|
|
222
|
+
return kv;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Resolve the path of the configuration files.
|
|
227
|
+
* It ignores files that does not exist or is not
|
|
228
|
+
* suppported by the configuration parsers.
|
|
229
|
+
*
|
|
230
|
+
* @param {string | string[]} path the configuration path
|
|
231
|
+
* @returns {string[]} list of configuration files
|
|
232
|
+
*/
|
|
233
|
+
private static resolveConfigurationFiles(path?: string | string[]): string[] {
|
|
234
|
+
return []
|
|
235
|
+
.concat(path, this.DEFAULT_CONFIG_FILES)
|
|
236
|
+
.filter(
|
|
237
|
+
(file) =>
|
|
238
|
+
fs.existsSync(file) && ConfigurationParserFactory.supports(file),
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { SecretsManagerClient } from '@aws-sdk/client-secrets-manager';
|
|
2
|
+
import { SSMClient } from '@aws-sdk/client-ssm';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The configuration options interface
|
|
6
|
+
*/
|
|
7
|
+
export interface ConfigfyModuleOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Ignores any config file.
|
|
10
|
+
* The default value is false;
|
|
11
|
+
*/
|
|
12
|
+
ignoreConfigFile?: boolean;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Ignores environment variables
|
|
16
|
+
* The default value is false;
|
|
17
|
+
*/
|
|
18
|
+
ignoreEnvVars?: boolean;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The path of the configuration files
|
|
22
|
+
*/
|
|
23
|
+
configFilePath?: string | string[];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Expands variables
|
|
27
|
+
* The default value is true
|
|
28
|
+
*/
|
|
29
|
+
expandConfig?: boolean;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The AWS Secrets Manager Client
|
|
33
|
+
* If no client is provided, the module will create one.
|
|
34
|
+
*/
|
|
35
|
+
secretsManagerClient?: SecretsManagerClient;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The AWS Systems Manager Client
|
|
39
|
+
* If no client is provided, the module will create one.
|
|
40
|
+
*/
|
|
41
|
+
ssmClient?: SSMClient;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The default module options
|
|
46
|
+
*/
|
|
47
|
+
export const DefaultConfigfyModuleOptions: ConfigfyModuleOptions = {
|
|
48
|
+
ignoreConfigFile: false,
|
|
49
|
+
ignoreEnvVars: false,
|
|
50
|
+
expandConfig: true,
|
|
51
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The configuraion parser interface.
|
|
3
|
+
* This interface is implemented by all
|
|
4
|
+
* the supported configuration parsers.
|
|
5
|
+
*/
|
|
6
|
+
export interface ConfigurationParser {
|
|
7
|
+
/**
|
|
8
|
+
* Reads a file and assign its values
|
|
9
|
+
* to an object representation;
|
|
10
|
+
*
|
|
11
|
+
* @param {string} file the configuration file path
|
|
12
|
+
* @returns {Record<string, any>} the object representation of the configuration file
|
|
13
|
+
*/
|
|
14
|
+
parse(file: string): Record<string, any>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ValueDecoratedKey,
|
|
3
|
+
VALUE_METADATA,
|
|
4
|
+
VALUE_PROPERTIES_METADATA,
|
|
5
|
+
} from '../decorators';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The configuration registry.
|
|
9
|
+
*
|
|
10
|
+
* The registry keeps track of all classes decorated
|
|
11
|
+
* with Configuration decorator.
|
|
12
|
+
*/
|
|
13
|
+
export class ConfigurationRegistry {
|
|
14
|
+
private static readonly registry = [];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Registers a type.
|
|
18
|
+
*
|
|
19
|
+
* @param {any} type the class type
|
|
20
|
+
*/
|
|
21
|
+
static registerTarget(type: any): void {
|
|
22
|
+
this.registry.push(type);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Registers a class attribute.
|
|
27
|
+
*
|
|
28
|
+
* @param {any} target the class target
|
|
29
|
+
* @param {string} attribute the attribute name
|
|
30
|
+
*/
|
|
31
|
+
static registerAttribute(target: any, attribute: string): void {
|
|
32
|
+
(
|
|
33
|
+
target[VALUE_PROPERTIES_METADATA] ||
|
|
34
|
+
(target[VALUE_PROPERTIES_METADATA] = [])
|
|
35
|
+
).push(attribute);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Returns the configuration registry.
|
|
40
|
+
*
|
|
41
|
+
* @returns {any[]} the configuration registry
|
|
42
|
+
*/
|
|
43
|
+
static getRegistry(): any[] {
|
|
44
|
+
return this.registry;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Returns the class attribute names decorated with Decorated decorator
|
|
49
|
+
*
|
|
50
|
+
* @param {any} target the instance target;
|
|
51
|
+
* @returns {string[]} the list of attribute names
|
|
52
|
+
*/
|
|
53
|
+
static getValueDecoratedAttributes(target: any): string[] {
|
|
54
|
+
return target[VALUE_PROPERTIES_METADATA];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns the value of the decorated key.
|
|
59
|
+
*
|
|
60
|
+
* @param {any} instance the target instance
|
|
61
|
+
* @param {string} attribute the attribute name
|
|
62
|
+
* @returns {ValueDecoratedKey} the value decorated key
|
|
63
|
+
*/
|
|
64
|
+
static getValueDecoratedKey(
|
|
65
|
+
instance: any,
|
|
66
|
+
attribute: string,
|
|
67
|
+
): ValueDecoratedKey {
|
|
68
|
+
return Reflect.getMetadata(VALUE_METADATA, instance, attribute);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ConfigurationParser } from '../configuration-parser.interface';
|
|
2
|
+
import { DotEnvConfigurationParser } from './dotenv-configuration.parser';
|
|
3
|
+
import { JsonConfigurationParser } from './json-configuration.parser';
|
|
4
|
+
import { YamlConfigurationParser } from './yaml-configuration.parser';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The configuration parser factory.
|
|
8
|
+
* This factory class contains all the supported
|
|
9
|
+
* file configuration parsers.
|
|
10
|
+
*/
|
|
11
|
+
export class ConfigurationParserFactory {
|
|
12
|
+
/**
|
|
13
|
+
* The supported file configuration parsers
|
|
14
|
+
*/
|
|
15
|
+
private static readonly parsers = {
|
|
16
|
+
env: new DotEnvConfigurationParser(),
|
|
17
|
+
yml: new YamlConfigurationParser(),
|
|
18
|
+
yaml: new YamlConfigurationParser(),
|
|
19
|
+
json: new JsonConfigurationParser(),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Gets the file configuration parser based
|
|
24
|
+
* on the file extension.
|
|
25
|
+
* @param {string} file the configuration file name
|
|
26
|
+
* @returns {ConfigurationParser} the configuration parser
|
|
27
|
+
*/
|
|
28
|
+
static getParser(file: string): ConfigurationParser {
|
|
29
|
+
const ext = this.getFileExt(file);
|
|
30
|
+
return this.parsers[ext];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Checks if the given file has a parser registered.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} file the configuration file name
|
|
37
|
+
* @returns {boolean} true if a parser is found, false otherwise
|
|
38
|
+
*/
|
|
39
|
+
static supports(file: string): boolean {
|
|
40
|
+
const ext = this.getFileExt(file);
|
|
41
|
+
return this.parsers.hasOwnProperty(ext);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Returns the file extension.
|
|
46
|
+
*
|
|
47
|
+
* @param {string} file the file name
|
|
48
|
+
* @returns {string} the file extension
|
|
49
|
+
*/
|
|
50
|
+
private static getFileExt(file: string): string {
|
|
51
|
+
return file.split('.').pop();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as dotenv from 'dotenv';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import { ConfigurationParser } from '../configuration-parser.interface';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Dotenv configuration parser.
|
|
7
|
+
*/
|
|
8
|
+
export class DotEnvConfigurationParser implements ConfigurationParser {
|
|
9
|
+
/**
|
|
10
|
+
* Reads the configuration file and assign
|
|
11
|
+
* its contents to an object.
|
|
12
|
+
* @param {string} file the configuration file
|
|
13
|
+
* @returns {Record<string, any>} an object representation of the configuration file
|
|
14
|
+
*/
|
|
15
|
+
public parse(file: string): Record<string, any> {
|
|
16
|
+
return dotenv.parse(fs.readFileSync(file));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import { ConfigurationParser } from '../configuration-parser.interface';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* JSON configuration parser
|
|
6
|
+
*/
|
|
7
|
+
export class JsonConfigurationParser implements ConfigurationParser {
|
|
8
|
+
/**
|
|
9
|
+
* Reads the configuration file and assign
|
|
10
|
+
* its contents to an object.
|
|
11
|
+
* @param {string} file the configuration file
|
|
12
|
+
* @returns {Record<string, any>} an object representation of the configuration file
|
|
13
|
+
*/
|
|
14
|
+
public parse(file: string): Record<string, any> {
|
|
15
|
+
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as yaml from 'js-yaml';
|
|
3
|
+
import { ConfigurationParser } from '../configuration-parser.interface';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* YAML configuration parser
|
|
7
|
+
*/
|
|
8
|
+
export class YamlConfigurationParser implements ConfigurationParser {
|
|
9
|
+
/**
|
|
10
|
+
* Reads the configuration file and assign
|
|
11
|
+
* its contents to an object.
|
|
12
|
+
* @param {string} file the configuration file
|
|
13
|
+
* @returns {Record<string, any>} an object representation of the configuration file
|
|
14
|
+
*/
|
|
15
|
+
public parse(file: string): Record<string, any> {
|
|
16
|
+
return yaml.load(fs.readFileSync(file, 'utf-8'));
|
|
17
|
+
}
|
|
18
|
+
}
|