+import { getRandomValues, randomBytes, randomInt, randomUUID } from 'node:crypto';
+import { env, nextTick } from 'node:process';
+
+import {
+ formatDuration,
+ hoursToMinutes,
+ hoursToSeconds,
+ isDate,
+ millisecondsToHours,
+ millisecondsToMinutes,
+ millisecondsToSeconds,
+ minutesToSeconds,
+ secondsToMilliseconds,
+} from 'date-fns';
+
+import { Constants } from './Constants';
+import { type TimestampedData, WebSocketCloseEventStatusString } from '../types';
+
+export const logPrefix = (prefixString = ''): string => {
+ return `${new Date().toLocaleString()}${prefixString}`;
+};
+
+export const generateUUID = (): string => {
+ return randomUUID();
+};
+
+export const validateUUID = (uuid: string): boolean => {
+ return /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(
+ uuid,
+ );
+};
+
+export const sleep = async (milliSeconds: number): Promise<NodeJS.Timeout> => {
+ return new Promise<NodeJS.Timeout>((resolve) => setTimeout(resolve as () => void, milliSeconds));
+};
+
+export const formatDurationMilliSeconds = (duration: number): string => {
+ duration = convertToInt(duration);
+ if (duration < 0) {
+ throw new RangeError('Duration cannot be negative');
+ }
+ const days = Math.floor(duration / (24 * 3600 * 1000));
+ const hours = Math.floor(millisecondsToHours(duration) - days * 24);
+ const minutes = Math.floor(
+ millisecondsToMinutes(duration) - days * 24 * 60 - hoursToMinutes(hours),
+ );
+ const seconds = Math.floor(
+ millisecondsToSeconds(duration) -
+ days * 24 * 3600 -
+ hoursToSeconds(hours) -
+ minutesToSeconds(minutes),
+ );
+ if (days === 0 && hours === 0 && minutes === 0 && seconds === 0) {
+ return formatDuration({ seconds }, { zero: true });
+ }
+ return formatDuration({
+ days,
+ hours,
+ minutes,
+ seconds,
+ });
+};
+
+export const formatDurationSeconds = (duration: number): string => {
+ return formatDurationMilliSeconds(secondsToMilliseconds(duration));
+};
+
+// More efficient time validation function than the one provided by date-fns
+export const isValidTime = (date: unknown): boolean => {
+ if (typeof date === 'number') {
+ return !isNaN(date);
+ } else if (isDate(date)) {
+ return !isNaN(date.getTime());
+ }
+ return false;
+};
+
+export const convertToDate = (
+ value: Date | string | number | null | undefined,
+): Date | null | undefined => {
+ if (isNullOrUndefined(value)) {
+ return value as null | undefined;
+ }
+ if (isDate(value)) {
+ return value;
+ }
+ if (isString(value) || typeof value === 'number') {
+ const valueToDate = new Date(value!);
+ if (isNaN(valueToDate.getTime())) {
+ throw new Error(`Cannot convert to date: '${value!}'`);
+ }
+ return valueToDate;