Releases: pmxt-dev/pmxt
v2.26.2
Added
-
openapi.yamlnow ships in the publishedpmxt-coretarball atdist/server/openapi.yaml. Previously the spec was generated intocore/src/server/openapi.yamland consumed in-repo (by the SDK generators and the openapi drift check) but was excluded from the npm package because onlydist/,bin/, andAPI_REFERENCE.mdwere in thefilesfield. Downstream consumers ofpmxt-corecan now read the spec directly fromnode_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:
buildnow doestsc && cp src/server/openapi.yaml dist/server/openapi.yaml. The existingdistentry infilesmeans it's included innpm publishwithout touching thefilesarray. Verified withnpm pack --dry-run—dist/server/openapi.yaml(52 kB) is in the tarball.
Installation
npm:
npm install pmxtjs@2.26.2PyPI:
pip install pmxt==2.26.2Links
Full Changelog: v2.26.1f...v2.26.2f
v2.26.1
Changed
pmxt.stop_server()/pmxt.restart_server()now emitDeprecationWarning(Python SDK): The flat aliases still work and still call the underlyingServerManager, but they now warn thatpmxt.server.stop()/pmxt.server.restart()is the standard. This reverses the "no deprecation, no warnings" stance from 2.26.0 — the namespacedpmxt.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.1PyPI:
pip install pmxt==2.26.1Links
Full Changelog: v2.26.0f...v2.26.1f
v2.26.0
Fixed
-
ServerManager.ensureServerRunning()race condition (TypeScript and Python SDKs): Creating multipleExchangeinstances in parallel (e.g.const p = new Polymarket(); const k = new Kalshi(); const l = new Limitless();) caused every request to return401 Unauthorized. EachExchangeconstructed its ownServerManagerand each one calledensureServerRunning()concurrently. Every call saw "no server running", every call spawned its own sidecar viapmxt-ensure-server, and the lock file ended up pointing at whichever spawn wrote last — but eachExchangehad already captured its ownbasePathat 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 staticPromise | nullcache. 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-levelthreading.Lockfor 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.
- TypeScript:
Added
-
pmxt.servernamespace 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()— Returnstrueif the sidecar responds to/health,falseotherwise. 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 lastnlines 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
Exchangeinstances boot in parallel. Previously users had to reach intoServerManagerdirectly or shell out tops/lsofto 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-servernow redirects the spawned sidecar's stdio to a log file in the~/.pmxt/directory sopmxt.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.0PyPI:
pip install pmxt==2.26.0Links
Full Changelog: v2.25.3f...v2.26.0f
v2.25.3
Added
- TypeScript SDK:
Opinion,Metaculus,Smarkets,PolymarketUSexchange classes: These adapters already existed incore/src/exchanges/and were reachable via the sidecar HTTP API, but the hand-maintained TypeScript SDK client atsdks/typescript/pmxt/client.ts(and the package entry point atsdks/typescript/index.ts) never exposed them. Anyone usingpmxtjswould seepmxt.Opinion === undefinedeven though the core adapter had been merged. All four are now exported and work via the standardnew pmxt.Opinion({}).fetchEvents()consumer path. - Python SDK:
Smarkets,PolymarketUSexchange classes: Same drift insdks/python/pmxt/_exchanges.pyandsdks/python/pmxt/__init__.py. Both are now exported. openapi.yamlsource_exchangeenum: Addedkalshi-demoandpolymarket_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 tocore/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 reachedpmxtjs.
CI
- New
core/scripts/check-exchange-drift.jsand.github/workflows/exchange-drift-check.yml: Walkscore/src/exchanges/*/index.tsto discover every concretePredictionMarketExchangesubclass, 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.3PyPI:
pip install pmxt==2.25.3Links
Full Changelog: v2.25.2f...v2.25.3f
v2.25.2
Fixed
- TypeScript and Python SDKs: dropped fields in
convertMarket/convertEvent: The hand-maintained converter shims at the top ofsdks/typescript/pmxt/client.tsandsdks/python/pmxt/client.pyhad their own allowlists and were silently droppingslug,tickSize,status,contractAddressonUnifiedMarketandvolume,volume24honUnifiedEventeven though the sidecar populates them and the generated OpenAPI client maps them. Both shims now copy the full set, and the correspondingUnifiedMarket/UnifiedEventinterfaces inmodels.ts/models.pydeclare 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.2PyPI:
pip install pmxt==2.25.2Links
Full Changelog: v2.25.1f...v2.25.2f
v2.25.1
Fixed
- Polymarket: dropped market fields:
mapMarketToUnifiednow populatesslug(from Gammaslug),tickSize(fromorderPriceMinTickSize),status(fromarchived>closed>activeprecedence), andcontractAddress(fromconditionId). These were silently dropped during normalization and surfaced asundefinedto consumers. - OpenAPI spec drift:
core/scripts/generate-openapi.jswas missing severalUnifiedEventandUnifiedMarketfields that already existed intypes.ts(UnifiedEvent.volume,UnifiedEvent.volume24h,UnifiedMarket.slug,UnifiedMarket.tickSize) plusCreateOrderParams.tickSize/CreateOrderParams.negRisk. The generatedopenapi.yamland 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. UnifiedMarkettype: AddedstatusandcontractAddressto the type declaration so the new Polymarket fields are visible to TypeScript consumers.
Installation
npm:
npm install pmxtjs@2.25.1PyPI:
pip install pmxt==2.25.1Links
Full Changelog: v2.25.0f...v2.25.1f
v2.25.0
Added
-
Polymarket US Exchange Integration 🇺🇸: New adapter wrapping the official
polymarket-usSDK for the US-regulated Polymarket gateway. SupportsfetchMarkets/fetchEvents(by slug, event, or outcomeId),fetchOrderBook,fetchBalance,fetchPositions,fetchMyTrades,fetchOpenOrders,fetchOrder,createOrder/buildOrder/submitOrder,cancelOrder, and WebSocket streaming viawatchOrderBook/watchTrades(backed by the SDK'sMarketsWebSocket; credentials are required because the SDK factory mandateskeyId+secretKeyeven for the public market socket). Handles the long-side price convention (all API prices are YES-side; short-side inputs are auto-converted via1 - price), normalizes outcomes to${slug}:long/${slug}:short, surfaces live prices frommarketSides[].price(withoutcomePrices[]fallback), liftsorderPriceMinTickSizeontoUnifiedMarket.tickSize, and stashes human side labels (e.g. team names) in outcome metadata. Maintains an in-memoryorderId -> marketSlugcache socancelOrder(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 is0.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.0PyPI:
pip install pmxt==2.25.0Links
Full Changelog: v2.24.0f...v2.25.0f
v2.24.0
Added
- Smarkets Exchange Integration: Full support for the Smarkets betting exchange with session-based authentication. Browse leaf events and markets via
fetchEventsandfetchMarkets, query order books, place and cancel orders, and read balances. Includes correct array parameter serialization for the Smarkets API andtype_scope=single_eventfiltering for leaf events. Comes with unit tests covering price conversion, auth, normalizer, and error translation.
Fixed
- Polymarket: Silent Zero Balance:
fetchBalancenow catches the bundled@polymarket/clob-clientTypeErrorthrown whengetOpenOrdersspreads an HTTP error envelope and translates it to a clearAuthenticationErrorwith onboarding guidance. Also validatesgetBalanceAllowanceshape so a swallowed error envelope no longer producesNaNand disables the on-chain fallback. - Polymarket: Proxy Discovery:
auth.getClobClientnow runsdiscoverProxywheneversignatureTypeis missing (even iffunderAddressis set), ignores the synthetic EOA fallback from failed discovery, and defaults tognosissafe(2) when the funder differs from the signer EOA. Fixes silent zero balances for modern Polymarket accounts. Closes #72. - Polymarket: Env Configuration:
server/app.tsnow readsPOLYMARKET_FUNDER_ADDRESS/POLYMARKET_PROXY_ADDRESSandPOLYMARKET_SIGNATURE_TYPEfrom the environment so SDK users can configure them without code changes.
Installation
npm:
npm install pmxtjs@2.24.0PyPI:
pip install pmxt==2.24.0Links
Full Changelog: v2.23.0f...v2.24.0f
v2.23.0
Added
- Metaculus Exchange Integration: Full support for the Metaculus reputation-based forecasting platform. Browse questions, community predictions, and tournament structures via
fetchMarketsandfetchEvents. Submit probability forecasts viacreateOrder(binary and multiple-choice questions) and withdraw them viacancelOrder. Group-of-questions posts are automatically expanded into individual sub-question markets. Token-based authentication via{ apiToken: "..." }. - Python SDK: Token Auth:
Exchangebase class andMetaculussubclass now acceptapi_tokenfor 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
WalletClienttype disagreement when@prob/clobresolves a different viem copy than the host package.
Changed
- TypeScript SDK: Bumped
ts-jestto^29.4.9.
Installation
npm:
npm install pmxtjs@2.23.0PyPI:
pip install pmxt==2.23.0Links
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
- @Bortlesboat made their first contribution in #68
Full Changelog: v2.22.2f...v2.23.0f
v2.22.2
Fixed
- MarketOutcome Shorthand Consistency:
fetchOrderBook,fetchOHLCV,fetchTrades,watchOrderBook, andwatchTradesnow accept aMarketOutcomeobject directly (e.g.market.yes) in both Python and TypeScript SDKs, matching the existing behavior ofcreateOrderandbuildOrder.
Installation
npm:
npm install pmxtjs@2.22.2PyPI:
pip install pmxt==2.22.2Links
Full Changelog: v2.22.1f...v2.22.2f