@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/README.md
CHANGED
|
@@ -1,152 +1,126 @@
|
|
|
1
|
-
# @clicadigital/vault-sdk
|
|
2
|
-
|
|
3
|
-
SDK
|
|
4
|
-
|
|
5
|
-
Pensado para uso **entre pods no
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
```
|
|
1
|
+
# @clicadigital/vault-sdk
|
|
2
|
+
|
|
3
|
+
SDK para carregar variáveis de ambiente do **Clica VPN Vault** em `process.env`. Projeto, environment e allow ficam na UI do vault.
|
|
4
|
+
|
|
5
|
+
Pensado para uso **entre pods no k3s/k8s**. Sem API key estática.
|
|
6
|
+
|
|
7
|
+
Segurança em camadas:
|
|
8
|
+
1. **NetworkPolicy** — só pods com `vault.clica.io/access=true` (e o `vault-web`) alcançam a API
|
|
9
|
+
2. **ServiceAccount + TokenReview** — o SDK envia o JWT projetado (`audience: vault`); a API valida e checa allowlist
|
|
10
|
+
3. **Master key** — só no Deployment do vault (`VAULT_MASTER_KEY`), nunca nos apps
|
|
11
|
+
|
|
12
|
+
Local/dev: API com `VAULT_AUTH=none` (sem token).
|
|
13
|
+
|
|
14
|
+
## Instalação
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @clicadigital/vault-sdk
|
|
18
|
+
# ou
|
|
19
|
+
bun add @clicadigital/vault-sdk
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Configuração
|
|
23
|
+
|
|
24
|
+
| Variável | Obrigatória | Descrição |
|
|
25
|
+
|----------------------|-------------|--------------------------------------------------------|
|
|
26
|
+
| `VAULT_URL` | não | Override da URL. Default: `http://vault-api-service.vault.svc.cluster.local:3001` |
|
|
27
|
+
| `VAULT_SA_TOKEN_PATH`| não | Path do token SA (default: `/var/run/secrets/tokens/vault/token`) |
|
|
28
|
+
| `VAULT_PROJECT` | não | Default de `--project` na CLI |
|
|
29
|
+
| `VAULT_ENV` | não | Default de `--env` na CLI |
|
|
30
|
+
|
|
31
|
+
Também aceita `VAULT_API_URL` ou `API_URL` no lugar de `VAULT_URL`. Em pods no cluster normalmente **não precisa** setar URL.
|
|
32
|
+
|
|
33
|
+
No cluster, monte um projected token:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
volumeMounts:
|
|
37
|
+
- name: vault-token
|
|
38
|
+
mountPath: /var/run/secrets/tokens/vault
|
|
39
|
+
readOnly: true
|
|
40
|
+
volumes:
|
|
41
|
+
- name: vault-token
|
|
42
|
+
projected:
|
|
43
|
+
sources:
|
|
44
|
+
- serviceAccountToken:
|
|
45
|
+
path: token
|
|
46
|
+
expirationSeconds: 3600
|
|
47
|
+
audience: vault
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
O SDK lê o token sozinho e manda `Authorization: Bearer …`.
|
|
51
|
+
|
|
52
|
+
## CLI
|
|
53
|
+
|
|
54
|
+
### Puxar variáveis no build (gera `.env`)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Dockerfile / CI / init container
|
|
58
|
+
npx vault-sdk pull \
|
|
59
|
+
--project meu-app \
|
|
60
|
+
--env production \
|
|
61
|
+
--out .env \
|
|
62
|
+
--no-inject
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Sem `--no-inject`, as vars também vão para `process.env` do processo da CLI.
|
|
66
|
+
|
|
67
|
+
### URL explícita
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx vault-sdk pull --url http://vault-api.vpn.svc.cluster.local:3001 \
|
|
71
|
+
--project meu-app --env staging --out .env
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Uso em código (Node / Bun)
|
|
75
|
+
|
|
76
|
+
### Carregar no boot / build script
|
|
77
|
+
|
|
78
|
+
O pacote publica ESM e CJS. Um `import` normal vira `require()` no build CJS e continua funcionando. Não use `new Function` nem `import()` dinâmico.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { loadVault } from "@clicadigital/vault-sdk";
|
|
82
|
+
|
|
83
|
+
export async function loadProductionVault(): Promise<void> {
|
|
84
|
+
if (process.env.NODE_ENV !== "production") return;
|
|
85
|
+
await loadVault({ project: "meu-app", env: "production" });
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Mantenha esse import num módulo separado do entry do Next, para o webpack não levar o SDK às outras rotas.
|
|
90
|
+
|
|
91
|
+
No pod, a URL default é a do Service e o token SA já vem montado. Manifests de referência: [`deploy/k3s/`](../deploy/k3s/) (NetworkPolicy, RBAC TokenReview, SA, exemplos).
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
kubectl apply -k deploy/k3s
|
|
95
|
+
kubectl apply -f deploy/k3s/secrets.yaml # a partir de secrets.example.yaml
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
O allow do app é feito no projeto, pela UI do vault. Informe a ServiceAccount `system:serviceaccount:<namespace>:<nome>`.
|
|
99
|
+
|
|
100
|
+
`VAULT_ALLOWED_SAS` no deployment fica só para o operador da UI (`vault-web`).
|
|
101
|
+
|
|
102
|
+
## API do vault usada pelo SDK
|
|
103
|
+
|
|
104
|
+
| Método | Path | Uso |
|
|
105
|
+
|--------|------|-----|
|
|
106
|
+
| `GET` | `/v1/projects` | Achar o projeto e o environment |
|
|
107
|
+
| `GET` | `/v1/environments/:id/vars` | Ler as vars já descriptografadas |
|
|
108
|
+
|
|
109
|
+
## Desenvolvimento local (neste monorepo)
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
cd sdk
|
|
113
|
+
bun install
|
|
114
|
+
bun run build
|
|
115
|
+
|
|
116
|
+
# fora do cluster, sobrescreva o default k8s
|
|
117
|
+
VAULT_URL=http://localhost:3001 bun run src/cli.ts pull --project demo --env production --out .env
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Publicar:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
cd sdk
|
|
124
|
+
bun run build
|
|
125
|
+
bun publish --access public
|
|
126
|
+
```
|
package/dist/cjs/cli.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const index_js_1 = require("./index.js");
|
|
5
|
+
function parseArgs(argv) {
|
|
6
|
+
const [cmd = "help", ...rest] = argv;
|
|
7
|
+
const flags = {};
|
|
8
|
+
for (let i = 0; i < rest.length; i++) {
|
|
9
|
+
const token = rest[i];
|
|
10
|
+
if (!token?.startsWith("--"))
|
|
11
|
+
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
|
+
function str(flags, key, fallback) {
|
|
24
|
+
const value = flags[key];
|
|
25
|
+
if (typeof value === "string" && value.length > 0)
|
|
26
|
+
return value;
|
|
27
|
+
if (fallback !== undefined)
|
|
28
|
+
return fallback;
|
|
29
|
+
throw new Error(`Missing --${key}`);
|
|
30
|
+
}
|
|
31
|
+
function printHelp() {
|
|
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
|
+
async function main() {
|
|
48
|
+
const { cmd, flags } = parseArgs(process.argv.slice(2));
|
|
49
|
+
if (cmd === "help" || flags.help === true) {
|
|
50
|
+
printHelp();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (typeof flags.url === "string")
|
|
54
|
+
process.env.VAULT_URL = flags.url;
|
|
55
|
+
if (cmd !== "pull") {
|
|
56
|
+
printHelp();
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
const project = str(flags, "project", process.env.VAULT_PROJECT);
|
|
60
|
+
const env = str(flags, "env", process.env.VAULT_ENV);
|
|
61
|
+
const out = typeof flags.out === "string" ? flags.out : undefined;
|
|
62
|
+
const inject = flags["no-inject"] !== true;
|
|
63
|
+
const result = await (0, index_js_1.pullVault)({ project, env, out, inject });
|
|
64
|
+
console.log(`pulled ${Object.keys(result.vars).length} vars for ${project}/${env}` +
|
|
65
|
+
(result.out ? ` → ${result.out}` : "") +
|
|
66
|
+
(inject ? " (injected into process.env)" : ""));
|
|
67
|
+
}
|
|
68
|
+
main().catch((err) => {
|
|
69
|
+
console.error(err instanceof Error ? err.message : err);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
});
|
|
72
|
+
//# 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,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VaultClient = exports.DEFAULT_VAULT_URL = void 0;
|
|
4
|
+
exports.createClientFromEnv = createClientFromEnv;
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const DEFAULT_TOKEN_PATHS = [
|
|
7
|
+
"/var/run/secrets/tokens/vault/token",
|
|
8
|
+
"/var/run/secrets/kubernetes.io/serviceaccount/token",
|
|
9
|
+
];
|
|
10
|
+
/** DNS interno do Service no k3s (namespace `vault`). Override com VAULT_URL. */
|
|
11
|
+
exports.DEFAULT_VAULT_URL = "http://vault-api-service.vault.svc.cluster.local:3001";
|
|
12
|
+
function resolveToken(opts) {
|
|
13
|
+
if (opts.token)
|
|
14
|
+
return opts.token;
|
|
15
|
+
const paths = opts.tokenPaths ?? DEFAULT_TOKEN_PATHS;
|
|
16
|
+
for (const path of paths) {
|
|
17
|
+
if (!(0, node_fs_1.existsSync)(path))
|
|
18
|
+
continue;
|
|
19
|
+
try {
|
|
20
|
+
const token = (0, node_fs_1.readFileSync)(path, "utf8").trim();
|
|
21
|
+
if (token)
|
|
22
|
+
return token;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// ignore unreadable path
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
class VaultClient {
|
|
31
|
+
baseUrl;
|
|
32
|
+
token;
|
|
33
|
+
fetchFn;
|
|
34
|
+
constructor(opts) {
|
|
35
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
36
|
+
this.token = resolveToken(opts);
|
|
37
|
+
this.fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
38
|
+
}
|
|
39
|
+
async request(path, init) {
|
|
40
|
+
const headers = {
|
|
41
|
+
"content-type": "application/json",
|
|
42
|
+
...init?.headers,
|
|
43
|
+
};
|
|
44
|
+
if (this.token)
|
|
45
|
+
headers.authorization = `Bearer ${this.token}`;
|
|
46
|
+
const res = await this.fetchFn(`${this.baseUrl}${path}`, {
|
|
47
|
+
...init,
|
|
48
|
+
headers,
|
|
49
|
+
});
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
const body = (await res.json().catch(() => null));
|
|
52
|
+
throw new Error(body?.error ?? `Vault API ${res.status} ${path}`);
|
|
53
|
+
}
|
|
54
|
+
if (res.status === 204)
|
|
55
|
+
return undefined;
|
|
56
|
+
return (await res.json());
|
|
57
|
+
}
|
|
58
|
+
listProjects() {
|
|
59
|
+
return this.request("/v1/projects");
|
|
60
|
+
}
|
|
61
|
+
listVars(environmentId) {
|
|
62
|
+
return this.request(`/v1/environments/${environmentId}/vars`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.VaultClient = VaultClient;
|
|
66
|
+
function createClientFromEnv(env = process.env) {
|
|
67
|
+
const baseUrl = env.VAULT_URL ?? env.VAULT_API_URL ?? env.API_URL ?? exports.DEFAULT_VAULT_URL;
|
|
68
|
+
const tokenPath = env.VAULT_SA_TOKEN_PATH;
|
|
69
|
+
return new VaultClient({
|
|
70
|
+
baseUrl,
|
|
71
|
+
token: env.VAULT_SA_TOKEN,
|
|
72
|
+
tokenPaths: tokenPath ? [tokenPath, ...DEFAULT_TOKEN_PATHS] : undefined,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toDotEnv = toDotEnv;
|
|
4
|
+
exports.varsToRecord = varsToRecord;
|
|
5
|
+
function toDotEnv(vars) {
|
|
6
|
+
return (Object.entries(vars)
|
|
7
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
8
|
+
.map(([key, value]) => `${key}=${escapeEnvValue(value)}`)
|
|
9
|
+
.join("\n") + "\n");
|
|
10
|
+
}
|
|
11
|
+
function escapeEnvValue(value) {
|
|
12
|
+
if (value === "")
|
|
13
|
+
return '""';
|
|
14
|
+
if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value))
|
|
15
|
+
return value;
|
|
16
|
+
return JSON.stringify(value);
|
|
17
|
+
}
|
|
18
|
+
function varsToRecord(rows) {
|
|
19
|
+
const out = {};
|
|
20
|
+
for (const row of rows)
|
|
21
|
+
out[row.key] = row.value;
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=dotenv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dotenv.js","sourceRoot":"","sources":["../../src/dotenv.ts"],"names":[],"mappings":";;AAAA,4BAOC;AAQD,oCAMC;AArBD,SAAgB,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,SAAgB,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,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadVault = loadVault;
|
|
4
|
+
exports.pullVault = pullVault;
|
|
5
|
+
const promises_1 = require("node:fs/promises");
|
|
6
|
+
const client_js_1 = require("./client.js");
|
|
7
|
+
const dotenv_js_1 = require("./dotenv.js");
|
|
8
|
+
async function readVars(opts) {
|
|
9
|
+
const client = (0, client_js_1.createClientFromEnv)();
|
|
10
|
+
const projects = await client.listProjects();
|
|
11
|
+
const project = projects.find((item) => item.name === opts.project);
|
|
12
|
+
if (!project)
|
|
13
|
+
throw new Error(`Project not found: ${opts.project}`);
|
|
14
|
+
const environment = project.environments.find((item) => item.name === opts.env);
|
|
15
|
+
if (!environment) {
|
|
16
|
+
throw new Error(`Environment "${opts.env}" not found in project "${opts.project}"`);
|
|
17
|
+
}
|
|
18
|
+
const rows = await client.listVars(environment.id);
|
|
19
|
+
return (0, dotenv_js_1.varsToRecord)(rows);
|
|
20
|
+
}
|
|
21
|
+
/** Lê o environment e injeta as variáveis em `process.env`. */
|
|
22
|
+
async function loadVault(opts) {
|
|
23
|
+
const vars = await readVars(opts);
|
|
24
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
25
|
+
process.env[key] = value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function pullVault(opts) {
|
|
29
|
+
const vars = await readVars(opts);
|
|
30
|
+
if (opts.inject !== false) {
|
|
31
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
32
|
+
process.env[key] = value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const out = opts.out;
|
|
36
|
+
if (out)
|
|
37
|
+
await (0, promises_1.writeFile)(out, (0, dotenv_js_1.toDotEnv)(vars), "utf8");
|
|
38
|
+
return out ? { vars, out } : { vars };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;AAyBA,8BAKC;AAED,8BAcC;AA9CD,+CAA6C;AAC7C,2CAAkD;AAClD,2CAAqD;AAOrD,KAAK,UAAU,QAAQ,CAAC,IAAsB;IAC5C,MAAM,MAAM,GAAG,IAAA,+BAAmB,GAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;IAC7C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC;IACpE,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAEpE,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC;IAChF,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,GAAG,2BAA2B,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACnD,OAAO,IAAA,wBAAY,EAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,+DAA+D;AACxD,KAAK,UAAU,SAAS,CAAC,IAAsB;IACpD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC3B,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,SAAS,CAC7B,IAA2D;IAE3D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;IAElC,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC1B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;IACrB,IAAI,GAAG;QAAE,MAAM,IAAA,oBAAS,EAAC,GAAG,EAAE,IAAA,oBAAQ,EAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;IACtD,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
|