UNPKG

@nktkas/hyperliquid

Version:

Hyperliquid API SDK for all major JS runtimes, written in TypeScript.

172 lines 8.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebSocketTransport = exports.TESTNET_RPC_WS_URL = exports.MAINNET_RPC_WS_URL = exports.TESTNET_API_WS_URL = exports.MAINNET_API_WS_URL = exports.WebSocketRequestError = void 0; const _errors_js_1 = require("../../_errors.js"); const _polyfills_js_1 = require("../_polyfills.js"); const rews_1 = require("@nktkas/rews"); const _hyperliquidEventTarget_js_1 = require("./_hyperliquidEventTarget.js"); const _postRequest_js_1 = require("./_postRequest.js"); Object.defineProperty(exports, "WebSocketRequestError", { enumerable: true, get: function () { return _postRequest_js_1.WebSocketRequestError; } }); const _subscriptionManager_js_1 = require("./_subscriptionManager.js"); /** Mainnet API WebSocket URL. */ exports.MAINNET_API_WS_URL = "wss://api.hyperliquid.xyz/ws"; /** Testnet API WebSocket URL. */ exports.TESTNET_API_WS_URL = "wss://api.hyperliquid-testnet.xyz/ws"; /** Mainnet RPC WebSocket URL. */ exports.MAINNET_RPC_WS_URL = "wss://rpc.hyperliquid.xyz/ws"; /** Testnet RPC WebSocket URL. */ exports.TESTNET_RPC_WS_URL = "wss://rpc.hyperliquid-testnet.xyz/ws"; /** * WebSocket transport for Hyperliquid API. * * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/post-requests */ class WebSocketTransport { isTestnet; timeout; /** The WebSocket that is used for communication. */ socket; get resubscribe() { return this._subscriptionManager.resubscribe; } set resubscribe(value) { this._subscriptionManager.resubscribe = value; } _wsRequester; _hlEvents; _subscriptionManager; _keepAliveInterval; /** * Creates a new WebSocket transport instance. * * @param options - Configuration options for the WebSocket transport layer. */ constructor(options) { this.isTestnet = options?.isTestnet ?? false; this.timeout = options?.timeout === undefined ? 10_000 : options.timeout; this.socket = new rews_1.ReconnectingWebSocket(options?.url ?? (this.isTestnet ? exports.TESTNET_API_WS_URL : exports.MAINNET_API_WS_URL), options?.reconnect); this._hlEvents = new _hyperliquidEventTarget_js_1.HyperliquidEventTarget(this.socket); this._wsRequester = new _postRequest_js_1.WebSocketAsyncRequest(this.socket, this._hlEvents); this._subscriptionManager = new _subscriptionManager_js_1.WebSocketSubscriptionManager(this.socket, this._wsRequester, this._hlEvents, options?.resubscribe ?? true); this._initKeepAlive(); } _initKeepAlive() { const start = () => { if (this._keepAliveInterval) return; this._keepAliveInterval = setInterval(() => { this.socket.send('{"method":"ping"}'); }, 30_000); }; const stop = () => { clearInterval(this._keepAliveInterval); this._keepAliveInterval = undefined; }; this.socket.addEventListener("open", start); this.socket.addEventListener("close", stop); this.socket.addEventListener("error", stop); } /** * Sends a request to the Hyperliquid API via WebSocket. * * @param endpoint - The API endpoint to send the request to. * @param payload - The payload to send with the request. * @param signal - [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) to cancel the request. * * @returns A promise that resolves with parsed JSON response body. * * @throws {WebSocketRequestError} - An error that occurs when a WebSocket request fails. */ async request(endpoint, payload, signal) { const timeoutSignal = this.timeout ? _polyfills_js_1.AbortSignal_.timeout(this.timeout) : undefined; const combinedSignal = signal && timeoutSignal ? _polyfills_js_1.AbortSignal_.any([signal, timeoutSignal]) : signal ?? timeoutSignal; const payload_ = { type: endpoint === "exchange" ? "action" : endpoint, payload }; return await this._wsRequester.request("post", payload_, combinedSignal) .catch((error) => { if (error instanceof _errors_js_1.TransportError) throw error; // Re-throw known errors throw new _postRequest_js_1.WebSocketRequestError(`Unknown error while making a WebSocket request: ${error}`, { cause: error }); }); } /** * Subscribes to a Hyperliquid event channel. * Sends a subscription request to the server and listens for events. * * @param channel - The event channel to listen to. * @param payload - A payload to send with the subscription request. * @param listener - A function to call when the event is dispatched. * * @returns A promise that resolves with a {@link WebSocketSubscription} object to manage the subscription lifecycle. * * @throws {WebSocketRequestError} - An error that occurs when a WebSocket request fails. */ subscribe(channel, payload, listener) { return this._subscriptionManager.subscribe(channel, payload, listener); } /** * Waits until the WebSocket connection is ready. * * @param signal - [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) to cancel the promise. * * @returns A promise that resolves when the connection is ready. * * @throws {WebSocketRequestError} When the connection cannot be established. */ ready(signal) { return new Promise((resolve, reject) => { const combinedSignal = signal ? _polyfills_js_1.AbortSignal_.any([this.socket.terminationSignal, signal]) : this.socket.terminationSignal; if (combinedSignal.aborted) { return reject(new _postRequest_js_1.WebSocketRequestError("Failed to establish WebSocket connection", { cause: combinedSignal.reason })); } if (this.socket.readyState === rews_1.ReconnectingWebSocket.OPEN) return resolve(); const handleOpen = () => { combinedSignal.removeEventListener("abort", handleAbort); resolve(); }; const handleAbort = () => { this.socket.removeEventListener("open", handleOpen); return reject(new _postRequest_js_1.WebSocketRequestError("Failed to establish WebSocket connection", { cause: combinedSignal.reason })); }; this.socket.addEventListener("open", handleOpen, { once: true }); combinedSignal.addEventListener("abort", handleAbort, { once: true }); }); } /** * Closes the WebSocket connection and waits until it is fully closed. * * @param signal - [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) to cancel the promise. * * @returns A promise that resolves when the connection is fully closed. * * @throws {WebSocketRequestError} When the connection cannot be closed. */ close(signal) { return new Promise((resolve, reject) => { if (signal?.aborted) { return reject(new _postRequest_js_1.WebSocketRequestError("Failed to close WebSocket connection", { cause: signal.reason })); } if (this.socket.readyState === rews_1.ReconnectingWebSocket.CLOSED) return resolve(); const handleClose = () => { signal?.removeEventListener("abort", handleAbort); resolve(); }; const handleAbort = () => { return reject(new _postRequest_js_1.WebSocketRequestError("Failed to close WebSocket connection", { cause: signal?.reason })); }; this.socket.addEventListener("close", handleClose, { once: true, signal }); this.socket.addEventListener("error", handleClose, { once: true, signal }); signal?.addEventListener("abort", handleAbort, { once: true }); this.socket.close(); }); } } exports.WebSocketTransport = WebSocketTransport; //# sourceMappingURL=mod.js.map