@decentnetwork/beagle 0.1.37 → 0.1.38
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/desktop/app.js +60 -25
- package/dist/server.js +30 -7
- package/package.json +1 -1
package/dist/desktop/app.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
window.__DK_UI_VERSION="0.1.
|
|
1
|
+
window.__DK_UI_VERSION="0.1.37";
|
|
2
2
|
const ICON_PATHS = {
|
|
3
3
|
// ---- tab bar (the four must feel like one set) ----
|
|
4
4
|
users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
|
|
@@ -2056,33 +2056,68 @@ function Msg({ m, peer, T, onTheater, onDelete, onCancel, onRetry, onReveal, onC
|
|
|
2056
2056
|
const meta = /* @__PURE__ */ React.createElement("div", { style: { minWidth: 0, flex: 1 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 12.5, fontWeight: 600, color: mine ? "#fff" : "var(--text)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" } }, m.file.name), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 11, color: mine ? "rgba(255,255,255,0.7)" : "var(--faint)", marginTop: 1 } }, busy === "cancel" ? `${m.file.size} \xB7 ${T.cancelling || "Cancelling\u2026"}` : busy === "retry" ? `${m.file.size} \xB7 ${T.retrying || "Retrying\u2026"}` : m.file.status === "queued" ? `${m.file.size} \xB7 ${T.queued || "queued"}` : m.file.status === "sending" ? `${m.file.size} \xB7 ${dkPct(m.file.pct)}${m.file.kbps ? " \xB7 " + dkSpeed(m.file.kbps) : ""}` : m.file.status === "failed" ? `${m.file.size} \xB7 failed` : m.file.status === "cancelled" ? `${m.file.size} \xB7 ${T.cancelled || "cancelled"}` : mine ? `${m.file.size} \xB7 sent` : `${m.file.size} \xB7 ${T.open || "open"}`));
|
|
2057
2057
|
if (mine) {
|
|
2058
2058
|
const btnBusy = !!busy;
|
|
2059
|
-
return /* @__PURE__ */ React.createElement(
|
|
2060
|
-
"
|
|
2059
|
+
return /* @__PURE__ */ React.createElement(
|
|
2060
|
+
"div",
|
|
2061
2061
|
{
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
onClick: (
|
|
2065
|
-
e.stopPropagation();
|
|
2066
|
-
if (!btnBusy)
|
|
2067
|
-
onCancel(m.id);
|
|
2068
|
-
},
|
|
2069
|
-
style: { background: "rgba(255,255,255,0.16)", border: "none", borderRadius: 6, cursor: btnBusy ? "wait" : "pointer", padding: 3, marginLeft: 2, display: "inline-flex", flexShrink: 0, opacity: btnBusy ? 0.5 : 1 }
|
|
2062
|
+
style: { ...cardStyle, cursor: "pointer", opacity: btnBusy ? 0.85 : 1 },
|
|
2063
|
+
title: T.open || "open",
|
|
2064
|
+
onClick: () => window.open(dkFileUrl(m.file.name), "_blank", "noopener")
|
|
2070
2065
|
},
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2066
|
+
icon,
|
|
2067
|
+
meta,
|
|
2068
|
+
onReveal && /* @__PURE__ */ React.createElement(
|
|
2069
|
+
"button",
|
|
2070
|
+
{
|
|
2071
|
+
title: T.revealInFinder || "\u5728\u6587\u4EF6\u7BA1\u7406\u5668\u4E2D\u663E\u793A / Show in file manager",
|
|
2072
|
+
onClick: (e) => {
|
|
2073
|
+
e.stopPropagation();
|
|
2074
|
+
onReveal(m.file.name);
|
|
2075
|
+
},
|
|
2076
|
+
style: { background: "none", border: "none", cursor: "pointer", padding: 0, display: "inline-flex", flexShrink: 0 }
|
|
2081
2077
|
},
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
/* @__PURE__ */ React.createElement(
|
|
2085
|
-
|
|
2078
|
+
/* @__PURE__ */ React.createElement(Icon, { name: "folderOpen", size: 15, stroke: 2, color: "rgba(255,255,255,0.85)" })
|
|
2079
|
+
),
|
|
2080
|
+
/* @__PURE__ */ React.createElement(
|
|
2081
|
+
"a",
|
|
2082
|
+
{
|
|
2083
|
+
href: dkFileDownloadUrl(m.file.name),
|
|
2084
|
+
download: m.file.name,
|
|
2085
|
+
title: "download",
|
|
2086
|
+
onClick: (e) => e.stopPropagation(),
|
|
2087
|
+
style: { display: "inline-flex", flexShrink: 0 }
|
|
2088
|
+
},
|
|
2089
|
+
/* @__PURE__ */ React.createElement(Icon, { name: "download", size: 15, stroke: 2, color: "rgba(255,255,255,0.85)" })
|
|
2090
|
+
),
|
|
2091
|
+
busy === "cancel" || busy === "retry" ? /* @__PURE__ */ React.createElement(Icon, { name: "clock", size: 16, stroke: 2, color: "rgba(255,255,255,0.85)" }) : m.file.status === "queued" ? /* @__PURE__ */ React.createElement(Icon, { name: "clock", size: 16, stroke: 2, color: "rgba(255,255,255,0.85)" }) : m.file.status === "sending" ? /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 11, fontWeight: 700, color: "rgba(255,255,255,0.9)", whiteSpace: "nowrap" } }, dkPct(m.file.pct), m.file.kbps ? " \xB7 " + dkSpeed(m.file.kbps) : "") : m.file.status === "failed" || m.file.status === "cancelled" ? /* @__PURE__ */ React.createElement(Icon, { name: "x", size: 16, stroke: 2.4, color: "rgba(255,200,190,0.95)" }) : /* @__PURE__ */ React.createElement(Icon, { name: "checkCheck", size: 16, stroke: 2, color: "rgba(255,255,255,0.85)" }),
|
|
2092
|
+
(m.file.status === "sending" || m.file.status === "queued" || busy === "cancel") && m.id && /* @__PURE__ */ React.createElement(
|
|
2093
|
+
"button",
|
|
2094
|
+
{
|
|
2095
|
+
title: T.cancel || "cancel",
|
|
2096
|
+
disabled: btnBusy,
|
|
2097
|
+
onClick: (e) => {
|
|
2098
|
+
e.stopPropagation();
|
|
2099
|
+
if (!btnBusy)
|
|
2100
|
+
onCancel(m.id);
|
|
2101
|
+
},
|
|
2102
|
+
style: { background: "rgba(255,255,255,0.16)", border: "none", borderRadius: 6, cursor: btnBusy ? "wait" : "pointer", padding: 3, marginLeft: 2, display: "inline-flex", flexShrink: 0, opacity: btnBusy ? 0.5 : 1 }
|
|
2103
|
+
},
|
|
2104
|
+
/* @__PURE__ */ React.createElement(Icon, { name: "x", size: 13, stroke: 2.4, color: "#fff" })
|
|
2105
|
+
),
|
|
2106
|
+
m.file.status !== "sent" && m.id && /* @__PURE__ */ React.createElement(
|
|
2107
|
+
"button",
|
|
2108
|
+
{
|
|
2109
|
+
title: T.retry || "retry",
|
|
2110
|
+
disabled: btnBusy,
|
|
2111
|
+
onClick: (e) => {
|
|
2112
|
+
e.stopPropagation();
|
|
2113
|
+
if (!btnBusy)
|
|
2114
|
+
onRetry(m.id);
|
|
2115
|
+
},
|
|
2116
|
+
style: { background: "rgba(255,255,255,0.16)", border: "none", borderRadius: 6, cursor: btnBusy ? "wait" : "pointer", padding: 3, marginLeft: 2, display: "inline-flex", flexShrink: 0, opacity: btnBusy ? 0.5 : 1 }
|
|
2117
|
+
},
|
|
2118
|
+
/* @__PURE__ */ React.createElement(Icon, { name: "refresh", size: 13, stroke: 2.2, color: "#fff" })
|
|
2119
|
+
)
|
|
2120
|
+
);
|
|
2086
2121
|
}
|
|
2087
2122
|
return /* @__PURE__ */ React.createElement(
|
|
2088
2123
|
"div",
|
package/dist/server.js
CHANGED
|
@@ -956,8 +956,10 @@ export function startBeagleServer(opts) {
|
|
|
956
956
|
}
|
|
957
957
|
// ── File transfer ──────────────────────────────────────────────────
|
|
958
958
|
// Upload: the browser POSTs raw file bytes with ?userid=&name= in the
|
|
959
|
-
// query.
|
|
960
|
-
//
|
|
959
|
+
// query. The upload is saved INTO downloads/ (collision-renamed) and
|
|
960
|
+
// kept — the sender's own chip can then open / reveal / download the
|
|
961
|
+
// file just like the receiver's. (It used to stream to a temp file
|
|
962
|
+
// deleted right after send, which made every sent chip a dead end.)
|
|
961
963
|
if (req.method === "POST" && url === "/api/file-send") {
|
|
962
964
|
const q = new URL(req.url || "", "http://x").searchParams;
|
|
963
965
|
const userid = q.get("userid") || "";
|
|
@@ -970,17 +972,37 @@ export function startBeagleServer(opts) {
|
|
|
970
972
|
const os = await import("node:os");
|
|
971
973
|
const fs = await import("node:fs");
|
|
972
974
|
const fsp = await import("node:fs/promises");
|
|
973
|
-
|
|
974
|
-
|
|
975
|
+
// Keep the copy under downloads when available (normal case); fall
|
|
976
|
+
// back to the old ephemeral temp only when downloads are disabled.
|
|
977
|
+
const keep = !!opts.downloadsDir;
|
|
978
|
+
let destDir;
|
|
979
|
+
if (keep) {
|
|
980
|
+
destDir = opts.downloadsDir;
|
|
981
|
+
await fsp.mkdir(destDir, { recursive: true });
|
|
982
|
+
}
|
|
983
|
+
else {
|
|
984
|
+
destDir = await fsp.mkdtemp(join(os.tmpdir(), "agentnet-up-"));
|
|
985
|
+
}
|
|
986
|
+
let destName = safe;
|
|
987
|
+
let destPath = join(destDir, destName);
|
|
988
|
+
if (keep) {
|
|
989
|
+
const dot = safe.lastIndexOf(".");
|
|
990
|
+
const base = dot > 0 ? safe.slice(0, dot) : safe;
|
|
991
|
+
const ext = dot > 0 ? safe.slice(dot) : "";
|
|
992
|
+
for (let i = 1; existsSync(destPath); i++) {
|
|
993
|
+
destName = `${base}-${i}${ext}`;
|
|
994
|
+
destPath = join(destDir, destName);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
975
997
|
try {
|
|
976
998
|
await new Promise((resolve2, reject) => {
|
|
977
|
-
const ws = fs.createWriteStream(
|
|
999
|
+
const ws = fs.createWriteStream(destPath);
|
|
978
1000
|
req.pipe(ws);
|
|
979
1001
|
req.on("error", reject);
|
|
980
1002
|
ws.on("error", reject);
|
|
981
1003
|
ws.on("finish", () => resolve2());
|
|
982
1004
|
});
|
|
983
|
-
const r = await opts.call({ op: "file-send", userid, path:
|
|
1005
|
+
const r = await opts.call({ op: "file-send", userid, path: destPath });
|
|
984
1006
|
if (!r.ok) {
|
|
985
1007
|
sendJson(res, 502, r);
|
|
986
1008
|
return;
|
|
@@ -991,7 +1013,8 @@ export function startBeagleServer(opts) {
|
|
|
991
1013
|
sendJson(res, 500, { ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
992
1014
|
}
|
|
993
1015
|
finally {
|
|
994
|
-
|
|
1016
|
+
if (!keep)
|
|
1017
|
+
await fsp.rm(destDir, { recursive: true, force: true }).catch(() => undefined);
|
|
995
1018
|
}
|
|
996
1019
|
return;
|
|
997
1020
|
}
|
package/package.json
CHANGED