@pokertools/sdk 1.0.4
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 +199 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/index.cjs +1126 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +750 -0
- package/dist/index.d.ts +750 -0
- package/dist/index.js +1096 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.cjs +1099 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +683 -0
- package/dist/react/index.d.ts +683 -0
- package/dist/react/index.js +1090 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,1099 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var types = require('@pokertools/types');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
// src/react/index.tsx
|
|
8
|
+
|
|
9
|
+
// src/types.ts
|
|
10
|
+
var PokerSDKError = class extends Error {
|
|
11
|
+
constructor(message, code, statusCode, details) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.statusCode = statusCode;
|
|
15
|
+
this.details = details;
|
|
16
|
+
this.name = "PokerSDKError";
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// src/client.ts
|
|
21
|
+
var DEFAULT_CONFIG = {
|
|
22
|
+
timeout: 3e4,
|
|
23
|
+
retry: {
|
|
24
|
+
count: 3,
|
|
25
|
+
delay: 1e3,
|
|
26
|
+
backoff: 2
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var PokerClient = class {
|
|
30
|
+
constructor(config) {
|
|
31
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
32
|
+
this.timeout = config.timeout ?? DEFAULT_CONFIG.timeout;
|
|
33
|
+
this.retry = {
|
|
34
|
+
count: config.retry?.count ?? DEFAULT_CONFIG.retry.count,
|
|
35
|
+
delay: config.retry?.delay ?? DEFAULT_CONFIG.retry.delay,
|
|
36
|
+
backoff: config.retry?.backoff ?? DEFAULT_CONFIG.retry.backoff
|
|
37
|
+
};
|
|
38
|
+
this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
39
|
+
this.debug = config.debug ?? false;
|
|
40
|
+
this.token = config.token ?? null;
|
|
41
|
+
}
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Configuration
|
|
44
|
+
// ============================================================================
|
|
45
|
+
/**
|
|
46
|
+
* Set the authentication token
|
|
47
|
+
*/
|
|
48
|
+
setToken(token) {
|
|
49
|
+
this.token = token;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get current token
|
|
53
|
+
*/
|
|
54
|
+
getToken() {
|
|
55
|
+
return this.token;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if client is authenticated
|
|
59
|
+
*/
|
|
60
|
+
isAuthenticated() {
|
|
61
|
+
return this.token !== null;
|
|
62
|
+
}
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// Authentication
|
|
65
|
+
// ============================================================================
|
|
66
|
+
/**
|
|
67
|
+
* Get a nonce for SIWE authentication
|
|
68
|
+
*/
|
|
69
|
+
async getNonce() {
|
|
70
|
+
const response = await this.request("POST", "/auth/nonce");
|
|
71
|
+
return response.nonce;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Login with SIWE signature
|
|
75
|
+
*/
|
|
76
|
+
async login(request) {
|
|
77
|
+
const response = await this.request("POST", "/auth/login", request);
|
|
78
|
+
this.token = response.token;
|
|
79
|
+
return response;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Logout and revoke session
|
|
83
|
+
*/
|
|
84
|
+
async logout() {
|
|
85
|
+
await this.request("POST", "/auth/logout");
|
|
86
|
+
this.token = null;
|
|
87
|
+
}
|
|
88
|
+
// ============================================================================
|
|
89
|
+
// Tables
|
|
90
|
+
// ============================================================================
|
|
91
|
+
/**
|
|
92
|
+
* Get list of active tables
|
|
93
|
+
*/
|
|
94
|
+
async getTables() {
|
|
95
|
+
const response = await this.request("GET", "/tables");
|
|
96
|
+
return response.tables;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create a new table
|
|
100
|
+
*/
|
|
101
|
+
async createTable(config) {
|
|
102
|
+
const response = await this.request("POST", "/tables", config);
|
|
103
|
+
return response.tableId;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get table state
|
|
107
|
+
* @param tableId - Table ID
|
|
108
|
+
* @param since - Optional version for conditional fetch (returns null if unchanged)
|
|
109
|
+
*/
|
|
110
|
+
async getTableState(tableId, since) {
|
|
111
|
+
const query = since !== void 0 ? `?since=${since}` : "";
|
|
112
|
+
try {
|
|
113
|
+
const response = await this.request(
|
|
114
|
+
"GET",
|
|
115
|
+
`/tables/${tableId}${query}`
|
|
116
|
+
);
|
|
117
|
+
return response.state;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (error instanceof PokerSDKError && error.statusCode === 304) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Buy in to a table
|
|
127
|
+
*/
|
|
128
|
+
async buyIn(tableId, request) {
|
|
129
|
+
await this.request("POST", `/tables/${tableId}/buy-in`, request);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Execute a game action
|
|
133
|
+
*/
|
|
134
|
+
async action(tableId, request) {
|
|
135
|
+
const response = await this.request(
|
|
136
|
+
"POST",
|
|
137
|
+
`/tables/${tableId}/action`,
|
|
138
|
+
request
|
|
139
|
+
);
|
|
140
|
+
return response.state;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Add chips to stack (rebuy/top-up)
|
|
144
|
+
*/
|
|
145
|
+
async addChips(tableId, request) {
|
|
146
|
+
await this.request("POST", `/tables/${tableId}/add-chips`, request);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Stand from table (leave and cash out)
|
|
150
|
+
*/
|
|
151
|
+
async stand(tableId) {
|
|
152
|
+
await this.request("POST", `/tables/${tableId}/stand`);
|
|
153
|
+
}
|
|
154
|
+
// ============================================================================
|
|
155
|
+
// Convenience Action Methods
|
|
156
|
+
// ============================================================================
|
|
157
|
+
/**
|
|
158
|
+
* Fold hand
|
|
159
|
+
*/
|
|
160
|
+
async fold(tableId) {
|
|
161
|
+
return this.action(tableId, { type: "FOLD" });
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Check (pass action)
|
|
165
|
+
*/
|
|
166
|
+
async check(tableId) {
|
|
167
|
+
return this.action(tableId, { type: "CHECK" });
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Call current bet
|
|
171
|
+
*/
|
|
172
|
+
async call(tableId) {
|
|
173
|
+
return this.action(tableId, { type: "CALL" });
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Place a bet
|
|
177
|
+
*/
|
|
178
|
+
async bet(tableId, amount) {
|
|
179
|
+
return this.action(tableId, { type: "BET", amount });
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Raise the current bet
|
|
183
|
+
*/
|
|
184
|
+
async raise(tableId, amount) {
|
|
185
|
+
return this.action(tableId, { type: "RAISE", amount });
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Deal new hand
|
|
189
|
+
*/
|
|
190
|
+
async deal(tableId) {
|
|
191
|
+
return this.action(tableId, { type: "DEAL" });
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Show cards at showdown
|
|
195
|
+
*/
|
|
196
|
+
async show(tableId, cardIndices) {
|
|
197
|
+
return this.action(tableId, { type: "SHOW", cardIndices });
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Muck cards at showdown
|
|
201
|
+
*/
|
|
202
|
+
async muck(tableId) {
|
|
203
|
+
return this.action(tableId, { type: "MUCK" });
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Use time bank
|
|
207
|
+
*/
|
|
208
|
+
async timeBank(tableId) {
|
|
209
|
+
return this.action(tableId, { type: "TIME_BANK" });
|
|
210
|
+
}
|
|
211
|
+
// ============================================================================
|
|
212
|
+
// User
|
|
213
|
+
// ============================================================================
|
|
214
|
+
/**
|
|
215
|
+
* Get current user profile and balances
|
|
216
|
+
*/
|
|
217
|
+
async getProfile() {
|
|
218
|
+
return this.request("GET", "/user/me");
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Get hand history
|
|
222
|
+
*/
|
|
223
|
+
async getHandHistory() {
|
|
224
|
+
const response = await this.request("GET", "/user/history");
|
|
225
|
+
return response.history;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Request a withdrawal
|
|
229
|
+
*/
|
|
230
|
+
async withdraw(request) {
|
|
231
|
+
return this.request("POST", "/user/withdraw", request);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Get withdrawal history
|
|
235
|
+
*/
|
|
236
|
+
async getWithdrawals() {
|
|
237
|
+
const response = await this.request(
|
|
238
|
+
"GET",
|
|
239
|
+
"/user/withdrawals"
|
|
240
|
+
);
|
|
241
|
+
return response.withdrawals;
|
|
242
|
+
}
|
|
243
|
+
// ============================================================================
|
|
244
|
+
// Finance
|
|
245
|
+
// ============================================================================
|
|
246
|
+
/**
|
|
247
|
+
* Get supported blockchains and tokens
|
|
248
|
+
*/
|
|
249
|
+
async getChains() {
|
|
250
|
+
return this.request("GET", "/finance/chains");
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Start deposit monitoring session
|
|
254
|
+
*/
|
|
255
|
+
async startDeposit() {
|
|
256
|
+
return this.request("POST", "/finance/deposit/start");
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Get deposit address
|
|
260
|
+
*/
|
|
261
|
+
async getDepositAddress() {
|
|
262
|
+
const response = await this.request("GET", "/finance/deposit/address");
|
|
263
|
+
return response.address;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Get deposit history
|
|
267
|
+
*/
|
|
268
|
+
async getDeposits() {
|
|
269
|
+
const response = await this.request("GET", "/finance/deposits");
|
|
270
|
+
return response.deposits;
|
|
271
|
+
}
|
|
272
|
+
// ============================================================================
|
|
273
|
+
// Notes
|
|
274
|
+
// ============================================================================
|
|
275
|
+
/**
|
|
276
|
+
* Get all notes by current user
|
|
277
|
+
*/
|
|
278
|
+
async getNotes() {
|
|
279
|
+
const response = await this.request("GET", "/notes");
|
|
280
|
+
return response.notes;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Get note for specific player
|
|
284
|
+
*/
|
|
285
|
+
async getNote(targetId) {
|
|
286
|
+
const response = await this.request("GET", `/notes/${targetId}`);
|
|
287
|
+
return response.note;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Save or update note
|
|
291
|
+
*/
|
|
292
|
+
async saveNote(targetId, content, label) {
|
|
293
|
+
const response = await this.request("POST", "/notes", {
|
|
294
|
+
targetId,
|
|
295
|
+
content,
|
|
296
|
+
label
|
|
297
|
+
});
|
|
298
|
+
return response.note;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Delete note
|
|
302
|
+
*/
|
|
303
|
+
async deleteNote(targetId) {
|
|
304
|
+
await this.request("DELETE", `/notes/${targetId}`);
|
|
305
|
+
}
|
|
306
|
+
// ============================================================================
|
|
307
|
+
// Health
|
|
308
|
+
// ============================================================================
|
|
309
|
+
/**
|
|
310
|
+
* Health check
|
|
311
|
+
*/
|
|
312
|
+
async health() {
|
|
313
|
+
return this.request("GET", "/health");
|
|
314
|
+
}
|
|
315
|
+
// ============================================================================
|
|
316
|
+
// Private Methods
|
|
317
|
+
// ============================================================================
|
|
318
|
+
/**
|
|
319
|
+
* Make HTTP request with retry logic
|
|
320
|
+
*/
|
|
321
|
+
async request(method, path, body) {
|
|
322
|
+
const url = `${this.baseUrl}${path}`;
|
|
323
|
+
const headers = {
|
|
324
|
+
"Content-Type": "application/json"
|
|
325
|
+
};
|
|
326
|
+
if (this.token) {
|
|
327
|
+
headers.Authorization = `Bearer ${this.token}`;
|
|
328
|
+
}
|
|
329
|
+
let lastError = null;
|
|
330
|
+
for (let attempt = 0; attempt <= this.retry.count; attempt++) {
|
|
331
|
+
try {
|
|
332
|
+
const controller = new AbortController();
|
|
333
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
334
|
+
if (this.debug) {
|
|
335
|
+
console.log(`[PokerSDK] ${method} ${path}`, body);
|
|
336
|
+
}
|
|
337
|
+
const response = await this.fetchFn(url, {
|
|
338
|
+
method,
|
|
339
|
+
headers,
|
|
340
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
341
|
+
signal: controller.signal
|
|
342
|
+
});
|
|
343
|
+
clearTimeout(timeoutId);
|
|
344
|
+
if (response.status === 304) {
|
|
345
|
+
throw new PokerSDKError("Not Modified", "NOT_MODIFIED", 304);
|
|
346
|
+
}
|
|
347
|
+
if (!response.ok) {
|
|
348
|
+
const errorData = await response.json().catch(() => ({}));
|
|
349
|
+
throw new PokerSDKError(
|
|
350
|
+
errorData.message ?? errorData.error ?? `HTTP ${response.status}`,
|
|
351
|
+
errorData.code ?? errorData.error ?? "HTTP_ERROR",
|
|
352
|
+
response.status,
|
|
353
|
+
errorData
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
const data = await response.json();
|
|
357
|
+
if (this.debug) {
|
|
358
|
+
console.log(`[PokerSDK] Response:`, data);
|
|
359
|
+
}
|
|
360
|
+
return data;
|
|
361
|
+
} catch (error) {
|
|
362
|
+
lastError = error;
|
|
363
|
+
if (error instanceof PokerSDKError) {
|
|
364
|
+
if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) {
|
|
365
|
+
throw error;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
369
|
+
throw new PokerSDKError("Request timeout", "TIMEOUT", void 0, {
|
|
370
|
+
timeout: this.timeout
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
if (attempt < this.retry.count) {
|
|
374
|
+
const delay = this.retry.delay * Math.pow(this.retry.backoff, attempt);
|
|
375
|
+
if (this.debug) {
|
|
376
|
+
console.log(`[PokerSDK] Retry ${attempt + 1}/${this.retry.count} in ${delay}ms`);
|
|
377
|
+
}
|
|
378
|
+
await this.sleep(delay);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
throw lastError ?? new PokerSDKError("Request failed", "REQUEST_FAILED");
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Sleep helper
|
|
386
|
+
*/
|
|
387
|
+
sleep(ms) {
|
|
388
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
var DEFAULT_SOCKET_CONFIG = {
|
|
392
|
+
heartbeatInterval: 25e3,
|
|
393
|
+
reconnectAttempts: 10,
|
|
394
|
+
reconnectDelay: 1e3,
|
|
395
|
+
maxReconnectDelay: 3e4
|
|
396
|
+
};
|
|
397
|
+
var PokerSocket = class _PokerSocket {
|
|
398
|
+
constructor(config) {
|
|
399
|
+
this.ws = null;
|
|
400
|
+
this.connectionState = "disconnected";
|
|
401
|
+
this.reconnectCount = 0;
|
|
402
|
+
this.heartbeatTimer = null;
|
|
403
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
404
|
+
this.joinedTables = /* @__PURE__ */ new Set();
|
|
405
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
406
|
+
this.shouldReconnect = true;
|
|
407
|
+
// Latest state cache for each table
|
|
408
|
+
this.stateCache = /* @__PURE__ */ new Map();
|
|
409
|
+
const wsUrl = new URL(config.url);
|
|
410
|
+
wsUrl.searchParams.set("token", config.token);
|
|
411
|
+
this.url = wsUrl.toString();
|
|
412
|
+
this.token = config.token;
|
|
413
|
+
this.heartbeatInterval = config.heartbeatInterval ?? DEFAULT_SOCKET_CONFIG.heartbeatInterval;
|
|
414
|
+
this.reconnectAttempts = config.reconnectAttempts ?? DEFAULT_SOCKET_CONFIG.reconnectAttempts;
|
|
415
|
+
this.reconnectDelay = config.reconnectDelay ?? DEFAULT_SOCKET_CONFIG.reconnectDelay;
|
|
416
|
+
this.maxReconnectDelay = config.maxReconnectDelay ?? DEFAULT_SOCKET_CONFIG.maxReconnectDelay;
|
|
417
|
+
this.WebSocketImpl = config.WebSocket ?? globalThis.WebSocket;
|
|
418
|
+
this.debug = config.debug ?? false;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Create a PokerSocket from SDK config
|
|
422
|
+
*/
|
|
423
|
+
static fromConfig(config) {
|
|
424
|
+
if (!config.token) {
|
|
425
|
+
throw new PokerSDKError("Token is required for WebSocket connection", "AUTH_REQUIRED");
|
|
426
|
+
}
|
|
427
|
+
const baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
428
|
+
const wsUrl = config.wsUrl ?? baseUrl.replace(/^http/, "ws") + "/ws/play";
|
|
429
|
+
return new _PokerSocket({
|
|
430
|
+
url: wsUrl,
|
|
431
|
+
token: config.token,
|
|
432
|
+
WebSocket: config.WebSocket,
|
|
433
|
+
debug: config.debug
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
// ============================================================================
|
|
437
|
+
// Connection Management
|
|
438
|
+
// ============================================================================
|
|
439
|
+
/**
|
|
440
|
+
* Connect to the WebSocket server
|
|
441
|
+
*/
|
|
442
|
+
connect() {
|
|
443
|
+
return new Promise((resolve, reject) => {
|
|
444
|
+
if (this.connectionState === "connected") {
|
|
445
|
+
resolve();
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
if (this.connectionState === "connecting") {
|
|
449
|
+
const checkConnection = () => {
|
|
450
|
+
if (this.connectionState === "connected") {
|
|
451
|
+
resolve();
|
|
452
|
+
} else if (this.connectionState === "disconnected") {
|
|
453
|
+
reject(new PokerSDKError("Connection failed", "CONNECTION_FAILED"));
|
|
454
|
+
} else {
|
|
455
|
+
setTimeout(checkConnection, 100);
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
checkConnection();
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
this.shouldReconnect = true;
|
|
462
|
+
this.connectionState = "connecting";
|
|
463
|
+
this.log("Connecting to", this.url);
|
|
464
|
+
try {
|
|
465
|
+
this.ws = new this.WebSocketImpl(this.url);
|
|
466
|
+
this.ws.onopen = () => {
|
|
467
|
+
this.connectionState = "connected";
|
|
468
|
+
this.reconnectCount = 0;
|
|
469
|
+
this.startHeartbeat();
|
|
470
|
+
this.emit("connect");
|
|
471
|
+
this.log("Connected");
|
|
472
|
+
void this.rejoinTables();
|
|
473
|
+
resolve();
|
|
474
|
+
};
|
|
475
|
+
this.ws.onclose = (event) => {
|
|
476
|
+
this.handleDisconnect(event.reason || "Connection closed");
|
|
477
|
+
};
|
|
478
|
+
this.ws.onerror = (event) => {
|
|
479
|
+
this.log("WebSocket error:", event);
|
|
480
|
+
if (this.connectionState === "connecting") {
|
|
481
|
+
reject(new PokerSDKError("Connection failed", "CONNECTION_FAILED"));
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
this.ws.onmessage = (event) => {
|
|
485
|
+
this.handleMessage(event.data);
|
|
486
|
+
};
|
|
487
|
+
} catch (error) {
|
|
488
|
+
this.connectionState = "disconnected";
|
|
489
|
+
reject(error);
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Disconnect from the WebSocket server
|
|
495
|
+
*/
|
|
496
|
+
disconnect() {
|
|
497
|
+
this.shouldReconnect = false;
|
|
498
|
+
this.stopHeartbeat();
|
|
499
|
+
this.clearPendingRequests("Connection closed");
|
|
500
|
+
if (this.ws) {
|
|
501
|
+
this.ws.close(1e3, "Client disconnect");
|
|
502
|
+
this.ws = null;
|
|
503
|
+
}
|
|
504
|
+
this.connectionState = "disconnected";
|
|
505
|
+
this.emit("disconnect", "Client disconnect");
|
|
506
|
+
this.log("Disconnected");
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Get current connection state
|
|
510
|
+
*/
|
|
511
|
+
getState() {
|
|
512
|
+
return this.connectionState;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Check if connected
|
|
516
|
+
*/
|
|
517
|
+
isConnected() {
|
|
518
|
+
return this.connectionState === "connected";
|
|
519
|
+
}
|
|
520
|
+
// ============================================================================
|
|
521
|
+
// Table Subscription
|
|
522
|
+
// ============================================================================
|
|
523
|
+
/**
|
|
524
|
+
* Join a table to receive real-time updates
|
|
525
|
+
*/
|
|
526
|
+
async join(tableId) {
|
|
527
|
+
if (this.connectionState !== "connected") {
|
|
528
|
+
throw new PokerSDKError("Not connected", "NOT_CONNECTED");
|
|
529
|
+
}
|
|
530
|
+
const requestId = this.generateRequestId();
|
|
531
|
+
const message = {
|
|
532
|
+
type: "JOIN",
|
|
533
|
+
tableId,
|
|
534
|
+
requestId
|
|
535
|
+
};
|
|
536
|
+
this.joinedTables.add(tableId);
|
|
537
|
+
this.send(message);
|
|
538
|
+
return new Promise((resolve, reject) => {
|
|
539
|
+
const timeout = setTimeout(() => {
|
|
540
|
+
this.pendingRequests.delete(requestId);
|
|
541
|
+
reject(new PokerSDKError("Join timeout", "TIMEOUT"));
|
|
542
|
+
}, 1e4);
|
|
543
|
+
this.pendingRequests.set(`snapshot:${tableId}`, {
|
|
544
|
+
resolve: (state) => {
|
|
545
|
+
clearTimeout(timeout);
|
|
546
|
+
resolve(state);
|
|
547
|
+
},
|
|
548
|
+
reject,
|
|
549
|
+
timeout
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Leave a table
|
|
555
|
+
*/
|
|
556
|
+
leave(tableId) {
|
|
557
|
+
if (this.connectionState !== "connected") {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
this.joinedTables.delete(tableId);
|
|
561
|
+
this.stateCache.delete(tableId);
|
|
562
|
+
const message = {
|
|
563
|
+
type: "LEAVE",
|
|
564
|
+
tableId
|
|
565
|
+
};
|
|
566
|
+
this.send(message);
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Get currently joined tables
|
|
570
|
+
*/
|
|
571
|
+
getJoinedTables() {
|
|
572
|
+
return Array.from(this.joinedTables);
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Get cached state for a table
|
|
576
|
+
*/
|
|
577
|
+
getCachedState(tableId) {
|
|
578
|
+
return this.stateCache.get(tableId);
|
|
579
|
+
}
|
|
580
|
+
// ============================================================================
|
|
581
|
+
// Event Handling
|
|
582
|
+
// ============================================================================
|
|
583
|
+
/**
|
|
584
|
+
* Subscribe to an event
|
|
585
|
+
*/
|
|
586
|
+
on(event, listener) {
|
|
587
|
+
if (!this.listeners.has(event)) {
|
|
588
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
589
|
+
}
|
|
590
|
+
this.listeners.get(event).add(listener);
|
|
591
|
+
return () => {
|
|
592
|
+
this.off(event, listener);
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Unsubscribe from an event
|
|
597
|
+
*/
|
|
598
|
+
off(event, listener) {
|
|
599
|
+
const listeners = this.listeners.get(event);
|
|
600
|
+
if (listeners) {
|
|
601
|
+
listeners.delete(listener);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Subscribe to an event (once)
|
|
606
|
+
*/
|
|
607
|
+
once(event, listener) {
|
|
608
|
+
const onceWrapper = ((...args) => {
|
|
609
|
+
this.off(event, onceWrapper);
|
|
610
|
+
listener(...args);
|
|
611
|
+
});
|
|
612
|
+
return this.on(event, onceWrapper);
|
|
613
|
+
}
|
|
614
|
+
// ============================================================================
|
|
615
|
+
// Ping
|
|
616
|
+
// ============================================================================
|
|
617
|
+
/**
|
|
618
|
+
* Send application-level ping (not WebSocket ping)
|
|
619
|
+
*/
|
|
620
|
+
async ping() {
|
|
621
|
+
if (this.connectionState !== "connected") {
|
|
622
|
+
throw new PokerSDKError("Not connected", "NOT_CONNECTED");
|
|
623
|
+
}
|
|
624
|
+
const requestId = this.generateRequestId();
|
|
625
|
+
const startTime = Date.now();
|
|
626
|
+
const message = {
|
|
627
|
+
type: "PING",
|
|
628
|
+
requestId,
|
|
629
|
+
timestamp: startTime
|
|
630
|
+
};
|
|
631
|
+
this.send(message);
|
|
632
|
+
return new Promise((resolve, reject) => {
|
|
633
|
+
const timeout = setTimeout(() => {
|
|
634
|
+
this.pendingRequests.delete(requestId);
|
|
635
|
+
reject(new PokerSDKError("Ping timeout", "TIMEOUT"));
|
|
636
|
+
}, 5e3);
|
|
637
|
+
this.pendingRequests.set(requestId, {
|
|
638
|
+
resolve: () => {
|
|
639
|
+
resolve(Date.now() - startTime);
|
|
640
|
+
},
|
|
641
|
+
reject,
|
|
642
|
+
timeout
|
|
643
|
+
});
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
// ============================================================================
|
|
647
|
+
// Private Methods
|
|
648
|
+
// ============================================================================
|
|
649
|
+
/**
|
|
650
|
+
* Send a message to the server
|
|
651
|
+
*/
|
|
652
|
+
send(message) {
|
|
653
|
+
if (this.ws?.readyState !== this.WebSocketImpl.OPEN) {
|
|
654
|
+
throw new PokerSDKError("WebSocket not open", "NOT_CONNECTED");
|
|
655
|
+
}
|
|
656
|
+
this.log("Sending:", message);
|
|
657
|
+
this.ws.send(JSON.stringify(message));
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Handle incoming message
|
|
661
|
+
*/
|
|
662
|
+
handleMessage(data) {
|
|
663
|
+
try {
|
|
664
|
+
const parsed = JSON.parse(data);
|
|
665
|
+
const result = types.safeParseServerMessage(parsed);
|
|
666
|
+
if (!result.success) {
|
|
667
|
+
this.log("Invalid server message:", result.error);
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
const message = result.data;
|
|
671
|
+
this.log("Received:", message);
|
|
672
|
+
switch (message.type) {
|
|
673
|
+
case "SNAPSHOT": {
|
|
674
|
+
this.stateCache.set(message.tableId, message.state);
|
|
675
|
+
const pending = this.pendingRequests.get(`snapshot:${message.tableId}`);
|
|
676
|
+
if (pending) {
|
|
677
|
+
this.pendingRequests.delete(`snapshot:${message.tableId}`);
|
|
678
|
+
pending.resolve(message.state);
|
|
679
|
+
}
|
|
680
|
+
this.emit("snapshot", message.tableId, message.state);
|
|
681
|
+
break;
|
|
682
|
+
}
|
|
683
|
+
case "STATE_UPDATE": {
|
|
684
|
+
const cachedState = this.stateCache.get(message.tableId);
|
|
685
|
+
if (cachedState) {
|
|
686
|
+
const updatedState = { ...cachedState, version: message.version };
|
|
687
|
+
this.stateCache.set(message.tableId, updatedState);
|
|
688
|
+
this.emit("stateUpdate", message.tableId, updatedState);
|
|
689
|
+
} else {
|
|
690
|
+
this.emit("stateUpdate", message.tableId, {
|
|
691
|
+
version: message.version
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
case "ACTION": {
|
|
697
|
+
this.emit(
|
|
698
|
+
"action",
|
|
699
|
+
message.tableId,
|
|
700
|
+
message.playerId,
|
|
701
|
+
message.actionType,
|
|
702
|
+
message.amount
|
|
703
|
+
);
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
case "ACK": {
|
|
707
|
+
const pending = this.pendingRequests.get(message.requestId);
|
|
708
|
+
if (pending) {
|
|
709
|
+
clearTimeout(pending.timeout);
|
|
710
|
+
this.pendingRequests.delete(message.requestId);
|
|
711
|
+
pending.resolve(void 0);
|
|
712
|
+
}
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
case "PONG": {
|
|
716
|
+
const pending = this.pendingRequests.get(message.requestId);
|
|
717
|
+
if (pending) {
|
|
718
|
+
clearTimeout(pending.timeout);
|
|
719
|
+
this.pendingRequests.delete(message.requestId);
|
|
720
|
+
pending.resolve(message.timestamp);
|
|
721
|
+
}
|
|
722
|
+
break;
|
|
723
|
+
}
|
|
724
|
+
case "ERROR": {
|
|
725
|
+
this.log("Server error:", message);
|
|
726
|
+
if (message.requestId) {
|
|
727
|
+
const pending = this.pendingRequests.get(message.requestId);
|
|
728
|
+
if (pending) {
|
|
729
|
+
clearTimeout(pending.timeout);
|
|
730
|
+
this.pendingRequests.delete(message.requestId);
|
|
731
|
+
pending.reject(new PokerSDKError(message.message, message.code));
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
this.emit("error", new PokerSDKError(message.message, message.code));
|
|
735
|
+
break;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
} catch (error) {
|
|
739
|
+
this.log("Failed to parse message:", error);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Handle disconnect
|
|
744
|
+
*/
|
|
745
|
+
handleDisconnect(reason) {
|
|
746
|
+
this.stopHeartbeat();
|
|
747
|
+
this.ws = null;
|
|
748
|
+
const wasConnected = this.connectionState === "connected";
|
|
749
|
+
this.connectionState = "disconnected";
|
|
750
|
+
if (wasConnected) {
|
|
751
|
+
this.emit("disconnect", reason);
|
|
752
|
+
}
|
|
753
|
+
if (this.shouldReconnect && this.reconnectCount < this.reconnectAttempts) {
|
|
754
|
+
void this.reconnect();
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Attempt to reconnect
|
|
759
|
+
*/
|
|
760
|
+
async reconnect() {
|
|
761
|
+
this.reconnectCount++;
|
|
762
|
+
this.connectionState = "reconnecting";
|
|
763
|
+
const delay = Math.min(
|
|
764
|
+
this.reconnectDelay * Math.pow(2, this.reconnectCount - 1),
|
|
765
|
+
this.maxReconnectDelay
|
|
766
|
+
);
|
|
767
|
+
this.log(
|
|
768
|
+
`Reconnecting in ${delay}ms (attempt ${this.reconnectCount}/${this.reconnectAttempts})`
|
|
769
|
+
);
|
|
770
|
+
this.emit("reconnect", this.reconnectCount);
|
|
771
|
+
await this.sleep(delay);
|
|
772
|
+
if (!this.shouldReconnect) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
try {
|
|
776
|
+
await this.connect();
|
|
777
|
+
} catch {
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Rejoin previously joined tables
|
|
782
|
+
*/
|
|
783
|
+
async rejoinTables() {
|
|
784
|
+
for (const tableId of this.joinedTables) {
|
|
785
|
+
try {
|
|
786
|
+
await this.join(tableId);
|
|
787
|
+
} catch (error) {
|
|
788
|
+
this.log("Failed to rejoin table:", tableId, error);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Start heartbeat timer
|
|
794
|
+
*/
|
|
795
|
+
startHeartbeat() {
|
|
796
|
+
this.stopHeartbeat();
|
|
797
|
+
this.heartbeatTimer = setInterval(() => {
|
|
798
|
+
if (this.connectionState === "connected") {
|
|
799
|
+
void this.ping().catch(() => {
|
|
800
|
+
this.log("Heartbeat failed");
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
}, this.heartbeatInterval);
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Stop heartbeat timer
|
|
807
|
+
*/
|
|
808
|
+
stopHeartbeat() {
|
|
809
|
+
if (this.heartbeatTimer) {
|
|
810
|
+
clearInterval(this.heartbeatTimer);
|
|
811
|
+
this.heartbeatTimer = null;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Clear all pending requests
|
|
816
|
+
*/
|
|
817
|
+
clearPendingRequests(reason) {
|
|
818
|
+
for (const pending of this.pendingRequests.values()) {
|
|
819
|
+
clearTimeout(pending.timeout);
|
|
820
|
+
pending.reject(new PokerSDKError(reason, "CONNECTION_CLOSED"));
|
|
821
|
+
}
|
|
822
|
+
this.pendingRequests.clear();
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Emit event to listeners
|
|
826
|
+
*/
|
|
827
|
+
emit(event, ...args) {
|
|
828
|
+
const listeners = this.listeners.get(event);
|
|
829
|
+
if (listeners) {
|
|
830
|
+
for (const listener of listeners) {
|
|
831
|
+
try {
|
|
832
|
+
listener(...args);
|
|
833
|
+
} catch (error) {
|
|
834
|
+
this.log("Listener error:", error);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Generate unique request ID
|
|
841
|
+
*/
|
|
842
|
+
generateRequestId() {
|
|
843
|
+
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Sleep helper
|
|
847
|
+
*/
|
|
848
|
+
sleep(ms) {
|
|
849
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Debug logger
|
|
853
|
+
*/
|
|
854
|
+
log(...args) {
|
|
855
|
+
if (this.debug) {
|
|
856
|
+
console.log("[PokerSocket]", ...args);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
var PokerContext = react.createContext(null);
|
|
861
|
+
function PokerProvider({ config, children, autoConnect = true }) {
|
|
862
|
+
const [connectionState, setConnectionState] = react.useState("disconnected");
|
|
863
|
+
const clientRef = react.useRef(null);
|
|
864
|
+
const socketRef = react.useRef(null);
|
|
865
|
+
clientRef.current ?? (clientRef.current = new PokerClient(config));
|
|
866
|
+
react.useEffect(() => {
|
|
867
|
+
if (clientRef.current) {
|
|
868
|
+
clientRef.current.setToken(config.token ?? null);
|
|
869
|
+
}
|
|
870
|
+
}, [config.token]);
|
|
871
|
+
react.useEffect(() => {
|
|
872
|
+
if (config.token && autoConnect && !socketRef.current) {
|
|
873
|
+
socketRef.current = PokerSocket.fromConfig(config);
|
|
874
|
+
socketRef.current.on("connect", () => setConnectionState("connected"));
|
|
875
|
+
socketRef.current.on("disconnect", () => setConnectionState("disconnected"));
|
|
876
|
+
socketRef.current.on("reconnect", () => setConnectionState("reconnecting"));
|
|
877
|
+
void socketRef.current.connect().catch(console.error);
|
|
878
|
+
}
|
|
879
|
+
return () => {
|
|
880
|
+
if (socketRef.current) {
|
|
881
|
+
socketRef.current.disconnect();
|
|
882
|
+
socketRef.current = null;
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
}, [config.token, autoConnect, config]);
|
|
886
|
+
const connect = react.useCallback(async () => {
|
|
887
|
+
if (!config.token) {
|
|
888
|
+
throw new Error("Token required to connect");
|
|
889
|
+
}
|
|
890
|
+
if (!socketRef.current) {
|
|
891
|
+
socketRef.current = PokerSocket.fromConfig(config);
|
|
892
|
+
socketRef.current.on("connect", () => setConnectionState("connected"));
|
|
893
|
+
socketRef.current.on("disconnect", () => setConnectionState("disconnected"));
|
|
894
|
+
socketRef.current.on("reconnect", () => setConnectionState("reconnecting"));
|
|
895
|
+
}
|
|
896
|
+
setConnectionState("connecting");
|
|
897
|
+
await socketRef.current.connect();
|
|
898
|
+
}, [config]);
|
|
899
|
+
const disconnect = react.useCallback(() => {
|
|
900
|
+
if (socketRef.current) {
|
|
901
|
+
socketRef.current.disconnect();
|
|
902
|
+
}
|
|
903
|
+
}, []);
|
|
904
|
+
const value = react.useMemo(
|
|
905
|
+
() => ({
|
|
906
|
+
client: clientRef.current,
|
|
907
|
+
socket: socketRef.current,
|
|
908
|
+
isAuthenticated: !!config.token,
|
|
909
|
+
connectionState,
|
|
910
|
+
connect,
|
|
911
|
+
disconnect
|
|
912
|
+
}),
|
|
913
|
+
[config.token, connectionState, connect, disconnect]
|
|
914
|
+
);
|
|
915
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PokerContext.Provider, { value, children });
|
|
916
|
+
}
|
|
917
|
+
function usePoker() {
|
|
918
|
+
const context = react.useContext(PokerContext);
|
|
919
|
+
if (!context) {
|
|
920
|
+
throw new Error("usePoker must be used within a PokerProvider");
|
|
921
|
+
}
|
|
922
|
+
return context;
|
|
923
|
+
}
|
|
924
|
+
function usePokerClient() {
|
|
925
|
+
return usePoker().client;
|
|
926
|
+
}
|
|
927
|
+
function usePokerSocket() {
|
|
928
|
+
return usePoker().socket;
|
|
929
|
+
}
|
|
930
|
+
function useTable(tableId, options = {}) {
|
|
931
|
+
const { pollInterval, autoJoin = true } = options;
|
|
932
|
+
const { client, socket } = usePoker();
|
|
933
|
+
const [state, setState] = react.useState(null);
|
|
934
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
935
|
+
const [error, setError] = react.useState(null);
|
|
936
|
+
const versionRef = react.useRef(0);
|
|
937
|
+
const refresh = react.useCallback(async () => {
|
|
938
|
+
try {
|
|
939
|
+
setIsLoading(true);
|
|
940
|
+
const newState = await client.getTableState(tableId);
|
|
941
|
+
if (newState) {
|
|
942
|
+
setState(newState);
|
|
943
|
+
versionRef.current = newState.version;
|
|
944
|
+
}
|
|
945
|
+
setError(null);
|
|
946
|
+
} catch (err) {
|
|
947
|
+
setError(err);
|
|
948
|
+
} finally {
|
|
949
|
+
setIsLoading(false);
|
|
950
|
+
}
|
|
951
|
+
}, [client, tableId]);
|
|
952
|
+
react.useEffect(() => {
|
|
953
|
+
void refresh();
|
|
954
|
+
}, [refresh]);
|
|
955
|
+
react.useEffect(() => {
|
|
956
|
+
if (!socket || !autoJoin) return;
|
|
957
|
+
const handleStateUpdate = (id, newState) => {
|
|
958
|
+
if (id === tableId) {
|
|
959
|
+
setState(newState);
|
|
960
|
+
versionRef.current = newState.version;
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
const handleSnapshot = (id, newState) => {
|
|
964
|
+
if (id === tableId) {
|
|
965
|
+
setState(newState);
|
|
966
|
+
versionRef.current = newState.version;
|
|
967
|
+
setIsLoading(false);
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
socket.on("stateUpdate", handleStateUpdate);
|
|
971
|
+
socket.on("snapshot", handleSnapshot);
|
|
972
|
+
if (socket.isConnected()) {
|
|
973
|
+
void socket.join(tableId).catch(console.error);
|
|
974
|
+
}
|
|
975
|
+
return () => {
|
|
976
|
+
socket.off("stateUpdate", handleStateUpdate);
|
|
977
|
+
socket.off("snapshot", handleSnapshot);
|
|
978
|
+
socket.leave(tableId);
|
|
979
|
+
};
|
|
980
|
+
}, [socket, tableId, autoJoin]);
|
|
981
|
+
react.useEffect(() => {
|
|
982
|
+
if (!pollInterval) return;
|
|
983
|
+
const interval = setInterval(() => {
|
|
984
|
+
void (async () => {
|
|
985
|
+
const newState = await client.getTableState(tableId, versionRef.current);
|
|
986
|
+
if (newState) {
|
|
987
|
+
setState(newState);
|
|
988
|
+
versionRef.current = newState.version;
|
|
989
|
+
}
|
|
990
|
+
})();
|
|
991
|
+
}, pollInterval);
|
|
992
|
+
return () => clearInterval(interval);
|
|
993
|
+
}, [client, tableId, pollInterval]);
|
|
994
|
+
const action = react.useCallback(
|
|
995
|
+
async (type, amount) => {
|
|
996
|
+
const newState = await client.action(tableId, { type, amount });
|
|
997
|
+
setState(newState);
|
|
998
|
+
versionRef.current = newState.version;
|
|
999
|
+
},
|
|
1000
|
+
[client, tableId]
|
|
1001
|
+
);
|
|
1002
|
+
const leave = react.useCallback(async () => {
|
|
1003
|
+
await client.stand(tableId);
|
|
1004
|
+
if (socket) {
|
|
1005
|
+
socket.leave(tableId);
|
|
1006
|
+
}
|
|
1007
|
+
}, [client, socket, tableId]);
|
|
1008
|
+
return { state, isLoading, error, refresh, action, leave };
|
|
1009
|
+
}
|
|
1010
|
+
function useUser() {
|
|
1011
|
+
const { client, isAuthenticated } = usePoker();
|
|
1012
|
+
const [profile, setProfile] = react.useState(null);
|
|
1013
|
+
const [isLoading, setIsLoading] = react.useState(false);
|
|
1014
|
+
const [error, setError] = react.useState(null);
|
|
1015
|
+
const refresh = react.useCallback(async () => {
|
|
1016
|
+
if (!isAuthenticated) return;
|
|
1017
|
+
try {
|
|
1018
|
+
setIsLoading(true);
|
|
1019
|
+
const data = await client.getProfile();
|
|
1020
|
+
setProfile(data);
|
|
1021
|
+
setError(null);
|
|
1022
|
+
} catch (err) {
|
|
1023
|
+
setError(err);
|
|
1024
|
+
} finally {
|
|
1025
|
+
setIsLoading(false);
|
|
1026
|
+
}
|
|
1027
|
+
}, [client, isAuthenticated]);
|
|
1028
|
+
react.useEffect(() => {
|
|
1029
|
+
if (isAuthenticated) {
|
|
1030
|
+
void refresh();
|
|
1031
|
+
} else {
|
|
1032
|
+
setProfile(null);
|
|
1033
|
+
}
|
|
1034
|
+
}, [isAuthenticated, refresh]);
|
|
1035
|
+
return {
|
|
1036
|
+
profile,
|
|
1037
|
+
balances: profile?.balances ?? null,
|
|
1038
|
+
isLoading,
|
|
1039
|
+
error,
|
|
1040
|
+
refresh
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
function useTables() {
|
|
1044
|
+
const { client } = usePoker();
|
|
1045
|
+
const [tables, setTables] = react.useState([]);
|
|
1046
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
1047
|
+
const [error, setError] = react.useState(null);
|
|
1048
|
+
const refresh = react.useCallback(async () => {
|
|
1049
|
+
try {
|
|
1050
|
+
setIsLoading(true);
|
|
1051
|
+
const data = await client.getTables();
|
|
1052
|
+
setTables(data);
|
|
1053
|
+
setError(null);
|
|
1054
|
+
} catch (err) {
|
|
1055
|
+
setError(err);
|
|
1056
|
+
} finally {
|
|
1057
|
+
setIsLoading(false);
|
|
1058
|
+
}
|
|
1059
|
+
}, [client]);
|
|
1060
|
+
react.useEffect(() => {
|
|
1061
|
+
void refresh();
|
|
1062
|
+
}, [refresh]);
|
|
1063
|
+
return { tables, isLoading, error, refresh };
|
|
1064
|
+
}
|
|
1065
|
+
function useConnection() {
|
|
1066
|
+
const { socket, connectionState, connect, disconnect } = usePoker();
|
|
1067
|
+
const [latency, setLatency] = react.useState(null);
|
|
1068
|
+
const ping = react.useCallback(async () => {
|
|
1069
|
+
if (!socket?.isConnected()) return null;
|
|
1070
|
+
try {
|
|
1071
|
+
const ms = await socket.ping();
|
|
1072
|
+
setLatency(ms);
|
|
1073
|
+
return ms;
|
|
1074
|
+
} catch {
|
|
1075
|
+
return null;
|
|
1076
|
+
}
|
|
1077
|
+
}, [socket]);
|
|
1078
|
+
return {
|
|
1079
|
+
state: connectionState,
|
|
1080
|
+
isConnected: connectionState === "connected",
|
|
1081
|
+
isConnecting: connectionState === "connecting",
|
|
1082
|
+
isReconnecting: connectionState === "reconnecting",
|
|
1083
|
+
latency,
|
|
1084
|
+
connect,
|
|
1085
|
+
disconnect,
|
|
1086
|
+
ping
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
exports.PokerProvider = PokerProvider;
|
|
1091
|
+
exports.useConnection = useConnection;
|
|
1092
|
+
exports.usePoker = usePoker;
|
|
1093
|
+
exports.usePokerClient = usePokerClient;
|
|
1094
|
+
exports.usePokerSocket = usePokerSocket;
|
|
1095
|
+
exports.useTable = useTable;
|
|
1096
|
+
exports.useTables = useTables;
|
|
1097
|
+
exports.useUser = useUser;
|
|
1098
|
+
//# sourceMappingURL=index.cjs.map
|
|
1099
|
+
//# sourceMappingURL=index.cjs.map
|