+ public static async promiseWithTimeout<T>(
+ promise: Promise<T>,
+ timeoutMs: number,
+ timeoutError: Error,
+ timeoutCallback: () => void = () => {
+ /* This is intentional */
+ }
+ ): Promise<T> {
+ // Create a timeout promise that rejects in timeout milliseconds
+ const timeoutPromise = new Promise<never>((_, reject) => {
+ setTimeout(() => {
+ timeoutCallback();
+ reject(timeoutError);
+ }, timeoutMs);
+ });
+
+ // Returns a race between timeout promise and the passed promise
+ return Promise.race<T>([promise, timeoutPromise]);
+ }
+
+ /**
+ * Generate a cryptographically secure random number in the [0,1[ range
+ *
+ * @returns
+ */
+ public static secureRandom(): number {
+ return crypto.randomBytes(4).readUInt32LE() / 0x100000000;
+ }
+
+ public static JSONStringifyWithMapSupport(
+ obj: Record<string, unknown> | Record<string, unknown>[],
+ space?: number
+ ): string {
+ return JSON.stringify(
+ obj,
+ (key, value: Record<string, unknown>) => {
+ if (value instanceof Map) {
+ return {
+ dataType: 'Map',
+ value: [...value],
+ };
+ }
+ return value;
+ },
+ space
+ );
+ }
+
+ /**
+ * Convert websocket error code to human readable string message
+ *
+ * @param code websocket error code
+ * @returns human readable string message
+ */
+ public static getWebSocketCloseEventStatusString(code: number): string {