@pawells/config 2.3.0 → 3.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/dist/errors.js CHANGED
@@ -1,17 +1,18 @@
1
1
  /**
2
2
  * Custom error classes for configuration management.
3
3
  *
4
- * Exports: {@link ConfigurationAlreadyRegisteredError}, {@link ConfigurationNotRegisteredError},
5
- * {@link ConfigurationError}, and {@link ConfigurationNotSetError}.
4
+ * Exports: {@link ConfigRegistrationError}, {@link ConfigNotRegisteredError},
5
+ * {@link ConfigError}, and {@link ConfigNotSetError}.
6
6
  */
7
+ import { BaseError } from '@pawells/typescript-common';
7
8
  /**
8
9
  * Abstract base class for configuration errors.
9
10
  * Automatically sets the error name to the class constructor name.
10
11
  */
11
- class ConfigurationBaseError extends Error {
12
- constructor(message) {
13
- super(message);
14
- this.name = this.constructor.name;
12
+ export class ConfigError extends BaseError {
13
+ constructor(message, metadata = {}) {
14
+ metadata.code ??= 'CONFIG_ERROR';
15
+ super(message, metadata);
15
16
  }
16
17
  }
17
18
  /**
@@ -20,58 +21,55 @@ class ConfigurationBaseError extends Error {
20
21
  * @param key - The configuration key that was already registered
21
22
  *
22
23
  * @example
23
- * throw new ConfigurationAlreadyRegisteredError('DATABASE_URL');
24
+ * throw new ConfigRegistrationError('DATABASE_URL');
24
25
  */
25
- export class ConfigurationAlreadyRegisteredError extends ConfigurationBaseError {
26
- Code = 'CONFIGURATION_ALREADY_REGISTERED';
27
- constructor(key) {
28
- super(`Configuration key "${key}" is already registered with a different schema.`);
26
+ export class ConfigRegistrationError extends ConfigError {
27
+ constructor(key, metadata = {}) {
28
+ metadata.code ??= 'CONFIG_REGISTRATION_ERROR';
29
+ super(`Configuration key "${key}" is already registered with a different schema.`, metadata);
29
30
  }
30
31
  }
31
32
  /**
32
- * Error thrown when attempting to access a configuration key that was not registered.
33
+ * Error thrown when a required configuration value is not set.
33
34
  *
34
- * @param key - The configuration key that is not registered
35
+ * @param key - The configuration key that is not set
35
36
  *
36
37
  * @example
37
- * throw new ConfigurationNotRegisteredError('UNKNOWN_KEY');
38
+ * throw new ConfigNotSetError('DATABASE_URL');
38
39
  */
39
- export class ConfigurationNotRegisteredError extends ConfigurationBaseError {
40
- Code = 'CONFIGURATION_NOT_REGISTERED';
41
- constructor(key) {
42
- super(`Configuration key "${key}" is not registered.`);
40
+ export class ConfigNotSetError extends ConfigError {
41
+ constructor(key, metadata = {}) {
42
+ metadata.code ??= 'CONFIG_NOT_SET_ERROR';
43
+ super(`Configuration key "${key}" is not set.`, metadata);
43
44
  }
44
45
  }
45
46
  /**
46
- * Error thrown when configuration validation fails.
47
+ * Error thrown when a configuration key is not registered.
47
48
  *
48
- * @param key - The configuration key that failed validation
49
- * @param message - Detailed error message about the validation failure
50
- * @param options - Optional options object with cause
49
+ * @param key - The configuration key that is not registered
51
50
  *
52
51
  * @example
53
- * throw new ConfigurationError('PORT', 'Must be a positive number');
52
+ * throw new ConfigNotRegisteredError('DATABASE_URL');
54
53
  */
55
- export class ConfigurationError extends ConfigurationBaseError {
56
- Code = 'CONFIGURATION_ERROR';
57
- constructor(key, message, options) {
58
- super(`Validation failed for configuration "${key}": ${message}`);
59
- if (options?.cause) {
60
- this.cause = options.cause;
61
- }
54
+ export class ConfigNotRegisteredError extends ConfigError {
55
+ constructor(key, metadata = {}) {
56
+ metadata.code ??= 'CONFIG_NOT_REGISTERED';
57
+ super(`Configuration key "${key}" is not registered.`, metadata);
62
58
  }
63
59
  }
64
60
  /**
65
- * Error thrown when a required configuration value is not set.
61
+ * Error thrown when a configuration value fails schema validation.
66
62
  *
67
- * @param key - The configuration key that is not set
63
+ * @param key - The configuration key that failed validation
64
+ * @param validationMessage - The validation error message describing why the value is invalid
68
65
  *
69
66
  * @example
70
- * throw new ConfigurationNotSetError('DATABASE_URL');
67
+ * throw new ConfigValidationError('PORT', 'Expected a number between 1 and 65535');
71
68
  */
72
- export class ConfigurationNotSetError extends ConfigurationBaseError {
73
- Code = 'CONFIGURATION_NOT_SET';
74
- constructor(key) {
75
- super(`Configuration key "${key}" is not set.`);
69
+ export class ConfigValidationError extends ConfigError {
70
+ constructor(key, validationMessage, metadata = {}) {
71
+ metadata.code ??= 'CONFIG_VALIDATION_ERROR';
72
+ super(`Validation Failed for Configuration "${key}": ${validationMessage}`, metadata);
76
73
  }
77
74
  }
75
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAuB,MAAM,4BAA4B,CAAC;AAE5E;;;GAGG;AACH,MAAM,OAAO,WAAY,SAAQ,SAAS;IACzC,YAAY,OAAe,EAAE,WAA2B,EAAE;QACzD,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC;QACjC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1B,CAAC;CACD;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,uBAAwB,SAAQ,WAAW;IACvD,YAAY,GAAW,EAAE,WAA2B,EAAE;QACrD,QAAQ,CAAC,IAAI,KAAK,2BAA2B,CAAC;QAC9C,KAAK,CAAC,sBAAsB,GAAG,kDAAkD,EAAE,QAAQ,CAAC,CAAC;IAC9F,CAAC;CACD;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAkB,SAAQ,WAAW;IACjD,YAAY,GAAW,EAAE,WAA2B,EAAE;QACrD,QAAQ,CAAC,IAAI,KAAK,sBAAsB,CAAC;QACzC,KAAK,CAAC,sBAAsB,GAAG,eAAe,EAAE,QAAQ,CAAC,CAAC;IAC3D,CAAC;CACD;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,wBAAyB,SAAQ,WAAW;IACxD,YAAY,GAAW,EAAE,WAA2B,EAAE;QACrD,QAAQ,CAAC,IAAI,KAAK,uBAAuB,CAAC;QAC1C,KAAK,CAAC,sBAAsB,GAAG,sBAAsB,EAAE,QAAQ,CAAC,CAAC;IAClE,CAAC;CACD;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,qBAAsB,SAAQ,WAAW;IACrD,YAAY,GAAW,EAAE,iBAAyB,EAAE,WAA2B,EAAE;QAChF,QAAQ,CAAC,IAAI,KAAK,yBAAyB,CAAC;QAC5C,KAAK,CAAC,wCAAwC,GAAG,MAAM,iBAAiB,EAAE,EAAE,QAAQ,CAAC,CAAC;IACvF,CAAC;CACD"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,13 @@
1
- export * from './errors.js';
2
- export * from './manager.js';
3
- export * from './schema.factory.js';
1
+ export { ConfigError, ConfigRegistrationError, ConfigNotSetError, ConfigNotRegisteredError, ConfigValidationError } from './errors.js';
2
+ export { ConfigManager, ScopedConfigManager } from './manager.js';
3
+ export type { TConfigSource, TConfigValueTypes, TConfig } from './manager.js';
4
+ export { CONFIG_VALUES_TYPES_SCHEMA, AssertConfigValueType } from './manager.js';
5
+ export { ConfigProvider } from './provider.js';
6
+ export type { IConfigProvider, ISyncConfigProvider, SaveOptions, ConfigSaveEntry, IConfigSaveEntry } from './provider.js';
7
+ export { CONFIG_PROVIDER_OPTIONS_SCHEMA, CONFIG_PROVIDER_SAVE_OPTIONS_SCHEMA } from './provider.js';
8
+ export type { TConfigProviderOptions, TConfigProviderSaveOptions } from './provider.js';
9
+ export { AssertConfigProviderOptions, ValidateConfigProviderOptions } from './provider.js';
10
+ export { RegisterConfigSchema } from './schema.factory.js';
11
+ export type { IConfigSchemaObject } from './schema.factory.js';
4
12
  export { Secret } from './secret.js';
5
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGvI,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAClE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGjF,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC1H,OAAO,EAAE,8BAA8B,EAAE,mCAAmC,EAAE,MAAM,eAAe,CAAC;AACpG,YAAY,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AACxF,OAAO,EAAE,2BAA2B,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAG3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG/D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,14 @@
1
- export * from './errors.js';
2
- export * from './manager.js';
3
- export * from './schema.factory.js';
1
+ // Errors
2
+ export { ConfigError, ConfigRegistrationError, ConfigNotSetError, ConfigNotRegisteredError, ConfigValidationError } from './errors.js';
3
+ // Manager (static singleton)
4
+ export { ConfigManager, ScopedConfigManager } from './manager.js';
5
+ export { CONFIG_VALUES_TYPES_SCHEMA, AssertConfigValueType } from './manager.js';
6
+ // Provider abstractions and schemas
7
+ export { ConfigProvider } from './provider.js';
8
+ export { CONFIG_PROVIDER_OPTIONS_SCHEMA, CONFIG_PROVIDER_SAVE_OPTIONS_SCHEMA } from './provider.js';
9
+ export { AssertConfigProviderOptions, ValidateConfigProviderOptions } from './provider.js';
10
+ // Schema factory
11
+ export { RegisterConfigSchema } from './schema.factory.js';
12
+ // Secret utility
4
13
  export { Secret } from './secret.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,SAAS;AACT,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEvI,6BAA6B;AAC7B,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAElE,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAEjF,oCAAoC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,8BAA8B,EAAE,mCAAmC,EAAE,MAAM,eAAe,CAAC;AAEpG,OAAO,EAAE,2BAA2B,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAE3F,iBAAiB;AACjB,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAG3D,iBAAiB;AACjB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
package/dist/manager.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod/v4';
2
+ import type { IConfigProvider, ISyncConfigProvider, SaveOptions } from './provider.js';
2
3
  /**
3
4
  * Zod schema for all supported configuration value types.
4
5
  * Accepts string, number, boolean, Date, string[], number[], boolean[], and undefined — nullable and optional.
@@ -26,102 +27,320 @@ export type TConfigSource = 'DEFAULT' | 'OVERRIDE';
26
27
  * Provides a singleton instance to register and retrieve typed configuration values.
27
28
  *
28
29
  * @example
30
+ * ```typescript
29
31
  * ConfigManager.Register('DATABASE_URL', z.string().url(), 'postgresql://localhost/mydb');
30
- * ConfigManager.Set('DEFAULT', 'DATABASE_URL', 'postgresql://localhost/mydb');
32
+ * ConfigManager.Set('DATABASE_URL', 'postgresql://localhost/mydb');
31
33
  * const url = ConfigManager.Get('DATABASE_URL');
34
+ * ```
32
35
  */
33
36
  export declare class ConfigManager {
34
- private static readonly _Schemas;
35
- private static readonly _DataDefaults;
36
- private static readonly _DataOverrides;
37
- private static get _Data();
37
+ private static readonly _state;
38
38
  /**
39
39
  * Reset the singleton instance (for testing).
40
+ *
40
41
  * @internal
41
42
  */
42
43
  static Reset(): void;
44
+ /**
45
+ * Set an optional handler for provider validation warnings.
46
+ *
47
+ * When a provider value fails schema validation, if a handler is set,
48
+ * it will be called with the key and provider name. If no handler is set,
49
+ * validation failures are silent (no-op).
50
+ *
51
+ * @param handler - Function to call on validation failure, or undefined to clear
52
+ * @example
53
+ * ```typescript
54
+ * ConfigManager.SetValidationWarningHandler((key, providerName) => {
55
+ * console.warn(`Provider ${providerName} failed for key ${key}`);
56
+ * });
57
+ * ```
58
+ */
59
+ static SetValidationWarningHandler(handler: ((key: string, providerName: string) => void) | undefined): void;
60
+ /**
61
+ * Register a configuration namespace for use when building save entries.
62
+ *
63
+ * Records the mapping from `prefix` to `sectionName` so that
64
+ * {@link Save} can split fully-qualified keys into section and field
65
+ * components (e.g. `KEYCLOAK_HOST` → section `KEYCLOAK`, field `HOST`).
66
+ *
67
+ * Called automatically by `RegisterConfigSchema` — applications do not
68
+ * normally need to call this directly.
69
+ *
70
+ * @param name - Human-readable namespace name (e.g. `'Keycloak'`)
71
+ * @param prefix - Derived environment variable prefix (e.g. `'KEYCLOAK_'`)
72
+ * @example
73
+ * ```typescript
74
+ * ConfigManager.RegisterNamespace('Keycloak', 'KEYCLOAK_');
75
+ * // KEYCLOAK_HOST → section='KEYCLOAK', field='HOST'
76
+ * ```
77
+ */
78
+ static RegisterNamespace(name: string, prefix: string): void;
79
+ /**
80
+ * Save all registered configuration values via a provider.
81
+ *
82
+ * Builds a {@link ConfigSaveEntry} for every registered schema key, then
83
+ * delegates formatting and file I/O to `provider.Save()`.
84
+ *
85
+ * In template mode (`useCurrentValues: false`, the default), each entry
86
+ * carries the registered default value. In current-values mode
87
+ * (`useCurrentValues: true`), each entry carries the fully resolved live
88
+ * value (DEFAULT → provider values → OVERRIDE). The `isSecret` flag is
89
+ * set for fields marked with {@link Secret}; providers are expected to
90
+ * redact those appropriately in template mode.
91
+ *
92
+ * @param provider - An {@link IConfigProvider} that handles the write
93
+ * @param options - Output path and save mode
94
+ * @returns - A promise that resolves when the save operation completes
95
+ * @remarks In `useCurrentValues` mode, keys that cannot be resolved (not set, not registered, or failing validation) are written as blank/undefined without throwing.
96
+ * @example
97
+ * ```typescript
98
+ * // Write .env.example (template, secrets blank)
99
+ * await ConfigManager.Save(envProvider, { path: '.env.example' });
100
+ *
101
+ * // Snapshot current runtime values
102
+ * await ConfigManager.Save(envProvider, { path: '.env', useCurrentValues: true });
103
+ * ```
104
+ */
105
+ static Save(provider: IConfigProvider, options: SaveOptions): Promise<void>;
106
+ /**
107
+ * Register a configuration value provider with the manager.
108
+ *
109
+ * Immediately calls `provider.Load()` to obtain all key/value pairs from the
110
+ * provider. All raw values are stored in the internal raw-data cache so that
111
+ * schemas registered after this call can still receive provider values.
112
+ * For any key that already has a registered schema, the raw value is validated
113
+ * and the validated result is stored in the provider values tier.
114
+ *
115
+ * Provider values occupy the middle precedence tier: they override registered
116
+ * defaults but are themselves overridden by explicit {@link Set} calls.
117
+ * When multiple providers supply the same key, the last-registered provider wins.
118
+ *
119
+ * @param provider - An {@link IConfigProvider} implementation to register
120
+ * @returns - A promise that resolves when registration completes
121
+ * @example
122
+ * ```typescript
123
+ * import { ConfigEnvironmentProvider } from '@pawells/config-provider-env';
124
+ * import { ConfigJSONProvider } from '@pawells/config-provider-json';
125
+ *
126
+ * // Register before importing any schema modules
127
+ * await ConfigManager.RegisterProvider(await ConfigEnvironmentProvider.Register({ path: '.env' }));
128
+ * await ConfigManager.RegisterProvider(await ConfigJSONProvider.Register({ path: './config.json' }));
129
+ * ```
130
+ */
131
+ static RegisterProvider(provider: IConfigProvider): Promise<void>;
132
+ /**
133
+ * Register a synchronous configuration provider with the manager.
134
+ * Use this only in contexts that cannot `await`. Most code should prefer
135
+ * `RegisterProvider()` with an async provider.
136
+ *
137
+ * Immediately calls `provider.LoadSync()` to obtain all key/value pairs from the
138
+ * provider. All raw values are stored in the internal raw-data cache so that
139
+ * schemas registered after this call can still receive provider values.
140
+ * For any key that already has a registered schema, the raw value is validated
141
+ * and the validated result is stored in the provider values tier.
142
+ *
143
+ * @param provider - An {@link ISyncConfigProvider} implementation to register
144
+ * @example
145
+ * ```typescript
146
+ * class MemoryProvider implements ISyncConfigProvider {
147
+ * readonly name = 'memory';
148
+ * LoadSync() {
149
+ * return { MY_KEY: 'value' };
150
+ * }
151
+ * }
152
+ * ConfigManager.RegisterSyncProvider(new MemoryProvider());
153
+ * ```
154
+ */
155
+ static RegisterSyncProvider(provider: ISyncConfigProvider): void;
43
156
  private constructor();
44
157
  /**
45
158
  * Register a configuration schema.
159
+ *
46
160
  * @param key - Unique configuration key
47
161
  * @param schema - Zod schema for runtime validation
48
162
  * @param defaultValue - Initial value for the configuration key, must satisfy the schema
49
- * @throws {ConfigurationAlreadyRegisteredError} If key is already registered
163
+ * @throws {ConfigRegistrationError} If key is already registered with a different schema
164
+ * @throws {ConfigValidationError} If defaultValue does not match the schema
50
165
  * @example
166
+ * ```typescript
51
167
  * ConfigManager.Register('PORT', z.coerce.number().positive(), 3000);
52
168
  * ConfigManager.Register('JWT_SECRET', z.string().min(32), 'default-secret');
169
+ * ```
53
170
  */
54
- static Register(key: string, schema: z.ZodType<TConfigValueTypes>, defaultValue: unknown): void;
171
+ static Register(key: string, schema: z.ZodTypeAny, defaultValue: unknown): void;
55
172
  /**
56
173
  * Set a configuration value and validate against its schema.
174
+ *
57
175
  * @param key - Configuration key
58
176
  * @param value - Value to set and validate
59
177
  * @param target - Whether to set the default store or the override store; defaults to `'OVERRIDE'`
60
- * @throws {ConfigurationNotRegisteredError} If schema is not registered for key
61
- * @throws {ConfigurationError} If validation fails
178
+ * @throws {ConfigNotRegisteredError} If schema is not registered for key
179
+ * @throws {ConfigValidationError} If validation fails
180
+ * @remarks
181
+ * When validation fails for a field marked with `Secret()`, the error message and error cause are sanitized to prevent secret values from appearing in error logs or stack traces.
62
182
  * @example
63
- * manager.set('PORT', 3000);
64
- * manager.set('JWT_SECRET', process.env.SECRET);
183
+ * ```typescript
184
+ * ConfigManager.Set('PORT', 3000);
185
+ * ConfigManager.Set('JWT_SECRET', process.env.SECRET);
186
+ * ```
65
187
  */
66
188
  static Set<T extends TConfigValueTypes>(key: string, value: T, target?: TConfigSource): void;
67
189
  /**
68
190
  * Retrieve a configuration value by key.
191
+ *
69
192
  * Returns the value parsed by its registered schema.
193
+ *
70
194
  * @param key - Configuration key
71
195
  * @param source - Optional — filter to a specific store (`'DEFAULT'` or `'OVERRIDE'`); omit to return the resolved value (overrides take precedence over defaults)
72
196
  * @returns The typed configuration value
73
- * @throws {ConfigurationNotSetError} If value was not set
74
- * @throws {ConfigurationNotRegisteredError} If schema is not registered
75
- * @throws {ConfigurationError} If validation fails on retrieval
197
+ * @throws {ConfigNotSetError} If value was not set
198
+ * @throws {ConfigNotRegisteredError} If schema is not registered
199
+ * @throws {ConfigValidationError} If validation fails on retrieval
76
200
  * @example
77
- * const port = manager.get('PORT'); // Returns number, guaranteed by schema
78
- * const secret = manager.get('JWT_SECRET'); // Returns string
201
+ * ```typescript
202
+ * const port = ConfigManager.Get('PORT'); // Returns number, guaranteed by schema
203
+ * const secret = ConfigManager.Get('JWT_SECRET'); // Returns string
204
+ * ```
79
205
  */
80
206
  static Get(key: string, source?: TConfigSource): TConfigValueTypes;
81
207
  /**
82
208
  * Retrieve the schema for a configuration key.
209
+ *
83
210
  * @param key - Configuration key
84
211
  * @returns The Zod schema for this configuration
85
- * @throws {ConfigurationNotRegisteredError} If schema is not registered for key
212
+ * @throws {ConfigNotRegisteredError} If schema is not registered for key
86
213
  * @example
87
- * const schema = manager.getSchema('PORT');
214
+ * ```typescript
215
+ * const schema = ConfigManager.GetSchema('PORT');
88
216
  * const parsed = schema.safeParse(value);
217
+ * ```
89
218
  */
90
219
  static GetSchema(key: string): z.ZodTypeAny;
220
+ }
221
+ /**
222
+ * Instance-based configuration manager for test isolation and multi-tenant scenarios.
223
+ *
224
+ * Unlike the static singleton {@link ConfigManager}, `ScopedConfigManager` maintains
225
+ * independent state in instance fields. This enables isolated configuration contexts
226
+ * without affecting the global singleton or other instances.
227
+ *
228
+ * The public API mirrors `ConfigManager` exactly, but as instance methods instead of
229
+ * static methods. Use this when you need:
230
+ * - Test isolation: each test gets its own config instance
231
+ * - Multi-tenant scenarios: separate configs per tenant
232
+ * - Feature-gating: isolated experimental configs
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * // Two independent configurations
237
+ * const config1 = new ScopedConfigManager();
238
+ * const config2 = new ScopedConfigManager();
239
+ *
240
+ * config1.Register('PORT', z.coerce.number(), 3000);
241
+ * config2.Register('PORT', z.coerce.number(), 4000);
242
+ *
243
+ * config1.Get('PORT'); // 3000
244
+ * config2.Get('PORT'); // 4000 — independent state
245
+ * ```
246
+ */
247
+ export declare class ScopedConfigManager {
248
+ private readonly _state;
249
+ constructor();
91
250
  /**
92
- * Generates a `.env` file string from all currently registered configuration keys.
251
+ * Reset this instance (for testing).
252
+ */
253
+ Reset(): void;
254
+ /**
255
+ * Set an optional handler for provider validation warnings.
93
256
  *
94
- * In template mode (default), each key is emitted with its registered default value.
95
- * Secret fields (marked with `Secret()`) are always emitted with a blank value in template
96
- * mode, regardless of their registered default.
97
- * In current-values mode, the live resolved value from `Get(key)` is used; keys that are
98
- * unset or produce a configuration error are emitted as commented-out blank lines (`# KEY=`).
257
+ * When a provider value fails schema validation, if a handler is set,
258
+ * it will be called with the key and provider name. If no handler is set,
259
+ * validation failures are silent (no-op).
99
260
  *
100
- * If a field has a Zod `.describe()` annotation, it is emitted as a `# comment` line
101
- * immediately before the key–value pair.
261
+ * @param handler - Function to call on validation failure, or undefined to clear
262
+ */
263
+ SetValidationWarningHandler(handler: ((key: string, providerName: string) => void) | undefined): void;
264
+ /**
265
+ * Register a configuration namespace for use when building save entries.
102
266
  *
103
- * @param options - Optional configuration for generation behavior
104
- * @param options.useCurrentValues - When `true`, emit current live values from `Get(key)`.
105
- * Defaults to `false` (template mode using registered defaults).
106
- * @param options.path - When provided, write the generated string to this file path in UTF-8.
107
- * @returns - The generated `.env` content as a string.
267
+ * Records the mapping from `prefix` to `sectionName` so that
268
+ * {@link Save} can split fully-qualified keys into section and field
269
+ * components (e.g. `KEYCLOAK_HOST` section `KEYCLOAK`, field `HOST`).
108
270
  *
109
- * @example
110
- * ```typescript
111
- * // Template mode — defaults shown, secrets blank
112
- * const template = ConfigManager.GenerateEnv();
113
- * // "APP_HOST=localhost\nAPP_PORT=3000\nAPP_SECRET_KEY="
114
- * ```
271
+ * @param name - Human-readable namespace name (e.g. `'Keycloak'`)
272
+ * @param prefix - Derived environment variable prefix (e.g. `'KEYCLOAK_'`)
273
+ */
274
+ RegisterNamespace(name: string, prefix: string): void;
275
+ /**
276
+ * Save all registered configuration values via a provider.
115
277
  *
116
- * @example
117
- * ```typescript
118
- * // Save current runtime settings to a file
119
- * ConfigManager.GenerateEnv({ useCurrentValues: true, path: '.env.snapshot' });
120
- * ```
278
+ * Builds a {@link ConfigSaveEntry} for every registered schema key, then
279
+ * delegates formatting and file I/O to `provider.Save()`.
280
+ *
281
+ * @param provider - An {@link IConfigProvider} that handles the write
282
+ * @param options - Output path and save mode
283
+ * @returns - A promise that resolves when the save operation completes
284
+ */
285
+ Save(provider: IConfigProvider, options: SaveOptions): Promise<void>;
286
+ /**
287
+ * Register a configuration value provider with this instance.
288
+ *
289
+ * @param provider - An {@link IConfigProvider} implementation to register
290
+ * @returns - A promise that resolves when registration completes
291
+ */
292
+ RegisterProvider(provider: IConfigProvider): Promise<void>;
293
+ /**
294
+ * Register a synchronous configuration provider with this instance.
295
+ *
296
+ * Use this only in contexts that cannot `await`. Most code should prefer
297
+ * `RegisterProvider()` with an async provider.
298
+ *
299
+ * @param provider - An {@link ISyncConfigProvider} implementation to register
300
+ */
301
+ RegisterSyncProvider(provider: ISyncConfigProvider): void;
302
+ /**
303
+ * Register a configuration schema.
304
+ *
305
+ * @param key - Unique configuration key
306
+ * @param schema - Zod schema for runtime validation
307
+ * @param defaultValue - Initial value for the configuration key, must satisfy the schema
308
+ * @throws {ConfigRegistrationError} If key is already registered with a different schema
309
+ * @throws {ConfigValidationError} If defaultValue does not match the schema
310
+ */
311
+ Register(key: string, schema: z.ZodTypeAny, defaultValue: unknown): void;
312
+ /**
313
+ * Set a configuration value and validate against its schema.
314
+ *
315
+ * @param key - Configuration key
316
+ * @param value - Value to set and validate
317
+ * @param target - Whether to set the default store or the override store; defaults to `'OVERRIDE'`
318
+ * @throws {ConfigNotRegisteredError} If schema is not registered for key
319
+ * @throws {ConfigValidationError} If validation fails
320
+ * @remarks
321
+ * When validation fails for a field marked with `Secret()`, the error message and error cause are sanitized to prevent secret values from appearing in error logs or stack traces.
322
+ */
323
+ Set<T extends TConfigValueTypes>(key: string, value: T, target?: TConfigSource): void;
324
+ /**
325
+ * Retrieve a configuration value by key.
326
+ *
327
+ * Returns the value parsed by its registered schema.
328
+ *
329
+ * @param key - Configuration key
330
+ * @param source - Optional — filter to a specific store (`'DEFAULT'` or `'OVERRIDE'`); omit to return the resolved value (overrides take precedence over defaults)
331
+ * @returns The typed configuration value
332
+ * @throws {ConfigNotSetError} If value was not set
333
+ * @throws {ConfigNotRegisteredError} If schema is not registered
334
+ * @throws {ConfigValidationError} If validation fails on retrieval
335
+ */
336
+ Get(key: string, source?: TConfigSource): TConfigValueTypes;
337
+ /**
338
+ * Retrieve the schema for a configuration key.
339
+ *
340
+ * @param key - Configuration key
341
+ * @returns The Zod schema for this configuration
342
+ * @throws {ConfigNotRegisteredError} If schema is not registered for key
121
343
  */
122
- static GenerateEnv(options?: {
123
- useCurrentValues?: boolean;
124
- path?: string;
125
- }): string;
344
+ GetSchema(key: string): z.ZodTypeAny;
126
345
  }
127
346
  //# sourceMappingURL=manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAI3B;;;GAGG;AACH,eAAO,MAAM,0BAA0B,oMASf,CAAC;AAEzB;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,iBAAiB,CAExF;AAED,wDAAwD;AACxD,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE3E,uDAAuD;AACvD,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AAErD,wGAAwG;AACxG,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AA8CnD;;;;;;;;GAQG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAwC;IAGxE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAsB;IAG3D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAsB;IAG5D,OAAO,CAAC,MAAM,KAAK,KAAK,GAMvB;IAED;;;OAGG;WACW,KAAK,IAAI,IAAI;IAM3B,OAAO;IAEP;;;;;;;;;OASG;WACW,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,YAAY,EAAE,OAAO,GAAG,IAAI;IAUtG;;;;;;;;;;OAUG;WACW,GAAG,CAAC,CAAC,SAAS,iBAAiB,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,GAAE,aAA0B,GAAG,IAAI;IAkB/G;;;;;;;;;;;;OAYG;WACW,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,iBAAiB;IAgBzE;;;;;;;;OAQG;WACW,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC,UAAU;IAMlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;WACW,WAAW,CAAC,OAAO,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;CA6C1F"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}