@binance/common 1.1.3 → 1.2.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 +1 -0
- package/dist/index.d.mts +86 -22
- package/dist/index.d.ts +86 -22
- package/dist/index.js +522 -416
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +519 -416
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -38,7 +38,7 @@ __export(index_exports, {
|
|
|
38
38
|
COPY_TRADING_REST_API_PROD_URL: () => COPY_TRADING_REST_API_PROD_URL,
|
|
39
39
|
CRYPTO_LOAN_REST_API_PROD_URL: () => CRYPTO_LOAN_REST_API_PROD_URL,
|
|
40
40
|
ConfigurationRestAPI: () => ConfigurationRestAPI,
|
|
41
|
-
ConfigurationWebsocketAPI: () =>
|
|
41
|
+
ConfigurationWebsocketAPI: () => ConfigurationWebsocketAPI2,
|
|
42
42
|
ConfigurationWebsocketStreams: () => ConfigurationWebsocketStreams,
|
|
43
43
|
ConnectorClientError: () => ConnectorClientError,
|
|
44
44
|
DERIVATIVES_TRADING_COIN_FUTURES_REST_API_PROD_URL: () => DERIVATIVES_TRADING_COIN_FUTURES_REST_API_PROD_URL,
|
|
@@ -102,16 +102,19 @@ __export(index_exports, {
|
|
|
102
102
|
assertParamExists: () => assertParamExists,
|
|
103
103
|
buildQueryString: () => buildQueryString,
|
|
104
104
|
buildUserAgent: () => buildUserAgent,
|
|
105
|
+
buildWebsocketAPIMessage: () => buildWebsocketAPIMessage,
|
|
105
106
|
clearSignerCache: () => clearSignerCache,
|
|
106
107
|
createStreamHandler: () => createStreamHandler,
|
|
107
108
|
delay: () => delay,
|
|
108
109
|
getSignature: () => getSignature,
|
|
109
110
|
getTimestamp: () => getTimestamp,
|
|
110
111
|
httpRequestFunction: () => httpRequestFunction,
|
|
112
|
+
parseCustomHeaders: () => parseCustomHeaders,
|
|
111
113
|
parseRateLimitHeaders: () => parseRateLimitHeaders,
|
|
112
114
|
randomString: () => randomString,
|
|
113
115
|
removeEmptyValue: () => removeEmptyValue,
|
|
114
116
|
replaceWebsocketStreamsPlaceholders: () => replaceWebsocketStreamsPlaceholders,
|
|
117
|
+
sanitizeHeaderValue: () => sanitizeHeaderValue,
|
|
115
118
|
sendRequest: () => sendRequest,
|
|
116
119
|
setFlattenedQueryParams: () => setFlattenedQueryParams,
|
|
117
120
|
setSearchParams: () => setSearchParams,
|
|
@@ -122,257 +125,6 @@ __export(index_exports, {
|
|
|
122
125
|
});
|
|
123
126
|
module.exports = __toCommonJS(index_exports);
|
|
124
127
|
|
|
125
|
-
// src/configuration.ts
|
|
126
|
-
var ConfigurationRestAPI = class {
|
|
127
|
-
constructor(param = { apiKey: "" }) {
|
|
128
|
-
this.apiKey = param.apiKey;
|
|
129
|
-
this.apiSecret = param.apiSecret;
|
|
130
|
-
this.basePath = param.basePath;
|
|
131
|
-
this.keepAlive = param.keepAlive ?? true;
|
|
132
|
-
this.compression = param.compression ?? true;
|
|
133
|
-
this.retries = param.retries ?? 3;
|
|
134
|
-
this.backoff = param.backoff ?? 1e3;
|
|
135
|
-
this.privateKey = param.privateKey;
|
|
136
|
-
this.privateKeyPassphrase = param.privateKeyPassphrase;
|
|
137
|
-
this.timeUnit = param.timeUnit;
|
|
138
|
-
this.baseOptions = {
|
|
139
|
-
timeout: param.timeout ?? 1e3,
|
|
140
|
-
proxy: param.proxy && {
|
|
141
|
-
host: param.proxy.host,
|
|
142
|
-
port: param.proxy.port,
|
|
143
|
-
auth: param.proxy.auth
|
|
144
|
-
},
|
|
145
|
-
httpsAgent: param.httpsAgent ?? false,
|
|
146
|
-
headers: {
|
|
147
|
-
"Content-Type": "application/json",
|
|
148
|
-
"X-MBX-APIKEY": param.apiKey
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
var ConfigurationWebsocketAPI = class {
|
|
154
|
-
constructor(param = { apiKey: "" }) {
|
|
155
|
-
this.apiKey = param.apiKey;
|
|
156
|
-
this.apiSecret = param.apiSecret;
|
|
157
|
-
this.wsURL = param.wsURL;
|
|
158
|
-
this.timeout = param.timeout ?? 5e3;
|
|
159
|
-
this.reconnectDelay = param.reconnectDelay ?? 5e3;
|
|
160
|
-
this.compression = param.compression ?? true;
|
|
161
|
-
this.agent = param.agent ?? false;
|
|
162
|
-
this.mode = param.mode ?? "single";
|
|
163
|
-
this.poolSize = param.poolSize ?? 1;
|
|
164
|
-
this.privateKey = param.privateKey;
|
|
165
|
-
this.privateKeyPassphrase = param.privateKeyPassphrase;
|
|
166
|
-
this.timeUnit = param.timeUnit;
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
var ConfigurationWebsocketStreams = class {
|
|
170
|
-
constructor(param = {}) {
|
|
171
|
-
this.wsURL = param.wsURL;
|
|
172
|
-
this.reconnectDelay = param.reconnectDelay ?? 5e3;
|
|
173
|
-
this.compression = param.compression ?? true;
|
|
174
|
-
this.agent = param.agent ?? false;
|
|
175
|
-
this.mode = param.mode ?? "single";
|
|
176
|
-
this.poolSize = param.poolSize ?? 1;
|
|
177
|
-
this.timeUnit = param.timeUnit;
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
// src/constants.ts
|
|
182
|
-
var TimeUnit = {
|
|
183
|
-
MILLISECOND: "MILLISECOND",
|
|
184
|
-
millisecond: "millisecond",
|
|
185
|
-
MICROSECOND: "MICROSECOND",
|
|
186
|
-
microsecond: "microsecond"
|
|
187
|
-
};
|
|
188
|
-
var ALGO_REST_API_PROD_URL = "https://api.binance.com";
|
|
189
|
-
var AUTO_INVEST_REST_API_PROD_URL = "https://api.binance.com";
|
|
190
|
-
var C2C_REST_API_PROD_URL = "https://api.binance.com";
|
|
191
|
-
var CONVERT_REST_API_PROD_URL = "https://api.binance.com";
|
|
192
|
-
var COPY_TRADING_REST_API_PROD_URL = "https://api.binance.com";
|
|
193
|
-
var CRYPTO_LOAN_REST_API_PROD_URL = "https://api.binance.com";
|
|
194
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_REST_API_PROD_URL = "https://dapi.binance.com";
|
|
195
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
196
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_WS_API_PROD_URL = "wss://ws-dapi.binance.com/ws-dapi/v1";
|
|
197
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_WS_API_TESTNET_URL = "wss://testnet.binancefuture.com/ws-dapi/v1";
|
|
198
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_PROD_URL = "wss://dstream.binance.com";
|
|
199
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_TESTNET_URL = "wss://dstream.binancefuture.com";
|
|
200
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_REST_API_PROD_URL = "https://fapi.binance.com";
|
|
201
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
202
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_WS_API_PROD_URL = "wss://ws-fapi.binance.com/ws-fapi/v1";
|
|
203
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_WS_API_TESTNET_URL = "wss://testnet.binancefuture.com/ws-fapi/v1";
|
|
204
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_PROD_URL = "wss://fstream.binance.com";
|
|
205
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_TESTNET_URL = "wss://stream.binancefuture.com";
|
|
206
|
-
var DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL = "https://eapi.binance.com";
|
|
207
|
-
var DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL = "wss://nbstream.binance.com/eoptions";
|
|
208
|
-
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL = "https://papi.binance.com";
|
|
209
|
-
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
210
|
-
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_PROD_URL = "wss://fstream.binance.com/pm";
|
|
211
|
-
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_TESTNET_URL = "wss://fstream.binancefuture.com/pm";
|
|
212
|
-
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_REST_API_PROD_URL = "https://api.binance.com";
|
|
213
|
-
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_WS_STREAMS_PROD_URL = "wss://fstream.binance.com/pm-classic";
|
|
214
|
-
var DUAL_INVESTMENT_REST_API_PROD_URL = "https://api.binance.com";
|
|
215
|
-
var FIAT_REST_API_PROD_URL = "https://api.binance.com";
|
|
216
|
-
var GIFT_CARD_REST_API_PROD_URL = "https://api.binance.com";
|
|
217
|
-
var MARGIN_TRADING_REST_API_PROD_URL = "https://api.binance.com";
|
|
218
|
-
var MARGIN_TRADING_WS_STREAMS_PROD_URL = "wss://stream.binance.com:9443";
|
|
219
|
-
var MARGIN_TRADING_RISK_WS_STREAMS_PROD_URL = "wss://margin-stream.binance.com";
|
|
220
|
-
var MINING_REST_API_PROD_URL = "https://api.binance.com";
|
|
221
|
-
var NFT_REST_API_PROD_URL = "https://api.binance.com";
|
|
222
|
-
var PAY_REST_API_PROD_URL = "https://api.binance.com";
|
|
223
|
-
var REBATE_REST_API_PROD_URL = "https://api.binance.com";
|
|
224
|
-
var SIMPLE_EARN_REST_API_PROD_URL = "https://api.binance.com";
|
|
225
|
-
var SPOT_REST_API_PROD_URL = "https://api.binance.com";
|
|
226
|
-
var SPOT_REST_API_TESTNET_URL = "https://testnet.binance.vision";
|
|
227
|
-
var SPOT_WS_API_PROD_URL = "wss://ws-api.binance.com:443/ws-api/v3";
|
|
228
|
-
var SPOT_WS_API_TESTNET_URL = "wss://ws-api.testnet.binance.vision/ws-api/v3";
|
|
229
|
-
var SPOT_WS_STREAMS_PROD_URL = "wss://stream.binance.com:9443";
|
|
230
|
-
var SPOT_WS_STREAMS_TESTNET_URL = "wss://stream.testnet.binance.vision";
|
|
231
|
-
var SPOT_REST_API_MARKET_URL = "https://data-api.binance.vision";
|
|
232
|
-
var SPOT_WS_STREAMS_MARKET_URL = "wss://data-stream.binance.vision";
|
|
233
|
-
var STAKING_REST_API_PROD_URL = "https://api.binance.com";
|
|
234
|
-
var SUB_ACCOUNT_REST_API_PROD_URL = "https://api.binance.com";
|
|
235
|
-
var VIP_LOAN_REST_API_PROD_URL = "https://api.binance.com";
|
|
236
|
-
var WALLET_REST_API_PROD_URL = "https://api.binance.com";
|
|
237
|
-
|
|
238
|
-
// src/errors.ts
|
|
239
|
-
var ConnectorClientError = class _ConnectorClientError extends Error {
|
|
240
|
-
constructor(msg) {
|
|
241
|
-
super(msg || "An unexpected error occurred.");
|
|
242
|
-
Object.setPrototypeOf(this, _ConnectorClientError.prototype);
|
|
243
|
-
this.name = "ConnectorClientError";
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
var RequiredError = class _RequiredError extends Error {
|
|
247
|
-
constructor(field, msg) {
|
|
248
|
-
super(msg || `Required parameter ${field} was null or undefined.`);
|
|
249
|
-
this.field = field;
|
|
250
|
-
Object.setPrototypeOf(this, _RequiredError.prototype);
|
|
251
|
-
this.name = "RequiredError";
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
var UnauthorizedError = class _UnauthorizedError extends Error {
|
|
255
|
-
constructor(msg) {
|
|
256
|
-
super(msg || "Unauthorized access. Authentication required.");
|
|
257
|
-
Object.setPrototypeOf(this, _UnauthorizedError.prototype);
|
|
258
|
-
this.name = "UnauthorizedError";
|
|
259
|
-
}
|
|
260
|
-
};
|
|
261
|
-
var ForbiddenError = class _ForbiddenError extends Error {
|
|
262
|
-
constructor(msg) {
|
|
263
|
-
super(msg || "Access to the requested resource is forbidden.");
|
|
264
|
-
Object.setPrototypeOf(this, _ForbiddenError.prototype);
|
|
265
|
-
this.name = "ForbiddenError";
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
var TooManyRequestsError = class _TooManyRequestsError extends Error {
|
|
269
|
-
constructor(msg) {
|
|
270
|
-
super(msg || "Too many requests. You are being rate-limited.");
|
|
271
|
-
Object.setPrototypeOf(this, _TooManyRequestsError.prototype);
|
|
272
|
-
this.name = "TooManyRequestsError";
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
var RateLimitBanError = class _RateLimitBanError extends Error {
|
|
276
|
-
constructor(msg) {
|
|
277
|
-
super(msg || "The IP address has been banned for exceeding rate limits.");
|
|
278
|
-
Object.setPrototypeOf(this, _RateLimitBanError.prototype);
|
|
279
|
-
this.name = "RateLimitBanError";
|
|
280
|
-
}
|
|
281
|
-
};
|
|
282
|
-
var ServerError = class _ServerError extends Error {
|
|
283
|
-
constructor(msg, statusCode) {
|
|
284
|
-
super(msg || "An internal server error occurred.");
|
|
285
|
-
this.statusCode = statusCode;
|
|
286
|
-
Object.setPrototypeOf(this, _ServerError.prototype);
|
|
287
|
-
this.name = "ServerError";
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
var NetworkError = class _NetworkError extends Error {
|
|
291
|
-
constructor(msg) {
|
|
292
|
-
super(msg || "A network error occurred.");
|
|
293
|
-
Object.setPrototypeOf(this, _NetworkError.prototype);
|
|
294
|
-
this.name = "NetworkError";
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
var NotFoundError = class _NotFoundError extends Error {
|
|
298
|
-
constructor(msg) {
|
|
299
|
-
super(msg || "The requested resource was not found.");
|
|
300
|
-
Object.setPrototypeOf(this, _NotFoundError.prototype);
|
|
301
|
-
this.name = "NotFoundError";
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
var BadRequestError = class _BadRequestError extends Error {
|
|
305
|
-
constructor(msg) {
|
|
306
|
-
super(msg || "The request was invalid or cannot be otherwise served.");
|
|
307
|
-
Object.setPrototypeOf(this, _BadRequestError.prototype);
|
|
308
|
-
this.name = "BadRequestError";
|
|
309
|
-
}
|
|
310
|
-
};
|
|
311
|
-
|
|
312
|
-
// src/logger.ts
|
|
313
|
-
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
314
|
-
LogLevel2["NONE"] = "";
|
|
315
|
-
LogLevel2["DEBUG"] = "debug";
|
|
316
|
-
LogLevel2["INFO"] = "info";
|
|
317
|
-
LogLevel2["WARN"] = "warn";
|
|
318
|
-
LogLevel2["ERROR"] = "error";
|
|
319
|
-
return LogLevel2;
|
|
320
|
-
})(LogLevel || {});
|
|
321
|
-
var Logger = class _Logger {
|
|
322
|
-
constructor() {
|
|
323
|
-
this.minLogLevel = "info" /* INFO */;
|
|
324
|
-
this.levelsOrder = [
|
|
325
|
-
"" /* NONE */,
|
|
326
|
-
"debug" /* DEBUG */,
|
|
327
|
-
"info" /* INFO */,
|
|
328
|
-
"warn" /* WARN */,
|
|
329
|
-
"error" /* ERROR */
|
|
330
|
-
];
|
|
331
|
-
}
|
|
332
|
-
static getInstance() {
|
|
333
|
-
if (!_Logger.instance) {
|
|
334
|
-
_Logger.instance = new _Logger();
|
|
335
|
-
}
|
|
336
|
-
return _Logger.instance;
|
|
337
|
-
}
|
|
338
|
-
setMinLogLevel(level) {
|
|
339
|
-
if (!this.isValidLogLevel(level)) {
|
|
340
|
-
throw new Error(`Invalid log level: ${level}`);
|
|
341
|
-
}
|
|
342
|
-
this.minLogLevel = level;
|
|
343
|
-
}
|
|
344
|
-
isValidLogLevel(level) {
|
|
345
|
-
return this.levelsOrder.includes(level);
|
|
346
|
-
}
|
|
347
|
-
log(level, ...message) {
|
|
348
|
-
if (level === "" /* NONE */ || !this.allowLevelLog(level)) {
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
352
|
-
console[level](`[${timestamp}] [${level.toLowerCase()}]`, ...message);
|
|
353
|
-
}
|
|
354
|
-
allowLevelLog(level) {
|
|
355
|
-
if (!this.isValidLogLevel(level)) {
|
|
356
|
-
throw new Error(`Invalid log level: ${level}`);
|
|
357
|
-
}
|
|
358
|
-
const currentLevelIndex = this.levelsOrder.indexOf(level);
|
|
359
|
-
const minLevelIndex = this.levelsOrder.indexOf(this.minLogLevel);
|
|
360
|
-
return currentLevelIndex >= minLevelIndex;
|
|
361
|
-
}
|
|
362
|
-
debug(...message) {
|
|
363
|
-
this.log("debug" /* DEBUG */, ...message);
|
|
364
|
-
}
|
|
365
|
-
info(...message) {
|
|
366
|
-
this.log("info" /* INFO */, ...message);
|
|
367
|
-
}
|
|
368
|
-
warn(...message) {
|
|
369
|
-
this.log("warn" /* WARN */, ...message);
|
|
370
|
-
}
|
|
371
|
-
error(...message) {
|
|
372
|
-
this.log("error" /* ERROR */, ...message);
|
|
373
|
-
}
|
|
374
|
-
};
|
|
375
|
-
|
|
376
128
|
// src/utils.ts
|
|
377
129
|
var import_crypto = __toESM(require("crypto"));
|
|
378
130
|
var import_fs = __toESM(require("fs"));
|
|
@@ -591,141 +343,431 @@ var httpRequestFunction = async function(axiosArgs, configuration) {
|
|
|
591
343
|
}
|
|
592
344
|
}
|
|
593
345
|
}
|
|
594
|
-
throw lastError;
|
|
346
|
+
throw lastError;
|
|
347
|
+
};
|
|
348
|
+
var parseRateLimitHeaders = function(headers) {
|
|
349
|
+
const rateLimits = [];
|
|
350
|
+
const parseIntervalDetails = (key) => {
|
|
351
|
+
const match = key.match(/x-mbx-used-weight-(\d+)([smhd])|x-mbx-order-count-(\d+)([smhd])/i);
|
|
352
|
+
if (!match) return null;
|
|
353
|
+
const intervalNum = parseInt(match[1] || match[3], 10);
|
|
354
|
+
const intervalLetter = (match[2] || match[4])?.toUpperCase();
|
|
355
|
+
let interval;
|
|
356
|
+
switch (intervalLetter) {
|
|
357
|
+
case "S":
|
|
358
|
+
interval = "SECOND";
|
|
359
|
+
break;
|
|
360
|
+
case "M":
|
|
361
|
+
interval = "MINUTE";
|
|
362
|
+
break;
|
|
363
|
+
case "H":
|
|
364
|
+
interval = "HOUR";
|
|
365
|
+
break;
|
|
366
|
+
case "D":
|
|
367
|
+
interval = "DAY";
|
|
368
|
+
break;
|
|
369
|
+
default:
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
return { interval, intervalNum };
|
|
373
|
+
};
|
|
374
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
375
|
+
const normalizedKey = key.toLowerCase();
|
|
376
|
+
if (value === void 0) continue;
|
|
377
|
+
if (normalizedKey.startsWith("x-mbx-used-weight-")) {
|
|
378
|
+
const details = parseIntervalDetails(normalizedKey);
|
|
379
|
+
if (details) {
|
|
380
|
+
rateLimits.push({
|
|
381
|
+
rateLimitType: "REQUEST_WEIGHT",
|
|
382
|
+
interval: details.interval,
|
|
383
|
+
intervalNum: details.intervalNum,
|
|
384
|
+
count: parseInt(value, 10)
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
} else if (normalizedKey.startsWith("x-mbx-order-count-")) {
|
|
388
|
+
const details = parseIntervalDetails(normalizedKey);
|
|
389
|
+
if (details) {
|
|
390
|
+
rateLimits.push({
|
|
391
|
+
rateLimitType: "ORDERS",
|
|
392
|
+
interval: details.interval,
|
|
393
|
+
intervalNum: details.intervalNum,
|
|
394
|
+
count: parseInt(value, 10)
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (headers["retry-after"]) {
|
|
400
|
+
const retryAfter = parseInt(headers["retry-after"], 10);
|
|
401
|
+
for (const limit of rateLimits) {
|
|
402
|
+
limit.retryAfter = retryAfter;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return rateLimits;
|
|
406
|
+
};
|
|
407
|
+
var sendRequest = function(configuration, endpoint, method, params = {}, timeUnit, options = {}) {
|
|
408
|
+
const localVarUrlObj = new URL(endpoint, configuration?.basePath);
|
|
409
|
+
const localVarRequestOptions = {
|
|
410
|
+
method,
|
|
411
|
+
...configuration?.baseOptions
|
|
412
|
+
};
|
|
413
|
+
const localVarQueryParameter = { ...params };
|
|
414
|
+
if (options.isSigned) {
|
|
415
|
+
const timestamp = getTimestamp();
|
|
416
|
+
localVarQueryParameter["timestamp"] = timestamp;
|
|
417
|
+
const signature = getSignature(configuration, localVarQueryParameter);
|
|
418
|
+
if (signature) {
|
|
419
|
+
localVarQueryParameter["signature"] = signature;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
|
423
|
+
if (timeUnit && localVarRequestOptions.headers) {
|
|
424
|
+
const _timeUnit = validateTimeUnit(timeUnit);
|
|
425
|
+
localVarRequestOptions.headers = {
|
|
426
|
+
...localVarRequestOptions.headers,
|
|
427
|
+
"X-MBX-TIME-UNIT": _timeUnit
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
return httpRequestFunction(
|
|
431
|
+
{
|
|
432
|
+
url: toPathString(localVarUrlObj),
|
|
433
|
+
options: localVarRequestOptions
|
|
434
|
+
},
|
|
435
|
+
configuration
|
|
436
|
+
);
|
|
437
|
+
};
|
|
438
|
+
function removeEmptyValue(obj) {
|
|
439
|
+
if (!(obj instanceof Object)) return {};
|
|
440
|
+
return Object.fromEntries(
|
|
441
|
+
Object.entries(obj).filter(
|
|
442
|
+
([, value]) => value !== null && value !== void 0 && value !== ""
|
|
443
|
+
)
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
function sortObject(obj) {
|
|
447
|
+
return Object.keys(obj).sort().reduce((res, key) => {
|
|
448
|
+
res[key] = obj[key];
|
|
449
|
+
return res;
|
|
450
|
+
}, {});
|
|
451
|
+
}
|
|
452
|
+
function replaceWebsocketStreamsPlaceholders(str, variables) {
|
|
453
|
+
const normalizedVariables = Object.keys(variables).reduce(
|
|
454
|
+
(acc, key) => {
|
|
455
|
+
const normalizedKey = key.toLowerCase().replace(/[-_]/g, "");
|
|
456
|
+
acc[normalizedKey] = variables[key];
|
|
457
|
+
return acc;
|
|
458
|
+
},
|
|
459
|
+
{}
|
|
460
|
+
);
|
|
461
|
+
return str.replace(/(@)?<([^>]+)>/g, (match, precedingAt, fieldName) => {
|
|
462
|
+
const normalizedFieldName = fieldName.toLowerCase().replace(/[-_]/g, "");
|
|
463
|
+
if (Object.prototype.hasOwnProperty.call(normalizedVariables, normalizedFieldName) && normalizedVariables[normalizedFieldName] != null) {
|
|
464
|
+
const value = normalizedVariables[normalizedFieldName];
|
|
465
|
+
switch (normalizedFieldName) {
|
|
466
|
+
case "symbol":
|
|
467
|
+
case "windowsize":
|
|
468
|
+
return value.toLowerCase();
|
|
469
|
+
case "updatespeed":
|
|
470
|
+
return `@${value}`;
|
|
471
|
+
default:
|
|
472
|
+
return (precedingAt || "") + value;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return "";
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
function buildUserAgent(packageName, packageVersion) {
|
|
479
|
+
return `${packageName}/${packageVersion} (Node.js/${process.version}; ${(0, import_os.platform)()}; ${(0, import_os.arch)()})`;
|
|
480
|
+
}
|
|
481
|
+
function buildWebsocketAPIMessage(configuration, method, payload, options, skipAuth = false) {
|
|
482
|
+
const id = payload.id && /^[0-9a-f]{32}$/.test(payload.id) ? payload.id : randomString();
|
|
483
|
+
delete payload.id;
|
|
484
|
+
let params = removeEmptyValue(payload);
|
|
485
|
+
if ((options.withApiKey || options.isSigned) && !skipAuth) params.apiKey = configuration.apiKey;
|
|
486
|
+
if (options.isSigned) {
|
|
487
|
+
params.timestamp = getTimestamp();
|
|
488
|
+
params = sortObject(params);
|
|
489
|
+
if (!skipAuth) params.signature = getSignature(configuration, params);
|
|
490
|
+
}
|
|
491
|
+
return { id, method, params };
|
|
492
|
+
}
|
|
493
|
+
function sanitizeHeaderValue(value) {
|
|
494
|
+
const sanitizeOne = (v) => {
|
|
495
|
+
if (/\r|\n/.test(v)) throw new Error(`Invalid header value (contains CR/LF): "${v}"`);
|
|
496
|
+
return v;
|
|
497
|
+
};
|
|
498
|
+
return Array.isArray(value) ? value.map(sanitizeOne) : sanitizeOne(value);
|
|
499
|
+
}
|
|
500
|
+
function parseCustomHeaders(headers) {
|
|
501
|
+
if (!headers || Object.keys(headers).length === 0) return {};
|
|
502
|
+
const forbidden = /* @__PURE__ */ new Set(["host", "authorization", "cookie", ":method", ":path"]);
|
|
503
|
+
const parsedHeaders = {};
|
|
504
|
+
for (const [rawName, rawValue] of Object.entries(headers || {})) {
|
|
505
|
+
const name = rawName.trim();
|
|
506
|
+
if (forbidden.has(name.toLowerCase())) {
|
|
507
|
+
console.warn(`Dropping forbidden header: ${name}`);
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
try {
|
|
511
|
+
parsedHeaders[name] = sanitizeHeaderValue(rawValue);
|
|
512
|
+
} catch {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return parsedHeaders;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// src/configuration.ts
|
|
520
|
+
var ConfigurationRestAPI = class {
|
|
521
|
+
constructor(param = { apiKey: "" }) {
|
|
522
|
+
this.apiKey = param.apiKey;
|
|
523
|
+
this.apiSecret = param.apiSecret;
|
|
524
|
+
this.basePath = param.basePath;
|
|
525
|
+
this.keepAlive = param.keepAlive ?? true;
|
|
526
|
+
this.compression = param.compression ?? true;
|
|
527
|
+
this.retries = param.retries ?? 3;
|
|
528
|
+
this.backoff = param.backoff ?? 1e3;
|
|
529
|
+
this.privateKey = param.privateKey;
|
|
530
|
+
this.privateKeyPassphrase = param.privateKeyPassphrase;
|
|
531
|
+
this.timeUnit = param.timeUnit;
|
|
532
|
+
this.baseOptions = {
|
|
533
|
+
timeout: param.timeout ?? 1e3,
|
|
534
|
+
proxy: param.proxy && {
|
|
535
|
+
host: param.proxy.host,
|
|
536
|
+
port: param.proxy.port,
|
|
537
|
+
auth: param.proxy.auth
|
|
538
|
+
},
|
|
539
|
+
httpsAgent: param.httpsAgent ?? false,
|
|
540
|
+
headers: {
|
|
541
|
+
...parseCustomHeaders(param.customHeaders || {}),
|
|
542
|
+
"Content-Type": "application/json",
|
|
543
|
+
"X-MBX-APIKEY": param.apiKey
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
var ConfigurationWebsocketAPI2 = class {
|
|
549
|
+
constructor(param = { apiKey: "" }) {
|
|
550
|
+
this.apiKey = param.apiKey;
|
|
551
|
+
this.apiSecret = param.apiSecret;
|
|
552
|
+
this.wsURL = param.wsURL;
|
|
553
|
+
this.timeout = param.timeout ?? 5e3;
|
|
554
|
+
this.reconnectDelay = param.reconnectDelay ?? 5e3;
|
|
555
|
+
this.compression = param.compression ?? true;
|
|
556
|
+
this.agent = param.agent ?? false;
|
|
557
|
+
this.mode = param.mode ?? "single";
|
|
558
|
+
this.poolSize = param.poolSize ?? 1;
|
|
559
|
+
this.privateKey = param.privateKey;
|
|
560
|
+
this.privateKeyPassphrase = param.privateKeyPassphrase;
|
|
561
|
+
this.timeUnit = param.timeUnit;
|
|
562
|
+
this.autoSessionReLogon = param.autoSessionReLogon ?? true;
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
var ConfigurationWebsocketStreams = class {
|
|
566
|
+
constructor(param = {}) {
|
|
567
|
+
this.wsURL = param.wsURL;
|
|
568
|
+
this.reconnectDelay = param.reconnectDelay ?? 5e3;
|
|
569
|
+
this.compression = param.compression ?? true;
|
|
570
|
+
this.agent = param.agent ?? false;
|
|
571
|
+
this.mode = param.mode ?? "single";
|
|
572
|
+
this.poolSize = param.poolSize ?? 1;
|
|
573
|
+
this.timeUnit = param.timeUnit;
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
// src/constants.ts
|
|
578
|
+
var TimeUnit = {
|
|
579
|
+
MILLISECOND: "MILLISECOND",
|
|
580
|
+
millisecond: "millisecond",
|
|
581
|
+
MICROSECOND: "MICROSECOND",
|
|
582
|
+
microsecond: "microsecond"
|
|
583
|
+
};
|
|
584
|
+
var ALGO_REST_API_PROD_URL = "https://api.binance.com";
|
|
585
|
+
var AUTO_INVEST_REST_API_PROD_URL = "https://api.binance.com";
|
|
586
|
+
var C2C_REST_API_PROD_URL = "https://api.binance.com";
|
|
587
|
+
var CONVERT_REST_API_PROD_URL = "https://api.binance.com";
|
|
588
|
+
var COPY_TRADING_REST_API_PROD_URL = "https://api.binance.com";
|
|
589
|
+
var CRYPTO_LOAN_REST_API_PROD_URL = "https://api.binance.com";
|
|
590
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_REST_API_PROD_URL = "https://dapi.binance.com";
|
|
591
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
592
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_WS_API_PROD_URL = "wss://ws-dapi.binance.com/ws-dapi/v1";
|
|
593
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_WS_API_TESTNET_URL = "wss://testnet.binancefuture.com/ws-dapi/v1";
|
|
594
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_PROD_URL = "wss://dstream.binance.com";
|
|
595
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_TESTNET_URL = "wss://dstream.binancefuture.com";
|
|
596
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_REST_API_PROD_URL = "https://fapi.binance.com";
|
|
597
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
598
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_WS_API_PROD_URL = "wss://ws-fapi.binance.com/ws-fapi/v1";
|
|
599
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_WS_API_TESTNET_URL = "wss://testnet.binancefuture.com/ws-fapi/v1";
|
|
600
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_PROD_URL = "wss://fstream.binance.com";
|
|
601
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_TESTNET_URL = "wss://stream.binancefuture.com";
|
|
602
|
+
var DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL = "https://eapi.binance.com";
|
|
603
|
+
var DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL = "wss://nbstream.binance.com/eoptions";
|
|
604
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL = "https://papi.binance.com";
|
|
605
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
606
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_PROD_URL = "wss://fstream.binance.com/pm";
|
|
607
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_TESTNET_URL = "wss://fstream.binancefuture.com/pm";
|
|
608
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_REST_API_PROD_URL = "https://api.binance.com";
|
|
609
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_WS_STREAMS_PROD_URL = "wss://fstream.binance.com/pm-classic";
|
|
610
|
+
var DUAL_INVESTMENT_REST_API_PROD_URL = "https://api.binance.com";
|
|
611
|
+
var FIAT_REST_API_PROD_URL = "https://api.binance.com";
|
|
612
|
+
var GIFT_CARD_REST_API_PROD_URL = "https://api.binance.com";
|
|
613
|
+
var MARGIN_TRADING_REST_API_PROD_URL = "https://api.binance.com";
|
|
614
|
+
var MARGIN_TRADING_WS_STREAMS_PROD_URL = "wss://stream.binance.com:9443";
|
|
615
|
+
var MARGIN_TRADING_RISK_WS_STREAMS_PROD_URL = "wss://margin-stream.binance.com";
|
|
616
|
+
var MINING_REST_API_PROD_URL = "https://api.binance.com";
|
|
617
|
+
var NFT_REST_API_PROD_URL = "https://api.binance.com";
|
|
618
|
+
var PAY_REST_API_PROD_URL = "https://api.binance.com";
|
|
619
|
+
var REBATE_REST_API_PROD_URL = "https://api.binance.com";
|
|
620
|
+
var SIMPLE_EARN_REST_API_PROD_URL = "https://api.binance.com";
|
|
621
|
+
var SPOT_REST_API_PROD_URL = "https://api.binance.com";
|
|
622
|
+
var SPOT_REST_API_TESTNET_URL = "https://testnet.binance.vision";
|
|
623
|
+
var SPOT_WS_API_PROD_URL = "wss://ws-api.binance.com:443/ws-api/v3";
|
|
624
|
+
var SPOT_WS_API_TESTNET_URL = "wss://ws-api.testnet.binance.vision/ws-api/v3";
|
|
625
|
+
var SPOT_WS_STREAMS_PROD_URL = "wss://stream.binance.com:9443";
|
|
626
|
+
var SPOT_WS_STREAMS_TESTNET_URL = "wss://stream.testnet.binance.vision";
|
|
627
|
+
var SPOT_REST_API_MARKET_URL = "https://data-api.binance.vision";
|
|
628
|
+
var SPOT_WS_STREAMS_MARKET_URL = "wss://data-stream.binance.vision";
|
|
629
|
+
var STAKING_REST_API_PROD_URL = "https://api.binance.com";
|
|
630
|
+
var SUB_ACCOUNT_REST_API_PROD_URL = "https://api.binance.com";
|
|
631
|
+
var VIP_LOAN_REST_API_PROD_URL = "https://api.binance.com";
|
|
632
|
+
var WALLET_REST_API_PROD_URL = "https://api.binance.com";
|
|
633
|
+
|
|
634
|
+
// src/errors.ts
|
|
635
|
+
var ConnectorClientError = class _ConnectorClientError extends Error {
|
|
636
|
+
constructor(msg) {
|
|
637
|
+
super(msg || "An unexpected error occurred.");
|
|
638
|
+
Object.setPrototypeOf(this, _ConnectorClientError.prototype);
|
|
639
|
+
this.name = "ConnectorClientError";
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
var RequiredError = class _RequiredError extends Error {
|
|
643
|
+
constructor(field, msg) {
|
|
644
|
+
super(msg || `Required parameter ${field} was null or undefined.`);
|
|
645
|
+
this.field = field;
|
|
646
|
+
Object.setPrototypeOf(this, _RequiredError.prototype);
|
|
647
|
+
this.name = "RequiredError";
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
var UnauthorizedError = class _UnauthorizedError extends Error {
|
|
651
|
+
constructor(msg) {
|
|
652
|
+
super(msg || "Unauthorized access. Authentication required.");
|
|
653
|
+
Object.setPrototypeOf(this, _UnauthorizedError.prototype);
|
|
654
|
+
this.name = "UnauthorizedError";
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
var ForbiddenError = class _ForbiddenError extends Error {
|
|
658
|
+
constructor(msg) {
|
|
659
|
+
super(msg || "Access to the requested resource is forbidden.");
|
|
660
|
+
Object.setPrototypeOf(this, _ForbiddenError.prototype);
|
|
661
|
+
this.name = "ForbiddenError";
|
|
662
|
+
}
|
|
595
663
|
};
|
|
596
|
-
var
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
664
|
+
var TooManyRequestsError = class _TooManyRequestsError extends Error {
|
|
665
|
+
constructor(msg) {
|
|
666
|
+
super(msg || "Too many requests. You are being rate-limited.");
|
|
667
|
+
Object.setPrototypeOf(this, _TooManyRequestsError.prototype);
|
|
668
|
+
this.name = "TooManyRequestsError";
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
var RateLimitBanError = class _RateLimitBanError extends Error {
|
|
672
|
+
constructor(msg) {
|
|
673
|
+
super(msg || "The IP address has been banned for exceeding rate limits.");
|
|
674
|
+
Object.setPrototypeOf(this, _RateLimitBanError.prototype);
|
|
675
|
+
this.name = "RateLimitBanError";
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
var ServerError = class _ServerError extends Error {
|
|
679
|
+
constructor(msg, statusCode) {
|
|
680
|
+
super(msg || "An internal server error occurred.");
|
|
681
|
+
this.statusCode = statusCode;
|
|
682
|
+
Object.setPrototypeOf(this, _ServerError.prototype);
|
|
683
|
+
this.name = "ServerError";
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
var NetworkError = class _NetworkError extends Error {
|
|
687
|
+
constructor(msg) {
|
|
688
|
+
super(msg || "A network error occurred.");
|
|
689
|
+
Object.setPrototypeOf(this, _NetworkError.prototype);
|
|
690
|
+
this.name = "NetworkError";
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
var NotFoundError = class _NotFoundError extends Error {
|
|
694
|
+
constructor(msg) {
|
|
695
|
+
super(msg || "The requested resource was not found.");
|
|
696
|
+
Object.setPrototypeOf(this, _NotFoundError.prototype);
|
|
697
|
+
this.name = "NotFoundError";
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
var BadRequestError = class _BadRequestError extends Error {
|
|
701
|
+
constructor(msg) {
|
|
702
|
+
super(msg || "The request was invalid or cannot be otherwise served.");
|
|
703
|
+
Object.setPrototypeOf(this, _BadRequestError.prototype);
|
|
704
|
+
this.name = "BadRequestError";
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
// src/logger.ts
|
|
709
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
710
|
+
LogLevel2["NONE"] = "";
|
|
711
|
+
LogLevel2["DEBUG"] = "debug";
|
|
712
|
+
LogLevel2["INFO"] = "info";
|
|
713
|
+
LogLevel2["WARN"] = "warn";
|
|
714
|
+
LogLevel2["ERROR"] = "error";
|
|
715
|
+
return LogLevel2;
|
|
716
|
+
})(LogLevel || {});
|
|
717
|
+
var Logger = class _Logger {
|
|
718
|
+
constructor() {
|
|
719
|
+
this.minLogLevel = "info" /* INFO */;
|
|
720
|
+
this.levelsOrder = [
|
|
721
|
+
"" /* NONE */,
|
|
722
|
+
"debug" /* DEBUG */,
|
|
723
|
+
"info" /* INFO */,
|
|
724
|
+
"warn" /* WARN */,
|
|
725
|
+
"error" /* ERROR */
|
|
726
|
+
];
|
|
727
|
+
}
|
|
728
|
+
static getInstance() {
|
|
729
|
+
if (!_Logger.instance) {
|
|
730
|
+
_Logger.instance = new _Logger();
|
|
619
731
|
}
|
|
620
|
-
return
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
if (normalizedKey.startsWith("x-mbx-used-weight-")) {
|
|
626
|
-
const details = parseIntervalDetails(normalizedKey);
|
|
627
|
-
if (details) {
|
|
628
|
-
rateLimits.push({
|
|
629
|
-
rateLimitType: "REQUEST_WEIGHT",
|
|
630
|
-
interval: details.interval,
|
|
631
|
-
intervalNum: details.intervalNum,
|
|
632
|
-
count: parseInt(value, 10)
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
} else if (normalizedKey.startsWith("x-mbx-order-count-")) {
|
|
636
|
-
const details = parseIntervalDetails(normalizedKey);
|
|
637
|
-
if (details) {
|
|
638
|
-
rateLimits.push({
|
|
639
|
-
rateLimitType: "ORDERS",
|
|
640
|
-
interval: details.interval,
|
|
641
|
-
intervalNum: details.intervalNum,
|
|
642
|
-
count: parseInt(value, 10)
|
|
643
|
-
});
|
|
644
|
-
}
|
|
732
|
+
return _Logger.instance;
|
|
733
|
+
}
|
|
734
|
+
setMinLogLevel(level) {
|
|
735
|
+
if (!this.isValidLogLevel(level)) {
|
|
736
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
645
737
|
}
|
|
738
|
+
this.minLogLevel = level;
|
|
646
739
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
740
|
+
isValidLogLevel(level) {
|
|
741
|
+
return this.levelsOrder.includes(level);
|
|
742
|
+
}
|
|
743
|
+
log(level, ...message) {
|
|
744
|
+
if (level === "" /* NONE */ || !this.allowLevelLog(level)) {
|
|
745
|
+
return;
|
|
651
746
|
}
|
|
747
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
748
|
+
console[level](`[${timestamp}] [${level.toLowerCase()}]`, ...message);
|
|
652
749
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
const localVarUrlObj = new URL(endpoint, configuration?.basePath);
|
|
657
|
-
const localVarRequestOptions = {
|
|
658
|
-
method,
|
|
659
|
-
...configuration?.baseOptions
|
|
660
|
-
};
|
|
661
|
-
const localVarQueryParameter = { ...params };
|
|
662
|
-
if (options.isSigned) {
|
|
663
|
-
const timestamp = getTimestamp();
|
|
664
|
-
localVarQueryParameter["timestamp"] = timestamp;
|
|
665
|
-
const signature = getSignature(configuration, localVarQueryParameter);
|
|
666
|
-
if (signature) {
|
|
667
|
-
localVarQueryParameter["signature"] = signature;
|
|
750
|
+
allowLevelLog(level) {
|
|
751
|
+
if (!this.isValidLogLevel(level)) {
|
|
752
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
668
753
|
}
|
|
754
|
+
const currentLevelIndex = this.levelsOrder.indexOf(level);
|
|
755
|
+
const minLevelIndex = this.levelsOrder.indexOf(this.minLogLevel);
|
|
756
|
+
return currentLevelIndex >= minLevelIndex;
|
|
669
757
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
758
|
+
debug(...message) {
|
|
759
|
+
this.log("debug" /* DEBUG */, ...message);
|
|
760
|
+
}
|
|
761
|
+
info(...message) {
|
|
762
|
+
this.log("info" /* INFO */, ...message);
|
|
763
|
+
}
|
|
764
|
+
warn(...message) {
|
|
765
|
+
this.log("warn" /* WARN */, ...message);
|
|
766
|
+
}
|
|
767
|
+
error(...message) {
|
|
768
|
+
this.log("error" /* ERROR */, ...message);
|
|
677
769
|
}
|
|
678
|
-
return httpRequestFunction(
|
|
679
|
-
{
|
|
680
|
-
url: toPathString(localVarUrlObj),
|
|
681
|
-
options: localVarRequestOptions
|
|
682
|
-
},
|
|
683
|
-
configuration
|
|
684
|
-
);
|
|
685
770
|
};
|
|
686
|
-
function removeEmptyValue(obj) {
|
|
687
|
-
if (!(obj instanceof Object)) return {};
|
|
688
|
-
return Object.fromEntries(
|
|
689
|
-
Object.entries(obj).filter(
|
|
690
|
-
([, value]) => value !== null && value !== void 0 && value !== ""
|
|
691
|
-
)
|
|
692
|
-
);
|
|
693
|
-
}
|
|
694
|
-
function sortObject(obj) {
|
|
695
|
-
return Object.keys(obj).sort().reduce((res, key) => {
|
|
696
|
-
res[key] = obj[key];
|
|
697
|
-
return res;
|
|
698
|
-
}, {});
|
|
699
|
-
}
|
|
700
|
-
function replaceWebsocketStreamsPlaceholders(str, variables) {
|
|
701
|
-
const normalizedVariables = Object.keys(variables).reduce(
|
|
702
|
-
(acc, key) => {
|
|
703
|
-
const normalizedKey = key.toLowerCase().replace(/[-_]/g, "");
|
|
704
|
-
acc[normalizedKey] = variables[key];
|
|
705
|
-
return acc;
|
|
706
|
-
},
|
|
707
|
-
{}
|
|
708
|
-
);
|
|
709
|
-
return str.replace(/(@)?<([^>]+)>/g, (match, precedingAt, fieldName) => {
|
|
710
|
-
const normalizedFieldName = fieldName.toLowerCase().replace(/[-_]/g, "");
|
|
711
|
-
if (Object.prototype.hasOwnProperty.call(normalizedVariables, normalizedFieldName) && normalizedVariables[normalizedFieldName] != null) {
|
|
712
|
-
const value = normalizedVariables[normalizedFieldName];
|
|
713
|
-
switch (normalizedFieldName) {
|
|
714
|
-
case "symbol":
|
|
715
|
-
case "windowsize":
|
|
716
|
-
return value.toLowerCase();
|
|
717
|
-
case "updatespeed":
|
|
718
|
-
return `@${value}`;
|
|
719
|
-
default:
|
|
720
|
-
return (precedingAt || "") + value;
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
return "";
|
|
724
|
-
});
|
|
725
|
-
}
|
|
726
|
-
function buildUserAgent(packageName, packageVersion) {
|
|
727
|
-
return `${packageName}/${packageVersion} (Node.js/${process.version}; ${(0, import_os.platform)()}; ${(0, import_os.arch)()})`;
|
|
728
|
-
}
|
|
729
771
|
|
|
730
772
|
// src/websocket.ts
|
|
731
773
|
var import_events = require("events");
|
|
@@ -785,6 +827,20 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
785
827
|
});
|
|
786
828
|
}
|
|
787
829
|
}
|
|
830
|
+
/**
|
|
831
|
+
* Retrieves available WebSocket connections based on the connection mode and readiness.
|
|
832
|
+
* In 'single' mode, returns the first connection in the pool.
|
|
833
|
+
* In 'pool' mode, filters and returns connections that are ready for use.
|
|
834
|
+
* @param allowNonEstablishedWebsockets - Optional flag to include non-established WebSocket connections.
|
|
835
|
+
* @returns An array of available WebSocket connections.
|
|
836
|
+
*/
|
|
837
|
+
getAvailableConnections(allowNonEstablishedWebsockets = false) {
|
|
838
|
+
if (this.mode === "single") return [this.connectionPool[0]];
|
|
839
|
+
const availableConnections = this.connectionPool.filter(
|
|
840
|
+
(connection) => this.isConnectionReady(connection, allowNonEstablishedWebsockets)
|
|
841
|
+
);
|
|
842
|
+
return availableConnections;
|
|
843
|
+
}
|
|
788
844
|
/**
|
|
789
845
|
* Gets a WebSocket connection from the pool or single connection.
|
|
790
846
|
* If the connection mode is 'single', it returns the first connection in the pool.
|
|
@@ -794,10 +850,7 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
794
850
|
* @returns {WebsocketConnection} The selected WebSocket connection.
|
|
795
851
|
*/
|
|
796
852
|
getConnection(allowNonEstablishedWebsockets = false) {
|
|
797
|
-
|
|
798
|
-
const availableConnections = this.connectionPool.filter(
|
|
799
|
-
(connection) => this.isConnectionReady(connection, allowNonEstablishedWebsockets)
|
|
800
|
-
);
|
|
853
|
+
const availableConnections = this.getAvailableConnections(allowNonEstablishedWebsockets);
|
|
801
854
|
if (availableConnections.length === 0) {
|
|
802
855
|
throw new Error("No available Websocket connections are ready.");
|
|
803
856
|
}
|
|
@@ -890,12 +943,16 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
890
943
|
*/
|
|
891
944
|
async closeConnectionGracefully(WebsocketConnectionToClose, connection) {
|
|
892
945
|
if (!WebsocketConnectionToClose || !connection) return;
|
|
893
|
-
this.logger.debug(
|
|
946
|
+
this.logger.debug(
|
|
947
|
+
`Waiting for pending requests to complete before disconnecting websocket on connection ${connection.id}.`
|
|
948
|
+
);
|
|
894
949
|
const closePromise = new Promise((resolve) => {
|
|
895
950
|
this.scheduleTimer(
|
|
896
951
|
WebsocketConnectionToClose,
|
|
897
952
|
() => {
|
|
898
|
-
this.logger.warn(
|
|
953
|
+
this.logger.warn(
|
|
954
|
+
`Force-closing websocket connection after 30 seconds on connection ${connection.id}.`
|
|
955
|
+
);
|
|
899
956
|
resolve();
|
|
900
957
|
},
|
|
901
958
|
3e4
|
|
@@ -904,7 +961,9 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
904
961
|
WebsocketConnectionToClose,
|
|
905
962
|
() => {
|
|
906
963
|
if (connection.pendingRequests.size === 0) {
|
|
907
|
-
this.logger.debug(
|
|
964
|
+
this.logger.debug(
|
|
965
|
+
`All pending requests completed, closing websocket connection on connection ${connection.id}.`
|
|
966
|
+
);
|
|
908
967
|
resolve();
|
|
909
968
|
}
|
|
910
969
|
},
|
|
@@ -913,10 +972,44 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
913
972
|
);
|
|
914
973
|
});
|
|
915
974
|
await closePromise;
|
|
916
|
-
this.logger.info(
|
|
975
|
+
this.logger.info(`Closing Websocket connection on connection ${connection.id}.`);
|
|
917
976
|
WebsocketConnectionToClose.close();
|
|
918
977
|
this.cleanup(WebsocketConnectionToClose);
|
|
919
978
|
}
|
|
979
|
+
/**
|
|
980
|
+
* Attempts to re-establish a session for a WebSocket connection.
|
|
981
|
+
* If a session logon request exists and the connection is not already logged on,
|
|
982
|
+
* it sends an authentication request and updates the connection's logged-on status.
|
|
983
|
+
* @param connection - The WebSocket connection to re-authenticate.
|
|
984
|
+
* @private
|
|
985
|
+
*/
|
|
986
|
+
async sessionReLogon(connection) {
|
|
987
|
+
const req = connection.sessionLogonReq;
|
|
988
|
+
if (req && !connection.isSessionLoggedOn) {
|
|
989
|
+
const data = buildWebsocketAPIMessage(
|
|
990
|
+
this.configuration,
|
|
991
|
+
req.method,
|
|
992
|
+
req.payload,
|
|
993
|
+
req.options
|
|
994
|
+
);
|
|
995
|
+
this.logger.debug(`Session re-logon on connection ${connection.id}`, data);
|
|
996
|
+
try {
|
|
997
|
+
await this.send(
|
|
998
|
+
JSON.stringify(data),
|
|
999
|
+
data.id,
|
|
1000
|
+
true,
|
|
1001
|
+
this.configuration.timeout,
|
|
1002
|
+
connection
|
|
1003
|
+
);
|
|
1004
|
+
this.logger.debug(
|
|
1005
|
+
`Session re-logon on connection ${connection.id} was successful.`
|
|
1006
|
+
);
|
|
1007
|
+
connection.isSessionLoggedOn = true;
|
|
1008
|
+
} catch (err) {
|
|
1009
|
+
this.logger.error(`Session re-logon on connection ${connection.id} failed:`, err);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
920
1013
|
/**
|
|
921
1014
|
* Cleans up WebSocket connection resources.
|
|
922
1015
|
* Removes all listeners and clears any associated timers for the provided WebSocket client.
|
|
@@ -941,8 +1034,6 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
941
1034
|
* Handles the opening of a WebSocket connection.
|
|
942
1035
|
* @param url - The URL of the WebSocket server.
|
|
943
1036
|
* @param targetConnection - The WebSocket connection being opened.
|
|
944
|
-
* @param oldConnection - The previous WebSocket connection, if this is a renewal.
|
|
945
|
-
* @param isRenewal - Indicates whether this is a connection renewal.
|
|
946
1037
|
* @param oldWSConnection - The WebSocket client instance associated with the old connection.
|
|
947
1038
|
*/
|
|
948
1039
|
onOpen(url, targetConnection, oldWSConnection) {
|
|
@@ -957,6 +1048,7 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
957
1048
|
} else {
|
|
958
1049
|
this.emit("open", this);
|
|
959
1050
|
}
|
|
1051
|
+
this.sessionReLogon(targetConnection);
|
|
960
1052
|
}
|
|
961
1053
|
/**
|
|
962
1054
|
* Returns the URL to use when reconnecting.
|
|
@@ -1027,10 +1119,12 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
1027
1119
|
);
|
|
1028
1120
|
if (isRenewal) targetConnection.renewalPending = true;
|
|
1029
1121
|
else targetConnection.ws = ws;
|
|
1122
|
+
targetConnection.isSessionLoggedOn = false;
|
|
1030
1123
|
this.scheduleTimer(
|
|
1031
1124
|
ws,
|
|
1032
1125
|
() => {
|
|
1033
1126
|
this.logger.info(`Renewing Websocket connection with id ${targetConnection.id}`);
|
|
1127
|
+
targetConnection.isSessionLoggedOn = false;
|
|
1034
1128
|
this.enqueueReconnection(
|
|
1035
1129
|
targetConnection,
|
|
1036
1130
|
this.getReconnectURL(url, targetConnection),
|
|
@@ -1074,6 +1168,7 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
1074
1168
|
this.logger.info(
|
|
1075
1169
|
`Reconnecting conection with id ${targetConnection.id} to the server.`
|
|
1076
1170
|
);
|
|
1171
|
+
targetConnection.isSessionLoggedOn = false;
|
|
1077
1172
|
targetConnection.reconnectionPending = true;
|
|
1078
1173
|
this.enqueueReconnection(
|
|
1079
1174
|
targetConnection,
|
|
@@ -1109,6 +1204,8 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
1109
1204
|
else {
|
|
1110
1205
|
this.connectionPool.forEach((connection) => {
|
|
1111
1206
|
connection.closeInitiated = true;
|
|
1207
|
+
connection.isSessionLoggedOn = false;
|
|
1208
|
+
connection.sessionLogonReq = void 0;
|
|
1112
1209
|
});
|
|
1113
1210
|
const disconnectPromises = this.connectionPool.map(
|
|
1114
1211
|
(connection) => this.closeConnectionGracefully(connection.ws, connection)
|
|
@@ -1269,37 +1366,44 @@ var WebsocketAPIBase = class extends WebsocketCommon {
|
|
|
1269
1366
|
});
|
|
1270
1367
|
});
|
|
1271
1368
|
}
|
|
1272
|
-
|
|
1273
|
-
* Sends a message to the WebSocket API Server.
|
|
1274
|
-
* Supports both signed and unsigned messages.
|
|
1275
|
-
* @param method The API method to call
|
|
1276
|
-
* @param payload Message parameters and options
|
|
1277
|
-
* @param options Additional requests options (withApiKey, isSigned)
|
|
1278
|
-
* @returns Promise that resolves with the server response
|
|
1279
|
-
* @throws Error if not connected
|
|
1280
|
-
*/
|
|
1281
|
-
sendMessage(method, payload = {}, options = {}) {
|
|
1369
|
+
async sendMessage(method, payload = {}, options = {}) {
|
|
1282
1370
|
if (!this.isConnected()) {
|
|
1283
|
-
|
|
1284
|
-
}
|
|
1285
|
-
const id = payload.id && /^[0-9a-f]{32}$/.test(payload.id) ? payload.id : randomString();
|
|
1286
|
-
delete payload.id;
|
|
1287
|
-
let params = removeEmptyValue(payload);
|
|
1288
|
-
if (options.withApiKey || options.isSigned) {
|
|
1289
|
-
params.apiKey = this.configuration.apiKey;
|
|
1371
|
+
throw new Error("Not connected");
|
|
1290
1372
|
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
const data = {
|
|
1297
|
-
id,
|
|
1373
|
+
const isSessionReq = options.isSessionLogon || options.isSessionLogout;
|
|
1374
|
+
const connections = isSessionReq ? this.getAvailableConnections() : [this.getConnection()];
|
|
1375
|
+
const skipAuth = isSessionReq ? false : this.configuration.autoSessionReLogon && connections[0].isSessionLoggedOn;
|
|
1376
|
+
const data = buildWebsocketAPIMessage(
|
|
1377
|
+
this.configuration,
|
|
1298
1378
|
method,
|
|
1299
|
-
|
|
1300
|
-
|
|
1379
|
+
payload,
|
|
1380
|
+
options,
|
|
1381
|
+
skipAuth
|
|
1382
|
+
);
|
|
1301
1383
|
this.logger.debug("Send message to Binance WebSocket API Server:", data);
|
|
1302
|
-
|
|
1384
|
+
const responses = await Promise.all(
|
|
1385
|
+
connections.map(
|
|
1386
|
+
(connection) => this.send(
|
|
1387
|
+
JSON.stringify(data),
|
|
1388
|
+
data.id,
|
|
1389
|
+
true,
|
|
1390
|
+
this.configuration.timeout,
|
|
1391
|
+
connection
|
|
1392
|
+
)
|
|
1393
|
+
)
|
|
1394
|
+
);
|
|
1395
|
+
if (isSessionReq && this.configuration.autoSessionReLogon) {
|
|
1396
|
+
connections.forEach((connection) => {
|
|
1397
|
+
if (options.isSessionLogon) {
|
|
1398
|
+
connection.isSessionLoggedOn = true;
|
|
1399
|
+
connection.sessionLogonReq = { method, payload, options };
|
|
1400
|
+
} else {
|
|
1401
|
+
connection.isSessionLoggedOn = false;
|
|
1402
|
+
connection.sessionLogonReq = void 0;
|
|
1403
|
+
}
|
|
1404
|
+
});
|
|
1405
|
+
}
|
|
1406
|
+
return connections.length === 1 && !isSessionReq ? responses[0] : responses;
|
|
1303
1407
|
}
|
|
1304
1408
|
};
|
|
1305
1409
|
var WebsocketStreamsBase = class extends WebsocketCommon {
|
|
@@ -1411,7 +1515,6 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
|
|
|
1411
1515
|
* @param url The URL of the WebSocket connection.
|
|
1412
1516
|
* @param targetConnection The WebSocket connection that was opened.
|
|
1413
1517
|
* @param oldConnection The previous WebSocket connection, if any.
|
|
1414
|
-
* @param isRenewal Whether the connection is a renewal of an existing connection.
|
|
1415
1518
|
*/
|
|
1416
1519
|
onOpen(url, targetConnection, oldWSConnection) {
|
|
1417
1520
|
this.processPendingSubscriptions(targetConnection);
|
|
@@ -1463,7 +1566,7 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
|
|
|
1463
1566
|
connectionStreamMap.forEach((streams2, connection) => {
|
|
1464
1567
|
if (!this.isConnected(connection)) {
|
|
1465
1568
|
this.logger.info(
|
|
1466
|
-
`Connection is not ready. Queuing subscription for streams: ${streams2}`
|
|
1569
|
+
`Connection ${connection.id} is not ready. Queuing subscription for streams: ${streams2}`
|
|
1467
1570
|
);
|
|
1468
1571
|
connection.pendingSubscriptions?.push(...streams2);
|
|
1469
1572
|
return;
|
|
@@ -1606,16 +1709,19 @@ function createStreamHandler(websocketBase, streamOrId, id) {
|
|
|
1606
1709
|
assertParamExists,
|
|
1607
1710
|
buildQueryString,
|
|
1608
1711
|
buildUserAgent,
|
|
1712
|
+
buildWebsocketAPIMessage,
|
|
1609
1713
|
clearSignerCache,
|
|
1610
1714
|
createStreamHandler,
|
|
1611
1715
|
delay,
|
|
1612
1716
|
getSignature,
|
|
1613
1717
|
getTimestamp,
|
|
1614
1718
|
httpRequestFunction,
|
|
1719
|
+
parseCustomHeaders,
|
|
1615
1720
|
parseRateLimitHeaders,
|
|
1616
1721
|
randomString,
|
|
1617
1722
|
removeEmptyValue,
|
|
1618
1723
|
replaceWebsocketStreamsPlaceholders,
|
|
1724
|
+
sanitizeHeaderValue,
|
|
1619
1725
|
sendRequest,
|
|
1620
1726
|
setFlattenedQueryParams,
|
|
1621
1727
|
setSearchParams,
|