UNPKG

okex-api

Version:

A modern, asynchronous, and easy-to-use [Okx API](https://www.okx.com/docs-v5) wrapper for Node.js/bun/Web Browser/Cloudflare workers.

190 lines (189 loc) 6.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WsPrivate = exports.WsPublic = void 0; const utils_1 = require("./utils"); const wsEvents = new Set(['error', 'login', 'subscribe', 'unsubscribe', 'channel-conn-count']); class WsApiEvent extends Event { data; constructor(type, data) { super(type); this.data = data; } } class WsChannelEvent extends Event { arg; data; constructor(type, arg, data) { super(type); this.arg = arg; this.data = data; } } class WsApi extends EventTarget { url; ws; shouldReconnect = true; constructor(url) { super(); this.url = url; } addEventListener(type, listener, options) { super.addEventListener(type, listener, options); } connect() { let pingInterval; const ws = new WebSocket(this.url); ws.onmessage = (event) => { const data = event.data; if (data !== 'pong') { const event = JSON.parse(data); if (wsEvents.has(event.event)) { this.dispatchEvent(new WsApiEvent(event.event, event)); } else if (event.op && event.id) { this.dispatchEvent(new WsApiEvent(event.op + '-' + event.id, event)); } else if (event.arg) { const ev = event; this.dispatchEvent(new WsChannelEvent(ev.arg.channel, ev.arg, ev.data)); } } }; ws.onopen = () => { this.ws = ws; this.dispatchEvent(new Event('open')); pingInterval = setInterval(() => ws.send('ping'), 10 * 1000); }; ws.onclose = (event) => { this.dispatchEvent(new CloseEvent('close', { code: event.code, reason: event.reason })); clearInterval(pingInterval); this.ws = undefined; if (this.shouldReconnect) { setTimeout(() => this.connect(), 1000); } }; ws.onerror = (event) => { this.dispatchEvent(new ErrorEvent('error', { error: event.error })); ws.close(); }; } close() { this.shouldReconnect = false; if (this.ws) this.ws.close(); } async subscribe(wsEvents) { const wsEventArgs = Array.isArray(wsEvents) ? wsEvents : [wsEvents]; await this.send({ op: 'subscribe', args: wsEventArgs }); } async unsubscribe(wsEvents) { const wsEventArgs = Array.isArray(wsEvents) ? wsEvents : [wsEvents]; await this.send({ op: 'unsubscribe', args: wsEventArgs }); } async waitForReady(timeout = 10 * 1000) { if (!this.ws) { return new Promise((resolve, reject) => { const controller = new AbortController(); const timeoutId = setTimeout(() => { controller.abort(); reject(new Error('Timeout')); }, timeout); this.addEventListener('open', () => { resolve(undefined); clearTimeout(timeoutId); }, { once: true, signal: controller.signal }); }); } } async send(data) { if (typeof data !== 'string') data = JSON.stringify(data); await this.waitForReady(); this.ws.send(data); } } class WsPublic extends WsApi { static create(baseURL = 'wss://ws.okx.com:8443') { return new WsPublic(baseURL); } constructor(baseURL = 'wss://ws.okx.com:8443') { super(baseURL + '/ws/v5/public'); } } exports.WsPublic = WsPublic; class WsPrivate extends WsApi { credentials; static async create(apiKey, apiSecret, passphrase, baseURL = 'wss://ws.okx.com:8443') { const credentials = await utils_1.APICredentials.create(apiKey, apiSecret, passphrase, true); if (credentials) return new WsPrivate(credentials, baseURL); else throw new Error('No credentials'); } ready = false; constructor(credentials, baseURL = 'wss://ws.okx.com:8443') { super(baseURL + '/ws/v5/private'); this.credentials = credentials; this.addEventListener('open', async () => { await super.waitForReady(); this.ws.send(await this.credentials.getWsLoginMessage()); }); this.addEventListener('login', (event) => { if (event.data.code === '0') { this.ready = true; this.dispatchEvent(new Event('ready')); } else { this.dispatchEvent(new ErrorEvent('error', { error: new Error(event.data.msg) })); } }); } connect() { this.ready = false; super.connect(); } async waitForReady(timeout) { await super.waitForReady(timeout); if (!this.ready) { await new Promise((resolve, reject) => { const resolveController = new AbortController(); const rejectController = new AbortController(); this.addEventListener('ready', () => { resolve(undefined); rejectController.abort(); }, { once: true, signal: resolveController.signal }); this.addEventListener('error', (err) => { reject(err.error || err.data); resolveController.abort(); }, { once: true, signal: rejectController.signal }); }); } } async sendTradeOp(op) { const promise = new Promise((resolve, reject) => { this.addEventListener(`${op.op}-${op.id}`, (event) => { if (event.data.code === '0') { resolve(event.data); } else { reject(event.data); } }, { once: true }); }); await this.send(op); return await promise; } order(arg) { return this.sendTradeOp({ op: 'order', id: crypto.randomUUID().replace(/-/g, ''), args: [arg] }); } batchOrder(args) { return this.sendTradeOp({ op: 'batch-orders', id: crypto.randomUUID().replace(/-/g, ''), args }); } cancelOrder(arg) { return this.sendTradeOp({ op: 'cancel-order', id: crypto.randomUUID().replace(/-/g, ''), args: [arg] }); } batchCancelOrder(args) { return this.sendTradeOp({ op: 'batch-cancel-orders', id: crypto.randomUUID().replace(/-/g, ''), args }); } } exports.WsPrivate = WsPrivate;