npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

polynode-sdk

v0.4.8

Published

TypeScript SDK for the PolyNode real-time Polymarket API

Readme

polynode-sdk

TypeScript SDK for the PolyNode real-time Polymarket API.

Stream settlements, trades, positions, deposits, oracle events, orderbook updates, and more through a single WebSocket connection. All events enriched with full market metadata.

New in v0.4: Local Cache — SQLite-backed local storage. Backfill wallet history in seconds, query trades and positions instantly with zero API calls.

Install

npm install polynode-sdk ws

# For local cache (optional):
npm install better-sqlite3

Requires Node.js 18+.

Quick Start

import { PolyNode } from 'polynode-sdk';

const pn = new PolyNode({ apiKey: 'pn_live_...' });

// Fetch top markets
const markets = await pn.markets({ count: 10 });
console.log(`${markets.count} markets, ${markets.total} total`);

// Search
const results = await pn.search('bitcoin');
console.log(results.results[0].question);

REST API

// System
await pn.healthz();
await pn.status();
await pn.createKey('my-bot');

// Markets
await pn.markets({ count: 10 });
await pn.market(tokenId);
await pn.marketBySlug('bitcoin-100k');
await pn.marketByCondition(conditionId);
await pn.marketsList({ count: 20, sort: 'volume' });
await pn.search('ethereum', { limit: 5 });

// Pricing
await pn.candles(tokenId, { resolution: '1h', limit: 100 });
await pn.stats(tokenId);

// Settlements
await pn.recentSettlements({ count: 20 });
await pn.tokenSettlements(tokenId, { count: 10 });
await pn.walletSettlements(address, { count: 10 });

// Wallets
await pn.wallet(address);

// RPC (rpc.polynode.dev)
await pn.rpc('eth_blockNumber');
await pn.rpc('eth_getBlockByNumber', ['latest', false]);

WebSocket Streaming

const sub = await pn.ws.subscribe('settlements')
  .minSize(100)
  .status('pending')
  .snapshotCount(20)
  .send();

sub.on('settlement', (event) => {
  console.log(`${event.taker_side} $${event.taker_size} on ${event.market_title}`);
});

sub.on('status_update', (event) => {
  console.log(`Confirmed in ${event.latency_ms}ms`);
});

// Or use async iterator
for await (const event of sub) {
  if (event.event_type === 'settlement') {
    console.log(event.taker_wallet, event.taker_size);
  }
}

Subscription Types

pn.ws.subscribe('settlements');   // pending + confirmed settlements
pn.ws.subscribe('trades');        // all trade activity
pn.ws.subscribe('prices');        // price-moving events
pn.ws.subscribe('blocks');        // new Polygon blocks
pn.ws.subscribe('wallets');       // all wallet activity
pn.ws.subscribe('markets');       // all market activity
pn.ws.subscribe('large_trades');  // $1K+ trades
pn.ws.subscribe('oracle');        // UMA resolution events
pn.ws.subscribe('chainlink');     // real-time price feeds

Subscription Filters

pn.ws.subscribe('settlements')
  .wallets(['0xabc...'])
  .tokens(['21742633...'])
  .slugs(['bitcoin-100k'])
  .conditionIds(['0xabc...'])
  .side('BUY')
  .status('pending')
  .minSize(100)
  .maxSize(10000)
  .eventTypes(['settlement'])
  .snapshotCount(50)
  .feeds(['BTC/USD'])
  .send();

Orderbook Streaming

await pn.orderbook.subscribe(['token_id_1', 'token_id_2']);

pn.orderbook.on('snapshot', (snap) => {
  console.log(snap.asset_id, snap.bids.length, 'bids', snap.asks.length, 'asks');
});

pn.orderbook.on('update', (delta) => {
  console.log(delta.asset_id, delta.bids.length, 'bid changes');
});

pn.orderbook.on('price', (change) => {
  for (const asset of change.assets) {
    console.log(asset.outcome, asset.price);
  }
});

LocalOrderbook

import { LocalOrderbook } from 'polynode-sdk';

const book = new LocalOrderbook();

pn.orderbook.on('snapshot', (snap) => book.applySnapshot(snap));
pn.orderbook.on('update', (delta) => book.applyUpdate(delta));

const fullBook = book.getBook(tokenId);
const bestBid = book.getBestBid(tokenId);
const bestAsk = book.getBestAsk(tokenId);
const spread = book.getSpread(tokenId);

OrderbookEngine

Higher-level orderbook client. One connection, shared state, filtered views for different parts of your app.

import { OrderbookEngine } from 'polynode-sdk';

const engine = new OrderbookEngine({ apiKey: 'pn_live_...' });

// Subscribe with token IDs, slugs, or condition IDs
await engine.subscribe([tokenA, tokenB, tokenC]);

engine.on('ready', () => {
  // Query computed values from local state
  engine.midpoint(tokenA);  // 0.465
  engine.spread(tokenA);    // 0.01
  engine.bestBid(tokenA);   // { price: '0.46', size: '226.29' }
  engine.book(tokenA);      // { bids: [...], asks: [...] }

  // Create filtered views for different components
  const view = engine.view([tokenA]);
  view.on('update', (u) => console.log(u.asset_id, 'updated'));
  view.midpoint(tokenA);    // reads from shared state

  // Swap tokens or destroy views at any time
  view.setTokens([tokenD, tokenE]);
  view.destroy();
});

engine.close();

Local Cache

Store trades and positions in a local SQLite database. Backfills recent history on startup, streams live updates, and serves all queries locally with zero API calls.

import { PolyNode, PolyNodeCache } from 'polynode-sdk';

const pn = new PolyNode({ apiKey: 'pn_live_...' });
const cache = new PolyNodeCache(pn, {
  dbPath: './cache.db',
  watchlistPath: './polynode.watch.json',
  onBackfillProgress: (p) => console.log(`${p.label}: ${p.fetched} trades`),
});

await cache.start();

// Query locally — instant, no API calls
const trades = cache.walletTrades('0xabc...', { limit: 50, side: 'BUY' });
const positions = cache.walletPositions('0xabc...');
const multiPos = cache.multiWalletPositions(['0xabc...', '0xdef...']);
const marketTrades = cache.marketTrades('0xcondition...');

// Add wallets at runtime
cache.addToWatchlist([{ type: 'wallet', id: '0xnew...', label: 'whale' }]);

// Stats
const stats = cache.stats();
console.log(`${stats.trade_count} trades, ${(stats.db_size_bytes / 1024 / 1024).toFixed(1)} MB`);

await cache.stop();

Watchlist (polynode.watch.json):

{
  "version": 1,
  "wallets": [
    { "address": "0xabc...", "label": "trader-1", "backfill": true }
  ],
  "settings": { "ttl_days": 30 }
}

Backfill timing: 1 request per wallet at 1 req/s. 10 wallets = 10 seconds. Up to 500 trades per wallet (configurable with backfillPages).

See full documentation for all query methods, configuration options, and examples.

Compression & Reconnection

Zlib compression is enabled by default (~50% bandwidth savings). All connections auto-reconnect with exponential backoff.

// Compression is automatic — no config needed
// To disable (not recommended):
const ws = pn.configureWs({ compress: false });

ws.onConnect(() => console.log('connected'));
ws.onDisconnect((reason) => console.log('disconnected:', reason));
ws.onReconnect((attempt) => console.log('reconnected, attempt', attempt));
ws.onError((err) => console.error(err));

Configuration

const pn = new PolyNode({
  apiKey: 'pn_live_...',
  baseUrl: 'https://api.polynode.dev',
  wsUrl: 'wss://ws.polynode.dev/ws',
  obUrl: 'wss://ob.polynode.dev/ws',
  rpcUrl: 'https://rpc.polynode.dev',
  timeout: 10000,
});

Error Handling

import { PolyNode, ApiError, WsError } from 'polynode-sdk';

try {
  await pn.market('invalid-id');
} catch (err) {
  if (err instanceof ApiError) {
    console.log(err.status);
    console.log(err.message);
  }
}

Cleanup

sub.unsubscribe();           // remove one subscription
pn.ws.unsubscribeAll();      // remove all
pn.ws.disconnect();          // close event stream
pn.orderbook.unsubscribe();  // unsubscribe orderbook
pn.orderbook.disconnect();   // close orderbook stream

Testing Utilities

The SDK includes helpers that return known-active Polymarket wallets for testing. Useful in examples, integration tests, and local development.

import { getActiveTestWallet, getActiveTestWallets } from 'polynode-sdk';

// Get a single active wallet (instant, uses cached fallback)
const wallet = await getActiveTestWallet();

// Get multiple active wallets
const wallets = await getActiveTestWallets(5);

// Fetch a fresh wallet from live data
const fresh = await getActiveTestWallet({ fresh: true });

Combine with the cache for a zero-config quickstart:

const wallet = await getActiveTestWallet();
cache.addToWatchlist([{ type: 'wallet', id: wallet, label: 'test' }]);

Links

License

MIT