From 8aace78beb4c6b67ec1cc10cf519c82d5ffa6f3f Mon Sep 17 00:00:00 2001 From: Josef Guenther Date: Thu, 1 Oct 2026 11:43:08 -0600 Subject: [PATCH] fix(base64_encode): encode large input in browser builds (#969) The browser base64Encode spread every UTF-8 byte of its input into a single String.fromCharCode call, one argument per byte, so input past the engine's argument limit threw: past ~125 KB on V8 ("Maximum call stack size exceeded") and past 64 KB on engines that cap arguments at 65535, such as QuickJS. It now converts the bytes in 32 KB chunks. The node build, which encodes with Buffer, is unchanged. Fixes #967 Co-authored-by: Claude Opus 5.5 (1M context) --- src/build/base64-impl-browser.spec.ts | 5 +++++ src/build/base64-impl-browser.ts | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/build/base64-impl-browser.spec.ts b/src/build/base64-impl-browser.spec.ts index 6078d0c3b..ddd2f9a75 100644 --- a/src/build/base64-impl-browser.spec.ts +++ b/src/build/base64-impl-browser.spec.ts @@ -52,6 +52,11 @@ describe('base64-impl/browser', function () { it('should encode boolean strings', function () { expect(base64.base64Encode('true')).toBe('dHJ1ZQ==') }) + + it('should encode a large string', function () { + const str = 'Hello 🌍'.repeat(20000) + expect(base64.base64Encode(str)).toBe(Buffer.from(str).toString('base64')) + }) }) describe('#base64Decode()', function () { diff --git a/src/build/base64-impl-browser.ts b/src/build/base64-impl-browser.ts index 100cf9f21..48ce759c7 100644 --- a/src/build/base64-impl-browser.ts +++ b/src/build/base64-impl-browser.ts @@ -1,6 +1,11 @@ export function base64Encode (str: string): string { - return btoa(String.fromCharCode(...new TextEncoder().encode(str))) + const bytes = new TextEncoder().encode(str) + let binary = '' + for (let i = 0; i < bytes.length; i += 0x8000) { + binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000)) + } + return btoa(binary) } export function base64Decode (str: string): string {