pmxtjs 2.49.1 → 2.49.4
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/README.md +3 -3
- package/dist/esm/pmxt/client.d.ts +3 -0
- package/dist/esm/pmxt/client.js +40 -5
- package/dist/pmxt/client.d.ts +3 -0
- package/dist/pmxt/client.js +40 -5
- package/generated/package.json +1 -1
- package/package.json +2 -2
- package/pmxt/client.ts +47 -7
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A unified TypeScript/Node.js SDK for prediction markets — The ccxt for prediction markets.
|
|
4
4
|
|
|
5
|
-
> **Note**: Use with a PMXT API key (hosted, recommended) or
|
|
5
|
+
> **Note**: Use with a PMXT API key (hosted, recommended) or run a local PMXT service. Get a key at [pmxt.dev/dashboard](https://pmxt.dev/dashboard).
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -53,7 +53,7 @@ When you pass `pmxtApiKey`, the SDK talks to PMXT's hosted services: catalog req
|
|
|
53
53
|
|
|
54
54
|
### How it works (self-hosted)
|
|
55
55
|
|
|
56
|
-
Omit `pmxtApiKey` to use the local
|
|
56
|
+
Omit `pmxtApiKey` to use the local PMXT service. Install `pmxt-core` from npm and supply venue credentials directly. See [Self-hosted trading (advanced)](#self-hosted-trading-advanced) below.
|
|
57
57
|
|
|
58
58
|
## Core Methods
|
|
59
59
|
|
|
@@ -139,7 +139,7 @@ See the full [hosted trading guide](https://pmxt.dev/docs/concepts/hosted-tradin
|
|
|
139
139
|
|
|
140
140
|
### Self-hosted trading (advanced)
|
|
141
141
|
|
|
142
|
-
When self-hosting, supply venue credentials directly — no `pmxtApiKey`. The SDK spawns a local
|
|
142
|
+
When self-hosting, supply venue credentials directly — no `pmxtApiKey`. The SDK spawns a local PMXT service.
|
|
143
143
|
|
|
144
144
|
**Polymarket:**
|
|
145
145
|
```typescript
|
|
@@ -72,6 +72,9 @@ export interface ExchangeOptions {
|
|
|
72
72
|
*/
|
|
73
73
|
export declare abstract class Exchange {
|
|
74
74
|
private static readonly OBDATA_WATCH_ALL_SOURCES;
|
|
75
|
+
private static readonly _UUID_RE;
|
|
76
|
+
/** True iff `value` parses as a canonical catalog UUID string. */
|
|
77
|
+
protected static _isCatalogUuid(value: string): boolean;
|
|
75
78
|
exchangeName: string;
|
|
76
79
|
pmxtApiKey?: string;
|
|
77
80
|
protected apiKey?: string;
|
package/dist/esm/pmxt/client.js
CHANGED
|
@@ -148,6 +148,14 @@ export class Exchange {
|
|
|
148
148
|
"kalshi",
|
|
149
149
|
"opinion",
|
|
150
150
|
]);
|
|
151
|
+
// Match a canonical 8-4-4-4-12 UUID string. The hosted catalog emits
|
|
152
|
+
// UUIDs in this exact shape, so a regex is both faster and stricter
|
|
153
|
+
// than `crypto.randomUUID()`-style parsing.
|
|
154
|
+
static _UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
155
|
+
/** True iff `value` parses as a canonical catalog UUID string. */
|
|
156
|
+
static _isCatalogUuid(value) {
|
|
157
|
+
return Exchange._UUID_RE.test(value);
|
|
158
|
+
}
|
|
151
159
|
// Public so structural interfaces like `HostedClientLike`
|
|
152
160
|
// (./hosted-routing) can read the venue name and hosted credentials
|
|
153
161
|
// without violating protected-access on this base class.
|
|
@@ -2202,12 +2210,17 @@ export class Exchange {
|
|
|
2202
2210
|
throw new InvalidOrder("cannot specify both 'outcome' and 'marketId'/'outcomeId'");
|
|
2203
2211
|
}
|
|
2204
2212
|
const outcome = params.outcome;
|
|
2205
|
-
if (!outcome.
|
|
2206
|
-
throw new InvalidOrder("outcome.
|
|
2213
|
+
if (!outcome.outcomeId) {
|
|
2214
|
+
throw new InvalidOrder("outcome.outcomeId is not set; ensure the outcome comes from a fetched market");
|
|
2207
2215
|
}
|
|
2208
|
-
marketId
|
|
2216
|
+
// marketId is optional in hosted mode -- backend derives it from
|
|
2217
|
+
// outcomeId (catalog UUID). Forward it when present for backcompat.
|
|
2218
|
+
marketId = outcome.marketId || undefined;
|
|
2209
2219
|
outcomeId = outcome.outcomeId;
|
|
2210
2220
|
}
|
|
2221
|
+
if (!outcomeId) {
|
|
2222
|
+
throw new InvalidOrder("outcomeId is required (or pass an 'outcome' from a fetched market)");
|
|
2223
|
+
}
|
|
2211
2224
|
const side = String(params.side);
|
|
2212
2225
|
const orderType = String(params.type ?? "market");
|
|
2213
2226
|
const denom = params["denom"];
|
|
@@ -2244,15 +2257,37 @@ export class Exchange {
|
|
|
2244
2257
|
}
|
|
2245
2258
|
// to6dec throws InvalidOrder for sub-micro precision.
|
|
2246
2259
|
const amount6dec = to6dec(params.amount).toString();
|
|
2260
|
+
// The supplied outcomeId may be a catalog UUID OR a venue-native id
|
|
2261
|
+
// (e.g. a Polymarket tokenId or an Opinion market hash). Catalog
|
|
2262
|
+
// UUIDs are forwarded as `outcome_id`; venue-native ids are
|
|
2263
|
+
// forwarded as `(venue, venue_outcome_id)` so the backend resolver
|
|
2264
|
+
// picks the right path. Either shape is accepted by the v0 trading
|
|
2265
|
+
// API.
|
|
2247
2266
|
const body = {
|
|
2248
|
-
market_id: marketId,
|
|
2249
|
-
outcome_id: outcomeId,
|
|
2250
2267
|
side,
|
|
2251
2268
|
order_type: orderType,
|
|
2252
2269
|
denom: resolvedDenom,
|
|
2253
2270
|
amount: params.amount,
|
|
2254
2271
|
amount_6dec: amount6dec,
|
|
2255
2272
|
};
|
|
2273
|
+
if (Exchange._isCatalogUuid(outcomeId)) {
|
|
2274
|
+
body["outcome_id"] = outcomeId;
|
|
2275
|
+
// market_id is optional in hosted mode: backend derives it
|
|
2276
|
+
// from outcome_id (UUID) when omitted. Forward only when the
|
|
2277
|
+
// caller supplied a non-empty UUID -- "absent" and "null" are
|
|
2278
|
+
// not equivalent under some Pydantic configs on the backend.
|
|
2279
|
+
if (marketId && Exchange._isCatalogUuid(marketId)) {
|
|
2280
|
+
body["market_id"] = marketId;
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
else {
|
|
2284
|
+
// Venue-native form: backend resolves the row from
|
|
2285
|
+
// (source_exchange, pmxt_id). marketId from a venue client is
|
|
2286
|
+
// itself venue-native and would fail backend UUID validation
|
|
2287
|
+
// if forwarded -- suppress it.
|
|
2288
|
+
body["venue"] = this.exchangeName;
|
|
2289
|
+
body["venue_outcome_id"] = outcomeId;
|
|
2290
|
+
}
|
|
2256
2291
|
if (params.price !== undefined)
|
|
2257
2292
|
body["price"] = params.price;
|
|
2258
2293
|
const extra = params;
|
package/dist/pmxt/client.d.ts
CHANGED
|
@@ -72,6 +72,9 @@ export interface ExchangeOptions {
|
|
|
72
72
|
*/
|
|
73
73
|
export declare abstract class Exchange {
|
|
74
74
|
private static readonly OBDATA_WATCH_ALL_SOURCES;
|
|
75
|
+
private static readonly _UUID_RE;
|
|
76
|
+
/** True iff `value` parses as a canonical catalog UUID string. */
|
|
77
|
+
protected static _isCatalogUuid(value: string): boolean;
|
|
75
78
|
exchangeName: string;
|
|
76
79
|
pmxtApiKey?: string;
|
|
77
80
|
protected apiKey?: string;
|
package/dist/pmxt/client.js
CHANGED
|
@@ -151,6 +151,14 @@ class Exchange {
|
|
|
151
151
|
"kalshi",
|
|
152
152
|
"opinion",
|
|
153
153
|
]);
|
|
154
|
+
// Match a canonical 8-4-4-4-12 UUID string. The hosted catalog emits
|
|
155
|
+
// UUIDs in this exact shape, so a regex is both faster and stricter
|
|
156
|
+
// than `crypto.randomUUID()`-style parsing.
|
|
157
|
+
static _UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
158
|
+
/** True iff `value` parses as a canonical catalog UUID string. */
|
|
159
|
+
static _isCatalogUuid(value) {
|
|
160
|
+
return Exchange._UUID_RE.test(value);
|
|
161
|
+
}
|
|
154
162
|
// Public so structural interfaces like `HostedClientLike`
|
|
155
163
|
// (./hosted-routing) can read the venue name and hosted credentials
|
|
156
164
|
// without violating protected-access on this base class.
|
|
@@ -2205,12 +2213,17 @@ class Exchange {
|
|
|
2205
2213
|
throw new errors_js_1.InvalidOrder("cannot specify both 'outcome' and 'marketId'/'outcomeId'");
|
|
2206
2214
|
}
|
|
2207
2215
|
const outcome = params.outcome;
|
|
2208
|
-
if (!outcome.
|
|
2209
|
-
throw new errors_js_1.InvalidOrder("outcome.
|
|
2216
|
+
if (!outcome.outcomeId) {
|
|
2217
|
+
throw new errors_js_1.InvalidOrder("outcome.outcomeId is not set; ensure the outcome comes from a fetched market");
|
|
2210
2218
|
}
|
|
2211
|
-
marketId
|
|
2219
|
+
// marketId is optional in hosted mode -- backend derives it from
|
|
2220
|
+
// outcomeId (catalog UUID). Forward it when present for backcompat.
|
|
2221
|
+
marketId = outcome.marketId || undefined;
|
|
2212
2222
|
outcomeId = outcome.outcomeId;
|
|
2213
2223
|
}
|
|
2224
|
+
if (!outcomeId) {
|
|
2225
|
+
throw new errors_js_1.InvalidOrder("outcomeId is required (or pass an 'outcome' from a fetched market)");
|
|
2226
|
+
}
|
|
2214
2227
|
const side = String(params.side);
|
|
2215
2228
|
const orderType = String(params.type ?? "market");
|
|
2216
2229
|
const denom = params["denom"];
|
|
@@ -2247,15 +2260,37 @@ class Exchange {
|
|
|
2247
2260
|
}
|
|
2248
2261
|
// to6dec throws InvalidOrder for sub-micro precision.
|
|
2249
2262
|
const amount6dec = (0, hosted_mappers_js_1.to6dec)(params.amount).toString();
|
|
2263
|
+
// The supplied outcomeId may be a catalog UUID OR a venue-native id
|
|
2264
|
+
// (e.g. a Polymarket tokenId or an Opinion market hash). Catalog
|
|
2265
|
+
// UUIDs are forwarded as `outcome_id`; venue-native ids are
|
|
2266
|
+
// forwarded as `(venue, venue_outcome_id)` so the backend resolver
|
|
2267
|
+
// picks the right path. Either shape is accepted by the v0 trading
|
|
2268
|
+
// API.
|
|
2250
2269
|
const body = {
|
|
2251
|
-
market_id: marketId,
|
|
2252
|
-
outcome_id: outcomeId,
|
|
2253
2270
|
side,
|
|
2254
2271
|
order_type: orderType,
|
|
2255
2272
|
denom: resolvedDenom,
|
|
2256
2273
|
amount: params.amount,
|
|
2257
2274
|
amount_6dec: amount6dec,
|
|
2258
2275
|
};
|
|
2276
|
+
if (Exchange._isCatalogUuid(outcomeId)) {
|
|
2277
|
+
body["outcome_id"] = outcomeId;
|
|
2278
|
+
// market_id is optional in hosted mode: backend derives it
|
|
2279
|
+
// from outcome_id (UUID) when omitted. Forward only when the
|
|
2280
|
+
// caller supplied a non-empty UUID -- "absent" and "null" are
|
|
2281
|
+
// not equivalent under some Pydantic configs on the backend.
|
|
2282
|
+
if (marketId && Exchange._isCatalogUuid(marketId)) {
|
|
2283
|
+
body["market_id"] = marketId;
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
else {
|
|
2287
|
+
// Venue-native form: backend resolves the row from
|
|
2288
|
+
// (source_exchange, pmxt_id). marketId from a venue client is
|
|
2289
|
+
// itself venue-native and would fail backend UUID validation
|
|
2290
|
+
// if forwarded -- suppress it.
|
|
2291
|
+
body["venue"] = this.exchangeName;
|
|
2292
|
+
body["venue_outcome_id"] = outcomeId;
|
|
2293
|
+
}
|
|
2259
2294
|
if (params.price !== undefined)
|
|
2260
2295
|
body["price"] = params.price;
|
|
2261
2296
|
const extra = params;
|
package/generated/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmxtjs",
|
|
3
|
-
"version": "2.49.
|
|
3
|
+
"version": "2.49.4",
|
|
4
4
|
"description": "Unified prediction market data API - The ccxt for prediction markets",
|
|
5
5
|
"author": "PMXT Contributors",
|
|
6
6
|
"repository": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"unified"
|
|
44
44
|
],
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"pmxt-core": "2.49.
|
|
46
|
+
"pmxt-core": "2.49.4",
|
|
47
47
|
"ws": "^8.18.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
package/pmxt/client.ts
CHANGED
|
@@ -300,6 +300,17 @@ export abstract class Exchange {
|
|
|
300
300
|
"opinion",
|
|
301
301
|
]);
|
|
302
302
|
|
|
303
|
+
// Match a canonical 8-4-4-4-12 UUID string. The hosted catalog emits
|
|
304
|
+
// UUIDs in this exact shape, so a regex is both faster and stricter
|
|
305
|
+
// than `crypto.randomUUID()`-style parsing.
|
|
306
|
+
private static readonly _UUID_RE =
|
|
307
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
308
|
+
|
|
309
|
+
/** True iff `value` parses as a canonical catalog UUID string. */
|
|
310
|
+
protected static _isCatalogUuid(value: string): boolean {
|
|
311
|
+
return Exchange._UUID_RE.test(value);
|
|
312
|
+
}
|
|
313
|
+
|
|
303
314
|
// Public so structural interfaces like `HostedClientLike`
|
|
304
315
|
// (./hosted-routing) can read the venue name and hosted credentials
|
|
305
316
|
// without violating protected-access on this base class.
|
|
@@ -2434,8 +2445,8 @@ export abstract class Exchange {
|
|
|
2434
2445
|
private _hostedBuildOrderBody(
|
|
2435
2446
|
params: CreateOrderParams & { outcome?: MarketOutcome },
|
|
2436
2447
|
): Record<string, unknown> {
|
|
2437
|
-
let marketId = params.marketId;
|
|
2438
|
-
let outcomeId = params.outcomeId;
|
|
2448
|
+
let marketId: string | undefined = params.marketId;
|
|
2449
|
+
let outcomeId: string | undefined = params.outcomeId;
|
|
2439
2450
|
|
|
2440
2451
|
if (params.outcome) {
|
|
2441
2452
|
if (marketId !== undefined || outcomeId !== undefined) {
|
|
@@ -2444,15 +2455,23 @@ export abstract class Exchange {
|
|
|
2444
2455
|
);
|
|
2445
2456
|
}
|
|
2446
2457
|
const outcome: MarketOutcome = params.outcome;
|
|
2447
|
-
if (!outcome.
|
|
2458
|
+
if (!outcome.outcomeId) {
|
|
2448
2459
|
throw new InvalidOrder(
|
|
2449
|
-
"outcome.
|
|
2460
|
+
"outcome.outcomeId is not set; ensure the outcome comes from a fetched market",
|
|
2450
2461
|
);
|
|
2451
2462
|
}
|
|
2452
|
-
marketId
|
|
2463
|
+
// marketId is optional in hosted mode -- backend derives it from
|
|
2464
|
+
// outcomeId (catalog UUID). Forward it when present for backcompat.
|
|
2465
|
+
marketId = outcome.marketId || undefined;
|
|
2453
2466
|
outcomeId = outcome.outcomeId;
|
|
2454
2467
|
}
|
|
2455
2468
|
|
|
2469
|
+
if (!outcomeId) {
|
|
2470
|
+
throw new InvalidOrder(
|
|
2471
|
+
"outcomeId is required (or pass an 'outcome' from a fetched market)",
|
|
2472
|
+
);
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2456
2475
|
const side = String(params.side);
|
|
2457
2476
|
const orderType = String(params.type ?? "market");
|
|
2458
2477
|
const denom = (params as unknown as Record<string, unknown>)["denom"] as
|
|
@@ -2493,15 +2512,36 @@ export abstract class Exchange {
|
|
|
2493
2512
|
// to6dec throws InvalidOrder for sub-micro precision.
|
|
2494
2513
|
const amount6dec = to6dec(params.amount as number).toString();
|
|
2495
2514
|
|
|
2515
|
+
// The supplied outcomeId may be a catalog UUID OR a venue-native id
|
|
2516
|
+
// (e.g. a Polymarket tokenId or an Opinion market hash). Catalog
|
|
2517
|
+
// UUIDs are forwarded as `outcome_id`; venue-native ids are
|
|
2518
|
+
// forwarded as `(venue, venue_outcome_id)` so the backend resolver
|
|
2519
|
+
// picks the right path. Either shape is accepted by the v0 trading
|
|
2520
|
+
// API.
|
|
2496
2521
|
const body: Record<string, unknown> = {
|
|
2497
|
-
market_id: marketId,
|
|
2498
|
-
outcome_id: outcomeId,
|
|
2499
2522
|
side,
|
|
2500
2523
|
order_type: orderType,
|
|
2501
2524
|
denom: resolvedDenom,
|
|
2502
2525
|
amount: params.amount,
|
|
2503
2526
|
amount_6dec: amount6dec,
|
|
2504
2527
|
};
|
|
2528
|
+
if (Exchange._isCatalogUuid(outcomeId)) {
|
|
2529
|
+
body["outcome_id"] = outcomeId;
|
|
2530
|
+
// market_id is optional in hosted mode: backend derives it
|
|
2531
|
+
// from outcome_id (UUID) when omitted. Forward only when the
|
|
2532
|
+
// caller supplied a non-empty UUID -- "absent" and "null" are
|
|
2533
|
+
// not equivalent under some Pydantic configs on the backend.
|
|
2534
|
+
if (marketId && Exchange._isCatalogUuid(marketId)) {
|
|
2535
|
+
body["market_id"] = marketId;
|
|
2536
|
+
}
|
|
2537
|
+
} else {
|
|
2538
|
+
// Venue-native form: backend resolves the row from
|
|
2539
|
+
// (source_exchange, pmxt_id). marketId from a venue client is
|
|
2540
|
+
// itself venue-native and would fail backend UUID validation
|
|
2541
|
+
// if forwarded -- suppress it.
|
|
2542
|
+
body["venue"] = this.exchangeName;
|
|
2543
|
+
body["venue_outcome_id"] = outcomeId;
|
|
2544
|
+
}
|
|
2505
2545
|
|
|
2506
2546
|
if (params.price !== undefined) body["price"] = params.price;
|
|
2507
2547
|
const extra = params as unknown as Record<string, unknown>;
|