···3 */
45import { SpotifyApi, type AccessToken } from "@spotify/web-api-ts-sdk";
06import { SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET } from "astro:env/server";
78import fs from "node:fs/promises";
9-import { isObj } from "/utils";
1011/**
12- * the refresh_token field is not checked as
13 */
14const isSpotifyAccessToken = (token: any): token is AccessToken =>
15 isObj(token) &&
···20 "expires_in" in token &&
21 typeof token.expires_in === "number";
220000000000000000000000000000000000000023// try load last known refresh token from file
24const refreshToken = await fs
25 .readFile("./.refreshToken", { encoding: "utf-8" })
···30// if refreshToken is undefined then we dont have a valid one saved, and can request the user obtain one
31// (this could be corruption, failed save, or missing file)
32if (!refreshToken)
33- throw new Error(
34- "No access token is stored in `./.refreshToken`. Please generate one using the `/callback` endpoint in a dev server.",
35- );
3637-const accessToken = await fetch("https://accounts.spotify.com/api/token", {
38- method: "post",
39-40- headers: {
41- "content-type": "application/x-www-form-urlencoded",
42- Authorization:
43- "Basic " +
44- Buffer.from(SPOTIFY_CLIENT_ID + ":" + SPOTIFY_CLIENT_SECRET).toString(
45- "base64",
46- ),
47- },
48-49- body: new URLSearchParams({
50- grant_type: "refresh_token",
51- refresh_token: refreshToken,
52- }).toString(),
53-})
54- .then((res) => res.json())
55- .then((token) =>
56- isSpotifyAccessToken(token)
57- ? {
58- ...token,
59- // if no refresh_token is provided then insert it
60- ...(token.refresh_token ? {} : { refresh_token: refreshToken }),
61- }
62- : console.error("Response was not a valid access token:", token),
63- )
64- .catch((err) => console.error(err));
6566if (!accessToken)
67- throw new Error(
68- "Could not generate a new access token from the refresh token",
69- );
7071-export const sdk = SpotifyApi.withAccessToken(SPOTIFY_CLIENT_ID, accessToken, {
72- async afterRequest() {
73- const token = await sdk.getAccessToken();
74- if (!token) return;
75- fs.writeFile("./.refreshToken", token.refresh_token, {
76- encoding: "utf-8",
77- });
0000078 },
79-});
···3 */
45import { SpotifyApi, type AccessToken } from "@spotify/web-api-ts-sdk";
6+import { ProvidedAccessTokenStrategy } from "@spotify/web-api-ts-sdk";
7import { SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET } from "astro:env/server";
89import fs from "node:fs/promises";
10+import { isObj, throws } from "/utils";
1112/**
13+ * the refresh_token field is not checked as it might not be returned from the api
14 */
15const isSpotifyAccessToken = (token: any): token is AccessToken =>
16 isObj(token) &&
···21 "expires_in" in token &&
22 typeof token.expires_in === "number";
2324+const reloadAccessToken = async (refresh_token: string) =>
25+ fetch("https://accounts.spotify.com/api/token", {
26+ method: "post",
27+ headers: {
28+ "content-type": "application/x-www-form-urlencoded",
29+ Authorization:
30+ "Basic " +
31+ Buffer.from(SPOTIFY_CLIENT_ID + ":" + SPOTIFY_CLIENT_SECRET).toString(
32+ "base64",
33+ ),
34+ },
35+ body: new URLSearchParams({
36+ grant_type: "refresh_token",
37+ refresh_token: refresh_token,
38+ }).toString(),
39+ })
40+ .then((res) => res.json())
41+ .then((token) =>
42+ isSpotifyAccessToken(token)
43+ ? {
44+ ...token,
45+ // if no refresh_token is provided then insert it
46+ ...(token.refresh_token ? {} : { refresh_token: refresh_token }),
47+ }
48+ : console.error("Response was not a valid access token:", token),
49+ )
50+ .catch((err) => console.error(err))
51+ .then((token) =>
52+ !!token
53+ ? token
54+ : throws(
55+ new Error(
56+ "Could not generate a new access token from the refresh token",
57+ ),
58+ ),
59+ );
60+61+/** MAIN LOGIC HERE */
62// try load last known refresh token from file
63const refreshToken = await fs
64 .readFile("./.refreshToken", { encoding: "utf-8" })
···69// if refreshToken is undefined then we dont have a valid one saved, and can request the user obtain one
70// (this could be corruption, failed save, or missing file)
71if (!refreshToken)
72+ throw "No access token is stored in `./.refreshToken`. Please generate one using the `/callback` endpoint in a dev server.";
007374+const accessToken = await reloadAccessToken(refreshToken);
0000000000000000000000000007576if (!accessToken)
77+ throw "Could not generate a new access token from the refresh token";
007879+export const sdk = new SpotifyApi(
80+ new ProvidedAccessTokenStrategy(SPOTIFY_CLIENT_ID, accessToken, (_, token) =>
81+ reloadAccessToken(token.refresh_token),
82+ ),
83+ {
84+ async afterRequest() {
85+ const token = await sdk.getAccessToken();
86+ if (!token) return;
87+ fs.writeFile("./.refreshToken", token.refresh_token, {
88+ encoding: "utf-8",
89+ });
90+ },
91 },
92+);