@dropthis/cli 0.10.0 → 0.12.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 +10 -6
- package/dist/cli.cjs +774 -86
- package/dist/cli.cjs.map +1 -1
- package/node_modules/@dropthis/node/README.md +48 -1
- package/node_modules/@dropthis/node/dist/{drops-D0MLPPF9.d.cts → drops-DEJcU6qw.d.cts} +130 -3
- package/node_modules/@dropthis/node/dist/{drops-D0MLPPF9.d.ts → drops-DEJcU6qw.d.ts} +130 -3
- package/node_modules/@dropthis/node/dist/edge.cjs +82 -3
- package/node_modules/@dropthis/node/dist/edge.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/edge.d.cts +3 -1
- package/node_modules/@dropthis/node/dist/edge.d.ts +3 -1
- package/node_modules/@dropthis/node/dist/edge.mjs +82 -3
- package/node_modules/@dropthis/node/dist/edge.mjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.cjs +84 -3
- package/node_modules/@dropthis/node/dist/index.cjs.map +1 -1
- package/node_modules/@dropthis/node/dist/index.d.cts +5 -3
- package/node_modules/@dropthis/node/dist/index.d.ts +5 -3
- package/node_modules/@dropthis/node/dist/index.mjs +83 -3
- package/node_modules/@dropthis/node/dist/index.mjs.map +1 -1
- package/node_modules/@dropthis/node/package.json +1 -1
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -202,10 +202,25 @@ function normalizeApiErrorCode(error2) {
|
|
|
202
202
|
if (error2.statusCode === 404) return "not_found";
|
|
203
203
|
return "api_error";
|
|
204
204
|
}
|
|
205
|
-
function nextActionForApiError(error2) {
|
|
205
|
+
function nextActionForApiError(error2, mode = "json") {
|
|
206
|
+
const cliHint = cliNextAction(error2);
|
|
207
|
+
if (mode === "human" && cliHint) return cliHint;
|
|
206
208
|
if (error2.suggestion) return error2.suggestion;
|
|
209
|
+
if (cliHint) return cliHint;
|
|
210
|
+
if (error2.statusCode === 422) {
|
|
211
|
+
return "Fix the input shown in the error detail and retry.";
|
|
212
|
+
}
|
|
213
|
+
if (error2.statusCode !== void 0 && error2.statusCode !== null && error2.statusCode >= 500) {
|
|
214
|
+
return "Retry the request with the same idempotency key, or contact support with the request id.";
|
|
215
|
+
}
|
|
216
|
+
return "Fix the request or retry after checking the drop state.";
|
|
217
|
+
}
|
|
218
|
+
function cliNextAction(error2) {
|
|
207
219
|
const uploadNextAction = error2.code ? UPLOAD_NEXT_ACTIONS[error2.code] : void 0;
|
|
208
220
|
if (uploadNextAction) return uploadNextAction;
|
|
221
|
+
if (error2.code === "network_error") {
|
|
222
|
+
return "Could not reach the dropthis API \u2014 check your network or DROPTHIS_API_URL.";
|
|
223
|
+
}
|
|
209
224
|
if (error2.code === "revision_conflict") {
|
|
210
225
|
return "Re-read the drop with dropthis get <drop-id>, merge your changes, and retry with --if-revision set to the current revision.";
|
|
211
226
|
}
|
|
@@ -218,13 +233,7 @@ function nextActionForApiError(error2) {
|
|
|
218
233
|
if (error2.statusCode === 413 || error2.code === "quota_exceeded") {
|
|
219
234
|
return "Reduce the upload size or upgrade the account limit.";
|
|
220
235
|
}
|
|
221
|
-
|
|
222
|
-
return "Fix the input shown in the error detail and retry.";
|
|
223
|
-
}
|
|
224
|
-
if (error2.statusCode !== void 0 && error2.statusCode !== null && error2.statusCode >= 500) {
|
|
225
|
-
return "Retry the request with the same idempotency key, or contact support with the request id.";
|
|
226
|
-
}
|
|
227
|
-
return "Fix the request or retry after checking the drop state.";
|
|
236
|
+
return void 0;
|
|
228
237
|
}
|
|
229
238
|
function exitCodeFor(code) {
|
|
230
239
|
if (code === "usage_error") return 2;
|
|
@@ -232,12 +241,14 @@ function exitCodeFor(code) {
|
|
|
232
241
|
if (code === "auth_error") return 3;
|
|
233
242
|
if (code === "local_input_error") return 4;
|
|
234
243
|
if (code === "network_error") return 5;
|
|
244
|
+
if (code === "verify_pending") return 6;
|
|
245
|
+
if (code === "verify_timeout") return 7;
|
|
235
246
|
return 1;
|
|
236
247
|
}
|
|
237
248
|
|
|
238
249
|
// src/program.ts
|
|
239
250
|
var import_commander = require("commander");
|
|
240
|
-
var
|
|
251
|
+
var import_picocolors6 = __toESM(require("picocolors"), 1);
|
|
241
252
|
|
|
242
253
|
// src/auth.ts
|
|
243
254
|
async function resolveCredential(input) {
|
|
@@ -285,6 +296,9 @@ function success(msg) {
|
|
|
285
296
|
function error(msg) {
|
|
286
297
|
return `${import_picocolors.default.red(symbols.error)} ${msg}`;
|
|
287
298
|
}
|
|
299
|
+
function warn(msg) {
|
|
300
|
+
return `${import_picocolors.default.yellow(symbols.warning)} ${msg}`;
|
|
301
|
+
}
|
|
288
302
|
function hint(msg) {
|
|
289
303
|
return ` ${import_picocolors.default.dim(msg)}`;
|
|
290
304
|
}
|
|
@@ -305,6 +319,21 @@ function writeResult(deps, link, verb, data) {
|
|
|
305
319
|
const details = formatDropDetails(data);
|
|
306
320
|
if (details) deps.stdout(`${details}
|
|
307
321
|
`);
|
|
322
|
+
const warnings = data.warnings;
|
|
323
|
+
if (Array.isArray(warnings)) {
|
|
324
|
+
for (const w of warnings) {
|
|
325
|
+
if (w.code === "slug_suffixed") {
|
|
326
|
+
deps.stderr(
|
|
327
|
+
`${hint(`Vanity slug was taken \u2014 served at: ${w.detail ?? "see URL"}`)}
|
|
328
|
+
`
|
|
329
|
+
);
|
|
330
|
+
} else {
|
|
331
|
+
const text2 = typeof w.detail === "string" ? w.detail : typeof w.message === "string" ? w.message : typeof w.code === "string" ? w.code : void 0;
|
|
332
|
+
if (text2) deps.stderr(`${hint(text2)}
|
|
333
|
+
`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
308
337
|
} else {
|
|
309
338
|
deps.stdout(`${JSON.stringify({ ok: true, drop: data })}
|
|
310
339
|
`);
|
|
@@ -323,6 +352,13 @@ function formatDropDetails(data) {
|
|
|
323
352
|
if (parts.length === 0) return "";
|
|
324
353
|
return ` ${import_picocolors2.default.dim(parts.join(" \xB7 "))}`;
|
|
325
354
|
}
|
|
355
|
+
function formatDate(iso) {
|
|
356
|
+
return iso.split("T")[0] ?? iso;
|
|
357
|
+
}
|
|
358
|
+
function formatDateTime(iso) {
|
|
359
|
+
const match = iso.match(/^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})/);
|
|
360
|
+
return match ? `${match[1]} ${match[2]}` : iso;
|
|
361
|
+
}
|
|
326
362
|
function formatBytes(bytes) {
|
|
327
363
|
if (bytes < 1024) return `${bytes} B`;
|
|
328
364
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -368,7 +404,7 @@ function writeApiError(deps, details) {
|
|
|
368
404
|
if (deps.outputMode === "human") {
|
|
369
405
|
deps.stderr(`${error(details.message)}
|
|
370
406
|
`);
|
|
371
|
-
const nextAction = nextActionForApiError(details);
|
|
407
|
+
const nextAction = nextActionForApiError(details, "human");
|
|
372
408
|
if (nextAction) deps.stderr(`${hint(nextAction)}
|
|
373
409
|
`);
|
|
374
410
|
if (details.currentRevision !== void 0)
|
|
@@ -383,7 +419,12 @@ function writeApiError(deps, details) {
|
|
|
383
419
|
deps.stderr(`${JSON.stringify(apiErrorEnvelope(details))}
|
|
384
420
|
`);
|
|
385
421
|
}
|
|
386
|
-
return { exitCode: exitCodeFor(
|
|
422
|
+
return { exitCode: exitCodeFor(cliErrorCodeFor(details)) };
|
|
423
|
+
}
|
|
424
|
+
function cliErrorCodeFor(details) {
|
|
425
|
+
if (details.code === "network_error") return "network_error";
|
|
426
|
+
if (details.code === "file_not_found") return "local_input_error";
|
|
427
|
+
return "api_error";
|
|
387
428
|
}
|
|
388
429
|
function writeApiErrorSimple(deps, message) {
|
|
389
430
|
if (deps.outputMode === "human") {
|
|
@@ -491,6 +532,14 @@ async function runAccountDelete(input, deps) {
|
|
|
491
532
|
var prompts = __toESM(require("@clack/prompts"), 1);
|
|
492
533
|
|
|
493
534
|
// src/types.ts
|
|
535
|
+
function extractPagination(data) {
|
|
536
|
+
if (!data || typeof data !== "object") return void 0;
|
|
537
|
+
const rec = data;
|
|
538
|
+
if (!("nextCursor" in rec) && !("hasMore" in rec)) return void 0;
|
|
539
|
+
const nextCursor = typeof rec.nextCursor === "string" ? rec.nextCursor : null;
|
|
540
|
+
const hasMore = typeof rec.hasMore === "boolean" ? rec.hasMore : nextCursor !== null;
|
|
541
|
+
return { nextCursor, hasMore };
|
|
542
|
+
}
|
|
494
543
|
function unwrapListData(data, ...fallbackKeys) {
|
|
495
544
|
if (data && typeof data === "object") {
|
|
496
545
|
if ("data" in data) {
|
|
@@ -631,7 +680,7 @@ var COMMAND_ANNOTATIONS = {
|
|
|
631
680
|
},
|
|
632
681
|
deployments: {
|
|
633
682
|
auth: "required",
|
|
634
|
-
examples: ["dropthis deployments drop_abc --json"]
|
|
683
|
+
examples: ["dropthis deployments list drop_abc --json"]
|
|
635
684
|
},
|
|
636
685
|
"deployments list": {
|
|
637
686
|
auth: "required",
|
|
@@ -641,6 +690,36 @@ var COMMAND_ANNOTATIONS = {
|
|
|
641
690
|
auth: "required",
|
|
642
691
|
examples: ["dropthis deployments get drop_abc dep_abc --json"]
|
|
643
692
|
},
|
|
693
|
+
domains: {
|
|
694
|
+
auth: "required",
|
|
695
|
+
examples: ["dropthis domains list --json"]
|
|
696
|
+
},
|
|
697
|
+
"domains connect": {
|
|
698
|
+
auth: "required",
|
|
699
|
+
examples: [
|
|
700
|
+
"dropthis domains connect reports.example.com --mode path --json"
|
|
701
|
+
]
|
|
702
|
+
},
|
|
703
|
+
"domains list": {
|
|
704
|
+
auth: "required",
|
|
705
|
+
examples: ["dropthis domains list --json"]
|
|
706
|
+
},
|
|
707
|
+
"domains status": {
|
|
708
|
+
auth: "required",
|
|
709
|
+
examples: ["dropthis domains status reports.example.com --json"]
|
|
710
|
+
},
|
|
711
|
+
"domains verify": {
|
|
712
|
+
auth: "required",
|
|
713
|
+
examples: ["dropthis domains verify reports.example.com --wait --json"]
|
|
714
|
+
},
|
|
715
|
+
"domains update": {
|
|
716
|
+
auth: "required",
|
|
717
|
+
examples: ["dropthis domains update reports.example.com --default --json"]
|
|
718
|
+
},
|
|
719
|
+
"domains remove": {
|
|
720
|
+
auth: "required",
|
|
721
|
+
examples: ["dropthis domains remove reports.example.com --yes --json"]
|
|
722
|
+
},
|
|
644
723
|
"api-keys": {
|
|
645
724
|
auth: "required",
|
|
646
725
|
examples: ["dropthis api-keys create --label CI --json"]
|
|
@@ -722,6 +801,7 @@ async function runDeploymentsList(dropId, input, deps) {
|
|
|
722
801
|
return writeApiError(deps, result.error);
|
|
723
802
|
}
|
|
724
803
|
const spread = spreadData(result.data);
|
|
804
|
+
const page = extractPagination(result.data);
|
|
725
805
|
const items = spread.deployments ?? spread.data ?? result.data;
|
|
726
806
|
if (deps.outputMode === "human") {
|
|
727
807
|
if (!items || Array.isArray(items) && items.length === 0) {
|
|
@@ -731,8 +811,15 @@ async function runDeploymentsList(dropId, input, deps) {
|
|
|
731
811
|
});
|
|
732
812
|
} else if (Array.isArray(items)) {
|
|
733
813
|
for (const item of items) {
|
|
814
|
+
const created = typeof item.createdAt === "string" ? formatDateTime(item.createdAt) : "";
|
|
815
|
+
deps.stdout(
|
|
816
|
+
`${item.id ?? ""} rev ${item.revision ?? "?"} ${created}
|
|
817
|
+
`
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
if (page?.hasMore && page.nextCursor) {
|
|
734
821
|
deps.stdout(
|
|
735
|
-
`${
|
|
822
|
+
`${hint(`More deployments: dropthis deployments list ${dropId} --cursor ${page.nextCursor}`)}
|
|
736
823
|
`
|
|
737
824
|
);
|
|
738
825
|
}
|
|
@@ -740,7 +827,11 @@ async function runDeploymentsList(dropId, input, deps) {
|
|
|
740
827
|
writeJson(deps, { ok: true, ...spread });
|
|
741
828
|
}
|
|
742
829
|
} else {
|
|
743
|
-
writeJson(deps, {
|
|
830
|
+
writeJson(deps, {
|
|
831
|
+
ok: true,
|
|
832
|
+
...spread,
|
|
833
|
+
...page ? { next_cursor: page.nextCursor, has_more: page.hasMore } : {}
|
|
834
|
+
});
|
|
744
835
|
}
|
|
745
836
|
return { exitCode: 0 };
|
|
746
837
|
}
|
|
@@ -763,7 +854,8 @@ async function runDeploymentsGet(dropId, deploymentId, _input, deps) {
|
|
|
763
854
|
if (data.id) pairs.push(["ID", String(data.id)]);
|
|
764
855
|
if (data.revision !== void 0)
|
|
765
856
|
pairs.push(["Revision", String(data.revision)]);
|
|
766
|
-
if (data.createdAt)
|
|
857
|
+
if (data.createdAt)
|
|
858
|
+
pairs.push(["Created", formatDateTime(String(data.createdAt))]);
|
|
767
859
|
writeKv(deps, pairs, { ok: true, deployment: result.data });
|
|
768
860
|
return { exitCode: 0 };
|
|
769
861
|
}
|
|
@@ -781,21 +873,386 @@ async function runDoctor(_input, deps) {
|
|
|
781
873
|
const authSource = credential?.source ?? "missing";
|
|
782
874
|
const storageBackend = stored?.storage ?? "none";
|
|
783
875
|
const pairs = [
|
|
784
|
-
["Version", "0.
|
|
876
|
+
["Version", "0.12.0"],
|
|
785
877
|
["Auth", authSource],
|
|
786
878
|
["Storage", storageBackend]
|
|
787
879
|
];
|
|
788
880
|
writeKv(deps, pairs, {
|
|
789
881
|
ok: true,
|
|
790
|
-
version: "0.
|
|
882
|
+
version: "0.12.0",
|
|
791
883
|
auth: { source: authSource },
|
|
792
884
|
storage: { backend: storageBackend }
|
|
793
885
|
});
|
|
794
886
|
return { exitCode: 0 };
|
|
795
887
|
}
|
|
796
888
|
|
|
797
|
-
// src/commands/
|
|
889
|
+
// src/commands/domains.ts
|
|
798
890
|
var prompts2 = __toESM(require("@clack/prompts"), 1);
|
|
891
|
+
var import_picocolors3 = __toESM(require("picocolors"), 1);
|
|
892
|
+
function formatDnsTable(records) {
|
|
893
|
+
if (records.length === 0) return "";
|
|
894
|
+
const rows = [];
|
|
895
|
+
const colWidths = {
|
|
896
|
+
type: Math.max(4, ...records.map((r) => r.type.length)),
|
|
897
|
+
name: Math.max(4, ...records.map((r) => r.name.length)),
|
|
898
|
+
value: Math.max(5, ...records.map((r) => r.value.length)),
|
|
899
|
+
status: Math.max(6, ...records.map((r) => r.status.length))
|
|
900
|
+
};
|
|
901
|
+
const header = [
|
|
902
|
+
"Type".padEnd(colWidths.type),
|
|
903
|
+
"Name".padEnd(colWidths.name),
|
|
904
|
+
"Value".padEnd(colWidths.value),
|
|
905
|
+
"Status".padEnd(colWidths.status)
|
|
906
|
+
].join(" ");
|
|
907
|
+
rows.push(import_picocolors3.default.dim(header));
|
|
908
|
+
rows.push(import_picocolors3.default.dim("\u2500".repeat(header.length)));
|
|
909
|
+
for (const rec of records) {
|
|
910
|
+
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));
|
|
911
|
+
rows.push(
|
|
912
|
+
[
|
|
913
|
+
rec.type.padEnd(colWidths.type),
|
|
914
|
+
rec.name.padEnd(colWidths.name),
|
|
915
|
+
rec.value.padEnd(colWidths.value),
|
|
916
|
+
statusColor
|
|
917
|
+
].join(" ")
|
|
918
|
+
);
|
|
919
|
+
if (rec.hint) {
|
|
920
|
+
rows.push(` ${import_picocolors3.default.dim(rec.hint)}`);
|
|
921
|
+
}
|
|
922
|
+
if (rec.observed) {
|
|
923
|
+
rows.push(` ${import_picocolors3.default.dim(`Observed: ${rec.observed}`)}`);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
return rows.join("\n");
|
|
927
|
+
}
|
|
928
|
+
function renderNextHint(h, hostname, maxRetryAfter) {
|
|
929
|
+
if (h.action === "verify") {
|
|
930
|
+
const recheck = maxRetryAfter > 0 ? ` (re-checks every ${maxRetryAfter}s)` : "";
|
|
931
|
+
return `Run: dropthis domains verify ${hostname} --wait${recheck}`;
|
|
932
|
+
}
|
|
933
|
+
if (h.action === "publish") {
|
|
934
|
+
return `Run: dropthis publish <file> --domain ${hostname}`;
|
|
935
|
+
}
|
|
936
|
+
return h.message;
|
|
937
|
+
}
|
|
938
|
+
function duplicatesRecordHint(h, dns) {
|
|
939
|
+
if (h.action !== "dns") return false;
|
|
940
|
+
return dns.some(
|
|
941
|
+
(r) => r.hint && h.message.includes(r.name) && h.message.includes(r.value)
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
function printNextHints(deps, hints, hostname, dns) {
|
|
945
|
+
const lines = hints.filter((h) => !duplicatesRecordHint(h, dns));
|
|
946
|
+
if (lines.length === 0) return;
|
|
947
|
+
const maxRetryAfter = dns.reduce(
|
|
948
|
+
(max, r) => Math.max(max, r.retryAfter ?? 0),
|
|
949
|
+
0
|
|
950
|
+
);
|
|
951
|
+
deps.stdout("\n");
|
|
952
|
+
for (const h of lines) {
|
|
953
|
+
deps.stdout(`${hint(renderNextHint(h, hostname, maxRetryAfter))}
|
|
954
|
+
`);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
function computeSleepMs(records, elapsedMs, timeoutMs) {
|
|
958
|
+
const maxRetryAfter = records.reduce(
|
|
959
|
+
(max, r) => Math.max(max, r.retryAfter ?? 0),
|
|
960
|
+
0
|
|
961
|
+
);
|
|
962
|
+
const defaultSeconds = maxRetryAfter > 0 ? maxRetryAfter : 15;
|
|
963
|
+
const desiredMs = defaultSeconds * 1e3;
|
|
964
|
+
const remainingMs = timeoutMs - elapsedMs;
|
|
965
|
+
return Math.min(desiredMs, Math.max(0, remainingMs));
|
|
966
|
+
}
|
|
967
|
+
async function runDomainsConnect(input, deps) {
|
|
968
|
+
try {
|
|
969
|
+
await requireCredential({
|
|
970
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
971
|
+
env: deps.env,
|
|
972
|
+
store: deps.store
|
|
973
|
+
});
|
|
974
|
+
} catch {
|
|
975
|
+
return writeAuthError(deps);
|
|
976
|
+
}
|
|
977
|
+
const result = await deps.client.domains.connect(input);
|
|
978
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
979
|
+
const domain = result.data;
|
|
980
|
+
if (deps.outputMode === "human") {
|
|
981
|
+
deps.stdout(
|
|
982
|
+
`${success(`Connected ${domain.hostname} (${domain.mode} mode)`)}
|
|
983
|
+
`
|
|
984
|
+
);
|
|
985
|
+
if (domain.dns.length > 0) {
|
|
986
|
+
deps.stdout("\nDNS records to create at your provider:\n\n");
|
|
987
|
+
deps.stdout(`${formatDnsTable(domain.dns)}
|
|
988
|
+
`);
|
|
989
|
+
}
|
|
990
|
+
printNextHints(deps, domain.next, domain.hostname, domain.dns);
|
|
991
|
+
} else {
|
|
992
|
+
writeJson(deps, { ok: true, domain });
|
|
993
|
+
}
|
|
994
|
+
return { exitCode: 0 };
|
|
995
|
+
}
|
|
996
|
+
async function runDomainsList(_input, deps) {
|
|
997
|
+
try {
|
|
998
|
+
await requireCredential({
|
|
999
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
1000
|
+
env: deps.env,
|
|
1001
|
+
store: deps.store
|
|
1002
|
+
});
|
|
1003
|
+
} catch {
|
|
1004
|
+
return writeAuthError(deps);
|
|
1005
|
+
}
|
|
1006
|
+
const result = await deps.client.domains.list();
|
|
1007
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
1008
|
+
const domains = result.data?.domains ?? [];
|
|
1009
|
+
if (deps.outputMode === "human") {
|
|
1010
|
+
if (domains.length === 0) {
|
|
1011
|
+
writeEmpty(deps, "No domains connected yet.", { ok: true, domains: [] });
|
|
1012
|
+
} else {
|
|
1013
|
+
for (const d of domains) {
|
|
1014
|
+
const defaultMark = d.default ? import_picocolors3.default.green(" (default)") : "";
|
|
1015
|
+
const drop = d.dropId ? import_picocolors3.default.dim(` \u2192 ${d.dropId}`) : "";
|
|
1016
|
+
deps.stdout(
|
|
1017
|
+
` ${d.hostname}${defaultMark} ${import_picocolors3.default.dim(d.mode)} ${import_picocolors3.default.dim(d.status)}${drop}
|
|
1018
|
+
`
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
} else {
|
|
1023
|
+
writeJson(deps, { ok: true, domains });
|
|
1024
|
+
}
|
|
1025
|
+
return { exitCode: 0 };
|
|
1026
|
+
}
|
|
1027
|
+
async function runDomainsStatus(idOrHostname, _input, deps) {
|
|
1028
|
+
try {
|
|
1029
|
+
await requireCredential({
|
|
1030
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
1031
|
+
env: deps.env,
|
|
1032
|
+
store: deps.store
|
|
1033
|
+
});
|
|
1034
|
+
} catch {
|
|
1035
|
+
return writeAuthError(deps);
|
|
1036
|
+
}
|
|
1037
|
+
const result = await deps.client.domains.get(idOrHostname);
|
|
1038
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
1039
|
+
const domain = result.data;
|
|
1040
|
+
if (deps.outputMode === "human") {
|
|
1041
|
+
deps.stdout(` ${import_picocolors3.default.dim("Hostname:")} ${domain.hostname}
|
|
1042
|
+
`);
|
|
1043
|
+
deps.stdout(` ${import_picocolors3.default.dim("Mode: ")} ${domain.mode}
|
|
1044
|
+
`);
|
|
1045
|
+
deps.stdout(` ${import_picocolors3.default.dim("Status: ")} ${domain.status}
|
|
1046
|
+
`);
|
|
1047
|
+
if (domain.failureReason) {
|
|
1048
|
+
deps.stdout(
|
|
1049
|
+
` ${import_picocolors3.default.dim("Reason: ")} ${import_picocolors3.default.red(domain.failureReason)}
|
|
1050
|
+
`
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
1053
|
+
if (domain.dropId) {
|
|
1054
|
+
deps.stdout(` ${import_picocolors3.default.dim("Drop: ")} ${domain.dropId}
|
|
1055
|
+
`);
|
|
1056
|
+
}
|
|
1057
|
+
if (domain.verifiedAt) {
|
|
1058
|
+
deps.stdout(
|
|
1059
|
+
` ${import_picocolors3.default.dim("Verified:")} ${formatDate(domain.verifiedAt)}
|
|
1060
|
+
`
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
deps.stdout(` ${import_picocolors3.default.dim("Created: ")} ${formatDate(domain.createdAt)}
|
|
1064
|
+
`);
|
|
1065
|
+
if (domain.dns.length > 0) {
|
|
1066
|
+
deps.stdout("\nDNS records:\n\n");
|
|
1067
|
+
deps.stdout(`${formatDnsTable(domain.dns)}
|
|
1068
|
+
`);
|
|
1069
|
+
}
|
|
1070
|
+
printNextHints(deps, domain.next, domain.hostname, domain.dns);
|
|
1071
|
+
} else {
|
|
1072
|
+
writeJson(deps, { ok: true, domain });
|
|
1073
|
+
}
|
|
1074
|
+
return { exitCode: 0 };
|
|
1075
|
+
}
|
|
1076
|
+
var defaultSleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1077
|
+
async function runDomainsVerify(idOrHostname, input, deps, sleep = defaultSleep) {
|
|
1078
|
+
try {
|
|
1079
|
+
await requireCredential({
|
|
1080
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
1081
|
+
env: deps.env,
|
|
1082
|
+
store: deps.store
|
|
1083
|
+
});
|
|
1084
|
+
} catch {
|
|
1085
|
+
return writeAuthError(deps);
|
|
1086
|
+
}
|
|
1087
|
+
const timeoutMs = (input.timeout ?? 300) * 1e3;
|
|
1088
|
+
const doVerify = async (elapsedMs) => {
|
|
1089
|
+
const result = await deps.client.domains.verify(idOrHostname);
|
|
1090
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
1091
|
+
const domain = result.data;
|
|
1092
|
+
if (!input.wait) {
|
|
1093
|
+
if (deps.outputMode === "human") {
|
|
1094
|
+
deps.stdout(
|
|
1095
|
+
`${domain.status === "live" ? success(`${idOrHostname} is live`) : warn(`${idOrHostname}: ${domain.status}`)}
|
|
1096
|
+
`
|
|
1097
|
+
);
|
|
1098
|
+
if (domain.dns.length > 0) {
|
|
1099
|
+
deps.stdout("\n");
|
|
1100
|
+
deps.stdout(`${formatDnsTable(domain.dns)}
|
|
1101
|
+
`);
|
|
1102
|
+
}
|
|
1103
|
+
printNextHints(deps, domain.next, domain.hostname, domain.dns);
|
|
1104
|
+
} else {
|
|
1105
|
+
writeJson(deps, { ok: true, domain });
|
|
1106
|
+
}
|
|
1107
|
+
return {
|
|
1108
|
+
exitCode: domain.status === "live" ? 0 : domain.status === "failed" ? 1 : 6
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
if (domain.status === "live" || domain.status === "failed") {
|
|
1112
|
+
if (deps.outputMode === "human") {
|
|
1113
|
+
deps.stdout(
|
|
1114
|
+
`${domain.status === "live" ? success(`${idOrHostname} is live`) : warn(`${idOrHostname}: ${domain.status}`)}
|
|
1115
|
+
`
|
|
1116
|
+
);
|
|
1117
|
+
if (domain.dns.length > 0) {
|
|
1118
|
+
deps.stdout("\n");
|
|
1119
|
+
deps.stdout(`${formatDnsTable(domain.dns)}
|
|
1120
|
+
`);
|
|
1121
|
+
}
|
|
1122
|
+
} else {
|
|
1123
|
+
writeJson(deps, { ok: true, domain });
|
|
1124
|
+
}
|
|
1125
|
+
return { exitCode: domain.status === "live" ? 0 : 1 };
|
|
1126
|
+
}
|
|
1127
|
+
const sleepMs = computeSleepMs(domain.dns, elapsedMs, timeoutMs);
|
|
1128
|
+
const newElapsed = elapsedMs + sleepMs;
|
|
1129
|
+
if (newElapsed >= timeoutMs) {
|
|
1130
|
+
const timeoutSecs = input.timeout ?? 300;
|
|
1131
|
+
const message = `Timed out waiting for ${idOrHostname} to go live after ${timeoutSecs}s`;
|
|
1132
|
+
if (deps.outputMode === "human") {
|
|
1133
|
+
deps.stderr(
|
|
1134
|
+
` ${import_picocolors3.default.red("Timed out waiting for")} ${idOrHostname} ${import_picocolors3.default.red("to go live")}
|
|
1135
|
+
`
|
|
1136
|
+
);
|
|
1137
|
+
} else {
|
|
1138
|
+
deps.stderr(
|
|
1139
|
+
`${JSON.stringify(errorEnvelope("verify_timeout", message))}
|
|
1140
|
+
`
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
return { exitCode: 7 };
|
|
1144
|
+
}
|
|
1145
|
+
if (deps.outputMode === "human" && domain.dns.length > 0) {
|
|
1146
|
+
deps.stdout(`${formatDnsTable(domain.dns)}
|
|
1147
|
+
`);
|
|
1148
|
+
}
|
|
1149
|
+
await sleep(sleepMs);
|
|
1150
|
+
return doVerify(newElapsed);
|
|
1151
|
+
};
|
|
1152
|
+
return doVerify(0);
|
|
1153
|
+
}
|
|
1154
|
+
async function runDomainsUpdate(idOrHostname, input, deps) {
|
|
1155
|
+
if (input.drop === void 0 && input.setDefault === void 0) {
|
|
1156
|
+
return writeError(
|
|
1157
|
+
deps,
|
|
1158
|
+
"invalid_usage",
|
|
1159
|
+
"Provide at least one option: --drop <dropId> or --default"
|
|
1160
|
+
);
|
|
1161
|
+
}
|
|
1162
|
+
try {
|
|
1163
|
+
await requireCredential({
|
|
1164
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
1165
|
+
env: deps.env,
|
|
1166
|
+
store: deps.store
|
|
1167
|
+
});
|
|
1168
|
+
} catch {
|
|
1169
|
+
return writeAuthError(deps);
|
|
1170
|
+
}
|
|
1171
|
+
const updateInput = {};
|
|
1172
|
+
if (input.drop !== void 0) updateInput.dropId = input.drop;
|
|
1173
|
+
if (input.setDefault !== void 0) updateInput.default = input.setDefault;
|
|
1174
|
+
const result = await deps.client.domains.update(idOrHostname, updateInput);
|
|
1175
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
1176
|
+
const domain = result.data;
|
|
1177
|
+
writeHumanOrJson(deps, `${success(`Updated ${domain.hostname}`)}
|
|
1178
|
+
`, {
|
|
1179
|
+
ok: true,
|
|
1180
|
+
domain
|
|
1181
|
+
});
|
|
1182
|
+
return { exitCode: 0 };
|
|
1183
|
+
}
|
|
1184
|
+
async function runDomainsRemove(idOrHostname, input, deps) {
|
|
1185
|
+
if (!input.yes && input.interactive === false) {
|
|
1186
|
+
return writeError(
|
|
1187
|
+
deps,
|
|
1188
|
+
"invalid_usage",
|
|
1189
|
+
"Pass --yes to remove the domain in non-interactive mode."
|
|
1190
|
+
);
|
|
1191
|
+
}
|
|
1192
|
+
if (!input.yes && input.interactive !== false) {
|
|
1193
|
+
const confirmed = await prompts2.confirm({
|
|
1194
|
+
message: `Remove ${idOrHostname}? This removes the domain and unmounts its drops.`
|
|
1195
|
+
});
|
|
1196
|
+
if (prompts2.isCancel(confirmed) || !confirmed) {
|
|
1197
|
+
return { exitCode: 0 };
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
try {
|
|
1201
|
+
await requireCredential({
|
|
1202
|
+
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
1203
|
+
env: deps.env,
|
|
1204
|
+
store: deps.store
|
|
1205
|
+
});
|
|
1206
|
+
} catch {
|
|
1207
|
+
return writeAuthError(deps);
|
|
1208
|
+
}
|
|
1209
|
+
const result = await deps.client.domains.delete(idOrHostname);
|
|
1210
|
+
if (result.error) return writeApiError(deps, result.error);
|
|
1211
|
+
const deleted = result.data;
|
|
1212
|
+
if (deps.outputMode === "human") {
|
|
1213
|
+
deps.stdout(`${success(`Removed ${deleted.hostname}`)}
|
|
1214
|
+
`);
|
|
1215
|
+
if (deleted.warning) {
|
|
1216
|
+
deps.stderr(`${warn(deleted.warning)}
|
|
1217
|
+
`);
|
|
1218
|
+
}
|
|
1219
|
+
} else {
|
|
1220
|
+
writeJson(deps, {
|
|
1221
|
+
ok: true,
|
|
1222
|
+
deleted: true,
|
|
1223
|
+
id: deleted.id,
|
|
1224
|
+
hostname: deleted.hostname,
|
|
1225
|
+
warning: deleted.warning
|
|
1226
|
+
});
|
|
1227
|
+
}
|
|
1228
|
+
return { exitCode: 0 };
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
// src/commands/drops.ts
|
|
1232
|
+
var prompts3 = __toESM(require("@clack/prompts"), 1);
|
|
1233
|
+
var import_picocolors4 = __toESM(require("picocolors"), 1);
|
|
1234
|
+
async function resolveDropTarget(target, deps) {
|
|
1235
|
+
if (target.startsWith("drop_")) return { ok: true, dropId: target };
|
|
1236
|
+
const resolved = await deps.client.drops.resolve(target);
|
|
1237
|
+
if (resolved.error) {
|
|
1238
|
+
return { ok: false, ...writeApiError(deps, resolved.error) };
|
|
1239
|
+
}
|
|
1240
|
+
if (resolved.data === null) {
|
|
1241
|
+
return {
|
|
1242
|
+
ok: false,
|
|
1243
|
+
...writeApiError(deps, {
|
|
1244
|
+
code: "not_found",
|
|
1245
|
+
message: `No drop matching "${target}" found in your account.`,
|
|
1246
|
+
suggestion: "It may belong to another account or have been deleted. Run dropthis list to see your drops, or pass the full drop_\u2026 id."
|
|
1247
|
+
})
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
return {
|
|
1251
|
+
ok: true,
|
|
1252
|
+
dropId: resolved.data.id,
|
|
1253
|
+
...resolved.data.slug ? { slug: resolved.data.slug } : {}
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
799
1256
|
async function runDropsList(input, deps) {
|
|
800
1257
|
try {
|
|
801
1258
|
await requireCredential({
|
|
@@ -813,24 +1270,40 @@ async function runDropsList(input, deps) {
|
|
|
813
1270
|
const result = await deps.client.drops.list(params);
|
|
814
1271
|
if (result.error) return writeApiError(deps, result.error);
|
|
815
1272
|
const raw = unwrapListData(result.data, "drops");
|
|
1273
|
+
const page = extractPagination(result.data);
|
|
816
1274
|
const items = Array.isArray(raw) ? raw : void 0;
|
|
817
1275
|
if (deps.outputMode === "human") {
|
|
818
1276
|
if (!items || items.length === 0) {
|
|
819
1277
|
writeEmpty(deps, "No drops found.", { ok: true, drops: [] });
|
|
820
1278
|
} else {
|
|
821
1279
|
for (const item of items) {
|
|
1280
|
+
const created = typeof item.createdAt === "string" ? import_picocolors4.default.dim(formatDate(item.createdAt)) : "";
|
|
822
1281
|
deps.stdout(
|
|
823
|
-
`${item.id ?? ""} ${item.title ?? ""} ${item.url ? url(String(item.url)) : ""}
|
|
1282
|
+
`${item.id ?? ""} ${created} ${item.title ?? ""} ${item.url ? url(String(item.url)) : ""}
|
|
1283
|
+
`
|
|
1284
|
+
);
|
|
1285
|
+
}
|
|
1286
|
+
deps.stdout(
|
|
1287
|
+
`${import_picocolors4.default.dim(`${items.length} ${items.length === 1 ? "drop" : "drops"}`)}
|
|
1288
|
+
`
|
|
1289
|
+
);
|
|
1290
|
+
if (page?.hasMore && page.nextCursor) {
|
|
1291
|
+
deps.stdout(
|
|
1292
|
+
`${hint(`More drops: dropthis list --cursor ${page.nextCursor}`)}
|
|
824
1293
|
`
|
|
825
1294
|
);
|
|
826
1295
|
}
|
|
827
1296
|
}
|
|
828
1297
|
} else {
|
|
829
|
-
writeJson(deps, {
|
|
1298
|
+
writeJson(deps, {
|
|
1299
|
+
ok: true,
|
|
1300
|
+
drops: items ?? raw,
|
|
1301
|
+
...page ? { next_cursor: page.nextCursor, has_more: page.hasMore } : {}
|
|
1302
|
+
});
|
|
830
1303
|
}
|
|
831
1304
|
return { exitCode: 0 };
|
|
832
1305
|
}
|
|
833
|
-
async function runDropsGet(
|
|
1306
|
+
async function runDropsGet(target, _input, deps) {
|
|
834
1307
|
try {
|
|
835
1308
|
await requireCredential({
|
|
836
1309
|
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
@@ -840,7 +1313,9 @@ async function runDropsGet(dropId, _input, deps) {
|
|
|
840
1313
|
} catch {
|
|
841
1314
|
return writeAuthError(deps);
|
|
842
1315
|
}
|
|
843
|
-
const
|
|
1316
|
+
const resolved = await resolveDropTarget(target, deps);
|
|
1317
|
+
if (!resolved.ok) return { exitCode: resolved.exitCode };
|
|
1318
|
+
const result = await deps.client.drops.get(resolved.dropId);
|
|
844
1319
|
if (result.error) return writeApiError(deps, result.error);
|
|
845
1320
|
const data = result.data;
|
|
846
1321
|
const pairs = [];
|
|
@@ -850,7 +1325,8 @@ async function runDropsGet(dropId, _input, deps) {
|
|
|
850
1325
|
if (data.visibility) pairs.push(["Visibility", String(data.visibility)]);
|
|
851
1326
|
if (data.revision !== void 0)
|
|
852
1327
|
pairs.push(["Revision", String(data.revision)]);
|
|
853
|
-
if (data.createdAt)
|
|
1328
|
+
if (data.createdAt)
|
|
1329
|
+
pairs.push(["Created", formatDate(String(data.createdAt))]);
|
|
854
1330
|
if (data.accessible !== void 0)
|
|
855
1331
|
pairs.push(["Accessible", String(data.accessible)]);
|
|
856
1332
|
if (data.persistent !== void 0)
|
|
@@ -860,7 +1336,7 @@ async function runDropsGet(dropId, _input, deps) {
|
|
|
860
1336
|
writeKv(deps, pairs, { ok: true, drop: result.data });
|
|
861
1337
|
return { exitCode: 0 };
|
|
862
1338
|
}
|
|
863
|
-
async function runDropsDelete(
|
|
1339
|
+
async function runDropsDelete(target, input, deps) {
|
|
864
1340
|
if (!input.yes && input.interactive === false) {
|
|
865
1341
|
return writeError(
|
|
866
1342
|
deps,
|
|
@@ -868,14 +1344,6 @@ async function runDropsDelete(dropId, input, deps) {
|
|
|
868
1344
|
"Pass --yes to delete in non-interactive mode."
|
|
869
1345
|
);
|
|
870
1346
|
}
|
|
871
|
-
if (!input.yes && input.interactive !== false) {
|
|
872
|
-
const confirmed = await prompts2.confirm({
|
|
873
|
-
message: `Delete ${dropId}?`
|
|
874
|
-
});
|
|
875
|
-
if (prompts2.isCancel(confirmed) || !confirmed) {
|
|
876
|
-
return { exitCode: 0 };
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
1347
|
try {
|
|
880
1348
|
await requireCredential({
|
|
881
1349
|
...deps.apiKey ? { apiKey: deps.apiKey } : {},
|
|
@@ -885,6 +1353,17 @@ async function runDropsDelete(dropId, input, deps) {
|
|
|
885
1353
|
} catch {
|
|
886
1354
|
return writeAuthError(deps);
|
|
887
1355
|
}
|
|
1356
|
+
const resolved = await resolveDropTarget(target, deps);
|
|
1357
|
+
if (!resolved.ok) return { exitCode: resolved.exitCode };
|
|
1358
|
+
const dropId = resolved.dropId;
|
|
1359
|
+
if (!input.yes && input.interactive !== false) {
|
|
1360
|
+
const confirmed = await prompts3.confirm({
|
|
1361
|
+
message: `Delete ${dropId}${dropId === target ? "" : ` (${target})`}?`
|
|
1362
|
+
});
|
|
1363
|
+
if (prompts3.isCancel(confirmed) || !confirmed) {
|
|
1364
|
+
return { exitCode: 0 };
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
888
1367
|
const result = await deps.client.drops.delete(dropId);
|
|
889
1368
|
if (result?.error) return writeApiError(deps, result.error);
|
|
890
1369
|
writeHumanOrJson(deps, success(`Deleted ${dropId}`), {
|
|
@@ -896,31 +1375,31 @@ async function runDropsDelete(dropId, input, deps) {
|
|
|
896
1375
|
}
|
|
897
1376
|
|
|
898
1377
|
// src/commands/login.ts
|
|
899
|
-
var
|
|
1378
|
+
var prompts4 = __toESM(require("@clack/prompts"), 1);
|
|
900
1379
|
async function runLoginInteractive(deps) {
|
|
901
|
-
|
|
902
|
-
const email = await
|
|
1380
|
+
prompts4.intro("dropthis login");
|
|
1381
|
+
const email = await prompts4.text({
|
|
903
1382
|
message: "Email address",
|
|
904
1383
|
validate: (v) => v?.includes("@") ? void 0 : "Enter a valid email"
|
|
905
1384
|
});
|
|
906
|
-
if (
|
|
907
|
-
|
|
1385
|
+
if (prompts4.isCancel(email)) {
|
|
1386
|
+
prompts4.cancel("Login cancelled.");
|
|
908
1387
|
return { exitCode: 0 };
|
|
909
1388
|
}
|
|
910
1389
|
const requestResult = await deps.client.auth.requestEmailOtp({ email });
|
|
911
1390
|
if (requestResult.error) {
|
|
912
|
-
|
|
1391
|
+
prompts4.cancel(requestResult.error.message);
|
|
913
1392
|
return { exitCode: exitCodeFor("api_error") };
|
|
914
1393
|
}
|
|
915
1394
|
const maxAttempts = 3;
|
|
916
1395
|
let session;
|
|
917
1396
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
918
|
-
const otp = await
|
|
1397
|
+
const otp = await prompts4.text({
|
|
919
1398
|
message: attempt === 1 ? "Paste the code from your email" : "Try again \u2014 paste the code from your email",
|
|
920
1399
|
validate: (v) => v && v.length >= 4 && v.length <= 8 ? void 0 : "Code must be 4\u20138 characters."
|
|
921
1400
|
});
|
|
922
|
-
if (
|
|
923
|
-
|
|
1401
|
+
if (prompts4.isCancel(otp)) {
|
|
1402
|
+
prompts4.cancel("Login cancelled.");
|
|
924
1403
|
return { exitCode: 0 };
|
|
925
1404
|
}
|
|
926
1405
|
const result = await deps.client.auth.verifyEmailOtp({
|
|
@@ -932,20 +1411,20 @@ async function runLoginInteractive(deps) {
|
|
|
932
1411
|
break;
|
|
933
1412
|
}
|
|
934
1413
|
if (attempt < maxAttempts) {
|
|
935
|
-
|
|
1414
|
+
prompts4.log.warning(result.error.message);
|
|
936
1415
|
} else {
|
|
937
|
-
|
|
1416
|
+
prompts4.cancel(result.error.message);
|
|
938
1417
|
return { exitCode: exitCodeFor("api_error") };
|
|
939
1418
|
}
|
|
940
1419
|
}
|
|
941
1420
|
if (!session) {
|
|
942
|
-
|
|
1421
|
+
prompts4.cancel("Login failed.");
|
|
943
1422
|
return { exitCode: exitCodeFor("api_error") };
|
|
944
1423
|
}
|
|
945
1424
|
const authedClient = deps.createClient(session.data.token);
|
|
946
1425
|
const apiKey = await authedClient.apiKeys.create({ label: "CLI" });
|
|
947
1426
|
if (apiKey.error) {
|
|
948
|
-
|
|
1427
|
+
prompts4.cancel(apiKey.error.message);
|
|
949
1428
|
return { exitCode: exitCodeFor("api_error") };
|
|
950
1429
|
}
|
|
951
1430
|
await deps.store.save({
|
|
@@ -956,7 +1435,7 @@ async function runLoginInteractive(deps) {
|
|
|
956
1435
|
email,
|
|
957
1436
|
storage: "secure"
|
|
958
1437
|
});
|
|
959
|
-
|
|
1438
|
+
prompts4.outro("Logged in successfully.");
|
|
960
1439
|
return { exitCode: 0 };
|
|
961
1440
|
}
|
|
962
1441
|
async function runLoginRequest(input, deps) {
|
|
@@ -1131,7 +1610,9 @@ async function parseDropOptions(raw) {
|
|
|
1131
1610
|
...raw.entry ? { entry: raw.entry } : {},
|
|
1132
1611
|
...raw.contentType ? { contentType: raw.contentType } : {},
|
|
1133
1612
|
...raw.path ? { path: raw.path } : {},
|
|
1134
|
-
...raw.idempotencyKey ? { idempotencyKey: raw.idempotencyKey } : {}
|
|
1613
|
+
...raw.idempotencyKey ? { idempotencyKey: raw.idempotencyKey } : {},
|
|
1614
|
+
...raw.domain ? { domain: raw.domain } : {},
|
|
1615
|
+
...raw.slug ? { slug: raw.slug } : {}
|
|
1135
1616
|
};
|
|
1136
1617
|
}
|
|
1137
1618
|
function parseJsonObject(value, label) {
|
|
@@ -1143,12 +1624,12 @@ function parseJsonObject(value, label) {
|
|
|
1143
1624
|
}
|
|
1144
1625
|
|
|
1145
1626
|
// src/spinner.ts
|
|
1146
|
-
var
|
|
1627
|
+
var import_picocolors5 = __toESM(require("picocolors"), 1);
|
|
1147
1628
|
var frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1148
1629
|
function createSpinner(message, stderr) {
|
|
1149
1630
|
let i = 0;
|
|
1150
1631
|
const timer = setInterval(() => {
|
|
1151
|
-
stderr(`\r\x1B[2K${
|
|
1632
|
+
stderr(`\r\x1B[2K${import_picocolors5.default.cyan(frames[i % frames.length])} ${message}`);
|
|
1152
1633
|
i++;
|
|
1153
1634
|
}, 80);
|
|
1154
1635
|
return {
|
|
@@ -1299,24 +1780,10 @@ async function runPull(target, input, deps) {
|
|
|
1299
1780
|
} catch {
|
|
1300
1781
|
return writeAuthError(deps);
|
|
1301
1782
|
}
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
defaultDirName = target;
|
|
1307
|
-
} else {
|
|
1308
|
-
const resolved = await deps.client.drops.resolve(target);
|
|
1309
|
-
if (resolved.error) return writeApiError(deps, resolved.error);
|
|
1310
|
-
if (resolved.data === null) {
|
|
1311
|
-
return writeApiError(deps, {
|
|
1312
|
-
code: "not_found",
|
|
1313
|
-
message: `No drop matching "${target}" found in your account.`,
|
|
1314
|
-
suggestion: "It may belong to another account or have been deleted. Run dropthis list to see your drops, or pass the full drop_\u2026 id."
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
dropId = resolved.data.id;
|
|
1318
|
-
defaultDirName = resolved.data.slug || resolved.data.id;
|
|
1319
|
-
}
|
|
1783
|
+
const resolved = await resolveDropTarget(target, deps);
|
|
1784
|
+
if (!resolved.ok) return { exitCode: resolved.exitCode };
|
|
1785
|
+
const dropId = resolved.dropId;
|
|
1786
|
+
const defaultDirName = resolved.slug || resolved.dropId;
|
|
1320
1787
|
const spin = shouldSpin(deps.outputMode) ? createSpinner("Pulling content\u2026", deps.stderr) : void 0;
|
|
1321
1788
|
const manifestResult = await deps.client.drops.getContent(dropId);
|
|
1322
1789
|
if (manifestResult.error) {
|
|
@@ -1499,7 +1966,7 @@ function assertDropId(target) {
|
|
|
1499
1966
|
}
|
|
1500
1967
|
|
|
1501
1968
|
// src/commands/update-settings.ts
|
|
1502
|
-
var
|
|
1969
|
+
var prompts5 = __toESM(require("@clack/prompts"), 1);
|
|
1503
1970
|
var NO_SETTINGS_MESSAGE = "Nothing to update. Provide at least one settings option.";
|
|
1504
1971
|
var NO_SETTINGS_NEXT_ACTION = "Run dropthis update-settings --help, or retry with one of: --title, --visibility, --password, --no-password, --noindex, --index, --expires-at, --metadata, or --metadata-file. To replace the content at the URL instead, use dropthis update-content <dropId> ./dist.";
|
|
1505
1972
|
async function runUpdateSettings(dropId, raw, deps) {
|
|
@@ -1523,7 +1990,7 @@ async function runUpdateSettings(dropId, raw, deps) {
|
|
|
1523
1990
|
if (shouldPrompt(deps)) {
|
|
1524
1991
|
const prompted = await promptForSettings(
|
|
1525
1992
|
dropId,
|
|
1526
|
-
deps.prompts ??
|
|
1993
|
+
deps.prompts ?? prompts5
|
|
1527
1994
|
);
|
|
1528
1995
|
if (!prompted) return { exitCode: 0 };
|
|
1529
1996
|
parsed = { ...parsed, ...prompted };
|
|
@@ -1912,6 +2379,55 @@ async function writeCredentialFile(path, credential) {
|
|
|
1912
2379
|
await (0, import_promises3.rename)(tmpPath, path);
|
|
1913
2380
|
}
|
|
1914
2381
|
|
|
2382
|
+
// src/typo-guard.ts
|
|
2383
|
+
var import_promises4 = require("fs/promises");
|
|
2384
|
+
function levenshtein(a, b) {
|
|
2385
|
+
if (a === b) return 0;
|
|
2386
|
+
if (a.length === 0) return b.length;
|
|
2387
|
+
if (b.length === 0) return a.length;
|
|
2388
|
+
let prev = Array.from({ length: b.length + 1 }, (_, j) => j);
|
|
2389
|
+
for (let i = 1; i <= a.length; i++) {
|
|
2390
|
+
const curr = [i];
|
|
2391
|
+
for (let j = 1; j <= b.length; j++) {
|
|
2392
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
2393
|
+
const deletion = (prev[j] ?? 0) + 1;
|
|
2394
|
+
const insertion = (curr[j - 1] ?? 0) + 1;
|
|
2395
|
+
const substitution = (prev[j - 1] ?? 0) + cost;
|
|
2396
|
+
curr[j] = Math.min(deletion, insertion, substitution);
|
|
2397
|
+
}
|
|
2398
|
+
prev = curr;
|
|
2399
|
+
}
|
|
2400
|
+
return prev[b.length] ?? 0;
|
|
2401
|
+
}
|
|
2402
|
+
function suggestCommand(token, names) {
|
|
2403
|
+
const lower = token.toLowerCase();
|
|
2404
|
+
let best = null;
|
|
2405
|
+
for (const name of names) {
|
|
2406
|
+
if (lower.length >= 2 && name.startsWith(lower)) return name;
|
|
2407
|
+
const dist = levenshtein(lower, name);
|
|
2408
|
+
if (best === null || dist < best.dist) best = { name, dist };
|
|
2409
|
+
}
|
|
2410
|
+
if (best !== null && best.dist <= 2 && best.dist < lower.length) {
|
|
2411
|
+
return best.name;
|
|
2412
|
+
}
|
|
2413
|
+
return null;
|
|
2414
|
+
}
|
|
2415
|
+
function isBareWordToken(token) {
|
|
2416
|
+
if (token === "" || token === "-") return false;
|
|
2417
|
+
if (/\s/.test(token)) return false;
|
|
2418
|
+
if (token.includes("/") || token.includes("\\")) return false;
|
|
2419
|
+
if (token.includes(".")) return false;
|
|
2420
|
+
return true;
|
|
2421
|
+
}
|
|
2422
|
+
async function pathExists(path) {
|
|
2423
|
+
try {
|
|
2424
|
+
await (0, import_promises4.stat)(path);
|
|
2425
|
+
return true;
|
|
2426
|
+
} catch {
|
|
2427
|
+
return false;
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
|
|
1915
2431
|
// src/program.ts
|
|
1916
2432
|
function buildProgram(options = {}) {
|
|
1917
2433
|
const program = new import_commander.Command();
|
|
@@ -1922,6 +2438,7 @@ function buildProgram(options = {}) {
|
|
|
1922
2438
|
return argv.includes("--json") || argv.includes("--quiet") || argv.includes("-q") || options.env?.CI === "true" || options.env === void 0 && process.env.CI === "true" || options.stdoutIsTTY === false || options.stdoutIsTTY === void 0 && process.stdout.isTTY !== true;
|
|
1923
2439
|
};
|
|
1924
2440
|
program.exitOverride();
|
|
2441
|
+
program.showSuggestionAfterError();
|
|
1925
2442
|
program.configureOutput({
|
|
1926
2443
|
writeErr,
|
|
1927
2444
|
// In JSON mode, suppress commander's default plain-text error so the
|
|
@@ -1932,13 +2449,13 @@ function buildProgram(options = {}) {
|
|
|
1932
2449
|
});
|
|
1933
2450
|
program.name("dropthis").description(
|
|
1934
2451
|
[
|
|
1935
|
-
|
|
2452
|
+
import_picocolors6.default.dim("Publish anything online and get a URL back."),
|
|
1936
2453
|
"",
|
|
1937
|
-
`${
|
|
1938
|
-
` ${
|
|
1939
|
-
` ${
|
|
2454
|
+
`${import_picocolors6.default.bold("Quick start:")}`,
|
|
2455
|
+
` ${import_picocolors6.default.cyan("dropthis login")}`,
|
|
2456
|
+
` ${import_picocolors6.default.cyan("dropthis publish ./dist")}`
|
|
1940
2457
|
].join("\n")
|
|
1941
|
-
).version("0.
|
|
2458
|
+
).version("0.12.0").configureHelp({
|
|
1942
2459
|
subcommandTerm(cmd) {
|
|
1943
2460
|
const args = cmd.registeredArguments.map((a) => {
|
|
1944
2461
|
const name = a.name();
|
|
@@ -1947,16 +2464,28 @@ function buildProgram(options = {}) {
|
|
|
1947
2464
|
}).join(" ");
|
|
1948
2465
|
return args ? `${cmd.name()} ${args}` : cmd.name();
|
|
1949
2466
|
},
|
|
1950
|
-
styleTitle: (title) =>
|
|
1951
|
-
styleCommandText: (str) =>
|
|
1952
|
-
styleSubcommandText: (str) =>
|
|
1953
|
-
styleOptionText: (str) =>
|
|
2467
|
+
styleTitle: (title) => import_picocolors6.default.bold(title),
|
|
2468
|
+
styleCommandText: (str) => import_picocolors6.default.cyan(str),
|
|
2469
|
+
styleSubcommandText: (str) => import_picocolors6.default.cyan(str),
|
|
2470
|
+
styleOptionText: (str) => import_picocolors6.default.yellow(str)
|
|
1954
2471
|
});
|
|
1955
2472
|
program.option("--api-key <key>", "Override API key for this invocation");
|
|
1956
2473
|
program.option("--api-url <url>", "Override API base URL");
|
|
1957
2474
|
program.option("--json", "Force JSON output");
|
|
1958
2475
|
program.option("-q, --quiet", "Suppress status output and imply JSON");
|
|
1959
2476
|
program.option("--no-interactive", "Disable interactive prompts");
|
|
2477
|
+
program.addHelpText(
|
|
2478
|
+
"after",
|
|
2479
|
+
[
|
|
2480
|
+
"",
|
|
2481
|
+
"Output is JSON when piped/CI/--json; human tables in a terminal.",
|
|
2482
|
+
"Docs: https://dropthis.app"
|
|
2483
|
+
].join("\n")
|
|
2484
|
+
);
|
|
2485
|
+
const examplesBlock = (lines) => `
|
|
2486
|
+
${import_picocolors6.default.bold("Examples:")}
|
|
2487
|
+
${lines.map((l) => ` ${l}`).join("\n")}
|
|
2488
|
+
`;
|
|
1960
2489
|
program.command("publish [input...]", { isDefault: true }).description(
|
|
1961
2490
|
"Publish content to a permanent public URL (also: share, post, put online, make public, get a link).\nFiles, folders, URLs, strings, or stdin; multiple files bundle into one drop. Use - for stdin, or pipe without args.\nCreates a NEW drop each run \u2014 to change one you already published, use update-content (the files) or update-settings (title/visibility/password/expiry/metadata) with its drop_\u2026 id, not publish again."
|
|
1962
2491
|
).option("--title <title>", "Drop title").option("--visibility <v>", "public or unlisted (default: public)").option("--password <password>", "Require password to view").option("--noindex", "Prevent search-engine indexing").option("--expires-at <datetime>", "Auto-delete after this ISO 8601 date").option(
|
|
@@ -1968,12 +2497,27 @@ function buildProgram(options = {}) {
|
|
|
1968
2497
|
).option(
|
|
1969
2498
|
"--metadata <json>",
|
|
1970
2499
|
`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(
|
|
2500
|
+
).option("--metadata-file <path>", "Read metadata JSON from a file").option("--path <name>", "Set filename when publishing from stdin").option(
|
|
2501
|
+
"--domain <hostname>",
|
|
2502
|
+
"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."
|
|
2503
|
+
).option(
|
|
2504
|
+
"--slug <vanity-slug>",
|
|
2505
|
+
"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."
|
|
2506
|
+
).option("--url", "Print only the published URL (no JSON envelope)").option(
|
|
1972
2507
|
"--dry-run",
|
|
1973
2508
|
"Show what would be published without publishing (JSON; cannot combine with --url)"
|
|
1974
2509
|
).option("--json", "Force JSON output").option(
|
|
1975
2510
|
"--idempotency-key <key>",
|
|
1976
2511
|
"Prevent duplicate publishes on retry (auto-generated)"
|
|
2512
|
+
).addHelpText(
|
|
2513
|
+
"after",
|
|
2514
|
+
examplesBlock([
|
|
2515
|
+
"dropthis publish ./report.html",
|
|
2516
|
+
"dropthis publish ./dist --title 'Launch page'",
|
|
2517
|
+
"cat report.md | dropthis publish - --content-type text/markdown --path report.md",
|
|
2518
|
+
"dropthis publish ./dist --domain reports.example.com --slug launch",
|
|
2519
|
+
"URL=$(dropthis publish ./dist --url)"
|
|
2520
|
+
])
|
|
1977
2521
|
).action(async (inputs, commandOptions) => {
|
|
1978
2522
|
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
1979
2523
|
if (inputs.length === 0 && stdinIsTTY) {
|
|
@@ -1999,6 +2543,29 @@ function buildProgram(options = {}) {
|
|
|
1999
2543
|
process.exitCode = writeError(deps, "local_input_error", msg).exitCode;
|
|
2000
2544
|
return;
|
|
2001
2545
|
}
|
|
2546
|
+
if (deps.outputMode === "human" && deps.interactive && inputs.length === 1 && typeof publishInput === "string" && isBareWordToken(publishInput) && !await pathExists(publishInput)) {
|
|
2547
|
+
const suggestion = suggestCommand(
|
|
2548
|
+
publishInput,
|
|
2549
|
+
program.commands.map((c) => c.name())
|
|
2550
|
+
);
|
|
2551
|
+
if (suggestion) {
|
|
2552
|
+
process.exitCode = writeError(
|
|
2553
|
+
deps,
|
|
2554
|
+
"invalid_usage",
|
|
2555
|
+
`Unknown command '${publishInput}' \u2014 did you mean '${suggestion}'?`,
|
|
2556
|
+
`To publish the literal text, pipe it: echo '${publishInput}' | dropthis publish`
|
|
2557
|
+
).exitCode;
|
|
2558
|
+
return;
|
|
2559
|
+
}
|
|
2560
|
+
const prompts6 = await import("@clack/prompts");
|
|
2561
|
+
const confirmed = await prompts6.confirm({
|
|
2562
|
+
message: `Publish '${publishInput}' as inline text?`,
|
|
2563
|
+
initialValue: false
|
|
2564
|
+
});
|
|
2565
|
+
if (prompts6.isCancel(confirmed) || !confirmed) {
|
|
2566
|
+
return;
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2002
2569
|
let dropOpts;
|
|
2003
2570
|
try {
|
|
2004
2571
|
dropOpts = toDropOptions(commandOptions);
|
|
@@ -2102,7 +2669,14 @@ function buildProgram(options = {}) {
|
|
|
2102
2669
|
);
|
|
2103
2670
|
program.command("pull <target>").description(
|
|
2104
2671
|
"Download a drop's files into a local directory (accepts the drop_\u2026 id, the drop URL, or its slug).\nFetches the current deployment's file manifest and writes every file. Pull, edit, then update-content to ship the changes back to the same URL \u2014 also the rollback path."
|
|
2105
|
-
).option("-o, --output <dir>", "Output directory (default: ./<slug-or-id>)").option("--json", "Force JSON output").
|
|
2672
|
+
).option("-o, --output <dir>", "Output directory (default: ./<slug-or-id>)").option("--json", "Force JSON output").addHelpText(
|
|
2673
|
+
"after",
|
|
2674
|
+
examplesBlock([
|
|
2675
|
+
"dropthis pull drop_abc123 -o ./site # download the drop's files",
|
|
2676
|
+
"$EDITOR ./site/index.html # edit locally",
|
|
2677
|
+
"dropthis update-content drop_abc123 ./site # ship back to the same URL"
|
|
2678
|
+
])
|
|
2679
|
+
).action(
|
|
2106
2680
|
async (target, commandOptions) => {
|
|
2107
2681
|
const deps = await commandDeps(
|
|
2108
2682
|
program,
|
|
@@ -2114,19 +2688,29 @@ function buildProgram(options = {}) {
|
|
|
2114
2688
|
process.exitCode = result.exitCode;
|
|
2115
2689
|
}
|
|
2116
2690
|
);
|
|
2117
|
-
program.command("get <dropId>").description(
|
|
2691
|
+
program.command("get <dropId>").description(
|
|
2692
|
+
"Show drop details (accepts the drop_\u2026 id, the drop URL, or its slug)"
|
|
2693
|
+
).option("--json", "Force JSON output").action(async (dropId, commandOptions) => {
|
|
2118
2694
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
2119
2695
|
const result = await runDropsGet(dropId, commandOptions, deps);
|
|
2120
2696
|
process.exitCode = result.exitCode;
|
|
2121
2697
|
});
|
|
2122
|
-
program.command("list").description("List your drops").option("--limit <n>", "Page size", parseInteger).option("--cursor <cursor>", "Pagination cursor").option("--json", "Force JSON output").
|
|
2698
|
+
program.command("list").description("List your drops").option("--limit <n>", "Page size", parseInteger).option("--cursor <cursor>", "Pagination cursor").option("--json", "Force JSON output").addHelpText(
|
|
2699
|
+
"after",
|
|
2700
|
+
examplesBlock([
|
|
2701
|
+
"dropthis list",
|
|
2702
|
+
"dropthis list --json | jq -r '.drops[] | [.id, .url] | @tsv' # recover drop ids"
|
|
2703
|
+
])
|
|
2704
|
+
).action(
|
|
2123
2705
|
async (commandOptions) => {
|
|
2124
2706
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
2125
2707
|
const result = await runDropsList(commandOptions, deps);
|
|
2126
2708
|
process.exitCode = result.exitCode;
|
|
2127
2709
|
}
|
|
2128
2710
|
);
|
|
2129
|
-
program.command("delete <dropId>").description(
|
|
2711
|
+
program.command("delete <dropId>").description(
|
|
2712
|
+
"Delete a drop (accepts the drop_\u2026 id, the drop URL, or its slug)"
|
|
2713
|
+
).option("--yes", "Confirm deletion").option("--json", "Force JSON output").action(
|
|
2130
2714
|
async (dropId, commandOptions) => {
|
|
2131
2715
|
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
2132
2716
|
const global = globalOptions(program, commandOptions);
|
|
@@ -2162,6 +2746,101 @@ function buildProgram(options = {}) {
|
|
|
2162
2746
|
process.exitCode = result.exitCode;
|
|
2163
2747
|
}
|
|
2164
2748
|
);
|
|
2749
|
+
const domains = program.command("domains").description(
|
|
2750
|
+
"Manage custom domains. Loop: connect \u2192 create the CNAME at your DNS provider \u2192 verify --wait \u2192 publish --domain"
|
|
2751
|
+
);
|
|
2752
|
+
domains.command("connect <hostname>").description(
|
|
2753
|
+
"Connect a custom domain. Returns DNS records to create at your provider.\nAfter adding them: dropthis domains verify <hostname> --wait"
|
|
2754
|
+
).requiredOption(
|
|
2755
|
+
"--mode <mode>",
|
|
2756
|
+
"Mount mode: path (many drops at hostname/{slug}/) or dedicated (one drop at root)"
|
|
2757
|
+
).option("--json", "Force JSON output").addHelpText(
|
|
2758
|
+
"after",
|
|
2759
|
+
examplesBlock([
|
|
2760
|
+
"dropthis domains connect reports.example.com --mode path",
|
|
2761
|
+
"# add the CNAME shown above at your DNS provider, then:",
|
|
2762
|
+
"dropthis domains verify reports.example.com --wait",
|
|
2763
|
+
"dropthis publish ./report.html --domain reports.example.com"
|
|
2764
|
+
])
|
|
2765
|
+
).action(
|
|
2766
|
+
async (hostname, commandOptions) => {
|
|
2767
|
+
if (commandOptions.mode !== "path" && commandOptions.mode !== "dedicated") {
|
|
2768
|
+
process.stderr.write(`error: --mode must be "path" or "dedicated"
|
|
2769
|
+
`);
|
|
2770
|
+
process.exitCode = 2;
|
|
2771
|
+
return;
|
|
2772
|
+
}
|
|
2773
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
2774
|
+
const result = await runDomainsConnect(
|
|
2775
|
+
{ hostname, mode: commandOptions.mode },
|
|
2776
|
+
deps
|
|
2777
|
+
);
|
|
2778
|
+
process.exitCode = result.exitCode;
|
|
2779
|
+
}
|
|
2780
|
+
);
|
|
2781
|
+
domains.command("list").description("List connected custom domains").option("--json", "Force JSON output").action(async (commandOptions) => {
|
|
2782
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
2783
|
+
const result = await runDomainsList(commandOptions, deps);
|
|
2784
|
+
process.exitCode = result.exitCode;
|
|
2785
|
+
});
|
|
2786
|
+
domains.command("status <hostname>").description("Show domain details and DNS record status").option("--json", "Force JSON output").action(async (hostname, commandOptions) => {
|
|
2787
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
2788
|
+
const result = await runDomainsStatus(hostname, commandOptions, deps);
|
|
2789
|
+
process.exitCode = result.exitCode;
|
|
2790
|
+
});
|
|
2791
|
+
domains.command("verify <hostname>").description(
|
|
2792
|
+
"Trigger a DNS verification check. With --wait, polls until live or failed.\nUse after adding the DNS records from: dropthis domains connect"
|
|
2793
|
+
).option("--wait", "Poll until live (or failed/timeout)").option(
|
|
2794
|
+
"--timeout <secs>",
|
|
2795
|
+
"Max seconds to wait (default: 300)",
|
|
2796
|
+
parseInteger
|
|
2797
|
+
).option("--json", "Force JSON output").addHelpText(
|
|
2798
|
+
"after",
|
|
2799
|
+
examplesBlock([
|
|
2800
|
+
"dropthis domains verify reports.example.com --wait",
|
|
2801
|
+
"dropthis domains verify reports.example.com --wait --timeout 600"
|
|
2802
|
+
])
|
|
2803
|
+
).action(
|
|
2804
|
+
async (hostname, commandOptions) => {
|
|
2805
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
2806
|
+
const result = await runDomainsVerify(hostname, commandOptions, deps);
|
|
2807
|
+
process.exitCode = result.exitCode;
|
|
2808
|
+
}
|
|
2809
|
+
);
|
|
2810
|
+
domains.command("update <hostname>").description(
|
|
2811
|
+
"Update a domain \u2014 repoint to a different drop (dedicated mode) or set/clear as account default (path mode). At least one option required."
|
|
2812
|
+
).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(
|
|
2813
|
+
async (hostname, commandOptions) => {
|
|
2814
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
2815
|
+
const result = await runDomainsUpdate(
|
|
2816
|
+
hostname,
|
|
2817
|
+
{
|
|
2818
|
+
...commandOptions.drop !== void 0 ? { drop: commandOptions.drop } : {},
|
|
2819
|
+
...commandOptions.default !== void 0 ? { setDefault: commandOptions.default } : {}
|
|
2820
|
+
},
|
|
2821
|
+
deps
|
|
2822
|
+
);
|
|
2823
|
+
process.exitCode = result.exitCode;
|
|
2824
|
+
}
|
|
2825
|
+
);
|
|
2826
|
+
domains.command("remove <hostname>").description(
|
|
2827
|
+
"Remove a custom domain (unmounts its drops). IMPORTANT: also delete the DNS CNAME at your provider to prevent DNS hijacking."
|
|
2828
|
+
).option("--yes", "Confirm removal").option("--json", "Force JSON output").action(
|
|
2829
|
+
async (hostname, commandOptions) => {
|
|
2830
|
+
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
2831
|
+
const global = globalOptions(program, commandOptions);
|
|
2832
|
+
const deps = await commandDeps(program, options, store, commandOptions);
|
|
2833
|
+
const result = await runDomainsRemove(
|
|
2834
|
+
hostname,
|
|
2835
|
+
{
|
|
2836
|
+
...commandOptions,
|
|
2837
|
+
interactive: isInteractive(stdinIsTTY, deps.env, global)
|
|
2838
|
+
},
|
|
2839
|
+
deps
|
|
2840
|
+
);
|
|
2841
|
+
process.exitCode = result.exitCode;
|
|
2842
|
+
}
|
|
2843
|
+
);
|
|
2165
2844
|
const apiKeys = program.command("api-keys").description("Manage API keys");
|
|
2166
2845
|
apiKeys.command("create").description("Create an API key").option("--label <label>", "API key label", "CLI").option("--json", "Force JSON output").action(async (commandOptions) => {
|
|
2167
2846
|
const deps = await commandDeps(program, options, store, commandOptions);
|
|
@@ -2194,6 +2873,16 @@ function buildProgram(options = {}) {
|
|
|
2194
2873
|
if (!commandOptions.email || !commandOptions.otp) {
|
|
2195
2874
|
const deps2 = await commandDeps(program, options, store, commandOptions);
|
|
2196
2875
|
const global2 = globalOptions(program, commandOptions);
|
|
2876
|
+
const stdinIsTTY = options.stdinIsTTY ?? process.stdin.isTTY ?? false;
|
|
2877
|
+
if (!isInteractive(stdinIsTTY, deps2.env, global2)) {
|
|
2878
|
+
process.exitCode = writeError(
|
|
2879
|
+
deps2,
|
|
2880
|
+
"invalid_usage",
|
|
2881
|
+
"dropthis login is interactive and needs a terminal.",
|
|
2882
|
+
"Set DROPTHIS_API_KEY, or run: dropthis login request --email <email>, then dropthis login verify --email <email> --otp <code>."
|
|
2883
|
+
).exitCode;
|
|
2884
|
+
return;
|
|
2885
|
+
}
|
|
2197
2886
|
const context = createContext({ global: global2 });
|
|
2198
2887
|
const result2 = await runLoginInteractive({
|
|
2199
2888
|
...deps2,
|
|
@@ -2400,6 +3089,8 @@ function toDropOptions(options) {
|
|
|
2400
3089
|
...options.contentType ? { contentType: options.contentType } : {},
|
|
2401
3090
|
...options.path ? { path: options.path } : {},
|
|
2402
3091
|
...options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {},
|
|
3092
|
+
...options.domain ? { domain: options.domain } : {},
|
|
3093
|
+
...options.slug ? { slug: options.slug } : {},
|
|
2403
3094
|
...options.json !== void 0 ? { json: options.json } : {},
|
|
2404
3095
|
...options.quiet !== void 0 ? { quiet: options.quiet } : {},
|
|
2405
3096
|
...options.url !== void 0 ? { url: options.url } : {},
|
|
@@ -2450,9 +3141,6 @@ function writeUsageErrorEnvelope(input) {
|
|
|
2450
3141
|
`${JSON.stringify(errorEnvelope("usage_error", input.message))}
|
|
2451
3142
|
`
|
|
2452
3143
|
);
|
|
2453
|
-
} else {
|
|
2454
|
-
input.stderr(`${input.message}
|
|
2455
|
-
`);
|
|
2456
3144
|
}
|
|
2457
3145
|
return 2;
|
|
2458
3146
|
}
|