Skip to content

Releases: pmxt-dev/pmxt

v2.26.2

08 Apr 16:40

Choose a tag to compare

Added

  • openapi.yaml now ships in the published pmxt-core tarball at dist/server/openapi.yaml. Previously the spec was generated into core/src/server/openapi.yaml and consumed in-repo (by the SDK generators and the openapi drift check) but was excluded from the npm package because only dist/, bin/, and API_REFERENCE.md were in the files field. Downstream consumers of pmxt-core can now read the spec directly from node_modules/pmxt-core/dist/server/openapi.yaml — no git clone, no version-pinned GitHub raw fetch, no drift between the installed package and the spec. Enables documentation sites (Mintlify, Redocly, Stoplight) and type generators to sit on top of the installed package and stay automatically in lockstep with whichever pmxt-core version is pinned.

    Mechanically: build now does tsc && cp src/server/openapi.yaml dist/server/openapi.yaml. The existing dist entry in files means it's included in npm publish without touching the files array. Verified with npm pack --dry-rundist/server/openapi.yaml (52 kB) is in the tarball.


Installation

npm:

npm install pmxtjs@2.26.2

PyPI:

pip install pmxt==2.26.2

Links

Full Changelog: v2.26.1f...v2.26.2f

v2.26.1

08 Apr 07:36

Choose a tag to compare

Changed

  • pmxt.stop_server() / pmxt.restart_server() now emit DeprecationWarning (Python SDK): The flat aliases still work and still call the underlying ServerManager, but they now warn that pmxt.server.stop() / pmxt.server.restart() is the standard. This reverses the "no deprecation, no warnings" stance from 2.26.0 — the namespaced pmxt.server.* API is the single canonical surface for sidecar lifecycle management, and the flat helpers are kept only for backwards compatibility.

Installation

npm:

npm install pmxtjs@2.26.1

PyPI:

pip install pmxt==2.26.1

Links

Full Changelog: v2.26.0f...v2.26.1f

v2.26.0

08 Apr 07:25

Choose a tag to compare

Fixed

  • ServerManager.ensureServerRunning() race condition (TypeScript and Python SDKs): Creating multiple Exchange instances in parallel (e.g. const p = new Polymarket(); const k = new Kalshi(); const l = new Limitless();) caused every request to return 401 Unauthorized. Each Exchange constructed its own ServerManager and each one called ensureServerRunning() concurrently. Every call saw "no server running", every call spawned its own sidecar via pmxt-ensure-server, and the lock file ended up pointing at whichever spawn wrote last — but each Exchange had already captured its own basePath at construction time, so most requests hit a sidecar whose access token did NOT match the token later read from the lock file.

    Fix is process-wide coalescing inside ServerManager:

    • TypeScript: ensureServerRunning() now uses a static Promise | null cache. Concurrent callers await the same in-flight promise; the cache is cleared on settle so later calls can re-check the sidecar state.
    • Python: ensure_server_running() now holds a class-level threading.Lock for the entire check-and-spawn critical section. The "is the server already running?" check is re-evaluated inside the lock so threads that lose the race observe the sidecar that the winning thread just started.

Added

  • pmxt.server namespace for sidecar lifecycle management (TypeScript and Python SDKs): A single, discoverable namespace for managing the background sidecar. All six commands are available identically in both SDKs:

    • pmxt.server.status() — Structured snapshot: { running, pid, port, version, uptimeSeconds, lockFile }. Returns a fresh object on every call (no shared mutable state).
    • pmxt.server.health() — Returns true if the sidecar responds to /health, false otherwise. Fast, no side effects.
    • pmxt.server.start() — Idempotently starts the sidecar. No-op if one is already running.
    • pmxt.server.stop() — Stops the sidecar and removes the lock file.
    • pmxt.server.restart() — Stop + start.
    • pmxt.server.logs(n = 50) — Returns the last n lines from ~/.pmxt/server.log, or an empty list if the launcher never wrote a log file.

    Motivation: sidecar lifecycle is a real surface users hit regularly — stale lock files, zombie sidecars from crashed parents, version mismatches, and race conditions when multiple Exchange instances boot in parallel. Previously users had to reach into ServerManager directly or shell out to ps / lsof to diagnose. pmxt.server.* makes the lifecycle observable and controllable from a single entry point. Example:

    import pmxt from 'pmxtjs';
    const s = await pmxt.server.status();
    if (!s.running) await pmxt.server.start();
    console.log(await pmxt.server.logs(20));
  • Sidecar writes stdout/stderr to ~/.pmxt/server.log: pmxt-ensure-server now redirects the spawned sidecar's stdio to a log file in the ~/.pmxt/ directory so pmxt.server.logs() has something to read. Previously stdio was dropped (stdio: 'ignore') and any crash during boot left no trace.

Fully backwards compatible: the existing flat helpers pmxt.stopServer() / pmxt.restartServer() (TypeScript) and pmxt.stop_server() / pmxt.restart_server() (Python) remain first-class, fully-supported aliases for pmxt.server.stop() / pmxt.server.restart(). No deprecation, no warnings — both spellings work and will keep working.


Installation

npm:

npm install pmxtjs@2.26.0

PyPI:

pip install pmxt==2.26.0

Links

Full Changelog: v2.25.3f...v2.26.0f

v2.25.3

08 Apr 06:33

Choose a tag to compare

Added

  • TypeScript SDK: Opinion, Metaculus, Smarkets, PolymarketUS exchange classes: These adapters already existed in core/src/exchanges/ and were reachable via the sidecar HTTP API, but the hand-maintained TypeScript SDK client at sdks/typescript/pmxt/client.ts (and the package entry point at sdks/typescript/index.ts) never exposed them. Anyone using pmxtjs would see pmxt.Opinion === undefined even though the core adapter had been merged. All four are now exported and work via the standard new pmxt.Opinion({}).fetchEvents() consumer path.
  • Python SDK: Smarkets, PolymarketUS exchange classes: Same drift in sdks/python/pmxt/_exchanges.py and sdks/python/pmxt/__init__.py. Both are now exported.
  • openapi.yaml source_exchange enum: Added kalshi-demo and polymarket_us, which were missing even though the sidecar routes accepted them. The generated openapi-fetch TypeScript SDK would have rejected requests targeting these exchanges at the type layer.

Fixed

  • Hand-maintained allowlists across five layers were silently drifting: Every layer that exchanges have to cross to reach a consumer had its own allowlist — generate-openapi.js, sdks/typescript/pmxt/client.ts, sdks/typescript/index.ts, sdks/python/pmxt/_exchanges.py, sdks/python/pmxt/__init__.py. Adding a new exchange to core/src/exchanges/ required manual edits at up to five places and nothing blocked a PR that forgot them. The immediate symptom was that four exchanges (opinion, metaculus, smarkets, polymarket_us) shipped into core but never reached pmxtjs.

CI

  • New core/scripts/check-exchange-drift.js and .github/workflows/exchange-drift-check.yml: Walks core/src/exchanges/*/index.ts to discover every concrete PredictionMarketExchange subclass, then asserts that each one is exposed by the openapi enum, both TypeScript SDK files, and both Python SDK files. Exits non-zero with a per-layer table of missing entries. Runs on every PR that touches any of the covered files. This makes it structurally impossible to merge a new exchange without wiring it through every layer.

Installation

npm:

npm install pmxtjs@2.25.3

PyPI:

pip install pmxt==2.25.3

Links

Full Changelog: v2.25.2f...v2.25.3f

v2.25.2

07 Apr 13:34

Choose a tag to compare

Fixed

  • TypeScript and Python SDKs: dropped fields in convertMarket / convertEvent: The hand-maintained converter shims at the top of sdks/typescript/pmxt/client.ts and sdks/python/pmxt/client.py had their own allowlists and were silently dropping slug, tickSize, status, contractAddress on UnifiedMarket and volume, volume24h on UnifiedEvent even though the sidecar populates them and the generated OpenAPI client maps them. Both shims now copy the full set, and the corresponding UnifiedMarket / UnifiedEvent interfaces in models.ts / models.py declare the new fields. The 2.25.1 release fixed the sidecar end of the pipe; this release fixes the SDK consumer end.

Installation

npm:

npm install pmxtjs@2.25.2

PyPI:

pip install pmxt==2.25.2

Links

Full Changelog: v2.25.1f...v2.25.2f

v2.25.1

07 Apr 13:08

Choose a tag to compare

Fixed

  • Polymarket: dropped market fields: mapMarketToUnified now populates slug (from Gamma slug), tickSize (from orderPriceMinTickSize), status (from archived > closed > active precedence), and contractAddress (from conditionId). These were silently dropped during normalization and surfaced as undefined to consumers.
  • OpenAPI spec drift: core/scripts/generate-openapi.js was missing several UnifiedEvent and UnifiedMarket fields that already existed in types.ts (UnifiedEvent.volume, UnifiedEvent.volume24h, UnifiedMarket.slug, UnifiedMarket.tickSize) plus CreateOrderParams.tickSize / CreateOrderParams.negRisk. The generated openapi.yaml and downstream typed SDKs (e.g. pmxtjs) stripped these fields at the client boundary, producing NULL columns in catalog ingest pipelines. Generator now declares the full set so they round-trip end-to-end.
  • UnifiedMarket type: Added status and contractAddress to the type declaration so the new Polymarket fields are visible to TypeScript consumers.

Installation

npm:

npm install pmxtjs@2.25.1

PyPI:

pip install pmxt==2.25.1

Links

Full Changelog: v2.25.0f...v2.25.1f

v2.25.0

06 Apr 20:00

Choose a tag to compare

Added

  • Polymarket US Exchange Integration 🇺🇸: New adapter wrapping the official polymarket-us SDK for the US-regulated Polymarket gateway. Supports fetchMarkets / fetchEvents (by slug, event, or outcomeId), fetchOrderBook, fetchBalance, fetchPositions, fetchMyTrades, fetchOpenOrders, fetchOrder, createOrder / buildOrder / submitOrder, cancelOrder, and WebSocket streaming via watchOrderBook / watchTrades (backed by the SDK's MarketsWebSocket; credentials are required because the SDK factory mandates keyId + secretKey even for the public market socket). Handles the long-side price convention (all API prices are YES-side; short-side inputs are auto-converted via 1 - price), normalizes outcomes to ${slug}:long / ${slug}:short, surfaces live prices from marketSides[].price (with outcomePrices[] fallback), lifts orderPriceMinTickSize onto UnifiedMarket.tickSize, and stashes human side labels (e.g. team names) in outcome metadata. Maintains an in-memory orderId -> marketSlug cache so cancelOrder(orderId) can supply the SDK-required body field. The normalizer reads the real gateway response shape (question, endDate, category, tags, marketSides) rather than the SDK's declared types. Prices serialize at 3-decimal precision ("0.864") and the default tick size is 0.001, matching observed live markets. Includes unit tests covering price conversion, normalizer, error mapping, the exchange wrapper, and the WebSocket layer, plus a live-gateway smoke script (core/scripts/smoke-polymarket-us.ts).

    Polymarket US is a distinct exchange from the international Polymarket adapter — different API, different auth, different price convention. Usage is parallel:

    import { Polymarket, PolymarketUS } from 'pmxtjs';
    
    // International Polymarket (USDC on-chain wallet)
    const intl = new Polymarket({
      privateKey: process.env.POLYMARKET_PRIVATE_KEY!,
      funderAddress: process.env.POLYMARKET_FUNDER_ADDRESS!,
    });
    const intlMarkets = await intl.fetchMarkets({ limit: 10 });
    console.log(intlMarkets[0].yes.price);
    
    // Polymarket US (API key + secret, USD-denominated)
    const us = new PolymarketUS({
      keyId: process.env.POLYMARKET_US_KEY_ID!,
      secretKey: process.env.POLYMARKET_US_SECRET_KEY!,
    });
    const usMarkets = await us.fetchMarkets({ limit: 10 });
    console.log(usMarkets[0].yes.price); // populated from marketSides[].price

Installation

npm:

npm install pmxtjs@2.25.0

PyPI:

pip install pmxt==2.25.0

Links

Full Changelog: v2.24.0f...v2.25.0f

v2.24.0

06 Apr 14:02

Choose a tag to compare

Added

  • Smarkets Exchange Integration: Full support for the Smarkets betting exchange with session-based authentication. Browse leaf events and markets via fetchEvents and fetchMarkets, query order books, place and cancel orders, and read balances. Includes correct array parameter serialization for the Smarkets API and type_scope=single_event filtering for leaf events. Comes with unit tests covering price conversion, auth, normalizer, and error translation.

Fixed

  • Polymarket: Silent Zero Balance: fetchBalance now catches the bundled @polymarket/clob-client TypeError thrown when getOpenOrders spreads an HTTP error envelope and translates it to a clear AuthenticationError with onboarding guidance. Also validates getBalanceAllowance shape so a swallowed error envelope no longer produces NaN and disables the on-chain fallback.
  • Polymarket: Proxy Discovery: auth.getClobClient now runs discoverProxy whenever signatureType is missing (even if funderAddress is set), ignores the synthetic EOA fallback from failed discovery, and defaults to gnosissafe (2) when the funder differs from the signer EOA. Fixes silent zero balances for modern Polymarket accounts. Closes #72.
  • Polymarket: Env Configuration: server/app.ts now reads POLYMARKET_FUNDER_ADDRESS / POLYMARKET_PROXY_ADDRESS and POLYMARKET_SIGNATURE_TYPE from the environment so SDK users can configure them without code changes.

Installation

npm:

npm install pmxtjs@2.24.0

PyPI:

pip install pmxt==2.24.0

Links

Full Changelog: v2.23.0f...v2.24.0f

v2.23.0

04 Apr 07:53

Choose a tag to compare

Added

  • Metaculus Exchange Integration: Full support for the Metaculus reputation-based forecasting platform. Browse questions, community predictions, and tournament structures via fetchMarkets and fetchEvents. Submit probability forecasts via createOrder (binary and multiple-choice questions) and withdraw them via cancelOrder. Group-of-questions posts are automatically expanded into individual sub-question markets. Token-based authentication via { apiToken: "..." }.
  • Python SDK: Token Auth: Exchange base class and Metaculus subclass now accept api_token for token-based authentication, with credential forwarding to the sidecar server.
  • Python SDK: Unit Tests: Comprehensive unit test suite for the Python client wrapper (test_client.py, conftest.py) covering market fetching, order creation, filtering, error handling, and credential forwarding.

Fixed

  • Probable Auth: viem Type Mismatch: Resolved WalletClient type disagreement when @prob/clob resolves a different viem copy than the host package.

Changed

  • TypeScript SDK: Bumped ts-jest to ^29.4.9.

Installation

npm:

npm install pmxtjs@2.23.0

PyPI:

pip install pmxt==2.23.0

Links

What's Changed

  • feat(python): add unit tests for client wrapper by @Bortlesboat in #68
  • feat(Metaculus): wire Metaculus exchange into package, server, docs, and compliance by @0xharryriddle in #71

New Contributors

Full Changelog: v2.22.2f...v2.23.0f

v2.22.2

02 Apr 13:43

Choose a tag to compare

Fixed

  • MarketOutcome Shorthand Consistency: fetchOrderBook, fetchOHLCV, fetchTrades, watchOrderBook, and watchTrades now accept a MarketOutcome object directly (e.g. market.yes) in both Python and TypeScript SDKs, matching the existing behavior of createOrder and buildOrder.

Installation

npm:

npm install pmxtjs@2.22.2

PyPI:

pip install pmxt==2.22.2

Links

Full Changelog: v2.22.1f...v2.22.2f