star-leaderboard 0.1.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/README.md +258 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +228 -0
- package/dist/index.d.ts +228 -0
- package/dist/index.mjs +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# Star Leaderboard
|
|
2
|
+
|
|
3
|
+
A simple leaderboard SDK for web games that "just works" on Star.
|
|
4
|
+
|
|
5
|
+
`star-leaderboard` handles score submission and leaderboard display with a mobile-first design. It's designed to be predictable, easy to use, and LLM-friendly.
|
|
6
|
+
|
|
7
|
+
This package is part of the **Star SDK**.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Bulletproof:** API failures won't crash your game - errors are logged but never thrown.
|
|
12
|
+
- **Zero Config on Star:** When running inside the Star platform, gameId is auto-detected.
|
|
13
|
+
- **Tiny API Surface:** A small, guessable API (`submit`, `show`, `getScores`). No try/catch needed.
|
|
14
|
+
- **Dual Mode:** Works inside Star platform (via postMessage) or standalone (direct API).
|
|
15
|
+
- **SSR-Safe:** Can be imported in server-side environments without errors.
|
|
16
|
+
- **Zero Dependencies:** Pure TypeScript, under 2KB minified.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
yarn add star-leaderboard
|
|
22
|
+
# or
|
|
23
|
+
npm install star-leaderboard
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Starts
|
|
27
|
+
|
|
28
|
+
### 1. Vanilla JS on Star Platform (30 seconds)
|
|
29
|
+
|
|
30
|
+
This is the fastest way to add leaderboards to a Star game.
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
import { createLeaderboard } from 'star-leaderboard';
|
|
34
|
+
|
|
35
|
+
const leaderboard = createLeaderboard();
|
|
36
|
+
|
|
37
|
+
// When the game ends, submit the score and show the leaderboard
|
|
38
|
+
function gameOver(finalScore) {
|
|
39
|
+
leaderboard.submit(finalScore);
|
|
40
|
+
leaderboard.show();
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. With Async Result
|
|
45
|
+
|
|
46
|
+
If you want to know the player's rank after submitting:
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
import { createLeaderboard } from 'star-leaderboard';
|
|
50
|
+
|
|
51
|
+
const leaderboard = createLeaderboard();
|
|
52
|
+
|
|
53
|
+
async function gameOver(finalScore) {
|
|
54
|
+
const { success, rank } = await leaderboard.submit(finalScore);
|
|
55
|
+
|
|
56
|
+
if (success && rank) {
|
|
57
|
+
console.log(`You ranked #${rank}!`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
leaderboard.show();
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 3. Next.js / React (Client Component)
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
/* app/game/page.tsx */
|
|
68
|
+
"use client";
|
|
69
|
+
import { useEffect, useMemo } from 'react';
|
|
70
|
+
import { createLeaderboard } from 'star-leaderboard';
|
|
71
|
+
|
|
72
|
+
export default function Game() {
|
|
73
|
+
const leaderboard = useMemo(() => createLeaderboard(), []);
|
|
74
|
+
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
return () => leaderboard.destroy();
|
|
77
|
+
}, [leaderboard]);
|
|
78
|
+
|
|
79
|
+
const handleGameOver = async (score: number) => {
|
|
80
|
+
await leaderboard.submit(score);
|
|
81
|
+
leaderboard.show();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div className="h-screen w-screen">
|
|
86
|
+
{/* Your game here */}
|
|
87
|
+
<button onClick={() => handleGameOver(1250)}>
|
|
88
|
+
End Game (Score: 1250)
|
|
89
|
+
</button>
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 4. Standalone Use (Outside Star Platform)
|
|
96
|
+
|
|
97
|
+
For games hosted outside Star that want to use the Star leaderboard API:
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
import { createLeaderboard } from 'star-leaderboard';
|
|
101
|
+
|
|
102
|
+
const leaderboard = createLeaderboard({
|
|
103
|
+
gameId: 'your-game-uuid',
|
|
104
|
+
apiBase: 'https://buildwithstar.com'
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Fetch and display scores in your own UI
|
|
108
|
+
const { scores, you, config } = await leaderboard.getScores({
|
|
109
|
+
timeframe: 'weekly',
|
|
110
|
+
limit: 10
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
scores.forEach(entry => {
|
|
114
|
+
console.log(`#${entry.rank} ${entry.playerName}: ${entry.score}`);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (you) {
|
|
118
|
+
console.log(`Your best: #${you.rank} with ${you.score}`);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Common Recipes
|
|
123
|
+
|
|
124
|
+
### Submit Score and Show Leaderboard
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
// Fire and forget - simplest approach
|
|
128
|
+
leaderboard.submit(score);
|
|
129
|
+
leaderboard.show();
|
|
130
|
+
|
|
131
|
+
// Or wait for result
|
|
132
|
+
const result = await leaderboard.submit(score);
|
|
133
|
+
if (result.success) {
|
|
134
|
+
leaderboard.show();
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Custom Leaderboard UI
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
// Fetch scores for custom rendering
|
|
142
|
+
const data = await leaderboard.getScores({
|
|
143
|
+
timeframe: 'all_time',
|
|
144
|
+
limit: 100
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Build your own leaderboard UI
|
|
148
|
+
renderCustomLeaderboard(data.scores, data.config);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Share Leaderboard
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
// Generate a shareable link
|
|
155
|
+
const { shareUrl } = await leaderboard.share({
|
|
156
|
+
score: 1250,
|
|
157
|
+
gameTitle: 'My Awesome Game'
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Use Web Share API or open in new tab
|
|
161
|
+
if (navigator.share) {
|
|
162
|
+
navigator.share({ url: shareUrl });
|
|
163
|
+
} else {
|
|
164
|
+
window.open(shareUrl, '_blank');
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Listen for Submit Events
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
const unsubscribe = leaderboard.onSubmit((result) => {
|
|
172
|
+
if (result.success) {
|
|
173
|
+
showConfetti();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Later, clean up
|
|
178
|
+
unsubscribe();
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## API Reference
|
|
182
|
+
|
|
183
|
+
### `createLeaderboard(options?)`
|
|
184
|
+
|
|
185
|
+
Creates a leaderboard instance.
|
|
186
|
+
|
|
187
|
+
**Options:**
|
|
188
|
+
- `gameId?: string` - Game ID (auto-detected on Star platform)
|
|
189
|
+
- `apiBase?: string` - Base URL for API calls (default: relative paths)
|
|
190
|
+
|
|
191
|
+
**Returns:** `StarLeaderboard` instance
|
|
192
|
+
|
|
193
|
+
### `StarLeaderboard`
|
|
194
|
+
|
|
195
|
+
| Method | Description |
|
|
196
|
+
|--------|-------------|
|
|
197
|
+
| `submit(score)` | Submit a score. Returns `Promise<SubmitResult>` |
|
|
198
|
+
| `show()` | Show the platform leaderboard UI (Star platform only) |
|
|
199
|
+
| `getScores(options?)` | Fetch leaderboard data. Returns `Promise<LeaderboardData>` |
|
|
200
|
+
| `share(options?)` | Generate a shareable link. Returns `Promise<ShareResult>` |
|
|
201
|
+
| `onSubmit(fn)` | Subscribe to submit events. Returns unsubscribe function |
|
|
202
|
+
| `destroy()` | Clean up resources |
|
|
203
|
+
|
|
204
|
+
**Aliases:**
|
|
205
|
+
- `submitScore` → alias for `submit`
|
|
206
|
+
- `showLeaderboard` → alias for `show`
|
|
207
|
+
|
|
208
|
+
### Types
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
interface SubmitResult {
|
|
212
|
+
success: boolean;
|
|
213
|
+
rank?: number;
|
|
214
|
+
scoreId?: string;
|
|
215
|
+
error?: string;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
interface LeaderboardData {
|
|
219
|
+
scores: ScoreEntry[];
|
|
220
|
+
config?: LeaderboardConfig;
|
|
221
|
+
timeframe: 'weekly' | 'all_time';
|
|
222
|
+
you?: ScoreEntry | null;
|
|
223
|
+
weekResetTime?: number | null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
interface ScoreEntry {
|
|
227
|
+
id: string;
|
|
228
|
+
playerName: string | null;
|
|
229
|
+
score: number;
|
|
230
|
+
rank: number;
|
|
231
|
+
submittedAt: string;
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Error Handling Philosophy
|
|
236
|
+
|
|
237
|
+
Star Leaderboard is designed to **never crash your game**. All methods gracefully handle failures:
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
// ✅ This never throws - even if the API is down!
|
|
241
|
+
const result = await leaderboard.submit(score);
|
|
242
|
+
|
|
243
|
+
if (!result.success) {
|
|
244
|
+
// ⚠️ Logged to console, error in result
|
|
245
|
+
console.log('Submission failed:', result.error);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Game continues working
|
|
249
|
+
leaderboard.show(); // ✅ Still works (shows cached/empty state)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**No try/catch needed.** Failed API calls are logged to the console with clear warnings, but your game keeps running.
|
|
253
|
+
|
|
254
|
+
## Known Limitations
|
|
255
|
+
|
|
256
|
+
- **Platform UI only on Star:** The `show()` method only works inside the Star platform iframe. For standalone use, build custom UI with `getScores()`.
|
|
257
|
+
- **No offline support:** Scores require network connectivity to submit.
|
|
258
|
+
- **Weekly reset:** Weekly leaderboards reset Monday 02:00 UTC (Sunday 9pm ET).
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var S=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var T=(n,t)=>{for(var d in t)S(n,d,{get:t[d],enumerable:!0})},P=(n,t,d,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of k(t))!R.call(n,e)&&e!==d&&S(n,e,{get:()=>t[e],enumerable:!(s=I(t,e))||s.enumerable});return n};var v=n=>P(S({},"__esModule",{value:!0}),n);var _={};T(_,{VERSION:()=>E,createLeaderboard:()=>h,default:()=>U});module.exports=v(_);var x="star_leaderboard_sdk",L="star_leaderboard_parent",O="star_game_runtime";function y(){let n=null,t=!1,d=0,s=new Map;function e(i,r){try{window.parent.postMessage({source:x,type:i,payload:r},"*")}catch{}}function u(i,r){try{window.parent.postMessage({source:O,type:i,payload:r},"*")}catch{}}function c(i){if(!i.data||typeof i.data!="object")return;let{source:r,type:a,payload:o}=i.data;if(r===L)switch(a){case"context":o?.gameId&&(n=o.gameId,t=!0);break;case"submit_result":{let m=o?.id,f=s.get(m);f&&(clearTimeout(f.timeoutId),s.delete(m),f.resolve({success:o?.success??!1,rank:o?.rank,scoreId:o?.scoreId,error:o?.error}));break}}}return window.addEventListener("message",c),e("request_context"),{get gameId(){return n},get ready(){return t},async submit(i){let r=++d;return new Promise(a=>{let o=setTimeout(()=>{s.has(r)&&(s.delete(r),a({success:!1,error:"Timeout waiting for response"}))},1e4);s.set(r,{resolve:a,timeoutId:o}),e("submit_score",{id:r,score:i})})},show(){u("star_show_leaderboard")},destroy(){window.removeEventListener("message",c);for(let[i,r]of s)clearTimeout(r.timeoutId),r.resolve({success:!1,error:"SDK destroyed"});s.clear()}}}function b(n=""){async function t(d,s,e){let u=`${n}${s}`,c={method:d,headers:{"Content-Type":"application/json"}};e!==void 0&&(c.body=JSON.stringify(e));let i=await fetch(u,c);if(!i.ok){let r=await i.json().catch(()=>({}));throw new Error(r.error||`HTTP ${i.status}`)}return i.json()}return{async submit(d,s){try{let e=encodeURIComponent(d),u=await t("POST",`/api/sdk/leaderboard/${e}/submit`,{score:s});return{success:u.success,rank:u.rank,scoreId:u.scoreId}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Unknown error"}}},async getScores(d,s={}){try{let e=new URLSearchParams;s.limit&&e.set("limit",String(s.limit)),s.timeframe&&e.set("timeframe",s.timeframe);let u=e.toString(),i=`/api/sdk/leaderboard/${encodeURIComponent(d)}${u?`?${u}`:""}`,r=await t("GET",i);return{scores:r.scores.map((a,o)=>({id:a.id,playerName:a.playerName,score:a.score,rank:a.rank??o+1,submittedAt:a.submittedAt})),config:r.config,timeframe:r.timeframe,you:r.you?{id:r.you.id,playerName:r.you.playerName,score:r.you.score,rank:r.you.rank??0,submittedAt:r.you.submittedAt}:null,weekResetTime:r.weekResetTime}}catch{return{scores:[],timeframe:s.timeframe??"weekly",you:null}}},async share(d,s={}){try{let e=encodeURIComponent(d);return{success:!0,shareUrl:(await t("POST",`/api/sdk/leaderboard/${e}/share`,{gameTitle:s.gameTitle,score:s.score,playerName:s.playerName})).shareUrl}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Unknown error"}}}}}function p(){return typeof window<"u"}function l(n,...t){p()&&typeof console<"u"&&console.warn(`[star-leaderboard] ${n}`,...t)}function g(n,...t){p()&&typeof console<"u"&&console.error(`[star-leaderboard] ${n}`,...t)}function C(){try{return window.parent===window?!1:typeof window.submitStarScore=="function"}catch{return!1}}function w(n={}){let t=C(),d=n.gameId??null,s=n.apiBase??"",e=null,u=null,c=new Set;t?e=y():u=b(s);function i(){return d??e?.gameId??null}let r={get ready(){return t?e?.ready??!1:d!==null},get gameId(){return i()},async submit(a){if(typeof a!="number"||!isFinite(a))return l("Invalid score value:",a),{success:!1,error:"Invalid score value"};try{let o;if(t&&e)o=await e.submit(a);else if(u){let m=i();if(!m)return l("gameId is required for standalone mode"),{success:!1,error:"gameId is required"};o=await u.submit(m,a)}else return{success:!1,error:"Not initialized"};for(let m of c)try{m(o)}catch(f){g("Submit handler error:",f)}return o}catch(o){let m=o instanceof Error?o.message:"Unknown error";return g("Failed to submit score:",o),{success:!1,error:m}}},async getScores(a={}){let o=i();return o?(u||(u=b(s)),u.getScores(o,a)):(l("gameId is required to fetch scores"),{scores:[],timeframe:a.timeframe??"weekly",you:null})},show(){t&&e?e.show():l("show() requires Star platform context. Use getScores() to build custom UI.")},async share(a={}){let o=i();if(!o)return l("gameId is required for sharing"),{success:!1,error:"gameId is required"};u||(u=b(s));try{return await u.share(o,a)}catch(m){return g("Failed to generate share link:",m),{success:!1,error:m instanceof Error?m.message:"Unknown error"}}},get submitScore(){return r.submit},get showLeaderboard(){return r.show},onSubmit(a){return c.add(a),()=>{c.delete(a)}},destroy(){e&&(e.destroy(),e=null),c.clear()}};return r}var E="0.0.1";function A(){let n=()=>{},t=d=>()=>Promise.resolve(d);return{ready:!1,gameId:null,submit:t({success:!1,error:"SSR environment"}),getScores:t({scores:[],timeframe:"weekly",you:null}),show:n,share:t({success:!1,error:"SSR environment"}),get submitScore(){return this.submit},get showLeaderboard(){return this.show},onSubmit:()=>n,destroy:n}}function h(n){return p()?w(n):A()}var U=h;0&&(module.exports={VERSION,createLeaderboard});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Star Leaderboard SDK
|
|
3
|
+
*
|
|
4
|
+
* Submit scores and display leaderboards for Star games.
|
|
5
|
+
*
|
|
6
|
+
* Design goals:
|
|
7
|
+
* - LLM-friendly: Obvious method names, copy-paste examples
|
|
8
|
+
* - Never crashes: All errors handled gracefully
|
|
9
|
+
* - Dual mode: Works inside Star platform or standalone
|
|
10
|
+
* - SSR-safe: No-op in server environments
|
|
11
|
+
*/
|
|
12
|
+
declare const VERSION = "0.0.1";
|
|
13
|
+
/**
|
|
14
|
+
* Value type for leaderboard scores.
|
|
15
|
+
* The system auto-detects this based on the game.
|
|
16
|
+
*/
|
|
17
|
+
type ValueType = 'score' | 'time' | 'moves' | 'attempts' | 'strokes';
|
|
18
|
+
/**
|
|
19
|
+
* Timeframe for fetching scores.
|
|
20
|
+
*/
|
|
21
|
+
type Timeframe = 'weekly' | 'all_time';
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for the leaderboard SDK.
|
|
24
|
+
*/
|
|
25
|
+
interface LeaderboardOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Game ID - auto-detected on Star platform, required for standalone use.
|
|
28
|
+
* If not provided, SDK will attempt to get it from platform context.
|
|
29
|
+
*/
|
|
30
|
+
gameId?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Base URL for API calls. Defaults to relative paths for Star platform.
|
|
33
|
+
* Set to 'https://buildwithstar.com' for standalone use.
|
|
34
|
+
*/
|
|
35
|
+
apiBase?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Result of submitting a score.
|
|
39
|
+
*/
|
|
40
|
+
interface SubmitResult {
|
|
41
|
+
/** Whether the submission succeeded */
|
|
42
|
+
success: boolean;
|
|
43
|
+
/** Player's rank on the leaderboard (1 = first place) */
|
|
44
|
+
rank?: number;
|
|
45
|
+
/** Unique ID of the submitted score */
|
|
46
|
+
scoreId?: string;
|
|
47
|
+
/** Error message if submission failed */
|
|
48
|
+
error?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A single score entry on the leaderboard.
|
|
52
|
+
*/
|
|
53
|
+
interface ScoreEntry {
|
|
54
|
+
/** Unique ID of the score */
|
|
55
|
+
id: string;
|
|
56
|
+
/** Player's display name */
|
|
57
|
+
playerName: string | null;
|
|
58
|
+
/** The score value */
|
|
59
|
+
score: number;
|
|
60
|
+
/** Player's rank (1 = first place) */
|
|
61
|
+
rank: number;
|
|
62
|
+
/** ISO timestamp when score was submitted */
|
|
63
|
+
submittedAt: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Configuration for the leaderboard (auto-detected by AI).
|
|
67
|
+
*/
|
|
68
|
+
interface LeaderboardConfig {
|
|
69
|
+
/** Sort order: DESC for "higher is better", ASC for "lower is better" */
|
|
70
|
+
sort?: 'ASC' | 'DESC';
|
|
71
|
+
/** Type of value being tracked */
|
|
72
|
+
valueType?: ValueType;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Full leaderboard data payload.
|
|
76
|
+
*/
|
|
77
|
+
interface LeaderboardData {
|
|
78
|
+
/** Top scores */
|
|
79
|
+
scores: ScoreEntry[];
|
|
80
|
+
/** Leaderboard configuration */
|
|
81
|
+
config?: LeaderboardConfig;
|
|
82
|
+
/** Current timeframe */
|
|
83
|
+
timeframe: Timeframe;
|
|
84
|
+
/** Current user's score (if outside top scores) */
|
|
85
|
+
you?: ScoreEntry | null;
|
|
86
|
+
/** Unix timestamp (ms) when weekly leaderboard resets */
|
|
87
|
+
weekResetTime?: number | null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Options for fetching scores.
|
|
91
|
+
*/
|
|
92
|
+
interface GetScoresOptions {
|
|
93
|
+
/** Time period: 'weekly' (default) or 'all_time' */
|
|
94
|
+
timeframe?: Timeframe;
|
|
95
|
+
/** Maximum scores to return (default: 10) */
|
|
96
|
+
limit?: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Options for sharing the leaderboard.
|
|
100
|
+
*/
|
|
101
|
+
interface ShareOptions {
|
|
102
|
+
/** Game title for the share card */
|
|
103
|
+
gameTitle?: string;
|
|
104
|
+
/** Score to highlight */
|
|
105
|
+
score?: number;
|
|
106
|
+
/** Player name to display */
|
|
107
|
+
playerName?: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Result of generating a share link.
|
|
111
|
+
*/
|
|
112
|
+
interface ShareResult {
|
|
113
|
+
/** Whether share link was generated */
|
|
114
|
+
success: boolean;
|
|
115
|
+
/** Shareable URL */
|
|
116
|
+
shareUrl?: string;
|
|
117
|
+
/** Error message if failed */
|
|
118
|
+
error?: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The main Star Leaderboard SDK interface.
|
|
122
|
+
*/
|
|
123
|
+
interface StarLeaderboard {
|
|
124
|
+
/** Whether the SDK is ready to use */
|
|
125
|
+
readonly ready: boolean;
|
|
126
|
+
/** Current game ID */
|
|
127
|
+
readonly gameId: string | null;
|
|
128
|
+
/**
|
|
129
|
+
* Submit a score to the leaderboard.
|
|
130
|
+
*
|
|
131
|
+
* @param score - The score value to submit
|
|
132
|
+
* @returns Result with success status and rank
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```javascript
|
|
136
|
+
* const { success, rank } = await leaderboard.submit(1250);
|
|
137
|
+
* if (success) console.log(`You're ranked #${rank}!`);
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
submit(score: number): Promise<SubmitResult>;
|
|
141
|
+
/**
|
|
142
|
+
* Fetch leaderboard scores.
|
|
143
|
+
*
|
|
144
|
+
* @param options - Fetch options (timeframe, limit)
|
|
145
|
+
* @returns Leaderboard data with scores
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```javascript
|
|
149
|
+
* const { scores, you } = await leaderboard.getScores({ timeframe: 'weekly' });
|
|
150
|
+
* scores.forEach(s => console.log(`#${s.rank} ${s.playerName}: ${s.score}`));
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
getScores(options?: GetScoresOptions): Promise<LeaderboardData>;
|
|
154
|
+
/**
|
|
155
|
+
* Show the platform leaderboard UI.
|
|
156
|
+
* Only works inside Star platform; logs warning otherwise.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```javascript
|
|
160
|
+
* // After game over
|
|
161
|
+
* leaderboard.submit(score);
|
|
162
|
+
* leaderboard.show();
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
show(): void;
|
|
166
|
+
/**
|
|
167
|
+
* Generate a shareable link for the leaderboard.
|
|
168
|
+
*
|
|
169
|
+
* @param options - Share options
|
|
170
|
+
* @returns Result with shareable URL
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```javascript
|
|
174
|
+
* const { shareUrl } = await leaderboard.share({ score: 1250 });
|
|
175
|
+
* navigator.share?.({ url: shareUrl });
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
share(options?: ShareOptions): Promise<ShareResult>;
|
|
179
|
+
/** Alias for submit() - for LLM discoverability */
|
|
180
|
+
submitScore: StarLeaderboard['submit'];
|
|
181
|
+
/** Alias for show() - for LLM discoverability */
|
|
182
|
+
showLeaderboard: StarLeaderboard['show'];
|
|
183
|
+
/**
|
|
184
|
+
* Subscribe to score submission results.
|
|
185
|
+
*
|
|
186
|
+
* @param fn - Callback function
|
|
187
|
+
* @returns Unsubscribe function
|
|
188
|
+
*/
|
|
189
|
+
onSubmit(fn: (result: SubmitResult) => void): () => void;
|
|
190
|
+
/**
|
|
191
|
+
* Clean up SDK resources.
|
|
192
|
+
*/
|
|
193
|
+
destroy(): void;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Creates a Star Leaderboard SDK instance.
|
|
197
|
+
*
|
|
198
|
+
* @param options - Configuration options
|
|
199
|
+
* @returns StarLeaderboard instance
|
|
200
|
+
*
|
|
201
|
+
* @example Platform use (inside Star iframe):
|
|
202
|
+
* ```javascript
|
|
203
|
+
* import { createLeaderboard } from 'star-leaderboard';
|
|
204
|
+
*
|
|
205
|
+
* const leaderboard = createLeaderboard();
|
|
206
|
+
*
|
|
207
|
+
* // Submit a score when game ends
|
|
208
|
+
* await leaderboard.submit(1250);
|
|
209
|
+
*
|
|
210
|
+
* // Show the leaderboard UI
|
|
211
|
+
* leaderboard.show();
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
214
|
+
* @example Standalone use:
|
|
215
|
+
* ```javascript
|
|
216
|
+
* import { createLeaderboard } from 'star-leaderboard';
|
|
217
|
+
*
|
|
218
|
+
* const leaderboard = createLeaderboard({
|
|
219
|
+
* gameId: 'your-game-id',
|
|
220
|
+
* apiBase: 'https://buildwithstar.com'
|
|
221
|
+
* });
|
|
222
|
+
*
|
|
223
|
+
* const { scores } = await leaderboard.getScores({ timeframe: 'weekly' });
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
declare function createLeaderboard(options?: LeaderboardOptions): StarLeaderboard;
|
|
227
|
+
|
|
228
|
+
export { type GetScoresOptions, type LeaderboardConfig, type LeaderboardData, type LeaderboardOptions, type ScoreEntry, type ShareOptions, type ShareResult, type StarLeaderboard, type SubmitResult, type Timeframe, VERSION, type ValueType, createLeaderboard, createLeaderboard as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Star Leaderboard SDK
|
|
3
|
+
*
|
|
4
|
+
* Submit scores and display leaderboards for Star games.
|
|
5
|
+
*
|
|
6
|
+
* Design goals:
|
|
7
|
+
* - LLM-friendly: Obvious method names, copy-paste examples
|
|
8
|
+
* - Never crashes: All errors handled gracefully
|
|
9
|
+
* - Dual mode: Works inside Star platform or standalone
|
|
10
|
+
* - SSR-safe: No-op in server environments
|
|
11
|
+
*/
|
|
12
|
+
declare const VERSION = "0.0.1";
|
|
13
|
+
/**
|
|
14
|
+
* Value type for leaderboard scores.
|
|
15
|
+
* The system auto-detects this based on the game.
|
|
16
|
+
*/
|
|
17
|
+
type ValueType = 'score' | 'time' | 'moves' | 'attempts' | 'strokes';
|
|
18
|
+
/**
|
|
19
|
+
* Timeframe for fetching scores.
|
|
20
|
+
*/
|
|
21
|
+
type Timeframe = 'weekly' | 'all_time';
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for the leaderboard SDK.
|
|
24
|
+
*/
|
|
25
|
+
interface LeaderboardOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Game ID - auto-detected on Star platform, required for standalone use.
|
|
28
|
+
* If not provided, SDK will attempt to get it from platform context.
|
|
29
|
+
*/
|
|
30
|
+
gameId?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Base URL for API calls. Defaults to relative paths for Star platform.
|
|
33
|
+
* Set to 'https://buildwithstar.com' for standalone use.
|
|
34
|
+
*/
|
|
35
|
+
apiBase?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Result of submitting a score.
|
|
39
|
+
*/
|
|
40
|
+
interface SubmitResult {
|
|
41
|
+
/** Whether the submission succeeded */
|
|
42
|
+
success: boolean;
|
|
43
|
+
/** Player's rank on the leaderboard (1 = first place) */
|
|
44
|
+
rank?: number;
|
|
45
|
+
/** Unique ID of the submitted score */
|
|
46
|
+
scoreId?: string;
|
|
47
|
+
/** Error message if submission failed */
|
|
48
|
+
error?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A single score entry on the leaderboard.
|
|
52
|
+
*/
|
|
53
|
+
interface ScoreEntry {
|
|
54
|
+
/** Unique ID of the score */
|
|
55
|
+
id: string;
|
|
56
|
+
/** Player's display name */
|
|
57
|
+
playerName: string | null;
|
|
58
|
+
/** The score value */
|
|
59
|
+
score: number;
|
|
60
|
+
/** Player's rank (1 = first place) */
|
|
61
|
+
rank: number;
|
|
62
|
+
/** ISO timestamp when score was submitted */
|
|
63
|
+
submittedAt: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Configuration for the leaderboard (auto-detected by AI).
|
|
67
|
+
*/
|
|
68
|
+
interface LeaderboardConfig {
|
|
69
|
+
/** Sort order: DESC for "higher is better", ASC for "lower is better" */
|
|
70
|
+
sort?: 'ASC' | 'DESC';
|
|
71
|
+
/** Type of value being tracked */
|
|
72
|
+
valueType?: ValueType;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Full leaderboard data payload.
|
|
76
|
+
*/
|
|
77
|
+
interface LeaderboardData {
|
|
78
|
+
/** Top scores */
|
|
79
|
+
scores: ScoreEntry[];
|
|
80
|
+
/** Leaderboard configuration */
|
|
81
|
+
config?: LeaderboardConfig;
|
|
82
|
+
/** Current timeframe */
|
|
83
|
+
timeframe: Timeframe;
|
|
84
|
+
/** Current user's score (if outside top scores) */
|
|
85
|
+
you?: ScoreEntry | null;
|
|
86
|
+
/** Unix timestamp (ms) when weekly leaderboard resets */
|
|
87
|
+
weekResetTime?: number | null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Options for fetching scores.
|
|
91
|
+
*/
|
|
92
|
+
interface GetScoresOptions {
|
|
93
|
+
/** Time period: 'weekly' (default) or 'all_time' */
|
|
94
|
+
timeframe?: Timeframe;
|
|
95
|
+
/** Maximum scores to return (default: 10) */
|
|
96
|
+
limit?: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Options for sharing the leaderboard.
|
|
100
|
+
*/
|
|
101
|
+
interface ShareOptions {
|
|
102
|
+
/** Game title for the share card */
|
|
103
|
+
gameTitle?: string;
|
|
104
|
+
/** Score to highlight */
|
|
105
|
+
score?: number;
|
|
106
|
+
/** Player name to display */
|
|
107
|
+
playerName?: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Result of generating a share link.
|
|
111
|
+
*/
|
|
112
|
+
interface ShareResult {
|
|
113
|
+
/** Whether share link was generated */
|
|
114
|
+
success: boolean;
|
|
115
|
+
/** Shareable URL */
|
|
116
|
+
shareUrl?: string;
|
|
117
|
+
/** Error message if failed */
|
|
118
|
+
error?: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The main Star Leaderboard SDK interface.
|
|
122
|
+
*/
|
|
123
|
+
interface StarLeaderboard {
|
|
124
|
+
/** Whether the SDK is ready to use */
|
|
125
|
+
readonly ready: boolean;
|
|
126
|
+
/** Current game ID */
|
|
127
|
+
readonly gameId: string | null;
|
|
128
|
+
/**
|
|
129
|
+
* Submit a score to the leaderboard.
|
|
130
|
+
*
|
|
131
|
+
* @param score - The score value to submit
|
|
132
|
+
* @returns Result with success status and rank
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```javascript
|
|
136
|
+
* const { success, rank } = await leaderboard.submit(1250);
|
|
137
|
+
* if (success) console.log(`You're ranked #${rank}!`);
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
submit(score: number): Promise<SubmitResult>;
|
|
141
|
+
/**
|
|
142
|
+
* Fetch leaderboard scores.
|
|
143
|
+
*
|
|
144
|
+
* @param options - Fetch options (timeframe, limit)
|
|
145
|
+
* @returns Leaderboard data with scores
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```javascript
|
|
149
|
+
* const { scores, you } = await leaderboard.getScores({ timeframe: 'weekly' });
|
|
150
|
+
* scores.forEach(s => console.log(`#${s.rank} ${s.playerName}: ${s.score}`));
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
getScores(options?: GetScoresOptions): Promise<LeaderboardData>;
|
|
154
|
+
/**
|
|
155
|
+
* Show the platform leaderboard UI.
|
|
156
|
+
* Only works inside Star platform; logs warning otherwise.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```javascript
|
|
160
|
+
* // After game over
|
|
161
|
+
* leaderboard.submit(score);
|
|
162
|
+
* leaderboard.show();
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
show(): void;
|
|
166
|
+
/**
|
|
167
|
+
* Generate a shareable link for the leaderboard.
|
|
168
|
+
*
|
|
169
|
+
* @param options - Share options
|
|
170
|
+
* @returns Result with shareable URL
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```javascript
|
|
174
|
+
* const { shareUrl } = await leaderboard.share({ score: 1250 });
|
|
175
|
+
* navigator.share?.({ url: shareUrl });
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
share(options?: ShareOptions): Promise<ShareResult>;
|
|
179
|
+
/** Alias for submit() - for LLM discoverability */
|
|
180
|
+
submitScore: StarLeaderboard['submit'];
|
|
181
|
+
/** Alias for show() - for LLM discoverability */
|
|
182
|
+
showLeaderboard: StarLeaderboard['show'];
|
|
183
|
+
/**
|
|
184
|
+
* Subscribe to score submission results.
|
|
185
|
+
*
|
|
186
|
+
* @param fn - Callback function
|
|
187
|
+
* @returns Unsubscribe function
|
|
188
|
+
*/
|
|
189
|
+
onSubmit(fn: (result: SubmitResult) => void): () => void;
|
|
190
|
+
/**
|
|
191
|
+
* Clean up SDK resources.
|
|
192
|
+
*/
|
|
193
|
+
destroy(): void;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Creates a Star Leaderboard SDK instance.
|
|
197
|
+
*
|
|
198
|
+
* @param options - Configuration options
|
|
199
|
+
* @returns StarLeaderboard instance
|
|
200
|
+
*
|
|
201
|
+
* @example Platform use (inside Star iframe):
|
|
202
|
+
* ```javascript
|
|
203
|
+
* import { createLeaderboard } from 'star-leaderboard';
|
|
204
|
+
*
|
|
205
|
+
* const leaderboard = createLeaderboard();
|
|
206
|
+
*
|
|
207
|
+
* // Submit a score when game ends
|
|
208
|
+
* await leaderboard.submit(1250);
|
|
209
|
+
*
|
|
210
|
+
* // Show the leaderboard UI
|
|
211
|
+
* leaderboard.show();
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
214
|
+
* @example Standalone use:
|
|
215
|
+
* ```javascript
|
|
216
|
+
* import { createLeaderboard } from 'star-leaderboard';
|
|
217
|
+
*
|
|
218
|
+
* const leaderboard = createLeaderboard({
|
|
219
|
+
* gameId: 'your-game-id',
|
|
220
|
+
* apiBase: 'https://buildwithstar.com'
|
|
221
|
+
* });
|
|
222
|
+
*
|
|
223
|
+
* const { scores } = await leaderboard.getScores({ timeframe: 'weekly' });
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
declare function createLeaderboard(options?: LeaderboardOptions): StarLeaderboard;
|
|
227
|
+
|
|
228
|
+
export { type GetScoresOptions, type LeaderboardConfig, type LeaderboardData, type LeaderboardOptions, type ScoreEntry, type ShareOptions, type ShareResult, type StarLeaderboard, type SubmitResult, type Timeframe, VERSION, type ValueType, createLeaderboard, createLeaderboard as default };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var w="star_leaderboard_sdk",h="star_leaderboard_parent",I="star_game_runtime";function S(){let u=null,i=!1,d=0,s=new Map;function e(n,r){try{window.parent.postMessage({source:w,type:n,payload:r},"*")}catch{}}function a(n,r){try{window.parent.postMessage({source:I,type:n,payload:r},"*")}catch{}}function c(n){if(!n.data||typeof n.data!="object")return;let{source:r,type:o,payload:t}=n.data;if(r===h)switch(o){case"context":t?.gameId&&(u=t.gameId,i=!0);break;case"submit_result":{let m=t?.id,f=s.get(m);f&&(clearTimeout(f.timeoutId),s.delete(m),f.resolve({success:t?.success??!1,rank:t?.rank,scoreId:t?.scoreId,error:t?.error}));break}}}return window.addEventListener("message",c),e("request_context"),{get gameId(){return u},get ready(){return i},async submit(n){let r=++d;return new Promise(o=>{let t=setTimeout(()=>{s.has(r)&&(s.delete(r),o({success:!1,error:"Timeout waiting for response"}))},1e4);s.set(r,{resolve:o,timeoutId:t}),e("submit_score",{id:r,score:n})})},show(){a("star_show_leaderboard")},destroy(){window.removeEventListener("message",c);for(let[n,r]of s)clearTimeout(r.timeoutId),r.resolve({success:!1,error:"SDK destroyed"});s.clear()}}}function b(u=""){async function i(d,s,e){let a=`${u}${s}`,c={method:d,headers:{"Content-Type":"application/json"}};e!==void 0&&(c.body=JSON.stringify(e));let n=await fetch(a,c);if(!n.ok){let r=await n.json().catch(()=>({}));throw new Error(r.error||`HTTP ${n.status}`)}return n.json()}return{async submit(d,s){try{let e=encodeURIComponent(d),a=await i("POST",`/api/sdk/leaderboard/${e}/submit`,{score:s});return{success:a.success,rank:a.rank,scoreId:a.scoreId}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Unknown error"}}},async getScores(d,s={}){try{let e=new URLSearchParams;s.limit&&e.set("limit",String(s.limit)),s.timeframe&&e.set("timeframe",s.timeframe);let a=e.toString(),n=`/api/sdk/leaderboard/${encodeURIComponent(d)}${a?`?${a}`:""}`,r=await i("GET",n);return{scores:r.scores.map((o,t)=>({id:o.id,playerName:o.playerName,score:o.score,rank:o.rank??t+1,submittedAt:o.submittedAt})),config:r.config,timeframe:r.timeframe,you:r.you?{id:r.you.id,playerName:r.you.playerName,score:r.you.score,rank:r.you.rank??0,submittedAt:r.you.submittedAt}:null,weekResetTime:r.weekResetTime}}catch{return{scores:[],timeframe:s.timeframe??"weekly",you:null}}},async share(d,s={}){try{let e=encodeURIComponent(d);return{success:!0,shareUrl:(await i("POST",`/api/sdk/leaderboard/${e}/share`,{gameTitle:s.gameTitle,score:s.score,playerName:s.playerName})).shareUrl}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Unknown error"}}}}}function p(){return typeof window<"u"}function l(u,...i){p()&&typeof console<"u"&&console.warn(`[star-leaderboard] ${u}`,...i)}function g(u,...i){p()&&typeof console<"u"&&console.error(`[star-leaderboard] ${u}`,...i)}function k(){try{return window.parent===window?!1:typeof window.submitStarScore=="function"}catch{return!1}}function y(u={}){let i=k(),d=u.gameId??null,s=u.apiBase??"",e=null,a=null,c=new Set;i?e=S():a=b(s);function n(){return d??e?.gameId??null}let r={get ready(){return i?e?.ready??!1:d!==null},get gameId(){return n()},async submit(o){if(typeof o!="number"||!isFinite(o))return l("Invalid score value:",o),{success:!1,error:"Invalid score value"};try{let t;if(i&&e)t=await e.submit(o);else if(a){let m=n();if(!m)return l("gameId is required for standalone mode"),{success:!1,error:"gameId is required"};t=await a.submit(m,o)}else return{success:!1,error:"Not initialized"};for(let m of c)try{m(t)}catch(f){g("Submit handler error:",f)}return t}catch(t){let m=t instanceof Error?t.message:"Unknown error";return g("Failed to submit score:",t),{success:!1,error:m}}},async getScores(o={}){let t=n();return t?(a||(a=b(s)),a.getScores(t,o)):(l("gameId is required to fetch scores"),{scores:[],timeframe:o.timeframe??"weekly",you:null})},show(){i&&e?e.show():l("show() requires Star platform context. Use getScores() to build custom UI.")},async share(o={}){let t=n();if(!t)return l("gameId is required for sharing"),{success:!1,error:"gameId is required"};a||(a=b(s));try{return await a.share(t,o)}catch(m){return g("Failed to generate share link:",m),{success:!1,error:m instanceof Error?m.message:"Unknown error"}}},get submitScore(){return r.submit},get showLeaderboard(){return r.show},onSubmit(o){return c.add(o),()=>{c.delete(o)}},destroy(){e&&(e.destroy(),e=null),c.clear()}};return r}var _="0.0.1";function R(){let u=()=>{},i=d=>()=>Promise.resolve(d);return{ready:!1,gameId:null,submit:i({success:!1,error:"SSR environment"}),getScores:i({scores:[],timeframe:"weekly",you:null}),show:u,share:i({success:!1,error:"SSR environment"}),get submitScore(){return this.submit},get showLeaderboard(){return this.show},onSubmit:()=>u,destroy:u}}function T(u){return p()?y(u):R()}var N=T;export{_ as VERSION,T as createLeaderboard,N as default};
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "star-leaderboard",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Leaderboard SDK for Star games - submit scores and display rankings.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"starSdk": {
|
|
9
|
+
"internalImport": "import { createLeaderboard } from '/star-sdk/v1/leaderboard.js';",
|
|
10
|
+
"publicImport": "import { createLeaderboard } from 'star-leaderboard';",
|
|
11
|
+
"publicPath": "dist/index.mjs",
|
|
12
|
+
"outputs": [
|
|
13
|
+
{ "src": "dist/index.mjs", "dest": "v1/leaderboard.js" }
|
|
14
|
+
],
|
|
15
|
+
"skill": {
|
|
16
|
+
"name": "star-leaderboard-sdk",
|
|
17
|
+
"description": "Star Leaderboard SDK for competitive game rankings. Use when implementing score submission, leaderboard display, high scores, or sharing game results."
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.mjs",
|
|
24
|
+
"require": "./dist/index.cjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"module": "./dist/index.mjs",
|
|
28
|
+
"main": "./dist/index.cjs",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsup",
|
|
35
|
+
"clean": "rm -rf dist",
|
|
36
|
+
"test": "jest",
|
|
37
|
+
"prepublishOnly": "node ../../apps/web/scripts/process-sdks.js --package star-leaderboard --public-only && yarn build"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"leaderboard",
|
|
41
|
+
"scores",
|
|
42
|
+
"highscore",
|
|
43
|
+
"ranking",
|
|
44
|
+
"games",
|
|
45
|
+
"star-sdk"
|
|
46
|
+
],
|
|
47
|
+
"dependencies": {},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/jest": "^29.5.12",
|
|
50
|
+
"jest": "^29.7.0",
|
|
51
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
52
|
+
"ts-jest": "^29.1.2",
|
|
53
|
+
"tsup": "^8.0.2",
|
|
54
|
+
"typescript": "^5.4.5"
|
|
55
|
+
}
|
|
56
|
+
}
|