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