Commit Graph
7 Commits
Author SHA1 Message Date
tomdebone 6a82c906de tauri-app: tray settings menu item
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'.
2026-07-07 18:57:45 +02:00
tomdebone 550b89673d feat(tauri-app): expand tray menu + open_external_url + Profile/Search items
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).
2026-07-07 17:31:09 +02:00
tomdebone 6a85f44bab fix(tauri-app): guard Tauri runtime in client.ts and main.ts
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.
2026-07-07 08:30:48 +02:00
tomdebone 0fbae97306 fix(tauri-app): vite bind 127.0.0.1 (not localhost)
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:`.
2026-07-07 07:22:33 +02:00
tomdebone b912132a05 tauri-app: 8a review fixes
- 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.
2026-07-06 18:53:09 +02:00
tomdebone 226cfdac5c tauri-app: switch to native title bar (fixes drag + clicks)
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).
2026-07-06 16:29:39 +02:00
tomdebone c586fd39c9 maarcadetweet: initial commit
AT Protocol PDS + AppView + Tauri Desktop Client, 160-char post limit.

- PDS (Rust + axum + sqlx)
  - Auth: createAccount, createSession, refreshSession
  - Records: createRecord, deleteRecord (race-safe via SELECT FOR UPDATE)
  - Feed: feed.like.create, feed.repost.create
  - Sync: getRepo, getBlocks, getLatestCommit, getRecord (with MST proof), listRepos
  - Identity: resolveHandle
  - MST: spec-conformant (at-mst crate, 27 tests)
  - Repo: signed commits, TID counter (monotonic, 4096 wrap safe)

- AppView (Rust + axum + sqlx)
  - Jetstream consumer (WebSocket, exponential backoff, 38k+ events indexed)
  - REST API: timeline/home (graph-aware), profile, search, post (with thread hydration)
  - Handle-sync worker (did:plc + did:web)
  - JSONB embed storage + thread columns (migration 0003)
  - Like/repost counter cache (migration 0004)

- Tauri 2 + Svelte 5 Desktop Client
  - System tray (Show/Compose/Quit menu)
  - OS notifications (tauri-plugin-notification)
  - Auto-update (tauri-plugin-updater, placeholder endpoint)
  - Window-state (tauri-plugin-window-state)
  - 160-char compose with live counter
  - Image/Link embed rendering
  - LocalStorage-persisted like state
  - Timeline with poll (prepend new posts)
  - Custom TitleBar (transparent, no decorations)
  - Orange/IBM Plex Mono maarcade design

Tests: 231 Rust + 9 vitest = 240 passed.
2026-07-05 20:01:31 +02:00