61 lines
1.5 KiB
TypeScript
61 lines
1.5 KiB
TypeScript
import "server-only";
|
|
import { admin, required } from "./supabase";
|
|
import type {
|
|
LeaderboardData,
|
|
LeaderboardDifficulty,
|
|
} from "@/shared/leaderboard";
|
|
|
|
export async function leaderboard({
|
|
difficulty = "all",
|
|
search = "",
|
|
page = 1,
|
|
limit = 25,
|
|
}: {
|
|
difficulty?: LeaderboardDifficulty;
|
|
search?: string;
|
|
page?: number;
|
|
limit?: number;
|
|
} = {}): Promise<LeaderboardData | null> {
|
|
try {
|
|
const data = required(
|
|
await admin().rpc("player_leaderboard", {
|
|
p_difficulty: difficulty,
|
|
p_search: search,
|
|
p_page: page,
|
|
p_limit: limit,
|
|
}),
|
|
) as unknown as LeaderboardData;
|
|
const ids = [
|
|
...new Set(
|
|
[...data.entries, ...data.leaders].map((entry) => entry.player_id),
|
|
),
|
|
];
|
|
const profiles = ids.length
|
|
? required(
|
|
await admin()
|
|
.from("profiles")
|
|
.select(
|
|
"id,name_glow,glow_color,role,bug_finder,custom_prefix,custom_prefix_icon",
|
|
)
|
|
.in("id", ids),
|
|
)
|
|
: [];
|
|
const addGlow = (entry: LeaderboardData["entries"][number]) => ({
|
|
...entry,
|
|
...profiles.find((profile) => profile.id === entry.player_id),
|
|
});
|
|
return {
|
|
...data,
|
|
entries: data.entries.map(addGlow),
|
|
leaders: data.leaders.map(addGlow),
|
|
};
|
|
} catch (error) {
|
|
// A leaderboard outage must not take the map catalog or homepage offline.
|
|
console.error(
|
|
"Leaderboard query failed",
|
|
error instanceof Error ? error.message : "Unknown error",
|
|
);
|
|
return null;
|
|
}
|
|
}
|