# @mcxross/surflux

Unofficial TypeScript SDK for the [Surflux](https://surflux.dev) API — DeepBook spot/margin data, NFT indexing, and real-time SSE trade streams.

## Installation

```sh
npm install @mcxross/surflux
```

## Configuration

### API key types

Surflux uses **two separate API key systems**:

| Key | Purpose | Required |
|-----|---------|---------|
| `restApiKey` | All REST endpoints (DeepBook + NFT) | Always |
| `sseApiKeys[poolName]` | SSE trade streams — one key **per DeepBook pool** | Only when streaming |

Per-pool SSE keys are enforced at subscription time. Calling `subscribeTrades("SUI_USDC", …)` without a corresponding `sseApiKeys["SUI_USDC"]` throws immediately.

### Networks

```ts
import { SurfluxClient } from "@mcxross/surflux";

const mainnet = new SurfluxClient({
  restApiKey: "your-rest-api-key",
  network: "mainnet", // default
});

const testnet = new SurfluxClient({
  restApiKey: "your-rest-api-key",
  network: "testnet",
});
```

Default base URLs:

| Network | REST | SSE stream |
|---------|------|-----------|
| mainnet | `https://api.surflux.dev` | `https://flux.surflux.dev` |
| testnet | `https://api.surflux.dev` | `https://testnet-flux.surflux.dev` |

Override either URL:

```ts
const client = new SurfluxClient({
  restApiKey: "key",
  restBaseUrl: "https://custom-api.example.com",
  streamBaseUrl: "https://custom-flux.example.com",
});
```

## DeepBook spot

```ts
const client = new SurfluxClient({ restApiKey: "key" });

const pools   = await client.getSpotPools();
const book    = await client.getOrderbook("SUI_USDC", { limit: 10 });
const trades  = await client.getTrades("SUI_USDC", { limit: 100 });
const candles = await client.getOhlcv("SUI_USDC", "1h", {
  limit: 50,
  from: 1700000000, // UNIX seconds
  to: 1700086400,
});
```

Pool names accept any of: `SUI_USDC`, `sui_usdc`, `SUI/USDC`, or `SUI-USDC`.

OHLCV timeframes: `"1m"` `"5m"` `"15m"` `"1h"` `"4h"` `"1d"`

## DeepBook margin

```ts
const pools      = await client.getMarginPools();
const registered = await client.getRegisteredMarginPools();
const managers   = await client.getMarginManagers();
const loans      = await client.getActiveLoans();
const supplies   = await client.getActiveSupplies();
const liquidations = await client.getLiquidations();
const caps       = await client.getSupplierCaps();
const referrals  = await client.getSupplyReferrals();
```

## NFT endpoints

```ts
// Paginated — returns { items, isLastPage, currentPage, perPage }
const page    = await client.getNftsByAddress("0xabc…", { page: 0, perPage: 20 });
const snap    = await client.getCollectionSnapshot("0x41c…::panzerdog::Panzerdog");
const holders = await client.getCollectionHolders("0x41c…::panzerdog::Panzerdog");
const kiosk   = await client.getKioskNfts("0xkiosk…");

// Single item
const nft = await client.getNftByObjectId("0xdef…");

// Auto-walk all pages — return flat T[]
const allNfts    = await client.fetchAllNftsByAddress("0xabc…");
const allInCol   = await client.fetchAllCollectionSnapshot("0x41c…::panzerdog::Panzerdog");
const allHolders = await client.fetchAllCollectionHolders("0x41c…::panzerdog::Panzerdog");
const allKiosk   = await client.fetchAllKioskNfts("0xkiosk…");
```

## SSE trade streams

Each pool requires its own SSE API key:

```ts
const client = new SurfluxClient({
  restApiKey: "rest-key",
  sseApiKeys: {
    SUI_USDC:  "sse-key-for-sui-usdc",
    DEEP_USDC: "sse-key-for-deep-usdc",
  },
});

const sub = client.subscribeTrades("SUI_USDC", (event) => {
  console.log(event.pool, event.event, event.data);
});

sub.stop();
```

Options:

```ts
const sub = client.subscribeTrades("SUI_USDC", callback, {
  kind: "deepbook",         // "deepbook" (default) | "deepbook-margin"
  reconnect: true,          // auto-reconnect on error (default: true)
  reconnectDelayMs: 1000,   // delay between reconnects in ms (default: 1000)
  onError: (err) => console.error(err.message),
});
```

## Architecture

All methods live on `SurfluxClient`. Internally, `DeepBookClient`, `MarginClient`, and `NftClient` are private implementation layers — they can be imported and composed directly for advanced use cases:

```ts
import { DeepBookClient, NftClient, RestClient } from "@mcxross/surflux";

const rest = new RestClient({ baseUrl: "https://api.surflux.dev", apiKey: "key" });
const db   = new DeepBookClient(rest);
```

Adding a new endpoint:
1. Add the method to the relevant domain class (`deepbook.ts`, `nft.ts`, …)
2. Add one delegation line in `client.ts`

## Building

```sh
npm run build     # compile to dist/
npm test          # run all tests
npm run typecheck
```
