@pear-protocol/market-sdk 0.0.14 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +27 -0
  2. package/dist/chart/cache/index.d.ts +1 -1
  3. package/dist/chart/chart.d.ts +1 -1
  4. package/dist/chart/collector/binance.d.ts +1 -1
  5. package/dist/chart/collector/bybit.d.ts +1 -1
  6. package/dist/chart/collector/helpers.d.ts +2 -2
  7. package/dist/chart/collector/helpers.js +2 -2
  8. package/dist/chart/collector/hyperliquid.d.ts +1 -1
  9. package/dist/chart/collector/index.d.ts +1 -1
  10. package/dist/chart/collector/index.js +2 -1
  11. package/dist/chart/collector/lighter.d.ts +2 -2
  12. package/dist/chart/collector/lighter.js +6 -2
  13. package/dist/chart/collector/okx.d.ts +1 -1
  14. package/dist/chart/compute/asset.d.ts +1 -1
  15. package/dist/chart/compute/index.d.ts +1 -1
  16. package/dist/chart/compute/performance.d.ts +1 -1
  17. package/dist/chart/compute/price-ratio.d.ts +1 -1
  18. package/dist/chart/compute/weighted-ratio.d.ts +1 -1
  19. package/dist/chart/types.d.ts +1 -1
  20. package/dist/chart/utils.d.ts +1 -1
  21. package/dist/chart/ws/lighter.js +9 -1
  22. package/dist/funding-rate/fetcher/binance.d.ts +1 -1
  23. package/dist/funding-rate/fetcher/bybit.d.ts +1 -1
  24. package/dist/funding-rate/fetcher/http-client.d.ts +1 -1
  25. package/dist/funding-rate/fetcher/http-client.js +4 -2
  26. package/dist/funding-rate/fetcher/hyperliquid.d.ts +1 -1
  27. package/dist/funding-rate/fetcher/index.d.ts +2 -2
  28. package/dist/funding-rate/fetcher/index.js +2 -2
  29. package/dist/funding-rate/fetcher/lighter.d.ts +2 -2
  30. package/dist/funding-rate/fetcher/lighter.js +4 -2
  31. package/dist/funding-rate/fetcher/okx.d.ts +1 -1
  32. package/dist/funding-rate/funding-rate.d.ts +1 -1
  33. package/dist/funding-rate/funding-rate.js +2 -1
  34. package/dist/funding-rate/types.d.ts +1 -1
  35. package/dist/funding-rate/utils.d.ts +1 -1
  36. package/dist/index.d.ts +2 -2
  37. package/dist/orderbook/book/aggregate.d.ts +1 -1
  38. package/dist/orderbook/book/local-book.d.ts +1 -1
  39. package/dist/orderbook/orderbook.d.ts +1 -1
  40. package/dist/orderbook/types.d.ts +1 -1
  41. package/dist/orderbook/utils.d.ts +1 -1
  42. package/dist/orderbook/ws/lighter.js +9 -1
  43. package/dist/shared/types.d.ts +6 -1
  44. package/dist/transport/base-transport.d.ts +4 -0
  45. package/dist/transport/base-transport.js +8 -0
  46. package/dist/transport/index.d.ts +11 -3
  47. package/dist/transport/index.js +2 -2
  48. package/dist/transport/lighter.d.ts +31 -1
  49. package/dist/transport/lighter.js +78 -0
  50. package/package.json +5 -3
package/README.md CHANGED
@@ -70,6 +70,33 @@ orderbook.destroy();
70
70
  transport.destroy();
71
71
  ```
72
72
 
73
+ ## Transport
74
+
75
+ `CreateTransport(connector)` builds the connection every feature shares. Pass it to `Chart`,
76
+ `Orderbook`, and `FundingRate`, then `destroy()` it once when you are done.
77
+
78
+ ### Lighter rate limits
79
+
80
+ Lighter grants a wider rate limit to requests it can attribute to an account, on public market data
81
+ as well as private endpoints. Supply a token provider and this SDK sends it on Lighter's candle and
82
+ funding reads (`authorization` header) and on its candle and order-book subscriptions (`auth` field):
83
+
84
+ ```typescript
85
+ import { CreateTransport } from '@pear-protocol/market-sdk';
86
+ import { retrieveLighterAuthToken } from '@pear-protocol/exchanges-sdk';
87
+
88
+ const transport = CreateTransport('lighter', {
89
+ authToken: () => retrieveLighterAuthToken(sdk, credentials, false),
90
+ });
91
+ ```
92
+
93
+ This SDK never holds Lighter credentials — the caller mints the token and owns its cache.
94
+ `retrieveLighterAuthToken` is the same cache the account trackers use, so both SDKs share one token.
95
+
96
+ Everything is optional. Omit `authToken`, or resolve `undefined` for a visitor with no connected
97
+ account, and every request goes out anonymously. A failed mint logs a warning and falls back to
98
+ anonymous rather than breaking the market data.
99
+
73
100
  ## Chart
74
101
 
75
102
  ### Initialization
@@ -1,9 +1,9 @@
1
1
  import { CandleInterval, CandleData, HistoricalRange } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare class CandleCache {
9
9
  private historicalPriceData;
@@ -1,9 +1,9 @@
1
1
  import { ChartConfig, TokenSelection, CandleInterval, ChartType, Bar, RealtimeBarCallback } from './types.js';
2
2
  import '../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../shared/types.js';
4
5
  import '../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../shared/types.js';
7
7
 
8
8
  declare class Chart {
9
9
  private collector;
@@ -1,9 +1,9 @@
1
1
  import { CandleInterval, CandleData } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function fetchHistoricalCandles(symbol: string, startTime: number, endTime: number, interval: CandleInterval): Promise<CandleData[]>;
9
9
 
@@ -1,9 +1,9 @@
1
1
  import { CandleInterval, CandleData } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function fetchHistoricalCandles(symbol: string, startTime: number, endTime: number, interval: CandleInterval): Promise<CandleData[]>;
9
9
 
@@ -1,10 +1,10 @@
1
1
  import { Connector } from '@pear-protocol/types';
2
2
  import { CandleInterval, CandleData } from '../types.js';
3
3
  import '../../transport/index.js';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
- declare function fetchHistoricalCandles(connector: Connector, symbol: string, startTime: number, endTime: number, interval: CandleInterval): Promise<CandleData[]>;
8
+ declare function fetchHistoricalCandles(connector: Connector, symbol: string, startTime: number, endTime: number, interval: CandleInterval, authToken?: string): Promise<CandleData[]>;
9
9
 
10
10
  export { fetchHistoricalCandles };
@@ -6,7 +6,7 @@ import { fetchHistoricalCandles as fetchHistoricalCandles$2 } from './okx';
6
6
 
7
7
  var __defProp = Object.defineProperty;
8
8
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
- async function fetchHistoricalCandles(connector, symbol, startTime, endTime, interval) {
9
+ async function fetchHistoricalCandles(connector, symbol, startTime, endTime, interval, authToken) {
10
10
  switch (connector) {
11
11
  case "hyperliquid":
12
12
  return fetchHistoricalCandles$5(symbol, startTime, endTime, interval);
@@ -17,7 +17,7 @@ async function fetchHistoricalCandles(connector, symbol, startTime, endTime, int
17
17
  case "okx":
18
18
  return fetchHistoricalCandles$2(symbol, startTime, endTime, interval);
19
19
  case "lighter":
20
- return fetchHistoricalCandles$1(symbol, startTime, endTime, interval);
20
+ return fetchHistoricalCandles$1(symbol, startTime, endTime, interval, authToken);
21
21
  default:
22
22
  throw new Error(`Unsupported connector: ${connector}`);
23
23
  }
@@ -1,9 +1,9 @@
1
1
  import { CandleInterval, CandleData } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function fetchHistoricalCandles(symbol: string, startTime: number, endTime: number, interval: CandleInterval): Promise<CandleData[]>;
9
9
 
@@ -1,9 +1,9 @@
1
1
  import { ChartConfig, TokenSelection, CandleInterval, RealtimeCandleCallback, CandleData } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare class DataCollector {
9
9
  private transport;
@@ -127,10 +127,11 @@ class DataCollector {
127
127
  for (const token of tokensToFetch) {
128
128
  this.cache.addLoadingToken(token.symbol);
129
129
  }
130
+ const authToken = await this.transport.retrieveAuthToken();
130
131
  try {
131
132
  const fetchPromises = tokensToFetch.map(async (token) => {
132
133
  try {
133
- const candles = await fetchHistoricalCandles(this.transport.connector, token.symbol, startTime, endTime, interval);
134
+ const candles = await fetchHistoricalCandles(this.transport.connector, token.symbol, startTime, endTime, interval, authToken);
134
135
  this.cache.addHistoricalPriceData(token.symbol, interval, candles, {
135
136
  start: startTime,
136
137
  end: endTime
@@ -1,10 +1,10 @@
1
1
  import { CandleInterval, CandleData } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
- declare function fetchHistoricalCandles(symbol: string, startTime: number, endTime: number, interval: CandleInterval): Promise<CandleData[]>;
8
+ declare function fetchHistoricalCandles(symbol: string, startTime: number, endTime: number, interval: CandleInterval, authToken?: string): Promise<CandleData[]>;
9
9
 
10
10
  export { fetchHistoricalCandles };
@@ -14,7 +14,7 @@ const RESOLUTION_MAP = {
14
14
  "12h": "12h",
15
15
  "1d": "1d"
16
16
  };
17
- async function fetchHistoricalCandles(symbol, startTime, endTime, interval) {
17
+ async function fetchHistoricalCandles(symbol, startTime, endTime, interval, authToken) {
18
18
  const resolution = RESOLUTION_MAP[interval];
19
19
  if (!resolution) throw new Error(`Lighter does not support the '${interval}' interval`);
20
20
  const intervalMs = getIntervalSeconds(interval) * 1e3;
@@ -26,7 +26,11 @@ async function fetchHistoricalCandles(symbol, startTime, endTime, interval) {
26
26
  end_timestamp: String(endTime),
27
27
  count_back: String(countBack)
28
28
  });
29
- const response = await fetch(`${BASE_URL}/api/v1/candles?${params}`);
29
+ const response = await fetch(`${BASE_URL}/api/v1/candles?${params}`, authToken ? {
30
+ headers: {
31
+ authorization: authToken
32
+ }
33
+ } : void 0);
30
34
  if (!response.ok) throw new Error(`Lighter API error: ${response.status} ${response.statusText}`);
31
35
  const data = await response.json();
32
36
  if (data.code !== 200) throw new Error(`Lighter API error: ${data.message ?? String(data.code)}`);
@@ -1,9 +1,9 @@
1
1
  import { CandleInterval, CandleData } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function fetchHistoricalCandles(instId: string, startTime: number, endTime: number, interval: CandleInterval): Promise<CandleData[]>;
9
9
 
@@ -1,9 +1,9 @@
1
1
  import { CandleData, Bar } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function computeAssetBars(tokenCandles: Record<string, CandleData[]>, symbol: string): Bar[];
9
9
  declare function computeRealtimeAssetBar(snapshot: Record<string, CandleData>, symbol: string): Bar | null;
@@ -5,6 +5,6 @@ export { computeRealtimeWeightedRatioBar, computeWeightedRatioCandles } from './
5
5
  import '../types.js';
6
6
  import '../../transport/index.js';
7
7
  import '@pear-protocol/types';
8
+ import '../../shared/types.js';
8
9
  import '../../transport/base-transport.js';
9
10
  import 'partysocket';
10
- import '../../shared/types.js';
@@ -1,9 +1,9 @@
1
1
  import { TokenSelection, CandleData, PerformanceResult, Bar } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function computePerformanceCandles(longTokens: TokenSelection[], shortTokens: TokenSelection[], tokenCandles: Record<string, CandleData[]>): PerformanceResult;
9
9
  declare function computeRealtimePerformanceBar(longTokens: TokenSelection[], shortTokens: TokenSelection[], snapshot: Record<string, CandleData>, baselinePrices: Record<string, number>): Bar | null;
@@ -1,9 +1,9 @@
1
1
  import { TokenSelection, CandleData, Bar } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function computePriceRatioCandles(longTokens: TokenSelection[], shortTokens: TokenSelection[], tokenCandles: Record<string, CandleData[]>): Bar[];
9
9
  declare function computeRealtimePriceRatioBar(longTokens: TokenSelection[], shortTokens: TokenSelection[], snapshot: Record<string, CandleData>): Bar | null;
@@ -1,9 +1,9 @@
1
1
  import { TokenSelection, CandleData, Bar } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function computeWeightedRatioCandles(longTokens: TokenSelection[], shortTokens: TokenSelection[], tokenCandles: Record<string, CandleData[]>): Bar[];
9
9
  declare function computeRealtimeWeightedRatioBar(longTokens: TokenSelection[], shortTokens: TokenSelection[], snapshot: Record<string, CandleData>): Bar | null;
@@ -1,8 +1,8 @@
1
1
  import { Transport } from '../transport/index.js';
2
2
  import '@pear-protocol/types';
3
+ import '../shared/types.js';
3
4
  import '../transport/base-transport.js';
4
5
  import 'partysocket';
5
- import '../shared/types.js';
6
6
 
7
7
  interface TokenSelection {
8
8
  symbol: string;
@@ -1,9 +1,9 @@
1
1
  import { CandleData, CandleInterval, HistoricalRange } from './types.js';
2
2
  import '../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../shared/types.js';
4
5
  import '../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../shared/types.js';
7
7
 
8
8
  declare const createKey: (symbol: string, interval: CandleInterval) => string;
9
9
  declare const getIntervalSeconds: (interval: CandleInterval) => number;
@@ -19,9 +19,17 @@ class LighterCandleWs extends BaseCandleWs {
19
19
  }
20
20
  /** Subscribes to a market's candle stream; `symbol` is Lighter's numeric market id. */
21
21
  buildSubscribeMessage(symbol, interval) {
22
+ const authToken = this.transport.authToken;
23
+ if (!authToken) {
24
+ return {
25
+ type: "subscribe",
26
+ channel: `candle/${symbol}/${interval}`
27
+ };
28
+ }
22
29
  return {
23
30
  type: "subscribe",
24
- channel: `candle/${symbol}/${interval}`
31
+ channel: `candle/${symbol}/${interval}`,
32
+ auth: authToken
25
33
  };
26
34
  }
27
35
  /** Mirrors the subscribe channel — Lighter keys unsubscribes by the same slash-delimited name. */
@@ -1,9 +1,9 @@
1
1
  import { FundingRateEntry } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function fetchHistoricalFundingRates(symbol: string, startTime: number, endTime: number): Promise<FundingRateEntry[]>;
9
9
 
@@ -1,9 +1,9 @@
1
1
  import { FundingRateEntry } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function fetchHistoricalFundingRates(symbol: string, startTime: number, endTime: number): Promise<FundingRateEntry[]>;
9
9
 
@@ -1,5 +1,5 @@
1
1
  type ResponseValidator<T> = (data: T) => string | undefined;
2
- declare function httpGet<T>(url: string, params: Record<string, string>, validate?: ResponseValidator<T>): Promise<T>;
2
+ declare function httpGet<T>(url: string, params: Record<string, string>, validate?: ResponseValidator<T>, headers?: Record<string, string>): Promise<T>;
3
3
  declare function httpPost<T>(url: string, body: unknown, validate?: ResponseValidator<T>): Promise<T>;
4
4
 
5
5
  export { type ResponseValidator, httpGet, httpPost };
@@ -2,9 +2,11 @@ var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
  const BASE_DELAY_MS = 1e3;
4
4
  const MAX_DELAY_MS = 6e4;
5
- async function httpGet(url, params, validate) {
5
+ async function httpGet(url, params, validate, headers) {
6
6
  const qs = new URLSearchParams(params).toString();
7
- return httpFetch(`${url}?${qs}`, void 0, validate);
7
+ return httpFetch(`${url}?${qs}`, headers ? {
8
+ headers
9
+ } : void 0, validate);
8
10
  }
9
11
  __name(httpGet, "httpGet");
10
12
  async function httpPost(url, body, validate) {
@@ -1,9 +1,9 @@
1
1
  import { FundingRateEntry } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function fetchHistoricalFundingRates(symbol: string, startTime: number, endTime: number): Promise<FundingRateEntry[]>;
9
9
 
@@ -1,10 +1,10 @@
1
1
  import { Connector } from '@pear-protocol/types';
2
2
  import { FundingRateDuration, FundingRateEntry } from '../types.js';
3
3
  import '../../transport/index.js';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
- declare function fetchHistoricalFundingRates(connector: Connector, symbol: string, startTime: number, endTime: number, duration: FundingRateDuration): Promise<FundingRateEntry[]>;
8
+ declare function fetchHistoricalFundingRates(connector: Connector, symbol: string, startTime: number, endTime: number, duration: FundingRateDuration, authToken?: string): Promise<FundingRateEntry[]>;
9
9
 
10
10
  export { fetchHistoricalFundingRates };
@@ -6,7 +6,7 @@ import { fetchHistoricalFundingRates as fetchHistoricalFundingRates$2 } from './
6
6
 
7
7
  var __defProp = Object.defineProperty;
8
8
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
- async function fetchHistoricalFundingRates(connector, symbol, startTime, endTime, duration) {
9
+ async function fetchHistoricalFundingRates(connector, symbol, startTime, endTime, duration, authToken) {
10
10
  switch (connector) {
11
11
  case "hyperliquid":
12
12
  return fetchHistoricalFundingRates$5(symbol, startTime, endTime);
@@ -17,7 +17,7 @@ async function fetchHistoricalFundingRates(connector, symbol, startTime, endTime
17
17
  case "okx":
18
18
  return fetchHistoricalFundingRates$2(symbol, startTime, endTime);
19
19
  case "lighter":
20
- return fetchHistoricalFundingRates$1(symbol, startTime, endTime, duration);
20
+ return fetchHistoricalFundingRates$1(symbol, startTime, endTime, duration, authToken);
21
21
  default:
22
22
  throw new Error(`Unsupported connector: ${connector}`);
23
23
  }
@@ -1,10 +1,10 @@
1
1
  import { FundingRateDuration, FundingRateEntry } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
- declare function fetchHistoricalFundingRates(symbol: string, startTime: number, endTime: number, _duration: FundingRateDuration): Promise<FundingRateEntry[]>;
8
+ declare function fetchHistoricalFundingRates(symbol: string, startTime: number, endTime: number, _duration: FundingRateDuration, authToken?: string): Promise<FundingRateEntry[]>;
9
9
 
10
10
  export { fetchHistoricalFundingRates };
@@ -5,7 +5,7 @@ var __defProp = Object.defineProperty;
5
5
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
6
  const BASE_URL = "https://mainnet.zklighter.elliot.ai";
7
7
  const MAX_LIMIT = 500;
8
- async function fetchHistoricalFundingRates(symbol, startTime, endTime, _duration) {
8
+ async function fetchHistoricalFundingRates(symbol, startTime, endTime, _duration, authToken) {
9
9
  const intervalMs = 60 * 60 * 1e3;
10
10
  const allRates = [];
11
11
  let cursor = startTime;
@@ -17,7 +17,9 @@ async function fetchHistoricalFundingRates(symbol, startTime, endTime, _duration
17
17
  start_timestamp: String(cursor),
18
18
  end_timestamp: String(endTime),
19
19
  count_back: String(countBack)
20
- });
20
+ }, void 0, authToken ? {
21
+ authorization: authToken
22
+ } : void 0);
21
23
  const entries = data.fundings ?? [];
22
24
  if (entries.length === 0) break;
23
25
  for (const entry of entries) {
@@ -1,9 +1,9 @@
1
1
  import { FundingRateEntry } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  declare function fetchHistoricalFundingRates(instId: string, startTime: number, endTime: number): Promise<FundingRateEntry[]>;
9
9
 
@@ -1,9 +1,9 @@
1
1
  import { FundingRateConfig, TokenSelection, FundingRateAggregation, FundingRateDuration, FundingRateEntry } from './types.js';
2
2
  import '../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../shared/types.js';
4
5
  import '../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../shared/types.js';
7
7
 
8
8
  declare class FundingRate {
9
9
  private transport;
@@ -88,12 +88,13 @@ class FundingRate {
88
88
  }
89
89
  async refetch(tokens, start, end, duration) {
90
90
  if (tokens.length === 0) return;
91
+ const authToken = await this.transport.retrieveAuthToken();
91
92
  await Promise.all(tokens.map(async (token) => {
92
93
  const existing = this.cache[token.symbol];
93
94
  const fetchStart = existing ? Math.min(start, existing.start) : start;
94
95
  const fetchEnd = existing ? Math.max(end, existing.end) : end;
95
96
  try {
96
- const rates = await fetchHistoricalFundingRates(this.transport.connector, token.symbol, fetchStart, fetchEnd, duration);
97
+ const rates = await fetchHistoricalFundingRates(this.transport.connector, token.symbol, fetchStart, fetchEnd, duration, authToken);
97
98
  this.cache[token.symbol] = {
98
99
  entries: rates,
99
100
  start: fetchStart,
@@ -1,8 +1,8 @@
1
1
  import { Transport } from '../transport/index.js';
2
2
  import '@pear-protocol/types';
3
+ import '../shared/types.js';
3
4
  import '../transport/base-transport.js';
4
5
  import 'partysocket';
5
- import '../shared/types.js';
6
6
 
7
7
  interface TokenSelection {
8
8
  symbol: string;
@@ -1,9 +1,9 @@
1
1
  import { FundingRateEntry, FundingRateAggregation, TokenSelection, FundingRateDuration } from './types.js';
2
2
  import '../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../shared/types.js';
4
5
  import '../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../shared/types.js';
7
7
 
8
8
  declare function computeStartTime(endTime: number, duration: FundingRateDuration): number;
9
9
  declare function aggregateRates(rawRates: FundingRateEntry[], aggregation: FundingRateAggregation): FundingRateEntry[];
package/dist/index.d.ts CHANGED
@@ -5,8 +5,8 @@ export { FundingRateAggregation, FundingRateConfig, FundingRateDuration, Funding
5
5
  export { Orderbook } from './orderbook/orderbook.js';
6
6
  export { AggregationConfig, BBO, CexAggregationConfig, HyperliquidAggregationConfig, OrderbookCallback, OrderbookConfig, OrderbookLevel, OrderbookSnapshot } from './orderbook/types.js';
7
7
  export { getAvailableAggregations } from './orderbook/utils.js';
8
- export { CreateTransport, Transport } from './transport/index.js';
8
+ export { AuthTokenProvider } from './shared/types.js';
9
+ export { CreateTransport, Transport, TransportOptions } from './transport/index.js';
9
10
  export { BaseTransport } from './transport/base-transport.js';
10
11
  import '@pear-protocol/types';
11
12
  import 'partysocket';
12
- import './shared/types.js';
@@ -2,9 +2,9 @@ import { OrderbookLevel } from '../types.js';
2
2
  import { LocalBook } from './local-book.js';
3
3
  import '../../transport/index.js';
4
4
  import '@pear-protocol/types';
5
+ import '../../shared/types.js';
5
6
  import '../../transport/base-transport.js';
6
7
  import 'partysocket';
7
- import '../../shared/types.js';
8
8
 
9
9
  /**
10
10
  * Pure aggregation of a LocalBook into top-N bid/ask buckets at the given
@@ -1,9 +1,9 @@
1
1
  import { BBO } from '../types.js';
2
2
  import '../../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../../shared/types.js';
4
5
  import '../../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../../shared/types.js';
7
7
 
8
8
  type Level = readonly [price: string, size: number];
9
9
  declare class LocalBook {
@@ -1,9 +1,9 @@
1
1
  import { OrderbookConfig, OrderbookCallback, OrderbookSnapshot, BBO } from './types.js';
2
2
  import '../transport/index.js';
3
3
  import '@pear-protocol/types';
4
+ import '../shared/types.js';
4
5
  import '../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../shared/types.js';
7
7
 
8
8
  /**
9
9
  * Orderbook exposes an aggregated top-of-book view for a single symbol.
@@ -1,8 +1,8 @@
1
1
  import { Transport } from '../transport/index.js';
2
2
  import '@pear-protocol/types';
3
+ import '../shared/types.js';
3
4
  import '../transport/base-transport.js';
4
5
  import 'partysocket';
5
- import '../shared/types.js';
6
6
 
7
7
  declare const DEFAULT_DEPTH = 10;
8
8
  declare const DEFAULT_MULTIPLIERS: number[];
@@ -1,9 +1,9 @@
1
1
  import { Connector } from '@pear-protocol/types';
2
2
  import { AggregationConfig } from './types.js';
3
3
  import '../transport/index.js';
4
+ import '../shared/types.js';
4
5
  import '../transport/base-transport.js';
5
6
  import 'partysocket';
6
- import '../shared/types.js';
7
7
 
8
8
  declare function getCexAvailableAggregations(tickSize: number, midPrice: number, multipliers?: number[]): number[];
9
9
  declare function getHyperliquidAvailableAggregations(maxDecimals: number, midPrice: number, multipliers?: number[]): number[];
@@ -10,9 +10,17 @@ class LighterDepthWs extends BaseDepthWs {
10
10
  lastNonce = /* @__PURE__ */ new Map();
11
11
  resetListenerId = null;
12
12
  buildSubscribeMessage(symbol) {
13
+ const authToken = this.transport.authToken;
14
+ if (!authToken) {
15
+ return {
16
+ type: "subscribe",
17
+ channel: `order_book@tier2/${symbol}`
18
+ };
19
+ }
13
20
  return {
14
21
  type: "subscribe",
15
- channel: `order_book@tier2/${symbol}`
22
+ channel: `order_book@tier2/${symbol}`,
23
+ auth: authToken
16
24
  };
17
25
  }
18
26
  buildUnsubscribeMessage(symbol) {
@@ -2,5 +2,10 @@ interface WsMessage {
2
2
  [key: string]: unknown;
3
3
  }
4
4
  type MessageListener = (data: string) => void;
5
+ /**
6
+ * Mints the identity a venue rate-limits by. Supplied by the caller, which owns the credentials and
7
+ * the token cache; resolving `undefined` keeps the traffic anonymous.
8
+ */
9
+ type AuthTokenProvider = () => Promise<string | undefined>;
5
10
 
6
- export type { MessageListener, WsMessage };
11
+ export type { AuthTokenProvider, MessageListener, WsMessage };
@@ -15,6 +15,10 @@ declare abstract class BaseTransport {
15
15
  connect(): void;
16
16
  disconnect(): void;
17
17
  get connected(): boolean;
18
+ /** The identity already in hand, for venues that widen rate limits for a known account. */
19
+ get authToken(): string | undefined;
20
+ /** Resolves a live identity for the next request; a venue without one stays anonymous. */
21
+ retrieveAuthToken(): Promise<string | undefined>;
18
22
  send(msg: WsMessage | string): void;
19
23
  addMessageListener(listener: MessageListener): string;
20
24
  removeMessageListener(id: string): void;
@@ -55,6 +55,14 @@ class BaseTransport {
55
55
  get connected() {
56
56
  return this.ws?.readyState === WebSocket.OPEN;
57
57
  }
58
+ /** The identity already in hand, for venues that widen rate limits for a known account. */
59
+ get authToken() {
60
+ return void 0;
61
+ }
62
+ /** Resolves a live identity for the next request; a venue without one stays anonymous. */
63
+ retrieveAuthToken() {
64
+ return Promise.resolve(void 0);
65
+ }
58
66
  send(msg) {
59
67
  if (this.ws?.readyState === WebSocket.OPEN) {
60
68
  this.ws.send(typeof msg === "string" ? msg : JSON.stringify(msg));
@@ -1,10 +1,18 @@
1
1
  import { Connector } from '@pear-protocol/types';
2
+ import { AuthTokenProvider } from '../shared/types.js';
2
3
  import { BaseTransport } from './base-transport.js';
3
4
  import 'partysocket';
4
- import '../shared/types.js';
5
5
 
6
6
  type Transport = BaseTransport;
7
7
 
8
- declare function CreateTransport(connector: Connector): Transport;
8
+ interface TransportOptions {
9
+ /**
10
+ * Mints the token that attributes this transport's traffic to a connected account. Only Lighter
11
+ * reads it today, where an authenticated request earns a wider rate limit on public market data.
12
+ * Omit it — or resolve `undefined` — to stay anonymous.
13
+ */
14
+ authToken?: AuthTokenProvider;
15
+ }
16
+ declare function CreateTransport(connector: Connector, options?: TransportOptions): Transport;
9
17
 
10
- export { BaseTransport, CreateTransport, type Transport };
18
+ export { BaseTransport, CreateTransport, type Transport, type TransportOptions };
@@ -7,7 +7,7 @@ import { OkxTransport } from './okx';
7
7
 
8
8
  var __defProp = Object.defineProperty;
9
9
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
10
- function CreateTransport(connector) {
10
+ function CreateTransport(connector, options) {
11
11
  switch (connector) {
12
12
  case "binance":
13
13
  return new BinanceTransport();
@@ -18,7 +18,7 @@ function CreateTransport(connector) {
18
18
  case "hyperliquid":
19
19
  return new HyperliquidTransport();
20
20
  case "lighter":
21
- return new LighterTransport();
21
+ return new LighterTransport(options?.authToken);
22
22
  default: {
23
23
  const _exhaustive = connector;
24
24
  throw new Error(`Unsupported connector: ${String(_exhaustive)}`);
@@ -1,13 +1,43 @@
1
1
  import { Connector } from '@pear-protocol/types';
2
- import { WsMessage } from '../shared/types.js';
2
+ import { AuthTokenProvider, WsMessage } from '../shared/types.js';
3
3
  import { BaseTransport } from './base-transport.js';
4
4
  import 'partysocket';
5
5
 
6
+ /**
7
+ * Lighter's transport carries the connected account's identity alongside the socket, because the
8
+ * venue widens rate limits for authenticated traffic on otherwise public market data. The token is
9
+ * supplied by the caller — this package never holds Lighter credentials.
10
+ */
11
+
6
12
  declare class LighterTransport extends BaseTransport {
7
13
  readonly connector: Connector;
14
+ private readonly authTokenProvider;
15
+ private cachedAuthToken;
16
+ private authRefreshTimer;
17
+ private mintInFlight;
18
+ private wantsConnection;
19
+ /** Takes the caller's minter; without one this transport stays anonymous for its whole life. */
20
+ constructor(authTokenProvider?: AuthTokenProvider);
21
+ /** Holds the socket until a first token lands, so the opening subscriptions carry it. */
22
+ connect(): void;
23
+ /** Tears the socket down and drops the identity that belonged to it. */
24
+ disconnect(): void;
25
+ /** Exposes the cached token to the subscription frames, which are built synchronously. */
26
+ get authToken(): string | undefined;
27
+ /** Refreshes the cached token; the caller's provider owns expiry and request coalescing. */
28
+ retrieveAuthToken(): Promise<string | undefined>;
29
+ /** The venue's public market-data stream, which serves both authenticated and anonymous traffic. */
8
30
  protected getWsUrl(): string;
31
+ /** How often the socket must speak to stay open. */
9
32
  protected getPingIntervalMs(): number;
33
+ /** The keep-alive frame the venue expects. */
10
34
  protected buildPingMessage(): WsMessage;
35
+ /** Opens the socket and keeps the token fresh for as long as it stays open. */
36
+ private openSocket;
37
+ /** Re-mints the cached token on a timer, because reconnects resubscribe without warning. */
38
+ private startAuthRefresh;
39
+ /** Stops the re-minting timer, so a closed socket costs nothing. */
40
+ private stopAuthRefresh;
11
41
  }
12
42
 
13
43
  export { LighterTransport };
@@ -2,22 +2,100 @@ import { BaseTransport } from './base-transport';
2
2
 
3
3
  var __defProp = Object.defineProperty;
4
4
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
5
+ const AUTH_REFRESH_INTERVAL_MS = 6e4;
5
6
  class LighterTransport extends BaseTransport {
6
7
  static {
7
8
  __name(this, "LighterTransport");
8
9
  }
9
10
  connector = "lighter";
11
+ authTokenProvider;
12
+ cachedAuthToken;
13
+ authRefreshTimer = null;
14
+ mintInFlight = false;
15
+ wantsConnection = false;
16
+ /** Takes the caller's minter; without one this transport stays anonymous for its whole life. */
17
+ constructor(authTokenProvider) {
18
+ super();
19
+ this.authTokenProvider = authTokenProvider;
20
+ }
21
+ /** Holds the socket until a first token lands, so the opening subscriptions carry it. */
22
+ connect() {
23
+ this.wantsConnection = true;
24
+ if (!this.authTokenProvider || this.cachedAuthToken) {
25
+ this.openSocket();
26
+ return;
27
+ }
28
+ if (this.mintInFlight) {
29
+ return;
30
+ }
31
+ this.mintInFlight = true;
32
+ void this.retrieveAuthToken().then(() => {
33
+ this.mintInFlight = false;
34
+ if (!this.wantsConnection) {
35
+ this.cachedAuthToken = void 0;
36
+ return;
37
+ }
38
+ this.openSocket();
39
+ });
40
+ }
41
+ /** Tears the socket down and drops the identity that belonged to it. */
42
+ disconnect() {
43
+ this.wantsConnection = false;
44
+ this.stopAuthRefresh();
45
+ this.cachedAuthToken = void 0;
46
+ super.disconnect();
47
+ }
48
+ /** Exposes the cached token to the subscription frames, which are built synchronously. */
49
+ get authToken() {
50
+ return this.cachedAuthToken;
51
+ }
52
+ /** Refreshes the cached token; the caller's provider owns expiry and request coalescing. */
53
+ async retrieveAuthToken() {
54
+ if (!this.authTokenProvider) {
55
+ return void 0;
56
+ }
57
+ try {
58
+ this.cachedAuthToken = await this.authTokenProvider();
59
+ } catch (error) {
60
+ console.warn("Failed to mint Lighter auth token, keeping the identity already in hand", error);
61
+ }
62
+ return this.cachedAuthToken;
63
+ }
64
+ /** The venue's public market-data stream, which serves both authenticated and anonymous traffic. */
10
65
  getWsUrl() {
11
66
  return "wss://mainnet.zklighter.elliot.ai/stream";
12
67
  }
68
+ /** How often the socket must speak to stay open. */
13
69
  getPingIntervalMs() {
14
70
  return 6e4;
15
71
  }
72
+ /** The keep-alive frame the venue expects. */
16
73
  buildPingMessage() {
17
74
  return {
18
75
  type: "ping"
19
76
  };
20
77
  }
78
+ /** Opens the socket and keeps the token fresh for as long as it stays open. */
79
+ openSocket() {
80
+ super.connect();
81
+ this.startAuthRefresh();
82
+ }
83
+ /** Re-mints the cached token on a timer, because reconnects resubscribe without warning. */
84
+ startAuthRefresh() {
85
+ if (!this.authTokenProvider || this.authRefreshTimer) {
86
+ return;
87
+ }
88
+ this.authRefreshTimer = setInterval(() => {
89
+ void this.retrieveAuthToken();
90
+ }, AUTH_REFRESH_INTERVAL_MS);
91
+ }
92
+ /** Stops the re-minting timer, so a closed socket costs nothing. */
93
+ stopAuthRefresh() {
94
+ if (this.authRefreshTimer) {
95
+ clearInterval(this.authRefreshTimer);
96
+ this.authRefreshTimer = null;
97
+ }
98
+ }
21
99
  }
22
100
 
23
101
  export { LighterTransport };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/market-sdk",
3
- "version": "0.0.14",
3
+ "version": "0.1.0",
4
4
  "description": "Pear Protocol Market SDK",
5
5
  "private": false,
6
6
  "type": "module",
@@ -22,16 +22,18 @@
22
22
  "scripts": {
23
23
  "build": "tsup",
24
24
  "clean": "rm -rf dist .turbo",
25
+ "test": "vitest run",
25
26
  "typecheck": "tsc --noEmit"
26
27
  },
27
28
  "dependencies": {
28
- "@pear-protocol/types": "^1.26.0",
29
+ "@pear-protocol/types": "^1.28.0",
29
30
  "bignumber.js": "^9.1.2",
30
31
  "partysocket": "^1.0.3"
31
32
  },
32
33
  "devDependencies": {
33
34
  "@backend/typescript-config": "workspace:*",
34
35
  "tsup": "8.5.1",
35
- "typescript": "5.9.3"
36
+ "typescript": "5.9.3",
37
+ "vitest": "4.1.2"
36
38
  }
37
39
  }