New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@avanio/variable-util-node

Package Overview
Dependencies
Maintainers
3
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@avanio/variable-util-node - npm Package Compare versions

Comparing version
1.3.1
to
1.3.2
+7
-10
dist/index.cjs

@@ -76,3 +76,2 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });

options.logger?.debug(this.buildErrorStr(`loading file ${options.fileName}`));
if (!(0, fs.existsSync)(options.fileName)) return (0, _luolapeikko_result_option.Err)(new _avanio_variable_util.VariableError(this.buildErrorStr(`file ${options.fileName} not found`)));
let buffer;

@@ -82,3 +81,3 @@ try {

} catch (cause) {
return (0, _luolapeikko_result_option.Err)(new _avanio_variable_util.VariableError(_luolapeikko_ts_common.ErrorCore.from(cause).message, { cause }));
return (0, _luolapeikko_result_option.Err)(new _avanio_variable_util.VariableError(this.buildErrorStr(_luolapeikko_ts_common.ErrorCore.from(cause).message), { cause }));
}

@@ -96,10 +95,8 @@ try {

const { logger, isSilent } = await this.getOptions();
const res = await this.handleData();
if (res.isErr) {
if (!isSilent) res.unwrap();
else logger?.debug(res.err());
return false;
}
(0, _avanio_variable_util.applyStringMap)(res.ok(), this.data);
return true;
const res = (await this.handleData()).inspectErr((err) => isSilent && logger?.debug(err)).andThen((data) => {
(0, _avanio_variable_util.applyStringMap)(data, this.data);
return (0, _luolapeikko_result_option.Ok)();
});
if (res.isErr && !isSilent) res.unwrap();
return res.isOk;
}

@@ -106,0 +103,0 @@ handleFileWatch(options) {

@@ -1,1 +0,1 @@

{"version":3,"file":"index.cjs","names":["MapConfigLoader","VariableError","ErrorCore","ConfigLoader","VariableLookupError","UndefCore"],"sources":["../src/AbstractFileRecordLoader.ts","../src/DockerSecretsConfigLoader.ts","../src/DotEnvLoader.ts","../src/FileConfigLoader.ts"],"sourcesContent":["import type {ILoggerLike} from '@avanio/logger-like';\nimport {\n\tapplyStringMap,\n\ttype IConfigLoaderProps,\n\ttype LoaderValue,\n\tMapConfigLoader,\n\ttype OverrideKeyMap,\n\ttype ValidateCallback,\n\tVariableError,\n} from '@avanio/variable-util';\nimport {Err, type IResult, Ok} from '@luolapeikko/result-option';\nimport {ErrorCore, type Loadable} from '@luolapeikko/ts-common';\nimport {existsSync, type FSWatcher, watch} from 'fs';\nimport {readFile} from 'fs/promises';\n\n/**\n * Options for the AbstractFileRecordLoader.\n * @template FileType Type of the file\n * @since v1.0.0\n */\nexport interface AbstractFileRecordLoaderOptions<FileType extends string> extends IConfigLoaderProps {\n\tfileType: FileType;\n\t/** file name to load */\n\tfileName: string;\n\t/** set to false if need errors */\n\tisSilent: boolean;\n\t/** optional logger */\n\tlogger: ILoggerLike | undefined;\n\t/** set to true to watch file for changes */\n\twatch: boolean;\n\t/** set to true to disable loader */\n\tdisabled: boolean;\n\t/**\n\t * optional validator for data (Record<string, string | undefined>)\n\t * @example\n\t * // using zod\n\t * const stringRecordSchema = z.record(z.string().min(1), z.string());\n\t * const validate: ValidateCallback<Record<string, string>> = async (data) => {\n\t * const result = await stringRecordSchema.safeParseAsync(data);\n\t * if (!result.success) {\n\t * return {success: false, message: result.error.message};\n\t * }\n\t * return {success: true};\n\t * };\n\t */\n\tvalidate: ValidateCallback<Record<string, string | undefined>, Record<string, string | undefined>> | undefined;\n}\n\n/**\n * Abstract class for loading records from a file.\n * @template Options Options for the loader\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport abstract class AbstractFileRecordLoader<\n\tOptions extends AbstractFileRecordLoaderOptions<string> = AbstractFileRecordLoaderOptions<string>,\n\tOverrideMap extends OverrideKeyMap = OverrideKeyMap,\n> extends MapConfigLoader<Options, OverrideMap> {\n\tpublic abstract readonly loaderType: Lowercase<string>;\n\tprotected abstract defaultOptions: Options;\n\tprivate watcher: FSWatcher | undefined;\n\tprivate timeout: ReturnType<typeof setTimeout> | undefined;\n\n\tpublic constructor(options: Loadable<Partial<Options>>, overrideKeys?: Partial<OverrideMap>) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.handleFileChange = this.handleFileChange.bind(this);\n\t}\n\n\t/**\n\t * If the loader is watching the file, it will stop watching.\n\t */\n\tpublic async close(): Promise<void> {\n\t\tif (this.watcher) {\n\t\t\tconst {logger, fileName} = await this.getOptions();\n\t\t\tlogger?.debug(this.buildErrorStr(`closing file watcher for ${fileName}`));\n\t\t\tthis.watcher.close();\n\t\t}\n\t}\n\n\tprotected async handleLoaderValue(lookupKey: string): Promise<LoaderValue> {\n\t\tconst {fileName} = await this.getOptions();\n\t\tif (!this._isLoaded) {\n\t\t\tawait this.loadData();\n\t\t\tthis._isLoaded = true; // only load data once to prevent spamming\n\t\t}\n\t\tconst value = this.data.get(lookupKey);\n\t\treturn {path: fileName, value};\n\t}\n\n\tprotected async handleData(): Promise<IResult<Record<string, string | undefined>, VariableError>> {\n\t\tconst options = await this.getOptions();\n\t\toptions.logger?.debug(this.buildErrorStr(`loading file ${options.fileName}`));\n\t\tif (!existsSync(options.fileName)) {\n\t\t\treturn Err(new VariableError(this.buildErrorStr(`file ${options.fileName} not found`)));\n\t\t}\n\t\tlet buffer: Buffer;\n\t\ttry {\n\t\t\tbuffer = await readFile(options.fileName);\n\t\t} catch (cause) {\n\t\t\treturn Err(new VariableError(ErrorCore.from(cause).message, {cause}));\n\t\t}\n\t\ttry {\n\t\t\tlet data = await this.handleParse(buffer, options);\n\t\t\tif (options.validate) {\n\t\t\t\tdata = await options.validate(data);\n\t\t\t}\n\t\t\tthis.handleFileWatch(options); // add watch after successful load\n\t\t\treturn Ok(data);\n\t\t} catch (cause) {\n\t\t\treturn Err(new VariableError(this.buildErrorStr(`file ${options.fileName} is not a valid ${options.fileType}`), {cause}));\n\t\t}\n\t}\n\n\tprotected async handleLoadData(): Promise<boolean> {\n\t\tconst {logger, isSilent} = await this.getOptions();\n\t\tconst res = await this.handleData();\n\t\tif (res.isErr) {\n\t\t\tif (!isSilent) {\n\t\t\t\tres.unwrap();\n\t\t\t} else {\n\t\t\t\tlogger?.debug(res.err());\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\tapplyStringMap(res.ok(), this.data);\n\t\treturn true;\n\t}\n\n\tprivate handleFileWatch(options: Options): void {\n\t\tif (options.watch && !this.watcher) {\n\t\t\toptions.logger?.debug(this.buildErrorStr(`opening file watcher for ${options.fileName}`));\n\t\t\tthis.watcher = watch(options.fileName, () => {\n\t\t\t\tif (this.timeout) {\n\t\t\t\t\tclearTimeout(this.timeout);\n\t\t\t\t}\n\t\t\t\t// delay to prevent multiple reloads\n\t\t\t\tthis.timeout = setTimeout(() => {\n\t\t\t\t\tvoid this.handleFileChange(options);\n\t\t\t\t}, 200);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async handleFileChange(options: Options): Promise<void> {\n\t\ttry {\n\t\t\toptions.logger?.debug(this.buildErrorStr(`file ${options.fileName} changed`));\n\t\t\tawait this.reload();\n\t\t} catch (err) {\n\t\t\toptions.logger?.error(this.buildErrorStr(`error reloading file ${options.fileName}: ${ErrorCore.from(err).message}`));\n\t\t}\n\t}\n\n\t/**\n\t * Handle the parsing of the file.\n\t */\n\tprotected abstract handleParse(rawData: Buffer, options: Options): Record<string, string | undefined> | Promise<Record<string, string | undefined>>;\n}\n","import type {ILoggerLike} from '@avanio/logger-like';\nimport {ConfigLoader, type LoaderValue, type OverrideKeyMap, VariableLookupError} from '@avanio/variable-util';\nimport type {Loadable} from '@luolapeikko/ts-common';\nimport {existsSync} from 'fs';\nimport {readFile} from 'fs/promises';\nimport * as path from 'path';\n\n/**\n * DockerSecretsConfigLoaderOptions is the interface for DockerSecretsConfigLoader options\n * @category Loaders\n * @since v1.0.0\n * @template OverrideMap - the type of the override key map\n */\nexport interface DockerSecretsConfigLoaderOptions {\n\t/** force file name to lower case */\n\tfileLowerCase: boolean;\n\t/** path to docker secrets, default is '/run/secrets' */\n\tpath: string;\n\t/** set to false if need errors */\n\tisSilent: boolean;\n\t/** optional logger */\n\tlogger: ILoggerLike | undefined;\n\t/** set to true to disable loader, default is false */\n\tdisabled: boolean;\n}\n\n/**\n * Loader for docker secrets, reads secrets from the `/run/secrets` directory.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class DockerSecretsConfigLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends ConfigLoader<\n\tDockerSecretsConfigLoaderOptions,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\tprivate valuePromises = new Map<string, Promise<string | undefined>>();\n\tprotected defaultOptions: DockerSecretsConfigLoaderOptions = {\n\t\tdisabled: false,\n\t\tfileLowerCase: false,\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tpath: '/run/secrets',\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<DockerSecretsConfigLoaderOptions>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\tloaderType: Lowercase<string> = 'docker-secrets',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = loaderType;\n\t}\n\n\tprotected async handleLoaderValue(lookupKey: string): Promise<LoaderValue> {\n\t\tconst options = await this.getOptions();\n\t\tconst filePath = this.filePath(lookupKey, options);\n\t\tlet valuePromise = this.valuePromises.get(lookupKey) ?? Promise.resolve(undefined);\n\t\tconst seen = this.valuePromises.has(lookupKey); // if valuePromise exists, it means we have seen this key before\n\t\tif (!seen) {\n\t\t\tif (!existsSync(filePath)) {\n\t\t\t\tif (!options.isSilent) {\n\t\t\t\t\tthrow new VariableLookupError(lookupKey, `ConfigVariables[${this.loaderType}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t\t}\n\t\t\t\toptions.logger?.debug(`ConfigVariables[${this.loaderType}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t} else {\n\t\t\t\tvaluePromise = readFile(filePath, 'utf8');\n\t\t\t}\n\t\t\t// store value promise as haven't seen this key before\n\t\t\tthis.valuePromises.set(lookupKey, valuePromise);\n\t\t}\n\t\treturn {path: filePath, value: await valuePromise};\n\t}\n\n\tprivate filePath(key: string, options: DockerSecretsConfigLoaderOptions): string {\n\t\treturn path.join(path.resolve(options.path), options.fileLowerCase ? key.toLowerCase() : key);\n\t}\n}\n","import type {OverrideKeyMap} from '@avanio/variable-util';\nimport type {Loadable} from '@luolapeikko/ts-common';\nimport {parse} from 'dotenv';\nimport {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\n\n/**\n * Loader for dotenv files, using the `dotenv` packages parser.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class DotEnvLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends AbstractFileRecordLoader<\n\tAbstractFileRecordLoaderOptions<string>,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\n\tprotected defaultOptions: AbstractFileRecordLoaderOptions<'env'> = {\n\t\tdisabled: false,\n\t\tfileName: '.env',\n\t\tfileType: 'env',\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tvalidate: undefined,\n\t\twatch: false,\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<AbstractFileRecordLoaderOptions<'env'>>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\ttype: Lowercase<string> = 'dotenv',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = type;\n\t}\n\n\tprotected handleParse(rawData: Buffer): Record<string, string | undefined> {\n\t\treturn parse(rawData);\n\t}\n}\n","import type {OverrideKeyMap} from '@avanio/variable-util';\nimport {type Loadable, UndefCore} from '@luolapeikko/ts-common';\nimport {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\n\n/**\n * A file-based configuration loader that reads a JSON file.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class FileConfigLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends AbstractFileRecordLoader<\n\tAbstractFileRecordLoaderOptions<'json'>,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\n\tprotected defaultOptions: AbstractFileRecordLoaderOptions<'json'> = {\n\t\tdisabled: false,\n\t\tfileName: 'config.json',\n\t\tfileType: 'json',\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tvalidate: undefined,\n\t\twatch: false,\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<AbstractFileRecordLoaderOptions<'json'>>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\ttype: Lowercase<string> = 'file',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = type;\n\t}\n\n\tprotected handleParse(rawData: Buffer, options: AbstractFileRecordLoaderOptions<'json'>): Record<string, string | undefined> {\n\t\tconst data: unknown = JSON.parse(rawData.toString());\n\t\tif (typeof data !== 'object' || data === null || Array.isArray(data)) {\n\t\t\toptions.logger?.error(`ConfigVariables[${this.loaderType}]: Invalid JSON data from ${options.fileName}`);\n\t\t\treturn {};\n\t\t}\n\t\treturn this.convertObjectToStringRecord(data);\n\t}\n\n\t/**\n\t * Converts an object to a record of strings as env values are always strings.\n\t * @param {object} data The object to convert\n\t * @returns {Record<string, string>} The converted object\n\t */\n\tprivate convertObjectToStringRecord(data: object): Record<string, string> {\n\t\treturn Object.entries(data).reduce<Record<string, string>>((acc, [key, value]) => {\n\t\t\tif (UndefCore.isNotNullish(value)) {\n\t\t\t\tacc[key] = String(value);\n\t\t\t}\n\t\t\treturn acc;\n\t\t}, {});\n\t}\n}\n"],"mappings":"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"}
{"version":3,"file":"index.cjs","names":["MapConfigLoader","VariableError","ErrorCore","ConfigLoader","VariableLookupError","UndefCore"],"sources":["../src/AbstractFileRecordLoader.ts","../src/DockerSecretsConfigLoader.ts","../src/DotEnvLoader.ts","../src/FileConfigLoader.ts"],"sourcesContent":["import type {ILoggerLike} from '@avanio/logger-like';\nimport {\n\tapplyStringMap,\n\ttype IConfigLoaderProps,\n\ttype LoaderValue,\n\tMapConfigLoader,\n\ttype OverrideKeyMap,\n\ttype ValidateCallback,\n\tVariableError,\n} from '@avanio/variable-util';\nimport {Err, type IResult, Ok} from '@luolapeikko/result-option';\nimport {ErrorCore, type Loadable} from '@luolapeikko/ts-common';\nimport {type FSWatcher, watch} from 'fs';\nimport {readFile} from 'fs/promises';\n\n/**\n * Options for the AbstractFileRecordLoader.\n * @template FileType Type of the file\n * @since v1.0.0\n */\nexport interface AbstractFileRecordLoaderOptions<FileType extends string> extends IConfigLoaderProps {\n\tfileType: FileType;\n\t/** file name to load */\n\tfileName: string;\n\t/** set to false if need errors */\n\tisSilent: boolean;\n\t/** optional logger */\n\tlogger: ILoggerLike | undefined;\n\t/** set to true to watch file for changes */\n\twatch: boolean;\n\t/** set to true to disable loader */\n\tdisabled: boolean;\n\t/**\n\t * optional validator for data (Record<string, string | undefined>)\n\t * @example\n\t * // using zod\n\t * const stringRecordSchema = z.record(z.string().min(1), z.string());\n\t * const validate: ValidateCallback<Record<string, string>> = async (data) => {\n\t * const result = await stringRecordSchema.safeParseAsync(data);\n\t * if (!result.success) {\n\t * return {success: false, message: result.error.message};\n\t * }\n\t * return {success: true};\n\t * };\n\t */\n\tvalidate: ValidateCallback<Record<string, string | undefined>, Record<string, string | undefined>> | undefined;\n}\n\n/**\n * Abstract class for loading records from a file.\n * @template Options Options for the loader\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport abstract class AbstractFileRecordLoader<\n\tOptions extends AbstractFileRecordLoaderOptions<string> = AbstractFileRecordLoaderOptions<string>,\n\tOverrideMap extends OverrideKeyMap = OverrideKeyMap,\n> extends MapConfigLoader<Options, OverrideMap> {\n\tpublic abstract readonly loaderType: Lowercase<string>;\n\tprotected abstract defaultOptions: Options;\n\tprivate watcher: FSWatcher | undefined;\n\tprivate timeout: ReturnType<typeof setTimeout> | undefined;\n\n\tpublic constructor(options: Loadable<Partial<Options>>, overrideKeys?: Partial<OverrideMap>) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.handleFileChange = this.handleFileChange.bind(this);\n\t}\n\n\t/**\n\t * If the loader is watching the file, it will stop watching.\n\t */\n\tpublic async close(): Promise<void> {\n\t\tif (this.watcher) {\n\t\t\tconst {logger, fileName} = await this.getOptions();\n\t\t\tlogger?.debug(this.buildErrorStr(`closing file watcher for ${fileName}`));\n\t\t\tthis.watcher.close();\n\t\t}\n\t}\n\n\tprotected async handleLoaderValue(lookupKey: string): Promise<LoaderValue> {\n\t\tconst {fileName} = await this.getOptions();\n\t\tif (!this._isLoaded) {\n\t\t\tawait this.loadData();\n\t\t\tthis._isLoaded = true; // only load data once to prevent spamming\n\t\t}\n\t\tconst value = this.data.get(lookupKey);\n\t\treturn {path: fileName, value};\n\t}\n\n\tprotected async handleData(): Promise<IResult<Record<string, string | undefined>, VariableError>> {\n\t\tconst options = await this.getOptions();\n\t\toptions.logger?.debug(this.buildErrorStr(`loading file ${options.fileName}`));\n\t\tlet buffer: Buffer;\n\t\ttry {\n\t\t\tbuffer = await readFile(options.fileName);\n\t\t} catch (cause) {\n\t\t\treturn Err(new VariableError(this.buildErrorStr(ErrorCore.from(cause).message), {cause}));\n\t\t}\n\t\ttry {\n\t\t\tlet data = await this.handleParse(buffer, options);\n\t\t\tif (options.validate) {\n\t\t\t\tdata = await options.validate(data);\n\t\t\t}\n\t\t\tthis.handleFileWatch(options); // add watch after successful load\n\t\t\treturn Ok(data);\n\t\t} catch (cause) {\n\t\t\treturn Err(new VariableError(this.buildErrorStr(`file ${options.fileName} is not a valid ${options.fileType}`), {cause}));\n\t\t}\n\t}\n\n\tprotected async handleLoadData(): Promise<boolean> {\n\t\tconst {logger, isSilent} = await this.getOptions();\n\t\tconst res = (await this.handleData())\n\t\t\t.inspectErr((err) => isSilent && logger?.debug(err))\n\t\t\t.andThen((data) => {\n\t\t\t\tapplyStringMap(data, this.data);\n\t\t\t\treturn Ok();\n\t\t\t});\n\t\tif (res.isErr && !isSilent) {\n\t\t\tres.unwrap();\n\t\t}\n\t\treturn res.isOk;\n\t}\n\n\tprivate handleFileWatch(options: Options): void {\n\t\tif (options.watch && !this.watcher) {\n\t\t\toptions.logger?.debug(this.buildErrorStr(`opening file watcher for ${options.fileName}`));\n\t\t\tthis.watcher = watch(options.fileName, () => {\n\t\t\t\tif (this.timeout) {\n\t\t\t\t\tclearTimeout(this.timeout);\n\t\t\t\t}\n\t\t\t\t// delay to prevent multiple reloads\n\t\t\t\tthis.timeout = setTimeout(() => {\n\t\t\t\t\tvoid this.handleFileChange(options);\n\t\t\t\t}, 200);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async handleFileChange(options: Options): Promise<void> {\n\t\ttry {\n\t\t\toptions.logger?.debug(this.buildErrorStr(`file ${options.fileName} changed`));\n\t\t\tawait this.reload();\n\t\t} catch (err) {\n\t\t\toptions.logger?.error(this.buildErrorStr(`error reloading file ${options.fileName}: ${ErrorCore.from(err).message}`));\n\t\t}\n\t}\n\n\t/**\n\t * Handle the parsing of the file.\n\t */\n\tprotected abstract handleParse(rawData: Buffer, options: Options): Record<string, string | undefined> | Promise<Record<string, string | undefined>>;\n}\n","import type {ILoggerLike} from '@avanio/logger-like';\nimport {ConfigLoader, type LoaderValue, type OverrideKeyMap, VariableLookupError} from '@avanio/variable-util';\nimport type {Loadable} from '@luolapeikko/ts-common';\nimport {existsSync} from 'fs';\nimport {readFile} from 'fs/promises';\nimport * as path from 'path';\n\n/**\n * DockerSecretsConfigLoaderOptions is the interface for DockerSecretsConfigLoader options\n * @category Loaders\n * @since v1.0.0\n * @template OverrideMap - the type of the override key map\n */\nexport interface DockerSecretsConfigLoaderOptions {\n\t/** force file name to lower case */\n\tfileLowerCase: boolean;\n\t/** path to docker secrets, default is '/run/secrets' */\n\tpath: string;\n\t/** set to false if need errors */\n\tisSilent: boolean;\n\t/** optional logger */\n\tlogger: ILoggerLike | undefined;\n\t/** set to true to disable loader, default is false */\n\tdisabled: boolean;\n}\n\n/**\n * Loader for docker secrets, reads secrets from the `/run/secrets` directory.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class DockerSecretsConfigLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends ConfigLoader<\n\tDockerSecretsConfigLoaderOptions,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\tprivate valuePromises = new Map<string, Promise<string | undefined>>();\n\tprotected defaultOptions: DockerSecretsConfigLoaderOptions = {\n\t\tdisabled: false,\n\t\tfileLowerCase: false,\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tpath: '/run/secrets',\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<DockerSecretsConfigLoaderOptions>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\tloaderType: Lowercase<string> = 'docker-secrets',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = loaderType;\n\t}\n\n\tprotected async handleLoaderValue(lookupKey: string): Promise<LoaderValue> {\n\t\tconst options = await this.getOptions();\n\t\tconst filePath = this.filePath(lookupKey, options);\n\t\tlet valuePromise = this.valuePromises.get(lookupKey) ?? Promise.resolve(undefined);\n\t\tconst seen = this.valuePromises.has(lookupKey); // if valuePromise exists, it means we have seen this key before\n\t\tif (!seen) {\n\t\t\tif (!existsSync(filePath)) {\n\t\t\t\tif (!options.isSilent) {\n\t\t\t\t\tthrow new VariableLookupError(lookupKey, `ConfigVariables[${this.loaderType}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t\t}\n\t\t\t\toptions.logger?.debug(`ConfigVariables[${this.loaderType}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t} else {\n\t\t\t\tvaluePromise = readFile(filePath, 'utf8');\n\t\t\t}\n\t\t\t// store value promise as haven't seen this key before\n\t\t\tthis.valuePromises.set(lookupKey, valuePromise);\n\t\t}\n\t\treturn {path: filePath, value: await valuePromise};\n\t}\n\n\tprivate filePath(key: string, options: DockerSecretsConfigLoaderOptions): string {\n\t\treturn path.join(path.resolve(options.path), options.fileLowerCase ? key.toLowerCase() : key);\n\t}\n}\n","import type {OverrideKeyMap} from '@avanio/variable-util';\nimport type {Loadable} from '@luolapeikko/ts-common';\nimport {parse} from 'dotenv';\nimport {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\n\n/**\n * Loader for dotenv files, using the `dotenv` packages parser.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class DotEnvLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends AbstractFileRecordLoader<\n\tAbstractFileRecordLoaderOptions<string>,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\n\tprotected defaultOptions: AbstractFileRecordLoaderOptions<'env'> = {\n\t\tdisabled: false,\n\t\tfileName: '.env',\n\t\tfileType: 'env',\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tvalidate: undefined,\n\t\twatch: false,\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<AbstractFileRecordLoaderOptions<'env'>>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\ttype: Lowercase<string> = 'dotenv',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = type;\n\t}\n\n\tprotected handleParse(rawData: Buffer): Record<string, string | undefined> {\n\t\treturn parse(rawData);\n\t}\n}\n","import type {OverrideKeyMap} from '@avanio/variable-util';\nimport {type Loadable, UndefCore} from '@luolapeikko/ts-common';\nimport {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\n\n/**\n * A file-based configuration loader that reads a JSON file.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class FileConfigLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends AbstractFileRecordLoader<\n\tAbstractFileRecordLoaderOptions<'json'>,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\n\tprotected defaultOptions: AbstractFileRecordLoaderOptions<'json'> = {\n\t\tdisabled: false,\n\t\tfileName: 'config.json',\n\t\tfileType: 'json',\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tvalidate: undefined,\n\t\twatch: false,\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<AbstractFileRecordLoaderOptions<'json'>>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\ttype: Lowercase<string> = 'file',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = type;\n\t}\n\n\tprotected handleParse(rawData: Buffer, options: AbstractFileRecordLoaderOptions<'json'>): Record<string, string | undefined> {\n\t\tconst data: unknown = JSON.parse(rawData.toString());\n\t\tif (typeof data !== 'object' || data === null || Array.isArray(data)) {\n\t\t\toptions.logger?.error(`ConfigVariables[${this.loaderType}]: Invalid JSON data from ${options.fileName}`);\n\t\t\treturn {};\n\t\t}\n\t\treturn this.convertObjectToStringRecord(data);\n\t}\n\n\t/**\n\t * Converts an object to a record of strings as env values are always strings.\n\t * @param {object} data The object to convert\n\t * @returns {Record<string, string>} The converted object\n\t */\n\tprivate convertObjectToStringRecord(data: object): Record<string, string> {\n\t\treturn Object.entries(data).reduce<Record<string, string>>((acc, [key, value]) => {\n\t\t\tif (UndefCore.isNotNullish(value)) {\n\t\t\t\tacc[key] = String(value);\n\t\t\t}\n\t\t\treturn acc;\n\t\t}, {});\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,IAAsB,2BAAtB,cAGUA,sCAAsC;CAG/C,AAAQ;CACR,AAAQ;CAER,AAAO,YAAY,SAAqC,cAAqC;AAC5F,QAAM,SAAS,aAAa;AAC5B,OAAK,mBAAmB,KAAK,iBAAiB,KAAK,KAAK;;;;;CAMzD,MAAa,QAAuB;AACnC,MAAI,KAAK,SAAS;GACjB,MAAM,EAAC,QAAQ,aAAY,MAAM,KAAK,YAAY;AAClD,WAAQ,MAAM,KAAK,cAAc,4BAA4B,WAAW,CAAC;AACzE,QAAK,QAAQ,OAAO;;;CAItB,MAAgB,kBAAkB,WAAyC;EAC1E,MAAM,EAAC,aAAY,MAAM,KAAK,YAAY;AAC1C,MAAI,CAAC,KAAK,WAAW;AACpB,SAAM,KAAK,UAAU;AACrB,QAAK,YAAY;;AAGlB,SAAO;GAAC,MAAM;GAAU,OADV,KAAK,KAAK,IAAI,UAAU;GACR;;CAG/B,MAAgB,aAAkF;EACjG,MAAM,UAAU,MAAM,KAAK,YAAY;AACvC,UAAQ,QAAQ,MAAM,KAAK,cAAc,gBAAgB,QAAQ,WAAW,CAAC;EAC7E,IAAI;AACJ,MAAI;AACH,YAAS,gCAAe,QAAQ,SAAS;WACjC,OAAO;AACf,8CAAW,IAAIC,oCAAc,KAAK,cAAcC,iCAAU,KAAK,MAAM,CAAC,QAAQ,EAAE,EAAC,OAAM,CAAC,CAAC;;AAE1F,MAAI;GACH,IAAI,OAAO,MAAM,KAAK,YAAY,QAAQ,QAAQ;AAClD,OAAI,QAAQ,SACX,QAAO,MAAM,QAAQ,SAAS,KAAK;AAEpC,QAAK,gBAAgB,QAAQ;AAC7B,6CAAU,KAAK;WACP,OAAO;AACf,8CAAW,IAAID,oCAAc,KAAK,cAAc,QAAQ,QAAQ,SAAS,kBAAkB,QAAQ,WAAW,EAAE,EAAC,OAAM,CAAC,CAAC;;;CAI3H,MAAgB,iBAAmC;EAClD,MAAM,EAAC,QAAQ,aAAY,MAAM,KAAK,YAAY;EAClD,MAAM,OAAO,MAAM,KAAK,YAAY,EAClC,YAAY,QAAQ,YAAY,QAAQ,MAAM,IAAI,CAAC,CACnD,SAAS,SAAS;AAClB,6CAAe,MAAM,KAAK,KAAK;AAC/B,8CAAW;IACV;AACH,MAAI,IAAI,SAAS,CAAC,SACjB,KAAI,QAAQ;AAEb,SAAO,IAAI;;CAGZ,AAAQ,gBAAgB,SAAwB;AAC/C,MAAI,QAAQ,SAAS,CAAC,KAAK,SAAS;AACnC,WAAQ,QAAQ,MAAM,KAAK,cAAc,4BAA4B,QAAQ,WAAW,CAAC;AACzF,QAAK,wBAAgB,QAAQ,gBAAgB;AAC5C,QAAI,KAAK,QACR,cAAa,KAAK,QAAQ;AAG3B,SAAK,UAAU,iBAAiB;AAC/B,KAAK,KAAK,iBAAiB,QAAQ;OACjC,IAAI;KACN;;;CAIJ,MAAc,iBAAiB,SAAiC;AAC/D,MAAI;AACH,WAAQ,QAAQ,MAAM,KAAK,cAAc,QAAQ,QAAQ,SAAS,UAAU,CAAC;AAC7E,SAAM,KAAK,QAAQ;WACX,KAAK;AACb,WAAQ,QAAQ,MAAM,KAAK,cAAc,wBAAwB,QAAQ,SAAS,IAAIC,iCAAU,KAAK,IAAI,CAAC,UAAU,CAAC;;;;;;;;;;;;ACjHxH,IAAa,4BAAb,cAAoGC,mCAGlG;CACD,AAAgB;CAChB,AAAQ,gCAAgB,IAAI,KAA0C;CACtE,AAAU,iBAAmD;EAC5D,UAAU;EACV,eAAe;EACf,UAAU;EACV,QAAQ;EACR,MAAM;EACN;CAED,AAAO,YACN,SACA,cACA,aAAgC,kBAC/B;AACD,QAAM,SAAS,aAAa;AAC5B,OAAK,aAAa;;CAGnB,MAAgB,kBAAkB,WAAyC;EAC1E,MAAM,UAAU,MAAM,KAAK,YAAY;EACvC,MAAM,WAAW,KAAK,SAAS,WAAW,QAAQ;EAClD,IAAI,eAAe,KAAK,cAAc,IAAI,UAAU,IAAI,QAAQ,QAAQ,OAAU;AAElF,MAAI,CADS,KAAK,cAAc,IAAI,UAAU,EACnC;AACV,OAAI,oBAAY,SAAS,EAAE;AAC1B,QAAI,CAAC,QAAQ,SACZ,OAAM,IAAIC,0CAAoB,WAAW,mBAAmB,KAAK,WAAW,KAAK,UAAU,QAAQ,SAAS,YAAY;AAEzH,YAAQ,QAAQ,MAAM,mBAAmB,KAAK,WAAW,KAAK,UAAU,QAAQ,SAAS,YAAY;SAErG,0CAAwB,UAAU,OAAO;AAG1C,QAAK,cAAc,IAAI,WAAW,aAAa;;AAEhD,SAAO;GAAC,MAAM;GAAU,OAAO,MAAM;GAAa;;CAGnD,AAAQ,SAAS,KAAa,SAAmD;AAChF,SAAO,KAAK,KAAK,KAAK,QAAQ,QAAQ,KAAK,EAAE,QAAQ,gBAAgB,IAAI,aAAa,GAAG,IAAI;;;;;;;;;;;ACjE/F,IAAa,eAAb,cAAuF,yBAGrF;CACD,AAAgB;CAEhB,AAAU,iBAAyD;EAClE,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EACV,QAAQ;EACR,UAAU;EACV,OAAO;EACP;CAED,AAAO,YACN,SACA,cACA,OAA0B,UACzB;AACD,QAAM,SAAS,aAAa;AAC5B,OAAK,aAAa;;CAGnB,AAAU,YAAY,SAAqD;AAC1E,2BAAa,QAAQ;;;;;;;;;;;AC3BvB,IAAa,mBAAb,cAA2F,yBAGzF;CACD,AAAgB;CAEhB,AAAU,iBAA0D;EACnE,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EACV,QAAQ;EACR,UAAU;EACV,OAAO;EACP;CAED,AAAO,YACN,SACA,cACA,OAA0B,QACzB;AACD,QAAM,SAAS,aAAa;AAC5B,OAAK,aAAa;;CAGnB,AAAU,YAAY,SAAiB,SAAsF;EAC5H,MAAM,OAAgB,KAAK,MAAM,QAAQ,UAAU,CAAC;AACpD,MAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,KAAK,EAAE;AACrE,WAAQ,QAAQ,MAAM,mBAAmB,KAAK,WAAW,4BAA4B,QAAQ,WAAW;AACxG,UAAO,EAAE;;AAEV,SAAO,KAAK,4BAA4B,KAAK;;;;;;;CAQ9C,AAAQ,4BAA4B,MAAsC;AACzE,SAAO,OAAO,QAAQ,KAAK,CAAC,QAAgC,KAAK,CAAC,KAAK,WAAW;AACjF,OAAIC,iCAAU,aAAa,MAAM,CAChC,KAAI,OAAO,OAAO,MAAM;AAEzB,UAAO;KACL,EAAE,CAAC"}

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.cts","names":[],"sources":["../src/AbstractFileRecordLoader.ts","../src/DockerSecretsConfigLoader.ts","../src/DotEnvLoader.ts","../src/FileConfigLoader.ts"],"mappings":";;;;;;;;AAoBA;;;UAAiB,+BAAA,kCAAiE,kBAAA;EACjF,QAAA,EAAU,QAAA;;EAEV,QAAA;;EAEA,QAAA;;EAEA,MAAA,EAAQ,WAAA;;EAER,KAAA;;EAEA,QAAA;;;;;;;;;;;;;AAuBD;EATC,QAAA,EAAU,gBAAA,CAAiB,MAAA,8BAAoC,MAAA;AAAA;;;;;;;uBAS1C,wBAAA,iBACL,+BAAA,WAA0C,+BAAA,8BACtC,cAAA,GAAiB,cAAA,UAC5B,eAAA,CAAgB,OAAA,EAAS,WAAA;EAAA,kBACT,UAAA,EAAY,SAAA;EAAA,mBAClB,cAAA,EAAgB,OAAA;EAAA,QAC3B,OAAA;EAAA,QACA,OAAA;EAER,WAAA,CAAmB,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,OAAA,IAAW,YAAA,GAAe,OAAA,CAAQ,WAAA;;;;EAQ/E,KAAA,CAAA,GAAsB,OAAA;EAAA,UAQN,iBAAA,CAAkB,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAAA,UAU9C,UAAA,CAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,MAAA,8BAAoC,aAAA;EAAA,UAwBlE,cAAA,CAAA,GAAkB,OAAA;EAAA,QAe1B,eAAA;EAAA,QAeM,gBAAA;;;;qBAYK,WAAA,CAAY,OAAA,EAAS,MAAA,EAAQ,OAAA,EAAS,OAAA,GAAU,MAAA,+BAAqC,OAAA,CAAQ,MAAA;AAAA;;;;;;AAvIjH;;;UCPiB,gCAAA;;EAEhB,aAAA;;EAEA,IAAA;;EAEA,QAAA;EDCiF;ECCjF,MAAA,EAAQ,WAAA;;EAER,QAAA;AAAA;;;;;;cAQY,yBAAA,qBAA8C,cAAA,GAAiB,cAAA,UAAwB,YAAA,CACnG,gCAAA,EACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,QACpB,aAAA;EAAA,UACE,cAAA,EAAgB,gCAAA;EAQ1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,gCAAA,IAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,UAAA,GAAY,SAAA;EAAA,UAMG,iBAAA,CAAkB,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAAA,QAoBtD,QAAA;AAAA;;;;;;ADtDT;;cEVa,YAAA,qBAAiC,cAAA,GAAiB,cAAA,UAAwB,wBAAA,CACtF,+BAAA,UACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,UAElB,cAAA,EAAgB,+BAAA;EAU1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,+BAAA,WAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,IAAA,GAAM,SAAA;EAAA,UAMG,WAAA,CAAY,OAAA,EAAS,MAAA,GAAS,MAAA;AAAA;;;;;;AFfzC;;cGXa,gBAAA,qBAAqC,cAAA,GAAiB,cAAA,UAAwB,wBAAA,CAC1F,+BAAA,UACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,UAElB,cAAA,EAAgB,+BAAA;EAU1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,+BAAA,YAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,IAAA,GAAM,SAAA;EAAA,UAMG,WAAA,CAAY,OAAA,EAAS,MAAA,EAAQ,OAAA,EAAS,+BAAA,WAA0C,MAAA;;;;;;UAclF,2BAAA;AAAA"}
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/AbstractFileRecordLoader.ts","../src/DockerSecretsConfigLoader.ts","../src/DotEnvLoader.ts","../src/FileConfigLoader.ts"],"mappings":";;;;;;;;AAoBA;;;UAAiB,+BAAA,kCAAiE,kBAAA;EACjF,QAAA,EAAU,QAAA;;EAEV,QAAA;;EAEA,QAAA;;EAEA,MAAA,EAAQ,WAAA;;EAER,KAAA;;EAEA,QAAA;;;;;;;;;;;;;AAuBD;EATC,QAAA,EAAU,gBAAA,CAAiB,MAAA,8BAAoC,MAAA;AAAA;;;;;;;uBAS1C,wBAAA,iBACL,+BAAA,WAA0C,+BAAA,8BACtC,cAAA,GAAiB,cAAA,UAC5B,eAAA,CAAgB,OAAA,EAAS,WAAA;EAAA,kBACT,UAAA,EAAY,SAAA;EAAA,mBAClB,cAAA,EAAgB,OAAA;EAAA,QAC3B,OAAA;EAAA,QACA,OAAA;EAER,WAAA,CAAmB,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,OAAA,IAAW,YAAA,GAAe,OAAA,CAAQ,WAAA;;;;EAQ/E,KAAA,CAAA,GAAsB,OAAA;EAAA,UAQN,iBAAA,CAAkB,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAAA,UAU9C,UAAA,CAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,MAAA,8BAAoC,aAAA;EAAA,UAqBlE,cAAA,CAAA,GAAkB,OAAA;EAAA,QAc1B,eAAA;EAAA,QAeM,gBAAA;;;;qBAYK,WAAA,CAAY,OAAA,EAAS,MAAA,EAAQ,OAAA,EAAS,OAAA,GAAU,MAAA,+BAAqC,OAAA,CAAQ,MAAA;AAAA;;;;;;AAnIjH;;;UCPiB,gCAAA;;EAEhB,aAAA;;EAEA,IAAA;;EAEA,QAAA;EDCiF;ECCjF,MAAA,EAAQ,WAAA;;EAER,QAAA;AAAA;;;;;;cAQY,yBAAA,qBAA8C,cAAA,GAAiB,cAAA,UAAwB,YAAA,CACnG,gCAAA,EACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,QACpB,aAAA;EAAA,UACE,cAAA,EAAgB,gCAAA;EAQ1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,gCAAA,IAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,UAAA,GAAY,SAAA;EAAA,UAMG,iBAAA,CAAkB,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAAA,QAoBtD,QAAA;AAAA;;;;;;ADtDT;;cEVa,YAAA,qBAAiC,cAAA,GAAiB,cAAA,UAAwB,wBAAA,CACtF,+BAAA,UACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,UAElB,cAAA,EAAgB,+BAAA;EAU1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,+BAAA,WAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,IAAA,GAAM,SAAA;EAAA,UAMG,WAAA,CAAY,OAAA,EAAS,MAAA,GAAS,MAAA;AAAA;;;;;;AFfzC;;cGXa,gBAAA,qBAAqC,cAAA,GAAiB,cAAA,UAAwB,wBAAA,CAC1F,+BAAA,UACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,UAElB,cAAA,EAAgB,+BAAA;EAU1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,+BAAA,YAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,IAAA,GAAM,SAAA;EAAA,UAMG,WAAA,CAAY,OAAA,EAAS,MAAA,EAAQ,OAAA,EAAS,+BAAA,WAA0C,MAAA;;;;;;UAclF,2BAAA;AAAA"}

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.mts","names":[],"sources":["../src/AbstractFileRecordLoader.ts","../src/DockerSecretsConfigLoader.ts","../src/DotEnvLoader.ts","../src/FileConfigLoader.ts"],"mappings":";;;;;;;;AAoBA;;;UAAiB,+BAAA,kCAAiE,kBAAA;EACjF,QAAA,EAAU,QAAA;;EAEV,QAAA;;EAEA,QAAA;;EAEA,MAAA,EAAQ,WAAA;;EAER,KAAA;;EAEA,QAAA;;;;;;;;;;;;;AAuBD;EATC,QAAA,EAAU,gBAAA,CAAiB,MAAA,8BAAoC,MAAA;AAAA;;;;;;;uBAS1C,wBAAA,iBACL,+BAAA,WAA0C,+BAAA,8BACtC,cAAA,GAAiB,cAAA,UAC5B,eAAA,CAAgB,OAAA,EAAS,WAAA;EAAA,kBACT,UAAA,EAAY,SAAA;EAAA,mBAClB,cAAA,EAAgB,OAAA;EAAA,QAC3B,OAAA;EAAA,QACA,OAAA;EAER,WAAA,CAAmB,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,OAAA,IAAW,YAAA,GAAe,OAAA,CAAQ,WAAA;;;;EAQ/E,KAAA,CAAA,GAAsB,OAAA;EAAA,UAQN,iBAAA,CAAkB,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAAA,UAU9C,UAAA,CAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,MAAA,8BAAoC,aAAA;EAAA,UAwBlE,cAAA,CAAA,GAAkB,OAAA;EAAA,QAe1B,eAAA;EAAA,QAeM,gBAAA;;;;qBAYK,WAAA,CAAY,OAAA,EAAS,MAAA,EAAQ,OAAA,EAAS,OAAA,GAAU,MAAA,+BAAqC,OAAA,CAAQ,MAAA;AAAA;;;;;;AAvIjH;;;UCPiB,gCAAA;;EAEhB,aAAA;;EAEA,IAAA;;EAEA,QAAA;EDCiF;ECCjF,MAAA,EAAQ,WAAA;;EAER,QAAA;AAAA;;;;;;cAQY,yBAAA,qBAA8C,cAAA,GAAiB,cAAA,UAAwB,YAAA,CACnG,gCAAA,EACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,QACpB,aAAA;EAAA,UACE,cAAA,EAAgB,gCAAA;EAQ1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,gCAAA,IAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,UAAA,GAAY,SAAA;EAAA,UAMG,iBAAA,CAAkB,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAAA,QAoBtD,QAAA;AAAA;;;;;;ADtDT;;cEVa,YAAA,qBAAiC,cAAA,GAAiB,cAAA,UAAwB,wBAAA,CACtF,+BAAA,UACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,UAElB,cAAA,EAAgB,+BAAA;EAU1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,+BAAA,WAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,IAAA,GAAM,SAAA;EAAA,UAMG,WAAA,CAAY,OAAA,EAAS,MAAA,GAAS,MAAA;AAAA;;;;;;AFfzC;;cGXa,gBAAA,qBAAqC,cAAA,GAAiB,cAAA,UAAwB,wBAAA,CAC1F,+BAAA,UACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,UAElB,cAAA,EAAgB,+BAAA;EAU1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,+BAAA,YAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,IAAA,GAAM,SAAA;EAAA,UAMG,WAAA,CAAY,OAAA,EAAS,MAAA,EAAQ,OAAA,EAAS,+BAAA,WAA0C,MAAA;;;;;;UAclF,2BAAA;AAAA"}
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/AbstractFileRecordLoader.ts","../src/DockerSecretsConfigLoader.ts","../src/DotEnvLoader.ts","../src/FileConfigLoader.ts"],"mappings":";;;;;;;;AAoBA;;;UAAiB,+BAAA,kCAAiE,kBAAA;EACjF,QAAA,EAAU,QAAA;;EAEV,QAAA;;EAEA,QAAA;;EAEA,MAAA,EAAQ,WAAA;;EAER,KAAA;;EAEA,QAAA;;;;;;;;;;;;;AAuBD;EATC,QAAA,EAAU,gBAAA,CAAiB,MAAA,8BAAoC,MAAA;AAAA;;;;;;;uBAS1C,wBAAA,iBACL,+BAAA,WAA0C,+BAAA,8BACtC,cAAA,GAAiB,cAAA,UAC5B,eAAA,CAAgB,OAAA,EAAS,WAAA;EAAA,kBACT,UAAA,EAAY,SAAA;EAAA,mBAClB,cAAA,EAAgB,OAAA;EAAA,QAC3B,OAAA;EAAA,QACA,OAAA;EAER,WAAA,CAAmB,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,OAAA,IAAW,YAAA,GAAe,OAAA,CAAQ,WAAA;;;;EAQ/E,KAAA,CAAA,GAAsB,OAAA;EAAA,UAQN,iBAAA,CAAkB,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAAA,UAU9C,UAAA,CAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,MAAA,8BAAoC,aAAA;EAAA,UAqBlE,cAAA,CAAA,GAAkB,OAAA;EAAA,QAc1B,eAAA;EAAA,QAeM,gBAAA;;;;qBAYK,WAAA,CAAY,OAAA,EAAS,MAAA,EAAQ,OAAA,EAAS,OAAA,GAAU,MAAA,+BAAqC,OAAA,CAAQ,MAAA;AAAA;;;;;;AAnIjH;;;UCPiB,gCAAA;;EAEhB,aAAA;;EAEA,IAAA;;EAEA,QAAA;EDCiF;ECCjF,MAAA,EAAQ,WAAA;;EAER,QAAA;AAAA;;;;;;cAQY,yBAAA,qBAA8C,cAAA,GAAiB,cAAA,UAAwB,YAAA,CACnG,gCAAA,EACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,QACpB,aAAA;EAAA,UACE,cAAA,EAAgB,gCAAA;EAQ1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,gCAAA,IAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,UAAA,GAAY,SAAA;EAAA,UAMG,iBAAA,CAAkB,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAAA,QAoBtD,QAAA;AAAA;;;;;;ADtDT;;cEVa,YAAA,qBAAiC,cAAA,GAAiB,cAAA,UAAwB,wBAAA,CACtF,+BAAA,UACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,UAElB,cAAA,EAAgB,+BAAA;EAU1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,+BAAA,WAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,IAAA,GAAM,SAAA;EAAA,UAMG,WAAA,CAAY,OAAA,EAAS,MAAA,GAAS,MAAA;AAAA;;;;;;AFfzC;;cGXa,gBAAA,qBAAqC,cAAA,GAAiB,cAAA,UAAwB,wBAAA,CAC1F,+BAAA,UACA,WAAA;EAAA,SAEgB,UAAA,EAAY,SAAA;EAAA,UAElB,cAAA,EAAgB,+BAAA;EAU1B,WAAA,CACC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,+BAAA,YAC1B,YAAA,GAAe,OAAA,CAAQ,WAAA,GACvB,IAAA,GAAM,SAAA;EAAA,UAMG,WAAA,CAAY,OAAA,EAAS,MAAA,EAAQ,OAAA,EAAS,+BAAA,WAA0C,MAAA;;;;;;UAclF,2BAAA;AAAA"}

@@ -47,3 +47,2 @@ import { ConfigLoader, MapConfigLoader, VariableError, VariableLookupError, applyStringMap } from "@avanio/variable-util";

options.logger?.debug(this.buildErrorStr(`loading file ${options.fileName}`));
if (!existsSync(options.fileName)) return Err(new VariableError(this.buildErrorStr(`file ${options.fileName} not found`)));
let buffer;

@@ -53,3 +52,3 @@ try {

} catch (cause) {
return Err(new VariableError(ErrorCore.from(cause).message, { cause }));
return Err(new VariableError(this.buildErrorStr(ErrorCore.from(cause).message), { cause }));
}

@@ -67,10 +66,8 @@ try {

const { logger, isSilent } = await this.getOptions();
const res = await this.handleData();
if (res.isErr) {
if (!isSilent) res.unwrap();
else logger?.debug(res.err());
return false;
}
applyStringMap(res.ok(), this.data);
return true;
const res = (await this.handleData()).inspectErr((err) => isSilent && logger?.debug(err)).andThen((data) => {
applyStringMap(data, this.data);
return Ok();
});
if (res.isErr && !isSilent) res.unwrap();
return res.isOk;
}

@@ -77,0 +74,0 @@ handleFileWatch(options) {

@@ -1,1 +0,1 @@

{"version":3,"file":"index.mjs","names":[],"sources":["../src/AbstractFileRecordLoader.ts","../src/DockerSecretsConfigLoader.ts","../src/DotEnvLoader.ts","../src/FileConfigLoader.ts"],"sourcesContent":["import type {ILoggerLike} from '@avanio/logger-like';\nimport {\n\tapplyStringMap,\n\ttype IConfigLoaderProps,\n\ttype LoaderValue,\n\tMapConfigLoader,\n\ttype OverrideKeyMap,\n\ttype ValidateCallback,\n\tVariableError,\n} from '@avanio/variable-util';\nimport {Err, type IResult, Ok} from '@luolapeikko/result-option';\nimport {ErrorCore, type Loadable} from '@luolapeikko/ts-common';\nimport {existsSync, type FSWatcher, watch} from 'fs';\nimport {readFile} from 'fs/promises';\n\n/**\n * Options for the AbstractFileRecordLoader.\n * @template FileType Type of the file\n * @since v1.0.0\n */\nexport interface AbstractFileRecordLoaderOptions<FileType extends string> extends IConfigLoaderProps {\n\tfileType: FileType;\n\t/** file name to load */\n\tfileName: string;\n\t/** set to false if need errors */\n\tisSilent: boolean;\n\t/** optional logger */\n\tlogger: ILoggerLike | undefined;\n\t/** set to true to watch file for changes */\n\twatch: boolean;\n\t/** set to true to disable loader */\n\tdisabled: boolean;\n\t/**\n\t * optional validator for data (Record<string, string | undefined>)\n\t * @example\n\t * // using zod\n\t * const stringRecordSchema = z.record(z.string().min(1), z.string());\n\t * const validate: ValidateCallback<Record<string, string>> = async (data) => {\n\t * const result = await stringRecordSchema.safeParseAsync(data);\n\t * if (!result.success) {\n\t * return {success: false, message: result.error.message};\n\t * }\n\t * return {success: true};\n\t * };\n\t */\n\tvalidate: ValidateCallback<Record<string, string | undefined>, Record<string, string | undefined>> | undefined;\n}\n\n/**\n * Abstract class for loading records from a file.\n * @template Options Options for the loader\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport abstract class AbstractFileRecordLoader<\n\tOptions extends AbstractFileRecordLoaderOptions<string> = AbstractFileRecordLoaderOptions<string>,\n\tOverrideMap extends OverrideKeyMap = OverrideKeyMap,\n> extends MapConfigLoader<Options, OverrideMap> {\n\tpublic abstract readonly loaderType: Lowercase<string>;\n\tprotected abstract defaultOptions: Options;\n\tprivate watcher: FSWatcher | undefined;\n\tprivate timeout: ReturnType<typeof setTimeout> | undefined;\n\n\tpublic constructor(options: Loadable<Partial<Options>>, overrideKeys?: Partial<OverrideMap>) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.handleFileChange = this.handleFileChange.bind(this);\n\t}\n\n\t/**\n\t * If the loader is watching the file, it will stop watching.\n\t */\n\tpublic async close(): Promise<void> {\n\t\tif (this.watcher) {\n\t\t\tconst {logger, fileName} = await this.getOptions();\n\t\t\tlogger?.debug(this.buildErrorStr(`closing file watcher for ${fileName}`));\n\t\t\tthis.watcher.close();\n\t\t}\n\t}\n\n\tprotected async handleLoaderValue(lookupKey: string): Promise<LoaderValue> {\n\t\tconst {fileName} = await this.getOptions();\n\t\tif (!this._isLoaded) {\n\t\t\tawait this.loadData();\n\t\t\tthis._isLoaded = true; // only load data once to prevent spamming\n\t\t}\n\t\tconst value = this.data.get(lookupKey);\n\t\treturn {path: fileName, value};\n\t}\n\n\tprotected async handleData(): Promise<IResult<Record<string, string | undefined>, VariableError>> {\n\t\tconst options = await this.getOptions();\n\t\toptions.logger?.debug(this.buildErrorStr(`loading file ${options.fileName}`));\n\t\tif (!existsSync(options.fileName)) {\n\t\t\treturn Err(new VariableError(this.buildErrorStr(`file ${options.fileName} not found`)));\n\t\t}\n\t\tlet buffer: Buffer;\n\t\ttry {\n\t\t\tbuffer = await readFile(options.fileName);\n\t\t} catch (cause) {\n\t\t\treturn Err(new VariableError(ErrorCore.from(cause).message, {cause}));\n\t\t}\n\t\ttry {\n\t\t\tlet data = await this.handleParse(buffer, options);\n\t\t\tif (options.validate) {\n\t\t\t\tdata = await options.validate(data);\n\t\t\t}\n\t\t\tthis.handleFileWatch(options); // add watch after successful load\n\t\t\treturn Ok(data);\n\t\t} catch (cause) {\n\t\t\treturn Err(new VariableError(this.buildErrorStr(`file ${options.fileName} is not a valid ${options.fileType}`), {cause}));\n\t\t}\n\t}\n\n\tprotected async handleLoadData(): Promise<boolean> {\n\t\tconst {logger, isSilent} = await this.getOptions();\n\t\tconst res = await this.handleData();\n\t\tif (res.isErr) {\n\t\t\tif (!isSilent) {\n\t\t\t\tres.unwrap();\n\t\t\t} else {\n\t\t\t\tlogger?.debug(res.err());\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\tapplyStringMap(res.ok(), this.data);\n\t\treturn true;\n\t}\n\n\tprivate handleFileWatch(options: Options): void {\n\t\tif (options.watch && !this.watcher) {\n\t\t\toptions.logger?.debug(this.buildErrorStr(`opening file watcher for ${options.fileName}`));\n\t\t\tthis.watcher = watch(options.fileName, () => {\n\t\t\t\tif (this.timeout) {\n\t\t\t\t\tclearTimeout(this.timeout);\n\t\t\t\t}\n\t\t\t\t// delay to prevent multiple reloads\n\t\t\t\tthis.timeout = setTimeout(() => {\n\t\t\t\t\tvoid this.handleFileChange(options);\n\t\t\t\t}, 200);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async handleFileChange(options: Options): Promise<void> {\n\t\ttry {\n\t\t\toptions.logger?.debug(this.buildErrorStr(`file ${options.fileName} changed`));\n\t\t\tawait this.reload();\n\t\t} catch (err) {\n\t\t\toptions.logger?.error(this.buildErrorStr(`error reloading file ${options.fileName}: ${ErrorCore.from(err).message}`));\n\t\t}\n\t}\n\n\t/**\n\t * Handle the parsing of the file.\n\t */\n\tprotected abstract handleParse(rawData: Buffer, options: Options): Record<string, string | undefined> | Promise<Record<string, string | undefined>>;\n}\n","import type {ILoggerLike} from '@avanio/logger-like';\nimport {ConfigLoader, type LoaderValue, type OverrideKeyMap, VariableLookupError} from '@avanio/variable-util';\nimport type {Loadable} from '@luolapeikko/ts-common';\nimport {existsSync} from 'fs';\nimport {readFile} from 'fs/promises';\nimport * as path from 'path';\n\n/**\n * DockerSecretsConfigLoaderOptions is the interface for DockerSecretsConfigLoader options\n * @category Loaders\n * @since v1.0.0\n * @template OverrideMap - the type of the override key map\n */\nexport interface DockerSecretsConfigLoaderOptions {\n\t/** force file name to lower case */\n\tfileLowerCase: boolean;\n\t/** path to docker secrets, default is '/run/secrets' */\n\tpath: string;\n\t/** set to false if need errors */\n\tisSilent: boolean;\n\t/** optional logger */\n\tlogger: ILoggerLike | undefined;\n\t/** set to true to disable loader, default is false */\n\tdisabled: boolean;\n}\n\n/**\n * Loader for docker secrets, reads secrets from the `/run/secrets` directory.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class DockerSecretsConfigLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends ConfigLoader<\n\tDockerSecretsConfigLoaderOptions,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\tprivate valuePromises = new Map<string, Promise<string | undefined>>();\n\tprotected defaultOptions: DockerSecretsConfigLoaderOptions = {\n\t\tdisabled: false,\n\t\tfileLowerCase: false,\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tpath: '/run/secrets',\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<DockerSecretsConfigLoaderOptions>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\tloaderType: Lowercase<string> = 'docker-secrets',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = loaderType;\n\t}\n\n\tprotected async handleLoaderValue(lookupKey: string): Promise<LoaderValue> {\n\t\tconst options = await this.getOptions();\n\t\tconst filePath = this.filePath(lookupKey, options);\n\t\tlet valuePromise = this.valuePromises.get(lookupKey) ?? Promise.resolve(undefined);\n\t\tconst seen = this.valuePromises.has(lookupKey); // if valuePromise exists, it means we have seen this key before\n\t\tif (!seen) {\n\t\t\tif (!existsSync(filePath)) {\n\t\t\t\tif (!options.isSilent) {\n\t\t\t\t\tthrow new VariableLookupError(lookupKey, `ConfigVariables[${this.loaderType}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t\t}\n\t\t\t\toptions.logger?.debug(`ConfigVariables[${this.loaderType}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t} else {\n\t\t\t\tvaluePromise = readFile(filePath, 'utf8');\n\t\t\t}\n\t\t\t// store value promise as haven't seen this key before\n\t\t\tthis.valuePromises.set(lookupKey, valuePromise);\n\t\t}\n\t\treturn {path: filePath, value: await valuePromise};\n\t}\n\n\tprivate filePath(key: string, options: DockerSecretsConfigLoaderOptions): string {\n\t\treturn path.join(path.resolve(options.path), options.fileLowerCase ? key.toLowerCase() : key);\n\t}\n}\n","import type {OverrideKeyMap} from '@avanio/variable-util';\nimport type {Loadable} from '@luolapeikko/ts-common';\nimport {parse} from 'dotenv';\nimport {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\n\n/**\n * Loader for dotenv files, using the `dotenv` packages parser.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class DotEnvLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends AbstractFileRecordLoader<\n\tAbstractFileRecordLoaderOptions<string>,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\n\tprotected defaultOptions: AbstractFileRecordLoaderOptions<'env'> = {\n\t\tdisabled: false,\n\t\tfileName: '.env',\n\t\tfileType: 'env',\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tvalidate: undefined,\n\t\twatch: false,\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<AbstractFileRecordLoaderOptions<'env'>>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\ttype: Lowercase<string> = 'dotenv',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = type;\n\t}\n\n\tprotected handleParse(rawData: Buffer): Record<string, string | undefined> {\n\t\treturn parse(rawData);\n\t}\n}\n","import type {OverrideKeyMap} from '@avanio/variable-util';\nimport {type Loadable, UndefCore} from '@luolapeikko/ts-common';\nimport {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\n\n/**\n * A file-based configuration loader that reads a JSON file.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class FileConfigLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends AbstractFileRecordLoader<\n\tAbstractFileRecordLoaderOptions<'json'>,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\n\tprotected defaultOptions: AbstractFileRecordLoaderOptions<'json'> = {\n\t\tdisabled: false,\n\t\tfileName: 'config.json',\n\t\tfileType: 'json',\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tvalidate: undefined,\n\t\twatch: false,\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<AbstractFileRecordLoaderOptions<'json'>>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\ttype: Lowercase<string> = 'file',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = type;\n\t}\n\n\tprotected handleParse(rawData: Buffer, options: AbstractFileRecordLoaderOptions<'json'>): Record<string, string | undefined> {\n\t\tconst data: unknown = JSON.parse(rawData.toString());\n\t\tif (typeof data !== 'object' || data === null || Array.isArray(data)) {\n\t\t\toptions.logger?.error(`ConfigVariables[${this.loaderType}]: Invalid JSON data from ${options.fileName}`);\n\t\t\treturn {};\n\t\t}\n\t\treturn this.convertObjectToStringRecord(data);\n\t}\n\n\t/**\n\t * Converts an object to a record of strings as env values are always strings.\n\t * @param {object} data The object to convert\n\t * @returns {Record<string, string>} The converted object\n\t */\n\tprivate convertObjectToStringRecord(data: object): Record<string, string> {\n\t\treturn Object.entries(data).reduce<Record<string, string>>((acc, [key, value]) => {\n\t\t\tif (UndefCore.isNotNullish(value)) {\n\t\t\t\tacc[key] = String(value);\n\t\t\t}\n\t\t\treturn acc;\n\t\t}, {});\n\t}\n}\n"],"mappings":"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"}
{"version":3,"file":"index.mjs","names":[],"sources":["../src/AbstractFileRecordLoader.ts","../src/DockerSecretsConfigLoader.ts","../src/DotEnvLoader.ts","../src/FileConfigLoader.ts"],"sourcesContent":["import type {ILoggerLike} from '@avanio/logger-like';\nimport {\n\tapplyStringMap,\n\ttype IConfigLoaderProps,\n\ttype LoaderValue,\n\tMapConfigLoader,\n\ttype OverrideKeyMap,\n\ttype ValidateCallback,\n\tVariableError,\n} from '@avanio/variable-util';\nimport {Err, type IResult, Ok} from '@luolapeikko/result-option';\nimport {ErrorCore, type Loadable} from '@luolapeikko/ts-common';\nimport {type FSWatcher, watch} from 'fs';\nimport {readFile} from 'fs/promises';\n\n/**\n * Options for the AbstractFileRecordLoader.\n * @template FileType Type of the file\n * @since v1.0.0\n */\nexport interface AbstractFileRecordLoaderOptions<FileType extends string> extends IConfigLoaderProps {\n\tfileType: FileType;\n\t/** file name to load */\n\tfileName: string;\n\t/** set to false if need errors */\n\tisSilent: boolean;\n\t/** optional logger */\n\tlogger: ILoggerLike | undefined;\n\t/** set to true to watch file for changes */\n\twatch: boolean;\n\t/** set to true to disable loader */\n\tdisabled: boolean;\n\t/**\n\t * optional validator for data (Record<string, string | undefined>)\n\t * @example\n\t * // using zod\n\t * const stringRecordSchema = z.record(z.string().min(1), z.string());\n\t * const validate: ValidateCallback<Record<string, string>> = async (data) => {\n\t * const result = await stringRecordSchema.safeParseAsync(data);\n\t * if (!result.success) {\n\t * return {success: false, message: result.error.message};\n\t * }\n\t * return {success: true};\n\t * };\n\t */\n\tvalidate: ValidateCallback<Record<string, string | undefined>, Record<string, string | undefined>> | undefined;\n}\n\n/**\n * Abstract class for loading records from a file.\n * @template Options Options for the loader\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport abstract class AbstractFileRecordLoader<\n\tOptions extends AbstractFileRecordLoaderOptions<string> = AbstractFileRecordLoaderOptions<string>,\n\tOverrideMap extends OverrideKeyMap = OverrideKeyMap,\n> extends MapConfigLoader<Options, OverrideMap> {\n\tpublic abstract readonly loaderType: Lowercase<string>;\n\tprotected abstract defaultOptions: Options;\n\tprivate watcher: FSWatcher | undefined;\n\tprivate timeout: ReturnType<typeof setTimeout> | undefined;\n\n\tpublic constructor(options: Loadable<Partial<Options>>, overrideKeys?: Partial<OverrideMap>) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.handleFileChange = this.handleFileChange.bind(this);\n\t}\n\n\t/**\n\t * If the loader is watching the file, it will stop watching.\n\t */\n\tpublic async close(): Promise<void> {\n\t\tif (this.watcher) {\n\t\t\tconst {logger, fileName} = await this.getOptions();\n\t\t\tlogger?.debug(this.buildErrorStr(`closing file watcher for ${fileName}`));\n\t\t\tthis.watcher.close();\n\t\t}\n\t}\n\n\tprotected async handleLoaderValue(lookupKey: string): Promise<LoaderValue> {\n\t\tconst {fileName} = await this.getOptions();\n\t\tif (!this._isLoaded) {\n\t\t\tawait this.loadData();\n\t\t\tthis._isLoaded = true; // only load data once to prevent spamming\n\t\t}\n\t\tconst value = this.data.get(lookupKey);\n\t\treturn {path: fileName, value};\n\t}\n\n\tprotected async handleData(): Promise<IResult<Record<string, string | undefined>, VariableError>> {\n\t\tconst options = await this.getOptions();\n\t\toptions.logger?.debug(this.buildErrorStr(`loading file ${options.fileName}`));\n\t\tlet buffer: Buffer;\n\t\ttry {\n\t\t\tbuffer = await readFile(options.fileName);\n\t\t} catch (cause) {\n\t\t\treturn Err(new VariableError(this.buildErrorStr(ErrorCore.from(cause).message), {cause}));\n\t\t}\n\t\ttry {\n\t\t\tlet data = await this.handleParse(buffer, options);\n\t\t\tif (options.validate) {\n\t\t\t\tdata = await options.validate(data);\n\t\t\t}\n\t\t\tthis.handleFileWatch(options); // add watch after successful load\n\t\t\treturn Ok(data);\n\t\t} catch (cause) {\n\t\t\treturn Err(new VariableError(this.buildErrorStr(`file ${options.fileName} is not a valid ${options.fileType}`), {cause}));\n\t\t}\n\t}\n\n\tprotected async handleLoadData(): Promise<boolean> {\n\t\tconst {logger, isSilent} = await this.getOptions();\n\t\tconst res = (await this.handleData())\n\t\t\t.inspectErr((err) => isSilent && logger?.debug(err))\n\t\t\t.andThen((data) => {\n\t\t\t\tapplyStringMap(data, this.data);\n\t\t\t\treturn Ok();\n\t\t\t});\n\t\tif (res.isErr && !isSilent) {\n\t\t\tres.unwrap();\n\t\t}\n\t\treturn res.isOk;\n\t}\n\n\tprivate handleFileWatch(options: Options): void {\n\t\tif (options.watch && !this.watcher) {\n\t\t\toptions.logger?.debug(this.buildErrorStr(`opening file watcher for ${options.fileName}`));\n\t\t\tthis.watcher = watch(options.fileName, () => {\n\t\t\t\tif (this.timeout) {\n\t\t\t\t\tclearTimeout(this.timeout);\n\t\t\t\t}\n\t\t\t\t// delay to prevent multiple reloads\n\t\t\t\tthis.timeout = setTimeout(() => {\n\t\t\t\t\tvoid this.handleFileChange(options);\n\t\t\t\t}, 200);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async handleFileChange(options: Options): Promise<void> {\n\t\ttry {\n\t\t\toptions.logger?.debug(this.buildErrorStr(`file ${options.fileName} changed`));\n\t\t\tawait this.reload();\n\t\t} catch (err) {\n\t\t\toptions.logger?.error(this.buildErrorStr(`error reloading file ${options.fileName}: ${ErrorCore.from(err).message}`));\n\t\t}\n\t}\n\n\t/**\n\t * Handle the parsing of the file.\n\t */\n\tprotected abstract handleParse(rawData: Buffer, options: Options): Record<string, string | undefined> | Promise<Record<string, string | undefined>>;\n}\n","import type {ILoggerLike} from '@avanio/logger-like';\nimport {ConfigLoader, type LoaderValue, type OverrideKeyMap, VariableLookupError} from '@avanio/variable-util';\nimport type {Loadable} from '@luolapeikko/ts-common';\nimport {existsSync} from 'fs';\nimport {readFile} from 'fs/promises';\nimport * as path from 'path';\n\n/**\n * DockerSecretsConfigLoaderOptions is the interface for DockerSecretsConfigLoader options\n * @category Loaders\n * @since v1.0.0\n * @template OverrideMap - the type of the override key map\n */\nexport interface DockerSecretsConfigLoaderOptions {\n\t/** force file name to lower case */\n\tfileLowerCase: boolean;\n\t/** path to docker secrets, default is '/run/secrets' */\n\tpath: string;\n\t/** set to false if need errors */\n\tisSilent: boolean;\n\t/** optional logger */\n\tlogger: ILoggerLike | undefined;\n\t/** set to true to disable loader, default is false */\n\tdisabled: boolean;\n}\n\n/**\n * Loader for docker secrets, reads secrets from the `/run/secrets` directory.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class DockerSecretsConfigLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends ConfigLoader<\n\tDockerSecretsConfigLoaderOptions,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\tprivate valuePromises = new Map<string, Promise<string | undefined>>();\n\tprotected defaultOptions: DockerSecretsConfigLoaderOptions = {\n\t\tdisabled: false,\n\t\tfileLowerCase: false,\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tpath: '/run/secrets',\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<DockerSecretsConfigLoaderOptions>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\tloaderType: Lowercase<string> = 'docker-secrets',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = loaderType;\n\t}\n\n\tprotected async handleLoaderValue(lookupKey: string): Promise<LoaderValue> {\n\t\tconst options = await this.getOptions();\n\t\tconst filePath = this.filePath(lookupKey, options);\n\t\tlet valuePromise = this.valuePromises.get(lookupKey) ?? Promise.resolve(undefined);\n\t\tconst seen = this.valuePromises.has(lookupKey); // if valuePromise exists, it means we have seen this key before\n\t\tif (!seen) {\n\t\t\tif (!existsSync(filePath)) {\n\t\t\t\tif (!options.isSilent) {\n\t\t\t\t\tthrow new VariableLookupError(lookupKey, `ConfigVariables[${this.loaderType}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t\t}\n\t\t\t\toptions.logger?.debug(`ConfigVariables[${this.loaderType}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t} else {\n\t\t\t\tvaluePromise = readFile(filePath, 'utf8');\n\t\t\t}\n\t\t\t// store value promise as haven't seen this key before\n\t\t\tthis.valuePromises.set(lookupKey, valuePromise);\n\t\t}\n\t\treturn {path: filePath, value: await valuePromise};\n\t}\n\n\tprivate filePath(key: string, options: DockerSecretsConfigLoaderOptions): string {\n\t\treturn path.join(path.resolve(options.path), options.fileLowerCase ? key.toLowerCase() : key);\n\t}\n}\n","import type {OverrideKeyMap} from '@avanio/variable-util';\nimport type {Loadable} from '@luolapeikko/ts-common';\nimport {parse} from 'dotenv';\nimport {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\n\n/**\n * Loader for dotenv files, using the `dotenv` packages parser.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class DotEnvLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends AbstractFileRecordLoader<\n\tAbstractFileRecordLoaderOptions<string>,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\n\tprotected defaultOptions: AbstractFileRecordLoaderOptions<'env'> = {\n\t\tdisabled: false,\n\t\tfileName: '.env',\n\t\tfileType: 'env',\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tvalidate: undefined,\n\t\twatch: false,\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<AbstractFileRecordLoaderOptions<'env'>>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\ttype: Lowercase<string> = 'dotenv',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = type;\n\t}\n\n\tprotected handleParse(rawData: Buffer): Record<string, string | undefined> {\n\t\treturn parse(rawData);\n\t}\n}\n","import type {OverrideKeyMap} from '@avanio/variable-util';\nimport {type Loadable, UndefCore} from '@luolapeikko/ts-common';\nimport {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\n\n/**\n * A file-based configuration loader that reads a JSON file.\n * @template OverrideMap Type of the override keys\n * @since v1.0.0\n */\nexport class FileConfigLoader<OverrideMap extends OverrideKeyMap = OverrideKeyMap> extends AbstractFileRecordLoader<\n\tAbstractFileRecordLoaderOptions<'json'>,\n\tOverrideMap\n> {\n\tpublic readonly loaderType: Lowercase<string>;\n\n\tprotected defaultOptions: AbstractFileRecordLoaderOptions<'json'> = {\n\t\tdisabled: false,\n\t\tfileName: 'config.json',\n\t\tfileType: 'json',\n\t\tisSilent: true,\n\t\tlogger: undefined,\n\t\tvalidate: undefined,\n\t\twatch: false,\n\t};\n\n\tpublic constructor(\n\t\toptions: Loadable<Partial<AbstractFileRecordLoaderOptions<'json'>>>,\n\t\toverrideKeys?: Partial<OverrideMap>,\n\t\ttype: Lowercase<string> = 'file',\n\t) {\n\t\tsuper(options, overrideKeys);\n\t\tthis.loaderType = type;\n\t}\n\n\tprotected handleParse(rawData: Buffer, options: AbstractFileRecordLoaderOptions<'json'>): Record<string, string | undefined> {\n\t\tconst data: unknown = JSON.parse(rawData.toString());\n\t\tif (typeof data !== 'object' || data === null || Array.isArray(data)) {\n\t\t\toptions.logger?.error(`ConfigVariables[${this.loaderType}]: Invalid JSON data from ${options.fileName}`);\n\t\t\treturn {};\n\t\t}\n\t\treturn this.convertObjectToStringRecord(data);\n\t}\n\n\t/**\n\t * Converts an object to a record of strings as env values are always strings.\n\t * @param {object} data The object to convert\n\t * @returns {Record<string, string>} The converted object\n\t */\n\tprivate convertObjectToStringRecord(data: object): Record<string, string> {\n\t\treturn Object.entries(data).reduce<Record<string, string>>((acc, [key, value]) => {\n\t\t\tif (UndefCore.isNotNullish(value)) {\n\t\t\t\tacc[key] = String(value);\n\t\t\t}\n\t\t\treturn acc;\n\t\t}, {});\n\t}\n}\n"],"mappings":"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"}
{
"name": "@avanio/variable-util-node",
"version": "1.3.1",
"version": "1.3.2",
"description": "nodejs env util",

@@ -5,0 +5,0 @@ "main": "./dist/index.cjs",