@freecodecamp/universe-cli 0.6.0 → 0.7.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 +8 -8
- package/dist/index.cjs +361 -171
- package/dist/index.js +326 -211
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { cac } from "cac";
|
|
|
6
6
|
// src/commands/deploy.ts
|
|
7
7
|
import { readFile as readFile2 } from "fs/promises";
|
|
8
8
|
import { resolve as resolve2 } from "path";
|
|
9
|
-
import { log } from "@clack/prompts";
|
|
9
|
+
import { log as log2, spinner } from "@clack/prompts";
|
|
10
10
|
|
|
11
11
|
// src/output/exit-codes.ts
|
|
12
12
|
var EXIT_USAGE = 10;
|
|
@@ -221,14 +221,14 @@ async function resolveIdentity(opts = {}) {
|
|
|
221
221
|
if (isNonEmpty(ghTokenEnv)) {
|
|
222
222
|
return { token: ghTokenEnv.trim(), source: "env_GH_TOKEN" };
|
|
223
223
|
}
|
|
224
|
-
const ghCli = await execGh();
|
|
225
|
-
if (isNonEmpty(ghCli)) {
|
|
226
|
-
return { token: ghCli.trim(), source: "gh_cli" };
|
|
227
|
-
}
|
|
228
224
|
const stored = await loadStored();
|
|
229
225
|
if (isNonEmpty(stored)) {
|
|
230
226
|
return { token: stored.trim(), source: "device_flow" };
|
|
231
227
|
}
|
|
228
|
+
const ghCli = await execGh();
|
|
229
|
+
if (isNonEmpty(ghCli)) {
|
|
230
|
+
return { token: ghCli.trim(), source: "gh_cli" };
|
|
231
|
+
}
|
|
232
232
|
return null;
|
|
233
233
|
}
|
|
234
234
|
|
|
@@ -429,6 +429,14 @@ function suggest(target, candidates, threshold = 2) {
|
|
|
429
429
|
}
|
|
430
430
|
|
|
431
431
|
// src/lib/proxy-client.ts
|
|
432
|
+
var DEFAULT_FETCH_TIMEOUT_MS = 3e4;
|
|
433
|
+
function parseFetchTimeoutMs(env) {
|
|
434
|
+
const raw = env["UNIVERSE_FETCH_TIMEOUT_MS"];
|
|
435
|
+
if (raw === void 0 || raw === "") return void 0;
|
|
436
|
+
const n = Number(raw);
|
|
437
|
+
if (!Number.isFinite(n) || n < 0) return void 0;
|
|
438
|
+
return Math.floor(n);
|
|
439
|
+
}
|
|
432
440
|
var ProxyError = class extends CliError {
|
|
433
441
|
exitCode;
|
|
434
442
|
status;
|
|
@@ -506,6 +514,24 @@ function stripTrailingSlash(url) {
|
|
|
506
514
|
function createProxyClient(cfg) {
|
|
507
515
|
const base = stripTrailingSlash(cfg.baseUrl);
|
|
508
516
|
const fetchImpl = cfg.fetch ?? globalThis.fetch.bind(globalThis);
|
|
517
|
+
const timeoutMs = cfg.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
|
|
518
|
+
function withTimeoutSignal(init) {
|
|
519
|
+
if (timeoutMs <= 0) return init;
|
|
520
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
521
|
+
const merged = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
|
|
522
|
+
return { ...init, signal: merged };
|
|
523
|
+
}
|
|
524
|
+
function translateFetchError(err) {
|
|
525
|
+
if (err instanceof DOMException && (err.name === "TimeoutError" || err.name === "AbortError")) {
|
|
526
|
+
throw new ProxyError(
|
|
527
|
+
0,
|
|
528
|
+
"timeout",
|
|
529
|
+
`proxy timed out after ${timeoutMs}ms`
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
533
|
+
throw new ProxyError(0, "network_error", `proxy unreachable: ${message}`);
|
|
534
|
+
}
|
|
509
535
|
async function userBearer() {
|
|
510
536
|
const tok = await cfg.getAuthToken();
|
|
511
537
|
return `Bearer ${tok}`;
|
|
@@ -513,10 +539,9 @@ function createProxyClient(cfg) {
|
|
|
513
539
|
async function call(url, init) {
|
|
514
540
|
let response;
|
|
515
541
|
try {
|
|
516
|
-
response = await fetchImpl(url, init);
|
|
542
|
+
response = await fetchImpl(url, withTimeoutSignal(init));
|
|
517
543
|
} catch (err) {
|
|
518
|
-
|
|
519
|
-
throw new ProxyError(0, "network_error", `proxy unreachable: ${message}`);
|
|
544
|
+
translateFetchError(err);
|
|
520
545
|
}
|
|
521
546
|
if (!response.ok) {
|
|
522
547
|
const env = await readErrorEnvelope(response);
|
|
@@ -588,20 +613,18 @@ function createProxyClient(cfg) {
|
|
|
588
613
|
const url = `${base}/api/site/${encodeURIComponent(req.site)}/alias/${encodeURIComponent(req.mode)}`;
|
|
589
614
|
let response;
|
|
590
615
|
try {
|
|
591
|
-
response = await fetchImpl(
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
throw new ProxyError(
|
|
601
|
-
0,
|
|
602
|
-
"network_error",
|
|
603
|
-
`proxy unreachable: ${message}`
|
|
616
|
+
response = await fetchImpl(
|
|
617
|
+
url,
|
|
618
|
+
withTimeoutSignal({
|
|
619
|
+
method: "GET",
|
|
620
|
+
headers: {
|
|
621
|
+
Authorization: await userBearer(),
|
|
622
|
+
Accept: "application/json"
|
|
623
|
+
}
|
|
624
|
+
})
|
|
604
625
|
);
|
|
626
|
+
} catch (err) {
|
|
627
|
+
translateFetchError(err);
|
|
605
628
|
}
|
|
606
629
|
if (response.status === 404) return null;
|
|
607
630
|
if (!response.ok) {
|
|
@@ -845,6 +868,106 @@ function buildErrorEnvelope(command, code, message, issues) {
|
|
|
845
868
|
};
|
|
846
869
|
}
|
|
847
870
|
|
|
871
|
+
// src/output/format.ts
|
|
872
|
+
import { log } from "@clack/prompts";
|
|
873
|
+
|
|
874
|
+
// src/output/redact.ts
|
|
875
|
+
var AWS_KEY_PREFIX_PATTERN = /(?:AKIA|ASIA|AROA|AIDA|ACCA|ANPA|ABIA|AGPA)[A-Z0-9]{12,}/g;
|
|
876
|
+
var URL_CREDS_PATTERN = /https?:\/\/[^@\s]+@/g;
|
|
877
|
+
var CREDENTIAL_CONTEXT_PATTERN = /(?:access_key_id|secret_access_key|accessKeyId|secretAccessKey|secret|password|token|key|credential|auth)\s*[=:]\s*([A-Za-z0-9/+=]{21,})/gi;
|
|
878
|
+
var HEX_CREDENTIAL_CONTEXT_PATTERN = /(?:secret|password|token|key|credential|auth|access_key_id|secret_access_key)\s*[=:]\s*([a-f0-9]{32,})/gi;
|
|
879
|
+
var JSON_CREDENTIAL_PATTERN = /"(?:secret|password|token|key|credential|auth|access_key_id|secret_access_key|accessKeyId|secretAccessKey)"\s*:\s*"[^"]+"/gi;
|
|
880
|
+
var BEARER_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]+/gi;
|
|
881
|
+
var CREDENTIAL_KEY_PATTERN = /(?:secret|password|token|key|credential|auth)/i;
|
|
882
|
+
var EXACT_CREDENTIAL_KEYS = /* @__PURE__ */ new Set([
|
|
883
|
+
"accesskeyid",
|
|
884
|
+
"secretaccesskey",
|
|
885
|
+
"access_key_id",
|
|
886
|
+
"secret_access_key"
|
|
887
|
+
]);
|
|
888
|
+
var STANDALONE_LONG_SECRET = /^[A-Za-z0-9/+=]{21,}$/;
|
|
889
|
+
function maskAwsKey(match) {
|
|
890
|
+
return match.slice(0, 4) + "****" + match.slice(-4);
|
|
891
|
+
}
|
|
892
|
+
function maskUrlCreds(match) {
|
|
893
|
+
const atIndex = match.lastIndexOf("@");
|
|
894
|
+
const protocolEnd = match.indexOf("://") + 3;
|
|
895
|
+
return match.slice(0, protocolEnd) + "****:****@" + match.slice(atIndex + 1);
|
|
896
|
+
}
|
|
897
|
+
function redact(value) {
|
|
898
|
+
let result = value;
|
|
899
|
+
result = result.replace(URL_CREDS_PATTERN, maskUrlCreds);
|
|
900
|
+
result = result.replace(AWS_KEY_PREFIX_PATTERN, maskAwsKey);
|
|
901
|
+
result = result.replace(BEARER_PATTERN, "Bearer ****");
|
|
902
|
+
result = result.replace(JSON_CREDENTIAL_PATTERN, (match) => {
|
|
903
|
+
const colonIndex = match.indexOf(":");
|
|
904
|
+
return match.slice(0, colonIndex + 1) + '"****"';
|
|
905
|
+
});
|
|
906
|
+
result = result.replace(
|
|
907
|
+
CREDENTIAL_CONTEXT_PATTERN,
|
|
908
|
+
(_match, _secret, _offset, _full) => {
|
|
909
|
+
const eqIndex = _match.indexOf("=");
|
|
910
|
+
const colonIndex = _match.indexOf(":");
|
|
911
|
+
const sepIndex = eqIndex >= 0 && colonIndex >= 0 ? Math.min(eqIndex, colonIndex) : eqIndex >= 0 ? eqIndex : colonIndex;
|
|
912
|
+
const prefix = _match.slice(0, sepIndex + 1);
|
|
913
|
+
return prefix + "****";
|
|
914
|
+
}
|
|
915
|
+
);
|
|
916
|
+
result = result.replace(HEX_CREDENTIAL_CONTEXT_PATTERN, (_match, _secret) => {
|
|
917
|
+
const eqIndex = _match.indexOf("=");
|
|
918
|
+
const colonIndex = _match.indexOf(":");
|
|
919
|
+
const sepIndex = eqIndex >= 0 && colonIndex >= 0 ? Math.min(eqIndex, colonIndex) : eqIndex >= 0 ? eqIndex : colonIndex;
|
|
920
|
+
const prefix = _match.slice(0, sepIndex + 1);
|
|
921
|
+
return prefix + "****";
|
|
922
|
+
});
|
|
923
|
+
return result;
|
|
924
|
+
}
|
|
925
|
+
function redactValue(value, keyName) {
|
|
926
|
+
if (typeof value === "string") {
|
|
927
|
+
if (keyName && EXACT_CREDENTIAL_KEYS.has(keyName.toLowerCase())) {
|
|
928
|
+
return "****";
|
|
929
|
+
}
|
|
930
|
+
const redacted = redact(value);
|
|
931
|
+
if (redacted === value && keyName && CREDENTIAL_KEY_PATTERN.test(keyName) && STANDALONE_LONG_SECRET.test(value)) {
|
|
932
|
+
return "****";
|
|
933
|
+
}
|
|
934
|
+
return redacted;
|
|
935
|
+
}
|
|
936
|
+
if (Array.isArray(value)) {
|
|
937
|
+
return value.map((v) => redactValue(v, keyName));
|
|
938
|
+
}
|
|
939
|
+
if (value !== null && typeof value === "object") {
|
|
940
|
+
return redactObject(value);
|
|
941
|
+
}
|
|
942
|
+
return value;
|
|
943
|
+
}
|
|
944
|
+
function redactObject(obj) {
|
|
945
|
+
const result = {};
|
|
946
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
947
|
+
result[key] = redactValue(value, key);
|
|
948
|
+
}
|
|
949
|
+
return result;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// src/output/format.ts
|
|
953
|
+
function outputError(ctx, code, message, optsOrIssues) {
|
|
954
|
+
const opts = Array.isArray(optsOrIssues) ? { issues: optsOrIssues } : optsOrIssues ?? {};
|
|
955
|
+
const redactedMessage = redact(message);
|
|
956
|
+
const redactedIssues = opts.issues?.map(redact);
|
|
957
|
+
if (ctx.json) {
|
|
958
|
+
const envelope = buildErrorEnvelope(
|
|
959
|
+
ctx.command,
|
|
960
|
+
code,
|
|
961
|
+
redactedMessage,
|
|
962
|
+
redactedIssues
|
|
963
|
+
);
|
|
964
|
+
const payload = opts.extras ? { ...envelope, ...redactObject(opts.extras) } : envelope;
|
|
965
|
+
process.stdout.write(JSON.stringify(payload) + "\n");
|
|
966
|
+
} else {
|
|
967
|
+
(opts.logError ?? ((m) => log.error(m)))(redactedMessage);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
848
971
|
// src/commands/deploy.ts
|
|
849
972
|
var defaultReadPlatformYaml = async (cwd) => {
|
|
850
973
|
return readFile2(resolve2(cwd, "platform.yaml"), "utf-8");
|
|
@@ -938,10 +1061,11 @@ async function deploy(options, deps = {}) {
|
|
|
938
1061
|
const build = deps.runBuild ?? runBuild;
|
|
939
1062
|
const walk = deps.walkFiles ?? walkFiles;
|
|
940
1063
|
const upload = deps.uploadFiles ?? uploadFiles;
|
|
941
|
-
const
|
|
942
|
-
const
|
|
943
|
-
const
|
|
944
|
-
const
|
|
1064
|
+
const mkSpinner = deps.createSpinner ?? (() => spinner());
|
|
1065
|
+
const success = deps.logSuccess ?? ((s) => log2.success(s));
|
|
1066
|
+
const info = deps.logInfo ?? ((s) => log2.info(s));
|
|
1067
|
+
const warn = deps.logWarn ?? ((s) => log2.warn(s));
|
|
1068
|
+
const error = deps.logError ?? ((s) => log2.error(s));
|
|
945
1069
|
const exit = deps.exit ?? exitWithCode;
|
|
946
1070
|
try {
|
|
947
1071
|
const identity = await resolveId({ env });
|
|
@@ -954,7 +1078,8 @@ async function deploy(options, deps = {}) {
|
|
|
954
1078
|
const baseUrl = env["UNIVERSE_PROXY_URL"] ?? DEFAULT_PROXY_URL;
|
|
955
1079
|
const client = mkClient({
|
|
956
1080
|
baseUrl,
|
|
957
|
-
getAuthToken: () => identity.token
|
|
1081
|
+
getAuthToken: () => identity.token,
|
|
1082
|
+
timeoutMs: parseFetchTimeoutMs(env)
|
|
958
1083
|
});
|
|
959
1084
|
let me;
|
|
960
1085
|
try {
|
|
@@ -1005,17 +1130,22 @@ async function deploy(options, deps = {}) {
|
|
|
1005
1130
|
} catch (err) {
|
|
1006
1131
|
rethrowProxy("deploy init failed", err);
|
|
1007
1132
|
}
|
|
1133
|
+
const spin = options.json ? null : mkSpinner();
|
|
1134
|
+
spin?.start(`Uploading 0/${filtered.length} files`);
|
|
1008
1135
|
const uploadResult = await upload({
|
|
1009
1136
|
client,
|
|
1010
1137
|
deployId: initResult.deployId,
|
|
1011
1138
|
jwt: initResult.jwt,
|
|
1012
|
-
files: filtered
|
|
1139
|
+
files: filtered,
|
|
1140
|
+
onProgress: spin ? (p) => spin.message(`Uploading ${p.uploaded}/${p.total} \u2014 ${p.current}`) : void 0
|
|
1013
1141
|
});
|
|
1014
1142
|
if (uploadResult.errors.length > 0) {
|
|
1143
|
+
spin?.error(`Upload failed: ${uploadResult.errors.length} file(s)`);
|
|
1015
1144
|
const message = `Upload partially failed: ${uploadResult.errors.length} file(s) failed:
|
|
1016
1145
|
- ${uploadResult.errors.join("\n - ")}`;
|
|
1017
1146
|
throw new PartialUploadError(message);
|
|
1018
1147
|
}
|
|
1148
|
+
spin?.stop(`Uploaded ${uploadResult.fileCount} files`);
|
|
1019
1149
|
const mode = options.promote ? "production" : "preview";
|
|
1020
1150
|
let finalizeResult;
|
|
1021
1151
|
try {
|
|
@@ -1028,6 +1158,25 @@ async function deploy(options, deps = {}) {
|
|
|
1028
1158
|
} catch (err) {
|
|
1029
1159
|
rethrowProxy("deploy finalize failed", err);
|
|
1030
1160
|
}
|
|
1161
|
+
if (options.promote && !options.json) {
|
|
1162
|
+
try {
|
|
1163
|
+
const preview = await client.getAlias({
|
|
1164
|
+
site: config.site,
|
|
1165
|
+
mode: "preview"
|
|
1166
|
+
});
|
|
1167
|
+
if (preview && preview.deployId !== finalizeResult.deployId) {
|
|
1168
|
+
warn(
|
|
1169
|
+
`Preview alias still points to ${preview.deployId}; it will not auto-update. Run \`universe static deploy\` (without --promote) to refresh preview.`
|
|
1170
|
+
);
|
|
1171
|
+
}
|
|
1172
|
+
} catch (err) {
|
|
1173
|
+
if (err instanceof ProxyError && (err.status === 401 || err.status === 403)) {
|
|
1174
|
+
warn(
|
|
1175
|
+
`Preview alias probe got ${err.status} (${err.code}) \u2014 token may need rotation: ${err.message}`
|
|
1176
|
+
);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1031
1180
|
if (options.json) {
|
|
1032
1181
|
emitJson(
|
|
1033
1182
|
buildEnvelope("deploy", true, {
|
|
@@ -1074,17 +1223,15 @@ async function deploy(options, deps = {}) {
|
|
|
1074
1223
|
code = EXIT_USAGE;
|
|
1075
1224
|
message = String(err);
|
|
1076
1225
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
}
|
|
1080
|
-
error(message);
|
|
1081
|
-
}
|
|
1226
|
+
outputError({ json: options.json, command: "deploy" }, code, message, {
|
|
1227
|
+
logError: error
|
|
1228
|
+
});
|
|
1082
1229
|
exit(code);
|
|
1083
1230
|
}
|
|
1084
1231
|
}
|
|
1085
1232
|
|
|
1086
1233
|
// src/commands/login.ts
|
|
1087
|
-
import { log as
|
|
1234
|
+
import { log as log3 } from "@clack/prompts";
|
|
1088
1235
|
|
|
1089
1236
|
// src/lib/device-flow.ts
|
|
1090
1237
|
var DEVICE_CODE_URL = "https://github.com/login/device/code";
|
|
@@ -1161,6 +1308,19 @@ async function runDeviceFlow(opts) {
|
|
|
1161
1308
|
|
|
1162
1309
|
// src/commands/login.ts
|
|
1163
1310
|
var DEFAULT_SCOPE = "read:org user:email";
|
|
1311
|
+
var DEFAULT_PROXY_URL2 = "https://uploads.freecode.camp";
|
|
1312
|
+
var NO_SITES_WARNING = [
|
|
1313
|
+
"Logged in, but the proxy reports 0 authorized sites for your account.",
|
|
1314
|
+
"This usually means the Universe CLI GitHub App is not installed on the org",
|
|
1315
|
+
"that owns the registry-authz team (production: `freeCodeCamp-Universe`), or",
|
|
1316
|
+
"your account is not on a team granted access to any site.",
|
|
1317
|
+
"",
|
|
1318
|
+
"Next steps:",
|
|
1319
|
+
" 1. Run `universe whoami` to confirm the identity that resolved.",
|
|
1320
|
+
" 2. Ask an org owner to install the Universe CLI GitHub App on the org.",
|
|
1321
|
+
" 3. Confirm your team membership at",
|
|
1322
|
+
" https://github.com/orgs/freeCodeCamp-Universe/teams."
|
|
1323
|
+
].join("\n");
|
|
1164
1324
|
function emitJson2(envelope) {
|
|
1165
1325
|
process.stdout.write(JSON.stringify(envelope) + "\n");
|
|
1166
1326
|
}
|
|
@@ -1169,9 +1329,9 @@ async function login(options, deps = {}) {
|
|
|
1169
1329
|
const runFlow = deps.runDeviceFlow ?? runDeviceFlow;
|
|
1170
1330
|
const save = deps.saveToken ?? saveToken;
|
|
1171
1331
|
const load = deps.loadToken ?? loadToken;
|
|
1172
|
-
const success = deps.logSuccess ?? ((s) =>
|
|
1173
|
-
const info = deps.logInfo ?? ((s) =>
|
|
1174
|
-
const error = deps.logError ?? ((s) =>
|
|
1332
|
+
const success = deps.logSuccess ?? ((s) => log3.success(s));
|
|
1333
|
+
const info = deps.logInfo ?? ((s) => log3.info(s));
|
|
1334
|
+
const error = deps.logError ?? ((s) => log3.error(s));
|
|
1175
1335
|
const exit = deps.exit ?? exitWithCode;
|
|
1176
1336
|
const envClientId = env["UNIVERSE_GH_CLIENT_ID"];
|
|
1177
1337
|
const clientId = envClientId && envClientId.trim().length > 0 ? envClientId : DEFAULT_GH_CLIENT_ID;
|
|
@@ -1222,38 +1382,69 @@ async function login(options, deps = {}) {
|
|
|
1222
1382
|
});
|
|
1223
1383
|
} catch (err) {
|
|
1224
1384
|
const message = err instanceof Error ? err.message : String(err);
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
error: { code: EXIT_CREDENTIALS, message }
|
|
1232
|
-
});
|
|
1233
|
-
} else {
|
|
1234
|
-
error(message);
|
|
1235
|
-
}
|
|
1385
|
+
outputError(
|
|
1386
|
+
{ json: options.json, command: "login" },
|
|
1387
|
+
EXIT_CREDENTIALS,
|
|
1388
|
+
message,
|
|
1389
|
+
{ logError: error }
|
|
1390
|
+
);
|
|
1236
1391
|
exit(EXIT_CREDENTIALS);
|
|
1237
1392
|
return;
|
|
1238
1393
|
}
|
|
1239
1394
|
await save(token);
|
|
1395
|
+
const selfCheck = await postLoginSelfCheck(token, env, deps);
|
|
1240
1396
|
if (options.json) {
|
|
1241
|
-
emitJson2(
|
|
1397
|
+
emitJson2(
|
|
1398
|
+
buildEnvelope("login", true, {
|
|
1399
|
+
stored: true,
|
|
1400
|
+
...selfCheck.checked ? {
|
|
1401
|
+
authorizedSitesCount: selfCheck.authorizedSitesCount,
|
|
1402
|
+
...selfCheck.warning ? { warning: selfCheck.warning } : {}
|
|
1403
|
+
} : {}
|
|
1404
|
+
})
|
|
1405
|
+
);
|
|
1242
1406
|
} else {
|
|
1243
1407
|
success("Logged in. Token stored at ~/.config/universe-cli/token.");
|
|
1408
|
+
if (selfCheck.checked && selfCheck.warning) {
|
|
1409
|
+
const warn = deps.logWarn ?? ((s) => log3.warn(s));
|
|
1410
|
+
warn(selfCheck.warning);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
async function postLoginSelfCheck(token, env, deps) {
|
|
1415
|
+
const mkClient = deps.createProxyClient ?? createProxyClient;
|
|
1416
|
+
try {
|
|
1417
|
+
const baseUrl = env["UNIVERSE_PROXY_URL"] ?? DEFAULT_PROXY_URL2;
|
|
1418
|
+
const client = mkClient({
|
|
1419
|
+
baseUrl,
|
|
1420
|
+
getAuthToken: () => token,
|
|
1421
|
+
timeoutMs: parseFetchTimeoutMs(env)
|
|
1422
|
+
});
|
|
1423
|
+
const result = await client.whoami();
|
|
1424
|
+
const count = result.authorizedSites.length;
|
|
1425
|
+
if (count === 0) {
|
|
1426
|
+
return {
|
|
1427
|
+
checked: true,
|
|
1428
|
+
authorizedSitesCount: 0,
|
|
1429
|
+
warning: NO_SITES_WARNING
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
return { checked: true, authorizedSitesCount: count };
|
|
1433
|
+
} catch {
|
|
1434
|
+
return { checked: false, authorizedSitesCount: 0 };
|
|
1244
1435
|
}
|
|
1245
1436
|
}
|
|
1246
1437
|
|
|
1247
1438
|
// src/commands/logout.ts
|
|
1248
|
-
import { log as
|
|
1439
|
+
import { log as log4 } from "@clack/prompts";
|
|
1249
1440
|
function emitJson3(envelope) {
|
|
1250
1441
|
process.stdout.write(JSON.stringify(envelope) + "\n");
|
|
1251
1442
|
}
|
|
1252
1443
|
async function logout(options, deps = {}) {
|
|
1253
1444
|
const load = deps.loadToken ?? loadToken;
|
|
1254
1445
|
const del = deps.deleteToken ?? deleteToken;
|
|
1255
|
-
const success = deps.logSuccess ?? ((s) =>
|
|
1256
|
-
const info = deps.logInfo ?? ((s) =>
|
|
1446
|
+
const success = deps.logSuccess ?? ((s) => log4.success(s));
|
|
1447
|
+
const info = deps.logInfo ?? ((s) => log4.info(s));
|
|
1257
1448
|
const existing = await load();
|
|
1258
1449
|
await del();
|
|
1259
1450
|
if (options.json) {
|
|
@@ -1270,7 +1461,7 @@ async function logout(options, deps = {}) {
|
|
|
1270
1461
|
// src/commands/ls.ts
|
|
1271
1462
|
import { readFile as readFile3 } from "fs/promises";
|
|
1272
1463
|
import { resolve as resolve3 } from "path";
|
|
1273
|
-
import { log as
|
|
1464
|
+
import { log as log5 } from "@clack/prompts";
|
|
1274
1465
|
var defaultReadPlatformYaml2 = async (cwd) => {
|
|
1275
1466
|
return readFile3(resolve3(cwd, "platform.yaml"), "utf-8");
|
|
1276
1467
|
};
|
|
@@ -1320,9 +1511,9 @@ async function ls(options, deps = {}) {
|
|
|
1320
1511
|
const readYaml = deps.readPlatformYaml ?? defaultReadPlatformYaml2;
|
|
1321
1512
|
const resolveId = deps.resolveIdentity ?? resolveIdentity;
|
|
1322
1513
|
const mkClient = deps.createProxyClient ?? createProxyClient;
|
|
1323
|
-
const success = deps.logSuccess ?? ((s) =>
|
|
1324
|
-
const info = deps.logInfo ?? ((s) =>
|
|
1325
|
-
const error = deps.logError ?? ((s) =>
|
|
1514
|
+
const success = deps.logSuccess ?? ((s) => log5.success(s));
|
|
1515
|
+
const info = deps.logInfo ?? ((s) => log5.info(s));
|
|
1516
|
+
const error = deps.logError ?? ((s) => log5.error(s));
|
|
1326
1517
|
const exit = deps.exit ?? exitWithCode;
|
|
1327
1518
|
try {
|
|
1328
1519
|
const identity = await resolveId({ env });
|
|
@@ -1343,7 +1534,8 @@ async function ls(options, deps = {}) {
|
|
|
1343
1534
|
const baseUrl = env["UNIVERSE_PROXY_URL"] ?? DEFAULT_PROXY_URL;
|
|
1344
1535
|
const client = mkClient({
|
|
1345
1536
|
baseUrl,
|
|
1346
|
-
getAuthToken: () => identity.token
|
|
1537
|
+
getAuthToken: () => identity.token,
|
|
1538
|
+
timeoutMs: parseFetchTimeoutMs(env)
|
|
1347
1539
|
});
|
|
1348
1540
|
const raw = await client.siteDeploys({ site });
|
|
1349
1541
|
const sorted = [...raw].sort(
|
|
@@ -1367,11 +1559,9 @@ async function ls(options, deps = {}) {
|
|
|
1367
1559
|
success(formatTable(deploys));
|
|
1368
1560
|
} catch (err) {
|
|
1369
1561
|
const { code, message } = wrapProxyError("ls", err);
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
}
|
|
1373
|
-
error(message);
|
|
1374
|
-
}
|
|
1562
|
+
outputError({ json: options.json, command: "ls" }, code, message, {
|
|
1563
|
+
logError: error
|
|
1564
|
+
});
|
|
1375
1565
|
exit(code);
|
|
1376
1566
|
}
|
|
1377
1567
|
}
|
|
@@ -1379,7 +1569,7 @@ async function ls(options, deps = {}) {
|
|
|
1379
1569
|
// src/commands/promote.ts
|
|
1380
1570
|
import { readFile as readFile4 } from "fs/promises";
|
|
1381
1571
|
import { resolve as resolve4 } from "path";
|
|
1382
|
-
import { confirm, isCancel, log as
|
|
1572
|
+
import { confirm, isCancel, log as log6 } from "@clack/prompts";
|
|
1383
1573
|
var defaultPromptConfirm = async (msg) => {
|
|
1384
1574
|
const r = await confirm({ message: msg, initialValue: false });
|
|
1385
1575
|
if (isCancel(r)) return false;
|
|
@@ -1413,8 +1603,8 @@ async function promote(options, deps = {}) {
|
|
|
1413
1603
|
const readYaml = deps.readPlatformYaml ?? defaultReadPlatformYaml3;
|
|
1414
1604
|
const resolveId = deps.resolveIdentity ?? resolveIdentity;
|
|
1415
1605
|
const mkClient = deps.createProxyClient ?? createProxyClient;
|
|
1416
|
-
const success = deps.logSuccess ?? ((s) =>
|
|
1417
|
-
const error = deps.logError ?? ((s) =>
|
|
1606
|
+
const success = deps.logSuccess ?? ((s) => log6.success(s));
|
|
1607
|
+
const error = deps.logError ?? ((s) => log6.error(s));
|
|
1418
1608
|
const exit = deps.exit ?? exitWithCode;
|
|
1419
1609
|
const promptConfirm = deps.promptConfirm ?? defaultPromptConfirm;
|
|
1420
1610
|
try {
|
|
@@ -1428,7 +1618,8 @@ async function promote(options, deps = {}) {
|
|
|
1428
1618
|
const baseUrl = env["UNIVERSE_PROXY_URL"] ?? DEFAULT_PROXY_URL;
|
|
1429
1619
|
const client = mkClient({
|
|
1430
1620
|
baseUrl,
|
|
1431
|
-
getAuthToken: () => identity.token
|
|
1621
|
+
getAuthToken: () => identity.token,
|
|
1622
|
+
timeoutMs: parseFetchTimeoutMs(env)
|
|
1432
1623
|
});
|
|
1433
1624
|
let result;
|
|
1434
1625
|
if (options.from) {
|
|
@@ -1526,16 +1717,11 @@ async function promote(options, deps = {}) {
|
|
|
1526
1717
|
}
|
|
1527
1718
|
} catch (err) {
|
|
1528
1719
|
const { code, message } = wrapProxyError("promote", err);
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
emitJson5(envelope);
|
|
1535
|
-
}
|
|
1536
|
-
} else {
|
|
1537
|
-
error(message);
|
|
1538
|
-
}
|
|
1720
|
+
const extras = err instanceof AliasDriftError ? { current: err.current } : void 0;
|
|
1721
|
+
outputError({ json: options.json, command: "promote" }, code, message, {
|
|
1722
|
+
logError: error,
|
|
1723
|
+
extras
|
|
1724
|
+
});
|
|
1539
1725
|
exit(code);
|
|
1540
1726
|
}
|
|
1541
1727
|
}
|
|
@@ -1543,7 +1729,7 @@ async function promote(options, deps = {}) {
|
|
|
1543
1729
|
// src/commands/rollback.ts
|
|
1544
1730
|
import { readFile as readFile5 } from "fs/promises";
|
|
1545
1731
|
import { resolve as resolve5 } from "path";
|
|
1546
|
-
import { confirm as confirm2, isCancel as isCancel2, log as
|
|
1732
|
+
import { confirm as confirm2, isCancel as isCancel2, log as log7 } from "@clack/prompts";
|
|
1547
1733
|
var defaultPromptConfirm2 = async (msg) => {
|
|
1548
1734
|
const r = await confirm2({ message: msg, initialValue: false });
|
|
1549
1735
|
if (isCancel2(r)) return false;
|
|
@@ -1577,8 +1763,8 @@ async function rollback(options, deps = {}) {
|
|
|
1577
1763
|
const readYaml = deps.readPlatformYaml ?? defaultReadPlatformYaml4;
|
|
1578
1764
|
const resolveId = deps.resolveIdentity ?? resolveIdentity;
|
|
1579
1765
|
const mkClient = deps.createProxyClient ?? createProxyClient;
|
|
1580
|
-
const success = deps.logSuccess ?? ((s) =>
|
|
1581
|
-
const error = deps.logError ?? ((s) =>
|
|
1766
|
+
const success = deps.logSuccess ?? ((s) => log7.success(s));
|
|
1767
|
+
const error = deps.logError ?? ((s) => log7.error(s));
|
|
1582
1768
|
const exit = deps.exit ?? exitWithCode;
|
|
1583
1769
|
const promptConfirm = deps.promptConfirm ?? defaultPromptConfirm2;
|
|
1584
1770
|
try {
|
|
@@ -1597,7 +1783,8 @@ async function rollback(options, deps = {}) {
|
|
|
1597
1783
|
const baseUrl = env["UNIVERSE_PROXY_URL"] ?? DEFAULT_PROXY_URL;
|
|
1598
1784
|
const client = mkClient({
|
|
1599
1785
|
baseUrl,
|
|
1600
|
-
getAuthToken: () => identity.token
|
|
1786
|
+
getAuthToken: () => identity.token,
|
|
1787
|
+
timeoutMs: parseFetchTimeoutMs(env)
|
|
1601
1788
|
});
|
|
1602
1789
|
const to = options.to.trim();
|
|
1603
1790
|
const prod = await client.getAlias({
|
|
@@ -1650,23 +1837,18 @@ async function rollback(options, deps = {}) {
|
|
|
1650
1837
|
}
|
|
1651
1838
|
} catch (err) {
|
|
1652
1839
|
const { code, message } = wrapProxyError("rollback", err);
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
emitJson6(envelope);
|
|
1659
|
-
}
|
|
1660
|
-
} else {
|
|
1661
|
-
error(message);
|
|
1662
|
-
}
|
|
1840
|
+
const extras = err instanceof AliasDriftError ? { current: err.current } : void 0;
|
|
1841
|
+
outputError({ json: options.json, command: "rollback" }, code, message, {
|
|
1842
|
+
logError: error,
|
|
1843
|
+
extras
|
|
1844
|
+
});
|
|
1663
1845
|
exit(code);
|
|
1664
1846
|
}
|
|
1665
1847
|
}
|
|
1666
1848
|
|
|
1667
1849
|
// src/commands/whoami.ts
|
|
1668
|
-
import { log as
|
|
1669
|
-
var
|
|
1850
|
+
import { log as log8 } from "@clack/prompts";
|
|
1851
|
+
var DEFAULT_PROXY_URL3 = "https://uploads.freecode.camp";
|
|
1670
1852
|
function emitJson7(envelope) {
|
|
1671
1853
|
process.stdout.write(JSON.stringify(envelope) + "\n");
|
|
1672
1854
|
}
|
|
@@ -1674,24 +1856,26 @@ async function whoami(options, deps = {}) {
|
|
|
1674
1856
|
const env = deps.env ?? process.env;
|
|
1675
1857
|
const resolve6 = deps.resolveIdentity ?? resolveIdentity;
|
|
1676
1858
|
const mkClient = deps.createProxyClient ?? createProxyClient;
|
|
1677
|
-
const success = deps.logSuccess ?? ((s) =>
|
|
1678
|
-
const error = deps.logError ?? ((s) =>
|
|
1859
|
+
const success = deps.logSuccess ?? ((s) => log8.success(s));
|
|
1860
|
+
const error = deps.logError ?? ((s) => log8.error(s));
|
|
1679
1861
|
const exit = deps.exit ?? exitWithCode;
|
|
1680
1862
|
const identity = await resolve6({ env });
|
|
1681
1863
|
if (!identity) {
|
|
1682
1864
|
const msg = "No GitHub identity available. Run `universe login`, set $GITHUB_TOKEN, or install the gh CLI.";
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1865
|
+
outputError(
|
|
1866
|
+
{ json: options.json, command: "whoami" },
|
|
1867
|
+
EXIT_CREDENTIALS,
|
|
1868
|
+
msg,
|
|
1869
|
+
{ logError: error }
|
|
1870
|
+
);
|
|
1688
1871
|
exit(EXIT_CREDENTIALS);
|
|
1689
1872
|
return;
|
|
1690
1873
|
}
|
|
1691
|
-
const baseUrl = env["UNIVERSE_PROXY_URL"] ??
|
|
1874
|
+
const baseUrl = env["UNIVERSE_PROXY_URL"] ?? DEFAULT_PROXY_URL3;
|
|
1692
1875
|
const client = mkClient({
|
|
1693
1876
|
baseUrl,
|
|
1694
|
-
getAuthToken: () => identity.token
|
|
1877
|
+
getAuthToken: () => identity.token,
|
|
1878
|
+
timeoutMs: parseFetchTimeoutMs(env)
|
|
1695
1879
|
});
|
|
1696
1880
|
try {
|
|
1697
1881
|
const result = await client.whoami();
|
|
@@ -1717,17 +1901,15 @@ async function whoami(options, deps = {}) {
|
|
|
1717
1901
|
} catch (err) {
|
|
1718
1902
|
const exitCode = err instanceof CliError ? err.exitCode : EXIT_CREDENTIALS;
|
|
1719
1903
|
const message = err instanceof ProxyError ? `whoami failed (${err.code}): ${err.message}` : err instanceof Error ? err.message : String(err);
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
}
|
|
1723
|
-
error(message);
|
|
1724
|
-
}
|
|
1904
|
+
outputError({ json: options.json, command: "whoami" }, exitCode, message, {
|
|
1905
|
+
logError: error
|
|
1906
|
+
});
|
|
1725
1907
|
exit(exitCode);
|
|
1726
1908
|
}
|
|
1727
1909
|
}
|
|
1728
1910
|
|
|
1729
1911
|
// src/commands/sites/ls.ts
|
|
1730
|
-
import { log as
|
|
1912
|
+
import { log as log9 } from "@clack/prompts";
|
|
1731
1913
|
|
|
1732
1914
|
// src/commands/sites/_shared.ts
|
|
1733
1915
|
function emitJson8(envelope) {
|
|
@@ -1751,7 +1933,8 @@ async function setupClient(deps) {
|
|
|
1751
1933
|
const baseUrl = env["UNIVERSE_PROXY_URL"] ?? DEFAULT_PROXY_URL;
|
|
1752
1934
|
const client = mkClient({
|
|
1753
1935
|
baseUrl,
|
|
1754
|
-
getAuthToken: () => identity.token
|
|
1936
|
+
getAuthToken: () => identity.token,
|
|
1937
|
+
timeoutMs: parseFetchTimeoutMs(env)
|
|
1755
1938
|
});
|
|
1756
1939
|
return { client, identitySource: identity.source };
|
|
1757
1940
|
}
|
|
@@ -1774,11 +1957,11 @@ function formatTable2(rows) {
|
|
|
1774
1957
|
}
|
|
1775
1958
|
async function ls2(options, deps = {}) {
|
|
1776
1959
|
const command = "sites ls";
|
|
1777
|
-
const success = deps.logSuccess ?? ((s) =>
|
|
1778
|
-
const error = deps.logError ?? ((s) =>
|
|
1960
|
+
const success = deps.logSuccess ?? ((s) => log9.message(s));
|
|
1961
|
+
const error = deps.logError ?? ((s) => log9.error(s));
|
|
1779
1962
|
const exit = deps.exit ?? exitWithCode;
|
|
1780
1963
|
try {
|
|
1781
|
-
const { client } = await setupClient(deps);
|
|
1964
|
+
const { client, identitySource } = await setupClient(deps);
|
|
1782
1965
|
let rows = await client.listSites();
|
|
1783
1966
|
let scope = "all";
|
|
1784
1967
|
if (options.mine) {
|
|
@@ -1792,7 +1975,8 @@ async function ls2(options, deps = {}) {
|
|
|
1792
1975
|
buildEnvelope(command, true, {
|
|
1793
1976
|
count: rows.length,
|
|
1794
1977
|
scope,
|
|
1795
|
-
sites: rows
|
|
1978
|
+
sites: rows,
|
|
1979
|
+
identitySource
|
|
1796
1980
|
})
|
|
1797
1981
|
);
|
|
1798
1982
|
} else {
|
|
@@ -1800,28 +1984,26 @@ async function ls2(options, deps = {}) {
|
|
|
1800
1984
|
}
|
|
1801
1985
|
} catch (err) {
|
|
1802
1986
|
const { code, message } = wrapProxyError(command, err);
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
}
|
|
1806
|
-
error(message);
|
|
1807
|
-
}
|
|
1987
|
+
outputError({ json: options.json, command }, code, message, {
|
|
1988
|
+
logError: error
|
|
1989
|
+
});
|
|
1808
1990
|
exit(code);
|
|
1809
1991
|
}
|
|
1810
1992
|
}
|
|
1811
1993
|
|
|
1812
1994
|
// src/commands/sites/register.ts
|
|
1813
|
-
import { log as
|
|
1995
|
+
import { log as log10 } from "@clack/prompts";
|
|
1814
1996
|
async function register(options, deps = {}) {
|
|
1815
1997
|
const command = "sites register";
|
|
1816
|
-
const success = deps.logSuccess ?? ((s) =>
|
|
1817
|
-
const error = deps.logError ?? ((s) =>
|
|
1998
|
+
const success = deps.logSuccess ?? ((s) => log10.success(s));
|
|
1999
|
+
const error = deps.logError ?? ((s) => log10.error(s));
|
|
1818
2000
|
const exit = deps.exit ?? exitWithCode;
|
|
1819
2001
|
try {
|
|
1820
2002
|
if (!options.slug || options.slug.trim().length === 0) {
|
|
1821
2003
|
throw new UsageError("slug is required (positional argument)");
|
|
1822
2004
|
}
|
|
1823
2005
|
const teams = parseTeamsFlag(options.team);
|
|
1824
|
-
const { client } = await setupClient(deps);
|
|
2006
|
+
const { client, identitySource } = await setupClient(deps);
|
|
1825
2007
|
const row = await client.registerSite({
|
|
1826
2008
|
slug: options.slug,
|
|
1827
2009
|
teams: teams.length > 0 ? teams : void 0
|
|
@@ -1832,7 +2014,8 @@ async function register(options, deps = {}) {
|
|
|
1832
2014
|
slug: row.slug,
|
|
1833
2015
|
teams: row.teams,
|
|
1834
2016
|
createdAt: row.createdAt,
|
|
1835
|
-
createdBy: row.createdBy
|
|
2017
|
+
createdBy: row.createdBy,
|
|
2018
|
+
identitySource
|
|
1836
2019
|
})
|
|
1837
2020
|
);
|
|
1838
2021
|
} else {
|
|
@@ -1849,33 +2032,32 @@ async function register(options, deps = {}) {
|
|
|
1849
2032
|
}
|
|
1850
2033
|
} catch (err) {
|
|
1851
2034
|
const { code, message } = wrapProxyError(command, err);
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
}
|
|
1855
|
-
error(message);
|
|
1856
|
-
}
|
|
2035
|
+
outputError({ json: options.json, command }, code, message, {
|
|
2036
|
+
logError: error
|
|
2037
|
+
});
|
|
1857
2038
|
exit(code);
|
|
1858
2039
|
}
|
|
1859
2040
|
}
|
|
1860
2041
|
|
|
1861
2042
|
// src/commands/sites/rm.ts
|
|
1862
|
-
import { log as
|
|
2043
|
+
import { log as log11 } from "@clack/prompts";
|
|
1863
2044
|
async function rm2(options, deps = {}) {
|
|
1864
2045
|
const command = "sites rm";
|
|
1865
|
-
const success = deps.logSuccess ?? ((s) =>
|
|
1866
|
-
const error = deps.logError ?? ((s) =>
|
|
2046
|
+
const success = deps.logSuccess ?? ((s) => log11.success(s));
|
|
2047
|
+
const error = deps.logError ?? ((s) => log11.error(s));
|
|
1867
2048
|
const exit = deps.exit ?? exitWithCode;
|
|
1868
2049
|
try {
|
|
1869
2050
|
if (!options.slug || options.slug.trim().length === 0) {
|
|
1870
2051
|
throw new UsageError("slug is required (positional argument)");
|
|
1871
2052
|
}
|
|
1872
|
-
const { client } = await setupClient(deps);
|
|
2053
|
+
const { client, identitySource } = await setupClient(deps);
|
|
1873
2054
|
await client.deleteSite({ slug: options.slug });
|
|
1874
2055
|
if (options.json) {
|
|
1875
2056
|
emitJson8(
|
|
1876
2057
|
buildEnvelope(command, true, {
|
|
1877
2058
|
slug: options.slug,
|
|
1878
|
-
deleted: true
|
|
2059
|
+
deleted: true,
|
|
2060
|
+
identitySource
|
|
1879
2061
|
})
|
|
1880
2062
|
);
|
|
1881
2063
|
} else {
|
|
@@ -1890,21 +2072,19 @@ async function rm2(options, deps = {}) {
|
|
|
1890
2072
|
}
|
|
1891
2073
|
} catch (err) {
|
|
1892
2074
|
const { code, message } = wrapProxyError(command, err);
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
}
|
|
1896
|
-
error(message);
|
|
1897
|
-
}
|
|
2075
|
+
outputError({ json: options.json, command }, code, message, {
|
|
2076
|
+
logError: error
|
|
2077
|
+
});
|
|
1898
2078
|
exit(code);
|
|
1899
2079
|
}
|
|
1900
2080
|
}
|
|
1901
2081
|
|
|
1902
2082
|
// src/commands/sites/update.ts
|
|
1903
|
-
import { log as
|
|
2083
|
+
import { log as log12 } from "@clack/prompts";
|
|
1904
2084
|
async function update(options, deps = {}) {
|
|
1905
2085
|
const command = "sites update";
|
|
1906
|
-
const success = deps.logSuccess ?? ((s) =>
|
|
1907
|
-
const error = deps.logError ?? ((s) =>
|
|
2086
|
+
const success = deps.logSuccess ?? ((s) => log12.success(s));
|
|
2087
|
+
const error = deps.logError ?? ((s) => log12.error(s));
|
|
1908
2088
|
const exit = deps.exit ?? exitWithCode;
|
|
1909
2089
|
try {
|
|
1910
2090
|
if (!options.slug || options.slug.trim().length === 0) {
|
|
@@ -1916,7 +2096,7 @@ async function update(options, deps = {}) {
|
|
|
1916
2096
|
"--team is required with at least one slug; use `sites rm` to remove a site"
|
|
1917
2097
|
);
|
|
1918
2098
|
}
|
|
1919
|
-
const { client } = await setupClient(deps);
|
|
2099
|
+
const { client, identitySource } = await setupClient(deps);
|
|
1920
2100
|
const row = await client.updateSite({
|
|
1921
2101
|
slug: options.slug,
|
|
1922
2102
|
teams
|
|
@@ -1926,7 +2106,8 @@ async function update(options, deps = {}) {
|
|
|
1926
2106
|
buildEnvelope(command, true, {
|
|
1927
2107
|
slug: row.slug,
|
|
1928
2108
|
teams: row.teams,
|
|
1929
|
-
updatedAt: row.updatedAt
|
|
2109
|
+
updatedAt: row.updatedAt,
|
|
2110
|
+
identitySource
|
|
1930
2111
|
})
|
|
1931
2112
|
);
|
|
1932
2113
|
} else {
|
|
@@ -1942,81 +2123,15 @@ async function update(options, deps = {}) {
|
|
|
1942
2123
|
}
|
|
1943
2124
|
} catch (err) {
|
|
1944
2125
|
const { code, message } = wrapProxyError(command, err);
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
}
|
|
1948
|
-
error(message);
|
|
1949
|
-
}
|
|
2126
|
+
outputError({ json: options.json, command }, code, message, {
|
|
2127
|
+
logError: error
|
|
2128
|
+
});
|
|
1950
2129
|
exit(code);
|
|
1951
2130
|
}
|
|
1952
2131
|
}
|
|
1953
2132
|
|
|
1954
|
-
// src/output/format.ts
|
|
1955
|
-
import { log as log12 } from "@clack/prompts";
|
|
1956
|
-
|
|
1957
|
-
// src/output/redact.ts
|
|
1958
|
-
var AWS_KEY_PREFIX_PATTERN = /(?:AKIA|ASIA|AROA|AIDA|ACCA|ANPA|ABIA|AGPA)[A-Z0-9]{12,}/g;
|
|
1959
|
-
var URL_CREDS_PATTERN = /https?:\/\/[^@\s]+@/g;
|
|
1960
|
-
var CREDENTIAL_CONTEXT_PATTERN = /(?:access_key_id|secret_access_key|accessKeyId|secretAccessKey|secret|password|token|key|credential|auth)\s*[=:]\s*([A-Za-z0-9/+=]{21,})/gi;
|
|
1961
|
-
var HEX_CREDENTIAL_CONTEXT_PATTERN = /(?:secret|password|token|key|credential|auth|access_key_id|secret_access_key)\s*[=:]\s*([a-f0-9]{32,})/gi;
|
|
1962
|
-
var JSON_CREDENTIAL_PATTERN = /"(?:secret|password|token|key|credential|auth|access_key_id|secret_access_key|accessKeyId|secretAccessKey)"\s*:\s*"[^"]+"/gi;
|
|
1963
|
-
var BEARER_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]+/gi;
|
|
1964
|
-
function maskAwsKey(match) {
|
|
1965
|
-
return match.slice(0, 4) + "****" + match.slice(-4);
|
|
1966
|
-
}
|
|
1967
|
-
function maskUrlCreds(match) {
|
|
1968
|
-
const atIndex = match.lastIndexOf("@");
|
|
1969
|
-
const protocolEnd = match.indexOf("://") + 3;
|
|
1970
|
-
return match.slice(0, protocolEnd) + "****:****@" + match.slice(atIndex + 1);
|
|
1971
|
-
}
|
|
1972
|
-
function redact(value) {
|
|
1973
|
-
let result = value;
|
|
1974
|
-
result = result.replace(URL_CREDS_PATTERN, maskUrlCreds);
|
|
1975
|
-
result = result.replace(AWS_KEY_PREFIX_PATTERN, maskAwsKey);
|
|
1976
|
-
result = result.replace(BEARER_PATTERN, "Bearer ****");
|
|
1977
|
-
result = result.replace(JSON_CREDENTIAL_PATTERN, (match) => {
|
|
1978
|
-
const colonIndex = match.indexOf(":");
|
|
1979
|
-
return match.slice(0, colonIndex + 1) + '"****"';
|
|
1980
|
-
});
|
|
1981
|
-
result = result.replace(
|
|
1982
|
-
CREDENTIAL_CONTEXT_PATTERN,
|
|
1983
|
-
(_match, _secret, _offset, _full) => {
|
|
1984
|
-
const eqIndex = _match.indexOf("=");
|
|
1985
|
-
const colonIndex = _match.indexOf(":");
|
|
1986
|
-
const sepIndex = eqIndex >= 0 && colonIndex >= 0 ? Math.min(eqIndex, colonIndex) : eqIndex >= 0 ? eqIndex : colonIndex;
|
|
1987
|
-
const prefix = _match.slice(0, sepIndex + 1);
|
|
1988
|
-
return prefix + "****";
|
|
1989
|
-
}
|
|
1990
|
-
);
|
|
1991
|
-
result = result.replace(HEX_CREDENTIAL_CONTEXT_PATTERN, (_match, _secret) => {
|
|
1992
|
-
const eqIndex = _match.indexOf("=");
|
|
1993
|
-
const colonIndex = _match.indexOf(":");
|
|
1994
|
-
const sepIndex = eqIndex >= 0 && colonIndex >= 0 ? Math.min(eqIndex, colonIndex) : eqIndex >= 0 ? eqIndex : colonIndex;
|
|
1995
|
-
const prefix = _match.slice(0, sepIndex + 1);
|
|
1996
|
-
return prefix + "****";
|
|
1997
|
-
});
|
|
1998
|
-
return result;
|
|
1999
|
-
}
|
|
2000
|
-
|
|
2001
|
-
// src/output/format.ts
|
|
2002
|
-
function outputError(ctx, code, message, issues) {
|
|
2003
|
-
const redactedMessage = redact(message);
|
|
2004
|
-
const redactedIssues = issues?.map(redact);
|
|
2005
|
-
if (ctx.json) {
|
|
2006
|
-
const envelope = buildErrorEnvelope(
|
|
2007
|
-
ctx.command,
|
|
2008
|
-
code,
|
|
2009
|
-
redactedMessage,
|
|
2010
|
-
redactedIssues
|
|
2011
|
-
);
|
|
2012
|
-
process.stdout.write(JSON.stringify(envelope) + "\n");
|
|
2013
|
-
} else {
|
|
2014
|
-
log12.error(redactedMessage);
|
|
2015
|
-
}
|
|
2016
|
-
}
|
|
2017
|
-
|
|
2018
2133
|
// src/cli.ts
|
|
2019
|
-
var version = true ? "0.
|
|
2134
|
+
var version = true ? "0.7.1" : "0.0.0";
|
|
2020
2135
|
function handleActionError(command, json, err) {
|
|
2021
2136
|
const ctx = { json, command };
|
|
2022
2137
|
const message = err instanceof Error ? err.message : "unknown error";
|