bini-env 1.0.8 → 1.0.10

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.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # bini-env
2
2
 
3
- ![npm](https://img.shields.io/npm/v/bini-env?color=cyan\&style=flat-square)
3
+ ![npm](https://img.shields.io/npm/v/bini-env?color=cyan&style=flat-square)
4
4
  ![npm downloads](https://img.shields.io/npm/dm/bini-env?style=flat-square)
5
5
  ![license](https://img.shields.io/npm/l/bini-env?style=flat-square)
6
- ![vite](https://img.shields.io/badge/vite-%3E%3D8.0-646CFF?style=flat-square\&logo=vite)
7
- ![typescript](https://img.shields.io/badge/TypeScript-ready-3178C6?style=flat-square\&logo=typescript)
8
- ![node](https://img.shields.io/badge/node-%3E%3D20.19-339933?style=flat-square\&logo=node.js)
6
+ ![vite](https://img.shields.io/badge/vite-%3E%3D8.0-646CFF?style=flat-square&logo=vite)
7
+ ![typescript](https://img.shields.io/badge/TypeScript-ready-3178C6?style=flat-square&logo=typescript)
8
+ ![node](https://img.shields.io/badge/node-%3E%3D20.19-339933?style=flat-square&logo=node.js)
9
9
 
10
- **Zero-config environment variable system + Vite plugin for Bini.js**
11
- Loads `.env` in development, uses host-provided variables in production, and works across Node.js, Bun, Deno, and edge runtimes — without leaking secrets or adding runtime cost.
10
+ **Zero-config environment variable system + Vite plugin for Bini.js**
11
+ Loads `.env` in development, uses host-provided variables in production, and works across Node.js, Bun, Deno, Vercel Edge, Netlify Edge, and Cloudflare Workers — without leaking secrets or adding runtime cost.
12
12
 
13
13
  ---
14
14
 
@@ -16,24 +16,25 @@ Loads `.env` in development, uses host-provided variables in production, and wor
16
16
 
17
17
  This library **does NOT magically make env vars safe**.
18
18
 
19
- * Anything exposed to the client (`import.meta.env`) is **public**.
20
- * Only server-side code (`getEnv`, `requireEnv`) can safely access secrets.
21
- * Misconfigured prefixes = **data leak**.
19
+ - Anything exposed to the client (`import.meta.env`) is **public**.
20
+ - Only server-side code (`getEnv`, `requireEnv`) can safely access secrets.
21
+ - Misconfigured prefixes = **data leak**.
22
22
 
23
- If you don’t understand this, stop and fix that first.
23
+ If you don't understand this, stop and fix that first.
24
24
 
25
25
  ---
26
26
 
27
27
  ## ✨ Features
28
28
 
29
- * **Universal API** — `getEnv()` / `requireEnv()` work across runtimes
30
- * **Zero-config `.env` loading** in development
31
- * **Strict production behavior** — no file reads, no dotenv
32
- * **Prefix control** — supports `BINI_`, `VITE_`, or custom
33
- * **Tree-shakeable** — no dead code in client bundles
34
- * **Edge-safe** — no static dotenv import
35
- * **Typed** — full TypeScript support
36
- * **Fast** — single load in dev, zero overhead in prod
29
+ - **Universal API** — `getEnv()` / `requireEnv()` work across all runtimes
30
+ - **Zero-config `.env` loading** in development
31
+ - **Edge-safe** — no static `fs`, `path`, or `dotenv` imports in bundles
32
+ - **Auto server restart** — dev server restarts when `.env` files are created or changed
33
+ - **Strict production behavior** — no file reads, no dotenv
34
+ - **Prefix control** — supports `BINI_`, `VITE_`, or custom
35
+ - **Tree-shakeable** — no dead code in client bundles
36
+ - **Typed** — full TypeScript support
37
+ - **Fast** — single load in dev, zero overhead in prod
37
38
 
38
39
  ---
39
40
 
@@ -49,7 +50,7 @@ yarn add bini-env
49
50
 
50
51
  ---
51
52
 
52
- ## 🚀 Quick Start (Don’t Overthink It)
53
+ ## 🚀 Quick Start
53
54
 
54
55
  ```ts
55
56
  // vite.config.ts
@@ -61,15 +62,13 @@ export default defineConfig({
61
62
  });
62
63
  ```
63
64
 
64
- Done.
65
-
66
- If this doesn’t work, your project setup is broken — not the plugin.
65
+ Done. If this doesn't work, your project setup is broken — not the plugin.
67
66
 
68
67
  ---
69
68
 
70
69
  ## 🔐 Environment Rules (Read This Twice)
71
70
 
72
- > ✅ **Good news:** Both `BINI_` and `VITE_` prefixes work out of the box — no extra config needed.
71
+ > ✅ Both `BINI_` and `VITE_` prefixes work out of the box — no extra config needed.
73
72
 
74
73
  ### Client (PUBLIC)
75
74
 
@@ -78,16 +77,12 @@ BINI_PUBLIC_API_URL=https://api.example.com
78
77
  VITE_ANALYTICS_ID=UA-XXXX
79
78
  ```
80
79
 
81
- Accessible via:
82
-
83
80
  ```ts
84
81
  import.meta.env.BINI_PUBLIC_API_URL
85
82
  ```
86
83
 
87
84
  👉 **Never put secrets here. Ever.**
88
85
 
89
- ---
90
-
91
86
  ### Server (PRIVATE)
92
87
 
93
88
  ```env
@@ -96,25 +91,59 @@ DATABASE_URL=postgres://...
96
91
  ```
97
92
 
98
93
  ```ts
99
- import { requireEnv } from 'bini-env';
100
-
101
- const pass = requireEnv('SMTP_PASS');
94
+ // getEnv and requireEnv are auto-imported in API routes
95
+ const pass = requireEnv('SMTP_PASS'); // throws if missing
96
+ const db = getEnv('DATABASE_URL'); // returns undefined if missing
102
97
  ```
103
98
 
104
- 👉 If this leaks, it’s your fault, not the library’s.
99
+ 👉 If this leaks, it's your fault, not the library's.
100
+
101
+ ---
102
+
103
+ ## 🌍 Platform Support
104
+
105
+ `getEnv` and `requireEnv` work identically across every supported platform. Write your API routes once — they run everywhere unchanged.
106
+
107
+ | Platform | Runtime | Where vars come from | How `getEnv` reads them |
108
+ | ------------------ | ------------- | ------------------------------------- | ----------------------- |
109
+ | Node.js | Node | `.env` file / system env | `process.env` ✅ |
110
+ | Bun | Bun | `.env` file / system env | `process.env` ✅ |
111
+ | Vercel Edge | V8 isolate | Project settings → Environment Vars | `process.env` ✅ |
112
+ | Netlify Edge | Deno | Site settings → Environment Vars | `Deno.env.get()` ✅ |
113
+ | Cloudflare Workers | V8 isolate | `wrangler.toml [vars]` / dashboard | `process.env` ✅ |
114
+ | Deno Deploy | Deno | Project settings → Environment Vars | `Deno.env.get()` ✅ |
115
+
116
+ > **Cloudflare note:** Variables set in `wrangler.toml [vars]` or the dashboard work with `getEnv` at the top level. Secrets added via `wrangler secret put` are only available inside the fetch handler via `c.env` — this is a Cloudflare Workers architecture constraint, not a bini-env limitation.
105
117
 
106
118
  ---
107
119
 
108
120
  ## 🧠 How It Actually Works
109
121
 
110
- | Mode | Behavior |
111
- | ---------------- | ---------------------------------------- |
112
- | Dev (`vite dev`) | Loads `.env` once via dynamic dotenv |
113
- | Preview | Same as dev |
114
- | Production | Uses `process.env` / host injection only |
115
- | Edge/Deno | Uses native `Deno.env` |
122
+ | Mode | Behavior |
123
+ | ---------------- | ------------------------------------------------- |
124
+ | Dev (`vite dev`) | Loads `.env` once via dynamic dotenv |
125
+ | Preview | Same as dev |
126
+ | Production | Uses `process.env` / host injection only |
127
+ | Deno / Netlify Edge | Uses native `Deno.env` |
128
+ | Vercel / Cloudflare Edge | Uses `process.env` injected by the host |
116
129
 
117
- **No runtime branching in client bundles. No hidden magic.**
130
+ `fs`, `path`, and `dotenv` are **never imported at the top level**. They are dynamically imported at runtime, inside Node-only guards, so edge bundlers never trace them into your bundle.
131
+
132
+ ---
133
+
134
+ ## 🔄 Auto Server Restart
135
+
136
+ The dev server automatically restarts when any `.env*` file is created or changed in your project root — no manual restart needed.
137
+
138
+ ```
139
+ 12:00:01 [bini-env] .env.local changed — restarting server
140
+ ```
141
+
142
+ Covered events:
143
+ - Creating a new `.env`, `.env.local`, `.env.production`, etc.
144
+ - Editing any existing `.env*` file
145
+
146
+ Editor swap files (`.env.swp`, `.env~`, `.env.bak`) are ignored.
118
147
 
119
148
  ---
120
149
 
@@ -122,18 +151,15 @@ const pass = requireEnv('SMTP_PASS');
122
151
 
123
152
  ```ts
124
153
  biniEnv({
125
- enabled: true,
154
+ enabled : true,
126
155
  clearViteHeader: true,
127
- logo: 'ß',
128
- envPrefix: ['BINI_', 'VITE_']
156
+ logo : 'ß',
157
+ envPrefix : ['BINI_', 'VITE_'],
158
+ loadInPreview : true,
129
159
  });
130
160
  ```
131
161
 
132
- ### Critical Detail
133
-
134
- If you change `envPrefix`, you are changing what gets exposed to the browser.
135
-
136
- Break this → you leak secrets.
162
+ > **Critical:** If you change `envPrefix`, you are changing what gets exposed to the browser. Break this → you leak secrets.
137
163
 
138
164
  ---
139
165
 
@@ -141,38 +167,43 @@ Break this → you leak secrets.
141
167
 
142
168
  ### `getEnv(key)`
143
169
 
144
- Returns `string | undefined`.
170
+ Returns `string | undefined`. Auto-imported in API routes.
145
171
 
146
- Safe fallback reader across:
172
+ Lookup order:
173
+ 1. `Deno.env.get(key)` — Deno / Netlify Edge
174
+ 2. `process.env[key]` — Node, Bun, Vercel Edge, Cloudflare Workers
175
+ 3. `import.meta.env[key]` — Vite client (prefixed variants only)
147
176
 
148
- * `Deno.env`
149
- * `process.env`
150
- * `import.meta.env`
151
-
152
- ---
177
+ ```ts
178
+ const debug = getEnv('DEBUG_MODE');
179
+ ```
153
180
 
154
181
  ### `requireEnv(key)`
155
182
 
156
- Same as `getEnv` but throws:
183
+ Same as `getEnv` but throws if missing:
157
184
 
158
- ```txt
185
+ ```
159
186
  [bini-env] Missing required environment variable: "SMTP_PASS"
187
+ → In development: add it to your .env file.
188
+ → In production: set it in your hosting dashboard.
160
189
  ```
161
190
 
162
- Use this for anything critical.
191
+ Use this for anything critical that must exist at startup.
163
192
 
164
- ---
193
+ ```ts
194
+ const dbUrl = requireEnv('DATABASE_URL');
195
+ ```
165
196
 
166
197
  ### `biniEnv(options)`
167
198
 
168
- Vite plugin.
169
-
170
- If your plugin order is wrong and things break, that’s on your config.
199
+ Vite plugin. Handles `.env` loading, terminal output, and dev server watching.
171
200
 
172
201
  ---
173
202
 
174
203
  ## 📂 Env File Resolution Order
175
204
 
205
+ Higher entries take priority:
206
+
176
207
  1. `.env.local`
177
208
  2. `.env.[mode].local`
178
209
  3. `.env.[mode]`
@@ -196,22 +227,23 @@ If you see overhead in production, you did something wrong.
196
227
 
197
228
  ## 🔥 Common Failure Modes
198
229
 
199
- ### 1. “Env is undefined”
200
-
201
- You forgot the prefix.
230
+ ### "Env is undefined"
231
+ You forgot the prefix (`BINI_` or `VITE_`) on a client-side var, or you're reading an unprefixed secret from `import.meta.env`.
202
232
 
203
- ### 2. “Works in dev, broken in prod”
233
+ ### "Works in dev, broken in prod"
234
+ You relied on a `.env` file in production. Set vars in your hosting dashboard.
204
235
 
205
- You relied on `.env` in production.
236
+ ### "Secrets leaked"
237
+ You exposed them via `BINI_` or `VITE_` prefix. Those are public. Use unprefixed vars for secrets.
206
238
 
207
- ### 3. “Secrets leaked”
239
+ ### "Works on Node, broken on Vercel/Netlify/Cloudflare"
240
+ You had the old version with static `fs`/`path` imports. Upgrade — this version is edge-safe.
208
241
 
209
- You exposed them via prefix.
210
-
211
- ### 4. “Types not found”
212
-
213
- Add:
242
+ ### "Cloudflare secret not found"
243
+ Secrets added via `wrangler secret put` are only available via `c.env` inside your handler. Use `wrangler.toml [vars]` for anything `getEnv` needs at the top level.
214
244
 
245
+ ### "Types not found"
246
+ Add to your `tsconfig` or entry file:
215
247
  ```ts
216
248
  /// <reference types="vite/client" />
217
249
  ```
@@ -223,24 +255,22 @@ Add:
223
255
  This library is intentionally simple.
224
256
 
225
257
  If you need:
258
+ - Secret rotation
259
+ - Encrypted envs
260
+ - Runtime validation schemas
226
261
 
227
- * secret rotation
228
- * encrypted envs
229
- * runtime validation schemas
230
-
231
- That’s **your job**, not this package.
262
+ That's **your job**, not this package.
232
263
 
233
264
  ---
234
265
 
235
266
  ## 🤝 Contributing
236
267
 
237
268
  PRs welcome — but:
269
+ - No bloat
270
+ - No magic
271
+ - No runtime cost
238
272
 
239
- * No bloat
240
- * No magic
241
- * No runtime cost
242
-
243
- If it slows startup or increases bundle size, it’s getting rejected.
273
+ If it slows startup or increases bundle size, it's getting rejected.
244
274
 
245
275
  ---
246
276
 
@@ -250,4 +280,4 @@ MIT © Bini.js Team
250
280
 
251
281
  ---
252
282
 
253
- **Ship fast. Leak nothing. Blame config, not tooling.**
283
+ **Ship fast. Leak nothing. Blame config, not tooling.**
package/dist/index.d.mts CHANGED
@@ -8,16 +8,22 @@ interface BiniEnvPluginOptions {
8
8
  readonly logo?: string;
9
9
  readonly envPrefix?: string | string[];
10
10
  readonly loadInPreview?: boolean;
11
+ /** @deprecated Suppression is always applied at module load; this option is ignored. */
11
12
  readonly suppressDotenvLogs?: boolean;
12
13
  }
13
14
  interface DetectedEnvFile {
14
15
  readonly name: string;
15
16
  readonly path: string;
16
17
  }
18
+ declare const biniLogger: {
19
+ readonly info: (msg: string) => void;
20
+ readonly warn: (msg: string) => void;
21
+ readonly error: (msg: string, err?: unknown) => void;
22
+ };
17
23
  declare function getEnv(key: string): string | undefined;
18
24
  declare function requireEnv(key: string): string;
19
25
  declare function loadEnv(projectRoot?: string): Promise<void>;
20
26
  declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
21
27
  declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
22
28
 
23
- export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, detectEnvFiles, getEnv, loadEnv, requireEnv, suppressDotenvLogsGlobally };
29
+ export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, biniLogger, detectEnvFiles, getEnv, loadEnv, requireEnv, suppressDotenvLogsGlobally };
package/dist/index.d.ts CHANGED
@@ -8,16 +8,22 @@ interface BiniEnvPluginOptions {
8
8
  readonly logo?: string;
9
9
  readonly envPrefix?: string | string[];
10
10
  readonly loadInPreview?: boolean;
11
+ /** @deprecated Suppression is always applied at module load; this option is ignored. */
11
12
  readonly suppressDotenvLogs?: boolean;
12
13
  }
13
14
  interface DetectedEnvFile {
14
15
  readonly name: string;
15
16
  readonly path: string;
16
17
  }
18
+ declare const biniLogger: {
19
+ readonly info: (msg: string) => void;
20
+ readonly warn: (msg: string) => void;
21
+ readonly error: (msg: string, err?: unknown) => void;
22
+ };
17
23
  declare function getEnv(key: string): string | undefined;
18
24
  declare function requireEnv(key: string): string;
19
25
  declare function loadEnv(projectRoot?: string): Promise<void>;
20
26
  declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
21
27
  declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
22
28
 
23
- export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, detectEnvFiles, getEnv, loadEnv, requireEnv, suppressDotenvLogsGlobally };
29
+ export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, biniLogger, detectEnvFiles, getEnv, loadEnv, requireEnv, suppressDotenvLogsGlobally };