@pokertools/sdk 1.0.9 → 1.0.10

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/README.md CHANGED
@@ -7,14 +7,12 @@ The official TypeScript SDK for the **PokerTools** platform. Build real-time Tex
7
7
 
8
8
  ## ✨ Features
9
9
 
10
- - 🔌 **Real-time WebSocket Client**: Automatic reconnection, heartbeats, and typed events.
11
- - 🎣 **React Hooks**: `useTable`, `usePoker`, `useUser` for seamless UI integration.
12
- - 🔐 **Authentication**: Built-in support for Sign-In with Ethereum (SIWE).
13
- - 🛡️ **Type-Safe**: Full TypeScript support with shared types from the core engine.
14
- - 🔄 **State Management**: Automatic synchronization of game state (snapshots + delta updates).
15
- - 💰 **Financials**: Deposit, withdrawal, and chip management utilities.
16
- - 🔐 **Replay-safe Withdrawals**: Helpers generate nonce/timestamp withdrawal messages for the current API contract.
17
- - 🔒 **Safer WebSocket Auth**: JWTs are sent as WebSocket subprotocol credentials, not query-string parameters.
10
+ - 🔌 **Real-time WebSocket Client**: Automatic reconnection, heartbeats, and typed events. JWTs are sent as WebSocket subprotocol credentials (not in the URL query string) to avoid leaking tokens in access logs.
11
+ - 🎣 **React Hooks**: `PokerProvider`, `usePoker`, `usePokerClient`, `usePokerSocket`, `useTable`, `useUser`, `useTables`, `useConnection` for seamless UI integration.
12
+ - 🔐 **Authentication**: Built-in support for Sign-In with Ethereum (SIWE), nonce/lifecycle helpers, and replay-safe withdrawal message generation.
13
+ - 🛡️ **Type-Safe**: Full TypeScript support with shared types re-exported from `@pokertools/types`.
14
+ - 🔄 **State Management**: Automatic synchronization of game state (snapshots + delta updates) with version-tracking and conditional fetching.
15
+ - 💰 **Financials**: Deposit, withdrawal, and chip management utilities with full REST client coverage.
18
16
 
19
17
  ## 📦 Installation
20
18
 
@@ -26,32 +24,64 @@ yarn add @pokertools/sdk @pokertools/types
26
24
  pnpm add @pokertools/sdk @pokertools/types
27
25
  ```
28
26
 
27
+ `@pokertools/sdk` (v1.0.10) depends on `@pokertools/types` (v1.0.10) for shared TypeScript types.
28
+ The React hooks require `react >= 19.2.3` as an **optional** peer dependency — install `react`
29
+ and `react-dom` only if you plan to use the React integration.
30
+
31
+ Requires **Node.js >= 24.0.0**.
32
+
29
33
  ## 🚀 Quick Start (React)
30
34
 
31
- Wrap your application in the `PokerProvider` and use the hooks to interact with the game.
35
+ Wrap your application in `PokerProvider` and use the hooks to interact with tables, user profile, and connection state.
32
36
 
33
37
  ```tsx
34
38
  import React from "react";
35
- import { PokerProvider, useTable } from "@pokertools/sdk/react";
39
+ import {
40
+ PokerProvider,
41
+ useTable,
42
+ usePoker,
43
+ useUser,
44
+ useTables,
45
+ useConnection,
46
+ } from "@pokertools/sdk/react";
36
47
 
37
48
  const config = {
38
49
  baseUrl: "https://api.poker.example.com",
39
- token: "YOUR_JWT_TOKEN", // Optional: can be set later via client.setToken()
50
+ token: "YOUR_JWT_TOKEN", // Optional: set later via client.setToken() or auth flow
40
51
  };
41
52
 
42
53
  export default function App() {
43
54
  return (
44
55
  <PokerProvider config={config}>
56
+ <Lobby />
45
57
  <GameTable tableId="table-123" />
46
58
  </PokerProvider>
47
59
  );
48
60
  }
49
61
 
62
+ function Lobby() {
63
+ const { tables, isLoading } = useTables();
64
+
65
+ if (isLoading) return <div>Loading tables...</div>;
66
+
67
+ return (
68
+ <ul>
69
+ {tables.map((t) => (
70
+ <li key={t.id}>
71
+ {t.name} — {t.seatedCount}/{t.maxPlayers} players
72
+ </li>
73
+ ))}
74
+ </ul>
75
+ );
76
+ }
77
+
50
78
  function GameTable({ tableId }: { tableId: string }) {
51
79
  // Automatically joins the table via WebSocket and syncs state
52
- const { state, isLoading, action } = useTable(tableId);
80
+ const { state, isLoading, error, action } = useTable(tableId);
81
+ const { profile } = useUser();
53
82
 
54
83
  if (isLoading) return <div>Loading table...</div>;
84
+ if (error) return <div>Error: {error.message}</div>;
55
85
  if (!state) return <div>Table not found</div>;
56
86
 
57
87
  return (
@@ -67,13 +97,35 @@ function GameTable({ tableId }: { tableId: string }) {
67
97
  <div className="controls">
68
98
  <button onClick={() => action("CHECK")}>Check</button>
69
99
  <button onClick={() => action("FOLD")}>Fold</button>
100
+ <button onClick={() => action("CALL")}>Call</button>
70
101
  <button onClick={() => action("BET", 100)}>Bet $1</button>
71
102
  </div>
103
+
104
+ {profile && (
105
+ <div className="player-info">
106
+ Playing as: {profile.username} | Balance: ${profile.balances.main / 100}
107
+ </div>
108
+ )}
109
+ </div>
110
+ );
111
+ }
112
+
113
+ function ConnectionStatus() {
114
+ const { isConnected, latency } = useConnection();
115
+
116
+ return (
117
+ <div className="connection-status">
118
+ {isConnected ? <span>🟢 Connected ({latency}ms)</span> : <span>🔴 Disconnected</span>}
72
119
  </div>
73
120
  );
74
121
  }
75
122
  ```
76
123
 
124
+ > **🔒 WebSocket Security:** The SDK sends the JWT as a WebSocket subprotocol
125
+ > (`Sec-WebSocket-Protocol: pokertools, jwt.<token>`) instead of appending
126
+ > `?token=...` to the URL. This prevents JWTs from being captured in server
127
+ > access logs, proxy logs, and browser history.
128
+
77
129
  ## 🏗️ Architecture
78
130
 
79
131
  The SDK bridges your frontend application with the PokerTools API and Real-time Engine.
@@ -105,12 +157,18 @@ The SDK bridges your frontend application with the PokerTools API and Real-time
105
157
 
106
158
  ### Key Components
107
159
 
108
- | Component | Description |
109
- | --------------- | -------------------------------------------------------------- |
110
- | `PokerClient` | Handles REST API requests (Tables, User, Finance). |
111
- | `PokerSocket` | Manages WebSocket connection and real-time events. |
112
- | `PokerProvider` | React Context provider that initializes the client and socket. |
113
- | `useTable` | Hook that subscribes to a specific table's updates. |
160
+ | Component | Description |
161
+ | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
162
+ | `PokerClient` | Handles REST API requests (Tables, User, Finance, Notes, Health). Auto-retry with exponential backoff. |
163
+ | `PokerSocket` | Manages WebSocket connection, auto-reconnection, heartbeats, and typed real-time events. |
164
+ | `PokerProvider` | React Context provider that initializes the client and socket. Accepts `autoConnect` prop (default `true`) to automatically connect the WebSocket when a token is present. |
165
+ | `useTable` | Hook that subscribes to a specific table's real-time updates via WebSocket (snapshots + deltas). |
166
+ | `useUser` | Hook to fetch and manage the current user's profile and balances. |
167
+ | `useTables` | Hook to fetch the list of active tables from the REST API. |
168
+ | `usePoker` | Low-level hook to access the full `PokerContextValue` (client, socket, connection state). |
169
+ | `usePokerClient` | Convenience hook to get the `PokerClient` instance. |
170
+ | `usePokerSocket` | Convenience hook to get the `PokerSocket` instance (null if not connected). |
171
+ | `useConnection` | Hook to monitor WebSocket connection state and measure latency via application-level ping. |
114
172
 
115
173
  `STATE_UPDATE` WebSocket events are lightweight version notifications. Use `getTableVersion(tableId)` to inspect the latest server version and fetch full state via REST when the version advances beyond your cached snapshot.
116
174
 
@@ -164,42 +222,360 @@ import { PokerSocket } from "@pokertools/sdk";
164
222
  const socket = new PokerSocket({
165
223
  url: "wss://api.poker.example.com/ws/play",
166
224
  token: "jwt-token",
225
+ heartbeatInterval: 25000, // default
226
+ reconnectAttempts: 10, // default
227
+ reconnectDelay: 1000, // default base delay (ms)
228
+ maxReconnectDelay: 30000, // default max delay (ms)
229
+ debug: false, // enable debug logging
167
230
  });
168
231
 
169
- await socket.connect();
170
-
171
- // The SDK does not append token=... to the URL. It connects with
232
+ // The SDK does NOT append token=... to the URL. It connects with
172
233
  // Sec-WebSocket-Protocol: pokertools, jwt.<token> to avoid leaking JWTs in logs.
173
234
 
174
- // Subscribe to table updates
235
+ // Lifecycle events
236
+ socket.on("connect", () => console.log("Connected"));
237
+ socket.on("disconnect", (reason) => console.log("Disconnected:", reason));
238
+ socket.on("reconnect", (attempt) => console.log("Reconnecting (attempt " + attempt + ")"));
239
+ socket.on("error", (error) => console.error("Socket error:", error));
240
+
241
+ await socket.connect();
242
+
243
+ // Join a table and receive initial snapshot
175
244
  const initialState = await socket.join("table-1");
176
- console.log("Initial State:", initialState);
245
+ console.log("Initial state:", initialState);
177
246
 
178
- // Listen for updates
247
+ // Listen for state updates (version-tracked; only emitted when prior snapshot is cached)
179
248
  socket.on("stateUpdate", (tableId, state) => {
180
- console.log("New State:", state);
249
+ console.log(`Table ${tableId} version:`, state.version);
181
250
  });
182
251
 
183
- socket.on("action", (tableId, playerId, type, amount) => {
184
- console.log(`Player ${playerId} did ${type}`);
252
+ // Full state snapshot (emitted on join, reconnect, and periodic sync)
253
+ socket.on("snapshot", (tableId, state) => {
254
+ console.log("Full state:", state);
185
255
  });
256
+
257
+ // Player actions
258
+ socket.on("action", (tableId, playerId, actionType, amount) => {
259
+ console.log(`Player ${playerId} did ${actionType}${amount ? " " + amount : ""}`);
260
+ });
261
+
262
+ // Inspect the latest server version without fetching full state
263
+ const version = socket.getTableVersion("table-1");
264
+
265
+ // Application-level ping (not WebSocket protocol ping)
266
+ const rtt = await socket.ping();
267
+ console.log(`Round-trip time: ${rtt}ms`);
268
+
269
+ // One-time listener
270
+ socket.once("connect", () => console.log("First connect"));
271
+
272
+ // Leave a table
273
+ socket.leave("table-1");
274
+
275
+ // Manual disconnect (stops auto-reconnect)
276
+ socket.disconnect();
186
277
  ```
187
278
 
188
279
  ## 🛠️ API Reference
189
280
 
190
- ### `useTable(tableId, options)`
281
+ ### React Hooks
282
+
283
+ #### `PokerProvider`
284
+
285
+ Props:
286
+
287
+ | Prop | Type | Default | Description |
288
+ | ------------- | ---------------- | ------- | ---------------------------------------------------------------- |
289
+ | `config` | `PokerSDKConfig` | — | SDK configuration (baseUrl, token, timeout, retry, debug, etc.). |
290
+ | `autoConnect` | `boolean` | `true` | Automatically open WebSocket when `config.token` is set. |
291
+ | `children` | `ReactNode` | — | React children. |
292
+
293
+ #### `usePoker()`
294
+
295
+ Returns the full `PokerContextValue`:
296
+
297
+ - `client`: `PokerClient` instance for REST API calls.
298
+ - `socket`: `PokerSocket | null` for WebSocket operations.
299
+ - `isAuthenticated`: `boolean` — whether a token is present.
300
+ - `connectionState`: `"disconnected" | "connecting" | "connected" | "reconnecting"`.
301
+ - `connect()`: Initiates WebSocket connection (requires token).
302
+ - `disconnect()`: Closes WebSocket connection.
303
+
304
+ #### `usePokerClient()`
305
+
306
+ Returns the `PokerClient` instance from context.
307
+
308
+ #### `usePokerSocket()`
309
+
310
+ Returns the `PokerSocket` instance (or `null` if not connected).
191
311
 
192
- | Option | Type | Default | Description |
193
- | -------------- | --------- | ----------- | ------------------------------------------- |
194
- | `autoJoin` | `boolean` | `true` | Automatically join the table via WebSocket. |
195
- | `pollInterval` | `number` | `undefined` | Fallback polling interval in ms (optional). |
312
+ #### `useUser()`
196
313
 
197
- **Returns:**
314
+ Returns:
315
+
316
+ | Field | Type | Description |
317
+ | ----------- | ---------------------- | ----------------------------------------------------------------- |
318
+ | `profile` | `UserProfile \| null` | Full profile including `username`, `address`, `role`, `balances`. |
319
+ | `balances` | `UserBalances \| null` | `{ main: number, inPlay: number }` in cents. |
320
+ | `isLoading` | `boolean` | Initial fetch in progress. |
321
+ | `error` | `Error \| null` | Fetch error if any. |
322
+ | `refresh()` | `() => Promise<void>` | Re-fetch profile from API. |
323
+
324
+ #### `useTable(tableId, options?)`
325
+
326
+ Options:
327
+
328
+ | Option | Type | Default | Description |
329
+ | -------------- | --------- | ----------- | ------------------------------------- |
330
+ | `autoJoin` | `boolean` | `true` | Auto-join table WebSocket on mount. |
331
+ | `pollInterval` | `number` | `undefined` | Fallback HTTP polling interval in ms. |
332
+
333
+ Returns:
334
+
335
+ | Field | Type | Description |
336
+ | ----------- | -------------------------------------------------- | ------------------------------------------------------------ |
337
+ | `state` | `PublicState \| null` | Current table state (cached + live). |
338
+ | `isLoading` | `boolean` | Initial fetch in progress. |
339
+ | `error` | `Error \| null` | Fetch error if any. |
340
+ | `refresh()` | `() => Promise<void>` | Re-fetch state from REST API. |
341
+ | `action()` | `(type: string, amount?: number) => Promise<void>` | Execute a game action (CHECK, FOLD, CALL, BET, RAISE, etc.). |
342
+ | `leave()` | `() => Promise<void>` | Stand from table and leave WebSocket subscription. |
343
+
344
+ #### `useTables()`
345
+
346
+ Returns:
347
+
348
+ | Field | Type | Description |
349
+ | ----------- | --------------------- | ----------------------------------- |
350
+ | `tables` | `TableListItem[]` | List of active tables from the API. |
351
+ | `isLoading` | `boolean` | Initial fetch in progress. |
352
+ | `error` | `Error \| null` | Fetch error if any. |
353
+ | `refresh()` | `() => Promise<void>` | Re-fetch tables list. |
354
+
355
+ #### `useConnection()`
356
+
357
+ Returns:
358
+
359
+ | Field | Type | Description |
360
+ | ---------------- | ------------------------------- | -------------------------------------------------- |
361
+ | `state` | `ConnectionState` | Current WebSocket connection state. |
362
+ | `isConnected` | `boolean` | `true` when fully connected. |
363
+ | `isConnecting` | `boolean` | `true` during initial handshake. |
364
+ | `isReconnecting` | `boolean` | `true` during automatic reconnection. |
365
+ | `latency` | `number \| null` | Last measured RTT in ms (requires calling `ping`). |
366
+ | `connect()` | `() => Promise<void>` | Manually initiate connection. |
367
+ | `disconnect()` | `() => void` | Manually close connection. |
368
+ | `ping()` | `() => Promise<number \| null>` | Measure round-trip time. |
369
+
370
+ ---
371
+
372
+ ### PokerClient (REST API)
373
+
374
+ The `PokerClient` class provides type-safe methods for every API endpoint. Obtain it via `new PokerClient(config)` or `usePokerClient()` in React.
375
+
376
+ #### Configuration
377
+
378
+ ```typescript
379
+ interface PokerSDKConfig {
380
+ baseUrl: string; // API base URL (e.g., "https://api.poker.example.com")
381
+ wsUrl?: string; // WebSocket URL (defaults to baseUrl with ws:// protocol)
382
+ token?: string; // JWT token
383
+ timeout?: number; // Request timeout in ms (default: 30000)
384
+ retry?: {
385
+ // Retry config
386
+ count?: number; // Max retries (default: 3)
387
+ delay?: number; // Base delay in ms (default: 1000)
388
+ backoff?: number; // Exponential multiplier (default: 2)
389
+ };
390
+ fetch?: typeof fetch; // Custom fetch implementation
391
+ WebSocket?: typeof WebSocket; // Custom WebSocket implementation
392
+ debug?: boolean; // Enable debug logging
393
+ }
394
+ ```
395
+
396
+ #### Methods
397
+
398
+ | Method | Description |
399
+ | --------------------------- | ----------------------------------------------------------------------- |
400
+ | `setToken(token)` | Update or clear the JWT. |
401
+ | `getToken()` | Get current token. |
402
+ | `isAuthenticated()` | Check if token is present. |
403
+ | `health()` | `GET /health` — health check. |
404
+ | `getNonce()` | `POST /auth/nonce` — get SIWE nonce. |
405
+ | `login(request)` | `POST /auth/login` — complete SIWE auth. |
406
+ | `logout()` | `POST /auth/logout` — revoke session. |
407
+ | `getTables()` | `GET /tables` — list active tables. |
408
+ | `createTable(config)` | `POST /tables` — create a new table. Returns `tableId`. |
409
+ | `getTableState(id, since?)` | `GET /tables/:id` — fetch state; returns `null` (via 304) if unchanged. |
410
+ | `buyIn(tableId, request)` | `POST /tables/:id/buy-in` — join a table. |
411
+ | `action(tableId, request)` | `POST /tables/:id/action` — execute game action. |
412
+
413
+ **Convenience action wrappers** (all return `Promise<PublicState>`):
414
+
415
+ | Method | Equivalent |
416
+ | ------------------------- | ------------------------------------------- |
417
+ | `fold(tableId)` | `action(id, { type: "FOLD" })` |
418
+ | `check(tableId)` | `action(id, { type: "CHECK" })` |
419
+ | `call(tableId)` | `action(id, { type: "CALL" })` |
420
+ | `bet(tableId, amount)` | `action(id, { type: "BET", amount })` |
421
+ | `raise(tableId, amount)` | `action(id, { type: "RAISE", amount })` |
422
+ | `deal(tableId)` | `action(id, { type: "DEAL" })` |
423
+ | `show(tableId, indices?)` | `action(id, { type: "SHOW", cardIndices })` |
424
+ | `muck(tableId)` | `action(id, { type: "MUCK" })` |
425
+ | `timeBank(tableId)` | `action(id, { type: "TIME_BANK" })` |
426
+
427
+ Additional REST methods:
428
+
429
+ | Method | Description |
430
+ | ------------------------------------- | ------------------------------------------------------ |
431
+ | `addChips(tableId, req)` | `POST /tables/:id/add-chips` — rebuy/top-up. |
432
+ | `stand(tableId)` | `POST /tables/:id/stand` — leave and cash out. |
433
+ | `getProfile()` | `GET /user/me` — user profile and balances. |
434
+ | `getHandHistory()` | `GET /user/history` — hand history entries. |
435
+ | `withdraw(request)` | `POST /user/withdraw` — signed withdrawal request. |
436
+ | `getWithdrawals()` | `GET /user/withdrawals` — withdrawal history. |
437
+ | `getChains()` | `GET /finance/chains` — supported blockchains/tokens. |
438
+ | `startDeposit()` | `POST /finance/deposit/start` — start deposit session. |
439
+ | `getDepositAddress()` | `GET /finance/deposit/address` — get deposit address. |
440
+ | `getDeposits()` | `GET /finance/deposits` — deposit history. |
441
+ | `getNotes()` | `GET /notes` — all player notes. |
442
+ | `getNote(targetId)` | `GET /notes/:id` — specific player note. |
443
+ | `saveNote(targetId, content, label?)` | `POST /notes` — create/update note. |
444
+ | `deleteNote(targetId)` | `DELETE /notes/:id` — delete note. |
445
+
446
+ ---
447
+
448
+ ### PokerSocket (WebSocket)
449
+
450
+ Config options (all optional except `url` and `token`):
451
+
452
+ | Option | Type | Default | Description |
453
+ | ------------------- | ------------------ | ---------------------- | ------------------------------------- |
454
+ | `url` | `string` | — | WebSocket server URL. |
455
+ | `token` | `string` | — | JWT for subprotocol authentication. |
456
+ | `heartbeatInterval` | `number` | `25000` | Application-level ping interval (ms). |
457
+ | `reconnectAttempts` | `number` | `10` | Max reconnection attempts. |
458
+ | `reconnectDelay` | `number` | `1000` | Base reconnection delay (ms). |
459
+ | `maxReconnectDelay` | `number` | `30000` | Max reconnection delay (ms). |
460
+ | `WebSocket` | `typeof WebSocket` | `globalThis.WebSocket` | Custom WebSocket impl. |
461
+ | `debug` | `boolean` | `false` | Enable debug logging. |
462
+
463
+ Static factory: `PokerSocket.fromConfig(config: PokerSDKConfig)` creates a socket from SDK config.
464
+
465
+ Methods:
466
+
467
+ | Method | Description |
468
+ | -------------------------- | -------------------------------------------------------------- |
469
+ | `connect()` | Open WebSocket connection. Returns `Promise<void>`. |
470
+ | `disconnect()` | Close connection and stop auto-reconnect. |
471
+ | `getState()` | Returns current `ConnectionState`. |
472
+ | `isConnected()` | Returns `boolean`. |
473
+ | `join(tableId)` | Join table subscription. Returns `Promise<PublicState>`. |
474
+ | `leave(tableId)` | Leave table subscription. |
475
+ | `getJoinedTables()` | Returns `string[]` of table IDs. |
476
+ | `getCachedState(tableId)` | Returns `PublicState \| undefined`. |
477
+ | `getTableVersion(tableId)` | Returns latest server version number `\| undefined`. |
478
+ | `on(event, listener)` | Subscribe to event. Returns unsubscribe function. |
479
+ | `off(event, listener)` | Unsubscribe from event. |
480
+ | `once(event, listener)` | Subscribe for a single emission. Returns unsubscribe function. |
481
+ | `ping()` | Application-level ping. Returns `Promise<number>` (RTT in ms). |
482
+
483
+ Events:
484
+
485
+ | Event | Signature | Description |
486
+ | ------------- | ---------------------------------------------------------------------------------- | ----------------------------- |
487
+ | `connect` | `() => void` | WebSocket connected. |
488
+ | `disconnect` | `(reason?: string) => void` | WebSocket disconnected. |
489
+ | `reconnect` | `(attempt: number) => void` | Reconnection started. |
490
+ | `error` | `(error: Error) => void` | Socket-level or server error. |
491
+ | `snapshot` | `(tableId: string, state: PublicState) => void` | Full table state snapshot. |
492
+ | `stateUpdate` | `(tableId: string, state: PublicState) => void` | Version-tracked delta update. |
493
+ | `action` | `(tableId: string, playerId: string, actionType: string, amount?: number) => void` | Player action observed. |
494
+
495
+ ---
496
+
497
+ ### Auth Helpers (SIWE)
498
+
499
+ Exported from `@pokertools/sdk`:
500
+
501
+ | Function | Description |
502
+ | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
503
+ | `createSiweMessage(params)` | Build an [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) SIWE message string for wallet signing. |
504
+ | `parseSiweMessage(message)` | Parse a SIWE message back into `Partial<SiweMessageParams>`. |
505
+ | `isSiweExpired(message)` | Check if a SIWE message's expiration time has passed. |
506
+ | `createWithdrawalMessage(amount, address, nonce, ts?)` | Build a replay-safe withdrawal message with nonce + timestamp. |
507
+ | `generateIdempotencyKey()` | Generate a random UUID v4 idempotency key. |
508
+
509
+ Also exported: `SiweMessageParams` type.
510
+
511
+ ---
512
+
513
+ ### Utilities
514
+
515
+ Exported from `@pokertools/sdk` (25+ helpers for formatting, state inspection, and display):
516
+
517
+ **Chip formatting:**
518
+
519
+ | Function | Description |
520
+ | ------------------------------- | --------------------------------------------------- |
521
+ | `formatChips(chips, currency?)` | Convert cents to display string (e.g., `"$10.00"`). |
522
+ | `parseChips(amount)` | Parse display string to cents. |
523
+ | `abbreviateNumber(num)` | Abbreviate (e.g., `1000` → `"1.0K"`). |
524
+
525
+ **State inspection:**
526
+
527
+ | Function | Description |
528
+ | -------------------------- | -------------------------------------------- |
529
+ | `getActivePlayer(state)` | Player whose turn it is (by `actionTo`). |
530
+ | `getPlayerById(state, id)` | Find player in state by ID. |
531
+ | `getPlayerSeat(state, id)` | Get seat index for a player. |
532
+ | `isPlayerTurn(state, id)` | Check if it's a specific player's turn. |
533
+ | `getCallAmount(state, id)` | Amount needed to call (capped by stack). |
534
+ | `getMinRaise(state)` | Minimum raise amount (minRaise or bigBlind). |
535
+ | `canCheck(state, id)` | Whether player can check. |
536
+ | `canBet(state, id)` | Whether player can open-bet. |
537
+ | `getTotalPot(state)` | Sum of main + side pots. |
538
+ | `getActivePlayers(state)` | Players with stack > 0 and not folded. |
539
+ | `getPlayersInHand(state)` | Players not folded. |
540
+ | `getPotOdds(state, id)` | Pot odds as a ratio (Infinity if no call). |
541
+ | `isShowdown(state)` | Check if street is SHOWDOWN. |
542
+ | `isHandComplete(state)` | Check if winners are determined. |
543
+
544
+ **Display helpers:**
545
+
546
+ | Function | Description |
547
+ | ----------------------- | ------------------------------------------------- |
548
+ | `suitToEmoji(suit)` | Convert suit char to emoji (e.g., `"s"` → `"♠"`). |
549
+ | `formatCard(card)` | Format card string (e.g., `"As"` → `"A♠"`). |
550
+ | `formatCards(cards)` | Format card array (null-safe). |
551
+ | `getStreetName(street)` | Convert street enum to display name. |
552
+
553
+ ---
198
554
 
199
- - `state`: The current `PublicState` of the table.
200
- - `isLoading`: Boolean indicating if initial state is being fetched.
201
- - `action(type, amount)`: Function to perform game actions.
202
- - `refresh()`: Manually re-fetch state.
555
+ ### Main Exports
556
+
557
+ #### `@pokertools/sdk` (main entry)
558
+
559
+ | Export | Kind |
560
+ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
561
+ | `PokerClient` | Class |
562
+ | `PokerSocket` | Class |
563
+ | `createSiweMessage`, `parseSiweMessage`, `isSiweExpired`, `createWithdrawalMessage`, `generateIdempotencyKey` | Function |
564
+ | `SiweMessageParams` | Type |
565
+ | `formatChips`, `parseChips`, `getActivePlayer`, `getPlayerById`, `getPlayerSeat`, `isPlayerTurn`, `getCallAmount`, `getMinRaise`, `canCheck`, `canBet`, `getTotalPot`, `getActivePlayers`, `getPlayersInHand`, `suitToEmoji`, `formatCard`, `formatCards`, `getStreetName`, `isShowdown`, `isHandComplete`, `getPotOdds`, `abbreviateNumber` | Function |
566
+ | `PokerSDKConfig`, `UserBalances`, `UserProfile`, `BlockchainInfo`, `TokenInfo`, `DepositSession`, `DepositRecord`, `WithdrawalRequest`, `WithdrawalRecord`, `HandHistoryEntry`, `PlayerNote`, `ConnectionState`, `PokerSocketEvents`, `EventListener` | Type |
567
+ | `PokerSDKError` | Class |
568
+ | `PublicState`, `PublicPlayer`, `GameState`, `Player`, `Action`, `ActionType`, `TableConfig`, `ServerMessage`, `ClientMessage`, `SnapshotMessage`, `StateUpdateMessage`, `ErrorMessage`, `JoinTableMessage`, `LeaveTableMessage`, `CreateTableRequest`, `BuyInRequest`, `AddChipsRequest`, `GameActionRequest`, `LoginRequest`, `LoginResponse`, `NonceResponse`, `TableListItem` | Type (re-exported from `@pokertools/types`) |
569
+
570
+ #### `@pokertools/sdk/react` (React subpath)
571
+
572
+ | Export | Kind |
573
+ | --------------------------------------------------------------------------------------------------- | --------- |
574
+ | `PokerProvider` | Component |
575
+ | `PokerProviderProps` | Type |
576
+ | `PokerContextValue` | Type |
577
+ | `usePoker`, `usePokerClient`, `usePokerSocket`, `useTable`, `useUser`, `useTables`, `useConnection` | Hook |
578
+ | `UseTableOptions`, `UseTableResult`, `UseUserResult`, `UseTablesResult` | Type |
203
579
 
204
580
  ---
205
581