/** * Encoding utilities for WHMCS helpers (domain-internal) * * Avoid hard Node `Buffer` dependency. Use it when available; otherwise fall back * to pure JS UTF-8 + base64. */ const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; function encodeUtf8Fallback(value: string): Uint8Array { const bytes: number[] = []; for (let i = 0; i < value.length; i++) { let codePoint = value.charCodeAt(i); // Handle surrogate pairs if (codePoint >= 0xd800 && codePoint <= 0xdbff && i + 1 < value.length) { const next = value.charCodeAt(i + 1); if (next >= 0xdc00 && next <= 0xdfff) { codePoint = ((codePoint - 0xd800) << 10) + (next - 0xdc00) + 0x10000; i++; } } if (codePoint <= 0x7f) { bytes.push(codePoint); } else if (codePoint <= 0x7ff) { bytes.push(0xc0 | (codePoint >> 6)); bytes.push(0x80 | (codePoint & 0x3f)); } else if (codePoint <= 0xffff) { bytes.push(0xe0 | (codePoint >> 12)); bytes.push(0x80 | ((codePoint >> 6) & 0x3f)); bytes.push(0x80 | (codePoint & 0x3f)); } else { bytes.push(0xf0 | (codePoint >> 18)); bytes.push(0x80 | ((codePoint >> 12) & 0x3f)); bytes.push(0x80 | ((codePoint >> 6) & 0x3f)); bytes.push(0x80 | (codePoint & 0x3f)); } } return new Uint8Array(bytes); } function encodeUtf8(value: string): Uint8Array { if (typeof TextEncoder !== "undefined") { return new TextEncoder().encode(value); } return encodeUtf8Fallback(value); } export function byteLengthUtf8(value: string): number { if (typeof Buffer !== "undefined") { return Buffer.byteLength(value, "utf8"); } return encodeUtf8(value).length; } function base64EncodeBytes(bytes: Uint8Array): string { let out = ""; for (let i = 0; i < bytes.length; i += 3) { const b1 = bytes[i] ?? 0; const b2 = bytes[i + 1] ?? 0; const b3 = bytes[i + 2] ?? 0; const triplet = (b1 << 16) | (b2 << 8) | b3; out += BASE64_ALPHABET[(triplet >> 18) & 0x3f]; out += BASE64_ALPHABET[(triplet >> 12) & 0x3f]; out += i + 1 < bytes.length ? BASE64_ALPHABET[(triplet >> 6) & 0x3f] : "="; out += i + 2 < bytes.length ? BASE64_ALPHABET[triplet & 0x3f] : "="; } return out; } export function utf8ToBase64(value: string): string { if (typeof Buffer !== "undefined") { return Buffer.from(value, "utf8").toString("base64"); } return base64EncodeBytes(encodeUtf8(value)); }