fix(web): drift audit batch 5 — SSR redirect + radio exclude cap
test-web / test (push) Successful in 33s
test-web / test (push) Successful in 33s
Two web-side findings from the 2026-06-02 drift audit (#552): - **#559** /library and /playlists each had a +page.server.ts file calling redirect(308, ...). The app is configured as adapter-static + ssr=false (+layout.ts:5), so +page.server.ts files only run at build time / dev server — NEVER at runtime in the deployed build. Direct navigation to /library or /playlists (mobile bookmarks, hand-typed URLs) hit a blank page or 404. We worked around this earlier today by linking the nav directly to /library/artists, but bookmarks stayed broken. Converted both files to +page.ts (universal load) — same redirect logic, runs client-side in the SPA, which is what actually executes. - **#554** Radio auto-refresh built its exclude= query parameter from the ENTIRE queue, growing unbounded each refresh as new tracks were appended. UUIDs are ~36 chars + comma; with the common 8KB query-string limit, ~220 tracks is the ceiling. A multi-hour radio session eventually 414'd; the .catch() ate the error and the player silently stopped topping up — dead radio with no user-visible signal. Cap exclude to the most recent 100 ids; the server's RecentlyPlayedHours filter already handles broader history dedup so the request-side cap only needs to cover the visible queue's recent tail.
This commit is contained in:
@@ -462,7 +462,18 @@ $effect.root(() => {
|
|||||||
|
|
||||||
_radioRefreshInFlight = true;
|
_radioRefreshInFlight = true;
|
||||||
const seed = _radioSeedId;
|
const seed = _radioSeedId;
|
||||||
const exclude = _queue.map((t) => t.id).join(',');
|
// Drift #554: cap the exclude list so a multi-hour radio session
|
||||||
|
// doesn't grow the query string past common 8KB limits and start
|
||||||
|
// 414-ing /api/radio. The .catch() below would silently swallow
|
||||||
|
// that failure and the player would stop topping up — a dead
|
||||||
|
// radio. The server's RecentlyPlayedHours filter already handles
|
||||||
|
// broader history dedup, so the request-side exclude only needs
|
||||||
|
// to cover the visible queue's recent tail.
|
||||||
|
const RADIO_EXCLUDE_CAP = 100;
|
||||||
|
const exclude = _queue
|
||||||
|
.slice(-RADIO_EXCLUDE_CAP)
|
||||||
|
.map((t) => t.id)
|
||||||
|
.join(',');
|
||||||
api
|
api
|
||||||
.get<RadioResponse>(
|
.get<RadioResponse>(
|
||||||
`/api/radio?seed_track=${encodeURIComponent(seed)}&exclude=${exclude}`
|
`/api/radio?seed_track=${encodeURIComponent(seed)}&exclude=${exclude}`
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ import { redirect } from '@sveltejs/kit';
|
|||||||
// always renders the active sub-page. Bare hits go to the default tab
|
// always renders the active sub-page. Bare hits go to the default tab
|
||||||
// (Artists, matching Android's LibraryScreen default). 308 = permanent
|
// (Artists, matching Android's LibraryScreen default). 308 = permanent
|
||||||
// + preserve method, so SPA navigations and direct loads behave the same.
|
// + preserve method, so SPA navigations and direct loads behave the same.
|
||||||
|
//
|
||||||
|
// Drift #559: this was a +page.server.ts which DOES NOT run in
|
||||||
|
// production — the app is configured as adapter-static + ssr=false
|
||||||
|
// (see +layout.ts). +page.ts (universal load) runs client-side, which
|
||||||
|
// is what the SPA actually executes when a route is hit.
|
||||||
export const load = () => {
|
export const load = () => {
|
||||||
throw redirect(308, '/library/artists');
|
throw redirect(308, '/library/artists');
|
||||||
};
|
};
|
||||||
@@ -5,6 +5,10 @@ import { redirect } from '@sveltejs/kit';
|
|||||||
// still lives here at /routes/playlists/[id]/+page.svelte — that URL
|
// still lives here at /routes/playlists/[id]/+page.svelte — that URL
|
||||||
// matches the server API shape and is unchanged.
|
// matches the server API shape and is unchanged.
|
||||||
// 308 = permanent + preserve method; old bookmarks land on the new URL.
|
// 308 = permanent + preserve method; old bookmarks land on the new URL.
|
||||||
|
//
|
||||||
|
// Drift #559: this was a +page.server.ts which DOES NOT run in
|
||||||
|
// production (adapter-static + ssr=false, see +layout.ts). +page.ts
|
||||||
|
// universal load runs client-side and IS what the SPA executes.
|
||||||
export const load = () => {
|
export const load = () => {
|
||||||
throw redirect(308, '/library/playlists');
|
throw redirect(308, '/library/playlists');
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user