bini-env 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -126
- package/dist/index.d.mts +37 -0
- package/dist/index.d.ts +10 -52
- package/dist/index.js +166 -100
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +235 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +31 -19
- package/dist/index.cjs +0 -191
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -79
package/README.md
CHANGED
|
@@ -1,25 +1,43 @@
|
|
|
1
1
|
# bini-env
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|

|
|
5
5
|

|
|
6
|
-

|
|
7
|
+

|
|
8
|
+

|
|
8
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
12
|
|
|
11
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
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
|
-
###
|
|
74
|
+
### Client (PUBLIC)
|
|
56
75
|
|
|
57
76
|
```env
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
81
|
+
Accessible via:
|
|
69
82
|
|
|
70
83
|
```ts
|
|
71
|
-
import
|
|
84
|
+
import.meta.env.BINI_PUBLIC_API_URL
|
|
85
|
+
```
|
|
72
86
|
|
|
73
|
-
|
|
74
|
-
const smtpUser = getEnv('SMTP_USER');
|
|
87
|
+
👉 **Never put secrets here. Ever.**
|
|
75
88
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### Server (PRIVATE)
|
|
79
92
|
|
|
80
|
-
|
|
93
|
+
```env
|
|
94
|
+
SMTP_PASS=super_secret
|
|
95
|
+
DATABASE_URL=postgres://...
|
|
96
|
+
```
|
|
81
97
|
|
|
82
98
|
```ts
|
|
83
|
-
|
|
84
|
-
|
|
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
|
|
108
|
+
## 🧠 How It Actually Works
|
|
90
109
|
|
|
91
|
-
|
|
|
92
|
-
|
|
93
|
-
| Dev (
|
|
94
|
-
| Preview
|
|
95
|
-
| Production
|
|
96
|
-
|
|
|
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
|
-
|
|
117
|
+
**No runtime branching in client bundles. No hidden magic.**
|
|
100
118
|
|
|
101
119
|
---
|
|
102
120
|
|
|
103
|
-
##
|
|
121
|
+
## ⚙️ Plugin Options
|
|
104
122
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
123
|
+
```ts
|
|
124
|
+
biniEnv({
|
|
125
|
+
enabled: true,
|
|
126
|
+
clearViteHeader: true,
|
|
127
|
+
logo: 'ß',
|
|
128
|
+
envPrefix: ['BINI_', 'VITE_']
|
|
129
|
+
});
|
|
111
130
|
```
|
|
112
131
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
##
|
|
140
|
+
## 📚 API
|
|
124
141
|
|
|
125
|
-
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
166
|
+
### `biniEnv(options)`
|
|
143
167
|
|
|
144
|
-
|
|
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.[
|
|
148
|
-
3. `.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
|
-
##
|
|
185
|
+
## ⚡ Performance
|
|
154
186
|
|
|
155
|
-
|
|
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
|
-
|
|
193
|
+
If you see overhead in production, you did something wrong.
|
|
158
194
|
|
|
159
|
-
|
|
160
|
-
import { getEnv } from 'bini-env';
|
|
195
|
+
---
|
|
161
196
|
|
|
162
|
-
|
|
163
|
-
```
|
|
197
|
+
## 🔥 Common Failure Modes
|
|
164
198
|
|
|
165
|
-
###
|
|
199
|
+
### 1. “Env is undefined”
|
|
166
200
|
|
|
167
|
-
|
|
201
|
+
You forgot the prefix.
|
|
168
202
|
|
|
169
|
-
|
|
170
|
-
import { requireEnv } from 'bini-env';
|
|
203
|
+
### 2. “Works in dev, broken in prod”
|
|
171
204
|
|
|
172
|
-
|
|
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
|
-
###
|
|
207
|
+
### 3. “Secrets leaked”
|
|
179
208
|
|
|
180
|
-
|
|
209
|
+
You exposed them via prefix.
|
|
181
210
|
|
|
182
|
-
###
|
|
211
|
+
### 4. “Types not found”
|
|
183
212
|
|
|
184
|
-
|
|
213
|
+
Add:
|
|
185
214
|
|
|
186
215
|
```ts
|
|
187
|
-
|
|
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
|
-
##
|
|
221
|
+
## 🧪 Reality Check
|
|
196
222
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
##
|
|
235
|
+
## 🤝 Contributing
|
|
236
|
+
|
|
237
|
+
PRs welcome — but:
|
|
238
|
+
|
|
239
|
+
* No bloat
|
|
240
|
+
* No magic
|
|
241
|
+
* No runtime cost
|
|
214
242
|
|
|
215
|
-
|
|
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
|
-
|
|
253
|
+
**Ship fast. Leak nothing. Blame config, not tooling.**
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
export { Plugin } from 'vite';
|
|
3
|
+
|
|
4
|
+
interface BiniEnvPluginOptions {
|
|
5
|
+
readonly enabled?: boolean;
|
|
6
|
+
readonly clearViteHeader?: boolean;
|
|
7
|
+
readonly logo?: string;
|
|
8
|
+
readonly envPrefix?: string | string[];
|
|
9
|
+
}
|
|
10
|
+
interface DetectedEnvFile {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly path: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Read an environment variable with caching for performance.
|
|
16
|
+
* Cache is cleared on module reload in development only.
|
|
17
|
+
*/
|
|
18
|
+
declare function getEnv(key: string): string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Optimized requireEnv with cached error messages
|
|
21
|
+
*/
|
|
22
|
+
declare function requireEnv(key: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Load .env file with memoization and race condition prevention
|
|
25
|
+
*/
|
|
26
|
+
declare function loadEnv(projectRoot?: string): Promise<void>;
|
|
27
|
+
declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
|
|
28
|
+
/**
|
|
29
|
+
* Production-ready Vite plugin with performance optimizations:
|
|
30
|
+
* - Lazy loading
|
|
31
|
+
* - Caching
|
|
32
|
+
* - Minimal bundle impact
|
|
33
|
+
* - No runtime overhead in production
|
|
34
|
+
*/
|
|
35
|
+
declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
|
|
36
|
+
|
|
37
|
+
export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, detectEnvFiles, getEnv, loadEnv, requireEnv };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,77 +2,35 @@ import { Plugin } from 'vite';
|
|
|
2
2
|
export { Plugin } from 'vite';
|
|
3
3
|
|
|
4
4
|
interface BiniEnvPluginOptions {
|
|
5
|
-
/**
|
|
6
|
-
* Enable/disable the plugin
|
|
7
|
-
* @default true
|
|
8
|
-
*/
|
|
9
5
|
readonly enabled?: boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Remove Vite's default header
|
|
12
|
-
* @default true
|
|
13
|
-
*/
|
|
14
6
|
readonly clearViteHeader?: boolean;
|
|
15
|
-
/**
|
|
16
|
-
* Custom logo/text to display
|
|
17
|
-
* @default 'ß'
|
|
18
|
-
*/
|
|
19
7
|
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;
|
|
8
|
+
readonly envPrefix?: string | string[];
|
|
27
9
|
}
|
|
28
10
|
interface DetectedEnvFile {
|
|
29
11
|
readonly name: string;
|
|
30
12
|
readonly path: string;
|
|
31
13
|
}
|
|
32
14
|
/**
|
|
33
|
-
* Read an environment variable
|
|
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');
|
|
15
|
+
* Read an environment variable with caching for performance.
|
|
16
|
+
* Cache is cleared on module reload in development only.
|
|
43
17
|
*/
|
|
44
18
|
declare function getEnv(key: string): string | undefined;
|
|
45
19
|
/**
|
|
46
|
-
*
|
|
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');
|
|
20
|
+
* Optimized requireEnv with cached error messages
|
|
52
21
|
*/
|
|
53
22
|
declare function requireEnv(key: string): string;
|
|
54
23
|
/**
|
|
55
|
-
*
|
|
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.
|
|
24
|
+
* Load .env file with memoization and race condition prevention
|
|
63
25
|
*/
|
|
64
26
|
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
27
|
declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
|
|
69
28
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* - Replaces Vite's startup output with the Bini.js branded header
|
|
29
|
+
* Production-ready Vite plugin with performance optimizations:
|
|
30
|
+
* - Lazy loading
|
|
31
|
+
* - Caching
|
|
32
|
+
* - Minimal bundle impact
|
|
33
|
+
* - No runtime overhead in production
|
|
76
34
|
*/
|
|
77
35
|
declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
|
|
78
36
|
|