envpass-cli 0.0.0-stage → 0.2.7

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,47 @@
1
- # Temporary Holding Version
1
+ # envpass-cli
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
+ Client library and CLI for [envpass](https://envpass.dev): encrypted environment variables for every project and environment.
4
+
5
+ ## CLI
6
+
7
+ ```bash
8
+ bunx envpass-cli login # sign in through your browser
9
+ bunx envpass-cli link -w acme -p shop -e dev # save defaults to .envpass.json (no secrets inside)
10
+ bunx envpass-cli pull # write .env
11
+ bunx envpass-cli pull -e prod -o - # print to stdout
12
+ bunx envpass-cli run -e dev -- bun dev # run with values injected, masked in output
13
+ bunx envpass-cli webhooks list # webhooks and syncs need `login`
14
+ bunx envpass-cli syncs run <id> # push a sync now
15
+ ```
16
+
17
+ `npx envpass-cli …` works the same way.
18
+
19
+ In CI, use a service token instead of `login`:
20
+
21
+ ```bash
22
+ ENVPASS_TOKEN=ep_live_… npx envpass-cli pull -e prod
23
+ ```
24
+
25
+ | Option | Environment variable | |
26
+ |---|---|---|
27
+ | `-w, --workspace` | `ENVPASS_WORKSPACE` | Workspace slug (not needed with a service token) |
28
+ | `-p, --project` | `ENVPASS_PROJECT` | Project slug (not needed with a service token) |
29
+ | `-e, --env` | `ENVPASS_ENV` | Environment slug |
30
+ | `--url` | `ENVPASS_URL` | Server, default `https://envpass.dev` |
31
+ | | `ENVPASS_TOKEN` | Service token or CLI session token |
32
+
33
+ ## Library
34
+
35
+ ```ts
36
+ import { createEnvpass, loadEnv } from "envpass-cli"
37
+
38
+ await loadEnv({ environment: "prod" })
39
+
40
+ const envpass = createEnvpass({ token: process.env.ENVPASS_TOKEN })
41
+ const entries = await envpass.resolve({ environment: "prod" })
42
+ const webhooks = await envpass.listWebhooks({ workspace: "acme" })
43
+
44
+ const { data } = await envpass.api.GET("/api/v1/workspaces")
45
+ ```
46
+
47
+ `envpass.api` is a fully typed client for the whole REST API, generated from the OpenAPI spec.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,231 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from "node:child_process";
3
+ import { writeFileSync } from "node:fs";
4
+ import { createRequire } from "node:module";
5
+ import { parseArgs } from "node:util";
6
+ import { createEnvpass, EnvpassError } from "./client.js";
7
+ import { baseUrl, forgetToken, resolveScope, saveToken, storedToken, writeProjectLink, } from "./config.js";
8
+ import { deviceLogin, openBrowser } from "./device.js";
9
+ import { syncsCommand, webhooksCommand } from "./integrations.js";
10
+ import { maskingStream } from "./mask.js";
11
+ const { version } = createRequire(import.meta.url)("../package.json");
12
+ const HELP = `envpass ${version}: encrypted environment variables for every project and environment
13
+
14
+ Usage
15
+ envpass login Sign in through your browser
16
+ envpass logout Forget the saved login
17
+ envpass whoami Show who the current token belongs to
18
+ envpass link -w <ws> -p <project> Save defaults to .envpass.json in this directory
19
+ envpass pull [-e env] [-o .env] Write resolved values to a file ("-" for stdout)
20
+ envpass run [-e env] -- <command> Run a command with the values injected
21
+
22
+ Webhooks and syncs (need \`envpass login\`, not a service token)
23
+ envpass webhooks list List the workspace's webhooks
24
+ envpass webhooks add --url <url> Register a webhook and print its signing secret once
25
+ envpass webhooks remove <id> Delete a webhook
26
+ envpass webhooks test <id> Send a test event (exit code 1 if it fails)
27
+ envpass webhooks deliveries <id> Show a webhook's recent deliveries
28
+ envpass syncs list [-p project] List the project's syncs
29
+ envpass syncs run <id> Push a sync now
30
+ envpass syncs pause <id> Stop a sync from running
31
+ envpass syncs resume <id> Turn a paused sync back on
32
+
33
+ Options
34
+ -w, --workspace <slug> Workspace (not needed with a service token)
35
+ -p, --project <slug> Project (not needed with a service token)
36
+ -e, --env <slug> Environment, e.g. dev or prod
37
+ -o, --out <file> pull: output file (default .env)
38
+ -f, --format <format> pull: dotenv, shell or json (default dotenv)
39
+ --no-mask run: show secret values in the command's output
40
+ --no-browser login: print the link instead of opening a browser
41
+ --json webhooks list, webhooks deliveries, syncs list: print raw JSON
42
+ --limit <n> webhooks deliveries: how many to show, 1-100 (default 25)
43
+ --url <url> envpass server (default https://envpass.dev, or ENVPASS_URL)
44
+
45
+ Options for webhooks add
46
+ --url <url> Endpoint to POST to (point at your server with ENVPASS_URL)
47
+ --event <event> secrets.changed, sync.succeeded or sync.failed; repeat for more
48
+ (default secrets.changed and sync.failed)
49
+ -e, --env <slug> Only these environments; repeat for more (default all)
50
+ -p, --project <slug> Only these projects; repeat for more (default all)
51
+ -f, --format <format> json or slack (default slack for Slack URLs, json otherwise)
52
+ --description <text> A note to tell webhooks apart
53
+
54
+ Environment
55
+ ENVPASS_TOKEN A service token (ep_live_…) or CLI session token
56
+ ENVPASS_WORKSPACE, ENVPASS_PROJECT, ENVPASS_ENV
57
+ `;
58
+ function fail(message, code = 1) {
59
+ process.stderr.write(`envpass: ${message}\n`);
60
+ process.exit(code);
61
+ }
62
+ async function main(argv) {
63
+ const { values, positionals } = parseArgs({
64
+ args: argv,
65
+ allowPositionals: true,
66
+ options: {
67
+ workspace: { type: "string", short: "w" },
68
+ project: { type: "string", short: "p", multiple: true },
69
+ env: { type: "string", short: "e", multiple: true },
70
+ out: { type: "string", short: "o" },
71
+ format: { type: "string", short: "f" },
72
+ url: { type: "string" },
73
+ event: { type: "string", multiple: true },
74
+ description: { type: "string" },
75
+ limit: { type: "string" },
76
+ json: { type: "boolean" },
77
+ "no-mask": { type: "boolean" },
78
+ "no-browser": { type: "boolean" },
79
+ help: { type: "boolean", short: "h" },
80
+ version: { type: "boolean", short: "v" },
81
+ },
82
+ });
83
+ const [command, ...rest] = positionals;
84
+ if (values.version)
85
+ return void process.stdout.write(`${version}\n`);
86
+ if (values.help || !command || command === "help")
87
+ return void process.stdout.write(HELP);
88
+ const endpointUrl = command === "webhooks" && rest[0] === "add";
89
+ const url = baseUrl(endpointUrl ? undefined : values.url);
90
+ const flags = {
91
+ workspace: values.workspace,
92
+ project: values.project?.at(-1),
93
+ environment: values.env?.at(-1),
94
+ };
95
+ switch (command) {
96
+ case "login": {
97
+ const token = await deviceLogin(url, (code) => {
98
+ const link = code.verification_uri_complete ?? code.verification_uri;
99
+ process.stderr.write(`\nOpen ${link}\nand confirm the code: ${code.user_code}\n\nWaiting for approval…\n`);
100
+ if (!values["no-browser"])
101
+ openBrowser(link);
102
+ });
103
+ const path = saveToken(url, token);
104
+ const me = await createEnvpass({ baseUrl: url, token }).me();
105
+ process.stderr.write(`Signed in. Token saved to ${path}\n`);
106
+ if (me.workspaces.length) {
107
+ process.stderr.write(`Workspaces: ${me.workspaces.map((w) => w.slug).join(", ")}\n`);
108
+ }
109
+ return;
110
+ }
111
+ case "logout": {
112
+ const token = storedToken(url);
113
+ if (token) {
114
+ await fetch(`${url}/api/auth/sign-out`, {
115
+ method: "POST",
116
+ headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
117
+ body: "{}",
118
+ }).catch(() => undefined);
119
+ }
120
+ const removed = forgetToken(url);
121
+ process.stderr.write(removed ? `Signed out of ${url}\n` : `No saved login for ${url}\n`);
122
+ return;
123
+ }
124
+ case "whoami": {
125
+ const client = createEnvpass({ baseUrl: url });
126
+ if (!client.hasToken)
127
+ fail("Not signed in. Run `envpass login` or set ENVPASS_TOKEN.");
128
+ const me = await client.me();
129
+ if (me.token) {
130
+ process.stdout.write(`Service token ${me.token.id} (${me.token.access}) for project ${me.token.projectId}\n`);
131
+ }
132
+ else {
133
+ process.stdout.write(`User ${me.userId}\n`);
134
+ for (const ws of me.workspaces)
135
+ process.stdout.write(` ${ws.slug}${ws.isOwner ? " (owner)" : ""}\n`);
136
+ }
137
+ return;
138
+ }
139
+ case "link": {
140
+ const scope = resolveScope(flags);
141
+ if (!scope.workspace || !scope.project)
142
+ fail("Pass --workspace and --project.");
143
+ const path = writeProjectLink(scope);
144
+ process.stderr.write(`Saved ${path}. It holds no secrets and is safe to commit.\n`);
145
+ return;
146
+ }
147
+ case "pull": {
148
+ const format = (values.format ?? "dotenv");
149
+ if (!["dotenv", "shell", "json"].includes(format))
150
+ fail("--format must be dotenv, shell or json");
151
+ const client = createEnvpass({ baseUrl: url });
152
+ if (!client.hasToken)
153
+ fail("Not signed in. Run `envpass login` or set ENVPASS_TOKEN.");
154
+ const text = format === "json"
155
+ ? `${JSON.stringify(Object.fromEntries((await client.resolve(flags)).map((e) => [e.key, e.value])), null, 2)}\n`
156
+ : await client.resolveText(flags, format);
157
+ const out = values.out ?? ".env";
158
+ if (out === "-")
159
+ return void process.stdout.write(text);
160
+ writeFileSync(out, text, { mode: 0o600 });
161
+ const count = text
162
+ .split("\n")
163
+ .filter((line) => line.includes("=") || line.includes(":")).length;
164
+ process.stderr.write(`Wrote ${out} (${count} values). Keep it out of git.\n`);
165
+ return;
166
+ }
167
+ case "run": {
168
+ const separator = argv.indexOf("--");
169
+ const commandArgs = separator === -1 ? rest : argv.slice(separator + 1);
170
+ const [program, ...programArgs] = commandArgs;
171
+ if (!program)
172
+ fail("Usage: envpass run [-e env] -- <command> [args…]");
173
+ const client = createEnvpass({ baseUrl: url });
174
+ if (!client.hasToken)
175
+ fail("Not signed in. Run `envpass login` or set ENVPASS_TOKEN.");
176
+ const entries = await client.resolve(flags);
177
+ const env = { ...process.env, ...Object.fromEntries(entries.map((e) => [e.key, e.value])) };
178
+ const mask = !values["no-mask"];
179
+ const child = spawn(program, programArgs, {
180
+ env,
181
+ stdio: mask ? ["inherit", "pipe", "pipe"] : "inherit",
182
+ });
183
+ if (mask) {
184
+ const secrets = entries.map((e) => e.value);
185
+ child.stdout?.pipe(maskingStream(secrets)).pipe(process.stdout);
186
+ child.stderr?.pipe(maskingStream(secrets)).pipe(process.stderr);
187
+ }
188
+ for (const signal of ["SIGINT", "SIGTERM"]) {
189
+ process.on(signal, () => child.kill(signal));
190
+ }
191
+ child.on("error", (error) => fail(`Could not start ${program}: ${error.message}`, 127));
192
+ child.on("exit", (code, signal) => {
193
+ if (signal)
194
+ process.kill(process.pid, signal);
195
+ else
196
+ process.exit(code ?? 0);
197
+ });
198
+ return;
199
+ }
200
+ case "webhooks":
201
+ case "syncs": {
202
+ const client = createEnvpass({ baseUrl: url });
203
+ if (!client.hasToken)
204
+ fail("Not signed in. Run `envpass login` or set ENVPASS_TOKEN.");
205
+ const run = command === "webhooks" ? webhooksCommand : syncsCommand;
206
+ process.exitCode = await run(client, {
207
+ scope: flags,
208
+ args: rest,
209
+ json: values.json,
210
+ url: endpointUrl ? values.url : undefined,
211
+ events: values.event,
212
+ environments: values.env,
213
+ projects: values.project,
214
+ format: values.format,
215
+ description: values.description,
216
+ limit: values.limit,
217
+ }, {
218
+ out: (text) => process.stdout.write(text),
219
+ err: (text) => process.stderr.write(text),
220
+ });
221
+ return;
222
+ }
223
+ default:
224
+ fail(`Unknown command "${command}". Run \`envpass --help\`.`);
225
+ }
226
+ }
227
+ main(process.argv.slice(2)).catch((error) => {
228
+ if (error instanceof EnvpassError)
229
+ fail(`${error.message}${error.code ? ` (${error.code})` : ""}`);
230
+ fail(error instanceof Error ? error.message : String(error));
231
+ });
@@ -0,0 +1,86 @@
1
+ import { type ProjectLink } from "./config.js";
2
+ import type { components, paths } from "./schema.js";
3
+ type Schemas = components["schemas"];
4
+ export type Source = Schemas["SecretSource"];
5
+ export type ResolvedEntry = {
6
+ key: string;
7
+ value: string;
8
+ source: Source;
9
+ };
10
+ export type ExportFormat = "dotenv" | "json" | "shell";
11
+ export type Workspace = Schemas["Workspace"];
12
+ export type Environment = Schemas["Environment"];
13
+ export type Webhook = Schemas["Webhook"];
14
+ export type WebhookEvent = Schemas["WebhookEvent"];
15
+ export type WebhookFormat = Webhook["format"];
16
+ export type WebhookDelivery = Schemas["WebhookDelivery"];
17
+ export type WebhookTestResult = Schemas["WebhookTestResult"];
18
+ export type Connection = Schemas["Connection"];
19
+ export type Sync = Schemas["Sync"];
20
+ export type NewWebhook = {
21
+ url: string;
22
+ events?: WebhookEvent[];
23
+ environments?: string[];
24
+ projects?: string[];
25
+ format?: WebhookFormat;
26
+ description?: string | null;
27
+ };
28
+ export declare const WEBHOOK_EVENTS: readonly WebhookEvent[];
29
+ export type EnvpassOptions = {
30
+ baseUrl?: string;
31
+ token?: string;
32
+ userAgent?: string;
33
+ fetch?: typeof fetch;
34
+ };
35
+ export declare class EnvpassError extends Error {
36
+ readonly status: number;
37
+ readonly code?: string | undefined;
38
+ constructor(message: string, status: number, code?: string | undefined);
39
+ }
40
+ export declare function createEnvpass(options?: EnvpassOptions): {
41
+ url: string;
42
+ hasToken: boolean;
43
+ api: import("openapi-fetch").Client<paths, `${string}/${string}`>;
44
+ me(): Promise<{
45
+ actor: "user" | "token";
46
+ userId: string;
47
+ token: {
48
+ id: string;
49
+ workspaceId: string;
50
+ projectId: string;
51
+ access: "read" | "write";
52
+ } | null;
53
+ workspaces: {
54
+ id: string;
55
+ name: string;
56
+ slug: string;
57
+ isOwner: boolean;
58
+ }[];
59
+ }>;
60
+ resolve(scope?: ProjectLink): Promise<ResolvedEntry[]>;
61
+ resolveText(scope?: ProjectLink, format?: Exclude<ExportFormat, "json">): Promise<string>;
62
+ workspace(scope?: ProjectLink): Promise<Workspace>;
63
+ listEnvironments(scope?: ProjectLink): Promise<Environment[]>;
64
+ listWebhooks(scope?: ProjectLink): Promise<Webhook[]>;
65
+ createWebhook(input: NewWebhook, scope?: ProjectLink): Promise<{
66
+ webhook: Webhook;
67
+ secret: string;
68
+ }>;
69
+ deleteWebhook(id: string, scope?: ProjectLink): Promise<void>;
70
+ testWebhook(id: string, scope?: ProjectLink): Promise<WebhookTestResult>;
71
+ listWebhookDeliveries(id: string, options?: {
72
+ limit?: number;
73
+ before?: string;
74
+ }, scope?: ProjectLink): Promise<WebhookDelivery[]>;
75
+ listConnections(scope?: ProjectLink): Promise<Connection[]>;
76
+ listSyncs(scope?: ProjectLink): Promise<Sync[]>;
77
+ runSync(id: string, scope?: ProjectLink): Promise<void>;
78
+ setSyncEnabled(id: string, enabled: boolean, scope?: ProjectLink): Promise<void>;
79
+ };
80
+ export type Envpass = ReturnType<typeof createEnvpass>;
81
+ export declare function loadEnv(scope?: ProjectLink & EnvpassOptions & {
82
+ override?: boolean;
83
+ }): Promise<{
84
+ [k: string]: string;
85
+ }>;
86
+ export {};
package/dist/client.js ADDED
@@ -0,0 +1,219 @@
1
+ import createFetchClient from "openapi-fetch";
2
+ import { baseUrl, resolveScope, resolveToken } from "./config.js";
3
+ export const WEBHOOK_EVENTS = [
4
+ "secrets.changed",
5
+ "sync.succeeded",
6
+ "sync.failed",
7
+ ];
8
+ const DEFAULT_WEBHOOK_EVENTS = ["secrets.changed", "sync.failed"];
9
+ export class EnvpassError extends Error {
10
+ status;
11
+ code;
12
+ constructor(message, status, code) {
13
+ super(message);
14
+ this.status = status;
15
+ this.code = code;
16
+ this.name = "EnvpassError";
17
+ }
18
+ }
19
+ function errorFrom(status, body) {
20
+ const error = body?.error;
21
+ return new EnvpassError(error?.message ?? `Request failed with status ${status}`, status, error?.code);
22
+ }
23
+ function unwrap(result) {
24
+ if (result.data === undefined)
25
+ throw errorFrom(result.response.status, result.error);
26
+ return result.data;
27
+ }
28
+ function pickIds(items, refs, kind, workspace) {
29
+ return refs.map((ref) => {
30
+ const item = items.find((candidate) => candidate.slug === ref || candidate.id === ref);
31
+ if (!item)
32
+ throw new EnvpassError(`No ${kind} "${ref}" in ${workspace.slug}`, 404, "not_found");
33
+ return item.id;
34
+ });
35
+ }
36
+ export function createEnvpass(options = {}) {
37
+ const url = baseUrl(options.baseUrl);
38
+ const token = resolveToken(url, options.token);
39
+ const headers = { "user-agent": options.userAgent ?? "envpass-node" };
40
+ if (token)
41
+ headers.authorization = `Bearer ${token}`;
42
+ const fetcher = options.fetch ?? globalThis.fetch;
43
+ const api = createFetchClient({ baseUrl: url, headers, fetch: fetcher });
44
+ function scopeQuery(scope) {
45
+ if (!scope.environment) {
46
+ throw new EnvpassError("No environment. Pass --env, set ENVPASS_ENV, or run `envpass link`.", 400, "invalid");
47
+ }
48
+ return {
49
+ workspace: scope.workspace,
50
+ project: scope.project,
51
+ environment: scope.environment,
52
+ };
53
+ }
54
+ function requireUser() {
55
+ if (token?.startsWith("ep_")) {
56
+ throw new EnvpassError("Webhooks and syncs need a user login, not a service token. Run `envpass login` and unset ENVPASS_TOKEN.", 403, "forbidden");
57
+ }
58
+ }
59
+ async function workspaceFor(scope) {
60
+ requireUser();
61
+ const ref = resolveScope(scope).workspace;
62
+ const { workspaces } = unwrap(await api.GET("/api/v1/workspaces"));
63
+ if (ref) {
64
+ const match = workspaces.find((w) => w.slug === ref || w.id === ref);
65
+ if (!match)
66
+ throw new EnvpassError(`No workspace "${ref}" for this login`, 404, "not_found");
67
+ return match;
68
+ }
69
+ const [only] = workspaces;
70
+ if (only && workspaces.length === 1)
71
+ return only;
72
+ throw new EnvpassError("No workspace. Pass --workspace, set ENVPASS_WORKSPACE, or run `envpass link`.", 400, "invalid");
73
+ }
74
+ async function projectsOf(workspaceId) {
75
+ const path = { workspaceId };
76
+ return unwrap(await api.GET("/api/v1/workspaces/{workspaceId}/projects", { params: { path } }))
77
+ .projects;
78
+ }
79
+ async function environmentsOf(workspaceId) {
80
+ const path = { workspaceId };
81
+ return unwrap(await api.GET("/api/v1/workspaces/{workspaceId}/environments", { params: { path } })).environments;
82
+ }
83
+ async function projectFor(scope) {
84
+ const workspace = await workspaceFor(scope);
85
+ const ref = resolveScope(scope).project;
86
+ if (!ref) {
87
+ throw new EnvpassError("No project. Pass --project, set ENVPASS_PROJECT, or run `envpass link`.", 400, "invalid");
88
+ }
89
+ const [projectId = ref] = pickIds(await projectsOf(workspace.id), [ref], "project", workspace);
90
+ return { workspaceId: workspace.id, projectId };
91
+ }
92
+ async function webhookPath(webhookId, scope) {
93
+ return { workspaceId: (await workspaceFor(scope)).id, webhookId };
94
+ }
95
+ async function syncPath(syncId, scope) {
96
+ return { ...(await projectFor(scope)), syncId };
97
+ }
98
+ return {
99
+ url,
100
+ hasToken: Boolean(token),
101
+ api,
102
+ async me() {
103
+ const { data, error, response } = await api.GET("/api/v1/me");
104
+ if (!data)
105
+ throw errorFrom(response.status, error);
106
+ return data;
107
+ },
108
+ async resolve(scope = {}) {
109
+ const query = scopeQuery(resolveScope(scope));
110
+ const { data, error, response } = await api.GET("/api/v1/resolve", {
111
+ params: { query: { ...query, format: "json" } },
112
+ });
113
+ if (!data || typeof data === "string")
114
+ throw errorFrom(response.status, error);
115
+ return data.entries;
116
+ },
117
+ async resolveText(scope = {}, format = "dotenv") {
118
+ const query = scopeQuery(resolveScope(scope));
119
+ const response = await fetcher(`${url}/api/v1/resolve?${new URLSearchParams(Object.entries({ ...query, format }).filter((entry) => Boolean(entry[1])))}`, { headers });
120
+ const text = await response.text();
121
+ if (!response.ok) {
122
+ let body;
123
+ try {
124
+ body = JSON.parse(text);
125
+ }
126
+ catch {
127
+ body = undefined;
128
+ }
129
+ throw errorFrom(response.status, body);
130
+ }
131
+ return text;
132
+ },
133
+ async workspace(scope = {}) {
134
+ return workspaceFor(scope);
135
+ },
136
+ async listEnvironments(scope = {}) {
137
+ return environmentsOf((await workspaceFor(scope)).id);
138
+ },
139
+ async listWebhooks(scope = {}) {
140
+ const path = { workspaceId: (await workspaceFor(scope)).id };
141
+ return unwrap(await api.GET("/api/v1/workspaces/{workspaceId}/webhooks", { params: { path } })).webhooks;
142
+ },
143
+ async createWebhook(input, scope = {}) {
144
+ const workspace = await workspaceFor(scope);
145
+ const environments = input.environments ?? [];
146
+ const projects = input.projects ?? [];
147
+ const [environmentIds, projectIds] = await Promise.all([
148
+ environments.length
149
+ ? environmentsOf(workspace.id).then((all) => pickIds(all, environments, "environment", workspace))
150
+ : [],
151
+ projects.length
152
+ ? projectsOf(workspace.id).then((all) => pickIds(all, projects, "project", workspace))
153
+ : [],
154
+ ]);
155
+ return unwrap(await api.POST("/api/v1/workspaces/{workspaceId}/webhooks", {
156
+ params: { path: { workspaceId: workspace.id } },
157
+ body: {
158
+ url: input.url,
159
+ events: input.events?.length ? input.events : DEFAULT_WEBHOOK_EVENTS,
160
+ environmentIds,
161
+ projectIds,
162
+ format: input.format,
163
+ description: input.description,
164
+ },
165
+ }));
166
+ },
167
+ async deleteWebhook(id, scope = {}) {
168
+ const path = await webhookPath(id, scope);
169
+ unwrap(await api.DELETE("/api/v1/workspaces/{workspaceId}/webhooks/{webhookId}", {
170
+ params: { path },
171
+ }));
172
+ },
173
+ async testWebhook(id, scope = {}) {
174
+ const path = await webhookPath(id, scope);
175
+ return unwrap(await api.POST("/api/v1/workspaces/{workspaceId}/webhooks/{webhookId}/test", {
176
+ params: { path },
177
+ }));
178
+ },
179
+ async listWebhookDeliveries(id, options = {}, scope = {}) {
180
+ const path = await webhookPath(id, scope);
181
+ return unwrap(await api.GET("/api/v1/workspaces/{workspaceId}/webhooks/{webhookId}/deliveries", {
182
+ params: { path, query: options },
183
+ })).deliveries;
184
+ },
185
+ async listConnections(scope = {}) {
186
+ const path = { workspaceId: (await workspaceFor(scope)).id };
187
+ return unwrap(await api.GET("/api/v1/workspaces/{workspaceId}/connections", { params: { path } })).connections;
188
+ },
189
+ async listSyncs(scope = {}) {
190
+ const path = await projectFor(scope);
191
+ return unwrap(await api.GET("/api/v1/workspaces/{workspaceId}/projects/{projectId}/syncs", {
192
+ params: { path },
193
+ })).syncs;
194
+ },
195
+ async runSync(id, scope = {}) {
196
+ const path = await syncPath(id, scope);
197
+ unwrap(await api.POST("/api/v1/workspaces/{workspaceId}/projects/{projectId}/syncs/{syncId}/run", {
198
+ params: { path },
199
+ }));
200
+ },
201
+ async setSyncEnabled(id, enabled, scope = {}) {
202
+ const path = await syncPath(id, scope);
203
+ unwrap(await api.PATCH("/api/v1/workspaces/{workspaceId}/projects/{projectId}/syncs/{syncId}", {
204
+ params: { path },
205
+ body: { enabled },
206
+ }));
207
+ },
208
+ };
209
+ }
210
+ export async function loadEnv(scope = {}) {
211
+ const { baseUrl: url, token, userAgent, override = false, ...link } = scope;
212
+ const client = createEnvpass({ baseUrl: url, token, userAgent });
213
+ const entries = await client.resolve(link);
214
+ for (const entry of entries) {
215
+ if (override || process.env[entry.key] === undefined)
216
+ process.env[entry.key] = entry.value;
217
+ }
218
+ return Object.fromEntries(entries.map((entry) => [entry.key, entry.value]));
219
+ }
@@ -0,0 +1,13 @@
1
+ export declare const DEFAULT_URL = "https://envpass.dev";
2
+ export type ProjectLink = {
3
+ workspace?: string;
4
+ project?: string;
5
+ environment?: string;
6
+ };
7
+ export declare function baseUrl(explicit?: string): string;
8
+ export declare function saveToken(url: string, token: string): string;
9
+ export declare function forgetToken(url: string): boolean;
10
+ export declare function storedToken(url: string): string | undefined;
11
+ export declare function resolveToken(url: string, explicit?: string): string | undefined;
12
+ export declare function writeProjectLink(link: ProjectLink, dir?: string): string;
13
+ export declare function resolveScope(flags: ProjectLink, start?: string): ProjectLink;