bini-env 1.0.3 → 1.0.6
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/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/index.cjs +139 -126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -10
- package/dist/index.d.ts +48 -10
- package/dist/index.js +127 -89
- package/dist/index.js.map +1 -1
- package/package.json +32 -11
- package/Readme.md +0 -135
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Binidu Ranasinghe
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# bini-env
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
Universal environment variable loader and Vite plugin for Bini.js. Automatically loads `.env` files in development, reads env vars from the host in production, and works across Node.js, Deno, Bun, and Vite edge functions — with zero configuration.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Universal `getEnv()` / `requireEnv()`** — read env vars in any runtime (Node.js, Deno, Bun, Vite client)
|
|
14
|
+
- **Auto `.env` loading** — no manual `dotenv` setup needed in API routes
|
|
15
|
+
- **`BINI_` prefix** — replaces Vite's `VITE_` prefix with `BINI_` automatically
|
|
16
|
+
- **Branded startup banner** — replaces Vite's default header with a clean Bini.js output
|
|
17
|
+
- **Supports dev and preview modes**
|
|
18
|
+
- **Safe for edge bundlers** — dotenv is loaded via dynamic import, never statically resolved
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pnpm add bini-env
|
|
26
|
+
# or
|
|
27
|
+
npm install bini-env
|
|
28
|
+
# or
|
|
29
|
+
yarn add bini-env
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Vite Plugin Setup
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
// vite.config.ts
|
|
38
|
+
import { defineConfig } from 'vite';
|
|
39
|
+
import biniEnv from 'bini-env';
|
|
40
|
+
|
|
41
|
+
export default defineConfig({
|
|
42
|
+
plugins: [biniEnv()]
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
That's it. Once added:
|
|
47
|
+
- Your `.env` is auto-loaded for API routes in dev
|
|
48
|
+
- Client code uses `import.meta.env.BINI_*` instead of `VITE_*`
|
|
49
|
+
- The startup banner is replaced with the Bini.js header
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Environment Variables
|
|
54
|
+
|
|
55
|
+
### `.env` file
|
|
56
|
+
|
|
57
|
+
```env
|
|
58
|
+
# Client-side vars — accessible via import.meta.env.BINI_*
|
|
59
|
+
BINI_FIREBASE_API_KEY=your_key
|
|
60
|
+
BINI_FIREBASE_AUTH_DOMAIN=your_domain
|
|
61
|
+
|
|
62
|
+
# Server-side vars — accessible via getEnv() in API routes
|
|
63
|
+
SMTP_USER=user@smtp.example.com
|
|
64
|
+
SMTP_PASS=your_password
|
|
65
|
+
FROM_EMAIL=App Name <noreply@example.com>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### In API routes
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { getEnv, requireEnv } from 'bini-env';
|
|
72
|
+
|
|
73
|
+
// Returns string | undefined
|
|
74
|
+
const smtpUser = getEnv('SMTP_USER');
|
|
75
|
+
|
|
76
|
+
// Returns string — throws a clear error if missing
|
|
77
|
+
const smtpPass = requireEnv('SMTP_PASS');
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### In client code (React / Vue / etc.)
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// Works because bini-env sets envPrefix: 'BINI_' automatically
|
|
84
|
+
const apiKey = import.meta.env.BINI_FIREBASE_API_KEY;
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## How env loading works by environment
|
|
90
|
+
|
|
91
|
+
| Environment | How vars are loaded | dotenv used? |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| Dev (Node.js / bini-router) | Auto-loaded from `.env` by bini-env | ✅ Yes (automatic) |
|
|
94
|
+
| Preview (`vite preview`) | Auto-loaded from `.env` by bini-env | ✅ Yes (automatic) |
|
|
95
|
+
| Production (Netlify / Vercel) | Injected by host dashboard | ❌ No |
|
|
96
|
+
| Production (bini-server / VPS) | Set via server env or hosting panel | ❌ No |
|
|
97
|
+
| Deno / Edge Functions | Read from `Deno.env` natively | ❌ No |
|
|
98
|
+
|
|
99
|
+
You never need to import or configure `dotenv` manually.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Startup Output
|
|
104
|
+
|
|
105
|
+
**Dev mode**
|
|
106
|
+
```
|
|
107
|
+
ß Bini.js (dev)
|
|
108
|
+
➜ Environments: .env.local, .env
|
|
109
|
+
➜ Local: http://localhost:3000/
|
|
110
|
+
➜ Network: http://192.168.1.10:3000/
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Preview mode**
|
|
114
|
+
```
|
|
115
|
+
ß Bini.js (preview)
|
|
116
|
+
➜ Environments: .env.local, .env
|
|
117
|
+
➜ Local: http://localhost:4173/
|
|
118
|
+
➜ Network: http://192.168.1.10:4173/
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Plugin Options
|
|
124
|
+
|
|
125
|
+
| Option | Type | Default | Description |
|
|
126
|
+
|---|---|---|---|
|
|
127
|
+
| `enabled` | `boolean` | `true` | Enable or disable the plugin |
|
|
128
|
+
| `clearViteHeader` | `boolean` | `true` | Replace Vite's default startup header |
|
|
129
|
+
| `logo` | `string` | `'ß'` | Custom logo or text shown in the banner |
|
|
130
|
+
| `envPrefix` | `string` | `'BINI_'` | Prefix for client-side env vars in `import.meta.env` |
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
biniEnv({
|
|
134
|
+
logo: '🚀',
|
|
135
|
+
clearViteHeader: true,
|
|
136
|
+
envPrefix: 'BINI_', // change to 'VITE_' to keep Vite's default
|
|
137
|
+
})
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Detected `.env` Files
|
|
143
|
+
|
|
144
|
+
The plugin checks for the following files in your project root (in priority order):
|
|
145
|
+
|
|
146
|
+
1. `.env.local`
|
|
147
|
+
2. `.env.[NODE_ENV].local`
|
|
148
|
+
3. `.env.[NODE_ENV]`
|
|
149
|
+
4. `.env`
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## API Reference
|
|
154
|
+
|
|
155
|
+
### `getEnv(key: string): string | undefined`
|
|
156
|
+
|
|
157
|
+
Read an environment variable in any runtime. Checks `Deno.env` → `process.env` → `import.meta.env` in order.
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { getEnv } from 'bini-env';
|
|
161
|
+
|
|
162
|
+
const smtpUser = getEnv('SMTP_USER');
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### `requireEnv(key: string): string`
|
|
166
|
+
|
|
167
|
+
Same as `getEnv` but throws a descriptive error if the variable is missing or empty. Use this for required secrets.
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import { requireEnv } from 'bini-env';
|
|
171
|
+
|
|
172
|
+
const smtpPass = requireEnv('SMTP_PASS');
|
|
173
|
+
// Throws: [bini-env] Missing required environment variable: "SMTP_PASS".
|
|
174
|
+
// → In development: add it to your .env file.
|
|
175
|
+
// → In production: add it to your hosting dashboard environment variables.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### `loadEnv(projectRoot?: string): Promise<void>`
|
|
179
|
+
|
|
180
|
+
Manually trigger `.env` loading. Called automatically by the Vite plugin — you should not need this.
|
|
181
|
+
|
|
182
|
+
### `detectEnvFiles(projectRoot?: string): DetectedEnvFile[]`
|
|
183
|
+
|
|
184
|
+
Scan a directory for `.env` files and return an array of matches.
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { detectEnvFiles } from 'bini-env';
|
|
188
|
+
|
|
189
|
+
const files = detectEnvFiles('/my/project');
|
|
190
|
+
// [{ name: '.env.local', path: '/my/project/.env.local' }, ...]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Types
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
interface BiniEnvPluginOptions {
|
|
199
|
+
enabled?: boolean;
|
|
200
|
+
clearViteHeader?: boolean;
|
|
201
|
+
logo?: string;
|
|
202
|
+
envPrefix?: string;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
interface DetectedEnvFile {
|
|
206
|
+
name: string;
|
|
207
|
+
path: string;
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Compatibility
|
|
214
|
+
|
|
215
|
+
| Runtime | Supported |
|
|
216
|
+
|---|---|
|
|
217
|
+
| Node.js 18+ | ✅ |
|
|
218
|
+
| Bun | ✅ |
|
|
219
|
+
| Deno / Edge Functions | ✅ |
|
|
220
|
+
| Vite 7 | ✅ |
|
|
221
|
+
| Vite 8 | ✅ |
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -1,166 +1,177 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
var
|
|
9
|
-
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
|
|
6
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
|
|
8
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
9
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
29
10
|
|
|
30
11
|
// src/index.ts
|
|
31
|
-
var index_exports = {};
|
|
32
|
-
__export(index_exports, {
|
|
33
|
-
default: () => biniEnvPlugin,
|
|
34
|
-
detectEnvFiles: () => detectEnvFiles,
|
|
35
|
-
formatEnvFilesForDisplay: () => formatEnvFilesForDisplay
|
|
36
|
-
});
|
|
37
|
-
module.exports = __toCommonJS(index_exports);
|
|
38
|
-
var import_fs = __toESM(require("fs"), 1);
|
|
39
|
-
var import_path = __toESM(require("path"), 1);
|
|
40
12
|
var BINI_LOGO = "\xDF";
|
|
13
|
+
var DEFAULT_ENV_PREFIX = "BINI_";
|
|
41
14
|
var DEFAULT_OPTIONS = {
|
|
42
15
|
enabled: true,
|
|
43
16
|
clearViteHeader: true,
|
|
44
|
-
logo: BINI_LOGO
|
|
17
|
+
logo: BINI_LOGO,
|
|
18
|
+
envPrefix: DEFAULT_ENV_PREFIX
|
|
45
19
|
};
|
|
46
20
|
var COLORS = {
|
|
47
21
|
CYAN: "\x1B[36m",
|
|
48
22
|
RESET: "\x1B[0m",
|
|
49
|
-
GREEN: "\x1B[32m"
|
|
50
|
-
YELLOW: "\x1B[33m",
|
|
51
|
-
DIM: "\x1B[2m"
|
|
23
|
+
GREEN: "\x1B[32m"
|
|
52
24
|
};
|
|
25
|
+
function getEnv(key) {
|
|
26
|
+
const deno = globalThis.Deno;
|
|
27
|
+
if (deno) {
|
|
28
|
+
try {
|
|
29
|
+
const val = deno.env.get(key);
|
|
30
|
+
if (val !== void 0) return val;
|
|
31
|
+
} catch {
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (typeof process !== "undefined" && process.env) {
|
|
35
|
+
if (process.env[key] !== void 0) return process.env[key];
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const metaEnv = undefined;
|
|
39
|
+
if (metaEnv) {
|
|
40
|
+
if (metaEnv[key] !== void 0) return metaEnv[key];
|
|
41
|
+
if (metaEnv[`BINI_${key}`] !== void 0) return metaEnv[`BINI_${key}`];
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
function requireEnv(key) {
|
|
48
|
+
const val = getEnv(key);
|
|
49
|
+
if (!val) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`[bini-env] Missing required environment variable: "${key}".
|
|
52
|
+
\u2192 In development: add it to your .env file.
|
|
53
|
+
\u2192 In production: add it to your hosting dashboard environment variables.`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return val;
|
|
57
|
+
}
|
|
58
|
+
var _envLoaded = false;
|
|
59
|
+
async function loadEnv(projectRoot) {
|
|
60
|
+
if (_envLoaded) return;
|
|
61
|
+
if (globalThis.Deno) {
|
|
62
|
+
_envLoaded = true;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (typeof process === "undefined" || !process.env) {
|
|
66
|
+
_envLoaded = true;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (process.env.NODE_ENV === "production") {
|
|
70
|
+
_envLoaded = true;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const root = projectRoot ?? process.cwd();
|
|
75
|
+
const envPath = path__default.default.join(root, ".env");
|
|
76
|
+
if (!fs__default.default.existsSync(envPath)) {
|
|
77
|
+
_envLoaded = true;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const dotenv = await import('dotenv');
|
|
81
|
+
dotenv.config({ path: envPath });
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
_envLoaded = true;
|
|
85
|
+
}
|
|
53
86
|
function detectEnvFiles(projectRoot = process.cwd()) {
|
|
54
|
-
const nodeEnv = process.env.NODE_ENV
|
|
55
|
-
const
|
|
87
|
+
const nodeEnv = process.env.NODE_ENV ?? "development";
|
|
88
|
+
const candidates = [
|
|
56
89
|
".env.local",
|
|
57
90
|
`.env.${nodeEnv}.local`,
|
|
58
91
|
`.env.${nodeEnv}`,
|
|
59
92
|
".env"
|
|
60
93
|
];
|
|
61
94
|
const found = [];
|
|
62
|
-
for (const file of
|
|
63
|
-
const filePath =
|
|
64
|
-
if (
|
|
65
|
-
found.push({
|
|
66
|
-
name: file,
|
|
67
|
-
path: filePath
|
|
68
|
-
});
|
|
95
|
+
for (const file of candidates) {
|
|
96
|
+
const filePath = path__default.default.join(projectRoot, file);
|
|
97
|
+
if (fs__default.default.existsSync(filePath)) {
|
|
98
|
+
found.push({ name: file, path: filePath });
|
|
69
99
|
}
|
|
70
100
|
}
|
|
71
101
|
return found;
|
|
72
102
|
}
|
|
73
|
-
function formatEnvFilesForDisplay(envFiles) {
|
|
74
|
-
if (envFiles.length === 0) {
|
|
75
|
-
return "";
|
|
76
|
-
}
|
|
77
|
-
const envString = envFiles.map((f) => f.name).join(", ");
|
|
78
|
-
return `${COLORS.GREEN}\u279C${COLORS.RESET} Environments: ${envString}`;
|
|
79
|
-
}
|
|
80
103
|
function clearLine() {
|
|
81
104
|
process.stdout.write("\x1B[2K\r");
|
|
82
105
|
}
|
|
83
|
-
function
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
106
|
+
function printResolvedUrls(urls) {
|
|
107
|
+
if (!urls) return;
|
|
108
|
+
if (urls.local.length > 0)
|
|
109
|
+
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);
|
|
110
|
+
if (urls.network.length > 0)
|
|
111
|
+
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);
|
|
112
|
+
}
|
|
113
|
+
function biniEnv(options = {}) {
|
|
114
|
+
const resolvedOptions = Object.freeze({ ...DEFAULT_OPTIONS, ...options });
|
|
115
|
+
const { enabled, clearViteHeader, logo, envPrefix } = resolvedOptions;
|
|
116
|
+
let resolvedConfig;
|
|
91
117
|
let serverStarted = false;
|
|
92
118
|
let previewStarted = false;
|
|
93
119
|
return {
|
|
94
120
|
name: "vite-plugin-bini-env",
|
|
95
121
|
apply: "serve",
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
122
|
+
// Set BINI_ as the env prefix so import.meta.env.BINI_* works in client code
|
|
123
|
+
config() {
|
|
124
|
+
return { envPrefix };
|
|
125
|
+
},
|
|
126
|
+
configResolved(cfg) {
|
|
127
|
+
resolvedConfig = cfg;
|
|
101
128
|
},
|
|
102
129
|
configureServer(server) {
|
|
103
130
|
if (!enabled) return;
|
|
104
|
-
|
|
131
|
+
if (server.httpServer) {
|
|
132
|
+
server.httpServer.once("listening", () => {
|
|
133
|
+
void loadEnv(resolvedConfig?.root ?? process.cwd());
|
|
134
|
+
});
|
|
135
|
+
} else {
|
|
136
|
+
void loadEnv(resolvedConfig?.root ?? process.cwd());
|
|
137
|
+
}
|
|
138
|
+
const originalPrintUrls = server.printUrls.bind(server);
|
|
105
139
|
server.printUrls = () => {
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
console.log(`
|
|
140
|
+
if (serverStarted) return;
|
|
141
|
+
serverStarted = true;
|
|
142
|
+
if (clearViteHeader) clearLine();
|
|
143
|
+
console.log(`
|
|
112
144
|
${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (dev)`);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (urls) {
|
|
123
|
-
if (urls.local.length > 0) {
|
|
124
|
-
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);
|
|
125
|
-
}
|
|
126
|
-
if (urls.network.length > 0) {
|
|
127
|
-
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
145
|
+
const found = detectEnvFiles(resolvedConfig?.root);
|
|
146
|
+
if (found.length > 0) {
|
|
147
|
+
const envString = found.map((f) => f.name).join(", ");
|
|
148
|
+
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Environments: ${envString}`);
|
|
149
|
+
}
|
|
150
|
+
if (!clearViteHeader) {
|
|
151
|
+
originalPrintUrls();
|
|
152
|
+
} else {
|
|
153
|
+
printResolvedUrls(server.resolvedUrls);
|
|
131
154
|
}
|
|
132
155
|
};
|
|
133
156
|
},
|
|
134
157
|
configurePreviewServer(server) {
|
|
135
158
|
if (!enabled) return;
|
|
136
|
-
|
|
137
|
-
const originalPrintUrls = server.printUrls;
|
|
159
|
+
const originalPrintUrls = server.printUrls.bind(server);
|
|
138
160
|
server.printUrls = () => {
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
console.log(`
|
|
161
|
+
if (previewStarted) return;
|
|
162
|
+
previewStarted = true;
|
|
163
|
+
if (clearViteHeader) clearLine();
|
|
164
|
+
console.log(`
|
|
145
165
|
${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (preview)`);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (urls) {
|
|
156
|
-
if (urls.local.length > 0) {
|
|
157
|
-
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);
|
|
158
|
-
}
|
|
159
|
-
if (urls.network.length > 0) {
|
|
160
|
-
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
166
|
+
const found = detectEnvFiles(resolvedConfig?.root);
|
|
167
|
+
if (found.length > 0) {
|
|
168
|
+
const envString = found.map((f) => f.name).join(", ");
|
|
169
|
+
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Environments: ${envString}`);
|
|
170
|
+
}
|
|
171
|
+
if (!clearViteHeader) {
|
|
172
|
+
originalPrintUrls();
|
|
173
|
+
} else {
|
|
174
|
+
printResolvedUrls(server.resolvedUrls);
|
|
164
175
|
}
|
|
165
176
|
};
|
|
166
177
|
},
|
|
@@ -170,9 +181,11 @@ function biniEnvPlugin(options = {}) {
|
|
|
170
181
|
}
|
|
171
182
|
};
|
|
172
183
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
184
|
+
|
|
185
|
+
exports.biniEnv = biniEnv;
|
|
186
|
+
exports.detectEnvFiles = detectEnvFiles;
|
|
187
|
+
exports.getEnv = getEnv;
|
|
188
|
+
exports.loadEnv = loadEnv;
|
|
189
|
+
exports.requireEnv = requireEnv;
|
|
190
|
+
//# sourceMappingURL=index.cjs.map
|
|
178
191
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// src/index.ts\r\nimport fs from 'fs';\r\nimport path from 'path';\r\nimport type { Plugin, ResolvedConfig } from 'vite';\r\n\r\n// Types\r\nexport interface BiniEnvPluginOptions {\r\n /**\r\n * Enable/disable the plugin\r\n * @default true\r\n * @readonly\r\n */\r\n readonly enabled?: boolean;\r\n \r\n /**\r\n * Remove Vite's default header\r\n * @default true\r\n * @readonly\r\n */\r\n readonly clearViteHeader?: boolean;\r\n \r\n /**\r\n * Custom logo/text to display\r\n * @default 'ß'\r\n * @readonly\r\n */\r\n readonly logo?: string;\r\n}\r\n\r\nexport interface DetectedEnvFile {\r\n readonly name: string;\r\n readonly path: string;\r\n}\r\n\r\n// Constants\r\nconst BINI_LOGO = 'ß' as const;\r\nconst DEFAULT_OPTIONS = {\r\n enabled: true,\r\n clearViteHeader: true,\r\n logo: BINI_LOGO,\r\n} as const;\r\n\r\n// Color definitions\r\nconst COLORS = {\r\n CYAN: '\\x1b[36m',\r\n RESET: '\\x1b[0m',\r\n GREEN: '\\x1b[32m',\r\n YELLOW: '\\x1b[33m',\r\n DIM: '\\x1b[2m'\r\n} as const;\r\n\r\n/**\r\n * Detect which .env files exist in project root\r\n */\r\nexport function detectEnvFiles(projectRoot: string = process.cwd()): DetectedEnvFile[] {\r\n const nodeEnv = process.env.NODE_ENV || 'development';\r\n\r\n const envFiles = [\r\n '.env.local',\r\n `.env.${nodeEnv}.local`,\r\n `.env.${nodeEnv}`,\r\n '.env'\r\n ] as const;\r\n\r\n const found: DetectedEnvFile[] = [];\r\n\r\n for (const file of envFiles) {\r\n const filePath = path.join(projectRoot, file);\r\n if (fs.existsSync(filePath)) {\r\n found.push({\r\n name: file,\r\n path: filePath\r\n });\r\n }\r\n }\r\n\r\n return found;\r\n}\r\n\r\n/**\r\n * Format environment files for console display\r\n */\r\nexport function formatEnvFilesForDisplay(envFiles: DetectedEnvFile[]): string {\r\n if (envFiles.length === 0) {\r\n return '';\r\n }\r\n\r\n const envString = envFiles.map(f => f.name).join(', ');\r\n return `${COLORS.GREEN}➜${COLORS.RESET} Environments: ${envString}`;\r\n}\r\n\r\n/**\r\n * Clear the current line in console\r\n */\r\nfunction clearLine(): void {\r\n process.stdout.write('\\x1b[2K\\r');\r\n}\r\n\r\n/**\r\n * Main plugin function\r\n */\r\nexport default function biniEnvPlugin(options: Readonly<BiniEnvPluginOptions> = {}): Plugin {\r\n // Merge with defaults — user cannot override core behaviour\r\n const resolvedOptions = Object.freeze({\r\n ...DEFAULT_OPTIONS,\r\n ...options,\r\n });\r\n\r\n const { enabled, clearViteHeader, logo } = resolvedOptions;\r\n\r\n let config: ResolvedConfig;\r\n let isPreviewMode = false;\r\n let serverStarted = false;\r\n let previewStarted = false;\r\n\r\n return {\r\n name: 'vite-plugin-bini-env',\r\n \r\n apply: 'serve',\r\n \r\n configResolved(resolvedConfig: ResolvedConfig) {\r\n config = resolvedConfig;\r\n \r\n if (resolvedConfig.command === 'serve') {\r\n isPreviewMode = process.env.VITE_PREVIEW === 'true' || \r\n process.argv.includes('preview') ||\r\n false;\r\n }\r\n },\r\n\r\n configureServer(server) {\r\n if (!enabled) return;\r\n\r\n const originalPrintUrls = server.printUrls;\r\n \r\n server.printUrls = () => {\r\n if (!serverStarted) {\r\n serverStarted = true;\r\n \r\n if (clearViteHeader) {\r\n clearLine();\r\n }\r\n \r\n console.log(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (dev)`);\r\n\r\n const found = detectEnvFiles(config.root);\r\n if (found.length > 0) {\r\n const envString = found.map(f => f.name).join(', ');\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${envString}`);\r\n }\r\n \r\n if (!clearViteHeader) {\r\n originalPrintUrls.call(server);\r\n } else {\r\n const urls = server.resolvedUrls;\r\n if (urls) {\r\n if (urls.local.length > 0) {\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);\r\n }\r\n if (urls.network.length > 0) {\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);\r\n }\r\n }\r\n }\r\n }\r\n };\r\n },\r\n\r\n configurePreviewServer(server) {\r\n if (!enabled) return;\r\n \r\n isPreviewMode = true;\r\n \r\n const originalPrintUrls = server.printUrls;\r\n \r\n server.printUrls = () => {\r\n if (!previewStarted) {\r\n previewStarted = true;\r\n \r\n if (clearViteHeader) {\r\n clearLine();\r\n }\r\n \r\n console.log(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (preview)`);\r\n\r\n const found = detectEnvFiles(config.root);\r\n if (found.length > 0) {\r\n const envString = found.map(f => f.name).join(', ');\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${envString}`);\r\n }\r\n \r\n if (!clearViteHeader) {\r\n originalPrintUrls.call(server);\r\n } else {\r\n const urls = server.resolvedUrls;\r\n if (urls) {\r\n if (urls.local.length > 0) {\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);\r\n }\r\n if (urls.network.length > 0) {\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);\r\n }\r\n }\r\n }\r\n }\r\n };\r\n },\r\n\r\n buildEnd() {\r\n serverStarted = false;\r\n previewStarted = false;\r\n }\r\n };\r\n}\r\n\r\nexport type { Plugin } from 'vite';"],"mappings":"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","names":["path","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["path","fs"],"mappings":"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","file":"index.cjs","sourcesContent":["// src/index.ts\nimport fs from 'fs';\nimport path from 'path';\nimport type { Plugin, ResolvedConfig, UserConfig } from 'vite';\n\n/* ==========================================================================\n Global type declarations for cross-runtime compatibility\n ========================================================================== */\n\n// Deno runtime type — declared as an interface so we can safely cast\n// without relying on a global that TypeScript doesn't know about\ninterface DenoEnv {\n get(key: string): string | undefined;\n toObject(): Record<string, string>;\n}\ninterface DenoNamespace {\n env: DenoEnv;\n}\n\n// Vite augments ImportMeta with .env\n// Using triple-slash reference so it works both inside and outside Vite projects\n/// <reference types=\"vite/client\" />\n\n/* ==========================================================================\n Types\n ========================================================================== */\n\nexport interface BiniEnvPluginOptions {\n /**\n * Enable/disable the plugin\n * @default true\n */\n readonly enabled?: boolean;\n\n /**\n * Remove Vite's default header\n * @default true\n */\n readonly clearViteHeader?: boolean;\n\n /**\n * Custom logo/text to display\n * @default 'ß'\n */\n readonly logo?: string;\n\n /**\n * Override the env var prefix exposed to client code.\n * Defaults to 'BINI_' — so BINI_MY_VAR is accessible via import.meta.env.BINI_MY_VAR\n * Set to 'VITE_' to keep Vite's default behaviour.\n * @default 'BINI_'\n */\n readonly envPrefix?: string;\n}\n\nexport interface DetectedEnvFile {\n readonly name: string;\n readonly path: string;\n}\n\n/* ==========================================================================\n Constants\n ========================================================================== */\n\nconst BINI_LOGO = 'ß' as const;\nconst DEFAULT_ENV_PREFIX = 'BINI_' as const;\n\nconst DEFAULT_OPTIONS = {\n enabled: true,\n clearViteHeader: true,\n logo: BINI_LOGO,\n envPrefix: DEFAULT_ENV_PREFIX,\n} as const;\n\nconst COLORS = {\n CYAN: '\\x1b[36m',\n RESET: '\\x1b[0m',\n GREEN: '\\x1b[32m',\n} as const;\n\n/* ==========================================================================\n getEnv — Universal env var accessor\n Works in: Node.js, Deno (edge functions), Bun, Vite client\n ========================================================================== */\n\n/**\n * Read an environment variable in any runtime.\n *\n * Priority order:\n * 1. Deno.env — Netlify edge functions / Deno runtime\n * 2. process.env — Node.js / Bun / bini-server\n * 3. import.meta.env — Vite client (BINI_-prefixed vars)\n *\n * Usage in API routes:\n * import { getEnv } from 'bini-env';\n * const smtpUser = getEnv('SMTP_USER');\n */\nexport function getEnv(key: string): string | undefined {\n // 1. Deno runtime (Netlify edge functions)\n const deno = (globalThis as unknown as { Deno?: DenoNamespace }).Deno;\n if (deno) {\n try {\n const val = deno.env.get(key);\n if (val !== undefined) return val;\n } catch {\n // Deno env access denied — fall through\n }\n }\n\n // 2. Node.js / Bun / bini-server\n if (typeof process !== 'undefined' && process.env) {\n if (process.env[key] !== undefined) return process.env[key];\n }\n\n // 3. Vite injected (import.meta.env) — BINI_-prefixed client vars\n // Wrapped in try/catch because import.meta.env doesn't exist in Node/Deno\n try {\n const metaEnv = import.meta.env as Record<string, string | undefined> | undefined;\n if (metaEnv) {\n if (metaEnv[key] !== undefined) return metaEnv[key];\n // Try with BINI_ prefix automatically\n if (metaEnv[`BINI_${key}`] !== undefined) return metaEnv[`BINI_${key}`];\n }\n } catch {\n // import.meta.env not available in this runtime — ignore\n }\n\n return undefined;\n}\n\n/**\n * Read an environment variable and throw if it's missing or empty.\n * Use this for required secrets so you get a clear error at startup\n * instead of a cryptic crash later.\n *\n * Usage:\n * const smtpPass = requireEnv('SMTP_PASS');\n */\nexport function requireEnv(key: string): string {\n const val = getEnv(key);\n if (!val) {\n throw new Error(\n `[bini-env] Missing required environment variable: \"${key}\".\\n` +\n ` → In development: add it to your .env file.\\n` +\n ` → In production: add it to your hosting dashboard environment variables.`\n );\n }\n return val;\n}\n\n/* ==========================================================================\n loadEnv — Auto dotenv loader for bini-router API routes (Node.js only)\n Called internally by the Vite plugin. Safe to call multiple times.\n ========================================================================== */\n\nlet _envLoaded = false;\n\n/**\n * Auto-load .env into process.env for Node.js API route contexts.\n *\n * Behaviour by environment:\n * - Deno (edge functions) → no-op, Deno/Netlify injects env natively\n * - NODE_ENV=production → no-op, host injects env vars automatically\n * - Node.js dev → loads .env via dotenv (dynamic import, safe for bundlers)\n *\n * Called automatically by bini-env Vite plugin. You should not need to call this manually.\n */\nexport async function loadEnv(projectRoot?: string): Promise<void> {\n // Already loaded — skip\n if (_envLoaded) return;\n\n // Deno runtime — env is handled natively, skip\n if ((globalThis as unknown as { Deno?: DenoNamespace }).Deno) {\n _envLoaded = true;\n return;\n }\n\n // Not in a Node-like runtime — skip\n if (typeof process === 'undefined' || !process.env) {\n _envLoaded = true;\n return;\n }\n\n // Production — host injects env vars, dotenv not needed\n if (process.env.NODE_ENV === 'production') {\n _envLoaded = true;\n return;\n }\n\n try {\n const root = projectRoot ?? process.cwd();\n const envPath = path.join(root, '.env');\n\n if (!fs.existsSync(envPath)) {\n _envLoaded = true;\n return;\n }\n\n // Dynamic import so Deno/edge bundlers never try to statically resolve dotenv\n const dotenv = await import('dotenv');\n dotenv.config({ path: envPath });\n } catch {\n // dotenv not installed or read failed — silently skip.\n // requireEnv() will surface clear errors if vars are missing when used.\n }\n\n _envLoaded = true;\n}\n\n/* ==========================================================================\n detectEnvFiles — used by the Vite plugin display\n ========================================================================== */\n\n/**\n * Detect which .env files exist in the project root, in Vite's priority order.\n */\nexport function detectEnvFiles(projectRoot: string = process.cwd()): DetectedEnvFile[] {\n const nodeEnv = process.env.NODE_ENV ?? 'development';\n\n const candidates = [\n '.env.local',\n `.env.${nodeEnv}.local`,\n `.env.${nodeEnv}`,\n '.env',\n ] as const;\n\n const found: DetectedEnvFile[] = [];\n\n for (const file of candidates) {\n const filePath = path.join(projectRoot, file);\n if (fs.existsSync(filePath)) {\n found.push({ name: file, path: filePath });\n }\n }\n\n return found;\n}\n\n/* ==========================================================================\n Vite plugin\n ========================================================================== */\n\nfunction clearLine(): void {\n process.stdout.write('\\x1b[2K\\r');\n}\n\nfunction printResolvedUrls(urls: { local: string[]; network: string[] } | null | undefined): void {\n if (!urls) return;\n if (urls.local.length > 0)\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);\n if (urls.network.length > 0)\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);\n}\n\n/**\n * Bini.js Vite plugin.\n *\n * What it does:\n * - Sets envPrefix to 'BINI_' so client code uses import.meta.env.BINI_MY_VAR\n * - Auto-loads .env for API routes in dev via loadEnv()\n * - Replaces Vite's startup output with the Bini.js branded header\n */\nexport function biniEnv(options: Readonly<BiniEnvPluginOptions> = {}): Plugin {\n const resolvedOptions = Object.freeze({ ...DEFAULT_OPTIONS, ...options });\n const { enabled, clearViteHeader, logo, envPrefix } = resolvedOptions;\n\n let resolvedConfig: ResolvedConfig;\n let serverStarted = false;\n let previewStarted = false;\n\n return {\n name: 'vite-plugin-bini-env',\n\n apply: 'serve',\n\n // Set BINI_ as the env prefix so import.meta.env.BINI_* works in client code\n config(): UserConfig {\n return { envPrefix };\n },\n\n configResolved(cfg: ResolvedConfig) {\n resolvedConfig = cfg;\n },\n\n configureServer(server) {\n if (!enabled) return;\n\n // Auto-load .env after server starts — guarantees resolvedConfig is available\n // Falls back to immediate call in middleware mode where httpServer is null\n if (server.httpServer) {\n server.httpServer.once('listening', () => {\n void loadEnv(resolvedConfig?.root ?? process.cwd());\n });\n } else {\n // Middleware mode — httpServer is null, call immediately\n void loadEnv(resolvedConfig?.root ?? process.cwd());\n }\n\n const originalPrintUrls = server.printUrls.bind(server);\n\n server.printUrls = () => {\n if (serverStarted) return;\n serverStarted = true;\n\n if (clearViteHeader) clearLine();\n console.log(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (dev)`);\n\n const found = detectEnvFiles(resolvedConfig?.root);\n if (found.length > 0) {\n const envString = found.map((f) => f.name).join(', ');\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${envString}`);\n }\n\n if (!clearViteHeader) {\n originalPrintUrls();\n } else {\n printResolvedUrls(server.resolvedUrls);\n }\n };\n },\n\n configurePreviewServer(server) {\n if (!enabled) return;\n\n const originalPrintUrls = server.printUrls.bind(server);\n\n server.printUrls = () => {\n if (previewStarted) return;\n previewStarted = true;\n\n if (clearViteHeader) clearLine();\n console.log(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (preview)`);\n\n const found = detectEnvFiles(resolvedConfig?.root);\n if (found.length > 0) {\n const envString = found.map((f) => f.name).join(', ');\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${envString}`);\n }\n\n if (!clearViteHeader) {\n originalPrintUrls();\n } else {\n printResolvedUrls(server.resolvedUrls);\n }\n };\n },\n\n buildEnd() {\n serverStarted = false;\n previewStarted = false;\n },\n };\n}\n\n// Named export: import { biniEnv } from 'bini-env'\nexport type { Plugin } from 'vite';"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -5,37 +5,75 @@ interface BiniEnvPluginOptions {
|
|
|
5
5
|
/**
|
|
6
6
|
* Enable/disable the plugin
|
|
7
7
|
* @default true
|
|
8
|
-
* @readonly
|
|
9
8
|
*/
|
|
10
9
|
readonly enabled?: boolean;
|
|
11
10
|
/**
|
|
12
11
|
* Remove Vite's default header
|
|
13
12
|
* @default true
|
|
14
|
-
* @readonly
|
|
15
13
|
*/
|
|
16
14
|
readonly clearViteHeader?: boolean;
|
|
17
15
|
/**
|
|
18
16
|
* Custom logo/text to display
|
|
19
17
|
* @default 'ß'
|
|
20
|
-
* @readonly
|
|
21
18
|
*/
|
|
22
19
|
readonly logo?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Override the env var prefix exposed to client code.
|
|
22
|
+
* Defaults to 'BINI_' — so BINI_MY_VAR is accessible via import.meta.env.BINI_MY_VAR
|
|
23
|
+
* Set to 'VITE_' to keep Vite's default behaviour.
|
|
24
|
+
* @default 'BINI_'
|
|
25
|
+
*/
|
|
26
|
+
readonly envPrefix?: string;
|
|
23
27
|
}
|
|
24
28
|
interface DetectedEnvFile {
|
|
25
29
|
readonly name: string;
|
|
26
30
|
readonly path: string;
|
|
27
31
|
}
|
|
28
32
|
/**
|
|
29
|
-
*
|
|
33
|
+
* Read an environment variable in any runtime.
|
|
34
|
+
*
|
|
35
|
+
* Priority order:
|
|
36
|
+
* 1. Deno.env — Netlify edge functions / Deno runtime
|
|
37
|
+
* 2. process.env — Node.js / Bun / bini-server
|
|
38
|
+
* 3. import.meta.env — Vite client (BINI_-prefixed vars)
|
|
39
|
+
*
|
|
40
|
+
* Usage in API routes:
|
|
41
|
+
* import { getEnv } from 'bini-env';
|
|
42
|
+
* const smtpUser = getEnv('SMTP_USER');
|
|
30
43
|
*/
|
|
31
|
-
declare function
|
|
44
|
+
declare function getEnv(key: string): string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Read an environment variable and throw if it's missing or empty.
|
|
47
|
+
* Use this for required secrets so you get a clear error at startup
|
|
48
|
+
* instead of a cryptic crash later.
|
|
49
|
+
*
|
|
50
|
+
* Usage:
|
|
51
|
+
* const smtpPass = requireEnv('SMTP_PASS');
|
|
52
|
+
*/
|
|
53
|
+
declare function requireEnv(key: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Auto-load .env into process.env for Node.js API route contexts.
|
|
56
|
+
*
|
|
57
|
+
* Behaviour by environment:
|
|
58
|
+
* - Deno (edge functions) → no-op, Deno/Netlify injects env natively
|
|
59
|
+
* - NODE_ENV=production → no-op, host injects env vars automatically
|
|
60
|
+
* - Node.js dev → loads .env via dotenv (dynamic import, safe for bundlers)
|
|
61
|
+
*
|
|
62
|
+
* Called automatically by bini-env Vite plugin. You should not need to call this manually.
|
|
63
|
+
*/
|
|
64
|
+
declare function loadEnv(projectRoot?: string): Promise<void>;
|
|
32
65
|
/**
|
|
33
|
-
*
|
|
66
|
+
* Detect which .env files exist in the project root, in Vite's priority order.
|
|
34
67
|
*/
|
|
35
|
-
declare function
|
|
68
|
+
declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
|
|
36
69
|
/**
|
|
37
|
-
*
|
|
70
|
+
* Bini.js Vite plugin.
|
|
71
|
+
*
|
|
72
|
+
* What it does:
|
|
73
|
+
* - Sets envPrefix to 'BINI_' so client code uses import.meta.env.BINI_MY_VAR
|
|
74
|
+
* - Auto-loads .env for API routes in dev via loadEnv()
|
|
75
|
+
* - Replaces Vite's startup output with the Bini.js branded header
|
|
38
76
|
*/
|
|
39
|
-
declare function
|
|
77
|
+
declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
|
|
40
78
|
|
|
41
|
-
export { type BiniEnvPluginOptions, type DetectedEnvFile,
|
|
79
|
+
export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, detectEnvFiles, getEnv, loadEnv, requireEnv };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,37 +5,75 @@ interface BiniEnvPluginOptions {
|
|
|
5
5
|
/**
|
|
6
6
|
* Enable/disable the plugin
|
|
7
7
|
* @default true
|
|
8
|
-
* @readonly
|
|
9
8
|
*/
|
|
10
9
|
readonly enabled?: boolean;
|
|
11
10
|
/**
|
|
12
11
|
* Remove Vite's default header
|
|
13
12
|
* @default true
|
|
14
|
-
* @readonly
|
|
15
13
|
*/
|
|
16
14
|
readonly clearViteHeader?: boolean;
|
|
17
15
|
/**
|
|
18
16
|
* Custom logo/text to display
|
|
19
17
|
* @default 'ß'
|
|
20
|
-
* @readonly
|
|
21
18
|
*/
|
|
22
19
|
readonly logo?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Override the env var prefix exposed to client code.
|
|
22
|
+
* Defaults to 'BINI_' — so BINI_MY_VAR is accessible via import.meta.env.BINI_MY_VAR
|
|
23
|
+
* Set to 'VITE_' to keep Vite's default behaviour.
|
|
24
|
+
* @default 'BINI_'
|
|
25
|
+
*/
|
|
26
|
+
readonly envPrefix?: string;
|
|
23
27
|
}
|
|
24
28
|
interface DetectedEnvFile {
|
|
25
29
|
readonly name: string;
|
|
26
30
|
readonly path: string;
|
|
27
31
|
}
|
|
28
32
|
/**
|
|
29
|
-
*
|
|
33
|
+
* Read an environment variable in any runtime.
|
|
34
|
+
*
|
|
35
|
+
* Priority order:
|
|
36
|
+
* 1. Deno.env — Netlify edge functions / Deno runtime
|
|
37
|
+
* 2. process.env — Node.js / Bun / bini-server
|
|
38
|
+
* 3. import.meta.env — Vite client (BINI_-prefixed vars)
|
|
39
|
+
*
|
|
40
|
+
* Usage in API routes:
|
|
41
|
+
* import { getEnv } from 'bini-env';
|
|
42
|
+
* const smtpUser = getEnv('SMTP_USER');
|
|
30
43
|
*/
|
|
31
|
-
declare function
|
|
44
|
+
declare function getEnv(key: string): string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Read an environment variable and throw if it's missing or empty.
|
|
47
|
+
* Use this for required secrets so you get a clear error at startup
|
|
48
|
+
* instead of a cryptic crash later.
|
|
49
|
+
*
|
|
50
|
+
* Usage:
|
|
51
|
+
* const smtpPass = requireEnv('SMTP_PASS');
|
|
52
|
+
*/
|
|
53
|
+
declare function requireEnv(key: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Auto-load .env into process.env for Node.js API route contexts.
|
|
56
|
+
*
|
|
57
|
+
* Behaviour by environment:
|
|
58
|
+
* - Deno (edge functions) → no-op, Deno/Netlify injects env natively
|
|
59
|
+
* - NODE_ENV=production → no-op, host injects env vars automatically
|
|
60
|
+
* - Node.js dev → loads .env via dotenv (dynamic import, safe for bundlers)
|
|
61
|
+
*
|
|
62
|
+
* Called automatically by bini-env Vite plugin. You should not need to call this manually.
|
|
63
|
+
*/
|
|
64
|
+
declare function loadEnv(projectRoot?: string): Promise<void>;
|
|
32
65
|
/**
|
|
33
|
-
*
|
|
66
|
+
* Detect which .env files exist in the project root, in Vite's priority order.
|
|
34
67
|
*/
|
|
35
|
-
declare function
|
|
68
|
+
declare function detectEnvFiles(projectRoot?: string): DetectedEnvFile[];
|
|
36
69
|
/**
|
|
37
|
-
*
|
|
70
|
+
* Bini.js Vite plugin.
|
|
71
|
+
*
|
|
72
|
+
* What it does:
|
|
73
|
+
* - Sets envPrefix to 'BINI_' so client code uses import.meta.env.BINI_MY_VAR
|
|
74
|
+
* - Auto-loads .env for API routes in dev via loadEnv()
|
|
75
|
+
* - Replaces Vite's startup output with the Bini.js branded header
|
|
38
76
|
*/
|
|
39
|
-
declare function
|
|
77
|
+
declare function biniEnv(options?: Readonly<BiniEnvPluginOptions>): Plugin;
|
|
40
78
|
|
|
41
|
-
export { type BiniEnvPluginOptions, type DetectedEnvFile,
|
|
79
|
+
export { type BiniEnvPluginOptions, type DetectedEnvFile, biniEnv, detectEnvFiles, getEnv, loadEnv, requireEnv };
|
package/dist/index.js
CHANGED
|
@@ -1,130 +1,170 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
1
4
|
// src/index.ts
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import path from "path";
|
|
4
5
|
var BINI_LOGO = "\xDF";
|
|
6
|
+
var DEFAULT_ENV_PREFIX = "BINI_";
|
|
5
7
|
var DEFAULT_OPTIONS = {
|
|
6
8
|
enabled: true,
|
|
7
9
|
clearViteHeader: true,
|
|
8
|
-
logo: BINI_LOGO
|
|
10
|
+
logo: BINI_LOGO,
|
|
11
|
+
envPrefix: DEFAULT_ENV_PREFIX
|
|
9
12
|
};
|
|
10
13
|
var COLORS = {
|
|
11
14
|
CYAN: "\x1B[36m",
|
|
12
15
|
RESET: "\x1B[0m",
|
|
13
|
-
GREEN: "\x1B[32m"
|
|
14
|
-
YELLOW: "\x1B[33m",
|
|
15
|
-
DIM: "\x1B[2m"
|
|
16
|
+
GREEN: "\x1B[32m"
|
|
16
17
|
};
|
|
18
|
+
function getEnv(key) {
|
|
19
|
+
const deno = globalThis.Deno;
|
|
20
|
+
if (deno) {
|
|
21
|
+
try {
|
|
22
|
+
const val = deno.env.get(key);
|
|
23
|
+
if (val !== void 0) return val;
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (typeof process !== "undefined" && process.env) {
|
|
28
|
+
if (process.env[key] !== void 0) return process.env[key];
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const metaEnv = import.meta.env;
|
|
32
|
+
if (metaEnv) {
|
|
33
|
+
if (metaEnv[key] !== void 0) return metaEnv[key];
|
|
34
|
+
if (metaEnv[`BINI_${key}`] !== void 0) return metaEnv[`BINI_${key}`];
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
}
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
function requireEnv(key) {
|
|
41
|
+
const val = getEnv(key);
|
|
42
|
+
if (!val) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`[bini-env] Missing required environment variable: "${key}".
|
|
45
|
+
\u2192 In development: add it to your .env file.
|
|
46
|
+
\u2192 In production: add it to your hosting dashboard environment variables.`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return val;
|
|
50
|
+
}
|
|
51
|
+
var _envLoaded = false;
|
|
52
|
+
async function loadEnv(projectRoot) {
|
|
53
|
+
if (_envLoaded) return;
|
|
54
|
+
if (globalThis.Deno) {
|
|
55
|
+
_envLoaded = true;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (typeof process === "undefined" || !process.env) {
|
|
59
|
+
_envLoaded = true;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (process.env.NODE_ENV === "production") {
|
|
63
|
+
_envLoaded = true;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const root = projectRoot ?? process.cwd();
|
|
68
|
+
const envPath = path.join(root, ".env");
|
|
69
|
+
if (!fs.existsSync(envPath)) {
|
|
70
|
+
_envLoaded = true;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const dotenv = await import('dotenv');
|
|
74
|
+
dotenv.config({ path: envPath });
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
77
|
+
_envLoaded = true;
|
|
78
|
+
}
|
|
17
79
|
function detectEnvFiles(projectRoot = process.cwd()) {
|
|
18
|
-
const nodeEnv = process.env.NODE_ENV
|
|
19
|
-
const
|
|
80
|
+
const nodeEnv = process.env.NODE_ENV ?? "development";
|
|
81
|
+
const candidates = [
|
|
20
82
|
".env.local",
|
|
21
83
|
`.env.${nodeEnv}.local`,
|
|
22
84
|
`.env.${nodeEnv}`,
|
|
23
85
|
".env"
|
|
24
86
|
];
|
|
25
87
|
const found = [];
|
|
26
|
-
for (const file of
|
|
88
|
+
for (const file of candidates) {
|
|
27
89
|
const filePath = path.join(projectRoot, file);
|
|
28
90
|
if (fs.existsSync(filePath)) {
|
|
29
|
-
found.push({
|
|
30
|
-
name: file,
|
|
31
|
-
path: filePath
|
|
32
|
-
});
|
|
91
|
+
found.push({ name: file, path: filePath });
|
|
33
92
|
}
|
|
34
93
|
}
|
|
35
94
|
return found;
|
|
36
95
|
}
|
|
37
|
-
function formatEnvFilesForDisplay(envFiles) {
|
|
38
|
-
if (envFiles.length === 0) {
|
|
39
|
-
return "";
|
|
40
|
-
}
|
|
41
|
-
const envString = envFiles.map((f) => f.name).join(", ");
|
|
42
|
-
return `${COLORS.GREEN}\u279C${COLORS.RESET} Environments: ${envString}`;
|
|
43
|
-
}
|
|
44
96
|
function clearLine() {
|
|
45
97
|
process.stdout.write("\x1B[2K\r");
|
|
46
98
|
}
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
99
|
+
function printResolvedUrls(urls) {
|
|
100
|
+
if (!urls) return;
|
|
101
|
+
if (urls.local.length > 0)
|
|
102
|
+
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);
|
|
103
|
+
if (urls.network.length > 0)
|
|
104
|
+
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);
|
|
105
|
+
}
|
|
106
|
+
function biniEnv(options = {}) {
|
|
107
|
+
const resolvedOptions = Object.freeze({ ...DEFAULT_OPTIONS, ...options });
|
|
108
|
+
const { enabled, clearViteHeader, logo, envPrefix } = resolvedOptions;
|
|
109
|
+
let resolvedConfig;
|
|
55
110
|
let serverStarted = false;
|
|
56
111
|
let previewStarted = false;
|
|
57
112
|
return {
|
|
58
113
|
name: "vite-plugin-bini-env",
|
|
59
114
|
apply: "serve",
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
115
|
+
// Set BINI_ as the env prefix so import.meta.env.BINI_* works in client code
|
|
116
|
+
config() {
|
|
117
|
+
return { envPrefix };
|
|
118
|
+
},
|
|
119
|
+
configResolved(cfg) {
|
|
120
|
+
resolvedConfig = cfg;
|
|
65
121
|
},
|
|
66
122
|
configureServer(server) {
|
|
67
123
|
if (!enabled) return;
|
|
68
|
-
|
|
124
|
+
if (server.httpServer) {
|
|
125
|
+
server.httpServer.once("listening", () => {
|
|
126
|
+
void loadEnv(resolvedConfig?.root ?? process.cwd());
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
void loadEnv(resolvedConfig?.root ?? process.cwd());
|
|
130
|
+
}
|
|
131
|
+
const originalPrintUrls = server.printUrls.bind(server);
|
|
69
132
|
server.printUrls = () => {
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
console.log(`
|
|
133
|
+
if (serverStarted) return;
|
|
134
|
+
serverStarted = true;
|
|
135
|
+
if (clearViteHeader) clearLine();
|
|
136
|
+
console.log(`
|
|
76
137
|
${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (dev)`);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (urls) {
|
|
87
|
-
if (urls.local.length > 0) {
|
|
88
|
-
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);
|
|
89
|
-
}
|
|
90
|
-
if (urls.network.length > 0) {
|
|
91
|
-
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
138
|
+
const found = detectEnvFiles(resolvedConfig?.root);
|
|
139
|
+
if (found.length > 0) {
|
|
140
|
+
const envString = found.map((f) => f.name).join(", ");
|
|
141
|
+
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Environments: ${envString}`);
|
|
142
|
+
}
|
|
143
|
+
if (!clearViteHeader) {
|
|
144
|
+
originalPrintUrls();
|
|
145
|
+
} else {
|
|
146
|
+
printResolvedUrls(server.resolvedUrls);
|
|
95
147
|
}
|
|
96
148
|
};
|
|
97
149
|
},
|
|
98
150
|
configurePreviewServer(server) {
|
|
99
151
|
if (!enabled) return;
|
|
100
|
-
|
|
101
|
-
const originalPrintUrls = server.printUrls;
|
|
152
|
+
const originalPrintUrls = server.printUrls.bind(server);
|
|
102
153
|
server.printUrls = () => {
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
console.log(`
|
|
154
|
+
if (previewStarted) return;
|
|
155
|
+
previewStarted = true;
|
|
156
|
+
if (clearViteHeader) clearLine();
|
|
157
|
+
console.log(`
|
|
109
158
|
${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (preview)`);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (urls) {
|
|
120
|
-
if (urls.local.length > 0) {
|
|
121
|
-
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);
|
|
122
|
-
}
|
|
123
|
-
if (urls.network.length > 0) {
|
|
124
|
-
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
159
|
+
const found = detectEnvFiles(resolvedConfig?.root);
|
|
160
|
+
if (found.length > 0) {
|
|
161
|
+
const envString = found.map((f) => f.name).join(", ");
|
|
162
|
+
console.log(` ${COLORS.GREEN}\u279C${COLORS.RESET} Environments: ${envString}`);
|
|
163
|
+
}
|
|
164
|
+
if (!clearViteHeader) {
|
|
165
|
+
originalPrintUrls();
|
|
166
|
+
} else {
|
|
167
|
+
printResolvedUrls(server.resolvedUrls);
|
|
128
168
|
}
|
|
129
169
|
};
|
|
130
170
|
},
|
|
@@ -134,9 +174,7 @@ function biniEnvPlugin(options = {}) {
|
|
|
134
174
|
}
|
|
135
175
|
};
|
|
136
176
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
formatEnvFilesForDisplay
|
|
141
|
-
};
|
|
177
|
+
|
|
178
|
+
export { biniEnv, detectEnvFiles, getEnv, loadEnv, requireEnv };
|
|
179
|
+
//# sourceMappingURL=index.js.map
|
|
142
180
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// src/index.ts\r\nimport fs from 'fs';\r\nimport path from 'path';\r\nimport type { Plugin, ResolvedConfig } from 'vite';\r\n\r\n// Types\r\nexport interface BiniEnvPluginOptions {\r\n /**\r\n * Enable/disable the plugin\r\n * @default true\r\n * @readonly\r\n */\r\n readonly enabled?: boolean;\r\n \r\n /**\r\n * Remove Vite's default header\r\n * @default true\r\n * @readonly\r\n */\r\n readonly clearViteHeader?: boolean;\r\n \r\n /**\r\n * Custom logo/text to display\r\n * @default 'ß'\r\n * @readonly\r\n */\r\n readonly logo?: string;\r\n}\r\n\r\nexport interface DetectedEnvFile {\r\n readonly name: string;\r\n readonly path: string;\r\n}\r\n\r\n// Constants\r\nconst BINI_LOGO = 'ß' as const;\r\nconst DEFAULT_OPTIONS = {\r\n enabled: true,\r\n clearViteHeader: true,\r\n logo: BINI_LOGO,\r\n} as const;\r\n\r\n// Color definitions\r\nconst COLORS = {\r\n CYAN: '\\x1b[36m',\r\n RESET: '\\x1b[0m',\r\n GREEN: '\\x1b[32m',\r\n YELLOW: '\\x1b[33m',\r\n DIM: '\\x1b[2m'\r\n} as const;\r\n\r\n/**\r\n * Detect which .env files exist in project root\r\n */\r\nexport function detectEnvFiles(projectRoot: string = process.cwd()): DetectedEnvFile[] {\r\n const nodeEnv = process.env.NODE_ENV || 'development';\r\n\r\n const envFiles = [\r\n '.env.local',\r\n `.env.${nodeEnv}.local`,\r\n `.env.${nodeEnv}`,\r\n '.env'\r\n ] as const;\r\n\r\n const found: DetectedEnvFile[] = [];\r\n\r\n for (const file of envFiles) {\r\n const filePath = path.join(projectRoot, file);\r\n if (fs.existsSync(filePath)) {\r\n found.push({\r\n name: file,\r\n path: filePath\r\n });\r\n }\r\n }\r\n\r\n return found;\r\n}\r\n\r\n/**\r\n * Format environment files for console display\r\n */\r\nexport function formatEnvFilesForDisplay(envFiles: DetectedEnvFile[]): string {\r\n if (envFiles.length === 0) {\r\n return '';\r\n }\r\n\r\n const envString = envFiles.map(f => f.name).join(', ');\r\n return `${COLORS.GREEN}➜${COLORS.RESET} Environments: ${envString}`;\r\n}\r\n\r\n/**\r\n * Clear the current line in console\r\n */\r\nfunction clearLine(): void {\r\n process.stdout.write('\\x1b[2K\\r');\r\n}\r\n\r\n/**\r\n * Main plugin function\r\n */\r\nexport default function biniEnvPlugin(options: Readonly<BiniEnvPluginOptions> = {}): Plugin {\r\n // Merge with defaults — user cannot override core behaviour\r\n const resolvedOptions = Object.freeze({\r\n ...DEFAULT_OPTIONS,\r\n ...options,\r\n });\r\n\r\n const { enabled, clearViteHeader, logo } = resolvedOptions;\r\n\r\n let config: ResolvedConfig;\r\n let isPreviewMode = false;\r\n let serverStarted = false;\r\n let previewStarted = false;\r\n\r\n return {\r\n name: 'vite-plugin-bini-env',\r\n \r\n apply: 'serve',\r\n \r\n configResolved(resolvedConfig: ResolvedConfig) {\r\n config = resolvedConfig;\r\n \r\n if (resolvedConfig.command === 'serve') {\r\n isPreviewMode = process.env.VITE_PREVIEW === 'true' || \r\n process.argv.includes('preview') ||\r\n false;\r\n }\r\n },\r\n\r\n configureServer(server) {\r\n if (!enabled) return;\r\n\r\n const originalPrintUrls = server.printUrls;\r\n \r\n server.printUrls = () => {\r\n if (!serverStarted) {\r\n serverStarted = true;\r\n \r\n if (clearViteHeader) {\r\n clearLine();\r\n }\r\n \r\n console.log(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (dev)`);\r\n\r\n const found = detectEnvFiles(config.root);\r\n if (found.length > 0) {\r\n const envString = found.map(f => f.name).join(', ');\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${envString}`);\r\n }\r\n \r\n if (!clearViteHeader) {\r\n originalPrintUrls.call(server);\r\n } else {\r\n const urls = server.resolvedUrls;\r\n if (urls) {\r\n if (urls.local.length > 0) {\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);\r\n }\r\n if (urls.network.length > 0) {\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);\r\n }\r\n }\r\n }\r\n }\r\n };\r\n },\r\n\r\n configurePreviewServer(server) {\r\n if (!enabled) return;\r\n \r\n isPreviewMode = true;\r\n \r\n const originalPrintUrls = server.printUrls;\r\n \r\n server.printUrls = () => {\r\n if (!previewStarted) {\r\n previewStarted = true;\r\n \r\n if (clearViteHeader) {\r\n clearLine();\r\n }\r\n \r\n console.log(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (preview)`);\r\n\r\n const found = detectEnvFiles(config.root);\r\n if (found.length > 0) {\r\n const envString = found.map(f => f.name).join(', ');\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${envString}`);\r\n }\r\n \r\n if (!clearViteHeader) {\r\n originalPrintUrls.call(server);\r\n } else {\r\n const urls = server.resolvedUrls;\r\n if (urls) {\r\n if (urls.local.length > 0) {\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);\r\n }\r\n if (urls.network.length > 0) {\r\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);\r\n }\r\n }\r\n }\r\n }\r\n };\r\n },\r\n\r\n buildEnd() {\r\n serverStarted = false;\r\n previewStarted = false;\r\n }\r\n };\r\n}\r\n\r\nexport type { Plugin } from 'vite';"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// src/index.ts\nimport fs from 'fs';\nimport path from 'path';\nimport type { Plugin, ResolvedConfig, UserConfig } from 'vite';\n\n/* ==========================================================================\n Global type declarations for cross-runtime compatibility\n ========================================================================== */\n\n// Deno runtime type — declared as an interface so we can safely cast\n// without relying on a global that TypeScript doesn't know about\ninterface DenoEnv {\n get(key: string): string | undefined;\n toObject(): Record<string, string>;\n}\ninterface DenoNamespace {\n env: DenoEnv;\n}\n\n// Vite augments ImportMeta with .env\n// Using triple-slash reference so it works both inside and outside Vite projects\n/// <reference types=\"vite/client\" />\n\n/* ==========================================================================\n Types\n ========================================================================== */\n\nexport interface BiniEnvPluginOptions {\n /**\n * Enable/disable the plugin\n * @default true\n */\n readonly enabled?: boolean;\n\n /**\n * Remove Vite's default header\n * @default true\n */\n readonly clearViteHeader?: boolean;\n\n /**\n * Custom logo/text to display\n * @default 'ß'\n */\n readonly logo?: string;\n\n /**\n * Override the env var prefix exposed to client code.\n * Defaults to 'BINI_' — so BINI_MY_VAR is accessible via import.meta.env.BINI_MY_VAR\n * Set to 'VITE_' to keep Vite's default behaviour.\n * @default 'BINI_'\n */\n readonly envPrefix?: string;\n}\n\nexport interface DetectedEnvFile {\n readonly name: string;\n readonly path: string;\n}\n\n/* ==========================================================================\n Constants\n ========================================================================== */\n\nconst BINI_LOGO = 'ß' as const;\nconst DEFAULT_ENV_PREFIX = 'BINI_' as const;\n\nconst DEFAULT_OPTIONS = {\n enabled: true,\n clearViteHeader: true,\n logo: BINI_LOGO,\n envPrefix: DEFAULT_ENV_PREFIX,\n} as const;\n\nconst COLORS = {\n CYAN: '\\x1b[36m',\n RESET: '\\x1b[0m',\n GREEN: '\\x1b[32m',\n} as const;\n\n/* ==========================================================================\n getEnv — Universal env var accessor\n Works in: Node.js, Deno (edge functions), Bun, Vite client\n ========================================================================== */\n\n/**\n * Read an environment variable in any runtime.\n *\n * Priority order:\n * 1. Deno.env — Netlify edge functions / Deno runtime\n * 2. process.env — Node.js / Bun / bini-server\n * 3. import.meta.env — Vite client (BINI_-prefixed vars)\n *\n * Usage in API routes:\n * import { getEnv } from 'bini-env';\n * const smtpUser = getEnv('SMTP_USER');\n */\nexport function getEnv(key: string): string | undefined {\n // 1. Deno runtime (Netlify edge functions)\n const deno = (globalThis as unknown as { Deno?: DenoNamespace }).Deno;\n if (deno) {\n try {\n const val = deno.env.get(key);\n if (val !== undefined) return val;\n } catch {\n // Deno env access denied — fall through\n }\n }\n\n // 2. Node.js / Bun / bini-server\n if (typeof process !== 'undefined' && process.env) {\n if (process.env[key] !== undefined) return process.env[key];\n }\n\n // 3. Vite injected (import.meta.env) — BINI_-prefixed client vars\n // Wrapped in try/catch because import.meta.env doesn't exist in Node/Deno\n try {\n const metaEnv = import.meta.env as Record<string, string | undefined> | undefined;\n if (metaEnv) {\n if (metaEnv[key] !== undefined) return metaEnv[key];\n // Try with BINI_ prefix automatically\n if (metaEnv[`BINI_${key}`] !== undefined) return metaEnv[`BINI_${key}`];\n }\n } catch {\n // import.meta.env not available in this runtime — ignore\n }\n\n return undefined;\n}\n\n/**\n * Read an environment variable and throw if it's missing or empty.\n * Use this for required secrets so you get a clear error at startup\n * instead of a cryptic crash later.\n *\n * Usage:\n * const smtpPass = requireEnv('SMTP_PASS');\n */\nexport function requireEnv(key: string): string {\n const val = getEnv(key);\n if (!val) {\n throw new Error(\n `[bini-env] Missing required environment variable: \"${key}\".\\n` +\n ` → In development: add it to your .env file.\\n` +\n ` → In production: add it to your hosting dashboard environment variables.`\n );\n }\n return val;\n}\n\n/* ==========================================================================\n loadEnv — Auto dotenv loader for bini-router API routes (Node.js only)\n Called internally by the Vite plugin. Safe to call multiple times.\n ========================================================================== */\n\nlet _envLoaded = false;\n\n/**\n * Auto-load .env into process.env for Node.js API route contexts.\n *\n * Behaviour by environment:\n * - Deno (edge functions) → no-op, Deno/Netlify injects env natively\n * - NODE_ENV=production → no-op, host injects env vars automatically\n * - Node.js dev → loads .env via dotenv (dynamic import, safe for bundlers)\n *\n * Called automatically by bini-env Vite plugin. You should not need to call this manually.\n */\nexport async function loadEnv(projectRoot?: string): Promise<void> {\n // Already loaded — skip\n if (_envLoaded) return;\n\n // Deno runtime — env is handled natively, skip\n if ((globalThis as unknown as { Deno?: DenoNamespace }).Deno) {\n _envLoaded = true;\n return;\n }\n\n // Not in a Node-like runtime — skip\n if (typeof process === 'undefined' || !process.env) {\n _envLoaded = true;\n return;\n }\n\n // Production — host injects env vars, dotenv not needed\n if (process.env.NODE_ENV === 'production') {\n _envLoaded = true;\n return;\n }\n\n try {\n const root = projectRoot ?? process.cwd();\n const envPath = path.join(root, '.env');\n\n if (!fs.existsSync(envPath)) {\n _envLoaded = true;\n return;\n }\n\n // Dynamic import so Deno/edge bundlers never try to statically resolve dotenv\n const dotenv = await import('dotenv');\n dotenv.config({ path: envPath });\n } catch {\n // dotenv not installed or read failed — silently skip.\n // requireEnv() will surface clear errors if vars are missing when used.\n }\n\n _envLoaded = true;\n}\n\n/* ==========================================================================\n detectEnvFiles — used by the Vite plugin display\n ========================================================================== */\n\n/**\n * Detect which .env files exist in the project root, in Vite's priority order.\n */\nexport function detectEnvFiles(projectRoot: string = process.cwd()): DetectedEnvFile[] {\n const nodeEnv = process.env.NODE_ENV ?? 'development';\n\n const candidates = [\n '.env.local',\n `.env.${nodeEnv}.local`,\n `.env.${nodeEnv}`,\n '.env',\n ] as const;\n\n const found: DetectedEnvFile[] = [];\n\n for (const file of candidates) {\n const filePath = path.join(projectRoot, file);\n if (fs.existsSync(filePath)) {\n found.push({ name: file, path: filePath });\n }\n }\n\n return found;\n}\n\n/* ==========================================================================\n Vite plugin\n ========================================================================== */\n\nfunction clearLine(): void {\n process.stdout.write('\\x1b[2K\\r');\n}\n\nfunction printResolvedUrls(urls: { local: string[]; network: string[] } | null | undefined): void {\n if (!urls) return;\n if (urls.local.length > 0)\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Local: ${COLORS.CYAN}${urls.local[0]}${COLORS.RESET}`);\n if (urls.network.length > 0)\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Network: ${COLORS.CYAN}${urls.network[0]}${COLORS.RESET}`);\n}\n\n/**\n * Bini.js Vite plugin.\n *\n * What it does:\n * - Sets envPrefix to 'BINI_' so client code uses import.meta.env.BINI_MY_VAR\n * - Auto-loads .env for API routes in dev via loadEnv()\n * - Replaces Vite's startup output with the Bini.js branded header\n */\nexport function biniEnv(options: Readonly<BiniEnvPluginOptions> = {}): Plugin {\n const resolvedOptions = Object.freeze({ ...DEFAULT_OPTIONS, ...options });\n const { enabled, clearViteHeader, logo, envPrefix } = resolvedOptions;\n\n let resolvedConfig: ResolvedConfig;\n let serverStarted = false;\n let previewStarted = false;\n\n return {\n name: 'vite-plugin-bini-env',\n\n apply: 'serve',\n\n // Set BINI_ as the env prefix so import.meta.env.BINI_* works in client code\n config(): UserConfig {\n return { envPrefix };\n },\n\n configResolved(cfg: ResolvedConfig) {\n resolvedConfig = cfg;\n },\n\n configureServer(server) {\n if (!enabled) return;\n\n // Auto-load .env after server starts — guarantees resolvedConfig is available\n // Falls back to immediate call in middleware mode where httpServer is null\n if (server.httpServer) {\n server.httpServer.once('listening', () => {\n void loadEnv(resolvedConfig?.root ?? process.cwd());\n });\n } else {\n // Middleware mode — httpServer is null, call immediately\n void loadEnv(resolvedConfig?.root ?? process.cwd());\n }\n\n const originalPrintUrls = server.printUrls.bind(server);\n\n server.printUrls = () => {\n if (serverStarted) return;\n serverStarted = true;\n\n if (clearViteHeader) clearLine();\n console.log(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (dev)`);\n\n const found = detectEnvFiles(resolvedConfig?.root);\n if (found.length > 0) {\n const envString = found.map((f) => f.name).join(', ');\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${envString}`);\n }\n\n if (!clearViteHeader) {\n originalPrintUrls();\n } else {\n printResolvedUrls(server.resolvedUrls);\n }\n };\n },\n\n configurePreviewServer(server) {\n if (!enabled) return;\n\n const originalPrintUrls = server.printUrls.bind(server);\n\n server.printUrls = () => {\n if (previewStarted) return;\n previewStarted = true;\n\n if (clearViteHeader) clearLine();\n console.log(`\\n ${COLORS.CYAN}${logo} Bini.js${COLORS.RESET} (preview)`);\n\n const found = detectEnvFiles(resolvedConfig?.root);\n if (found.length > 0) {\n const envString = found.map((f) => f.name).join(', ');\n console.log(` ${COLORS.GREEN}➜${COLORS.RESET} Environments: ${envString}`);\n }\n\n if (!clearViteHeader) {\n originalPrintUrls();\n } else {\n printResolvedUrls(server.resolvedUrls);\n }\n };\n },\n\n buildEnd() {\n serverStarted = false;\n previewStarted = false;\n },\n };\n}\n\n// Named export: import { biniEnv } from 'bini-env'\nexport type { Plugin } from 'vite';"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bini-env",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Vite plugin for Bini.js
|
|
3
|
+
"version": "1.0.6",
|
|
4
|
+
"description": "Universal environment variable loader and Vite plugin for Bini.js — works in Node.js, Deno, Bun, and Vite edge functions",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -17,25 +17,45 @@
|
|
|
17
17
|
"dist",
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"dev": "tsup --watch",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
20
25
|
"keywords": [
|
|
21
26
|
"vite",
|
|
22
27
|
"vite-plugin",
|
|
23
|
-
"bini.js",
|
|
24
28
|
"bini",
|
|
29
|
+
"bini-js",
|
|
30
|
+
"bini.js",
|
|
25
31
|
"environment",
|
|
26
32
|
"env",
|
|
27
|
-
"dotenv"
|
|
33
|
+
"dotenv",
|
|
34
|
+
"deno",
|
|
35
|
+
"edge-functions",
|
|
36
|
+
"cross-runtime"
|
|
28
37
|
],
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/Binidu01/Bini-Env.git"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/Binidu01/Bini-Env#readme",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/Binidu01/Bini-Env/issues"
|
|
45
|
+
},
|
|
29
46
|
"author": "Bini.js Team",
|
|
30
47
|
"license": "MIT",
|
|
31
48
|
"peerDependencies": {
|
|
32
|
-
"vite": "
|
|
49
|
+
"vite": ">=7.0.0"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"dotenv": "^17.3.1"
|
|
33
53
|
},
|
|
34
54
|
"devDependencies": {
|
|
35
55
|
"@types/node": "^22.15.3",
|
|
36
56
|
"tsup": "^8.4.0",
|
|
37
57
|
"typescript": "^5.8.3",
|
|
38
|
-
"vite": "^
|
|
58
|
+
"vite": "^7.3.1"
|
|
39
59
|
},
|
|
40
60
|
"tsup": {
|
|
41
61
|
"entry": [
|
|
@@ -49,13 +69,14 @@
|
|
|
49
69
|
"clean": true,
|
|
50
70
|
"splitting": false,
|
|
51
71
|
"sourcemap": true,
|
|
52
|
-
"minify": false
|
|
72
|
+
"minify": false,
|
|
73
|
+
"external": [
|
|
74
|
+
"vite",
|
|
75
|
+
"fs",
|
|
76
|
+
"path"
|
|
77
|
+
]
|
|
53
78
|
},
|
|
54
79
|
"engines": {
|
|
55
80
|
"node": ">=18.0.0"
|
|
56
|
-
},
|
|
57
|
-
"scripts": {
|
|
58
|
-
"build": "tsup",
|
|
59
|
-
"dev": "tsup --watch"
|
|
60
81
|
}
|
|
61
82
|
}
|
package/Readme.md
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
# bini-env
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-

|
|
5
|
-

|
|
6
|
-

|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
A lightweight Vite plugin that enhances your dev and preview server output with a clean startup banner and detected `.env` files.
|
|
10
|
-
|
|
11
|
-
## Features
|
|
12
|
-
|
|
13
|
-
- Replaces Vite's default header with a clean custom banner
|
|
14
|
-
- Automatically detects and displays active `.env` files
|
|
15
|
-
- Supports `dev` and `preview` modes
|
|
16
|
-
- Fully customizable logo and behavior
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
19
|
-
```bash
|
|
20
|
-
npm install bini-env --save-dev
|
|
21
|
-
# or
|
|
22
|
-
pnpm add -D bini-env
|
|
23
|
-
# or
|
|
24
|
-
yarn add -D bini-env
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Usage
|
|
28
|
-
```ts
|
|
29
|
-
// vite.config.ts
|
|
30
|
-
import { defineConfig } from 'vite';
|
|
31
|
-
import biniEnv from 'bini-env';
|
|
32
|
-
|
|
33
|
-
export default defineConfig({
|
|
34
|
-
plugins: [biniEnv()]
|
|
35
|
-
});
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Output Example
|
|
39
|
-
|
|
40
|
-
**Dev mode**
|
|
41
|
-
```
|
|
42
|
-
ß Bini.js (dev)
|
|
43
|
-
➜ Environments: .env.local, .env
|
|
44
|
-
➜ Local: http://localhost:5173/
|
|
45
|
-
➜ Network: http://192.168.1.10:5173/
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
**Preview mode**
|
|
49
|
-
```
|
|
50
|
-
ß Bini.js (preview)
|
|
51
|
-
➜ Environments: .env.local, .env
|
|
52
|
-
➜ Local: http://localhost:4173/
|
|
53
|
-
➜ Network: http://192.168.1.10:4173/
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Options
|
|
57
|
-
|
|
58
|
-
| Option | Type | Default | Description |
|
|
59
|
-
|--------|------|---------|-------------|
|
|
60
|
-
| `enabled` | `boolean` | `true` | Enable or disable the plugin |
|
|
61
|
-
| `clearViteHeader` | `boolean` | `true` | Replace Vite's default startup header |
|
|
62
|
-
| `logo` | `string` | `'ß'` | Custom logo or text shown in the banner |
|
|
63
|
-
|
|
64
|
-
### Example with options
|
|
65
|
-
```ts
|
|
66
|
-
biniEnv({
|
|
67
|
-
logo: '🚀',
|
|
68
|
-
clearViteHeader: true,
|
|
69
|
-
})
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Detected `.env` Files
|
|
73
|
-
|
|
74
|
-
The plugin checks for the following files in your project root (in priority order):
|
|
75
|
-
|
|
76
|
-
1. `.env.local`
|
|
77
|
-
2. `.env.[NODE_ENV].local`
|
|
78
|
-
3. `.env.[NODE_ENV]`
|
|
79
|
-
4. `.env`
|
|
80
|
-
|
|
81
|
-
Any files found are displayed in the banner on startup.
|
|
82
|
-
|
|
83
|
-
## Modes
|
|
84
|
-
|
|
85
|
-
| Mode | Trigger | Banner |
|
|
86
|
-
|------|---------|--------|
|
|
87
|
-
| Development | `vite dev` | `ß Bini.js (dev)` |
|
|
88
|
-
| Preview | `vite preview` | `ß Bini.js (preview)` |
|
|
89
|
-
|
|
90
|
-
> **Note:** `bini-env` is a server-only plugin (`apply: 'serve'`) and does not run during `vite build`.
|
|
91
|
-
|
|
92
|
-
## API
|
|
93
|
-
|
|
94
|
-
The following utilities are exported for use outside of the plugin if needed.
|
|
95
|
-
|
|
96
|
-
### `detectEnvFiles(projectRoot?: string): DetectedEnvFile[]`
|
|
97
|
-
|
|
98
|
-
Scans a directory for `.env` files and returns an array of matches.
|
|
99
|
-
```ts
|
|
100
|
-
import { detectEnvFiles } from 'bini-env';
|
|
101
|
-
|
|
102
|
-
const files = detectEnvFiles('/my/project');
|
|
103
|
-
// [{ name: '.env.local', path: '/my/project/.env.local' }, ...]
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Defaults to `process.cwd()` if no path is provided.
|
|
107
|
-
|
|
108
|
-
### `formatEnvFilesForDisplay(envFiles: DetectedEnvFile[]): string`
|
|
109
|
-
|
|
110
|
-
Formats a list of detected env files into a display-ready console string.
|
|
111
|
-
```ts
|
|
112
|
-
import { detectEnvFiles, formatEnvFilesForDisplay } from 'bini-env';
|
|
113
|
-
|
|
114
|
-
const files = detectEnvFiles();
|
|
115
|
-
console.log(formatEnvFilesForDisplay(files));
|
|
116
|
-
// ➜ Environments: .env
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Types
|
|
120
|
-
```ts
|
|
121
|
-
interface BiniEnvPluginOptions {
|
|
122
|
-
enabled?: boolean;
|
|
123
|
-
clearViteHeader?: boolean;
|
|
124
|
-
logo?: string;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
interface DetectedEnvFile {
|
|
128
|
-
name: string;
|
|
129
|
-
path: string;
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## License
|
|
134
|
-
|
|
135
|
-
MIT
|