src/utils.ts

import { sleep as sleepShared } from "./normalization/time.ts";

export function nowIso() { return new Date().toISOString(); }

export function clamp(value, min, max) { return Math.min(max, Math.max(min, value)); }

export function chance(probability) { return Math.random() < probability; }

export function sleep(ms) { return sleepShared(ms); }

export function deepMerge(base, patch) { if (!isObject(base) || !isObject(patch)) { return patch; }

const out = { ...base }; for (const [key, value] of Object.entries(patch)) { if (Array.isArray(value)) { out[key] = value.slice(); continue; }

if (isObject(value)) {
  out[key] = deepMerge(isObject(base[key]) ? base[key] : {}, value);
  continue;
}

out[key] = value;

} return out; }

const DISCORD_MESSAGE_SAFE_LIMIT = 1900;

export function sanitizeBotText(text, maxLen = DISCORD_MESSAGE_SAFE_LIMIT) { if (!text) return "";

let clean = String(text).trim(); clean = clean.replace(/^"|"$/g, ""); clean = clean.replace(/ {3,}/g, "

"); clean = clean.replace(/@everyone|@here/g, "");

const limit = Number(maxLen); if (Number.isFinite(limit) && limit > 0 && clean.length > limit) { const sliceLen = Math.max(1, Math.floor(limit) - 1); clean = clean.slice(0, sliceLen).trimEnd() + "…"; }

return clean; }

function isObject(value) { return value !== null && typeof value === "object" && !Array.isArray(value); }