diff --git a/packages/svelte/src/internal/server/crypto.js b/packages/svelte/src/internal/server/crypto.js index 9b62d10a1d..43bc52c6d6 100644 --- a/packages/svelte/src/internal/server/crypto.js +++ b/packages/svelte/src/internal/server/crypto.js @@ -1,3 +1,5 @@ +import { BROWSER } from 'esm-env'; + let text_encoder; // TODO - remove this and use global `crypto` when we drop Node 18 let crypto = globalThis.crypto; @@ -9,5 +11,24 @@ export async function sha256(data) { crypto ??= (await import('node:crypto')).webcrypto; const hash_buffer = await crypto.subtle.digest('SHA-256', text_encoder.encode(data)); // @ts-ignore - we don't install node types in the prod build - return Buffer.from(hash_buffer).toString('base64'); + return base64_encode(hash_buffer); +} + +/** + * @param {Uint8Array} bytes + * @returns {string} + */ +export function base64_encode(bytes) { + // Using `Buffer` is faster than iterating + if (!BROWSER && globalThis.Buffer) { + return globalThis.Buffer.from(bytes).toString('base64'); + } + + let binary = ''; + + for (let i = 0; i < bytes.length; i++) { + binary += String.fromCharCode(bytes[i]); + } + + return btoa(binary); }