bini-env 1.0.6 → 1.0.8

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,25 +1,43 @@
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-plugin-646CFF?style=flat-square&logo=vite)
7
- ![typescript](https://img.shields.io/badge/TypeScript-ready-3178C6?style=flat-square&logo=typescript)
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)
8
9
 
9
- Universal environment variable loader and Vite plugin for Bini.js. Automatically loads `.env` files in development, reads env vars from the host in production, and works across Node.js, Deno, Bun, and Vite edge functions — with zero configuration.
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
12
 
11
- ## Features
13
+ ---
14
+
15
+ ## ⚠️ Before You Use This
16
+
17
+ This library **does NOT magically make env vars safe**.
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**.
22
+
23
+ If you don’t understand this, stop and fix that first.
24
+
25
+ ---
26
+
27
+ ## ✨ Features
12
28
 
13
- - **Universal `getEnv()` / `requireEnv()`** — read env vars in any runtime (Node.js, Deno, Bun, Vite client)
14
- - **Auto `.env` loading** — no manual `dotenv` setup needed in API routes
15
- - **`BINI_` prefix** — replaces Vite's `VITE_` prefix with `BINI_` automatically
16
- - **Branded startup banner** — replaces Vite's default header with a clean Bini.js output
17
- - **Supports dev and preview modes**
18
- - **Safe for edge bundlers** — dotenv is loaded via dynamic import, never statically resolved
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
19
37
 
20
38
  ---
21
39
 
22
- ## Installation
40
+ ## 📦 Installation
23
41
 
24
42
  ```bash
25
43
  pnpm add bini-env
@@ -31,197 +49,205 @@ yarn add bini-env
31
49
 
32
50
  ---
33
51
 
34
- ## Vite Plugin Setup
52
+ ## 🚀 Quick Start (Don’t Overthink It)
35
53
 
36
54
  ```ts
37
55
  // vite.config.ts
38
56
  import { defineConfig } from 'vite';
39
- import biniEnv from 'bini-env';
57
+ import { biniEnv } from 'bini-env';
40
58
 
41
59
  export default defineConfig({
42
60
  plugins: [biniEnv()]
43
61
  });
44
62
  ```
45
63
 
46
- That's it. Once added:
47
- - Your `.env` is auto-loaded for API routes in dev
48
- - Client code uses `import.meta.env.BINI_*` instead of `VITE_*`
49
- - The startup banner is replaced with the Bini.js header
64
+ Done.
65
+
66
+ If this doesn’t work, your project setup is broken — not the plugin.
50
67
 
51
68
  ---
52
69
 
53
- ## Environment Variables
70
+ ## 🔐 Environment Rules (Read This Twice)
71
+
72
+ > ✅ **Good news:** Both `BINI_` and `VITE_` prefixes work out of the box — no extra config needed.
54
73
 
55
- ### `.env` file
74
+ ### Client (PUBLIC)
56
75
 
57
76
  ```env
58
- # Client-side vars — accessible via import.meta.env.BINI_*
59
- BINI_FIREBASE_API_KEY=your_key
60
- BINI_FIREBASE_AUTH_DOMAIN=your_domain
61
-
62
- # Server-side vars — accessible via getEnv() in API routes
63
- SMTP_USER=user@smtp.example.com
64
- SMTP_PASS=your_password
65
- FROM_EMAIL=App Name <noreply@example.com>
77
+ BINI_PUBLIC_API_URL=https://api.example.com
78
+ VITE_ANALYTICS_ID=UA-XXXX
66
79
  ```
67
80
 
68
- ### In API routes
81
+ Accessible via:
69
82
 
70
83
  ```ts
71
- import { getEnv, requireEnv } from 'bini-env';
84
+ import.meta.env.BINI_PUBLIC_API_URL
85
+ ```
72
86
 
73
- // Returns string | undefined
74
- const smtpUser = getEnv('SMTP_USER');
87
+ 👉 **Never put secrets here. Ever.**
75
88
 
76
- // Returns string — throws a clear error if missing
77
- const smtpPass = requireEnv('SMTP_PASS');
78
- ```
89
+ ---
90
+
91
+ ### Server (PRIVATE)
79
92
 
80
- ### In client code (React / Vue / etc.)
93
+ ```env
94
+ SMTP_PASS=super_secret
95
+ DATABASE_URL=postgres://...
96
+ ```
81
97
 
82
98
  ```ts
83
- // Works because bini-env sets envPrefix: 'BINI_' automatically
84
- const apiKey = import.meta.env.BINI_FIREBASE_API_KEY;
99
+ import { requireEnv } from 'bini-env';
100
+
101
+ const pass = requireEnv('SMTP_PASS');
85
102
  ```
86
103
 
104
+ 👉 If this leaks, it’s your fault, not the library’s.
105
+
87
106
  ---
88
107
 
89
- ## How env loading works by environment
108
+ ## 🧠 How It Actually Works
90
109
 
91
- | Environment | How vars are loaded | dotenv used? |
92
- |---|---|---|
93
- | Dev (Node.js / bini-router) | Auto-loaded from `.env` by bini-env | ✅ Yes (automatic) |
94
- | Preview (`vite preview`) | Auto-loaded from `.env` by bini-env | ✅ Yes (automatic) |
95
- | Production (Netlify / Vercel) | Injected by host dashboard | ❌ No |
96
- | Production (bini-server / VPS) | Set via server env or hosting panel | ❌ No |
97
- | Deno / Edge Functions | Read from `Deno.env` natively | ❌ No |
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` |
98
116
 
99
- You never need to import or configure `dotenv` manually.
117
+ **No runtime branching in client bundles. No hidden magic.**
100
118
 
101
119
  ---
102
120
 
103
- ## Startup Output
121
+ ## ⚙️ Plugin Options
104
122
 
105
- **Dev mode**
106
- ```
107
- ß Bini.js (dev)
108
- ➜ Environments: .env.local, .env
109
- ➜ Local: http://localhost:3000/
110
- ➜ Network: http://192.168.1.10:3000/
123
+ ```ts
124
+ biniEnv({
125
+ enabled: true,
126
+ clearViteHeader: true,
127
+ logo: 'ß',
128
+ envPrefix: ['BINI_', 'VITE_']
129
+ });
111
130
  ```
112
131
 
113
- **Preview mode**
114
- ```
115
- ß Bini.js (preview)
116
- ➜ Environments: .env.local, .env
117
- ➜ Local: http://localhost:4173/
118
- ➜ Network: http://192.168.1.10:4173/
119
- ```
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.
120
137
 
121
138
  ---
122
139
 
123
- ## Plugin Options
140
+ ## 📚 API
124
141
 
125
- | Option | Type | Default | Description |
126
- |---|---|---|---|
127
- | `enabled` | `boolean` | `true` | Enable or disable the plugin |
128
- | `clearViteHeader` | `boolean` | `true` | Replace Vite's default startup header |
129
- | `logo` | `string` | `'ß'` | Custom logo or text shown in the banner |
130
- | `envPrefix` | `string` | `'BINI_'` | Prefix for client-side env vars in `import.meta.env` |
142
+ ### `getEnv(key)`
131
143
 
132
- ```ts
133
- biniEnv({
134
- logo: '🚀',
135
- clearViteHeader: true,
136
- envPrefix: 'BINI_', // change to 'VITE_' to keep Vite's default
137
- })
144
+ Returns `string | undefined`.
145
+
146
+ Safe fallback reader across:
147
+
148
+ * `Deno.env`
149
+ * `process.env`
150
+ * `import.meta.env`
151
+
152
+ ---
153
+
154
+ ### `requireEnv(key)`
155
+
156
+ Same as `getEnv` but throws:
157
+
158
+ ```txt
159
+ [bini-env] Missing required environment variable: "SMTP_PASS"
138
160
  ```
139
161
 
162
+ Use this for anything critical.
163
+
140
164
  ---
141
165
 
142
- ## Detected `.env` Files
166
+ ### `biniEnv(options)`
143
167
 
144
- The plugin checks for the following files in your project root (in priority order):
168
+ Vite plugin.
169
+
170
+ If your plugin order is wrong and things break, that’s on your config.
171
+
172
+ ---
173
+
174
+ ## 📂 Env File Resolution Order
145
175
 
146
176
  1. `.env.local`
147
- 2. `.env.[NODE_ENV].local`
148
- 3. `.env.[NODE_ENV]`
177
+ 2. `.env.[mode].local`
178
+ 3. `.env.[mode]`
149
179
  4. `.env`
150
180
 
181
+ Loaded once. Cached. No repeated disk reads.
182
+
151
183
  ---
152
184
 
153
- ## API Reference
185
+ ## ⚡ Performance
154
186
 
155
- ### `getEnv(key: string): string | undefined`
187
+ | Metric | Dev | Prod |
188
+ | ------------- | --------- | ----------- |
189
+ | File Reads | 1–5 | 0 |
190
+ | Runtime Cost | ~5ms once | 0 |
191
+ | Bundle Impact | Minimal | Tree-shaken |
156
192
 
157
- Read an environment variable in any runtime. Checks `Deno.env` → `process.env` → `import.meta.env` in order.
193
+ If you see overhead in production, you did something wrong.
158
194
 
159
- ```ts
160
- import { getEnv } from 'bini-env';
195
+ ---
161
196
 
162
- const smtpUser = getEnv('SMTP_USER');
163
- ```
197
+ ## 🔥 Common Failure Modes
164
198
 
165
- ### `requireEnv(key: string): string`
199
+ ### 1. “Env is undefined”
166
200
 
167
- Same as `getEnv` but throws a descriptive error if the variable is missing or empty. Use this for required secrets.
201
+ You forgot the prefix.
168
202
 
169
- ```ts
170
- import { requireEnv } from 'bini-env';
203
+ ### 2. “Works in dev, broken in prod”
171
204
 
172
- const smtpPass = requireEnv('SMTP_PASS');
173
- // Throws: [bini-env] Missing required environment variable: "SMTP_PASS".
174
- // → In development: add it to your .env file.
175
- // → In production: add it to your hosting dashboard environment variables.
176
- ```
205
+ You relied on `.env` in production.
177
206
 
178
- ### `loadEnv(projectRoot?: string): Promise<void>`
207
+ ### 3. “Secrets leaked”
179
208
 
180
- Manually trigger `.env` loading. Called automatically by the Vite plugin — you should not need this.
209
+ You exposed them via prefix.
181
210
 
182
- ### `detectEnvFiles(projectRoot?: string): DetectedEnvFile[]`
211
+ ### 4. “Types not found”
183
212
 
184
- Scan a directory for `.env` files and return an array of matches.
213
+ Add:
185
214
 
186
215
  ```ts
187
- import { detectEnvFiles } from 'bini-env';
188
-
189
- const files = detectEnvFiles('/my/project');
190
- // [{ name: '.env.local', path: '/my/project/.env.local' }, ...]
216
+ /// <reference types="vite/client" />
191
217
  ```
192
218
 
193
219
  ---
194
220
 
195
- ## Types
221
+ ## 🧪 Reality Check
196
222
 
197
- ```ts
198
- interface BiniEnvPluginOptions {
199
- enabled?: boolean;
200
- clearViteHeader?: boolean;
201
- logo?: string;
202
- envPrefix?: string;
203
- }
204
-
205
- interface DetectedEnvFile {
206
- name: string;
207
- path: string;
208
- }
209
- ```
223
+ This library is intentionally simple.
224
+
225
+ If you need:
226
+
227
+ * secret rotation
228
+ * encrypted envs
229
+ * runtime validation schemas
230
+
231
+ That’s **your job**, not this package.
210
232
 
211
233
  ---
212
234
 
213
- ## Compatibility
235
+ ## 🤝 Contributing
236
+
237
+ PRs welcome — but:
238
+
239
+ * No bloat
240
+ * No magic
241
+ * No runtime cost
214
242
 
215
- | Runtime | Supported |
216
- |---|---|
217
- | Node.js 18+ | ✅ |
218
- | Bun | ✅ |
219
- | Deno / Edge Functions | ✅ |
220
- | Vite 7 | ✅ |
221
- | Vite 8 | ✅ |
243
+ If it slows startup or increases bundle size, it’s getting rejected.
222
244
 
223
245
  ---
224
246
 
225
- ## License
247
+ ## 📄 License
248
+
249
+ MIT © Bini.js Team
250
+
251
+ ---
226
252
 
227
- MIT
253
+ **Ship fast. Leak nothing. Blame config, not tooling.**
@@ -0,0 +1,23 @@
1
+ import { Plugin } from 'vite';
2
+ export { Plugin } from 'vite';
3
+
4
+ declare function suppressDotenvLogsGlobally(): void;
5
+ interface BiniEnvPluginOptions {
6
+ readonly enabled?: boolean;
7
+ readonly clearViteHeader?: boolean;
8
+ readonly logo?: string;
9
+ readonly envPrefix?: string | string[];
10
+ readonly loadInPreview?: boolean;
11
+ readonly suppressDotenvLogs?: boolean;
12
+ }
13
+ interface DetectedEnvFile {
14
+ readonly name: string;
15
+ readonly path: string;
16
+ }
17
+ declare function getEnv(key: string): string | undefined;
18
+ declare function requireEnv(key: string): string;
19
+ declare function loadEnv(projectRoot?: string): Promise<void>;
20
+ declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
21
+ declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
22
+
23
+ export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, detectEnvFiles, getEnv, loadEnv, requireEnv, suppressDotenvLogsGlobally };
package/dist/index.d.ts CHANGED
@@ -1,79 +1,23 @@
1
1
  import { Plugin } from 'vite';
2
2
  export { Plugin } from 'vite';
3
3
 
4
+ declare function suppressDotenvLogsGlobally(): void;
4
5
  interface BiniEnvPluginOptions {
5
- /**
6
- * Enable/disable the plugin
7
- * @default true
8
- */
9
6
  readonly enabled?: boolean;
10
- /**
11
- * Remove Vite's default header
12
- * @default true
13
- */
14
7
  readonly clearViteHeader?: boolean;
15
- /**
16
- * Custom logo/text to display
17
- * @default 'ß'
18
- */
19
8
  readonly logo?: string;
20
- /**
21
- * Override the env var prefix exposed to client code.
22
- * Defaults to 'BINI_' — so BINI_MY_VAR is accessible via import.meta.env.BINI_MY_VAR
23
- * Set to 'VITE_' to keep Vite's default behaviour.
24
- * @default 'BINI_'
25
- */
26
- readonly envPrefix?: string;
9
+ readonly envPrefix?: string | string[];
10
+ readonly loadInPreview?: boolean;
11
+ readonly suppressDotenvLogs?: boolean;
27
12
  }
28
13
  interface DetectedEnvFile {
29
14
  readonly name: string;
30
15
  readonly path: string;
31
16
  }
32
- /**
33
- * Read an environment variable in any runtime.
34
- *
35
- * Priority order:
36
- * 1. Deno.env — Netlify edge functions / Deno runtime
37
- * 2. process.env — Node.js / Bun / bini-server
38
- * 3. import.meta.env — Vite client (BINI_-prefixed vars)
39
- *
40
- * Usage in API routes:
41
- * import { getEnv } from 'bini-env';
42
- * const smtpUser = getEnv('SMTP_USER');
43
- */
44
17
  declare function getEnv(key: string): string | undefined;
45
- /**
46
- * Read an environment variable and throw if it's missing or empty.
47
- * Use this for required secrets so you get a clear error at startup
48
- * instead of a cryptic crash later.
49
- *
50
- * Usage:
51
- * const smtpPass = requireEnv('SMTP_PASS');
52
- */
53
18
  declare function requireEnv(key: string): string;
54
- /**
55
- * Auto-load .env into process.env for Node.js API route contexts.
56
- *
57
- * Behaviour by environment:
58
- * - Deno (edge functions) → no-op, Deno/Netlify injects env natively
59
- * - NODE_ENV=production → no-op, host injects env vars automatically
60
- * - Node.js dev → loads .env via dotenv (dynamic import, safe for bundlers)
61
- *
62
- * Called automatically by bini-env Vite plugin. You should not need to call this manually.
63
- */
64
19
  declare function loadEnv(projectRoot?: string): Promise<void>;
65
- /**
66
- * Detect which .env files exist in the project root, in Vite's priority order.
67
- */
68
20
  declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
69
- /**
70
- * Bini.js Vite plugin.
71
- *
72
- * What it does:
73
- * - Sets envPrefix to 'BINI_' so client code uses import.meta.env.BINI_MY_VAR
74
- * - Auto-loads .env for API routes in dev via loadEnv()
75
- * - Replaces Vite's startup output with the Bini.js branded header
76
- */
77
21
  declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
78
22
 
79
- export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, detectEnvFiles, getEnv, loadEnv, requireEnv };
23
+ export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, detectEnvFiles, getEnv, loadEnv, requireEnv, suppressDotenvLogsGlobally };