@0xarchive/sdk 0.5.4 → 0.6.1
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/README.md +88 -0
- package/dist/index.d.mts +464 -8
- package/dist/index.d.ts +464 -8
- package/dist/index.js +212 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +212 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -682,6 +682,186 @@ var LiquidationsResource = class {
|
|
|
682
682
|
}
|
|
683
683
|
};
|
|
684
684
|
|
|
685
|
+
// src/resources/data-quality.ts
|
|
686
|
+
var DataQualityResource = class {
|
|
687
|
+
constructor(http, basePath = "/v1/data-quality") {
|
|
688
|
+
this.http = http;
|
|
689
|
+
this.basePath = basePath;
|
|
690
|
+
}
|
|
691
|
+
// ===========================================================================
|
|
692
|
+
// Status Endpoints
|
|
693
|
+
// ===========================================================================
|
|
694
|
+
/**
|
|
695
|
+
* Get overall system health status
|
|
696
|
+
*
|
|
697
|
+
* @returns StatusResponse with overall status, per-exchange status,
|
|
698
|
+
* per-data-type status, and active incident count
|
|
699
|
+
*
|
|
700
|
+
* @example
|
|
701
|
+
* ```typescript
|
|
702
|
+
* const status = await client.dataQuality.status();
|
|
703
|
+
* console.log(`Overall: ${status.status}`);
|
|
704
|
+
* for (const [exchange, info] of Object.entries(status.exchanges)) {
|
|
705
|
+
* console.log(`${exchange}: ${info.status}`);
|
|
706
|
+
* }
|
|
707
|
+
* ```
|
|
708
|
+
*/
|
|
709
|
+
async status() {
|
|
710
|
+
return this.http.get(`${this.basePath}/status`);
|
|
711
|
+
}
|
|
712
|
+
// ===========================================================================
|
|
713
|
+
// Coverage Endpoints
|
|
714
|
+
// ===========================================================================
|
|
715
|
+
/**
|
|
716
|
+
* Get data coverage summary for all exchanges
|
|
717
|
+
*
|
|
718
|
+
* @returns CoverageResponse with coverage info for all exchanges and data types
|
|
719
|
+
*
|
|
720
|
+
* @example
|
|
721
|
+
* ```typescript
|
|
722
|
+
* const coverage = await client.dataQuality.coverage();
|
|
723
|
+
* for (const exchange of coverage.exchanges) {
|
|
724
|
+
* console.log(`${exchange.exchange}:`);
|
|
725
|
+
* for (const [dtype, info] of Object.entries(exchange.dataTypes)) {
|
|
726
|
+
* console.log(` ${dtype}: ${info.totalRecords} records`);
|
|
727
|
+
* }
|
|
728
|
+
* }
|
|
729
|
+
* ```
|
|
730
|
+
*/
|
|
731
|
+
async coverage() {
|
|
732
|
+
return this.http.get(`${this.basePath}/coverage`);
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Get data coverage for a specific exchange
|
|
736
|
+
*
|
|
737
|
+
* @param exchange - Exchange name ('hyperliquid' or 'lighter')
|
|
738
|
+
* @returns ExchangeCoverage with coverage info for all data types on this exchange
|
|
739
|
+
*
|
|
740
|
+
* @example
|
|
741
|
+
* ```typescript
|
|
742
|
+
* const hl = await client.dataQuality.exchangeCoverage('hyperliquid');
|
|
743
|
+
* console.log(`Orderbook earliest: ${hl.dataTypes.orderbook.earliest}`);
|
|
744
|
+
* ```
|
|
745
|
+
*/
|
|
746
|
+
async exchangeCoverage(exchange) {
|
|
747
|
+
return this.http.get(
|
|
748
|
+
`${this.basePath}/coverage/${exchange.toLowerCase()}`
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Get data coverage for a specific symbol on an exchange
|
|
753
|
+
*
|
|
754
|
+
* Includes gap detection showing periods where data may be missing.
|
|
755
|
+
*
|
|
756
|
+
* @param exchange - Exchange name ('hyperliquid' or 'lighter')
|
|
757
|
+
* @param symbol - Symbol name (e.g., 'BTC', 'ETH')
|
|
758
|
+
* @returns SymbolCoverageResponse with per-data-type coverage including gaps
|
|
759
|
+
*
|
|
760
|
+
* @example
|
|
761
|
+
* ```typescript
|
|
762
|
+
* const btc = await client.dataQuality.symbolCoverage('hyperliquid', 'BTC');
|
|
763
|
+
* const oi = btc.dataTypes.open_interest;
|
|
764
|
+
* console.log(`OI completeness: ${oi.completeness}%`);
|
|
765
|
+
* console.log(`Gaps found: ${oi.gaps.length}`);
|
|
766
|
+
* for (const gap of oi.gaps.slice(0, 3)) {
|
|
767
|
+
* console.log(` ${gap.durationMinutes} min gap at ${gap.start}`);
|
|
768
|
+
* }
|
|
769
|
+
* ```
|
|
770
|
+
*/
|
|
771
|
+
async symbolCoverage(exchange, symbol) {
|
|
772
|
+
return this.http.get(
|
|
773
|
+
`${this.basePath}/coverage/${exchange.toLowerCase()}/${symbol.toUpperCase()}`
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
// ===========================================================================
|
|
777
|
+
// Incidents Endpoints
|
|
778
|
+
// ===========================================================================
|
|
779
|
+
/**
|
|
780
|
+
* List incidents with filtering and pagination
|
|
781
|
+
*
|
|
782
|
+
* @param params - Filter and pagination options
|
|
783
|
+
* @returns IncidentsResponse with list of incidents and pagination info
|
|
784
|
+
*
|
|
785
|
+
* @example
|
|
786
|
+
* ```typescript
|
|
787
|
+
* // Get all open incidents
|
|
788
|
+
* const result = await client.dataQuality.listIncidents({ status: 'open' });
|
|
789
|
+
* for (const incident of result.incidents) {
|
|
790
|
+
* console.log(`${incident.severity}: ${incident.title}`);
|
|
791
|
+
* }
|
|
792
|
+
* ```
|
|
793
|
+
*/
|
|
794
|
+
async listIncidents(params) {
|
|
795
|
+
return this.http.get(
|
|
796
|
+
`${this.basePath}/incidents`,
|
|
797
|
+
params
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Get a specific incident by ID
|
|
802
|
+
*
|
|
803
|
+
* @param incidentId - The incident ID
|
|
804
|
+
* @returns Incident details
|
|
805
|
+
*
|
|
806
|
+
* @example
|
|
807
|
+
* ```typescript
|
|
808
|
+
* const incident = await client.dataQuality.getIncident('inc_123');
|
|
809
|
+
* console.log(`Status: ${incident.status}`);
|
|
810
|
+
* console.log(`Root cause: ${incident.rootCause}`);
|
|
811
|
+
* ```
|
|
812
|
+
*/
|
|
813
|
+
async getIncident(incidentId) {
|
|
814
|
+
return this.http.get(`${this.basePath}/incidents/${incidentId}`);
|
|
815
|
+
}
|
|
816
|
+
// ===========================================================================
|
|
817
|
+
// Latency Endpoints
|
|
818
|
+
// ===========================================================================
|
|
819
|
+
/**
|
|
820
|
+
* Get current latency metrics for all exchanges
|
|
821
|
+
*
|
|
822
|
+
* @returns LatencyResponse with WebSocket, REST API, and data freshness metrics
|
|
823
|
+
*
|
|
824
|
+
* @example
|
|
825
|
+
* ```typescript
|
|
826
|
+
* const latency = await client.dataQuality.latency();
|
|
827
|
+
* for (const [exchange, metrics] of Object.entries(latency.exchanges)) {
|
|
828
|
+
* console.log(`${exchange}:`);
|
|
829
|
+
* if (metrics.websocket) {
|
|
830
|
+
* console.log(` WS current: ${metrics.websocket.currentMs}ms`);
|
|
831
|
+
* }
|
|
832
|
+
* console.log(` OB lag: ${metrics.dataFreshness.orderbookLagMs}ms`);
|
|
833
|
+
* }
|
|
834
|
+
* ```
|
|
835
|
+
*/
|
|
836
|
+
async latency() {
|
|
837
|
+
return this.http.get(`${this.basePath}/latency`);
|
|
838
|
+
}
|
|
839
|
+
// ===========================================================================
|
|
840
|
+
// SLA Endpoints
|
|
841
|
+
// ===========================================================================
|
|
842
|
+
/**
|
|
843
|
+
* Get SLA compliance metrics for a specific month
|
|
844
|
+
*
|
|
845
|
+
* @param params - Optional year and month (defaults to current month)
|
|
846
|
+
* @returns SlaResponse with SLA targets, actual metrics, and compliance status
|
|
847
|
+
*
|
|
848
|
+
* @example
|
|
849
|
+
* ```typescript
|
|
850
|
+
* const sla = await client.dataQuality.sla({ year: 2026, month: 1 });
|
|
851
|
+
* console.log(`Period: ${sla.period}`);
|
|
852
|
+
* console.log(`Uptime: ${sla.actual.uptime}% (${sla.actual.uptimeStatus})`);
|
|
853
|
+
* console.log(`Completeness: ${sla.actual.dataCompleteness.overall}%`);
|
|
854
|
+
* console.log(`API P99: ${sla.actual.apiLatencyP99Ms}ms`);
|
|
855
|
+
* ```
|
|
856
|
+
*/
|
|
857
|
+
async sla(params) {
|
|
858
|
+
return this.http.get(
|
|
859
|
+
`${this.basePath}/sla`,
|
|
860
|
+
params
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
};
|
|
864
|
+
|
|
685
865
|
// src/exchanges.ts
|
|
686
866
|
var HyperliquidClient = class {
|
|
687
867
|
/**
|
|
@@ -772,6 +952,10 @@ var OxArchive = class {
|
|
|
772
952
|
* Lighter.xyz exchange data (August 2025+)
|
|
773
953
|
*/
|
|
774
954
|
lighter;
|
|
955
|
+
/**
|
|
956
|
+
* Data quality metrics: status, coverage, incidents, latency, SLA
|
|
957
|
+
*/
|
|
958
|
+
dataQuality;
|
|
775
959
|
/**
|
|
776
960
|
* @deprecated Use client.hyperliquid.orderbook instead
|
|
777
961
|
*/
|
|
@@ -809,6 +993,7 @@ var OxArchive = class {
|
|
|
809
993
|
});
|
|
810
994
|
this.hyperliquid = new HyperliquidClient(this.http);
|
|
811
995
|
this.lighter = new LighterClient(this.http);
|
|
996
|
+
this.dataQuality = new DataQualityResource(this.http);
|
|
812
997
|
const legacyBase = "/v1/hyperliquid";
|
|
813
998
|
this.orderbook = new OrderBookResource(this.http, legacyBase);
|
|
814
999
|
this.trades = new TradesResource(this.http, legacyBase);
|
|
@@ -913,6 +1098,7 @@ var OxArchiveWs = class {
|
|
|
913
1098
|
streamCompleteHandlers = [];
|
|
914
1099
|
orderbookHandlers = [];
|
|
915
1100
|
tradesHandlers = [];
|
|
1101
|
+
gapHandlers = [];
|
|
916
1102
|
constructor(options) {
|
|
917
1103
|
this.options = {
|
|
918
1104
|
apiKey: options.apiKey,
|
|
@@ -1202,6 +1388,25 @@ var OxArchiveWs = class {
|
|
|
1202
1388
|
onStreamComplete(handler) {
|
|
1203
1389
|
this.streamCompleteHandlers.push(handler);
|
|
1204
1390
|
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Handle gap detected events during replay or streaming.
|
|
1393
|
+
* Called when there's a gap in the historical data exceeding the threshold.
|
|
1394
|
+
* Thresholds: 2 minutes for orderbook/candles/liquidations, 60 minutes for trades.
|
|
1395
|
+
*
|
|
1396
|
+
* @param handler - Callback receiving channel, coin, gap start/end timestamps (ms), and duration (minutes)
|
|
1397
|
+
*
|
|
1398
|
+
* @example
|
|
1399
|
+
* ```typescript
|
|
1400
|
+
* ws.onGap((channel, coin, gapStart, gapEnd, durationMinutes) => {
|
|
1401
|
+
* console.warn(`Gap detected in ${channel} ${coin}: ${durationMinutes} minutes`);
|
|
1402
|
+
* console.warn(` From: ${new Date(gapStart).toISOString()}`);
|
|
1403
|
+
* console.warn(` To: ${new Date(gapEnd).toISOString()}`);
|
|
1404
|
+
* });
|
|
1405
|
+
* ```
|
|
1406
|
+
*/
|
|
1407
|
+
onGap(handler) {
|
|
1408
|
+
this.gapHandlers.push(handler);
|
|
1409
|
+
}
|
|
1205
1410
|
/**
|
|
1206
1411
|
* Get current connection state
|
|
1207
1412
|
*/
|
|
@@ -1344,6 +1549,13 @@ var OxArchiveWs = class {
|
|
|
1344
1549
|
}
|
|
1345
1550
|
break;
|
|
1346
1551
|
}
|
|
1552
|
+
case "gap_detected": {
|
|
1553
|
+
const msg = message;
|
|
1554
|
+
for (const handler of this.gapHandlers) {
|
|
1555
|
+
handler(msg.channel, msg.coin, msg.gap_start, msg.gap_end, msg.duration_minutes);
|
|
1556
|
+
}
|
|
1557
|
+
break;
|
|
1558
|
+
}
|
|
1347
1559
|
case "data": {
|
|
1348
1560
|
if (message.channel === "orderbook") {
|
|
1349
1561
|
const orderbook = transformOrderbook(message.coin, message.data);
|