drop2run 0.2.1 → 0.4.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 +15 -2
- package/dist/index.js +156 -31
- package/dist/{package-D-UHpX_a.js → package-Cz51eZ2C.js} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ drop2run login [--device] Sign in and store a token
|
|
|
16
16
|
drop2run logout Remove the stored token
|
|
17
17
|
drop2run init [dir] [--site <subdomain>] Tie this folder to a site
|
|
18
18
|
drop2run deploy [dir] [--site <subdomain>] Publish a folder
|
|
19
|
+
drop2run init|deploy --subdomain <name> Create a new site under a name you pick
|
|
19
20
|
drop2run ls List your sites
|
|
20
21
|
drop2run open [site] Open a site in a browser
|
|
21
22
|
drop2run rollback <deployId> [--site X] Put an earlier version back live
|
|
@@ -30,14 +31,26 @@ drop2run --version Print the version
|
|
|
30
31
|
|
|
31
32
|
## Which site a command acts on
|
|
32
33
|
|
|
33
|
-
`--site`, then `drop2run.json`, then a new
|
|
34
|
-
normal project:
|
|
34
|
+
`--subdomain` creates one under the name you give; otherwise `--site`, then `drop2run.json`, then a new
|
|
35
|
+
site with a generated name. `init` writes that file, so this is the whole of a normal project:
|
|
35
36
|
|
|
36
37
|
```bash
|
|
37
38
|
drop2run init dist # creates a site, writes drop2run.json
|
|
38
39
|
drop2run deploy # publishes dist to it, no arguments
|
|
39
40
|
```
|
|
40
41
|
|
|
42
|
+
```bash
|
|
43
|
+
drop2run init dist --subdomain my-docs # same, but you choose the address
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Lowercase letters, digits and hyphens, not starting or ending with one. A name that is taken, reserved,
|
|
47
|
+
or past the number of self-picked names your plan allows is refused with the reason. It cannot be changed
|
|
48
|
+
later — a site is reached by the address it was created with — so a wrong name means deleting the site,
|
|
49
|
+
which is not undoable.
|
|
50
|
+
|
|
51
|
+
`--site` never creates anything: it finds a site you already have, and fails when nothing matches. That
|
|
52
|
+
is what keeps a subdomain typed one letter wrong from quietly becoming a second site.
|
|
53
|
+
|
|
41
54
|
`deploy` never creates a second site while a `drop2run.json` sits next to it — that would leave the real
|
|
42
55
|
site untouched and you looking at a URL you did not expect.
|
|
43
56
|
|
package/dist/index.js
CHANGED
|
@@ -55,11 +55,17 @@ async function listSites(credentials) {
|
|
|
55
55
|
const body = await call(credentials, "sites");
|
|
56
56
|
return body.sites;
|
|
57
57
|
}
|
|
58
|
-
async function createSite(credentials) {
|
|
58
|
+
async function createSite(credentials, subdomain) {
|
|
59
59
|
const created = await call(
|
|
60
60
|
credentials,
|
|
61
61
|
"sites",
|
|
62
|
-
{
|
|
62
|
+
{
|
|
63
|
+
method: "POST",
|
|
64
|
+
// An absent field rather than a null one, because the API reads null, empty and missing the
|
|
65
|
+
// same way and a body carrying only what was asked for is the one that reads correctly in a
|
|
66
|
+
// log.
|
|
67
|
+
body: JSON.stringify(subdomain === void 0 ? {} : { subdomain })
|
|
68
|
+
}
|
|
63
69
|
);
|
|
64
70
|
return { ...created, name: null };
|
|
65
71
|
}
|
|
@@ -369,6 +375,7 @@ const ClientErrorCode = {
|
|
|
369
375
|
/** An upload kept failing after every retry. */
|
|
370
376
|
UploadFailed: "upload_failed"
|
|
371
377
|
};
|
|
378
|
+
const ACCOUNT_HEADER = "X-Drop2Run-Account";
|
|
372
379
|
const CLAIM_TOKEN_HEADER = "X-Claim-Token";
|
|
373
380
|
async function prepareDeploy(siteId, files, options, signal) {
|
|
374
381
|
const manifest = files.map((file) => ({
|
|
@@ -405,6 +412,7 @@ async function request(path, body, options, signal) {
|
|
|
405
412
|
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
406
413
|
if (options.claimToken) headers[CLAIM_TOKEN_HEADER] = options.claimToken;
|
|
407
414
|
if (options.token) headers.Authorization = `Bearer ${options.token}`;
|
|
415
|
+
if (options.accountId) headers[ACCOUNT_HEADER] = options.accountId;
|
|
408
416
|
const response = await doFetch(`${base}/${path}`, {
|
|
409
417
|
method: "POST",
|
|
410
418
|
headers,
|
|
@@ -517,7 +525,7 @@ function renameOfLoneHtmlPage(paths) {
|
|
|
517
525
|
const lower = only.toLowerCase();
|
|
518
526
|
return lower.endsWith(".html") || lower.endsWith(".htm") ? only : null;
|
|
519
527
|
}
|
|
520
|
-
function formatBytes(bytes) {
|
|
528
|
+
function formatBytes$1(bytes) {
|
|
521
529
|
if (bytes < 1024) return `${bytes} B`;
|
|
522
530
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
523
531
|
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
@@ -548,7 +556,7 @@ function checkLimits(files, limits) {
|
|
|
548
556
|
if (oversized) {
|
|
549
557
|
throw new DeployError(
|
|
550
558
|
ClientErrorCode.FileTooLarge,
|
|
551
|
-
`${oversized.path} is ${formatBytes(oversized.bytes.length)}, and this plan allows ${formatBytes(limits.maxFileBytes)} per file.`,
|
|
559
|
+
`${oversized.path} is ${formatBytes$1(oversized.bytes.length)}, and this plan allows ${formatBytes$1(limits.maxFileBytes)} per file.`,
|
|
552
560
|
{
|
|
553
561
|
path: oversized.path,
|
|
554
562
|
limit: limits.maxFileBytes,
|
|
@@ -560,7 +568,7 @@ function checkLimits(files, limits) {
|
|
|
560
568
|
if (limits.maxSiteBytes !== null && total > limits.maxSiteBytes) {
|
|
561
569
|
throw new DeployError(
|
|
562
570
|
ClientErrorCode.TooLarge,
|
|
563
|
-
`That drop is ${formatBytes(total)}, and this plan allows ${formatBytes(limits.maxSiteBytes)}.`,
|
|
571
|
+
`That drop is ${formatBytes$1(total)}, and this plan allows ${formatBytes$1(limits.maxSiteBytes)}.`,
|
|
564
572
|
{ limit: limits.maxSiteBytes, actual: total }
|
|
565
573
|
);
|
|
566
574
|
}
|
|
@@ -698,7 +706,7 @@ async function uploadAll(targets, uploadUrl, files, onProgress, signal, deps = {
|
|
|
698
706
|
});
|
|
699
707
|
done += 1;
|
|
700
708
|
uploadedBytes += file.bytes.length;
|
|
701
|
-
onProgress?.(done, targets.length, uploadedBytes);
|
|
709
|
+
onProgress?.(done, targets.length, uploadedBytes, file.path);
|
|
702
710
|
}
|
|
703
711
|
};
|
|
704
712
|
const workers = Array.from(
|
|
@@ -793,12 +801,13 @@ async function deploy(source, siteId, onProgress, signal, options = {}) {
|
|
|
793
801
|
prepared.upload,
|
|
794
802
|
prepared.uploadUrl,
|
|
795
803
|
hashed,
|
|
796
|
-
(done, _total, bytes) => onProgress({
|
|
804
|
+
(done, _total, bytes, path) => onProgress({
|
|
797
805
|
type: "uploading",
|
|
798
806
|
done: prepared.reused + done,
|
|
799
807
|
total: prepared.total,
|
|
800
808
|
bytes,
|
|
801
|
-
reused: prepared.reused
|
|
809
|
+
reused: prepared.reused,
|
|
810
|
+
path
|
|
802
811
|
}),
|
|
803
812
|
signal,
|
|
804
813
|
options.upload
|
|
@@ -864,7 +873,15 @@ function escapesRoot(root, candidate) {
|
|
|
864
873
|
const inside = relative(root, candidate);
|
|
865
874
|
return inside === "" || inside.startsWith("..");
|
|
866
875
|
}
|
|
867
|
-
async function resolveSite(credentials, site) {
|
|
876
|
+
async function resolveSite(credentials, site, subdomain) {
|
|
877
|
+
if (subdomain !== void 0) {
|
|
878
|
+
if (site !== void 0) {
|
|
879
|
+
throw new Error(
|
|
880
|
+
"Give either an existing site or a subdomain for a new one, not both: publishing over a site and creating one are different requests."
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
return await createSite(credentials, subdomain);
|
|
884
|
+
}
|
|
868
885
|
if (site === void 0) return await createSite(credentials);
|
|
869
886
|
const wanted = site.trim().toLowerCase();
|
|
870
887
|
const found = (await listSites(credentials)).find(
|
|
@@ -872,13 +889,13 @@ async function resolveSite(credentials, site) {
|
|
|
872
889
|
);
|
|
873
890
|
if (found === void 0) {
|
|
874
891
|
throw new Error(
|
|
875
|
-
`No site of yours is called "${site}". Leave the site out to publish to a new one, or
|
|
892
|
+
`No site of yours is called "${site}". Leave the site out to publish to a new one, or list your sites to see what exists.`
|
|
876
893
|
);
|
|
877
894
|
}
|
|
878
895
|
return found;
|
|
879
896
|
}
|
|
880
|
-
async function publish(credentials, source, site) {
|
|
881
|
-
const target = await resolveSite(credentials, site);
|
|
897
|
+
async function publish(credentials, source, site, onProgress, subdomain) {
|
|
898
|
+
const target = await resolveSite(credentials, site, subdomain);
|
|
882
899
|
let files = 0;
|
|
883
900
|
let url = target.url;
|
|
884
901
|
let unchanged = false;
|
|
@@ -895,6 +912,7 @@ async function publish(credentials, source, site) {
|
|
|
895
912
|
failure2 = event.message;
|
|
896
913
|
failureDetail = event.detail;
|
|
897
914
|
}
|
|
915
|
+
onProgress?.(event);
|
|
898
916
|
};
|
|
899
917
|
await deploy(source, target.siteId, record, void 0, {
|
|
900
918
|
baseUrl: credentials.apiBaseUrl,
|
|
@@ -908,8 +926,75 @@ async function publish(credentials, source, site) {
|
|
|
908
926
|
});
|
|
909
927
|
return { url, siteId: target.siteId, subdomain: target.subdomain, files, unchanged };
|
|
910
928
|
}
|
|
911
|
-
function publishDirectory(credentials, directory, site) {
|
|
912
|
-
return publish(credentials, directorySource(directory), site);
|
|
929
|
+
function publishDirectory(credentials, directory, site, onProgress, subdomain) {
|
|
930
|
+
return publish(credentials, directorySource(directory), site, onProgress, subdomain);
|
|
931
|
+
}
|
|
932
|
+
const silentProgress = Object.assign(() => {
|
|
933
|
+
}, { done: () => {
|
|
934
|
+
} });
|
|
935
|
+
const STEP = 1024;
|
|
936
|
+
const UNITS = ["B", "KB", "MB", "GB"];
|
|
937
|
+
function formatBytes(bytes) {
|
|
938
|
+
let value = bytes;
|
|
939
|
+
let unit = 0;
|
|
940
|
+
while (value >= STEP && unit < UNITS.length - 1) {
|
|
941
|
+
value /= STEP;
|
|
942
|
+
unit += 1;
|
|
943
|
+
}
|
|
944
|
+
return `${unit === 0 ? value : value.toFixed(1)} ${UNITS[unit]}`;
|
|
945
|
+
}
|
|
946
|
+
function shortenPath(path, width) {
|
|
947
|
+
if (path.length <= width) return path;
|
|
948
|
+
return `…${path.slice(path.length - width + 1)}`;
|
|
949
|
+
}
|
|
950
|
+
function describe(event, width = 80) {
|
|
951
|
+
switch (event.type) {
|
|
952
|
+
case "collecting":
|
|
953
|
+
return `Collected ${event.files.toLocaleString()} ${event.files === 1 ? "file" : "files"}`;
|
|
954
|
+
case "hashing":
|
|
955
|
+
return `Hashing ${event.done.toLocaleString()}/${event.total.toLocaleString()}`;
|
|
956
|
+
case "preparing":
|
|
957
|
+
return "Asking the server which files it already has";
|
|
958
|
+
case "uploading": {
|
|
959
|
+
const counted = `Uploading ${event.done.toLocaleString()}/${event.total.toLocaleString()}`;
|
|
960
|
+
const reused = event.reused === 0 ? "" : ` (${event.reused.toLocaleString()} already there)`;
|
|
961
|
+
const head = `${counted}${reused} · ${formatBytes(event.bytes)}`;
|
|
962
|
+
const room = width - head.length - 3;
|
|
963
|
+
return event.path === void 0 || room < 12 ? head : `${head} · ${shortenPath(event.path, room)}`;
|
|
964
|
+
}
|
|
965
|
+
case "completing":
|
|
966
|
+
return "Publishing";
|
|
967
|
+
// Both end the deploy, and the command prints the URL from the result it returns. Saying it here
|
|
968
|
+
// as well would print it twice, once on stderr and once on stdout.
|
|
969
|
+
case "done":
|
|
970
|
+
case "unchanged":
|
|
971
|
+
case "error":
|
|
972
|
+
return null;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
function progressWriter(write, isTerminal, width = 80) {
|
|
976
|
+
let painted = 0;
|
|
977
|
+
let lastStage = null;
|
|
978
|
+
const writer = ((event) => {
|
|
979
|
+
const line = describe(event, width - 1);
|
|
980
|
+
if (line === null) return;
|
|
981
|
+
if (!isTerminal) {
|
|
982
|
+
if (event.type === lastStage) return;
|
|
983
|
+
lastStage = event.type;
|
|
984
|
+
write(`${line}
|
|
985
|
+
`);
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
lastStage = event.type;
|
|
989
|
+
write(`\r${line}${" ".repeat(Math.max(0, painted - line.length))}`);
|
|
990
|
+
painted = line.length;
|
|
991
|
+
});
|
|
992
|
+
writer.done = () => {
|
|
993
|
+
if (!isTerminal || painted === 0) return;
|
|
994
|
+
write(`\r${" ".repeat(painted)}\r`);
|
|
995
|
+
painted = 0;
|
|
996
|
+
};
|
|
997
|
+
return writer;
|
|
913
998
|
}
|
|
914
999
|
function failure(text) {
|
|
915
1000
|
return { text, json: { error: text }, code: 1 };
|
|
@@ -1053,14 +1138,20 @@ async function list() {
|
|
|
1053
1138
|
code: 0
|
|
1054
1139
|
};
|
|
1055
1140
|
}
|
|
1056
|
-
async function deployCommand(directory, site) {
|
|
1141
|
+
async function deployCommand(directory, site, report = silentProgress, subdomain) {
|
|
1057
1142
|
const found = credentialsOr();
|
|
1058
1143
|
if ("result" in found) return found.result;
|
|
1059
1144
|
const project = readProject();
|
|
1060
|
-
const target = site ?? project?.siteId;
|
|
1061
1145
|
const folder = directory ?? project?.dir ?? ".";
|
|
1146
|
+
const target = subdomain === void 0 ? site ?? project?.siteId : void 0;
|
|
1062
1147
|
try {
|
|
1063
|
-
const result = await publishDirectory(
|
|
1148
|
+
const result = await publishDirectory(
|
|
1149
|
+
found.credentials,
|
|
1150
|
+
resolve(folder),
|
|
1151
|
+
target,
|
|
1152
|
+
report,
|
|
1153
|
+
subdomain
|
|
1154
|
+
);
|
|
1064
1155
|
const what = result.unchanged ? "Already up to date — nothing needed publishing." : `Published ${result.files.toLocaleString()} ${result.files === 1 ? "file" : "files"}.`;
|
|
1065
1156
|
return {
|
|
1066
1157
|
text: `${what}
|
|
@@ -1070,9 +1161,11 @@ ${result.url}`,
|
|
|
1070
1161
|
};
|
|
1071
1162
|
} catch (error) {
|
|
1072
1163
|
return failureFrom(error);
|
|
1164
|
+
} finally {
|
|
1165
|
+
report.done();
|
|
1073
1166
|
}
|
|
1074
1167
|
}
|
|
1075
|
-
async function init(directory, site) {
|
|
1168
|
+
async function init(directory, site, subdomain) {
|
|
1076
1169
|
const found = credentialsOr();
|
|
1077
1170
|
if ("result" in found) return found.result;
|
|
1078
1171
|
if (readProject() !== null) {
|
|
@@ -1081,7 +1174,7 @@ async function init(directory, site) {
|
|
|
1081
1174
|
);
|
|
1082
1175
|
}
|
|
1083
1176
|
try {
|
|
1084
|
-
const target = site === void 0 ? await createSite(found.credentials) : await findSite(found.credentials, site);
|
|
1177
|
+
const target = site === void 0 ? await createSite(found.credentials, subdomain) : await findSite(found.credentials, site);
|
|
1085
1178
|
const project = {
|
|
1086
1179
|
siteId: target.siteId,
|
|
1087
1180
|
subdomain: target.subdomain,
|
|
@@ -1219,6 +1312,7 @@ const HELP = `drop2run — publish a static site from the command line
|
|
|
1219
1312
|
drop2run logout Remove the stored token
|
|
1220
1313
|
drop2run init [dir] [--site <subdomain>] Tie this folder to a site (writes drop2run.json)
|
|
1221
1314
|
drop2run deploy [dir] [--site <subdomain>] Publish a folder (default: . or drop2run.json)
|
|
1315
|
+
drop2run init|deploy --subdomain <name> Create a new site under a name you pick
|
|
1222
1316
|
drop2run ls List your sites
|
|
1223
1317
|
drop2run open [site] Open a site in a browser
|
|
1224
1318
|
drop2run rollback <deployId> [--site X] Put an earlier version back live
|
|
@@ -1229,14 +1323,19 @@ const HELP = `drop2run — publish a static site from the command line
|
|
|
1229
1323
|
drop2run --version Print the version
|
|
1230
1324
|
|
|
1231
1325
|
Flags
|
|
1232
|
-
--json
|
|
1233
|
-
--site X
|
|
1234
|
-
--
|
|
1235
|
-
--
|
|
1326
|
+
--json Print machine-readable output instead of text
|
|
1327
|
+
--site X Act on an existing site rather than the one in drop2run.json
|
|
1328
|
+
--subdomain X Create a new site under this name (init and deploy only)
|
|
1329
|
+
--device Sign in by approving a code on another machine
|
|
1330
|
+
--yes Confirm a deletion, which cannot be undone
|
|
1236
1331
|
|
|
1237
1332
|
Where a site comes from
|
|
1238
|
-
--
|
|
1239
|
-
|
|
1333
|
+
--subdomain creates one under the name you give. Otherwise: --site, then
|
|
1334
|
+
drop2run.json, then a new site with a generated name. \`init\` writes that
|
|
1335
|
+
file, so \`deploy\` in the same folder needs no arguments at all.
|
|
1336
|
+
|
|
1337
|
+
--site only ever finds a site you already have; it never creates one, so a
|
|
1338
|
+
subdomain typed wrong fails instead of quietly becoming a second site.
|
|
1240
1339
|
|
|
1241
1340
|
Signing in
|
|
1242
1341
|
\`login\` opens a browser and listens on 127.0.0.1, so it needs both on this
|
|
@@ -1253,12 +1352,25 @@ function flagValue(args, flag) {
|
|
|
1253
1352
|
const value = args[at + 1];
|
|
1254
1353
|
return value === void 0 || value.startsWith("-") ? void 0 : value;
|
|
1255
1354
|
}
|
|
1355
|
+
function subdomainFlagProblem(argv, command, site, subdomain) {
|
|
1356
|
+
if (!argv.includes("--subdomain")) return void 0;
|
|
1357
|
+
if (subdomain === void 0) {
|
|
1358
|
+
return "`--subdomain` needs a name after it, for example `--subdomain my-docs`.";
|
|
1359
|
+
}
|
|
1360
|
+
if (site !== void 0) {
|
|
1361
|
+
return "`--site` and `--subdomain` cannot both be given: `--site` publishes to a site you already have, and `--subdomain` creates a new one. Drop whichever is not what you meant.";
|
|
1362
|
+
}
|
|
1363
|
+
if (command !== "init" && command !== "deploy") {
|
|
1364
|
+
return `\`--subdomain\` only applies to \`init\` and \`deploy\`, which can create a site. Use \`--site\` to tell \`${command}\` which of your sites to act on.`;
|
|
1365
|
+
}
|
|
1366
|
+
return void 0;
|
|
1367
|
+
}
|
|
1256
1368
|
async function run(argv) {
|
|
1257
1369
|
const json = argv.includes("--json");
|
|
1258
1370
|
const positional = argv.filter((argument) => !argument.startsWith("-"));
|
|
1259
1371
|
const [command, ...rest] = positional;
|
|
1260
1372
|
if (argv.includes("--version")) {
|
|
1261
|
-
const { version } = await import("./package-
|
|
1373
|
+
const { version } = await import("./package-Cz51eZ2C.js").then(
|
|
1262
1374
|
(module) => module.default
|
|
1263
1375
|
);
|
|
1264
1376
|
return { text: version, json: { version }, code: 0 };
|
|
@@ -1267,17 +1379,24 @@ async function run(argv) {
|
|
|
1267
1379
|
if (askedForHelp) return { text: HELP, json: { help: HELP }, code: 0 };
|
|
1268
1380
|
if (command === void 0) return { text: HELP, json: { help: HELP }, code: 1 };
|
|
1269
1381
|
const site = flagValue(argv, "--site");
|
|
1382
|
+
const subdomain = flagValue(argv, "--subdomain");
|
|
1383
|
+
const refusal = subdomainFlagProblem(argv, command, site, subdomain);
|
|
1384
|
+
if (refusal !== void 0) {
|
|
1385
|
+
const failed = { text: refusal, json: { error: refusal }, code: 1 };
|
|
1386
|
+
return json ? { ...failed, text: JSON.stringify(failed.json, null, 2) } : failed;
|
|
1387
|
+
}
|
|
1270
1388
|
const result = await dispatch(
|
|
1271
1389
|
command,
|
|
1272
1390
|
rest,
|
|
1273
1391
|
site,
|
|
1274
1392
|
json,
|
|
1275
1393
|
argv.includes("--device"),
|
|
1276
|
-
argv.includes("--yes")
|
|
1394
|
+
argv.includes("--yes"),
|
|
1395
|
+
subdomain
|
|
1277
1396
|
);
|
|
1278
1397
|
return json ? { ...result, text: JSON.stringify(result.json, null, 2) } : result;
|
|
1279
1398
|
}
|
|
1280
|
-
async function dispatch(command, rest, site, json, device, confirmed) {
|
|
1399
|
+
async function dispatch(command, rest, site, json, device, confirmed, subdomain) {
|
|
1281
1400
|
switch (command) {
|
|
1282
1401
|
case "login": {
|
|
1283
1402
|
const print = json ? () => {
|
|
@@ -1287,9 +1406,15 @@ async function dispatch(command, rest, site, json, device, confirmed) {
|
|
|
1287
1406
|
case "logout":
|
|
1288
1407
|
return logout();
|
|
1289
1408
|
case "init":
|
|
1290
|
-
return await init(rest[0] ?? ".", site);
|
|
1291
|
-
case "deploy":
|
|
1292
|
-
|
|
1409
|
+
return await init(rest[0] ?? ".", site, subdomain);
|
|
1410
|
+
case "deploy": {
|
|
1411
|
+
const report = json ? silentProgress : progressWriter(
|
|
1412
|
+
(text) => process.stderr.write(text),
|
|
1413
|
+
process.stderr.isTTY === true,
|
|
1414
|
+
process.stderr.columns ?? 80
|
|
1415
|
+
);
|
|
1416
|
+
return await deployCommand(rest[0], site, report, subdomain);
|
|
1417
|
+
}
|
|
1293
1418
|
case "ls":
|
|
1294
1419
|
case "list":
|
|
1295
1420
|
return await list();
|