morphix-env 0.2.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -109
- package/dist/cli.js +85 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ npm install -D morphix-env
|
|
|
26
26
|
## Quick Start
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
# Run a command with
|
|
29
|
+
# Run a command with env injection
|
|
30
30
|
morphix-env run -- next dev
|
|
31
31
|
|
|
32
32
|
# Generate client-side __env.js
|
|
@@ -36,6 +36,126 @@ morphix-env generate --out public/__env.js
|
|
|
36
36
|
morphix-env inspect
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
## How It Works
|
|
40
|
+
|
|
41
|
+
### Core Flow
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
morphix-env run -- <command>
|
|
45
|
+
│
|
|
46
|
+
├─ 1. Read mx-env.config.json
|
|
47
|
+
│
|
|
48
|
+
├─ 2. Load Infisical secrets ──────────────────────────┐
|
|
49
|
+
│ │ │
|
|
50
|
+
│ ├─ INFISICAL_CLIENT_ID exists? │
|
|
51
|
+
│ │ ├─ Yes → SDK (Machine Identity) ── CI/Docker │
|
|
52
|
+
│ │ └─ No ──┐ │
|
|
53
|
+
│ │ ├─ infisical CLI installed? │
|
|
54
|
+
│ │ │ ├─ Yes → CLI (user login) ── Local │
|
|
55
|
+
│ │ │ └─ No → Skip │
|
|
56
|
+
│ │ │
|
|
57
|
+
│ └─ Inject into process.env (does NOT overwrite) │
|
|
58
|
+
│ │
|
|
59
|
+
├─ 3. Load .env.local ─────────────────────────────────┐
|
|
60
|
+
│ └─ Inject into process.env (OVERWRITES all) │
|
|
61
|
+
│ │
|
|
62
|
+
├─ 4. Generate __env.js (if configured) │
|
|
63
|
+
│ └─ Extract NEXT_PUBLIC_* / VITE_* → write file │
|
|
64
|
+
│ │
|
|
65
|
+
└─ 5. Spawn child command │
|
|
66
|
+
└─ Inherits fully assembled process.env │
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Priority (high → low)
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
┌─────────────────────────────────────────────────┐
|
|
73
|
+
│ .env.local ← HIGHEST │
|
|
74
|
+
│ Always wins. Developer's local overrides. │
|
|
75
|
+
├─────────────────────────────────────────────────┤
|
|
76
|
+
│ Infisical secrets ← MEDIUM │
|
|
77
|
+
│ Pulled via SDK or CLI. Does not overwrite. │
|
|
78
|
+
├─────────────────────────────────────────────────┤
|
|
79
|
+
│ process.env ← LOWEST │
|
|
80
|
+
│ Docker ENV, CI vars, shell exports. │
|
|
81
|
+
└─────────────────────────────────────────────────┘
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Authentication Flow
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
┌──────────────────────────────────────────────────────────┐
|
|
88
|
+
│ morphix-env starts │
|
|
89
|
+
│ │ │
|
|
90
|
+
│ INFISICAL_CLIENT_ID set? │
|
|
91
|
+
│ / \ │
|
|
92
|
+
│ Yes No │
|
|
93
|
+
│ │ │ │
|
|
94
|
+
│ ┌───────▼────────┐ infisical CLI installed? │
|
|
95
|
+
│ │ SDK Auth │ / \ │
|
|
96
|
+
│ │ (Machine ID) │ Yes No │
|
|
97
|
+
│ │ │ │ │ │
|
|
98
|
+
│ │ CI / Docker / │ ┌──▼───────────┐ │ │
|
|
99
|
+
│ │ Production │ │ CLI Auth │ ▼ │
|
|
100
|
+
│ └────────┬────────┘ │ (User Login) │ Skip │
|
|
101
|
+
│ │ │ │ Infisical │
|
|
102
|
+
│ │ │ Local Dev │ │
|
|
103
|
+
│ │ └──────┬────────┘ │
|
|
104
|
+
│ │ │ │
|
|
105
|
+
│ ▼ ▼ │
|
|
106
|
+
│ Pull secrets from Infisical │
|
|
107
|
+
│ Inject into process.env │
|
|
108
|
+
└──────────────────────────────────────────────────────────┘
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Local Development
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
Developer machine:
|
|
115
|
+
1. infisical login ← one-time, session cached
|
|
116
|
+
2. pnpm dev ← morphix-env auto-detects CLI
|
|
117
|
+
└─ morphix-env run
|
|
118
|
+
├─ infisical CLI pulls 69 secrets
|
|
119
|
+
├─ .env.local overrides API_BASE_URL → localhost
|
|
120
|
+
└─ next dev starts with all vars
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### CI / Docker
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
Container / CI runner:
|
|
127
|
+
ENV INFISICAL_CLIENT_ID=xxx
|
|
128
|
+
ENV INFISICAL_CLIENT_SECRET=xxx
|
|
129
|
+
ENV DEPLOY_ENV=prod
|
|
130
|
+
|
|
131
|
+
CMD morphix-env run -- node server.js
|
|
132
|
+
└─ morphix-env run
|
|
133
|
+
├─ SDK pulls secrets (no CLI needed)
|
|
134
|
+
├─ .env.local not present → skip
|
|
135
|
+
└─ server starts with prod vars
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### `__env.js` — Client-Side Runtime Injection
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
Build phase (CI):
|
|
142
|
+
morphix-env run -- next build
|
|
143
|
+
├─ NEXT_PUBLIC_* injected at build time → baked into JS bundle
|
|
144
|
+
└─ Works, but image is environment-specific
|
|
145
|
+
|
|
146
|
+
Runtime injection (Docker, optional):
|
|
147
|
+
morphix-env run -- node server.js
|
|
148
|
+
├─ morphix-env generates public/__env.js:
|
|
149
|
+
│ window.__ENV = {
|
|
150
|
+
│ "NEXT_PUBLIC_API_URL": "https://api.prod.example.com",
|
|
151
|
+
│ "NEXT_PUBLIC_APP_NAME": "MyApp"
|
|
152
|
+
│ };
|
|
153
|
+
│
|
|
154
|
+
├─ Browser loads <script src="/__env.js"> before app
|
|
155
|
+
└─ App reads: window.__ENV?.NEXT_PUBLIC_API_URL
|
|
156
|
+
→ One build, deploy to any environment
|
|
157
|
+
```
|
|
158
|
+
|
|
39
159
|
## Commands
|
|
40
160
|
|
|
41
161
|
### `morphix-env run [options] -- <command>`
|
|
@@ -43,7 +163,7 @@ morphix-env inspect
|
|
|
43
163
|
Load environment variables, then execute a command. The child process inherits all injected vars.
|
|
44
164
|
|
|
45
165
|
```bash
|
|
46
|
-
# Basic: load
|
|
166
|
+
# Basic: load env, run dev server
|
|
47
167
|
morphix-env run -- next dev --turbo -p 3004
|
|
48
168
|
|
|
49
169
|
# Custom env file
|
|
@@ -56,46 +176,14 @@ morphix-env run --no-infisical -- npm start
|
|
|
56
176
|
morphix-env run -v -- node server.js
|
|
57
177
|
```
|
|
58
178
|
|
|
59
|
-
**Loading priority (high to low):**
|
|
60
|
-
|
|
61
|
-
1. `.env.local` (or `--env-file`) — always wins
|
|
62
|
-
2. Infisical secrets — pulled via SDK
|
|
63
|
-
3. Existing `process.env` — Docker ENV, CI vars, etc.
|
|
64
|
-
|
|
65
179
|
### `morphix-env generate [options]`
|
|
66
180
|
|
|
67
|
-
Extract public environment variables
|
|
181
|
+
Extract public environment variables and write to a JS file for browser runtime injection.
|
|
68
182
|
|
|
69
183
|
```bash
|
|
70
|
-
#
|
|
71
|
-
morphix-env generate
|
|
72
|
-
|
|
73
|
-
# Custom output path (Vite projects)
|
|
74
|
-
morphix-env generate --out dist/__env.js
|
|
75
|
-
|
|
76
|
-
# Only include specific prefix
|
|
77
|
-
morphix-env generate --filter NEXT_PUBLIC_
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Output file content:
|
|
81
|
-
|
|
82
|
-
```js
|
|
83
|
-
window.__ENV={"NEXT_PUBLIC_API_URL":"https://api.example.com","NEXT_PUBLIC_APP_NAME":"MyApp"};
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Load it in your HTML before your app bundle:
|
|
87
|
-
|
|
88
|
-
```html
|
|
89
|
-
<script src="/__env.js"></script>
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Read in your app:
|
|
93
|
-
|
|
94
|
-
```ts
|
|
95
|
-
function getEnv(key: string, fallback = ''): string {
|
|
96
|
-
if (typeof window === 'undefined') return process.env[key] || fallback
|
|
97
|
-
return window.__ENV?.[key] || process.env[key] || fallback
|
|
98
|
-
}
|
|
184
|
+
morphix-env generate # → public/__env.js
|
|
185
|
+
morphix-env generate --out dist/__env.js # Vite projects
|
|
186
|
+
morphix-env generate --filter NEXT_PUBLIC_ # Only Next.js vars
|
|
99
187
|
```
|
|
100
188
|
|
|
101
189
|
### `morphix-env inspect [options]`
|
|
@@ -115,19 +203,18 @@ morphix-env inspect -f .env.production
|
|
|
115
203
|
| `--env-file <path>` | `-f` | Env file to load (default: `.env.local`, repeatable) |
|
|
116
204
|
| `--out <path>` | `-o` | Output path for generate (default: `public/__env.js`) |
|
|
117
205
|
| `--filter <prefix>` | | Only include vars with this prefix |
|
|
118
|
-
| `--no-infisical` | | Skip Infisical
|
|
206
|
+
| `--no-infisical` | | Skip Infisical fetch entirely |
|
|
119
207
|
| `--verbose` | `-v` | Show loaded variable names |
|
|
120
208
|
|
|
121
209
|
## Config File
|
|
122
210
|
|
|
123
|
-
Create `
|
|
211
|
+
Create `mx-env.config.json` in your project root. Committed to git.
|
|
124
212
|
|
|
125
213
|
```json
|
|
126
214
|
{
|
|
127
215
|
"infisical": {
|
|
128
|
-
"
|
|
129
|
-
"
|
|
130
|
-
"env": "$DEPLOY_ENV"
|
|
216
|
+
"paths": ["/ai"],
|
|
217
|
+
"env": "dev"
|
|
131
218
|
},
|
|
132
219
|
"envFiles": [".env.local"],
|
|
133
220
|
"generate": {
|
|
@@ -137,56 +224,55 @@ Create `morphix-env.config.json` in your project root to declare project-level s
|
|
|
137
224
|
}
|
|
138
225
|
```
|
|
139
226
|
|
|
140
|
-
|
|
141
|
-
|-------|-------------|-------------------|
|
|
142
|
-
| `infisical.projectId` | Infisical project ID | Yes — not a secret |
|
|
143
|
-
| `infisical.paths` | Secret paths to pull | Yes — not a secret |
|
|
144
|
-
| `infisical.env` | Environment name, supports `$VAR` references | Yes |
|
|
145
|
-
| `envFiles` | Local override files to load | Yes |
|
|
146
|
-
| `generate` | Client-side __env.js output config | Yes |
|
|
227
|
+
### Config vs Environment Variables
|
|
147
228
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
229
|
+
```
|
|
230
|
+
┌──────────────────────────────────────────────────────┐
|
|
231
|
+
│ mx-env.config.json (committed to git) │
|
|
232
|
+
│ ├─ paths → which secrets to pull │
|
|
233
|
+
│ ├─ env → which environment │
|
|
234
|
+
│ ├─ envFiles → which override files to load │
|
|
235
|
+
│ └─ generate → __env.js output config │
|
|
236
|
+
│ │
|
|
237
|
+
│ These are PROJECT CONFIG, not secrets. │
|
|
238
|
+
├──────────────────────────────────────────────────────┤
|
|
239
|
+
│ Environment Variables (NEVER committed) │
|
|
240
|
+
│ ├─ INFISICAL_CLIENT_ID → Machine Identity │
|
|
241
|
+
│ ├─ INFISICAL_CLIENT_SECRET → Machine Identity │
|
|
242
|
+
│ └─ DEPLOY_ENV → prod / staging / dev │
|
|
243
|
+
│ │
|
|
244
|
+
│ These are CREDENTIALS, set in CI/Docker only. │
|
|
245
|
+
│ Local dev uses infisical CLI login instead. │
|
|
246
|
+
└──────────────────────────────────────────────────────┘
|
|
247
|
+
```
|
|
155
248
|
|
|
156
249
|
## Usage Examples
|
|
157
250
|
|
|
158
251
|
### Next.js
|
|
159
252
|
|
|
160
|
-
```
|
|
253
|
+
```jsonc
|
|
254
|
+
// package.json
|
|
161
255
|
{
|
|
162
256
|
"scripts": {
|
|
163
257
|
"dev": "morphix-env run -- next dev --turbo -p 3004",
|
|
164
258
|
"build": "morphix-env run -- next build",
|
|
165
|
-
"start": "morphix-env run --
|
|
259
|
+
"start": "morphix-env run -- next start"
|
|
166
260
|
}
|
|
167
261
|
}
|
|
168
262
|
```
|
|
169
263
|
|
|
170
|
-
`morphix-env.config.json`:
|
|
171
|
-
|
|
172
264
|
```json
|
|
265
|
+
// mx-env.config.json
|
|
173
266
|
{
|
|
174
|
-
"infisical": {
|
|
175
|
-
"projectId": "xxx",
|
|
176
|
-
"paths": ["/ai/shared", "/ai/web"],
|
|
177
|
-
"env": "$DEPLOY_ENV"
|
|
178
|
-
},
|
|
267
|
+
"infisical": { "paths": ["/ai"], "env": "dev" },
|
|
179
268
|
"envFiles": [".env.local"],
|
|
180
|
-
"generate": {
|
|
181
|
-
"out": "public/__env.js",
|
|
182
|
-
"filter": "NEXT_PUBLIC_"
|
|
183
|
-
}
|
|
269
|
+
"generate": { "out": "public/__env.js", "filter": "NEXT_PUBLIC_" }
|
|
184
270
|
}
|
|
185
271
|
```
|
|
186
272
|
|
|
187
273
|
### Vite (React / Vue / Ionic)
|
|
188
274
|
|
|
189
|
-
```
|
|
275
|
+
```jsonc
|
|
190
276
|
{
|
|
191
277
|
"scripts": {
|
|
192
278
|
"dev": "morphix-env run -- vite",
|
|
@@ -197,21 +283,14 @@ Create `morphix-env.config.json` in your project root to declare project-level s
|
|
|
197
283
|
|
|
198
284
|
```json
|
|
199
285
|
{
|
|
200
|
-
"infisical": {
|
|
201
|
-
|
|
202
|
-
"paths": ["/ai/shared", "/ai/shell"],
|
|
203
|
-
"env": "$DEPLOY_ENV"
|
|
204
|
-
},
|
|
205
|
-
"generate": {
|
|
206
|
-
"out": "dist/__env.js",
|
|
207
|
-
"filter": "VITE_"
|
|
208
|
-
}
|
|
286
|
+
"infisical": { "paths": ["/frontend"], "env": "dev" },
|
|
287
|
+
"generate": { "out": "dist/__env.js", "filter": "VITE_" }
|
|
209
288
|
}
|
|
210
289
|
```
|
|
211
290
|
|
|
212
291
|
### Express API
|
|
213
292
|
|
|
214
|
-
```
|
|
293
|
+
```jsonc
|
|
215
294
|
{
|
|
216
295
|
"scripts": {
|
|
217
296
|
"dev": "morphix-env run -- tsx watch src/index.ts",
|
|
@@ -222,15 +301,12 @@ Create `morphix-env.config.json` in your project root to declare project-level s
|
|
|
222
301
|
|
|
223
302
|
```json
|
|
224
303
|
{
|
|
225
|
-
"infisical": {
|
|
226
|
-
|
|
227
|
-
"paths": ["/ai/shared", "/ai/api"],
|
|
228
|
-
"env": "$DEPLOY_ENV"
|
|
229
|
-
}
|
|
304
|
+
"infisical": { "paths": ["/ai"], "env": "dev" },
|
|
305
|
+
"envFiles": [".env.local"]
|
|
230
306
|
}
|
|
231
307
|
```
|
|
232
308
|
|
|
233
|
-
No `generate`
|
|
309
|
+
No `generate` — server-side apps don't need `__env.js`.
|
|
234
310
|
|
|
235
311
|
### Docker
|
|
236
312
|
|
|
@@ -240,7 +316,6 @@ WORKDIR /app
|
|
|
240
316
|
COPY . .
|
|
241
317
|
RUN pnpm install && pnpm build
|
|
242
318
|
|
|
243
|
-
# Only these 3 vars needed at runtime
|
|
244
319
|
ENV INFISICAL_CLIENT_ID=""
|
|
245
320
|
ENV INFISICAL_CLIENT_SECRET=""
|
|
246
321
|
ENV DEPLOY_ENV="prod"
|
|
@@ -250,27 +325,6 @@ CMD ["npx", "morphix-env", "run", "--", "node", "server.js"]
|
|
|
250
325
|
|
|
251
326
|
No Infisical CLI binary needed in the image.
|
|
252
327
|
|
|
253
|
-
### Local Development with Infisical CLI
|
|
254
|
-
|
|
255
|
-
If you already use `infisical run` locally, morphix-env still adds value as the override layer:
|
|
256
|
-
|
|
257
|
-
```json
|
|
258
|
-
{
|
|
259
|
-
"dev": "infisical run --path=/ai --env=dev -- morphix-env run -- next dev",
|
|
260
|
-
"dev:local": "infisical run --path=/ai --env=dev -- morphix-env run -- next dev"
|
|
261
|
-
}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
`.env.local` overrides take effect on top of Infisical CLI injection.
|
|
265
|
-
|
|
266
|
-
## How It Works
|
|
267
|
-
|
|
268
|
-
1. Read `morphix-env.config.json` for project settings
|
|
269
|
-
2. If `INFISICAL_CLIENT_ID` + `INFISICAL_CLIENT_SECRET` exist → fetch secrets via SDK, inject into `process.env` (does not overwrite existing vars)
|
|
270
|
-
3. Read `.env.local` → inject into `process.env` (overwrites everything, highest priority)
|
|
271
|
-
4. If `generate` is configured → write `__env.js` with public vars
|
|
272
|
-
5. Spawn child command — it inherits the fully assembled `process.env`
|
|
273
|
-
|
|
274
328
|
## License
|
|
275
329
|
|
|
276
330
|
MIT
|
package/dist/cli.js
CHANGED
|
@@ -60,10 +60,14 @@ function extractPublicVars() {
|
|
|
60
60
|
|
|
61
61
|
// src/infisical.ts
|
|
62
62
|
var import_sdk = require("@infisical/sdk");
|
|
63
|
+
var import_child_process = require("child_process");
|
|
64
|
+
var import_fs2 = require("fs");
|
|
65
|
+
var import_path2 = require("path");
|
|
66
|
+
var import_dotenv2 = require("dotenv");
|
|
63
67
|
function getInfisicalConfig() {
|
|
64
68
|
const clientId = process.env.INFISICAL_CLIENT_ID;
|
|
65
69
|
const clientSecret = process.env.INFISICAL_CLIENT_SECRET;
|
|
66
|
-
const projectId = process.env.INFISICAL_PROJECT_ID;
|
|
70
|
+
const projectId = process.env.INFISICAL_PROJECT_ID || readInfisicalJson().workspaceId;
|
|
67
71
|
if (!clientId || !clientSecret || !projectId) return null;
|
|
68
72
|
return {
|
|
69
73
|
clientId,
|
|
@@ -98,37 +102,62 @@ async function fetchInfisicalSecrets(config) {
|
|
|
98
102
|
}
|
|
99
103
|
return count;
|
|
100
104
|
}
|
|
105
|
+
function hasInfisicalCLI() {
|
|
106
|
+
try {
|
|
107
|
+
(0, import_child_process.execSync)("infisical --version", { stdio: "pipe" });
|
|
108
|
+
return true;
|
|
109
|
+
} catch {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function readInfisicalJson() {
|
|
114
|
+
const filePath = (0, import_path2.resolve)(".infisical.json");
|
|
115
|
+
if (!(0, import_fs2.existsSync)(filePath)) return {};
|
|
116
|
+
try {
|
|
117
|
+
return JSON.parse((0, import_fs2.readFileSync)(filePath, "utf8"));
|
|
118
|
+
} catch {
|
|
119
|
+
return {};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function fetchSecretsViaCLI(environment, paths) {
|
|
123
|
+
let count = 0;
|
|
124
|
+
for (const secretPath of paths) {
|
|
125
|
+
try {
|
|
126
|
+
const output = (0, import_child_process.execSync)(
|
|
127
|
+
`infisical export --path=${secretPath} --env=${environment} --format=dotenv`,
|
|
128
|
+
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }
|
|
129
|
+
);
|
|
130
|
+
const vars = (0, import_dotenv2.parse)(output);
|
|
131
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
132
|
+
process.env[key] = value;
|
|
133
|
+
count++;
|
|
134
|
+
}
|
|
135
|
+
} catch {
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return count;
|
|
139
|
+
}
|
|
101
140
|
|
|
102
141
|
// src/config.ts
|
|
103
|
-
var
|
|
104
|
-
var
|
|
142
|
+
var import_fs3 = require("fs");
|
|
143
|
+
var import_path3 = require("path");
|
|
105
144
|
var CONFIG_FILE = "mx-env.config.json";
|
|
106
|
-
function resolveEnvRef(value) {
|
|
107
|
-
if (value.startsWith("$")) {
|
|
108
|
-
return process.env[value.slice(1)] || "";
|
|
109
|
-
}
|
|
110
|
-
return value;
|
|
111
|
-
}
|
|
112
145
|
function loadConfig() {
|
|
113
|
-
const configPath = (0,
|
|
114
|
-
if (!(0,
|
|
146
|
+
const configPath = (0, import_path3.resolve)(CONFIG_FILE);
|
|
147
|
+
if (!(0, import_fs3.existsSync)(configPath)) return {};
|
|
115
148
|
try {
|
|
116
|
-
|
|
117
|
-
if (raw.infisical?.env) {
|
|
118
|
-
raw.infisical.env = resolveEnvRef(raw.infisical.env);
|
|
119
|
-
}
|
|
120
|
-
return raw;
|
|
149
|
+
return JSON.parse((0, import_fs3.readFileSync)(configPath, "utf8"));
|
|
121
150
|
} catch (e) {
|
|
122
|
-
console.warn(`[
|
|
151
|
+
console.warn(`[morphix-env] Failed to parse ${CONFIG_FILE}: ${e.message}`);
|
|
123
152
|
return {};
|
|
124
153
|
}
|
|
125
154
|
}
|
|
126
155
|
|
|
127
156
|
// src/cli.ts
|
|
128
157
|
var import_cross_spawn = __toESM(require("cross-spawn"));
|
|
129
|
-
var
|
|
130
|
-
var
|
|
131
|
-
var VERSION = "0.
|
|
158
|
+
var import_fs4 = require("fs");
|
|
159
|
+
var import_path4 = require("path");
|
|
160
|
+
var VERSION = "0.4.1";
|
|
132
161
|
var DEFAULT_ENV_FILE = ".env.local";
|
|
133
162
|
function parseArgs(argv) {
|
|
134
163
|
const args = {
|
|
@@ -138,7 +167,8 @@ function parseArgs(argv) {
|
|
|
138
167
|
outFile: null,
|
|
139
168
|
verbose: false,
|
|
140
169
|
filter: null,
|
|
141
|
-
noInfisical: false
|
|
170
|
+
noInfisical: false,
|
|
171
|
+
env: null
|
|
142
172
|
};
|
|
143
173
|
let i = 2;
|
|
144
174
|
const command = argv[i];
|
|
@@ -160,6 +190,9 @@ function parseArgs(argv) {
|
|
|
160
190
|
} else if (arg === "--filter") {
|
|
161
191
|
i++;
|
|
162
192
|
if (argv[i]) args.filter = argv[i];
|
|
193
|
+
} else if (arg === "--env" || arg === "-e") {
|
|
194
|
+
i++;
|
|
195
|
+
if (argv[i]) args.env = argv[i];
|
|
163
196
|
} else if (arg === "--verbose" || arg === "-v") {
|
|
164
197
|
args.verbose = true;
|
|
165
198
|
} else if (arg === "--no-infisical") {
|
|
@@ -188,28 +221,42 @@ function mergeWithConfig(args, config) {
|
|
|
188
221
|
}
|
|
189
222
|
async function loadAllEnv(args, config) {
|
|
190
223
|
if (!args.noInfisical) {
|
|
224
|
+
const env = args.env || process.env.DEPLOY_ENV || process.env.INFISICAL_ENV || "prod";
|
|
225
|
+
const paths = config.infisical?.paths || ["/"];
|
|
226
|
+
const resolvedProjectId = process.env.INFISICAL_PROJECT_ID || config.infisical?.projectId || readInfisicalJson().workspaceId || "";
|
|
191
227
|
const infisicalConfig = config.infisical ? {
|
|
192
228
|
clientId: process.env.INFISICAL_CLIENT_ID || "",
|
|
193
229
|
clientSecret: process.env.INFISICAL_CLIENT_SECRET || "",
|
|
194
|
-
projectId:
|
|
195
|
-
environment:
|
|
196
|
-
paths
|
|
230
|
+
projectId: resolvedProjectId,
|
|
231
|
+
environment: env,
|
|
232
|
+
paths,
|
|
197
233
|
siteUrl: config.infisical.siteUrl
|
|
198
234
|
} : getInfisicalConfig();
|
|
199
235
|
if (infisicalConfig && infisicalConfig.clientId && infisicalConfig.clientSecret) {
|
|
200
236
|
try {
|
|
201
237
|
const count = await fetchInfisicalSecrets(infisicalConfig);
|
|
202
|
-
console.log(`[
|
|
238
|
+
console.log(`[morphix-env] Infisical SDK: loaded ${count} secrets (${env}: ${paths.join(", ")})`);
|
|
239
|
+
} catch (e) {
|
|
240
|
+
console.warn(`[morphix-env] Infisical SDK: failed - ${e.message}`);
|
|
241
|
+
}
|
|
242
|
+
} else if (hasInfisicalCLI()) {
|
|
243
|
+
try {
|
|
244
|
+
const count = fetchSecretsViaCLI(env, paths);
|
|
245
|
+
if (count > 0) {
|
|
246
|
+
console.log(`[morphix-env] Infisical CLI: loaded ${count} secrets (${env}: ${paths.join(", ")})`);
|
|
247
|
+
} else {
|
|
248
|
+
console.log(`[morphix-env] Infisical CLI: no secrets found (run 'infisical login' first?)`);
|
|
249
|
+
}
|
|
203
250
|
} catch (e) {
|
|
204
|
-
console.warn(`[
|
|
251
|
+
console.warn(`[morphix-env] Infisical CLI: failed - ${e.message}`);
|
|
205
252
|
}
|
|
206
253
|
} else if (args.verbose) {
|
|
207
|
-
console.log("[
|
|
254
|
+
console.log("[morphix-env] Infisical: skipped (no SDK credentials, no CLI)");
|
|
208
255
|
}
|
|
209
256
|
}
|
|
210
257
|
const overrides = loadEnvFiles(args.envFiles);
|
|
211
258
|
if (overrides.length > 0) {
|
|
212
|
-
console.log(`[
|
|
259
|
+
console.log(`[morphix-env] Loaded ${overrides.length} overrides from ${args.envFiles.join(", ")}`);
|
|
213
260
|
if (args.verbose) {
|
|
214
261
|
for (const o of overrides) {
|
|
215
262
|
console.log(` ${o.key} (from ${o.source})`);
|
|
@@ -219,7 +266,7 @@ async function loadAllEnv(args, config) {
|
|
|
219
266
|
}
|
|
220
267
|
async function cmdRun(args, config) {
|
|
221
268
|
if (args.subArgs.length === 0) {
|
|
222
|
-
console.error("[
|
|
269
|
+
console.error("[morphix-env] No command specified. Usage: mx-env run -- <command>");
|
|
223
270
|
process.exit(1);
|
|
224
271
|
}
|
|
225
272
|
await loadAllEnv(args, config);
|
|
@@ -232,7 +279,7 @@ async function cmdRun(args, config) {
|
|
|
232
279
|
env: process.env
|
|
233
280
|
});
|
|
234
281
|
if (result.error) {
|
|
235
|
-
console.error(`[
|
|
282
|
+
console.error(`[morphix-env] Failed to execute: ${cmd}`, result.error.message);
|
|
236
283
|
process.exit(1);
|
|
237
284
|
}
|
|
238
285
|
process.exit(result.status ?? 1);
|
|
@@ -245,9 +292,9 @@ function generateClientEnv(outFile, filter) {
|
|
|
245
292
|
);
|
|
246
293
|
}
|
|
247
294
|
const js = `window.__ENV=${JSON.stringify(vars)};`;
|
|
248
|
-
(0,
|
|
249
|
-
(0,
|
|
250
|
-
console.log(`[
|
|
295
|
+
(0, import_fs4.mkdirSync)((0, import_path4.dirname)(outFile), { recursive: true });
|
|
296
|
+
(0, import_fs4.writeFileSync)(outFile, js);
|
|
297
|
+
console.log(`[morphix-env] Generated ${outFile} (${Object.keys(vars).length} client vars)`);
|
|
251
298
|
}
|
|
252
299
|
async function cmdGenerate(args, config) {
|
|
253
300
|
const outFile = args.outFile || "public/__env.js";
|
|
@@ -288,7 +335,7 @@ process.env public vars: (${filtered.length})`);
|
|
|
288
335
|
}
|
|
289
336
|
function showHelp() {
|
|
290
337
|
console.log(`
|
|
291
|
-
|
|
338
|
+
morphix-env v${VERSION} \u2014 MorphixAI environment variable toolkit
|
|
292
339
|
|
|
293
340
|
Usage:
|
|
294
341
|
mx-env run [options] -- <command> Load env + exec command
|
|
@@ -298,8 +345,9 @@ Usage:
|
|
|
298
345
|
Options:
|
|
299
346
|
-f, --env-file <path> Env file to load (default: .env.local, repeatable)
|
|
300
347
|
-o, --out <path> Output path for generate (default: public/__env.js)
|
|
348
|
+
-e, --env <name> Infisical environment (dev/staging/prod), overrides config
|
|
301
349
|
--filter <prefix> Only include vars with this prefix
|
|
302
|
-
--no-infisical Skip Infisical
|
|
350
|
+
--no-infisical Skip Infisical fetch entirely
|
|
303
351
|
-v, --verbose Show loaded variable names
|
|
304
352
|
--help, -h Show this help
|
|
305
353
|
--version Show version
|
|
@@ -355,13 +403,13 @@ async function main() {
|
|
|
355
403
|
break;
|
|
356
404
|
default:
|
|
357
405
|
if (args.command) {
|
|
358
|
-
console.error(`[
|
|
406
|
+
console.error(`[morphix-env] Unknown command: ${args.command}`);
|
|
359
407
|
}
|
|
360
408
|
showHelp();
|
|
361
409
|
process.exit(args.command ? 1 : 0);
|
|
362
410
|
}
|
|
363
411
|
}
|
|
364
412
|
main().catch((e) => {
|
|
365
|
-
console.error("[
|
|
413
|
+
console.error("[morphix-env] Fatal:", e.message);
|
|
366
414
|
process.exit(1);
|
|
367
415
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "morphix-env",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Environment variable toolkit — Infisical integration, local overrides, and client-side runtime injection for Next.js / Vite / Express.",
|
|
5
5
|
"author": "MorphixAI <dev@morphixai.com>",
|
|
6
6
|
"homepage": "https://github.com/Morphicai/morphix-env#readme",
|