@0xarchive/sdk 0.2.2 → 0.3.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.
package/dist/index.d.mts CHANGED
@@ -30,15 +30,17 @@ interface ApiResponse<T> {
30
30
  }
31
31
  /**
32
32
  * Pagination parameters for list endpoints
33
+ * @deprecated Use cursor-based pagination instead (CursorPaginationParams)
33
34
  */
34
35
  interface PaginationParams {
35
36
  /** Maximum number of results to return */
36
37
  limit?: number;
37
- /** Number of results to skip */
38
+ /** @deprecated Use cursor instead. Number of results to skip */
38
39
  offset?: number;
39
40
  }
40
41
  /**
41
42
  * Time range parameters for historical queries
43
+ * @deprecated Use CursorPaginationParams for better performance with large datasets
42
44
  */
43
45
  interface TimeRangeParams extends PaginationParams {
44
46
  /** Start timestamp (Unix ms or ISO string) - REQUIRED for history endpoints */
@@ -129,10 +131,43 @@ interface Trade {
129
131
  /** User's wallet address */
130
132
  user_address?: string;
131
133
  }
134
+ /**
135
+ * @deprecated Use GetTradesCursorParams instead for better performance with large datasets
136
+ */
132
137
  interface GetTradesParams extends TimeRangeParams {
133
138
  /** Filter by side */
134
139
  side?: TradeSide;
135
140
  }
141
+ /**
142
+ * Cursor-based pagination parameters for trades (recommended)
143
+ * More efficient than offset-based pagination for large datasets.
144
+ * The cursor is a timestamp - use the `nextCursor` from the response to get the next page.
145
+ */
146
+ interface CursorPaginationParams {
147
+ /** Start timestamp (Unix ms or ISO string) - REQUIRED */
148
+ start: number | string;
149
+ /** End timestamp (Unix ms or ISO string) - REQUIRED */
150
+ end: number | string;
151
+ /** Cursor from previous response's nextCursor (timestamp). If not provided, starts from the beginning of the range. */
152
+ cursor?: number | string;
153
+ /** Maximum number of results to return (default: 100, max: 1000) */
154
+ limit?: number;
155
+ }
156
+ /**
157
+ * Parameters for getting trades with cursor-based pagination (recommended)
158
+ */
159
+ interface GetTradesCursorParams extends CursorPaginationParams {
160
+ /** Filter by side */
161
+ side?: TradeSide;
162
+ }
163
+ /**
164
+ * Response with cursor for pagination
165
+ */
166
+ interface CursorResponse<T> {
167
+ data: T;
168
+ /** Cursor for next page (use as cursor parameter) */
169
+ nextCursor?: string;
170
+ }
136
171
  /** Instrument type */
137
172
  type InstrumentType = 'perp' | 'spot';
138
173
  /**
@@ -481,25 +516,60 @@ declare class OrderBookResource {
481
516
  * // Get recent trades
482
517
  * const trades = await client.trades.recent('BTC');
483
518
  *
484
- * // Get trade history with time range
485
- * const history = await client.trades.list('ETH', {
486
- * start: Date.now() - 3600000,
519
+ * // Get trade history with cursor-based pagination (recommended)
520
+ * let result = await client.trades.list('BTC', {
521
+ * start: Date.now() - 86400000,
487
522
  * end: Date.now(),
488
- * limit: 500
523
+ * limit: 1000
489
524
  * });
525
+ *
526
+ * // Get all pages
527
+ * const allTrades = [...result.data];
528
+ * while (result.nextCursor) {
529
+ * result = await client.trades.list('BTC', {
530
+ * start: Date.now() - 86400000,
531
+ * end: Date.now(),
532
+ * cursor: result.nextCursor,
533
+ * limit: 1000
534
+ * });
535
+ * allTrades.push(...result.data);
536
+ * }
490
537
  * ```
491
538
  */
492
539
  declare class TradesResource {
493
540
  private http;
494
541
  constructor(http: HttpClient);
495
542
  /**
496
- * Get trade history for a coin
543
+ * Get trade history for a coin using cursor-based pagination
544
+ *
545
+ * Uses cursor-based pagination by default, which is more efficient for large datasets.
546
+ * Use the `nextCursor` from the response as the `cursor` parameter to get the next page.
497
547
  *
498
548
  * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
499
- * @param params - Time range and pagination parameters (start is required)
500
- * @returns Array of trades
549
+ * @param params - Time range and cursor pagination parameters (start and end are required)
550
+ * @returns Object with trades array and nextCursor for pagination
551
+ *
552
+ * @example
553
+ * ```typescript
554
+ * // First page
555
+ * let result = await client.trades.list('BTC', {
556
+ * start: Date.now() - 86400000,
557
+ * end: Date.now(),
558
+ * limit: 1000
559
+ * });
560
+ *
561
+ * // Subsequent pages
562
+ * while (result.nextCursor) {
563
+ * result = await client.trades.list('BTC', {
564
+ * start: Date.now() - 86400000,
565
+ * end: Date.now(),
566
+ * cursor: result.nextCursor,
567
+ * limit: 1000
568
+ * });
569
+ * }
570
+ * ```
501
571
  */
502
- list(coin: string, params: GetTradesParams): Promise<Trade[]>;
572
+ list(coin: string, params: GetTradesCursorParams): Promise<CursorResponse<Trade[]>>;
503
573
  /**
504
574
  * Get most recent trades for a coin
505
575
  *
@@ -508,6 +578,26 @@ declare class TradesResource {
508
578
  * @returns Array of recent trades
509
579
  */
510
580
  recent(coin: string, limit?: number): Promise<Trade[]>;
581
+ /**
582
+ * Get trade history using cursor-based pagination (explicit endpoint)
583
+ *
584
+ * @deprecated Use `list()` instead - it now uses cursor-based pagination by default.
585
+ *
586
+ * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
587
+ * @param params - Cursor pagination parameters (start and end are required)
588
+ * @returns Object with trades array and nextCursor for pagination
589
+ */
590
+ listWithCursor(coin: string, params: GetTradesCursorParams): Promise<CursorResponse<Trade[]>>;
591
+ /**
592
+ * Get trade history using offset-based pagination
593
+ *
594
+ * @deprecated Use `list()` with cursor-based pagination instead for better performance.
595
+ *
596
+ * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
597
+ * @param params - Time range and offset pagination parameters
598
+ * @returns Array of trades (without cursor response wrapper)
599
+ */
600
+ listWithOffset(coin: string, params: GetTradesParams): Promise<Trade[]>;
511
601
  }
512
602
 
513
603
  /**
package/dist/index.d.ts CHANGED
@@ -30,15 +30,17 @@ interface ApiResponse<T> {
30
30
  }
31
31
  /**
32
32
  * Pagination parameters for list endpoints
33
+ * @deprecated Use cursor-based pagination instead (CursorPaginationParams)
33
34
  */
34
35
  interface PaginationParams {
35
36
  /** Maximum number of results to return */
36
37
  limit?: number;
37
- /** Number of results to skip */
38
+ /** @deprecated Use cursor instead. Number of results to skip */
38
39
  offset?: number;
39
40
  }
40
41
  /**
41
42
  * Time range parameters for historical queries
43
+ * @deprecated Use CursorPaginationParams for better performance with large datasets
42
44
  */
43
45
  interface TimeRangeParams extends PaginationParams {
44
46
  /** Start timestamp (Unix ms or ISO string) - REQUIRED for history endpoints */
@@ -129,10 +131,43 @@ interface Trade {
129
131
  /** User's wallet address */
130
132
  user_address?: string;
131
133
  }
134
+ /**
135
+ * @deprecated Use GetTradesCursorParams instead for better performance with large datasets
136
+ */
132
137
  interface GetTradesParams extends TimeRangeParams {
133
138
  /** Filter by side */
134
139
  side?: TradeSide;
135
140
  }
141
+ /**
142
+ * Cursor-based pagination parameters for trades (recommended)
143
+ * More efficient than offset-based pagination for large datasets.
144
+ * The cursor is a timestamp - use the `nextCursor` from the response to get the next page.
145
+ */
146
+ interface CursorPaginationParams {
147
+ /** Start timestamp (Unix ms or ISO string) - REQUIRED */
148
+ start: number | string;
149
+ /** End timestamp (Unix ms or ISO string) - REQUIRED */
150
+ end: number | string;
151
+ /** Cursor from previous response's nextCursor (timestamp). If not provided, starts from the beginning of the range. */
152
+ cursor?: number | string;
153
+ /** Maximum number of results to return (default: 100, max: 1000) */
154
+ limit?: number;
155
+ }
156
+ /**
157
+ * Parameters for getting trades with cursor-based pagination (recommended)
158
+ */
159
+ interface GetTradesCursorParams extends CursorPaginationParams {
160
+ /** Filter by side */
161
+ side?: TradeSide;
162
+ }
163
+ /**
164
+ * Response with cursor for pagination
165
+ */
166
+ interface CursorResponse<T> {
167
+ data: T;
168
+ /** Cursor for next page (use as cursor parameter) */
169
+ nextCursor?: string;
170
+ }
136
171
  /** Instrument type */
137
172
  type InstrumentType = 'perp' | 'spot';
138
173
  /**
@@ -481,25 +516,60 @@ declare class OrderBookResource {
481
516
  * // Get recent trades
482
517
  * const trades = await client.trades.recent('BTC');
483
518
  *
484
- * // Get trade history with time range
485
- * const history = await client.trades.list('ETH', {
486
- * start: Date.now() - 3600000,
519
+ * // Get trade history with cursor-based pagination (recommended)
520
+ * let result = await client.trades.list('BTC', {
521
+ * start: Date.now() - 86400000,
487
522
  * end: Date.now(),
488
- * limit: 500
523
+ * limit: 1000
489
524
  * });
525
+ *
526
+ * // Get all pages
527
+ * const allTrades = [...result.data];
528
+ * while (result.nextCursor) {
529
+ * result = await client.trades.list('BTC', {
530
+ * start: Date.now() - 86400000,
531
+ * end: Date.now(),
532
+ * cursor: result.nextCursor,
533
+ * limit: 1000
534
+ * });
535
+ * allTrades.push(...result.data);
536
+ * }
490
537
  * ```
491
538
  */
492
539
  declare class TradesResource {
493
540
  private http;
494
541
  constructor(http: HttpClient);
495
542
  /**
496
- * Get trade history for a coin
543
+ * Get trade history for a coin using cursor-based pagination
544
+ *
545
+ * Uses cursor-based pagination by default, which is more efficient for large datasets.
546
+ * Use the `nextCursor` from the response as the `cursor` parameter to get the next page.
497
547
  *
498
548
  * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
499
- * @param params - Time range and pagination parameters (start is required)
500
- * @returns Array of trades
549
+ * @param params - Time range and cursor pagination parameters (start and end are required)
550
+ * @returns Object with trades array and nextCursor for pagination
551
+ *
552
+ * @example
553
+ * ```typescript
554
+ * // First page
555
+ * let result = await client.trades.list('BTC', {
556
+ * start: Date.now() - 86400000,
557
+ * end: Date.now(),
558
+ * limit: 1000
559
+ * });
560
+ *
561
+ * // Subsequent pages
562
+ * while (result.nextCursor) {
563
+ * result = await client.trades.list('BTC', {
564
+ * start: Date.now() - 86400000,
565
+ * end: Date.now(),
566
+ * cursor: result.nextCursor,
567
+ * limit: 1000
568
+ * });
569
+ * }
570
+ * ```
501
571
  */
502
- list(coin: string, params: GetTradesParams): Promise<Trade[]>;
572
+ list(coin: string, params: GetTradesCursorParams): Promise<CursorResponse<Trade[]>>;
503
573
  /**
504
574
  * Get most recent trades for a coin
505
575
  *
@@ -508,6 +578,26 @@ declare class TradesResource {
508
578
  * @returns Array of recent trades
509
579
  */
510
580
  recent(coin: string, limit?: number): Promise<Trade[]>;
581
+ /**
582
+ * Get trade history using cursor-based pagination (explicit endpoint)
583
+ *
584
+ * @deprecated Use `list()` instead - it now uses cursor-based pagination by default.
585
+ *
586
+ * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
587
+ * @param params - Cursor pagination parameters (start and end are required)
588
+ * @returns Object with trades array and nextCursor for pagination
589
+ */
590
+ listWithCursor(coin: string, params: GetTradesCursorParams): Promise<CursorResponse<Trade[]>>;
591
+ /**
592
+ * Get trade history using offset-based pagination
593
+ *
594
+ * @deprecated Use `list()` with cursor-based pagination instead for better performance.
595
+ *
596
+ * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
597
+ * @param params - Time range and offset pagination parameters
598
+ * @returns Array of trades (without cursor response wrapper)
599
+ */
600
+ listWithOffset(coin: string, params: GetTradesParams): Promise<Trade[]>;
511
601
  }
512
602
 
513
603
  /**
package/dist/index.js CHANGED
@@ -140,18 +140,44 @@ var TradesResource = class {
140
140
  this.http = http;
141
141
  }
142
142
  /**
143
- * Get trade history for a coin
143
+ * Get trade history for a coin using cursor-based pagination
144
+ *
145
+ * Uses cursor-based pagination by default, which is more efficient for large datasets.
146
+ * Use the `nextCursor` from the response as the `cursor` parameter to get the next page.
144
147
  *
145
148
  * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
146
- * @param params - Time range and pagination parameters (start is required)
147
- * @returns Array of trades
149
+ * @param params - Time range and cursor pagination parameters (start and end are required)
150
+ * @returns Object with trades array and nextCursor for pagination
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * // First page
155
+ * let result = await client.trades.list('BTC', {
156
+ * start: Date.now() - 86400000,
157
+ * end: Date.now(),
158
+ * limit: 1000
159
+ * });
160
+ *
161
+ * // Subsequent pages
162
+ * while (result.nextCursor) {
163
+ * result = await client.trades.list('BTC', {
164
+ * start: Date.now() - 86400000,
165
+ * end: Date.now(),
166
+ * cursor: result.nextCursor,
167
+ * limit: 1000
168
+ * });
169
+ * }
170
+ * ```
148
171
  */
149
172
  async list(coin, params) {
150
173
  const response = await this.http.get(
151
174
  `/v1/trades/${coin.toUpperCase()}`,
152
175
  params
153
176
  );
154
- return response.data;
177
+ return {
178
+ data: response.data,
179
+ nextCursor: response.meta.next_cursor
180
+ };
155
181
  }
156
182
  /**
157
183
  * Get most recent trades for a coin
@@ -167,6 +193,34 @@ var TradesResource = class {
167
193
  );
168
194
  return response.data;
169
195
  }
196
+ /**
197
+ * Get trade history using cursor-based pagination (explicit endpoint)
198
+ *
199
+ * @deprecated Use `list()` instead - it now uses cursor-based pagination by default.
200
+ *
201
+ * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
202
+ * @param params - Cursor pagination parameters (start and end are required)
203
+ * @returns Object with trades array and nextCursor for pagination
204
+ */
205
+ async listWithCursor(coin, params) {
206
+ return this.list(coin, params);
207
+ }
208
+ /**
209
+ * Get trade history using offset-based pagination
210
+ *
211
+ * @deprecated Use `list()` with cursor-based pagination instead for better performance.
212
+ *
213
+ * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
214
+ * @param params - Time range and offset pagination parameters
215
+ * @returns Array of trades (without cursor response wrapper)
216
+ */
217
+ async listWithOffset(coin, params) {
218
+ const response = await this.http.get(
219
+ `/v1/trades/${coin.toUpperCase()}`,
220
+ params
221
+ );
222
+ return response.data;
223
+ }
170
224
  };
171
225
 
172
226
  // src/resources/instruments.ts
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/http.ts","../src/resources/orderbook.ts","../src/resources/trades.ts","../src/resources/instruments.ts","../src/resources/funding.ts","../src/resources/openinterest.ts","../src/client.ts","../src/websocket.ts"],"sourcesContent":["/**\r\n * @0xarchive/sdk - Official TypeScript SDK for 0xarchive\r\n *\r\n * @example\r\n * ```typescript\r\n * import { OxArchive } from '@0xarchive/sdk';\r\n *\r\n * const client = new OxArchive({ apiKey: 'ox_your_api_key' });\r\n *\r\n * // Get current order book\r\n * const orderbook = await client.orderbook.get('BTC');\r\n *\r\n * // Get historical snapshots\r\n * const history = await client.orderbook.history('ETH', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now()\r\n * });\r\n * ```\r\n *\r\n * @packageDocumentation\r\n */\r\n\r\n// Main client\r\nexport { OxArchive } from './client';\r\n\r\n// WebSocket client\r\nexport { OxArchiveWs } from './websocket';\r\n\r\n// Types\r\nexport type {\r\n ClientOptions,\r\n ApiMeta,\r\n ApiResponse,\r\n PaginationParams,\r\n TimeRangeParams,\r\n Timestamp,\r\n // Order Book\r\n PriceLevel,\r\n OrderBook,\r\n GetOrderBookParams,\r\n OrderBookHistoryParams,\r\n // Trades\r\n Trade,\r\n GetTradesParams,\r\n TradeSide,\r\n TradeDirection,\r\n DataSource,\r\n // Instruments\r\n Instrument,\r\n InstrumentType,\r\n // Funding\r\n FundingRate,\r\n // Open Interest\r\n OpenInterest,\r\n // WebSocket\r\n WsChannel,\r\n WsOptions,\r\n WsClientMessage,\r\n WsServerMessage,\r\n WsConnectionState,\r\n WsEventHandlers,\r\n WsSubscribe,\r\n WsUnsubscribe,\r\n WsPing,\r\n WsSubscribed,\r\n WsUnsubscribed,\r\n WsPong,\r\n WsError,\r\n WsData,\r\n // WebSocket Replay (Option B)\r\n WsReplay,\r\n WsReplayPause,\r\n WsReplayResume,\r\n WsReplaySeek,\r\n WsReplayStop,\r\n WsReplayStarted,\r\n WsReplayPaused,\r\n WsReplayResumed,\r\n WsReplayCompleted,\r\n WsReplayStopped,\r\n WsHistoricalData,\r\n // WebSocket Bulk Stream (Option D)\r\n WsStream,\r\n WsStreamStop,\r\n WsStreamStarted,\r\n WsStreamProgress,\r\n TimestampedRecord,\r\n WsHistoricalBatch,\r\n WsStreamCompleted,\r\n WsStreamStopped,\r\n // Errors\r\n ApiError,\r\n} from './types';\r\n\r\nexport { OxArchiveError } from './types';\r\n\r\n// Default export for convenience\r\nexport { OxArchive as default } from './client';\r\n","/**\r\n * Configuration options for the 0xarchive client\r\n */\r\nexport interface ClientOptions {\r\n /** Your 0xarchive API key */\r\n apiKey: string;\r\n /** Base URL for the API (defaults to https://api.0xarchive.io) */\r\n baseUrl?: string;\r\n /** Request timeout in milliseconds (defaults to 30000) */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Response metadata\r\n */\r\nexport interface ApiMeta {\r\n /** Number of records returned */\r\n count: number;\r\n /** Cursor for next page (if available) */\r\n next_cursor?: string;\r\n /** Unique request ID for debugging */\r\n request_id: string;\r\n}\r\n\r\n/**\r\n * Standard API response wrapper\r\n */\r\nexport interface ApiResponse<T> {\r\n success: boolean;\r\n data: T;\r\n meta: ApiMeta;\r\n}\r\n\r\n/**\r\n * Pagination parameters for list endpoints\r\n */\r\nexport interface PaginationParams {\r\n /** Maximum number of results to return */\r\n limit?: number;\r\n /** Number of results to skip */\r\n offset?: number;\r\n}\r\n\r\n/**\r\n * Time range parameters for historical queries\r\n */\r\nexport interface TimeRangeParams extends PaginationParams {\r\n /** Start timestamp (Unix ms or ISO string) - REQUIRED for history endpoints */\r\n start: number | string;\r\n /** End timestamp (Unix ms or ISO string) - REQUIRED for history endpoints */\r\n end: number | string;\r\n}\r\n\r\n// =============================================================================\r\n// Order Book Types\r\n// =============================================================================\r\n\r\n/**\r\n * A price level in the order book\r\n */\r\nexport interface PriceLevel {\r\n /** Price at this level */\r\n px: string;\r\n /** Total size at this price level */\r\n sz: string;\r\n /** Number of orders at this level */\r\n n: number;\r\n}\r\n\r\n/**\r\n * Order book snapshot\r\n */\r\nexport interface OrderBook {\r\n /** Trading pair symbol (e.g., BTC, ETH) */\r\n coin: string;\r\n /** Snapshot timestamp (UTC) */\r\n timestamp: string;\r\n /** Bid price levels (best bid first) */\r\n bids: PriceLevel[];\r\n /** Ask price levels (best ask first) */\r\n asks: PriceLevel[];\r\n /** Mid price (best bid + best ask) / 2 */\r\n mid_price?: string;\r\n /** Spread in absolute terms (best ask - best bid) */\r\n spread?: string;\r\n /** Spread in basis points */\r\n spread_bps?: string;\r\n}\r\n\r\nexport interface GetOrderBookParams {\r\n /** Timestamp to get order book at (Unix ms or ISO string) */\r\n timestamp?: number | string;\r\n /** Number of price levels to return per side */\r\n depth?: number;\r\n}\r\n\r\nexport interface OrderBookHistoryParams extends TimeRangeParams {\r\n /** Number of price levels to return per side */\r\n depth?: number;\r\n}\r\n\r\n// =============================================================================\r\n// Trade/Fill Types\r\n// =============================================================================\r\n\r\n/** Trade side: 'A' (ask/sell) or 'B' (bid/buy) */\r\nexport type TradeSide = 'A' | 'B';\r\n\r\n/** Position direction */\r\nexport type TradeDirection = 'Open Long' | 'Open Short' | 'Close Long' | 'Close Short';\r\n\r\n/** Data source */\r\nexport type DataSource = 's3' | 'ws' | 'api';\r\n\r\n/**\r\n * Trade/fill record with full execution details\r\n */\r\nexport interface Trade {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Trade side: 'A' (ask/sell) or 'B' (bid/buy) */\r\n side: TradeSide;\r\n /** Execution price */\r\n price: string;\r\n /** Trade size */\r\n size: string;\r\n /** Execution timestamp (UTC) */\r\n timestamp: string;\r\n /** Blockchain transaction hash */\r\n tx_hash?: string;\r\n /** Unique trade ID */\r\n trade_id?: number;\r\n /** Associated order ID */\r\n order_id?: number;\r\n /** True if taker (crossed the spread), false if maker */\r\n crossed?: boolean;\r\n /** Trading fee amount */\r\n fee?: string;\r\n /** Fee denomination (e.g., USDC) */\r\n fee_token?: string;\r\n /** Realized PnL if closing a position */\r\n closed_pnl?: string;\r\n /** Position direction */\r\n direction?: TradeDirection;\r\n /** Position size before this trade */\r\n start_position?: string;\r\n /** Data source */\r\n source?: DataSource;\r\n /** User's wallet address */\r\n user_address?: string;\r\n}\r\n\r\nexport interface GetTradesParams extends TimeRangeParams {\r\n /** Filter by side */\r\n side?: TradeSide;\r\n}\r\n\r\n// =============================================================================\r\n// Instruments Types\r\n// =============================================================================\r\n\r\n/** Instrument type */\r\nexport type InstrumentType = 'perp' | 'spot';\r\n\r\n/**\r\n * Trading instrument metadata\r\n */\r\nexport interface Instrument {\r\n /** Instrument symbol (e.g., BTC) */\r\n name: string;\r\n /** Size decimal precision */\r\n szDecimals: number;\r\n /** Maximum leverage allowed */\r\n maxLeverage?: number;\r\n /** If true, only isolated margin mode is allowed */\r\n onlyIsolated?: boolean;\r\n /** Type of instrument */\r\n instrumentType?: InstrumentType;\r\n /** Whether the instrument is currently tradeable */\r\n isActive: boolean;\r\n}\r\n\r\n// =============================================================================\r\n// Funding Types\r\n// =============================================================================\r\n\r\n/**\r\n * Funding rate record\r\n */\r\nexport interface FundingRate {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Funding timestamp (UTC) */\r\n timestamp: string;\r\n /** Funding rate as decimal (e.g., 0.0001 = 0.01%) */\r\n funding_rate: string;\r\n /** Premium component of funding rate */\r\n premium?: string;\r\n}\r\n\r\n// =============================================================================\r\n// Open Interest Types\r\n// =============================================================================\r\n\r\n/**\r\n * Open interest snapshot with market context\r\n */\r\nexport interface OpenInterest {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Snapshot timestamp (UTC) */\r\n timestamp: string;\r\n /** Total open interest in contracts */\r\n open_interest: string;\r\n /** Mark price used for liquidations */\r\n mark_price?: string;\r\n /** Oracle price from external feed */\r\n oracle_price?: string;\r\n /** 24-hour notional volume */\r\n day_ntl_volume?: string;\r\n /** Price 24 hours ago */\r\n prev_day_price?: string;\r\n /** Current mid price */\r\n mid_price?: string;\r\n /** Impact bid price for liquidations */\r\n impact_bid_price?: string;\r\n /** Impact ask price for liquidations */\r\n impact_ask_price?: string;\r\n}\r\n\r\n// =============================================================================\r\n// WebSocket Types\r\n// =============================================================================\r\n\r\n/** WebSocket channel types. Note: ticker/all_tickers are real-time only. */\r\nexport type WsChannel = 'orderbook' | 'trades' | 'ticker' | 'all_tickers';\r\n\r\n/** Subscribe message from client */\r\nexport interface WsSubscribe {\r\n op: 'subscribe';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Unsubscribe message from client */\r\nexport interface WsUnsubscribe {\r\n op: 'unsubscribe';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Ping message from client */\r\nexport interface WsPing {\r\n op: 'ping';\r\n}\r\n\r\n/** Replay message from client - replays historical data with timing preserved */\r\nexport interface WsReplay {\r\n op: 'replay';\r\n channel: WsChannel;\r\n coin?: string;\r\n /** Start timestamp (Unix ms) */\r\n start: number;\r\n /** End timestamp (Unix ms, defaults to now) */\r\n end?: number;\r\n /** Playback speed multiplier (1 = real-time, 10 = 10x faster) */\r\n speed?: number;\r\n}\r\n\r\n/** Replay control messages */\r\nexport interface WsReplayPause { op: 'replay.pause'; }\r\nexport interface WsReplayResume { op: 'replay.resume'; }\r\nexport interface WsReplaySeek { op: 'replay.seek'; timestamp: number; }\r\nexport interface WsReplayStop { op: 'replay.stop'; }\r\n\r\n/** Stream message from client - bulk download historical data */\r\nexport interface WsStream {\r\n op: 'stream';\r\n channel: WsChannel;\r\n coin?: string;\r\n /** Start timestamp (Unix ms) */\r\n start: number;\r\n /** End timestamp (Unix ms) */\r\n end: number;\r\n /** Batch size (records per message) */\r\n batch_size?: number;\r\n}\r\n\r\n/** Stream control messages */\r\nexport interface WsStreamStop { op: 'stream.stop'; }\r\n\r\n/** Client message union type */\r\nexport type WsClientMessage =\r\n | WsSubscribe\r\n | WsUnsubscribe\r\n | WsPing\r\n | WsReplay\r\n | WsReplayPause\r\n | WsReplayResume\r\n | WsReplaySeek\r\n | WsReplayStop\r\n | WsStream\r\n | WsStreamStop;\r\n\r\n/** Subscription confirmed from server */\r\nexport interface WsSubscribed {\r\n type: 'subscribed';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Unsubscription confirmed from server */\r\nexport interface WsUnsubscribed {\r\n type: 'unsubscribed';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Pong response from server */\r\nexport interface WsPong {\r\n type: 'pong';\r\n}\r\n\r\n/** Error from server */\r\nexport interface WsError {\r\n type: 'error';\r\n message: string;\r\n}\r\n\r\n/** Data message from server (real-time) */\r\nexport interface WsData<T = unknown> {\r\n type: 'data';\r\n channel: WsChannel;\r\n coin: string;\r\n data: T;\r\n}\r\n\r\n/** Replay started response */\r\nexport interface WsReplayStarted {\r\n type: 'replay_started';\r\n channel: WsChannel;\r\n coin: string;\r\n /** Start timestamp in milliseconds */\r\n start: number;\r\n /** End timestamp in milliseconds */\r\n end: number;\r\n /** Playback speed multiplier */\r\n speed: number;\r\n}\r\n\r\n/** Replay paused response */\r\nexport interface WsReplayPaused {\r\n type: 'replay_paused';\r\n current_timestamp: number;\r\n}\r\n\r\n/** Replay resumed response */\r\nexport interface WsReplayResumed {\r\n type: 'replay_resumed';\r\n current_timestamp: number;\r\n}\r\n\r\n/** Replay completed response */\r\nexport interface WsReplayCompleted {\r\n type: 'replay_completed';\r\n channel: WsChannel;\r\n coin: string;\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Replay stopped response */\r\nexport interface WsReplayStopped {\r\n type: 'replay_stopped';\r\n}\r\n\r\n/** Historical data point (replay mode) */\r\nexport interface WsHistoricalData<T = unknown> {\r\n type: 'historical_data';\r\n channel: WsChannel;\r\n coin: string;\r\n timestamp: number;\r\n data: T;\r\n}\r\n\r\n/** Stream started response */\r\nexport interface WsStreamStarted {\r\n type: 'stream_started';\r\n channel: WsChannel;\r\n coin: string;\r\n /** Start timestamp in milliseconds */\r\n start: number;\r\n /** End timestamp in milliseconds */\r\n end: number;\r\n}\r\n\r\n/** Stream progress response (sent periodically during streaming) */\r\nexport interface WsStreamProgress {\r\n type: 'stream_progress';\r\n snapshots_sent: number;\r\n}\r\n\r\n/** A record with timestamp for batched data */\r\nexport interface TimestampedRecord<T = unknown> {\r\n timestamp: number;\r\n data: T;\r\n}\r\n\r\n/** Batch of historical data (bulk streaming) */\r\nexport interface WsHistoricalBatch<T = unknown> {\r\n type: 'historical_batch';\r\n channel: WsChannel;\r\n coin: string;\r\n data: TimestampedRecord<T>[];\r\n}\r\n\r\n/** Stream completed response */\r\nexport interface WsStreamCompleted {\r\n type: 'stream_completed';\r\n channel: WsChannel;\r\n coin: string;\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Stream stopped response */\r\nexport interface WsStreamStopped {\r\n type: 'stream_stopped';\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Server message union type */\r\nexport type WsServerMessage =\r\n | WsSubscribed\r\n | WsUnsubscribed\r\n | WsPong\r\n | WsError\r\n | WsData\r\n | WsReplayStarted\r\n | WsReplayPaused\r\n | WsReplayResumed\r\n | WsReplayCompleted\r\n | WsReplayStopped\r\n | WsHistoricalData\r\n | WsStreamStarted\r\n | WsStreamProgress\r\n | WsHistoricalBatch\r\n | WsStreamCompleted\r\n | WsStreamStopped;\r\n\r\n/**\r\n * WebSocket connection options.\r\n *\r\n * The server sends WebSocket ping frames every 30 seconds and will disconnect\r\n * idle connections after 60 seconds. The SDK automatically handles keep-alive\r\n * by sending application-level pings at the configured interval.\r\n */\r\nexport interface WsOptions {\r\n /** API key for authentication */\r\n apiKey: string;\r\n /** WebSocket URL (defaults to wss://api.0xarchive.io/ws) */\r\n wsUrl?: string;\r\n /** Auto-reconnect on disconnect (defaults to true) */\r\n autoReconnect?: boolean;\r\n /** Reconnect delay in ms (defaults to 1000) */\r\n reconnectDelay?: number;\r\n /** Maximum reconnect attempts (defaults to 10) */\r\n maxReconnectAttempts?: number;\r\n /** Ping interval in ms to keep connection alive (defaults to 30000). Server disconnects after 60s idle. */\r\n pingInterval?: number;\r\n}\r\n\r\n/** WebSocket connection state */\r\nexport type WsConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';\r\n\r\n/** WebSocket event handlers */\r\nexport interface WsEventHandlers {\r\n onOpen?: () => void;\r\n onClose?: (code: number, reason: string) => void;\r\n onError?: (error: Error) => void;\r\n onMessage?: (message: WsServerMessage) => void;\r\n onStateChange?: (state: WsConnectionState) => void;\r\n}\r\n\r\n// =============================================================================\r\n// Error Types\r\n// =============================================================================\r\n\r\n/**\r\n * API error response\r\n */\r\nexport interface ApiError {\r\n code: number;\r\n error: string;\r\n}\r\n\r\n/**\r\n * SDK error class\r\n */\r\nexport class OxArchiveError extends Error {\r\n code: number;\r\n requestId?: string;\r\n\r\n constructor(message: string, code: number, requestId?: string) {\r\n super(message);\r\n this.name = 'OxArchiveError';\r\n this.code = code;\r\n this.requestId = requestId;\r\n }\r\n}\r\n\r\n/** Timestamp can be Unix ms (number), ISO string, or Date object */\r\nexport type Timestamp = number | string | Date;\r\n","import type { ApiResponse, ApiError } from './types';\r\nimport { OxArchiveError } from './types';\r\n\r\nexport interface HttpClientOptions {\r\n baseUrl: string;\r\n apiKey: string;\r\n timeout: number;\r\n}\r\n\r\n/**\r\n * Internal HTTP client for making API requests\r\n */\r\nexport class HttpClient {\r\n private baseUrl: string;\r\n private apiKey: string;\r\n private timeout: number;\r\n\r\n constructor(options: HttpClientOptions) {\r\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\r\n this.apiKey = options.apiKey;\r\n this.timeout = options.timeout;\r\n }\r\n\r\n /**\r\n * Make a GET request to the API\r\n */\r\n async get<T>(path: string, params?: Record<string, unknown>): Promise<T> {\r\n const url = new URL(`${this.baseUrl}${path}`);\r\n\r\n if (params) {\r\n for (const [key, value] of Object.entries(params)) {\r\n if (value !== undefined && value !== null) {\r\n url.searchParams.set(key, String(value));\r\n }\r\n }\r\n }\r\n\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url.toString(), {\r\n method: 'GET',\r\n headers: {\r\n 'X-API-Key': this.apiKey,\r\n 'Content-Type': 'application/json',\r\n },\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n const data = await response.json();\r\n\r\n if (!response.ok) {\r\n const error = data as ApiError;\r\n throw new OxArchiveError(\r\n error.error || `Request failed with status ${response.status}`,\r\n response.status,\r\n (data as ApiResponse<unknown>).meta?.request_id\r\n );\r\n }\r\n\r\n return data as T;\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof OxArchiveError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof Error && error.name === 'AbortError') {\r\n throw new OxArchiveError(`Request timeout after ${this.timeout}ms`, 408);\r\n }\r\n\r\n throw new OxArchiveError(\r\n error instanceof Error ? error.message : 'Unknown error',\r\n 500\r\n );\r\n }\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type {\r\n ApiResponse,\r\n OrderBook,\r\n GetOrderBookParams,\r\n OrderBookHistoryParams,\r\n} from '../types';\r\n\r\n/**\r\n * Order book API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current order book\r\n * const orderbook = await client.orderbook.get('BTC');\r\n *\r\n * // Get order book at specific timestamp\r\n * const historical = await client.orderbook.get('ETH', {\r\n * timestamp: 1704067200000,\r\n * depth: 10\r\n * });\r\n *\r\n * // Get order book history\r\n * const history = await client.orderbook.history('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n * ```\r\n */\r\nexport class OrderBookResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get order book snapshot for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Optional parameters\r\n * @returns Order book snapshot\r\n */\r\n async get(coin: string, params?: GetOrderBookParams): Promise<OrderBook> {\r\n const response = await this.http.get<ApiResponse<OrderBook>>(\r\n `/v1/orderbook/${coin.toUpperCase()}`,\r\n params as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get historical order book snapshots\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of order book snapshots\r\n */\r\n async history(\r\n coin: string,\r\n params: OrderBookHistoryParams\r\n ): Promise<OrderBook[]> {\r\n const response = await this.http.get<ApiResponse<OrderBook[]>>(\r\n `/v1/orderbook/${coin.toUpperCase()}/history`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, Trade, GetTradesParams } from '../types';\r\n\r\n/**\r\n * Trades API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get recent trades\r\n * const trades = await client.trades.recent('BTC');\r\n *\r\n * // Get trade history with time range\r\n * const history = await client.trades.list('ETH', {\r\n * start: Date.now() - 3600000,\r\n * end: Date.now(),\r\n * limit: 500\r\n * });\r\n * ```\r\n */\r\nexport class TradesResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get trade history for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of trades\r\n */\r\n async list(coin: string, params: GetTradesParams): Promise<Trade[]> {\r\n const response = await this.http.get<ApiResponse<Trade[]>>(\r\n `/v1/trades/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get most recent trades for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param limit - Number of trades to return (default: 100)\r\n * @returns Array of recent trades\r\n */\r\n async recent(coin: string, limit?: number): Promise<Trade[]> {\r\n const response = await this.http.get<ApiResponse<Trade[]>>(\r\n `/v1/trades/${coin.toUpperCase()}/recent`,\r\n { limit }\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, Instrument } from '../types';\r\n\r\n/**\r\n * Instruments API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // List all instruments\r\n * const instruments = await client.instruments.list();\r\n *\r\n * // Get specific instrument\r\n * const btc = await client.instruments.get('BTC');\r\n * ```\r\n */\r\nexport class InstrumentsResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * List all available trading instruments\r\n *\r\n * @returns Array of instruments\r\n */\r\n async list(): Promise<Instrument[]> {\r\n const response = await this.http.get<ApiResponse<Instrument[]>>(\r\n '/v1/instruments'\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get a specific instrument by coin symbol\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Instrument details\r\n */\r\n async get(coin: string): Promise<Instrument> {\r\n const response = await this.http.get<ApiResponse<Instrument>>(\r\n `/v1/instruments/${coin.toUpperCase()}`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, FundingRate, TimeRangeParams } from '../types';\r\n\r\n/**\r\n * Funding rates API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current funding rate\r\n * const current = await client.funding.current('BTC');\r\n *\r\n * // Get funding rate history\r\n * const history = await client.funding.history('ETH', {\r\n * start: Date.now() - 86400000 * 7,\r\n * end: Date.now()\r\n * });\r\n * ```\r\n */\r\nexport class FundingResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get funding rate history for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of funding rate records\r\n */\r\n async history(coin: string, params: TimeRangeParams): Promise<FundingRate[]> {\r\n const response = await this.http.get<ApiResponse<FundingRate[]>>(\r\n `/v1/funding/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get current funding rate for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Current funding rate\r\n */\r\n async current(coin: string): Promise<FundingRate> {\r\n const response = await this.http.get<ApiResponse<FundingRate>>(\r\n `/v1/funding/${coin.toUpperCase()}/current`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, OpenInterest, TimeRangeParams } from '../types';\r\n\r\n/**\r\n * Open interest API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current open interest\r\n * const current = await client.openInterest.current('BTC');\r\n *\r\n * // Get open interest history\r\n * const history = await client.openInterest.history('ETH', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n * ```\r\n */\r\nexport class OpenInterestResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get open interest history for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of open interest records\r\n */\r\n async history(coin: string, params: TimeRangeParams): Promise<OpenInterest[]> {\r\n const response = await this.http.get<ApiResponse<OpenInterest[]>>(\r\n `/v1/openinterest/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get current open interest for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Current open interest\r\n */\r\n async current(coin: string): Promise<OpenInterest> {\r\n const response = await this.http.get<ApiResponse<OpenInterest>>(\r\n `/v1/openinterest/${coin.toUpperCase()}/current`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { ClientOptions } from './types';\r\nimport { HttpClient } from './http';\r\nimport {\r\n OrderBookResource,\r\n TradesResource,\r\n InstrumentsResource,\r\n FundingResource,\r\n OpenInterestResource,\r\n} from './resources';\r\n\r\nconst DEFAULT_BASE_URL = 'https://api.0xarchive.io';\r\nconst DEFAULT_TIMEOUT = 30000;\r\n\r\n/**\r\n * 0xarchive API client\r\n *\r\n * @example\r\n * ```typescript\r\n * import { OxArchive } from '@0xarchive/sdk';\r\n *\r\n * const client = new OxArchive({ apiKey: 'ox_your_api_key' });\r\n *\r\n * // Get current order book\r\n * const orderbook = await client.orderbook.get('BTC');\r\n * console.log(`BTC mid price: ${orderbook.mid_price}`);\r\n *\r\n * // Get historical data\r\n * const history = await client.orderbook.history('ETH', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n *\r\n * // List all instruments\r\n * const instruments = await client.instruments.list();\r\n * ```\r\n */\r\nexport class OxArchive {\r\n private http: HttpClient;\r\n\r\n /**\r\n * Order book data (L2 snapshots from April 2023)\r\n */\r\n public readonly orderbook: OrderBookResource;\r\n\r\n /**\r\n * Trade/fill history\r\n */\r\n public readonly trades: TradesResource;\r\n\r\n /**\r\n * Trading instruments metadata\r\n */\r\n public readonly instruments: InstrumentsResource;\r\n\r\n /**\r\n * Funding rates\r\n */\r\n public readonly funding: FundingResource;\r\n\r\n /**\r\n * Open interest\r\n */\r\n public readonly openInterest: OpenInterestResource;\r\n\r\n /**\r\n * Create a new 0xarchive client\r\n *\r\n * @param options - Client configuration options\r\n */\r\n constructor(options: ClientOptions) {\r\n if (!options.apiKey) {\r\n throw new Error('API key is required. Get one at https://0xarchive.io/signup');\r\n }\r\n\r\n this.http = new HttpClient({\r\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\r\n apiKey: options.apiKey,\r\n timeout: options.timeout ?? DEFAULT_TIMEOUT,\r\n });\r\n\r\n // Initialize resource namespaces\r\n this.orderbook = new OrderBookResource(this.http);\r\n this.trades = new TradesResource(this.http);\r\n this.instruments = new InstrumentsResource(this.http);\r\n this.funding = new FundingResource(this.http);\r\n this.openInterest = new OpenInterestResource(this.http);\r\n }\r\n}\r\n","/**\r\n * WebSocket client for 0xarchive real-time streaming, replay, and bulk download\r\n *\r\n * @example Real-time streaming\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect({\r\n * onMessage: (msg) => console.log(msg)\r\n * });\r\n * ws.subscribeOrderbook('BTC');\r\n * ```\r\n *\r\n * @example Historical replay (like Tardis.dev)\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect();\r\n * ws.onHistoricalData((coin, timestamp, data) => {\r\n * console.log(`${new Date(timestamp)}: ${data.mid_price}`);\r\n * });\r\n * ws.replay('orderbook', 'BTC', {\r\n * start: Date.now() - 86400000,\r\n * speed: 10 // 10x speed\r\n * });\r\n * ```\r\n *\r\n * @example Bulk streaming (like Databento)\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect();\r\n * const batches: OrderBook[] = [];\r\n * ws.onBatch((coin, records) => {\r\n * batches.push(...records.map(r => r.data));\r\n * });\r\n * ws.onStreamComplete((channel, coin, count) => {\r\n * console.log(`Downloaded ${count} records`);\r\n * });\r\n * ws.stream('orderbook', 'ETH', {\r\n * start: Date.now() - 3600000,\r\n * end: Date.now(),\r\n * batchSize: 1000\r\n * });\r\n * ```\r\n */\r\n\r\nimport type {\r\n WsOptions,\r\n WsChannel,\r\n WsClientMessage,\r\n WsServerMessage,\r\n WsConnectionState,\r\n WsEventHandlers,\r\n OrderBook,\r\n PriceLevel,\r\n Trade,\r\n WsHistoricalData,\r\n WsHistoricalBatch,\r\n WsReplayStarted,\r\n WsReplayCompleted,\r\n WsStreamStarted,\r\n WsStreamCompleted,\r\n WsStreamProgress,\r\n} from './types';\r\n\r\nconst DEFAULT_WS_URL = 'wss://api.0xarchive.io/ws';\r\nconst DEFAULT_PING_INTERVAL = 30000; // 30 seconds\r\nconst DEFAULT_RECONNECT_DELAY = 1000;\r\nconst DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;\r\n\r\n// Server idle timeout is 60 seconds. The SDK sends pings every 30 seconds\r\n// to keep the connection alive. Browser WebSocket API automatically responds\r\n// to WebSocket protocol-level ping frames from the server.\r\n\r\n/**\r\n * Transform raw Hyperliquid orderbook format to SDK OrderBook type.\r\n * Raw format: { coin, levels: [[{px, sz, n}, ...], [{px, sz, n}, ...]], time }\r\n * SDK format: { coin, timestamp, bids: [{px, sz, n}], asks: [{px, sz, n}], mid_price, spread, spread_bps }\r\n */\r\nfunction transformOrderbook(coin: string, raw: Record<string, unknown>): OrderBook {\r\n // Check if already in SDK format (from REST API or historical replay)\r\n if ('bids' in raw && 'asks' in raw) {\r\n return raw as unknown as OrderBook;\r\n }\r\n\r\n // Transform from Hyperliquid raw format\r\n // levels is [[{px, sz, n}, ...], [{px, sz, n}, ...]] where [0]=bids, [1]=asks\r\n const levels = raw.levels as Array<Array<{ px: string; sz: string; n: number }>> | undefined;\r\n const time = raw.time as number | undefined;\r\n\r\n const bids: PriceLevel[] = [];\r\n const asks: PriceLevel[] = [];\r\n\r\n if (levels && levels.length >= 2) {\r\n // levels[0] = bids, levels[1] = asks\r\n // Each level is already {px, sz, n} object\r\n for (const level of levels[0] || []) {\r\n bids.push({ px: level.px, sz: level.sz, n: level.n });\r\n }\r\n for (const level of levels[1] || []) {\r\n asks.push({ px: level.px, sz: level.sz, n: level.n });\r\n }\r\n }\r\n\r\n // Calculate mid price and spread\r\n let mid_price: string | undefined;\r\n let spread: string | undefined;\r\n let spread_bps: string | undefined;\r\n\r\n if (bids.length > 0 && asks.length > 0) {\r\n const bestBid = parseFloat(bids[0].px);\r\n const bestAsk = parseFloat(asks[0].px);\r\n const mid = (bestBid + bestAsk) / 2;\r\n mid_price = mid.toString();\r\n spread = (bestAsk - bestBid).toString();\r\n spread_bps = ((bestAsk - bestBid) / mid * 10000).toFixed(2);\r\n }\r\n\r\n return {\r\n coin,\r\n timestamp: time ? new Date(time).toISOString() : new Date().toISOString(),\r\n bids,\r\n asks,\r\n mid_price,\r\n spread,\r\n spread_bps,\r\n };\r\n}\r\n\r\n/**\r\n * WebSocket client for real-time data streaming.\r\n *\r\n * **Keep-Alive:** The server sends WebSocket ping frames every 30 seconds\r\n * and will disconnect idle connections after 60 seconds. This SDK automatically\r\n * handles keep-alive by sending application-level pings at the configured interval\r\n * (default: 30 seconds). The browser WebSocket API automatically responds to\r\n * server ping frames.\r\n */\r\nexport class OxArchiveWs {\r\n private ws: WebSocket | null = null;\r\n private options: Required<WsOptions>;\r\n private handlers: WsEventHandlers = {};\r\n private subscriptions: Set<string> = new Set();\r\n private state: WsConnectionState = 'disconnected';\r\n private reconnectAttempts = 0;\r\n private pingTimer: ReturnType<typeof setInterval> | null = null;\r\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n // Typed event handlers (separate from WsEventHandlers to avoid wrapping issues)\r\n private historicalDataHandlers: Array<(coin: string, timestamp: number, data: unknown) => void> = [];\r\n private batchHandlers: Array<(coin: string, records: Array<{ timestamp: number; data: unknown }>) => void> = [];\r\n private replayStartHandlers: Array<(channel: WsChannel, coin: string, start: number, end: number, speed: number) => void> = [];\r\n private replayCompleteHandlers: Array<(channel: WsChannel, coin: string, snapshotsSent: number) => void> = [];\r\n private streamStartHandlers: Array<(channel: WsChannel, coin: string, start: number, end: number) => void> = [];\r\n private streamProgressHandlers: Array<(snapshotsSent: number) => void> = [];\r\n private streamCompleteHandlers: Array<(channel: WsChannel, coin: string, snapshotsSent: number) => void> = [];\r\n private orderbookHandlers: Array<(coin: string, data: OrderBook) => void> = [];\r\n private tradesHandlers: Array<(coin: string, data: Trade[]) => void> = [];\r\n\r\n constructor(options: WsOptions) {\r\n this.options = {\r\n apiKey: options.apiKey,\r\n wsUrl: options.wsUrl ?? DEFAULT_WS_URL,\r\n autoReconnect: options.autoReconnect ?? true,\r\n reconnectDelay: options.reconnectDelay ?? DEFAULT_RECONNECT_DELAY,\r\n maxReconnectAttempts: options.maxReconnectAttempts ?? DEFAULT_MAX_RECONNECT_ATTEMPTS,\r\n pingInterval: options.pingInterval ?? DEFAULT_PING_INTERVAL,\r\n };\r\n }\r\n\r\n /**\r\n * Connect to the WebSocket server\r\n */\r\n connect(handlers?: WsEventHandlers): void {\r\n if (handlers) {\r\n this.handlers = handlers;\r\n }\r\n\r\n this.setState('connecting');\r\n\r\n const url = `${this.options.wsUrl}?apiKey=${encodeURIComponent(this.options.apiKey)}`;\r\n this.ws = new WebSocket(url);\r\n\r\n this.ws.onopen = () => {\r\n this.reconnectAttempts = 0;\r\n this.setState('connected');\r\n this.startPing();\r\n this.resubscribe();\r\n this.handlers.onOpen?.();\r\n };\r\n\r\n this.ws.onclose = (event) => {\r\n this.stopPing();\r\n this.handlers.onClose?.(event.code, event.reason);\r\n\r\n if (this.options.autoReconnect && this.state !== 'disconnected') {\r\n this.scheduleReconnect();\r\n } else {\r\n this.setState('disconnected');\r\n }\r\n };\r\n\r\n this.ws.onerror = () => {\r\n const error = new Error('WebSocket connection error');\r\n this.handlers.onError?.(error);\r\n };\r\n\r\n this.ws.onmessage = (event) => {\r\n try {\r\n const message = JSON.parse(event.data) as WsServerMessage;\r\n this.handleMessage(message);\r\n } catch {\r\n // Ignore parse errors for malformed messages\r\n }\r\n };\r\n }\r\n\r\n /**\r\n * Disconnect from the WebSocket server\r\n */\r\n disconnect(): void {\r\n this.setState('disconnected');\r\n this.stopPing();\r\n this.clearReconnectTimer();\r\n\r\n if (this.ws) {\r\n this.ws.close(1000, 'Client disconnect');\r\n this.ws = null;\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to a channel\r\n */\r\n subscribe(channel: WsChannel, coin?: string): void {\r\n const key = this.subscriptionKey(channel, coin);\r\n this.subscriptions.add(key);\r\n\r\n if (this.isConnected()) {\r\n this.send({ op: 'subscribe', channel, coin });\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to order book updates for a coin\r\n */\r\n subscribeOrderbook(coin: string): void {\r\n this.subscribe('orderbook', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to trades for a coin\r\n */\r\n subscribeTrades(coin: string): void {\r\n this.subscribe('trades', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to ticker updates for a coin\r\n */\r\n subscribeTicker(coin: string): void {\r\n this.subscribe('ticker', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to all tickers\r\n */\r\n subscribeAllTickers(): void {\r\n this.subscribe('all_tickers');\r\n }\r\n\r\n /**\r\n * Unsubscribe from a channel\r\n */\r\n unsubscribe(channel: WsChannel, coin?: string): void {\r\n const key = this.subscriptionKey(channel, coin);\r\n this.subscriptions.delete(key);\r\n\r\n if (this.isConnected()) {\r\n this.send({ op: 'unsubscribe', channel, coin });\r\n }\r\n }\r\n\r\n /**\r\n * Unsubscribe from order book updates for a coin\r\n */\r\n unsubscribeOrderbook(coin: string): void {\r\n this.unsubscribe('orderbook', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from trades for a coin\r\n */\r\n unsubscribeTrades(coin: string): void {\r\n this.unsubscribe('trades', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from ticker updates for a coin\r\n */\r\n unsubscribeTicker(coin: string): void {\r\n this.unsubscribe('ticker', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from all tickers\r\n */\r\n unsubscribeAllTickers(): void {\r\n this.unsubscribe('all_tickers');\r\n }\r\n\r\n // ==========================================================================\r\n // Historical Replay (Option B) - Like Tardis.dev\r\n // ==========================================================================\r\n\r\n /**\r\n * Start historical replay with timing preserved\r\n *\r\n * @param channel - Data channel to replay\r\n * @param coin - Trading pair (e.g., 'BTC', 'ETH')\r\n * @param options - Replay options\r\n *\r\n * @example\r\n * ```typescript\r\n * ws.replay('orderbook', 'BTC', {\r\n * start: Date.now() - 86400000, // 24 hours ago\r\n * speed: 10 // 10x faster than real-time\r\n * });\r\n * ```\r\n */\r\n replay(\r\n channel: WsChannel,\r\n coin: string,\r\n options: {\r\n start: number;\r\n end?: number;\r\n speed?: number;\r\n }\r\n ): void {\r\n this.send({\r\n op: 'replay',\r\n channel,\r\n coin,\r\n start: options.start,\r\n end: options.end,\r\n speed: options.speed ?? 1,\r\n });\r\n }\r\n\r\n /**\r\n * Pause the current replay\r\n */\r\n replayPause(): void {\r\n this.send({ op: 'replay.pause' });\r\n }\r\n\r\n /**\r\n * Resume a paused replay\r\n */\r\n replayResume(): void {\r\n this.send({ op: 'replay.resume' });\r\n }\r\n\r\n /**\r\n * Seek to a specific timestamp in the replay\r\n * @param timestamp - Unix timestamp in milliseconds\r\n */\r\n replaySeek(timestamp: number): void {\r\n this.send({ op: 'replay.seek', timestamp });\r\n }\r\n\r\n /**\r\n * Stop the current replay\r\n */\r\n replayStop(): void {\r\n this.send({ op: 'replay.stop' });\r\n }\r\n\r\n // ==========================================================================\r\n // Bulk Streaming (Option D) - Like Databento\r\n // ==========================================================================\r\n\r\n /**\r\n * Start bulk streaming for fast data download\r\n *\r\n * @param channel - Data channel to stream\r\n * @param coin - Trading pair (e.g., 'BTC', 'ETH')\r\n * @param options - Stream options\r\n *\r\n * @example\r\n * ```typescript\r\n * ws.stream('orderbook', 'ETH', {\r\n * start: Date.now() - 3600000, // 1 hour ago\r\n * end: Date.now(),\r\n * batchSize: 1000\r\n * });\r\n * ```\r\n */\r\n stream(\r\n channel: WsChannel,\r\n coin: string,\r\n options: {\r\n start: number;\r\n end: number;\r\n batchSize?: number;\r\n }\r\n ): void {\r\n this.send({\r\n op: 'stream',\r\n channel,\r\n coin,\r\n start: options.start,\r\n end: options.end,\r\n batch_size: options.batchSize ?? 1000,\r\n });\r\n }\r\n\r\n /**\r\n * Stop the current bulk stream\r\n */\r\n streamStop(): void {\r\n this.send({ op: 'stream.stop' });\r\n }\r\n\r\n // ==========================================================================\r\n // Event Handlers for Replay/Stream\r\n // ==========================================================================\r\n\r\n /**\r\n * Handle historical data points (replay mode)\r\n */\r\n onHistoricalData<T = unknown>(\r\n handler: (coin: string, timestamp: number, data: T) => void\r\n ): void {\r\n this.historicalDataHandlers.push(handler as (coin: string, timestamp: number, data: unknown) => void);\r\n }\r\n\r\n /**\r\n * Handle batched data (bulk stream mode)\r\n */\r\n onBatch<T = unknown>(\r\n handler: (coin: string, records: Array<{ timestamp: number; data: T }>) => void\r\n ): void {\r\n this.batchHandlers.push(handler as (coin: string, records: Array<{ timestamp: number; data: unknown }>) => void);\r\n }\r\n\r\n /**\r\n * Handle replay started event\r\n */\r\n onReplayStart(\r\n handler: (channel: WsChannel, coin: string, start: number, end: number, speed: number) => void\r\n ): void {\r\n this.replayStartHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle replay completed event\r\n */\r\n onReplayComplete(\r\n handler: (channel: WsChannel, coin: string, snapshotsSent: number) => void\r\n ): void {\r\n this.replayCompleteHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream started event\r\n */\r\n onStreamStart(\r\n handler: (channel: WsChannel, coin: string, start: number, end: number) => void\r\n ): void {\r\n this.streamStartHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream progress event\r\n */\r\n onStreamProgress(\r\n handler: (snapshotsSent: number) => void\r\n ): void {\r\n this.streamProgressHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream completed event\r\n */\r\n onStreamComplete(\r\n handler: (channel: WsChannel, coin: string, snapshotsSent: number) => void\r\n ): void {\r\n this.streamCompleteHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Get current connection state\r\n */\r\n getState(): WsConnectionState {\r\n return this.state;\r\n }\r\n\r\n /**\r\n * Check if connected\r\n */\r\n isConnected(): boolean {\r\n return this.ws?.readyState === WebSocket.OPEN;\r\n }\r\n\r\n /**\r\n * Set event handlers after construction\r\n */\r\n on<K extends keyof WsEventHandlers>(event: K, handler: WsEventHandlers[K]): void {\r\n this.handlers[event] = handler;\r\n }\r\n\r\n /**\r\n * Helper to handle typed orderbook data\r\n */\r\n onOrderbook(handler: (coin: string, data: OrderBook) => void): void {\r\n this.orderbookHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Helper to handle typed trade data\r\n */\r\n onTrades(handler: (coin: string, data: Trade[]) => void): void {\r\n this.tradesHandlers.push(handler);\r\n }\r\n\r\n // Private methods\r\n\r\n private send(message: WsClientMessage): void {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify(message));\r\n }\r\n }\r\n\r\n private setState(state: WsConnectionState): void {\r\n this.state = state;\r\n this.handlers.onStateChange?.(state);\r\n }\r\n\r\n private startPing(): void {\r\n this.stopPing();\r\n this.pingTimer = setInterval(() => {\r\n this.send({ op: 'ping' });\r\n }, this.options.pingInterval);\r\n }\r\n\r\n private stopPing(): void {\r\n if (this.pingTimer) {\r\n clearInterval(this.pingTimer);\r\n this.pingTimer = null;\r\n }\r\n }\r\n\r\n private subscriptionKey(channel: WsChannel, coin?: string): string {\r\n return coin ? `${channel}:${coin}` : channel;\r\n }\r\n\r\n private resubscribe(): void {\r\n for (const key of this.subscriptions) {\r\n const [channel, coin] = key.split(':') as [WsChannel, string | undefined];\r\n this.send({ op: 'subscribe', channel, coin });\r\n }\r\n }\r\n\r\n private scheduleReconnect(): void {\r\n if (this.reconnectAttempts >= this.options.maxReconnectAttempts) {\r\n this.setState('disconnected');\r\n return;\r\n }\r\n\r\n this.setState('reconnecting');\r\n this.reconnectAttempts++;\r\n\r\n const delay = this.options.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);\r\n\r\n this.reconnectTimer = setTimeout(() => {\r\n this.connect();\r\n }, delay);\r\n }\r\n\r\n private clearReconnectTimer(): void {\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = null;\r\n }\r\n }\r\n\r\n private handleMessage(message: WsServerMessage): void {\r\n // Call the generic onMessage handler first\r\n this.handlers.onMessage?.(message);\r\n\r\n // Dispatch to typed handlers based on message type\r\n switch (message.type) {\r\n case 'historical_data': {\r\n const msg = message as WsHistoricalData;\r\n for (const handler of this.historicalDataHandlers) {\r\n handler(msg.coin, msg.timestamp, msg.data);\r\n }\r\n break;\r\n }\r\n case 'historical_batch': {\r\n const msg = message as WsHistoricalBatch;\r\n for (const handler of this.batchHandlers) {\r\n handler(msg.coin, msg.data as Array<{ timestamp: number; data: unknown }>);\r\n }\r\n break;\r\n }\r\n case 'replay_started': {\r\n const msg = message as WsReplayStarted;\r\n for (const handler of this.replayStartHandlers) {\r\n handler(msg.channel, msg.coin, msg.start, msg.end, msg.speed);\r\n }\r\n break;\r\n }\r\n case 'replay_completed': {\r\n const msg = message as WsReplayCompleted;\r\n for (const handler of this.replayCompleteHandlers) {\r\n handler(msg.channel, msg.coin, msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'stream_started': {\r\n const msg = message as WsStreamStarted;\r\n for (const handler of this.streamStartHandlers) {\r\n handler(msg.channel, msg.coin, msg.start, msg.end);\r\n }\r\n break;\r\n }\r\n case 'stream_progress': {\r\n const msg = message as WsStreamProgress;\r\n for (const handler of this.streamProgressHandlers) {\r\n handler(msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'stream_completed': {\r\n const msg = message as WsStreamCompleted;\r\n for (const handler of this.streamCompleteHandlers) {\r\n handler(msg.channel, msg.coin, msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'data': {\r\n if (message.channel === 'orderbook') {\r\n // Transform raw Hyperliquid format to SDK OrderBook type\r\n const orderbook = transformOrderbook(message.coin, message.data as Record<string, unknown>);\r\n for (const handler of this.orderbookHandlers) {\r\n handler(message.coin, orderbook);\r\n }\r\n } else if (message.channel === 'trades') {\r\n for (const handler of this.tradesHandlers) {\r\n handler(message.coin, message.data as Trade[]);\r\n }\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACifO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACxC;AAAA,EACA;AAAA,EAEA,YAAY,SAAiB,MAAc,WAAoB;AAC7D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,YAAY;AAAA,EACnB;AACF;;;AC/eO,IAAM,aAAN,MAAiB;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,SAA4B;AACtC,SAAK,UAAU,QAAQ,QAAQ,QAAQ,OAAO,EAAE;AAChD,SAAK,SAAS,QAAQ;AACtB,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAO,MAAc,QAA8C;AACvE,UAAM,MAAM,IAAI,IAAI,GAAG,KAAK,OAAO,GAAG,IAAI,EAAE;AAE5C,QAAI,QAAQ;AACV,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,YAAI,UAAU,UAAa,UAAU,MAAM;AACzC,cAAI,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,OAAO;AAEnE,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;AAAA,QAC3C,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,aAAa,KAAK;AAAA,UAClB,gBAAgB;AAAA,QAClB;AAAA,QACA,QAAQ,WAAW;AAAA,MACrB,CAAC;AAED,mBAAa,SAAS;AAEtB,YAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,QAAQ;AACd,cAAM,IAAI;AAAA,UACR,MAAM,SAAS,8BAA8B,SAAS,MAAM;AAAA,UAC5D,SAAS;AAAA,UACR,KAA8B,MAAM;AAAA,QACvC;AAAA,MACF;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,mBAAa,SAAS;AAEtB,UAAI,iBAAiB,gBAAgB;AACnC,cAAM;AAAA,MACR;AAEA,UAAI,iBAAiB,SAAS,MAAM,SAAS,cAAc;AACzD,cAAM,IAAI,eAAe,yBAAyB,KAAK,OAAO,MAAM,GAAG;AAAA,MACzE;AAEA,YAAM,IAAI;AAAA,QACR,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACnDO,IAAM,oBAAN,MAAwB;AAAA,EAC7B,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASvC,MAAM,IAAI,MAAc,QAAiD;AACvE,UAAM,WAAW,MAAM,KAAK,KAAK;AAAA,MAC/B,iBAAiB,KAAK,YAAY,CAAC;AAAA,MACnC;AAAA,IACF;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QACJ,MACA,QACsB;AACtB,UAAM,WAAW,MAAM,KAAK,KAAK;AAAA,MAC/B,iBAAiB,KAAK,YAAY,CAAC;AAAA,MACnC;AAAA,IACF;AACA,WAAO,SAAS;AAAA,EAClB;AACF;;;AC9CO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASvC,MAAM,KAAK,MAAc,QAA2C;AAClE,UAAM,WAAW,MAAM,KAAK,KAAK;AAAA,MAC/B,cAAc,KAAK,YAAY,CAAC;AAAA,MAChC;AAAA,IACF;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,OAAO,MAAc,OAAkC;AAC3D,UAAM,WAAW,MAAM,KAAK,KAAK;AAAA,MAC/B,cAAc,KAAK,YAAY,CAAC;AAAA,MAChC,EAAE,MAAM;AAAA,IACV;AACA,WAAO,SAAS;AAAA,EAClB;AACF;;;ACpCO,IAAM,sBAAN,MAA0B;AAAA,EAC/B,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvC,MAAM,OAA8B;AAClC,UAAM,WAAW,MAAM,KAAK,KAAK;AAAA,MAC/B;AAAA,IACF;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,IAAI,MAAmC;AAC3C,UAAM,WAAW,MAAM,KAAK,KAAK;AAAA,MAC/B,mBAAmB,KAAK,YAAY,CAAC;AAAA,IACvC;AACA,WAAO,SAAS;AAAA,EAClB;AACF;;;ACxBO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASvC,MAAM,QAAQ,MAAc,QAAiD;AAC3E,UAAM,WAAW,MAAM,KAAK,KAAK;AAAA,MAC/B,eAAe,KAAK,YAAY,CAAC;AAAA,MACjC;AAAA,IACF;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,QAAQ,MAAoC;AAChD,UAAM,WAAW,MAAM,KAAK,KAAK;AAAA,MAC/B,eAAe,KAAK,YAAY,CAAC;AAAA,IACnC;AACA,WAAO,SAAS;AAAA,EAClB;AACF;;;AC7BO,IAAM,uBAAN,MAA2B;AAAA,EAChC,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASvC,MAAM,QAAQ,MAAc,QAAkD;AAC5E,UAAM,WAAW,MAAM,KAAK,KAAK;AAAA,MAC/B,oBAAoB,KAAK,YAAY,CAAC;AAAA,MACtC;AAAA,IACF;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,QAAQ,MAAqC;AACjD,UAAM,WAAW,MAAM,KAAK,KAAK;AAAA,MAC/B,oBAAoB,KAAK,YAAY,CAAC;AAAA,IACxC;AACA,WAAO,SAAS;AAAA,EAClB;AACF;;;ACvCA,IAAM,mBAAmB;AACzB,IAAM,kBAAkB;AA0BjB,IAAM,YAAN,MAAgB;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKQ;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhB,YAAY,SAAwB;AAClC,QAAI,CAAC,QAAQ,QAAQ;AACnB,YAAM,IAAI,MAAM,6DAA6D;AAAA,IAC/E;AAEA,SAAK,OAAO,IAAI,WAAW;AAAA,MACzB,SAAS,QAAQ,WAAW;AAAA,MAC5B,QAAQ,QAAQ;AAAA,MAChB,SAAS,QAAQ,WAAW;AAAA,IAC9B,CAAC;AAGD,SAAK,YAAY,IAAI,kBAAkB,KAAK,IAAI;AAChD,SAAK,SAAS,IAAI,eAAe,KAAK,IAAI;AAC1C,SAAK,cAAc,IAAI,oBAAoB,KAAK,IAAI;AACpD,SAAK,UAAU,IAAI,gBAAgB,KAAK,IAAI;AAC5C,SAAK,eAAe,IAAI,qBAAqB,KAAK,IAAI;AAAA,EACxD;AACF;;;ACzBA,IAAM,iBAAiB;AACvB,IAAM,wBAAwB;AAC9B,IAAM,0BAA0B;AAChC,IAAM,iCAAiC;AAWvC,SAAS,mBAAmB,MAAc,KAAyC;AAEjF,MAAI,UAAU,OAAO,UAAU,KAAK;AAClC,WAAO;AAAA,EACT;AAIA,QAAM,SAAS,IAAI;AACnB,QAAM,OAAO,IAAI;AAEjB,QAAM,OAAqB,CAAC;AAC5B,QAAM,OAAqB,CAAC;AAE5B,MAAI,UAAU,OAAO,UAAU,GAAG;AAGhC,eAAW,SAAS,OAAO,CAAC,KAAK,CAAC,GAAG;AACnC,WAAK,KAAK,EAAE,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC;AAAA,IACtD;AACA,eAAW,SAAS,OAAO,CAAC,KAAK,CAAC,GAAG;AACnC,WAAK,KAAK,EAAE,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC;AAAA,IACtD;AAAA,EACF;AAGA,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,MAAI,KAAK,SAAS,KAAK,KAAK,SAAS,GAAG;AACtC,UAAM,UAAU,WAAW,KAAK,CAAC,EAAE,EAAE;AACrC,UAAM,UAAU,WAAW,KAAK,CAAC,EAAE,EAAE;AACrC,UAAM,OAAO,UAAU,WAAW;AAClC,gBAAY,IAAI,SAAS;AACzB,cAAU,UAAU,SAAS,SAAS;AACtC,mBAAe,UAAU,WAAW,MAAM,KAAO,QAAQ,CAAC;AAAA,EAC5D;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAW,OAAO,IAAI,KAAK,IAAI,EAAE,YAAY,KAAI,oBAAI,KAAK,GAAE,YAAY;AAAA,IACxE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAWO,IAAM,cAAN,MAAkB;AAAA,EACf,KAAuB;AAAA,EACvB;AAAA,EACA,WAA4B,CAAC;AAAA,EAC7B,gBAA6B,oBAAI,IAAI;AAAA,EACrC,QAA2B;AAAA,EAC3B,oBAAoB;AAAA,EACpB,YAAmD;AAAA,EACnD,iBAAuD;AAAA;AAAA,EAGvD,yBAA0F,CAAC;AAAA,EAC3F,gBAAqG,CAAC;AAAA,EACtG,sBAAoH,CAAC;AAAA,EACrH,yBAAmG,CAAC;AAAA,EACpG,sBAAqG,CAAC;AAAA,EACtG,yBAAiE,CAAC;AAAA,EAClE,yBAAmG,CAAC;AAAA,EACpG,oBAAoE,CAAC;AAAA,EACrE,iBAA+D,CAAC;AAAA,EAExE,YAAY,SAAoB;AAC9B,SAAK,UAAU;AAAA,MACb,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ,SAAS;AAAA,MACxB,eAAe,QAAQ,iBAAiB;AAAA,MACxC,gBAAgB,QAAQ,kBAAkB;AAAA,MAC1C,sBAAsB,QAAQ,wBAAwB;AAAA,MACtD,cAAc,QAAQ,gBAAgB;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,UAAkC;AACxC,QAAI,UAAU;AACZ,WAAK,WAAW;AAAA,IAClB;AAEA,SAAK,SAAS,YAAY;AAE1B,UAAM,MAAM,GAAG,KAAK,QAAQ,KAAK,WAAW,mBAAmB,KAAK,QAAQ,MAAM,CAAC;AACnF,SAAK,KAAK,IAAI,UAAU,GAAG;AAE3B,SAAK,GAAG,SAAS,MAAM;AACrB,WAAK,oBAAoB;AACzB,WAAK,SAAS,WAAW;AACzB,WAAK,UAAU;AACf,WAAK,YAAY;AACjB,WAAK,SAAS,SAAS;AAAA,IACzB;AAEA,SAAK,GAAG,UAAU,CAAC,UAAU;AAC3B,WAAK,SAAS;AACd,WAAK,SAAS,UAAU,MAAM,MAAM,MAAM,MAAM;AAEhD,UAAI,KAAK,QAAQ,iBAAiB,KAAK,UAAU,gBAAgB;AAC/D,aAAK,kBAAkB;AAAA,MACzB,OAAO;AACL,aAAK,SAAS,cAAc;AAAA,MAC9B;AAAA,IACF;AAEA,SAAK,GAAG,UAAU,MAAM;AACtB,YAAM,QAAQ,IAAI,MAAM,4BAA4B;AACpD,WAAK,SAAS,UAAU,KAAK;AAAA,IAC/B;AAEA,SAAK,GAAG,YAAY,CAAC,UAAU;AAC7B,UAAI;AACF,cAAM,UAAU,KAAK,MAAM,MAAM,IAAI;AACrC,aAAK,cAAc,OAAO;AAAA,MAC5B,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,SAAS,cAAc;AAC5B,SAAK,SAAS;AACd,SAAK,oBAAoB;AAEzB,QAAI,KAAK,IAAI;AACX,WAAK,GAAG,MAAM,KAAM,mBAAmB;AACvC,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,SAAoB,MAAqB;AACjD,UAAM,MAAM,KAAK,gBAAgB,SAAS,IAAI;AAC9C,SAAK,cAAc,IAAI,GAAG;AAE1B,QAAI,KAAK,YAAY,GAAG;AACtB,WAAK,KAAK,EAAE,IAAI,aAAa,SAAS,KAAK,CAAC;AAAA,IAC9C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,MAAoB;AACrC,SAAK,UAAU,aAAa,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,MAAoB;AAClC,SAAK,UAAU,UAAU,IAAI;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,MAAoB;AAClC,SAAK,UAAU,UAAU,IAAI;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,sBAA4B;AAC1B,SAAK,UAAU,aAAa;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,SAAoB,MAAqB;AACnD,UAAM,MAAM,KAAK,gBAAgB,SAAS,IAAI;AAC9C,SAAK,cAAc,OAAO,GAAG;AAE7B,QAAI,KAAK,YAAY,GAAG;AACtB,WAAK,KAAK,EAAE,IAAI,eAAe,SAAS,KAAK,CAAC;AAAA,IAChD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB,MAAoB;AACvC,SAAK,YAAY,aAAa,IAAI;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,MAAoB;AACpC,SAAK,YAAY,UAAU,IAAI;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,MAAoB;AACpC,SAAK,YAAY,UAAU,IAAI;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,wBAA8B;AAC5B,SAAK,YAAY,aAAa;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,OACE,SACA,MACA,SAKM;AACN,SAAK,KAAK;AAAA,MACR,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,KAAK,QAAQ;AAAA,MACb,OAAO,QAAQ,SAAS;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,cAAoB;AAClB,SAAK,KAAK,EAAE,IAAI,eAAe,CAAC;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,eAAqB;AACnB,SAAK,KAAK,EAAE,IAAI,gBAAgB,CAAC;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,WAAyB;AAClC,SAAK,KAAK,EAAE,IAAI,eAAe,UAAU,CAAC;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,KAAK,EAAE,IAAI,cAAc,CAAC;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,OACE,SACA,MACA,SAKM;AACN,SAAK,KAAK;AAAA,MACR,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,KAAK,QAAQ;AAAA,MACb,YAAY,QAAQ,aAAa;AAAA,IACnC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,KAAK,EAAE,IAAI,cAAc,CAAC;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,iBACE,SACM;AACN,SAAK,uBAAuB,KAAK,OAAmE;AAAA,EACtG;AAAA;AAAA;AAAA;AAAA,EAKA,QACE,SACM;AACN,SAAK,cAAc,KAAK,OAAuF;AAAA,EACjH;AAAA;AAAA;AAAA;AAAA,EAKA,cACE,SACM;AACN,SAAK,oBAAoB,KAAK,OAAO;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,iBACE,SACM;AACN,SAAK,uBAAuB,KAAK,OAAO;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,cACE,SACM;AACN,SAAK,oBAAoB,KAAK,OAAO;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,iBACE,SACM;AACN,SAAK,uBAAuB,KAAK,OAAO;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,iBACE,SACM;AACN,SAAK,uBAAuB,KAAK,OAAO;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,WAA8B;AAC5B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,KAAK,IAAI,eAAe,UAAU;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,GAAoC,OAAU,SAAmC;AAC/E,SAAK,SAAS,KAAK,IAAI;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,SAAwD;AAClE,SAAK,kBAAkB,KAAK,OAAO;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,SAAsD;AAC7D,SAAK,eAAe,KAAK,OAAO;AAAA,EAClC;AAAA;AAAA,EAIQ,KAAK,SAAgC;AAC3C,QAAI,KAAK,IAAI,eAAe,UAAU,MAAM;AAC1C,WAAK,GAAG,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,IACtC;AAAA,EACF;AAAA,EAEQ,SAAS,OAAgC;AAC/C,SAAK,QAAQ;AACb,SAAK,SAAS,gBAAgB,KAAK;AAAA,EACrC;AAAA,EAEQ,YAAkB;AACxB,SAAK,SAAS;AACd,SAAK,YAAY,YAAY,MAAM;AACjC,WAAK,KAAK,EAAE,IAAI,OAAO,CAAC;AAAA,IAC1B,GAAG,KAAK,QAAQ,YAAY;AAAA,EAC9B;AAAA,EAEQ,WAAiB;AACvB,QAAI,KAAK,WAAW;AAClB,oBAAc,KAAK,SAAS;AAC5B,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA,EAEQ,gBAAgB,SAAoB,MAAuB;AACjE,WAAO,OAAO,GAAG,OAAO,IAAI,IAAI,KAAK;AAAA,EACvC;AAAA,EAEQ,cAAoB;AAC1B,eAAW,OAAO,KAAK,eAAe;AACpC,YAAM,CAAC,SAAS,IAAI,IAAI,IAAI,MAAM,GAAG;AACrC,WAAK,KAAK,EAAE,IAAI,aAAa,SAAS,KAAK,CAAC;AAAA,IAC9C;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,QAAI,KAAK,qBAAqB,KAAK,QAAQ,sBAAsB;AAC/D,WAAK,SAAS,cAAc;AAC5B;AAAA,IACF;AAEA,SAAK,SAAS,cAAc;AAC5B,SAAK;AAEL,UAAM,QAAQ,KAAK,QAAQ,iBAAiB,KAAK,IAAI,GAAG,KAAK,oBAAoB,CAAC;AAElF,SAAK,iBAAiB,WAAW,MAAM;AACrC,WAAK,QAAQ;AAAA,IACf,GAAG,KAAK;AAAA,EACV;AAAA,EAEQ,sBAA4B;AAClC,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,cAAc,SAAgC;AAEpD,SAAK,SAAS,YAAY,OAAO;AAGjC,YAAQ,QAAQ,MAAM;AAAA,MACpB,KAAK,mBAAmB;AACtB,cAAM,MAAM;AACZ,mBAAW,WAAW,KAAK,wBAAwB;AACjD,kBAAQ,IAAI,MAAM,IAAI,WAAW,IAAI,IAAI;AAAA,QAC3C;AACA;AAAA,MACF;AAAA,MACA,KAAK,oBAAoB;AACvB,cAAM,MAAM;AACZ,mBAAW,WAAW,KAAK,eAAe;AACxC,kBAAQ,IAAI,MAAM,IAAI,IAAmD;AAAA,QAC3E;AACA;AAAA,MACF;AAAA,MACA,KAAK,kBAAkB;AACrB,cAAM,MAAM;AACZ,mBAAW,WAAW,KAAK,qBAAqB;AAC9C,kBAAQ,IAAI,SAAS,IAAI,MAAM,IAAI,OAAO,IAAI,KAAK,IAAI,KAAK;AAAA,QAC9D;AACA;AAAA,MACF;AAAA,MACA,KAAK,oBAAoB;AACvB,cAAM,MAAM;AACZ,mBAAW,WAAW,KAAK,wBAAwB;AACjD,kBAAQ,IAAI,SAAS,IAAI,MAAM,IAAI,cAAc;AAAA,QACnD;AACA;AAAA,MACF;AAAA,MACA,KAAK,kBAAkB;AACrB,cAAM,MAAM;AACZ,mBAAW,WAAW,KAAK,qBAAqB;AAC9C,kBAAQ,IAAI,SAAS,IAAI,MAAM,IAAI,OAAO,IAAI,GAAG;AAAA,QACnD;AACA;AAAA,MACF;AAAA,MACA,KAAK,mBAAmB;AACtB,cAAM,MAAM;AACZ,mBAAW,WAAW,KAAK,wBAAwB;AACjD,kBAAQ,IAAI,cAAc;AAAA,QAC5B;AACA;AAAA,MACF;AAAA,MACA,KAAK,oBAAoB;AACvB,cAAM,MAAM;AACZ,mBAAW,WAAW,KAAK,wBAAwB;AACjD,kBAAQ,IAAI,SAAS,IAAI,MAAM,IAAI,cAAc;AAAA,QACnD;AACA;AAAA,MACF;AAAA,MACA,KAAK,QAAQ;AACX,YAAI,QAAQ,YAAY,aAAa;AAEnC,gBAAM,YAAY,mBAAmB,QAAQ,MAAM,QAAQ,IAA+B;AAC1F,qBAAW,WAAW,KAAK,mBAAmB;AAC5C,oBAAQ,QAAQ,MAAM,SAAS;AAAA,UACjC;AAAA,QACF,WAAW,QAAQ,YAAY,UAAU;AACvC,qBAAW,WAAW,KAAK,gBAAgB;AACzC,oBAAQ,QAAQ,MAAM,QAAQ,IAAe;AAAA,UAC/C;AAAA,QACF;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/http.ts","../src/resources/orderbook.ts","../src/resources/trades.ts","../src/resources/instruments.ts","../src/resources/funding.ts","../src/resources/openinterest.ts","../src/client.ts","../src/websocket.ts"],"sourcesContent":["/**\r\n * @0xarchive/sdk - Official TypeScript SDK for 0xarchive\r\n *\r\n * @example\r\n * ```typescript\r\n * import { OxArchive } from '@0xarchive/sdk';\r\n *\r\n * const client = new OxArchive({ apiKey: 'ox_your_api_key' });\r\n *\r\n * // Get current order book\r\n * const orderbook = await client.orderbook.get('BTC');\r\n *\r\n * // Get historical snapshots\r\n * const history = await client.orderbook.history('ETH', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now()\r\n * });\r\n * ```\r\n *\r\n * @packageDocumentation\r\n */\r\n\r\n// Main client\r\nexport { OxArchive } from './client';\r\n\r\n// WebSocket client\r\nexport { OxArchiveWs } from './websocket';\r\n\r\n// Types\r\nexport type {\r\n ClientOptions,\r\n ApiMeta,\r\n ApiResponse,\r\n PaginationParams,\r\n TimeRangeParams,\r\n Timestamp,\r\n // Order Book\r\n PriceLevel,\r\n OrderBook,\r\n GetOrderBookParams,\r\n OrderBookHistoryParams,\r\n // Trades\r\n Trade,\r\n GetTradesParams,\r\n TradeSide,\r\n TradeDirection,\r\n DataSource,\r\n // Instruments\r\n Instrument,\r\n InstrumentType,\r\n // Funding\r\n FundingRate,\r\n // Open Interest\r\n OpenInterest,\r\n // WebSocket\r\n WsChannel,\r\n WsOptions,\r\n WsClientMessage,\r\n WsServerMessage,\r\n WsConnectionState,\r\n WsEventHandlers,\r\n WsSubscribe,\r\n WsUnsubscribe,\r\n WsPing,\r\n WsSubscribed,\r\n WsUnsubscribed,\r\n WsPong,\r\n WsError,\r\n WsData,\r\n // WebSocket Replay (Option B)\r\n WsReplay,\r\n WsReplayPause,\r\n WsReplayResume,\r\n WsReplaySeek,\r\n WsReplayStop,\r\n WsReplayStarted,\r\n WsReplayPaused,\r\n WsReplayResumed,\r\n WsReplayCompleted,\r\n WsReplayStopped,\r\n WsHistoricalData,\r\n // WebSocket Bulk Stream (Option D)\r\n WsStream,\r\n WsStreamStop,\r\n WsStreamStarted,\r\n WsStreamProgress,\r\n TimestampedRecord,\r\n WsHistoricalBatch,\r\n WsStreamCompleted,\r\n WsStreamStopped,\r\n // Errors\r\n ApiError,\r\n} from './types';\r\n\r\nexport { OxArchiveError } from './types';\r\n\r\n// Default export for convenience\r\nexport { OxArchive as default } from './client';\r\n","/**\r\n * Configuration options for the 0xarchive client\r\n */\r\nexport interface ClientOptions {\r\n /** Your 0xarchive API key */\r\n apiKey: string;\r\n /** Base URL for the API (defaults to https://api.0xarchive.io) */\r\n baseUrl?: string;\r\n /** Request timeout in milliseconds (defaults to 30000) */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Response metadata\r\n */\r\nexport interface ApiMeta {\r\n /** Number of records returned */\r\n count: number;\r\n /** Cursor for next page (if available) */\r\n next_cursor?: string;\r\n /** Unique request ID for debugging */\r\n request_id: string;\r\n}\r\n\r\n/**\r\n * Standard API response wrapper\r\n */\r\nexport interface ApiResponse<T> {\r\n success: boolean;\r\n data: T;\r\n meta: ApiMeta;\r\n}\r\n\r\n/**\r\n * Pagination parameters for list endpoints\r\n * @deprecated Use cursor-based pagination instead (CursorPaginationParams)\r\n */\r\nexport interface PaginationParams {\r\n /** Maximum number of results to return */\r\n limit?: number;\r\n /** @deprecated Use cursor instead. Number of results to skip */\r\n offset?: number;\r\n}\r\n\r\n/**\r\n * Time range parameters for historical queries\r\n * @deprecated Use CursorPaginationParams for better performance with large datasets\r\n */\r\nexport interface TimeRangeParams extends PaginationParams {\r\n /** Start timestamp (Unix ms or ISO string) - REQUIRED for history endpoints */\r\n start: number | string;\r\n /** End timestamp (Unix ms or ISO string) - REQUIRED for history endpoints */\r\n end: number | string;\r\n}\r\n\r\n// =============================================================================\r\n// Order Book Types\r\n// =============================================================================\r\n\r\n/**\r\n * A price level in the order book\r\n */\r\nexport interface PriceLevel {\r\n /** Price at this level */\r\n px: string;\r\n /** Total size at this price level */\r\n sz: string;\r\n /** Number of orders at this level */\r\n n: number;\r\n}\r\n\r\n/**\r\n * Order book snapshot\r\n */\r\nexport interface OrderBook {\r\n /** Trading pair symbol (e.g., BTC, ETH) */\r\n coin: string;\r\n /** Snapshot timestamp (UTC) */\r\n timestamp: string;\r\n /** Bid price levels (best bid first) */\r\n bids: PriceLevel[];\r\n /** Ask price levels (best ask first) */\r\n asks: PriceLevel[];\r\n /** Mid price (best bid + best ask) / 2 */\r\n mid_price?: string;\r\n /** Spread in absolute terms (best ask - best bid) */\r\n spread?: string;\r\n /** Spread in basis points */\r\n spread_bps?: string;\r\n}\r\n\r\nexport interface GetOrderBookParams {\r\n /** Timestamp to get order book at (Unix ms or ISO string) */\r\n timestamp?: number | string;\r\n /** Number of price levels to return per side */\r\n depth?: number;\r\n}\r\n\r\nexport interface OrderBookHistoryParams extends TimeRangeParams {\r\n /** Number of price levels to return per side */\r\n depth?: number;\r\n}\r\n\r\n// =============================================================================\r\n// Trade/Fill Types\r\n// =============================================================================\r\n\r\n/** Trade side: 'A' (ask/sell) or 'B' (bid/buy) */\r\nexport type TradeSide = 'A' | 'B';\r\n\r\n/** Position direction */\r\nexport type TradeDirection = 'Open Long' | 'Open Short' | 'Close Long' | 'Close Short';\r\n\r\n/** Data source */\r\nexport type DataSource = 's3' | 'ws' | 'api';\r\n\r\n/**\r\n * Trade/fill record with full execution details\r\n */\r\nexport interface Trade {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Trade side: 'A' (ask/sell) or 'B' (bid/buy) */\r\n side: TradeSide;\r\n /** Execution price */\r\n price: string;\r\n /** Trade size */\r\n size: string;\r\n /** Execution timestamp (UTC) */\r\n timestamp: string;\r\n /** Blockchain transaction hash */\r\n tx_hash?: string;\r\n /** Unique trade ID */\r\n trade_id?: number;\r\n /** Associated order ID */\r\n order_id?: number;\r\n /** True if taker (crossed the spread), false if maker */\r\n crossed?: boolean;\r\n /** Trading fee amount */\r\n fee?: string;\r\n /** Fee denomination (e.g., USDC) */\r\n fee_token?: string;\r\n /** Realized PnL if closing a position */\r\n closed_pnl?: string;\r\n /** Position direction */\r\n direction?: TradeDirection;\r\n /** Position size before this trade */\r\n start_position?: string;\r\n /** Data source */\r\n source?: DataSource;\r\n /** User's wallet address */\r\n user_address?: string;\r\n}\r\n\r\n/**\r\n * @deprecated Use GetTradesCursorParams instead for better performance with large datasets\r\n */\r\nexport interface GetTradesParams extends TimeRangeParams {\r\n /** Filter by side */\r\n side?: TradeSide;\r\n}\r\n\r\n/**\r\n * Cursor-based pagination parameters for trades (recommended)\r\n * More efficient than offset-based pagination for large datasets.\r\n * The cursor is a timestamp - use the `nextCursor` from the response to get the next page.\r\n */\r\nexport interface CursorPaginationParams {\r\n /** Start timestamp (Unix ms or ISO string) - REQUIRED */\r\n start: number | string;\r\n /** End timestamp (Unix ms or ISO string) - REQUIRED */\r\n end: number | string;\r\n /** Cursor from previous response's nextCursor (timestamp). If not provided, starts from the beginning of the range. */\r\n cursor?: number | string;\r\n /** Maximum number of results to return (default: 100, max: 1000) */\r\n limit?: number;\r\n}\r\n\r\n/**\r\n * Parameters for getting trades with cursor-based pagination (recommended)\r\n */\r\nexport interface GetTradesCursorParams extends CursorPaginationParams {\r\n /** Filter by side */\r\n side?: TradeSide;\r\n}\r\n\r\n/**\r\n * Response with cursor for pagination\r\n */\r\nexport interface CursorResponse<T> {\r\n data: T;\r\n /** Cursor for next page (use as cursor parameter) */\r\n nextCursor?: string;\r\n}\r\n\r\n// =============================================================================\r\n// Instruments Types\r\n// =============================================================================\r\n\r\n/** Instrument type */\r\nexport type InstrumentType = 'perp' | 'spot';\r\n\r\n/**\r\n * Trading instrument metadata\r\n */\r\nexport interface Instrument {\r\n /** Instrument symbol (e.g., BTC) */\r\n name: string;\r\n /** Size decimal precision */\r\n szDecimals: number;\r\n /** Maximum leverage allowed */\r\n maxLeverage?: number;\r\n /** If true, only isolated margin mode is allowed */\r\n onlyIsolated?: boolean;\r\n /** Type of instrument */\r\n instrumentType?: InstrumentType;\r\n /** Whether the instrument is currently tradeable */\r\n isActive: boolean;\r\n}\r\n\r\n// =============================================================================\r\n// Funding Types\r\n// =============================================================================\r\n\r\n/**\r\n * Funding rate record\r\n */\r\nexport interface FundingRate {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Funding timestamp (UTC) */\r\n timestamp: string;\r\n /** Funding rate as decimal (e.g., 0.0001 = 0.01%) */\r\n funding_rate: string;\r\n /** Premium component of funding rate */\r\n premium?: string;\r\n}\r\n\r\n// =============================================================================\r\n// Open Interest Types\r\n// =============================================================================\r\n\r\n/**\r\n * Open interest snapshot with market context\r\n */\r\nexport interface OpenInterest {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Snapshot timestamp (UTC) */\r\n timestamp: string;\r\n /** Total open interest in contracts */\r\n open_interest: string;\r\n /** Mark price used for liquidations */\r\n mark_price?: string;\r\n /** Oracle price from external feed */\r\n oracle_price?: string;\r\n /** 24-hour notional volume */\r\n day_ntl_volume?: string;\r\n /** Price 24 hours ago */\r\n prev_day_price?: string;\r\n /** Current mid price */\r\n mid_price?: string;\r\n /** Impact bid price for liquidations */\r\n impact_bid_price?: string;\r\n /** Impact ask price for liquidations */\r\n impact_ask_price?: string;\r\n}\r\n\r\n// =============================================================================\r\n// WebSocket Types\r\n// =============================================================================\r\n\r\n/** WebSocket channel types. Note: ticker/all_tickers are real-time only. */\r\nexport type WsChannel = 'orderbook' | 'trades' | 'ticker' | 'all_tickers';\r\n\r\n/** Subscribe message from client */\r\nexport interface WsSubscribe {\r\n op: 'subscribe';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Unsubscribe message from client */\r\nexport interface WsUnsubscribe {\r\n op: 'unsubscribe';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Ping message from client */\r\nexport interface WsPing {\r\n op: 'ping';\r\n}\r\n\r\n/** Replay message from client - replays historical data with timing preserved */\r\nexport interface WsReplay {\r\n op: 'replay';\r\n channel: WsChannel;\r\n coin?: string;\r\n /** Start timestamp (Unix ms) */\r\n start: number;\r\n /** End timestamp (Unix ms, defaults to now) */\r\n end?: number;\r\n /** Playback speed multiplier (1 = real-time, 10 = 10x faster) */\r\n speed?: number;\r\n}\r\n\r\n/** Replay control messages */\r\nexport interface WsReplayPause { op: 'replay.pause'; }\r\nexport interface WsReplayResume { op: 'replay.resume'; }\r\nexport interface WsReplaySeek { op: 'replay.seek'; timestamp: number; }\r\nexport interface WsReplayStop { op: 'replay.stop'; }\r\n\r\n/** Stream message from client - bulk download historical data */\r\nexport interface WsStream {\r\n op: 'stream';\r\n channel: WsChannel;\r\n coin?: string;\r\n /** Start timestamp (Unix ms) */\r\n start: number;\r\n /** End timestamp (Unix ms) */\r\n end: number;\r\n /** Batch size (records per message) */\r\n batch_size?: number;\r\n}\r\n\r\n/** Stream control messages */\r\nexport interface WsStreamStop { op: 'stream.stop'; }\r\n\r\n/** Client message union type */\r\nexport type WsClientMessage =\r\n | WsSubscribe\r\n | WsUnsubscribe\r\n | WsPing\r\n | WsReplay\r\n | WsReplayPause\r\n | WsReplayResume\r\n | WsReplaySeek\r\n | WsReplayStop\r\n | WsStream\r\n | WsStreamStop;\r\n\r\n/** Subscription confirmed from server */\r\nexport interface WsSubscribed {\r\n type: 'subscribed';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Unsubscription confirmed from server */\r\nexport interface WsUnsubscribed {\r\n type: 'unsubscribed';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Pong response from server */\r\nexport interface WsPong {\r\n type: 'pong';\r\n}\r\n\r\n/** Error from server */\r\nexport interface WsError {\r\n type: 'error';\r\n message: string;\r\n}\r\n\r\n/** Data message from server (real-time) */\r\nexport interface WsData<T = unknown> {\r\n type: 'data';\r\n channel: WsChannel;\r\n coin: string;\r\n data: T;\r\n}\r\n\r\n/** Replay started response */\r\nexport interface WsReplayStarted {\r\n type: 'replay_started';\r\n channel: WsChannel;\r\n coin: string;\r\n /** Start timestamp in milliseconds */\r\n start: number;\r\n /** End timestamp in milliseconds */\r\n end: number;\r\n /** Playback speed multiplier */\r\n speed: number;\r\n}\r\n\r\n/** Replay paused response */\r\nexport interface WsReplayPaused {\r\n type: 'replay_paused';\r\n current_timestamp: number;\r\n}\r\n\r\n/** Replay resumed response */\r\nexport interface WsReplayResumed {\r\n type: 'replay_resumed';\r\n current_timestamp: number;\r\n}\r\n\r\n/** Replay completed response */\r\nexport interface WsReplayCompleted {\r\n type: 'replay_completed';\r\n channel: WsChannel;\r\n coin: string;\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Replay stopped response */\r\nexport interface WsReplayStopped {\r\n type: 'replay_stopped';\r\n}\r\n\r\n/** Historical data point (replay mode) */\r\nexport interface WsHistoricalData<T = unknown> {\r\n type: 'historical_data';\r\n channel: WsChannel;\r\n coin: string;\r\n timestamp: number;\r\n data: T;\r\n}\r\n\r\n/** Stream started response */\r\nexport interface WsStreamStarted {\r\n type: 'stream_started';\r\n channel: WsChannel;\r\n coin: string;\r\n /** Start timestamp in milliseconds */\r\n start: number;\r\n /** End timestamp in milliseconds */\r\n end: number;\r\n}\r\n\r\n/** Stream progress response (sent periodically during streaming) */\r\nexport interface WsStreamProgress {\r\n type: 'stream_progress';\r\n snapshots_sent: number;\r\n}\r\n\r\n/** A record with timestamp for batched data */\r\nexport interface TimestampedRecord<T = unknown> {\r\n timestamp: number;\r\n data: T;\r\n}\r\n\r\n/** Batch of historical data (bulk streaming) */\r\nexport interface WsHistoricalBatch<T = unknown> {\r\n type: 'historical_batch';\r\n channel: WsChannel;\r\n coin: string;\r\n data: TimestampedRecord<T>[];\r\n}\r\n\r\n/** Stream completed response */\r\nexport interface WsStreamCompleted {\r\n type: 'stream_completed';\r\n channel: WsChannel;\r\n coin: string;\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Stream stopped response */\r\nexport interface WsStreamStopped {\r\n type: 'stream_stopped';\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Server message union type */\r\nexport type WsServerMessage =\r\n | WsSubscribed\r\n | WsUnsubscribed\r\n | WsPong\r\n | WsError\r\n | WsData\r\n | WsReplayStarted\r\n | WsReplayPaused\r\n | WsReplayResumed\r\n | WsReplayCompleted\r\n | WsReplayStopped\r\n | WsHistoricalData\r\n | WsStreamStarted\r\n | WsStreamProgress\r\n | WsHistoricalBatch\r\n | WsStreamCompleted\r\n | WsStreamStopped;\r\n\r\n/**\r\n * WebSocket connection options.\r\n *\r\n * The server sends WebSocket ping frames every 30 seconds and will disconnect\r\n * idle connections after 60 seconds. The SDK automatically handles keep-alive\r\n * by sending application-level pings at the configured interval.\r\n */\r\nexport interface WsOptions {\r\n /** API key for authentication */\r\n apiKey: string;\r\n /** WebSocket URL (defaults to wss://api.0xarchive.io/ws) */\r\n wsUrl?: string;\r\n /** Auto-reconnect on disconnect (defaults to true) */\r\n autoReconnect?: boolean;\r\n /** Reconnect delay in ms (defaults to 1000) */\r\n reconnectDelay?: number;\r\n /** Maximum reconnect attempts (defaults to 10) */\r\n maxReconnectAttempts?: number;\r\n /** Ping interval in ms to keep connection alive (defaults to 30000). Server disconnects after 60s idle. */\r\n pingInterval?: number;\r\n}\r\n\r\n/** WebSocket connection state */\r\nexport type WsConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';\r\n\r\n/** WebSocket event handlers */\r\nexport interface WsEventHandlers {\r\n onOpen?: () => void;\r\n onClose?: (code: number, reason: string) => void;\r\n onError?: (error: Error) => void;\r\n onMessage?: (message: WsServerMessage) => void;\r\n onStateChange?: (state: WsConnectionState) => void;\r\n}\r\n\r\n// =============================================================================\r\n// Error Types\r\n// =============================================================================\r\n\r\n/**\r\n * API error response\r\n */\r\nexport interface ApiError {\r\n code: number;\r\n error: string;\r\n}\r\n\r\n/**\r\n * SDK error class\r\n */\r\nexport class OxArchiveError extends Error {\r\n code: number;\r\n requestId?: string;\r\n\r\n constructor(message: string, code: number, requestId?: string) {\r\n super(message);\r\n this.name = 'OxArchiveError';\r\n this.code = code;\r\n this.requestId = requestId;\r\n }\r\n}\r\n\r\n/** Timestamp can be Unix ms (number), ISO string, or Date object */\r\nexport type Timestamp = number | string | Date;\r\n","import type { ApiResponse, ApiError } from './types';\r\nimport { OxArchiveError } from './types';\r\n\r\nexport interface HttpClientOptions {\r\n baseUrl: string;\r\n apiKey: string;\r\n timeout: number;\r\n}\r\n\r\n/**\r\n * Internal HTTP client for making API requests\r\n */\r\nexport class HttpClient {\r\n private baseUrl: string;\r\n private apiKey: string;\r\n private timeout: number;\r\n\r\n constructor(options: HttpClientOptions) {\r\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\r\n this.apiKey = options.apiKey;\r\n this.timeout = options.timeout;\r\n }\r\n\r\n /**\r\n * Make a GET request to the API\r\n */\r\n async get<T>(path: string, params?: Record<string, unknown>): Promise<T> {\r\n const url = new URL(`${this.baseUrl}${path}`);\r\n\r\n if (params) {\r\n for (const [key, value] of Object.entries(params)) {\r\n if (value !== undefined && value !== null) {\r\n url.searchParams.set(key, String(value));\r\n }\r\n }\r\n }\r\n\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url.toString(), {\r\n method: 'GET',\r\n headers: {\r\n 'X-API-Key': this.apiKey,\r\n 'Content-Type': 'application/json',\r\n },\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n const data = await response.json();\r\n\r\n if (!response.ok) {\r\n const error = data as ApiError;\r\n throw new OxArchiveError(\r\n error.error || `Request failed with status ${response.status}`,\r\n response.status,\r\n (data as ApiResponse<unknown>).meta?.request_id\r\n );\r\n }\r\n\r\n return data as T;\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof OxArchiveError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof Error && error.name === 'AbortError') {\r\n throw new OxArchiveError(`Request timeout after ${this.timeout}ms`, 408);\r\n }\r\n\r\n throw new OxArchiveError(\r\n error instanceof Error ? error.message : 'Unknown error',\r\n 500\r\n );\r\n }\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type {\r\n ApiResponse,\r\n OrderBook,\r\n GetOrderBookParams,\r\n OrderBookHistoryParams,\r\n} from '../types';\r\n\r\n/**\r\n * Order book API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current order book\r\n * const orderbook = await client.orderbook.get('BTC');\r\n *\r\n * // Get order book at specific timestamp\r\n * const historical = await client.orderbook.get('ETH', {\r\n * timestamp: 1704067200000,\r\n * depth: 10\r\n * });\r\n *\r\n * // Get order book history\r\n * const history = await client.orderbook.history('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n * ```\r\n */\r\nexport class OrderBookResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get order book snapshot for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Optional parameters\r\n * @returns Order book snapshot\r\n */\r\n async get(coin: string, params?: GetOrderBookParams): Promise<OrderBook> {\r\n const response = await this.http.get<ApiResponse<OrderBook>>(\r\n `/v1/orderbook/${coin.toUpperCase()}`,\r\n params as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get historical order book snapshots\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of order book snapshots\r\n */\r\n async history(\r\n coin: string,\r\n params: OrderBookHistoryParams\r\n ): Promise<OrderBook[]> {\r\n const response = await this.http.get<ApiResponse<OrderBook[]>>(\r\n `/v1/orderbook/${coin.toUpperCase()}/history`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, Trade, GetTradesParams, GetTradesCursorParams, CursorResponse } from '../types';\r\n\r\n/**\r\n * Trades API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get recent trades\r\n * const trades = await client.trades.recent('BTC');\r\n *\r\n * // Get trade history with cursor-based pagination (recommended)\r\n * let result = await client.trades.list('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 1000\r\n * });\r\n *\r\n * // Get all pages\r\n * const allTrades = [...result.data];\r\n * while (result.nextCursor) {\r\n * result = await client.trades.list('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * cursor: result.nextCursor,\r\n * limit: 1000\r\n * });\r\n * allTrades.push(...result.data);\r\n * }\r\n * ```\r\n */\r\nexport class TradesResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get trade history for a coin using cursor-based pagination\r\n *\r\n * Uses cursor-based pagination by default, which is more efficient for large datasets.\r\n * Use the `nextCursor` from the response as the `cursor` parameter to get the next page.\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and cursor pagination parameters (start and end are required)\r\n * @returns Object with trades array and nextCursor for pagination\r\n *\r\n * @example\r\n * ```typescript\r\n * // First page\r\n * let result = await client.trades.list('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 1000\r\n * });\r\n *\r\n * // Subsequent pages\r\n * while (result.nextCursor) {\r\n * result = await client.trades.list('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * cursor: result.nextCursor,\r\n * limit: 1000\r\n * });\r\n * }\r\n * ```\r\n */\r\n async list(coin: string, params: GetTradesCursorParams): Promise<CursorResponse<Trade[]>> {\r\n const response = await this.http.get<ApiResponse<Trade[]>>(\r\n `/v1/trades/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return {\r\n data: response.data,\r\n nextCursor: response.meta.next_cursor,\r\n };\r\n }\r\n\r\n /**\r\n * Get most recent trades for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param limit - Number of trades to return (default: 100)\r\n * @returns Array of recent trades\r\n */\r\n async recent(coin: string, limit?: number): Promise<Trade[]> {\r\n const response = await this.http.get<ApiResponse<Trade[]>>(\r\n `/v1/trades/${coin.toUpperCase()}/recent`,\r\n { limit }\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get trade history using cursor-based pagination (explicit endpoint)\r\n *\r\n * @deprecated Use `list()` instead - it now uses cursor-based pagination by default.\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Cursor pagination parameters (start and end are required)\r\n * @returns Object with trades array and nextCursor for pagination\r\n */\r\n async listWithCursor(coin: string, params: GetTradesCursorParams): Promise<CursorResponse<Trade[]>> {\r\n // Now just calls the main endpoint since it supports cursor by default\r\n return this.list(coin, params);\r\n }\r\n\r\n /**\r\n * Get trade history using offset-based pagination\r\n *\r\n * @deprecated Use `list()` with cursor-based pagination instead for better performance.\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and offset pagination parameters\r\n * @returns Array of trades (without cursor response wrapper)\r\n */\r\n async listWithOffset(coin: string, params: GetTradesParams): Promise<Trade[]> {\r\n const response = await this.http.get<ApiResponse<Trade[]>>(\r\n `/v1/trades/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, Instrument } from '../types';\r\n\r\n/**\r\n * Instruments API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // List all instruments\r\n * const instruments = await client.instruments.list();\r\n *\r\n * // Get specific instrument\r\n * const btc = await client.instruments.get('BTC');\r\n * ```\r\n */\r\nexport class InstrumentsResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * List all available trading instruments\r\n *\r\n * @returns Array of instruments\r\n */\r\n async list(): Promise<Instrument[]> {\r\n const response = await this.http.get<ApiResponse<Instrument[]>>(\r\n '/v1/instruments'\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get a specific instrument by coin symbol\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Instrument details\r\n */\r\n async get(coin: string): Promise<Instrument> {\r\n const response = await this.http.get<ApiResponse<Instrument>>(\r\n `/v1/instruments/${coin.toUpperCase()}`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, FundingRate, TimeRangeParams } from '../types';\r\n\r\n/**\r\n * Funding rates API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current funding rate\r\n * const current = await client.funding.current('BTC');\r\n *\r\n * // Get funding rate history\r\n * const history = await client.funding.history('ETH', {\r\n * start: Date.now() - 86400000 * 7,\r\n * end: Date.now()\r\n * });\r\n * ```\r\n */\r\nexport class FundingResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get funding rate history for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of funding rate records\r\n */\r\n async history(coin: string, params: TimeRangeParams): Promise<FundingRate[]> {\r\n const response = await this.http.get<ApiResponse<FundingRate[]>>(\r\n `/v1/funding/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get current funding rate for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Current funding rate\r\n */\r\n async current(coin: string): Promise<FundingRate> {\r\n const response = await this.http.get<ApiResponse<FundingRate>>(\r\n `/v1/funding/${coin.toUpperCase()}/current`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, OpenInterest, TimeRangeParams } from '../types';\r\n\r\n/**\r\n * Open interest API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current open interest\r\n * const current = await client.openInterest.current('BTC');\r\n *\r\n * // Get open interest history\r\n * const history = await client.openInterest.history('ETH', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n * ```\r\n */\r\nexport class OpenInterestResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get open interest history for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of open interest records\r\n */\r\n async history(coin: string, params: TimeRangeParams): Promise<OpenInterest[]> {\r\n const response = await this.http.get<ApiResponse<OpenInterest[]>>(\r\n `/v1/openinterest/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get current open interest for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Current open interest\r\n */\r\n async current(coin: string): Promise<OpenInterest> {\r\n const response = await this.http.get<ApiResponse<OpenInterest>>(\r\n `/v1/openinterest/${coin.toUpperCase()}/current`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { ClientOptions } from './types';\r\nimport { HttpClient } from './http';\r\nimport {\r\n OrderBookResource,\r\n TradesResource,\r\n InstrumentsResource,\r\n FundingResource,\r\n OpenInterestResource,\r\n} from './resources';\r\n\r\nconst DEFAULT_BASE_URL = 'https://api.0xarchive.io';\r\nconst DEFAULT_TIMEOUT = 30000;\r\n\r\n/**\r\n * 0xarchive API client\r\n *\r\n * @example\r\n * ```typescript\r\n * import { OxArchive } from '@0xarchive/sdk';\r\n *\r\n * const client = new OxArchive({ apiKey: 'ox_your_api_key' });\r\n *\r\n * // Get current order book\r\n * const orderbook = await client.orderbook.get('BTC');\r\n * console.log(`BTC mid price: ${orderbook.mid_price}`);\r\n *\r\n * // Get historical data\r\n * const history = await client.orderbook.history('ETH', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n *\r\n * // List all instruments\r\n * const instruments = await client.instruments.list();\r\n * ```\r\n */\r\nexport class OxArchive {\r\n private http: HttpClient;\r\n\r\n /**\r\n * Order book data (L2 snapshots from April 2023)\r\n */\r\n public readonly orderbook: OrderBookResource;\r\n\r\n /**\r\n * Trade/fill history\r\n */\r\n public readonly trades: TradesResource;\r\n\r\n /**\r\n * Trading instruments metadata\r\n */\r\n public readonly instruments: InstrumentsResource;\r\n\r\n /**\r\n * Funding rates\r\n */\r\n public readonly funding: FundingResource;\r\n\r\n /**\r\n * Open interest\r\n */\r\n public readonly openInterest: OpenInterestResource;\r\n\r\n /**\r\n * Create a new 0xarchive client\r\n *\r\n * @param options - Client configuration options\r\n */\r\n constructor(options: ClientOptions) {\r\n if (!options.apiKey) {\r\n throw new Error('API key is required. Get one at https://0xarchive.io/signup');\r\n }\r\n\r\n this.http = new HttpClient({\r\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\r\n apiKey: options.apiKey,\r\n timeout: options.timeout ?? DEFAULT_TIMEOUT,\r\n });\r\n\r\n // Initialize resource namespaces\r\n this.orderbook = new OrderBookResource(this.http);\r\n this.trades = new TradesResource(this.http);\r\n this.instruments = new InstrumentsResource(this.http);\r\n this.funding = new FundingResource(this.http);\r\n this.openInterest = new OpenInterestResource(this.http);\r\n }\r\n}\r\n","/**\r\n * WebSocket client for 0xarchive real-time streaming, replay, and bulk download\r\n *\r\n * @example Real-time streaming\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect({\r\n * onMessage: (msg) => console.log(msg)\r\n * });\r\n * ws.subscribeOrderbook('BTC');\r\n * ```\r\n *\r\n * @example Historical replay (like Tardis.dev)\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect();\r\n * ws.onHistoricalData((coin, timestamp, data) => {\r\n * console.log(`${new Date(timestamp)}: ${data.mid_price}`);\r\n * });\r\n * ws.replay('orderbook', 'BTC', {\r\n * start: Date.now() - 86400000,\r\n * speed: 10 // 10x speed\r\n * });\r\n * ```\r\n *\r\n * @example Bulk streaming (like Databento)\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect();\r\n * const batches: OrderBook[] = [];\r\n * ws.onBatch((coin, records) => {\r\n * batches.push(...records.map(r => r.data));\r\n * });\r\n * ws.onStreamComplete((channel, coin, count) => {\r\n * console.log(`Downloaded ${count} records`);\r\n * });\r\n * ws.stream('orderbook', 'ETH', {\r\n * start: Date.now() - 3600000,\r\n * end: Date.now(),\r\n * batchSize: 1000\r\n * });\r\n * ```\r\n */\r\n\r\nimport type {\r\n WsOptions,\r\n WsChannel,\r\n WsClientMessage,\r\n WsServerMessage,\r\n WsConnectionState,\r\n WsEventHandlers,\r\n OrderBook,\r\n PriceLevel,\r\n Trade,\r\n WsHistoricalData,\r\n WsHistoricalBatch,\r\n WsReplayStarted,\r\n WsReplayCompleted,\r\n WsStreamStarted,\r\n WsStreamCompleted,\r\n WsStreamProgress,\r\n} from './types';\r\n\r\nconst DEFAULT_WS_URL = 'wss://api.0xarchive.io/ws';\r\nconst DEFAULT_PING_INTERVAL = 30000; // 30 seconds\r\nconst DEFAULT_RECONNECT_DELAY = 1000;\r\nconst DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;\r\n\r\n// Server idle timeout is 60 seconds. The SDK sends pings every 30 seconds\r\n// to keep the connection alive. Browser WebSocket API automatically responds\r\n// to WebSocket protocol-level ping frames from the server.\r\n\r\n/**\r\n * Transform raw Hyperliquid orderbook format to SDK OrderBook type.\r\n * Raw format: { coin, levels: [[{px, sz, n}, ...], [{px, sz, n}, ...]], time }\r\n * SDK format: { coin, timestamp, bids: [{px, sz, n}], asks: [{px, sz, n}], mid_price, spread, spread_bps }\r\n */\r\nfunction transformOrderbook(coin: string, raw: Record<string, unknown>): OrderBook {\r\n // Check if already in SDK format (from REST API or historical replay)\r\n if ('bids' in raw && 'asks' in raw) {\r\n return raw as unknown as OrderBook;\r\n }\r\n\r\n // Transform from Hyperliquid raw format\r\n // levels is [[{px, sz, n}, ...], [{px, sz, n}, ...]] where [0]=bids, [1]=asks\r\n const levels = raw.levels as Array<Array<{ px: string; sz: string; n: number }>> | undefined;\r\n const time = raw.time as number | undefined;\r\n\r\n const bids: PriceLevel[] = [];\r\n const asks: PriceLevel[] = [];\r\n\r\n if (levels && levels.length >= 2) {\r\n // levels[0] = bids, levels[1] = asks\r\n // Each level is already {px, sz, n} object\r\n for (const level of levels[0] || []) {\r\n bids.push({ px: level.px, sz: level.sz, n: level.n });\r\n }\r\n for (const level of levels[1] || []) {\r\n asks.push({ px: level.px, sz: level.sz, n: level.n });\r\n }\r\n }\r\n\r\n // Calculate mid price and spread\r\n let mid_price: string | undefined;\r\n let spread: string | undefined;\r\n let spread_bps: string | undefined;\r\n\r\n if (bids.length > 0 && asks.length > 0) {\r\n const bestBid = parseFloat(bids[0].px);\r\n const bestAsk = parseFloat(asks[0].px);\r\n const mid = (bestBid + bestAsk) / 2;\r\n mid_price = mid.toString();\r\n spread = (bestAsk - bestBid).toString();\r\n spread_bps = ((bestAsk - bestBid) / mid * 10000).toFixed(2);\r\n }\r\n\r\n return {\r\n coin,\r\n timestamp: time ? new Date(time).toISOString() : new Date().toISOString(),\r\n bids,\r\n asks,\r\n mid_price,\r\n spread,\r\n spread_bps,\r\n };\r\n}\r\n\r\n/**\r\n * WebSocket client for real-time data streaming.\r\n *\r\n * **Keep-Alive:** The server sends WebSocket ping frames every 30 seconds\r\n * and will disconnect idle connections after 60 seconds. This SDK automatically\r\n * handles keep-alive by sending application-level pings at the configured interval\r\n * (default: 30 seconds). The browser WebSocket API automatically responds to\r\n * server ping frames.\r\n */\r\nexport class OxArchiveWs {\r\n private ws: WebSocket | null = null;\r\n private options: Required<WsOptions>;\r\n private handlers: WsEventHandlers = {};\r\n private subscriptions: Set<string> = new Set();\r\n private state: WsConnectionState = 'disconnected';\r\n private reconnectAttempts = 0;\r\n private pingTimer: ReturnType<typeof setInterval> | null = null;\r\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n // Typed event handlers (separate from WsEventHandlers to avoid wrapping issues)\r\n private historicalDataHandlers: Array<(coin: string, timestamp: number, data: unknown) => void> = [];\r\n private batchHandlers: Array<(coin: string, records: Array<{ timestamp: number; data: unknown }>) => void> = [];\r\n private replayStartHandlers: Array<(channel: WsChannel, coin: string, start: number, end: number, speed: number) => void> = [];\r\n private replayCompleteHandlers: Array<(channel: WsChannel, coin: string, snapshotsSent: number) => void> = [];\r\n private streamStartHandlers: Array<(channel: WsChannel, coin: string, start: number, end: number) => void> = [];\r\n private streamProgressHandlers: Array<(snapshotsSent: number) => void> = [];\r\n private streamCompleteHandlers: Array<(channel: WsChannel, coin: string, snapshotsSent: number) => void> = [];\r\n private orderbookHandlers: Array<(coin: string, data: OrderBook) => void> = [];\r\n private tradesHandlers: Array<(coin: string, data: Trade[]) => void> = [];\r\n\r\n constructor(options: WsOptions) {\r\n this.options = {\r\n apiKey: options.apiKey,\r\n wsUrl: options.wsUrl ?? DEFAULT_WS_URL,\r\n autoReconnect: options.autoReconnect ?? true,\r\n reconnectDelay: options.reconnectDelay ?? DEFAULT_RECONNECT_DELAY,\r\n maxReconnectAttempts: options.maxReconnectAttempts ?? DEFAULT_MAX_RECONNECT_ATTEMPTS,\r\n pingInterval: options.pingInterval ?? DEFAULT_PING_INTERVAL,\r\n };\r\n }\r\n\r\n /**\r\n * Connect to the WebSocket server\r\n */\r\n connect(handlers?: WsEventHandlers): void {\r\n if (handlers) {\r\n this.handlers = handlers;\r\n }\r\n\r\n this.setState('connecting');\r\n\r\n const url = `${this.options.wsUrl}?apiKey=${encodeURIComponent(this.options.apiKey)}`;\r\n this.ws = new WebSocket(url);\r\n\r\n this.ws.onopen = () => {\r\n this.reconnectAttempts = 0;\r\n this.setState('connected');\r\n this.startPing();\r\n this.resubscribe();\r\n this.handlers.onOpen?.();\r\n };\r\n\r\n this.ws.onclose = (event) => {\r\n this.stopPing();\r\n this.handlers.onClose?.(event.code, event.reason);\r\n\r\n if (this.options.autoReconnect && this.state !== 'disconnected') {\r\n this.scheduleReconnect();\r\n } else {\r\n this.setState('disconnected');\r\n }\r\n };\r\n\r\n this.ws.onerror = () => {\r\n const error = new Error('WebSocket connection error');\r\n this.handlers.onError?.(error);\r\n };\r\n\r\n this.ws.onmessage = (event) => {\r\n try {\r\n const message = JSON.parse(event.data) as WsServerMessage;\r\n this.handleMessage(message);\r\n } catch {\r\n // Ignore parse errors for malformed messages\r\n }\r\n };\r\n }\r\n\r\n /**\r\n * Disconnect from the WebSocket server\r\n */\r\n disconnect(): void {\r\n this.setState('disconnected');\r\n this.stopPing();\r\n this.clearReconnectTimer();\r\n\r\n if (this.ws) {\r\n this.ws.close(1000, 'Client disconnect');\r\n this.ws = null;\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to a channel\r\n */\r\n subscribe(channel: WsChannel, coin?: string): void {\r\n const key = this.subscriptionKey(channel, coin);\r\n this.subscriptions.add(key);\r\n\r\n if (this.isConnected()) {\r\n this.send({ op: 'subscribe', channel, coin });\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to order book updates for a coin\r\n */\r\n subscribeOrderbook(coin: string): void {\r\n this.subscribe('orderbook', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to trades for a coin\r\n */\r\n subscribeTrades(coin: string): void {\r\n this.subscribe('trades', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to ticker updates for a coin\r\n */\r\n subscribeTicker(coin: string): void {\r\n this.subscribe('ticker', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to all tickers\r\n */\r\n subscribeAllTickers(): void {\r\n this.subscribe('all_tickers');\r\n }\r\n\r\n /**\r\n * Unsubscribe from a channel\r\n */\r\n unsubscribe(channel: WsChannel, coin?: string): void {\r\n const key = this.subscriptionKey(channel, coin);\r\n this.subscriptions.delete(key);\r\n\r\n if (this.isConnected()) {\r\n this.send({ op: 'unsubscribe', channel, coin });\r\n }\r\n }\r\n\r\n /**\r\n * Unsubscribe from order book updates for a coin\r\n */\r\n unsubscribeOrderbook(coin: string): void {\r\n this.unsubscribe('orderbook', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from trades for a coin\r\n */\r\n unsubscribeTrades(coin: string): void {\r\n this.unsubscribe('trades', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from ticker updates for a coin\r\n */\r\n unsubscribeTicker(coin: string): void {\r\n this.unsubscribe('ticker', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from all tickers\r\n */\r\n unsubscribeAllTickers(): void {\r\n this.unsubscribe('all_tickers');\r\n }\r\n\r\n // ==========================================================================\r\n // Historical Replay (Option B) - Like Tardis.dev\r\n // ==========================================================================\r\n\r\n /**\r\n * Start historical replay with timing preserved\r\n *\r\n * @param channel - Data channel to replay\r\n * @param coin - Trading pair (e.g., 'BTC', 'ETH')\r\n * @param options - Replay options\r\n *\r\n * @example\r\n * ```typescript\r\n * ws.replay('orderbook', 'BTC', {\r\n * start: Date.now() - 86400000, // 24 hours ago\r\n * speed: 10 // 10x faster than real-time\r\n * });\r\n * ```\r\n */\r\n replay(\r\n channel: WsChannel,\r\n coin: string,\r\n options: {\r\n start: number;\r\n end?: number;\r\n speed?: number;\r\n }\r\n ): void {\r\n this.send({\r\n op: 'replay',\r\n channel,\r\n coin,\r\n start: options.start,\r\n end: options.end,\r\n speed: options.speed ?? 1,\r\n });\r\n }\r\n\r\n /**\r\n * Pause the current replay\r\n */\r\n replayPause(): void {\r\n this.send({ op: 'replay.pause' });\r\n }\r\n\r\n /**\r\n * Resume a paused replay\r\n */\r\n replayResume(): void {\r\n this.send({ op: 'replay.resume' });\r\n }\r\n\r\n /**\r\n * Seek to a specific timestamp in the replay\r\n * @param timestamp - Unix timestamp in milliseconds\r\n */\r\n replaySeek(timestamp: number): void {\r\n this.send({ op: 'replay.seek', timestamp });\r\n }\r\n\r\n /**\r\n * Stop the current replay\r\n */\r\n replayStop(): void {\r\n this.send({ op: 'replay.stop' });\r\n }\r\n\r\n // ==========================================================================\r\n // Bulk Streaming (Option D) - Like Databento\r\n // ==========================================================================\r\n\r\n /**\r\n * Start bulk streaming for fast data download\r\n *\r\n * @param channel - Data channel to stream\r\n * @param coin - Trading pair (e.g., 'BTC', 'ETH')\r\n * @param options - Stream options\r\n *\r\n * @example\r\n * ```typescript\r\n * ws.stream('orderbook', 'ETH', {\r\n * start: Date.now() - 3600000, // 1 hour ago\r\n * end: Date.now(),\r\n * batchSize: 1000\r\n * });\r\n * ```\r\n */\r\n stream(\r\n channel: WsChannel,\r\n coin: string,\r\n options: {\r\n start: number;\r\n end: number;\r\n batchSize?: number;\r\n }\r\n ): void {\r\n this.send({\r\n op: 'stream',\r\n channel,\r\n coin,\r\n start: options.start,\r\n end: options.end,\r\n batch_size: options.batchSize ?? 1000,\r\n });\r\n }\r\n\r\n /**\r\n * Stop the current bulk stream\r\n */\r\n streamStop(): void {\r\n this.send({ op: 'stream.stop' });\r\n }\r\n\r\n // ==========================================================================\r\n // Event Handlers for Replay/Stream\r\n // ==========================================================================\r\n\r\n /**\r\n * Handle historical data points (replay mode)\r\n */\r\n onHistoricalData<T = unknown>(\r\n handler: (coin: string, timestamp: number, data: T) => void\r\n ): void {\r\n this.historicalDataHandlers.push(handler as (coin: string, timestamp: number, data: unknown) => void);\r\n }\r\n\r\n /**\r\n * Handle batched data (bulk stream mode)\r\n */\r\n onBatch<T = unknown>(\r\n handler: (coin: string, records: Array<{ timestamp: number; data: T }>) => void\r\n ): void {\r\n this.batchHandlers.push(handler as (coin: string, records: Array<{ timestamp: number; data: unknown }>) => void);\r\n }\r\n\r\n /**\r\n * Handle replay started event\r\n */\r\n onReplayStart(\r\n handler: (channel: WsChannel, coin: string, start: number, end: number, speed: number) => void\r\n ): void {\r\n this.replayStartHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle replay completed event\r\n */\r\n onReplayComplete(\r\n handler: (channel: WsChannel, coin: string, snapshotsSent: number) => void\r\n ): void {\r\n this.replayCompleteHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream started event\r\n */\r\n onStreamStart(\r\n handler: (channel: WsChannel, coin: string, start: number, end: number) => void\r\n ): void {\r\n this.streamStartHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream progress event\r\n */\r\n onStreamProgress(\r\n handler: (snapshotsSent: number) => void\r\n ): void {\r\n this.streamProgressHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream completed event\r\n */\r\n onStreamComplete(\r\n handler: (channel: WsChannel, coin: string, snapshotsSent: number) => void\r\n ): void {\r\n this.streamCompleteHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Get current connection state\r\n */\r\n getState(): WsConnectionState {\r\n return this.state;\r\n }\r\n\r\n /**\r\n * Check if connected\r\n */\r\n isConnected(): boolean {\r\n return this.ws?.readyState === WebSocket.OPEN;\r\n }\r\n\r\n /**\r\n * Set event handlers after construction\r\n */\r\n on<K extends keyof WsEventHandlers>(event: K, handler: WsEventHandlers[K]): void {\r\n this.handlers[event] = handler;\r\n }\r\n\r\n /**\r\n * Helper to handle typed orderbook data\r\n */\r\n onOrderbook(handler: (coin: string, data: OrderBook) => void): void {\r\n this.orderbookHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Helper to handle typed trade data\r\n */\r\n onTrades(handler: (coin: string, data: Trade[]) => void): void {\r\n this.tradesHandlers.push(handler);\r\n }\r\n\r\n // Private methods\r\n\r\n private send(message: WsClientMessage): void {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify(message));\r\n }\r\n }\r\n\r\n private setState(state: WsConnectionState): void {\r\n this.state = state;\r\n this.handlers.onStateChange?.(state);\r\n }\r\n\r\n private startPing(): void {\r\n this.stopPing();\r\n this.pingTimer = setInterval(() => {\r\n this.send({ op: 'ping' });\r\n }, this.options.pingInterval);\r\n }\r\n\r\n private stopPing(): void {\r\n if (this.pingTimer) {\r\n clearInterval(this.pingTimer);\r\n this.pingTimer = null;\r\n }\r\n }\r\n\r\n private subscriptionKey(channel: WsChannel, coin?: string): string {\r\n return coin ? `${channel}:${coin}` : channel;\r\n }\r\n\r\n private resubscribe(): void {\r\n for (const key of this.subscriptions) {\r\n const [channel, coin] = key.split(':') as [WsChannel, string | undefined];\r\n this.send({ op: 'subscribe', channel, coin });\r\n }\r\n }\r\n\r\n private scheduleReconnect(): void {\r\n if (this.reconnectAttempts >= this.options.maxReconnectAttempts) {\r\n this.setState('disconnected');\r\n return;\r\n }\r\n\r\n this.setState('reconnecting');\r\n this.reconnectAttempts++;\r\n\r\n const delay = this.options.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);\r\n\r\n this.reconnectTimer = setTimeout(() => {\r\n this.connect();\r\n }, delay);\r\n }\r\n\r\n private clearReconnectTimer(): void {\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = null;\r\n }\r\n }\r\n\r\n private handleMessage(message: WsServerMessage): void {\r\n // Call the generic onMessage handler first\r\n this.handlers.onMessage?.(message);\r\n\r\n // Dispatch to typed handlers based on message type\r\n switch (message.type) {\r\n case 'historical_data': {\r\n const msg = message as WsHistoricalData;\r\n for (const handler of this.historicalDataHandlers) {\r\n handler(msg.coin, msg.timestamp, msg.data);\r\n }\r\n break;\r\n }\r\n case 'historical_batch': {\r\n const msg = message as WsHistoricalBatch;\r\n for (const handler of this.batchHandlers) {\r\n handler(msg.coin, msg.data as Array<{ timestamp: number; data: unknown }>);\r\n }\r\n break;\r\n }\r\n case 'replay_started': {\r\n const msg = message as WsReplayStarted;\r\n for (const handler of this.replayStartHandlers) {\r\n handler(msg.channel, msg.coin, msg.start, msg.end, msg.speed);\r\n }\r\n break;\r\n }\r\n case 'replay_completed': {\r\n const msg = message as WsReplayCompleted;\r\n for (const handler of this.replayCompleteHandlers) {\r\n handler(msg.channel, msg.coin, msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'stream_started': {\r\n const msg = message as WsStreamStarted;\r\n for (const handler of this.streamStartHandlers) {\r\n handler(msg.channel, msg.coin, msg.start, msg.end);\r\n }\r\n break;\r\n }\r\n case 'stream_progress': {\r\n const msg = message as WsStreamProgress;\r\n for (const handler of this.streamProgressHandlers) {\r\n handler(msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'stream_completed': {\r\n const msg = message as WsStreamCompleted;\r\n for (const handler of this.streamCompleteHandlers) {\r\n handler(msg.channel, msg.coin, msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'data': {\r\n if (message.channel === 'orderbook') {\r\n // Transform raw Hyperliquid format to SDK OrderBook type\r\n const orderbook = transformOrderbook(message.coin, message.data as Record<string, unknown>);\r\n for (const handler of this.orderbookHandlers) {\r\n handler(message.coin, orderbook);\r\n }\r\n } else if (message.channel === 'trades') {\r\n for (const handler of this.tradesHandlers) {\r\n handler(message.coin, message.data as Trade[]);\r\n }\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -111,18 +111,44 @@ var TradesResource = class {
111
111
  this.http = http;
112
112
  }
113
113
  /**
114
- * Get trade history for a coin
114
+ * Get trade history for a coin using cursor-based pagination
115
+ *
116
+ * Uses cursor-based pagination by default, which is more efficient for large datasets.
117
+ * Use the `nextCursor` from the response as the `cursor` parameter to get the next page.
115
118
  *
116
119
  * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
117
- * @param params - Time range and pagination parameters (start is required)
118
- * @returns Array of trades
120
+ * @param params - Time range and cursor pagination parameters (start and end are required)
121
+ * @returns Object with trades array and nextCursor for pagination
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * // First page
126
+ * let result = await client.trades.list('BTC', {
127
+ * start: Date.now() - 86400000,
128
+ * end: Date.now(),
129
+ * limit: 1000
130
+ * });
131
+ *
132
+ * // Subsequent pages
133
+ * while (result.nextCursor) {
134
+ * result = await client.trades.list('BTC', {
135
+ * start: Date.now() - 86400000,
136
+ * end: Date.now(),
137
+ * cursor: result.nextCursor,
138
+ * limit: 1000
139
+ * });
140
+ * }
141
+ * ```
119
142
  */
120
143
  async list(coin, params) {
121
144
  const response = await this.http.get(
122
145
  `/v1/trades/${coin.toUpperCase()}`,
123
146
  params
124
147
  );
125
- return response.data;
148
+ return {
149
+ data: response.data,
150
+ nextCursor: response.meta.next_cursor
151
+ };
126
152
  }
127
153
  /**
128
154
  * Get most recent trades for a coin
@@ -138,6 +164,34 @@ var TradesResource = class {
138
164
  );
139
165
  return response.data;
140
166
  }
167
+ /**
168
+ * Get trade history using cursor-based pagination (explicit endpoint)
169
+ *
170
+ * @deprecated Use `list()` instead - it now uses cursor-based pagination by default.
171
+ *
172
+ * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
173
+ * @param params - Cursor pagination parameters (start and end are required)
174
+ * @returns Object with trades array and nextCursor for pagination
175
+ */
176
+ async listWithCursor(coin, params) {
177
+ return this.list(coin, params);
178
+ }
179
+ /**
180
+ * Get trade history using offset-based pagination
181
+ *
182
+ * @deprecated Use `list()` with cursor-based pagination instead for better performance.
183
+ *
184
+ * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
185
+ * @param params - Time range and offset pagination parameters
186
+ * @returns Array of trades (without cursor response wrapper)
187
+ */
188
+ async listWithOffset(coin, params) {
189
+ const response = await this.http.get(
190
+ `/v1/trades/${coin.toUpperCase()}`,
191
+ params
192
+ );
193
+ return response.data;
194
+ }
141
195
  };
142
196
 
143
197
  // src/resources/instruments.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/http.ts","../src/resources/orderbook.ts","../src/resources/trades.ts","../src/resources/instruments.ts","../src/resources/funding.ts","../src/resources/openinterest.ts","../src/client.ts","../src/websocket.ts"],"sourcesContent":["/**\r\n * Configuration options for the 0xarchive client\r\n */\r\nexport interface ClientOptions {\r\n /** Your 0xarchive API key */\r\n apiKey: string;\r\n /** Base URL for the API (defaults to https://api.0xarchive.io) */\r\n baseUrl?: string;\r\n /** Request timeout in milliseconds (defaults to 30000) */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Response metadata\r\n */\r\nexport interface ApiMeta {\r\n /** Number of records returned */\r\n count: number;\r\n /** Cursor for next page (if available) */\r\n next_cursor?: string;\r\n /** Unique request ID for debugging */\r\n request_id: string;\r\n}\r\n\r\n/**\r\n * Standard API response wrapper\r\n */\r\nexport interface ApiResponse<T> {\r\n success: boolean;\r\n data: T;\r\n meta: ApiMeta;\r\n}\r\n\r\n/**\r\n * Pagination parameters for list endpoints\r\n */\r\nexport interface PaginationParams {\r\n /** Maximum number of results to return */\r\n limit?: number;\r\n /** Number of results to skip */\r\n offset?: number;\r\n}\r\n\r\n/**\r\n * Time range parameters for historical queries\r\n */\r\nexport interface TimeRangeParams extends PaginationParams {\r\n /** Start timestamp (Unix ms or ISO string) - REQUIRED for history endpoints */\r\n start: number | string;\r\n /** End timestamp (Unix ms or ISO string) - REQUIRED for history endpoints */\r\n end: number | string;\r\n}\r\n\r\n// =============================================================================\r\n// Order Book Types\r\n// =============================================================================\r\n\r\n/**\r\n * A price level in the order book\r\n */\r\nexport interface PriceLevel {\r\n /** Price at this level */\r\n px: string;\r\n /** Total size at this price level */\r\n sz: string;\r\n /** Number of orders at this level */\r\n n: number;\r\n}\r\n\r\n/**\r\n * Order book snapshot\r\n */\r\nexport interface OrderBook {\r\n /** Trading pair symbol (e.g., BTC, ETH) */\r\n coin: string;\r\n /** Snapshot timestamp (UTC) */\r\n timestamp: string;\r\n /** Bid price levels (best bid first) */\r\n bids: PriceLevel[];\r\n /** Ask price levels (best ask first) */\r\n asks: PriceLevel[];\r\n /** Mid price (best bid + best ask) / 2 */\r\n mid_price?: string;\r\n /** Spread in absolute terms (best ask - best bid) */\r\n spread?: string;\r\n /** Spread in basis points */\r\n spread_bps?: string;\r\n}\r\n\r\nexport interface GetOrderBookParams {\r\n /** Timestamp to get order book at (Unix ms or ISO string) */\r\n timestamp?: number | string;\r\n /** Number of price levels to return per side */\r\n depth?: number;\r\n}\r\n\r\nexport interface OrderBookHistoryParams extends TimeRangeParams {\r\n /** Number of price levels to return per side */\r\n depth?: number;\r\n}\r\n\r\n// =============================================================================\r\n// Trade/Fill Types\r\n// =============================================================================\r\n\r\n/** Trade side: 'A' (ask/sell) or 'B' (bid/buy) */\r\nexport type TradeSide = 'A' | 'B';\r\n\r\n/** Position direction */\r\nexport type TradeDirection = 'Open Long' | 'Open Short' | 'Close Long' | 'Close Short';\r\n\r\n/** Data source */\r\nexport type DataSource = 's3' | 'ws' | 'api';\r\n\r\n/**\r\n * Trade/fill record with full execution details\r\n */\r\nexport interface Trade {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Trade side: 'A' (ask/sell) or 'B' (bid/buy) */\r\n side: TradeSide;\r\n /** Execution price */\r\n price: string;\r\n /** Trade size */\r\n size: string;\r\n /** Execution timestamp (UTC) */\r\n timestamp: string;\r\n /** Blockchain transaction hash */\r\n tx_hash?: string;\r\n /** Unique trade ID */\r\n trade_id?: number;\r\n /** Associated order ID */\r\n order_id?: number;\r\n /** True if taker (crossed the spread), false if maker */\r\n crossed?: boolean;\r\n /** Trading fee amount */\r\n fee?: string;\r\n /** Fee denomination (e.g., USDC) */\r\n fee_token?: string;\r\n /** Realized PnL if closing a position */\r\n closed_pnl?: string;\r\n /** Position direction */\r\n direction?: TradeDirection;\r\n /** Position size before this trade */\r\n start_position?: string;\r\n /** Data source */\r\n source?: DataSource;\r\n /** User's wallet address */\r\n user_address?: string;\r\n}\r\n\r\nexport interface GetTradesParams extends TimeRangeParams {\r\n /** Filter by side */\r\n side?: TradeSide;\r\n}\r\n\r\n// =============================================================================\r\n// Instruments Types\r\n// =============================================================================\r\n\r\n/** Instrument type */\r\nexport type InstrumentType = 'perp' | 'spot';\r\n\r\n/**\r\n * Trading instrument metadata\r\n */\r\nexport interface Instrument {\r\n /** Instrument symbol (e.g., BTC) */\r\n name: string;\r\n /** Size decimal precision */\r\n szDecimals: number;\r\n /** Maximum leverage allowed */\r\n maxLeverage?: number;\r\n /** If true, only isolated margin mode is allowed */\r\n onlyIsolated?: boolean;\r\n /** Type of instrument */\r\n instrumentType?: InstrumentType;\r\n /** Whether the instrument is currently tradeable */\r\n isActive: boolean;\r\n}\r\n\r\n// =============================================================================\r\n// Funding Types\r\n// =============================================================================\r\n\r\n/**\r\n * Funding rate record\r\n */\r\nexport interface FundingRate {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Funding timestamp (UTC) */\r\n timestamp: string;\r\n /** Funding rate as decimal (e.g., 0.0001 = 0.01%) */\r\n funding_rate: string;\r\n /** Premium component of funding rate */\r\n premium?: string;\r\n}\r\n\r\n// =============================================================================\r\n// Open Interest Types\r\n// =============================================================================\r\n\r\n/**\r\n * Open interest snapshot with market context\r\n */\r\nexport interface OpenInterest {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Snapshot timestamp (UTC) */\r\n timestamp: string;\r\n /** Total open interest in contracts */\r\n open_interest: string;\r\n /** Mark price used for liquidations */\r\n mark_price?: string;\r\n /** Oracle price from external feed */\r\n oracle_price?: string;\r\n /** 24-hour notional volume */\r\n day_ntl_volume?: string;\r\n /** Price 24 hours ago */\r\n prev_day_price?: string;\r\n /** Current mid price */\r\n mid_price?: string;\r\n /** Impact bid price for liquidations */\r\n impact_bid_price?: string;\r\n /** Impact ask price for liquidations */\r\n impact_ask_price?: string;\r\n}\r\n\r\n// =============================================================================\r\n// WebSocket Types\r\n// =============================================================================\r\n\r\n/** WebSocket channel types. Note: ticker/all_tickers are real-time only. */\r\nexport type WsChannel = 'orderbook' | 'trades' | 'ticker' | 'all_tickers';\r\n\r\n/** Subscribe message from client */\r\nexport interface WsSubscribe {\r\n op: 'subscribe';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Unsubscribe message from client */\r\nexport interface WsUnsubscribe {\r\n op: 'unsubscribe';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Ping message from client */\r\nexport interface WsPing {\r\n op: 'ping';\r\n}\r\n\r\n/** Replay message from client - replays historical data with timing preserved */\r\nexport interface WsReplay {\r\n op: 'replay';\r\n channel: WsChannel;\r\n coin?: string;\r\n /** Start timestamp (Unix ms) */\r\n start: number;\r\n /** End timestamp (Unix ms, defaults to now) */\r\n end?: number;\r\n /** Playback speed multiplier (1 = real-time, 10 = 10x faster) */\r\n speed?: number;\r\n}\r\n\r\n/** Replay control messages */\r\nexport interface WsReplayPause { op: 'replay.pause'; }\r\nexport interface WsReplayResume { op: 'replay.resume'; }\r\nexport interface WsReplaySeek { op: 'replay.seek'; timestamp: number; }\r\nexport interface WsReplayStop { op: 'replay.stop'; }\r\n\r\n/** Stream message from client - bulk download historical data */\r\nexport interface WsStream {\r\n op: 'stream';\r\n channel: WsChannel;\r\n coin?: string;\r\n /** Start timestamp (Unix ms) */\r\n start: number;\r\n /** End timestamp (Unix ms) */\r\n end: number;\r\n /** Batch size (records per message) */\r\n batch_size?: number;\r\n}\r\n\r\n/** Stream control messages */\r\nexport interface WsStreamStop { op: 'stream.stop'; }\r\n\r\n/** Client message union type */\r\nexport type WsClientMessage =\r\n | WsSubscribe\r\n | WsUnsubscribe\r\n | WsPing\r\n | WsReplay\r\n | WsReplayPause\r\n | WsReplayResume\r\n | WsReplaySeek\r\n | WsReplayStop\r\n | WsStream\r\n | WsStreamStop;\r\n\r\n/** Subscription confirmed from server */\r\nexport interface WsSubscribed {\r\n type: 'subscribed';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Unsubscription confirmed from server */\r\nexport interface WsUnsubscribed {\r\n type: 'unsubscribed';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Pong response from server */\r\nexport interface WsPong {\r\n type: 'pong';\r\n}\r\n\r\n/** Error from server */\r\nexport interface WsError {\r\n type: 'error';\r\n message: string;\r\n}\r\n\r\n/** Data message from server (real-time) */\r\nexport interface WsData<T = unknown> {\r\n type: 'data';\r\n channel: WsChannel;\r\n coin: string;\r\n data: T;\r\n}\r\n\r\n/** Replay started response */\r\nexport interface WsReplayStarted {\r\n type: 'replay_started';\r\n channel: WsChannel;\r\n coin: string;\r\n /** Start timestamp in milliseconds */\r\n start: number;\r\n /** End timestamp in milliseconds */\r\n end: number;\r\n /** Playback speed multiplier */\r\n speed: number;\r\n}\r\n\r\n/** Replay paused response */\r\nexport interface WsReplayPaused {\r\n type: 'replay_paused';\r\n current_timestamp: number;\r\n}\r\n\r\n/** Replay resumed response */\r\nexport interface WsReplayResumed {\r\n type: 'replay_resumed';\r\n current_timestamp: number;\r\n}\r\n\r\n/** Replay completed response */\r\nexport interface WsReplayCompleted {\r\n type: 'replay_completed';\r\n channel: WsChannel;\r\n coin: string;\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Replay stopped response */\r\nexport interface WsReplayStopped {\r\n type: 'replay_stopped';\r\n}\r\n\r\n/** Historical data point (replay mode) */\r\nexport interface WsHistoricalData<T = unknown> {\r\n type: 'historical_data';\r\n channel: WsChannel;\r\n coin: string;\r\n timestamp: number;\r\n data: T;\r\n}\r\n\r\n/** Stream started response */\r\nexport interface WsStreamStarted {\r\n type: 'stream_started';\r\n channel: WsChannel;\r\n coin: string;\r\n /** Start timestamp in milliseconds */\r\n start: number;\r\n /** End timestamp in milliseconds */\r\n end: number;\r\n}\r\n\r\n/** Stream progress response (sent periodically during streaming) */\r\nexport interface WsStreamProgress {\r\n type: 'stream_progress';\r\n snapshots_sent: number;\r\n}\r\n\r\n/** A record with timestamp for batched data */\r\nexport interface TimestampedRecord<T = unknown> {\r\n timestamp: number;\r\n data: T;\r\n}\r\n\r\n/** Batch of historical data (bulk streaming) */\r\nexport interface WsHistoricalBatch<T = unknown> {\r\n type: 'historical_batch';\r\n channel: WsChannel;\r\n coin: string;\r\n data: TimestampedRecord<T>[];\r\n}\r\n\r\n/** Stream completed response */\r\nexport interface WsStreamCompleted {\r\n type: 'stream_completed';\r\n channel: WsChannel;\r\n coin: string;\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Stream stopped response */\r\nexport interface WsStreamStopped {\r\n type: 'stream_stopped';\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Server message union type */\r\nexport type WsServerMessage =\r\n | WsSubscribed\r\n | WsUnsubscribed\r\n | WsPong\r\n | WsError\r\n | WsData\r\n | WsReplayStarted\r\n | WsReplayPaused\r\n | WsReplayResumed\r\n | WsReplayCompleted\r\n | WsReplayStopped\r\n | WsHistoricalData\r\n | WsStreamStarted\r\n | WsStreamProgress\r\n | WsHistoricalBatch\r\n | WsStreamCompleted\r\n | WsStreamStopped;\r\n\r\n/**\r\n * WebSocket connection options.\r\n *\r\n * The server sends WebSocket ping frames every 30 seconds and will disconnect\r\n * idle connections after 60 seconds. The SDK automatically handles keep-alive\r\n * by sending application-level pings at the configured interval.\r\n */\r\nexport interface WsOptions {\r\n /** API key for authentication */\r\n apiKey: string;\r\n /** WebSocket URL (defaults to wss://api.0xarchive.io/ws) */\r\n wsUrl?: string;\r\n /** Auto-reconnect on disconnect (defaults to true) */\r\n autoReconnect?: boolean;\r\n /** Reconnect delay in ms (defaults to 1000) */\r\n reconnectDelay?: number;\r\n /** Maximum reconnect attempts (defaults to 10) */\r\n maxReconnectAttempts?: number;\r\n /** Ping interval in ms to keep connection alive (defaults to 30000). Server disconnects after 60s idle. */\r\n pingInterval?: number;\r\n}\r\n\r\n/** WebSocket connection state */\r\nexport type WsConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';\r\n\r\n/** WebSocket event handlers */\r\nexport interface WsEventHandlers {\r\n onOpen?: () => void;\r\n onClose?: (code: number, reason: string) => void;\r\n onError?: (error: Error) => void;\r\n onMessage?: (message: WsServerMessage) => void;\r\n onStateChange?: (state: WsConnectionState) => void;\r\n}\r\n\r\n// =============================================================================\r\n// Error Types\r\n// =============================================================================\r\n\r\n/**\r\n * API error response\r\n */\r\nexport interface ApiError {\r\n code: number;\r\n error: string;\r\n}\r\n\r\n/**\r\n * SDK error class\r\n */\r\nexport class OxArchiveError extends Error {\r\n code: number;\r\n requestId?: string;\r\n\r\n constructor(message: string, code: number, requestId?: string) {\r\n super(message);\r\n this.name = 'OxArchiveError';\r\n this.code = code;\r\n this.requestId = requestId;\r\n }\r\n}\r\n\r\n/** Timestamp can be Unix ms (number), ISO string, or Date object */\r\nexport type Timestamp = number | string | Date;\r\n","import type { ApiResponse, ApiError } from './types';\r\nimport { OxArchiveError } from './types';\r\n\r\nexport interface HttpClientOptions {\r\n baseUrl: string;\r\n apiKey: string;\r\n timeout: number;\r\n}\r\n\r\n/**\r\n * Internal HTTP client for making API requests\r\n */\r\nexport class HttpClient {\r\n private baseUrl: string;\r\n private apiKey: string;\r\n private timeout: number;\r\n\r\n constructor(options: HttpClientOptions) {\r\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\r\n this.apiKey = options.apiKey;\r\n this.timeout = options.timeout;\r\n }\r\n\r\n /**\r\n * Make a GET request to the API\r\n */\r\n async get<T>(path: string, params?: Record<string, unknown>): Promise<T> {\r\n const url = new URL(`${this.baseUrl}${path}`);\r\n\r\n if (params) {\r\n for (const [key, value] of Object.entries(params)) {\r\n if (value !== undefined && value !== null) {\r\n url.searchParams.set(key, String(value));\r\n }\r\n }\r\n }\r\n\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url.toString(), {\r\n method: 'GET',\r\n headers: {\r\n 'X-API-Key': this.apiKey,\r\n 'Content-Type': 'application/json',\r\n },\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n const data = await response.json();\r\n\r\n if (!response.ok) {\r\n const error = data as ApiError;\r\n throw new OxArchiveError(\r\n error.error || `Request failed with status ${response.status}`,\r\n response.status,\r\n (data as ApiResponse<unknown>).meta?.request_id\r\n );\r\n }\r\n\r\n return data as T;\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof OxArchiveError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof Error && error.name === 'AbortError') {\r\n throw new OxArchiveError(`Request timeout after ${this.timeout}ms`, 408);\r\n }\r\n\r\n throw new OxArchiveError(\r\n error instanceof Error ? error.message : 'Unknown error',\r\n 500\r\n );\r\n }\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type {\r\n ApiResponse,\r\n OrderBook,\r\n GetOrderBookParams,\r\n OrderBookHistoryParams,\r\n} from '../types';\r\n\r\n/**\r\n * Order book API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current order book\r\n * const orderbook = await client.orderbook.get('BTC');\r\n *\r\n * // Get order book at specific timestamp\r\n * const historical = await client.orderbook.get('ETH', {\r\n * timestamp: 1704067200000,\r\n * depth: 10\r\n * });\r\n *\r\n * // Get order book history\r\n * const history = await client.orderbook.history('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n * ```\r\n */\r\nexport class OrderBookResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get order book snapshot for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Optional parameters\r\n * @returns Order book snapshot\r\n */\r\n async get(coin: string, params?: GetOrderBookParams): Promise<OrderBook> {\r\n const response = await this.http.get<ApiResponse<OrderBook>>(\r\n `/v1/orderbook/${coin.toUpperCase()}`,\r\n params as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get historical order book snapshots\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of order book snapshots\r\n */\r\n async history(\r\n coin: string,\r\n params: OrderBookHistoryParams\r\n ): Promise<OrderBook[]> {\r\n const response = await this.http.get<ApiResponse<OrderBook[]>>(\r\n `/v1/orderbook/${coin.toUpperCase()}/history`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, Trade, GetTradesParams } from '../types';\r\n\r\n/**\r\n * Trades API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get recent trades\r\n * const trades = await client.trades.recent('BTC');\r\n *\r\n * // Get trade history with time range\r\n * const history = await client.trades.list('ETH', {\r\n * start: Date.now() - 3600000,\r\n * end: Date.now(),\r\n * limit: 500\r\n * });\r\n * ```\r\n */\r\nexport class TradesResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get trade history for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of trades\r\n */\r\n async list(coin: string, params: GetTradesParams): Promise<Trade[]> {\r\n const response = await this.http.get<ApiResponse<Trade[]>>(\r\n `/v1/trades/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get most recent trades for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param limit - Number of trades to return (default: 100)\r\n * @returns Array of recent trades\r\n */\r\n async recent(coin: string, limit?: number): Promise<Trade[]> {\r\n const response = await this.http.get<ApiResponse<Trade[]>>(\r\n `/v1/trades/${coin.toUpperCase()}/recent`,\r\n { limit }\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, Instrument } from '../types';\r\n\r\n/**\r\n * Instruments API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // List all instruments\r\n * const instruments = await client.instruments.list();\r\n *\r\n * // Get specific instrument\r\n * const btc = await client.instruments.get('BTC');\r\n * ```\r\n */\r\nexport class InstrumentsResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * List all available trading instruments\r\n *\r\n * @returns Array of instruments\r\n */\r\n async list(): Promise<Instrument[]> {\r\n const response = await this.http.get<ApiResponse<Instrument[]>>(\r\n '/v1/instruments'\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get a specific instrument by coin symbol\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Instrument details\r\n */\r\n async get(coin: string): Promise<Instrument> {\r\n const response = await this.http.get<ApiResponse<Instrument>>(\r\n `/v1/instruments/${coin.toUpperCase()}`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, FundingRate, TimeRangeParams } from '../types';\r\n\r\n/**\r\n * Funding rates API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current funding rate\r\n * const current = await client.funding.current('BTC');\r\n *\r\n * // Get funding rate history\r\n * const history = await client.funding.history('ETH', {\r\n * start: Date.now() - 86400000 * 7,\r\n * end: Date.now()\r\n * });\r\n * ```\r\n */\r\nexport class FundingResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get funding rate history for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of funding rate records\r\n */\r\n async history(coin: string, params: TimeRangeParams): Promise<FundingRate[]> {\r\n const response = await this.http.get<ApiResponse<FundingRate[]>>(\r\n `/v1/funding/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get current funding rate for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Current funding rate\r\n */\r\n async current(coin: string): Promise<FundingRate> {\r\n const response = await this.http.get<ApiResponse<FundingRate>>(\r\n `/v1/funding/${coin.toUpperCase()}/current`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, OpenInterest, TimeRangeParams } from '../types';\r\n\r\n/**\r\n * Open interest API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current open interest\r\n * const current = await client.openInterest.current('BTC');\r\n *\r\n * // Get open interest history\r\n * const history = await client.openInterest.history('ETH', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n * ```\r\n */\r\nexport class OpenInterestResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get open interest history for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of open interest records\r\n */\r\n async history(coin: string, params: TimeRangeParams): Promise<OpenInterest[]> {\r\n const response = await this.http.get<ApiResponse<OpenInterest[]>>(\r\n `/v1/openinterest/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get current open interest for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Current open interest\r\n */\r\n async current(coin: string): Promise<OpenInterest> {\r\n const response = await this.http.get<ApiResponse<OpenInterest>>(\r\n `/v1/openinterest/${coin.toUpperCase()}/current`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { ClientOptions } from './types';\r\nimport { HttpClient } from './http';\r\nimport {\r\n OrderBookResource,\r\n TradesResource,\r\n InstrumentsResource,\r\n FundingResource,\r\n OpenInterestResource,\r\n} from './resources';\r\n\r\nconst DEFAULT_BASE_URL = 'https://api.0xarchive.io';\r\nconst DEFAULT_TIMEOUT = 30000;\r\n\r\n/**\r\n * 0xarchive API client\r\n *\r\n * @example\r\n * ```typescript\r\n * import { OxArchive } from '@0xarchive/sdk';\r\n *\r\n * const client = new OxArchive({ apiKey: 'ox_your_api_key' });\r\n *\r\n * // Get current order book\r\n * const orderbook = await client.orderbook.get('BTC');\r\n * console.log(`BTC mid price: ${orderbook.mid_price}`);\r\n *\r\n * // Get historical data\r\n * const history = await client.orderbook.history('ETH', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n *\r\n * // List all instruments\r\n * const instruments = await client.instruments.list();\r\n * ```\r\n */\r\nexport class OxArchive {\r\n private http: HttpClient;\r\n\r\n /**\r\n * Order book data (L2 snapshots from April 2023)\r\n */\r\n public readonly orderbook: OrderBookResource;\r\n\r\n /**\r\n * Trade/fill history\r\n */\r\n public readonly trades: TradesResource;\r\n\r\n /**\r\n * Trading instruments metadata\r\n */\r\n public readonly instruments: InstrumentsResource;\r\n\r\n /**\r\n * Funding rates\r\n */\r\n public readonly funding: FundingResource;\r\n\r\n /**\r\n * Open interest\r\n */\r\n public readonly openInterest: OpenInterestResource;\r\n\r\n /**\r\n * Create a new 0xarchive client\r\n *\r\n * @param options - Client configuration options\r\n */\r\n constructor(options: ClientOptions) {\r\n if (!options.apiKey) {\r\n throw new Error('API key is required. Get one at https://0xarchive.io/signup');\r\n }\r\n\r\n this.http = new HttpClient({\r\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\r\n apiKey: options.apiKey,\r\n timeout: options.timeout ?? DEFAULT_TIMEOUT,\r\n });\r\n\r\n // Initialize resource namespaces\r\n this.orderbook = new OrderBookResource(this.http);\r\n this.trades = new TradesResource(this.http);\r\n this.instruments = new InstrumentsResource(this.http);\r\n this.funding = new FundingResource(this.http);\r\n this.openInterest = new OpenInterestResource(this.http);\r\n }\r\n}\r\n","/**\r\n * WebSocket client for 0xarchive real-time streaming, replay, and bulk download\r\n *\r\n * @example Real-time streaming\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect({\r\n * onMessage: (msg) => console.log(msg)\r\n * });\r\n * ws.subscribeOrderbook('BTC');\r\n * ```\r\n *\r\n * @example Historical replay (like Tardis.dev)\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect();\r\n * ws.onHistoricalData((coin, timestamp, data) => {\r\n * console.log(`${new Date(timestamp)}: ${data.mid_price}`);\r\n * });\r\n * ws.replay('orderbook', 'BTC', {\r\n * start: Date.now() - 86400000,\r\n * speed: 10 // 10x speed\r\n * });\r\n * ```\r\n *\r\n * @example Bulk streaming (like Databento)\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect();\r\n * const batches: OrderBook[] = [];\r\n * ws.onBatch((coin, records) => {\r\n * batches.push(...records.map(r => r.data));\r\n * });\r\n * ws.onStreamComplete((channel, coin, count) => {\r\n * console.log(`Downloaded ${count} records`);\r\n * });\r\n * ws.stream('orderbook', 'ETH', {\r\n * start: Date.now() - 3600000,\r\n * end: Date.now(),\r\n * batchSize: 1000\r\n * });\r\n * ```\r\n */\r\n\r\nimport type {\r\n WsOptions,\r\n WsChannel,\r\n WsClientMessage,\r\n WsServerMessage,\r\n WsConnectionState,\r\n WsEventHandlers,\r\n OrderBook,\r\n PriceLevel,\r\n Trade,\r\n WsHistoricalData,\r\n WsHistoricalBatch,\r\n WsReplayStarted,\r\n WsReplayCompleted,\r\n WsStreamStarted,\r\n WsStreamCompleted,\r\n WsStreamProgress,\r\n} from './types';\r\n\r\nconst DEFAULT_WS_URL = 'wss://api.0xarchive.io/ws';\r\nconst DEFAULT_PING_INTERVAL = 30000; // 30 seconds\r\nconst DEFAULT_RECONNECT_DELAY = 1000;\r\nconst DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;\r\n\r\n// Server idle timeout is 60 seconds. The SDK sends pings every 30 seconds\r\n// to keep the connection alive. Browser WebSocket API automatically responds\r\n// to WebSocket protocol-level ping frames from the server.\r\n\r\n/**\r\n * Transform raw Hyperliquid orderbook format to SDK OrderBook type.\r\n * Raw format: { coin, levels: [[{px, sz, n}, ...], [{px, sz, n}, ...]], time }\r\n * SDK format: { coin, timestamp, bids: [{px, sz, n}], asks: [{px, sz, n}], mid_price, spread, spread_bps }\r\n */\r\nfunction transformOrderbook(coin: string, raw: Record<string, unknown>): OrderBook {\r\n // Check if already in SDK format (from REST API or historical replay)\r\n if ('bids' in raw && 'asks' in raw) {\r\n return raw as unknown as OrderBook;\r\n }\r\n\r\n // Transform from Hyperliquid raw format\r\n // levels is [[{px, sz, n}, ...], [{px, sz, n}, ...]] where [0]=bids, [1]=asks\r\n const levels = raw.levels as Array<Array<{ px: string; sz: string; n: number }>> | undefined;\r\n const time = raw.time as number | undefined;\r\n\r\n const bids: PriceLevel[] = [];\r\n const asks: PriceLevel[] = [];\r\n\r\n if (levels && levels.length >= 2) {\r\n // levels[0] = bids, levels[1] = asks\r\n // Each level is already {px, sz, n} object\r\n for (const level of levels[0] || []) {\r\n bids.push({ px: level.px, sz: level.sz, n: level.n });\r\n }\r\n for (const level of levels[1] || []) {\r\n asks.push({ px: level.px, sz: level.sz, n: level.n });\r\n }\r\n }\r\n\r\n // Calculate mid price and spread\r\n let mid_price: string | undefined;\r\n let spread: string | undefined;\r\n let spread_bps: string | undefined;\r\n\r\n if (bids.length > 0 && asks.length > 0) {\r\n const bestBid = parseFloat(bids[0].px);\r\n const bestAsk = parseFloat(asks[0].px);\r\n const mid = (bestBid + bestAsk) / 2;\r\n mid_price = mid.toString();\r\n spread = (bestAsk - bestBid).toString();\r\n spread_bps = ((bestAsk - bestBid) / mid * 10000).toFixed(2);\r\n }\r\n\r\n return {\r\n coin,\r\n timestamp: time ? new Date(time).toISOString() : new Date().toISOString(),\r\n bids,\r\n asks,\r\n mid_price,\r\n spread,\r\n spread_bps,\r\n };\r\n}\r\n\r\n/**\r\n * WebSocket client for real-time data streaming.\r\n *\r\n * **Keep-Alive:** The server sends WebSocket ping frames every 30 seconds\r\n * and will disconnect idle connections after 60 seconds. This SDK automatically\r\n * handles keep-alive by sending application-level pings at the configured interval\r\n * (default: 30 seconds). The browser WebSocket API automatically responds to\r\n * server ping frames.\r\n */\r\nexport class OxArchiveWs {\r\n private ws: WebSocket | null = null;\r\n private options: Required<WsOptions>;\r\n private handlers: WsEventHandlers = {};\r\n private subscriptions: Set<string> = new Set();\r\n private state: WsConnectionState = 'disconnected';\r\n private reconnectAttempts = 0;\r\n private pingTimer: ReturnType<typeof setInterval> | null = null;\r\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n // Typed event handlers (separate from WsEventHandlers to avoid wrapping issues)\r\n private historicalDataHandlers: Array<(coin: string, timestamp: number, data: unknown) => void> = [];\r\n private batchHandlers: Array<(coin: string, records: Array<{ timestamp: number; data: unknown }>) => void> = [];\r\n private replayStartHandlers: Array<(channel: WsChannel, coin: string, start: number, end: number, speed: number) => void> = [];\r\n private replayCompleteHandlers: Array<(channel: WsChannel, coin: string, snapshotsSent: number) => void> = [];\r\n private streamStartHandlers: Array<(channel: WsChannel, coin: string, start: number, end: number) => void> = [];\r\n private streamProgressHandlers: Array<(snapshotsSent: number) => void> = [];\r\n private streamCompleteHandlers: Array<(channel: WsChannel, coin: string, snapshotsSent: number) => void> = [];\r\n private orderbookHandlers: Array<(coin: string, data: OrderBook) => void> = [];\r\n private tradesHandlers: Array<(coin: string, data: Trade[]) => void> = [];\r\n\r\n constructor(options: WsOptions) {\r\n this.options = {\r\n apiKey: options.apiKey,\r\n wsUrl: options.wsUrl ?? DEFAULT_WS_URL,\r\n autoReconnect: options.autoReconnect ?? true,\r\n reconnectDelay: options.reconnectDelay ?? DEFAULT_RECONNECT_DELAY,\r\n maxReconnectAttempts: options.maxReconnectAttempts ?? DEFAULT_MAX_RECONNECT_ATTEMPTS,\r\n pingInterval: options.pingInterval ?? DEFAULT_PING_INTERVAL,\r\n };\r\n }\r\n\r\n /**\r\n * Connect to the WebSocket server\r\n */\r\n connect(handlers?: WsEventHandlers): void {\r\n if (handlers) {\r\n this.handlers = handlers;\r\n }\r\n\r\n this.setState('connecting');\r\n\r\n const url = `${this.options.wsUrl}?apiKey=${encodeURIComponent(this.options.apiKey)}`;\r\n this.ws = new WebSocket(url);\r\n\r\n this.ws.onopen = () => {\r\n this.reconnectAttempts = 0;\r\n this.setState('connected');\r\n this.startPing();\r\n this.resubscribe();\r\n this.handlers.onOpen?.();\r\n };\r\n\r\n this.ws.onclose = (event) => {\r\n this.stopPing();\r\n this.handlers.onClose?.(event.code, event.reason);\r\n\r\n if (this.options.autoReconnect && this.state !== 'disconnected') {\r\n this.scheduleReconnect();\r\n } else {\r\n this.setState('disconnected');\r\n }\r\n };\r\n\r\n this.ws.onerror = () => {\r\n const error = new Error('WebSocket connection error');\r\n this.handlers.onError?.(error);\r\n };\r\n\r\n this.ws.onmessage = (event) => {\r\n try {\r\n const message = JSON.parse(event.data) as WsServerMessage;\r\n this.handleMessage(message);\r\n } catch {\r\n // Ignore parse errors for malformed messages\r\n }\r\n };\r\n }\r\n\r\n /**\r\n * Disconnect from the WebSocket server\r\n */\r\n disconnect(): void {\r\n this.setState('disconnected');\r\n this.stopPing();\r\n this.clearReconnectTimer();\r\n\r\n if (this.ws) {\r\n this.ws.close(1000, 'Client disconnect');\r\n this.ws = null;\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to a channel\r\n */\r\n subscribe(channel: WsChannel, coin?: string): void {\r\n const key = this.subscriptionKey(channel, coin);\r\n this.subscriptions.add(key);\r\n\r\n if (this.isConnected()) {\r\n this.send({ op: 'subscribe', channel, coin });\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to order book updates for a coin\r\n */\r\n subscribeOrderbook(coin: string): void {\r\n this.subscribe('orderbook', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to trades for a coin\r\n */\r\n subscribeTrades(coin: string): void {\r\n this.subscribe('trades', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to ticker updates for a coin\r\n */\r\n subscribeTicker(coin: string): void {\r\n this.subscribe('ticker', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to all tickers\r\n */\r\n subscribeAllTickers(): void {\r\n this.subscribe('all_tickers');\r\n }\r\n\r\n /**\r\n * Unsubscribe from a channel\r\n */\r\n unsubscribe(channel: WsChannel, coin?: string): void {\r\n const key = this.subscriptionKey(channel, coin);\r\n this.subscriptions.delete(key);\r\n\r\n if (this.isConnected()) {\r\n this.send({ op: 'unsubscribe', channel, coin });\r\n }\r\n }\r\n\r\n /**\r\n * Unsubscribe from order book updates for a coin\r\n */\r\n unsubscribeOrderbook(coin: string): void {\r\n this.unsubscribe('orderbook', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from trades for a coin\r\n */\r\n unsubscribeTrades(coin: string): void {\r\n this.unsubscribe('trades', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from ticker updates for a coin\r\n */\r\n unsubscribeTicker(coin: string): void {\r\n this.unsubscribe('ticker', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from all tickers\r\n */\r\n unsubscribeAllTickers(): void {\r\n this.unsubscribe('all_tickers');\r\n }\r\n\r\n // ==========================================================================\r\n // Historical Replay (Option B) - Like Tardis.dev\r\n // ==========================================================================\r\n\r\n /**\r\n * Start historical replay with timing preserved\r\n *\r\n * @param channel - Data channel to replay\r\n * @param coin - Trading pair (e.g., 'BTC', 'ETH')\r\n * @param options - Replay options\r\n *\r\n * @example\r\n * ```typescript\r\n * ws.replay('orderbook', 'BTC', {\r\n * start: Date.now() - 86400000, // 24 hours ago\r\n * speed: 10 // 10x faster than real-time\r\n * });\r\n * ```\r\n */\r\n replay(\r\n channel: WsChannel,\r\n coin: string,\r\n options: {\r\n start: number;\r\n end?: number;\r\n speed?: number;\r\n }\r\n ): void {\r\n this.send({\r\n op: 'replay',\r\n channel,\r\n coin,\r\n start: options.start,\r\n end: options.end,\r\n speed: options.speed ?? 1,\r\n });\r\n }\r\n\r\n /**\r\n * Pause the current replay\r\n */\r\n replayPause(): void {\r\n this.send({ op: 'replay.pause' });\r\n }\r\n\r\n /**\r\n * Resume a paused replay\r\n */\r\n replayResume(): void {\r\n this.send({ op: 'replay.resume' });\r\n }\r\n\r\n /**\r\n * Seek to a specific timestamp in the replay\r\n * @param timestamp - Unix timestamp in milliseconds\r\n */\r\n replaySeek(timestamp: number): void {\r\n this.send({ op: 'replay.seek', timestamp });\r\n }\r\n\r\n /**\r\n * Stop the current replay\r\n */\r\n replayStop(): void {\r\n this.send({ op: 'replay.stop' });\r\n }\r\n\r\n // ==========================================================================\r\n // Bulk Streaming (Option D) - Like Databento\r\n // ==========================================================================\r\n\r\n /**\r\n * Start bulk streaming for fast data download\r\n *\r\n * @param channel - Data channel to stream\r\n * @param coin - Trading pair (e.g., 'BTC', 'ETH')\r\n * @param options - Stream options\r\n *\r\n * @example\r\n * ```typescript\r\n * ws.stream('orderbook', 'ETH', {\r\n * start: Date.now() - 3600000, // 1 hour ago\r\n * end: Date.now(),\r\n * batchSize: 1000\r\n * });\r\n * ```\r\n */\r\n stream(\r\n channel: WsChannel,\r\n coin: string,\r\n options: {\r\n start: number;\r\n end: number;\r\n batchSize?: number;\r\n }\r\n ): void {\r\n this.send({\r\n op: 'stream',\r\n channel,\r\n coin,\r\n start: options.start,\r\n end: options.end,\r\n batch_size: options.batchSize ?? 1000,\r\n });\r\n }\r\n\r\n /**\r\n * Stop the current bulk stream\r\n */\r\n streamStop(): void {\r\n this.send({ op: 'stream.stop' });\r\n }\r\n\r\n // ==========================================================================\r\n // Event Handlers for Replay/Stream\r\n // ==========================================================================\r\n\r\n /**\r\n * Handle historical data points (replay mode)\r\n */\r\n onHistoricalData<T = unknown>(\r\n handler: (coin: string, timestamp: number, data: T) => void\r\n ): void {\r\n this.historicalDataHandlers.push(handler as (coin: string, timestamp: number, data: unknown) => void);\r\n }\r\n\r\n /**\r\n * Handle batched data (bulk stream mode)\r\n */\r\n onBatch<T = unknown>(\r\n handler: (coin: string, records: Array<{ timestamp: number; data: T }>) => void\r\n ): void {\r\n this.batchHandlers.push(handler as (coin: string, records: Array<{ timestamp: number; data: unknown }>) => void);\r\n }\r\n\r\n /**\r\n * Handle replay started event\r\n */\r\n onReplayStart(\r\n handler: (channel: WsChannel, coin: string, start: number, end: number, speed: number) => void\r\n ): void {\r\n this.replayStartHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle replay completed event\r\n */\r\n onReplayComplete(\r\n handler: (channel: WsChannel, coin: string, snapshotsSent: number) => void\r\n ): void {\r\n this.replayCompleteHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream started event\r\n */\r\n onStreamStart(\r\n handler: (channel: WsChannel, coin: string, start: number, end: number) => void\r\n ): void {\r\n this.streamStartHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream progress event\r\n */\r\n onStreamProgress(\r\n handler: (snapshotsSent: number) => void\r\n ): void {\r\n this.streamProgressHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream completed event\r\n */\r\n onStreamComplete(\r\n handler: (channel: WsChannel, coin: string, snapshotsSent: number) => void\r\n ): void {\r\n this.streamCompleteHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Get current connection state\r\n */\r\n getState(): WsConnectionState {\r\n return this.state;\r\n }\r\n\r\n /**\r\n * Check if connected\r\n */\r\n isConnected(): boolean {\r\n return this.ws?.readyState === WebSocket.OPEN;\r\n }\r\n\r\n /**\r\n * Set event handlers after construction\r\n */\r\n on<K extends keyof WsEventHandlers>(event: K, handler: WsEventHandlers[K]): void {\r\n this.handlers[event] = handler;\r\n }\r\n\r\n /**\r\n * Helper to handle typed orderbook data\r\n */\r\n onOrderbook(handler: (coin: string, data: OrderBook) => void): void {\r\n this.orderbookHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Helper to handle typed trade data\r\n */\r\n onTrades(handler: (coin: string, data: Trade[]) => void): void {\r\n this.tradesHandlers.push(handler);\r\n }\r\n\r\n // Private methods\r\n\r\n private send(message: WsClientMessage): void {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify(message));\r\n }\r\n }\r\n\r\n private setState(state: WsConnectionState): void {\r\n this.state = state;\r\n this.handlers.onStateChange?.(state);\r\n }\r\n\r\n private startPing(): void {\r\n this.stopPing();\r\n this.pingTimer = setInterval(() => {\r\n this.send({ op: 'ping' });\r\n }, this.options.pingInterval);\r\n }\r\n\r\n private stopPing(): void {\r\n if (this.pingTimer) {\r\n clearInterval(this.pingTimer);\r\n this.pingTimer = null;\r\n }\r\n }\r\n\r\n private subscriptionKey(channel: WsChannel, coin?: string): string {\r\n return coin ? `${channel}:${coin}` : channel;\r\n }\r\n\r\n private resubscribe(): void {\r\n for (const key of this.subscriptions) {\r\n const [channel, coin] = key.split(':') as [WsChannel, string | undefined];\r\n this.send({ op: 'subscribe', channel, coin });\r\n }\r\n }\r\n\r\n private scheduleReconnect(): void {\r\n if (this.reconnectAttempts >= this.options.maxReconnectAttempts) {\r\n this.setState('disconnected');\r\n return;\r\n }\r\n\r\n this.setState('reconnecting');\r\n this.reconnectAttempts++;\r\n\r\n const delay = this.options.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);\r\n\r\n this.reconnectTimer = setTimeout(() => {\r\n this.connect();\r\n }, delay);\r\n }\r\n\r\n private clearReconnectTimer(): void {\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = null;\r\n }\r\n }\r\n\r\n private handleMessage(message: WsServerMessage): void {\r\n // Call the generic onMessage handler first\r\n this.handlers.onMessage?.(message);\r\n\r\n // Dispatch to typed handlers based on message type\r\n switch (message.type) {\r\n case 'historical_data': {\r\n const msg = message as WsHistoricalData;\r\n for (const handler of this.historicalDataHandlers) {\r\n handler(msg.coin, msg.timestamp, msg.data);\r\n }\r\n break;\r\n }\r\n case 'historical_batch': {\r\n const msg = message as WsHistoricalBatch;\r\n for (const handler of this.batchHandlers) {\r\n handler(msg.coin, msg.data as Array<{ timestamp: number; data: unknown }>);\r\n }\r\n break;\r\n }\r\n case 'replay_started': {\r\n const msg = message as WsReplayStarted;\r\n for (const handler of this.replayStartHandlers) {\r\n handler(msg.channel, msg.coin, msg.start, msg.end, msg.speed);\r\n }\r\n break;\r\n }\r\n case 'replay_completed': {\r\n const msg = message as WsReplayCompleted;\r\n for (const handler of this.replayCompleteHandlers) {\r\n handler(msg.channel, msg.coin, msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'stream_started': {\r\n const msg = message as WsStreamStarted;\r\n for (const handler of this.streamStartHandlers) {\r\n handler(msg.channel, msg.coin, msg.start, msg.end);\r\n }\r\n break;\r\n }\r\n case 'stream_progress': {\r\n const msg = message as WsStreamProgress;\r\n for (const handler of this.streamProgressHandlers) {\r\n handler(msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'stream_completed': {\r\n const msg = message as WsStreamCompleted;\r\n for (const handler of this.streamCompleteHandlers) {\r\n handler(msg.channel, msg.coin, msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'data': {\r\n if (message.channel === 'orderbook') {\r\n // Transform raw Hyperliquid format to SDK OrderBook type\r\n const orderbook = transformOrderbook(message.coin, message.data as Record<string, unknown>);\r\n for (const handler of this.orderbookHandlers) {\r\n handler(message.coin, orderbook);\r\n }\r\n } else if (message.channel === 'trades') {\r\n for (const handler of this.tradesHandlers) {\r\n handler(message.coin, message.data as Trade[]);\r\n }\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/types.ts","../src/http.ts","../src/resources/orderbook.ts","../src/resources/trades.ts","../src/resources/instruments.ts","../src/resources/funding.ts","../src/resources/openinterest.ts","../src/client.ts","../src/websocket.ts"],"sourcesContent":["/**\r\n * Configuration options for the 0xarchive client\r\n */\r\nexport interface ClientOptions {\r\n /** Your 0xarchive API key */\r\n apiKey: string;\r\n /** Base URL for the API (defaults to https://api.0xarchive.io) */\r\n baseUrl?: string;\r\n /** Request timeout in milliseconds (defaults to 30000) */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Response metadata\r\n */\r\nexport interface ApiMeta {\r\n /** Number of records returned */\r\n count: number;\r\n /** Cursor for next page (if available) */\r\n next_cursor?: string;\r\n /** Unique request ID for debugging */\r\n request_id: string;\r\n}\r\n\r\n/**\r\n * Standard API response wrapper\r\n */\r\nexport interface ApiResponse<T> {\r\n success: boolean;\r\n data: T;\r\n meta: ApiMeta;\r\n}\r\n\r\n/**\r\n * Pagination parameters for list endpoints\r\n * @deprecated Use cursor-based pagination instead (CursorPaginationParams)\r\n */\r\nexport interface PaginationParams {\r\n /** Maximum number of results to return */\r\n limit?: number;\r\n /** @deprecated Use cursor instead. Number of results to skip */\r\n offset?: number;\r\n}\r\n\r\n/**\r\n * Time range parameters for historical queries\r\n * @deprecated Use CursorPaginationParams for better performance with large datasets\r\n */\r\nexport interface TimeRangeParams extends PaginationParams {\r\n /** Start timestamp (Unix ms or ISO string) - REQUIRED for history endpoints */\r\n start: number | string;\r\n /** End timestamp (Unix ms or ISO string) - REQUIRED for history endpoints */\r\n end: number | string;\r\n}\r\n\r\n// =============================================================================\r\n// Order Book Types\r\n// =============================================================================\r\n\r\n/**\r\n * A price level in the order book\r\n */\r\nexport interface PriceLevel {\r\n /** Price at this level */\r\n px: string;\r\n /** Total size at this price level */\r\n sz: string;\r\n /** Number of orders at this level */\r\n n: number;\r\n}\r\n\r\n/**\r\n * Order book snapshot\r\n */\r\nexport interface OrderBook {\r\n /** Trading pair symbol (e.g., BTC, ETH) */\r\n coin: string;\r\n /** Snapshot timestamp (UTC) */\r\n timestamp: string;\r\n /** Bid price levels (best bid first) */\r\n bids: PriceLevel[];\r\n /** Ask price levels (best ask first) */\r\n asks: PriceLevel[];\r\n /** Mid price (best bid + best ask) / 2 */\r\n mid_price?: string;\r\n /** Spread in absolute terms (best ask - best bid) */\r\n spread?: string;\r\n /** Spread in basis points */\r\n spread_bps?: string;\r\n}\r\n\r\nexport interface GetOrderBookParams {\r\n /** Timestamp to get order book at (Unix ms or ISO string) */\r\n timestamp?: number | string;\r\n /** Number of price levels to return per side */\r\n depth?: number;\r\n}\r\n\r\nexport interface OrderBookHistoryParams extends TimeRangeParams {\r\n /** Number of price levels to return per side */\r\n depth?: number;\r\n}\r\n\r\n// =============================================================================\r\n// Trade/Fill Types\r\n// =============================================================================\r\n\r\n/** Trade side: 'A' (ask/sell) or 'B' (bid/buy) */\r\nexport type TradeSide = 'A' | 'B';\r\n\r\n/** Position direction */\r\nexport type TradeDirection = 'Open Long' | 'Open Short' | 'Close Long' | 'Close Short';\r\n\r\n/** Data source */\r\nexport type DataSource = 's3' | 'ws' | 'api';\r\n\r\n/**\r\n * Trade/fill record with full execution details\r\n */\r\nexport interface Trade {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Trade side: 'A' (ask/sell) or 'B' (bid/buy) */\r\n side: TradeSide;\r\n /** Execution price */\r\n price: string;\r\n /** Trade size */\r\n size: string;\r\n /** Execution timestamp (UTC) */\r\n timestamp: string;\r\n /** Blockchain transaction hash */\r\n tx_hash?: string;\r\n /** Unique trade ID */\r\n trade_id?: number;\r\n /** Associated order ID */\r\n order_id?: number;\r\n /** True if taker (crossed the spread), false if maker */\r\n crossed?: boolean;\r\n /** Trading fee amount */\r\n fee?: string;\r\n /** Fee denomination (e.g., USDC) */\r\n fee_token?: string;\r\n /** Realized PnL if closing a position */\r\n closed_pnl?: string;\r\n /** Position direction */\r\n direction?: TradeDirection;\r\n /** Position size before this trade */\r\n start_position?: string;\r\n /** Data source */\r\n source?: DataSource;\r\n /** User's wallet address */\r\n user_address?: string;\r\n}\r\n\r\n/**\r\n * @deprecated Use GetTradesCursorParams instead for better performance with large datasets\r\n */\r\nexport interface GetTradesParams extends TimeRangeParams {\r\n /** Filter by side */\r\n side?: TradeSide;\r\n}\r\n\r\n/**\r\n * Cursor-based pagination parameters for trades (recommended)\r\n * More efficient than offset-based pagination for large datasets.\r\n * The cursor is a timestamp - use the `nextCursor` from the response to get the next page.\r\n */\r\nexport interface CursorPaginationParams {\r\n /** Start timestamp (Unix ms or ISO string) - REQUIRED */\r\n start: number | string;\r\n /** End timestamp (Unix ms or ISO string) - REQUIRED */\r\n end: number | string;\r\n /** Cursor from previous response's nextCursor (timestamp). If not provided, starts from the beginning of the range. */\r\n cursor?: number | string;\r\n /** Maximum number of results to return (default: 100, max: 1000) */\r\n limit?: number;\r\n}\r\n\r\n/**\r\n * Parameters for getting trades with cursor-based pagination (recommended)\r\n */\r\nexport interface GetTradesCursorParams extends CursorPaginationParams {\r\n /** Filter by side */\r\n side?: TradeSide;\r\n}\r\n\r\n/**\r\n * Response with cursor for pagination\r\n */\r\nexport interface CursorResponse<T> {\r\n data: T;\r\n /** Cursor for next page (use as cursor parameter) */\r\n nextCursor?: string;\r\n}\r\n\r\n// =============================================================================\r\n// Instruments Types\r\n// =============================================================================\r\n\r\n/** Instrument type */\r\nexport type InstrumentType = 'perp' | 'spot';\r\n\r\n/**\r\n * Trading instrument metadata\r\n */\r\nexport interface Instrument {\r\n /** Instrument symbol (e.g., BTC) */\r\n name: string;\r\n /** Size decimal precision */\r\n szDecimals: number;\r\n /** Maximum leverage allowed */\r\n maxLeverage?: number;\r\n /** If true, only isolated margin mode is allowed */\r\n onlyIsolated?: boolean;\r\n /** Type of instrument */\r\n instrumentType?: InstrumentType;\r\n /** Whether the instrument is currently tradeable */\r\n isActive: boolean;\r\n}\r\n\r\n// =============================================================================\r\n// Funding Types\r\n// =============================================================================\r\n\r\n/**\r\n * Funding rate record\r\n */\r\nexport interface FundingRate {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Funding timestamp (UTC) */\r\n timestamp: string;\r\n /** Funding rate as decimal (e.g., 0.0001 = 0.01%) */\r\n funding_rate: string;\r\n /** Premium component of funding rate */\r\n premium?: string;\r\n}\r\n\r\n// =============================================================================\r\n// Open Interest Types\r\n// =============================================================================\r\n\r\n/**\r\n * Open interest snapshot with market context\r\n */\r\nexport interface OpenInterest {\r\n /** Trading pair symbol */\r\n coin: string;\r\n /** Snapshot timestamp (UTC) */\r\n timestamp: string;\r\n /** Total open interest in contracts */\r\n open_interest: string;\r\n /** Mark price used for liquidations */\r\n mark_price?: string;\r\n /** Oracle price from external feed */\r\n oracle_price?: string;\r\n /** 24-hour notional volume */\r\n day_ntl_volume?: string;\r\n /** Price 24 hours ago */\r\n prev_day_price?: string;\r\n /** Current mid price */\r\n mid_price?: string;\r\n /** Impact bid price for liquidations */\r\n impact_bid_price?: string;\r\n /** Impact ask price for liquidations */\r\n impact_ask_price?: string;\r\n}\r\n\r\n// =============================================================================\r\n// WebSocket Types\r\n// =============================================================================\r\n\r\n/** WebSocket channel types. Note: ticker/all_tickers are real-time only. */\r\nexport type WsChannel = 'orderbook' | 'trades' | 'ticker' | 'all_tickers';\r\n\r\n/** Subscribe message from client */\r\nexport interface WsSubscribe {\r\n op: 'subscribe';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Unsubscribe message from client */\r\nexport interface WsUnsubscribe {\r\n op: 'unsubscribe';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Ping message from client */\r\nexport interface WsPing {\r\n op: 'ping';\r\n}\r\n\r\n/** Replay message from client - replays historical data with timing preserved */\r\nexport interface WsReplay {\r\n op: 'replay';\r\n channel: WsChannel;\r\n coin?: string;\r\n /** Start timestamp (Unix ms) */\r\n start: number;\r\n /** End timestamp (Unix ms, defaults to now) */\r\n end?: number;\r\n /** Playback speed multiplier (1 = real-time, 10 = 10x faster) */\r\n speed?: number;\r\n}\r\n\r\n/** Replay control messages */\r\nexport interface WsReplayPause { op: 'replay.pause'; }\r\nexport interface WsReplayResume { op: 'replay.resume'; }\r\nexport interface WsReplaySeek { op: 'replay.seek'; timestamp: number; }\r\nexport interface WsReplayStop { op: 'replay.stop'; }\r\n\r\n/** Stream message from client - bulk download historical data */\r\nexport interface WsStream {\r\n op: 'stream';\r\n channel: WsChannel;\r\n coin?: string;\r\n /** Start timestamp (Unix ms) */\r\n start: number;\r\n /** End timestamp (Unix ms) */\r\n end: number;\r\n /** Batch size (records per message) */\r\n batch_size?: number;\r\n}\r\n\r\n/** Stream control messages */\r\nexport interface WsStreamStop { op: 'stream.stop'; }\r\n\r\n/** Client message union type */\r\nexport type WsClientMessage =\r\n | WsSubscribe\r\n | WsUnsubscribe\r\n | WsPing\r\n | WsReplay\r\n | WsReplayPause\r\n | WsReplayResume\r\n | WsReplaySeek\r\n | WsReplayStop\r\n | WsStream\r\n | WsStreamStop;\r\n\r\n/** Subscription confirmed from server */\r\nexport interface WsSubscribed {\r\n type: 'subscribed';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Unsubscription confirmed from server */\r\nexport interface WsUnsubscribed {\r\n type: 'unsubscribed';\r\n channel: WsChannel;\r\n coin?: string;\r\n}\r\n\r\n/** Pong response from server */\r\nexport interface WsPong {\r\n type: 'pong';\r\n}\r\n\r\n/** Error from server */\r\nexport interface WsError {\r\n type: 'error';\r\n message: string;\r\n}\r\n\r\n/** Data message from server (real-time) */\r\nexport interface WsData<T = unknown> {\r\n type: 'data';\r\n channel: WsChannel;\r\n coin: string;\r\n data: T;\r\n}\r\n\r\n/** Replay started response */\r\nexport interface WsReplayStarted {\r\n type: 'replay_started';\r\n channel: WsChannel;\r\n coin: string;\r\n /** Start timestamp in milliseconds */\r\n start: number;\r\n /** End timestamp in milliseconds */\r\n end: number;\r\n /** Playback speed multiplier */\r\n speed: number;\r\n}\r\n\r\n/** Replay paused response */\r\nexport interface WsReplayPaused {\r\n type: 'replay_paused';\r\n current_timestamp: number;\r\n}\r\n\r\n/** Replay resumed response */\r\nexport interface WsReplayResumed {\r\n type: 'replay_resumed';\r\n current_timestamp: number;\r\n}\r\n\r\n/** Replay completed response */\r\nexport interface WsReplayCompleted {\r\n type: 'replay_completed';\r\n channel: WsChannel;\r\n coin: string;\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Replay stopped response */\r\nexport interface WsReplayStopped {\r\n type: 'replay_stopped';\r\n}\r\n\r\n/** Historical data point (replay mode) */\r\nexport interface WsHistoricalData<T = unknown> {\r\n type: 'historical_data';\r\n channel: WsChannel;\r\n coin: string;\r\n timestamp: number;\r\n data: T;\r\n}\r\n\r\n/** Stream started response */\r\nexport interface WsStreamStarted {\r\n type: 'stream_started';\r\n channel: WsChannel;\r\n coin: string;\r\n /** Start timestamp in milliseconds */\r\n start: number;\r\n /** End timestamp in milliseconds */\r\n end: number;\r\n}\r\n\r\n/** Stream progress response (sent periodically during streaming) */\r\nexport interface WsStreamProgress {\r\n type: 'stream_progress';\r\n snapshots_sent: number;\r\n}\r\n\r\n/** A record with timestamp for batched data */\r\nexport interface TimestampedRecord<T = unknown> {\r\n timestamp: number;\r\n data: T;\r\n}\r\n\r\n/** Batch of historical data (bulk streaming) */\r\nexport interface WsHistoricalBatch<T = unknown> {\r\n type: 'historical_batch';\r\n channel: WsChannel;\r\n coin: string;\r\n data: TimestampedRecord<T>[];\r\n}\r\n\r\n/** Stream completed response */\r\nexport interface WsStreamCompleted {\r\n type: 'stream_completed';\r\n channel: WsChannel;\r\n coin: string;\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Stream stopped response */\r\nexport interface WsStreamStopped {\r\n type: 'stream_stopped';\r\n snapshots_sent: number;\r\n}\r\n\r\n/** Server message union type */\r\nexport type WsServerMessage =\r\n | WsSubscribed\r\n | WsUnsubscribed\r\n | WsPong\r\n | WsError\r\n | WsData\r\n | WsReplayStarted\r\n | WsReplayPaused\r\n | WsReplayResumed\r\n | WsReplayCompleted\r\n | WsReplayStopped\r\n | WsHistoricalData\r\n | WsStreamStarted\r\n | WsStreamProgress\r\n | WsHistoricalBatch\r\n | WsStreamCompleted\r\n | WsStreamStopped;\r\n\r\n/**\r\n * WebSocket connection options.\r\n *\r\n * The server sends WebSocket ping frames every 30 seconds and will disconnect\r\n * idle connections after 60 seconds. The SDK automatically handles keep-alive\r\n * by sending application-level pings at the configured interval.\r\n */\r\nexport interface WsOptions {\r\n /** API key for authentication */\r\n apiKey: string;\r\n /** WebSocket URL (defaults to wss://api.0xarchive.io/ws) */\r\n wsUrl?: string;\r\n /** Auto-reconnect on disconnect (defaults to true) */\r\n autoReconnect?: boolean;\r\n /** Reconnect delay in ms (defaults to 1000) */\r\n reconnectDelay?: number;\r\n /** Maximum reconnect attempts (defaults to 10) */\r\n maxReconnectAttempts?: number;\r\n /** Ping interval in ms to keep connection alive (defaults to 30000). Server disconnects after 60s idle. */\r\n pingInterval?: number;\r\n}\r\n\r\n/** WebSocket connection state */\r\nexport type WsConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';\r\n\r\n/** WebSocket event handlers */\r\nexport interface WsEventHandlers {\r\n onOpen?: () => void;\r\n onClose?: (code: number, reason: string) => void;\r\n onError?: (error: Error) => void;\r\n onMessage?: (message: WsServerMessage) => void;\r\n onStateChange?: (state: WsConnectionState) => void;\r\n}\r\n\r\n// =============================================================================\r\n// Error Types\r\n// =============================================================================\r\n\r\n/**\r\n * API error response\r\n */\r\nexport interface ApiError {\r\n code: number;\r\n error: string;\r\n}\r\n\r\n/**\r\n * SDK error class\r\n */\r\nexport class OxArchiveError extends Error {\r\n code: number;\r\n requestId?: string;\r\n\r\n constructor(message: string, code: number, requestId?: string) {\r\n super(message);\r\n this.name = 'OxArchiveError';\r\n this.code = code;\r\n this.requestId = requestId;\r\n }\r\n}\r\n\r\n/** Timestamp can be Unix ms (number), ISO string, or Date object */\r\nexport type Timestamp = number | string | Date;\r\n","import type { ApiResponse, ApiError } from './types';\r\nimport { OxArchiveError } from './types';\r\n\r\nexport interface HttpClientOptions {\r\n baseUrl: string;\r\n apiKey: string;\r\n timeout: number;\r\n}\r\n\r\n/**\r\n * Internal HTTP client for making API requests\r\n */\r\nexport class HttpClient {\r\n private baseUrl: string;\r\n private apiKey: string;\r\n private timeout: number;\r\n\r\n constructor(options: HttpClientOptions) {\r\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\r\n this.apiKey = options.apiKey;\r\n this.timeout = options.timeout;\r\n }\r\n\r\n /**\r\n * Make a GET request to the API\r\n */\r\n async get<T>(path: string, params?: Record<string, unknown>): Promise<T> {\r\n const url = new URL(`${this.baseUrl}${path}`);\r\n\r\n if (params) {\r\n for (const [key, value] of Object.entries(params)) {\r\n if (value !== undefined && value !== null) {\r\n url.searchParams.set(key, String(value));\r\n }\r\n }\r\n }\r\n\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url.toString(), {\r\n method: 'GET',\r\n headers: {\r\n 'X-API-Key': this.apiKey,\r\n 'Content-Type': 'application/json',\r\n },\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n const data = await response.json();\r\n\r\n if (!response.ok) {\r\n const error = data as ApiError;\r\n throw new OxArchiveError(\r\n error.error || `Request failed with status ${response.status}`,\r\n response.status,\r\n (data as ApiResponse<unknown>).meta?.request_id\r\n );\r\n }\r\n\r\n return data as T;\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof OxArchiveError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof Error && error.name === 'AbortError') {\r\n throw new OxArchiveError(`Request timeout after ${this.timeout}ms`, 408);\r\n }\r\n\r\n throw new OxArchiveError(\r\n error instanceof Error ? error.message : 'Unknown error',\r\n 500\r\n );\r\n }\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type {\r\n ApiResponse,\r\n OrderBook,\r\n GetOrderBookParams,\r\n OrderBookHistoryParams,\r\n} from '../types';\r\n\r\n/**\r\n * Order book API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current order book\r\n * const orderbook = await client.orderbook.get('BTC');\r\n *\r\n * // Get order book at specific timestamp\r\n * const historical = await client.orderbook.get('ETH', {\r\n * timestamp: 1704067200000,\r\n * depth: 10\r\n * });\r\n *\r\n * // Get order book history\r\n * const history = await client.orderbook.history('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n * ```\r\n */\r\nexport class OrderBookResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get order book snapshot for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Optional parameters\r\n * @returns Order book snapshot\r\n */\r\n async get(coin: string, params?: GetOrderBookParams): Promise<OrderBook> {\r\n const response = await this.http.get<ApiResponse<OrderBook>>(\r\n `/v1/orderbook/${coin.toUpperCase()}`,\r\n params as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get historical order book snapshots\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of order book snapshots\r\n */\r\n async history(\r\n coin: string,\r\n params: OrderBookHistoryParams\r\n ): Promise<OrderBook[]> {\r\n const response = await this.http.get<ApiResponse<OrderBook[]>>(\r\n `/v1/orderbook/${coin.toUpperCase()}/history`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, Trade, GetTradesParams, GetTradesCursorParams, CursorResponse } from '../types';\r\n\r\n/**\r\n * Trades API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get recent trades\r\n * const trades = await client.trades.recent('BTC');\r\n *\r\n * // Get trade history with cursor-based pagination (recommended)\r\n * let result = await client.trades.list('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 1000\r\n * });\r\n *\r\n * // Get all pages\r\n * const allTrades = [...result.data];\r\n * while (result.nextCursor) {\r\n * result = await client.trades.list('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * cursor: result.nextCursor,\r\n * limit: 1000\r\n * });\r\n * allTrades.push(...result.data);\r\n * }\r\n * ```\r\n */\r\nexport class TradesResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get trade history for a coin using cursor-based pagination\r\n *\r\n * Uses cursor-based pagination by default, which is more efficient for large datasets.\r\n * Use the `nextCursor` from the response as the `cursor` parameter to get the next page.\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and cursor pagination parameters (start and end are required)\r\n * @returns Object with trades array and nextCursor for pagination\r\n *\r\n * @example\r\n * ```typescript\r\n * // First page\r\n * let result = await client.trades.list('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 1000\r\n * });\r\n *\r\n * // Subsequent pages\r\n * while (result.nextCursor) {\r\n * result = await client.trades.list('BTC', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * cursor: result.nextCursor,\r\n * limit: 1000\r\n * });\r\n * }\r\n * ```\r\n */\r\n async list(coin: string, params: GetTradesCursorParams): Promise<CursorResponse<Trade[]>> {\r\n const response = await this.http.get<ApiResponse<Trade[]>>(\r\n `/v1/trades/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return {\r\n data: response.data,\r\n nextCursor: response.meta.next_cursor,\r\n };\r\n }\r\n\r\n /**\r\n * Get most recent trades for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param limit - Number of trades to return (default: 100)\r\n * @returns Array of recent trades\r\n */\r\n async recent(coin: string, limit?: number): Promise<Trade[]> {\r\n const response = await this.http.get<ApiResponse<Trade[]>>(\r\n `/v1/trades/${coin.toUpperCase()}/recent`,\r\n { limit }\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get trade history using cursor-based pagination (explicit endpoint)\r\n *\r\n * @deprecated Use `list()` instead - it now uses cursor-based pagination by default.\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Cursor pagination parameters (start and end are required)\r\n * @returns Object with trades array and nextCursor for pagination\r\n */\r\n async listWithCursor(coin: string, params: GetTradesCursorParams): Promise<CursorResponse<Trade[]>> {\r\n // Now just calls the main endpoint since it supports cursor by default\r\n return this.list(coin, params);\r\n }\r\n\r\n /**\r\n * Get trade history using offset-based pagination\r\n *\r\n * @deprecated Use `list()` with cursor-based pagination instead for better performance.\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and offset pagination parameters\r\n * @returns Array of trades (without cursor response wrapper)\r\n */\r\n async listWithOffset(coin: string, params: GetTradesParams): Promise<Trade[]> {\r\n const response = await this.http.get<ApiResponse<Trade[]>>(\r\n `/v1/trades/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, Instrument } from '../types';\r\n\r\n/**\r\n * Instruments API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // List all instruments\r\n * const instruments = await client.instruments.list();\r\n *\r\n * // Get specific instrument\r\n * const btc = await client.instruments.get('BTC');\r\n * ```\r\n */\r\nexport class InstrumentsResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * List all available trading instruments\r\n *\r\n * @returns Array of instruments\r\n */\r\n async list(): Promise<Instrument[]> {\r\n const response = await this.http.get<ApiResponse<Instrument[]>>(\r\n '/v1/instruments'\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get a specific instrument by coin symbol\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Instrument details\r\n */\r\n async get(coin: string): Promise<Instrument> {\r\n const response = await this.http.get<ApiResponse<Instrument>>(\r\n `/v1/instruments/${coin.toUpperCase()}`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, FundingRate, TimeRangeParams } from '../types';\r\n\r\n/**\r\n * Funding rates API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current funding rate\r\n * const current = await client.funding.current('BTC');\r\n *\r\n * // Get funding rate history\r\n * const history = await client.funding.history('ETH', {\r\n * start: Date.now() - 86400000 * 7,\r\n * end: Date.now()\r\n * });\r\n * ```\r\n */\r\nexport class FundingResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get funding rate history for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of funding rate records\r\n */\r\n async history(coin: string, params: TimeRangeParams): Promise<FundingRate[]> {\r\n const response = await this.http.get<ApiResponse<FundingRate[]>>(\r\n `/v1/funding/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get current funding rate for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Current funding rate\r\n */\r\n async current(coin: string): Promise<FundingRate> {\r\n const response = await this.http.get<ApiResponse<FundingRate>>(\r\n `/v1/funding/${coin.toUpperCase()}/current`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { HttpClient } from '../http';\r\nimport type { ApiResponse, OpenInterest, TimeRangeParams } from '../types';\r\n\r\n/**\r\n * Open interest API resource\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get current open interest\r\n * const current = await client.openInterest.current('BTC');\r\n *\r\n * // Get open interest history\r\n * const history = await client.openInterest.history('ETH', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n * ```\r\n */\r\nexport class OpenInterestResource {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get open interest history for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @param params - Time range and pagination parameters (start is required)\r\n * @returns Array of open interest records\r\n */\r\n async history(coin: string, params: TimeRangeParams): Promise<OpenInterest[]> {\r\n const response = await this.http.get<ApiResponse<OpenInterest[]>>(\r\n `/v1/openinterest/${coin.toUpperCase()}`,\r\n params as unknown as Record<string, unknown>\r\n );\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get current open interest for a coin\r\n *\r\n * @param coin - The coin symbol (e.g., 'BTC', 'ETH')\r\n * @returns Current open interest\r\n */\r\n async current(coin: string): Promise<OpenInterest> {\r\n const response = await this.http.get<ApiResponse<OpenInterest>>(\r\n `/v1/openinterest/${coin.toUpperCase()}/current`\r\n );\r\n return response.data;\r\n }\r\n}\r\n","import type { ClientOptions } from './types';\r\nimport { HttpClient } from './http';\r\nimport {\r\n OrderBookResource,\r\n TradesResource,\r\n InstrumentsResource,\r\n FundingResource,\r\n OpenInterestResource,\r\n} from './resources';\r\n\r\nconst DEFAULT_BASE_URL = 'https://api.0xarchive.io';\r\nconst DEFAULT_TIMEOUT = 30000;\r\n\r\n/**\r\n * 0xarchive API client\r\n *\r\n * @example\r\n * ```typescript\r\n * import { OxArchive } from '@0xarchive/sdk';\r\n *\r\n * const client = new OxArchive({ apiKey: 'ox_your_api_key' });\r\n *\r\n * // Get current order book\r\n * const orderbook = await client.orderbook.get('BTC');\r\n * console.log(`BTC mid price: ${orderbook.mid_price}`);\r\n *\r\n * // Get historical data\r\n * const history = await client.orderbook.history('ETH', {\r\n * start: Date.now() - 86400000,\r\n * end: Date.now(),\r\n * limit: 100\r\n * });\r\n *\r\n * // List all instruments\r\n * const instruments = await client.instruments.list();\r\n * ```\r\n */\r\nexport class OxArchive {\r\n private http: HttpClient;\r\n\r\n /**\r\n * Order book data (L2 snapshots from April 2023)\r\n */\r\n public readonly orderbook: OrderBookResource;\r\n\r\n /**\r\n * Trade/fill history\r\n */\r\n public readonly trades: TradesResource;\r\n\r\n /**\r\n * Trading instruments metadata\r\n */\r\n public readonly instruments: InstrumentsResource;\r\n\r\n /**\r\n * Funding rates\r\n */\r\n public readonly funding: FundingResource;\r\n\r\n /**\r\n * Open interest\r\n */\r\n public readonly openInterest: OpenInterestResource;\r\n\r\n /**\r\n * Create a new 0xarchive client\r\n *\r\n * @param options - Client configuration options\r\n */\r\n constructor(options: ClientOptions) {\r\n if (!options.apiKey) {\r\n throw new Error('API key is required. Get one at https://0xarchive.io/signup');\r\n }\r\n\r\n this.http = new HttpClient({\r\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\r\n apiKey: options.apiKey,\r\n timeout: options.timeout ?? DEFAULT_TIMEOUT,\r\n });\r\n\r\n // Initialize resource namespaces\r\n this.orderbook = new OrderBookResource(this.http);\r\n this.trades = new TradesResource(this.http);\r\n this.instruments = new InstrumentsResource(this.http);\r\n this.funding = new FundingResource(this.http);\r\n this.openInterest = new OpenInterestResource(this.http);\r\n }\r\n}\r\n","/**\r\n * WebSocket client for 0xarchive real-time streaming, replay, and bulk download\r\n *\r\n * @example Real-time streaming\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect({\r\n * onMessage: (msg) => console.log(msg)\r\n * });\r\n * ws.subscribeOrderbook('BTC');\r\n * ```\r\n *\r\n * @example Historical replay (like Tardis.dev)\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect();\r\n * ws.onHistoricalData((coin, timestamp, data) => {\r\n * console.log(`${new Date(timestamp)}: ${data.mid_price}`);\r\n * });\r\n * ws.replay('orderbook', 'BTC', {\r\n * start: Date.now() - 86400000,\r\n * speed: 10 // 10x speed\r\n * });\r\n * ```\r\n *\r\n * @example Bulk streaming (like Databento)\r\n * ```typescript\r\n * const ws = new OxArchiveWs({ apiKey: 'ox_...' });\r\n * ws.connect();\r\n * const batches: OrderBook[] = [];\r\n * ws.onBatch((coin, records) => {\r\n * batches.push(...records.map(r => r.data));\r\n * });\r\n * ws.onStreamComplete((channel, coin, count) => {\r\n * console.log(`Downloaded ${count} records`);\r\n * });\r\n * ws.stream('orderbook', 'ETH', {\r\n * start: Date.now() - 3600000,\r\n * end: Date.now(),\r\n * batchSize: 1000\r\n * });\r\n * ```\r\n */\r\n\r\nimport type {\r\n WsOptions,\r\n WsChannel,\r\n WsClientMessage,\r\n WsServerMessage,\r\n WsConnectionState,\r\n WsEventHandlers,\r\n OrderBook,\r\n PriceLevel,\r\n Trade,\r\n WsHistoricalData,\r\n WsHistoricalBatch,\r\n WsReplayStarted,\r\n WsReplayCompleted,\r\n WsStreamStarted,\r\n WsStreamCompleted,\r\n WsStreamProgress,\r\n} from './types';\r\n\r\nconst DEFAULT_WS_URL = 'wss://api.0xarchive.io/ws';\r\nconst DEFAULT_PING_INTERVAL = 30000; // 30 seconds\r\nconst DEFAULT_RECONNECT_DELAY = 1000;\r\nconst DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;\r\n\r\n// Server idle timeout is 60 seconds. The SDK sends pings every 30 seconds\r\n// to keep the connection alive. Browser WebSocket API automatically responds\r\n// to WebSocket protocol-level ping frames from the server.\r\n\r\n/**\r\n * Transform raw Hyperliquid orderbook format to SDK OrderBook type.\r\n * Raw format: { coin, levels: [[{px, sz, n}, ...], [{px, sz, n}, ...]], time }\r\n * SDK format: { coin, timestamp, bids: [{px, sz, n}], asks: [{px, sz, n}], mid_price, spread, spread_bps }\r\n */\r\nfunction transformOrderbook(coin: string, raw: Record<string, unknown>): OrderBook {\r\n // Check if already in SDK format (from REST API or historical replay)\r\n if ('bids' in raw && 'asks' in raw) {\r\n return raw as unknown as OrderBook;\r\n }\r\n\r\n // Transform from Hyperliquid raw format\r\n // levels is [[{px, sz, n}, ...], [{px, sz, n}, ...]] where [0]=bids, [1]=asks\r\n const levels = raw.levels as Array<Array<{ px: string; sz: string; n: number }>> | undefined;\r\n const time = raw.time as number | undefined;\r\n\r\n const bids: PriceLevel[] = [];\r\n const asks: PriceLevel[] = [];\r\n\r\n if (levels && levels.length >= 2) {\r\n // levels[0] = bids, levels[1] = asks\r\n // Each level is already {px, sz, n} object\r\n for (const level of levels[0] || []) {\r\n bids.push({ px: level.px, sz: level.sz, n: level.n });\r\n }\r\n for (const level of levels[1] || []) {\r\n asks.push({ px: level.px, sz: level.sz, n: level.n });\r\n }\r\n }\r\n\r\n // Calculate mid price and spread\r\n let mid_price: string | undefined;\r\n let spread: string | undefined;\r\n let spread_bps: string | undefined;\r\n\r\n if (bids.length > 0 && asks.length > 0) {\r\n const bestBid = parseFloat(bids[0].px);\r\n const bestAsk = parseFloat(asks[0].px);\r\n const mid = (bestBid + bestAsk) / 2;\r\n mid_price = mid.toString();\r\n spread = (bestAsk - bestBid).toString();\r\n spread_bps = ((bestAsk - bestBid) / mid * 10000).toFixed(2);\r\n }\r\n\r\n return {\r\n coin,\r\n timestamp: time ? new Date(time).toISOString() : new Date().toISOString(),\r\n bids,\r\n asks,\r\n mid_price,\r\n spread,\r\n spread_bps,\r\n };\r\n}\r\n\r\n/**\r\n * WebSocket client for real-time data streaming.\r\n *\r\n * **Keep-Alive:** The server sends WebSocket ping frames every 30 seconds\r\n * and will disconnect idle connections after 60 seconds. This SDK automatically\r\n * handles keep-alive by sending application-level pings at the configured interval\r\n * (default: 30 seconds). The browser WebSocket API automatically responds to\r\n * server ping frames.\r\n */\r\nexport class OxArchiveWs {\r\n private ws: WebSocket | null = null;\r\n private options: Required<WsOptions>;\r\n private handlers: WsEventHandlers = {};\r\n private subscriptions: Set<string> = new Set();\r\n private state: WsConnectionState = 'disconnected';\r\n private reconnectAttempts = 0;\r\n private pingTimer: ReturnType<typeof setInterval> | null = null;\r\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n // Typed event handlers (separate from WsEventHandlers to avoid wrapping issues)\r\n private historicalDataHandlers: Array<(coin: string, timestamp: number, data: unknown) => void> = [];\r\n private batchHandlers: Array<(coin: string, records: Array<{ timestamp: number; data: unknown }>) => void> = [];\r\n private replayStartHandlers: Array<(channel: WsChannel, coin: string, start: number, end: number, speed: number) => void> = [];\r\n private replayCompleteHandlers: Array<(channel: WsChannel, coin: string, snapshotsSent: number) => void> = [];\r\n private streamStartHandlers: Array<(channel: WsChannel, coin: string, start: number, end: number) => void> = [];\r\n private streamProgressHandlers: Array<(snapshotsSent: number) => void> = [];\r\n private streamCompleteHandlers: Array<(channel: WsChannel, coin: string, snapshotsSent: number) => void> = [];\r\n private orderbookHandlers: Array<(coin: string, data: OrderBook) => void> = [];\r\n private tradesHandlers: Array<(coin: string, data: Trade[]) => void> = [];\r\n\r\n constructor(options: WsOptions) {\r\n this.options = {\r\n apiKey: options.apiKey,\r\n wsUrl: options.wsUrl ?? DEFAULT_WS_URL,\r\n autoReconnect: options.autoReconnect ?? true,\r\n reconnectDelay: options.reconnectDelay ?? DEFAULT_RECONNECT_DELAY,\r\n maxReconnectAttempts: options.maxReconnectAttempts ?? DEFAULT_MAX_RECONNECT_ATTEMPTS,\r\n pingInterval: options.pingInterval ?? DEFAULT_PING_INTERVAL,\r\n };\r\n }\r\n\r\n /**\r\n * Connect to the WebSocket server\r\n */\r\n connect(handlers?: WsEventHandlers): void {\r\n if (handlers) {\r\n this.handlers = handlers;\r\n }\r\n\r\n this.setState('connecting');\r\n\r\n const url = `${this.options.wsUrl}?apiKey=${encodeURIComponent(this.options.apiKey)}`;\r\n this.ws = new WebSocket(url);\r\n\r\n this.ws.onopen = () => {\r\n this.reconnectAttempts = 0;\r\n this.setState('connected');\r\n this.startPing();\r\n this.resubscribe();\r\n this.handlers.onOpen?.();\r\n };\r\n\r\n this.ws.onclose = (event) => {\r\n this.stopPing();\r\n this.handlers.onClose?.(event.code, event.reason);\r\n\r\n if (this.options.autoReconnect && this.state !== 'disconnected') {\r\n this.scheduleReconnect();\r\n } else {\r\n this.setState('disconnected');\r\n }\r\n };\r\n\r\n this.ws.onerror = () => {\r\n const error = new Error('WebSocket connection error');\r\n this.handlers.onError?.(error);\r\n };\r\n\r\n this.ws.onmessage = (event) => {\r\n try {\r\n const message = JSON.parse(event.data) as WsServerMessage;\r\n this.handleMessage(message);\r\n } catch {\r\n // Ignore parse errors for malformed messages\r\n }\r\n };\r\n }\r\n\r\n /**\r\n * Disconnect from the WebSocket server\r\n */\r\n disconnect(): void {\r\n this.setState('disconnected');\r\n this.stopPing();\r\n this.clearReconnectTimer();\r\n\r\n if (this.ws) {\r\n this.ws.close(1000, 'Client disconnect');\r\n this.ws = null;\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to a channel\r\n */\r\n subscribe(channel: WsChannel, coin?: string): void {\r\n const key = this.subscriptionKey(channel, coin);\r\n this.subscriptions.add(key);\r\n\r\n if (this.isConnected()) {\r\n this.send({ op: 'subscribe', channel, coin });\r\n }\r\n }\r\n\r\n /**\r\n * Subscribe to order book updates for a coin\r\n */\r\n subscribeOrderbook(coin: string): void {\r\n this.subscribe('orderbook', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to trades for a coin\r\n */\r\n subscribeTrades(coin: string): void {\r\n this.subscribe('trades', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to ticker updates for a coin\r\n */\r\n subscribeTicker(coin: string): void {\r\n this.subscribe('ticker', coin);\r\n }\r\n\r\n /**\r\n * Subscribe to all tickers\r\n */\r\n subscribeAllTickers(): void {\r\n this.subscribe('all_tickers');\r\n }\r\n\r\n /**\r\n * Unsubscribe from a channel\r\n */\r\n unsubscribe(channel: WsChannel, coin?: string): void {\r\n const key = this.subscriptionKey(channel, coin);\r\n this.subscriptions.delete(key);\r\n\r\n if (this.isConnected()) {\r\n this.send({ op: 'unsubscribe', channel, coin });\r\n }\r\n }\r\n\r\n /**\r\n * Unsubscribe from order book updates for a coin\r\n */\r\n unsubscribeOrderbook(coin: string): void {\r\n this.unsubscribe('orderbook', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from trades for a coin\r\n */\r\n unsubscribeTrades(coin: string): void {\r\n this.unsubscribe('trades', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from ticker updates for a coin\r\n */\r\n unsubscribeTicker(coin: string): void {\r\n this.unsubscribe('ticker', coin);\r\n }\r\n\r\n /**\r\n * Unsubscribe from all tickers\r\n */\r\n unsubscribeAllTickers(): void {\r\n this.unsubscribe('all_tickers');\r\n }\r\n\r\n // ==========================================================================\r\n // Historical Replay (Option B) - Like Tardis.dev\r\n // ==========================================================================\r\n\r\n /**\r\n * Start historical replay with timing preserved\r\n *\r\n * @param channel - Data channel to replay\r\n * @param coin - Trading pair (e.g., 'BTC', 'ETH')\r\n * @param options - Replay options\r\n *\r\n * @example\r\n * ```typescript\r\n * ws.replay('orderbook', 'BTC', {\r\n * start: Date.now() - 86400000, // 24 hours ago\r\n * speed: 10 // 10x faster than real-time\r\n * });\r\n * ```\r\n */\r\n replay(\r\n channel: WsChannel,\r\n coin: string,\r\n options: {\r\n start: number;\r\n end?: number;\r\n speed?: number;\r\n }\r\n ): void {\r\n this.send({\r\n op: 'replay',\r\n channel,\r\n coin,\r\n start: options.start,\r\n end: options.end,\r\n speed: options.speed ?? 1,\r\n });\r\n }\r\n\r\n /**\r\n * Pause the current replay\r\n */\r\n replayPause(): void {\r\n this.send({ op: 'replay.pause' });\r\n }\r\n\r\n /**\r\n * Resume a paused replay\r\n */\r\n replayResume(): void {\r\n this.send({ op: 'replay.resume' });\r\n }\r\n\r\n /**\r\n * Seek to a specific timestamp in the replay\r\n * @param timestamp - Unix timestamp in milliseconds\r\n */\r\n replaySeek(timestamp: number): void {\r\n this.send({ op: 'replay.seek', timestamp });\r\n }\r\n\r\n /**\r\n * Stop the current replay\r\n */\r\n replayStop(): void {\r\n this.send({ op: 'replay.stop' });\r\n }\r\n\r\n // ==========================================================================\r\n // Bulk Streaming (Option D) - Like Databento\r\n // ==========================================================================\r\n\r\n /**\r\n * Start bulk streaming for fast data download\r\n *\r\n * @param channel - Data channel to stream\r\n * @param coin - Trading pair (e.g., 'BTC', 'ETH')\r\n * @param options - Stream options\r\n *\r\n * @example\r\n * ```typescript\r\n * ws.stream('orderbook', 'ETH', {\r\n * start: Date.now() - 3600000, // 1 hour ago\r\n * end: Date.now(),\r\n * batchSize: 1000\r\n * });\r\n * ```\r\n */\r\n stream(\r\n channel: WsChannel,\r\n coin: string,\r\n options: {\r\n start: number;\r\n end: number;\r\n batchSize?: number;\r\n }\r\n ): void {\r\n this.send({\r\n op: 'stream',\r\n channel,\r\n coin,\r\n start: options.start,\r\n end: options.end,\r\n batch_size: options.batchSize ?? 1000,\r\n });\r\n }\r\n\r\n /**\r\n * Stop the current bulk stream\r\n */\r\n streamStop(): void {\r\n this.send({ op: 'stream.stop' });\r\n }\r\n\r\n // ==========================================================================\r\n // Event Handlers for Replay/Stream\r\n // ==========================================================================\r\n\r\n /**\r\n * Handle historical data points (replay mode)\r\n */\r\n onHistoricalData<T = unknown>(\r\n handler: (coin: string, timestamp: number, data: T) => void\r\n ): void {\r\n this.historicalDataHandlers.push(handler as (coin: string, timestamp: number, data: unknown) => void);\r\n }\r\n\r\n /**\r\n * Handle batched data (bulk stream mode)\r\n */\r\n onBatch<T = unknown>(\r\n handler: (coin: string, records: Array<{ timestamp: number; data: T }>) => void\r\n ): void {\r\n this.batchHandlers.push(handler as (coin: string, records: Array<{ timestamp: number; data: unknown }>) => void);\r\n }\r\n\r\n /**\r\n * Handle replay started event\r\n */\r\n onReplayStart(\r\n handler: (channel: WsChannel, coin: string, start: number, end: number, speed: number) => void\r\n ): void {\r\n this.replayStartHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle replay completed event\r\n */\r\n onReplayComplete(\r\n handler: (channel: WsChannel, coin: string, snapshotsSent: number) => void\r\n ): void {\r\n this.replayCompleteHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream started event\r\n */\r\n onStreamStart(\r\n handler: (channel: WsChannel, coin: string, start: number, end: number) => void\r\n ): void {\r\n this.streamStartHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream progress event\r\n */\r\n onStreamProgress(\r\n handler: (snapshotsSent: number) => void\r\n ): void {\r\n this.streamProgressHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Handle stream completed event\r\n */\r\n onStreamComplete(\r\n handler: (channel: WsChannel, coin: string, snapshotsSent: number) => void\r\n ): void {\r\n this.streamCompleteHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Get current connection state\r\n */\r\n getState(): WsConnectionState {\r\n return this.state;\r\n }\r\n\r\n /**\r\n * Check if connected\r\n */\r\n isConnected(): boolean {\r\n return this.ws?.readyState === WebSocket.OPEN;\r\n }\r\n\r\n /**\r\n * Set event handlers after construction\r\n */\r\n on<K extends keyof WsEventHandlers>(event: K, handler: WsEventHandlers[K]): void {\r\n this.handlers[event] = handler;\r\n }\r\n\r\n /**\r\n * Helper to handle typed orderbook data\r\n */\r\n onOrderbook(handler: (coin: string, data: OrderBook) => void): void {\r\n this.orderbookHandlers.push(handler);\r\n }\r\n\r\n /**\r\n * Helper to handle typed trade data\r\n */\r\n onTrades(handler: (coin: string, data: Trade[]) => void): void {\r\n this.tradesHandlers.push(handler);\r\n }\r\n\r\n // Private methods\r\n\r\n private send(message: WsClientMessage): void {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify(message));\r\n }\r\n }\r\n\r\n private setState(state: WsConnectionState): void {\r\n this.state = state;\r\n this.handlers.onStateChange?.(state);\r\n }\r\n\r\n private startPing(): void {\r\n this.stopPing();\r\n this.pingTimer = setInterval(() => {\r\n this.send({ op: 'ping' });\r\n }, this.options.pingInterval);\r\n }\r\n\r\n private stopPing(): void {\r\n if (this.pingTimer) {\r\n clearInterval(this.pingTimer);\r\n this.pingTimer = null;\r\n }\r\n }\r\n\r\n private subscriptionKey(channel: WsChannel, coin?: string): string {\r\n return coin ? `${channel}:${coin}` : channel;\r\n }\r\n\r\n private resubscribe(): void {\r\n for (const key of this.subscriptions) {\r\n const [channel, coin] = key.split(':') as [WsChannel, string | undefined];\r\n this.send({ op: 'subscribe', channel, coin });\r\n }\r\n }\r\n\r\n private scheduleReconnect(): void {\r\n if (this.reconnectAttempts >= this.options.maxReconnectAttempts) {\r\n this.setState('disconnected');\r\n return;\r\n }\r\n\r\n this.setState('reconnecting');\r\n this.reconnectAttempts++;\r\n\r\n const delay = this.options.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);\r\n\r\n this.reconnectTimer = setTimeout(() => {\r\n this.connect();\r\n }, delay);\r\n }\r\n\r\n private clearReconnectTimer(): void {\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = null;\r\n }\r\n }\r\n\r\n private handleMessage(message: WsServerMessage): void {\r\n // Call the generic onMessage handler first\r\n this.handlers.onMessage?.(message);\r\n\r\n // Dispatch to typed handlers based on message type\r\n switch (message.type) {\r\n case 'historical_data': {\r\n const msg = message as WsHistoricalData;\r\n for (const handler of this.historicalDataHandlers) {\r\n handler(msg.coin, msg.timestamp, msg.data);\r\n }\r\n break;\r\n }\r\n case 'historical_batch': {\r\n const msg = message as WsHistoricalBatch;\r\n for (const handler of this.batchHandlers) {\r\n handler(msg.coin, msg.data as Array<{ timestamp: number; data: unknown }>);\r\n }\r\n break;\r\n }\r\n case 'replay_started': {\r\n const msg = message as WsReplayStarted;\r\n for (const handler of this.replayStartHandlers) {\r\n handler(msg.channel, msg.coin, msg.start, msg.end, msg.speed);\r\n }\r\n break;\r\n }\r\n case 'replay_completed': {\r\n const msg = message as WsReplayCompleted;\r\n for (const handler of this.replayCompleteHandlers) {\r\n handler(msg.channel, msg.coin, msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'stream_started': {\r\n const msg = message as WsStreamStarted;\r\n for (const handler of this.streamStartHandlers) {\r\n handler(msg.channel, msg.coin, msg.start, msg.end);\r\n }\r\n break;\r\n }\r\n case 'stream_progress': {\r\n const msg = message as WsStreamProgress;\r\n for (const handler of this.streamProgressHandlers) {\r\n handler(msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'stream_completed': {\r\n const msg = message as WsStreamCompleted;\r\n for (const handler of this.streamCompleteHandlers) {\r\n handler(msg.channel, msg.coin, msg.snapshots_sent);\r\n }\r\n break;\r\n }\r\n case 'data': {\r\n if (message.channel === 'orderbook') {\r\n // Transform raw Hyperliquid format to SDK OrderBook type\r\n const orderbook = transformOrderbook(message.coin, message.data as Record<string, unknown>);\r\n for (const handler of this.orderbookHandlers) {\r\n handler(message.coin, orderbook);\r\n }\r\n } else if (message.channel === 'trades') {\r\n for (const handler of this.tradesHandlers) {\r\n handler(message.coin, message.data as Trade[]);\r\n }\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xarchive/sdk",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Official TypeScript SDK for 0xarchive - Hyperliquid Historical Data API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",