@dropthis/cli 0.31.0 → 0.33.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 +36 -10
- package/dist/cli.cjs +702 -108
- package/dist/cli.cjs.map +1 -1
- package/node_modules/@dropthis/node/README.md +2 -2
- package/node_modules/@dropthis/node/dist/edge.cjs +21 -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 +21 -1
- package/node_modules/@dropthis/node/dist/edge.mjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.cjs +100 -1
- package/node_modules/@dropthis/node/dist/index.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.d.cts +43 -3
- package/node_modules/@dropthis/node/dist/index.d.ts +43 -3
- package/node_modules/@dropthis/node/dist/index.mjs +98 -1
- package/node_modules/@dropthis/node/dist/index.mjs.map +1 -1
- package/node_modules/@dropthis/node/dist/{workspaces-Xmo2L46y.d.cts → workspaces-CebiV4DS.d.cts} +59 -1
- package/node_modules/@dropthis/node/dist/{workspaces-Xmo2L46y.d.ts → workspaces-CebiV4DS.d.ts} +59 -1
- package/node_modules/@dropthis/node/package.json +1 -1
- package/package.json +49 -49
package/dist/cli.cjs
CHANGED
|
@@ -305,6 +305,16 @@ function exitCodeFor(code) {
|
|
|
305
305
|
if (code === "verify_timeout") return 7;
|
|
306
306
|
return 1;
|
|
307
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
|
+
};
|
|
308
318
|
|
|
309
319
|
// src/program.ts
|
|
310
320
|
var import_commander = require("commander");
|
|
@@ -324,7 +334,8 @@ async function resolveCredential(input) {
|
|
|
324
334
|
...stored.keyId ? { keyId: stored.keyId } : {},
|
|
325
335
|
...stored.keyLast4 ? { keyLast4: stored.keyLast4 } : {},
|
|
326
336
|
...stored.accountId ? { accountId: stored.accountId } : {},
|
|
327
|
-
...stored.email ? { email: stored.email } : {}
|
|
337
|
+
...stored.email ? { email: stored.email } : {},
|
|
338
|
+
...stored.scopes?.length ? { scopes: stored.scopes } : {}
|
|
328
339
|
};
|
|
329
340
|
}
|
|
330
341
|
async function requireCredential(input) {
|
|
@@ -673,14 +684,55 @@ async function runApiKeysCreate(input, deps) {
|
|
|
673
684
|
} catch {
|
|
674
685
|
return writeAuthError(deps);
|
|
675
686
|
}
|
|
676
|
-
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);
|
|
677
722
|
if (result.error) return writeApiError(deps, result.error);
|
|
678
723
|
const data = result.data;
|
|
679
724
|
const pairs = [];
|
|
680
725
|
if (data.id) pairs.push(["ID", String(data.id)]);
|
|
681
726
|
if (data.key) pairs.push(["Key", String(data.key)]);
|
|
682
727
|
if (data.keyLast4) pairs.push(["Last 4", String(data.keyLast4)]);
|
|
728
|
+
if (data.label) pairs.push(["Label", String(data.label)]);
|
|
683
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
|
+
}
|
|
684
736
|
return { exitCode: 0 };
|
|
685
737
|
}
|
|
686
738
|
async function runApiKeysList(_input, deps) {
|
|
@@ -845,7 +897,10 @@ var COMMAND_ANNOTATIONS = {
|
|
|
845
897
|
},
|
|
846
898
|
"api-keys create": {
|
|
847
899
|
auth: "required",
|
|
848
|
-
examples: [
|
|
900
|
+
examples: [
|
|
901
|
+
"dropthis api-keys create --label CI --json",
|
|
902
|
+
"dropthis api-keys create --service --workspace acme --json"
|
|
903
|
+
]
|
|
849
904
|
},
|
|
850
905
|
"api-keys list": {
|
|
851
906
|
auth: "required",
|
|
@@ -870,17 +925,56 @@ var COMMAND_ANNOTATIONS = {
|
|
|
870
925
|
"dropthis workspace use ws_team123"
|
|
871
926
|
]
|
|
872
927
|
},
|
|
873
|
-
|
|
928
|
+
"workspace create": {
|
|
929
|
+
auth: "required",
|
|
930
|
+
examples: ['dropthis workspace create "Acme" --slug acme --json']
|
|
931
|
+
},
|
|
932
|
+
"workspace rename": {
|
|
933
|
+
auth: "required",
|
|
934
|
+
examples: ['dropthis workspace rename ws_team123 --name "Acme Inc" --json']
|
|
935
|
+
},
|
|
936
|
+
"workspace delete": {
|
|
874
937
|
auth: "required",
|
|
875
|
-
examples: ["dropthis
|
|
938
|
+
examples: ["dropthis workspace delete ws_team123 --yes --json"]
|
|
876
939
|
},
|
|
877
|
-
|
|
940
|
+
members: {
|
|
941
|
+
auth: "required",
|
|
942
|
+
examples: ["dropthis members list ws_team123 --json"]
|
|
943
|
+
},
|
|
944
|
+
"members list": {
|
|
945
|
+
auth: "required",
|
|
946
|
+
examples: ["dropthis members list ws_team123 --json"]
|
|
947
|
+
},
|
|
948
|
+
"members invite": {
|
|
878
949
|
auth: "required",
|
|
879
950
|
examples: [
|
|
880
|
-
"dropthis
|
|
881
|
-
"dropthis keys create --service --workspace acme --json"
|
|
951
|
+
"dropthis members invite ws_team123 --email teammate@acme.com --role member --json"
|
|
882
952
|
]
|
|
883
953
|
},
|
|
954
|
+
"members role": {
|
|
955
|
+
auth: "required",
|
|
956
|
+
examples: ["dropthis members role ws_team123 acc_123 --role admin --json"]
|
|
957
|
+
},
|
|
958
|
+
"members remove": {
|
|
959
|
+
auth: "required",
|
|
960
|
+
examples: ["dropthis members remove ws_team123 acc_123 --yes --json"]
|
|
961
|
+
},
|
|
962
|
+
invitations: {
|
|
963
|
+
auth: "required",
|
|
964
|
+
examples: ["dropthis invitations --json"]
|
|
965
|
+
},
|
|
966
|
+
"invitations list": {
|
|
967
|
+
auth: "required",
|
|
968
|
+
examples: ["dropthis invitations list --json"]
|
|
969
|
+
},
|
|
970
|
+
"invitations accept": {
|
|
971
|
+
auth: "required",
|
|
972
|
+
examples: ["dropthis invitations accept --token inv_tok_abc --json"]
|
|
973
|
+
},
|
|
974
|
+
"invitations accept-by-id": {
|
|
975
|
+
auth: "required",
|
|
976
|
+
examples: ["dropthis invitations accept-by-id inv_123 --json"]
|
|
977
|
+
},
|
|
884
978
|
login: {
|
|
885
979
|
examples: [
|
|
886
980
|
"dropthis login",
|
|
@@ -908,7 +1002,9 @@ var COMMAND_ANNOTATIONS = {
|
|
|
908
1002
|
auth: "required",
|
|
909
1003
|
examples: ["dropthis account delete --yes --json"]
|
|
910
1004
|
},
|
|
911
|
-
doctor: {
|
|
1005
|
+
doctor: {
|
|
1006
|
+
examples: ["dropthis doctor --json", "dropthis doctor --online --json"]
|
|
1007
|
+
},
|
|
912
1008
|
upgrade: { examples: ["dropthis upgrade", "dropthis upgrade --json"] },
|
|
913
1009
|
commands: { examples: ["dropthis commands --json"] }
|
|
914
1010
|
};
|
|
@@ -935,6 +1031,12 @@ function toEntry(cmd, path) {
|
|
|
935
1031
|
function buildCatalog(program) {
|
|
936
1032
|
return program.commands.map((cmd) => toEntry(cmd, []));
|
|
937
1033
|
}
|
|
1034
|
+
function buildGlobalOptions(program) {
|
|
1035
|
+
return program.options.map((o) => ({
|
|
1036
|
+
flags: o.flags,
|
|
1037
|
+
description: o.description
|
|
1038
|
+
}));
|
|
1039
|
+
}
|
|
938
1040
|
|
|
939
1041
|
// src/commands/commands.ts
|
|
940
1042
|
async function runCommands(_input, deps) {
|
|
@@ -942,7 +1044,9 @@ async function runCommands(_input, deps) {
|
|
|
942
1044
|
`${JSON.stringify({
|
|
943
1045
|
ok: true,
|
|
944
1046
|
output: "JSON by default in CI, pipes, non-TTY, --json, or --quiet.",
|
|
945
|
-
commands: buildCatalog(deps.program)
|
|
1047
|
+
commands: buildCatalog(deps.program),
|
|
1048
|
+
global_options: buildGlobalOptions(deps.program),
|
|
1049
|
+
exit_codes: EXIT_CODES
|
|
946
1050
|
})}
|
|
947
1051
|
`
|
|
948
1052
|
);
|
|
@@ -1032,10 +1136,76 @@ function spreadData(data) {
|
|
|
1032
1136
|
}
|
|
1033
1137
|
|
|
1034
1138
|
// src/version.ts
|
|
1035
|
-
var CLI_VERSION = true ? "0.
|
|
1139
|
+
var CLI_VERSION = true ? "0.33.1" : "0.0.0-dev";
|
|
1036
1140
|
|
|
1037
1141
|
// src/commands/doctor.ts
|
|
1038
|
-
async function
|
|
1142
|
+
async function onlineChecks(deps, hasCredential) {
|
|
1143
|
+
if (!hasCredential) {
|
|
1144
|
+
return {
|
|
1145
|
+
checks: [
|
|
1146
|
+
{
|
|
1147
|
+
name: "auth",
|
|
1148
|
+
status: "fail",
|
|
1149
|
+
detail: "No credential found \u2014 run `dropthis login` or set DROPTHIS_API_KEY."
|
|
1150
|
+
}
|
|
1151
|
+
],
|
|
1152
|
+
exitCode: exitCodeFor("auth_error")
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
const account = await deps.client.account.get();
|
|
1156
|
+
if (account.error) {
|
|
1157
|
+
const code = cliErrorCodeFor(account.error);
|
|
1158
|
+
const isAuth = code === "auth_error";
|
|
1159
|
+
return {
|
|
1160
|
+
checks: [
|
|
1161
|
+
{
|
|
1162
|
+
name: "api_reachable",
|
|
1163
|
+
status: isAuth ? "ok" : "fail",
|
|
1164
|
+
detail: isAuth ? "reached the API" : `could not reach the API: ${account.error.message}`
|
|
1165
|
+
},
|
|
1166
|
+
{
|
|
1167
|
+
name: "auth",
|
|
1168
|
+
status: isAuth ? "fail" : "warn",
|
|
1169
|
+
detail: isAuth ? "credential rejected \u2014 re-authenticate with `dropthis login`" : account.error.message
|
|
1170
|
+
}
|
|
1171
|
+
],
|
|
1172
|
+
exitCode: exitCodeFor(code)
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
const data = account.data;
|
|
1176
|
+
const checks = [
|
|
1177
|
+
{ name: "api_reachable", status: "ok", detail: "reached the API" },
|
|
1178
|
+
{ name: "auth", status: "ok", detail: "credential accepted" }
|
|
1179
|
+
];
|
|
1180
|
+
const ws = data?.workspace;
|
|
1181
|
+
checks.push(
|
|
1182
|
+
ws?.name ? {
|
|
1183
|
+
name: "workspace",
|
|
1184
|
+
status: "ok",
|
|
1185
|
+
detail: `active: ${String(ws.name)} (${String(ws.kind)})`
|
|
1186
|
+
} : {
|
|
1187
|
+
name: "workspace",
|
|
1188
|
+
status: "warn",
|
|
1189
|
+
detail: "no active workspace resolved \u2014 pass --workspace or run `dropthis workspace use`"
|
|
1190
|
+
}
|
|
1191
|
+
);
|
|
1192
|
+
if (data?.plan) {
|
|
1193
|
+
checks.push({ name: "plan", status: "ok", detail: String(data.plan) });
|
|
1194
|
+
}
|
|
1195
|
+
const domains = await deps.client.domains.list();
|
|
1196
|
+
if (!domains.error) {
|
|
1197
|
+
const list = domains.data?.domains ?? [];
|
|
1198
|
+
const live = list.filter((d) => d.status === "live").length;
|
|
1199
|
+
const pending = list.length - live;
|
|
1200
|
+
checks.push({
|
|
1201
|
+
name: "domains",
|
|
1202
|
+
status: pending > 0 ? "warn" : "ok",
|
|
1203
|
+
detail: `${list.length} connected, ${live} live${pending > 0 ? `, ${pending} pending verification` : ""}`
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
return { checks, exitCode: 0 };
|
|
1207
|
+
}
|
|
1208
|
+
async function runDoctor(input, deps) {
|
|
1039
1209
|
const stored = await deps.store.read();
|
|
1040
1210
|
const credential = await resolveCredential({
|
|
1041
1211
|
env: deps.env,
|
|
@@ -1048,13 +1218,30 @@ async function runDoctor(_input, deps) {
|
|
|
1048
1218
|
["Auth", authSource],
|
|
1049
1219
|
["Storage", storageBackend]
|
|
1050
1220
|
];
|
|
1221
|
+
if (!input.online) {
|
|
1222
|
+
writeKv(deps, pairs, {
|
|
1223
|
+
ok: true,
|
|
1224
|
+
version: CLI_VERSION,
|
|
1225
|
+
auth: { source: authSource },
|
|
1226
|
+
storage: { backend: storageBackend }
|
|
1227
|
+
});
|
|
1228
|
+
return { exitCode: 0 };
|
|
1229
|
+
}
|
|
1230
|
+
const { checks, exitCode } = await onlineChecks(
|
|
1231
|
+
deps,
|
|
1232
|
+
credential !== void 0
|
|
1233
|
+
);
|
|
1234
|
+
for (const c of checks) {
|
|
1235
|
+
pairs.push([c.name, `${c.status} \u2014 ${c.detail}`]);
|
|
1236
|
+
}
|
|
1051
1237
|
writeKv(deps, pairs, {
|
|
1052
|
-
ok:
|
|
1238
|
+
ok: exitCode === 0,
|
|
1053
1239
|
version: CLI_VERSION,
|
|
1054
1240
|
auth: { source: authSource },
|
|
1055
|
-
storage: { backend: storageBackend }
|
|
1241
|
+
storage: { backend: storageBackend },
|
|
1242
|
+
checks
|
|
1056
1243
|
});
|
|
1057
|
-
return { exitCode
|
|
1244
|
+
return { exitCode };
|
|
1058
1245
|
}
|
|
1059
1246
|
|
|
1060
1247
|
// src/commands/domains.ts
|
|
@@ -1635,8 +1822,8 @@ async function runDropsDelete(target, input, deps) {
|
|
|
1635
1822
|
return { exitCode: 0 };
|
|
1636
1823
|
}
|
|
1637
1824
|
|
|
1638
|
-
// src/commands/
|
|
1639
|
-
async function
|
|
1825
|
+
// src/commands/invitations.ts
|
|
1826
|
+
async function runInvitationsList(_input, deps) {
|
|
1640
1827
|
try {
|
|
1641
1828
|
await requireCredential({
|
|
1642
1829
|
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
@@ -1646,45 +1833,67 @@ async function runKeysCreate(input, deps) {
|
|
|
1646
1833
|
} catch {
|
|
1647
1834
|
return writeAuthError(deps);
|
|
1648
1835
|
}
|
|
1649
|
-
const
|
|
1650
|
-
if (
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1836
|
+
const result = await deps.client.invitations.list();
|
|
1837
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
1838
|
+
const raw = unwrapListData(result.data, "invitations");
|
|
1839
|
+
const items = Array.isArray(raw) ? raw : [];
|
|
1840
|
+
if (deps.outputMode === "human") {
|
|
1841
|
+
if (items.length === 0) {
|
|
1842
|
+
writeEmpty(deps, "No pending invitations.", {
|
|
1843
|
+
ok: true,
|
|
1844
|
+
invitations: []
|
|
1845
|
+
});
|
|
1846
|
+
} else {
|
|
1847
|
+
for (const inv of items) {
|
|
1848
|
+
deps.stdout(`${inv.email} ${inv.role} ${inv.status} ${inv.id}
|
|
1849
|
+
`);
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
} else {
|
|
1853
|
+
writeJson(deps, { ok: true, invitations: items });
|
|
1664
1854
|
}
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1855
|
+
return { exitCode: 0 };
|
|
1856
|
+
}
|
|
1857
|
+
async function runInvitationsAccept(input, deps) {
|
|
1858
|
+
try {
|
|
1859
|
+
await requireCredential({
|
|
1860
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
1861
|
+
env: deps.env,
|
|
1862
|
+
store: deps.store
|
|
1863
|
+
});
|
|
1864
|
+
} catch {
|
|
1865
|
+
return writeAuthError(deps);
|
|
1672
1866
|
}
|
|
1673
|
-
const result = await deps.client.
|
|
1867
|
+
const result = await deps.client.invitations.accept({ token: input.token });
|
|
1674
1868
|
if (result.error) return writeApiError(deps, result.error);
|
|
1675
|
-
const
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1869
|
+
const ws = result.data;
|
|
1870
|
+
writeHumanOrJson(
|
|
1871
|
+
deps,
|
|
1872
|
+
success(`Joined ${ws.name} (${ws.slug}) \u2014 now your active workspace.`),
|
|
1873
|
+
{ ok: true, workspace: ws }
|
|
1874
|
+
);
|
|
1875
|
+
return { exitCode: 0 };
|
|
1876
|
+
}
|
|
1877
|
+
async function runInvitationsAcceptById(input, deps) {
|
|
1878
|
+
try {
|
|
1879
|
+
await requireCredential({
|
|
1880
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
1881
|
+
env: deps.env,
|
|
1882
|
+
store: deps.store
|
|
1883
|
+
});
|
|
1884
|
+
} catch {
|
|
1885
|
+
return writeAuthError(deps);
|
|
1687
1886
|
}
|
|
1887
|
+
const result = await deps.client.invitations.acceptById({
|
|
1888
|
+
invitationId: input.invitationId
|
|
1889
|
+
});
|
|
1890
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
1891
|
+
const ws = result.data;
|
|
1892
|
+
writeHumanOrJson(
|
|
1893
|
+
deps,
|
|
1894
|
+
success(`Joined ${ws.name} (${ws.slug}) \u2014 now your active workspace.`),
|
|
1895
|
+
{ ok: true, workspace: ws }
|
|
1896
|
+
);
|
|
1688
1897
|
return { exitCode: 0 };
|
|
1689
1898
|
}
|
|
1690
1899
|
|
|
@@ -1747,7 +1956,8 @@ async function runLoginInteractive(deps) {
|
|
|
1747
1956
|
const authedClient = deps.createClient(session.data.token);
|
|
1748
1957
|
const apiKey = await authedClient.apiKeys.create({
|
|
1749
1958
|
label: "CLI",
|
|
1750
|
-
type: "delegated"
|
|
1959
|
+
type: "delegated",
|
|
1960
|
+
...deps.scope ? { scopes: [deps.scope] } : {}
|
|
1751
1961
|
});
|
|
1752
1962
|
if (apiKey.error) {
|
|
1753
1963
|
prompts4.cancel(apiKey.error.message);
|
|
@@ -1759,6 +1969,7 @@ async function runLoginInteractive(deps) {
|
|
|
1759
1969
|
keyLast4: apiKey.data.keyLast4,
|
|
1760
1970
|
accountId: apiKey.data.accountId ?? session.data.accountId,
|
|
1761
1971
|
email,
|
|
1972
|
+
...apiKey.data.scopes ? { scopes: apiKey.data.scopes } : {},
|
|
1762
1973
|
storage: "secure"
|
|
1763
1974
|
});
|
|
1764
1975
|
prompts4.outro("Logged in successfully.");
|
|
@@ -1793,7 +2004,10 @@ async function runLoginVerify(input, deps) {
|
|
|
1793
2004
|
const authedClient = deps.createClient(session.data.token);
|
|
1794
2005
|
const apiKey = await authedClient.apiKeys.create({
|
|
1795
2006
|
label: "CLI",
|
|
1796
|
-
type: "delegated"
|
|
2007
|
+
type: "delegated",
|
|
2008
|
+
// A single bundle name (e.g. "team") requests a capability-scoped key; the
|
|
2009
|
+
// server returns the resolved scope list on the mint response.
|
|
2010
|
+
...input.scope ? { scopes: [input.scope] } : {}
|
|
1797
2011
|
});
|
|
1798
2012
|
if (apiKey.error) {
|
|
1799
2013
|
return writeApiError(deps, apiKey.error);
|
|
@@ -1804,6 +2018,7 @@ async function runLoginVerify(input, deps) {
|
|
|
1804
2018
|
keyLast4: apiKey.data.keyLast4,
|
|
1805
2019
|
accountId: apiKey.data.accountId ?? session.data.accountId,
|
|
1806
2020
|
email: input.email,
|
|
2021
|
+
...apiKey.data.scopes ? { scopes: apiKey.data.scopes } : {},
|
|
1807
2022
|
storage: "secure"
|
|
1808
2023
|
});
|
|
1809
2024
|
writeHumanOrJson(deps, success(`Logged in as ${input.email}.`), {
|
|
@@ -1832,6 +2047,115 @@ async function runLogout(input, deps) {
|
|
|
1832
2047
|
return { exitCode: 0 };
|
|
1833
2048
|
}
|
|
1834
2049
|
|
|
2050
|
+
// src/commands/members.ts
|
|
2051
|
+
var prompts5 = __toESM(require("@clack/prompts"), 1);
|
|
2052
|
+
async function runMembersList(workspaceId, _input, deps) {
|
|
2053
|
+
try {
|
|
2054
|
+
await requireCredential({
|
|
2055
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
2056
|
+
env: deps.env,
|
|
2057
|
+
store: deps.store
|
|
2058
|
+
});
|
|
2059
|
+
} catch {
|
|
2060
|
+
return writeAuthError(deps);
|
|
2061
|
+
}
|
|
2062
|
+
const result = await deps.client.members.list(workspaceId);
|
|
2063
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
2064
|
+
const raw = unwrapListData(result.data, "members");
|
|
2065
|
+
const items = Array.isArray(raw) ? raw : [];
|
|
2066
|
+
if (deps.outputMode === "human") {
|
|
2067
|
+
if (items.length === 0) {
|
|
2068
|
+
writeEmpty(deps, "No members.", { ok: true, members: [] });
|
|
2069
|
+
} else {
|
|
2070
|
+
for (const m of items) {
|
|
2071
|
+
const who = m.email || m.accountId;
|
|
2072
|
+
const you = m.isYou ? "(you)" : "";
|
|
2073
|
+
deps.stdout(`${who} ${m.role} ${you}
|
|
2074
|
+
`);
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
} else {
|
|
2078
|
+
writeJson(deps, { ok: true, members: items });
|
|
2079
|
+
}
|
|
2080
|
+
return { exitCode: 0 };
|
|
2081
|
+
}
|
|
2082
|
+
async function runMembersInvite(workspaceId, input, deps) {
|
|
2083
|
+
try {
|
|
2084
|
+
await requireCredential({
|
|
2085
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
2086
|
+
env: deps.env,
|
|
2087
|
+
store: deps.store
|
|
2088
|
+
});
|
|
2089
|
+
} catch {
|
|
2090
|
+
return writeAuthError(deps);
|
|
2091
|
+
}
|
|
2092
|
+
const role = input.role ?? "member";
|
|
2093
|
+
const result = await deps.client.members.invite(workspaceId, {
|
|
2094
|
+
email: input.email,
|
|
2095
|
+
role
|
|
2096
|
+
});
|
|
2097
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
2098
|
+
writeHumanOrJson(deps, success(`Invited ${input.email} as ${role}`), {
|
|
2099
|
+
ok: true,
|
|
2100
|
+
invitation: result.data
|
|
2101
|
+
});
|
|
2102
|
+
return { exitCode: 0 };
|
|
2103
|
+
}
|
|
2104
|
+
async function runMembersRole(workspaceId, accountId, input, deps) {
|
|
2105
|
+
try {
|
|
2106
|
+
await requireCredential({
|
|
2107
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
2108
|
+
env: deps.env,
|
|
2109
|
+
store: deps.store
|
|
2110
|
+
});
|
|
2111
|
+
} catch {
|
|
2112
|
+
return writeAuthError(deps);
|
|
2113
|
+
}
|
|
2114
|
+
const result = await deps.client.members.updateRole(workspaceId, accountId, {
|
|
2115
|
+
role: input.role
|
|
2116
|
+
});
|
|
2117
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
2118
|
+
writeHumanOrJson(deps, success(`Set ${accountId} to ${input.role}`), {
|
|
2119
|
+
ok: true,
|
|
2120
|
+
member: result.data
|
|
2121
|
+
});
|
|
2122
|
+
return { exitCode: 0 };
|
|
2123
|
+
}
|
|
2124
|
+
async function runMembersRemove(workspaceId, accountId, input, deps) {
|
|
2125
|
+
if (!input.yes && input.interactive === false) {
|
|
2126
|
+
return writeError(
|
|
2127
|
+
deps,
|
|
2128
|
+
"invalid_usage",
|
|
2129
|
+
"Pass --yes to remove in non-interactive mode."
|
|
2130
|
+
);
|
|
2131
|
+
}
|
|
2132
|
+
if (!input.yes && input.interactive !== false) {
|
|
2133
|
+
const confirmed = await prompts5.confirm({
|
|
2134
|
+
message: `Remove ${accountId} from workspace ${workspaceId}?`
|
|
2135
|
+
});
|
|
2136
|
+
if (prompts5.isCancel(confirmed) || !confirmed) {
|
|
2137
|
+
return { exitCode: 0 };
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
try {
|
|
2141
|
+
await requireCredential({
|
|
2142
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
2143
|
+
env: deps.env,
|
|
2144
|
+
store: deps.store
|
|
2145
|
+
});
|
|
2146
|
+
} catch {
|
|
2147
|
+
return writeAuthError(deps);
|
|
2148
|
+
}
|
|
2149
|
+
const result = await deps.client.members.remove(workspaceId, accountId);
|
|
2150
|
+
if (result?.error) return writeApiError(deps, result.error);
|
|
2151
|
+
writeHumanOrJson(deps, success(`Removed ${accountId}`), {
|
|
2152
|
+
ok: true,
|
|
2153
|
+
removed: true,
|
|
2154
|
+
account_id: accountId
|
|
2155
|
+
});
|
|
2156
|
+
return { exitCode: 0 };
|
|
2157
|
+
}
|
|
2158
|
+
|
|
1835
2159
|
// src/drop-operations.ts
|
|
1836
2160
|
var import_node_crypto = require("crypto");
|
|
1837
2161
|
var import_promises = require("fs/promises");
|
|
@@ -1968,6 +2292,9 @@ async function parseDropOptions(raw) {
|
|
|
1968
2292
|
if (raw.noindex && raw.index) {
|
|
1969
2293
|
throw new Error("Use either --noindex or --index, not both.");
|
|
1970
2294
|
}
|
|
2295
|
+
if (raw.expiresAt && raw.noExpires) {
|
|
2296
|
+
throw new Error("Use either --expires-at or --no-expires, not both.");
|
|
2297
|
+
}
|
|
1971
2298
|
if (raw.shared && raw.domain) {
|
|
1972
2299
|
throw new Error("Use either --shared or --domain <hostname>, not both.");
|
|
1973
2300
|
}
|
|
@@ -1996,6 +2323,7 @@ async function parseDropOptions(raw) {
|
|
|
1996
2323
|
...raw.noindex ? { noindex: true } : {},
|
|
1997
2324
|
...raw.index ? { noindex: false } : {},
|
|
1998
2325
|
...raw.expiresAt ? { expiresAt: raw.expiresAt } : {},
|
|
2326
|
+
...raw.noExpires ? { expiresAt: null } : {},
|
|
1999
2327
|
...metadata ? { metadata } : {},
|
|
2000
2328
|
...raw.entry ? { entry: raw.entry } : {},
|
|
2001
2329
|
...raw.contentType ? { contentType: raw.contentType } : {},
|
|
@@ -2197,7 +2525,9 @@ async function runPull(target, input, deps) {
|
|
|
2197
2525
|
const dropId = resolved.dropId;
|
|
2198
2526
|
const defaultDirName = resolved.slug || resolved.dropId;
|
|
2199
2527
|
const spin = shouldSpin(deps.outputMode) ? createSpinner("Pulling content\u2026", deps.stderr) : void 0;
|
|
2200
|
-
const
|
|
2528
|
+
const deploymentId = input.deployment;
|
|
2529
|
+
const manifestOptions = deploymentId ? { deploymentId } : void 0;
|
|
2530
|
+
const manifestResult = manifestOptions ? await deps.client.drops.getContent(dropId, manifestOptions) : await deps.client.drops.getContent(dropId);
|
|
2201
2531
|
if (manifestResult.error) {
|
|
2202
2532
|
spin?.fail();
|
|
2203
2533
|
return writeApiError(deps, manifestResult.error);
|
|
@@ -2221,7 +2551,10 @@ async function runPull(target, input, deps) {
|
|
|
2221
2551
|
try {
|
|
2222
2552
|
await (0, import_promises3.mkdir)(outDir, { recursive: true });
|
|
2223
2553
|
for (const { path, dest } of destinations) {
|
|
2224
|
-
const fileResult = await deps.client.drops.getContent(dropId, {
|
|
2554
|
+
const fileResult = await deps.client.drops.getContent(dropId, {
|
|
2555
|
+
path,
|
|
2556
|
+
...deploymentId ? { deploymentId } : {}
|
|
2557
|
+
});
|
|
2225
2558
|
if (fileResult.error) {
|
|
2226
2559
|
spin?.fail();
|
|
2227
2560
|
return writeApiError(deps, {
|
|
@@ -2408,9 +2741,9 @@ async function handleDryRun(dropId, input, raw, deps) {
|
|
|
2408
2741
|
}
|
|
2409
2742
|
|
|
2410
2743
|
// src/commands/update-settings.ts
|
|
2411
|
-
var
|
|
2744
|
+
var prompts6 = __toESM(require("@clack/prompts"), 1);
|
|
2412
2745
|
var NO_SETTINGS_MESSAGE = "Nothing to update. Provide at least one settings option.";
|
|
2413
|
-
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.";
|
|
2746
|
+
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.";
|
|
2414
2747
|
async function runUpdateSettings(target, raw, deps) {
|
|
2415
2748
|
const apiKey = raw.apiKey ?? deps.apiKey;
|
|
2416
2749
|
try {
|
|
@@ -2440,7 +2773,7 @@ async function runUpdateSettings(target, raw, deps) {
|
|
|
2440
2773
|
if (shouldPrompt(deps)) {
|
|
2441
2774
|
const prompted = await promptForSettings(
|
|
2442
2775
|
dropId,
|
|
2443
|
-
deps.prompts ??
|
|
2776
|
+
deps.prompts ?? prompts6
|
|
2444
2777
|
);
|
|
2445
2778
|
if (!prompted) return { exitCode: 0 };
|
|
2446
2779
|
parsed = { ...parsed, ...prompted };
|
|
@@ -2629,8 +2962,10 @@ async function handleDryRun2(dropId, raw, deps) {
|
|
|
2629
2962
|
if (options.visibility) fields.visibility = options.visibility;
|
|
2630
2963
|
if (options.password !== void 0) fields.password = options.password;
|
|
2631
2964
|
if (options.noindex !== void 0) fields.noindex = options.noindex;
|
|
2632
|
-
if (options.expiresAt) fields.expires_at = options.expiresAt;
|
|
2965
|
+
if (options.expiresAt !== void 0) fields.expires_at = options.expiresAt;
|
|
2633
2966
|
if (options.metadata) fields.metadata = options.metadata;
|
|
2967
|
+
if (options.domain) fields.domain = options.domain;
|
|
2968
|
+
if (options.slug) fields.slug = options.slug;
|
|
2634
2969
|
deps.stdout(
|
|
2635
2970
|
`${JSON.stringify({ ok: true, dryRun: true, kind: "settings_update", target: dropId, fields }, null, 2)}
|
|
2636
2971
|
`
|
|
@@ -2778,6 +3113,8 @@ async function runWhoami(_input, deps) {
|
|
|
2778
3113
|
pairs.push(["Source", credential.source]);
|
|
2779
3114
|
if (credential.accountId ?? account.id)
|
|
2780
3115
|
pairs.push(["Account", String(credential.accountId ?? account.id)]);
|
|
3116
|
+
if (credential.scopes?.length)
|
|
3117
|
+
pairs.push(["Scopes", credential.scopes.join(", ")]);
|
|
2781
3118
|
const jsonEnvelope = {
|
|
2782
3119
|
ok: true,
|
|
2783
3120
|
authenticated: true,
|
|
@@ -2786,13 +3123,15 @@ async function runWhoami(_input, deps) {
|
|
|
2786
3123
|
...credential.keyId ? { key_id: credential.keyId } : {},
|
|
2787
3124
|
...last4 ? { key_last4: last4 } : {},
|
|
2788
3125
|
...credential.accountId ?? account.id ? { account_id: String(credential.accountId ?? account.id) } : {},
|
|
2789
|
-
...credential.email ?? account.email ? { email: String(credential.email ?? account.email) } : {}
|
|
3126
|
+
...credential.email ?? account.email ? { email: String(credential.email ?? account.email) } : {},
|
|
3127
|
+
...credential.scopes?.length ? { scopes: credential.scopes } : {}
|
|
2790
3128
|
};
|
|
2791
3129
|
writeKv(deps, pairs, jsonEnvelope);
|
|
2792
3130
|
return { exitCode: 0 };
|
|
2793
3131
|
}
|
|
2794
3132
|
|
|
2795
3133
|
// src/commands/workspace.ts
|
|
3134
|
+
var prompts7 = __toESM(require("@clack/prompts"), 1);
|
|
2796
3135
|
async function runWorkspaceList(_input, deps) {
|
|
2797
3136
|
try {
|
|
2798
3137
|
await requireCredential({
|
|
@@ -2845,6 +3184,104 @@ async function runWorkspaceUse(slugOrId, _input, deps) {
|
|
|
2845
3184
|
);
|
|
2846
3185
|
return { exitCode: 0 };
|
|
2847
3186
|
}
|
|
3187
|
+
async function runWorkspaceCreate(input, deps) {
|
|
3188
|
+
try {
|
|
3189
|
+
await requireCredential({
|
|
3190
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
3191
|
+
env: deps.env,
|
|
3192
|
+
store: deps.store
|
|
3193
|
+
});
|
|
3194
|
+
} catch {
|
|
3195
|
+
return writeAuthError(deps);
|
|
3196
|
+
}
|
|
3197
|
+
const createInput = { name: input.name };
|
|
3198
|
+
if (input.slug !== void 0) createInput.slug = input.slug;
|
|
3199
|
+
const result = await deps.client.workspaces.create(createInput);
|
|
3200
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
3201
|
+
const ws = result.data;
|
|
3202
|
+
writeHumanOrJson(
|
|
3203
|
+
deps,
|
|
3204
|
+
success(`Created workspace: ${ws.name} (${ws.slug})`),
|
|
3205
|
+
{
|
|
3206
|
+
ok: true,
|
|
3207
|
+
workspace: ws
|
|
3208
|
+
}
|
|
3209
|
+
);
|
|
3210
|
+
if (ws.creatorCanReach === false && deps.outputMode === "human") {
|
|
3211
|
+
deps.stderr(
|
|
3212
|
+
`${hint("This key can't reach the new workspace \u2014 re-authenticate (dropthis login) to pick it up.")}
|
|
3213
|
+
`
|
|
3214
|
+
);
|
|
3215
|
+
}
|
|
3216
|
+
return { exitCode: 0 };
|
|
3217
|
+
}
|
|
3218
|
+
async function runWorkspaceRename(workspaceId, input, deps) {
|
|
3219
|
+
if (input.name === void 0 && input.slug === void 0) {
|
|
3220
|
+
return writeError(
|
|
3221
|
+
deps,
|
|
3222
|
+
"invalid_usage",
|
|
3223
|
+
"Provide --name and/or --slug to rename."
|
|
3224
|
+
);
|
|
3225
|
+
}
|
|
3226
|
+
try {
|
|
3227
|
+
await requireCredential({
|
|
3228
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
3229
|
+
env: deps.env,
|
|
3230
|
+
store: deps.store
|
|
3231
|
+
});
|
|
3232
|
+
} catch {
|
|
3233
|
+
return writeAuthError(deps);
|
|
3234
|
+
}
|
|
3235
|
+
const renameInput = {};
|
|
3236
|
+
if (input.name !== void 0) renameInput.name = input.name;
|
|
3237
|
+
if (input.slug !== void 0) renameInput.slug = input.slug;
|
|
3238
|
+
const result = await deps.client.workspaces.rename(workspaceId, renameInput);
|
|
3239
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
3240
|
+
const ws = result.data;
|
|
3241
|
+
writeHumanOrJson(
|
|
3242
|
+
deps,
|
|
3243
|
+
success(`Renamed workspace: ${ws.name} (${ws.slug})`),
|
|
3244
|
+
{
|
|
3245
|
+
ok: true,
|
|
3246
|
+
workspace: ws
|
|
3247
|
+
}
|
|
3248
|
+
);
|
|
3249
|
+
return { exitCode: 0 };
|
|
3250
|
+
}
|
|
3251
|
+
async function runWorkspaceDelete(workspaceId, input, deps) {
|
|
3252
|
+
if (!input.yes && input.interactive === false) {
|
|
3253
|
+
return writeError(
|
|
3254
|
+
deps,
|
|
3255
|
+
"invalid_usage",
|
|
3256
|
+
"Pass --yes to delete in non-interactive mode."
|
|
3257
|
+
);
|
|
3258
|
+
}
|
|
3259
|
+
if (!input.yes && input.interactive !== false) {
|
|
3260
|
+
const confirmed = await prompts7.confirm({
|
|
3261
|
+
message: `Delete workspace ${workspaceId}?`
|
|
3262
|
+
});
|
|
3263
|
+
if (prompts7.isCancel(confirmed) || !confirmed) {
|
|
3264
|
+
return { exitCode: 0 };
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
try {
|
|
3268
|
+
await requireCredential({
|
|
3269
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
3270
|
+
env: deps.env,
|
|
3271
|
+
store: deps.store
|
|
3272
|
+
});
|
|
3273
|
+
} catch {
|
|
3274
|
+
return writeAuthError(deps);
|
|
3275
|
+
}
|
|
3276
|
+
const result = await deps.client.workspaces.delete(workspaceId);
|
|
3277
|
+
if (result?.error) return writeApiError(deps, result.error);
|
|
3278
|
+
writeHumanOrJson(deps, success(`Deleted workspace ${workspaceId}`), {
|
|
3279
|
+
ok: true,
|
|
3280
|
+
deleted: true,
|
|
3281
|
+
id: workspaceId
|
|
3282
|
+
});
|
|
3283
|
+
return { exitCode: 0 };
|
|
3284
|
+
}
|
|
2848
3285
|
|
|
2849
3286
|
// src/context.ts
|
|
2850
3287
|
var import_node2 = require("@dropthis/node");
|
|
@@ -3170,7 +3607,8 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3170
3607
|
return;
|
|
3171
3608
|
}
|
|
3172
3609
|
}
|
|
3173
|
-
|
|
3610
|
+
const publishWasExplicit = (program.rawArgs ?? []).includes("publish");
|
|
3611
|
+
if (!publishWasExplicit && inputs.length === 1 && typeof publishInput === "string" && isBareWordToken(publishInput) && !await pathExists(publishInput)) {
|
|
3174
3612
|
const suggestion = suggestCommand(
|
|
3175
3613
|
publishInput,
|
|
3176
3614
|
program.commands.map((c) => c.name())
|
|
@@ -3184,13 +3622,15 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3184
3622
|
).exitCode;
|
|
3185
3623
|
return;
|
|
3186
3624
|
}
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3625
|
+
if (deps.outputMode === "human" && deps.interactive) {
|
|
3626
|
+
const prompts8 = await import("@clack/prompts");
|
|
3627
|
+
const confirmed = await prompts8.confirm({
|
|
3628
|
+
message: `Publish '${publishInput}' as inline text?`,
|
|
3629
|
+
initialValue: false
|
|
3630
|
+
});
|
|
3631
|
+
if (prompts8.isCancel(confirmed) || !confirmed) {
|
|
3632
|
+
return;
|
|
3633
|
+
}
|
|
3194
3634
|
}
|
|
3195
3635
|
}
|
|
3196
3636
|
let dropOpts;
|
|
@@ -3281,10 +3721,19 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3281
3721
|
);
|
|
3282
3722
|
program.command("update-settings <dropId>").description(
|
|
3283
3723
|
"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."
|
|
3284
|
-
).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(
|
|
3724
|
+
).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(
|
|
3285
3725
|
"--metadata <json>",
|
|
3286
3726
|
`Attach JSON key-value pairs, e.g. '{"source":"ci"}'`
|
|
3287
3727
|
).option("--metadata-file <path>", "Read metadata JSON from a file").option(
|
|
3728
|
+
"--domain <hostname>",
|
|
3729
|
+
"Move this drop to a connected custom domain (must be live \u2014 see: dropthis domains list)."
|
|
3730
|
+
).option(
|
|
3731
|
+
"--shared",
|
|
3732
|
+
"Unmount this drop back to the shared dropthis pool. Cannot combine with --domain."
|
|
3733
|
+
).option(
|
|
3734
|
+
"--slug <vanity-slug>",
|
|
3735
|
+
"Rename the vanity slug on a path-mode custom domain (1\u201363 lowercase letters/digits/hyphens). 409 on conflict \u2014 does not auto-suffix."
|
|
3736
|
+
).option(
|
|
3288
3737
|
"--if-revision <n>",
|
|
3289
3738
|
"Fail if current revision doesn't match (optimistic lock)",
|
|
3290
3739
|
parseInteger
|
|
@@ -3316,7 +3765,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3316
3765
|
);
|
|
3317
3766
|
program.command("pull <target>").description(
|
|
3318
3767
|
"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."
|
|
3319
|
-
).option("-o, --output <dir>", "Output directory (default: ./<slug-or-id>)").option("--json", "Force JSON output").addHelpText(
|
|
3768
|
+
).option("-o, --output <dir>", "Output directory (default: ./<slug-or-id>)").option("--deployment <deploymentId>", "Download a specific deployment").option("--json", "Force JSON output").addHelpText(
|
|
3320
3769
|
"after",
|
|
3321
3770
|
examplesBlock([
|
|
3322
3771
|
"dropthis pull drop_abc123 -o ./site # download the drop's files",
|
|
@@ -3452,7 +3901,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3452
3901
|
process.exitCode = result.exitCode;
|
|
3453
3902
|
});
|
|
3454
3903
|
domains.command("verify <hostname>").description(
|
|
3455
|
-
"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).
|
|
3904
|
+
"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."
|
|
3456
3905
|
).option("--wait", "Poll until live (or failed/timeout)").option(
|
|
3457
3906
|
"--timeout <secs>",
|
|
3458
3907
|
"Max seconds to wait (default: 300)",
|
|
@@ -3508,11 +3957,35 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3508
3957
|
}
|
|
3509
3958
|
);
|
|
3510
3959
|
const apiKeys = program.command("api-keys").description("Manage API keys");
|
|
3511
|
-
apiKeys.command("create").description(
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3960
|
+
apiKeys.command("create").description(
|
|
3961
|
+
"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."
|
|
3962
|
+
).option("--label <label>", "API key label").option(
|
|
3963
|
+
"--service",
|
|
3964
|
+
"Mint a pinned service key for CI/automation (requires --workspace to pin it)"
|
|
3965
|
+
).option(
|
|
3966
|
+
"--workspace <slugOrId>",
|
|
3967
|
+
"Pin this service key to the given workspace slug or id (only valid with --service)"
|
|
3968
|
+
).option(
|
|
3969
|
+
"--allowed-workspace <slugOrId>",
|
|
3970
|
+
"Allow a delegated key to access the given workspace slug or id",
|
|
3971
|
+
collect,
|
|
3972
|
+
[]
|
|
3973
|
+
).option("--json", "Force JSON output").action(
|
|
3974
|
+
async (commandOptions) => {
|
|
3975
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3976
|
+
const result = await runApiKeysCreate(
|
|
3977
|
+
{
|
|
3978
|
+
...commandOptions.label !== void 0 ? { label: commandOptions.label } : {},
|
|
3979
|
+
type: commandOptions.service ? "service" : "delegated",
|
|
3980
|
+
...commandOptions.workspace !== void 0 ? { workspace: commandOptions.workspace } : {},
|
|
3981
|
+
...commandOptions.allowedWorkspace?.length ? { allowedWorkspaces: commandOptions.allowedWorkspace } : {},
|
|
3982
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
3983
|
+
},
|
|
3984
|
+
deps
|
|
3985
|
+
);
|
|
3986
|
+
process.exitCode = result.exitCode;
|
|
3987
|
+
}
|
|
3988
|
+
);
|
|
3516
3989
|
apiKeys.command("list").description("List API keys").option("--json", "Force JSON output").action(async (commandOptions) => {
|
|
3517
3990
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3518
3991
|
const result = await runApiKeysList(commandOptions, deps);
|
|
@@ -3549,25 +4022,121 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3549
4022
|
const result = await runWorkspaceUse(slugOrId, commandOptions, deps);
|
|
3550
4023
|
process.exitCode = result.exitCode;
|
|
3551
4024
|
});
|
|
3552
|
-
|
|
3553
|
-
|
|
4025
|
+
workspace.command("create <name>").description("Create a new team workspace").option("--slug <slug>", "Vanity slug for the workspace").option("--json", "Force JSON output").action(
|
|
4026
|
+
async (name, commandOptions) => {
|
|
4027
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4028
|
+
const result = await runWorkspaceCreate(
|
|
4029
|
+
{
|
|
4030
|
+
name,
|
|
4031
|
+
...commandOptions.slug !== void 0 ? { slug: commandOptions.slug } : {},
|
|
4032
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
4033
|
+
},
|
|
4034
|
+
deps
|
|
4035
|
+
);
|
|
4036
|
+
process.exitCode = result.exitCode;
|
|
4037
|
+
}
|
|
3554
4038
|
);
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
).option("--label <label>", "Key label").option(
|
|
3558
|
-
"--service",
|
|
3559
|
-
"Mint a pinned service key for CI/automation (requires --workspace to pin it)"
|
|
3560
|
-
).option(
|
|
3561
|
-
"--workspace <slugOrId>",
|
|
3562
|
-
"Pin this service key to the given workspace slug or id (only valid with --service)"
|
|
3563
|
-
).option("--json", "Force JSON output").action(
|
|
3564
|
-
async (commandOptions) => {
|
|
4039
|
+
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(
|
|
4040
|
+
async (workspaceId, commandOptions) => {
|
|
3565
4041
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3566
|
-
const result = await
|
|
4042
|
+
const result = await runWorkspaceRename(
|
|
4043
|
+
workspaceId,
|
|
3567
4044
|
{
|
|
3568
|
-
...commandOptions.
|
|
3569
|
-
|
|
3570
|
-
...commandOptions.
|
|
4045
|
+
...commandOptions.name !== void 0 ? { name: commandOptions.name } : {},
|
|
4046
|
+
...commandOptions.slug !== void 0 ? { slug: commandOptions.slug } : {},
|
|
4047
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
4048
|
+
},
|
|
4049
|
+
deps
|
|
4050
|
+
);
|
|
4051
|
+
process.exitCode = result.exitCode;
|
|
4052
|
+
}
|
|
4053
|
+
);
|
|
4054
|
+
workspace.command("delete <workspaceId>").description("Delete a workspace").option("--yes", "Confirm deletion").option("--json", "Force JSON output").action(
|
|
4055
|
+
async (workspaceId, commandOptions) => {
|
|
4056
|
+
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
4057
|
+
const global = globalOptions(program, commandOptions);
|
|
4058
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4059
|
+
const result = await runWorkspaceDelete(
|
|
4060
|
+
workspaceId,
|
|
4061
|
+
{
|
|
4062
|
+
...commandOptions,
|
|
4063
|
+
interactive: isInteractive(stdinIsTTY, deps.env, global)
|
|
4064
|
+
},
|
|
4065
|
+
deps
|
|
4066
|
+
);
|
|
4067
|
+
process.exitCode = result.exitCode;
|
|
4068
|
+
}
|
|
4069
|
+
);
|
|
4070
|
+
const members = program.command("members").description("Manage team members");
|
|
4071
|
+
members.command("list <workspaceId>").description("List members of a workspace").option("--json", "Force JSON output").action(async (workspaceId, commandOptions) => {
|
|
4072
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4073
|
+
const result = await runMembersList(workspaceId, commandOptions, deps);
|
|
4074
|
+
process.exitCode = result.exitCode;
|
|
4075
|
+
});
|
|
4076
|
+
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(
|
|
4077
|
+
async (workspaceId, commandOptions) => {
|
|
4078
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4079
|
+
const result = await runMembersInvite(
|
|
4080
|
+
workspaceId,
|
|
4081
|
+
{
|
|
4082
|
+
email: commandOptions.email,
|
|
4083
|
+
...commandOptions.role !== void 0 ? { role: commandOptions.role } : {},
|
|
4084
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
4085
|
+
},
|
|
4086
|
+
deps
|
|
4087
|
+
);
|
|
4088
|
+
process.exitCode = result.exitCode;
|
|
4089
|
+
}
|
|
4090
|
+
);
|
|
4091
|
+
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(
|
|
4092
|
+
async (workspaceId, accountId, commandOptions) => {
|
|
4093
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4094
|
+
const result = await runMembersRole(
|
|
4095
|
+
workspaceId,
|
|
4096
|
+
accountId,
|
|
4097
|
+
{
|
|
4098
|
+
role: commandOptions.role,
|
|
4099
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
4100
|
+
},
|
|
4101
|
+
deps
|
|
4102
|
+
);
|
|
4103
|
+
process.exitCode = result.exitCode;
|
|
4104
|
+
}
|
|
4105
|
+
);
|
|
4106
|
+
members.command("remove <workspaceId> <accountId>").description("Remove a member from a workspace").option("--yes", "Confirm removal").option("--json", "Force JSON output").action(
|
|
4107
|
+
async (workspaceId, accountId, commandOptions) => {
|
|
4108
|
+
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
4109
|
+
const global = globalOptions(program, commandOptions);
|
|
4110
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4111
|
+
const result = await runMembersRemove(
|
|
4112
|
+
workspaceId,
|
|
4113
|
+
accountId,
|
|
4114
|
+
{
|
|
4115
|
+
...commandOptions,
|
|
4116
|
+
interactive: isInteractive(stdinIsTTY, deps.env, global)
|
|
4117
|
+
},
|
|
4118
|
+
deps
|
|
4119
|
+
);
|
|
4120
|
+
process.exitCode = result.exitCode;
|
|
4121
|
+
}
|
|
4122
|
+
);
|
|
4123
|
+
const invitations = program.command("invitations").description("Manage your workspace invitations");
|
|
4124
|
+
invitations.command("list", { isDefault: true }).description("List your pending workspace invitations").option("--json", "Force JSON output").action(async (commandOptions) => {
|
|
4125
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4126
|
+
const result = await runInvitationsList(commandOptions, deps);
|
|
4127
|
+
process.exitCode = result.exitCode;
|
|
4128
|
+
});
|
|
4129
|
+
invitations.command("accept").description("Accept a workspace invitation by token").requiredOption("--token <token>", "Invitation token").option("--json", "Force JSON output").action(async (commandOptions) => {
|
|
4130
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4131
|
+
const result = await runInvitationsAccept(commandOptions, deps);
|
|
4132
|
+
process.exitCode = result.exitCode;
|
|
4133
|
+
});
|
|
4134
|
+
invitations.command("accept-by-id <invitationId>").description("Accept a workspace invitation by its id").option("--json", "Force JSON output").action(
|
|
4135
|
+
async (invitationId, commandOptions) => {
|
|
4136
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4137
|
+
const result = await runInvitationsAcceptById(
|
|
4138
|
+
{
|
|
4139
|
+
invitationId,
|
|
3571
4140
|
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
3572
4141
|
},
|
|
3573
4142
|
deps
|
|
@@ -3575,7 +4144,10 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3575
4144
|
process.exitCode = result.exitCode;
|
|
3576
4145
|
}
|
|
3577
4146
|
);
|
|
3578
|
-
program.command("login").description("Authenticate with email OTP").option("--email <email>", "Email address").option("--otp <otp>", "One-time passcode").option(
|
|
4147
|
+
program.command("login").description("Authenticate with email OTP").option("--email <email>", "Email address").option("--otp <otp>", "One-time passcode").option(
|
|
4148
|
+
"--scope <scope>",
|
|
4149
|
+
"Capability scope to request for the minted key (e.g. team)"
|
|
4150
|
+
).option("--json", "Force JSON output").action(
|
|
3579
4151
|
async (commandOptions) => {
|
|
3580
4152
|
if (!commandOptions.email || !commandOptions.otp) {
|
|
3581
4153
|
const deps2 = await commandDeps(program, options, store, commandOptions);
|
|
@@ -3593,7 +4165,8 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3593
4165
|
const context = createContext({ global: global2 });
|
|
3594
4166
|
const result2 = await runLoginInteractive({
|
|
3595
4167
|
...deps2,
|
|
3596
|
-
createClient: (apiKey) => context.createClient(apiKey)
|
|
4168
|
+
createClient: (apiKey) => context.createClient(apiKey),
|
|
4169
|
+
...commandOptions.scope ? { scope: commandOptions.scope } : {}
|
|
3597
4170
|
});
|
|
3598
4171
|
process.exitCode = result2.exitCode;
|
|
3599
4172
|
return;
|
|
@@ -3605,6 +4178,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3605
4178
|
{
|
|
3606
4179
|
email: commandOptions.email,
|
|
3607
4180
|
otp: commandOptions.otp,
|
|
4181
|
+
...commandOptions.scope ? { scope: commandOptions.scope } : {},
|
|
3608
4182
|
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
3609
4183
|
},
|
|
3610
4184
|
{
|
|
@@ -3621,7 +4195,10 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3621
4195
|
const result = await runLoginRequest(commandOptions, deps);
|
|
3622
4196
|
process.exitCode = result.exitCode;
|
|
3623
4197
|
});
|
|
3624
|
-
login?.command("verify").description("Verify email OTP and store an API key").requiredOption("--email <email>", "Email address").requiredOption("--otp <otp>", "One-time passcode").option(
|
|
4198
|
+
login?.command("verify").description("Verify email OTP and store an API key").requiredOption("--email <email>", "Email address").requiredOption("--otp <otp>", "One-time passcode").option(
|
|
4199
|
+
"--scope <scope>",
|
|
4200
|
+
"Capability scope to request for the minted key (e.g. team)"
|
|
4201
|
+
).option("--json", "Force JSON output").action(
|
|
3625
4202
|
async (commandOptions) => {
|
|
3626
4203
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
3627
4204
|
const global = globalOptions(program, commandOptions);
|
|
@@ -3659,17 +4236,30 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3659
4236
|
const result = await runAccountGet(commandOptions, deps);
|
|
3660
4237
|
process.exitCode = result.exitCode;
|
|
3661
4238
|
});
|
|
3662
|
-
account.command("update").description("Update account display name").
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
4239
|
+
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(
|
|
4240
|
+
async (commandOptions) => {
|
|
4241
|
+
if (commandOptions.displayName === void 0 && !commandOptions.clearDisplayName || commandOptions.displayName !== void 0 && commandOptions.clearDisplayName) {
|
|
4242
|
+
const writer = outputWriter(program, options, commandOptions);
|
|
4243
|
+
process.exitCode = writeError(
|
|
4244
|
+
writer,
|
|
4245
|
+
"invalid_usage",
|
|
4246
|
+
"Use either --display-name <name> or --clear-display-name."
|
|
4247
|
+
).exitCode;
|
|
4248
|
+
return;
|
|
4249
|
+
}
|
|
4250
|
+
const displayName = commandOptions.clearDisplayName ? null : commandOptions.displayName;
|
|
4251
|
+
if (displayName === void 0) return;
|
|
4252
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
4253
|
+
const result = await runAccountUpdate(
|
|
4254
|
+
{
|
|
4255
|
+
displayName,
|
|
4256
|
+
...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
|
|
4257
|
+
},
|
|
4258
|
+
deps
|
|
4259
|
+
);
|
|
4260
|
+
process.exitCode = result.exitCode;
|
|
4261
|
+
}
|
|
4262
|
+
);
|
|
3673
4263
|
account.command("delete").description("Delete your account").option("--yes", "Confirm deletion").option("--json", "Force JSON output").action(async (commandOptions) => {
|
|
3674
4264
|
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
3675
4265
|
const global = globalOptions(program, commandOptions);
|
|
@@ -3683,7 +4273,10 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
|
|
|
3683
4273
|
);
|
|
3684
4274
|
process.exitCode = result.exitCode;
|
|
3685
4275
|
});
|
|
3686
|
-
program.command("doctor").description("Report CLI diagnostics").option("--json", "Force JSON output").
|
|
4276
|
+
program.command("doctor").description("Report CLI diagnostics").option("--json", "Force JSON output").option(
|
|
4277
|
+
"--online",
|
|
4278
|
+
"Run a network preflight (auth + active workspace + custom-domain status) \u2014 exits 3 on auth failure, 5 on a network failure"
|
|
4279
|
+
).action(async (commandOptions) => {
|
|
3687
4280
|
const deps = await commandDeps(
|
|
3688
4281
|
program,
|
|
3689
4282
|
options,
|
|
@@ -3818,6 +4411,7 @@ function toDropOptions(options) {
|
|
|
3818
4411
|
...options.noindex ? { noindex: true } : {},
|
|
3819
4412
|
...options.index ? { index: true } : {},
|
|
3820
4413
|
...options.expiresAt ? { expiresAt: options.expiresAt } : {},
|
|
4414
|
+
...options.expires === false || options.noExpires ? { noExpires: true } : {},
|
|
3821
4415
|
...options.metadata ? { metadata: options.metadata } : {},
|
|
3822
4416
|
...options.metadataFile ? { metadataFile: options.metadataFile } : {},
|
|
3823
4417
|
...options.entry ? { entry: options.entry } : {},
|