Skip to content

Commit bbe18b0

Browse files
committed
fix(sdk): add SuiBetsOptions interface and wire walletAddress through TS client
- Add SuiBetsOptions interface extending ExchangeOptions with optional walletAddress - SuiBets class now accepts SuiBetsOptions and stores _walletAddress - Override getCredentials() to include walletAddress in sidecar payload - Base client.ts is current upstream main (all WS refactor changes included)
1 parent 289ba11 commit bbe18b0

1 file changed

Lines changed: 67 additions & 25 deletions

File tree

sdks/typescript/pmxt/client.ts

Lines changed: 67 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@ import {
3636
PaginatedMarketsResult,
3737
PaginatedEventsResult,
3838
Position,
39+
SeriesFetchParams,
3940
PriceCandle,
4041
SubscribedAddressSnapshot,
4142
SubscriptionOption,
4243
Trade,
4344
UnifiedEvent,
4445
UnifiedMarket,
46+
UnifiedSeries,
4547
UserTrade,
4648
FirehoseEvent,
4749
} from "./models.js";
@@ -61,6 +63,7 @@ interface SidecarWsClientInternals {
6163
ws: RawWebSocketLike | null;
6264
activeSubs: Map<string, string>;
6365
subscriptions: Map<string, { reject: ((error: Error) => void) | null }>;
66+
dataQueues: Map<string, any[]>;
6467
dataStore: Map<string, any>;
6568
}
6669

@@ -171,6 +174,10 @@ function convertEvent(raw: any): UnifiedEvent {
171174
return { ...raw, markets };
172175
}
173176

177+
function convertSeries(raw: any): UnifiedSeries {
178+
const events = Array.isArray(raw.events) ? raw.events.map(convertEvent) : undefined;
179+
return { ...raw, ...(events !== undefined ? { events } : {}) };
180+
}
174181

175182
function convertSubscriptionSnapshot(raw: any): SubscribedAddressSnapshot {
176183
return {
@@ -238,6 +245,13 @@ export interface ExchangeOptions {
238245
* prediction market platforms (Polymarket, Kalshi, etc.).
239246
*/
240247
export abstract class Exchange {
248+
private static readonly OBDATA_WATCH_ALL_SOURCES = new Set([
249+
"polymarket",
250+
"limitless",
251+
"kalshi",
252+
"opinion",
253+
]);
254+
241255
protected exchangeName: string;
242256
protected apiKey?: string;
243257
protected privateKey?: string;
@@ -508,6 +522,13 @@ export abstract class Exchange {
508522
&& /connection failed|no websocket|websocket.*not connected/i.test(error.message);
509523
}
510524

525+
private defaultWatchAllOrderBookVenues(): string[] | undefined {
526+
if (Exchange.OBDATA_WATCH_ALL_SOURCES.has(this.exchangeName)) {
527+
return [this.exchangeName];
528+
}
529+
return undefined;
530+
}
531+
511532
private getWsInternals(ws: SidecarWsClient): SidecarWsClientInternals {
512533
return ws as unknown as SidecarWsClientInternals;
513534
}
@@ -538,6 +559,7 @@ export abstract class Exchange {
538559

539560
internals.activeSubs.delete(subKey);
540561
internals.subscriptions.delete(requestId);
562+
internals.dataQueues.delete(requestId);
541563
internals.dataStore.delete(requestId);
542564

543565
const firstArg = args[0] ?? "";
@@ -847,6 +869,32 @@ export abstract class Exchange {
847869
}
848870
}
849871

872+
async fetchSeries(params?: SeriesFetchParams): Promise<UnifiedSeries[]> {
873+
await this.initPromise;
874+
try {
875+
const args: any[] = [];
876+
if (params !== undefined) args.push(params);
877+
const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchSeries`, {
878+
method: 'POST',
879+
headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
880+
body: JSON.stringify({ args, credentials: this.getCredentials() }),
881+
});
882+
if (!response.ok) {
883+
const body = await response.json().catch(() => ({}));
884+
if (body.error && typeof body.error === "object") {
885+
throw fromServerError(body.error);
886+
}
887+
throw new PmxtError(body.error?.message || response.statusText);
888+
}
889+
const json = await response.json();
890+
const data = this.handleResponse(json);
891+
return data.map(convertSeries);
892+
} catch (error) {
893+
if (error instanceof PmxtError) throw error;
894+
throw new PmxtError(`Failed to fetchSeries: ${error}`);
895+
}
896+
}
897+
850898
async fetchMarket(params?: MarketFetchParams): Promise<UnifiedMarket> {
851899
await this.initPromise;
852900
try {
@@ -1199,32 +1247,24 @@ export abstract class Exchange {
11991247

12001248
async unwatchOrderBook(outcomeId: string | MarketOutcome): Promise<void> {
12011249
await this.initPromise;
1202-
const resolvedOutcomeId = resolveOutcomeId(outcomeId);
1203-
const args: any[] = [resolvedOutcomeId];
12041250
try {
1205-
const ws = await this.getOrCreateWs();
1206-
if (!ws) {
1207-
throw this.wsTransportUnavailableError("unwatchOrderBook");
1251+
const args: any[] = [];
1252+
args.push(resolveOutcomeId(outcomeId));
1253+
const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/unwatchOrderBook`, {
1254+
method: 'POST',
1255+
headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1256+
body: JSON.stringify({ args, credentials: this.getCredentials() }),
1257+
});
1258+
if (!response.ok) {
1259+
const body = await response.json().catch(() => ({}));
1260+
if (body.error && typeof body.error === "object") {
1261+
throw fromServerError(body.error);
1262+
}
1263+
throw new PmxtError(body.error?.message || response.statusText);
12081264
}
1209-
1210-
const requestId = this.getWsSubscriptionId(ws, "watchOrderBook", args)
1211-
?? `req-${Math.random().toString(36).slice(2, 14)}`;
1212-
1213-
await this.sendWsMessage(
1214-
ws,
1215-
{
1216-
id: requestId,
1217-
action: "unsubscribe",
1218-
exchange: this.exchangeName,
1219-
method: "unwatchOrderBook",
1220-
args,
1221-
},
1222-
);
1223-
this.clearWsSubscription(ws, "watchOrderBook", args);
1265+
const json = await response.json();
1266+
this.handleResponse(json);
12241267
} catch (error) {
1225-
if (this.isWsTransportUnavailableError(error)) {
1226-
throw this.wsTransportUnavailableError("unwatchOrderBook");
1227-
}
12281268
if (error instanceof PmxtError) throw error;
12291269
throw new PmxtError(`Failed to unwatchOrderBook: ${error}`);
12301270
}
@@ -1718,7 +1758,8 @@ export abstract class Exchange {
17181758
* Call repeatedly in a loop to stream updates (CCXT Pro pattern).
17191759
* Requires hosted mode (`pmxtApiKey` set).
17201760
*
1721-
* @param venues - Optional venue filter (e.g. ["polymarket", "limitless"])
1761+
* @param venues - Optional venue filter. Defaults to this exchange's venue
1762+
* for venue clients (e.g. Kalshi -> ["kalshi"]); Router defaults to all venues.
17221763
* @returns Next event with source, symbol, and orderbook
17231764
*
17241765
* @example
@@ -1737,7 +1778,8 @@ export abstract class Exchange {
17371778
throw new PmxtError("watchAllOrderBooks() requires hosted mode (set pmxtApiKey)");
17381779
}
17391780

1740-
const args: any[] = venues ? [venues] : [];
1781+
const effectiveVenues = venues ?? this.defaultWatchAllOrderBookVenues();
1782+
const args: any[] = effectiveVenues?.length ? [effectiveVenues] : [];
17411783
const wsData = await this.watchViaWs("watchAllOrderBooks", args);
17421784
if (wsData !== null) {
17431785
return {

0 commit comments

Comments
 (0)