pmxt-core 2.46.14 → 2.48.0

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.
Files changed (82) hide show
  1. package/dist/BaseExchange.d.ts +42 -1
  2. package/dist/BaseExchange.js +29 -2
  3. package/dist/exchanges/baozi/index.d.ts +1 -0
  4. package/dist/exchanges/baozi/index.js +5 -0
  5. package/dist/exchanges/baozi/normalizer.js +2 -0
  6. package/dist/exchanges/baozi/utils.js +28 -0
  7. package/dist/exchanges/gemini-titan/index.d.ts +6 -2
  8. package/dist/exchanges/gemini-titan/index.js +81 -1
  9. package/dist/exchanges/gemini-titan/normalizer.d.ts +7 -1
  10. package/dist/exchanges/gemini-titan/normalizer.js +54 -0
  11. package/dist/exchanges/hyperliquid/index.d.ts +3 -0
  12. package/dist/exchanges/hyperliquid/index.js +7 -0
  13. package/dist/exchanges/hyperliquid/normalizer.js +20 -0
  14. package/dist/exchanges/kalshi/api.d.ts +1 -1
  15. package/dist/exchanges/kalshi/api.js +1 -1
  16. package/dist/exchanges/kalshi/fetcher.d.ts +10 -0
  17. package/dist/exchanges/kalshi/fetcher.js +36 -0
  18. package/dist/exchanges/kalshi/index.d.ts +3 -2
  19. package/dist/exchanges/kalshi/index.js +33 -0
  20. package/dist/exchanges/kalshi/normalizer.d.ts +3 -2
  21. package/dist/exchanges/kalshi/normalizer.js +35 -0
  22. package/dist/exchanges/limitless/api.d.ts +1 -1
  23. package/dist/exchanges/limitless/api.js +1 -1
  24. package/dist/exchanges/limitless/index.d.ts +1 -0
  25. package/dist/exchanges/limitless/index.js +5 -0
  26. package/dist/exchanges/limitless/normalizer.js +10 -0
  27. package/dist/exchanges/limitless/utils.js +17 -0
  28. package/dist/exchanges/metaculus/fetchEvents.js +6 -0
  29. package/dist/exchanges/metaculus/index.d.ts +3 -0
  30. package/dist/exchanges/metaculus/index.js +3 -0
  31. package/dist/exchanges/metaculus/utils.d.ts +2 -1
  32. package/dist/exchanges/metaculus/utils.js +32 -3
  33. package/dist/exchanges/myriad/api.d.ts +1 -1
  34. package/dist/exchanges/myriad/api.js +1 -1
  35. package/dist/exchanges/myriad/index.d.ts +1 -0
  36. package/dist/exchanges/myriad/index.js +5 -0
  37. package/dist/exchanges/myriad/normalizer.js +14 -0
  38. package/dist/exchanges/myriad/utils.js +14 -0
  39. package/dist/exchanges/opinion/api.d.ts +1 -1
  40. package/dist/exchanges/opinion/api.js +1 -1
  41. package/dist/exchanges/opinion/index.d.ts +6 -2
  42. package/dist/exchanges/opinion/index.js +54 -1
  43. package/dist/exchanges/opinion/normalizer.d.ts +8 -2
  44. package/dist/exchanges/opinion/normalizer.js +42 -0
  45. package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
  46. package/dist/exchanges/polymarket/api-clob.js +1 -1
  47. package/dist/exchanges/polymarket/api-data.d.ts +1 -1
  48. package/dist/exchanges/polymarket/api-data.js +1 -1
  49. package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
  50. package/dist/exchanges/polymarket/api-gamma.js +1 -1
  51. package/dist/exchanges/polymarket/index.d.ts +13 -2
  52. package/dist/exchanges/polymarket/index.js +49 -0
  53. package/dist/exchanges/polymarket/normalizer.d.ts +2 -1
  54. package/dist/exchanges/polymarket/normalizer.js +48 -0
  55. package/dist/exchanges/polymarket/utils.js +28 -0
  56. package/dist/exchanges/polymarket_us/index.d.ts +3 -2
  57. package/dist/exchanges/polymarket_us/index.js +57 -0
  58. package/dist/exchanges/polymarket_us/normalizer.d.ts +9 -2
  59. package/dist/exchanges/polymarket_us/normalizer.js +42 -0
  60. package/dist/exchanges/probable/api.d.ts +1 -1
  61. package/dist/exchanges/probable/api.js +1 -1
  62. package/dist/exchanges/probable/index.d.ts +3 -0
  63. package/dist/exchanges/probable/index.js +7 -0
  64. package/dist/exchanges/probable/utils.js +17 -0
  65. package/dist/exchanges/smarkets/index.d.ts +1 -0
  66. package/dist/exchanges/smarkets/index.js +5 -0
  67. package/dist/exchanges/smarkets/normalizer.js +20 -0
  68. package/dist/exchanges/suibets/index.d.ts +1 -0
  69. package/dist/exchanges/suibets/index.js +5 -0
  70. package/dist/exchanges/suibets/normalizer.js +20 -0
  71. package/dist/router/Router.d.ts +29 -2
  72. package/dist/router/Router.js +145 -0
  73. package/dist/router/index.d.ts +1 -0
  74. package/dist/router/index.js +1 -0
  75. package/dist/router/series-map.d.ts +32 -0
  76. package/dist/router/series-map.js +146 -0
  77. package/dist/server/method-verbs.json +10 -0
  78. package/dist/server/openapi.yaml +132 -0
  79. package/dist/types.d.ts +35 -0
  80. package/dist/utils/metadata.d.ts +14 -0
  81. package/dist/utils/metadata.js +33 -0
  82. package/package.json +3 -3
@@ -16,6 +16,7 @@ const logger_1 = require("../../utils/logger");
16
16
  class SmarketsExchange extends BaseExchange_1.PredictionMarketExchange {
17
17
  capabilityOverrides = {
18
18
  fetchPositions: 'emulated',
19
+ fetchSeries: false,
19
20
  };
20
21
  auth;
21
22
  loginPromise = null;
@@ -149,6 +150,10 @@ class SmarketsExchange extends BaseExchange_1.PredictionMarketExchange {
149
150
  return allMarkets.slice(offset, offset + limit);
150
151
  }
151
152
  async fetchEventsImpl(params) {
153
+ // Venue does not expose a series concept; honoring `params.series` by
154
+ // returning [] rather than ignoring the filter.
155
+ if (params.series !== undefined)
156
+ return [];
152
157
  const rawEvents = await this.fetcher.fetchRawEvents(params);
153
158
  const limit = params?.limit || 250000;
154
159
  const query = (params?.query || '').toLowerCase();
@@ -2,7 +2,20 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SmarketsNormalizer = void 0;
4
4
  const market_utils_1 = require("../../utils/market-utils");
5
+ const metadata_1 = require("../../utils/metadata");
5
6
  const price_1 = require("./price");
7
+ // Raw Smarkets event fields already promoted to first-class Unified columns —
8
+ // excluded from sourceMetadata so we capture only vendor data not in the
9
+ // unified shape.
10
+ const SMARKETS_PROMOTED_EVENT_KEYS = [
11
+ 'id', 'name', 'description', 'slug', 'full_slug',
12
+ 'start_datetime', 'end_date',
13
+ ];
14
+ // Raw Smarkets market fields already promoted to first-class Unified columns.
15
+ const SMARKETS_PROMOTED_MARKET_KEYS = [
16
+ 'id', 'event_id', 'name', 'slug', 'description',
17
+ 'category', 'categories',
18
+ ];
6
19
  // ----------------------------------------------------------------------------
7
20
  // Helpers
8
21
  // ----------------------------------------------------------------------------
@@ -94,6 +107,9 @@ class SmarketsNormalizer {
94
107
  url: buildEventUrl(event),
95
108
  category,
96
109
  tags,
110
+ // event_id is promoted to eventId; parent_id lives on the raw event
111
+ // (not a recurring/series market field), so no extra is needed.
112
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(market, SMARKETS_PROMOTED_MARKET_KEYS),
97
113
  };
98
114
  (0, market_utils_1.addBinaryOutcomes)(um);
99
115
  return um;
@@ -116,6 +132,10 @@ class SmarketsNormalizer {
116
132
  url: buildEventUrl(raw.event),
117
133
  category,
118
134
  tags: category ? [category] : [],
135
+ // Captures non-promoted event fields: state, type, parent_id,
136
+ // start_date, created, modified, bettable, hidden, inplay_enabled,
137
+ // short_name, seo_description, special_rules, chart_time_period, etc.
138
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw.event, SMARKETS_PROMOTED_EVENT_KEYS),
119
139
  };
120
140
  }
121
141
  normalizeOrderBook(raw, _id) {
@@ -33,6 +33,7 @@ export declare class SuiBetsExchange extends PredictionMarketExchange {
33
33
  fetchPositions: true;
34
34
  watchOrderBook: false;
35
35
  watchTrades: false;
36
+ fetchSeries: false;
36
37
  };
37
38
  private readonly config;
38
39
  private readonly fetcher;
@@ -34,6 +34,7 @@ class SuiBetsExchange extends BaseExchange_1.PredictionMarketExchange {
34
34
  fetchPositions: true,
35
35
  watchOrderBook: false,
36
36
  watchTrades: false,
37
+ fetchSeries: false,
37
38
  };
38
39
  config;
39
40
  fetcher;
@@ -72,6 +73,10 @@ class SuiBetsExchange extends BaseExchange_1.PredictionMarketExchange {
72
73
  .filter((m) => m !== null);
73
74
  }
74
75
  async fetchEventsImpl(params) {
76
+ // Venue does not expose a series concept; honoring `params.series` by returning [] rather than ignoring the filter.
77
+ if (params.series !== undefined) {
78
+ return [];
79
+ }
75
80
  const raw = await this.fetcher.fetchRawEvents(params);
76
81
  return raw
77
82
  .map(r => this.normalizer.normalizeEvent(r))
@@ -1,7 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SuibetsNormalizer = void 0;
4
+ const metadata_1 = require("../../utils/metadata");
4
5
  const utils_1 = require("./utils");
6
+ // Raw SuiBets offer fields already promoted to first-class UnifiedMarket columns.
7
+ // Omit these from sourceMetadata to capture only vendor-specific data not
8
+ // represented by the unified shape.
9
+ const SUIBETS_PROMOTED_OFFER_KEYS = [
10
+ 'id', 'matchId', 'matchName', 'homeTeam', 'awayTeam',
11
+ 'creatorOdds', 'creatorStake', 'remainingStake', 'totalMatched',
12
+ 'matchDate', 'expiresAt', 'status', 'onchainOfferId',
13
+ 'leagueName', 'sport', 'isOnchain',
14
+ ];
15
+ // Raw SuiBets event fields already promoted to first-class UnifiedEvent columns.
16
+ const SUIBETS_PROMOTED_EVENT_KEYS = [
17
+ 'id', 'name', 'homeTeam', 'awayTeam', 'sport', 'leagueName', 'offers',
18
+ ];
5
19
  function liquidity(offer) {
6
20
  const remaining = offer.remainingStake ?? offer.creatorStake;
7
21
  return (0, utils_1.mistToSui)(remaining);
@@ -57,6 +71,9 @@ class SuibetsNormalizer {
57
71
  contractAddress: raw.onchainOfferId,
58
72
  yes: creatorOutcome,
59
73
  no: takerOutcome,
74
+ // Retains creatorWallet, creatorTeam, takerStake, currency \u2014 fields
75
+ // that are vendor-specific and not promoted to any unified column.
76
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, SUIBETS_PROMOTED_OFFER_KEYS),
60
77
  };
61
78
  return market;
62
79
  }
@@ -84,6 +101,9 @@ class SuibetsNormalizer {
84
101
  url: 'https://suibets.replit.app/p2p',
85
102
  category: 'Sports',
86
103
  tags: ['Sports', 'P2P', 'Sui', raw.sport, raw.leagueName].filter((t) => Boolean(t)),
104
+ // Retains matchDate and status \u2014 event-level fields not promoted to
105
+ // any first-class UnifiedEvent column.
106
+ sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, SUIBETS_PROMOTED_EVENT_KEYS),
87
107
  };
88
108
  }
89
109
  normalizePosition(raw) {
@@ -1,5 +1,5 @@
1
- import { PredictionMarketExchange, type MarketFetchParams, type EventFetchParams } from '../BaseExchange';
2
- import type { UnifiedMarket, UnifiedEvent, OrderBook } from '../types';
1
+ import { PredictionMarketExchange, type MarketFetchParams, type EventFetchParams, type SeriesFetchParams } from '../BaseExchange';
2
+ import type { UnifiedMarket, UnifiedEvent, UnifiedSeries, OrderBook } from '../types';
3
3
  import type { RouterOptions, MatchResult, EventMatchResult, PriceComparison, ArbitrageOpportunity, MatchedMarketPair, MatchedPricePair, FetchMarketMatchesParams, FetchMatchesParams, FetchEventMatchesParams, FetchArbitrageParams, FetchMatchedMarketsParams, FetchMatchedPricesParams } from './types';
4
4
  export declare class Router extends PredictionMarketExchange {
5
5
  private readonly client;
@@ -9,6 +9,33 @@ export declare class Router extends PredictionMarketExchange {
9
9
  get name(): string;
10
10
  protected fetchMarketsImpl(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
11
11
  protected fetchEventsImpl(params?: EventFetchParams): Promise<UnifiedEvent[]>;
12
+ /**
13
+ * Fan out fetchEvents({series: venueSeriesId}) to each venue in the
14
+ * mapping, collect all results, and tag each event with its sourceExchange.
15
+ */
16
+ private fetchEventsForMappedSeries;
17
+ /**
18
+ * Cross-venue series fetch.
19
+ *
20
+ * - If `params.id` matches a normalized id in SERIES_MAP, returns a single
21
+ * synthesized `UnifiedSeries` whose `events` is the concatenation of
22
+ * `fetchEvents({series: venueSeriesId})` results from each mapped venue.
23
+ * - Otherwise fans out `fetchSeries(params)` to all venue instances with
24
+ * `has.fetchSeries !== false`, collects, and returns deduplicated results
25
+ * tagged with their `sourceExchange`.
26
+ */
27
+ protected fetchSeriesImpl(params: SeriesFetchParams): Promise<UnifiedSeries[]>;
28
+ /**
29
+ * Build a single synthesized `UnifiedSeries` from the SERIES_MAP entry by
30
+ * fetching events from all mapped venues and concatenating them.
31
+ */
32
+ private fetchSynthesizedSeries;
33
+ /**
34
+ * Fan out `fetchSeries(params)` to all venue instances whose
35
+ * `has.fetchSeries` is not `false`. Tag each result with its originating
36
+ * venue name.
37
+ */
38
+ private fanOutFetchSeries;
12
39
  fetchOrderBook(outcomeId: string, limit?: number, params?: Record<string, any>): Promise<OrderBook>;
13
40
  fetchMarketMatches(params?: FetchMarketMatchesParams): Promise<MatchResult[]>;
14
41
  /**
@@ -5,6 +5,7 @@ const BaseExchange_1 = require("../BaseExchange");
5
5
  const errors_1 = require("../errors");
6
6
  const logger_1 = require("../utils/logger");
7
7
  const client_1 = require("./client");
8
+ const series_map_1 = require("./series-map");
8
9
  // ---------------------------------------------------------------------------
9
10
  // Orderbook merge utilities
10
11
  // ---------------------------------------------------------------------------
@@ -127,6 +128,18 @@ class Router extends BaseExchange_1.PredictionMarketExchange {
127
128
  return response;
128
129
  }
129
130
  async fetchEventsImpl(params) {
131
+ // When a normalized series id is requested, fan out to each mapped venue
132
+ // using the venue-native series id and aggregate the results.
133
+ if (params?.series !== undefined) {
134
+ const normalized = params.series;
135
+ const entry = series_map_1.SERIES_MAP.find((e) => e.id === normalized);
136
+ if (entry !== undefined) {
137
+ return this.fetchEventsForMappedSeries(entry.venues, params);
138
+ }
139
+ // Not a known normalized id — fall through and pass the raw value to
140
+ // the hosted search endpoint (single-venue callers using vendor-native
141
+ // ids still work).
142
+ }
130
143
  const response = await this.client.searchEvents({
131
144
  query: params?.query,
132
145
  category: params?.category,
@@ -138,6 +151,138 @@ class Router extends BaseExchange_1.PredictionMarketExchange {
138
151
  }
139
152
  return response;
140
153
  }
154
+ /**
155
+ * Fan out fetchEvents({series: venueSeriesId}) to each venue in the
156
+ * mapping, collect all results, and tag each event with its sourceExchange.
157
+ */
158
+ async fetchEventsForMappedSeries(venueMap, baseParams) {
159
+ const venueEntries = Object.entries(venueMap);
160
+ if (venueEntries.length === 0)
161
+ return [];
162
+ const fetchResults = await Promise.all(venueEntries.map(async ([venueName, venueSeriesId]) => {
163
+ const exchange = this.localExchanges[venueName];
164
+ if (!exchange) {
165
+ logger_1.logger.debug(`Router.fetchEventsForMappedSeries: no exchange instance for venue "${venueName}", skipping`);
166
+ return [];
167
+ }
168
+ try {
169
+ const events = await exchange.fetchEvents({
170
+ ...baseParams,
171
+ series: venueSeriesId,
172
+ });
173
+ return events.map((ev) => ({
174
+ ...ev,
175
+ sourceExchange: ev.sourceExchange ?? venueName,
176
+ }));
177
+ }
178
+ catch (error) {
179
+ logger_1.logger.warn(`Router.fetchEventsForMappedSeries: fetchEvents failed for venue "${venueName}" ` +
180
+ `series "${venueSeriesId}": ${error instanceof Error ? error.message : String(error)}`);
181
+ return [];
182
+ }
183
+ }));
184
+ return fetchResults.flat();
185
+ }
186
+ // -----------------------------------------------------------------------
187
+ // Cross-venue series (series-map + fan-out)
188
+ // -----------------------------------------------------------------------
189
+ /**
190
+ * Cross-venue series fetch.
191
+ *
192
+ * - If `params.id` matches a normalized id in SERIES_MAP, returns a single
193
+ * synthesized `UnifiedSeries` whose `events` is the concatenation of
194
+ * `fetchEvents({series: venueSeriesId})` results from each mapped venue.
195
+ * - Otherwise fans out `fetchSeries(params)` to all venue instances with
196
+ * `has.fetchSeries !== false`, collects, and returns deduplicated results
197
+ * tagged with their `sourceExchange`.
198
+ */
199
+ async fetchSeriesImpl(params) {
200
+ const requestedId = params.id;
201
+ if (requestedId !== undefined) {
202
+ const entry = series_map_1.SERIES_MAP.find((e) => e.id === requestedId);
203
+ if (entry !== undefined) {
204
+ return this.fetchSynthesizedSeries(entry, params);
205
+ }
206
+ }
207
+ return this.fanOutFetchSeries(params);
208
+ }
209
+ /**
210
+ * Build a single synthesized `UnifiedSeries` from the SERIES_MAP entry by
211
+ * fetching events from all mapped venues and concatenating them.
212
+ */
213
+ async fetchSynthesizedSeries(entry, params) {
214
+ const venueEntries = Object.entries(entry.venues);
215
+ const eventsPerVenue = await Promise.all(venueEntries.map(async ([venueName, venueSeriesId]) => {
216
+ const exchange = this.localExchanges[venueName];
217
+ if (!exchange) {
218
+ logger_1.logger.debug(`Router.fetchSynthesizedSeries: no exchange instance for venue "${venueName}", skipping`);
219
+ return [];
220
+ }
221
+ try {
222
+ const events = await exchange.fetchEvents({ series: venueSeriesId });
223
+ return events.map((ev) => ({
224
+ ...ev,
225
+ sourceExchange: ev.sourceExchange ?? venueName,
226
+ }));
227
+ }
228
+ catch (error) {
229
+ logger_1.logger.warn(`Router.fetchSynthesizedSeries: fetchEvents failed for venue "${venueName}" ` +
230
+ `series "${venueSeriesId}": ${error instanceof Error ? error.message : String(error)}`);
231
+ return [];
232
+ }
233
+ }));
234
+ const allEvents = eventsPerVenue.flat();
235
+ const synthesized = {
236
+ id: entry.id,
237
+ title: entry.title,
238
+ events: allEvents,
239
+ sourceExchange: 'Router',
240
+ };
241
+ // Apply limit/offset if the caller passed them (BaseExchange.fetchSeries strips
242
+ // them before calling fetchSeriesImpl, but guard defensively).
243
+ const limit = params.limit;
244
+ const offset = params.offset ?? 0;
245
+ if (limit !== undefined) {
246
+ return [{ ...synthesized, events: allEvents.slice(offset, offset + limit) }];
247
+ }
248
+ return [synthesized];
249
+ }
250
+ /**
251
+ * Fan out `fetchSeries(params)` to all venue instances whose
252
+ * `has.fetchSeries` is not `false`. Tag each result with its originating
253
+ * venue name.
254
+ */
255
+ async fanOutFetchSeries(params) {
256
+ const venueEntries = Object.entries(this.localExchanges);
257
+ if (venueEntries.length === 0)
258
+ return [];
259
+ const fetchResults = await Promise.all(venueEntries.map(async ([venueName, exchange]) => {
260
+ if (exchange.has.fetchSeries === false)
261
+ return [];
262
+ // When params.id is a venue-native id on this specific venue,
263
+ // pass it through directly so single-venue lookups still work.
264
+ let venueParams = params;
265
+ if (params.id !== undefined) {
266
+ const nativeId = (0, series_map_1.getVenueSeriesId)(params.id, venueName);
267
+ if (nativeId !== undefined) {
268
+ venueParams = { ...params, id: nativeId };
269
+ }
270
+ }
271
+ try {
272
+ const series = await exchange.fetchSeries(venueParams);
273
+ return series.map((s) => ({
274
+ ...s,
275
+ sourceExchange: s.sourceExchange ?? venueName,
276
+ }));
277
+ }
278
+ catch (error) {
279
+ logger_1.logger.warn(`Router.fanOutFetchSeries: fetchSeries failed for venue "${venueName}": ` +
280
+ `${error instanceof Error ? error.message : String(error)}`);
281
+ return [];
282
+ }
283
+ }));
284
+ return fetchResults.flat();
285
+ }
141
286
  // -----------------------------------------------------------------------
142
287
  // Unified orderbook (cross-exchange merge)
143
288
  // -----------------------------------------------------------------------
@@ -1,3 +1,4 @@
1
1
  export { Router } from './Router';
2
2
  export { PmxtApiClient } from './client';
3
3
  export * from './types';
4
+ export * from './series-map';
@@ -20,3 +20,4 @@ Object.defineProperty(exports, "Router", { enumerable: true, get: function () {
20
20
  var client_1 = require("./client");
21
21
  Object.defineProperty(exports, "PmxtApiClient", { enumerable: true, get: function () { return client_1.PmxtApiClient; } });
22
22
  __exportStar(require("./types"), exports);
23
+ __exportStar(require("./series-map"), exports);
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Curated mapping from normalized PMXT series ids to per-venue native series ids.
3
+ *
4
+ * The normalized ids use kebab-case following the pattern:
5
+ * <sport-or-domain>-<category-or-format>
6
+ *
7
+ * Venue-native ids are the raw tickers/slugs each platform uses.
8
+ * It is intentional for some entries to have only partial venue coverage --
9
+ * the Router handles missing venue mappings gracefully by skipping that venue.
10
+ */
11
+ export interface RouterSeriesEntry {
12
+ /** Normalized PMXT series id (kebab-case). */
13
+ id: string;
14
+ /** Human-readable title. */
15
+ title: string;
16
+ /** Map of venueName -> venue-native series id. */
17
+ venues: {
18
+ readonly [venueName: string]: string;
19
+ };
20
+ }
21
+ export declare const SERIES_MAP: readonly RouterSeriesEntry[];
22
+ /**
23
+ * Resolve a normalized PMXT series id to the venue-native series id for a
24
+ * given venue. Returns `undefined` when either the normalized id is not in the
25
+ * map or that venue has no mapping for it.
26
+ */
27
+ export declare function getVenueSeriesId(normalizedId: string, venue: string): string | undefined;
28
+ /**
29
+ * Reverse-lookup: given a venue name and a venue-native series id, return the
30
+ * normalized PMXT series id. Returns `undefined` when not found.
31
+ */
32
+ export declare function getNormalizedSeriesId(venue: string, venueSeriesId: string): string | undefined;
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ /**
3
+ * Curated mapping from normalized PMXT series ids to per-venue native series ids.
4
+ *
5
+ * The normalized ids use kebab-case following the pattern:
6
+ * <sport-or-domain>-<category-or-format>
7
+ *
8
+ * Venue-native ids are the raw tickers/slugs each platform uses.
9
+ * It is intentional for some entries to have only partial venue coverage --
10
+ * the Router handles missing venue mappings gracefully by skipping that venue.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.SERIES_MAP = void 0;
14
+ exports.getVenueSeriesId = getVenueSeriesId;
15
+ exports.getNormalizedSeriesId = getNormalizedSeriesId;
16
+ exports.SERIES_MAP = [
17
+ {
18
+ id: 'tennis-atp-match',
19
+ title: 'ATP Match Winner',
20
+ venues: {
21
+ kalshi: 'KXATPSETWINNER',
22
+ polymarket: 'atp',
23
+ },
24
+ },
25
+ {
26
+ id: 'tennis-atp-challenger',
27
+ title: 'ATP Challenger Match Winner',
28
+ venues: {
29
+ kalshi: 'KXATPCHALLENGERMATCH',
30
+ },
31
+ },
32
+ {
33
+ id: 'tennis-wta-match',
34
+ title: 'WTA Match Winner',
35
+ venues: {
36
+ kalshi: 'KXWTASETWINNER',
37
+ polymarket: 'wta',
38
+ },
39
+ },
40
+ {
41
+ id: 'tennis-itf-match',
42
+ title: 'ITF Match Winner',
43
+ venues: {
44
+ kalshi: 'KXITFMATCH',
45
+ },
46
+ },
47
+ {
48
+ id: 'tennis-itf-women-match',
49
+ title: "ITF Women's Match Winner",
50
+ venues: {
51
+ kalshi: 'KXITFWMATCH',
52
+ },
53
+ },
54
+ {
55
+ id: 'nfl',
56
+ title: 'NFL Game Winner',
57
+ venues: {
58
+ kalshi: 'KXNFLGAME',
59
+ polymarket: 'nfl-game',
60
+ },
61
+ },
62
+ {
63
+ id: 'nba',
64
+ title: 'NBA Game Winner',
65
+ venues: {
66
+ kalshi: 'KXNBAGAME',
67
+ polymarket: 'nba',
68
+ },
69
+ },
70
+ {
71
+ id: 'ncaa-basketball',
72
+ title: 'NCAA Basketball Game Winner',
73
+ venues: {
74
+ kalshi: 'KXNCAABBGAME',
75
+ },
76
+ },
77
+ {
78
+ id: 'ufc',
79
+ title: 'UFC Fight Winner',
80
+ venues: {
81
+ polymarket: 'ufc',
82
+ },
83
+ },
84
+ {
85
+ id: 'soccer-fifa-world-cup',
86
+ title: 'FIFA World Cup Match Winner',
87
+ venues: {
88
+ polymarket: 'soccer-fifwc',
89
+ },
90
+ },
91
+ {
92
+ id: 'esports-cs2-map',
93
+ title: 'CS2 Map Winner',
94
+ venues: {
95
+ kalshi: 'KXCS2MAP',
96
+ },
97
+ },
98
+ {
99
+ id: 'esports-lol-map',
100
+ title: 'League of Legends Map Winner',
101
+ venues: {
102
+ kalshi: 'KXLOLMAP',
103
+ },
104
+ },
105
+ {
106
+ id: 'crypto-btc-15m',
107
+ title: 'Bitcoin Price (15-minute)',
108
+ venues: {
109
+ kalshi: 'KXBTC15M',
110
+ },
111
+ },
112
+ {
113
+ id: 'crypto-eth-15m',
114
+ title: 'Ethereum Price (15-minute)',
115
+ venues: {
116
+ kalshi: 'KXETH15M',
117
+ },
118
+ },
119
+ {
120
+ id: 'crypto-sol-15m',
121
+ title: 'Solana Price (15-minute)',
122
+ venues: {
123
+ kalshi: 'KXSOL15M',
124
+ },
125
+ },
126
+ ];
127
+ // ---------------------------------------------------------------------------
128
+ // Lookup helpers (O(n) over small constant array; acceptable for this table)
129
+ // ---------------------------------------------------------------------------
130
+ /**
131
+ * Resolve a normalized PMXT series id to the venue-native series id for a
132
+ * given venue. Returns `undefined` when either the normalized id is not in the
133
+ * map or that venue has no mapping for it.
134
+ */
135
+ function getVenueSeriesId(normalizedId, venue) {
136
+ const entry = exports.SERIES_MAP.find((e) => e.id === normalizedId);
137
+ return entry?.venues[venue];
138
+ }
139
+ /**
140
+ * Reverse-lookup: given a venue name and a venue-native series id, return the
141
+ * normalized PMXT series id. Returns `undefined` when not found.
142
+ */
143
+ function getNormalizedSeriesId(venue, venueSeriesId) {
144
+ const entry = exports.SERIES_MAP.find((e) => e.venues[venue] === venueSeriesId);
145
+ return entry?.id;
146
+ }
@@ -49,6 +49,16 @@
49
49
  }
50
50
  ]
51
51
  },
52
+ "fetchSeries": {
53
+ "verb": "get",
54
+ "args": [
55
+ {
56
+ "name": "params",
57
+ "kind": "object",
58
+ "optional": true
59
+ }
60
+ ]
61
+ },
52
62
  "fetchMarket": {
53
63
  "verb": "get",
54
64
  "args": [