@rawnodes/config-loader 1.1.0 → 1.2.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/index.js +44 -18
- package/dist/index.js.map +1 -1
- package/dist/{index.cjs → index.mjs} +20 -46
- package/dist/index.mjs.map +1 -0
- package/package.json +11 -7
- package/dist/index.cjs.map +0 -1
- /package/dist/{index.d.cts → index.d.mts} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var yaml = require('js-yaml');
|
|
5
|
+
var dotenv = require('dotenv');
|
|
6
|
+
var path = require('path');
|
|
7
|
+
|
|
8
|
+
function _interopNamespace(e) {
|
|
9
|
+
if (e && e.__esModule) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var yaml__namespace = /*#__PURE__*/_interopNamespace(yaml);
|
|
27
|
+
var dotenv__namespace = /*#__PURE__*/_interopNamespace(dotenv);
|
|
5
28
|
|
|
6
29
|
// src/loader.ts
|
|
7
30
|
|
|
@@ -169,18 +192,18 @@ function loadDotenv(dotenvOption, environment) {
|
|
|
169
192
|
} else {
|
|
170
193
|
envPath = environment === "production" ? ".env" : `.env.${environment}`;
|
|
171
194
|
}
|
|
172
|
-
|
|
195
|
+
dotenv__namespace.config({ path: envPath });
|
|
173
196
|
}
|
|
174
197
|
function resolveConfigDir(configDir) {
|
|
175
198
|
const possiblePaths = [
|
|
176
|
-
join(configDir, "src", "config"),
|
|
177
|
-
join(configDir, "dist", "config"),
|
|
178
|
-
join(configDir, "config"),
|
|
199
|
+
path.join(configDir, "src", "config"),
|
|
200
|
+
path.join(configDir, "dist", "config"),
|
|
201
|
+
path.join(configDir, "config"),
|
|
179
202
|
configDir
|
|
180
203
|
];
|
|
181
|
-
for (const path of possiblePaths) {
|
|
182
|
-
if (existsSync(join(path, "base.yml")) || existsSync(join(path, "base.yaml"))) {
|
|
183
|
-
return path;
|
|
204
|
+
for (const path$1 of possiblePaths) {
|
|
205
|
+
if (fs.existsSync(path.join(path$1, "base.yml")) || fs.existsSync(path.join(path$1, "base.yaml"))) {
|
|
206
|
+
return path$1;
|
|
184
207
|
}
|
|
185
208
|
}
|
|
186
209
|
throw new Error(
|
|
@@ -189,21 +212,24 @@ ${possiblePaths.map((p) => ` - ${p}`).join("\n")}`
|
|
|
189
212
|
);
|
|
190
213
|
}
|
|
191
214
|
function loadYamlFile(dir, filename) {
|
|
192
|
-
const filePath = join(dir, filename);
|
|
193
|
-
if (!existsSync(filePath)) {
|
|
215
|
+
const filePath = path.join(dir, filename);
|
|
216
|
+
if (!fs.existsSync(filePath)) {
|
|
194
217
|
return {};
|
|
195
218
|
}
|
|
196
|
-
const content = readFileSync(filePath, "utf8");
|
|
197
|
-
return
|
|
219
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
220
|
+
return yaml__namespace.load(content) || {};
|
|
198
221
|
}
|
|
199
222
|
function loadOverrideDir(dir) {
|
|
200
|
-
if (!existsSync(dir)) {
|
|
223
|
+
if (!fs.existsSync(dir)) {
|
|
201
224
|
return [];
|
|
202
225
|
}
|
|
203
|
-
const files = readdirSync(dir).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml")).sort();
|
|
226
|
+
const files = fs.readdirSync(dir).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml")).sort();
|
|
204
227
|
return files.map((file) => loadYamlFile(dir, file));
|
|
205
228
|
}
|
|
206
229
|
|
|
207
|
-
|
|
230
|
+
exports.deepMerge = deepMerge;
|
|
231
|
+
exports.loadConfig = loadConfig;
|
|
232
|
+
exports.maskSecrets = maskSecrets;
|
|
233
|
+
exports.replacePlaceholders = replacePlaceholders;
|
|
208
234
|
//# sourceMappingURL=index.js.map
|
|
209
235
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/deep-merge.ts","../src/utils/env-replacer.ts","../src/utils/mask-secrets.ts","../src/loader.ts"],"names":["isPlainObject","config"],"mappings":"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","file":"index.js","sourcesContent":["type DeepObject = Record<string, unknown>;\n\nexport function deepMerge(base: DeepObject, override: DeepObject): DeepObject {\n const merged = { ...base };\n\n for (const key in override) {\n const overrideValue = override[key];\n const baseValue = base[key];\n\n if (isPlainObject(overrideValue) && isPlainObject(baseValue)) {\n merged[key] = deepMerge(baseValue as DeepObject, overrideValue as DeepObject);\n } else {\n merged[key] = overrideValue;\n }\n }\n\n return merged;\n}\n\nfunction isPlainObject(value: unknown): value is DeepObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","const ENV_PLACEHOLDER_REGEX = /\\${(.*?)}/g;\n\nexport function replacePlaceholders(obj: unknown): unknown {\n if (typeof obj === 'string') {\n return replaceStringPlaceholders(obj);\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => replacePlaceholders(item));\n }\n\n if (isPlainObject(obj)) {\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n result[key] = replacePlaceholders(obj[key]);\n }\n return result;\n }\n\n return obj;\n}\n\nfunction replaceStringPlaceholders(str: string): string {\n return str.replace(ENV_PLACEHOLDER_REGEX, (match, key) => {\n const [envKey, ...rest] = key.split(':');\n const defaultValue = rest.length > 0 ? rest.join(':') : undefined;\n const envValue = process.env[envKey];\n\n let value: string;\n if (envValue !== undefined) {\n value = envValue;\n } else if (defaultValue !== undefined) {\n value = defaultValue;\n } else {\n throw new Error(`Environment variable \"${envKey}\" is not defined and no default value provided`);\n }\n\n if (value.includes('${')) {\n return replacePlaceholders(value) as string;\n }\n\n return value;\n });\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","const SECRET_PATTERNS = ['token', 'password', 'secret', 'key', 'apikey', 'api_key', 'credential'];\n\nconst URL_WITH_CREDENTIALS_REGEX = /^([a-z]+:\\/\\/)([^:]+):([^@]+)@(.+)$/i;\n\nexport function maskSecrets(obj: unknown): unknown {\n if (typeof obj === 'string') {\n return maskUrlCredentials(obj);\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => maskSecrets(item));\n }\n\n if (isPlainObject(obj)) {\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n const value = obj[key];\n if (isSecretKey(key)) {\n result[key] = maskValue(value);\n } else {\n result[key] = maskSecrets(value);\n }\n }\n return result;\n }\n\n return obj;\n}\n\nfunction isSecretKey(key: string): boolean {\n const lowerKey = key.toLowerCase();\n return SECRET_PATTERNS.some((pattern) => lowerKey.includes(pattern));\n}\n\nfunction maskValue(value: unknown): string {\n if (typeof value !== 'string') {\n return '***';\n }\n if (value.length <= 4) {\n return '***';\n }\n return value.slice(0, 2) + '***' + value.slice(-2);\n}\n\nfunction maskUrlCredentials(url: string): string {\n const match = url.match(URL_WITH_CREDENTIALS_REGEX);\n if (match) {\n const [, protocol, user, , host] = match;\n return `${protocol}${user}:***@${host}`;\n }\n return url;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","import { readFileSync, existsSync, readdirSync } from 'fs';\nimport * as yaml from 'js-yaml';\nimport * as dotenv from 'dotenv';\nimport { join } from 'path';\nimport type { ConfigLoaderOptions, ConfigLoaderResult } from './types.js';\nimport { deepMerge, replacePlaceholders, maskSecrets } from './utils/index.js';\n\nconst DEFAULT_OPTIONS = {\n configDir: process.cwd(),\n baseFileName: 'base',\n environment: process.env.NODE_ENV || 'local',\n extension: 'yml' as const,\n overrideDir: '/etc/app/config',\n};\n\nexport function loadConfig<T>(options: ConfigLoaderOptions<T> = {}): ConfigLoaderResult<T> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const { configDir, baseFileName, environment, extension } = opts;\n\n // Load .env if requested\n if (options.dotenv) {\n loadDotenv(options.dotenv, environment);\n }\n\n const resolvedConfigDir = resolveConfigDir(configDir);\n\n const baseConfig = loadYamlFile(resolvedConfigDir, `${baseFileName}.${extension}`);\n const envConfig = loadYamlFile(resolvedConfigDir, `${environment}.${extension}`);\n\n let mergedConfig = deepMerge(baseConfig, envConfig);\n\n // Load override files from directory\n const overrideDir = options.overrideDir !== false ? (options.overrideDir ?? DEFAULT_OPTIONS.overrideDir) : null;\n if (overrideDir) {\n const overrideConfigs = loadOverrideDir(overrideDir);\n for (const override of overrideConfigs) {\n mergedConfig = deepMerge(mergedConfig, override);\n }\n }\n\n let config = replacePlaceholders(mergedConfig) as T;\n\n // Post-process\n if (options.postProcess) {\n config = options.postProcess(config);\n }\n\n // Validate with Zod schema\n if (options.schema) {\n const result = options.schema.safeParse(config);\n if (!result.success) {\n const errors = result.error.issues\n .map((e) => ` - ${e.path.join('.')}: ${e.message}`)\n .join('\\n');\n throw new Error(`Config validation failed:\\n${errors}`);\n }\n config = result.data;\n }\n\n // Log config with masked secrets\n if (options.logger) {\n const maskedConfig = maskSecrets(config);\n options.logger(`Config loaded (${environment}):\\n${JSON.stringify(maskedConfig, null, 2)}`);\n }\n\n return {\n config,\n environment,\n configDir: resolvedConfigDir,\n };\n}\n\nfunction loadDotenv(\n dotenvOption: boolean | { path?: string },\n environment: string,\n): void {\n let envPath: string;\n\n if (typeof dotenvOption === 'object' && dotenvOption.path) {\n envPath = dotenvOption.path;\n } else {\n envPath = environment === 'production' ? '.env' : `.env.${environment}`;\n }\n\n dotenv.config({ path: envPath });\n}\n\nfunction resolveConfigDir(configDir: string): string {\n const possiblePaths = [\n join(configDir, 'src', 'config'),\n join(configDir, 'dist', 'config'),\n join(configDir, 'config'),\n configDir,\n ];\n\n for (const path of possiblePaths) {\n if (existsSync(join(path, 'base.yml')) || existsSync(join(path, 'base.yaml'))) {\n return path;\n }\n }\n\n throw new Error(\n `Config files not found. Searched in:\\n${possiblePaths.map((p) => ` - ${p}`).join('\\n')}`,\n );\n}\n\nfunction loadYamlFile(dir: string, filename: string): Record<string, unknown> {\n const filePath = join(dir, filename);\n\n if (!existsSync(filePath)) {\n return {};\n }\n\n const content = readFileSync(filePath, 'utf8');\n return (yaml.load(content) as Record<string, unknown>) || {};\n}\n\nfunction loadOverrideDir(dir: string): Record<string, unknown>[] {\n if (!existsSync(dir)) {\n return [];\n }\n\n const files = readdirSync(dir)\n .filter((f) => f.endsWith('.yml') || f.endsWith('.yaml'))\n .sort();\n\n return files.map((file) => loadYamlFile(dir, file));\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/deep-merge.ts","../src/utils/env-replacer.ts","../src/utils/mask-secrets.ts","../src/loader.ts"],"names":["isPlainObject","config","dotenv","join","path","existsSync","readFileSync","yaml","readdirSync"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEO,SAAS,SAAA,CAAU,MAAkB,QAAA,EAAkC;AAC5E,EAAA,MAAM,MAAA,GAAS,EAAE,GAAG,IAAA,EAAK;AAEzB,EAAA,KAAA,MAAW,OAAO,QAAA,EAAU;AAC1B,IAAA,MAAM,aAAA,GAAgB,SAAS,GAAG,CAAA;AAClC,IAAA,MAAM,SAAA,GAAY,KAAK,GAAG,CAAA;AAE1B,IAAA,IAAI,aAAA,CAAc,aAAa,CAAA,IAAK,aAAA,CAAc,SAAS,CAAA,EAAG;AAC5D,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,SAAA,CAAU,SAAA,EAAyB,aAA2B,CAAA;AAAA,IAC9E,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,aAAA;AAAA,IAChB;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,cAAc,KAAA,EAAqC;AAC1D,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5E;;;ACrBA,IAAM,qBAAA,GAAwB,YAAA;AAEvB,SAAS,oBAAoB,GAAA,EAAuB;AACzD,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,IAAA,OAAO,0BAA0B,GAAG,CAAA;AAAA,EACtC;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtB,IAAA,OAAO,IAAI,GAAA,CAAI,CAAC,IAAA,KAAS,mBAAA,CAAoB,IAAI,CAAC,CAAA;AAAA,EACpD;AAEA,EAAA,IAAIA,cAAAA,CAAc,GAAG,CAAA,EAAG;AACtB,IAAA,MAAM,SAAkC,EAAC;AACzC,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,EAAG;AAClC,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,mBAAA,CAAoB,GAAA,CAAI,GAAG,CAAC,CAAA;AAAA,IAC5C;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,0BAA0B,GAAA,EAAqB;AACtD,EAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,qBAAA,EAAuB,CAAC,OAAO,GAAA,KAAQ;AACxD,IAAA,MAAM,CAAC,MAAA,EAAQ,GAAG,IAAI,CAAA,GAAI,GAAA,CAAI,MAAM,GAAG,CAAA;AACvC,IAAA,MAAM,eAAe,IAAA,CAAK,MAAA,GAAS,IAAI,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA,GAAI,MAAA;AACxD,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA;AAEnC,IAAA,IAAI,KAAA;AACJ,IAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,MAAA,KAAA,GAAQ,QAAA;AAAA,IACV,CAAA,MAAA,IAAW,iBAAiB,MAAA,EAAW;AACrC,MAAA,KAAA,GAAQ,YAAA;AAAA,IACV,CAAA,MAAO;AACL,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,MAAM,CAAA,8CAAA,CAAgD,CAAA;AAAA,IACjG;AAEA,IAAA,IAAI,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA,EAAG;AACxB,MAAA,OAAO,oBAAoB,KAAK,CAAA;AAAA,IAClC;AAEA,IAAA,OAAO,KAAA;AAAA,EACT,CAAC,CAAA;AACH;AAEA,SAASA,eAAc,KAAA,EAAkD;AACvE,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5E;;;AC/CA,IAAM,eAAA,GAAkB,CAAC,OAAA,EAAS,UAAA,EAAY,UAAU,KAAA,EAAO,QAAA,EAAU,WAAW,YAAY,CAAA;AAEhG,IAAM,0BAAA,GAA6B,sCAAA;AAE5B,SAAS,YAAY,GAAA,EAAuB;AACjD,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,IAAA,OAAO,mBAAmB,GAAG,CAAA;AAAA,EAC/B;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtB,IAAA,OAAO,IAAI,GAAA,CAAI,CAAC,IAAA,KAAS,WAAA,CAAY,IAAI,CAAC,CAAA;AAAA,EAC5C;AAEA,EAAA,IAAIA,cAAAA,CAAc,GAAG,CAAA,EAAG;AACtB,IAAA,MAAM,SAAkC,EAAC;AACzC,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,EAAG;AAClC,MAAA,MAAM,KAAA,GAAQ,IAAI,GAAG,CAAA;AACrB,MAAA,IAAI,WAAA,CAAY,GAAG,CAAA,EAAG;AACpB,QAAA,MAAA,CAAO,GAAG,CAAA,GAAI,SAAA,CAAU,KAAK,CAAA;AAAA,MAC/B,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,GAAG,CAAA,GAAI,WAAA,CAAY,KAAK,CAAA;AAAA,MACjC;AAAA,IACF;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,YAAY,GAAA,EAAsB;AACzC,EAAA,MAAM,QAAA,GAAW,IAAI,WAAA,EAAY;AACjC,EAAA,OAAO,gBAAgB,IAAA,CAAK,CAAC,YAAY,QAAA,CAAS,QAAA,CAAS,OAAO,CAAC,CAAA;AACrE;AAEA,SAAS,UAAU,KAAA,EAAwB;AACzC,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,IAAI,KAAA,CAAM,UAAU,CAAA,EAAG;AACrB,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA,CAAM,MAAM,CAAA,EAAG,CAAC,IAAI,KAAA,GAAQ,KAAA,CAAM,MAAM,EAAE,CAAA;AACnD;AAEA,SAAS,mBAAmB,GAAA,EAAqB;AAC/C,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,0BAA0B,CAAA;AAClD,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,MAAM,GAAG,QAAA,EAAU,IAAA,IAAQ,IAAI,CAAA,GAAI,KAAA;AACnC,IAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,EAAG,IAAI,QAAQ,IAAI,CAAA,CAAA;AAAA,EACvC;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAASA,eAAc,KAAA,EAAkD;AACvE,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5E;;;AChDA,IAAM,eAAA,GAAkB;AAAA,EACtB,SAAA,EAAW,QAAQ,GAAA,EAAI;AAAA,EACvB,YAAA,EAAc,MAAA;AAAA,EACd,WAAA,EAAa,OAAA,CAAQ,GAAA,CAAI,QAAA,IAAY,OAAA;AAAA,EACrC,SAAA,EAAW,KAAA;AAAA,EACX,WAAA,EAAa;AACf,CAAA;AAEO,SAAS,UAAA,CAAc,OAAA,GAAkC,EAAC,EAA0B;AACzF,EAAA,MAAM,IAAA,GAAO,EAAE,GAAG,eAAA,EAAiB,GAAG,OAAA,EAAQ;AAC9C,EAAA,MAAM,EAAE,SAAA,EAAW,YAAA,EAAc,WAAA,EAAa,WAAU,GAAI,IAAA;AAG5D,EAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,IAAA,UAAA,CAAW,OAAA,CAAQ,QAAQ,WAAW,CAAA;AAAA,EACxC;AAEA,EAAA,MAAM,iBAAA,GAAoB,iBAAiB,SAAS,CAAA;AAEpD,EAAA,MAAM,aAAa,YAAA,CAAa,iBAAA,EAAmB,GAAG,YAAY,CAAA,CAAA,EAAI,SAAS,CAAA,CAAE,CAAA;AACjF,EAAA,MAAM,YAAY,YAAA,CAAa,iBAAA,EAAmB,GAAG,WAAW,CAAA,CAAA,EAAI,SAAS,CAAA,CAAE,CAAA;AAE/E,EAAA,IAAI,YAAA,GAAe,SAAA,CAAU,UAAA,EAAY,SAAS,CAAA;AAGlD,EAAA,MAAM,cAAc,OAAA,CAAQ,WAAA,KAAgB,QAAS,OAAA,CAAQ,WAAA,IAAe,gBAAgB,WAAA,GAAe,IAAA;AAC3G,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,MAAM,eAAA,GAAkB,gBAAgB,WAAW,CAAA;AACnD,IAAA,KAAA,MAAW,YAAY,eAAA,EAAiB;AACtC,MAAA,YAAA,GAAe,SAAA,CAAU,cAAc,QAAQ,CAAA;AAAA,IACjD;AAAA,EACF;AAEA,EAAA,IAAIC,OAAAA,GAAS,oBAAoB,YAAY,CAAA;AAG7C,EAAA,IAAI,QAAQ,WAAA,EAAa;AACvB,IAAAA,OAAAA,GAAS,OAAA,CAAQ,WAAA,CAAYA,OAAM,CAAA;AAAA,EACrC;AAGA,EAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,CAAO,SAAA,CAAUA,OAAM,CAAA;AAC9C,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,MAAA,MAAM,SAAS,MAAA,CAAO,KAAA,CAAM,OACzB,GAAA,CAAI,CAAC,MAAM,CAAA,IAAA,EAAO,CAAA,CAAE,KAAK,IAAA,CAAK,GAAG,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,OAAO,CAAA,CAAE,CAAA,CAClD,KAAK,IAAI,CAAA;AACZ,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA;AAAA,EAA8B,MAAM,CAAA,CAAE,CAAA;AAAA,IACxD;AACA,IAAAA,UAAS,MAAA,CAAO,IAAA;AAAA,EAClB;AAGA,EAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,IAAA,MAAM,YAAA,GAAe,YAAYA,OAAM,CAAA;AACvC,IAAA,OAAA,CAAQ,MAAA,CAAO,kBAAkB,WAAW,CAAA;AAAA,EAAO,KAAK,SAAA,CAAU,YAAA,EAAc,IAAA,EAAM,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,EAC5F;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAAA,OAAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA,EAAW;AAAA,GACb;AACF;AAEA,SAAS,UAAA,CACP,cACA,WAAA,EACM;AACN,EAAA,IAAI,OAAA;AAEJ,EAAA,IAAI,OAAO,YAAA,KAAiB,QAAA,IAAY,YAAA,CAAa,IAAA,EAAM;AACzD,IAAA,OAAA,GAAU,YAAA,CAAa,IAAA;AAAA,EACzB,CAAA,MAAO;AACL,IAAA,OAAA,GAAU,WAAA,KAAgB,YAAA,GAAe,MAAA,GAAS,CAAA,KAAA,EAAQ,WAAW,CAAA,CAAA;AAAA,EACvE;AAEA,EAAOC,iBAAA,CAAA,MAAA,CAAO,EAAE,IAAA,EAAM,OAAA,EAAS,CAAA;AACjC;AAEA,SAAS,iBAAiB,SAAA,EAA2B;AACnD,EAAA,MAAM,aAAA,GAAgB;AAAA,IACpBC,SAAA,CAAK,SAAA,EAAW,KAAA,EAAO,QAAQ,CAAA;AAAA,IAC/BA,SAAA,CAAK,SAAA,EAAW,MAAA,EAAQ,QAAQ,CAAA;AAAA,IAChCA,SAAA,CAAK,WAAW,QAAQ,CAAA;AAAA,IACxB;AAAA,GACF;AAEA,EAAA,KAAA,MAAWC,UAAQ,aAAA,EAAe;AAChC,IAAA,IAAIC,aAAA,CAAWF,SAAA,CAAKC,MAAA,EAAM,UAAU,CAAC,CAAA,IAAKC,aAAA,CAAWF,SAAA,CAAKC,MAAA,EAAM,WAAW,CAAC,CAAA,EAAG;AAC7E,MAAA,OAAOA,MAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,MAAM,IAAI,KAAA;AAAA,IACR,CAAA;AAAA,EAAyC,aAAA,CAAc,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,IAAA,EAAO,CAAC,CAAA,CAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,GAC1F;AACF;AAEA,SAAS,YAAA,CAAa,KAAa,QAAA,EAA2C;AAC5E,EAAA,MAAM,QAAA,GAAWD,SAAA,CAAK,GAAA,EAAK,QAAQ,CAAA;AAEnC,EAAA,IAAI,CAACE,aAAA,CAAW,QAAQ,CAAA,EAAG;AACzB,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,OAAA,GAAUC,eAAA,CAAa,QAAA,EAAU,MAAM,CAAA;AAC7C,EAAA,OAAaC,eAAA,CAAA,IAAA,CAAK,OAAO,CAAA,IAAiC,EAAC;AAC7D;AAEA,SAAS,gBAAgB,GAAA,EAAwC;AAC/D,EAAA,IAAI,CAACF,aAAA,CAAW,GAAG,CAAA,EAAG;AACpB,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,QAAQG,cAAA,CAAY,GAAG,CAAA,CAC1B,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,CAAS,MAAM,KAAK,CAAA,CAAE,QAAA,CAAS,OAAO,CAAC,EACvD,IAAA,EAAK;AAER,EAAA,OAAO,MAAM,GAAA,CAAI,CAAC,SAAS,YAAA,CAAa,GAAA,EAAK,IAAI,CAAC,CAAA;AACpD","file":"index.js","sourcesContent":["type DeepObject = Record<string, unknown>;\n\nexport function deepMerge(base: DeepObject, override: DeepObject): DeepObject {\n const merged = { ...base };\n\n for (const key in override) {\n const overrideValue = override[key];\n const baseValue = base[key];\n\n if (isPlainObject(overrideValue) && isPlainObject(baseValue)) {\n merged[key] = deepMerge(baseValue as DeepObject, overrideValue as DeepObject);\n } else {\n merged[key] = overrideValue;\n }\n }\n\n return merged;\n}\n\nfunction isPlainObject(value: unknown): value is DeepObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","const ENV_PLACEHOLDER_REGEX = /\\${(.*?)}/g;\n\nexport function replacePlaceholders(obj: unknown): unknown {\n if (typeof obj === 'string') {\n return replaceStringPlaceholders(obj);\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => replacePlaceholders(item));\n }\n\n if (isPlainObject(obj)) {\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n result[key] = replacePlaceholders(obj[key]);\n }\n return result;\n }\n\n return obj;\n}\n\nfunction replaceStringPlaceholders(str: string): string {\n return str.replace(ENV_PLACEHOLDER_REGEX, (match, key) => {\n const [envKey, ...rest] = key.split(':');\n const defaultValue = rest.length > 0 ? rest.join(':') : undefined;\n const envValue = process.env[envKey];\n\n let value: string;\n if (envValue !== undefined) {\n value = envValue;\n } else if (defaultValue !== undefined) {\n value = defaultValue;\n } else {\n throw new Error(`Environment variable \"${envKey}\" is not defined and no default value provided`);\n }\n\n if (value.includes('${')) {\n return replacePlaceholders(value) as string;\n }\n\n return value;\n });\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","const SECRET_PATTERNS = ['token', 'password', 'secret', 'key', 'apikey', 'api_key', 'credential'];\n\nconst URL_WITH_CREDENTIALS_REGEX = /^([a-z]+:\\/\\/)([^:]+):([^@]+)@(.+)$/i;\n\nexport function maskSecrets(obj: unknown): unknown {\n if (typeof obj === 'string') {\n return maskUrlCredentials(obj);\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => maskSecrets(item));\n }\n\n if (isPlainObject(obj)) {\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n const value = obj[key];\n if (isSecretKey(key)) {\n result[key] = maskValue(value);\n } else {\n result[key] = maskSecrets(value);\n }\n }\n return result;\n }\n\n return obj;\n}\n\nfunction isSecretKey(key: string): boolean {\n const lowerKey = key.toLowerCase();\n return SECRET_PATTERNS.some((pattern) => lowerKey.includes(pattern));\n}\n\nfunction maskValue(value: unknown): string {\n if (typeof value !== 'string') {\n return '***';\n }\n if (value.length <= 4) {\n return '***';\n }\n return value.slice(0, 2) + '***' + value.slice(-2);\n}\n\nfunction maskUrlCredentials(url: string): string {\n const match = url.match(URL_WITH_CREDENTIALS_REGEX);\n if (match) {\n const [, protocol, user, , host] = match;\n return `${protocol}${user}:***@${host}`;\n }\n return url;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","import { readFileSync, existsSync, readdirSync } from 'fs';\nimport * as yaml from 'js-yaml';\nimport * as dotenv from 'dotenv';\nimport { join } from 'path';\nimport type { ConfigLoaderOptions, ConfigLoaderResult } from './types.js';\nimport { deepMerge, replacePlaceholders, maskSecrets } from './utils/index.js';\n\nconst DEFAULT_OPTIONS = {\n configDir: process.cwd(),\n baseFileName: 'base',\n environment: process.env.NODE_ENV || 'local',\n extension: 'yml' as const,\n overrideDir: '/etc/app/config',\n};\n\nexport function loadConfig<T>(options: ConfigLoaderOptions<T> = {}): ConfigLoaderResult<T> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const { configDir, baseFileName, environment, extension } = opts;\n\n // Load .env if requested\n if (options.dotenv) {\n loadDotenv(options.dotenv, environment);\n }\n\n const resolvedConfigDir = resolveConfigDir(configDir);\n\n const baseConfig = loadYamlFile(resolvedConfigDir, `${baseFileName}.${extension}`);\n const envConfig = loadYamlFile(resolvedConfigDir, `${environment}.${extension}`);\n\n let mergedConfig = deepMerge(baseConfig, envConfig);\n\n // Load override files from directory\n const overrideDir = options.overrideDir !== false ? (options.overrideDir ?? DEFAULT_OPTIONS.overrideDir) : null;\n if (overrideDir) {\n const overrideConfigs = loadOverrideDir(overrideDir);\n for (const override of overrideConfigs) {\n mergedConfig = deepMerge(mergedConfig, override);\n }\n }\n\n let config = replacePlaceholders(mergedConfig) as T;\n\n // Post-process\n if (options.postProcess) {\n config = options.postProcess(config);\n }\n\n // Validate with Zod schema\n if (options.schema) {\n const result = options.schema.safeParse(config);\n if (!result.success) {\n const errors = result.error.issues\n .map((e) => ` - ${e.path.join('.')}: ${e.message}`)\n .join('\\n');\n throw new Error(`Config validation failed:\\n${errors}`);\n }\n config = result.data;\n }\n\n // Log config with masked secrets\n if (options.logger) {\n const maskedConfig = maskSecrets(config);\n options.logger(`Config loaded (${environment}):\\n${JSON.stringify(maskedConfig, null, 2)}`);\n }\n\n return {\n config,\n environment,\n configDir: resolvedConfigDir,\n };\n}\n\nfunction loadDotenv(\n dotenvOption: boolean | { path?: string },\n environment: string,\n): void {\n let envPath: string;\n\n if (typeof dotenvOption === 'object' && dotenvOption.path) {\n envPath = dotenvOption.path;\n } else {\n envPath = environment === 'production' ? '.env' : `.env.${environment}`;\n }\n\n dotenv.config({ path: envPath });\n}\n\nfunction resolveConfigDir(configDir: string): string {\n const possiblePaths = [\n join(configDir, 'src', 'config'),\n join(configDir, 'dist', 'config'),\n join(configDir, 'config'),\n configDir,\n ];\n\n for (const path of possiblePaths) {\n if (existsSync(join(path, 'base.yml')) || existsSync(join(path, 'base.yaml'))) {\n return path;\n }\n }\n\n throw new Error(\n `Config files not found. Searched in:\\n${possiblePaths.map((p) => ` - ${p}`).join('\\n')}`,\n );\n}\n\nfunction loadYamlFile(dir: string, filename: string): Record<string, unknown> {\n const filePath = join(dir, filename);\n\n if (!existsSync(filePath)) {\n return {};\n }\n\n const content = readFileSync(filePath, 'utf8');\n return (yaml.load(content) as Record<string, unknown>) || {};\n}\n\nfunction loadOverrideDir(dir: string): Record<string, unknown>[] {\n if (!existsSync(dir)) {\n return [];\n }\n\n const files = readdirSync(dir)\n .filter((f) => f.endsWith('.yml') || f.endsWith('.yaml'))\n .sort();\n\n return files.map((file) => loadYamlFile(dir, file));\n}\n"]}
|
|
@@ -1,30 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var dotenv = require('dotenv');
|
|
6
|
-
var path = require('path');
|
|
7
|
-
|
|
8
|
-
function _interopNamespace(e) {
|
|
9
|
-
if (e && e.__esModule) return e;
|
|
10
|
-
var n = Object.create(null);
|
|
11
|
-
if (e) {
|
|
12
|
-
Object.keys(e).forEach(function (k) {
|
|
13
|
-
if (k !== 'default') {
|
|
14
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
-
enumerable: true,
|
|
17
|
-
get: function () { return e[k]; }
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
n.default = e;
|
|
23
|
-
return Object.freeze(n);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
var yaml__namespace = /*#__PURE__*/_interopNamespace(yaml);
|
|
27
|
-
var dotenv__namespace = /*#__PURE__*/_interopNamespace(dotenv);
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from 'fs';
|
|
2
|
+
import * as yaml from 'js-yaml';
|
|
3
|
+
import * as dotenv from 'dotenv';
|
|
4
|
+
import { join } from 'path';
|
|
28
5
|
|
|
29
6
|
// src/loader.ts
|
|
30
7
|
|
|
@@ -192,18 +169,18 @@ function loadDotenv(dotenvOption, environment) {
|
|
|
192
169
|
} else {
|
|
193
170
|
envPath = environment === "production" ? ".env" : `.env.${environment}`;
|
|
194
171
|
}
|
|
195
|
-
|
|
172
|
+
dotenv.config({ path: envPath });
|
|
196
173
|
}
|
|
197
174
|
function resolveConfigDir(configDir) {
|
|
198
175
|
const possiblePaths = [
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
176
|
+
join(configDir, "src", "config"),
|
|
177
|
+
join(configDir, "dist", "config"),
|
|
178
|
+
join(configDir, "config"),
|
|
202
179
|
configDir
|
|
203
180
|
];
|
|
204
|
-
for (const path
|
|
205
|
-
if (
|
|
206
|
-
return path
|
|
181
|
+
for (const path of possiblePaths) {
|
|
182
|
+
if (existsSync(join(path, "base.yml")) || existsSync(join(path, "base.yaml"))) {
|
|
183
|
+
return path;
|
|
207
184
|
}
|
|
208
185
|
}
|
|
209
186
|
throw new Error(
|
|
@@ -212,24 +189,21 @@ ${possiblePaths.map((p) => ` - ${p}`).join("\n")}`
|
|
|
212
189
|
);
|
|
213
190
|
}
|
|
214
191
|
function loadYamlFile(dir, filename) {
|
|
215
|
-
const filePath =
|
|
216
|
-
if (!
|
|
192
|
+
const filePath = join(dir, filename);
|
|
193
|
+
if (!existsSync(filePath)) {
|
|
217
194
|
return {};
|
|
218
195
|
}
|
|
219
|
-
const content =
|
|
220
|
-
return
|
|
196
|
+
const content = readFileSync(filePath, "utf8");
|
|
197
|
+
return yaml.load(content) || {};
|
|
221
198
|
}
|
|
222
199
|
function loadOverrideDir(dir) {
|
|
223
|
-
if (!
|
|
200
|
+
if (!existsSync(dir)) {
|
|
224
201
|
return [];
|
|
225
202
|
}
|
|
226
|
-
const files =
|
|
203
|
+
const files = readdirSync(dir).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml")).sort();
|
|
227
204
|
return files.map((file) => loadYamlFile(dir, file));
|
|
228
205
|
}
|
|
229
206
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
exports.replacePlaceholders = replacePlaceholders;
|
|
234
|
-
//# sourceMappingURL=index.cjs.map
|
|
235
|
-
//# sourceMappingURL=index.cjs.map
|
|
207
|
+
export { deepMerge, loadConfig, maskSecrets, replacePlaceholders };
|
|
208
|
+
//# sourceMappingURL=index.mjs.map
|
|
209
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/deep-merge.ts","../src/utils/env-replacer.ts","../src/utils/mask-secrets.ts","../src/loader.ts"],"names":["isPlainObject","config"],"mappings":"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","file":"index.mjs","sourcesContent":["type DeepObject = Record<string, unknown>;\n\nexport function deepMerge(base: DeepObject, override: DeepObject): DeepObject {\n const merged = { ...base };\n\n for (const key in override) {\n const overrideValue = override[key];\n const baseValue = base[key];\n\n if (isPlainObject(overrideValue) && isPlainObject(baseValue)) {\n merged[key] = deepMerge(baseValue as DeepObject, overrideValue as DeepObject);\n } else {\n merged[key] = overrideValue;\n }\n }\n\n return merged;\n}\n\nfunction isPlainObject(value: unknown): value is DeepObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","const ENV_PLACEHOLDER_REGEX = /\\${(.*?)}/g;\n\nexport function replacePlaceholders(obj: unknown): unknown {\n if (typeof obj === 'string') {\n return replaceStringPlaceholders(obj);\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => replacePlaceholders(item));\n }\n\n if (isPlainObject(obj)) {\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n result[key] = replacePlaceholders(obj[key]);\n }\n return result;\n }\n\n return obj;\n}\n\nfunction replaceStringPlaceholders(str: string): string {\n return str.replace(ENV_PLACEHOLDER_REGEX, (match, key) => {\n const [envKey, ...rest] = key.split(':');\n const defaultValue = rest.length > 0 ? rest.join(':') : undefined;\n const envValue = process.env[envKey];\n\n let value: string;\n if (envValue !== undefined) {\n value = envValue;\n } else if (defaultValue !== undefined) {\n value = defaultValue;\n } else {\n throw new Error(`Environment variable \"${envKey}\" is not defined and no default value provided`);\n }\n\n if (value.includes('${')) {\n return replacePlaceholders(value) as string;\n }\n\n return value;\n });\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","const SECRET_PATTERNS = ['token', 'password', 'secret', 'key', 'apikey', 'api_key', 'credential'];\n\nconst URL_WITH_CREDENTIALS_REGEX = /^([a-z]+:\\/\\/)([^:]+):([^@]+)@(.+)$/i;\n\nexport function maskSecrets(obj: unknown): unknown {\n if (typeof obj === 'string') {\n return maskUrlCredentials(obj);\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => maskSecrets(item));\n }\n\n if (isPlainObject(obj)) {\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n const value = obj[key];\n if (isSecretKey(key)) {\n result[key] = maskValue(value);\n } else {\n result[key] = maskSecrets(value);\n }\n }\n return result;\n }\n\n return obj;\n}\n\nfunction isSecretKey(key: string): boolean {\n const lowerKey = key.toLowerCase();\n return SECRET_PATTERNS.some((pattern) => lowerKey.includes(pattern));\n}\n\nfunction maskValue(value: unknown): string {\n if (typeof value !== 'string') {\n return '***';\n }\n if (value.length <= 4) {\n return '***';\n }\n return value.slice(0, 2) + '***' + value.slice(-2);\n}\n\nfunction maskUrlCredentials(url: string): string {\n const match = url.match(URL_WITH_CREDENTIALS_REGEX);\n if (match) {\n const [, protocol, user, , host] = match;\n return `${protocol}${user}:***@${host}`;\n }\n return url;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","import { readFileSync, existsSync, readdirSync } from 'fs';\nimport * as yaml from 'js-yaml';\nimport * as dotenv from 'dotenv';\nimport { join } from 'path';\nimport type { ConfigLoaderOptions, ConfigLoaderResult } from './types.js';\nimport { deepMerge, replacePlaceholders, maskSecrets } from './utils/index.js';\n\nconst DEFAULT_OPTIONS = {\n configDir: process.cwd(),\n baseFileName: 'base',\n environment: process.env.NODE_ENV || 'local',\n extension: 'yml' as const,\n overrideDir: '/etc/app/config',\n};\n\nexport function loadConfig<T>(options: ConfigLoaderOptions<T> = {}): ConfigLoaderResult<T> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const { configDir, baseFileName, environment, extension } = opts;\n\n // Load .env if requested\n if (options.dotenv) {\n loadDotenv(options.dotenv, environment);\n }\n\n const resolvedConfigDir = resolveConfigDir(configDir);\n\n const baseConfig = loadYamlFile(resolvedConfigDir, `${baseFileName}.${extension}`);\n const envConfig = loadYamlFile(resolvedConfigDir, `${environment}.${extension}`);\n\n let mergedConfig = deepMerge(baseConfig, envConfig);\n\n // Load override files from directory\n const overrideDir = options.overrideDir !== false ? (options.overrideDir ?? DEFAULT_OPTIONS.overrideDir) : null;\n if (overrideDir) {\n const overrideConfigs = loadOverrideDir(overrideDir);\n for (const override of overrideConfigs) {\n mergedConfig = deepMerge(mergedConfig, override);\n }\n }\n\n let config = replacePlaceholders(mergedConfig) as T;\n\n // Post-process\n if (options.postProcess) {\n config = options.postProcess(config);\n }\n\n // Validate with Zod schema\n if (options.schema) {\n const result = options.schema.safeParse(config);\n if (!result.success) {\n const errors = result.error.issues\n .map((e) => ` - ${e.path.join('.')}: ${e.message}`)\n .join('\\n');\n throw new Error(`Config validation failed:\\n${errors}`);\n }\n config = result.data;\n }\n\n // Log config with masked secrets\n if (options.logger) {\n const maskedConfig = maskSecrets(config);\n options.logger(`Config loaded (${environment}):\\n${JSON.stringify(maskedConfig, null, 2)}`);\n }\n\n return {\n config,\n environment,\n configDir: resolvedConfigDir,\n };\n}\n\nfunction loadDotenv(\n dotenvOption: boolean | { path?: string },\n environment: string,\n): void {\n let envPath: string;\n\n if (typeof dotenvOption === 'object' && dotenvOption.path) {\n envPath = dotenvOption.path;\n } else {\n envPath = environment === 'production' ? '.env' : `.env.${environment}`;\n }\n\n dotenv.config({ path: envPath });\n}\n\nfunction resolveConfigDir(configDir: string): string {\n const possiblePaths = [\n join(configDir, 'src', 'config'),\n join(configDir, 'dist', 'config'),\n join(configDir, 'config'),\n configDir,\n ];\n\n for (const path of possiblePaths) {\n if (existsSync(join(path, 'base.yml')) || existsSync(join(path, 'base.yaml'))) {\n return path;\n }\n }\n\n throw new Error(\n `Config files not found. Searched in:\\n${possiblePaths.map((p) => ` - ${p}`).join('\\n')}`,\n );\n}\n\nfunction loadYamlFile(dir: string, filename: string): Record<string, unknown> {\n const filePath = join(dir, filename);\n\n if (!existsSync(filePath)) {\n return {};\n }\n\n const content = readFileSync(filePath, 'utf8');\n return (yaml.load(content) as Record<string, unknown>) || {};\n}\n\nfunction loadOverrideDir(dir: string): Record<string, unknown>[] {\n if (!existsSync(dir)) {\n return [];\n }\n\n const files = readdirSync(dir)\n .filter((f) => f.endsWith('.yml') || f.endsWith('.yaml'))\n .sort();\n\n return files.map((file) => loadYamlFile(dir, file));\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rawnodes/config-loader",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Flexible YAML config loader with environment overrides, Zod validation, and Docker-friendly features",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"module": "./dist/index.js",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
8
7
|
"types": "./dist/index.d.ts",
|
|
9
8
|
"exports": {
|
|
10
9
|
".": {
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"default": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
14
18
|
}
|
|
15
19
|
},
|
|
16
20
|
"files": [
|
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/deep-merge.ts","../src/utils/env-replacer.ts","../src/utils/mask-secrets.ts","../src/loader.ts"],"names":["isPlainObject","config","dotenv","join","path","existsSync","readFileSync","yaml","readdirSync"],"mappings":"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","file":"index.cjs","sourcesContent":["type DeepObject = Record<string, unknown>;\n\nexport function deepMerge(base: DeepObject, override: DeepObject): DeepObject {\n const merged = { ...base };\n\n for (const key in override) {\n const overrideValue = override[key];\n const baseValue = base[key];\n\n if (isPlainObject(overrideValue) && isPlainObject(baseValue)) {\n merged[key] = deepMerge(baseValue as DeepObject, overrideValue as DeepObject);\n } else {\n merged[key] = overrideValue;\n }\n }\n\n return merged;\n}\n\nfunction isPlainObject(value: unknown): value is DeepObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","const ENV_PLACEHOLDER_REGEX = /\\${(.*?)}/g;\n\nexport function replacePlaceholders(obj: unknown): unknown {\n if (typeof obj === 'string') {\n return replaceStringPlaceholders(obj);\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => replacePlaceholders(item));\n }\n\n if (isPlainObject(obj)) {\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n result[key] = replacePlaceholders(obj[key]);\n }\n return result;\n }\n\n return obj;\n}\n\nfunction replaceStringPlaceholders(str: string): string {\n return str.replace(ENV_PLACEHOLDER_REGEX, (match, key) => {\n const [envKey, ...rest] = key.split(':');\n const defaultValue = rest.length > 0 ? rest.join(':') : undefined;\n const envValue = process.env[envKey];\n\n let value: string;\n if (envValue !== undefined) {\n value = envValue;\n } else if (defaultValue !== undefined) {\n value = defaultValue;\n } else {\n throw new Error(`Environment variable \"${envKey}\" is not defined and no default value provided`);\n }\n\n if (value.includes('${')) {\n return replacePlaceholders(value) as string;\n }\n\n return value;\n });\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","const SECRET_PATTERNS = ['token', 'password', 'secret', 'key', 'apikey', 'api_key', 'credential'];\n\nconst URL_WITH_CREDENTIALS_REGEX = /^([a-z]+:\\/\\/)([^:]+):([^@]+)@(.+)$/i;\n\nexport function maskSecrets(obj: unknown): unknown {\n if (typeof obj === 'string') {\n return maskUrlCredentials(obj);\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => maskSecrets(item));\n }\n\n if (isPlainObject(obj)) {\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n const value = obj[key];\n if (isSecretKey(key)) {\n result[key] = maskValue(value);\n } else {\n result[key] = maskSecrets(value);\n }\n }\n return result;\n }\n\n return obj;\n}\n\nfunction isSecretKey(key: string): boolean {\n const lowerKey = key.toLowerCase();\n return SECRET_PATTERNS.some((pattern) => lowerKey.includes(pattern));\n}\n\nfunction maskValue(value: unknown): string {\n if (typeof value !== 'string') {\n return '***';\n }\n if (value.length <= 4) {\n return '***';\n }\n return value.slice(0, 2) + '***' + value.slice(-2);\n}\n\nfunction maskUrlCredentials(url: string): string {\n const match = url.match(URL_WITH_CREDENTIALS_REGEX);\n if (match) {\n const [, protocol, user, , host] = match;\n return `${protocol}${user}:***@${host}`;\n }\n return url;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","import { readFileSync, existsSync, readdirSync } from 'fs';\nimport * as yaml from 'js-yaml';\nimport * as dotenv from 'dotenv';\nimport { join } from 'path';\nimport type { ConfigLoaderOptions, ConfigLoaderResult } from './types.js';\nimport { deepMerge, replacePlaceholders, maskSecrets } from './utils/index.js';\n\nconst DEFAULT_OPTIONS = {\n configDir: process.cwd(),\n baseFileName: 'base',\n environment: process.env.NODE_ENV || 'local',\n extension: 'yml' as const,\n overrideDir: '/etc/app/config',\n};\n\nexport function loadConfig<T>(options: ConfigLoaderOptions<T> = {}): ConfigLoaderResult<T> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const { configDir, baseFileName, environment, extension } = opts;\n\n // Load .env if requested\n if (options.dotenv) {\n loadDotenv(options.dotenv, environment);\n }\n\n const resolvedConfigDir = resolveConfigDir(configDir);\n\n const baseConfig = loadYamlFile(resolvedConfigDir, `${baseFileName}.${extension}`);\n const envConfig = loadYamlFile(resolvedConfigDir, `${environment}.${extension}`);\n\n let mergedConfig = deepMerge(baseConfig, envConfig);\n\n // Load override files from directory\n const overrideDir = options.overrideDir !== false ? (options.overrideDir ?? DEFAULT_OPTIONS.overrideDir) : null;\n if (overrideDir) {\n const overrideConfigs = loadOverrideDir(overrideDir);\n for (const override of overrideConfigs) {\n mergedConfig = deepMerge(mergedConfig, override);\n }\n }\n\n let config = replacePlaceholders(mergedConfig) as T;\n\n // Post-process\n if (options.postProcess) {\n config = options.postProcess(config);\n }\n\n // Validate with Zod schema\n if (options.schema) {\n const result = options.schema.safeParse(config);\n if (!result.success) {\n const errors = result.error.issues\n .map((e) => ` - ${e.path.join('.')}: ${e.message}`)\n .join('\\n');\n throw new Error(`Config validation failed:\\n${errors}`);\n }\n config = result.data;\n }\n\n // Log config with masked secrets\n if (options.logger) {\n const maskedConfig = maskSecrets(config);\n options.logger(`Config loaded (${environment}):\\n${JSON.stringify(maskedConfig, null, 2)}`);\n }\n\n return {\n config,\n environment,\n configDir: resolvedConfigDir,\n };\n}\n\nfunction loadDotenv(\n dotenvOption: boolean | { path?: string },\n environment: string,\n): void {\n let envPath: string;\n\n if (typeof dotenvOption === 'object' && dotenvOption.path) {\n envPath = dotenvOption.path;\n } else {\n envPath = environment === 'production' ? '.env' : `.env.${environment}`;\n }\n\n dotenv.config({ path: envPath });\n}\n\nfunction resolveConfigDir(configDir: string): string {\n const possiblePaths = [\n join(configDir, 'src', 'config'),\n join(configDir, 'dist', 'config'),\n join(configDir, 'config'),\n configDir,\n ];\n\n for (const path of possiblePaths) {\n if (existsSync(join(path, 'base.yml')) || existsSync(join(path, 'base.yaml'))) {\n return path;\n }\n }\n\n throw new Error(\n `Config files not found. Searched in:\\n${possiblePaths.map((p) => ` - ${p}`).join('\\n')}`,\n );\n}\n\nfunction loadYamlFile(dir: string, filename: string): Record<string, unknown> {\n const filePath = join(dir, filename);\n\n if (!existsSync(filePath)) {\n return {};\n }\n\n const content = readFileSync(filePath, 'utf8');\n return (yaml.load(content) as Record<string, unknown>) || {};\n}\n\nfunction loadOverrideDir(dir: string): Record<string, unknown>[] {\n if (!existsSync(dir)) {\n return [];\n }\n\n const files = readdirSync(dir)\n .filter((f) => f.endsWith('.yml') || f.endsWith('.yaml'))\n .sort();\n\n return files.map((file) => loadYamlFile(dir, file));\n}\n"]}
|
|
File without changes
|