@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,356 @@
|
|
|
1
|
+
import { ConfigurationError, ConfigurationLoadError, ValidationError } from './errors';
|
|
2
|
+
/**
|
|
3
|
+
* Default console logger implementation
|
|
4
|
+
*/
|
|
5
|
+
const defaultLogger = {
|
|
6
|
+
log: (message) => console.log(message),
|
|
7
|
+
error: (message) => console.error(message),
|
|
8
|
+
warn: (message) => console.warn(message),
|
|
9
|
+
debug: (message) => console.debug(message),
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Default sensitive keys that should always be masked
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_SENSITIVE_KEYS = ['password', 'secret', 'key', 'token', 'credential', 'api_key', 'apikey'];
|
|
15
|
+
/**
|
|
16
|
+
* Default verbose options
|
|
17
|
+
*/
|
|
18
|
+
const DEFAULT_VERBOSE_OPTIONS = {
|
|
19
|
+
logKeys: true,
|
|
20
|
+
logValues: false,
|
|
21
|
+
logOverrides: true,
|
|
22
|
+
logTiming: true,
|
|
23
|
+
maskValues: true,
|
|
24
|
+
sensitiveKeys: DEFAULT_SENSITIVE_KEYS,
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Predefined precedence orders for common strategies
|
|
28
|
+
* Higher index = higher priority (later loaders override earlier ones)
|
|
29
|
+
*/
|
|
30
|
+
const PRECEDENCE_ORDERS = {
|
|
31
|
+
// AWS wins: env -> envFile -> s3 -> secretsManager -> ssm
|
|
32
|
+
'aws-first': [
|
|
33
|
+
'EnvironmentLoader',
|
|
34
|
+
'EnvFileLoader',
|
|
35
|
+
'S3Loader',
|
|
36
|
+
'SecretsManagerLoader',
|
|
37
|
+
'SSMParameterStoreLoader',
|
|
38
|
+
],
|
|
39
|
+
// Local wins: ssm -> secretsManager -> s3 -> envFile -> env
|
|
40
|
+
'local-first': [
|
|
41
|
+
'SSMParameterStoreLoader',
|
|
42
|
+
'SecretsManagerLoader',
|
|
43
|
+
'S3Loader',
|
|
44
|
+
'EnvFileLoader',
|
|
45
|
+
'EnvironmentLoader',
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* ConfigManager orchestrates loading configuration from multiple sources
|
|
50
|
+
* with configurable precedence and validation.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* import { ConfigManager, EnvironmentLoader, SecretsManagerLoader } from '@dyanet/config-aws';
|
|
55
|
+
* import { z } from 'zod';
|
|
56
|
+
*
|
|
57
|
+
* const schema = z.object({
|
|
58
|
+
* DATABASE_URL: z.string(),
|
|
59
|
+
* API_KEY: z.string(),
|
|
60
|
+
* PORT: z.coerce.number().default(3000),
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* const manager = new ConfigManager({
|
|
64
|
+
* loaders: [
|
|
65
|
+
* new EnvironmentLoader({ prefix: 'APP_' }),
|
|
66
|
+
* new SecretsManagerLoader({ secretName: '/my-app/config' }),
|
|
67
|
+
* ],
|
|
68
|
+
* schema,
|
|
69
|
+
* precedence: 'aws-first',
|
|
70
|
+
* verbose: true,
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* await manager.load();
|
|
74
|
+
* const dbUrl = manager.get('DATABASE_URL');
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export class ConfigManager {
|
|
78
|
+
constructor(options = {}) {
|
|
79
|
+
this.config = null;
|
|
80
|
+
this.loadResult = null;
|
|
81
|
+
this.loaded = false;
|
|
82
|
+
this._options = {
|
|
83
|
+
loaders: options.loaders ?? [],
|
|
84
|
+
schema: options.schema,
|
|
85
|
+
precedence: options.precedence ?? 'aws-first',
|
|
86
|
+
validateOnLoad: options.validateOnLoad ?? true,
|
|
87
|
+
enableLogging: options.enableLogging ?? false,
|
|
88
|
+
logger: options.logger,
|
|
89
|
+
verbose: options.verbose,
|
|
90
|
+
};
|
|
91
|
+
this._logger = options.logger ?? defaultLogger;
|
|
92
|
+
this._verboseOptions = this.resolveVerboseOptions(options.verbose);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Resolve verbose options from boolean or object
|
|
96
|
+
*/
|
|
97
|
+
resolveVerboseOptions(verbose) {
|
|
98
|
+
if (verbose === undefined || verbose === false) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
if (verbose === true) {
|
|
102
|
+
return { ...DEFAULT_VERBOSE_OPTIONS };
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
logKeys: verbose.logKeys ?? DEFAULT_VERBOSE_OPTIONS.logKeys,
|
|
106
|
+
logValues: verbose.logValues ?? DEFAULT_VERBOSE_OPTIONS.logValues,
|
|
107
|
+
logOverrides: verbose.logOverrides ?? DEFAULT_VERBOSE_OPTIONS.logOverrides,
|
|
108
|
+
logTiming: verbose.logTiming ?? DEFAULT_VERBOSE_OPTIONS.logTiming,
|
|
109
|
+
maskValues: verbose.maskValues ?? DEFAULT_VERBOSE_OPTIONS.maskValues,
|
|
110
|
+
sensitiveKeys: verbose.sensitiveKeys ?? DEFAULT_VERBOSE_OPTIONS.sensitiveKeys,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Log a message if logging is enabled
|
|
115
|
+
*/
|
|
116
|
+
log(message) {
|
|
117
|
+
if (this._options.enableLogging || this._verboseOptions) {
|
|
118
|
+
this._logger.log(`[config-aws] ${message}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Mask a value for logging
|
|
123
|
+
*/
|
|
124
|
+
maskValue(key, value) {
|
|
125
|
+
if (!this._verboseOptions?.logValues) {
|
|
126
|
+
return '';
|
|
127
|
+
}
|
|
128
|
+
const strValue = String(value);
|
|
129
|
+
const lowerKey = key.toLowerCase();
|
|
130
|
+
// Check if key contains any sensitive patterns
|
|
131
|
+
const isSensitive = this._verboseOptions.sensitiveKeys.some((pattern) => lowerKey.includes(pattern.toLowerCase()));
|
|
132
|
+
if (this._verboseOptions.maskValues || isSensitive) {
|
|
133
|
+
if (strValue.length <= 4) {
|
|
134
|
+
return '****';
|
|
135
|
+
}
|
|
136
|
+
return `${strValue.slice(0, 2)}**...${strValue.slice(-2)}`;
|
|
137
|
+
}
|
|
138
|
+
return strValue;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get the loading order for loaders based on precedence strategy.
|
|
142
|
+
* Returns loaders sorted by priority (lower priority first, so higher priority loads last and wins).
|
|
143
|
+
*/
|
|
144
|
+
getLoadOrder() {
|
|
145
|
+
const { loaders, precedence } = this._options;
|
|
146
|
+
if (!loaders || loaders.length === 0) {
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
// If precedence is a custom array, use it
|
|
150
|
+
if (Array.isArray(precedence)) {
|
|
151
|
+
return this.sortByCustomPrecedence(loaders, precedence);
|
|
152
|
+
}
|
|
153
|
+
// Use predefined precedence order
|
|
154
|
+
const order = PRECEDENCE_ORDERS[precedence];
|
|
155
|
+
return this.sortByPredefinedOrder(loaders, order);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Sort loaders by custom precedence configuration
|
|
159
|
+
*/
|
|
160
|
+
sortByCustomPrecedence(loaders, precedence) {
|
|
161
|
+
const priorityMap = new Map();
|
|
162
|
+
for (const p of precedence) {
|
|
163
|
+
priorityMap.set(p.loader, p.priority);
|
|
164
|
+
}
|
|
165
|
+
// Sort by priority (lower first, so higher priority loads last and wins)
|
|
166
|
+
return [...loaders].sort((a, b) => {
|
|
167
|
+
const priorityA = priorityMap.get(a.getName()) ?? 0;
|
|
168
|
+
const priorityB = priorityMap.get(b.getName()) ?? 0;
|
|
169
|
+
return priorityA - priorityB;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Sort loaders by predefined order
|
|
174
|
+
*/
|
|
175
|
+
sortByPredefinedOrder(loaders, order) {
|
|
176
|
+
const orderMap = new Map();
|
|
177
|
+
order.forEach((name, index) => orderMap.set(name, index));
|
|
178
|
+
// Sort by order index (lower first, so higher index loads last and wins)
|
|
179
|
+
return [...loaders].sort((a, b) => {
|
|
180
|
+
const indexA = orderMap.get(a.getName()) ?? -1;
|
|
181
|
+
const indexB = orderMap.get(b.getName()) ?? -1;
|
|
182
|
+
return indexA - indexB;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Load configuration from all configured loaders.
|
|
187
|
+
* Loaders are executed in precedence order, with later loaders overriding earlier ones.
|
|
188
|
+
*/
|
|
189
|
+
async load() {
|
|
190
|
+
const startTime = Date.now();
|
|
191
|
+
const sources = [];
|
|
192
|
+
let mergedConfig = {};
|
|
193
|
+
const keyOrigins = new Map(); // Track which loader set each key
|
|
194
|
+
this.log('Loading configuration...');
|
|
195
|
+
const orderedLoaders = this.getLoadOrder();
|
|
196
|
+
for (const loader of orderedLoaders) {
|
|
197
|
+
const loaderName = loader.getName();
|
|
198
|
+
const loaderStartTime = Date.now();
|
|
199
|
+
try {
|
|
200
|
+
// Check if loader is available
|
|
201
|
+
const isAvailable = await loader.isAvailable();
|
|
202
|
+
if (!isAvailable) {
|
|
203
|
+
if (this._verboseOptions?.logTiming) {
|
|
204
|
+
this.log(`${loaderName}: skipped (not available)`);
|
|
205
|
+
}
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
// Load configuration from this loader
|
|
209
|
+
const loaderConfig = await loader.load();
|
|
210
|
+
const keysLoaded = Object.keys(loaderConfig);
|
|
211
|
+
const duration = Date.now() - loaderStartTime;
|
|
212
|
+
// Track source info
|
|
213
|
+
sources.push({
|
|
214
|
+
loader: loaderName,
|
|
215
|
+
keysLoaded,
|
|
216
|
+
duration,
|
|
217
|
+
});
|
|
218
|
+
// Log timing and keys
|
|
219
|
+
if (this._verboseOptions?.logTiming) {
|
|
220
|
+
this.log(`${loaderName}: loaded ${keysLoaded.length} keys in ${duration}ms`);
|
|
221
|
+
}
|
|
222
|
+
// Log individual keys and track overrides
|
|
223
|
+
for (const key of keysLoaded) {
|
|
224
|
+
const previousLoader = keyOrigins.get(key);
|
|
225
|
+
const isOverride = previousLoader !== undefined;
|
|
226
|
+
if (this._verboseOptions?.logKeys) {
|
|
227
|
+
let logLine = ` - ${key}`;
|
|
228
|
+
if (this._verboseOptions.logValues) {
|
|
229
|
+
logLine += ` = "${this.maskValue(key, loaderConfig[key])}"`;
|
|
230
|
+
}
|
|
231
|
+
if (isOverride && this._verboseOptions.logOverrides) {
|
|
232
|
+
logLine += ` (overrides ${previousLoader})`;
|
|
233
|
+
}
|
|
234
|
+
this.log(logLine);
|
|
235
|
+
}
|
|
236
|
+
keyOrigins.set(key, loaderName);
|
|
237
|
+
}
|
|
238
|
+
// Merge configuration (later loaders override earlier ones)
|
|
239
|
+
mergedConfig = { ...mergedConfig, ...loaderConfig };
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
throw new ConfigurationLoadError(`Failed to load configuration from ${loaderName}: ${error instanceof Error ? error.message : String(error)}`, loaderName, error instanceof Error ? error : undefined);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// Count overrides
|
|
246
|
+
const totalKeys = Object.keys(mergedConfig).length;
|
|
247
|
+
const totalDuration = Date.now() - startTime;
|
|
248
|
+
const overrideCount = sources.reduce((acc, s) => acc + s.keysLoaded.length, 0) - totalKeys;
|
|
249
|
+
if (this._verboseOptions?.logTiming) {
|
|
250
|
+
this.log(`Configuration loaded: ${totalKeys} total keys, ${overrideCount} overrides, ${totalDuration}ms total`);
|
|
251
|
+
}
|
|
252
|
+
// Validate if schema is provided and validation is enabled
|
|
253
|
+
if (this._options.schema && this._options.validateOnLoad) {
|
|
254
|
+
const result = this._options.schema.safeParse(mergedConfig);
|
|
255
|
+
if (!result.success) {
|
|
256
|
+
const zodError = result.error;
|
|
257
|
+
throw new ValidationError(`Configuration validation failed: ${zodError.errors.map((e) => `${e.path.join('.')}: ${e.message}`).join(', ')}`, zodError.errors, undefined);
|
|
258
|
+
}
|
|
259
|
+
this.config = result.data;
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
this.config = mergedConfig;
|
|
263
|
+
}
|
|
264
|
+
this.loadResult = {
|
|
265
|
+
config: this.config,
|
|
266
|
+
sources,
|
|
267
|
+
loadedAt: new Date(),
|
|
268
|
+
};
|
|
269
|
+
this.loaded = true;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Get a specific configuration value by key.
|
|
273
|
+
* @param key The configuration key
|
|
274
|
+
* @returns The configuration value
|
|
275
|
+
* @throws ConfigurationError if configuration is not loaded
|
|
276
|
+
*/
|
|
277
|
+
get(key) {
|
|
278
|
+
if (!this.loaded || this.config === null) {
|
|
279
|
+
throw new ConfigurationError('Configuration not loaded. Call load() first.');
|
|
280
|
+
}
|
|
281
|
+
// Non-null assertion is safe here because we've checked this.config !== null above
|
|
282
|
+
return this.config[key];
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Get all configuration values.
|
|
286
|
+
* @returns The complete configuration object
|
|
287
|
+
* @throws ConfigurationError if configuration is not loaded
|
|
288
|
+
*/
|
|
289
|
+
getAll() {
|
|
290
|
+
if (!this.loaded || this.config === null) {
|
|
291
|
+
throw new ConfigurationError('Configuration not loaded. Call load() first.');
|
|
292
|
+
}
|
|
293
|
+
return this.config;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Check if configuration has been loaded.
|
|
297
|
+
* @returns true if configuration is loaded
|
|
298
|
+
*/
|
|
299
|
+
isLoaded() {
|
|
300
|
+
return this.loaded;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Get the current application environment.
|
|
304
|
+
* @returns The APP_ENV value or 'development' as default
|
|
305
|
+
*/
|
|
306
|
+
getAppEnv() {
|
|
307
|
+
return process.env['APP_ENV'] ?? 'development';
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Get the load result with source information.
|
|
311
|
+
* @returns The load result or null if not loaded
|
|
312
|
+
*/
|
|
313
|
+
getLoadResult() {
|
|
314
|
+
return this.loadResult;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Serialize the current configuration to JSON string.
|
|
318
|
+
* @returns JSON string representation of the configuration
|
|
319
|
+
* @throws ConfigurationError if configuration is not loaded
|
|
320
|
+
*/
|
|
321
|
+
serialize() {
|
|
322
|
+
if (!this.loaded || this.config === null) {
|
|
323
|
+
throw new ConfigurationError('Configuration not loaded. Call load() first.');
|
|
324
|
+
}
|
|
325
|
+
return JSON.stringify(this.config);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Create a new ConfigManager with configuration loaded from a JSON string.
|
|
329
|
+
* This is useful for restoring configuration from a serialized state.
|
|
330
|
+
* @param json JSON string to deserialize
|
|
331
|
+
* @param options Optional ConfigManager options (schema will be used for validation)
|
|
332
|
+
* @returns A new ConfigManager instance with the deserialized configuration
|
|
333
|
+
*/
|
|
334
|
+
static deserialize(json, options = {}) {
|
|
335
|
+
const parsed = JSON.parse(json);
|
|
336
|
+
// Validate if schema is provided
|
|
337
|
+
if (options.schema) {
|
|
338
|
+
const result = options.schema.safeParse(parsed);
|
|
339
|
+
if (!result.success) {
|
|
340
|
+
const zodError = result.error;
|
|
341
|
+
throw new ValidationError(`Deserialization validation failed: ${zodError.errors.map((e) => `${e.path.join('.')}: ${e.message}`).join(', ')}`, zodError.errors, undefined);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
// Create a new ConfigManager and set its internal state
|
|
345
|
+
const manager = new ConfigManager(options);
|
|
346
|
+
manager.config = parsed;
|
|
347
|
+
manager.loaded = true;
|
|
348
|
+
manager.loadResult = {
|
|
349
|
+
config: parsed,
|
|
350
|
+
sources: [{ loader: 'deserialize', keysLoaded: Object.keys(parsed), duration: 0 }],
|
|
351
|
+
loadedAt: new Date(),
|
|
352
|
+
};
|
|
353
|
+
return manager;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
//# sourceMappingURL=config-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/config-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for all configuration-related errors
|
|
3
|
+
*/
|
|
4
|
+
export class ConfigurationError extends Error {
|
|
5
|
+
constructor(message, cause) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'ConfigurationError';
|
|
8
|
+
this.cause = cause;
|
|
9
|
+
Object.setPrototypeOf(this, ConfigurationError.prototype);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Error thrown when configuration validation fails
|
|
14
|
+
*/
|
|
15
|
+
export class ValidationError extends ConfigurationError {
|
|
16
|
+
constructor(message, validationErrors, cause) {
|
|
17
|
+
super(message, cause);
|
|
18
|
+
this.name = 'ValidationError';
|
|
19
|
+
this.validationErrors = validationErrors;
|
|
20
|
+
Object.setPrototypeOf(this, ValidationError.prototype);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Error thrown when an AWS service operation fails
|
|
25
|
+
*/
|
|
26
|
+
export class AWSServiceError extends ConfigurationError {
|
|
27
|
+
constructor(message, service, operation, cause) {
|
|
28
|
+
super(message, cause);
|
|
29
|
+
this.name = 'AWSServiceError';
|
|
30
|
+
this.service = service;
|
|
31
|
+
this.operation = operation;
|
|
32
|
+
Object.setPrototypeOf(this, AWSServiceError.prototype);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Error thrown when a configuration loader fails to load
|
|
37
|
+
*/
|
|
38
|
+
export class ConfigurationLoadError extends ConfigurationError {
|
|
39
|
+
constructor(message, loader, cause) {
|
|
40
|
+
super(message, cause);
|
|
41
|
+
this.name = 'ConfigurationLoadError';
|
|
42
|
+
this.loader = loader;
|
|
43
|
+
Object.setPrototypeOf(this, ConfigurationLoadError.prototype);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Error thrown when required configuration keys are missing
|
|
48
|
+
*/
|
|
49
|
+
export class MissingConfigurationError extends ConfigurationError {
|
|
50
|
+
constructor(message, missingKeys, cause) {
|
|
51
|
+
super(message, cause);
|
|
52
|
+
this.name = 'MissingConfigurationError';
|
|
53
|
+
this.missingKeys = missingKeys;
|
|
54
|
+
Object.setPrototypeOf(this, MissingConfigurationError.prototype);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/errors/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAI3C,YAAY,OAAe,EAAE,KAAa;QACxC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,eAAgB,SAAQ,kBAAkB;IAIrD,YAAY,OAAe,EAAE,gBAAyB,EAAE,KAAa;QACnE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IACzD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,eAAgB,SAAQ,kBAAkB;IAMrD,YAAY,OAAe,EAAE,OAAe,EAAE,SAAiB,EAAE,KAAa;QAC5E,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IACzD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,sBAAuB,SAAQ,kBAAkB;IAI5D,YAAY,OAAe,EAAE,MAAc,EAAE,KAAa;QACxD,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,yBAA0B,SAAQ,kBAAkB;IAI/D,YAAY,OAAe,EAAE,WAAqB,EAAE,KAAa;QAC/D,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QACxC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,yBAAyB,CAAC,SAAS,CAAC,CAAC;IACnE,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @dyanet/config-aws
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic AWS configuration management library.
|
|
5
|
+
* Supports environment variables, AWS Secrets Manager, SSM Parameter Store,
|
|
6
|
+
* S3, and .env files with configurable precedence.
|
|
7
|
+
*/
|
|
8
|
+
// Error classes
|
|
9
|
+
export { ConfigurationError, ValidationError, AWSServiceError, ConfigurationLoadError, MissingConfigurationError, } from './errors';
|
|
10
|
+
// Loaders
|
|
11
|
+
export { EnvironmentLoader } from './loaders/environment.loader';
|
|
12
|
+
export { EnvFileLoader } from './loaders/env-file.loader';
|
|
13
|
+
export { S3Loader } from './loaders/s3.loader';
|
|
14
|
+
export { SecretsManagerLoader } from './loaders/secrets-manager.loader';
|
|
15
|
+
export { SSMParameterStoreLoader } from './loaders/ssm-parameter-store.loader';
|
|
16
|
+
// ConfigManager
|
|
17
|
+
export { ConfigManager } from './config-manager';
|
|
18
|
+
// Utilities
|
|
19
|
+
export { ConfigValidationUtil } from './utils/validation.util';
|
|
20
|
+
export { EnvFileParser } from './utils/env-file-parser.util';
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsCH,gBAAgB;AAChB,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,UAAU,CAAC;AAElB,UAAU;AACV,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAE/E,gBAAgB;AAChB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,YAAY;AACZ,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC"}
|
|
@@ -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,130 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { EnvFileParser } from '../utils/env-file-parser.util';
|
|
4
|
+
import { ConfigurationLoadError } from '../errors';
|
|
5
|
+
/**
|
|
6
|
+
* Loader that reads configuration from .env files on the filesystem.
|
|
7
|
+
* Uses AWS ECS-compatible format for parsing.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* // Load from default paths (.env, .env.local)
|
|
12
|
+
* const loader = new EnvFileLoader();
|
|
13
|
+
*
|
|
14
|
+
* // Load from specific paths
|
|
15
|
+
* const loader = new EnvFileLoader({
|
|
16
|
+
* paths: ['.env', '.env.production']
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // Disable override (first file wins)
|
|
20
|
+
* const loader = new EnvFileLoader({
|
|
21
|
+
* paths: ['.env', '.env.local'],
|
|
22
|
+
* override: false
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/use-environment-file.html
|
|
27
|
+
*/
|
|
28
|
+
export class EnvFileLoader {
|
|
29
|
+
constructor(config = {}) {
|
|
30
|
+
this._config = {
|
|
31
|
+
paths: config.paths ?? EnvFileLoader.DEFAULT_PATHS,
|
|
32
|
+
encoding: config.encoding ?? EnvFileLoader.DEFAULT_ENCODING,
|
|
33
|
+
override: config.override ?? true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
getName() {
|
|
37
|
+
return 'EnvFileLoader';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Check if at least one of the configured .env files exists.
|
|
41
|
+
* @returns Promise resolving to true if any file exists
|
|
42
|
+
*/
|
|
43
|
+
async isAvailable() {
|
|
44
|
+
for (const filePath of this._config.paths) {
|
|
45
|
+
const resolvedPath = this.resolvePath(filePath);
|
|
46
|
+
if (await this.fileExists(resolvedPath)) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Load configuration from .env files.
|
|
54
|
+
*
|
|
55
|
+
* Files are processed in order. When override is true (default),
|
|
56
|
+
* later files override earlier ones. When override is false,
|
|
57
|
+
* earlier files take precedence.
|
|
58
|
+
*
|
|
59
|
+
* Missing files are silently skipped.
|
|
60
|
+
*
|
|
61
|
+
* @returns Promise resolving to the merged configuration
|
|
62
|
+
* @throws ConfigurationLoadError if a file exists but cannot be read
|
|
63
|
+
*/
|
|
64
|
+
async load() {
|
|
65
|
+
const result = {};
|
|
66
|
+
for (const filePath of this._config.paths) {
|
|
67
|
+
const resolvedPath = this.resolvePath(filePath);
|
|
68
|
+
if (!(await this.fileExists(resolvedPath))) {
|
|
69
|
+
// Skip missing files silently
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const content = await this.readFile(resolvedPath);
|
|
74
|
+
const parsed = EnvFileParser.parse(content);
|
|
75
|
+
// Merge based on override setting
|
|
76
|
+
if (this._config.override) {
|
|
77
|
+
// Later files override earlier ones
|
|
78
|
+
Object.assign(result, parsed);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Earlier files take precedence - only add keys that don't exist
|
|
82
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
83
|
+
if (!(key in result)) {
|
|
84
|
+
result[key] = value;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
throw new ConfigurationLoadError(`Failed to read env file: ${resolvedPath}`, this.getName(), error instanceof Error ? error : undefined);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Resolve a file path relative to the current working directory.
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
99
|
+
resolvePath(filePath) {
|
|
100
|
+
if (path.isAbsolute(filePath)) {
|
|
101
|
+
return filePath;
|
|
102
|
+
}
|
|
103
|
+
return path.resolve(process.cwd(), filePath);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Check if a file exists.
|
|
107
|
+
* @internal
|
|
108
|
+
*/
|
|
109
|
+
async fileExists(filePath) {
|
|
110
|
+
try {
|
|
111
|
+
await fs.promises.access(filePath, fs.constants.R_OK);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Read a file's contents.
|
|
120
|
+
* @internal
|
|
121
|
+
*/
|
|
122
|
+
async readFile(filePath) {
|
|
123
|
+
return fs.promises.readFile(filePath, { encoding: this._config.encoding });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Default paths to search for .env files */
|
|
127
|
+
EnvFileLoader.DEFAULT_PATHS = ['.env', '.env.local'];
|
|
128
|
+
/** Default file encoding */
|
|
129
|
+
EnvFileLoader.DEFAULT_ENCODING = 'utf-8';
|
|
130
|
+
//# 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":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,aAAa;IAUxB,YAAY,SAA8B,EAAE;QAC1C,IAAI,CAAC,OAAO,GAAG;YACb,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,aAAa,CAAC,aAAa;YAClD,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,aAAa,CAAC,gBAAgB;YAC3D,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;SAClC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,eAAe,CAAC;IACzB,CAAC;IAGD;;;OAGG;IACH,KAAK,CAAC,WAAW;QACf,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YAChD,IAAI,MAAM,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;gBACxC,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,MAAM,GAA4B,EAAE,CAAC;QAE3C,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YAEhD,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;gBAC3C,8BAA8B;gBAC9B,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;gBAClD,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAE5C,kCAAkC;gBAClC,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;oBAC1B,oCAAoC;oBACpC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAChC,CAAC;qBAAM,CAAC;oBACN,iEAAiE;oBACjE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;wBAClD,IAAI,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,EAAE,CAAC;4BACrB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;wBACtB,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,sBAAsB,CAC9B,4BAA4B,YAAY,EAAE,EAC1C,IAAI,CAAC,OAAO,EAAE,EACd,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAC3C,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;OAGG;IACO,WAAW,CAAC,QAAgB;QACpC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED;;;OAGG;IACO,KAAK,CAAC,UAAU,CAAC,QAAgB;QACzC,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACtD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;;OAGG;IACO,KAAK,CAAC,QAAQ,CAAC,QAAgB;QACvC,OAAO,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC7E,CAAC;;AAlHD,6CAA6C;AACrB,2BAAa,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAE/D,4BAA4B;AACJ,8BAAgB,GAAmB,OAAO,CAAC"}
|