diff --git a/packages/client/signers-cryptography/src/primitives/encoding/base64.test.ts b/packages/client/signers-cryptography/src/primitives/encoding/base64.test.ts new file mode 100644 index 000000000..e8910293b --- /dev/null +++ b/packages/client/signers-cryptography/src/primitives/encoding/base64.test.ts @@ -0,0 +1,12 @@ +import { describe, expect, it } from "vitest"; +import { decodeBase64, encodeBase64 } from "./base64"; + +describe("base64 encoding", () => { + it("encodes large byte arrays without exceeding the call stack", () => { + const bytes = new Uint8Array(200_000); + bytes.fill(65); + + expect(() => encodeBase64(bytes)).not.toThrow(); + expect(decodeBase64(encodeBase64(bytes))).toEqual(bytes); + }); +}); diff --git a/packages/client/signers-cryptography/src/primitives/encoding/base64.ts b/packages/client/signers-cryptography/src/primitives/encoding/base64.ts index 50dadb2bf..a09c14d53 100644 --- a/packages/client/signers-cryptography/src/primitives/encoding/base64.ts +++ b/packages/client/signers-cryptography/src/primitives/encoding/base64.ts @@ -1,5 +1,12 @@ export function encodeBase64(bytes: Uint8Array): string { - return btoa(String.fromCharCode.apply(null, Array.from(bytes))); + let binary = ""; + const chunkSize = 0x8000; + + for (let i = 0; i < bytes.length; i += chunkSize) { + binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize)); + } + + return btoa(binary); } export function decodeBase64(base64: string): Uint8Array {