env-typed-checker 0.2.0 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  EnvDoctorError,
3
3
  envDoctor
4
- } from "./chunk-U6GH2TRS.mjs";
4
+ } from "./chunk-L5DK6LRX.mjs";
5
5
  export {
6
6
  EnvDoctorError,
7
7
  envDoctor
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "env-typed-checker",
3
- "version": "0.2.0",
3
+ "version": "0.2.3",
4
4
  "description": "Validate and parse environment variables with a tiny, type-safe schema.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -1,126 +0,0 @@
1
- // src/index.ts
2
- import * as dotenv from "dotenv";
3
-
4
- // src/error.ts
5
- var EnvDoctorError = class extends Error {
6
- constructor(issues) {
7
- const header = "ENV validation failed";
8
- const lines = issues.map((i) => `- ${i.key}: ${i.message}`);
9
- super([header, ...lines].join("\n"));
10
- this.name = "EnvDoctorError";
11
- this.issues = issues;
12
- }
13
- };
14
-
15
- // src/parsers.ts
16
- function parseByType(type, raw) {
17
- switch (type) {
18
- case "string":
19
- return raw;
20
- case "number": {
21
- const n = Number(raw.trim());
22
- if (!Number.isFinite(n)) {
23
- throw new Error(`expected number, got "${raw}"`);
24
- }
25
- return n;
26
- }
27
- case "boolean": {
28
- const v = raw.trim().toLowerCase();
29
- if (["true", "1", "yes", "y", "on"].includes(v)) return true;
30
- if (["false", "0", "no", "n", "off"].includes(v)) return false;
31
- throw new Error(
32
- `expected boolean (true/false/1/0/yes/no/on/off), got "${raw}"`
33
- );
34
- }
35
- case "json": {
36
- try {
37
- return JSON.parse(raw);
38
- } catch {
39
- throw new Error(`expected json, got "${raw}"`);
40
- }
41
- }
42
- case "url": {
43
- try {
44
- new URL(raw);
45
- return raw;
46
- } catch {
47
- throw new Error(`expected url, got "${raw}"`);
48
- }
49
- }
50
- /* v8 ignore next -- @preserve */
51
- default: {
52
- const _never = type;
53
- return _never;
54
- }
55
- }
56
- }
57
- function splitOptional(schemaValue) {
58
- const optional = schemaValue.endsWith("?");
59
- const base = optional ? schemaValue.slice(0, -1) : schemaValue;
60
- const allowed = ["string", "number", "boolean", "json", "url"];
61
- if (!allowed.includes(base)) {
62
- throw new Error(
63
- `Unsupported type "${schemaValue}". Supported: string, number, boolean, json, url (optional with ?)`
64
- );
65
- }
66
- return { baseType: base, optional };
67
- }
68
-
69
- // src/validator.ts
70
- function validateAndParse(schema, env) {
71
- const issues = [];
72
- const out = {};
73
- for (const [key, schemaValue] of Object.entries(schema)) {
74
- let baseType;
75
- let optional;
76
- try {
77
- ({ baseType, optional } = splitOptional(schemaValue));
78
- } catch (e) {
79
- issues.push({
80
- key,
81
- kind: "invalid",
82
- message: String(e)
83
- });
84
- continue;
85
- }
86
- const raw = env[key];
87
- if (raw === void 0 || raw === "") {
88
- if (optional) {
89
- out[key] = void 0;
90
- } else {
91
- issues.push({
92
- key,
93
- kind: "missing",
94
- message: "missing required environment variable"
95
- });
96
- }
97
- continue;
98
- }
99
- try {
100
- out[key] = parseByType(baseType, raw);
101
- } catch (e) {
102
- issues.push({
103
- key,
104
- kind: "invalid",
105
- message: String(e)
106
- });
107
- }
108
- }
109
- if (issues.length > 0) {
110
- throw new EnvDoctorError(issues);
111
- }
112
- return out;
113
- }
114
-
115
- // src/index.ts
116
- function envDoctor(schema, options = {}) {
117
- const { loadDotEnv = true, env = process.env } = options;
118
- if (loadDotEnv) dotenv.config();
119
- return validateAndParse(schema, env);
120
- }
121
-
122
- export {
123
- EnvDoctorError,
124
- envDoctor
125
- };
126
- //# sourceMappingURL=chunk-U6GH2TRS.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../src/error.ts","../src/parsers.ts","../src/validator.ts"],"sourcesContent":["import * as dotenv from \"dotenv\";\nimport { validateAndParse } from \"./validator\";\nimport type { EnvDoctorOptions, EnvDoctorResult, EnvDoctorSchema } from \"./types\";\n\nexport type { EnvDoctorOptions, EnvDoctorSchema } from \"./types\";\nexport { EnvDoctorError } from \"./error\";\n\nexport function envDoctor<TSchema extends EnvDoctorSchema>(\n schema: TSchema,\n options: EnvDoctorOptions = {}\n): EnvDoctorResult<TSchema> {\n const { loadDotEnv = true, env = process.env } = options;\n\n if (loadDotEnv) dotenv.config();\n\n return validateAndParse(schema, env);\n}\n","export type EnvDoctorIssue =\n | { key: string; kind: \"missing\"; message: string }\n | { key: string; kind: \"invalid\"; message: string };\n\nexport class EnvDoctorError extends Error {\n public readonly issues: EnvDoctorIssue[];\n\n constructor(issues: EnvDoctorIssue[]) {\n const header = \"ENV validation failed\";\n const lines = issues.map((i) => `- ${i.key}: ${i.message}`);\n super([header, ...lines].join(\"\\n\"));\n this.name = \"EnvDoctorError\";\n this.issues = issues;\n }\n}\n","import type { EnvBaseType } from \"./types\";\n\nexport function parseByType(type: EnvBaseType, raw: string): unknown {\n switch (type) {\n case \"string\":\n return raw;\n\n case \"number\": {\n // Trim to handle \" 3000 \"\n const n = Number(raw.trim());\n if (!Number.isFinite(n)) {\n throw new Error(`expected number, got \"${raw}\"`);\n }\n return n;\n }\n\n case \"boolean\": {\n const v = raw.trim().toLowerCase();\n if ([\"true\", \"1\", \"yes\", \"y\", \"on\"].includes(v)) return true;\n if ([\"false\", \"0\", \"no\", \"n\", \"off\"].includes(v)) return false;\n throw new Error(\n `expected boolean (true/false/1/0/yes/no/on/off), got \"${raw}\"`,\n );\n }\n\n case \"json\": {\n try {\n return JSON.parse(raw);\n } catch {\n throw new Error(`expected json, got \"${raw}\"`);\n }\n }\n\n case \"url\": {\n try {\n // If it doesn't parse as a URL, this throws.\n // We return the original string (common for configs).\n new URL(raw);\n return raw;\n } catch {\n throw new Error(`expected url, got \"${raw}\"`);\n }\n }\n\n /* v8 ignore next -- @preserve */\n default: {\n // Exhaustive check (unreachable at runtime)\n const _never: never = type;\n return _never;\n }\n }\n}\n\nexport function splitOptional(schemaValue: string): {\n baseType: EnvBaseType;\n optional: boolean;\n} {\n const optional = schemaValue.endsWith(\"?\");\n const base = optional ? schemaValue.slice(0, -1) : schemaValue;\n\n // runtime safety\n const allowed = [\"string\", \"number\", \"boolean\", \"json\", \"url\"] as const;\n if (!allowed.includes(base as any)) {\n throw new Error(\n `Unsupported type \"${schemaValue}\". Supported: string, number, boolean, json, url (optional with ?)`,\n );\n }\n\n return { baseType: base as EnvBaseType, optional };\n}\n","import { EnvDoctorError, type EnvDoctorIssue } from \"./error\";\nimport { parseByType, splitOptional } from \"./parsers\";\nimport type { EnvDoctorResult, EnvDoctorSchema } from \"./types\";\n\nexport function validateAndParse<TSchema extends EnvDoctorSchema>(\n schema: TSchema,\n env: Record<string, string | undefined>,\n): EnvDoctorResult<TSchema> {\n const issues: EnvDoctorIssue[] = [];\n const out: Record<string, unknown> = {};\n\n for (const [key, schemaValue] of Object.entries(schema)) {\n let baseType: any;\n let optional: boolean;\n\n try {\n ({ baseType, optional } = splitOptional(schemaValue));\n } catch (e) {\n issues.push({\n key,\n kind: \"invalid\",\n message: String(e),\n });\n continue;\n }\n\n const raw = env[key];\n\n if (raw === undefined || raw === \"\") {\n if (optional) {\n out[key] = undefined;\n } else {\n issues.push({\n key,\n kind: \"missing\",\n message: \"missing required environment variable\",\n });\n }\n continue;\n }\n\n try {\n out[key] = parseByType(baseType, raw);\n } catch (e) {\n issues.push({\n key,\n kind: \"invalid\",\n message: String(e),\n });\n }\n }\n\n if (issues.length > 0) {\n throw new EnvDoctorError(issues);\n }\n\n return out as EnvDoctorResult<TSchema>;\n}\n"],"mappings":";AAAA,YAAY,YAAY;;;ACIjB,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAGxC,YAAY,QAA0B;AACpC,UAAM,SAAS;AACf,UAAM,QAAQ,OAAO,IAAI,CAAC,MAAM,KAAK,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE;AAC1D,UAAM,CAAC,QAAQ,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;AACnC,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AACF;;;ACZO,SAAS,YAAY,MAAmB,KAAsB;AACnE,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IAET,KAAK,UAAU;AAEb,YAAM,IAAI,OAAO,IAAI,KAAK,CAAC;AAC3B,UAAI,CAAC,OAAO,SAAS,CAAC,GAAG;AACvB,cAAM,IAAI,MAAM,yBAAyB,GAAG,GAAG;AAAA,MACjD;AACA,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,WAAW;AACd,YAAM,IAAI,IAAI,KAAK,EAAE,YAAY;AACjC,UAAI,CAAC,QAAQ,KAAK,OAAO,KAAK,IAAI,EAAE,SAAS,CAAC,EAAG,QAAO;AACxD,UAAI,CAAC,SAAS,KAAK,MAAM,KAAK,KAAK,EAAE,SAAS,CAAC,EAAG,QAAO;AACzD,YAAM,IAAI;AAAA,QACR,yDAAyD,GAAG;AAAA,MAC9D;AAAA,IACF;AAAA,IAEA,KAAK,QAAQ;AACX,UAAI;AACF,eAAO,KAAK,MAAM,GAAG;AAAA,MACvB,QAAQ;AACN,cAAM,IAAI,MAAM,uBAAuB,GAAG,GAAG;AAAA,MAC/C;AAAA,IACF;AAAA,IAEA,KAAK,OAAO;AACV,UAAI;AAGF,YAAI,IAAI,GAAG;AACX,eAAO;AAAA,MACT,QAAQ;AACN,cAAM,IAAI,MAAM,sBAAsB,GAAG,GAAG;AAAA,MAC9C;AAAA,IACF;AAAA;AAAA,IAGA,SAAS;AAEP,YAAM,SAAgB;AACtB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,cAAc,aAG5B;AACA,QAAM,WAAW,YAAY,SAAS,GAAG;AACzC,QAAM,OAAO,WAAW,YAAY,MAAM,GAAG,EAAE,IAAI;AAGnD,QAAM,UAAU,CAAC,UAAU,UAAU,WAAW,QAAQ,KAAK;AAC7D,MAAI,CAAC,QAAQ,SAAS,IAAW,GAAG;AAClC,UAAM,IAAI;AAAA,MACR,qBAAqB,WAAW;AAAA,IAClC;AAAA,EACF;AAEA,SAAO,EAAE,UAAU,MAAqB,SAAS;AACnD;;;ACjEO,SAAS,iBACd,QACA,KAC0B;AAC1B,QAAM,SAA2B,CAAC;AAClC,QAAM,MAA+B,CAAC;AAEtC,aAAW,CAAC,KAAK,WAAW,KAAK,OAAO,QAAQ,MAAM,GAAG;AACvD,QAAI;AACJ,QAAI;AAEJ,QAAI;AACF,OAAC,EAAE,UAAU,SAAS,IAAI,cAAc,WAAW;AAAA,IACrD,SAAS,GAAG;AACV,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM;AAAA,QACN,SAAS,OAAO,CAAC;AAAA,MACnB,CAAC;AACD;AAAA,IACF;AAEA,UAAM,MAAM,IAAI,GAAG;AAEnB,QAAI,QAAQ,UAAa,QAAQ,IAAI;AACnC,UAAI,UAAU;AACZ,YAAI,GAAG,IAAI;AAAA,MACb,OAAO;AACL,eAAO,KAAK;AAAA,UACV;AAAA,UACA,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AACA;AAAA,IACF;AAEA,QAAI;AACF,UAAI,GAAG,IAAI,YAAY,UAAU,GAAG;AAAA,IACtC,SAAS,GAAG;AACV,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM;AAAA,QACN,SAAS,OAAO,CAAC;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,IAAI,eAAe,MAAM;AAAA,EACjC;AAEA,SAAO;AACT;;;AHlDO,SAAS,UACd,QACA,UAA4B,CAAC,GACH;AAC1B,QAAM,EAAE,aAAa,MAAM,MAAM,QAAQ,IAAI,IAAI;AAEjD,MAAI,WAAY,CAAO,cAAO;AAE9B,SAAO,iBAAiB,QAAQ,GAAG;AACrC;","names":[]}
package/dist/cli.js DELETED
@@ -1,247 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/cli.ts
31
- var cli_exports = {};
32
- __export(cli_exports, {
33
- runCli: () => runCli
34
- });
35
- module.exports = __toCommonJS(cli_exports);
36
- var import_node_fs = __toESM(require("fs"));
37
- var import_node_path = __toESM(require("path"));
38
- var dotenv2 = __toESM(require("dotenv"));
39
-
40
- // src/index.ts
41
- var dotenv = __toESM(require("dotenv"));
42
-
43
- // src/error.ts
44
- var EnvDoctorError = class extends Error {
45
- constructor(issues) {
46
- const header = "ENV validation failed";
47
- const lines = issues.map((i) => `- ${i.key}: ${i.message}`);
48
- super([header, ...lines].join("\n"));
49
- this.name = "EnvDoctorError";
50
- this.issues = issues;
51
- }
52
- };
53
-
54
- // src/parsers.ts
55
- function parseByType(type, raw) {
56
- switch (type) {
57
- case "string":
58
- return raw;
59
- case "number": {
60
- const n = Number(raw.trim());
61
- if (!Number.isFinite(n)) {
62
- throw new Error(`expected number, got "${raw}"`);
63
- }
64
- return n;
65
- }
66
- case "boolean": {
67
- const v = raw.trim().toLowerCase();
68
- if (["true", "1", "yes", "y", "on"].includes(v)) return true;
69
- if (["false", "0", "no", "n", "off"].includes(v)) return false;
70
- throw new Error(
71
- `expected boolean (true/false/1/0/yes/no/on/off), got "${raw}"`
72
- );
73
- }
74
- case "json": {
75
- try {
76
- return JSON.parse(raw);
77
- } catch {
78
- throw new Error(`expected json, got "${raw}"`);
79
- }
80
- }
81
- case "url": {
82
- try {
83
- new URL(raw);
84
- return raw;
85
- } catch {
86
- throw new Error(`expected url, got "${raw}"`);
87
- }
88
- }
89
- /* v8 ignore next -- @preserve */
90
- default: {
91
- const _never = type;
92
- return _never;
93
- }
94
- }
95
- }
96
- function splitOptional(schemaValue) {
97
- const optional = schemaValue.endsWith("?");
98
- const base = optional ? schemaValue.slice(0, -1) : schemaValue;
99
- const allowed = ["string", "number", "boolean", "json", "url"];
100
- if (!allowed.includes(base)) {
101
- throw new Error(
102
- `Unsupported type "${schemaValue}". Supported: string, number, boolean, json, url (optional with ?)`
103
- );
104
- }
105
- return { baseType: base, optional };
106
- }
107
-
108
- // src/validator.ts
109
- function validateAndParse(schema, env) {
110
- const issues = [];
111
- const out = {};
112
- for (const [key, schemaValue] of Object.entries(schema)) {
113
- let baseType;
114
- let optional;
115
- try {
116
- ({ baseType, optional } = splitOptional(schemaValue));
117
- } catch (e) {
118
- issues.push({
119
- key,
120
- kind: "invalid",
121
- message: String(e)
122
- });
123
- continue;
124
- }
125
- const raw = env[key];
126
- if (raw === void 0 || raw === "") {
127
- if (optional) {
128
- out[key] = void 0;
129
- } else {
130
- issues.push({
131
- key,
132
- kind: "missing",
133
- message: "missing required environment variable"
134
- });
135
- }
136
- continue;
137
- }
138
- try {
139
- out[key] = parseByType(baseType, raw);
140
- } catch (e) {
141
- issues.push({
142
- key,
143
- kind: "invalid",
144
- message: String(e)
145
- });
146
- }
147
- }
148
- if (issues.length > 0) {
149
- throw new EnvDoctorError(issues);
150
- }
151
- return out;
152
- }
153
-
154
- // src/index.ts
155
- function envDoctor(schema, options = {}) {
156
- const { loadDotEnv = true, env = process.env } = options;
157
- if (loadDotEnv) dotenv.config();
158
- return validateAndParse(schema, env);
159
- }
160
-
161
- // src/cli.ts
162
- function parseArgs(argv) {
163
- const out = { useDotenv: true };
164
- const [cmd, ...rest] = argv;
165
- out.cmd = cmd;
166
- for (let i = 0; i < rest.length; i++) {
167
- const a = rest[i];
168
- if (a === "--schema") {
169
- out.schemaPath = rest[++i];
170
- } else if (a.startsWith("--schema=")) {
171
- out.schemaPath = a.split("=", 2)[1];
172
- } else if (a === "--env-file") {
173
- out.envFile = rest[++i];
174
- } else if (a.startsWith("--env-file=")) {
175
- out.envFile = a.split("=", 2)[1];
176
- } else if (a === "--no-dotenv") {
177
- out.useDotenv = false;
178
- }
179
- }
180
- return out;
181
- }
182
- function loadSchema(schemaPath) {
183
- const abs = import_node_path.default.resolve(process.cwd(), schemaPath);
184
- const raw = import_node_fs.default.readFileSync(abs, "utf8");
185
- const json = JSON.parse(raw);
186
- if (!json || typeof json !== "object" || Array.isArray(json)) {
187
- throw new Error("Schema must be a JSON object of key -> type.");
188
- }
189
- for (const [k, v] of Object.entries(json)) {
190
- if (typeof k !== "string" || typeof v !== "string") {
191
- throw new Error("Schema must be a JSON object of string -> string.");
192
- }
193
- }
194
- return json;
195
- }
196
- function runCli(argv, io = console) {
197
- const { cmd, schemaPath, envFile, useDotenv } = parseArgs(argv);
198
- if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") {
199
- io.log(
200
- [
201
- "env-typed-checker",
202
- "",
203
- "Usage:",
204
- " env-typed-checker check --schema <file> [--env-file <file>] [--no-dotenv]",
205
- "",
206
- "Options:",
207
- " --schema <file> Path to schema JSON (required)",
208
- " --env-file <file> Env file path (default: .env)",
209
- " --no-dotenv Do not load env file; use process.env only",
210
- "",
211
- "Exit codes:",
212
- " 0 = OK, 1 = validation failed, 2 = CLI error"
213
- ].join("\n")
214
- );
215
- return 0;
216
- }
217
- if (cmd !== "check") {
218
- io.error(`Unknown command: ${cmd}`);
219
- return 2;
220
- }
221
- if (!schemaPath) {
222
- io.error("Missing required option: --schema <file>");
223
- return 2;
224
- }
225
- try {
226
- if (useDotenv) {
227
- const p = envFile ?? ".env";
228
- dotenv2.config({ path: import_node_path.default.resolve(process.cwd(), p) });
229
- }
230
- const schema = loadSchema(schemaPath);
231
- envDoctor(schema, { loadDotEnv: false, env: process.env });
232
- io.log("\u2705 Environment is valid.");
233
- return 0;
234
- } catch (e) {
235
- if (e instanceof EnvDoctorError) {
236
- io.error(e.message);
237
- return 1;
238
- }
239
- io.error(String(e));
240
- return 2;
241
- }
242
- }
243
- // Annotate the CommonJS export names for ESM import in node:
244
- 0 && (module.exports = {
245
- runCli
246
- });
247
- //# sourceMappingURL=cli.js.map
package/dist/cli.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/index.ts","../src/error.ts","../src/parsers.ts","../src/validator.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport * as dotenv from \"dotenv\";\nimport { envDoctor, EnvDoctorError } from \"./index\";\nimport type { EnvDoctorSchema } from \"./types\";\n\ntype Io = {\n log: (msg: string) => void;\n error: (msg: string) => void;\n};\n\nfunction parseArgs(argv: string[]) {\n const out: {\n cmd?: string;\n schemaPath?: string;\n envFile?: string;\n useDotenv: boolean;\n } = { useDotenv: true };\n\n const [cmd, ...rest] = argv;\n out.cmd = cmd;\n\n for (let i = 0; i < rest.length; i++) {\n const a = rest[i];\n\n if (a === \"--schema\") {\n out.schemaPath = rest[++i];\n } else if (a.startsWith(\"--schema=\")) {\n out.schemaPath = a.split(\"=\", 2)[1];\n } else if (a === \"--env-file\") {\n out.envFile = rest[++i];\n } else if (a.startsWith(\"--env-file=\")) {\n out.envFile = a.split(\"=\", 2)[1];\n } else if (a === \"--no-dotenv\") {\n out.useDotenv = false;\n }\n }\n\n return out;\n}\n\nfunction loadSchema(schemaPath: string): EnvDoctorSchema {\n const abs = path.resolve(process.cwd(), schemaPath);\n const raw = fs.readFileSync(abs, \"utf8\");\n const json = JSON.parse(raw);\n\n if (!json || typeof json !== \"object\" || Array.isArray(json)) {\n throw new Error(\"Schema must be a JSON object of key -> type.\");\n }\n\n // Ensure values are strings\n for (const [k, v] of Object.entries(json)) {\n if (typeof k !== \"string\" || typeof v !== \"string\") {\n throw new Error(\"Schema must be a JSON object of string -> string.\");\n }\n }\n\n return json as EnvDoctorSchema;\n}\n\nexport function runCli(argv: string[], io: Io = console): number {\n const { cmd, schemaPath, envFile, useDotenv } = parseArgs(argv);\n\n if (!cmd || cmd === \"help\" || cmd === \"--help\" || cmd === \"-h\") {\n io.log(\n [\n \"env-typed-checker\",\n \"\",\n \"Usage:\",\n \" env-typed-checker check --schema <file> [--env-file <file>] [--no-dotenv]\",\n \"\",\n \"Options:\",\n \" --schema <file> Path to schema JSON (required)\",\n \" --env-file <file> Env file path (default: .env)\",\n \" --no-dotenv Do not load env file; use process.env only\",\n \"\",\n \"Exit codes:\",\n \" 0 = OK, 1 = validation failed, 2 = CLI error\",\n ].join(\"\\n\"),\n );\n return 0;\n }\n\n if (cmd !== \"check\") {\n io.error(`Unknown command: ${cmd}`);\n return 2;\n }\n\n if (!schemaPath) {\n io.error(\"Missing required option: --schema <file>\");\n return 2;\n }\n\n try {\n if (useDotenv) {\n const p = envFile ?? \".env\";\n dotenv.config({ path: path.resolve(process.cwd(), p) });\n }\n\n const schema = loadSchema(schemaPath);\n\n // envDoctor will validate and throw EnvDoctorError if invalid\n envDoctor(schema, { loadDotEnv: false, env: process.env });\n\n io.log(\"✅ Environment is valid.\");\n return 0;\n } catch (e) {\n if (e instanceof EnvDoctorError) {\n io.error(e.message);\n return 1;\n }\n io.error(String(e));\n return 2;\n }\n}\n","import * as dotenv from \"dotenv\";\nimport { validateAndParse } from \"./validator\";\nimport type { EnvDoctorOptions, EnvDoctorResult, EnvDoctorSchema } from \"./types\";\n\nexport type { EnvDoctorOptions, EnvDoctorSchema } from \"./types\";\nexport { EnvDoctorError } from \"./error\";\n\nexport function envDoctor<TSchema extends EnvDoctorSchema>(\n schema: TSchema,\n options: EnvDoctorOptions = {}\n): EnvDoctorResult<TSchema> {\n const { loadDotEnv = true, env = process.env } = options;\n\n if (loadDotEnv) dotenv.config();\n\n return validateAndParse(schema, env);\n}\n","export type EnvDoctorIssue =\n | { key: string; kind: \"missing\"; message: string }\n | { key: string; kind: \"invalid\"; message: string };\n\nexport class EnvDoctorError extends Error {\n public readonly issues: EnvDoctorIssue[];\n\n constructor(issues: EnvDoctorIssue[]) {\n const header = \"ENV validation failed\";\n const lines = issues.map((i) => `- ${i.key}: ${i.message}`);\n super([header, ...lines].join(\"\\n\"));\n this.name = \"EnvDoctorError\";\n this.issues = issues;\n }\n}\n","import type { EnvBaseType } from \"./types\";\n\nexport function parseByType(type: EnvBaseType, raw: string): unknown {\n switch (type) {\n case \"string\":\n return raw;\n\n case \"number\": {\n // Trim to handle \" 3000 \"\n const n = Number(raw.trim());\n if (!Number.isFinite(n)) {\n throw new Error(`expected number, got \"${raw}\"`);\n }\n return n;\n }\n\n case \"boolean\": {\n const v = raw.trim().toLowerCase();\n if ([\"true\", \"1\", \"yes\", \"y\", \"on\"].includes(v)) return true;\n if ([\"false\", \"0\", \"no\", \"n\", \"off\"].includes(v)) return false;\n throw new Error(\n `expected boolean (true/false/1/0/yes/no/on/off), got \"${raw}\"`,\n );\n }\n\n case \"json\": {\n try {\n return JSON.parse(raw);\n } catch {\n throw new Error(`expected json, got \"${raw}\"`);\n }\n }\n\n case \"url\": {\n try {\n // If it doesn't parse as a URL, this throws.\n // We return the original string (common for configs).\n new URL(raw);\n return raw;\n } catch {\n throw new Error(`expected url, got \"${raw}\"`);\n }\n }\n\n /* v8 ignore next -- @preserve */\n default: {\n // Exhaustive check (unreachable at runtime)\n const _never: never = type;\n return _never;\n }\n }\n}\n\nexport function splitOptional(schemaValue: string): {\n baseType: EnvBaseType;\n optional: boolean;\n} {\n const optional = schemaValue.endsWith(\"?\");\n const base = optional ? schemaValue.slice(0, -1) : schemaValue;\n\n // runtime safety\n const allowed = [\"string\", \"number\", \"boolean\", \"json\", \"url\"] as const;\n if (!allowed.includes(base as any)) {\n throw new Error(\n `Unsupported type \"${schemaValue}\". Supported: string, number, boolean, json, url (optional with ?)`,\n );\n }\n\n return { baseType: base as EnvBaseType, optional };\n}\n","import { EnvDoctorError, type EnvDoctorIssue } from \"./error\";\nimport { parseByType, splitOptional } from \"./parsers\";\nimport type { EnvDoctorResult, EnvDoctorSchema } from \"./types\";\n\nexport function validateAndParse<TSchema extends EnvDoctorSchema>(\n schema: TSchema,\n env: Record<string, string | undefined>,\n): EnvDoctorResult<TSchema> {\n const issues: EnvDoctorIssue[] = [];\n const out: Record<string, unknown> = {};\n\n for (const [key, schemaValue] of Object.entries(schema)) {\n let baseType: any;\n let optional: boolean;\n\n try {\n ({ baseType, optional } = splitOptional(schemaValue));\n } catch (e) {\n issues.push({\n key,\n kind: \"invalid\",\n message: String(e),\n });\n continue;\n }\n\n const raw = env[key];\n\n if (raw === undefined || raw === \"\") {\n if (optional) {\n out[key] = undefined;\n } else {\n issues.push({\n key,\n kind: \"missing\",\n message: \"missing required environment variable\",\n });\n }\n continue;\n }\n\n try {\n out[key] = parseByType(baseType, raw);\n } catch (e) {\n issues.push({\n key,\n kind: \"invalid\",\n message: String(e),\n });\n }\n }\n\n if (issues.length > 0) {\n throw new EnvDoctorError(issues);\n }\n\n return out as EnvDoctorResult<TSchema>;\n}\n"],"mappings":"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","names":["dotenv","path","fs"]}
package/dist/cli.mjs DELETED
@@ -1,94 +0,0 @@
1
- import {
2
- EnvDoctorError,
3
- envDoctor
4
- } from "./chunk-U6GH2TRS.mjs";
5
-
6
- // src/cli.ts
7
- import fs from "fs";
8
- import path from "path";
9
- import * as dotenv from "dotenv";
10
- function parseArgs(argv) {
11
- const out = { useDotenv: true };
12
- const [cmd, ...rest] = argv;
13
- out.cmd = cmd;
14
- for (let i = 0; i < rest.length; i++) {
15
- const a = rest[i];
16
- if (a === "--schema") {
17
- out.schemaPath = rest[++i];
18
- } else if (a.startsWith("--schema=")) {
19
- out.schemaPath = a.split("=", 2)[1];
20
- } else if (a === "--env-file") {
21
- out.envFile = rest[++i];
22
- } else if (a.startsWith("--env-file=")) {
23
- out.envFile = a.split("=", 2)[1];
24
- } else if (a === "--no-dotenv") {
25
- out.useDotenv = false;
26
- }
27
- }
28
- return out;
29
- }
30
- function loadSchema(schemaPath) {
31
- const abs = path.resolve(process.cwd(), schemaPath);
32
- const raw = fs.readFileSync(abs, "utf8");
33
- const json = JSON.parse(raw);
34
- if (!json || typeof json !== "object" || Array.isArray(json)) {
35
- throw new Error("Schema must be a JSON object of key -> type.");
36
- }
37
- for (const [k, v] of Object.entries(json)) {
38
- if (typeof k !== "string" || typeof v !== "string") {
39
- throw new Error("Schema must be a JSON object of string -> string.");
40
- }
41
- }
42
- return json;
43
- }
44
- function runCli(argv, io = console) {
45
- const { cmd, schemaPath, envFile, useDotenv } = parseArgs(argv);
46
- if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") {
47
- io.log(
48
- [
49
- "env-typed-checker",
50
- "",
51
- "Usage:",
52
- " env-typed-checker check --schema <file> [--env-file <file>] [--no-dotenv]",
53
- "",
54
- "Options:",
55
- " --schema <file> Path to schema JSON (required)",
56
- " --env-file <file> Env file path (default: .env)",
57
- " --no-dotenv Do not load env file; use process.env only",
58
- "",
59
- "Exit codes:",
60
- " 0 = OK, 1 = validation failed, 2 = CLI error"
61
- ].join("\n")
62
- );
63
- return 0;
64
- }
65
- if (cmd !== "check") {
66
- io.error(`Unknown command: ${cmd}`);
67
- return 2;
68
- }
69
- if (!schemaPath) {
70
- io.error("Missing required option: --schema <file>");
71
- return 2;
72
- }
73
- try {
74
- if (useDotenv) {
75
- const p = envFile ?? ".env";
76
- dotenv.config({ path: path.resolve(process.cwd(), p) });
77
- }
78
- const schema = loadSchema(schemaPath);
79
- envDoctor(schema, { loadDotEnv: false, env: process.env });
80
- io.log("\u2705 Environment is valid.");
81
- return 0;
82
- } catch (e) {
83
- if (e instanceof EnvDoctorError) {
84
- io.error(e.message);
85
- return 1;
86
- }
87
- io.error(String(e));
88
- return 2;
89
- }
90
- }
91
- export {
92
- runCli
93
- };
94
- //# sourceMappingURL=cli.mjs.map
package/dist/cli.mjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport * as dotenv from \"dotenv\";\nimport { envDoctor, EnvDoctorError } from \"./index\";\nimport type { EnvDoctorSchema } from \"./types\";\n\ntype Io = {\n log: (msg: string) => void;\n error: (msg: string) => void;\n};\n\nfunction parseArgs(argv: string[]) {\n const out: {\n cmd?: string;\n schemaPath?: string;\n envFile?: string;\n useDotenv: boolean;\n } = { useDotenv: true };\n\n const [cmd, ...rest] = argv;\n out.cmd = cmd;\n\n for (let i = 0; i < rest.length; i++) {\n const a = rest[i];\n\n if (a === \"--schema\") {\n out.schemaPath = rest[++i];\n } else if (a.startsWith(\"--schema=\")) {\n out.schemaPath = a.split(\"=\", 2)[1];\n } else if (a === \"--env-file\") {\n out.envFile = rest[++i];\n } else if (a.startsWith(\"--env-file=\")) {\n out.envFile = a.split(\"=\", 2)[1];\n } else if (a === \"--no-dotenv\") {\n out.useDotenv = false;\n }\n }\n\n return out;\n}\n\nfunction loadSchema(schemaPath: string): EnvDoctorSchema {\n const abs = path.resolve(process.cwd(), schemaPath);\n const raw = fs.readFileSync(abs, \"utf8\");\n const json = JSON.parse(raw);\n\n if (!json || typeof json !== \"object\" || Array.isArray(json)) {\n throw new Error(\"Schema must be a JSON object of key -> type.\");\n }\n\n // Ensure values are strings\n for (const [k, v] of Object.entries(json)) {\n if (typeof k !== \"string\" || typeof v !== \"string\") {\n throw new Error(\"Schema must be a JSON object of string -> string.\");\n }\n }\n\n return json as EnvDoctorSchema;\n}\n\nexport function runCli(argv: string[], io: Io = console): number {\n const { cmd, schemaPath, envFile, useDotenv } = parseArgs(argv);\n\n if (!cmd || cmd === \"help\" || cmd === \"--help\" || cmd === \"-h\") {\n io.log(\n [\n \"env-typed-checker\",\n \"\",\n \"Usage:\",\n \" env-typed-checker check --schema <file> [--env-file <file>] [--no-dotenv]\",\n \"\",\n \"Options:\",\n \" --schema <file> Path to schema JSON (required)\",\n \" --env-file <file> Env file path (default: .env)\",\n \" --no-dotenv Do not load env file; use process.env only\",\n \"\",\n \"Exit codes:\",\n \" 0 = OK, 1 = validation failed, 2 = CLI error\",\n ].join(\"\\n\"),\n );\n return 0;\n }\n\n if (cmd !== \"check\") {\n io.error(`Unknown command: ${cmd}`);\n return 2;\n }\n\n if (!schemaPath) {\n io.error(\"Missing required option: --schema <file>\");\n return 2;\n }\n\n try {\n if (useDotenv) {\n const p = envFile ?? \".env\";\n dotenv.config({ path: path.resolve(process.cwd(), p) });\n }\n\n const schema = loadSchema(schemaPath);\n\n // envDoctor will validate and throw EnvDoctorError if invalid\n envDoctor(schema, { loadDotEnv: false, env: process.env });\n\n io.log(\"✅ Environment is valid.\");\n return 0;\n } catch (e) {\n if (e instanceof EnvDoctorError) {\n io.error(e.message);\n return 1;\n }\n io.error(String(e));\n return 2;\n }\n}\n"],"mappings":";;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,YAAY,YAAY;AASxB,SAAS,UAAU,MAAgB;AACjC,QAAM,MAKF,EAAE,WAAW,KAAK;AAEtB,QAAM,CAAC,KAAK,GAAG,IAAI,IAAI;AACvB,MAAI,MAAM;AAEV,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,KAAK,CAAC;AAEhB,QAAI,MAAM,YAAY;AACpB,UAAI,aAAa,KAAK,EAAE,CAAC;AAAA,IAC3B,WAAW,EAAE,WAAW,WAAW,GAAG;AACpC,UAAI,aAAa,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;AAAA,IACpC,WAAW,MAAM,cAAc;AAC7B,UAAI,UAAU,KAAK,EAAE,CAAC;AAAA,IACxB,WAAW,EAAE,WAAW,aAAa,GAAG;AACtC,UAAI,UAAU,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;AAAA,IACjC,WAAW,MAAM,eAAe;AAC9B,UAAI,YAAY;AAAA,IAClB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,WAAW,YAAqC;AACvD,QAAM,MAAM,KAAK,QAAQ,QAAQ,IAAI,GAAG,UAAU;AAClD,QAAM,MAAM,GAAG,aAAa,KAAK,MAAM;AACvC,QAAM,OAAO,KAAK,MAAM,GAAG;AAE3B,MAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,GAAG;AAC5D,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AAGA,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,GAAG;AACzC,QAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU;AAClD,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,OAAO,MAAgB,KAAS,SAAiB;AAC/D,QAAM,EAAE,KAAK,YAAY,SAAS,UAAU,IAAI,UAAU,IAAI;AAE9D,MAAI,CAAC,OAAO,QAAQ,UAAU,QAAQ,YAAY,QAAQ,MAAM;AAC9D,OAAG;AAAA,MACD;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,IACb;AACA,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,SAAS;AACnB,OAAG,MAAM,oBAAoB,GAAG,EAAE;AAClC,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,YAAY;AACf,OAAG,MAAM,0CAA0C;AACnD,WAAO;AAAA,EACT;AAEA,MAAI;AACF,QAAI,WAAW;AACb,YAAM,IAAI,WAAW;AACrB,MAAO,cAAO,EAAE,MAAM,KAAK,QAAQ,QAAQ,IAAI,GAAG,CAAC,EAAE,CAAC;AAAA,IACxD;AAEA,UAAM,SAAS,WAAW,UAAU;AAGpC,cAAU,QAAQ,EAAE,YAAY,OAAO,KAAK,QAAQ,IAAI,CAAC;AAEzD,OAAG,IAAI,8BAAyB;AAChC,WAAO;AAAA,EACT,SAAS,GAAG;AACV,QAAI,aAAa,gBAAgB;AAC/B,SAAG,MAAM,EAAE,OAAO;AAClB,aAAO;AAAA,IACT;AACA,OAAG,MAAM,OAAO,CAAC,CAAC;AAClB,WAAO;AAAA,EACT;AACF;","names":[]}
File without changes
File without changes