@freegamestore/games 0.15.1 → 0.18.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.
Files changed (91) hide show
  1. package/README.md +61 -8
  2. package/TOKENS.md +132 -0
  3. package/dist/Confetti.d.ts +20 -0
  4. package/dist/Confetti.d.ts.map +1 -0
  5. package/dist/Confetti.js +76 -0
  6. package/dist/Confetti.js.map +1 -0
  7. package/dist/GameConfirm.d.ts +1 -1
  8. package/dist/GameConfirm.d.ts.map +1 -1
  9. package/dist/GameModal.d.ts +1 -1
  10. package/dist/GameModal.d.ts.map +1 -1
  11. package/dist/GameOverScreen.d.ts +1 -1
  12. package/dist/GameOverScreen.d.ts.map +1 -1
  13. package/dist/GameResultScreen.d.ts +46 -0
  14. package/dist/GameResultScreen.d.ts.map +1 -0
  15. package/dist/GameResultScreen.js +157 -0
  16. package/dist/GameResultScreen.js.map +1 -0
  17. package/dist/GameTextSizeToggle.d.ts +1 -1
  18. package/dist/GameTextSizeToggle.d.ts.map +1 -1
  19. package/dist/GameThemeToggle.d.ts +1 -1
  20. package/dist/GameThemeToggle.d.ts.map +1 -1
  21. package/dist/GameThemeToggle.js +43 -7
  22. package/dist/GameThemeToggle.js.map +1 -1
  23. package/dist/GameTopbar.d.ts +19 -7
  24. package/dist/GameTopbar.d.ts.map +1 -1
  25. package/dist/GameTopbar.js +113 -168
  26. package/dist/GameTopbar.js.map +1 -1
  27. package/dist/GameTopbar.module.css +201 -0
  28. package/dist/StartScreen.d.ts +48 -0
  29. package/dist/StartScreen.d.ts.map +1 -0
  30. package/dist/StartScreen.js +159 -0
  31. package/dist/StartScreen.js.map +1 -0
  32. package/dist/feel/ScorePopup.d.ts +25 -0
  33. package/dist/feel/ScorePopup.d.ts.map +1 -0
  34. package/dist/feel/ScorePopup.js +67 -0
  35. package/dist/feel/ScorePopup.js.map +1 -0
  36. package/dist/feel/easing.d.ts +14 -0
  37. package/dist/feel/easing.d.ts.map +1 -0
  38. package/dist/feel/easing.js +12 -0
  39. package/dist/feel/easing.js.map +1 -0
  40. package/dist/feel/haptics.d.ts +19 -0
  41. package/dist/feel/haptics.d.ts.map +1 -0
  42. package/dist/feel/haptics.js +24 -0
  43. package/dist/feel/haptics.js.map +1 -0
  44. package/dist/feel/index.d.ts +17 -0
  45. package/dist/feel/index.d.ts.map +1 -0
  46. package/dist/feel/index.js +17 -0
  47. package/dist/feel/index.js.map +1 -0
  48. package/dist/feel/particles.d.ts +46 -0
  49. package/dist/feel/particles.d.ts.map +1 -0
  50. package/dist/feel/particles.js +61 -0
  51. package/dist/feel/particles.js.map +1 -0
  52. package/dist/feel/reducedMotion.d.ts +6 -0
  53. package/dist/feel/reducedMotion.d.ts.map +1 -0
  54. package/dist/feel/reducedMotion.js +10 -0
  55. package/dist/feel/reducedMotion.js.map +1 -0
  56. package/dist/feel/shake.d.ts +6 -0
  57. package/dist/feel/shake.d.ts.map +1 -0
  58. package/dist/feel/shake.js +17 -0
  59. package/dist/feel/shake.js.map +1 -0
  60. package/dist/feel/tween.d.ts +9 -0
  61. package/dist/feel/tween.d.ts.map +1 -0
  62. package/dist/feel/tween.js +15 -0
  63. package/dist/feel/tween.js.map +1 -0
  64. package/dist/feel/useHaptics.d.ts +12 -0
  65. package/dist/feel/useHaptics.d.ts.map +1 -0
  66. package/dist/feel/useHaptics.js +16 -0
  67. package/dist/feel/useHaptics.js.map +1 -0
  68. package/dist/feel/useParticles.d.ts +18 -0
  69. package/dist/feel/useParticles.d.ts.map +1 -0
  70. package/dist/feel/useParticles.js +79 -0
  71. package/dist/feel/useParticles.js.map +1 -0
  72. package/dist/feel/useShake.d.ts +14 -0
  73. package/dist/feel/useShake.d.ts.map +1 -0
  74. package/dist/feel/useShake.js +17 -0
  75. package/dist/feel/useShake.js.map +1 -0
  76. package/dist/index.d.ts +5 -2
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +14 -2
  79. package/dist/index.js.map +1 -1
  80. package/dist/tokens.d.ts +112 -0
  81. package/dist/tokens.d.ts.map +1 -0
  82. package/dist/tokens.js +106 -0
  83. package/dist/tokens.js.map +1 -0
  84. package/dist/useGameSounds.d.ts.map +1 -1
  85. package/dist/useGameSounds.js +37 -15
  86. package/dist/useGameSounds.js.map +1 -1
  87. package/dist/useLeaderboard.d.ts +8 -1
  88. package/dist/useLeaderboard.d.ts.map +1 -1
  89. package/dist/useLeaderboard.js +21 -11
  90. package/dist/useLeaderboard.js.map +1 -1
  91. package/package.json +21 -6
package/dist/tokens.js ADDED
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Brand, typography and motion design tokens for FreeGameStore games.
3
+ *
4
+ * These values are lifted from the Mosaic Rush pilot (`web/src/index.css`),
5
+ * which is the first game to be built on them. They are the single definition
6
+ * the SDK documents. See TOKENS.md for the full reference.
7
+ *
8
+ * The SDK components read these as CSS custom properties (`var(--paper)` and
9
+ * so on), with their own fallbacks. This module does not inject anything on
10
+ * import (the package is `sideEffects: false`). A game that wants the tokens
11
+ * adds GAME_TOKENS_CSS to its stylesheet, or copies it into index.css.
12
+ *
13
+ * Changing a value here changes every game that adopts the tokens, so treat
14
+ * it as a platform-wide decision.
15
+ */
16
+ /** Light theme. The default when `data-theme` is absent. */
17
+ export const LIGHT_COLOURS = {
18
+ paper: '#ffffff',
19
+ ink: '#1a1a1a',
20
+ muted: '#6b7280',
21
+ line: '#e5e7eb',
22
+ lineStrong: '#d1d5db',
23
+ panel: '#f9fafb',
24
+ glass: 'rgba(255, 255, 255, 0.8)',
25
+ dock: '#ffffff',
26
+ success: '#16a34a',
27
+ warning: '#d97706',
28
+ error: '#dc2626',
29
+ accent: '#2563eb',
30
+ accentSoft: '#eff6ff',
31
+ accentInk: '#2563eb',
32
+ };
33
+ /**
34
+ * Only the tokens that differ in dark mode. Applied under `:root[data-theme="dark"]`.
35
+ * `accent` is not listed: it is the same in both themes.
36
+ */
37
+ export const DARK_COLOUR_OVERRIDES = {
38
+ paper: '#0f0f0f',
39
+ ink: '#f5f5f5',
40
+ muted: '#9ca3af',
41
+ line: '#2d2d2d',
42
+ lineStrong: '#404040',
43
+ panel: '#1a1a1a',
44
+ glass: 'rgba(15, 15, 15, 0.8)',
45
+ dock: '#1a1a1a',
46
+ success: '#22c55e',
47
+ warning: '#fbbf24',
48
+ error: '#ef4444',
49
+ accentSoft: '#1a2e26',
50
+ accentInk: '#60a5fa',
51
+ };
52
+ /** Dark theme, resolved: the light values with the dark overrides applied. */
53
+ export const DARK_COLOURS = { ...LIGHT_COLOURS, ...DARK_COLOUR_OVERRIDES };
54
+ export const TYPOGRAPHY_TOKENS = {
55
+ fontDisplay: '"Fraunces", Georgia, serif',
56
+ fontBody: '"Manrope", system-ui, sans-serif',
57
+ textStat: '1.25rem',
58
+ textTitle: 'clamp(2rem, 9vw, 2.6rem)',
59
+ textDisplay: 'clamp(2.25rem, 11vw, 3.25rem)',
60
+ };
61
+ export const SHAPE_TOKENS = {
62
+ radius: '1.25rem',
63
+ };
64
+ export const MOTION_TOKENS = {
65
+ fast: '120ms',
66
+ base: '240ms',
67
+ slow: '420ms',
68
+ easeOut: 'cubic-bezier(0.2, 0.9, 0.3, 1)',
69
+ easeSpring: 'cubic-bezier(0.2, 0.9, 0.3, 1.3)',
70
+ duration: 'var(--motion-fast)',
71
+ easing: 'var(--motion-ease-out)',
72
+ };
73
+ /**
74
+ * Durations under `prefers-reduced-motion: reduce`. The animations finish at
75
+ * once and only the final state is shown. Easings are unchanged.
76
+ */
77
+ export const REDUCED_MOTION_DURATIONS = {
78
+ fast: '0ms',
79
+ base: '0ms',
80
+ slow: '0ms',
81
+ duration: '0ms',
82
+ };
83
+ const toKebab = (name) => name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
84
+ const declarations = (entries, prefix = '', indent = ' ') => Object.entries(entries)
85
+ .map(([key, value]) => `${indent}--${prefix}${toKebab(key)}: ${value};`)
86
+ .join('\n');
87
+ /**
88
+ * A stylesheet that defines every token. It has three blocks:
89
+ * - `:root`, the light values and the type, shape and motion tokens;
90
+ * - `:root[data-theme="dark"]`, the dark colour overrides;
91
+ * - `prefers-reduced-motion: reduce`, which zeroes the durations.
92
+ *
93
+ * Add it to a game's stylesheet, for example `<style>{GAME_TOKENS_CSS}</style>`
94
+ * or the top of `index.css`.
95
+ */
96
+ export const GAME_TOKENS_CSS = [
97
+ `:root {\n${[
98
+ declarations(LIGHT_COLOURS),
99
+ declarations(TYPOGRAPHY_TOKENS),
100
+ declarations(SHAPE_TOKENS),
101
+ declarations(MOTION_TOKENS, 'motion-'),
102
+ ].join('\n')}\n}`,
103
+ `:root[data-theme="dark"] {\n${declarations(DARK_COLOUR_OVERRIDES)}\n}`,
104
+ `@media (prefers-reduced-motion: reduce) {\n :root {\n${declarations(REDUCED_MOTION_DURATIONS, 'motion-', ' ')}\n }\n}`,
105
+ ].join('\n\n');
106
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAkCH,4DAA4D;AAC5D,MAAM,CAAC,MAAM,aAAa,GAAiB;IACzC,KAAK,EAAE,SAAS;IAChB,GAAG,EAAE,SAAS;IACd,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,SAAS;IACf,UAAU,EAAE,SAAS;IACrB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,0BAA0B;IACjC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;IACjB,UAAU,EAAE,SAAS;IACrB,SAAS,EAAE,SAAS;CACrB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAA0B;IAC1D,KAAK,EAAE,SAAS;IAChB,GAAG,EAAE,SAAS;IACd,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,SAAS;IACf,UAAU,EAAE,SAAS;IACrB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,uBAAuB;IAC9B,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,SAAS;IAChB,UAAU,EAAE,SAAS;IACrB,SAAS,EAAE,SAAS;CACrB,CAAC;AAEF,8EAA8E;AAC9E,MAAM,CAAC,MAAM,YAAY,GAAiB,EAAE,GAAG,aAAa,EAAE,GAAG,qBAAqB,EAAE,CAAC;AAgBzF,MAAM,CAAC,MAAM,iBAAiB,GAAqB;IACjD,WAAW,EAAE,4BAA4B;IACzC,QAAQ,EAAE,kCAAkC;IAC5C,QAAQ,EAAE,SAAS;IACnB,SAAS,EAAE,0BAA0B;IACrC,WAAW,EAAE,+BAA+B;CAC7C,CAAC;AAQF,MAAM,CAAC,MAAM,YAAY,GAAgB;IACvC,MAAM,EAAE,SAAS;CAClB,CAAC;AAuBF,MAAM,CAAC,MAAM,aAAa,GAAiB;IACzC,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,gCAAgC;IACzC,UAAU,EAAE,kCAAkC;IAC9C,QAAQ,EAAE,oBAAoB;IAC9B,MAAM,EAAE,wBAAwB;CACjC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAA8D;IACjG,IAAI,EAAE,KAAK;IACX,IAAI,EAAE,KAAK;IACX,IAAI,EAAE,KAAK;IACX,QAAQ,EAAE,KAAK;CAChB,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AAE/F,MAAM,YAAY,GAAG,CAAC,OAAe,EAAE,MAAM,GAAG,EAAE,EAAE,MAAM,GAAG,IAAI,EAAU,EAAE,CAC3E,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;KACpB,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,KAAK,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC;KACvE,IAAI,CAAC,IAAI,CAAC,CAAC;AAEhB;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,YAAY;QACV,YAAY,CAAC,aAAa,CAAC;QAC3B,YAAY,CAAC,iBAAiB,CAAC;QAC/B,YAAY,CAAC,YAAY,CAAC;QAC1B,YAAY,CAAC,aAAa,EAAE,SAAS,CAAC;KACvC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;IACjB,+BAA+B,YAAY,CAAC,qBAAqB,CAAC,KAAK;IACvE,yDAAyD,YAAY,CAAC,wBAAwB,EAAE,SAAS,EAAE,MAAM,CAAC,UAAU;CAC7H,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useGameSounds.d.ts","sourceRoot":"","sources":["../src/useGameSounds.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,aAAa;;;;;;;;;EAoH5B"}
1
+ {"version":3,"file":"useGameSounds.d.ts","sourceRoot":"","sources":["../src/useGameSounds.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,aAAa;;;;;;;;;EA6I5B"}
@@ -8,16 +8,30 @@ import { useSound } from './SoundContext.js';
8
8
  export function useGameSounds() {
9
9
  const { muted } = useSound();
10
10
  const ctxRef = useRef(null);
11
+ // Set once the game unmounts: no new AudioContext may be created after that.
12
+ const disposedRef = useRef(false);
13
+ // Delayed notes of multi-tone sounds (score, game over, level up, …).
14
+ const timersRef = useRef(new Set());
11
15
  // Release the AudioContext when the game unmounts so it isn't leaked
12
- // (browsers cap concurrent contexts).
16
+ // (browsers cap concurrent contexts). Pending delayed notes are cancelled
17
+ // first: one firing after unmount used to create a NEW context that nothing
18
+ // ever closed — one leak per game swapped out mid-sound, until browsers stop
19
+ // allowing new contexts and sound dies (#99). Reset on (re)mount so
20
+ // StrictMode's simulated remount doesn't leave sounds permanently disabled.
13
21
  useEffect(() => {
22
+ disposedRef.current = false;
23
+ const timers = timersRef.current;
14
24
  return () => {
15
- void ctxRef.current?.close();
25
+ disposedRef.current = true;
26
+ for (const t of timers)
27
+ clearTimeout(t);
28
+ timers.clear();
29
+ void ctxRef.current?.close().catch(() => { });
16
30
  ctxRef.current = null;
17
31
  };
18
32
  }, []);
19
33
  const getCtx = useCallback(() => {
20
- if (muted)
34
+ if (muted || disposedRef.current)
21
35
  return null;
22
36
  if (!ctxRef.current) {
23
37
  try {
@@ -59,6 +73,14 @@ export function useGameSounds() {
59
73
  osc.start(ctx.currentTime);
60
74
  osc.stop(ctx.currentTime + duration);
61
75
  }, [getCtx]);
76
+ /** Play a note after `ms`, cancelled if the game unmounts first. */
77
+ const later = useCallback((ms, ...args) => {
78
+ const timer = setTimeout(() => {
79
+ timersRef.current.delete(timer);
80
+ tone(...args);
81
+ }, ms);
82
+ timersRef.current.add(timer);
83
+ }, [tone]);
62
84
  /** Short click/tap — piece moved, card flipped, button pressed */
63
85
  const playMove = useCallback(() => {
64
86
  tone(600, 0.06, 'square', 0.08);
@@ -66,8 +88,8 @@ export function useGameSounds() {
66
88
  /** Positive ding — scored a point, matched, correct answer */
67
89
  const playScore = useCallback(() => {
68
90
  tone(880, 0.12, 'sine', 0.15);
69
- setTimeout(() => tone(1100, 0.15, 'sine', 0.12), 60);
70
- }, [tone]);
91
+ later(60, 1100, 0.15, 'sine', 0.12);
92
+ }, [tone, later]);
71
93
  /** Negative buzz — wrong answer, hit obstacle, lost life */
72
94
  const playError = useCallback(() => {
73
95
  tone(200, 0.2, 'sawtooth', 0.1);
@@ -75,16 +97,16 @@ export function useGameSounds() {
75
97
  /** Game over — descending tones */
76
98
  const playGameOver = useCallback(() => {
77
99
  tone(440, 0.15, 'sine', 0.12);
78
- setTimeout(() => tone(350, 0.15, 'sine', 0.1), 100);
79
- setTimeout(() => tone(260, 0.3, 'sine', 0.08), 200);
80
- }, [tone]);
100
+ later(100, 350, 0.15, 'sine', 0.1);
101
+ later(200, 260, 0.3, 'sine', 0.08);
102
+ }, [tone, later]);
81
103
  /** Level up / achievement — ascending arpeggio */
82
104
  const playLevelUp = useCallback(() => {
83
105
  tone(523, 0.1, 'sine', 0.12);
84
- setTimeout(() => tone(659, 0.1, 'sine', 0.12), 80);
85
- setTimeout(() => tone(784, 0.1, 'sine', 0.12), 160);
86
- setTimeout(() => tone(1047, 0.2, 'sine', 0.15), 240);
87
- }, [tone]);
106
+ later(80, 659, 0.1, 'sine', 0.12);
107
+ later(160, 784, 0.1, 'sine', 0.12);
108
+ later(240, 1047, 0.2, 'sine', 0.15);
109
+ }, [tone, later]);
88
110
  /** Hard drop / thud — Tetris block landing, bowling throw */
89
111
  const playDrop = useCallback(() => {
90
112
  tone(150, 0.12, 'triangle', 0.2);
@@ -92,9 +114,9 @@ export function useGameSounds() {
92
114
  /** Line clear / combo — satisfying sweep */
93
115
  const playClear = useCallback(() => {
94
116
  tone(700, 0.08, 'sine', 0.1);
95
- setTimeout(() => tone(900, 0.08, 'sine', 0.1), 50);
96
- setTimeout(() => tone(1200, 0.12, 'sine', 0.12), 100);
97
- }, [tone]);
117
+ later(50, 900, 0.08, 'sine', 0.1);
118
+ later(100, 1200, 0.12, 'sine', 0.12);
119
+ }, [tone, later]);
98
120
  /** Countdown tick — timer warning */
99
121
  const playTick = useCallback(() => {
100
122
  tone(1000, 0.03, 'square', 0.06);
@@ -1 +1 @@
1
- {"version":3,"file":"useGameSounds.js","sourceRoot":"","sources":["../src/useGameSounds.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useGameSounds.js","sourceRoot":"","sources":["../src/useGameSounds.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,14 @@ export interface LeaderboardEntry {
5
5
  avatar_url?: string;
6
6
  created_at: string;
7
7
  }
8
- export declare function useLeaderboard(gameId: string): {
8
+ export interface UseLeaderboardOptions {
9
+ /**
10
+ * A day key (YYYY-MM-DD, UTC) for a per-day board, such as a daily puzzle.
11
+ * Omit it for the all-time board.
12
+ */
13
+ period?: string;
14
+ }
15
+ export declare function useLeaderboard(gameId: string, options?: UseLeaderboardOptions): {
9
16
  topScores: LeaderboardEntry[];
10
17
  recentScores: LeaderboardEntry[];
11
18
  submitScore: (score: number) => Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"useLeaderboard.d.ts","sourceRoot":"","sources":["../src/useLeaderboard.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAoBD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAC9C,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAiFA"}
1
+ {"version":3,"file":"useLeaderboard.d.ts","sourceRoot":"","sources":["../src/useLeaderboard.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAoBD,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,qBAA0B,GAClC;IACD,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CA2FA"}
@@ -3,7 +3,10 @@ import { useCallback, useEffect, useRef, useState } from 'react';
3
3
  // The worker also serves the unversioned paths, so games built against older
4
4
  // SDK releases keep working.
5
5
  const API_BASE = 'https://leaderboard.freegamestore.online/v1';
6
- export function useLeaderboard(gameId) {
6
+ const AUTH_BASE = 'https://auth.freegamestore.online/v1';
7
+ export function useLeaderboard(gameId, options = {}) {
8
+ const period = options.period;
9
+ const periodQuery = period ? `&period=${encodeURIComponent(period)}` : '';
7
10
  const [topScores, setTopScores] = useState([]);
8
11
  const [recentScores, setRecentScores] = useState([]);
9
12
  const [loading, setLoading] = useState(true);
@@ -24,7 +27,9 @@ export function useLeaderboard(gameId) {
24
27
  // Fire-and-forget: inner fetches each .catch() to [], so this never
25
28
  // rejects; `void` marks the intentional non-await.
26
29
  void Promise.all([
27
- fetch(`${API_BASE}/api/leaderboard/${gameId}?limit=50`, { credentials: 'include' })
30
+ fetch(`${API_BASE}/api/leaderboard/${gameId}?limit=50${periodQuery}`, {
31
+ credentials: 'include',
32
+ })
28
33
  .then(async (r) => {
29
34
  if (!r.ok)
30
35
  return [];
@@ -32,7 +37,7 @@ export function useLeaderboard(gameId) {
32
37
  return data.scores ?? [];
33
38
  })
34
39
  .catch(() => []),
35
- fetch(`${API_BASE}/api/leaderboard/${gameId}/recent?limit=50`, {
40
+ fetch(`${API_BASE}/api/leaderboard/${gameId}/recent?limit=50${periodQuery}`, {
36
41
  credentials: 'include',
37
42
  })
38
43
  .then(async (r) => {
@@ -50,20 +55,25 @@ export function useLeaderboard(gameId) {
50
55
  setRecentScores(recent);
51
56
  setLoading(false);
52
57
  });
53
- }, [gameId]);
58
+ }, [gameId, periodQuery]);
54
59
  useEffect(() => {
55
60
  load();
56
61
  }, [load]);
57
62
  const submitScore = useCallback(async (score) => {
58
63
  try {
59
- // The Worker wants `{ game, score }`. Submitting requires auth: the
60
- // player name comes from the cookie JWT, and an unauthenticated post
61
- // is rejected with 401 (handled by the `!res.ok` check below).
64
+ // Exchange the auth-origin cookie for a five-minute bearer token bound
65
+ // to THIS game. Untrusted game JS never receives a store-wide session,
66
+ // and leaderboard rejects the token for every other game id.
67
+ const handoffRes = await fetch(`${AUTH_BASE}/handoff/issue?target=${encodeURIComponent('https://leaderboard.freegamestore.online')}&game=${encodeURIComponent(gameId)}`, { method: 'POST', credentials: 'include' });
68
+ if (!handoffRes.ok)
69
+ return { ok: false };
70
+ const handoff = (await handoffRes.json());
71
+ if (!handoff.token)
72
+ return { ok: false };
62
73
  const res = await fetch(`${API_BASE}/api/scores`, {
63
74
  method: 'POST',
64
- credentials: 'include',
65
- headers: { 'Content-Type': 'application/json' },
66
- body: JSON.stringify({ game: gameId, score }),
75
+ headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${handoff.token}` },
76
+ body: JSON.stringify(period ? { game: gameId, score, period } : { game: gameId, score }),
67
77
  });
68
78
  if (!res.ok)
69
79
  return { ok: false };
@@ -78,7 +88,7 @@ export function useLeaderboard(gameId) {
78
88
  catch {
79
89
  return { ok: false };
80
90
  }
81
- }, [gameId, load]);
91
+ }, [gameId, period, load]);
82
92
  return { topScores, recentScores, submitScore, loading, refresh: load };
83
93
  }
84
94
  //# sourceMappingURL=useLeaderboard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLeaderboard.js","sourceRoot":"","sources":["../src/useLeaderboard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useLeaderboard.js","sourceRoot":"","sources":["../src/useLeaderboard.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freegamestore/games",
3
- "version": "0.15.1",
3
+ "version": "0.18.0",
4
4
  "description": "Shared React UI primitives for games on FreeGameStore — GameShell, GameTopbar, etc. Brand-consistent, scroll-free.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -10,6 +10,10 @@
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js"
13
+ },
14
+ "./feel": {
15
+ "types": "./dist/feel/index.d.ts",
16
+ "import": "./dist/feel/index.js"
13
17
  }
14
18
  },
15
19
  "homepage": "https://github.com/freegamestore-online/platform#readme",
@@ -31,7 +35,8 @@
31
35
  ],
32
36
  "files": [
33
37
  "dist",
34
- "README.md"
38
+ "README.md",
39
+ "TOKENS.md"
35
40
  ],
36
41
  "engines": {
37
42
  "node": ">=22"
@@ -40,13 +45,23 @@
40
45
  "react": "^19.0.0"
41
46
  },
42
47
  "devDependencies": {
48
+ "@testing-library/dom": "^10.4.1",
49
+ "@testing-library/jest-dom": "^6.6.3",
50
+ "@testing-library/react": "^16.3.0",
43
51
  "@types/react": "^19.2.14",
44
- "react": "^19.2.5",
45
- "typescript": "^5.7.0"
52
+ "@types/react-dom": "^19.2.3",
53
+ "@vitejs/plugin-react": "^5.2.0",
54
+ "jsdom": "^26",
55
+ "react": "19.2.6",
56
+ "react-dom": "19.2.6",
57
+ "typescript": "^5.7.0",
58
+ "vite": "^6",
59
+ "vitest": "^2.1.0"
46
60
  },
47
61
  "sideEffects": false,
48
62
  "scripts": {
49
- "build": "tsc",
50
- "typecheck": "tsc --noEmit"
63
+ "build": "tsc && cp src/GameTopbar.module.css dist/",
64
+ "typecheck": "tsc --noEmit",
65
+ "test": "vitest run"
51
66
  }
52
67
  }