@decentnetwork/beagle-ui 0.2.32 → 0.2.34
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/beagle-ui.js +159 -14
- package/dist/wallet-proof.d.ts +38 -0
- package/dist/wallet-proof.js +3903 -0
- package/package.json +12 -3
package/dist/beagle-ui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const BEAGLE_UI_VERSION = "0.2.
|
|
1
|
+
export const BEAGLE_UI_VERSION = "0.2.34";
|
|
2
2
|
// src/icons.jsx
|
|
3
3
|
var ICON_PATHS = {
|
|
4
4
|
// ---- tab bar (the four must feel like one set) ----
|
|
@@ -125,6 +125,8 @@ var hostNeedsWelcome = false;
|
|
|
125
125
|
var hostPrefersRtcFile = false;
|
|
126
126
|
var hostHasKeyBackup = false;
|
|
127
127
|
var hostEnsWrite = true;
|
|
128
|
+
var hostWalletBind = true;
|
|
129
|
+
var hostAssistant = true;
|
|
128
130
|
var hostBrandHref = "";
|
|
129
131
|
var hostTabs = null;
|
|
130
132
|
var hostHideApps = null;
|
|
@@ -144,6 +146,8 @@ function setUiHost(host) {
|
|
|
144
146
|
hostPrefersRtcFile = !!H.hostPrefersRtcFile;
|
|
145
147
|
hostHasKeyBackup = !!H.hostHasKeyBackup;
|
|
146
148
|
hostEnsWrite = H.hostEnsWrite !== void 0 ? !!H.hostEnsWrite : !H.hostNeedsWelcome;
|
|
149
|
+
hostWalletBind = H.hostWalletBind !== void 0 ? !!H.hostWalletBind : hostEnsWrite;
|
|
150
|
+
hostAssistant = H.hostAssistant !== void 0 ? !!H.hostAssistant : true;
|
|
147
151
|
hostBrandHref = typeof H.hostBrandHref === "string" ? H.hostBrandHref : "";
|
|
148
152
|
}
|
|
149
153
|
function fileUrl(name) {
|
|
@@ -1708,6 +1712,28 @@ ${lines}`, { assistant: { kind: "adopt", rows: fresh } }));
|
|
|
1708
1712
|
return { thread, handle, removeFriends, adoptServicePeers };
|
|
1709
1713
|
}
|
|
1710
1714
|
|
|
1715
|
+
// src/request-avatar.js
|
|
1716
|
+
var MAX_URL = 2048;
|
|
1717
|
+
function requestAvatarUrl(r) {
|
|
1718
|
+
const u = r && r.avatarUrl;
|
|
1719
|
+
if (typeof u !== "string" || !u || u.length > MAX_URL)
|
|
1720
|
+
return null;
|
|
1721
|
+
return /^https:\/\/[^\s"'<>]+$/i.test(u) ? u : null;
|
|
1722
|
+
}
|
|
1723
|
+
function requestPunkId(r) {
|
|
1724
|
+
const p = r && r.punkId;
|
|
1725
|
+
return typeof p === "number" && Number.isInteger(p) && p >= 0 ? p : null;
|
|
1726
|
+
}
|
|
1727
|
+
function requestAvatarSource(r, skipUrl = false) {
|
|
1728
|
+
const url = skipUrl ? null : requestAvatarUrl(r);
|
|
1729
|
+
if (url)
|
|
1730
|
+
return { kind: "url", url };
|
|
1731
|
+
const id = requestPunkId(r);
|
|
1732
|
+
if (id != null)
|
|
1733
|
+
return { kind: "punk", id };
|
|
1734
|
+
return { kind: "ens" };
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1711
1737
|
// src/chat.jsx
|
|
1712
1738
|
var DK_CMD_HIST_KEY = "beagle.assistant.history";
|
|
1713
1739
|
var DK_CMD_HIST_MAX = 50;
|
|
@@ -1752,7 +1778,7 @@ function RequestsBlock({ T, requests, onAct }) {
|
|
|
1752
1778
|
display: "flex",
|
|
1753
1779
|
flexDirection: "column",
|
|
1754
1780
|
gap: 8
|
|
1755
|
-
} }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement(
|
|
1781
|
+
} }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement(DkRequestAvatar, { r, size: 30, radius: 7 }), /* @__PURE__ */ React.createElement("div", { style: { minWidth: 0, flex: 1 } }, r.name ? /* @__PURE__ */ React.createElement("div", { style: {
|
|
1756
1782
|
fontFamily: "var(--ui)",
|
|
1757
1783
|
fontSize: 13,
|
|
1758
1784
|
fontWeight: 600,
|
|
@@ -1769,6 +1795,32 @@ function RequestsBlock({ T, requests, onAct }) {
|
|
|
1769
1795
|
paddingLeft: 8
|
|
1770
1796
|
} }, r.descr), failed[r.id] && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 11, color: "var(--danger)" } }, failed[r.id]), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", gap: 6 } }, /* @__PURE__ */ React.createElement(Btn, { tone: "ok", icon: "check", size: "sm", onClick: () => act(r, "accept"), style: { flex: 1 } }, T.accept), /* @__PURE__ */ React.createElement(Btn, { tone: "danger", icon: "x", size: "sm", onClick: () => act(r, "reject"), style: { flex: 1 } }, T.reject))))));
|
|
1771
1797
|
}
|
|
1798
|
+
function DkRequestAvatar({ r, size, radius }) {
|
|
1799
|
+
const [urlBroken, setUrlBroken] = React.useState(false);
|
|
1800
|
+
const url = requestAvatarUrl(r);
|
|
1801
|
+
React.useEffect(() => {
|
|
1802
|
+
setUrlBroken(false);
|
|
1803
|
+
}, [url]);
|
|
1804
|
+
const src = requestAvatarSource(r, urlBroken);
|
|
1805
|
+
const seed = r.carrier || r.userid || r.id;
|
|
1806
|
+
if (src.kind === "url") {
|
|
1807
|
+
return /* @__PURE__ */ React.createElement(
|
|
1808
|
+
"img",
|
|
1809
|
+
{
|
|
1810
|
+
src: src.url,
|
|
1811
|
+
alt: "",
|
|
1812
|
+
width: size,
|
|
1813
|
+
height: size,
|
|
1814
|
+
referrerPolicy: "no-referrer",
|
|
1815
|
+
onError: () => setUrlBroken(true),
|
|
1816
|
+
style: { width: size, height: size, borderRadius: radius, objectFit: "cover", flexShrink: 0, background: "var(--panel-2)" }
|
|
1817
|
+
}
|
|
1818
|
+
);
|
|
1819
|
+
}
|
|
1820
|
+
if (src.kind === "punk")
|
|
1821
|
+
return /* @__PURE__ */ React.createElement(DkPunkAvatar, { id: src.id, size, radius, fallbackSeed: seed });
|
|
1822
|
+
return /* @__PURE__ */ React.createElement(DkEnsAvatar, { userid: r.userid || r.id, name: r.name, fallbackSeed: r.carrier, size, radius });
|
|
1823
|
+
}
|
|
1772
1824
|
function PeerRow({ peer, T, active, onClick, muted, isProtocol, fix }) {
|
|
1773
1825
|
const name = peer.alias || peer.userId;
|
|
1774
1826
|
const row = rosterRow(peer, isProtocol || (() => false), fix);
|
|
@@ -3501,6 +3553,67 @@ function ChatTab({ T, lang, peers, requests, activeId, thread, isProtocol, proto
|
|
|
3501
3553
|
}
|
|
3502
3554
|
Object.assign(window, { ChatTab });
|
|
3503
3555
|
|
|
3556
|
+
// src/wallet-proof.js
|
|
3557
|
+
var PROOF_KEY = { eth: "proof.eth", sol: "proof.sol" };
|
|
3558
|
+
var HEAD = "Beagle wallet binding";
|
|
3559
|
+
var LINE = "I bind this wallet to my Beagle identity.";
|
|
3560
|
+
var ADDRESS_RE = { eth: /^0x[0-9a-fA-F]{40}$/, sol: /^[1-9A-HJ-NP-Za-km-z]{32,44}$/ };
|
|
3561
|
+
var USERID_RE = /^[1-9A-HJ-NP-Za-km-z]{32,48}$/;
|
|
3562
|
+
var ISSUED_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;
|
|
3563
|
+
function isWalletAddress(chain, address) {
|
|
3564
|
+
const re = ADDRESS_RE[chain];
|
|
3565
|
+
return !!re && typeof address === "string" && re.test(address);
|
|
3566
|
+
}
|
|
3567
|
+
function proofTime(date = /* @__PURE__ */ new Date()) {
|
|
3568
|
+
return new Date(Math.floor(date.getTime() / 1e3) * 1e3).toISOString().replace(".000Z", "Z");
|
|
3569
|
+
}
|
|
3570
|
+
function walletProofMessage({ userid, chain, address, issued }) {
|
|
3571
|
+
if (!USERID_RE.test(String(userid || "")))
|
|
3572
|
+
throw new Error("wallet proof: bad userid");
|
|
3573
|
+
if (!isWalletAddress(chain, address))
|
|
3574
|
+
throw new Error("wallet proof: bad chain or address");
|
|
3575
|
+
if (!ISSUED_RE.test(String(issued || "")))
|
|
3576
|
+
throw new Error("wallet proof: bad issued time");
|
|
3577
|
+
return [HEAD, "", LINE, "", `userid: ${userid}`, `chain: ${chain}`, `address: ${address}`, `issued: ${issued}`].join("\n");
|
|
3578
|
+
}
|
|
3579
|
+
var B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
3580
|
+
function base58Encode(bytes) {
|
|
3581
|
+
const digits = [];
|
|
3582
|
+
for (const b of bytes) {
|
|
3583
|
+
let carry = b;
|
|
3584
|
+
for (let j = 0; j < digits.length; j++) {
|
|
3585
|
+
carry += digits[j] << 8;
|
|
3586
|
+
digits[j] = carry % 58;
|
|
3587
|
+
carry = carry / 58 | 0;
|
|
3588
|
+
}
|
|
3589
|
+
while (carry > 0) {
|
|
3590
|
+
digits.push(carry % 58);
|
|
3591
|
+
carry = carry / 58 | 0;
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
let out = "";
|
|
3595
|
+
for (const b of bytes) {
|
|
3596
|
+
if (b !== 0)
|
|
3597
|
+
break;
|
|
3598
|
+
out += "1";
|
|
3599
|
+
}
|
|
3600
|
+
for (let i = digits.length - 1; i >= 0; i--)
|
|
3601
|
+
out += B58[digits[i]];
|
|
3602
|
+
return out;
|
|
3603
|
+
}
|
|
3604
|
+
var utf8Hex = (s) => "0x" + Array.from(new TextEncoder().encode(s), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
3605
|
+
async function signEthProof(provider, { userid, address, issued = proofTime() }) {
|
|
3606
|
+
const message = walletProofMessage({ userid, chain: "eth", address, issued });
|
|
3607
|
+
const signature = await provider.request({ method: "personal_sign", params: [utf8Hex(message), address] });
|
|
3608
|
+
return { message, signature: String(signature) };
|
|
3609
|
+
}
|
|
3610
|
+
async function signSolProof(wallet, { userid, address, issued = proofTime() }) {
|
|
3611
|
+
const message = walletProofMessage({ userid, chain: "sol", address, issued });
|
|
3612
|
+
const r = await wallet.signMessage(new TextEncoder().encode(message), "utf8");
|
|
3613
|
+
const sig = r && r.signature ? r.signature : r;
|
|
3614
|
+
return { message, signature: base58Encode(Uint8Array.from(sig)) };
|
|
3615
|
+
}
|
|
3616
|
+
|
|
3504
3617
|
// src/profile.jsx
|
|
3505
3618
|
function CopyBtn({ value, copiedText = "Copied", copyFailedText = "Copy failed", copyTitle = "Copy" }) {
|
|
3506
3619
|
const [status, setStatus] = React.useState(null);
|
|
@@ -3915,7 +4028,7 @@ function DkEnsCard({ T, me, onRecord }) {
|
|
|
3915
4028
|
const [msg, setMsg] = React.useState(null);
|
|
3916
4029
|
const reload = () => {
|
|
3917
4030
|
fetch("/api/ens-name").then((r) => r.json()).then((d) => {
|
|
3918
|
-
setSt({ loading: false, registered: !!d.registered, record: d.record || null, mineOwned: !!d.mineOwned });
|
|
4031
|
+
setSt({ loading: false, registered: !!d.registered, record: d.record || null, mineOwned: !!d.mineOwned, writeBlocked: d.writeBlocked || "" });
|
|
3919
4032
|
if (d.registered && d.record && d.record.name)
|
|
3920
4033
|
setLabel(d.record.name.replace(/\.beagles\.eth$/i, ""));
|
|
3921
4034
|
if (onRecord)
|
|
@@ -3942,7 +4055,15 @@ function DkEnsCard({ T, me, onRecord }) {
|
|
|
3942
4055
|
if (l)
|
|
3943
4056
|
post("/api/ens-register", { name: l, displayName: me.name, description: me.description || "" });
|
|
3944
4057
|
};
|
|
3945
|
-
const bind = (chain, address) => post("/api/ens-bind-wallet", { chain, address });
|
|
4058
|
+
const bind = (chain, address, proof) => post("/api/ens-bind-wallet", proof ? { chain, address, proof } : { chain, address });
|
|
4059
|
+
const signing = () => {
|
|
4060
|
+
setBusy(true);
|
|
4061
|
+
setMsg({ tone: "ok", text: T.ensSigning || "approve the signature in your wallet\u2026" });
|
|
4062
|
+
};
|
|
4063
|
+
const walletErr = (e) => {
|
|
4064
|
+
setBusy(false);
|
|
4065
|
+
setMsg({ tone: "err", text: String(e && e.message || e) });
|
|
4066
|
+
};
|
|
3946
4067
|
const bindEth = async () => {
|
|
3947
4068
|
const eth = window.ethereum;
|
|
3948
4069
|
if (!eth) {
|
|
@@ -3951,10 +4072,13 @@ function DkEnsCard({ T, me, onRecord }) {
|
|
|
3951
4072
|
}
|
|
3952
4073
|
try {
|
|
3953
4074
|
const a = await eth.request({ method: "eth_requestAccounts" });
|
|
3954
|
-
if (a
|
|
3955
|
-
|
|
4075
|
+
if (!a || !a[0])
|
|
4076
|
+
return;
|
|
4077
|
+
signing();
|
|
4078
|
+
const proof = await signEthProof(eth, { userid: me.userId, address: a[0] });
|
|
4079
|
+
bind("eth", a[0], proof);
|
|
3956
4080
|
} catch (e) {
|
|
3957
|
-
|
|
4081
|
+
walletErr(e);
|
|
3958
4082
|
}
|
|
3959
4083
|
};
|
|
3960
4084
|
const bindSol = async () => {
|
|
@@ -3966,10 +4090,13 @@ function DkEnsCard({ T, me, onRecord }) {
|
|
|
3966
4090
|
try {
|
|
3967
4091
|
const r = await sol.connect();
|
|
3968
4092
|
const a = r && r.publicKey && r.publicKey.toString();
|
|
3969
|
-
if (a)
|
|
3970
|
-
|
|
4093
|
+
if (!a)
|
|
4094
|
+
return;
|
|
4095
|
+
signing();
|
|
4096
|
+
const proof = await signSolProof(sol, { userid: me.userId, address: a });
|
|
4097
|
+
bind("sol", a, proof);
|
|
3971
4098
|
} catch (e) {
|
|
3972
|
-
|
|
4099
|
+
walletErr(e);
|
|
3973
4100
|
}
|
|
3974
4101
|
};
|
|
3975
4102
|
const field = { flex: 1, minWidth: 0, height: 34, borderRadius: 8, border: "1px solid var(--line)", background: "var(--panel-2)", color: "var(--text)", fontFamily: "var(--mono)", fontSize: 13, padding: "0 10px", outline: "none" };
|
|
@@ -4018,6 +4145,7 @@ function DkEnsCard({ T, me, onRecord }) {
|
|
|
4018
4145
|
const [picking, setPicking] = React.useState(false);
|
|
4019
4146
|
const fileRef = React.useRef(null);
|
|
4020
4147
|
const canWrite = hostEnsWrite && !!st.mineOwned;
|
|
4148
|
+
const canBind = hostWalletBind && !!st.mineOwned && !st.writeBlocked;
|
|
4021
4149
|
const rec = st.record;
|
|
4022
4150
|
const boundEth = rec && rec.addresses && rec.addresses["60"];
|
|
4023
4151
|
const boundSol = rec && rec.addresses && rec.addresses["501"];
|
|
@@ -4040,7 +4168,16 @@ function DkEnsCard({ T, me, onRecord }) {
|
|
|
4040
4168
|
setMsg({ tone: "err", text: m === "too-big" ? T.ensTooBig || "image too large even after scaling" : m === "bad-image" ? T.ensBadImage || "cannot read that image" : String(m || err) });
|
|
4041
4169
|
});
|
|
4042
4170
|
};
|
|
4043
|
-
const
|
|
4171
|
+
const proven = (chain, bound) => {
|
|
4172
|
+
if (rec && rec.owner && String(rec.owner).toLowerCase() === String(bound).toLowerCase())
|
|
4173
|
+
return true;
|
|
4174
|
+
try {
|
|
4175
|
+
return JSON.parse((rec && rec.texts || {})[PROOF_KEY[chain]]).msg.indexOf("address: " + bound + "\n") >= 0;
|
|
4176
|
+
} catch {
|
|
4177
|
+
return false;
|
|
4178
|
+
}
|
|
4179
|
+
};
|
|
4180
|
+
const walletRow = (lbl, chain, bound, onBind, last) => /* @__PURE__ */ React.createElement("div", { className: "dk-row", style: { ...row, borderBottom: last ? "none" : row.borderBottom } }, /* @__PURE__ */ React.createElement("span", { className: "dk-lbl", style: { width: 130, flexShrink: 0, fontFamily: "var(--mono)", fontSize: 11.5, fontWeight: 600, color: "var(--faint)", textTransform: "uppercase", letterSpacing: 0.5 } }, lbl), bound ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 12.5, color: "var(--text)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, bound), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--ui)", fontSize: 11, color: proven(chain, bound) ? "var(--online)" : "var(--faint)" } }, proven(chain, bound) ? T.ensProven || "signed by this wallet" : T.ensUnproven || "no wallet signature yet")), /* @__PURE__ */ React.createElement(CopyBtn, { value: bound, copiedText: T.copied, copyFailedText: T.copyFailed, copyTitle: T.copy }), !proven(chain, bound) && /* @__PURE__ */ React.createElement(Btn, { size: "sm", disabled: busy || !canBind, onClick: onBind }, T.ensProve || "sign"), /* @__PURE__ */ React.createElement(Btn, { size: "sm", tone: "danger", disabled: busy || !canBind, onClick: () => bind(chain, "") }, T.ensUnbind || "unbind")) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { style: { flex: 1, fontFamily: "var(--ui)", fontSize: 12, color: "var(--faint)" } }, T.ensNotBound || "not bound"), /* @__PURE__ */ React.createElement(Btn, { size: "sm", disabled: busy || !canBind, onClick: onBind }, T.ensBind || "bind")));
|
|
4044
4181
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Card, { label: T.ensCard || "Name \xB7 beagles.eth" }, st.loading ? /* @__PURE__ */ React.createElement("div", { style: { padding: "14px 16px", fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--faint)" } }, T.dirLoading || "loading\u2026") : /* @__PURE__ */ React.createElement(React.Fragment, null, !hostEnsWrite ? /* @__PURE__ */ React.createElement("div", { className: "dk-row dk-wrap", style: row }, /* @__PURE__ */ React.createElement("span", { className: "dk-lbl", style: { width: 130, flexShrink: 0, fontFamily: "var(--mono)", fontSize: 11.5, fontWeight: 600, color: "var(--faint)", textTransform: "uppercase", letterSpacing: 0.5 } }, T.ensName || "name"), st.registered && rec && rec.name ? /* @__PURE__ */ React.createElement("span", { style: { flex: 1, minWidth: 0, fontFamily: "var(--mono)", fontSize: 13, color: "var(--text)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, rec.name) : /* @__PURE__ */ React.createElement("span", { style: { flex: 1, minWidth: 0, fontFamily: "var(--ui)", fontSize: 12, lineHeight: 1.5, color: "var(--faint)" } }, T.ensWebOnly || "Registering a beagles.eth name needs the Beagle phone or desktop app. Your avatar can be set above without one.")) : /* @__PURE__ */ React.createElement("div", { className: "dk-row dk-wrap", style: row }, /* @__PURE__ */ React.createElement("span", { className: "dk-lbl", style: { width: 130, flexShrink: 0, fontFamily: "var(--mono)", fontSize: 11.5, fontWeight: 600, color: "var(--faint)", textTransform: "uppercase", letterSpacing: 0.5 } }, T.ensName || "name"), /* @__PURE__ */ React.createElement(
|
|
4045
4182
|
"input",
|
|
4046
4183
|
{
|
|
@@ -4054,7 +4191,7 @@ function DkEnsCard({ T, me, onRecord }) {
|
|
|
4054
4191
|
},
|
|
4055
4192
|
style: { ...field, minWidth: 110 }
|
|
4056
4193
|
}
|
|
4057
|
-
), /* @__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", { className: "dk-row dk-wrap", style: row }, /* @__PURE__ */ React.createElement("span", { className: "dk-lbl", 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 || !canWrite, 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 || !canWrite, 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 || !canWrite, onClick: () => fileRef.current && fileRef.current.click() }, T.ensUpload || "upload"), /* @__PURE__ */ React.createElement(Btn, { size: "sm", disabled: busy || !canWrite, 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))));
|
|
4194
|
+
), /* @__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", { className: "dk-row dk-wrap", style: row }, /* @__PURE__ */ React.createElement("span", { className: "dk-lbl", 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 || !canWrite, 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 || !canWrite, 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 || !canWrite, onClick: () => fileRef.current && fileRef.current.click() }, T.ensUpload || "upload"), /* @__PURE__ */ React.createElement(Btn, { size: "sm", disabled: busy || !canWrite, 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 && !st.writeBlocked), st.writeBlocked && hostWalletBind && /* @__PURE__ */ React.createElement("div", { style: { padding: "10px 16px", borderBottom: msg ? "1px solid var(--line)" : "none", fontFamily: "var(--ui)", fontSize: 12, lineHeight: 1.5, color: "var(--faint)" } }, st.writeBlocked), 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))));
|
|
4058
4195
|
}
|
|
4059
4196
|
function DkUpdateCheck({ T }) {
|
|
4060
4197
|
const [st, setSt] = React.useState("idle");
|
|
@@ -6454,6 +6591,10 @@ var STR = {
|
|
|
6454
6591
|
ensUnbind: "unbind",
|
|
6455
6592
|
ensNotBound: "not bound",
|
|
6456
6593
|
ensWebOnly: "Registering a beagles.eth name needs the Beagle phone or desktop app. Your avatar can be set above without one.",
|
|
6594
|
+
ensProven: "signed by this wallet",
|
|
6595
|
+
ensUnproven: "no wallet signature yet",
|
|
6596
|
+
ensProve: "sign",
|
|
6597
|
+
ensSigning: "approve the signature in your wallet\u2026",
|
|
6457
6598
|
ensAvatar: "avatar",
|
|
6458
6599
|
ensChoose: "choose",
|
|
6459
6600
|
ensClear: "clear",
|
|
@@ -6649,6 +6790,10 @@ var STR = {
|
|
|
6649
6790
|
ensUnbind: "\u89E3\u7ED1",
|
|
6650
6791
|
ensNotBound: "\u672A\u7ED1\u5B9A",
|
|
6651
6792
|
ensWebOnly: "\u6CE8\u518C beagles.eth \u540D\u5B57\u9700\u8981 Beagle \u624B\u673A\u6216\u684C\u9762\u5E94\u7528\u3002\u5934\u50CF\u4E0D\u9700\u8981\u540D\u5B57\uFF0C\u53EF\u5728\u4E0A\u65B9\u76F4\u63A5\u8BBE\u7F6E\u3002",
|
|
6793
|
+
ensProven: "\u5DF2\u7531\u8BE5\u94B1\u5305\u7B7E\u540D",
|
|
6794
|
+
ensUnproven: "\u5C1A\u65E0\u94B1\u5305\u7B7E\u540D",
|
|
6795
|
+
ensProve: "\u7B7E\u540D",
|
|
6796
|
+
ensSigning: "\u8BF7\u5728\u94B1\u5305\u4E2D\u786E\u8BA4\u7B7E\u540D\u2026",
|
|
6652
6797
|
ensAvatar: "\u5934\u50CF",
|
|
6653
6798
|
ensChoose: "\u9009\u62E9",
|
|
6654
6799
|
ensClear: "\u6E05\u9664",
|
|
@@ -6983,10 +7128,10 @@ function DkApp() {
|
|
|
6983
7128
|
window.location.reload();
|
|
6984
7129
|
}, [me && me.beagleVer]);
|
|
6985
7130
|
const [assistantTs, setAssistantTs] = React.useState(loadAssistantTs);
|
|
6986
|
-
const peers = React.useMemo(() => (data.peers || []).concat([Object.assign({}, ASSISTANT_PEER, {
|
|
7131
|
+
const peers = React.useMemo(() => (data.peers || []).concat(hostAssistant ? [Object.assign({}, ASSISTANT_PEER, {
|
|
6987
7132
|
lastTs: assistantTs,
|
|
6988
7133
|
lastTime: assistantTs ? dkClock(assistantTs) : ""
|
|
6989
|
-
})]), [data.peers, assistantTs]);
|
|
7134
|
+
})] : []), [data.peers, assistantTs]);
|
|
6990
7135
|
const [pendingAddr, setPendingAddr] = React.useState(() => dkParseDeepLinkAddress());
|
|
6991
7136
|
React.useEffect(() => {
|
|
6992
7137
|
const onHash = () => {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Types for @decentnetwork/beagle-ui/wallet-proof. Copied to dist/ by the build.
|
|
2
|
+
export type WalletChain = 'eth' | 'sol';
|
|
3
|
+
export interface WalletProof { message: string; signature: string }
|
|
4
|
+
export type VerifyResult = { ok: true; issued: string } | { ok: false; error: string };
|
|
5
|
+
|
|
6
|
+
export const WALLET_PROOF_VERSION: 1;
|
|
7
|
+
export const WALLET_CHAINS: WalletChain[];
|
|
8
|
+
export const COIN_TYPE: { eth: '60'; sol: '501' };
|
|
9
|
+
export const PROOF_KEY: { eth: 'proof.eth'; sol: 'proof.sol' };
|
|
10
|
+
|
|
11
|
+
export function isWalletAddress(chain: string, address: unknown): boolean;
|
|
12
|
+
export function proofTime(date?: Date): string;
|
|
13
|
+
export function walletProofMessage(f: { userid: string; chain: WalletChain; address: string; issued: string }): string;
|
|
14
|
+
export function parseWalletProofMessage(msg: unknown): { userid: string; chain: WalletChain; address: string; issued: string } | null;
|
|
15
|
+
export function encodeWalletProof(p: WalletProof): string;
|
|
16
|
+
export function decodeWalletProof(text: unknown): WalletProof | null;
|
|
17
|
+
export function base58Encode(bytes: Uint8Array): string;
|
|
18
|
+
export function base58Decode(str: string): Uint8Array;
|
|
19
|
+
export function signEthProof(provider: { request(a: { method: string; params: unknown[] }): Promise<unknown> }, f: { userid: string; address: string; issued?: string }): Promise<WalletProof>;
|
|
20
|
+
export function signSolProof(wallet: { signMessage(m: Uint8Array, display?: string): Promise<unknown> }, f: { userid: string; address: string; issued?: string }): Promise<WalletProof>;
|
|
21
|
+
|
|
22
|
+
export function eip191Hash(message: string): Uint8Array;
|
|
23
|
+
export function recoverEthAddress(message: string, signature: string): string;
|
|
24
|
+
export function verifyWalletProof(a: {
|
|
25
|
+
chain: string; address: string; userid: string;
|
|
26
|
+
proof: string | WalletProof | null | undefined;
|
|
27
|
+
maxAgeMs?: number; now?: number;
|
|
28
|
+
}): VerifyResult;
|
|
29
|
+
export function verifyRecordWallet(
|
|
30
|
+
record: { owner?: string; addresses?: Record<string, string>; texts?: Record<string, string> } | null | undefined,
|
|
31
|
+
chain: WalletChain
|
|
32
|
+
): { ok: true; address: string; via: 'proof'; issued: string } | { ok: true; address: string; via: 'owner' } | { ok: false; error: string };
|
|
33
|
+
|
|
34
|
+
export const BIND_MAX_AGE_MS: number;
|
|
35
|
+
export function applyWalletBind(
|
|
36
|
+
record: { addresses?: Record<string, string>; texts?: Record<string, string> } | null | undefined,
|
|
37
|
+
req: { chain: string; address: unknown; proof?: string | WalletProof | null; userid: string; now?: number }
|
|
38
|
+
): { ok: true; addresses: Record<string, string>; texts: Record<string, string> } | { ok: false; status: number; error: string };
|