/** Compares two byte sequences without coercion or serialization. */ export function bytesEqual(left: Uint8Array, right: Uint8Array): boolean { if (left.byteLength !== right.byteLength) return false; for (let index = 0; index < left.byteLength; index += 1) { if (left[index] !== right[index]) return false; } return true; } /** Returns an owned copy so callers cannot mutate adapter-held bytes. */ export function copyBytes(value: Uint8Array): Uint8Array { return value.slice(); } const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** Encodes arbitrary bytes using RFC 4648 standard base64 with padding. */ export function bytesToBase64(value: Uint8Array): string { let result = ""; for (let index = 0; index < value.length; index += 3) { const first = value[index] ?? 0; const second = value[index + 1] ?? 0; const third = value[index + 2] ?? 0; const packed = (first << 16) | (second << 8) | third; result += BASE64_ALPHABET[(packed >>> 18) & 63]; result += BASE64_ALPHABET[(packed >>> 12) & 63]; result += index + 1 < value.length ? BASE64_ALPHABET[(packed >>> 6) & 63] : "="; result += index + 2 < value.length ? BASE64_ALPHABET[packed & 63] : "="; } return result; } /** Decodes strict, padded RFC 4648 base64 and rejects malformed input. */ export function base64ToBytes(value: string): Uint8Array { if (value.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) { throw new TypeError("Invalid base64 value"); } const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0; const result = new Uint8Array((value.length / 4) * 3 - padding); let output = 0; for (let index = 0; index < value.length; index += 4) { const a = BASE64_ALPHABET.indexOf(value[index] ?? ""); const b = BASE64_ALPHABET.indexOf(value[index + 1] ?? ""); const c = value[index + 2] === "=" ? 0 : BASE64_ALPHABET.indexOf(value[index + 2] ?? ""); const d = value[index + 3] === "=" ? 0 : BASE64_ALPHABET.indexOf(value[index + 3] ?? ""); const packed = (a << 18) | (b << 12) | (c << 6) | d; if (output < result.length) result[output++] = (packed >>> 16) & 255; if (output < result.length) result[output++] = (packed >>> 8) & 255; if (output < result.length) result[output++] = packed & 255; } return result; }