Files
Toju/toju-app/src/app/domains/attachment/domain/logic/attachment-blob.rules.ts
T
myxeliumandCursor bb0ac930ad
Queue Release Build / prepare (push) Successful in 20s
Deploy Web Apps / deploy (push) Successful in 9m2s
Queue Release Build / build-windows (push) Successful in 28m8s
Queue Release Build / build-linux (push) Successful in 47m26s
Queue Release Build / build-android (push) Successful in 19m52s
Queue Release Build / finalize (push) Successful in 4m42s
Improve attachment memory safety, downloads, and high-memory alert UX.
Stream large receives to disk with chunk acks to cap renderer RAM, evict
off-screen display blobs, and route exports through a disk-aware download
service. Fix the high-memory dialog (backdrop dismiss, copy, log actions),
allow diagnostics paths in the path jail, and restore persisted image
hydration after reload.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-14 00:25:22 +02:00

45 lines
1.6 KiB
TypeScript

/** Chunk size used when rebuilding attachment blobs from disk without blocking the UI thread. */
export const ATTACHMENT_BLOB_READ_CHUNK_SIZE_BYTES = 256 * 1024;
/** Number of bytes encoded per chunk to keep base64 encoding off the call stack. */
const BASE64_ENCODE_CHUNK_SIZE = 0x8000;
/** Decode a base64 payload into bytes for Blob construction. */
export function decodeBase64ToUint8Array(base64: string): Uint8Array {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let index = 0; index < binary.length; index++) {
bytes[index] = binary.charCodeAt(index);
}
return bytes;
}
/** Encode bytes into a base64 payload, chunked so large buffers cannot overflow the call stack. */
export function encodeUint8ArrayToBase64(bytes: Uint8Array): string {
let binary = '';
for (let offset = 0; offset < bytes.length; offset += BASE64_ENCODE_CHUNK_SIZE) {
const chunk = bytes.subarray(offset, offset + BASE64_ENCODE_CHUNK_SIZE);
binary += String.fromCharCode(...chunk);
}
return btoa(binary);
}
/** Returns the decoded byte length of a base64 payload without allocating the bytes. */
export function base64DecodedByteLength(base64: string): number {
const padding = base64.endsWith('==') ? 2 : base64.endsWith('=') ? 1 : 0;
return Math.max(0, Math.floor((base64.length * 3) / 4) - padding);
}
/** Yield control back to the browser so long attachment hydration cannot freeze Electron. */
export function yieldToAttachmentHydrationLoop(): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, 0);
});
}