@avanio/variable-util-node
Advanced tools
+109
| import { ConfigLoader, Loadable, LoaderValue, IConfigLoaderProps, ValidateCallback, RecordConfigLoader } from '@avanio/variable-util'; | ||
| import { ILoggerLike } from '@avanio/logger-like'; | ||
| interface DockerSecretsConfigLoaderOptions { | ||
| /** force file name to lower case */ | ||
| fileLowerCase: boolean; | ||
| /** path to docker secrets, default is '/run/secrets' */ | ||
| path: string; | ||
| /** set to false if need errors */ | ||
| isSilent: boolean; | ||
| /** optional logger */ | ||
| logger: ILoggerLike | undefined; | ||
| /** set to true to disable loader, default is false */ | ||
| disabled: boolean; | ||
| } | ||
| /** | ||
| * Loader for docker secrets, reads secrets from the `/run/secrets` directory. | ||
| * @since v0.8.0 | ||
| */ | ||
| declare class DockerSecretsConfigLoader extends ConfigLoader<string | undefined, Partial<DockerSecretsConfigLoaderOptions>, DockerSecretsConfigLoaderOptions> { | ||
| readonly type: Lowercase<string>; | ||
| private valuePromises; | ||
| protected defaultOptions: DockerSecretsConfigLoaderOptions; | ||
| constructor(options: Loadable<Partial<DockerSecretsConfigLoaderOptions>>, type?: Lowercase<string>); | ||
| protected handleLoader(lookupKey: string, overrideKey?: string): Promise<LoaderValue>; | ||
| private filePath; | ||
| } | ||
| /** | ||
| * Options for the AbstractFileRecordLoader. | ||
| * @since v0.8.0 | ||
| */ | ||
| interface AbstractFileRecordLoaderOptions<FileType extends string> extends IConfigLoaderProps { | ||
| fileType: FileType; | ||
| /** file name to load */ | ||
| fileName: string; | ||
| /** set to false if need errors */ | ||
| isSilent: boolean; | ||
| /** optional logger */ | ||
| logger: ILoggerLike | undefined; | ||
| /** set to true to watch file for changes */ | ||
| watch: boolean; | ||
| /** set to true to disable loader */ | ||
| disabled: boolean; | ||
| /** | ||
| * optional validator for data (Record<string, string | undefined>) | ||
| * | ||
| * @example | ||
| * // using zod | ||
| * const stringRecordSchema = z.record(z.string().min(1), z.string()); | ||
| * const validate: ValidateCallback<Record<string, string>> = async (data) => { | ||
| * const result = await stringRecordSchema.safeParseAsync(data); | ||
| * if (!result.success) { | ||
| * return {success: false, message: result.error.message}; | ||
| * } | ||
| * return {success: true}; | ||
| * }; | ||
| */ | ||
| validate: ValidateCallback<Record<string, string | undefined>, Record<string, string | undefined>> | undefined; | ||
| } | ||
| /** | ||
| * Abstract class for loading records from a file. | ||
| * @since v0.8.0 | ||
| */ | ||
| declare abstract class AbstractFileRecordLoader<Options extends AbstractFileRecordLoaderOptions<string> = AbstractFileRecordLoaderOptions<string>> extends RecordConfigLoader<string | undefined, Partial<Options>, Options> { | ||
| abstract readonly type: Lowercase<string>; | ||
| private watcher; | ||
| private timeout; | ||
| protected abstract defaultOptions: Options; | ||
| constructor(options: Loadable<Partial<Options>>); | ||
| /** | ||
| * If the loader is watching the file, it will stop watching. | ||
| */ | ||
| close(): Promise<void>; | ||
| protected handleLoader(rootKey: string, key?: string): Promise<LoaderValue>; | ||
| protected handleData(): Promise<Record<string, string | undefined>>; | ||
| /** | ||
| * Handle the parsing of the file. | ||
| */ | ||
| protected abstract handleParse(rawData: Buffer, options: Options): Record<string, string | undefined> | Promise<Record<string, string | undefined>>; | ||
| private handleFileWatch; | ||
| private handleFileChange; | ||
| } | ||
| /** | ||
| * A file-based configuration loader that reads a JSON file. | ||
| * @since v0.9.1 | ||
| */ | ||
| declare class FileConfigLoader extends AbstractFileRecordLoader<AbstractFileRecordLoaderOptions<'json'>> { | ||
| readonly type: Lowercase<string>; | ||
| constructor(options: Loadable<Partial<AbstractFileRecordLoaderOptions<'json'>>>, type?: Lowercase<string>); | ||
| protected defaultOptions: AbstractFileRecordLoaderOptions<'json'>; | ||
| protected handleParse(rawData: Buffer): Record<string, string | undefined>; | ||
| } | ||
| /** | ||
| * Loader for dotenv files, using the `dotenv` packages parser. | ||
| * @since v0.6.1 | ||
| */ | ||
| declare class DotEnvLoader extends AbstractFileRecordLoader { | ||
| readonly type: Lowercase<string>; | ||
| constructor(options: Loadable<Partial<AbstractFileRecordLoaderOptions<'env'>>>, type?: Lowercase<string>); | ||
| protected defaultOptions: AbstractFileRecordLoaderOptions<'env'>; | ||
| protected handleParse(rawData: Buffer): Record<string, string | undefined>; | ||
| } | ||
| declare function getError(error: unknown): Error; | ||
| export { AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions, DockerSecretsConfigLoader, type DockerSecretsConfigLoaderOptions, DotEnvLoader, FileConfigLoader, getError }; |
| {"version":3,"sources":["../src/index.ts","../src/DockerSecretsConfigLoader.ts","../src/AbstractFileRecordLoader.ts","../src/errorUtil.ts","../src/FileConfigLoader.ts","../src/DotEnvLoader.ts"],"sourcesContent":["export * from './DockerSecretsConfigLoader';\nexport * from './FileConfigLoader';\nexport * from './DotEnvLoader';\nexport * from './AbstractFileRecordLoader';\nexport * from './errorUtil';\n","import * as path from 'path';\nimport {ConfigLoader, type Loadable, type LoaderValue, VariableLookupError} from '@avanio/variable-util';\nimport {existsSync} from 'fs';\nimport type {ILoggerLike} from '@avanio/logger-like';\nimport {readFile} from 'fs/promises';\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 * @since v0.8.0\n */\nexport class DockerSecretsConfigLoader extends ConfigLoader<string | undefined, Partial<DockerSecretsConfigLoaderOptions>, DockerSecretsConfigLoaderOptions> {\n\tpublic readonly type: Lowercase<string>;\n\tprivate valuePromises: Record<string, Promise<string | undefined> | 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(options: Loadable<Partial<DockerSecretsConfigLoaderOptions>>, type: Lowercase<string> = 'docker-secrets') {\n\t\tsuper(options);\n\t\tthis.getLoader = this.getLoader.bind(this);\n\t\tthis.type = type;\n\t}\n\n\tprotected async handleLoader(lookupKey: string, overrideKey?: string): Promise<LoaderValue> {\n\t\tconst options = await this.getOptions();\n\t\tif (options.disabled) {\n\t\t\treturn {type: this.type, result: undefined};\n\t\t}\n\t\tconst targetKey = overrideKey || lookupKey;\n\t\tconst filePath = this.filePath(targetKey, options);\n\t\tconst valuePromise = this.valuePromises[targetKey];\n\t\tconst seen = !!valuePromise; // if valuePromise exists, it means we have seen this key before\n\t\tif (!valuePromise) {\n\t\t\tif (!existsSync(filePath)) {\n\t\t\t\tif (!options.isSilent) {\n\t\t\t\t\tthrow new VariableLookupError(targetKey, `ConfigVariables[${this.type}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t\t}\n\t\t\t\toptions.logger?.debug(`ConfigVariables[${this.type}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t\tthis.valuePromises[targetKey] = Promise.resolve(undefined);\n\t\t\t} else {\n\t\t\t\tthis.valuePromises[targetKey] = readFile(filePath, 'utf8');\n\t\t\t}\n\t\t}\n\t\tconst value = await this.valuePromises[targetKey];\n\t\treturn {type: this.type, result: {path: filePath, value, seen}};\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 {existsSync, type FSWatcher, watch} from 'fs';\nimport {type IConfigLoaderProps, type Loadable, type LoaderValue, RecordConfigLoader, type ValidateCallback, VariableError} from '@avanio/variable-util';\nimport {getError} from './errorUtil';\nimport type {ILoggerLike} from '@avanio/logger-like';\nimport {readFile} from 'fs/promises';\n\n/**\n * Options for the AbstractFileRecordLoader.\n * @since v0.8.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 *\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 * @since v0.8.0\n */\nexport abstract class AbstractFileRecordLoader<\n\tOptions extends AbstractFileRecordLoaderOptions<string> = AbstractFileRecordLoaderOptions<string>,\n> extends RecordConfigLoader<string | undefined, Partial<Options>, Options> {\n\tabstract readonly type: Lowercase<string>;\n\tprivate watcher: FSWatcher | undefined;\n\tprivate timeout: ReturnType<typeof setTimeout> | undefined;\n\n\tprotected abstract defaultOptions: Options;\n\n\tpublic constructor(options: Loadable<Partial<Options>>) {\n\t\tsuper(options);\n\t\tthis.getLoader = this.getLoader.bind(this);\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 handleLoader(rootKey: string, key?: string): Promise<LoaderValue> {\n\t\tconst {disabled, fileName} = await this.getOptions();\n\t\tif (disabled) {\n\t\t\treturn {type: this.type, result: undefined};\n\t\t}\n\t\tif (!this.dataPromise) {\n\t\t\tthis.dataPromise = this.handleData();\n\t\t}\n\t\tconst data = await this.dataPromise;\n\t\tconst targetKey = key || rootKey;\n\t\tconst currentValue = data[targetKey];\n\t\treturn {type: this.type, result: {value: currentValue, path: fileName, seen: this.handleSeen(targetKey, currentValue)}};\n\t}\n\n\tprotected async handleData(): Promise<Record<string, string | undefined>> {\n\t\tconst options = await this.getOptions();\n\t\toptions.logger?.debug(this.buildErrorStr(`loading file ${options.fileName}`));\n\t\t// if file is disabled, return empty object\n\t\tif (options.disabled) {\n\t\t\treturn {};\n\t\t}\n\t\tif (!existsSync(options.fileName)) {\n\t\t\tconst msg = this.buildErrorStr(`file ${options.fileName} not found`);\n\t\t\tif (options.isSilent) {\n\t\t\t\toptions.logger?.debug(msg);\n\t\t\t\treturn {};\n\t\t\t}\n\t\t\tthrow new VariableError(msg);\n\t\t}\n\t\ttry {\n\t\t\tconst data = await this.handleParse(await readFile(options.fileName), options);\n\t\t\tif (options.validate) {\n\t\t\t\treturn await options.validate(data);\n\t\t\t}\n\t\t\tthis.handleFileWatch(options); // add watch after successful load\n\t\t\treturn data;\n\t\t} catch (_err) {\n\t\t\tconst msg = this.buildErrorStr(`file ${options.fileName} is not a valid ${options.fileType}`);\n\t\t\tif (options.isSilent) {\n\t\t\t\toptions.logger?.info(msg);\n\t\t\t\treturn {};\n\t\t\t}\n\t\t\tthrow new VariableError(msg);\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\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}: ${getError(err).message}`));\n\t\t}\n\t}\n}\n","export function getError(error: unknown): Error {\n\tif (error instanceof Error) {\n\t\treturn error;\n\t}\n\tif (typeof error === 'string') {\n\t\treturn new Error(error);\n\t}\n\treturn new Error(`Unknown error: ${JSON.stringify(error)}`);\n}\n","import {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\nimport {type Loadable} from '@avanio/variable-util';\n\n/**\n * A file-based configuration loader that reads a JSON file.\n * @since v0.9.1\n */\nexport class FileConfigLoader extends AbstractFileRecordLoader<AbstractFileRecordLoaderOptions<'json'>> {\n\tpublic readonly type: Lowercase<string>;\n\n\tpublic constructor(options: Loadable<Partial<AbstractFileRecordLoaderOptions<'json'>>>, type: Lowercase<string> = 'file') {\n\t\tsuper(options);\n\t\tthis.type = type;\n\t}\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\tprotected handleParse(rawData: Buffer): Record<string, string | undefined> {\n\t\treturn JSON.parse(rawData.toString()) as Record<string, string | undefined>;\n\t}\n}\n","import {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\nimport {type Loadable} from '@avanio/variable-util';\nimport {parse} from 'dotenv';\n\n/**\n * Loader for dotenv files, using the `dotenv` packages parser.\n * @since v0.6.1\n */\nexport class DotEnvLoader extends AbstractFileRecordLoader {\n\tpublic readonly type: Lowercase<string>;\n\n\tpublic constructor(options: Loadable<Partial<AbstractFileRecordLoaderOptions<'env'>>>, type: Lowercase<string> = 'dotenv') {\n\t\tsuper(options);\n\t\tthis.type = type;\n\t}\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\tprotected handleParse(rawData: Buffer): Record<string, string | undefined> {\n\t\treturn parse(rawData);\n\t}\n}\n"],"mappings":"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","names":["import_fs","import_variable_util","import_promises"]} |
+199
| // src/DockerSecretsConfigLoader.ts | ||
| import * as path from "path"; | ||
| import { ConfigLoader, VariableLookupError } from "@avanio/variable-util"; | ||
| import { existsSync } from "fs"; | ||
| import { readFile } from "fs/promises"; | ||
| var DockerSecretsConfigLoader = class extends ConfigLoader { | ||
| type; | ||
| valuePromises = {}; | ||
| defaultOptions = { | ||
| disabled: false, | ||
| fileLowerCase: false, | ||
| isSilent: true, | ||
| logger: void 0, | ||
| path: "/run/secrets" | ||
| }; | ||
| constructor(options, type = "docker-secrets") { | ||
| super(options); | ||
| this.getLoader = this.getLoader.bind(this); | ||
| this.type = type; | ||
| } | ||
| async handleLoader(lookupKey, overrideKey) { | ||
| const options = await this.getOptions(); | ||
| if (options.disabled) { | ||
| return { type: this.type, result: void 0 }; | ||
| } | ||
| const targetKey = overrideKey || lookupKey; | ||
| const filePath = this.filePath(targetKey, options); | ||
| const valuePromise = this.valuePromises[targetKey]; | ||
| const seen = !!valuePromise; | ||
| if (!valuePromise) { | ||
| if (!existsSync(filePath)) { | ||
| if (!options.isSilent) { | ||
| throw new VariableLookupError(targetKey, `ConfigVariables[${this.type}]: ${lookupKey} from ${filePath} not found`); | ||
| } | ||
| options.logger?.debug(`ConfigVariables[${this.type}]: ${lookupKey} from ${filePath} not found`); | ||
| this.valuePromises[targetKey] = Promise.resolve(void 0); | ||
| } else { | ||
| this.valuePromises[targetKey] = readFile(filePath, "utf8"); | ||
| } | ||
| } | ||
| const value = await this.valuePromises[targetKey]; | ||
| return { type: this.type, result: { path: filePath, value, seen } }; | ||
| } | ||
| filePath(key, options) { | ||
| return path.join(path.resolve(options.path), options.fileLowerCase ? key.toLowerCase() : key); | ||
| } | ||
| }; | ||
| // src/AbstractFileRecordLoader.ts | ||
| import { existsSync as existsSync2, watch } from "fs"; | ||
| import { RecordConfigLoader, VariableError } from "@avanio/variable-util"; | ||
| // src/errorUtil.ts | ||
| function getError(error) { | ||
| if (error instanceof Error) { | ||
| return error; | ||
| } | ||
| if (typeof error === "string") { | ||
| return new Error(error); | ||
| } | ||
| return new Error(`Unknown error: ${JSON.stringify(error)}`); | ||
| } | ||
| // src/AbstractFileRecordLoader.ts | ||
| import { readFile as readFile2 } from "fs/promises"; | ||
| var AbstractFileRecordLoader = class extends RecordConfigLoader { | ||
| watcher; | ||
| timeout; | ||
| constructor(options) { | ||
| super(options); | ||
| this.getLoader = this.getLoader.bind(this); | ||
| this.handleFileChange = this.handleFileChange.bind(this); | ||
| } | ||
| /** | ||
| * If the loader is watching the file, it will stop watching. | ||
| */ | ||
| async close() { | ||
| if (this.watcher) { | ||
| const { logger, fileName } = await this.getOptions(); | ||
| logger?.debug(this.buildErrorStr(`closing file watcher for ${fileName}`)); | ||
| this.watcher.close(); | ||
| } | ||
| } | ||
| async handleLoader(rootKey, key) { | ||
| const { disabled, fileName } = await this.getOptions(); | ||
| if (disabled) { | ||
| return { type: this.type, result: void 0 }; | ||
| } | ||
| if (!this.dataPromise) { | ||
| this.dataPromise = this.handleData(); | ||
| } | ||
| const data = await this.dataPromise; | ||
| const targetKey = key || rootKey; | ||
| const currentValue = data[targetKey]; | ||
| return { type: this.type, result: { value: currentValue, path: fileName, seen: this.handleSeen(targetKey, currentValue) } }; | ||
| } | ||
| async handleData() { | ||
| const options = await this.getOptions(); | ||
| options.logger?.debug(this.buildErrorStr(`loading file ${options.fileName}`)); | ||
| if (options.disabled) { | ||
| return {}; | ||
| } | ||
| if (!existsSync2(options.fileName)) { | ||
| const msg = this.buildErrorStr(`file ${options.fileName} not found`); | ||
| if (options.isSilent) { | ||
| options.logger?.debug(msg); | ||
| return {}; | ||
| } | ||
| throw new VariableError(msg); | ||
| } | ||
| try { | ||
| const data = await this.handleParse(await readFile2(options.fileName), options); | ||
| if (options.validate) { | ||
| return await options.validate(data); | ||
| } | ||
| this.handleFileWatch(options); | ||
| return data; | ||
| } catch (_err) { | ||
| const msg = this.buildErrorStr(`file ${options.fileName} is not a valid ${options.fileType}`); | ||
| if (options.isSilent) { | ||
| options.logger?.info(msg); | ||
| return {}; | ||
| } | ||
| throw new VariableError(msg); | ||
| } | ||
| } | ||
| handleFileWatch(options) { | ||
| if (options.watch && !this.watcher) { | ||
| options.logger?.debug(this.buildErrorStr(`opening file watcher for ${options.fileName}`)); | ||
| this.watcher = watch(options.fileName, () => { | ||
| if (this.timeout) { | ||
| clearTimeout(this.timeout); | ||
| } | ||
| this.timeout = setTimeout(() => { | ||
| void this.handleFileChange(options); | ||
| }, 200); | ||
| }); | ||
| } | ||
| } | ||
| async handleFileChange(options) { | ||
| try { | ||
| options.logger?.debug(this.buildErrorStr(`file ${options.fileName} changed`)); | ||
| await this.reload(); | ||
| } catch (err) { | ||
| options.logger?.error(this.buildErrorStr(`error reloading file ${options.fileName}: ${getError(err).message}`)); | ||
| } | ||
| } | ||
| }; | ||
| // src/FileConfigLoader.ts | ||
| var FileConfigLoader = class extends AbstractFileRecordLoader { | ||
| type; | ||
| constructor(options, type = "file") { | ||
| super(options); | ||
| this.type = type; | ||
| } | ||
| defaultOptions = { | ||
| disabled: false, | ||
| fileName: "config.json", | ||
| fileType: "json", | ||
| isSilent: true, | ||
| logger: void 0, | ||
| validate: void 0, | ||
| watch: false | ||
| }; | ||
| handleParse(rawData) { | ||
| return JSON.parse(rawData.toString()); | ||
| } | ||
| }; | ||
| // src/DotEnvLoader.ts | ||
| import { parse } from "dotenv"; | ||
| var DotEnvLoader = class extends AbstractFileRecordLoader { | ||
| type; | ||
| constructor(options, type = "dotenv") { | ||
| super(options); | ||
| this.type = type; | ||
| } | ||
| defaultOptions = { | ||
| disabled: false, | ||
| fileName: ".env", | ||
| fileType: "env", | ||
| isSilent: true, | ||
| logger: void 0, | ||
| validate: void 0, | ||
| watch: false | ||
| }; | ||
| handleParse(rawData) { | ||
| return parse(rawData); | ||
| } | ||
| }; | ||
| export { | ||
| AbstractFileRecordLoader, | ||
| DockerSecretsConfigLoader, | ||
| DotEnvLoader, | ||
| FileConfigLoader, | ||
| getError | ||
| }; | ||
| //# sourceMappingURL=index.mjs.map |
| {"version":3,"sources":["../src/DockerSecretsConfigLoader.ts","../src/AbstractFileRecordLoader.ts","../src/errorUtil.ts","../src/FileConfigLoader.ts","../src/DotEnvLoader.ts"],"sourcesContent":["import * as path from 'path';\nimport {ConfigLoader, type Loadable, type LoaderValue, VariableLookupError} from '@avanio/variable-util';\nimport {existsSync} from 'fs';\nimport type {ILoggerLike} from '@avanio/logger-like';\nimport {readFile} from 'fs/promises';\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 * @since v0.8.0\n */\nexport class DockerSecretsConfigLoader extends ConfigLoader<string | undefined, Partial<DockerSecretsConfigLoaderOptions>, DockerSecretsConfigLoaderOptions> {\n\tpublic readonly type: Lowercase<string>;\n\tprivate valuePromises: Record<string, Promise<string | undefined> | 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(options: Loadable<Partial<DockerSecretsConfigLoaderOptions>>, type: Lowercase<string> = 'docker-secrets') {\n\t\tsuper(options);\n\t\tthis.getLoader = this.getLoader.bind(this);\n\t\tthis.type = type;\n\t}\n\n\tprotected async handleLoader(lookupKey: string, overrideKey?: string): Promise<LoaderValue> {\n\t\tconst options = await this.getOptions();\n\t\tif (options.disabled) {\n\t\t\treturn {type: this.type, result: undefined};\n\t\t}\n\t\tconst targetKey = overrideKey || lookupKey;\n\t\tconst filePath = this.filePath(targetKey, options);\n\t\tconst valuePromise = this.valuePromises[targetKey];\n\t\tconst seen = !!valuePromise; // if valuePromise exists, it means we have seen this key before\n\t\tif (!valuePromise) {\n\t\t\tif (!existsSync(filePath)) {\n\t\t\t\tif (!options.isSilent) {\n\t\t\t\t\tthrow new VariableLookupError(targetKey, `ConfigVariables[${this.type}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t\t}\n\t\t\t\toptions.logger?.debug(`ConfigVariables[${this.type}]: ${lookupKey} from ${filePath} not found`);\n\t\t\t\tthis.valuePromises[targetKey] = Promise.resolve(undefined);\n\t\t\t} else {\n\t\t\t\tthis.valuePromises[targetKey] = readFile(filePath, 'utf8');\n\t\t\t}\n\t\t}\n\t\tconst value = await this.valuePromises[targetKey];\n\t\treturn {type: this.type, result: {path: filePath, value, seen}};\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 {existsSync, type FSWatcher, watch} from 'fs';\nimport {type IConfigLoaderProps, type Loadable, type LoaderValue, RecordConfigLoader, type ValidateCallback, VariableError} from '@avanio/variable-util';\nimport {getError} from './errorUtil';\nimport type {ILoggerLike} from '@avanio/logger-like';\nimport {readFile} from 'fs/promises';\n\n/**\n * Options for the AbstractFileRecordLoader.\n * @since v0.8.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 *\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 * @since v0.8.0\n */\nexport abstract class AbstractFileRecordLoader<\n\tOptions extends AbstractFileRecordLoaderOptions<string> = AbstractFileRecordLoaderOptions<string>,\n> extends RecordConfigLoader<string | undefined, Partial<Options>, Options> {\n\tabstract readonly type: Lowercase<string>;\n\tprivate watcher: FSWatcher | undefined;\n\tprivate timeout: ReturnType<typeof setTimeout> | undefined;\n\n\tprotected abstract defaultOptions: Options;\n\n\tpublic constructor(options: Loadable<Partial<Options>>) {\n\t\tsuper(options);\n\t\tthis.getLoader = this.getLoader.bind(this);\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 handleLoader(rootKey: string, key?: string): Promise<LoaderValue> {\n\t\tconst {disabled, fileName} = await this.getOptions();\n\t\tif (disabled) {\n\t\t\treturn {type: this.type, result: undefined};\n\t\t}\n\t\tif (!this.dataPromise) {\n\t\t\tthis.dataPromise = this.handleData();\n\t\t}\n\t\tconst data = await this.dataPromise;\n\t\tconst targetKey = key || rootKey;\n\t\tconst currentValue = data[targetKey];\n\t\treturn {type: this.type, result: {value: currentValue, path: fileName, seen: this.handleSeen(targetKey, currentValue)}};\n\t}\n\n\tprotected async handleData(): Promise<Record<string, string | undefined>> {\n\t\tconst options = await this.getOptions();\n\t\toptions.logger?.debug(this.buildErrorStr(`loading file ${options.fileName}`));\n\t\t// if file is disabled, return empty object\n\t\tif (options.disabled) {\n\t\t\treturn {};\n\t\t}\n\t\tif (!existsSync(options.fileName)) {\n\t\t\tconst msg = this.buildErrorStr(`file ${options.fileName} not found`);\n\t\t\tif (options.isSilent) {\n\t\t\t\toptions.logger?.debug(msg);\n\t\t\t\treturn {};\n\t\t\t}\n\t\t\tthrow new VariableError(msg);\n\t\t}\n\t\ttry {\n\t\t\tconst data = await this.handleParse(await readFile(options.fileName), options);\n\t\t\tif (options.validate) {\n\t\t\t\treturn await options.validate(data);\n\t\t\t}\n\t\t\tthis.handleFileWatch(options); // add watch after successful load\n\t\t\treturn data;\n\t\t} catch (_err) {\n\t\t\tconst msg = this.buildErrorStr(`file ${options.fileName} is not a valid ${options.fileType}`);\n\t\t\tif (options.isSilent) {\n\t\t\t\toptions.logger?.info(msg);\n\t\t\t\treturn {};\n\t\t\t}\n\t\t\tthrow new VariableError(msg);\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\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}: ${getError(err).message}`));\n\t\t}\n\t}\n}\n","export function getError(error: unknown): Error {\n\tif (error instanceof Error) {\n\t\treturn error;\n\t}\n\tif (typeof error === 'string') {\n\t\treturn new Error(error);\n\t}\n\treturn new Error(`Unknown error: ${JSON.stringify(error)}`);\n}\n","import {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\nimport {type Loadable} from '@avanio/variable-util';\n\n/**\n * A file-based configuration loader that reads a JSON file.\n * @since v0.9.1\n */\nexport class FileConfigLoader extends AbstractFileRecordLoader<AbstractFileRecordLoaderOptions<'json'>> {\n\tpublic readonly type: Lowercase<string>;\n\n\tpublic constructor(options: Loadable<Partial<AbstractFileRecordLoaderOptions<'json'>>>, type: Lowercase<string> = 'file') {\n\t\tsuper(options);\n\t\tthis.type = type;\n\t}\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\tprotected handleParse(rawData: Buffer): Record<string, string | undefined> {\n\t\treturn JSON.parse(rawData.toString()) as Record<string, string | undefined>;\n\t}\n}\n","import {AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions} from './AbstractFileRecordLoader';\nimport {type Loadable} from '@avanio/variable-util';\nimport {parse} from 'dotenv';\n\n/**\n * Loader for dotenv files, using the `dotenv` packages parser.\n * @since v0.6.1\n */\nexport class DotEnvLoader extends AbstractFileRecordLoader {\n\tpublic readonly type: Lowercase<string>;\n\n\tpublic constructor(options: Loadable<Partial<AbstractFileRecordLoaderOptions<'env'>>>, type: Lowercase<string> = 'dotenv') {\n\t\tsuper(options);\n\t\tthis.type = type;\n\t}\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\tprotected handleParse(rawData: Buffer): Record<string, string | undefined> {\n\t\treturn parse(rawData);\n\t}\n}\n"],"mappings":"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","names":["existsSync","readFile","existsSync"]} |
+109
-5
@@ -1,5 +0,109 @@ | ||
| export * from './DockerSecretsConfigLoader'; | ||
| export * from './FileConfigLoader'; | ||
| export * from './DotEnvLoader'; | ||
| export * from './AbstractFileRecordLoader'; | ||
| export * from './errorUtil'; | ||
| import { ConfigLoader, Loadable, LoaderValue, IConfigLoaderProps, ValidateCallback, RecordConfigLoader } from '@avanio/variable-util'; | ||
| import { ILoggerLike } from '@avanio/logger-like'; | ||
| interface DockerSecretsConfigLoaderOptions { | ||
| /** force file name to lower case */ | ||
| fileLowerCase: boolean; | ||
| /** path to docker secrets, default is '/run/secrets' */ | ||
| path: string; | ||
| /** set to false if need errors */ | ||
| isSilent: boolean; | ||
| /** optional logger */ | ||
| logger: ILoggerLike | undefined; | ||
| /** set to true to disable loader, default is false */ | ||
| disabled: boolean; | ||
| } | ||
| /** | ||
| * Loader for docker secrets, reads secrets from the `/run/secrets` directory. | ||
| * @since v0.8.0 | ||
| */ | ||
| declare class DockerSecretsConfigLoader extends ConfigLoader<string | undefined, Partial<DockerSecretsConfigLoaderOptions>, DockerSecretsConfigLoaderOptions> { | ||
| readonly type: Lowercase<string>; | ||
| private valuePromises; | ||
| protected defaultOptions: DockerSecretsConfigLoaderOptions; | ||
| constructor(options: Loadable<Partial<DockerSecretsConfigLoaderOptions>>, type?: Lowercase<string>); | ||
| protected handleLoader(lookupKey: string, overrideKey?: string): Promise<LoaderValue>; | ||
| private filePath; | ||
| } | ||
| /** | ||
| * Options for the AbstractFileRecordLoader. | ||
| * @since v0.8.0 | ||
| */ | ||
| interface AbstractFileRecordLoaderOptions<FileType extends string> extends IConfigLoaderProps { | ||
| fileType: FileType; | ||
| /** file name to load */ | ||
| fileName: string; | ||
| /** set to false if need errors */ | ||
| isSilent: boolean; | ||
| /** optional logger */ | ||
| logger: ILoggerLike | undefined; | ||
| /** set to true to watch file for changes */ | ||
| watch: boolean; | ||
| /** set to true to disable loader */ | ||
| disabled: boolean; | ||
| /** | ||
| * optional validator for data (Record<string, string | undefined>) | ||
| * | ||
| * @example | ||
| * // using zod | ||
| * const stringRecordSchema = z.record(z.string().min(1), z.string()); | ||
| * const validate: ValidateCallback<Record<string, string>> = async (data) => { | ||
| * const result = await stringRecordSchema.safeParseAsync(data); | ||
| * if (!result.success) { | ||
| * return {success: false, message: result.error.message}; | ||
| * } | ||
| * return {success: true}; | ||
| * }; | ||
| */ | ||
| validate: ValidateCallback<Record<string, string | undefined>, Record<string, string | undefined>> | undefined; | ||
| } | ||
| /** | ||
| * Abstract class for loading records from a file. | ||
| * @since v0.8.0 | ||
| */ | ||
| declare abstract class AbstractFileRecordLoader<Options extends AbstractFileRecordLoaderOptions<string> = AbstractFileRecordLoaderOptions<string>> extends RecordConfigLoader<string | undefined, Partial<Options>, Options> { | ||
| abstract readonly type: Lowercase<string>; | ||
| private watcher; | ||
| private timeout; | ||
| protected abstract defaultOptions: Options; | ||
| constructor(options: Loadable<Partial<Options>>); | ||
| /** | ||
| * If the loader is watching the file, it will stop watching. | ||
| */ | ||
| close(): Promise<void>; | ||
| protected handleLoader(rootKey: string, key?: string): Promise<LoaderValue>; | ||
| protected handleData(): Promise<Record<string, string | undefined>>; | ||
| /** | ||
| * Handle the parsing of the file. | ||
| */ | ||
| protected abstract handleParse(rawData: Buffer, options: Options): Record<string, string | undefined> | Promise<Record<string, string | undefined>>; | ||
| private handleFileWatch; | ||
| private handleFileChange; | ||
| } | ||
| /** | ||
| * A file-based configuration loader that reads a JSON file. | ||
| * @since v0.9.1 | ||
| */ | ||
| declare class FileConfigLoader extends AbstractFileRecordLoader<AbstractFileRecordLoaderOptions<'json'>> { | ||
| readonly type: Lowercase<string>; | ||
| constructor(options: Loadable<Partial<AbstractFileRecordLoaderOptions<'json'>>>, type?: Lowercase<string>); | ||
| protected defaultOptions: AbstractFileRecordLoaderOptions<'json'>; | ||
| protected handleParse(rawData: Buffer): Record<string, string | undefined>; | ||
| } | ||
| /** | ||
| * Loader for dotenv files, using the `dotenv` packages parser. | ||
| * @since v0.6.1 | ||
| */ | ||
| declare class DotEnvLoader extends AbstractFileRecordLoader { | ||
| readonly type: Lowercase<string>; | ||
| constructor(options: Loadable<Partial<AbstractFileRecordLoaderOptions<'env'>>>, type?: Lowercase<string>); | ||
| protected defaultOptions: AbstractFileRecordLoaderOptions<'env'>; | ||
| protected handleParse(rawData: Buffer): Record<string, string | undefined>; | ||
| } | ||
| declare function getError(error: unknown): Error; | ||
| export { AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions, DockerSecretsConfigLoader, type DockerSecretsConfigLoaderOptions, DotEnvLoader, FileConfigLoader, getError }; |
+237
-19
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| var desc = Object.getOwnPropertyDescriptor(m, k); | ||
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
| desc = { enumerable: true, get: function() { return m[k]; } }; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| // src/index.ts | ||
| var src_exports = {}; | ||
| __export(src_exports, { | ||
| AbstractFileRecordLoader: () => AbstractFileRecordLoader, | ||
| DockerSecretsConfigLoader: () => DockerSecretsConfigLoader, | ||
| DotEnvLoader: () => DotEnvLoader, | ||
| FileConfigLoader: () => FileConfigLoader, | ||
| getError: () => getError | ||
| }); | ||
| module.exports = __toCommonJS(src_exports); | ||
| // src/DockerSecretsConfigLoader.ts | ||
| var path = __toESM(require("path")); | ||
| var import_variable_util = require("@avanio/variable-util"); | ||
| var import_fs = require("fs"); | ||
| var import_promises = require("fs/promises"); | ||
| var DockerSecretsConfigLoader = class extends import_variable_util.ConfigLoader { | ||
| type; | ||
| valuePromises = {}; | ||
| defaultOptions = { | ||
| disabled: false, | ||
| fileLowerCase: false, | ||
| isSilent: true, | ||
| logger: void 0, | ||
| path: "/run/secrets" | ||
| }; | ||
| constructor(options, type = "docker-secrets") { | ||
| super(options); | ||
| this.getLoader = this.getLoader.bind(this); | ||
| this.type = type; | ||
| } | ||
| async handleLoader(lookupKey, overrideKey) { | ||
| const options = await this.getOptions(); | ||
| if (options.disabled) { | ||
| return { type: this.type, result: void 0 }; | ||
| } | ||
| Object.defineProperty(o, k2, desc); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
| for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
| const targetKey = overrideKey || lookupKey; | ||
| const filePath = this.filePath(targetKey, options); | ||
| const valuePromise = this.valuePromises[targetKey]; | ||
| const seen = !!valuePromise; | ||
| if (!valuePromise) { | ||
| if (!(0, import_fs.existsSync)(filePath)) { | ||
| if (!options.isSilent) { | ||
| throw new import_variable_util.VariableLookupError(targetKey, `ConfigVariables[${this.type}]: ${lookupKey} from ${filePath} not found`); | ||
| } | ||
| options.logger?.debug(`ConfigVariables[${this.type}]: ${lookupKey} from ${filePath} not found`); | ||
| this.valuePromises[targetKey] = Promise.resolve(void 0); | ||
| } else { | ||
| this.valuePromises[targetKey] = (0, import_promises.readFile)(filePath, "utf8"); | ||
| } | ||
| } | ||
| const value = await this.valuePromises[targetKey]; | ||
| return { type: this.type, result: { path: filePath, value, seen } }; | ||
| } | ||
| filePath(key, options) { | ||
| return path.join(path.resolve(options.path), options.fileLowerCase ? key.toLowerCase() : key); | ||
| } | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| __exportStar(require("./DockerSecretsConfigLoader"), exports); | ||
| __exportStar(require("./FileConfigLoader"), exports); | ||
| __exportStar(require("./DotEnvLoader"), exports); | ||
| __exportStar(require("./AbstractFileRecordLoader"), exports); | ||
| __exportStar(require("./errorUtil"), exports); | ||
| //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiLi9zcmMvIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsOERBQTRDO0FBQzVDLHFEQUFtQztBQUNuQyxpREFBK0I7QUFDL0IsNkRBQTJDO0FBQzNDLDhDQUE0QiJ9 | ||
| // src/AbstractFileRecordLoader.ts | ||
| var import_fs2 = require("fs"); | ||
| var import_variable_util2 = require("@avanio/variable-util"); | ||
| // src/errorUtil.ts | ||
| function getError(error) { | ||
| if (error instanceof Error) { | ||
| return error; | ||
| } | ||
| if (typeof error === "string") { | ||
| return new Error(error); | ||
| } | ||
| return new Error(`Unknown error: ${JSON.stringify(error)}`); | ||
| } | ||
| // src/AbstractFileRecordLoader.ts | ||
| var import_promises2 = require("fs/promises"); | ||
| var AbstractFileRecordLoader = class extends import_variable_util2.RecordConfigLoader { | ||
| watcher; | ||
| timeout; | ||
| constructor(options) { | ||
| super(options); | ||
| this.getLoader = this.getLoader.bind(this); | ||
| this.handleFileChange = this.handleFileChange.bind(this); | ||
| } | ||
| /** | ||
| * If the loader is watching the file, it will stop watching. | ||
| */ | ||
| async close() { | ||
| if (this.watcher) { | ||
| const { logger, fileName } = await this.getOptions(); | ||
| logger?.debug(this.buildErrorStr(`closing file watcher for ${fileName}`)); | ||
| this.watcher.close(); | ||
| } | ||
| } | ||
| async handleLoader(rootKey, key) { | ||
| const { disabled, fileName } = await this.getOptions(); | ||
| if (disabled) { | ||
| return { type: this.type, result: void 0 }; | ||
| } | ||
| if (!this.dataPromise) { | ||
| this.dataPromise = this.handleData(); | ||
| } | ||
| const data = await this.dataPromise; | ||
| const targetKey = key || rootKey; | ||
| const currentValue = data[targetKey]; | ||
| return { type: this.type, result: { value: currentValue, path: fileName, seen: this.handleSeen(targetKey, currentValue) } }; | ||
| } | ||
| async handleData() { | ||
| const options = await this.getOptions(); | ||
| options.logger?.debug(this.buildErrorStr(`loading file ${options.fileName}`)); | ||
| if (options.disabled) { | ||
| return {}; | ||
| } | ||
| if (!(0, import_fs2.existsSync)(options.fileName)) { | ||
| const msg = this.buildErrorStr(`file ${options.fileName} not found`); | ||
| if (options.isSilent) { | ||
| options.logger?.debug(msg); | ||
| return {}; | ||
| } | ||
| throw new import_variable_util2.VariableError(msg); | ||
| } | ||
| try { | ||
| const data = await this.handleParse(await (0, import_promises2.readFile)(options.fileName), options); | ||
| if (options.validate) { | ||
| return await options.validate(data); | ||
| } | ||
| this.handleFileWatch(options); | ||
| return data; | ||
| } catch (_err) { | ||
| const msg = this.buildErrorStr(`file ${options.fileName} is not a valid ${options.fileType}`); | ||
| if (options.isSilent) { | ||
| options.logger?.info(msg); | ||
| return {}; | ||
| } | ||
| throw new import_variable_util2.VariableError(msg); | ||
| } | ||
| } | ||
| handleFileWatch(options) { | ||
| if (options.watch && !this.watcher) { | ||
| options.logger?.debug(this.buildErrorStr(`opening file watcher for ${options.fileName}`)); | ||
| this.watcher = (0, import_fs2.watch)(options.fileName, () => { | ||
| if (this.timeout) { | ||
| clearTimeout(this.timeout); | ||
| } | ||
| this.timeout = setTimeout(() => { | ||
| void this.handleFileChange(options); | ||
| }, 200); | ||
| }); | ||
| } | ||
| } | ||
| async handleFileChange(options) { | ||
| try { | ||
| options.logger?.debug(this.buildErrorStr(`file ${options.fileName} changed`)); | ||
| await this.reload(); | ||
| } catch (err) { | ||
| options.logger?.error(this.buildErrorStr(`error reloading file ${options.fileName}: ${getError(err).message}`)); | ||
| } | ||
| } | ||
| }; | ||
| // src/FileConfigLoader.ts | ||
| var FileConfigLoader = class extends AbstractFileRecordLoader { | ||
| type; | ||
| constructor(options, type = "file") { | ||
| super(options); | ||
| this.type = type; | ||
| } | ||
| defaultOptions = { | ||
| disabled: false, | ||
| fileName: "config.json", | ||
| fileType: "json", | ||
| isSilent: true, | ||
| logger: void 0, | ||
| validate: void 0, | ||
| watch: false | ||
| }; | ||
| handleParse(rawData) { | ||
| return JSON.parse(rawData.toString()); | ||
| } | ||
| }; | ||
| // src/DotEnvLoader.ts | ||
| var import_dotenv = require("dotenv"); | ||
| var DotEnvLoader = class extends AbstractFileRecordLoader { | ||
| type; | ||
| constructor(options, type = "dotenv") { | ||
| super(options); | ||
| this.type = type; | ||
| } | ||
| defaultOptions = { | ||
| disabled: false, | ||
| fileName: ".env", | ||
| fileType: "env", | ||
| isSilent: true, | ||
| logger: void 0, | ||
| validate: void 0, | ||
| watch: false | ||
| }; | ||
| handleParse(rawData) { | ||
| return (0, import_dotenv.parse)(rawData); | ||
| } | ||
| }; | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| AbstractFileRecordLoader, | ||
| DockerSecretsConfigLoader, | ||
| DotEnvLoader, | ||
| FileConfigLoader, | ||
| getError | ||
| }); | ||
| //# sourceMappingURL=index.js.map |
+32
-39
| { | ||
| "name": "@avanio/variable-util-node", | ||
| "version": "0.10.0", | ||
| "version": "0.11.0", | ||
| "description": "nodejs env util", | ||
| "main": "./dist/index.js", | ||
| "module": "./dist/index.mjs", | ||
| "types": "./dist/index.d.ts", | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "require": "./dist/index.js", | ||
| "import": "./dist/index.mjs" | ||
| } | ||
| }, | ||
| "private": false, | ||
@@ -10,43 +19,19 @@ "engines": { | ||
| }, | ||
| "scripts": { | ||
| "build": "tsc", | ||
| "prepublishOnly": "npm run validate && npm run test && npm run lint && npm run build", | ||
| "test": "mocha", | ||
| "lint": "eslint . --ext .ts", | ||
| "validate": "tsc --noEmit --project tsconfig.test.json" | ||
| }, | ||
| "files": [ | ||
| "dist" | ||
| ], | ||
| "mocha": { | ||
| "exit": true, | ||
| "extension": [ | ||
| "ts", | ||
| "js" | ||
| ], | ||
| "recursive": true, | ||
| "require": [ | ||
| "ts-node/register", | ||
| "source-map-support/register" | ||
| ], | ||
| "reporters": [ | ||
| "spec", | ||
| "mocha-junit-reporter" | ||
| ] | ||
| }, | ||
| "author": "mharj", | ||
| "license": "MIT", | ||
| "devDependencies": { | ||
| "@avanio/logger-like": "^0.2.5", | ||
| "@avanio/variable-util": "^0.10.0", | ||
| "@stylistic/eslint-plugin": "^2.9.0", | ||
| "@stylistic/eslint-plugin-ts": "^2.9.0", | ||
| "@avanio/logger-like": "^0.2.7", | ||
| "@avanio/variable-util": "^0.11.0", | ||
| "@stylistic/eslint-plugin": "^2.10.1", | ||
| "@stylistic/eslint-plugin-ts": "^2.10.1", | ||
| "@tsconfig/node18": "^18.2.4", | ||
| "@types/chai": "^4.3.20", | ||
| "@types/mocha": "^10.0.9", | ||
| "@types/node": "^18.19.55", | ||
| "@types/node": "^18.19.64", | ||
| "@types/sinon": "^17.0.3", | ||
| "@typescript-eslint/eslint-plugin": "^8.8.1", | ||
| "@typescript-eslint/parser": "^8.8.1", | ||
| "chai": "^4.5.0", | ||
| "@typescript-eslint/eslint-plugin": "^8.14.0", | ||
| "@typescript-eslint/parser": "^8.14.0", | ||
| "@vitest/coverage-v8": "^2.1.5", | ||
| "c8": "^10.1.2", | ||
| "dotenv": "^16.4.5", | ||
@@ -59,14 +44,22 @@ "eslint": "^8.57.1", | ||
| "eslint-plugin-sonarjs": "^0.25.1", | ||
| "mocha": "^10.7.3", | ||
| "prettier": "^3.3.3", | ||
| "sinon": "^19.0.2", | ||
| "source-map-support": "^0.5.21", | ||
| "ts-node": "^10.9.2", | ||
| "typescript": "^5.6.3" | ||
| "tsup": "^8.3.5", | ||
| "typescript": "^5.6.3", | ||
| "vite": "^5.4.11", | ||
| "vitest": "^2.1.4" | ||
| }, | ||
| "peerDependencies": { | ||
| "@avanio/logger-like": "^0.1 || ^0.2", | ||
| "@avanio/variable-util": "^0.8 || ^0.9 || ^0.10", | ||
| "@avanio/variable-util": "^0.11", | ||
| "dotenv": "^16" | ||
| }, | ||
| "scripts": { | ||
| "build": "tsup src/index.ts --sourcemap --format cjs,esm --dts --clean", | ||
| "test": "vitest test --run --no-isolate --coverage", | ||
| "coverage": "vitest test --run --no-isolate --reporter=dot --coverage --coverage.reporter=lcov", | ||
| "lint": "eslint . --ext .ts", | ||
| "validate": "tsc --noEmit --project tsconfig.test.json" | ||
| } | ||
| } | ||
| } |
| import { type IConfigLoaderProps, type Loadable, type LoaderValue, RecordConfigLoader, type ValidateCallback } from '@avanio/variable-util'; | ||
| import type { ILoggerLike } from '@avanio/logger-like'; | ||
| /** | ||
| * Options for the AbstractFileRecordLoader. | ||
| * @since v0.8.0 | ||
| */ | ||
| export interface AbstractFileRecordLoaderOptions<FileType extends string> extends IConfigLoaderProps { | ||
| fileType: FileType; | ||
| /** file name to load */ | ||
| fileName: string; | ||
| /** set to false if need errors */ | ||
| isSilent: boolean; | ||
| /** optional logger */ | ||
| logger: ILoggerLike | undefined; | ||
| /** set to true to watch file for changes */ | ||
| watch: boolean; | ||
| /** set to true to disable loader */ | ||
| disabled: boolean; | ||
| /** | ||
| * optional validator for data (Record<string, string | undefined>) | ||
| * | ||
| * @example | ||
| * // using zod | ||
| * const stringRecordSchema = z.record(z.string().min(1), z.string()); | ||
| * const validate: ValidateCallback<Record<string, string>> = async (data) => { | ||
| * const result = await stringRecordSchema.safeParseAsync(data); | ||
| * if (!result.success) { | ||
| * return {success: false, message: result.error.message}; | ||
| * } | ||
| * return {success: true}; | ||
| * }; | ||
| */ | ||
| validate: ValidateCallback<Record<string, string | undefined>, Record<string, string | undefined>> | undefined; | ||
| } | ||
| /** | ||
| * Abstract class for loading records from a file. | ||
| * @since v0.8.0 | ||
| */ | ||
| export declare abstract class AbstractFileRecordLoader<Options extends AbstractFileRecordLoaderOptions<string> = AbstractFileRecordLoaderOptions<string>> extends RecordConfigLoader<string | undefined, Partial<Options>, Options> { | ||
| abstract readonly type: string; | ||
| private watcher; | ||
| private timeout; | ||
| protected abstract defaultOptions: Options; | ||
| constructor(options: Loadable<Partial<Options>>); | ||
| /** | ||
| * If the loader is watching the file, it will stop watching. | ||
| */ | ||
| close(): Promise<void>; | ||
| protected handleLoader(rootKey: string, key?: string): Promise<LoaderValue>; | ||
| protected handleData(): Promise<Record<string, string | undefined>>; | ||
| /** | ||
| * Handle the parsing of the file. | ||
| */ | ||
| protected abstract handleParse(rawData: Buffer, options: Options): Record<string, string | undefined> | Promise<Record<string, string | undefined>>; | ||
| private handleFileWatch; | ||
| private handleFileChange; | ||
| } |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.AbstractFileRecordLoader = void 0; | ||
| const fs_1 = require("fs"); | ||
| const variable_util_1 = require("@avanio/variable-util"); | ||
| const errorUtil_1 = require("./errorUtil"); | ||
| const promises_1 = require("fs/promises"); | ||
| /** | ||
| * Abstract class for loading records from a file. | ||
| * @since v0.8.0 | ||
| */ | ||
| class AbstractFileRecordLoader extends variable_util_1.RecordConfigLoader { | ||
| watcher; | ||
| timeout; | ||
| constructor(options) { | ||
| super(options); | ||
| this.getLoader = this.getLoader.bind(this); | ||
| this.handleFileChange = this.handleFileChange.bind(this); | ||
| } | ||
| /** | ||
| * If the loader is watching the file, it will stop watching. | ||
| */ | ||
| async close() { | ||
| if (this.watcher) { | ||
| const { logger, fileName } = await this.getOptions(); | ||
| logger?.debug(this.buildErrorStr(`closing file watcher for ${fileName}`)); | ||
| this.watcher.close(); | ||
| } | ||
| } | ||
| async handleLoader(rootKey, key) { | ||
| const { disabled, fileName } = await this.getOptions(); | ||
| if (disabled) { | ||
| return { type: this.type, result: undefined }; | ||
| } | ||
| if (!this.dataPromise) { | ||
| this.dataPromise = this.handleData(); | ||
| } | ||
| const data = await this.dataPromise; | ||
| const targetKey = key || rootKey; | ||
| const currentValue = data[targetKey]; | ||
| return { type: this.type, result: { value: currentValue, path: fileName, seen: this.handleSeen(targetKey, currentValue) } }; | ||
| } | ||
| async handleData() { | ||
| const options = await this.getOptions(); | ||
| options.logger?.debug(this.buildErrorStr(`loading file ${options.fileName}`)); | ||
| // if file is disabled, return empty object | ||
| if (options.disabled) { | ||
| return {}; | ||
| } | ||
| if (!(0, fs_1.existsSync)(options.fileName)) { | ||
| const msg = this.buildErrorStr(`file ${options.fileName} not found`); | ||
| if (options.isSilent) { | ||
| options.logger?.debug(msg); | ||
| return {}; | ||
| } | ||
| throw new variable_util_1.VariableError(msg); | ||
| } | ||
| try { | ||
| const data = await this.handleParse(await (0, promises_1.readFile)(options.fileName), options); | ||
| if (options.validate) { | ||
| return await options.validate(data); | ||
| } | ||
| this.handleFileWatch(options); // add watch after successful load | ||
| return data; | ||
| } | ||
| catch (_err) { | ||
| const msg = this.buildErrorStr(`file ${options.fileName} is not a valid ${options.fileType}`); | ||
| if (options.isSilent) { | ||
| options.logger?.info(msg); | ||
| return {}; | ||
| } | ||
| throw new variable_util_1.VariableError(msg); | ||
| } | ||
| } | ||
| handleFileWatch(options) { | ||
| if (options.watch && !this.watcher) { | ||
| options.logger?.debug(this.buildErrorStr(`opening file watcher for ${options.fileName}`)); | ||
| this.watcher = (0, fs_1.watch)(options.fileName, () => { | ||
| if (this.timeout) { | ||
| clearTimeout(this.timeout); | ||
| } | ||
| // delay to prevent multiple reloads | ||
| this.timeout = setTimeout(() => { | ||
| void this.handleFileChange(options); | ||
| }, 200); | ||
| }); | ||
| } | ||
| } | ||
| async handleFileChange(options) { | ||
| try { | ||
| options.logger?.debug(this.buildErrorStr(`file ${options.fileName} changed`)); | ||
| await this.reload(); | ||
| } | ||
| catch (err) { | ||
| options.logger?.error(this.buildErrorStr(`error reloading file ${options.fileName}: ${(0, errorUtil_1.getError)(err).message}`)); | ||
| } | ||
| } | ||
| } | ||
| exports.AbstractFileRecordLoader = AbstractFileRecordLoader; | ||
| //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RGaWxlUmVjb3JkTG9hZGVyLmpzIiwic291cmNlUm9vdCI6Ii4vc3JjLyIsInNvdXJjZXMiOlsiQWJzdHJhY3RGaWxlUmVjb3JkTG9hZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJCQUFxRDtBQUNyRCx5REFBeUo7QUFDekosMkNBQXFDO0FBRXJDLDBDQUFxQztBQW1DckM7OztHQUdHO0FBQ0gsTUFBc0Isd0JBRXBCLFNBQVEsa0NBQWlFO0lBRWxFLE9BQU8sQ0FBd0I7SUFDL0IsT0FBTyxDQUE0QztJQUkzRCxZQUFtQixPQUFtQztRQUNyRCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzNDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFELENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxLQUFLO1FBQ2pCLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2xCLE1BQU0sRUFBQyxNQUFNLEVBQUUsUUFBUSxFQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDbkQsTUFBTSxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLDRCQUE0QixRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDMUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUN0QixDQUFDO0lBQ0YsQ0FBQztJQUVTLEtBQUssQ0FBQyxZQUFZLENBQUMsT0FBZSxFQUFFLEdBQVk7UUFDekQsTUFBTSxFQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUMsR0FBRyxNQUFNLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNyRCxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQ2QsT0FBTyxF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 |
| import { ConfigLoader, type Loadable, type LoaderValue } from '@avanio/variable-util'; | ||
| import type { ILoggerLike } from '@avanio/logger-like'; | ||
| export interface DockerSecretsConfigLoaderOptions { | ||
| /** force file name to lower case */ | ||
| fileLowerCase: boolean; | ||
| /** path to docker secrets, default is '/run/secrets' */ | ||
| path: string; | ||
| /** set to false if need errors */ | ||
| isSilent: boolean; | ||
| /** optional logger */ | ||
| logger: ILoggerLike | undefined; | ||
| /** set to true to disable loader, default is false */ | ||
| disabled: boolean; | ||
| } | ||
| /** | ||
| * Loader for docker secrets, reads secrets from the `/run/secrets` directory. | ||
| * @since v0.8.0 | ||
| */ | ||
| export declare class DockerSecretsConfigLoader extends ConfigLoader<string | undefined, Partial<DockerSecretsConfigLoaderOptions>, DockerSecretsConfigLoaderOptions> { | ||
| readonly type = "docker-secrets"; | ||
| private valuePromises; | ||
| protected defaultOptions: DockerSecretsConfigLoaderOptions; | ||
| constructor(options: Loadable<Partial<DockerSecretsConfigLoaderOptions>>); | ||
| protected handleLoader(lookupKey: string, overrideKey?: string): Promise<LoaderValue>; | ||
| private filePath; | ||
| } |
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| var desc = Object.getOwnPropertyDescriptor(m, k); | ||
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
| desc = { enumerable: true, get: function() { return m[k]; } }; | ||
| } | ||
| Object.defineProperty(o, k2, desc); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
| Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
| }) : function(o, v) { | ||
| o["default"] = v; | ||
| }); | ||
| var __importStar = (this && this.__importStar) || function (mod) { | ||
| if (mod && mod.__esModule) return mod; | ||
| var result = {}; | ||
| if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
| __setModuleDefault(result, mod); | ||
| return result; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.DockerSecretsConfigLoader = void 0; | ||
| const path = __importStar(require("path")); | ||
| const variable_util_1 = require("@avanio/variable-util"); | ||
| const fs_1 = require("fs"); | ||
| const promises_1 = require("fs/promises"); | ||
| /** | ||
| * Loader for docker secrets, reads secrets from the `/run/secrets` directory. | ||
| * @since v0.8.0 | ||
| */ | ||
| class DockerSecretsConfigLoader extends variable_util_1.ConfigLoader { | ||
| type = 'docker-secrets'; | ||
| valuePromises = {}; | ||
| defaultOptions = { | ||
| disabled: false, | ||
| fileLowerCase: false, | ||
| isSilent: true, | ||
| logger: undefined, | ||
| path: '/run/secrets', | ||
| }; | ||
| constructor(options) { | ||
| super(options); | ||
| this.getLoader = this.getLoader.bind(this); | ||
| } | ||
| async handleLoader(lookupKey, overrideKey) { | ||
| const options = await this.getOptions(); | ||
| if (options.disabled) { | ||
| return { type: this.type, result: undefined }; | ||
| } | ||
| const targetKey = overrideKey || lookupKey; | ||
| const filePath = this.filePath(targetKey, options); | ||
| const valuePromise = this.valuePromises[targetKey]; | ||
| const seen = !!valuePromise; // if valuePromise exists, it means we have seen this key before | ||
| if (!valuePromise) { | ||
| if (!(0, fs_1.existsSync)(filePath)) { | ||
| if (!options.isSilent) { | ||
| throw new variable_util_1.VariableLookupError(targetKey, `ConfigVariables[${this.type}]: ${lookupKey} from ${filePath} not found`); | ||
| } | ||
| options.logger?.debug(`ConfigVariables[${this.type}]: ${lookupKey} from ${filePath} not found`); | ||
| this.valuePromises[targetKey] = Promise.resolve(undefined); | ||
| } | ||
| else { | ||
| this.valuePromises[targetKey] = (0, promises_1.readFile)(filePath, 'utf8'); | ||
| } | ||
| } | ||
| const value = await this.valuePromises[targetKey]; | ||
| return { type: this.type, result: { path: filePath, value, seen } }; | ||
| } | ||
| filePath(key, options) { | ||
| return path.join(path.resolve(options.path), options.fileLowerCase ? key.toLowerCase() : key); | ||
| } | ||
| } | ||
| exports.DockerSecretsConfigLoader = DockerSecretsConfigLoader; | ||
| //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRG9ja2VyU2VjcmV0c0NvbmZpZ0xvYWRlci5qcyIsInNvdXJjZVJvb3QiOiIuL3NyYy8iLCJzb3VyY2VzIjpbIkRvY2tlclNlY3JldHNDb25maWdMb2FkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwyQ0FBNkI7QUFDN0IseURBQXlHO0FBQ3pHLDJCQUE4QjtBQUU5QiwwQ0FBcUM7QUFlckM7OztHQUdHO0FBQ0gsTUFBYSx5QkFBMEIsU0FBUSw0QkFBNkc7SUFDM0ksSUFBSSxHQUFHLGdCQUFnQixDQUFDO0lBQ2hDLGFBQWEsR0FBNEQsRUFBRSxDQUFDO0lBQzFFLGNBQWMsR0FBcUM7UUFDNUQsUUFBUSxFQUFFLEtBQUs7UUFDZixhQUFhLEVBQUUsS0FBSztRQUNwQixRQUFRLEVBQUUsSUFBSTtRQUNkLE1BQU0sRUFBRSxTQUFTO1FBQ2pCLElBQUksRUFBRSxjQUFjO0tBQ3BCLENBQUM7SUFFRixZQUFtQixPQUE0RDtRQUM5RSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFFUyxLQUFLLENBQUMsWUFBWSxDQUFDLFNBQWlCLEVBQUUsV0FBb0I7UUFDbkUsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDeEMsSUFBSSxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDdEIsT0FBTyxFQUFDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUMsQ0FBQztRQUM3QyxDQUFDO1FBQ0QsTUFBTSxTQUFTLEdBQUcsV0FBVyxJQUFJLFNBQVMsQ0FBQztRQUMzQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNuRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ25ELE1BQU0sSUFBSSxHQUFHLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxnRUFBZ0U7UUFDN0YsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxJQUFBLGVBQVUsRUFBQyxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUMzQixJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO29CQUN2QixNQUFNLElBQUksbUNBQW1CLENBQUMsU0FBUyxFQUFFLG1CQUFtQixJQUFJLENBQUMsSUFBSSxNQUFNLFNBQVMsU0FBUyxRQUFRLFlBQVksQ0FBQyxDQUFDO2dCQUNwSCxDQUFDO2dCQUNELE9BQU8sQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLG1CQUFtQixJQUFJLENBQUMsSUFBSSxNQUFNLFNBQVMsU0FBUyxRQUFRLFlBQVksQ0FBQyxDQUFDO2dCQUNoRyxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDNUQsQ0FBQztpQkFBTSxDQUFDO2dCQUNQLElBQUksQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLEdBQUcsSUFBQSxtQkFBUSxFQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUM1RCxDQUFDO1FBQ0YsQ0FBQztRQUNELE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNsRCxPQUFPLEVBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLEVBQUMsSUFBSSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFDLEVBQUMsQ0FBQztJQUNqRSxDQUFDO0lBRU8sUUFBUSxDQUFDLEdBQVcsRUFBRSxPQUF5QztRQUN0RSxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMvRixDQUFDO0NBQ0Q7QUEzQ0QsOERBMkNDIn0= |
| import { AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions } from './AbstractFileRecordLoader'; | ||
| /** | ||
| * Loader for dotenv files, using the `dotenv` packages parser. | ||
| * @since v0.6.1 | ||
| */ | ||
| export declare class DotEnvLoader extends AbstractFileRecordLoader { | ||
| readonly type = "dotenv"; | ||
| protected defaultOptions: AbstractFileRecordLoaderOptions<'env'>; | ||
| protected handleParse(rawData: Buffer): Record<string, string | undefined>; | ||
| } |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.DotEnvLoader = void 0; | ||
| const AbstractFileRecordLoader_1 = require("./AbstractFileRecordLoader"); | ||
| const dotenv_1 = require("dotenv"); | ||
| /** | ||
| * Loader for dotenv files, using the `dotenv` packages parser. | ||
| * @since v0.6.1 | ||
| */ | ||
| class DotEnvLoader extends AbstractFileRecordLoader_1.AbstractFileRecordLoader { | ||
| type = 'dotenv'; | ||
| defaultOptions = { | ||
| disabled: false, | ||
| fileName: '.env', | ||
| fileType: 'env', | ||
| isSilent: true, | ||
| logger: undefined, | ||
| validate: undefined, | ||
| watch: false, | ||
| }; | ||
| handleParse(rawData) { | ||
| return (0, dotenv_1.parse)(rawData); | ||
| } | ||
| } | ||
| exports.DotEnvLoader = DotEnvLoader; | ||
| //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRG90RW52TG9hZGVyLmpzIiwic291cmNlUm9vdCI6Ii4vc3JjLyIsInNvdXJjZXMiOlsiRG90RW52TG9hZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHlFQUEwRztBQUMxRyxtQ0FBNkI7QUFFN0I7OztHQUdHO0FBQ0gsTUFBYSxZQUFhLFNBQVEsbURBQXdCO0lBQ3pDLElBQUksR0FBRyxRQUFRLENBQUM7SUFDdEIsY0FBYyxHQUEyQztRQUNsRSxRQUFRLEVBQUUsS0FBSztRQUNmLFFBQVEsRUFBRSxNQUFNO1FBQ2hCLFFBQVEsRUFBRSxLQUFLO1FBQ2YsUUFBUSxFQUFFLElBQUk7UUFDZCxNQUFNLEVBQUUsU0FBUztRQUNqQixRQUFRLEVBQUUsU0FBUztRQUNuQixLQUFLLEVBQUUsS0FBSztLQUNaLENBQUM7SUFFUSxXQUFXLENBQUMsT0FBZTtRQUNwQyxPQUFPLElBQUEsY0FBSyxFQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3ZCLENBQUM7Q0FDRDtBQWZELG9DQWVDIn0= |
| export declare function getError(error: unknown): Error; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.getError = getError; | ||
| function getError(error) { | ||
| if (error instanceof Error) { | ||
| return error; | ||
| } | ||
| if (typeof error === 'string') { | ||
| return new Error(error); | ||
| } | ||
| return new Error(`Unknown error: ${JSON.stringify(error)}`); | ||
| } | ||
| //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JVdGlsLmpzIiwic291cmNlUm9vdCI6Ii4vc3JjLyIsInNvdXJjZXMiOlsiZXJyb3JVdGlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsNEJBUUM7QUFSRCxTQUFnQixRQUFRLENBQUMsS0FBYztJQUN0QyxJQUFJLEtBQUssWUFBWSxLQUFLLEVBQUUsQ0FBQztRQUM1QixPQUFPLEtBQUssQ0FBQztJQUNkLENBQUM7SUFDRCxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQy9CLE9BQU8sSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUNELE9BQU8sSUFBSSxLQUFLLENBQUMsa0JBQWtCLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQzdELENBQUMifQ== |
| import { AbstractFileRecordLoader, type AbstractFileRecordLoaderOptions } from './AbstractFileRecordLoader'; | ||
| /** | ||
| * A file-based configuration loader that reads a JSON file. | ||
| * @since v0.9.1 | ||
| */ | ||
| export declare class FileConfigLoader extends AbstractFileRecordLoader<AbstractFileRecordLoaderOptions<'json'>> { | ||
| readonly type = "file"; | ||
| protected defaultOptions: AbstractFileRecordLoaderOptions<'json'>; | ||
| protected handleParse(rawData: Buffer): Record<string, string | undefined>; | ||
| } |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.FileConfigLoader = void 0; | ||
| const AbstractFileRecordLoader_1 = require("./AbstractFileRecordLoader"); | ||
| /** | ||
| * A file-based configuration loader that reads a JSON file. | ||
| * @since v0.9.1 | ||
| */ | ||
| class FileConfigLoader extends AbstractFileRecordLoader_1.AbstractFileRecordLoader { | ||
| type = 'file'; | ||
| defaultOptions = { | ||
| disabled: false, | ||
| fileName: 'config.json', | ||
| fileType: 'json', | ||
| isSilent: true, | ||
| logger: undefined, | ||
| validate: undefined, | ||
| watch: false, | ||
| }; | ||
| handleParse(rawData) { | ||
| return JSON.parse(rawData.toString()); | ||
| } | ||
| } | ||
| exports.FileConfigLoader = FileConfigLoader; | ||
| //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmlsZUNvbmZpZ0xvYWRlci5qcyIsInNvdXJjZVJvb3QiOiIuL3NyYy8iLCJzb3VyY2VzIjpbIkZpbGVDb25maWdMb2FkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEseUVBQTBHO0FBRTFHOzs7R0FHRztBQUNILE1BQWEsZ0JBQWlCLFNBQVEsbURBQWlFO0lBQ3RGLElBQUksR0FBRyxNQUFNLENBQUM7SUFDcEIsY0FBYyxHQUE0QztRQUNuRSxRQUFRLEVBQUUsS0FBSztRQUNmLFFBQVEsRUFBRSxhQUFhO1FBQ3ZCLFFBQVEsRUFBRSxNQUFNO1FBQ2hCLFFBQVEsRUFBRSxJQUFJO1FBQ2QsTUFBTSxFQUFFLFNBQVM7UUFDakIsUUFBUSxFQUFFLFNBQVM7UUFDbkIsS0FBSyxFQUFFLEtBQUs7S0FDWixDQUFDO0lBRVEsV0FBVyxDQUFDLE9BQWU7UUFDcEMsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBdUMsQ0FBQztJQUM3RSxDQUFDO0NBQ0Q7QUFmRCw0Q0FlQyJ9 |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
55871
103.97%528
43.87%8
-42.86%9
80%1
Infinity%