@zh-moody/safe-env 0.3.6 → 0.3.7

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Moody (https://github.com/zhMoody)
3
+ Copyright (c) 2026 Moody (https://github.com/zhMoody)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.en.md CHANGED
@@ -12,6 +12,10 @@ Whether you are writing Vue, React, or Node.js, environment variables are often
12
12
 
13
13
  ---
14
14
 
15
+ ![](./assets/demo.gif)
16
+
17
+ ---
18
+
15
19
  ### 🚀 Core Features
16
20
 
17
21
  - **Build-time Validation**: Provides a Vite plugin to intercept invalid configurations during development or build.
package/README.md CHANGED
@@ -12,6 +12,10 @@
12
12
 
13
13
  ---
14
14
 
15
+ ![](./assets/demo.gif)
16
+
17
+ ---
18
+
15
19
  ### 🚀 核心特性
16
20
 
17
21
  - **构建时预校验**:提供 Vite 插件,在开发启动或打包瞬间拦截非法配置。
@@ -0,0 +1 @@
1
+ function u(f){let t={},l=f.split(/\r?\n/);for(let d of l){let i=d.trim();if(!i||i.startsWith("#"))continue;let e=i.indexOf("=");if(e===-1)continue;let s=i.slice(0,e).trim(),n=i.slice(e+1).trim();if(!n){t[s]="";continue}let o=n[0];if(o==='"'||o==="'"){let r=n.indexOf(o,1);if(r!==-1){t[s]=n.slice(1,r);continue}}let c=n.indexOf("#");c!==-1&&(n=n.slice(0,c).trim()),t[s]=n}return t}export{u as a};
@@ -0,0 +1,9 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _chunkD6WM53FNcjs = require('./chunk-D6WM53FN.cjs');var $="development",_= exports.b ="serve",j= exports.c ="build",S= exports.d ="VITE_DEV_SERVER",F= exports.e ="VITE_";var V=typeof window<"u"&&typeof window.document<"u";function x(i,s=!0){if(V)return`SafeEnv Validation Failed: ${i.map(o=>`${o.key} (${o.error})`).join(", ")}`;let c={r:"\x1B[31m",g:"\x1B[32m",y:"\x1B[33m",b:"\x1B[1m",res:"\x1B[0m",d:"\x1B[2m",cy:"\x1B[36m"},e=(o,t)=>{let f=String(o),p=()=>f.length+(f.match(/[^\x00-\xff]/g)||[]).length;for(;p()>t;)f=f.slice(0,-1);return f+" ".repeat(t-p())},E=80,v=Math.floor(E*.3),g=Math.floor(E*.5),r=s?c:{r:"",g:"",y:"",b:"",res:"",d:"",cy:""},d=`
2
+ ${r.r}${r.b}\u274C SafeEnv Validation Failed${r.res}
3
+ `;return d+=` ${r.b}${e("Key",v)} \u2502 ${e("Error",g)} \u2502 Value${r.res}
4
+ `,d+=r.d+"\u2500".repeat(E+5)+r.res+`
5
+ `,i.forEach(o=>{let t=o.value===void 0?"undefined":o.isSecret?"********":`"${o.value}"`,f=o.value===void 0?r.d:o.isSecret?r.y:r.cy;d+=` ${r.y}${e(o.key,v)}${r.res} \u2502 ${r.r}${e(o.error,g)}${r.res} \u2502 ${f}${t}${r.res}
6
+ `}),d+=r.d+"\u2500".repeat(E+5)+r.res+`
7
+ `,d+=` ${r.g}\u{1F4A1} Tip: Check your .env files or schema definitions.${r.res}
8
+ `,d}function O(i){if(V){let s=i.reduce((c,e)=>(c[e.key]={"Error Message":e.error,"Current Value":e.value===void 0?"undefined":e.isSecret?"********":e.value},c),{});console.table(s)}else console.error(x(i,!0))}var y={};function I(i){let s=x(i,!1);return new Proxy({},{get(c,e){if(e==="__isSafeEnvError")return!0;if(e==="toJSON")return()=>({error:"SafeEnv Validation Failed"});throw new Error(`[safe-env] Cannot access "${String(e)}" because validation failed:
9
+ ${s}`)},ownKeys(){return[]},getOwnPropertyDescriptor(){}})}function k(i){let s=Object.getOwnPropertyNames(i);for(let c of s){let e=i[c];e&&typeof e=="object"&&!Object.isFrozen(e)&&k(e)}return Object.freeze(i)}function z(i,s={}){let{loadProcessEnv:c=!0,prefix:e=F,cwd:E,useCache:v=!0,refreshCache:g=!1}=s;if(g)for(let n in y)delete y[n];let r=typeof window<"u",d=typeof process<"u"&&(!!process.env.VITE||!!process.env[S]),o=r||d||"source"in s,t={};if("source"in s)t=s.source||{};else if(v&&!g&&Object.keys(y).length>0)t=y;else if(typeof process<"u"&&!r)try{let n=s.mode||process.env.NODE_ENV||$,{loadDotEnv:a}=_chunkD6WM53FNcjs.a.call(void 0, "./fs-node.cjs"),u={};for(let h of[".env",`.env.${n}`,".env.local",`.env.${n}.local`])u={...u,...a(h,E)};t={...u,...c?process.env:{}}}catch (e2){t={}}let f=Object.keys(t).length;if(v&&(f>0?Object.assign(y,t):Object.keys(y).length>0&&(t=y)),o&&Object.keys(t).length===0)return{};let p={},m=[];for(let n in i){let a=i[n],u=e&&!n.startsWith(e)?e+n:n,h=a.sourceKey||(t[u]!==void 0?u:t[n]!==void 0?n:u),b=t[h];try{if(b===void 0||b===""&&a.default!==void 0){if(a.required&&b===void 0)throw new Error("Missing required field");p[n]=a.default}else{let l=a.parse(b);if(l!==void 0&&a.metadata){let{min:D,max:w,validate:T}=a.metadata;if(typeof l=="number"){if(D!==void 0&&l<D)throw new Error(`Below min ${D}`);if(w!==void 0&&l>w)throw new Error(`Above max ${w}`)}if(T&&!T.fn(l))throw new Error(T.message)}p[n]=l}}catch(l){m.push({key:h,error:l.message,value:b,isSecret:_optionalChain([a, 'access', _2 => _2.metadata, 'optionalAccess', _3 => _3.isSecret])})}}if(m.length>0){if(s.throwOnError){let n=new Error(x(m,!0));throw n.plainMessage=x(m,!1),n}return O(m),typeof process<"u"&&process.exit&&!o&&process.exit(1),I(m)}return k(p)}exports.a = $; exports.b = _; exports.c = j; exports.d = S; exports.e = F; exports.f = x; exports.g = O; exports.h = z;
@@ -0,0 +1,9 @@
1
+ import{a as R}from"./chunk-I7AUKTXE.js";var $="development",_="serve",j="build",S="VITE_DEV_SERVER",F="VITE_";var V=typeof window<"u"&&typeof window.document<"u";function x(i,s=!0){if(V)return`SafeEnv Validation Failed: ${i.map(o=>`${o.key} (${o.error})`).join(", ")}`;let c={r:"\x1B[31m",g:"\x1B[32m",y:"\x1B[33m",b:"\x1B[1m",res:"\x1B[0m",d:"\x1B[2m",cy:"\x1B[36m"},e=(o,t)=>{let f=String(o),p=()=>f.length+(f.match(/[^\x00-\xff]/g)||[]).length;for(;p()>t;)f=f.slice(0,-1);return f+" ".repeat(t-p())},E=80,v=Math.floor(E*.3),g=Math.floor(E*.5),r=s?c:{r:"",g:"",y:"",b:"",res:"",d:"",cy:""},d=`
2
+ ${r.r}${r.b}\u274C SafeEnv Validation Failed${r.res}
3
+ `;return d+=` ${r.b}${e("Key",v)} \u2502 ${e("Error",g)} \u2502 Value${r.res}
4
+ `,d+=r.d+"\u2500".repeat(E+5)+r.res+`
5
+ `,i.forEach(o=>{let t=o.value===void 0?"undefined":o.isSecret?"********":`"${o.value}"`,f=o.value===void 0?r.d:o.isSecret?r.y:r.cy;d+=` ${r.y}${e(o.key,v)}${r.res} \u2502 ${r.r}${e(o.error,g)}${r.res} \u2502 ${f}${t}${r.res}
6
+ `}),d+=r.d+"\u2500".repeat(E+5)+r.res+`
7
+ `,d+=` ${r.g}\u{1F4A1} Tip: Check your .env files or schema definitions.${r.res}
8
+ `,d}function O(i){if(V){let s=i.reduce((c,e)=>(c[e.key]={"Error Message":e.error,"Current Value":e.value===void 0?"undefined":e.isSecret?"********":e.value},c),{});console.table(s)}else console.error(x(i,!0))}var y={};function I(i){let s=x(i,!1);return new Proxy({},{get(c,e){if(e==="__isSafeEnvError")return!0;if(e==="toJSON")return()=>({error:"SafeEnv Validation Failed"});throw new Error(`[safe-env] Cannot access "${String(e)}" because validation failed:
9
+ ${s}`)},ownKeys(){return[]},getOwnPropertyDescriptor(){}})}function k(i){let s=Object.getOwnPropertyNames(i);for(let c of s){let e=i[c];e&&typeof e=="object"&&!Object.isFrozen(e)&&k(e)}return Object.freeze(i)}function z(i,s={}){let{loadProcessEnv:c=!0,prefix:e=F,cwd:E,useCache:v=!0,refreshCache:g=!1}=s;if(g)for(let n in y)delete y[n];let r=typeof window<"u",d=typeof process<"u"&&(!!process.env.VITE||!!process.env[S]),o=r||d||"source"in s,t={};if("source"in s)t=s.source||{};else if(v&&!g&&Object.keys(y).length>0)t=y;else if(typeof process<"u"&&!r)try{let n=s.mode||process.env.NODE_ENV||$,{loadDotEnv:a}=R("./fs-node.cjs"),u={};for(let h of[".env",`.env.${n}`,".env.local",`.env.${n}.local`])u={...u,...a(h,E)};t={...u,...c?process.env:{}}}catch{t={}}let f=Object.keys(t).length;if(v&&(f>0?Object.assign(y,t):Object.keys(y).length>0&&(t=y)),o&&Object.keys(t).length===0)return{};let p={},m=[];for(let n in i){let a=i[n],u=e&&!n.startsWith(e)?e+n:n,h=a.sourceKey||(t[u]!==void 0?u:t[n]!==void 0?n:u),b=t[h];try{if(b===void 0||b===""&&a.default!==void 0){if(a.required&&b===void 0)throw new Error("Missing required field");p[n]=a.default}else{let l=a.parse(b);if(l!==void 0&&a.metadata){let{min:D,max:w,validate:T}=a.metadata;if(typeof l=="number"){if(D!==void 0&&l<D)throw new Error(`Below min ${D}`);if(w!==void 0&&l>w)throw new Error(`Above max ${w}`)}if(T&&!T.fn(l))throw new Error(T.message)}p[n]=l}}catch(l){m.push({key:h,error:l.message,value:b,isSecret:a.metadata?.isSecret})}}if(m.length>0){if(s.throwOnError){let n=new Error(x(m,!0));throw n.plainMessage=x(m,!1),n}return O(m),typeof process<"u"&&process.exit&&!o&&process.exit(1),I(m)}return k(p)}export{$ as a,_ as b,j as c,S as d,F as e,x as f,O as g,z as h};
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});function u(f){let t={},l=f.split(/\r?\n/);for(let d of l){let i=d.trim();if(!i||i.startsWith("#"))continue;let e=i.indexOf("=");if(e===-1)continue;let s=i.slice(0,e).trim(),n=i.slice(e+1).trim();if(!n){t[s]="";continue}let o=n[0];if(o==='"'||o==="'"){let r=n.indexOf(o,1);if(r!==-1){t[s]=n.slice(1,r);continue}}let c=n.indexOf("#");c!==-1&&(n=n.slice(0,c).trim()),t[s]=n}return t}exports.a = u;
package/dist/fs-node.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var _chunk5LT4H5GXcjs = require('./chunk-5LT4H5GX.cjs');require('./chunk-D6WM53FN.cjs');var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs);var _path = require('path'); var _path2 = _interopRequireDefault(_path);function p(e=".env",n){try{let r=_path2.default.resolve(n||process.cwd(),e);if(_fs2.default.existsSync(r))return _chunk5LT4H5GXcjs.a.call(void 0, _fs2.default.readFileSync(r,"utf-8"))}catch (e2){}return{}}exports.loadDotEnv = p;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var _chunkPLO26PP5cjs = require('./chunk-PLO26PP5.cjs');require('./chunk-D6WM53FN.cjs');var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs);var _path = require('path'); var _path2 = _interopRequireDefault(_path);function p(e=".env",n){try{let r=_path2.default.resolve(n||process.cwd(),e);if(_fs2.default.existsSync(r))return _chunkPLO26PP5cjs.a.call(void 0, _fs2.default.readFileSync(r,"utf-8"))}catch (e2){}return{}}exports.loadDotEnv = p;
package/dist/fs-node.js CHANGED
@@ -1 +1 @@
1
- import{a as t}from"./chunk-FBIIFJ67.js";import"./chunk-I7AUKTXE.js";import o from"fs";import s from"path";function p(e=".env",n){try{let r=s.resolve(n||process.cwd(),e);if(o.existsSync(r))return t(o.readFileSync(r,"utf-8"))}catch{}return{}}export{p as loadDotEnv};
1
+ import{a as t}from"./chunk-7CVG4I6F.js";import"./chunk-I7AUKTXE.js";import o from"fs";import s from"path";function p(e=".env",n){try{let r=s.resolve(n||process.cwd(),e);if(o.existsSync(r))return t(o.readFileSync(r,"utf-8"))}catch{}return{}}export{p as loadDotEnv};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunk5LT4H5GXcjs = require('./chunk-5LT4H5GX.cjs');var _chunkSHSPQLLUcjs = require('./chunk-SHSPQLLU.cjs');require('./chunk-D6WM53FN.cjs');function a(i,e,n,s=[]){return{type:i,default:e,required:e===void 0,parse:n,metadata:s.length?{options:s}:{},from(t){return this.sourceKey=t,this},validate(t,r="Custom validation failed"){return this.metadata={...this.metadata,validate:{fn:t,message:r}},this},min(t){return this.metadata={...this.metadata,min:t},this},max(t){return this.metadata={...this.metadata,max:t},this},transform(t){let r=this.parse;return this.parse=o=>t(r(o)),this},secret(){return this.metadata={...this.metadata,isSecret:!0},this},url(){return this.validate(t=>{try{return new URL(String(t)),!0}catch (e2){return!1}},"Invalid URL format")},email(){return this.validate(t=>/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(String(t)),"Invalid email format")},regex(t,r="Value does not match pattern"){return this.validate(o=>t.test(String(o)),r)},description(t){return this.metadata={...this.metadata,description:t},this}}}var p={string:i=>a("string",i,e=>String(e)),number:i=>a("number",i,e=>{let n=Number(e);if(isNaN(n))throw new Error(`Invalid number: ${e}`);return n}),boolean:i=>a("boolean",i,e=>{if(typeof e=="boolean")return e;if(e===void 0||e==="")return!1;let n=String(e).toLowerCase().trim();if(["true","1","yes","on"].includes(n))return!0;if(["false","0","no","off"].includes(n))return!1;throw new Error(`Invalid boolean: ${e}`)}),enum:(i,e)=>a("enum",e,n=>{if(!i.includes(n))throw new Error(`Value "${n}" is not one of: ${i.join(", ")}`);return n},i),array:(i,e=",")=>a("array",i,n=>Array.isArray(n)?n:typeof n!="string"?[]:n.split(e).map(s=>s.trim()).filter(Boolean))};exports.BUILD = _chunkSHSPQLLUcjs.c; exports.DEV = _chunkSHSPQLLUcjs.a; exports.SERVE = _chunkSHSPQLLUcjs.b; exports.VITE_DEV_FLAG = _chunkSHSPQLLUcjs.d; exports.VITE_PREFIX = _chunkSHSPQLLUcjs.e; exports.formatErrorReport = _chunkSHSPQLLUcjs.f; exports.parseDotEnv = _chunk5LT4H5GXcjs.a; exports.reportErrors = _chunkSHSPQLLUcjs.g; exports.s = p; exports.safeEnv = _chunkSHSPQLLUcjs.h;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkPLO26PP5cjs = require('./chunk-PLO26PP5.cjs');var _chunkBX67JRJUcjs = require('./chunk-BX67JRJU.cjs');require('./chunk-D6WM53FN.cjs');function a(r,e,n,s=[]){return{type:r,default:e,required:e===void 0,parse:n,metadata:s.length?{options:s}:{},from(t){return this.sourceKey=t,this},validate(t,i="Custom validation failed"){return this.metadata={...this.metadata,validate:{fn:t,message:i}},this},min(t){return this.metadata={...this.metadata,min:t},this},max(t){return this.metadata={...this.metadata,max:t},this},transform(t){let i=this.parse;return this.parse=o=>t(i(o)),this},secret(){return this.metadata={...this.metadata,isSecret:!0},this},url(){return this.validate(t=>{try{return new URL(String(t)),!0}catch (e2){return!1}},"Invalid URL format")},email(){return this.validate(t=>/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(String(t)),"Invalid email format")},regex(t,i="Value does not match pattern"){return this.validate(o=>t.test(String(o)),i)},description(t){return this.metadata={...this.metadata,description:t},this}}}var m={string:r=>a("string",r,e=>String(e)),number:r=>a("number",r,e=>{let n=Number(e);if(isNaN(n))throw new Error(`Invalid number: ${e}`);return n}),boolean:r=>a("boolean",r,e=>{if(typeof e=="boolean")return e;if(e===void 0||e==="")return!1;let n=String(e).toLowerCase().trim();if(["true","1","yes","on"].includes(n))return!0;if(["false","0","no","off"].includes(n))return!1;throw new Error(`Invalid boolean: ${e}`)}),enum:(r,e)=>a("enum",e,n=>{if(!r.includes(n))throw new Error(`Value "${n}" is not one of: ${r.join(", ")}`);return n},r),array:(r,e=",")=>a("array",r,n=>Array.isArray(n)?n:typeof n!="string"?[]:n.split(e).map(s=>s.trim()).filter(Boolean))};exports.BUILD = _chunkBX67JRJUcjs.c; exports.DEV = _chunkBX67JRJUcjs.a; exports.SERVE = _chunkBX67JRJUcjs.b; exports.VITE_DEV_FLAG = _chunkBX67JRJUcjs.d; exports.VITE_PREFIX = _chunkBX67JRJUcjs.e; exports.formatErrorReport = _chunkBX67JRJUcjs.f; exports.parseDotEnv = _chunkPLO26PP5cjs.a; exports.reportErrors = _chunkBX67JRJUcjs.g; exports.s = m; exports.safeEnv = _chunkBX67JRJUcjs.h;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,10 @@
1
- import { F as FieldDefinition, S as Schema, a as SafeEnvOptions, I as InferSchema, E as EnvError } from './types-C7kDNgjd.cjs';
2
- export { B as BUILD, b as BaseType, D as DEV, c as SERVE, V as VITE_DEV_FLAG, d as VITE_PREFIX } from './types-C7kDNgjd.cjs';
1
+ import { S as Schema, a as SafeEnvOptions, I as InferSchema, F as FieldDefinition, E as EnvError } from './types-Bx-JEkTH.cjs';
2
+ export { B as BUILD, b as BaseType, D as DEV, c as SERVE, V as VITE_DEV_FLAG, d as VITE_PREFIX } from './types-Bx-JEkTH.cjs';
3
+
4
+ declare function safeEnv<T extends Schema>(schema: T, options?: SafeEnvOptions & {
5
+ throwOnError?: boolean;
6
+ useCache?: boolean;
7
+ }): Readonly<InferSchema<T>>;
3
8
 
4
9
  declare const s: {
5
10
  string: (d?: string) => FieldDefinition<string>;
@@ -9,16 +14,15 @@ declare const s: {
9
14
  array: (d?: string[], sep?: string) => FieldDefinition<string[]>;
10
15
  };
11
16
 
12
- declare function safeEnv<T extends Schema>(schema: T, options?: SafeEnvOptions & {
13
- throwOnError?: boolean;
14
- useCache?: boolean;
15
- }): Readonly<InferSchema<T>>;
16
-
17
17
  /***
18
- * 将 .env 内容字符串解析为对象
19
- * */
18
+ * 将 .env 内容字符串解析为对象
19
+ * 兼容带引号的值、多层引号内部的注释标识符以及行尾注释
20
+ */
20
21
  declare function parseDotEnv(content: string): Record<string, string>;
21
22
 
23
+ /**
24
+ * 格式化终端报错表格 (仅 Node 端/开发端使用)
25
+ */
22
26
  declare function formatErrorReport(errors: EnvError[], useColor?: boolean): string;
23
27
  declare function reportErrors(errors: EnvError[]): void;
24
28
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,10 @@
1
- import { F as FieldDefinition, S as Schema, a as SafeEnvOptions, I as InferSchema, E as EnvError } from './types-C7kDNgjd.js';
2
- export { B as BUILD, b as BaseType, D as DEV, c as SERVE, V as VITE_DEV_FLAG, d as VITE_PREFIX } from './types-C7kDNgjd.js';
1
+ import { S as Schema, a as SafeEnvOptions, I as InferSchema, F as FieldDefinition, E as EnvError } from './types-Bx-JEkTH.js';
2
+ export { B as BUILD, b as BaseType, D as DEV, c as SERVE, V as VITE_DEV_FLAG, d as VITE_PREFIX } from './types-Bx-JEkTH.js';
3
+
4
+ declare function safeEnv<T extends Schema>(schema: T, options?: SafeEnvOptions & {
5
+ throwOnError?: boolean;
6
+ useCache?: boolean;
7
+ }): Readonly<InferSchema<T>>;
3
8
 
4
9
  declare const s: {
5
10
  string: (d?: string) => FieldDefinition<string>;
@@ -9,16 +14,15 @@ declare const s: {
9
14
  array: (d?: string[], sep?: string) => FieldDefinition<string[]>;
10
15
  };
11
16
 
12
- declare function safeEnv<T extends Schema>(schema: T, options?: SafeEnvOptions & {
13
- throwOnError?: boolean;
14
- useCache?: boolean;
15
- }): Readonly<InferSchema<T>>;
16
-
17
17
  /***
18
- * 将 .env 内容字符串解析为对象
19
- * */
18
+ * 将 .env 内容字符串解析为对象
19
+ * 兼容带引号的值、多层引号内部的注释标识符以及行尾注释
20
+ */
20
21
  declare function parseDotEnv(content: string): Record<string, string>;
21
22
 
23
+ /**
24
+ * 格式化终端报错表格 (仅 Node 端/开发端使用)
25
+ */
22
26
  declare function formatErrorReport(errors: EnvError[], useColor?: boolean): string;
23
27
  declare function reportErrors(errors: EnvError[]): void;
24
28
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{a as u}from"./chunk-FBIIFJ67.js";import{a as l,b as f,c as m,d as h,e as y,f as g,g as D,h as T}from"./chunk-E625KLX5.js";import"./chunk-I7AUKTXE.js";function a(i,e,n,s=[]){return{type:i,default:e,required:e===void 0,parse:n,metadata:s.length?{options:s}:{},from(t){return this.sourceKey=t,this},validate(t,r="Custom validation failed"){return this.metadata={...this.metadata,validate:{fn:t,message:r}},this},min(t){return this.metadata={...this.metadata,min:t},this},max(t){return this.metadata={...this.metadata,max:t},this},transform(t){let r=this.parse;return this.parse=o=>t(r(o)),this},secret(){return this.metadata={...this.metadata,isSecret:!0},this},url(){return this.validate(t=>{try{return new URL(String(t)),!0}catch{return!1}},"Invalid URL format")},email(){return this.validate(t=>/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(String(t)),"Invalid email format")},regex(t,r="Value does not match pattern"){return this.validate(o=>t.test(String(o)),r)},description(t){return this.metadata={...this.metadata,description:t},this}}}var p={string:i=>a("string",i,e=>String(e)),number:i=>a("number",i,e=>{let n=Number(e);if(isNaN(n))throw new Error(`Invalid number: ${e}`);return n}),boolean:i=>a("boolean",i,e=>{if(typeof e=="boolean")return e;if(e===void 0||e==="")return!1;let n=String(e).toLowerCase().trim();if(["true","1","yes","on"].includes(n))return!0;if(["false","0","no","off"].includes(n))return!1;throw new Error(`Invalid boolean: ${e}`)}),enum:(i,e)=>a("enum",e,n=>{if(!i.includes(n))throw new Error(`Value "${n}" is not one of: ${i.join(", ")}`);return n},i),array:(i,e=",")=>a("array",i,n=>Array.isArray(n)?n:typeof n!="string"?[]:n.split(e).map(s=>s.trim()).filter(Boolean))};export{m as BUILD,l as DEV,f as SERVE,h as VITE_DEV_FLAG,y as VITE_PREFIX,g as formatErrorReport,u as parseDotEnv,D as reportErrors,p as s,T as safeEnv};
1
+ import{a as d}from"./chunk-7CVG4I6F.js";import{a as y,b as p,c as D,d as g,e as T,f,g as u,h as l}from"./chunk-IHZESWXY.js";import"./chunk-I7AUKTXE.js";function a(r,e,n,s=[]){return{type:r,default:e,required:e===void 0,parse:n,metadata:s.length?{options:s}:{},from(t){return this.sourceKey=t,this},validate(t,i="Custom validation failed"){return this.metadata={...this.metadata,validate:{fn:t,message:i}},this},min(t){return this.metadata={...this.metadata,min:t},this},max(t){return this.metadata={...this.metadata,max:t},this},transform(t){let i=this.parse;return this.parse=o=>t(i(o)),this},secret(){return this.metadata={...this.metadata,isSecret:!0},this},url(){return this.validate(t=>{try{return new URL(String(t)),!0}catch{return!1}},"Invalid URL format")},email(){return this.validate(t=>/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(String(t)),"Invalid email format")},regex(t,i="Value does not match pattern"){return this.validate(o=>t.test(String(o)),i)},description(t){return this.metadata={...this.metadata,description:t},this}}}var m={string:r=>a("string",r,e=>String(e)),number:r=>a("number",r,e=>{let n=Number(e);if(isNaN(n))throw new Error(`Invalid number: ${e}`);return n}),boolean:r=>a("boolean",r,e=>{if(typeof e=="boolean")return e;if(e===void 0||e==="")return!1;let n=String(e).toLowerCase().trim();if(["true","1","yes","on"].includes(n))return!0;if(["false","0","no","off"].includes(n))return!1;throw new Error(`Invalid boolean: ${e}`)}),enum:(r,e)=>a("enum",e,n=>{if(!r.includes(n))throw new Error(`Value "${n}" is not one of: ${r.join(", ")}`);return n},r),array:(r,e=",")=>a("array",r,n=>Array.isArray(n)?n:typeof n!="string"?[]:n.split(e).map(s=>s.trim()).filter(Boolean))};export{D as BUILD,y as DEV,p as SERVE,g as VITE_DEV_FLAG,T as VITE_PREFIX,f as formatErrorReport,d as parseDotEnv,u as reportErrors,m as s,l as safeEnv};
@@ -38,6 +38,8 @@ interface SafeEnvOptions {
38
38
  source?: Record<string, any>;
39
39
  prefix?: string;
40
40
  cwd?: string;
41
+ /** 是否强制刷新缓存,重新从磁盘或进程读取 */
42
+ refreshCache?: boolean;
41
43
  /** @internal */ manualSource?: boolean;
42
44
  /** @internal */ devMode?: boolean;
43
45
  }
@@ -38,6 +38,8 @@ interface SafeEnvOptions {
38
38
  source?: Record<string, any>;
39
39
  prefix?: string;
40
40
  cwd?: string;
41
+ /** 是否强制刷新缓存,重新从磁盘或进程读取 */
42
+ refreshCache?: boolean;
41
43
  /** @internal */ manualSource?: boolean;
42
44
  /** @internal */ devMode?: boolean;
43
45
  }
package/dist/vite.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkSHSPQLLUcjs = require('./chunk-SHSPQLLU.cjs');require('./chunk-D6WM53FN.cjs');var _vite = require('vite');function g(v,f={}){let n=null,o=!1;return{name:"vite-plugin-safe-env",configResolved(e){o=e.command===_chunkSHSPQLLUcjs.b,process.env[_chunkSHSPQLLUcjs.d]=o?"true":"";let{envDir:t=e.root,prefix:r=e.envPrefix||_chunkSHSPQLLUcjs.e}=f,p=_vite.loadEnv.call(void 0, e.mode,t,r);try{_chunkSHSPQLLUcjs.h.call(void 0, v,{source:p,prefix:Array.isArray(r)?r[0]:r,loadProcessEnv:!1,throwOnError:!0}),n=null}catch(s){n=s,o?e.logger.error(s.message):(console.error(s.message),console.error(`\x1B[31m[safe-env] Fatal: Environment validation failed during build. Exiting...\x1B[0m
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkBX67JRJUcjs = require('./chunk-BX67JRJU.cjs');require('./chunk-D6WM53FN.cjs');var _vite = require('vite');function g(v,f={}){let n=null,o=!1;return{name:"vite-plugin-safe-env",configResolved(e){o=e.command===_chunkBX67JRJUcjs.b,process.env[_chunkBX67JRJUcjs.d]=o?"true":"";let{envDir:t=e.root,prefix:r=e.envPrefix||_chunkBX67JRJUcjs.e}=f,p=_vite.loadEnv.call(void 0, e.mode,t,r);try{_chunkBX67JRJUcjs.h.call(void 0, v,{source:p,prefix:Array.isArray(r)?r[0]:r,loadProcessEnv:!1,throwOnError:!0}),n=null}catch(s){n=s,o?e.logger.error(s.message):(console.error(s.message),console.error(`\x1B[31m[safe-env] Fatal: Environment validation failed during build. Exiting...\x1B[0m
2
2
  `),process.exit(1))}},transform(e,t){if(o&&n&&(e.includes("import.meta.env")||e.includes("safeEnv"))){let r=new Error(n.plainMessage||n.message);throw r.stack="",r}return null}}}exports.viteSafeEnv = g;
package/dist/vite.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Plugin } from 'vite';
2
- import { S as Schema } from './types-C7kDNgjd.cjs';
2
+ import { S as Schema } from './types-Bx-JEkTH.cjs';
3
3
 
4
4
  /**
5
5
  * Vite 插件:在构建或开发启动时校验环境变量
package/dist/vite.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Plugin } from 'vite';
2
- import { S as Schema } from './types-C7kDNgjd.js';
2
+ import { S as Schema } from './types-Bx-JEkTH.js';
3
3
 
4
4
  /**
5
5
  * Vite 插件:在构建或开发启动时校验环境变量
package/dist/vite.js CHANGED
@@ -1,2 +1,2 @@
1
- import{b as a,d as i,e as l,h as m}from"./chunk-E625KLX5.js";import"./chunk-I7AUKTXE.js";import{loadEnv as u}from"vite";function g(v,f={}){let n=null,o=!1;return{name:"vite-plugin-safe-env",configResolved(e){o=e.command===a,process.env[i]=o?"true":"";let{envDir:t=e.root,prefix:r=e.envPrefix||l}=f,p=u(e.mode,t,r);try{m(v,{source:p,prefix:Array.isArray(r)?r[0]:r,loadProcessEnv:!1,throwOnError:!0}),n=null}catch(s){n=s,o?e.logger.error(s.message):(console.error(s.message),console.error(`\x1B[31m[safe-env] Fatal: Environment validation failed during build. Exiting...\x1B[0m
1
+ import{b as a,d as i,e as l,h as m}from"./chunk-IHZESWXY.js";import"./chunk-I7AUKTXE.js";import{loadEnv as u}from"vite";function g(v,f={}){let n=null,o=!1;return{name:"vite-plugin-safe-env",configResolved(e){o=e.command===a,process.env[i]=o?"true":"";let{envDir:t=e.root,prefix:r=e.envPrefix||l}=f,p=u(e.mode,t,r);try{m(v,{source:p,prefix:Array.isArray(r)?r[0]:r,loadProcessEnv:!1,throwOnError:!0}),n=null}catch(s){n=s,o?e.logger.error(s.message):(console.error(s.message),console.error(`\x1B[31m[safe-env] Fatal: Environment validation failed during build. Exiting...\x1B[0m
2
2
  `),process.exit(1))}},transform(e,t){if(o&&n&&(e.includes("import.meta.env")||e.includes("safeEnv"))){let r=new Error(n.plainMessage||n.message);throw r.stack="",r}return null}}}export{g as viteSafeEnv};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zh-moody/safe-env",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "Type-safe environment variables for Node.js and Browser with schema validation.",
5
5
  "author": "Moody",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});function l(e){let s={},r=e.split(/\r?\n/);for(let o of r){let i=o.trim();if(!i||i.startsWith("#"))continue;let n=i.indexOf("=");if(n==-1)continue;let c=i.slice(0,n).trim(),t=i.slice(n+1).trim();(t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'"))&&(t=t.slice(1,-1)),s[c]=t}return s}exports.a = l;
@@ -1,9 +0,0 @@
1
- import{a as k}from"./chunk-I7AUKTXE.js";var T="development",R="serve",I="build",$="VITE_DEV_SERVER",S="VITE_";var V=typeof window<"u"&&typeof window.document<"u";function g(s,t=!0){if(V)return`SafeEnv Validation Failed: ${s.map(e=>`${e.key} (${e.error})`).join(", ")}`;let l={r:"\x1B[31m",g:"\x1B[32m",y:"\x1B[33m",b:"\x1B[1m",res:"\x1B[0m",d:"\x1B[2m",cy:"\x1B[36m"},n=(e,p)=>{let i=String(e),d=()=>i.length+(i.match(/[^\x00-\xff]/g)||[]).length;for(;d()>p;)i=i.slice(0,-1);return i+" ".repeat(p-d())},E=Math.max(80,(typeof process<"u"?process.stdout.columns:80)||80)-10,y=Math.floor(E*.3),m=Math.floor(E*.5),r=t?l:{r:"",g:"",y:"",b:"",res:"",d:"",cy:""},c=`
2
- ${r.r}${r.b}\u274C SafeEnv Validation Failed${r.res}
3
- `;return c+=` ${r.b}${n("Key",y)} \u2502 ${n("Error",m)} \u2502 Value${r.res}
4
- `,c+=r.d+"\u2500".repeat(E+5)+r.res+`
5
- `,s.forEach(e=>{let p=e.value===void 0?"undefined":e.isSecret?"********":`"${e.value}"`,i=e.value===void 0?r.d:e.isSecret?r.y:r.cy;c+=` ${r.y}${n(e.key,y)}${r.res} \u2502 ${r.r}${n(e.error,m)}${r.res} \u2502 ${i}${p}${r.res}
6
- `}),c+=r.d+"\u2500".repeat(E+5)+r.res+`
7
- `,c+=` ${r.g}\u{1F4A1} Tip: Check your .env files or schema definitions.${r.res}
8
- `,c}function F(s){if(V){console.group("%c \u274C SafeEnv Validation Failed ","background: #fee2e2; color: #b91c1c; font-weight: bold; padding: 4px; border-radius: 2px;");let t=s.reduce((l,n)=>(l[n.key]={"Error Message":n.error,"Current Value":n.value===void 0?"undefined":n.isSecret?"********":n.value},l),{});console.table(t),console.log("%c \u{1F4A1} Tip: Check your .env files or schema definitions. ","color: #059669; font-style: italic;"),console.groupEnd()}else console.error(g(s,!0))}var x={};function O(s){let t=g(s,!1);return new Proxy({},{get(l,n){if(n==="__isSafeEnvError")return!0;if(n==="toJSON")return()=>({error:"SafeEnv Validation Failed"});throw new Error(`[safe-env] Cannot access "${String(n)}" because validation failed:
9
- ${t}`)},ownKeys(){return[]},getOwnPropertyDescriptor(){}})}function U(s,t={}){let{loadProcessEnv:l=!0,prefix:n=S,cwd:E,useCache:y=!0}=t,m=typeof window<"u",r=typeof process<"u"&&(!!process.env.VITE||!!process.env[$]),c=m||r||"source"in t,e={};if("source"in t)e=t.source||{};else if(y&&Object.keys(x).length>0)e=x;else if(typeof process<"u"&&!m)try{let o=t.mode||process.env.NODE_ENV||T,{loadDotEnv:a}=k("./fs-node.cjs"),u={};for(let b of[".env",`.env.${o}`,".env.local",`.env.${o}.local`])u={...u,...a(b,E)};e={...u,...l?process.env:{}}}catch{e={}}let p=Object.keys(e).length;if(y&&(p>0?Object.assign(x,e):Object.keys(x).length>0&&(e=x)),c&&Object.keys(e).length===0)return{};let i={},d=[];for(let o in s){let a=s[o],u=n&&!o.startsWith(n)?n+o:o,b=a.sourceKey||(e[u]!==void 0?u:e[o]!==void 0?o:u),v=e[b];try{if(v===void 0||v===""&&a.default!==void 0){if(a.required&&v===void 0)throw new Error("Missing required field");i[o]=a.default}else{let f=a.parse(v);if(f!==void 0&&a.metadata){let{min:h,max:D,validate:w}=a.metadata;if(typeof f=="number"){if(h!==void 0&&f<h)throw new Error(`Below min ${h}`);if(D!==void 0&&f>D)throw new Error(`Above max ${D}`)}if(w&&!w.fn(f))throw new Error(w.message)}i[o]=f}}catch(f){d.push({key:b,error:f.message,value:v,isSecret:a.metadata?.isSecret})}}if(d.length>0){if(t.throwOnError){let o=new Error(g(d,!0));throw o.plainMessage=g(d,!1),o}return F(d),typeof process<"u"&&process.exit&&!c&&process.exit(1),O(d)}return Object.freeze(i)}export{T as a,R as b,I as c,$ as d,S as e,g as f,F as g,U as h};
@@ -1 +0,0 @@
1
- function l(e){let s={},r=e.split(/\r?\n/);for(let o of r){let i=o.trim();if(!i||i.startsWith("#"))continue;let n=i.indexOf("=");if(n==-1)continue;let c=i.slice(0,n).trim(),t=i.slice(n+1).trim();(t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'"))&&(t=t.slice(1,-1)),s[c]=t}return s}export{l as a};
@@ -1,9 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _chunkD6WM53FNcjs = require('./chunk-D6WM53FN.cjs');var T="development",R= exports.b ="serve",I= exports.c ="build",$= exports.d ="VITE_DEV_SERVER",S= exports.e ="VITE_";var V=typeof window<"u"&&typeof window.document<"u";function g(s,t=!0){if(V)return`SafeEnv Validation Failed: ${s.map(e=>`${e.key} (${e.error})`).join(", ")}`;let l={r:"\x1B[31m",g:"\x1B[32m",y:"\x1B[33m",b:"\x1B[1m",res:"\x1B[0m",d:"\x1B[2m",cy:"\x1B[36m"},n=(e,p)=>{let i=String(e),d=()=>i.length+(i.match(/[^\x00-\xff]/g)||[]).length;for(;d()>p;)i=i.slice(0,-1);return i+" ".repeat(p-d())},E=Math.max(80,(typeof process<"u"?process.stdout.columns:80)||80)-10,y=Math.floor(E*.3),m=Math.floor(E*.5),r=t?l:{r:"",g:"",y:"",b:"",res:"",d:"",cy:""},c=`
2
- ${r.r}${r.b}\u274C SafeEnv Validation Failed${r.res}
3
- `;return c+=` ${r.b}${n("Key",y)} \u2502 ${n("Error",m)} \u2502 Value${r.res}
4
- `,c+=r.d+"\u2500".repeat(E+5)+r.res+`
5
- `,s.forEach(e=>{let p=e.value===void 0?"undefined":e.isSecret?"********":`"${e.value}"`,i=e.value===void 0?r.d:e.isSecret?r.y:r.cy;c+=` ${r.y}${n(e.key,y)}${r.res} \u2502 ${r.r}${n(e.error,m)}${r.res} \u2502 ${i}${p}${r.res}
6
- `}),c+=r.d+"\u2500".repeat(E+5)+r.res+`
7
- `,c+=` ${r.g}\u{1F4A1} Tip: Check your .env files or schema definitions.${r.res}
8
- `,c}function F(s){if(V){console.group("%c \u274C SafeEnv Validation Failed ","background: #fee2e2; color: #b91c1c; font-weight: bold; padding: 4px; border-radius: 2px;");let t=s.reduce((l,n)=>(l[n.key]={"Error Message":n.error,"Current Value":n.value===void 0?"undefined":n.isSecret?"********":n.value},l),{});console.table(t),console.log("%c \u{1F4A1} Tip: Check your .env files or schema definitions. ","color: #059669; font-style: italic;"),console.groupEnd()}else console.error(g(s,!0))}var x={};function O(s){let t=g(s,!1);return new Proxy({},{get(l,n){if(n==="__isSafeEnvError")return!0;if(n==="toJSON")return()=>({error:"SafeEnv Validation Failed"});throw new Error(`[safe-env] Cannot access "${String(n)}" because validation failed:
9
- ${t}`)},ownKeys(){return[]},getOwnPropertyDescriptor(){}})}function U(s,t={}){let{loadProcessEnv:l=!0,prefix:n=S,cwd:E,useCache:y=!0}=t,m=typeof window<"u",r=typeof process<"u"&&(!!process.env.VITE||!!process.env[$]),c=m||r||"source"in t,e={};if("source"in t)e=t.source||{};else if(y&&Object.keys(x).length>0)e=x;else if(typeof process<"u"&&!m)try{let o=t.mode||process.env.NODE_ENV||T,{loadDotEnv:a}=_chunkD6WM53FNcjs.a.call(void 0, "./fs-node.cjs"),u={};for(let b of[".env",`.env.${o}`,".env.local",`.env.${o}.local`])u={...u,...a(b,E)};e={...u,...l?process.env:{}}}catch (e2){e={}}let p=Object.keys(e).length;if(y&&(p>0?Object.assign(x,e):Object.keys(x).length>0&&(e=x)),c&&Object.keys(e).length===0)return{};let i={},d=[];for(let o in s){let a=s[o],u=n&&!o.startsWith(n)?n+o:o,b=a.sourceKey||(e[u]!==void 0?u:e[o]!==void 0?o:u),v=e[b];try{if(v===void 0||v===""&&a.default!==void 0){if(a.required&&v===void 0)throw new Error("Missing required field");i[o]=a.default}else{let f=a.parse(v);if(f!==void 0&&a.metadata){let{min:h,max:D,validate:w}=a.metadata;if(typeof f=="number"){if(h!==void 0&&f<h)throw new Error(`Below min ${h}`);if(D!==void 0&&f>D)throw new Error(`Above max ${D}`)}if(w&&!w.fn(f))throw new Error(w.message)}i[o]=f}}catch(f){d.push({key:b,error:f.message,value:v,isSecret:_optionalChain([a, 'access', _ => _.metadata, 'optionalAccess', _2 => _2.isSecret])})}}if(d.length>0){if(t.throwOnError){let o=new Error(g(d,!0));throw o.plainMessage=g(d,!1),o}return F(d),typeof process<"u"&&process.exit&&!c&&process.exit(1),O(d)}return Object.freeze(i)}exports.a = T; exports.b = R; exports.c = I; exports.d = $; exports.e = S; exports.f = g; exports.g = F; exports.h = U;