music: document the full /api/music/* contract at the source of truth
The proxy is an opaque catch-all, so the endpoint surface wasn't perceivable from the platform side. Add a contract header (all routes + params + SSE/response shapes) atop the sidecar fetch handler where the routes are defined, and point the proxy router at it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,12 @@ import { getMusicServerUrl } from './sidecar-server';
|
||||
|
||||
// Thin reverse-proxy for /api/music/*. Auth is handled upstream by userMiddleware (this router mounts
|
||||
// under the protected /api tree, so the media `?token=` path works). Everything else — path resolution,
|
||||
// byte-range streaming, ffprobe duration — is done by the officer-music sidecar's audio server. We only
|
||||
// forward the subpath + query + Range and stream the response back.
|
||||
// byte-range streaming, ffprobe duration, indexing — is done by the officer-music sidecar's audio
|
||||
// server. We only forward the subpath + query + Range and stream the response back.
|
||||
//
|
||||
// This is a catch-all, so it lists no routes: the full /api/music/* HTTP contract (stream, manifest,
|
||||
// meta, cover, reindex, reindex/stream + their SSE/response shapes) is documented at the top of the
|
||||
// sidecar's fetch handler — src/servers/sidecar/music/index.ts.
|
||||
|
||||
export const musicRouter = createRouter();
|
||||
|
||||
|
||||
@@ -21,6 +21,28 @@ const DATA_PATH = process.env.DATA_PATH ?? join(process.cwd(), 'data');
|
||||
// resolution + streaming + ffprobe duration happens here); the platform API is just a thin proxy that
|
||||
// authenticates and forwards to us. The server listens on a random loopback port, reported to the API
|
||||
// on connect so it can route `/api/music/*` here.
|
||||
//
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
// HTTP CONTRACT — the full `/api/music/*` surface (this fetch handler is the source of truth; the
|
||||
// platform side is an opaque catch-all proxy). All routes are reached as `/api/music/<name>`, authed
|
||||
// upstream by userMiddleware (Bearer header or `?token=` for media). Data shapes are the exported
|
||||
// `IndexStatus` / `IndexReport` / `IndexMeta` types in indexer.ts.
|
||||
//
|
||||
// GET /stream?path=<home-relative> audio with Range→206 (Content-Range/Length/Accept-Ranges)
|
||||
// + `X-Audio-Duration` (seconds, ffprobe). 400/404/416.
|
||||
// GET /manifest { version, generatedAt, albums: { "<rel>": { v, cover, tracks } } }
|
||||
// GET /meta?path=<rel> album meta.json (IndexMeta). ETag: <v>; If-None-Match → 304.
|
||||
// GET /cover?path=<rel> compressed cover.jpg. ETag: <v>; If-None-Match → 304.
|
||||
// POST /reindex start an async build; returns IndexStatus (running: true).
|
||||
// GET /reindex/status IndexStatus snapshot.
|
||||
// GET /reindex/stream SSE. Triggers a build if idle (`?trigger=0` = watch-only).
|
||||
// `event: progress` (IndexStatus) throttled ~200ms, then one
|
||||
// `event: done` (IndexReport) and the stream closes.
|
||||
// GET /health "ok".
|
||||
//
|
||||
// `<rel>` = album folder path relative to the Music root (e.g. "Albums/AC-DC/[1980] Back in Black").
|
||||
// `v` = per-album version stamp; unchanged `v` ⇒ nothing changed ⇒ the phone can skip re-downloading.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user