@clicadigital/vault-sdk 0.1.0 → 0.4.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/README.md +126 -152
- package/dist/cjs/cli.js +72 -0
- package/dist/cjs/cli.js.map +1 -0
- package/dist/cjs/client.js +75 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/dotenv.js +24 -0
- package/dist/cjs/dotenv.js.map +1 -0
- package/dist/cjs/index.js +40 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/types.js +3 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cli.js +30 -75
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +5 -11
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +41 -27
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +5 -46
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -87
- package/dist/index.js.map +1 -1
- package/package.json +44 -43
- package/src/cli.ts +78 -132
- package/src/client.ts +85 -74
- package/src/dotenv.ts +22 -22
- package/src/index.ts +47 -167
- package/src/types.ts +14 -14
package/src/cli.ts
CHANGED
|
@@ -1,132 +1,78 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (typeof flags.url === "string") process.env.VAULT_URL = flags.url;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const project = str(flags, "project", process.env.VAULT_PROJECT);
|
|
81
|
-
const env = str(flags, "env", process.env.VAULT_ENV);
|
|
82
|
-
const url = typeof flags.url === "string" ? flags.url : undefined;
|
|
83
|
-
const client = url
|
|
84
|
-
? createClientFromEnv({ ...process.env, VAULT_URL: url })
|
|
85
|
-
: undefined;
|
|
86
|
-
|
|
87
|
-
if (cmd === "create") {
|
|
88
|
-
const vars = parseVarList(flags);
|
|
89
|
-
const result = await createEnv({ project, env, url, vars, client });
|
|
90
|
-
console.log(JSON.stringify({ project, env, ...result }, null, 2));
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (cmd === "ensure") {
|
|
95
|
-
const result = await ensureEnvironment({ project, env, client });
|
|
96
|
-
console.log(
|
|
97
|
-
JSON.stringify(
|
|
98
|
-
{
|
|
99
|
-
project,
|
|
100
|
-
env,
|
|
101
|
-
projectId: result.projectId,
|
|
102
|
-
environmentId: result.environmentId,
|
|
103
|
-
createdProject: result.createdProject,
|
|
104
|
-
createdEnvironment: result.createdEnvironment,
|
|
105
|
-
},
|
|
106
|
-
null,
|
|
107
|
-
2,
|
|
108
|
-
),
|
|
109
|
-
);
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (cmd === "pull") {
|
|
114
|
-
const out = typeof flags.out === "string" ? flags.out : undefined;
|
|
115
|
-
const inject = flags["no-inject"] !== true;
|
|
116
|
-
const result = await pullVault({ project, env, out, inject, client });
|
|
117
|
-
console.log(
|
|
118
|
-
`pulled ${Object.keys(result.vars).length} vars for ${project}/${env}` +
|
|
119
|
-
(result.out ? ` → ${result.out}` : "") +
|
|
120
|
-
(inject ? " (injected into process.env)" : ""),
|
|
121
|
-
);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
printHelp();
|
|
126
|
-
process.exit(1);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
main().catch((err) => {
|
|
130
|
-
console.error(err instanceof Error ? err.message : err);
|
|
131
|
-
process.exit(1);
|
|
132
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { pullVault } from "./index.js";
|
|
3
|
+
|
|
4
|
+
type Flags = Record<string, string | boolean>;
|
|
5
|
+
|
|
6
|
+
function parseArgs(argv: string[]): { cmd: string; flags: Flags } {
|
|
7
|
+
const [cmd = "help", ...rest] = argv;
|
|
8
|
+
const flags: Flags = {};
|
|
9
|
+
for (let i = 0; i < rest.length; i++) {
|
|
10
|
+
const token = rest[i];
|
|
11
|
+
if (!token?.startsWith("--")) continue;
|
|
12
|
+
const key = token.slice(2);
|
|
13
|
+
const next = rest[i + 1];
|
|
14
|
+
if (!next || next.startsWith("--")) {
|
|
15
|
+
flags[key] = true;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
flags[key] = next;
|
|
19
|
+
i++;
|
|
20
|
+
}
|
|
21
|
+
return { cmd, flags };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function str(flags: Flags, key: string, fallback?: string): string {
|
|
25
|
+
const value = flags[key];
|
|
26
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
27
|
+
if (fallback !== undefined) return fallback;
|
|
28
|
+
throw new Error(`Missing --${key}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function printHelp(): void {
|
|
32
|
+
console.log(`@clicadigital/vault-sdk — carrega envs do vault
|
|
33
|
+
|
|
34
|
+
Usage:
|
|
35
|
+
vault-sdk pull --project <name> --env <name> [--out .env] [--no-inject] [--url <vpn-url>]
|
|
36
|
+
|
|
37
|
+
Env:
|
|
38
|
+
VAULT_URL opcional; default k8s: http://vault-api-service.vault.svc.cluster.local:3001
|
|
39
|
+
VAULT_PROJECT default --project
|
|
40
|
+
VAULT_ENV default --env
|
|
41
|
+
VAULT_SA_TOKEN_PATH path do token SA (default: /var/run/secrets/tokens/vault/token)
|
|
42
|
+
|
|
43
|
+
No código: loadVault({ project, env }) injeta em process.env.
|
|
44
|
+
Criar projeto, environment e allow é pela UI do vault.
|
|
45
|
+
`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function main(): Promise<void> {
|
|
49
|
+
const { cmd, flags } = parseArgs(process.argv.slice(2));
|
|
50
|
+
|
|
51
|
+
if (cmd === "help" || flags.help === true) {
|
|
52
|
+
printHelp();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (typeof flags.url === "string") process.env.VAULT_URL = flags.url;
|
|
57
|
+
|
|
58
|
+
if (cmd !== "pull") {
|
|
59
|
+
printHelp();
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const project = str(flags, "project", process.env.VAULT_PROJECT);
|
|
64
|
+
const env = str(flags, "env", process.env.VAULT_ENV);
|
|
65
|
+
const out = typeof flags.out === "string" ? flags.out : undefined;
|
|
66
|
+
const inject = flags["no-inject"] !== true;
|
|
67
|
+
const result = await pullVault({ project, env, out, inject });
|
|
68
|
+
console.log(
|
|
69
|
+
`pulled ${Object.keys(result.vars).length} vars for ${project}/${env}` +
|
|
70
|
+
(result.out ? ` → ${result.out}` : "") +
|
|
71
|
+
(inject ? " (injected into process.env)" : ""),
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
main().catch((err) => {
|
|
76
|
+
console.error(err instanceof Error ? err.message : err);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
});
|
package/src/client.ts
CHANGED
|
@@ -1,74 +1,85 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
1
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import type { EnvVar, ProjectTree } from "./types.js";
|
|
3
|
+
|
|
4
|
+
const DEFAULT_TOKEN_PATHS = [
|
|
5
|
+
"/var/run/secrets/tokens/vault/token",
|
|
6
|
+
"/var/run/secrets/kubernetes.io/serviceaccount/token",
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
/** DNS interno do Service no k3s (namespace `vault`). Override com VAULT_URL. */
|
|
10
|
+
export const DEFAULT_VAULT_URL =
|
|
11
|
+
"http://vault-api-service.vault.svc.cluster.local:3001";
|
|
12
|
+
|
|
13
|
+
export type VaultClientOptions = {
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
token?: string;
|
|
16
|
+
tokenPaths?: string[];
|
|
17
|
+
fetch?: typeof globalThis.fetch;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function resolveToken(opts: VaultClientOptions): string | undefined {
|
|
21
|
+
if (opts.token) return opts.token;
|
|
22
|
+
const paths = opts.tokenPaths ?? DEFAULT_TOKEN_PATHS;
|
|
23
|
+
for (const path of paths) {
|
|
24
|
+
if (!existsSync(path)) continue;
|
|
25
|
+
try {
|
|
26
|
+
const token = readFileSync(path, "utf8").trim();
|
|
27
|
+
if (token) return token;
|
|
28
|
+
} catch {
|
|
29
|
+
// ignore unreadable path
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class VaultClient {
|
|
36
|
+
readonly baseUrl: string;
|
|
37
|
+
private readonly token: string | undefined;
|
|
38
|
+
private readonly fetchFn: typeof globalThis.fetch;
|
|
39
|
+
|
|
40
|
+
constructor(opts: VaultClientOptions) {
|
|
41
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
42
|
+
this.token = resolveToken(opts);
|
|
43
|
+
this.fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private async request<T>(path: string, init?: RequestInit): Promise<T> {
|
|
47
|
+
const headers: Record<string, string> = {
|
|
48
|
+
"content-type": "application/json",
|
|
49
|
+
...(init?.headers as Record<string, string> | undefined),
|
|
50
|
+
};
|
|
51
|
+
if (this.token) headers.authorization = `Bearer ${this.token}`;
|
|
52
|
+
|
|
53
|
+
const res = await this.fetchFn(`${this.baseUrl}${path}`, {
|
|
54
|
+
...init,
|
|
55
|
+
headers,
|
|
56
|
+
});
|
|
57
|
+
if (!res.ok) {
|
|
58
|
+
const body = (await res.json().catch(() => null)) as { error?: string } | null;
|
|
59
|
+
throw new Error(body?.error ?? `Vault API ${res.status} ${path}`);
|
|
60
|
+
}
|
|
61
|
+
if (res.status === 204) return undefined as T;
|
|
62
|
+
return (await res.json()) as T;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
listProjects(): Promise<ProjectTree[]> {
|
|
66
|
+
return this.request("/v1/projects");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
listVars(environmentId: string): Promise<EnvVar[]> {
|
|
70
|
+
return this.request(`/v1/environments/${environmentId}/vars`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function createClientFromEnv(
|
|
75
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
76
|
+
): VaultClient {
|
|
77
|
+
const baseUrl =
|
|
78
|
+
env.VAULT_URL ?? env.VAULT_API_URL ?? env.API_URL ?? DEFAULT_VAULT_URL;
|
|
79
|
+
const tokenPath = env.VAULT_SA_TOKEN_PATH;
|
|
80
|
+
return new VaultClient({
|
|
81
|
+
baseUrl,
|
|
82
|
+
token: env.VAULT_SA_TOKEN,
|
|
83
|
+
tokenPaths: tokenPath ? [tokenPath, ...DEFAULT_TOKEN_PATHS] : undefined,
|
|
84
|
+
});
|
|
85
|
+
}
|
package/src/dotenv.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
export function toDotEnv(vars: Record<string, string>): string {
|
|
2
|
-
return (
|
|
3
|
-
Object.entries(vars)
|
|
4
|
-
.sort(([a], [b]) => a.localeCompare(b))
|
|
5
|
-
.map(([key, value]) => `${key}=${escapeEnvValue(value)}`)
|
|
6
|
-
.join("\n") + "\n"
|
|
7
|
-
);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function escapeEnvValue(value: string): string {
|
|
11
|
-
if (value === "") return '""';
|
|
12
|
-
if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value)) return value;
|
|
13
|
-
return JSON.stringify(value);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function varsToRecord(
|
|
17
|
-
rows: { key: string; value: string }[],
|
|
18
|
-
): Record<string, string> {
|
|
19
|
-
const out: Record<string, string> = {};
|
|
20
|
-
for (const row of rows) out[row.key] = row.value;
|
|
21
|
-
return out;
|
|
22
|
-
}
|
|
1
|
+
export function toDotEnv(vars: Record<string, string>): string {
|
|
2
|
+
return (
|
|
3
|
+
Object.entries(vars)
|
|
4
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
5
|
+
.map(([key, value]) => `${key}=${escapeEnvValue(value)}`)
|
|
6
|
+
.join("\n") + "\n"
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function escapeEnvValue(value: string): string {
|
|
11
|
+
if (value === "") return '""';
|
|
12
|
+
if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value)) return value;
|
|
13
|
+
return JSON.stringify(value);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function varsToRecord(
|
|
17
|
+
rows: { key: string; value: string }[],
|
|
18
|
+
): Record<string, string> {
|
|
19
|
+
const out: Record<string, string> = {};
|
|
20
|
+
for (const row of rows) out[row.key] = row.value;
|
|
21
|
+
return out;
|
|
22
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,167 +1,47 @@
|
|
|
1
|
-
import { writeFile } from "node:fs/promises";
|
|
2
|
-
import { createClientFromEnv
|
|
3
|
-
import { toDotEnv, varsToRecord } from "./dotenv.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export async function resolveEnvironment(
|
|
49
|
-
opts: ResolveOptions,
|
|
50
|
-
): Promise<{ projectId: string; environmentId: string }> {
|
|
51
|
-
const client = opts.client ?? createClientFromEnv();
|
|
52
|
-
const project = await findProject(client, opts.project);
|
|
53
|
-
if (!project) throw new Error(`Project not found: ${opts.project}`);
|
|
54
|
-
const environment = project.environments.find((e) => e.name === opts.env);
|
|
55
|
-
if (!environment) {
|
|
56
|
-
throw new Error(`Environment "${opts.env}" not found in project "${opts.project}"`);
|
|
57
|
-
}
|
|
58
|
-
return { projectId: project.id, environmentId: environment.id };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** Garante projeto + environment na VPN (cria se não existir). */
|
|
62
|
-
export async function ensureEnvironment(opts: EnsureOptions): Promise<{
|
|
63
|
-
projectId: string;
|
|
64
|
-
environmentId: string;
|
|
65
|
-
createdProject: boolean;
|
|
66
|
-
createdEnvironment: boolean;
|
|
67
|
-
}> {
|
|
68
|
-
const client = opts.client ?? createClientFromEnv();
|
|
69
|
-
let createdProject = false;
|
|
70
|
-
let createdEnvironment = false;
|
|
71
|
-
|
|
72
|
-
let project = await findProject(client, opts.project);
|
|
73
|
-
if (!project) {
|
|
74
|
-
if (opts.createProject === false) {
|
|
75
|
-
throw new Error(`Project not found: ${opts.project}`);
|
|
76
|
-
}
|
|
77
|
-
await client.createProject(opts.project);
|
|
78
|
-
createdProject = true;
|
|
79
|
-
project = await findProject(client, opts.project);
|
|
80
|
-
if (!project) throw new Error(`Failed to create project: ${opts.project}`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
let environment = project.environments.find((e) => e.name === opts.env);
|
|
84
|
-
if (!environment) {
|
|
85
|
-
await client.createEnvironment(project.id, opts.env);
|
|
86
|
-
createdEnvironment = true;
|
|
87
|
-
const refreshed = await findProject(client, opts.project);
|
|
88
|
-
if (!refreshed) throw new Error(`Failed to reload project: ${opts.project}`);
|
|
89
|
-
project = refreshed;
|
|
90
|
-
environment = project.environments.find((e) => e.name === opts.env);
|
|
91
|
-
if (!environment) throw new Error(`Failed to create environment: ${opts.env}`);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
projectId: project.id,
|
|
96
|
-
environmentId: environment.id,
|
|
97
|
-
createdProject,
|
|
98
|
-
createdEnvironment,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Cria (ou garante) o environment no vault via URL da VPN
|
|
104
|
-
* e opcionalmente faz upsert das variáveis.
|
|
105
|
-
*/
|
|
106
|
-
export async function createEnv(opts: CreateEnvOptions): Promise<{
|
|
107
|
-
projectId: string;
|
|
108
|
-
environmentId: string;
|
|
109
|
-
createdProject: boolean;
|
|
110
|
-
createdEnvironment: boolean;
|
|
111
|
-
upserted: string[];
|
|
112
|
-
}> {
|
|
113
|
-
const client = resolveClient(opts);
|
|
114
|
-
const ensured = await ensureEnvironment({
|
|
115
|
-
project: opts.project,
|
|
116
|
-
env: opts.env,
|
|
117
|
-
client,
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
const upserted: string[] = [];
|
|
121
|
-
if (opts.vars) {
|
|
122
|
-
for (const [key, value] of Object.entries(opts.vars)) {
|
|
123
|
-
await client.upsertVar(ensured.environmentId, key, value);
|
|
124
|
-
upserted.push(key);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return { ...ensured, upserted };
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export async function fetchVars(opts: ResolveOptions): Promise<EnvVar[]> {
|
|
132
|
-
const client = opts.client ?? createClientFromEnv();
|
|
133
|
-
const { environmentId } = await resolveEnvironment({ ...opts, client });
|
|
134
|
-
return client.listVars(environmentId);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export async function loadVault(
|
|
138
|
-
opts: ResolveOptions,
|
|
139
|
-
): Promise<Record<string, string>> {
|
|
140
|
-
const rows = await fetchVars(opts);
|
|
141
|
-
const record = varsToRecord(rows);
|
|
142
|
-
for (const [key, value] of Object.entries(record)) {
|
|
143
|
-
process.env[key] = value;
|
|
144
|
-
}
|
|
145
|
-
return record;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export async function pullVault(opts: PullOptions): Promise<{
|
|
149
|
-
vars: Record<string, string>;
|
|
150
|
-
out?: string;
|
|
151
|
-
}> {
|
|
152
|
-
const rows = await fetchVars(opts);
|
|
153
|
-
const vars = varsToRecord(rows);
|
|
154
|
-
|
|
155
|
-
if (opts.inject !== false) {
|
|
156
|
-
for (const [key, value] of Object.entries(vars)) {
|
|
157
|
-
process.env[key] = value;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const out = opts.out;
|
|
162
|
-
if (out) {
|
|
163
|
-
await writeFile(out, toDotEnv(vars), "utf8");
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return out ? { vars, out } : { vars };
|
|
167
|
-
}
|
|
1
|
+
import { writeFile } from "node:fs/promises";
|
|
2
|
+
import { createClientFromEnv } from "./client.js";
|
|
3
|
+
import { toDotEnv, varsToRecord } from "./dotenv.js";
|
|
4
|
+
|
|
5
|
+
export type LoadVaultOptions = {
|
|
6
|
+
project: string;
|
|
7
|
+
env: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
async function readVars(opts: LoadVaultOptions): Promise<Record<string, string>> {
|
|
11
|
+
const client = createClientFromEnv();
|
|
12
|
+
const projects = await client.listProjects();
|
|
13
|
+
const project = projects.find((item) => item.name === opts.project);
|
|
14
|
+
if (!project) throw new Error(`Project not found: ${opts.project}`);
|
|
15
|
+
|
|
16
|
+
const environment = project.environments.find((item) => item.name === opts.env);
|
|
17
|
+
if (!environment) {
|
|
18
|
+
throw new Error(`Environment "${opts.env}" not found in project "${opts.project}"`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const rows = await client.listVars(environment.id);
|
|
22
|
+
return varsToRecord(rows);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Lê o environment e injeta as variáveis em `process.env`. */
|
|
26
|
+
export async function loadVault(opts: LoadVaultOptions): Promise<void> {
|
|
27
|
+
const vars = await readVars(opts);
|
|
28
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
29
|
+
process.env[key] = value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function pullVault(
|
|
34
|
+
opts: LoadVaultOptions & { out?: string; inject?: boolean },
|
|
35
|
+
): Promise<{ vars: Record<string, string>; out?: string }> {
|
|
36
|
+
const vars = await readVars(opts);
|
|
37
|
+
|
|
38
|
+
if (opts.inject !== false) {
|
|
39
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
40
|
+
process.env[key] = value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const out = opts.out;
|
|
45
|
+
if (out) await writeFile(out, toDotEnv(vars), "utf8");
|
|
46
|
+
return out ? { vars, out } : { vars };
|
|
47
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
export type ProjectTreeEnv = { id: string; name: string };
|
|
2
|
-
|
|
3
|
-
export type ProjectTree = {
|
|
4
|
-
id: string;
|
|
5
|
-
name: string;
|
|
6
|
-
environments: ProjectTreeEnv[];
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export type EnvVar = {
|
|
10
|
-
id: string;
|
|
11
|
-
key: string;
|
|
12
|
-
value: string;
|
|
13
|
-
updated_at: string;
|
|
14
|
-
};
|
|
1
|
+
export type ProjectTreeEnv = { id: string; name: string };
|
|
2
|
+
|
|
3
|
+
export type ProjectTree = {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
environments: ProjectTreeEnv[];
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type EnvVar = {
|
|
10
|
+
id: string;
|
|
11
|
+
key: string;
|
|
12
|
+
value: string;
|
|
13
|
+
updated_at: string;
|
|
14
|
+
};
|