@dropthis/cli 0.28.0 → 0.30.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
@@ -250,6 +250,12 @@ function cliNextAction(error2) {
250
250
  if (error2.code === "network_error") {
251
251
  return "Could not reach the dropthis API \u2014 check your network or DROPTHIS_API_URL.";
252
252
  }
253
+ if (error2.code === "workspace_pinned") {
254
+ return "Service keys are pinned to one workspace. To switch workspaces, use a delegated login (run: dropthis login) instead of a service key.";
255
+ }
256
+ if (error2.code === "workspace_selector_not_allowed") {
257
+ return "Service keys (sk_) are pinned to one workspace and cannot target another with --workspace. Use a delegated login key (run: dropthis login), or run without --workspace.";
258
+ }
253
259
  if (error2.code === "revision_conflict") {
254
260
  return "Re-read the drop with dropthis get <drop-id>, merge your changes, and retry with --if-revision set to the current revision.";
255
261
  }
@@ -265,9 +271,15 @@ function cliNextAction(error2) {
265
271
  if (error2.code === "otp_invalid") {
266
272
  return "Re-enter the code from your email; if it keeps failing, request a fresh one with dropthis login request --email <email>.";
267
273
  }
274
+ if (error2.code === "workspace_not_found") {
275
+ return "Workspace not found. List your workspaces with: dropthis workspace list";
276
+ }
268
277
  if (error2.statusCode === 404 || error2.code === "not_found") {
269
278
  return "Check the drop id or slug and retry; list your drops with dropthis list.";
270
279
  }
280
+ if (error2.code === "invalid_api_key") {
281
+ return "API key is invalid or revoked. Run dropthis login to re-authenticate, or set a valid DROPTHIS_API_KEY.";
282
+ }
271
283
  if (error2.statusCode === 401 || error2.code === "missing_api_key") {
272
284
  return "Authenticate with dropthis login or set DROPTHIS_API_KEY.";
273
285
  }
@@ -721,7 +733,8 @@ var COMMAND_ANNOTATIONS = {
721
733
  "dropthis ./report.html",
722
734
  "dropthis publish ./site --json",
723
735
  "dropthis publish ./site --url",
724
- "dropthis publish ./dist --dry-run"
736
+ "dropthis publish ./dist --dry-run",
737
+ "dropthis publish ./report.html --workspace acme --json # target a specific workspace (delegated keys only)"
725
738
  ]
726
739
  },
727
740
  "update-content": {
@@ -807,6 +820,18 @@ var COMMAND_ANNOTATIONS = {
807
820
  auth: "required",
808
821
  examples: ["dropthis api-keys create --label CI --json"]
809
822
  },
823
+ "api-keys create": {
824
+ auth: "required",
825
+ examples: ["dropthis api-keys create --label CI --json"]
826
+ },
827
+ "api-keys list": {
828
+ auth: "required",
829
+ examples: ["dropthis api-keys list --json"]
830
+ },
831
+ "api-keys delete": {
832
+ auth: "required",
833
+ examples: ["dropthis api-keys delete key_abc --yes --json"]
834
+ },
810
835
  workspace: {
811
836
  auth: "required",
812
837
  examples: ["dropthis workspace list --json", "dropthis workspace use acme"]
@@ -834,6 +859,16 @@ var COMMAND_ANNOTATIONS = {
834
859
  ]
835
860
  },
836
861
  login: {
862
+ examples: [
863
+ "dropthis login",
864
+ "dropthis login request --email user@example.com --json",
865
+ "dropthis login verify --email user@example.com --otp 123456 --json"
866
+ ]
867
+ },
868
+ "login request": {
869
+ examples: ["dropthis login request --email user@example.com --json"]
870
+ },
871
+ "login verify": {
837
872
  examples: [
838
873
  "dropthis login verify --email user@example.com --otp 123456 --json"
839
874
  ]
@@ -974,7 +1009,7 @@ function spreadData(data) {
974
1009
  }
975
1010
 
976
1011
  // src/version.ts
977
- var CLI_VERSION = true ? "0.28.0" : "0.0.0-dev";
1012
+ var CLI_VERSION = true ? "0.30.0" : "0.0.0-dev";
978
1013
 
979
1014
  // src/commands/doctor.ts
980
1015
  async function runDoctor(_input, deps) {
@@ -1086,6 +1121,13 @@ function computeSleepMs(records, elapsedMs, timeoutMs) {
1086
1121
  return Math.min(desiredMs, Math.max(0, remainingMs));
1087
1122
  }
1088
1123
  async function runDomainsConnect(input, deps) {
1124
+ if (input.mode !== "path" && input.mode !== "dedicated") {
1125
+ return writeError(
1126
+ deps,
1127
+ "invalid_usage",
1128
+ '--mode must be "path" or "dedicated"'
1129
+ );
1130
+ }
1089
1131
  try {
1090
1132
  await requireCredential({
1091
1133
  ...deps.apiKey ? { apiKey: deps.apiKey } : {},
@@ -1095,7 +1137,9 @@ async function runDomainsConnect(input, deps) {
1095
1137
  } catch {
1096
1138
  return writeAuthError(deps);
1097
1139
  }
1098
- const result = await deps.client.domains.connect(input);
1140
+ const result = await deps.client.domains.connect(
1141
+ input
1142
+ );
1099
1143
  if (result.error) return writeApiError(deps, result.error);
1100
1144
  const domain = result.data;
1101
1145
  if (deps.outputMode === "human") {
@@ -1213,6 +1257,27 @@ async function runDomainsVerify(idOrHostname, input, deps, sleep = defaultSleep)
1213
1257
  if (result.error) return writeApiError(deps, result.error);
1214
1258
  const domain = result.data;
1215
1259
  if (!input.wait) {
1260
+ if (domain.status !== "live" && domain.status !== "failed") {
1261
+ if (deps.outputMode === "human") {
1262
+ deps.stdout(`${warn(`${idOrHostname}: ${domain.status}`)}
1263
+ `);
1264
+ if (domain.dns.length > 0) {
1265
+ deps.stdout("\n");
1266
+ deps.stdout(`${formatDnsTable(domain.dns)}
1267
+ `);
1268
+ }
1269
+ printNextHints(deps, domain.next, domain.hostname, domain.dns);
1270
+ printConsoleHandoff(deps, domain);
1271
+ } else {
1272
+ writeError(
1273
+ deps,
1274
+ "verify_pending",
1275
+ `${idOrHostname}: ${domain.status}`,
1276
+ `Re-run: dropthis domains verify ${idOrHostname}`
1277
+ );
1278
+ }
1279
+ return { exitCode: 6 };
1280
+ }
1216
1281
  if (deps.outputMode === "human") {
1217
1282
  deps.stdout(
1218
1283
  `${domain.status === "live" ? success(`${idOrHostname} is live`) : warn(`${idOrHostname}: ${domain.status}`)}
@@ -1229,7 +1294,7 @@ async function runDomainsVerify(idOrHostname, input, deps, sleep = defaultSleep)
1229
1294
  writeJson(deps, { ok: true, domain });
1230
1295
  }
1231
1296
  return {
1232
- exitCode: domain.status === "live" ? 0 : domain.status === "failed" ? 1 : 6
1297
+ exitCode: domain.status === "live" ? 0 : 1
1233
1298
  };
1234
1299
  }
1235
1300
  if (domain.status === "live" || domain.status === "failed") {
@@ -1260,12 +1325,19 @@ async function runDomainsVerify(idOrHostname, input, deps, sleep = defaultSleep)
1260
1325
  );
1261
1326
  } else {
1262
1327
  deps.stderr(
1263
- `${JSON.stringify(errorEnvelope("verify_timeout", message))}
1328
+ `${JSON.stringify(errorEnvelope("verify_timeout", message, `DNS is still propagating. Re-run: dropthis domains verify ${idOrHostname}`))}
1264
1329
  `
1265
1330
  );
1266
1331
  }
1267
1332
  return { exitCode: 7 };
1268
1333
  }
1334
+ if (deps.outputMode === "json" && domain.dns.length > 0) {
1335
+ const elapsed = Math.round(elapsedMs / 1e3);
1336
+ deps.stderr(
1337
+ `${JSON.stringify({ ok: false, pending: true, status: domain.status, elapsed })}
1338
+ `
1339
+ );
1340
+ }
1269
1341
  if (deps.outputMode === "human" && domain.dns.length > 0) {
1270
1342
  deps.stdout(`${formatDnsTable(domain.dns)}
1271
1343
  `);
@@ -1563,7 +1635,8 @@ async function runKeysCreate(input, deps) {
1563
1635
  return writeError(
1564
1636
  deps,
1565
1637
  "invalid_usage",
1566
- "Service keys must be pinned to a workspace: pass --workspace <slug-or-id>. (A service key is for CI/automation and never switches workspace.)"
1638
+ "Service keys must be pinned to a workspace.",
1639
+ "Run: dropthis workspace list to see slugs, then: dropthis keys create --service --workspace <slug>"
1567
1640
  );
1568
1641
  }
1569
1642
  const label = input.label ?? (keyType === "service" ? `Service key${input.workspace ? ` (${input.workspace})` : ""}` : "CLI key");
@@ -2709,7 +2782,7 @@ async function runWorkspaceList(_input, deps) {
2709
2782
  }
2710
2783
  const result = await deps.client.workspaces.list();
2711
2784
  if (result.error) return writeApiError(deps, result.error);
2712
- const raw = unwrapListData(result.data);
2785
+ const raw = unwrapListData(result.data, "workspaces");
2713
2786
  const items = Array.isArray(raw) ? raw : [];
2714
2787
  if (deps.outputMode === "human") {
2715
2788
  if (items.length === 0) {
@@ -2724,7 +2797,8 @@ async function runWorkspaceList(_input, deps) {
2724
2797
  }
2725
2798
  }
2726
2799
  } else {
2727
- writeJson(deps, { ok: true, workspaces: items });
2800
+ const activeWorkspace = items.find((w) => w.isActive) ?? null;
2801
+ writeJson(deps, { ok: true, workspaces: items, active: activeWorkspace });
2728
2802
  }
2729
2803
  return { exitCode: 0 };
2730
2804
  }
@@ -3329,9 +3403,11 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
3329
3403
  ).action(
3330
3404
  async (hostname, commandOptions) => {
3331
3405
  if (commandOptions.mode !== "path" && commandOptions.mode !== "dedicated") {
3332
- process.stderr.write(`error: --mode must be "path" or "dedicated"
3333
- `);
3334
- process.exitCode = 2;
3406
+ process.exitCode = writeError(
3407
+ outputWriter(program, options, commandOptions),
3408
+ "invalid_usage",
3409
+ '--mode must be "path" or "dedicated"'
3410
+ ).exitCode;
3335
3411
  return;
3336
3412
  }
3337
3413
  const deps = await commandDeps(program, options, store, commandOptions);
@@ -3353,7 +3429,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
3353
3429
  process.exitCode = result.exitCode;
3354
3430
  });
3355
3431
  domains.command("verify <hostname>").description(
3356
- "Trigger a DNS verification check. With --wait, polls until live or failed.\nUse after adding the DNS records from: dropthis domains connect"
3432
+ "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). Use --wait to poll automatically."
3357
3433
  ).option("--wait", "Poll until live (or failed/timeout)").option(
3358
3434
  "--timeout <secs>",
3359
3435
  "Max seconds to wait (default: 300)",
@@ -3619,6 +3695,21 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
3619
3695
  });
3620
3696
  return program;
3621
3697
  }
3698
+ function outputWriter(program, options, commandOptions) {
3699
+ const global = globalOptions(program, commandOptions);
3700
+ const context = createContext({
3701
+ global,
3702
+ ...options.env !== void 0 ? { env: options.env } : {},
3703
+ ...options.stdout !== void 0 ? { stdout: options.stdout } : {},
3704
+ ...options.stderr !== void 0 ? { stderr: options.stderr } : {},
3705
+ ...options.stdoutIsTTY !== void 0 ? { stdoutIsTTY: options.stdoutIsTTY } : {}
3706
+ });
3707
+ return {
3708
+ stdout: context.stdout,
3709
+ stderr: context.stderr,
3710
+ outputMode: context.output.mode
3711
+ };
3712
+ }
3622
3713
  async function commandDeps(program, options, store, commandOptions) {
3623
3714
  const global = globalOptions(program, commandOptions);
3624
3715
  const context = createContext({