credvault 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/audit.d.ts +23 -0
- package/dist/audit.js +29 -0
- package/dist/audit.js.map +1 -0
- package/dist/canary.d.ts +30 -0
- package/dist/canary.js +44 -0
- package/dist/canary.js.map +1 -0
- package/dist/chain.d.ts +26 -0
- package/dist/chain.js +117 -0
- package/dist/chain.js.map +1 -0
- package/dist/cipher.d.ts +26 -0
- package/dist/cipher.js +103 -0
- package/dist/cipher.js.map +1 -0
- package/dist/credentials.d.ts +106 -0
- package/dist/credentials.js +314 -0
- package/dist/credentials.js.map +1 -0
- package/dist/env-store.d.ts +61 -0
- package/dist/env-store.js +288 -0
- package/dist/env-store.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/passwords.d.ts +2 -0
- package/dist/passwords.js +19 -0
- package/dist/passwords.js.map +1 -0
- package/dist/secrets.d.ts +17 -0
- package/dist/secrets.js +37 -0
- package/dist/secrets.js.map +1 -0
- package/dist/tail.d.ts +4 -0
- package/dist/tail.js +56 -0
- package/dist/tail.js.map +1 -0
- package/dist/totp.d.ts +24 -0
- package/dist/totp.js +111 -0
- package/dist/totp.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What it takes to sign in to a site, by site name (`github`, or
|
|
3
|
+
* `google@ops` for a second account). Stored outside any repo or journal:
|
|
4
|
+
* a sealed 0600 JSON file on a laptop, env entries in a container. Read at
|
|
5
|
+
* the moment a login needs it, never carried on a plan or in a memo.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { homedir } from "node:os";
|
|
9
|
+
import { dirname } from "node:path";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { isSealed, plainCipher } from "./cipher.js";
|
|
12
|
+
const expandHome = (p) => (p.startsWith("~/") ? `${homedir()}${p.slice(1)}` : p);
|
|
13
|
+
export const credentialSchema = z
|
|
14
|
+
.object({
|
|
15
|
+
username: z.string().min(1),
|
|
16
|
+
/** Absent when the account has none: it signs in through a provider (`via`). */
|
|
17
|
+
password: z.string().min(1).optional(),
|
|
18
|
+
/** The password before the last rotation: tried once when the site rejects the current one. */
|
|
19
|
+
previousPassword: z.string().min(1).optional(),
|
|
20
|
+
/** Base32 TOTP seed (the site's "manual entry key", spaces and dashes allowed); never a 6-digit code. */
|
|
21
|
+
totpSecret: z
|
|
22
|
+
.string()
|
|
23
|
+
.transform((s) => s.replace(/[\s=-]/g, "").toUpperCase())
|
|
24
|
+
.pipe(z
|
|
25
|
+
.string()
|
|
26
|
+
.regex(/^[A-Z2-7]{16,}$/, "totpSecret must be the base32 seed (16+ letters/digits), not a 6-digit code"))
|
|
27
|
+
.optional(),
|
|
28
|
+
/** One-time recovery codes the site handed out; used, then dropped. */
|
|
29
|
+
recoveryCodes: z.array(z.string().min(1)).default([]),
|
|
30
|
+
/** Where the site sends email codes; defaults to `username` when that is an address. */
|
|
31
|
+
codesInbox: z.string().email().optional(),
|
|
32
|
+
/** Passkeys enrolled by us (the virtual authenticator's export); loaded into the site's browser session. */
|
|
33
|
+
passkeys: z
|
|
34
|
+
.array(z.object({
|
|
35
|
+
rpId: z.string(),
|
|
36
|
+
credentialId: z.string(),
|
|
37
|
+
privateKey: z.string(),
|
|
38
|
+
userHandle: z.string().optional(),
|
|
39
|
+
signCount: z.number(),
|
|
40
|
+
isResidentCredential: z.boolean(),
|
|
41
|
+
}))
|
|
42
|
+
.default([]),
|
|
43
|
+
/** Sign in through this identity provider's button (`google`) instead of a password; the provider's own credential does the work. */
|
|
44
|
+
via: z.string().min(1).optional(),
|
|
45
|
+
/**
|
|
46
|
+
* A tripwire, not an account: nothing legitimate ever reads it. A `get`
|
|
47
|
+
* of a canary is an alarm (see canary.ts), and its password belongs on
|
|
48
|
+
* no host.
|
|
49
|
+
*/
|
|
50
|
+
canary: z.boolean().optional(),
|
|
51
|
+
/** Where the sign-in page is, when the caller knows no login page of its own for the site. */
|
|
52
|
+
url: z.string().url().optional(),
|
|
53
|
+
/** When the account was made; a minted credential without it is a signup still owed. */
|
|
54
|
+
madeAt: z.string().datetime().optional(),
|
|
55
|
+
})
|
|
56
|
+
.refine((c) => c.password || c.via, { message: "a credential has a password or a via provider" });
|
|
57
|
+
const fileSchema = z.object({ sites: z.record(z.string(), credentialSchema) });
|
|
58
|
+
/**
|
|
59
|
+
* `{ "sites": { "<site>": Credential } }` at `path`, mode 0600, written
|
|
60
|
+
* atomically, sealed with `cipher` (a plain file written earlier is still
|
|
61
|
+
* read, and sealed on the next write).
|
|
62
|
+
*/
|
|
63
|
+
export function fileCredentials(path, cipher = plainCipher) {
|
|
64
|
+
const file = expandHome(path);
|
|
65
|
+
// Opened and parsed once per version of the file: a `list` + `get` per name is one read, and
|
|
66
|
+
// a file another process rewrote (its mtime or size moved) is read again. A stat per call.
|
|
67
|
+
let cached = null;
|
|
68
|
+
const read = () => {
|
|
69
|
+
if (!existsSync(file)) {
|
|
70
|
+
cached = null;
|
|
71
|
+
return { sites: {} };
|
|
72
|
+
}
|
|
73
|
+
const st = statSync(file);
|
|
74
|
+
const stamp = `${st.mtimeMs}:${st.size}`;
|
|
75
|
+
if (cached?.stamp === stamp)
|
|
76
|
+
return cached.data;
|
|
77
|
+
const raw = readFileSync(file, "utf8");
|
|
78
|
+
const data = fileSchema.parse(JSON.parse(isSealed(raw) ? cipher.open(raw) : raw));
|
|
79
|
+
cached = { stamp, data };
|
|
80
|
+
return data;
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
async get(site) {
|
|
84
|
+
return read().sites[site] ?? null;
|
|
85
|
+
},
|
|
86
|
+
async put(site, cred) {
|
|
87
|
+
const data = { sites: { ...read().sites, [site]: credentialSchema.parse(cred) } };
|
|
88
|
+
mkdirSync(dirname(file), { recursive: true, mode: 0o700 });
|
|
89
|
+
const tmp = `${file}.tmp`;
|
|
90
|
+
writeFileSync(tmp, cipher.seal(JSON.stringify(data, null, 2)), { mode: 0o600 });
|
|
91
|
+
renameSync(tmp, file);
|
|
92
|
+
cached = null;
|
|
93
|
+
},
|
|
94
|
+
async list() {
|
|
95
|
+
return Object.keys(read().sites);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export function memoryCredentials(init = {}) {
|
|
100
|
+
const sites = new Map(Object.entries(init).map(([k, v]) => [k, credentialSchema.parse(v)]));
|
|
101
|
+
return {
|
|
102
|
+
async get(site) {
|
|
103
|
+
return sites.get(site) ?? null;
|
|
104
|
+
},
|
|
105
|
+
async put(site, cred) {
|
|
106
|
+
sites.set(site, credentialSchema.parse(cred));
|
|
107
|
+
},
|
|
108
|
+
async list() {
|
|
109
|
+
return [...sites.keys()];
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const DEFAULT_PREFIX = "CRED_";
|
|
114
|
+
/** `CRED_<SITE>_<FIELD>`: the env name a credential field travels under. */
|
|
115
|
+
export function credentialEnvName(site, field, o = {}) {
|
|
116
|
+
return `${o.prefix ?? DEFAULT_PREFIX}${envSiteName(site)}_${field}`;
|
|
117
|
+
}
|
|
118
|
+
/** `google@ops` → `GOOGLE__OPS`, `google-admin` → `GOOGLE_ADMIN`: the account keeps its own mark so `list` can read it back. */
|
|
119
|
+
const envSiteName = (site) => site
|
|
120
|
+
.replace(/@/g, "__")
|
|
121
|
+
.replace(/[^a-zA-Z0-9_]+/g, "_")
|
|
122
|
+
.toUpperCase();
|
|
123
|
+
const USERNAME = "_USERNAME";
|
|
124
|
+
const siteFromEnvName = (s) => s.toLowerCase().replace(/__/g, "@").replace(/_/g, "-");
|
|
125
|
+
/** Fields that travel as plain strings, and the list fields that travel as JSON. */
|
|
126
|
+
const STRING_FIELDS = [
|
|
127
|
+
["USERNAME", "username"],
|
|
128
|
+
["PASSWORD", "password"],
|
|
129
|
+
["PREVIOUS_PASSWORD", "previousPassword"],
|
|
130
|
+
["TOTP_SECRET", "totpSecret"],
|
|
131
|
+
["VIA", "via"],
|
|
132
|
+
["CODES_INBOX", "codesInbox"],
|
|
133
|
+
["URL", "url"],
|
|
134
|
+
["MADE_AT", "madeAt"],
|
|
135
|
+
];
|
|
136
|
+
const JSON_FIELDS = [
|
|
137
|
+
["RECOVERY_CODES", "recoveryCodes"],
|
|
138
|
+
["PASSKEYS", "passkeys"],
|
|
139
|
+
];
|
|
140
|
+
/** Every env field a credential can use: what a push clears when the credential no longer has it. */
|
|
141
|
+
export const CREDENTIAL_ENV_FIELDS = [...STRING_FIELDS, ...JSON_FIELDS].map(([f]) => f);
|
|
142
|
+
/**
|
|
143
|
+
* A credential as env entries, every field of it: the strings as they are,
|
|
144
|
+
* recovery codes and passkeys as JSON. Empty fields are left out. A
|
|
145
|
+
* canary's entries are never asked for (see `pushCredentials`).
|
|
146
|
+
*/
|
|
147
|
+
export function credentialEnv(site, cred, o = {}) {
|
|
148
|
+
const fields = [
|
|
149
|
+
...STRING_FIELDS.map(([f, k]) => [f, cred[k]]),
|
|
150
|
+
...JSON_FIELDS.map(([f, k]) => [
|
|
151
|
+
f,
|
|
152
|
+
cred[k].length ? JSON.stringify(cred[k]) : undefined,
|
|
153
|
+
]),
|
|
154
|
+
];
|
|
155
|
+
return fields
|
|
156
|
+
.filter((f) => Boolean(f[1]))
|
|
157
|
+
.map(([field, value]) => ({ name: credentialEnvName(site, field, o), value }));
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* `CRED_<SITE>_<FIELD>`: the container form, where a Secret becomes env,
|
|
161
|
+
* and the shape a pull reads back. Read-only.
|
|
162
|
+
*/
|
|
163
|
+
export function envCredentials(env = process.env, o = {}) {
|
|
164
|
+
const prefix = o.prefix ?? DEFAULT_PREFIX;
|
|
165
|
+
const key = (site, field) => credentialEnvName(site, field, o);
|
|
166
|
+
return {
|
|
167
|
+
async get(site) {
|
|
168
|
+
const username = env[key(site, "USERNAME")];
|
|
169
|
+
if (!username || !(env[key(site, "PASSWORD")] || env[key(site, "VIA")]))
|
|
170
|
+
return null;
|
|
171
|
+
const out = {};
|
|
172
|
+
for (const [f, k] of STRING_FIELDS) {
|
|
173
|
+
const v = env[key(site, f)];
|
|
174
|
+
if (v)
|
|
175
|
+
out[k] = v;
|
|
176
|
+
}
|
|
177
|
+
for (const [f, k] of JSON_FIELDS) {
|
|
178
|
+
const v = env[key(site, f)];
|
|
179
|
+
if (!v)
|
|
180
|
+
continue;
|
|
181
|
+
try {
|
|
182
|
+
out[k] = JSON.parse(v);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
throw new Error(`credentials for ${site}: ${key(site, f)} is not JSON`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return credentialSchema.parse(out);
|
|
189
|
+
},
|
|
190
|
+
async put(site) {
|
|
191
|
+
throw new Error(`credentials for ${site}: env store is read-only; set ${key(site, "*")}`);
|
|
192
|
+
},
|
|
193
|
+
async list() {
|
|
194
|
+
return Object.keys(env)
|
|
195
|
+
.map((k) => k.startsWith(prefix) && k.endsWith(USERNAME)
|
|
196
|
+
? k.slice(prefix.length, -USERNAME.length)
|
|
197
|
+
: undefined)
|
|
198
|
+
.filter((s) => Boolean(s))
|
|
199
|
+
.map(siteFromEnvName);
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* This machine's credentials into the env store, every site or the named
|
|
205
|
+
* ones, every field (passkeys and recovery codes as JSON). Canaries never
|
|
206
|
+
* travel: a tripwire belongs to one machine. Answers what was pushed, never
|
|
207
|
+
* a value.
|
|
208
|
+
*/
|
|
209
|
+
export async function pushCredentials(local, store, sites, o = {}) {
|
|
210
|
+
const chosen = sites?.length ? sites : await local.list();
|
|
211
|
+
const out = [];
|
|
212
|
+
const there = store.list && store.remove ? new Set((await store.list()).map((e) => e.name)) : null;
|
|
213
|
+
for (const site of chosen) {
|
|
214
|
+
const cred = await local.get(site);
|
|
215
|
+
if (!cred)
|
|
216
|
+
throw new Error(`no credential stored here for ${site}`);
|
|
217
|
+
if (cred.canary)
|
|
218
|
+
continue;
|
|
219
|
+
const entries = credentialEnv(site, cred, o);
|
|
220
|
+
for (const e of entries)
|
|
221
|
+
await store.put(e.name, e.value);
|
|
222
|
+
if (there && store.remove) {
|
|
223
|
+
const kept = new Set(entries.map((e) => e.name));
|
|
224
|
+
for (const f of CREDENTIAL_ENV_FIELDS) {
|
|
225
|
+
const name = credentialEnvName(site, f, o);
|
|
226
|
+
if (there.has(name) && !kept.has(name))
|
|
227
|
+
await store.remove(name);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
out.push({ site, names: entries.map((e) => e.name) });
|
|
231
|
+
}
|
|
232
|
+
return out;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* The env store's credentials into this machine's file, the other way: a
|
|
236
|
+
* new laptop, or a box's file for a passkey site. A site already here is
|
|
237
|
+
* kept unless `overwrite`, and even then passkeys here are never dropped:
|
|
238
|
+
* the shared ones join them. Answers what was written and what was kept.
|
|
239
|
+
*/
|
|
240
|
+
export async function pullCredentials(store, local, sites, o = {}) {
|
|
241
|
+
const env = Object.fromEntries((await store.all()).map((e) => [e.name, e.value]));
|
|
242
|
+
const remote = envCredentials(env, o);
|
|
243
|
+
const chosen = sites?.length ? sites : await remote.list();
|
|
244
|
+
const written = [];
|
|
245
|
+
const kept = [];
|
|
246
|
+
for (const site of chosen) {
|
|
247
|
+
const cred = await remote.get(site);
|
|
248
|
+
if (!cred)
|
|
249
|
+
throw new Error(`no credential in the shared store for ${site}: push it first`);
|
|
250
|
+
const here = await local.get(site);
|
|
251
|
+
if (here && !o.overwrite) {
|
|
252
|
+
kept.push(site);
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const shared = new Set(cred.passkeys.map((p) => p.credentialId));
|
|
256
|
+
await local.put(site, {
|
|
257
|
+
...cred,
|
|
258
|
+
// A store pushed before codes travelled has none: the ones here stay.
|
|
259
|
+
recoveryCodes: cred.recoveryCodes.length ? cred.recoveryCodes : (here?.recoveryCodes ?? []),
|
|
260
|
+
passkeys: [
|
|
261
|
+
...cred.passkeys,
|
|
262
|
+
...(here?.passkeys ?? []).filter((p) => !shared.has(p.credentialId)),
|
|
263
|
+
],
|
|
264
|
+
});
|
|
265
|
+
written.push(site);
|
|
266
|
+
}
|
|
267
|
+
return { written, kept };
|
|
268
|
+
}
|
|
269
|
+
/** First store that has the site wins; writes go to `write`, which defaults to the last store. */
|
|
270
|
+
export function layeredCredentials(stores, write = stores.at(-1)) {
|
|
271
|
+
const first = write;
|
|
272
|
+
if (!first)
|
|
273
|
+
throw new Error("layeredCredentials needs at least one store");
|
|
274
|
+
return {
|
|
275
|
+
async get(site) {
|
|
276
|
+
for (const s of stores) {
|
|
277
|
+
const c = await s.get(site);
|
|
278
|
+
if (c)
|
|
279
|
+
return c;
|
|
280
|
+
}
|
|
281
|
+
return null;
|
|
282
|
+
},
|
|
283
|
+
put: (site, cred) => first.put(site, cred),
|
|
284
|
+
async list() {
|
|
285
|
+
const all = await Promise.all(stores.map((s) => s.list()));
|
|
286
|
+
return [...new Set(all.flat())];
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* `local`, with every write copied to the shared env store: the file on this
|
|
292
|
+
* machine becomes a cache, and a lost machine loses nothing. The local write
|
|
293
|
+
* lands first; a failed copy goes to `onMirrorError` (default: throw), and
|
|
294
|
+
* `pushCredentials` for that site repairs it. Canaries stay local.
|
|
295
|
+
*/
|
|
296
|
+
export function mirroredCredentials(local, store, o = {}) {
|
|
297
|
+
const naming = o.prefix ? { prefix: o.prefix } : {};
|
|
298
|
+
return {
|
|
299
|
+
get: (site) => local.get(site),
|
|
300
|
+
list: () => local.list(),
|
|
301
|
+
async put(site, cred) {
|
|
302
|
+
await local.put(site, cred);
|
|
303
|
+
try {
|
|
304
|
+
await pushCredentials(local, store, [site], naming);
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
if (!o.onMirrorError)
|
|
308
|
+
throw err;
|
|
309
|
+
o.onMirrorError(site, err);
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one place a secret lives across machines: SSM Parameter Store, one
|
|
3
|
+
* SecureString per name under the app's path (`/myapp/config/NAME`). KMS
|
|
4
|
+
* at rest, IAM at the door, every read in CloudTrail. Values never enter
|
|
5
|
+
* argv, logs or errors.
|
|
6
|
+
*/
|
|
7
|
+
import { type SSMClient } from "@aws-sdk/client-ssm";
|
|
8
|
+
export declare const ENV_KEY: RegExp;
|
|
9
|
+
export interface EnvEntry {
|
|
10
|
+
name: string;
|
|
11
|
+
value: string;
|
|
12
|
+
}
|
|
13
|
+
/** What the store knows about an entry besides its value. */
|
|
14
|
+
export interface EnvListing {
|
|
15
|
+
name: string;
|
|
16
|
+
/** When the value last changed. */
|
|
17
|
+
updatedAt: string | null;
|
|
18
|
+
/** When the value stops working (a token's expiry), if whoever stored it knew. */
|
|
19
|
+
expiresAt: string | null;
|
|
20
|
+
}
|
|
21
|
+
export interface PutOptions {
|
|
22
|
+
/** ISO time the value stops working; absent = it does not, or nobody knows. */
|
|
23
|
+
expiresAt?: string | undefined;
|
|
24
|
+
}
|
|
25
|
+
export interface EnvStore {
|
|
26
|
+
/** Names, change and expiry times; never values. */
|
|
27
|
+
list(): Promise<EnvListing[]>;
|
|
28
|
+
get(name: string): Promise<string | null>;
|
|
29
|
+
/** Every entry, decrypted: what a pull or a deploy reads. */
|
|
30
|
+
all(): Promise<EnvEntry[]>;
|
|
31
|
+
put(name: string, value: string, o?: PutOptions): Promise<void>;
|
|
32
|
+
remove(name: string): Promise<boolean>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Entries that stop working within `withinMs` of `now` (already expired
|
|
36
|
+
* included), soonest first: what a watcher re-mints.
|
|
37
|
+
*/
|
|
38
|
+
export declare function expiring(entries: readonly EnvListing[], withinMs: number, now?: number): EnvListing[];
|
|
39
|
+
/** SSM under `prefix`: `/prefix/NAME`. The client comes in so tests pass a fake. */
|
|
40
|
+
export declare function ssmEnvStore(ssm: SSMClient, prefix: string): EnvStore;
|
|
41
|
+
export declare function memoryEnvStore(initial?: Record<string, string>): EnvStore & {
|
|
42
|
+
values: Record<string, string>;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* A local `.env` as a store: 0600, one line per name, other lines untouched.
|
|
46
|
+
* Expiry is a comment directly above the line, so a person reading the file
|
|
47
|
+
* sees it too. A put also sets `env[name]`, so this process sees the value.
|
|
48
|
+
*/
|
|
49
|
+
export declare function envFileStore(path: string, env?: NodeJS.ProcessEnv): EnvStore;
|
|
50
|
+
/**
|
|
51
|
+
* `KEY=VALUE` lines → entries. Comments, blanks and quotes as a shell would
|
|
52
|
+
* read them; a value naming a readable file whose content is JSON (a
|
|
53
|
+
* service account) is inlined so the store holds the secret, not a path.
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseDotenv(text: string, readFile?: (path: string) => string | null): EnvEntry[];
|
|
56
|
+
/** Entries → `KEY=VALUE` lines. A multi-line value cannot live in one line: `files` takes it and the line names the path. */
|
|
57
|
+
export declare function toDotenv(entries: EnvEntry[], files?: (name: string, value: string) => string): string;
|
|
58
|
+
/** Entries → `export KEY='…'` lines for `eval "$(…)"`; single quotes are the one thing escaped. */
|
|
59
|
+
export declare function toExports(entries: EnvEntry[]): string;
|
|
60
|
+
/** Upsert `entries` into an env file's text; other lines untouched. */
|
|
61
|
+
export declare function upsertDotenv(text: string, entries: EnvEntry[]): string;
|