@@ -0,0 +1,52 @@
|
||||
import type { RudderContext } from '../core/context.js';
|
||||
import { api } from '../generated/api.js';
|
||||
import type { RankEntry } from '../generated/leaderboards.js';
|
||||
|
||||
/**
|
||||
* A cached handle for a specific leaderboard.
|
||||
*
|
||||
* Created by `LeaderboardsService.findBySlug()` — subsequent calls with
|
||||
* the same slug return the same handle, avoiding redundant fetches.
|
||||
*/
|
||||
export class LeaderboardHandle {
|
||||
private entries: RankEntry[] = [];
|
||||
|
||||
constructor(
|
||||
public readonly slug: string,
|
||||
private readonly ctx: RudderContext,
|
||||
) {}
|
||||
|
||||
getEntries(): readonly RankEntry[] {
|
||||
return this.entries;
|
||||
}
|
||||
|
||||
async submit(score: number): Promise<void> {
|
||||
return api.submitScore(this.ctx, { slug: this.slug }, { slug: this.slug, score });
|
||||
}
|
||||
|
||||
async list(limit = 100): Promise<readonly RankEntry[]> {
|
||||
const response = await api.getRanking(
|
||||
this.ctx,
|
||||
{ slug: this.slug },
|
||||
{ limit: limit > 0 ? limit : undefined },
|
||||
);
|
||||
this.entries = response.entries ?? [];
|
||||
return this.entries;
|
||||
}
|
||||
}
|
||||
|
||||
export class LeaderboardsService {
|
||||
private readonly cache = new Map<string, LeaderboardHandle>();
|
||||
|
||||
constructor(private readonly ctx: RudderContext) {}
|
||||
|
||||
/** Returns a cached handle for the given leaderboard slug. */
|
||||
findBySlug(slug: string): LeaderboardHandle {
|
||||
let handle = this.cache.get(slug);
|
||||
if (!handle) {
|
||||
handle = new LeaderboardHandle(slug, this.ctx);
|
||||
this.cache.set(slug, handle);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user