@decentnetwork/beagle 0.1.26 → 0.1.28
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 +87 -10
- package/dist/server.js +53 -8
- 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.27";
|
|
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"/>',
|
|
@@ -2593,7 +2593,7 @@ ${peer.address}`
|
|
|
2593
2593
|
style: { maxWidth: "100%", maxHeight: "100%", objectFit: "contain", borderRadius: 6 }
|
|
2594
2594
|
}
|
|
2595
2595
|
))),
|
|
2596
|
-
pubProfile && /* @__PURE__ */ React.createElement(DkPublicProfile, { T, userid: peer.userId, fallbackName: peer.alias, onClose: () => setPubProfile(false) })
|
|
2596
|
+
pubProfile && /* @__PURE__ */ React.createElement(DkPublicProfile, { T, userid: peer.userId, fallbackName: peer.alias, isFriend: true, onClose: () => setPubProfile(false) })
|
|
2597
2597
|
);
|
|
2598
2598
|
}
|
|
2599
2599
|
function MenuItem({ icon, label, onClick, danger }) {
|
|
@@ -2928,8 +2928,13 @@ function DkPunkPicker({ T, onPick, onClose }) {
|
|
|
2928
2928
|
/* @__PURE__ */ React.createElement("img", { src: p.image, alt: `punk #${p.id}`, style: { width: "100%", height: "100%", imageRendering: "pixelated", display: "block" } })
|
|
2929
2929
|
))))));
|
|
2930
2930
|
}
|
|
2931
|
-
function DkPublicProfile({ T, userid, fallbackName, onClose }) {
|
|
2931
|
+
function DkPublicProfile({ T, userid, fallbackName, onClose, isFriend, isMe }) {
|
|
2932
2932
|
const [st, setSt] = React.useState({ loading: true });
|
|
2933
|
+
const [addState, setAddState] = React.useState(null);
|
|
2934
|
+
const addFriend = (address) => {
|
|
2935
|
+
setAddState("busy");
|
|
2936
|
+
fetch("/api/add", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ address }) }).then((r) => r.json()).then((r) => setAddState(r.ok !== false ? "sent" : r.error || T.addFailed || "failed")).catch((e) => setAddState(String(e && e.message || e)));
|
|
2937
|
+
};
|
|
2933
2938
|
React.useEffect(() => {
|
|
2934
2939
|
let dead = false;
|
|
2935
2940
|
setSt({ loading: true });
|
|
@@ -2960,7 +2965,25 @@ function DkPublicProfile({ T, userid, fallbackName, onClose }) {
|
|
|
2960
2965
|
},
|
|
2961
2966
|
k,
|
|
2962
2967
|
" \u2197"
|
|
2963
|
-
))), prof.eth && /* @__PURE__ */ React.createElement("div", { style: rowS }, /* @__PURE__ */ React.createElement("span", { style: lbl }, "ethereum"), /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: prof.eth, title: prof.eth }, shortKey(prof.eth, 8, 6))), prof.sol && /* @__PURE__ */ React.createElement("div", { style: rowS }, /* @__PURE__ */ React.createElement("span", { style: lbl }, "solana"), /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: prof.sol, title: prof.sol }, shortKey(prof.sol, 8, 6))), /* @__PURE__ */ React.createElement("div", { style: rowS }, /* @__PURE__ */ React.createElement("span", { style: lbl }, T.userId || "user id"), /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: userid, title: userid }, shortKey(userid, 10, 6))))))
|
|
2968
|
+
))), prof.eth && /* @__PURE__ */ React.createElement("div", { style: rowS }, /* @__PURE__ */ React.createElement("span", { style: lbl }, "ethereum"), /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: prof.eth, title: prof.eth }, shortKey(prof.eth, 8, 6))), prof.sol && /* @__PURE__ */ React.createElement("div", { style: rowS }, /* @__PURE__ */ React.createElement("span", { style: lbl }, "solana"), /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: prof.sol, title: prof.sol }, shortKey(prof.sol, 8, 6))), /* @__PURE__ */ React.createElement("div", { style: rowS }, /* @__PURE__ */ React.createElement("span", { style: lbl }, T.userId || "user id"), /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: userid, title: userid }, shortKey(userid, 10, 6))), !isMe && !isFriend && prof.address && /* @__PURE__ */ React.createElement("div", { style: { ...rowS, justifyContent: "flex-end" } }, addState === "sent" ? /* @__PURE__ */ React.createElement(Tag, { tone: "accent" }, T.dirSent || "requested") : addState && addState !== "busy" ? /* @__PURE__ */ React.createElement("span", { title: addState, style: { fontFamily: "var(--ui)", fontSize: 11.5, color: "var(--warn, #f59e0b)" } }, T.addFailed || "failed") : /* @__PURE__ */ React.createElement(
|
|
2969
|
+
"button",
|
|
2970
|
+
{
|
|
2971
|
+
onClick: () => addFriend(prof.address),
|
|
2972
|
+
disabled: addState === "busy",
|
|
2973
|
+
style: {
|
|
2974
|
+
padding: "7px 16px",
|
|
2975
|
+
borderRadius: 9,
|
|
2976
|
+
border: "none",
|
|
2977
|
+
cursor: addState === "busy" ? "default" : "pointer",
|
|
2978
|
+
background: "var(--accent)",
|
|
2979
|
+
color: "#fff",
|
|
2980
|
+
fontFamily: "var(--ui)",
|
|
2981
|
+
fontSize: 12.5,
|
|
2982
|
+
opacity: addState === "busy" ? 0.6 : 1
|
|
2983
|
+
}
|
|
2984
|
+
},
|
|
2985
|
+
addState === "busy" ? "\u2026" : T.dirAdd || "Add"
|
|
2986
|
+
)))));
|
|
2964
2987
|
}
|
|
2965
2988
|
function DkEnsCard({ T, me, onRecord }) {
|
|
2966
2989
|
const [st, setSt] = React.useState({ loading: true });
|
|
@@ -3146,6 +3169,22 @@ function DkEnsCard({ T, me, onRecord }) {
|
|
|
3146
3169
|
}
|
|
3147
3170
|
), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 12.5, color: "var(--dim)", flexShrink: 0 } }, ".beagles.eth"), /* @__PURE__ */ React.createElement(Btn, { tone: "accent", size: "sm", disabled: busy || !label.trim(), onClick: register }, busy ? "\u2026" : st.registered && st.mineOwned ? T.ensUpdate || "update" : T.ensRegister || "register")), st.registered && !st.mineOwned && /* @__PURE__ */ React.createElement("div", { style: { padding: "10px 16px", borderBottom: "1px solid var(--line)", fontFamily: "var(--ui)", fontSize: 11.5, color: "var(--faint)" } }, (T.ensWalletOwned || "registered via your mobile wallet as") + " ", /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)" } }, rec && rec.name)), st.registered && /* @__PURE__ */ React.createElement("div", { style: row }, /* @__PURE__ */ React.createElement("span", { style: { width: 130, flexShrink: 0, fontFamily: "var(--mono)", fontSize: 11.5, fontWeight: 600, color: "var(--faint)", textTransform: "uppercase", letterSpacing: 0.5 } }, T.ensAvatar || "avatar"), upAvatar ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("img", { src: upAvatar, alt: "", width: 34, height: 34, style: { width: 34, height: 34, borderRadius: 9, objectFit: "cover", flexShrink: 0, background: "var(--panel-2)" } }), /* @__PURE__ */ React.createElement("span", { style: { flex: 1, minWidth: 0, fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--text)" } }, T.ensCustom || "custom image"), /* @__PURE__ */ React.createElement(Btn, { size: "sm", tone: "danger", disabled: busy || !st.mineOwned, onClick: () => post("/api/ens-avatar", { nftid: null }) }, T.ensClear || "clear")) : punkId != null ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(DkPunkAvatar, { id: punkId, size: 34, radius: 9, fallbackSeed: me.userId }), /* @__PURE__ */ React.createElement("span", { style: { flex: 1, minWidth: 0, fontFamily: "var(--mono)", fontSize: 12.5, color: "var(--text)" } }, `CryptoPunk #${punkId}`), /* @__PURE__ */ React.createElement(Btn, { size: "sm", tone: "danger", disabled: busy || !st.mineOwned, onClick: () => post("/api/ens-avatar", { nftid: null }) }, T.ensClear || "clear")) : /* @__PURE__ */ React.createElement("span", { style: { flex: 1, fontFamily: "var(--ui)", fontSize: 12, color: "var(--faint)" } }, T.ensNotSet || "not set"), /* @__PURE__ */ React.createElement(Btn, { size: "sm", disabled: busy || !st.mineOwned, onClick: () => fileRef.current && fileRef.current.click() }, T.ensUpload || "upload"), /* @__PURE__ */ React.createElement(Btn, { size: "sm", disabled: busy || !st.mineOwned, onClick: () => setPicking(true) }, T.ensChoose || "choose"), /* @__PURE__ */ React.createElement("input", { ref: fileRef, type: "file", accept: "image/*", onChange: onUploadFile, style: { display: "none" } })), walletRow(T.ensEth || "ethereum", "eth", boundEth, bindEth, false), walletRow(T.ensSol || "solana", "sol", boundSol, bindSol, !msg), msg && /* @__PURE__ */ React.createElement("div", { style: { padding: "10px 16px", fontFamily: "var(--ui)", fontSize: 12, color: msg.tone === "ok" ? "var(--online)" : "var(--danger)" } }, msg.text)), picking && /* @__PURE__ */ React.createElement(DkPunkPicker, { T, onPick: pickPunk, onClose: () => setPicking(false) })), !st.loading && st.registered && /* @__PURE__ */ React.createElement(Card, { label: T.linksCard || "Links" }, SOCIALS.map((s, i) => socialRow(s, i === SOCIALS.length - 1))));
|
|
3148
3171
|
}
|
|
3172
|
+
function DkUpdateCheck({ T }) {
|
|
3173
|
+
const [st, setSt] = React.useState("idle");
|
|
3174
|
+
const [info, setInfo] = React.useState(null);
|
|
3175
|
+
const check = () => {
|
|
3176
|
+
setSt("busy");
|
|
3177
|
+
fetch("/api/update-check?force=1").then((r) => r.json()).then((d) => {
|
|
3178
|
+
const behind = (d && d.updates || []).filter((u) => u.behind);
|
|
3179
|
+
if (d && d.ok && behind.length) {
|
|
3180
|
+
setInfo(d);
|
|
3181
|
+
setSt("idle");
|
|
3182
|
+
} else
|
|
3183
|
+
setSt("latest");
|
|
3184
|
+
}).catch(() => setSt("idle"));
|
|
3185
|
+
};
|
|
3186
|
+
return /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 14, padding: "13px 16px" } }, /* @__PURE__ */ React.createElement("span", { style: { width: 130, flexShrink: 0, fontFamily: "var(--mono)", fontSize: 11.5, fontWeight: 600, color: "var(--faint)", textTransform: "uppercase", letterSpacing: 0.5 } }, T.updCheckLabel || "updates"), /* @__PURE__ */ React.createElement("span", { style: { flex: 1, fontFamily: "var(--ui)", fontSize: 12, color: st === "latest" ? "var(--online)" : "var(--faint)" } }, st === "latest" ? T.updLatest || "up to date \u2713" : ""), /* @__PURE__ */ React.createElement(Btn, { size: "sm", disabled: st === "busy", onClick: check }, st === "busy" ? "\u2026" : T.updCheck || "check for updates"), info && /* @__PURE__ */ React.createElement(DkUpdateModal, { T, info, onClose: () => setInfo(null) }));
|
|
3187
|
+
}
|
|
3149
3188
|
function ProfileTab({ T, me, onEdit }) {
|
|
3150
3189
|
const [qr, setQr] = React.useState(null);
|
|
3151
3190
|
const [editing, setEditing] = React.useState(false);
|
|
@@ -3164,7 +3203,7 @@ function ProfileTab({ T, me, onEdit }) {
|
|
|
3164
3203
|
},
|
|
3165
3204
|
style: { width: 16, height: 16, accentColor: "var(--accent)" }
|
|
3166
3205
|
}
|
|
3167
|
-
), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 600, color: "var(--text)" } }, T && T.autoAcceptLabel || "Auto-accept friend requests"), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 11.5, color: "var(--dim)", marginTop: 2 } }, T && T.autoAcceptSub || "Off: requests wait in the sidebar for your approval.")))), /* @__PURE__ */ React.createElement(Card, { label: T.network }, /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.virtualIp, value: me.ip, copy: true }), /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.wireLabel, value: `${me.wire} \xB7 lossless`, mono: false }), /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.version, value: `lan ${me.lanVer} \xB7 peer ${me.peerVer} \xB7 ${me.channel}
|
|
3206
|
+
), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 600, color: "var(--text)" } }, T && T.autoAcceptLabel || "Auto-accept friend requests"), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 11.5, color: "var(--dim)", marginTop: 2 } }, T && T.autoAcceptSub || "Off: requests wait in the sidebar for your approval.")))), /* @__PURE__ */ React.createElement(Card, { label: T.network }, /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.virtualIp, value: me.ip, copy: true }), /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.wireLabel, value: `${me.wire} \xB7 lossless`, mono: false }), /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.version, value: `lan ${me.lanVer} \xB7 peer ${me.peerVer} \xB7 ${me.channel}` }), /* @__PURE__ */ React.createElement(DkUpdateCheck, { T })), /* @__PURE__ */ React.createElement(Card, { label: T.dangerZone }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 13, padding: "14px 16px" } }, /* @__PURE__ */ React.createElement("div", { style: { width: 34, height: 34, borderRadius: 8, flexShrink: 0, background: "color-mix(in oklab, var(--danger), transparent 86%)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--danger)" } }, /* @__PURE__ */ React.createElement(Icon, { name: "trash", size: 17, stroke: 2 })), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 600, color: "var(--danger)" } }, T.deleteNode), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--faint)", marginTop: 1 } }, T.deleteSub)), /* @__PURE__ */ React.createElement(Btn, { tone: "danger", size: "sm" }, T.delete)))), qr && /* @__PURE__ */ React.createElement(DkQrModal, { T, value: qr.value, label: qr.label, onClose: () => setQr(null) }), editing && /* @__PURE__ */ React.createElement(DkEditModal, { T, me, onClose: () => setEditing(false), onSave: (name, description) => {
|
|
3168
3207
|
if (onEdit)
|
|
3169
3208
|
onEdit(name, description);
|
|
3170
3209
|
setEditing(false);
|
|
@@ -3293,7 +3332,17 @@ function DiscoverTab({ T, kind, peers, meId, onAdd, onOpenChat }) {
|
|
|
3293
3332
|
onOpenChat,
|
|
3294
3333
|
onOpenProfile: (row) => setProf({ userid: row.userid, name: row.name })
|
|
3295
3334
|
}
|
|
3296
|
-
))), prof && /* @__PURE__ */ React.createElement(
|
|
3335
|
+
))), prof && /* @__PURE__ */ React.createElement(
|
|
3336
|
+
DkPublicProfile,
|
|
3337
|
+
{
|
|
3338
|
+
T,
|
|
3339
|
+
userid: prof.userid,
|
|
3340
|
+
fallbackName: prof.name,
|
|
3341
|
+
onClose: () => setProf(null),
|
|
3342
|
+
isFriend: friendIds.has(prof.userid),
|
|
3343
|
+
isMe: !!meId && prof.userid === meId
|
|
3344
|
+
}
|
|
3345
|
+
));
|
|
3297
3346
|
}
|
|
3298
3347
|
const DK_FILE_RTC_KIND = "file";
|
|
3299
3348
|
const DK_FILE_RTC_CHUNK = 16 * 1024;
|
|
@@ -4238,7 +4287,13 @@ const STR = {
|
|
|
4238
4287
|
updRestarting: "Restarting\u2026 this page reloads when it\u2019s back. (If beagle was started by hand in a terminal, run it again.)",
|
|
4239
4288
|
updNpx: "Running via npx \u2014 restarting picks up the latest version automatically.",
|
|
4240
4289
|
updDev: "Running from a source checkout \u2014 update with:",
|
|
4241
|
-
updLanNote: "agentnet (lan)
|
|
4290
|
+
updLanNote: "agentnet (lan): one click reinstalls it and asks the running daemon to restart itself. Manual equivalent:",
|
|
4291
|
+
updCheck: "check for updates",
|
|
4292
|
+
updCheckLabel: "updates",
|
|
4293
|
+
updLatest: "up to date \u2713",
|
|
4294
|
+
updLanNow: "Update lan",
|
|
4295
|
+
updLanDone: "lan updated \u2014 daemon restarted with the new version \u2713",
|
|
4296
|
+
updLanNoRestart: "lan updated, but the daemon was not running (or refused) \u2014 the new version applies on its next start.",
|
|
4242
4297
|
pubOpen: "View public profile",
|
|
4243
4298
|
pubNone: "No public profile \u2014 this user has not registered a beagles.eth name.",
|
|
4244
4299
|
ensNoEthWallet: "no Ethereum wallet extension found (MetaMask\u2026)",
|
|
@@ -4394,7 +4449,13 @@ const STR = {
|
|
|
4394
4449
|
updRestarting: "\u6B63\u5728\u91CD\u542F\u2026\u5B8C\u6210\u540E\u672C\u9875\u4F1A\u81EA\u52A8\u5237\u65B0\u3002(\u5982\u679C beagle \u662F\u5728\u7EC8\u7AEF\u91CC\u624B\u52A8\u542F\u52A8\u7684,\u8BF7\u91CD\u65B0\u8FD0\u884C\u4E00\u6B21\u3002)",
|
|
4395
4450
|
updNpx: "\u4F60\u662F\u7528 npx \u8FD0\u884C\u7684\u2014\u2014\u91CD\u542F\u5373\u81EA\u52A8\u83B7\u53D6\u6700\u65B0\u7248\u3002",
|
|
4396
4451
|
updDev: "\u5F53\u524D\u4ECE\u6E90\u7801\u76EE\u5F55\u8FD0\u884C,\u8BF7\u624B\u52A8\u66F4\u65B0:",
|
|
4397
|
-
updLanNote: "agentnet(lan)\
|
|
4452
|
+
updLanNote: "agentnet(lan):\u4E00\u952E\u91CD\u88C5\u5E76\u8BA9\u8FD0\u884C\u4E2D\u7684 daemon \u81EA\u6211\u91CD\u542F\u3002\u7B49\u4EF7\u624B\u52A8\u547D\u4EE4:",
|
|
4453
|
+
updCheck: "\u68C0\u67E5\u66F4\u65B0",
|
|
4454
|
+
updCheckLabel: "\u66F4\u65B0",
|
|
4455
|
+
updLatest: "\u5DF2\u662F\u6700\u65B0\u7248\u672C \u2713",
|
|
4456
|
+
updLanNow: "\u66F4\u65B0 lan",
|
|
4457
|
+
updLanDone: "lan \u5DF2\u66F4\u65B0\u2014\u2014daemon \u5DF2\u7528\u65B0\u7248\u91CD\u542F \u2713",
|
|
4458
|
+
updLanNoRestart: "lan \u5DF2\u66F4\u65B0,\u4F46 daemon \u672A\u5728\u8FD0\u884C(\u6216\u91CD\u542F\u88AB\u62D2)\u2014\u2014\u4E0B\u6B21\u542F\u52A8\u65F6\u751F\u6548\u3002",
|
|
4398
4459
|
pubOpen: "\u67E5\u770B\u516C\u5F00\u8D44\u6599",
|
|
4399
4460
|
pubNone: "\u6682\u65E0\u516C\u5F00\u8D44\u6599\u2014\u2014\u5BF9\u65B9\u8FD8\u6CA1\u6709\u6CE8\u518C beagles.eth \u540D\u5B57\u3002",
|
|
4400
4461
|
ensNoEthWallet: "\u672A\u68C0\u6D4B\u5230\u4EE5\u592A\u574A\u94B1\u5305\u63D2\u4EF6(MetaMask \u7B49)",
|
|
@@ -4454,7 +4515,7 @@ function DkUpdateModal({ T, info, onClose }) {
|
|
|
4454
4515
|
const doUpdate = () => {
|
|
4455
4516
|
setPhase("running");
|
|
4456
4517
|
setErr(null);
|
|
4457
|
-
fetch("/api/update-run", { method: "POST" }).then((r) => r.json()).then((d) => {
|
|
4518
|
+
fetch("/api/update-run", { method: "POST", headers: { "content-type": "application/json" }, body: "{}" }).then((r) => r.json()).then((d) => {
|
|
4458
4519
|
if (d.ok)
|
|
4459
4520
|
setPhase("done");
|
|
4460
4521
|
else {
|
|
@@ -4466,6 +4527,21 @@ function DkUpdateModal({ T, info, onClose }) {
|
|
|
4466
4527
|
setErr(String(e && e.message || e));
|
|
4467
4528
|
});
|
|
4468
4529
|
};
|
|
4530
|
+
const doLanUpdate = () => {
|
|
4531
|
+
setPhase("running");
|
|
4532
|
+
setErr(null);
|
|
4533
|
+
fetch("/api/update-run", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ pkg: "lan" }) }).then((r) => r.json()).then((d) => {
|
|
4534
|
+
if (d.ok)
|
|
4535
|
+
setPhase(d.restarted ? "lan-done" : "lan-norestart");
|
|
4536
|
+
else {
|
|
4537
|
+
setPhase("error");
|
|
4538
|
+
setErr(d.error || "update failed");
|
|
4539
|
+
}
|
|
4540
|
+
}).catch((e) => {
|
|
4541
|
+
setPhase("error");
|
|
4542
|
+
setErr(String(e && e.message || e));
|
|
4543
|
+
});
|
|
4544
|
+
};
|
|
4469
4545
|
const doRestart = () => {
|
|
4470
4546
|
setPhase("restarting");
|
|
4471
4547
|
fetch("/api/update-restart", { method: "POST" }).catch(() => {
|
|
@@ -4490,7 +4566,7 @@ function DkUpdateModal({ T, info, onClose }) {
|
|
|
4490
4566
|
background: tone ? "var(--accent)" : "transparent",
|
|
4491
4567
|
color: tone ? "#fff" : "var(--text)"
|
|
4492
4568
|
} }, label);
|
|
4493
|
-
return /* @__PURE__ */ React.createElement("div", { style: { position: "fixed", inset: 0, zIndex: 95, background: "color-mix(in oklab, #000, transparent 38%)", display: "flex", alignItems: "center", justifyContent: "center", padding: 24 } }, /* @__PURE__ */ React.createElement("div", { style: { width: 430, maxWidth: "94vw", background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 16, padding: "20px 22px", display: "flex", flexDirection: "column", gap: 14 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 700, color: "var(--text)" } }, T.updTitle || "Update available"), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, behind.map((u) => /* @__PURE__ */ React.createElement("div", { key: u.pkg, style: { display: "flex", alignItems: "center", gap: 10, fontFamily: "var(--mono)", fontSize: 12.5 } }, /* @__PURE__ */ React.createElement("span", { style: { width: 70, color: "var(--faint)" } }, short(u.pkg)), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--dim)" } }, u.current), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--faint)" } }, "\u2192"), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--accent)", fontWeight: 700 } }, u.latest)))), phase === "idle" && appBehind && info.mode === "dev" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updDev || "Running from a source checkout \u2014 update with:", /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("code", { style: { fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--text)" } }, "git pull && npm run build")), phase === "idle" && appBehind && info.mode === "npx" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updNpx || "Running via npx \u2014 restarting picks up the latest version automatically."), lanBehind && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updLanNote || "agentnet (lan)
|
|
4569
|
+
return /* @__PURE__ */ React.createElement("div", { style: { position: "fixed", inset: 0, zIndex: 95, background: "color-mix(in oklab, #000, transparent 38%)", display: "flex", alignItems: "center", justifyContent: "center", padding: 24 } }, /* @__PURE__ */ React.createElement("div", { style: { width: 430, maxWidth: "94vw", background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 16, padding: "20px 22px", display: "flex", flexDirection: "column", gap: 14 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 700, color: "var(--text)" } }, T.updTitle || "Update available"), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, behind.map((u) => /* @__PURE__ */ React.createElement("div", { key: u.pkg, style: { display: "flex", alignItems: "center", gap: 10, fontFamily: "var(--mono)", fontSize: 12.5 } }, /* @__PURE__ */ React.createElement("span", { style: { width: 70, color: "var(--faint)" } }, short(u.pkg)), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--dim)" } }, u.current), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--faint)" } }, "\u2192"), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--accent)", fontWeight: 700 } }, u.latest)))), phase === "idle" && appBehind && info.mode === "dev" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updDev || "Running from a source checkout \u2014 update with:", /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("code", { style: { fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--text)" } }, "git pull && npm run build")), phase === "idle" && appBehind && info.mode === "npx" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updNpx || "Running via npx \u2014 restarting picks up the latest version automatically."), lanBehind && phase === "idle" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updLanNote || "agentnet (lan): one click reinstalls it and asks the running daemon to restart itself. Manual equivalent:", /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("code", { style: { fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--text)", userSelect: "all" } }, "npm i -g @decentnetwork/lan@latest && agentnet restart")), phase === "lan-done" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--online)" } }, T.updLanDone || "lan updated \u2014 daemon restarted with the new version \u2713"), phase === "lan-norestart" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--warn, #f59e0b)" } }, T.updLanNoRestart || "lan updated, but the daemon was not running (or refused) \u2014 the new version applies on its next start."), phase === "running" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--dim)" } }, T.updBusy || "Updating\u2026 (about a minute)"), phase === "done" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--online)" } }, T.updDone || "Updated \u2014 restart to apply."), phase === "restarting" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--dim)" } }, T.updRestarting || "Restarting\u2026 this page reloads when it\u2019s back. (If beagle was started by hand in a terminal, run it again.)"), phase === "error" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--danger)", wordBreak: "break-word" } }, err), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 } }, (phase === "idle" || phase === "error" || phase === "lan-done" || phase === "lan-norestart") && btn(phase === "idle" ? T.updLater || "Later" : T.receivedClose || "Close", onClose), phase === "idle" && lanBehind && btn(T.updLanNow || "Update lan", doLanUpdate, !appBehind), phase === "idle" && appBehind && info.mode === "global" && btn(T.updNow || "Update now", doUpdate, true), phase === "idle" && appBehind && info.mode === "npx" && btn(T.updRestart || "Restart", doRestart, true), phase === "done" && btn(T.updRestart || "Restart", doRestart, true))));
|
|
4494
4570
|
}
|
|
4495
4571
|
function DkApp() {
|
|
4496
4572
|
const [t, setTweak] = useTweaks(DK_DEFAULTS);
|
|
@@ -4748,4 +4824,5 @@ function DkApp() {
|
|
|
4748
4824
|
}
|
|
4749
4825
|
));
|
|
4750
4826
|
}
|
|
4827
|
+
Object.assign(window, { DkUpdateModal });
|
|
4751
4828
|
ReactDOM.createRoot(document.getElementById("root")).render(/* @__PURE__ */ React.createElement(DkApp, null));
|
package/dist/server.js
CHANGED
|
@@ -158,6 +158,8 @@ function ensPubFromEntry(ens, v) {
|
|
|
158
158
|
const t = v?.texts ?? {};
|
|
159
159
|
return {
|
|
160
160
|
ens,
|
|
161
|
+
// Shareable Carrier address — lets the profile card offer add-friend.
|
|
162
|
+
address: t.carrierAddress || null,
|
|
161
163
|
avatarUrl: t.avatar || null,
|
|
162
164
|
punkId: v?.nft === "CryptoPunks" && typeof v?.nftid === "number" && v.nftid > 0 ? v.nftid : null,
|
|
163
165
|
displayName: t.displayName || null,
|
|
@@ -241,12 +243,12 @@ function verLt(a, b) {
|
|
|
241
243
|
}
|
|
242
244
|
return false;
|
|
243
245
|
}
|
|
244
|
-
/** Run `npm i -g
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
async function
|
|
246
|
+
/** Run `npm i -g <pkg>@latest`. npm is found on PATH, else via npm-cli.js
|
|
247
|
+
* next to the running node (covers pm2/cron environments whose PATH lacks
|
|
248
|
+
* the nvm shims). */
|
|
249
|
+
async function npmGlobalInstall(pkg) {
|
|
248
250
|
const { spawn } = await import("node:child_process");
|
|
249
|
-
const args = ["i", "-g", `${
|
|
251
|
+
const args = ["i", "-g", `${pkg}@latest`];
|
|
250
252
|
const npmCli = join(dirname(process.execPath), "..", "lib", "node_modules", "npm", "bin", "npm-cli.js");
|
|
251
253
|
const attempts = [
|
|
252
254
|
{ cmd: "npm", args },
|
|
@@ -268,11 +270,40 @@ async function npmSelfUpdate() {
|
|
|
268
270
|
if (r.code === 0)
|
|
269
271
|
return { ok: true, log: tail };
|
|
270
272
|
const hint = /EACCES|permission denied/i.test(r.out)
|
|
271
|
-
?
|
|
273
|
+
? ` — no write access to the global npm dir; run \`sudo npm i -g ${pkg}@latest\` manually`
|
|
272
274
|
: "";
|
|
273
275
|
return { ok: false, error: `npm exited ${r.code}${hint}`, log: tail };
|
|
274
276
|
}
|
|
275
|
-
return { ok: false, error:
|
|
277
|
+
return { ok: false, error: `npm not found — update manually: npm i -g ${pkg}@latest` };
|
|
278
|
+
}
|
|
279
|
+
/** Ask the running agentnet daemon to re-exec itself so it picks up the
|
|
280
|
+
* just-installed lan version. Tries the PATH binary, then the global
|
|
281
|
+
* install's CLI entry directly (pm2 PATH often lacks the nvm shims). */
|
|
282
|
+
async function agentnetRestart() {
|
|
283
|
+
const { spawn } = await import("node:child_process");
|
|
284
|
+
const cliJs = join(dirname(process.execPath), "..", "lib", "node_modules", "@decentnetwork", "lan", "dist", "cli", "index.js");
|
|
285
|
+
const attempts = [
|
|
286
|
+
{ cmd: "agentnet", args: ["restart"] },
|
|
287
|
+
...(existsSync(cliJs) ? [{ cmd: process.execPath, args: [cliJs, "restart"] }] : []),
|
|
288
|
+
];
|
|
289
|
+
let lastErr = "agentnet CLI not found";
|
|
290
|
+
for (const a of attempts) {
|
|
291
|
+
const r = await new Promise((resolveRun) => {
|
|
292
|
+
const ch = spawn(a.cmd, a.args, { shell: process.platform === "win32" });
|
|
293
|
+
let out = "";
|
|
294
|
+
const timer = setTimeout(() => ch.kill("SIGKILL"), 60_000);
|
|
295
|
+
ch.stdout?.on("data", (c) => (out += c));
|
|
296
|
+
ch.stderr?.on("data", (c) => (out += c));
|
|
297
|
+
ch.on("error", (e) => { clearTimeout(timer); resolveRun({ code: null, out, spawnErr: e.message }); });
|
|
298
|
+
ch.on("close", (code) => { clearTimeout(timer); resolveRun({ code, out }); });
|
|
299
|
+
});
|
|
300
|
+
if (r.spawnErr)
|
|
301
|
+
continue;
|
|
302
|
+
if (r.code === 0)
|
|
303
|
+
return { ok: true };
|
|
304
|
+
lastErr = r.out.slice(-400) || `agentnet restart exited ${r.code}`;
|
|
305
|
+
}
|
|
306
|
+
return { ok: false, error: lastErr };
|
|
276
307
|
}
|
|
277
308
|
/** True only when the request came from the local machine. Used to gate the
|
|
278
309
|
* "Sign in with Decent" routes so binding the UI to a LAN IP can't expose
|
|
@@ -1251,6 +1282,20 @@ export function startBeagleServer(opts) {
|
|
|
1251
1282
|
sendJson(res, 403, { ok: false, error: "update runs only from this machine (localhost)" });
|
|
1252
1283
|
return;
|
|
1253
1284
|
}
|
|
1285
|
+
const body = await readBody(req);
|
|
1286
|
+
// lan (the agentnet daemon) updates independently of beagle's own
|
|
1287
|
+
// install mode: global reinstall, then ask the daemon to re-exec.
|
|
1288
|
+
if (body.pkg === "lan") {
|
|
1289
|
+
const inst = await npmGlobalInstall("@decentnetwork/lan");
|
|
1290
|
+
if (!inst.ok) {
|
|
1291
|
+
sendJson(res, 502, inst);
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
const rr = await agentnetRestart();
|
|
1295
|
+
updateCache = null;
|
|
1296
|
+
sendJson(res, 200, { ok: true, restarted: rr.ok, ...(rr.ok ? {} : { note: rr.error }) });
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1254
1299
|
const mode = installMode();
|
|
1255
1300
|
if (mode === "dev") {
|
|
1256
1301
|
sendJson(res, 400, { ok: false, error: "running from a source checkout — update with: git pull && npm run build" });
|
|
@@ -1261,7 +1306,7 @@ export function startBeagleServer(opts) {
|
|
|
1261
1306
|
sendJson(res, 200, { ok: true, npx: true });
|
|
1262
1307
|
return;
|
|
1263
1308
|
}
|
|
1264
|
-
const r = await
|
|
1309
|
+
const r = await npmGlobalInstall(BEAGLE_PKG);
|
|
1265
1310
|
updateCache = null; // next check reflects the new install
|
|
1266
1311
|
sendJson(res, r.ok ? 200 : 502, r);
|
|
1267
1312
|
return;
|
package/package.json
CHANGED