@binance/common 1.1.2 → 1.2.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/README.md +1 -0
- package/dist/index.d.mts +91 -22
- package/dist/index.d.ts +91 -22
- package/dist/index.js +520 -406
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +512 -406
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,249 +1,3 @@
|
|
|
1
|
-
// src/configuration.ts
|
|
2
|
-
var ConfigurationRestAPI = class {
|
|
3
|
-
constructor(param = { apiKey: "" }) {
|
|
4
|
-
this.apiKey = param.apiKey;
|
|
5
|
-
this.apiSecret = param.apiSecret;
|
|
6
|
-
this.basePath = param.basePath;
|
|
7
|
-
this.keepAlive = param.keepAlive ?? true;
|
|
8
|
-
this.compression = param.compression ?? true;
|
|
9
|
-
this.retries = param.retries ?? 3;
|
|
10
|
-
this.backoff = param.backoff ?? 1e3;
|
|
11
|
-
this.privateKey = param.privateKey;
|
|
12
|
-
this.privateKeyPassphrase = param.privateKeyPassphrase;
|
|
13
|
-
this.timeUnit = param.timeUnit;
|
|
14
|
-
this.baseOptions = {
|
|
15
|
-
timeout: param.timeout ?? 1e3,
|
|
16
|
-
proxy: param.proxy && {
|
|
17
|
-
host: param.proxy.host,
|
|
18
|
-
port: param.proxy.port,
|
|
19
|
-
auth: param.proxy.auth
|
|
20
|
-
},
|
|
21
|
-
httpsAgent: param.httpsAgent ?? false,
|
|
22
|
-
headers: {
|
|
23
|
-
"Content-Type": "application/json",
|
|
24
|
-
"X-MBX-APIKEY": param.apiKey
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
var ConfigurationWebsocketAPI = class {
|
|
30
|
-
constructor(param = { apiKey: "" }) {
|
|
31
|
-
this.apiKey = param.apiKey;
|
|
32
|
-
this.apiSecret = param.apiSecret;
|
|
33
|
-
this.wsURL = param.wsURL;
|
|
34
|
-
this.timeout = param.timeout ?? 5e3;
|
|
35
|
-
this.reconnectDelay = param.reconnectDelay ?? 5e3;
|
|
36
|
-
this.compression = param.compression ?? true;
|
|
37
|
-
this.agent = param.agent ?? false;
|
|
38
|
-
this.mode = param.mode ?? "single";
|
|
39
|
-
this.poolSize = param.poolSize ?? 1;
|
|
40
|
-
this.privateKey = param.privateKey;
|
|
41
|
-
this.privateKeyPassphrase = param.privateKeyPassphrase;
|
|
42
|
-
this.timeUnit = param.timeUnit;
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
var ConfigurationWebsocketStreams = class {
|
|
46
|
-
constructor(param = {}) {
|
|
47
|
-
this.wsURL = param.wsURL;
|
|
48
|
-
this.reconnectDelay = param.reconnectDelay ?? 5e3;
|
|
49
|
-
this.compression = param.compression ?? true;
|
|
50
|
-
this.agent = param.agent ?? false;
|
|
51
|
-
this.mode = param.mode ?? "single";
|
|
52
|
-
this.poolSize = param.poolSize ?? 1;
|
|
53
|
-
this.timeUnit = param.timeUnit;
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// src/constants.ts
|
|
58
|
-
var TimeUnit = {
|
|
59
|
-
MILLISECOND: "MILLISECOND",
|
|
60
|
-
millisecond: "millisecond",
|
|
61
|
-
MICROSECOND: "MICROSECOND",
|
|
62
|
-
microsecond: "microsecond"
|
|
63
|
-
};
|
|
64
|
-
var ALGO_REST_API_PROD_URL = "https://api.binance.com";
|
|
65
|
-
var AUTO_INVEST_REST_API_PROD_URL = "https://api.binance.com";
|
|
66
|
-
var C2C_REST_API_PROD_URL = "https://api.binance.com";
|
|
67
|
-
var CONVERT_REST_API_PROD_URL = "https://api.binance.com";
|
|
68
|
-
var COPY_TRADING_REST_API_PROD_URL = "https://api.binance.com";
|
|
69
|
-
var CRYPTO_LOAN_REST_API_PROD_URL = "https://api.binance.com";
|
|
70
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_REST_API_PROD_URL = "https://dapi.binance.com";
|
|
71
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
72
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_WS_API_PROD_URL = "wss://ws-dapi.binance.com/ws-dapi/v1";
|
|
73
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_WS_API_TESTNET_URL = "wss://testnet.binancefuture.com/ws-dapi/v1";
|
|
74
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_PROD_URL = "wss://dstream.binance.com";
|
|
75
|
-
var DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_TESTNET_URL = "wss://dstream.binancefuture.com";
|
|
76
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_REST_API_PROD_URL = "https://fapi.binance.com";
|
|
77
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
78
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_WS_API_PROD_URL = "wss://ws-fapi.binance.com/ws-fapi/v1";
|
|
79
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_WS_API_TESTNET_URL = "wss://testnet.binancefuture.com/ws-fapi/v1";
|
|
80
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_PROD_URL = "wss://fstream.binance.com";
|
|
81
|
-
var DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_TESTNET_URL = "wss://stream.binancefuture.com";
|
|
82
|
-
var DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL = "https://eapi.binance.com";
|
|
83
|
-
var DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL = "wss://nbstream.binance.com/eoptions";
|
|
84
|
-
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL = "https://papi.binance.com";
|
|
85
|
-
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
86
|
-
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_REST_API_PROD_URL = "https://api.binance.com";
|
|
87
|
-
var DUAL_INVESTMENT_REST_API_PROD_URL = "https://api.binance.com";
|
|
88
|
-
var FIAT_REST_API_PROD_URL = "https://api.binance.com";
|
|
89
|
-
var GIFT_CARD_REST_API_PROD_URL = "https://api.binance.com";
|
|
90
|
-
var MARGIN_TRADING_REST_API_PROD_URL = "https://api.binance.com";
|
|
91
|
-
var MINING_REST_API_PROD_URL = "https://api.binance.com";
|
|
92
|
-
var NFT_REST_API_PROD_URL = "https://api.binance.com";
|
|
93
|
-
var PAY_REST_API_PROD_URL = "https://api.binance.com";
|
|
94
|
-
var REBATE_REST_API_PROD_URL = "https://api.binance.com";
|
|
95
|
-
var SIMPLE_EARN_REST_API_PROD_URL = "https://api.binance.com";
|
|
96
|
-
var SPOT_REST_API_PROD_URL = "https://api.binance.com";
|
|
97
|
-
var SPOT_REST_API_TESTNET_URL = "https://testnet.binance.vision";
|
|
98
|
-
var SPOT_WS_API_PROD_URL = "wss://ws-api.binance.com:443/ws-api/v3";
|
|
99
|
-
var SPOT_WS_API_TESTNET_URL = "wss://ws-api.testnet.binance.vision/ws-api/v3";
|
|
100
|
-
var SPOT_WS_STREAMS_PROD_URL = "wss://stream.binance.com:9443";
|
|
101
|
-
var SPOT_WS_STREAMS_TESTNET_URL = "wss://stream.testnet.binance.vision";
|
|
102
|
-
var SPOT_REST_API_MARKET_URL = "https://data-api.binance.vision";
|
|
103
|
-
var SPOT_WS_STREAMS_MARKET_URL = "wss://data-stream.binance.vision";
|
|
104
|
-
var STAKING_REST_API_PROD_URL = "https://api.binance.com";
|
|
105
|
-
var SUB_ACCOUNT_REST_API_PROD_URL = "https://api.binance.com";
|
|
106
|
-
var VIP_LOAN_REST_API_PROD_URL = "https://api.binance.com";
|
|
107
|
-
var WALLET_REST_API_PROD_URL = "https://api.binance.com";
|
|
108
|
-
|
|
109
|
-
// src/errors.ts
|
|
110
|
-
var ConnectorClientError = class _ConnectorClientError extends Error {
|
|
111
|
-
constructor(msg) {
|
|
112
|
-
super(msg || "An unexpected error occurred.");
|
|
113
|
-
Object.setPrototypeOf(this, _ConnectorClientError.prototype);
|
|
114
|
-
this.name = "ConnectorClientError";
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
var RequiredError = class _RequiredError extends Error {
|
|
118
|
-
constructor(field, msg) {
|
|
119
|
-
super(msg || `Required parameter ${field} was null or undefined.`);
|
|
120
|
-
this.field = field;
|
|
121
|
-
Object.setPrototypeOf(this, _RequiredError.prototype);
|
|
122
|
-
this.name = "RequiredError";
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
var UnauthorizedError = class _UnauthorizedError extends Error {
|
|
126
|
-
constructor(msg) {
|
|
127
|
-
super(msg || "Unauthorized access. Authentication required.");
|
|
128
|
-
Object.setPrototypeOf(this, _UnauthorizedError.prototype);
|
|
129
|
-
this.name = "UnauthorizedError";
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
var ForbiddenError = class _ForbiddenError extends Error {
|
|
133
|
-
constructor(msg) {
|
|
134
|
-
super(msg || "Access to the requested resource is forbidden.");
|
|
135
|
-
Object.setPrototypeOf(this, _ForbiddenError.prototype);
|
|
136
|
-
this.name = "ForbiddenError";
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
var TooManyRequestsError = class _TooManyRequestsError extends Error {
|
|
140
|
-
constructor(msg) {
|
|
141
|
-
super(msg || "Too many requests. You are being rate-limited.");
|
|
142
|
-
Object.setPrototypeOf(this, _TooManyRequestsError.prototype);
|
|
143
|
-
this.name = "TooManyRequestsError";
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
var RateLimitBanError = class _RateLimitBanError extends Error {
|
|
147
|
-
constructor(msg) {
|
|
148
|
-
super(msg || "The IP address has been banned for exceeding rate limits.");
|
|
149
|
-
Object.setPrototypeOf(this, _RateLimitBanError.prototype);
|
|
150
|
-
this.name = "RateLimitBanError";
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
var ServerError = class _ServerError extends Error {
|
|
154
|
-
constructor(msg, statusCode) {
|
|
155
|
-
super(msg || "An internal server error occurred.");
|
|
156
|
-
this.statusCode = statusCode;
|
|
157
|
-
Object.setPrototypeOf(this, _ServerError.prototype);
|
|
158
|
-
this.name = "ServerError";
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
var NetworkError = class _NetworkError extends Error {
|
|
162
|
-
constructor(msg) {
|
|
163
|
-
super(msg || "A network error occurred.");
|
|
164
|
-
Object.setPrototypeOf(this, _NetworkError.prototype);
|
|
165
|
-
this.name = "NetworkError";
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
var NotFoundError = class _NotFoundError extends Error {
|
|
169
|
-
constructor(msg) {
|
|
170
|
-
super(msg || "The requested resource was not found.");
|
|
171
|
-
Object.setPrototypeOf(this, _NotFoundError.prototype);
|
|
172
|
-
this.name = "NotFoundError";
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
var BadRequestError = class _BadRequestError extends Error {
|
|
176
|
-
constructor(msg) {
|
|
177
|
-
super(msg || "The request was invalid or cannot be otherwise served.");
|
|
178
|
-
Object.setPrototypeOf(this, _BadRequestError.prototype);
|
|
179
|
-
this.name = "BadRequestError";
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
// src/logger.ts
|
|
184
|
-
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
185
|
-
LogLevel2["NONE"] = "";
|
|
186
|
-
LogLevel2["DEBUG"] = "debug";
|
|
187
|
-
LogLevel2["INFO"] = "info";
|
|
188
|
-
LogLevel2["WARN"] = "warn";
|
|
189
|
-
LogLevel2["ERROR"] = "error";
|
|
190
|
-
return LogLevel2;
|
|
191
|
-
})(LogLevel || {});
|
|
192
|
-
var Logger = class _Logger {
|
|
193
|
-
constructor() {
|
|
194
|
-
this.minLogLevel = "info" /* INFO */;
|
|
195
|
-
this.levelsOrder = [
|
|
196
|
-
"" /* NONE */,
|
|
197
|
-
"debug" /* DEBUG */,
|
|
198
|
-
"info" /* INFO */,
|
|
199
|
-
"warn" /* WARN */,
|
|
200
|
-
"error" /* ERROR */
|
|
201
|
-
];
|
|
202
|
-
}
|
|
203
|
-
static getInstance() {
|
|
204
|
-
if (!_Logger.instance) {
|
|
205
|
-
_Logger.instance = new _Logger();
|
|
206
|
-
}
|
|
207
|
-
return _Logger.instance;
|
|
208
|
-
}
|
|
209
|
-
setMinLogLevel(level) {
|
|
210
|
-
if (!this.isValidLogLevel(level)) {
|
|
211
|
-
throw new Error(`Invalid log level: ${level}`);
|
|
212
|
-
}
|
|
213
|
-
this.minLogLevel = level;
|
|
214
|
-
}
|
|
215
|
-
isValidLogLevel(level) {
|
|
216
|
-
return this.levelsOrder.includes(level);
|
|
217
|
-
}
|
|
218
|
-
log(level, ...message) {
|
|
219
|
-
if (level === "" /* NONE */ || !this.allowLevelLog(level)) {
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
223
|
-
console[level](`[${timestamp}] [${level.toLowerCase()}]`, ...message);
|
|
224
|
-
}
|
|
225
|
-
allowLevelLog(level) {
|
|
226
|
-
if (!this.isValidLogLevel(level)) {
|
|
227
|
-
throw new Error(`Invalid log level: ${level}`);
|
|
228
|
-
}
|
|
229
|
-
const currentLevelIndex = this.levelsOrder.indexOf(level);
|
|
230
|
-
const minLevelIndex = this.levelsOrder.indexOf(this.minLogLevel);
|
|
231
|
-
return currentLevelIndex >= minLevelIndex;
|
|
232
|
-
}
|
|
233
|
-
debug(...message) {
|
|
234
|
-
this.log("debug" /* DEBUG */, ...message);
|
|
235
|
-
}
|
|
236
|
-
info(...message) {
|
|
237
|
-
this.log("info" /* INFO */, ...message);
|
|
238
|
-
}
|
|
239
|
-
warn(...message) {
|
|
240
|
-
this.log("warn" /* WARN */, ...message);
|
|
241
|
-
}
|
|
242
|
-
error(...message) {
|
|
243
|
-
this.log("error" /* ERROR */, ...message);
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
|
|
247
1
|
// src/utils.ts
|
|
248
2
|
import crypto from "crypto";
|
|
249
3
|
import fs from "fs";
|
|
@@ -462,141 +216,431 @@ var httpRequestFunction = async function(axiosArgs, configuration) {
|
|
|
462
216
|
}
|
|
463
217
|
}
|
|
464
218
|
}
|
|
465
|
-
throw lastError;
|
|
219
|
+
throw lastError;
|
|
220
|
+
};
|
|
221
|
+
var parseRateLimitHeaders = function(headers) {
|
|
222
|
+
const rateLimits = [];
|
|
223
|
+
const parseIntervalDetails = (key) => {
|
|
224
|
+
const match = key.match(/x-mbx-used-weight-(\d+)([smhd])|x-mbx-order-count-(\d+)([smhd])/i);
|
|
225
|
+
if (!match) return null;
|
|
226
|
+
const intervalNum = parseInt(match[1] || match[3], 10);
|
|
227
|
+
const intervalLetter = (match[2] || match[4])?.toUpperCase();
|
|
228
|
+
let interval;
|
|
229
|
+
switch (intervalLetter) {
|
|
230
|
+
case "S":
|
|
231
|
+
interval = "SECOND";
|
|
232
|
+
break;
|
|
233
|
+
case "M":
|
|
234
|
+
interval = "MINUTE";
|
|
235
|
+
break;
|
|
236
|
+
case "H":
|
|
237
|
+
interval = "HOUR";
|
|
238
|
+
break;
|
|
239
|
+
case "D":
|
|
240
|
+
interval = "DAY";
|
|
241
|
+
break;
|
|
242
|
+
default:
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
return { interval, intervalNum };
|
|
246
|
+
};
|
|
247
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
248
|
+
const normalizedKey = key.toLowerCase();
|
|
249
|
+
if (value === void 0) continue;
|
|
250
|
+
if (normalizedKey.startsWith("x-mbx-used-weight-")) {
|
|
251
|
+
const details = parseIntervalDetails(normalizedKey);
|
|
252
|
+
if (details) {
|
|
253
|
+
rateLimits.push({
|
|
254
|
+
rateLimitType: "REQUEST_WEIGHT",
|
|
255
|
+
interval: details.interval,
|
|
256
|
+
intervalNum: details.intervalNum,
|
|
257
|
+
count: parseInt(value, 10)
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
} else if (normalizedKey.startsWith("x-mbx-order-count-")) {
|
|
261
|
+
const details = parseIntervalDetails(normalizedKey);
|
|
262
|
+
if (details) {
|
|
263
|
+
rateLimits.push({
|
|
264
|
+
rateLimitType: "ORDERS",
|
|
265
|
+
interval: details.interval,
|
|
266
|
+
intervalNum: details.intervalNum,
|
|
267
|
+
count: parseInt(value, 10)
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (headers["retry-after"]) {
|
|
273
|
+
const retryAfter = parseInt(headers["retry-after"], 10);
|
|
274
|
+
for (const limit of rateLimits) {
|
|
275
|
+
limit.retryAfter = retryAfter;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return rateLimits;
|
|
279
|
+
};
|
|
280
|
+
var sendRequest = function(configuration, endpoint, method, params = {}, timeUnit, options = {}) {
|
|
281
|
+
const localVarUrlObj = new URL(endpoint, configuration?.basePath);
|
|
282
|
+
const localVarRequestOptions = {
|
|
283
|
+
method,
|
|
284
|
+
...configuration?.baseOptions
|
|
285
|
+
};
|
|
286
|
+
const localVarQueryParameter = { ...params };
|
|
287
|
+
if (options.isSigned) {
|
|
288
|
+
const timestamp = getTimestamp();
|
|
289
|
+
localVarQueryParameter["timestamp"] = timestamp;
|
|
290
|
+
const signature = getSignature(configuration, localVarQueryParameter);
|
|
291
|
+
if (signature) {
|
|
292
|
+
localVarQueryParameter["signature"] = signature;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
|
296
|
+
if (timeUnit && localVarRequestOptions.headers) {
|
|
297
|
+
const _timeUnit = validateTimeUnit(timeUnit);
|
|
298
|
+
localVarRequestOptions.headers = {
|
|
299
|
+
...localVarRequestOptions.headers,
|
|
300
|
+
"X-MBX-TIME-UNIT": _timeUnit
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
return httpRequestFunction(
|
|
304
|
+
{
|
|
305
|
+
url: toPathString(localVarUrlObj),
|
|
306
|
+
options: localVarRequestOptions
|
|
307
|
+
},
|
|
308
|
+
configuration
|
|
309
|
+
);
|
|
310
|
+
};
|
|
311
|
+
function removeEmptyValue(obj) {
|
|
312
|
+
if (!(obj instanceof Object)) return {};
|
|
313
|
+
return Object.fromEntries(
|
|
314
|
+
Object.entries(obj).filter(
|
|
315
|
+
([, value]) => value !== null && value !== void 0 && value !== ""
|
|
316
|
+
)
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
function sortObject(obj) {
|
|
320
|
+
return Object.keys(obj).sort().reduce((res, key) => {
|
|
321
|
+
res[key] = obj[key];
|
|
322
|
+
return res;
|
|
323
|
+
}, {});
|
|
324
|
+
}
|
|
325
|
+
function replaceWebsocketStreamsPlaceholders(str, variables) {
|
|
326
|
+
const normalizedVariables = Object.keys(variables).reduce(
|
|
327
|
+
(acc, key) => {
|
|
328
|
+
const normalizedKey = key.toLowerCase().replace(/[-_]/g, "");
|
|
329
|
+
acc[normalizedKey] = variables[key];
|
|
330
|
+
return acc;
|
|
331
|
+
},
|
|
332
|
+
{}
|
|
333
|
+
);
|
|
334
|
+
return str.replace(/(@)?<([^>]+)>/g, (match, precedingAt, fieldName) => {
|
|
335
|
+
const normalizedFieldName = fieldName.toLowerCase().replace(/[-_]/g, "");
|
|
336
|
+
if (Object.prototype.hasOwnProperty.call(normalizedVariables, normalizedFieldName) && normalizedVariables[normalizedFieldName] != null) {
|
|
337
|
+
const value = normalizedVariables[normalizedFieldName];
|
|
338
|
+
switch (normalizedFieldName) {
|
|
339
|
+
case "symbol":
|
|
340
|
+
case "windowsize":
|
|
341
|
+
return value.toLowerCase();
|
|
342
|
+
case "updatespeed":
|
|
343
|
+
return `@${value}`;
|
|
344
|
+
default:
|
|
345
|
+
return (precedingAt || "") + value;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return "";
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
function buildUserAgent(packageName, packageVersion) {
|
|
352
|
+
return `${packageName}/${packageVersion} (Node.js/${process.version}; ${platform()}; ${arch()})`;
|
|
353
|
+
}
|
|
354
|
+
function buildWebsocketAPIMessage(configuration, method, payload, options, skipAuth = false) {
|
|
355
|
+
const id = payload.id && /^[0-9a-f]{32}$/.test(payload.id) ? payload.id : randomString();
|
|
356
|
+
delete payload.id;
|
|
357
|
+
let params = removeEmptyValue(payload);
|
|
358
|
+
if ((options.withApiKey || options.isSigned) && !skipAuth) params.apiKey = configuration.apiKey;
|
|
359
|
+
if (options.isSigned) {
|
|
360
|
+
params.timestamp = getTimestamp();
|
|
361
|
+
params = sortObject(params);
|
|
362
|
+
if (!skipAuth) params.signature = getSignature(configuration, params);
|
|
363
|
+
}
|
|
364
|
+
return { id, method, params };
|
|
365
|
+
}
|
|
366
|
+
function sanitizeHeaderValue(value) {
|
|
367
|
+
const sanitizeOne = (v) => {
|
|
368
|
+
if (/\r|\n/.test(v)) throw new Error(`Invalid header value (contains CR/LF): "${v}"`);
|
|
369
|
+
return v;
|
|
370
|
+
};
|
|
371
|
+
return Array.isArray(value) ? value.map(sanitizeOne) : sanitizeOne(value);
|
|
372
|
+
}
|
|
373
|
+
function parseCustomHeaders(headers) {
|
|
374
|
+
if (!headers || Object.keys(headers).length === 0) return {};
|
|
375
|
+
const forbidden = /* @__PURE__ */ new Set(["host", "authorization", "cookie", ":method", ":path"]);
|
|
376
|
+
const parsedHeaders = {};
|
|
377
|
+
for (const [rawName, rawValue] of Object.entries(headers || {})) {
|
|
378
|
+
const name = rawName.trim();
|
|
379
|
+
if (forbidden.has(name.toLowerCase())) {
|
|
380
|
+
console.warn(`Dropping forbidden header: ${name}`);
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
try {
|
|
384
|
+
parsedHeaders[name] = sanitizeHeaderValue(rawValue);
|
|
385
|
+
} catch {
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return parsedHeaders;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// src/configuration.ts
|
|
393
|
+
var ConfigurationRestAPI = class {
|
|
394
|
+
constructor(param = { apiKey: "" }) {
|
|
395
|
+
this.apiKey = param.apiKey;
|
|
396
|
+
this.apiSecret = param.apiSecret;
|
|
397
|
+
this.basePath = param.basePath;
|
|
398
|
+
this.keepAlive = param.keepAlive ?? true;
|
|
399
|
+
this.compression = param.compression ?? true;
|
|
400
|
+
this.retries = param.retries ?? 3;
|
|
401
|
+
this.backoff = param.backoff ?? 1e3;
|
|
402
|
+
this.privateKey = param.privateKey;
|
|
403
|
+
this.privateKeyPassphrase = param.privateKeyPassphrase;
|
|
404
|
+
this.timeUnit = param.timeUnit;
|
|
405
|
+
this.baseOptions = {
|
|
406
|
+
timeout: param.timeout ?? 1e3,
|
|
407
|
+
proxy: param.proxy && {
|
|
408
|
+
host: param.proxy.host,
|
|
409
|
+
port: param.proxy.port,
|
|
410
|
+
auth: param.proxy.auth
|
|
411
|
+
},
|
|
412
|
+
httpsAgent: param.httpsAgent ?? false,
|
|
413
|
+
headers: {
|
|
414
|
+
...parseCustomHeaders(param.customHeaders || {}),
|
|
415
|
+
"Content-Type": "application/json",
|
|
416
|
+
"X-MBX-APIKEY": param.apiKey
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
var ConfigurationWebsocketAPI2 = class {
|
|
422
|
+
constructor(param = { apiKey: "" }) {
|
|
423
|
+
this.apiKey = param.apiKey;
|
|
424
|
+
this.apiSecret = param.apiSecret;
|
|
425
|
+
this.wsURL = param.wsURL;
|
|
426
|
+
this.timeout = param.timeout ?? 5e3;
|
|
427
|
+
this.reconnectDelay = param.reconnectDelay ?? 5e3;
|
|
428
|
+
this.compression = param.compression ?? true;
|
|
429
|
+
this.agent = param.agent ?? false;
|
|
430
|
+
this.mode = param.mode ?? "single";
|
|
431
|
+
this.poolSize = param.poolSize ?? 1;
|
|
432
|
+
this.privateKey = param.privateKey;
|
|
433
|
+
this.privateKeyPassphrase = param.privateKeyPassphrase;
|
|
434
|
+
this.timeUnit = param.timeUnit;
|
|
435
|
+
this.autoSessionReLogon = param.autoSessionReLogon ?? true;
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
var ConfigurationWebsocketStreams = class {
|
|
439
|
+
constructor(param = {}) {
|
|
440
|
+
this.wsURL = param.wsURL;
|
|
441
|
+
this.reconnectDelay = param.reconnectDelay ?? 5e3;
|
|
442
|
+
this.compression = param.compression ?? true;
|
|
443
|
+
this.agent = param.agent ?? false;
|
|
444
|
+
this.mode = param.mode ?? "single";
|
|
445
|
+
this.poolSize = param.poolSize ?? 1;
|
|
446
|
+
this.timeUnit = param.timeUnit;
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
// src/constants.ts
|
|
451
|
+
var TimeUnit = {
|
|
452
|
+
MILLISECOND: "MILLISECOND",
|
|
453
|
+
millisecond: "millisecond",
|
|
454
|
+
MICROSECOND: "MICROSECOND",
|
|
455
|
+
microsecond: "microsecond"
|
|
456
|
+
};
|
|
457
|
+
var ALGO_REST_API_PROD_URL = "https://api.binance.com";
|
|
458
|
+
var AUTO_INVEST_REST_API_PROD_URL = "https://api.binance.com";
|
|
459
|
+
var C2C_REST_API_PROD_URL = "https://api.binance.com";
|
|
460
|
+
var CONVERT_REST_API_PROD_URL = "https://api.binance.com";
|
|
461
|
+
var COPY_TRADING_REST_API_PROD_URL = "https://api.binance.com";
|
|
462
|
+
var CRYPTO_LOAN_REST_API_PROD_URL = "https://api.binance.com";
|
|
463
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_REST_API_PROD_URL = "https://dapi.binance.com";
|
|
464
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
465
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_WS_API_PROD_URL = "wss://ws-dapi.binance.com/ws-dapi/v1";
|
|
466
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_WS_API_TESTNET_URL = "wss://testnet.binancefuture.com/ws-dapi/v1";
|
|
467
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_PROD_URL = "wss://dstream.binance.com";
|
|
468
|
+
var DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_TESTNET_URL = "wss://dstream.binancefuture.com";
|
|
469
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_REST_API_PROD_URL = "https://fapi.binance.com";
|
|
470
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
471
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_WS_API_PROD_URL = "wss://ws-fapi.binance.com/ws-fapi/v1";
|
|
472
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_WS_API_TESTNET_URL = "wss://testnet.binancefuture.com/ws-fapi/v1";
|
|
473
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_PROD_URL = "wss://fstream.binance.com";
|
|
474
|
+
var DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_TESTNET_URL = "wss://stream.binancefuture.com";
|
|
475
|
+
var DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL = "https://eapi.binance.com";
|
|
476
|
+
var DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL = "wss://nbstream.binance.com/eoptions";
|
|
477
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL = "https://papi.binance.com";
|
|
478
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
|
|
479
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_PROD_URL = "wss://fstream.binance.com/pm";
|
|
480
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_TESTNET_URL = "wss://fstream.binancefuture.com/pm";
|
|
481
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_REST_API_PROD_URL = "https://api.binance.com";
|
|
482
|
+
var DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_WS_STREAMS_PROD_URL = "wss://fstream.binance.com/pm-classic";
|
|
483
|
+
var DUAL_INVESTMENT_REST_API_PROD_URL = "https://api.binance.com";
|
|
484
|
+
var FIAT_REST_API_PROD_URL = "https://api.binance.com";
|
|
485
|
+
var GIFT_CARD_REST_API_PROD_URL = "https://api.binance.com";
|
|
486
|
+
var MARGIN_TRADING_REST_API_PROD_URL = "https://api.binance.com";
|
|
487
|
+
var MARGIN_TRADING_WS_STREAMS_PROD_URL = "wss://stream.binance.com:9443";
|
|
488
|
+
var MARGIN_TRADING_RISK_WS_STREAMS_PROD_URL = "wss://margin-stream.binance.com";
|
|
489
|
+
var MINING_REST_API_PROD_URL = "https://api.binance.com";
|
|
490
|
+
var NFT_REST_API_PROD_URL = "https://api.binance.com";
|
|
491
|
+
var PAY_REST_API_PROD_URL = "https://api.binance.com";
|
|
492
|
+
var REBATE_REST_API_PROD_URL = "https://api.binance.com";
|
|
493
|
+
var SIMPLE_EARN_REST_API_PROD_URL = "https://api.binance.com";
|
|
494
|
+
var SPOT_REST_API_PROD_URL = "https://api.binance.com";
|
|
495
|
+
var SPOT_REST_API_TESTNET_URL = "https://testnet.binance.vision";
|
|
496
|
+
var SPOT_WS_API_PROD_URL = "wss://ws-api.binance.com:443/ws-api/v3";
|
|
497
|
+
var SPOT_WS_API_TESTNET_URL = "wss://ws-api.testnet.binance.vision/ws-api/v3";
|
|
498
|
+
var SPOT_WS_STREAMS_PROD_URL = "wss://stream.binance.com:9443";
|
|
499
|
+
var SPOT_WS_STREAMS_TESTNET_URL = "wss://stream.testnet.binance.vision";
|
|
500
|
+
var SPOT_REST_API_MARKET_URL = "https://data-api.binance.vision";
|
|
501
|
+
var SPOT_WS_STREAMS_MARKET_URL = "wss://data-stream.binance.vision";
|
|
502
|
+
var STAKING_REST_API_PROD_URL = "https://api.binance.com";
|
|
503
|
+
var SUB_ACCOUNT_REST_API_PROD_URL = "https://api.binance.com";
|
|
504
|
+
var VIP_LOAN_REST_API_PROD_URL = "https://api.binance.com";
|
|
505
|
+
var WALLET_REST_API_PROD_URL = "https://api.binance.com";
|
|
506
|
+
|
|
507
|
+
// src/errors.ts
|
|
508
|
+
var ConnectorClientError = class _ConnectorClientError extends Error {
|
|
509
|
+
constructor(msg) {
|
|
510
|
+
super(msg || "An unexpected error occurred.");
|
|
511
|
+
Object.setPrototypeOf(this, _ConnectorClientError.prototype);
|
|
512
|
+
this.name = "ConnectorClientError";
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
var RequiredError = class _RequiredError extends Error {
|
|
516
|
+
constructor(field, msg) {
|
|
517
|
+
super(msg || `Required parameter ${field} was null or undefined.`);
|
|
518
|
+
this.field = field;
|
|
519
|
+
Object.setPrototypeOf(this, _RequiredError.prototype);
|
|
520
|
+
this.name = "RequiredError";
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
var UnauthorizedError = class _UnauthorizedError extends Error {
|
|
524
|
+
constructor(msg) {
|
|
525
|
+
super(msg || "Unauthorized access. Authentication required.");
|
|
526
|
+
Object.setPrototypeOf(this, _UnauthorizedError.prototype);
|
|
527
|
+
this.name = "UnauthorizedError";
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
var ForbiddenError = class _ForbiddenError extends Error {
|
|
531
|
+
constructor(msg) {
|
|
532
|
+
super(msg || "Access to the requested resource is forbidden.");
|
|
533
|
+
Object.setPrototypeOf(this, _ForbiddenError.prototype);
|
|
534
|
+
this.name = "ForbiddenError";
|
|
535
|
+
}
|
|
466
536
|
};
|
|
467
|
-
var
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
537
|
+
var TooManyRequestsError = class _TooManyRequestsError extends Error {
|
|
538
|
+
constructor(msg) {
|
|
539
|
+
super(msg || "Too many requests. You are being rate-limited.");
|
|
540
|
+
Object.setPrototypeOf(this, _TooManyRequestsError.prototype);
|
|
541
|
+
this.name = "TooManyRequestsError";
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
var RateLimitBanError = class _RateLimitBanError extends Error {
|
|
545
|
+
constructor(msg) {
|
|
546
|
+
super(msg || "The IP address has been banned for exceeding rate limits.");
|
|
547
|
+
Object.setPrototypeOf(this, _RateLimitBanError.prototype);
|
|
548
|
+
this.name = "RateLimitBanError";
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
var ServerError = class _ServerError extends Error {
|
|
552
|
+
constructor(msg, statusCode) {
|
|
553
|
+
super(msg || "An internal server error occurred.");
|
|
554
|
+
this.statusCode = statusCode;
|
|
555
|
+
Object.setPrototypeOf(this, _ServerError.prototype);
|
|
556
|
+
this.name = "ServerError";
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
var NetworkError = class _NetworkError extends Error {
|
|
560
|
+
constructor(msg) {
|
|
561
|
+
super(msg || "A network error occurred.");
|
|
562
|
+
Object.setPrototypeOf(this, _NetworkError.prototype);
|
|
563
|
+
this.name = "NetworkError";
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
var NotFoundError = class _NotFoundError extends Error {
|
|
567
|
+
constructor(msg) {
|
|
568
|
+
super(msg || "The requested resource was not found.");
|
|
569
|
+
Object.setPrototypeOf(this, _NotFoundError.prototype);
|
|
570
|
+
this.name = "NotFoundError";
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
var BadRequestError = class _BadRequestError extends Error {
|
|
574
|
+
constructor(msg) {
|
|
575
|
+
super(msg || "The request was invalid or cannot be otherwise served.");
|
|
576
|
+
Object.setPrototypeOf(this, _BadRequestError.prototype);
|
|
577
|
+
this.name = "BadRequestError";
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
// src/logger.ts
|
|
582
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
583
|
+
LogLevel2["NONE"] = "";
|
|
584
|
+
LogLevel2["DEBUG"] = "debug";
|
|
585
|
+
LogLevel2["INFO"] = "info";
|
|
586
|
+
LogLevel2["WARN"] = "warn";
|
|
587
|
+
LogLevel2["ERROR"] = "error";
|
|
588
|
+
return LogLevel2;
|
|
589
|
+
})(LogLevel || {});
|
|
590
|
+
var Logger = class _Logger {
|
|
591
|
+
constructor() {
|
|
592
|
+
this.minLogLevel = "info" /* INFO */;
|
|
593
|
+
this.levelsOrder = [
|
|
594
|
+
"" /* NONE */,
|
|
595
|
+
"debug" /* DEBUG */,
|
|
596
|
+
"info" /* INFO */,
|
|
597
|
+
"warn" /* WARN */,
|
|
598
|
+
"error" /* ERROR */
|
|
599
|
+
];
|
|
600
|
+
}
|
|
601
|
+
static getInstance() {
|
|
602
|
+
if (!_Logger.instance) {
|
|
603
|
+
_Logger.instance = new _Logger();
|
|
490
604
|
}
|
|
491
|
-
return
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
if (normalizedKey.startsWith("x-mbx-used-weight-")) {
|
|
497
|
-
const details = parseIntervalDetails(normalizedKey);
|
|
498
|
-
if (details) {
|
|
499
|
-
rateLimits.push({
|
|
500
|
-
rateLimitType: "REQUEST_WEIGHT",
|
|
501
|
-
interval: details.interval,
|
|
502
|
-
intervalNum: details.intervalNum,
|
|
503
|
-
count: parseInt(value, 10)
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
} else if (normalizedKey.startsWith("x-mbx-order-count-")) {
|
|
507
|
-
const details = parseIntervalDetails(normalizedKey);
|
|
508
|
-
if (details) {
|
|
509
|
-
rateLimits.push({
|
|
510
|
-
rateLimitType: "ORDERS",
|
|
511
|
-
interval: details.interval,
|
|
512
|
-
intervalNum: details.intervalNum,
|
|
513
|
-
count: parseInt(value, 10)
|
|
514
|
-
});
|
|
515
|
-
}
|
|
605
|
+
return _Logger.instance;
|
|
606
|
+
}
|
|
607
|
+
setMinLogLevel(level) {
|
|
608
|
+
if (!this.isValidLogLevel(level)) {
|
|
609
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
516
610
|
}
|
|
611
|
+
this.minLogLevel = level;
|
|
517
612
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
613
|
+
isValidLogLevel(level) {
|
|
614
|
+
return this.levelsOrder.includes(level);
|
|
615
|
+
}
|
|
616
|
+
log(level, ...message) {
|
|
617
|
+
if (level === "" /* NONE */ || !this.allowLevelLog(level)) {
|
|
618
|
+
return;
|
|
522
619
|
}
|
|
620
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
621
|
+
console[level](`[${timestamp}] [${level.toLowerCase()}]`, ...message);
|
|
523
622
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
const localVarUrlObj = new URL(endpoint, configuration?.basePath);
|
|
528
|
-
const localVarRequestOptions = {
|
|
529
|
-
method,
|
|
530
|
-
...configuration?.baseOptions
|
|
531
|
-
};
|
|
532
|
-
const localVarQueryParameter = { ...params };
|
|
533
|
-
if (options.isSigned) {
|
|
534
|
-
const timestamp = getTimestamp();
|
|
535
|
-
localVarQueryParameter["timestamp"] = timestamp;
|
|
536
|
-
const signature = getSignature(configuration, localVarQueryParameter);
|
|
537
|
-
if (signature) {
|
|
538
|
-
localVarQueryParameter["signature"] = signature;
|
|
623
|
+
allowLevelLog(level) {
|
|
624
|
+
if (!this.isValidLogLevel(level)) {
|
|
625
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
539
626
|
}
|
|
627
|
+
const currentLevelIndex = this.levelsOrder.indexOf(level);
|
|
628
|
+
const minLevelIndex = this.levelsOrder.indexOf(this.minLogLevel);
|
|
629
|
+
return currentLevelIndex >= minLevelIndex;
|
|
540
630
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
631
|
+
debug(...message) {
|
|
632
|
+
this.log("debug" /* DEBUG */, ...message);
|
|
633
|
+
}
|
|
634
|
+
info(...message) {
|
|
635
|
+
this.log("info" /* INFO */, ...message);
|
|
636
|
+
}
|
|
637
|
+
warn(...message) {
|
|
638
|
+
this.log("warn" /* WARN */, ...message);
|
|
639
|
+
}
|
|
640
|
+
error(...message) {
|
|
641
|
+
this.log("error" /* ERROR */, ...message);
|
|
548
642
|
}
|
|
549
|
-
return httpRequestFunction(
|
|
550
|
-
{
|
|
551
|
-
url: toPathString(localVarUrlObj),
|
|
552
|
-
options: localVarRequestOptions
|
|
553
|
-
},
|
|
554
|
-
configuration
|
|
555
|
-
);
|
|
556
643
|
};
|
|
557
|
-
function removeEmptyValue(obj) {
|
|
558
|
-
if (!(obj instanceof Object)) return {};
|
|
559
|
-
return Object.fromEntries(
|
|
560
|
-
Object.entries(obj).filter(
|
|
561
|
-
([, value]) => value !== null && value !== void 0 && value !== ""
|
|
562
|
-
)
|
|
563
|
-
);
|
|
564
|
-
}
|
|
565
|
-
function sortObject(obj) {
|
|
566
|
-
return Object.keys(obj).sort().reduce((res, key) => {
|
|
567
|
-
res[key] = obj[key];
|
|
568
|
-
return res;
|
|
569
|
-
}, {});
|
|
570
|
-
}
|
|
571
|
-
function replaceWebsocketStreamsPlaceholders(str, variables) {
|
|
572
|
-
const normalizedVariables = Object.keys(variables).reduce(
|
|
573
|
-
(acc, key) => {
|
|
574
|
-
const normalizedKey = key.toLowerCase().replace(/[-_]/g, "");
|
|
575
|
-
acc[normalizedKey] = variables[key];
|
|
576
|
-
return acc;
|
|
577
|
-
},
|
|
578
|
-
{}
|
|
579
|
-
);
|
|
580
|
-
return str.replace(/(@)?<([^>]+)>/g, (match, precedingAt, fieldName) => {
|
|
581
|
-
const normalizedFieldName = fieldName.toLowerCase().replace(/[-_]/g, "");
|
|
582
|
-
if (Object.prototype.hasOwnProperty.call(normalizedVariables, normalizedFieldName) && normalizedVariables[normalizedFieldName] != null) {
|
|
583
|
-
const value = normalizedVariables[normalizedFieldName];
|
|
584
|
-
switch (normalizedFieldName) {
|
|
585
|
-
case "symbol":
|
|
586
|
-
case "windowsize":
|
|
587
|
-
return value.toLowerCase();
|
|
588
|
-
case "updatespeed":
|
|
589
|
-
return `@${value}`;
|
|
590
|
-
default:
|
|
591
|
-
return (precedingAt || "") + value;
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
return "";
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
function buildUserAgent(packageName, packageVersion) {
|
|
598
|
-
return `${packageName}/${packageVersion} (Node.js/${process.version}; ${platform()}; ${arch()})`;
|
|
599
|
-
}
|
|
600
644
|
|
|
601
645
|
// src/websocket.ts
|
|
602
646
|
import { EventEmitter } from "events";
|
|
@@ -656,6 +700,20 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
656
700
|
});
|
|
657
701
|
}
|
|
658
702
|
}
|
|
703
|
+
/**
|
|
704
|
+
* Retrieves available WebSocket connections based on the connection mode and readiness.
|
|
705
|
+
* In 'single' mode, returns the first connection in the pool.
|
|
706
|
+
* In 'pool' mode, filters and returns connections that are ready for use.
|
|
707
|
+
* @param allowNonEstablishedWebsockets - Optional flag to include non-established WebSocket connections.
|
|
708
|
+
* @returns An array of available WebSocket connections.
|
|
709
|
+
*/
|
|
710
|
+
getAvailableConnections(allowNonEstablishedWebsockets = false) {
|
|
711
|
+
if (this.mode === "single") return [this.connectionPool[0]];
|
|
712
|
+
const availableConnections = this.connectionPool.filter(
|
|
713
|
+
(connection) => this.isConnectionReady(connection, allowNonEstablishedWebsockets)
|
|
714
|
+
);
|
|
715
|
+
return availableConnections;
|
|
716
|
+
}
|
|
659
717
|
/**
|
|
660
718
|
* Gets a WebSocket connection from the pool or single connection.
|
|
661
719
|
* If the connection mode is 'single', it returns the first connection in the pool.
|
|
@@ -665,10 +723,7 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
665
723
|
* @returns {WebsocketConnection} The selected WebSocket connection.
|
|
666
724
|
*/
|
|
667
725
|
getConnection(allowNonEstablishedWebsockets = false) {
|
|
668
|
-
|
|
669
|
-
const availableConnections = this.connectionPool.filter(
|
|
670
|
-
(connection) => this.isConnectionReady(connection, allowNonEstablishedWebsockets)
|
|
671
|
-
);
|
|
726
|
+
const availableConnections = this.getAvailableConnections(allowNonEstablishedWebsockets);
|
|
672
727
|
if (availableConnections.length === 0) {
|
|
673
728
|
throw new Error("No available Websocket connections are ready.");
|
|
674
729
|
}
|
|
@@ -788,6 +843,40 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
788
843
|
WebsocketConnectionToClose.close();
|
|
789
844
|
this.cleanup(WebsocketConnectionToClose);
|
|
790
845
|
}
|
|
846
|
+
/**
|
|
847
|
+
* Attempts to re-establish a session for a WebSocket connection.
|
|
848
|
+
* If a session logon request exists and the connection is not already logged on,
|
|
849
|
+
* it sends an authentication request and updates the connection's logged-on status.
|
|
850
|
+
* @param connection - The WebSocket connection to re-authenticate.
|
|
851
|
+
* @private
|
|
852
|
+
*/
|
|
853
|
+
async sessionReLogon(connection) {
|
|
854
|
+
const req = connection.sessionLogonReq;
|
|
855
|
+
if (req && !connection.isSessionLoggedOn) {
|
|
856
|
+
const data = buildWebsocketAPIMessage(
|
|
857
|
+
this.configuration,
|
|
858
|
+
req.method,
|
|
859
|
+
req.payload,
|
|
860
|
+
req.options
|
|
861
|
+
);
|
|
862
|
+
this.logger.debug(`Session re-logon with connection id: ${connection.id}`, data);
|
|
863
|
+
try {
|
|
864
|
+
await this.send(
|
|
865
|
+
JSON.stringify(data),
|
|
866
|
+
data.id,
|
|
867
|
+
true,
|
|
868
|
+
this.configuration.timeout,
|
|
869
|
+
connection
|
|
870
|
+
);
|
|
871
|
+
connection.isSessionLoggedOn = true;
|
|
872
|
+
} catch (err) {
|
|
873
|
+
this.logger.error(
|
|
874
|
+
`Session re-logon with connection id ${connection.id} failed:`,
|
|
875
|
+
err
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
791
880
|
/**
|
|
792
881
|
* Cleans up WebSocket connection resources.
|
|
793
882
|
* Removes all listeners and clears any associated timers for the provided WebSocket client.
|
|
@@ -812,8 +901,6 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
812
901
|
* Handles the opening of a WebSocket connection.
|
|
813
902
|
* @param url - The URL of the WebSocket server.
|
|
814
903
|
* @param targetConnection - The WebSocket connection being opened.
|
|
815
|
-
* @param oldConnection - The previous WebSocket connection, if this is a renewal.
|
|
816
|
-
* @param isRenewal - Indicates whether this is a connection renewal.
|
|
817
904
|
* @param oldWSConnection - The WebSocket client instance associated with the old connection.
|
|
818
905
|
*/
|
|
819
906
|
onOpen(url, targetConnection, oldWSConnection) {
|
|
@@ -828,6 +915,7 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
828
915
|
} else {
|
|
829
916
|
this.emit("open", this);
|
|
830
917
|
}
|
|
918
|
+
this.sessionReLogon(targetConnection);
|
|
831
919
|
}
|
|
832
920
|
/**
|
|
833
921
|
* Returns the URL to use when reconnecting.
|
|
@@ -898,10 +986,12 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
898
986
|
);
|
|
899
987
|
if (isRenewal) targetConnection.renewalPending = true;
|
|
900
988
|
else targetConnection.ws = ws;
|
|
989
|
+
targetConnection.isSessionLoggedOn = false;
|
|
901
990
|
this.scheduleTimer(
|
|
902
991
|
ws,
|
|
903
992
|
() => {
|
|
904
993
|
this.logger.info(`Renewing Websocket connection with id ${targetConnection.id}`);
|
|
994
|
+
targetConnection.isSessionLoggedOn = false;
|
|
905
995
|
this.enqueueReconnection(
|
|
906
996
|
targetConnection,
|
|
907
997
|
this.getReconnectURL(url, targetConnection),
|
|
@@ -945,6 +1035,7 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
945
1035
|
this.logger.info(
|
|
946
1036
|
`Reconnecting conection with id ${targetConnection.id} to the server.`
|
|
947
1037
|
);
|
|
1038
|
+
targetConnection.isSessionLoggedOn = false;
|
|
948
1039
|
targetConnection.reconnectionPending = true;
|
|
949
1040
|
this.enqueueReconnection(
|
|
950
1041
|
targetConnection,
|
|
@@ -980,6 +1071,8 @@ var WebsocketCommon = class _WebsocketCommon extends WebsocketEventEmitter {
|
|
|
980
1071
|
else {
|
|
981
1072
|
this.connectionPool.forEach((connection) => {
|
|
982
1073
|
connection.closeInitiated = true;
|
|
1074
|
+
connection.isSessionLoggedOn = false;
|
|
1075
|
+
connection.sessionLogonReq = void 0;
|
|
983
1076
|
});
|
|
984
1077
|
const disconnectPromises = this.connectionPool.map(
|
|
985
1078
|
(connection) => this.closeConnectionGracefully(connection.ws, connection)
|
|
@@ -1140,37 +1233,43 @@ var WebsocketAPIBase = class extends WebsocketCommon {
|
|
|
1140
1233
|
});
|
|
1141
1234
|
});
|
|
1142
1235
|
}
|
|
1143
|
-
|
|
1144
|
-
* Sends a message to the WebSocket API Server.
|
|
1145
|
-
* Supports both signed and unsigned messages.
|
|
1146
|
-
* @param method The API method to call
|
|
1147
|
-
* @param payload Message parameters and options
|
|
1148
|
-
* @param options Additional requests options (withApiKey, isSigned)
|
|
1149
|
-
* @returns Promise that resolves with the server response
|
|
1150
|
-
* @throws Error if not connected
|
|
1151
|
-
*/
|
|
1152
|
-
sendMessage(method, payload = {}, options = {}) {
|
|
1236
|
+
async sendMessage(method, payload = {}, options = {}) {
|
|
1153
1237
|
if (!this.isConnected()) {
|
|
1154
|
-
|
|
1155
|
-
}
|
|
1156
|
-
const id = payload.id && /^[0-9a-f]{32}$/.test(payload.id) ? payload.id : randomString();
|
|
1157
|
-
delete payload.id;
|
|
1158
|
-
let params = removeEmptyValue(payload);
|
|
1159
|
-
if (options.withApiKey || options.isSigned) {
|
|
1160
|
-
params.apiKey = this.configuration.apiKey;
|
|
1238
|
+
throw new Error("Not connected");
|
|
1161
1239
|
}
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
}
|
|
1167
|
-
const data = {
|
|
1168
|
-
id,
|
|
1240
|
+
const connections = options.isSessionLogon || options.isSessionLogout ? this.getAvailableConnections() : [this.getConnection()];
|
|
1241
|
+
const skipAuth = options.isSessionLogon || options.isSessionLogout ? false : this.configuration.autoSessionReLogon && connections[0].isSessionLoggedOn;
|
|
1242
|
+
const data = buildWebsocketAPIMessage(
|
|
1243
|
+
this.configuration,
|
|
1169
1244
|
method,
|
|
1170
|
-
|
|
1171
|
-
|
|
1245
|
+
payload,
|
|
1246
|
+
options,
|
|
1247
|
+
skipAuth
|
|
1248
|
+
);
|
|
1172
1249
|
this.logger.debug("Send message to Binance WebSocket API Server:", data);
|
|
1173
|
-
|
|
1250
|
+
const responses = await Promise.all(
|
|
1251
|
+
connections.map(
|
|
1252
|
+
(connection) => this.send(
|
|
1253
|
+
JSON.stringify(data),
|
|
1254
|
+
data.id,
|
|
1255
|
+
true,
|
|
1256
|
+
this.configuration.timeout,
|
|
1257
|
+
connection
|
|
1258
|
+
)
|
|
1259
|
+
)
|
|
1260
|
+
);
|
|
1261
|
+
if ((options.isSessionLogon || options.isSessionLogout) && this.configuration.autoSessionReLogon) {
|
|
1262
|
+
connections.forEach((connection) => {
|
|
1263
|
+
if (options.isSessionLogon) {
|
|
1264
|
+
connection.isSessionLoggedOn = true;
|
|
1265
|
+
connection.sessionLogonReq = { method, payload, options };
|
|
1266
|
+
} else {
|
|
1267
|
+
connection.isSessionLoggedOn = false;
|
|
1268
|
+
connection.sessionLogonReq = void 0;
|
|
1269
|
+
}
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
return connections.length === 1 ? responses[0] : responses;
|
|
1174
1273
|
}
|
|
1175
1274
|
};
|
|
1176
1275
|
var WebsocketStreamsBase = class extends WebsocketCommon {
|
|
@@ -1282,7 +1381,6 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
|
|
|
1282
1381
|
* @param url The URL of the WebSocket connection.
|
|
1283
1382
|
* @param targetConnection The WebSocket connection that was opened.
|
|
1284
1383
|
* @param oldConnection The previous WebSocket connection, if any.
|
|
1285
|
-
* @param isRenewal Whether the connection is a renewal of an existing connection.
|
|
1286
1384
|
*/
|
|
1287
1385
|
onOpen(url, targetConnection, oldWSConnection) {
|
|
1288
1386
|
this.processPendingSubscriptions(targetConnection);
|
|
@@ -1412,7 +1510,7 @@ export {
|
|
|
1412
1510
|
COPY_TRADING_REST_API_PROD_URL,
|
|
1413
1511
|
CRYPTO_LOAN_REST_API_PROD_URL,
|
|
1414
1512
|
ConfigurationRestAPI,
|
|
1415
|
-
ConfigurationWebsocketAPI,
|
|
1513
|
+
ConfigurationWebsocketAPI2 as ConfigurationWebsocketAPI,
|
|
1416
1514
|
ConfigurationWebsocketStreams,
|
|
1417
1515
|
ConnectorClientError,
|
|
1418
1516
|
DERIVATIVES_TRADING_COIN_FUTURES_REST_API_PROD_URL,
|
|
@@ -1424,8 +1522,11 @@ export {
|
|
|
1424
1522
|
DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL,
|
|
1425
1523
|
DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL,
|
|
1426
1524
|
DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_REST_API_PROD_URL,
|
|
1525
|
+
DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_WS_STREAMS_PROD_URL,
|
|
1427
1526
|
DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL,
|
|
1428
1527
|
DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_TESTNET_URL,
|
|
1528
|
+
DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_PROD_URL,
|
|
1529
|
+
DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_TESTNET_URL,
|
|
1429
1530
|
DERIVATIVES_TRADING_USDS_FUTURES_REST_API_PROD_URL,
|
|
1430
1531
|
DERIVATIVES_TRADING_USDS_FUTURES_REST_API_TESTNET_URL,
|
|
1431
1532
|
DERIVATIVES_TRADING_USDS_FUTURES_WS_API_PROD_URL,
|
|
@@ -1439,6 +1540,8 @@ export {
|
|
|
1439
1540
|
LogLevel,
|
|
1440
1541
|
Logger,
|
|
1441
1542
|
MARGIN_TRADING_REST_API_PROD_URL,
|
|
1543
|
+
MARGIN_TRADING_RISK_WS_STREAMS_PROD_URL,
|
|
1544
|
+
MARGIN_TRADING_WS_STREAMS_PROD_URL,
|
|
1442
1545
|
MINING_REST_API_PROD_URL,
|
|
1443
1546
|
NFT_REST_API_PROD_URL,
|
|
1444
1547
|
NetworkError,
|
|
@@ -1471,16 +1574,19 @@ export {
|
|
|
1471
1574
|
assertParamExists,
|
|
1472
1575
|
buildQueryString,
|
|
1473
1576
|
buildUserAgent,
|
|
1577
|
+
buildWebsocketAPIMessage,
|
|
1474
1578
|
clearSignerCache,
|
|
1475
1579
|
createStreamHandler,
|
|
1476
1580
|
delay,
|
|
1477
1581
|
getSignature,
|
|
1478
1582
|
getTimestamp,
|
|
1479
1583
|
httpRequestFunction,
|
|
1584
|
+
parseCustomHeaders,
|
|
1480
1585
|
parseRateLimitHeaders,
|
|
1481
1586
|
randomString,
|
|
1482
1587
|
removeEmptyValue,
|
|
1483
1588
|
replaceWebsocketStreamsPlaceholders,
|
|
1589
|
+
sanitizeHeaderValue,
|
|
1484
1590
|
sendRequest,
|
|
1485
1591
|
setFlattenedQueryParams,
|
|
1486
1592
|
setSearchParams,
|