7cfeddc770f3455104e93a4c5bcc6dbd5cfab42d
17 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
df005e2963 |
feat(packaging/web): bundle the web console into the apt install (punktfunk-web)
android / android (push) Failing after 22s
deb / build-publish (push) Failing after 0s
decky / build-publish (push) Failing after 0s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Failing after 1s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Failing after 0s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Failing after 1s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Failing after 0s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Failing after 0s
flatpak / build-publish (push) Failing after 1s
docker / deploy-docs (push) Has been skipped
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Failing after 0s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Failing after 0s
apple / swift (push) Successful in 53s
ci / web (push) Successful in 28s
ci / docs-site (push) Successful in 34s
ci / bench (push) Successful in 1m32s
ci / rust (push) Failing after 53s
Every user needs the console for pairing, so ship it via apt, auto-wired to the host — no manual bun/env setup. New punktfunk-web .deb (Architecture: all, Depends: nodejs >= 20 — runs the node-server build under apt-native node, no bundled bun): - packaging/debian/build-web-deb.sh: stages web/.output (server + public) + a /usr/bin/punktfunk-web-server wrapper (node) + the systemd --user units + the web.env template + docs. Refuses a bun bundle (Bun.serve) as a wrong-preset guard. - scripts/punktfunk-web.service: --user unit on :3000, EnvironmentFile sources the host's ~/.config/punktfunk/mgmt-token (the shared bearer) + the generated web-password; sets PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990 + NODE_TLS_REJECT_UNAUTHORIZED=0 (loopback self-signed cert). Restart=on-failure rides out the host-writes-token-first ordering. - scripts/punktfunk-web-init.service + web-init.sh: --user one-shot that generates the login password (a .deb postinst runs as root → wrong $HOME) and surfaces it to the journal. - build-deb.sh: punktfunk-host now Recommends punktfunk-web (apt pulls it by default; headless boxes opt out with --no-install-recommends). - deb.yml: build the web console + smoke-boot it under node (gate the .deb on a real /login 200) + build-web-deb.sh; the publish loop globs it automatically. - web/{.env.example,web.env.example}: document the auto-wiring vs a manual deploy. End state: `apt install punktfunk-host` pulls punktfunk-web; enable both --user services; the console logs in (password from the journal) and proxies the host's HTTPS mgmt API with the shared token — zero hand-edited env. Local .deb build + node smoke-boot verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
b2a335122e |
build(web): node-server preset (apt-native runtime, no bun dependency)
decky / build-publish (push) Failing after 0s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Failing after 1s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Failing after 0s
android / android (push) Failing after 20s
ci / web (push) Failing after 12s
ci / docs-site (push) Failing after 0s
ci / bench (push) Failing after 1s
deb / build-publish (push) Failing after 0s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Failing after 0s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Failing after 1s
docker / deploy-docs (push) Has been skipped
flatpak / build-publish (push) Failing after 1s
ci / rust (push) Failing after 2m24s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Failing after 0s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Failing after 0s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Failing after 1s
apple / swift (push) Successful in 54s
Switch the Nitro build preset from `bun` to `node-server` so the built .output/server is a standalone HTTP server runnable by apt-native `node` (validated: `node .output/server/index.mjs` → Listening, /login 200 on node v25.9.0). This lets the upcoming punktfunk-web .deb depend on `nodejs (>= 20)` instead of vendoring the bun binary. CI still BUILDS with bun; only the runtime target changes, and bun still runs a node-server build, so existing `bun run .output/server/index.mjs` deployments keep working. `vite dev` is unaffected. Prereq for bundling the web console into the apt install. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
b2e5878711 |
feat(host/mgmt): HTTPS + token auth by default (no loopback no-auth fallback)
android / android (push) Failing after 21s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Failing after 0s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Failing after 1s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Failing after 1s
ci / rust (push) Failing after 2m27s
ci / web (push) Failing after 10s
ci / docs-site (push) Failing after 0s
ci / bench (push) Failing after 1s
deb / build-publish (push) Failing after 0s
decky / build-publish (push) Failing after 1s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Failing after 0s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Failing after 0s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Failing after 0s
docker / deploy-docs (push) Has been skipped
flatpak / build-publish (push) Failing after 0s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Failing after 0s
apple / swift (push) Successful in 53s
The mgmt API already always serves HTTPS (the host identity cert), but on a loopback bind with no token it ran unauthenticated — any local process could drive it. Make auth required ALWAYS: - new mgmt_token::load_or_generate(): token precedence is --mgmt-token > env PUNKTFUNK_MGMT_TOKEN > persisted ~/.config/punktfunk/mgmt-token > freshly generated 32-byte hex, persisted 0600 in KEY=VALUE form (so the bundled web console can source it directly as a systemd EnvironmentFile — one source of truth). config_dir() made pub(crate). - parse_serve() resolves the token via load_or_generate() when unset, so a bare `serve` Just Works with auth on and no operator step. - mgmt::run() drops the loopback no-token exemption and requires a token; require_auth()'s unauthenticated fallback now returns 401. The paired-cert (mTLS) branch is unchanged — Apple client + library auth unaffected. - web /api proxy: 503 (legible) instead of forwarding an empty bearer. - tests: test_app/test_app_native default a token, send() auto-attaches the bearer; blank-token test asserts the new "no token" refusal. 80 pass. - docs: mgmt module doc + host.env.example reflect always-on auth + auto-gen. Compiles, clippy/fmt clean, openapi no drift. Part B (bundle the web console into apt, auto-wired to this token) follows. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
95c4058582 |
fix(web): default mgmt proxy to the HTTPS self-signed mgmt API
apple / swift (push) Successful in 54s
android / android (push) Failing after 54s
ci / web (push) Successful in 38s
ci / docs-site (push) Successful in 34s
ci / rust (push) Failing after 2m30s
ci / bench (push) Failing after 1m15s
decky / build-publish (push) Failing after 4s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Failing after 0s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Failing after 1s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Failing after 0s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Failing after 1s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Failing after 0s
docker / deploy-docs (push) Has been skipped
flatpak / build-publish (push) Failing after 0s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Failing after 1s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Failing after 0s
deb / build-publish (push) Successful in 3m22s
The mgmt API serves HTTPS with the host's self-signed identity cert and requires mTLS-or-bearer auth (the mTLS work), but the web console's proxy still defaulted to `http://127.0.0.1:47990` — so a deployment copying .env.example got a plain-HTTP request to an HTTPS port (→ 502 Bad Gateway, observed live on the Bazzite box). - .env.example + server/util/auth.ts + vite.config.ts: default PUNKTFUNK_MGMT_URL to https://127.0.0.1:47990. - vite dev proxy: `secure: false` (the host cert is self-signed). - Document that the deployment needs PUNKTFUNK_MGMT_TOKEN (matching the host's) and NODE_TLS_REJECT_UNAUTHORIZED=0 — the web server's only outbound TLS is the loopback hop to the host's own self-signed cert, so disabling verify there is scoped + safe. The running Bazzite box is already fixed live (web.env → https + token + cert-skip, verified: login 200, /api/v1/status 200). This makes fresh deployments correct. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
6136ba4c72 |
feat(web/library): game library page — grid + custom-entry CRUD
ci / rust (push) Successful in 2m9s
apple / swift (push) Successful in 1m14s
ci / web (push) Successful in 30s
ci / docs-site (push) Successful in 35s
ci / bench (push) Successful in 1m32s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 13s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 5s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
deb / build-publish (push) Successful in 2m11s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 4m53s
docker / deploy-docs (push) Successful in 18s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 4m48s
Consumes the new library API (
|
||
|
|
99b4de32ee |
feat(pairing): delegated approval (§8b-1) — approve an unpaired device from the console
ci / web (push) Failing after 40s
ci / rust (push) Successful in 1m6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 13s
apple / swift (push) Successful in 1m20s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
ci / docs-site (push) Failing after 46s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 18s
docker / deploy-docs (push) Successful in 16s
An identified-but-unpaired device that knocks on a pairing-required host is now
held as a pending request the operator approves from the web console — pairing it
with no PIN fetched out of band — instead of a flat reject.
- core: Hello gains an optional trailing device name (len u8 || UTF-8, ≤64,
same trailing-back-compat pattern as compositor/gamepad/bitrate). client-rs
--name sends it; the connector sends None (fingerprint-derived label).
- native_pairing: in-memory pending queue (note_pending dedups by fingerprint,
evicts the least-recently-active past a 32 cap, 10-min TTL); approve_pending
pins the fingerprint, deny drops it. Names are sanitized (strip control/ANSI/
bidi — untrusted wire input); add()/remove() roll back in-memory on a persist
failure; pairing clears any stale pending knock.
- m3: the require_pairing gate records the knock (sanitized label) before
rejecting; anonymous (certless) clients record nothing.
- mgmt: GET /native/pending, POST /native/pending/{id}/approve (optional {name})
and /deny; OpenAPI + tests; docs/api/openapi.json regenerated.
- web: a "Waiting for approval" section on the Pairing page (live-poll, Approve/
Deny, error-surfaced via QueryState); en+de strings.
- Also completes an in-progress NativeClient Sync refactor (receivers behind
per-plane mutexes) that was left half-applied in the tree.
Adversarially reviewed (4 lenses + 3-vote verify); the confirmed findings are
fixed here. Validated live on the GNOME box: knock (with a wire name, and a
malicious ANSI/bidi name that got neutralized) → pending → approve → the same
identity streams real video. Full workspace tests + clippy + fmt green; web tsc
clean. Roadmap §8b-1 marked done; §8b-2 (peer-push approval) is the client
follow-up. See docs-site pairing page.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
d0f8896570 |
fix(web): mobile navigation — add a bottom tab bar + top bar
ci / web (push) Failing after 49s
ci / rust (push) Successful in 55s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 13s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
apple / swift (push) Successful in 1m19s
ci / docs-site (push) Failing after 37s
docker / deploy-docs (push) Successful in 16s
The app shell's only navigation was the desktop sidebar (`hidden … sm:flex`), so on phones (< sm) it was hidden with no replacement — you couldn't navigate at all. Add a responsive mobile layout shown only below `sm`: a top bar (brand + language switcher) and a fixed bottom tab bar with the five nav items (icon + label). The desktop sidebar is unchanged. Page content gets bottom padding so the fixed bar doesn't cover it, and the bar respects the iOS `safe-area-inset-bottom`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f1af74b403 |
feat(ci): Gitea Actions — dockerized web/docs/rust-ci images, Apple client CI, Mac runner
apple / swift (push) Failing after 3s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / web (push) Has been cancelled
ci / rust (push) Has been cancelled
Three workflows: ci.yml (Rust workspace inside the punktfunk-rust-ci builder image + web/docs-site build+typecheck), docker.yml (build+push punktfunk-web, punktfunk-docs, punktfunk-rust-ci to git.unom.io — host and native clients stay un-dockerized by design), apple.yml (host-mode macos-arm64 runner: Rust core -> PunktfunkCore.xcframework -> swift build + swift test). ci/rust-ci.Dockerfile: Ubuntu 26.04 with the workspace's link deps (FFmpeg 8, PipeWire, Opus, GL/EGL/GBM, xkbcommon, libcuda via the 580-server userspace as a link stub) + pinned rustup + node for the JS actions. Verified end to end in-container: build, 141/141 tests, C ABI harness; all three images seeded to the registry manually. scripts/ci/setup-macos-runner.sh provisions the Mac (rustup + darwin targets, Node tarball, gitea-runner 1.0.8 host mode, LaunchAgent with DEVELOPER_DIR auto-detect for sudo-free Xcode selection). Docs in docs-site/content/docs/ci.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
76d5e41dc5 |
chore(web): check in the inlang project_id
ci / rust (push) Has been cancelled
Machine-generated on first open of the web console; inlang's tooling expects it committed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
f8c2ecf85f |
feat(web): "Pair a device" card — native pairing from the console
ci / rust (push) Has been cancelled
Completes the web-UI native (punktfunk/1) pairing flow the unified host backs. The Pairing page now leads with a native card that arms a window via the mgmt API and DISPLAYS the host PIN (the SPAKE2 ceremony is host-mints / client-enters) with a live countdown + Cancel, plus a paired-devices list with unpair — no journalctl. The existing Moonlight PIN-submit moves into its own section below. Uses the orval-generated `native` hooks (regenerated from the committed OpenAPI on build) + en/de strings. Validated end-to-end through the web server's proxy + cookie auth: login → status → arm (PIN shown) → clients. tsc + production build clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
6575dddac7 |
fix: keep the workspace green on macOS after the mic/touch/rich-input batch
The new features were Linux-built only and broke the documented macOS gate (cargo build/test/clippy --workspace) four ways, all fixed following the existing platform-gating conventions: - m3.rs: mic_service_thread split into the Linux worker and a non-Linux stub that drains and drops (sessions still count the datagrams) — opus/PipeWire are Linux-gated deps, same pattern as audio_thread. - punktfunk-client-rs: the new `opus` dependency moved into the Linux target table and --mic-test gated with a warn-and-skip stub (only the synthetic-tone test rig needs the encoder; the mic uplink itself is portable). - gamestream/audio.rs: SAMPLE_RATE import gated to any(linux, test) (the frame_sizing test uses it everywhere, the data plane only on Linux). - tests/c_abi.rs: the harness's macOS link flags gained Security + CoreFoundation — the quic feature now pulls rustls's platform verifier into the staticlib. Also: two clippy match-ref-pats lints in the new rich-input/HID-output decoders (clippy -D warnings is the repo gate), the regenerated punktfunk_core.h committed (the checked-in copy predated the rich-input/HID-output constants — CI fails on drift), and web's inlang cache dir gitignored. cargo build/test/clippy/fmt --workspace: green on macOS, 122 tests passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
6fdf7d1511 |
feat: client-selectable compositor (protocol → host → client → C ABI → mgmt → web)
A client can now request which compositor backend the host drives its virtual
output on (gamescope/KWin/Mutter/wlroots). The host honors the request if that
backend is available, else falls back to auto-detect and reports the resolved
choice back — wire-compatible both directions (no ABI bump).
Protocol (punktfunk-core):
- New CompositorPref (config.rs): Auto|Kwin|Wlroots|Mutter|Gamescope with
u8/name mappings. Appended as one optional byte to Hello (client preference)
and Welcome (host's resolved choice). Both decoders already tolerate trailing
bytes, so old↔new interop is preserved — ABI_VERSION stays 2. Round-trip +
back-compat (truncated-message) tests.
- C ABI: punktfunk_connect_ex(compositor) + PUNKTFUNK_COMPOSITOR_* constants;
punktfunk_connect delegates with AUTO, so the existing symbol is unchanged.
NativeClient::connect / worker_main thread the preference through.
Host:
- vdisplay::available() enumerates usable backends via cheap, side-effect-free
probes (KWin zkde global, gamescope binary+version, GNOME/Sway env), plus
Compositor id/label/as_pref/from_pref/all helpers.
- m3 handshake resolves the preference to a concrete backend during the
handshake (pick_compositor pure + resolved logging), reports it in Welcome,
and threads it into virtual_stream (replacing the unconditional detect()).
- mgmt GET /v1/compositors lists every backend with availability + the
auto-detected default (OpenAPI regenerated).
Client:
- punktfunk-client-rs --compositor NAME; logs the host's resolved choice from
the Welcome ("session offer … compositor=…").
Web console:
- Host page gains a Compositors card (availability + default badges) via the
codegen'd useListCompositors hook; en/de strings added.
Also fixes a pre-existing, env-dependent test-isolation bug:
mgmt::tests::paired_clients_list_and_unpair seeded the real
~/.config/punktfunk/paired.json (AppState::new loads it), so a real
GameStream-paired client leaked into body[0] on a dev box — now cleared first.
Live-validated against headless KWin: --compositor kwin honored, --compositor
mutter falls back to kwin (available=[kwin, gamescope]), resolved choice
round-trips to the client. Tests: +6 (wire/back-compat, resolution precedence,
endpoint); workspace green, clippy/fmt clean, C ABI harness PASS at abi_version=2,
web typecheck + build clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
c9ad74a620 |
fix(web): harden BFF auth — adversarial-review fixes
ci / rust (push) Has been cancelled
Multi-agent security review of
|
||
|
|
9856c04b75 |
feat(web): login-gated BFF auth — sealed session cookie + server-side token injection
ci / rust (push) Has been cancelled
Single-user, LAN-reachable-but-gated. The web server is a backend-for-frontend:
- Login: POST /_auth/login {password} checks PUNKTFUNK_UI_PASSWORD (constant-time) and
sets a SEALED session cookie (h3 useSession / AES-GCM). server/middleware/auth.ts gates
every request — pages 302 → /login, /api → 401 — and FAILS CLOSED (503) when
PUNKTFUNK_UI_PASSWORD is unset, so a misconfigured LAN-exposed server admits no one.
- The management API stays loopback-only + token (never LAN-exposed). The proxy
(server/routes/api/[...].ts) injects PUNKTFUNK_MGMT_TOKEN server-side and drops the
browser's cookie before forwarding — the token never reaches the browser, which only
holds the session cookie.
Nitro doesn't auto-scan a server/ dir, so the Nitro plugin gets an explicit scanDirs to
pick up middleware + routes. Client: removed the localStorage token (server injects it);
the fetcher bounces to /login on 401; new /login page (bare, no shell); Settings drops the
token field and gains a Sign-out button; en/de strings.
Validated live end to end: unauth /→302, /api→401; wrong pw→401; right pw→200+cookie;
authed /api/v1/status→200 (proxied, mgmt token injected — the host required it); logout→
session cleared→401. tsc + build green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
7e4ae05944 |
refactor(web): switch to Bun + Nitro v2 (bun preset) — proper TanStack Start deploy
ci / rust (push) Has been cancelled
The earlier "render the shell with a custom script" was a hack. The real issues were a version matrix and a missing server target: - TanStack Start's start-plugin-core peer-requires Vite >= 7; on Vite 6 the build's prerender/post-build buildApp plugin hook silently doesn't run (Vite 6 lets a config-level builder.buildApp suppress plugin buildApp hooks; Vite 7 runs both). Pinned Vite ^7 + @vitejs/plugin-react ^5 (v5 ↔ Vite 7; v6 needs Vite 8 / vite/internal). - Added @tanstack/nitro-v2-vite-plugin with the `bun` preset — the server/deploy target. `bun run build` → .output/ (bun-runnable server + .output/public). `bun run start` = `bun run .output/server/index.mjs`. - Full SSR instead of SPA mode: SPA-shell prerender points its preview server at the old dist/server/server.js path that Nitro relocates, breaking the build. The Nitro server renders the shell per request; React Query fetches client-side after hydration. - Nitro routeRules proxy /api/** → PUNKTFUNK_MGMT_URL (default 127.0.0.1:47990), so the browser stays same-origin (bearer token rides along, no CORS). Toolchain is now Bun (package manager + runtime): bun.lock replaces pnpm-lock.yaml; scripts/prepare/start use bun. Validated live: bun build → .output, bun server SSR-renders the console on :3000 and proxies the API (health/host return through it). tsc clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
381b059852 |
fix(web): add @vitejs/plugin-react — dev mode needs the React Refresh runtime
ci / rust (push) Has been cancelled
TanStack Start's dev server requires a React Refresh plugin; without it `/@react-refresh` 404s, the client entry 500s, and nothing hydrates (blank screen — the production build was unaffected since rollup handles JSX there). Pinned to the v4 line: plugin-react 6 imports `vite/internal` (Vite 7 only) and we're on Vite 6. Must sit after tanstackStart() in the plugin list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e0b166ad60 |
feat(web): management console — TanStack Start + orval + shadcn + Paraglide
ci / rust (push) Has been cancelled
Browser UI for the host's management REST API (mgmt.rs / docs/api/openapi.json). Stack, exactly as specified: - TanStack Start (Vite, SPA mode) — file-based routes, SSR shell + client hydration. - React Query via orval codegen from the checked-in OpenAPI spec: a custom fetch mutator (src/api/fetcher.ts) centralizes the base URL, the bearer token (Settings → localStorage), JSON, and a throwing ApiError; the query client skips retries on 4xx. orval returns the response body directly (includeHttpResponseReturnType:false) so a query's `.data` is the typed payload; GET→useQuery, POST/DELETE→useMutation by method. - shadcn/ui on Tailwind v4 (CSS-first tokens, dark-first) — button/card/badge/input/label/ table/skeleton primitives hand-authored from the canonical source. - Paraglide i18n (en + de) with a reactive useLocale() hook and a language switcher. Pages: dashboard (live status — video/audio/session/stream, stop-session + request-IDR, 2s polling), host (identity/codecs/ports), clients (paired list + unpair), pairing (PIN submit, polls pin_pending), settings (API token + language). Dev server proxies /api → 127.0.0.1:47990 (same-origin, no CORS; PUNKTFUNK_MGMT_URL to override). Generated code (orval client, paraglide runtime, routeTree) is gitignored and reproduced by `pnpm codegen` (prepare/pre* scripts). Validated live against `serve`: API shapes match, dev proxy works, SSR shell renders the localized nav, build + tsc green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |