@dotenvage/node 0.1.5
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 +337 -0
- package/bin/dotenvage-next.js +18 -0
- package/bin/dotenvage.js +265 -0
- package/dotenvage-napi.darwin-arm64.node +0 -0
- package/dotenvage-napi.darwin-x64.node +0 -0
- package/dotenvage-napi.linux-arm64-musl.node +0 -0
- package/examples/app-config.ts +129 -0
- package/examples/auto-encrypt.ts +132 -0
- package/examples/basic.js +127 -0
- package/examples/encrypt-decrypt.ts +56 -0
- package/examples/load-env.ts +51 -0
- package/examples/nextjs-config.ts +132 -0
- package/examples/tsconfig.json +22 -0
- package/index.d.ts +57 -0
- package/index.js +582 -0
- package/nextjs/README.md +271 -0
- package/nextjs/config.d.ts +32 -0
- package/nextjs/config.mjs +59 -0
- package/nextjs/loader.d.ts +22 -0
- package/nextjs/loader.mjs +117 -0
- package/nextjs/preinit.d.ts +13 -0
- package/nextjs/preinit.mjs +106 -0
- package/nextjs/wrapper.mjs +87 -0
- package/package.json +91 -0
package/README.md
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# @dotenvage/node
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@dotenvage/node)
|
|
4
|
+
[](https://github.com/dataroadinc/dotenvage/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
Node.js bindings for
|
|
7
|
+
[dotenvage](https://github.com/dataroadinc/dotenvage) - **Dotenv with
|
|
8
|
+
age encryption**.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- 🔒 **Encrypt secrets in `.env` files** - Safely commit encrypted
|
|
13
|
+
secrets to version control
|
|
14
|
+
- 📦 **Native performance** - Built with NAPI-RS for fast Rust
|
|
15
|
+
performance
|
|
16
|
+
- 🔄 **Auto-detection** - Automatically identifies which keys should
|
|
17
|
+
be encrypted
|
|
18
|
+
- 🌳 **File layering** - Multiple `.env*` files with automatic
|
|
19
|
+
precedence
|
|
20
|
+
- 💻 **CLI support** - Includes `dotenvage` command-line tool
|
|
21
|
+
- 📝 **TypeScript support** - Full TypeScript definitions included
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @dotenvage/node
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
### Basic Usage (Like dotenv)
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import * as dotenvage from "@dotenvage/node";
|
|
35
|
+
|
|
36
|
+
// Load encrypted .env files into process.env
|
|
37
|
+
const loader = dotenvage.JsEnvLoaderNew();
|
|
38
|
+
loader.load(); // Mutates process.env (like dotenv.config())
|
|
39
|
+
|
|
40
|
+
// Now access variables
|
|
41
|
+
const apiKey = process.env.API_KEY;
|
|
42
|
+
const dbUrl = process.env.DATABASE_URL;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Get Variables as Object (Non-mutating)
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import * as dotenvage from "@dotenvage/node";
|
|
49
|
+
|
|
50
|
+
const loader = dotenvage.JsEnvLoaderNew();
|
|
51
|
+
const env = loader.getAllVariables(); // Returns Record<string, string>
|
|
52
|
+
|
|
53
|
+
// Use without modifying process.env
|
|
54
|
+
console.log(env.API_KEY);
|
|
55
|
+
console.log(env.DATABASE_URL);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Encrypt and Decrypt Values
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import * as dotenvage from "@dotenvage/node";
|
|
62
|
+
|
|
63
|
+
// Generate a new key pair
|
|
64
|
+
const manager = dotenvage.JsSecretManagerGenerate();
|
|
65
|
+
const publicKey = manager.publicKeyString(); // Share this public key
|
|
66
|
+
|
|
67
|
+
// Encrypt a secret
|
|
68
|
+
const secret = "sk_live_abc123";
|
|
69
|
+
const encrypted = manager.encryptValue(secret);
|
|
70
|
+
// Returns: "ENC[AGE:b64:...]"
|
|
71
|
+
|
|
72
|
+
// Decrypt it back
|
|
73
|
+
const decrypted = manager.decryptValue(encrypted);
|
|
74
|
+
console.log(decrypted === secret); // true
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## API Reference
|
|
78
|
+
|
|
79
|
+
### JsEnvLoader
|
|
80
|
+
|
|
81
|
+
Loads and decrypts `.env` files.
|
|
82
|
+
|
|
83
|
+
#### `JsEnvLoaderNew(): JsEnvLoader`
|
|
84
|
+
|
|
85
|
+
Creates a new loader with a default SecretManager.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
const loader = dotenvage.JsEnvLoaderNew();
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### `load(): void`
|
|
92
|
+
|
|
93
|
+
Loads `.env` files from the current directory into `process.env`.
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
loader.load(); // Sets variables in process.env
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### `loadFromDir(dir: string): void`
|
|
100
|
+
|
|
101
|
+
Loads `.env` files from a specific directory.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
loader.loadFromDir("./config");
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### `getAllVariableNames(): string[]`
|
|
108
|
+
|
|
109
|
+
Gets all variable names from all loaded `.env` files (without loading
|
|
110
|
+
into environment).
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
const names = loader.getAllVariableNames();
|
|
114
|
+
console.log(names); // ["API_KEY", "DATABASE_URL", ...]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### `getAllVariables(): Record<string, string>`
|
|
118
|
+
|
|
119
|
+
Gets all environment variables as an object (decrypted). Note: This
|
|
120
|
+
loads variables into the process environment first.
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
const env = loader.getAllVariables();
|
|
124
|
+
console.log(env.API_KEY);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### `resolveEnvPaths(dir: string): string[]`
|
|
128
|
+
|
|
129
|
+
Computes the ordered list of env file paths that would be loaded.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
const paths = loader.resolveEnvPaths(".");
|
|
133
|
+
console.log(paths); // [".env", ".env.local", ...]
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### JsSecretManager
|
|
137
|
+
|
|
138
|
+
Manages encryption and decryption of secrets.
|
|
139
|
+
|
|
140
|
+
#### `JsSecretManagerGenerate(): JsSecretManager`
|
|
141
|
+
|
|
142
|
+
Generates a new random encryption key pair.
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
const manager = dotenvage.JsSecretManagerGenerate();
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### `JsSecretManagerNew(): JsSecretManager`
|
|
149
|
+
|
|
150
|
+
Creates a SecretManager by loading the key from standard locations:
|
|
151
|
+
|
|
152
|
+
1. `DOTENVAGE_AGE_KEY` environment variable
|
|
153
|
+
2. `AGE_KEY` environment variable
|
|
154
|
+
3. `EKG_AGE_KEY` environment variable
|
|
155
|
+
4. Key file at `~/.local/state/dotenvage/dotenvage.key`
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
const manager = dotenvage.JsSecretManagerNew();
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### `publicKeyString(): string`
|
|
162
|
+
|
|
163
|
+
Gets the public key as a string (starts with `age1`).
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
const publicKey = manager.publicKeyString();
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
#### `encryptValue(plaintext: string): string`
|
|
170
|
+
|
|
171
|
+
Encrypts a plaintext value.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const encrypted = manager.encryptValue("secret");
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### `decryptValue(value: string): string`
|
|
178
|
+
|
|
179
|
+
Decrypts a value if it's encrypted; otherwise returns it unchanged.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
const decrypted = manager.decryptValue(encrypted);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### `isEncrypted(value: string): boolean`
|
|
186
|
+
|
|
187
|
+
Checks if a value is in a recognized encrypted format.
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
const isEncrypted = manager.isEncrypted("ENC[AGE:b64:...]");
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Utility Functions
|
|
194
|
+
|
|
195
|
+
#### `shouldEncrypt(key: string): boolean`
|
|
196
|
+
|
|
197
|
+
Checks if a key name should be encrypted based on auto-detection
|
|
198
|
+
patterns.
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
dotenvage.shouldEncrypt("API_KEY"); // true
|
|
202
|
+
dotenvage.shouldEncrypt("PORT"); // false
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## CLI Usage
|
|
206
|
+
|
|
207
|
+
The package includes a `dotenvage` CLI command:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
npx dotenvage list
|
|
211
|
+
npx dotenvage get API_KEY
|
|
212
|
+
npx dotenvage dump --export
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
See the
|
|
216
|
+
[main dotenvage README](https://github.com/dataroadinc/dotenvage#usage)
|
|
217
|
+
for full CLI documentation.
|
|
218
|
+
|
|
219
|
+
## Next.js Integration
|
|
220
|
+
|
|
221
|
+
For Next.js applications, use the dedicated integration utilities:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// In next.config.mjs
|
|
225
|
+
import { loadEnv } from "@dotenvage/node/nextjs";
|
|
226
|
+
loadEnv();
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Or use the pre-initialization loader to ensure environment variables
|
|
230
|
+
are available for Edge Runtime (middleware):
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"scripts": {
|
|
235
|
+
"dev": "node -r @dotenvage/node/nextjs/preinit node_modules/.bin/next dev"
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
See [`nextjs/README.md`](./nextjs/README.md) for complete Next.js
|
|
241
|
+
integration documentation.
|
|
242
|
+
|
|
243
|
+
## TypeScript Examples
|
|
244
|
+
|
|
245
|
+
See the `examples/` directory for TypeScript examples:
|
|
246
|
+
|
|
247
|
+
- `load-env.ts` - Loading environment variables
|
|
248
|
+
- `encrypt-decrypt.ts` - Encryption and decryption
|
|
249
|
+
- `app-config.ts` - Type-safe application configuration
|
|
250
|
+
- `auto-encrypt.ts` - Auto-detection patterns
|
|
251
|
+
- `nextjs-config.ts` - Basic Next.js usage example
|
|
252
|
+
|
|
253
|
+
## File Layering
|
|
254
|
+
|
|
255
|
+
dotenvage supports automatic file layering with precedence:
|
|
256
|
+
|
|
257
|
+
1. `.env` - Base configuration
|
|
258
|
+
2. `.env.<ENV>` - Environment-specific (e.g., `.env.production`)
|
|
259
|
+
3. `.env.<ENV>.<OS>` - OS-specific (e.g., `.env.production.linux`)
|
|
260
|
+
4. `.env.<ENV>.<OS>.<ARCH>` - Architecture-specific
|
|
261
|
+
5. `.env.<ENV>.<OS>.<ARCH>.<USER>` - User-specific overrides
|
|
262
|
+
|
|
263
|
+
Files are loaded in specificity order - more specific files override
|
|
264
|
+
less specific ones.
|
|
265
|
+
|
|
266
|
+
## Key Management
|
|
267
|
+
|
|
268
|
+
### Setting the Encryption Key
|
|
269
|
+
|
|
270
|
+
Set one of these environment variables:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
export DOTENVAGE_AGE_KEY="AGE-SECRET-KEY-1..."
|
|
274
|
+
export AGE_KEY="AGE-SECRET-KEY-1..."
|
|
275
|
+
export EKG_AGE_KEY="AGE-SECRET-KEY-1..."
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Generating a Key
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
const manager = dotenvage.JsSecretManagerGenerate();
|
|
282
|
+
const publicKey = manager.publicKeyString();
|
|
283
|
+
console.log(`Public key: ${publicKey}`);
|
|
284
|
+
console.log(`Set: export DOTENVAGE_AGE_KEY="<private-key>"`);
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Or use the CLI:
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
npx dotenvage keygen
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Comparison with dotenv
|
|
294
|
+
|
|
295
|
+
| Feature | dotenv | @dotenvage/node |
|
|
296
|
+
| -------------------- | ------ | --------------- |
|
|
297
|
+
| Load `.env` files | ✅ | ✅ |
|
|
298
|
+
| Mutate `process.env` | ✅ | ✅ |
|
|
299
|
+
| Encrypt secrets | ❌ | ✅ |
|
|
300
|
+
| Commit to git safely | ❌ | ✅ |
|
|
301
|
+
| File layering | ❌ | ✅ |
|
|
302
|
+
| Auto-detection | ❌ | ✅ |
|
|
303
|
+
| Native performance | ❌ | ✅ (Rust) |
|
|
304
|
+
|
|
305
|
+
## Requirements
|
|
306
|
+
|
|
307
|
+
- Node.js >= 18.0.0
|
|
308
|
+
- Valid age encryption key (set via environment variable or key file)
|
|
309
|
+
|
|
310
|
+
## Building from Source
|
|
311
|
+
|
|
312
|
+
From the `npm/` directory:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
cd npm
|
|
316
|
+
npm install
|
|
317
|
+
npm run build
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Or from the project root:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
npm run npm:install
|
|
324
|
+
npm run npm:build
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## License
|
|
328
|
+
|
|
329
|
+
MIT - See
|
|
330
|
+
[LICENSE](https://github.com/dataroadinc/dotenvage/blob/main/LICENSE)
|
|
331
|
+
|
|
332
|
+
## Links
|
|
333
|
+
|
|
334
|
+
- [GitHub Repository](https://github.com/dataroadinc/dotenvage)
|
|
335
|
+
- [Rust Crate](https://crates.io/crates/dotenvage)
|
|
336
|
+
- [Rust Documentation](https://docs.rs/dotenvage)
|
|
337
|
+
- [Main README](https://github.com/dataroadinc/dotenvage#readme)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Next.js wrapper for dotenvage - loads encrypted environment variables before Next.js starts.
|
|
4
|
+
*
|
|
5
|
+
* This bin script allows users to call dotenvage-next directly without specifying the full path.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* pnpm exec dotenvage-next dev
|
|
9
|
+
* pnpm exec dotenvage-next build
|
|
10
|
+
*
|
|
11
|
+
* Or via package.json scripts:
|
|
12
|
+
* "dev": "dotenvage-next dev"
|
|
13
|
+
* "build": "dotenvage-next build"
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// Import and execute the wrapper script
|
|
17
|
+
// The wrapper.mjs file uses top-level await and has side effects, so importing it will execute it
|
|
18
|
+
import("../nextjs/wrapper.mjs");
|
package/bin/dotenvage.js
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Node.js CLI wrapper for dotenvage
|
|
5
|
+
*
|
|
6
|
+
* This wrapper attempts to use the native Rust binary if available,
|
|
7
|
+
* otherwise falls back to using the NAPI bindings to implement CLI functionality.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { existsSync } = require("fs");
|
|
11
|
+
const { join } = require("path");
|
|
12
|
+
const { spawn, execSync } = require("child_process");
|
|
13
|
+
const { platform, arch } = require("os");
|
|
14
|
+
|
|
15
|
+
// Determine the binary name based on platform
|
|
16
|
+
function getBinaryName() {
|
|
17
|
+
const plat = platform();
|
|
18
|
+
const architecture = arch();
|
|
19
|
+
|
|
20
|
+
// Map Node.js arch to Rust target arch
|
|
21
|
+
const archMap = {
|
|
22
|
+
x64: "x86_64",
|
|
23
|
+
arm64: "aarch64",
|
|
24
|
+
ia32: "i686",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const rustArch = archMap[architecture] || architecture;
|
|
28
|
+
|
|
29
|
+
if (plat === "win32") {
|
|
30
|
+
return `dotenvage-${rustArch}-pc-windows-msvc.exe`;
|
|
31
|
+
} else if (plat === "darwin") {
|
|
32
|
+
return `dotenvage-${rustArch}-apple-darwin`;
|
|
33
|
+
} else {
|
|
34
|
+
return `dotenvage-${rustArch}-unknown-linux-gnu`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Try to find the native binary
|
|
39
|
+
function findNativeBinary() {
|
|
40
|
+
// Check in common locations
|
|
41
|
+
const possiblePaths = [
|
|
42
|
+
// In the npm package directory
|
|
43
|
+
join(__dirname, "..", "bin", getBinaryName()),
|
|
44
|
+
// In node_modules/.bin
|
|
45
|
+
join(__dirname, "..", "..", "..", "bin", getBinaryName()),
|
|
46
|
+
// Global installation
|
|
47
|
+
join(
|
|
48
|
+
process.env.HOME || process.env.USERPROFILE || "",
|
|
49
|
+
".cargo",
|
|
50
|
+
"bin",
|
|
51
|
+
"dotenvage"
|
|
52
|
+
),
|
|
53
|
+
join(
|
|
54
|
+
process.env.HOME || process.env.USERPROFILE || "",
|
|
55
|
+
".local",
|
|
56
|
+
"bin",
|
|
57
|
+
"dotenvage"
|
|
58
|
+
),
|
|
59
|
+
// PATH
|
|
60
|
+
"dotenvage",
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
for (const path of possiblePaths) {
|
|
64
|
+
try {
|
|
65
|
+
if (path === "dotenvage") {
|
|
66
|
+
// Check if it's in PATH
|
|
67
|
+
execSync(`which ${path}`, { stdio: "ignore" });
|
|
68
|
+
return path;
|
|
69
|
+
} else if (existsSync(path)) {
|
|
70
|
+
return path;
|
|
71
|
+
}
|
|
72
|
+
} catch (e) {
|
|
73
|
+
// Continue searching
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Fallback to NAPI implementation
|
|
81
|
+
function useNapiImplementation() {
|
|
82
|
+
try {
|
|
83
|
+
const dotenvage = require("../index.js");
|
|
84
|
+
|
|
85
|
+
// Parse command line arguments
|
|
86
|
+
const args = process.argv.slice(2);
|
|
87
|
+
const command = args[0];
|
|
88
|
+
|
|
89
|
+
switch (command) {
|
|
90
|
+
case "keygen":
|
|
91
|
+
case "gen":
|
|
92
|
+
{
|
|
93
|
+
const manager = dotenvage.JsSecretManagerGenerate();
|
|
94
|
+
console.log(`✓ Private key generated`);
|
|
95
|
+
console.log(
|
|
96
|
+
`Public recipient: ${manager.publicKeyString()}`
|
|
97
|
+
);
|
|
98
|
+
console.log(
|
|
99
|
+
`Note: Use DOTENVAGE_AGE_KEY or AGE_KEY environment variable to set the key`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
|
|
104
|
+
case "get":
|
|
105
|
+
{
|
|
106
|
+
const key = args[1];
|
|
107
|
+
if (!key) {
|
|
108
|
+
console.error("Error: key name required");
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const loader = dotenvage.JsEnvLoaderNew();
|
|
113
|
+
loader.load();
|
|
114
|
+
|
|
115
|
+
const value = process.env[key];
|
|
116
|
+
if (value === undefined) {
|
|
117
|
+
console.error(
|
|
118
|
+
`Error: key '${key}' not found in any .env* file`
|
|
119
|
+
);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.log(value);
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
|
|
127
|
+
case "list":
|
|
128
|
+
{
|
|
129
|
+
const verbose =
|
|
130
|
+
args.includes("--verbose") || args.includes("-v");
|
|
131
|
+
const json = args.includes("--json");
|
|
132
|
+
const plain = args.includes("--plain");
|
|
133
|
+
const fileIndex = args.indexOf("--file");
|
|
134
|
+
const file = fileIndex >= 0 ? args[fileIndex + 1] : null;
|
|
135
|
+
|
|
136
|
+
const loader = dotenvage.JsEnvLoaderNew();
|
|
137
|
+
let names;
|
|
138
|
+
|
|
139
|
+
if (file) {
|
|
140
|
+
loader.loadFromDir(process.cwd());
|
|
141
|
+
names = loader.getAllVariableNamesFromDir(process.cwd());
|
|
142
|
+
} else {
|
|
143
|
+
loader.load();
|
|
144
|
+
names = loader.getAllVariableNames();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (json) {
|
|
148
|
+
const output = {};
|
|
149
|
+
for (const name of names) {
|
|
150
|
+
const value = process.env[name];
|
|
151
|
+
if (value) {
|
|
152
|
+
output[name] = verbose
|
|
153
|
+
? { value, encrypted: false }
|
|
154
|
+
: { encrypted: false };
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
console.log(JSON.stringify(output, null, 2));
|
|
158
|
+
} else {
|
|
159
|
+
for (const name of names) {
|
|
160
|
+
if (verbose) {
|
|
161
|
+
const value = process.env[name];
|
|
162
|
+
const lockIcon = " "; // Can't easily detect encryption without manager
|
|
163
|
+
console.log(`${lockIcon} ${name} = ${value}`);
|
|
164
|
+
} else if (plain) {
|
|
165
|
+
console.log(name);
|
|
166
|
+
} else {
|
|
167
|
+
console.log(` ${name}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
|
|
174
|
+
case "dump":
|
|
175
|
+
{
|
|
176
|
+
const exportFlag =
|
|
177
|
+
args.includes("--export") || args.includes("-e");
|
|
178
|
+
const fileIndex = args.indexOf("--file");
|
|
179
|
+
const file = fileIndex >= 0 ? args[fileIndex + 1] : null;
|
|
180
|
+
|
|
181
|
+
const loader = dotenvage.JsEnvLoaderNew();
|
|
182
|
+
|
|
183
|
+
if (file) {
|
|
184
|
+
loader.loadFromDir(process.cwd());
|
|
185
|
+
} else {
|
|
186
|
+
loader.load();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const vars = loader.getAllVariables();
|
|
190
|
+
const prefix = exportFlag ? "export " : "";
|
|
191
|
+
|
|
192
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
193
|
+
// Simple escaping for values
|
|
194
|
+
const needsQuotes =
|
|
195
|
+
value.includes(" ") ||
|
|
196
|
+
value.includes("$") ||
|
|
197
|
+
value.includes("`");
|
|
198
|
+
if (needsQuotes) {
|
|
199
|
+
const escaped = value
|
|
200
|
+
.replace(/"/g, '\\"')
|
|
201
|
+
.replace(/\$/g, "\\$");
|
|
202
|
+
console.log(`${prefix}${key}="${escaped}"`);
|
|
203
|
+
} else {
|
|
204
|
+
console.log(`${prefix}${key}=${value}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
break;
|
|
209
|
+
|
|
210
|
+
default:
|
|
211
|
+
console.error(`Error: Unknown command '${command}'`);
|
|
212
|
+
console.error(`
|
|
213
|
+
Usage: dotenvage <command> [options]
|
|
214
|
+
|
|
215
|
+
Commands:
|
|
216
|
+
keygen, gen Generate a new encryption key pair
|
|
217
|
+
get <key> Get a decrypted secret value
|
|
218
|
+
list List environment variables
|
|
219
|
+
dump Dump all decrypted env vars
|
|
220
|
+
|
|
221
|
+
Note: This is a limited implementation using NAPI bindings.
|
|
222
|
+
For full functionality, install the native Rust binary:
|
|
223
|
+
cargo install dotenvage
|
|
224
|
+
`);
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.error("Error:", error.message);
|
|
229
|
+
console.error(`
|
|
230
|
+
Note: Native bindings not available. Install the native Rust binary:
|
|
231
|
+
cargo install dotenvage
|
|
232
|
+
`);
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Main entry point
|
|
238
|
+
function main() {
|
|
239
|
+
const binary = findNativeBinary();
|
|
240
|
+
|
|
241
|
+
if (binary) {
|
|
242
|
+
// Use native binary
|
|
243
|
+
const child = spawn(binary, process.argv.slice(2), {
|
|
244
|
+
stdio: "inherit",
|
|
245
|
+
shell: false,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
child.on("error", (error) => {
|
|
249
|
+
console.error(`Error running dotenvage: ${error.message}`);
|
|
250
|
+
console.error("Falling back to NAPI implementation...");
|
|
251
|
+
useNapiImplementation();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
child.on("exit", (code) => {
|
|
255
|
+
process.exit(code || 0);
|
|
256
|
+
});
|
|
257
|
+
} else {
|
|
258
|
+
// Fallback to NAPI implementation
|
|
259
|
+
useNapiImplementation();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (require.main === module) {
|
|
264
|
+
main();
|
|
265
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|