Skip to content

TypeScript (web) SDK

ESM-only TypeScript SDK that speaks gRPC-Web directly to the upstream sweetspot-server (tonic + tonic_web). Works in any modern browser and in Node 18.14+. No build-time codegen required by consumers — the package ships pre-generated TypeScript.

Surfaces

SurfaceHow
Public (MarketDataService, StatsService, HistoricalService)createClient, createServiceClient
Authenticated (MakerService)createMakerClient + AuthFlow (passwordless email) or apiKeyInterceptor(...) (org API key)
TxService + wallet signingNot exposed — drive a wallet adapter or use the Rust / Python SDK

Install

sh
npm install @superis-labs/sweetspot-client @bufbuild/protobuf

The only runtime dependency is @bufbuild/protobuf for serialization. The gRPC-Web transport ships in-tree.

Quickstart

ts
import {
  GrpcWebTransport,
  MarketDataService,
  StatsService,
  createServiceClient,
} from "@superis-labs/sweetspot-client";
import { FeedLevel } from "@superis-labs/sweetspot-client/gen/sweetspot/api/v1/common_pb.js";

const transport = new GrpcWebTransport({
  baseUrl: "https://api.superis.exchange",
});

// Public RPC — no auth needed.
const market = createServiceClient(MarketDataService, transport);
const stats = createServiceClient(StatsService, transport);
const pairs = await market.listPairs({});
const summary = await stats.getSummary({});
console.log(pairs.pairs);
console.log(summary);

// Server-streaming RPC — `for await` works directly.
const pair = { base: { id: 1n }, quote: { id: 0n } };
for await (const event of market.subscribe({
  pairs: [{ pair, level: FeedLevel.L2, snapshotOnly: false }],
})) {
  console.log(event);
}

Where to go from here

You wantPage
Stream books and fillsMarket data
Pull historical trades / candlesHistorical queries
Authenticate against MakerServiceAuth flow

MakerService (authenticated)

MakerService requires organization-scoped credentials. Build a maker client via createMakerClient, passing either an AuthFlow (passwordless email login) or apiKeyInterceptor(key) (organization API key).

ts
import {
  AuthFlow,
  createMakerClient,
} from "@superis-labs/sweetspot-client";

// Persist the bearer across reloads. Any localStorage-shaped store works
// — pass a sessionStorage, an IndexedDB-backed shim, or your own.
const auth = new AuthFlow({
  baseUrl: "https://auth.api.superis.exchange",
  storage: globalThis.localStorage,
  onExpired: () => router.push("/login"),
});

// Login form:
await auth.requestLoginCode("trader@example.com");
// …prompt user, then…
await auth.verifyLoginCode("trader@example.com", code);

// Bind credentials to a maker client.
const maker = createMakerClient({
  baseUrl: "https://auth.api.superis.exchange",
  auth,
});
const { balances } = await maker.getBalance({ spotIds: [] });

See Auth flow → TypeScript for the full walk-through, including API key auth.

HistoricalService (public)

HistoricalService is exposed as a generated descriptor. Build a service client with the public transport:

ts
import {
  GrpcWebTransport,
  HistoricalService,
  createServiceClient,
} from "@superis-labs/sweetspot-client";

const historical = createServiceClient(
  HistoricalService,
  new GrpcWebTransport({
    baseUrl: "https://api.superis.exchange",
  }),
);

const { trades } = await historical.getTrades({ pair, limit: 100 });

Decimal handling

Live book and fill price / size fields come back as Decimal { value: string }. Parse with bignumber.js or decimal.js:

ts
import BigNumber from "bignumber.js";

const price = new BigNumber(trade.price.value);
const size = new BigNumber(trade.size.value);
const notional = price.multipliedBy(size);

Historical Trade and Candle responses use the same Decimal { value: string } wrapper for price, size, and OHLCV fields.

Errors

ts
import { GrpcError, GrpcCode } from "@superis-labs/sweetspot-client";

try {
  await market.listPairs({});
} catch (err) {
  if (err instanceof GrpcError) {
    switch (err.code) {
      case GrpcCode.ResourceExhausted: await sleep(backoff); break;
      case GrpcCode.Unavailable: await sleep(backoff); break;
    }
  }
}

See Errors for the full code map.

Wire format

The transport speaks application/grpc-web+proto over HTTP/1.1, terminating at the server's tonic_web::GrpcWebLayer. Server streaming is supported via AsyncIterable<Output> on every streaming RPC. There is no gRPC-streaming-bidi or client-streaming over gRPC-Web — those RPCs throw at call time.

Browser compatibility

Modern browsers (Chrome 90+, Firefox 90+, Safari 14+). Requires fetch and ReadableStream — both baseline in every release-channel browser since 2022.

Source

Build on Solana