@primitivedotdev/cli 0.26.2 → 0.26.3
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/dist/oclif/index.js +12554 -178
- package/dist/oclif/proxy-auto-detect.js +38 -57
- package/package.json +7 -9
- package/dist/oclif/api-command.js +0 -799
- package/dist/oclif/auth.js +0 -223
- package/dist/oclif/commands/doctor.js +0 -361
- package/dist/oclif/commands/emails-latest.js +0 -184
- package/dist/oclif/commands/emails-poll.js +0 -121
- package/dist/oclif/commands/emails-wait.js +0 -171
- package/dist/oclif/commands/emails-watch.js +0 -165
- package/dist/oclif/commands/functions-deploy.js +0 -302
- package/dist/oclif/commands/functions-init.js +0 -374
- package/dist/oclif/commands/functions-redeploy.js +0 -240
- package/dist/oclif/commands/functions-set-secret.js +0 -212
- package/dist/oclif/commands/functions-test-function.js +0 -238
- package/dist/oclif/commands/login.js +0 -236
- package/dist/oclif/commands/logout.js +0 -87
- package/dist/oclif/commands/send.js +0 -221
- package/dist/oclif/commands/whoami.js +0 -94
- package/dist/oclif/endpoints-test-redirect.js +0 -94
- package/dist/oclif/fish-completion.js +0 -87
- package/dist/oclif/lint/raw-send-mail-fetch.js +0 -98
- package/dist/oclif/secret-flags.js +0 -59
- package/oclif.manifest.json +0 -4462
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import { Command, Flags } from "@oclif/core";
|
|
2
|
-
import { PrimitiveApiClient, setFunctionSecret, updateFunction, } from "@primitivedotdev/sdk/api";
|
|
3
|
-
import { extractErrorPayload, readTextFileFlag, removeStaleSavedCredentialOnUnauthorized, runWithTiming, TIME_FLAG_DESCRIPTION, writeErrorWithHints, } from "../api-command.js";
|
|
4
|
-
import { resolveCliAuth } from "../auth.js";
|
|
5
|
-
import { emitRawSendMailFetchWarning } from "../lint/raw-send-mail-fetch.js";
|
|
6
|
-
import { parseSecretFlags, SECRET_FLAG_SECURITY_NOTE, } from "../secret-flags.js";
|
|
7
|
-
// Pure-ish orchestration of (optional secrets +) update-function.
|
|
8
|
-
// Writes every secret first, then re-deploys with the new bundle so
|
|
9
|
-
// a single updateFunction call refreshes every binding the user
|
|
10
|
-
// wrote. Pulled out as a named export so the unit test can drive
|
|
11
|
-
// every branch with a fake RedeployApiSurface, without spinning up
|
|
12
|
-
// a real client or the oclif command lifecycle.
|
|
13
|
-
export async function runRedeployWithSecrets(api, params) {
|
|
14
|
-
const writtenSecrets = [];
|
|
15
|
-
const succeededKeys = [];
|
|
16
|
-
for (let i = 0; i < params.secrets.length; i++) {
|
|
17
|
-
const pair = params.secrets[i];
|
|
18
|
-
// Pre-compute the keys that come AFTER the current pair so a
|
|
19
|
-
// set-secret failure can surface every key that was never
|
|
20
|
-
// attempted, not just the one that failed.
|
|
21
|
-
const pendingKeys = params.secrets.slice(i + 1).map((p) => p.key);
|
|
22
|
-
const setResult = await api.setSecret({
|
|
23
|
-
id: params.id,
|
|
24
|
-
key: pair.key,
|
|
25
|
-
value: pair.value,
|
|
26
|
-
});
|
|
27
|
-
if (setResult.error) {
|
|
28
|
-
return {
|
|
29
|
-
failedKey: pair.key,
|
|
30
|
-
kind: "error",
|
|
31
|
-
payload: extractErrorPayload(setResult.error),
|
|
32
|
-
pendingKeys,
|
|
33
|
-
stage: "set-secret",
|
|
34
|
-
succeededKeys,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
const secret = setResult.data?.data;
|
|
38
|
-
if (!secret) {
|
|
39
|
-
return {
|
|
40
|
-
failedKey: pair.key,
|
|
41
|
-
kind: "error",
|
|
42
|
-
payload: {
|
|
43
|
-
code: "client_error",
|
|
44
|
-
message: "Secret write returned no data",
|
|
45
|
-
},
|
|
46
|
-
pendingKeys,
|
|
47
|
-
stage: "set-secret",
|
|
48
|
-
succeededKeys,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
writtenSecrets.push(secret);
|
|
52
|
-
succeededKeys.push(pair.key);
|
|
53
|
-
}
|
|
54
|
-
const updateResult = await api.updateFunction({
|
|
55
|
-
code: params.code,
|
|
56
|
-
id: params.id,
|
|
57
|
-
...(params.sourceMap !== undefined ? { sourceMap: params.sourceMap } : {}),
|
|
58
|
-
});
|
|
59
|
-
if (updateResult.error) {
|
|
60
|
-
return {
|
|
61
|
-
kind: "error",
|
|
62
|
-
payload: extractErrorPayload(updateResult.error),
|
|
63
|
-
stage: "redeploy",
|
|
64
|
-
succeededKeys,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
const redeployed = updateResult.data?.data;
|
|
68
|
-
if (!redeployed) {
|
|
69
|
-
return {
|
|
70
|
-
kind: "error",
|
|
71
|
-
payload: {
|
|
72
|
-
code: "client_error",
|
|
73
|
-
message: "Redeploy returned no data",
|
|
74
|
-
},
|
|
75
|
-
stage: "redeploy",
|
|
76
|
-
succeededKeys,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
return {
|
|
80
|
-
kind: "ok",
|
|
81
|
-
result: {
|
|
82
|
-
redeploy: redeployed,
|
|
83
|
-
...(writtenSecrets.length > 0 ? { secrets: writtenSecrets } : {}),
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
class FunctionsRedeployCommand extends Command {
|
|
88
|
-
static description = `Update or redeploy a function from a bundled handler file. Agent-grade shortcut for functions:update-function.
|
|
89
|
-
|
|
90
|
-
Use to push a new bundle OR to refresh secret bindings into the
|
|
91
|
-
running handler. The same file is fine for both: the deploy reads
|
|
92
|
-
the bindings table fresh on every call, so passing the existing
|
|
93
|
-
bundle picks up any secret writes since the last deploy.
|
|
94
|
-
|
|
95
|
-
Pass --secret KEY=VALUE (repeatable) to write secrets BEFORE the
|
|
96
|
-
redeploy fires; one update-function call then refreshes every new
|
|
97
|
-
binding. Keys must match \`^[A-Z_][A-Z0-9_]*$\` (uppercase letters,
|
|
98
|
-
digits, underscores; first character is a letter or underscore).
|
|
99
|
-
With one or more --secret flags the redeploy fans out to multiple
|
|
100
|
-
API calls (set-secret per pair, then update-function).`;
|
|
101
|
-
static summary = "Redeploy a function from a bundled handler file";
|
|
102
|
-
static examples = [
|
|
103
|
-
"<%= config.bin %> functions:redeploy --id <fn-id> --file ./bundle.js",
|
|
104
|
-
"<%= config.bin %> functions:redeploy --id <fn-id> --file ./bundle.js --source-map-file ./bundle.js.map",
|
|
105
|
-
"<%= config.bin %> functions:redeploy --id <fn-id> --file ./bundle.js --secret OPENAI_KEY=sk-... --secret OWNER_EMAIL=me@example.com",
|
|
106
|
-
];
|
|
107
|
-
static flags = {
|
|
108
|
-
"api-key": Flags.string({
|
|
109
|
-
description: "Primitive API key (defaults to PRIMITIVE_API_KEY or saved `primitive login` credentials)",
|
|
110
|
-
env: "PRIMITIVE_API_KEY",
|
|
111
|
-
}),
|
|
112
|
-
"api-base-url-1": Flags.string({
|
|
113
|
-
description: "Override the primary API base URL. Internal testing only; not documented to customers.",
|
|
114
|
-
env: "PRIMITIVE_API_BASE_URL_1",
|
|
115
|
-
hidden: true,
|
|
116
|
-
}),
|
|
117
|
-
"api-base-url-2": Flags.string({
|
|
118
|
-
description: "Override the attachments-supporting send host base URL. Internal testing only; not documented to customers.",
|
|
119
|
-
env: "PRIMITIVE_API_BASE_URL_2",
|
|
120
|
-
hidden: true,
|
|
121
|
-
}),
|
|
122
|
-
id: Flags.string({
|
|
123
|
-
description: "Function id (UUID). The function must already exist.",
|
|
124
|
-
required: true,
|
|
125
|
-
}),
|
|
126
|
-
file: Flags.string({
|
|
127
|
-
description: "Path to the bundled ESM handler file. Loaded as the `code` body field.",
|
|
128
|
-
required: true,
|
|
129
|
-
}),
|
|
130
|
-
"source-map-file": Flags.string({
|
|
131
|
-
description: "Optional path to a source map for the bundle. Used to symbolicate stack traces in the function's logs.",
|
|
132
|
-
}),
|
|
133
|
-
secret: Flags.string({
|
|
134
|
-
description: `Secret KEY=VALUE to write on the function before the redeploy fires. Repeatable. KEY must match \`^[A-Z_][A-Z0-9_]*$\`; VALUE may contain \`=\` (only the first \`=\` is treated as a delimiter). Each KEY may only appear once per command. Passing one or more --secret flags fans out to set-secret per pair then a single update-function call so the new bindings land in the same redeploy. ${SECRET_FLAG_SECURITY_NOTE}`,
|
|
135
|
-
multiple: true,
|
|
136
|
-
}),
|
|
137
|
-
time: Flags.boolean({
|
|
138
|
-
description: TIME_FLAG_DESCRIPTION,
|
|
139
|
-
}),
|
|
140
|
-
};
|
|
141
|
-
async run() {
|
|
142
|
-
const { flags } = await this.parse(FunctionsRedeployCommand);
|
|
143
|
-
await runWithTiming(flags.time, async () => {
|
|
144
|
-
// Validate --secret pairs BEFORE any disk read or API call so
|
|
145
|
-
// a malformed input fails fast with a clear error and zero
|
|
146
|
-
// side effects. The fast path (no --secret flags) skips the
|
|
147
|
-
// secret-write loop entirely.
|
|
148
|
-
const rawSecrets = flags.secret ?? [];
|
|
149
|
-
const parsedSecrets = parseSecretFlags(rawSecrets);
|
|
150
|
-
if (parsedSecrets.kind === "error") {
|
|
151
|
-
process.stderr.write(`${parsedSecrets.message}\n`);
|
|
152
|
-
process.exitCode = 1;
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
// Reads inside the timed block: --time captures disk I/O too,
|
|
156
|
-
// which is the latency the flag is meant to surface.
|
|
157
|
-
const code = readTextFileFlag(flags.file, "--file");
|
|
158
|
-
const sourceMap = flags["source-map-file"]
|
|
159
|
-
? readTextFileFlag(flags["source-map-file"], "--source-map-file")
|
|
160
|
-
: undefined;
|
|
161
|
-
// Non-blocking deploy-time lint: if the bundle has a raw
|
|
162
|
-
// fetch(...) call against /send-mail, nudge the author toward
|
|
163
|
-
// `createPrimitiveClient` from `@primitivedotdev/sdk/api`.
|
|
164
|
-
// Same check as functions:deploy; warning goes to stderr and
|
|
165
|
-
// the deploy continues regardless.
|
|
166
|
-
emitRawSendMailFetchWarning(code, (chunk) => process.stderr.write(chunk));
|
|
167
|
-
const baseUrlOverridden = flags["api-base-url-1"] !== undefined ||
|
|
168
|
-
flags["api-base-url-2"] !== undefined;
|
|
169
|
-
const auth = resolveCliAuth({
|
|
170
|
-
apiKey: flags["api-key"],
|
|
171
|
-
apiBaseUrl1: flags["api-base-url-1"],
|
|
172
|
-
apiBaseUrl2: flags["api-base-url-2"],
|
|
173
|
-
configDir: this.config.configDir,
|
|
174
|
-
});
|
|
175
|
-
const apiClient = new PrimitiveApiClient({
|
|
176
|
-
apiKey: auth.apiKey,
|
|
177
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
178
|
-
apiBaseUrl2: auth.apiBaseUrl2,
|
|
179
|
-
});
|
|
180
|
-
const authFailureContext = {
|
|
181
|
-
auth,
|
|
182
|
-
baseUrlOverridden,
|
|
183
|
-
configDir: this.config.configDir,
|
|
184
|
-
};
|
|
185
|
-
// Adapter: thin wrappers around the generated SDK calls,
|
|
186
|
-
// routed through host 1 (apiClient.client). The function
|
|
187
|
-
// CRUD and secrets endpoints are not on host 2.
|
|
188
|
-
const apiSurface = {
|
|
189
|
-
setSecret: (p) => setFunctionSecret({
|
|
190
|
-
body: { value: p.value },
|
|
191
|
-
client: apiClient.client,
|
|
192
|
-
path: { id: p.id, key: p.key },
|
|
193
|
-
responseStyle: "fields",
|
|
194
|
-
}),
|
|
195
|
-
updateFunction: (p) => updateFunction({
|
|
196
|
-
body: {
|
|
197
|
-
code: p.code,
|
|
198
|
-
...(p.sourceMap !== undefined ? { sourceMap: p.sourceMap } : {}),
|
|
199
|
-
},
|
|
200
|
-
client: apiClient.client,
|
|
201
|
-
path: { id: p.id },
|
|
202
|
-
responseStyle: "fields",
|
|
203
|
-
}),
|
|
204
|
-
};
|
|
205
|
-
const outcome = await runRedeployWithSecrets(apiSurface, {
|
|
206
|
-
code,
|
|
207
|
-
id: flags.id,
|
|
208
|
-
secrets: parsedSecrets.secrets,
|
|
209
|
-
...(sourceMap !== undefined ? { sourceMap } : {}),
|
|
210
|
-
});
|
|
211
|
-
if (outcome.kind === "error") {
|
|
212
|
-
if (outcome.stage === "set-secret") {
|
|
213
|
-
const succeeded = outcome.succeededKeys.length > 0
|
|
214
|
-
? outcome.succeededKeys.join(", ")
|
|
215
|
-
: "(none)";
|
|
216
|
-
const pending = outcome.pendingKeys.length > 0
|
|
217
|
-
? outcome.pendingKeys.join(", ")
|
|
218
|
-
: "(none)";
|
|
219
|
-
const allMissing = [outcome.failedKey, ...outcome.pendingKeys].join(", ");
|
|
220
|
-
process.stderr.write(`Writing secret ${outcome.failedKey} failed before the redeploy; succeeded keys so far: ${succeeded}; keys not yet attempted: ${pending}. The new bundle has NOT been deployed. Re-run \`primitive functions:set-secret\` for each of [${allMissing}], then \`primitive functions:redeploy --id ${flags.id} --file <bundle>\` to push them live.\n`);
|
|
221
|
-
}
|
|
222
|
-
else if (outcome.stage === "redeploy") {
|
|
223
|
-
const succeeded = outcome.succeededKeys.length > 0
|
|
224
|
-
? outcome.succeededKeys.join(", ")
|
|
225
|
-
: "(none)";
|
|
226
|
-
process.stderr.write(`Secrets [${succeeded}] were written, but the redeploy step failed; the new bindings are NOT yet live. Re-run \`primitive functions:redeploy --id ${flags.id} --file <bundle>\` once the cause is fixed.\n`);
|
|
227
|
-
}
|
|
228
|
-
writeErrorWithHints(outcome.payload);
|
|
229
|
-
removeStaleSavedCredentialOnUnauthorized({
|
|
230
|
-
...authFailureContext,
|
|
231
|
-
payload: outcome.payload,
|
|
232
|
-
});
|
|
233
|
-
process.exitCode = 1;
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
this.log(JSON.stringify(outcome.result.redeploy, null, 2));
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
export default FunctionsRedeployCommand;
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import { Command, Flags } from "@oclif/core";
|
|
2
|
-
import { getFunction, PrimitiveApiClient, setFunctionSecret, updateFunction, } from "@primitivedotdev/sdk/api";
|
|
3
|
-
import { extractErrorPayload, removeStaleSavedCredentialOnUnauthorized, runWithTiming, TIME_FLAG_DESCRIPTION, writeErrorWithHints, } from "../api-command.js";
|
|
4
|
-
import { resolveCliAuth } from "../auth.js";
|
|
5
|
-
// Pure-ish orchestration of the set-secret + optional redeploy
|
|
6
|
-
// flow. Pulled out as a named export so the unit test can drive
|
|
7
|
-
// both the happy path and each error stage with a fake API
|
|
8
|
-
// surface, without spinning up a real client or the oclif
|
|
9
|
-
// command lifecycle.
|
|
10
|
-
//
|
|
11
|
-
// The redeploy step uses the function's CURRENT code (fetched via
|
|
12
|
-
// getFunction) as the new bundle. This is the documented way to
|
|
13
|
-
// "refresh secret bindings without changing the handler": the
|
|
14
|
-
// server-side deploy reads the secrets table fresh on every call,
|
|
15
|
-
// so re-deploying the same code picks up the secret we just wrote.
|
|
16
|
-
export async function runSetSecret(api, params) {
|
|
17
|
-
const setResult = await api.setSecret({
|
|
18
|
-
id: params.id,
|
|
19
|
-
key: params.key,
|
|
20
|
-
value: params.value,
|
|
21
|
-
});
|
|
22
|
-
if (setResult.error) {
|
|
23
|
-
return {
|
|
24
|
-
kind: "error",
|
|
25
|
-
payload: extractErrorPayload(setResult.error),
|
|
26
|
-
stage: "set-secret",
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
const secret = setResult.data?.data;
|
|
30
|
-
if (!secret) {
|
|
31
|
-
// Server returned 2xx with no `data` body. Treat as an error
|
|
32
|
-
// so we don't fabricate a success payload; this should not
|
|
33
|
-
// happen in practice but the shape forces us to handle it.
|
|
34
|
-
return {
|
|
35
|
-
kind: "error",
|
|
36
|
-
payload: {
|
|
37
|
-
code: "client_error",
|
|
38
|
-
message: "Secret write returned no data",
|
|
39
|
-
},
|
|
40
|
-
stage: "set-secret",
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
if (!params.redeploy) {
|
|
44
|
-
return { kind: "ok", result: { secret } };
|
|
45
|
-
}
|
|
46
|
-
const fnResult = await api.getFunction({ id: params.id });
|
|
47
|
-
if (fnResult.error) {
|
|
48
|
-
return {
|
|
49
|
-
kind: "error",
|
|
50
|
-
payload: extractErrorPayload(fnResult.error),
|
|
51
|
-
stage: "get-function",
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
const fn = fnResult.data?.data;
|
|
55
|
-
if (!fn) {
|
|
56
|
-
return {
|
|
57
|
-
kind: "error",
|
|
58
|
-
payload: {
|
|
59
|
-
code: "client_error",
|
|
60
|
-
message: "Could not read current function code for redeploy",
|
|
61
|
-
},
|
|
62
|
-
stage: "get-function",
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
const updateResult = await api.updateFunction({
|
|
66
|
-
code: fn.code,
|
|
67
|
-
id: params.id,
|
|
68
|
-
});
|
|
69
|
-
if (updateResult.error) {
|
|
70
|
-
return {
|
|
71
|
-
kind: "error",
|
|
72
|
-
payload: extractErrorPayload(updateResult.error),
|
|
73
|
-
stage: "redeploy",
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
const redeployed = updateResult.data?.data;
|
|
77
|
-
if (!redeployed) {
|
|
78
|
-
return {
|
|
79
|
-
kind: "error",
|
|
80
|
-
payload: {
|
|
81
|
-
code: "client_error",
|
|
82
|
-
message: "Redeploy returned no data",
|
|
83
|
-
},
|
|
84
|
-
stage: "redeploy",
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
return { kind: "ok", result: { redeploy: redeployed, secret } };
|
|
88
|
-
}
|
|
89
|
-
class FunctionsSetSecretCommand extends Command {
|
|
90
|
-
static description = `Write a function secret and optionally redeploy so the new value lands in the running handler. Agent-grade shortcut for functions:set-function-secret + functions:redeploy.
|
|
91
|
-
|
|
92
|
-
Without --redeploy this is a plain secret upsert: the value is
|
|
93
|
-
encrypted at rest but is NOT visible to the running handler until
|
|
94
|
-
the next deploy. Pass --redeploy to re-run the deploy with the
|
|
95
|
-
function's current code in the same call, which refreshes the
|
|
96
|
-
binding set with the value you just wrote.
|
|
97
|
-
|
|
98
|
-
Keys must match \`^[A-Z_][A-Z0-9_]*$\` (uppercase letters, digits,
|
|
99
|
-
underscores; first character is a letter or underscore). System-
|
|
100
|
-
managed keys are reserved and rejected.`;
|
|
101
|
-
static summary = "Write a function secret (optionally redeploying to push it live)";
|
|
102
|
-
static examples = [
|
|
103
|
-
"<%= config.bin %> functions:set-secret --id <fn-id> --key API_TOKEN --value abc123",
|
|
104
|
-
"<%= config.bin %> functions:set-secret --id <fn-id> --key API_TOKEN --value abc123 --redeploy",
|
|
105
|
-
];
|
|
106
|
-
static flags = {
|
|
107
|
-
"api-key": Flags.string({
|
|
108
|
-
description: "Primitive API key (defaults to PRIMITIVE_API_KEY or saved `primitive login` credentials)",
|
|
109
|
-
env: "PRIMITIVE_API_KEY",
|
|
110
|
-
}),
|
|
111
|
-
"api-base-url-1": Flags.string({
|
|
112
|
-
description: "Override the primary API base URL. Internal testing only; not documented to customers.",
|
|
113
|
-
env: "PRIMITIVE_API_BASE_URL_1",
|
|
114
|
-
hidden: true,
|
|
115
|
-
}),
|
|
116
|
-
"api-base-url-2": Flags.string({
|
|
117
|
-
description: "Override the attachments-supporting send host base URL. Internal testing only; not documented to customers.",
|
|
118
|
-
env: "PRIMITIVE_API_BASE_URL_2",
|
|
119
|
-
hidden: true,
|
|
120
|
-
}),
|
|
121
|
-
id: Flags.string({
|
|
122
|
-
description: "Function id (UUID). The function must already exist.",
|
|
123
|
-
required: true,
|
|
124
|
-
}),
|
|
125
|
-
key: Flags.string({
|
|
126
|
-
description: "Secret key. Uppercase letters, digits, underscores; must start with a letter or underscore. System-managed keys are reserved.",
|
|
127
|
-
required: true,
|
|
128
|
-
}),
|
|
129
|
-
value: Flags.string({
|
|
130
|
-
description: "Secret value (up to 4096 UTF-8 bytes). Encrypted at rest.",
|
|
131
|
-
required: true,
|
|
132
|
-
}),
|
|
133
|
-
redeploy: Flags.boolean({
|
|
134
|
-
description: "Also redeploy the function with its current code so the new value lands in the running handler. Without this, the secret is written but not visible to the handler until the next deploy. Note: source maps are stored only on the runtime side and getFunction does not return them, so this redeploy drops any previously-uploaded source map. If preserving stack-trace symbolication matters, use `functions:redeploy --file <bundle.js> --source-map-file <bundle.js.map>` instead.",
|
|
135
|
-
}),
|
|
136
|
-
time: Flags.boolean({
|
|
137
|
-
description: TIME_FLAG_DESCRIPTION,
|
|
138
|
-
}),
|
|
139
|
-
};
|
|
140
|
-
async run() {
|
|
141
|
-
const { flags } = await this.parse(FunctionsSetSecretCommand);
|
|
142
|
-
await runWithTiming(flags.time, async () => {
|
|
143
|
-
const baseUrlOverridden = flags["api-base-url-1"] !== undefined ||
|
|
144
|
-
flags["api-base-url-2"] !== undefined;
|
|
145
|
-
const auth = resolveCliAuth({
|
|
146
|
-
apiKey: flags["api-key"],
|
|
147
|
-
apiBaseUrl1: flags["api-base-url-1"],
|
|
148
|
-
apiBaseUrl2: flags["api-base-url-2"],
|
|
149
|
-
configDir: this.config.configDir,
|
|
150
|
-
});
|
|
151
|
-
const apiClient = new PrimitiveApiClient({
|
|
152
|
-
apiKey: auth.apiKey,
|
|
153
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
154
|
-
apiBaseUrl2: auth.apiBaseUrl2,
|
|
155
|
-
});
|
|
156
|
-
const authFailureContext = {
|
|
157
|
-
auth,
|
|
158
|
-
baseUrlOverridden,
|
|
159
|
-
configDir: this.config.configDir,
|
|
160
|
-
};
|
|
161
|
-
// Adapter: thin wrappers around the generated SDK calls,
|
|
162
|
-
// routed through host 1 (apiClient.client). The secrets and
|
|
163
|
-
// function-detail endpoints are not on host 2.
|
|
164
|
-
const apiSurface = {
|
|
165
|
-
getFunction: (p) => getFunction({
|
|
166
|
-
client: apiClient.client,
|
|
167
|
-
path: { id: p.id },
|
|
168
|
-
responseStyle: "fields",
|
|
169
|
-
}),
|
|
170
|
-
setSecret: (p) => setFunctionSecret({
|
|
171
|
-
body: { value: p.value },
|
|
172
|
-
client: apiClient.client,
|
|
173
|
-
path: { id: p.id, key: p.key },
|
|
174
|
-
responseStyle: "fields",
|
|
175
|
-
}),
|
|
176
|
-
updateFunction: (p) => updateFunction({
|
|
177
|
-
body: { code: p.code },
|
|
178
|
-
client: apiClient.client,
|
|
179
|
-
path: { id: p.id },
|
|
180
|
-
responseStyle: "fields",
|
|
181
|
-
}),
|
|
182
|
-
};
|
|
183
|
-
const outcome = await runSetSecret(apiSurface, {
|
|
184
|
-
id: flags.id,
|
|
185
|
-
key: flags.key,
|
|
186
|
-
redeploy: flags.redeploy === true,
|
|
187
|
-
value: flags.value,
|
|
188
|
-
});
|
|
189
|
-
if (outcome.kind === "error") {
|
|
190
|
-
// Stage-specific framing on stderr so callers can tell
|
|
191
|
-
// whether the secret landed before a failed redeploy. The
|
|
192
|
-
// JSON envelope still goes through writeErrorWithHints so
|
|
193
|
-
// any actionable hint (e.g. unauthorized) is surfaced.
|
|
194
|
-
if (outcome.stage === "get-function") {
|
|
195
|
-
process.stderr.write("Secret was written, but reading current function code for redeploy failed; the secret is NOT yet live. Re-run with --redeploy, or call `primitive functions:redeploy --id <id> --file <bundle>` once you have the bundle.\n");
|
|
196
|
-
}
|
|
197
|
-
else if (outcome.stage === "redeploy") {
|
|
198
|
-
process.stderr.write("Secret was written, but the redeploy step failed; the secret is NOT yet live. Inspect the function's deploy_error and re-run `primitive functions:redeploy --id <id> --file <bundle>` once the cause is fixed.\n");
|
|
199
|
-
}
|
|
200
|
-
writeErrorWithHints(outcome.payload);
|
|
201
|
-
removeStaleSavedCredentialOnUnauthorized({
|
|
202
|
-
...authFailureContext,
|
|
203
|
-
payload: outcome.payload,
|
|
204
|
-
});
|
|
205
|
-
process.exitCode = 1;
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
this.log(JSON.stringify(outcome.result, null, 2));
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
export default FunctionsSetSecretCommand;
|