@binance/common 1.2.2 → 1.2.4
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.d.mts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +43 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +43 -29
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/configuration.ts","../src/constants.ts","../src/errors.ts","../src/logger.ts","../src/websocket.ts"],"sourcesContent":["export * from './configuration';\nexport * from './constants';\nexport * from './errors';\nexport * from './logger';\nexport * from './types';\nexport * from './utils';\nexport * from './websocket';\n","import crypto from 'crypto';\nimport fs from 'fs';\nimport https from 'https';\nimport { platform, arch } from 'os';\nimport {\n AxiosResponseHeaders,\n RawAxiosResponseHeaders,\n AxiosResponse,\n AxiosError,\n RawAxiosRequestConfig,\n} from 'axios';\nimport globalAxios from 'axios';\nimport {\n type ConfigurationRestAPI,\n type RestApiRateLimit,\n type RestApiResponse,\n TimeUnit,\n RequiredError,\n BadRequestError,\n ConnectorClientError,\n ForbiddenError,\n NetworkError,\n NotFoundError,\n RateLimitBanError,\n ServerError,\n TooManyRequestsError,\n UnauthorizedError,\n AxiosRequestArgs,\n SendMessageOptions,\n ObjectType,\n WebsocketSendMsgOptions,\n WebsocketSendMsgConfig,\n ConfigurationWebsocketAPI,\n Logger,\n} from '.';\n\n/**\n * A weak cache for storing RequestSigner instances based on configuration parameters.\n *\n * @remarks\n * Uses a WeakMap to cache and reuse RequestSigner instances for configurations with\n * apiSecret, privateKey, and privateKeyPassphrase, allowing efficient memory management.\n */\nlet signerCache = new WeakMap<\n {\n apiSecret?: string;\n privateKey?: string | Buffer;\n privateKeyPassphrase?: string;\n },\n RequestSigner\n>();\n\n/**\n * Represents a request signer for generating signatures using HMAC-SHA256 or asymmetric key signing.\n *\n * Supports two signing methods:\n * 1. HMAC-SHA256 using an API secret\n * 2. Asymmetric signing using RSA or ED25519 private keys\n *\n * @throws {Error} If neither API secret nor private key is provided, or if the private key is invalid\n */\nclass RequestSigner {\n private apiSecret?: string;\n private keyObject?: crypto.KeyObject;\n private keyType?: string;\n\n constructor(configuration: {\n apiSecret?: string;\n privateKey?: string | Buffer;\n privateKeyPassphrase?: string;\n }) {\n // HMAC-SHA256 path\n if (configuration.apiSecret && !configuration.privateKey) {\n this.apiSecret = configuration.apiSecret;\n return;\n }\n\n // Asymmetric path\n if (configuration.privateKey) {\n let privateKey: string | Buffer = configuration.privateKey;\n\n // If path, read file once\n if (typeof privateKey === 'string' && fs.existsSync(privateKey)) {\n privateKey = fs.readFileSync(privateKey, 'utf-8');\n }\n\n // Build KeyObject once\n const keyInput: crypto.PrivateKeyInput = { key: privateKey };\n if (\n configuration.privateKeyPassphrase &&\n typeof configuration.privateKeyPassphrase === 'string'\n ) {\n keyInput.passphrase = configuration.privateKeyPassphrase;\n }\n\n try {\n this.keyObject = crypto.createPrivateKey(keyInput);\n this.keyType = this.keyObject.asymmetricKeyType;\n } catch {\n throw new Error(\n 'Invalid private key. Please provide a valid RSA or ED25519 private key.'\n );\n }\n\n return;\n }\n\n throw new Error('Either \\'apiSecret\\' or \\'privateKey\\' must be provided for signed requests.');\n }\n\n sign(queryParams: object): string {\n const params = buildQueryString(queryParams);\n\n // HMAC-SHA256 signing\n if (this.apiSecret)\n return crypto.createHmac('sha256', this.apiSecret).update(params).digest('hex');\n\n // Asymmetric signing\n if (this.keyObject && this.keyType) {\n const data = Buffer.from(params);\n\n if (this.keyType === 'rsa')\n return crypto.sign('RSA-SHA256', data, this.keyObject).toString('base64');\n if (this.keyType === 'ed25519')\n return crypto.sign(null, data, this.keyObject).toString('base64');\n\n throw new Error('Unsupported private key type. Must be RSA or ED25519.');\n }\n\n throw new Error('Signer is not properly initialized.');\n }\n}\n\n/**\n * Resets the signer cache to a new empty WeakMap.\n *\n * This function clears the existing signer cache, creating a fresh WeakMap\n * to store RequestSigner instances associated with configuration objects.\n */\nexport const clearSignerCache = function (): void {\n signerCache = new WeakMap<\n {\n apiSecret?: string;\n privateKey?: string | Buffer;\n privateKeyPassphrase?: string;\n },\n RequestSigner\n >();\n};\n\n/**\n * Generates a query string from an object of parameters.\n *\n * @param params - An object containing the query parameters.\n * @returns The generated query string.\n */\nexport function buildQueryString(params: object): string {\n if (!params) return '';\n return Object.entries(params).map(stringifyKeyValuePair).join('&');\n}\n\n/**\n * Converts a key-value pair into a URL-encoded query parameter string.\n *\n * @param [key, value] - The key-value pair to be converted.\n * @returns The URL-encoded query parameter string.\n */\nfunction stringifyKeyValuePair([key, value]: [string, string]) {\n const valueString = Array.isArray(value) ? `[\"${value.join('\",\"')}\"]` : value;\n return `${key}=${encodeURIComponent(valueString)}`;\n}\n\n/**\n * Generates a random string of 16 hexadecimal characters.\n *\n * @returns A random string of 16 hexadecimal characters.\n */\nexport function randomString() {\n return crypto.randomBytes(16).toString('hex');\n}\n\n/**\n * Validates the provided time unit string and returns it if it is either 'MILLISECOND' or 'MICROSECOND'.\n *\n * @param timeUnit - The time unit string to be validated.\n * @returns The validated time unit string, or `undefined` if the input is falsy.\n * @throws {Error} If the time unit is not 'MILLISECOND' or 'MICROSECOND'.\n */\nexport function validateTimeUnit(timeUnit: string): string | undefined {\n if (!timeUnit) {\n return;\n } else if (\n timeUnit !== TimeUnit.MILLISECOND &&\n timeUnit !== TimeUnit.MICROSECOND &&\n timeUnit !== TimeUnit.millisecond &&\n timeUnit !== TimeUnit.microsecond\n ) {\n throw new Error('timeUnit must be either \\'MILLISECOND\\' or \\'MICROSECOND\\'');\n }\n\n return timeUnit;\n}\n\n/**\n * Delays the execution of the current function for the specified number of milliseconds.\n *\n * @param ms - The number of milliseconds to delay the function.\n * @returns A Promise that resolves after the specified delay.\n */\nexport async function delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Generates the current timestamp in milliseconds.\n *\n * @returns The current timestamp in milliseconds.\n */\nexport function getTimestamp(): number {\n return Date.now();\n}\n\n/**\n * Generates a signature for the given configuration and query parameters using a cached request signer.\n *\n * @param configuration - Configuration object containing API secret, private key, and optional passphrase.\n * @param queryParams - The query parameters to be signed.\n * @returns A string representing the generated signature.\n */\nexport const getSignature = function (\n configuration: {\n apiSecret?: string;\n privateKey?: string | Buffer;\n privateKeyPassphrase?: string;\n },\n queryParams: object\n): string {\n let signer = signerCache.get(configuration);\n if (!signer) {\n signer = new RequestSigner(configuration);\n signerCache.set(configuration, signer);\n }\n return signer.sign(queryParams);\n};\n\n/**\n * Asserts that a function parameter exists and is not null or undefined.\n *\n * @param functionName - The name of the function that the parameter belongs to.\n * @param paramName - The name of the parameter to check.\n * @param paramValue - The value of the parameter to check.\n * @throws {RequiredError} If the parameter is null or undefined.\n */\nexport const assertParamExists = function (\n functionName: string,\n paramName: string,\n paramValue: unknown\n) {\n if (paramValue === null || paramValue === undefined) {\n throw new RequiredError(\n paramName,\n `Required parameter ${paramName} was null or undefined when calling ${functionName}.`\n );\n }\n};\n\n/**\n * Recursively flattens an object or array into URL search parameters.\n *\n * This function handles nested objects and arrays by converting them into dot-notation query parameters.\n * It supports different types of parameters:\n * - Arrays can be stringified or recursively added\n * - Objects are flattened with dot notation keys\n * - Primitive values are converted to strings\n *\n * @param urlSearchParams The URLSearchParams object to modify\n * @param parameter The parameter to flatten (can be an object, array, or primitive)\n * @param key Optional key for nested parameters, used for creating dot-notation keys\n */\nexport function setFlattenedQueryParams(\n urlSearchParams: URLSearchParams,\n parameter: unknown,\n key: string = ''\n): void {\n if (parameter == null) return;\n\n // Array handling\n if (Array.isArray(parameter)) {\n if (key)\n // non-empty key: stringify the entire array\n urlSearchParams.set(key, JSON.stringify(parameter));\n else\n // empty key: recurse into each item without using an empty key\n for (const item of parameter) {\n setFlattenedQueryParams(urlSearchParams, item, '');\n }\n return;\n }\n\n // Object handling\n if (typeof parameter === 'object') {\n for (const subKey of Object.keys(parameter as Record<string, unknown>)) {\n const subVal = (parameter as Record<string, unknown>)[subKey];\n const newKey = key ? `${key}.${subKey}` : subKey;\n setFlattenedQueryParams(urlSearchParams, subVal, newKey);\n }\n return;\n }\n\n // Primitive handling\n const str = String(parameter);\n if (urlSearchParams.has(key)) urlSearchParams.append(key, str);\n else urlSearchParams.set(key, str);\n}\n\n/**\n * Sets the search parameters of the provided URL by flattening the given objects into the URL's search parameters.\n *\n * This function takes a URL and one or more objects, and updates the URL's search parameters by flattening the objects into key-value pairs. It uses the `setFlattenedQueryParams` function to recursively flatten the objects.\n *\n * @param url - The URL to update the search parameters for.\n * @param objects - One or more objects to flatten into the URL's search parameters.\n */\nexport const setSearchParams = function (url: URL, ...objects: Record<string, unknown>[]) {\n const searchParams = new URLSearchParams(url.search);\n setFlattenedQueryParams(searchParams, objects);\n url.search = searchParams.toString();\n};\n\n/**\n * Converts a URL object to a full path string, including pathname, search parameters, and hash.\n *\n * @param url The URL object to convert to a path string.\n * @returns A complete path string representation of the URL.\n */\nexport const toPathString = function (url: URL) {\n return url.pathname + url.search + url.hash;\n};\n\n/**\n * A type utility that transforms numbers in a type to their string representation when in scientific notation,\n * while preserving the structure of arrays and objects.\n *\n * @template T The input type to be transformed\n * @returns A type where numbers potentially become strings, maintaining the original type's structure\n */\ntype ScientificToString<T> = T extends number\n ? string | number\n : T extends Array<infer U>\n ? Array<ScientificToString<U>>\n : T extends object\n ? { [K in keyof T]: ScientificToString<T[K]> }\n : T;\n\n/**\n * Normalizes scientific notation numbers in an object or array to a fixed number of decimal places.\n *\n * This function recursively processes objects, arrays, and numbers, converting scientific notation\n * to a fixed decimal representation. Non-numeric values are left unchanged.\n *\n * @template T The type of the input object or value\n * @param obj The object, array, or value to normalize\n * @returns A new object or value with scientific notation numbers normalized\n */\nexport function normalizeScientificNumbers<T>(obj: T): ScientificToString<T> {\n if (Array.isArray(obj)) {\n return obj.map((item) => normalizeScientificNumbers(item)) as ScientificToString<T>;\n } else if (typeof obj === 'object' && obj !== null) {\n const result = {} as Record<string, unknown>;\n for (const key of Object.keys(obj)) {\n result[key] = normalizeScientificNumbers((obj as Record<string, unknown>)[key]);\n }\n return result as ScientificToString<T>;\n } else if (typeof obj === 'number') {\n if (!Number.isFinite(obj)) return obj as ScientificToString<T>;\n\n const abs = Math.abs(obj);\n if (abs === 0 || (abs >= 1e-6 && abs < 1e21)) return String(obj) as ScientificToString<T>;\n\n const isNegative = obj < 0;\n const [rawMantissa, rawExponent] = abs.toExponential().split('e');\n const exponent = +rawExponent;\n const digits = rawMantissa.replace('.', '');\n\n if (exponent < 0) {\n const zeros = '0'.repeat(Math.abs(exponent) - 1);\n return ((isNegative ? '-' : '') + '0.' + zeros + digits) as ScientificToString<T>;\n } else {\n const pad = exponent - (digits.length - 1);\n\n if (pad >= 0) {\n return ((isNegative ? '-' : '') +\n digits +\n '0'.repeat(pad)) as ScientificToString<T>;\n } else {\n const point = digits.length + pad;\n return ((isNegative ? '-' : '') +\n digits.slice(0, point) +\n '.' +\n digits.slice(point)) as ScientificToString<T>;\n }\n }\n } else {\n return obj as ScientificToString<T>;\n }\n}\n\n/**\n * Determines whether a request should be retried based on the provided error.\n *\n * This function checks the HTTP method, response status, and number of retries left to determine if a request should be retried.\n *\n * @param error The error object to check.\n * @param method The HTTP method of the request (optional).\n * @param retriesLeft The number of retries left (optional).\n * @returns `true` if the request should be retried, `false` otherwise.\n */\nexport const shouldRetryRequest = function (\n error: AxiosError | object,\n method?: string,\n retriesLeft?: number\n): boolean {\n const isRetriableMethod = ['GET', 'DELETE'].includes(method ?? '');\n const isRetriableStatus = [500, 502, 503, 504].includes(\n (error as AxiosError)?.response?.status ?? 0\n );\n return (\n (retriesLeft ?? 0) > 0 &&\n isRetriableMethod &&\n (isRetriableStatus || !(error as AxiosError)?.response)\n );\n};\n\n/**\n * Performs an HTTP request using the provided Axios instance and configuration.\n *\n * This function handles retries, rate limit handling, and error handling for the HTTP request.\n *\n * @param axiosArgs The request arguments to be passed to Axios.\n * @param configuration The configuration options for the request.\n * @returns A Promise that resolves to the API response, including the data and rate limit headers.\n */\nexport const httpRequestFunction = async function <T>(\n axiosArgs: AxiosRequestArgs,\n configuration?: ConfigurationRestAPI\n): Promise<RestApiResponse<T>> {\n const axiosRequestArgs = {\n ...axiosArgs.options,\n url: (globalAxios.defaults?.baseURL ? '' : (configuration?.basePath ?? '')) + axiosArgs.url,\n };\n\n if (configuration?.keepAlive && !configuration?.baseOptions?.httpsAgent)\n axiosRequestArgs.httpsAgent = new https.Agent({ keepAlive: true });\n\n if (configuration?.compression)\n axiosRequestArgs.headers = {\n ...axiosRequestArgs.headers,\n 'Accept-Encoding': 'gzip, deflate, br',\n };\n\n const retries = configuration?.retries ?? 0;\n const backoff = configuration?.backoff ?? 0;\n let attempt = 0;\n let lastError;\n\n while (attempt <= retries) {\n try {\n const response: AxiosResponse = await globalAxios.request({\n ...axiosRequestArgs,\n responseType: 'text',\n });\n const rateLimits: RestApiRateLimit[] = parseRateLimitHeaders(response.headers);\n return {\n data: async (): Promise<T> => {\n try {\n return JSON.parse(response.data) as T;\n } catch (err) {\n throw new Error(`Failed to parse JSON response: ${err}`);\n }\n },\n status: response.status,\n headers: response.headers as Record<string, string>,\n rateLimits,\n };\n } catch (error) {\n attempt++;\n const axiosError = error as AxiosError;\n\n if (\n shouldRetryRequest(\n axiosError,\n axiosRequestArgs?.method?.toUpperCase(),\n retries - attempt\n )\n ) {\n await delay(backoff * attempt);\n } else {\n if (axiosError.response && axiosError.response.status) {\n const status = axiosError.response?.status;\n const responseData = axiosError.response.data;\n\n let data: Record<string, unknown> = {};\n if (responseData && responseData !== null) {\n if (typeof responseData === 'string' && responseData !== '')\n try {\n data = JSON.parse(responseData);\n } catch {\n data = {};\n }\n else if (typeof responseData === 'object')\n data = responseData as Record<string, unknown>;\n }\n\n const errorMsg = (data as { msg?: string }).msg;\n\n switch (status) {\n case 400:\n throw new BadRequestError(errorMsg);\n case 401:\n throw new UnauthorizedError(errorMsg);\n case 403:\n throw new ForbiddenError(errorMsg);\n case 404:\n throw new NotFoundError(errorMsg);\n case 418:\n throw new RateLimitBanError(errorMsg);\n case 429:\n throw new TooManyRequestsError(errorMsg);\n default:\n if (status >= 500 && status < 600)\n throw new ServerError(`Server error: ${status}`, status);\n throw new ConnectorClientError(errorMsg);\n }\n } else {\n if (retries > 0 && attempt >= retries)\n lastError = new Error(`Request failed after ${retries} retries`);\n else lastError = new NetworkError('Network error or request timeout.');\n\n break;\n }\n }\n }\n }\n\n throw lastError;\n};\n\n/**\n * Parses the rate limit headers from the Axios response headers and returns an array of `RestApiRateLimit` objects.\n *\n * @param headers - The Axios response headers.\n * @returns An array of `RestApiRateLimit` objects containing the parsed rate limit information.\n */\nexport const parseRateLimitHeaders = function (\n headers: RawAxiosResponseHeaders | AxiosResponseHeaders\n): RestApiRateLimit[] {\n const rateLimits: RestApiRateLimit[] = [];\n\n const parseIntervalDetails = (\n key: string\n ): { interval: 'SECOND' | 'MINUTE' | 'HOUR' | 'DAY'; intervalNum: number } | null => {\n const match = key.match(/x-mbx-used-weight-(\\d+)([smhd])|x-mbx-order-count-(\\d+)([smhd])/i);\n if (!match) return null;\n\n const intervalNum = parseInt(match[1] || match[3], 10);\n const intervalLetter = (match[2] || match[4])?.toUpperCase();\n\n let interval: 'SECOND' | 'MINUTE' | 'HOUR' | 'DAY';\n switch (intervalLetter) {\n case 'S':\n interval = 'SECOND';\n break;\n case 'M':\n interval = 'MINUTE';\n break;\n case 'H':\n interval = 'HOUR';\n break;\n case 'D':\n interval = 'DAY';\n break;\n default:\n return null;\n }\n\n return { interval, intervalNum };\n };\n\n for (const [key, value] of Object.entries(headers)) {\n const normalizedKey = key.toLowerCase();\n if (value === undefined) continue;\n\n if (normalizedKey.startsWith('x-mbx-used-weight-')) {\n const details = parseIntervalDetails(normalizedKey);\n if (details) {\n rateLimits.push({\n rateLimitType: 'REQUEST_WEIGHT',\n interval: details.interval,\n intervalNum: details.intervalNum,\n count: parseInt(value, 10),\n });\n }\n } else if (normalizedKey.startsWith('x-mbx-order-count-')) {\n const details = parseIntervalDetails(normalizedKey);\n if (details) {\n rateLimits.push({\n rateLimitType: 'ORDERS',\n interval: details.interval,\n intervalNum: details.intervalNum,\n count: parseInt(value, 10),\n });\n }\n }\n }\n\n if (headers['retry-after']) {\n const retryAfter = parseInt(headers['retry-after'], 10);\n for (const limit of rateLimits) {\n limit.retryAfter = retryAfter;\n }\n }\n\n return rateLimits;\n};\n\n/**\n * Generic function to send a request with optional API key and signature.\n * @param endpoint - The API endpoint to call.\n * @param method - HTTP method to use (GET, POST, DELETE, etc.).\n * @param params - Query parameters for the request.\n * @param timeUnit - The time unit for the request.\n * @param options - Additional request options (isSigned).\n * @returns A promise resolving to the response data object.\n */\nexport const sendRequest = function <T>(\n configuration: ConfigurationRestAPI,\n endpoint: string,\n method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH',\n params: Record<string, unknown> = {},\n timeUnit?: TimeUnit,\n options: { isSigned?: boolean } = {}\n): Promise<RestApiResponse<T>> {\n const localVarUrlObj = new URL(endpoint, configuration?.basePath);\n const localVarRequestOptions: RawAxiosRequestConfig = {\n method,\n ...configuration?.baseOptions,\n };\n const localVarQueryParameter = { ...normalizeScientificNumbers(params) };\n\n if (options.isSigned) {\n const timestamp = getTimestamp();\n localVarQueryParameter['timestamp'] = timestamp;\n const signature = getSignature(configuration!, localVarQueryParameter);\n if (signature) {\n localVarQueryParameter['signature'] = signature;\n }\n }\n\n setSearchParams(localVarUrlObj, localVarQueryParameter);\n\n if (timeUnit && localVarRequestOptions.headers) {\n const _timeUnit = validateTimeUnit(timeUnit);\n localVarRequestOptions.headers = {\n ...localVarRequestOptions.headers,\n 'X-MBX-TIME-UNIT': _timeUnit,\n };\n }\n\n return httpRequestFunction<T>(\n {\n url: toPathString(localVarUrlObj),\n options: localVarRequestOptions,\n },\n configuration\n );\n};\n\n/**\n * Removes any null, undefined, or empty string values from the provided object.\n *\n * @param obj - The object to remove empty values from.\n * @returns A new object with empty values removed.\n */\nexport function removeEmptyValue(obj: object): SendMessageOptions {\n if (!(obj instanceof Object)) return {};\n return Object.fromEntries(\n Object.entries(obj).filter(\n ([, value]) => value !== null && value !== undefined && value !== ''\n )\n );\n}\n\n/**\n * Sorts the properties of the provided object in alphabetical order and returns a new object with the sorted properties.\n *\n * @param obj - The object to be sorted.\n * @returns A new object with the properties sorted in alphabetical order.\n */\nexport function sortObject(obj: ObjectType) {\n return Object.keys(obj)\n .sort()\n .reduce((res: ObjectType, key: string) => {\n res[key] = obj[key] as string | number | boolean | object;\n return res;\n }, {});\n}\n\n/**\n * Replaces placeholders in the format <field> with corresponding values from the provided variables object.\n *\n * @param {string} str - The input string containing placeholders.\n * @param {Object} variables - An object where keys correspond to placeholder names and values are the replacements.\n * @returns {string} - The resulting string with placeholders replaced by their corresponding values.\n */\nexport function replaceWebsocketStreamsPlaceholders(\n str: string,\n variables: Record<string, unknown>\n): string {\n const normalizedVariables = Object.keys(variables).reduce(\n (acc, key) => {\n const normalizedKey = key.toLowerCase().replace(/[-_]/g, '');\n acc[normalizedKey] = variables[key];\n return acc;\n },\n {} as Record<string, unknown>\n );\n\n return str.replace(/(@)?<([^>]+)>/g, (match, precedingAt, fieldName) => {\n const normalizedFieldName = fieldName.toLowerCase().replace(/[-_]/g, '');\n\n if (\n Object.prototype.hasOwnProperty.call(normalizedVariables, normalizedFieldName) &&\n normalizedVariables[normalizedFieldName] != null\n ) {\n const value = normalizedVariables[normalizedFieldName];\n\n switch (normalizedFieldName) {\n case 'symbol':\n case 'windowsize':\n return (value as string).toLowerCase();\n case 'updatespeed':\n return `@${value}`;\n default:\n return (precedingAt || '') + (value as string);\n }\n }\n\n return '';\n });\n}\n\n/**\n * Generates a standardized user agent string for the application.\n *\n * @param {string} packageName - The name of the package/application.\n * @param {string} packageVersion - The version of the package/application.\n * @returns {string} A formatted user agent string including package details, Node.js version, platform, and architecture.\n */\nexport function buildUserAgent(packageName: string, packageVersion: string): string {\n return `${packageName}/${packageVersion} (Node.js/${process.version}; ${platform()}; ${arch()})`;\n}\n\n/**\n * Builds a WebSocket API message with optional authentication and signature.\n *\n * @param {ConfigurationWebsocketAPI} configuration - The WebSocket API configuration.\n * @param {string} method - The method name for the WebSocket message.\n * @param {WebsocketSendMsgOptions} payload - The payload data to be sent.\n * @param {WebsocketSendMsgConfig} options - Configuration options for message sending.\n * @param {boolean} [skipAuth=false] - Flag to skip authentication if needed.\n * @returns {Object} A structured WebSocket message with id, method, and params.\n */\nexport function buildWebsocketAPIMessage(\n configuration: ConfigurationWebsocketAPI,\n method: string,\n payload: WebsocketSendMsgOptions,\n options: WebsocketSendMsgConfig,\n skipAuth: boolean = false\n): { id: string; method: string; params: Record<string, unknown> } {\n const id = payload.id && /^[0-9a-f]{32}$/.test(payload.id) ? payload.id : randomString();\n delete payload.id;\n\n let params = normalizeScientificNumbers(removeEmptyValue(payload));\n if ((options.withApiKey || options.isSigned) && !skipAuth) params.apiKey = configuration.apiKey;\n\n if (options.isSigned) {\n params.timestamp = getTimestamp();\n params = sortObject(params as ObjectType);\n if (!skipAuth) params.signature = getSignature(configuration!, params);\n }\n\n return { id, method, params };\n}\n\n/**\n * Sanitizes a header value by checking for and preventing carriage return and line feed characters.\n *\n * @param {string | string[]} value - The header value or array of header values to sanitize.\n * @returns {string | string[]} The sanitized header value(s).\n * @throws {Error} If the header value contains CR/LF characters.\n */\nexport function sanitizeHeaderValue(value: string | string[]): string | string[] {\n const sanitizeOne = (v: string) => {\n if (/\\r|\\n/.test(v)) throw new Error(`Invalid header value (contains CR/LF): \"${v}\"`);\n return v;\n };\n\n return Array.isArray(value) ? value.map(sanitizeOne) : sanitizeOne(value);\n}\n\n/**\n * Parses and sanitizes custom headers, filtering out forbidden headers.\n *\n * @param {Record<string, string | string[]>} headers - The input headers to be parsed.\n * @returns {Record<string, string | string[]>} A new object with sanitized and allowed headers.\n * @description Removes forbidden headers like 'host', 'authorization', and 'cookie',\n * and sanitizes remaining header values to prevent injection of carriage return or line feed characters.\n */\nexport function parseCustomHeaders(\n headers: Record<string, string | string[]>\n): Record<string, string | string[]> {\n if (!headers || Object.keys(headers).length === 0) return {};\n\n const forbidden = new Set(['host', 'authorization', 'cookie', ':method', ':path']);\n const parsedHeaders: Record<string, string | string[]> = {};\n\n for (const [rawName, rawValue] of Object.entries(headers || {})) {\n const name = rawName.trim();\n if (forbidden.has(name.toLowerCase())) {\n Logger.getInstance().warn(`Dropping forbidden header: ${name}`);\n continue;\n }\n\n try {\n parsedHeaders[name] = sanitizeHeaderValue(rawValue);\n } catch {\n continue;\n }\n }\n\n return parsedHeaders;\n}\n","import { Agent } from 'https';\nimport type { TimeUnit } from './constants';\nimport { parseCustomHeaders } from './utils';\n\nexport class ConfigurationRestAPI {\n /**\n * The API key used for authentication.\n * @memberof ConfigurationRestAPI\n */\n apiKey: string;\n /**\n * The API secret used for authentication.\n * @memberof ConfigurationRestAPI\n */\n apiSecret?: string;\n /**\n * override base path\n * @type {string}\n * @memberof ConfigurationRestAPI\n */\n basePath?: string;\n /**\n * set a timeout (in milliseconds) for the request\n * @default 1000\n * @type {number}\n * @memberof ConfigurationRestAPI\n */\n timeout?: number;\n /**\n * HTTP/HTTPS proxy configuration\n * @default false\n * @type {object}\n * @property {string} host - Proxy server hostname\n * @property {number} port - Proxy server port number\n * @property {string} protocol - Proxy server protocol\n * @property {object} [auth] - Proxy authentication credentials\n * @property {string} auth.username - Proxy authentication username\n * @property {string} auth.password - Proxy authentication password\n * @memberof ConfigurationRestAPI\n */\n proxy?: {\n host: string;\n port: number;\n protocol?: string;\n auth?: { username: string; password: string };\n };\n /**\n * Optional custom headers to be sent with the request\n * @default {}\n * @type {Record<string, string | string[]>}\n * @memberof ConfigurationRestAPI\n */\n customHeaders?: Record<string, string | string[]>;\n /**\n * enables keep-alive functionality for the connection (if httpsAgent is set then we use httpsAgent.keepAlive instead)\n * @default true\n * @type {boolean}\n * @memberof ConfigurationRestAPI\n */\n keepAlive?: boolean;\n /**\n * enables response compression\n * @default true\n * @type {boolean}\n * @memberof ConfigurationRestAPI\n */\n compression?: boolean;\n /**\n * number of retry attempts for failed requests\n * @default 3\n * @type {number}\n * @memberof ConfigurationRestAPI\n */\n retries?: number;\n /**\n * delay between retry attempts in milliseconds\n * @default 1000\n * @type {number}\n * @memberof ConfigurationRestAPI\n */\n backoff?: number;\n /**\n * https agent\n * @default false\n * @type {boolean | Agent}\n * @memberof ConfigurationRestAPI\n */\n httpsAgent?: boolean | Agent;\n /**\n * private key\n * @type {string | Buffer}\n * @memberof ConfigurationRestAPI\n */\n privateKey?: string | Buffer;\n /**\n * private key passphrase\n * @type {string}\n * @memberof ConfigurationRestAPI\n */\n privateKeyPassphrase?: string;\n /**\n * timeUnit (used only on SPOT API)\n * @type {TimeUnit}\n * @memberof ConfigurationRestAPI\n */\n timeUnit?: TimeUnit;\n /**\n * base options for axios calls\n * @type {Record<string, unknown>}\n * @memberof ConfigurationRestAPI\n * @internal\n */\n baseOptions?: Record<string, unknown>;\n\n constructor(param: ConfigurationRestAPI = { apiKey: '' }) {\n this.apiKey = param.apiKey;\n this.apiSecret = param.apiSecret;\n this.basePath = param.basePath;\n this.keepAlive = param.keepAlive ?? true;\n this.compression = param.compression ?? true;\n this.retries = param.retries ?? 3;\n this.backoff = param.backoff ?? 1000;\n this.privateKey = param.privateKey;\n this.privateKeyPassphrase = param.privateKeyPassphrase;\n this.timeUnit = param.timeUnit;\n this.baseOptions = {\n timeout: param.timeout ?? 1000,\n proxy: param.proxy && {\n host: param.proxy.host,\n port: param.proxy.port,\n auth: param.proxy.auth,\n },\n httpsAgent: param.httpsAgent ?? false,\n headers: {\n ...parseCustomHeaders(param.customHeaders || {}),\n 'Content-Type': 'application/json',\n 'X-MBX-APIKEY': param.apiKey,\n },\n };\n }\n}\n\nexport class ConfigurationWebsocketAPI {\n /**\n * The API key used for authentication.\n * @memberof ConfigurationWebsocketAPI\n */\n apiKey: string;\n /**\n * The API secret used for authentication.\n * @memberof ConfigurationWebsocketAPI\n */\n apiSecret?: string;\n /**\n * override websocket url\n * @type {string}\n * @memberof ConfigurationWebsocketAPI\n */\n wsURL?: string;\n /**\n * set a timeout (in milliseconds) for the request\n * @default 5000\n * @type {number}\n * @memberof ConfigurationWebsocketAPI\n */\n timeout?: number;\n /**\n * reconnction delay\n * @default 5000\n * @type {number}\n * @memberof ConfigurationWebsocketAPI\n */\n reconnectDelay?: number;\n /**\n * use compression for websocket messages\n * @default true\n * @type {boolean}\n * @memberof ConfigurationWebsocketAPI\n */\n compression?: boolean;\n /**\n * websocket agent\n * @default false\n * @type {boolean | Agent}\n * @memberof ConfigurationWebsocketAPI\n */\n agent?: boolean | Agent;\n /**\n * the mode of the connection, either 'single' or 'pool'.\n * @default 'single'\n * @type {'single' | 'pool'}\n * @memberof ConfigurationWebsocketAPI\n */\n mode?: 'single' | 'pool';\n /**\n * the size of the connection pool, if the mode is set to 'pool'.\n * @default 1\n * @type {number}\n * @memberof ConfigurationWebsocketAPI\n */\n poolSize?: number;\n /**\n * private key\n * @type {string | Buffer}\n * @memberof ConfigurationWebsocketAPI\n */\n privateKey?: string | Buffer;\n /**\n * private key passphrase\n * @type {string}\n * @memberof ConfigurationWebsocketAPI\n */\n privateKeyPassphrase?: string;\n /**\n * timeUnit (used only on SPOT API)\n * @type {TimeUnit}\n * @memberof ConfigurationWebsocketAPI\n */\n timeUnit?: TimeUnit;\n /**\n * auto session re-logon on reconnects/renewals\n * @default true\n * @type {boolean}\n * @memberof ConfigurationWebsocketAPI\n */\n autoSessionReLogon?: boolean;\n /**\n * Optional user agent string for identifying the client\n * @type {string}\n * @memberof ConfigurationWebsocketStreams\n * @internal\n */\n userAgent?: string;\n\n constructor(param: ConfigurationWebsocketAPI = { apiKey: '' }) {\n this.apiKey = param.apiKey;\n this.apiSecret = param.apiSecret;\n this.wsURL = param.wsURL;\n this.timeout = param.timeout ?? 5000;\n this.reconnectDelay = param.reconnectDelay ?? 5000;\n this.compression = param.compression ?? true;\n this.agent = param.agent ?? false;\n this.mode = param.mode ?? 'single';\n this.poolSize = param.poolSize ?? 1;\n this.privateKey = param.privateKey;\n this.privateKeyPassphrase = param.privateKeyPassphrase;\n this.timeUnit = param.timeUnit;\n this.autoSessionReLogon = param.autoSessionReLogon ?? true;\n }\n}\n\nexport class ConfigurationWebsocketStreams {\n /**\n * override websocket url\n * @type {string}\n * @memberof ConfigurationWebsocketStreams\n */\n wsURL?: string;\n /**\n * reconnction delay\n * @default 5000\n * @type {number}\n * @memberof ConfigurationWebsocketStreams\n */\n reconnectDelay?: number;\n /**\n * use compression for websocket messages\n * @default true\n * @type {boolean}\n * @memberof ConfigurationWebsocketAPI\n */\n compression?: boolean;\n /**\n * websocket agent\n * @default false\n * @type {boolean | Agent}\n * @memberof ConfigurationWebsocketStreams\n */\n agent?: boolean | Agent;\n /**\n * the mode of the connection, either 'single' or 'pool'.\n * @default single\n * @type {'single' | 'pool'}\n * @memberof ConfigurationWebsocketStreams\n */\n mode?: 'single' | 'pool';\n /**\n * the size of the connection pool, if the mode is set to 'pool'.\n * @default 1\n * @type {number}\n * @memberof ConfigurationWebsocketStreams\n */\n poolSize?: number;\n /**\n * timeUnit (used only on SPOT API)\n * @type {TimeUnit}\n * @memberof ConfigurationWebsocketStreams\n */\n timeUnit?: TimeUnit;\n /**\n * Optional user agent string for identifying the client\n * @type {string}\n * @memberof ConfigurationWebsocketStreams\n * @internal\n */\n userAgent?: string;\n\n constructor(param: ConfigurationWebsocketStreams = {}) {\n this.wsURL = param.wsURL;\n this.reconnectDelay = param.reconnectDelay ?? 5000;\n this.compression = param.compression ?? true;\n this.agent = param.agent ?? false;\n this.mode = param.mode ?? 'single';\n this.poolSize = param.poolSize ?? 1;\n this.timeUnit = param.timeUnit;\n }\n}\n","export const TimeUnit = {\n MILLISECOND: 'MILLISECOND',\n millisecond: 'millisecond',\n MICROSECOND: 'MICROSECOND',\n microsecond: 'microsecond',\n} as const;\nexport type TimeUnit = (typeof TimeUnit)[keyof typeof TimeUnit];\n\n// Algo constants\nexport const ALGO_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Auto Invest constants\nexport const AUTO_INVEST_REST_API_PROD_URL = 'https://api.binance.com';\n\n// C2C constants\nexport const C2C_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Convert constants\nexport const CONVERT_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Copy Trading constants\nexport const COPY_TRADING_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Crypto Loan constants\nexport const CRYPTO_LOAN_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Derivatives Trading (COIN-M Futures) constants\nexport const DERIVATIVES_TRADING_COIN_FUTURES_REST_API_PROD_URL = 'https://dapi.binance.com';\nexport const DERIVATIVES_TRADING_COIN_FUTURES_REST_API_TESTNET_URL =\n 'https://testnet.binancefuture.com';\nexport const DERIVATIVES_TRADING_COIN_FUTURES_WS_API_PROD_URL =\n 'wss://ws-dapi.binance.com/ws-dapi/v1';\nexport const DERIVATIVES_TRADING_COIN_FUTURES_WS_API_TESTNET_URL =\n 'wss://testnet.binancefuture.com/ws-dapi/v1';\nexport const DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_PROD_URL = 'wss://dstream.binance.com';\nexport const DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_TESTNET_URL =\n 'wss://dstream.binancefuture.com';\n\n// Derivatives Trading (USDS Futures) constants\nexport const DERIVATIVES_TRADING_USDS_FUTURES_REST_API_PROD_URL = 'https://fapi.binance.com';\nexport const DERIVATIVES_TRADING_USDS_FUTURES_REST_API_TESTNET_URL =\n 'https://testnet.binancefuture.com';\nexport const DERIVATIVES_TRADING_USDS_FUTURES_WS_API_PROD_URL =\n 'wss://ws-fapi.binance.com/ws-fapi/v1';\nexport const DERIVATIVES_TRADING_USDS_FUTURES_WS_API_TESTNET_URL =\n 'wss://testnet.binancefuture.com/ws-fapi/v1';\nexport const DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_PROD_URL = 'wss://fstream.binance.com';\nexport const DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_TESTNET_URL =\n 'wss://stream.binancefuture.com';\n\n// Derivatives Trading (Options) constants\nexport const DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL = 'https://eapi.binance.com';\nexport const DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL =\n 'wss://nbstream.binance.com/eoptions';\n\n// Derivatives Trading (Portfolio Margin) constants\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL = 'https://papi.binance.com';\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_TESTNET_URL =\n 'https://testnet.binancefuture.com';\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_PROD_URL =\n 'wss://fstream.binance.com/pm';\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_TESTNET_URL =\n 'wss://fstream.binancefuture.com/pm';\n\n// Derivatives Trading (Portfolio Margin Pro) constants\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_REST_API_PROD_URL = 'https://api.binance.com';\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_WS_STREAMS_PROD_URL =\n 'wss://fstream.binance.com/pm-classic';\n\n// Dual Investment constants\nexport const DUAL_INVESTMENT_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Fiat constants\nexport const FIAT_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Gift Card constants\nexport const GIFT_CARD_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Margin Trading constants\nexport const MARGIN_TRADING_REST_API_PROD_URL = 'https://api.binance.com';\nexport const MARGIN_TRADING_WS_STREAMS_PROD_URL = 'wss://stream.binance.com:9443';\nexport const MARGIN_TRADING_RISK_WS_STREAMS_PROD_URL = 'wss://margin-stream.binance.com';\n\n// Mining constants\nexport const MINING_REST_API_PROD_URL = 'https://api.binance.com';\n\n// NFT constants\nexport const NFT_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Pay constants\nexport const PAY_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Rebate constants\nexport const REBATE_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Simple Earn constants\nexport const SIMPLE_EARN_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Spot constants\nexport const SPOT_REST_API_PROD_URL = 'https://api.binance.com';\nexport const SPOT_REST_API_TESTNET_URL = 'https://testnet.binance.vision';\nexport const SPOT_WS_API_PROD_URL = 'wss://ws-api.binance.com:443/ws-api/v3';\nexport const SPOT_WS_API_TESTNET_URL = 'wss://ws-api.testnet.binance.vision/ws-api/v3';\nexport const SPOT_WS_STREAMS_PROD_URL = 'wss://stream.binance.com:9443';\nexport const SPOT_WS_STREAMS_TESTNET_URL = 'wss://stream.testnet.binance.vision';\nexport const SPOT_REST_API_MARKET_URL = 'https://data-api.binance.vision';\nexport const SPOT_WS_STREAMS_MARKET_URL = 'wss://data-stream.binance.vision';\n\n// Staking constants\nexport const STAKING_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Sub Account constants\nexport const SUB_ACCOUNT_REST_API_PROD_URL = 'https://api.binance.com';\n\n// VIP Loan constants\nexport const VIP_LOAN_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Wallet constants\nexport const WALLET_REST_API_PROD_URL = 'https://api.binance.com';\n","/**\n * Represents an error that occurred in the Connector client.\n * @param msg - An optional error message.\n */\nexport class ConnectorClientError extends Error {\n constructor(msg?: string) {\n super(msg || 'An unexpected error occurred.');\n Object.setPrototypeOf(this, ConnectorClientError.prototype);\n this.name = 'ConnectorClientError';\n }\n}\n\n/**\n * Represents an error that occurs when a required parameter is missing or undefined.\n * @param field - The name of the missing parameter.\n * @param msg - An optional error message.\n */\nexport class RequiredError extends Error {\n constructor(\n public field: string,\n msg?: string\n ) {\n super(msg || `Required parameter ${field} was null or undefined.`);\n Object.setPrototypeOf(this, RequiredError.prototype);\n this.name = 'RequiredError';\n }\n}\n\n/**\n * Represents an error that occurs when a client is unauthorized to access a resource.\n * @param msg - An optional error message.\n */\nexport class UnauthorizedError extends Error {\n constructor(msg?: string) {\n super(msg || 'Unauthorized access. Authentication required.');\n Object.setPrototypeOf(this, UnauthorizedError.prototype);\n this.name = 'UnauthorizedError';\n }\n}\n\n/**\n * Represents an error that occurs when a resource is forbidden to the client.\n * @param msg - An optional error message.\n */\nexport class ForbiddenError extends Error {\n constructor(msg?: string) {\n super(msg || 'Access to the requested resource is forbidden.');\n Object.setPrototypeOf(this, ForbiddenError.prototype);\n this.name = 'ForbiddenError';\n }\n}\n\n/**\n * Represents an error that occurs when client is doing too many requests.\n * @param msg - An optional error message.\n */\nexport class TooManyRequestsError extends Error {\n constructor(msg?: string) {\n super(msg || 'Too many requests. You are being rate-limited.');\n Object.setPrototypeOf(this, TooManyRequestsError.prototype);\n this.name = 'TooManyRequestsError';\n }\n}\n\n/**\n * Represents an error that occurs when client's IP has been banned.\n * @param msg - An optional error message.\n */\nexport class RateLimitBanError extends Error {\n constructor(msg?: string) {\n super(msg || 'The IP address has been banned for exceeding rate limits.');\n Object.setPrototypeOf(this, RateLimitBanError.prototype);\n this.name = 'RateLimitBanError';\n }\n}\n\n/**\n * Represents an error that occurs when there is an internal server error.\n * @param msg - An optional error message.\n * @param statusCode - An optional HTTP status code associated with the error.\n */\nexport class ServerError extends Error {\n constructor(\n msg?: string,\n public statusCode?: number\n ) {\n super(msg || 'An internal server error occurred.');\n Object.setPrototypeOf(this, ServerError.prototype);\n this.name = 'ServerError';\n }\n}\n\n/**\n * Represents an error that occurs when a network error occurs.\n * @param msg - An optional error message.\n */\nexport class NetworkError extends Error {\n constructor(msg?: string) {\n super(msg || 'A network error occurred.');\n Object.setPrototypeOf(this, NetworkError.prototype);\n this.name = 'NetworkError';\n }\n}\n\n/**\n * Represents an error that occurs when the requested resource was not found.\n * @param msg - An optional error message.\n */\nexport class NotFoundError extends Error {\n constructor(msg?: string) {\n super(msg || 'The requested resource was not found.');\n Object.setPrototypeOf(this, NotFoundError.prototype);\n this.name = 'NotFoundError';\n }\n}\n\n/**\n * Represents an error that occurs when a request is invalid or cannot be otherwise served.\n * @param msg - An optional error message.\n */\nexport class BadRequestError extends Error {\n constructor(msg?: string) {\n super(msg || 'The request was invalid or cannot be otherwise served.');\n Object.setPrototypeOf(this, BadRequestError.prototype);\n this.name = 'BadRequestError';\n }\n}\n","export enum LogLevel {\n NONE = '',\n DEBUG = 'debug',\n INFO = 'info',\n WARN = 'warn',\n ERROR = 'error',\n}\n\nexport class Logger {\n private static instance: Logger;\n private minLogLevel: LogLevel = LogLevel.INFO;\n private readonly levelsOrder: LogLevel[] = [\n LogLevel.NONE,\n LogLevel.DEBUG,\n LogLevel.INFO,\n LogLevel.WARN,\n LogLevel.ERROR,\n ];\n\n constructor() {\n const envLevel = process.env.LOG_LEVEL?.toLowerCase() as LogLevel | undefined;\n this.minLogLevel = envLevel && this.isValidLogLevel(envLevel) ? envLevel : LogLevel.INFO;\n }\n\n public static getInstance(): Logger {\n if (!Logger.instance) Logger.instance = new Logger();\n return Logger.instance;\n }\n\n public setMinLogLevel(level: LogLevel): void {\n if (!this.isValidLogLevel(level)) throw new Error(`Invalid log level: ${level}`);\n this.minLogLevel = level;\n }\n\n private isValidLogLevel(level: LogLevel): boolean {\n return this.levelsOrder.includes(level);\n }\n\n private log(level: LogLevel, ...message: unknown[]): void {\n if (level === LogLevel.NONE || !this.allowLevelLog(level)) return;\n\n const timestamp = new Date().toISOString();\n console[level](`[${timestamp}] [${level.toLowerCase()}]`, ...message);\n }\n\n private allowLevelLog(level: LogLevel): boolean {\n if (!this.isValidLogLevel(level)) throw new Error(`Invalid log level: ${level}`);\n\n const currentLevelIndex = this.levelsOrder.indexOf(level);\n const minLevelIndex = this.levelsOrder.indexOf(this.minLogLevel);\n return currentLevelIndex >= minLevelIndex;\n }\n\n public debug(...message: unknown[]): void {\n this.log(LogLevel.DEBUG, ...message);\n }\n\n public info(...message: unknown[]): void {\n this.log(LogLevel.INFO, ...message);\n }\n\n public warn(...message: unknown[]): void {\n this.log(LogLevel.WARN, ...message);\n }\n\n public error(...message: unknown[]): void {\n this.log(LogLevel.ERROR, ...message);\n }\n}\n","import { EventEmitter } from 'events';\nimport WebSocketClient from 'ws';\nimport { ClientRequestArgs } from 'http';\nimport {\n type ConfigurationWebsocketAPI,\n type ConfigurationWebsocketStreams,\n WebsocketApiResponse,\n Logger,\n delay,\n randomString,\n validateTimeUnit,\n buildWebsocketAPIMessage,\n} from '.';\n\nexport class WebsocketEventEmitter {\n private eventEmitter: EventEmitter;\n\n constructor() {\n this.eventEmitter = new EventEmitter();\n }\n\n /* eslint-disable @typescript-eslint/no-explicit-any */\n on(\n event: 'open' | 'message' | 'error' | 'close' | 'ping' | 'pong',\n listener: (...args: any[]) => void\n ): void {\n this.eventEmitter.on(event, listener);\n }\n\n /* eslint-disable @typescript-eslint/no-explicit-any */\n off(\n event: 'open' | 'message' | 'error' | 'close' | 'ping' | 'pong',\n listener: (...args: any[]) => void\n ): void {\n this.eventEmitter.off(event, listener);\n }\n\n /* eslint-disable @typescript-eslint/no-explicit-any */\n protected emit(\n event: 'open' | 'message' | 'error' | 'close' | 'ping' | 'pong',\n ...args: any[]\n ): void {\n this.eventEmitter.emit(event, ...args);\n }\n}\n\nexport interface WebsocketConnection {\n id: string;\n reconnectionPending: boolean;\n renewalPending: boolean;\n closeInitiated: boolean;\n pendingRequests: Map<\n string,\n { resolve: (value: any) => void; reject: (reason?: unknown) => void }\n >;\n pendingSubscriptions?: string[];\n ws?: WebSocketClient;\n isSessionLoggedOn?: boolean;\n sessionLogonReq?: {\n method: string;\n payload: WebsocketSendMsgOptions;\n options: WebsocketSendMsgConfig;\n };\n}\n\nexport class WebsocketCommon extends WebsocketEventEmitter {\n private static readonly MAX_CONNECTION_DURATION = 23 * 60 * 60 * 1000;\n private readonly connectionQueue: Array<{\n connection: WebsocketConnection;\n url: string;\n isRenewal: boolean;\n }> = [];\n private queueProcessing: boolean = false;\n private connectionTimers: Map<\n WebSocketClient,\n Set<{ timer: NodeJS.Timeout; type: 'timeout' | 'interval' }>\n > = new Map();\n private mode: 'single' | 'pool';\n private poolSize: number;\n private roundRobinIndex = 0;\n connectionPool: WebsocketConnection[];\n logger: Logger = Logger.getInstance();\n\n constructor(\n protected configuration: ConfigurationWebsocketAPI | ConfigurationWebsocketStreams,\n connectionPool: WebsocketConnection[] = []\n ) {\n super();\n this.connectionPool = connectionPool;\n this.mode = this.configuration?.mode ?? 'single';\n this.poolSize =\n this.mode === 'pool' && this.configuration?.poolSize ? this.configuration.poolSize : 1;\n if (!connectionPool || connectionPool.length === 0) this.initializePool(this.poolSize);\n }\n\n /**\n * Initializes the WebSocket connection pool by creating a specified number of connection objects\n * and adding them to the `connectionPool` array. Each connection object has the following properties:\n * - `closeInitiated`: a boolean indicating whether the connection has been closed\n * - `reconnectionPending`: a boolean indicating whether a reconnection is pending\n * - `pendingRequests`: a Map that tracks pending requests for the connection\n * @param size - The number of connection objects to create and add to the pool.\n * @returns void\n */\n private initializePool(size: number): void {\n for (let i = 0; i < size; i++) {\n this.connectionPool.push({\n id: randomString(),\n closeInitiated: false,\n reconnectionPending: false,\n renewalPending: false,\n pendingRequests: new Map(),\n pendingSubscriptions: [],\n });\n }\n }\n\n /**\n * Retrieves available WebSocket connections based on the connection mode and readiness.\n * In 'single' mode, returns the first connection in the pool.\n * In 'pool' mode, filters and returns connections that are ready for use.\n * @param allowNonEstablishedWebsockets - Optional flag to include non-established WebSocket connections.\n * @returns An array of available WebSocket connections.\n */\n protected getAvailableConnections(\n allowNonEstablishedWebsockets: boolean = false\n ): WebsocketConnection[] {\n if (this.mode === 'single') return [this.connectionPool[0]];\n\n // Filter connections based on readiness and pending reconnection status\n const availableConnections = this.connectionPool.filter((connection) =>\n this.isConnectionReady(connection, allowNonEstablishedWebsockets)\n );\n\n return availableConnections;\n }\n\n /**\n * Gets a WebSocket connection from the pool or single connection.\n * If the connection mode is 'single', it returns the first connection in the pool.\n * If the connection mode is 'pool', it returns an available connection from the pool,\n * using a round-robin selection strategy. If no available connections are found, it throws an error.\n * @param allowNonEstablishedWebsockets - A boolean indicating whether to allow connections that are not established.\n * @returns {WebsocketConnection} The selected WebSocket connection.\n */\n protected getConnection(allowNonEstablishedWebsockets: boolean = false): WebsocketConnection {\n const availableConnections = this.getAvailableConnections(allowNonEstablishedWebsockets);\n\n if (availableConnections.length === 0) {\n throw new Error('No available Websocket connections are ready.');\n }\n\n // Select a connection using round-robin algorithm\n const selectedConnection =\n availableConnections[this.roundRobinIndex % availableConnections.length];\n this.roundRobinIndex = (this.roundRobinIndex + 1) % availableConnections.length;\n return selectedConnection!;\n }\n\n /**\n * Checks if the provided WebSocket connection is ready for use.\n * A connection is considered ready if it is open, has no pending reconnection, and has not been closed.\n * @param connection - The WebSocket connection to check.\n * @param allowNonEstablishedWebsockets - An optional flag to allow non-established WebSocket connections.\n * @returns `true` if the connection is ready, `false` otherwise.\n */\n protected isConnectionReady(\n connection: WebsocketConnection,\n allowNonEstablishedWebsockets: boolean = false\n ): boolean {\n return (\n (allowNonEstablishedWebsockets || connection.ws?.readyState === WebSocketClient.OPEN) &&\n !connection.reconnectionPending &&\n !connection.closeInitiated\n );\n }\n\n /**\n * Schedules a timer for a WebSocket connection and tracks it\n * @param connection WebSocket client instance\n * @param callback Function to execute when timer triggers\n * @param delay Time in milliseconds before callback execution\n * @param type Timer type ('timeout' or 'interval')\n * @returns Timer handle\n */\n private scheduleTimer(\n connection: WebSocketClient,\n callback: () => void,\n delay: number,\n type: 'timeout' | 'interval' = 'timeout'\n ): NodeJS.Timeout {\n const timer =\n type === 'timeout' ? setTimeout(callback, delay) : setInterval(callback, delay);\n if (!this.connectionTimers.has(connection))\n this.connectionTimers.set(connection, new Set());\n this.connectionTimers.get(connection)?.add({ timer, type });\n return timer;\n }\n\n /**\n * Clears all timers associated with a WebSocket connection.\n * @param connection - The WebSocket client instance to clear timers for.\n * @returns void\n */\n private clearTimers(connection: WebSocketClient): void {\n const timers = this.connectionTimers.get(connection);\n if (timers) {\n timers.forEach(({ timer, type }) => {\n if (type === 'timeout') clearTimeout(timer);\n else if (type === 'interval') clearInterval(timer);\n });\n\n this.connectionTimers.delete(connection);\n }\n }\n\n /**\n * Processes the connection queue, reconnecting or renewing connections as needed.\n * This method is responsible for iterating through the connection queue and initiating\n * the reconnection or renewal process for each connection in the queue. It throttles\n * the queue processing to avoid overwhelming the server with too many connection\n * requests at once.\n * @param throttleRate - The time in milliseconds to wait between processing each\n * connection in the queue.\n * @returns A Promise that resolves when the queue has been fully processed.\n */\n private async processQueue(throttleRate: number = 1000): Promise<void> {\n if (this.queueProcessing) return;\n this.queueProcessing = true;\n\n while (this.connectionQueue.length > 0) {\n const { connection, url, isRenewal } = this.connectionQueue.shift()!;\n this.initConnect(url, isRenewal, connection);\n await delay(throttleRate);\n }\n\n this.queueProcessing = false;\n }\n\n /**\n * Enqueues a reconnection or renewal for a WebSocket connection.\n * This method adds the connection, URL, and renewal flag to the connection queue,\n * and then calls the `processQueue` method to initiate the reconnection or renewal\n * process.\n * @param connection - The WebSocket connection to reconnect or renew.\n * @param url - The URL to use for the reconnection or renewal.\n * @param isRenewal - A flag indicating whether this is a renewal (true) or a reconnection (false).\n */\n private enqueueReconnection(\n connection: WebsocketConnection,\n url: string,\n isRenewal: boolean\n ): void {\n this.connectionQueue.push({ connection, url, isRenewal });\n this.processQueue();\n }\n\n /**\n * Gracefully closes a WebSocket connection after pending requests complete.\n * This method waits for any pending requests to complete before closing the connection.\n * It sets up a timeout to force-close the connection after 30 seconds if the pending requests\n * do not complete. Once all pending requests are completed, the connection is closed.\n * @param connectionToClose - The WebSocket client instance to close.\n * @param WebsocketConnectionToClose - The WebSocket connection to close.\n * @param connection - The WebSocket connection to close.\n * @returns Promise that resolves when the connection is closed.\n */\n private async closeConnectionGracefully(\n WebsocketConnectionToClose: WebSocketClient,\n connection: WebsocketConnection\n ): Promise<void> {\n if (!WebsocketConnectionToClose || !connection) return;\n\n this.logger.debug(\n `Waiting for pending requests to complete before disconnecting websocket on connection ${connection.id}.`\n );\n\n const closePromise = new Promise<void>((resolve) => {\n this.scheduleTimer(\n WebsocketConnectionToClose,\n () => {\n this.logger.warn(\n `Force-closing websocket connection after 30 seconds on connection ${connection.id}.`\n );\n resolve();\n },\n 30000\n );\n\n this.scheduleTimer(\n WebsocketConnectionToClose,\n () => {\n if (connection.pendingRequests.size === 0) {\n this.logger.debug(\n `All pending requests completed, closing websocket connection on connection ${connection.id}.`\n );\n resolve();\n }\n },\n 1000,\n 'interval'\n );\n });\n\n await closePromise;\n\n this.logger.info(`Closing Websocket connection on connection ${connection.id}.`);\n WebsocketConnectionToClose.close();\n this.cleanup(WebsocketConnectionToClose);\n }\n\n /**\n * Attempts to re-establish a session for a WebSocket connection.\n * If a session logon request exists and the connection is not already logged on,\n * it sends an authentication request and updates the connection's logged-on status.\n * @param connection - The WebSocket connection to re-authenticate.\n * @private\n */\n private async sessionReLogon(connection: WebsocketConnection) {\n const req = connection.sessionLogonReq;\n if (req && !connection.isSessionLoggedOn) {\n const data = buildWebsocketAPIMessage(\n this.configuration as ConfigurationWebsocketAPI,\n req.method,\n req.payload,\n req.options\n );\n\n this.logger.debug(`Session re-logon on connection ${connection.id}`, data);\n\n try {\n await this.send(\n JSON.stringify(data),\n data.id,\n true,\n (this.configuration as ConfigurationWebsocketAPI).timeout,\n connection\n );\n this.logger.debug(\n `Session re-logon on connection ${connection.id} was successful.`\n );\n connection.isSessionLoggedOn = true;\n } catch (err) {\n this.logger.error(`Session re-logon on connection ${connection.id} failed:`, err);\n }\n }\n }\n\n /**\n * Cleans up WebSocket connection resources.\n * Removes all listeners and clears any associated timers for the provided WebSocket client.\n * @param ws - The WebSocket client to clean up.\n * @returns void\n */\n protected cleanup(ws: WebSocketClient): void {\n if (ws) {\n ws.removeAllListeners();\n this.clearTimers(ws);\n }\n }\n\n /**\n * Handles incoming WebSocket messages\n * @param data Raw message data received\n * @param connection Websocket connection\n */\n protected onMessage(data: string, connection: WebsocketConnection): void {\n this.emit('message', data.toString(), connection);\n }\n\n /**\n * Handles the opening of a WebSocket connection.\n * @param url - The URL of the WebSocket server.\n * @param targetConnection - The WebSocket connection being opened.\n * @param oldWSConnection - The WebSocket client instance associated with the old connection.\n */\n protected onOpen(\n url: string,\n targetConnection: WebsocketConnection,\n oldWSConnection: WebSocketClient\n ): void {\n this.logger.info(\n `Connected to the Websocket Server with id ${targetConnection.id}: ${url}`\n );\n if (targetConnection.renewalPending) {\n targetConnection.renewalPending = false;\n this.closeConnectionGracefully(oldWSConnection, targetConnection);\n } else if (targetConnection.closeInitiated) {\n this.closeConnectionGracefully(targetConnection.ws!, targetConnection);\n } else {\n this.emit('open', this);\n }\n this.sessionReLogon(targetConnection);\n }\n\n /**\n * Returns the URL to use when reconnecting.\n * Derived classes should override this to provide dynamic URLs.\n * @param defaultURL The URL originally passed during the first connection.\n * @param targetConnection The WebSocket connection being connected.\n * @returns The URL to reconnect to.\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected getReconnectURL(defaultURL: string, targetConnection: WebsocketConnection): string {\n return defaultURL;\n }\n\n /**\n * Connects all WebSocket connections in the pool\n * @param url - The Websocket server URL.\n * @returns A promise that resolves when all connections are established.\n */\n protected async connectPool(url: string): Promise<void> {\n const connectPromises = this.connectionPool.map(\n (connection) =>\n new Promise<void>((resolve, reject) => {\n this.initConnect(url, false, connection);\n\n connection.ws?.on('open', () => resolve());\n connection.ws?.on('error', (err) => reject(err));\n connection.ws?.on('close', () =>\n reject(new Error('Connection closed unexpectedly.'))\n );\n })\n );\n await Promise.all(connectPromises);\n }\n\n /**\n * Creates a new WebSocket client instance.\n * @param url - The URL to connect to.\n * @returns A new WebSocket client instance.\n */\n protected createWebSocket(url: string): WebSocketClient {\n const wsClientOptions: WebSocketClient.ClientOptions | ClientRequestArgs = {\n perMessageDeflate: this.configuration?.compression,\n agent: this.configuration?.agent,\n };\n if (this.configuration.userAgent)\n wsClientOptions.headers = { 'User-Agent': this.configuration.userAgent };\n\n return new WebSocketClient(url, wsClientOptions);\n }\n\n /**\n * Initializes a WebSocket connection.\n * @param url - The Websocket server URL.\n * @param isRenewal - Whether this is a connection renewal.\n * @param connection - An optional WebSocket connection to use.\n * @returns The WebSocket connection.\n */\n protected initConnect(\n url: string,\n isRenewal: boolean = false,\n connection?: WebsocketConnection\n ) {\n const targetConnection = connection || this.getConnection();\n\n if (targetConnection.renewalPending && isRenewal) {\n this.logger.warn(\n `Connection renewal with id ${targetConnection.id} is already in progress`\n );\n return;\n }\n\n if (\n targetConnection.ws &&\n targetConnection.ws.readyState === WebSocketClient.OPEN &&\n !isRenewal\n ) {\n this.logger.warn(`Connection with id ${targetConnection.id} already exists`);\n return;\n }\n\n const ws = this.createWebSocket(url);\n\n this.logger.info(\n `Establishing Websocket connection with id ${targetConnection.id} to: ${url}`\n );\n\n if (isRenewal) targetConnection.renewalPending = true;\n else targetConnection.ws = ws;\n\n targetConnection.isSessionLoggedOn = false;\n\n this.scheduleTimer(\n ws,\n () => {\n this.logger.info(`Renewing Websocket connection with id ${targetConnection.id}`);\n targetConnection.isSessionLoggedOn = false;\n this.enqueueReconnection(\n targetConnection,\n this.getReconnectURL(url, targetConnection),\n true\n );\n },\n WebsocketCommon.MAX_CONNECTION_DURATION\n );\n\n ws.on('open', () => {\n const oldWSConnection = targetConnection.ws;\n if (targetConnection.renewalPending) targetConnection.ws = ws;\n this.onOpen(url, targetConnection, oldWSConnection!);\n });\n\n ws.on('message', (data: WebSocketClient.Data) => {\n this.onMessage(data.toString(), targetConnection);\n });\n\n ws.on('ping', () => {\n this.logger.info('Received PING from server');\n this.emit('ping');\n ws.pong();\n this.logger.info('Responded PONG to server\\'s PING message');\n });\n\n ws.on('pong', () => {\n this.logger.info('Received PONG from server');\n this.emit('pong');\n });\n\n ws.on('error', (err) => {\n this.logger.error('Received error from server');\n this.logger.error(err);\n this.emit('error', err);\n });\n\n ws.on('close', (closeEventCode, reason) => {\n this.emit('close', closeEventCode, reason);\n\n if (!targetConnection.closeInitiated && !isRenewal) {\n this.logger.warn(\n `Connection with id ${targetConnection.id} closed due to ${closeEventCode}: ${reason}`\n );\n this.scheduleTimer(\n ws,\n () => {\n this.logger.info(\n `Reconnecting conection with id ${targetConnection.id} to the server.`\n );\n targetConnection.isSessionLoggedOn = false;\n targetConnection.reconnectionPending = true;\n this.enqueueReconnection(\n targetConnection,\n this.getReconnectURL(url, targetConnection),\n false\n );\n },\n this.configuration?.reconnectDelay ?? 5000\n );\n }\n });\n\n return targetConnection;\n }\n\n /**\n * Checks if the WebSocket connection is currently open.\n * @param connection - An optional WebSocket connection to check. If not provided, the entire connection pool is checked.\n * @returns `true` if the connection is open, `false` otherwise.\n */\n isConnected(connection?: WebsocketConnection): boolean {\n const connectionPool = connection ? [connection] : this.connectionPool;\n return connectionPool.some((connection) => this.isConnectionReady(connection));\n }\n\n /**\n * Disconnects from the WebSocket server.\n * If there is no active connection, a warning is logged.\n * Otherwise, all connections in the connection pool are closed gracefully,\n * and a message is logged indicating that the connection has been disconnected.\n * @returns A Promise that resolves when all connections have been closed.\n * @throws Error if the WebSocket client is not set.\n */\n async disconnect(): Promise<void> {\n if (!this.isConnected()) this.logger.warn('No connection to close.');\n else {\n this.connectionPool.forEach((connection) => {\n connection.closeInitiated = true;\n connection.isSessionLoggedOn = false;\n connection.sessionLogonReq = undefined;\n });\n\n const disconnectPromises = this.connectionPool.map((connection: WebsocketConnection) =>\n this.closeConnectionGracefully(connection.ws!, connection)\n );\n\n await Promise.all(disconnectPromises);\n this.logger.info('Disconnected with Binance Websocket Server');\n }\n }\n\n /**\n * Sends a ping message to all connected Websocket servers in the pool.\n * If no connections are ready, a warning is logged.\n * For each active connection, the ping message is sent, and debug logs provide details.\n * @throws Error if a Websocket client is not set for a connection.\n */\n pingServer(): void {\n const connectedConnections = this.connectionPool.filter((connection) =>\n this.isConnected(connection)\n );\n\n if (connectedConnections.length === 0) {\n this.logger.warn('Ping only can be sent when connection is ready.');\n return;\n }\n\n this.logger.info('Sending PING to all connected Websocket servers.');\n\n connectedConnections.forEach((connection) => {\n if (connection.ws) {\n connection.ws.ping();\n this.logger.debug(`PING sent to connection with id ${connection.id}`);\n } else {\n this.logger.error('WebSocket Client not set for a connection.');\n }\n });\n }\n\n /**\n * Sends a payload through the WebSocket connection.\n * @param payload - Message to send.\n * @param id - Optional request identifier.\n * @param promiseBased - Whether to return a promise.\n * @param timeout - Timeout duration in milliseconds.\n * @param connection - The WebSocket connection to use.\n * @returns A promise if `promiseBased` is true, void otherwise.\n * @throws Error if not connected or WebSocket client is not set.\n */\n protected send<T = unknown>(\n payload: string,\n id?: string,\n promiseBased: boolean = true,\n timeout: number = 5000,\n connection?: WebsocketConnection\n ): Promise<WebsocketApiResponse<T>> | void {\n if (!this.isConnected(connection)) {\n const errorMsg = 'Send can only be sent when connection is ready.';\n this.logger.warn(errorMsg);\n if (promiseBased) return Promise.reject(new Error(errorMsg));\n else throw new Error(errorMsg);\n }\n\n const connectionToUse: WebsocketConnection = connection ?? this.getConnection();\n\n if (!connectionToUse.ws) {\n const errorMsg = 'Websocket Client not set';\n this.logger.error(errorMsg);\n if (promiseBased) return Promise.reject(new Error(errorMsg));\n else throw new Error(errorMsg);\n }\n\n connectionToUse.ws.send(payload);\n\n if (promiseBased) {\n return new Promise<WebsocketApiResponse<T>>((resolve, reject) => {\n if (!id) return reject(new Error('id is required for promise-based sending.'));\n\n connectionToUse.pendingRequests.set(id, { resolve, reject });\n\n this.scheduleTimer(\n connectionToUse.ws!,\n () => {\n if (connectionToUse.pendingRequests.has(id)) {\n connectionToUse.pendingRequests.delete(id);\n reject(new Error(`Request timeout for id: ${id}`));\n }\n },\n timeout\n );\n });\n }\n }\n}\n\nexport interface WebsocketSendMsgOptions {\n id?: string;\n [key: string]: string | number | boolean | object | undefined;\n}\n\nexport interface WebsocketSendMsgConfig {\n withApiKey?: boolean;\n isSigned?: boolean;\n isSessionLogon?: boolean;\n isSessionLogout?: boolean;\n}\n\nexport class WebsocketAPIBase extends WebsocketCommon {\n private isConnecting: boolean = false;\n streamCallbackMap: Map<string, Set<(data: unknown) => void>> = new Map();\n configuration: ConfigurationWebsocketAPI;\n logger: Logger = Logger.getInstance();\n\n constructor(\n configuration: ConfigurationWebsocketAPI,\n connectionPool: WebsocketConnection[] = []\n ) {\n super(configuration, connectionPool);\n this.configuration = configuration;\n }\n\n /**\n * Prepares the WebSocket URL by adding optional timeUnit parameter\n * @param wsUrl The base WebSocket URL\n * @returns The formatted WebSocket URL with parameters\n */\n private prepareURL(wsUrl: string): string {\n let url = wsUrl;\n if (this?.configuration.timeUnit) {\n try {\n const _timeUnit = validateTimeUnit(this.configuration.timeUnit);\n url = `${url}${url.includes('?') ? '&' : '?'}timeUnit=${_timeUnit}`;\n } catch (err) {\n this.logger.error(err);\n }\n }\n return url;\n }\n\n /**\n * Processes incoming WebSocket messages\n * @param data The raw message data received\n */\n protected onMessage<T>(data: string, connection: WebsocketConnection): void {\n try {\n const message = JSON.parse(data);\n const { id, status } = message;\n\n if (id && connection.pendingRequests.has(id)) {\n const request = connection.pendingRequests.get(id);\n connection.pendingRequests.delete(id);\n\n if (status && status >= 400) {\n request?.reject(message.error);\n } else {\n const response: WebsocketApiResponse<T> = {\n data: message.result ?? message.response,\n ...(message.rateLimits && { rateLimits: message.rateLimits }),\n };\n request?.resolve(response);\n }\n } else if (\n 'event' in message &&\n 'e' in message['event'] &&\n this.streamCallbackMap.size > 0\n ) {\n // Handle user data stream messages (currently with no ID we send the message to all registered callbacks)\n this.streamCallbackMap.forEach((callbacks) =>\n callbacks.forEach((callback) => callback(message['event']))\n );\n } else {\n this.logger.warn('Received response for unknown or timed-out request:', message);\n }\n } catch (error) {\n this.logger.error('Failed to parse WebSocket message:', data, error);\n }\n\n super.onMessage(data, connection);\n }\n\n /**\n * Establishes a WebSocket connection to Binance\n * @returns Promise that resolves when connection is established\n * @throws Error if connection times out\n */\n connect(): Promise<void> {\n if (this.isConnected()) {\n this.logger.info('WebSocket connection already established');\n return Promise.resolve();\n }\n\n return new Promise((resolve, reject) => {\n if (this.isConnecting) return;\n\n this.isConnecting = true;\n\n const timeout = setTimeout(() => {\n this.isConnecting = false;\n reject(new Error('Websocket connection timed out'));\n }, 10000);\n\n this.connectPool(this.prepareURL(this.configuration.wsURL as string))\n .then(() => {\n clearTimeout(timeout);\n this.isConnecting = false;\n resolve();\n })\n .catch((error) => {\n clearTimeout(timeout);\n this.isConnecting = false;\n reject(error);\n });\n });\n }\n\n sendMessage<T>(\n method: string,\n payload: WebsocketSendMsgOptions,\n options: WebsocketSendMsgConfig & { isSessionLogon: true }\n ): Promise<WebsocketApiResponse<T>[]>;\n\n sendMessage<T>(\n method: string,\n payload: WebsocketSendMsgOptions,\n options: WebsocketSendMsgConfig & { isSessionLogout: true }\n ): Promise<WebsocketApiResponse<T>[]>;\n\n sendMessage<T>(\n method: string,\n payload?: WebsocketSendMsgOptions,\n options?: WebsocketSendMsgConfig\n ): Promise<WebsocketApiResponse<T>>;\n\n async sendMessage<T>(\n method: string,\n payload: WebsocketSendMsgOptions = {},\n options: WebsocketSendMsgConfig = {}\n ): Promise<WebsocketApiResponse<T> | WebsocketApiResponse<T>[]> {\n if (!this.isConnected()) {\n throw new Error('Not connected');\n }\n\n const isSessionReq = options.isSessionLogon || options.isSessionLogout;\n\n const connections: WebsocketConnection[] = isSessionReq\n ? this.getAvailableConnections()\n : [this.getConnection()];\n\n const skipAuth = isSessionReq\n ? false\n : this.configuration.autoSessionReLogon && connections[0].isSessionLoggedOn;\n\n const data = buildWebsocketAPIMessage(\n this.configuration,\n method,\n payload,\n options,\n skipAuth\n );\n\n this.logger.debug('Send message to Binance WebSocket API Server:', data);\n\n const responses = await Promise.all(\n connections.map(\n (connection) =>\n this.send<T>(\n JSON.stringify(data),\n data.id,\n true,\n this.configuration.timeout,\n connection\n ) as Promise<WebsocketApiResponse<T>>\n )\n );\n\n if (isSessionReq && this.configuration.autoSessionReLogon) {\n connections.forEach((connection) => {\n if (options.isSessionLogon) {\n connection.isSessionLoggedOn = true;\n connection.sessionLogonReq = { method, payload, options };\n } else {\n connection.isSessionLoggedOn = false;\n connection.sessionLogonReq = undefined;\n }\n });\n }\n\n return connections.length === 1 && !isSessionReq ? responses[0] : responses;\n }\n}\n\nexport class WebsocketStreamsBase extends WebsocketCommon {\n private streamConnectionMap: Map<string, WebsocketConnection> = new Map();\n protected configuration: ConfigurationWebsocketStreams;\n protected wsURL: string;\n streamCallbackMap: Map<string, Set<(data: unknown) => void>> = new Map();\n logger: Logger = Logger.getInstance();\n\n constructor(\n configuration: ConfigurationWebsocketStreams,\n connectionPool: WebsocketConnection[] = []\n ) {\n super(configuration, connectionPool);\n this.configuration = configuration;\n this.wsURL = configuration.wsURL as string;\n }\n\n /**\n * Formats the WebSocket URL for a given stream or streams.\n * @param streams - Array of stream names to include in the URL.\n * @returns The formatted WebSocket URL with the provided streams.\n */\n private prepareURL(streams: string[] = []): string {\n let url = `${this.wsURL}/stream?streams=${streams.join('/')}`;\n\n if (this.configuration?.timeUnit) {\n try {\n const _timeUnit = validateTimeUnit(this.configuration.timeUnit);\n url = `${url}${url.includes('?') ? '&' : '?'}timeUnit=${_timeUnit}`;\n } catch (err) {\n this.logger.error(err);\n }\n }\n\n return url;\n }\n\n /**\n * Formats the WebSocket URL with stream and configuration parameters to be used for reconnection.\n * @param url - The base WebSocket URL.\n * @param targetConnection - The target WebSocket connection.\n * @returns The formatted WebSocket URL with streams and optional parameters.\n */\n protected getReconnectURL(url: string, targetConnection: WebsocketConnection): string {\n const streams = Array.from(this.streamConnectionMap.keys()).filter(\n (stream) => this.streamConnectionMap.get(stream) === targetConnection\n );\n return this.prepareURL(streams);\n }\n\n /**\n * Handles subscription to streams and assigns them to specific connections\n * @param streams Array of stream names to subscribe to\n * @returns Map of connections to streams\n */\n private handleStreamAssignment(streams: string[]): Map<WebsocketConnection, string[]> {\n const connectionStreamMap = new Map<WebsocketConnection, string[]>();\n\n streams.forEach((stream) => {\n if (!this.streamCallbackMap.has(stream)) this.streamCallbackMap.set(stream, new Set());\n\n let connection = this.streamConnectionMap.get(stream);\n\n if (!connection || connection.closeInitiated || connection.reconnectionPending) {\n connection = this.getConnection(true);\n this.streamConnectionMap.set(stream, connection);\n }\n\n if (!connectionStreamMap.has(connection)) connectionStreamMap.set(connection, []);\n\n connectionStreamMap.get(connection)?.push(stream);\n });\n\n return connectionStreamMap;\n }\n\n /**\n * Sends a subscription payload for specified streams on a given connection.\n * @param connection The WebSocket connection to use for sending the subscription.\n * @param streams The streams to subscribe to.\n * @param id Optional ID for the subscription.\n */\n private sendSubscriptionPayload(\n connection: WebsocketConnection,\n streams: string[],\n id?: string\n ): void {\n const payload = {\n method: 'SUBSCRIBE',\n params: streams,\n id: id && /^[0-9a-f]{32}$/.test(id) ? id : randomString(),\n };\n this.logger.debug('SUBSCRIBE', payload);\n this.send(JSON.stringify(payload), undefined, false, 0, connection);\n }\n\n /**\n * Processes pending subscriptions for a given connection.\n * Sends all queued subscriptions in a single payload.\n * @param connection The WebSocket connection to process.\n */\n private processPendingSubscriptions(connection: WebsocketConnection): void {\n if (connection.pendingSubscriptions && connection.pendingSubscriptions.length > 0) {\n this.logger.info('Processing queued subscriptions for connection');\n this.sendSubscriptionPayload(connection, connection.pendingSubscriptions);\n connection.pendingSubscriptions = [];\n }\n }\n\n /**\n * Handles incoming WebSocket messages, parsing the data and invoking the appropriate callback function.\n * If the message contains a stream name that is registered in the `streamCallbackMap`, the corresponding\n * callback function is called with the message data.\n * If the message cannot be parsed, an error is logged.\n * @param data The raw WebSocket message data.\n * @param connection The WebSocket connection that received the message.\n */\n protected onMessage(data: string, connection: WebsocketConnection): void {\n try {\n const parsedData = JSON.parse(data);\n const streamName = parsedData?.stream;\n\n if (streamName && this.streamCallbackMap.has(streamName))\n this.streamCallbackMap\n .get(streamName)\n ?.forEach((callback) => callback(parsedData.data));\n } catch (error) {\n this.logger.error('Failed to parse WebSocket message:', data, error);\n }\n\n super.onMessage(data, connection);\n }\n\n /**\n * Called when the WebSocket connection is opened.\n * Processes any pending subscriptions for the target connection.\n * @param url The URL of the WebSocket connection.\n * @param targetConnection The WebSocket connection that was opened.\n * @param oldConnection The previous WebSocket connection, if any.\n */\n protected onOpen(\n url: string,\n targetConnection: WebsocketConnection,\n oldWSConnection: WebSocketClient\n ): void {\n this.processPendingSubscriptions(targetConnection);\n super.onOpen(url, targetConnection, oldWSConnection);\n }\n\n /**\n * Connects to the WebSocket server and subscribes to the specified streams.\n * This method returns a Promise that resolves when the connection is established,\n * or rejects with an error if the connection fails to be established within 10 seconds.\n * @param stream - A single stream name or an array of stream names to subscribe to.\n * @returns A Promise that resolves when the connection is established.\n */\n connect(stream: string | string[] = []): Promise<void> {\n const streams = Array.isArray(stream) ? stream : [stream];\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error('Websocket connection timed out'));\n }, 10000);\n\n this.connectPool(this.prepareURL(streams))\n .then(() => {\n clearTimeout(timeout);\n resolve();\n })\n .catch((error) => {\n clearTimeout(timeout);\n reject(error);\n });\n });\n }\n\n /**\n * Disconnects the WebSocket connection and clears the stream callback map.\n * This method is called to clean up the connection and associated resources.\n */\n async disconnect(): Promise<void> {\n this.streamCallbackMap.clear();\n this.streamConnectionMap.clear();\n super.disconnect();\n }\n\n /**\n * Subscribes to one or multiple WebSocket streams\n * Handles both single and pool modes\n * @param stream Single stream name or array of stream names to subscribe to\n * @param id Optional subscription ID\n * @returns void\n */\n subscribe(stream: string | string[], id?: string): void {\n const streams = (Array.isArray(stream) ? stream : [stream]).filter(\n (stream) => !this.streamConnectionMap.has(stream)\n );\n const connectionStreamMap = this.handleStreamAssignment(streams);\n\n connectionStreamMap.forEach((streams, connection) => {\n if (!this.isConnected(connection)) {\n this.logger.info(\n `Connection ${connection.id} is not ready. Queuing subscription for streams: ${streams}`\n );\n connection.pendingSubscriptions?.push(...streams);\n\n return;\n }\n\n this.sendSubscriptionPayload(connection, streams, id);\n });\n }\n\n /**\n * Unsubscribes from one or multiple WebSocket streams\n * Handles both single and pool modes\n * @param stream Single stream name or array of stream names to unsubscribe from\n * @param id Optional unsubscription ID\n * @returns void\n */\n unsubscribe(stream: string | string[], id?: string): void {\n const streams = Array.isArray(stream) ? stream : [stream];\n\n streams.forEach((stream) => {\n const connection = this.streamConnectionMap.get(stream);\n if (!connection || !connection.ws || !this.isConnected(connection)) {\n this.logger.warn(`Stream ${stream} not associated with an active connection.`);\n return;\n }\n\n if (\n !this.streamCallbackMap.has(stream) ||\n this.streamCallbackMap.get(stream)?.size === 0\n ) {\n const payload = {\n method: 'UNSUBSCRIBE',\n params: [stream],\n id: id && /^[0-9a-f]{32}$/.test(id) ? id : randomString(),\n };\n this.logger.debug('UNSUBSCRIBE', payload);\n this.send(JSON.stringify(payload), undefined, false, 0, connection);\n\n this.streamConnectionMap.delete(stream);\n this.streamCallbackMap.delete(stream);\n }\n });\n }\n\n /**\n * Checks if the specified stream is currently subscribed.\n * @param stream - The name of the stream to check.\n * @returns `true` if the stream is currently subscribed, `false` otherwise.\n */\n isSubscribed(stream: string): boolean {\n return this.streamConnectionMap.has(stream);\n }\n}\n\nexport interface WebsocketStream<T> {\n /**\n * Attach a listener for the stream.\n * @param event - Event name (currently supports \"message\").\n * @param callback - Callback function to handle incoming data.\n */\n on(event: 'message', callback: (data: T) => void | Promise<void>): void;\n\n /**\n * Unsubscribe from the stream and clean up resources.\n */\n unsubscribe(): void;\n}\n\n/**\n * Creates a WebSocket stream handler for managing stream subscriptions and callbacks.\n *\n * @template T The type of data expected in the stream messages\n * @param {WebsocketAPIBase | WebsocketStreamsBase} websocketBase The WebSocket base instance\n * @param {string} streamOrId The stream identifier\n * @param {string} [id] Optional additional identifier\n * @returns {WebsocketStream<T>} A stream handler with methods to register callbacks and unsubscribe\n */\nexport function createStreamHandler<T>(\n websocketBase: WebsocketAPIBase | WebsocketStreamsBase,\n streamOrId: string,\n id?: string\n): WebsocketStream<T> {\n if (websocketBase instanceof WebsocketStreamsBase) websocketBase.subscribe(streamOrId, id);\n\n let registeredCallback: (data: unknown) => void;\n return {\n on: (event: 'message', callback: (data: T) => void | Promise<void>) => {\n if (event === 'message') {\n registeredCallback = (data: unknown) => {\n Promise.resolve(callback(data as T)).catch((err) => {\n websocketBase.logger.error(`Error in stream callback: ${err}`);\n });\n };\n const callbackSet = websocketBase.streamCallbackMap.get(streamOrId) ?? new Set();\n callbackSet.add(registeredCallback);\n websocketBase.streamCallbackMap.set(streamOrId, callbackSet);\n }\n },\n unsubscribe: () => {\n if (registeredCallback)\n websocketBase.streamCallbackMap.get(streamOrId)?.delete(registeredCallback);\n if (websocketBase instanceof WebsocketStreamsBase)\n websocketBase.unsubscribe(streamOrId, id);\n },\n };\n}\n"],"mappings":"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","names":["ConfigurationWebsocketAPI","fs","crypto","globalAxios","https","ConfigurationWebsocketAPI","LogLevel","WebSocketClient","delay","connection","stream","streams"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/configuration.ts","../src/constants.ts","../src/errors.ts","../src/logger.ts","../src/websocket.ts"],"sourcesContent":["export * from './configuration';\nexport * from './constants';\nexport * from './errors';\nexport * from './logger';\nexport * from './types';\nexport * from './utils';\nexport * from './websocket';\n","import crypto from 'crypto';\nimport fs from 'fs';\nimport https from 'https';\nimport { platform, arch } from 'os';\nimport {\n AxiosResponseHeaders,\n RawAxiosResponseHeaders,\n AxiosResponse,\n AxiosError,\n RawAxiosRequestConfig,\n} from 'axios';\nimport globalAxios from 'axios';\nimport {\n type ConfigurationRestAPI,\n type RestApiRateLimit,\n type RestApiResponse,\n TimeUnit,\n RequiredError,\n BadRequestError,\n ConnectorClientError,\n ForbiddenError,\n NetworkError,\n NotFoundError,\n RateLimitBanError,\n ServerError,\n TooManyRequestsError,\n UnauthorizedError,\n AxiosRequestArgs,\n SendMessageOptions,\n ObjectType,\n WebsocketSendMsgOptions,\n WebsocketSendMsgConfig,\n ConfigurationWebsocketAPI,\n Logger,\n} from '.';\n\n/**\n * A weak cache for storing RequestSigner instances based on configuration parameters.\n *\n * @remarks\n * Uses a WeakMap to cache and reuse RequestSigner instances for configurations with\n * apiSecret, privateKey, and privateKeyPassphrase, allowing efficient memory management.\n */\nlet signerCache = new WeakMap<\n {\n apiSecret?: string;\n privateKey?: string | Buffer;\n privateKeyPassphrase?: string;\n },\n RequestSigner\n>();\n\n/**\n * Represents a request signer for generating signatures using HMAC-SHA256 or asymmetric key signing.\n *\n * Supports two signing methods:\n * 1. HMAC-SHA256 using an API secret\n * 2. Asymmetric signing using RSA or ED25519 private keys\n *\n * @throws {Error} If neither API secret nor private key is provided, or if the private key is invalid\n */\nclass RequestSigner {\n private apiSecret?: string;\n private keyObject?: crypto.KeyObject;\n private keyType?: string;\n\n constructor(configuration: {\n apiSecret?: string;\n privateKey?: string | Buffer;\n privateKeyPassphrase?: string;\n }) {\n // HMAC-SHA256 path\n if (configuration.apiSecret && !configuration.privateKey) {\n this.apiSecret = configuration.apiSecret;\n return;\n }\n\n // Asymmetric path\n if (configuration.privateKey) {\n let privateKey: string | Buffer = configuration.privateKey;\n\n // If path, read file once\n if (typeof privateKey === 'string' && fs.existsSync(privateKey)) {\n privateKey = fs.readFileSync(privateKey, 'utf-8');\n }\n\n // Build KeyObject once\n const keyInput: crypto.PrivateKeyInput = { key: privateKey };\n if (\n configuration.privateKeyPassphrase &&\n typeof configuration.privateKeyPassphrase === 'string'\n ) {\n keyInput.passphrase = configuration.privateKeyPassphrase;\n }\n\n try {\n this.keyObject = crypto.createPrivateKey(keyInput);\n this.keyType = this.keyObject.asymmetricKeyType;\n } catch {\n throw new Error(\n 'Invalid private key. Please provide a valid RSA or ED25519 private key.'\n );\n }\n\n return;\n }\n\n throw new Error('Either \\'apiSecret\\' or \\'privateKey\\' must be provided for signed requests.');\n }\n\n sign(queryParams: object): string {\n const params = buildQueryString(queryParams);\n\n // HMAC-SHA256 signing\n if (this.apiSecret)\n return crypto.createHmac('sha256', this.apiSecret).update(params).digest('hex');\n\n // Asymmetric signing\n if (this.keyObject && this.keyType) {\n const data = Buffer.from(params);\n\n if (this.keyType === 'rsa')\n return crypto.sign('RSA-SHA256', data, this.keyObject).toString('base64');\n if (this.keyType === 'ed25519')\n return crypto.sign(null, data, this.keyObject).toString('base64');\n\n throw new Error('Unsupported private key type. Must be RSA or ED25519.');\n }\n\n throw new Error('Signer is not properly initialized.');\n }\n}\n\n/**\n * Resets the signer cache to a new empty WeakMap.\n *\n * This function clears the existing signer cache, creating a fresh WeakMap\n * to store RequestSigner instances associated with configuration objects.\n */\nexport const clearSignerCache = function (): void {\n signerCache = new WeakMap<\n {\n apiSecret?: string;\n privateKey?: string | Buffer;\n privateKeyPassphrase?: string;\n },\n RequestSigner\n >();\n};\n\n/**\n * Generates a query string from an object of parameters.\n *\n * @param params - An object containing the query parameters.\n * @returns The generated query string.\n */\nexport function buildQueryString(params: object): string {\n if (!params) return '';\n return Object.entries(params).map(stringifyKeyValuePair).join('&');\n}\n\n/**\n * Converts a key-value pair into a URL-encoded query parameter string.\n *\n * @param [key, value] - The key-value pair to be converted.\n * @returns The URL-encoded query parameter string.\n */\nfunction stringifyKeyValuePair([key, value]: [string, string]) {\n const valueString = Array.isArray(value) ? `[\"${value.join('\",\"')}\"]` : value;\n return `${key}=${encodeURIComponent(valueString)}`;\n}\n\n/**\n * Generates a random string of 16 hexadecimal characters.\n *\n * @returns A random string of 16 hexadecimal characters.\n */\nexport function randomString() {\n return crypto.randomBytes(16).toString('hex');\n}\n\n/**\n * Validates the provided time unit string and returns it if it is either 'MILLISECOND' or 'MICROSECOND'.\n *\n * @param timeUnit - The time unit string to be validated.\n * @returns The validated time unit string, or `undefined` if the input is falsy.\n * @throws {Error} If the time unit is not 'MILLISECOND' or 'MICROSECOND'.\n */\nexport function validateTimeUnit(timeUnit: string): string | undefined {\n if (!timeUnit) {\n return;\n } else if (\n timeUnit !== TimeUnit.MILLISECOND &&\n timeUnit !== TimeUnit.MICROSECOND &&\n timeUnit !== TimeUnit.millisecond &&\n timeUnit !== TimeUnit.microsecond\n ) {\n throw new Error('timeUnit must be either \\'MILLISECOND\\' or \\'MICROSECOND\\'');\n }\n\n return timeUnit;\n}\n\n/**\n * Delays the execution of the current function for the specified number of milliseconds.\n *\n * @param ms - The number of milliseconds to delay the function.\n * @returns A Promise that resolves after the specified delay.\n */\nexport async function delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Generates the current timestamp in milliseconds.\n *\n * @returns The current timestamp in milliseconds.\n */\nexport function getTimestamp(): number {\n return Date.now();\n}\n\n/**\n * Generates a signature for the given configuration and query parameters using a cached request signer.\n *\n * @param configuration - Configuration object containing API secret, private key, and optional passphrase.\n * @param queryParams - The query parameters to be signed.\n * @returns A string representing the generated signature.\n */\nexport const getSignature = function (\n configuration: {\n apiSecret?: string;\n privateKey?: string | Buffer;\n privateKeyPassphrase?: string;\n },\n queryParams: object\n): string {\n let signer = signerCache.get(configuration);\n if (!signer) {\n signer = new RequestSigner(configuration);\n signerCache.set(configuration, signer);\n }\n return signer.sign(queryParams);\n};\n\n/**\n * Asserts that a function parameter exists and is not null or undefined.\n *\n * @param functionName - The name of the function that the parameter belongs to.\n * @param paramName - The name of the parameter to check.\n * @param paramValue - The value of the parameter to check.\n * @throws {RequiredError} If the parameter is null or undefined.\n */\nexport const assertParamExists = function (\n functionName: string,\n paramName: string,\n paramValue: unknown\n) {\n if (paramValue === null || paramValue === undefined) {\n throw new RequiredError(\n paramName,\n `Required parameter ${paramName} was null or undefined when calling ${functionName}.`\n );\n }\n};\n\n/**\n * Recursively flattens an object or array into URL search parameters.\n *\n * This function handles nested objects and arrays by converting them into dot-notation query parameters.\n * It supports different types of parameters:\n * - Arrays can be stringified or recursively added\n * - Objects are flattened with dot notation keys\n * - Primitive values are converted to strings\n *\n * @param urlSearchParams The URLSearchParams object to modify\n * @param parameter The parameter to flatten (can be an object, array, or primitive)\n * @param key Optional key for nested parameters, used for creating dot-notation keys\n */\nexport function setFlattenedQueryParams(\n urlSearchParams: URLSearchParams,\n parameter: unknown,\n key: string = ''\n): void {\n if (parameter == null) return;\n\n // Array handling\n if (Array.isArray(parameter)) {\n if (key)\n // non-empty key: stringify the entire array\n urlSearchParams.set(key, JSON.stringify(parameter));\n else\n // empty key: recurse into each item without using an empty key\n for (const item of parameter) {\n setFlattenedQueryParams(urlSearchParams, item, '');\n }\n return;\n }\n\n // Object handling\n if (typeof parameter === 'object') {\n for (const subKey of Object.keys(parameter as Record<string, unknown>)) {\n const subVal = (parameter as Record<string, unknown>)[subKey];\n const newKey = key ? `${key}.${subKey}` : subKey;\n setFlattenedQueryParams(urlSearchParams, subVal, newKey);\n }\n return;\n }\n\n // Primitive handling\n const str = String(parameter);\n if (urlSearchParams.has(key)) urlSearchParams.append(key, str);\n else urlSearchParams.set(key, str);\n}\n\n/**\n * Sets the search parameters of the provided URL by flattening the given objects into the URL's search parameters.\n *\n * This function takes a URL and one or more objects, and updates the URL's search parameters by flattening the objects into key-value pairs. It uses the `setFlattenedQueryParams` function to recursively flatten the objects.\n *\n * @param url - The URL to update the search parameters for.\n * @param objects - One or more objects to flatten into the URL's search parameters.\n */\nexport const setSearchParams = function (url: URL, ...objects: Record<string, unknown>[]) {\n const searchParams = new URLSearchParams(url.search);\n setFlattenedQueryParams(searchParams, objects);\n url.search = searchParams.toString();\n};\n\n/**\n * Converts a URL object to a full path string, including pathname, search parameters, and hash.\n *\n * @param url The URL object to convert to a path string.\n * @returns A complete path string representation of the URL.\n */\nexport const toPathString = function (url: URL) {\n return url.pathname + url.search + url.hash;\n};\n\n/**\n * A type utility that transforms numbers in a type to their string representation when in scientific notation,\n * while preserving the structure of arrays and objects.\n *\n * @template T The input type to be transformed\n * @returns A type where numbers potentially become strings, maintaining the original type's structure\n */\ntype ScientificToString<T> = T extends number\n ? string | number\n : T extends Array<infer U>\n ? Array<ScientificToString<U>>\n : T extends object\n ? { [K in keyof T]: ScientificToString<T[K]> }\n : T;\n\n/**\n * Normalizes scientific notation numbers in an object or array to a fixed number of decimal places.\n *\n * This function recursively processes objects, arrays, and numbers, converting scientific notation\n * to a fixed decimal representation. Non-numeric values are left unchanged.\n *\n * @template T The type of the input object or value\n * @param obj The object, array, or value to normalize\n * @returns A new object or value with scientific notation numbers normalized\n */\nexport function normalizeScientificNumbers<T>(obj: T): ScientificToString<T> {\n if (Array.isArray(obj)) {\n return obj.map((item) => normalizeScientificNumbers(item)) as ScientificToString<T>;\n } else if (typeof obj === 'object' && obj !== null) {\n const result = {} as Record<string, unknown>;\n for (const key of Object.keys(obj)) {\n result[key] = normalizeScientificNumbers((obj as Record<string, unknown>)[key]);\n }\n return result as ScientificToString<T>;\n } else if (typeof obj === 'number') {\n if (!Number.isFinite(obj)) return obj as ScientificToString<T>;\n\n const abs = Math.abs(obj);\n if (abs === 0 || (abs >= 1e-6 && abs < 1e21)) return String(obj) as ScientificToString<T>;\n\n const isNegative = obj < 0;\n const [rawMantissa, rawExponent] = abs.toExponential().split('e');\n const exponent = +rawExponent;\n const digits = rawMantissa.replace('.', '');\n\n if (exponent < 0) {\n const zeros = '0'.repeat(Math.abs(exponent) - 1);\n return ((isNegative ? '-' : '') + '0.' + zeros + digits) as ScientificToString<T>;\n } else {\n const pad = exponent - (digits.length - 1);\n\n if (pad >= 0) {\n return ((isNegative ? '-' : '') +\n digits +\n '0'.repeat(pad)) as ScientificToString<T>;\n } else {\n const point = digits.length + pad;\n return ((isNegative ? '-' : '') +\n digits.slice(0, point) +\n '.' +\n digits.slice(point)) as ScientificToString<T>;\n }\n }\n } else {\n return obj as ScientificToString<T>;\n }\n}\n\n/**\n * Determines whether a request should be retried based on the provided error.\n *\n * This function checks the HTTP method, response status, and number of retries left to determine if a request should be retried.\n *\n * @param error The error object to check.\n * @param method The HTTP method of the request (optional).\n * @param retriesLeft The number of retries left (optional).\n * @returns `true` if the request should be retried, `false` otherwise.\n */\nexport const shouldRetryRequest = function (\n error: AxiosError | object,\n method?: string,\n retriesLeft?: number\n): boolean {\n const isRetriableMethod = ['GET', 'DELETE'].includes(method ?? '');\n const isRetriableStatus = [500, 502, 503, 504].includes(\n (error as AxiosError)?.response?.status ?? 0\n );\n return (\n (retriesLeft ?? 0) > 0 &&\n isRetriableMethod &&\n (isRetriableStatus || !(error as AxiosError)?.response)\n );\n};\n\n/**\n * Performs an HTTP request using the provided Axios instance and configuration.\n *\n * This function handles retries, rate limit handling, and error handling for the HTTP request.\n *\n * @param axiosArgs The request arguments to be passed to Axios.\n * @param configuration The configuration options for the request.\n * @returns A Promise that resolves to the API response, including the data and rate limit headers.\n */\nexport const httpRequestFunction = async function <T>(\n axiosArgs: AxiosRequestArgs,\n configuration?: ConfigurationRestAPI\n): Promise<RestApiResponse<T>> {\n const axiosRequestArgs = {\n ...axiosArgs.options,\n url: (globalAxios.defaults?.baseURL ? '' : (configuration?.basePath ?? '')) + axiosArgs.url,\n };\n\n if (configuration?.keepAlive && !configuration?.baseOptions?.httpsAgent)\n axiosRequestArgs.httpsAgent = new https.Agent({ keepAlive: true });\n\n if (configuration?.compression)\n axiosRequestArgs.headers = {\n ...axiosRequestArgs.headers,\n 'Accept-Encoding': 'gzip, deflate, br',\n };\n\n const retries = configuration?.retries ?? 0;\n const backoff = configuration?.backoff ?? 0;\n let attempt = 0;\n let lastError;\n\n while (attempt <= retries) {\n try {\n const response: AxiosResponse = await globalAxios.request({\n ...axiosRequestArgs,\n responseType: 'text',\n });\n const rateLimits: RestApiRateLimit[] = parseRateLimitHeaders(response.headers);\n return {\n data: async (): Promise<T> => {\n try {\n return JSON.parse(response.data) as T;\n } catch (err) {\n throw new Error(`Failed to parse JSON response: ${err}`);\n }\n },\n status: response.status,\n headers: response.headers as Record<string, string>,\n rateLimits,\n };\n } catch (error) {\n attempt++;\n const axiosError = error as AxiosError;\n\n if (\n shouldRetryRequest(\n axiosError,\n axiosRequestArgs?.method?.toUpperCase(),\n retries - attempt\n )\n ) {\n await delay(backoff * attempt);\n } else {\n if (axiosError.response && axiosError.response.status) {\n const status = axiosError.response?.status;\n const responseData = axiosError.response.data;\n\n let data: Record<string, unknown> = {};\n if (responseData && responseData !== null) {\n if (typeof responseData === 'string' && responseData !== '')\n try {\n data = JSON.parse(responseData);\n } catch {\n data = {};\n }\n else if (typeof responseData === 'object')\n data = responseData as Record<string, unknown>;\n }\n\n const errorMsg = (data as { msg?: string }).msg;\n\n switch (status) {\n case 400:\n throw new BadRequestError(errorMsg);\n case 401:\n throw new UnauthorizedError(errorMsg);\n case 403:\n throw new ForbiddenError(errorMsg);\n case 404:\n throw new NotFoundError(errorMsg);\n case 418:\n throw new RateLimitBanError(errorMsg);\n case 429:\n throw new TooManyRequestsError(errorMsg);\n default:\n if (status >= 500 && status < 600)\n throw new ServerError(`Server error: ${status}`, status);\n throw new ConnectorClientError(errorMsg);\n }\n } else {\n if (retries > 0 && attempt >= retries)\n lastError = new Error(`Request failed after ${retries} retries`);\n else lastError = new NetworkError('Network error or request timeout.');\n\n break;\n }\n }\n }\n }\n\n throw lastError;\n};\n\n/**\n * Parses the rate limit headers from the Axios response headers and returns an array of `RestApiRateLimit` objects.\n *\n * @param headers - The Axios response headers.\n * @returns An array of `RestApiRateLimit` objects containing the parsed rate limit information.\n */\nexport const parseRateLimitHeaders = function (\n headers: RawAxiosResponseHeaders | AxiosResponseHeaders\n): RestApiRateLimit[] {\n const rateLimits: RestApiRateLimit[] = [];\n\n const parseIntervalDetails = (\n key: string\n ): { interval: 'SECOND' | 'MINUTE' | 'HOUR' | 'DAY'; intervalNum: number } | null => {\n const match = key.match(/x-mbx-used-weight-(\\d+)([smhd])|x-mbx-order-count-(\\d+)([smhd])/i);\n if (!match) return null;\n\n const intervalNum = parseInt(match[1] || match[3], 10);\n const intervalLetter = (match[2] || match[4])?.toUpperCase();\n\n let interval: 'SECOND' | 'MINUTE' | 'HOUR' | 'DAY';\n switch (intervalLetter) {\n case 'S':\n interval = 'SECOND';\n break;\n case 'M':\n interval = 'MINUTE';\n break;\n case 'H':\n interval = 'HOUR';\n break;\n case 'D':\n interval = 'DAY';\n break;\n default:\n return null;\n }\n\n return { interval, intervalNum };\n };\n\n for (const [key, value] of Object.entries(headers)) {\n const normalizedKey = key.toLowerCase();\n if (value === undefined) continue;\n\n if (normalizedKey.startsWith('x-mbx-used-weight-')) {\n const details = parseIntervalDetails(normalizedKey);\n if (details) {\n rateLimits.push({\n rateLimitType: 'REQUEST_WEIGHT',\n interval: details.interval,\n intervalNum: details.intervalNum,\n count: parseInt(value, 10),\n });\n }\n } else if (normalizedKey.startsWith('x-mbx-order-count-')) {\n const details = parseIntervalDetails(normalizedKey);\n if (details) {\n rateLimits.push({\n rateLimitType: 'ORDERS',\n interval: details.interval,\n intervalNum: details.intervalNum,\n count: parseInt(value, 10),\n });\n }\n }\n }\n\n if (headers['retry-after']) {\n const retryAfter = parseInt(headers['retry-after'], 10);\n for (const limit of rateLimits) {\n limit.retryAfter = retryAfter;\n }\n }\n\n return rateLimits;\n};\n\n/**\n * Generic function to send a request with optional API key and signature.\n * @param endpoint - The API endpoint to call.\n * @param method - HTTP method to use (GET, POST, DELETE, etc.).\n * @param params - Query parameters for the request.\n * @param timeUnit - The time unit for the request.\n * @param options - Additional request options (isSigned).\n * @returns A promise resolving to the response data object.\n */\nexport const sendRequest = function <T>(\n configuration: ConfigurationRestAPI,\n endpoint: string,\n method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH',\n params: Record<string, unknown> = {},\n timeUnit?: TimeUnit,\n options: { isSigned?: boolean } = {}\n): Promise<RestApiResponse<T>> {\n const localVarUrlObj = new URL(endpoint, configuration?.basePath);\n const localVarRequestOptions: RawAxiosRequestConfig = {\n method,\n ...configuration?.baseOptions,\n };\n const localVarQueryParameter = { ...normalizeScientificNumbers(params) };\n\n if (options.isSigned) {\n const timestamp = getTimestamp();\n localVarQueryParameter['timestamp'] = timestamp;\n const signature = getSignature(configuration!, localVarQueryParameter);\n if (signature) {\n localVarQueryParameter['signature'] = signature;\n }\n }\n\n setSearchParams(localVarUrlObj, localVarQueryParameter);\n\n if (timeUnit && localVarRequestOptions.headers) {\n const _timeUnit = validateTimeUnit(timeUnit);\n localVarRequestOptions.headers = {\n ...localVarRequestOptions.headers,\n 'X-MBX-TIME-UNIT': _timeUnit,\n };\n }\n\n return httpRequestFunction<T>(\n {\n url: toPathString(localVarUrlObj),\n options: localVarRequestOptions,\n },\n configuration\n );\n};\n\n/**\n * Removes any null, undefined, or empty string values from the provided object.\n *\n * @param obj - The object to remove empty values from.\n * @returns A new object with empty values removed.\n */\nexport function removeEmptyValue(obj: object): SendMessageOptions {\n if (!(obj instanceof Object)) return {};\n return Object.fromEntries(\n Object.entries(obj).filter(\n ([, value]) => value !== null && value !== undefined && value !== ''\n )\n );\n}\n\n/**\n * Sorts the properties of the provided object in alphabetical order and returns a new object with the sorted properties.\n *\n * @param obj - The object to be sorted.\n * @returns A new object with the properties sorted in alphabetical order.\n */\nexport function sortObject(obj: ObjectType) {\n return Object.keys(obj)\n .sort()\n .reduce((res: ObjectType, key: string) => {\n res[key] = obj[key] as string | number | boolean | object;\n return res;\n }, {});\n}\n\n/**\n * Replaces placeholders in the format <field> with corresponding values from the provided variables object.\n *\n * @param {string} str - The input string containing placeholders.\n * @param {Object} variables - An object where keys correspond to placeholder names and values are the replacements.\n * @returns {string} - The resulting string with placeholders replaced by their corresponding values.\n */\nexport function replaceWebsocketStreamsPlaceholders(\n str: string,\n variables: Record<string, unknown>\n): string {\n const normalizedVariables = Object.keys(variables).reduce(\n (acc, key) => {\n const normalizedKey = key.toLowerCase().replace(/[-_]/g, '');\n acc[normalizedKey] = variables[key];\n return acc;\n },\n {} as Record<string, unknown>\n );\n\n return str.replace(/(@)?<([^>]+)>/g, (match, precedingAt, fieldName) => {\n const normalizedFieldName = fieldName.toLowerCase().replace(/[-_]/g, '');\n\n if (\n Object.prototype.hasOwnProperty.call(normalizedVariables, normalizedFieldName) &&\n normalizedVariables[normalizedFieldName] != null\n ) {\n const value = normalizedVariables[normalizedFieldName];\n\n switch (normalizedFieldName) {\n case 'symbol':\n case 'windowsize':\n return (value as string).toLowerCase();\n case 'updatespeed':\n return `@${value}`;\n default:\n return (precedingAt || '') + (value as string);\n }\n }\n\n return '';\n });\n}\n\n/**\n * Generates a standardized user agent string for the application.\n *\n * @param {string} packageName - The name of the package/application.\n * @param {string} packageVersion - The version of the package/application.\n * @returns {string} A formatted user agent string including package details, Node.js version, platform, and architecture.\n */\nexport function buildUserAgent(packageName: string, packageVersion: string): string {\n return `${packageName}/${packageVersion} (Node.js/${process.version}; ${platform()}; ${arch()})`;\n}\n\n/**\n * Builds a WebSocket API message with optional authentication and signature.\n *\n * @param {ConfigurationWebsocketAPI} configuration - The WebSocket API configuration.\n * @param {string} method - The method name for the WebSocket message.\n * @param {WebsocketSendMsgOptions} payload - The payload data to be sent.\n * @param {WebsocketSendMsgConfig} options - Configuration options for message sending.\n * @param {boolean} [skipAuth=false] - Flag to skip authentication if needed.\n * @returns {Object} A structured WebSocket message with id, method, and params.\n */\nexport function buildWebsocketAPIMessage(\n configuration: ConfigurationWebsocketAPI,\n method: string,\n payload: WebsocketSendMsgOptions,\n options: WebsocketSendMsgConfig,\n skipAuth: boolean = false\n): { id: string; method: string; params: Record<string, unknown> } {\n const id = payload.id && /^[0-9a-f]{32}$/.test(payload.id) ? payload.id : randomString();\n delete payload.id;\n\n let params = normalizeScientificNumbers(removeEmptyValue(payload));\n if ((options.withApiKey || options.isSigned) && !skipAuth) params.apiKey = configuration.apiKey;\n\n if (options.isSigned) {\n params.timestamp = getTimestamp();\n params = sortObject(params as ObjectType);\n if (!skipAuth) params.signature = getSignature(configuration!, params);\n }\n\n return { id, method, params };\n}\n\n/**\n * Sanitizes a header value by checking for and preventing carriage return and line feed characters.\n *\n * @param {string | string[]} value - The header value or array of header values to sanitize.\n * @returns {string | string[]} The sanitized header value(s).\n * @throws {Error} If the header value contains CR/LF characters.\n */\nexport function sanitizeHeaderValue(value: string | string[]): string | string[] {\n const sanitizeOne = (v: string) => {\n if (/\\r|\\n/.test(v)) throw new Error(`Invalid header value (contains CR/LF): \"${v}\"`);\n return v;\n };\n\n return Array.isArray(value) ? value.map(sanitizeOne) : sanitizeOne(value);\n}\n\n/**\n * Parses and sanitizes custom headers, filtering out forbidden headers.\n *\n * @param {Record<string, string | string[]>} headers - The input headers to be parsed.\n * @returns {Record<string, string | string[]>} A new object with sanitized and allowed headers.\n * @description Removes forbidden headers like 'host', 'authorization', and 'cookie',\n * and sanitizes remaining header values to prevent injection of carriage return or line feed characters.\n */\nexport function parseCustomHeaders(\n headers: Record<string, string | string[]>\n): Record<string, string | string[]> {\n if (!headers || Object.keys(headers).length === 0) return {};\n\n const forbidden = new Set(['host', 'authorization', 'cookie', ':method', ':path']);\n const parsedHeaders: Record<string, string | string[]> = {};\n\n for (const [rawName, rawValue] of Object.entries(headers || {})) {\n const name = rawName.trim();\n if (forbidden.has(name.toLowerCase())) {\n Logger.getInstance().warn(`Dropping forbidden header: ${name}`);\n continue;\n }\n\n try {\n parsedHeaders[name] = sanitizeHeaderValue(rawValue);\n } catch {\n continue;\n }\n }\n\n return parsedHeaders;\n}\n","import { Agent } from 'https';\nimport type { TimeUnit } from './constants';\nimport { parseCustomHeaders } from './utils';\n\nexport class ConfigurationRestAPI {\n /**\n * The API key used for authentication.\n * @memberof ConfigurationRestAPI\n */\n apiKey: string;\n /**\n * The API secret used for authentication.\n * @memberof ConfigurationRestAPI\n */\n apiSecret?: string;\n /**\n * override base path\n * @type {string}\n * @memberof ConfigurationRestAPI\n */\n basePath?: string;\n /**\n * set a timeout (in milliseconds) for the request\n * @default 1000\n * @type {number}\n * @memberof ConfigurationRestAPI\n */\n timeout?: number;\n /**\n * HTTP/HTTPS proxy configuration\n * @default false\n * @type {object}\n * @property {string} host - Proxy server hostname\n * @property {number} port - Proxy server port number\n * @property {string} protocol - Proxy server protocol\n * @property {object} [auth] - Proxy authentication credentials\n * @property {string} auth.username - Proxy authentication username\n * @property {string} auth.password - Proxy authentication password\n * @memberof ConfigurationRestAPI\n */\n proxy?: {\n host: string;\n port: number;\n protocol?: string;\n auth?: { username: string; password: string };\n };\n /**\n * Optional custom headers to be sent with the request\n * @default {}\n * @type {Record<string, string | string[]>}\n * @memberof ConfigurationRestAPI\n */\n customHeaders?: Record<string, string | string[]>;\n /**\n * enables keep-alive functionality for the connection (if httpsAgent is set then we use httpsAgent.keepAlive instead)\n * @default true\n * @type {boolean}\n * @memberof ConfigurationRestAPI\n */\n keepAlive?: boolean;\n /**\n * enables response compression\n * @default true\n * @type {boolean}\n * @memberof ConfigurationRestAPI\n */\n compression?: boolean;\n /**\n * number of retry attempts for failed requests\n * @default 3\n * @type {number}\n * @memberof ConfigurationRestAPI\n */\n retries?: number;\n /**\n * delay between retry attempts in milliseconds\n * @default 1000\n * @type {number}\n * @memberof ConfigurationRestAPI\n */\n backoff?: number;\n /**\n * https agent\n * @default false\n * @type {boolean | Agent}\n * @memberof ConfigurationRestAPI\n */\n httpsAgent?: boolean | Agent;\n /**\n * private key\n * @type {string | Buffer}\n * @memberof ConfigurationRestAPI\n */\n privateKey?: string | Buffer;\n /**\n * private key passphrase\n * @type {string}\n * @memberof ConfigurationRestAPI\n */\n privateKeyPassphrase?: string;\n /**\n * timeUnit (used only on SPOT API)\n * @type {TimeUnit}\n * @memberof ConfigurationRestAPI\n */\n timeUnit?: TimeUnit;\n /**\n * base options for axios calls\n * @type {Record<string, unknown>}\n * @memberof ConfigurationRestAPI\n * @internal\n */\n baseOptions?: Record<string, unknown>;\n\n constructor(param: ConfigurationRestAPI = { apiKey: '' }) {\n this.apiKey = param.apiKey;\n this.apiSecret = param.apiSecret;\n this.basePath = param.basePath;\n this.keepAlive = param.keepAlive ?? true;\n this.compression = param.compression ?? true;\n this.retries = param.retries ?? 3;\n this.backoff = param.backoff ?? 1000;\n this.privateKey = param.privateKey;\n this.privateKeyPassphrase = param.privateKeyPassphrase;\n this.timeUnit = param.timeUnit;\n this.baseOptions = {\n timeout: param.timeout ?? 1000,\n proxy: param.proxy && {\n host: param.proxy.host,\n port: param.proxy.port,\n ...(param.proxy.protocol && { protocol: param.proxy.protocol }),\n ...(param.proxy.auth && { auth: param.proxy.auth }),\n },\n httpsAgent: param.httpsAgent ?? false,\n headers: {\n ...parseCustomHeaders(param.customHeaders || {}),\n 'Content-Type': 'application/json',\n 'X-MBX-APIKEY': param.apiKey,\n },\n };\n }\n}\n\nexport class ConfigurationWebsocketAPI {\n /**\n * The API key used for authentication.\n * @memberof ConfigurationWebsocketAPI\n */\n apiKey: string;\n /**\n * The API secret used for authentication.\n * @memberof ConfigurationWebsocketAPI\n */\n apiSecret?: string;\n /**\n * override websocket url\n * @type {string}\n * @memberof ConfigurationWebsocketAPI\n */\n wsURL?: string;\n /**\n * set a timeout (in milliseconds) for the request\n * @default 5000\n * @type {number}\n * @memberof ConfigurationWebsocketAPI\n */\n timeout?: number;\n /**\n * reconnction delay\n * @default 5000\n * @type {number}\n * @memberof ConfigurationWebsocketAPI\n */\n reconnectDelay?: number;\n /**\n * use compression for websocket messages\n * @default true\n * @type {boolean}\n * @memberof ConfigurationWebsocketAPI\n */\n compression?: boolean;\n /**\n * websocket agent\n * @default false\n * @type {boolean | Agent}\n * @memberof ConfigurationWebsocketAPI\n */\n agent?: boolean | Agent;\n /**\n * the mode of the connection, either 'single' or 'pool'.\n * @default 'single'\n * @type {'single' | 'pool'}\n * @memberof ConfigurationWebsocketAPI\n */\n mode?: 'single' | 'pool';\n /**\n * the size of the connection pool, if the mode is set to 'pool'.\n * @default 1\n * @type {number}\n * @memberof ConfigurationWebsocketAPI\n */\n poolSize?: number;\n /**\n * private key\n * @type {string | Buffer}\n * @memberof ConfigurationWebsocketAPI\n */\n privateKey?: string | Buffer;\n /**\n * private key passphrase\n * @type {string}\n * @memberof ConfigurationWebsocketAPI\n */\n privateKeyPassphrase?: string;\n /**\n * timeUnit (used only on SPOT API)\n * @type {TimeUnit}\n * @memberof ConfigurationWebsocketAPI\n */\n timeUnit?: TimeUnit;\n /**\n * auto session re-logon on reconnects/renewals\n * @default true\n * @type {boolean}\n * @memberof ConfigurationWebsocketAPI\n */\n autoSessionReLogon?: boolean;\n /**\n * Optional user agent string for identifying the client\n * @type {string}\n * @memberof ConfigurationWebsocketStreams\n * @internal\n */\n userAgent?: string;\n\n constructor(param: ConfigurationWebsocketAPI = { apiKey: '' }) {\n this.apiKey = param.apiKey;\n this.apiSecret = param.apiSecret;\n this.wsURL = param.wsURL;\n this.timeout = param.timeout ?? 5000;\n this.reconnectDelay = param.reconnectDelay ?? 5000;\n this.compression = param.compression ?? true;\n this.agent = param.agent ?? false;\n this.mode = param.mode ?? 'single';\n this.poolSize = param.poolSize ?? 1;\n this.privateKey = param.privateKey;\n this.privateKeyPassphrase = param.privateKeyPassphrase;\n this.timeUnit = param.timeUnit;\n this.autoSessionReLogon = param.autoSessionReLogon ?? true;\n }\n}\n\nexport class ConfigurationWebsocketStreams {\n /**\n * override websocket url\n * @type {string}\n * @memberof ConfigurationWebsocketStreams\n */\n wsURL?: string;\n /**\n * reconnction delay\n * @default 5000\n * @type {number}\n * @memberof ConfigurationWebsocketStreams\n */\n reconnectDelay?: number;\n /**\n * use compression for websocket messages\n * @default true\n * @type {boolean}\n * @memberof ConfigurationWebsocketAPI\n */\n compression?: boolean;\n /**\n * websocket agent\n * @default false\n * @type {boolean | Agent}\n * @memberof ConfigurationWebsocketStreams\n */\n agent?: boolean | Agent;\n /**\n * the mode of the connection, either 'single' or 'pool'.\n * @default single\n * @type {'single' | 'pool'}\n * @memberof ConfigurationWebsocketStreams\n */\n mode?: 'single' | 'pool';\n /**\n * the size of the connection pool, if the mode is set to 'pool'.\n * @default 1\n * @type {number}\n * @memberof ConfigurationWebsocketStreams\n */\n poolSize?: number;\n /**\n * timeUnit (used only on SPOT API)\n * @type {TimeUnit}\n * @memberof ConfigurationWebsocketStreams\n */\n timeUnit?: TimeUnit;\n /**\n * Optional user agent string for identifying the client\n * @type {string}\n * @memberof ConfigurationWebsocketStreams\n * @internal\n */\n userAgent?: string;\n\n constructor(param: ConfigurationWebsocketStreams = {}) {\n this.wsURL = param.wsURL;\n this.reconnectDelay = param.reconnectDelay ?? 5000;\n this.compression = param.compression ?? true;\n this.agent = param.agent ?? false;\n this.mode = param.mode ?? 'single';\n this.poolSize = param.poolSize ?? 1;\n this.timeUnit = param.timeUnit;\n }\n}\n","export const TimeUnit = {\n MILLISECOND: 'MILLISECOND',\n millisecond: 'millisecond',\n MICROSECOND: 'MICROSECOND',\n microsecond: 'microsecond',\n} as const;\nexport type TimeUnit = (typeof TimeUnit)[keyof typeof TimeUnit];\n\n// Algo constants\nexport const ALGO_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Auto Invest constants\nexport const AUTO_INVEST_REST_API_PROD_URL = 'https://api.binance.com';\n\n// C2C constants\nexport const C2C_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Convert constants\nexport const CONVERT_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Copy Trading constants\nexport const COPY_TRADING_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Crypto Loan constants\nexport const CRYPTO_LOAN_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Derivatives Trading (COIN-M Futures) constants\nexport const DERIVATIVES_TRADING_COIN_FUTURES_REST_API_PROD_URL = 'https://dapi.binance.com';\nexport const DERIVATIVES_TRADING_COIN_FUTURES_REST_API_TESTNET_URL =\n 'https://testnet.binancefuture.com';\nexport const DERIVATIVES_TRADING_COIN_FUTURES_WS_API_PROD_URL =\n 'wss://ws-dapi.binance.com/ws-dapi/v1';\nexport const DERIVATIVES_TRADING_COIN_FUTURES_WS_API_TESTNET_URL =\n 'wss://testnet.binancefuture.com/ws-dapi/v1';\nexport const DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_PROD_URL = 'wss://dstream.binance.com';\nexport const DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_TESTNET_URL =\n 'wss://dstream.binancefuture.com';\n\n// Derivatives Trading (USDS Futures) constants\nexport const DERIVATIVES_TRADING_USDS_FUTURES_REST_API_PROD_URL = 'https://fapi.binance.com';\nexport const DERIVATIVES_TRADING_USDS_FUTURES_REST_API_TESTNET_URL =\n 'https://testnet.binancefuture.com';\nexport const DERIVATIVES_TRADING_USDS_FUTURES_WS_API_PROD_URL =\n 'wss://ws-fapi.binance.com/ws-fapi/v1';\nexport const DERIVATIVES_TRADING_USDS_FUTURES_WS_API_TESTNET_URL =\n 'wss://testnet.binancefuture.com/ws-fapi/v1';\nexport const DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_PROD_URL = 'wss://fstream.binance.com';\nexport const DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_TESTNET_URL =\n 'wss://stream.binancefuture.com';\n\n// Derivatives Trading (Options) constants\nexport const DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL = 'https://eapi.binance.com';\nexport const DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL =\n 'wss://nbstream.binance.com/eoptions';\n\n// Derivatives Trading (Portfolio Margin) constants\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL = 'https://papi.binance.com';\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_TESTNET_URL =\n 'https://testnet.binancefuture.com';\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_PROD_URL =\n 'wss://fstream.binance.com/pm';\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_TESTNET_URL =\n 'wss://fstream.binancefuture.com/pm';\n\n// Derivatives Trading (Portfolio Margin Pro) constants\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_REST_API_PROD_URL = 'https://api.binance.com';\nexport const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_WS_STREAMS_PROD_URL =\n 'wss://fstream.binance.com/pm-classic';\n\n// Dual Investment constants\nexport const DUAL_INVESTMENT_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Fiat constants\nexport const FIAT_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Gift Card constants\nexport const GIFT_CARD_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Margin Trading constants\nexport const MARGIN_TRADING_REST_API_PROD_URL = 'https://api.binance.com';\nexport const MARGIN_TRADING_WS_STREAMS_PROD_URL = 'wss://stream.binance.com:9443';\nexport const MARGIN_TRADING_RISK_WS_STREAMS_PROD_URL = 'wss://margin-stream.binance.com';\n\n// Mining constants\nexport const MINING_REST_API_PROD_URL = 'https://api.binance.com';\n\n// NFT constants\nexport const NFT_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Pay constants\nexport const PAY_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Rebate constants\nexport const REBATE_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Simple Earn constants\nexport const SIMPLE_EARN_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Spot constants\nexport const SPOT_REST_API_PROD_URL = 'https://api.binance.com';\nexport const SPOT_REST_API_TESTNET_URL = 'https://testnet.binance.vision';\nexport const SPOT_WS_API_PROD_URL = 'wss://ws-api.binance.com:443/ws-api/v3';\nexport const SPOT_WS_API_TESTNET_URL = 'wss://ws-api.testnet.binance.vision/ws-api/v3';\nexport const SPOT_WS_STREAMS_PROD_URL = 'wss://stream.binance.com:9443';\nexport const SPOT_WS_STREAMS_TESTNET_URL = 'wss://stream.testnet.binance.vision';\nexport const SPOT_REST_API_MARKET_URL = 'https://data-api.binance.vision';\nexport const SPOT_WS_STREAMS_MARKET_URL = 'wss://data-stream.binance.vision';\n\n// Staking constants\nexport const STAKING_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Sub Account constants\nexport const SUB_ACCOUNT_REST_API_PROD_URL = 'https://api.binance.com';\n\n// VIP Loan constants\nexport const VIP_LOAN_REST_API_PROD_URL = 'https://api.binance.com';\n\n// Wallet constants\nexport const WALLET_REST_API_PROD_URL = 'https://api.binance.com';\n","/**\n * Represents an error that occurred in the Connector client.\n * @param msg - An optional error message.\n */\nexport class ConnectorClientError extends Error {\n constructor(msg?: string) {\n super(msg || 'An unexpected error occurred.');\n Object.setPrototypeOf(this, ConnectorClientError.prototype);\n this.name = 'ConnectorClientError';\n }\n}\n\n/**\n * Represents an error that occurs when a required parameter is missing or undefined.\n * @param field - The name of the missing parameter.\n * @param msg - An optional error message.\n */\nexport class RequiredError extends Error {\n constructor(\n public field: string,\n msg?: string\n ) {\n super(msg || `Required parameter ${field} was null or undefined.`);\n Object.setPrototypeOf(this, RequiredError.prototype);\n this.name = 'RequiredError';\n }\n}\n\n/**\n * Represents an error that occurs when a client is unauthorized to access a resource.\n * @param msg - An optional error message.\n */\nexport class UnauthorizedError extends Error {\n constructor(msg?: string) {\n super(msg || 'Unauthorized access. Authentication required.');\n Object.setPrototypeOf(this, UnauthorizedError.prototype);\n this.name = 'UnauthorizedError';\n }\n}\n\n/**\n * Represents an error that occurs when a resource is forbidden to the client.\n * @param msg - An optional error message.\n */\nexport class ForbiddenError extends Error {\n constructor(msg?: string) {\n super(msg || 'Access to the requested resource is forbidden.');\n Object.setPrototypeOf(this, ForbiddenError.prototype);\n this.name = 'ForbiddenError';\n }\n}\n\n/**\n * Represents an error that occurs when client is doing too many requests.\n * @param msg - An optional error message.\n */\nexport class TooManyRequestsError extends Error {\n constructor(msg?: string) {\n super(msg || 'Too many requests. You are being rate-limited.');\n Object.setPrototypeOf(this, TooManyRequestsError.prototype);\n this.name = 'TooManyRequestsError';\n }\n}\n\n/**\n * Represents an error that occurs when client's IP has been banned.\n * @param msg - An optional error message.\n */\nexport class RateLimitBanError extends Error {\n constructor(msg?: string) {\n super(msg || 'The IP address has been banned for exceeding rate limits.');\n Object.setPrototypeOf(this, RateLimitBanError.prototype);\n this.name = 'RateLimitBanError';\n }\n}\n\n/**\n * Represents an error that occurs when there is an internal server error.\n * @param msg - An optional error message.\n * @param statusCode - An optional HTTP status code associated with the error.\n */\nexport class ServerError extends Error {\n constructor(\n msg?: string,\n public statusCode?: number\n ) {\n super(msg || 'An internal server error occurred.');\n Object.setPrototypeOf(this, ServerError.prototype);\n this.name = 'ServerError';\n }\n}\n\n/**\n * Represents an error that occurs when a network error occurs.\n * @param msg - An optional error message.\n */\nexport class NetworkError extends Error {\n constructor(msg?: string) {\n super(msg || 'A network error occurred.');\n Object.setPrototypeOf(this, NetworkError.prototype);\n this.name = 'NetworkError';\n }\n}\n\n/**\n * Represents an error that occurs when the requested resource was not found.\n * @param msg - An optional error message.\n */\nexport class NotFoundError extends Error {\n constructor(msg?: string) {\n super(msg || 'The requested resource was not found.');\n Object.setPrototypeOf(this, NotFoundError.prototype);\n this.name = 'NotFoundError';\n }\n}\n\n/**\n * Represents an error that occurs when a request is invalid or cannot be otherwise served.\n * @param msg - An optional error message.\n */\nexport class BadRequestError extends Error {\n constructor(msg?: string) {\n super(msg || 'The request was invalid or cannot be otherwise served.');\n Object.setPrototypeOf(this, BadRequestError.prototype);\n this.name = 'BadRequestError';\n }\n}\n","export enum LogLevel {\n NONE = '',\n DEBUG = 'debug',\n INFO = 'info',\n WARN = 'warn',\n ERROR = 'error',\n}\n\nexport class Logger {\n private static instance: Logger;\n private minLogLevel: LogLevel = LogLevel.INFO;\n private readonly levelsOrder: LogLevel[] = [\n LogLevel.NONE,\n LogLevel.DEBUG,\n LogLevel.INFO,\n LogLevel.WARN,\n LogLevel.ERROR,\n ];\n\n constructor() {\n const envLevel = process.env.LOG_LEVEL?.toLowerCase() as LogLevel | undefined;\n this.minLogLevel = envLevel && this.isValidLogLevel(envLevel) ? envLevel : LogLevel.INFO;\n }\n\n public static getInstance(): Logger {\n if (!Logger.instance) Logger.instance = new Logger();\n return Logger.instance;\n }\n\n public setMinLogLevel(level: LogLevel): void {\n if (!this.isValidLogLevel(level)) throw new Error(`Invalid log level: ${level}`);\n this.minLogLevel = level;\n }\n\n private isValidLogLevel(level: LogLevel): boolean {\n return this.levelsOrder.includes(level);\n }\n\n private log(level: LogLevel, ...message: unknown[]): void {\n if (level === LogLevel.NONE || !this.allowLevelLog(level)) return;\n\n const timestamp = new Date().toISOString();\n console[level](`[${timestamp}] [${level.toLowerCase()}]`, ...message);\n }\n\n private allowLevelLog(level: LogLevel): boolean {\n if (!this.isValidLogLevel(level)) throw new Error(`Invalid log level: ${level}`);\n\n const currentLevelIndex = this.levelsOrder.indexOf(level);\n const minLevelIndex = this.levelsOrder.indexOf(this.minLogLevel);\n return currentLevelIndex >= minLevelIndex;\n }\n\n public debug(...message: unknown[]): void {\n this.log(LogLevel.DEBUG, ...message);\n }\n\n public info(...message: unknown[]): void {\n this.log(LogLevel.INFO, ...message);\n }\n\n public warn(...message: unknown[]): void {\n this.log(LogLevel.WARN, ...message);\n }\n\n public error(...message: unknown[]): void {\n this.log(LogLevel.ERROR, ...message);\n }\n}\n","import { EventEmitter } from 'events';\nimport WebSocketClient from 'ws';\nimport { ClientRequestArgs } from 'http';\nimport {\n type ConfigurationWebsocketAPI,\n type ConfigurationWebsocketStreams,\n WebsocketApiResponse,\n Logger,\n delay,\n randomString,\n validateTimeUnit,\n buildWebsocketAPIMessage,\n} from '.';\n\nexport class WebsocketEventEmitter {\n private eventEmitter: EventEmitter;\n\n constructor() {\n this.eventEmitter = new EventEmitter();\n }\n\n /* eslint-disable @typescript-eslint/no-explicit-any */\n on(\n event: 'open' | 'message' | 'error' | 'close' | 'ping' | 'pong',\n listener: (...args: any[]) => void\n ): void {\n this.eventEmitter.on(event, listener);\n }\n\n /* eslint-disable @typescript-eslint/no-explicit-any */\n off(\n event: 'open' | 'message' | 'error' | 'close' | 'ping' | 'pong',\n listener: (...args: any[]) => void\n ): void {\n this.eventEmitter.off(event, listener);\n }\n\n /* eslint-disable @typescript-eslint/no-explicit-any */\n protected emit(\n event: 'open' | 'message' | 'error' | 'close' | 'ping' | 'pong',\n ...args: any[]\n ): void {\n this.eventEmitter.emit(event, ...args);\n }\n}\n\nexport interface TimerRecord {\n timer?: NodeJS.Timeout;\n type: 'timeout' | 'interval';\n}\n\nexport interface WebsocketConnection {\n id: string;\n reconnectionPending: boolean;\n renewalPending: boolean;\n closeInitiated: boolean;\n pendingRequests: Map<\n string,\n { resolve: (value: any) => void; reject: (reason?: unknown) => void }\n >;\n pendingSubscriptions?: string[];\n ws?: WebSocketClient;\n isSessionLoggedOn?: boolean;\n sessionLogonReq?: {\n method: string;\n payload: WebsocketSendMsgOptions;\n options: WebsocketSendMsgConfig;\n };\n}\n\nexport class WebsocketCommon extends WebsocketEventEmitter {\n private static readonly MAX_CONNECTION_DURATION = 23 * 60 * 60 * 1000;\n private readonly connectionQueue: Array<{\n connection: WebsocketConnection;\n url: string;\n isRenewal: boolean;\n }> = [];\n private queueProcessing: boolean = false;\n protected connectionTimers: Map<WebSocketClient, Set<TimerRecord>> = new Map();\n private mode: 'single' | 'pool';\n private poolSize: number;\n private roundRobinIndex = 0;\n connectionPool: WebsocketConnection[];\n logger: Logger = Logger.getInstance();\n\n constructor(\n protected configuration: ConfigurationWebsocketAPI | ConfigurationWebsocketStreams,\n connectionPool: WebsocketConnection[] = []\n ) {\n super();\n this.connectionPool = connectionPool;\n this.mode = this.configuration?.mode ?? 'single';\n this.poolSize =\n this.mode === 'pool' && this.configuration?.poolSize ? this.configuration.poolSize : 1;\n if (!connectionPool || connectionPool.length === 0) this.initializePool(this.poolSize);\n }\n\n /**\n * Initializes the WebSocket connection pool by creating a specified number of connection objects\n * and adding them to the `connectionPool` array. Each connection object has the following properties:\n * - `closeInitiated`: a boolean indicating whether the connection has been closed\n * - `reconnectionPending`: a boolean indicating whether a reconnection is pending\n * - `pendingRequests`: a Map that tracks pending requests for the connection\n * @param size - The number of connection objects to create and add to the pool.\n * @returns void\n */\n private initializePool(size: number): void {\n for (let i = 0; i < size; i++) {\n this.connectionPool.push({\n id: randomString(),\n closeInitiated: false,\n reconnectionPending: false,\n renewalPending: false,\n pendingRequests: new Map(),\n pendingSubscriptions: [],\n });\n }\n }\n\n /**\n * Retrieves available WebSocket connections based on the connection mode and readiness.\n * In 'single' mode, returns the first connection in the pool.\n * In 'pool' mode, filters and returns connections that are ready for use.\n * @param allowNonEstablishedWebsockets - Optional flag to include non-established WebSocket connections.\n * @returns An array of available WebSocket connections.\n */\n protected getAvailableConnections(\n allowNonEstablishedWebsockets: boolean = false\n ): WebsocketConnection[] {\n if (this.mode === 'single') return [this.connectionPool[0]];\n\n // Filter connections based on readiness and pending reconnection status\n const availableConnections = this.connectionPool.filter((connection) =>\n this.isConnectionReady(connection, allowNonEstablishedWebsockets)\n );\n\n return availableConnections;\n }\n\n /**\n * Gets a WebSocket connection from the pool or single connection.\n * If the connection mode is 'single', it returns the first connection in the pool.\n * If the connection mode is 'pool', it returns an available connection from the pool,\n * using a round-robin selection strategy. If no available connections are found, it throws an error.\n * @param allowNonEstablishedWebsockets - A boolean indicating whether to allow connections that are not established.\n * @returns {WebsocketConnection} The selected WebSocket connection.\n */\n protected getConnection(allowNonEstablishedWebsockets: boolean = false): WebsocketConnection {\n const availableConnections = this.getAvailableConnections(allowNonEstablishedWebsockets);\n\n if (availableConnections.length === 0) {\n throw new Error('No available Websocket connections are ready.');\n }\n\n // Select a connection using round-robin algorithm\n const selectedConnection =\n availableConnections[this.roundRobinIndex % availableConnections.length];\n this.roundRobinIndex = (this.roundRobinIndex + 1) % availableConnections.length;\n return selectedConnection!;\n }\n\n /**\n * Checks if the provided WebSocket connection is ready for use.\n * A connection is considered ready if it is open, has no pending reconnection, and has not been closed.\n * @param connection - The WebSocket connection to check.\n * @param allowNonEstablishedWebsockets - An optional flag to allow non-established WebSocket connections.\n * @returns `true` if the connection is ready, `false` otherwise.\n */\n protected isConnectionReady(\n connection: WebsocketConnection,\n allowNonEstablishedWebsockets: boolean = false\n ): boolean {\n return (\n (allowNonEstablishedWebsockets || connection.ws?.readyState === WebSocketClient.OPEN) &&\n !connection.reconnectionPending &&\n !connection.closeInitiated\n );\n }\n\n /**\n * Schedules a timer for a WebSocket connection and tracks it\n * @param connection WebSocket client instance\n * @param callback Function to execute when timer triggers\n * @param delay Time in milliseconds before callback execution\n * @param type Timer type ('timeout' or 'interval')\n * @returns Timer handle\n */\n protected scheduleTimer(\n connection: WebSocketClient,\n callback: () => void,\n delay: number,\n type: 'timeout' | 'interval' = 'timeout'\n ): NodeJS.Timeout {\n let timers = this.connectionTimers.get(connection);\n if (!timers) {\n timers = new Set<TimerRecord>();\n this.connectionTimers.set(connection, timers);\n }\n\n const timerRecord: TimerRecord = { type };\n\n const wrappedTimeout = () => {\n try {\n callback();\n } finally {\n timers!.delete(timerRecord);\n }\n };\n\n let timer: NodeJS.Timeout;\n if (type === 'timeout') timer = setTimeout(wrappedTimeout, delay);\n else timer = setInterval(callback, delay);\n\n timerRecord.timer = timer;\n timers.add(timerRecord);\n return timer;\n }\n\n /**\n * Clears all timers associated with a WebSocket connection.\n * @param connection - The WebSocket client instance to clear timers for.\n * @returns void\n */\n protected clearTimers(connection: WebSocketClient): void {\n const timers = this.connectionTimers.get(connection);\n if (timers) {\n timers.forEach(({ timer, type }) => {\n if (type === 'timeout') clearTimeout(timer);\n else if (type === 'interval') clearInterval(timer);\n });\n\n this.connectionTimers.delete(connection);\n }\n }\n\n /**\n * Processes the connection queue, reconnecting or renewing connections as needed.\n * This method is responsible for iterating through the connection queue and initiating\n * the reconnection or renewal process for each connection in the queue. It throttles\n * the queue processing to avoid overwhelming the server with too many connection\n * requests at once.\n * @param throttleRate - The time in milliseconds to wait between processing each\n * connection in the queue.\n * @returns A Promise that resolves when the queue has been fully processed.\n */\n private async processQueue(throttleRate: number = 1000): Promise<void> {\n if (this.queueProcessing) return;\n this.queueProcessing = true;\n\n while (this.connectionQueue.length > 0) {\n const { connection, url, isRenewal } = this.connectionQueue.shift()!;\n this.initConnect(url, isRenewal, connection);\n await delay(throttleRate);\n }\n\n this.queueProcessing = false;\n }\n\n /**\n * Enqueues a reconnection or renewal for a WebSocket connection.\n * This method adds the connection, URL, and renewal flag to the connection queue,\n * and then calls the `processQueue` method to initiate the reconnection or renewal\n * process.\n * @param connection - The WebSocket connection to reconnect or renew.\n * @param url - The URL to use for the reconnection or renewal.\n * @param isRenewal - A flag indicating whether this is a renewal (true) or a reconnection (false).\n */\n private enqueueReconnection(\n connection: WebsocketConnection,\n url: string,\n isRenewal: boolean\n ): void {\n this.connectionQueue.push({ connection, url, isRenewal });\n this.processQueue();\n }\n\n /**\n * Gracefully closes a WebSocket connection after pending requests complete.\n * This method waits for any pending requests to complete before closing the connection.\n * It sets up a timeout to force-close the connection after 30 seconds if the pending requests\n * do not complete. Once all pending requests are completed, the connection is closed.\n * @param connectionToClose - The WebSocket client instance to close.\n * @param WebsocketConnectionToClose - The WebSocket connection to close.\n * @param connection - The WebSocket connection to close.\n * @returns Promise that resolves when the connection is closed.\n */\n private async closeConnectionGracefully(\n WebsocketConnectionToClose: WebSocketClient,\n connection: WebsocketConnection\n ): Promise<void> {\n if (!WebsocketConnectionToClose || !connection) return;\n\n this.logger.debug(\n `Waiting for pending requests to complete before disconnecting websocket on connection ${connection.id}.`\n );\n\n const closePromise = new Promise<void>((resolve) => {\n this.scheduleTimer(\n WebsocketConnectionToClose,\n () => {\n this.logger.warn(\n `Force-closing websocket connection after 30 seconds on connection ${connection.id}.`\n );\n resolve();\n },\n 30000\n );\n\n this.scheduleTimer(\n WebsocketConnectionToClose,\n () => {\n if (connection.pendingRequests.size === 0) {\n this.logger.debug(\n `All pending requests completed, closing websocket connection on connection ${connection.id}.`\n );\n resolve();\n }\n },\n 1000,\n 'interval'\n );\n });\n\n await closePromise;\n\n this.logger.info(`Closing Websocket connection on connection ${connection.id}.`);\n WebsocketConnectionToClose.close();\n this.cleanup(WebsocketConnectionToClose);\n }\n\n /**\n * Attempts to re-establish a session for a WebSocket connection.\n * If a session logon request exists and the connection is not already logged on,\n * it sends an authentication request and updates the connection's logged-on status.\n * @param connection - The WebSocket connection to re-authenticate.\n * @private\n */\n private async sessionReLogon(connection: WebsocketConnection) {\n const req = connection.sessionLogonReq;\n if (req && !connection.isSessionLoggedOn) {\n const data = buildWebsocketAPIMessage(\n this.configuration as ConfigurationWebsocketAPI,\n req.method,\n req.payload,\n req.options\n );\n\n this.logger.debug(`Session re-logon on connection ${connection.id}`, data);\n\n try {\n await this.send(\n JSON.stringify(data),\n data.id,\n true,\n (this.configuration as ConfigurationWebsocketAPI).timeout,\n connection\n );\n this.logger.debug(\n `Session re-logon on connection ${connection.id} was successful.`\n );\n connection.isSessionLoggedOn = true;\n } catch (err) {\n this.logger.error(`Session re-logon on connection ${connection.id} failed:`, err);\n }\n }\n }\n\n /**\n * Cleans up WebSocket connection resources.\n * Removes all listeners and clears any associated timers for the provided WebSocket client.\n * @param ws - The WebSocket client to clean up.\n * @returns void\n */\n protected cleanup(ws: WebSocketClient): void {\n if (ws) {\n ws.removeAllListeners();\n this.clearTimers(ws);\n }\n }\n\n /**\n * Handles incoming WebSocket messages\n * @param data Raw message data received\n * @param connection Websocket connection\n */\n protected onMessage(data: string, connection: WebsocketConnection): void {\n this.emit('message', data.toString(), connection);\n }\n\n /**\n * Handles the opening of a WebSocket connection.\n * @param url - The URL of the WebSocket server.\n * @param targetConnection - The WebSocket connection being opened.\n * @param oldWSConnection - The WebSocket client instance associated with the old connection.\n */\n protected onOpen(\n url: string,\n targetConnection: WebsocketConnection,\n oldWSConnection: WebSocketClient\n ): void {\n this.logger.info(\n `Connected to the Websocket Server with id ${targetConnection.id}: ${url}`\n );\n if (targetConnection.renewalPending) {\n targetConnection.renewalPending = false;\n this.closeConnectionGracefully(oldWSConnection, targetConnection);\n } else if (targetConnection.closeInitiated) {\n this.closeConnectionGracefully(targetConnection.ws!, targetConnection);\n } else {\n this.emit('open', this);\n }\n this.sessionReLogon(targetConnection);\n }\n\n /**\n * Returns the URL to use when reconnecting.\n * Derived classes should override this to provide dynamic URLs.\n * @param defaultURL The URL originally passed during the first connection.\n * @param targetConnection The WebSocket connection being connected.\n * @returns The URL to reconnect to.\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected getReconnectURL(defaultURL: string, targetConnection: WebsocketConnection): string {\n return defaultURL;\n }\n\n /**\n * Connects all WebSocket connections in the pool\n * @param url - The Websocket server URL.\n * @returns A promise that resolves when all connections are established.\n */\n protected async connectPool(url: string): Promise<void> {\n const connectPromises = this.connectionPool.map(\n (connection) =>\n new Promise<void>((resolve, reject) => {\n this.initConnect(url, false, connection);\n\n connection.ws?.on('open', () => resolve());\n connection.ws?.on('error', (err) => reject(err));\n connection.ws?.on('close', () =>\n reject(new Error('Connection closed unexpectedly.'))\n );\n })\n );\n await Promise.all(connectPromises);\n }\n\n /**\n * Creates a new WebSocket client instance.\n * @param url - The URL to connect to.\n * @returns A new WebSocket client instance.\n */\n protected createWebSocket(url: string): WebSocketClient {\n const wsClientOptions: WebSocketClient.ClientOptions | ClientRequestArgs = {\n perMessageDeflate: this.configuration?.compression,\n agent: this.configuration?.agent,\n };\n if (this.configuration.userAgent)\n wsClientOptions.headers = { 'User-Agent': this.configuration.userAgent };\n\n return new WebSocketClient(url, wsClientOptions);\n }\n\n /**\n * Initializes a WebSocket connection.\n * @param url - The Websocket server URL.\n * @param isRenewal - Whether this is a connection renewal.\n * @param connection - An optional WebSocket connection to use.\n * @returns The WebSocket connection.\n */\n protected initConnect(\n url: string,\n isRenewal: boolean = false,\n connection?: WebsocketConnection\n ) {\n const targetConnection = connection || this.getConnection();\n\n if (targetConnection.renewalPending && isRenewal) {\n this.logger.warn(\n `Connection renewal with id ${targetConnection.id} is already in progress`\n );\n return;\n }\n\n if (\n targetConnection.ws &&\n targetConnection.ws.readyState === WebSocketClient.OPEN &&\n !isRenewal\n ) {\n this.logger.warn(`Connection with id ${targetConnection.id} already exists`);\n return;\n }\n\n const ws = this.createWebSocket(url);\n\n this.logger.info(\n `Establishing Websocket connection with id ${targetConnection.id} to: ${url}`\n );\n\n if (isRenewal) targetConnection.renewalPending = true;\n else targetConnection.ws = ws;\n\n targetConnection.isSessionLoggedOn = false;\n\n this.scheduleTimer(\n ws,\n () => {\n this.logger.info(`Renewing Websocket connection with id ${targetConnection.id}`);\n targetConnection.isSessionLoggedOn = false;\n this.enqueueReconnection(\n targetConnection,\n this.getReconnectURL(url, targetConnection),\n true\n );\n },\n WebsocketCommon.MAX_CONNECTION_DURATION\n );\n\n ws.on('open', () => {\n const oldWSConnection = targetConnection.ws;\n if (targetConnection.renewalPending) targetConnection.ws = ws;\n this.onOpen(url, targetConnection, oldWSConnection!);\n });\n\n ws.on('message', (data: WebSocketClient.Data) => {\n this.onMessage(data.toString(), targetConnection);\n });\n\n ws.on('ping', () => {\n this.logger.debug('Received PING from server');\n this.emit('ping');\n ws.pong();\n this.logger.debug('Responded PONG to server\\'s PING message');\n });\n\n ws.on('pong', () => {\n this.logger.debug('Received PONG from server');\n this.emit('pong');\n });\n\n ws.on('error', (err) => {\n this.logger.error('Received error from server');\n this.logger.error(err);\n this.emit('error', err);\n });\n\n ws.on('close', (closeEventCode, reason) => {\n this.emit('close', closeEventCode, reason);\n\n if (!targetConnection.closeInitiated && !isRenewal) {\n this.logger.warn(\n `Connection with id ${targetConnection.id} closed due to ${closeEventCode}: ${reason}`\n );\n this.scheduleTimer(\n ws,\n () => {\n this.logger.info(\n `Reconnecting conection with id ${targetConnection.id} to the server.`\n );\n targetConnection.isSessionLoggedOn = false;\n targetConnection.reconnectionPending = true;\n this.enqueueReconnection(\n targetConnection,\n this.getReconnectURL(url, targetConnection),\n false\n );\n },\n this.configuration?.reconnectDelay ?? 5000\n );\n }\n });\n\n return targetConnection;\n }\n\n /**\n * Checks if the WebSocket connection is currently open.\n * @param connection - An optional WebSocket connection to check. If not provided, the entire connection pool is checked.\n * @returns `true` if the connection is open, `false` otherwise.\n */\n isConnected(connection?: WebsocketConnection): boolean {\n const connectionPool = connection ? [connection] : this.connectionPool;\n return connectionPool.some((connection) => this.isConnectionReady(connection));\n }\n\n /**\n * Disconnects from the WebSocket server.\n * If there is no active connection, a warning is logged.\n * Otherwise, all connections in the connection pool are closed gracefully,\n * and a message is logged indicating that the connection has been disconnected.\n * @returns A Promise that resolves when all connections have been closed.\n * @throws Error if the WebSocket client is not set.\n */\n async disconnect(): Promise<void> {\n if (!this.isConnected()) this.logger.warn('No connection to close.');\n else {\n this.connectionPool.forEach((connection) => {\n connection.closeInitiated = true;\n connection.isSessionLoggedOn = false;\n connection.sessionLogonReq = undefined;\n });\n\n const disconnectPromises = this.connectionPool.map((connection: WebsocketConnection) =>\n this.closeConnectionGracefully(connection.ws!, connection)\n );\n\n await Promise.all(disconnectPromises);\n this.logger.info('Disconnected with Binance Websocket Server');\n }\n }\n\n /**\n * Sends a ping message to all connected Websocket servers in the pool.\n * If no connections are ready, a warning is logged.\n * For each active connection, the ping message is sent, and debug logs provide details.\n * @throws Error if a Websocket client is not set for a connection.\n */\n pingServer(): void {\n const connectedConnections = this.connectionPool.filter((connection) =>\n this.isConnected(connection)\n );\n\n if (connectedConnections.length === 0) {\n this.logger.warn('Ping only can be sent when connection is ready.');\n return;\n }\n\n this.logger.debug('Sending PING to all connected Websocket servers.');\n\n connectedConnections.forEach((connection) => {\n if (connection.ws) {\n connection.ws.ping();\n this.logger.debug(`PING sent to connection with id ${connection.id}`);\n } else {\n this.logger.error('WebSocket Client not set for a connection.');\n }\n });\n }\n\n /**\n * Sends a payload through the WebSocket connection.\n * @param payload - Message to send.\n * @param id - Optional request identifier.\n * @param promiseBased - Whether to return a promise.\n * @param timeout - Timeout duration in milliseconds.\n * @param connection - The WebSocket connection to use.\n * @returns A promise if `promiseBased` is true, void otherwise.\n * @throws Error if not connected or WebSocket client is not set.\n */\n protected send<T = unknown>(\n payload: string,\n id?: string,\n promiseBased: boolean = true,\n timeout: number = 5000,\n connection?: WebsocketConnection\n ): Promise<WebsocketApiResponse<T>> | void {\n if (!this.isConnected(connection)) {\n const errorMsg = 'Unable to send message — connection is not available.';\n this.logger.warn(errorMsg);\n if (promiseBased) return Promise.reject(new Error(errorMsg));\n else throw new Error(errorMsg);\n }\n\n const connectionToUse: WebsocketConnection = connection ?? this.getConnection();\n\n if (!connectionToUse.ws) {\n const errorMsg = 'Websocket Client not set';\n this.logger.error(errorMsg);\n if (promiseBased) return Promise.reject(new Error(errorMsg));\n else throw new Error(errorMsg);\n }\n\n connectionToUse.ws.send(payload);\n\n if (promiseBased) {\n return new Promise<WebsocketApiResponse<T>>((resolve, reject) => {\n if (!id) return reject(new Error('id is required for promise-based sending.'));\n\n const timeoutHandle = setTimeout(() => {\n if (connectionToUse.pendingRequests.has(id)) {\n connectionToUse.pendingRequests.delete(id);\n reject(new Error(`Request timeout for id: ${id}`));\n }\n }, timeout);\n\n connectionToUse.pendingRequests.set(id, {\n resolve: (v) => {\n clearTimeout(timeoutHandle);\n resolve(v);\n },\n reject: (e) => {\n clearTimeout(timeoutHandle);\n reject(e);\n },\n });\n });\n }\n }\n}\n\nexport interface WebsocketSendMsgOptions {\n id?: string;\n [key: string]: string | number | boolean | object | undefined;\n}\n\nexport interface WebsocketSendMsgConfig {\n withApiKey?: boolean;\n isSigned?: boolean;\n isSessionLogon?: boolean;\n isSessionLogout?: boolean;\n}\n\nexport class WebsocketAPIBase extends WebsocketCommon {\n private isConnecting: boolean = false;\n streamCallbackMap: Map<string, Set<(data: unknown) => void>> = new Map();\n configuration: ConfigurationWebsocketAPI;\n logger: Logger = Logger.getInstance();\n\n constructor(\n configuration: ConfigurationWebsocketAPI,\n connectionPool: WebsocketConnection[] = []\n ) {\n super(configuration, connectionPool);\n this.configuration = configuration;\n }\n\n /**\n * Prepares the WebSocket URL by adding optional timeUnit parameter\n * @param wsUrl The base WebSocket URL\n * @returns The formatted WebSocket URL with parameters\n */\n private prepareURL(wsUrl: string): string {\n let url = wsUrl;\n if (this?.configuration.timeUnit) {\n try {\n const _timeUnit = validateTimeUnit(this.configuration.timeUnit);\n url = `${url}${url.includes('?') ? '&' : '?'}timeUnit=${_timeUnit}`;\n } catch (err) {\n this.logger.error(err);\n }\n }\n return url;\n }\n\n /**\n * Processes incoming WebSocket messages\n * @param data The raw message data received\n */\n protected onMessage<T>(data: string, connection: WebsocketConnection): void {\n try {\n const message = JSON.parse(data);\n const { id, status } = message;\n\n if (id && connection.pendingRequests.has(id)) {\n const request = connection.pendingRequests.get(id);\n connection.pendingRequests.delete(id);\n\n if (status && status >= 400) {\n request?.reject(message.error);\n } else {\n const response: WebsocketApiResponse<T> = {\n data: message.result ?? message.response,\n ...(message.rateLimits && { rateLimits: message.rateLimits }),\n };\n request?.resolve(response);\n }\n } else if (\n 'event' in message &&\n 'e' in message['event'] &&\n this.streamCallbackMap.size > 0\n ) {\n // Handle user data stream messages (currently with no ID we send the message to all registered callbacks)\n this.streamCallbackMap.forEach((callbacks) =>\n callbacks.forEach((callback) => callback(message['event']))\n );\n } else {\n this.logger.warn('Received response for unknown or timed-out request:', message);\n }\n } catch (error) {\n this.logger.error('Failed to parse WebSocket message:', data, error);\n }\n\n super.onMessage(data, connection);\n }\n\n /**\n * Establishes a WebSocket connection to Binance\n * @returns Promise that resolves when connection is established\n * @throws Error if connection times out\n */\n connect(): Promise<void> {\n if (this.isConnected()) {\n this.logger.info('WebSocket connection already established');\n return Promise.resolve();\n }\n\n return new Promise((resolve, reject) => {\n if (this.isConnecting) return;\n\n this.isConnecting = true;\n\n const timeout = setTimeout(() => {\n this.isConnecting = false;\n reject(new Error('Websocket connection timed out'));\n }, 10000);\n\n this.connectPool(this.prepareURL(this.configuration.wsURL as string))\n .then(() => {\n this.isConnecting = false;\n resolve();\n })\n .catch((error) => {\n this.isConnecting = false;\n reject(error);\n })\n .finally(() => {\n clearTimeout(timeout);\n });\n });\n }\n\n sendMessage<T>(\n method: string,\n payload: WebsocketSendMsgOptions,\n options: WebsocketSendMsgConfig & { isSessionLogon: true }\n ): Promise<WebsocketApiResponse<T>[]>;\n\n sendMessage<T>(\n method: string,\n payload: WebsocketSendMsgOptions,\n options: WebsocketSendMsgConfig & { isSessionLogout: true }\n ): Promise<WebsocketApiResponse<T>[]>;\n\n sendMessage<T>(\n method: string,\n payload?: WebsocketSendMsgOptions,\n options?: WebsocketSendMsgConfig\n ): Promise<WebsocketApiResponse<T>>;\n\n async sendMessage<T>(\n method: string,\n payload: WebsocketSendMsgOptions = {},\n options: WebsocketSendMsgConfig = {}\n ): Promise<WebsocketApiResponse<T> | WebsocketApiResponse<T>[]> {\n if (!this.isConnected()) {\n throw new Error('Not connected');\n }\n\n const isSessionReq = options.isSessionLogon || options.isSessionLogout;\n\n const connections: WebsocketConnection[] = isSessionReq\n ? this.getAvailableConnections()\n : [this.getConnection()];\n\n const skipAuth = isSessionReq\n ? false\n : this.configuration.autoSessionReLogon && connections[0].isSessionLoggedOn;\n\n const data = buildWebsocketAPIMessage(\n this.configuration,\n method,\n payload,\n options,\n skipAuth\n );\n\n this.logger.debug('Send message to Binance WebSocket API Server:', data);\n\n const responses = await Promise.all(\n connections.map(\n (connection) =>\n this.send<T>(\n JSON.stringify(data),\n data.id,\n true,\n this.configuration.timeout,\n connection\n ) as Promise<WebsocketApiResponse<T>>\n )\n );\n\n if (isSessionReq && this.configuration.autoSessionReLogon) {\n connections.forEach((connection) => {\n if (options.isSessionLogon) {\n connection.isSessionLoggedOn = true;\n connection.sessionLogonReq = { method, payload, options };\n } else {\n connection.isSessionLoggedOn = false;\n connection.sessionLogonReq = undefined;\n }\n });\n }\n\n return connections.length === 1 && !isSessionReq ? responses[0] : responses;\n }\n}\n\nexport class WebsocketStreamsBase extends WebsocketCommon {\n private streamConnectionMap: Map<string, WebsocketConnection> = new Map();\n protected configuration: ConfigurationWebsocketStreams;\n protected wsURL: string;\n streamCallbackMap: Map<string, Set<(data: unknown) => void>> = new Map();\n logger: Logger = Logger.getInstance();\n\n constructor(\n configuration: ConfigurationWebsocketStreams,\n connectionPool: WebsocketConnection[] = []\n ) {\n super(configuration, connectionPool);\n this.configuration = configuration;\n this.wsURL = configuration.wsURL as string;\n }\n\n /**\n * Formats the WebSocket URL for a given stream or streams.\n * @param streams - Array of stream names to include in the URL.\n * @returns The formatted WebSocket URL with the provided streams.\n */\n private prepareURL(streams: string[] = []): string {\n let url = `${this.wsURL}/stream?streams=${streams.join('/')}`;\n\n if (this.configuration?.timeUnit) {\n try {\n const _timeUnit = validateTimeUnit(this.configuration.timeUnit);\n url = `${url}${url.includes('?') ? '&' : '?'}timeUnit=${_timeUnit}`;\n } catch (err) {\n this.logger.error(err);\n }\n }\n\n return url;\n }\n\n /**\n * Formats the WebSocket URL with stream and configuration parameters to be used for reconnection.\n * @param url - The base WebSocket URL.\n * @param targetConnection - The target WebSocket connection.\n * @returns The formatted WebSocket URL with streams and optional parameters.\n */\n protected getReconnectURL(url: string, targetConnection: WebsocketConnection): string {\n const streams = Array.from(this.streamConnectionMap.keys()).filter(\n (stream) => this.streamConnectionMap.get(stream) === targetConnection\n );\n return this.prepareURL(streams);\n }\n\n /**\n * Handles subscription to streams and assigns them to specific connections\n * @param streams Array of stream names to subscribe to\n * @returns Map of connections to streams\n */\n private handleStreamAssignment(streams: string[]): Map<WebsocketConnection, string[]> {\n const connectionStreamMap = new Map<WebsocketConnection, string[]>();\n\n streams.forEach((stream) => {\n if (!this.streamCallbackMap.has(stream)) this.streamCallbackMap.set(stream, new Set());\n\n let connection = this.streamConnectionMap.get(stream);\n\n if (!connection || connection.closeInitiated || connection.reconnectionPending) {\n connection = this.getConnection(true);\n this.streamConnectionMap.set(stream, connection);\n }\n\n if (!connectionStreamMap.has(connection)) connectionStreamMap.set(connection, []);\n\n connectionStreamMap.get(connection)?.push(stream);\n });\n\n return connectionStreamMap;\n }\n\n /**\n * Sends a subscription payload for specified streams on a given connection.\n * @param connection The WebSocket connection to use for sending the subscription.\n * @param streams The streams to subscribe to.\n * @param id Optional ID for the subscription.\n */\n private sendSubscriptionPayload(\n connection: WebsocketConnection,\n streams: string[],\n id?: string\n ): void {\n const payload = {\n method: 'SUBSCRIBE',\n params: streams,\n id: id && /^[0-9a-f]{32}$/.test(id) ? id : randomString(),\n };\n this.logger.debug('SUBSCRIBE', payload);\n this.send(JSON.stringify(payload), undefined, false, 0, connection);\n }\n\n /**\n * Processes pending subscriptions for a given connection.\n * Sends all queued subscriptions in a single payload.\n * @param connection The WebSocket connection to process.\n */\n private processPendingSubscriptions(connection: WebsocketConnection): void {\n if (connection.pendingSubscriptions && connection.pendingSubscriptions.length > 0) {\n this.logger.info('Processing queued subscriptions for connection');\n this.sendSubscriptionPayload(connection, connection.pendingSubscriptions);\n connection.pendingSubscriptions = [];\n }\n }\n\n /**\n * Handles incoming WebSocket messages, parsing the data and invoking the appropriate callback function.\n * If the message contains a stream name that is registered in the `streamCallbackMap`, the corresponding\n * callback function is called with the message data.\n * If the message cannot be parsed, an error is logged.\n * @param data The raw WebSocket message data.\n * @param connection The WebSocket connection that received the message.\n */\n protected onMessage(data: string, connection: WebsocketConnection): void {\n try {\n const parsedData = JSON.parse(data);\n const streamName = parsedData?.stream;\n\n if (streamName && this.streamCallbackMap.has(streamName))\n this.streamCallbackMap\n .get(streamName)\n ?.forEach((callback) => callback(parsedData.data));\n } catch (error) {\n this.logger.error('Failed to parse WebSocket message:', data, error);\n }\n\n super.onMessage(data, connection);\n }\n\n /**\n * Called when the WebSocket connection is opened.\n * Processes any pending subscriptions for the target connection.\n * @param url The URL of the WebSocket connection.\n * @param targetConnection The WebSocket connection that was opened.\n * @param oldConnection The previous WebSocket connection, if any.\n */\n protected onOpen(\n url: string,\n targetConnection: WebsocketConnection,\n oldWSConnection: WebSocketClient\n ): void {\n this.processPendingSubscriptions(targetConnection);\n super.onOpen(url, targetConnection, oldWSConnection);\n }\n\n /**\n * Connects to the WebSocket server and subscribes to the specified streams.\n * This method returns a Promise that resolves when the connection is established,\n * or rejects with an error if the connection fails to be established within 10 seconds.\n * @param stream - A single stream name or an array of stream names to subscribe to.\n * @returns A Promise that resolves when the connection is established.\n */\n connect(stream: string | string[] = []): Promise<void> {\n const streams = Array.isArray(stream) ? stream : [stream];\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error('Websocket connection timed out'));\n }, 10000);\n\n this.connectPool(this.prepareURL(streams))\n .then(() => resolve())\n .catch((error) => reject(error))\n .finally(() => clearTimeout(timeout));\n });\n }\n\n /**\n * Disconnects the WebSocket connection and clears the stream callback map.\n * This method is called to clean up the connection and associated resources.\n */\n async disconnect(): Promise<void> {\n this.streamCallbackMap.clear();\n this.streamConnectionMap.clear();\n super.disconnect();\n }\n\n /**\n * Subscribes to one or multiple WebSocket streams\n * Handles both single and pool modes\n * @param stream Single stream name or array of stream names to subscribe to\n * @param id Optional subscription ID\n * @returns void\n */\n subscribe(stream: string | string[], id?: string): void {\n const streams = (Array.isArray(stream) ? stream : [stream]).filter(\n (stream) => !this.streamConnectionMap.has(stream)\n );\n const connectionStreamMap = this.handleStreamAssignment(streams);\n\n connectionStreamMap.forEach((streams, connection) => {\n if (!this.isConnected(connection)) {\n this.logger.info(\n `Connection ${connection.id} is not ready. Queuing subscription for streams: ${streams}`\n );\n connection.pendingSubscriptions?.push(...streams);\n\n return;\n }\n\n this.sendSubscriptionPayload(connection, streams, id);\n });\n }\n\n /**\n * Unsubscribes from one or multiple WebSocket streams\n * Handles both single and pool modes\n * @param stream Single stream name or array of stream names to unsubscribe from\n * @param id Optional unsubscription ID\n * @returns void\n */\n unsubscribe(stream: string | string[], id?: string): void {\n const streams = Array.isArray(stream) ? stream : [stream];\n\n streams.forEach((stream) => {\n const connection = this.streamConnectionMap.get(stream);\n if (!connection || !connection.ws || !this.isConnected(connection)) {\n this.logger.warn(`Stream ${stream} not associated with an active connection.`);\n return;\n }\n\n if (\n !this.streamCallbackMap.has(stream) ||\n this.streamCallbackMap.get(stream)?.size === 0\n ) {\n const payload = {\n method: 'UNSUBSCRIBE',\n params: [stream],\n id: id && /^[0-9a-f]{32}$/.test(id) ? id : randomString(),\n };\n this.logger.debug('UNSUBSCRIBE', payload);\n this.send(JSON.stringify(payload), undefined, false, 0, connection);\n\n this.streamConnectionMap.delete(stream);\n this.streamCallbackMap.delete(stream);\n }\n });\n }\n\n /**\n * Checks if the specified stream is currently subscribed.\n * @param stream - The name of the stream to check.\n * @returns `true` if the stream is currently subscribed, `false` otherwise.\n */\n isSubscribed(stream: string): boolean {\n return this.streamConnectionMap.has(stream);\n }\n}\n\nexport interface WebsocketStream<T> {\n /**\n * Attach a listener for the stream.\n * @param event - Event name (currently supports \"message\").\n * @param callback - Callback function to handle incoming data.\n */\n on(event: 'message', callback: (data: T) => void | Promise<void>): void;\n\n /**\n * Unsubscribe from the stream and clean up resources.\n */\n unsubscribe(): void;\n}\n\n/**\n * Creates a WebSocket stream handler for managing stream subscriptions and callbacks.\n *\n * @template T The type of data expected in the stream messages\n * @param {WebsocketAPIBase | WebsocketStreamsBase} websocketBase The WebSocket base instance\n * @param {string} streamOrId The stream identifier\n * @param {string} [id] Optional additional identifier\n * @returns {WebsocketStream<T>} A stream handler with methods to register callbacks and unsubscribe\n */\nexport function createStreamHandler<T>(\n websocketBase: WebsocketAPIBase | WebsocketStreamsBase,\n streamOrId: string,\n id?: string\n): WebsocketStream<T> {\n if (websocketBase instanceof WebsocketStreamsBase) websocketBase.subscribe(streamOrId, id);\n\n let registeredCallback: (data: unknown) => void;\n return {\n on: (event: 'message', callback: (data: T) => void | Promise<void>) => {\n if (event === 'message') {\n registeredCallback = (data: unknown) => {\n Promise.resolve(callback(data as T)).catch((err) => {\n websocketBase.logger.error(`Error in stream callback: ${err}`);\n });\n };\n const callbackSet = websocketBase.streamCallbackMap.get(streamOrId) ?? new Set();\n callbackSet.add(registeredCallback);\n websocketBase.streamCallbackMap.set(streamOrId, callbackSet);\n }\n },\n unsubscribe: () => {\n if (registeredCallback)\n websocketBase.streamCallbackMap.get(streamOrId)?.delete(registeredCallback);\n if (websocketBase instanceof WebsocketStreamsBase)\n websocketBase.unsubscribe(streamOrId, id);\n },\n };\n}\n"],"mappings":"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","names":["ConfigurationWebsocketAPI","fs","crypto","globalAxios","https","ConfigurationWebsocketAPI","LogLevel","WebSocketClient","delay","connection","stream","streams"]}
|