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

@liberfi.io/react-predict

v0.1.4

Published

React hooks and client for prediction markets (prediction-server backend), including Polymarket and DFlow order flows

Readme

@liberfi.io/react-predict

React hooks and HTTP client for prediction markets backed by the prediction-server API. Supports Polymarket (EVM, CLOB-based) and DFlow (Solana-based) order flows, including L1/L2 authentication, EIP-712 order signing, and all read-side market data queries.

Consumed primarily by @liberfi.io/ui-predict and by Next.js prediction-market applications. The package is wallet-agnostic — it defines a PolymarketSigner interface rather than depending on any specific wallet library.

Design Philosophy

  • Wallet-agnostic (IoC)PolymarketSigner is an interface injected by the consumer. No dependency on @liberfi.io/wallet-connector or any specific wallet library.
  • No @polymarket/clob-client dependency — EIP-712 signing and HMAC-SHA256 are implemented with the Web Crypto API to avoid ethers v5/v6 conflicts.
  • In-memory credentials — Polymarket L2 API keys are derived with nonce=0 (permanent, deterministic) and stored only in a React context. They disappear on page unload.
  • Dual entry pointsindex.ts for React consumers; server.ts for SSR-safe usage in Next.js Server Components and route handlers (no React imports).
  • Layered realtime API — Low-level WS subscription hooks give full control; high-level useRealtime* hooks merge WS + REST with automatic fallback, so consumers can upgrade from polling to real-time with a one-line change.

Installation

pnpm add @liberfi.io/react-predict

Peer dependencies the consumer must provide:

pnpm add react react-dom @tanstack/react-query

API Reference

Providers

PredictProvider

Provides the PredictClient instance via React context. Place at the application root where prediction hooks are used.

import {
  createPredictClient,
  PredictProvider,
} from "@liberfi.io/react-predict";

const client = createPredictClient("https://prediction.example.com");

<PredictProvider client={client}>
  <App />
</PredictProvider>;

Props:

  • client: PredictClient — a PredictClient instance.
  • wsClient?: PredictWsClient | null — optional WebSocket client for real-time data.

PolymarketProvider

Manages in-memory Polymarket L2 credentials. Wrap around components that place Polymarket orders.

import { PolymarketProvider } from "@liberfi.io/react-predict";

<PolymarketProvider>
  <TradePanel />
</PolymarketProvider>;

Client

PredictClient

HTTP client for the prediction-server REST API.

import { createPredictClient } from "@liberfi.io/react-predict";

const client = createPredictClient("https://prediction.example.com");
const page = await client.listEvents({ status: "open", limit: 20 });
const event = await client.getEvent("will-trump-win-2024");

Key methods:

| Method | Maps to | | ----------------------------------------- | ----------------------------------------- | | listEvents(params?) | GET /api/v1/events | | getEvent(slug, source?) | GET /api/v1/events/:slug | | getSimilarEvents(slug, source, params?) | GET /api/v1/events/:slug/similar | | getMarket(slug, source?) | GET /api/v1/markets/:slug | | getOrderbook(slug, source) | GET /api/v1/markets/:slug/orderbook | | listMarketTrades(slug, params) | GET /api/v1/markets/:slug/trades | | getPriceHistory(slug, source, range?) | GET /api/v1/markets/:slug/price-history | | listCandlesticks(slug, params?) | GET /api/v1/markets/:slug/candlesticks | | getPositions(source, user) | GET /api/v1/positions | | listOrders(params) | GET /api/v1/orders | | getOrder(id, source) | GET /api/v1/orders/:id | | cancelOrder(id, source) | DELETE /api/v1/orders/:id | | createPolymarketOrder(input, headers) | POST /api/v1/orders/polymarket | | createDFlowQuote(body) | POST /api/v1/orders/dflow/quote | | submitDFlowTransaction(body) | POST /api/v1/orders/dflow/submit | | listTrades(params) | GET /api/v1/trades |


PredictWsClient

WebSocket client for real-time market data from prediction-server (/api/v1/ws). Supports orderbook, prices, and trades channels with auto-reconnect.

import { createPredictWsClient } from "@liberfi.io/react-predict";

const wsClient = createPredictWsClient({
  wsUrl: "wss://prediction.example.com/api/v1/ws",
});

// Convenience subscription — returns unsubscribe function
const unsub = wsClient.subscribePrices(["btc-above-100k"], (msg) => {
  console.log(msg.data.yes_bid);
});

// Low-level multi-channel subscription
wsClient.subscribe(["orderbook", "trades"], ["btc-above-100k"]);

// Clean up
unsub();
wsClient.disconnect();

Config (PredictWsClientConfig):

| Option | Type | Default | Description | | ----------------------- | --------- | ------- | --------------------------------------- | | wsUrl | string | — | WebSocket URL (required) | | autoConnect | boolean | true | Connect on construction | | autoReconnect | boolean | true | Reconnect on unexpected close | | reconnectIntervalBase | number | 1000 | Base delay (ms) for exponential backoff | | reconnectMaxInterval | number | 30000 | Max reconnect delay (ms) | | pingInterval | number | 30000 | Application-level ping interval (ms) |


Hooks — Predict (data queries)

All hooks require PredictProvider in the tree.

usePredictClient()

Returns the PredictClient from context.

useEvents(params?, queryOptions?)

GET /api/v1/events — paginated events list.

useEvent({ slug, source? }, queryOptions?)

GET /api/v1/events/:slug — single event.

useInfiniteEvents(params, queryOptions?)

Cursor-based infinite query for events. Use resolveEventsParams() to build params.

useSearchEvents({ keyword, ...options }, queryOptions?)

Infinite query with search parameter for full-text event search.

useSimilarEvents({ slug, source, limit?, same_source? }, queryOptions?)

GET /api/v1/events/:slug/similar

useMarket({ slug, source? }, queryOptions?)

GET /api/v1/markets/:slug

useMarketHistory(markets, range?)

Price history series for multiple markets. Uses ChartRange enum for range.

useOrderbook({ slug, source }, queryOptions?)

GET /api/v1/markets/:slug/orderbook — polls every 5 s.

useMarketTrades({ slug, source, ... }, queryOptions?)

GET /api/v1/markets/:slug/trades

usePriceHistory({ slug, source, range? }, queryOptions?)

GET /api/v1/markets/:slug/price-history

useCandlesticks({ slug, interval?, limit? }, queryOptions?)

GET /api/v1/markets/:slug/candlesticks

usePositions({ source, user }, queryOptions?)

GET /api/v1/positions

useOrders(params, queryOptions?)

GET /api/v1/orders

useOrder({ id, source }, queryOptions?)

GET /api/v1/orders/:id — polls every 1 s.

useCancelOrder(mutationOptions?)

DELETE /api/v1/orders/:id — invalidates orders queries on success.

useTrades(params, queryOptions?)

GET /api/v1/trades (by wallet)

useDFlowQuote(params, queryOptions?)

POST /api/v1/orders/dflow/quote

useDFlowSubmit(mutationOptions?)

POST /api/v1/orders/dflow/submit — invalidates orders and positions queries on success.


Hooks — WebSocket (low-level subscriptions)

These hooks manage pure WS subscription state and do not interact with React Query. Require PredictProvider with a wsClient prop.

usePredictWsClient()

Returns { wsClient, wsStatus, isWsConnected } from context.

usePricesSubscription({ wsClient, slugs, enabled?, onUpdate? })

Subscribe to price updates. Returns { prices: Map<slug, WsPriceEvent>, isSubscribed }.

useOrderbookSubscription({ wsClient, slug, enabled?, onUpdate? })

Subscribe to orderbook snapshots for a single market. Returns { orderbook: WsOrderbookEvent | null, isSubscribed }.

useTradesSubscription({ wsClient, slug, enabled?, maxHistory?, onUpdate? })

Subscribe to trade events. Maintains a bounded buffer (default 100). Returns { trades: WsTradeEvent[], isSubscribed, clearHistory }.


Hooks — WebSocket (high-level realtime, WS + REST merged)

These hooks combine WS subscriptions with REST queries for automatic fallback. When WS is connected, they write data directly into the React Query cache via setQueryData (no refetch) and disable polling. When WS is unavailable, they fall back to REST polling.

useRealtimeOrderbook({ slug, source }, queryOptions?)

Drop-in replacement for useOrderbook. Returns the same UseQueryResult<Orderbook>.

// Before (5s polling)
const { data } = useOrderbook({ slug, source });

// After (real-time + auto fallback)
const { data } = useRealtimeOrderbook({ slug, source });

useRealtimePrices({ slugs, enabled?, onUpdate? })

Returns { prices: Map<slug, WsPriceEvent>, isSubscribed }. Falls back gracefully (empty map) when no WS client.

useRealtimeTrades({ slug, enabled?, maxHistory?, onUpdate?, syncToQueryCache? })

Returns { trades, isSubscribed, clearHistory }. When syncToQueryCache is true (default), new trades are also prepended into React Query market-trades cache entries.


Hooks — Polymarket (order placement)

All hooks require both PredictProvider and PolymarketProvider in the tree.

usePolymarket()

Returns { credentials, isAuthenticating, authError, authenticate, clearCredentials } from the Polymarket context.

useCreatePolymarketOrder(mutationOptions?)

Full Polymarket order flow — authenticate if needed, sign EIP-712 order on CTF Exchange, build HMAC L2 headers, submit via prediction-server proxy.

const { mutateAsync: createOrder, isPending } = useCreatePolymarketOrder({
  onError: (err) => toast.error(err.message),
});

await createOrder({
  signer: myPolymarketSigner,
  input: {
    tokenId: "123456789",
    price: 0.55,
    size: 10,
    side: "BUY",
    tickSize: "0.01",
    negRisk: false,
  },
});

Types — Key Interfaces

| Type | Description | | ----------------------- | ----------------------------------------------------------------------- | | PolymarketSigner | IoC interface for EIP-712 signing (implement in the consumer app) | | PolymarketCredentials | In-memory L2 apiKey / secret / passphrase | | CreateOrderInput | Parameters for a Polymarket limit order | | PredictEvent | Prediction event aggregate | | PredictMarket | Tradeable market within an event | | PredictOrder | User order record | | PredictTrade | Trade record | | PredictPosition | User position | | ProviderSource | "dflow" | "polymarket" | | OrderSide | "BUY" | "SELL" | | PredictPage<T> | Paginated response wrapper | | WsChannel | "orderbook" | "prices" | "trades" | | WsConnectionStatus | "connecting" | "connected" | "disconnected" | "reconnecting" | | WsOrderbookEvent | Full orderbook snapshot from WS | | WsPriceEvent | Price update from WS | | WsTradeEvent | Single trade from WS | | WsDataMessage<T> | Envelope: { channel, market_slug, data: T, ts } |


Server-safe exports (/server)

Import from @liberfi.io/react-predict/server in Server Components and route handlers:

import {
  resolveEventsParams,
  infiniteEventsQueryKey,
  fetchEventsPage,
  fetchEvent,
  createPredictClient,
} from "@liberfi.io/react-predict/server";

// Prefetch on the server
const client = createPredictClient(process.env.PREDICT_API_URL);
const params = resolveEventsParams({ status: "open" });
await queryClient.prefetchInfiniteQuery({
  queryKey: infiniteEventsQueryKey(params),
  queryFn: ({ pageParam }) =>
    fetchEventsPage(client, { ...params, cursor: pageParam }),
  initialPageParam: undefined,
});

Usage Example

import {
  createPredictClient,
  PredictProvider,
  PolymarketProvider,
  useInfiniteEvents,
  resolveEventsParams,
  useCreatePolymarketOrder,
} from "@liberfi.io/react-predict";

const client = createPredictClient("https://prediction.example.com");

function App() {
  return (
    <PredictProvider client={client}>
      <PolymarketProvider>
        <EventList />
        <TradePanel />
      </PolymarketProvider>
    </PredictProvider>
  );
}

function EventList() {
  const params = resolveEventsParams({ status: "open", limit: 20 });
  const { data, hasNextPage, fetchNextPage } = useInfiniteEvents(params);
  const events = data?.pages.flatMap((p) => p.items) ?? [];
  return <ul>{events.map((e) => <li key={e.slug}>{e.title}</li>)}</ul>;
}

function TradePanel() {
  const { mutateAsync: createOrder } = useCreatePolymarketOrder();
  // implement signer using EvmWalletAdapter.getEip1193Provider()
  return <button onClick={() => createOrder({ signer, input: { ... } })}>Trade</button>;
}

WebSocket Real-time Example

import {
  createPredictClient,
  createPredictWsClient,
  PredictProvider,
  useRealtimeOrderbook,
  useRealtimePrices,
} from "@liberfi.io/react-predict";

const client = createPredictClient("https://prediction.example.com");
const wsClient = createPredictWsClient({
  wsUrl: "wss://prediction.example.com/api/v1/ws",
});

function App() {
  return (
    <PredictProvider client={client} wsClient={wsClient}>
      <MarketView slug="btc-above-100k" source="dflow" />
    </PredictProvider>
  );
}

function MarketView({
  slug,
  source,
}: {
  slug: string;
  source: "dflow" | "polymarket";
}) {
  // Real-time orderbook — falls back to 5s polling when WS unavailable
  const { data: orderbook } = useRealtimeOrderbook({ slug, source });

  // Real-time prices
  const { prices } = useRealtimePrices({ slugs: [slug] });
  const price = prices.get(slug);

  return (
    <div>
      <p>Yes bid: {price?.yes_bid ?? "—"}</p>
      <p>Bids: {orderbook?.bids.length ?? 0} levels</p>
    </div>
  );
}

Future Improvements

  • Server-side Polymarket credential management via prediction-server (requires JWT auth in the server).
  • Cancel-order support for Polymarket (currently only DFlow cancel is available server-side).
  • useInfiniteOrders hook for cursor-based order history pagination.
  • Retry logic for failed L2 authentication (e.g. expired credentials).
  • Migrate ui-predict's DflowPredictWsClient to use PredictWsClient from this package (unified protocol via prediction-server instead of direct DFlow WS).