import { Decimal } from "decimal.js"; export const nullish = ( value: T | null | undefined, ): value is null | undefined => { return value === null || value === undefined; }; export const notNullish = (value: T | null | undefined): value is T => value !== null && value !== undefined; export const idRegex = /^[a-zA-Z0-9_-]+$/; export const sumValues = (vals: number[]) => { return vals.reduce((acc, curr) => acc.add(curr), new Decimal(0)).toNumber(); }; export const keyToTitle = ( key: string, options?: { exclusionMap?: Record }, ) => { if (options?.exclusionMap?.[key]) { return options.exclusionMap[key]; } return key .replace(/[-_]/g, " ") .replace(/\b\w/g, (char) => char.toUpperCase()); }; /** Fast hash using Bun's native hasher */ export const hashString = (str: string): string => { const hasher = new Bun.CryptoHasher("sha256"); hasher.update(str); return hasher.digest("base64"); }; // Types for the result object with discriminated union type Success = { data: T; error: null; }; type Failure = { data: null; error: E; }; type Result = Success | Failure; /** Wraps a promise and returns a discriminated union result */ export async function tryCatch( promise: Promise, ): Promise> { try { const data = await promise; return { data, error: null }; } catch (error) { return { data: null, error: error as E }; } } /** Sleep until a specific epoch timestamp (in milliseconds) */ export function sleepUntil(epochMs: number): Promise { const now = Date.now(); const delay = epochMs - now; if (delay <= 0) return Promise.resolve(); return new Promise((resolve) => setTimeout(resolve, delay)); } export const deduplicateArray = (array: T[]): T[] => { return Array.from(new Set(array)); };