impl(web): configurable Connection abstraction (tauri port phase 2)#75
Draft
andykais-claude wants to merge 1 commit into
Draft
impl(web): configurable Connection abstraction (tauri port phase 2)#75andykais-claude wants to merge 1 commit into
andykais-claude wants to merge 1 commit into
Conversation
Phase 2 of the Tauri port plan. The frontend used to hardcode same-origin
when constructing the RPC client and /files/* URLs. With Tauri (and a
'point my browser at a remote forager' use-case for the web build) on the
horizon, both need to be resolved from a runtime Connection.
new: packages/web/src/lib/connection.ts
- resolve_connection() picks a base_url in this priority order:
1. window.__FORAGER_CONNECTION__ (Tauri injects this at startup)
2. ?api=https://example.com query string
3. Same origin (current default)
- Result is cached per session.
- Trailing slashes stripped for predictable URL building.
new: packages/web/test/connection.test.ts
- 8 unit tests covering each branch + caching + SSR placeholder fallback.
BaseController and Rune
- Both accept an optional Connection (default = resolve_connection()).
- Both expose media_url(id) and thumbnail_url(id, index?) helpers so the
rest of the SPA never builds those URLs by hand.
- BaseController's RPC client URL now derives from connection.base_url.
callers
- lib/runes/media_view_rune.svelte.ts: preview_thumbnail now uses
this.thumbnail_url(...) on both MediaViewRune and MediaGroupRune.
- routes/browse/components/MediaView.svelte: media_url, audio thumbnail
src, and the filmstrip thumbnails all go through controller.{media,
thumbnail}_url(...).
Browser experience is identical for the same-origin default path. The two
new branches are exercised by the unit tests; visual smoke-tested in a
Chromium webview.
Co-authored-by: andykais-claude <andykais-claude@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 2 of the Tauri port plan. Stacked on top of phase 1 — please review/merge phase 1 first, then this. (Base branch is intentionally
cursor/tauri-server-phase1-1e82; rebase tomainonce phase 1 lands.)The frontend used to hardcode same-origin when constructing the RPC client and
/files/*URLs. With Tauri (and a "point my browser at a remote forager" use-case for the web build) on the horizon, both need to come from a runtimeConnection.Walkthrough
forager_phase2_connection_smoketest.mp4
Browser smoke test of the resolver: thumbnails, RPC, image preview, and video playback (HTTP
Range) all working through the newcontroller.media_url/controller.thumbnail_urlhelpers.Same-origin default — thumbnail src is http://127.0.0.1:8000/files/thumbnail/...
?api=... query string accepted; SPA boots and renders
Cronch video streaming via the new media_url helper
What changed
New:
packages/web/src/lib/connection.tsThe
Connectionabstraction the design doc described in §5.resolve_connection()picks a base URL in priority order:window.__FORAGER_CONNECTION__— injected by the Tauri shell before the SPA boots.?api=https://example.comquery string — handy for the browser-served build pointing at a different backend.Trailing slashes stripped, result cached per session, SSR/test path returns an empty placeholder so module load doesn't blow up.
New:
packages/web/test/connection.test.ts8 unit tests covering every branch, plus caching and the SSR placeholder. Run with
deno test packages/web/test/connection.test.ts. These nail down the resolver behaviour without needing a browser, which the in-page smoke test couldn't do reliably (CORS not in scope until phase 4).BaseController(packages/web/src/lib/base_controller.ts)connection: Connectionfield, populated from a constructor arg (defaults toresolve_connection()).connection.base_urlinstead ofwindow.location.protocol + host(this also incidentally fixes a missing//in the old string concatenation).media_url(id)andthumbnail_url(id, index?)helpers so the rest of the SPA never builds those URLs by hand.Rune(packages/web/src/lib/runes/rune.ts)Same treatment — accepts an optional
Connection(defaultresolve_connection()) and exposes the same two URL helpers asprotectedmethods.MediaViewRune.preview_thumbnailis the consumer today; the helpers are there for any future rune that needs to build asset URLs.Replaced: every hardcoded
/files/*literal in the frontendMediaViewRune.preview_thumbnail`/files/thumbnail/${...?.id}`this.thumbnail_url(thumbnail.id)MediaGroupRune.preview_thumbnail`/files/thumbnail/${...id}`this.thumbnail_url(...)MediaView.sveltemedia_urlderivable`/files/media_file/${ref.id}`controller.media_url(ref.id)MediaView.sveltefilmstrip<img src>/files/thumbnail/{id}?index={i}controller.thumbnail_url(id, i)MediaView.svelteaudio thumbnail<img src>/files/thumbnail/{id}controller.thumbnail_url(id)grep -rn '/files/(media_file\|thumbnail)' packages/web/srcnow only matches the two helper bodies (base_controller.ts,rune.ts).Why default-resolve in the constructor instead of plumbing through
+page.svelte?Tauri injects
window.__FORAGER_CONNECTION__before any SPA code runs, and the browser-served build either picks up?api=from the URL or falls back to same-origin. In every caseresolve_connection()is correct by the time a controller is constructed. Plumbing through layout/page data would just be ceremony with no runtime effect, and the design doc didn't call for it. Both the constructor andRunestill accept an explicitConnectionfor testability and for any future case that wants to override.Testing
deno test packages/web/test/connection.test.ts— 8 / 8 pass.deno task --cwd packages/web build:local— clean.deno task compile:local— full CLI binary builds.deno task --cwd packages/cli test— 2 / 2 pass.grep -oE '/files/(media_file|thumbnail)[^"\]{0,80}' .../chunks/*.jsshows only/files/media_file/${t}and/files/thumbnail/${t}template-literal placeholders — i.e. the helpers concatenateconnection.base_url + /files/...` at runtime as intended.srcresolves tohttp://127.0.0.1:8000/files/thumbnail/....?api=http://127.0.0.1:8000: SPA still boots, thumbnails render, no console errors.deno checkagainst the SvelteKit source surfaces 91 pre-existing errors ($app/navigationresolution, Deno globals not typed when checked outsidedeno task) — same count and same files on phase 1's tip, verified bygit stash+ recheck. Build is the actual gate and it's clean.Follow-ups (not in this PR)
adapter-staticswitch; collapse the custom Deno SvelteKit adapter once the SPA is fully decoupled.web.server.cors_allow_originsso a browser-served?api=against a different host actually works (today both ends would be same-origin, so the SPA loads fine but a true cross-origin remote would hit CORS).To show artifacts inline, enable in settings.