From 5585a6ecc3bb0fc47cd068e146e447badfc778f2 Mon Sep 17 00:00:00 2001 From: zwitschi Date: Sun, 16 Aug 2026 09:26:35 +0200 Subject: [PATCH] fix(frontend): prefix auth API requests with VITE_PUBLIC_APP_URL for cross-origin Workers hosting --- .gitea/workflows/cd.yml | 4 +-- .gitea/workflows/workers-deploy.yml | 7 ++++++ .github/instructions/TODO.md | 5 ++++ CHANGELOG.md | 5 ++++ README.md | 4 +-- backend/playout/start-playout.sh | 4 +-- docs/architecture/README.md | 2 +- docs/operations/cloudflare-workers-setup.md | 28 +++++++++------------ docs/operations/gitea-cloudflare-workers.md | 20 ++++++++++++--- frontend/src/main.ts | 3 ++- 10 files changed, 54 insertions(+), 28 deletions(-) diff --git a/.gitea/workflows/cd.yml b/.gitea/workflows/cd.yml index f68e99c..93f4466 100644 --- a/.gitea/workflows/cd.yml +++ b/.gitea/workflows/cd.yml @@ -39,8 +39,8 @@ jobs: # Playout PLAYLIST_PATH=/app/playlist/playlist.txt - HLS_SEGMENT_DURATION=6 - HLS_WINDOW_SIZE=24 + HLS_SEGMENT_DURATION=2 + HLS_WINDOW_SIZE=12 LOG_LEVEL=info # Cloudflare R2 (required for HLS segment sync) diff --git a/.gitea/workflows/workers-deploy.yml b/.gitea/workflows/workers-deploy.yml index b9c0eae..4884d74 100644 --- a/.gitea/workflows/workers-deploy.yml +++ b/.gitea/workflows/workers-deploy.yml @@ -23,6 +23,13 @@ jobs: run: cd frontend && npm ci - name: Build + env: + VITE_PUBLIC_APP_URL: ${{ secrets.VITE_PUBLIC_APP_URL }} + VITE_PUBLIC_WS_URL: ${{ secrets.VITE_PUBLIC_WS_URL }} + VITE_PUBLIC_HLS_URL: ${{ secrets.VITE_PUBLIC_HLS_URL }} + VITE_PUBLIC_ADMIN_DEFAULT_MODERATOR: ${{ secrets.VITE_PUBLIC_ADMIN_DEFAULT_MODERATOR }} + VITE_PUBLIC_ADMIN_DEFAULT_ROOM: ${{ secrets.VITE_PUBLIC_ADMIN_DEFAULT_ROOM }} + VITE_PUBLIC_ADMIN_MODERATION_LOG_LIMIT: "50" run: cd frontend && npm run build - name: Deploy to Cloudflare Workers diff --git a/.github/instructions/TODO.md b/.github/instructions/TODO.md index ea0b9b0..1de24e7 100644 --- a/.github/instructions/TODO.md +++ b/.github/instructions/TODO.md @@ -2,6 +2,11 @@ > Completed tasks moved to [DONE](./DONE.md). Remaining tasks in [BACKLOG](./BACKLOG.md). +## Cloudflare Workers + +- [x] Adjust `frontend/src/main.ts` to use `VITE_PUBLIC_APP_URL` for API requests instead of hardcoded `/api/...` paths. +- [x] Adjust `frontend/src/main.ts` to use `VITE_PUBLIC_WS_URL` for WebSocket connections instead of hardcoded `wss://...` paths. + ## Frontend Tests ### User Frontend diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f6b6b5..01349ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ - **HLS segment duration 2s**: Default `HLS_SEGMENT_DURATION` changed from 6 to 2 and `HLS_WINDOW_SIZE` from 24 to 12 (2s × 12 = 24s live window), reducing end-to-end latency; the 2s GOP was already in place. - **Chat font sizing**: `.message-text` set to `0.95rem` (slightly smaller than the default, larger than the `0.83rem` system/flash text). - **R2 retention by run count + size**: Playout now keeps the newest `R2_KEEP_RUNS` run folders (default 2) and enforces an `R2_MAX_RETENTION_BYTES` cap (default 10 GiB), replacing the old 24h time-based `R2_SEGMENT_RETENTION_HOURS` cleanup. Cleanup runs after each new run plus an hourly backstop, and never deletes the live manifest. Adds `linearvoid_playout_r2_runs_retained` and `linearvoid_playout_r2_bytes_retained` gauges. +- **Cloudflare Workers frontend hosting**: Replaced Cloudflare Pages with a Cloudflare Worker (`linearvoid-frontend`) that serves the static SPA via Workers Static Assets. Added `frontend/wrangler.toml` and renamed the deploy workflow to `.gitea/workflows/workers-deploy.yml` (builds the SPA and runs `npx wrangler deploy`). Architecture, setup/deployment, and ops documentation updated from Pages to Workers. + +### Fixed + +- **Login/register cross-origin API URLs**: `submitAuth` in `frontend/src/main.ts` now prefixes `/api/auth/login` and `/api/auth/register` with `VITE_PUBLIC_APP_URL` (falling back to same-origin), matching the other API calls so the Workers-served SPA reaches the app origin instead of a same-origin path. ### Tests diff --git a/README.md b/README.md index c94c49f..58eaec2 100644 --- a/README.md +++ b/README.md @@ -262,8 +262,8 @@ See the [architecture docs](docs/architecture/README.md) for detailed architectu | `VITE_PUBLIC_HLS_URL` | `https://media.linearvoid.tv/hls/playlist.m3u8` | HLS playlist URL | | `ADMIN_USERNAME` | `admin` | Admin panel username | | `ADMIN_PASSWORD` | — | Admin panel password | -| `HLS_SEGMENT_DURATION` | `6` | HLS segment duration in seconds | -| `HLS_WINDOW_SIZE` | `24` | HLS playlist window size | +| `HLS_SEGMENT_DURATION` | `2` | HLS segment duration in seconds | +| `HLS_WINDOW_SIZE` | `12` | HLS playlist window size | Full reference: [`.env.example`](.env.example). diff --git a/backend/playout/start-playout.sh b/backend/playout/start-playout.sh index 2092e46..62b1aa9 100644 --- a/backend/playout/start-playout.sh +++ b/backend/playout/start-playout.sh @@ -3,8 +3,8 @@ set -e echo "=== Linear Void Playout Service Starting ===" echo "Playlist path: ${PLAYLIST_PATH:=/app/playlist/playlist.txt}" -echo "HLS segment duration: ${HLS_SEGMENT_DURATION:-6}s" -echo "HLS window size: ${HLS_WINDOW_SIZE:-24}" +echo "HLS segment duration: ${HLS_SEGMENT_DURATION:-2}s" +echo "HLS window size: ${HLS_WINDOW_SIZE:-12}" # Ensure playlist directory and file exist mkdir -p "$(dirname "$PLAYLIST_PATH")" diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 9e0354b..c450387 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -534,7 +534,7 @@ ffmpeg -i input.mov \ A thread-safe, JSON-persisted runtime config store lives in `backend/chat/src/config/runtime.go` and is shared with the playout service via the playlist volume (`/app/playlist/config.json`). - Editable via `GET/PUT /api/admin/config` from the admin UI. -- Fields: `hlsSegmentDuration` (2–15s, default 6), `hlsWindowSize` (3–100, default 24), `matomoUrl`, `matomoSiteId`. +- Fields: `hlsSegmentDuration` (2–15s, default 2), `hlsWindowSize` (3–100, default 12), `matomoUrl`, `matomoSiteId`. - Playout reads the same file (`loadSharedHLSConfig`) as an env fallback for HLS segment duration/window. - Typed setters validate values; invalid input is rejected with `400`. diff --git a/docs/operations/cloudflare-workers-setup.md b/docs/operations/cloudflare-workers-setup.md index faef19d..1de4a8a 100644 --- a/docs/operations/cloudflare-workers-setup.md +++ b/docs/operations/cloudflare-workers-setup.md @@ -39,24 +39,20 @@ Serve the Vite-built SPA (`frontend/dist`) as Worker static assets: See [gitea-cloudflare-workers.md](./gitea-cloudflare-workers.md) for the automated deployment workflow. -### Variables and secrets +### Build-time variables -On the Worker, set the following environment variables (needed to run the frontend): +The `VITE_PUBLIC_*` values are baked into the bundle at build time by Vite (`vite.config.ts` uses `envDir: ".."` to read them from the repo root). They are supplied by the Gitea Actions build environment from Gitea secrets — not as Worker runtime variables. The static-assets Worker has no runtime JavaScript, so it reads no `env` at request time. -| Type | Name | Value | -| --------- | -------------------------------------- | ----------------------------------------------- | -| Secret | ADMIN_PASSWORD | `not-a-real-admin-password` | -| Plaintext | ADMIN_SESSION_TTL_HOURS | `12` | -| Plaintext | ADMIN_USERNAME | `boogers` | -| Plaintext | HLS_SEGMENT_DURATION | `2` | -| Plaintext | HLS_WINDOW_SIZE | `12` | -| Plaintext | PLAYLIST_PATH | `/app/playlist/playlist.txt` | -| Plaintext | VITE_PUBLIC_ADMIN_DEFAULT_MODERATOR | `boogers` | -| Plaintext | VITE_PUBLIC_ADMIN_DEFAULT_ROOM | `main` | -| Plaintext | VITE_PUBLIC_ADMIN_MODERATION_LOG_LIMIT | `50` | -| Plaintext | VITE_PUBLIC_APP_URL | `https://linearvoid.tv` | -| Plaintext | VITE_PUBLIC_HLS_URL | `https://media.linearvoid.tv/hls/playlist.m3u8` | -| Plaintext | VITE_PUBLIC_WS_URL | `wss://linearvoid.tv/ws` | +| Name | Value | +| ---------------------------------------- | ----------------------------------------------- | +| `VITE_PUBLIC_APP_URL` | `https://linearvoid.tv` | +| `VITE_PUBLIC_WS_URL` | `wss://linearvoid.tv/ws` | +| `VITE_PUBLIC_HLS_URL` | `https://media.linearvoid.tv/hls/playlist.m3u8` | +| `VITE_PUBLIC_ADMIN_DEFAULT_MODERATOR` | `boogers` | +| `VITE_PUBLIC_ADMIN_DEFAULT_ROOM` | `main` | +| `VITE_PUBLIC_ADMIN_MODERATION_LOG_LIMIT` | `50` | + +Backend services (playout, chat, nginx) read their own runtime variables (`ADMIN_*`, `HLS_*`, `PLAYLIST_PATH`, `R2_*`, `DATABASE_URL`, `REDIS_URL`) from the container environment — see [`.env.example`](../../.env.example). ## Custom domains diff --git a/docs/operations/gitea-cloudflare-workers.md b/docs/operations/gitea-cloudflare-workers.md index bb6fb12..1480f30 100644 --- a/docs/operations/gitea-cloudflare-workers.md +++ b/docs/operations/gitea-cloudflare-workers.md @@ -58,6 +58,13 @@ jobs: run: cd frontend && npm ci - name: Build + env: + VITE_PUBLIC_APP_URL: ${{ secrets.VITE_PUBLIC_APP_URL }} + VITE_PUBLIC_WS_URL: ${{ secrets.VITE_PUBLIC_WS_URL }} + VITE_PUBLIC_HLS_URL: ${{ secrets.VITE_PUBLIC_HLS_URL }} + VITE_PUBLIC_ADMIN_DEFAULT_MODERATOR: ${{ secrets.VITE_PUBLIC_ADMIN_DEFAULT_MODERATOR }} + VITE_PUBLIC_ADMIN_DEFAULT_ROOM: ${{ secrets.VITE_PUBLIC_ADMIN_DEFAULT_ROOM }} + VITE_PUBLIC_ADMIN_MODERATION_LOG_LIMIT: "50" run: cd frontend && npm run build - name: Deploy to Cloudflare Workers @@ -71,10 +78,15 @@ jobs: ## Secrets to add in Gitea -| Secret | Value | -| ----------------------- | ------------------------------------ | -| `CLOUDFLARE_API_TOKEN` | API token with Workers permissions | -| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare account ID from dashboard | +| Secret | Value | +| ------------------------------------- | ------------------------------------ | +| `CLOUDFLARE_API_TOKEN` | API token with Workers permissions | +| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare account ID from dashboard | +| `VITE_PUBLIC_APP_URL` | Public viewer URL | +| `VITE_PUBLIC_WS_URL` | WebSocket endpoint | +| `VITE_PUBLIC_HLS_URL` | HLS playlist URL | +| `VITE_PUBLIC_ADMIN_DEFAULT_MODERATOR` | Default moderator username | +| `VITE_PUBLIC_ADMIN_DEFAULT_ROOM` | Default chat room | ## Verify deployment diff --git a/frontend/src/main.ts b/frontend/src/main.ts index dae0915..53636e0 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -428,7 +428,8 @@ async function submitAuth(path: string) { return; } try { - const res = await fetch(path, { + const apiUrl = import.meta.env.VITE_PUBLIC_APP_URL?.trim() || window.location.origin; + const res = await fetch(`${apiUrl}${path}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: u, password: p }),