pmxt-core 2.16.1 → 2.17.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.
@@ -272,7 +272,7 @@ export declare abstract class PredictionMarketExchange {
272
272
  * Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
273
273
  *
274
274
  * @param params - Optional parameters for search and filtering
275
- * @param params.query - Search keyword to filter events (required)
275
+ * @param params.query - Search keyword to filter events. If omitted, returns top events by volume.
276
276
  * @param params.limit - Maximum number of results
277
277
  * @param params.offset - Pagination offset
278
278
  * @param params.searchIn - Where to search ('title' | 'description' | 'both')
@@ -242,7 +242,7 @@ class PredictionMarketExchange {
242
242
  * Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
243
243
  *
244
244
  * @param params - Optional parameters for search and filtering
245
- * @param params.query - Search keyword to filter events (required)
245
+ * @param params.query - Search keyword to filter events. If omitted, returns top events by volume.
246
246
  * @param params.limit - Maximum number of results
247
247
  * @param params.offset - Pagination offset
248
248
  * @param params.searchIn - Where to search ('title' | 'description' | 'both')
@@ -261,10 +261,7 @@ class PredictionMarketExchange {
261
261
  * print(fed_event.title, len(fed_event.markets), 'markets')
262
262
  */
263
263
  async fetchEvents(params) {
264
- if (!params?.query && !params?.eventId && !params?.slug) {
265
- throw new Error("fetchEvents() requires a query, eventId, or slug parameter");
266
- }
267
- return this.fetchEventsImpl(params);
264
+ return this.fetchEventsImpl(params ?? {});
268
265
  }
269
266
  /**
270
267
  * Fetch a single market by lookup parameters.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
3
- * Generated at: 2026-02-24T09:41:14.329Z
3
+ * Generated at: 2026-02-24T10:20:38.358Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const kalshiApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.kalshiApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
6
- * Generated at: 2026-02-24T09:41:14.329Z
6
+ * Generated at: 2026-02-24T10:20:38.358Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.kalshiApiSpec = {
@@ -34,6 +34,52 @@ async function fetchEventByTicker(eventTicker, callApi) {
34
34
  };
35
35
  return [unifiedEvent];
36
36
  }
37
+ function rawEventToUnified(event) {
38
+ const markets = [];
39
+ if (event.markets) {
40
+ for (const market of event.markets) {
41
+ const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market);
42
+ if (unifiedMarket) {
43
+ markets.push(unifiedMarket);
44
+ }
45
+ }
46
+ }
47
+ return {
48
+ id: event.event_ticker,
49
+ title: event.title,
50
+ description: event.mututals_description || "",
51
+ slug: event.event_ticker,
52
+ markets: markets,
53
+ url: `https://kalshi.com/events/${event.event_ticker}`,
54
+ image: event.image_url,
55
+ category: event.category,
56
+ tags: event.tags || [],
57
+ };
58
+ }
59
+ async function fetchAllWithStatus(callApi, apiStatus) {
60
+ let allEvents = [];
61
+ let cursor = null;
62
+ let page = 0;
63
+ const MAX_PAGES = 1000;
64
+ const BATCH_SIZE = 200;
65
+ do {
66
+ const queryParams = {
67
+ limit: BATCH_SIZE,
68
+ with_nested_markets: true,
69
+ status: apiStatus,
70
+ };
71
+ if (cursor)
72
+ queryParams.cursor = cursor;
73
+ const data = await callApi("GetEvents", queryParams);
74
+ const events = data.events || [];
75
+ if (events.length === 0)
76
+ break;
77
+ allEvents = allEvents.concat(events);
78
+ cursor = data.cursor;
79
+ page++;
80
+ } while (cursor && page < MAX_PAGES);
81
+ return allEvents;
82
+ }
37
83
  async function fetchEvents(params, callApi) {
38
84
  try {
39
85
  // Handle eventId lookup (direct API call)
@@ -47,82 +93,64 @@ async function fetchEvents(params, callApi) {
47
93
  const status = params?.status || "active";
48
94
  const limit = params?.limit || 10000;
49
95
  const query = (params?.query || "").toLowerCase();
50
- const fetchAllWithStatus = async (apiStatus) => {
51
- let allEvents = [];
52
- let cursor = null;
53
- let page = 0;
54
- const MAX_PAGES = 1000; // Safety cap against infinite loops
55
- const BATCH_SIZE = 200; // Max limit per Kalshi API docs
56
- do {
57
- const queryParams = {
58
- limit: BATCH_SIZE,
59
- with_nested_markets: true,
60
- status: apiStatus,
61
- };
62
- if (cursor)
63
- queryParams.cursor = cursor;
64
- const data = await callApi("GetEvents", queryParams);
65
- const events = data.events || [];
66
- if (events.length === 0)
67
- break;
68
- allEvents = allEvents.concat(events);
69
- cursor = data.cursor;
70
- page++;
71
- // If we have no search query and have fetched enough events, we can stop early
72
- if (!query && allEvents.length >= limit * 1.5) {
73
- break;
74
- }
75
- } while (cursor && page < MAX_PAGES);
76
- return allEvents;
77
- };
78
96
  let events = [];
79
97
  if (status === "all") {
80
98
  const [openEvents, closedEvents, settledEvents] = await Promise.all([
81
- fetchAllWithStatus("open"),
82
- fetchAllWithStatus("closed"),
83
- fetchAllWithStatus("settled"),
99
+ fetchAllWithStatus(callApi, "open"),
100
+ fetchAllWithStatus(callApi, "closed"),
101
+ fetchAllWithStatus(callApi, "settled"),
84
102
  ]);
85
103
  events = [...openEvents, ...closedEvents, ...settledEvents];
86
104
  }
87
105
  else if (status === "closed" || status === "inactive") {
88
106
  const [closedEvents, settledEvents] = await Promise.all([
89
- fetchAllWithStatus("closed"),
90
- fetchAllWithStatus("settled"),
107
+ fetchAllWithStatus(callApi, "closed"),
108
+ fetchAllWithStatus(callApi, "settled"),
91
109
  ]);
92
110
  events = [...closedEvents, ...settledEvents];
93
111
  }
94
112
  else {
95
- events = await fetchAllWithStatus("open");
113
+ events = await fetchAllWithStatus(callApi, "open");
96
114
  }
97
- const filtered = events.filter((event) => {
98
- return (event.title || "").toLowerCase().includes(query);
99
- });
100
- const unifiedEvents = filtered.map((event) => {
101
- const markets = [];
102
- if (event.markets) {
103
- for (const market of event.markets) {
104
- const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market);
105
- if (unifiedMarket) {
106
- markets.push(unifiedMarket);
107
- }
108
- }
109
- }
110
- const unifiedEvent = {
111
- id: event.event_ticker,
112
- title: event.title,
113
- description: event.mututals_description || "",
114
- slug: event.event_ticker,
115
- markets: markets,
116
- url: `https://kalshi.com/events/${event.event_ticker}`,
117
- image: event.image_url,
118
- category: event.category,
119
- tags: event.tags || [],
120
- };
121
- return unifiedEvent;
122
- });
115
+ // Apply keyword filter if a query was provided
116
+ const filtered = query
117
+ ? events.filter((event) => (event.title || "").toLowerCase().includes(query))
118
+ : events;
119
+ // Client-side sort — Kalshi's /events endpoint has no sort param.
120
+ // We aggregate stats from nested markets and sort the full set before slicing.
121
+ const sort = params?.sort || "volume";
122
+ const sorted = sortRawEvents(filtered, sort);
123
+ const unifiedEvents = sorted.map(rawEventToUnified);
123
124
  return unifiedEvents.slice(0, limit);
124
125
  }
125
126
  catch (error) {
126
127
  throw errors_1.kalshiErrorMapper.mapError(error);
127
128
  }
128
129
  }
130
+ function eventVolume(event) {
131
+ return (event.markets || []).reduce((sum, m) => sum + Number(m.volume || 0), 0);
132
+ }
133
+ function eventLiquidity(event) {
134
+ return (event.markets || []).reduce((sum, m) => sum + Number(m.open_interest || m.liquidity || 0), 0);
135
+ }
136
+ function eventNewest(event) {
137
+ // Use the earliest close_time across markets as a proxy for "newness"
138
+ const times = (event.markets || [])
139
+ .map((m) => (m.close_time ? new Date(m.close_time).getTime() : 0))
140
+ .filter((t) => t > 0);
141
+ return times.length > 0 ? Math.min(...times) : 0;
142
+ }
143
+ function sortRawEvents(events, sort) {
144
+ const copy = [...events];
145
+ if (sort === "newest") {
146
+ copy.sort((a, b) => eventNewest(b) - eventNewest(a));
147
+ }
148
+ else if (sort === "liquidity") {
149
+ copy.sort((a, b) => eventLiquidity(b) - eventLiquidity(a));
150
+ }
151
+ else {
152
+ // Default: volume
153
+ copy.sort((a, b) => eventVolume(b) - eventVolume(a));
154
+ }
155
+ return copy;
156
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
3
- * Generated at: 2026-02-24T09:41:14.367Z
3
+ * Generated at: 2026-02-24T10:20:38.402Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const limitlessApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.limitlessApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
6
- * Generated at: 2026-02-24T09:41:14.367Z
6
+ * Generated at: 2026-02-24T10:20:38.402Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.limitlessApiSpec = {
@@ -32,15 +32,17 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
35
38
  Object.defineProperty(exports, "__esModule", { value: true });
36
39
  exports.fetchEvents = fetchEvents;
37
40
  const utils_1 = require("./utils");
38
41
  const errors_1 = require("./errors");
42
+ const axios_1 = __importDefault(require("axios"));
39
43
  async function fetchEventBySlug(slug) {
40
44
  const { HttpClient, MarketFetcher } = await Promise.resolve().then(() => __importStar(require('@limitless-exchange/sdk')));
41
45
  const httpClient = new HttpClient({ baseURL: utils_1.LIMITLESS_API_URL });
42
- // TODO: Ideally inject http into HttpClient if supported, but SDK abstracts it.
43
- // For now, single market fetch uses SDK's internal client.
44
46
  const marketFetcher = new MarketFetcher(httpClient);
45
47
  const market = await marketFetcher.getMarket(slug);
46
48
  if (!market)
@@ -68,6 +70,30 @@ async function fetchEventBySlug(slug) {
68
70
  tags: market.tags || []
69
71
  };
70
72
  }
73
+ function rawMarketToEvent(market) {
74
+ let marketsList = [];
75
+ if (market.markets && Array.isArray(market.markets)) {
76
+ marketsList = market.markets
77
+ .map((child) => (0, utils_1.mapMarketToUnified)(child))
78
+ .filter((m) => m !== null);
79
+ }
80
+ else {
81
+ const unifiedMarket = (0, utils_1.mapMarketToUnified)(market);
82
+ if (unifiedMarket)
83
+ marketsList = [unifiedMarket];
84
+ }
85
+ return {
86
+ id: market.slug,
87
+ title: market.title || market.question,
88
+ description: market.description || '',
89
+ slug: market.slug,
90
+ markets: marketsList,
91
+ url: `https://limitless.exchange/markets/${market.slug}`,
92
+ image: market.logo || `https://limitless.exchange/api/og?slug=${market.slug}`,
93
+ category: market.categories?.[0],
94
+ tags: market.tags || []
95
+ };
96
+ }
71
97
  async function fetchEvents(params, callApi) {
72
98
  try {
73
99
  // Handle eventId/slug lookup (same thing for Limitless)
@@ -76,52 +102,66 @@ async function fetchEvents(params, callApi) {
76
102
  const event = await fetchEventBySlug(slug);
77
103
  return event ? [event] : [];
78
104
  }
79
- // NOTE: The Limitless /markets/search endpoint currently only returns active/funded markets.
80
- // It does not include expired or resolved markets in search results.
81
- // Consequently, status 'inactive' will likely return 0 results and 'all' will only show active markets.
82
- const data = await callApi('MarketSearchController_search', {
83
- query: params.query,
84
- limit: params?.limit || 10000,
85
- similarityThreshold: 0.5,
86
- });
87
- let markets = data?.markets || [];
88
- // Filter by status based on expired/resolved state
89
- // Active: not expired and not resolved
90
- // Inactive: expired OR resolved (has winningOutcomeIndex)
91
- const status = params?.status || 'active';
92
- if (status === 'active') {
93
- markets = markets.filter((m) => !m.expired && m.winningOutcomeIndex === null);
94
- }
95
- else if (status === 'inactive' || status === 'closed') {
96
- markets = markets.filter((m) => m.expired === true || m.winningOutcomeIndex !== null);
105
+ // Query-based search: use the /markets/search endpoint
106
+ if (params.query) {
107
+ return await searchEvents(params, callApi);
97
108
  }
98
- // If status === 'all', don't filter
99
- return markets.map((market) => {
100
- let marketsList = [];
101
- if (market.markets && Array.isArray(market.markets)) {
102
- marketsList = market.markets
103
- .map((child) => (0, utils_1.mapMarketToUnified)(child))
104
- .filter((m) => m !== null);
105
- }
106
- else {
107
- const unifiedMarket = (0, utils_1.mapMarketToUnified)(market);
108
- if (unifiedMarket)
109
- marketsList = [unifiedMarket];
110
- }
111
- return {
112
- id: market.slug,
113
- title: market.title || market.question,
114
- description: market.description || '',
115
- slug: market.slug,
116
- markets: marketsList,
117
- url: `https://limitless.exchange/markets/${market.slug}`,
118
- image: market.logo || `https://limitless.exchange/api/og?slug=${market.slug}`,
119
- category: market.categories?.[0],
120
- tags: market.tags || []
121
- };
122
- });
109
+ // Default: fetch active group markets from /markets/active
110
+ // On Limitless, "events" = group markets (tradeType === 'group')
111
+ return await fetchEventsDefault(params);
123
112
  }
124
113
  catch (error) {
125
114
  throw errors_1.limitlessErrorMapper.mapError(error);
126
115
  }
127
116
  }
117
+ async function searchEvents(params, callApi) {
118
+ // NOTE: The Limitless /markets/search endpoint currently only returns active/funded markets.
119
+ const data = await callApi('MarketSearchController_search', {
120
+ query: params.query,
121
+ limit: params?.limit || 10000,
122
+ similarityThreshold: 0.5,
123
+ });
124
+ let markets = data?.markets || [];
125
+ const status = params?.status || 'active';
126
+ if (status === 'active') {
127
+ markets = markets.filter((m) => !m.expired && m.winningOutcomeIndex === null);
128
+ }
129
+ else if (status === 'inactive' || status === 'closed') {
130
+ markets = markets.filter((m) => m.expired === true || m.winningOutcomeIndex !== null);
131
+ }
132
+ return markets.map(rawMarketToEvent);
133
+ }
134
+ async function fetchEventsDefault(params) {
135
+ // Limitless has no dedicated /events endpoint.
136
+ // Group markets (tradeType === 'group') are the semantic equivalent of events.
137
+ // We use GET /markets/active and filter for groups only.
138
+ const limit = params?.limit || 10000;
139
+ let page = 1;
140
+ const pageSize = 25; // Limitless API hard limit
141
+ const MAX_PAGES = 40; // Safety cap
142
+ const allGroups = [];
143
+ while (allGroups.length < limit && page <= MAX_PAGES) {
144
+ const response = await axios_1.default.get(`${utils_1.LIMITLESS_API_URL}/markets/active`, {
145
+ params: {
146
+ page,
147
+ limit: pageSize,
148
+ tradeType: 'group',
149
+ sortBy: params?.sort === 'newest' ? 'newest' : params?.sort === 'liquidity' ? 'lp_rewards' : 'high_value',
150
+ }
151
+ });
152
+ const items = response.data?.data || response.data || [];
153
+ if (items.length === 0)
154
+ break;
155
+ for (const item of items) {
156
+ if (allGroups.length >= limit)
157
+ break;
158
+ const event = rawMarketToEvent(item);
159
+ allGroups.push(event);
160
+ }
161
+ // If the page returned fewer items than the page size, we've reached the end
162
+ if (items.length < pageSize)
163
+ break;
164
+ page++;
165
+ }
166
+ return allGroups;
167
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
3
- * Generated at: 2026-02-24T09:41:14.379Z
3
+ * Generated at: 2026-02-24T10:20:38.413Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const myriadApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.myriadApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
6
- * Generated at: 2026-02-24T09:41:14.379Z
6
+ * Generated at: 2026-02-24T10:20:38.413Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.myriadApiSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
3
- * Generated at: 2026-02-24T09:41:14.335Z
3
+ * Generated at: 2026-02-24T10:20:38.367Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketClobSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketClobSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
6
- * Generated at: 2026-02-24T09:41:14.335Z
6
+ * Generated at: 2026-02-24T10:20:38.367Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketClobSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
3
- * Generated at: 2026-02-24T09:41:14.348Z
3
+ * Generated at: 2026-02-24T10:20:38.384Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketDataSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketDataSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
6
- * Generated at: 2026-02-24T09:41:14.348Z
6
+ * Generated at: 2026-02-24T10:20:38.384Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketDataSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
3
- * Generated at: 2026-02-24T09:41:14.345Z
3
+ * Generated at: 2026-02-24T10:20:38.380Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketGammaSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketGammaSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
6
- * Generated at: 2026-02-24T09:41:14.345Z
6
+ * Generated at: 2026-02-24T10:20:38.380Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketGammaSpec = {
@@ -7,36 +7,32 @@ exports.fetchEvents = fetchEvents;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const utils_1 = require("./utils");
9
9
  const errors_1 = require("./errors");
10
+ function mapRawEventToUnified(event) {
11
+ const markets = [];
12
+ if (event.markets && Array.isArray(event.markets)) {
13
+ for (const market of event.markets) {
14
+ const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market, { useQuestionAsCandidateFallback: true });
15
+ if (unifiedMarket) {
16
+ markets.push(unifiedMarket);
17
+ }
18
+ }
19
+ }
20
+ return {
21
+ id: event.id || event.slug,
22
+ title: event.title,
23
+ description: event.description || '',
24
+ slug: event.slug,
25
+ markets: markets,
26
+ url: `https://polymarket.com/event/${event.slug}`,
27
+ image: event.image || `https://polymarket.com/api/og?slug=${event.slug}`,
28
+ category: event.category || event.tags?.[0]?.label,
29
+ tags: event.tags?.map((t) => t.label) || []
30
+ };
31
+ }
10
32
  async function fetchEvents(params, http = axios_1.default) {
11
33
  try {
12
- if (!params.query && !params.eventId && !params.slug) {
13
- throw new Error("Query, eventId, or slug is required for Polymarket event search");
14
- }
15
34
  const limit = params.limit || 10000;
16
- const status = params.status || 'active';
17
- // Helper to map a raw event to a UnifiedEvent
18
- const mapRawEventToUnified = (event) => {
19
- const markets = [];
20
- if (event.markets && Array.isArray(event.markets)) {
21
- for (const market of event.markets) {
22
- const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market, { useQuestionAsCandidateFallback: true });
23
- if (unifiedMarket) {
24
- markets.push(unifiedMarket);
25
- }
26
- }
27
- }
28
- return {
29
- id: event.id || event.slug,
30
- title: event.title,
31
- description: event.description || '',
32
- slug: event.slug,
33
- markets: markets,
34
- url: `https://polymarket.com/event/${event.slug}`,
35
- image: event.image || `https://polymarket.com/api/og?slug=${event.slug}`,
36
- category: event.category || event.tags?.[0]?.label,
37
- tags: event.tags?.map((t) => t.label) || []
38
- };
39
- };
35
+ // Handle eventId or slug lookup (direct API call)
40
36
  if (params.eventId || params.slug) {
41
37
  const queryParams = params.eventId ? { id: params.eventId } : { slug: params.slug };
42
38
  const response = await http.get(utils_1.GAMMA_API_URL, { params: queryParams });
@@ -45,68 +41,92 @@ async function fetchEvents(params, http = axios_1.default) {
45
41
  return [];
46
42
  return events.map(mapRawEventToUnified).slice(0, limit);
47
43
  }
48
- let sortParam = 'volume';
49
- if (params.sort === 'newest')
50
- sortParam = 'startDate';
51
- if (params.sort === 'liquidity')
52
- sortParam = 'liquidity';
53
- const queryParams = {
54
- q: params.query,
55
- limit_per_type: 50,
56
- sort: sortParam,
57
- ascending: false
58
- };
59
- const fetchWithStatus = async (eventStatus) => {
60
- const currentParams = { ...queryParams, events_status: eventStatus };
61
- return (0, utils_1.paginateSearchParallel)(utils_1.GAMMA_SEARCH_URL, currentParams, limit * 10, http);
62
- };
63
- // Client-side filtering logic
64
- // The API returns active events when querying for 'closed' status sometimes.
65
- // We must strictly filter based on the event's `active` and `closed` properties.
66
- const filterActive = (e) => e.active === true;
67
- const filterClosed = (e) => e.closed === true;
68
- let events = [];
69
- if (status === 'all') {
70
- const [activeEvents, closedEvents] = await Promise.all([
71
- fetchWithStatus('active'),
72
- fetchWithStatus('closed')
73
- ]);
74
- // Merge and de-duplicate by ID
75
- const seenIds = new Set();
76
- events = [...activeEvents, ...closedEvents].filter(event => {
77
- const id = event.id || event.slug;
78
- if (seenIds.has(id))
79
- return false;
80
- seenIds.add(id);
81
- return true;
82
- });
83
- }
84
- else if (status === 'active') {
85
- const rawEvents = await fetchWithStatus('active');
86
- events = rawEvents.filter(filterActive);
44
+ // Handle query-based search (uses the /public-search endpoint)
45
+ if (params.query) {
46
+ return await searchEvents(params, limit, http);
87
47
  }
88
- else if (status === 'inactive' || status === 'closed') {
89
- // Polymarket sometimes returns active events when querying for closed
90
- // So we fetch 'closed' but strictly filter
91
- const rawEvents = await fetchWithStatus('closed');
92
- events = rawEvents.filter(filterClosed);
93
- }
94
- // Client-side filtering to ensure title matches (API does fuzzy search)
95
- const lowerQuery = params.query.toLowerCase();
96
- const searchIn = params.searchIn || 'title';
97
- const filteredEvents = events.filter((event) => {
98
- const titleMatch = (event.title || '').toLowerCase().includes(lowerQuery);
99
- const descMatch = (event.description || '').toLowerCase().includes(lowerQuery);
100
- if (searchIn === 'title')
101
- return titleMatch;
102
- if (searchIn === 'description')
103
- return descMatch;
104
- return titleMatch || descMatch; // 'both'
105
- });
106
- const unifiedEvents = filteredEvents.map(mapRawEventToUnified);
107
- return unifiedEvents.slice(0, limit);
48
+ // Default: fetch top events list from the Gamma /events endpoint (no query required)
49
+ return await fetchEventsDefault(params, limit, http);
108
50
  }
109
51
  catch (error) {
110
52
  throw errors_1.polymarketErrorMapper.mapError(error);
111
53
  }
112
54
  }
55
+ async function searchEvents(params, limit, http) {
56
+ let sortParam = 'volume';
57
+ if (params.sort === 'newest')
58
+ sortParam = 'startDate';
59
+ if (params.sort === 'liquidity')
60
+ sortParam = 'liquidity';
61
+ const queryParams = {
62
+ q: params.query,
63
+ limit_per_type: 50,
64
+ sort: sortParam,
65
+ ascending: false
66
+ };
67
+ const status = params.status || 'active';
68
+ const fetchWithStatus = async (eventStatus) => {
69
+ const currentParams = { ...queryParams, events_status: eventStatus };
70
+ return (0, utils_1.paginateSearchParallel)(utils_1.GAMMA_SEARCH_URL, currentParams, limit * 10, http);
71
+ };
72
+ const filterActive = (e) => e.active === true;
73
+ const filterClosed = (e) => e.closed === true;
74
+ let events = [];
75
+ if (status === 'all') {
76
+ const [activeEvents, closedEvents] = await Promise.all([
77
+ fetchWithStatus('active'),
78
+ fetchWithStatus('closed')
79
+ ]);
80
+ const seenIds = new Set();
81
+ events = [...activeEvents, ...closedEvents].filter(event => {
82
+ const id = event.id || event.slug;
83
+ if (seenIds.has(id))
84
+ return false;
85
+ seenIds.add(id);
86
+ return true;
87
+ });
88
+ }
89
+ else if (status === 'active') {
90
+ const rawEvents = await fetchWithStatus('active');
91
+ events = rawEvents.filter(filterActive);
92
+ }
93
+ else if (status === 'inactive' || status === 'closed') {
94
+ const rawEvents = await fetchWithStatus('closed');
95
+ events = rawEvents.filter(filterClosed);
96
+ }
97
+ const lowerQuery = params.query.toLowerCase();
98
+ const searchIn = params.searchIn || 'title';
99
+ const filteredEvents = events.filter((event) => {
100
+ const titleMatch = (event.title || '').toLowerCase().includes(lowerQuery);
101
+ const descMatch = (event.description || '').toLowerCase().includes(lowerQuery);
102
+ if (searchIn === 'title')
103
+ return titleMatch;
104
+ if (searchIn === 'description')
105
+ return descMatch;
106
+ return titleMatch || descMatch;
107
+ });
108
+ return filteredEvents.map(mapRawEventToUnified).slice(0, limit);
109
+ }
110
+ async function fetchEventsDefault(params, limit, http) {
111
+ const status = params.status || 'active';
112
+ let sortParam = 'volume';
113
+ if (params.sort === 'newest')
114
+ sortParam = 'startDate';
115
+ else if (params.sort === 'liquidity')
116
+ sortParam = 'liquidity';
117
+ const queryParams = {
118
+ order: sortParam,
119
+ ascending: false,
120
+ };
121
+ if (status === 'active') {
122
+ queryParams.active = 'true';
123
+ queryParams.closed = 'false';
124
+ }
125
+ else if (status === 'closed' || status === 'inactive') {
126
+ queryParams.active = 'false';
127
+ queryParams.closed = 'true';
128
+ }
129
+ // 'all' — no status filter applied
130
+ const events = await (0, utils_1.paginateParallel)(utils_1.GAMMA_API_URL, queryParams, http, limit);
131
+ return events.map(mapRawEventToUnified).slice(0, limit);
132
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
3
- * Generated at: 2026-02-24T09:41:14.372Z
3
+ * Generated at: 2026-02-24T10:20:38.408Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const probableApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.probableApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
6
- * Generated at: 2026-02-24T09:41:14.372Z
6
+ * Generated at: 2026-02-24T10:20:38.408Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.probableApiSpec = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxt-core",
3
- "version": "2.16.1",
3
+ "version": "2.17.0",
4
4
  "description": "pmxt is a unified prediction market data API. The ccxt for prediction markets.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -29,8 +29,8 @@
29
29
  "test": "jest -c jest.config.js",
30
30
  "server": "tsx watch src/server/index.ts",
31
31
  "server:prod": "node dist/server/index.js",
32
- "generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.16.1,library=urllib3",
33
- "generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.16.1,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.js",
32
+ "generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.17.0,library=urllib3",
33
+ "generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.17.0,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.js",
34
34
  "fetch:openapi": "node scripts/fetch-openapi-specs.js",
35
35
  "extract:jsdoc": "node ../scripts/extract-jsdoc.js",
36
36
  "generate:docs": "npm run extract:jsdoc && node ../scripts/generate-api-docs.js",