From be36492d8a14bfd2fce46dbd87e01a2a36fef57c Mon Sep 17 00:00:00 2001 From: Local Dev Date: Mon, 21 Sep 2026 02:40:05 +0200 Subject: [PATCH] feat(theseus): one-click "Install in Theseus" from theseus.x/extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The extensions page could only hand out tarballs; installing meant going to Settings › Extensions › Community and finding the entry again. Pages now get window.bcnr.installExtension(id) and Theseus intercepts theseus://extensions/install/ links (page clicks, target=_blank and the address bar). The page only names a catalog id: Theseus fetches the catalog and package itself, asks in a native dialog the page cannot draw over, verifies the publisher signature against the name's current owner and activates the add-on — the same path a Settings install takes. One prompt at a time; an already-installed version says so instead of offering a no-op update. The site shows the button inside Theseus (feature-detected on the bridge), a "update Theseus" hint on older builds and a download hint in other browsers. --- extensions/index.html | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/extensions/index.html b/extensions/index.html index cc690a9f..2bb8db1e 100644 --- a/extensions/index.html +++ b/extensions/index.html @@ -96,6 +96,14 @@ .ext .h b{color:var(--mut);font-weight:600;min-width:70px} .ext .h code{font-family:ui-monospace,monospace;font-size:10.5px;color:#c9d4e3;word-break:break-all;background:transparent;border:none;padding:0} .ext .meta{color:var(--dim);font-size:12.5px;margin-top:.4rem} + .ext .act{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:.8rem} + .ext .install{display:inline-block;background:var(--acid);color:#0b0e14;font-weight:600;font-size:14px; + border:none;border-radius:9px;padding:9px 18px;cursor:pointer;text-decoration:none;font-family:inherit} + .ext .install:hover{filter:brightness(1.08)} + .ext .install[disabled]{opacity:.6;cursor:default} + .ext .install.alt{background:rgba(214,255,61,.12);color:var(--acid)} + .ext .act .st{font-size:13px;color:var(--mut)} + .ext .act .st.ok{color:var(--acid)} .ext .act .st.err{color:#f6768a} .note{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--acid); border-radius:10px;padding:14px 18px;color:var(--mut);font-size:14px;margin:1.4rem 0} .note b{color:var(--ink)} @@ -190,9 +198,10 @@

Community extensions

-

Published by BCDN name holders, signed with the wallet that holds the name. Theseus installs them - from Settings › Extensions › Community and re-checks every signature against the name's current owner - in its own chain index — the relay cannot substitute code under a trusted name.

+

Published by BCDN name holders, signed with the wallet that holds the name. Open this page in Theseus + and click Install in Theseus — or use Settings › Extensions › Community. Either way Theseus fetches the + package itself and re-checks every signature against the name's current owner in its own chain index — the relay + cannot substitute code under a trusted name.

Loading the catalog…
Trust, stated plainly. A community extension runs with the same access as any add-on — treat one like an unsigned executable from that publisher. The signature proves who published it, @@ -254,6 +263,16 @@ // Community catalog const box = document.getElementById("communityList"); const esc = (s) => String(s || "").replace(/[&<>"']/g, (c) => ({ "&":"&","<":"<",">":">",'"':""","'":"'" })[c]); + // Inside Theseus every page has window.bcnr; builds since 0.3.50 add + // installExtension(id). The page only passes the catalog id — Theseus + // fetches the package, confirms in a native dialog and verifies the signature. + const inTheseus = !!window.bcnr; + const canInstall = inTheseus && typeof window.bcnr.installExtension === "function"; + const installUi = (id) => canInstall + ? `` + : inTheseus + ? `Update Theseus to install from hereuntil then: Settings › Extensions › Community › Install` + : `Get Theseus to installone click from this page inside Theseus`; try { const r = await fetch("./community/catalog.json", { cache: "no-store" }); const cat = r.ok ? await r.json() : { extensions: [] }; @@ -264,14 +283,22 @@

${esc(e.icon || "🧩")} ${esc(e.name)} v${esc(e.latest)}

${esc(e.description)}
Published by ${esc(e.publisher)} · ${esc(String(e.versions || 1))} version${e.versions === 1 ? "" : "s"} · updated ${esc(String(e.updatedAt || "").slice(0, 10))}${e.capabilities && e.capabilities.length ? " · " + esc(e.capabilities.join(", ")) : ""}
+
${installUi(e.id)}
Publisher-signed channel — verified by Theseus against ${esc(e.publisher)}'s current owner
sha256${esc(e.sha256)}
-
InstallTheseus › Settings › Extensions › Community › Install
+
Linktheseus://extensions/install/${esc(e.id)}
`).join(""); + box.querySelectorAll("button[data-install]").forEach((btn) => btn.addEventListener("click", async () => { + const id = btn.dataset.install, st = box.querySelector(`[data-st="${CSS.escape(id)}"]`); + btn.disabled = true; st.className = "st"; st.textContent = "Confirm in the Theseus dialog…"; + let r; try { r = await window.bcnr.installExtension(id); } catch (err) { r = { ok: false, error: err?.message || String(err) }; } + if (r && r.ok) { st.className = "st ok"; st.textContent = `Installed v${r.version} — signed by ${r.publisher}`; btn.textContent = "Installed"; } + else { btn.disabled = false; st.className = r?.error === "cancelled" ? "st" : "st err"; st.textContent = r?.error === "cancelled" ? "" : (r?.error || "install failed"); } + })); } catch (e) { box.innerHTML = '
Catalog unavailable right now.
'; } })();