From 85a9b2a90885456d90cb8b7b5f34e3cb6b06770b Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Sat, 15 Aug 2026 08:21:23 -0700 Subject: [PATCH] Address response bodies by response id instead of a filesystem path (#550) --- .../components/HttpResponsePane.tsx | 22 +++-- .../responseViewers/AudioViewer.tsx | 18 ++-- .../responseViewers/ImageViewer.tsx | 18 ++-- .../components/responseViewers/PdfViewer.tsx | 12 +-- .../responseViewers/VideoViewer.tsx | 18 ++-- .../yaak-client/hooks/useIntrospectGraphQL.ts | 9 +- apps/yaak-client/hooks/useResponseBodyUrl.ts | 24 +++++ apps/yaak-client/lib/responseBody.ts | 30 ++++-- apps/yaak-client/lib/sendEphemeralRequest.ts | 5 +- .../yaak-app-client/bindings/gen_rpc.ts | 17 +++- .../yaak-app-client/src/http_request.rs | 25 +++-- crates-tauri/yaak-app-client/src/lib.rs | 99 +++++++++++++++---- .../yaak-app-client/src/plugin_events.rs | 2 +- crates-tauri/yaak-app-client/src/rpc_ext.rs | 39 ++++++-- crates/yaak/src/send.rs | 82 +++++++++++++-- packages/platform/src/registry.ts | 3 + packages/platform/src/tauri/index.ts | 25 ++++- packages/platform/src/types.ts | 29 +++++- 18 files changed, 375 insertions(+), 102 deletions(-) create mode 100644 apps/yaak-client/hooks/useResponseBodyUrl.ts diff --git a/apps/yaak-client/components/HttpResponsePane.tsx b/apps/yaak-client/components/HttpResponsePane.tsx index 645de078..8d0697d7 100644 --- a/apps/yaak-client/components/HttpResponsePane.tsx +++ b/apps/yaak-client/components/HttpResponsePane.tsx @@ -8,6 +8,7 @@ import { useCopyHttpResponse } from "../hooks/useCopyHttpResponse"; import { useHttpResponseEvents } from "../hooks/useHttpResponseEvents"; import { usePinnedHttpResponse } from "../hooks/usePinnedHttpResponse"; import { useResponseBodyBytes, useResponseBodyText } from "../hooks/useResponseBodyText"; +import { useResponseBodyUrl } from "../hooks/useResponseBodyUrl"; import { useResponseViewMode } from "../hooks/useResponseViewMode"; import { useSaveResponse } from "../hooks/useSaveResponse"; import { useTimelineViewMode } from "../hooks/useTimelineViewMode"; @@ -409,14 +410,13 @@ function EnsureCompleteResponse({ Component, }: { response: HttpResponse; - Component: ComponentType<{ bodyPath: string }>; + Component: ComponentType<{ bodyUrl: string }>; }) { - if (response.bodyPath === null) { - return
Empty response body
; - } + // Wait until the response has been fully-downloaded before asking for it + const complete = response.state === "closed"; + const bodyUrl = useResponseBodyUrl(complete ? response : null); - // Wait until the response has been fully-downloaded - if (response.state !== "closed") { + if (!complete || bodyUrl.isPending) { return ( @@ -424,7 +424,15 @@ function EnsureCompleteResponse({ ); } - return ; + if (bodyUrl.error) { + return {String(bodyUrl.error)}; + } + + if (bodyUrl.data == null) { + return
Empty response body
; + } + + return ; } function HttpSvgViewer({ response }: { response: HttpResponse }) { diff --git a/apps/yaak-client/components/responseViewers/AudioViewer.tsx b/apps/yaak-client/components/responseViewers/AudioViewer.tsx index 89f102de..f72f9fef 100644 --- a/apps/yaak-client/components/responseViewers/AudioViewer.tsx +++ b/apps/yaak-client/components/responseViewers/AudioViewer.tsx @@ -1,29 +1,29 @@ import { useEffect, useState } from "react"; -import { platform } from "@yaakapp-internal/platform"; interface Props { - bodyPath?: string; + /** A URL for the body the host already stored. */ + bodyUrl?: string; data?: Uint8Array; mimeType?: string; } -export function AudioViewer({ bodyPath, data, mimeType }: Props) { +export function AudioViewer({ bodyUrl, data, mimeType }: Props) { const [src, setSrc] = useState(); useEffect(() => { - if (bodyPath) { - setSrc(platform.files.url(bodyPath)); + if (bodyUrl) { + setSrc(bodyUrl); } else if (data) { // The type matters here in a way it doesn't for an image: a media element goes by what // the blob declares rather than sniffing it, so an Ogg labelled as MP3 won't play const blob = new Blob([new Uint8Array(data)], { type: mimeType ?? "audio/mpeg" }); - const url = URL.createObjectURL(blob); - setSrc(url); - return () => URL.revokeObjectURL(url); + const objectUrl = URL.createObjectURL(blob); + setSrc(objectUrl); + return () => URL.revokeObjectURL(objectUrl); } else { setSrc(undefined); } - }, [bodyPath, data, mimeType]); + }, [bodyUrl, data, mimeType]); // oxlint-disable-next-line jsx-a11y/media-has-caption return