@zh-moody/safe-env 0.4.0 → 0.4.2

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/README.en.md CHANGED
@@ -6,9 +6,9 @@
6
6
 
7
7
  [简体中文](./README.md) | English
8
8
 
9
- **Say goodbye to `undefined`! Intercept all configuration risks at the first line of your app.**
9
+ **Say goodbye to `undefined`! Intercept all configuration hazards on the first line of your app.**
10
10
 
11
- Whether you are writing Vue, React, or Node.js, environment variables are often a source of production incidents. `safe-env` ensures your app always runs on the expected configuration through strong-typed Schema validation and runtime protection.
11
+ Whether you're building with Vue, React, or Node.js, environment variables are often the root of production incidents. `safe-env` ensures your application always runs on top of expected configurations through strong schema validation and runtime protection.
12
12
 
13
13
  ---
14
14
 
@@ -16,14 +16,14 @@ Whether you are writing Vue, React, or Node.js, environment variables are often
16
16
 
17
17
  ---
18
18
 
19
- ### 🚀 Core Features
19
+ ### 🚀 Key Features
20
20
 
21
- - **Build-time Validation**: Provides a Vite plugin to intercept invalid configurations during development or build.
22
- - **Sensitive Data Masking**: Supports `.secret()` to ensure keys and passwords are masked as `********` in logs or error tables.
23
- - **Runtime Immutability**: Parsed config objects are deep-frozen with `Object.freeze` by default, preventing any illegal runtime modification.
24
- - **Monorepo Ready**: Supports `cwd` parameter to explicitly specify the `.env` directory, ideal for complex project architectures.
25
- - **IDE Enhancement**: Supports `.description()` to view variable usage and documentation directly via hover in your code.
26
- - **Rigorous Type Parsing**: Built-in `s.array()`, `s.boolean()` with enhanced conversion, and `.transform()` for chainable piping.
21
+ - **Build-time Pre-validation**: Vite plugin intercepts invalid configurations during dev startup or build.
22
+ - **Sensitive Data Masking**: Supports `.secret()` to ensure keys/tokens are masked in logs or error reports.
23
+ - **Runtime Lazy Protection**: **HPC Ready**. Powered by **Lazy Proxy**, achieving $O(1)$ startup latency and on-demand read-only protection.
24
+ - **Monorepo Ready**: Explicitly specify `.env` search directories via `cwd`, fitting complex architectures.
25
+ - **IDE Enhancement**: `.description()` allows you to view variable purposes/documentation via hover.
26
+ - **Robust Parsing**: Built-in `s.array()`, `s.boolean()` with intelligent conversion and `.transform()` pipe processing.
27
27
 
28
28
  ---
29
29
 
@@ -37,9 +37,15 @@ npm install @zh-moody/safe-env
37
37
 
38
38
  ### 🚀 Quick Start
39
39
 
40
- #### 🔹 [Vite / React / Vue]
40
+ Ensure you have a **`.env`** file in your project root before starting:
41
41
 
42
- For frontend projects, use the Vite plugin for **build-time validation**.
42
+ ```bash
43
+ # .env example
44
+ VITE_API_URL=https://api.example.com
45
+ VITE_PORT=8080
46
+ ```
47
+
48
+ #### 🔹 [Vite / React / Vue] Usage
43
49
 
44
50
  **1. Configure Vite Plugin (`vite.config.ts`):**
45
51
 
@@ -52,14 +58,14 @@ export default {
52
58
  };
53
59
  ```
54
60
 
55
- **2. Define and Export Config (`src/env.ts`):**
61
+ **2. Define and Export Schema (`src/env.ts`):**
56
62
 
57
63
  ```typescript
58
- import { safeEnv, s } from "@zh-moody/safe-env";
64
+ import { safeEnv, s, isUrl } from "@zh-moody/safe-env";
59
65
 
60
66
  export const schema = {
61
- VITE_API_URL: s.string().url().description("Backend API Base URL"),
62
- VITE_PORT: s.number(3000).description("Development Server Port"),
67
+ VITE_API_URL: s.string().validate(isUrl, "Invalid URL").description("Backend API endpoint"),
68
+ VITE_PORT: s.number(3000).description("Server port"),
63
69
  };
64
70
 
65
71
  export const env = safeEnv(schema, {
@@ -67,33 +73,22 @@ export const env = safeEnv(schema, {
67
73
  });
68
74
  ```
69
75
 
70
- > **💡 Best Practice: Prevent Vite Type Pollution**
71
- > To completely disable the insecure original `import.meta.env.XXX` hints, modify `src/vite-env.d.ts`:
72
- >
73
- > ```typescript
74
- > interface ImportMetaEnv {
75
- > [key: string]: never;
76
- > }
77
- > ```
78
-
79
76
  ---
80
77
 
81
- #### 🔸 [Node.js / Server-side]
78
+ #### 🔸 [Node.js / Server-side] Usage
82
79
 
83
- In Node.js, the library automatically looks for and parses `.env` files on disk.
84
-
85
- **1. Define Config (`src/config.ts`):**
80
+ **1. Define Configuration (`src/config.ts`):**
86
81
 
87
82
  ```typescript
88
83
  import { safeEnv, s } from "@zh-moody/safe-env";
89
84
 
90
85
  const config = safeEnv(
91
86
  {
92
- DB_PASSWORD: s.string().secret().description("Database Password"),
87
+ DB_PASSWORD: s.string().secret().description("Database password"),
93
88
  DB_PORT: s.number(5432).min(1).max(65535),
94
89
  },
95
90
  {
96
- // Explicitly specify the .env directory for Monorepo or specific deployments
91
+ // Explicitly specify .env root in Monorepo or deployment environments
97
92
  // cwd: '/path/to/project-root'
98
93
  },
99
94
  );
@@ -105,59 +100,100 @@ export default config;
105
100
 
106
101
  ### 🛠️ API Reference
107
102
 
108
- #### 1. Define Fields (`s.xxx`)
103
+ #### 1. Global Options (`safeEnv`)
104
+
105
+ `safeEnv(schema, options?)` accepts an optional object to control the parsing engine:
106
+
107
+ - **`useCache (boolean)`**: Enable global memoization (default `true`). Significantly improves performance for high-frequency calls.
108
+ - **`refreshCache (boolean)`**: Force flush and re-read disk/process variables (default `false`). Essential for HMR or switching envs in automated tests.
109
+ - **`cwd (string)`**: Specify the search root for `.env` files (Node.js).
110
+ - **`source (Record<string, any>)`**: Manually provide the data source (e.g., `import.meta.env`), skipping automatic file retrieval.
111
+ - **`prefix (string)`**: Filter prefix for env variables (default `VITE_`).
112
+
113
+ #### 2. Field Definitions (`s.xxx`)
109
114
 
110
- - `s.string(default?)`: String field. Required if no default value.
111
- - `s.number(default?)`: Automatically converted to `number` and validated.
112
- - `s.boolean(default?)`: Supports `"true"`, `"1"`, `"yes"`, `"on"` as `true`.
113
- - `s.array(default?, separator?)`: Splits string by separator (default `,`) into an array.
114
- - `s.enum(options, default?)`: Value must be one of the provided options.
115
+ - **`s.string(default?)`**:
116
+ - **Logic**: If no default is provided, it's marked as **Required**.
117
+ - **`s.number(default?)`**:
118
+ - **Logic**: Executes `Number(v)`. Aborts with an error if result is `NaN` (e.g., `VITE_PORT=abc`).
119
+ - **`s.boolean(default?)`**: Intelligent Boolean parsing.
120
+ - **Logic**:
121
+ - **`true`**: `true`, `"true"`, `"1"`, `"yes"`, `"on"`.
122
+ - **`false`**: `false`, `"false"`, `"0"`, `"no"`, `"off"`, or empty strings.
123
+ - **`s.array(default?, separator?)`**:
124
+ - **Logic**: Default separator is `,`. Supports custom ones like `s.array([], '|')`.
125
+ - **`s.enum(options, default?)`**:
126
+ - **Logic**: Input must be one of the `options`. Perfect for mode locking (`dev`, `prod`, `test`).
115
127
 
116
- #### 2. Validation & Enhancement (Chainable)
128
+ #### 3. Enhancements & Validation (Chaining)
117
129
 
118
- - **`.secret()`**: Masks the value as `********` in error reports.
130
+ - **`.secret()`**: Mask sensitive data in error reports (`********`).
119
131
  ```typescript
120
132
  PASSWORD: s.string().secret();
121
133
  ```
122
- - **`.url()` / `.email()`**: Built-in format validation.
134
+ - **`.description(text)`**: Hover hints for IDEs.
123
135
  ```typescript
124
- API_URL: s.string().url();
136
+ PORT: s.number(3000).description("Server port");
125
137
  ```
126
- - **`.regex(pattern, msg?)`**: Custom regex validation.
138
+ - **`.optional()`**: Explicitly declare this field as optional. Missing values drop back to `undefined` instead of throwing an error.
127
139
  ```typescript
128
- VERSION: s.string().regex(/^v\d+\.\d+\.\d+$/, "Invalid format");
140
+ TRACKING_ID: s.string().optional();
129
141
  ```
130
- - **`.description(text)`**: Adds a description for IDE hover hints.
142
+ - **`.requiredIf(fn)`**: Context-Aware validation. Dynamically determine if the field is required based on values parsed so far.
131
143
  ```typescript
132
- PORT: s.number(3000).description("Server Port");
144
+ // ICP_NUMBER is required ONLY if parsed REGION equals 'CN'
145
+ ICP_NUMBER: s.string().requiredIf((ctx) => ctx.parsed.REGION === 'CN');
133
146
  ```
134
- - **`.transform(fn)`**: Custom data transformation, supports multi-level piping.
147
+ - **`.transform(fn)`**: Custom data transformation (Multi-level pipe).
135
148
  ```typescript
136
149
  NAME: s.string()
137
150
  .transform((v) => v.trim())
138
151
  .transform((v) => v.toUpperCase());
139
152
  ```
140
- - **`.from(key)`**: Maps environment variable name (Alias).
153
+ - **`.from(key)`**: Alias mapping (Environment key mapping).
141
154
  ```typescript
142
155
  port: s.number().from("VITE_SERVER_PORT");
143
156
  ```
144
- - **`.min(n)` / `.max(n)`**: Constraints for number values.
157
+ - **`.min(n)` / `.max(n)`**: Number range constraints.
145
158
  ```typescript
146
159
  PORT: s.number().min(1024).max(65535);
147
160
  ```
148
- - **`.validate(fn, msg?)`**: Fully custom validation logic.
161
+ - **`.validate(fn, msg?)`**: Custom logic validation. Supports context passing and native pure-function integration (See "Built-in Validation Rules").
149
162
  ```typescript
150
163
  INTERNAL_URL: s.string().validate(
151
- (v) => v.endsWith(".internal.com"),
164
+ (v, ctx) => v.endsWith(".internal.com"),
152
165
  "Must be internal",
153
166
  );
154
167
  ```
155
168
 
169
+ #### 4. Built-in Validation Rules
170
+
171
+ To support an infinite amount of business validation logic without blowing up bundle sizes, all heavy string validators (like Regex) and transformers are separated from the core class. They are instead provided as **pure, perfectly tree-shakable higher-order functions** that can be imported directly.
172
+
173
+ Seamlessly integrate them using native `validate`/`transform` methods:
174
+
175
+ ```typescript
176
+ import { safeEnv, s, isUrl, isIPv4, isUUID, isJSON, toJSON, trim } from "@zh-moody/safe-env";
177
+
178
+ const schema = {
179
+ // Dirty data processing: Trim whitespaces, then validate IPv4
180
+ HOST: s.string().transform(trim).validate(isIPv4, "Must be valid IPv4"),
181
+ // Serialization mapping natively
182
+ PAYLOAD: s.string().validate(isJSON).transform(toJSON),
183
+ // Common URL link checking
184
+ API_URL: s.string().validate(isUrl, "Must be a valid URL")
185
+ };
186
+ ```
187
+
188
+ Currently, `@zh-moody/safe-env` exports the following utility functions out-of-the-box:
189
+ - **Validators**: `isUrl`, `isEmail`, `isIPv4`, `isUUID`, `isBase64`, `isJSON`, `isHexColor`, `isObjectId`, `matchesRegex(pattern)`
190
+ - **Transformers**: `trim`, `toLowerCase`, `toUpperCase`, `toJSON`
191
+
156
192
  ---
157
193
 
158
194
  ### 🎨 Error Reporting
159
195
 
160
- When validation fails, `safe-env` outputs a structured, adaptive table in the console showing: **Key / Error Reason / Current Value (Masked)**.
196
+ When validation fails, `safe-env` outputs an adaptive structured table showing: **Key / Error / Current Value (Masked)**.
161
197
 
162
198
  ---
163
199
 
package/README.md CHANGED
@@ -37,6 +37,14 @@ npm install @zh-moody/safe-env
37
37
 
38
38
  ### 🚀 快速上手
39
39
 
40
+ 在开始之前,请确保你的项目根目录下已有相应的 **`.env`** 配置文件:
41
+
42
+ ```bash
43
+ # .env 示例
44
+ VITE_API_URL=https://api.example.com
45
+ VITE_PORT=8080
46
+ ```
47
+
40
48
  #### 🔹 [Vite / React / Vue] 使用
41
49
 
42
50
  在前端,建议配合 Vite 插件实现**构建时校验**。
@@ -105,15 +113,33 @@ export default config;
105
113
 
106
114
  ### 🛠️ API 详解
107
115
 
108
- #### 1. 定义字段 (`s.xxx`)
116
+ #### 1. 全局配置与选项 (`safeEnv`)
117
+
118
+ `safeEnv(schema, options?)` 接收一个可选的配置对象,用于深度控制解析行为:
119
+
120
+ - **`useCache (boolean)`**: 是否启用全局缓存(默认 `true`)。开启后,后续调用将优先从内存获取已解析的配置,极大提升高频调用的性能。
121
+ - **`refreshCache (boolean)`**: 强制刷新并重新读取磁盘/进程变量(默认 `false`)。常用于开发环境下的热更新或自动化测试中切换不同的环境配置。
122
+ - **`cwd (string)`**: 显式指定 `.env` 文件的检索根目录(Node.js 环境)。
123
+ - **`source (Record<string, any>)`**: 手动指定数据源(如 `import.meta.env` 或 `process.env`),跳过自动文件检索。
124
+ - **`prefix (string)`**: 过滤环境变量的前缀(默认 `VITE_`)。
125
+
126
+ #### 2. 定义字段 (`s.xxx`)
109
127
 
110
- - `s.string(default?)`: 字符串。若无默认值则必填。
111
- - `s.number(default?)`: 数字。自动转换为 `number` 类型并校验合法性。
112
- - `s.boolean(default?)`: 布尔型。支持将 `"true"`, `"1"`, `"yes"`, `"on"` 解析为 `true`。
113
- - `s.array(default?, separator?)`: 数组型。支持将字符串按分隔符(默认 `,`)拆分为数组。
114
- - `s.enum(options, default?)`: 枚举。值必须在预设数组中。
128
+ - **`s.string(default?)`**: 字符串解析。
129
+ - **逻辑**: 如果不提供默认值,该字段将被标记为 **必填 (Required)**,若 `.env` 中缺失会触发报错。
130
+ - **`s.number(default?)`**: 数字解析。
131
+ - **逻辑**: 自动执行 `Number(v)`。若转换结果为 `NaN`(如 `VITE_PORT=abc`),解析会立即中止并报错。
132
+ - **`s.boolean(default?)`**: 增强布尔解析。
133
+ - **逻辑**: 支持多种真假语义的自动转换:
134
+ - **`true`**: `true`, `"true"`, `"1"`, `"yes"`, `"on"`。
135
+ - **`false`**: `false`, `"false"`, `"0"`, `"no"`, `"off"`, 以及空字符串。
136
+ - **`s.array(default?, separator?)`**: 数组解析。
137
+ - **逻辑**: 默认使用 `,` 作为分隔符。支持自定义,如 `s.array([], '|')`。
138
+ - **示例**: `VITE_MODS=auth,cache` ➡️ `['auth', 'cache']`。
139
+ - **`s.enum(options, default?)`**: 枚举约束。
140
+ - **逻辑**: 强制输入值必须在 `options` 数组中,否则报错。非常适用于多环境(`dev`, `prod`, `test`)的模式锁定。
115
141
 
116
- #### 2. 校验与增强 (链式调用)
142
+ #### 3. 校验与增强 (链式调用)
117
143
 
118
144
  每个字段都可以通过链式调用进行深度定制:
119
145
 
@@ -121,13 +147,14 @@ export default config;
121
147
  ```typescript
122
148
  PASSWORD: s.string().secret();
123
149
  ```
124
- - **`.url()` / `.email()`**: 常用格式校验。
150
+ - **`.optional()`**: 显式声明该字段为非必填。解析如果不存在,则返回 `undefined` 而不报错。
125
151
  ```typescript
126
- API_URL: s.string().url();
152
+ TRACKING_ID: s.string().optional();
127
153
  ```
128
- - **`.regex(pattern, msg?)`**: 自定义正则校验。
154
+ - **`.requiredIf(fn)`**: 联动校验(Context-Aware)。依据当前已解析的其他配置动态决定该字段是否必填。
129
155
  ```typescript
130
- VERSION: s.string().regex(/^v\d+\.\d+\.\d+$/, "格式错误");
156
+ // 只有当 REGION 明确被设为 CN 时,ICP 备案号才是必填的
157
+ ICP_NUMBER: s.string().requiredIf((ctx) => ctx.parsed.REGION === 'CN');
131
158
  ```
132
159
  - **`.description(text)`**: 添加变量描述,映射到 IDE 悬停提示中。
133
160
  ```typescript
@@ -147,14 +174,36 @@ export default config;
147
174
  ```typescript
148
175
  PORT: s.number().min(1024).max(65535);
149
176
  ```
150
- - **`.validate(fn, msg?)`**: 完全自定义的逻辑校验。
177
+ - **`.validate(fn, msg?)`**: 传入纯函数进行校验。支持上下文透传以及库内置高阶纯函数的直接切入(详情见下文 "内置验证库")。
151
178
  ```typescript
152
179
  INTERNAL_URL: s.string().validate(
153
- (v) => v.endsWith(".internal.com"),
180
+ (v, ctx) => v.endsWith(".internal.com"),
154
181
  "Must be internal",
155
182
  );
156
183
  ```
157
184
 
185
+ #### 4. 内置验证库
186
+
187
+ 为了支持无限的业务规则而不造成构建体积膨胀,所有重型字符串校验(长正则)和转换规则均剔除出了核心类,化作了**支持完美 Tree-Shaking 的扁平化导出的高阶函数**。只有你明确通过 `import` 引用的微小单点代码才会被真正打包!
188
+
189
+ 使用原生 `validate`/`transform` 方法无隙集成它们:
190
+ ```typescript
191
+ import { safeEnv, s, isUrl, isIPv4, isUUID, isJSON, toJSON, trim } from "@zh-moody/safe-env";
192
+
193
+ const schema = {
194
+ // 脏数据清理:先裁剪首尾空格、后校验 IPv4 格式
195
+ HOST: s.string().transform(trim).validate(isIPv4, "必需是合法 IPv4"),
196
+ // 支持链式序列化
197
+ PAYLOAD: s.string().validate(isJSON).transform(toJSON),
198
+ // 甚至只是普通的链接和格式判定
199
+ API_URL: s.string().validate(isUrl, "必须抛出无效链接")
200
+ };
201
+ ```
202
+
203
+ 目前的 `@zh-moody/safe-env` 原生伴随导出了以下优质清洗函数组合,按需使用即可:
204
+ - **Validators (验证器)**: `isUrl`, `isEmail`, `isIPv4`, `isUUID`, `isBase64`, `isJSON`, `isHexColor`, `isObjectId`, `matchesRegex(pattern)`
205
+ - **Transformers (转换器)**: `trim`, `toLowerCase`, `toUpperCase`, `toJSON`
206
+
158
207
  ---
159
208
 
160
209
  ### 🎨 错误报告
@@ -0,0 +1 @@
1
+ import u from"fs";import a from"path";function m(r){let n={},i=r.split(/\r?\n/);for(let d of i){let e=d.trim();if(!e||e.startsWith("#"))continue;let o=e.indexOf("=");if(o===-1)continue;let s=e.slice(0,o).trim(),t=e.slice(o+1).trim();if(!t){n[s]="";continue}let c=t[0];if(c==='"'||c==="'"){let l=t.indexOf(c,1);if(l!==-1){n[s]=t.slice(1,l);continue}}let f=t.indexOf("#");f!==-1&&(t=t.slice(0,f).trim()),n[s]=t}return n}function h(r=".env",n){try{let i=a.resolve(n||process.cwd(),r);if(u.existsSync(i))return m(u.readFileSync(i,"utf-8"))}catch{}return{}}export{m as a,h as b};
@@ -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 F="development",j= exports.b ="serve",K= exports.c ="build",C= exports.d ="VITE_DEV_SERVER",k= exports.e ="VITE_";var O=typeof window<"u"&&typeof window.document<"u";function b(i,o=!0){if(O)return`SafeEnv Validation Failed: ${i.map(s=>`${s.key} (${s.error})`).join(", ")}`;let d={r:"\x1B[31m",g:"\x1B[32m",y:"\x1B[33m",b:"\x1B[1m",res:"\x1B[0m",d:"\x1B[2m",cy:"\x1B[36m"},n=(s,p)=>{let r=String(s),x=()=>r.length+(r.match(/[^\x00-\xff]/g)||[]).length;for(;x()>p;)r=r.slice(0,-1);return r+" ".repeat(p-x())},c=Math.max(80,(typeof process<"u"?process.stdout.columns:80)||80)-10,u=Math.floor(c*.3),y=Math.floor(c*.5),e=o?d:{r:"",g:"",y:"",b:"",res:"",d:"",cy:""},f=`
2
+ ${e.r}${e.b}\u274C SafeEnv Validation Failed${e.res}
3
+ `;return f+=` ${e.b}${n("Key",u)} \u2502 ${n("Error",y)} \u2502 Value${e.res}
4
+ `,f+=e.d+"\u2500".repeat(c+5)+e.res+`
5
+ `,i.forEach(s=>{let p=s.value===void 0?"undefined":s.isSecret?"********":`"${s.value}"`,r=s.value===void 0?e.d:s.isSecret?e.y:e.cy;f+=` ${e.y}${n(s.key,u)}${e.res} \u2502 ${e.r}${n(s.error,y)}${e.res} \u2502 ${r}${p}${e.res}
6
+ `}),f+=e.d+"\u2500".repeat(c+5)+e.res+`
7
+ `,f+=` ${e.g}\u{1F4A1} Tip: Check your .env files or schema definitions.${e.res}
8
+ `,f}function _(i){if(O){console.group("%c \u274C SafeEnv Validation Failed ","background: #fee2e2; color: #b91c1c; font-weight: bold; padding: 4px; border-radius: 2px;");let o=i.reduce((d,n)=>(d[n.key]={"Error Message":n.error,"Current Value":n.value===void 0?"undefined":n.isSecret?"********":n.value},d),{});console.table(o),console.log("%c \u{1F4A1} Tip: Check your .env files or schema definitions. ","color: #059669; font-style: italic;"),console.groupEnd()}else console.error(b(i,!0))}var l={},$=new WeakMap;function P(i){let o=b(i,!1);return new Proxy({},{get(d,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
+ ${o}`)},ownKeys(){return[]},getOwnPropertyDescriptor(){}})}var w="[safe-env] Cannot modify read-only environment variables.";function I(i){if($.has(i))return $.get(i);let o=new Proxy(i,{get(d,n){if(n==="__isSafeEnv")return!0;let c=Reflect.get(d,n);return c!==null&&typeof c=="object"&&!Object.isFrozen(c)?I(c):c},set(){throw new Error(w)},deleteProperty(){throw new Error(w)},defineProperty(){throw new Error(w)},setPrototypeOf(){throw new Error(w)}});return $.set(i,o),o}function X(i,o={}){let{loadProcessEnv:d=!0,prefix:n=k,cwd:c,useCache:u=!0,refreshCache:y=!1,envLoader:e}=o;if(y)for(let t in l)delete l[t];let f=typeof window<"u",s=typeof process<"u"&&(!!process.env.VITE||!!process.env[C]),p=f||s||"source"in o,r={},x=!1;if("source"in o)o.source===void 0?(x=!0,r={}):r=o.source;else if(u&&!y&&Object.keys(l).length>0)r=l;else if(typeof process<"u"&&!f)try{let t=o.mode||process.env.NODE_ENV||F,a={};if(e)for(let v of[".env",`.env.${t}`,".env.local",`.env.${t}.local`])a={...a,...e(v,c)};r={...a,...d?process.env:{}}}catch (e2){r={}}u&&!y&&Object.keys(l).length>0?Object.keys(r).length===0?r=l:Object.assign(l,r):u&&Object.keys(r).length>0&&Object.assign(l,r);let h={},E=[];for(let t in i){let a=i[t],v=n&&!t.startsWith(n)?n+t:t,S=a.sourceKey||(r[v]!==void 0?v:r[t]!==void 0?t:v),m=r[S],R={source:r,parsed:h};try{let D=typeof a.required=="function"?a.required(R):a.required;if(m===void 0||m===""&&a.default!==void 0){if(D&&m===void 0)throw new Error("Missing required field");h[t]=a.default}else{let g=a.parse(m,R);if(g!==void 0&&a.metadata){let{min:T,max:V}=a.metadata;if(typeof g=="number"){if(T!==void 0&&g<T)throw new Error(`Below min ${T}`);if(V!==void 0&&g>V)throw new Error(`Above max ${V}`)}}h[t]=g}}catch(D){E.push({key:S,error:D.message,value:m,isSecret:_optionalChain([a, 'access', _2 => _2.metadata, 'optionalAccess', _3 => _3.isSecret])})}}if(E.length>0){if(o.throwOnError){let t=new Error(b(E,!0));throw t.plainMessage=b(E,!1),t}return x||_(E),typeof process<"u"&&process.exit&&!p&&process.exit(1),P(E)}return I(h)}exports.a = F; exports.b = j; exports.c = K; exports.d = C; exports.e = k; exports.f = b; exports.g = _; exports.h = X;
@@ -0,0 +1,9 @@
1
+ var F="development",j="serve",K="build",C="VITE_DEV_SERVER",k="VITE_";var O=typeof window<"u"&&typeof window.document<"u";function b(i,o=!0){if(O)return`SafeEnv Validation Failed: ${i.map(s=>`${s.key} (${s.error})`).join(", ")}`;let d={r:"\x1B[31m",g:"\x1B[32m",y:"\x1B[33m",b:"\x1B[1m",res:"\x1B[0m",d:"\x1B[2m",cy:"\x1B[36m"},n=(s,p)=>{let r=String(s),x=()=>r.length+(r.match(/[^\x00-\xff]/g)||[]).length;for(;x()>p;)r=r.slice(0,-1);return r+" ".repeat(p-x())},c=Math.max(80,(typeof process<"u"?process.stdout.columns:80)||80)-10,u=Math.floor(c*.3),y=Math.floor(c*.5),e=o?d:{r:"",g:"",y:"",b:"",res:"",d:"",cy:""},f=`
2
+ ${e.r}${e.b}\u274C SafeEnv Validation Failed${e.res}
3
+ `;return f+=` ${e.b}${n("Key",u)} \u2502 ${n("Error",y)} \u2502 Value${e.res}
4
+ `,f+=e.d+"\u2500".repeat(c+5)+e.res+`
5
+ `,i.forEach(s=>{let p=s.value===void 0?"undefined":s.isSecret?"********":`"${s.value}"`,r=s.value===void 0?e.d:s.isSecret?e.y:e.cy;f+=` ${e.y}${n(s.key,u)}${e.res} \u2502 ${e.r}${n(s.error,y)}${e.res} \u2502 ${r}${p}${e.res}
6
+ `}),f+=e.d+"\u2500".repeat(c+5)+e.res+`
7
+ `,f+=` ${e.g}\u{1F4A1} Tip: Check your .env files or schema definitions.${e.res}
8
+ `,f}function _(i){if(O){console.group("%c \u274C SafeEnv Validation Failed ","background: #fee2e2; color: #b91c1c; font-weight: bold; padding: 4px; border-radius: 2px;");let o=i.reduce((d,n)=>(d[n.key]={"Error Message":n.error,"Current Value":n.value===void 0?"undefined":n.isSecret?"********":n.value},d),{});console.table(o),console.log("%c \u{1F4A1} Tip: Check your .env files or schema definitions. ","color: #059669; font-style: italic;"),console.groupEnd()}else console.error(b(i,!0))}var l={},$=new WeakMap;function P(i){let o=b(i,!1);return new Proxy({},{get(d,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
+ ${o}`)},ownKeys(){return[]},getOwnPropertyDescriptor(){}})}var w="[safe-env] Cannot modify read-only environment variables.";function I(i){if($.has(i))return $.get(i);let o=new Proxy(i,{get(d,n){if(n==="__isSafeEnv")return!0;let c=Reflect.get(d,n);return c!==null&&typeof c=="object"&&!Object.isFrozen(c)?I(c):c},set(){throw new Error(w)},deleteProperty(){throw new Error(w)},defineProperty(){throw new Error(w)},setPrototypeOf(){throw new Error(w)}});return $.set(i,o),o}function X(i,o={}){let{loadProcessEnv:d=!0,prefix:n=k,cwd:c,useCache:u=!0,refreshCache:y=!1,envLoader:e}=o;if(y)for(let t in l)delete l[t];let f=typeof window<"u",s=typeof process<"u"&&(!!process.env.VITE||!!process.env[C]),p=f||s||"source"in o,r={},x=!1;if("source"in o)o.source===void 0?(x=!0,r={}):r=o.source;else if(u&&!y&&Object.keys(l).length>0)r=l;else if(typeof process<"u"&&!f)try{let t=o.mode||process.env.NODE_ENV||F,a={};if(e)for(let v of[".env",`.env.${t}`,".env.local",`.env.${t}.local`])a={...a,...e(v,c)};r={...a,...d?process.env:{}}}catch{r={}}u&&!y&&Object.keys(l).length>0?Object.keys(r).length===0?r=l:Object.assign(l,r):u&&Object.keys(r).length>0&&Object.assign(l,r);let h={},E=[];for(let t in i){let a=i[t],v=n&&!t.startsWith(n)?n+t:t,S=a.sourceKey||(r[v]!==void 0?v:r[t]!==void 0?t:v),m=r[S],R={source:r,parsed:h};try{let D=typeof a.required=="function"?a.required(R):a.required;if(m===void 0||m===""&&a.default!==void 0){if(D&&m===void 0)throw new Error("Missing required field");h[t]=a.default}else{let g=a.parse(m,R);if(g!==void 0&&a.metadata){let{min:T,max:V}=a.metadata;if(typeof g=="number"){if(T!==void 0&&g<T)throw new Error(`Below min ${T}`);if(V!==void 0&&g>V)throw new Error(`Above max ${V}`)}}h[t]=g}}catch(D){E.push({key:S,error:D.message,value:m,isSecret:a.metadata?.isSecret})}}if(E.length>0){if(o.throwOnError){let t=new Error(b(E,!0));throw t.plainMessage=b(E,!1),t}return x||_(E),typeof process<"u"&&process.exit&&!p&&process.exit(1),P(E)}return I(h)}export{F as a,j as b,K as c,C as d,k as e,b as f,_ as g,X as h};
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs);var _path = require('path'); var _path2 = _interopRequireDefault(_path);function m(r){let n={},i=r.split(/\r?\n/);for(let d of i){let e=d.trim();if(!e||e.startsWith("#"))continue;let o=e.indexOf("=");if(o===-1)continue;let s=e.slice(0,o).trim(),t=e.slice(o+1).trim();if(!t){n[s]="";continue}let c=t[0];if(c==='"'||c==="'"){let l=t.indexOf(c,1);if(l!==-1){n[s]=t.slice(1,l);continue}}let f=t.indexOf("#");f!==-1&&(t=t.slice(0,f).trim()),n[s]=t}return n}function h(r=".env",n){try{let i=_path2.default.resolve(n||process.cwd(),r);if(_fs2.default.existsSync(i))return m(_fs2.default.readFileSync(i,"utf-8"))}catch (e2){}return{}}exports.a = m; exports.b = h;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});require('./chunk-D6WM53FN.cjs');function r(n=".env",t){return{}}exports.loadDotEnv = r;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});function r(n=".env",t){return{}}exports.loadDotEnv = r;
@@ -1 +1 @@
1
- import"./chunk-I7AUKTXE.js";function r(n=".env",t){return{}}export{r as loadDotEnv};
1
+ function r(n=".env",t){return{}}export{r as loadDotEnv};
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 _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;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkTR6KYAQIcjs = require('./chunk-TR6KYAQI.cjs');exports.loadDotEnv = _chunkTR6KYAQIcjs.b;
package/dist/fs-node.js CHANGED
@@ -1 +1 @@
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};
1
+ import{b as a}from"./chunk-5KPNMU6R.js";export{a as loadDotEnv};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkPLO26PP5cjs = require('./chunk-PLO26PP5.cjs');var _chunkPBYVLIUGcjs = require('./chunk-PBYVLIUG.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 = _chunkPBYVLIUGcjs.c; exports.DEV = _chunkPBYVLIUGcjs.a; exports.SERVE = _chunkPBYVLIUGcjs.b; exports.VITE_DEV_FLAG = _chunkPBYVLIUGcjs.d; exports.VITE_PREFIX = _chunkPBYVLIUGcjs.e; exports.formatErrorReport = _chunkPBYVLIUGcjs.f; exports.parseDotEnv = _chunkPLO26PP5cjs.a; exports.reportErrors = _chunkPBYVLIUGcjs.g; exports.s = m; exports.safeEnv = _chunkPBYVLIUGcjs.h;
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 _chunkTR6KYAQIcjs = require('./chunk-TR6KYAQI.cjs');var _chunk6NHVLNFIcjs = require('./chunk-6NHVLNFI.cjs');var o=class{constructor(n,e,r,i=[]){this.type=n,this.default=e,this.required=e===void 0,this.parse=r,this.metadata=i.length?{options:i}:{}}from(n){return this.sourceKey=n,this}optional(){return this.required=!1,this}requiredIf(n){return this.required=n,this}validate(n,e="Custom validation failed"){let r=this.parse;return this.parse=(i,a)=>{let s=r(i,a);if(!n(s,a))throw new Error(e);return s},this}min(n){return this.metadata={...this.metadata,min:n},this}max(n){return this.metadata={...this.metadata,max:n},this}transform(n){let e=this.parse;return this.parse=(r,i)=>n(e(r,i),i),this}secret(){return this.metadata={...this.metadata,isSecret:!0},this}description(n){return this.metadata={...this.metadata,description:n},this}},m= exports.s ={string:t=>new o("string",t,n=>String(n)),number:t=>new o("number",t,n=>{let e=Number(n);if(isNaN(e))throw new Error(`Invalid number: ${n}`);return e}),boolean:t=>new o("boolean",t,n=>{if(typeof n=="boolean")return n;if(n===void 0||n==="")return!1;let e=String(n).toLowerCase().trim();if(["true","1","yes","on"].includes(e))return!0;if(["false","0","no","off"].includes(e))return!1;throw new Error(`Invalid boolean: ${n}`)}),enum:(t,n)=>new o("enum",n,e=>{if(!t.includes(e))throw new Error(`Value "${e}" is not one of: ${t.join(", ")}`);return e},t),array:(t,n=",")=>new o("array",t,e=>Array.isArray(e)?e:typeof e!="string"?[]:e.split(n).map(r=>r.trim()).filter(Boolean))};var b=t=>{try{return new URL(String(t)),!0}catch (e2){return!1}},D= exports.isEmail =t=>/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(String(t)),S= exports.matchesRegex =t=>n=>t.test(String(n)),T= exports.isIPv4 =t=>/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(String(t)),F= exports.isUUID =t=>/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(String(t)),C= exports.isBase64 =t=>/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/.test(String(t)),E= exports.isJSON =t=>{try{return JSON.parse(String(t)),!0}catch (e3){return!1}},N= exports.isHexColor =t=>/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/.test(String(t)),$= exports.isObjectId =t=>/^[0-9a-fA-F]{24}$/.test(String(t)),k= exports.trim =t=>String(t).trim(),v= exports.toLowerCase =t=>String(t).toLowerCase(),I= exports.toUpperCase =t=>String(t).toUpperCase(),O= exports.toJSON =t=>{try{return JSON.parse(String(t))}catch (e4){throw new Error("Invalid JSON string")}};function q(t,n={}){let e=typeof process<"u"&&(_optionalChain([process, 'access', _ => _.release, 'optionalAccess', _2 => _2.name])==="node"||!!_optionalChain([process, 'access', _3 => _3.versions, 'optionalAccess', _4 => _4.node]));return _chunk6NHVLNFIcjs.h.call(void 0, t,{...n,envLoader:e?_chunkTR6KYAQIcjs.b:void 0})}exports.BUILD = _chunk6NHVLNFIcjs.c; exports.DEV = _chunk6NHVLNFIcjs.a; exports.SERVE = _chunk6NHVLNFIcjs.b; exports.VITE_DEV_FLAG = _chunk6NHVLNFIcjs.d; exports.VITE_PREFIX = _chunk6NHVLNFIcjs.e; exports.formatErrorReport = _chunk6NHVLNFIcjs.f; exports.isBase64 = C; exports.isEmail = D; exports.isHexColor = N; exports.isIPv4 = T; exports.isJSON = E; exports.isObjectId = $; exports.isUUID = F; exports.isUrl = b; exports.matchesRegex = S; exports.parseDotEnv = _chunkTR6KYAQIcjs.a; exports.reportErrors = _chunk6NHVLNFIcjs.g; exports.s = m; exports.safeEnv = q; exports.toJSON = O; exports.toLowerCase = v; exports.toUpperCase = I; exports.trim = k;
package/dist/index.d.cts CHANGED
@@ -1,10 +1,5 @@
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>>;
1
+ import { F as FieldDefinition, E as EnvError, S as Schema, a as SafeEnvOptions, I as InferSchema } from './types-BsDPVktI.cjs';
2
+ export { B as BUILD, b as BaseType, D as DEV, c as SERVE, V as VITE_DEV_FLAG, d as VITE_PREFIX, e as ValidationContext } from './types-BsDPVktI.cjs';
8
3
 
9
4
  declare const s: {
10
5
  string: (d?: string) => FieldDefinition<string>;
@@ -14,6 +9,20 @@ declare const s: {
14
9
  array: (d?: string[], sep?: string) => FieldDefinition<string[]>;
15
10
  };
16
11
 
12
+ declare const isUrl: (v: string) => boolean;
13
+ declare const isEmail: (v: string) => boolean;
14
+ declare const matchesRegex: (pattern: RegExp) => (v: string) => boolean;
15
+ declare const isIPv4: (v: string) => boolean;
16
+ declare const isUUID: (v: string) => boolean;
17
+ declare const isBase64: (v: string) => boolean;
18
+ declare const isJSON: (v: string) => boolean;
19
+ declare const isHexColor: (v: string) => boolean;
20
+ declare const isObjectId: (v: string) => boolean;
21
+ declare const trim: (v: string) => string;
22
+ declare const toLowerCase: (v: string) => string;
23
+ declare const toUpperCase: (v: string) => string;
24
+ declare const toJSON: (v: string) => any;
25
+
17
26
  /***
18
27
  * 将 .env 内容字符串解析为对象
19
28
  * 兼容带引号的值、多层引号内部的注释标识符以及行尾注释
@@ -23,4 +32,9 @@ declare function parseDotEnv(content: string): Record<string, string>;
23
32
  declare function formatErrorReport(errors: EnvError[], useColor?: boolean): string;
24
33
  declare function reportErrors(errors: EnvError[]): void;
25
34
 
26
- export { EnvError, FieldDefinition, InferSchema, SafeEnvOptions, Schema, formatErrorReport, parseDotEnv, reportErrors, s, safeEnv };
35
+ declare function safeEnv<T extends Schema>(schema: T, options?: SafeEnvOptions & {
36
+ throwOnError?: boolean;
37
+ useCache?: boolean;
38
+ }): Readonly<InferSchema<T>>;
39
+
40
+ export { EnvError, FieldDefinition, InferSchema, SafeEnvOptions, Schema, formatErrorReport, isBase64, isEmail, isHexColor, isIPv4, isJSON, isObjectId, isUUID, isUrl, matchesRegex, parseDotEnv, reportErrors, s, safeEnv, toJSON, toLowerCase, toUpperCase, trim };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,5 @@
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>>;
1
+ import { F as FieldDefinition, E as EnvError, S as Schema, a as SafeEnvOptions, I as InferSchema } from './types-BsDPVktI.js';
2
+ export { B as BUILD, b as BaseType, D as DEV, c as SERVE, V as VITE_DEV_FLAG, d as VITE_PREFIX, e as ValidationContext } from './types-BsDPVktI.js';
8
3
 
9
4
  declare const s: {
10
5
  string: (d?: string) => FieldDefinition<string>;
@@ -14,6 +9,20 @@ declare const s: {
14
9
  array: (d?: string[], sep?: string) => FieldDefinition<string[]>;
15
10
  };
16
11
 
12
+ declare const isUrl: (v: string) => boolean;
13
+ declare const isEmail: (v: string) => boolean;
14
+ declare const matchesRegex: (pattern: RegExp) => (v: string) => boolean;
15
+ declare const isIPv4: (v: string) => boolean;
16
+ declare const isUUID: (v: string) => boolean;
17
+ declare const isBase64: (v: string) => boolean;
18
+ declare const isJSON: (v: string) => boolean;
19
+ declare const isHexColor: (v: string) => boolean;
20
+ declare const isObjectId: (v: string) => boolean;
21
+ declare const trim: (v: string) => string;
22
+ declare const toLowerCase: (v: string) => string;
23
+ declare const toUpperCase: (v: string) => string;
24
+ declare const toJSON: (v: string) => any;
25
+
17
26
  /***
18
27
  * 将 .env 内容字符串解析为对象
19
28
  * 兼容带引号的值、多层引号内部的注释标识符以及行尾注释
@@ -23,4 +32,9 @@ declare function parseDotEnv(content: string): Record<string, string>;
23
32
  declare function formatErrorReport(errors: EnvError[], useColor?: boolean): string;
24
33
  declare function reportErrors(errors: EnvError[]): void;
25
34
 
26
- export { EnvError, FieldDefinition, InferSchema, SafeEnvOptions, Schema, formatErrorReport, parseDotEnv, reportErrors, s, safeEnv };
35
+ declare function safeEnv<T extends Schema>(schema: T, options?: SafeEnvOptions & {
36
+ throwOnError?: boolean;
37
+ useCache?: boolean;
38
+ }): Readonly<InferSchema<T>>;
39
+
40
+ export { EnvError, FieldDefinition, InferSchema, SafeEnvOptions, Schema, formatErrorReport, isBase64, isEmail, isHexColor, isIPv4, isJSON, isObjectId, isUUID, isUrl, matchesRegex, parseDotEnv, reportErrors, s, safeEnv, toJSON, toLowerCase, toUpperCase, trim };
package/dist/index.js CHANGED
@@ -1 +1 @@
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-K2JQKLKN.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};
1
+ import{a as f,b as l}from"./chunk-5KPNMU6R.js";import{a as c,b as g,c as h,d as x,e as w,f as u,g as p,h as d}from"./chunk-JBML47XC.js";var o=class{type;default;required;sourceKey;metadata;parse;constructor(n,e,r,i=[]){this.type=n,this.default=e,this.required=e===void 0,this.parse=r,this.metadata=i.length?{options:i}:{}}from(n){return this.sourceKey=n,this}optional(){return this.required=!1,this}requiredIf(n){return this.required=n,this}validate(n,e="Custom validation failed"){let r=this.parse;return this.parse=(i,a)=>{let s=r(i,a);if(!n(s,a))throw new Error(e);return s},this}min(n){return this.metadata={...this.metadata,min:n},this}max(n){return this.metadata={...this.metadata,max:n},this}transform(n){let e=this.parse;return this.parse=(r,i)=>n(e(r,i),i),this}secret(){return this.metadata={...this.metadata,isSecret:!0},this}description(n){return this.metadata={...this.metadata,description:n},this}},m={string:t=>new o("string",t,n=>String(n)),number:t=>new o("number",t,n=>{let e=Number(n);if(isNaN(e))throw new Error(`Invalid number: ${n}`);return e}),boolean:t=>new o("boolean",t,n=>{if(typeof n=="boolean")return n;if(n===void 0||n==="")return!1;let e=String(n).toLowerCase().trim();if(["true","1","yes","on"].includes(e))return!0;if(["false","0","no","off"].includes(e))return!1;throw new Error(`Invalid boolean: ${n}`)}),enum:(t,n)=>new o("enum",n,e=>{if(!t.includes(e))throw new Error(`Value "${e}" is not one of: ${t.join(", ")}`);return e},t),array:(t,n=",")=>new o("array",t,e=>Array.isArray(e)?e:typeof e!="string"?[]:e.split(n).map(r=>r.trim()).filter(Boolean))};var b=t=>{try{return new URL(String(t)),!0}catch{return!1}},D=t=>/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(String(t)),S=t=>n=>t.test(String(n)),T=t=>/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(String(t)),F=t=>/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(String(t)),C=t=>/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/.test(String(t)),E=t=>{try{return JSON.parse(String(t)),!0}catch{return!1}},N=t=>/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/.test(String(t)),$=t=>/^[0-9a-fA-F]{24}$/.test(String(t)),k=t=>String(t).trim(),v=t=>String(t).toLowerCase(),I=t=>String(t).toUpperCase(),O=t=>{try{return JSON.parse(String(t))}catch{throw new Error("Invalid JSON string")}};function q(t,n={}){let e=typeof process<"u"&&(process.release?.name==="node"||!!process.versions?.node);return d(t,{...n,envLoader:e?l:void 0})}export{h as BUILD,c as DEV,g as SERVE,x as VITE_DEV_FLAG,w as VITE_PREFIX,u as formatErrorReport,C as isBase64,D as isEmail,N as isHexColor,T as isIPv4,E as isJSON,$ as isObjectId,F as isUUID,b as isUrl,S as matchesRegex,f as parseDotEnv,p as reportErrors,m as s,q as safeEnv,O as toJSON,v as toLowerCase,I as toUpperCase,k as trim};
@@ -4,22 +4,25 @@ declare const BUILD = "build";
4
4
  declare const VITE_DEV_FLAG = "VITE_DEV_SERVER";
5
5
  declare const VITE_PREFIX = "VITE_";
6
6
  type BaseType = "string" | "number" | "boolean" | "enum" | "array";
7
+ interface ValidationContext {
8
+ source: Record<string, any>;
9
+ parsed: Record<string, any>;
10
+ }
7
11
  interface FieldDefinition<T = any, D extends string = string> {
8
12
  type: BaseType;
9
13
  default?: T;
10
- required: boolean;
14
+ required: boolean | ((ctx: ValidationContext) => boolean);
11
15
  sourceKey?: string;
12
16
  metadata?: any;
13
- parse: (val: any) => T;
17
+ parse: (val: any, ctx: ValidationContext) => T;
14
18
  from: (key: string) => FieldDefinition<T, D>;
15
- validate: (fn: (val: T) => boolean, message?: string) => FieldDefinition<T, D>;
19
+ optional: () => FieldDefinition<T | undefined, D>;
20
+ requiredIf: (fn: (ctx: ValidationContext) => boolean) => FieldDefinition<T, D>;
21
+ validate: (fn: (val: T, ctx: ValidationContext) => boolean, message?: string) => FieldDefinition<T, D>;
16
22
  min: (val: number) => FieldDefinition<T, D>;
17
23
  max: (val: number) => FieldDefinition<T, D>;
18
- transform: <U>(fn: (val: T) => U) => FieldDefinition<U, D>;
24
+ transform: <U>(fn: (val: T, ctx: ValidationContext) => U) => FieldDefinition<U, D>;
19
25
  secret: () => FieldDefinition<T, D>;
20
- url: () => FieldDefinition<T, D>;
21
- email: () => FieldDefinition<T, D>;
22
- regex: (pattern: RegExp, message?: string) => FieldDefinition<T, D>;
23
26
  description: <NewD extends string>(text: NewD) => FieldDefinition<T, NewD>;
24
27
  }
25
28
  type Schema = Record<string, FieldDefinition<any, any>>;
@@ -44,4 +47,4 @@ interface SafeEnvOptions {
44
47
  /** @internal */ devMode?: boolean;
45
48
  }
46
49
 
47
- export { BUILD as B, DEV as D, type EnvError as E, type FieldDefinition as F, type InferSchema as I, type Schema as S, VITE_DEV_FLAG as V, type SafeEnvOptions as a, type BaseType as b, SERVE as c, VITE_PREFIX as d };
50
+ export { BUILD as B, DEV as D, type EnvError as E, type FieldDefinition as F, type InferSchema as I, type Schema as S, VITE_DEV_FLAG as V, type SafeEnvOptions as a, type BaseType as b, SERVE as c, VITE_PREFIX as d, type ValidationContext as e };
@@ -4,22 +4,25 @@ declare const BUILD = "build";
4
4
  declare const VITE_DEV_FLAG = "VITE_DEV_SERVER";
5
5
  declare const VITE_PREFIX = "VITE_";
6
6
  type BaseType = "string" | "number" | "boolean" | "enum" | "array";
7
+ interface ValidationContext {
8
+ source: Record<string, any>;
9
+ parsed: Record<string, any>;
10
+ }
7
11
  interface FieldDefinition<T = any, D extends string = string> {
8
12
  type: BaseType;
9
13
  default?: T;
10
- required: boolean;
14
+ required: boolean | ((ctx: ValidationContext) => boolean);
11
15
  sourceKey?: string;
12
16
  metadata?: any;
13
- parse: (val: any) => T;
17
+ parse: (val: any, ctx: ValidationContext) => T;
14
18
  from: (key: string) => FieldDefinition<T, D>;
15
- validate: (fn: (val: T) => boolean, message?: string) => FieldDefinition<T, D>;
19
+ optional: () => FieldDefinition<T | undefined, D>;
20
+ requiredIf: (fn: (ctx: ValidationContext) => boolean) => FieldDefinition<T, D>;
21
+ validate: (fn: (val: T, ctx: ValidationContext) => boolean, message?: string) => FieldDefinition<T, D>;
16
22
  min: (val: number) => FieldDefinition<T, D>;
17
23
  max: (val: number) => FieldDefinition<T, D>;
18
- transform: <U>(fn: (val: T) => U) => FieldDefinition<U, D>;
24
+ transform: <U>(fn: (val: T, ctx: ValidationContext) => U) => FieldDefinition<U, D>;
19
25
  secret: () => FieldDefinition<T, D>;
20
- url: () => FieldDefinition<T, D>;
21
- email: () => FieldDefinition<T, D>;
22
- regex: (pattern: RegExp, message?: string) => FieldDefinition<T, D>;
23
26
  description: <NewD extends string>(text: NewD) => FieldDefinition<T, NewD>;
24
27
  }
25
28
  type Schema = Record<string, FieldDefinition<any, any>>;
@@ -44,4 +47,4 @@ interface SafeEnvOptions {
44
47
  /** @internal */ devMode?: boolean;
45
48
  }
46
49
 
47
- export { BUILD as B, DEV as D, type EnvError as E, type FieldDefinition as F, type InferSchema as I, type Schema as S, VITE_DEV_FLAG as V, type SafeEnvOptions as a, type BaseType as b, SERVE as c, VITE_PREFIX as d };
50
+ export { BUILD as B, DEV as D, type EnvError as E, type FieldDefinition as F, type InferSchema as I, type Schema as S, VITE_DEV_FLAG as V, type SafeEnvOptions as a, type BaseType as b, SERVE as c, VITE_PREFIX as d, type ValidationContext as e };
package/dist/vite.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkPBYVLIUGcjs = require('./chunk-PBYVLIUG.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===_chunkPBYVLIUGcjs.b,process.env[_chunkPBYVLIUGcjs.d]=o?"true":"";let{envDir:t=e.root,prefix:r=e.envPrefix||_chunkPBYVLIUGcjs.e}=f,p=_vite.loadEnv.call(void 0, e.mode,t,r);try{_chunkPBYVLIUGcjs.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 _chunk6NHVLNFIcjs = require('./chunk-6NHVLNFI.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===_chunk6NHVLNFIcjs.b,process.env[_chunk6NHVLNFIcjs.d]=o?"true":"";let{envDir:t=e.root,prefix:r=e.envPrefix||_chunk6NHVLNFIcjs.e}=f,p=_vite.loadEnv.call(void 0, e.mode,t,r);try{_chunk6NHVLNFIcjs.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-Bx-JEkTH.cjs';
2
+ import { S as Schema } from './types-BsDPVktI.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-Bx-JEkTH.js';
2
+ import { S as Schema } from './types-BsDPVktI.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-K2JQKLKN.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-JBML47XC.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.4.0",
3
+ "version": "0.4.2",
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
- 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};
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var d=(a=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(a,{get:(b,c)=>(typeof require<"u"?require:b)[c]}):a)(function(a){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+a+'" is not supported')});exports.a = d;
@@ -1 +0,0 @@
1
- var d=(a=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(a,{get:(b,c)=>(typeof require<"u"?require:b)[c]}):a)(function(a){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+a+'" is not supported')});export{d as a};
@@ -1,9 +0,0 @@
1
- import{a as _}from"./chunk-I7AUKTXE.js";var S="development",P="serve",C="build",F="VITE_DEV_SERVER",V="VITE_";var R=typeof window<"u"&&typeof window.document<"u";function x(o,t=!0){if(R)return`SafeEnv Validation Failed: ${o.map(i=>`${i.key} (${i.error})`).join(", ")}`;let d={r:"\x1B[31m",g:"\x1B[32m",y:"\x1B[33m",b:"\x1B[1m",res:"\x1B[0m",d:"\x1B[2m",cy:"\x1B[36m"},r=(i,s)=>{let c=String(i),l=()=>c.length+(c.match(/[^\x00-\xff]/g)||[]).length;for(;l()>s;)c=c.slice(0,-1);return c+" ".repeat(s-l())},a=Math.max(80,(typeof process<"u"?process.stdout.columns:80)||80)-10,v=Math.floor(a*.3),m=Math.floor(a*.5),e=t?d:{r:"",g:"",y:"",b:"",res:"",d:"",cy:""},u=`
2
- ${e.r}${e.b}\u274C SafeEnv Validation Failed${e.res}
3
- `;return u+=` ${e.b}${r("Key",v)} \u2502 ${r("Error",m)} \u2502 Value${e.res}
4
- `,u+=e.d+"\u2500".repeat(a+5)+e.res+`
5
- `,o.forEach(i=>{let s=i.value===void 0?"undefined":i.isSecret?"********":`"${i.value}"`,c=i.value===void 0?e.d:i.isSecret?e.y:e.cy;u+=` ${e.y}${r(i.key,v)}${e.res} \u2502 ${e.r}${r(i.error,m)}${e.res} \u2502 ${c}${s}${e.res}
6
- `}),u+=e.d+"\u2500".repeat(a+5)+e.res+`
7
- `,u+=` ${e.g}\u{1F4A1} Tip: Check your .env files or schema definitions.${e.res}
8
- `,u}function k(o){if(R){console.group("%c \u274C SafeEnv Validation Failed ","background: #fee2e2; color: #b91c1c; font-weight: bold; padding: 4px; border-radius: 2px;");let t=o.reduce((d,r)=>(d[r.key]={"Error Message":r.error,"Current Value":r.value===void 0?"undefined":r.isSecret?"********":r.value},d),{});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(x(o,!0))}var p={},$=new WeakMap;function I(o){let t=x(o,!1);return new Proxy({},{get(d,r){if(r==="__isSafeEnvError")return!0;if(r==="toJSON")return()=>({error:"SafeEnv Validation Failed"});throw new Error(`[safe-env] Cannot access "${String(r)}" because validation failed:
9
- ${t}`)},ownKeys(){return[]},getOwnPropertyDescriptor(){}})}var b="[safe-env] Cannot modify read-only environment variables.";function O(o){if($.has(o))return $.get(o);let t=new Proxy(o,{get(d,r){if(r==="__isSafeEnv")return!0;let a=Reflect.get(d,r);return a!==null&&typeof a=="object"&&!Object.isFrozen(a)?O(a):a},set(){throw new Error(b)},deleteProperty(){throw new Error(b)},defineProperty(){throw new Error(b)},setPrototypeOf(){throw new Error(b)}});return $.set(o,t),t}function L(o,t={}){let{loadProcessEnv:d=!0,prefix:r=V,cwd:a,useCache:v=!0,refreshCache:m=!1}=t;if(m)for(let n in p)delete p[n];let e=typeof window<"u",u=typeof process<"u"&&(!!process.env.VITE||!!process.env[F]),i=e||u||"source"in t,s={};if("source"in t)s=t.source||{};else if(v&&!m&&Object.keys(p).length>0)s=p;else if(typeof process<"u"&&!e)try{let n=t.mode||process.env.NODE_ENV||S,{loadDotEnv:f}=_("./fs-node.cjs"),E={};for(let h of[".env",`.env.${n}`,".env.local",`.env.${n}.local`])E={...E,...f(h,a)};s={...E,...d?process.env:{}}}catch{s={}}if(v&&Object.keys(s).length>0&&Object.keys(p).length===0&&Object.assign(p,s),i&&Object.keys(s).length===0)return{};let c={},l=[];for(let n in o){let f=o[n],E=r&&!n.startsWith(r)?r+n:n,h=f.sourceKey||(s[E]!==void 0?E:s[n]!==void 0?n:E),g=s[h];try{if(g===void 0||g===""&&f.default!==void 0){if(f.required&&g===void 0)throw new Error("Missing required field");c[n]=f.default}else{let y=f.parse(g);if(y!==void 0&&f.metadata){let{min:w,max:D,validate:T}=f.metadata;if(typeof y=="number"){if(w!==void 0&&y<w)throw new Error(`Below min ${w}`);if(D!==void 0&&y>D)throw new Error(`Above max ${D}`)}if(T&&!T.fn(y))throw new Error(T.message)}c[n]=y}}catch(y){l.push({key:h,error:y.message,value:g,isSecret:f.metadata?.isSecret})}}if(l.length>0){if(t.throwOnError){let n=new Error(x(l,!0));throw n.plainMessage=x(l,!1),n}return k(l),typeof process<"u"&&process.exit&&!i&&process.exit(1),I(l)}return O(c)}export{S as a,P as b,C as c,F as d,V as e,x as f,k as g,L as h};
@@ -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 S="development",P= exports.b ="serve",C= exports.c ="build",F= exports.d ="VITE_DEV_SERVER",V= exports.e ="VITE_";var R=typeof window<"u"&&typeof window.document<"u";function x(o,t=!0){if(R)return`SafeEnv Validation Failed: ${o.map(i=>`${i.key} (${i.error})`).join(", ")}`;let d={r:"\x1B[31m",g:"\x1B[32m",y:"\x1B[33m",b:"\x1B[1m",res:"\x1B[0m",d:"\x1B[2m",cy:"\x1B[36m"},r=(i,s)=>{let c=String(i),l=()=>c.length+(c.match(/[^\x00-\xff]/g)||[]).length;for(;l()>s;)c=c.slice(0,-1);return c+" ".repeat(s-l())},a=Math.max(80,(typeof process<"u"?process.stdout.columns:80)||80)-10,v=Math.floor(a*.3),m=Math.floor(a*.5),e=t?d:{r:"",g:"",y:"",b:"",res:"",d:"",cy:""},u=`
2
- ${e.r}${e.b}\u274C SafeEnv Validation Failed${e.res}
3
- `;return u+=` ${e.b}${r("Key",v)} \u2502 ${r("Error",m)} \u2502 Value${e.res}
4
- `,u+=e.d+"\u2500".repeat(a+5)+e.res+`
5
- `,o.forEach(i=>{let s=i.value===void 0?"undefined":i.isSecret?"********":`"${i.value}"`,c=i.value===void 0?e.d:i.isSecret?e.y:e.cy;u+=` ${e.y}${r(i.key,v)}${e.res} \u2502 ${e.r}${r(i.error,m)}${e.res} \u2502 ${c}${s}${e.res}
6
- `}),u+=e.d+"\u2500".repeat(a+5)+e.res+`
7
- `,u+=` ${e.g}\u{1F4A1} Tip: Check your .env files or schema definitions.${e.res}
8
- `,u}function k(o){if(R){console.group("%c \u274C SafeEnv Validation Failed ","background: #fee2e2; color: #b91c1c; font-weight: bold; padding: 4px; border-radius: 2px;");let t=o.reduce((d,r)=>(d[r.key]={"Error Message":r.error,"Current Value":r.value===void 0?"undefined":r.isSecret?"********":r.value},d),{});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(x(o,!0))}var p={},$=new WeakMap;function I(o){let t=x(o,!1);return new Proxy({},{get(d,r){if(r==="__isSafeEnvError")return!0;if(r==="toJSON")return()=>({error:"SafeEnv Validation Failed"});throw new Error(`[safe-env] Cannot access "${String(r)}" because validation failed:
9
- ${t}`)},ownKeys(){return[]},getOwnPropertyDescriptor(){}})}var b="[safe-env] Cannot modify read-only environment variables.";function O(o){if($.has(o))return $.get(o);let t=new Proxy(o,{get(d,r){if(r==="__isSafeEnv")return!0;let a=Reflect.get(d,r);return a!==null&&typeof a=="object"&&!Object.isFrozen(a)?O(a):a},set(){throw new Error(b)},deleteProperty(){throw new Error(b)},defineProperty(){throw new Error(b)},setPrototypeOf(){throw new Error(b)}});return $.set(o,t),t}function L(o,t={}){let{loadProcessEnv:d=!0,prefix:r=V,cwd:a,useCache:v=!0,refreshCache:m=!1}=t;if(m)for(let n in p)delete p[n];let e=typeof window<"u",u=typeof process<"u"&&(!!process.env.VITE||!!process.env[F]),i=e||u||"source"in t,s={};if("source"in t)s=t.source||{};else if(v&&!m&&Object.keys(p).length>0)s=p;else if(typeof process<"u"&&!e)try{let n=t.mode||process.env.NODE_ENV||S,{loadDotEnv:f}=_chunkD6WM53FNcjs.a.call(void 0, "./fs-node.cjs"),E={};for(let h of[".env",`.env.${n}`,".env.local",`.env.${n}.local`])E={...E,...f(h,a)};s={...E,...d?process.env:{}}}catch (e2){s={}}if(v&&Object.keys(s).length>0&&Object.keys(p).length===0&&Object.assign(p,s),i&&Object.keys(s).length===0)return{};let c={},l=[];for(let n in o){let f=o[n],E=r&&!n.startsWith(r)?r+n:n,h=f.sourceKey||(s[E]!==void 0?E:s[n]!==void 0?n:E),g=s[h];try{if(g===void 0||g===""&&f.default!==void 0){if(f.required&&g===void 0)throw new Error("Missing required field");c[n]=f.default}else{let y=f.parse(g);if(y!==void 0&&f.metadata){let{min:w,max:D,validate:T}=f.metadata;if(typeof y=="number"){if(w!==void 0&&y<w)throw new Error(`Below min ${w}`);if(D!==void 0&&y>D)throw new Error(`Above max ${D}`)}if(T&&!T.fn(y))throw new Error(T.message)}c[n]=y}}catch(y){l.push({key:h,error:y.message,value:g,isSecret:_optionalChain([f, 'access', _2 => _2.metadata, 'optionalAccess', _3 => _3.isSecret])})}}if(l.length>0){if(t.throwOnError){let n=new Error(x(l,!0));throw n.plainMessage=x(l,!1),n}return k(l),typeof process<"u"&&process.exit&&!i&&process.exit(1),I(l)}return O(c)}exports.a = S; exports.b = P; exports.c = C; exports.d = F; exports.e = V; exports.f = x; exports.g = k; exports.h = L;
@@ -1 +0,0 @@
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;