Skip to content

Commit 323a275

Browse files
committed
get Buffer and atob/btoa from global object explicitly
1 parent 512387b commit 323a275

File tree

1 file changed

+24
-8
lines changed

1 file changed

+24
-8
lines changed

packages/utils/src/string.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ export function isMatchingPattern(value: string, pattern: RegExp | string): bool
104104
return false;
105105
}
106106

107+
type GlobalWithBase64Helpers = {
108+
// browser
109+
atob?: (base64String: string) => string;
110+
btoa?: (utf8String: string) => string;
111+
// Node
112+
Buffer?: { from: (input: string, encoding: string) => { toString: (encoding: string) => string } };
113+
};
114+
107115
/**
108116
* Convert a Unicode string to a base64 string.
109117
*
@@ -112,26 +120,30 @@ export function isMatchingPattern(value: string, pattern: RegExp | string): bool
112120
* @returns A base64-encoded version of the string
113121
*/
114122
export function unicodeToBase64(plaintext: string): string {
115-
const global = getGlobalObject();
123+
const globalObject = getGlobalObject() as GlobalWithBase64Helpers;
116124

117125
// To account for the fact that different platforms use different character encodings natively, our `tracestate`
118126
// spec calls for all jsonified data to be encoded in UTF-8 bytes before being passed to the base64 encoder.
119127
try {
120128
// browser
121-
if ('btoa' in global) {
129+
if ('btoa' in globalObject) {
122130
// encode using UTF-8
123131
const bytes = new TextEncoder().encode(plaintext);
124132

125133
// decode using UTF-16 (JS's native encoding) since `btoa` requires string input
126134
const bytesAsString = String.fromCharCode(...bytes);
127135

128-
return btoa(bytesAsString);
136+
// TODO: if TS ever learns about "in", we can get rid of the non-null assertion
137+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
138+
return globalObject.btoa!(bytesAsString);
129139
}
130140

131141
// Node
132-
if ('Buffer' in global) {
142+
if ('Buffer' in globalObject) {
133143
// encode using UTF-8
134-
const bytes = Buffer.from(plaintext, 'utf-8');
144+
// TODO: if TS ever learns about "in", we can get rid of the non-null assertion
145+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
146+
const bytes = globalObject.Buffer!.from(plaintext, 'utf-8');
135147

136148
// unlike the browser, Node can go straight from bytes to base64
137149
return bytes.toString('base64');
@@ -157,7 +169,7 @@ export function unicodeToBase64(plaintext: string): string {
157169
* @returns A Unicode string
158170
*/
159171
export function base64ToUnicode(base64String: string): string {
160-
const globalObject = getGlobalObject();
172+
const globalObject = getGlobalObject() as GlobalWithBase64Helpers;
161173

162174
// To account for the fact that different platforms use different character encodings natively, our `tracestate` spec
163175
// calls for all jsonified data to be encoded in UTF-8 bytes before being passed to the base64 encoder. So to reverse
@@ -166,7 +178,9 @@ export function base64ToUnicode(base64String: string): string {
166178
// browser
167179
if ('atob' in globalObject) {
168180
// `atob` returns a string rather than bytes, so we first need to encode using the native encoding (UTF-16)
169-
const bytesAsString = atob(base64String);
181+
// TODO: if TS ever learns about "in", we can get rid of the non-null assertion
182+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
183+
const bytesAsString = globalObject.atob!(base64String);
170184
const bytes = [...bytesAsString].map(char => char.charCodeAt(0));
171185

172186
// decode using UTF-8 (cast the `bytes` arry to a Uint8Array just because that's the format `decode()` expects)
@@ -176,7 +190,9 @@ export function base64ToUnicode(base64String: string): string {
176190
// Node
177191
if ('Buffer' in globalObject) {
178192
// unlike the browser, Node can go straight from base64 to bytes
179-
const bytes = Buffer.from(base64String, 'base64');
193+
// TODO: if TS ever learns about "in", we can get rid of the non-null assertion
194+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
195+
const bytes = globalObject.Buffer!.from(base64String, 'base64');
180196

181197
// decode using UTF-8
182198
return bytes.toString('utf-8');

0 commit comments

Comments
 (0)