@captainsafia/burrow 1.0.0-preview.0d335f8 → 1.0.0-preview.2be53e0
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 +26 -7
- package/dist/api.d.ts +5 -9
- package/dist/api.js +53 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ burrow set DATABASE_URL=postgres://localhost/mydb --path ~/projects
|
|
|
30
30
|
### Get a secret
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
burrow get API_KEY
|
|
33
|
+
burrow get API_KEY
|
|
34
34
|
burrow get API_KEY --format json
|
|
35
35
|
```
|
|
36
36
|
|
|
@@ -44,8 +44,14 @@ burrow list --format json
|
|
|
44
44
|
### Export to your shell
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
+
# Auto-detects your shell (bash, fish, powershell, cmd)
|
|
47
48
|
eval "$(burrow export)"
|
|
48
|
-
|
|
49
|
+
|
|
50
|
+
# Or specify a format explicitly
|
|
51
|
+
burrow export --format fish
|
|
52
|
+
burrow export --format powershell
|
|
53
|
+
burrow export --format dotenv
|
|
54
|
+
burrow export --format json
|
|
49
55
|
```
|
|
50
56
|
|
|
51
57
|
### Block inheritance
|
|
@@ -84,13 +90,26 @@ import { BurrowClient } from '@captainsafia/burrow';
|
|
|
84
90
|
|
|
85
91
|
const client = new BurrowClient();
|
|
86
92
|
|
|
87
|
-
|
|
93
|
+
try {
|
|
94
|
+
await client.set('API_KEY', 'secret123', { path: '/my/project' });
|
|
95
|
+
|
|
96
|
+
const secret = await client.get('API_KEY', { cwd: '/my/project/subdir' });
|
|
97
|
+
console.log(secret?.value); // 'secret123'
|
|
98
|
+
console.log(secret?.sourcePath); // '/my/project'
|
|
88
99
|
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
const allSecrets = await client.list({ cwd: '/my/project' });
|
|
101
|
+
} finally {
|
|
102
|
+
client.close(); // Clean up database connection
|
|
103
|
+
}
|
|
104
|
+
```
|
|
92
105
|
|
|
93
|
-
|
|
106
|
+
Or with TypeScript's `using` declarations for automatic cleanup:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
{
|
|
110
|
+
using client = new BurrowClient();
|
|
111
|
+
await client.set('API_KEY', 'secret123');
|
|
112
|
+
} // Automatically cleaned up
|
|
94
113
|
```
|
|
95
114
|
|
|
96
115
|
## Contributing
|
package/dist/api.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export interface ResolvedSecret {
|
|
|
5
5
|
value: string;
|
|
6
6
|
sourcePath: string;
|
|
7
7
|
}
|
|
8
|
-
export type ExportFormat = "shell" | "dotenv" | "json";
|
|
8
|
+
export type ExportFormat = "shell" | "bash" | "fish" | "powershell" | "cmd" | "dotenv" | "json";
|
|
9
9
|
/**
|
|
10
10
|
* Configuration options for creating a BurrowClient instance.
|
|
11
11
|
*/
|
|
@@ -21,7 +21,7 @@ export interface BurrowClientOptions {
|
|
|
21
21
|
configDir?: string;
|
|
22
22
|
/**
|
|
23
23
|
* Custom filename for the secrets store.
|
|
24
|
-
* Defaults to `store.
|
|
24
|
+
* Defaults to `store.db`.
|
|
25
25
|
*/
|
|
26
26
|
storeFileName?: string;
|
|
27
27
|
/**
|
|
@@ -99,10 +99,6 @@ export interface ExportOptions {
|
|
|
99
99
|
* - `json`: Exports as a JSON object
|
|
100
100
|
*/
|
|
101
101
|
format?: ExportFormat;
|
|
102
|
-
/**
|
|
103
|
-
* Whether to show actual values (currently unused, reserved for future use).
|
|
104
|
-
*/
|
|
105
|
-
showValues?: boolean;
|
|
106
102
|
/**
|
|
107
103
|
* Whether to include source paths in JSON output.
|
|
108
104
|
* When true, JSON output includes `{ key: { value, sourcePath } }` format.
|
|
@@ -151,7 +147,7 @@ export declare class BurrowClient {
|
|
|
151
147
|
* The secret will be available to the specified directory and all its
|
|
152
148
|
* subdirectories, unless overridden or blocked at a deeper level.
|
|
153
149
|
*
|
|
154
|
-
* @param key - Environment variable name. Must match `^[A-
|
|
150
|
+
* @param key - Environment variable name. Must match `^[A-Za-z_][A-Za-z0-9_]*$`
|
|
155
151
|
* @param value - Secret value to store
|
|
156
152
|
* @param options - Set options including target path
|
|
157
153
|
* @throws Error if the key format is invalid
|
|
@@ -215,7 +211,7 @@ export declare class BurrowClient {
|
|
|
215
211
|
*
|
|
216
212
|
* A blocked key can be re-enabled by calling `set` at the same or deeper path.
|
|
217
213
|
*
|
|
218
|
-
* @param key - Environment variable name to block. Must match `^[A-
|
|
214
|
+
* @param key - Environment variable name to block. Must match `^[A-Za-z_][A-Za-z0-9_]*$`
|
|
219
215
|
* @param options - Block options including target path
|
|
220
216
|
* @throws Error if the key format is invalid
|
|
221
217
|
*
|
|
@@ -240,7 +236,7 @@ export declare class BurrowClient {
|
|
|
240
236
|
* `remove` completely deletes the secret entry. After removal, the key
|
|
241
237
|
* may still be inherited from parent directories if defined there.
|
|
242
238
|
*
|
|
243
|
-
* @param key - Environment variable name to remove. Must match `^[A-
|
|
239
|
+
* @param key - Environment variable name to remove. Must match `^[A-Za-z_][A-Za-z0-9_]*$`
|
|
244
240
|
* @param options - Remove options including target path
|
|
245
241
|
* @returns true if the secret was found and removed, false if it didn't exist
|
|
246
242
|
* @throws Error if the key format is invalid
|
package/dist/api.js
CHANGED
|
@@ -66,10 +66,10 @@ class Storage {
|
|
|
66
66
|
await chmod(this.configDir, 448);
|
|
67
67
|
}
|
|
68
68
|
this.db = new Database(this.storePath);
|
|
69
|
-
this.db.run("PRAGMA journal_mode = WAL");
|
|
70
69
|
if (!isWindows()) {
|
|
71
70
|
await chmod(this.storePath, 384);
|
|
72
71
|
}
|
|
72
|
+
this.db.run("PRAGMA journal_mode = WAL");
|
|
73
73
|
this.db.run(`
|
|
74
74
|
CREATE TABLE IF NOT EXISTS secrets (
|
|
75
75
|
path TEXT NOT NULL,
|
|
@@ -122,7 +122,12 @@ class Storage {
|
|
|
122
122
|
}
|
|
123
123
|
async getAncestorPaths(canonicalPath) {
|
|
124
124
|
const db = await this.ensureDb();
|
|
125
|
-
|
|
125
|
+
let rows;
|
|
126
|
+
if (isWindows()) {
|
|
127
|
+
rows = db.query("SELECT DISTINCT path FROM secrets WHERE ? = path OR ? LIKE path || '\\' || '%' OR (length(path) = 3 AND path LIKE '_:\\' AND ? LIKE path || '%')").all(canonicalPath, canonicalPath, canonicalPath);
|
|
128
|
+
} else {
|
|
129
|
+
rows = db.query("SELECT DISTINCT path FROM secrets WHERE ? = path OR ? LIKE path || '/' || '%' OR path = '/'").all(canonicalPath, canonicalPath);
|
|
130
|
+
}
|
|
126
131
|
return rows.map((row) => row.path);
|
|
127
132
|
}
|
|
128
133
|
async removeKey(canonicalPath, key) {
|
|
@@ -246,6 +251,9 @@ function escapeShellValue(value) {
|
|
|
246
251
|
function escapeDoubleQuotes(value) {
|
|
247
252
|
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
248
253
|
}
|
|
254
|
+
function escapePowerShellValue(value) {
|
|
255
|
+
return value.replace(/'/g, "''");
|
|
256
|
+
}
|
|
249
257
|
function formatShell(secrets) {
|
|
250
258
|
const lines = [];
|
|
251
259
|
const sortedKeys = Array.from(secrets.keys()).sort();
|
|
@@ -258,6 +266,42 @@ function formatShell(secrets) {
|
|
|
258
266
|
return lines.join(`
|
|
259
267
|
`);
|
|
260
268
|
}
|
|
269
|
+
function formatFish(secrets) {
|
|
270
|
+
const lines = [];
|
|
271
|
+
const sortedKeys = Array.from(secrets.keys()).sort();
|
|
272
|
+
for (const key of sortedKeys) {
|
|
273
|
+
const secret = secrets.get(key);
|
|
274
|
+
assertValidEnvKey(key);
|
|
275
|
+
const escapedValue = escapeShellValue(secret.value);
|
|
276
|
+
lines.push(`set -gx ${key} '${escapedValue}'`);
|
|
277
|
+
}
|
|
278
|
+
return lines.join(`
|
|
279
|
+
`);
|
|
280
|
+
}
|
|
281
|
+
function formatPowerShell(secrets) {
|
|
282
|
+
const lines = [];
|
|
283
|
+
const sortedKeys = Array.from(secrets.keys()).sort();
|
|
284
|
+
for (const key of sortedKeys) {
|
|
285
|
+
const secret = secrets.get(key);
|
|
286
|
+
assertValidEnvKey(key);
|
|
287
|
+
const escapedValue = escapePowerShellValue(secret.value);
|
|
288
|
+
lines.push(`$env:${key} = '${escapedValue}'`);
|
|
289
|
+
}
|
|
290
|
+
return lines.join(`
|
|
291
|
+
`);
|
|
292
|
+
}
|
|
293
|
+
function formatCmd(secrets) {
|
|
294
|
+
const lines = [];
|
|
295
|
+
const sortedKeys = Array.from(secrets.keys()).sort();
|
|
296
|
+
for (const key of sortedKeys) {
|
|
297
|
+
const secret = secrets.get(key);
|
|
298
|
+
assertValidEnvKey(key);
|
|
299
|
+
const escapedValue = secret.value.replace(/([&|<>^])/g, "^$1");
|
|
300
|
+
lines.push(`set ${key}=${escapedValue}`);
|
|
301
|
+
}
|
|
302
|
+
return lines.join(`
|
|
303
|
+
`);
|
|
304
|
+
}
|
|
261
305
|
function formatDotenv(secrets) {
|
|
262
306
|
const lines = [];
|
|
263
307
|
const sortedKeys = Array.from(secrets.keys()).sort();
|
|
@@ -295,7 +339,14 @@ function formatJson(secrets, includeSources = false) {
|
|
|
295
339
|
function format(secrets, fmt, options = {}) {
|
|
296
340
|
switch (fmt) {
|
|
297
341
|
case "shell":
|
|
342
|
+
case "bash":
|
|
298
343
|
return formatShell(secrets);
|
|
344
|
+
case "fish":
|
|
345
|
+
return formatFish(secrets);
|
|
346
|
+
case "powershell":
|
|
347
|
+
return formatPowerShell(secrets);
|
|
348
|
+
case "cmd":
|
|
349
|
+
return formatCmd(secrets);
|
|
299
350
|
case "dotenv":
|
|
300
351
|
return formatDotenv(secrets);
|
|
301
352
|
case "json":
|