encodeBase64/decodeBase64 for UTF-8 text
TypeScript
const encoder = new TextEncoder();
const decoder = new TextDecoder();
/** Encode any text as Base64 over its UTF-8 bytes, not raw UTF-16 code units. */
export function encodeBase64(text: string): string {
let binary = '';
for (const byte of encoder.encode(text)) binary += String.fromCharCode(byte);
return btoa(binary);
}
/** Decode Base64 text, rejecting characters or padding that cannot be valid. */
export function decodeBase64(encoded: string): string {
const compact = encoded.replace(/\s+/g, '');
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(compact) || compact.length % 4 === 1) {
throw new SyntaxError('input is not valid Base64');
}
const binary = atob(compact);
const bytes = new Uint8Array(binary.length);
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
return decoder.decode(bytes);
}
/** URL-safe Base64 without padding, for query params and file names. */
export function toBase64Url(text: string): string {
return encodeBase64(text).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
// decodeBase64(encodeBase64('héllo 世界')) === 'héllo 世界'