impl(server,web,cli): extract @forager/server (tauri port phase 1)#74
Draft
andykais-claude wants to merge 1 commit into
Draft
impl(server,web,cli): extract @forager/server (tauri port phase 1)#74andykais-claude wants to merge 1 commit into
andykais-claude wants to merge 1 commit into
Conversation
Carve the RPC endpoint, media-file streaming, thumbnail streaming, and the
Forager config schema out of the SvelteKit app into a new framework-agnostic
@forager/server package.
@forager/server
- api.ts (moved from packages/web/src/lib/api.ts)
- config.ts (moved from packages/web/src/lib/server/config.ts)
- handlers/rpc.ts (wraps ts-rpc's SvelteKit adapter with a Request stub
until ts-rpc publishes a Request adapter; module is internal)
- handlers/media_file.ts, handlers/thumbnail.ts (pure Request -> Response)
- ForagerServer class with try_handle_request(request) so embedders can
mount it ahead of their own routes, plus a standalone start() for the
upcoming 'forager serve' command.
@forager/web
- SvelteKit +server.ts routes become thin delegates so dev mode (vite +
sveltekit hooks) keeps working unchanged.
- The published web.Server now accepts forager + config directly and
dispatches /rpc/* and /files/* through ForagerServer, bypassing
SvelteKit. Static assets and HTML routes still flow through SvelteKit.
- $lib/api.ts and $lib/server/config.ts become shims re-exporting from
@forager/server so frontend imports don't need to move yet.
@forager/cli
- Pass forager + config into web.Server in both 'init' and 'gui' so the
bypass kicks in.
No frontend behaviour changes. Same URLs, same response shapes.
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 1 of the Tauri port plan (
docs/design/tauri-port.md). Carves the RPC endpoint, media-file streaming, thumbnail streaming, and the Forager config schema out of the SvelteKit app into a new framework-agnostic@forager/serverpackage, so a future Tauri shell and a remote-mode browser can both talk to the same backend.No frontend behaviour changes. Same URLs, same response shapes; only the call graph behind them moves.
Walkthrough
forager_gui_phase1_smoketest.mp4
End-to-end manual test of
forager guiafter the refactor: thumbnails render, the image preview loads, the video plays (HTTP Range request served by the new@forager/serverpath).Browse view with two media tiles served via /files/thumbnail
Image preview served via /files/media_file
Video player streaming via /files/media_file with Range requests
What moves where
New:
packages/server(@forager/server)src/api.tspackages/web/src/lib/api.tssrc/config.tspackages/web/src/lib/server/config.tssrc/handlers/rpc.tspackages/web/src/routes/rpc/[signature]/+server.tssrc/handlers/media_file.tspackages/web/src/routes/files/media_file/[id]/+server.tssrc/handlers/thumbnail.tspackages/web/src/routes/files/thumbnail/[id]/+server.tssrc/server.tsForagerServerclassForagerServer.try_handle_request(request)returns aResponseif the request matches/rpc/*or/files/(media_file|thumbnail)/:id, otherwisenullso embedders can route it elsewhere.ForagerServer.start({ port, hostname })runs it standalone — that's whatforager servewill use in a later phase.Implementation note on the RPC handler: ts-rpc 0.2.4 only exports framework adapters (Oak, SvelteKit). The SvelteKit adapter only reads
event.request, so for nowcreate_rpc_handlerwraps it with a stub{ request }event. Once ts-rpc ships aRequest → Responseadapter, that wrapper goes away.Changed:
packages/websrc/lib/api.ts→ 4-line re-export shim of@forager/server/api.src/lib/server/config.ts→ 8-line re-export shim of@forager/server/config. All$lib/server/config.tsimports across the frontend keep working unchanged.src/routes/rpc/[signature]/+server.ts,src/routes/files/media_file/[id]/+server.ts,src/routes/files/thumbnail/[id]/+server.ts→ thin delegates into@forager/server/handlers. This keepsvite devworking: SvelteKit still owns the routes, the logic just lives in the new package.adapter/lib/mod.ts(the JSR-publishedweb.Server):forager+configoptions.ForagerServer.try_handle_requestbefore falling through to SvelteKit — so in production,/rpc/*and/files/*skip the SvelteKit handler entirely.Changed:
packages/cliinitandguicommands now passforagerandconfigdirectly intoweb.Serverso the bypass kicks in.Workspace
packages/serveradded to the rootdeno.jsonworkspace list.Why split this way
The design doc described
@forager/webbecoming "a thin wrapper that runs ForagerServer + serves SvelteKit assets exactly as today." This PR delivers exactly that: the runtime now has two entry points into the same handler functions — SvelteKit (for dev mode) andweb.Server(production bypass) — both backed by the new package. The bypass is what the future Tauri shell will use to talk to a remote Forager.Testing
deno check packages/server/src/mod.ts— cleandeno check packages/web/adapter/lib/mod.ts— cleandeno check packages/cli/src/cli.ts— cleandeno task compile:local— full production build of CLI binary with embedded@forager/websucceeds.deno task --cwd packages/cli test— all 2 tests pass (1 step ignored, same asmain).deno task --cwd packages/core test— 26 pass, 4 fail with the same ffmpeg-precision failures that exist onmain(verified by running onmainwith my changes stashed). Documented inAGENTS.mdas known.forager guibinary against a fresh database:curl http://127.0.0.1:8000/→200(SvelteKit HTML)PUT /rpc/forager.media.search→ JSON RPC response with the seeded media (handled by@forager/server)GET /files/thumbnail/1→200,image/jpeg, 36544 bytesGET /files/media_file/1→200,image/jpeg, 874874 bytes (byte-identical to source, EXIF preserved)GET /files/media_file/2withRange: bytes=0-1023→206,content-range: bytes 0-1023/400240(video seeking works)GET /files/media_file/9999→404 Media not found(NotFound branch)GET /nonexistent-page→404from SvelteKit (fall-through path works)The 3 HTML validation warnings the browser flagged on
<label for=…>are pre-existing and unrelated to this PR.Follow-ups (not in this PR)
Connectionabstraction throughBaseControllerand replace hardcoded/files/...URLs.adapter-static; collapseweb.Serverinto a thinner mount aroundForagerServer.To show artifacts inline, enable in settings.