@dyanet/config-aws 1.0.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/README.md +195 -0
- package/dist/cjs/config-manager.js +360 -0
- package/dist/cjs/config-manager.js.map +1 -0
- package/dist/cjs/errors/index.js +65 -0
- package/dist/cjs/errors/index.js.map +1 -0
- package/dist/cjs/index.js +37 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/interfaces/config-loader.interface.js +3 -0
- package/dist/cjs/interfaces/config-loader.interface.js.map +1 -0
- package/dist/cjs/interfaces/config-manager.interface.js +3 -0
- package/dist/cjs/interfaces/config-manager.interface.js.map +1 -0
- package/dist/cjs/interfaces/env-file-loader.interface.js +3 -0
- package/dist/cjs/interfaces/env-file-loader.interface.js.map +1 -0
- package/dist/cjs/interfaces/environment-loader.interface.js +3 -0
- package/dist/cjs/interfaces/environment-loader.interface.js.map +1 -0
- package/dist/cjs/interfaces/index.js +3 -0
- package/dist/cjs/interfaces/index.js.map +1 -0
- package/dist/cjs/interfaces/s3-loader.interface.js +3 -0
- package/dist/cjs/interfaces/s3-loader.interface.js.map +1 -0
- package/dist/cjs/interfaces/secrets-manager-loader.interface.js +3 -0
- package/dist/cjs/interfaces/secrets-manager-loader.interface.js.map +1 -0
- package/dist/cjs/interfaces/ssm-parameter-store-loader.interface.js +3 -0
- package/dist/cjs/interfaces/ssm-parameter-store-loader.interface.js.map +1 -0
- package/dist/cjs/loaders/env-file.loader.js +167 -0
- package/dist/cjs/loaders/env-file.loader.js.map +1 -0
- package/dist/cjs/loaders/environment.loader.js +83 -0
- package/dist/cjs/loaders/environment.loader.js.map +1 -0
- package/dist/cjs/loaders/index.js +14 -0
- package/dist/cjs/loaders/index.js.map +1 -0
- package/dist/cjs/loaders/s3.loader.js +141 -0
- package/dist/cjs/loaders/s3.loader.js.map +1 -0
- package/dist/cjs/loaders/secrets-manager.loader.js +156 -0
- package/dist/cjs/loaders/secrets-manager.loader.js.map +1 -0
- package/dist/cjs/loaders/ssm-parameter-store.loader.js +193 -0
- package/dist/cjs/loaders/ssm-parameter-store.loader.js.map +1 -0
- package/dist/cjs/utils/env-file-parser.util.js +98 -0
- package/dist/cjs/utils/env-file-parser.util.js.map +1 -0
- package/dist/cjs/utils/index.js +8 -0
- package/dist/cjs/utils/index.js.map +1 -0
- package/dist/cjs/utils/validation.util.js +116 -0
- package/dist/cjs/utils/validation.util.js.map +1 -0
- package/dist/esm/config-manager.js +356 -0
- package/dist/esm/config-manager.js.map +1 -0
- package/dist/esm/errors/index.js +57 -0
- package/dist/esm/errors/index.js.map +1 -0
- package/dist/esm/index.js +21 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/interfaces/config-loader.interface.js +2 -0
- package/dist/esm/interfaces/config-loader.interface.js.map +1 -0
- package/dist/esm/interfaces/config-manager.interface.js +2 -0
- package/dist/esm/interfaces/config-manager.interface.js.map +1 -0
- package/dist/esm/interfaces/env-file-loader.interface.js +2 -0
- package/dist/esm/interfaces/env-file-loader.interface.js.map +1 -0
- package/dist/esm/interfaces/environment-loader.interface.js +2 -0
- package/dist/esm/interfaces/environment-loader.interface.js.map +1 -0
- package/dist/esm/interfaces/index.js +2 -0
- package/dist/esm/interfaces/index.js.map +1 -0
- package/dist/esm/interfaces/s3-loader.interface.js +2 -0
- package/dist/esm/interfaces/s3-loader.interface.js.map +1 -0
- package/dist/esm/interfaces/secrets-manager-loader.interface.js +2 -0
- package/dist/esm/interfaces/secrets-manager-loader.interface.js.map +1 -0
- package/dist/esm/interfaces/ssm-parameter-store-loader.interface.js +2 -0
- package/dist/esm/interfaces/ssm-parameter-store-loader.interface.js.map +1 -0
- package/dist/esm/loaders/env-file.loader.js +130 -0
- package/dist/esm/loaders/env-file.loader.js.map +1 -0
- package/dist/esm/loaders/environment.loader.js +79 -0
- package/dist/esm/loaders/environment.loader.js.map +1 -0
- package/dist/esm/loaders/index.js +6 -0
- package/dist/esm/loaders/index.js.map +1 -0
- package/dist/esm/loaders/s3.loader.js +137 -0
- package/dist/esm/loaders/s3.loader.js.map +1 -0
- package/dist/esm/loaders/secrets-manager.loader.js +152 -0
- package/dist/esm/loaders/secrets-manager.loader.js.map +1 -0
- package/dist/esm/loaders/ssm-parameter-store.loader.js +189 -0
- package/dist/esm/loaders/ssm-parameter-store.loader.js.map +1 -0
- package/dist/esm/utils/env-file-parser.util.js +94 -0
- package/dist/esm/utils/env-file-parser.util.js.map +1 -0
- package/dist/esm/utils/index.js +3 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/esm/utils/validation.util.js +112 -0
- package/dist/esm/utils/validation.util.js.map +1 -0
- package/dist/types/config-manager.d.ts +119 -0
- package/dist/types/config-manager.d.ts.map +1 -0
- package/dist/types/errors/index.d.ts +43 -0
- package/dist/types/errors/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +24 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/interfaces/config-loader.interface.d.ts +33 -0
- package/dist/types/interfaces/config-loader.interface.d.ts.map +1 -0
- package/dist/types/interfaces/config-manager.interface.d.ts +86 -0
- package/dist/types/interfaces/config-manager.interface.d.ts.map +1 -0
- package/dist/types/interfaces/env-file-loader.interface.d.ts +12 -0
- package/dist/types/interfaces/env-file-loader.interface.d.ts.map +1 -0
- package/dist/types/interfaces/environment-loader.interface.d.ts +10 -0
- package/dist/types/interfaces/environment-loader.interface.d.ts.map +1 -0
- package/dist/types/interfaces/index.d.ts +8 -0
- package/dist/types/interfaces/index.d.ts.map +1 -0
- package/dist/types/interfaces/s3-loader.interface.d.ts +14 -0
- package/dist/types/interfaces/s3-loader.interface.d.ts.map +1 -0
- package/dist/types/interfaces/secrets-manager-loader.interface.d.ts +12 -0
- package/dist/types/interfaces/secrets-manager-loader.interface.d.ts.map +1 -0
- package/dist/types/interfaces/ssm-parameter-store-loader.interface.d.ts +14 -0
- package/dist/types/interfaces/ssm-parameter-store-loader.interface.d.ts.map +1 -0
- package/dist/types/loaders/env-file.loader.d.ts +69 -0
- package/dist/types/loaders/env-file.loader.d.ts.map +1 -0
- package/dist/types/loaders/environment.loader.d.ts +46 -0
- package/dist/types/loaders/environment.loader.d.ts.map +1 -0
- package/dist/types/loaders/index.d.ts +6 -0
- package/dist/types/loaders/index.d.ts.map +1 -0
- package/dist/types/loaders/s3.loader.d.ts +62 -0
- package/dist/types/loaders/s3.loader.d.ts.map +1 -0
- package/dist/types/loaders/secrets-manager.loader.d.ts +68 -0
- package/dist/types/loaders/secrets-manager.loader.d.ts.map +1 -0
- package/dist/types/loaders/ssm-parameter-store.loader.d.ts +78 -0
- package/dist/types/loaders/ssm-parameter-store.loader.d.ts.map +1 -0
- package/dist/types/utils/env-file-parser.util.d.ts +45 -0
- package/dist/types/utils/env-file-parser.util.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +3 -0
- package/dist/types/utils/index.d.ts.map +1 -0
- package/dist/types/utils/validation.util.d.ts +53 -0
- package/dist/types/utils/validation.util.d.ts.map +1 -0
- package/package.json +97 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.interface.js","sourceRoot":"","sources":["../../../src/interfaces/config-loader.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.interface.js","sourceRoot":"","sources":["../../../src/interfaces/config-manager.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-file-loader.interface.js","sourceRoot":"","sources":["../../../src/interfaces/env-file-loader.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-loader.interface.js","sourceRoot":"","sources":["../../../src/interfaces/environment-loader.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/interfaces/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-loader.interface.js","sourceRoot":"","sources":["../../../src/interfaces/s3-loader.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets-manager-loader.interface.js","sourceRoot":"","sources":["../../../src/interfaces/secrets-manager-loader.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssm-parameter-store-loader.interface.js","sourceRoot":"","sources":["../../../src/interfaces/ssm-parameter-store-loader.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.EnvFileLoader = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const env_file_parser_util_1 = require("../utils/env-file-parser.util");
|
|
40
|
+
const errors_1 = require("../errors");
|
|
41
|
+
/**
|
|
42
|
+
* Loader that reads configuration from .env files on the filesystem.
|
|
43
|
+
* Uses AWS ECS-compatible format for parsing.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // Load from default paths (.env, .env.local)
|
|
48
|
+
* const loader = new EnvFileLoader();
|
|
49
|
+
*
|
|
50
|
+
* // Load from specific paths
|
|
51
|
+
* const loader = new EnvFileLoader({
|
|
52
|
+
* paths: ['.env', '.env.production']
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* // Disable override (first file wins)
|
|
56
|
+
* const loader = new EnvFileLoader({
|
|
57
|
+
* paths: ['.env', '.env.local'],
|
|
58
|
+
* override: false
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/use-environment-file.html
|
|
63
|
+
*/
|
|
64
|
+
class EnvFileLoader {
|
|
65
|
+
constructor(config = {}) {
|
|
66
|
+
this._config = {
|
|
67
|
+
paths: config.paths ?? EnvFileLoader.DEFAULT_PATHS,
|
|
68
|
+
encoding: config.encoding ?? EnvFileLoader.DEFAULT_ENCODING,
|
|
69
|
+
override: config.override ?? true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
getName() {
|
|
73
|
+
return 'EnvFileLoader';
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Check if at least one of the configured .env files exists.
|
|
77
|
+
* @returns Promise resolving to true if any file exists
|
|
78
|
+
*/
|
|
79
|
+
async isAvailable() {
|
|
80
|
+
for (const filePath of this._config.paths) {
|
|
81
|
+
const resolvedPath = this.resolvePath(filePath);
|
|
82
|
+
if (await this.fileExists(resolvedPath)) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Load configuration from .env files.
|
|
90
|
+
*
|
|
91
|
+
* Files are processed in order. When override is true (default),
|
|
92
|
+
* later files override earlier ones. When override is false,
|
|
93
|
+
* earlier files take precedence.
|
|
94
|
+
*
|
|
95
|
+
* Missing files are silently skipped.
|
|
96
|
+
*
|
|
97
|
+
* @returns Promise resolving to the merged configuration
|
|
98
|
+
* @throws ConfigurationLoadError if a file exists but cannot be read
|
|
99
|
+
*/
|
|
100
|
+
async load() {
|
|
101
|
+
const result = {};
|
|
102
|
+
for (const filePath of this._config.paths) {
|
|
103
|
+
const resolvedPath = this.resolvePath(filePath);
|
|
104
|
+
if (!(await this.fileExists(resolvedPath))) {
|
|
105
|
+
// Skip missing files silently
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
const content = await this.readFile(resolvedPath);
|
|
110
|
+
const parsed = env_file_parser_util_1.EnvFileParser.parse(content);
|
|
111
|
+
// Merge based on override setting
|
|
112
|
+
if (this._config.override) {
|
|
113
|
+
// Later files override earlier ones
|
|
114
|
+
Object.assign(result, parsed);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// Earlier files take precedence - only add keys that don't exist
|
|
118
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
119
|
+
if (!(key in result)) {
|
|
120
|
+
result[key] = value;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
throw new errors_1.ConfigurationLoadError(`Failed to read env file: ${resolvedPath}`, this.getName(), error instanceof Error ? error : undefined);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Resolve a file path relative to the current working directory.
|
|
133
|
+
* @internal
|
|
134
|
+
*/
|
|
135
|
+
resolvePath(filePath) {
|
|
136
|
+
if (path.isAbsolute(filePath)) {
|
|
137
|
+
return filePath;
|
|
138
|
+
}
|
|
139
|
+
return path.resolve(process.cwd(), filePath);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Check if a file exists.
|
|
143
|
+
* @internal
|
|
144
|
+
*/
|
|
145
|
+
async fileExists(filePath) {
|
|
146
|
+
try {
|
|
147
|
+
await fs.promises.access(filePath, fs.constants.R_OK);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Read a file's contents.
|
|
156
|
+
* @internal
|
|
157
|
+
*/
|
|
158
|
+
async readFile(filePath) {
|
|
159
|
+
return fs.promises.readFile(filePath, { encoding: this._config.encoding });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.EnvFileLoader = EnvFileLoader;
|
|
163
|
+
/** Default paths to search for .env files */
|
|
164
|
+
EnvFileLoader.DEFAULT_PATHS = ['.env', '.env.local'];
|
|
165
|
+
/** Default file encoding */
|
|
166
|
+
EnvFileLoader.DEFAULT_ENCODING = 'utf-8';
|
|
167
|
+
//# sourceMappingURL=env-file.loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-file.loader.js","sourceRoot":"","sources":["../../../src/loaders/env-file.loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EnvironmentLoader = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Loader that reads configuration from process.env.
|
|
6
|
+
* Supports prefix filtering and exclusion lists.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* // Load all environment variables
|
|
11
|
+
* const loader = new EnvironmentLoader();
|
|
12
|
+
*
|
|
13
|
+
* // Load only variables starting with 'APP_', stripping the prefix
|
|
14
|
+
* const loader = new EnvironmentLoader({ prefix: 'APP_' });
|
|
15
|
+
*
|
|
16
|
+
* // Load all except specific variables
|
|
17
|
+
* const loader = new EnvironmentLoader({ exclude: ['PATH', 'HOME'] });
|
|
18
|
+
*
|
|
19
|
+
* // Combine prefix and exclusion
|
|
20
|
+
* const loader = new EnvironmentLoader({
|
|
21
|
+
* prefix: 'APP_',
|
|
22
|
+
* exclude: ['APP_DEBUG']
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
class EnvironmentLoader {
|
|
27
|
+
constructor(config = {}) {
|
|
28
|
+
this._config = config;
|
|
29
|
+
}
|
|
30
|
+
getName() {
|
|
31
|
+
return 'EnvironmentLoader';
|
|
32
|
+
}
|
|
33
|
+
async isAvailable() {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Load configuration from process.env.
|
|
38
|
+
*
|
|
39
|
+
* When a prefix is specified:
|
|
40
|
+
* - Only variables starting with the prefix are included
|
|
41
|
+
* - The prefix is stripped from the resulting key names
|
|
42
|
+
*
|
|
43
|
+
* When an exclusion list is specified:
|
|
44
|
+
* - Variables in the list are excluded from the result
|
|
45
|
+
* - Exclusion is checked against the original key (before prefix stripping)
|
|
46
|
+
*
|
|
47
|
+
* @returns Promise resolving to the loaded configuration
|
|
48
|
+
*/
|
|
49
|
+
async load() {
|
|
50
|
+
const result = {};
|
|
51
|
+
const { prefix, exclude = [] } = this._config;
|
|
52
|
+
const excludeSet = new Set(exclude);
|
|
53
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
54
|
+
// Skip undefined values
|
|
55
|
+
if (value === undefined) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
// Check exclusion list (against original key)
|
|
59
|
+
if (excludeSet.has(key)) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
// Handle prefix filtering
|
|
63
|
+
if (prefix) {
|
|
64
|
+
if (key.startsWith(prefix)) {
|
|
65
|
+
// Strip prefix from key
|
|
66
|
+
const strippedKey = key.slice(prefix.length);
|
|
67
|
+
// Only include if there's a key remaining after stripping
|
|
68
|
+
if (strippedKey) {
|
|
69
|
+
result[strippedKey] = value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Skip keys that don't match the prefix
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// No prefix - include all non-excluded keys
|
|
76
|
+
result[key] = value;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.EnvironmentLoader = EnvironmentLoader;
|
|
83
|
+
//# sourceMappingURL=environment.loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment.loader.js","sourceRoot":"","sources":["../../../src/loaders/environment.loader.ts"],"names":[],"mappings":";;;AAGA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAa,iBAAiB;IAI5B,YAAY,SAAkC,EAAE;QAC9C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED,OAAO;QACL,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAC9C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAEpC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACvD,wBAAwB;YACxB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,SAAS;YACX,CAAC;YAED,8CAA8C;YAC9C,IAAI,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxB,SAAS;YACX,CAAC;YAED,0BAA0B;YAC1B,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC3B,wBAAwB;oBACxB,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBAC7C,0DAA0D;oBAC1D,IAAI,WAAW,EAAE,CAAC;wBAChB,MAAM,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;oBAC9B,CAAC;gBACH,CAAC;gBACD,wCAAwC;YAC1C,CAAC;iBAAM,CAAC;gBACN,4CAA4C;gBAC5C,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACtB,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAhED,8CAgEC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SSMParameterStoreLoader = exports.SecretsManagerLoader = exports.S3Loader = exports.EnvFileLoader = exports.EnvironmentLoader = void 0;
|
|
4
|
+
var environment_loader_1 = require("./environment.loader");
|
|
5
|
+
Object.defineProperty(exports, "EnvironmentLoader", { enumerable: true, get: function () { return environment_loader_1.EnvironmentLoader; } });
|
|
6
|
+
var env_file_loader_1 = require("./env-file.loader");
|
|
7
|
+
Object.defineProperty(exports, "EnvFileLoader", { enumerable: true, get: function () { return env_file_loader_1.EnvFileLoader; } });
|
|
8
|
+
var s3_loader_1 = require("./s3.loader");
|
|
9
|
+
Object.defineProperty(exports, "S3Loader", { enumerable: true, get: function () { return s3_loader_1.S3Loader; } });
|
|
10
|
+
var secrets_manager_loader_1 = require("./secrets-manager.loader");
|
|
11
|
+
Object.defineProperty(exports, "SecretsManagerLoader", { enumerable: true, get: function () { return secrets_manager_loader_1.SecretsManagerLoader; } });
|
|
12
|
+
var ssm_parameter_store_loader_1 = require("./ssm-parameter-store.loader");
|
|
13
|
+
Object.defineProperty(exports, "SSMParameterStoreLoader", { enumerable: true, get: function () { return ssm_parameter_store_loader_1.SSMParameterStoreLoader; } });
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/loaders/index.ts"],"names":[],"mappings":";;;AAAA,2DAAyD;AAAhD,uHAAA,iBAAiB,OAAA;AAC1B,qDAAkD;AAAzC,gHAAA,aAAa,OAAA;AACtB,yCAAuC;AAA9B,qGAAA,QAAQ,OAAA;AACjB,mEAAgE;AAAvD,8HAAA,oBAAoB,OAAA;AAC7B,2EAAuE;AAA9D,qIAAA,uBAAuB,OAAA"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.S3Loader = void 0;
|
|
4
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
5
|
+
const credential_providers_1 = require("@aws-sdk/credential-providers");
|
|
6
|
+
const env_file_parser_util_1 = require("../utils/env-file-parser.util");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
/**
|
|
9
|
+
* Loader that reads configuration from S3 buckets.
|
|
10
|
+
* Supports JSON and .env file formats with auto-detection.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* // Load JSON config from S3
|
|
15
|
+
* const loader = new S3Loader({
|
|
16
|
+
* bucket: 'my-config-bucket',
|
|
17
|
+
* key: 'config/app.json',
|
|
18
|
+
* format: 'json'
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // Load .env file from S3 with auto-detection
|
|
22
|
+
* const loader = new S3Loader({
|
|
23
|
+
* bucket: 'my-config-bucket',
|
|
24
|
+
* key: 'config/.env'
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/use-environment-file.html
|
|
29
|
+
*/
|
|
30
|
+
class S3Loader {
|
|
31
|
+
constructor(config) {
|
|
32
|
+
this._config = {
|
|
33
|
+
bucket: config.bucket,
|
|
34
|
+
key: config.key,
|
|
35
|
+
region: config.region || process.env['AWS_REGION'] || 'us-east-1',
|
|
36
|
+
format: config.format || 'auto',
|
|
37
|
+
};
|
|
38
|
+
this._client = new client_s3_1.S3Client({
|
|
39
|
+
credentials: (0, credential_providers_1.fromNodeProviderChain)(),
|
|
40
|
+
region: this._config.region,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
getName() {
|
|
44
|
+
return `S3Loader(s3://${this._config.bucket}/${this._config.key})`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if this loader is available by verifying AWS credentials.
|
|
48
|
+
* @returns Promise resolving to true if AWS credentials are available
|
|
49
|
+
*/
|
|
50
|
+
async isAvailable() {
|
|
51
|
+
try {
|
|
52
|
+
await this._client.config.credentials();
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Load configuration from S3.
|
|
61
|
+
* @returns Promise resolving to configuration key-value pairs
|
|
62
|
+
* @throws AWSServiceError if S3 operation fails
|
|
63
|
+
* @throws ConfigurationLoadError if content cannot be parsed
|
|
64
|
+
*/
|
|
65
|
+
async load() {
|
|
66
|
+
try {
|
|
67
|
+
const command = new client_s3_1.GetObjectCommand({
|
|
68
|
+
Bucket: this._config.bucket,
|
|
69
|
+
Key: this._config.key,
|
|
70
|
+
});
|
|
71
|
+
const response = await this._client.send(command);
|
|
72
|
+
if (!response.Body) {
|
|
73
|
+
return {};
|
|
74
|
+
}
|
|
75
|
+
const content = await response.Body.transformToString();
|
|
76
|
+
if (!content || content.trim() === '') {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
return this.parseContent(content);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (error instanceof errors_1.ConfigurationLoadError) {
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
if (error instanceof Error) {
|
|
86
|
+
if (error.name === 'NoSuchKey' || error.name === 'NoSuchBucket') {
|
|
87
|
+
// Object or bucket doesn't exist - return empty config
|
|
88
|
+
return {};
|
|
89
|
+
}
|
|
90
|
+
if (error.name === 'AccessDenied') {
|
|
91
|
+
throw new errors_1.AWSServiceError(`Access denied when retrieving s3://${this._config.bucket}/${this._config.key}. Check AWS credentials and permissions.`, 'S3', 'GetObject', error);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
throw new errors_1.AWSServiceError(`Failed to retrieve s3://${this._config.bucket}/${this._config.key}: ${error instanceof Error ? error.message : String(error)}`, 'S3', 'GetObject', error instanceof Error ? error : undefined);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Parse content based on format setting or auto-detection.
|
|
99
|
+
* @internal
|
|
100
|
+
*/
|
|
101
|
+
parseContent(content) {
|
|
102
|
+
const format = this._config.format === 'auto' ? this.detectFormat(content) : this._config.format;
|
|
103
|
+
if (format === 'json') {
|
|
104
|
+
return this.parseJson(content);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
return env_file_parser_util_1.EnvFileParser.parse(content);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Detect content format based on structure.
|
|
112
|
+
* JSON content starts with '{' after trimming whitespace.
|
|
113
|
+
* @internal
|
|
114
|
+
*/
|
|
115
|
+
detectFormat(content) {
|
|
116
|
+
const trimmed = content.trim();
|
|
117
|
+
if (trimmed.startsWith('{')) {
|
|
118
|
+
return 'json';
|
|
119
|
+
}
|
|
120
|
+
return 'env';
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Parse JSON content.
|
|
124
|
+
* @internal
|
|
125
|
+
*/
|
|
126
|
+
parseJson(content) {
|
|
127
|
+
try {
|
|
128
|
+
const parsed = JSON.parse(content);
|
|
129
|
+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
130
|
+
return parsed;
|
|
131
|
+
}
|
|
132
|
+
// If not an object, wrap it
|
|
133
|
+
return { CONFIG_VALUE: parsed };
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
throw new errors_1.ConfigurationLoadError(`Failed to parse JSON from s3://${this._config.bucket}/${this._config.key}: ${error instanceof Error ? error.message : String(error)}`, this.getName(), error instanceof Error ? error : undefined);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.S3Loader = S3Loader;
|
|
141
|
+
//# sourceMappingURL=s3.loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.loader.js","sourceRoot":"","sources":["../../../src/loaders/s3.loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SecretsManagerLoader = void 0;
|
|
4
|
+
const client_secrets_manager_1 = require("@aws-sdk/client-secrets-manager");
|
|
5
|
+
const credential_providers_1 = require("@aws-sdk/credential-providers");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
/**
|
|
8
|
+
* Loader that reads configuration from AWS Secrets Manager.
|
|
9
|
+
* Supports environment-aware path construction.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Basic usage
|
|
14
|
+
* const loader = new SecretsManagerLoader({
|
|
15
|
+
* secretName: '/my-app/config',
|
|
16
|
+
* region: 'us-east-1'
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // With environment mapping
|
|
20
|
+
* const loader = new SecretsManagerLoader({
|
|
21
|
+
* secretName: '/my-app/config',
|
|
22
|
+
* environmentMapping: {
|
|
23
|
+
* development: 'dev',
|
|
24
|
+
* staging: 'stg',
|
|
25
|
+
* production: 'prod'
|
|
26
|
+
* }
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
class SecretsManagerLoader {
|
|
31
|
+
constructor(config = {}) {
|
|
32
|
+
this._appEnv = process.env['APP_ENV'] || process.env['NODE_ENV'] || 'local';
|
|
33
|
+
// Set default configuration
|
|
34
|
+
this._config = {
|
|
35
|
+
secretName: config.secretName || '/nestjs-config-aws',
|
|
36
|
+
region: config.region || process.env['AWS_REGION'] || 'us-east-1',
|
|
37
|
+
environmentMapping: config.environmentMapping || {
|
|
38
|
+
development: 'dev',
|
|
39
|
+
test: 'test',
|
|
40
|
+
production: 'production',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
// Initialize AWS Secrets Manager client
|
|
44
|
+
this._client = new client_secrets_manager_1.SecretsManagerClient({
|
|
45
|
+
credentials: (0, credential_providers_1.fromNodeProviderChain)(),
|
|
46
|
+
region: this._config.region,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get the name of this loader for logging and debugging.
|
|
51
|
+
* @returns The loader name with secret path
|
|
52
|
+
*/
|
|
53
|
+
getName() {
|
|
54
|
+
const secretName = this.buildSecretName();
|
|
55
|
+
return `SecretsManagerLoader(${secretName})`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if this loader is available in the current environment.
|
|
59
|
+
* @returns Promise resolving to true if not in local environment and AWS credentials are available
|
|
60
|
+
*/
|
|
61
|
+
async isAvailable() {
|
|
62
|
+
// Skip in local environment
|
|
63
|
+
if (this._appEnv === 'local') {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
// Test AWS credentials by attempting to get caller identity
|
|
68
|
+
await this._client.config.credentials();
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Load configuration from AWS Secrets Manager.
|
|
77
|
+
* @returns Promise resolving to configuration key-value pairs from the secret
|
|
78
|
+
* @throws AWSServiceError if AWS operation fails
|
|
79
|
+
* @throws ConfigurationLoadError if secret cannot be parsed
|
|
80
|
+
*/
|
|
81
|
+
async load() {
|
|
82
|
+
// Skip loading in local environment
|
|
83
|
+
if (this._appEnv === 'local') {
|
|
84
|
+
return {};
|
|
85
|
+
}
|
|
86
|
+
const secretName = this.buildSecretName();
|
|
87
|
+
try {
|
|
88
|
+
const command = new client_secrets_manager_1.GetSecretValueCommand({ SecretId: secretName });
|
|
89
|
+
const response = await this._client.send(command);
|
|
90
|
+
if (!response.SecretString) {
|
|
91
|
+
return {};
|
|
92
|
+
}
|
|
93
|
+
// Try to parse as JSON, fallback to string value
|
|
94
|
+
try {
|
|
95
|
+
const parsed = JSON.parse(response.SecretString);
|
|
96
|
+
// Ensure we return an object for configuration merging
|
|
97
|
+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
98
|
+
return parsed;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// If it's not an object, wrap it in a configuration object
|
|
102
|
+
return { SECRET_VALUE: parsed };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// If JSON parsing fails, treat as a single string value
|
|
107
|
+
return { SECRET_VALUE: response.SecretString };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
// Handle specific AWS errors
|
|
112
|
+
if (error instanceof Error) {
|
|
113
|
+
if (error.name === 'ResourceNotFoundException') {
|
|
114
|
+
// Secret doesn't exist - this is not necessarily an error in all environments
|
|
115
|
+
return {};
|
|
116
|
+
}
|
|
117
|
+
if (error.name === 'AccessDeniedException') {
|
|
118
|
+
throw new errors_1.AWSServiceError(`Access denied when retrieving secret '${secretName}'. Check AWS credentials and permissions.`, 'SecretsManager', 'GetSecretValue', error);
|
|
119
|
+
}
|
|
120
|
+
if (error.name === 'InvalidRequestException') {
|
|
121
|
+
throw new errors_1.AWSServiceError(`Invalid request when retrieving secret '${secretName}'. Check secret name format.`, 'SecretsManager', 'GetSecretValue', error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// For other errors, wrap in AWSServiceError
|
|
125
|
+
throw new errors_1.AWSServiceError(`Failed to retrieve secret '${secretName}' from AWS Secrets Manager: ${error instanceof Error ? error.message : String(error)}`, 'SecretsManager', 'GetSecretValue', error instanceof Error ? error : undefined);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Build the environment-aware secret name/path.
|
|
130
|
+
* @returns The full secret name with environment prefix
|
|
131
|
+
*/
|
|
132
|
+
buildSecretName() {
|
|
133
|
+
const envPrefix = this._config.environmentMapping[this._appEnv];
|
|
134
|
+
if (!envPrefix) {
|
|
135
|
+
throw new errors_1.ConfigurationLoadError(`No environment mapping found for APP_ENV '${this._appEnv}'. ` +
|
|
136
|
+
`Available environments: ${Object.keys(this._config.environmentMapping).join(', ')}`, this.getName());
|
|
137
|
+
}
|
|
138
|
+
return `/${envPrefix}${this._config.secretName}`;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get the current app environment.
|
|
142
|
+
* @returns The current APP_ENV or NODE_ENV value
|
|
143
|
+
*/
|
|
144
|
+
getAppEnv() {
|
|
145
|
+
return this._appEnv;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get the environment mapping configuration.
|
|
149
|
+
* @returns The environment mapping record
|
|
150
|
+
*/
|
|
151
|
+
getEnvironmentMapping() {
|
|
152
|
+
return { ...this._config.environmentMapping };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
exports.SecretsManagerLoader = SecretsManagerLoader;
|
|
156
|
+
//# sourceMappingURL=secrets-manager.loader.js.map
|