Files
AeroFetch/src/main/history.ts
T
debont80 9134e7d216 feat(audit): Batch 25 — project reorg (CC12), leading DI args (CC7), CC10 by-design
CC12: renderer views/ (5 screens + Onboarding + settings cards) +
lib/ (theme/thumb/datetime/id/qualityOptions/useClipboardLink/queueStats);
main core/ (buildArgs/validation/indexerCore/ytdlpPolicy). git mv preserved
history; all src+test imports updated. Build emits view chunks from views/,
344 tests + typecheck green, live probe rendered all screens.
CC7: wc/onProgress is the leading arg everywhere — downloadAppUpdate(wc,url),
indexSource(onProgress,url,signal), indexSourceCancelable(onProgress,url).
CC10: closed by-design — jsonStore backs all records; settings stay in
electron-store for DPAPI secret encryption (a deliberate two-store split).
Also closes the UI24/W4 context-menu cross-reference.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 15:37:28 -04:00

40 lines
1.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { HISTORY_MAX_ENTRIES, type HistoryEntry } from '@shared/ipc'
import { isValidHistoryEntry } from './core/validation'
import { createJsonStore } from './jsonStore'
// Plain JSON in userData (portable build redirects userData next to the exe).
// Kept simple per the build plan; can migrate to better-sqlite3 later. Atomic
// writes, corruption backup, and caching come from the shared jsonStore (R1R3).
// The row cap (HISTORY_MAX_ENTRIES) is shared with the renderer's optimistic list.
//
// Per-entry validation (isValidHistoryEntry) so a hand-edited or corrupted
// history.json can't feed the UI (or openPath) entries with the wrong shape —
// invalid rows are dropped rather than trusted. (audit S5)
const store = createJsonStore('history.json', isValidHistoryEntry, HISTORY_MAX_ENTRIES)
export function listHistory(): HistoryEntry[] {
return store.read()
}
export function addHistory(entry: HistoryEntry): HistoryEntry[] {
// De-dupe by id AND url (M35): a History re-download re-queues via addFromUrl,
// which mints a NEW id, so id-only de-dup would let the same video accumulate a
// fresh row on every re-download. Dropping any prior entry with the same url
// keeps one row per video, refreshed to the top.
const prior = listHistory().filter((e) => e.id !== entry.id && e.url !== entry.url)
return store.write([entry, ...prior])
}
export function removeHistory(id: string): HistoryEntry[] {
return store.write(listHistory().filter((e) => e.id !== id))
}
export function removeManyHistory(ids: string[]): HistoryEntry[] {
const remove = new Set(ids)
return store.write(listHistory().filter((e) => !remove.has(e.id)))
}
export function clearHistory(): HistoryEntry[] {
return store.write([])
}