@wolfstar/env-utilities 2.2.0 → 2.2.1-next-20260927142544

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_src = require('./src-DCzHag6L.cjs');
2
+ const require_src = require('./src-BdFPSw_y.cjs');
3
3
 
4
4
  exports.envIsDefined = require_src.envIsDefined;
5
5
  exports.envIsNull = require_src.envIsNull;
@@ -1,4 +1,4 @@
1
- const require_src = require('./src-DCzHag6L.cjs');
1
+ const require_src = require('./src-BdFPSw_y.cjs');
2
2
 
3
3
  //#region src/setup.ts
4
4
  require_src.setup();
@@ -6,7 +6,7 @@ let node_module = require("node:module");
6
6
  let node_path = require("node:path");
7
7
 
8
8
  //#region src/lib/env-loader.ts
9
- const packageVersion = "2.2.0";
9
+ const packageVersion = "2.2.1-next-20260927142544";
10
10
  function resolveDebugLogger() {
11
11
  return _sapphire_pieces.container.logger ?? console;
12
12
  }
@@ -29,14 +29,16 @@ function loadEnvFiles(options) {
29
29
  * @see {@linkplain https://github.com/facebook/create-react-app/blob/d960b9e38c062584ff6cfb1a70e1512509a966e7/packages/react-scripts/config/env.js#L36-L49}
30
30
  */
31
31
  let parsed = {};
32
+ const scratch = dotenvSettingsFromProcessEnv();
32
33
  for (const dotenvFile of dotenvFiles) {
33
34
  const dotenvFileString = typeof dotenvFile === "string" ? dotenvFile : (0, node_url.fileURLToPath)(dotenvFile);
34
35
  log(`loading \`${(0, node_path.basename)(dotenvFileString)}\``);
35
- const result = (0, dotenv_expand.expand)((0, dotenv.config)({
36
+ const result = (0, dotenv.config)({
36
37
  debug: options?.debug,
37
38
  encoding: options?.encoding,
38
- path: dotenvFile
39
- }));
39
+ path: dotenvFile,
40
+ processEnv: scratch
41
+ });
40
42
  if (result.error) {
41
43
  if (result.error.code === "ENOENT") {
42
44
  log(`\`${(0, node_path.basename)(dotenvFileString)}\` file not found`);
@@ -49,6 +51,13 @@ function loadEnvFiles(options) {
49
51
  ...parsed
50
52
  };
51
53
  }
54
+ const alreadySet = new Set(Object.keys(parsed).filter((key) => process.env[key]));
55
+ for (const key of findReferenceCycles(parsed, alreadySet)) {
56
+ log(`\`${key}\` is part of a circular reference and resolves to an empty string`);
57
+ parsed[key] = "";
58
+ }
59
+ (0, dotenv.populate)(process.env, parsed, { debug: options?.debug });
60
+ parsed = (0, dotenv_expand.expand)({ parsed }).parsed;
52
61
  /**
53
62
  * @see {@linkplain https://github.com/facebook/create-react-app/blob/d960b9e38c062584ff6cfb1a70e1512509a966e7/packages/react-scripts/config/env.js#L72-L89}
54
63
  */
@@ -94,6 +103,67 @@ function filterByPrefix(parsed, prefix, log) {
94
103
  return obj;
95
104
  }, {});
96
105
  }
106
+ /**
107
+ * dotenv reads its own `DOTENV_CONFIG_DEBUG` and `DOTENV_CONFIG_QUIET` switches from the `processEnv` it writes to,
108
+ * so forward the ones set in the real environment to the scratch object used while parsing.
109
+ */
110
+ function dotenvSettingsFromProcessEnv() {
111
+ const settings = {};
112
+ for (const key of ["DOTENV_CONFIG_DEBUG", "DOTENV_CONFIG_QUIET"]) {
113
+ const value = process.env[key];
114
+ if (value !== void 0) settings[key] = value;
115
+ }
116
+ return settings;
117
+ }
118
+ /**
119
+ * Finds the variables that take part in a reference cycle spanning several variables (`A=${B}`, `B=${A}`).
120
+ *
121
+ * dotenv-expand only stops a cycle when a substituted value equals a whole intermediate result, so once a value
122
+ * around the cycle carries a prefix or suffix (e.g. `C=${B}z`) it never terminates. Resolving the variables of such
123
+ * a cycle to an empty string beforehand keeps loading bounded. Variables already set in `process.env` are left out,
124
+ * as `expand` uses their existing value instead of expanding the one from the file. A variable referencing itself
125
+ * is left alone too: dotenv-expand handles that case on its own.
126
+ */
127
+ function findReferenceCycles(parsed, alreadySet) {
128
+ const references = /* @__PURE__ */ new Map();
129
+ for (const [key, value] of Object.entries(parsed)) {
130
+ if (alreadySet.has(key)) continue;
131
+ const targets = /* @__PURE__ */ new Set();
132
+ for (const match of value.matchAll(/(?<!\\)\$\{?([A-Za-z_][A-Za-z0-9_]*)/g)) {
133
+ const target = match[1];
134
+ if (target !== key && target in parsed && !alreadySet.has(target)) targets.add(target);
135
+ }
136
+ references.set(key, [...targets]);
137
+ }
138
+ const cyclic = /* @__PURE__ */ new Set();
139
+ const indexes = /* @__PURE__ */ new Map();
140
+ const lowLinks = /* @__PURE__ */ new Map();
141
+ const stack = [];
142
+ const onStack = /* @__PURE__ */ new Set();
143
+ let counter = 0;
144
+ const visit = (key) => {
145
+ indexes.set(key, counter);
146
+ lowLinks.set(key, counter);
147
+ counter++;
148
+ stack.push(key);
149
+ onStack.add(key);
150
+ for (const target of references.get(key) ?? []) if (!indexes.has(target)) {
151
+ visit(target);
152
+ lowLinks.set(key, Math.min(lowLinks.get(key), lowLinks.get(target)));
153
+ } else if (onStack.has(target)) lowLinks.set(key, Math.min(lowLinks.get(key), indexes.get(target)));
154
+ if (lowLinks.get(key) !== indexes.get(key)) return;
155
+ const component = [];
156
+ let member;
157
+ do {
158
+ member = stack.pop();
159
+ onStack.delete(member);
160
+ component.push(member);
161
+ } while (member !== key);
162
+ if (component.length > 1) for (const item of component) cyclic.add(item);
163
+ };
164
+ for (const key of references.keys()) if (!indexes.has(key)) visit(key);
165
+ return cyclic;
166
+ }
97
167
  function appendSuffix(path, suffix) {
98
168
  if (typeof path === "string") return `${path}${suffix}`;
99
169
  const file = (0, node_url.fileURLToPath)(path);
@@ -280,4 +350,4 @@ Object.defineProperty(exports, 'setup', {
280
350
  return setup;
281
351
  }
282
352
  });
283
- //# sourceMappingURL=src-DCzHag6L.cjs.map
353
+ //# sourceMappingURL=src-BdFPSw_y.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"src-DCzHag6L.cjs","names":["fileURLToPath"],"sources":["../../src/lib/utils.ts","../../src/lib/setup.ts"],"sourcesContent":["import type { Env, EnvAny, EnvArray, EnvBoolean, EnvInteger, EnvNumber, EnvString } from './types';\n\nexport function envParseInteger(key: EnvInteger, defaultValue?: number): number;\nexport function envParseInteger(key: EnvInteger, defaultValue: number | null): number | null;\nexport function envParseInteger(key: EnvInteger, defaultValue?: number | null): number | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be an integer, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tconst integer = Number(value);\n\tif (Number.isInteger(integer)) return integer;\n\tthrow new TypeError(`[ENV] ${key} - The key must be an integer, but received '${value}'.`);\n}\n\nexport function envParseNumber(key: EnvNumber, defaultValue?: number): number;\nexport function envParseNumber(key: EnvNumber, defaultValue: number | null): number | null;\nexport function envParseNumber(key: EnvNumber, defaultValue?: number | null): number | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a number, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tconst integer = Number(value);\n\tif (!Number.isNaN(integer)) return integer;\n\tthrow new TypeError(`[ENV] ${key} - The key must be a number, but received '${value}'.`);\n}\n\nexport function envParseBoolean(key: EnvBoolean, defaultValue?: boolean): boolean;\nexport function envParseBoolean(key: EnvBoolean, defaultValue: boolean | null): boolean | null;\nexport function envParseBoolean(key: EnvBoolean, defaultValue?: boolean | null): boolean | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a boolean, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tif (value.length === 4 && value.toLowerCase() === 'true') return true;\n\tif (value.length === 5 && value.toLowerCase() === 'false') return false;\n\tthrow new TypeError(`[ENV] ${key} - The key must be a boolean, but received '${value}'.`);\n}\n\nexport function envParseString<K extends EnvString>(key: K, defaultValue?: Env[K]): NonNullable<Env[K]>;\nexport function envParseString<K extends EnvString>(key: K, defaultValue: Env[K] | null): NonNullable<Env[K]> | null;\nexport function envParseString<K extends EnvString>(key: K, defaultValue?: Env[K] | null): NonNullable<Env[K]> | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a string, but is empty or undefined.`);\n\t\treturn defaultValue!;\n\t}\n\n\treturn value!;\n}\n\nexport function envParseArray(key: EnvArray, defaultValue?: string[]): string[];\nexport function envParseArray(key: EnvArray, defaultValue: string[] | null): string[] | null;\nexport function envParseArray(key: EnvArray, defaultValue?: string[] | null): string[] | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be an array, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\treturn value.split(' ');\n}\n\n/**\n * Checks if the value of the specified environment variable is null.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - The string `\"0\"`\n * - The string `\"null\"`, case insensitive\n */\nexport function envIsNull(key: EnvAny): boolean {\n\tconst value = process.env[key];\n\treturn typeof value === 'string' && (value === '0' || (value.length === 4 && value.toLowerCase() === 'null'));\n}\n\n/**\n * Checks if the value of the specified environment variable is undefined.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - `undefined`\n * - An empty string (`\"\"`)\n */\nexport function envIsUndefined(key: EnvAny): boolean {\n\tconst value = process.env[key];\n\treturn value === undefined || value.length === 0;\n}\n\n/**\n * Checks if the value of the specified environment variable is nullish.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - `undefined`\n * - An empty string (`\"\"`)\n * - The string `\"0\"`\n * - The string `\"null\"`, case insensitive\n */\nexport function envIsNullish(key: EnvAny): boolean {\n\treturn envIsUndefined(key) || envIsNull(key);\n}\n\n/**\n * Checks if any of the specified environment variables is defined.\n * @param key - The name of the environment variable.\n * @returns Whether the value of any of the specified environment variables is a non-empty string\n */\nexport function envIsDefined(...keys: readonly EnvAny[]): boolean {\n\treturn keys.every((key) => !envIsUndefined(key));\n}\n","import type { DotenvConfigOutput } from 'dotenv';\nimport { fileURLToPath } from 'node:url';\nimport { loadEnvFiles, type EnvLoaderOptions } from './env-loader';\nimport { envIsDefined, envParseBoolean } from './utils';\n\nexport function setup(pathOrOptions?: string | URL | EnvSetupOptions): DotenvConfigOutput {\n\t// Unless explicitly defined, set NODE_ENV as development:\n\tprocess.env.NODE_ENV ??= 'development';\n\n\tlet options: EnvLoaderOptions;\n\tif (typeof pathOrOptions === 'undefined') {\n\t\toptions = {};\n\t} else if (typeof pathOrOptions === 'string') {\n\t\toptions = { path: pathOrOptions };\n\t} else if (typeof pathOrOptions === 'object') {\n\t\tif (pathOrOptions instanceof URL) {\n\t\t\toptions = { path: fileURLToPath(pathOrOptions) };\n\t\t} else {\n\t\t\tconst { path, ...rest } = pathOrOptions;\n\t\t\toptions = { path: typeof path === 'undefined' ? path : typeof path === 'string' ? path : fileURLToPath(path), ...rest };\n\t\t}\n\t} else {\n\t\tthrow new TypeError('Expected undefined, string, URL, or EnvSetupOptions');\n\t}\n\n\treturn loadEnvFiles({\n\t\tdebug: envIsDefined('DOTENV_DEBUG') ? envParseBoolean('DOTENV_DEBUG') : undefined,\n\t\tencoding: process.env.DOTENV_ENCODING,\n\t\tenv: process.env.DOTENV_ENV,\n\t\tpath: process.env.DOTENV_PATH,\n\t\tprefix: process.env.DOTENV_PREFIX,\n\t\tloader: process.env.DOTENV_LOADER,\n\t\t...options\n\t});\n}\n\nexport interface EnvSetupOptions extends Omit<EnvLoaderOptions, 'path'> {\n\t/**\n\t * You may specify a custom path if your file containing environment variables is located elsewhere.\n\t */\n\tpath?: string | URL;\n}\n\nexport type EnvSetupResult = DotenvConfigOutput;\n"],"mappings":"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"}
1
+ {"version":3,"file":"src-BdFPSw_y.cjs","names":["fileURLToPath"],"sources":["../../src/lib/utils.ts","../../src/lib/setup.ts"],"sourcesContent":["import type { Env, EnvAny, EnvArray, EnvBoolean, EnvInteger, EnvNumber, EnvString } from './types';\n\nexport function envParseInteger(key: EnvInteger, defaultValue?: number): number;\nexport function envParseInteger(key: EnvInteger, defaultValue: number | null): number | null;\nexport function envParseInteger(key: EnvInteger, defaultValue?: number | null): number | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be an integer, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tconst integer = Number(value);\n\tif (Number.isInteger(integer)) return integer;\n\tthrow new TypeError(`[ENV] ${key} - The key must be an integer, but received '${value}'.`);\n}\n\nexport function envParseNumber(key: EnvNumber, defaultValue?: number): number;\nexport function envParseNumber(key: EnvNumber, defaultValue: number | null): number | null;\nexport function envParseNumber(key: EnvNumber, defaultValue?: number | null): number | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a number, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tconst integer = Number(value);\n\tif (!Number.isNaN(integer)) return integer;\n\tthrow new TypeError(`[ENV] ${key} - The key must be a number, but received '${value}'.`);\n}\n\nexport function envParseBoolean(key: EnvBoolean, defaultValue?: boolean): boolean;\nexport function envParseBoolean(key: EnvBoolean, defaultValue: boolean | null): boolean | null;\nexport function envParseBoolean(key: EnvBoolean, defaultValue?: boolean | null): boolean | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a boolean, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tif (value.length === 4 && value.toLowerCase() === 'true') return true;\n\tif (value.length === 5 && value.toLowerCase() === 'false') return false;\n\tthrow new TypeError(`[ENV] ${key} - The key must be a boolean, but received '${value}'.`);\n}\n\nexport function envParseString<K extends EnvString>(key: K, defaultValue?: Env[K]): NonNullable<Env[K]>;\nexport function envParseString<K extends EnvString>(key: K, defaultValue: Env[K] | null): NonNullable<Env[K]> | null;\nexport function envParseString<K extends EnvString>(key: K, defaultValue?: Env[K] | null): NonNullable<Env[K]> | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a string, but is empty or undefined.`);\n\t\treturn defaultValue!;\n\t}\n\n\treturn value!;\n}\n\nexport function envParseArray(key: EnvArray, defaultValue?: string[]): string[];\nexport function envParseArray(key: EnvArray, defaultValue: string[] | null): string[] | null;\nexport function envParseArray(key: EnvArray, defaultValue?: string[] | null): string[] | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be an array, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\treturn value.split(' ');\n}\n\n/**\n * Checks if the value of the specified environment variable is null.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - The string `\"0\"`\n * - The string `\"null\"`, case insensitive\n */\nexport function envIsNull(key: EnvAny): boolean {\n\tconst value = process.env[key];\n\treturn typeof value === 'string' && (value === '0' || (value.length === 4 && value.toLowerCase() === 'null'));\n}\n\n/**\n * Checks if the value of the specified environment variable is undefined.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - `undefined`\n * - An empty string (`\"\"`)\n */\nexport function envIsUndefined(key: EnvAny): boolean {\n\tconst value = process.env[key];\n\treturn value === undefined || value.length === 0;\n}\n\n/**\n * Checks if the value of the specified environment variable is nullish.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - `undefined`\n * - An empty string (`\"\"`)\n * - The string `\"0\"`\n * - The string `\"null\"`, case insensitive\n */\nexport function envIsNullish(key: EnvAny): boolean {\n\treturn envIsUndefined(key) || envIsNull(key);\n}\n\n/**\n * Checks if any of the specified environment variables is defined.\n * @param key - The name of the environment variable.\n * @returns Whether the value of any of the specified environment variables is a non-empty string\n */\nexport function envIsDefined(...keys: readonly EnvAny[]): boolean {\n\treturn keys.every((key) => !envIsUndefined(key));\n}\n","import type { DotenvConfigOutput } from 'dotenv';\nimport { fileURLToPath } from 'node:url';\nimport { loadEnvFiles, type EnvLoaderOptions } from './env-loader';\nimport { envIsDefined, envParseBoolean } from './utils';\n\nexport function setup(pathOrOptions?: string | URL | EnvSetupOptions): DotenvConfigOutput {\n\t// Unless explicitly defined, set NODE_ENV as development:\n\tprocess.env.NODE_ENV ??= 'development';\n\n\tlet options: EnvLoaderOptions;\n\tif (typeof pathOrOptions === 'undefined') {\n\t\toptions = {};\n\t} else if (typeof pathOrOptions === 'string') {\n\t\toptions = { path: pathOrOptions };\n\t} else if (typeof pathOrOptions === 'object') {\n\t\tif (pathOrOptions instanceof URL) {\n\t\t\toptions = { path: fileURLToPath(pathOrOptions) };\n\t\t} else {\n\t\t\tconst { path, ...rest } = pathOrOptions;\n\t\t\toptions = { path: typeof path === 'undefined' ? path : typeof path === 'string' ? path : fileURLToPath(path), ...rest };\n\t\t}\n\t} else {\n\t\tthrow new TypeError('Expected undefined, string, URL, or EnvSetupOptions');\n\t}\n\n\treturn loadEnvFiles({\n\t\tdebug: envIsDefined('DOTENV_DEBUG') ? envParseBoolean('DOTENV_DEBUG') : undefined,\n\t\tencoding: process.env.DOTENV_ENCODING,\n\t\tenv: process.env.DOTENV_ENV,\n\t\tpath: process.env.DOTENV_PATH,\n\t\tprefix: process.env.DOTENV_PREFIX,\n\t\tloader: process.env.DOTENV_LOADER,\n\t\t...options\n\t});\n}\n\nexport interface EnvSetupOptions extends Omit<EnvLoaderOptions, 'path'> {\n\t/**\n\t * You may specify a custom path if your file containing environment variables is located elsewhere.\n\t */\n\tpath?: string | URL;\n}\n\nexport type EnvSetupResult = DotenvConfigOutput;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,SAAgB,gBAAgB,KAAiB,cAA6C;CAC7F,MAAM,QAAQ,QAAQ,IAAI;CAC1B,IAAI,CAAC,OAAO;EACX,IAAI,iBAAiB,QAAW,MAAM,IAAI,eAAe,SAAS,IAAI,0DAA0D;EAChI,OAAO;CACR;CAEA,MAAM,UAAU,OAAO,KAAK;CAC5B,IAAI,OAAO,UAAU,OAAO,GAAG,OAAO;CACtC,MAAM,IAAI,UAAU,SAAS,IAAI,+CAA+C,MAAM,GAAG;AAC1F;AAIA,SAAgB,eAAe,KAAgB,cAA6C;CAC3F,MAAM,QAAQ,QAAQ,IAAI;CAC1B,IAAI,CAAC,OAAO;EACX,IAAI,iBAAiB,QAAW,MAAM,IAAI,eAAe,SAAS,IAAI,wDAAwD;EAC9H,OAAO;CACR;CAEA,MAAM,UAAU,OAAO,KAAK;CAC5B,IAAI,CAAC,OAAO,MAAM,OAAO,GAAG,OAAO;CACnC,MAAM,IAAI,UAAU,SAAS,IAAI,6CAA6C,MAAM,GAAG;AACxF;AAIA,SAAgB,gBAAgB,KAAiB,cAA+C;CAC/F,MAAM,QAAQ,QAAQ,IAAI;CAC1B,IAAI,CAAC,OAAO;EACX,IAAI,iBAAiB,QAAW,MAAM,IAAI,eAAe,SAAS,IAAI,yDAAyD;EAC/H,OAAO;CACR;CAEA,IAAI,MAAM,WAAW,KAAK,MAAM,YAAY,MAAM,QAAQ,OAAO;CACjE,IAAI,MAAM,WAAW,KAAK,MAAM,YAAY,MAAM,SAAS,OAAO;CAClE,MAAM,IAAI,UAAU,SAAS,IAAI,8CAA8C,MAAM,GAAG;AACzF;AAIA,SAAgB,eAAoC,KAAQ,cAA0D;CACrH,MAAM,QAAQ,QAAQ,IAAI;CAC1B,IAAI,CAAC,OAAO;EACX,IAAI,iBAAiB,QAAW,MAAM,IAAI,eAAe,SAAS,IAAI,wDAAwD;EAC9H,OAAO;CACR;CAEA,OAAO;AACR;AAIA,SAAgB,cAAc,KAAe,cAAiD;CAC7F,MAAM,QAAQ,QAAQ,IAAI;CAC1B,IAAI,CAAC,OAAO;EACX,IAAI,iBAAiB,QAAW,MAAM,IAAI,eAAe,SAAS,IAAI,wDAAwD;EAC9H,OAAO;CACR;CAEA,OAAO,MAAM,MAAM,GAAG;AACvB;;;;;;;;AASA,SAAgB,UAAU,KAAsB;CAC/C,MAAM,QAAQ,QAAQ,IAAI;CAC1B,OAAO,OAAO,UAAU,aAAa,UAAU,OAAQ,MAAM,WAAW,KAAK,MAAM,YAAY,MAAM;AACtG;;;;;;;;AASA,SAAgB,eAAe,KAAsB;CACpD,MAAM,QAAQ,QAAQ,IAAI;CAC1B,OAAO,UAAU,UAAa,MAAM,WAAW;AAChD;;;;;;;;;;AAWA,SAAgB,aAAa,KAAsB;CAClD,OAAO,eAAe,GAAG,KAAK,UAAU,GAAG;AAC5C;;;;;;AAOA,SAAgB,aAAa,GAAG,MAAkC;CACjE,OAAO,KAAK,OAAO,QAAQ,CAAC,eAAe,GAAG,CAAC;AAChD;;;;AC3GA,SAAgB,MAAM,eAAoE;CAEzF,QAAQ,IAAI,aAAa;CAEzB,IAAI;CACJ,IAAI,OAAO,kBAAkB,aAC5B,UAAU,CAAC;MACL,IAAI,OAAO,kBAAkB,UACnC,UAAU,EAAE,MAAM,cAAc;MAC1B,IAAI,OAAO,kBAAkB,UAAU;EAC7C,IAAI,yBAAyB,KAC5B,UAAU,EAAE,UAAMA,wBAAc,aAAa,EAAE;OACzC;GACN,MAAM,EAAE,MAAM,GAAG,SAAS;GAC1B,UAAU;IAAE,MAAM,OAAO,SAAS,cAAc,OAAO,OAAO,SAAS,WAAW,WAAOA,wBAAc,IAAI;IAAG,GAAG;GAAK;EACvH;CACD,OACC,MAAM,IAAI,UAAU,qDAAqD;CAG1E,OAAO,aAAa;EACnB,OAAO,aAAa,cAAc,IAAI,gBAAgB,cAAc,IAAI;EACxE,UAAU,QAAQ,IAAI;EACtB,KAAK,QAAQ,IAAI;EACjB,MAAM,QAAQ,IAAI;EAClB,QAAQ,QAAQ,IAAI;EACpB,QAAQ,QAAQ,IAAI;EACpB,GAAG;CACJ,CAAC;AACF"}
package/dist/esm/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { a as envIsUndefined, c as envParseInteger, i as envIsNullish, l as envParseNumber, n as envIsDefined, o as envParseArray, r as envIsNull, s as envParseBoolean, t as setup, u as envParseString } from "./src-BHEW4qZd.js";
1
+ import { a as envIsUndefined, c as envParseInteger, i as envIsNullish, l as envParseNumber, n as envIsDefined, o as envParseArray, r as envIsNull, s as envParseBoolean, t as setup, u as envParseString } from "./src-DEtFY63P.js";
2
2
 
3
3
  export { envIsDefined, envIsNull, envIsNullish, envIsUndefined, envParseArray, envParseBoolean, envParseInteger, envParseNumber, envParseString, setup };
package/dist/esm/setup.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as setup } from "./src-BHEW4qZd.js";
1
+ import { t as setup } from "./src-DEtFY63P.js";
2
2
 
3
3
  //#region src/setup.ts
4
4
  setup();
@@ -1,12 +1,12 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { container } from "@sapphire/pieces";
4
- import { config } from "dotenv";
4
+ import { config, populate } from "dotenv";
5
5
  import { expand } from "dotenv-expand";
6
6
  import { basename, dirname, join, resolve } from "node:path";
7
7
 
8
8
  //#region src/lib/env-loader.ts
9
- const packageVersion = "2.2.0";
9
+ const packageVersion = "2.2.1-next-20260927142544";
10
10
  function resolveDebugLogger() {
11
11
  return container.logger ?? console;
12
12
  }
@@ -29,14 +29,16 @@ function loadEnvFiles(options) {
29
29
  * @see {@linkplain https://github.com/facebook/create-react-app/blob/d960b9e38c062584ff6cfb1a70e1512509a966e7/packages/react-scripts/config/env.js#L36-L49}
30
30
  */
31
31
  let parsed = {};
32
+ const scratch = dotenvSettingsFromProcessEnv();
32
33
  for (const dotenvFile of dotenvFiles) {
33
34
  const dotenvFileString = typeof dotenvFile === "string" ? dotenvFile : fileURLToPath(dotenvFile);
34
35
  log(`loading \`${basename(dotenvFileString)}\``);
35
- const result = expand(config({
36
+ const result = config({
36
37
  debug: options?.debug,
37
38
  encoding: options?.encoding,
38
- path: dotenvFile
39
- }));
39
+ path: dotenvFile,
40
+ processEnv: scratch
41
+ });
40
42
  if (result.error) {
41
43
  if (result.error.code === "ENOENT") {
42
44
  log(`\`${basename(dotenvFileString)}\` file not found`);
@@ -49,6 +51,13 @@ function loadEnvFiles(options) {
49
51
  ...parsed
50
52
  };
51
53
  }
54
+ const alreadySet = new Set(Object.keys(parsed).filter((key) => process.env[key]));
55
+ for (const key of findReferenceCycles(parsed, alreadySet)) {
56
+ log(`\`${key}\` is part of a circular reference and resolves to an empty string`);
57
+ parsed[key] = "";
58
+ }
59
+ populate(process.env, parsed, { debug: options?.debug });
60
+ parsed = expand({ parsed }).parsed;
52
61
  /**
53
62
  * @see {@linkplain https://github.com/facebook/create-react-app/blob/d960b9e38c062584ff6cfb1a70e1512509a966e7/packages/react-scripts/config/env.js#L72-L89}
54
63
  */
@@ -94,6 +103,67 @@ function filterByPrefix(parsed, prefix, log) {
94
103
  return obj;
95
104
  }, {});
96
105
  }
106
+ /**
107
+ * dotenv reads its own `DOTENV_CONFIG_DEBUG` and `DOTENV_CONFIG_QUIET` switches from the `processEnv` it writes to,
108
+ * so forward the ones set in the real environment to the scratch object used while parsing.
109
+ */
110
+ function dotenvSettingsFromProcessEnv() {
111
+ const settings = {};
112
+ for (const key of ["DOTENV_CONFIG_DEBUG", "DOTENV_CONFIG_QUIET"]) {
113
+ const value = process.env[key];
114
+ if (value !== void 0) settings[key] = value;
115
+ }
116
+ return settings;
117
+ }
118
+ /**
119
+ * Finds the variables that take part in a reference cycle spanning several variables (`A=${B}`, `B=${A}`).
120
+ *
121
+ * dotenv-expand only stops a cycle when a substituted value equals a whole intermediate result, so once a value
122
+ * around the cycle carries a prefix or suffix (e.g. `C=${B}z`) it never terminates. Resolving the variables of such
123
+ * a cycle to an empty string beforehand keeps loading bounded. Variables already set in `process.env` are left out,
124
+ * as `expand` uses their existing value instead of expanding the one from the file. A variable referencing itself
125
+ * is left alone too: dotenv-expand handles that case on its own.
126
+ */
127
+ function findReferenceCycles(parsed, alreadySet) {
128
+ const references = /* @__PURE__ */ new Map();
129
+ for (const [key, value] of Object.entries(parsed)) {
130
+ if (alreadySet.has(key)) continue;
131
+ const targets = /* @__PURE__ */ new Set();
132
+ for (const match of value.matchAll(/(?<!\\)\$\{?([A-Za-z_][A-Za-z0-9_]*)/g)) {
133
+ const target = match[1];
134
+ if (target !== key && target in parsed && !alreadySet.has(target)) targets.add(target);
135
+ }
136
+ references.set(key, [...targets]);
137
+ }
138
+ const cyclic = /* @__PURE__ */ new Set();
139
+ const indexes = /* @__PURE__ */ new Map();
140
+ const lowLinks = /* @__PURE__ */ new Map();
141
+ const stack = [];
142
+ const onStack = /* @__PURE__ */ new Set();
143
+ let counter = 0;
144
+ const visit = (key) => {
145
+ indexes.set(key, counter);
146
+ lowLinks.set(key, counter);
147
+ counter++;
148
+ stack.push(key);
149
+ onStack.add(key);
150
+ for (const target of references.get(key) ?? []) if (!indexes.has(target)) {
151
+ visit(target);
152
+ lowLinks.set(key, Math.min(lowLinks.get(key), lowLinks.get(target)));
153
+ } else if (onStack.has(target)) lowLinks.set(key, Math.min(lowLinks.get(key), indexes.get(target)));
154
+ if (lowLinks.get(key) !== indexes.get(key)) return;
155
+ const component = [];
156
+ let member;
157
+ do {
158
+ member = stack.pop();
159
+ onStack.delete(member);
160
+ component.push(member);
161
+ } while (member !== key);
162
+ if (component.length > 1) for (const item of component) cyclic.add(item);
163
+ };
164
+ for (const key of references.keys()) if (!indexes.has(key)) visit(key);
165
+ return cyclic;
166
+ }
97
167
  function appendSuffix(path, suffix) {
98
168
  if (typeof path === "string") return `${path}${suffix}`;
99
169
  const file = fileURLToPath(path);
@@ -221,4 +291,4 @@ function setup(pathOrOptions) {
221
291
 
222
292
  //#endregion
223
293
  export { envIsUndefined as a, envParseInteger as c, envIsNullish as i, envParseNumber as l, envIsDefined as n, envParseArray as o, envIsNull as r, envParseBoolean as s, setup as t, envParseString as u };
224
- //# sourceMappingURL=src-BHEW4qZd.js.map
294
+ //# sourceMappingURL=src-DEtFY63P.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src-BHEW4qZd.js","names":[],"sources":["../../src/lib/utils.ts","../../src/lib/setup.ts"],"sourcesContent":["import type { Env, EnvAny, EnvArray, EnvBoolean, EnvInteger, EnvNumber, EnvString } from './types';\n\nexport function envParseInteger(key: EnvInteger, defaultValue?: number): number;\nexport function envParseInteger(key: EnvInteger, defaultValue: number | null): number | null;\nexport function envParseInteger(key: EnvInteger, defaultValue?: number | null): number | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be an integer, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tconst integer = Number(value);\n\tif (Number.isInteger(integer)) return integer;\n\tthrow new TypeError(`[ENV] ${key} - The key must be an integer, but received '${value}'.`);\n}\n\nexport function envParseNumber(key: EnvNumber, defaultValue?: number): number;\nexport function envParseNumber(key: EnvNumber, defaultValue: number | null): number | null;\nexport function envParseNumber(key: EnvNumber, defaultValue?: number | null): number | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a number, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tconst integer = Number(value);\n\tif (!Number.isNaN(integer)) return integer;\n\tthrow new TypeError(`[ENV] ${key} - The key must be a number, but received '${value}'.`);\n}\n\nexport function envParseBoolean(key: EnvBoolean, defaultValue?: boolean): boolean;\nexport function envParseBoolean(key: EnvBoolean, defaultValue: boolean | null): boolean | null;\nexport function envParseBoolean(key: EnvBoolean, defaultValue?: boolean | null): boolean | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a boolean, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tif (value.length === 4 && value.toLowerCase() === 'true') return true;\n\tif (value.length === 5 && value.toLowerCase() === 'false') return false;\n\tthrow new TypeError(`[ENV] ${key} - The key must be a boolean, but received '${value}'.`);\n}\n\nexport function envParseString<K extends EnvString>(key: K, defaultValue?: Env[K]): NonNullable<Env[K]>;\nexport function envParseString<K extends EnvString>(key: K, defaultValue: Env[K] | null): NonNullable<Env[K]> | null;\nexport function envParseString<K extends EnvString>(key: K, defaultValue?: Env[K] | null): NonNullable<Env[K]> | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a string, but is empty or undefined.`);\n\t\treturn defaultValue!;\n\t}\n\n\treturn value!;\n}\n\nexport function envParseArray(key: EnvArray, defaultValue?: string[]): string[];\nexport function envParseArray(key: EnvArray, defaultValue: string[] | null): string[] | null;\nexport function envParseArray(key: EnvArray, defaultValue?: string[] | null): string[] | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be an array, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\treturn value.split(' ');\n}\n\n/**\n * Checks if the value of the specified environment variable is null.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - The string `\"0\"`\n * - The string `\"null\"`, case insensitive\n */\nexport function envIsNull(key: EnvAny): boolean {\n\tconst value = process.env[key];\n\treturn typeof value === 'string' && (value === '0' || (value.length === 4 && value.toLowerCase() === 'null'));\n}\n\n/**\n * Checks if the value of the specified environment variable is undefined.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - `undefined`\n * - An empty string (`\"\"`)\n */\nexport function envIsUndefined(key: EnvAny): boolean {\n\tconst value = process.env[key];\n\treturn value === undefined || value.length === 0;\n}\n\n/**\n * Checks if the value of the specified environment variable is nullish.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - `undefined`\n * - An empty string (`\"\"`)\n * - The string `\"0\"`\n * - The string `\"null\"`, case insensitive\n */\nexport function envIsNullish(key: EnvAny): boolean {\n\treturn envIsUndefined(key) || envIsNull(key);\n}\n\n/**\n * Checks if any of the specified environment variables is defined.\n * @param key - The name of the environment variable.\n * @returns Whether the value of any of the specified environment variables is a non-empty string\n */\nexport function envIsDefined(...keys: readonly EnvAny[]): boolean {\n\treturn keys.every((key) => !envIsUndefined(key));\n}\n","import type { DotenvConfigOutput } from 'dotenv';\nimport { fileURLToPath } from 'node:url';\nimport { loadEnvFiles, type EnvLoaderOptions } from './env-loader';\nimport { envIsDefined, envParseBoolean } from './utils';\n\nexport function setup(pathOrOptions?: string | URL | EnvSetupOptions): DotenvConfigOutput {\n\t// Unless explicitly defined, set NODE_ENV as development:\n\tprocess.env.NODE_ENV ??= 'development';\n\n\tlet options: EnvLoaderOptions;\n\tif (typeof pathOrOptions === 'undefined') {\n\t\toptions = {};\n\t} else if (typeof pathOrOptions === 'string') {\n\t\toptions = { path: pathOrOptions };\n\t} else if (typeof pathOrOptions === 'object') {\n\t\tif (pathOrOptions instanceof URL) {\n\t\t\toptions = { path: fileURLToPath(pathOrOptions) };\n\t\t} else {\n\t\t\tconst { path, ...rest } = pathOrOptions;\n\t\t\toptions = { path: typeof path === 'undefined' ? path : typeof path === 'string' ? path : fileURLToPath(path), ...rest };\n\t\t}\n\t} else {\n\t\tthrow new TypeError('Expected undefined, string, URL, or EnvSetupOptions');\n\t}\n\n\treturn loadEnvFiles({\n\t\tdebug: envIsDefined('DOTENV_DEBUG') ? envParseBoolean('DOTENV_DEBUG') : undefined,\n\t\tencoding: process.env.DOTENV_ENCODING,\n\t\tenv: process.env.DOTENV_ENV,\n\t\tpath: process.env.DOTENV_PATH,\n\t\tprefix: process.env.DOTENV_PREFIX,\n\t\tloader: process.env.DOTENV_LOADER,\n\t\t...options\n\t});\n}\n\nexport interface EnvSetupOptions extends Omit<EnvLoaderOptions, 'path'> {\n\t/**\n\t * You may specify a custom path if your file containing environment variables is located elsewhere.\n\t */\n\tpath?: string | URL;\n}\n\nexport type EnvSetupResult = DotenvConfigOutput;\n"],"mappings":"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"}
1
+ {"version":3,"file":"src-DEtFY63P.js","names":[],"sources":["../../src/lib/utils.ts","../../src/lib/setup.ts"],"sourcesContent":["import type { Env, EnvAny, EnvArray, EnvBoolean, EnvInteger, EnvNumber, EnvString } from './types';\n\nexport function envParseInteger(key: EnvInteger, defaultValue?: number): number;\nexport function envParseInteger(key: EnvInteger, defaultValue: number | null): number | null;\nexport function envParseInteger(key: EnvInteger, defaultValue?: number | null): number | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be an integer, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tconst integer = Number(value);\n\tif (Number.isInteger(integer)) return integer;\n\tthrow new TypeError(`[ENV] ${key} - The key must be an integer, but received '${value}'.`);\n}\n\nexport function envParseNumber(key: EnvNumber, defaultValue?: number): number;\nexport function envParseNumber(key: EnvNumber, defaultValue: number | null): number | null;\nexport function envParseNumber(key: EnvNumber, defaultValue?: number | null): number | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a number, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tconst integer = Number(value);\n\tif (!Number.isNaN(integer)) return integer;\n\tthrow new TypeError(`[ENV] ${key} - The key must be a number, but received '${value}'.`);\n}\n\nexport function envParseBoolean(key: EnvBoolean, defaultValue?: boolean): boolean;\nexport function envParseBoolean(key: EnvBoolean, defaultValue: boolean | null): boolean | null;\nexport function envParseBoolean(key: EnvBoolean, defaultValue?: boolean | null): boolean | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a boolean, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\tif (value.length === 4 && value.toLowerCase() === 'true') return true;\n\tif (value.length === 5 && value.toLowerCase() === 'false') return false;\n\tthrow new TypeError(`[ENV] ${key} - The key must be a boolean, but received '${value}'.`);\n}\n\nexport function envParseString<K extends EnvString>(key: K, defaultValue?: Env[K]): NonNullable<Env[K]>;\nexport function envParseString<K extends EnvString>(key: K, defaultValue: Env[K] | null): NonNullable<Env[K]> | null;\nexport function envParseString<K extends EnvString>(key: K, defaultValue?: Env[K] | null): NonNullable<Env[K]> | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be a string, but is empty or undefined.`);\n\t\treturn defaultValue!;\n\t}\n\n\treturn value!;\n}\n\nexport function envParseArray(key: EnvArray, defaultValue?: string[]): string[];\nexport function envParseArray(key: EnvArray, defaultValue: string[] | null): string[] | null;\nexport function envParseArray(key: EnvArray, defaultValue?: string[] | null): string[] | null {\n\tconst value = process.env[key];\n\tif (!value) {\n\t\tif (defaultValue === undefined) throw new ReferenceError(`[ENV] ${key} - The key must be an array, but is empty or undefined.`);\n\t\treturn defaultValue;\n\t}\n\n\treturn value.split(' ');\n}\n\n/**\n * Checks if the value of the specified environment variable is null.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - The string `\"0\"`\n * - The string `\"null\"`, case insensitive\n */\nexport function envIsNull(key: EnvAny): boolean {\n\tconst value = process.env[key];\n\treturn typeof value === 'string' && (value === '0' || (value.length === 4 && value.toLowerCase() === 'null'));\n}\n\n/**\n * Checks if the value of the specified environment variable is undefined.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - `undefined`\n * - An empty string (`\"\"`)\n */\nexport function envIsUndefined(key: EnvAny): boolean {\n\tconst value = process.env[key];\n\treturn value === undefined || value.length === 0;\n}\n\n/**\n * Checks if the value of the specified environment variable is nullish.\n * @param key - The name of the environment variable.\n * @returns Whether the value of the specified environment variable is:\n * - `undefined`\n * - An empty string (`\"\"`)\n * - The string `\"0\"`\n * - The string `\"null\"`, case insensitive\n */\nexport function envIsNullish(key: EnvAny): boolean {\n\treturn envIsUndefined(key) || envIsNull(key);\n}\n\n/**\n * Checks if any of the specified environment variables is defined.\n * @param key - The name of the environment variable.\n * @returns Whether the value of any of the specified environment variables is a non-empty string\n */\nexport function envIsDefined(...keys: readonly EnvAny[]): boolean {\n\treturn keys.every((key) => !envIsUndefined(key));\n}\n","import type { DotenvConfigOutput } from 'dotenv';\nimport { fileURLToPath } from 'node:url';\nimport { loadEnvFiles, type EnvLoaderOptions } from './env-loader';\nimport { envIsDefined, envParseBoolean } from './utils';\n\nexport function setup(pathOrOptions?: string | URL | EnvSetupOptions): DotenvConfigOutput {\n\t// Unless explicitly defined, set NODE_ENV as development:\n\tprocess.env.NODE_ENV ??= 'development';\n\n\tlet options: EnvLoaderOptions;\n\tif (typeof pathOrOptions === 'undefined') {\n\t\toptions = {};\n\t} else if (typeof pathOrOptions === 'string') {\n\t\toptions = { path: pathOrOptions };\n\t} else if (typeof pathOrOptions === 'object') {\n\t\tif (pathOrOptions instanceof URL) {\n\t\t\toptions = { path: fileURLToPath(pathOrOptions) };\n\t\t} else {\n\t\t\tconst { path, ...rest } = pathOrOptions;\n\t\t\toptions = { path: typeof path === 'undefined' ? path : typeof path === 'string' ? path : fileURLToPath(path), ...rest };\n\t\t}\n\t} else {\n\t\tthrow new TypeError('Expected undefined, string, URL, or EnvSetupOptions');\n\t}\n\n\treturn loadEnvFiles({\n\t\tdebug: envIsDefined('DOTENV_DEBUG') ? envParseBoolean('DOTENV_DEBUG') : undefined,\n\t\tencoding: process.env.DOTENV_ENCODING,\n\t\tenv: process.env.DOTENV_ENV,\n\t\tpath: process.env.DOTENV_PATH,\n\t\tprefix: process.env.DOTENV_PREFIX,\n\t\tloader: process.env.DOTENV_LOADER,\n\t\t...options\n\t});\n}\n\nexport interface EnvSetupOptions extends Omit<EnvLoaderOptions, 'path'> {\n\t/**\n\t * You may specify a custom path if your file containing environment variables is located elsewhere.\n\t */\n\tpath?: string | URL;\n}\n\nexport type EnvSetupResult = DotenvConfigOutput;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wolfstar/env-utilities",
3
- "version": "2.2.0",
3
+ "version": "2.2.1-next-20260927142544",
4
4
  "description": "Functional utilities for reading and parsing environmental variables",
5
5
  "keywords": [
6
6
  "api",
@@ -65,12 +65,12 @@
65
65
  },
66
66
  "devDependencies": {
67
67
  "@redstardev/unplugin-version-injector": "^0.0.2",
68
- "@vitest/coverage-v8": "^4.1.11",
68
+ "@vitest/coverage-v8": "^5.0.1",
69
69
  "golar": "^0.1.10",
70
70
  "tsdown": "^0.23.0",
71
71
  "typescript": "~7.0.2",
72
- "varlock": "^1.19.0",
73
- "vitest": "^4.1.11"
72
+ "varlock": "^1.20.0",
73
+ "vitest": "^5.0.1"
74
74
  },
75
75
  "peerDependencies": {
76
76
  "varlock": "^1.19.0"