@0xarchive/sdk 1.4.0 → 1.7.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.mjs CHANGED
@@ -12,7 +12,7 @@ var OxArchiveError = class extends Error {
12
12
 
13
13
  // src/http.ts
14
14
  function snakeToCamel(str) {
15
- return str.replace(/_([a-z0-9])/g, (_, char) => char.toUpperCase());
15
+ return str.replace(/_([a-z])/g, (_, char) => char.toUpperCase());
16
16
  }
17
17
  function transformKeys(obj) {
18
18
  if (obj === null || obj === void 0) {
@@ -265,7 +265,7 @@ var OpenInterestSchema = z.object({
265
265
  impactBidPrice: z.string().optional(),
266
266
  impactAskPrice: z.string().optional()
267
267
  });
268
- var LiquidationSideSchema = z.enum(["B", "S"]);
268
+ var LiquidationSideSchema = z.enum(["A", "B"]);
269
269
  var LiquidationSchema = z.object({
270
270
  coin: z.string(),
271
271
  timestamp: z.string(),
@@ -305,11 +305,27 @@ var WsChannelSchema = z.enum([
305
305
  "lighter_candles",
306
306
  "lighter_open_interest",
307
307
  "lighter_funding",
308
+ "lighter_l3_orderbook",
308
309
  "hip3_orderbook",
309
310
  "hip3_trades",
310
311
  "hip3_candles",
311
312
  "hip3_open_interest",
312
- "hip3_funding"
313
+ "hip3_funding",
314
+ "hip3_liquidations",
315
+ "hip4_orderbook",
316
+ "hip4_trades",
317
+ "hip4_open_interest",
318
+ "spot_orderbook",
319
+ "spot_trades",
320
+ "spot_l4_diffs",
321
+ "spot_l4_orders",
322
+ "spot_twap",
323
+ "l4_diffs",
324
+ "l4_orders",
325
+ "hip3_l4_diffs",
326
+ "hip3_l4_orders",
327
+ "hip4_l4_diffs",
328
+ "hip4_l4_orders"
313
329
  ]);
314
330
  var WsConnectionStateSchema = z.enum(["connecting", "connected", "disconnected", "reconnecting"]);
315
331
  var WsSubscribedSchema = z.object({
@@ -405,6 +421,14 @@ var WsStreamStoppedSchema = z.object({
405
421
  type: z.literal("stream_stopped"),
406
422
  snapshots_sent: z.number()
407
423
  });
424
+ var WsOutcomeSettledSchema = z.object({
425
+ type: z.literal("outcome_settled"),
426
+ coin: z.string(),
427
+ outcome_id: z.number(),
428
+ side: z.number(),
429
+ settlement_value: z.number().optional(),
430
+ settlement_at: z.string().optional()
431
+ });
408
432
  var WsServerMessageSchema = z.discriminatedUnion("type", [
409
433
  WsSubscribedSchema,
410
434
  WsUnsubscribedSchema,
@@ -422,7 +446,8 @@ var WsServerMessageSchema = z.discriminatedUnion("type", [
422
446
  WsStreamProgressSchema,
423
447
  WsHistoricalBatchSchema,
424
448
  WsStreamCompletedSchema,
425
- WsStreamStoppedSchema
449
+ WsStreamStoppedSchema,
450
+ WsOutcomeSettledSchema
426
451
  ]);
427
452
  var OrderBookResponseSchema = ApiResponseSchema(OrderBookSchema);
428
453
  var OrderBookArrayResponseSchema = ApiResponseSchema(z.array(OrderBookSchema));
@@ -972,16 +997,26 @@ var TradesResource = class {
972
997
  /**
973
998
  * Get most recent trades for a symbol.
974
999
  *
975
- * Note: This method is available for Lighter (client.lighter.trades.recent())
976
- * and HIP-3 (client.hyperliquid.hip3.trades.recent()) which have real-time data
977
- * ingestion. Hyperliquid uses hourly backfill so this endpoint is not available
978
- * for Hyperliquid.
1000
+ * Note: This method is available on Lighter (`client.lighter.trades.recent()`),
1001
+ * HIP-3 (`client.hyperliquid.hip3.trades.recent()`), and HIP-4
1002
+ * (`client.hyperliquid.hip4.trades.recent()`) which have real-time ingestion.
1003
+ * Hyperliquid uses hourly S3 backfill and does NOT expose a recent endpoint —
1004
+ * calling `client.hyperliquid.trades.recent()` (or the legacy
1005
+ * `client.trades.recent()`) throws a structured `OxArchiveError` rather than
1006
+ * letting the request fail with an opaque JSON parse error.
979
1007
  *
980
1008
  * @param symbol - The symbol (e.g., 'BTC', 'ETH')
981
1009
  * @param limit - Number of trades to return (default: 100)
982
1010
  * @returns Array of recent trades
1011
+ * @throws {OxArchiveError} When called on the bare Hyperliquid namespace.
983
1012
  */
984
1013
  async recent(symbol, limit) {
1014
+ if (this.basePath === "/v1/hyperliquid" || this.basePath === "/v1") {
1015
+ throw new OxArchiveError(
1016
+ "trades.recent() is not available on Hyperliquid (no real-time ingestion). Use client.hyperliquid.trades.list(symbol, { start, end }) with a time range, or call recent() on a real-time namespace: client.hyperliquid.hip3.trades.recent(), client.hyperliquid.hip4.trades.recent(), or client.lighter.trades.recent().",
1017
+ 404
1018
+ );
1019
+ }
985
1020
  const response = await this.http.get(
986
1021
  `${this.basePath}/trades/${this.coinTransform(symbol)}/recent`,
987
1022
  { limit },
@@ -1086,6 +1121,61 @@ var Hip3InstrumentsResource = class {
1086
1121
  return response.data;
1087
1122
  }
1088
1123
  };
1124
+ var Hip4InstrumentsResource = class {
1125
+ constructor(http, basePath = "/v1/hyperliquid/hip4", coinTransform) {
1126
+ this.http = http;
1127
+ this.basePath = basePath;
1128
+ this.coinTransform = coinTransform || ((c) => encodeURIComponent(c));
1129
+ }
1130
+ coinTransform;
1131
+ async list() {
1132
+ const response = await this.http.get(
1133
+ `${this.basePath}/instruments`
1134
+ );
1135
+ return response.data;
1136
+ }
1137
+ async get(coin) {
1138
+ const response = await this.http.get(
1139
+ `${this.basePath}/instruments/${this.coinTransform(coin)}`
1140
+ );
1141
+ return response.data;
1142
+ }
1143
+ };
1144
+ var Hip4OutcomesResource = class {
1145
+ constructor(http, basePath = "/v1/hyperliquid/hip4") {
1146
+ this.http = http;
1147
+ this.basePath = basePath;
1148
+ }
1149
+ /** List per-outcome aggregates. `aggregatedOi` is omitted on list responses. */
1150
+ async list(params) {
1151
+ const response = await this.http.get(
1152
+ `${this.basePath}/outcomes`,
1153
+ params
1154
+ );
1155
+ return {
1156
+ data: response.data,
1157
+ nextCursor: response.meta.nextCursor
1158
+ };
1159
+ }
1160
+ /** Get a single outcome aggregate. Response includes `aggregatedOi`. */
1161
+ async get(outcomeId) {
1162
+ const response = await this.http.get(
1163
+ `${this.basePath}/outcomes/${outcomeId}`
1164
+ );
1165
+ return response.data;
1166
+ }
1167
+ /**
1168
+ * Look up an outcome aggregate by its synthesized slug. Accepts the
1169
+ * per-outcome slug (`btc-above-78213-may-04-0600`) OR a per-side slug
1170
+ * (`btc-above-78213-yes-may-04-0600`). Response includes `aggregatedOi`.
1171
+ */
1172
+ async getBySlug(slug) {
1173
+ const response = await this.http.get(
1174
+ `${this.basePath}/outcomes/by-slug/${slug}`
1175
+ );
1176
+ return response.data;
1177
+ }
1178
+ };
1089
1179
 
1090
1180
  // src/resources/funding.ts
1091
1181
  var FundingResource = class {
@@ -1278,7 +1368,7 @@ var DataQualityResource = class {
1278
1368
  /**
1279
1369
  * Get overall system health status
1280
1370
  *
1281
- * @returns StatusResponse with overall status, per-exchange status,
1371
+ * @returns StatusResponse with overall status, per-scope status,
1282
1372
  * per-data-type status, and active incident count
1283
1373
  *
1284
1374
  * @example
@@ -1297,9 +1387,9 @@ var DataQualityResource = class {
1297
1387
  // Coverage Endpoints
1298
1388
  // ===========================================================================
1299
1389
  /**
1300
- * Get data coverage summary for all exchanges
1390
+ * Get data coverage summary across venue APIs
1301
1391
  *
1302
- * @returns CoverageResponse with coverage info for all exchanges and data types
1392
+ * @returns CoverageResponse with coverage info for supported venue APIs and data types
1303
1393
  *
1304
1394
  * @example
1305
1395
  * ```typescript
@@ -1316,10 +1406,10 @@ var DataQualityResource = class {
1316
1406
  return this.http.get(`${this.basePath}/coverage`);
1317
1407
  }
1318
1408
  /**
1319
- * Get data coverage for a specific exchange
1409
+ * Get data coverage for a specific venue scope
1320
1410
  *
1321
- * @param exchange - Exchange name ('hyperliquid', 'lighter', or 'hip3')
1322
- * @returns ExchangeCoverage with coverage info for all data types on this exchange
1411
+ * @param exchange - Venue scope ('hyperliquid', 'lighter', 'hip3', or 'hip4')
1412
+ * @returns ExchangeCoverage with coverage info for all data types on this venue scope
1323
1413
  *
1324
1414
  * @example
1325
1415
  * ```typescript
@@ -1333,12 +1423,12 @@ var DataQualityResource = class {
1333
1423
  );
1334
1424
  }
1335
1425
  /**
1336
- * Get data coverage for a specific symbol on an exchange
1426
+ * Get data coverage for a specific symbol on a venue scope
1337
1427
  *
1338
1428
  * Includes gap detection, empirical data cadence, and hour-level historical coverage.
1339
1429
  * Supports optional time bounds for gap detection (default: last 30 days).
1340
1430
  *
1341
- * @param exchange - Exchange name ('hyperliquid', 'lighter', or 'hip3')
1431
+ * @param exchange - Venue scope ('hyperliquid', 'lighter', 'hip3', or 'hip4')
1342
1432
  * @param symbol - Symbol name (e.g., 'BTC', 'ETH', or HIP3 coins like 'xyz:XYZ100')
1343
1433
  * @param options - Optional time bounds for gap detection window
1344
1434
  * @returns SymbolCoverageResponse with per-data-type coverage including gaps, cadence, and historical coverage
@@ -1416,7 +1506,7 @@ var DataQualityResource = class {
1416
1506
  // Latency Endpoints
1417
1507
  // ===========================================================================
1418
1508
  /**
1419
- * Get current latency metrics for all exchanges
1509
+ * Get current latency metrics for supported venue APIs
1420
1510
  *
1421
1511
  * @returns LatencyResponse with WebSocket, REST API, and data freshness metrics
1422
1512
  *
@@ -1718,7 +1808,7 @@ var L2OrderBookResource = class {
1718
1808
  if (params?.timestamp != null) query.timestamp = params.timestamp;
1719
1809
  if (params?.depth != null) query.depth = params.depth;
1720
1810
  const resp = await this.http.get(
1721
- `${this.basePath}/orderbook/${encodeURIComponent(coin)}/l2`,
1811
+ `${this.basePath}/orderbook/${coin}/l2`,
1722
1812
  query
1723
1813
  );
1724
1814
  return resp.data;
@@ -1727,7 +1817,7 @@ var L2OrderBookResource = class {
1727
1817
  async history(symbol, params) {
1728
1818
  const coin = this.coinTransform(symbol);
1729
1819
  const resp = await this.http.get(
1730
- `${this.basePath}/orderbook/${encodeURIComponent(coin)}/l2/history`,
1820
+ `${this.basePath}/orderbook/${coin}/l2/history`,
1731
1821
  params
1732
1822
  );
1733
1823
  return {
@@ -1739,7 +1829,7 @@ var L2OrderBookResource = class {
1739
1829
  async diffs(symbol, params) {
1740
1830
  const coin = this.coinTransform(symbol);
1741
1831
  const resp = await this.http.get(
1742
- `${this.basePath}/orderbook/${encodeURIComponent(coin)}/l2/diffs`,
1832
+ `${this.basePath}/orderbook/${coin}/l2/diffs`,
1743
1833
  params
1744
1834
  );
1745
1835
  return {
@@ -1786,6 +1876,54 @@ var L3OrderBookResource = class {
1786
1876
  }
1787
1877
  };
1788
1878
 
1879
+ // src/resources/spot.ts
1880
+ var SpotPairsResource = class {
1881
+ constructor(http, basePath = "/v1/hyperliquid/spot", coinTransform = (c) => c.toUpperCase()) {
1882
+ this.http = http;
1883
+ this.basePath = basePath;
1884
+ this.coinTransform = coinTransform;
1885
+ }
1886
+ /** List every active spot pair. */
1887
+ async list() {
1888
+ const response = await this.http.get(
1889
+ `${this.basePath}/pairs`
1890
+ );
1891
+ return response.data;
1892
+ }
1893
+ /**
1894
+ * Get a specific spot pair by dashed symbol (e.g. `HYPE-USDC`).
1895
+ */
1896
+ async get(symbol) {
1897
+ const response = await this.http.get(
1898
+ `${this.basePath}/pairs/${this.coinTransform(symbol)}`
1899
+ );
1900
+ return response.data;
1901
+ }
1902
+ };
1903
+ var SpotTwapResource = class {
1904
+ constructor(http, basePath = "/v1/hyperliquid/spot", coinTransform = (c) => c.toUpperCase()) {
1905
+ this.http = http;
1906
+ this.basePath = basePath;
1907
+ this.coinTransform = coinTransform;
1908
+ }
1909
+ /** TWAP statuses for a single spot pair. */
1910
+ async bySymbol(symbol, params) {
1911
+ const response = await this.http.get(
1912
+ `${this.basePath}/twap/${this.coinTransform(symbol)}`,
1913
+ params
1914
+ );
1915
+ return { data: response.data, nextCursor: response.meta.nextCursor };
1916
+ }
1917
+ /** TWAP statuses for a single user wallet across every spot pair. */
1918
+ async byUser(user, params) {
1919
+ const response = await this.http.get(
1920
+ `${this.basePath}/twap/user/${user}`,
1921
+ params
1922
+ );
1923
+ return { data: response.data, nextCursor: response.meta.nextCursor };
1924
+ }
1925
+ };
1926
+
1789
1927
  // src/exchanges.ts
1790
1928
  var HyperliquidClient = class {
1791
1929
  /**
@@ -1832,6 +1970,10 @@ var HyperliquidClient = class {
1832
1970
  * HIP-3 builder-deployed perpetuals (February 2026+)
1833
1971
  */
1834
1972
  hip3;
1973
+ /**
1974
+ * HIP-4 outcome markets (binary YES/NO; May 2026+)
1975
+ */
1976
+ hip4;
1835
1977
  http;
1836
1978
  constructor(http) {
1837
1979
  this.http = http;
@@ -1847,6 +1989,7 @@ var HyperliquidClient = class {
1847
1989
  this.l4Orderbook = new L4OrderBookResource(http, basePath);
1848
1990
  this.l2Orderbook = new L2OrderBookResource(http, basePath);
1849
1991
  this.hip3 = new Hip3Client(http);
1992
+ this.hip4 = new Hip4Client(http);
1850
1993
  }
1851
1994
  /**
1852
1995
  * Get per-symbol data freshness across all data types
@@ -1999,6 +2142,244 @@ var Hip3Client = class {
1999
2142
  };
2000
2143
  }
2001
2144
  };
2145
+ var Hip4Client = class {
2146
+ /**
2147
+ * HIP-4 per-side instruments (one row per `#N`).
2148
+ */
2149
+ instruments;
2150
+ /**
2151
+ * HIP-4 per-outcome aggregates (one row per outcome). HIP-4-specific, no HIP-3 analog.
2152
+ */
2153
+ outcomes;
2154
+ /**
2155
+ * L2 orderbook snapshots (Pro+).
2156
+ */
2157
+ orderbook;
2158
+ /**
2159
+ * Trade/fill history.
2160
+ */
2161
+ trades;
2162
+ /**
2163
+ * Open interest (per side).
2164
+ */
2165
+ openInterest;
2166
+ /**
2167
+ * Order history, flow, and TP/SL (Pro+).
2168
+ */
2169
+ orders;
2170
+ /**
2171
+ * L4 orderbook (snapshots, diffs, history).
2172
+ */
2173
+ l4Orderbook;
2174
+ /**
2175
+ * L2 full-depth orderbook (derived from L4).
2176
+ */
2177
+ l2Orderbook;
2178
+ http;
2179
+ constructor(http) {
2180
+ this.http = http;
2181
+ const basePath = "/v1/hyperliquid/hip4";
2182
+ const coinTransform = (c) => encodeURIComponent(c);
2183
+ this.instruments = new Hip4InstrumentsResource(http, basePath, coinTransform);
2184
+ this.outcomes = new Hip4OutcomesResource(http, basePath);
2185
+ this.orderbook = new OrderBookResource(http, basePath, coinTransform);
2186
+ this.trades = new TradesResource(http, basePath, coinTransform);
2187
+ this.openInterest = new OpenInterestResource(http, basePath, coinTransform);
2188
+ this.orders = new OrdersResource(http, basePath, coinTransform);
2189
+ this.l4Orderbook = new L4OrderBookResource(http, basePath, coinTransform);
2190
+ this.l2Orderbook = new L2OrderBookResource(http, basePath, coinTransform);
2191
+ }
2192
+ /** @internal Encode a HIP-4 coin for use in URL paths. */
2193
+ encodeCoin(coin) {
2194
+ return encodeURIComponent(coin);
2195
+ }
2196
+ /**
2197
+ * List per-outcome aggregates. `aggregatedOi` is omitted on list responses.
2198
+ */
2199
+ async listOutcomes(params) {
2200
+ return this.outcomes.list(params);
2201
+ }
2202
+ /**
2203
+ * Get a single outcome aggregate (includes `aggregatedOi`).
2204
+ */
2205
+ async getOutcome(outcomeId) {
2206
+ return this.outcomes.get(outcomeId);
2207
+ }
2208
+ /**
2209
+ * Look up an outcome aggregate by slug. Accepts the per-outcome slug
2210
+ * (e.g. `btc-above-78213-may-04-0600`) OR a per-side slug
2211
+ * (e.g. `btc-above-78213-yes-may-04-0600`). Includes `aggregatedOi`.
2212
+ */
2213
+ async getOutcomeBySlug(slug) {
2214
+ return this.outcomes.getBySlug(slug);
2215
+ }
2216
+ /**
2217
+ * List all per-side instruments (one row per `#N`).
2218
+ */
2219
+ async getInstruments() {
2220
+ return this.instruments.list();
2221
+ }
2222
+ /**
2223
+ * Get a single per-side instrument by coin (e.g. `#0`).
2224
+ */
2225
+ async getInstrument(coin) {
2226
+ return this.instruments.get(coin);
2227
+ }
2228
+ /**
2229
+ * Get current L2 orderbook snapshot for a HIP-4 coin (Pro+).
2230
+ * @param coin Coin string with leading `#` (e.g. `#0`).
2231
+ */
2232
+ async getOrderbook(coin, params) {
2233
+ return this.orderbook.get(coin, params);
2234
+ }
2235
+ /**
2236
+ * Get historical L2 orderbook snapshots for a HIP-4 coin (Pro+).
2237
+ */
2238
+ async getOrderbookHistory(coin, params) {
2239
+ return this.orderbook.history(coin, params);
2240
+ }
2241
+ /**
2242
+ * Get historical fills for a HIP-4 coin.
2243
+ */
2244
+ async getTrades(coin, params) {
2245
+ return this.trades.list(coin, params);
2246
+ }
2247
+ /**
2248
+ * Get most recent N fills for a HIP-4 coin (latest first).
2249
+ */
2250
+ async getTradesRecent(coin, limit) {
2251
+ return this.trades.recent(coin, limit);
2252
+ }
2253
+ /**
2254
+ * Get per-side open interest history for a HIP-4 coin.
2255
+ * Note: `markPrice` on the response is an implied probability (0..1), not USD.
2256
+ */
2257
+ async getOpenInterest(coin, params) {
2258
+ return this.openInterest.history(coin, params);
2259
+ }
2260
+ /**
2261
+ * Get current per-side open interest for a HIP-4 coin.
2262
+ * Note: `markPrice` on the response is an implied probability (0..1), not USD.
2263
+ */
2264
+ async getOpenInterestCurrent(coin) {
2265
+ return this.openInterest.current(coin);
2266
+ }
2267
+ /**
2268
+ * Get combined market summary for a HIP-4 coin.
2269
+ * @param coin Either bare numeric form (`'0'`) or `#`-prefixed form (`'#0'`). The SDK URL-encodes `#` so both work.
2270
+ */
2271
+ async getSummary(coin) {
2272
+ const response = await this.http.get(
2273
+ `/v1/hyperliquid/hip4/summary/${this.encodeCoin(coin)}`,
2274
+ void 0,
2275
+ this.http.validationEnabled ? CoinSummaryResponseSchema : void 0
2276
+ );
2277
+ return response.data;
2278
+ }
2279
+ /**
2280
+ * Get per-symbol data freshness across all HIP-4 data types.
2281
+ * @param coin Either bare numeric form (`'0'`) or `#`-prefixed form (`'#0'`). The SDK URL-encodes `#` so both work.
2282
+ */
2283
+ async getFreshness(coin) {
2284
+ const response = await this.http.get(
2285
+ `/v1/hyperliquid/hip4/freshness/${this.encodeCoin(coin)}`,
2286
+ void 0,
2287
+ this.http.validationEnabled ? CoinFreshnessResponseSchema : void 0
2288
+ );
2289
+ return response.data;
2290
+ }
2291
+ /**
2292
+ * Get mid-price history for a HIP-4 coin.
2293
+ * Note: returned `markPrice`/`midPrice` are probabilities (0..1), not USD.
2294
+ * @param coin Either bare numeric form (`'0'`) or `#`-prefixed form (`'#0'`). The SDK URL-encodes `#` so both work.
2295
+ */
2296
+ async getPrices(coin, params) {
2297
+ const response = await this.http.get(
2298
+ `/v1/hyperliquid/hip4/prices/${this.encodeCoin(coin)}`,
2299
+ params,
2300
+ this.http.validationEnabled ? PriceSnapshotArrayResponseSchema : void 0
2301
+ );
2302
+ return {
2303
+ data: response.data,
2304
+ nextCursor: response.meta.nextCursor
2305
+ };
2306
+ }
2307
+ /**
2308
+ * Get order lifecycle events for a HIP-4 coin (Pro+).
2309
+ */
2310
+ async getOrderHistory(coin, params) {
2311
+ return this.orders.history(coin, params);
2312
+ }
2313
+ /**
2314
+ * Get time-bucketed order-flow aggregates for a HIP-4 coin (Pro+).
2315
+ */
2316
+ async getOrderFlow(coin, params) {
2317
+ return this.orders.flow(coin, params);
2318
+ }
2319
+ /**
2320
+ * Get TP/SL orders for a HIP-4 coin (Pro+).
2321
+ */
2322
+ async getTpsl(coin, params) {
2323
+ return this.orders.tpsl(coin, params);
2324
+ }
2325
+ /**
2326
+ * Get full L4 reconstruction (current) for a HIP-4 coin (Pro+).
2327
+ */
2328
+ async getL4Orderbook(coin, params) {
2329
+ return this.l4Orderbook.get(coin, params);
2330
+ }
2331
+ /**
2332
+ * Get L4 diffs (event stream) for a HIP-4 coin (Pro+).
2333
+ */
2334
+ async getL4Diffs(coin, params) {
2335
+ return this.l4Orderbook.diffs(coin, params);
2336
+ }
2337
+ /**
2338
+ * Get L4 checkpoint history for a HIP-4 coin (Build+; hard cap limit=10).
2339
+ */
2340
+ async getL4History(coin, params) {
2341
+ return this.l4Orderbook.history(coin, params);
2342
+ }
2343
+ };
2344
+ var SpotClient = class {
2345
+ /** Spot pair metadata (one row per dashed symbol). */
2346
+ pairs;
2347
+ /** L2 order book snapshots (live from 2026-05-05). */
2348
+ orderbook;
2349
+ /** Trade history (S3 backfill from 2025-03-22, live since). */
2350
+ trades;
2351
+ /** Order lifecycle events (Pro+; live from 2026-05-05). */
2352
+ orders;
2353
+ /** L4 order book: snapshots, diffs, and checkpoint history. */
2354
+ l4Orderbook;
2355
+ /** TWAP statuses by symbol or by user wallet (Build+). */
2356
+ twap;
2357
+ http;
2358
+ constructor(http) {
2359
+ this.http = http;
2360
+ const basePath = "/v1/hyperliquid/spot";
2361
+ const coinTransform = (c) => c.toUpperCase();
2362
+ this.pairs = new SpotPairsResource(http, basePath, coinTransform);
2363
+ this.orderbook = new OrderBookResource(http, basePath, coinTransform);
2364
+ this.trades = new TradesResource(http, basePath, coinTransform);
2365
+ this.orders = new OrdersResource(http, basePath, coinTransform);
2366
+ this.l4Orderbook = new L4OrderBookResource(http, basePath, coinTransform);
2367
+ this.twap = new SpotTwapResource(http, basePath, coinTransform);
2368
+ }
2369
+ /**
2370
+ * Get per-symbol data freshness across all spot data types.
2371
+ *
2372
+ * @param symbol Dashed canonical (e.g. `HYPE-USDC`).
2373
+ */
2374
+ async freshness(symbol) {
2375
+ const response = await this.http.get(
2376
+ `/v1/hyperliquid/spot/freshness/${symbol.toUpperCase()}`,
2377
+ void 0,
2378
+ this.http.validationEnabled ? CoinFreshnessResponseSchema : void 0
2379
+ );
2380
+ return response.data;
2381
+ }
2382
+ };
2002
2383
  var LighterClient = class {
2003
2384
  /**
2004
2385
  * Order book data (L2 snapshots)
@@ -2101,6 +2482,12 @@ var OxArchive = class {
2101
2482
  * Lighter.xyz exchange data (August 2025+)
2102
2483
  */
2103
2484
  lighter;
2485
+ /**
2486
+ * Hyperliquid Spot exchange data. Trades backfilled from 2025-03-22;
2487
+ * orderbook, L4, and TWAP statuses live from 2026-05-05. Symbols are
2488
+ * dashed canonical (e.g. `HYPE-USDC`).
2489
+ */
2490
+ spot;
2104
2491
  /**
2105
2492
  * Data quality metrics: status, coverage, incidents, latency, SLA
2106
2493
  */
@@ -2146,6 +2533,7 @@ var OxArchive = class {
2146
2533
  });
2147
2534
  this.hyperliquid = new HyperliquidClient(this.http);
2148
2535
  this.lighter = new LighterClient(this.http);
2536
+ this.spot = new SpotClient(this.http);
2149
2537
  this.dataQuality = new DataQualityResource(this.http);
2150
2538
  this.web3 = new Web3Resource(this.http);
2151
2539
  const legacyBase = "/v1/hyperliquid";
@@ -2253,7 +2641,9 @@ var OxArchiveWs = class {
2253
2641
  streamCompleteHandlers = [];
2254
2642
  orderbookHandlers = [];
2255
2643
  tradesHandlers = [];
2644
+ liquidationsHandlers = [];
2256
2645
  gapHandlers = [];
2646
+ outcomeSettledHandlers = [];
2257
2647
  constructor(options) {
2258
2648
  this.options = {
2259
2649
  apiKey: options.apiKey,
@@ -2337,7 +2727,7 @@ var OxArchiveWs = class {
2337
2727
  const key = this.subscriptionKey(channel, coin);
2338
2728
  this.subscriptions.add(key);
2339
2729
  if (this.isConnected()) {
2340
- this.send({ op: "subscribe", channel, coin });
2730
+ this.send({ op: "subscribe", channel, symbol: coin });
2341
2731
  }
2342
2732
  }
2343
2733
  /**
@@ -2371,7 +2761,7 @@ var OxArchiveWs = class {
2371
2761
  const key = this.subscriptionKey(channel, coin);
2372
2762
  this.subscriptions.delete(key);
2373
2763
  if (this.isConnected()) {
2374
- this.send({ op: "unsubscribe", channel, coin });
2764
+ this.send({ op: "unsubscribe", channel, symbol: coin });
2375
2765
  }
2376
2766
  }
2377
2767
  /**
@@ -2398,6 +2788,67 @@ var OxArchiveWs = class {
2398
2788
  unsubscribeAllTickers() {
2399
2789
  this.unsubscribe("all_tickers");
2400
2790
  }
2791
+ /**
2792
+ * Subscribe to live liquidation events for a coin (Hyperliquid).
2793
+ *
2794
+ * Each message is a fill row with `is_liquidation: true`. Same wire shape as
2795
+ * trades. Live as of v1.6.0 (Hyperliquid + HIP-3 nodes); historical replay
2796
+ * also supported via `replay('liquidations', ...)`.
2797
+ */
2798
+ subscribeLiquidations(coin) {
2799
+ this.subscribe("liquidations", coin);
2800
+ }
2801
+ /** Unsubscribe from live liquidation events (Hyperliquid). */
2802
+ unsubscribeLiquidations(coin) {
2803
+ this.unsubscribe("liquidations", coin);
2804
+ }
2805
+ /**
2806
+ * Subscribe to live HIP-3 liquidation events for a coin.
2807
+ * Each message is a fill row with `is_liquidation: true`.
2808
+ */
2809
+ subscribeHip3Liquidations(coin) {
2810
+ this.subscribe("hip3_liquidations", coin);
2811
+ }
2812
+ /** Unsubscribe from live HIP-3 liquidation events. */
2813
+ unsubscribeHip3Liquidations(coin) {
2814
+ this.unsubscribe("hip3_liquidations", coin);
2815
+ }
2816
+ /**
2817
+ * Subscribe to a Hyperliquid Spot channel for a given dashed pair.
2818
+ *
2819
+ * @param channel One of `spot_orderbook`, `spot_trades`, `spot_l4_diffs`,
2820
+ * `spot_l4_orders`, `spot_twap`. The short form (e.g. `'orderbook'`) is
2821
+ * also accepted and the `spot_` prefix is added automatically.
2822
+ * @param coin Spot dashed canonical symbol (e.g. `'HYPE-USDC'`).
2823
+ */
2824
+ subscribeSpot(channel, coin) {
2825
+ const fullChannel = channel.startsWith("spot_") ? channel : `spot_${channel}`;
2826
+ this.subscribe(fullChannel, coin);
2827
+ }
2828
+ /** Unsubscribe from a Hyperliquid Spot channel for a given dashed pair.
2829
+ * Accepts the short form (`'orderbook'`) or the full form (`'spot_orderbook'`). */
2830
+ unsubscribeSpot(channel, coin) {
2831
+ const fullChannel = channel.startsWith("spot_") ? channel : `spot_${channel}`;
2832
+ this.unsubscribe(fullChannel, coin);
2833
+ }
2834
+ /**
2835
+ * Subscribe to a HIP-4 channel for a given outcome coin.
2836
+ *
2837
+ * @param channel One of `hip4_orderbook`, `hip4_trades`, `hip4_open_interest`,
2838
+ * `hip4_l4_diffs`, `hip4_l4_orders`.
2839
+ * @param coin HIP-4 coin (e.g. `'#0'` or `'0'`). The bare numeric form is
2840
+ * recommended; both are accepted by the backend.
2841
+ */
2842
+ subscribeHip4(channel, coin) {
2843
+ const fullChannel = channel.startsWith("hip4_") ? channel : `hip4_${channel}`;
2844
+ this.subscribe(fullChannel, coin);
2845
+ }
2846
+ /** Unsubscribe from a HIP-4 channel for a given outcome coin. Accepts the
2847
+ * short channel form (`'orderbook'`) or the full form (`'hip4_orderbook'`). */
2848
+ unsubscribeHip4(channel, coin) {
2849
+ const fullChannel = channel.startsWith("hip4_") ? channel : `hip4_${channel}`;
2850
+ this.unsubscribe(fullChannel, coin);
2851
+ }
2401
2852
  // ==========================================================================
2402
2853
  // Historical Replay (Option B) - Like Tardis.dev
2403
2854
  // ==========================================================================
@@ -2420,7 +2871,7 @@ var OxArchiveWs = class {
2420
2871
  this.send({
2421
2872
  op: "replay",
2422
2873
  channel,
2423
- coin,
2874
+ symbol: coin,
2424
2875
  start: options.start,
2425
2876
  end: options.end,
2426
2877
  speed: options.speed ?? 1,
@@ -2455,7 +2906,7 @@ var OxArchiveWs = class {
2455
2906
  this.send({
2456
2907
  op: "replay",
2457
2908
  channels,
2458
- coin,
2909
+ symbol: coin,
2459
2910
  start: options.start,
2460
2911
  end: options.end,
2461
2912
  speed: options.speed ?? 1,
@@ -2511,7 +2962,7 @@ var OxArchiveWs = class {
2511
2962
  this.send({
2512
2963
  op: "stream",
2513
2964
  channel,
2514
- coin,
2965
+ symbol: coin,
2515
2966
  start: options.start,
2516
2967
  end: options.end,
2517
2968
  batch_size: options.batchSize ?? 1e3,
@@ -2548,7 +2999,7 @@ var OxArchiveWs = class {
2548
2999
  this.send({
2549
3000
  op: "stream",
2550
3001
  channels,
2551
- coin,
3002
+ symbol: coin,
2552
3003
  start: options.start,
2553
3004
  end: options.end,
2554
3005
  batch_size: options.batchSize ?? 1e3,
@@ -2687,6 +3138,44 @@ var OxArchiveWs = class {
2687
3138
  onTrades(handler) {
2688
3139
  this.tradesHandlers.push(handler);
2689
3140
  }
3141
+ /**
3142
+ * Helper to handle live liquidation events for both `liquidations` and
3143
+ * `hip3_liquidations` channels. Each item is a fill row with
3144
+ * `is_liquidation: true`, surfaced as a `Trade` (the wire shape matches
3145
+ * trades exactly).
3146
+ *
3147
+ * @param handler Called with the channel, coin, and parsed Trade array.
3148
+ *
3149
+ * @example
3150
+ * ```typescript
3151
+ * ws.onLiquidations((channel, coin, fills) => {
3152
+ * for (const f of fills) {
3153
+ * console.log(`${channel} ${coin} liq: ${f.side} ${f.size}@${f.price}`);
3154
+ * }
3155
+ * });
3156
+ * ws.subscribeLiquidations('BTC');
3157
+ * ws.subscribeHip3Liquidations('hyna:BTC');
3158
+ * ```
3159
+ */
3160
+ onLiquidations(handler) {
3161
+ this.liquidationsHandlers.push(handler);
3162
+ }
3163
+ /**
3164
+ * Handle HIP-4 outcome settlement events. Pushed once per `(outcome_id, side)`
3165
+ * when the outcome flips to settled. After this event the server proactively
3166
+ * unsubscribes the client from every hip4_* subscription on the settled coin —
3167
+ * treat the event as a terminal signal for that coin.
3168
+ *
3169
+ * @example
3170
+ * ```typescript
3171
+ * ws.onOutcomeSettled((coin, outcomeId, side, value, at) => {
3172
+ * console.log(`${coin} (outcome ${outcomeId} side ${side}) settled to ${value} at ${at}`);
3173
+ * });
3174
+ * ```
3175
+ */
3176
+ onOutcomeSettled(handler) {
3177
+ this.outcomeSettledHandlers.push(handler);
3178
+ }
2690
3179
  // Private methods
2691
3180
  send(message) {
2692
3181
  if (this.ws?.readyState === WebSocket.OPEN) {
@@ -2715,7 +3204,7 @@ var OxArchiveWs = class {
2715
3204
  resubscribe() {
2716
3205
  for (const key of this.subscriptions) {
2717
3206
  const [channel, coin] = key.split(":");
2718
- this.send({ op: "subscribe", channel, coin });
3207
+ this.send({ op: "subscribe", channel, symbol: coin });
2719
3208
  }
2720
3209
  }
2721
3210
  scheduleReconnect() {
@@ -2814,16 +3303,28 @@ var OxArchiveWs = class {
2814
3303
  break;
2815
3304
  }
2816
3305
  case "data": {
2817
- if (message.channel === "orderbook") {
3306
+ if (message.channel === "orderbook" || message.channel === "hip3_orderbook" || message.channel === "hip4_orderbook" || message.channel === "lighter_orderbook" || message.channel === "spot_orderbook") {
2818
3307
  const orderbook = transformOrderbook(message.coin, message.data);
2819
3308
  for (const handler of this.orderbookHandlers) {
2820
3309
  handler(message.coin, orderbook);
2821
3310
  }
2822
- } else if (message.channel === "trades") {
3311
+ } else if (message.channel === "trades" || message.channel === "hip3_trades" || message.channel === "hip4_trades" || message.channel === "lighter_trades" || message.channel === "spot_trades") {
2823
3312
  const trades = transformTrades(message.coin, message.data);
2824
3313
  for (const handler of this.tradesHandlers) {
2825
3314
  handler(message.coin, trades);
2826
3315
  }
3316
+ } else if (message.channel === "liquidations" || message.channel === "hip3_liquidations") {
3317
+ const fills = transformTrades(message.coin, message.data);
3318
+ for (const handler of this.liquidationsHandlers) {
3319
+ handler(message.channel, message.coin, fills);
3320
+ }
3321
+ }
3322
+ break;
3323
+ }
3324
+ case "outcome_settled": {
3325
+ const msg = message;
3326
+ for (const handler of this.outcomeSettledHandlers) {
3327
+ handler(msg.coin, msg.outcome_id, msg.side, msg.settlement_value, msg.settlement_at);
2827
3328
  }
2828
3329
  break;
2829
3330
  }
@@ -2975,6 +3476,7 @@ export {
2975
3476
  FundingRateResponseSchema,
2976
3477
  FundingRateSchema,
2977
3478
  Hip3Client,
3479
+ Hip4Client,
2978
3480
  HyperliquidClient,
2979
3481
  InstrumentArrayResponseSchema,
2980
3482
  InstrumentResponseSchema,
@@ -3001,6 +3503,7 @@ export {
3001
3503
  PriceLevelSchema,
3002
3504
  PriceSnapshotArrayResponseSchema,
3003
3505
  PriceSnapshotSchema,
3506
+ SpotClient,
3004
3507
  TimestampedRecordSchema,
3005
3508
  TradeArrayResponseSchema,
3006
3509
  TradeDirectionSchema,
@@ -3012,6 +3515,7 @@ export {
3012
3515
  WsErrorSchema,
3013
3516
  WsHistoricalBatchSchema,
3014
3517
  WsHistoricalDataSchema,
3518
+ WsOutcomeSettledSchema,
3015
3519
  WsPongSchema,
3016
3520
  WsReplayCompletedSchema,
3017
3521
  WsReplayPausedSchema,