@dropthis/cli 0.22.0 → 0.24.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 CHANGED
@@ -1,3 +1,5 @@
1
+ <p align="center"><img src="https://dropthis.app/icon-512.png" width="76" height="76" alt="dropthis" /></p>
2
+
1
3
  # @dropthis/cli
2
4
 
3
5
  Official CLI for [dropthis](https://dropthis.app) -- the publish layer between AI and the internet. Built for humans, AI agents, and CI/CD pipelines.
@@ -35,6 +37,8 @@ dropthis login request --email you@example.com
35
37
  dropthis login verify --email you@example.com --otp 123456
36
38
  ```
37
39
 
40
+ > A failed verify prints `Your code has expired` (`otp_expired`) or `That code is incorrect` (`otp_invalid`) and exits non-zero.
41
+
38
42
  Or pass both flags directly:
39
43
 
40
44
  ```bash
@@ -151,7 +155,7 @@ All publish flags:
151
155
  |------|-------------|
152
156
  | `--title <title>` | Drop title |
153
157
  | `--visibility <public\|unlisted>` | Drop visibility |
154
- | `--password <password>` | Set password protection (ships with Pro; not enabled on any tier yet) |
158
+ | `--password <password>` | Require a password to view the drop (Pro plan) |
155
159
  | `--noindex` | Prevent search indexing |
156
160
  | `--entry <path>` | Entry file for directories |
157
161
  | `--content-type <mime>` | MIME type (required for stdin) |
@@ -290,7 +294,7 @@ dropthis publish ./dist --url
290
294
  | 0 | Success |
291
295
  | 1 | API or generic error |
292
296
  | 2 | Invalid usage |
293
- | 3 | Auth required |
297
+ | 3 | Auth required (no credential, or the API returned 401 — re-authenticate) |
294
298
  | 4 | Local input error (file or directory not found, too many files) |
295
299
  | 5 | Network error (could not reach the API) |
296
300
  | 6 | Domain verification pending (`domains verify` one-shot, not live yet) |
package/dist/cli.cjs CHANGED
@@ -227,6 +227,15 @@ function cliNextAction(error2) {
227
227
  if (error2.code === "publish_conflict") {
228
228
  return "The drop changed state mid-publish (likely deleted). Run dropthis publish again to create a fresh drop.";
229
229
  }
230
+ if (error2.code === "access_token_cannot_delete_account") {
231
+ return "Account deletion needs a real API key, not a login session. Create one with dropthis api-keys create, then re-run with --api-key sk_\u2026";
232
+ }
233
+ if (error2.code === "otp_expired") {
234
+ return "Request a fresh code with: dropthis login request --email <email>.";
235
+ }
236
+ if (error2.code === "otp_invalid") {
237
+ return "Re-enter the code from your email; if it keeps failing, request a fresh one with dropthis login request --email <email>.";
238
+ }
230
239
  if (error2.statusCode === 404 || error2.code === "not_found") {
231
240
  return "Check the drop id or slug and retry; list your drops with dropthis list.";
232
241
  }
@@ -434,17 +443,10 @@ function writeApiError(deps, details) {
434
443
  function cliErrorCodeFor(details) {
435
444
  if (details.code === "network_error") return "network_error";
436
445
  if (details.code === "file_not_found") return "local_input_error";
437
- return "api_error";
438
- }
439
- function writeApiErrorSimple(deps, message) {
440
- if (deps.outputMode === "human") {
441
- deps.stderr(`${error(message)}
442
- `);
443
- } else {
444
- deps.stderr(`${JSON.stringify(errorEnvelope("api_error", message))}
445
- `);
446
+ if (details.statusCode === 401 || details.code === "authentication_required" || details.code === "missing_api_key") {
447
+ return "auth_error";
446
448
  }
447
- return { exitCode: exitCodeFor("api_error") };
449
+ return "api_error";
448
450
  }
449
451
  function writeAuthError(deps) {
450
452
  return writeError(
@@ -916,13 +918,13 @@ async function runDoctor(_input, deps) {
916
918
  const authSource = credential?.source ?? "missing";
917
919
  const storageBackend = stored?.storage ?? "none";
918
920
  const pairs = [
919
- ["Version", "0.22.0"],
921
+ ["Version", "0.24.0"],
920
922
  ["Auth", authSource],
921
923
  ["Storage", storageBackend]
922
924
  ];
923
925
  writeKv(deps, pairs, {
924
926
  ok: true,
925
- version: "0.22.0",
927
+ version: "0.24.0",
926
928
  auth: { source: authSource },
927
929
  storage: { backend: storageBackend }
928
930
  });
@@ -1506,6 +1508,15 @@ async function runLoginInteractive(deps) {
1506
1508
  session = result;
1507
1509
  break;
1508
1510
  }
1511
+ if (result.error.code === "otp_expired" && attempt < maxAttempts) {
1512
+ const resend = await deps.client.auth.requestEmailOtp({ email });
1513
+ if (resend.error) {
1514
+ prompts4.cancel(resend.error.message);
1515
+ return { exitCode: exitCodeFor("api_error") };
1516
+ }
1517
+ prompts4.log.info("That code expired \u2014 we sent a new one.");
1518
+ continue;
1519
+ }
1509
1520
  if (attempt < maxAttempts) {
1510
1521
  prompts4.log.warning(result.error.message);
1511
1522
  } else {
@@ -1539,19 +1550,16 @@ async function runLoginRequest(input, deps) {
1539
1550
  email: input.email
1540
1551
  });
1541
1552
  if (result.error) {
1542
- deps.stderr(
1543
- `${JSON.stringify(errorEnvelope("api_error", result.error.message))}
1544
- `
1545
- );
1546
- return { exitCode: exitCodeFor("api_error") };
1553
+ return writeApiError(deps, result.error);
1547
1554
  }
1548
- deps.stdout(
1549
- `${JSON.stringify({
1555
+ writeHumanOrJson(
1556
+ deps,
1557
+ success(`Code sent to ${input.email}. Check your inbox.`),
1558
+ {
1550
1559
  ok: true,
1551
1560
  email: input.email,
1552
1561
  expires_in: result.data.expiresIn
1553
- })}
1554
- `
1562
+ }
1555
1563
  );
1556
1564
  return { exitCode: 0 };
1557
1565
  }
@@ -1561,20 +1569,12 @@ async function runLoginVerify(input, deps) {
1561
1569
  code: input.otp
1562
1570
  });
1563
1571
  if (session.error) {
1564
- deps.stderr(
1565
- `${JSON.stringify(errorEnvelope("api_error", session.error.message))}
1566
- `
1567
- );
1568
- return { exitCode: exitCodeFor("api_error") };
1572
+ return writeApiError(deps, session.error);
1569
1573
  }
1570
1574
  const authedClient = deps.createClient(session.data.token);
1571
1575
  const apiKey = await authedClient.apiKeys.create({ label: "CLI" });
1572
1576
  if (apiKey.error) {
1573
- deps.stderr(
1574
- `${JSON.stringify(errorEnvelope("api_error", apiKey.error.message))}
1575
- `
1576
- );
1577
- return { exitCode: exitCodeFor("api_error") };
1577
+ return writeApiError(deps, apiKey.error);
1578
1578
  }
1579
1579
  await deps.store.save({
1580
1580
  apiKey: apiKey.data.key,
@@ -1584,16 +1584,13 @@ async function runLoginVerify(input, deps) {
1584
1584
  email: input.email,
1585
1585
  storage: "secure"
1586
1586
  });
1587
- deps.stdout(
1588
- `${JSON.stringify({
1589
- ok: true,
1590
- account_id: apiKey.data.accountId ?? session.data.accountId,
1591
- key_id: apiKey.data.id,
1592
- key_last4: apiKey.data.keyLast4,
1593
- is_new_account: apiKey.data.isNewAccount ?? session.data.isNewAccount
1594
- })}
1595
- `
1596
- );
1587
+ writeHumanOrJson(deps, success(`Logged in as ${input.email}.`), {
1588
+ ok: true,
1589
+ account_id: apiKey.data.accountId ?? session.data.accountId,
1590
+ key_id: apiKey.data.id,
1591
+ key_last4: apiKey.data.keyLast4,
1592
+ is_new_account: apiKey.data.isNewAccount ?? session.data.isNewAccount
1593
+ });
1597
1594
  return { exitCode: 0 };
1598
1595
  }
1599
1596
 
@@ -1603,12 +1600,12 @@ async function runLogout(input, deps) {
1603
1600
  let revokeError;
1604
1601
  if (input.revoke && stored?.keyId) {
1605
1602
  const result = await deps.client.apiKeys.delete(stored.keyId);
1606
- if (result?.error) revokeError = result.error.message;
1603
+ if (result?.error) revokeError = result.error;
1607
1604
  }
1605
+ await deps.store.clear();
1608
1606
  if (revokeError) {
1609
- return writeApiErrorSimple(deps, revokeError);
1607
+ return writeApiError(deps, revokeError);
1610
1608
  }
1611
- await deps.store.clear();
1612
1609
  writeHumanOrJson(deps, success("Logged out."), { ok: true });
1613
1610
  return { exitCode: 0 };
1614
1611
  }
@@ -2780,7 +2777,7 @@ function buildProgram(options = {}) {
2780
2777
  ` ${import_picocolors6.default.cyan("dropthis login")}`,
2781
2778
  ` ${import_picocolors6.default.cyan("dropthis publish ./dist")}`
2782
2779
  ].join("\n")
2783
- ).version("0.22.0").configureHelp({
2780
+ ).version("0.24.0").configureHelp({
2784
2781
  subcommandTerm(cmd) {
2785
2782
  const args = cmd.registeredArguments.map((a) => {
2786
2783
  const name = a.name();
@@ -3382,7 +3379,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
3382
3379
  );
3383
3380
  const result = await runUpgrade(commandOptions, {
3384
3381
  ...deps,
3385
- currentVersion: "0.22.0"
3382
+ currentVersion: "0.24.0"
3386
3383
  });
3387
3384
  process.exitCode = result.exitCode;
3388
3385
  });
@@ -3636,7 +3633,7 @@ var showNotice = shouldShowNotice({
3636
3633
  if (showNotice) {
3637
3634
  const notice = noticeFromCache({
3638
3635
  cache: updateCache,
3639
- currentVersion: "0.22.0"
3636
+ currentVersion: "0.24.0"
3640
3637
  });
3641
3638
  if (notice) {
3642
3639
  process.stderr.write(`