From 2b3ee6c0a03bb7a1e177d606610f547c3d22cf26 Mon Sep 17 00:00:00 2001 From: Vaggelis Date: Sat, 22 Aug 2026 21:33:40 +0300 Subject: [PATCH] fix(typescript): build Router event markets as MarketList Router's local convertEvent() returned markets as a plain array, but UnifiedEvent.markets is typed MarketList and callers rely on its .match() helper, so results from fetchEventMatches and fetchMatchedEventClusters threw TypeError on .match(). Build the array with MarketList.from(...) exactly like the canonical converter in client.ts does. Fixes #2074 --- sdks/typescript/pmxt/router.ts | 3 +- .../tests/router-event-markets.test.ts | 82 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 sdks/typescript/tests/router-event-markets.test.ts diff --git a/sdks/typescript/pmxt/router.ts b/sdks/typescript/pmxt/router.ts index 7cc9ca3d..cc3d6290 100644 --- a/sdks/typescript/pmxt/router.ts +++ b/sdks/typescript/pmxt/router.ts @@ -21,6 +21,7 @@ import { UnifiedMarket, UnifiedEvent, MarketOutcome, + MarketList, OrderBook, FetchOrderBookParams, SqlResult, @@ -91,7 +92,7 @@ function convertEvent(raw: any): UnifiedEvent { title: raw.title, description: raw.description, slug: raw.slug, - markets: (raw.markets || []).map(convertMarket), + markets: MarketList.from((raw.markets || []).map(convertMarket)) as MarketList, volume24h: raw.volume24h, volume: raw.volume, url: raw.url, diff --git a/sdks/typescript/tests/router-event-markets.test.ts b/sdks/typescript/tests/router-event-markets.test.ts new file mode 100644 index 00000000..660e5a33 --- /dev/null +++ b/sdks/typescript/tests/router-event-markets.test.ts @@ -0,0 +1,82 @@ +import { Router } from "../pmxt/router"; +import { MarketList } from "../pmxt/models"; + +const PMXT_API_KEY = "test_pmxt_key_xxx"; +const BASE_URL = "https://api.example.test"; + +function installFetchSpy(handler: () => Response): void { + jest.spyOn(global, "fetch").mockImplementation(async () => handler()); +} + +function jsonResponse(payload: unknown, status = 200): Response { + return new Response(JSON.stringify(payload), { + status, + headers: { "Content-Type": "application/json" }, + }); +} + +function makeRouter(): Router { + return new Router({ pmxtApiKey: PMXT_API_KEY, baseUrl: BASE_URL, autoStartServer: false }); +} + +const RAW_EVENT = { + id: "evt-1", + title: "US Election", + slug: "us-election", + markets: [ + { + marketId: "mkt-1", + title: "Trump wins", + slug: "trump-wins", + }, + ], +}; + +afterEach(() => { + jest.restoreAllMocks(); +}); + +describe("Router event markets are MarketList", () => { + it("fetchEventMatches returns MarketList for both markets surfaces so .match() works", async () => { + installFetchSpy(() => + jsonResponse({ + success: true, + data: [ + { + event: RAW_EVENT, + marketMatches: [], + }, + ], + }), + ); + + const router = makeRouter(); + const results = await router.fetchEventMatches({ query: "election" }); + + expect(results).toHaveLength(1); + // UnifiedEvent.markets is declared as MarketList; callers rely on .match(). + expect(results[0].markets).toBeInstanceOf(MarketList); + expect(results[0].event.markets).toBeInstanceOf(MarketList); + const matched = results[0].markets.match("Trump"); + expect(matched.marketId).toBe("mkt-1"); + }); + + it("fetchMatchedEventClusters returns MarketList for clustered events", async () => { + installFetchSpy(() => + jsonResponse([ + { + clusterId: "c1", + events: [RAW_EVENT], + }, + ]), + ); + + const router = makeRouter(); + const clusters = await router.fetchMatchedEventClusters({ query: "election" }); + + expect(clusters).toHaveLength(1); + expect(clusters[0].events[0].markets).toBeInstanceOf(MarketList); + const matched = clusters[0].events[0].markets.match("Trump"); + expect(matched.marketId).toBe("mkt-1"); + }); +});