fix(call): Response return-type can't be wrapped in Result
Previous commit had the command typed as Result<tauri::ipc::Response, String>. Turns out that forces Tauri to JSON-serialise the variant wrapper around the Response body — the frontend gets a JSON object instead of the raw ArrayBuffer, the runtime check for byteLength fails, and every thumbnail comes back as null. Changed the return type to `tauri::ipc::Response` directly. Bad source ids and capture failures now funnel into an empty byte buffer; the JS side still detects "no thumbnail" via `byteLength === 0` so the contract stays the same. Frontend also widens the invoke-result typing to ArrayBuffer | Uint8Array | number[] so an older WebView2 that happens to deserialise as an array still works, and normalises into a plain ArrayBuffer before constructing the Blob to sidestep a TS SharedArrayBuffer incompatibility. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -60,18 +60,41 @@ export async function captureScreenSourceThumbnail(
|
||||
// in a Blob so callers can hand it straight to `URL.createObjectURL` —
|
||||
// never touches base64 on either side. Returns null when the Rust side
|
||||
// produced zero bytes (capture failed, source vanished).
|
||||
//
|
||||
// Tauri's invoke may resolve with different shapes depending on runtime
|
||||
// version — accept ArrayBuffer, Uint8Array, or a number[] fallback so a
|
||||
// WebView2 variant that doesn't speak the binary channel still works.
|
||||
export async function captureScreenSourceThumbnailBytes(
|
||||
sourceId: string,
|
||||
): Promise<Blob | null> {
|
||||
if (!isTauriRuntime()) return null;
|
||||
try {
|
||||
const { invoke } = await import('@tauri-apps/api/core');
|
||||
const result = await invoke<ArrayBuffer>(
|
||||
const result = await invoke<ArrayBuffer | Uint8Array | number[]>(
|
||||
'capture_screen_source_thumbnail_bytes',
|
||||
{ sourceId },
|
||||
);
|
||||
if (!result || result.byteLength === 0) return null;
|
||||
return new Blob([result], { type: 'image/jpeg' });
|
||||
let bytes: ArrayBuffer | Uint8Array | null = null;
|
||||
if (result instanceof ArrayBuffer) {
|
||||
bytes = result;
|
||||
} else if (result instanceof Uint8Array) {
|
||||
bytes = result;
|
||||
} else if (Array.isArray(result) && result.length > 0) {
|
||||
bytes = new Uint8Array(result);
|
||||
}
|
||||
if (!bytes || bytes.byteLength === 0) {
|
||||
return null;
|
||||
}
|
||||
// Normalise to ArrayBuffer so Blob() accepts the part without TS
|
||||
// complaining about SharedArrayBuffer-backed Uint8Array flavours.
|
||||
const buffer =
|
||||
bytes instanceof ArrayBuffer
|
||||
? bytes
|
||||
: (bytes.buffer.slice(
|
||||
bytes.byteOffset,
|
||||
bytes.byteOffset + bytes.byteLength,
|
||||
) as ArrayBuffer);
|
||||
return new Blob([buffer], { type: 'image/jpeg' });
|
||||
} catch (err: unknown) {
|
||||
console.warn('capture_screen_source_thumbnail_bytes failed', { sourceId, err });
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user