bini-env 1.0.10 → 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 +262 -154
- package/dist/index.d.mts +21 -16
- package/dist/index.d.ts +21 -16
- package/dist/index.js +51 -268
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +52 -266
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -7
package/README.md
CHANGED
|
@@ -3,281 +3,389 @@
|
|
|
3
3
|

|
|
4
4
|

|
|
5
5
|

|
|
6
|
-

|
|
7
|
+

|
|
7
8
|

|
|
8
9
|

|
|
9
10
|
|
|
10
|
-
**Zero-config environment variable system + Vite plugin for Bini.js**
|
|
11
|
-
Loads `.env` in development, uses host-provided variables in production, and works across Node.js, Bun, Deno, Vercel Edge, Netlify Edge, and Cloudflare Workers — without leaking secrets or adding runtime cost.
|
|
11
|
+
**Zero-config environment variable system + Vite plugin for Bini.js**
|
|
12
12
|
|
|
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.
|
|
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.
|
|
24
14
|
|
|
25
15
|
---
|
|
26
16
|
|
|
27
|
-
##
|
|
17
|
+
## Features
|
|
28
18
|
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
31
|
-
- **
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
34
|
-
- **Prefix control** —
|
|
35
|
-
- **Tree-shakeable** —
|
|
36
|
-
- **Typed** — full TypeScript support
|
|
37
|
-
- **Fast** — single load in dev, zero overhead in prod
|
|
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
|
|
38
27
|
|
|
39
28
|
---
|
|
40
29
|
|
|
41
|
-
##
|
|
30
|
+
## Installation
|
|
42
31
|
|
|
43
32
|
```bash
|
|
44
|
-
pnpm add bini-env
|
|
33
|
+
pnpm add bini-env hono
|
|
45
34
|
# or
|
|
46
|
-
npm install bini-env
|
|
35
|
+
npm install bini-env hono
|
|
47
36
|
# or
|
|
48
|
-
yarn add bini-env
|
|
37
|
+
yarn add bini-env hono
|
|
49
38
|
```
|
|
50
39
|
|
|
40
|
+
> `hono` is a required peer dependency.
|
|
41
|
+
|
|
51
42
|
---
|
|
52
43
|
|
|
53
|
-
##
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
**1. Register the Vite plugin**
|
|
54
47
|
|
|
55
48
|
```ts
|
|
56
49
|
// vite.config.ts
|
|
57
|
-
import { defineConfig } from 'vite'
|
|
58
|
-
import { biniEnv } from 'bini-env'
|
|
50
|
+
import { defineConfig } from 'vite'
|
|
51
|
+
import { biniEnv } from 'bini-env'
|
|
59
52
|
|
|
60
53
|
export default defineConfig({
|
|
61
54
|
plugins: [biniEnv()]
|
|
62
|
-
})
|
|
55
|
+
})
|
|
63
56
|
```
|
|
64
57
|
|
|
65
|
-
|
|
58
|
+
**2. Read env vars in your Hono handlers**
|
|
66
59
|
|
|
67
|
-
|
|
60
|
+
```ts
|
|
61
|
+
// src/app/api/hello.ts
|
|
62
|
+
import { Hono } from 'hono'
|
|
63
|
+
import { getEnv, requireEnv } from 'bini-env'
|
|
68
64
|
|
|
69
|
-
|
|
65
|
+
const app = new Hono()
|
|
70
66
|
|
|
71
|
-
|
|
67
|
+
app.post('/hello', async (c) => {
|
|
68
|
+
try {
|
|
69
|
+
const ctx = c as any
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
// requireEnv throws if the var is missing — fail fast on required config
|
|
72
|
+
const apiKey = requireEnv(ctx, 'MY_API_KEY')
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
export default app
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Usage Pattern
|
|
94
|
+
|
|
95
|
+
**Always pass `c` explicitly.** Cast it once at the top of the handler, then use `ctx` throughout.
|
|
96
|
+
|
|
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
|
+
})
|
|
78
121
|
```
|
|
79
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
|
+
|
|
80
139
|
```ts
|
|
81
|
-
|
|
140
|
+
biniEnv({ envPrefix: ['BINI_', 'VITE_', 'MY_PUBLIC_'] })
|
|
82
141
|
```
|
|
83
142
|
|
|
84
|
-
|
|
143
|
+
### `VITE_` — public client vars
|
|
85
144
|
|
|
86
|
-
|
|
145
|
+
`VITE_` is Vite's built-in prefix. Any var starting with `VITE_` is bundled into your client-side JavaScript and is publicly visible.
|
|
87
146
|
|
|
88
147
|
```env
|
|
89
|
-
|
|
90
|
-
|
|
148
|
+
VITE_ANALYTICS_ID=UA-XXXX # bundled into client JS — public
|
|
149
|
+
VITE_API_URL=https://api.example.com # bundled into client JS — public
|
|
91
150
|
```
|
|
92
151
|
|
|
93
152
|
```ts
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
const db = getEnv('DATABASE_URL'); // returns undefined if missing
|
|
153
|
+
// accessible anywhere, including the browser
|
|
154
|
+
import.meta.env.VITE_ANALYTICS_ID
|
|
97
155
|
```
|
|
98
156
|
|
|
99
|
-
|
|
157
|
+
### Choosing the right prefix
|
|
100
158
|
|
|
101
|
-
|
|
159
|
+
```env
|
|
160
|
+
# ✓ use VITE_ for anything the browser needs
|
|
161
|
+
VITE_API_URL=https://api.example.com
|
|
102
162
|
|
|
103
|
-
|
|
163
|
+
# ✓ use BINI_ for server-side config
|
|
164
|
+
BINI_FEATURE_FLAG=true
|
|
104
165
|
|
|
105
|
-
|
|
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.
|
|
106
172
|
|
|
107
|
-
|
|
108
|
-
| ------------------ | ------------- | ------------------------------------- | ----------------------- |
|
|
109
|
-
| Node.js | Node | `.env` file / system env | `process.env` ✅ |
|
|
110
|
-
| Bun | Bun | `.env` file / system env | `process.env` ✅ |
|
|
111
|
-
| Vercel Edge | V8 isolate | Project settings → Environment Vars | `process.env` ✅ |
|
|
112
|
-
| Netlify Edge | Deno | Site settings → Environment Vars | `Deno.env.get()` ✅ |
|
|
113
|
-
| Cloudflare Workers | V8 isolate | `wrangler.toml [vars]` / dashboard | `process.env` ✅ |
|
|
114
|
-
| Deno Deploy | Deno | Project settings → Environment Vars | `Deno.env.get()` ✅ |
|
|
173
|
+
### Prefix summary
|
|
115
174
|
|
|
116
|
-
|
|
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 |
|
|
117
180
|
|
|
118
181
|
---
|
|
119
182
|
|
|
120
|
-
##
|
|
183
|
+
## Platform Support
|
|
121
184
|
|
|
122
|
-
|
|
123
|
-
| ---------------- | ------------------------------------------------- |
|
|
124
|
-
| Dev (`vite dev`) | Loads `.env` once via dynamic dotenv |
|
|
125
|
-
| Preview | Same as dev |
|
|
126
|
-
| Production | Uses `process.env` / host injection only |
|
|
127
|
-
| Deno / Netlify Edge | Uses native `Deno.env` |
|
|
128
|
-
| Vercel / Cloudflare Edge | Uses `process.env` injected by the host |
|
|
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.
|
|
129
186
|
|
|
130
|
-
|
|
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()` ✅ |
|
|
195
|
+
|
|
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`.
|
|
131
197
|
|
|
132
198
|
---
|
|
133
199
|
|
|
134
|
-
##
|
|
200
|
+
## How It Works
|
|
201
|
+
|
|
202
|
+
### The plugin — `biniEnv()`
|
|
135
203
|
|
|
136
|
-
|
|
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.
|
|
137
205
|
|
|
206
|
+
```ts
|
|
207
|
+
// what biniEnv() does internally
|
|
208
|
+
config() {
|
|
209
|
+
return { envPrefix: ['BINI_', 'VITE_', ...yourExtras] }
|
|
210
|
+
}
|
|
138
211
|
```
|
|
139
|
-
|
|
212
|
+
|
|
213
|
+
On server start you will see:
|
|
214
|
+
|
|
140
215
|
```
|
|
216
|
+
ß Bini.js (dev)
|
|
217
|
+
➜ Environments: .env.local, .env
|
|
218
|
+
➜ Local: http://localhost:3000/
|
|
219
|
+
➜ Network: http://192.168.1.7:3000/
|
|
220
|
+
```
|
|
221
|
+
|
|
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.
|
|
141
223
|
|
|
142
|
-
|
|
143
|
-
- Creating a new `.env`, `.env.local`, `.env.production`, etc.
|
|
144
|
-
- Editing any existing `.env*` file
|
|
224
|
+
### The env functions — `getEnv` / `requireEnv`
|
|
145
225
|
|
|
146
|
-
|
|
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.
|
|
227
|
+
|
|
228
|
+
`dotenv` is never used. In production, vars are set in your hosting platform's environment config.
|
|
147
229
|
|
|
148
230
|
---
|
|
149
231
|
|
|
150
|
-
##
|
|
232
|
+
## API Reference
|
|
233
|
+
|
|
234
|
+
### `getEnv(c, key)`
|
|
235
|
+
|
|
236
|
+
Returns `string | undefined`. Reads from the Hono request context.
|
|
151
237
|
|
|
152
238
|
```ts
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
239
|
+
app.get('/config', async (c) => {
|
|
240
|
+
const ctx = c as any
|
|
241
|
+
|
|
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'
|
|
245
|
+
|
|
246
|
+
return c.json({ region, logLevel, debug })
|
|
247
|
+
})
|
|
160
248
|
```
|
|
161
249
|
|
|
162
|
-
|
|
250
|
+
### `requireEnv(c, key)`
|
|
163
251
|
|
|
164
|
-
|
|
252
|
+
Returns `string`. Throws immediately if the variable is missing or empty. Logs a descriptive error to the terminal on failure.
|
|
165
253
|
|
|
166
|
-
|
|
254
|
+
```ts
|
|
255
|
+
app.post('/send-email', async (c) => {
|
|
256
|
+
try {
|
|
257
|
+
const ctx = c as any
|
|
167
258
|
|
|
168
|
-
|
|
259
|
+
const smtpHost = requireEnv(ctx, 'SMTP_HOST')
|
|
260
|
+
const smtpPass = requireEnv(ctx, 'SMTP_PASS')
|
|
261
|
+
const smtpPort = parseInt(getEnv(ctx, 'SMTP_PORT') ?? '587')
|
|
169
262
|
|
|
170
|
-
|
|
263
|
+
// ... send email
|
|
171
264
|
|
|
172
|
-
|
|
173
|
-
1. `Deno.env.get(key)` — Deno / Netlify Edge
|
|
174
|
-
2. `process.env[key]` — Node, Bun, Vercel Edge, Cloudflare Workers
|
|
175
|
-
3. `import.meta.env[key]` — Vite client (prefixed variants only)
|
|
265
|
+
return c.json({ sent: true })
|
|
176
266
|
|
|
177
|
-
|
|
178
|
-
|
|
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
|
+
})
|
|
179
274
|
```
|
|
180
275
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
Same as `getEnv` but throws if missing:
|
|
276
|
+
On failure, the terminal will show:
|
|
184
277
|
|
|
185
278
|
```
|
|
186
|
-
[bini-env] Missing required environment variable: "
|
|
187
|
-
|
|
188
|
-
→ In production: set it in your hosting dashboard.
|
|
279
|
+
[bini-env] error Missing required environment variable: "SMTP_HOST"
|
|
280
|
+
-> Set it in your platform's env config or hosting dashboard.
|
|
189
281
|
```
|
|
190
282
|
|
|
191
|
-
|
|
283
|
+
### `biniEnv(options?)`
|
|
284
|
+
|
|
285
|
+
Vite plugin. Registers `BINI_` and `VITE_` as env prefixes and optionally adds more.
|
|
192
286
|
|
|
193
287
|
```ts
|
|
194
|
-
|
|
288
|
+
biniEnv()
|
|
289
|
+
// or with extra prefixes
|
|
290
|
+
biniEnv({ envPrefix: ['MY_PUBLIC_'] })
|
|
195
291
|
```
|
|
196
292
|
|
|
197
|
-
|
|
293
|
+
| Option | Type | Default | Description |
|
|
294
|
+
|--------|------|---------|-------------|
|
|
295
|
+
| `envPrefix` | `string \| string[]` | `[]` | Extra prefixes to expose to `import.meta.env`, in addition to `BINI_` and `VITE_` |
|
|
198
296
|
|
|
199
|
-
|
|
297
|
+
### `biniLogger`
|
|
200
298
|
|
|
201
|
-
|
|
299
|
+
Vite-style terminal logger. Use it in your own Bini.js plugins or server-side code.
|
|
202
300
|
|
|
203
|
-
|
|
301
|
+
```ts
|
|
302
|
+
import { biniLogger } from 'bini-env'
|
|
204
303
|
|
|
205
|
-
|
|
304
|
+
biniLogger.info('Server ready')
|
|
305
|
+
biniLogger.warn('Missing optional var')
|
|
306
|
+
biniLogger.error('Something broke', error)
|
|
307
|
+
```
|
|
206
308
|
|
|
207
|
-
|
|
208
|
-
2. `.env.[mode].local`
|
|
209
|
-
3. `.env.[mode]`
|
|
210
|
-
4. `.env`
|
|
309
|
+
### `HonoContext`
|
|
211
310
|
|
|
212
|
-
|
|
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.
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
import type { HonoContext } from 'bini-env'
|
|
315
|
+
|
|
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
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
213
325
|
|
|
214
326
|
---
|
|
215
327
|
|
|
216
|
-
##
|
|
328
|
+
## Performance
|
|
217
329
|
|
|
218
|
-
| Metric
|
|
219
|
-
|
|
220
|
-
| File
|
|
221
|
-
| Runtime
|
|
222
|
-
| Bundle
|
|
330
|
+
| Metric | Dev | Prod |
|
|
331
|
+
|--------|-----|------|
|
|
332
|
+
| File reads | 0 | 0 |
|
|
333
|
+
| Runtime cost | ~0ms | 0 |
|
|
334
|
+
| Bundle impact | Minimal | Tree-shaken |
|
|
223
335
|
|
|
224
|
-
|
|
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.
|
|
225
337
|
|
|
226
338
|
---
|
|
227
339
|
|
|
228
|
-
##
|
|
340
|
+
## Troubleshooting
|
|
229
341
|
|
|
230
|
-
### "Env is undefined"
|
|
231
|
-
You forgot the prefix (`BINI_` or `VITE_`) on a client-side var, or you're reading an unprefixed secret from `import.meta.env`.
|
|
342
|
+
### "Env var is undefined in production"
|
|
232
343
|
|
|
233
|
-
|
|
234
|
-
You relied on a `.env` file in production. Set vars in your hosting dashboard.
|
|
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.).
|
|
235
345
|
|
|
236
|
-
### "
|
|
237
|
-
You exposed them via `BINI_` or `VITE_` prefix. Those are public. Use unprefixed vars for secrets.
|
|
346
|
+
### "Works in dev, undefined in prod"
|
|
238
347
|
|
|
239
|
-
|
|
240
|
-
You had the old version with static `fs`/`path` imports. Upgrade — this version is edge-safe.
|
|
348
|
+
Same as above. Local dev works because Vite loads `.env` files automatically. Production requires platform-level configuration.
|
|
241
349
|
|
|
242
350
|
### "Cloudflare secret not found"
|
|
243
|
-
Secrets added via `wrangler secret put` are only available via `c.env` inside your handler. Use `wrangler.toml [vars]` for anything `getEnv` needs at the top level.
|
|
244
351
|
|
|
245
|
-
|
|
246
|
-
Add to your `tsconfig` or entry file:
|
|
247
|
-
```ts
|
|
248
|
-
/// <reference types="vite/client" />
|
|
249
|
-
```
|
|
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.
|
|
250
353
|
|
|
251
|
-
|
|
354
|
+
### "TypeScript error: Context not assignable to HonoContext"
|
|
252
355
|
|
|
253
|
-
|
|
356
|
+
Hono 4.12+ added a symbol to `HonoRequest` that can break structural assignability in strict TypeScript projects. Cast once per handler:
|
|
254
357
|
|
|
255
|
-
|
|
358
|
+
```ts
|
|
359
|
+
const ctx = c as any
|
|
360
|
+
```
|
|
256
361
|
|
|
257
|
-
|
|
258
|
-
- Secret rotation
|
|
259
|
-
- Encrypted envs
|
|
260
|
-
- Runtime validation schemas
|
|
362
|
+
### "Types not found"
|
|
261
363
|
|
|
262
|
-
|
|
364
|
+
Add to your `tsconfig.json` or entry file:
|
|
263
365
|
|
|
264
|
-
|
|
366
|
+
```ts
|
|
367
|
+
/// <reference types="vite/client" />
|
|
368
|
+
```
|
|
265
369
|
|
|
266
|
-
|
|
370
|
+
---
|
|
267
371
|
|
|
268
|
-
|
|
269
|
-
- No bloat
|
|
270
|
-
- No magic
|
|
271
|
-
- No runtime cost
|
|
372
|
+
## Compatibility
|
|
272
373
|
|
|
273
|
-
|
|
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 |
|
|
274
380
|
|
|
275
381
|
---
|
|
276
382
|
|
|
277
|
-
##
|
|
383
|
+
## Contributing
|
|
278
384
|
|
|
279
|
-
|
|
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.
|
|
280
386
|
|
|
281
387
|
---
|
|
282
388
|
|
|
283
|
-
|
|
389
|
+
## License
|
|
390
|
+
|
|
391
|
+
MIT © Bini.js Team
|
package/dist/index.d.mts
CHANGED
|
@@ -1,29 +1,34 @@
|
|
|
1
|
+
import { Context } from 'hono';
|
|
1
2
|
import { Plugin } from 'vite';
|
|
2
3
|
export { Plugin } from 'vite';
|
|
3
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
|
+
type HonoContext = Context;
|
|
5
21
|
interface BiniEnvPluginOptions {
|
|
6
|
-
|
|
7
|
-
readonly clearViteHeader?: boolean;
|
|
8
|
-
readonly logo?: string;
|
|
22
|
+
/** Extra prefixes to expose to import.meta.env, in addition to BINI_ and VITE_. */
|
|
9
23
|
readonly envPrefix?: string | string[];
|
|
10
|
-
readonly loadInPreview?: boolean;
|
|
11
|
-
/** @deprecated Suppression is always applied at module load; this option is ignored. */
|
|
12
|
-
readonly suppressDotenvLogs?: boolean;
|
|
13
|
-
}
|
|
14
|
-
interface DetectedEnvFile {
|
|
15
|
-
readonly name: string;
|
|
16
|
-
readonly path: string;
|
|
17
24
|
}
|
|
18
25
|
declare const biniLogger: {
|
|
19
26
|
readonly info: (msg: string) => void;
|
|
20
27
|
readonly warn: (msg: string) => void;
|
|
21
28
|
readonly error: (msg: string, err?: unknown) => void;
|
|
22
29
|
};
|
|
23
|
-
declare function getEnv(key: string): string | undefined;
|
|
24
|
-
declare function requireEnv(key: string): string;
|
|
25
|
-
declare function loadEnv(projectRoot?: string): Promise<void>;
|
|
26
|
-
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;
|
|
27
32
|
declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
|
|
28
33
|
|
|
29
|
-
export { type BiniEnvPluginOptions, type
|
|
34
|
+
export { type BiniEnvPluginOptions, type HonoContext, biniEnv, biniLogger, getEnv, requireEnv };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,29 +1,34 @@
|
|
|
1
|
+
import { Context } from 'hono';
|
|
1
2
|
import { Plugin } from 'vite';
|
|
2
3
|
export { Plugin } from 'vite';
|
|
3
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
|
+
type HonoContext = Context;
|
|
5
21
|
interface BiniEnvPluginOptions {
|
|
6
|
-
|
|
7
|
-
readonly clearViteHeader?: boolean;
|
|
8
|
-
readonly logo?: string;
|
|
22
|
+
/** Extra prefixes to expose to import.meta.env, in addition to BINI_ and VITE_. */
|
|
9
23
|
readonly envPrefix?: string | string[];
|
|
10
|
-
readonly loadInPreview?: boolean;
|
|
11
|
-
/** @deprecated Suppression is always applied at module load; this option is ignored. */
|
|
12
|
-
readonly suppressDotenvLogs?: boolean;
|
|
13
|
-
}
|
|
14
|
-
interface DetectedEnvFile {
|
|
15
|
-
readonly name: string;
|
|
16
|
-
readonly path: string;
|
|
17
24
|
}
|
|
18
25
|
declare const biniLogger: {
|
|
19
26
|
readonly info: (msg: string) => void;
|
|
20
27
|
readonly warn: (msg: string) => void;
|
|
21
28
|
readonly error: (msg: string, err?: unknown) => void;
|
|
22
29
|
};
|
|
23
|
-
declare function getEnv(key: string): string | undefined;
|
|
24
|
-
declare function requireEnv(key: string): string;
|
|
25
|
-
declare function loadEnv(projectRoot?: string): Promise<void>;
|
|
26
|
-
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;
|
|
27
32
|
declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
|
|
28
33
|
|
|
29
|
-
export { type BiniEnvPluginOptions, type
|
|
34
|
+
export { type BiniEnvPluginOptions, type HonoContext, biniEnv, biniLogger, getEnv, requireEnv };
|