UNPKG

okx-api

Version:

Complete & robust Node.js SDK for OKX's REST APIs and WebSockets, with TypeScript & end-to-end tests

217 lines 10.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MISSING_CREDENTIALS_ERROR = void 0; const axios_1 = __importDefault(require("axios")); const https_1 = __importDefault(require("https")); const node_support_1 = require("./node-support"); const requestUtils_1 = require("./requestUtils"); const typeGuards_1 = require("./typeGuards"); // axios.interceptors.request.use((request) => { // console.log(new Date(), 'Starting Request', JSON.stringify(request, null, 2)); // return request; // }); // axios.interceptors.response.use((response) => { // // console.log(new Date(), 'Response:', JSON.stringify(response, null, 2)); // console.log( // new Date(), // 'Response:', // JSON.stringify( // { // data: response.data, // headers: response.headers, // }, // null, // 2, // ), // ); // return response; // }); exports.MISSING_CREDENTIALS_ERROR = 'Private endpoints require api and secret to be provided in the REST client constructor'; class BaseRestClient { constructor(options = {}, requestOptions = {}) { // this.environment = environment; this.options = Object.assign({ // if true, we'll throw errors if any params are undefined strict_param_validation: false }, options); this.baseUrl = (0, requestUtils_1.getRestBaseUrl)(options.market || 'prod', options); const hasOneCredential = options.apiKey || options.apiSecret || options.apiPass; const hasAllCredentials = !!options.apiKey && !!options.apiSecret && !!options.apiPass; // Allow empty object if (hasOneCredential && !hasAllCredentials) { throw new Error('API Key, Secret AND Passphrase are ALL required for private enpoints'); } this.globalRequestOptions = Object.assign({ // in ms == 5 minutes by default timeout: 1000 * 60 * 5 }, requestOptions); if (!this.globalRequestOptions.headers) { this.globalRequestOptions.headers = {}; } // Note: `x-simulated-trading: 1` needs to be added to the header of the Demo Trading request. if (options.market === 'demo') { this.globalRequestOptions.headers['x-simulated-trading'] = 1; } this.globalRequestOptions.headers['Content-Type'] = 'application/json'; this.globalRequestOptions.headers['Accept'] = 'application/json'; // If enabled, configure a https agent with keepAlive enabled if (this.options.keepAlive) { // Extract existing https agent parameters, if provided, to prevent the keepAlive flag from overwriting an existing https agent completely const existingHttpsAgent = this.globalRequestOptions.httpsAgent; const existingAgentOptions = (existingHttpsAgent === null || existingHttpsAgent === void 0 ? void 0 : existingHttpsAgent.options) || {}; // For more advanced configuration, raise an issue on GitHub or use the "requestOptions" // parameter to define a custom httpsAgent with the desired properties this.globalRequestOptions.httpsAgent = new https_1.default.Agent(Object.assign(Object.assign({}, existingAgentOptions), { keepAlive: true, keepAliveMsecs: this.options.keepAliveMsecs })); } this.apiKey = options === null || options === void 0 ? void 0 : options.apiKey; this.apiSecret = options === null || options === void 0 ? void 0 : options.apiSecret; this.apiPassphrase = options === null || options === void 0 ? void 0 : options.apiPass; } get(endpoint, params) { return this._call('GET', endpoint, params, true); } post(endpoint, params) { return this._call('POST', endpoint, params, true); } getPrivate(endpoint, params) { return this._call('GET', endpoint, params, false); } postPrivate(endpoint, params) { return this._call('POST', endpoint, Array.isArray(params) ? params.map((p) => (Object.assign(Object.assign({}, p), { [requestUtils_1.programKey]: requestUtils_1.programId }))) : Object.assign(Object.assign({}, params), { [requestUtils_1.programKey]: requestUtils_1.programId }), false); } deletePrivate(endpoint, params) { return this._call('DELETE', endpoint, params, false); } /** * Make a HTTP request to a specific endpoint. Private endpoints are automatically signed. */ _call(method, endpoint, params, isPublicApi) { return __awaiter(this, void 0, void 0, function* () { const options = Object.assign(Object.assign({}, this.globalRequestOptions), { url: [this.baseUrl, endpoint].join(endpoint.startsWith('/') ? '' : '/'), method: method, json: true }); // Delete any params without value for (const key in params) { if (typeof params[key] === 'undefined') { delete params[key]; } } const tsISO = new Date().toISOString(); const signResult = yield this.signRequest(isPublicApi, tsISO, method, endpoint, params); if (!options.headers) { options.headers = {}; } if (!isPublicApi) { options.headers['OK-ACCESS-KEY'] = this.apiKey; options.headers['OK-ACCESS-SIGN'] = signResult.sign; options.headers['OK-ACCESS-TIMESTAMP'] = tsISO; options.headers['OK-ACCESS-PASSPHRASE'] = this.apiPassphrase; } if (method === 'GET') { options.params = signResult.requestBody; } else { options.data = signResult.requestBody; } // console.log(new Date(), 'request: ', { // url: options.url, // method, // params: signResult.requestBody, // sign: signResult.sign, // options, // }); return (0, axios_1.default)(options) .then((response) => { var _a; // Check this is an API response without an error code. // If so, resolve the nested data property, else throw the full response body if ((0, typeGuards_1.isRawAPIResponse)(response.data) && response.status == 200 && ((_a = response.data) === null || _a === void 0 ? void 0 : _a.code) === '0') { return response.data.data; } // console.log('request: ', JSON.stringify(options, null, 2)); // console.log( // 'bad response: ', // JSON.stringify( // { // data: response.data, // headers: response.headers, // }, // null, // 2 // ) // ); // Also throw if API returned error code // This API error thrown by the exchange will be post-processed by the exception parser throw { response }; }) .catch((e) => this.parseException(e)); }); } /** * Sign request */ signRequest(isPublicApi, tsISO, method, endpoint, params) { return __awaiter(this, void 0, void 0, function* () { const res = { requestBody: params, method, endpoint, sign: '', }; if (isPublicApi) { return res; } if (!this.apiKey || !this.apiSecret || !this.apiPassphrase) { throw new Error(exports.MISSING_CREDENTIALS_ERROR); } const serializedParams = (0, requestUtils_1.serializeParams)(params, method, this.options.strict_param_validation); const message = tsISO + method + endpoint + serializedParams; // console.log(new Date(), `Sign params: `, { // message, // secret: this.apiSecret, // }); return Object.assign(Object.assign({}, res), { sign: yield (0, node_support_1.signMessage)(message, this.apiSecret) }); }); } /** * Generic handler to parse request exceptions */ parseException(e) { if (this.options.parse_exceptions === false) { throw e; } // Something happened in setting up the request that triggered an Error if (!e.response) { if (!e.request) { throw e.message; } // request made but no response received throw e; } // The request was made and the server responded with a status code // that falls out of the range of 2xx const response = e.response; throw response.data; // throw { // status: response.status, // statusText: response.statusText, // data: response.data, // headers: response.headers, // requestOptions: this.options, // }; } } exports.default = BaseRestClient; //# sourceMappingURL=BaseRestClient.js.map