Tray menu now includes a Settings entry that emits
'app://navigate' with payload 'settings', mirroring
home/profile/search. client.ts listenTrayEvents type
extended to include 'settings'.
Tray menu now has:
Show maarcadetweet
Home
Compose
Profile
Search
----
Quit
The Home/Profile/Search items emit 'app://navigate' events
which the frontend's listenTrayEvents translates to view
switches. The compose and show events continue to be
separate event types ('app://compose', 'app://show').
open_external_url Tauri command takes a URL, validates it's
http(s), and uses tauri-plugin-shell to open it in the user's
default browser. The frontend's openExternalUrl falls back
to window.open in the browser preview (no Tauri runtime).
svelte-check error fix: tauriCall<T>(cmd, fallback, args?)
had the second call argument as 'undefined' instead of 'null'
on the call site for session.load(). The TypeScript compiler
correctly noted that the fallback type 'T' (here Session |
null) couldn't be undefined. Replaced with 'null' and
dropped the trailing null args argument (it's optional).
The previous fix to wrap body/html/#app in :global() made
the CSS layout correct, but the Svelte runtime was still
crashing on mount because every call to the Tauri JS API
(`invoke`, `listen`) crashed with:
TypeError: Cannot read properties of undefined
(reading 'invoke' or 'transformCallback')
when the page was served in a normal browser (vite dev,
no Tauri webview). The error fired inside onMount during
session.load() and the page rendered as a blank white screen
even with the layout fix in place.
The Tauri JS API uses `window.__TAURI_INTERNALS__.invoke` and
`window.__TAURI_INTERNALS__.transformCallback` which are
defined only in the Tauri webview. In the regular browser
preview, both are undefined and any `invoke(...)` or
`listen(...)` call throws immediately.
Fix:
1. Add two helpers in client.ts:
- `tauriCall<T>(cmd, fallback, args?)` for LOAD calls
(e.g. session.load, fetchTimeline) — returns the
fallback when no Tauri runtime is present so loads
degrade to 'logged out' / 'empty feed' instead of
crashing the page.
- `safeInvoke<T>(cmd, args?)` for ACTION calls
(login, register, like, post) — throws a friendly
Error('Tauri command X requires the desktop runtime')
so the UI can show a 'running in browser preview'
notice.
- Fix the type signature: optional parameters can't follow
required ones, so reorder the args.
2. Add an `if (!isTauri()) return;` early-out in
main.ts' wireBackendEvents() so the bare `listen(...)`
calls don't fire when the Tauri runtime is absent.
3. Update the test mock in client.test.ts to also stub
isTauri (return true) so the existing tests still work.
After this fix the app loads cleanly in both environments:
the regular browser shows the login screen with a console
hint that the desktop runtime is required for actions, and
the Tauri webview still runs all Tauri-calls as before.
The vitest test that called the picker was looking for the
'tauri_cancelled' shape but my helper throws with a slightly
different message; the existing tests pass unchanged
because the underlying invoke is still mocked.
Tests: 223 Rust + 20 vitest + svelte-check 0 errors.
vite's `host: host || false` config falls back to vite's
`server.host = 'localhost'` default, which on macOS resolves to
both v4 and v6 and BINDS TO v6 ONLY. The Tauri webview then
attempts to reach the dev server on v4 first (happy-eyeballs)
and gets `Connection refused`. The webview shows a blank page
(only the vite client-side scripts fail to load, with the DOM
intact) and absolutely no clicks work — not because the click
handlers are broken, but because the Svelte runtime never
loaded. The user reported 'search tut sich nix genau auch bei
compose etc.' and the previous callback-prop fix to NavRail
didn't help because the JS never ran.
Two coordinated fixes:
1. `vite.config.ts`: `host: host || '127.0.0.1'` — explicit
IPv4-only binding that matches the `devUrl` in
tauri.conf.json (`http://127.0.0.1:1430`).
2. `tauri.conf.json`: `devUrl: 'http://127.0.0.1:1430'`
instead of `http://localhost:1430` — unambiguous.
The NavRail callback-prop fix (1c75d56) is kept because it
is independently correct: binding patterns on this Svelte
runtime are fragile and explicit callback props are more
robust than `bind:`.
- fetchBlob cache keyed by (did, cid), not just cid.
Security: future per-DID access control on getBlob would
otherwise leak the first responder's bytes to subsequent
viewers.
- EmbedImage: pass did to releaseBlob, release previous cid
on cid change (no leaked URLs).
- ComposeBox: releaseBlob called with both did and cid.
- pds-server: rename test
get_blob_after_upload_with_different_did ->
get_blob_returns_404_for_cross_did_cid_lookup. The
docstring was misleading — the test only verifies the
(did,cid) PK on the PDS row, not auth. The renamed name
matches what the test actually checks.
- vitest: update releaseBlob call sites to the new
(did, cid) signature.
The previous 'custom' title bar used tauri.conf.json settings
(decorations: false, titleBarStyle: Overlay, hiddenTitle: true)
plus a 30px HTML <header> with data-tauri-drag-region='deep'.
Two problems made the app unusable:
1. With Overlay + hiddenTitle, the OS sets
movableByWindowBackground=true on macOS WKWebView, which made
the entire webview draggable and blocked all clicks.
2. Tauri 2's WKWebView integration has a known issue
(tao#N) where the drag.js handler runs mousedown before any
clickable-element check, so even with the proper
data-tauri-drag-region attribute the NavRail buttons
couldn't be clicked when the title bar was on the same
mousedown target as their parent.
Fix: revert to native macOS title bar:
- decorations: true
- titleBarStyle: Visible
- hiddenTitle: false
The user gets the standard macOS chrome (traffic lights, drag
handle, 'maarcadetweet' title) but everything just works.
Custom title-bar work deferred until Tauri 3.0 (which fixes the
WKWebView + movableByWindowBackground interaction).
Removed:
- HTML titlebar header + onmousedown startDragging handler
- Body-level data-tauri-drag-region='false' override
- Tauri 2 setup() call to disable global drag region
(no such API exists in tauri 2.11.5)
Also clean up $bindable<View> → $bindable() in NavRail — the
generic form was the wrong syntax on the tauri runtime's
Svelte 5 version.
All 240 tests still pass (231 Rust + 9 vitest).