Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions src/utils/twitch-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ export const generateTwitchRequestHeaders = (accessToken: string) => {
};

export const getTwitchUserId = async (userName: string, token: string) => {
const res = await fetch(
`https://api.twitch.tv/helix/users?login=${userName}`,
const response = await fetch(
`https://api.twitch.tv/helix/users?${new URLSearchParams({
login: userName,
})}`,
{
method: "GET",
headers: generateTwitchRequestHeaders(token),
next: { revalidate: Infinity }, // These should never change
// Twitch logins can change or be reassigned to another account.
next: { revalidate: 60 },
}
).then((response) => response.json());
if (res.error === "Unauthorized") throw new Error("Unauthorized");

const responseId = (res as any)?.data[0]?.id as string;
if (!responseId) return null;
);
if (!response.ok) {
throw new Error(`Could not look up Twitch user: ${response.status}`);
}

return responseId;
const result = (await response.json()) as { data?: { id: string }[] };
return result.data?.[0]?.id ?? null;
};

export type VOD = {
Expand Down
44 changes: 44 additions & 0 deletions src/utils/twitch-user.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { getTwitchUserId } from "./twitch-server";

vi.mock("@clerk/nextjs/server", () => ({ clerkClient: vi.fn() }));

afterEach(() => vi.unstubAllGlobals());

describe("getTwitchUserId", () => {
it("encodes the login and returns the matching ID", async () => {
const fetchMock = vi
.fn()
.mockResolvedValue(
new Response(JSON.stringify({ data: [{ id: "123" }] }), { status: 200 })
);
vi.stubGlobal("fetch", fetchMock);

await expect(getTwitchUserId("name&other", "app-token")).resolves.toBe(
"123"
);
expect(fetchMock.mock.calls[0]![0]).toBe(
"https://api.twitch.tv/helix/users?login=name%26other"
);
Comment thread
t3dotgg marked this conversation as resolved.
});

it("returns null when Twitch has no account for the login", async () => {
vi.stubGlobal(
"fetch",
vi.fn().mockResolvedValue(new Response(JSON.stringify({ data: [] })))
);

await expect(getTwitchUserId("missing", "app-token")).resolves.toBeNull();
});

it("throws a clear error when the Twitch request fails", async () => {
vi.stubGlobal(
"fetch",
vi.fn().mockResolvedValue(new Response(null, { status: 401 }))
);

await expect(getTwitchUserId("creator", "bad-token")).rejects.toThrow(
"Could not look up Twitch user: 401"
);
});
});
Loading