pmxt-core 2.51.0 → 2.51.2
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.
- package/dist/exchanges/hunch/fetcher.d.ts +4 -0
- package/dist/exchanges/hunch/fetcher.js +19 -6
- package/dist/exchanges/hunch/utils.d.ts +8 -0
- package/dist/exchanges/hunch/utils.js +61 -7
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/index.js +4 -1
- package/dist/exchanges/metaculus/index.js +2 -1
- package/dist/exchanges/mock/index.d.ts +1 -1
- package/dist/exchanges/mock/index.js +37 -3
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/myriad/index.js +1 -1
- package/dist/exchanges/opinion/api.d.ts +1 -1
- package/dist/exchanges/opinion/api.js +1 -1
- package/dist/exchanges/opinion/index.js +1 -1
- package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
- package/dist/exchanges/polymarket/api-clob.js +1 -1
- package/dist/exchanges/polymarket/api-data.d.ts +1 -1
- package/dist/exchanges/polymarket/api-data.js +1 -1
- package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
- package/dist/exchanges/polymarket/api-gamma.js +1 -1
- package/dist/exchanges/polymarket_us/config.js +4 -2
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/index.js +1 -1
- package/dist/exchanges/smarkets/config.js +2 -1
- package/dist/server/app.d.ts +9 -0
- package/dist/server/app.js +34 -16
- package/dist/server/exchange-factory.js +9 -3
- package/dist/server/openapi.yaml +1 -0
- package/package.json +3 -3
|
@@ -34,6 +34,10 @@ export interface HunchRawMarket {
|
|
|
34
34
|
/** Present in the schema; absent on the bare list endpoint — optional. */
|
|
35
35
|
volumeUsd?: number;
|
|
36
36
|
totalBets?: number;
|
|
37
|
+
/** Trailing-24h pool inflow (USD); absent on older API builds — optional. */
|
|
38
|
+
volume24hUsd?: number;
|
|
39
|
+
/** Live binary YES/NO odds on the list item; null/absent for N-way markets. */
|
|
40
|
+
odds?: HunchRawBinaryOdds | null;
|
|
37
41
|
targetMarketCapUsd: number | null;
|
|
38
42
|
outcomes: HunchRawOutcome[] | null;
|
|
39
43
|
headline?: string | null;
|
|
@@ -5,6 +5,8 @@ const utils_1 = require("./utils");
|
|
|
5
5
|
const errors_1 = require("./errors");
|
|
6
6
|
const AGENT_PREFIX = '/api/agent/v1';
|
|
7
7
|
const DEFAULT_LIMIT = 200;
|
|
8
|
+
/** Safety backstop for cursor draining: 50 pages * 200 = 10k markets. */
|
|
9
|
+
const MAX_LIST_PAGES = 50;
|
|
8
10
|
/**
|
|
9
11
|
* HunchFetcher — raw GETs against the live agent API. Hunch reads are keyless,
|
|
10
12
|
* so we hit the HTTP client directly (clearer + more robust than the implicit
|
|
@@ -28,6 +30,7 @@ class HunchFetcher {
|
|
|
28
30
|
const one = await this.fetchRawMarketById(params.slug);
|
|
29
31
|
return one ? [one] : [];
|
|
30
32
|
}
|
|
33
|
+
const explicitLimit = typeof params?.limit === 'number';
|
|
31
34
|
const query = {
|
|
32
35
|
limit: params?.limit ?? DEFAULT_LIMIT,
|
|
33
36
|
};
|
|
@@ -36,12 +39,22 @@ class HunchFetcher {
|
|
|
36
39
|
query.status = status;
|
|
37
40
|
if (params?.query)
|
|
38
41
|
query.token = params.query;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
// A catalog crawl (no explicit limit) follows `nextCursor` to drain
|
|
43
|
+
// the whole list; an explicit limit fetches just that one page.
|
|
44
|
+
// MAX_LIST_PAGES is a safety backstop against a runaway cursor loop.
|
|
45
|
+
const all = [];
|
|
46
|
+
let cursor;
|
|
47
|
+
let pages = 0;
|
|
48
|
+
do {
|
|
49
|
+
const res = await this.ctx.http.get(`${this.baseUrl}${AGENT_PREFIX}/markets`, {
|
|
50
|
+
params: cursor ? { ...query, cursor } : query,
|
|
51
|
+
headers: this.ctx.getHeaders(),
|
|
52
|
+
});
|
|
53
|
+
all.push(...(res.data?.markets ?? []));
|
|
54
|
+
cursor = typeof res.data?.nextCursor === 'string' ? res.data.nextCursor : undefined;
|
|
55
|
+
pages += 1;
|
|
56
|
+
} while (!explicitLimit && cursor && pages < MAX_LIST_PAGES);
|
|
57
|
+
return all;
|
|
45
58
|
}
|
|
46
59
|
catch (error) {
|
|
47
60
|
throw errors_1.hunchErrorMapper.mapError(error);
|
|
@@ -45,6 +45,14 @@ export declare function parseHunchSide(outcomeId: string): {
|
|
|
45
45
|
marketId: string;
|
|
46
46
|
side: string;
|
|
47
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* Map a Hunch native category to a pmxt top-level category. Hunch is
|
|
50
|
+
* crypto-native, so every token/price/on-chain subtype rolls up to "Crypto";
|
|
51
|
+
* only the manual "event" markets (fights/debates) map elsewhere.
|
|
52
|
+
*/
|
|
53
|
+
export declare function mapHunchCategory(rawCategory: string | undefined): string;
|
|
54
|
+
/** Tags = top category + a human subtype label + the token (deduped, non-empty). */
|
|
55
|
+
export declare function hunchMarketTags(raw: HunchRawMarket): string[];
|
|
48
56
|
/**
|
|
49
57
|
* Shared market normalizer used by both the live fetch path and the (rare)
|
|
50
58
|
* direct-mapping helper. Pulls a Hunch market ref into a {@link UnifiedMarket}.
|
|
@@ -5,6 +5,8 @@ exports.mapHunchStatus = mapHunchStatus;
|
|
|
5
5
|
exports.mapStatusToHunch = mapStatusToHunch;
|
|
6
6
|
exports.buildOutcomeId = buildOutcomeId;
|
|
7
7
|
exports.parseHunchSide = parseHunchSide;
|
|
8
|
+
exports.mapHunchCategory = mapHunchCategory;
|
|
9
|
+
exports.hunchMarketTags = hunchMarketTags;
|
|
8
10
|
exports.mapHunchMarketToUnified = mapHunchMarketToUnified;
|
|
9
11
|
const market_utils_1 = require("../../utils/market-utils");
|
|
10
12
|
const metadata_1 = require("../../utils/metadata");
|
|
@@ -102,6 +104,55 @@ function parseHunchSide(outcomeId) {
|
|
|
102
104
|
side: outcomeId.slice(idx + 1),
|
|
103
105
|
};
|
|
104
106
|
}
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// Category + tags — map Hunch's fine-grained native taxonomy onto pmxt's
|
|
109
|
+
// top-level categories (Crypto / Culture / …) + granular tags, so Hunch
|
|
110
|
+
// markets answer `?category=` filters and match with higher confidence.
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
/** Hunch native categories that are NOT crypto (manual-resolution markets). */
|
|
113
|
+
const HUNCH_TOP_CATEGORY = {
|
|
114
|
+
event: 'Culture',
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Map a Hunch native category to a pmxt top-level category. Hunch is
|
|
118
|
+
* crypto-native, so every token/price/on-chain subtype rolls up to "Crypto";
|
|
119
|
+
* only the manual "event" markets (fights/debates) map elsewhere.
|
|
120
|
+
*/
|
|
121
|
+
function mapHunchCategory(rawCategory) {
|
|
122
|
+
return HUNCH_TOP_CATEGORY[rawCategory ?? ''] ?? 'Crypto';
|
|
123
|
+
}
|
|
124
|
+
/** Human-readable granular label per Hunch native category (for tags). */
|
|
125
|
+
const HUNCH_SUBTYPE_LABEL = {
|
|
126
|
+
market_cap: 'Market Cap',
|
|
127
|
+
token_mcap_range: 'Market Cap',
|
|
128
|
+
token_mcap_flip: 'Market Cap',
|
|
129
|
+
token_mcap_close: 'Market Cap',
|
|
130
|
+
token_basket_mcap: 'Market Cap',
|
|
131
|
+
price_direction: 'Price',
|
|
132
|
+
token_price_range: 'Price',
|
|
133
|
+
token_return: 'Returns',
|
|
134
|
+
token_rank_milestone: 'Ranking',
|
|
135
|
+
chain_volume: 'On-chain Volume',
|
|
136
|
+
chain_throughput: 'Throughput',
|
|
137
|
+
chain_stablecoins: 'Stablecoins',
|
|
138
|
+
launchpad_volume: 'Launchpad',
|
|
139
|
+
dune_metric: 'On-chain',
|
|
140
|
+
volume_eta: 'Volume',
|
|
141
|
+
event: 'Event',
|
|
142
|
+
};
|
|
143
|
+
function titleCaseSlug(s) {
|
|
144
|
+
return s
|
|
145
|
+
.split(/[_\s-]+/)
|
|
146
|
+
.filter(Boolean)
|
|
147
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
148
|
+
.join(' ');
|
|
149
|
+
}
|
|
150
|
+
/** Tags = top category + a human subtype label + the token (deduped, non-empty). */
|
|
151
|
+
function hunchMarketTags(raw) {
|
|
152
|
+
const top = mapHunchCategory(raw.category);
|
|
153
|
+
const label = HUNCH_SUBTYPE_LABEL[raw.category] ?? (raw.category ? titleCaseSlug(raw.category) : '');
|
|
154
|
+
return [...new Set([top, label, raw.tokenSymbol].filter((t) => Boolean(t)))];
|
|
155
|
+
}
|
|
105
156
|
/**
|
|
106
157
|
* Shared market normalizer used by both the live fetch path and the (rare)
|
|
107
158
|
* direct-mapping helper. Pulls a Hunch market ref into a {@link UnifiedMarket}.
|
|
@@ -119,6 +170,9 @@ function mapHunchMarketToUnified(raw, odds, ladder) {
|
|
|
119
170
|
if (!raw || !raw.id)
|
|
120
171
|
return null;
|
|
121
172
|
const marketId = raw.id;
|
|
173
|
+
// Explicit odds (detail/quote read) win; else fall back to the live odds the
|
|
174
|
+
// list item now carries — so a bare list-crawl prices binary markets too.
|
|
175
|
+
const effectiveOdds = odds ?? raw.odds ?? null;
|
|
122
176
|
let outcomes;
|
|
123
177
|
if (Array.isArray(raw.outcomes) && raw.outcomes.length > 0) {
|
|
124
178
|
// N-way parimutuel ladder / date-window market.
|
|
@@ -148,9 +202,9 @@ function mapHunchMarketToUnified(raw, odds, ladder) {
|
|
|
148
202
|
}
|
|
149
203
|
else {
|
|
150
204
|
// Binary YES/NO market.
|
|
151
|
-
const yesPrice =
|
|
152
|
-
const noPrice =
|
|
153
|
-
?
|
|
205
|
+
const yesPrice = effectiveOdds && typeof effectiveOdds.yesPriceCents === 'number' ? effectiveOdds.yesPriceCents / 100 : 0;
|
|
206
|
+
const noPrice = effectiveOdds && typeof effectiveOdds.noPriceCents === 'number'
|
|
207
|
+
? effectiveOdds.noPriceCents / 100
|
|
154
208
|
: yesPrice > 0
|
|
155
209
|
? 1 - yesPrice
|
|
156
210
|
: 0;
|
|
@@ -166,13 +220,13 @@ function mapHunchMarketToUnified(raw, odds, ladder) {
|
|
|
166
220
|
slug: raw.slug,
|
|
167
221
|
outcomes,
|
|
168
222
|
resolutionDate: raw.deadlineAt ? new Date(raw.deadlineAt) : undefined,
|
|
169
|
-
//
|
|
170
|
-
volume24h: 0,
|
|
223
|
+
// Trailing-24h pool inflow off the list item (0 when absent / no trades).
|
|
224
|
+
volume24h: typeof raw.volume24hUsd === 'number' ? raw.volume24hUsd : 0,
|
|
171
225
|
volume: typeof raw.volumeUsd === 'number' ? raw.volumeUsd : undefined,
|
|
172
226
|
liquidity: Number(raw.virtualLiquidityUsd || 0),
|
|
173
227
|
url: raw.links?.app || `${exports.DEFAULT_BASE_URL}/markets/${raw.slug || marketId}`,
|
|
174
|
-
category: raw.category,
|
|
175
|
-
tags: raw
|
|
228
|
+
category: mapHunchCategory(raw.category),
|
|
229
|
+
tags: hunchMarketTags(raw),
|
|
176
230
|
status: mapHunchStatus(raw.status),
|
|
177
231
|
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, exports.HUNCH_PROMOTED_MARKET_KEYS),
|
|
178
232
|
};
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-23T09:51:53.440Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-23T09:51:53.440Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.kalshiApiSpec = {
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-23T09:51:53.479Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-23T09:51:53.479Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.limitlessApiSpec = {
|
|
@@ -100,7 +100,10 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
100
100
|
callApi: this.callApi.bind(this),
|
|
101
101
|
getHeaders: () => this.getHeaders(),
|
|
102
102
|
};
|
|
103
|
-
const limitlessBaseUrl = this.auth?.host ||
|
|
103
|
+
const limitlessBaseUrl = this.auth?.host ||
|
|
104
|
+
credentials?.baseUrl ||
|
|
105
|
+
process.env.LIMITLESS_BASE_URL ||
|
|
106
|
+
utils_1.DEFAULT_LIMITLESS_API_URL;
|
|
104
107
|
this.fetcher = new fetcher_1.LimitlessFetcher(ctx, this.http, this.auth?.getApiKey(), limitlessBaseUrl);
|
|
105
108
|
this.normalizer = new normalizer_1.LimitlessNormalizer();
|
|
106
109
|
}
|
|
@@ -58,7 +58,8 @@ class MetaculusExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
58
58
|
this.apiToken = credentials?.apiToken;
|
|
59
59
|
// Rate-limit conservatively; authenticated users get higher Metaculus quotas
|
|
60
60
|
this.rateLimit = 500;
|
|
61
|
-
this.baseUrl =
|
|
61
|
+
this.baseUrl =
|
|
62
|
+
credentials?.baseUrl || process.env.METACULUS_BASE_URL || utils_1.DEFAULT_BASE_URL;
|
|
62
63
|
const descriptor = (0, openapi_1.parseOpenApiSpec)(api_1.metaculusApiSpec, this.baseUrl);
|
|
63
64
|
this.defineImplicitApi(descriptor);
|
|
64
65
|
}
|
|
@@ -43,7 +43,7 @@ export declare class MockExchange extends PredictionMarketExchange {
|
|
|
43
43
|
fillOrder(orderId: string, amount?: number): Promise<Order>;
|
|
44
44
|
cancelOrder(orderId: string): Promise<Order>;
|
|
45
45
|
fetchOrder(orderId: string): Promise<Order>;
|
|
46
|
-
fetchOpenOrders(
|
|
46
|
+
fetchOpenOrders(marketId?: string): Promise<Order[]>;
|
|
47
47
|
fetchMyTrades(_params?: {
|
|
48
48
|
outcomeId?: string;
|
|
49
49
|
marketId?: string;
|
|
@@ -277,12 +277,25 @@ class MockExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
277
277
|
const q = params.query.toLowerCase();
|
|
278
278
|
markets = markets.filter(m => m.title.toLowerCase().includes(q));
|
|
279
279
|
}
|
|
280
|
+
if (params?.slug) {
|
|
281
|
+
markets = markets.filter(m => m.slug === params.slug);
|
|
282
|
+
}
|
|
280
283
|
if (params?.eventId) {
|
|
281
284
|
markets = markets.filter(m => m.eventId === params.eventId);
|
|
282
285
|
}
|
|
283
286
|
if (params?.marketId) {
|
|
284
287
|
markets = markets.filter(m => m.marketId === params.marketId);
|
|
285
288
|
}
|
|
289
|
+
if (params?.outcomeId) {
|
|
290
|
+
markets = markets.filter(m => m.outcomes.some(o => o.outcomeId === params.outcomeId));
|
|
291
|
+
}
|
|
292
|
+
if (params?.status && params.status !== 'all') {
|
|
293
|
+
markets = markets.filter(m => (m.status ?? 'active') === params.status);
|
|
294
|
+
}
|
|
295
|
+
const sourceExchange = params?.sourceExchange ?? params?.exchange;
|
|
296
|
+
if (sourceExchange) {
|
|
297
|
+
markets = markets.filter(m => m.sourceExchange === sourceExchange);
|
|
298
|
+
}
|
|
286
299
|
const offset = params?.offset ?? 0;
|
|
287
300
|
const limit = params?.limit;
|
|
288
301
|
return limit !== undefined ? markets.slice(offset, offset + limit) : markets.slice(offset);
|
|
@@ -296,6 +309,19 @@ class MockExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
296
309
|
if (params?.eventId) {
|
|
297
310
|
events = events.filter(e => e.id === params.eventId);
|
|
298
311
|
}
|
|
312
|
+
if (params?.slug) {
|
|
313
|
+
events = events.filter(e => e.slug === params.slug);
|
|
314
|
+
}
|
|
315
|
+
if (params?.series) {
|
|
316
|
+
events = events.filter(e => e.sourceMetadata?.series === params.series);
|
|
317
|
+
}
|
|
318
|
+
if (params?.status && params.status !== 'all') {
|
|
319
|
+
events = events.filter(e => (e.status ?? 'active') === params.status);
|
|
320
|
+
}
|
|
321
|
+
const sourceExchange = params?.sourceExchange ?? params?.exchange;
|
|
322
|
+
if (sourceExchange) {
|
|
323
|
+
events = events.filter(e => e.sourceExchange === sourceExchange);
|
|
324
|
+
}
|
|
299
325
|
const offset = params?.offset ?? 0;
|
|
300
326
|
const limit = params?.limit;
|
|
301
327
|
return limit !== undefined ? events.slice(offset, offset + limit) : events.slice(offset);
|
|
@@ -378,8 +404,15 @@ class MockExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
378
404
|
outcomeId: id,
|
|
379
405
|
});
|
|
380
406
|
}
|
|
381
|
-
const
|
|
382
|
-
|
|
407
|
+
const start = toTimestamp(params.start);
|
|
408
|
+
const end = toTimestamp(params.end);
|
|
409
|
+
const filtered = [...trades]
|
|
410
|
+
.sort((a, b) => b.timestamp - a.timestamp)
|
|
411
|
+
.filter((trade) => start === undefined || trade.timestamp >= start)
|
|
412
|
+
.filter((trade) => end === undefined || trade.timestamp <= end);
|
|
413
|
+
return params.limit === undefined
|
|
414
|
+
? filtered
|
|
415
|
+
: filtered.slice(0, Math.max(0, Math.floor(params.limit)));
|
|
383
416
|
}
|
|
384
417
|
async fetchBalance(_address) {
|
|
385
418
|
const locked = this._locked();
|
|
@@ -609,9 +642,10 @@ class MockExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
609
642
|
throw new Error(`Order not found: ${orderId}`);
|
|
610
643
|
return { ...o };
|
|
611
644
|
}
|
|
612
|
-
async fetchOpenOrders(
|
|
645
|
+
async fetchOpenOrders(marketId) {
|
|
613
646
|
return Array.from(this._orders.values())
|
|
614
647
|
.filter(o => o.status === 'open' || o.status === 'pending')
|
|
648
|
+
.filter(o => marketId === undefined || o.marketId === marketId)
|
|
615
649
|
.map(o => ({ ...o }));
|
|
616
650
|
}
|
|
617
651
|
async fetchMyTrades(_params) {
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-23T09:51:53.491Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-23T09:51:53.491Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.myriadApiSpec = {
|
|
@@ -35,7 +35,7 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
35
35
|
if (credentials?.apiKey || credentials?.privateKey) {
|
|
36
36
|
this.auth = new auth_1.MyriadAuth(credentials);
|
|
37
37
|
}
|
|
38
|
-
const myriadBaseUrl = credentials?.baseUrl || utils_1.DEFAULT_BASE_URL;
|
|
38
|
+
const myriadBaseUrl = credentials?.baseUrl || process.env.MYRIAD_BASE_URL || utils_1.DEFAULT_BASE_URL;
|
|
39
39
|
const descriptor = (0, openapi_1.parseOpenApiSpec)(api_1.myriadApiSpec, myriadBaseUrl);
|
|
40
40
|
this.defineImplicitApi(descriptor);
|
|
41
41
|
const ctx = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/opinion/opinion-openapi.yaml
|
|
3
|
-
* Generated at: 2026-06-
|
|
3
|
+
* Generated at: 2026-06-23T09:51:53.496Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const opinionApiSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.opinionApiSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/opinion/opinion-openapi.yaml
|
|
6
|
-
* Generated at: 2026-06-
|
|
6
|
+
* Generated at: 2026-06-23T09:51:53.496Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.opinionApiSpec = {
|
|
@@ -82,7 +82,7 @@ class OpinionExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
82
82
|
if (credentials?.apiKey) {
|
|
83
83
|
this.auth = new auth_1.OpinionAuth(credentials);
|
|
84
84
|
}
|
|
85
|
-
const opinionBaseUrl = credentials?.baseUrl || config_1.DEFAULT_OPINION_API_URL;
|
|
85
|
+
const opinionBaseUrl = credentials?.baseUrl || process.env.OPINION_BASE_URL || config_1.DEFAULT_OPINION_API_URL;
|
|
86
86
|
const descriptor = (0, openapi_1.parseOpenApiSpec)(api_1.opinionApiSpec, opinionBaseUrl);
|
|
87
87
|
this.defineImplicitApi(descriptor);
|
|
88
88
|
const ctx = {
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-23T09:51:53.448Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-23T09:51:53.448Z
|
|
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-06-
|
|
3
|
+
* Generated at: 2026-06-23T09:51:53.462Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-23T09:51:53.462Z
|
|
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-06-
|
|
3
|
+
* Generated at: 2026-06-23T09:51:53.459Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-23T09:51:53.459Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.polymarketGammaSpec = {
|
|
@@ -15,8 +15,10 @@ exports.POLYMARKET_US_GATEWAY_BASE_URL = process.env.POLYMARKET_US_GATEWAY_URL |
|
|
|
15
15
|
* Return a typed config object for the Polymarket US API.
|
|
16
16
|
*/
|
|
17
17
|
function getPolymarketUSConfig(baseUrlOverride) {
|
|
18
|
+
const apiUrl = baseUrlOverride || process.env.POLYMARKET_US_BASE_URL || exports.POLYMARKET_US_API_BASE_URL;
|
|
19
|
+
const gatewayUrl = process.env.POLYMARKET_US_GATEWAY_URL || exports.POLYMARKET_US_GATEWAY_BASE_URL;
|
|
18
20
|
return {
|
|
19
|
-
apiUrl
|
|
20
|
-
gatewayUrl
|
|
21
|
+
apiUrl,
|
|
22
|
+
gatewayUrl,
|
|
21
23
|
};
|
|
22
24
|
}
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-23T09:51:53.484Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-23T09:51:53.484Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.probableApiSpec = {
|
|
@@ -31,7 +31,7 @@ class ProbableExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
31
31
|
if (credentials?.privateKey && credentials?.apiKey && credentials?.apiSecret && credentials?.passphrase) {
|
|
32
32
|
this.auth = new auth_1.ProbableAuth(credentials);
|
|
33
33
|
}
|
|
34
|
-
const probableBaseUrl = credentials?.baseUrl || utils_1.DEFAULT_BASE_URL;
|
|
34
|
+
const probableBaseUrl = credentials?.baseUrl || process.env.PROBABLE_BASE_URL || utils_1.DEFAULT_BASE_URL;
|
|
35
35
|
const descriptor = (0, openapi_1.parseOpenApiSpec)(api_1.probableApiSpec, probableBaseUrl);
|
|
36
36
|
this.defineImplicitApi(descriptor);
|
|
37
37
|
const ctx = {
|
|
@@ -42,7 +42,8 @@ exports.SMARKETS_PATHS = {
|
|
|
42
42
|
* Return a typed config object for the Smarkets API.
|
|
43
43
|
*/
|
|
44
44
|
function getSmarketsConfig(baseUrlOverride) {
|
|
45
|
+
const apiUrl = baseUrlOverride || process.env.SMARKETS_BASE_URL || exports.DEFAULT_SMARKETS_BASE_URL;
|
|
45
46
|
return {
|
|
46
|
-
apiUrl
|
|
47
|
+
apiUrl,
|
|
47
48
|
};
|
|
48
49
|
}
|
package/dist/server/app.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Express } from "express";
|
|
2
2
|
import { Server as HttpServer } from "http";
|
|
3
3
|
import { createWebSocketHandler, CreateWebSocketHandlerOptions } from "./ws-handler";
|
|
4
|
+
import { PredictionMarketExchange } from "../BaseExchange";
|
|
4
5
|
/**
|
|
5
6
|
* Options accepted by {@link createApp}.
|
|
6
7
|
*/
|
|
@@ -25,6 +26,14 @@ export interface CreateAppOptions {
|
|
|
25
26
|
* Defaults to false.
|
|
26
27
|
*/
|
|
27
28
|
skipBaseMiddleware?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Exchange instances scoped to this app.
|
|
31
|
+
*
|
|
32
|
+
* By default, unauthenticated local usage reuses process-wide singleton
|
|
33
|
+
* exchanges. Embedders and tests can provide explicit instances here when
|
|
34
|
+
* they need isolated state or non-default mock exchange options.
|
|
35
|
+
*/
|
|
36
|
+
localExchanges?: Partial<Record<string, PredictionMarketExchange>>;
|
|
28
37
|
}
|
|
29
38
|
/**
|
|
30
39
|
* Build an Express app that serves the PMXT sidecar API surface without
|
package/dist/server/app.js
CHANGED
|
@@ -162,6 +162,15 @@ function normalizeDateFields(params, fields, exchange) {
|
|
|
162
162
|
}
|
|
163
163
|
return normalized;
|
|
164
164
|
}
|
|
165
|
+
function normalizeArrayFields(params, fields) {
|
|
166
|
+
return fields.reduce((normalized, field) => {
|
|
167
|
+
const value = normalized[field];
|
|
168
|
+
if (typeof value === "string") {
|
|
169
|
+
return { ...normalized, [field]: [value] };
|
|
170
|
+
}
|
|
171
|
+
return normalized;
|
|
172
|
+
}, { ...params });
|
|
173
|
+
}
|
|
165
174
|
function isMissing(value) {
|
|
166
175
|
return value === undefined || value === null || value === "";
|
|
167
176
|
}
|
|
@@ -200,9 +209,12 @@ function validateCreateOrderParams(params, exchange) {
|
|
|
200
209
|
}
|
|
201
210
|
function normalizeDispatchArgs(methodName, args, exchange) {
|
|
202
211
|
const normalized = [...args];
|
|
203
|
-
if (methodName === "fetchOHLCV" && isRecord(normalized[1])) {
|
|
212
|
+
if ((methodName === "fetchOHLCV" || methodName === "fetchTrades") && isRecord(normalized[1])) {
|
|
204
213
|
normalized[1] = normalizeDateFields(normalized[1], ["start", "end"], exchange);
|
|
205
214
|
}
|
|
215
|
+
if ((methodName === "fetchMarkets" || methodName === "fetchEvents") && isRecord(normalized[0])) {
|
|
216
|
+
normalized[0] = normalizeArrayFields(normalized[0], ["tags"]);
|
|
217
|
+
}
|
|
206
218
|
if (methodName === "createOrder") {
|
|
207
219
|
normalized[0] = validateCreateOrderParams(normalized[0], exchange);
|
|
208
220
|
}
|
|
@@ -268,8 +280,9 @@ function getDefaultExchange(exchangeName) {
|
|
|
268
280
|
* ```
|
|
269
281
|
*/
|
|
270
282
|
function createApp(options = {}) {
|
|
271
|
-
const { accessToken, skipBaseMiddleware = false } = options;
|
|
283
|
+
const { accessToken, skipBaseMiddleware = false, localExchanges = {}, } = options;
|
|
272
284
|
const app = (0, express_1.default)();
|
|
285
|
+
const getAppExchange = (exchangeName) => (localExchanges[exchangeName] ?? getDefaultExchange(exchangeName));
|
|
273
286
|
if (!skipBaseMiddleware) {
|
|
274
287
|
app.use((0, cors_1.default)());
|
|
275
288
|
app.use(express_1.default.json({ limit: "2mb" }));
|
|
@@ -307,16 +320,22 @@ function createApp(options = {}) {
|
|
|
307
320
|
const exchangeName = req.params.exchange.toLowerCase();
|
|
308
321
|
let exchange;
|
|
309
322
|
if (exchangeName === "router") {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
323
|
+
const localRouter = localExchanges[exchangeName];
|
|
324
|
+
if (localRouter) {
|
|
325
|
+
exchange = localRouter;
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
// Router uses the caller's Bearer token for its internal /v0/
|
|
329
|
+
// calls — not a server-side env var. Each request may carry a
|
|
330
|
+
// different key, so Router is never cached as a singleton.
|
|
331
|
+
const bearer = req.headers.authorization?.replace(/^Bearer\s+/i, "") || "";
|
|
332
|
+
exchange = new router_1.Router({
|
|
333
|
+
apiKey: bearer,
|
|
334
|
+
localExchanges: {
|
|
335
|
+
mock: getAppExchange("mock"),
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
}
|
|
320
339
|
}
|
|
321
340
|
else if (credentials &&
|
|
322
341
|
(credentials.privateKey ||
|
|
@@ -325,7 +344,7 @@ function createApp(options = {}) {
|
|
|
325
344
|
exchange = (0, exchange_factory_1.createExchange)(exchangeName, credentials);
|
|
326
345
|
}
|
|
327
346
|
else {
|
|
328
|
-
exchange =
|
|
347
|
+
exchange = getAppExchange(exchangeName);
|
|
329
348
|
}
|
|
330
349
|
if (req.headers["x-pmxt-verbose"] === "true") {
|
|
331
350
|
exchange.verbose = true;
|
|
@@ -340,9 +359,8 @@ function createApp(options = {}) {
|
|
|
340
359
|
});
|
|
341
360
|
return;
|
|
342
361
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
exchange.has[methodName] === false) {
|
|
362
|
+
const capability = exchange.has?.[methodName];
|
|
363
|
+
if (capability === false && methodName !== "fetchSeries") {
|
|
346
364
|
res.status(501).json({
|
|
347
365
|
success: false,
|
|
348
366
|
error: `Method '${methodName}' is not supported by '${exchangeName}'. ` +
|
|
@@ -54,8 +54,12 @@ function createExchange(name, credentials, bearerToken) {
|
|
|
54
54
|
case "kalshi-demo":
|
|
55
55
|
return new kalshi_demo_1.KalshiDemoExchange({
|
|
56
56
|
credentials: {
|
|
57
|
-
apiKey: credentials?.apiKey ||
|
|
58
|
-
|
|
57
|
+
apiKey: credentials?.apiKey ||
|
|
58
|
+
process.env.KALSHI_DEMO_API_KEY ||
|
|
59
|
+
process.env.KALSHI_API_KEY,
|
|
60
|
+
privateKey: credentials?.privateKey ||
|
|
61
|
+
process.env.KALSHI_DEMO_PRIVATE_KEY ||
|
|
62
|
+
process.env.KALSHI_PRIVATE_KEY,
|
|
59
63
|
},
|
|
60
64
|
});
|
|
61
65
|
case "probable":
|
|
@@ -80,7 +84,9 @@ function createExchange(name, credentials, bearerToken) {
|
|
|
80
84
|
return new opinion_1.OpinionExchange({
|
|
81
85
|
apiKey: credentials?.apiKey || process.env.OPINION_API_KEY,
|
|
82
86
|
privateKey: credentials?.privateKey || process.env.OPINION_PRIVATE_KEY,
|
|
83
|
-
funderAddress: credentials?.funderAddress
|
|
87
|
+
funderAddress: credentials?.funderAddress ||
|
|
88
|
+
process.env.OPINION_FUNDER_ADDRESS ||
|
|
89
|
+
process.env.OPINION_PROXY_ADDRESS,
|
|
84
90
|
});
|
|
85
91
|
case "metaculus":
|
|
86
92
|
return new metaculus_1.MetaculusExchange({
|
package/dist/server/openapi.yaml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmxt-core",
|
|
3
|
-
"version": "2.51.
|
|
3
|
+
"version": "2.51.2",
|
|
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.51.
|
|
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.51.
|
|
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.51.2,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.51.2,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",
|