@clicadigital/vault-sdk 0.0.0-stage → 0.1.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 CHANGED
@@ -1,3 +1,152 @@
1
- # Temporary Holding Version
1
+ # @clicadigital/vault-sdk
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ SDK e CLI para criar e carregar variáveis de ambiente a partir do **Clica VPN Vault**.
4
+
5
+ Pensado para uso **entre pods no mesmo cluster / VPN**. Não há API key: a segurança é a rede interna (NetworkPolicy / VPN). Devs usam a UI do vault; apps usam este SDK no build ou no boot.
6
+
7
+ ## Instalação
8
+
9
+ ```bash
10
+ npm install @clicadigital/vault-sdk
11
+ # ou
12
+ bun add @clicadigital/vault-sdk
13
+ ```
14
+
15
+ ## Configuração
16
+
17
+ | Variável | Obrigatória | Descrição |
18
+ |-----------------|-------------|--------------------------------------------------------|
19
+ | `VAULT_URL` | sim* | URL interna do vault, ex: `http://vault-api:3001` |
20
+ | `VAULT_PROJECT` | não | Default de `--project` na CLI |
21
+ | `VAULT_ENV` | não | Default de `--env` na CLI |
22
+
23
+ \* Também aceita `VAULT_API_URL` ou `API_URL`. Pode passar `--url` / `url` no código.
24
+
25
+ ## CLI
26
+
27
+ ### Garantir projeto + environment
28
+
29
+ Cria o projeto (se não existir) e o environment (se não existir). Projetos novos já nascem com `production` e `staging` no vault; outros nomes são criados sob demanda.
30
+
31
+ ```bash
32
+ export VAULT_URL=http://vault-api:3001
33
+
34
+ npx vault-sdk ensure --project meu-app --env production
35
+ ```
36
+
37
+ ### Criar environment e gravar variáveis
38
+
39
+ ```bash
40
+ npx vault-sdk create \
41
+ --project meu-app \
42
+ --env production \
43
+ --var DATABASE_URL=postgres://... \
44
+ --var API_TOKEN=secret
45
+ ```
46
+
47
+ ### Puxar variáveis no build (gera `.env`)
48
+
49
+ ```bash
50
+ # Dockerfile / CI / init container
51
+ npx vault-sdk pull \
52
+ --project meu-app \
53
+ --env production \
54
+ --out .env \
55
+ --no-inject
56
+ ```
57
+
58
+ Sem `--no-inject`, as vars também vão para `process.env` do processo da CLI.
59
+
60
+ ### URL explícita
61
+
62
+ ```bash
63
+ npx vault-sdk pull --url http://vault-api.vpn.svc.cluster.local:3001 \
64
+ --project meu-app --env staging --out .env
65
+ ```
66
+
67
+ ## Uso em código (Node / Bun)
68
+
69
+ ### Carregar no boot / build script
70
+
71
+ ```ts
72
+ import { loadVault, pullVault, createEnv, ensureEnvironment } from "@clicadigital/vault-sdk";
73
+
74
+ // injeta em process.env
75
+ await loadVault({ project: "meu-app", env: "production" });
76
+
77
+ // ou grava arquivo
78
+ await pullVault({
79
+ project: "meu-app",
80
+ env: "production",
81
+ out: ".env",
82
+ inject: false,
83
+ });
84
+ ```
85
+
86
+ ### Criar environment + vars pela URL da VPN
87
+
88
+ ```ts
89
+ await createEnv({
90
+ url: "http://vault-api:3001",
91
+ project: "meu-app",
92
+ env: "production",
93
+ vars: {
94
+ DATABASE_URL: "postgres://...",
95
+ REDIS_URL: "redis://...",
96
+ },
97
+ });
98
+ ```
99
+
100
+ ### Só garantir que o environment existe
101
+
102
+ ```ts
103
+ await ensureEnvironment({ project: "meu-app", env: "qa" });
104
+ ```
105
+
106
+ ## Exemplo Kubernetes (build)
107
+
108
+ ```dockerfile
109
+ # build stage (mesmo cluster / network policy liberando vault-api)
110
+ ENV VAULT_URL=http://vault-api:3001
111
+ RUN npx vault-sdk pull --project meu-app --env production --out .env --no-inject
112
+ ```
113
+
114
+ Ou no `package.json` do app:
115
+
116
+ ```json
117
+ {
118
+ "scripts": {
119
+ "prebuild": "vault-sdk pull --project meu-app --env production --out .env --no-inject",
120
+ "build": "…"
121
+ }
122
+ }
123
+ ```
124
+
125
+ ## API do vault usada pelo SDK
126
+
127
+ | Método | Path | Uso |
128
+ |--------|------|-----|
129
+ | `GET` | `/v1/projects` | Árvore projetos + environments |
130
+ | `POST` | `/v1/projects` | Criar projeto |
131
+ | `POST` | `/v1/projects/:id/environments` | Criar environment |
132
+ | `GET` | `/v1/environments/:id/vars` | Listar vars (já descriptografadas) |
133
+ | `PUT` | `/v1/environments/:id/vars` | Upsert var |
134
+
135
+ ## Desenvolvimento local (neste monorepo)
136
+
137
+ ```bash
138
+ cd sdk
139
+ bun install
140
+ bun run build
141
+
142
+ # vault API em localhost:3001
143
+ VAULT_URL=http://localhost:3001 bun run src/cli.ts pull --project demo --env production --out .env
144
+ ```
145
+
146
+ Publicar:
147
+
148
+ ```bash
149
+ cd sdk
150
+ bun run build
151
+ bun publish --access public
152
+ ```
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+ import { createClientFromEnv } from "./client.js";
3
+ import { createEnv, ensureEnvironment, pullVault } from "./index.js";
4
+ function parseArgs(argv) {
5
+ const [cmd = "help", ...rest] = argv;
6
+ const flags = {};
7
+ for (let i = 0; i < rest.length; i++) {
8
+ const token = rest[i];
9
+ if (!token?.startsWith("--"))
10
+ continue;
11
+ const key = token.slice(2);
12
+ const next = rest[i + 1];
13
+ if (!next || next.startsWith("--")) {
14
+ flags[key] = true;
15
+ continue;
16
+ }
17
+ if (key === "var") {
18
+ const list = Array.isArray(flags.var) ? flags.var : [];
19
+ list.push(next);
20
+ flags.var = list;
21
+ }
22
+ else {
23
+ flags[key] = next;
24
+ }
25
+ i++;
26
+ }
27
+ return { cmd, flags };
28
+ }
29
+ function str(flags, key, fallback) {
30
+ const v = flags[key];
31
+ if (typeof v === "string" && v.length > 0)
32
+ return v;
33
+ if (fallback !== undefined)
34
+ return fallback;
35
+ throw new Error(`Missing --${key}`);
36
+ }
37
+ function printHelp() {
38
+ console.log(`@clicadigital/vault-sdk — cria e carrega envs via URL do vault na VPN
39
+
40
+ Usage:
41
+ vault-sdk create --project <name> --env <name> [--url <vpn-url>] [--var KEY=VAL]...
42
+ vault-sdk ensure --project <name> --env <name> [--url <vpn-url>]
43
+ vault-sdk pull --project <name> --env <name> [--out .env] [--no-inject] [--url <vpn-url>]
44
+
45
+ Env:
46
+ VAULT_URL URL do vault no cluster/VPN (ex: http://vault-api:3001)
47
+ VAULT_PROJECT default --project
48
+ VAULT_ENV default --env
49
+
50
+ Auth: nenhuma chave — acesso só via rede interna (pods / VPN).
51
+ `);
52
+ }
53
+ function applyUrl(flags) {
54
+ if (typeof flags.url === "string")
55
+ process.env.VAULT_URL = flags.url;
56
+ }
57
+ function parseVarList(flags) {
58
+ const out = {};
59
+ const list = Array.isArray(flags.var) ? flags.var : [];
60
+ for (const pair of list) {
61
+ const eq = pair.indexOf("=");
62
+ if (eq < 1)
63
+ throw new Error(`Invalid --var ${pair} (use KEY=VALUE)`);
64
+ out[pair.slice(0, eq)] = pair.slice(eq + 1);
65
+ }
66
+ return out;
67
+ }
68
+ async function main() {
69
+ const { cmd, flags } = parseArgs(process.argv.slice(2));
70
+ if (cmd === "help" || flags.help === true) {
71
+ printHelp();
72
+ return;
73
+ }
74
+ applyUrl(flags);
75
+ const project = str(flags, "project", process.env.VAULT_PROJECT);
76
+ const env = str(flags, "env", process.env.VAULT_ENV);
77
+ const url = typeof flags.url === "string" ? flags.url : undefined;
78
+ const client = url
79
+ ? createClientFromEnv({ ...process.env, VAULT_URL: url })
80
+ : undefined;
81
+ if (cmd === "create") {
82
+ const vars = parseVarList(flags);
83
+ const result = await createEnv({ project, env, url, vars, client });
84
+ console.log(JSON.stringify({ project, env, ...result }, null, 2));
85
+ return;
86
+ }
87
+ if (cmd === "ensure") {
88
+ const result = await ensureEnvironment({ project, env, client });
89
+ console.log(JSON.stringify({
90
+ project,
91
+ env,
92
+ projectId: result.projectId,
93
+ environmentId: result.environmentId,
94
+ createdProject: result.createdProject,
95
+ createdEnvironment: result.createdEnvironment,
96
+ }, null, 2));
97
+ return;
98
+ }
99
+ if (cmd === "pull") {
100
+ const out = typeof flags.out === "string" ? flags.out : undefined;
101
+ const inject = flags["no-inject"] !== true;
102
+ const result = await pullVault({ project, env, out, inject, client });
103
+ console.log(`pulled ${Object.keys(result.vars).length} vars for ${project}/${env}` +
104
+ (result.out ? ` → ${result.out}` : "") +
105
+ (inject ? " (injected into process.env)" : ""));
106
+ return;
107
+ }
108
+ printHelp();
109
+ process.exit(1);
110
+ }
111
+ main().catch((err) => {
112
+ console.error(err instanceof Error ? err.message : err);
113
+ process.exit(1);
114
+ });
115
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { EnvVar, ProjectTree } from "./types.js";
2
+ export type VaultClientOptions = {
3
+ /** Base URL da API do vault na VPN, ex: http://vault-api.vpn.local:3001 */
4
+ baseUrl: string;
5
+ fetch?: typeof globalThis.fetch;
6
+ };
7
+ export declare class VaultClient {
8
+ readonly baseUrl: string;
9
+ private readonly fetchFn;
10
+ constructor(opts: VaultClientOptions);
11
+ private request;
12
+ listProjects(): Promise<ProjectTree[]>;
13
+ createProject(name: string): Promise<{
14
+ id: string;
15
+ name: string;
16
+ }>;
17
+ createEnvironment(projectId: string, name: string): Promise<{
18
+ ok: boolean;
19
+ }>;
20
+ listVars(environmentId: string): Promise<EnvVar[]>;
21
+ upsertVar(environmentId: string, key: string, value: string): Promise<{
22
+ ok: boolean;
23
+ }>;
24
+ }
25
+ export declare function createClientFromEnv(env?: NodeJS.ProcessEnv): VaultClient;
26
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC,CAAC;AAEF,qBAAa,WAAW;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;gBAEtC,IAAI,EAAE,kBAAkB;YAKtB,OAAO;IAgBrB,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAItC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAOlE,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAC;IAO5E,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAIlD,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAC;CAMvF;AAED,wBAAgB,mBAAmB,CACjC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,WAAW,CAQb"}
package/dist/client.js ADDED
@@ -0,0 +1,56 @@
1
+ export class VaultClient {
2
+ baseUrl;
3
+ fetchFn;
4
+ constructor(opts) {
5
+ this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
6
+ this.fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
7
+ }
8
+ async request(path, init) {
9
+ const res = await this.fetchFn(`${this.baseUrl}${path}`, {
10
+ ...init,
11
+ headers: {
12
+ "content-type": "application/json",
13
+ ...(init?.headers ?? {}),
14
+ },
15
+ });
16
+ if (!res.ok) {
17
+ const body = (await res.json().catch(() => null));
18
+ throw new Error(body?.error ?? `Vault API ${res.status} ${path}`);
19
+ }
20
+ if (res.status === 204)
21
+ return undefined;
22
+ return (await res.json());
23
+ }
24
+ listProjects() {
25
+ return this.request("/v1/projects");
26
+ }
27
+ createProject(name) {
28
+ return this.request("/v1/projects", {
29
+ method: "POST",
30
+ body: JSON.stringify({ name }),
31
+ });
32
+ }
33
+ createEnvironment(projectId, name) {
34
+ return this.request(`/v1/projects/${projectId}/environments`, {
35
+ method: "POST",
36
+ body: JSON.stringify({ name }),
37
+ });
38
+ }
39
+ listVars(environmentId) {
40
+ return this.request(`/v1/environments/${environmentId}/vars`);
41
+ }
42
+ upsertVar(environmentId, key, value) {
43
+ return this.request(`/v1/environments/${environmentId}/vars`, {
44
+ method: "PUT",
45
+ body: JSON.stringify({ key, value }),
46
+ });
47
+ }
48
+ }
49
+ export function createClientFromEnv(env = process.env) {
50
+ const baseUrl = env.VAULT_URL ?? env.VAULT_API_URL ?? env.API_URL;
51
+ if (!baseUrl) {
52
+ throw new Error("VAULT_URL is required (URL local da VPN, ex: http://vault-api:3001)");
53
+ }
54
+ return new VaultClient({ baseUrl });
55
+ }
56
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,WAAW;IACb,OAAO,CAAS;IACR,OAAO,CAA0B;IAElD,YAAY,IAAwB;QAClC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjE,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,IAAY,EAAE,IAAkB;QACvD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YACvD,GAAG,IAAI;YACP,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC;aACzB;SACF,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAA8B,CAAC;YAC/E,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,IAAI,aAAa,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,SAAc,CAAC;QAC9C,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;IACjC,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACtC,CAAC;IAED,aAAa,CAAC,IAAY;QACxB,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE;YAClC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,iBAAiB,CAAC,SAAiB,EAAE,IAAY;QAC/C,OAAO,IAAI,CAAC,OAAO,CAAC,gBAAgB,SAAS,eAAe,EAAE;YAC5D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,aAAqB;QAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,oBAAoB,aAAa,OAAO,CAAC,CAAC;IAChE,CAAC;IAED,SAAS,CAAC,aAAqB,EAAE,GAAW,EAAE,KAAa;QACzD,OAAO,IAAI,CAAC,OAAO,CAAC,oBAAoB,aAAa,OAAO,EAAE;YAC5D,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;SACrC,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB,CACjC,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,OAAO,CAAC;IAClE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,qEAAqE,CACtE,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function toDotEnv(vars: Record<string, string>): string;
2
+ export declare function varsToRecord(rows: {
3
+ key: string;
4
+ value: string;
5
+ }[]): Record<string, string>;
6
+ //# sourceMappingURL=dotenv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dotenv.d.ts","sourceRoot":"","sources":["../src/dotenv.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAO7D;AAQD,wBAAgB,YAAY,CAC1B,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,GACrC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIxB"}
package/dist/dotenv.js ADDED
@@ -0,0 +1,20 @@
1
+ export function toDotEnv(vars) {
2
+ return (Object.entries(vars)
3
+ .sort(([a], [b]) => a.localeCompare(b))
4
+ .map(([key, value]) => `${key}=${escapeEnvValue(value)}`)
5
+ .join("\n") + "\n");
6
+ }
7
+ function escapeEnvValue(value) {
8
+ if (value === "")
9
+ return '""';
10
+ if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value))
11
+ return value;
12
+ return JSON.stringify(value);
13
+ }
14
+ export function varsToRecord(rows) {
15
+ const out = {};
16
+ for (const row of rows)
17
+ out[row.key] = row.value;
18
+ return out;
19
+ }
20
+ //# sourceMappingURL=dotenv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dotenv.js","sourceRoot":"","sources":["../src/dotenv.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,QAAQ,CAAC,IAA4B;IACnD,OAAO,CACL,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;SACjB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;SACxD,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CACrB,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC9B,IAAI,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACzD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,IAAsC;IAEtC,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC;IACjD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,55 @@
1
+ import { createClientFromEnv, VaultClient, type VaultClientOptions } from "./client.js";
2
+ import { toDotEnv, varsToRecord } from "./dotenv.js";
3
+ import type { EnvVar } from "./types.js";
4
+ export type { EnvVar, ProjectTree, ProjectTreeEnv } from "./types.js";
5
+ export { VaultClient, createClientFromEnv, type VaultClientOptions };
6
+ export { toDotEnv, varsToRecord };
7
+ export type ResolveOptions = {
8
+ project: string;
9
+ env: string;
10
+ client?: VaultClient;
11
+ };
12
+ export type EnsureOptions = ResolveOptions & {
13
+ createProject?: boolean;
14
+ };
15
+ export type PullOptions = ResolveOptions & {
16
+ out?: string;
17
+ inject?: boolean;
18
+ };
19
+ export type CreateEnvOptions = {
20
+ project: string;
21
+ env: string;
22
+ /** URL da API do vault na VPN (cluster-internal) */
23
+ url?: string;
24
+ vars?: Record<string, string>;
25
+ client?: VaultClient;
26
+ };
27
+ export declare function resolveEnvironment(opts: ResolveOptions): Promise<{
28
+ projectId: string;
29
+ environmentId: string;
30
+ }>;
31
+ /** Garante projeto + environment na VPN (cria se não existir). */
32
+ export declare function ensureEnvironment(opts: EnsureOptions): Promise<{
33
+ projectId: string;
34
+ environmentId: string;
35
+ createdProject: boolean;
36
+ createdEnvironment: boolean;
37
+ }>;
38
+ /**
39
+ * Cria (ou garante) o environment no vault via URL da VPN
40
+ * e opcionalmente faz upsert das variáveis.
41
+ */
42
+ export declare function createEnv(opts: CreateEnvOptions): Promise<{
43
+ projectId: string;
44
+ environmentId: string;
45
+ createdProject: boolean;
46
+ createdEnvironment: boolean;
47
+ upserted: string[];
48
+ }>;
49
+ export declare function fetchVars(opts: ResolveOptions): Promise<EnvVar[]>;
50
+ export declare function loadVault(opts: ResolveOptions): Promise<Record<string, string>>;
51
+ export declare function pullVault(opts: PullOptions): Promise<{
52
+ vars: Record<string, string>;
53
+ out?: string;
54
+ }>;
55
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,YAAY,CAAC;AAEtD,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;AAElC,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAgBF,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CASvD;AAED,kEAAkE;AAClE,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,kBAAkB,EAAE,OAAO,CAAC;CAC7B,CAAC,CAiCD;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC;IAC/D,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC,CAiBD;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAIvE;AAED,wBAAsB,SAAS,CAC7B,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAOjC;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC;IAC1D,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC,CAgBD"}
package/dist/index.js ADDED
@@ -0,0 +1,110 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { createClientFromEnv, VaultClient } from "./client.js";
3
+ import { toDotEnv, varsToRecord } from "./dotenv.js";
4
+ export { VaultClient, createClientFromEnv };
5
+ export { toDotEnv, varsToRecord };
6
+ async function findProject(client, name) {
7
+ const tree = await client.listProjects();
8
+ return tree.find((p) => p.name === name);
9
+ }
10
+ function resolveClient(opts) {
11
+ if (opts.client)
12
+ return opts.client;
13
+ if (opts.url)
14
+ return new VaultClient({ baseUrl: opts.url });
15
+ return createClientFromEnv();
16
+ }
17
+ export async function resolveEnvironment(opts) {
18
+ const client = opts.client ?? createClientFromEnv();
19
+ const project = await findProject(client, opts.project);
20
+ if (!project)
21
+ throw new Error(`Project not found: ${opts.project}`);
22
+ const environment = project.environments.find((e) => e.name === opts.env);
23
+ if (!environment) {
24
+ throw new Error(`Environment "${opts.env}" not found in project "${opts.project}"`);
25
+ }
26
+ return { projectId: project.id, environmentId: environment.id };
27
+ }
28
+ /** Garante projeto + environment na VPN (cria se não existir). */
29
+ export async function ensureEnvironment(opts) {
30
+ const client = opts.client ?? createClientFromEnv();
31
+ let createdProject = false;
32
+ let createdEnvironment = false;
33
+ let project = await findProject(client, opts.project);
34
+ if (!project) {
35
+ if (opts.createProject === false) {
36
+ throw new Error(`Project not found: ${opts.project}`);
37
+ }
38
+ await client.createProject(opts.project);
39
+ createdProject = true;
40
+ project = await findProject(client, opts.project);
41
+ if (!project)
42
+ throw new Error(`Failed to create project: ${opts.project}`);
43
+ }
44
+ let environment = project.environments.find((e) => e.name === opts.env);
45
+ if (!environment) {
46
+ await client.createEnvironment(project.id, opts.env);
47
+ createdEnvironment = true;
48
+ const refreshed = await findProject(client, opts.project);
49
+ if (!refreshed)
50
+ throw new Error(`Failed to reload project: ${opts.project}`);
51
+ project = refreshed;
52
+ environment = project.environments.find((e) => e.name === opts.env);
53
+ if (!environment)
54
+ throw new Error(`Failed to create environment: ${opts.env}`);
55
+ }
56
+ return {
57
+ projectId: project.id,
58
+ environmentId: environment.id,
59
+ createdProject,
60
+ createdEnvironment,
61
+ };
62
+ }
63
+ /**
64
+ * Cria (ou garante) o environment no vault via URL da VPN
65
+ * e opcionalmente faz upsert das variáveis.
66
+ */
67
+ export async function createEnv(opts) {
68
+ const client = resolveClient(opts);
69
+ const ensured = await ensureEnvironment({
70
+ project: opts.project,
71
+ env: opts.env,
72
+ client,
73
+ });
74
+ const upserted = [];
75
+ if (opts.vars) {
76
+ for (const [key, value] of Object.entries(opts.vars)) {
77
+ await client.upsertVar(ensured.environmentId, key, value);
78
+ upserted.push(key);
79
+ }
80
+ }
81
+ return { ...ensured, upserted };
82
+ }
83
+ export async function fetchVars(opts) {
84
+ const client = opts.client ?? createClientFromEnv();
85
+ const { environmentId } = await resolveEnvironment({ ...opts, client });
86
+ return client.listVars(environmentId);
87
+ }
88
+ export async function loadVault(opts) {
89
+ const rows = await fetchVars(opts);
90
+ const record = varsToRecord(rows);
91
+ for (const [key, value] of Object.entries(record)) {
92
+ process.env[key] = value;
93
+ }
94
+ return record;
95
+ }
96
+ export async function pullVault(opts) {
97
+ const rows = await fetchVars(opts);
98
+ const vars = varsToRecord(rows);
99
+ if (opts.inject !== false) {
100
+ for (const [key, value] of Object.entries(vars)) {
101
+ process.env[key] = value;
102
+ }
103
+ }
104
+ const out = opts.out;
105
+ if (out) {
106
+ await writeFile(out, toDotEnv(vars), "utf8");
107
+ }
108
+ return out ? { vars, out } : { vars };
109
+ }
110
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export type ProjectTreeEnv = {
2
+ id: string;
3
+ name: string;
4
+ };
5
+ export type ProjectTree = {
6
+ id: string;
7
+ name: string;
8
+ environments: ProjectTreeEnv[];
9
+ };
10
+ export type EnvVar = {
11
+ id: string;
12
+ key: string;
13
+ value: string;
14
+ updated_at: string;
15
+ };
16
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,cAAc,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,43 @@
1
1
  {
2
2
  "name": "@clicadigital/vault-sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "SDK + CLI to ensure and pull env vars from Clica VPN Vault",
5
+ "type": "module",
6
+ "license": "UNLICENSED",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "vault-sdk": "./dist/cli.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "bun": "./src/index.ts",
16
+ "import": "./dist/index.js",
17
+ "default": "./dist/index.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "src"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsc -p tsconfig.json",
26
+ "prepublishOnly": "bun run build",
27
+ "vault": "bun run src/cli.ts"
28
+ },
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "keywords": [
33
+ "vault",
34
+ "env",
35
+ "secrets",
36
+ "kubernetes",
37
+ "clicadigital"
38
+ ],
39
+ "devDependencies": {
40
+ "@types/node": "^22.16.5",
41
+ "typescript": "^5.8.3"
42
+ }
43
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env node
2
+ import { createClientFromEnv } from "./client.js";
3
+ import { createEnv, ensureEnvironment, pullVault } from "./index.js";
4
+
5
+ type Flags = Record<string, string | boolean | string[]>;
6
+
7
+ function parseArgs(argv: string[]): { cmd: string; flags: Flags } {
8
+ const [cmd = "help", ...rest] = argv;
9
+ const flags: Flags = {};
10
+ for (let i = 0; i < rest.length; i++) {
11
+ const token = rest[i];
12
+ if (!token?.startsWith("--")) continue;
13
+ const key = token.slice(2);
14
+ const next = rest[i + 1];
15
+ if (!next || next.startsWith("--")) {
16
+ flags[key] = true;
17
+ continue;
18
+ }
19
+ if (key === "var") {
20
+ const list = Array.isArray(flags.var) ? flags.var : [];
21
+ list.push(next);
22
+ flags.var = list;
23
+ } else {
24
+ flags[key] = next;
25
+ }
26
+ i++;
27
+ }
28
+ return { cmd, flags };
29
+ }
30
+
31
+ function str(flags: Flags, key: string, fallback?: string): string {
32
+ const v = flags[key];
33
+ if (typeof v === "string" && v.length > 0) return v;
34
+ if (fallback !== undefined) return fallback;
35
+ throw new Error(`Missing --${key}`);
36
+ }
37
+
38
+ function printHelp(): void {
39
+ console.log(`@clicadigital/vault-sdk — cria e carrega envs via URL do vault na VPN
40
+
41
+ Usage:
42
+ vault-sdk create --project <name> --env <name> [--url <vpn-url>] [--var KEY=VAL]...
43
+ vault-sdk ensure --project <name> --env <name> [--url <vpn-url>]
44
+ vault-sdk pull --project <name> --env <name> [--out .env] [--no-inject] [--url <vpn-url>]
45
+
46
+ Env:
47
+ VAULT_URL URL do vault no cluster/VPN (ex: http://vault-api:3001)
48
+ VAULT_PROJECT default --project
49
+ VAULT_ENV default --env
50
+
51
+ Auth: nenhuma chave — acesso só via rede interna (pods / VPN).
52
+ `);
53
+ }
54
+
55
+ function applyUrl(flags: Flags): void {
56
+ if (typeof flags.url === "string") process.env.VAULT_URL = flags.url;
57
+ }
58
+
59
+ function parseVarList(flags: Flags): Record<string, string> {
60
+ const out: Record<string, string> = {};
61
+ const list = Array.isArray(flags.var) ? flags.var : [];
62
+ for (const pair of list) {
63
+ const eq = pair.indexOf("=");
64
+ if (eq < 1) throw new Error(`Invalid --var ${pair} (use KEY=VALUE)`);
65
+ out[pair.slice(0, eq)] = pair.slice(eq + 1);
66
+ }
67
+ return out;
68
+ }
69
+
70
+ async function main(): Promise<void> {
71
+ const { cmd, flags } = parseArgs(process.argv.slice(2));
72
+
73
+ if (cmd === "help" || flags.help === true) {
74
+ printHelp();
75
+ return;
76
+ }
77
+
78
+ applyUrl(flags);
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
+ });
package/src/client.ts ADDED
@@ -0,0 +1,74 @@
1
+ import type { EnvVar, ProjectTree } from "./types.js";
2
+
3
+ export type VaultClientOptions = {
4
+ /** Base URL da API do vault na VPN, ex: http://vault-api.vpn.local:3001 */
5
+ baseUrl: string;
6
+ fetch?: typeof globalThis.fetch;
7
+ };
8
+
9
+ export class VaultClient {
10
+ readonly baseUrl: string;
11
+ private readonly fetchFn: typeof globalThis.fetch;
12
+
13
+ constructor(opts: VaultClientOptions) {
14
+ this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
15
+ this.fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
16
+ }
17
+
18
+ private async request<T>(path: string, init?: RequestInit): Promise<T> {
19
+ const res = await this.fetchFn(`${this.baseUrl}${path}`, {
20
+ ...init,
21
+ headers: {
22
+ "content-type": "application/json",
23
+ ...(init?.headers ?? {}),
24
+ },
25
+ });
26
+ if (!res.ok) {
27
+ const body = (await res.json().catch(() => null)) as { error?: string } | null;
28
+ throw new Error(body?.error ?? `Vault API ${res.status} ${path}`);
29
+ }
30
+ if (res.status === 204) return undefined as T;
31
+ return (await res.json()) as T;
32
+ }
33
+
34
+ listProjects(): Promise<ProjectTree[]> {
35
+ return this.request("/v1/projects");
36
+ }
37
+
38
+ createProject(name: string): Promise<{ id: string; name: string }> {
39
+ return this.request("/v1/projects", {
40
+ method: "POST",
41
+ body: JSON.stringify({ name }),
42
+ });
43
+ }
44
+
45
+ createEnvironment(projectId: string, name: string): Promise<{ ok: boolean }> {
46
+ return this.request(`/v1/projects/${projectId}/environments`, {
47
+ method: "POST",
48
+ body: JSON.stringify({ name }),
49
+ });
50
+ }
51
+
52
+ listVars(environmentId: string): Promise<EnvVar[]> {
53
+ return this.request(`/v1/environments/${environmentId}/vars`);
54
+ }
55
+
56
+ upsertVar(environmentId: string, key: string, value: string): Promise<{ ok: boolean }> {
57
+ return this.request(`/v1/environments/${environmentId}/vars`, {
58
+ method: "PUT",
59
+ body: JSON.stringify({ key, value }),
60
+ });
61
+ }
62
+ }
63
+
64
+ export function createClientFromEnv(
65
+ env: NodeJS.ProcessEnv = process.env,
66
+ ): VaultClient {
67
+ const baseUrl = env.VAULT_URL ?? env.VAULT_API_URL ?? env.API_URL;
68
+ if (!baseUrl) {
69
+ throw new Error(
70
+ "VAULT_URL is required (URL local da VPN, ex: http://vault-api:3001)",
71
+ );
72
+ }
73
+ return new VaultClient({ baseUrl });
74
+ }
package/src/dotenv.ts ADDED
@@ -0,0 +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
+ }
package/src/index.ts ADDED
@@ -0,0 +1,167 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { createClientFromEnv, VaultClient, type VaultClientOptions } from "./client.js";
3
+ import { toDotEnv, varsToRecord } from "./dotenv.js";
4
+ import type { EnvVar, ProjectTree } from "./types.js";
5
+
6
+ export type { EnvVar, ProjectTree, ProjectTreeEnv } from "./types.js";
7
+ export { VaultClient, createClientFromEnv, type VaultClientOptions };
8
+ export { toDotEnv, varsToRecord };
9
+
10
+ export type ResolveOptions = {
11
+ project: string;
12
+ env: string;
13
+ client?: VaultClient;
14
+ };
15
+
16
+ export type EnsureOptions = ResolveOptions & {
17
+ createProject?: boolean;
18
+ };
19
+
20
+ export type PullOptions = ResolveOptions & {
21
+ out?: string;
22
+ inject?: boolean;
23
+ };
24
+
25
+ export type CreateEnvOptions = {
26
+ project: string;
27
+ env: string;
28
+ /** URL da API do vault na VPN (cluster-internal) */
29
+ url?: string;
30
+ vars?: Record<string, string>;
31
+ client?: VaultClient;
32
+ };
33
+
34
+ async function findProject(
35
+ client: VaultClient,
36
+ name: string,
37
+ ): Promise<ProjectTree | undefined> {
38
+ const tree = await client.listProjects();
39
+ return tree.find((p) => p.name === name);
40
+ }
41
+
42
+ function resolveClient(opts: { client?: VaultClient; url?: string }): VaultClient {
43
+ if (opts.client) return opts.client;
44
+ if (opts.url) return new VaultClient({ baseUrl: opts.url });
45
+ return createClientFromEnv();
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
+ }
package/src/types.ts ADDED
@@ -0,0 +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
+ };