@dropthis/cli 0.10.0 → 0.11.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/dist/cli.cjs CHANGED
@@ -232,12 +232,14 @@ function exitCodeFor(code) {
232
232
  if (code === "auth_error") return 3;
233
233
  if (code === "local_input_error") return 4;
234
234
  if (code === "network_error") return 5;
235
+ if (code === "verify_pending") return 6;
236
+ if (code === "verify_timeout") return 7;
235
237
  return 1;
236
238
  }
237
239
 
238
240
  // src/program.ts
239
241
  var import_commander = require("commander");
240
- var import_picocolors4 = __toESM(require("picocolors"), 1);
242
+ var import_picocolors5 = __toESM(require("picocolors"), 1);
241
243
 
242
244
  // src/auth.ts
243
245
  async function resolveCredential(input) {
@@ -285,6 +287,9 @@ function success(msg) {
285
287
  function error(msg) {
286
288
  return `${import_picocolors.default.red(symbols.error)} ${msg}`;
287
289
  }
290
+ function warn(msg) {
291
+ return `${import_picocolors.default.yellow(symbols.warning)} ${msg}`;
292
+ }
288
293
  function hint(msg) {
289
294
  return ` ${import_picocolors.default.dim(msg)}`;
290
295
  }
@@ -305,6 +310,17 @@ function writeResult(deps, link, verb, data) {
305
310
  const details = formatDropDetails(data);
306
311
  if (details) deps.stdout(`${details}
307
312
  `);
313
+ const warnings = data.warnings;
314
+ if (Array.isArray(warnings)) {
315
+ for (const w of warnings) {
316
+ if (w.code === "slug_suffixed") {
317
+ deps.stderr(
318
+ `${hint(`Vanity slug was taken \u2014 served at: ${w.detail ?? "see URL"}`)}
319
+ `
320
+ );
321
+ }
322
+ }
323
+ }
308
324
  } else {
309
325
  deps.stdout(`${JSON.stringify({ ok: true, drop: data })}
310
326
  `);
@@ -781,19 +797,322 @@ async function runDoctor(_input, deps) {
781
797
  const authSource = credential?.source ?? "missing";
782
798
  const storageBackend = stored?.storage ?? "none";
783
799
  const pairs = [
784
- ["Version", "0.10.0"],
800
+ ["Version", "0.11.0"],
785
801
  ["Auth", authSource],
786
802
  ["Storage", storageBackend]
787
803
  ];
788
804
  writeKv(deps, pairs, {
789
805
  ok: true,
790
- version: "0.10.0",
806
+ version: "0.11.0",
791
807
  auth: { source: authSource },
792
808
  storage: { backend: storageBackend }
793
809
  });
794
810
  return { exitCode: 0 };
795
811
  }
796
812
 
813
+ // src/commands/domains.ts
814
+ var import_picocolors3 = __toESM(require("picocolors"), 1);
815
+ function formatDnsTable(records) {
816
+ if (records.length === 0) return "";
817
+ const rows = [];
818
+ const colWidths = {
819
+ type: Math.max(4, ...records.map((r) => r.type.length)),
820
+ name: Math.max(4, ...records.map((r) => r.name.length)),
821
+ value: Math.max(5, ...records.map((r) => r.value.length)),
822
+ status: Math.max(6, ...records.map((r) => r.status.length))
823
+ };
824
+ const header = [
825
+ "Type".padEnd(colWidths.type),
826
+ "Name".padEnd(colWidths.name),
827
+ "Value".padEnd(colWidths.value),
828
+ "Status".padEnd(colWidths.status)
829
+ ].join(" ");
830
+ rows.push(import_picocolors3.default.dim(header));
831
+ rows.push(import_picocolors3.default.dim("\u2500".repeat(header.length)));
832
+ for (const rec of records) {
833
+ const statusColor = rec.status === "ok" ? import_picocolors3.default.green(rec.status.padEnd(colWidths.status)) : rec.status === "mismatch" ? import_picocolors3.default.yellow(rec.status.padEnd(colWidths.status)) : import_picocolors3.default.red(rec.status.padEnd(colWidths.status));
834
+ rows.push(
835
+ [
836
+ rec.type.padEnd(colWidths.type),
837
+ rec.name.padEnd(colWidths.name),
838
+ rec.value.padEnd(colWidths.value),
839
+ statusColor
840
+ ].join(" ")
841
+ );
842
+ if (rec.hint) {
843
+ rows.push(` ${import_picocolors3.default.dim(rec.hint)}`);
844
+ }
845
+ if (rec.observed) {
846
+ rows.push(` ${import_picocolors3.default.dim(`Observed: ${rec.observed}`)}`);
847
+ }
848
+ }
849
+ return rows.join("\n");
850
+ }
851
+ function printNextHints(deps, hints) {
852
+ if (hints.length === 0) return;
853
+ deps.stdout("\n");
854
+ for (const h of hints) {
855
+ deps.stdout(`${hint(h.message)}
856
+ `);
857
+ }
858
+ }
859
+ function computeSleepMs(records, elapsedMs, timeoutMs) {
860
+ const maxRetryAfter = records.reduce(
861
+ (max, r) => Math.max(max, r.retryAfter ?? 0),
862
+ 0
863
+ );
864
+ const defaultSeconds = maxRetryAfter > 0 ? maxRetryAfter : 15;
865
+ const desiredMs = defaultSeconds * 1e3;
866
+ const remainingMs = timeoutMs - elapsedMs;
867
+ return Math.min(desiredMs, Math.max(0, remainingMs));
868
+ }
869
+ async function runDomainsConnect(input, deps) {
870
+ try {
871
+ await requireCredential({
872
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
873
+ env: deps.env,
874
+ store: deps.store
875
+ });
876
+ } catch {
877
+ return writeAuthError(deps);
878
+ }
879
+ const result = await deps.client.domains.connect(input);
880
+ if (result.error) return writeApiError(deps, result.error);
881
+ const domain = result.data;
882
+ if (deps.outputMode === "human") {
883
+ deps.stdout(
884
+ `${success(`Connected ${domain.hostname} (${domain.mode} mode)`)}
885
+ `
886
+ );
887
+ if (domain.dns.length > 0) {
888
+ deps.stdout("\nDNS records to create at your provider:\n\n");
889
+ deps.stdout(`${formatDnsTable(domain.dns)}
890
+ `);
891
+ }
892
+ printNextHints(deps, domain.next);
893
+ } else {
894
+ writeJson(deps, { ok: true, domain });
895
+ }
896
+ return { exitCode: 0 };
897
+ }
898
+ async function runDomainsList(_input, deps) {
899
+ try {
900
+ await requireCredential({
901
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
902
+ env: deps.env,
903
+ store: deps.store
904
+ });
905
+ } catch {
906
+ return writeAuthError(deps);
907
+ }
908
+ const result = await deps.client.domains.list();
909
+ if (result.error) return writeApiError(deps, result.error);
910
+ const domains = result.data?.domains ?? [];
911
+ if (deps.outputMode === "human") {
912
+ if (domains.length === 0) {
913
+ writeEmpty(deps, "No domains connected yet.", { ok: true, domains: [] });
914
+ } else {
915
+ for (const d of domains) {
916
+ const defaultMark = d.default ? import_picocolors3.default.green(" (default)") : "";
917
+ const drop = d.dropId ? import_picocolors3.default.dim(` \u2192 ${d.dropId}`) : "";
918
+ deps.stdout(
919
+ ` ${d.hostname}${defaultMark} ${import_picocolors3.default.dim(d.mode)} ${import_picocolors3.default.dim(d.status)}${drop}
920
+ `
921
+ );
922
+ }
923
+ }
924
+ } else {
925
+ writeJson(deps, { ok: true, domains });
926
+ }
927
+ return { exitCode: 0 };
928
+ }
929
+ async function runDomainsStatus(idOrHostname, _input, deps) {
930
+ try {
931
+ await requireCredential({
932
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
933
+ env: deps.env,
934
+ store: deps.store
935
+ });
936
+ } catch {
937
+ return writeAuthError(deps);
938
+ }
939
+ const result = await deps.client.domains.get(idOrHostname);
940
+ if (result.error) return writeApiError(deps, result.error);
941
+ const domain = result.data;
942
+ if (deps.outputMode === "human") {
943
+ deps.stdout(` ${import_picocolors3.default.dim("Hostname:")} ${domain.hostname}
944
+ `);
945
+ deps.stdout(` ${import_picocolors3.default.dim("Mode: ")} ${domain.mode}
946
+ `);
947
+ deps.stdout(` ${import_picocolors3.default.dim("Status: ")} ${domain.status}
948
+ `);
949
+ if (domain.failureReason) {
950
+ deps.stdout(
951
+ ` ${import_picocolors3.default.dim("Reason: ")} ${import_picocolors3.default.red(domain.failureReason)}
952
+ `
953
+ );
954
+ }
955
+ if (domain.dropId) {
956
+ deps.stdout(` ${import_picocolors3.default.dim("Drop: ")} ${domain.dropId}
957
+ `);
958
+ }
959
+ if (domain.verifiedAt) {
960
+ deps.stdout(` ${import_picocolors3.default.dim("Verified:")} ${domain.verifiedAt}
961
+ `);
962
+ }
963
+ deps.stdout(` ${import_picocolors3.default.dim("Created: ")} ${domain.createdAt}
964
+ `);
965
+ if (domain.dns.length > 0) {
966
+ deps.stdout("\nDNS records:\n\n");
967
+ deps.stdout(`${formatDnsTable(domain.dns)}
968
+ `);
969
+ }
970
+ printNextHints(deps, domain.next);
971
+ } else {
972
+ writeJson(deps, { ok: true, domain });
973
+ }
974
+ return { exitCode: 0 };
975
+ }
976
+ var defaultSleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
977
+ async function runDomainsVerify(idOrHostname, input, deps, sleep = defaultSleep) {
978
+ try {
979
+ await requireCredential({
980
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
981
+ env: deps.env,
982
+ store: deps.store
983
+ });
984
+ } catch {
985
+ return writeAuthError(deps);
986
+ }
987
+ const timeoutMs = (input.timeout ?? 300) * 1e3;
988
+ const doVerify = async (elapsedMs) => {
989
+ const result = await deps.client.domains.verify(idOrHostname);
990
+ if (result.error) return writeApiError(deps, result.error);
991
+ const domain = result.data;
992
+ if (!input.wait) {
993
+ if (deps.outputMode === "human") {
994
+ deps.stdout(
995
+ `${domain.status === "live" ? success(`${idOrHostname} is live`) : warn(`${idOrHostname}: ${domain.status}`)}
996
+ `
997
+ );
998
+ if (domain.dns.length > 0) {
999
+ deps.stdout("\n");
1000
+ deps.stdout(`${formatDnsTable(domain.dns)}
1001
+ `);
1002
+ }
1003
+ printNextHints(deps, domain.next);
1004
+ } else {
1005
+ writeJson(deps, { ok: true, domain });
1006
+ }
1007
+ return {
1008
+ exitCode: domain.status === "live" ? 0 : domain.status === "failed" ? 1 : 6
1009
+ };
1010
+ }
1011
+ if (domain.status === "live" || domain.status === "failed") {
1012
+ if (deps.outputMode === "human") {
1013
+ deps.stdout(
1014
+ `${domain.status === "live" ? success(`${idOrHostname} is live`) : warn(`${idOrHostname}: ${domain.status}`)}
1015
+ `
1016
+ );
1017
+ if (domain.dns.length > 0) {
1018
+ deps.stdout("\n");
1019
+ deps.stdout(`${formatDnsTable(domain.dns)}
1020
+ `);
1021
+ }
1022
+ } else {
1023
+ writeJson(deps, { ok: true, domain });
1024
+ }
1025
+ return { exitCode: domain.status === "live" ? 0 : 1 };
1026
+ }
1027
+ const sleepMs = computeSleepMs(domain.dns, elapsedMs, timeoutMs);
1028
+ const newElapsed = elapsedMs + sleepMs;
1029
+ if (newElapsed >= timeoutMs) {
1030
+ const timeoutSecs = input.timeout ?? 300;
1031
+ const message = `Timed out waiting for ${idOrHostname} to go live after ${timeoutSecs}s`;
1032
+ if (deps.outputMode === "human") {
1033
+ deps.stderr(
1034
+ ` ${import_picocolors3.default.red("Timed out waiting for")} ${idOrHostname} ${import_picocolors3.default.red("to go live")}
1035
+ `
1036
+ );
1037
+ } else {
1038
+ deps.stderr(
1039
+ `${JSON.stringify(errorEnvelope("verify_timeout", message))}
1040
+ `
1041
+ );
1042
+ }
1043
+ return { exitCode: 7 };
1044
+ }
1045
+ if (deps.outputMode === "human" && domain.dns.length > 0) {
1046
+ deps.stdout(`${formatDnsTable(domain.dns)}
1047
+ `);
1048
+ }
1049
+ await sleep(sleepMs);
1050
+ return doVerify(newElapsed);
1051
+ };
1052
+ return doVerify(0);
1053
+ }
1054
+ async function runDomainsUpdate(idOrHostname, input, deps) {
1055
+ if (input.drop === void 0 && input.setDefault === void 0) {
1056
+ return writeError(
1057
+ deps,
1058
+ "invalid_usage",
1059
+ "Provide at least one option: --drop <dropId> or --default"
1060
+ );
1061
+ }
1062
+ try {
1063
+ await requireCredential({
1064
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
1065
+ env: deps.env,
1066
+ store: deps.store
1067
+ });
1068
+ } catch {
1069
+ return writeAuthError(deps);
1070
+ }
1071
+ const updateInput = {};
1072
+ if (input.drop !== void 0) updateInput.dropId = input.drop;
1073
+ if (input.setDefault !== void 0) updateInput.default = input.setDefault;
1074
+ const result = await deps.client.domains.update(idOrHostname, updateInput);
1075
+ if (result.error) return writeApiError(deps, result.error);
1076
+ const domain = result.data;
1077
+ writeHumanOrJson(deps, `${success(`Updated ${domain.hostname}`)}
1078
+ `, {
1079
+ ok: true,
1080
+ domain
1081
+ });
1082
+ return { exitCode: 0 };
1083
+ }
1084
+ async function runDomainsRemove(idOrHostname, _input, deps) {
1085
+ try {
1086
+ await requireCredential({
1087
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
1088
+ env: deps.env,
1089
+ store: deps.store
1090
+ });
1091
+ } catch {
1092
+ return writeAuthError(deps);
1093
+ }
1094
+ const result = await deps.client.domains.delete(idOrHostname);
1095
+ if (result.error) return writeApiError(deps, result.error);
1096
+ const deleted = result.data;
1097
+ if (deps.outputMode === "human") {
1098
+ deps.stdout(`${success(`Removed ${deleted.hostname}`)}
1099
+ `);
1100
+ if (deleted.warning) {
1101
+ deps.stderr(`${warn(deleted.warning)}
1102
+ `);
1103
+ }
1104
+ } else {
1105
+ writeJson(deps, {
1106
+ ok: true,
1107
+ deleted: true,
1108
+ id: deleted.id,
1109
+ hostname: deleted.hostname,
1110
+ warning: deleted.warning
1111
+ });
1112
+ }
1113
+ return { exitCode: 0 };
1114
+ }
1115
+
797
1116
  // src/commands/drops.ts
798
1117
  var prompts2 = __toESM(require("@clack/prompts"), 1);
799
1118
  async function runDropsList(input, deps) {
@@ -1131,7 +1450,9 @@ async function parseDropOptions(raw) {
1131
1450
  ...raw.entry ? { entry: raw.entry } : {},
1132
1451
  ...raw.contentType ? { contentType: raw.contentType } : {},
1133
1452
  ...raw.path ? { path: raw.path } : {},
1134
- ...raw.idempotencyKey ? { idempotencyKey: raw.idempotencyKey } : {}
1453
+ ...raw.idempotencyKey ? { idempotencyKey: raw.idempotencyKey } : {},
1454
+ ...raw.domain ? { domain: raw.domain } : {},
1455
+ ...raw.slug ? { slug: raw.slug } : {}
1135
1456
  };
1136
1457
  }
1137
1458
  function parseJsonObject(value, label) {
@@ -1143,12 +1464,12 @@ function parseJsonObject(value, label) {
1143
1464
  }
1144
1465
 
1145
1466
  // src/spinner.ts
1146
- var import_picocolors3 = __toESM(require("picocolors"), 1);
1467
+ var import_picocolors4 = __toESM(require("picocolors"), 1);
1147
1468
  var frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1148
1469
  function createSpinner(message, stderr) {
1149
1470
  let i = 0;
1150
1471
  const timer = setInterval(() => {
1151
- stderr(`\r\x1B[2K${import_picocolors3.default.cyan(frames[i % frames.length])} ${message}`);
1472
+ stderr(`\r\x1B[2K${import_picocolors4.default.cyan(frames[i % frames.length])} ${message}`);
1152
1473
  i++;
1153
1474
  }, 80);
1154
1475
  return {
@@ -1932,13 +2253,13 @@ function buildProgram(options = {}) {
1932
2253
  });
1933
2254
  program.name("dropthis").description(
1934
2255
  [
1935
- import_picocolors4.default.dim("Publish anything online and get a URL back."),
2256
+ import_picocolors5.default.dim("Publish anything online and get a URL back."),
1936
2257
  "",
1937
- `${import_picocolors4.default.bold("Quick start:")}`,
1938
- ` ${import_picocolors4.default.cyan("dropthis login")}`,
1939
- ` ${import_picocolors4.default.cyan("dropthis publish ./dist")}`
2258
+ `${import_picocolors5.default.bold("Quick start:")}`,
2259
+ ` ${import_picocolors5.default.cyan("dropthis login")}`,
2260
+ ` ${import_picocolors5.default.cyan("dropthis publish ./dist")}`
1940
2261
  ].join("\n")
1941
- ).version("0.10.0").configureHelp({
2262
+ ).version("0.11.0").configureHelp({
1942
2263
  subcommandTerm(cmd) {
1943
2264
  const args = cmd.registeredArguments.map((a) => {
1944
2265
  const name = a.name();
@@ -1947,10 +2268,10 @@ function buildProgram(options = {}) {
1947
2268
  }).join(" ");
1948
2269
  return args ? `${cmd.name()} ${args}` : cmd.name();
1949
2270
  },
1950
- styleTitle: (title) => import_picocolors4.default.bold(title),
1951
- styleCommandText: (str) => import_picocolors4.default.cyan(str),
1952
- styleSubcommandText: (str) => import_picocolors4.default.cyan(str),
1953
- styleOptionText: (str) => import_picocolors4.default.yellow(str)
2271
+ styleTitle: (title) => import_picocolors5.default.bold(title),
2272
+ styleCommandText: (str) => import_picocolors5.default.cyan(str),
2273
+ styleSubcommandText: (str) => import_picocolors5.default.cyan(str),
2274
+ styleOptionText: (str) => import_picocolors5.default.yellow(str)
1954
2275
  });
1955
2276
  program.option("--api-key <key>", "Override API key for this invocation");
1956
2277
  program.option("--api-url <url>", "Override API base URL");
@@ -1968,7 +2289,13 @@ function buildProgram(options = {}) {
1968
2289
  ).option(
1969
2290
  "--metadata <json>",
1970
2291
  `Attach JSON key-value pairs, e.g. '{"source":"ci"}'`
1971
- ).option("--metadata-file <path>", "Read metadata JSON from a file").option("--path <name>", "Set filename when publishing from stdin").option("--url", "Print only the published URL (no JSON envelope)").option(
2292
+ ).option("--metadata-file <path>", "Read metadata JSON from a file").option("--path <name>", "Set filename when publishing from stdin").option(
2293
+ "--domain <hostname>",
2294
+ "Serve this drop under a connected custom domain (must be live \u2014 see: dropthis domains list). Path-mode: drop lives at https://domain/{slug}/. Dedicated: drop is at the root (409 if occupied). Omit to use the account's default path domain."
2295
+ ).option(
2296
+ "--slug <vanity-slug>",
2297
+ "Vanity slug for path-mode custom domains (1\u201363 lowercase letters/digits/hyphens). Auto-suffixed if taken. Only valid with --domain on a path-mode domain."
2298
+ ).option("--url", "Print only the published URL (no JSON envelope)").option(
1972
2299
  "--dry-run",
1973
2300
  "Show what would be published without publishing (JSON; cannot combine with --url)"
1974
2301
  ).option("--json", "Force JSON output").option(
@@ -2162,6 +2489,76 @@ function buildProgram(options = {}) {
2162
2489
  process.exitCode = result.exitCode;
2163
2490
  }
2164
2491
  );
2492
+ const domains = program.command("domains").description(
2493
+ "Manage custom domains. Loop: connect \u2192 create the CNAME at your DNS provider \u2192 verify --wait \u2192 publish --domain"
2494
+ );
2495
+ domains.command("connect <hostname>").description(
2496
+ "Connect a custom domain. Returns DNS records to create at your provider.\nAfter adding them: dropthis domains verify <hostname> --wait"
2497
+ ).requiredOption(
2498
+ "--mode <mode>",
2499
+ "Mount mode: path (many drops at hostname/{slug}/) or dedicated (one drop at root)"
2500
+ ).option("--json", "Force JSON output").action(
2501
+ async (hostname, commandOptions) => {
2502
+ if (commandOptions.mode !== "path" && commandOptions.mode !== "dedicated") {
2503
+ process.stderr.write(`error: --mode must be "path" or "dedicated"
2504
+ `);
2505
+ process.exitCode = 2;
2506
+ return;
2507
+ }
2508
+ const deps = await commandDeps(program, options, store, commandOptions);
2509
+ const result = await runDomainsConnect(
2510
+ { hostname, mode: commandOptions.mode },
2511
+ deps
2512
+ );
2513
+ process.exitCode = result.exitCode;
2514
+ }
2515
+ );
2516
+ domains.command("list").description("List connected custom domains").option("--json", "Force JSON output").action(async (commandOptions) => {
2517
+ const deps = await commandDeps(program, options, store, commandOptions);
2518
+ const result = await runDomainsList(commandOptions, deps);
2519
+ process.exitCode = result.exitCode;
2520
+ });
2521
+ domains.command("status <hostname>").description("Show domain details and DNS record status").option("--json", "Force JSON output").action(async (hostname, commandOptions) => {
2522
+ const deps = await commandDeps(program, options, store, commandOptions);
2523
+ const result = await runDomainsStatus(hostname, commandOptions, deps);
2524
+ process.exitCode = result.exitCode;
2525
+ });
2526
+ domains.command("verify <hostname>").description(
2527
+ "Trigger a DNS verification check. With --wait, polls until live or failed.\nUse after adding the DNS records from: dropthis domains connect"
2528
+ ).option("--wait", "Poll until live (or failed/timeout)").option(
2529
+ "--timeout <secs>",
2530
+ "Max seconds to wait (default: 300)",
2531
+ parseInteger
2532
+ ).option("--json", "Force JSON output").action(
2533
+ async (hostname, commandOptions) => {
2534
+ const deps = await commandDeps(program, options, store, commandOptions);
2535
+ const result = await runDomainsVerify(hostname, commandOptions, deps);
2536
+ process.exitCode = result.exitCode;
2537
+ }
2538
+ );
2539
+ domains.command("update <hostname>").description(
2540
+ "Update a domain \u2014 repoint to a different drop (dedicated mode) or set/clear as account default (path mode). At least one option required."
2541
+ ).option("--drop <dropId>", "Repoint to a different drop (dedicated mode)").option("--default", "Set as account default publish domain (path mode)").option("--json", "Force JSON output").action(
2542
+ async (hostname, commandOptions) => {
2543
+ const deps = await commandDeps(program, options, store, commandOptions);
2544
+ const result = await runDomainsUpdate(
2545
+ hostname,
2546
+ {
2547
+ ...commandOptions.drop !== void 0 ? { drop: commandOptions.drop } : {},
2548
+ ...commandOptions.default !== void 0 ? { setDefault: commandOptions.default } : {}
2549
+ },
2550
+ deps
2551
+ );
2552
+ process.exitCode = result.exitCode;
2553
+ }
2554
+ );
2555
+ domains.command("remove <hostname>").description(
2556
+ "Remove a custom domain. IMPORTANT: also delete the DNS CNAME at your provider to prevent DNS hijacking."
2557
+ ).option("--json", "Force JSON output").action(async (hostname, commandOptions) => {
2558
+ const deps = await commandDeps(program, options, store, commandOptions);
2559
+ const result = await runDomainsRemove(hostname, commandOptions, deps);
2560
+ process.exitCode = result.exitCode;
2561
+ });
2165
2562
  const apiKeys = program.command("api-keys").description("Manage API keys");
2166
2563
  apiKeys.command("create").description("Create an API key").option("--label <label>", "API key label", "CLI").option("--json", "Force JSON output").action(async (commandOptions) => {
2167
2564
  const deps = await commandDeps(program, options, store, commandOptions);
@@ -2400,6 +2797,8 @@ function toDropOptions(options) {
2400
2797
  ...options.contentType ? { contentType: options.contentType } : {},
2401
2798
  ...options.path ? { path: options.path } : {},
2402
2799
  ...options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {},
2800
+ ...options.domain ? { domain: options.domain } : {},
2801
+ ...options.slug ? { slug: options.slug } : {},
2403
2802
  ...options.json !== void 0 ? { json: options.json } : {},
2404
2803
  ...options.quiet !== void 0 ? { quiet: options.quiet } : {},
2405
2804
  ...options.url !== void 0 ? { url: options.url } : {},