feat(backend,frontend): migrate data APIs from REST to native tRPC over WebSocket
Replace REST module routers with a single typed tRPC appRouter served over
/trpc (HTTP + WebSocket), and rewire the frontend to call it via
@trpc/client wsLink (browser) and httpLink (RSC data layer). Existing
/api/health + /api/metrics stay as plain Express for infra scraping.
Notable fixes surfaced by the live smoke test:
- Express 5 / path-to-regexp v8 rejects the /trpc/* wildcard route; use a
prefix middleware that computes opts.path from the URL instead.
- nodeHTTPRequestHandler treats opts.path as the literal procedure path, so
it is derived per-request from req.url.
- Two ws servers on one http.Server (the /ws voice socket + /trpc) collided
and returned 400 on upgrade; both now use noServer + a manually routed
server.on('upgrade') keyed by path.
Verified: BE tsc+biome+40 vitest green; FE tsc+biome green; live
HTTP and WebSocket calls returned real prod data.
Co-Authored-By: Claude Opus 4.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
d8552a9fb8
commit
2fa1827f17
@@ -1,11 +1,12 @@
|
||||
import { trpc } from "@/lib/trpc/client";
|
||||
import type { MediaState } from "@/lib/types";
|
||||
import { api } from "./client";
|
||||
|
||||
export const mediaApi = {
|
||||
getStatus: () => api.get<MediaState>("/api/media/status"),
|
||||
getStatus: () => trpc.media.status.query() as unknown as Promise<MediaState>,
|
||||
queue: (source: string, mode: string) =>
|
||||
api.post<MediaState>("/api/media/queue", { source, mode }),
|
||||
skip: () => api.post<MediaState>("/api/media/skip", {}),
|
||||
stop: () => api.post<MediaState>("/api/media/stop", {}),
|
||||
loop: (loop: boolean) => api.post<MediaState>("/api/media/loop", { loop }),
|
||||
trpc.media.queue.mutate({ source, mode }) as unknown as Promise<MediaState>,
|
||||
skip: () => trpc.media.skip.mutate() as unknown as Promise<MediaState>,
|
||||
stop: () => trpc.media.stop.mutate() as unknown as Promise<MediaState>,
|
||||
loop: (loop: boolean) =>
|
||||
trpc.media.loop.mutate({ loop }) as unknown as Promise<MediaState>,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user