Common patterns for timeouts, cancellation, pagination, heartbeat, and advanced client configuration.
Timeouts and cancellation
Every SDK method accepts timeoutMs and signal for deadline control:
Code
// Per-request timeoutconst symbols = await client.marketData.listSymbols({ timeoutMs: 5_000,});// Cancellation via AbortControllerconst controller = new AbortController();const events = client.predictions.listEvents( { status: ["active"] }, { signal: controller.signal },);// Cancel from elsewherecontroller.abort();
Set a default timeout for all operations on the client:
Code
const client = await createClient({ auth, timeoutMs: 10_000, // 10s default for all REST and WebSocket waits});
WebSocket stream listeners also support signal-based cleanup:
Code
const trades = client.websocket.trades("BTCUSD");const controller = new AbortController();trades.on("message", (trade) => { console.log(trade);}, { signal: controller.signal });// Later: remove the listener without manually calling off()controller.abort();
Pagination
List endpoints that return many results use offset pagination. The SDK provides an async generator that walks pages automatically:
Code
import { HttpTransport, HmacAuth } from "gemini-markets/server";const transport = new HttpTransport({ env: "sandbox", auth: new HmacAuth({ apiKey, apiSecret }),});// Walk prediction market positions, 100 per page, up to 500 totalfor await (const position of transport.paginate({ method: "POST", path: "/v1/prediction-markets/positions", limit: 100, maxItems: 500, itemsKey: "positions", // response is { positions, total }, not a bare array parameterLocation: "query", // limit/offset go as query params, not in signed payload})) { console.log(position);}
Deduplication
Offset pagination is not snapshot-consistent — records can shift between pages while you're iterating. Use dedupeKey to fail loudly if the same record appears twice:
Code
for await (const position of transport.paginate({ method: "POST", path: "/v1/prediction-markets/positions", limit: 100, itemsKey: "positions", parameterLocation: "query", dedupeKey: (item: unknown) => { const pos = item as Record<string, unknown>; return `${pos.instrumentId}:${pos.outcome}`; // instrumentId alone is not unique — YES and NO positions share the same ID },})) { // Throws SdkError if a duplicate instrumentId:outcome pair is seen}
Heartbeat
Keep a session alive with an explicit heartbeat. The heartbeat is stopped by default — you control its lifecycle: