bini-env 1.1.0 → 1.1.1
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 +219 -173
- package/dist/index.d.mts +21 -19
- package/dist/index.d.ts +21 -19
- package/dist/index.js +49 -178
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +50 -176
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,43 +3,31 @@
|
|
|
3
3
|

|
|
4
4
|

|
|
5
5
|

|
|
6
|
-

|
|
7
|
+

|
|
8
8
|

|
|
9
9
|

|
|
10
10
|
|
|
11
|
-
**Zero-config environment variable system + Vite plugin for Bini.js**
|
|
12
|
-
Powered by [Hono](https://hono.dev) — reads env vars from the 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.
|
|
11
|
+
**Zero-config environment variable system + Vite plugin for Bini.js**
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
## ⚠️ Before You Use This
|
|
17
|
-
|
|
18
|
-
This library **does NOT magically make env vars safe**.
|
|
19
|
-
|
|
20
|
-
- Anything exposed to the client (`import.meta.env`) is **public**.
|
|
21
|
-
- Only server-side code (`getEnv`, `requireEnv`) can safely access secrets.
|
|
22
|
-
- Misconfigured prefixes = **data leak**.
|
|
23
|
-
|
|
24
|
-
If you don't understand this, stop and fix that first.
|
|
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.
|
|
25
14
|
|
|
26
15
|
---
|
|
27
16
|
|
|
28
|
-
##
|
|
17
|
+
## Features
|
|
29
18
|
|
|
30
|
-
- **Hono-native
|
|
31
|
-
- **Universal runtime
|
|
32
|
-
- **Zero dotenv** — no `.env`
|
|
33
|
-
- **
|
|
34
|
-
- **
|
|
35
|
-
- **Prefix control** —
|
|
36
|
-
- **Tree-shakeable** —
|
|
37
|
-
- **Typed** — full TypeScript support with exported `HonoContext`
|
|
38
|
-
- **Fast** — zero overhead; no file reads in production
|
|
19
|
+
- **Hono-native** — `getEnv(c, key)` / `requireEnv(c, key)` read directly from the Hono request context
|
|
20
|
+
- **Universal runtime** — CF Workers, Node, Bun, Deno, Vercel Edge, Netlify Edge — Hono's adapter handles all of it
|
|
21
|
+
- **Zero dotenv** — no `.env` parsing at runtime; vars come from the host platform
|
|
22
|
+
- **Vite-native dev** — `.env` loading, file watching, and server restarts are handled by Vite itself
|
|
23
|
+
- **Dev banner** — prints `ß Bini.js (dev/preview)` and lists detected `.env` files on server start
|
|
24
|
+
- **Prefix control** — `BINI_` and `VITE_` included out of the box, extend with your own
|
|
25
|
+
- **Tree-shakeable** — nothing lands in the client bundle that shouldn't
|
|
26
|
+
- **Typed** — full TypeScript support with an exported `HonoContext` type
|
|
39
27
|
|
|
40
28
|
---
|
|
41
29
|
|
|
42
|
-
##
|
|
30
|
+
## Installation
|
|
43
31
|
|
|
44
32
|
```bash
|
|
45
33
|
pnpm add bini-env hono
|
|
@@ -53,7 +41,9 @@ yarn add bini-env hono
|
|
|
53
41
|
|
|
54
42
|
---
|
|
55
43
|
|
|
56
|
-
##
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
**1. Register the Vite plugin**
|
|
57
47
|
|
|
58
48
|
```ts
|
|
59
49
|
// vite.config.ts
|
|
@@ -65,18 +55,34 @@ export default defineConfig({
|
|
|
65
55
|
})
|
|
66
56
|
```
|
|
67
57
|
|
|
58
|
+
**2. Read env vars in your Hono handlers**
|
|
59
|
+
|
|
68
60
|
```ts
|
|
69
|
-
// src/app/api/
|
|
61
|
+
// src/app/api/hello.ts
|
|
70
62
|
import { Hono } from 'hono'
|
|
71
63
|
import { getEnv, requireEnv } from 'bini-env'
|
|
72
64
|
|
|
73
65
|
const app = new Hono()
|
|
74
66
|
|
|
75
|
-
app.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
67
|
+
app.post('/hello', async (c) => {
|
|
68
|
+
try {
|
|
69
|
+
const ctx = c as any
|
|
70
|
+
|
|
71
|
+
// requireEnv throws if the var is missing — fail fast on required config
|
|
72
|
+
const apiKey = requireEnv(ctx, 'MY_API_KEY')
|
|
73
|
+
|
|
74
|
+
// getEnv returns undefined if missing — use ?? to provide a default
|
|
75
|
+
const appName = getEnv(ctx, 'APP_NAME') ?? 'World'
|
|
76
|
+
const timeout = parseInt(getEnv(ctx, 'TIMEOUT_MS') ?? '5000')
|
|
77
|
+
|
|
78
|
+
return c.json({ message: `Hello, ${appName}!` })
|
|
79
|
+
|
|
80
|
+
} catch (error: any) {
|
|
81
|
+
if (error.message?.includes('[bini-env] Missing required')) {
|
|
82
|
+
return c.json({ error: error.message }, 500)
|
|
83
|
+
}
|
|
84
|
+
return c.json({ error: 'Something went wrong.' }, 500)
|
|
85
|
+
}
|
|
80
86
|
})
|
|
81
87
|
|
|
82
88
|
export default app
|
|
@@ -84,155 +90,213 @@ export default app
|
|
|
84
90
|
|
|
85
91
|
---
|
|
86
92
|
|
|
87
|
-
##
|
|
88
|
-
|
|
89
|
-
> ✅ Both `BINI_` and `VITE_` prefixes work out of the box — no extra config needed.
|
|
93
|
+
## Usage Pattern
|
|
90
94
|
|
|
91
|
-
|
|
95
|
+
**Always pass `c` explicitly.** Cast it once at the top of the handler, then use `ctx` throughout.
|
|
92
96
|
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
```ts
|
|
98
|
+
app.post('/example', async (c) => {
|
|
99
|
+
try {
|
|
100
|
+
const ctx = c as any
|
|
101
|
+
|
|
102
|
+
// Required vars — handler throws immediately if missing
|
|
103
|
+
const dbUrl = requireEnv(ctx, 'DATABASE_URL')
|
|
104
|
+
const apiKey = requireEnv(ctx, 'STRIPE_SECRET_KEY')
|
|
105
|
+
|
|
106
|
+
// Optional vars — fall back to sensible defaults
|
|
107
|
+
const model = getEnv(ctx, 'AI_MODEL') ?? 'gpt-4o'
|
|
108
|
+
const region = getEnv(ctx, 'AWS_REGION') ?? 'us-east-1'
|
|
109
|
+
const maxRetries = parseInt(getEnv(ctx, 'MAX_RETRIES') ?? '3')
|
|
110
|
+
const debug = getEnv(ctx, 'DEBUG_MODE') === 'true'
|
|
111
|
+
|
|
112
|
+
// ... rest of handler
|
|
113
|
+
|
|
114
|
+
} catch (error: any) {
|
|
115
|
+
if (error.message?.includes('[bini-env] Missing required')) {
|
|
116
|
+
return c.json({ error: error.message }, 500)
|
|
117
|
+
}
|
|
118
|
+
return c.json({ error: 'Something went wrong.' }, 500)
|
|
119
|
+
}
|
|
120
|
+
})
|
|
96
121
|
```
|
|
97
122
|
|
|
123
|
+
**The pattern in three steps:**
|
|
124
|
+
|
|
125
|
+
1. `const ctx = c as any` — once, at the top of the handler
|
|
126
|
+
2. `requireEnv(ctx, 'KEY')` — for vars the handler cannot run without
|
|
127
|
+
3. `getEnv(ctx, 'KEY') ?? 'default'` — for optional vars with sensible defaults
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Environment Prefixes
|
|
132
|
+
|
|
133
|
+
### `BINI_` — server-side vars
|
|
134
|
+
|
|
135
|
+
`BINI_` is bini-env's own prefix. Variables are **not** exposed to `import.meta.env` by default, making it the right choice for server-side config and secrets.
|
|
136
|
+
|
|
137
|
+
To additionally expose a `BINI_` var to the client, add it to `envPrefix` explicitly:
|
|
138
|
+
|
|
98
139
|
```ts
|
|
99
|
-
|
|
140
|
+
biniEnv({ envPrefix: ['BINI_', 'VITE_', 'MY_PUBLIC_'] })
|
|
100
141
|
```
|
|
101
142
|
|
|
102
|
-
|
|
143
|
+
### `VITE_` — public client vars
|
|
103
144
|
|
|
104
|
-
|
|
145
|
+
`VITE_` is Vite's built-in prefix. Any var starting with `VITE_` is bundled into your client-side JavaScript and is publicly visible.
|
|
105
146
|
|
|
106
147
|
```env
|
|
107
|
-
|
|
108
|
-
|
|
148
|
+
VITE_ANALYTICS_ID=UA-XXXX # bundled into client JS — public
|
|
149
|
+
VITE_API_URL=https://api.example.com # bundled into client JS — public
|
|
109
150
|
```
|
|
110
151
|
|
|
111
152
|
```ts
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
const pass = requireEnv(ctx, 'SMTP_PASS') // throws if missing
|
|
115
|
-
const db = getEnv(ctx, 'DATABASE_URL') // returns undefined if missing
|
|
153
|
+
// accessible anywhere, including the browser
|
|
154
|
+
import.meta.env.VITE_ANALYTICS_ID
|
|
116
155
|
```
|
|
117
156
|
|
|
118
|
-
|
|
157
|
+
### Choosing the right prefix
|
|
119
158
|
|
|
120
|
-
|
|
159
|
+
```env
|
|
160
|
+
# ✓ use VITE_ for anything the browser needs
|
|
161
|
+
VITE_API_URL=https://api.example.com
|
|
121
162
|
|
|
122
|
-
|
|
163
|
+
# ✓ use BINI_ for server-side config
|
|
164
|
+
BINI_FEATURE_FLAG=true
|
|
123
165
|
|
|
124
|
-
|
|
166
|
+
# ✓ no prefix for secrets — read via getEnv(ctx, key) only
|
|
167
|
+
DATABASE_URL=postgres://...
|
|
168
|
+
STRIPE_SECRET_KEY=sk_live_...
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
> Avoid defining the same variable under two different prefixes — your code will silently read whichever one it finds first.
|
|
125
172
|
|
|
126
|
-
|
|
127
|
-
| -------------------- | ------------- | ----------------------------------- | ---------------------------- |
|
|
128
|
-
| Node.js | Node | System env / platform dashboard | `process.env` ✅ |
|
|
129
|
-
| Bun | Bun | System env / platform dashboard | `process.env` ✅ |
|
|
130
|
-
| Vercel Edge | V8 isolate | Project settings → Environment Vars | `process.env` ✅ |
|
|
131
|
-
| Netlify Edge | Deno | Site settings → Environment Vars | `Deno.env.get()` ✅ |
|
|
132
|
-
| Cloudflare Workers | V8 isolate | `wrangler.toml [vars]` / dashboard | CF bindings via `c.env` ✅ |
|
|
133
|
-
| Deno Deploy | Deno | Project settings → Environment Vars | `Deno.env.get()` ✅ |
|
|
173
|
+
### Prefix summary
|
|
134
174
|
|
|
135
|
-
|
|
175
|
+
| Prefix | Exposed to browser | Use for |
|
|
176
|
+
|--------|--------------------|---------|
|
|
177
|
+
| `BINI_` | No (unless added to `envPrefix`) | Server-side config |
|
|
178
|
+
| `VITE_` | Yes, always | Public client config |
|
|
179
|
+
| No prefix | No | Secrets — server only |
|
|
136
180
|
|
|
137
181
|
---
|
|
138
182
|
|
|
139
|
-
##
|
|
183
|
+
## Platform Support
|
|
140
184
|
|
|
141
|
-
`getEnv(c
|
|
185
|
+
`getEnv` and `requireEnv` delegate to Hono's `env(c)` adapter, which reads from the correct source on every supported platform automatically. Your code never changes regardless of where it deploys.
|
|
142
186
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
187
|
+
| Platform | Runtime | Env source | How Hono reads it |
|
|
188
|
+
|----------|---------|------------|-------------------|
|
|
189
|
+
| Node.js | Node | System env / platform dashboard | `process.env` ✅ |
|
|
190
|
+
| Bun | Bun | System env / platform dashboard | `process.env` ✅ |
|
|
191
|
+
| Vercel Edge | V8 isolate | Project settings → Env Vars | `process.env` ✅ |
|
|
192
|
+
| Netlify Edge | Deno | Site settings → Env Vars | `Deno.env.get()` ✅ |
|
|
193
|
+
| Cloudflare Workers | V8 isolate | `wrangler.toml` / dashboard | CF bindings via `c.env` ✅ |
|
|
194
|
+
| Deno Deploy | Deno | Project settings → Env Vars | `Deno.env.get()` ✅ |
|
|
146
195
|
|
|
147
|
-
`
|
|
196
|
+
> **Cloudflare note:** Secrets set via `wrangler secret put` are only available inside the fetch handler via `c.env` — this is a Workers architecture constraint. `getEnv(ctx, key)` reads them correctly as long as you pass `c`.
|
|
148
197
|
|
|
149
198
|
---
|
|
150
199
|
|
|
151
|
-
##
|
|
200
|
+
## How It Works
|
|
152
201
|
|
|
153
|
-
The
|
|
202
|
+
### The plugin — `biniEnv()`
|
|
154
203
|
|
|
155
|
-
|
|
156
|
-
|
|
204
|
+
Does two things: tells Vite which env prefixes to expose to `import.meta.env`, and prints the `ß Bini.js` banner with detected `.env` files when the dev or preview server starts.
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
// what biniEnv() does internally
|
|
208
|
+
config() {
|
|
209
|
+
return { envPrefix: ['BINI_', 'VITE_', ...yourExtras] }
|
|
210
|
+
}
|
|
157
211
|
```
|
|
158
212
|
|
|
159
|
-
|
|
160
|
-
- Creating a new `.env`, `.env.local`, `.env.production`, etc.
|
|
161
|
-
- Editing any existing `.env*` file
|
|
213
|
+
On server start you will see:
|
|
162
214
|
|
|
163
|
-
|
|
215
|
+
```
|
|
216
|
+
ß Bini.js (dev)
|
|
217
|
+
➜ Environments: .env.local, .env
|
|
218
|
+
➜ Local: http://localhost:3000/
|
|
219
|
+
➜ Network: http://192.168.1.7:3000/
|
|
220
|
+
```
|
|
164
221
|
|
|
165
|
-
|
|
222
|
+
Vite handles everything else 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. bini-env does not reimplement any of that.
|
|
166
223
|
|
|
167
|
-
|
|
224
|
+
### The env functions — `getEnv` / `requireEnv`
|
|
168
225
|
|
|
169
|
-
|
|
170
|
-
biniEnv({
|
|
171
|
-
enabled : true,
|
|
172
|
-
clearViteHeader: true,
|
|
173
|
-
logo : 'ß',
|
|
174
|
-
envPrefix : ['BINI_', 'VITE_'],
|
|
175
|
-
loadInPreview : true,
|
|
176
|
-
})
|
|
177
|
-
```
|
|
226
|
+
Both functions read exclusively from `env(c)` via `hono/adapter` — the Hono request context. There are no `process.env` fallbacks. Every read is request-scoped and resolved by Hono's adapter for the current platform.
|
|
178
227
|
|
|
179
|
-
|
|
228
|
+
`dotenv` is never used. In production, vars are set in your hosting platform's environment config.
|
|
180
229
|
|
|
181
230
|
---
|
|
182
231
|
|
|
183
|
-
##
|
|
232
|
+
## API Reference
|
|
184
233
|
|
|
185
234
|
### `getEnv(c, key)`
|
|
186
235
|
|
|
187
|
-
Returns `string | undefined`. Reads from Hono
|
|
236
|
+
Returns `string | undefined`. Reads from the Hono request context.
|
|
188
237
|
|
|
189
238
|
```ts
|
|
190
|
-
|
|
191
|
-
const ctx = c as any
|
|
192
|
-
const debug = getEnv(ctx, 'DEBUG_MODE')
|
|
193
|
-
```
|
|
239
|
+
app.get('/config', async (c) => {
|
|
240
|
+
const ctx = c as any
|
|
194
241
|
|
|
195
|
-
|
|
242
|
+
const region = getEnv(ctx, 'AWS_REGION') ?? 'us-east-1'
|
|
243
|
+
const logLevel = getEnv(ctx, 'LOG_LEVEL') ?? 'info'
|
|
244
|
+
const debug = getEnv(ctx, 'DEBUG_MODE') === 'true'
|
|
196
245
|
|
|
197
|
-
|
|
198
|
-
|
|
246
|
+
return c.json({ region, logLevel, debug })
|
|
247
|
+
})
|
|
199
248
|
```
|
|
200
249
|
|
|
201
250
|
### `requireEnv(c, key)`
|
|
202
251
|
|
|
203
|
-
|
|
252
|
+
Returns `string`. Throws immediately if the variable is missing or empty. Logs a descriptive error to the terminal on failure.
|
|
204
253
|
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
254
|
+
```ts
|
|
255
|
+
app.post('/send-email', async (c) => {
|
|
256
|
+
try {
|
|
257
|
+
const ctx = c as any
|
|
258
|
+
|
|
259
|
+
const smtpHost = requireEnv(ctx, 'SMTP_HOST')
|
|
260
|
+
const smtpPass = requireEnv(ctx, 'SMTP_PASS')
|
|
261
|
+
const smtpPort = parseInt(getEnv(ctx, 'SMTP_PORT') ?? '587')
|
|
262
|
+
|
|
263
|
+
// ... send email
|
|
264
|
+
|
|
265
|
+
return c.json({ sent: true })
|
|
266
|
+
|
|
267
|
+
} catch (error: any) {
|
|
268
|
+
if (error.message?.includes('[bini-env] Missing required')) {
|
|
269
|
+
return c.json({ error: error.message }, 500)
|
|
270
|
+
}
|
|
271
|
+
return c.json({ error: 'Failed to send email.' }, 500)
|
|
272
|
+
}
|
|
273
|
+
})
|
|
209
274
|
```
|
|
210
275
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
276
|
+
On failure, the terminal will show:
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
[bini-env] error Missing required environment variable: "SMTP_HOST"
|
|
280
|
+
-> Set it in your platform's env config or hosting dashboard.
|
|
215
281
|
```
|
|
216
282
|
|
|
217
|
-
### `
|
|
283
|
+
### `biniEnv(options?)`
|
|
218
284
|
|
|
219
|
-
|
|
285
|
+
Vite plugin. Registers `BINI_` and `VITE_` as env prefixes and optionally adds more.
|
|
220
286
|
|
|
221
287
|
```ts
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
return next()
|
|
226
|
-
})
|
|
288
|
+
biniEnv()
|
|
289
|
+
// or with extra prefixes
|
|
290
|
+
biniEnv({ envPrefix: ['MY_PUBLIC_'] })
|
|
227
291
|
```
|
|
228
292
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
293
|
+
| Option | Type | Default | Description |
|
|
294
|
+
|--------|------|---------|-------------|
|
|
295
|
+
| `envPrefix` | `string \| string[]` | `[]` | Extra prefixes to expose to `import.meta.env`, in addition to `BINI_` and `VITE_` |
|
|
232
296
|
|
|
233
297
|
### `biniLogger`
|
|
234
298
|
|
|
235
|
-
|
|
299
|
+
Vite-style terminal logger. Use it in your own Bini.js plugins or server-side code.
|
|
236
300
|
|
|
237
301
|
```ts
|
|
238
302
|
import { biniLogger } from 'bini-env'
|
|
@@ -244,102 +308,84 @@ biniLogger.error('Something broke', error)
|
|
|
244
308
|
|
|
245
309
|
### `HonoContext`
|
|
246
310
|
|
|
247
|
-
Exported
|
|
311
|
+
Exported type (`Context` from Hono). Use it to type helper functions that group env reads, so you only cast `c as any` once per entry point.
|
|
248
312
|
|
|
249
313
|
```ts
|
|
250
314
|
import type { HonoContext } from 'bini-env'
|
|
251
315
|
|
|
252
|
-
function
|
|
253
|
-
|
|
316
|
+
function readDbConfig(c: HonoContext) {
|
|
317
|
+
const ctx = c as any
|
|
318
|
+
return {
|
|
319
|
+
url: requireEnv(ctx, 'DATABASE_URL'),
|
|
320
|
+
poolSize: parseInt(getEnv(ctx, 'DB_POOL_SIZE') ?? '10'),
|
|
321
|
+
ssl: getEnv(ctx, 'DB_SSL') !== 'false',
|
|
322
|
+
}
|
|
254
323
|
}
|
|
255
324
|
```
|
|
256
325
|
|
|
257
326
|
---
|
|
258
327
|
|
|
259
|
-
##
|
|
328
|
+
## Performance
|
|
260
329
|
|
|
261
|
-
|
|
330
|
+
| Metric | Dev | Prod |
|
|
331
|
+
|--------|-----|------|
|
|
332
|
+
| File reads | 0 | 0 |
|
|
333
|
+
| Runtime cost | ~0ms | 0 |
|
|
334
|
+
| Bundle impact | Minimal | Tree-shaken |
|
|
262
335
|
|
|
263
|
-
|
|
264
|
-
2. `.env.[mode].local`
|
|
265
|
-
3. `.env.[mode]`
|
|
266
|
-
4. `.env`
|
|
267
|
-
|
|
268
|
-
In production, none of these are read. Variables must come from your platform.
|
|
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.
|
|
269
337
|
|
|
270
338
|
---
|
|
271
339
|
|
|
272
|
-
##
|
|
340
|
+
## Troubleshooting
|
|
273
341
|
|
|
274
|
-
|
|
275
|
-
| ------------- | -------- | ----------- |
|
|
276
|
-
| File Reads | 0 | 0 |
|
|
277
|
-
| Runtime Cost | ~0ms | 0 |
|
|
278
|
-
| Bundle Impact | Minimal | Tree-shaken |
|
|
342
|
+
### "Env var is undefined in production"
|
|
279
343
|
|
|
280
|
-
|
|
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.).
|
|
281
345
|
|
|
282
|
-
|
|
346
|
+
### "Works in dev, undefined in prod"
|
|
283
347
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
### "Env is undefined in production"
|
|
287
|
-
You relied on a `.env` file in production. Set vars in your hosting dashboard — bini-env does not read `.env` files at runtime.
|
|
288
|
-
|
|
289
|
-
### "Works in dev, broken in prod"
|
|
290
|
-
Same as above. Production vars come from the host, not from files.
|
|
291
|
-
|
|
292
|
-
### "Secrets leaked"
|
|
293
|
-
You exposed them via `BINI_` or `VITE_` prefix. Those are public. Use unprefixed vars for secrets and only read them server-side via `getEnv(c, key)`.
|
|
348
|
+
Same as above. Local dev works because Vite loads `.env` files automatically. Production requires platform-level configuration.
|
|
294
349
|
|
|
295
350
|
### "Cloudflare secret not found"
|
|
296
|
-
|
|
351
|
+
|
|
352
|
+
Secrets set via `wrangler secret put` are only available via `c.env` inside a handler — which is exactly what `getEnv(ctx, key)` reads. Ensure you are passing `c` to the function.
|
|
297
353
|
|
|
298
354
|
### "TypeScript error: Context not assignable to HonoContext"
|
|
299
|
-
|
|
355
|
+
|
|
356
|
+
Hono 4.12+ added a symbol to `HonoRequest` that can break structural assignability in strict TypeScript projects. Cast once per handler:
|
|
300
357
|
|
|
301
358
|
```ts
|
|
302
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
303
359
|
const ctx = c as any
|
|
304
|
-
const key = requireEnv(ctx, 'MY_KEY')
|
|
305
360
|
```
|
|
306
361
|
|
|
307
362
|
### "Types not found"
|
|
308
|
-
|
|
363
|
+
|
|
364
|
+
Add to your `tsconfig.json` or entry file:
|
|
365
|
+
|
|
309
366
|
```ts
|
|
310
367
|
/// <reference types="vite/client" />
|
|
311
368
|
```
|
|
312
369
|
|
|
313
370
|
---
|
|
314
371
|
|
|
315
|
-
##
|
|
316
|
-
|
|
317
|
-
This library is intentionally simple.
|
|
318
|
-
|
|
319
|
-
If you need:
|
|
320
|
-
- Secret rotation
|
|
321
|
-
- Encrypted envs
|
|
322
|
-
- Runtime validation schemas
|
|
372
|
+
## Compatibility
|
|
323
373
|
|
|
324
|
-
|
|
374
|
+
| Tool | Version | Notes |
|
|
375
|
+
|------|---------|-------|
|
|
376
|
+
| Vite | 8.x | `envPrefix` hook is fully compatible; empty prefix array is never passed |
|
|
377
|
+
| Hono | 4.x | `hono/adapter` `env()` is stable across all 4.x releases |
|
|
378
|
+
| TypeScript | 5.x | Full type support via exported `HonoContext` |
|
|
379
|
+
| Node.js | ≥ 20.19 | Minimum required version |
|
|
325
380
|
|
|
326
381
|
---
|
|
327
382
|
|
|
328
|
-
##
|
|
383
|
+
## Contributing
|
|
329
384
|
|
|
330
|
-
PRs welcome
|
|
331
|
-
- No bloat
|
|
332
|
-
- No magic
|
|
333
|
-
- No runtime cost
|
|
334
|
-
|
|
335
|
-
If it slows startup or increases bundle size, it's getting rejected.
|
|
385
|
+
PRs are welcome. The goal of this library is to stay minimal and runtime-cost-free. Contributions that add unnecessary complexity, increase bundle size, or introduce startup overhead will not be accepted.
|
|
336
386
|
|
|
337
387
|
---
|
|
338
388
|
|
|
339
|
-
##
|
|
340
|
-
|
|
341
|
-
MIT © Bini.js Team
|
|
342
|
-
|
|
343
|
-
---
|
|
389
|
+
## License
|
|
344
390
|
|
|
345
|
-
|
|
391
|
+
MIT © Bini.js Team
|
package/dist/index.d.mts
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
|
+
import { Context } from 'hono';
|
|
1
2
|
import { Plugin } from 'vite';
|
|
2
3
|
export { Plugin } from 'vite';
|
|
3
|
-
export { Context } from 'hono';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
+
type HonoContext = Context;
|
|
9
21
|
interface BiniEnvPluginOptions {
|
|
10
|
-
|
|
11
|
-
readonly clearViteHeader?: boolean;
|
|
12
|
-
readonly logo?: string;
|
|
22
|
+
/** Extra prefixes to expose to import.meta.env, in addition to BINI_ and VITE_. */
|
|
13
23
|
readonly envPrefix?: string | string[];
|
|
14
|
-
readonly loadInPreview?: boolean;
|
|
15
|
-
}
|
|
16
|
-
interface DetectedEnvFile {
|
|
17
|
-
readonly name: string;
|
|
18
|
-
readonly path: string;
|
|
19
24
|
}
|
|
20
25
|
declare const biniLogger: {
|
|
21
26
|
readonly info: (msg: string) => void;
|
|
22
27
|
readonly warn: (msg: string) => void;
|
|
23
28
|
readonly error: (msg: string, err?: unknown) => void;
|
|
24
29
|
};
|
|
25
|
-
declare function
|
|
26
|
-
declare function
|
|
27
|
-
declare function getEnv(c: HonoContext | string, key?: string): string | undefined;
|
|
28
|
-
declare function requireEnv(c: HonoContext | string, key?: string): string;
|
|
29
|
-
declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
|
|
30
|
+
declare function getEnv(c: HonoContext, key: string): string | undefined;
|
|
31
|
+
declare function requireEnv(c: HonoContext, key: string): string;
|
|
30
32
|
declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
|
|
31
33
|
|
|
32
|
-
export { type BiniEnvPluginOptions, type
|
|
34
|
+
export { type BiniEnvPluginOptions, type HonoContext, biniEnv, biniLogger, getEnv, requireEnv };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
|
+
import { Context } from 'hono';
|
|
1
2
|
import { Plugin } from 'vite';
|
|
2
3
|
export { Plugin } from 'vite';
|
|
3
|
-
export { Context } from 'hono';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
+
type HonoContext = Context;
|
|
9
21
|
interface BiniEnvPluginOptions {
|
|
10
|
-
|
|
11
|
-
readonly clearViteHeader?: boolean;
|
|
12
|
-
readonly logo?: string;
|
|
22
|
+
/** Extra prefixes to expose to import.meta.env, in addition to BINI_ and VITE_. */
|
|
13
23
|
readonly envPrefix?: string | string[];
|
|
14
|
-
readonly loadInPreview?: boolean;
|
|
15
|
-
}
|
|
16
|
-
interface DetectedEnvFile {
|
|
17
|
-
readonly name: string;
|
|
18
|
-
readonly path: string;
|
|
19
24
|
}
|
|
20
25
|
declare const biniLogger: {
|
|
21
26
|
readonly info: (msg: string) => void;
|
|
22
27
|
readonly warn: (msg: string) => void;
|
|
23
28
|
readonly error: (msg: string, err?: unknown) => void;
|
|
24
29
|
};
|
|
25
|
-
declare function
|
|
26
|
-
declare function
|
|
27
|
-
declare function getEnv(c: HonoContext | string, key?: string): string | undefined;
|
|
28
|
-
declare function requireEnv(c: HonoContext | string, key?: string): string;
|
|
29
|
-
declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
|
|
30
|
+
declare function getEnv(c: HonoContext, key: string): string | undefined;
|
|
31
|
+
declare function requireEnv(c: HonoContext, key: string): string;
|
|
30
32
|
declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
|
|
31
33
|
|
|
32
|
-
export { type BiniEnvPluginOptions, type
|
|
34
|
+
export { type BiniEnvPluginOptions, type HonoContext, biniEnv, biniLogger, getEnv, requireEnv };
|