@dropthis/cli 0.3.4 → 0.3.5

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
@@ -44,6 +44,15 @@ async function resolveCredential(input) {
44
44
  ...stored.email ? { email: stored.email } : {}
45
45
  };
46
46
  }
47
+ async function requireCredential(input) {
48
+ const credential = await resolveCredential(input);
49
+ if (!credential) {
50
+ throw Object.assign(new Error("No API key found."), {
51
+ code: "auth_error"
52
+ });
53
+ }
54
+ return credential;
55
+ }
47
56
  function maskKey(apiKey) {
48
57
  return apiKey.length <= 8 ? "sk_..." : `${apiKey.slice(0, 3)}...${apiKey.slice(-4)}`;
49
58
  }
@@ -251,11 +260,13 @@ function writeEmpty(deps, message, json) {
251
260
 
252
261
  // src/commands/account.ts
253
262
  async function runAccountGet(_input, deps) {
254
- if (await resolveCredential({
255
- ...deps.apiKey ? { apiKey: deps.apiKey } : {},
256
- env: deps.env,
257
- store: deps.store
258
- }) === null) {
263
+ try {
264
+ await requireCredential({
265
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
266
+ env: deps.env,
267
+ store: deps.store
268
+ });
269
+ } catch {
259
270
  return writeAuthError(deps);
260
271
  }
261
272
  const result = await deps.client.account.get();
@@ -273,8 +284,33 @@ async function runAccountGet(_input, deps) {
273
284
 
274
285
  // src/commands/api-keys.ts
275
286
  var prompts = __toESM(require("@clack/prompts"), 1);
287
+
288
+ // src/types.ts
289
+ function unwrapListData(data, ...fallbackKeys) {
290
+ if (data && typeof data === "object") {
291
+ if ("data" in data) {
292
+ return data.data;
293
+ }
294
+ for (const key of fallbackKeys) {
295
+ if (key in data) {
296
+ return data[key];
297
+ }
298
+ }
299
+ }
300
+ return data;
301
+ }
302
+
303
+ // src/commands/api-keys.ts
276
304
  async function runApiKeysCreate(input, deps) {
277
- if (!await hasCredential(deps)) return writeAuthError(deps);
305
+ try {
306
+ await requireCredential({
307
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
308
+ env: deps.env,
309
+ store: deps.store
310
+ });
311
+ } catch {
312
+ return writeAuthError(deps);
313
+ }
278
314
  const result = await deps.client.apiKeys.create({ label: input.label });
279
315
  if (result.error) return writeApiErrorSimple(deps, result.error.message);
280
316
  const data = result.data;
@@ -286,10 +322,18 @@ async function runApiKeysCreate(input, deps) {
286
322
  return { exitCode: 0 };
287
323
  }
288
324
  async function runApiKeysList(_input, deps) {
289
- if (!await hasCredential(deps)) return writeAuthError(deps);
325
+ try {
326
+ await requireCredential({
327
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
328
+ env: deps.env,
329
+ store: deps.store
330
+ });
331
+ } catch {
332
+ return writeAuthError(deps);
333
+ }
290
334
  const result = await deps.client.apiKeys.list();
291
335
  if (result.error) return writeApiErrorSimple(deps, result.error.message);
292
- const raw = listItems(result.data);
336
+ const raw = unwrapListData(result.data, "apiKeys", "api_keys");
293
337
  const items = Array.isArray(raw) ? raw : void 0;
294
338
  if (deps.outputMode === "human") {
295
339
  if (!items || items.length === 0) {
@@ -323,7 +367,15 @@ async function runApiKeysDelete(keyId, input, deps) {
323
367
  return { exitCode: 0 };
324
368
  }
325
369
  }
326
- if (!await hasCredential(deps)) return writeAuthError(deps);
370
+ try {
371
+ await requireCredential({
372
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
373
+ env: deps.env,
374
+ store: deps.store
375
+ });
376
+ } catch {
377
+ return writeAuthError(deps);
378
+ }
327
379
  const result = await deps.client.apiKeys.delete(keyId);
328
380
  if (result?.error) return writeApiErrorSimple(deps, result.error.message);
329
381
  writeHumanOrJson(deps, success(`Deleted ${keyId}`), {
@@ -333,25 +385,9 @@ async function runApiKeysDelete(keyId, input, deps) {
333
385
  });
334
386
  return { exitCode: 0 };
335
387
  }
336
- async function hasCredential(deps) {
337
- return await resolveCredential({
338
- ...deps.apiKey ? { apiKey: deps.apiKey } : {},
339
- env: deps.env,
340
- store: deps.store
341
- }) !== null;
342
- }
343
- function listItems(data) {
344
- if (data && typeof data === "object" && "data" in data) {
345
- return data.data;
346
- }
347
- if (data && typeof data === "object" && "apiKeys" in data) {
348
- return data.apiKeys;
349
- }
350
- return data;
351
- }
352
388
 
353
- // src/commands/commands.ts
354
- var COMMANDS = [
389
+ // src/catalog.ts
390
+ var COMMAND_CATALOG = [
355
391
  {
356
392
  name: "publish",
357
393
  description: "Publish an input and return a Dropthis URL.",
@@ -426,12 +462,14 @@ var COMMANDS = [
426
462
  examples: ["dropthis commands --json"]
427
463
  }
428
464
  ];
465
+
466
+ // src/commands/commands.ts
429
467
  async function runCommands(_input, deps) {
430
468
  deps.stdout(
431
469
  `${JSON.stringify({
432
470
  ok: true,
433
471
  output: "JSON by default in CI, pipes, non-TTY, --json, or --quiet.",
434
- commands: COMMANDS
472
+ commands: COMMAND_CATALOG
435
473
  })}
436
474
  `
437
475
  );
@@ -440,7 +478,15 @@ async function runCommands(_input, deps) {
440
478
 
441
479
  // src/commands/deployments.ts
442
480
  async function runDeploymentsList(dropId, input, deps) {
443
- if (!await hasCredential2(deps)) return writeAuthError(deps);
481
+ try {
482
+ await requireCredential({
483
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
484
+ env: deps.env,
485
+ store: deps.store
486
+ });
487
+ } catch {
488
+ return writeAuthError(deps);
489
+ }
444
490
  const params = {
445
491
  ...input.limit !== void 0 ? { limit: input.limit } : {},
446
492
  ...input.cursor ? { cursor: input.cursor } : {}
@@ -473,7 +519,15 @@ async function runDeploymentsList(dropId, input, deps) {
473
519
  return { exitCode: 0 };
474
520
  }
475
521
  async function runDeploymentsGet(dropId, deploymentId, _input, deps) {
476
- if (!await hasCredential2(deps)) return writeAuthError(deps);
522
+ try {
523
+ await requireCredential({
524
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
525
+ env: deps.env,
526
+ store: deps.store
527
+ });
528
+ } catch {
529
+ return writeAuthError(deps);
530
+ }
477
531
  const result = await deps.client.deployments.get(dropId, deploymentId);
478
532
  if (result.error) {
479
533
  return writeApiError(deps, result.error);
@@ -487,13 +541,6 @@ async function runDeploymentsGet(dropId, deploymentId, _input, deps) {
487
541
  writeKv(deps, pairs, { ok: true, deployment: result.data });
488
542
  return { exitCode: 0 };
489
543
  }
490
- async function hasCredential2(deps) {
491
- return await resolveCredential({
492
- ...deps.apiKey ? { apiKey: deps.apiKey } : {},
493
- env: deps.env,
494
- store: deps.store
495
- }) !== null;
496
- }
497
544
  function spreadData(data) {
498
545
  return data && typeof data === "object" ? data : { data };
499
546
  }
@@ -508,13 +555,13 @@ async function runDoctor(_input, deps) {
508
555
  const authSource = credential?.source ?? "missing";
509
556
  const storageBackend = stored?.storage ?? "none";
510
557
  const pairs = [
511
- ["Version", "0.3.4"],
558
+ ["Version", "0.3.5"],
512
559
  ["Auth", authSource],
513
560
  ["Storage", storageBackend]
514
561
  ];
515
562
  writeKv(deps, pairs, {
516
563
  ok: true,
517
- version: "0.3.4",
564
+ version: "0.3.5",
518
565
  auth: { source: authSource },
519
566
  storage: { backend: storageBackend }
520
567
  });
@@ -524,14 +571,22 @@ async function runDoctor(_input, deps) {
524
571
  // src/commands/drops.ts
525
572
  var prompts2 = __toESM(require("@clack/prompts"), 1);
526
573
  async function runDropsList(input, deps) {
527
- if (!await hasCredential3(deps)) return writeAuthError(deps);
574
+ try {
575
+ await requireCredential({
576
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
577
+ env: deps.env,
578
+ store: deps.store
579
+ });
580
+ } catch {
581
+ return writeAuthError(deps);
582
+ }
528
583
  const params = {
529
584
  ...input.limit !== void 0 ? { limit: input.limit } : {},
530
585
  ...input.cursor ? { cursor: input.cursor } : {}
531
586
  };
532
587
  const result = await deps.client.drops.list(params);
533
588
  if (result.error) return writeApiErrorSimple(deps, result.error.message);
534
- const raw = listItems2(result.data);
589
+ const raw = unwrapListData(result.data, "drops");
535
590
  const items = Array.isArray(raw) ? raw : void 0;
536
591
  if (deps.outputMode === "human") {
537
592
  if (!items || items.length === 0) {
@@ -550,7 +605,15 @@ async function runDropsList(input, deps) {
550
605
  return { exitCode: 0 };
551
606
  }
552
607
  async function runDropsGet(dropId, _input, deps) {
553
- if (!await hasCredential3(deps)) return writeAuthError(deps);
608
+ try {
609
+ await requireCredential({
610
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
611
+ env: deps.env,
612
+ store: deps.store
613
+ });
614
+ } catch {
615
+ return writeAuthError(deps);
616
+ }
554
617
  const result = await deps.client.drops.get(dropId);
555
618
  if (result.error) return writeApiErrorSimple(deps, result.error.message);
556
619
  const data = result.data;
@@ -587,7 +650,15 @@ async function runDropsDelete(dropId, input, deps) {
587
650
  return { exitCode: 0 };
588
651
  }
589
652
  }
590
- if (!await hasCredential3(deps)) return writeAuthError(deps);
653
+ try {
654
+ await requireCredential({
655
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
656
+ env: deps.env,
657
+ store: deps.store
658
+ });
659
+ } catch {
660
+ return writeAuthError(deps);
661
+ }
591
662
  const result = await deps.client.drops.delete(dropId);
592
663
  if (result?.error) return writeApiErrorSimple(deps, result.error.message);
593
664
  writeHumanOrJson(deps, success(`Deleted ${dropId}`), {
@@ -597,22 +668,6 @@ async function runDropsDelete(dropId, input, deps) {
597
668
  });
598
669
  return { exitCode: 0 };
599
670
  }
600
- async function hasCredential3(deps) {
601
- return await resolveCredential({
602
- ...deps.apiKey ? { apiKey: deps.apiKey } : {},
603
- env: deps.env,
604
- store: deps.store
605
- }) !== null;
606
- }
607
- function listItems2(data) {
608
- if (data && typeof data === "object" && "data" in data) {
609
- return data.data;
610
- }
611
- if (data && typeof data === "object" && "drops" in data) {
612
- return data.drops;
613
- }
614
- return data;
615
- }
616
671
 
617
672
  // src/commands/login.ts
618
673
  var prompts3 = __toESM(require("@clack/prompts"), 1);
@@ -758,9 +813,88 @@ async function runLogout(input, deps) {
758
813
  }
759
814
 
760
815
  // src/commands/publish.ts
761
- var import_node_crypto = require("crypto");
762
816
  var import_promises3 = require("fs/promises");
817
+ var import_node_path2 = require("path");
818
+
819
+ // src/drop-operations.ts
820
+ var import_node_crypto = require("crypto");
763
821
  var import_node_path = require("path");
822
+ var MAX_BUNDLE_FILE_COUNT = 200;
823
+ function isFileSystemError(error2) {
824
+ if (!(error2 instanceof Error)) return false;
825
+ const code = error2.code;
826
+ return code === "ENOENT" || code === "ENOTDIR" || code === "EACCES" || code === "ELIMIT";
827
+ }
828
+ function mimeForPath(filePath) {
829
+ const ext = (0, import_node_path.extname)(filePath).toLowerCase();
830
+ const types = {
831
+ ".html": "text/html",
832
+ ".htm": "text/html",
833
+ ".css": "text/css",
834
+ ".js": "text/javascript",
835
+ ".mjs": "text/javascript",
836
+ ".json": "application/json",
837
+ ".xml": "application/xml",
838
+ ".svg": "image/svg+xml",
839
+ ".txt": "text/plain",
840
+ ".md": "text/markdown",
841
+ ".jpg": "image/jpeg",
842
+ ".jpeg": "image/jpeg",
843
+ ".png": "image/png",
844
+ ".gif": "image/gif",
845
+ ".webp": "image/webp",
846
+ ".ico": "image/x-icon",
847
+ ".avif": "image/avif",
848
+ ".pdf": "application/pdf",
849
+ ".zip": "application/zip",
850
+ ".woff": "font/woff",
851
+ ".woff2": "font/woff2",
852
+ ".ttf": "font/ttf",
853
+ ".mp4": "video/mp4",
854
+ ".webm": "video/webm"
855
+ };
856
+ return types[ext] ?? "application/octet-stream";
857
+ }
858
+ function withIdempotencyKey(options, prefix) {
859
+ return options.idempotencyKey ? options : { ...options, idempotencyKey: `cli_${prefix}_${(0, import_node_crypto.randomUUID)()}` };
860
+ }
861
+ function validateManifestFileCount(count) {
862
+ if (count > MAX_BUNDLE_FILE_COUNT) {
863
+ throw Object.assign(
864
+ new Error(
865
+ `Bundle contains ${count} files, exceeding the maximum of ${MAX_BUNDLE_FILE_COUNT}.`
866
+ ),
867
+ { code: "ELIMIT" }
868
+ );
869
+ }
870
+ }
871
+ function formatDryRunManifest(prepared, extra) {
872
+ const totalBytes = prepared.manifest.files.reduce(
873
+ (sum, f) => sum + f.sizeBytes,
874
+ 0
875
+ );
876
+ return {
877
+ dryRun: true,
878
+ kind: "staged",
879
+ ...extra,
880
+ manifest: {
881
+ files: prepared.manifest.files,
882
+ entry: prepared.manifest.entry ?? null
883
+ },
884
+ options: prepared.options,
885
+ ...prepared.metadata ? { metadata: prepared.metadata } : {},
886
+ totalBytes
887
+ };
888
+ }
889
+ function dryRunOptionsBody(options) {
890
+ const result = {};
891
+ if (options.title) result.title = options.title;
892
+ if (options.visibility) result.visibility = options.visibility;
893
+ if (options.password !== void 0) result.password = options.password;
894
+ if (options.noindex !== void 0) result.noindex = options.noindex;
895
+ if (options.expiresAt) result.expires_at = options.expiresAt;
896
+ return result;
897
+ }
764
898
 
765
899
  // src/options.ts
766
900
  var import_promises = require("fs/promises");
@@ -856,14 +990,14 @@ async function readJsonObjectFile(path) {
856
990
  }
857
991
 
858
992
  // src/commands/publish.ts
859
- var MAX_BUNDLE_FILE_COUNT = 200;
860
993
  async function runPublish(input, raw, deps) {
861
- const credential = await resolveCredential({
862
- ...raw.apiKey ?? deps.apiKey ? { apiKey: raw.apiKey ?? deps.apiKey } : {},
863
- env: deps.env,
864
- store: deps.store
865
- });
866
- if (!credential) {
994
+ try {
995
+ await requireCredential({
996
+ ...raw.apiKey ?? deps.apiKey ? { apiKey: raw.apiKey ?? deps.apiKey } : {},
997
+ env: deps.env,
998
+ store: deps.store
999
+ });
1000
+ } catch {
867
1001
  return writeAuthError(deps);
868
1002
  }
869
1003
  if (raw.dryRun) {
@@ -875,7 +1009,7 @@ async function runPublish(input, raw, deps) {
875
1009
  if (raw.fromJson && singleInput) {
876
1010
  throw new Error("Use either <input> or --from-json, not both.");
877
1011
  }
878
- const options = withPublishIdempotency(await parseDropOptions(raw));
1012
+ const options = withIdempotencyKey(await parseDropOptions(raw), "pub");
879
1013
  const result = raw.fromJson ? await deps.client.drops.createRaw(
880
1014
  await (deps.readJsonObject ?? readJsonObjectFile)(raw.fromJson),
881
1015
  options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {}
@@ -931,8 +1065,10 @@ async function handlePublishDryRun(input, raw, deps) {
931
1065
  throw new Error("Client does not support dry-run.");
932
1066
  }
933
1067
  const prepared = await deps.client.prepare(input, options);
934
- const output = formatDryRunOutput(prepared);
935
- validateDryRunOutput(output);
1068
+ const output = formatDryRunManifest(prepared);
1069
+ validateManifestFileCount(
1070
+ output.manifest.files.length
1071
+ );
936
1072
  deps.stdout(`${JSON.stringify(output, null, 2)}
937
1073
  `);
938
1074
  return { exitCode: 0 };
@@ -963,18 +1099,12 @@ async function dryRunMultiFile(inputs, options, deps) {
963
1099
  );
964
1100
  }
965
1101
  files.push({
966
- path: (0, import_node_path.basename)(filePath),
1102
+ path: (0, import_node_path2.basename)(filePath),
967
1103
  contentType: mimeForPath(filePath),
968
1104
  sizeBytes: info.size
969
1105
  });
970
1106
  }
971
- if (files.length > MAX_BUNDLE_FILE_COUNT) {
972
- return writeError(
973
- deps,
974
- "local_input_error",
975
- `Bundle contains ${files.length} files, exceeding the maximum of ${MAX_BUNDLE_FILE_COUNT}.`
976
- );
977
- }
1107
+ validateManifestFileCount(files.length);
978
1108
  const entry = options.entry ?? files.find((f) => f.path === "index.html")?.path ?? files[0]?.path ?? null;
979
1109
  const totalBytes = files.reduce((sum, f) => sum + f.sizeBytes, 0);
980
1110
  const output = {
@@ -988,92 +1118,16 @@ async function dryRunMultiFile(inputs, options, deps) {
988
1118
  `);
989
1119
  return { exitCode: 0 };
990
1120
  }
991
- function formatDryRunOutput(prepared) {
992
- const totalBytes = prepared.manifest.files.reduce(
993
- (sum, f) => sum + f.sizeBytes,
994
- 0
995
- );
996
- return {
997
- dryRun: true,
998
- kind: "staged",
999
- manifest: {
1000
- files: prepared.manifest.files,
1001
- entry: prepared.manifest.entry ?? null
1002
- },
1003
- options: prepared.options,
1004
- ...prepared.metadata ? { metadata: prepared.metadata } : {},
1005
- totalBytes
1006
- };
1007
- }
1008
- function validateDryRunOutput(output) {
1009
- if (output.kind !== "staged") return;
1010
- const manifest = output.manifest;
1011
- if (manifest.files.length > MAX_BUNDLE_FILE_COUNT) {
1012
- throw Object.assign(
1013
- new Error(
1014
- `Bundle contains ${manifest.files.length} files, exceeding the maximum of ${MAX_BUNDLE_FILE_COUNT}.`
1015
- ),
1016
- { code: "ELIMIT" }
1017
- );
1018
- }
1019
- }
1020
- function dryRunOptionsBody(options) {
1021
- const result = {};
1022
- if (options.title) result.title = options.title;
1023
- if (options.visibility) result.visibility = options.visibility;
1024
- if (options.password !== void 0) result.password = options.password;
1025
- if (options.noindex !== void 0) result.noindex = options.noindex;
1026
- if (options.expiresAt) result.expires_at = options.expiresAt;
1027
- return result;
1028
- }
1029
- function mimeForPath(filePath) {
1030
- const ext = (0, import_node_path.extname)(filePath).toLowerCase();
1031
- const types = {
1032
- ".html": "text/html",
1033
- ".htm": "text/html",
1034
- ".css": "text/css",
1035
- ".js": "text/javascript",
1036
- ".mjs": "text/javascript",
1037
- ".json": "application/json",
1038
- ".xml": "application/xml",
1039
- ".svg": "image/svg+xml",
1040
- ".txt": "text/plain",
1041
- ".md": "text/markdown",
1042
- ".jpg": "image/jpeg",
1043
- ".jpeg": "image/jpeg",
1044
- ".png": "image/png",
1045
- ".gif": "image/gif",
1046
- ".webp": "image/webp",
1047
- ".ico": "image/x-icon",
1048
- ".avif": "image/avif",
1049
- ".pdf": "application/pdf",
1050
- ".zip": "application/zip",
1051
- ".woff": "font/woff",
1052
- ".woff2": "font/woff2",
1053
- ".ttf": "font/ttf",
1054
- ".mp4": "video/mp4",
1055
- ".webm": "video/webm"
1056
- };
1057
- return types[ext] ?? "application/octet-stream";
1058
- }
1059
- function isFileSystemError(error2) {
1060
- if (!(error2 instanceof Error)) return false;
1061
- const code = error2.code;
1062
- return code === "ENOENT" || code === "ENOTDIR" || code === "EACCES" || code === "ELIMIT";
1063
- }
1064
- function withPublishIdempotency(options) {
1065
- return options.idempotencyKey ? options : { ...options, idempotencyKey: `cli_pub_${(0, import_node_crypto.randomUUID)()}` };
1066
- }
1067
1121
 
1068
1122
  // src/commands/update.ts
1069
- var import_node_crypto2 = require("crypto");
1070
1123
  async function runUpdate(target, input, raw, deps) {
1071
- const credential = await resolveCredential({
1072
- ...raw.apiKey ?? deps.apiKey ? { apiKey: raw.apiKey ?? deps.apiKey } : {},
1073
- env: deps.env,
1074
- store: deps.store
1075
- });
1076
- if (!credential) {
1124
+ try {
1125
+ await requireCredential({
1126
+ ...raw.apiKey ?? deps.apiKey ? { apiKey: raw.apiKey ?? deps.apiKey } : {},
1127
+ env: deps.env,
1128
+ store: deps.store
1129
+ });
1130
+ } catch {
1077
1131
  return writeAuthError(deps);
1078
1132
  }
1079
1133
  if (raw.dryRun) {
@@ -1090,17 +1144,23 @@ async function runUpdate(target, input, raw, deps) {
1090
1144
  const result = raw.fromJson ? await deps.client.deployments.createRaw(
1091
1145
  target,
1092
1146
  await (deps.readJsonObject ?? readJsonObjectFile)(raw.fromJson),
1093
- withUpdateIdempotency({
1094
- ...revisionOptions,
1095
- ...parsed.idempotencyKey ? { idempotencyKey: parsed.idempotencyKey } : {}
1096
- })
1147
+ withIdempotencyKey(
1148
+ {
1149
+ ...revisionOptions,
1150
+ ...parsed.idempotencyKey ? { idempotencyKey: parsed.idempotencyKey } : {}
1151
+ },
1152
+ "upd"
1153
+ )
1097
1154
  ) : input ? await deps.client.update(
1098
1155
  target,
1099
1156
  input,
1100
- withUpdateIdempotency({
1101
- ...parsed,
1102
- ...revisionOptions
1103
- })
1157
+ withIdempotencyKey(
1158
+ {
1159
+ ...parsed,
1160
+ ...revisionOptions
1161
+ },
1162
+ "upd"
1163
+ )
1104
1164
  ) : await deps.client.update(target, parsed, revisionOptions);
1105
1165
  if (result.error) {
1106
1166
  spin?.fail();
@@ -1113,8 +1173,9 @@ async function runUpdate(target, input, raw, deps) {
1113
1173
  return { exitCode: 0 };
1114
1174
  } catch (error2) {
1115
1175
  const message = error2 instanceof Error ? error2.message : "Update failed.";
1176
+ const code = isFileSystemError(error2) ? "local_input_error" : "invalid_usage";
1116
1177
  spin?.fail();
1117
- return writeError(deps, "invalid_usage", message);
1178
+ return writeError(deps, code, message);
1118
1179
  }
1119
1180
  }
1120
1181
  async function handleUpdateDryRun(target, input, raw, deps) {
@@ -1160,56 +1221,17 @@ async function handleUpdateDryRun(target, input, raw, deps) {
1160
1221
  throw new Error("Client does not support dry-run.");
1161
1222
  }
1162
1223
  const prepared = await deps.client.prepare(input, options);
1163
- const output = formatUpdateDryRun(target, prepared);
1164
- validateDryRunFileCount(output);
1224
+ const output = formatDryRunManifest(prepared, { target });
1225
+ validateManifestFileCount(prepared.manifest.files.length);
1165
1226
  deps.stdout(`${JSON.stringify(output, null, 2)}
1166
1227
  `);
1167
1228
  return { exitCode: 0 };
1168
1229
  } catch (error2) {
1169
- const code = isFileSystemError2(error2) ? "local_input_error" : "invalid_usage";
1230
+ const code = isFileSystemError(error2) ? "local_input_error" : "invalid_usage";
1170
1231
  const message = error2 instanceof Error ? error2.message : "Dry-run failed.";
1171
1232
  return writeError(deps, code, message);
1172
1233
  }
1173
1234
  }
1174
- var MAX_BUNDLE_FILE_COUNT2 = 200;
1175
- function formatUpdateDryRun(target, prepared) {
1176
- const totalBytes = prepared.manifest.files.reduce(
1177
- (sum, f) => sum + f.sizeBytes,
1178
- 0
1179
- );
1180
- return {
1181
- dryRun: true,
1182
- kind: "staged",
1183
- target,
1184
- manifest: {
1185
- files: prepared.manifest.files,
1186
- entry: prepared.manifest.entry ?? null
1187
- },
1188
- options: prepared.options,
1189
- ...prepared.metadata ? { metadata: prepared.metadata } : {},
1190
- totalBytes
1191
- };
1192
- }
1193
- function validateDryRunFileCount(output) {
1194
- if (output.kind !== "staged") return;
1195
- const manifest = output.manifest;
1196
- if (manifest.files.length > MAX_BUNDLE_FILE_COUNT2) {
1197
- throw Object.assign(
1198
- new Error(
1199
- `Bundle contains ${manifest.files.length} files, exceeding the maximum of ${MAX_BUNDLE_FILE_COUNT2}.`
1200
- ),
1201
- { code: "ELIMIT" }
1202
- );
1203
- }
1204
- }
1205
- function isFileSystemError2(error2) {
1206
- if (!(error2 instanceof Error)) return false;
1207
- const code = error2.code;
1208
- return code === "ENOENT" || code === "ENOTDIR";
1209
- }
1210
- function withUpdateIdempotency(options) {
1211
- return options.idempotencyKey ? options : { ...options, idempotencyKey: `cli_upd_${(0, import_node_crypto2.randomUUID)()}` };
1212
- }
1213
1235
  function assertDropId(target) {
1214
1236
  if (!target.startsWith("drop_")) {
1215
1237
  throw new Error(
@@ -1280,7 +1302,7 @@ function createContext(input) {
1280
1302
  // src/storage.ts
1281
1303
  var import_promises4 = require("fs/promises");
1282
1304
  var import_node_os = require("os");
1283
- var import_node_path2 = require("path");
1305
+ var import_node_path3 = require("path");
1284
1306
  var import_keyring = require("@napi-rs/keyring");
1285
1307
  var MemoryCredentialStore = class {
1286
1308
  credential = null;
@@ -1357,8 +1379,8 @@ function defaultKeyringAdapter() {
1357
1379
  };
1358
1380
  }
1359
1381
  function credentialPath(configDir) {
1360
- return (0, import_node_path2.join)(
1361
- configDir ?? (0, import_node_path2.join)((0, import_node_os.homedir)(), ".config", "dropthis"),
1382
+ return (0, import_node_path3.join)(
1383
+ configDir ?? (0, import_node_path3.join)((0, import_node_os.homedir)(), ".config", "dropthis"),
1362
1384
  "credentials.json"
1363
1385
  );
1364
1386
  }
@@ -1373,7 +1395,7 @@ async function readJsonFile(path) {
1373
1395
  }
1374
1396
  }
1375
1397
  async function writeCredentialFile(path, credential) {
1376
- await (0, import_promises4.mkdir)((0, import_node_path2.dirname)(path), { recursive: true });
1398
+ await (0, import_promises4.mkdir)((0, import_node_path3.dirname)(path), { recursive: true });
1377
1399
  await (0, import_promises4.writeFile)(path, `${JSON.stringify(credential, null, 2)}
1378
1400
  `, {
1379
1401
  mode: 384
@@ -1393,7 +1415,7 @@ function buildProgram(options = {}) {
1393
1415
  ` ${import_picocolors4.default.cyan("dropthis login")}`,
1394
1416
  ` ${import_picocolors4.default.cyan("dropthis publish ./dist")}`
1395
1417
  ].join("\n")
1396
- ).version("0.3.4").configureHelp({
1418
+ ).version("0.3.5").configureHelp({
1397
1419
  subcommandTerm(cmd) {
1398
1420
  const args = cmd.registeredArguments.map((a) => {
1399
1421
  const name = a.name();
@@ -1696,15 +1718,10 @@ function globalOptions(program, commandOptions) {
1696
1718
  };
1697
1719
  }
1698
1720
  function toDropOptions(options) {
1699
- if (options.visibility && options.visibility !== "public" && options.visibility !== "unlisted") {
1700
- throw new Error(
1701
- `Invalid visibility "${options.visibility}". Use "public" or "unlisted".`
1702
- );
1703
- }
1704
1721
  return {
1705
1722
  ...options.slug ? { slug: options.slug } : {},
1706
1723
  ...options.title ? { title: options.title } : {},
1707
- ...options.visibility === "public" || options.visibility === "unlisted" ? { visibility: options.visibility } : {},
1724
+ ...options.visibility ? { visibility: options.visibility } : {},
1708
1725
  ...typeof options.password === "string" ? { password: options.password } : {},
1709
1726
  ...options.password === false || options.noPassword ? { noPassword: true } : {},
1710
1727
  ...options.noindex ? { noindex: true } : {},