@dubsdotapp/expo 0.2.70 → 0.2.72
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 +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +37 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +37 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +7 -3
- package/src/hooks/useAuth.ts +13 -2
- package/src/hooks/useCreateCustomGame.ts +2 -3
- package/src/hooks/useCreateGame.ts +2 -3
- package/src/hooks/useJoinGame.ts +2 -3
- package/src/provider.tsx +21 -7
- package/src/types.ts +1 -0
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -473,9 +473,13 @@ export class DubsClient {
|
|
|
473
473
|
|
|
474
474
|
// ── App Config ──
|
|
475
475
|
|
|
476
|
-
/** Fetch the app's UI customization config (accent color, icon, tagline) */
|
|
476
|
+
/** Fetch the app's UI customization config (accent color, icon, tagline, environment) */
|
|
477
477
|
async getAppConfig(): Promise<UiConfig> {
|
|
478
|
-
const res = await this.request<{ data: { uiConfig: UiConfig } }>('GET', '/apps/config');
|
|
479
|
-
|
|
478
|
+
const res = await this.request<{ data: { environment?: string; uiConfig: UiConfig } }>('GET', '/apps/config');
|
|
479
|
+
const config = res.data?.uiConfig || {};
|
|
480
|
+
if (res.data?.environment) {
|
|
481
|
+
config.environment = res.data.environment as UiConfig['environment'];
|
|
482
|
+
}
|
|
483
|
+
return config;
|
|
480
484
|
}
|
|
481
485
|
}
|
package/src/hooks/useAuth.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { useState, useCallback, useRef, useContext } from 'react';
|
|
|
2
2
|
import bs58 from 'bs58';
|
|
3
3
|
import { useDubs } from '../provider';
|
|
4
4
|
import { AuthContext } from '../auth-context';
|
|
5
|
+
import { useDisconnect } from '../managed-wallet';
|
|
5
6
|
import { getDeviceInfo } from '../utils/device';
|
|
6
7
|
import type { AuthStatus, DubsUser } from '../types';
|
|
7
8
|
|
|
@@ -51,6 +52,7 @@ export function useAuth(): UseAuthResult {
|
|
|
51
52
|
const sharedAuth = useContext(AuthContext);
|
|
52
53
|
|
|
53
54
|
const { client, wallet } = useDubs();
|
|
55
|
+
const disconnect = useDisconnect();
|
|
54
56
|
const [status, setStatus] = useState<AuthStatus>('idle');
|
|
55
57
|
const [user, setUser] = useState<DubsUser | null>(null);
|
|
56
58
|
const [token, setToken] = useState<string | null>(null);
|
|
@@ -117,10 +119,19 @@ export function useAuth(): UseAuthResult {
|
|
|
117
119
|
setToken(result.token!);
|
|
118
120
|
setStatus('authenticated');
|
|
119
121
|
} catch (err) {
|
|
120
|
-
|
|
122
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
123
|
+
// Phantom 4100 = stale/revoked session — clear it and return to connect screen
|
|
124
|
+
if (message.includes('4100') || message.includes('not been authorized')) {
|
|
125
|
+
console.log('[useAuth] Stale Phantom session detected (4100), forcing disconnect');
|
|
126
|
+
await disconnect?.();
|
|
127
|
+
setStatus('idle');
|
|
128
|
+
setError(null);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
setError(err instanceof Error ? err : new Error(message));
|
|
121
132
|
setStatus('error');
|
|
122
133
|
}
|
|
123
|
-
}, [client, wallet]);
|
|
134
|
+
}, [client, wallet, disconnect]);
|
|
124
135
|
|
|
125
136
|
const register = useCallback(async (username: string, referralCode?: string, avatarUrl?: string) => {
|
|
126
137
|
try {
|
|
@@ -47,7 +47,7 @@ export function useCreateCustomGame() {
|
|
|
47
47
|
// 3. Confirm with backend
|
|
48
48
|
setStatus('confirming');
|
|
49
49
|
console.log('[useCreateCustomGame] Step 3: Confirming with backend...');
|
|
50
|
-
await client.confirmCustomGame({
|
|
50
|
+
const confirmResult = await client.confirmCustomGame({
|
|
51
51
|
gameId: createResult.gameId,
|
|
52
52
|
playerWallet: params.playerWallet,
|
|
53
53
|
signature,
|
|
@@ -58,12 +58,11 @@ export function useCreateCustomGame() {
|
|
|
58
58
|
});
|
|
59
59
|
console.log('[useCreateCustomGame] Step 3 done.');
|
|
60
60
|
|
|
61
|
-
const explorerUrl = `https://solscan.io/tx/${signature}`;
|
|
62
61
|
const result: CreateCustomGameMutationResult = {
|
|
63
62
|
gameId: createResult.gameId,
|
|
64
63
|
gameAddress: createResult.gameAddress,
|
|
65
64
|
signature,
|
|
66
|
-
explorerUrl,
|
|
65
|
+
explorerUrl: confirmResult.explorerUrl,
|
|
67
66
|
buyIn: params.wagerAmount,
|
|
68
67
|
};
|
|
69
68
|
|
|
@@ -46,7 +46,7 @@ export function useCreateGame() {
|
|
|
46
46
|
// 3. Confirm with backend (server handles on-chain verification)
|
|
47
47
|
setStatus('confirming');
|
|
48
48
|
console.log('[useCreateGame] Step 3: Confirming with backend...');
|
|
49
|
-
await client.confirmGame({
|
|
49
|
+
const confirmResult = await client.confirmGame({
|
|
50
50
|
gameId: createResult.gameId,
|
|
51
51
|
playerWallet: params.playerWallet,
|
|
52
52
|
signature,
|
|
@@ -57,12 +57,11 @@ export function useCreateGame() {
|
|
|
57
57
|
});
|
|
58
58
|
console.log('[useCreateGame] Step 3 done.');
|
|
59
59
|
|
|
60
|
-
const explorerUrl = `https://solscan.io/tx/${signature}`;
|
|
61
60
|
const result: CreateGameMutationResult = {
|
|
62
61
|
gameId: createResult.gameId,
|
|
63
62
|
gameAddress: createResult.gameAddress,
|
|
64
63
|
signature,
|
|
65
|
-
explorerUrl,
|
|
64
|
+
explorerUrl: confirmResult.explorerUrl,
|
|
66
65
|
};
|
|
67
66
|
|
|
68
67
|
setData(result);
|
package/src/hooks/useJoinGame.ts
CHANGED
|
@@ -55,15 +55,14 @@ export function useJoinGame() {
|
|
|
55
55
|
gameAddress: joinResult.gameAddress,
|
|
56
56
|
};
|
|
57
57
|
console.log('[useJoinGame] Step 3: Confirming with backend...', confirmParams);
|
|
58
|
-
await client.confirmGame(confirmParams);
|
|
58
|
+
const confirmResult = await client.confirmGame(confirmParams);
|
|
59
59
|
console.log('[useJoinGame] Step 3 done. Backend confirmed.');
|
|
60
60
|
|
|
61
|
-
const explorerUrl = `https://solscan.io/tx/${signature}`;
|
|
62
61
|
const result: JoinGameMutationResult = {
|
|
63
62
|
gameId: params.gameId,
|
|
64
63
|
gameAddress: joinResult.gameAddress,
|
|
65
64
|
signature,
|
|
66
|
-
explorerUrl,
|
|
65
|
+
explorerUrl: confirmResult.explorerUrl,
|
|
67
66
|
};
|
|
68
67
|
|
|
69
68
|
setData(result);
|
package/src/provider.tsx
CHANGED
|
@@ -86,20 +86,26 @@ export function DubsProvider({
|
|
|
86
86
|
const config = NETWORK_CONFIG[network];
|
|
87
87
|
const baseUrl = baseUrlOverride || config.baseUrl;
|
|
88
88
|
const rpcUrl = rpcUrlOverride || config.rpcUrl;
|
|
89
|
-
const cluster = config.cluster;
|
|
90
89
|
|
|
91
90
|
// Create stable instances
|
|
92
91
|
const client = useMemo(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
|
|
93
|
-
const connection = useMemo(() => new Connection(rpcUrl, { commitment: 'confirmed' }), [rpcUrl]);
|
|
94
92
|
const storage = useMemo(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
|
|
95
93
|
|
|
96
94
|
// Fetch developer UI config on mount (silent fail = default theme)
|
|
95
|
+
// Also auto-detects sandbox/production environment from the API key
|
|
97
96
|
const [uiConfig, setUiConfig] = useState<UiConfig | null>(null);
|
|
97
|
+
const [resolvedNetwork, setResolvedNetwork] = useState<DubsNetwork>(network);
|
|
98
98
|
useEffect(() => {
|
|
99
99
|
client.getAppConfig()
|
|
100
|
-
.then((
|
|
101
|
-
console.log('[DubsProvider] UI config loaded:', JSON.stringify(
|
|
102
|
-
setUiConfig(
|
|
100
|
+
.then((cfg) => {
|
|
101
|
+
console.log('[DubsProvider] UI config loaded:', JSON.stringify(cfg));
|
|
102
|
+
setUiConfig(cfg);
|
|
103
|
+
// Auto-detect network from API key environment (sandbox → devnet)
|
|
104
|
+
// Only override if the user didn't explicitly set network or rpcUrl
|
|
105
|
+
if (cfg.environment === 'sandbox' && network === 'mainnet-beta' && !rpcUrlOverride) {
|
|
106
|
+
console.log('[DubsProvider] Sandbox API key detected — auto-switching to devnet');
|
|
107
|
+
setResolvedNetwork('devnet');
|
|
108
|
+
}
|
|
103
109
|
})
|
|
104
110
|
.catch((err) => {
|
|
105
111
|
console.log('[DubsProvider] UI config fetch failed, using defaults:', err?.message);
|
|
@@ -110,6 +116,14 @@ export function DubsProvider({
|
|
|
110
116
|
// Wait for config before rendering so accent color is applied on first paint
|
|
111
117
|
if (uiConfig === null) return null;
|
|
112
118
|
|
|
119
|
+
// Use resolved network (may differ from prop if sandbox was auto-detected)
|
|
120
|
+
const resolvedConfig = NETWORK_CONFIG[resolvedNetwork];
|
|
121
|
+
const resolvedRpcUrl = rpcUrlOverride || resolvedConfig.rpcUrl;
|
|
122
|
+
const cluster = resolvedConfig.cluster;
|
|
123
|
+
|
|
124
|
+
// Connection uses the resolved RPC (auto-switched to devnet for sandbox keys)
|
|
125
|
+
const connection = useMemo(() => new Connection(resolvedRpcUrl, { commitment: 'confirmed' }), [resolvedRpcUrl]);
|
|
126
|
+
|
|
113
127
|
// Build theme overrides from server config so all SDK components respect the tint
|
|
114
128
|
const themeOverrides: Partial<DubsTheme> = {};
|
|
115
129
|
if (uiConfig.accentColor) {
|
|
@@ -125,7 +139,7 @@ export function DubsProvider({
|
|
|
125
139
|
connection={connection}
|
|
126
140
|
wallet={externalWallet}
|
|
127
141
|
appName={uiConfig.appName || appName}
|
|
128
|
-
network={
|
|
142
|
+
network={resolvedNetwork}
|
|
129
143
|
storage={storage}
|
|
130
144
|
managed={managed}
|
|
131
145
|
renderLoading={renderLoading}
|
|
@@ -161,7 +175,7 @@ export function DubsProvider({
|
|
|
161
175
|
connection={connection}
|
|
162
176
|
wallet={adapter}
|
|
163
177
|
appName={uiConfig.appName || appName}
|
|
164
|
-
network={
|
|
178
|
+
network={resolvedNetwork}
|
|
165
179
|
storage={storage}
|
|
166
180
|
renderLoading={renderLoading}
|
|
167
181
|
renderError={renderError}
|