@dubsdotapp/expo 0.3.0 → 0.3.2
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.d.mts +1 -62
- package/dist/index.d.ts +1 -62
- package/dist/index.js +302 -627
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +319 -654
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +72 -26
- package/src/hooks/index.ts +6 -0
- package/src/hooks/useArcadeGame.ts +102 -0
- package/src/hooks/useArcadePool.ts +44 -0
- package/src/hooks/useArcadePools.ts +34 -0
- package/src/index.ts +15 -5
- package/src/types.ts +62 -45
- package/src/ui/index.ts +0 -2
- package/src/ui/DeveloperDashboardSheet.tsx +0 -353
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -37,8 +37,12 @@ import type {
|
|
|
37
37
|
UiConfig,
|
|
38
38
|
UFCEvent,
|
|
39
39
|
UFCFighterDetail,
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
ArcadePool,
|
|
41
|
+
ArcadeEntry,
|
|
42
|
+
ArcadeLeaderboardEntry,
|
|
43
|
+
ArcadePoolStats,
|
|
44
|
+
StartAttemptResult,
|
|
45
|
+
SubmitScoreResult,
|
|
42
46
|
} from './types';
|
|
43
47
|
|
|
44
48
|
export interface DubsClientConfig {
|
|
@@ -473,43 +477,85 @@ export class DubsClient {
|
|
|
473
477
|
return { ...SOLANA_PROGRAM_ERRORS };
|
|
474
478
|
}
|
|
475
479
|
|
|
476
|
-
// ──
|
|
480
|
+
// ── Arcade Pools ──
|
|
477
481
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
482
|
+
async getArcadePools(params?: { gameSlug?: string; status?: string }): Promise<ArcadePool[]> {
|
|
483
|
+
const qs = new URLSearchParams();
|
|
484
|
+
if (params?.gameSlug) qs.set('gameSlug', params.gameSlug);
|
|
485
|
+
if (params?.status) qs.set('status', params.status);
|
|
486
|
+
const query = qs.toString();
|
|
487
|
+
const res = await this.request<{ success: true; pools: ArcadePool[] }>(
|
|
488
|
+
'GET',
|
|
489
|
+
`/arcade/pools${query ? `?${query}` : ''}`,
|
|
490
|
+
);
|
|
491
|
+
return res.pools;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
async getArcadePool(poolId: number): Promise<{ pool: ArcadePool; stats: ArcadePoolStats }> {
|
|
495
|
+
const res = await this.request<{ success: true; pool: ArcadePool; stats: ArcadePoolStats }>(
|
|
496
|
+
'GET',
|
|
497
|
+
`/arcade/pools/${poolId}`,
|
|
498
|
+
);
|
|
499
|
+
return { pool: res.pool, stats: res.stats };
|
|
486
500
|
}
|
|
487
501
|
|
|
488
|
-
|
|
502
|
+
async enterArcadePool(poolId: number, params: { walletAddress: string; txSignature: string }): Promise<ArcadeEntry> {
|
|
503
|
+
const res = await this.request<{ success: true; entry: ArcadeEntry }>(
|
|
504
|
+
'POST',
|
|
505
|
+
`/arcade/pools/${poolId}/enter`,
|
|
506
|
+
params,
|
|
507
|
+
);
|
|
508
|
+
return res.entry;
|
|
509
|
+
}
|
|
489
510
|
|
|
490
|
-
|
|
491
|
-
|
|
511
|
+
async startArcadeAttempt(poolId: number, walletAddress: string): Promise<StartAttemptResult> {
|
|
512
|
+
const res = await this.request<{ success: true } & StartAttemptResult>(
|
|
513
|
+
'POST',
|
|
514
|
+
`/arcade/pools/${poolId}/start-attempt`,
|
|
515
|
+
{ walletAddress },
|
|
516
|
+
);
|
|
517
|
+
return { sessionToken: res.sessionToken, attemptNumber: res.attemptNumber, livesRemaining: res.livesRemaining };
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
async submitArcadeScore(poolId: number, params: { walletAddress: string; sessionToken: string; score: number; durationMs?: number }): Promise<SubmitScoreResult> {
|
|
521
|
+
const res = await this.request<{ success: true } & SubmitScoreResult>(
|
|
522
|
+
'POST',
|
|
523
|
+
`/arcade/pools/${poolId}/submit-score`,
|
|
524
|
+
params,
|
|
525
|
+
);
|
|
526
|
+
return { score: res.score, bestScore: res.bestScore, livesUsed: res.livesUsed, isNewBest: res.isNewBest };
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
async getArcadeLeaderboard(poolId: number, params?: { limit?: number; offset?: number }): Promise<ArcadeLeaderboardEntry[]> {
|
|
492
530
|
const qs = new URLSearchParams();
|
|
493
531
|
if (params?.limit != null) qs.set('limit', String(params.limit));
|
|
494
532
|
if (params?.offset != null) qs.set('offset', String(params.offset));
|
|
495
533
|
const query = qs.toString();
|
|
496
|
-
const res = await this.request<{ success: true
|
|
534
|
+
const res = await this.request<{ success: true; leaderboard: ArcadeLeaderboardEntry[] }>(
|
|
497
535
|
'GET',
|
|
498
|
-
`/
|
|
536
|
+
`/arcade/pools/${poolId}/leaderboard${query ? `?${query}` : ''}`,
|
|
499
537
|
);
|
|
500
|
-
return
|
|
501
|
-
commissions: res.commissions,
|
|
502
|
-
summary: res.summary,
|
|
503
|
-
pagination: res.pagination,
|
|
504
|
-
};
|
|
538
|
+
return res.leaderboard;
|
|
505
539
|
}
|
|
506
540
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
const res = await this.request<{ success: true; summary: DeveloperCommissionsSummary }>(
|
|
541
|
+
async getArcadeEntry(poolId: number, walletAddress: string): Promise<ArcadeEntry> {
|
|
542
|
+
const res = await this.request<{ success: true; entry: ArcadeEntry }>(
|
|
510
543
|
'GET',
|
|
511
|
-
|
|
544
|
+
`/arcade/pools/${poolId}/my-entry?walletAddress=${encodeURIComponent(walletAddress)}`,
|
|
512
545
|
);
|
|
513
|
-
return res.
|
|
546
|
+
return res.entry;
|
|
514
547
|
}
|
|
548
|
+
|
|
549
|
+
// ── App Config ──
|
|
550
|
+
|
|
551
|
+
/** Fetch the app's UI customization config (accent color, icon, tagline, environment) */
|
|
552
|
+
async getAppConfig(): Promise<UiConfig> {
|
|
553
|
+
const res = await this.request<{ data: { environment?: string; uiConfig: UiConfig } }>('GET', '/apps/config');
|
|
554
|
+
const config = res.data?.uiConfig || {};
|
|
555
|
+
if (res.data?.environment) {
|
|
556
|
+
config.environment = res.data.environment as UiConfig['environment'];
|
|
557
|
+
}
|
|
558
|
+
return config;
|
|
559
|
+
}
|
|
560
|
+
|
|
515
561
|
}
|
package/src/hooks/index.ts
CHANGED
|
@@ -18,3 +18,9 @@ export { useUFCFightCard } from './useUFCFightCard';
|
|
|
18
18
|
export { useUFCFighterDetail } from './useUFCFighterDetail';
|
|
19
19
|
export { usePushNotifications } from './usePushNotifications';
|
|
20
20
|
export type { PushNotificationStatus } from './usePushNotifications';
|
|
21
|
+
export { useArcadePools } from './useArcadePools';
|
|
22
|
+
export type { UseArcadePoolsResult } from './useArcadePools';
|
|
23
|
+
export { useArcadePool } from './useArcadePool';
|
|
24
|
+
export type { UseArcadePoolResult } from './useArcadePool';
|
|
25
|
+
export { useArcadeGame } from './useArcadeGame';
|
|
26
|
+
export type { UseArcadeGameResult } from './useArcadeGame';
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { useState, useCallback } from 'react';
|
|
2
|
+
import { useDubs } from '../provider';
|
|
3
|
+
import { useAuth } from './useAuth';
|
|
4
|
+
import type { ArcadeEntry, StartAttemptResult, SubmitScoreResult } from '../types';
|
|
5
|
+
|
|
6
|
+
export interface UseArcadeGameResult {
|
|
7
|
+
entry: ArcadeEntry | null;
|
|
8
|
+
livesRemaining: number;
|
|
9
|
+
bestScore: number;
|
|
10
|
+
loading: boolean;
|
|
11
|
+
error: Error | null;
|
|
12
|
+
/** Fetch/refresh the user's entry for this pool */
|
|
13
|
+
refreshEntry: () => Promise<void>;
|
|
14
|
+
/** Start a new life — returns session token to pass to the game */
|
|
15
|
+
startAttempt: () => Promise<StartAttemptResult>;
|
|
16
|
+
/** Submit score after game over */
|
|
17
|
+
submitScore: (sessionToken: string, score: number, durationMs?: number) => Promise<SubmitScoreResult>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function useArcadeGame(poolId: number | null, maxLives: number = 3): UseArcadeGameResult {
|
|
21
|
+
const { client } = useDubs();
|
|
22
|
+
const { user } = useAuth();
|
|
23
|
+
const [entry, setEntry] = useState<ArcadeEntry | null>(null);
|
|
24
|
+
const [loading, setLoading] = useState(false);
|
|
25
|
+
const [error, setError] = useState<Error | null>(null);
|
|
26
|
+
|
|
27
|
+
const walletAddress = user?.walletAddress || '';
|
|
28
|
+
|
|
29
|
+
const refreshEntry = useCallback(async () => {
|
|
30
|
+
if (!poolId || !walletAddress) return;
|
|
31
|
+
setLoading(true);
|
|
32
|
+
setError(null);
|
|
33
|
+
try {
|
|
34
|
+
const e = await client.getArcadeEntry(poolId, walletAddress);
|
|
35
|
+
setEntry(e);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
// 404 means no entry yet — that's fine
|
|
38
|
+
if (err instanceof Error && err.message.includes('No entry found')) {
|
|
39
|
+
setEntry(null);
|
|
40
|
+
} else {
|
|
41
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
42
|
+
}
|
|
43
|
+
} finally {
|
|
44
|
+
setLoading(false);
|
|
45
|
+
}
|
|
46
|
+
}, [client, poolId, walletAddress]);
|
|
47
|
+
|
|
48
|
+
const startAttempt = useCallback(async (): Promise<StartAttemptResult> => {
|
|
49
|
+
if (!poolId || !walletAddress) throw new Error('Not ready');
|
|
50
|
+
setError(null);
|
|
51
|
+
try {
|
|
52
|
+
const result = await client.startArcadeAttempt(poolId, walletAddress);
|
|
53
|
+
return result;
|
|
54
|
+
} catch (err) {
|
|
55
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
56
|
+
setError(e);
|
|
57
|
+
throw e;
|
|
58
|
+
}
|
|
59
|
+
}, [client, poolId, walletAddress]);
|
|
60
|
+
|
|
61
|
+
const submitScore = useCallback(async (
|
|
62
|
+
sessionToken: string,
|
|
63
|
+
score: number,
|
|
64
|
+
durationMs?: number,
|
|
65
|
+
): Promise<SubmitScoreResult> => {
|
|
66
|
+
if (!poolId || !walletAddress) throw new Error('Not ready');
|
|
67
|
+
setError(null);
|
|
68
|
+
try {
|
|
69
|
+
const result = await client.submitArcadeScore(poolId, {
|
|
70
|
+
walletAddress,
|
|
71
|
+
sessionToken,
|
|
72
|
+
score,
|
|
73
|
+
durationMs,
|
|
74
|
+
});
|
|
75
|
+
// Update local entry state
|
|
76
|
+
setEntry(prev => prev ? {
|
|
77
|
+
...prev,
|
|
78
|
+
best_score: result.bestScore,
|
|
79
|
+
lives_used: result.livesUsed,
|
|
80
|
+
} : prev);
|
|
81
|
+
return result;
|
|
82
|
+
} catch (err) {
|
|
83
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
84
|
+
setError(e);
|
|
85
|
+
throw e;
|
|
86
|
+
}
|
|
87
|
+
}, [client, poolId, walletAddress]);
|
|
88
|
+
|
|
89
|
+
const livesRemaining = entry ? maxLives - entry.lives_used : maxLives;
|
|
90
|
+
const bestScore = entry?.best_score || 0;
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
entry,
|
|
94
|
+
livesRemaining,
|
|
95
|
+
bestScore,
|
|
96
|
+
loading,
|
|
97
|
+
error,
|
|
98
|
+
refreshEntry,
|
|
99
|
+
startAttempt,
|
|
100
|
+
submitScore,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
2
|
+
import { useDubs } from '../provider';
|
|
3
|
+
import type { ArcadePool, ArcadePoolStats, ArcadeLeaderboardEntry } from '../types';
|
|
4
|
+
|
|
5
|
+
export interface UseArcadePoolResult {
|
|
6
|
+
pool: ArcadePool | null;
|
|
7
|
+
stats: ArcadePoolStats | null;
|
|
8
|
+
leaderboard: ArcadeLeaderboardEntry[];
|
|
9
|
+
loading: boolean;
|
|
10
|
+
error: Error | null;
|
|
11
|
+
refetch: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function useArcadePool(poolId: number | null): UseArcadePoolResult {
|
|
15
|
+
const { client } = useDubs();
|
|
16
|
+
const [pool, setPool] = useState<ArcadePool | null>(null);
|
|
17
|
+
const [stats, setStats] = useState<ArcadePoolStats | null>(null);
|
|
18
|
+
const [leaderboard, setLeaderboard] = useState<ArcadeLeaderboardEntry[]>([]);
|
|
19
|
+
const [loading, setLoading] = useState(false);
|
|
20
|
+
const [error, setError] = useState<Error | null>(null);
|
|
21
|
+
|
|
22
|
+
const fetch = useCallback(async () => {
|
|
23
|
+
if (!poolId) return;
|
|
24
|
+
setLoading(true);
|
|
25
|
+
setError(null);
|
|
26
|
+
try {
|
|
27
|
+
const [poolRes, lb] = await Promise.all([
|
|
28
|
+
client.getArcadePool(poolId),
|
|
29
|
+
client.getArcadeLeaderboard(poolId),
|
|
30
|
+
]);
|
|
31
|
+
setPool(poolRes.pool);
|
|
32
|
+
setStats(poolRes.stats);
|
|
33
|
+
setLeaderboard(lb);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
36
|
+
} finally {
|
|
37
|
+
setLoading(false);
|
|
38
|
+
}
|
|
39
|
+
}, [client, poolId]);
|
|
40
|
+
|
|
41
|
+
useEffect(() => { fetch(); }, [fetch]);
|
|
42
|
+
|
|
43
|
+
return { pool, stats, leaderboard, loading, error, refetch: fetch };
|
|
44
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import { useDubs } from '../provider';
|
|
3
|
+
import type { ArcadePool } from '../types';
|
|
4
|
+
|
|
5
|
+
export interface UseArcadePoolsResult {
|
|
6
|
+
pools: ArcadePool[];
|
|
7
|
+
loading: boolean;
|
|
8
|
+
error: Error | null;
|
|
9
|
+
refetch: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function useArcadePools(gameSlug?: string): UseArcadePoolsResult {
|
|
13
|
+
const { client } = useDubs();
|
|
14
|
+
const [pools, setPools] = useState<ArcadePool[]>([]);
|
|
15
|
+
const [loading, setLoading] = useState(false);
|
|
16
|
+
const [error, setError] = useState<Error | null>(null);
|
|
17
|
+
|
|
18
|
+
const fetch = useCallback(async () => {
|
|
19
|
+
setLoading(true);
|
|
20
|
+
setError(null);
|
|
21
|
+
try {
|
|
22
|
+
const result = await client.getArcadePools({ gameSlug });
|
|
23
|
+
setPools(result);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
26
|
+
} finally {
|
|
27
|
+
setLoading(false);
|
|
28
|
+
}
|
|
29
|
+
}, [client, gameSlug]);
|
|
30
|
+
|
|
31
|
+
useEffect(() => { fetch(); }, [fetch]);
|
|
32
|
+
|
|
33
|
+
return { pools, loading, error, refetch: fetch };
|
|
34
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -67,9 +67,13 @@ export type {
|
|
|
67
67
|
UFCData,
|
|
68
68
|
UFCFight,
|
|
69
69
|
UFCEvent,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
ArcadePool,
|
|
71
|
+
ArcadeEntry,
|
|
72
|
+
ArcadeAttempt,
|
|
73
|
+
ArcadeLeaderboardEntry,
|
|
74
|
+
ArcadePoolStats,
|
|
75
|
+
StartAttemptResult,
|
|
76
|
+
SubmitScoreResult,
|
|
73
77
|
} from './types';
|
|
74
78
|
|
|
75
79
|
// Provider
|
|
@@ -98,6 +102,9 @@ export {
|
|
|
98
102
|
useUFCFightCard,
|
|
99
103
|
useUFCFighterDetail,
|
|
100
104
|
usePushNotifications,
|
|
105
|
+
useArcadePools,
|
|
106
|
+
useArcadePool,
|
|
107
|
+
useArcadeGame,
|
|
101
108
|
} from './hooks';
|
|
102
109
|
export type {
|
|
103
110
|
CreateGameMutationResult,
|
|
@@ -107,11 +114,14 @@ export type {
|
|
|
107
114
|
ClaimStatus,
|
|
108
115
|
UseAuthResult,
|
|
109
116
|
PushNotificationStatus,
|
|
117
|
+
UseArcadePoolsResult,
|
|
118
|
+
UseArcadePoolResult,
|
|
119
|
+
UseArcadeGameResult,
|
|
110
120
|
} from './hooks';
|
|
111
121
|
|
|
112
122
|
// UI
|
|
113
|
-
export { AuthGate, ConnectWalletScreen, UserProfileCard, SettingsSheet, UserProfileSheet,
|
|
114
|
-
export type { AuthGateProps, RegistrationScreenProps, ConnectWalletScreenProps, UserProfileCardProps, SettingsSheetProps, UserProfileSheetProps,
|
|
123
|
+
export { AuthGate, ConnectWalletScreen, UserProfileCard, SettingsSheet, UserProfileSheet, useDubsTheme, mergeTheme } from './ui';
|
|
124
|
+
export type { AuthGateProps, RegistrationScreenProps, ConnectWalletScreenProps, UserProfileCardProps, SettingsSheetProps, UserProfileSheetProps, DubsTheme } from './ui';
|
|
115
125
|
|
|
116
126
|
// Game widgets
|
|
117
127
|
export { GamePoster, LivePoolsCard, PickWinnerCard, PlayersCard, JoinGameButton, CreateCustomGameSheet, JoinGameSheet, ClaimPrizeSheet, ClaimButton } from './ui';
|
package/src/types.ts
CHANGED
|
@@ -481,57 +481,74 @@ export interface UFCEvent {
|
|
|
481
481
|
fights: UFCFight[];
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
-
// ──
|
|
484
|
+
// ── Arcade Pools ──
|
|
485
485
|
|
|
486
|
-
export interface
|
|
486
|
+
export interface ArcadePool {
|
|
487
487
|
id: number;
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
488
|
+
app_id: number;
|
|
489
|
+
game_slug: string;
|
|
490
|
+
name: string;
|
|
491
|
+
buy_in_lamports: number;
|
|
492
|
+
max_lives: number;
|
|
493
|
+
period_start: string;
|
|
494
|
+
period_end: string;
|
|
495
|
+
schedule: 'weekly' | 'daily' | 'manual';
|
|
496
|
+
status: 'open' | 'active' | 'resolving' | 'complete' | 'cancelled';
|
|
497
|
+
solana_game_id: string | null;
|
|
498
|
+
solana_game_address: string | null;
|
|
499
|
+
total_entries: number;
|
|
500
|
+
created_at: string;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
export interface ArcadeEntry {
|
|
504
|
+
id: number;
|
|
505
|
+
pool_id: number;
|
|
506
|
+
wallet_address: string;
|
|
507
|
+
best_score: number;
|
|
508
|
+
lives_used: number;
|
|
509
|
+
rank: number | null;
|
|
510
|
+
created_at: string;
|
|
511
|
+
attempts: ArcadeAttempt[] | null;
|
|
504
512
|
}
|
|
505
513
|
|
|
506
|
-
export interface
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
last7Days?: {
|
|
515
|
-
games: number;
|
|
516
|
-
earned: number;
|
|
517
|
-
earnedSol: number;
|
|
518
|
-
};
|
|
519
|
-
last30Days?: {
|
|
520
|
-
games: number;
|
|
521
|
-
earned: number;
|
|
522
|
-
earnedSol: number;
|
|
523
|
-
};
|
|
524
|
-
commissionWallet?: string;
|
|
514
|
+
export interface ArcadeAttempt {
|
|
515
|
+
id: number;
|
|
516
|
+
attempt_number: number;
|
|
517
|
+
score: number | null;
|
|
518
|
+
status: 'active' | 'submitted' | 'expired';
|
|
519
|
+
started_at: string;
|
|
520
|
+
submitted_at: string | null;
|
|
521
|
+
duration_ms: number | null;
|
|
525
522
|
}
|
|
526
523
|
|
|
527
|
-
export interface
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
524
|
+
export interface ArcadeLeaderboardEntry {
|
|
525
|
+
id: number;
|
|
526
|
+
wallet_address: string;
|
|
527
|
+
best_score: number;
|
|
528
|
+
lives_used: number;
|
|
529
|
+
username: string;
|
|
530
|
+
avatar: string | null;
|
|
531
|
+
rank: number;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
export interface ArcadePoolStats {
|
|
535
|
+
total_entries: number;
|
|
536
|
+
top_score: number;
|
|
537
|
+
avg_score: number;
|
|
538
|
+
active_players: number;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
export interface StartAttemptResult {
|
|
542
|
+
sessionToken: string;
|
|
543
|
+
attemptNumber: number;
|
|
544
|
+
livesRemaining: number;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export interface SubmitScoreResult {
|
|
548
|
+
score: number;
|
|
549
|
+
bestScore: number;
|
|
550
|
+
livesUsed: number;
|
|
551
|
+
isNewBest: boolean;
|
|
535
552
|
}
|
|
536
553
|
|
|
537
554
|
// ── UI Config (developer branding) ──
|
package/src/ui/index.ts
CHANGED
|
@@ -8,8 +8,6 @@ export { SettingsSheet } from './SettingsSheet';
|
|
|
8
8
|
export type { SettingsSheetProps } from './SettingsSheet';
|
|
9
9
|
export { UserProfileSheet } from './UserProfileSheet';
|
|
10
10
|
export type { UserProfileSheetProps } from './UserProfileSheet';
|
|
11
|
-
export { DeveloperDashboardSheet } from './DeveloperDashboardSheet';
|
|
12
|
-
export type { DeveloperDashboardSheetProps } from './DeveloperDashboardSheet';
|
|
13
11
|
export { useDubsTheme, mergeTheme } from './theme';
|
|
14
12
|
export type { DubsTheme } from './theme';
|
|
15
13
|
|