@zh-moody/safe-env 0.3.5 → 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.
@@ -20,7 +24,6 @@ Whether you are writing Vue, React, or Node.js, environment variables are often
20
24
  - **Monorepo Ready**: Supports `cwd` parameter to explicitly specify the `.env` directory, ideal for complex project architectures.
21
25
  - **IDE Enhancement**: Supports `.description()` to view variable usage and documentation directly via hover in your code.
22
26
  - **Rigorous Type Parsing**: Built-in `s.array()`, `s.boolean()` with enhanced conversion, and `.transform()` for chainable piping.
23
- - **Ultra-lightweight**: Only **1.9 KB** after Gzip, with zero runtime dependencies.
24
27
 
25
28
  ---
26
29
 
@@ -35,36 +38,38 @@ npm install @zh-moody/safe-env
35
38
  ### 🚀 Quick Start
36
39
 
37
40
  #### 🔹 [Vite / React / Vue]
41
+
38
42
  For frontend projects, use the Vite plugin for **build-time validation**.
39
43
 
40
44
  **1. Configure Vite Plugin (`vite.config.ts`):**
45
+
41
46
  ```typescript
42
- import { viteSafeEnv } from '@zh-moody/safe-env/vite';
43
- import { schema } from './src/env';
47
+ import { viteSafeEnv } from "@zh-moody/safe-env/vite";
48
+ import { schema } from "./src/env";
44
49
 
45
50
  export default {
46
- plugins: [
47
- viteSafeEnv(schema)
48
- ]
49
- }
51
+ plugins: [viteSafeEnv(schema)],
52
+ };
50
53
  ```
51
54
 
52
55
  **2. Define and Export Config (`src/env.ts`):**
56
+
53
57
  ```typescript
54
- import { safeEnv, s } from '@zh-moody/safe-env';
58
+ import { safeEnv, s } from "@zh-moody/safe-env";
55
59
 
56
60
  export const schema = {
57
61
  VITE_API_URL: s.string().url().description("Backend API Base URL"),
58
62
  VITE_PORT: s.number(3000).description("Development Server Port"),
59
63
  };
60
64
 
61
- export const env = safeEnv(schema, {
62
- source: import.meta.env
65
+ export const env = safeEnv(schema, {
66
+ source: import.meta.env,
63
67
  });
64
68
  ```
65
69
 
66
70
  > **💡 Best Practice: Prevent Vite Type Pollution**
67
71
  > To completely disable the insecure original `import.meta.env.XXX` hints, modify `src/vite-env.d.ts`:
72
+ >
68
73
  > ```typescript
69
74
  > interface ImportMetaEnv {
70
75
  > [key: string]: never;
@@ -74,19 +79,24 @@ export const env = safeEnv(schema, {
74
79
  ---
75
80
 
76
81
  #### 🔸 [Node.js / Server-side]
82
+
77
83
  In Node.js, the library automatically looks for and parses `.env` files on disk.
78
84
 
79
85
  **1. Define Config (`src/config.ts`):**
86
+
80
87
  ```typescript
81
- import { safeEnv, s } from '@zh-moody/safe-env';
82
-
83
- const config = safeEnv({
84
- DB_PASSWORD: s.string().secret().description("Database Password"),
85
- DB_PORT: s.number(5432).min(1).max(65535),
86
- }, {
87
- // Explicitly specify the .env directory for Monorepo or specific deployments
88
- // cwd: '/path/to/project-root'
89
- });
88
+ import { safeEnv, s } from "@zh-moody/safe-env";
89
+
90
+ const config = safeEnv(
91
+ {
92
+ DB_PASSWORD: s.string().secret().description("Database Password"),
93
+ DB_PORT: s.number(5432).min(1).max(65535),
94
+ },
95
+ {
96
+ // Explicitly specify the .env directory for Monorepo or specific deployments
97
+ // cwd: '/path/to/project-root'
98
+ },
99
+ );
90
100
 
91
101
  export default config;
92
102
  ```
@@ -96,6 +106,7 @@ export default config;
96
106
  ### 🛠️ API Reference
97
107
 
98
108
  #### 1. Define Fields (`s.xxx`)
109
+
99
110
  - `s.string(default?)`: String field. Required if no default value.
100
111
  - `s.number(default?)`: Automatically converted to `number` and validated.
101
112
  - `s.boolean(default?)`: Supports `"true"`, `"1"`, `"yes"`, `"on"` as `true`.
@@ -106,43 +117,50 @@ export default config;
106
117
 
107
118
  - **`.secret()`**: Masks the value as `********` in error reports.
108
119
  ```typescript
109
- PASSWORD: s.string().secret()
120
+ PASSWORD: s.string().secret();
110
121
  ```
111
122
  - **`.url()` / `.email()`**: Built-in format validation.
112
123
  ```typescript
113
- API_URL: s.string().url()
124
+ API_URL: s.string().url();
114
125
  ```
115
126
  - **`.regex(pattern, msg?)`**: Custom regex validation.
116
127
  ```typescript
117
- VERSION: s.string().regex(/^v\d+\.\d+\.\d+$/, "Invalid format")
128
+ VERSION: s.string().regex(/^v\d+\.\d+\.\d+$/, "Invalid format");
118
129
  ```
119
130
  - **`.description(text)`**: Adds a description for IDE hover hints.
120
131
  ```typescript
121
- PORT: s.number(3000).description("Server Port")
132
+ PORT: s.number(3000).description("Server Port");
122
133
  ```
123
134
  - **`.transform(fn)`**: Custom data transformation, supports multi-level piping.
124
135
  ```typescript
125
- NAME: s.string().transform(v => v.trim()).transform(v => v.toUpperCase())
136
+ NAME: s.string()
137
+ .transform((v) => v.trim())
138
+ .transform((v) => v.toUpperCase());
126
139
  ```
127
140
  - **`.from(key)`**: Maps environment variable name (Alias).
128
141
  ```typescript
129
- port: s.number().from('VITE_SERVER_PORT')
142
+ port: s.number().from("VITE_SERVER_PORT");
130
143
  ```
131
144
  - **`.min(n)` / `.max(n)`**: Constraints for number values.
132
145
  ```typescript
133
- PORT: s.number().min(1024).max(65535)
146
+ PORT: s.number().min(1024).max(65535);
134
147
  ```
135
148
  - **`.validate(fn, msg?)`**: Fully custom validation logic.
136
149
  ```typescript
137
- INTERNAL_URL: s.string().validate(v => v.endsWith('.internal.com'), 'Must be internal')
150
+ INTERNAL_URL: s.string().validate(
151
+ (v) => v.endsWith(".internal.com"),
152
+ "Must be internal",
153
+ );
138
154
  ```
139
155
 
140
156
  ---
141
157
 
142
158
  ### 🎨 Error Reporting
159
+
143
160
  When validation fails, `safe-env` outputs a structured, adaptive table in the console showing: **Key / Error Reason / Current Value (Masked)**.
144
161
 
145
162
  ---
146
163
 
147
164
  ### 📄 License
165
+
148
166
  [MIT License](./LICENSE) - Copyright (c) 2026 Moody.
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 插件,在开发启动或打包瞬间拦截非法配置。
@@ -20,7 +24,6 @@
20
24
  - **Monorepo 精准定位**:支持 `cwd` 参数,可显式指定配置文件检索目录,适配复杂的项目架构。
21
25
  - **IDE 增强**:支持 `.description()`,在代码中通过悬停直接查看变量用途与文档。
22
26
  - **严谨的类型解析**:内置 `s.array()`, `s.boolean()` 增强转换,支持 `.transform()` 链式 Pipe 处理。
23
- - **极致轻量**:Gzip 压缩后仅 **1.9 KB**,零运行时依赖。
24
27
 
25
28
  ---
26
29
 
@@ -35,36 +38,38 @@ npm install @zh-moody/safe-env
35
38
  ### 🚀 快速上手
36
39
 
37
40
  #### 🔹 [Vite / React / Vue] 使用
41
+
38
42
  在前端,建议配合 Vite 插件实现**构建时校验**。
39
43
 
40
44
  **1. 配置 Vite 插件 (`vite.config.ts`):**
45
+
41
46
  ```typescript
42
- import { viteSafeEnv } from '@zh-moody/safe-env/vite';
43
- import { schema } from './src/env';
47
+ import { viteSafeEnv } from "@zh-moody/safe-env/vite";
48
+ import { schema } from "./src/env";
44
49
 
45
50
  export default {
46
- plugins: [
47
- viteSafeEnv(schema)
48
- ]
49
- }
51
+ plugins: [viteSafeEnv(schema)],
52
+ };
50
53
  ```
51
54
 
52
55
  **2. 定义配置并导出 (`src/env.ts`):**
56
+
53
57
  ```typescript
54
- import { safeEnv, s } from '@zh-moody/safe-env';
58
+ import { safeEnv, s } from "@zh-moody/safe-env";
55
59
 
56
60
  export const schema = {
57
61
  VITE_API_URL: s.string().url().description("后端 API 地址"),
58
62
  VITE_PORT: s.number(3000).description("服务端口"),
59
63
  };
60
64
 
61
- export const env = safeEnv(schema, {
62
- source: import.meta.env
65
+ export const env = safeEnv(schema, {
66
+ source: import.meta.env,
63
67
  });
64
68
  ```
65
69
 
66
70
  > **💡 最佳实践:防止 Vite 类型污染**
67
71
  > 为彻底禁用 `import.meta.env.XXX` 的原生提示,建议修改 `src/vite-env.d.ts`:
72
+ >
68
73
  > ```typescript
69
74
  > interface ImportMetaEnv {
70
75
  > [key: string]: never;
@@ -74,19 +79,24 @@ export const env = safeEnv(schema, {
74
79
  ---
75
80
 
76
81
  #### 🔸 [Node.js / 服务端] 使用
82
+
77
83
  在后端环境,库会自动检索并解析磁盘上的 `.env` 系列文件。
78
84
 
79
85
  **1. 定义配置 (`src/config.ts`):**
86
+
80
87
  ```typescript
81
- import { safeEnv, s } from '@zh-moody/safe-env';
82
-
83
- const config = safeEnv({
84
- DB_PASSWORD: s.string().secret().description("数据库密码"),
85
- DB_PORT: s.number(5432).min(1).max(65535),
86
- }, {
87
- // 在 Monorepo 或特定部署环境下,可显式指定 .env 所在目录
88
- // cwd: '/path/to/project-root'
89
- });
88
+ import { safeEnv, s } from "@zh-moody/safe-env";
89
+
90
+ const config = safeEnv(
91
+ {
92
+ DB_PASSWORD: s.string().secret().description("数据库密码"),
93
+ DB_PORT: s.number(5432).min(1).max(65535),
94
+ },
95
+ {
96
+ // 在 Monorepo 或特定部署环境下,可显式指定 .env 所在目录
97
+ // cwd: '/path/to/project-root'
98
+ },
99
+ );
90
100
 
91
101
  export default config;
92
102
  ```
@@ -96,6 +106,7 @@ export default config;
96
106
  ### 🛠️ API 详解
97
107
 
98
108
  #### 1. 定义字段 (`s.xxx`)
109
+
99
110
  - `s.string(default?)`: 字符串。若无默认值则必填。
100
111
  - `s.number(default?)`: 数字。自动转换为 `number` 类型并校验合法性。
101
112
  - `s.boolean(default?)`: 布尔型。支持将 `"true"`, `"1"`, `"yes"`, `"on"` 解析为 `true`。
@@ -108,43 +119,50 @@ export default config;
108
119
 
109
120
  - **`.secret()`**: 标记敏感数据,报错时该值会以 `********` 遮罩显示。
110
121
  ```typescript
111
- PASSWORD: s.string().secret()
122
+ PASSWORD: s.string().secret();
112
123
  ```
113
124
  - **`.url()` / `.email()`**: 常用格式校验。
114
125
  ```typescript
115
- API_URL: s.string().url()
126
+ API_URL: s.string().url();
116
127
  ```
117
128
  - **`.regex(pattern, msg?)`**: 自定义正则校验。
118
129
  ```typescript
119
- VERSION: s.string().regex(/^v\d+\.\d+\.\d+$/, "格式错误")
130
+ VERSION: s.string().regex(/^v\d+\.\d+\.\d+$/, "格式错误");
120
131
  ```
121
132
  - **`.description(text)`**: 添加变量描述,映射到 IDE 悬停提示中。
122
133
  ```typescript
123
- PORT: s.number(3000).description("服务端口")
134
+ PORT: s.number(3000).description("服务端口");
124
135
  ```
125
136
  - **`.transform(fn)`**: 自定义数据转换,支持多级 Pipe。
126
137
  ```typescript
127
- NAME: s.string().transform(v => v.trim()).transform(v => v.toUpperCase())
138
+ NAME: s.string()
139
+ .transform((v) => v.trim())
140
+ .transform((v) => v.toUpperCase());
128
141
  ```
129
142
  - **`.from(key)`**: 映射环境变量名(别名)。
130
143
  ```typescript
131
- port: s.number().from('VITE_SERVER_PORT')
144
+ port: s.number().from("VITE_SERVER_PORT");
132
145
  ```
133
146
  - **`.min(n)` / `.max(n)`**: 限制数字取值范围。
134
147
  ```typescript
135
- PORT: s.number().min(1024).max(65535)
148
+ PORT: s.number().min(1024).max(65535);
136
149
  ```
137
150
  - **`.validate(fn, msg?)`**: 完全自定义的逻辑校验。
138
151
  ```typescript
139
- INTERNAL_URL: s.string().validate(v => v.endsWith('.internal.com'), 'Must be internal')
152
+ INTERNAL_URL: s.string().validate(
153
+ (v) => v.endsWith(".internal.com"),
154
+ "Must be internal",
155
+ );
140
156
  ```
141
157
 
142
158
  ---
143
159
 
144
160
  ### 🎨 错误报告
161
+
145
162
  当校验失败时,`safe-env` 会在控制台输出结构化的自适应表格,清晰展示:**Key / 错误原因 / 当前值(已脱敏)**。
146
163
 
147
164
  ---
148
165
 
149
166
  ### 📄 开源协议 (License)
167
+
150
168
  [MIT License](./LICENSE) - Copyright (c) 2026 Moody.
@@ -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 _chunkCYBE3YNHcjs = require('./chunk-CYBE3YNH.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 = _chunkCYBE3YNHcjs.c; exports.DEV = _chunkCYBE3YNHcjs.a; exports.SERVE = _chunkCYBE3YNHcjs.b; exports.VITE_DEV_FLAG = _chunkCYBE3YNHcjs.d; exports.VITE_PREFIX = _chunkCYBE3YNHcjs.e; exports.formatErrorReport = _chunkCYBE3YNHcjs.f; exports.parseDotEnv = _chunk5LT4H5GXcjs.a; exports.reportErrors = _chunkCYBE3YNHcjs.g; exports.s = p; exports.safeEnv = _chunkCYBE3YNHcjs.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-MZ3R3VUV.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 _chunkCYBE3YNHcjs = require('./chunk-CYBE3YNH.cjs');require('./chunk-D6WM53FN.cjs');var _vite = require('vite');function y(v,f={}){let n=null,o=!1;return{name:"vite-plugin-safe-env",configResolved(e){o=e.command===_chunkCYBE3YNHcjs.b,process.env[_chunkCYBE3YNHcjs.d]=o?"true":"";let{envDir:t=e.root,prefix:r=e.envPrefix||_chunkCYBE3YNHcjs.e}=f,c=_vite.loadEnv.call(void 0, e.mode,t,r);try{_chunkCYBE3YNHcjs.h.call(void 0, v,{source:c,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
- `),process.exit(1))}},transform(e,t){if(o&&n&&e.includes("@zh-moody/safe-env")){let r=new Error(n.plainMessage||n.message);throw r.stack="",r}return null}}}exports.viteSafeEnv = y;
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
+ `),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-MZ3R3VUV.js";import"./chunk-I7AUKTXE.js";import{loadEnv as p}from"vite";function y(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,c=p(e.mode,t,r);try{m(v,{source:c,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
- `),process.exit(1))}},transform(e,t){if(o&&n&&e.includes("@zh-moody/safe-env")){let r=new Error(n.plainMessage||n.message);throw r.stack="",r}return null}}}export{y as viteSafeEnv};
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
+ `),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.5",
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,8 +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",I= exports.b ="serve",_= exports.c ="build",$= exports.d ="VITE_DEV_SERVER",K= exports.e ="VITE_";var F={r:"\x1B[31m",g:"\x1B[32m",y:"\x1B[33m",b:"\x1B[1m",res:"\x1B[0m",d:"\x1B[2m",cy:"\x1B[36m"},k=typeof window<"u"&&typeof window.document<"u",g=(s,i)=>{let r=String(s),n=()=>r.length+(r.match(/[^\x00-\xff]/g)||[]).length;for(;n()>i;)r=r.slice(0,-1);return r+" ".repeat(i-n())};function v(s,i=!0){let r=Math.max(80,(typeof process<"u"?process.stdout.columns:80)||80)-10,n=Math.floor(r*.3),y=Math.floor(r*.5),e=i?F:{r:"",g:"",y:"",b:"",res:"",d:"",cy:""},a="";return a+=`
2
- ${e.r}${e.b}\u274C SafeEnv Validation Failed${e.res}
3
- `,a+=` ${e.b}${g("Key",n)} \u2502 ${g("Error",y)} \u2502 Value${e.res}
4
- `,a+=e.d+"\u2500".repeat(r+5)+e.res+`
5
- `,s.forEach(d=>{let E=d.value===void 0?"undefined":d.isSecret?"********":`"${d.value}"`,o=d.value===void 0?e.d:d.isSecret?e.y:e.cy;a+=` ${e.y}${g(d.key,n)}${e.res} \u2502 ${e.r}${g(d.error,y)}${e.res} \u2502 ${o}${E}${e.res}
6
- `}),a+=e.d+"\u2500".repeat(r+5)+e.res+`
7
- `,a+=` ${e.g}\u{1F4A1} Tip: Check your .env files or schema definitions.${e.res}
8
- `,a}function O(s){console.group("%c \u274C SafeEnv Validation Failed ","background: #fee2e2; color: #b91c1c; font-weight: bold; padding: 4px; border-radius: 2px;");let i=s.reduce((r,n)=>(r[n.key]={"Error Message":n.error,"Current Value":n.value===void 0?"undefined":n.isSecret?"********":n.value},r),{});console.table(i),console.log("%c \u{1F4A1} Tip: Check your .env files or schema definitions. ","color: #059669; font-style: italic;"),console.groupEnd()}function S(s){k?O(s):console.error(v(s,!0))}var x={};function R(){return new Proxy({},{get:()=>{}})}function A(s,i={}){let{loadProcessEnv:r=!0,prefix:n="",cwd:y,useCache:e=!0}=i,a=typeof window<"u",d=typeof process<"u"&&(!!process.env.VITE||!!process.env[$]),E=a||d||"source"in i,o;if(e&&Object.keys(x).length>0&&!("source"in i))o=x;else if("source"in i)o=i.source||{},e&&Object.keys(o).length>0&&Object.assign(x,o);else if(typeof process<"u"&&!a)try{let t=i.mode||process.env.NODE_ENV||T,{loadDotEnv:c}=_chunkD6WM53FNcjs.a.call(void 0, "./fs-node.cjs"),l={};for(let m of[".env",`.env.${t}`,".env.local",`.env.${t}.local`])l={...l,...c(m,y)};o={...l,...r?process.env:{}},e&&Object.keys(o).length>0&&Object.assign(x,o)}catch (e2){o={}}else o={};if(E&&Object.keys(o).length===0)return{};let b={},u=[];for(let t in s){let c=s[t],l=n&&!t.startsWith(n)?n+t:t,m=c.sourceKey||(o[l]!==void 0?l:o[t]!==void 0?t:l),p=o[m];try{if(p===void 0||p===""&&c.default!==void 0){if(c.required&&p===void 0)throw new Error("Missing required field");b[t]=c.default}else{let f=c.parse(p);if(f!==void 0&&c.metadata){let{min:h,max:D,validate:w}=c.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)}b[t]=f}}catch(f){u.push({key:m,error:f.message,value:p,isSecret:_optionalChain([c, 'access', _2 => _2.metadata, 'optionalAccess', _3 => _3.isSecret])})}}if(u.length>0){if(i.throwOnError){let t=new Error(v(u,!0));throw t.plainMessage=v(u,!1),t}return S(u),typeof process<"u"&&process.exit&&!E&&process.exit(1),R()}return Object.freeze(b)}exports.a = T; exports.b = I; exports.c = _; exports.d = $; exports.e = K; exports.f = v; exports.g = S; exports.h = A;
@@ -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,8 +0,0 @@
1
- import{a as V}from"./chunk-I7AUKTXE.js";var T="development",I="serve",_="build",$="VITE_DEV_SERVER",K="VITE_";var F={r:"\x1B[31m",g:"\x1B[32m",y:"\x1B[33m",b:"\x1B[1m",res:"\x1B[0m",d:"\x1B[2m",cy:"\x1B[36m"},k=typeof window<"u"&&typeof window.document<"u",g=(s,i)=>{let r=String(s),n=()=>r.length+(r.match(/[^\x00-\xff]/g)||[]).length;for(;n()>i;)r=r.slice(0,-1);return r+" ".repeat(i-n())};function v(s,i=!0){let r=Math.max(80,(typeof process<"u"?process.stdout.columns:80)||80)-10,n=Math.floor(r*.3),y=Math.floor(r*.5),e=i?F:{r:"",g:"",y:"",b:"",res:"",d:"",cy:""},a="";return a+=`
2
- ${e.r}${e.b}\u274C SafeEnv Validation Failed${e.res}
3
- `,a+=` ${e.b}${g("Key",n)} \u2502 ${g("Error",y)} \u2502 Value${e.res}
4
- `,a+=e.d+"\u2500".repeat(r+5)+e.res+`
5
- `,s.forEach(d=>{let E=d.value===void 0?"undefined":d.isSecret?"********":`"${d.value}"`,o=d.value===void 0?e.d:d.isSecret?e.y:e.cy;a+=` ${e.y}${g(d.key,n)}${e.res} \u2502 ${e.r}${g(d.error,y)}${e.res} \u2502 ${o}${E}${e.res}
6
- `}),a+=e.d+"\u2500".repeat(r+5)+e.res+`
7
- `,a+=` ${e.g}\u{1F4A1} Tip: Check your .env files or schema definitions.${e.res}
8
- `,a}function O(s){console.group("%c \u274C SafeEnv Validation Failed ","background: #fee2e2; color: #b91c1c; font-weight: bold; padding: 4px; border-radius: 2px;");let i=s.reduce((r,n)=>(r[n.key]={"Error Message":n.error,"Current Value":n.value===void 0?"undefined":n.isSecret?"********":n.value},r),{});console.table(i),console.log("%c \u{1F4A1} Tip: Check your .env files or schema definitions. ","color: #059669; font-style: italic;"),console.groupEnd()}function S(s){k?O(s):console.error(v(s,!0))}var x={};function R(){return new Proxy({},{get:()=>{}})}function A(s,i={}){let{loadProcessEnv:r=!0,prefix:n="",cwd:y,useCache:e=!0}=i,a=typeof window<"u",d=typeof process<"u"&&(!!process.env.VITE||!!process.env[$]),E=a||d||"source"in i,o;if(e&&Object.keys(x).length>0&&!("source"in i))o=x;else if("source"in i)o=i.source||{},e&&Object.keys(o).length>0&&Object.assign(x,o);else if(typeof process<"u"&&!a)try{let t=i.mode||process.env.NODE_ENV||T,{loadDotEnv:c}=V("./fs-node.cjs"),l={};for(let m of[".env",`.env.${t}`,".env.local",`.env.${t}.local`])l={...l,...c(m,y)};o={...l,...r?process.env:{}},e&&Object.keys(o).length>0&&Object.assign(x,o)}catch{o={}}else o={};if(E&&Object.keys(o).length===0)return{};let b={},u=[];for(let t in s){let c=s[t],l=n&&!t.startsWith(n)?n+t:t,m=c.sourceKey||(o[l]!==void 0?l:o[t]!==void 0?t:l),p=o[m];try{if(p===void 0||p===""&&c.default!==void 0){if(c.required&&p===void 0)throw new Error("Missing required field");b[t]=c.default}else{let f=c.parse(p);if(f!==void 0&&c.metadata){let{min:h,max:D,validate:w}=c.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)}b[t]=f}}catch(f){u.push({key:m,error:f.message,value:p,isSecret:c.metadata?.isSecret})}}if(u.length>0){if(i.throwOnError){let t=new Error(v(u,!0));throw t.plainMessage=v(u,!1),t}return S(u),typeof process<"u"&&process.exit&&!E&&process.exit(1),R()}return Object.freeze(b)}export{T as a,I as b,_ as c,$ as d,K as e,v as f,S as g,A as h};