@rawnodes/config-loader 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/LICENSE +21 -0
- package/README.md +225 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +3 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +100 -0
- package/dist/loader.js.map +1 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/deep-merge.d.ts +4 -0
- package/dist/utils/deep-merge.d.ts.map +1 -0
- package/dist/utils/deep-merge.js +18 -0
- package/dist/utils/deep-merge.js.map +1 -0
- package/dist/utils/env-replacer.d.ts +2 -0
- package/dist/utils/env-replacer.d.ts.map +1 -0
- package/dist/utils/env-replacer.js +42 -0
- package/dist/utils/env-replacer.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/mask-secrets.d.ts +2 -0
- package/dist/utils/mask-secrets.d.ts.map +1 -0
- package/dist/utils/mask-secrets.js +49 -0
- package/dist/utils/mask-secrets.js.map +1 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 RawNodes
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# @rawnodes/config-loader
|
|
2
|
+
|
|
3
|
+
Flexible YAML configuration loader for Node.js applications with environment overrides, Zod validation, and Docker-friendly features.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **YAML Configuration** - Load config from YAML files with environment-specific overrides
|
|
8
|
+
- **Environment Variables** - Replace `${VAR}` placeholders with env values
|
|
9
|
+
- **Zod Validation** - Optional schema validation with detailed error messages
|
|
10
|
+
- **Docker/K8s Ready** - Mount additional config files via `overrideDir`
|
|
11
|
+
- **Secret Masking** - Automatic masking of sensitive values in logs
|
|
12
|
+
- **TypeScript First** - Full type safety with generics
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @rawnodes/config-loader
|
|
18
|
+
# or
|
|
19
|
+
npm install @rawnodes/config-loader
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For Zod validation (optional):
|
|
23
|
+
```bash
|
|
24
|
+
pnpm add zod
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### 1. Create config files
|
|
30
|
+
|
|
31
|
+
```yaml
|
|
32
|
+
# config/base.yml
|
|
33
|
+
server:
|
|
34
|
+
port: 3000
|
|
35
|
+
host: localhost
|
|
36
|
+
|
|
37
|
+
database:
|
|
38
|
+
host: localhost
|
|
39
|
+
port: 5432
|
|
40
|
+
name: myapp
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
# config/production.yml
|
|
45
|
+
server:
|
|
46
|
+
host: 0.0.0.0
|
|
47
|
+
|
|
48
|
+
database:
|
|
49
|
+
host: ${DATABASE_HOST}
|
|
50
|
+
password: ${DATABASE_PASSWORD}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Load configuration
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { loadConfig } from '@rawnodes/config-loader';
|
|
57
|
+
|
|
58
|
+
interface AppConfig {
|
|
59
|
+
server: { port: number; host: string };
|
|
60
|
+
database: { host: string; port: number; name: string; password?: string };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const { config } = loadConfig<AppConfig>({
|
|
64
|
+
configDir: './config',
|
|
65
|
+
dotenv: true,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
console.log(config.server.port); // 3000
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Configuration Options
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
interface ConfigLoaderOptions<T> {
|
|
75
|
+
// Directory with config files (default: process.cwd())
|
|
76
|
+
configDir?: string;
|
|
77
|
+
|
|
78
|
+
// Base config filename without extension (default: 'base')
|
|
79
|
+
baseFileName?: string;
|
|
80
|
+
|
|
81
|
+
// Environment name (default: process.env.NODE_ENV || 'local')
|
|
82
|
+
environment?: string;
|
|
83
|
+
|
|
84
|
+
// File extension (default: 'yml')
|
|
85
|
+
extension?: 'yml' | 'yaml';
|
|
86
|
+
|
|
87
|
+
// Custom post-processing function
|
|
88
|
+
postProcess?: (config: T) => T;
|
|
89
|
+
|
|
90
|
+
// Zod schema for validation
|
|
91
|
+
schema?: z.ZodType<T>;
|
|
92
|
+
|
|
93
|
+
// Logger callback (config will be logged with masked secrets)
|
|
94
|
+
logger?: (message: string) => void;
|
|
95
|
+
|
|
96
|
+
// Load .env file (default: false)
|
|
97
|
+
dotenv?: boolean | { path?: string };
|
|
98
|
+
|
|
99
|
+
// Directory with additional YAML files to merge (default: '/etc/app/config')
|
|
100
|
+
// Set to false to disable
|
|
101
|
+
overrideDir?: string | false;
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Environment Variables
|
|
106
|
+
|
|
107
|
+
Use `${VAR}` syntax with optional defaults:
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
database:
|
|
111
|
+
host: ${DB_HOST:localhost}
|
|
112
|
+
port: ${DB_PORT:5432}
|
|
113
|
+
password: ${DB_PASSWORD} # Required - throws if not set
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Zod Validation
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { z } from 'zod';
|
|
120
|
+
import { loadConfig } from '@rawnodes/config-loader';
|
|
121
|
+
|
|
122
|
+
const AppConfigSchema = z.object({
|
|
123
|
+
server: z.object({
|
|
124
|
+
port: z.number().min(1).max(65535),
|
|
125
|
+
host: z.string(),
|
|
126
|
+
}),
|
|
127
|
+
database: z.object({
|
|
128
|
+
host: z.string(),
|
|
129
|
+
port: z.number(),
|
|
130
|
+
name: z.string(),
|
|
131
|
+
password: z.string().optional(),
|
|
132
|
+
}),
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
type AppConfig = z.infer<typeof AppConfigSchema>;
|
|
136
|
+
|
|
137
|
+
const { config } = loadConfig<AppConfig>({
|
|
138
|
+
schema: AppConfigSchema,
|
|
139
|
+
logger: console.log,
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Docker/Kubernetes Override
|
|
144
|
+
|
|
145
|
+
Mount additional config files in `/etc/app/config/`:
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
# /etc/app/config/01-secrets.yml
|
|
149
|
+
database:
|
|
150
|
+
password: super-secret
|
|
151
|
+
|
|
152
|
+
# /etc/app/config/02-overrides.yml
|
|
153
|
+
server:
|
|
154
|
+
port: 8080
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Files are merged in alphabetical order.
|
|
158
|
+
|
|
159
|
+
## NestJS Integration
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// config.module.ts
|
|
163
|
+
import { Module, Global } from '@nestjs/common';
|
|
164
|
+
import { loadConfig } from '@rawnodes/config-loader';
|
|
165
|
+
import { AppConfigSchema, AppConfig } from './app.config';
|
|
166
|
+
|
|
167
|
+
const { config } = loadConfig<AppConfig>({
|
|
168
|
+
schema: AppConfigSchema,
|
|
169
|
+
dotenv: true,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
@Global()
|
|
173
|
+
@Module({
|
|
174
|
+
providers: [
|
|
175
|
+
{
|
|
176
|
+
provide: 'CONFIG',
|
|
177
|
+
useValue: config,
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
exports: ['CONFIG'],
|
|
181
|
+
})
|
|
182
|
+
export class ConfigModule {}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## API
|
|
186
|
+
|
|
187
|
+
### `loadConfig<T>(options?): ConfigLoaderResult<T>`
|
|
188
|
+
|
|
189
|
+
Loads and merges configuration files.
|
|
190
|
+
|
|
191
|
+
**Returns:**
|
|
192
|
+
```typescript
|
|
193
|
+
interface ConfigLoaderResult<T> {
|
|
194
|
+
config: T; // Loaded configuration
|
|
195
|
+
environment: string; // Resolved environment name
|
|
196
|
+
configDir: string; // Resolved config directory path
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### `maskSecrets(obj): unknown`
|
|
201
|
+
|
|
202
|
+
Masks sensitive values in an object. Useful for logging.
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { maskSecrets } from '@rawnodes/config-loader';
|
|
206
|
+
|
|
207
|
+
const masked = maskSecrets({
|
|
208
|
+
user: 'admin',
|
|
209
|
+
password: 'secret123',
|
|
210
|
+
url: 'postgres://user:pass@localhost/db',
|
|
211
|
+
});
|
|
212
|
+
// { user: 'admin', password: 'se***23', url: 'postgres://user:***@localhost/db' }
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### `deepMerge(base, override): object`
|
|
216
|
+
|
|
217
|
+
Deep merges two objects.
|
|
218
|
+
|
|
219
|
+
### `replacePlaceholders(obj): unknown`
|
|
220
|
+
|
|
221
|
+
Replaces `${VAR}` placeholders with environment variable values.
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/E,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,GACd,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAW1E,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAE,mBAAmB,CAAC,CAAC,CAAM,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAuDzF"}
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { readFileSync, existsSync, readdirSync } from 'fs';
|
|
2
|
+
import * as yaml from 'js-yaml';
|
|
3
|
+
import * as dotenv from 'dotenv';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { deepMerge, replacePlaceholders, maskSecrets } from './utils/index.js';
|
|
6
|
+
const DEFAULT_OPTIONS = {
|
|
7
|
+
configDir: process.cwd(),
|
|
8
|
+
baseFileName: 'base',
|
|
9
|
+
environment: process.env.NODE_ENV || 'local',
|
|
10
|
+
extension: 'yml',
|
|
11
|
+
overrideDir: '/etc/app/config',
|
|
12
|
+
};
|
|
13
|
+
export function loadConfig(options = {}) {
|
|
14
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
15
|
+
const { configDir, baseFileName, environment, extension } = opts;
|
|
16
|
+
// Load .env if requested
|
|
17
|
+
if (options.dotenv) {
|
|
18
|
+
loadDotenv(options.dotenv, environment);
|
|
19
|
+
}
|
|
20
|
+
const resolvedConfigDir = resolveConfigDir(configDir);
|
|
21
|
+
const baseConfig = loadYamlFile(resolvedConfigDir, `${baseFileName}.${extension}`);
|
|
22
|
+
const envConfig = loadYamlFile(resolvedConfigDir, `${environment}.${extension}`);
|
|
23
|
+
let mergedConfig = deepMerge(baseConfig, envConfig);
|
|
24
|
+
// Load override files from directory
|
|
25
|
+
const overrideDir = options.overrideDir !== false ? (options.overrideDir ?? DEFAULT_OPTIONS.overrideDir) : null;
|
|
26
|
+
if (overrideDir) {
|
|
27
|
+
const overrideConfigs = loadOverrideDir(overrideDir);
|
|
28
|
+
for (const override of overrideConfigs) {
|
|
29
|
+
mergedConfig = deepMerge(mergedConfig, override);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
let config = replacePlaceholders(mergedConfig);
|
|
33
|
+
// Post-process
|
|
34
|
+
if (options.postProcess) {
|
|
35
|
+
config = options.postProcess(config);
|
|
36
|
+
}
|
|
37
|
+
// Validate with Zod schema
|
|
38
|
+
if (options.schema) {
|
|
39
|
+
const result = options.schema.safeParse(config);
|
|
40
|
+
if (!result.success) {
|
|
41
|
+
const errors = result.error.issues
|
|
42
|
+
.map((e) => ` - ${e.path.join('.')}: ${e.message}`)
|
|
43
|
+
.join('\n');
|
|
44
|
+
throw new Error(`Config validation failed:\n${errors}`);
|
|
45
|
+
}
|
|
46
|
+
config = result.data;
|
|
47
|
+
}
|
|
48
|
+
// Log config with masked secrets
|
|
49
|
+
if (options.logger) {
|
|
50
|
+
const maskedConfig = maskSecrets(config);
|
|
51
|
+
options.logger(`Config loaded (${environment}):\n${JSON.stringify(maskedConfig, null, 2)}`);
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
config,
|
|
55
|
+
environment,
|
|
56
|
+
configDir: resolvedConfigDir,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function loadDotenv(dotenvOption, environment) {
|
|
60
|
+
let envPath;
|
|
61
|
+
if (typeof dotenvOption === 'object' && dotenvOption.path) {
|
|
62
|
+
envPath = dotenvOption.path;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
envPath = environment === 'production' ? '.env' : `.env.${environment}`;
|
|
66
|
+
}
|
|
67
|
+
dotenv.config({ path: envPath });
|
|
68
|
+
}
|
|
69
|
+
function resolveConfigDir(configDir) {
|
|
70
|
+
const possiblePaths = [
|
|
71
|
+
join(configDir, 'src', 'config'),
|
|
72
|
+
join(configDir, 'dist', 'config'),
|
|
73
|
+
join(configDir, 'config'),
|
|
74
|
+
configDir,
|
|
75
|
+
];
|
|
76
|
+
for (const path of possiblePaths) {
|
|
77
|
+
if (existsSync(join(path, 'base.yml')) || existsSync(join(path, 'base.yaml'))) {
|
|
78
|
+
return path;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
throw new Error(`Config files not found. Searched in:\n${possiblePaths.map((p) => ` - ${p}`).join('\n')}`);
|
|
82
|
+
}
|
|
83
|
+
function loadYamlFile(dir, filename) {
|
|
84
|
+
const filePath = join(dir, filename);
|
|
85
|
+
if (!existsSync(filePath)) {
|
|
86
|
+
return {};
|
|
87
|
+
}
|
|
88
|
+
const content = readFileSync(filePath, 'utf8');
|
|
89
|
+
return yaml.load(content) || {};
|
|
90
|
+
}
|
|
91
|
+
function loadOverrideDir(dir) {
|
|
92
|
+
if (!existsSync(dir)) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
const files = readdirSync(dir)
|
|
96
|
+
.filter((f) => f.endsWith('.yml') || f.endsWith('.yaml'))
|
|
97
|
+
.sort();
|
|
98
|
+
return files.map((file) => loadYamlFile(dir, file));
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
export interface DotenvOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Path to .env file
|
|
5
|
+
* @default auto-detected based on NODE_ENV
|
|
6
|
+
*/
|
|
7
|
+
path?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ConfigLoaderOptions<T = unknown> {
|
|
10
|
+
/**
|
|
11
|
+
* Directory where config files are located
|
|
12
|
+
* @default process.cwd()
|
|
13
|
+
*/
|
|
14
|
+
configDir?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Base config filename (without extension)
|
|
17
|
+
* @default 'base'
|
|
18
|
+
*/
|
|
19
|
+
baseFileName?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Environment name for environment-specific config
|
|
22
|
+
* @default process.env.NODE_ENV || 'local'
|
|
23
|
+
*/
|
|
24
|
+
environment?: string;
|
|
25
|
+
/**
|
|
26
|
+
* File extension
|
|
27
|
+
* @default 'yml'
|
|
28
|
+
*/
|
|
29
|
+
extension?: 'yml' | 'yaml';
|
|
30
|
+
/**
|
|
31
|
+
* Custom post-processing function to transform the loaded config
|
|
32
|
+
*/
|
|
33
|
+
postProcess?: (config: T) => T;
|
|
34
|
+
/**
|
|
35
|
+
* Zod schema for validation
|
|
36
|
+
* If provided, config will be validated against this schema
|
|
37
|
+
*/
|
|
38
|
+
schema?: z.ZodType<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Logger callback for logging loaded config
|
|
41
|
+
* Config will be logged with secrets masked
|
|
42
|
+
*/
|
|
43
|
+
logger?: (message: string) => void;
|
|
44
|
+
/**
|
|
45
|
+
* Load .env file before loading config
|
|
46
|
+
* - true: auto-detect .env file based on NODE_ENV
|
|
47
|
+
* - object: custom options
|
|
48
|
+
*/
|
|
49
|
+
dotenv?: boolean | DotenvOptions;
|
|
50
|
+
/**
|
|
51
|
+
* Directory with additional YAML files to merge
|
|
52
|
+
* All *.yml files in this directory will be merged (sorted by filename)
|
|
53
|
+
* Useful for Docker/Kubernetes config mounts
|
|
54
|
+
* @default '/etc/app/config'
|
|
55
|
+
*/
|
|
56
|
+
overrideDir?: string | false;
|
|
57
|
+
}
|
|
58
|
+
export interface ConfigLoaderResult<T> {
|
|
59
|
+
config: T;
|
|
60
|
+
environment: string;
|
|
61
|
+
configDir: string;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC,GAAG,OAAO;IAC9C;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAE3B;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;IAE/B;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAEtB;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnC;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,aAAa,CAAC;IAEjC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,MAAM,EAAE,CAAC,CAAC;IACV,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deep-merge.d.ts","sourceRoot":"","sources":["../../src/utils/deep-merge.ts"],"names":[],"mappings":"AAAA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1C,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,GAAG,UAAU,CAe5E"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function deepMerge(base, override) {
|
|
2
|
+
const merged = { ...base };
|
|
3
|
+
for (const key in override) {
|
|
4
|
+
const overrideValue = override[key];
|
|
5
|
+
const baseValue = base[key];
|
|
6
|
+
if (isPlainObject(overrideValue) && isPlainObject(baseValue)) {
|
|
7
|
+
merged[key] = deepMerge(baseValue, overrideValue);
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
merged[key] = overrideValue;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return merged;
|
|
14
|
+
}
|
|
15
|
+
function isPlainObject(value) {
|
|
16
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=deep-merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deep-merge.js","sourceRoot":"","sources":["../../src/utils/deep-merge.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CAAC,IAAgB,EAAE,QAAoB;IAC9D,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;IAE3B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,aAAa,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QAE5B,IAAI,aAAa,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7D,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,SAAuB,EAAE,aAA2B,CAAC,CAAC;QAChF,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-replacer.d.ts","sourceRoot":"","sources":["../../src/utils/env-replacer.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAkBzD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const ENV_PLACEHOLDER_REGEX = /\${(.*?)}/g;
|
|
2
|
+
export function replacePlaceholders(obj) {
|
|
3
|
+
if (typeof obj === 'string') {
|
|
4
|
+
return replaceStringPlaceholders(obj);
|
|
5
|
+
}
|
|
6
|
+
if (Array.isArray(obj)) {
|
|
7
|
+
return obj.map((item) => replacePlaceholders(item));
|
|
8
|
+
}
|
|
9
|
+
if (isPlainObject(obj)) {
|
|
10
|
+
const result = {};
|
|
11
|
+
for (const key of Object.keys(obj)) {
|
|
12
|
+
result[key] = replacePlaceholders(obj[key]);
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
return obj;
|
|
17
|
+
}
|
|
18
|
+
function replaceStringPlaceholders(str) {
|
|
19
|
+
return str.replace(ENV_PLACEHOLDER_REGEX, (match, key) => {
|
|
20
|
+
const [envKey, ...rest] = key.split(':');
|
|
21
|
+
const defaultValue = rest.length > 0 ? rest.join(':') : undefined;
|
|
22
|
+
const envValue = process.env[envKey];
|
|
23
|
+
let value;
|
|
24
|
+
if (envValue !== undefined) {
|
|
25
|
+
value = envValue;
|
|
26
|
+
}
|
|
27
|
+
else if (defaultValue !== undefined) {
|
|
28
|
+
value = defaultValue;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
throw new Error(`Environment variable "${envKey}" is not defined and no default value provided`);
|
|
32
|
+
}
|
|
33
|
+
if (value.includes('${')) {
|
|
34
|
+
return replacePlaceholders(value);
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function isPlainObject(value) {
|
|
40
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=env-replacer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-replacer.js","sourceRoot":"","sources":["../../src/utils/env-replacer.ts"],"names":[],"mappings":"AAAA,MAAM,qBAAqB,GAAG,YAAY,CAAC;AAE3C,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,yBAAyB,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,CAAC,GAAG,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,yBAAyB,CAAC,GAAW;IAC5C,OAAO,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACvD,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAClE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAErC,IAAI,KAAa,CAAC;QAClB,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,KAAK,GAAG,QAAQ,CAAC;QACnB,CAAC;aAAM,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YACtC,KAAK,GAAG,YAAY,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,gDAAgD,CAAC,CAAC;QACnG,CAAC;QAED,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,OAAO,mBAAmB,CAAC,KAAK,CAAW,CAAC;QAC9C,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mask-secrets.d.ts","sourceRoot":"","sources":["../../src/utils/mask-secrets.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAuBjD"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const SECRET_PATTERNS = ['token', 'password', 'secret', 'key', 'apikey', 'api_key', 'credential'];
|
|
2
|
+
const URL_WITH_CREDENTIALS_REGEX = /^([a-z]+:\/\/)([^:]+):([^@]+)@(.+)$/i;
|
|
3
|
+
export function maskSecrets(obj) {
|
|
4
|
+
if (typeof obj === 'string') {
|
|
5
|
+
return maskUrlCredentials(obj);
|
|
6
|
+
}
|
|
7
|
+
if (Array.isArray(obj)) {
|
|
8
|
+
return obj.map((item) => maskSecrets(item));
|
|
9
|
+
}
|
|
10
|
+
if (isPlainObject(obj)) {
|
|
11
|
+
const result = {};
|
|
12
|
+
for (const key of Object.keys(obj)) {
|
|
13
|
+
const value = obj[key];
|
|
14
|
+
if (isSecretKey(key)) {
|
|
15
|
+
result[key] = maskValue(value);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
result[key] = maskSecrets(value);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
return obj;
|
|
24
|
+
}
|
|
25
|
+
function isSecretKey(key) {
|
|
26
|
+
const lowerKey = key.toLowerCase();
|
|
27
|
+
return SECRET_PATTERNS.some((pattern) => lowerKey.includes(pattern));
|
|
28
|
+
}
|
|
29
|
+
function maskValue(value) {
|
|
30
|
+
if (typeof value !== 'string') {
|
|
31
|
+
return '***';
|
|
32
|
+
}
|
|
33
|
+
if (value.length <= 4) {
|
|
34
|
+
return '***';
|
|
35
|
+
}
|
|
36
|
+
return value.slice(0, 2) + '***' + value.slice(-2);
|
|
37
|
+
}
|
|
38
|
+
function maskUrlCredentials(url) {
|
|
39
|
+
const match = url.match(URL_WITH_CREDENTIALS_REGEX);
|
|
40
|
+
if (match) {
|
|
41
|
+
const [, protocol, user, , host] = match;
|
|
42
|
+
return `${protocol}${user}:***@${host}`;
|
|
43
|
+
}
|
|
44
|
+
return url;
|
|
45
|
+
}
|
|
46
|
+
function isPlainObject(value) {
|
|
47
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=mask-secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mask-secrets.js","sourceRoot":"","sources":["../../src/utils/mask-secrets.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;AAElG,MAAM,0BAA0B,GAAG,sCAAsC,CAAC;AAE1E,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;YACvB,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;YACjC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IACnC,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAW;IACrC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACpD,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,AAAD,EAAG,IAAI,CAAC,GAAG,KAAK,CAAC;QACzC,OAAO,GAAG,QAAQ,GAAG,IAAI,QAAQ,IAAI,EAAE,CAAC;IAC1C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rawnodes/config-loader",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Flexible YAML config loader with environment overrides, Zod validation, and Docker-friendly features",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"dev": "tsc --watch",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"test:coverage": "vitest run --coverage",
|
|
25
|
+
"lint": "eslint src --ext .ts",
|
|
26
|
+
"prepublishOnly": "pnpm build"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"config",
|
|
30
|
+
"configuration",
|
|
31
|
+
"yaml",
|
|
32
|
+
"environment",
|
|
33
|
+
"dotenv",
|
|
34
|
+
"zod",
|
|
35
|
+
"typescript",
|
|
36
|
+
"docker",
|
|
37
|
+
"kubernetes"
|
|
38
|
+
],
|
|
39
|
+
"author": "RawNodes",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/rawnodes/config-loader.git"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"dotenv": "^16.4.5",
|
|
50
|
+
"js-yaml": "^4.1.0"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"zod": "^3.0.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependenciesMeta": {
|
|
56
|
+
"zod": {
|
|
57
|
+
"optional": true
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/js-yaml": "^4.0.9",
|
|
62
|
+
"@types/node": "^22.0.0",
|
|
63
|
+
"typescript": "^5.7.0",
|
|
64
|
+
"vitest": "^2.0.0",
|
|
65
|
+
"zod": "^3.24.0"
|
|
66
|
+
}
|
|
67
|
+
}
|