@dropthis/cli 0.30.1 → 0.33.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 +36 -10
- package/dist/cli.cjs +678 -115
- package/dist/cli.cjs.map +1 -1
- package/node_modules/@dropthis/node/README.md +18 -7
- package/node_modules/@dropthis/node/dist/edge.cjs +37 -1
- package/node_modules/@dropthis/node/dist/edge.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/edge.d.cts +1 -1
- package/node_modules/@dropthis/node/dist/edge.d.ts +1 -1
- package/node_modules/@dropthis/node/dist/edge.mjs +37 -1
- package/node_modules/@dropthis/node/dist/edge.mjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.cjs +131 -1
- package/node_modules/@dropthis/node/dist/index.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.d.cts +64 -3
- package/node_modules/@dropthis/node/dist/index.d.ts +64 -3
- package/node_modules/@dropthis/node/dist/index.mjs +126 -1
- package/node_modules/@dropthis/node/dist/index.mjs.map +1 -1
- package/node_modules/@dropthis/node/dist/{workspaces-BXW942z-.d.cts → workspaces-CebiV4DS.d.cts} +107 -11
- package/node_modules/@dropthis/node/dist/{workspaces-BXW942z-.d.ts → workspaces-CebiV4DS.d.ts} +107 -11
- package/node_modules/@dropthis/node/package.json +1 -1
- package/package.json +49 -49
package/dist/cli.cjs
CHANGED
|
@@ -206,6 +206,13 @@ function apiErrorEnvelope(error2) {
|
|
|
206
206
|
...error2.requestId ? { request_id: error2.requestId } : {},
|
|
207
207
|
...error2.suggestion ? { suggestion: error2.suggestion } : {},
|
|
208
208
|
...error2.retryable !== void 0 && error2.retryable !== null ? { retryable: error2.retryable } : {},
|
|
209
|
+
...error2.feature ? { feature: error2.feature } : {},
|
|
210
|
+
...error2.currentPlan ? { current_plan: error2.currentPlan } : {},
|
|
211
|
+
...error2.requiredPlan ? { required_plan: error2.requiredPlan } : {},
|
|
212
|
+
...error2.upgradeUrl ? { upgrade_url: error2.upgradeUrl } : {},
|
|
213
|
+
...typeof error2.limit === "number" ? { limit: error2.limit } : {},
|
|
214
|
+
...typeof error2.used === "number" ? { used: error2.used } : {},
|
|
215
|
+
...typeof error2.requested === "number" ? { requested: error2.requested } : {},
|
|
209
216
|
...failures.length ? { failures } : {},
|
|
210
217
|
next_action: nextActionForApiError(error2)
|
|
211
218
|
}
|
|
@@ -298,6 +305,16 @@ function exitCodeFor(code) {
|
|
|
298
305
|
if (code === "verify_timeout") return 7;
|
|
299
306
|
return 1;
|
|
300
307
|
}
|
|
308
|
+
var EXIT_CODES = {
|
|
309
|
+
"0": "success",
|
|
310
|
+
"1": "api_error \u2014 the server returned an error (see the error envelope)",
|
|
311
|
+
"2": "invalid_usage \u2014 bad arguments, bad options, or an unknown command",
|
|
312
|
+
"3": "auth_error \u2014 missing or invalid credential; re-authenticate (dropthis login)",
|
|
313
|
+
"4": "local_input_error \u2014 a local file or path could not be read",
|
|
314
|
+
"5": "network_error \u2014 could not reach the API; safe to retry",
|
|
315
|
+
"6": "verify_pending \u2014 a domain is not verified yet; retry later (domains verify)",
|
|
316
|
+
"7": "verify_timeout \u2014 domain verification timed out while waiting (--wait)"
|
|
317
|
+
};
|
|
301
318
|
|
|
302
319
|
// src/program.ts
|
|
303
320
|
var import_commander = require("commander");
|
|
@@ -317,7 +334,8 @@ async function resolveCredential(input) {
|
|
|
317
334
|
...stored.keyId ? { keyId: stored.keyId } : {},
|
|
318
335
|
...stored.keyLast4 ? { keyLast4: stored.keyLast4 } : {},
|
|
319
336
|
...stored.accountId ? { accountId: stored.accountId } : {},
|
|
320
|
-
...stored.email ? { email: stored.email } : {}
|
|
337
|
+
...stored.email ? { email: stored.email } : {},
|
|
338
|
+
...stored.scopes?.length ? { scopes: stored.scopes } : {}
|
|
321
339
|
};
|
|
322
340
|
}
|
|
323
341
|
async function requireCredential(input) {
|
|
@@ -473,6 +491,14 @@ function writeApiError(deps, details) {
|
|
|
473
491
|
deps.stderr(` ${f.path}: ${f.reason}
|
|
474
492
|
`);
|
|
475
493
|
}
|
|
494
|
+
if (details.code === "feature_not_in_plan" || details.code === "quota_exceeded") {
|
|
495
|
+
if (details.currentPlan && details.requiredPlan) {
|
|
496
|
+
deps.stderr(
|
|
497
|
+
`${hint(`Plan: ${details.currentPlan} \u2192 needs ${details.requiredPlan}`)}
|
|
498
|
+
`
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
476
502
|
const nextAction = nextActionForApiError(details, "human");
|
|
477
503
|
if (nextAction) deps.stderr(`${hint(nextAction)}
|
|
478
504
|
`);
|
|
@@ -546,7 +572,8 @@ async function runAccountGet(_input, deps) {
|
|
|
546
572
|
pairs.push(["Workspace", `${String(ws.name)} (${String(ws.kind)})${role}`]);
|
|
547
573
|
}
|
|
548
574
|
const usage = data?.usage;
|
|
549
|
-
const
|
|
575
|
+
const entitlements = data?.entitlements;
|
|
576
|
+
const limits = entitlements?.limits;
|
|
550
577
|
if (typeof usage?.storageUsedBytes === "number") {
|
|
551
578
|
if (typeof limits?.maxStorageBytes === "number") {
|
|
552
579
|
pairs.push([
|
|
@@ -563,6 +590,9 @@ async function runAccountGet(_input, deps) {
|
|
|
563
590
|
`${usage.customDomainsUsed} of ${limits.maxCustomHostnames}`
|
|
564
591
|
]);
|
|
565
592
|
}
|
|
593
|
+
if (typeof usage?.seatsUsed === "number" && typeof limits?.seatLimit === "number") {
|
|
594
|
+
pairs.push(["Seats", `${usage.seatsUsed} of ${limits.seatLimit}`]);
|
|
595
|
+
}
|
|
566
596
|
writeKv(deps, pairs, { ok: true, account: result.data });
|
|
567
597
|
if (typeof data?.upgradeUrl === "string") {
|
|
568
598
|
deps.stderr(`${hint(`Upgrade: ${data.upgradeUrl}`)}
|
|
@@ -654,14 +684,55 @@ async function runApiKeysCreate(input, deps) {
|
|
|
654
684
|
} catch {
|
|
655
685
|
return writeAuthError(deps);
|
|
656
686
|
}
|
|
657
|
-
const
|
|
687
|
+
const keyType = input.type ?? "delegated";
|
|
688
|
+
if (input.workspace && keyType !== "service") {
|
|
689
|
+
return writeError(
|
|
690
|
+
deps,
|
|
691
|
+
"invalid_usage",
|
|
692
|
+
"--workspace is only valid with --service (it pins a CI service key to one workspace). A delegated login key is account-scoped and switchable \u2014 use `dropthis workspace use <slug>` to change its active workspace."
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
if (input.allowedWorkspaces?.length && keyType === "service") {
|
|
696
|
+
return writeError(
|
|
697
|
+
deps,
|
|
698
|
+
"invalid_usage",
|
|
699
|
+
"--allowed-workspace is only valid for delegated keys; do not combine it with --service."
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
if (keyType === "service" && !input.workspace) {
|
|
703
|
+
return writeError(
|
|
704
|
+
deps,
|
|
705
|
+
"invalid_usage",
|
|
706
|
+
"Service keys must be pinned to a workspace.",
|
|
707
|
+
"Run: dropthis workspace list to see slugs, then: dropthis api-keys create --service --workspace <slug>"
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
const label = input.label ?? (keyType === "service" ? `Service key${input.workspace ? ` (${input.workspace})` : ""}` : "CLI key");
|
|
711
|
+
const createInput = {
|
|
712
|
+
label,
|
|
713
|
+
type: keyType
|
|
714
|
+
};
|
|
715
|
+
if (keyType === "service" && input.workspace) {
|
|
716
|
+
createInput.workspace = input.workspace;
|
|
717
|
+
}
|
|
718
|
+
if (input.allowedWorkspaces?.length) {
|
|
719
|
+
createInput.allowedWorkspaces = input.allowedWorkspaces;
|
|
720
|
+
}
|
|
721
|
+
const result = await deps.client.apiKeys.create(createInput);
|
|
658
722
|
if (result.error) return writeApiError(deps, result.error);
|
|
659
723
|
const data = result.data;
|
|
660
724
|
const pairs = [];
|
|
661
725
|
if (data.id) pairs.push(["ID", String(data.id)]);
|
|
662
726
|
if (data.key) pairs.push(["Key", String(data.key)]);
|
|
663
727
|
if (data.keyLast4) pairs.push(["Last 4", String(data.keyLast4)]);
|
|
728
|
+
if (data.label) pairs.push(["Label", String(data.label)]);
|
|
664
729
|
writeKv(deps, pairs, { ok: true, api_key: result.data });
|
|
730
|
+
if (deps.outputMode === "human") {
|
|
731
|
+
deps.stderr(
|
|
732
|
+
`${hint("Store this key now \u2014 it will not be shown again.")}
|
|
733
|
+
`
|
|
734
|
+
);
|
|
735
|
+
}
|
|
665
736
|
return { exitCode: 0 };
|
|
666
737
|
}
|
|
667
738
|
async function runApiKeysList(_input, deps) {
|
|
@@ -826,7 +897,10 @@ var COMMAND_ANNOTATIONS = {
|
|
|
826
897
|
},
|
|
827
898
|
"api-keys create": {
|
|
828
899
|
auth: "required",
|
|
829
|
-
examples: [
|
|
900
|
+
examples: [
|
|
901
|
+
"dropthis api-keys create --label CI --json",
|
|
902
|
+
"dropthis api-keys create --service --workspace acme --json"
|
|
903
|
+
]
|
|
830
904
|
},
|
|
831
905
|
"api-keys list": {
|
|
832
906
|
auth: "required",
|
|
@@ -851,17 +925,6 @@ var COMMAND_ANNOTATIONS = {
|
|
|
851
925
|
"dropthis workspace use ws_team123"
|
|
852
926
|
]
|
|
853
927
|
},
|
|
854
|
-
keys: {
|
|
855
|
-
auth: "required",
|
|
856
|
-
examples: ["dropthis keys create --service --workspace acme --json"]
|
|
857
|
-
},
|
|
858
|
-
"keys create": {
|
|
859
|
-
auth: "required",
|
|
860
|
-
examples: [
|
|
861
|
-
"dropthis keys create --json",
|
|
862
|
-
"dropthis keys create --service --workspace acme --json"
|
|
863
|
-
]
|
|
864
|
-
},
|
|
865
928
|
login: {
|
|
866
929
|
examples: [
|
|
867
930
|
"dropthis login",
|
|
@@ -889,7 +952,9 @@ var COMMAND_ANNOTATIONS = {
|
|
|
889
952
|
auth: "required",
|
|
890
953
|
examples: ["dropthis account delete --yes --json"]
|
|
891
954
|
},
|
|
892
|
-
doctor: {
|
|
955
|
+
doctor: {
|
|
956
|
+
examples: ["dropthis doctor --json", "dropthis doctor --online --json"]
|
|
957
|
+
},
|
|
893
958
|
upgrade: { examples: ["dropthis upgrade", "dropthis upgrade --json"] },
|
|
894
959
|
commands: { examples: ["dropthis commands --json"] }
|
|
895
960
|
};
|
|
@@ -916,6 +981,12 @@ function toEntry(cmd, path) {
|
|
|
916
981
|
function buildCatalog(program) {
|
|
917
982
|
return program.commands.map((cmd) => toEntry(cmd, []));
|
|
918
983
|
}
|
|
984
|
+
function buildGlobalOptions(program) {
|
|
985
|
+
return program.options.map((o) => ({
|
|
986
|
+
flags: o.flags,
|
|
987
|
+
description: o.description
|
|
988
|
+
}));
|
|
989
|
+
}
|
|
919
990
|
|
|
920
991
|
// src/commands/commands.ts
|
|
921
992
|
async function runCommands(_input, deps) {
|
|
@@ -923,7 +994,9 @@ async function runCommands(_input, deps) {
|
|
|
923
994
|
`${JSON.stringify({
|
|
924
995
|
ok: true,
|
|
925
996
|
output: "JSON by default in CI, pipes, non-TTY, --json, or --quiet.",
|
|
926
|
-
commands: buildCatalog(deps.program)
|
|
997
|
+
commands: buildCatalog(deps.program),
|
|
998
|
+
global_options: buildGlobalOptions(deps.program),
|
|
999
|
+
exit_codes: EXIT_CODES
|
|
927
1000
|
})}
|
|
928
1001
|
`
|
|
929
1002
|
);
|
|
@@ -1013,10 +1086,76 @@ function spreadData(data) {
|
|
|
1013
1086
|
}
|
|
1014
1087
|
|
|
1015
1088
|
// src/version.ts
|
|
1016
|
-
var CLI_VERSION = true ? "0.
|
|
1089
|
+
var CLI_VERSION = true ? "0.33.0" : "0.0.0-dev";
|
|
1017
1090
|
|
|
1018
1091
|
// src/commands/doctor.ts
|
|
1019
|
-
async function
|
|
1092
|
+
async function onlineChecks(deps, hasCredential) {
|
|
1093
|
+
if (!hasCredential) {
|
|
1094
|
+
return {
|
|
1095
|
+
checks: [
|
|
1096
|
+
{
|
|
1097
|
+
name: "auth",
|
|
1098
|
+
status: "fail",
|
|
1099
|
+
detail: "No credential found \u2014 run `dropthis login` or set DROPTHIS_API_KEY."
|
|
1100
|
+
}
|
|
1101
|
+
],
|
|
1102
|
+
exitCode: exitCodeFor("auth_error")
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
const account = await deps.client.account.get();
|
|
1106
|
+
if (account.error) {
|
|
1107
|
+
const code = cliErrorCodeFor(account.error);
|
|
1108
|
+
const isAuth = code === "auth_error";
|
|
1109
|
+
return {
|
|
1110
|
+
checks: [
|
|
1111
|
+
{
|
|
1112
|
+
name: "api_reachable",
|
|
1113
|
+
status: isAuth ? "ok" : "fail",
|
|
1114
|
+
detail: isAuth ? "reached the API" : `could not reach the API: ${account.error.message}`
|
|
1115
|
+
},
|
|
1116
|
+
{
|
|
1117
|
+
name: "auth",
|
|
1118
|
+
status: isAuth ? "fail" : "warn",
|
|
1119
|
+
detail: isAuth ? "credential rejected \u2014 re-authenticate with `dropthis login`" : account.error.message
|
|
1120
|
+
}
|
|
1121
|
+
],
|
|
1122
|
+
exitCode: exitCodeFor(code)
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
const data = account.data;
|
|
1126
|
+
const checks = [
|
|
1127
|
+
{ name: "api_reachable", status: "ok", detail: "reached the API" },
|
|
1128
|
+
{ name: "auth", status: "ok", detail: "credential accepted" }
|
|
1129
|
+
];
|
|
1130
|
+
const ws = data?.workspace;
|
|
1131
|
+
checks.push(
|
|
1132
|
+
ws?.name ? {
|
|
1133
|
+
name: "workspace",
|
|
1134
|
+
status: "ok",
|
|
1135
|
+
detail: `active: ${String(ws.name)} (${String(ws.kind)})`
|
|
1136
|
+
} : {
|
|
1137
|
+
name: "workspace",
|
|
1138
|
+
status: "warn",
|
|
1139
|
+
detail: "no active workspace resolved \u2014 pass --workspace or run `dropthis workspace use`"
|
|
1140
|
+
}
|
|
1141
|
+
);
|
|
1142
|
+
if (data?.plan) {
|
|
1143
|
+
checks.push({ name: "plan", status: "ok", detail: String(data.plan) });
|
|
1144
|
+
}
|
|
1145
|
+
const domains = await deps.client.domains.list();
|
|
1146
|
+
if (!domains.error) {
|
|
1147
|
+
const list = domains.data?.domains ?? [];
|
|
1148
|
+
const live = list.filter((d) => d.status === "live").length;
|
|
1149
|
+
const pending = list.length - live;
|
|
1150
|
+
checks.push({
|
|
1151
|
+
name: "domains",
|
|
1152
|
+
status: pending > 0 ? "warn" : "ok",
|
|
1153
|
+
detail: `${list.length} connected, ${live} live${pending > 0 ? `, ${pending} pending verification` : ""}`
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
return { checks, exitCode: 0 };
|
|
1157
|
+
}
|
|
1158
|
+
async function runDoctor(input, deps) {
|
|
1020
1159
|
const stored = await deps.store.read();
|
|
1021
1160
|
const credential = await resolveCredential({
|
|
1022
1161
|
env: deps.env,
|
|
@@ -1029,13 +1168,30 @@ async function runDoctor(_input, deps) {
|
|
|
1029
1168
|
["Auth", authSource],
|
|
1030
1169
|
["Storage", storageBackend]
|
|
1031
1170
|
];
|
|
1171
|
+
if (!input.online) {
|
|
1172
|
+
writeKv(deps, pairs, {
|
|
1173
|
+
ok: true,
|
|
1174
|
+
version: CLI_VERSION,
|
|
1175
|
+
auth: { source: authSource },
|
|
1176
|
+
storage: { backend: storageBackend }
|
|
1177
|
+
});
|
|
1178
|
+
return { exitCode: 0 };
|
|
1179
|
+
}
|
|
1180
|
+
const { checks, exitCode } = await onlineChecks(
|
|
1181
|
+
deps,
|
|
1182
|
+
credential !== void 0
|
|
1183
|
+
);
|
|
1184
|
+
for (const c of checks) {
|
|
1185
|
+
pairs.push([c.name, `${c.status} \u2014 ${c.detail}`]);
|
|
1186
|
+
}
|
|
1032
1187
|
writeKv(deps, pairs, {
|
|
1033
|
-
ok:
|
|
1188
|
+
ok: exitCode === 0,
|
|
1034
1189
|
version: CLI_VERSION,
|
|
1035
1190
|
auth: { source: authSource },
|
|
1036
|
-
storage: { backend: storageBackend }
|
|
1191
|
+
storage: { backend: storageBackend },
|
|
1192
|
+
checks
|
|
1037
1193
|
});
|
|
1038
|
-
return { exitCode
|
|
1194
|
+
return { exitCode };
|
|
1039
1195
|
}
|
|
1040
1196
|
|
|
1041
1197
|
// src/commands/domains.ts
|
|
@@ -1616,8 +1772,8 @@ async function runDropsDelete(target, input, deps) {
|
|
|
1616
1772
|
return { exitCode: 0 };
|
|
1617
1773
|
}
|
|
1618
1774
|
|
|
1619
|
-
// src/commands/
|
|
1620
|
-
async function
|
|
1775
|
+
// src/commands/invitations.ts
|
|
1776
|
+
async function runInvitationsList(_input, deps) {
|
|
1621
1777
|
try {
|
|
1622
1778
|
await requireCredential({
|
|
1623
1779
|
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
@@ -1627,45 +1783,67 @@ async function runKeysCreate(input, deps) {
|
|
|
1627
1783
|
} catch {
|
|
1628
1784
|
return writeAuthError(deps);
|
|
1629
1785
|
}
|
|
1630
|
-
const
|
|
1631
|
-
if (
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1786
|
+
const result = await deps.client.invitations.list();
|
|
1787
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
1788
|
+
const raw = unwrapListData(result.data, "invitations");
|
|
1789
|
+
const items = Array.isArray(raw) ? raw : [];
|
|
1790
|
+
if (deps.outputMode === "human") {
|
|
1791
|
+
if (items.length === 0) {
|
|
1792
|
+
writeEmpty(deps, "No pending invitations.", {
|
|
1793
|
+
ok: true,
|
|
1794
|
+
invitations: []
|
|
1795
|
+
});
|
|
1796
|
+
} else {
|
|
1797
|
+
for (const inv of items) {
|
|
1798
|
+
deps.stdout(`${inv.email} ${inv.role} ${inv.status} ${inv.id}
|
|
1799
|
+
`);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
} else {
|
|
1803
|
+
writeJson(deps, { ok: true, invitations: items });
|
|
1645
1804
|
}
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1805
|
+
return { exitCode: 0 };
|
|
1806
|
+
}
|
|
1807
|
+
async function runInvitationsAccept(input, deps) {
|
|
1808
|
+
try {
|
|
1809
|
+
await requireCredential({
|
|
1810
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
1811
|
+
env: deps.env,
|
|
1812
|
+
store: deps.store
|
|
1813
|
+
});
|
|
1814
|
+
} catch {
|
|
1815
|
+
return writeAuthError(deps);
|
|
1653
1816
|
}
|
|
1654
|
-
const result = await deps.client.
|
|
1817
|
+
const result = await deps.client.invitations.accept({ token: input.token });
|
|
1655
1818
|
if (result.error) return writeApiError(deps, result.error);
|
|
1656
|
-
const
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1819
|
+
const ws = result.data;
|
|
1820
|
+
writeHumanOrJson(
|
|
1821
|
+
deps,
|
|
1822
|
+
success(`Joined ${ws.name} (${ws.slug}) \u2014 now your active workspace.`),
|
|
1823
|
+
{ ok: true, workspace: ws }
|
|
1824
|
+
);
|
|
1825
|
+
return { exitCode: 0 };
|
|
1826
|
+
}
|
|
1827
|
+
async function runInvitationsAcceptById(input, deps) {
|
|
1828
|
+
try {
|
|
1829
|
+
await requireCredential({
|
|
1830
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
1831
|
+
env: deps.env,
|
|
1832
|
+
store: deps.store
|
|
1833
|
+
});
|
|
1834
|
+
} catch {
|
|
1835
|
+
return writeAuthError(deps);
|
|
1668
1836
|
}
|
|
1837
|
+
const result = await deps.client.invitations.acceptById({
|
|
1838
|
+
invitationId: input.invitationId
|
|
1839
|
+
});
|
|
1840
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
1841
|
+
const ws = result.data;
|
|
1842
|
+
writeHumanOrJson(
|
|
1843
|
+
deps,
|
|
1844
|
+
success(`Joined ${ws.name} (${ws.slug}) \u2014 now your active workspace.`),
|
|
1845
|
+
{ ok: true, workspace: ws }
|
|
1846
|
+
);
|
|
1669
1847
|
return { exitCode: 0 };
|
|
1670
1848
|
}
|
|
1671
1849
|
|
|
@@ -1728,7 +1906,8 @@ async function runLoginInteractive(deps) {
|
|
|
1728
1906
|
const authedClient = deps.createClient(session.data.token);
|
|
1729
1907
|
const apiKey = await authedClient.apiKeys.create({
|
|
1730
1908
|
label: "CLI",
|
|
1731
|
-
type: "delegated"
|
|
1909
|
+
type: "delegated",
|
|
1910
|
+
...deps.scope ? { scopes: [deps.scope] } : {}
|
|
1732
1911
|
});
|
|
1733
1912
|
if (apiKey.error) {
|
|
1734
1913
|
prompts4.cancel(apiKey.error.message);
|
|
@@ -1740,6 +1919,7 @@ async function runLoginInteractive(deps) {
|
|
|
1740
1919
|
keyLast4: apiKey.data.keyLast4,
|
|
1741
1920
|
accountId: apiKey.data.accountId ?? session.data.accountId,
|
|
1742
1921
|
email,
|
|
1922
|
+
...apiKey.data.scopes ? { scopes: apiKey.data.scopes } : {},
|
|
1743
1923
|
storage: "secure"
|
|
1744
1924
|
});
|
|
1745
1925
|
prompts4.outro("Logged in successfully.");
|
|
@@ -1774,7 +1954,10 @@ async function runLoginVerify(input, deps) {
|
|
|
1774
1954
|
const authedClient = deps.createClient(session.data.token);
|
|
1775
1955
|
const apiKey = await authedClient.apiKeys.create({
|
|
1776
1956
|
label: "CLI",
|
|
1777
|
-
type: "delegated"
|
|
1957
|
+
type: "delegated",
|
|
1958
|
+
// A single bundle name (e.g. "team") requests a capability-scoped key; the
|
|
1959
|
+
// server returns the resolved scope list on the mint response.
|
|
1960
|
+
...input.scope ? { scopes: [input.scope] } : {}
|
|
1778
1961
|
});
|
|
1779
1962
|
if (apiKey.error) {
|
|
1780
1963
|
return writeApiError(deps, apiKey.error);
|
|
@@ -1785,6 +1968,7 @@ async function runLoginVerify(input, deps) {
|
|
|
1785
1968
|
keyLast4: apiKey.data.keyLast4,
|
|
1786
1969
|
accountId: apiKey.data.accountId ?? session.data.accountId,
|
|
1787
1970
|
email: input.email,
|
|
1971
|
+
...apiKey.data.scopes ? { scopes: apiKey.data.scopes } : {},
|
|
1788
1972
|
storage: "secure"
|
|
1789
1973
|
});
|
|
1790
1974
|
writeHumanOrJson(deps, success(`Logged in as ${input.email}.`), {
|
|
@@ -1813,6 +1997,115 @@ async function runLogout(input, deps) {
|
|
|
1813
1997
|
return { exitCode: 0 };
|
|
1814
1998
|
}
|
|
1815
1999
|
|
|
2000
|
+
// src/commands/members.ts
|
|
2001
|
+
var prompts5 = __toESM(require("@clack/prompts"), 1);
|
|
2002
|
+
async function runMembersList(workspaceId, _input, deps) {
|
|
2003
|
+
try {
|
|
2004
|
+
await requireCredential({
|
|
2005
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
2006
|
+
env: deps.env,
|
|
2007
|
+
store: deps.store
|
|
2008
|
+
});
|
|
2009
|
+
} catch {
|
|
2010
|
+
return writeAuthError(deps);
|
|
2011
|
+
}
|
|
2012
|
+
const result = await deps.client.members.list(workspaceId);
|
|
2013
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
2014
|
+
const raw = unwrapListData(result.data, "members");
|
|
2015
|
+
const items = Array.isArray(raw) ? raw : [];
|
|
2016
|
+
if (deps.outputMode === "human") {
|
|
2017
|
+
if (items.length === 0) {
|
|
2018
|
+
writeEmpty(deps, "No members.", { ok: true, members: [] });
|
|
2019
|
+
} else {
|
|
2020
|
+
for (const m of items) {
|
|
2021
|
+
const who = m.email || m.accountId;
|
|
2022
|
+
const you = m.isYou ? "(you)" : "";
|
|
2023
|
+
deps.stdout(`${who} ${m.role} ${you}
|
|
2024
|
+
`);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
} else {
|
|
2028
|
+
writeJson(deps, { ok: true, members: items });
|
|
2029
|
+
}
|
|
2030
|
+
return { exitCode: 0 };
|
|
2031
|
+
}
|
|
2032
|
+
async function runMembersInvite(workspaceId, input, deps) {
|
|
2033
|
+
try {
|
|
2034
|
+
await requireCredential({
|
|
2035
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
2036
|
+
env: deps.env,
|
|
2037
|
+
store: deps.store
|
|
2038
|
+
});
|
|
2039
|
+
} catch {
|
|
2040
|
+
return writeAuthError(deps);
|
|
2041
|
+
}
|
|
2042
|
+
const role = input.role ?? "member";
|
|
2043
|
+
const result = await deps.client.members.invite(workspaceId, {
|
|
2044
|
+
email: input.email,
|
|
2045
|
+
role
|
|
2046
|
+
});
|
|
2047
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
2048
|
+
writeHumanOrJson(deps, success(`Invited ${input.email} as ${role}`), {
|
|
2049
|
+
ok: true,
|
|
2050
|
+
invitation: result.data
|
|
2051
|
+
});
|
|
2052
|
+
return { exitCode: 0 };
|
|
2053
|
+
}
|
|
2054
|
+
async function runMembersRole(workspaceId, accountId, input, deps) {
|
|
2055
|
+
try {
|
|
2056
|
+
await requireCredential({
|
|
2057
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
2058
|
+
env: deps.env,
|
|
2059
|
+
store: deps.store
|
|
2060
|
+
});
|
|
2061
|
+
} catch {
|
|
2062
|
+
return writeAuthError(deps);
|
|
2063
|
+
}
|
|
2064
|
+
const result = await deps.client.members.updateRole(workspaceId, accountId, {
|
|
2065
|
+
role: input.role
|
|
2066
|
+
});
|
|
2067
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
2068
|
+
writeHumanOrJson(deps, success(`Set ${accountId} to ${input.role}`), {
|
|
2069
|
+
ok: true,
|
|
2070
|
+
member: result.data
|
|
2071
|
+
});
|
|
2072
|
+
return { exitCode: 0 };
|
|
2073
|
+
}
|
|
2074
|
+
async function runMembersRemove(workspaceId, accountId, input, deps) {
|
|
2075
|
+
if (!input.yes && input.interactive === false) {
|
|
2076
|
+
return writeError(
|
|
2077
|
+
deps,
|
|
2078
|
+
"invalid_usage",
|
|
2079
|
+
"Pass --yes to remove in non-interactive mode."
|
|
2080
|
+
);
|
|
2081
|
+
}
|
|
2082
|
+
if (!input.yes && input.interactive !== false) {
|
|
2083
|
+
const confirmed = await prompts5.confirm({
|
|
2084
|
+
message: `Remove ${accountId} from workspace ${workspaceId}?`
|
|
2085
|
+
});
|
|
2086
|
+
if (prompts5.isCancel(confirmed) || !confirmed) {
|
|
2087
|
+
return { exitCode: 0 };
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
try {
|
|
2091
|
+
await requireCredential({
|
|
2092
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
2093
|
+
env: deps.env,
|
|
2094
|
+
store: deps.store
|
|
2095
|
+
});
|
|
2096
|
+
} catch {
|
|
2097
|
+
return writeAuthError(deps);
|
|
2098
|
+
}
|
|
2099
|
+
const result = await deps.client.members.remove(workspaceId, accountId);
|
|
2100
|
+
if (result?.error) return writeApiError(deps, result.error);
|
|
2101
|
+
writeHumanOrJson(deps, success(`Removed ${accountId}`), {
|
|
2102
|
+
ok: true,
|
|
2103
|
+
removed: true,
|
|
2104
|
+
account_id: accountId
|
|
2105
|
+
});
|
|
2106
|
+
return { exitCode: 0 };
|
|
2107
|
+
}
|
|
2108
|
+
|
|
1816
2109
|
// src/drop-operations.ts
|
|
1817
2110
|
var import_node_crypto = require("crypto");
|
|
1818
2111
|
var import_promises = require("fs/promises");
|
|
@@ -1949,6 +2242,9 @@ async function parseDropOptions(raw) {
|
|
|
1949
2242
|
if (raw.noindex && raw.index) {
|
|
1950
2243
|
throw new Error("Use either --noindex or --index, not both.");
|
|
1951
2244
|
}
|
|
2245
|
+
if (raw.expiresAt && raw.noExpires) {
|
|
2246
|
+
throw new Error("Use either --expires-at or --no-expires, not both.");
|
|
2247
|
+
}
|
|
1952
2248
|
if (raw.shared && raw.domain) {
|
|
1953
2249
|
throw new Error("Use either --shared or --domain <hostname>, not both.");
|
|
1954
2250
|
}
|
|
@@ -1977,6 +2273,7 @@ async function parseDropOptions(raw) {
|
|
|
1977
2273
|
...raw.noindex ? { noindex: true } : {},
|
|
1978
2274
|
...raw.index ? { noindex: false } : {},
|
|
1979
2275
|
...raw.expiresAt ? { expiresAt: raw.expiresAt } : {},
|
|
2276
|
+
...raw.noExpires ? { expiresAt: null } : {},
|
|
1980
2277
|
...metadata ? { metadata } : {},
|
|
1981
2278
|
...raw.entry ? { entry: raw.entry } : {},
|
|
1982
2279
|
...raw.contentType ? { contentType: raw.contentType } : {},
|
|
@@ -2178,7 +2475,9 @@ async function runPull(target, input, deps) {
|
|
|
2178
2475
|
const dropId = resolved.dropId;
|
|
2179
2476
|
const defaultDirName = resolved.slug || resolved.dropId;
|
|
2180
2477
|
const spin = shouldSpin(deps.outputMode) ? createSpinner("Pulling content\u2026", deps.stderr) : void 0;
|
|
2181
|
-
const
|
|
2478
|
+
const deploymentId = input.deployment;
|
|
2479
|
+
const manifestOptions = deploymentId ? { deploymentId } : void 0;
|
|
2480
|
+
const manifestResult = manifestOptions ? await deps.client.drops.getContent(dropId, manifestOptions) : await deps.client.drops.getContent(dropId);
|
|
2182
2481
|
if (manifestResult.error) {
|
|
2183
2482
|
spin?.fail();
|
|
2184
2483
|
return writeApiError(deps, manifestResult.error);
|
|
@@ -2202,7 +2501,10 @@ async function runPull(target, input, deps) {
|
|
|
2202
2501
|
try {
|
|
2203
2502
|
await (0, import_promises3.mkdir)(outDir, { recursive: true });
|
|
2204
2503
|
for (const { path, dest } of destinations) {
|
|
2205
|
-
const fileResult = await deps.client.drops.getContent(dropId, {
|
|
2504
|
+
const fileResult = await deps.client.drops.getContent(dropId, {
|
|
2505
|
+
path,
|
|
2506
|
+
...deploymentId ? { deploymentId } : {}
|
|
2507
|
+
});
|
|
2206
2508
|
if (fileResult.error) {
|
|
2207
2509
|
spin?.fail();
|
|
2208
2510
|
return writeApiError(deps, {
|
|
@@ -2389,9 +2691,9 @@ async function handleDryRun(dropId, input, raw, deps) {
|
|
|
2389
2691
|
}
|
|
2390
2692
|
|
|
2391
2693
|
// src/commands/update-settings.ts
|
|
2392
|
-
var
|
|
2694
|
+
var prompts6 = __toESM(require("@clack/prompts"), 1);
|
|
2393
2695
|
var NO_SETTINGS_MESSAGE = "Nothing to update. Provide at least one settings option.";
|
|
2394
|
-
var NO_SETTINGS_NEXT_ACTION = "Run dropthis update-settings --help, or retry with one of: --title, --visibility, --password, --no-password, --noindex, --index, --expires-at, --metadata, or --metadata-file. To replace the content at the URL instead, use dropthis update-content <dropId> ./dist.";
|
|
2696
|
+
var NO_SETTINGS_NEXT_ACTION = "Run dropthis update-settings --help, or retry with one of: --title, --visibility, --password, --no-password, --noindex, --index, --expires-at, --no-expires, --domain, --shared, --slug, --metadata, or --metadata-file. To replace the content at the URL instead, use dropthis update-content <dropId> ./dist.";
|
|
2395
2697
|
async function runUpdateSettings(target, raw, deps) {
|
|
2396
2698
|
const apiKey = raw.apiKey ?? deps.apiKey;
|
|
2397
2699
|
try {
|
|
@@ -2421,7 +2723,7 @@ async function runUpdateSettings(target, raw, deps) {
|
|
|
2421
2723
|
if (shouldPrompt(deps)) {
|
|
2422
2724
|
const prompted = await promptForSettings(
|
|
2423
2725
|
dropId,
|
|
2424
|
-
deps.prompts ??
|
|
2726
|
+
deps.prompts ?? prompts6
|
|
2425
2727
|
);
|
|
2426
2728
|
if (!prompted) return { exitCode: 0 };
|
|
2427
2729
|
parsed = { ...parsed, ...prompted };
|
|
@@ -2610,8 +2912,10 @@ async function handleDryRun2(dropId, raw, deps) {
|
|
|
2610
2912
|
if (options.visibility) fields.visibility = options.visibility;
|
|
2611
2913
|
if (options.password !== void 0) fields.password = options.password;
|
|
2612
2914
|
if (options.noindex !== void 0) fields.noindex = options.noindex;
|
|
2613
|
-
if (options.expiresAt) fields.expires_at = options.expiresAt;
|
|
2915
|
+
if (options.expiresAt !== void 0) fields.expires_at = options.expiresAt;
|
|
2614
2916
|
if (options.metadata) fields.metadata = options.metadata;
|
|
2917
|
+
if (options.domain) fields.domain = options.domain;
|
|
2918
|
+
if (options.slug) fields.slug = options.slug;
|
|
2615
2919
|
deps.stdout(
|
|
2616
2920
|
`${JSON.stringify({ ok: true, dryRun: true, kind: "settings_update", target: dropId, fields }, null, 2)}
|
|
2617
2921
|
`
|
|
@@ -2759,6 +3063,8 @@ async function runWhoami(_input, deps) {
|
|
|
2759
3063
|
pairs.push(["Source", credential.source]);
|
|
2760
3064
|
if (credential.accountId ?? account.id)
|
|
2761
3065
|
pairs.push(["Account", String(credential.accountId ?? account.id)]);
|
|
3066
|
+
if (credential.scopes?.length)
|
|
3067
|
+
pairs.push(["Scopes", credential.scopes.join(", ")]);
|
|
2762
3068
|
const jsonEnvelope = {
|
|
2763
3069
|
ok: true,
|
|
2764
3070
|
authenticated: true,
|
|
@@ -2767,13 +3073,15 @@ async function runWhoami(_input, deps) {
|
|
|
2767
3073
|
...credential.keyId ? { key_id: credential.keyId } : {},
|
|
2768
3074
|
...last4 ? { key_last4: last4 } : {},
|
|
2769
3075
|
...credential.accountId ?? account.id ? { account_id: String(credential.accountId ?? account.id) } : {},
|
|
2770
|
-
...credential.email ?? account.email ? { email: String(credential.email ?? account.email) } : {}
|
|
3076
|
+
...credential.email ?? account.email ? { email: String(credential.email ?? account.email) } : {},
|
|
3077
|
+
...credential.scopes?.length ? { scopes: credential.scopes } : {}
|
|
2771
3078
|
};
|
|
2772
3079
|
writeKv(deps, pairs, jsonEnvelope);
|
|
2773
3080
|
return { exitCode: 0 };
|
|
2774
3081
|
}
|
|
2775
3082
|
|
|
2776
3083
|
// src/commands/workspace.ts
|
|
3084
|
+
var prompts7 = __toESM(require("@clack/prompts"), 1);
|
|
2777
3085
|
async function runWorkspaceList(_input, deps) {
|
|
2778
3086
|
try {
|
|
2779
3087
|
await requireCredential({
|
|
@@ -2826,6 +3134,104 @@ async function runWorkspaceUse(slugOrId, _input, deps) {
|
|
|
2826
3134
|
);
|
|
2827
3135
|
return { exitCode: 0 };
|
|
2828
3136
|
}
|
|
3137
|
+
async function runWorkspaceCreate(input, deps) {
|
|
3138
|
+
try {
|
|
3139
|
+
await requireCredential({
|
|
3140
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
3141
|
+
env: deps.env,
|
|
3142
|
+
store: deps.store
|
|
3143
|
+
});
|
|
3144
|
+
} catch {
|
|
3145
|
+
return writeAuthError(deps);
|
|
3146
|
+
}
|
|
3147
|
+
const createInput = { name: input.name };
|
|
3148
|
+
if (input.slug !== void 0) createInput.slug = input.slug;
|
|
3149
|
+
const result = await deps.client.workspaces.create(createInput);
|
|
3150
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
3151
|
+
const ws = result.data;
|
|
3152
|
+
writeHumanOrJson(
|
|
3153
|
+
deps,
|
|
3154
|
+
success(`Created workspace: ${ws.name} (${ws.slug})`),
|
|
3155
|
+
{
|
|
3156
|
+
ok: true,
|
|
3157
|
+
workspace: ws
|
|
3158
|
+
}
|
|
3159
|
+
);
|
|
3160
|
+
if (ws.creatorCanReach === false && deps.outputMode === "human") {
|
|
3161
|
+
deps.stderr(
|
|
3162
|
+
`${hint("This key can't reach the new workspace \u2014 re-authenticate (dropthis login) to pick it up.")}
|
|
3163
|
+
`
|
|
3164
|
+
);
|
|
3165
|
+
}
|
|
3166
|
+
return { exitCode: 0 };
|
|
3167
|
+
}
|
|
3168
|
+
async function runWorkspaceRename(workspaceId, input, deps) {
|
|
3169
|
+
if (input.name === void 0 && input.slug === void 0) {
|
|
3170
|
+
return writeError(
|
|
3171
|
+
deps,
|
|
3172
|
+
"invalid_usage",
|
|
3173
|
+
"Provide --name and/or --slug to rename."
|
|
3174
|
+
);
|
|
3175
|
+
}
|
|
3176
|
+
try {
|
|
3177
|
+
await requireCredential({
|
|
3178
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
3179
|
+
env: deps.env,
|
|
3180
|
+
store: deps.store
|
|
3181
|
+
});
|
|
3182
|
+
} catch {
|
|
3183
|
+
return writeAuthError(deps);
|
|
3184
|
+
}
|
|
3185
|
+
const renameInput = {};
|
|
3186
|
+
if (input.name !== void 0) renameInput.name = input.name;
|
|
3187
|
+
if (input.slug !== void 0) renameInput.slug = input.slug;
|
|
3188
|
+
const result = await deps.client.workspaces.rename(workspaceId, renameInput);
|
|
3189
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
3190
|
+
const ws = result.data;
|
|
3191
|
+
writeHumanOrJson(
|
|
3192
|
+
deps,
|
|
3193
|
+
success(`Renamed workspace: ${ws.name} (${ws.slug})`),
|
|
3194
|
+
{
|
|
3195
|
+
ok: true,
|
|
3196
|
+
workspace: ws
|
|
3197
|
+
}
|
|
3198
|
+
);
|
|
3199
|
+
return { exitCode: 0 };
|
|
3200
|
+
}
|
|
3201
|
+
async function runWorkspaceDelete(workspaceId, input, deps) {
|
|
3202
|
+
if (!input.yes && input.interactive === false) {
|
|
3203
|
+
return writeError(
|
|
3204
|
+
deps,
|
|
3205
|
+
"invalid_usage",
|
|
3206
|
+
"Pass --yes to delete in non-interactive mode."
|
|
3207
|
+
);
|
|
3208
|
+
}
|
|
3209
|
+
if (!input.yes && input.interactive !== false) {
|
|
3210
|
+
const confirmed = await prompts7.confirm({
|
|
3211
|
+
message: `Delete workspace ${workspaceId}?`
|
|
3212
|
+
});
|
|
3213
|
+
if (prompts7.isCancel(confirmed) || !confirmed) {
|
|
3214
|
+
return { exitCode: 0 };
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
try {
|
|
3218
|
+
await requireCredential({
|
|
3219
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
3220
|
+
env: deps.env,
|
|
3221
|
+
store: deps.store
|
|
3222
|
+
});
|
|
3223
|
+
} catch {
|
|
3224
|
+
return writeAuthError(deps);
|
|
3225
|
+
}
|
|
3226
|
+
const result = await deps.client.workspaces.delete(workspaceId);
|
|
3227
|
+
if (result?.error) return writeApiError(deps, result.error);
|
|
3228
|
+
writeHumanOrJson(deps, success(`Deleted workspace ${workspaceId}`), {
|
|
3229
|
+
ok: true,
|
|
3230
|
+
deleted: true,
|
|
3231
|
+
id: workspaceId
|
|
3232
|
+
});
|
|
3233
|
+
return { exitCode: 0 };
|
|
3234
|
+
}
|
|
2829
3235
|
|
|
2830
3236
|
// src/context.ts
|
|
2831
3237
|
var import_node2 = require("@dropthis/node");
|
|
@@ -3151,7 +3557,8 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3151
3557
|
return;
|
|
3152
3558
|
}
|
|
3153
3559
|
}
|
|
3154
|
-
|
|
3560
|
+
const publishWasExplicit = (program.rawArgs ?? []).includes("publish");
|
|
3561
|
+
if (!publishWasExplicit && inputs.length === 1 && typeof publishInput === "string" && isBareWordToken(publishInput) && !await pathExists(publishInput)) {
|
|
3155
3562
|
const suggestion = suggestCommand(
|
|
3156
3563
|
publishInput,
|
|
3157
3564
|
program.commands.map((c) => c.name())
|
|
@@ -3165,13 +3572,15 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3165
3572
|
).exitCode;
|
|
3166
3573
|
return;
|
|
3167
3574
|
}
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3575
|
+
if (deps.outputMode === "human" && deps.interactive) {
|
|
3576
|
+
const prompts8 = await import("@clack/prompts");
|
|
3577
|
+
const confirmed = await prompts8.confirm({
|
|
3578
|
+
message: `Publish '${publishInput}' as inline text?`,
|
|
3579
|
+
initialValue: false
|
|
3580
|
+
});
|
|
3581
|
+
if (prompts8.isCancel(confirmed) || !confirmed) {
|
|
3582
|
+
return;
|
|
3583
|
+
}
|
|
3175
3584
|
}
|
|
3176
3585
|
}
|
|
3177
3586
|
let dropOpts;
|
|
@@ -3262,10 +3671,19 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3262
3671
|
);
|
|
3263
3672
|
program.command("update-settings <dropId>").description(
|
|
3264
3673
|
"Change a drop's title, visibility, password, expiry, or metadata (pass the full drop_\u2026 id, not the slug).\nContent stays unchanged \u2014 use update-content to replace the files at the URL."
|
|
3265
|
-
).option("--title <title>", "Change title").option("--visibility <v>", "Set to public or unlisted").option("--password <password>", "Require password to view").option("--no-password", "Remove password protection").option("--noindex", "Prevent search-engine indexing").option("--index", "Allow search-engine indexing").option("--expires-at <datetime>", "Auto-delete after this ISO 8601 date").option(
|
|
3674
|
+
).option("--title <title>", "Change title").option("--visibility <v>", "Set to public or unlisted").option("--password <password>", "Require password to view").option("--no-password", "Remove password protection").option("--noindex", "Prevent search-engine indexing").option("--index", "Allow search-engine indexing").option("--expires-at <datetime>", "Auto-delete after this ISO 8601 date").option("--no-expires", "Clear the auto-delete expiry").option(
|
|
3266
3675
|
"--metadata <json>",
|
|
3267
3676
|
`Attach JSON key-value pairs, e.g. '{"source":"ci"}'`
|
|
3268
3677
|
).option("--metadata-file <path>", "Read metadata JSON from a file").option(
|
|
3678
|
+
"--domain <hostname>",
|
|
3679
|
+
"Move this drop to a connected custom domain (must be live \u2014 see: dropthis domains list)."
|
|
3680
|
+
).option(
|
|
3681
|
+
"--shared",
|
|
3682
|
+
"Unmount this drop back to the shared dropthis pool. Cannot combine with --domain."
|
|
3683
|
+
).option(
|
|
3684
|
+
"--slug <vanity-slug>",
|
|
3685
|
+
"Rename the vanity slug on a path-mode custom domain (1\u201363 lowercase letters/digits/hyphens). 409 on conflict \u2014 does not auto-suffix."
|
|
3686
|
+
).option(
|
|
3269
3687
|
"--if-revision <n>",
|
|
3270
3688
|
"Fail if current revision doesn't match (optimistic lock)",
|
|
3271
3689
|
parseInteger
|
|
@@ -3297,7 +3715,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3297
3715
|
);
|
|
3298
3716
|
program.command("pull <target>").description(
|
|
3299
3717
|
"Download a drop's files into a local directory (accepts the drop_\u2026 id, the drop URL, or its slug).\nFetches the current deployment's file manifest and writes every file. Pull, edit, then update-content to ship the changes back to the same URL \u2014 also the rollback path."
|
|
3300
|
-
).option("-o, --output <dir>", "Output directory (default: ./<slug-or-id>)").option("--json", "Force JSON output").addHelpText(
|
|
3718
|
+
).option("-o, --output <dir>", "Output directory (default: ./<slug-or-id>)").option("--deployment <deploymentId>", "Download a specific deployment").option("--json", "Force JSON output").addHelpText(
|
|
3301
3719
|
"after",
|
|
3302
3720
|
examplesBlock([
|
|
3303
3721
|
"dropthis pull drop_abc123 -o ./site # download the drop's files",
|
|
@@ -3433,7 +3851,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3433
3851
|
process.exitCode = result.exitCode;
|
|
3434
3852
|
});
|
|
3435
3853
|
domains.command("verify <hostname>").description(
|
|
3436
|
-
"Trigger a DNS verification check. With --wait, polls until live or failed.\nUse after adding the DNS records from: dropthis domains connect\n\nExit codes: 0=live, 1=failed, 6=still pending (retry).
|
|
3854
|
+
"Trigger a DNS verification check. With --wait, polls until live or failed.\nUse after adding the DNS records from: dropthis domains connect\n\nExit codes (one-shot): 0=live, 1=failed, 6=still pending (retry). With --wait: 0=live, 1=failed, 7=timed out."
|
|
3437
3855
|
).option("--wait", "Poll until live (or failed/timeout)").option(
|
|
3438
3856
|
"--timeout <secs>",
|
|
3439
3857
|
"Max seconds to wait (default: 300)",
|
|
@@ -3489,11 +3907,35 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3489
3907
|
}
|
|
3490
3908
|
);
|
|
3491
3909
|
const apiKeys = program.command("api-keys").description("Manage API keys");
|
|
3492
|
-
apiKeys.command("create").description(
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3910
|
+
apiKeys.command("create").description(
|
|
3911
|
+
"Create an API key. Without --service, mints a delegated account-scoped key (default for login). With --service --workspace <ws>, mints a CI key pinned to that workspace."
|
|
3912
|
+
).option("--label <label>", "API key label").option(
|
|
3913
|
+
"--service",
|
|
3914
|
+
"Mint a pinned service key for CI/automation (requires --workspace to pin it)"
|
|
3915
|
+
).option(
|
|
3916
|
+
"--workspace <slugOrId>",
|
|
3917
|
+
"Pin this service key to the given workspace slug or id (only valid with --service)"
|
|
3918
|
+
).option(
|
|
3919
|
+
"--allowed-workspace <slugOrId>",
|
|
3920
|
+
"Allow a delegated key to access the given workspace slug or id",
|
|
3921
|
+
collect,
|
|
3922
|
+
[]
|
|
3923
|
+
).option("--json", "Force JSON output").action(
|
|
3924
|
+
async (commandOptions) => {
|
|
3925
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3926
|
+
const result = await runApiKeysCreate(
|
|
3927
|
+
{
|
|
3928
|
+
...commandOptions.label !== void 0 ? { label: commandOptions.label } : {},
|
|
3929
|
+
type: commandOptions.service ? "service" : "delegated",
|
|
3930
|
+
...commandOptions.workspace !== void 0 ? { workspace: commandOptions.workspace } : {},
|
|
3931
|
+
...commandOptions.allowedWorkspace?.length ? { allowedWorkspaces: commandOptions.allowedWorkspace } : {},
|
|
3932
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
3933
|
+
},
|
|
3934
|
+
deps
|
|
3935
|
+
);
|
|
3936
|
+
process.exitCode = result.exitCode;
|
|
3937
|
+
}
|
|
3938
|
+
);
|
|
3497
3939
|
apiKeys.command("list").description("List API keys").option("--json", "Force JSON output").action(async (commandOptions) => {
|
|
3498
3940
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3499
3941
|
const result = await runApiKeysList(commandOptions, deps);
|
|
@@ -3530,25 +3972,80 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3530
3972
|
const result = await runWorkspaceUse(slugOrId, commandOptions, deps);
|
|
3531
3973
|
process.exitCode = result.exitCode;
|
|
3532
3974
|
});
|
|
3533
|
-
|
|
3534
|
-
|
|
3975
|
+
workspace.command("create <name>").description("Create a new team workspace").option("--slug <slug>", "Vanity slug for the workspace").option("--json", "Force JSON output").action(
|
|
3976
|
+
async (name, commandOptions) => {
|
|
3977
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3978
|
+
const result = await runWorkspaceCreate(
|
|
3979
|
+
{
|
|
3980
|
+
name,
|
|
3981
|
+
...commandOptions.slug !== void 0 ? { slug: commandOptions.slug } : {},
|
|
3982
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
3983
|
+
},
|
|
3984
|
+
deps
|
|
3985
|
+
);
|
|
3986
|
+
process.exitCode = result.exitCode;
|
|
3987
|
+
}
|
|
3535
3988
|
);
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
).option("--label <label>", "Key label").option(
|
|
3539
|
-
"--service",
|
|
3540
|
-
"Mint a pinned service key for CI/automation (requires --workspace to pin it)"
|
|
3541
|
-
).option(
|
|
3542
|
-
"--workspace <slugOrId>",
|
|
3543
|
-
"Pin this service key to the given workspace slug or id (only valid with --service)"
|
|
3544
|
-
).option("--json", "Force JSON output").action(
|
|
3545
|
-
async (commandOptions) => {
|
|
3989
|
+
workspace.command("rename <workspaceId>").description("Rename a workspace or change its vanity slug").option("--name <name>", "New workspace name").option("--slug <slug>", "New vanity slug").option("--json", "Force JSON output").action(
|
|
3990
|
+
async (workspaceId, commandOptions) => {
|
|
3546
3991
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3547
|
-
const result = await
|
|
3992
|
+
const result = await runWorkspaceRename(
|
|
3993
|
+
workspaceId,
|
|
3548
3994
|
{
|
|
3549
|
-
...commandOptions.
|
|
3550
|
-
|
|
3551
|
-
...commandOptions.
|
|
3995
|
+
...commandOptions.name !== void 0 ? { name: commandOptions.name } : {},
|
|
3996
|
+
...commandOptions.slug !== void 0 ? { slug: commandOptions.slug } : {},
|
|
3997
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
3998
|
+
},
|
|
3999
|
+
deps
|
|
4000
|
+
);
|
|
4001
|
+
process.exitCode = result.exitCode;
|
|
4002
|
+
}
|
|
4003
|
+
);
|
|
4004
|
+
workspace.command("delete <workspaceId>").description("Delete a workspace").option("--yes", "Confirm deletion").option("--json", "Force JSON output").action(
|
|
4005
|
+
async (workspaceId, commandOptions) => {
|
|
4006
|
+
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
4007
|
+
const global = globalOptions(program, commandOptions);
|
|
4008
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4009
|
+
const result = await runWorkspaceDelete(
|
|
4010
|
+
workspaceId,
|
|
4011
|
+
{
|
|
4012
|
+
...commandOptions,
|
|
4013
|
+
interactive: isInteractive(stdinIsTTY, deps.env, global)
|
|
4014
|
+
},
|
|
4015
|
+
deps
|
|
4016
|
+
);
|
|
4017
|
+
process.exitCode = result.exitCode;
|
|
4018
|
+
}
|
|
4019
|
+
);
|
|
4020
|
+
const members = program.command("members").description("Manage team members");
|
|
4021
|
+
members.command("list <workspaceId>").description("List members of a workspace").option("--json", "Force JSON output").action(async (workspaceId, commandOptions) => {
|
|
4022
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4023
|
+
const result = await runMembersList(workspaceId, commandOptions, deps);
|
|
4024
|
+
process.exitCode = result.exitCode;
|
|
4025
|
+
});
|
|
4026
|
+
members.command("invite <workspaceId>").description("Invite someone to a workspace by email").requiredOption("--email <email>", "Email address to invite").option("--role <role>", "Role to grant (admin or member)", "member").option("--json", "Force JSON output").action(
|
|
4027
|
+
async (workspaceId, commandOptions) => {
|
|
4028
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4029
|
+
const result = await runMembersInvite(
|
|
4030
|
+
workspaceId,
|
|
4031
|
+
{
|
|
4032
|
+
email: commandOptions.email,
|
|
4033
|
+
...commandOptions.role !== void 0 ? { role: commandOptions.role } : {},
|
|
4034
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
4035
|
+
},
|
|
4036
|
+
deps
|
|
4037
|
+
);
|
|
4038
|
+
process.exitCode = result.exitCode;
|
|
4039
|
+
}
|
|
4040
|
+
);
|
|
4041
|
+
members.command("role <workspaceId> <accountId>").description("Change a member's role").requiredOption("--role <role>", "New role (owner, admin, or member)").option("--json", "Force JSON output").action(
|
|
4042
|
+
async (workspaceId, accountId, commandOptions) => {
|
|
4043
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4044
|
+
const result = await runMembersRole(
|
|
4045
|
+
workspaceId,
|
|
4046
|
+
accountId,
|
|
4047
|
+
{
|
|
4048
|
+
role: commandOptions.role,
|
|
3552
4049
|
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
3553
4050
|
},
|
|
3554
4051
|
deps
|
|
@@ -3556,7 +4053,51 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3556
4053
|
process.exitCode = result.exitCode;
|
|
3557
4054
|
}
|
|
3558
4055
|
);
|
|
3559
|
-
|
|
4056
|
+
members.command("remove <workspaceId> <accountId>").description("Remove a member from a workspace").option("--yes", "Confirm removal").option("--json", "Force JSON output").action(
|
|
4057
|
+
async (workspaceId, accountId, commandOptions) => {
|
|
4058
|
+
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
4059
|
+
const global = globalOptions(program, commandOptions);
|
|
4060
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4061
|
+
const result = await runMembersRemove(
|
|
4062
|
+
workspaceId,
|
|
4063
|
+
accountId,
|
|
4064
|
+
{
|
|
4065
|
+
...commandOptions,
|
|
4066
|
+
interactive: isInteractive(stdinIsTTY, deps.env, global)
|
|
4067
|
+
},
|
|
4068
|
+
deps
|
|
4069
|
+
);
|
|
4070
|
+
process.exitCode = result.exitCode;
|
|
4071
|
+
}
|
|
4072
|
+
);
|
|
4073
|
+
const invitations = program.command("invitations").description("Manage your workspace invitations");
|
|
4074
|
+
invitations.command("list", { isDefault: true }).description("List your pending workspace invitations").option("--json", "Force JSON output").action(async (commandOptions) => {
|
|
4075
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4076
|
+
const result = await runInvitationsList(commandOptions, deps);
|
|
4077
|
+
process.exitCode = result.exitCode;
|
|
4078
|
+
});
|
|
4079
|
+
invitations.command("accept").description("Accept a workspace invitation by token").requiredOption("--token <token>", "Invitation token").option("--json", "Force JSON output").action(async (commandOptions) => {
|
|
4080
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4081
|
+
const result = await runInvitationsAccept(commandOptions, deps);
|
|
4082
|
+
process.exitCode = result.exitCode;
|
|
4083
|
+
});
|
|
4084
|
+
invitations.command("accept-by-id <invitationId>").description("Accept a workspace invitation by its id").option("--json", "Force JSON output").action(
|
|
4085
|
+
async (invitationId, commandOptions) => {
|
|
4086
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4087
|
+
const result = await runInvitationsAcceptById(
|
|
4088
|
+
{
|
|
4089
|
+
invitationId,
|
|
4090
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
4091
|
+
},
|
|
4092
|
+
deps
|
|
4093
|
+
);
|
|
4094
|
+
process.exitCode = result.exitCode;
|
|
4095
|
+
}
|
|
4096
|
+
);
|
|
4097
|
+
program.command("login").description("Authenticate with email OTP").option("--email <email>", "Email address").option("--otp <otp>", "One-time passcode").option(
|
|
4098
|
+
"--scope <scope>",
|
|
4099
|
+
"Capability scope to request for the minted key (e.g. team)"
|
|
4100
|
+
).option("--json", "Force JSON output").action(
|
|
3560
4101
|
async (commandOptions) => {
|
|
3561
4102
|
if (!commandOptions.email || !commandOptions.otp) {
|
|
3562
4103
|
const deps2 = await commandDeps(program, options, store, commandOptions);
|
|
@@ -3574,7 +4115,8 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3574
4115
|
const context = createContext({ global: global2 });
|
|
3575
4116
|
const result2 = await runLoginInteractive({
|
|
3576
4117
|
...deps2,
|
|
3577
|
-
createClient: (apiKey) => context.createClient(apiKey)
|
|
4118
|
+
createClient: (apiKey) => context.createClient(apiKey),
|
|
4119
|
+
...commandOptions.scope ? { scope: commandOptions.scope } : {}
|
|
3578
4120
|
});
|
|
3579
4121
|
process.exitCode = result2.exitCode;
|
|
3580
4122
|
return;
|
|
@@ -3586,6 +4128,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3586
4128
|
{
|
|
3587
4129
|
email: commandOptions.email,
|
|
3588
4130
|
otp: commandOptions.otp,
|
|
4131
|
+
...commandOptions.scope ? { scope: commandOptions.scope } : {},
|
|
3589
4132
|
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
3590
4133
|
},
|
|
3591
4134
|
{
|
|
@@ -3602,7 +4145,10 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3602
4145
|
const result = await runLoginRequest(commandOptions, deps);
|
|
3603
4146
|
process.exitCode = result.exitCode;
|
|
3604
4147
|
});
|
|
3605
|
-
login?.command("verify").description("Verify email OTP and store an API key").requiredOption("--email <email>", "Email address").requiredOption("--otp <otp>", "One-time passcode").option(
|
|
4148
|
+
login?.command("verify").description("Verify email OTP and store an API key").requiredOption("--email <email>", "Email address").requiredOption("--otp <otp>", "One-time passcode").option(
|
|
4149
|
+
"--scope <scope>",
|
|
4150
|
+
"Capability scope to request for the minted key (e.g. team)"
|
|
4151
|
+
).option("--json", "Force JSON output").action(
|
|
3606
4152
|
async (commandOptions) => {
|
|
3607
4153
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3608
4154
|
const global = globalOptions(program, commandOptions);
|
|
@@ -3640,17 +4186,30 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3640
4186
|
const result = await runAccountGet(commandOptions, deps);
|
|
3641
4187
|
process.exitCode = result.exitCode;
|
|
3642
4188
|
});
|
|
3643
|
-
account.command("update").description("Update account display name").
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
4189
|
+
account.command("update").description("Update account display name").option("--display-name <name>", "Set the display name").option("--clear-display-name", "Clear the display name").option("--json", "Force JSON output").action(
|
|
4190
|
+
async (commandOptions) => {
|
|
4191
|
+
if (commandOptions.displayName === void 0 && !commandOptions.clearDisplayName || commandOptions.displayName !== void 0 && commandOptions.clearDisplayName) {
|
|
4192
|
+
const writer = outputWriter(program, options, commandOptions);
|
|
4193
|
+
process.exitCode = writeError(
|
|
4194
|
+
writer,
|
|
4195
|
+
"invalid_usage",
|
|
4196
|
+
"Use either --display-name <name> or --clear-display-name."
|
|
4197
|
+
).exitCode;
|
|
4198
|
+
return;
|
|
4199
|
+
}
|
|
4200
|
+
const displayName = commandOptions.clearDisplayName ? null : commandOptions.displayName;
|
|
4201
|
+
if (displayName === void 0) return;
|
|
4202
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4203
|
+
const result = await runAccountUpdate(
|
|
4204
|
+
{
|
|
4205
|
+
displayName,
|
|
4206
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
4207
|
+
},
|
|
4208
|
+
deps
|
|
4209
|
+
);
|
|
4210
|
+
process.exitCode = result.exitCode;
|
|
4211
|
+
}
|
|
4212
|
+
);
|
|
3654
4213
|
account.command("delete").description("Delete your account").option("--yes", "Confirm deletion").option("--json", "Force JSON output").action(async (commandOptions) => {
|
|
3655
4214
|
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
3656
4215
|
const global = globalOptions(program, commandOptions);
|
|
@@ -3664,7 +4223,10 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3664
4223
|
);
|
|
3665
4224
|
process.exitCode = result.exitCode;
|
|
3666
4225
|
});
|
|
3667
|
-
program.command("doctor").description("Report CLI diagnostics").option("--json", "Force JSON output").
|
|
4226
|
+
program.command("doctor").description("Report CLI diagnostics").option("--json", "Force JSON output").option(
|
|
4227
|
+
"--online",
|
|
4228
|
+
"Run a network preflight (auth + active workspace + custom-domain status) \u2014 exits 3 on auth failure, 5 on a network failure"
|
|
4229
|
+
).action(async (commandOptions) => {
|
|
3668
4230
|
const deps = await commandDeps(
|
|
3669
4231
|
program,
|
|
3670
4232
|
options,
|
|
@@ -3799,6 +4361,7 @@ function toDropOptions(options) {
|
|
|
3799
4361
|
...options.noindex ? { noindex: true } : {},
|
|
3800
4362
|
...options.index ? { index: true } : {},
|
|
3801
4363
|
...options.expiresAt ? { expiresAt: options.expiresAt } : {},
|
|
4364
|
+
...options.expires === false || options.noExpires ? { noExpires: true } : {},
|
|
3802
4365
|
...options.metadata ? { metadata: options.metadata } : {},
|
|
3803
4366
|
...options.metadataFile ? { metadataFile: options.metadataFile } : {},
|
|
3804
4367
|
...options.entry ? { entry: options.entry } : {},
|