@@ -28,55 +28,14 @@ export default {
2828}
2929
3030export const safeBtoa = function ( str : string ) : string {
31+ // Prefer Buffer when available (Node.js / SSR): handles UTF-8 natively.
3132 if ( typeof ( globalThis as any ) . Buffer !== "undefined" ) {
3233 return ( globalThis as any ) . Buffer . from ( str , "utf8" ) . toString ( "base64" ) ;
3334 }
3435
35- const bytes =
36- typeof TextEncoder !== "undefined"
37- ? new TextEncoder ( ) . encode ( str )
38- : encodeUTF8Fallback ( str ) ;
39-
40- if ( typeof btoa !== "undefined" ) {
41- let binary = "" ;
42- const chunkSize = 0x8000 ;
43- for ( let i = 0 ; i < bytes . length ; i += chunkSize ) {
44- binary += String . fromCharCode . apply (
45- null ,
46- Array . prototype . slice . call ( bytes , i , i + chunkSize ) as any ,
47- ) ;
48- }
49- return btoa ( binary ) ;
50- }
51-
52- throw new Error ( "Cannot generate base64 string; Expected `Buffer` or `btoa` to be defined" ) ;
53- } ;
54-
55- function encodeUTF8Fallback ( str : string ) : Uint8Array {
56- const out : number [ ] = [ ] ;
57- for ( let i = 0 ; i < str . length ; i ++ ) {
58- let c = str . charCodeAt ( i ) ;
59- if ( c < 0x80 ) {
60- out . push ( c ) ;
61- } else if ( c < 0x800 ) {
62- out . push ( 0xc0 | ( c >> 6 ) , 0x80 | ( c & 0x3f ) ) ;
63- } else if ( c >= 0xd800 && c <= 0xdbff && i + 1 < str . length ) {
64- const c2 = str . charCodeAt ( i + 1 ) ;
65- if ( c2 >= 0xdc00 && c2 <= 0xdfff ) {
66- const cp = 0x10000 + ( ( ( c & 0x3ff ) << 10 ) | ( c2 & 0x3ff ) ) ;
67- out . push (
68- 0xf0 | ( cp >> 18 ) ,
69- 0x80 | ( ( cp >> 12 ) & 0x3f ) ,
70- 0x80 | ( ( cp >> 6 ) & 0x3f ) ,
71- 0x80 | ( cp & 0x3f ) ,
72- ) ;
73- i ++ ;
74- continue ;
75- }
76- out . push ( 0xe0 | ( c >> 12 ) , 0x80 | ( ( c >> 6 ) & 0x3f ) , 0x80 | ( c & 0x3f ) ) ;
77- } else {
78- out . push ( 0xe0 | ( c >> 12 ) , 0x80 | ( ( c >> 6 ) & 0x3f ) , 0x80 | ( c & 0x3f ) ) ;
79- }
80- }
81- return new Uint8Array ( out ) ;
82- }
36+ // Browser: btoa() throws on characters with code points > 0xFF, so convert
37+ // the string to UTF-8 bytes first, then base64-encode them (per MDN).
38+ const bytes = new TextEncoder ( ) . encode ( str ) ;
39+ const binary = Array . from ( bytes , ( byte ) => String . fromCodePoint ( byte ) ) . join ( "" ) ;
40+ return btoa ( binary ) ;
41+ } ;
0 commit comments