@binance/common 1.0.6 → 1.1.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/dist/index.mjs CHANGED
@@ -249,6 +249,52 @@ import crypto from "crypto";
249
249
  import fs from "fs";
250
250
  import https from "https";
251
251
  import globalAxios from "axios";
252
+ var signerCache = /* @__PURE__ */ new WeakMap();
253
+ var RequestSigner = class {
254
+ constructor(configuration) {
255
+ if (configuration.apiSecret && !configuration.privateKey) {
256
+ this.apiSecret = configuration.apiSecret;
257
+ return;
258
+ }
259
+ if (configuration.privateKey) {
260
+ let privateKey = configuration.privateKey;
261
+ if (typeof privateKey === "string" && fs.existsSync(privateKey)) {
262
+ privateKey = fs.readFileSync(privateKey, "utf-8");
263
+ }
264
+ const keyInput = { key: privateKey };
265
+ if (configuration.privateKeyPassphrase && typeof configuration.privateKeyPassphrase === "string") {
266
+ keyInput.passphrase = configuration.privateKeyPassphrase;
267
+ }
268
+ try {
269
+ this.keyObject = crypto.createPrivateKey(keyInput);
270
+ this.keyType = this.keyObject.asymmetricKeyType;
271
+ } catch {
272
+ throw new Error(
273
+ "Invalid private key. Please provide a valid RSA or ED25519 private key."
274
+ );
275
+ }
276
+ return;
277
+ }
278
+ throw new Error("Either 'apiSecret' or 'privateKey' must be provided for signed requests.");
279
+ }
280
+ sign(queryParams) {
281
+ const params = buildQueryString(queryParams);
282
+ if (this.apiSecret)
283
+ return crypto.createHmac("sha256", this.apiSecret).update(params).digest("hex");
284
+ if (this.keyObject && this.keyType) {
285
+ const data = Buffer.from(params);
286
+ if (this.keyType === "rsa")
287
+ return crypto.sign("RSA-SHA256", data, this.keyObject).toString("base64");
288
+ if (this.keyType === "ed25519")
289
+ return crypto.sign(null, data, this.keyObject).toString("base64");
290
+ throw new Error("Unsupported private key type. Must be RSA or ED25519.");
291
+ }
292
+ throw new Error("Signer is not properly initialized.");
293
+ }
294
+ };
295
+ var clearSignerCache = function() {
296
+ signerCache = /* @__PURE__ */ new WeakMap();
297
+ };
252
298
  function buildQueryString(params) {
253
299
  if (!params) return "";
254
300
  return Object.entries(params).map(stringifyKeyValuePair).join("&");
@@ -275,39 +321,12 @@ function getTimestamp() {
275
321
  return Date.now();
276
322
  }
277
323
  var getSignature = function(configuration, queryParams) {
278
- const params = buildQueryString(queryParams);
279
- let signature = "";
280
- if (configuration?.apiSecret && !configuration?.privateKey) {
281
- signature = crypto.createHmac("sha256", configuration.apiSecret).update(params).digest("hex");
282
- } else if (configuration?.privateKey) {
283
- let privateKey = configuration.privateKey;
284
- if (typeof privateKey === "string" && fs.existsSync(privateKey)) {
285
- privateKey = fs.readFileSync(privateKey, "utf-8");
286
- }
287
- let keyObject;
288
- try {
289
- const privateKeyObj = { key: privateKey };
290
- if (configuration.privateKeyPassphrase && typeof configuration.privateKeyPassphrase === "string") {
291
- privateKeyObj.passphrase = configuration.privateKeyPassphrase;
292
- }
293
- keyObject = crypto.createPrivateKey(privateKeyObj);
294
- } catch {
295
- throw new Error(
296
- "Invalid private key. Please provide a valid RSA or ED25519 private key."
297
- );
298
- }
299
- const keyType = keyObject.asymmetricKeyType;
300
- if (keyType === "rsa") {
301
- signature = crypto.sign("RSA-SHA256", Buffer.from(params), keyObject).toString("base64");
302
- } else if (keyType === "ed25519") {
303
- signature = crypto.sign(null, Buffer.from(params), keyObject).toString("base64");
304
- } else {
305
- throw new Error("Unsupported private key type. Must be RSA or ED25519.");
306
- }
307
- } else {
308
- throw new Error("Either 'apiSecret' or 'privateKey' must be provided for signed requests.");
324
+ let signer = signerCache.get(configuration);
325
+ if (!signer) {
326
+ signer = new RequestSigner(configuration);
327
+ signerCache.set(configuration, signer);
309
328
  }
310
- return signature;
329
+ return signer.sign(queryParams);
311
330
  };
312
331
  var assertParamExists = function(functionName, paramName, paramValue) {
313
332
  if (paramValue === null || paramValue === void 0) {
@@ -319,25 +338,26 @@ var assertParamExists = function(functionName, paramName, paramValue) {
319
338
  };
320
339
  function setFlattenedQueryParams(urlSearchParams, parameter, key = "") {
321
340
  if (parameter == null) return;
341
+ if (Array.isArray(parameter)) {
342
+ if (key)
343
+ urlSearchParams.set(key, JSON.stringify(parameter));
344
+ else
345
+ for (const item of parameter) {
346
+ setFlattenedQueryParams(urlSearchParams, item, "");
347
+ }
348
+ return;
349
+ }
322
350
  if (typeof parameter === "object") {
323
- if (Array.isArray(parameter)) {
324
- parameter.forEach((item) => setFlattenedQueryParams(urlSearchParams, item, key));
325
- } else {
326
- Object.keys(parameter).forEach(
327
- (currentKey) => setFlattenedQueryParams(
328
- urlSearchParams,
329
- parameter[currentKey],
330
- `${key}${key !== "" ? "." : ""}${currentKey}`
331
- )
332
- );
333
- }
334
- } else {
335
- if (urlSearchParams.has(key)) {
336
- urlSearchParams.append(key, String(parameter));
337
- } else {
338
- urlSearchParams.set(key, String(parameter));
351
+ for (const subKey of Object.keys(parameter)) {
352
+ const subVal = parameter[subKey];
353
+ const newKey = key ? `${key}.${subKey}` : subKey;
354
+ setFlattenedQueryParams(urlSearchParams, subVal, newKey);
339
355
  }
356
+ return;
340
357
  }
358
+ const str = String(parameter);
359
+ if (urlSearchParams.has(key)) urlSearchParams.append(key, str);
360
+ else urlSearchParams.set(key, str);
341
361
  }
342
362
  var setSearchParams = function(url, ...objects) {
343
363
  const searchParams = new URLSearchParams(url.search);
@@ -359,18 +379,13 @@ var httpRequestFunction = async function(axiosArgs, configuration) {
359
379
  ...axiosArgs.options,
360
380
  url: (globalAxios.defaults?.baseURL ? "" : configuration?.basePath ?? "") + axiosArgs.url
361
381
  };
362
- if (configuration?.keepAlive) {
363
- axiosRequestArgs.httpsAgent = new https.Agent({
364
- ...configuration?.httpsAgent instanceof https.Agent ? configuration.httpsAgent.options : {},
365
- keepAlive: true
366
- });
367
- }
368
- if (configuration?.compression) {
382
+ if (configuration?.keepAlive && !configuration?.baseOptions?.httpsAgent)
383
+ axiosRequestArgs.httpsAgent = new https.Agent({ keepAlive: true });
384
+ if (configuration?.compression)
369
385
  axiosRequestArgs.headers = {
370
386
  ...axiosRequestArgs.headers,
371
387
  "Accept-Encoding": "gzip, deflate, br"
372
388
  };
373
- }
374
389
  const retries = configuration?.retries ?? 0;
375
390
  const backoff = configuration?.backoff ?? 0;
376
391
  let attempt = 0;
@@ -383,7 +398,13 @@ var httpRequestFunction = async function(axiosArgs, configuration) {
383
398
  });
384
399
  const rateLimits = parseRateLimitHeaders(response.headers);
385
400
  return {
386
- data: async () => JSON.parse(response.data),
401
+ data: async () => {
402
+ try {
403
+ return JSON.parse(response.data);
404
+ } catch (err) {
405
+ throw new Error(`Failed to parse JSON response: ${err}`);
406
+ }
407
+ },
387
408
  status: response.status,
388
409
  headers: response.headers,
389
410
  rateLimits
@@ -404,7 +425,11 @@ var httpRequestFunction = async function(axiosArgs, configuration) {
404
425
  let data = {};
405
426
  if (responseData && responseData !== null) {
406
427
  if (typeof responseData === "string" && responseData !== "")
407
- data = JSON.parse(responseData);
428
+ try {
429
+ data = JSON.parse(responseData);
430
+ } catch {
431
+ data = {};
432
+ }
408
433
  else if (typeof responseData === "object")
409
434
  data = responseData;
410
435
  }
@@ -1353,7 +1378,11 @@ function createStreamHandler(websocketBase, streamOrId, id) {
1353
1378
  return {
1354
1379
  on: (event, callback) => {
1355
1380
  if (event === "message") {
1356
- registeredCallback = (data) => callback(data);
1381
+ registeredCallback = (data) => {
1382
+ Promise.resolve(callback(data)).catch((err) => {
1383
+ websocketBase.logger.error(`Error in stream callback: ${err}`);
1384
+ });
1385
+ };
1357
1386
  const callbackSet = websocketBase.streamCallbackMap.get(streamOrId) ?? /* @__PURE__ */ new Set();
1358
1387
  callbackSet.add(registeredCallback);
1359
1388
  websocketBase.streamCallbackMap.set(streamOrId, callbackSet);
@@ -1434,6 +1463,7 @@ export {
1434
1463
  WebsocketStreamsBase,
1435
1464
  assertParamExists,
1436
1465
  buildQueryString,
1466
+ clearSignerCache,
1437
1467
  createStreamHandler,
1438
1468
  delay,
1439
1469
  getSignature,
@@ -1444,6 +1474,7 @@ export {
1444
1474
  removeEmptyValue,
1445
1475
  replaceWebsocketStreamsPlaceholders,
1446
1476
  sendRequest,
1477
+ setFlattenedQueryParams,
1447
1478
  setSearchParams,
1448
1479
  shouldRetryRequest,
1449
1480
  sortObject,