@dubsdotapp/expo 0.3.2 → 0.3.3

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.mjs CHANGED
@@ -510,6 +510,67 @@ var DubsClient = class {
510
510
  getErrorCodesLocal() {
511
511
  return { ...SOLANA_PROGRAM_ERRORS };
512
512
  }
513
+ // ── Arcade Pools ──
514
+ async getArcadePools(params) {
515
+ const qs = new URLSearchParams();
516
+ if (params?.gameSlug) qs.set("gameSlug", params.gameSlug);
517
+ if (params?.status) qs.set("status", params.status);
518
+ const query = qs.toString();
519
+ const res = await this.request(
520
+ "GET",
521
+ `/arcade/pools${query ? `?${query}` : ""}`
522
+ );
523
+ return res.pools;
524
+ }
525
+ async getArcadePool(poolId) {
526
+ const res = await this.request(
527
+ "GET",
528
+ `/arcade/pools/${poolId}`
529
+ );
530
+ return { pool: res.pool, stats: res.stats };
531
+ }
532
+ async enterArcadePool(poolId, params) {
533
+ const res = await this.request(
534
+ "POST",
535
+ `/arcade/pools/${poolId}/enter`,
536
+ params
537
+ );
538
+ return res.entry;
539
+ }
540
+ async startArcadeAttempt(poolId, walletAddress) {
541
+ const res = await this.request(
542
+ "POST",
543
+ `/arcade/pools/${poolId}/start-attempt`,
544
+ { walletAddress }
545
+ );
546
+ return { sessionToken: res.sessionToken, attemptNumber: res.attemptNumber, livesRemaining: res.livesRemaining };
547
+ }
548
+ async submitArcadeScore(poolId, params) {
549
+ const res = await this.request(
550
+ "POST",
551
+ `/arcade/pools/${poolId}/submit-score`,
552
+ params
553
+ );
554
+ return { score: res.score, bestScore: res.bestScore, livesUsed: res.livesUsed, isNewBest: res.isNewBest };
555
+ }
556
+ async getArcadeLeaderboard(poolId, params) {
557
+ const qs = new URLSearchParams();
558
+ if (params?.limit != null) qs.set("limit", String(params.limit));
559
+ if (params?.offset != null) qs.set("offset", String(params.offset));
560
+ const query = qs.toString();
561
+ const res = await this.request(
562
+ "GET",
563
+ `/arcade/pools/${poolId}/leaderboard${query ? `?${query}` : ""}`
564
+ );
565
+ return res.leaderboard;
566
+ }
567
+ async getArcadeEntry(poolId, walletAddress) {
568
+ const res = await this.request(
569
+ "GET",
570
+ `/arcade/pools/${poolId}/my-entry?walletAddress=${encodeURIComponent(walletAddress)}`
571
+ );
572
+ return res.entry;
573
+ }
513
574
  // ── App Config ──
514
575
  /** Fetch the app's UI customization config (accent color, icon, tagline, environment) */
515
576
  async getAppConfig() {
@@ -561,7 +622,7 @@ function createSecureStoreStorage() {
561
622
  }
562
623
 
563
624
  // src/provider.tsx
564
- import { createContext as createContext4, useContext as useContext4, useMemo as useMemo2, useCallback as useCallback15, useState as useState16, useEffect as useEffect11 } from "react";
625
+ import { createContext as createContext4, useContext as useContext4, useMemo as useMemo3, useCallback as useCallback18, useState as useState19, useEffect as useEffect13 } from "react";
565
626
 
566
627
  // src/ui/theme.ts
567
628
  import { createContext, useContext } from "react";
@@ -1626,7 +1687,7 @@ function ManagedWalletProvider({
1626
1687
  }
1627
1688
 
1628
1689
  // src/ui/AuthGate.tsx
1629
- import React2, { useState as useState15, useEffect as useEffect10, useRef as useRef4, useCallback as useCallback14 } from "react";
1690
+ import React2, { useState as useState18, useEffect as useEffect12, useRef as useRef4, useCallback as useCallback17 } from "react";
1630
1691
  import {
1631
1692
  View as View3,
1632
1693
  Text as Text3,
@@ -2471,6 +2532,138 @@ function usePushNotifications() {
2471
2532
  };
2472
2533
  }
2473
2534
 
2535
+ // src/hooks/useArcadePools.ts
2536
+ import { useState as useState15, useEffect as useEffect10, useCallback as useCallback14 } from "react";
2537
+ function useArcadePools(gameSlug) {
2538
+ const { client } = useDubs();
2539
+ const [pools, setPools] = useState15([]);
2540
+ const [loading, setLoading] = useState15(false);
2541
+ const [error, setError] = useState15(null);
2542
+ const fetch2 = useCallback14(async () => {
2543
+ setLoading(true);
2544
+ setError(null);
2545
+ try {
2546
+ const result = await client.getArcadePools({ gameSlug });
2547
+ setPools(result);
2548
+ } catch (err) {
2549
+ setError(err instanceof Error ? err : new Error(String(err)));
2550
+ } finally {
2551
+ setLoading(false);
2552
+ }
2553
+ }, [client, gameSlug]);
2554
+ useEffect10(() => {
2555
+ fetch2();
2556
+ }, [fetch2]);
2557
+ return { pools, loading, error, refetch: fetch2 };
2558
+ }
2559
+
2560
+ // src/hooks/useArcadePool.ts
2561
+ import { useState as useState16, useEffect as useEffect11, useCallback as useCallback15 } from "react";
2562
+ function useArcadePool(poolId) {
2563
+ const { client } = useDubs();
2564
+ const [pool, setPool] = useState16(null);
2565
+ const [stats, setStats] = useState16(null);
2566
+ const [leaderboard, setLeaderboard] = useState16([]);
2567
+ const [loading, setLoading] = useState16(false);
2568
+ const [error, setError] = useState16(null);
2569
+ const fetch2 = useCallback15(async () => {
2570
+ if (!poolId) return;
2571
+ setLoading(true);
2572
+ setError(null);
2573
+ try {
2574
+ const [poolRes, lb] = await Promise.all([
2575
+ client.getArcadePool(poolId),
2576
+ client.getArcadeLeaderboard(poolId)
2577
+ ]);
2578
+ setPool(poolRes.pool);
2579
+ setStats(poolRes.stats);
2580
+ setLeaderboard(lb);
2581
+ } catch (err) {
2582
+ setError(err instanceof Error ? err : new Error(String(err)));
2583
+ } finally {
2584
+ setLoading(false);
2585
+ }
2586
+ }, [client, poolId]);
2587
+ useEffect11(() => {
2588
+ fetch2();
2589
+ }, [fetch2]);
2590
+ return { pool, stats, leaderboard, loading, error, refetch: fetch2 };
2591
+ }
2592
+
2593
+ // src/hooks/useArcadeGame.ts
2594
+ import { useState as useState17, useCallback as useCallback16 } from "react";
2595
+ function useArcadeGame(poolId, maxLives = 3) {
2596
+ const { client } = useDubs();
2597
+ const { user } = useAuth();
2598
+ const [entry, setEntry] = useState17(null);
2599
+ const [loading, setLoading] = useState17(false);
2600
+ const [error, setError] = useState17(null);
2601
+ const walletAddress = user?.walletAddress || "";
2602
+ const refreshEntry = useCallback16(async () => {
2603
+ if (!poolId || !walletAddress) return;
2604
+ setLoading(true);
2605
+ setError(null);
2606
+ try {
2607
+ const e = await client.getArcadeEntry(poolId, walletAddress);
2608
+ setEntry(e);
2609
+ } catch (err) {
2610
+ if (err instanceof Error && err.message.includes("No entry found")) {
2611
+ setEntry(null);
2612
+ } else {
2613
+ setError(err instanceof Error ? err : new Error(String(err)));
2614
+ }
2615
+ } finally {
2616
+ setLoading(false);
2617
+ }
2618
+ }, [client, poolId, walletAddress]);
2619
+ const startAttempt = useCallback16(async () => {
2620
+ if (!poolId || !walletAddress) throw new Error("Not ready");
2621
+ setError(null);
2622
+ try {
2623
+ const result = await client.startArcadeAttempt(poolId, walletAddress);
2624
+ return result;
2625
+ } catch (err) {
2626
+ const e = err instanceof Error ? err : new Error(String(err));
2627
+ setError(e);
2628
+ throw e;
2629
+ }
2630
+ }, [client, poolId, walletAddress]);
2631
+ const submitScore = useCallback16(async (sessionToken, score, durationMs) => {
2632
+ if (!poolId || !walletAddress) throw new Error("Not ready");
2633
+ setError(null);
2634
+ try {
2635
+ const result = await client.submitArcadeScore(poolId, {
2636
+ walletAddress,
2637
+ sessionToken,
2638
+ score,
2639
+ durationMs
2640
+ });
2641
+ setEntry((prev) => prev ? {
2642
+ ...prev,
2643
+ best_score: result.bestScore,
2644
+ lives_used: result.livesUsed
2645
+ } : prev);
2646
+ return result;
2647
+ } catch (err) {
2648
+ const e = err instanceof Error ? err : new Error(String(err));
2649
+ setError(e);
2650
+ throw e;
2651
+ }
2652
+ }, [client, poolId, walletAddress]);
2653
+ const livesRemaining = entry ? maxLives - entry.lives_used : maxLives;
2654
+ const bestScore = entry?.best_score || 0;
2655
+ return {
2656
+ entry,
2657
+ livesRemaining,
2658
+ bestScore,
2659
+ loading,
2660
+ error,
2661
+ refreshEntry,
2662
+ startAttempt,
2663
+ submitScore
2664
+ };
2665
+ }
2666
+
2474
2667
  // src/ui/AvatarEditor.tsx
2475
2668
  import {
2476
2669
  View as View2,
@@ -2638,11 +2831,11 @@ function AuthGate({
2638
2831
  }) {
2639
2832
  const { client, pushEnabled } = useDubs();
2640
2833
  const auth = useAuth();
2641
- const [phase, setPhase] = useState15("init");
2642
- const [registrationPhase, setRegistrationPhase] = useState15(false);
2643
- const [showPushSetup, setShowPushSetup] = useState15(false);
2644
- const [isRestoredSession, setIsRestoredSession] = useState15(false);
2645
- useEffect10(() => {
2834
+ const [phase, setPhase] = useState18("init");
2835
+ const [registrationPhase, setRegistrationPhase] = useState18(false);
2836
+ const [showPushSetup, setShowPushSetup] = useState18(false);
2837
+ const [isRestoredSession, setIsRestoredSession] = useState18(false);
2838
+ useEffect12(() => {
2646
2839
  let cancelled = false;
2647
2840
  (async () => {
2648
2841
  try {
@@ -2669,23 +2862,23 @@ function AuthGate({
2669
2862
  cancelled = true;
2670
2863
  };
2671
2864
  }, []);
2672
- useEffect10(() => {
2865
+ useEffect12(() => {
2673
2866
  if (auth.status === "needsRegistration") setRegistrationPhase(true);
2674
2867
  }, [auth.status]);
2675
- useEffect10(() => {
2868
+ useEffect12(() => {
2676
2869
  if (pushEnabled && auth.status === "authenticated" && registrationPhase && !isRestoredSession) {
2677
2870
  setShowPushSetup(true);
2678
2871
  }
2679
2872
  }, [pushEnabled, auth.status, registrationPhase, isRestoredSession]);
2680
- useEffect10(() => {
2873
+ useEffect12(() => {
2681
2874
  if (auth.token) onSaveToken(auth.token);
2682
2875
  }, [auth.token]);
2683
- const retry = useCallback14(() => {
2876
+ const retry = useCallback17(() => {
2684
2877
  setRegistrationPhase(false);
2685
2878
  auth.reset();
2686
2879
  auth.authenticate();
2687
2880
  }, [auth]);
2688
- const handleRegister = useCallback14(
2881
+ const handleRegister = useCallback17(
2689
2882
  (username, referralCode, avatarUrl) => {
2690
2883
  auth.register(username, referralCode, avatarUrl);
2691
2884
  },
@@ -2801,20 +2994,20 @@ function DefaultRegistrationScreen({
2801
2994
  }) {
2802
2995
  const t = useDubsTheme();
2803
2996
  const accent = accentColor || t.accent;
2804
- const [step, setStep] = useState15(0);
2805
- const [avatarSeed, setAvatarSeed] = useState15(generateSeed);
2806
- const [avatarStyle, setAvatarStyle] = useState15("adventurer");
2807
- const [avatarBg, setAvatarBg] = useState15("1a1a2e");
2808
- const [showStyles, setShowStyles] = useState15(false);
2809
- const [username, setUsername] = useState15("");
2810
- const [referralCode, setReferralCode] = useState15("");
2811
- const [checking, setChecking] = useState15(false);
2812
- const [availability, setAvailability] = useState15(null);
2997
+ const [step, setStep] = useState18(0);
2998
+ const [avatarSeed, setAvatarSeed] = useState18(generateSeed);
2999
+ const [avatarStyle, setAvatarStyle] = useState18("adventurer");
3000
+ const [avatarBg, setAvatarBg] = useState18("1a1a2e");
3001
+ const [showStyles, setShowStyles] = useState18(false);
3002
+ const [username, setUsername] = useState18("");
3003
+ const [referralCode, setReferralCode] = useState18("");
3004
+ const [checking, setChecking] = useState18(false);
3005
+ const [availability, setAvailability] = useState18(null);
2813
3006
  const debounceRef = useRef4(null);
2814
3007
  const fadeAnim = useRef4(new Animated.Value(1)).current;
2815
3008
  const slideAnim = useRef4(new Animated.Value(0)).current;
2816
3009
  const avatarUrl = getAvatarUrl(avatarStyle, avatarSeed, avatarBg);
2817
- useEffect10(() => {
3010
+ useEffect12(() => {
2818
3011
  if (debounceRef.current) clearTimeout(debounceRef.current);
2819
3012
  const trimmed = username.trim();
2820
3013
  if (trimmed.length < 3) {
@@ -2837,7 +3030,7 @@ function DefaultRegistrationScreen({
2837
3030
  if (debounceRef.current) clearTimeout(debounceRef.current);
2838
3031
  };
2839
3032
  }, [username, client]);
2840
- const animateToStep = useCallback14((newStep) => {
3033
+ const animateToStep = useCallback17((newStep) => {
2841
3034
  const dir = newStep > step ? 1 : -1;
2842
3035
  Keyboard.dismiss();
2843
3036
  Animated.parallel([
@@ -3077,7 +3270,7 @@ function DefaultRegistrationScreen({
3077
3270
  function PushTokenRestorer() {
3078
3271
  const push = usePushNotifications();
3079
3272
  const restored = useRef4(false);
3080
- useEffect10(() => {
3273
+ useEffect12(() => {
3081
3274
  if (restored.current) return;
3082
3275
  restored.current = true;
3083
3276
  push.restoreIfGranted();
@@ -3094,7 +3287,7 @@ function PushSetupScreen({
3094
3287
  const push = usePushNotifications();
3095
3288
  const fadeAnim = useRef4(new Animated.Value(0)).current;
3096
3289
  const slideAnim = useRef4(new Animated.Value(30)).current;
3097
- useEffect10(() => {
3290
+ useEffect12(() => {
3098
3291
  Animated.parallel([
3099
3292
  Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true }),
3100
3293
  Animated.timing(slideAnim, { toValue: 0, duration: 300, useNativeDriver: true })
@@ -3252,11 +3445,11 @@ function DubsProvider({
3252
3445
  const config = NETWORK_CONFIG[network];
3253
3446
  const baseUrl = baseUrlOverride || config.baseUrl;
3254
3447
  const rpcUrl = rpcUrlOverride || config.rpcUrl;
3255
- const client = useMemo2(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
3256
- const storage = useMemo2(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
3257
- const [uiConfig, setUiConfig] = useState16(null);
3258
- const [resolvedNetwork, setResolvedNetwork] = useState16(network);
3259
- useEffect11(() => {
3448
+ const client = useMemo3(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
3449
+ const storage = useMemo3(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
3450
+ const [uiConfig, setUiConfig] = useState19(null);
3451
+ const [resolvedNetwork, setResolvedNetwork] = useState19(network);
3452
+ useEffect13(() => {
3260
3453
  client.getAppConfig().then((cfg) => {
3261
3454
  console.log("[DubsProvider] UI config loaded:", JSON.stringify(cfg));
3262
3455
  setUiConfig(cfg);
@@ -3272,7 +3465,7 @@ function DubsProvider({
3272
3465
  const resolvedConfig = NETWORK_CONFIG[resolvedNetwork];
3273
3466
  const resolvedRpcUrl = rpcUrlOverride || resolvedConfig.rpcUrl;
3274
3467
  const cluster = resolvedConfig.cluster;
3275
- const connection = useMemo2(() => new Connection2(resolvedRpcUrl, { commitment: "confirmed" }), [resolvedRpcUrl]);
3468
+ const connection = useMemo3(() => new Connection2(resolvedRpcUrl, { commitment: "confirmed" }), [resolvedRpcUrl]);
3276
3469
  if (uiConfig === null) return null;
3277
3470
  const themeOverrides = {};
3278
3471
  if (uiConfig.accentColor) {
@@ -3348,11 +3541,11 @@ function ManagedInner({
3348
3541
  children
3349
3542
  }) {
3350
3543
  const managedDisconnect = useDisconnect();
3351
- const disconnect = useCallback15(async () => {
3544
+ const disconnect = useCallback18(async () => {
3352
3545
  client.setToken(null);
3353
3546
  await managedDisconnect?.();
3354
3547
  }, [client, managedDisconnect]);
3355
- const value = useMemo2(
3548
+ const value = useMemo3(
3356
3549
  () => ({ client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled }),
3357
3550
  [client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled]
3358
3551
  );
@@ -3389,13 +3582,13 @@ function ExternalWalletProvider({
3389
3582
  pushEnabled,
3390
3583
  children
3391
3584
  }) {
3392
- const disconnect = useCallback15(async () => {
3585
+ const disconnect = useCallback18(async () => {
3393
3586
  client.setToken(null);
3394
3587
  await storage.deleteItem(STORAGE_KEYS.JWT_TOKEN).catch(() => {
3395
3588
  });
3396
3589
  await wallet.disconnect?.();
3397
3590
  }, [client, storage, wallet]);
3398
- const value = useMemo2(
3591
+ const value = useMemo3(
3399
3592
  () => ({ client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled }),
3400
3593
  [client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled]
3401
3594
  );
@@ -3432,7 +3625,7 @@ function useAppConfig() {
3432
3625
  }
3433
3626
 
3434
3627
  // src/ui/UserProfileCard.tsx
3435
- import { useMemo as useMemo3 } from "react";
3628
+ import { useMemo as useMemo4 } from "react";
3436
3629
  import { View as View4, Text as Text4, Image as Image4, StyleSheet as StyleSheet4 } from "react-native";
3437
3630
  import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
3438
3631
  function truncateAddress(address, chars = 4) {
@@ -3452,7 +3645,7 @@ function UserProfileCard({
3452
3645
  memberSince
3453
3646
  }) {
3454
3647
  const t = useDubsTheme();
3455
- const imageUri = useMemo3(
3648
+ const imageUri = useMemo4(
3456
3649
  () => ensurePngAvatar(avatarUrl) || `https://api.dicebear.com/9.x/avataaars/png?seed=${walletAddress}&size=128`,
3457
3650
  [avatarUrl, walletAddress]
3458
3651
  );
@@ -3652,7 +3845,7 @@ var styles4 = StyleSheet5.create({
3652
3845
  });
3653
3846
 
3654
3847
  // src/ui/UserProfileSheet.tsx
3655
- import { useState as useState17, useEffect as useEffect12, useRef as useRef5, useCallback as useCallback16, useMemo as useMemo4 } from "react";
3848
+ import { useState as useState20, useEffect as useEffect14, useRef as useRef5, useCallback as useCallback19, useMemo as useMemo5 } from "react";
3656
3849
  import {
3657
3850
  View as View6,
3658
3851
  Text as Text6,
@@ -3684,30 +3877,30 @@ function UserProfileSheet({
3684
3877
  const { refreshUser } = useAuth();
3685
3878
  const push = usePushNotifications();
3686
3879
  const overlayOpacity = useRef5(new Animated2.Value(0)).current;
3687
- const parsed = useMemo4(() => parseAvatarUrl(user.avatar), [user.avatar]);
3688
- const [avatarStyle, setAvatarStyle] = useState17(parsed.style);
3689
- const [avatarSeed, setAvatarSeed] = useState17(parsed.seed);
3690
- const [bgColor, setBgColor] = useState17(parsed.bg);
3691
- const [saving, setSaving] = useState17(false);
3692
- const [error, setError] = useState17(null);
3693
- useEffect12(() => {
3880
+ const parsed = useMemo5(() => parseAvatarUrl(user.avatar), [user.avatar]);
3881
+ const [avatarStyle, setAvatarStyle] = useState20(parsed.style);
3882
+ const [avatarSeed, setAvatarSeed] = useState20(parsed.seed);
3883
+ const [bgColor, setBgColor] = useState20(parsed.bg);
3884
+ const [saving, setSaving] = useState20(false);
3885
+ const [error, setError] = useState20(null);
3886
+ useEffect14(() => {
3694
3887
  const p = parseAvatarUrl(user.avatar);
3695
3888
  setAvatarStyle(p.style);
3696
3889
  setAvatarSeed(p.seed);
3697
3890
  setBgColor(p.bg);
3698
3891
  }, [user.avatar]);
3699
- useEffect12(() => {
3892
+ useEffect14(() => {
3700
3893
  Animated2.timing(overlayOpacity, {
3701
3894
  toValue: visible ? 1 : 0,
3702
3895
  duration: 250,
3703
3896
  useNativeDriver: true
3704
3897
  }).start();
3705
3898
  }, [visible, overlayOpacity]);
3706
- useEffect12(() => {
3899
+ useEffect14(() => {
3707
3900
  if (visible) setError(null);
3708
3901
  }, [visible]);
3709
3902
  const currentAvatarUrl = getAvatarUrl(avatarStyle, avatarSeed, bgColor);
3710
- const saveAvatar = useCallback16(async (newUrl) => {
3903
+ const saveAvatar = useCallback19(async (newUrl) => {
3711
3904
  setSaving(true);
3712
3905
  setError(null);
3713
3906
  try {
@@ -3720,16 +3913,16 @@ function UserProfileSheet({
3720
3913
  setSaving(false);
3721
3914
  }
3722
3915
  }, [client, refreshUser, onAvatarUpdated]);
3723
- const handleStyleChange = useCallback16((style) => {
3916
+ const handleStyleChange = useCallback19((style) => {
3724
3917
  setAvatarStyle(style);
3725
3918
  saveAvatar(getAvatarUrl(style, avatarSeed, bgColor));
3726
3919
  }, [avatarSeed, bgColor, saveAvatar]);
3727
- const handleShuffle = useCallback16(() => {
3920
+ const handleShuffle = useCallback19(() => {
3728
3921
  const newSeed = generateSeed();
3729
3922
  setAvatarSeed(newSeed);
3730
3923
  saveAvatar(getAvatarUrl(avatarStyle, newSeed, bgColor));
3731
3924
  }, [avatarStyle, bgColor, saveAvatar]);
3732
- const handleBgChange = useCallback16((color) => {
3925
+ const handleBgChange = useCallback19((color) => {
3733
3926
  setBgColor(color);
3734
3927
  saveAvatar(getAvatarUrl(avatarStyle, avatarSeed, color));
3735
3928
  }, [avatarStyle, avatarSeed, saveAvatar]);
@@ -4009,7 +4202,7 @@ var styles5 = StyleSheet6.create({
4009
4202
  });
4010
4203
 
4011
4204
  // src/ui/game/GamePoster.tsx
4012
- import { useState as useState18 } from "react";
4205
+ import { useState as useState21 } from "react";
4013
4206
  import { StyleSheet as StyleSheet7, View as View7, Text as Text7 } from "react-native";
4014
4207
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
4015
4208
  function computeCountdown(lockTimestamp) {
@@ -4059,7 +4252,7 @@ function GamePoster({ game, ImageComponent }) {
4059
4252
  ] });
4060
4253
  }
4061
4254
  function TeamLogoInternal({ url, size, Img }) {
4062
- const [failed, setFailed] = useState18(false);
4255
+ const [failed, setFailed] = useState21(false);
4063
4256
  if (!url || failed) {
4064
4257
  return /* @__PURE__ */ jsx9(View7, { style: [styles6.logoPlaceholder, { width: size, height: size, borderRadius: size / 2 }] });
4065
4258
  }
@@ -4160,7 +4353,7 @@ var styles6 = StyleSheet7.create({
4160
4353
  });
4161
4354
 
4162
4355
  // src/ui/game/LivePoolsCard.tsx
4163
- import { useMemo as useMemo5 } from "react";
4356
+ import { useMemo as useMemo6 } from "react";
4164
4357
  import { StyleSheet as StyleSheet8, View as View8, Text as Text8 } from "react-native";
4165
4358
  import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
4166
4359
  function LivePoolsCard({
@@ -4176,7 +4369,7 @@ function LivePoolsCard({
4176
4369
  const homePool = game.homePool || 0;
4177
4370
  const awayPool = game.awayPool || 0;
4178
4371
  const totalPool = game.totalPool || 0;
4179
- const { homePercent, awayPercent, homeOdds, awayOdds } = useMemo5(() => {
4372
+ const { homePercent, awayPercent, homeOdds, awayOdds } = useMemo6(() => {
4180
4373
  return {
4181
4374
  homePercent: totalPool > 0 ? homePool / totalPool * 100 : 50,
4182
4375
  awayPercent: totalPool > 0 ? awayPool / totalPool * 100 : 50,
@@ -4239,7 +4432,7 @@ var styles7 = StyleSheet8.create({
4239
4432
  });
4240
4433
 
4241
4434
  // src/ui/game/PickWinnerCard.tsx
4242
- import { useState as useState19, useMemo as useMemo6 } from "react";
4435
+ import { useState as useState22, useMemo as useMemo7 } from "react";
4243
4436
  import { StyleSheet as StyleSheet9, View as View9, Text as Text9, TouchableOpacity as TouchableOpacity6 } from "react-native";
4244
4437
  import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
4245
4438
  function PickWinnerCard({
@@ -4257,7 +4450,7 @@ function PickWinnerCard({
4257
4450
  const totalPool = game.totalPool || 0;
4258
4451
  const homePool = game.homePool || 0;
4259
4452
  const awayPool = game.awayPool || 0;
4260
- const { homeOdds, awayOdds, homeBets, awayBets } = useMemo6(() => ({
4453
+ const { homeOdds, awayOdds, homeBets, awayBets } = useMemo7(() => ({
4261
4454
  homeOdds: homePool > 0 ? (totalPool / homePool).toFixed(2) : "\u2014",
4262
4455
  awayOdds: awayPool > 0 ? (totalPool / awayPool).toFixed(2) : "\u2014",
4263
4456
  homeBets: bettors.filter((b) => b.team === "home").length,
@@ -4310,7 +4503,7 @@ function TeamOption({
4310
4503
  ImageComponent,
4311
4504
  t
4312
4505
  }) {
4313
- const [imgFailed, setImgFailed] = useState19(false);
4506
+ const [imgFailed, setImgFailed] = useState22(false);
4314
4507
  const Img = ImageComponent || __require("react-native").Image;
4315
4508
  const showImage = imageUrl && !imgFailed;
4316
4509
  return /* @__PURE__ */ jsxs9(
@@ -4351,7 +4544,7 @@ var styles8 = StyleSheet9.create({
4351
4544
  });
4352
4545
 
4353
4546
  // src/ui/game/PlayersCard.tsx
4354
- import { useState as useState20 } from "react";
4547
+ import { useState as useState23 } from "react";
4355
4548
  import { StyleSheet as StyleSheet10, View as View10, Text as Text10 } from "react-native";
4356
4549
  import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
4357
4550
  function truncateWallet(addr, chars) {
@@ -4400,7 +4593,7 @@ function BettorRow({
4400
4593
  ImageComponent,
4401
4594
  t
4402
4595
  }) {
4403
- const [imgFailed, setImgFailed] = useState20(false);
4596
+ const [imgFailed, setImgFailed] = useState23(false);
4404
4597
  const Img = ImageComponent || __require("react-native").Image;
4405
4598
  const showAvatar = bettor.avatar && !imgFailed;
4406
4599
  return /* @__PURE__ */ jsxs10(View10, { style: [styles9.row, !isFirst && { borderTopColor: t.border, borderTopWidth: 1 }], children: [
@@ -4427,7 +4620,7 @@ var styles9 = StyleSheet10.create({
4427
4620
  });
4428
4621
 
4429
4622
  // src/ui/game/JoinGameButton.tsx
4430
- import { useMemo as useMemo7 } from "react";
4623
+ import { useMemo as useMemo8 } from "react";
4431
4624
  import { StyleSheet as StyleSheet11, View as View11, Text as Text11, TouchableOpacity as TouchableOpacity7, ActivityIndicator as ActivityIndicator5 } from "react-native";
4432
4625
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
4433
4626
  var STATUS_LABELS = {
@@ -4438,7 +4631,7 @@ var STATUS_LABELS = {
4438
4631
  };
4439
4632
  function JoinGameButton({ game, walletAddress, selectedTeam, status, onJoin }) {
4440
4633
  const t = useDubsTheme();
4441
- const alreadyJoined = useMemo7(() => {
4634
+ const alreadyJoined = useMemo8(() => {
4442
4635
  if (!walletAddress) return false;
4443
4636
  return (game.bettors || []).some((b) => b.wallet === walletAddress);
4444
4637
  }, [game.bettors, walletAddress]);
@@ -4479,7 +4672,7 @@ var styles10 = StyleSheet11.create({
4479
4672
  });
4480
4673
 
4481
4674
  // src/ui/game/CreateCustomGameSheet.tsx
4482
- import { useState as useState21, useEffect as useEffect13, useRef as useRef6, useCallback as useCallback17 } from "react";
4675
+ import { useState as useState24, useEffect as useEffect15, useRef as useRef6, useCallback as useCallback20 } from "react";
4483
4676
  import {
4484
4677
  View as View12,
4485
4678
  Text as Text12,
@@ -4516,18 +4709,18 @@ function CreateCustomGameSheet({
4516
4709
  const t = useDubsTheme();
4517
4710
  const { wallet } = useDubs();
4518
4711
  const mutation = useCreateCustomGame();
4519
- const [selectedAmount, setSelectedAmount] = useState21(null);
4520
- const [customAmount, setCustomAmount] = useState21("");
4521
- const [isCustom, setIsCustom] = useState21(false);
4712
+ const [selectedAmount, setSelectedAmount] = useState24(null);
4713
+ const [customAmount, setCustomAmount] = useState24("");
4714
+ const [isCustom, setIsCustom] = useState24(false);
4522
4715
  const overlayOpacity = useRef6(new Animated3.Value(0)).current;
4523
- useEffect13(() => {
4716
+ useEffect15(() => {
4524
4717
  Animated3.timing(overlayOpacity, {
4525
4718
  toValue: visible ? 1 : 0,
4526
4719
  duration: 250,
4527
4720
  useNativeDriver: true
4528
4721
  }).start();
4529
4722
  }, [visible, overlayOpacity]);
4530
- useEffect13(() => {
4723
+ useEffect15(() => {
4531
4724
  if (visible) {
4532
4725
  setSelectedAmount(defaultAmount ?? null);
4533
4726
  setCustomAmount("");
@@ -4535,7 +4728,7 @@ function CreateCustomGameSheet({
4535
4728
  mutation.reset();
4536
4729
  }
4537
4730
  }, [visible]);
4538
- useEffect13(() => {
4731
+ useEffect15(() => {
4539
4732
  if (mutation.status === "success" && mutation.data) {
4540
4733
  onSuccess?.(mutation.data);
4541
4734
  const timer = setTimeout(() => {
@@ -4544,23 +4737,23 @@ function CreateCustomGameSheet({
4544
4737
  return () => clearTimeout(timer);
4545
4738
  }
4546
4739
  }, [mutation.status, mutation.data]);
4547
- useEffect13(() => {
4740
+ useEffect15(() => {
4548
4741
  if (mutation.status === "error" && mutation.error) {
4549
4742
  onError?.(mutation.error);
4550
4743
  }
4551
4744
  }, [mutation.status, mutation.error]);
4552
- const handlePresetSelect = useCallback17((amount) => {
4745
+ const handlePresetSelect = useCallback20((amount) => {
4553
4746
  setSelectedAmount(amount);
4554
4747
  setIsCustom(false);
4555
4748
  setCustomAmount("");
4556
4749
  onAmountChange?.(amount);
4557
4750
  }, [onAmountChange]);
4558
- const handleCustomSelect = useCallback17(() => {
4751
+ const handleCustomSelect = useCallback20(() => {
4559
4752
  setIsCustom(true);
4560
4753
  setSelectedAmount(null);
4561
4754
  onAmountChange?.(null);
4562
4755
  }, [onAmountChange]);
4563
- const handleCustomAmountChange = useCallback17((text) => {
4756
+ const handleCustomAmountChange = useCallback20((text) => {
4564
4757
  const cleaned = text.replace(/[^0-9.]/g, "").replace(/(\..*?)\..*/g, "$1");
4565
4758
  setCustomAmount(cleaned);
4566
4759
  const parsed = parseFloat(cleaned);
@@ -4575,7 +4768,7 @@ function CreateCustomGameSheet({
4575
4768
  const winnerTakes = pot * (1 - fee / 100);
4576
4769
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
4577
4770
  const canCreate = finalAmount !== null && finalAmount > 0 && !isMutating && mutation.status !== "success";
4578
- const handleCreate = useCallback17(async () => {
4771
+ const handleCreate = useCallback20(async () => {
4579
4772
  if (!finalAmount || !wallet.publicKey) return;
4580
4773
  try {
4581
4774
  await mutation.execute({
@@ -4844,7 +5037,7 @@ var styles11 = StyleSheet12.create({
4844
5037
  });
4845
5038
 
4846
5039
  // src/ui/game/JoinGameSheet.tsx
4847
- import { useState as useState22, useEffect as useEffect14, useRef as useRef7, useCallback as useCallback18, useMemo as useMemo8 } from "react";
5040
+ import { useState as useState25, useEffect as useEffect16, useRef as useRef7, useCallback as useCallback21, useMemo as useMemo9 } from "react";
4848
5041
  import {
4849
5042
  View as View13,
4850
5043
  Text as Text13,
@@ -4880,22 +5073,22 @@ function JoinGameSheet({
4880
5073
  const { wallet } = useDubs();
4881
5074
  const mutation = useJoinGame();
4882
5075
  const isCustomGame = game.gameMode === CUSTOM_GAME_MODE;
4883
- const [selectedTeam, setSelectedTeam] = useState22(null);
5076
+ const [selectedTeam, setSelectedTeam] = useState25(null);
4884
5077
  const overlayOpacity = useRef7(new Animated4.Value(0)).current;
4885
- useEffect14(() => {
5078
+ useEffect16(() => {
4886
5079
  Animated4.timing(overlayOpacity, {
4887
5080
  toValue: visible ? 1 : 0,
4888
5081
  duration: 250,
4889
5082
  useNativeDriver: true
4890
5083
  }).start();
4891
5084
  }, [visible, overlayOpacity]);
4892
- useEffect14(() => {
5085
+ useEffect16(() => {
4893
5086
  if (visible) {
4894
5087
  setSelectedTeam(isPoolModeEnabled ? "home" : isCustomGame ? "away" : null);
4895
5088
  mutation.reset();
4896
5089
  }
4897
5090
  }, [visible]);
4898
- useEffect14(() => {
5091
+ useEffect16(() => {
4899
5092
  if (mutation.status === "success" && mutation.data) {
4900
5093
  onSuccess?.(mutation.data);
4901
5094
  const timer = setTimeout(() => {
@@ -4904,7 +5097,7 @@ function JoinGameSheet({
4904
5097
  return () => clearTimeout(timer);
4905
5098
  }
4906
5099
  }, [mutation.status, mutation.data]);
4907
- useEffect14(() => {
5100
+ useEffect16(() => {
4908
5101
  if (mutation.status === "error" && mutation.error) {
4909
5102
  onError?.(mutation.error);
4910
5103
  }
@@ -4915,7 +5108,7 @@ function JoinGameSheet({
4915
5108
  const homePool = game.homePool || 0;
4916
5109
  const awayPool = game.awayPool || 0;
4917
5110
  const buyIn = game.buyIn;
4918
- const { homeOdds, awayOdds, homeBets, awayBets } = useMemo8(() => ({
5111
+ const { homeOdds, awayOdds, homeBets, awayBets } = useMemo9(() => ({
4919
5112
  homeOdds: homePool > 0 ? (totalPool / homePool).toFixed(2) : "\u2014",
4920
5113
  awayOdds: awayPool > 0 ? (totalPool / awayPool).toFixed(2) : "\u2014",
4921
5114
  homeBets: bettors.filter((b) => b.team === "home").length,
@@ -4927,14 +5120,14 @@ function JoinGameSheet({
4927
5120
  const homeName = shortName ? shortName(opponents[0]?.name) : opponents[0]?.name || "Home";
4928
5121
  const awayName = shortName ? shortName(opponents[1]?.name) : opponents[1]?.name || "Away";
4929
5122
  const selectedName = selectedTeam === "home" ? homeName : selectedTeam === "away" ? awayName : "\u2014";
4930
- const alreadyJoined = useMemo8(() => {
5123
+ const alreadyJoined = useMemo9(() => {
4931
5124
  if (!wallet.publicKey) return false;
4932
5125
  const addr = wallet.publicKey.toBase58();
4933
5126
  return bettors.some((b) => b.wallet === addr);
4934
5127
  }, [bettors, wallet.publicKey]);
4935
5128
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
4936
5129
  const canJoin = selectedTeam !== null && !isMutating && mutation.status !== "success" && !alreadyJoined;
4937
- const handleJoin = useCallback18(async () => {
5130
+ const handleJoin = useCallback21(async () => {
4938
5131
  if (!selectedTeam || !wallet.publicKey) return;
4939
5132
  try {
4940
5133
  await mutation.execute({
@@ -5078,7 +5271,7 @@ function TeamButton({
5078
5271
  ImageComponent,
5079
5272
  t
5080
5273
  }) {
5081
- const [imgFailed, setImgFailed] = useState22(false);
5274
+ const [imgFailed, setImgFailed] = useState25(false);
5082
5275
  const Img = ImageComponent || __require("react-native").Image;
5083
5276
  const showImage = imageUrl && !imgFailed;
5084
5277
  return /* @__PURE__ */ jsxs13(
@@ -5255,7 +5448,7 @@ var styles12 = StyleSheet13.create({
5255
5448
  });
5256
5449
 
5257
5450
  // src/ui/game/ClaimPrizeSheet.tsx
5258
- import { useState as useState23, useEffect as useEffect15, useRef as useRef8, useCallback as useCallback19 } from "react";
5451
+ import { useState as useState26, useEffect as useEffect17, useRef as useRef8, useCallback as useCallback22 } from "react";
5259
5452
  import {
5260
5453
  View as View14,
5261
5454
  Text as Text14,
@@ -5289,15 +5482,15 @@ function ClaimPrizeSheet({
5289
5482
  const overlayOpacity = useRef8(new Animated5.Value(0)).current;
5290
5483
  const celebrationScale = useRef8(new Animated5.Value(0)).current;
5291
5484
  const celebrationOpacity = useRef8(new Animated5.Value(0)).current;
5292
- const [showCelebration, setShowCelebration] = useState23(false);
5293
- useEffect15(() => {
5485
+ const [showCelebration, setShowCelebration] = useState26(false);
5486
+ useEffect17(() => {
5294
5487
  Animated5.timing(overlayOpacity, {
5295
5488
  toValue: visible ? 1 : 0,
5296
5489
  duration: 250,
5297
5490
  useNativeDriver: true
5298
5491
  }).start();
5299
5492
  }, [visible, overlayOpacity]);
5300
- useEffect15(() => {
5493
+ useEffect17(() => {
5301
5494
  if (visible) {
5302
5495
  mutation.reset();
5303
5496
  setShowCelebration(false);
@@ -5305,7 +5498,7 @@ function ClaimPrizeSheet({
5305
5498
  celebrationOpacity.setValue(0);
5306
5499
  }
5307
5500
  }, [visible]);
5308
- useEffect15(() => {
5501
+ useEffect17(() => {
5309
5502
  if (mutation.status === "success" && mutation.data) {
5310
5503
  setShowCelebration(true);
5311
5504
  Animated5.parallel([
@@ -5328,14 +5521,14 @@ function ClaimPrizeSheet({
5328
5521
  return () => clearTimeout(timer);
5329
5522
  }
5330
5523
  }, [mutation.status, mutation.data]);
5331
- useEffect15(() => {
5524
+ useEffect17(() => {
5332
5525
  if (mutation.status === "error" && mutation.error) {
5333
5526
  onError?.(mutation.error);
5334
5527
  }
5335
5528
  }, [mutation.status, mutation.error]);
5336
5529
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
5337
5530
  const canClaim = !isMutating && mutation.status !== "success" && !!wallet.publicKey;
5338
- const handleClaim = useCallback19(async () => {
5531
+ const handleClaim = useCallback22(async () => {
5339
5532
  if (!wallet.publicKey) return;
5340
5533
  try {
5341
5534
  await mutation.execute({
@@ -5568,7 +5761,7 @@ var styles13 = StyleSheet14.create({
5568
5761
  });
5569
5762
 
5570
5763
  // src/ui/game/ClaimButton.tsx
5571
- import { useState as useState24, useMemo as useMemo9, useCallback as useCallback20 } from "react";
5764
+ import { useState as useState27, useMemo as useMemo10, useCallback as useCallback23 } from "react";
5572
5765
  import { StyleSheet as StyleSheet15, Text as Text15, TouchableOpacity as TouchableOpacity11 } from "react-native";
5573
5766
  import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
5574
5767
  function ClaimButton({ gameId, style, onSuccess, onError }) {
@@ -5576,9 +5769,9 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
5576
5769
  const { wallet } = useDubs();
5577
5770
  const game = useGame(gameId);
5578
5771
  const claimStatus = useHasClaimed(gameId);
5579
- const [sheetVisible, setSheetVisible] = useState24(false);
5772
+ const [sheetVisible, setSheetVisible] = useState27(false);
5580
5773
  const walletAddress = wallet.publicKey?.toBase58() ?? null;
5581
- const myBet = useMemo9(() => {
5774
+ const myBet = useMemo10(() => {
5582
5775
  if (!walletAddress || !game.data?.bettors) return null;
5583
5776
  return game.data.bettors.find((b) => b.wallet === walletAddress) ?? null;
5584
5777
  }, [walletAddress, game.data?.bettors]);
@@ -5587,7 +5780,7 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
5587
5780
  const isWinner = isResolved && myBet != null && myBet.team === game.data?.winnerSide;
5588
5781
  const isEligible = myBet != null && isResolved && (isWinner || isRefund);
5589
5782
  const prizeAmount = isRefund ? myBet?.amount ?? 0 : game.data?.totalPool ?? 0;
5590
- const handleSuccess = useCallback20(
5783
+ const handleSuccess = useCallback23(
5591
5784
  (result) => {
5592
5785
  claimStatus.refetch();
5593
5786
  onSuccess?.(result);
@@ -5705,6 +5898,9 @@ export {
5705
5898
  parseSolanaError,
5706
5899
  signAndSendBase64Transaction,
5707
5900
  useAppConfig,
5901
+ useArcadeGame,
5902
+ useArcadePool,
5903
+ useArcadePools,
5708
5904
  useAuth,
5709
5905
  useClaim,
5710
5906
  useCreateCustomGame,