zod-envkit 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.RU.md +1 -0
- package/README.md +1 -0
- package/dist/{chunk-WWWQDMV5.js → chunk-AGSAWBDX.js} +12 -0
- package/dist/cli/index.cjs +23 -1
- package/dist/cli/index.js +14 -2
- package/dist/index.cjs +13 -0
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [1.5.1](https://github.com/nxtxe/zod-envkit/compare/v1.5.0...v1.5.1) (2026-06-27)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **cli:** fail on empty required dotenv values in check --production ([0c46748](https://github.com/nxtxe/zod-envkit/commit/0c46748e4740c97d7fde7bb1a39b7dd4bb11109e))
|
|
7
|
+
|
|
1
8
|
# [1.5.0](https://github.com/nxtxe/zod-envkit/compare/v1.4.0...v1.5.0) (2026-06-06)
|
|
2
9
|
|
|
3
10
|
|
package/README.RU.md
CHANGED
|
@@ -242,6 +242,7 @@ npx zod-envkit check --production
|
|
|
242
242
|
- завершает процесс с кодом `1`, если отсутствуют обязательные переменные
|
|
243
243
|
- в `--strict` режиме также падает при неизвестных переменных (только ключи из dotenv)
|
|
244
244
|
- с `--production` также падает при неизвестных переменных из dotenv (тот же dotenv-only scope, что у `--strict`)
|
|
245
|
+
- с `--production` также падает, если обязательный ключ есть в dotenv, но пустой после trim (`PORT=`, `PORT=" "`)
|
|
245
246
|
|
|
246
247
|
---
|
|
247
248
|
|
package/README.md
CHANGED
|
@@ -239,6 +239,7 @@ npx zod-envkit check --production
|
|
|
239
239
|
* exits with code `1` if required variables are missing
|
|
240
240
|
* in `--strict` mode also fails on unknown variables (dotenv-loaded keys only)
|
|
241
241
|
* with `--production` also fails on unknown dotenv variables (same dotenv-only scope as `--strict`)
|
|
242
|
+
* with `--production` also fails when a required dotenv key is present but empty after trim (`PORT=`, `PORT=" "`)
|
|
242
243
|
|
|
243
244
|
---
|
|
244
245
|
|
|
@@ -172,6 +172,17 @@ function getMissingEnv(meta, env = process.env) {
|
|
|
172
172
|
}
|
|
173
173
|
return missing;
|
|
174
174
|
}
|
|
175
|
+
function getEmptyRequiredEnv(meta, env) {
|
|
176
|
+
const empty = [];
|
|
177
|
+
for (const [key, m] of Object.entries(meta)) {
|
|
178
|
+
const required = m.required !== false;
|
|
179
|
+
if (!required) continue;
|
|
180
|
+
if (!Object.prototype.hasOwnProperty.call(env, key)) continue;
|
|
181
|
+
if (env[key].trim() === "") empty.push(key);
|
|
182
|
+
}
|
|
183
|
+
empty.sort((a, b) => a.localeCompare(b));
|
|
184
|
+
return empty;
|
|
185
|
+
}
|
|
175
186
|
function getUnknownEnv(meta, env = process.env) {
|
|
176
187
|
const known = new Set(Object.keys(meta));
|
|
177
188
|
const unknown = [];
|
|
@@ -213,6 +224,7 @@ export {
|
|
|
213
224
|
generateEnvExample,
|
|
214
225
|
generateEnvDocs,
|
|
215
226
|
getMissingEnv,
|
|
227
|
+
getEmptyRequiredEnv,
|
|
216
228
|
getUnknownEnv,
|
|
217
229
|
isSecretKey,
|
|
218
230
|
checkEnv
|
package/dist/cli/index.cjs
CHANGED
|
@@ -42,6 +42,7 @@ var messages = {
|
|
|
42
42
|
GENERATED: "Generated: {example}, {docs}",
|
|
43
43
|
ENV_OK: "Environment looks good.",
|
|
44
44
|
MISSING_ENV: "Missing required environment variables:",
|
|
45
|
+
EMPTY_REQUIRED_ENV: "Required environment variables are empty (production; dotenv-loaded keys):",
|
|
45
46
|
UNKNOWN_ENV: "Unknown environment variables (strict mode; only dotenv-loaded keys):",
|
|
46
47
|
INVALID_FORMAT: "Invalid docs format",
|
|
47
48
|
INVALID_MASK_MODE: "Invalid mask mode",
|
|
@@ -69,6 +70,7 @@ var messages = {
|
|
|
69
70
|
GENERATED: "\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043E: {example}, {docs}",
|
|
70
71
|
ENV_OK: "\u041F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F \u0432 \u043F\u043E\u0440\u044F\u0434\u043A\u0435.",
|
|
71
72
|
MISSING_ENV: "\u041E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0442 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F:",
|
|
73
|
+
EMPTY_REQUIRED_ENV: "\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F \u043F\u0443\u0441\u0442\u044B\u0435 (production; \u0442\u043E\u043B\u044C\u043A\u043E \u0438\u0437 dotenv-\u0444\u0430\u0439\u043B\u043E\u0432):",
|
|
72
74
|
UNKNOWN_ENV: "\u041E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D\u044B \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F (strict; \u0442\u043E\u043B\u044C\u043A\u043E \u0438\u0437 dotenv-\u0444\u0430\u0439\u043B\u043E\u0432):",
|
|
73
75
|
INVALID_FORMAT: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u0438",
|
|
74
76
|
INVALID_MASK_MODE: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0440\u0435\u0436\u0438\u043C \u043C\u0430\u0441\u043A\u0438\u0440\u043E\u0432\u043A\u0438",
|
|
@@ -452,6 +454,17 @@ function getMissingEnv(meta, env = process.env) {
|
|
|
452
454
|
}
|
|
453
455
|
return missing;
|
|
454
456
|
}
|
|
457
|
+
function getEmptyRequiredEnv(meta, env) {
|
|
458
|
+
const empty = [];
|
|
459
|
+
for (const [key, m] of Object.entries(meta)) {
|
|
460
|
+
const required = m.required !== false;
|
|
461
|
+
if (!required) continue;
|
|
462
|
+
if (!Object.prototype.hasOwnProperty.call(env, key)) continue;
|
|
463
|
+
if (env[key].trim() === "") empty.push(key);
|
|
464
|
+
}
|
|
465
|
+
empty.sort((a, b) => a.localeCompare(b));
|
|
466
|
+
return empty;
|
|
467
|
+
}
|
|
455
468
|
function getUnknownEnv(meta, env = process.env) {
|
|
456
469
|
const known = new Set(Object.keys(meta));
|
|
457
470
|
const unknown = [];
|
|
@@ -652,12 +665,21 @@ function registerCheck(program2, getLang2) {
|
|
|
652
665
|
const loaded = loadDotEnv(opts.dotenv);
|
|
653
666
|
const { meta } = loadMeta(lang, opts.config);
|
|
654
667
|
const sections = [];
|
|
655
|
-
const
|
|
668
|
+
const emptyRequired = production ? getEmptyRequiredEnv(meta, loaded.env) : [];
|
|
669
|
+
const emptyRequiredSet = new Set(emptyRequired);
|
|
670
|
+
const missing = getMissingEnv(meta, process.env).filter(
|
|
671
|
+
(key) => !emptyRequiredSet.has(key)
|
|
672
|
+
);
|
|
656
673
|
if (missing.length) {
|
|
657
674
|
sections.push(t(lang, "MISSING_ENV"));
|
|
658
675
|
missing.forEach((k) => sections.push(`- ${k}`));
|
|
659
676
|
sections.push("");
|
|
660
677
|
}
|
|
678
|
+
if (production && emptyRequired.length) {
|
|
679
|
+
sections.push(t(lang, "EMPTY_REQUIRED_ENV"));
|
|
680
|
+
emptyRequired.forEach((k) => sections.push(`- ${k}`));
|
|
681
|
+
sections.push("");
|
|
682
|
+
}
|
|
661
683
|
if (strictEffective) {
|
|
662
684
|
const unknown = getUnknownEnv(meta, loaded.env);
|
|
663
685
|
if (unknown.length) {
|
package/dist/cli/index.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
import {
|
|
3
3
|
generateEnvDocs,
|
|
4
4
|
generateEnvExample,
|
|
5
|
+
getEmptyRequiredEnv,
|
|
5
6
|
getMissingEnv,
|
|
6
7
|
getUnknownEnv,
|
|
7
8
|
isSecretKey
|
|
8
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-AGSAWBDX.js";
|
|
9
10
|
|
|
10
11
|
// src/cli/index.ts
|
|
11
12
|
import { Command } from "commander";
|
|
@@ -26,6 +27,7 @@ var messages = {
|
|
|
26
27
|
GENERATED: "Generated: {example}, {docs}",
|
|
27
28
|
ENV_OK: "Environment looks good.",
|
|
28
29
|
MISSING_ENV: "Missing required environment variables:",
|
|
30
|
+
EMPTY_REQUIRED_ENV: "Required environment variables are empty (production; dotenv-loaded keys):",
|
|
29
31
|
UNKNOWN_ENV: "Unknown environment variables (strict mode; only dotenv-loaded keys):",
|
|
30
32
|
INVALID_FORMAT: "Invalid docs format",
|
|
31
33
|
INVALID_MASK_MODE: "Invalid mask mode",
|
|
@@ -53,6 +55,7 @@ var messages = {
|
|
|
53
55
|
GENERATED: "\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043E: {example}, {docs}",
|
|
54
56
|
ENV_OK: "\u041F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F \u0432 \u043F\u043E\u0440\u044F\u0434\u043A\u0435.",
|
|
55
57
|
MISSING_ENV: "\u041E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0442 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F:",
|
|
58
|
+
EMPTY_REQUIRED_ENV: "\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F \u043F\u0443\u0441\u0442\u044B\u0435 (production; \u0442\u043E\u043B\u044C\u043A\u043E \u0438\u0437 dotenv-\u0444\u0430\u0439\u043B\u043E\u0432):",
|
|
56
59
|
UNKNOWN_ENV: "\u041E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D\u044B \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F (strict; \u0442\u043E\u043B\u044C\u043A\u043E \u0438\u0437 dotenv-\u0444\u0430\u0439\u043B\u043E\u0432):",
|
|
57
60
|
INVALID_FORMAT: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u0438",
|
|
58
61
|
INVALID_MASK_MODE: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0440\u0435\u0436\u0438\u043C \u043C\u0430\u0441\u043A\u0438\u0440\u043E\u0432\u043A\u0438",
|
|
@@ -431,12 +434,21 @@ function registerCheck(program2, getLang2) {
|
|
|
431
434
|
const loaded = loadDotEnv(opts.dotenv);
|
|
432
435
|
const { meta } = loadMeta(lang, opts.config);
|
|
433
436
|
const sections = [];
|
|
434
|
-
const
|
|
437
|
+
const emptyRequired = production ? getEmptyRequiredEnv(meta, loaded.env) : [];
|
|
438
|
+
const emptyRequiredSet = new Set(emptyRequired);
|
|
439
|
+
const missing = getMissingEnv(meta, process.env).filter(
|
|
440
|
+
(key) => !emptyRequiredSet.has(key)
|
|
441
|
+
);
|
|
435
442
|
if (missing.length) {
|
|
436
443
|
sections.push(t(lang, "MISSING_ENV"));
|
|
437
444
|
missing.forEach((k) => sections.push(`- ${k}`));
|
|
438
445
|
sections.push("");
|
|
439
446
|
}
|
|
447
|
+
if (production && emptyRequired.length) {
|
|
448
|
+
sections.push(t(lang, "EMPTY_REQUIRED_ENV"));
|
|
449
|
+
emptyRequired.forEach((k) => sections.push(`- ${k}`));
|
|
450
|
+
sections.push("");
|
|
451
|
+
}
|
|
440
452
|
if (strictEffective) {
|
|
441
453
|
const unknown = getUnknownEnv(meta, loaded.env);
|
|
442
454
|
if (unknown.length) {
|
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
formatZodError: () => formatZodError,
|
|
25
25
|
generateEnvDocs: () => generateEnvDocs,
|
|
26
26
|
generateEnvExample: () => generateEnvExample,
|
|
27
|
+
getEmptyRequiredEnv: () => getEmptyRequiredEnv,
|
|
27
28
|
getMissingEnv: () => getMissingEnv,
|
|
28
29
|
getUnknownEnv: () => getUnknownEnv,
|
|
29
30
|
isSecretKey: () => isSecretKey,
|
|
@@ -207,6 +208,17 @@ function getMissingEnv(meta, env = process.env) {
|
|
|
207
208
|
}
|
|
208
209
|
return missing;
|
|
209
210
|
}
|
|
211
|
+
function getEmptyRequiredEnv(meta, env) {
|
|
212
|
+
const empty = [];
|
|
213
|
+
for (const [key, m] of Object.entries(meta)) {
|
|
214
|
+
const required = m.required !== false;
|
|
215
|
+
if (!required) continue;
|
|
216
|
+
if (!Object.prototype.hasOwnProperty.call(env, key)) continue;
|
|
217
|
+
if (env[key].trim() === "") empty.push(key);
|
|
218
|
+
}
|
|
219
|
+
empty.sort((a, b) => a.localeCompare(b));
|
|
220
|
+
return empty;
|
|
221
|
+
}
|
|
210
222
|
function getUnknownEnv(meta, env = process.env) {
|
|
211
223
|
const known = new Set(Object.keys(meta));
|
|
212
224
|
const unknown = [];
|
|
@@ -272,6 +284,7 @@ function formatZodError(err) {
|
|
|
272
284
|
formatZodError,
|
|
273
285
|
generateEnvDocs,
|
|
274
286
|
generateEnvExample,
|
|
287
|
+
getEmptyRequiredEnv,
|
|
275
288
|
getMissingEnv,
|
|
276
289
|
getUnknownEnv,
|
|
277
290
|
isSecretKey,
|
package/dist/index.d.cts
CHANGED
|
@@ -169,6 +169,16 @@ type EnvCheckResult = {
|
|
|
169
169
|
* @since 1.2.0
|
|
170
170
|
*/
|
|
171
171
|
declare function getMissingEnv(meta: EnvMeta, env?: NodeJS.ProcessEnv): string[];
|
|
172
|
+
/**
|
|
173
|
+
* Return required keys from `meta` that are present in `env` but empty after trim.
|
|
174
|
+
*
|
|
175
|
+
* Used by the CLI in `--production` mode to catch dotenv entries like `PORT=` or `PORT=" "`
|
|
176
|
+
* without changing default `check` behavior for whitespace-only values.
|
|
177
|
+
*
|
|
178
|
+
* @public
|
|
179
|
+
* @since 1.5.1
|
|
180
|
+
*/
|
|
181
|
+
declare function getEmptyRequiredEnv(meta: EnvMeta, env: Record<string, string>): string[];
|
|
172
182
|
/**
|
|
173
183
|
* Return keys present in `env` that are not defined in `meta`.
|
|
174
184
|
*
|
|
@@ -300,4 +310,4 @@ declare function mustLoadEnv<T extends z.ZodTypeAny>(schema: T): z.infer<T>;
|
|
|
300
310
|
*/
|
|
301
311
|
declare function formatZodError(err: z.ZodError): string;
|
|
302
312
|
|
|
303
|
-
export { type DocsFormat, type EnvCheckResult, type EnvMeta, type EnvMetaEntry, type GenerateDocsOptions, type LoadEnvFail, type LoadEnvOk, type LoadEnvOptions, type SortMode, checkEnv, formatZodError, generateEnvDocs, generateEnvExample, getMissingEnv, getUnknownEnv, isSecretKey, loadEnv, mustLoadEnv, sortMetaEntries };
|
|
313
|
+
export { type DocsFormat, type EnvCheckResult, type EnvMeta, type EnvMetaEntry, type GenerateDocsOptions, type LoadEnvFail, type LoadEnvOk, type LoadEnvOptions, type SortMode, checkEnv, formatZodError, generateEnvDocs, generateEnvExample, getEmptyRequiredEnv, getMissingEnv, getUnknownEnv, isSecretKey, loadEnv, mustLoadEnv, sortMetaEntries };
|
package/dist/index.d.ts
CHANGED
|
@@ -169,6 +169,16 @@ type EnvCheckResult = {
|
|
|
169
169
|
* @since 1.2.0
|
|
170
170
|
*/
|
|
171
171
|
declare function getMissingEnv(meta: EnvMeta, env?: NodeJS.ProcessEnv): string[];
|
|
172
|
+
/**
|
|
173
|
+
* Return required keys from `meta` that are present in `env` but empty after trim.
|
|
174
|
+
*
|
|
175
|
+
* Used by the CLI in `--production` mode to catch dotenv entries like `PORT=` or `PORT=" "`
|
|
176
|
+
* without changing default `check` behavior for whitespace-only values.
|
|
177
|
+
*
|
|
178
|
+
* @public
|
|
179
|
+
* @since 1.5.1
|
|
180
|
+
*/
|
|
181
|
+
declare function getEmptyRequiredEnv(meta: EnvMeta, env: Record<string, string>): string[];
|
|
172
182
|
/**
|
|
173
183
|
* Return keys present in `env` that are not defined in `meta`.
|
|
174
184
|
*
|
|
@@ -300,4 +310,4 @@ declare function mustLoadEnv<T extends z.ZodTypeAny>(schema: T): z.infer<T>;
|
|
|
300
310
|
*/
|
|
301
311
|
declare function formatZodError(err: z.ZodError): string;
|
|
302
312
|
|
|
303
|
-
export { type DocsFormat, type EnvCheckResult, type EnvMeta, type EnvMetaEntry, type GenerateDocsOptions, type LoadEnvFail, type LoadEnvOk, type LoadEnvOptions, type SortMode, checkEnv, formatZodError, generateEnvDocs, generateEnvExample, getMissingEnv, getUnknownEnv, isSecretKey, loadEnv, mustLoadEnv, sortMetaEntries };
|
|
313
|
+
export { type DocsFormat, type EnvCheckResult, type EnvMeta, type EnvMetaEntry, type GenerateDocsOptions, type LoadEnvFail, type LoadEnvOk, type LoadEnvOptions, type SortMode, checkEnv, formatZodError, generateEnvDocs, generateEnvExample, getEmptyRequiredEnv, getMissingEnv, getUnknownEnv, isSecretKey, loadEnv, mustLoadEnv, sortMetaEntries };
|
package/dist/index.js
CHANGED
|
@@ -2,11 +2,12 @@ import {
|
|
|
2
2
|
checkEnv,
|
|
3
3
|
generateEnvDocs,
|
|
4
4
|
generateEnvExample,
|
|
5
|
+
getEmptyRequiredEnv,
|
|
5
6
|
getMissingEnv,
|
|
6
7
|
getUnknownEnv,
|
|
7
8
|
isSecretKey,
|
|
8
9
|
sortMetaEntries
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-AGSAWBDX.js";
|
|
10
11
|
|
|
11
12
|
// src/index.ts
|
|
12
13
|
function loadEnv(schema, opts) {
|
|
@@ -36,6 +37,7 @@ export {
|
|
|
36
37
|
formatZodError,
|
|
37
38
|
generateEnvDocs,
|
|
38
39
|
generateEnvExample,
|
|
40
|
+
getEmptyRequiredEnv,
|
|
39
41
|
getMissingEnv,
|
|
40
42
|
getUnknownEnv,
|
|
41
43
|
isSecretKey,
|