From e2ab4ee1b0cd84d86833be14ca9eb81cdfa64f99 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Mon, 17 Aug 2026 08:21:59 -0700 Subject: [PATCH] Type the web sender with the generated model types --- package-lock.json | 1 + packages/platform/package.json | 1 + packages/platform/src/web/proxy.ts | 26 +++++----- packages/platform/src/web/send.ts | 77 +++++++++--------------------- 4 files changed, 39 insertions(+), 66 deletions(-) diff --git a/package-lock.json b/package-lock.json index ac03ad7b..13e4bc40 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15799,6 +15799,7 @@ "@tauri-apps/plugin-fs": "^2.5.1", "@tauri-apps/plugin-opener": "^2.5.4", "@tauri-apps/plugin-os": "^2.3.2", + "@yaakapp-internal/models": "^1.0.0", "@yaakapp-internal/rpc-schema": "^1.0.0", "@yaakapp-internal/web": "^1.0.0" } diff --git a/packages/platform/package.json b/packages/platform/package.json index d646b421..d0b3174b 100644 --- a/packages/platform/package.json +++ b/packages/platform/package.json @@ -9,6 +9,7 @@ "lint": "tsc --noEmit" }, "dependencies": { + "@yaakapp-internal/models": "^1.0.0", "@yaakapp-internal/rpc-schema": "^1.0.0", "@yaakapp-internal/web": "^1.0.0", "@tauri-apps/api": "^2.11.0", diff --git a/packages/platform/src/web/proxy.ts b/packages/platform/src/web/proxy.ts index 5246c8ff..d172e68a 100644 --- a/packages/platform/src/web/proxy.ts +++ b/packages/platform/src/web/proxy.ts @@ -7,6 +7,13 @@ * is a change to the other, and the frame `type` tags are the versioning. */ +import type { + Cookie, + HttpRequest, + HttpResponseEventData, + HttpResponseHeader, +} from "@yaakapp-internal/models"; + /* ------------------------------- location -------------------------------- */ /** @@ -30,7 +37,7 @@ export function proxySendUrl(): string { /** The body of `POST /v1/http/send`. */ export interface ProxyRequestBody { /** The rendered request, in the model shape (see `wire.rs` `SendRequest.request`). */ - request: Record; + request: HttpRequest; settings: { validateCertificates: boolean; followRedirects: boolean; @@ -39,16 +46,11 @@ export interface ProxyRequestBody { storeCookies: boolean; }; /** The jar's cookies to start from, or `null` for no jar at all. */ - cookies: unknown[] | null; + cookies: Cookie[] | null; } /* -------------------------------- down ----------------------------------- */ -interface WireHeader { - name: string; - value: string; -} - export interface ProxySendResponse { type: "response"; status: number; @@ -56,8 +58,8 @@ export interface ProxySendResponse { url: string; remoteAddr: string | null; version: string | null; - headers: WireHeader[]; - requestHeaders: WireHeader[]; + headers: HttpResponseHeader[]; + requestHeaders: HttpResponseHeader[]; contentLength: number | null; elapsedHeaders: number; elapsedDns: number; @@ -65,7 +67,7 @@ export interface ProxySendResponse { export type ProxyFrame = /** A timeline event in the `http_response_event.event` shape. */ - | { type: "event"; event: unknown } + | { type: "event"; event: HttpResponseEventData } | ProxySendResponse /** A body chunk, decompressed, base64. */ | { type: "body"; data: string } @@ -74,9 +76,9 @@ export type ProxyFrame = elapsed: number; contentLength: number; contentLengthCompressed: number; - cookies: unknown[] | null; + cookies: Cookie[] | null; } - | { type: "error"; message: string; cookies: unknown[] | null }; + | { type: "error"; message: string; cookies: Cookie[] | null }; /** * Yield frames from an NDJSON stream as they arrive. A partial trailing line is diff --git a/packages/platform/src/web/send.ts b/packages/platform/src/web/send.ts index f4ca341f..6d1150da 100644 --- a/packages/platform/src/web/send.ts +++ b/packages/platform/src/web/send.ts @@ -21,65 +21,38 @@ * byte it returns is stored by this tab. */ +// Types only: the models package imports this one at runtime, and a type import +// is erased, so there is no cycle. +import type { + Cookie, + CookieJar, + HttpRequest, + HttpResponse, + HttpResponseEventData, +} from "@yaakapp-internal/models"; import type { WorkerConnection } from "./connection"; import type { ProxyFrame, ProxyRequestBody, ProxySendResponse } from "./proxy"; import { proxySendUrl, readFrames } from "./proxy"; /* -------------------------------- shapes --------------------------------- */ -// The model types this file writes, spelled out rather than imported from -// `@yaakapp-internal/models`: the platform package sits underneath the model -// package in the dependency graph and must not import it. - -interface HttpResponseHeader { - name: string; - value: string; -} - /** - * The fields of the `http_response` model this sender writes as a send - * progresses. Every one is optional: a field this file never sets takes the - * model layer's default, the same way the desktop's row does. Defaults live in - * Rust, once. + * The response row as this file knows it: what identifies it, plus whatever + * has been written so far. Every other field is optional and takes the model + * layer's default when absent, the same way the desktop's row does — defaults + * live in Rust, once. */ -interface ResponsePatch { - state?: "initialized" | "connected" | "closed"; - url?: string; - status?: number; - statusReason?: string | null; - version?: string | null; - remoteAddr?: string | null; - headers?: HttpResponseHeader[]; - requestHeaders?: HttpResponseHeader[]; - contentLength?: number | null; - contentLengthCompressed?: number | null; - elapsed?: number; - elapsedHeaders?: number; - elapsedDns?: number; - error?: string | null; -} +type ResponseRow = Pick & + Partial>; -/** The row itself: what identifies it, plus whatever has been written so far. */ -type ResponseRow = { - model: "http_response"; - id?: string; - requestId: string; - workspaceId: string; -} & ResponsePatch; - -interface CookieJarModel { - model: "cookie_jar"; - id: string; - cookies: unknown[]; - [key: string]: unknown; -} +type ResponsePatch = Partial; /** What `prepare_http_send` (crates/yaak-web) hands back. */ interface PreparedHttpSend { - request: { url: string; [key: string]: unknown }; + request: HttpRequest; settings: ProxyRequestBody["settings"]; - settingEvents: unknown[]; - cookieJar: CookieJarModel | null; + settingEvents: HttpResponseEventData[]; + cookieJar: CookieJar | null; } /** The desktop writes progress at most this often while a body streams in. */ @@ -92,7 +65,7 @@ export async function sendHttpRequest( requestId: string, environmentId: string | null, cookieJarId: string | null, -): Promise { +): Promise { // The response row exists before anything can go wrong, as on the desktop, so // a failure to render or to reach the proxy lands in the response pane as // that response's error rather than as a toast that names no request. @@ -300,7 +273,7 @@ class ResponseWriter { * which the whole timeline is known to be in the database. */ class TimelineWriter { - private queue: unknown[] = []; + private queue: HttpResponseEventData[] = []; private inFlight: Promise = Promise.resolve(); constructor( @@ -309,7 +282,7 @@ class TimelineWriter { private readonly workspaceId: string, ) {} - push(events: unknown[]): void { + push(events: HttpResponseEventData[]): void { if (events.length === 0) return; this.queue.push(...events); this.inFlight = this.inFlight.then(() => this.drain()); @@ -331,11 +304,7 @@ class TimelineWriter { } } -async function persistCookies( - db: WorkerConnection, - jar: CookieJarModel, - cookies: unknown[], -): Promise { +async function persistCookies(db: WorkerConnection, jar: CookieJar, cookies: Cookie[]): Promise { // The desktop compares before writing so a jar edited mid-send isn't clobbered // by an unchanged copy. Structural equality is enough here: cookies are plain // data and the proxy hands back the whole jar.