lightleaderboard 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,237 @@
1
+ // src/error.ts
2
+ var LightLeaderboardError = class extends Error {
3
+ constructor(message, status, response) {
4
+ super(message);
5
+ this.name = "LightLeaderboardError";
6
+ this.status = status;
7
+ this.response = response;
8
+ Object.setPrototypeOf(this, new.target.prototype);
9
+ }
10
+ get isAuthError() {
11
+ return this.status === 401 || this.status === 403;
12
+ }
13
+ get isRateLimitError() {
14
+ return this.status === 429;
15
+ }
16
+ get isBillingError() {
17
+ return this.status === 402;
18
+ }
19
+ get isValidationError() {
20
+ return this.status === 400;
21
+ }
22
+ };
23
+
24
+ // src/client.ts
25
+ var DEFAULT_BASE_URL = "https://leaderboard.goproso.com";
26
+ async function hmacSha256(key, data) {
27
+ const enc = new TextEncoder();
28
+ const cryptoKey = await globalThis.crypto.subtle.importKey(
29
+ "raw",
30
+ enc.encode(key),
31
+ { name: "HMAC", hash: "SHA-256" },
32
+ false,
33
+ ["sign"]
34
+ );
35
+ const sig = await globalThis.crypto.subtle.sign("HMAC", cryptoKey, enc.encode(data));
36
+ return Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
37
+ }
38
+ function buildUrl(base, path, params) {
39
+ const url = `${base}${path}`;
40
+ if (!params) return url;
41
+ const sp = new URLSearchParams();
42
+ for (const [k, v] of Object.entries(params)) {
43
+ if (v !== void 0 && v !== null) sp.set(k, String(v));
44
+ }
45
+ const qs = sp.toString();
46
+ return qs ? `${url}?${qs}` : url;
47
+ }
48
+ var LightLeaderboard = class {
49
+ constructor(config) {
50
+ if (!config.apiKey) throw new Error("LightLeaderboard: apiKey is required");
51
+ if (!config.gameId) throw new Error("LightLeaderboard: gameId is required");
52
+ this.apiKey = config.apiKey;
53
+ this.gameId = config.gameId;
54
+ this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
55
+ this.scoreSecret = config.scoreSecret;
56
+ }
57
+ gameUrl(path, params) {
58
+ return buildUrl(this.baseUrl, `/api/v1/games/${encodeURIComponent(this.gameId)}${path}`, params);
59
+ }
60
+ async fetch(method, url, body, extraHeaders) {
61
+ const headers = {
62
+ Authorization: `Bearer ${this.apiKey}`,
63
+ "Content-Type": "application/json",
64
+ ...extraHeaders
65
+ };
66
+ const res = await globalThis.fetch(url, {
67
+ method,
68
+ headers,
69
+ body: body !== void 0 ? JSON.stringify(body) : void 0
70
+ });
71
+ let data;
72
+ try {
73
+ data = await res.json();
74
+ } catch {
75
+ throw new LightLeaderboardError(`HTTP ${res.status}: failed to parse response`, res.status, null);
76
+ }
77
+ if (!res.ok || data?.ok === false) {
78
+ throw new LightLeaderboardError(
79
+ data?.error ?? `HTTP ${res.status}`,
80
+ res.status,
81
+ data
82
+ );
83
+ }
84
+ return data;
85
+ }
86
+ // ─── Score submission ───────────────────────────────────────────────────────
87
+ /**
88
+ * Submit a score to the leaderboard.
89
+ *
90
+ * Returns the player's new rank immediately — no second API call needed.
91
+ *
92
+ * @example
93
+ * const result = await lb.submitScore({ score: 9500, playerRefId: 'p1', playerName: 'Alice' });
94
+ * console.log(`Rank #${result.rank} of ${result.totalPlayers}`);
95
+ */
96
+ async submitScore(options) {
97
+ const url = this.gameUrl("/scores");
98
+ const bodyStr = JSON.stringify(options);
99
+ const extraHeaders = {};
100
+ if (this.scoreSecret) {
101
+ const sig = await hmacSha256(this.scoreSecret, bodyStr);
102
+ extraHeaders["x-score-signature"] = `sha256=${sig}`;
103
+ }
104
+ const res = await globalThis.fetch(url, {
105
+ method: "POST",
106
+ headers: {
107
+ Authorization: `Bearer ${this.apiKey}`,
108
+ "Content-Type": "application/json",
109
+ ...extraHeaders
110
+ },
111
+ body: bodyStr
112
+ });
113
+ let data;
114
+ try {
115
+ data = await res.json();
116
+ } catch {
117
+ throw new LightLeaderboardError(`HTTP ${res.status}: failed to parse response`, res.status, null);
118
+ }
119
+ if (!res.ok || data?.ok === false) {
120
+ throw new LightLeaderboardError(data?.error ?? `HTTP ${res.status}`, res.status, data);
121
+ }
122
+ return {
123
+ id: data.id,
124
+ rank: data.rank ?? null,
125
+ isPersonalBest: data.isPersonalBest ?? false,
126
+ totalPlayers: data.totalPlayers ?? null,
127
+ deduped: data.deduped
128
+ };
129
+ }
130
+ // ─── Leaderboard ───────────────────────────────────────────────────────────
131
+ /**
132
+ * Fetch the leaderboard. Returns one entry per player (their best score) by default.
133
+ *
134
+ * @example
135
+ * const { entries } = await lb.getLeaderboard({ limit: 10, period: 'weekly' });
136
+ * entries.forEach(e => console.log(`#${e.rank} ${e.playerName}: ${e.score}`));
137
+ */
138
+ async getLeaderboard(options) {
139
+ const { allEntries, ...rest } = options ?? {};
140
+ const data = await this.fetch(
141
+ "GET",
142
+ this.gameUrl("/leaderboard", {
143
+ ...rest,
144
+ allEntries: allEntries ? "true" : void 0
145
+ })
146
+ );
147
+ return {
148
+ entries: data.entries,
149
+ scoreOrder: data.scoreOrder,
150
+ period: data.period,
151
+ season: data.season ?? null,
152
+ team: data.team ?? null,
153
+ limit: data.limit,
154
+ offset: data.offset
155
+ };
156
+ }
157
+ // ─── Rank ───────────────────────────────────────────────────────────────────
158
+ /**
159
+ * Get a player's current rank, score, and percentile.
160
+ *
161
+ * @example
162
+ * const { rank, percentile } = await lb.getPlayerRank('player-123');
163
+ * console.log(`Rank #${rank} — top ${(100 - percentile).toFixed(1)}%`);
164
+ */
165
+ async getPlayerRank(playerRefId, options) {
166
+ return this.fetch(
167
+ "GET",
168
+ this.gameUrl(`/players/${encodeURIComponent(playerRefId)}/rank`, options)
169
+ );
170
+ }
171
+ // ─── Centric leaderboard ───────────────────────────────────────────────────
172
+ /**
173
+ * Fetch the leaderboard centered on a specific player, showing the players
174
+ * immediately above and below them.
175
+ *
176
+ * @example
177
+ * const { entries, playerRank } = await lb.getCentricLeaderboard('player-123', { limit: 11 });
178
+ */
179
+ async getCentricLeaderboard(playerRefId, options) {
180
+ const data = await this.fetch(
181
+ "GET",
182
+ this.gameUrl(`/players/${encodeURIComponent(playerRefId)}/centric`, options)
183
+ );
184
+ return {
185
+ entries: data.entries,
186
+ playerRank: data.playerRank ?? null,
187
+ period: data.period,
188
+ season: data.season ?? null,
189
+ team: data.team ?? null,
190
+ scoreOrder: data.scoreOrder
191
+ };
192
+ }
193
+ // ─── Player profile ─────────────────────────────────────────────────────────
194
+ /**
195
+ * Fetch a player's profile (name, avatar, country, level, etc.).
196
+ */
197
+ async getPlayer(playerRefId) {
198
+ const data = await this.fetch(
199
+ "GET",
200
+ this.gameUrl(`/players/${encodeURIComponent(playerRefId)}`)
201
+ );
202
+ return data.player;
203
+ }
204
+ /**
205
+ * Create or update a player's profile. Fields are merged — omitted fields
206
+ * keep their existing values.
207
+ *
208
+ * @example
209
+ * await lb.updatePlayer('player-123', { playerName: 'Alice', country: 'US', level: 5 });
210
+ */
211
+ async updatePlayer(playerRefId, options) {
212
+ await this.fetch(
213
+ "PUT",
214
+ this.gameUrl(`/players/${encodeURIComponent(playerRefId)}`),
215
+ options
216
+ );
217
+ }
218
+ // ─── Score history ──────────────────────────────────────────────────────────
219
+ /**
220
+ * Fetch all submissions a player has ever made, ordered newest first.
221
+ * Useful for progression charts and run history screens.
222
+ *
223
+ * @example
224
+ * const { entries, bestScore, total } = await lb.getPlayerScores('player-123');
225
+ */
226
+ async getPlayerScores(playerRefId, options) {
227
+ return this.fetch(
228
+ "GET",
229
+ this.gameUrl(`/players/${encodeURIComponent(playerRefId)}/scores`, options)
230
+ );
231
+ }
232
+ };
233
+ export {
234
+ LightLeaderboard,
235
+ LightLeaderboardError
236
+ };
237
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/error.ts","../src/client.ts"],"sourcesContent":["export class LightLeaderboardError extends Error {\n /** HTTP status code returned by the API */\n readonly status: number;\n /** Raw response body from the API */\n readonly response: unknown;\n\n constructor(message: string, status: number, response: unknown) {\n super(message);\n this.name = 'LightLeaderboardError';\n this.status = status;\n this.response = response;\n // Restore prototype chain in environments that need it\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n get isAuthError() {\n return this.status === 401 || this.status === 403;\n }\n\n get isRateLimitError() {\n return this.status === 429;\n }\n\n get isBillingError() {\n return this.status === 402;\n }\n\n get isValidationError() {\n return this.status === 400;\n }\n}\n","import { LightLeaderboardError } from './error.js';\nimport type {\n LightLeaderboardConfig,\n SubmitScoreOptions,\n SubmitScoreResult,\n GetLeaderboardOptions,\n GetLeaderboardResult,\n GetRankOptions,\n PlayerRankResult,\n GetCentricOptions,\n CentricLeaderboardResult,\n PlayerProfile,\n UpdatePlayerOptions,\n GetPlayerScoresOptions,\n GetPlayerScoresResult,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://leaderboard.goproso.com';\n\nasync function hmacSha256(key: string, data: string): Promise<string> {\n const enc = new TextEncoder();\n const cryptoKey = await globalThis.crypto.subtle.importKey(\n 'raw',\n enc.encode(key),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n );\n const sig = await globalThis.crypto.subtle.sign('HMAC', cryptoKey, enc.encode(data));\n return Array.from(new Uint8Array(sig))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nfunction buildUrl(base: string, path: string, params?: object): string {\n const url = `${base}${path}`;\n if (!params) return url;\n const sp = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) sp.set(k, String(v));\n }\n const qs = sp.toString();\n return qs ? `${url}?${qs}` : url;\n}\n\nexport class LightLeaderboard {\n private readonly apiKey: string;\n private readonly gameId: string;\n private readonly baseUrl: string;\n private readonly scoreSecret?: string;\n\n constructor(config: LightLeaderboardConfig) {\n if (!config.apiKey) throw new Error('LightLeaderboard: apiKey is required');\n if (!config.gameId) throw new Error('LightLeaderboard: gameId is required');\n this.apiKey = config.apiKey;\n this.gameId = config.gameId;\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.scoreSecret = config.scoreSecret;\n }\n\n private gameUrl(path: string, params?: object): string {\n return buildUrl(this.baseUrl, `/api/v1/games/${encodeURIComponent(this.gameId)}${path}`, params);\n }\n\n private async fetch<T>(\n method: string,\n url: string,\n body?: unknown,\n extraHeaders?: Record<string, string>\n ): Promise<T> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n ...extraHeaders,\n };\n\n const res = await globalThis.fetch(url, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n let data: any;\n try {\n data = await res.json();\n } catch {\n throw new LightLeaderboardError(`HTTP ${res.status}: failed to parse response`, res.status, null);\n }\n\n if (!res.ok || data?.ok === false) {\n throw new LightLeaderboardError(\n data?.error ?? `HTTP ${res.status}`,\n res.status,\n data\n );\n }\n\n return data as T;\n }\n\n // ─── Score submission ───────────────────────────────────────────────────────\n\n /**\n * Submit a score to the leaderboard.\n *\n * Returns the player's new rank immediately — no second API call needed.\n *\n * @example\n * const result = await lb.submitScore({ score: 9500, playerRefId: 'p1', playerName: 'Alice' });\n * console.log(`Rank #${result.rank} of ${result.totalPlayers}`);\n */\n async submitScore(options: SubmitScoreOptions): Promise<SubmitScoreResult> {\n const url = this.gameUrl('/scores');\n const bodyStr = JSON.stringify(options);\n const extraHeaders: Record<string, string> = {};\n\n if (this.scoreSecret) {\n const sig = await hmacSha256(this.scoreSecret, bodyStr);\n extraHeaders['x-score-signature'] = `sha256=${sig}`;\n }\n\n const res = await globalThis.fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n ...extraHeaders,\n },\n body: bodyStr,\n });\n\n let data: any;\n try {\n data = await res.json();\n } catch {\n throw new LightLeaderboardError(`HTTP ${res.status}: failed to parse response`, res.status, null);\n }\n\n if (!res.ok || data?.ok === false) {\n throw new LightLeaderboardError(data?.error ?? `HTTP ${res.status}`, res.status, data);\n }\n\n return {\n id: data.id,\n rank: data.rank ?? null,\n isPersonalBest: data.isPersonalBest ?? false,\n totalPlayers: data.totalPlayers ?? null,\n deduped: data.deduped,\n };\n }\n\n // ─── Leaderboard ───────────────────────────────────────────────────────────\n\n /**\n * Fetch the leaderboard. Returns one entry per player (their best score) by default.\n *\n * @example\n * const { entries } = await lb.getLeaderboard({ limit: 10, period: 'weekly' });\n * entries.forEach(e => console.log(`#${e.rank} ${e.playerName}: ${e.score}`));\n */\n async getLeaderboard(options?: GetLeaderboardOptions): Promise<GetLeaderboardResult> {\n const { allEntries, ...rest } = options ?? {};\n const data = await this.fetch<any>(\n 'GET',\n this.gameUrl('/leaderboard', {\n ...rest,\n allEntries: allEntries ? 'true' : undefined,\n })\n );\n return {\n entries: data.entries,\n scoreOrder: data.scoreOrder,\n period: data.period,\n season: data.season ?? null,\n team: data.team ?? null,\n limit: data.limit,\n offset: data.offset,\n };\n }\n\n // ─── Rank ───────────────────────────────────────────────────────────────────\n\n /**\n * Get a player's current rank, score, and percentile.\n *\n * @example\n * const { rank, percentile } = await lb.getPlayerRank('player-123');\n * console.log(`Rank #${rank} — top ${(100 - percentile).toFixed(1)}%`);\n */\n async getPlayerRank(playerRefId: string, options?: GetRankOptions): Promise<PlayerRankResult> {\n return this.fetch<PlayerRankResult>(\n 'GET',\n this.gameUrl(`/players/${encodeURIComponent(playerRefId)}/rank`, options)\n );\n }\n\n // ─── Centric leaderboard ───────────────────────────────────────────────────\n\n /**\n * Fetch the leaderboard centered on a specific player, showing the players\n * immediately above and below them.\n *\n * @example\n * const { entries, playerRank } = await lb.getCentricLeaderboard('player-123', { limit: 11 });\n */\n async getCentricLeaderboard(\n playerRefId: string,\n options?: GetCentricOptions\n ): Promise<CentricLeaderboardResult> {\n const data = await this.fetch<any>(\n 'GET',\n this.gameUrl(`/players/${encodeURIComponent(playerRefId)}/centric`, options)\n );\n return {\n entries: data.entries,\n playerRank: data.playerRank ?? null,\n period: data.period,\n season: data.season ?? null,\n team: data.team ?? null,\n scoreOrder: data.scoreOrder,\n };\n }\n\n // ─── Player profile ─────────────────────────────────────────────────────────\n\n /**\n * Fetch a player's profile (name, avatar, country, level, etc.).\n */\n async getPlayer(playerRefId: string): Promise<PlayerProfile> {\n const data = await this.fetch<any>(\n 'GET',\n this.gameUrl(`/players/${encodeURIComponent(playerRefId)}`)\n );\n return data.player as PlayerProfile;\n }\n\n /**\n * Create or update a player's profile. Fields are merged — omitted fields\n * keep their existing values.\n *\n * @example\n * await lb.updatePlayer('player-123', { playerName: 'Alice', country: 'US', level: 5 });\n */\n async updatePlayer(playerRefId: string, options: UpdatePlayerOptions): Promise<void> {\n await this.fetch<any>(\n 'PUT',\n this.gameUrl(`/players/${encodeURIComponent(playerRefId)}`),\n options\n );\n }\n\n // ─── Score history ──────────────────────────────────────────────────────────\n\n /**\n * Fetch all submissions a player has ever made, ordered newest first.\n * Useful for progression charts and run history screens.\n *\n * @example\n * const { entries, bestScore, total } = await lb.getPlayerScores('player-123');\n */\n async getPlayerScores(\n playerRefId: string,\n options?: GetPlayerScoresOptions\n ): Promise<GetPlayerScoresResult> {\n return this.fetch<GetPlayerScoresResult>(\n 'GET',\n this.gameUrl(`/players/${encodeURIComponent(playerRefId)}/scores`, options)\n );\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "lightleaderboard",
3
+ "version": "1.0.0",
4
+ "description": "Official JavaScript/TypeScript SDK for LightLeaderboard — leaderboard-as-a-service for game developers",
5
+ "keywords": [
6
+ "leaderboard",
7
+ "game",
8
+ "gamedev",
9
+ "highscore",
10
+ "ranking",
11
+ "sdk"
12
+ ],
13
+ "homepage": "https://leaderboard.goproso.com",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/vivek/lightleaderboard"
17
+ },
18
+ "license": "MIT",
19
+ "type": "module",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js",
24
+ "require": "./dist/index.cjs"
25
+ }
26
+ },
27
+ "main": "./dist/index.cjs",
28
+ "module": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "files": [
31
+ "dist",
32
+ "README.md",
33
+ "LICENSE"
34
+ ],
35
+ "engines": {
36
+ "node": ">=18"
37
+ },
38
+ "scripts": {
39
+ "build": "tsup",
40
+ "dev": "tsup --watch",
41
+ "typecheck": "tsc --noEmit"
42
+ },
43
+ "devDependencies": {
44
+ "tsup": "^8.3.0",
45
+ "typescript": "^5.7.0"
46
+ }
47
+ }