2026-07-29 13:54:34 +02:00
|
|
|
|
const { contextBridge, ipcRenderer } = require("electron");
|
|
|
|
|
|
contextBridge.exposeInMainWorld("cfg", {
|
|
|
|
|
|
get: () => ipcRenderer.invoke("settings-get"),
|
|
|
|
|
|
set: (key, value) => ipcRenderer.invoke("settings-set", key, value),
|
2026-07-30 19:29:32 +02:00
|
|
|
|
engines: () => ipcRenderer.invoke("search-engines"),
|
2026-07-30 20:58:45 +02:00
|
|
|
|
addEngine: (eng) => ipcRenderer.invoke("add-engine", eng),
|
|
|
|
|
|
removeEngine: (id) => ipcRenderer.invoke("remove-engine", id),
|
2026-07-30 22:55:52 +02:00
|
|
|
|
setEngineEnabled: (id, on) => ipcRenderer.invoke("set-engine-enabled", id, on),
|
2026-07-30 23:26:00 +02:00
|
|
|
|
setEngineOrder: (ids) => ipcRenderer.invoke("set-engine-order", ids),
|
2026-08-06 01:41:31 +02:00
|
|
|
|
removeFromList: (id) => ipcRenderer.invoke("remove-from-list", id),
|
Snapshot in-progress work: Ariadne mobile, Theseus password manager, Hephaestus
Several concurrent workstreams committed together as a checkpoint:
- Ariadne mobile resolver — BchFetcher/Bns/MainActivity resolution logic,
AndroidManifest + build.ps1
- Theseus password manager — settings.html/chrome.html/settings-preload.js UI +
main.js wiring + package.json resource; Argus password-vault.js, record-picker.js
(+ tests) and resolver-web.d.ts
- Hephaestus — new BCH-wallet OIDC auth-proxy + Forgejo docker-compose and
restic/S3 scripts (secrets referenced via env only; Hephaestus/.env is gitignored)
- Argus public-gateway.mjs updates
- Docs — root README, Email README/RUNBOOK, VPS access runbooks (Checkers/Deviant),
site/hermes, WebsiteDev registry + faster-blocks, Failures/ AAAA-mangle writeup,
Decentralized Storage map, coordination notes
- .gitignore — exclude /.keys/ and Hephaestus/.env
2026-08-14 23:17:18 +02:00
|
|
|
|
// Storage: wipe browsing data on demand. Pass any subset of
|
|
|
|
|
|
// { cookies, cache, storage, history }.
|
|
|
|
|
|
clearBrowsingData: (opts) => ipcRenderer.invoke("clear-browsing-data", opts),
|
|
|
|
|
|
// Password vault. All calls return { ok, ... } | { ok: false, err }.
|
|
|
|
|
|
// Renderers never see the seed / vault key / master password past setup/
|
|
|
|
|
|
// unlock; get() returns plaintext only in explicit response to a user click.
|
|
|
|
|
|
pwStatus: () => ipcRenderer.invoke("password-status"),
|
|
|
|
|
|
pwSetup: (masterPassword, seedSource) => ipcRenderer.invoke("password-setup", { masterPassword, seedSource }),
|
|
|
|
|
|
pwUnlock: (masterPassword) => ipcRenderer.invoke("password-unlock", masterPassword),
|
|
|
|
|
|
pwLock: () => ipcRenderer.invoke("password-lock"),
|
|
|
|
|
|
pwList: () => ipcRenderer.invoke("password-list"),
|
|
|
|
|
|
pwGet: (id) => ipcRenderer.invoke("password-get", id),
|
|
|
|
|
|
pwAdd: (entry) => ipcRenderer.invoke("password-add", entry),
|
|
|
|
|
|
pwUpdate: (id, patch) => ipcRenderer.invoke("password-update", id, patch),
|
|
|
|
|
|
pwRemove: (id) => ipcRenderer.invoke("password-remove", id),
|
|
|
|
|
|
pwGenerate: (spec) => ipcRenderer.invoke("password-generate", spec),
|
Theseus: quick-unlock PIN for the vault, shared with extensions
The vault re-locks on every restart and only the master password opened
it, so every extension that needs it (Aegis, now Pithos) either asked for
the master password itself or grew its own PIN. Theseus now owns one:
- Settings > Passwords sets, changes or removes a 6-digit PIN. The PIN
wraps the master password (PBKDF2-SHA256, 600k iterations, AES-256-GCM)
and the result is sealed with the OS keystore (safeStorage: DPAPI /
Keychain / libsecret), so a copied vault-pin.json cannot be brute-forced
elsewhere. Every unlock still ends at the master password.
- Three wrong PINs in a row require the master password. The strike count
lives in the same file, so a restart does not reset it; a successful
master-password unlock does. A PIN whose password no longer opens the
vault (password changed) is dropped.
- unlock.html is Theseus's own prompt, over the whole window: PIN pad, or
the master password. Extensions call api.vault.requestUnlock({ reason })
(vault-derive capability) and get { ok } back; what the user typed never
reaches them. Settings' locked screen offers "Unlock with PIN" through
the same prompt.
2026-10-03 20:33:26 +02:00
|
|
|
|
// Quick-unlock PIN. pinSet proves the master password in main before
|
|
|
|
|
|
// wrapping it; pinUnlock opens Theseus's own PIN / password prompt.
|
|
|
|
|
|
pinStatus: () => ipcRenderer.invoke("vault-pin-status"),
|
|
|
|
|
|
pinSet: (pin, masterPassword) => ipcRenderer.invoke("vault-pin-set", { pin, masterPassword }),
|
|
|
|
|
|
pinClear: () => ipcRenderer.invoke("vault-pin-clear"),
|
Vault: PIN setup steps, 6-8 digit PINs, save and offer logins, keep sign-ins
The PIN could only be six digits and was set from three bare inputs; the
unlock prompt sat at the top of the page; and the password manager only
filled when you found the key chip, never offered to save, and "Clear
cookies on quit" signed you out of every site, including the ones whose
login the vault already holds.
- PINs are 6 to 8 digits. The PIN record stores its length so pads draw the
right number of dots and submit on the last digit; a PIN of the wrong
length is refused without a strike, so an older Aegis pad cannot burn the
count against an 8-digit PIN.
- Settings sets a PIN in steps: master password, choose the PIN on a pad
(6/7/8), repeat it, done. The locked vault opens Theseus's own prompt,
which is now centred, with the PIN pad or the master password field.
- After a sign-in or sign-up form is sent and the page moves on, Theseus
offers to save (or update) the login, with an optional "ask for my PIN or
password before filling it". Focusing a login form offers the saved
logins under it; on a locked vault it offers to unlock first. A failed
login (the password field still showing) gets no offer.
- "Keep sign-ins for sites in your vault" (on): the quit clear spares the
cookies and site storage of sites with a saved login. Their hostnames are
kept sealed with the OS keystore so the list is readable at quit while
the vault is locked. Verified end to end on a scratch profile: signed in,
restarted, still signed in; another site's cookie was cleared.
2026-10-04 20:23:43 +02:00
|
|
|
|
pinCheckMaster: (masterPassword) => ipcRenderer.invoke("vault-check-master", masterPassword),
|
|
|
|
|
|
// Asks for the PIN or master password even while the vault is open.
|
|
|
|
|
|
pwConfirm: (reason) => ipcRenderer.invoke("vault-confirm", reason),
|
Theseus ID in Theseus: window.theseusId.signIn and Settings › Theseus ID
Pages of Silent Mode projects can now sign the user in with their Theseus
ID instead of a wallet phrase typed into the page. Theseus writes the
sign-in message itself, takes the origin from the committed top frame, and
signs as a project only on an origin that project's list includes, so a
phishing page cannot get another project's signature and no page can use
the ID key to sign anything else.
- lib/theseus-id.cjs: the policy (first sign-in always asks and lets the
user pick a private or One ID; Silent Mode projects are silent after
that while the vault is open; per-site "always"; 10 silent signatures per
minute per origin), the per-project record encrypted under a key derived
from the vault, origin-list fetching with a 1 h cache and a 7-day stale
fallback, and ID moves that send a proof signed by both keys and only
finish once the project confirms.
- A locked vault is unlocked only for a page the user just clicked or typed
in: navigator.userActivation alone is true on load for pages opened with
loadURL, which would let a page pop the vault prompt by itself.
- Settings › Theseus ID: default mode, One ID, automatic sign-in toggle,
signed-in projects (always, change ID, new ID, revoke) and a recovery key
behind a fresh PIN / password check.
- TheseusID/registry/projects.json is the first-party list (Hephaestus,
Sirius, Pithos); it and TheseusID/lib ship as extraResources.
- Token-aware cashaddrs (BNS owners) now decode for owner-signed lists.
Verified on a scratch profile against a local test project whose server
checks signatures with TheseusID/lib/verify.mjs: locked vault on load gives
"locked" with no prompt, first sign-in prompt, silent second sign-in, a
claimed foreign project refused without a prompt, an ID move that keeps the
project's account, and the recovery key behind the confirm prompt.
2026-10-04 20:48:07 +02:00
|
|
|
|
// Settings › Theseus ID. Each resolves { ok, result } or { ok: false, error: { code, message } }.
|
|
|
|
|
|
tidOverview: () => ipcRenderer.invoke("theseus-id-overview"),
|
|
|
|
|
|
tidSetDefaultMode: (mode) => ipcRenderer.invoke("theseus-id-set-default-mode", mode),
|
|
|
|
|
|
tidSetAuto: (on) => ipcRenderer.invoke("theseus-id-set-auto", !!on),
|
|
|
|
|
|
tidSetAlways: (projectId, on) => ipcRenderer.invoke("theseus-id-set-always", projectId, !!on),
|
|
|
|
|
|
tidRevoke: (projectId) => ipcRenderer.invoke("theseus-id-revoke", projectId),
|
|
|
|
|
|
tidMove: (projectId, to) => ipcRenderer.invoke("theseus-id-move", projectId, to),
|
|
|
|
|
|
tidCancelMove: (projectId) => ipcRenderer.invoke("theseus-id-cancel-move", projectId),
|
|
|
|
|
|
tidRotate: (projectId) => ipcRenderer.invoke("theseus-id-rotate", projectId),
|
|
|
|
|
|
tidUnlock: () => ipcRenderer.invoke("theseus-id-unlock"),
|
|
|
|
|
|
tidRecoveryKey: () => ipcRenderer.invoke("theseus-id-recovery-key"),
|
Theseus: quick-unlock PIN for the vault, shared with extensions
The vault re-locks on every restart and only the master password opened
it, so every extension that needs it (Aegis, now Pithos) either asked for
the master password itself or grew its own PIN. Theseus now owns one:
- Settings > Passwords sets, changes or removes a 6-digit PIN. The PIN
wraps the master password (PBKDF2-SHA256, 600k iterations, AES-256-GCM)
and the result is sealed with the OS keystore (safeStorage: DPAPI /
Keychain / libsecret), so a copied vault-pin.json cannot be brute-forced
elsewhere. Every unlock still ends at the master password.
- Three wrong PINs in a row require the master password. The strike count
lives in the same file, so a restart does not reset it; a successful
master-password unlock does. A PIN whose password no longer opens the
vault (password changed) is dropped.
- unlock.html is Theseus's own prompt, over the whole window: PIN pad, or
the master password. Extensions call api.vault.requestUnlock({ reason })
(vault-derive capability) and get { ok } back; what the user typed never
reaches them. Settings' locked screen offers "Unlock with PIN" through
the same prompt.
2026-10-03 20:33:26 +02:00
|
|
|
|
pinUnlock: () => ipcRenderer.invoke("vault-pin-unlock"),
|
2026-08-06 01:41:31 +02:00
|
|
|
|
// Main asks settings to jump to a specific sidebar section (e.g. from the
|
|
|
|
|
|
// engine picker's "Search settings…" click). Emits the section id string.
|
|
|
|
|
|
onFocusSection: (cb) => ipcRenderer.on("focus-section", (_e, section) => cb(section)),
|
2026-08-02 11:39:00 +02:00
|
|
|
|
// Collision-mode: BCNR/ICANN policy + per-name/per-TLD overrides
|
|
|
|
|
|
collisionState: () => ipcRenderer.invoke("collision-state"),
|
|
|
|
|
|
setCollisionPolicy: (p) => ipcRenderer.invoke("collision-set-policy", p),
|
|
|
|
|
|
resetCollisions: () => ipcRenderer.invoke("collision-reset"),
|
Theseus: warn before opening a name a blocklist flags
The blocklist consumer existed in the resolver library and the gateway, but
the browser opened a flagged name without comment. Now the indexer process
reads the subscribed lists from the chain every ten minutes and hands the
flags to main. A flagged name loads a warning page naming the reason, the
list and the report; the user may continue, and that is remembered per name.
Two gates, because content is reached two ways. loadBns shows the real
interstitial. serveBns refuses with an inline page on every path that skips
it: reload, back and forward, bns:// links, web app windows. The inline page
has no button, since a page at the site's own origin must not be able to
approve itself; only blocked.html may ask to continue, checked by file URL.
Settings › Naming has the policy: warn (default), never open, or ignore the
lists. The csam reason is never offered a way through. A list that cannot be
read keeps the last known flags and never stops a name from resolving.
The gateway put its own warning in front of flagged sites, which this
browser could not get past: it fetches files itself, with no cookie jar. It
now sends x-bns-policy: client and the gateway stays out of the way for a
client that says it decides for itself.
dev/blocklist-selftest.js runs the real protocol handler and decision
functions against a scratch profile.
2026-10-04 15:50:35 +02:00
|
|
|
|
// Blocklists: flagged names, the policy, and the "continue anyway" choices
|
|
|
|
|
|
blocklistState: () => ipcRenderer.invoke("blocklist-state"),
|
|
|
|
|
|
setBlocklistPolicy: (p) => ipcRenderer.invoke("blocklist-set-policy", p),
|
|
|
|
|
|
resetBlocklist: () => ipcRenderer.invoke("blocklist-reset"),
|
Theseus: add-on framework MVP + Notepad reference add-on
New subsystem for extending Theseus with folders on disk. Each add-on
lives at <userData>/addons/<id>/ with an addon.json manifest and a
CommonJS entry that exports activate(api). Nothing about a private
add-on ships in the public installer - drop the folder, restart, it's
live. Bundled reference add-ons ride in the packaged app under
resources/bundled-addons/ and are seeded into <userData>/addons/ on
first boot; the framework treats seeded and drop-in add-ons the same.
Files:
- addons-host.js Loader + api.registerSidebarPanel() + per-
addon storage on <userData>/addons-data/.
Kept at the CommonJS-scoped top level (lib/
is ESM-scoped via its own package.json).
- sidebar-preload.js Runs in every sidebar panel. Exposes
window.silentmode.storage.{get,set,all} +
onVisibility. Main-side handlers derive the
add-on id from the sender file:// URL, so a
panel can only touch its own store.
- bundled-addons/notepad/ Reference add-on: addon.json, index.js,
note.html. Autosaving textarea with char /
word count.
main.js:
- Extension point: sidebar-panel. One right-anchored WebContentsView
(SIDEBAR_W=340) hosts the current panel; layout() shrinks the tab
views by the sidebar width when visible. First registered panel
wins for MVP; picker for multiple panels lands later.
- initAddons() at app.whenReady(): seedBundledAddons, then
AddonHost.discoverAndActivate.
- IPC surface: sidebar-toggle / sidebar-open / sidebar-close /
sidebar-state, addons-list / addons-set-enabled / addons-reveal /
addons-open-dir / addons-reload, and origin-gated
addon-storage-get/set/all.
- Settings gains `disabledAddons: []` — off-toggled ids persist and
the loader honours them without a restart (discoverAndActivate
runs again on toggle).
chrome.html: toolbar sidebar-toggle button, hidden until at least one
add-on has registered a sidebar panel.
settings.html: new "Add-ons" section under privacy. Lists installed
add-ons with icon / name / version / description / capabilities;
per-add-on enable/disable toggle + Show folder button; page-level
Reload and Open add-ons folder buttons; warning note about the trust
model.
package.json: build.files gains sidebar-preload.js + addons-host.js.
extraResources gains bundled-addons/ so the packaged app carries the
reference notepad for the first-boot seed.
Verified: `npm start` boots, addons-host discovers the notepad,
activates it, registers one sidebar panel. Log confirms
"1 installed, 1 enabled, 1 sidebar panels". Actual sidebar rendering
+ notepad UI need clicked-through validation on a real install.
Not shipped yet - deploy still blocked on the fail2ban VPS SSH ban.
Ships as 0.2.0 once SSH clears (this is a new subsystem, not a fix).
2026-08-31 13:51:08 +02:00
|
|
|
|
// Add-ons management (Settings > Add-ons tab).
|
|
|
|
|
|
listAddons: () => ipcRenderer.invoke("addons-list"),
|
|
|
|
|
|
setAddonEnabled: (id, enabled) => ipcRenderer.invoke("addons-set-enabled", id, !!enabled),
|
|
|
|
|
|
revealAddon: (folder) => ipcRenderer.invoke("addons-reveal", folder),
|
feat(theseus/settings): Extensions as compact rows with a detail view
The Extensions list was a stack of tall cards — description, author,
capabilities and buttons on every one — so seven add-ons filled the
page before the user found the toggle. Rows are now one line each,
Firefox-style: icon, name, built-in badge, version, a short update
status, the on/off switch and a ⋯ menu, grouped Enabled / Disabled /
Failed to load. Clicking a row opens the detail view in place: back
arrow, description, update status, author, version, type, folder with
Show folder, and a Permissions block that explains each declared
capability in plain words. The ⋯ menu (and right-click) offers Turn
on/off, Details, Show folder and, for non-bundled extensions, Remove —
a new addons-remove IPC that deletes the folder under the extensions
directory, refuses bundled add-ons (they would only be reseeded), and
clears the dock prefs it left behind.
2026-09-22 20:43:50 +02:00
|
|
|
|
// Delete a non-bundled extension's folder (Settings › Extensions › ⋯ › Remove).
|
|
|
|
|
|
removeAddon: (id) => ipcRenderer.invoke("addons-remove", id),
|
2026-09-30 02:16:11 +02:00
|
|
|
|
openAddonsDir: () => ipcRenderer.invoke("addons-open-dir"),
|
|
|
|
|
|
reloadAddons: () => ipcRenderer.invoke("addons-reload"),
|
|
|
|
|
|
// Add-on update flow. checkAddonUpdates hits the release manifest and
|
|
|
|
|
|
// stages any newer signed version; listStagedAddonUpdates reports what's
|
|
|
|
|
|
// waiting; applyStagedAddons promotes staged → active and reactivates the
|
|
|
|
|
|
// addon host so the new bytes load without a full Theseus restart.
|
|
|
|
|
|
// Community extensions from theseus.x/extensions: the catalog (with what
|
|
|
|
|
|
// is installed already) and a verified install/update of one entry.
|
|
|
|
|
|
communityCatalog: () => ipcRenderer.invoke("addons-community-catalog"),
|
|
|
|
|
|
installCommunity: (id) => ipcRenderer.invoke("addons-install-community", id),
|
|
|
|
|
|
checkAddonUpdates: () => ipcRenderer.invoke("addons-check-updates"),
|
|
|
|
|
|
listStagedAddonUpdates: () => ipcRenderer.invoke("addons-list-staged"),
|
fix(theseus): extension updates re-check, announce and install in place
Updates published after launch never showed: the add-on channel was
checked once, 30 s after boot, and staged copies only applied on the
next launch with nothing telling the user. On 2026-09-22 Aegis 0.8.3
and VPN 0.1.3 landed minutes after the app's only check and stayed
invisible through manual scans made earlier and a restart made before
they were published.
Now: the check repeats every 4 hours; every check (boot, timer, manual,
add-on-driven) reports what is staged to the chrome, which shows a chip
for staged extensions; clicking it, or the "Update to vX" button that
appears on the extension's row and detail in Settings, promotes the
staged folder over the installed one and rebuilds the add-on host, so
the new version runs without a restart. Plug-ins (Aegis) are excluded
from the chip and the hot swap — a wallet updates from its own panel
and applies on the next launch.
Also from the same review: the new-tab button follows the last tab and
parks after the scroll arrow only when the strip overflows; Tor sits
left of the Aegis chip; plug-ins no longer appear in Settings ›
Extensions (they have Plug-ins); the extension detail view has a
labelled Back button, a close button and a Check now button; the
promotion helper returns what it promoted and accepts a filter.
2026-09-22 21:25:33 +02:00
|
|
|
|
applyStagedAddons: (id) => ipcRenderer.invoke("addons-apply-staged", typeof id === "string" ? id : undefined),
|
2026-09-27 20:37:30 +02:00
|
|
|
|
// Settings › Performance › Protections: talk to an add-on's own message
|
|
|
|
|
|
// handlers (Shield, Cookie Pop-ups) and open its panel for the details.
|
|
|
|
|
|
addonInvoke: (id, msg, payload) => ipcRenderer.invoke("addon-invoke", String(id || ""), String(msg || ""), payload),
|
|
|
|
|
|
openPanel: (panelId) => ipcRenderer.invoke("settings-open-panel", String(panelId || "")),
|
2026-09-27 22:01:28 +02:00
|
|
|
|
// Which page is showing (the address bar follows), Tor state + toggle for Privacy › Network.
|
|
|
|
|
|
reportSection: (slug) => ipcRenderer.invoke("settings-section", String(slug || "")),
|
|
|
|
|
|
torState: () => ipcRenderer.invoke("tor-state"),
|
|
|
|
|
|
toggleTor: () => ipcRenderer.invoke("toggle-tor"),
|
2026-09-30 02:16:11 +02:00
|
|
|
|
// OS locale — used by the Website-language row to label "Automatic (OS: …)".
|
|
|
|
|
|
systemLocale: () => ipcRenderer.invoke("system-locale"),
|
|
|
|
|
|
// Live settings updates — the toolbar chip, this page's Website-language
|
|
|
|
|
|
// row, and the Anti-fingerprinting Language row all edit the same setting;
|
|
|
|
|
|
// any of them writing pushes a "settings-update" the others react to.
|
|
|
|
|
|
onSettingsUpdate: (cb) => ipcRenderer.on("settings-update", (_e, d) => cb(d)),
|
|
|
|
|
|
// Ariadne's Thread plug-in (system-wide resolver). The state getter returns
|
|
|
|
|
|
// { state:"running"|"stopped"|"not-installed", installedVersion, bundledVersion,
|
|
|
|
|
|
// canUpdate, hasUninstaller }; the mutators prompt UAC for admin.
|
|
|
|
|
|
ariadneState: () => ipcRenderer.invoke("ariadne-state"),
|
|
|
|
|
|
ariadneToggle: (on) => ipcRenderer.invoke("ariadne-toggle", !!on),
|
|
|
|
|
|
ariadneInstall: () => ipcRenderer.invoke("ariadne-install"),
|
|
|
|
|
|
ariadneUpdate: () => ipcRenderer.invoke("ariadne-update"),
|
|
|
|
|
|
ariadneUninstall: () => ipcRenderer.invoke("ariadne-uninstall"),
|
feat(theseus/ariadne): settings panel — policy + per-source toggles + status report
Ariadne 0.1.13 exposed /api/status and per-source enable flags in
policy.json. Theseus's Plug-ins > Ariadne's Thread sub-page now wires those
into a full UI, no daemon restart, no UAC.
Added to the plugins-ariadne sub-page (after Status, before Remove):
Collision policy -- radio group (BCNR-first / ICANN-first) writes
C:\ProgramData\Ariadne\policy.json.policy; hot-reloaded
by the daemon within 5 s.
Sources -- 3-column grid, one row per source (snapshotHttps,
electrumWss, perQueryLookup, diskCache, localApi):
enable checkbox + last-state summary
(last success / last error / hit-miss counters /
disk-cache size+mtime). Toggle writes
policy.json.sources.<name>.enabled and re-polls after
the 5-s hot-reload tick so the state text catches up.
Status report -- <pre> JSON dump of GET http://127.0.0.1/api/status
with Copy report + Refresh report buttons. This is
the paste-me-into-support artefact for any diagnosis.
IPC wiring:
main.js
ariadne-get-status -> GET http://127.0.0.1/api/status ({ok, status|error})
ariadne-get-policy -> read C:\ProgramData\Ariadne\policy.json (or {})
ariadne-set-policy -> merge {policy}, write back (validates enum)
ariadne-set-source -> merge {sources.<name>.enabled}, write back
(validates against the known 5 names)
settings-preload.js
ariadneGetStatus, ariadneGetPolicy, ariadneSetPolicy, ariadneSetSource
All four handlers write policy.json as the local user; no UAC. Works because
install.ps1 grants BUILTIN\Users Modify on the file (0.1.7+).
Sub-page auto-refreshes state every time it opens (listens on the existing
'section' custom event dispatched by showSection).
Not building/shipping Theseus here -- this rides the next Theseus release.
Panel gracefully handles: daemon down (shows 'Daemon unreachable' with a
pointer to the Status toggle), localApi disabled (daemon returns 503, panel
shows the error), missing policy.json (all sources default to true).
2026-10-01 00:51:50 +02:00
|
|
|
|
// Local BNS daemon settings + status (0.1.13+). All read/write against
|
|
|
|
|
|
// C:\ProgramData\Ariadne\policy.json (user-writable ACL) and the daemon's
|
|
|
|
|
|
// own /api/status endpoint on 127.0.0.1. No UAC required for any of these.
|
|
|
|
|
|
ariadneGetStatus: () => ipcRenderer.invoke("ariadne-get-status"),
|
|
|
|
|
|
ariadneGetPolicy: () => ipcRenderer.invoke("ariadne-get-policy"),
|
|
|
|
|
|
ariadneSetPolicy: (policy) => ipcRenderer.invoke("ariadne-set-policy", String(policy || "")),
|
|
|
|
|
|
ariadneSetSource: (name, enabled) => ipcRenderer.invoke("ariadne-set-source", String(name || ""), !!enabled),
|
2026-09-30 02:16:11 +02:00
|
|
|
|
// Manual "Check for updates" — un-dismisses any existing chip and re-
|
|
|
|
|
|
// fetches the release manifest. Returns { updateAvailable, currentVersion }.
|
|
|
|
|
|
recheckUpdate: () => ipcRenderer.invoke("recheck-update"),
|
fix(theseus): an installed app can be closed and removed; Settings lists apps
An app whose page has a beforeunload handler (CoinSpectrum) could not be
closed: tabs answer the page's "stay?" request, app windows had nothing
listening, and Electron reads silence as a veto. Closing the window is now
always the user's call; a reload or navigation inside the app asks, as a
tab does.
Removing it looked dead for a related reason. The confirmation was drawn
as Theseus's sheet in the main window, where the user was not looking (or
nowhere, with the main window closed), and the removal then closed the app
window with the same call the page vetoes. The question is now asked on
the app window that asked, and removal destroys the window.
Installed apps were only reachable from the address-bar chip while on the
site. Settings gets an Apps page, at theseus://settings/apps, that lists
them with Open and Remove and follows installs, removals and open windows.
The three list calls it uses are settings-only now.
2026-10-04 19:15:11 +02:00
|
|
|
|
// Sites installed as apps (Settings › Apps).
|
|
|
|
|
|
webapps: () => ipcRenderer.invoke("webapps-list"),
|
Theseus Settings: a Sidebar section for the left strip
Quick links sat in a small block under General, and the panel behaviour
added this week (per-app widths, pins, the Opera-style auto-hide) had no
place in Settings at all. Settings › Sidebar now holds the strip switch,
the web apps (drag to reorder like Search engines, pin, reset a remembered
width, remove), the extension panels on the strip (show or hide each one,
pin, reset width) and three switches for when the open panel steps aside:
a new tab, the right side panel opening, a click in the page. Apps gains
"Add to sidebar", so an installed site can also open in the strip.
2026-10-04 21:53:39 +02:00
|
|
|
|
sidebarLeftPanels: () => ipcRenderer.invoke("sidebar-left-panels"),
|
fix(theseus): an installed app can be closed and removed; Settings lists apps
An app whose page has a beforeunload handler (CoinSpectrum) could not be
closed: tabs answer the page's "stay?" request, app windows had nothing
listening, and Electron reads silence as a veto. Closing the window is now
always the user's call; a reload or navigation inside the app asks, as a
tab does.
Removing it looked dead for a related reason. The confirmation was drawn
as Theseus's sheet in the main window, where the user was not looking (or
nowhere, with the main window closed), and the removal then closed the app
window with the same call the page vetoes. The question is now asked on
the app window that asked, and removal destroys the window.
Installed apps were only reachable from the address-bar chip while on the
site. Settings gets an Apps page, at theseus://settings/apps, that lists
them with Open and Remove and follows installs, removals and open windows.
The three list calls it uses are settings-only now.
2026-10-04 19:15:11 +02:00
|
|
|
|
webappOpen: (key) => ipcRenderer.invoke("webapps-open", String(key || "")),
|
|
|
|
|
|
webappRemove: (key) => ipcRenderer.invoke("webapps-remove", String(key || "")),
|
|
|
|
|
|
onWebappsChanged: (cb) => ipcRenderer.on("webapps-changed", () => cb()),
|
2026-09-30 02:16:11 +02:00
|
|
|
|
appVersion: () => ipcRenderer.invoke("app-version"),
|
|
|
|
|
|
restartApp: () => ipcRenderer.invoke("app-restart"),
|
2026-07-29 13:54:34 +02:00
|
|
|
|
});
|