bini-env 1.1.1 → 2.0.0
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 +188 -52
- package/dist/index.d.mts +2 -21
- package/dist/index.d.ts +2 -21
- package/dist/index.js +29 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +29 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|

|
|
6
6
|

|
|
7
7
|

|
|
8
|
-

|
|
9
9
|

|
|
10
10
|
|
|
11
|
-
**
|
|
11
|
+
**Environment variable system + Vite plugin for Bini.js**
|
|
12
12
|
|
|
13
13
|
Powered by [Hono](https://hono.dev) — reads env vars from the Hono request context so variables are always resolved from the correct runtime binding, whether you're on Node.js, Bun, Deno, Vercel Edge, Netlify Edge, or Cloudflare Workers.
|
|
14
14
|
|
|
@@ -18,10 +18,11 @@ Powered by [Hono](https://hono.dev) — reads env vars from the Hono request con
|
|
|
18
18
|
|
|
19
19
|
- **Hono-native** — `getEnv(c, key)` / `requireEnv(c, key)` read directly from the Hono request context
|
|
20
20
|
- **Universal runtime** — CF Workers, Node, Bun, Deno, Vercel Edge, Netlify Edge — Hono's adapter handles all of it
|
|
21
|
-
- **Zero
|
|
21
|
+
- **Zero-config dev secrets** — non-prefixed `.env` values are always mirrored into `process.env` automatically during `vite dev` / `vite preview`, so Node-hosted Hono routes can read them with no manual loop
|
|
22
22
|
- **Vite-native dev** — `.env` loading, file watching, and server restarts are handled by Vite itself
|
|
23
|
+
- **`envDir`-aware** — respects a custom `envDir` or `root` in your `vite.config.ts` instead of always assuming the working directory
|
|
23
24
|
- **Dev banner** — prints `ß Bini.js (dev/preview)` and lists detected `.env` files on server start
|
|
24
|
-
- **
|
|
25
|
+
- **Fixed, predictable prefixes** — only `BINI_` and `VITE_` are ever exposed to the browser; there's no config surface that can accidentally widen it
|
|
25
26
|
- **Tree-shakeable** — nothing lands in the client bundle that shouldn't
|
|
26
27
|
- **Typed** — full TypeScript support with an exported `HonoContext` type
|
|
27
28
|
|
|
@@ -55,6 +56,8 @@ export default defineConfig({
|
|
|
55
56
|
})
|
|
56
57
|
```
|
|
57
58
|
|
|
59
|
+
`biniEnv()` takes no options — there's nothing to configure.
|
|
60
|
+
|
|
58
61
|
**2. Read env vars in your Hono handlers**
|
|
59
62
|
|
|
60
63
|
```ts
|
|
@@ -88,6 +91,8 @@ app.post('/hello', async (c) => {
|
|
|
88
91
|
export default app
|
|
89
92
|
```
|
|
90
93
|
|
|
94
|
+
That's it — no manual `loadEnv` loop in `vite.config.ts` needed. `MY_API_KEY` just needs to exist in your `.env` file with no prefix, and `requireEnv` will find it during dev and preview.
|
|
95
|
+
|
|
91
96
|
---
|
|
92
97
|
|
|
93
98
|
## Usage Pattern
|
|
@@ -128,55 +133,127 @@ app.post('/example', async (c) => {
|
|
|
128
133
|
|
|
129
134
|
---
|
|
130
135
|
|
|
131
|
-
##
|
|
136
|
+
## How It Works in Dev
|
|
132
137
|
|
|
133
|
-
|
|
138
|
+
When you run `vite dev` (or `vite preview`), `biniEnv()` automatically loads your `.env*` files with Vite's own `loadEnv` and mirrors every **non-prefixed** variable into `process.env`. This is what lets `getEnv` / `requireEnv` resolve server-side secrets inside Hono API routes without any extra setup — Hono's `env(c)` adapter reads from `process.env` on Node, and `process.env` is now populated for you.
|
|
134
139
|
|
|
135
|
-
`
|
|
140
|
+
It reads `.env` files from the same place Vite does: your configured `envDir` if you've set one, otherwise your `root`, otherwise the working directory. A custom `envDir` in `vite.config.ts` is respected automatically. If you've set `envDir: false` in your Vite config to disable `.env` loading entirely, `bini-env` respects that too and skips the mirror.
|
|
136
141
|
|
|
137
|
-
|
|
142
|
+
It happens silently in the background when it succeeds — no terminal log, no banner line, nothing to configure. Your existing dev server output (the `ß Bini.js` banner, detected `.env` files, local/network URLs) stays exactly as it was:
|
|
138
143
|
|
|
139
|
-
```
|
|
140
|
-
|
|
144
|
+
```
|
|
145
|
+
ß Bini.js (dev)
|
|
146
|
+
➜ Environments: .env.local, .env
|
|
147
|
+
➜ Local: http://localhost:3000/
|
|
148
|
+
➜ Network: http://192.168.1.7:3000/
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
If loading or mirroring the `.env` file fails for any reason, `bini-env` prints a warning — but the dev server still boots either way, it never throws:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
10:45:55 (!) [bini-env] Failed to inject .env into process.env: <reason>
|
|
141
155
|
```
|
|
142
156
|
|
|
143
|
-
|
|
157
|
+
This happens automatically — there is no flag to turn it off. It's core behavior of `biniEnv()`, not an opt-in feature.
|
|
144
158
|
|
|
145
|
-
|
|
159
|
+
**Precedence:** a value already present in `process.env` (set by your OS, shell, or CI) always wins. `.env` file values only fill in variables that aren't already set — they never override real environment configuration.
|
|
146
160
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
161
|
+
**What gets mirrored:**
|
|
162
|
+
|
|
163
|
+
| Variable | Mirrored into `process.env`? |
|
|
164
|
+
|----------|------------------------------|
|
|
165
|
+
| No prefix (`DATABASE_URL`) | ✅ Yes |
|
|
166
|
+
| `BINI_` / `VITE_` prefixed | ❌ No — already handled via `import.meta.env` |
|
|
167
|
+
| Empty value (`KEY=`) | ❌ No — skipped, so `requireEnv` still fails loudly on a blank placeholder |
|
|
168
|
+
| Already set in the OS/CI environment | ❌ No — existing value is kept |
|
|
169
|
+
|
|
170
|
+
**Scope:**
|
|
171
|
+
|
|
172
|
+
- Runs only for `vite dev` and `vite preview` (`command === 'serve'`)
|
|
173
|
+
- **Never** runs for `vite build` — production bundles and `process.env` at build time are untouched
|
|
174
|
+
- **Production** uses your hosting platform's native env injection (`bini-server`, Vercel, Netlify, Cloudflare, etc.) — nothing extra to do there
|
|
175
|
+
- This behavior is always on — there is no option to disable it
|
|
176
|
+
|
|
177
|
+
**Migrating from a manual loop:** if your project already has this in `vite.config.ts`, you can delete it — `biniEnv()` now does it for you:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
// vite.config.ts — no longer needed, remove this
|
|
181
|
+
const env = loadEnv(mode, process.cwd(), '')
|
|
182
|
+
for (const [key, value] of Object.entries(env)) {
|
|
183
|
+
if (!key.startsWith('BINI_') && !key.startsWith('VITE_')) {
|
|
184
|
+
process.env[key] = value
|
|
185
|
+
}
|
|
186
|
+
}
|
|
150
187
|
```
|
|
151
188
|
|
|
152
189
|
```ts
|
|
153
|
-
//
|
|
154
|
-
|
|
190
|
+
// vite.config.ts — this is all you need now
|
|
191
|
+
export default defineConfig({
|
|
192
|
+
plugins: [biniEnv()]
|
|
193
|
+
})
|
|
155
194
|
```
|
|
156
195
|
|
|
157
|
-
|
|
196
|
+
---
|
|
158
197
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
198
|
+
## Environment Prefixes
|
|
199
|
+
|
|
200
|
+
### The Truth About Prefixes
|
|
201
|
+
|
|
202
|
+
**Both `BINI_` and `VITE_` work exactly the same way.** Neither is special, and neither can be changed — `biniEnv()` always exposes exactly these two prefixes to the browser, nothing more.
|
|
162
203
|
|
|
163
|
-
|
|
164
|
-
|
|
204
|
+
| Prefix | Exposed to Browser? |
|
|
205
|
+
|--------|--------------------|
|
|
206
|
+
| `BINI_` | **Yes** — always |
|
|
207
|
+
| `VITE_` | **Yes** — always (Vite's own default prefix) |
|
|
208
|
+
| No prefix | **No** — mirrored into `process.env` in dev/preview instead |
|
|
165
209
|
|
|
166
|
-
|
|
210
|
+
### What `biniEnv()` Actually Does
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
// biniEnv() always sets envPrefix to:
|
|
214
|
+
envPrefix: ['BINI_', 'VITE_']
|
|
215
|
+
|
|
216
|
+
// This tells Vite: "Expose ALL variables starting with BINI_ or VITE_ to import.meta.env"
|
|
217
|
+
// Everything else is mirrored into process.env during vite dev / preview
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**This means:**
|
|
221
|
+
- ✅ `BINI_API_KEY` → available in browser via `import.meta.env.BINI_API_KEY`
|
|
222
|
+
- ✅ `VITE_API_URL` → available in browser via `import.meta.env.VITE_API_URL`
|
|
223
|
+
- ❌ `DATABASE_URL` → NOT available in browser (no prefix) — available server-side via `getEnv`/`requireEnv`
|
|
224
|
+
|
|
225
|
+
### How to Keep Secrets Secret
|
|
226
|
+
|
|
227
|
+
**Use no prefix for secrets:**
|
|
228
|
+
|
|
229
|
+
```env
|
|
230
|
+
# ✅ NOT exposed to browser — mirrored into process.env for server-side use only
|
|
167
231
|
DATABASE_URL=postgres://...
|
|
168
232
|
STRIPE_SECRET_KEY=sk_live_...
|
|
233
|
+
AWS_SECRET_KEY=...
|
|
169
234
|
```
|
|
170
235
|
|
|
171
|
-
|
|
236
|
+
That's the whole rule. Since the prefix list is fixed, there's no config mistake that can widen what gets exposed — anything without `BINI_` or `VITE_` in front of it simply never reaches the browser.
|
|
172
237
|
|
|
173
|
-
### Prefix
|
|
238
|
+
### Choosing the Right Prefix
|
|
174
239
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
240
|
+
```env
|
|
241
|
+
# ✅ Use no prefix for secrets
|
|
242
|
+
DATABASE_URL=postgres://...
|
|
243
|
+
STRIPE_SECRET_KEY=sk_live_...
|
|
244
|
+
|
|
245
|
+
# ✅ Use BINI_ or VITE_ for public config
|
|
246
|
+
BINI_API_URL=https://api.example.com
|
|
247
|
+
VITE_ANALYTICS_ID=UA-XXXX
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Prefix Summary
|
|
251
|
+
|
|
252
|
+
| Prefix | Exposed to Browser? | Mirrored to `process.env` (dev/preview)? | Use For |
|
|
253
|
+
|--------|--------------------|-------------------------------------------|---------|
|
|
254
|
+
| No prefix | ❌ Never | ✅ Yes (unless empty or already set) | **SECRETS** — API keys, database URLs, tokens |
|
|
255
|
+
| `BINI_` | ✅ Always | ❌ No | Public config |
|
|
256
|
+
| `VITE_` | ✅ Always | ❌ No | Public config (Vite's default) |
|
|
180
257
|
|
|
181
258
|
---
|
|
182
259
|
|
|
@@ -186,8 +263,8 @@ STRIPE_SECRET_KEY=sk_live_...
|
|
|
186
263
|
|
|
187
264
|
| Platform | Runtime | Env source | How Hono reads it |
|
|
188
265
|
|----------|---------|------------|-------------------|
|
|
189
|
-
| Node.js | Node | System env / platform dashboard | `process.env` ✅ |
|
|
190
|
-
| Bun | Bun | System env / platform dashboard | `process.env` ✅ |
|
|
266
|
+
| Node.js | Node | System env / platform dashboard / `bini-env` dev mirror | `process.env` ✅ |
|
|
267
|
+
| Bun | Bun | System env / platform dashboard / `bini-env` dev mirror | `process.env` ✅ |
|
|
191
268
|
| Vercel Edge | V8 isolate | Project settings → Env Vars | `process.env` ✅ |
|
|
192
269
|
| Netlify Edge | Deno | Site settings → Env Vars | `Deno.env.get()` ✅ |
|
|
193
270
|
| Cloudflare Workers | V8 isolate | `wrangler.toml` / dashboard | CF bindings via `c.env` ✅ |
|
|
@@ -201,16 +278,21 @@ STRIPE_SECRET_KEY=sk_live_...
|
|
|
201
278
|
|
|
202
279
|
### The plugin — `biniEnv()`
|
|
203
280
|
|
|
204
|
-
Does
|
|
281
|
+
Does three things: tells Vite to expose `BINI_` and `VITE_` prefixed vars to `import.meta.env`, mirrors non-prefixed `.env` values into `process.env` during `vite dev` / `vite preview` so Hono routes can read them, and prints the `ß Bini.js` banner with detected `.env` files when the dev or preview server starts.
|
|
205
282
|
|
|
206
283
|
```ts
|
|
207
284
|
// what biniEnv() does internally
|
|
208
|
-
config() {
|
|
209
|
-
|
|
285
|
+
config(userConfig, { command, mode }) {
|
|
286
|
+
if (command === 'serve') {
|
|
287
|
+
const envDir = userConfig.envDir ?? userConfig.root ?? process.cwd()
|
|
288
|
+
// mirrors non-prefixed, non-empty .env values into process.env
|
|
289
|
+
// silent on success, warns on failure — no opt-out
|
|
290
|
+
}
|
|
291
|
+
return { envPrefix: ['BINI_', 'VITE_'] }
|
|
210
292
|
}
|
|
211
293
|
```
|
|
212
294
|
|
|
213
|
-
On server start you will see:
|
|
295
|
+
The `process.env` mirror runs silently — it doesn't add any lines to the banner. On server start you will see the same banner as before:
|
|
214
296
|
|
|
215
297
|
```
|
|
216
298
|
ß Bini.js (dev)
|
|
@@ -219,11 +301,11 @@ On server start you will see:
|
|
|
219
301
|
➜ Network: http://192.168.1.7:3000/
|
|
220
302
|
```
|
|
221
303
|
|
|
222
|
-
Vite handles
|
|
304
|
+
Vite handles the rest natively: loading `.env`, `.env.local`, `.env.[mode]` files during dev, watching and restarting on change, injecting prefixed vars into `import.meta.env` at build time, and HMR when env files change.
|
|
223
305
|
|
|
224
306
|
### The env functions — `getEnv` / `requireEnv`
|
|
225
307
|
|
|
226
|
-
Both functions read exclusively from `env(c)` via `hono/adapter` — the Hono request context. There
|
|
308
|
+
Both functions read exclusively from `env(c)` via `hono/adapter` — the Hono request context. There is no direct `process.env` access inside `getEnv`/`requireEnv` themselves; on Node, Hono's adapter reads from `process.env`, which is why the dev-mode mirror above is what makes non-prefixed secrets resolvable there. Every read is request-scoped and resolved by Hono's adapter for the current platform.
|
|
227
309
|
|
|
228
310
|
`dotenv` is never used. In production, vars are set in your hosting platform's environment config.
|
|
229
311
|
|
|
@@ -280,19 +362,15 @@ On failure, the terminal will show:
|
|
|
280
362
|
-> Set it in your platform's env config or hosting dashboard.
|
|
281
363
|
```
|
|
282
364
|
|
|
283
|
-
### `biniEnv(
|
|
365
|
+
### `biniEnv()`
|
|
284
366
|
|
|
285
|
-
Vite plugin.
|
|
367
|
+
Vite plugin. Takes no options. Exposes `BINI_` and `VITE_` prefixed vars to `import.meta.env`, and mirrors every other (non-empty) `.env` value into `process.env` during dev/preview.
|
|
286
368
|
|
|
287
369
|
```ts
|
|
288
370
|
biniEnv()
|
|
289
|
-
// or with extra prefixes
|
|
290
|
-
biniEnv({ envPrefix: ['MY_PUBLIC_'] })
|
|
291
371
|
```
|
|
292
372
|
|
|
293
|
-
|
|
294
|
-
|--------|------|---------|-------------|
|
|
295
|
-
| `envPrefix` | `string \| string[]` | `[]` | Extra prefixes to expose to `import.meta.env`, in addition to `BINI_` and `VITE_` |
|
|
373
|
+
There's nothing to configure — no prefix list to extend, no flag to disable the `process.env` mirror. It reads `.env` files from your `envDir` (or `root`, or the working directory), never runs on `vite build`, never overrides a value already set in `process.env`, and skips the mirror entirely if you've set `envDir: false`.
|
|
296
374
|
|
|
297
375
|
### `biniLogger`
|
|
298
376
|
|
|
@@ -325,27 +403,85 @@ function readDbConfig(c: HonoContext) {
|
|
|
325
403
|
|
|
326
404
|
---
|
|
327
405
|
|
|
406
|
+
## Security Best Practices
|
|
407
|
+
|
|
408
|
+
### Rule 1: Never Prefix Secrets
|
|
409
|
+
```env
|
|
410
|
+
# ❌ BAD - This will be exposed to the browser!
|
|
411
|
+
BINI_DATABASE_URL=postgres://...
|
|
412
|
+
|
|
413
|
+
# ✅ GOOD - Not exposed to browser, mirrored into process.env for server-side use
|
|
414
|
+
DATABASE_URL=postgres://...
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Rule 2: Use No Prefix for Anything Secret
|
|
418
|
+
```env
|
|
419
|
+
# ✅ Safe - Not exposed, available server-side via getEnv/requireEnv
|
|
420
|
+
DATABASE_URL=postgres://...
|
|
421
|
+
STRIPE_SECRET=sk_live_...
|
|
422
|
+
AWS_SECRET_KEY=...
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Rule 3: Use `BINI_` or `VITE_` for Public Data
|
|
426
|
+
```env
|
|
427
|
+
# ✅ Safe - Public data
|
|
428
|
+
BINI_API_URL=https://api.example.com
|
|
429
|
+
VITE_GA_ID=UA-XXXXX
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Rule 4: Don't Leave Secret Placeholders Empty
|
|
433
|
+
|
|
434
|
+
An empty value (`API_KEY=`) is skipped by the `process.env` mirror, so `requireEnv` will correctly throw instead of silently succeeding with an empty string. Fill in real values, or remove the line entirely if it's genuinely unused.
|
|
435
|
+
|
|
436
|
+
### Rule 5: Let OS/CI Env Vars Win in Dev
|
|
437
|
+
|
|
438
|
+
The `process.env` mirror never overrides a variable that's already set. If you need to override a `.env` value locally (e.g. pointing at a different database), export it in your shell before starting the dev server rather than editing `.env`:
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
DATABASE_URL=postgres://staging... pnpm dev
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
328
446
|
## Performance
|
|
329
447
|
|
|
330
448
|
| Metric | Dev | Prod |
|
|
331
449
|
|--------|-----|------|
|
|
332
|
-
| File reads |
|
|
333
|
-
| Runtime cost | ~0ms | 0 |
|
|
450
|
+
| File reads | 1 (`loadEnv`, cached by Vite) | 0 |
|
|
451
|
+
| Runtime cost | ~0ms (mirror runs once at server start) | 0 |
|
|
334
452
|
| Bundle impact | Minimal | Tree-shaken |
|
|
335
453
|
|
|
336
|
-
No dotenv. No disk reads. No caching layer. `getEnv` is a direct call to Hono's adapter on every invocation — request-scoped and correct.
|
|
454
|
+
No dotenv. No per-request disk reads. No caching layer beyond Vite's own. `getEnv` is a direct call to Hono's adapter on every invocation — request-scoped and correct. The `process.env` mirror runs exactly once, when the dev or preview server starts.
|
|
337
455
|
|
|
338
456
|
---
|
|
339
457
|
|
|
340
458
|
## Troubleshooting
|
|
341
459
|
|
|
460
|
+
### "My BINI_ var is exposed to the browser!"
|
|
461
|
+
|
|
462
|
+
Yes — by design. `BINI_` is always exposed, the same as `VITE_`. Use no prefix for secrets.
|
|
463
|
+
|
|
342
464
|
### "Env var is undefined in production"
|
|
343
465
|
|
|
344
|
-
Vars set in `.env` files are only loaded by Vite during local development. In production, set your variables in your hosting platform's environment dashboard (Vercel, Netlify, Cloudflare, etc.).
|
|
466
|
+
Vars set in `.env` files are only loaded by Vite (and mirrored into `process.env`) during local development and preview. In production, set your variables in your hosting platform's environment dashboard (Vercel, Netlify, Cloudflare, etc.).
|
|
345
467
|
|
|
346
468
|
### "Works in dev, undefined in prod"
|
|
347
469
|
|
|
348
|
-
Same as above. Local dev works because
|
|
470
|
+
Same as above. Local dev works because `biniEnv()` loads `.env` files and mirrors non-prefixed vars into `process.env` automatically. Production requires platform-level configuration.
|
|
471
|
+
|
|
472
|
+
### "My .env value isn't taking effect in dev"
|
|
473
|
+
|
|
474
|
+
Two likely causes:
|
|
475
|
+
- Check your shell and CI environment first — the `process.env` mirror never overrides a variable that's already set there. Unset it in your shell, or override it directly in your shell instead of `.env`.
|
|
476
|
+
- Check the value isn't empty (`KEY=`) — empty values are skipped on purpose.
|
|
477
|
+
|
|
478
|
+
### "requireEnv still throws even though my key is in .env"
|
|
479
|
+
|
|
480
|
+
If the value is `KEY=` with nothing after the `=`, it's treated as unset and skipped by design — this is intentional so a blank placeholder doesn't silently pass as configured. Give it a real value.
|
|
481
|
+
|
|
482
|
+
### "bini-env isn't reading my .env file from the right folder"
|
|
483
|
+
|
|
484
|
+
`biniEnv()` reads from your Vite `envDir` if you've set one, otherwise your `root`, otherwise the working directory — the same resolution Vite itself uses. Double check `envDir`/`root` in `vite.config.ts` if your `.env` lives somewhere non-standard.
|
|
349
485
|
|
|
350
486
|
### "Cloudflare secret not found"
|
|
351
487
|
|
|
@@ -373,7 +509,7 @@ Add to your `tsconfig.json` or entry file:
|
|
|
373
509
|
|
|
374
510
|
| Tool | Version | Notes |
|
|
375
511
|
|------|---------|-------|
|
|
376
|
-
| Vite | 8.x | `envPrefix` hook
|
|
512
|
+
| Vite | 8.x | `envPrefix` hook and `loadEnv` are fully compatible; empty prefix array is never passed |
|
|
377
513
|
| Hono | 4.x | `hono/adapter` `env()` is stable across all 4.x releases |
|
|
378
514
|
| TypeScript | 5.x | Full type support via exported `HonoContext` |
|
|
379
515
|
| Node.js | ≥ 20.19 | Minimum required version |
|
package/dist/index.d.mts
CHANGED
|
@@ -2,26 +2,7 @@ import { Context } from 'hono';
|
|
|
2
2
|
import { Plugin } from 'vite';
|
|
3
3
|
export { Plugin } from 'vite';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* bini-env/src/index.ts
|
|
7
|
-
*
|
|
8
|
-
* Two responsibilities only:
|
|
9
|
-
* 1. Tell Vite which env prefixes to expose to import.meta.env (biniEnv plugin)
|
|
10
|
-
* 2. Read env vars from the Hono request context (getEnv / requireEnv)
|
|
11
|
-
*
|
|
12
|
-
* process.env is never used. All runtime env access goes through Hono's env() adapter,
|
|
13
|
-
* which handles Node, Bun, Cloudflare Workers, Deno, and Vercel Edge natively.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Accepts any Hono Context. Typed against Hono's own Context rather than a
|
|
18
|
-
* loose duck type so misuse is caught at the call site.
|
|
19
|
-
*/
|
|
20
5
|
type HonoContext = Context;
|
|
21
|
-
interface BiniEnvPluginOptions {
|
|
22
|
-
/** Extra prefixes to expose to import.meta.env, in addition to BINI_ and VITE_. */
|
|
23
|
-
readonly envPrefix?: string | string[];
|
|
24
|
-
}
|
|
25
6
|
declare const biniLogger: {
|
|
26
7
|
readonly info: (msg: string) => void;
|
|
27
8
|
readonly warn: (msg: string) => void;
|
|
@@ -29,6 +10,6 @@ declare const biniLogger: {
|
|
|
29
10
|
};
|
|
30
11
|
declare function getEnv(c: HonoContext, key: string): string | undefined;
|
|
31
12
|
declare function requireEnv(c: HonoContext, key: string): string;
|
|
32
|
-
declare function biniEnv(
|
|
13
|
+
declare function biniEnv(): Plugin;
|
|
33
14
|
|
|
34
|
-
export { type
|
|
15
|
+
export { type HonoContext, biniEnv, biniLogger, getEnv, requireEnv };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,26 +2,7 @@ import { Context } from 'hono';
|
|
|
2
2
|
import { Plugin } from 'vite';
|
|
3
3
|
export { Plugin } from 'vite';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* bini-env/src/index.ts
|
|
7
|
-
*
|
|
8
|
-
* Two responsibilities only:
|
|
9
|
-
* 1. Tell Vite which env prefixes to expose to import.meta.env (biniEnv plugin)
|
|
10
|
-
* 2. Read env vars from the Hono request context (getEnv / requireEnv)
|
|
11
|
-
*
|
|
12
|
-
* process.env is never used. All runtime env access goes through Hono's env() adapter,
|
|
13
|
-
* which handles Node, Bun, Cloudflare Workers, Deno, and Vercel Edge natively.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Accepts any Hono Context. Typed against Hono's own Context rather than a
|
|
18
|
-
* loose duck type so misuse is caught at the call site.
|
|
19
|
-
*/
|
|
20
5
|
type HonoContext = Context;
|
|
21
|
-
interface BiniEnvPluginOptions {
|
|
22
|
-
/** Extra prefixes to expose to import.meta.env, in addition to BINI_ and VITE_. */
|
|
23
|
-
readonly envPrefix?: string | string[];
|
|
24
|
-
}
|
|
25
6
|
declare const biniLogger: {
|
|
26
7
|
readonly info: (msg: string) => void;
|
|
27
8
|
readonly warn: (msg: string) => void;
|
|
@@ -29,6 +10,6 @@ declare const biniLogger: {
|
|
|
29
10
|
};
|
|
30
11
|
declare function getEnv(c: HonoContext, key: string): string | undefined;
|
|
31
12
|
declare function requireEnv(c: HonoContext, key: string): string;
|
|
32
|
-
declare function biniEnv(
|
|
13
|
+
declare function biniEnv(): Plugin;
|
|
33
14
|
|
|
34
|
-
export { type
|
|
15
|
+
export { type HonoContext, biniEnv, biniLogger, getEnv, requireEnv };
|
package/dist/index.js
CHANGED
|
@@ -51,7 +51,7 @@ function requireEnv(c, key) {
|
|
|
51
51
|
}
|
|
52
52
|
return val;
|
|
53
53
|
}
|
|
54
|
-
var
|
|
54
|
+
var ENV_PREFIXES = ["BINI_", "VITE_"];
|
|
55
55
|
function detectEnvFiles(root) {
|
|
56
56
|
try {
|
|
57
57
|
const fs = __require("fs");
|
|
@@ -67,6 +67,21 @@ function detectEnvFiles(root) {
|
|
|
67
67
|
return [];
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
+
function injectEnvIntoProcess(mode, envDir) {
|
|
71
|
+
if (typeof process === "undefined" || !process.env) return 0;
|
|
72
|
+
const { loadEnv } = __require("vite");
|
|
73
|
+
const loaded = loadEnv(mode, envDir, "");
|
|
74
|
+
let injected = 0;
|
|
75
|
+
for (const [key, value] of Object.entries(loaded)) {
|
|
76
|
+
const isPrefixed = ENV_PREFIXES.some((p) => key.startsWith(p));
|
|
77
|
+
if (isPrefixed) continue;
|
|
78
|
+
if (!value) continue;
|
|
79
|
+
if (process.env[key] !== void 0) continue;
|
|
80
|
+
process.env[key] = value;
|
|
81
|
+
injected++;
|
|
82
|
+
}
|
|
83
|
+
return injected;
|
|
84
|
+
}
|
|
70
85
|
function printBanner(server, mode, root) {
|
|
71
86
|
const original = server.printUrls.bind(server);
|
|
72
87
|
server.printUrls = () => {
|
|
@@ -79,15 +94,21 @@ function printBanner(server, mode, root) {
|
|
|
79
94
|
original();
|
|
80
95
|
};
|
|
81
96
|
}
|
|
82
|
-
function biniEnv(
|
|
83
|
-
const extraPrefixes = options.envPrefix ? Array.isArray(options.envPrefix) ? options.envPrefix : [options.envPrefix] : [];
|
|
84
|
-
const envPrefix = [
|
|
85
|
-
.../* @__PURE__ */ new Set([...DEFAULT_PREFIXES, ...extraPrefixes])
|
|
86
|
-
];
|
|
97
|
+
function biniEnv() {
|
|
87
98
|
return {
|
|
88
99
|
name: "bini-env",
|
|
89
|
-
config() {
|
|
90
|
-
|
|
100
|
+
config(userConfig, { command, mode }) {
|
|
101
|
+
if (command === "serve" && userConfig.envDir !== false) {
|
|
102
|
+
const envDir = typeof userConfig.envDir === "string" ? userConfig.envDir : userConfig.root ?? process.cwd();
|
|
103
|
+
try {
|
|
104
|
+
injectEnvIntoProcess(mode, envDir);
|
|
105
|
+
} catch (err) {
|
|
106
|
+
biniLogger.warn(
|
|
107
|
+
`Failed to inject .env into process.env: ${err.message}`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { envPrefix: [...ENV_PREFIXES] };
|
|
91
112
|
},
|
|
92
113
|
configureServer(server) {
|
|
93
114
|
printBanner(server, "dev", server.config.root);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["env"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["env"],"mappings":"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","file":"index.js","sourcesContent":["import { env } from 'hono/adapter';\nimport type { Context } from 'hono';\nimport type { Plugin, UserConfig, ViteDevServer, PreviewServer } from 'vite';\n\nconst C = {\n CYAN : '\\x1b[36m',\n RESET : '\\x1b[0m',\n YELLOW: '\\x1b[33m',\n RED : '\\x1b[31m',\n BOLD : '\\x1b[1m',\n DIM : '\\x1b[2m',\n} as const;\n\nexport type HonoContext = Context;\n\nfunction _ts(): string {\n return `${C.DIM}${new Date().toLocaleTimeString('en-US', { hour12: false })}${C.RESET}`;\n}\n\nexport const biniLogger = {\n info(msg: string): void {\n console.log(`${_ts()} ${C.CYAN}${C.BOLD}[bini-env]${C.RESET} ${msg}`);\n },\n warn(msg: string): void {\n console.warn(\n `${_ts()} ${C.YELLOW}${C.BOLD}(!) [bini-env]${C.RESET} ${C.YELLOW}${msg}${C.RESET}`,\n );\n },\n error(msg: string, err?: unknown): void {\n const detail =\n err instanceof Error ? `\\n ${C.DIM}${err.message}${C.RESET}` : '';\n console.error(\n `${_ts()} ${C.RED}${C.BOLD}[bini-env] error${C.RESET} ${msg}${detail}`,\n );\n },\n} as const;\n\nexport function getEnv(c: HonoContext, key: string): string | undefined {\n const honoEnvs = env(c) as Record<string, string | undefined>;\n return honoEnvs[key];\n}\n\nexport function requireEnv(c: HonoContext, key: string): string {\n const val = getEnv(c, key);\n\n if (!val) {\n biniLogger.error(\n `Missing required environment variable: \"${key}\"\\n` +\n ` ${C.DIM}-> Set it in your platform's env config or hosting dashboard.${C.RESET}`,\n );\n\n throw new Error(`[bini-env] Missing required environment variable: \"${key}\"`);\n }\n\n return val;\n}\n\nconst ENV_PREFIXES = ['BINI_', 'VITE_'] as const;\n\nfunction detectEnvFiles(root: string): string[] {\n try {\n const fs = require('node:fs') as typeof import('fs');\n const path = require('node:path') as typeof import('path');\n const nodeEnv = process.env.NODE_ENV ?? 'production';\n return [\n '.env.local',\n `.env.${nodeEnv}.local`,\n `.env.${nodeEnv}`,\n '.env',\n ].filter(f => fs.existsSync(path.join(root, f)));\n } catch {\n return [];\n }\n}\n\nfunction injectEnvIntoProcess(mode: string, envDir: string): number {\n if (typeof process === 'undefined' || !process.env) return 0;\n\n const { loadEnv } = require('vite') as typeof import('vite');\n const loaded = loadEnv(mode, envDir, '');\n let injected = 0;\n\n for (const [key, value] of Object.entries(loaded)) {\n const isPrefixed = ENV_PREFIXES.some((p) => key.startsWith(p));\n if (isPrefixed) continue;\n if (!value) continue;\n if (process.env[key] !== undefined) continue;\n process.env[key] = value;\n injected++;\n }\n\n return injected;\n}\n\nfunction printBanner(server: ViteDevServer | PreviewServer, mode: 'dev' | 'preview', root: string): void {\n const original = server.printUrls.bind(server);\n server.printUrls = () => {\n console.log(`\\n ${C.CYAN}ß Bini.js${C.RESET} (${mode})`);\n const found = detectEnvFiles(root);\n if (found.length > 0) {\n console.log(` \\x1b[32m➜\\x1b[0m Environments: ${found.join(', ')}`);\n }\n original();\n };\n}\n\nexport function biniEnv(): Plugin {\n return {\n name: 'bini-env',\n\n config(userConfig: UserConfig, { command, mode }): UserConfig {\n if (command === 'serve' && userConfig.envDir !== false) {\n const envDir =\n typeof userConfig.envDir === 'string'\n ? userConfig.envDir\n : userConfig.root ?? process.cwd();\n\n try {\n injectEnvIntoProcess(mode, envDir);\n } catch (err) {\n biniLogger.warn(\n `Failed to inject .env into process.env: ${(err as Error).message}`,\n );\n }\n }\n\n return { envPrefix: [...ENV_PREFIXES] };\n },\n\n configureServer(server) {\n printBanner(server, 'dev', server.config.root);\n },\n\n configurePreviewServer(server) {\n printBanner(server, 'preview', server.config.root);\n },\n };\n}\n\nexport type { Plugin } from 'vite';"]}
|
package/dist/index.mjs
CHANGED
|
@@ -49,7 +49,7 @@ function requireEnv(c, key) {
|
|
|
49
49
|
}
|
|
50
50
|
return val;
|
|
51
51
|
}
|
|
52
|
-
var
|
|
52
|
+
var ENV_PREFIXES = ["BINI_", "VITE_"];
|
|
53
53
|
function detectEnvFiles(root) {
|
|
54
54
|
try {
|
|
55
55
|
const fs = __require("fs");
|
|
@@ -65,6 +65,21 @@ function detectEnvFiles(root) {
|
|
|
65
65
|
return [];
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
+
function injectEnvIntoProcess(mode, envDir) {
|
|
69
|
+
if (typeof process === "undefined" || !process.env) return 0;
|
|
70
|
+
const { loadEnv } = __require("vite");
|
|
71
|
+
const loaded = loadEnv(mode, envDir, "");
|
|
72
|
+
let injected = 0;
|
|
73
|
+
for (const [key, value] of Object.entries(loaded)) {
|
|
74
|
+
const isPrefixed = ENV_PREFIXES.some((p) => key.startsWith(p));
|
|
75
|
+
if (isPrefixed) continue;
|
|
76
|
+
if (!value) continue;
|
|
77
|
+
if (process.env[key] !== void 0) continue;
|
|
78
|
+
process.env[key] = value;
|
|
79
|
+
injected++;
|
|
80
|
+
}
|
|
81
|
+
return injected;
|
|
82
|
+
}
|
|
68
83
|
function printBanner(server, mode, root) {
|
|
69
84
|
const original = server.printUrls.bind(server);
|
|
70
85
|
server.printUrls = () => {
|
|
@@ -77,15 +92,21 @@ function printBanner(server, mode, root) {
|
|
|
77
92
|
original();
|
|
78
93
|
};
|
|
79
94
|
}
|
|
80
|
-
function biniEnv(
|
|
81
|
-
const extraPrefixes = options.envPrefix ? Array.isArray(options.envPrefix) ? options.envPrefix : [options.envPrefix] : [];
|
|
82
|
-
const envPrefix = [
|
|
83
|
-
.../* @__PURE__ */ new Set([...DEFAULT_PREFIXES, ...extraPrefixes])
|
|
84
|
-
];
|
|
95
|
+
function biniEnv() {
|
|
85
96
|
return {
|
|
86
97
|
name: "bini-env",
|
|
87
|
-
config() {
|
|
88
|
-
|
|
98
|
+
config(userConfig, { command, mode }) {
|
|
99
|
+
if (command === "serve" && userConfig.envDir !== false) {
|
|
100
|
+
const envDir = typeof userConfig.envDir === "string" ? userConfig.envDir : userConfig.root ?? process.cwd();
|
|
101
|
+
try {
|
|
102
|
+
injectEnvIntoProcess(mode, envDir);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
biniLogger.warn(
|
|
105
|
+
`Failed to inject .env into process.env: ${err.message}`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return { envPrefix: [...ENV_PREFIXES] };
|
|
89
110
|
},
|
|
90
111
|
configureServer(server) {
|
|
91
112
|
printBanner(server, "dev", server.config.root);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { env } from 'hono/adapter';\nimport type { Context } from 'hono';\nimport type { Plugin, UserConfig, ViteDevServer, PreviewServer } from 'vite';\n\nconst C = {\n CYAN : '\\x1b[36m',\n RESET : '\\x1b[0m',\n YELLOW: '\\x1b[33m',\n RED : '\\x1b[31m',\n BOLD : '\\x1b[1m',\n DIM : '\\x1b[2m',\n} as const;\n\nexport type HonoContext = Context;\n\nfunction _ts(): string {\n return `${C.DIM}${new Date().toLocaleTimeString('en-US', { hour12: false })}${C.RESET}`;\n}\n\nexport const biniLogger = {\n info(msg: string): void {\n console.log(`${_ts()} ${C.CYAN}${C.BOLD}[bini-env]${C.RESET} ${msg}`);\n },\n warn(msg: string): void {\n console.warn(\n `${_ts()} ${C.YELLOW}${C.BOLD}(!) [bini-env]${C.RESET} ${C.YELLOW}${msg}${C.RESET}`,\n );\n },\n error(msg: string, err?: unknown): void {\n const detail =\n err instanceof Error ? `\\n ${C.DIM}${err.message}${C.RESET}` : '';\n console.error(\n `${_ts()} ${C.RED}${C.BOLD}[bini-env] error${C.RESET} ${msg}${detail}`,\n );\n },\n} as const;\n\nexport function getEnv(c: HonoContext, key: string): string | undefined {\n const honoEnvs = env(c) as Record<string, string | undefined>;\n return honoEnvs[key];\n}\n\nexport function requireEnv(c: HonoContext, key: string): string {\n const val = getEnv(c, key);\n\n if (!val) {\n biniLogger.error(\n `Missing required environment variable: \"${key}\"\\n` +\n ` ${C.DIM}-> Set it in your platform's env config or hosting dashboard.${C.RESET}`,\n );\n\n throw new Error(`[bini-env] Missing required environment variable: \"${key}\"`);\n }\n\n return val;\n}\n\nconst ENV_PREFIXES = ['BINI_', 'VITE_'] as const;\n\nfunction detectEnvFiles(root: string): string[] {\n try {\n const fs = require('node:fs') as typeof import('fs');\n const path = require('node:path') as typeof import('path');\n const nodeEnv = process.env.NODE_ENV ?? 'production';\n return [\n '.env.local',\n `.env.${nodeEnv}.local`,\n `.env.${nodeEnv}`,\n '.env',\n ].filter(f => fs.existsSync(path.join(root, f)));\n } catch {\n return [];\n }\n}\n\nfunction injectEnvIntoProcess(mode: string, envDir: string): number {\n if (typeof process === 'undefined' || !process.env) return 0;\n\n const { loadEnv } = require('vite') as typeof import('vite');\n const loaded = loadEnv(mode, envDir, '');\n let injected = 0;\n\n for (const [key, value] of Object.entries(loaded)) {\n const isPrefixed = ENV_PREFIXES.some((p) => key.startsWith(p));\n if (isPrefixed) continue;\n if (!value) continue;\n if (process.env[key] !== undefined) continue;\n process.env[key] = value;\n injected++;\n }\n\n return injected;\n}\n\nfunction printBanner(server: ViteDevServer | PreviewServer, mode: 'dev' | 'preview', root: string): void {\n const original = server.printUrls.bind(server);\n server.printUrls = () => {\n console.log(`\\n ${C.CYAN}ß Bini.js${C.RESET} (${mode})`);\n const found = detectEnvFiles(root);\n if (found.length > 0) {\n console.log(` \\x1b[32m➜\\x1b[0m Environments: ${found.join(', ')}`);\n }\n original();\n };\n}\n\nexport function biniEnv(): Plugin {\n return {\n name: 'bini-env',\n\n config(userConfig: UserConfig, { command, mode }): UserConfig {\n if (command === 'serve' && userConfig.envDir !== false) {\n const envDir =\n typeof userConfig.envDir === 'string'\n ? userConfig.envDir\n : userConfig.root ?? process.cwd();\n\n try {\n injectEnvIntoProcess(mode, envDir);\n } catch (err) {\n biniLogger.warn(\n `Failed to inject .env into process.env: ${(err as Error).message}`,\n );\n }\n }\n\n return { envPrefix: [...ENV_PREFIXES] };\n },\n\n configureServer(server) {\n printBanner(server, 'dev', server.config.root);\n },\n\n configurePreviewServer(server) {\n printBanner(server, 'preview', server.config.root);\n },\n };\n}\n\nexport type { Plugin } from 'vite';"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bini-env",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Universal environment variable loader and Vite plugin for Bini.js — powered by Hono, works across Node.js, Bun, Deno, Vercel Edge, Netlify Edge, and Cloudflare Workers",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -69,10 +69,10 @@
|
|
|
69
69
|
}
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"@types/node": "
|
|
72
|
+
"@types/node": "26.1.2",
|
|
73
73
|
"hono": "^4.8.4",
|
|
74
74
|
"tsup": "^8.5.1",
|
|
75
|
-
"typescript": "^5.
|
|
75
|
+
"typescript": "^5.8.3",
|
|
76
76
|
"vite": "^8.0.8"
|
|
77
77
|
},
|
|
78
78
|
"engines": {
|