Skip to content
StockSync
Docs · Core SDK

Interfaces

Core SDK

@stocksync/core is the library the CLI, the MCP server and the StockSync website are built on. It reads the Robinhood Stock Token API, Robinhood Chain and Chainlink price feeds, validates every response, and returns typed, read-only results.

Create a client

ts
import { createStockSync, resolveConfig } from '@stocksync/core';

const stocksync = createStockSync({ config: resolveConfig(process.env) });

Create one client per process and reuse it. The client owns the response cache, so repeated calls share upstream requests and concurrent calls for the same data make one request.

OptionDefaultPurpose
configresolveConfig({})Endpoints, default chain and timeouts
fetchglobalThis.fetchReplaces HTTP, for tests or custom transports
now() => new Date()Clock used for caching and freshness
retry3 attemptsOverrides the retry policy for transient failures
cachetrueSet to false to disable the in-memory cache
chainReadersviem readersReplaces the onchain readers, for example in tests

resolveConfig validates the STOCKSYNC_* environment variables described in Chain configuration and throws CONFIG_INVALID without echoing their values.

Methods

MethodReturns
getChainInfo(chain?)Network configuration; configured RPC URLs are never exposed
listAssets()Every token in the registry
searchAssets(query, { limit })Matches ranked by ticker, address, ISIN and name
getAsset(symbolOrAddress, { chain })One token, or data: null when nothing matches
getAssetByAddress(address, { chain })The token deployed at an address, or data: null
getPrices(symbols?)Raw underlying quotes
getPrice(symbol)One quote with the multiplier and the one-token equivalent
getCorporateActions(symbol?)Processed corporate actions, newest process date first
getMultiplierState(symbol, { chain, onchain })Registry and onchain multiplier, and whether they agree
getTradingCapabilities(symbol)Session tradability and the trading-halt flag
verifyCanonicalAddress({ address, chainId, expectedSymbol })A canonical verification verdict
getOraclePrice(symbol)The Chainlink feed reading, or data: null when no feed is listed

inspectStockToken(stocksync, symbolOrAddress) combines the registry entry, verification, quote, multiplier, trading status and corporate actions for one token. Each section degrades on its own: a failed quote becomes price: null with a SECTION_UNAVAILABLE warning instead of failing the whole inspection.

Results

Every data method resolves to a Sourced<T>:

ts
interface Sourced<T> {
  data: T;
  freshness: DataFreshness; // the data that defines this result, e.g. the quote in a price
  sources: DataFreshness[]; // every upstream the result was assembled from
  warnings: DataWarning[]; // non-fatal issues, never silently dropped
}

What each field means, and how to decide whether data is stale, is covered in Data semantics.

Request options

Every data method accepts { signal, fresh }:

  • signal: an AbortSignal. Cancelled requests are never retried.
  • fresh: bypass the cache for this call. The fresh response is still cached for later calls.

Errors

Methods throw only StockSyncError, with a stable code and a retryable flag. Lookups that can legitimately find nothing (getAsset, getAssetByAddress, getOraclePrice) return data: null instead of throwing.

ts
import { isStockSyncError } from '@stocksync/core';

try {
  const { data } = await stocksync.getPrice('NVDA');
} catch (error) {
  if (isStockSyncError(error) && error.retryable) {
    // A transient upstream failure: back off and try again.
  }
  throw error;
}

The full list is in Errors and warnings.

Example: refuse a contract that is not canonical

ts
const { data: verdict } = await stocksync.verifyCanonicalAddress({
  address: '0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC',
  expectedSymbol: 'NVDA',
});

if (verdict.status !== 'canonical') {
  throw new Error(`Not the canonical NVDA contract: ${verdict.status}`);
}

Example: read a price with its basis

ts
import { assessFreshness } from '@stocksync/core';

const { data: price, freshness } = await stocksync.getPrice('NVDA');

price.underlying.bid; // raw underlying-equity quote, not multiplier-adjusted
price.tokenEquivalent.bid; // quote × current multiplier, exact decimal string
assessFreshness(freshness).state; // 'fresh', 'stale' or 'unknown'

Runtime notes

  • Use the SDK on servers. It depends on viem, and configured RPC URLs often contain API keys.
  • Numeric values are decimal strings, never floating-point numbers. Use compareDecimals, multiplyDecimals and divideDecimals from the package when you need arithmetic.