bini-env 1.0.10 → 1.1.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 CHANGED
@@ -4,11 +4,12 @@
4
4
  ![npm downloads](https://img.shields.io/npm/dm/bini-env?style=flat-square)
5
5
  ![license](https://img.shields.io/npm/l/bini-env?style=flat-square)
6
6
  ![vite](https://img.shields.io/badge/vite-%3E%3D8.0-646CFF?style=flat-square&logo=vite)
7
+ ![hono](https://img.shields.io/badge/hono-%3E%3D4.0-E36002?style=flat-square&logo=hono)
7
8
  ![typescript](https://img.shields.io/badge/TypeScript-ready-3178C6?style=flat-square&logo=typescript)
8
9
  ![node](https://img.shields.io/badge/node-%3E%3D20.19-339933?style=flat-square&logo=node.js)
9
10
 
10
11
  **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.
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.
12
13
 
13
14
  ---
14
15
 
@@ -26,43 +27,60 @@ If you don't understand this, stop and fix that first.
26
27
 
27
28
  ## ✨ Features
28
29
 
29
- - **Universal API** — `getEnv()` / `requireEnv()` work across all runtimes
30
- - **Zero-config `.env` loading** in development
31
- - **Edge-safe** — no static `fs`, `path`, or `dotenv` imports in bundles
30
+ - **Hono-native API** — `getEnv(c, key)` / `requireEnv(c, key)` read from Hono's request context
31
+ - **Universal runtime support** — CF Workers, Node, Bun, Deno, Vercel Edge, Netlify Edge
32
+ - **Zero dotenv** — no `.env` file parsing at runtime; vars come from the host
33
+ - **Build-time `process.env` fallback** — for Vite plugin hooks that run outside a request
32
34
  - **Auto server restart** — dev server restarts when `.env` files are created or changed
33
- - **Strict production behavior** — no file reads, no dotenv
34
35
  - **Prefix control** — supports `BINI_`, `VITE_`, or custom
35
36
  - **Tree-shakeable** — no dead code in client bundles
36
- - **Typed** — full TypeScript support
37
- - **Fast** — single load in dev, zero overhead in prod
37
+ - **Typed** — full TypeScript support with exported `HonoContext` duck type
38
+ - **Fast** — zero overhead; no file reads in production
38
39
 
39
40
  ---
40
41
 
41
42
  ## 📦 Installation
42
43
 
43
44
  ```bash
44
- pnpm add bini-env
45
+ pnpm add bini-env hono
45
46
  # or
46
- npm install bini-env
47
+ npm install bini-env hono
47
48
  # or
48
- yarn add bini-env
49
+ yarn add bini-env hono
49
50
  ```
50
51
 
52
+ > `hono` is a required peer dependency.
53
+
51
54
  ---
52
55
 
53
56
  ## 🚀 Quick Start
54
57
 
55
58
  ```ts
56
59
  // vite.config.ts
57
- import { defineConfig } from 'vite';
58
- import { biniEnv } from 'bini-env';
60
+ import { defineConfig } from 'vite'
61
+ import { biniEnv } from 'bini-env'
59
62
 
60
63
  export default defineConfig({
61
64
  plugins: [biniEnv()]
62
- });
65
+ })
63
66
  ```
64
67
 
65
- Done. If this doesn't work, your project setup is broken — not the plugin.
68
+ ```ts
69
+ // src/app/api/example.ts
70
+ import { Hono } from 'hono'
71
+ import { getEnv, requireEnv } from 'bini-env'
72
+
73
+ const app = new Hono()
74
+
75
+ app.get('/hello', (c) => {
76
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
77
+ const ctx = c as any
78
+ const name = getEnv(ctx, 'APP_NAME') ?? 'World'
79
+ return c.json({ message: `Hello, ${name}!` })
80
+ })
81
+
82
+ export default app
83
+ ```
66
84
 
67
85
  ---
68
86
 
@@ -91,9 +109,10 @@ DATABASE_URL=postgres://...
91
109
  ```
92
110
 
93
111
  ```ts
94
- // getEnv and requireEnv are auto-imported in API routes
95
- const pass = requireEnv('SMTP_PASS'); // throws if missing
96
- const db = getEnv('DATABASE_URL'); // returns undefined if missing
112
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
113
+ const ctx = c as any
114
+ const pass = requireEnv(ctx, 'SMTP_PASS') // throws if missing
115
+ const db = getEnv(ctx, 'DATABASE_URL') // returns undefined if missing
97
116
  ```
98
117
 
99
118
  👉 If this leaks, it's your fault, not the library's.
@@ -102,38 +121,36 @@ const db = getEnv('DATABASE_URL'); // returns undefined if missing
102
121
 
103
122
  ## 🌍 Platform Support
104
123
 
105
- `getEnv` and `requireEnv` work identically across every supported platform. Write your API routes once — they run everywhere unchanged.
124
+ `getEnv` and `requireEnv` resolve vars from Hono's `env(c)` adapter, which maps to the correct source on every supported platform automatically.
106
125
 
107
- | Platform | Runtime | Where vars come from | How `getEnv` reads them |
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()` ✅ |
126
+ | Platform | Runtime | Where vars come from | How `env(c)` reads them |
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()` ✅ |
115
134
 
116
- > **Cloudflare note:** Variables set in `wrangler.toml [vars]` or the dashboard work with `getEnv` at the top level. Secrets added via `wrangler secret put` are only available inside the fetch handler via `c.env` — this is a Cloudflare Workers architecture constraint, not a bini-env limitation.
135
+ > **Cloudflare note:** Secrets added via `wrangler secret put` are only available inside the fetch handler via `c.env` — this is a Cloudflare Workers architecture constraint, not a bini-env limitation. `getEnv` reads them correctly when called with `c` inside a route handler.
117
136
 
118
137
  ---
119
138
 
120
139
  ## 🧠 How It Actually Works
121
140
 
122
- | Mode | Behavior |
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 |
141
+ `getEnv(c, key)` resolves in this order:
129
142
 
130
- `fs`, `path`, and `dotenv` are **never imported at the top level**. They are dynamically imported at runtime, inside Node-only guards, so edge bundlers never trace them into your bundle.
143
+ 1. **`env(c)` from `hono/adapter`** — the Hono request context. This is the primary and correct source on every runtime. Never cached — request-scoped.
144
+ 2. **Stored context** — if you called `setContext(c)` in a global middleware, `getEnv('KEY')` (no `c`) uses it.
145
+ 3. **`process.env`** — build-time only, for Vite plugin hooks that run outside any request.
146
+
147
+ `dotenv` is not used anywhere. Variables must be set in your platform's environment config.
131
148
 
132
149
  ---
133
150
 
134
151
  ## 🔄 Auto Server Restart
135
152
 
136
- The dev server automatically restarts when any `.env*` file is created or changed in your project root — no manual restart needed.
153
+ The dev server automatically restarts when any `.env*` file is created or changed in your project root.
137
154
 
138
155
  ```
139
156
  12:00:01 [bini-env] .env.local changed — restarting server
@@ -156,7 +173,7 @@ biniEnv({
156
173
  logo : 'ß',
157
174
  envPrefix : ['BINI_', 'VITE_'],
158
175
  loadInPreview : true,
159
- });
176
+ })
160
177
  ```
161
178
 
162
179
  > **Critical:** If you change `envPrefix`, you are changing what gets exposed to the browser. Break this → you leak secrets.
@@ -165,82 +182,127 @@ biniEnv({
165
182
 
166
183
  ## 📚 API
167
184
 
168
- ### `getEnv(key)`
185
+ ### `getEnv(c, key)`
186
+
187
+ Returns `string | undefined`. Reads from Hono's request context.
169
188
 
170
- Returns `string | undefined`. Auto-imported in API routes.
189
+ ```ts
190
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
191
+ const ctx = c as any
192
+ const debug = getEnv(ctx, 'DEBUG_MODE')
193
+ ```
171
194
 
172
- Lookup order:
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)
195
+ Also works without `c` outside a request (build-time / Vite hooks):
176
196
 
177
197
  ```ts
178
- const debug = getEnv('DEBUG_MODE');
198
+ const debug = getEnv('DEBUG_MODE')
179
199
  ```
180
200
 
181
- ### `requireEnv(key)`
201
+ ### `requireEnv(c, key)`
182
202
 
183
- Same as `getEnv` but throws if missing:
203
+ Same as `getEnv` but throws if the variable is missing:
184
204
 
185
205
  ```
186
206
  [bini-env] Missing required environment variable: "SMTP_PASS"
187
- → In development: add it to your .env file.
207
+ → In development: set it in your platform's env config.
188
208
  → In production: set it in your hosting dashboard.
189
209
  ```
190
210
 
191
- Use this for anything critical that must exist at startup.
211
+ ```ts
212
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
213
+ const ctx = c as any
214
+ const dbUrl = requireEnv(ctx, 'DATABASE_URL')
215
+ ```
216
+
217
+ ### `setContext(c)` / `clearContext()`
218
+
219
+ Store a Hono context module-level so `getEnv('KEY')` works without passing `c` at every call site. Register once in a global middleware:
192
220
 
193
221
  ```ts
194
- const dbUrl = requireEnv('DATABASE_URL');
222
+ app.use('*', (c, next) => {
223
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
224
+ setContext(c as any)
225
+ return next()
226
+ })
195
227
  ```
196
228
 
197
229
  ### `biniEnv(options)`
198
230
 
199
- Vite plugin. Handles `.env` loading, terminal output, and dev server watching.
231
+ Vite plugin. Handles terminal output and dev server watching.
232
+
233
+ ### `biniLogger`
234
+
235
+ Standalone logger that uses Vite-style terminal output. Available for use in your own Bini.js plugins.
236
+
237
+ ```ts
238
+ import { biniLogger } from 'bini-env'
239
+
240
+ biniLogger.info('Server ready')
241
+ biniLogger.warn('Missing optional var')
242
+ biniLogger.error('Something broke', error)
243
+ ```
244
+
245
+ ### `HonoContext`
246
+
247
+ Exported duck type satisfied by any Hono `Context`. Use it if you need to type a wrapper:
248
+
249
+ ```ts
250
+ import type { HonoContext } from 'bini-env'
251
+
252
+ function readConfig(c: HonoContext) {
253
+ return getEnv(c, 'CONFIG_KEY')
254
+ }
255
+ ```
200
256
 
201
257
  ---
202
258
 
203
- ## 📂 Env File Resolution Order
259
+ ## 📂 Env File Resolution Order (Dev only)
204
260
 
205
- Higher entries take priority:
261
+ The Vite plugin watches these files and triggers a server restart on change:
206
262
 
207
263
  1. `.env.local`
208
264
  2. `.env.[mode].local`
209
265
  3. `.env.[mode]`
210
266
  4. `.env`
211
267
 
212
- Loaded once. Cached. No repeated disk reads.
268
+ In production, none of these are read. Variables must come from your platform.
213
269
 
214
270
  ---
215
271
 
216
272
  ## ⚡ Performance
217
273
 
218
- | Metric | Dev | Prod |
219
- | ------------- | --------- | ----------- |
220
- | File Reads | 1–5 | 0 |
221
- | Runtime Cost | ~5ms once | 0 |
222
- | Bundle Impact | Minimal | Tree-shaken |
274
+ | Metric | Dev | Prod |
275
+ | ------------- | -------- | ----------- |
276
+ | File Reads | 0 | 0 |
277
+ | Runtime Cost | ~0ms | 0 |
278
+ | Bundle Impact | Minimal | Tree-shaken |
223
279
 
224
- If you see overhead in production, you did something wrong.
280
+ No dotenv. No disk reads. No overhead.
225
281
 
226
282
  ---
227
283
 
228
284
  ## 🔥 Common Failure Modes
229
285
 
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`.
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.
232
288
 
233
289
  ### "Works in dev, broken in prod"
234
- You relied on a `.env` file in production. Set vars in your hosting dashboard.
290
+ Same as above. Production vars come from the host, not from files.
235
291
 
236
292
  ### "Secrets leaked"
237
- You exposed them via `BINI_` or `VITE_` prefix. Those are public. Use unprefixed vars for secrets.
238
-
239
- ### "Works on Node, broken on Vercel/Netlify/Cloudflare"
240
- You had the old version with static `fs`/`path` imports. Upgrade — this version is edge-safe.
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)`.
241
294
 
242
295
  ### "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.
296
+ Secrets added via `wrangler secret put` are only available via `c.env` inside your handler — which is exactly where `getEnv(c, key)` reads from. Make sure you're passing `c`.
297
+
298
+ ### "TypeScript error: Context not assignable to HonoContext"
299
+ Hono 4.12 added a `[GET_MATCH_RESULT]` symbol to `HonoRequest` that breaks structural assignability. Cast once per handler:
300
+
301
+ ```ts
302
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
303
+ const ctx = c as any
304
+ const key = requireEnv(ctx, 'MY_KEY')
305
+ ```
244
306
 
245
307
  ### "Types not found"
246
308
  Add to your `tsconfig` or entry file:
package/dist/index.d.mts CHANGED
@@ -1,15 +1,17 @@
1
1
  import { Plugin } from 'vite';
2
2
  export { Plugin } from 'vite';
3
+ export { Context } from 'hono';
3
4
 
4
- declare function suppressDotenvLogsGlobally(): void;
5
+ /** Minimal shape accepted by getEnv / requireEnv. Satisfied by any Hono Context. */
6
+ type HonoContext = {
7
+ env: unknown;
8
+ } & Record<string, unknown>;
5
9
  interface BiniEnvPluginOptions {
6
10
  readonly enabled?: boolean;
7
11
  readonly clearViteHeader?: boolean;
8
12
  readonly logo?: string;
9
13
  readonly envPrefix?: string | string[];
10
14
  readonly loadInPreview?: boolean;
11
- /** @deprecated Suppression is always applied at module load; this option is ignored. */
12
- readonly suppressDotenvLogs?: boolean;
13
15
  }
14
16
  interface DetectedEnvFile {
15
17
  readonly name: string;
@@ -20,10 +22,11 @@ declare const biniLogger: {
20
22
  readonly warn: (msg: string) => void;
21
23
  readonly error: (msg: string, err?: unknown) => void;
22
24
  };
23
- declare function getEnv(key: string): string | undefined;
24
- declare function requireEnv(key: string): string;
25
- declare function loadEnv(projectRoot?: string): Promise<void>;
25
+ declare function setContext(c: HonoContext): void;
26
+ declare function clearContext(): void;
27
+ declare function getEnv(c: HonoContext | string, key?: string): string | undefined;
28
+ declare function requireEnv(c: HonoContext | string, key?: string): string;
26
29
  declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
27
30
  declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
28
31
 
29
- export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, biniLogger, detectEnvFiles, getEnv, loadEnv, requireEnv, suppressDotenvLogsGlobally };
32
+ export { type BiniEnvPluginOptions, type DetectedEnvFile, type HonoContext, biniEnv, biniLogger, clearContext, detectEnvFiles, getEnv, requireEnv, setContext };
package/dist/index.d.ts CHANGED
@@ -1,15 +1,17 @@
1
1
  import { Plugin } from 'vite';
2
2
  export { Plugin } from 'vite';
3
+ export { Context } from 'hono';
3
4
 
4
- declare function suppressDotenvLogsGlobally(): void;
5
+ /** Minimal shape accepted by getEnv / requireEnv. Satisfied by any Hono Context. */
6
+ type HonoContext = {
7
+ env: unknown;
8
+ } & Record<string, unknown>;
5
9
  interface BiniEnvPluginOptions {
6
10
  readonly enabled?: boolean;
7
11
  readonly clearViteHeader?: boolean;
8
12
  readonly logo?: string;
9
13
  readonly envPrefix?: string | string[];
10
14
  readonly loadInPreview?: boolean;
11
- /** @deprecated Suppression is always applied at module load; this option is ignored. */
12
- readonly suppressDotenvLogs?: boolean;
13
15
  }
14
16
  interface DetectedEnvFile {
15
17
  readonly name: string;
@@ -20,10 +22,11 @@ declare const biniLogger: {
20
22
  readonly warn: (msg: string) => void;
21
23
  readonly error: (msg: string, err?: unknown) => void;
22
24
  };
23
- declare function getEnv(key: string): string | undefined;
24
- declare function requireEnv(key: string): string;
25
- declare function loadEnv(projectRoot?: string): Promise<void>;
25
+ declare function setContext(c: HonoContext): void;
26
+ declare function clearContext(): void;
27
+ declare function getEnv(c: HonoContext | string, key?: string): string | undefined;
28
+ declare function requireEnv(c: HonoContext | string, key?: string): string;
26
29
  declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
27
30
  declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
28
31
 
29
- export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, biniLogger, detectEnvFiles, getEnv, loadEnv, requireEnv, suppressDotenvLogsGlobally };
32
+ export { type BiniEnvPluginOptions, type DetectedEnvFile, type HonoContext, biniEnv, biniLogger, clearContext, detectEnvFiles, getEnv, requireEnv, setContext };
package/dist/index.js CHANGED
@@ -1,46 +1,21 @@
1
1
  'use strict';
2
2
 
3
+ var adapter = require('hono/adapter');
4
+
3
5
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
6
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
7
  }) : x)(function(x) {
6
8
  if (typeof require !== "undefined") return require.apply(this, arguments);
7
9
  throw Error('Dynamic require of "' + x + '" is not supported');
8
10
  });
9
-
10
- // src/index.ts
11
11
  function isNodeLike() {
12
- return typeof process !== "undefined" && !!process.env && typeof process.versions === "object" && // Edge runtimes (Vercel, Cloudflare) expose a minimal `process` but not
13
- // `process.versions.node`. Checking for it keeps us out of edge bundles.
14
- (typeof process.versions.node === "string" || // Bun sets process.versions.bun
15
- typeof process.versions.bun === "string");
16
- }
17
- function isDenoRuntime() {
18
- return typeof globalThis.Deno !== "undefined";
12
+ return typeof process !== "undefined" && !!process.env && typeof process.versions === "object" && (typeof process.versions.node === "string" || typeof process.versions.bun === "string");
19
13
  }
20
14
  var originalConsoleLog = console.log.bind(console);
21
15
  var originalConsoleError = console.error.bind(console);
22
16
  if (isNodeLike() && !process.env.NODE_ENV) {
23
17
  process.env.NODE_ENV = "production";
24
18
  }
25
- var _suppressionApplied = false;
26
- function suppressDotenvLogsGlobally() {
27
- if (_suppressionApplied) return;
28
- _suppressionApplied = true;
29
- if (isNodeLike()) {
30
- process.env.DOTENV_QUIET = "true";
31
- }
32
- const isDotenvNoise = (...args) => {
33
- const msg = args.join(" ");
34
- return msg.includes("[dotenv@") || msg.includes("injected env") || msg.includes("injecting env");
35
- };
36
- console.log = (...args) => {
37
- if (!isDotenvNoise(...args)) originalConsoleLog(...args);
38
- };
39
- console.error = (...args) => {
40
- if (!isDotenvNoise(...args)) originalConsoleError(...args);
41
- };
42
- }
43
- suppressDotenvLogsGlobally();
44
19
  var BINI_LOGO = "\xDF";
45
20
  var DEFAULT_ENV_PREFIX = ["BINI_", "VITE_"];
46
21
  var DEFAULT_OPTIONS = Object.freeze({
@@ -73,9 +48,6 @@ var biniLogger = {
73
48
  );
74
49
  }
75
50
  };
76
- function getDeno() {
77
- return globalThis.Deno;
78
- }
79
51
  function defer(fn) {
80
52
  if (typeof setImmediate !== "undefined") {
81
53
  setImmediate(fn);
@@ -83,95 +55,47 @@ function defer(fn) {
83
55
  Promise.resolve().then(fn);
84
56
  }
85
57
  }
86
- function getEnv(key) {
87
- if (envCache.has(key)) return envCache.get(key);
88
- const deno = getDeno();
89
- if (deno) {
58
+ var _honoContext = null;
59
+ function setContext(c) {
60
+ _honoContext = c;
61
+ }
62
+ function clearContext() {
63
+ _honoContext = null;
64
+ }
65
+ function getEnv(c, key) {
66
+ const resolvedKey = typeof c === "string" ? c : key;
67
+ const resolvedCtx = typeof c === "string" ? null : c;
68
+ const ctx = resolvedCtx ?? _honoContext;
69
+ if (ctx) {
90
70
  try {
91
- const value = deno.env.get(key);
92
- if (value !== void 0) {
93
- envCache.set(key, value);
94
- return value;
95
- }
71
+ const honoEnvs = adapter.env(ctx);
72
+ const value = honoEnvs[resolvedKey];
73
+ if (value !== void 0) return value;
96
74
  } catch {
97
75
  }
98
76
  }
77
+ if (envCache.has(resolvedKey)) return envCache.get(resolvedKey);
99
78
  if (typeof process !== "undefined" && process.env) {
100
- const value = process.env[key];
101
- if (value !== void 0) {
102
- envCache.set(key, value);
103
- return value;
104
- }
105
- }
106
- try {
107
- const metaEnv = undefined;
108
- if (metaEnv) {
109
- for (const candidate of [key, `BINI_${key}`, `VITE_${key}`]) {
110
- if (metaEnv[candidate] !== void 0) {
111
- envCache.set(key, metaEnv[candidate]);
112
- return metaEnv[candidate];
113
- }
114
- }
115
- }
116
- } catch {
79
+ const value = process.env[resolvedKey];
80
+ envCache.set(resolvedKey, value);
81
+ return value;
117
82
  }
118
- envCache.set(key, void 0);
83
+ envCache.set(resolvedKey, void 0);
119
84
  return void 0;
120
85
  }
121
- function requireEnv(key) {
122
- const val = getEnv(key);
86
+ function requireEnv(c, key) {
87
+ const resolvedKey = typeof c === "string" ? c : key;
88
+ const val = getEnv(c, resolvedKey);
123
89
  if (val === void 0) {
124
90
  biniLogger.error(
125
- `Missing required environment variable: "${key}"
126
- ${"\x1B[2m" /* DIM */}\u2192 In development: add it to your .env file.${"\x1B[0m" /* RESET */}
91
+ `Missing required environment variable: "${resolvedKey}"
92
+ ${"\x1B[2m" /* DIM */}\u2192 In development: set it in your platform's env config.${"\x1B[0m" /* RESET */}
127
93
  ${"\x1B[2m" /* DIM */}\u2192 In production: set it in your hosting dashboard.${"\x1B[0m" /* RESET */}`
128
94
  );
129
- throw new Error(`[bini-env] Missing required environment variable: "${key}"`);
95
+ throw new Error(`[bini-env] Missing required environment variable: "${resolvedKey}"`);
130
96
  }
131
97
  return val;
132
98
  }
133
- var _envLoaded = false;
134
- var _loadPromise = null;
135
- async function loadEnv(projectRoot) {
136
- if (_envLoaded) return;
137
- if (_loadPromise) return _loadPromise;
138
- _loadPromise = (async () => {
139
- try {
140
- if (isDenoRuntime() || !isNodeLike()) return;
141
- const root = projectRoot ?? process.cwd();
142
- const nodeEnv = process.env.NODE_ENV ?? "production";
143
- const envFiles = [
144
- ".env",
145
- `.env.${nodeEnv}`,
146
- `.env.${nodeEnv}.local`,
147
- ".env.local"
148
- ];
149
- const [dotenvMod, fsMod, pathMod] = await Promise.all([
150
- import('dotenv'),
151
- import('fs'),
152
- import('path')
153
- ]);
154
- const dotenv = dotenvMod;
155
- const fs = fsMod.default ?? fsMod;
156
- const path = pathMod.default ?? pathMod;
157
- for (const file of envFiles) {
158
- const filePath = path.join(root, file);
159
- try {
160
- await fs.promises.access(filePath, fs.constants.R_OK);
161
- dotenv.config({ path: filePath, override: true });
162
- } catch {
163
- }
164
- }
165
- envCache.clear();
166
- _envLoaded = true;
167
- } catch (error) {
168
- biniLogger.error("Failed to load .env file", error);
169
- } finally {
170
- _loadPromise = null;
171
- }
172
- })();
173
- return _loadPromise;
174
- }
175
99
  var _envFilesCache = null;
176
100
  var _cacheKey = "";
177
101
  function detectEnvFiles(projectRoot) {
@@ -267,12 +191,7 @@ function biniEnv(options = {}) {
267
191
  resolvedConfig = cfg;
268
192
  },
269
193
  configureServer(server) {
270
- const triggerLoad = () => void loadEnv(getRoot());
271
- if (server.httpServer) {
272
- server.httpServer.once("listening", triggerLoad);
273
- } else {
274
- defer(triggerLoad);
275
- }
194
+ defer(() => envCache.clear());
276
195
  const envGlob = `${getRoot()}/.env*`;
277
196
  server.watcher.add(envGlob);
278
197
  const onEnvChange = (filePath) => {
@@ -280,8 +199,6 @@ function biniEnv(options = {}) {
280
199
  biniLogger.info(
281
200
  `env file ${filePath.replace(getRoot() + "/", "")} changed \u2014 restarting server`
282
201
  );
283
- _envLoaded = false;
284
- _loadPromise = null;
285
202
  envCache.clear();
286
203
  _envFilesCache = null;
287
204
  void server.restart();
@@ -298,12 +215,7 @@ function biniEnv(options = {}) {
298
215
  },
299
216
  configurePreviewServer(server) {
300
217
  if (loadInPreview) {
301
- const triggerLoad = () => void loadEnv(getRoot());
302
- if (server.httpServer) {
303
- server.httpServer.once("listening", triggerLoad);
304
- } else {
305
- defer(triggerLoad);
306
- }
218
+ defer(() => envCache.clear());
307
219
  }
308
220
  if (clearViteHeader || logo !== BINI_LOGO) {
309
221
  patchPrintUrls(server, "preview", logo, clearViteHeader, getRoot, loadInPreview);
@@ -314,10 +226,10 @@ function biniEnv(options = {}) {
314
226
 
315
227
  exports.biniEnv = biniEnv;
316
228
  exports.biniLogger = biniLogger;
229
+ exports.clearContext = clearContext;
317
230
  exports.detectEnvFiles = detectEnvFiles;
318
231
  exports.getEnv = getEnv;
319
- exports.loadEnv = loadEnv;
320
232
  exports.requireEnv = requireEnv;
321
- exports.suppressDotenvLogsGlobally = suppressDotenvLogsGlobally;
233
+ exports.setContext = setContext;
322
234
  //# sourceMappingURL=index.js.map
323
235
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// bini-env/src/index.ts\nimport type { Plugin, PreviewServer, ResolvedConfig, UserConfig, ViteDevServer } from 'vite';\n\n/* ==========================================================================\n Runtime detection — must run before anything else\n ========================================================================== */\n\nfunction isNodeLike(): boolean {\n return (\n typeof process !== 'undefined' &&\n !!process.env &&\n typeof process.versions === 'object' &&\n // Edge runtimes (Vercel, Cloudflare) expose a minimal `process` but not\n // `process.versions.node`. Checking for it keeps us out of edge bundles.\n (typeof process.versions.node === 'string' ||\n // Bun sets process.versions.bun\n typeof (process.versions as Record<string, unknown>).bun === 'string')\n );\n}\n\nfunction isDenoRuntime(): boolean {\n return typeof (globalThis as unknown as { Deno?: unknown }).Deno !== 'undefined';\n}\n\n/* ==========================================================================\n Capture originals FIRST — before any patching occurs\n ========================================================================== */\n\nconst originalConsoleLog = console.log.bind(console);\nconst originalConsoleError = console.error.bind(console);\n\n/* ==========================================================================\n Default NODE_ENV — must run before anything else\n ========================================================================== */\n\nif (isNodeLike() && !process.env.NODE_ENV) {\n process.env.NODE_ENV = 'production';\n}\n\n/* ==========================================================================\n DOTENV LOG SUPPRESSION\n Patched once at module load; subsequent calls are no-ops.\n ========================================================================== */\n\nlet _suppressionApplied = false;\n\nexport function suppressDotenvLogsGlobally(): void {\n if (_suppressionApplied) return;\n _suppressionApplied = true;\n\n if (isNodeLike()) {\n process.env.DOTENV_QUIET = 'true';\n }\n\n const isDotenvNoise = (...args: unknown[]): boolean => {\n const msg = args.join(' ');\n return (\n msg.includes('[dotenv@') ||\n msg.includes('injected env') ||\n msg.includes('injecting env')\n );\n };\n\n console.log = (...args: unknown[]) => {\n if (!isDotenvNoise(...args)) originalConsoleLog(...args);\n };\n\n console.error = (...args: unknown[]) => {\n if (!isDotenvNoise(...args)) originalConsoleError(...args);\n };\n}\n\n// Apply once at module load\nsuppressDotenvLogsGlobally();\n\n/* ==========================================================================\n Cross-runtime type declarations\n ========================================================================== */\n\ninterface DenoEnv {\n get(key: string): string | undefined;\n}\ninterface DenoNamespace {\n env: DenoEnv;\n}\n\n/* ==========================================================================\n Public types\n ========================================================================== */\n\nexport interface BiniEnvPluginOptions {\n readonly enabled?: boolean;\n readonly clearViteHeader?: boolean;\n readonly logo?: string;\n readonly envPrefix?: string | string[];\n readonly loadInPreview?: boolean;\n /** @deprecated Suppression is always applied at module load; this option is ignored. */\n readonly suppressDotenvLogs?: boolean;\n}\n\nexport interface DetectedEnvFile {\n readonly name: string;\n readonly path: string;\n}\n\n/* ==========================================================================\n Constants\n ========================================================================== */\n\nconst BINI_LOGO = 'ß';\nconst DEFAULT_ENV_PREFIX = ['BINI_', 'VITE_'] as const;\n\nconst DEFAULT_OPTIONS = Object.freeze({\n enabled : true,\n clearViteHeader: true,\n logo : BINI_LOGO,\n envPrefix : [...DEFAULT_ENV_PREFIX],\n loadInPreview : true,\n} satisfies Omit<Required<BiniEnvPluginOptions>, 'suppressDotenvLogs'>);\n\nconst enum COLORS {\n CYAN = '\\x1b[36m',\n RESET = '\\x1b[0m',\n GREEN = '\\x1b[32m',\n YELLOW = '\\x1b[33m',\n RED = '\\x1b[31m',\n BOLD = '\\x1b[1m',\n DIM = '\\x1b[2m',\n}\n\nconst envCache = new Map<string, string | undefined>();\n\n/* ==========================================================================\n Standalone logger\n ========================================================================== */\n\nfunction timestamp(): string {\n return `${COLORS.DIM}${new Date().toLocaleTimeString('en-US', { hour12: false })}${COLORS.RESET}`;\n}\n\nexport const biniLogger = {\n info(msg: string): void {\n originalConsoleLog(\n `${timestamp()} ${COLORS.CYAN}${COLORS.BOLD}[bini-env]${COLORS.RESET} ${msg}`,\n );\n },\n warn(msg: string): void {\n originalConsoleError(\n `${timestamp()} ${COLORS.YELLOW}${COLORS.BOLD}(!) [bini-env]${COLORS.RESET} ${COLORS.YELLOW}${msg}${COLORS.RESET}`,\n );\n },\n error(msg: string, err?: unknown): void {\n const detail = err instanceof Error\n ? `\\n ${COLORS.DIM}${err.message}${COLORS.RESET}`\n : '';\n originalConsoleError(\n `${timestamp()} ${COLORS.RED}${COLORS.BOLD}[bini-env] error${COLORS.RESET} ${msg}${detail}`,\n );\n },\n} as const;\n\n/* ==========================================================================\n Runtime helpers\n ========================================================================== */\n\nfunction getDeno(): DenoNamespace | undefined {\n return (globalThis as unknown as { Deno?: DenoNamespace }).Deno;\n}\n\n/** Schedule a task compatible with Node, Bun, Deno, and edge runtimes. */\nfunction defer(fn: () => void): void {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(fn);\n } else {\n Promise.resolve().then(fn);\n }\n}\n\n/* ==========================================================================\n getEnv\n ========================================================================== */\n\nexport function getEnv(key: string): string | undefined {\n if (envCache.has(key)) return envCache.get(key);\n\n // 1. Deno runtime\n const deno = getDeno();\n if (deno) {\n try {\n const value = deno.env.get(key);\n if (value !== undefined) {\n envCache.set(key, value);\n return value;\n }\n } catch { /* fall through */ }\n }\n\n // 2. Node.js / Bun / Edge (process.env is available on most edge runtimes too)\n if (typeof process !== 'undefined' && process.env) {\n const value = process.env[key];\n if (value !== undefined) {\n envCache.set(key, value);\n return value;\n }\n }\n\n // 3. Vite client (import.meta.env) — also checks BINI_ and VITE_ prefixed variants\n try {\n const metaEnv = import.meta.env as Record<string, string | undefined> | undefined;\n if (metaEnv) {\n for (const candidate of [key, `BINI_${key}`, `VITE_${key}`]) {\n if (metaEnv[candidate] !== undefined) {\n envCache.set(key, metaEnv[candidate]);\n return metaEnv[candidate];\n }\n }\n }\n } catch { /* import.meta.env not available in this runtime */ }\n\n envCache.set(key, undefined);\n return undefined;\n}\n\n/* ==========================================================================\n requireEnv\n ========================================================================== */\n\nexport function requireEnv(key: string): string {\n const val = getEnv(key);\n if (val === undefined) {\n biniLogger.error(\n `Missing required environment variable: \"${key}\"\\n` +\n ` ${COLORS.DIM}→ In development: add it to your .env file.${COLORS.RESET}\\n` +\n ` ${COLORS.DIM}→ In production: set it in your hosting dashboard.${COLORS.RESET}`,\n );\n throw new Error(`[bini-env] Missing required environment variable: \"${key}\"`);\n }\n return val;\n}\n\n/* ==========================================================================\n loadEnv\n - Only runs on Node-like runtimes (Node.js, Bun).\n - Edge runtimes and Deno skip entirely — they get vars from the host.\n - Idempotent; concurrent calls share one promise.\n ========================================================================== */\n\nlet _envLoaded = false;\nlet _loadPromise: Promise<void> | null = null;\n\nexport async function loadEnv(projectRoot?: string): Promise<void> {\n if (_envLoaded) return;\n if (_loadPromise) return _loadPromise;\n\n _loadPromise = (async () => {\n try {\n // Deno and edge runtimes do not use .env files — vars are injected by host\n if (isDenoRuntime() || !isNodeLike()) return;\n\n const root = projectRoot ?? process.cwd();\n const nodeEnv = process.env.NODE_ENV ?? 'production';\n\n // Load order: lowest → highest priority (later files override earlier ones)\n const envFiles = [\n '.env',\n `.env.${nodeEnv}`,\n `.env.${nodeEnv}.local`,\n '.env.local',\n ];\n\n // Dynamic import keeps `dotenv` and `fs`/`path` out of edge bundles entirely.\n // Bundlers that trace static imports (esbuild, Rollup) will NOT follow\n // a runtime-gated dynamic import when tree-shaking is enabled.\n const [dotenvMod, fsMod, pathMod] = await Promise.all([\n import('dotenv'),\n import('node:fs'),\n import('node:path'),\n ]);\n const dotenv = dotenvMod;\n const fs = fsMod.default ?? fsMod;\n const path = pathMod.default ?? pathMod;\n\n for (const file of envFiles) {\n const filePath = path.join(root, file);\n try {\n await fs.promises.access(filePath, fs.constants.R_OK);\n dotenv.config({ path: filePath, override: true });\n } catch { /* file absent — skip */ }\n }\n\n // Invalidate cache so newly loaded vars are picked up by getEnv\n envCache.clear();\n _envLoaded = true;\n\n } catch (error) {\n biniLogger.error('Failed to load .env file', error);\n // Do NOT set _envLoaded — allow a retry on the next call.\n } finally {\n _loadPromise = null;\n }\n })();\n\n return _loadPromise;\n}\n\n/* ==========================================================================\n detectEnvFiles\n Node-only utility used by the Vite plugin (build-time only, never edge).\n ========================================================================== */\n\nlet _envFilesCache: DetectedEnvFile[] | null = null;\nlet _cacheKey = '';\n\nexport function detectEnvFiles(projectRoot?: string): DetectedEnvFile[] {\n // Guard: this function uses fs synchronously; bail on non-Node runtimes.\n if (!isNodeLike()) return [];\n\n const root = projectRoot ?? process.cwd();\n const nodeEnv = process.env.NODE_ENV ?? 'production';\n const cacheKey = `${root}:${nodeEnv}`;\n if (_envFilesCache && _cacheKey === cacheKey) return _envFilesCache;\n\n // Inline the fs/path usage so no top-level import is needed.\n // This function is only ever called from the Vite plugin (configureServer /\n // configurePreviewServer), which runs in Node — never in an edge bundle.\n let fsSync: typeof import('fs');\n let pathMod: typeof import('path');\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n fsSync = require('node:fs');\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n pathMod = require('node:path');\n } catch {\n return [];\n }\n\n const candidates = [\n '.env.local',\n `.env.${nodeEnv}.local`,\n `.env.${nodeEnv}`,\n '.env',\n ];\n\n const found: DetectedEnvFile[] = [];\n for (const file of candidates) {\n try {\n const filePath = pathMod.join(root, file);\n if (fsSync.existsSync(filePath)) found.push({ name: file, path: filePath });\n } catch { /* skip unreadable paths */ }\n }\n\n _envFilesCache = found;\n _cacheKey = cacheKey;\n return found;\n}\n\n/* ==========================================================================\n Vite plugin helpers\n ========================================================================== */\n\nfunction clearLine(): void {\n if (typeof process !== 'undefined' && process.stdout?.isTTY) {\n process.stdout.write('\\x1b[2K\\r');\n }\n}\n\nfunction printResolvedUrls(\n urls: { local: string[]; network: string[] } | null | undefined,\n): void {\n if (!urls) return;\n if (urls.local.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`,\n );\n }\n if (urls.network.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`,\n );\n }\n}\n\ntype ServerLike = ViteDevServer | PreviewServer;\n\nfunction patchPrintUrls(\n server : ServerLike,\n mode : 'dev' | 'preview',\n logo : string,\n clearViteHeader: boolean,\n getRoot : () => string,\n showEnvFiles : boolean,\n): void {\n let started = false;\n const originalPrintUrls = server.printUrls.bind(server);\n\n server.printUrls = () => {\n if (started) return;\n started = true;\n\n if (clearViteHeader) clearLine();\n originalConsoleLog(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (${mode})`);\n\n if (showEnvFiles) {\n const found = detectEnvFiles(getRoot());\n if (found.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${found.map(f => f.name).join(', ')}`,\n );\n }\n }\n\n if (clearViteHeader) {\n printResolvedUrls(server.resolvedUrls);\n } else {\n originalPrintUrls();\n }\n };\n}\n\n/* ==========================================================================\n Vite plugin\n ========================================================================== */\n\nexport function biniEnv(options: Readonly<BiniEnvPluginOptions> = {}): Plugin {\n if (options.enabled === false) {\n return { name: 'vite-plugin-bini-env' };\n }\n\n const { clearViteHeader, logo, envPrefix, loadInPreview } = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n\n let resolvedConfig: ResolvedConfig;\n const getRoot = () => resolvedConfig?.root ?? process.cwd();\n\n return {\n name: 'vite-plugin-bini-env',\n\n config(): UserConfig {\n return { envPrefix };\n },\n\n configResolved(cfg: ResolvedConfig) {\n resolvedConfig = cfg;\n },\n\n configureServer(server) {\n const triggerLoad = () => void loadEnv(getRoot());\n if (server.httpServer) {\n server.httpServer.once('listening', triggerLoad);\n } else {\n defer(triggerLoad);\n }\n\n // Watch for new or changed .env files and restart the dev server so the\n // fresh variables are picked up. Chokidar (bundled with Vite) handles the\n // add/change events; we reset _envLoaded so loadEnv re-reads on restart.\n const envGlob = `${getRoot()}/.env*`;\n server.watcher.add(envGlob);\n\n const onEnvChange = (filePath: string) => {\n // Ignore editor swap/temp files (.env.swp, .env~, etc.)\n if (/\\.(swp|swo|bak|tmp)$|~$/.test(filePath)) return;\n\n biniLogger.info(\n `env file ${filePath.replace(getRoot() + '/', '')} changed — restarting server`,\n );\n\n // Reset load state so the restarted server re-reads all .env files\n _envLoaded = false;\n _loadPromise = null;\n envCache.clear();\n _envFilesCache = null;\n\n void server.restart();\n };\n\n server.watcher.on('add', onEnvChange);\n server.watcher.on('change', onEnvChange);\n\n // Remove listeners when the server closes so they don't stack across\n // restarts — Vite calls configureServer again on each restart.\n server.httpServer?.once('close', () => {\n server.watcher.off('add', onEnvChange);\n server.watcher.off('change', onEnvChange);\n });\n\n if (clearViteHeader || logo !== BINI_LOGO) {\n patchPrintUrls(server, 'dev', logo, clearViteHeader, getRoot, true);\n }\n },\n\n configurePreviewServer(server) {\n if (loadInPreview) {\n const triggerLoad = () => void loadEnv(getRoot());\n if (server.httpServer) {\n server.httpServer.once('listening', triggerLoad);\n } else {\n defer(triggerLoad);\n }\n }\n\n if (clearViteHeader || logo !== BINI_LOGO) {\n patchPrintUrls(server, 'preview', logo, clearViteHeader, getRoot, loadInPreview);\n }\n },\n };\n}\n\nexport type { Plugin } from 'vite';"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["env"],"mappings":"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","file":"index.js","sourcesContent":["// bini-env/src/index.ts\nimport { env } from 'hono/adapter';\nimport type { Plugin, PreviewServer, ResolvedConfig, UserConfig, ViteDevServer } from 'vite';\n\n/* ==========================================================================\n Runtime detection — used by Vite plugin hooks only\n ========================================================================== */\n\nfunction isNodeLike(): boolean {\n return (\n typeof process !== 'undefined' &&\n !!process.env &&\n typeof process.versions === 'object' &&\n (typeof process.versions.node === 'string' ||\n typeof (process.versions as Record<string, unknown>).bun === 'string')\n );\n}\n\n/* ==========================================================================\n Capture originals FIRST — before any patching occurs\n ========================================================================== */\n\nconst originalConsoleLog = console.log.bind(console);\nconst originalConsoleError = console.error.bind(console);\n\n/* ==========================================================================\n Default NODE_ENV\n ========================================================================== */\n\nif (isNodeLike() && !process.env.NODE_ENV) {\n process.env.NODE_ENV = 'production';\n}\n\n/* ==========================================================================\n HonoContext duck type\n\n We intentionally do NOT import Context<E,P,I> from hono because Hono 4.12\n added a [GET_MATCH_RESULT] symbol to HonoRequest, making every\n narrowly-typed Context (e.g. Context<BlankEnv, \"/chat\", BlankInput>)\n structurally incompatible with Context<any, any, any>. A minimal duck type\n that only requires what hono/adapter's env() accesses at runtime sidesteps\n the symbol variance entirely. Consumers cast with `c as any` once at the\n call site; the single `env(ctx as any)` below is the only unsafe cast in\n the entire package.\n ========================================================================== */\n\n/** Minimal shape accepted by getEnv / requireEnv. Satisfied by any Hono Context. */\nexport type HonoContext = { env: unknown } & Record<string, unknown>;\n\n/* ==========================================================================\n Public types\n ========================================================================== */\n\nexport interface BiniEnvPluginOptions {\n readonly enabled? : boolean;\n readonly clearViteHeader?: boolean;\n readonly logo? : string;\n readonly envPrefix? : string | string[];\n readonly loadInPreview? : boolean;\n}\n\nexport interface DetectedEnvFile {\n readonly name: string;\n readonly path: string;\n}\n\n/* ==========================================================================\n Constants\n ========================================================================== */\n\nconst BINI_LOGO = 'ß';\nconst DEFAULT_ENV_PREFIX = ['BINI_', 'VITE_'] as const;\n\nconst DEFAULT_OPTIONS = Object.freeze({\n enabled : true,\n clearViteHeader: true,\n logo : BINI_LOGO,\n envPrefix : [...DEFAULT_ENV_PREFIX],\n loadInPreview : true,\n} satisfies Required<BiniEnvPluginOptions>);\n\nconst enum COLORS {\n CYAN = '\\x1b[36m',\n RESET = '\\x1b[0m',\n GREEN = '\\x1b[32m',\n YELLOW = '\\x1b[33m',\n RED = '\\x1b[31m',\n BOLD = '\\x1b[1m',\n DIM = '\\x1b[2m',\n}\n\n// Build-time only cache — never used for request-scoped Hono env() results\nconst envCache = new Map<string, string | undefined>();\n\n/* ==========================================================================\n Standalone logger\n ========================================================================== */\n\nfunction timestamp(): string {\n return `${COLORS.DIM}${new Date().toLocaleTimeString('en-US', { hour12: false })}${COLORS.RESET}`;\n}\n\nexport const biniLogger = {\n info(msg: string): void {\n originalConsoleLog(\n `${timestamp()} ${COLORS.CYAN}${COLORS.BOLD}[bini-env]${COLORS.RESET} ${msg}`,\n );\n },\n warn(msg: string): void {\n originalConsoleError(\n `${timestamp()} ${COLORS.YELLOW}${COLORS.BOLD}(!) [bini-env]${COLORS.RESET} ${COLORS.YELLOW}${msg}${COLORS.RESET}`,\n );\n },\n error(msg: string, err?: unknown): void {\n const detail = err instanceof Error\n ? `\\n ${COLORS.DIM}${err.message}${COLORS.RESET}`\n : '';\n originalConsoleError(\n `${timestamp()} ${COLORS.RED}${COLORS.BOLD}[bini-env] error${COLORS.RESET} ${msg}${detail}`,\n );\n },\n} as const;\n\n/* ==========================================================================\n Vite plugin helper\n ========================================================================== */\n\nfunction defer(fn: () => void): void {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(fn);\n } else {\n Promise.resolve().then(fn);\n }\n}\n\n/* ==========================================================================\n Module-level Hono context store\n\n Lets getEnv / requireEnv work without an explicit `c` argument at every\n call site. Register once in a global middleware:\n\n app.use('*', (c, next) => { setContext(c as any); return next(); });\n ========================================================================== */\n\nlet _honoContext: HonoContext | null = null;\n\nexport function setContext(c: HonoContext): void {\n _honoContext = c;\n}\n\nexport function clearContext(): void {\n _honoContext = null;\n}\n\n/* ==========================================================================\n getEnv\n\n Resolution order:\n 1. Explicit Hono Context (c param) — request-scoped, never cached\n 2. Stored Hono Context (setContext) — request-scoped, never cached\n 3. process.env (build-time / Vite plugin hooks — no c available)\n\n Usage:\n getEnv(c as any, 'KEY') — inside a Hono route / middleware\n getEnv('KEY') — outside request context (build-time)\n ========================================================================== */\n\nexport function getEnv(c: HonoContext | string, key?: string): string | undefined {\n const resolvedKey = typeof c === 'string' ? c : key!;\n const resolvedCtx = typeof c === 'string' ? null : c;\n\n // 1 & 2. Hono env() — covers all runtimes: CF Workers, Node, Bun, Deno, Edge\n const ctx = resolvedCtx ?? _honoContext;\n if (ctx) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const honoEnvs = env(ctx as any) as Record<string, string | undefined>;\n const value = honoEnvs[resolvedKey];\n if (value !== undefined) return value; // never cache — request-scoped\n } catch { /* context binding unavailable — fall through */ }\n }\n\n // 3. process.env — build-time only (Vite plugin hooks run outside any request)\n if (envCache.has(resolvedKey)) return envCache.get(resolvedKey);\n\n if (typeof process !== 'undefined' && process.env) {\n const value = process.env[resolvedKey];\n envCache.set(resolvedKey, value);\n return value;\n }\n\n envCache.set(resolvedKey, undefined);\n return undefined;\n}\n\n/* ==========================================================================\n requireEnv\n ========================================================================== */\n\nexport function requireEnv(c: HonoContext | string, key?: string): string {\n const resolvedKey = typeof c === 'string' ? c : key!;\n const val = getEnv(c, resolvedKey);\n if (val === undefined) {\n biniLogger.error(\n `Missing required environment variable: \"${resolvedKey}\"\\n` +\n ` ${COLORS.DIM}→ In development: set it in your platform's env config.${COLORS.RESET}\\n` +\n ` ${COLORS.DIM}→ In production: set it in your hosting dashboard.${COLORS.RESET}`,\n );\n throw new Error(`[bini-env] Missing required environment variable: \"${resolvedKey}\"`);\n }\n return val;\n}\n\n/* ==========================================================================\n detectEnvFiles\n Node-only — used by the Vite plugin at build/dev time, never on edge.\n ========================================================================== */\n\nlet _envFilesCache: DetectedEnvFile[] | null = null;\nlet _cacheKey = '';\n\nexport function detectEnvFiles(projectRoot?: string): DetectedEnvFile[] {\n if (!isNodeLike()) return [];\n\n const root = projectRoot ?? process.cwd();\n const nodeEnv = process.env.NODE_ENV ?? 'production';\n const cacheKey = `${root}:${nodeEnv}`;\n if (_envFilesCache && _cacheKey === cacheKey) return _envFilesCache;\n\n let fsSync: typeof import('fs');\n let pathMod: typeof import('path');\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n fsSync = require('node:fs');\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n pathMod = require('node:path');\n } catch {\n return [];\n }\n\n const candidates = [\n '.env.local',\n `.env.${nodeEnv}.local`,\n `.env.${nodeEnv}`,\n '.env',\n ];\n\n const found: DetectedEnvFile[] = [];\n for (const file of candidates) {\n try {\n const filePath = pathMod.join(root, file);\n if (fsSync.existsSync(filePath)) found.push({ name: file, path: filePath });\n } catch { /* skip unreadable paths */ }\n }\n\n _envFilesCache = found;\n _cacheKey = cacheKey;\n return found;\n}\n\n/* ==========================================================================\n Vite plugin helpers\n ========================================================================== */\n\nfunction clearLine(): void {\n if (typeof process !== 'undefined' && process.stdout?.isTTY) {\n process.stdout.write('\\x1b[2K\\r');\n }\n}\n\nfunction printResolvedUrls(\n urls: { local: string[]; network: string[] } | null | undefined,\n): void {\n if (!urls) return;\n if (urls.local.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`,\n );\n }\n if (urls.network.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`,\n );\n }\n}\n\ntype ServerLike = ViteDevServer | PreviewServer;\n\nfunction patchPrintUrls(\n server : ServerLike,\n mode : 'dev' | 'preview',\n logo : string,\n clearViteHeader: boolean,\n getRoot : () => string,\n showEnvFiles : boolean,\n): void {\n let started = false;\n const originalPrintUrls = server.printUrls.bind(server);\n\n server.printUrls = () => {\n if (started) return;\n started = true;\n\n if (clearViteHeader) clearLine();\n originalConsoleLog(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (${mode})`);\n\n if (showEnvFiles) {\n const found = detectEnvFiles(getRoot());\n if (found.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${found.map(f => f.name).join(', ')}`,\n );\n }\n }\n\n if (clearViteHeader) {\n printResolvedUrls(server.resolvedUrls);\n } else {\n originalPrintUrls();\n }\n };\n}\n\n/* ==========================================================================\n Vite plugin\n ========================================================================== */\n\nexport function biniEnv(options: Readonly<BiniEnvPluginOptions> = {}): Plugin {\n if (options.enabled === false) {\n return { name: 'vite-plugin-bini-env' };\n }\n\n const { clearViteHeader, logo, envPrefix, loadInPreview } = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n\n let resolvedConfig: ResolvedConfig;\n const getRoot = () => resolvedConfig?.root ?? process.cwd();\n\n return {\n name: 'vite-plugin-bini-env',\n\n config(): UserConfig {\n return { envPrefix };\n },\n\n configResolved(cfg: ResolvedConfig) {\n resolvedConfig = cfg;\n },\n\n configureServer(server) {\n defer(() => envCache.clear());\n\n const envGlob = `${getRoot()}/.env*`;\n server.watcher.add(envGlob);\n\n const onEnvChange = (filePath: string) => {\n if (/\\.(swp|swo|bak|tmp)$|~$/.test(filePath)) return;\n\n biniLogger.info(\n `env file ${filePath.replace(getRoot() + '/', '')} changed — restarting server`,\n );\n\n envCache.clear();\n _envFilesCache = null;\n\n void server.restart();\n };\n\n server.watcher.on('add', onEnvChange);\n server.watcher.on('change', onEnvChange);\n\n server.httpServer?.once('close', () => {\n server.watcher.off('add', onEnvChange);\n server.watcher.off('change', onEnvChange);\n });\n\n if (clearViteHeader || logo !== BINI_LOGO) {\n patchPrintUrls(server, 'dev', logo, clearViteHeader, getRoot, true);\n }\n },\n\n configurePreviewServer(server) {\n if (loadInPreview) {\n defer(() => envCache.clear());\n }\n\n if (clearViteHeader || logo !== BINI_LOGO) {\n patchPrintUrls(server, 'preview', logo, clearViteHeader, getRoot, loadInPreview);\n }\n },\n };\n}\n\nexport type { Plugin } from 'vite';\nexport type { Context } from 'hono';"]}
package/dist/index.mjs CHANGED
@@ -1,44 +1,19 @@
1
+ import { env } from 'hono/adapter';
2
+
1
3
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
4
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
5
  }) : x)(function(x) {
4
6
  if (typeof require !== "undefined") return require.apply(this, arguments);
5
7
  throw Error('Dynamic require of "' + x + '" is not supported');
6
8
  });
7
-
8
- // src/index.ts
9
9
  function isNodeLike() {
10
- return typeof process !== "undefined" && !!process.env && typeof process.versions === "object" && // Edge runtimes (Vercel, Cloudflare) expose a minimal `process` but not
11
- // `process.versions.node`. Checking for it keeps us out of edge bundles.
12
- (typeof process.versions.node === "string" || // Bun sets process.versions.bun
13
- typeof process.versions.bun === "string");
14
- }
15
- function isDenoRuntime() {
16
- return typeof globalThis.Deno !== "undefined";
10
+ return typeof process !== "undefined" && !!process.env && typeof process.versions === "object" && (typeof process.versions.node === "string" || typeof process.versions.bun === "string");
17
11
  }
18
12
  var originalConsoleLog = console.log.bind(console);
19
13
  var originalConsoleError = console.error.bind(console);
20
14
  if (isNodeLike() && !process.env.NODE_ENV) {
21
15
  process.env.NODE_ENV = "production";
22
16
  }
23
- var _suppressionApplied = false;
24
- function suppressDotenvLogsGlobally() {
25
- if (_suppressionApplied) return;
26
- _suppressionApplied = true;
27
- if (isNodeLike()) {
28
- process.env.DOTENV_QUIET = "true";
29
- }
30
- const isDotenvNoise = (...args) => {
31
- const msg = args.join(" ");
32
- return msg.includes("[dotenv@") || msg.includes("injected env") || msg.includes("injecting env");
33
- };
34
- console.log = (...args) => {
35
- if (!isDotenvNoise(...args)) originalConsoleLog(...args);
36
- };
37
- console.error = (...args) => {
38
- if (!isDotenvNoise(...args)) originalConsoleError(...args);
39
- };
40
- }
41
- suppressDotenvLogsGlobally();
42
17
  var BINI_LOGO = "\xDF";
43
18
  var DEFAULT_ENV_PREFIX = ["BINI_", "VITE_"];
44
19
  var DEFAULT_OPTIONS = Object.freeze({
@@ -71,9 +46,6 @@ var biniLogger = {
71
46
  );
72
47
  }
73
48
  };
74
- function getDeno() {
75
- return globalThis.Deno;
76
- }
77
49
  function defer(fn) {
78
50
  if (typeof setImmediate !== "undefined") {
79
51
  setImmediate(fn);
@@ -81,95 +53,47 @@ function defer(fn) {
81
53
  Promise.resolve().then(fn);
82
54
  }
83
55
  }
84
- function getEnv(key) {
85
- if (envCache.has(key)) return envCache.get(key);
86
- const deno = getDeno();
87
- if (deno) {
56
+ var _honoContext = null;
57
+ function setContext(c) {
58
+ _honoContext = c;
59
+ }
60
+ function clearContext() {
61
+ _honoContext = null;
62
+ }
63
+ function getEnv(c, key) {
64
+ const resolvedKey = typeof c === "string" ? c : key;
65
+ const resolvedCtx = typeof c === "string" ? null : c;
66
+ const ctx = resolvedCtx ?? _honoContext;
67
+ if (ctx) {
88
68
  try {
89
- const value = deno.env.get(key);
90
- if (value !== void 0) {
91
- envCache.set(key, value);
92
- return value;
93
- }
69
+ const honoEnvs = env(ctx);
70
+ const value = honoEnvs[resolvedKey];
71
+ if (value !== void 0) return value;
94
72
  } catch {
95
73
  }
96
74
  }
75
+ if (envCache.has(resolvedKey)) return envCache.get(resolvedKey);
97
76
  if (typeof process !== "undefined" && process.env) {
98
- const value = process.env[key];
99
- if (value !== void 0) {
100
- envCache.set(key, value);
101
- return value;
102
- }
103
- }
104
- try {
105
- const metaEnv = import.meta.env;
106
- if (metaEnv) {
107
- for (const candidate of [key, `BINI_${key}`, `VITE_${key}`]) {
108
- if (metaEnv[candidate] !== void 0) {
109
- envCache.set(key, metaEnv[candidate]);
110
- return metaEnv[candidate];
111
- }
112
- }
113
- }
114
- } catch {
77
+ const value = process.env[resolvedKey];
78
+ envCache.set(resolvedKey, value);
79
+ return value;
115
80
  }
116
- envCache.set(key, void 0);
81
+ envCache.set(resolvedKey, void 0);
117
82
  return void 0;
118
83
  }
119
- function requireEnv(key) {
120
- const val = getEnv(key);
84
+ function requireEnv(c, key) {
85
+ const resolvedKey = typeof c === "string" ? c : key;
86
+ const val = getEnv(c, resolvedKey);
121
87
  if (val === void 0) {
122
88
  biniLogger.error(
123
- `Missing required environment variable: "${key}"
124
- ${"\x1B[2m" /* DIM */}\u2192 In development: add it to your .env file.${"\x1B[0m" /* RESET */}
89
+ `Missing required environment variable: "${resolvedKey}"
90
+ ${"\x1B[2m" /* DIM */}\u2192 In development: set it in your platform's env config.${"\x1B[0m" /* RESET */}
125
91
  ${"\x1B[2m" /* DIM */}\u2192 In production: set it in your hosting dashboard.${"\x1B[0m" /* RESET */}`
126
92
  );
127
- throw new Error(`[bini-env] Missing required environment variable: "${key}"`);
93
+ throw new Error(`[bini-env] Missing required environment variable: "${resolvedKey}"`);
128
94
  }
129
95
  return val;
130
96
  }
131
- var _envLoaded = false;
132
- var _loadPromise = null;
133
- async function loadEnv(projectRoot) {
134
- if (_envLoaded) return;
135
- if (_loadPromise) return _loadPromise;
136
- _loadPromise = (async () => {
137
- try {
138
- if (isDenoRuntime() || !isNodeLike()) return;
139
- const root = projectRoot ?? process.cwd();
140
- const nodeEnv = process.env.NODE_ENV ?? "production";
141
- const envFiles = [
142
- ".env",
143
- `.env.${nodeEnv}`,
144
- `.env.${nodeEnv}.local`,
145
- ".env.local"
146
- ];
147
- const [dotenvMod, fsMod, pathMod] = await Promise.all([
148
- import('dotenv'),
149
- import('fs'),
150
- import('path')
151
- ]);
152
- const dotenv = dotenvMod;
153
- const fs = fsMod.default ?? fsMod;
154
- const path = pathMod.default ?? pathMod;
155
- for (const file of envFiles) {
156
- const filePath = path.join(root, file);
157
- try {
158
- await fs.promises.access(filePath, fs.constants.R_OK);
159
- dotenv.config({ path: filePath, override: true });
160
- } catch {
161
- }
162
- }
163
- envCache.clear();
164
- _envLoaded = true;
165
- } catch (error) {
166
- biniLogger.error("Failed to load .env file", error);
167
- } finally {
168
- _loadPromise = null;
169
- }
170
- })();
171
- return _loadPromise;
172
- }
173
97
  var _envFilesCache = null;
174
98
  var _cacheKey = "";
175
99
  function detectEnvFiles(projectRoot) {
@@ -265,12 +189,7 @@ function biniEnv(options = {}) {
265
189
  resolvedConfig = cfg;
266
190
  },
267
191
  configureServer(server) {
268
- const triggerLoad = () => void loadEnv(getRoot());
269
- if (server.httpServer) {
270
- server.httpServer.once("listening", triggerLoad);
271
- } else {
272
- defer(triggerLoad);
273
- }
192
+ defer(() => envCache.clear());
274
193
  const envGlob = `${getRoot()}/.env*`;
275
194
  server.watcher.add(envGlob);
276
195
  const onEnvChange = (filePath) => {
@@ -278,8 +197,6 @@ function biniEnv(options = {}) {
278
197
  biniLogger.info(
279
198
  `env file ${filePath.replace(getRoot() + "/", "")} changed \u2014 restarting server`
280
199
  );
281
- _envLoaded = false;
282
- _loadPromise = null;
283
200
  envCache.clear();
284
201
  _envFilesCache = null;
285
202
  void server.restart();
@@ -296,12 +213,7 @@ function biniEnv(options = {}) {
296
213
  },
297
214
  configurePreviewServer(server) {
298
215
  if (loadInPreview) {
299
- const triggerLoad = () => void loadEnv(getRoot());
300
- if (server.httpServer) {
301
- server.httpServer.once("listening", triggerLoad);
302
- } else {
303
- defer(triggerLoad);
304
- }
216
+ defer(() => envCache.clear());
305
217
  }
306
218
  if (clearViteHeader || logo !== BINI_LOGO) {
307
219
  patchPrintUrls(server, "preview", logo, clearViteHeader, getRoot, loadInPreview);
@@ -310,6 +222,6 @@ function biniEnv(options = {}) {
310
222
  };
311
223
  }
312
224
 
313
- export { biniEnv, biniLogger, detectEnvFiles, getEnv, loadEnv, requireEnv, suppressDotenvLogsGlobally };
225
+ export { biniEnv, biniLogger, clearContext, detectEnvFiles, getEnv, requireEnv, setContext };
314
226
  //# sourceMappingURL=index.mjs.map
315
227
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// bini-env/src/index.ts\nimport type { Plugin, PreviewServer, ResolvedConfig, UserConfig, ViteDevServer } from 'vite';\n\n/* ==========================================================================\n Runtime detection — must run before anything else\n ========================================================================== */\n\nfunction isNodeLike(): boolean {\n return (\n typeof process !== 'undefined' &&\n !!process.env &&\n typeof process.versions === 'object' &&\n // Edge runtimes (Vercel, Cloudflare) expose a minimal `process` but not\n // `process.versions.node`. Checking for it keeps us out of edge bundles.\n (typeof process.versions.node === 'string' ||\n // Bun sets process.versions.bun\n typeof (process.versions as Record<string, unknown>).bun === 'string')\n );\n}\n\nfunction isDenoRuntime(): boolean {\n return typeof (globalThis as unknown as { Deno?: unknown }).Deno !== 'undefined';\n}\n\n/* ==========================================================================\n Capture originals FIRST — before any patching occurs\n ========================================================================== */\n\nconst originalConsoleLog = console.log.bind(console);\nconst originalConsoleError = console.error.bind(console);\n\n/* ==========================================================================\n Default NODE_ENV — must run before anything else\n ========================================================================== */\n\nif (isNodeLike() && !process.env.NODE_ENV) {\n process.env.NODE_ENV = 'production';\n}\n\n/* ==========================================================================\n DOTENV LOG SUPPRESSION\n Patched once at module load; subsequent calls are no-ops.\n ========================================================================== */\n\nlet _suppressionApplied = false;\n\nexport function suppressDotenvLogsGlobally(): void {\n if (_suppressionApplied) return;\n _suppressionApplied = true;\n\n if (isNodeLike()) {\n process.env.DOTENV_QUIET = 'true';\n }\n\n const isDotenvNoise = (...args: unknown[]): boolean => {\n const msg = args.join(' ');\n return (\n msg.includes('[dotenv@') ||\n msg.includes('injected env') ||\n msg.includes('injecting env')\n );\n };\n\n console.log = (...args: unknown[]) => {\n if (!isDotenvNoise(...args)) originalConsoleLog(...args);\n };\n\n console.error = (...args: unknown[]) => {\n if (!isDotenvNoise(...args)) originalConsoleError(...args);\n };\n}\n\n// Apply once at module load\nsuppressDotenvLogsGlobally();\n\n/* ==========================================================================\n Cross-runtime type declarations\n ========================================================================== */\n\ninterface DenoEnv {\n get(key: string): string | undefined;\n}\ninterface DenoNamespace {\n env: DenoEnv;\n}\n\n/* ==========================================================================\n Public types\n ========================================================================== */\n\nexport interface BiniEnvPluginOptions {\n readonly enabled?: boolean;\n readonly clearViteHeader?: boolean;\n readonly logo?: string;\n readonly envPrefix?: string | string[];\n readonly loadInPreview?: boolean;\n /** @deprecated Suppression is always applied at module load; this option is ignored. */\n readonly suppressDotenvLogs?: boolean;\n}\n\nexport interface DetectedEnvFile {\n readonly name: string;\n readonly path: string;\n}\n\n/* ==========================================================================\n Constants\n ========================================================================== */\n\nconst BINI_LOGO = 'ß';\nconst DEFAULT_ENV_PREFIX = ['BINI_', 'VITE_'] as const;\n\nconst DEFAULT_OPTIONS = Object.freeze({\n enabled : true,\n clearViteHeader: true,\n logo : BINI_LOGO,\n envPrefix : [...DEFAULT_ENV_PREFIX],\n loadInPreview : true,\n} satisfies Omit<Required<BiniEnvPluginOptions>, 'suppressDotenvLogs'>);\n\nconst enum COLORS {\n CYAN = '\\x1b[36m',\n RESET = '\\x1b[0m',\n GREEN = '\\x1b[32m',\n YELLOW = '\\x1b[33m',\n RED = '\\x1b[31m',\n BOLD = '\\x1b[1m',\n DIM = '\\x1b[2m',\n}\n\nconst envCache = new Map<string, string | undefined>();\n\n/* ==========================================================================\n Standalone logger\n ========================================================================== */\n\nfunction timestamp(): string {\n return `${COLORS.DIM}${new Date().toLocaleTimeString('en-US', { hour12: false })}${COLORS.RESET}`;\n}\n\nexport const biniLogger = {\n info(msg: string): void {\n originalConsoleLog(\n `${timestamp()} ${COLORS.CYAN}${COLORS.BOLD}[bini-env]${COLORS.RESET} ${msg}`,\n );\n },\n warn(msg: string): void {\n originalConsoleError(\n `${timestamp()} ${COLORS.YELLOW}${COLORS.BOLD}(!) [bini-env]${COLORS.RESET} ${COLORS.YELLOW}${msg}${COLORS.RESET}`,\n );\n },\n error(msg: string, err?: unknown): void {\n const detail = err instanceof Error\n ? `\\n ${COLORS.DIM}${err.message}${COLORS.RESET}`\n : '';\n originalConsoleError(\n `${timestamp()} ${COLORS.RED}${COLORS.BOLD}[bini-env] error${COLORS.RESET} ${msg}${detail}`,\n );\n },\n} as const;\n\n/* ==========================================================================\n Runtime helpers\n ========================================================================== */\n\nfunction getDeno(): DenoNamespace | undefined {\n return (globalThis as unknown as { Deno?: DenoNamespace }).Deno;\n}\n\n/** Schedule a task compatible with Node, Bun, Deno, and edge runtimes. */\nfunction defer(fn: () => void): void {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(fn);\n } else {\n Promise.resolve().then(fn);\n }\n}\n\n/* ==========================================================================\n getEnv\n ========================================================================== */\n\nexport function getEnv(key: string): string | undefined {\n if (envCache.has(key)) return envCache.get(key);\n\n // 1. Deno runtime\n const deno = getDeno();\n if (deno) {\n try {\n const value = deno.env.get(key);\n if (value !== undefined) {\n envCache.set(key, value);\n return value;\n }\n } catch { /* fall through */ }\n }\n\n // 2. Node.js / Bun / Edge (process.env is available on most edge runtimes too)\n if (typeof process !== 'undefined' && process.env) {\n const value = process.env[key];\n if (value !== undefined) {\n envCache.set(key, value);\n return value;\n }\n }\n\n // 3. Vite client (import.meta.env) — also checks BINI_ and VITE_ prefixed variants\n try {\n const metaEnv = import.meta.env as Record<string, string | undefined> | undefined;\n if (metaEnv) {\n for (const candidate of [key, `BINI_${key}`, `VITE_${key}`]) {\n if (metaEnv[candidate] !== undefined) {\n envCache.set(key, metaEnv[candidate]);\n return metaEnv[candidate];\n }\n }\n }\n } catch { /* import.meta.env not available in this runtime */ }\n\n envCache.set(key, undefined);\n return undefined;\n}\n\n/* ==========================================================================\n requireEnv\n ========================================================================== */\n\nexport function requireEnv(key: string): string {\n const val = getEnv(key);\n if (val === undefined) {\n biniLogger.error(\n `Missing required environment variable: \"${key}\"\\n` +\n ` ${COLORS.DIM}→ In development: add it to your .env file.${COLORS.RESET}\\n` +\n ` ${COLORS.DIM}→ In production: set it in your hosting dashboard.${COLORS.RESET}`,\n );\n throw new Error(`[bini-env] Missing required environment variable: \"${key}\"`);\n }\n return val;\n}\n\n/* ==========================================================================\n loadEnv\n - Only runs on Node-like runtimes (Node.js, Bun).\n - Edge runtimes and Deno skip entirely — they get vars from the host.\n - Idempotent; concurrent calls share one promise.\n ========================================================================== */\n\nlet _envLoaded = false;\nlet _loadPromise: Promise<void> | null = null;\n\nexport async function loadEnv(projectRoot?: string): Promise<void> {\n if (_envLoaded) return;\n if (_loadPromise) return _loadPromise;\n\n _loadPromise = (async () => {\n try {\n // Deno and edge runtimes do not use .env files — vars are injected by host\n if (isDenoRuntime() || !isNodeLike()) return;\n\n const root = projectRoot ?? process.cwd();\n const nodeEnv = process.env.NODE_ENV ?? 'production';\n\n // Load order: lowest → highest priority (later files override earlier ones)\n const envFiles = [\n '.env',\n `.env.${nodeEnv}`,\n `.env.${nodeEnv}.local`,\n '.env.local',\n ];\n\n // Dynamic import keeps `dotenv` and `fs`/`path` out of edge bundles entirely.\n // Bundlers that trace static imports (esbuild, Rollup) will NOT follow\n // a runtime-gated dynamic import when tree-shaking is enabled.\n const [dotenvMod, fsMod, pathMod] = await Promise.all([\n import('dotenv'),\n import('node:fs'),\n import('node:path'),\n ]);\n const dotenv = dotenvMod;\n const fs = fsMod.default ?? fsMod;\n const path = pathMod.default ?? pathMod;\n\n for (const file of envFiles) {\n const filePath = path.join(root, file);\n try {\n await fs.promises.access(filePath, fs.constants.R_OK);\n dotenv.config({ path: filePath, override: true });\n } catch { /* file absent — skip */ }\n }\n\n // Invalidate cache so newly loaded vars are picked up by getEnv\n envCache.clear();\n _envLoaded = true;\n\n } catch (error) {\n biniLogger.error('Failed to load .env file', error);\n // Do NOT set _envLoaded — allow a retry on the next call.\n } finally {\n _loadPromise = null;\n }\n })();\n\n return _loadPromise;\n}\n\n/* ==========================================================================\n detectEnvFiles\n Node-only utility used by the Vite plugin (build-time only, never edge).\n ========================================================================== */\n\nlet _envFilesCache: DetectedEnvFile[] | null = null;\nlet _cacheKey = '';\n\nexport function detectEnvFiles(projectRoot?: string): DetectedEnvFile[] {\n // Guard: this function uses fs synchronously; bail on non-Node runtimes.\n if (!isNodeLike()) return [];\n\n const root = projectRoot ?? process.cwd();\n const nodeEnv = process.env.NODE_ENV ?? 'production';\n const cacheKey = `${root}:${nodeEnv}`;\n if (_envFilesCache && _cacheKey === cacheKey) return _envFilesCache;\n\n // Inline the fs/path usage so no top-level import is needed.\n // This function is only ever called from the Vite plugin (configureServer /\n // configurePreviewServer), which runs in Node — never in an edge bundle.\n let fsSync: typeof import('fs');\n let pathMod: typeof import('path');\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n fsSync = require('node:fs');\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n pathMod = require('node:path');\n } catch {\n return [];\n }\n\n const candidates = [\n '.env.local',\n `.env.${nodeEnv}.local`,\n `.env.${nodeEnv}`,\n '.env',\n ];\n\n const found: DetectedEnvFile[] = [];\n for (const file of candidates) {\n try {\n const filePath = pathMod.join(root, file);\n if (fsSync.existsSync(filePath)) found.push({ name: file, path: filePath });\n } catch { /* skip unreadable paths */ }\n }\n\n _envFilesCache = found;\n _cacheKey = cacheKey;\n return found;\n}\n\n/* ==========================================================================\n Vite plugin helpers\n ========================================================================== */\n\nfunction clearLine(): void {\n if (typeof process !== 'undefined' && process.stdout?.isTTY) {\n process.stdout.write('\\x1b[2K\\r');\n }\n}\n\nfunction printResolvedUrls(\n urls: { local: string[]; network: string[] } | null | undefined,\n): void {\n if (!urls) return;\n if (urls.local.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`,\n );\n }\n if (urls.network.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`,\n );\n }\n}\n\ntype ServerLike = ViteDevServer | PreviewServer;\n\nfunction patchPrintUrls(\n server : ServerLike,\n mode : 'dev' | 'preview',\n logo : string,\n clearViteHeader: boolean,\n getRoot : () => string,\n showEnvFiles : boolean,\n): void {\n let started = false;\n const originalPrintUrls = server.printUrls.bind(server);\n\n server.printUrls = () => {\n if (started) return;\n started = true;\n\n if (clearViteHeader) clearLine();\n originalConsoleLog(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (${mode})`);\n\n if (showEnvFiles) {\n const found = detectEnvFiles(getRoot());\n if (found.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${found.map(f => f.name).join(', ')}`,\n );\n }\n }\n\n if (clearViteHeader) {\n printResolvedUrls(server.resolvedUrls);\n } else {\n originalPrintUrls();\n }\n };\n}\n\n/* ==========================================================================\n Vite plugin\n ========================================================================== */\n\nexport function biniEnv(options: Readonly<BiniEnvPluginOptions> = {}): Plugin {\n if (options.enabled === false) {\n return { name: 'vite-plugin-bini-env' };\n }\n\n const { clearViteHeader, logo, envPrefix, loadInPreview } = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n\n let resolvedConfig: ResolvedConfig;\n const getRoot = () => resolvedConfig?.root ?? process.cwd();\n\n return {\n name: 'vite-plugin-bini-env',\n\n config(): UserConfig {\n return { envPrefix };\n },\n\n configResolved(cfg: ResolvedConfig) {\n resolvedConfig = cfg;\n },\n\n configureServer(server) {\n const triggerLoad = () => void loadEnv(getRoot());\n if (server.httpServer) {\n server.httpServer.once('listening', triggerLoad);\n } else {\n defer(triggerLoad);\n }\n\n // Watch for new or changed .env files and restart the dev server so the\n // fresh variables are picked up. Chokidar (bundled with Vite) handles the\n // add/change events; we reset _envLoaded so loadEnv re-reads on restart.\n const envGlob = `${getRoot()}/.env*`;\n server.watcher.add(envGlob);\n\n const onEnvChange = (filePath: string) => {\n // Ignore editor swap/temp files (.env.swp, .env~, etc.)\n if (/\\.(swp|swo|bak|tmp)$|~$/.test(filePath)) return;\n\n biniLogger.info(\n `env file ${filePath.replace(getRoot() + '/', '')} changed — restarting server`,\n );\n\n // Reset load state so the restarted server re-reads all .env files\n _envLoaded = false;\n _loadPromise = null;\n envCache.clear();\n _envFilesCache = null;\n\n void server.restart();\n };\n\n server.watcher.on('add', onEnvChange);\n server.watcher.on('change', onEnvChange);\n\n // Remove listeners when the server closes so they don't stack across\n // restarts — Vite calls configureServer again on each restart.\n server.httpServer?.once('close', () => {\n server.watcher.off('add', onEnvChange);\n server.watcher.off('change', onEnvChange);\n });\n\n if (clearViteHeader || logo !== BINI_LOGO) {\n patchPrintUrls(server, 'dev', logo, clearViteHeader, getRoot, true);\n }\n },\n\n configurePreviewServer(server) {\n if (loadInPreview) {\n const triggerLoad = () => void loadEnv(getRoot());\n if (server.httpServer) {\n server.httpServer.once('listening', triggerLoad);\n } else {\n defer(triggerLoad);\n }\n }\n\n if (clearViteHeader || logo !== BINI_LOGO) {\n patchPrintUrls(server, 'preview', logo, clearViteHeader, getRoot, loadInPreview);\n }\n },\n };\n}\n\nexport type { Plugin } from 'vite';"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// bini-env/src/index.ts\nimport { env } from 'hono/adapter';\nimport type { Plugin, PreviewServer, ResolvedConfig, UserConfig, ViteDevServer } from 'vite';\n\n/* ==========================================================================\n Runtime detection — used by Vite plugin hooks only\n ========================================================================== */\n\nfunction isNodeLike(): boolean {\n return (\n typeof process !== 'undefined' &&\n !!process.env &&\n typeof process.versions === 'object' &&\n (typeof process.versions.node === 'string' ||\n typeof (process.versions as Record<string, unknown>).bun === 'string')\n );\n}\n\n/* ==========================================================================\n Capture originals FIRST — before any patching occurs\n ========================================================================== */\n\nconst originalConsoleLog = console.log.bind(console);\nconst originalConsoleError = console.error.bind(console);\n\n/* ==========================================================================\n Default NODE_ENV\n ========================================================================== */\n\nif (isNodeLike() && !process.env.NODE_ENV) {\n process.env.NODE_ENV = 'production';\n}\n\n/* ==========================================================================\n HonoContext duck type\n\n We intentionally do NOT import Context<E,P,I> from hono because Hono 4.12\n added a [GET_MATCH_RESULT] symbol to HonoRequest, making every\n narrowly-typed Context (e.g. Context<BlankEnv, \"/chat\", BlankInput>)\n structurally incompatible with Context<any, any, any>. A minimal duck type\n that only requires what hono/adapter's env() accesses at runtime sidesteps\n the symbol variance entirely. Consumers cast with `c as any` once at the\n call site; the single `env(ctx as any)` below is the only unsafe cast in\n the entire package.\n ========================================================================== */\n\n/** Minimal shape accepted by getEnv / requireEnv. Satisfied by any Hono Context. */\nexport type HonoContext = { env: unknown } & Record<string, unknown>;\n\n/* ==========================================================================\n Public types\n ========================================================================== */\n\nexport interface BiniEnvPluginOptions {\n readonly enabled? : boolean;\n readonly clearViteHeader?: boolean;\n readonly logo? : string;\n readonly envPrefix? : string | string[];\n readonly loadInPreview? : boolean;\n}\n\nexport interface DetectedEnvFile {\n readonly name: string;\n readonly path: string;\n}\n\n/* ==========================================================================\n Constants\n ========================================================================== */\n\nconst BINI_LOGO = 'ß';\nconst DEFAULT_ENV_PREFIX = ['BINI_', 'VITE_'] as const;\n\nconst DEFAULT_OPTIONS = Object.freeze({\n enabled : true,\n clearViteHeader: true,\n logo : BINI_LOGO,\n envPrefix : [...DEFAULT_ENV_PREFIX],\n loadInPreview : true,\n} satisfies Required<BiniEnvPluginOptions>);\n\nconst enum COLORS {\n CYAN = '\\x1b[36m',\n RESET = '\\x1b[0m',\n GREEN = '\\x1b[32m',\n YELLOW = '\\x1b[33m',\n RED = '\\x1b[31m',\n BOLD = '\\x1b[1m',\n DIM = '\\x1b[2m',\n}\n\n// Build-time only cache — never used for request-scoped Hono env() results\nconst envCache = new Map<string, string | undefined>();\n\n/* ==========================================================================\n Standalone logger\n ========================================================================== */\n\nfunction timestamp(): string {\n return `${COLORS.DIM}${new Date().toLocaleTimeString('en-US', { hour12: false })}${COLORS.RESET}`;\n}\n\nexport const biniLogger = {\n info(msg: string): void {\n originalConsoleLog(\n `${timestamp()} ${COLORS.CYAN}${COLORS.BOLD}[bini-env]${COLORS.RESET} ${msg}`,\n );\n },\n warn(msg: string): void {\n originalConsoleError(\n `${timestamp()} ${COLORS.YELLOW}${COLORS.BOLD}(!) [bini-env]${COLORS.RESET} ${COLORS.YELLOW}${msg}${COLORS.RESET}`,\n );\n },\n error(msg: string, err?: unknown): void {\n const detail = err instanceof Error\n ? `\\n ${COLORS.DIM}${err.message}${COLORS.RESET}`\n : '';\n originalConsoleError(\n `${timestamp()} ${COLORS.RED}${COLORS.BOLD}[bini-env] error${COLORS.RESET} ${msg}${detail}`,\n );\n },\n} as const;\n\n/* ==========================================================================\n Vite plugin helper\n ========================================================================== */\n\nfunction defer(fn: () => void): void {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(fn);\n } else {\n Promise.resolve().then(fn);\n }\n}\n\n/* ==========================================================================\n Module-level Hono context store\n\n Lets getEnv / requireEnv work without an explicit `c` argument at every\n call site. Register once in a global middleware:\n\n app.use('*', (c, next) => { setContext(c as any); return next(); });\n ========================================================================== */\n\nlet _honoContext: HonoContext | null = null;\n\nexport function setContext(c: HonoContext): void {\n _honoContext = c;\n}\n\nexport function clearContext(): void {\n _honoContext = null;\n}\n\n/* ==========================================================================\n getEnv\n\n Resolution order:\n 1. Explicit Hono Context (c param) — request-scoped, never cached\n 2. Stored Hono Context (setContext) — request-scoped, never cached\n 3. process.env (build-time / Vite plugin hooks — no c available)\n\n Usage:\n getEnv(c as any, 'KEY') — inside a Hono route / middleware\n getEnv('KEY') — outside request context (build-time)\n ========================================================================== */\n\nexport function getEnv(c: HonoContext | string, key?: string): string | undefined {\n const resolvedKey = typeof c === 'string' ? c : key!;\n const resolvedCtx = typeof c === 'string' ? null : c;\n\n // 1 & 2. Hono env() — covers all runtimes: CF Workers, Node, Bun, Deno, Edge\n const ctx = resolvedCtx ?? _honoContext;\n if (ctx) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const honoEnvs = env(ctx as any) as Record<string, string | undefined>;\n const value = honoEnvs[resolvedKey];\n if (value !== undefined) return value; // never cache — request-scoped\n } catch { /* context binding unavailable — fall through */ }\n }\n\n // 3. process.env — build-time only (Vite plugin hooks run outside any request)\n if (envCache.has(resolvedKey)) return envCache.get(resolvedKey);\n\n if (typeof process !== 'undefined' && process.env) {\n const value = process.env[resolvedKey];\n envCache.set(resolvedKey, value);\n return value;\n }\n\n envCache.set(resolvedKey, undefined);\n return undefined;\n}\n\n/* ==========================================================================\n requireEnv\n ========================================================================== */\n\nexport function requireEnv(c: HonoContext | string, key?: string): string {\n const resolvedKey = typeof c === 'string' ? c : key!;\n const val = getEnv(c, resolvedKey);\n if (val === undefined) {\n biniLogger.error(\n `Missing required environment variable: \"${resolvedKey}\"\\n` +\n ` ${COLORS.DIM}→ In development: set it in your platform's env config.${COLORS.RESET}\\n` +\n ` ${COLORS.DIM}→ In production: set it in your hosting dashboard.${COLORS.RESET}`,\n );\n throw new Error(`[bini-env] Missing required environment variable: \"${resolvedKey}\"`);\n }\n return val;\n}\n\n/* ==========================================================================\n detectEnvFiles\n Node-only — used by the Vite plugin at build/dev time, never on edge.\n ========================================================================== */\n\nlet _envFilesCache: DetectedEnvFile[] | null = null;\nlet _cacheKey = '';\n\nexport function detectEnvFiles(projectRoot?: string): DetectedEnvFile[] {\n if (!isNodeLike()) return [];\n\n const root = projectRoot ?? process.cwd();\n const nodeEnv = process.env.NODE_ENV ?? 'production';\n const cacheKey = `${root}:${nodeEnv}`;\n if (_envFilesCache && _cacheKey === cacheKey) return _envFilesCache;\n\n let fsSync: typeof import('fs');\n let pathMod: typeof import('path');\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n fsSync = require('node:fs');\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n pathMod = require('node:path');\n } catch {\n return [];\n }\n\n const candidates = [\n '.env.local',\n `.env.${nodeEnv}.local`,\n `.env.${nodeEnv}`,\n '.env',\n ];\n\n const found: DetectedEnvFile[] = [];\n for (const file of candidates) {\n try {\n const filePath = pathMod.join(root, file);\n if (fsSync.existsSync(filePath)) found.push({ name: file, path: filePath });\n } catch { /* skip unreadable paths */ }\n }\n\n _envFilesCache = found;\n _cacheKey = cacheKey;\n return found;\n}\n\n/* ==========================================================================\n Vite plugin helpers\n ========================================================================== */\n\nfunction clearLine(): void {\n if (typeof process !== 'undefined' && process.stdout?.isTTY) {\n process.stdout.write('\\x1b[2K\\r');\n }\n}\n\nfunction printResolvedUrls(\n urls: { local: string[]; network: string[] } | null | undefined,\n): void {\n if (!urls) return;\n if (urls.local.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`,\n );\n }\n if (urls.network.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`,\n );\n }\n}\n\ntype ServerLike = ViteDevServer | PreviewServer;\n\nfunction patchPrintUrls(\n server : ServerLike,\n mode : 'dev' | 'preview',\n logo : string,\n clearViteHeader: boolean,\n getRoot : () => string,\n showEnvFiles : boolean,\n): void {\n let started = false;\n const originalPrintUrls = server.printUrls.bind(server);\n\n server.printUrls = () => {\n if (started) return;\n started = true;\n\n if (clearViteHeader) clearLine();\n originalConsoleLog(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (${mode})`);\n\n if (showEnvFiles) {\n const found = detectEnvFiles(getRoot());\n if (found.length > 0) {\n originalConsoleLog(\n ` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${found.map(f => f.name).join(', ')}`,\n );\n }\n }\n\n if (clearViteHeader) {\n printResolvedUrls(server.resolvedUrls);\n } else {\n originalPrintUrls();\n }\n };\n}\n\n/* ==========================================================================\n Vite plugin\n ========================================================================== */\n\nexport function biniEnv(options: Readonly<BiniEnvPluginOptions> = {}): Plugin {\n if (options.enabled === false) {\n return { name: 'vite-plugin-bini-env' };\n }\n\n const { clearViteHeader, logo, envPrefix, loadInPreview } = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n\n let resolvedConfig: ResolvedConfig;\n const getRoot = () => resolvedConfig?.root ?? process.cwd();\n\n return {\n name: 'vite-plugin-bini-env',\n\n config(): UserConfig {\n return { envPrefix };\n },\n\n configResolved(cfg: ResolvedConfig) {\n resolvedConfig = cfg;\n },\n\n configureServer(server) {\n defer(() => envCache.clear());\n\n const envGlob = `${getRoot()}/.env*`;\n server.watcher.add(envGlob);\n\n const onEnvChange = (filePath: string) => {\n if (/\\.(swp|swo|bak|tmp)$|~$/.test(filePath)) return;\n\n biniLogger.info(\n `env file ${filePath.replace(getRoot() + '/', '')} changed — restarting server`,\n );\n\n envCache.clear();\n _envFilesCache = null;\n\n void server.restart();\n };\n\n server.watcher.on('add', onEnvChange);\n server.watcher.on('change', onEnvChange);\n\n server.httpServer?.once('close', () => {\n server.watcher.off('add', onEnvChange);\n server.watcher.off('change', onEnvChange);\n });\n\n if (clearViteHeader || logo !== BINI_LOGO) {\n patchPrintUrls(server, 'dev', logo, clearViteHeader, getRoot, true);\n }\n },\n\n configurePreviewServer(server) {\n if (loadInPreview) {\n defer(() => envCache.clear());\n }\n\n if (clearViteHeader || logo !== BINI_LOGO) {\n patchPrintUrls(server, 'preview', logo, clearViteHeader, getRoot, loadInPreview);\n }\n },\n };\n}\n\nexport type { Plugin } from 'vite';\nexport type { Context } from 'hono';"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bini-env",
3
- "version": "1.0.10",
4
- "description": "Universal environment variable loader and Vite plugin for Bini.js — works across Node.js, Bun, Deno, Vercel Edge, Netlify Edge, and Cloudflare Workers",
3
+ "version": "1.1.0",
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",
7
7
  "types": "./dist/index.d.ts",
@@ -31,11 +31,12 @@
31
31
  "bini",
32
32
  "bini-js",
33
33
  "bini.js",
34
+ "hono",
35
+ "hono-adapter",
34
36
  "environment",
35
37
  "env",
36
- "dotenv",
37
- "deno",
38
38
  "bun",
39
+ "deno",
39
40
  "edge-functions",
40
41
  "edge-runtime",
41
42
  "cross-runtime",
@@ -56,18 +57,20 @@
56
57
  "author": "Bini.js Team",
57
58
  "license": "MIT",
58
59
  "peerDependencies": {
60
+ "hono": ">=4.0.0",
59
61
  "vite": ">=8.0.0"
60
62
  },
61
63
  "peerDependenciesMeta": {
64
+ "hono": {
65
+ "optional": false
66
+ },
62
67
  "vite": {
63
68
  "optional": false
64
69
  }
65
70
  },
66
- "dependencies": {
67
- "dotenv": "^17.4.2"
68
- },
69
71
  "devDependencies": {
70
72
  "@types/node": "^25.6.0",
73
+ "hono": "^4.8.4",
71
74
  "tsup": "^8.5.1",
72
75
  "typescript": "^5.9.3",
73
76
  "vite": "^8.0.8"