fix(viewer): hand off transcript ID only, fetch row from SQLite on mount
HistoryPage previously serialised the full TranscriptDto — text, segments,
manual + LLM tags, audio path — into `localStorage["kon_viewer_item"]` so
the viewer window could pick it up on mount. On a multi-hour transcript
that's MB-scale of user voice content sitting in storage that any
same-origin script in any open Kon window can read.
Hand off only `{ id }` (and a timestamp on re-saves). The viewer fetches
the canonical row from SQLite via the existing `get_transcript` Tauri
command and hydrates via the now-exported `mapTranscriptRow`. Cross-window
sync via the `storage` event still works — the receiving window re-fetches
on event instead of trusting the payload.
- HistoryPage `openViewer` + `openEditor`: write `{ id }` only.
- viewer `onMount` + `handleStorageChange`: route through new
`loadFromHandoff` which calls `invoke("get_transcript", { id })`.
- viewer `saveItemToHistory`: re-stamp localStorage with `{ id, stamp }`
to retrigger the storage event in sibling windows without leaking
content.
- `mapTranscriptRow` exported from page.svelte.ts for the viewer's use.
Backward-compatible at the parse layer: the `{ id }` shape extracts cleanly
from a stale full-DTO payload (TranscriptEntry already carries `id` at top
level), so a session that survives the upgrade picks up the new path on
next handoff without manual cleanup.
https://claude.ai/code/session_0189xUb6ie6t9qHkzatGZ9Rb
This commit is contained in:
@@ -335,12 +335,18 @@
|
||||
}
|
||||
|
||||
async function openViewer(item) {
|
||||
// Hand off the transcript ID only — the viewer window fetches the full
|
||||
// row from SQLite via `get_transcript`. Previously the entire DTO
|
||||
// (text + segments + tags) was stuffed into localStorage, putting
|
||||
// potentially MB-scale PII in a place readable by any same-origin
|
||||
// script.
|
||||
const handoff = JSON.stringify({ id: String(item.id) });
|
||||
try {
|
||||
localStorage.setItem("kon_viewer_item", JSON.stringify(item));
|
||||
localStorage.setItem("kon_viewer_item", handoff);
|
||||
localStorage.setItem("kon_viewer_mode", "view");
|
||||
await invoke("open_viewer_window");
|
||||
} catch {
|
||||
localStorage.setItem("kon_viewer_item", JSON.stringify(item));
|
||||
localStorage.setItem("kon_viewer_item", handoff);
|
||||
localStorage.setItem("kon_viewer_mode", "view");
|
||||
window.open("/viewer", "_blank", "width=600,height=700");
|
||||
}
|
||||
@@ -499,12 +505,15 @@
|
||||
});
|
||||
|
||||
async function openEditor(item) {
|
||||
// Hand off the transcript ID only; the viewer hydrates from SQLite
|
||||
// (see openViewer above for the rationale).
|
||||
const handoff = JSON.stringify({ id: String(item.id) });
|
||||
try {
|
||||
localStorage.setItem("kon_viewer_item", JSON.stringify(item));
|
||||
localStorage.setItem("kon_viewer_item", handoff);
|
||||
localStorage.setItem("kon_viewer_mode", "edit");
|
||||
await invoke("open_viewer_window");
|
||||
} catch {
|
||||
localStorage.setItem("kon_viewer_item", JSON.stringify(item));
|
||||
localStorage.setItem("kon_viewer_item", handoff);
|
||||
localStorage.setItem("kon_viewer_mode", "edit");
|
||||
window.open("/viewer", "_blank", "width=600,height=700");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user