From c91df0d0ec9a55462391f690a1faa500e2d4297c Mon Sep 17 00:00:00 2001 From: Samuel Tinnerholm Date: Fri, 3 Jul 2026 06:59:54 +0000 Subject: [PATCH] fix(typescript): add documented event helper methods Fixes #1491 --- sdks/typescript/pmxt/client.ts | 52 ++++++++++++++ sdks/typescript/tests/event-methods.test.ts | 78 +++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 sdks/typescript/tests/event-methods.test.ts diff --git a/sdks/typescript/pmxt/client.ts b/sdks/typescript/pmxt/client.ts index 6e3664d8..057cf1e3 100644 --- a/sdks/typescript/pmxt/client.ts +++ b/sdks/typescript/pmxt/client.ts @@ -866,6 +866,58 @@ export abstract class Exchange { return response.json(); } + /** + * Pre-warm the sidecar's internal caches for a market outcome. + * + * @param outcomeId - The CLOB token ID for the outcome. + */ + async preWarmMarket(outcomeId: string): Promise { + await this.initPromise; + try { + const json = await this.sidecarPostRequest("preWarmMarket", [outcomeId]); + this.handleResponse(json); + } catch (error) { + if (error instanceof PmxtError) throw error; + throw new PmxtError(`Failed to preWarmMarket: ${error}`); + } + } + + /** + * Fetch a single Probable event by its numeric ID. + * + * @param id - The numeric event ID. + * @returns The event, or null when the venue has no matching event. + */ + async getEventById(id: string): Promise { + await this.initPromise; + try { + const json = await this.sidecarPostRequest("getEventById", [id]); + const data = this.handleResponse(json); + return data == null ? null : convertEvent(data); + } catch (error) { + if (error instanceof PmxtError) throw error; + throw new PmxtError(`Failed to getEventById: ${error}`); + } + } + + /** + * Fetch a single Probable event by its URL slug. + * + * @param slug - The event slug. + * @returns The event, or null when the venue has no matching event. + */ + async getEventBySlug(slug: string): Promise { + await this.initPromise; + try { + const json = await this.sidecarPostRequest("getEventBySlug", [slug]); + const data = this.handleResponse(json); + return data == null ? null : convertEvent(data); + } catch (error) { + if (error instanceof PmxtError) throw error; + throw new PmxtError(`Failed to getEventBySlug: ${error}`); + } + } + /** * Read a hosted catalog endpoint directly. * diff --git a/sdks/typescript/tests/event-methods.test.ts b/sdks/typescript/tests/event-methods.test.ts new file mode 100644 index 00000000..ac8afdb8 --- /dev/null +++ b/sdks/typescript/tests/event-methods.test.ts @@ -0,0 +1,78 @@ +import { Polymarket, Probable } from "../pmxt/client"; + +interface CapturedFetch { + url: string; + init?: RequestInit; +} + +function installFetchSpy(handler: (req: CapturedFetch) => Response): jest.SpyInstance { + const captured: CapturedFetch[] = []; + const spy = jest.spyOn(global, "fetch").mockImplementation(async (input, init) => { + const url = typeof input === "string" ? input : (input as URL | Request).toString(); + const rec: CapturedFetch = { url, init }; + captured.push(rec); + return handler(rec); + }); + (spy as unknown as { captured: CapturedFetch[] }).captured = captured; + return spy; +} + +function captured(spy: jest.SpyInstance): CapturedFetch[] { + return (spy as unknown as { captured: CapturedFetch[] }).captured; +} + +function jsonResponse(payload: unknown): Response { + return new Response(JSON.stringify(payload), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); +} + +afterEach(() => { + jest.restoreAllMocks(); +}); + +describe("event-specific SDK methods", () => { + it("preWarmMarket dispatches the documented sidecar method", async () => { + const spy = installFetchSpy(() => jsonResponse({ success: true, data: null })); + const api = new Polymarket({ baseUrl: "http://sidecar.test", autoStartServer: false }); + + await api.preWarmMarket("12345"); + + const reqs = captured(spy); + expect(reqs).toHaveLength(1); + expect(reqs[0].url).toBe("http://sidecar.test/api/polymarket/preWarmMarket"); + expect(reqs[0].init?.method).toBe("POST"); + expect(JSON.parse(reqs[0].init?.body as string)).toEqual({ + args: ["12345"], + }); + }); + + it("getEventById returns null without conversion when sidecar returns null", async () => { + installFetchSpy(() => jsonResponse({ success: true, data: null })); + const api = new Probable({ baseUrl: "http://sidecar.test", autoStartServer: false }); + + await expect(api.getEventById("180")).resolves.toBeNull(); + }); + + it("getEventBySlug converts returned event markets", async () => { + const spy = installFetchSpy(() => jsonResponse({ + success: true, + data: { + id: "180", + title: "Example event", + markets: [ + { id: "m1", title: "Will it happen?", outcomes: [] }, + ], + }, + })); + const api = new Probable({ baseUrl: "http://sidecar.test", autoStartServer: false }); + + const event = await api.getEventBySlug("example-event"); + + expect(event?.title).toBe("Example event"); + expect(event?.markets).toHaveLength(1); + expect(captured(spy)[0].url).toBe("http://sidecar.test/api/probable/getEventBySlug"); + expect(JSON.parse(captured(spy)[0].init?.body as string).args).toEqual(["example-event"]); + }); +});