From 5190a64017bf4391dc2584042711f235c296f002 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Thu, 13 Aug 2026 22:23:37 +0300 Subject: [PATCH] fix(tauri): transfer FIG exports over binary IPC (#509) - Return native FIG archives as raw IPC responses instead of JSON byte arrays - Decode the response as an ArrayBuffer and cover the binary contract - Prevent large desktop exports from multiplying memory use during save --- CHANGELOG.md | 1 + desktop/src/fig_container.rs | 4 ++-- packages/core/src/io/formats/fig/export.ts | 2 +- tests/helpers/tauri/fig-export-fixture.ts | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09e890946..c3f7c5c85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ### Fixed +- Transfer native `.fig` exports over binary Tauri IPC instead of JSON byte arrays, preventing large desktop saves from being truncated or exhausting WebView memory. (#484) - Keep unsaved source-less documents recoverable after their editor tab is closed, matching Figma's retained offline-change behavior. - Decode zstd-compressed FIG containers, reject invalid compressed payloads, and preserve exact fixture byte ranges. (#397) - Compose caller CSS with Tailwind defaults when importing DOM/CSS documents. (#397) diff --git a/desktop/src/fig_container.rs b/desktop/src/fig_container.rs index 16e206e8c..b30e7f1f3 100644 --- a/desktop/src/fig_container.rs +++ b/desktop/src/fig_container.rs @@ -15,7 +15,7 @@ pub fn build_fig_file( meta_json: String, images: Option>, fig_kiwi_version: Option, -) -> Result, String> { +) -> Result { let mut encoder = zstd::Encoder::new(Vec::new(), 3).map_err(|e| e.to_string())?; encoder .include_contentsize(true) @@ -63,5 +63,5 @@ pub fn build_fig_file( } let result = zip.finish().map_err(|e| e.to_string())?; - Ok(result.into_inner()) + Ok(tauri::ipc::Response::new(result.into_inner())) } diff --git a/packages/core/src/io/formats/fig/export.ts b/packages/core/src/io/formats/fig/export.ts index d3f0d3d44..dc3f11aa4 100644 --- a/packages/core/src/io/formats/fig/export.ts +++ b/packages/core/src/io/formats/fig/export.ts @@ -554,7 +554,7 @@ export async function exportFigFile( if (IS_TAURI) { const { invoke } = await import('@tauri-apps/api/core') return new Uint8Array( - await invoke('build_fig_file', { + await invoke('build_fig_file', { schemaDeflated: Array.from(schemaDeflated), kiwiData: Array.from(kiwiData), thumbnailPng: Array.from(thumbnailPNG), diff --git a/tests/helpers/tauri/fig-export-fixture.ts b/tests/helpers/tauri/fig-export-fixture.ts index 92b3b132a..1cba85d6e 100644 --- a/tests/helpers/tauri/fig-export-fixture.ts +++ b/tests/helpers/tauri/fig-export-fixture.ts @@ -20,7 +20,7 @@ mockIPC((cmd, args) => { if (payload.thumbnailPng.length === 0) throw new Error('thumbnailPng is empty') if (payload.images.length !== 0) throw new Error('images should be empty') JSON.parse(payload.metaJson) - return [7, 8, 9] + return new Uint8Array([7, 8, 9]).buffer }) const [{ exportFigFile }, { SceneGraph }] = await Promise.all([