feat(spotify): web OAuth endpoints + thread single shared SpotifyOAuth to web + controllers (Stage 3, Task 6)

Add the /api/spotify {login,callback,status} router behind the SpotifyOAuthLike
seam (DI-tested with supertest, no network). Build ONE process-wide SpotifyOAuth
in index.ts (clientId/redirectUri from config; store via the already-exported
createFileOAuthTokenStore) and thread that same instance into BOTH createWebServer
AND BotManager -> BotInstance -> SpotifyController, so a web login authorizes
playback (C3.1). Reuses the existing file token store (no token-store.ts).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
saopig1andClaude Opus 4.8 committed 2026-07-03 00:09:12 +08:00
1 parent 322335dfc5
commit 8998b9623f
8 files changed
+363 -2

No files matched your search

+19
View File
@@ -19,6 +19,8 @@ import { createUsersRouter } from "./api/users.js";
import { createAuditStore } from "../data/audit.js";
import { createAuditRouter } from "./api/audit.js";
import { createFavoritesRouter } from "./api/favorites.js";
import { createSpotifyRouter } from "./api/spotify.js";
import type { SpotifyOAuth } from "../music/spotify/spotify-oauth.js";
import { setupWebSocket } from "./websocket.js";
import { createUserStore } from "../data/users.js";
import { createSessionStore } from "../data/sessions.js";
@@ -48,6 +50,9 @@ export interface WebServerOptions {
cookieStore?: CookieStore;
avatarStore: AvatarStore;
staticDir?: string;
/** Process-wide shared Spotify OAuth (single account, Stage 3). When set, the
* /api/spotify {login,callback,status} router is mounted. */
spotifyOAuth?: SpotifyOAuth;
}
export interface WebServer {
@@ -136,6 +141,20 @@ export function createWebServer(options: WebServerOptions): WebServer {
"/api/auth",
createAuthRouter(options.neteaseProvider, options.qqProvider, options.bilibiliProvider, logger, options.cookieStore, options.kugouProvider, options.spotifyProvider)
);
if (options.spotifyOAuth) {
app.use(
"/api/spotify",
createSpotifyRouter({
oauth: options.spotifyOAuth,
logger,
getBackendInfo: () => ({
backend: options.config.spotify.backend,
deviceName: options.config.spotify.deviceName,
}),
webUiRedirect: "/",
}),
);
}
app.use("/api/favorites", requireNotGuest, createFavoritesRouter(options.database, logger));
// admin-only routes