- public static isEmptyArray(object: unknown): boolean {
- if (!object) {
- return true;
- }
- if (Array.isArray(object) && object.length > 0) {
- return false;
- }
- return true;
- }
-
- public static isEmptyObject(obj: Record<string, unknown>): boolean {
- return !Object.keys(obj).length;
- }
-
- public static insertAt = (str: string, subStr: string, pos: number): string => `${str.slice(0, pos)}${subStr}${str.slice(pos)}`;
-
- /**
- * @param [retryNumber=0]
- * @returns delay in milliseconds
- */
- public static exponentialDelay(retryNumber = 0): number {
- const delay = Math.pow(2, retryNumber) * 100;
- const randomSum = delay * 0.2 * Utils.secureRandom(); // 0-20% of the delay
- return delay + randomSum;
- }
-
- /**
- * 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 {
- if (code >= 0 && code <= 999) {
- return '(Unused)';
- } else if (code >= 1016) {
- if (code <= 1999) {
- return '(For WebSocket standard)';
- } else if (code <= 2999) {
- return '(For WebSocket extensions)';
- } else if (code <= 3999) {
- return '(For libraries and frameworks)';
- } else if (code <= 4999) {
- return '(For applications)';
+export const extractTimeSeriesValues = (timeSeries: TimestampedData[]): number[] => {
+ return timeSeries.map(timeSeriesItem => timeSeriesItem.value)
+}
+
+export const clone = <T>(object: T): T => {
+ return structuredClone<T>(object)
+}
+
+/**
+ * Detects whether the given value is an asynchronous function or not.
+ *
+ * @param fn - Unknown value.
+ * @returns `true` if `fn` was an asynchronous function, otherwise `false`.
+ * @internal
+ */
+export const isAsyncFunction = (fn: unknown): fn is (...args: unknown[]) => Promise<unknown> => {
+ return is(Function, fn) && fn.constructor.name === 'AsyncFunction'
+}
+
+export const isObject = (value: unknown): value is object => {
+ return value != null && !Array.isArray(value) && is(Object, value)
+}
+
+export const hasOwnProp = (value: unknown, property: PropertyKey): boolean => {
+ return isObject(value) && Object.hasOwn(value, property)
+}
+
+export const isCFEnvironment = (): boolean => {
+ return env.VCAP_APPLICATION != null
+}
+
+export const isNotEmptyString = (value: unknown): value is string => {
+ return typeof value === 'string' && value.trim().length > 0
+}
+
+export const isNotEmptyArray = (value: unknown): value is unknown[] => {
+ return Array.isArray(value) && value.length > 0
+}
+
+export const insertAt = (str: string, subStr: string, pos: number): string =>
+ `${str.slice(0, pos)}${subStr}${str.slice(pos)}`
+
+/**
+ * Computes the retry delay in milliseconds using an exponential backoff algorithm.
+ *
+ * @param retryNumber - the number of retries that have already been attempted
+ * @param delayFactor - the base delay factor in milliseconds
+ * @returns delay in milliseconds
+ */
+export const exponentialDelay = (retryNumber = 0, delayFactor = 100): number => {
+ const delay = Math.pow(2, retryNumber) * delayFactor
+ const randomSum = delay * 0.2 * secureRandom() // 0-20% of the delay
+ return delay + randomSum
+}
+
+/**
+ * Generates a cryptographically secure random number in the [0,1[ range
+ *
+ * @returns A number in the [0,1[ range
+ */
+export const secureRandom = (): number => {
+ return getRandomValues(new Uint32Array(1))[0] / 0x100000000
+}
+
+export const JSONStringify = <
+ T extends
+ | JsonType
+ | Array<Record<string, unknown>>
+ | Set<Record<string, unknown>>
+ | Map<string, Record<string, unknown>>
+>(
+ object: T,
+ space?: string | number,
+ mapFormat?: MapStringifyFormat
+ ): string => {
+ return JSON.stringify(
+ object,
+ (_, value: Record<string, unknown>) => {
+ if (is(Map, value)) {
+ switch (mapFormat) {
+ case MapStringifyFormat.object:
+ return { ...Object.fromEntries<Map<string, Record<string, unknown>>>(value.entries()) }
+ case MapStringifyFormat.array:
+ default:
+ return [...value]
+ }
+ } else if (is(Set, value)) {
+ return [...value] as JsonType[]