stow-cli 1.0.3 → 2.0.1
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/{app-JPUDM4LJ.js → app-2A2CFVBC.js} +1 -1
- package/dist/app-2H4TLSN7.js +239 -0
- package/dist/app-DTW2LNXW.js +249 -0
- package/dist/app-HYCPA7GA.js +239 -0
- package/dist/app-IZGSPZPX.js +239 -0
- package/dist/app-UGUM75MC.js +239 -0
- package/dist/app-XPOEAZJC.js +239 -0
- package/dist/app-YITP5APT.js +233 -0
- package/dist/{backfill-QZTVNJZM.js → backfill-G57M2BRA.js} +3 -3
- package/dist/{buckets-JQKZ3PH3.js → buckets-NXIVHPW5.js} +2 -2
- package/dist/chunk-2AORPTQB.js +23 -0
- package/dist/chunk-5LU25QZK.js +17 -0
- package/dist/chunk-FEMMZ4YZ.js +125 -0
- package/dist/chunk-LYCXXF2T.js +79 -0
- package/dist/chunk-MHRMBH4Y.js +36 -0
- package/dist/{chunk-WAQSCS57.js → chunk-QF7PVPWQ.js} +1 -1
- package/dist/chunk-R5CCBTXZ.js +79 -0
- package/dist/chunk-TOADDO2F.js +23 -0
- package/dist/chunk-YRHPOFJT.js +115 -0
- package/dist/chunk-ZDVARBCV.js +43 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +43 -43
- package/dist/delete-AECEJX5W.js +18 -0
- package/dist/delete-GEX3O7YS.js +14 -0
- package/dist/delete-KYOZEODD.js +18 -0
- package/dist/delete-OLOAJRRO.js +18 -0
- package/dist/delete-V4EY4UBG.js +18 -0
- package/dist/{drops-QXGTYB5E.js → drops-RD55IDZ4.js} +2 -2
- package/dist/{files-OCYICIAM.js → files-E662TXUP.js} +3 -3
- package/dist/{health-YMZTZUFX.js → health-6LWM7KAT.js} +3 -3
- package/dist/{jobs-6JY4SVV5.js → jobs-CLXYKZ3B.js} +4 -4
- package/dist/{jobs-OKKGKSIH.js → jobs-K3LTNETU.js} +5 -5
- package/dist/list-7A3VZA2T.js +97 -0
- package/dist/list-DHXVIMRI.js +94 -0
- package/dist/list-DJEAKEZJ.js +106 -0
- package/dist/list-DQRU6QHO.js +106 -0
- package/dist/list-I5A6LTHX.js +106 -0
- package/dist/list-KEQPJY7I.js +109 -0
- package/dist/list-Z3MPT6MI.js +109 -0
- package/dist/{maintenance-EZUHQK5Q.js → maintenance-7LOAGG6J.js} +6 -6
- package/dist/open-2YNHG3MA.js +15 -0
- package/dist/open-F73Q2OHD.js +15 -0
- package/dist/{profiles-GWLBEEIT.js → profiles-C6SCFXS6.js} +2 -2
- package/dist/{queues-EQX7EJZF.js → queues-2GJAMMNF.js} +4 -4
- package/dist/{search-2PXM6XQ6.js → search-DV4VV62L.js} +2 -2
- package/dist/{tags-LSVEIIUF.js → tags-URHK2YH5.js} +2 -2
- package/dist/upload-3NS5O3UL.js +120 -0
- package/dist/upload-5RIDB2C5.js +92 -0
- package/dist/upload-B2PGW3AN.js +125 -0
- package/dist/{upload-ESYKBYHA.js → upload-DQDBDIDI.js} +1 -1
- package/dist/upload-FGNGNPC3.js +93 -0
- package/dist/upload-HKUPWTK2.js +173 -0
- package/dist/upload-JDVSJVWK.js +173 -0
- package/dist/upload-K4H7ZVRW.js +98 -0
- package/dist/upload-MI6VFGTC.js +92 -0
- package/dist/whoami-2SLCNVKP.js +27 -0
- package/dist/whoami-5IYRZKWS.js +28 -0
- package/dist/{whoami-4UYMSRVP.js → whoami-754O5IML.js} +1 -1
- package/dist/whoami-DOMX3Z5K.js +28 -0
- package/dist/whoami-IPMCUEUH.js +27 -0
- package/dist/whoami-JSQA2IDN.js +27 -0
- package/dist/whoami-RKH5HHPR.js +27 -0
- package/package.json +1 -1
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatBytes,
|
|
3
|
+
formatTable,
|
|
4
|
+
usageBar
|
|
5
|
+
} from "./chunk-ZDVARBCV.js";
|
|
6
|
+
import {
|
|
7
|
+
createStow
|
|
8
|
+
} from "./chunk-JYOMHKFS.js";
|
|
9
|
+
import "./chunk-OZ7QQTIZ.js";
|
|
10
|
+
|
|
11
|
+
// src/commands/list.ts
|
|
12
|
+
async function listBuckets() {
|
|
13
|
+
const stow = createStow();
|
|
14
|
+
const data = await stow.listBuckets();
|
|
15
|
+
if (data.buckets.length === 0) {
|
|
16
|
+
console.log("No buckets yet. Create one with: stow buckets create <name>");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const rows = data.buckets.map((b) => [
|
|
20
|
+
b.name,
|
|
21
|
+
b.isPublic ? "public" : "private",
|
|
22
|
+
`${b.fileCount ?? 0} files`,
|
|
23
|
+
formatBytes(b.usageBytes ?? 0),
|
|
24
|
+
b.description || ""
|
|
25
|
+
]);
|
|
26
|
+
console.log(
|
|
27
|
+
formatTable(["Name", "Access", "Files", "Size", "Description"], rows)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
async function createBucket(name, options) {
|
|
31
|
+
const stow = createStow();
|
|
32
|
+
const bucket = await stow.createBucket({
|
|
33
|
+
name,
|
|
34
|
+
...options.description ? { description: options.description } : {},
|
|
35
|
+
...options.public ? { isPublic: true } : {}
|
|
36
|
+
});
|
|
37
|
+
console.log(`Created bucket: ${bucket.name}`);
|
|
38
|
+
}
|
|
39
|
+
async function renameBucket(name, newName, options) {
|
|
40
|
+
if (!options.yes) {
|
|
41
|
+
console.error(
|
|
42
|
+
"Warning: Renaming a bucket will break any existing URLs using the old name."
|
|
43
|
+
);
|
|
44
|
+
console.error("Use --yes to skip this warning.");
|
|
45
|
+
}
|
|
46
|
+
const stow = createStow();
|
|
47
|
+
const bucket = await stow.renameBucket(name, newName);
|
|
48
|
+
console.log(`Renamed bucket: ${name} \u2192 ${bucket.name}`);
|
|
49
|
+
}
|
|
50
|
+
async function listFiles(bucket, options) {
|
|
51
|
+
const stow = createStow();
|
|
52
|
+
const parsedLimit = options.limit ? Number.parseInt(options.limit, 10) : null;
|
|
53
|
+
const data = await stow.listFiles({
|
|
54
|
+
bucket,
|
|
55
|
+
...options.search ? { prefix: options.search } : {},
|
|
56
|
+
...parsedLimit && Number.isFinite(parsedLimit) && parsedLimit > 0 ? { limit: parsedLimit } : {}
|
|
57
|
+
});
|
|
58
|
+
if (data.files.length === 0) {
|
|
59
|
+
console.log(`No files in bucket '${bucket}'.`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const rows = data.files.map((f) => [
|
|
63
|
+
f.key,
|
|
64
|
+
formatBytes(f.size),
|
|
65
|
+
f.lastModified.split("T")[0]
|
|
66
|
+
]);
|
|
67
|
+
console.log(formatTable(["Key", "Size", "Modified"], rows));
|
|
68
|
+
if (data.nextCursor) {
|
|
69
|
+
console.log("\n(more files available \u2014 use --limit to see more)");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function listDrops() {
|
|
73
|
+
const stow = createStow();
|
|
74
|
+
const data = await stow.listDrops();
|
|
75
|
+
if (data.drops.length === 0) {
|
|
76
|
+
console.log("No drops yet. Create one with: stow drop <file>");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const rows = data.drops.map((d) => [
|
|
80
|
+
d.filename,
|
|
81
|
+
formatBytes(Number(d.size)),
|
|
82
|
+
d.contentType,
|
|
83
|
+
d.url
|
|
84
|
+
]);
|
|
85
|
+
console.log(formatTable(["Filename", "Size", "Type", "URL"], rows));
|
|
86
|
+
console.log(
|
|
87
|
+
`
|
|
88
|
+
Storage: ${usageBar(data.usage.bytes, data.usage.limit)} ${formatBytes(data.usage.bytes)} / ${formatBytes(data.usage.limit)}`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
async function deleteBucket(id) {
|
|
92
|
+
const stow = createStow();
|
|
93
|
+
await stow.deleteBucket(id);
|
|
94
|
+
console.log(`Deleted bucket: ${id}`);
|
|
95
|
+
}
|
|
96
|
+
async function deleteDrop(id) {
|
|
97
|
+
const stow = createStow();
|
|
98
|
+
await stow.deleteDrop(id);
|
|
99
|
+
console.log(`Deleted drop: ${id}`);
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
createBucket,
|
|
103
|
+
deleteBucket,
|
|
104
|
+
deleteDrop,
|
|
105
|
+
listBuckets,
|
|
106
|
+
listDrops,
|
|
107
|
+
listFiles,
|
|
108
|
+
renameBucket
|
|
109
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createStow
|
|
3
|
+
} from "./chunk-JYOMHKFS.js";
|
|
4
|
+
import {
|
|
5
|
+
formatBytes,
|
|
6
|
+
formatTable,
|
|
7
|
+
usageBar
|
|
8
|
+
} from "./chunk-ZDVARBCV.js";
|
|
9
|
+
import "./chunk-OZ7QQTIZ.js";
|
|
10
|
+
|
|
11
|
+
// src/commands/list.ts
|
|
12
|
+
async function listBuckets() {
|
|
13
|
+
const stow = createStow();
|
|
14
|
+
const data = await stow.listBuckets();
|
|
15
|
+
if (data.buckets.length === 0) {
|
|
16
|
+
console.log("No buckets yet. Create one with: stow buckets create <name>");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const rows = data.buckets.map((b) => [
|
|
20
|
+
b.name,
|
|
21
|
+
b.isPublic ? "public" : "private",
|
|
22
|
+
`${b.fileCount ?? 0} files`,
|
|
23
|
+
formatBytes(b.usageBytes ?? 0),
|
|
24
|
+
b.description || ""
|
|
25
|
+
]);
|
|
26
|
+
console.log(
|
|
27
|
+
formatTable(["Name", "Access", "Files", "Size", "Description"], rows)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
async function createBucket(name, options) {
|
|
31
|
+
const stow = createStow();
|
|
32
|
+
const bucket = await stow.createBucket({
|
|
33
|
+
name,
|
|
34
|
+
...options.description ? { description: options.description } : {},
|
|
35
|
+
...options.public ? { isPublic: true } : {}
|
|
36
|
+
});
|
|
37
|
+
console.log(`Created bucket: ${bucket.name}`);
|
|
38
|
+
}
|
|
39
|
+
async function renameBucket(name, newName, options) {
|
|
40
|
+
if (!options.yes) {
|
|
41
|
+
console.error(
|
|
42
|
+
"Warning: Renaming a bucket will break any existing URLs using the old name."
|
|
43
|
+
);
|
|
44
|
+
console.error("Use --yes to skip this warning.");
|
|
45
|
+
}
|
|
46
|
+
const stow = createStow();
|
|
47
|
+
const bucket = await stow.renameBucket(name, newName);
|
|
48
|
+
console.log(`Renamed bucket: ${name} \u2192 ${bucket.name}`);
|
|
49
|
+
}
|
|
50
|
+
async function listFiles(bucket, options) {
|
|
51
|
+
const stow = createStow();
|
|
52
|
+
const parsedLimit = options.limit ? Number.parseInt(options.limit, 10) : null;
|
|
53
|
+
const data = await stow.listFiles({
|
|
54
|
+
bucket,
|
|
55
|
+
...options.search ? { prefix: options.search } : {},
|
|
56
|
+
...parsedLimit && Number.isFinite(parsedLimit) && parsedLimit > 0 ? { limit: parsedLimit } : {}
|
|
57
|
+
});
|
|
58
|
+
if (data.files.length === 0) {
|
|
59
|
+
console.log(`No files in bucket '${bucket}'.`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const rows = data.files.map((f) => [
|
|
63
|
+
f.key,
|
|
64
|
+
formatBytes(f.size),
|
|
65
|
+
f.lastModified.split("T")[0]
|
|
66
|
+
]);
|
|
67
|
+
console.log(formatTable(["Key", "Size", "Modified"], rows));
|
|
68
|
+
if (data.nextCursor) {
|
|
69
|
+
console.log("\n(more files available \u2014 use --limit to see more)");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function listDrops() {
|
|
73
|
+
const stow = createStow();
|
|
74
|
+
const data = await stow.listDrops();
|
|
75
|
+
if (data.drops.length === 0) {
|
|
76
|
+
console.log("No drops yet. Create one with: stow drop <file>");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const rows = data.drops.map((d) => [
|
|
80
|
+
d.filename,
|
|
81
|
+
formatBytes(Number(d.size)),
|
|
82
|
+
d.contentType,
|
|
83
|
+
d.url
|
|
84
|
+
]);
|
|
85
|
+
console.log(formatTable(["Filename", "Size", "Type", "URL"], rows));
|
|
86
|
+
console.log(
|
|
87
|
+
`
|
|
88
|
+
Storage: ${usageBar(data.usage.bytes, data.usage.limit)} ${formatBytes(data.usage.bytes)} / ${formatBytes(data.usage.limit)}`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
async function deleteBucket(id) {
|
|
92
|
+
const stow = createStow();
|
|
93
|
+
await stow.deleteBucket(id);
|
|
94
|
+
console.log(`Deleted bucket: ${id}`);
|
|
95
|
+
}
|
|
96
|
+
async function deleteDrop(id) {
|
|
97
|
+
const stow = createStow();
|
|
98
|
+
await stow.deleteDrop(id);
|
|
99
|
+
console.log(`Deleted drop: ${id}`);
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
createBucket,
|
|
103
|
+
deleteBucket,
|
|
104
|
+
deleteDrop,
|
|
105
|
+
listBuckets,
|
|
106
|
+
listDrops,
|
|
107
|
+
listFiles,
|
|
108
|
+
renameBucket
|
|
109
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
adminRequest
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QF7PVPWQ.js";
|
|
4
4
|
import {
|
|
5
5
|
outputJson
|
|
6
6
|
} from "./chunk-ELSDWMEB.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-TOADDO2F.js";
|
|
8
8
|
|
|
9
9
|
// src/commands/admin/maintenance.ts
|
|
10
10
|
async function cleanupDrops(options) {
|
|
@@ -18,7 +18,7 @@ async function cleanupDrops(options) {
|
|
|
18
18
|
const qs = params.toString();
|
|
19
19
|
const result = await adminRequest({
|
|
20
20
|
method: "POST",
|
|
21
|
-
path: `/
|
|
21
|
+
path: `/admin/cleanup-drops${qs ? `?${qs}` : ""}`
|
|
22
22
|
});
|
|
23
23
|
if (options.json) {
|
|
24
24
|
outputJson(result);
|
|
@@ -36,7 +36,7 @@ async function purgeEvents(options) {
|
|
|
36
36
|
const qs = params.toString();
|
|
37
37
|
const result = await adminRequest({
|
|
38
38
|
method: "POST",
|
|
39
|
-
path: `/
|
|
39
|
+
path: `/admin/purge-events${qs ? `?${qs}` : ""}`
|
|
40
40
|
});
|
|
41
41
|
if (options.json) {
|
|
42
42
|
outputJson(result);
|
|
@@ -53,7 +53,7 @@ async function reconcileFiles(options) {
|
|
|
53
53
|
}
|
|
54
54
|
const result = await adminRequest({
|
|
55
55
|
method: "POST",
|
|
56
|
-
path: `/
|
|
56
|
+
path: `/admin/reconcile-files?${params}`
|
|
57
57
|
});
|
|
58
58
|
if (options.json) {
|
|
59
59
|
outputJson(result);
|
|
@@ -70,7 +70,7 @@ async function reconcileFiles(options) {
|
|
|
70
70
|
async function retrySyncFailures(options) {
|
|
71
71
|
const result = await adminRequest({
|
|
72
72
|
method: "POST",
|
|
73
|
-
path: "/
|
|
73
|
+
path: "/admin/retry-sync-failures"
|
|
74
74
|
});
|
|
75
75
|
if (options.json) {
|
|
76
76
|
outputJson(result);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getBaseUrl
|
|
3
|
+
} from "./chunk-2AORPTQB.js";
|
|
4
|
+
|
|
5
|
+
// src/commands/open.ts
|
|
6
|
+
async function openBucket(bucket) {
|
|
7
|
+
const baseUrl = getBaseUrl();
|
|
8
|
+
const url = `${baseUrl}/dashboard/buckets/${encodeURIComponent(bucket)}`;
|
|
9
|
+
const { default: open } = await import("open");
|
|
10
|
+
await open(url);
|
|
11
|
+
console.log(`Opened: ${url}`);
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
openBucket
|
|
15
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getBaseUrl
|
|
3
|
+
} from "./chunk-TOADDO2F.js";
|
|
4
|
+
|
|
5
|
+
// src/commands/open.ts
|
|
6
|
+
async function openBucket(bucket) {
|
|
7
|
+
const baseUrl = getBaseUrl();
|
|
8
|
+
const url = `${baseUrl}/dashboard/buckets/${encodeURIComponent(bucket)}`;
|
|
9
|
+
const { default: open } = await import("open");
|
|
10
|
+
await open(url);
|
|
11
|
+
console.log(`Opened: ${url}`);
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
openBucket
|
|
15
|
+
};
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
} from "./chunk-ELSDWMEB.js";
|
|
5
5
|
import {
|
|
6
6
|
createStow
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-5LU25QZK.js";
|
|
8
|
+
import "./chunk-TOADDO2F.js";
|
|
9
9
|
|
|
10
10
|
// src/commands/profiles.ts
|
|
11
11
|
async function createProfile(options) {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
adminRequest
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QF7PVPWQ.js";
|
|
4
4
|
import {
|
|
5
5
|
formatTable,
|
|
6
6
|
outputJson
|
|
7
7
|
} from "./chunk-ELSDWMEB.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-TOADDO2F.js";
|
|
9
9
|
|
|
10
10
|
// src/commands/admin/queues.ts
|
|
11
11
|
async function listQueues(options) {
|
|
12
12
|
const result = await adminRequest({
|
|
13
13
|
method: "GET",
|
|
14
|
-
path: "/
|
|
14
|
+
path: "/admin/queues"
|
|
15
15
|
});
|
|
16
16
|
if (options.json) {
|
|
17
17
|
outputJson(result.queues);
|
|
@@ -38,7 +38,7 @@ async function cleanQueue(queueName, options) {
|
|
|
38
38
|
const grace = options.grace ? Number(options.grace) : 0;
|
|
39
39
|
const result = await adminRequest({
|
|
40
40
|
method: "POST",
|
|
41
|
-
path: `/
|
|
41
|
+
path: `/admin/queues/${encodeURIComponent(queueName)}/clean`,
|
|
42
42
|
body: { status, grace }
|
|
43
43
|
});
|
|
44
44
|
console.log(
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
} from "./chunk-ELSDWMEB.js";
|
|
6
6
|
import {
|
|
7
7
|
createStow
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-5LU25QZK.js";
|
|
9
|
+
import "./chunk-TOADDO2F.js";
|
|
10
10
|
|
|
11
11
|
// src/commands/search.ts
|
|
12
12
|
async function textSearch(query, options) {
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatBytes
|
|
3
|
+
} from "./chunk-ZDVARBCV.js";
|
|
4
|
+
import {
|
|
5
|
+
apiRequest,
|
|
6
|
+
apiUpload
|
|
7
|
+
} from "./chunk-FEMMZ4YZ.js";
|
|
8
|
+
import "./chunk-2AORPTQB.js";
|
|
9
|
+
|
|
10
|
+
// src/commands/upload.ts
|
|
11
|
+
import { existsSync, readFileSync } from "fs";
|
|
12
|
+
import { basename, resolve } from "path";
|
|
13
|
+
var CONTENT_TYPES = {
|
|
14
|
+
png: "image/png",
|
|
15
|
+
jpg: "image/jpeg",
|
|
16
|
+
jpeg: "image/jpeg",
|
|
17
|
+
gif: "image/gif",
|
|
18
|
+
webp: "image/webp",
|
|
19
|
+
svg: "image/svg+xml",
|
|
20
|
+
ico: "image/x-icon",
|
|
21
|
+
avif: "image/avif",
|
|
22
|
+
pdf: "application/pdf",
|
|
23
|
+
mp4: "video/mp4",
|
|
24
|
+
webm: "video/webm",
|
|
25
|
+
mov: "video/quicktime",
|
|
26
|
+
mp3: "audio/mpeg",
|
|
27
|
+
wav: "audio/wav",
|
|
28
|
+
ogg: "audio/ogg",
|
|
29
|
+
zip: "application/zip",
|
|
30
|
+
tar: "application/x-tar",
|
|
31
|
+
gz: "application/gzip",
|
|
32
|
+
txt: "text/plain",
|
|
33
|
+
json: "application/json",
|
|
34
|
+
xml: "application/xml",
|
|
35
|
+
html: "text/html",
|
|
36
|
+
css: "text/css",
|
|
37
|
+
js: "application/javascript"
|
|
38
|
+
};
|
|
39
|
+
function getContentType(filename) {
|
|
40
|
+
const ext = filename.toLowerCase().split(".").pop();
|
|
41
|
+
return CONTENT_TYPES[ext || ""] || "application/octet-stream";
|
|
42
|
+
}
|
|
43
|
+
function readFile(filePath) {
|
|
44
|
+
const resolvedPath = resolve(filePath);
|
|
45
|
+
if (!existsSync(resolvedPath)) {
|
|
46
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
const buffer = readFileSync(resolvedPath);
|
|
50
|
+
const filename = basename(resolvedPath);
|
|
51
|
+
const contentType = getContentType(filename);
|
|
52
|
+
return { buffer, filename, contentType };
|
|
53
|
+
}
|
|
54
|
+
async function uploadDrop(filePath, options) {
|
|
55
|
+
const { buffer, filename, contentType } = readFile(filePath);
|
|
56
|
+
if (!options.quiet) {
|
|
57
|
+
console.error(`Uploading ${filename} (${formatBytes(buffer.length)})...`);
|
|
58
|
+
}
|
|
59
|
+
const presign = await apiRequest("/api/drops/presign", {
|
|
60
|
+
method: "POST",
|
|
61
|
+
body: JSON.stringify({
|
|
62
|
+
filename,
|
|
63
|
+
contentType,
|
|
64
|
+
size: buffer.length
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
const putRes = await fetch(presign.uploadUrl, {
|
|
68
|
+
method: "PUT",
|
|
69
|
+
headers: { "Content-Type": contentType },
|
|
70
|
+
body: new Uint8Array(buffer)
|
|
71
|
+
});
|
|
72
|
+
if (!putRes.ok) {
|
|
73
|
+
throw new Error(`Upload to storage failed (${putRes.status})`);
|
|
74
|
+
}
|
|
75
|
+
const result = await apiRequest("/api/drops/presign/confirm", {
|
|
76
|
+
method: "POST",
|
|
77
|
+
body: JSON.stringify({
|
|
78
|
+
shortId: presign.shortId,
|
|
79
|
+
r2Key: presign.r2Key,
|
|
80
|
+
size: buffer.length,
|
|
81
|
+
contentType,
|
|
82
|
+
filename,
|
|
83
|
+
...presign.uploadToken ? { uploadToken: presign.uploadToken } : {}
|
|
84
|
+
})
|
|
85
|
+
});
|
|
86
|
+
if (options.quiet) {
|
|
87
|
+
console.log(result.url);
|
|
88
|
+
} else {
|
|
89
|
+
console.error("Done!");
|
|
90
|
+
console.log("");
|
|
91
|
+
console.log(result.url);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function uploadFile(filePath, options) {
|
|
95
|
+
const { buffer, filename, contentType } = readFile(filePath);
|
|
96
|
+
if (!options.quiet) {
|
|
97
|
+
console.error(`Uploading ${filename} (${formatBytes(buffer.length)})...`);
|
|
98
|
+
}
|
|
99
|
+
let path = "/api/upload";
|
|
100
|
+
if (options.bucket) {
|
|
101
|
+
path += `?bucket=${encodeURIComponent(options.bucket)}`;
|
|
102
|
+
}
|
|
103
|
+
const result = await apiUpload(
|
|
104
|
+
path,
|
|
105
|
+
buffer,
|
|
106
|
+
filename,
|
|
107
|
+
contentType
|
|
108
|
+
);
|
|
109
|
+
if (options.quiet) {
|
|
110
|
+
console.log(result.url);
|
|
111
|
+
} else {
|
|
112
|
+
console.error("Done!");
|
|
113
|
+
console.log("");
|
|
114
|
+
console.log(result.url);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export {
|
|
118
|
+
uploadDrop,
|
|
119
|
+
uploadFile
|
|
120
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatBytes
|
|
3
|
+
} from "./chunk-ELSDWMEB.js";
|
|
4
|
+
import {
|
|
5
|
+
createStow
|
|
6
|
+
} from "./chunk-5LU25QZK.js";
|
|
7
|
+
import "./chunk-TOADDO2F.js";
|
|
8
|
+
|
|
9
|
+
// src/commands/upload.ts
|
|
10
|
+
import { existsSync, readFileSync } from "fs";
|
|
11
|
+
import { basename, resolve } from "path";
|
|
12
|
+
var CONTENT_TYPES = {
|
|
13
|
+
png: "image/png",
|
|
14
|
+
jpg: "image/jpeg",
|
|
15
|
+
jpeg: "image/jpeg",
|
|
16
|
+
gif: "image/gif",
|
|
17
|
+
webp: "image/webp",
|
|
18
|
+
svg: "image/svg+xml",
|
|
19
|
+
ico: "image/x-icon",
|
|
20
|
+
avif: "image/avif",
|
|
21
|
+
pdf: "application/pdf",
|
|
22
|
+
mp4: "video/mp4",
|
|
23
|
+
webm: "video/webm",
|
|
24
|
+
mov: "video/quicktime",
|
|
25
|
+
mp3: "audio/mpeg",
|
|
26
|
+
wav: "audio/wav",
|
|
27
|
+
ogg: "audio/ogg",
|
|
28
|
+
zip: "application/zip",
|
|
29
|
+
tar: "application/x-tar",
|
|
30
|
+
gz: "application/gzip",
|
|
31
|
+
txt: "text/plain",
|
|
32
|
+
json: "application/json",
|
|
33
|
+
xml: "application/xml",
|
|
34
|
+
html: "text/html",
|
|
35
|
+
css: "text/css",
|
|
36
|
+
js: "application/javascript"
|
|
37
|
+
};
|
|
38
|
+
function getContentType(filename) {
|
|
39
|
+
const ext = filename.toLowerCase().split(".").pop();
|
|
40
|
+
return CONTENT_TYPES[ext || ""] || "application/octet-stream";
|
|
41
|
+
}
|
|
42
|
+
function readFile(filePath) {
|
|
43
|
+
const resolvedPath = resolve(filePath);
|
|
44
|
+
if (!existsSync(resolvedPath)) {
|
|
45
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
const buffer = readFileSync(resolvedPath);
|
|
49
|
+
const filename = basename(resolvedPath);
|
|
50
|
+
const contentType = getContentType(filename);
|
|
51
|
+
return { buffer, filename, contentType };
|
|
52
|
+
}
|
|
53
|
+
function printUploadResult(url, options, opts) {
|
|
54
|
+
if (options.quiet) {
|
|
55
|
+
console.log(url);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
console.error(opts?.deduped ? "Done! (deduped)" : "Done!");
|
|
59
|
+
console.log("");
|
|
60
|
+
console.log(url);
|
|
61
|
+
}
|
|
62
|
+
async function uploadDrop(filePath, options) {
|
|
63
|
+
const { buffer, filename, contentType } = readFile(filePath);
|
|
64
|
+
if (!options.quiet) {
|
|
65
|
+
console.error(`Uploading ${filename} (${formatBytes(buffer.length)})...`);
|
|
66
|
+
}
|
|
67
|
+
const stow = createStow();
|
|
68
|
+
const result = await stow.drop(buffer, {
|
|
69
|
+
filename,
|
|
70
|
+
contentType
|
|
71
|
+
});
|
|
72
|
+
printUploadResult(result.url, options);
|
|
73
|
+
}
|
|
74
|
+
async function uploadFile(filePath, options) {
|
|
75
|
+
const { buffer, filename, contentType } = readFile(filePath);
|
|
76
|
+
if (!options.quiet) {
|
|
77
|
+
console.error(`Uploading ${filename} (${formatBytes(buffer.length)})...`);
|
|
78
|
+
}
|
|
79
|
+
const stow = createStow();
|
|
80
|
+
const result = await stow.uploadFile(buffer, {
|
|
81
|
+
...options.bucket ? { bucket: options.bucket } : {},
|
|
82
|
+
filename,
|
|
83
|
+
contentType
|
|
84
|
+
});
|
|
85
|
+
printUploadResult(result.url ?? result.key, options, {
|
|
86
|
+
deduped: result.deduped
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
uploadDrop,
|
|
91
|
+
uploadFile
|
|
92
|
+
};
|