@0xarchive/sdk 0.6.1 → 0.6.3

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.mjs CHANGED
@@ -335,6 +335,185 @@ var OpenInterestArrayResponseSchema = ApiResponseSchema(z.array(OpenInterestSche
335
335
  var CandleArrayResponseSchema = ApiResponseSchema(z.array(CandleSchema));
336
336
  var LiquidationArrayResponseSchema = ApiResponseSchema(z.array(LiquidationSchema));
337
337
 
338
+ // src/orderbook-reconstructor.ts
339
+ var OrderBookReconstructor = class {
340
+ bids = /* @__PURE__ */ new Map();
341
+ asks = /* @__PURE__ */ new Map();
342
+ coin = "";
343
+ lastTimestamp = "";
344
+ lastSequence = 0;
345
+ /**
346
+ * Initialize or reset the reconstructor with a checkpoint
347
+ */
348
+ initialize(checkpoint) {
349
+ this.bids.clear();
350
+ this.asks.clear();
351
+ this.coin = checkpoint.coin;
352
+ this.lastTimestamp = checkpoint.timestamp;
353
+ this.lastSequence = 0;
354
+ for (const level of checkpoint.bids) {
355
+ const price = parseFloat(level.px);
356
+ this.bids.set(price, {
357
+ price,
358
+ size: parseFloat(level.sz),
359
+ orders: level.n
360
+ });
361
+ }
362
+ for (const level of checkpoint.asks) {
363
+ const price = parseFloat(level.px);
364
+ this.asks.set(price, {
365
+ price,
366
+ size: parseFloat(level.sz),
367
+ orders: level.n
368
+ });
369
+ }
370
+ }
371
+ /**
372
+ * Apply a single delta to the current state
373
+ */
374
+ applyDelta(delta) {
375
+ const book = delta.side === "bid" ? this.bids : this.asks;
376
+ if (delta.size === 0) {
377
+ book.delete(delta.price);
378
+ } else {
379
+ book.set(delta.price, {
380
+ price: delta.price,
381
+ size: delta.size,
382
+ orders: 1
383
+ // Deltas don't include order count, assume 1
384
+ });
385
+ }
386
+ this.lastTimestamp = new Date(delta.timestamp).toISOString();
387
+ this.lastSequence = delta.sequence;
388
+ }
389
+ /**
390
+ * Get the current orderbook state as a snapshot
391
+ */
392
+ getSnapshot(depth) {
393
+ const sortedBids = Array.from(this.bids.values()).sort((a, b) => b.price - a.price);
394
+ const sortedAsks = Array.from(this.asks.values()).sort((a, b) => a.price - b.price);
395
+ const bidsOutput = (depth ? sortedBids.slice(0, depth) : sortedBids).map(this.toLevel);
396
+ const asksOutput = (depth ? sortedAsks.slice(0, depth) : sortedAsks).map(this.toLevel);
397
+ const bestBid = sortedBids[0]?.price;
398
+ const bestAsk = sortedAsks[0]?.price;
399
+ const midPrice = bestBid && bestAsk ? (bestBid + bestAsk) / 2 : void 0;
400
+ const spread = bestBid && bestAsk ? bestAsk - bestBid : void 0;
401
+ const spreadBps = midPrice && spread ? spread / midPrice * 1e4 : void 0;
402
+ return {
403
+ coin: this.coin,
404
+ timestamp: this.lastTimestamp,
405
+ bids: bidsOutput,
406
+ asks: asksOutput,
407
+ midPrice: midPrice?.toString(),
408
+ spread: spread?.toString(),
409
+ spreadBps: spreadBps?.toFixed(2),
410
+ sequence: this.lastSequence
411
+ };
412
+ }
413
+ /**
414
+ * Convert internal level to API format
415
+ */
416
+ toLevel = (level) => ({
417
+ px: level.price.toString(),
418
+ sz: level.size.toString(),
419
+ n: level.orders
420
+ });
421
+ /**
422
+ * Reconstruct all orderbook states from checkpoint + deltas.
423
+ * Returns an array of snapshots, one after each delta.
424
+ *
425
+ * For large datasets, prefer `iterate()` to avoid memory issues.
426
+ *
427
+ * @param checkpoint - Initial orderbook state
428
+ * @param deltas - Array of delta updates
429
+ * @param options - Reconstruction options
430
+ * @returns Array of reconstructed orderbook snapshots
431
+ */
432
+ reconstructAll(checkpoint, deltas, options = {}) {
433
+ const { depth, emitAll = true } = options;
434
+ const snapshots = [];
435
+ this.initialize(checkpoint);
436
+ const sortedDeltas = [...deltas].sort((a, b) => a.sequence - b.sequence);
437
+ if (emitAll) {
438
+ snapshots.push(this.getSnapshot(depth));
439
+ }
440
+ for (const delta of sortedDeltas) {
441
+ this.applyDelta(delta);
442
+ if (emitAll) {
443
+ snapshots.push(this.getSnapshot(depth));
444
+ }
445
+ }
446
+ if (!emitAll) {
447
+ snapshots.push(this.getSnapshot(depth));
448
+ }
449
+ return snapshots;
450
+ }
451
+ /**
452
+ * Iterate over reconstructed orderbook states (memory-efficient).
453
+ * Yields a snapshot after each delta is applied.
454
+ *
455
+ * @param checkpoint - Initial orderbook state
456
+ * @param deltas - Array of delta updates
457
+ * @param options - Reconstruction options
458
+ * @yields Reconstructed orderbook snapshots
459
+ */
460
+ *iterate(checkpoint, deltas, options = {}) {
461
+ const { depth } = options;
462
+ this.initialize(checkpoint);
463
+ yield this.getSnapshot(depth);
464
+ const sortedDeltas = [...deltas].sort((a, b) => a.sequence - b.sequence);
465
+ for (const delta of sortedDeltas) {
466
+ this.applyDelta(delta);
467
+ yield this.getSnapshot(depth);
468
+ }
469
+ }
470
+ /**
471
+ * Get the final reconstructed state without intermediate snapshots.
472
+ * Most efficient when you only need the end result.
473
+ *
474
+ * @param checkpoint - Initial orderbook state
475
+ * @param deltas - Array of delta updates
476
+ * @param depth - Maximum price levels to include
477
+ * @returns Final orderbook state after all deltas applied
478
+ */
479
+ reconstructFinal(checkpoint, deltas, depth) {
480
+ this.initialize(checkpoint);
481
+ const sortedDeltas = [...deltas].sort((a, b) => a.sequence - b.sequence);
482
+ for (const delta of sortedDeltas) {
483
+ this.applyDelta(delta);
484
+ }
485
+ return this.getSnapshot(depth);
486
+ }
487
+ /**
488
+ * Check for sequence gaps in deltas.
489
+ * Returns array of missing sequence numbers.
490
+ *
491
+ * @param deltas - Array of delta updates
492
+ * @returns Array of [expectedSeq, actualSeq] tuples where gaps exist
493
+ */
494
+ static detectGaps(deltas) {
495
+ if (deltas.length < 2) return [];
496
+ const sorted = [...deltas].sort((a, b) => a.sequence - b.sequence);
497
+ const gaps = [];
498
+ for (let i = 1; i < sorted.length; i++) {
499
+ const expected = sorted[i - 1].sequence + 1;
500
+ const actual = sorted[i].sequence;
501
+ if (actual !== expected) {
502
+ gaps.push([expected, actual]);
503
+ }
504
+ }
505
+ return gaps;
506
+ }
507
+ };
508
+ function reconstructOrderBook(tickData, options = {}) {
509
+ const reconstructor = new OrderBookReconstructor();
510
+ return reconstructor.reconstructAll(tickData.checkpoint, tickData.deltas, options);
511
+ }
512
+ function reconstructFinal(tickData, depth) {
513
+ const reconstructor = new OrderBookReconstructor();
514
+ return reconstructor.reconstructFinal(tickData.checkpoint, tickData.deltas, depth);
515
+ }
516
+
338
517
  // src/resources/orderbook.ts
339
518
  var OrderBookResource = class {
340
519
  constructor(http, basePath = "/v1") {
@@ -394,6 +573,119 @@ var OrderBookResource = class {
394
573
  nextCursor: response.meta.nextCursor
395
574
  };
396
575
  }
576
+ /**
577
+ * Get raw tick-level orderbook data (Enterprise tier only).
578
+ *
579
+ * Returns a checkpoint (full orderbook state) and array of deltas.
580
+ * Use this when you want to implement custom reconstruction logic
581
+ * (e.g., in Rust for maximum performance).
582
+ *
583
+ * For automatic reconstruction, use `historyReconstructed()` instead.
584
+ *
585
+ * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
586
+ * @param params - Time range parameters
587
+ * @returns Tick data with checkpoint and deltas
588
+ *
589
+ * @example
590
+ * ```typescript
591
+ * const tickData = await client.lighter.orderbook.historyTick('BTC', {
592
+ * start: Date.now() - 3600000,
593
+ * end: Date.now()
594
+ * });
595
+ *
596
+ * console.log('Checkpoint:', tickData.checkpoint);
597
+ * console.log('Deltas:', tickData.deltas.length);
598
+ *
599
+ * // Implement your own reconstruction...
600
+ * for (const delta of tickData.deltas) {
601
+ * // delta: { timestamp, side, price, size, sequence }
602
+ * }
603
+ * ```
604
+ */
605
+ async historyTick(coin, params) {
606
+ const response = await this.http.get(
607
+ `${this.basePath}/orderbook/${coin.toUpperCase()}/history`,
608
+ {
609
+ ...params,
610
+ granularity: "tick"
611
+ }
612
+ );
613
+ if (!response.checkpoint || !response.deltas) {
614
+ const errorMsg = response.error || response.message || "Tick-level orderbook data requires Enterprise tier. Upgrade your subscription or use a different granularity.";
615
+ throw new Error(errorMsg);
616
+ }
617
+ return {
618
+ checkpoint: response.checkpoint,
619
+ deltas: response.deltas
620
+ };
621
+ }
622
+ /**
623
+ * Get reconstructed tick-level orderbook history (Enterprise tier only).
624
+ *
625
+ * Fetches raw tick data and reconstructs full orderbook state at each delta.
626
+ * All reconstruction happens client-side for optimal server performance.
627
+ *
628
+ * For large time ranges, consider using `historyTick()` with the
629
+ * `OrderBookReconstructor.iterate()` method for memory efficiency.
630
+ *
631
+ * @param coin - The coin symbol (e.g., 'BTC', 'ETH')
632
+ * @param params - Time range parameters
633
+ * @param options - Reconstruction options
634
+ * @returns Array of reconstructed orderbook snapshots
635
+ *
636
+ * @example
637
+ * ```typescript
638
+ * // Get all snapshots
639
+ * const snapshots = await client.lighter.orderbook.historyReconstructed('BTC', {
640
+ * start: Date.now() - 3600000,
641
+ * end: Date.now()
642
+ * });
643
+ *
644
+ * for (const ob of snapshots) {
645
+ * console.log(ob.timestamp, 'Best bid:', ob.bids[0]?.px, 'Best ask:', ob.asks[0]?.px);
646
+ * }
647
+ *
648
+ * // Get only final state
649
+ * const [final] = await client.lighter.orderbook.historyReconstructed('BTC',
650
+ * { start, end },
651
+ * { emitAll: false }
652
+ * );
653
+ * ```
654
+ */
655
+ async historyReconstructed(coin, params, options = {}) {
656
+ const tickData = await this.historyTick(coin, params);
657
+ const reconstructor = new OrderBookReconstructor();
658
+ return reconstructor.reconstructAll(tickData.checkpoint, tickData.deltas, options);
659
+ }
660
+ /**
661
+ * Create a reconstructor for streaming tick-level data.
662
+ *
663
+ * Returns an OrderBookReconstructor instance that you can use
664
+ * to process tick data incrementally or with custom logic.
665
+ *
666
+ * @returns A new OrderBookReconstructor instance
667
+ *
668
+ * @example
669
+ * ```typescript
670
+ * const reconstructor = client.lighter.orderbook.createReconstructor();
671
+ * const tickData = await client.lighter.orderbook.historyTick('BTC', { start, end });
672
+ *
673
+ * // Memory-efficient iteration
674
+ * for (const snapshot of reconstructor.iterate(tickData.checkpoint, tickData.deltas)) {
675
+ * // Process each snapshot
676
+ * if (someCondition(snapshot)) break; // Early exit if needed
677
+ * }
678
+ *
679
+ * // Check for gaps
680
+ * const gaps = OrderBookReconstructor.detectGaps(tickData.deltas);
681
+ * if (gaps.length > 0) {
682
+ * console.warn('Sequence gaps detected:', gaps);
683
+ * }
684
+ * ```
685
+ */
686
+ createReconstructor() {
687
+ return new OrderBookReconstructor();
688
+ }
397
689
  };
398
690
 
399
691
  // src/resources/trades.ts
@@ -456,7 +748,7 @@ var TradesResource = class {
456
748
  */
457
749
  async recent(coin, limit) {
458
750
  const response = await this.http.get(
459
- `/v1/trades/${coin.toUpperCase()}/recent`,
751
+ `${this.basePath}/trades/${coin.toUpperCase()}/recent`,
460
752
  { limit },
461
753
  this.http.validationEnabled ? TradeArrayResponseSchema : void 0
462
754
  );
@@ -1595,6 +1887,7 @@ export {
1595
1887
  OpenInterestResponseSchema,
1596
1888
  OpenInterestSchema,
1597
1889
  OrderBookArrayResponseSchema,
1890
+ OrderBookReconstructor,
1598
1891
  OrderBookResponseSchema,
1599
1892
  OrderBookSchema,
1600
1893
  OxArchive,
@@ -1625,6 +1918,8 @@ export {
1625
1918
  WsStreamStoppedSchema,
1626
1919
  WsSubscribedSchema,
1627
1920
  WsUnsubscribedSchema,
1628
- OxArchive as default
1921
+ OxArchive as default,
1922
+ reconstructFinal,
1923
+ reconstructOrderBook
1629
1924
  };
1630
1925
  //# sourceMappingURL=index.mjs.map