itpdp/api/src/routes/spotify.ts
2026-05-24 18:18:54 +02:00

63 lines
1.5 KiB
TypeScript

import { and, eq } from "drizzle-orm";
import Elysia from "elysia";
import { auth, betterAuthElysia } from "../auth";
import { db } from "../db";
import { account } from "../db/schema";
const SPOTIFY_PLAYBACK_SCOPES = ["streaming", "user-read-private"];
function parseScopes(scope: string | null | undefined) {
return new Set(scope?.split(/[\s,]+/).filter(Boolean) ?? []);
}
export const spotifyRoutes = new Elysia()
.use(betterAuthElysia)
.group("/spotify", (app) =>
app.get(
"/token",
async ({ user, set }) => {
const [spotifyAccount] = await db
.select({ scope: account.scope })
.from(account)
.where(
and(eq(account.userId, user.id), eq(account.providerId, "spotify")),
)
.limit(1);
const grantedScopes = parseScopes(spotifyAccount?.scope);
const missingScopes = SPOTIFY_PLAYBACK_SCOPES.filter(
(scope) => !grantedScopes.has(scope),
);
if (missingScopes.length > 0) {
set.status = 403;
return {
error: "Spotify playback permission required",
code: "SPOTIFY_RELINK_REQUIRED",
missingScopes,
};
}
const token = await auth.api.getAccessToken({
body: {
userId: user.id,
providerId: "spotify",
},
});
if (!token?.accessToken) {
set.status = 404;
return { error: "Spotify access token not found" };
}
return {
accessToken: token.accessToken,
expiresAt: token.accessTokenExpiresAt
? Number(token.accessTokenExpiresAt)
: null,
};
},
{ auth: true },
),
);