@dimcool/sdk 0.1.29 → 0.1.31

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.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { Transaction } from '@solana/web3.js';
2
- import { RpsGameAction, RpsGameState, RpsAction } from '@dimcool/rps';
3
- import { ChessGameAction, ChessGameState, ChessMovePayload } from '@dimcool/chess';
4
- import { NimGameAction, NimGameState } from '@dimcool/nim';
5
- import { DotsAndBoxesGameAction, DotsAndBoxesGameState } from '@dimcool/dots-and-boxes';
6
- import { TicTacToeGameAction, TicTacToeGameState } from '@dimcool/tic-tac-toe';
7
- import { Connect4GameAction, Connect4GameState } from '@dimcool/connect-four';
2
+ import { RpsGameState, RpsGameAction, RpsAction } from '@dimcool/rps';
3
+ import { ChessGameState, ChessGameAction, ChessMovePayload } from '@dimcool/chess';
4
+ import { NimGameState, NimGameAction } from '@dimcool/nim';
5
+ import { DotsAndBoxesGameState, DotsAndBoxesGameAction } from '@dimcool/dots-and-boxes';
6
+ import { TicTacToeGameState, TicTacToeGameAction } from '@dimcool/tic-tac-toe';
7
+ import { Connect4GameState, Connect4GameAction } from '@dimcool/connect-four';
8
8
  export { MICRO_UNITS, formatMoneyMinor, toMajor } from '@dimcool/utils';
9
9
 
10
10
  /**
@@ -108,6 +108,62 @@ interface ConnectionState {
108
108
  error: string | null;
109
109
  }
110
110
 
111
+ interface AnalyticsUserData {
112
+ userId: string;
113
+ username?: string | null;
114
+ email?: string | null;
115
+ walletAddress?: string | null;
116
+ authProvider?: 'google' | 'apple' | 'injected' | 'keypair';
117
+ isBot?: boolean;
118
+ createdAt?: string;
119
+ }
120
+ interface IAnalyticsClient {
121
+ /**
122
+ * Called after a successful login. Implementations should identify the user
123
+ * and link any pre-login anonymous events to their profile.
124
+ */
125
+ userLoggedIn(user: AnalyticsUserData, meta: {
126
+ isNewUser: boolean;
127
+ authMethod: string;
128
+ referralCode?: string;
129
+ }): void;
130
+ /**
131
+ * Called on logout. Implementations should reset the current identity so
132
+ * subsequent events are associated with a new anonymous session.
133
+ */
134
+ userLoggedOut(): void;
135
+ /**
136
+ * Called on app boot when auth is restored from storage (returning user).
137
+ * Should re-attach the user identity without creating a new alias link.
138
+ */
139
+ sessionRestored(user: AnalyticsUserData): void;
140
+ /**
141
+ * Track a discrete event. Fire-and-forget — must never throw or block.
142
+ */
143
+ track(event: string, properties?: Record<string, unknown>): void;
144
+ /**
145
+ * Set persistent user properties that will be attached to the user's profile.
146
+ */
147
+ setUserProperties(properties: Record<string, unknown>): void;
148
+ /**
149
+ * Associate the current user with a group (e.g. game_type).
150
+ */
151
+ group(groupType: string, groupKey: string, properties?: Record<string, unknown>): void;
152
+ }
153
+ /** Default noop implementation — used when no analytics client is configured. */
154
+ declare class NoopAnalyticsClient implements IAnalyticsClient {
155
+ userLoggedIn(_user: AnalyticsUserData, _meta: {
156
+ isNewUser: boolean;
157
+ authMethod: string;
158
+ referralCode?: string;
159
+ }): void;
160
+ userLoggedOut(): void;
161
+ sessionRestored(_user: AnalyticsUserData): void;
162
+ track(_event: string, _properties?: Record<string, unknown>): void;
163
+ setUserProperties(_properties: Record<string, unknown>): void;
164
+ group(_groupType: string, _groupKey: string, _properties?: Record<string, unknown>): void;
165
+ }
166
+
111
167
  interface SDKConfig {
112
168
  appId: string;
113
169
  baseUrl?: string;
@@ -115,6 +171,7 @@ interface SDKConfig {
115
171
  httpClient?: IHttpClient;
116
172
  wsTransport?: WsTransport;
117
173
  logger?: ILogger;
174
+ analytics?: IAnalyticsClient;
118
175
  autoPay?: {
119
176
  enabled?: boolean;
120
177
  maxAmountMinor?: number;
@@ -207,6 +264,9 @@ interface FeatureFlag {
207
264
  createdAt: string;
208
265
  updatedAt: string;
209
266
  }
267
+ interface AdminFeatureFlag extends FeatureFlag {
268
+ description: string | null;
269
+ }
210
270
  interface ApiError {
211
271
  error?: string;
212
272
  message?: string | string[];
@@ -216,6 +276,7 @@ interface ApiError {
216
276
  interface UsernameAvailabilityResponse {
217
277
  valid: boolean;
218
278
  available: boolean;
279
+ reason?: 'reserved' | 'taken' | 'invalid_format' | 'blocked_domain';
219
280
  }
220
281
  interface PublicUser {
221
282
  id: string;
@@ -259,6 +320,10 @@ interface FriendRequestItem {
259
320
  mutualFriendsCount: number;
260
321
  createdAt: string;
261
322
  }
323
+ interface PaginatedFriendRequests {
324
+ items: FriendRequestItem[];
325
+ nextCursor?: string;
326
+ }
262
327
  interface PaginatedSearchUsers {
263
328
  users: SearchUser[];
264
329
  total: number;
@@ -284,6 +349,22 @@ interface PaginatedSessions {
284
349
  sessions: Session[];
285
350
  total: number;
286
351
  }
352
+ interface SessionStats {
353
+ total: number;
354
+ email: number;
355
+ wallet: number;
356
+ walletBreakdown: {
357
+ phantomEmbedded: number;
358
+ keypair: number;
359
+ byProvider: {
360
+ google: number;
361
+ apple: number;
362
+ injected: number;
363
+ unknown: number;
364
+ };
365
+ byWalletName: Record<string, number>;
366
+ };
367
+ }
287
368
  type ActivityFeedItemType = 'new_user' | 'win' | 'lobby_created' | 'game_started';
288
369
  interface ActivityFeedUser {
289
370
  id: string;
@@ -996,6 +1077,16 @@ declare class Wallet {
996
1077
  * Confirm a transfer that was already sent by the client (signAndSendTransaction path).
997
1078
  */
998
1079
  confirmTransferSignature(signature: string, senderAddress: string, recipientAddress: string, amount: number, token?: TransferToken, ataCreated?: boolean, recipientInput?: string): Promise<SubmitTransferResponse>;
1080
+ /**
1081
+ * Sign a prepared transaction and invoke the appropriate backend callback
1082
+ * based on the configured signer — without exposing the mode decision to callers.
1083
+ * - Embedded wallet (signAndSend): signs+sends, calls onSignedAndSent(signature)
1084
+ * - Injected wallet (signTransaction): signs locally, calls onSigned(signedTxBase64)
1085
+ */
1086
+ signAndDispatch<T>(unsignedTxBase64: string, handlers: {
1087
+ onSigned: (signedTxBase64: string) => Promise<T>;
1088
+ onSignedAndSent: (signature: string) => Promise<T>;
1089
+ }): Promise<T>;
999
1090
  /**
1000
1091
  * Full transfer flow in one call: prepare -> sign -> submit
1001
1092
  * Recipient can be username, .sol domain, or Solana address (resolved by backend).
@@ -1011,13 +1102,18 @@ declare class Auth {
1011
1102
  private logger;
1012
1103
  constructor(http: IHttpClient, storage: IStorage, wallet: Wallet, logger?: ILogger);
1013
1104
  login(email: string, password: string): Promise<LoginResponse>;
1014
- private generateHandshake;
1105
+ generateHandshake(walletAddress: string): Promise<GenerateHandshakeResponse>;
1015
1106
  loginWithWallet(options?: {
1016
1107
  referralCode?: string;
1017
1108
  walletMeta?: WalletMeta;
1018
1109
  }): Promise<LoginResponse>;
1110
+ loginWithExternalSignature(address: string, signedMessage: string, options?: {
1111
+ referralCode?: string;
1112
+ walletMeta?: WalletMeta;
1113
+ }): Promise<LoginResponse>;
1019
1114
  logout(): void;
1020
1115
  isAuthenticated(): boolean;
1116
+ getSessionStats(): Promise<SessionStats>;
1021
1117
  getLatestSessions(limit?: number): Promise<PaginatedSessions>;
1022
1118
  }
1023
1119
 
@@ -1025,6 +1121,11 @@ declare class Admin {
1025
1121
  private http;
1026
1122
  private logger?;
1027
1123
  constructor(http: IHttpClient, logger?: ILogger | undefined);
1124
+ getInternalBots(): Promise<(User & {
1125
+ sol: number;
1126
+ usdc: number;
1127
+ publicKey: string;
1128
+ })[]>;
1028
1129
  getUserById(id: string): Promise<User>;
1029
1130
  getUserBalance(userId: string): Promise<{
1030
1131
  sol: number;
@@ -1108,8 +1209,14 @@ declare class Users {
1108
1209
  removeFriend(userId: string): Promise<{
1109
1210
  message: string;
1110
1211
  }>;
1111
- getIncomingFriendRequests(): Promise<FriendRequestItem[]>;
1112
- getOutgoingFriendRequests(): Promise<FriendRequestItem[]>;
1212
+ getIncomingFriendRequests(opts?: {
1213
+ limit?: number;
1214
+ cursor?: string;
1215
+ }): Promise<PaginatedFriendRequests>;
1216
+ getOutgoingFriendRequests(opts?: {
1217
+ limit?: number;
1218
+ cursor?: string;
1219
+ }): Promise<PaginatedFriendRequests>;
1113
1220
  acceptFriendRequest(userId: string): Promise<{
1114
1221
  message: string;
1115
1222
  }>;
@@ -1159,141 +1266,238 @@ declare class FeatureFlags {
1159
1266
  private loaded;
1160
1267
  constructor(http: IHttpClient, logger?: ILogger | undefined);
1161
1268
  getFeatureFlags(): Promise<FeatureFlag[]>;
1269
+ getAdminFeatureFlags(): Promise<AdminFeatureFlag[]>;
1162
1270
  isEnabledFlag(name: string): boolean;
1163
1271
  isLoaded(): boolean;
1164
1272
  updateFeatureFlag(name: string, enabled: boolean): Promise<FeatureFlag>;
1165
- createFeatureFlag(name: string, enabled: boolean): Promise<FeatureFlag>;
1273
+ createFeatureFlag(name: string, enabled: boolean, description?: string): Promise<AdminFeatureFlag>;
1166
1274
  }
1167
1275
 
1168
- interface BetOption {
1169
- amount: MoneyMinor;
1170
- playersOnline: number;
1171
- estimatedTime: string;
1172
- }
1173
- interface LobbyPlayer {
1174
- userId: string;
1175
- username?: string;
1176
- avatar?: string;
1177
- joinedAt: string;
1178
- connected?: boolean;
1179
- /** USDC balance in minor units (cached, short TTL). Shown in lobby and used to gate Start Game. */
1180
- usdcBalance?: number;
1181
- }
1182
- interface Lobby {
1183
- id: string;
1184
- gameType: string;
1185
- gameName: string;
1186
- status: 'waiting' | 'preparing' | 'queued' | 'active';
1187
- creatorId: string;
1188
- maxPlayers: number;
1189
- betAmount?: MoneyMinor;
1190
- betOptions?: BetOption[];
1191
- gameId?: string;
1192
- createdAt: string;
1193
- updatedAt: string;
1194
- players: LobbyPlayer[];
1195
- }
1196
- interface CreateLobbyRequest {
1197
- gameType: string;
1198
- }
1199
- interface InviteFriendRequest {
1200
- friendId: string;
1276
+ /**
1277
+ * Retry configuration options
1278
+ */
1279
+ interface RetryOptions {
1280
+ /** Maximum number of retry attempts (default: 3) */
1281
+ maxAttempts?: number;
1282
+ /** Base delay in milliseconds (default: 1000) */
1283
+ baseDelayMs?: number;
1284
+ /** Maximum delay in milliseconds (default: 10000) */
1285
+ maxDelayMs?: number;
1286
+ /** Multiplier for exponential backoff (default: 2) */
1287
+ backoffMultiplier?: number;
1288
+ /** Function to determine if error is retryable (default: network/5xx errors) */
1289
+ isRetryable?: (error: unknown) => boolean;
1290
+ /** Callback for each retry attempt */
1291
+ onRetry?: (attempt: number, error: unknown, delayMs: number) => void;
1201
1292
  }
1202
- interface QueueStats {
1203
- totalPlayersInQueue: number;
1204
- queueSizes: Record<string, number>;
1205
- totalQueuedLobbies: number;
1293
+ /**
1294
+ * Default function to determine if an error is retryable.
1295
+ * Retries on network errors and 5xx server errors.
1296
+ */
1297
+ declare function isRetryableError(error: unknown): boolean;
1298
+ /**
1299
+ * Execute an async function with exponential backoff retry.
1300
+ *
1301
+ * @param fn - Async function to execute
1302
+ * @param options - Retry configuration
1303
+ * @returns Promise resolving to the function result
1304
+ * @throws Last error if all retries exhausted
1305
+ *
1306
+ * @example
1307
+ * ```typescript
1308
+ * const result = await withRetry(
1309
+ * () => fetch('/api/data'),
1310
+ * { maxAttempts: 3, baseDelayMs: 500 }
1311
+ * );
1312
+ * ```
1313
+ */
1314
+ declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
1315
+
1316
+ type EqualityFn<T> = (a: T, b: T) => boolean;
1317
+ interface SdkStore<S> {
1318
+ getSnapshot(): S;
1319
+ getState(): S;
1320
+ setState(next: S): void;
1321
+ updateState(updater: (prev: S) => S): void;
1322
+ subscribe(listener: () => void): () => void;
1323
+ subscribeSelector<T>(selector: (state: S) => T, listener: () => void, isEqual?: EqualityFn<T>): () => void;
1206
1324
  }
1207
- type ChatMessageType = 'user' | 'system';
1208
- type SystemMessageType = 'player_joined' | 'player_left' | 'bet_changed' | 'call_joined' | 'call_left' | 'global_help' | 'global_challenge' | 'global_tip' | 'spectator_donation' | 'challenge_accepted' | 'challenge_declined';
1209
- interface ChatMessageReply {
1325
+ declare function createSdkStore<S>(initial: S): SdkStore<S>;
1326
+
1327
+ type DmThreadsStoreState = {
1328
+ threads: DmThread[];
1329
+ loading: boolean;
1330
+ error: string | null;
1331
+ needsRefresh: boolean;
1332
+ };
1333
+ type DmThreadsStore = {
1334
+ store: SdkStore<DmThreadsStoreState>;
1335
+ setBaseState: (threads: DmThread[]) => void;
1336
+ setLoading: (loading: boolean) => void;
1337
+ setError: (error: string | null) => void;
1338
+ setCurrentUserId: (userId: string | null) => void;
1339
+ applyWsEvent: (event: WsEvent) => void;
1340
+ };
1341
+ declare function createDmThreadsStore(): DmThreadsStore;
1342
+
1343
+ type ChatContextType = 'lobby' | 'game' | 'dm' | 'global';
1344
+ interface ChatContext {
1345
+ type: ChatContextType;
1210
1346
  id: string;
1211
- userId?: string;
1212
- username?: string;
1213
- message: string;
1214
- }
1215
- interface ChatReaction {
1216
- emoji: string;
1217
- userId: string;
1218
- username?: string;
1219
- createdAt: string;
1220
- }
1221
- interface ChatReadBy {
1222
- userId: string;
1223
- readAt: string;
1224
1347
  }
1225
- interface ChatMessage {
1226
- id: string;
1227
- lobbyId: string;
1228
- userId?: string;
1229
- username?: string;
1230
- avatarUrl?: string;
1348
+ interface SendMessageRequest {
1231
1349
  message: string;
1232
- type: ChatMessageType;
1233
- systemType?: SystemMessageType;
1234
- metadata?: Record<string, any>;
1235
1350
  replyTo?: ChatMessageReply;
1236
- reactions?: ChatReaction[];
1237
- readBy?: ChatReadBy[];
1238
- createdAt: string;
1351
+ gifUrl?: string;
1239
1352
  }
1240
-
1241
- declare class Lobbies {
1353
+ interface DmThread {
1354
+ dmKey: string;
1355
+ otherUser: PublicUser;
1356
+ lastMessage: string | null;
1357
+ lastMessageAt: string | null;
1358
+ lastMessageSenderId: string | null;
1359
+ lastMessageSenderUsername: string | null;
1360
+ unreadCount: number;
1361
+ }
1362
+ declare class Chat {
1242
1363
  private http;
1243
1364
  private logger?;
1244
- constructor(http: IHttpClient, logger?: ILogger | undefined);
1245
- createLobby(gameType: string, betAmount?: MoneyMinor): Promise<Lobby>;
1246
- getLobby(lobbyId: string): Promise<Lobby>;
1247
- inviteFriend(lobbyId: string, friendId: string): Promise<{
1248
- message: string;
1249
- }>;
1250
- acceptInvite(lobbyId: string): Promise<Lobby>;
1251
- joinLobby(lobbyId: string): Promise<Lobby>;
1252
- removePlayer(lobbyId: string, userId: string): Promise<{
1253
- message: string;
1254
- }>;
1255
- kickPlayer(lobbyId: string, userId: string): Promise<{
1256
- message: string;
1257
- }>;
1258
- leaveLobby(lobbyId: string): Promise<{
1259
- message: string;
1260
- }>;
1261
- joinQueue(lobbyId: string): Promise<Lobby>;
1262
- cancelQueue(lobbyId: string): Promise<Lobby>;
1263
- updateBetAmount(lobbyId: string, betAmount: MoneyMinor): Promise<Lobby>;
1264
- playSound(lobbyId: string, sound: string): Promise<{
1265
- success: boolean;
1266
- }>;
1267
- getActiveLobbies(): Promise<Lobby[]>;
1268
- getQueueStats(): Promise<QueueStats>;
1269
- deleteLobby(lobbyId: string): Promise<{
1270
- message: string;
1271
- }>;
1365
+ private retryOptions;
1366
+ private dmThreadsStore?;
1367
+ constructor(http: IHttpClient, logger?: any | undefined, retryOptions?: RetryOptions);
1368
+ setDmThreadsStore(store: DmThreadsStore): void;
1369
+ private encodeContextId;
1272
1370
  /**
1273
- * Play again: Create a new lobby and prepare deposit in one flow.
1274
- * Returns the lobby and unsigned transaction that needs to be signed.
1275
- * @param gameType - The game type to play again
1276
- * @param betAmount - The bet amount (same as previous game)
1277
- * @param escrow - The escrow service instance (from sdk.escrow)
1371
+ * Send a chat message with automatic retry on transient failures
1372
+ *
1373
+ * @param clientMessageId - Optional client-generated ID for optimistic UI.
1374
+ * Echoed back in response metadata for deduplication.
1278
1375
  */
1279
- playAgain(gameType: string, betAmount: MoneyMinor, escrow: {
1280
- prepareAndStartDeposit: (id: string) => Promise<{
1281
- transaction: string;
1282
- message: string;
1283
- }>;
1284
- }): Promise<{
1285
- lobby: Lobby;
1286
- unsignedTransaction: string;
1376
+ sendMessage(context: ChatContext, message: string, replyTo?: ChatMessageReply, gifUrl?: string, clientMessageId?: string): Promise<ChatMessage>;
1377
+ /** Response from paginated chat history */
1378
+ getChatHistory(context: ChatContext, limit?: number, cursor?: string): Promise<ChatMessage[]>;
1379
+ /**
1380
+ * Get chat history with pagination support.
1381
+ * Returns messages and a cursor for loading older messages.
1382
+ * For global context, uses the public endpoint so it works without auth.
1383
+ */
1384
+ getChatHistoryPaginated(context: ChatContext, limit?: number, cursor?: string): Promise<{
1385
+ messages: ChatMessage[];
1386
+ nextCursor: string | null;
1287
1387
  }>;
1288
- }
1289
-
1290
- interface GameType {
1291
- id: string;
1292
- name: string;
1293
- maxPlayers: number;
1294
- minPlayers: number;
1295
- description?: string;
1296
- /** Agent-facing instructions including game pace (how fast the game is). */
1388
+ /**
1389
+ * Add a reaction to a message
1390
+ */
1391
+ addReaction(context: ChatContext, messageId: string, emoji: string): Promise<ChatMessage>;
1392
+ /**
1393
+ * Remove a reaction from a message
1394
+ */
1395
+ removeReaction(context: ChatContext, messageId: string, emoji: string): Promise<ChatMessage>;
1396
+ /**
1397
+ * Mark a message as read
1398
+ */
1399
+ markAsRead(context: ChatContext, messageId: string): Promise<ChatMessage>;
1400
+ listDmThreads(): Promise<DmThread[]>;
1401
+ getDmThread(dmKey: string): Promise<DmThread>;
1402
+ /**
1403
+ * Mark all messages in a DM thread as read
1404
+ */
1405
+ markDmThreadAsRead(dmKey: string): Promise<{
1406
+ markedCount: number;
1407
+ }>;
1408
+ /**
1409
+ * Accept a global chat challenge. Returns the lobby (and gameId if started).
1410
+ */
1411
+ acceptGlobalChallenge(challengeId: string): Promise<{
1412
+ lobbyId: string;
1413
+ gameId?: string;
1414
+ status: string;
1415
+ }>;
1416
+ /**
1417
+ * Broadcast a tip message to global chat (call after the user has signed and submitted the transfer).
1418
+ */
1419
+ broadcastGlobalTip(recipientUserId: string, amount: number): Promise<ChatMessage>;
1420
+ }
1421
+
1422
+ type GameStoreState = {
1423
+ gamesById: Record<string, Game>;
1424
+ /** Real-time spectator counts by userId, updated via spectator:count:updated WS events. */
1425
+ spectatorCounts: Record<string, number>;
1426
+ };
1427
+ type GameStore = {
1428
+ store: SdkStore<GameStoreState>;
1429
+ setBaseState: (games: Game[]) => void;
1430
+ applyWsEvent: (event: WsEvent) => void;
1431
+ joinGame: (gameId: string) => () => void;
1432
+ /** Join the spectate channel for a user. Returns a leave function. */
1433
+ joinSpectateChannel: (spectatedUserId: string) => () => void;
1434
+ /** Get a snapshot of the spectator count for a user (from the store). */
1435
+ getSpectatorCount: (userId: string) => number;
1436
+ };
1437
+ declare function createGameStore(transport: WsTransport): GameStore;
1438
+
1439
+ type GameActionsStoreState = {
1440
+ statesByGameId: Record<string, GameStateResponse>;
1441
+ };
1442
+ interface ChessClockTimes {
1443
+ whiteTimeMs: number;
1444
+ blackTimeMs: number;
1445
+ }
1446
+ interface ChessCapturedPieces {
1447
+ capturedByWhite: string[];
1448
+ capturedByBlack: string[];
1449
+ }
1450
+ interface TicTacToeClockTimes {
1451
+ xTimeMs: number;
1452
+ oTimeMs: number;
1453
+ }
1454
+ interface Connect4ClockTimes {
1455
+ redTimeMs: number;
1456
+ yellowTimeMs: number;
1457
+ }
1458
+ /**
1459
+ * Common lifecycle fields extracted from any game state.
1460
+ * Used by useGameLifecycle to avoid casting the raw union type.
1461
+ */
1462
+ interface GameLifecycleState {
1463
+ status: string;
1464
+ winnerId: string | null;
1465
+ betAmount: number;
1466
+ wonAmount: number | null;
1467
+ totalPotMinor: number | undefined;
1468
+ currentPlayerId: string | null;
1469
+ }
1470
+ /**
1471
+ * Pure selector — extracts lifecycle fields from any game state variant.
1472
+ * Accepts a single GameStateResponse so callers can use it after selecting
1473
+ * the stable store entry via useSdkSelector, avoiding new-object-per-call issues.
1474
+ */
1475
+ declare function selectGameLifecycleState(gameState: GameStateResponse | null | undefined): GameLifecycleState | null;
1476
+ type GameActionsStore = {
1477
+ store: SdkStore<GameActionsStoreState>;
1478
+ setBaseState: (gameId: string, state: GameStateResponse) => void;
1479
+ clearState: (gameId: string) => void;
1480
+ applyWsEvent: (event: WsEvent) => void;
1481
+ joinGame: (gameId: string) => () => void;
1482
+ getCountdownDigit: (gameId: string, nowMs: number) => number | null;
1483
+ /** Live chess clock — deducts elapsed time since turnStartedAt. */
1484
+ getChessClockTimes: (gameId: string, nowMs: number) => ChessClockTimes | null;
1485
+ /** Captured pieces derived from the current FEN position. */
1486
+ getChessCapturedPieces: (gameId: string) => ChessCapturedPieces | null;
1487
+ /** Live TTT clock — deducts elapsed from the current player's mark (X or O). */
1488
+ getTicTacToeClockTimes: (gameId: string, nowMs: number) => TicTacToeClockTimes | null;
1489
+ /** Live Connect Four clock — deducts elapsed from the current player's color. */
1490
+ getConnect4ClockTimes: (gameId: string, nowMs: number) => Connect4ClockTimes | null;
1491
+ };
1492
+ declare function createGameActionsStore(transport: WsTransport): GameActionsStore;
1493
+
1494
+ interface GameType {
1495
+ id: string;
1496
+ name: string;
1497
+ maxPlayers: number;
1498
+ minPlayers: number;
1499
+ description?: string;
1500
+ /** Agent-facing instructions including game pace (how fast the game is). */
1297
1501
  detailedInstructions?: string;
1298
1502
  available: boolean;
1299
1503
  betOptions?: BetOption[];
@@ -1392,7 +1596,11 @@ declare class Games {
1392
1596
  private http;
1393
1597
  private wallet;
1394
1598
  private logger?;
1599
+ private gameStore?;
1600
+ private gameActionsStore?;
1395
1601
  constructor(http: IHttpClient, wallet: Wallet, logger?: ILogger | undefined);
1602
+ setGameStore(store: GameStore): void;
1603
+ setGameActionsStore(store: GameActionsStore): void;
1396
1604
  getAvailableGames(): Promise<GameType[]>;
1397
1605
  /**
1398
1606
  * Get real-time metrics for all games.
@@ -1455,8 +1663,16 @@ declare class Games {
1455
1663
  signature: string;
1456
1664
  status: string;
1457
1665
  }>;
1666
+ /**
1667
+ * Confirm a donation that was already sent by the client (signAndSendTransaction path).
1668
+ */
1669
+ confirmGameDonationSignature(gameId: string, amountMinor: number, signature: string): Promise<{
1670
+ signature: string;
1671
+ status: string;
1672
+ }>;
1458
1673
  /**
1459
1674
  * One-call donation flow: prepare -> sign -> submit.
1675
+ * Automatically uses the right signing path (embedded vs injected wallet).
1460
1676
  */
1461
1677
  sendDonation(gameId: string, amountMinor: number): Promise<DonateToGameResponse>;
1462
1678
  /**
@@ -1466,249 +1682,6 @@ declare class Games {
1466
1682
  notifyRematchLobbyCreated(gameId: string, lobbyId: string): Promise<void>;
1467
1683
  }
1468
1684
 
1469
- /** A player currently in an active game; used for "Live now" and "Who to watch" UI. */
1470
- interface LivePlayer {
1471
- userId: string;
1472
- username: string;
1473
- avatar?: string;
1474
- gameId: string;
1475
- gameType: string;
1476
- spectatorCount: number;
1477
- }
1478
- /** Paginated response for live players (newest first, sample of games per page). */
1479
- interface LivePlayersPage {
1480
- items: LivePlayer[];
1481
- nextCursor: string | null;
1482
- }
1483
- /**
1484
- * SDK class for spectate discovery — finding who to watch.
1485
- *
1486
- * @example
1487
- * ```ts
1488
- * const page = await sdk.spectate.getLivePlayers({ limit: 10 });
1489
- * console.log(page.items); // LivePlayer[]
1490
- * ```
1491
- */
1492
- declare class Spectate {
1493
- private http;
1494
- private logger?;
1495
- constructor(http: IHttpClient, logger?: ILogger | undefined);
1496
- /**
1497
- * Get list of live players (one per unique player), sampled from newest games, paginated.
1498
- * Use for "Live now" and "Who to watch" UI; link to /spectate/:username.
1499
- * @param options.limit - Number of games to consider per page (1–20, default 10).
1500
- * @param options.cursor - Opaque cursor from previous page for next page.
1501
- */
1502
- getLivePlayers(options?: {
1503
- limit?: number;
1504
- cursor?: string;
1505
- }): Promise<LivePlayersPage>;
1506
- }
1507
-
1508
- /**
1509
- * Retry configuration options
1510
- */
1511
- interface RetryOptions {
1512
- /** Maximum number of retry attempts (default: 3) */
1513
- maxAttempts?: number;
1514
- /** Base delay in milliseconds (default: 1000) */
1515
- baseDelayMs?: number;
1516
- /** Maximum delay in milliseconds (default: 10000) */
1517
- maxDelayMs?: number;
1518
- /** Multiplier for exponential backoff (default: 2) */
1519
- backoffMultiplier?: number;
1520
- /** Function to determine if error is retryable (default: network/5xx errors) */
1521
- isRetryable?: (error: unknown) => boolean;
1522
- /** Callback for each retry attempt */
1523
- onRetry?: (attempt: number, error: unknown, delayMs: number) => void;
1524
- }
1525
- /**
1526
- * Default function to determine if an error is retryable.
1527
- * Retries on network errors and 5xx server errors.
1528
- */
1529
- declare function isRetryableError(error: unknown): boolean;
1530
- /**
1531
- * Execute an async function with exponential backoff retry.
1532
- *
1533
- * @param fn - Async function to execute
1534
- * @param options - Retry configuration
1535
- * @returns Promise resolving to the function result
1536
- * @throws Last error if all retries exhausted
1537
- *
1538
- * @example
1539
- * ```typescript
1540
- * const result = await withRetry(
1541
- * () => fetch('/api/data'),
1542
- * { maxAttempts: 3, baseDelayMs: 500 }
1543
- * );
1544
- * ```
1545
- */
1546
- declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
1547
-
1548
- type ChatContextType = 'lobby' | 'game' | 'dm' | 'global';
1549
- interface ChatContext {
1550
- type: ChatContextType;
1551
- id: string;
1552
- }
1553
- interface SendMessageRequest {
1554
- message: string;
1555
- replyTo?: ChatMessageReply;
1556
- gifUrl?: string;
1557
- }
1558
- interface DmThread {
1559
- dmKey: string;
1560
- otherUser: PublicUser;
1561
- lastMessage: string | null;
1562
- lastMessageAt: string | null;
1563
- lastMessageSenderId: string | null;
1564
- lastMessageSenderUsername: string | null;
1565
- unreadCount: number;
1566
- }
1567
- declare class Chat {
1568
- private http;
1569
- private logger?;
1570
- private retryOptions;
1571
- constructor(http: IHttpClient, logger?: any | undefined, retryOptions?: RetryOptions);
1572
- private encodeContextId;
1573
- /**
1574
- * Send a chat message with automatic retry on transient failures
1575
- *
1576
- * @param clientMessageId - Optional client-generated ID for optimistic UI.
1577
- * Echoed back in response metadata for deduplication.
1578
- */
1579
- sendMessage(context: ChatContext, message: string, replyTo?: ChatMessageReply, gifUrl?: string, clientMessageId?: string): Promise<ChatMessage>;
1580
- /** Response from paginated chat history */
1581
- getChatHistory(context: ChatContext, limit?: number, cursor?: string): Promise<ChatMessage[]>;
1582
- /**
1583
- * Get chat history with pagination support.
1584
- * Returns messages and a cursor for loading older messages.
1585
- * For global context, uses the public endpoint so it works without auth.
1586
- */
1587
- getChatHistoryPaginated(context: ChatContext, limit?: number, cursor?: string): Promise<{
1588
- messages: ChatMessage[];
1589
- nextCursor: string | null;
1590
- }>;
1591
- /**
1592
- * Add a reaction to a message
1593
- */
1594
- addReaction(context: ChatContext, messageId: string, emoji: string): Promise<ChatMessage>;
1595
- /**
1596
- * Remove a reaction from a message
1597
- */
1598
- removeReaction(context: ChatContext, messageId: string, emoji: string): Promise<ChatMessage>;
1599
- /**
1600
- * Mark a message as read
1601
- */
1602
- markAsRead(context: ChatContext, messageId: string): Promise<ChatMessage>;
1603
- listDmThreads(): Promise<DmThread[]>;
1604
- getDmThread(dmKey: string): Promise<DmThread>;
1605
- /**
1606
- * Mark all messages in a DM thread as read
1607
- */
1608
- markDmThreadAsRead(dmKey: string): Promise<{
1609
- markedCount: number;
1610
- }>;
1611
- /**
1612
- * Accept a global chat challenge. Returns the lobby (and gameId if started).
1613
- */
1614
- acceptGlobalChallenge(challengeId: string): Promise<{
1615
- lobbyId: string;
1616
- gameId?: string;
1617
- status: string;
1618
- }>;
1619
- /**
1620
- * Broadcast a tip message to global chat (call after the user has signed and submitted the transfer).
1621
- */
1622
- broadcastGlobalTip(recipientUserId: string, amount: number): Promise<ChatMessage>;
1623
- }
1624
-
1625
- interface CreateChallengeRequest {
1626
- gameType: string;
1627
- amount: number;
1628
- targetUserId?: string;
1629
- targetUsername?: string;
1630
- /** When set, post challenge system message to this DM thread (format: "userId1:userId2" sorted). */
1631
- dmKey?: string;
1632
- }
1633
- interface CreateChallengeResponse {
1634
- challengeId: string;
1635
- challengerId: string;
1636
- targetUserId: string;
1637
- gameType: string;
1638
- amountMinor: number;
1639
- challengerUsername?: string;
1640
- }
1641
- interface AcceptChallengeResponse {
1642
- lobbyId: string;
1643
- gameId?: string;
1644
- status: string;
1645
- }
1646
- declare class Challenges {
1647
- private http;
1648
- private logger?;
1649
- constructor(http: IHttpClient, logger?: any | undefined);
1650
- /**
1651
- * Create a challenge (any user can challenge any other user by id or username).
1652
- */
1653
- create(dto: CreateChallengeRequest): Promise<CreateChallengeResponse>;
1654
- /**
1655
- * Accept a challenge. Only the challenged user can accept. Creates a lobby with the challenge amount and adds both users.
1656
- */
1657
- accept(challengeId: string): Promise<AcceptChallengeResponse>;
1658
- /**
1659
- * Decline a challenge. Only the challenged user can decline. Optionally post a "declined" message to the DM thread.
1660
- */
1661
- decline(challengeId: string, dmKey?: string): Promise<{
1662
- message?: string;
1663
- }>;
1664
- }
1665
-
1666
- interface PrepareTipRequest {
1667
- recipientUsername: string;
1668
- amount: number;
1669
- }
1670
- interface PrepareTipResponse {
1671
- transaction: string;
1672
- fee: number;
1673
- totalAmount: number;
1674
- recipientAddress: string;
1675
- recipientUserId: string;
1676
- recipientUsername: string;
1677
- amount: number;
1678
- }
1679
- interface BroadcastTipRequest {
1680
- recipientUserId: string;
1681
- amount: number;
1682
- }
1683
- interface SendTipResponse extends SubmitTransferResponse {
1684
- recipientAddress: string;
1685
- recipientUserId: string;
1686
- recipientUsername: string;
1687
- amount: number;
1688
- fee: number;
1689
- totalAmount: number;
1690
- message: ChatMessage;
1691
- }
1692
- /**
1693
- * Tips are a shorthand for wallet send + global tip broadcast.
1694
- */
1695
- declare class Tips {
1696
- private http;
1697
- private wallet;
1698
- private chat;
1699
- private logger?;
1700
- constructor(http: IHttpClient, wallet: Wallet, chat: Chat, logger?: any | undefined);
1701
- prepare(dto: PrepareTipRequest): Promise<PrepareTipResponse>;
1702
- /**
1703
- * Broadcast a tip message to global chat (call after the transfer has been submitted).
1704
- */
1705
- broadcast(dto: BroadcastTipRequest): Promise<ChatMessage>;
1706
- /**
1707
- * One-call tip flow: prepare -> sign -> submit transfer -> broadcast tip message.
1708
- */
1709
- send(recipientUsername: string, amount: number): Promise<SendTipResponse>;
1710
- }
1711
-
1712
1685
  type WsEventName = 'lobby:created' | 'lobby:updated' | 'lobby:player:joined' | 'lobby:player:left' | 'lobby:player:connected' | 'lobby:player:disconnected' | 'lobby:bet:updated' | 'lobby:invitation' | 'lobby:deleted' | 'lobby:queue:joined' | 'lobby:queue:cancelled' | 'lobby:matched' | 'lobby:deposit:updated' | 'lobby:typing:start' | 'lobby:typing:stop' | 'game:updated' | 'game:completed' | 'game:paid' | 'game:abandoned' | 'game:turn' | 'game:move' | 'game:state' | 'game:player:connected' | 'game:player:disconnected' | 'game:rps:starting' | 'game:rps:round:started' | 'game:rps:action:received' | 'game:rps:timer:cutoff' | 'game:rps:round:reveal' | 'game:rps:round:completed' | 'game:rps:timeout' | 'game:rematch:requested' | 'game:rematch:cancelled' | 'game:rematch:started' | 'game:rematch:lobby:created' | 'game:pot:updated' | 'game:market:price:updated' | 'game:market:order:filled' | 'game:market:resolved' | 'spectator:count:updated' | 'chat:message' | 'chat:reaction' | 'chat:read' | 'chat:typing' | 'notification';
1713
1686
  type GameTurnPayload = {
1714
1687
  turn: number;
@@ -1815,10 +1788,10 @@ type MarketResolvedPayload = {
1815
1788
  type LobbyDepositUpdatedPayload = {
1816
1789
  lobbyId: string;
1817
1790
  userId: string;
1818
- status: string;
1791
+ status: 'confirmed' | 'failed' | 'refunded' | 'refund_failed';
1819
1792
  allConfirmed: boolean;
1820
1793
  };
1821
- type WsEvent = {
1794
+ type WsEventBase = {
1822
1795
  event: 'lobby:created';
1823
1796
  payload: Lobby;
1824
1797
  } | {
@@ -2016,17 +1989,282 @@ type WsEvent = {
2016
1989
  event: 'notification';
2017
1990
  payload: unknown;
2018
1991
  };
1992
+ type WsEvent = WsEventBase & {
1993
+ _serverTs?: number;
1994
+ };
1995
+
1996
+ type LobbyMatchedEvent = {
1997
+ gameId: string;
1998
+ gameType: string;
1999
+ matchedLobbies: Lobby[];
2000
+ };
2001
+ type LobbyStoreState = {
2002
+ lobbiesById: Record<string, Lobby>;
2003
+ matchedEvent: LobbyMatchedEvent | null;
2004
+ typingByLobbyId: Record<string, string[]>;
2005
+ depositStatusByLobbyId: Record<string, LobbyDepositUpdatedPayload>;
2006
+ };
2007
+ type LobbyStore = {
2008
+ store: SdkStore<LobbyStoreState>;
2009
+ setBaseState: (lobbies: Lobby[]) => void;
2010
+ applyWsEvent: (event: WsEvent) => void;
2011
+ joinLobby: (lobbyId: string) => () => void;
2012
+ subscribeMatched: (callback: (event: LobbyMatchedEvent) => void) => () => void;
2013
+ subscribeDepositUpdate: (lobbyId: string, callback: (data: LobbyDepositUpdatedPayload) => void) => () => void;
2014
+ };
2015
+ declare function createLobbyStore(transport: WsTransport): LobbyStore;
2016
+
2017
+ interface BetOption {
2018
+ amount: MoneyMinor;
2019
+ playersOnline: number;
2020
+ estimatedTime: string;
2021
+ }
2022
+ interface LobbyPlayer {
2023
+ userId: string;
2024
+ username?: string;
2025
+ avatar?: string;
2026
+ joinedAt: string;
2027
+ connected?: boolean;
2028
+ /** USDC balance in minor units (cached, short TTL). Shown in lobby and used to gate Start Game. */
2029
+ usdcBalance?: number;
2030
+ }
2031
+ interface Lobby {
2032
+ id: string;
2033
+ gameType: string;
2034
+ gameName: string;
2035
+ status: 'waiting' | 'preparing' | 'queued' | 'active';
2036
+ creatorId: string;
2037
+ maxPlayers: number;
2038
+ betAmount?: MoneyMinor;
2039
+ betOptions?: BetOption[];
2040
+ gameId?: string;
2041
+ createdAt: string;
2042
+ updatedAt: string;
2043
+ players: LobbyPlayer[];
2044
+ }
2045
+ interface CreateLobbyRequest {
2046
+ gameType: string;
2047
+ }
2048
+ interface InviteFriendRequest {
2049
+ friendId: string;
2050
+ }
2051
+ interface QueueStats {
2052
+ totalPlayersInQueue: number;
2053
+ queueSizes: Record<string, number>;
2054
+ totalQueuedLobbies: number;
2055
+ }
2056
+ type ChatMessageType = 'user' | 'system';
2057
+ type SystemMessageType = 'player_joined' | 'player_left' | 'bet_changed' | 'call_joined' | 'call_left' | 'global_help' | 'global_challenge' | 'global_tip' | 'spectator_donation' | 'challenge_accepted' | 'challenge_declined';
2058
+ interface ChatMessageReply {
2059
+ id: string;
2060
+ userId?: string;
2061
+ username?: string;
2062
+ message: string;
2063
+ }
2064
+ interface ChatReaction {
2065
+ emoji: string;
2066
+ userId: string;
2067
+ username?: string;
2068
+ createdAt: string;
2069
+ }
2070
+ interface ChatReadBy {
2071
+ userId: string;
2072
+ readAt: string;
2073
+ }
2074
+ interface ChatMessage {
2075
+ id: string;
2076
+ lobbyId: string;
2077
+ userId?: string;
2078
+ username?: string;
2079
+ avatarUrl?: string;
2080
+ message: string;
2081
+ type: ChatMessageType;
2082
+ systemType?: SystemMessageType;
2083
+ metadata?: Record<string, any>;
2084
+ replyTo?: ChatMessageReply;
2085
+ reactions?: ChatReaction[];
2086
+ readBy?: ChatReadBy[];
2087
+ createdAt: string;
2088
+ }
2089
+
2090
+ declare class Lobbies {
2091
+ private http;
2092
+ private logger?;
2093
+ private lobbyStore?;
2094
+ constructor(http: IHttpClient, logger?: ILogger | undefined);
2095
+ /** Called by SDK after the store is created so mutations can update state directly. */
2096
+ setLobbyStore(store: LobbyStore): void;
2097
+ createLobby(gameType: string, betAmount?: MoneyMinor): Promise<Lobby>;
2098
+ getLobby(lobbyId: string): Promise<Lobby>;
2099
+ inviteFriend(lobbyId: string, friendId: string): Promise<{
2100
+ message: string;
2101
+ }>;
2102
+ acceptInvite(lobbyId: string): Promise<Lobby>;
2103
+ joinLobby(lobbyId: string): Promise<Lobby>;
2104
+ removePlayer(lobbyId: string, userId: string): Promise<{
2105
+ message: string;
2106
+ }>;
2107
+ kickPlayer(lobbyId: string, userId: string): Promise<{
2108
+ message: string;
2109
+ }>;
2110
+ leaveLobby(lobbyId: string): Promise<{
2111
+ message: string;
2112
+ }>;
2113
+ joinQueue(lobbyId: string): Promise<Lobby>;
2114
+ cancelQueue(lobbyId: string): Promise<Lobby>;
2115
+ updateBetAmount(lobbyId: string, betAmount: MoneyMinor): Promise<Lobby>;
2116
+ playSound(lobbyId: string, sound: string): Promise<{
2117
+ success: boolean;
2118
+ }>;
2119
+ getActiveLobbies(): Promise<Lobby[]>;
2120
+ getQueueStats(): Promise<QueueStats>;
2121
+ deleteLobby(lobbyId: string): Promise<{
2122
+ message: string;
2123
+ }>;
2124
+ /**
2125
+ * Play again: Create a new lobby and prepare deposit in one flow.
2126
+ * Returns the lobby and unsigned transaction that needs to be signed.
2127
+ * @param gameType - The game type to play again
2128
+ * @param betAmount - The bet amount (same as previous game)
2129
+ * @param escrow - The escrow service instance (from sdk.escrow)
2130
+ */
2131
+ playAgain(gameType: string, betAmount: MoneyMinor, escrow: {
2132
+ prepareAndStartDeposit: (id: string) => Promise<{
2133
+ transaction: string;
2134
+ message: string;
2135
+ }>;
2136
+ }): Promise<{
2137
+ lobby: Lobby;
2138
+ unsignedTransaction: string;
2139
+ }>;
2140
+ }
2019
2141
 
2020
- type EqualityFn<T> = (a: T, b: T) => boolean;
2021
- interface SdkStore<S> {
2022
- getSnapshot(): S;
2023
- getState(): S;
2024
- setState(next: S): void;
2025
- updateState(updater: (prev: S) => S): void;
2026
- subscribe(listener: () => void): () => void;
2027
- subscribeSelector<T>(selector: (state: S) => T, listener: () => void, isEqual?: EqualityFn<T>): () => void;
2142
+ /** A player currently in an active game; used for "Live now" and "Who to watch" UI. */
2143
+ interface LivePlayer {
2144
+ userId: string;
2145
+ username: string;
2146
+ avatar?: string;
2147
+ gameId: string;
2148
+ gameType: string;
2149
+ spectatorCount: number;
2150
+ }
2151
+ /** Paginated response for live players (newest first, sample of games per page). */
2152
+ interface LivePlayersPage {
2153
+ items: LivePlayer[];
2154
+ nextCursor: string | null;
2155
+ }
2156
+ /**
2157
+ * SDK class for spectate discovery — finding who to watch.
2158
+ *
2159
+ * @example
2160
+ * ```ts
2161
+ * const page = await sdk.spectate.getLivePlayers({ limit: 10 });
2162
+ * console.log(page.items); // LivePlayer[]
2163
+ * ```
2164
+ */
2165
+ declare class Spectate {
2166
+ private http;
2167
+ private logger?;
2168
+ constructor(http: IHttpClient, logger?: ILogger | undefined);
2169
+ /**
2170
+ * Get list of live players (one per unique player), sampled from newest games, paginated.
2171
+ * Use for "Live now" and "Who to watch" UI; link to /spectate/:username.
2172
+ * @param options.limit - Number of games to consider per page (1–20, default 10).
2173
+ * @param options.cursor - Opaque cursor from previous page for next page.
2174
+ */
2175
+ getLivePlayers(options?: {
2176
+ limit?: number;
2177
+ cursor?: string;
2178
+ }): Promise<LivePlayersPage>;
2179
+ }
2180
+
2181
+ interface CreateChallengeRequest {
2182
+ gameType: string;
2183
+ amount: number;
2184
+ targetUserId?: string;
2185
+ targetUsername?: string;
2186
+ /** When set, post challenge system message to this DM thread (format: "userId1:userId2" sorted). */
2187
+ dmKey?: string;
2188
+ }
2189
+ interface CreateChallengeResponse {
2190
+ challengeId: string;
2191
+ challengerId: string;
2192
+ targetUserId: string;
2193
+ gameType: string;
2194
+ amountMinor: number;
2195
+ challengerUsername?: string;
2196
+ }
2197
+ interface AcceptChallengeResponse {
2198
+ lobbyId: string;
2199
+ gameId?: string;
2200
+ status: string;
2201
+ }
2202
+ declare class Challenges {
2203
+ private http;
2204
+ private logger?;
2205
+ constructor(http: IHttpClient, logger?: any | undefined);
2206
+ /**
2207
+ * Create a challenge (any user can challenge any other user by id or username).
2208
+ */
2209
+ create(dto: CreateChallengeRequest): Promise<CreateChallengeResponse>;
2210
+ /**
2211
+ * Accept a challenge. Only the challenged user can accept. Creates a lobby with the challenge amount and adds both users.
2212
+ */
2213
+ accept(challengeId: string): Promise<AcceptChallengeResponse>;
2214
+ /**
2215
+ * Decline a challenge. Only the challenged user can decline. Optionally post a "declined" message to the DM thread.
2216
+ */
2217
+ decline(challengeId: string, dmKey?: string): Promise<{
2218
+ message?: string;
2219
+ }>;
2220
+ }
2221
+
2222
+ interface PrepareTipRequest {
2223
+ recipientUsername: string;
2224
+ amount: number;
2225
+ supportsPresign?: boolean;
2226
+ }
2227
+ interface PrepareTipResponse {
2228
+ transaction: string;
2229
+ fee: number;
2230
+ totalAmount: number;
2231
+ recipientAddress: string;
2232
+ recipientUserId: string;
2233
+ recipientUsername: string;
2234
+ amount: number;
2235
+ }
2236
+ interface BroadcastTipRequest {
2237
+ recipientUserId: string;
2238
+ amount: number;
2239
+ }
2240
+ interface SendTipResponse extends SubmitTransferResponse {
2241
+ recipientAddress: string;
2242
+ recipientUserId: string;
2243
+ recipientUsername: string;
2244
+ amount: number;
2245
+ fee: number;
2246
+ totalAmount: number;
2247
+ message: ChatMessage;
2248
+ }
2249
+ /**
2250
+ * Tips are a shorthand for wallet send + global tip broadcast.
2251
+ */
2252
+ declare class Tips {
2253
+ private http;
2254
+ private wallet;
2255
+ private chat;
2256
+ private logger?;
2257
+ constructor(http: IHttpClient, wallet: Wallet, chat: Chat, logger?: any | undefined);
2258
+ prepare(dto: PrepareTipRequest): Promise<PrepareTipResponse>;
2259
+ /**
2260
+ * Broadcast a tip message to global chat (call after the transfer has been submitted).
2261
+ */
2262
+ broadcast(dto: BroadcastTipRequest): Promise<ChatMessage>;
2263
+ /**
2264
+ * One-call tip flow: prepare -> sign -> submit transfer -> broadcast tip message.
2265
+ */
2266
+ send(recipientUsername: string, amount: number): Promise<SendTipResponse>;
2028
2267
  }
2029
- declare function createSdkStore<S>(initial: S): SdkStore<S>;
2030
2268
 
2031
2269
  type NotificationEvent = {
2032
2270
  title: string;
@@ -2050,6 +2288,9 @@ type NotificationsStore = {
2050
2288
  applyWsEvent: (event: WsEvent) => void;
2051
2289
  setListFromApi: (res: PaginatedNotificationsResponse) => void;
2052
2290
  clear: () => void;
2291
+ markAsRead: (id: string) => void;
2292
+ markAllAsRead: () => void;
2293
+ dismiss: (id: string) => void;
2053
2294
  };
2054
2295
  declare function createNotificationsStore(): NotificationsStore;
2055
2296
 
@@ -2159,7 +2400,15 @@ declare class Escrow {
2159
2400
  * initializes depositStatus, and prepares the unsigned transaction in one call.
2160
2401
  * Eliminates one HTTP round-trip vs startDeposits() + prepareDepositTransaction().
2161
2402
  */
2162
- prepareAndStartDeposit(lobbyId: string): Promise<PrepareDepositResponse>;
2403
+ prepareAndStartDeposit(lobbyId: string, supportsPresign?: boolean): Promise<PrepareDepositResponse>;
2404
+ /**
2405
+ * Sign and submit a prepared (unsigned) deposit transaction using the
2406
+ * configured signer. Automatically picks the right path:
2407
+ * - Embedded wallet: signAndSendTransaction → confirmDepositSignature
2408
+ * - Injected wallet: signTransaction → submitDeposit
2409
+ * Returns the on-chain signature.
2410
+ */
2411
+ signAndSubmitPreparedDeposit(lobbyId: string, unsignedTxBase64: string): Promise<string>;
2163
2412
  /**
2164
2413
  * Submit a signed deposit transaction
2165
2414
  * The transaction will be submitted to the Solana network and confirmed
@@ -2184,8 +2433,13 @@ declare class Escrow {
2184
2433
  */
2185
2434
  depositForLobby(lobbyId: string): Promise<DepositForLobbyResponse>;
2186
2435
  /**
2187
- * Zero-polling deposit variant using server-side awaitConfirmation.
2188
- * 2 HTTP calls total, 0 client-side polling. Ideal for agents.
2436
+ * Deposit for a lobby and wait until the calling user's own deposit is confirmed.
2437
+ * Ideal for agents: returns as soon as your deposit is on-chain without waiting
2438
+ * for the other player. The server auto-joins the queue when all players deposit.
2439
+ *
2440
+ * Confirmation is handled asynchronously by the transaction queue processor.
2441
+ * This method polls the deposit status endpoint until the signature appears as
2442
+ * confirmed (up to 60 seconds).
2189
2443
  *
2190
2444
  * Automatically uses signAndSendTransaction or signTransaction based on signer capability.
2191
2445
  */
@@ -2500,7 +2754,8 @@ interface AdminMarketDetail {
2500
2754
  declare class Markets {
2501
2755
  private http;
2502
2756
  private logger?;
2503
- constructor(http: IHttpClient, logger?: ILogger | undefined);
2757
+ private wallet?;
2758
+ constructor(http: IHttpClient, logger?: ILogger | undefined, wallet?: Wallet | undefined);
2504
2759
  /**
2505
2760
  * Get the prediction market state for a game.
2506
2761
  * Returns prices, volume, collateral, and resolution status.
@@ -2529,6 +2784,15 @@ declare class Markets {
2529
2784
  * @param amountMinor - Amount to spend in USDC minor units
2530
2785
  */
2531
2786
  submitBuyOrder(gameId: string, signedTransaction: string, outcomeId: string, amountMinor: number): Promise<MarketBuyResult>;
2787
+ /**
2788
+ * Confirm a buy order that was already broadcast by the client (signAndSendTransaction path).
2789
+ */
2790
+ confirmBuyOrderSignature(gameId: string, depositSignature: string, outcomeId: string, amountMinor: number): Promise<MarketBuyResult>;
2791
+ /**
2792
+ * One-call buy order: prepare → sign → submit, automatically choosing
2793
+ * the right signing path (embedded vs injected wallet).
2794
+ */
2795
+ buy(gameId: string, outcomeId: string, amountMinor: number): Promise<MarketBuyResult>;
2532
2796
  /**
2533
2797
  * Sell shares back to the AMM pool.
2534
2798
  * @param gameId - The game ID
@@ -2562,56 +2826,6 @@ declare class Markets {
2562
2826
  }>;
2563
2827
  }
2564
2828
 
2565
- type LobbyMatchedEvent = {
2566
- gameId: string;
2567
- gameType: string;
2568
- matchedLobbies: Lobby[];
2569
- };
2570
- type LobbyStoreState = {
2571
- lobbiesById: Record<string, Lobby>;
2572
- matchedEvent: LobbyMatchedEvent | null;
2573
- typingByLobbyId: Record<string, string[]>;
2574
- depositStatusByLobbyId: Record<string, LobbyDepositUpdatedPayload>;
2575
- };
2576
- type LobbyStore = {
2577
- store: SdkStore<LobbyStoreState>;
2578
- setBaseState: (lobbies: Lobby[]) => void;
2579
- applyWsEvent: (event: WsEvent) => void;
2580
- joinLobby: (lobbyId: string) => () => void;
2581
- subscribeMatched: (callback: (event: LobbyMatchedEvent) => void) => () => void;
2582
- subscribeDepositUpdate: (lobbyId: string, callback: (data: LobbyDepositUpdatedPayload) => void) => () => void;
2583
- };
2584
- declare function createLobbyStore(transport: WsTransport): LobbyStore;
2585
-
2586
- type GameStoreState = {
2587
- gamesById: Record<string, Game>;
2588
- /** Real-time spectator counts by userId, updated via spectator:count:updated WS events. */
2589
- spectatorCounts: Record<string, number>;
2590
- };
2591
- type GameStore = {
2592
- store: SdkStore<GameStoreState>;
2593
- setBaseState: (games: Game[]) => void;
2594
- applyWsEvent: (event: WsEvent) => void;
2595
- joinGame: (gameId: string) => () => void;
2596
- /** Join the spectate channel for a user. Returns a leave function. */
2597
- joinSpectateChannel: (spectatedUserId: string) => () => void;
2598
- /** Get a snapshot of the spectator count for a user (from the store). */
2599
- getSpectatorCount: (userId: string) => number;
2600
- };
2601
- declare function createGameStore(transport: WsTransport): GameStore;
2602
-
2603
- type GameActionsStoreState = {
2604
- statesByGameId: Record<string, GameStateResponse>;
2605
- };
2606
- type GameActionsStore = {
2607
- store: SdkStore<GameActionsStoreState>;
2608
- setBaseState: (gameId: string, state: GameStateResponse) => void;
2609
- clearState: (gameId: string) => void;
2610
- applyWsEvent: (event: WsEvent) => void;
2611
- joinGame: (gameId: string) => () => void;
2612
- };
2613
- declare function createGameActionsStore(transport: WsTransport): GameActionsStore;
2614
-
2615
2829
  interface TypingUser {
2616
2830
  userId: string;
2617
2831
  username?: string;
@@ -2633,22 +2847,6 @@ type ChatStore = {
2633
2847
  };
2634
2848
  declare function createChatStore(transport: WsTransport): ChatStore;
2635
2849
 
2636
- type DmThreadsStoreState = {
2637
- threads: DmThread[];
2638
- loading: boolean;
2639
- error: string | null;
2640
- needsRefresh: boolean;
2641
- };
2642
- type DmThreadsStore = {
2643
- store: SdkStore<DmThreadsStoreState>;
2644
- setBaseState: (threads: DmThread[]) => void;
2645
- setLoading: (loading: boolean) => void;
2646
- setError: (error: string | null) => void;
2647
- setCurrentUserId: (userId: string | null) => void;
2648
- applyWsEvent: (event: WsEvent) => void;
2649
- };
2650
- declare function createDmThreadsStore(): DmThreadsStore;
2651
-
2652
2850
  type FriendshipStatus = 'none' | 'incoming' | 'outgoing' | 'friends';
2653
2851
  type FriendsStoreState = {
2654
2852
  /** Optimistic overrides keyed by userId. Only set when status differs from API (e.g. 'outgoing' after send, cleared when API data arrives). */
@@ -2711,6 +2909,7 @@ declare class SDK {
2711
2909
  notificationsStore: NotificationsStore;
2712
2910
  friendsStore: FriendsStore;
2713
2911
  events: WsEventBus;
2912
+ analytics: IAnalyticsClient;
2714
2913
  private wsRouter;
2715
2914
  constructor(config: SDKConfig);
2716
2915
  /**
@@ -2720,6 +2919,18 @@ declare class SDK {
2720
2919
  * to be connected to the app via WebSocket.
2721
2920
  */
2722
2921
  ensureWebSocketConnected(timeoutMs?: number): Promise<void>;
2922
+ /**
2923
+ * Handle the full deposit-to-queue lifecycle for a lobby.
2924
+ *
2925
+ * After the deposit is confirmed, the backend may not have processed the
2926
+ * `lobby.deposit.allConfirmed` event yet, so the lobby can still be in
2927
+ * 'preparing' status. This method re-fetches the lobby and explicitly
2928
+ * joins the queue if needed, then pushes the latest state to the store
2929
+ * so the UI transitions immediately.
2930
+ */
2931
+ depositAndJoinQueue(lobbyId: string): Promise<DepositForLobbyResponse & {
2932
+ lobby: Lobby;
2933
+ }>;
2723
2934
  }
2724
2935
 
2725
2936
  /**
@@ -2757,16 +2968,16 @@ declare abstract class BaseWsTransport implements WsTransport {
2757
2968
  }
2758
2969
 
2759
2970
  declare class StandaloneWsTransport extends BaseWsTransport {
2971
+ private static readonly FAST_RETRY_LIMIT;
2972
+ private static readonly FAST_RETRY_DELAY_MS;
2973
+ private static readonly MAX_BACKOFF_MS;
2760
2974
  private socket;
2761
2975
  private url;
2762
2976
  private accessToken;
2763
2977
  private reconnectAttempts;
2764
2978
  private reconnectTimer;
2765
- private periodicReconnectInterval;
2766
- private maxReconnectAttempts;
2767
- private reconnectDelay;
2768
- private reconnectDelayMax;
2769
- private static readonly PERIODIC_RECONNECT_MS;
2979
+ private needsReconnect;
2980
+ private visibilityHandler;
2770
2981
  private wildcardHandlers;
2771
2982
  private eventHandlers;
2772
2983
  private registeredEvents;
@@ -2785,8 +2996,7 @@ declare class StandaloneWsTransport extends BaseWsTransport {
2785
2996
  private reconnectWithAuth;
2786
2997
  /** Clear socket reference so ensureSocket() can create a new connection. */
2787
2998
  private clearSocketForReconnect;
2788
- private clearPeriodicReconnect;
2789
- private startPeriodicReconnect;
2999
+ private reconnectImmediately;
2790
3000
  private scheduleReconnect;
2791
3001
  private getEventHandlers;
2792
3002
  private unsubscribeEvent;
@@ -2800,6 +3010,10 @@ declare class StandaloneWsTransport extends BaseWsTransport {
2800
3010
  declare class SharedWorkerTransport extends BaseWsTransport {
2801
3011
  private client;
2802
3012
  private url;
3013
+ /** Tracks whether a successful connection has been established at least once,
3014
+ * so that subsequent ws_open events are treated as reconnects and the
3015
+ * `connection:reconnected` event is dispatched to subscribers. */
3016
+ private hasConnectedBefore;
2803
3017
  constructor(workerUrl: string, socketUrl: string);
2804
3018
  connect(): void;
2805
3019
  disconnect(): void;
@@ -2843,4 +3057,4 @@ declare class HttpClient implements IHttpClient {
2843
3057
  private payChallenge;
2844
3058
  }
2845
3059
 
2846
- export { type AcceptChallengeResponse, type Achievement, Activity, type ActivityFeedItem, type ActivityFeedItemType, type ActivityFeedResponse, type ActivityFeedUser, Admin, type AdminDailyStats, type AdminDailyStatsItem, type AdminGameHistory, type AdminGameHistoryFeeBreakdown, type AdminGameHistoryFeePlayer, type AdminGameHistoryPlayer, type AdminMarketDailyStats, type AdminMarketDailyStatsItem, type AdminMarketDetail, type AdminMarketStats, type AdminStats, type AdminWalletActivityItem, type AdminWalletActivityResponse, type ApiError, type AppNotification, type AppNotificationType, type ApplyReferralCodeResponse, type BalanceResponse, type BetOption, type BroadcastTipRequest, BrowserLocalStorage, Challenges, Chat, type ChatContext, type ChatContextType, type ChatMessage, type ChatMessageReply, type ChatMessageType, type ChatReaction, type ChatReadBy, type ChatState, type ChatStore, type ChatStoreState, type ClaimReferralRewardsResponse, type CreateChallengeRequest, type CreateChallengeResponse, type CreateLobbyRequest, type CreateTicketData, type CriticalIncident, type CriticalIncidentCategory, type CriticalIncidentImpactType, type CriticalIncidentSeverity, type CriticalIncidentStatus, type CriticalIncidentSummary, type CurrentGame, Daily, type DailyParticipant, type DailyRoom, type DailyToken, type DepositForLobbyResponse, type DepositStatus, type DepositStatusResponse, type DmThread, type DmThreadsStore, type DmThreadsStoreState, type DonateToGameResponse, ESTIMATED_SOL_FEE_LAMPORTS, Escrow, type EscrowSweepPreview, type EscrowSweepRecord, type FaucetResponse, type FeatureFlag, type FriendRequestItem, type FriendsStore, type FriendsStoreState, type FriendshipStatus, type Game, type GameActionsStore, type GameActionsStoreState, type GameHistoryItem, type GameMetrics, type GamePlayer, type GameStateResponse, type GameStore, type GameStoreState, type GameType, Games, type GenerateHandshakeResponse, type GetTicketsOptions, HttpClient, type IHttpClient, type ILogger, type IStorage, type ImageUploadPayload, type InviteFriendRequest, type LeaderboardEntry, type LeaderboardQuery, type LeaderboardRange, type LeaderboardResponse, Leaderboards, type LivePlayer, type LivePlayersPage, Lobbies, type Lobby, type LobbyDepositUpdatedPayload, type LobbyMatchedEvent, type LobbyPlayer, type LobbyStore, type LobbyStoreState, type LogLevel, type LoginResponse, MIN_SOL_TRANSFER_AMOUNT, MIN_TRANSFER_AMOUNT, type MarketBuyResult, type MarketPosition, type MarketSellResult, type MarketState, Markets, type MoneyMinor, NodeStorage, type NotificationEvent, type NotificationsStore, type NotificationsStoreState, type PaginatedCriticalIncidents, type PaginatedFriends, type PaginatedNotificationsResponse, type PaginatedPlatformFees, type PaginatedReports, type PaginatedSearchUsers, type PaginatedSessions, type PaginatedSupportTickets, type PaginatedTransactionJobs, type PaginatedUsers, type PaymentRequiredChallenge, type PlatformFeeItem, type PrepareDepositResponse, type PrepareTipRequest, type PrepareTipResponse, type PrepareTransferRequest, type PrepareTransferResponse, type PublicUser, type QueueStats, type RedeemResult, type ReferralRewardItem, type ReferralRewardStatus, type ReferralRewardsResponse, type ReferralSummary, type ReferralTreeItem, type ReferralTreeResponse, Referrals, type Report, type ReportCount, type ReportStatus, type ReportUser, Reports, type RetryOptions, SDK, type SDKConfig, SDK_VERSION, SOL_DECIMALS, SOL_MINT, type SdkStore, type SdkUpgradeInfo, type SearchUser, type SendMessageRequest, type SendTipResponse, type SendTransferResponse, type Session, SharedWorkerTransport, Spectate, type SpectatorMetrics, type SpectatorMetricsByUser, StandaloneWsTransport, type SubmitDepositResponse, type SubmitTransferRequest, type SubmitTransferResponse, Support, type SupportMessage, type SupportMessageSenderRole, type SupportTicket, type SupportTicketCategory, type SupportTicketPriority, type SupportTicketStatus, type SupportTicketUser, type SystemMessageType, TOKEN_KEY, TRANSFER_FEE_MINOR, Tips, type TransactionJob, type TransactionJobStatus, type TransactionJobType, type TransactionQueueStats, type TransferToken, type TypingUser, type UpdateTicketData, type User, type UserAchievement, type UserActivity, type UserActivityStatus, type UserStats, type UsernameAvailabilityResponse, Users, type ValidAction, Wallet, type WalletActivityCounterpartyType, type WalletActivityDirection, type WalletActivityItem, type WalletActivityKind, type WalletActivityResponse, type WalletActivityStatus, type WalletClaimAction, type WalletMeta, type WalletResponse, type WalletSigner, type WsEvent, WsEventBus, type WsEventName, type WsTransport, type ConnectionState as WsTransportState, createChatStore, createDmThreadsStore, createFriendsStore, createGameActionsStore, createGameStore, createLobbyStore, createLogger, createNotificationsStore, createSdkStore, isRetryableError, logger, withRetry };
3060
+ export { type AcceptChallengeResponse, type Achievement, Activity, type ActivityFeedItem, type ActivityFeedItemType, type ActivityFeedResponse, type ActivityFeedUser, Admin, type AdminDailyStats, type AdminDailyStatsItem, type AdminFeatureFlag, type AdminGameHistory, type AdminGameHistoryFeeBreakdown, type AdminGameHistoryFeePlayer, type AdminGameHistoryPlayer, type AdminMarketDailyStats, type AdminMarketDailyStatsItem, type AdminMarketDetail, type AdminMarketStats, type AdminStats, type AdminWalletActivityItem, type AdminWalletActivityResponse, type AnalyticsUserData, type ApiError, type AppNotification, type AppNotificationType, type ApplyReferralCodeResponse, type BalanceResponse, type BetOption, type BroadcastTipRequest, BrowserLocalStorage, Challenges, Chat, type ChatContext, type ChatContextType, type ChatMessage, type ChatMessageReply, type ChatMessageType, type ChatReaction, type ChatReadBy, type ChatState, type ChatStore, type ChatStoreState, type ChessCapturedPieces, type ChessClockTimes, type ClaimReferralRewardsResponse, type Connect4ClockTimes, type CreateChallengeRequest, type CreateChallengeResponse, type CreateLobbyRequest, type CreateTicketData, type CriticalIncident, type CriticalIncidentCategory, type CriticalIncidentImpactType, type CriticalIncidentSeverity, type CriticalIncidentStatus, type CriticalIncidentSummary, type CurrentGame, Daily, type DailyParticipant, type DailyRoom, type DailyToken, type DepositForLobbyResponse, type DepositStatus, type DepositStatusResponse, type DmThread, type DmThreadsStore, type DmThreadsStoreState, type DonateToGameResponse, ESTIMATED_SOL_FEE_LAMPORTS, Escrow, type EscrowSweepPreview, type EscrowSweepRecord, type FaucetResponse, type FeatureFlag, type FriendRequestItem, type FriendsStore, type FriendsStoreState, type FriendshipStatus, type Game, type GameActionsStore, type GameActionsStoreState, type GameHistoryItem, type GameLifecycleState, type GameMetrics, type GamePlayer, type GameStateResponse, type GameStore, type GameStoreState, type GameType, Games, type GenerateHandshakeResponse, type GetTicketsOptions, HttpClient, type IAnalyticsClient, type IHttpClient, type ILogger, type IStorage, type ImageUploadPayload, type InviteFriendRequest, type LeaderboardEntry, type LeaderboardQuery, type LeaderboardRange, type LeaderboardResponse, Leaderboards, type LivePlayer, type LivePlayersPage, Lobbies, type Lobby, type LobbyDepositUpdatedPayload, type LobbyMatchedEvent, type LobbyPlayer, type LobbyStore, type LobbyStoreState, type LogLevel, type LoginResponse, MIN_SOL_TRANSFER_AMOUNT, MIN_TRANSFER_AMOUNT, type MarketBuyResult, type MarketPosition, type MarketSellResult, type MarketState, Markets, type MoneyMinor, NodeStorage, NoopAnalyticsClient, type NotificationEvent, type NotificationsStore, type NotificationsStoreState, type PaginatedCriticalIncidents, type PaginatedFriendRequests, type PaginatedFriends, type PaginatedNotificationsResponse, type PaginatedPlatformFees, type PaginatedReports, type PaginatedSearchUsers, type PaginatedSessions, type PaginatedSupportTickets, type PaginatedTransactionJobs, type PaginatedUsers, type PaymentRequiredChallenge, type PlatformFeeItem, type PrepareDepositResponse, type PrepareTipRequest, type PrepareTipResponse, type PrepareTransferRequest, type PrepareTransferResponse, type PublicUser, type QueueStats, type RedeemResult, type ReferralRewardItem, type ReferralRewardStatus, type ReferralRewardsResponse, type ReferralSummary, type ReferralTreeItem, type ReferralTreeResponse, Referrals, type Report, type ReportCount, type ReportStatus, type ReportUser, Reports, type RetryOptions, SDK, type SDKConfig, SDK_VERSION, SOL_DECIMALS, SOL_MINT, type SdkStore, type SdkUpgradeInfo, type SearchUser, type SendMessageRequest, type SendTipResponse, type SendTransferResponse, type Session, type SessionStats, SharedWorkerTransport, Spectate, type SpectatorMetrics, type SpectatorMetricsByUser, StandaloneWsTransport, type SubmitDepositResponse, type SubmitTransferRequest, type SubmitTransferResponse, Support, type SupportMessage, type SupportMessageSenderRole, type SupportTicket, type SupportTicketCategory, type SupportTicketPriority, type SupportTicketStatus, type SupportTicketUser, type SystemMessageType, TOKEN_KEY, TRANSFER_FEE_MINOR, type TicTacToeClockTimes, Tips, type TransactionJob, type TransactionJobStatus, type TransactionJobType, type TransactionQueueStats, type TransferToken, type TypingUser, type UpdateTicketData, type User, type UserAchievement, type UserActivity, type UserActivityStatus, type UserStats, type UsernameAvailabilityResponse, Users, type ValidAction, Wallet, type WalletActivityCounterpartyType, type WalletActivityDirection, type WalletActivityItem, type WalletActivityKind, type WalletActivityResponse, type WalletActivityStatus, type WalletClaimAction, type WalletMeta, type WalletResponse, type WalletSigner, type WsEvent, WsEventBus, type WsEventName, type WsTransport, type ConnectionState as WsTransportState, createChatStore, createDmThreadsStore, createFriendsStore, createGameActionsStore, createGameStore, createLobbyStore, createLogger, createNotificationsStore, createSdkStore, isRetryableError, logger, selectGameLifecycleState, withRetry };