@dropthis/cli 0.4.1 → 0.5.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
@@ -689,13 +689,13 @@ async function runDoctor(_input, deps) {
689
689
  const authSource = credential?.source ?? "missing";
690
690
  const storageBackend = stored?.storage ?? "none";
691
691
  const pairs = [
692
- ["Version", "0.4.1"],
692
+ ["Version", "0.5.0"],
693
693
  ["Auth", authSource],
694
694
  ["Storage", storageBackend]
695
695
  ];
696
696
  writeKv(deps, pairs, {
697
697
  ok: true,
698
- version: "0.4.1",
698
+ version: "0.5.0",
699
699
  auth: { source: authSource },
700
700
  storage: { backend: storageBackend }
701
701
  });
@@ -1304,6 +1304,9 @@ async function dryRunMultiFile(inputs, options, deps) {
1304
1304
  }
1305
1305
 
1306
1306
  // src/commands/update.ts
1307
+ var prompts4 = __toESM(require("@clack/prompts"), 1);
1308
+ var NO_UPDATE_MESSAGE = "Nothing to update. Provide an input path or at least one update option.";
1309
+ var NO_UPDATE_NEXT_ACTION = "Run dropthis drops update --help, or retry with an input path (for example, dropthis drops update <dropId> ./dist) or one of: --title, --slug, --visibility, --password, --no-password, --noindex, --index, --expires-at, or --metadata.";
1307
1310
  async function runUpdate(target, input, raw, deps) {
1308
1311
  try {
1309
1312
  await requireCredential({
@@ -1317,14 +1320,31 @@ async function runUpdate(target, input, raw, deps) {
1317
1320
  if (raw.dryRun) {
1318
1321
  return handleUpdateDryRun(target, input, raw, deps);
1319
1322
  }
1320
- const spin = shouldSpin(deps.outputMode) ? createSpinner("Updating\u2026", deps.stderr) : void 0;
1323
+ let spin;
1321
1324
  try {
1322
1325
  assertDropId(target);
1323
1326
  if (raw.fromJson && input) {
1324
1327
  throw new Error("Use either [input] or --from-json, not both.");
1325
1328
  }
1326
- const parsed = await parseDropOptions(raw);
1329
+ let updateInput = input;
1330
+ let parsed = await parseDropOptions(raw);
1331
+ if (!updateInput && !raw.fromJson && !hasUpdateFields(parsed)) {
1332
+ if (shouldPromptForUpdate(deps)) {
1333
+ const prompted = await promptForUpdate(target, deps.prompts ?? prompts4);
1334
+ if (!prompted) return { exitCode: 0 };
1335
+ updateInput = prompted.input;
1336
+ parsed = { ...parsed, ...prompted.options };
1337
+ } else {
1338
+ return writeError(
1339
+ deps,
1340
+ "invalid_usage",
1341
+ NO_UPDATE_MESSAGE,
1342
+ NO_UPDATE_NEXT_ACTION
1343
+ );
1344
+ }
1345
+ }
1327
1346
  const revisionOptions = raw.ifRevision !== void 0 ? { ifRevision: Number(raw.ifRevision) } : {};
1347
+ spin = shouldSpin(deps.outputMode) ? createSpinner("Updating\u2026", deps.stderr) : void 0;
1328
1348
  const result = raw.fromJson ? await deps.client.deployments.createRaw(
1329
1349
  target,
1330
1350
  await (deps.readJsonObject ?? readJsonObjectFile)(raw.fromJson),
@@ -1335,9 +1355,9 @@ async function runUpdate(target, input, raw, deps) {
1335
1355
  },
1336
1356
  "upd"
1337
1357
  )
1338
- ) : input ? await deps.client.update(
1358
+ ) : updateInput ? await deps.client.update(
1339
1359
  target,
1340
- input,
1360
+ updateInput,
1341
1361
  withIdempotencyKey(
1342
1362
  {
1343
1363
  ...parsed,
@@ -1362,6 +1382,162 @@ async function runUpdate(target, input, raw, deps) {
1362
1382
  return writeError(deps, code, message);
1363
1383
  }
1364
1384
  }
1385
+ function hasUpdateFields(options) {
1386
+ const { idempotencyKey: _, ...fields } = options;
1387
+ return Object.keys(fields).length > 0;
1388
+ }
1389
+ function shouldPromptForUpdate(deps) {
1390
+ return deps.outputMode === "human" && deps.interactive === true;
1391
+ }
1392
+ async function promptForUpdate(target, prompt) {
1393
+ prompt.intro(`Update ${target}`);
1394
+ const fields = await prompt.multiselect({
1395
+ message: "What do you want to update?",
1396
+ required: true,
1397
+ options: [
1398
+ {
1399
+ value: "content",
1400
+ label: "Content",
1401
+ hint: "replace files, folder, URL, or text"
1402
+ },
1403
+ { value: "title", label: "Title", hint: "--title" },
1404
+ { value: "slug", label: "Slug", hint: "--slug" },
1405
+ { value: "visibility", label: "Visibility", hint: "--visibility" },
1406
+ {
1407
+ value: "password",
1408
+ label: "Password",
1409
+ hint: "--password or --no-password"
1410
+ },
1411
+ {
1412
+ value: "indexing",
1413
+ label: "Search indexing",
1414
+ hint: "--noindex or --index"
1415
+ },
1416
+ { value: "expiresAt", label: "Expiration", hint: "--expires-at" },
1417
+ { value: "metadata", label: "Metadata", hint: "--metadata" }
1418
+ ]
1419
+ });
1420
+ if (prompt.isCancel(fields)) {
1421
+ prompt.cancel("Update cancelled.");
1422
+ return void 0;
1423
+ }
1424
+ const selected = new Set(fields);
1425
+ const options = {};
1426
+ let input;
1427
+ if (selected.has("content")) {
1428
+ const value = await prompt.text({
1429
+ message: "Content path, URL, or text",
1430
+ validate: requireNonEmpty("Enter content or a path.")
1431
+ });
1432
+ if (prompt.isCancel(value)) return cancelUpdate(prompt);
1433
+ input = value.trim();
1434
+ }
1435
+ if (selected.has("title")) {
1436
+ const value = await prompt.text({
1437
+ message: "Title",
1438
+ validate: requireNonEmpty("Enter a title.")
1439
+ });
1440
+ if (prompt.isCancel(value)) return cancelUpdate(prompt);
1441
+ options.title = value.trim();
1442
+ }
1443
+ if (selected.has("slug")) {
1444
+ const value = await prompt.text({
1445
+ message: "Slug",
1446
+ validate: requireNonEmpty("Enter a slug.")
1447
+ });
1448
+ if (prompt.isCancel(value)) return cancelUpdate(prompt);
1449
+ options.slug = value.trim();
1450
+ }
1451
+ if (selected.has("visibility")) {
1452
+ const value = await prompt.select({
1453
+ message: "Visibility",
1454
+ options: [
1455
+ { value: "public", label: "Public" },
1456
+ { value: "unlisted", label: "Unlisted" }
1457
+ ]
1458
+ });
1459
+ if (prompt.isCancel(value)) return cancelUpdate(prompt);
1460
+ options.visibility = value;
1461
+ }
1462
+ if (selected.has("password")) {
1463
+ const action = await prompt.select({
1464
+ message: "Password",
1465
+ options: [
1466
+ { value: "set", label: "Set password" },
1467
+ { value: "remove", label: "Remove password" }
1468
+ ]
1469
+ });
1470
+ if (prompt.isCancel(action)) return cancelUpdate(prompt);
1471
+ if (action === "set") {
1472
+ const value = await prompt.password({
1473
+ message: "Password",
1474
+ validate: requireNonEmpty("Enter a password.")
1475
+ });
1476
+ if (prompt.isCancel(value)) return cancelUpdate(prompt);
1477
+ options.password = value;
1478
+ } else {
1479
+ options.password = null;
1480
+ }
1481
+ }
1482
+ if (selected.has("indexing")) {
1483
+ const value = await prompt.select({
1484
+ message: "Search indexing",
1485
+ options: [
1486
+ { value: "noindex", label: "Prevent indexing" },
1487
+ { value: "index", label: "Allow indexing" }
1488
+ ]
1489
+ });
1490
+ if (prompt.isCancel(value)) return cancelUpdate(prompt);
1491
+ options.noindex = value === "noindex";
1492
+ }
1493
+ if (selected.has("expiresAt")) {
1494
+ const value = await prompt.text({
1495
+ message: "Expiration date",
1496
+ placeholder: "2025-12-31T23:59:59Z",
1497
+ validate: validateIsoDate
1498
+ });
1499
+ if (prompt.isCancel(value)) return cancelUpdate(prompt);
1500
+ options.expiresAt = value.trim();
1501
+ }
1502
+ if (selected.has("metadata")) {
1503
+ const value = await prompt.text({
1504
+ message: "Metadata JSON object",
1505
+ placeholder: '{"source":"cli"}',
1506
+ validate: validateJsonObject
1507
+ });
1508
+ if (prompt.isCancel(value)) return cancelUpdate(prompt);
1509
+ options.metadata = parseJsonObject2(value);
1510
+ }
1511
+ return { ...input ? { input } : {}, options };
1512
+ }
1513
+ function cancelUpdate(prompt) {
1514
+ prompt.cancel("Update cancelled.");
1515
+ return void 0;
1516
+ }
1517
+ function requireNonEmpty(message) {
1518
+ return (value) => value?.trim() ? void 0 : message;
1519
+ }
1520
+ function validateIsoDate(value) {
1521
+ if (!value?.trim()) return "Enter an ISO 8601 date.";
1522
+ const d = new Date(value);
1523
+ return Number.isNaN(d.getTime()) ? "Enter a valid ISO 8601 date." : void 0;
1524
+ }
1525
+ function validateJsonObject(value) {
1526
+ if (!value?.trim()) return "Enter a JSON object.";
1527
+ try {
1528
+ parseJsonObject2(value);
1529
+ return void 0;
1530
+ } catch {
1531
+ return "Enter a valid JSON object.";
1532
+ }
1533
+ }
1534
+ function parseJsonObject2(value) {
1535
+ const parsed = JSON.parse(value);
1536
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1537
+ throw new Error("Metadata must be a JSON object.");
1538
+ }
1539
+ return parsed;
1540
+ }
1365
1541
  async function handleUpdateDryRun(target, input, raw, deps) {
1366
1542
  if (raw.url) {
1367
1543
  return writeError(
@@ -1601,7 +1777,7 @@ function buildProgram(options = {}) {
1601
1777
  ` ${import_picocolors4.default.cyan("dropthis login")}`,
1602
1778
  ` ${import_picocolors4.default.cyan("dropthis publish ./dist")}`
1603
1779
  ].join("\n")
1604
- ).version("0.4.1").configureHelp({
1780
+ ).version("0.5.0").configureHelp({
1605
1781
  subcommandTerm(cmd) {
1606
1782
  const args = cmd.registeredArguments.map((a) => {
1607
1783
  const name = a.name();
@@ -1708,6 +1884,8 @@ function buildProgram(options = {}) {
1708
1884
  "Prevent duplicate updates on retry (auto-generated)"
1709
1885
  ).action(
1710
1886
  async (dropId, input, commandOptions) => {
1887
+ const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
1888
+ const global = globalOptions(program, commandOptions);
1711
1889
  const deps = await commandDeps(program, options, store, commandOptions);
1712
1890
  let updateInput;
1713
1891
  try {
@@ -1729,7 +1907,10 @@ function buildProgram(options = {}) {
1729
1907
  process.exitCode = writeError(deps, "invalid_usage", msg).exitCode;
1730
1908
  return;
1731
1909
  }
1732
- const result = await runUpdate(dropId, updateInput, dropOpts, deps);
1910
+ const result = await runUpdate(dropId, updateInput, dropOpts, {
1911
+ ...deps,
1912
+ interactive: isInteractive(stdinIsTTY, deps.env, global)
1913
+ });
1733
1914
  process.exitCode = result.exitCode;
1734
1915
  }
1735
1916
  );