@barekey/cli 0.4.0 → 0.5.1
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 +53 -12
- package/bun.lock +9 -3
- package/dist/auth-provider.js +7 -4
- package/dist/command-utils.js +6 -6
- package/dist/commands/audit.d.ts +2 -0
- package/dist/commands/audit.js +47 -0
- package/dist/commands/auth.js +31 -9
- package/dist/commands/billing.d.ts +2 -0
- package/dist/commands/billing.js +59 -0
- package/dist/commands/env.js +157 -125
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +32 -0
- package/dist/commands/org.d.ts +2 -0
- package/dist/commands/org.js +85 -0
- package/dist/commands/project.d.ts +2 -0
- package/dist/commands/project.js +99 -0
- package/dist/commands/stage.d.ts +2 -0
- package/dist/commands/stage.js +125 -0
- package/dist/commands/target-prompts.d.ts +184 -0
- package/dist/commands/target-prompts.js +312 -0
- package/dist/commands/typegen.d.ts +2 -2
- package/dist/commands/typegen.js +57 -32
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/context/session-id.d.ts +11 -0
- package/dist/context/session-id.js +14 -0
- package/dist/contracts/index.d.ts +499 -0
- package/dist/contracts/index.js +313 -0
- package/dist/credentials-store.js +70 -11
- package/dist/http.d.ts +34 -0
- package/dist/http.js +56 -2
- package/dist/index.js +12 -0
- package/dist/runtime-config.js +14 -26
- package/dist/typegen/core.d.ts +45 -0
- package/dist/typegen/core.js +219 -0
- package/dist/types.d.ts +5 -3
- package/package.json +2 -2
- package/src/auth-provider.ts +8 -5
- package/src/command-utils.ts +6 -6
- package/src/commands/audit.ts +63 -0
- package/src/commands/auth.ts +45 -39
- package/src/commands/billing.ts +70 -0
- package/src/commands/env.ts +211 -218
- package/src/commands/init.ts +47 -0
- package/src/commands/org.ts +104 -0
- package/src/commands/project.ts +130 -0
- package/src/commands/stage.ts +167 -0
- package/src/commands/target-prompts.ts +357 -0
- package/src/commands/typegen.ts +71 -45
- package/src/constants.ts +1 -1
- package/src/context/session-id.ts +14 -0
- package/src/contracts/index.ts +376 -0
- package/src/credentials-store.ts +86 -12
- package/src/http.ts +78 -2
- package/src/index.ts +12 -0
- package/src/runtime-config.ts +19 -32
- package/src/typegen/core.ts +311 -0
- package/src/types.ts +5 -3
- package/test/command-utils.test.ts +47 -0
- package/test/credentials-store.test.ts +40 -0
package/src/commands/env.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { writeFile } from "node:fs/promises";
|
|
2
2
|
|
|
3
|
-
import { cancel, confirm, isCancel } from "@clack/prompts";
|
|
4
|
-
import { BarekeyClient } from "@barekey/sdk/server";
|
|
5
|
-
import type { BarekeyJsonConfig } from "@barekey/sdk/server";
|
|
3
|
+
import { cancel, confirm, isCancel, select, text } from "@clack/prompts";
|
|
6
4
|
import { Command } from "commander";
|
|
7
|
-
import pc from "picocolors";
|
|
8
5
|
|
|
9
6
|
import { createCliAuthProvider } from "../auth-provider.js";
|
|
10
7
|
import {
|
|
@@ -16,8 +13,14 @@ import {
|
|
|
16
13
|
toJsonOutput,
|
|
17
14
|
type EnvTargetOptions,
|
|
18
15
|
} from "../command-utils.js";
|
|
16
|
+
import {
|
|
17
|
+
EnvEvaluateBatchResponseSchema,
|
|
18
|
+
EnvEvaluateResponseSchema,
|
|
19
|
+
EnvListResponseSchema,
|
|
20
|
+
EnvPullResponseSchema,
|
|
21
|
+
EnvWriteResponseSchema,
|
|
22
|
+
} from "../contracts/index.js";
|
|
19
23
|
import { postJson } from "../http.js";
|
|
20
|
-
import { loadRuntimeConfig } from "../runtime-config.js";
|
|
21
24
|
import {
|
|
22
25
|
collectOptionValues,
|
|
23
26
|
parseRolloutFunction,
|
|
@@ -27,147 +30,184 @@ import {
|
|
|
27
30
|
type CliVisibility,
|
|
28
31
|
} from "./env-helpers.js";
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
type EnvWriteOptions = EnvTargetOptions & {
|
|
34
|
+
ab?: string;
|
|
35
|
+
rollout?: string;
|
|
36
|
+
function?: string;
|
|
37
|
+
point?: Array<string>;
|
|
38
|
+
chance?: string;
|
|
39
|
+
visibility?: CliVisibility;
|
|
40
|
+
type?: "string" | "boolean" | "int64" | "float" | "date" | "json";
|
|
41
|
+
json?: boolean;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
async function resolveEnvAccess(options: EnvTargetOptions) {
|
|
45
|
+
const local = await requireLocalSession();
|
|
46
|
+
const target = await resolveTarget(options, local);
|
|
47
|
+
const authProvider = createCliAuthProvider();
|
|
48
|
+
const accessToken = await authProvider.getAccessToken();
|
|
49
|
+
return {
|
|
50
|
+
local,
|
|
51
|
+
target,
|
|
52
|
+
accessToken,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
42
55
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
: {
|
|
50
|
-
config: {
|
|
51
|
-
typegen: input.runtimeConfig.config.config.typegen,
|
|
52
|
-
mode: input.runtimeConfig.config.config.mode,
|
|
53
|
-
},
|
|
54
|
-
}),
|
|
55
|
-
};
|
|
56
|
+
function renderScalar(value: unknown): string {
|
|
57
|
+
if (typeof value === "string") {
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
return JSON.stringify(value);
|
|
61
|
+
}
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
async function promptForRequiredText(
|
|
64
|
+
currentValue: string | undefined,
|
|
65
|
+
message: string,
|
|
66
|
+
): Promise<string> {
|
|
67
|
+
const existing = currentValue?.trim();
|
|
68
|
+
if (existing && existing.length > 0) {
|
|
69
|
+
return existing;
|
|
70
|
+
}
|
|
71
|
+
if (!process.stdout.isTTY) {
|
|
72
|
+
throw new Error(`${message} is required in non-interactive mode.`);
|
|
60
73
|
}
|
|
61
74
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
75
|
+
const prompted = await text({
|
|
76
|
+
message,
|
|
77
|
+
validate(value) {
|
|
78
|
+
return value.trim().length > 0 ? undefined : "This value is required.";
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
if (isCancel(prompted)) {
|
|
82
|
+
cancel("Command canceled.");
|
|
83
|
+
process.exit(0);
|
|
65
84
|
}
|
|
85
|
+
return prompted.trim();
|
|
86
|
+
}
|
|
66
87
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
88
|
+
async function maybePromptVariant(writeOptions: EnvWriteOptions): Promise<EnvWriteOptions> {
|
|
89
|
+
if (writeOptions.ab !== undefined || writeOptions.rollout !== undefined || !process.stdout.isTTY) {
|
|
90
|
+
return writeOptions;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const selectedKind = await select({
|
|
94
|
+
message: "What kind of variable is this?",
|
|
95
|
+
options: [
|
|
96
|
+
{ value: "secret", label: "Secret", hint: "One stored value" },
|
|
97
|
+
{ value: "ab_roll", label: "A/B roll", hint: "Two values plus traffic split" },
|
|
98
|
+
{ value: "rollout", label: "Rollout", hint: "Two values plus rollout milestones" },
|
|
99
|
+
],
|
|
100
|
+
initialValue: "secret",
|
|
71
101
|
});
|
|
102
|
+
if (isCancel(selectedKind)) {
|
|
103
|
+
cancel("Command canceled.");
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (selectedKind === "ab_roll") {
|
|
108
|
+
const valueB = await promptForRequiredText(undefined, "What's the alternate value?");
|
|
109
|
+
const chance = await promptForRequiredText(
|
|
110
|
+
writeOptions.chance,
|
|
111
|
+
"What's the A-branch probability between 0 and 1?",
|
|
112
|
+
);
|
|
113
|
+
return {
|
|
114
|
+
...writeOptions,
|
|
115
|
+
ab: valueB,
|
|
116
|
+
chance,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (selectedKind === "rollout") {
|
|
121
|
+
const valueB = await promptForRequiredText(undefined, "What's the rollout value B?");
|
|
122
|
+
return {
|
|
123
|
+
...writeOptions,
|
|
124
|
+
rollout: valueB,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return writeOptions;
|
|
72
129
|
}
|
|
73
130
|
|
|
74
131
|
async function runEnvGet(
|
|
75
|
-
name: string,
|
|
132
|
+
name: string | undefined,
|
|
76
133
|
options: EnvTargetOptions & {
|
|
77
134
|
seed?: string;
|
|
78
135
|
key?: string;
|
|
79
136
|
json?: boolean;
|
|
80
137
|
},
|
|
81
138
|
): Promise<void> {
|
|
82
|
-
const
|
|
83
|
-
const local
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
139
|
+
const resolvedName = await promptForRequiredText(name, "What's the name of this variable?");
|
|
140
|
+
const { local, target, accessToken } = await resolveEnvAccess(options);
|
|
141
|
+
const value = await postJson({
|
|
142
|
+
baseUrl: local.baseUrl,
|
|
143
|
+
path: "/v1/env/evaluate",
|
|
144
|
+
accessToken,
|
|
145
|
+
payload: {
|
|
146
|
+
orgSlug: target.orgSlug,
|
|
147
|
+
projectSlug: target.projectSlug,
|
|
148
|
+
stageSlug: target.stageSlug,
|
|
149
|
+
name: resolvedName,
|
|
150
|
+
seed: options.seed,
|
|
151
|
+
key: options.key,
|
|
152
|
+
},
|
|
153
|
+
schema: EnvEvaluateResponseSchema,
|
|
94
154
|
});
|
|
95
155
|
|
|
96
156
|
if (options.json) {
|
|
97
|
-
toJsonOutput(true,
|
|
98
|
-
name,
|
|
99
|
-
value,
|
|
100
|
-
});
|
|
157
|
+
toJsonOutput(true, value);
|
|
101
158
|
return;
|
|
102
159
|
}
|
|
103
160
|
|
|
104
|
-
console.log(
|
|
161
|
+
console.log(renderScalar(value.value));
|
|
105
162
|
}
|
|
106
163
|
|
|
107
164
|
async function runEnvGetMany(
|
|
108
165
|
options: EnvTargetOptions & {
|
|
109
|
-
names
|
|
166
|
+
names?: string;
|
|
110
167
|
seed?: string;
|
|
111
168
|
key?: string;
|
|
112
169
|
json?: boolean;
|
|
113
170
|
},
|
|
114
171
|
): Promise<void> {
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
project: target.projectSlug,
|
|
121
|
-
environment: target.stageSlug,
|
|
122
|
-
runtimeConfig: runtime,
|
|
123
|
-
});
|
|
172
|
+
const namesCsv = await promptForRequiredText(
|
|
173
|
+
options.names,
|
|
174
|
+
"Which variable names do you want, comma-separated?",
|
|
175
|
+
);
|
|
176
|
+
const { local, target, accessToken } = await resolveEnvAccess(options);
|
|
124
177
|
|
|
125
|
-
const names =
|
|
178
|
+
const names = namesCsv
|
|
126
179
|
.split(",")
|
|
127
180
|
.map((value) => value.trim())
|
|
128
181
|
.filter((value) => value.length > 0);
|
|
129
182
|
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
183
|
+
const response = await postJson({
|
|
184
|
+
baseUrl: local.baseUrl,
|
|
185
|
+
path: "/v1/env/evaluate-batch",
|
|
186
|
+
accessToken,
|
|
187
|
+
payload: {
|
|
188
|
+
orgSlug: target.orgSlug,
|
|
189
|
+
projectSlug: target.projectSlug,
|
|
190
|
+
stageSlug: target.stageSlug,
|
|
191
|
+
names,
|
|
192
|
+
seed: options.seed,
|
|
193
|
+
key: options.key,
|
|
194
|
+
},
|
|
195
|
+
schema: EnvEvaluateBatchResponseSchema,
|
|
196
|
+
});
|
|
139
197
|
|
|
140
198
|
if (options.json) {
|
|
141
|
-
toJsonOutput(true,
|
|
199
|
+
toJsonOutput(true, response.values);
|
|
142
200
|
return;
|
|
143
201
|
}
|
|
144
202
|
|
|
145
|
-
for (const value of
|
|
146
|
-
|
|
147
|
-
console.log(`${value.name}=${String(value.value)}`);
|
|
148
|
-
}
|
|
203
|
+
for (const value of [...response.values].sort((left, right) => left.name.localeCompare(right.name))) {
|
|
204
|
+
console.log(`${value.name}=${renderScalar(value.value)}`);
|
|
149
205
|
}
|
|
150
206
|
}
|
|
151
207
|
|
|
152
208
|
async function runEnvList(options: EnvTargetOptions & { json?: boolean }): Promise<void> {
|
|
153
|
-
const local = await
|
|
154
|
-
const
|
|
155
|
-
const authProvider = createCliAuthProvider();
|
|
156
|
-
const accessToken = await authProvider.getAccessToken();
|
|
157
|
-
|
|
158
|
-
const response = await postJson<{
|
|
159
|
-
variables: Array<{
|
|
160
|
-
name: string;
|
|
161
|
-
visibility: CliVisibility;
|
|
162
|
-
kind: "secret" | "ab_roll" | "rollout";
|
|
163
|
-
declaredType: "string" | "boolean" | "int64" | "float" | "date" | "json";
|
|
164
|
-
createdAtMs: number;
|
|
165
|
-
updatedAtMs: number;
|
|
166
|
-
chance: number | null;
|
|
167
|
-
rolloutFunction: CliRolloutFunction | null;
|
|
168
|
-
rolloutMilestones: Array<{ at: string; percentage: number }> | null;
|
|
169
|
-
}>;
|
|
170
|
-
}>({
|
|
209
|
+
const { local, target, accessToken } = await resolveEnvAccess(options);
|
|
210
|
+
const response = await postJson({
|
|
171
211
|
baseUrl: local.baseUrl,
|
|
172
212
|
path: "/v1/env/list",
|
|
173
213
|
accessToken,
|
|
@@ -176,6 +216,7 @@ async function runEnvList(options: EnvTargetOptions & { json?: boolean }): Promi
|
|
|
176
216
|
projectSlug: target.projectSlug,
|
|
177
217
|
stageSlug: target.stageSlug,
|
|
178
218
|
},
|
|
219
|
+
schema: EnvListResponseSchema,
|
|
179
220
|
});
|
|
180
221
|
|
|
181
222
|
if (options.json) {
|
|
@@ -192,85 +233,73 @@ async function runEnvList(options: EnvTargetOptions & { json?: boolean }): Promi
|
|
|
192
233
|
const chanceSuffix = row.kind === "ab_roll" ? ` chance=${row.chance ?? 0}` : "";
|
|
193
234
|
const rolloutSuffix =
|
|
194
235
|
row.kind === "rollout"
|
|
195
|
-
? ` ${
|
|
196
|
-
`${row.rolloutFunction ?? "linear"}(${row.rolloutMilestones?.length ?? 0} milestones)`,
|
|
197
|
-
)}`
|
|
236
|
+
? ` ${row.rolloutFunction ?? "linear"}(${row.rolloutMilestones?.length ?? 0} milestones)`
|
|
198
237
|
: "";
|
|
199
238
|
console.log(
|
|
200
|
-
`${row.name} ${
|
|
239
|
+
`${row.name} ${row.visibility} ${row.kind} ${row.declaredType}${chanceSuffix}${rolloutSuffix}`,
|
|
201
240
|
);
|
|
202
241
|
}
|
|
203
242
|
}
|
|
204
243
|
|
|
205
244
|
async function runEnvWrite(
|
|
206
245
|
operation: "create_only" | "upsert",
|
|
207
|
-
name: string,
|
|
208
|
-
value: string,
|
|
209
|
-
options:
|
|
210
|
-
ab?: string;
|
|
211
|
-
rollout?: string;
|
|
212
|
-
function?: string;
|
|
213
|
-
point?: Array<string>;
|
|
214
|
-
chance?: string;
|
|
215
|
-
visibility?: CliVisibility;
|
|
216
|
-
type?: "string" | "boolean" | "int64" | "float" | "date" | "json";
|
|
217
|
-
json?: boolean;
|
|
218
|
-
},
|
|
246
|
+
name: string | undefined,
|
|
247
|
+
value: string | undefined,
|
|
248
|
+
options: EnvWriteOptions,
|
|
219
249
|
): Promise<void> {
|
|
220
|
-
const
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
const accessToken = await
|
|
250
|
+
const resolvedName = await promptForRequiredText(name, "What's the name of this variable?");
|
|
251
|
+
const resolvedValue = await promptForRequiredText(value, "What's the value of this variable?");
|
|
252
|
+
const resolvedOptions = await maybePromptVariant(options);
|
|
253
|
+
const { local, target, accessToken } = await resolveEnvAccess(resolvedOptions);
|
|
224
254
|
|
|
225
|
-
if (
|
|
255
|
+
if (resolvedOptions.ab !== undefined && resolvedOptions.rollout !== undefined) {
|
|
226
256
|
throw new Error("Use either --ab or --rollout, not both.");
|
|
227
257
|
}
|
|
228
|
-
const hasRolloutPoints = (
|
|
229
|
-
if (
|
|
258
|
+
const hasRolloutPoints = (resolvedOptions.point?.length ?? 0) > 0;
|
|
259
|
+
if (
|
|
260
|
+
resolvedOptions.rollout === undefined &&
|
|
261
|
+
(resolvedOptions.function !== undefined || hasRolloutPoints)
|
|
262
|
+
) {
|
|
230
263
|
throw new Error("--function and --point can only be used together with --rollout.");
|
|
231
264
|
}
|
|
232
|
-
if (
|
|
265
|
+
if (resolvedOptions.ab !== undefined && (resolvedOptions.function !== undefined || hasRolloutPoints)) {
|
|
233
266
|
throw new Error("--function and --point are only supported for --rollout, not --ab.");
|
|
234
267
|
}
|
|
235
|
-
if (
|
|
268
|
+
if (resolvedOptions.rollout !== undefined && resolvedOptions.chance !== undefined) {
|
|
236
269
|
throw new Error("--chance only applies to --ab.");
|
|
237
270
|
}
|
|
238
271
|
|
|
239
272
|
const entry =
|
|
240
|
-
|
|
273
|
+
resolvedOptions.rollout !== undefined
|
|
241
274
|
? {
|
|
242
|
-
name,
|
|
243
|
-
visibility: parseVisibility(
|
|
275
|
+
name: resolvedName,
|
|
276
|
+
visibility: parseVisibility(resolvedOptions.visibility),
|
|
244
277
|
kind: "rollout" as const,
|
|
245
|
-
declaredType:
|
|
246
|
-
valueA:
|
|
247
|
-
valueB:
|
|
248
|
-
rolloutFunction: parseRolloutFunction(
|
|
249
|
-
rolloutMilestones: parseRolloutMilestones(
|
|
278
|
+
declaredType: resolvedOptions.type ?? "string",
|
|
279
|
+
valueA: resolvedValue,
|
|
280
|
+
valueB: resolvedOptions.rollout,
|
|
281
|
+
rolloutFunction: parseRolloutFunction(resolvedOptions.function),
|
|
282
|
+
rolloutMilestones: parseRolloutMilestones(resolvedOptions.point),
|
|
250
283
|
}
|
|
251
|
-
:
|
|
284
|
+
: resolvedOptions.ab !== undefined
|
|
252
285
|
? {
|
|
253
|
-
name,
|
|
254
|
-
visibility: parseVisibility(
|
|
286
|
+
name: resolvedName,
|
|
287
|
+
visibility: parseVisibility(resolvedOptions.visibility),
|
|
255
288
|
kind: "ab_roll" as const,
|
|
256
|
-
declaredType:
|
|
257
|
-
valueA:
|
|
258
|
-
valueB:
|
|
259
|
-
chance: parseChance(
|
|
289
|
+
declaredType: resolvedOptions.type ?? "string",
|
|
290
|
+
valueA: resolvedValue,
|
|
291
|
+
valueB: resolvedOptions.ab,
|
|
292
|
+
chance: parseChance(resolvedOptions.chance),
|
|
260
293
|
}
|
|
261
294
|
: {
|
|
262
|
-
name,
|
|
263
|
-
visibility: parseVisibility(
|
|
295
|
+
name: resolvedName,
|
|
296
|
+
visibility: parseVisibility(resolvedOptions.visibility),
|
|
264
297
|
kind: "secret" as const,
|
|
265
|
-
declaredType:
|
|
266
|
-
value,
|
|
298
|
+
declaredType: resolvedOptions.type ?? "string",
|
|
299
|
+
value: resolvedValue,
|
|
267
300
|
};
|
|
268
301
|
|
|
269
|
-
const result = await postJson
|
|
270
|
-
createdCount: number;
|
|
271
|
-
updatedCount: number;
|
|
272
|
-
deletedCount: number;
|
|
273
|
-
}>({
|
|
302
|
+
const result = await postJson({
|
|
274
303
|
baseUrl: local.baseUrl,
|
|
275
304
|
path: "/v1/env/write",
|
|
276
305
|
accessToken,
|
|
@@ -282,9 +311,10 @@ async function runEnvWrite(
|
|
|
282
311
|
entries: [entry],
|
|
283
312
|
deletes: [],
|
|
284
313
|
},
|
|
314
|
+
schema: EnvWriteResponseSchema,
|
|
285
315
|
});
|
|
286
316
|
|
|
287
|
-
if (
|
|
317
|
+
if (resolvedOptions.json) {
|
|
288
318
|
toJsonOutput(true, result);
|
|
289
319
|
return;
|
|
290
320
|
}
|
|
@@ -295,24 +325,18 @@ async function runEnvWrite(
|
|
|
295
325
|
}
|
|
296
326
|
|
|
297
327
|
async function runEnvDelete(
|
|
298
|
-
name: string,
|
|
328
|
+
name: string | undefined,
|
|
299
329
|
options: EnvTargetOptions & {
|
|
300
330
|
yes?: boolean;
|
|
301
331
|
ignoreMissing?: boolean;
|
|
302
332
|
json?: boolean;
|
|
303
333
|
},
|
|
304
334
|
): Promise<void> {
|
|
305
|
-
const
|
|
306
|
-
const target = await
|
|
307
|
-
const authProvider = createCliAuthProvider();
|
|
308
|
-
const accessToken = await authProvider.getAccessToken();
|
|
335
|
+
const resolvedName = await promptForRequiredText(name, "What's the name of the variable to delete?");
|
|
336
|
+
const { local, target, accessToken } = await resolveEnvAccess(options);
|
|
309
337
|
|
|
310
338
|
if (!options.ignoreMissing) {
|
|
311
|
-
const listed = await postJson
|
|
312
|
-
variables: Array<{
|
|
313
|
-
name: string;
|
|
314
|
-
}>;
|
|
315
|
-
}>({
|
|
339
|
+
const listed = await postJson({
|
|
316
340
|
baseUrl: local.baseUrl,
|
|
317
341
|
path: "/v1/env/list",
|
|
318
342
|
accessToken,
|
|
@@ -321,10 +345,11 @@ async function runEnvDelete(
|
|
|
321
345
|
projectSlug: target.projectSlug,
|
|
322
346
|
stageSlug: target.stageSlug,
|
|
323
347
|
},
|
|
348
|
+
schema: EnvListResponseSchema,
|
|
324
349
|
});
|
|
325
|
-
const exists = listed.variables.some((row) => row.name ===
|
|
350
|
+
const exists = listed.variables.some((row) => row.name === resolvedName);
|
|
326
351
|
if (!exists) {
|
|
327
|
-
throw new Error(`Variable ${
|
|
352
|
+
throw new Error(`Variable ${resolvedName} was not found in this stage.`);
|
|
328
353
|
}
|
|
329
354
|
}
|
|
330
355
|
|
|
@@ -333,7 +358,7 @@ async function runEnvDelete(
|
|
|
333
358
|
throw new Error("Deletion requires --yes in non-interactive mode.");
|
|
334
359
|
}
|
|
335
360
|
const confirmed = await confirm({
|
|
336
|
-
message: `Delete variable ${
|
|
361
|
+
message: `Delete variable ${resolvedName}?`,
|
|
337
362
|
initialValue: false,
|
|
338
363
|
});
|
|
339
364
|
if (isCancel(confirmed)) {
|
|
@@ -345,11 +370,7 @@ async function runEnvDelete(
|
|
|
345
370
|
}
|
|
346
371
|
}
|
|
347
372
|
|
|
348
|
-
const result = await postJson
|
|
349
|
-
createdCount: number;
|
|
350
|
-
updatedCount: number;
|
|
351
|
-
deletedCount: number;
|
|
352
|
-
}>({
|
|
373
|
+
const result = await postJson({
|
|
353
374
|
baseUrl: local.baseUrl,
|
|
354
375
|
path: "/v1/env/write",
|
|
355
376
|
accessToken,
|
|
@@ -359,8 +380,9 @@ async function runEnvDelete(
|
|
|
359
380
|
stageSlug: target.stageSlug,
|
|
360
381
|
mode: "upsert",
|
|
361
382
|
entries: [],
|
|
362
|
-
deletes: [
|
|
383
|
+
deletes: [resolvedName],
|
|
363
384
|
},
|
|
385
|
+
schema: EnvWriteResponseSchema,
|
|
364
386
|
});
|
|
365
387
|
|
|
366
388
|
if (options.json) {
|
|
@@ -380,20 +402,8 @@ async function runEnvPull(
|
|
|
380
402
|
redact?: boolean;
|
|
381
403
|
},
|
|
382
404
|
): Promise<void> {
|
|
383
|
-
const local = await
|
|
384
|
-
const
|
|
385
|
-
const authProvider = createCliAuthProvider();
|
|
386
|
-
const accessToken = await authProvider.getAccessToken();
|
|
387
|
-
|
|
388
|
-
const response = await postJson<{
|
|
389
|
-
values: Array<{
|
|
390
|
-
name: string;
|
|
391
|
-
kind: "secret" | "ab_roll" | "rollout";
|
|
392
|
-
declaredType: "string" | "boolean" | "int64" | "float" | "date" | "json";
|
|
393
|
-
value: string;
|
|
394
|
-
}>;
|
|
395
|
-
byName: Record<string, string>;
|
|
396
|
-
}>({
|
|
405
|
+
const { local, target, accessToken } = await resolveEnvAccess(options);
|
|
406
|
+
const response = await postJson({
|
|
397
407
|
baseUrl: local.baseUrl,
|
|
398
408
|
path: "/v1/env/pull",
|
|
399
409
|
accessToken,
|
|
@@ -404,6 +414,7 @@ async function runEnvPull(
|
|
|
404
414
|
seed: options.seed,
|
|
405
415
|
key: options.key,
|
|
406
416
|
},
|
|
417
|
+
schema: EnvPullResponseSchema,
|
|
407
418
|
});
|
|
408
419
|
|
|
409
420
|
const format = options.format ?? "dotenv";
|
|
@@ -434,13 +445,13 @@ export function registerEnvCommands(program: Command): void {
|
|
|
434
445
|
env
|
|
435
446
|
.command("get")
|
|
436
447
|
.description("Evaluate one variable")
|
|
437
|
-
.argument("
|
|
448
|
+
.argument("[name]", "Variable name")
|
|
438
449
|
.option("--seed <value>", "Deterministic seed")
|
|
439
450
|
.option("--key <value>", "Deterministic key")
|
|
440
451
|
.option("--json", "Machine-readable output", false),
|
|
441
452
|
).action(
|
|
442
453
|
async (
|
|
443
|
-
name: string,
|
|
454
|
+
name: string | undefined,
|
|
444
455
|
options: EnvTargetOptions & { seed?: string; key?: string; json?: boolean },
|
|
445
456
|
) => {
|
|
446
457
|
await runEnvGet(name, options);
|
|
@@ -451,14 +462,14 @@ export function registerEnvCommands(program: Command): void {
|
|
|
451
462
|
env
|
|
452
463
|
.command("get-many")
|
|
453
464
|
.description("Evaluate a batch of variables")
|
|
454
|
-
.
|
|
465
|
+
.option("--names <csv>", "Comma-separated variable names")
|
|
455
466
|
.option("--seed <value>", "Deterministic seed")
|
|
456
467
|
.option("--key <value>", "Deterministic key")
|
|
457
468
|
.option("--json", "Machine-readable output", false),
|
|
458
469
|
).action(
|
|
459
470
|
async (
|
|
460
471
|
options: EnvTargetOptions & {
|
|
461
|
-
names
|
|
472
|
+
names?: string;
|
|
462
473
|
seed?: string;
|
|
463
474
|
key?: string;
|
|
464
475
|
json?: boolean;
|
|
@@ -481,8 +492,8 @@ export function registerEnvCommands(program: Command): void {
|
|
|
481
492
|
env
|
|
482
493
|
.command("new")
|
|
483
494
|
.description("Create one variable")
|
|
484
|
-
.argument("
|
|
485
|
-
.argument("
|
|
495
|
+
.argument("[name]", "Variable name")
|
|
496
|
+
.argument("[value]", "Variable value")
|
|
486
497
|
.option("--ab <value-b>", "Second value for ab_roll")
|
|
487
498
|
.option("--rollout <value-b>", "Second value for rollout")
|
|
488
499
|
.option("--chance <number>", "A-branch probability between 0 and 1")
|
|
@@ -501,18 +512,9 @@ export function registerEnvCommands(program: Command): void {
|
|
|
501
512
|
.option("--json", "Machine-readable output", false),
|
|
502
513
|
).action(
|
|
503
514
|
async (
|
|
504
|
-
name: string,
|
|
505
|
-
value: string,
|
|
506
|
-
options:
|
|
507
|
-
ab?: string;
|
|
508
|
-
rollout?: string;
|
|
509
|
-
function?: string;
|
|
510
|
-
point?: Array<string>;
|
|
511
|
-
chance?: string;
|
|
512
|
-
visibility?: CliVisibility;
|
|
513
|
-
type?: "string" | "boolean" | "int64" | "float" | "date" | "json";
|
|
514
|
-
json?: boolean;
|
|
515
|
-
},
|
|
515
|
+
name: string | undefined,
|
|
516
|
+
value: string | undefined,
|
|
517
|
+
options: EnvWriteOptions,
|
|
516
518
|
) => {
|
|
517
519
|
await runEnvWrite("create_only", name, value, options);
|
|
518
520
|
},
|
|
@@ -522,8 +524,8 @@ export function registerEnvCommands(program: Command): void {
|
|
|
522
524
|
env
|
|
523
525
|
.command("set")
|
|
524
526
|
.description("Upsert one variable")
|
|
525
|
-
.argument("
|
|
526
|
-
.argument("
|
|
527
|
+
.argument("[name]", "Variable name")
|
|
528
|
+
.argument("[value]", "Variable value")
|
|
527
529
|
.option("--ab <value-b>", "Second value for ab_roll")
|
|
528
530
|
.option("--rollout <value-b>", "Second value for rollout")
|
|
529
531
|
.option("--chance <number>", "A-branch probability between 0 and 1")
|
|
@@ -542,18 +544,9 @@ export function registerEnvCommands(program: Command): void {
|
|
|
542
544
|
.option("--json", "Machine-readable output", false),
|
|
543
545
|
).action(
|
|
544
546
|
async (
|
|
545
|
-
name: string,
|
|
546
|
-
value: string,
|
|
547
|
-
options:
|
|
548
|
-
ab?: string;
|
|
549
|
-
rollout?: string;
|
|
550
|
-
function?: string;
|
|
551
|
-
point?: Array<string>;
|
|
552
|
-
chance?: string;
|
|
553
|
-
visibility?: CliVisibility;
|
|
554
|
-
type?: "string" | "boolean" | "int64" | "float" | "date" | "json";
|
|
555
|
-
json?: boolean;
|
|
556
|
-
},
|
|
547
|
+
name: string | undefined,
|
|
548
|
+
value: string | undefined,
|
|
549
|
+
options: EnvWriteOptions,
|
|
557
550
|
) => {
|
|
558
551
|
await runEnvWrite("upsert", name, value, options);
|
|
559
552
|
},
|
|
@@ -563,13 +556,13 @@ export function registerEnvCommands(program: Command): void {
|
|
|
563
556
|
env
|
|
564
557
|
.command("delete")
|
|
565
558
|
.description("Delete one variable")
|
|
566
|
-
.argument("
|
|
559
|
+
.argument("[name]", "Variable name")
|
|
567
560
|
.option("--yes", "Skip confirmation", false)
|
|
568
561
|
.option("--ignore-missing", "Do not fail when variable is missing", false)
|
|
569
562
|
.option("--json", "Machine-readable output", false),
|
|
570
563
|
).action(
|
|
571
564
|
async (
|
|
572
|
-
name: string,
|
|
565
|
+
name: string | undefined,
|
|
573
566
|
options: EnvTargetOptions & { yes?: boolean; ignoreMissing?: boolean; json?: boolean },
|
|
574
567
|
) => {
|
|
575
568
|
await runEnvDelete(name, options);
|