+ // Iterates over the keys of an object, if
+ // any exist, return false.
+ // eslint-disable-next-line no-unreachable-loop
+ for (const _ in object) {
+ return false
+ }
+ return true
+}
+
+export const hasOwnProp = (value: unknown, property: PropertyKey): boolean => {
+ return isObject(value) && Object.hasOwn(value, property)
+}
+
+export const isCFEnvironment = (): boolean => {
+ return env.VCAP_APPLICATION != null
+}
+
+const isString = (value: unknown): value is string => {
+ return typeof value === 'string'
+}
+
+export const isEmptyString = (value: unknown): value is '' | undefined | null => {
+ return value == null || (isString(value) && value.trim().length === 0)
+}
+
+export const isNotEmptyString = (value: unknown): value is string => {
+ return isString(value) && value.trim().length > 0
+}
+
+export const isEmptyArray = (value: unknown): value is never[] => {
+ return Array.isArray(value) && value.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
+}