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>
This commit is contained in:
2026-07-02 15:37:28 -04:00
parent f45acb645b
commit 9134e7d216
70 changed files with 160 additions and 151 deletions
+8 -8
View File
@@ -1,12 +1,12 @@
import { useState, useEffect, useMemo, useRef, lazy, Suspense } from 'react'
import { FluentProvider, makeStyles, tokens } from '@fluentui/react-components'
import { Sidebar } from './components/Sidebar'
import { DownloadsView } from './components/DownloadsView'
import { Onboarding } from './components/Onboarding'
import { DownloadsView } from './views/DownloadsView'
import { Onboarding } from './views/Onboarding'
import { CommandPalette, type PaletteAction } from './components/CommandPalette'
import { LiveRegion } from './components/LiveRegion'
import { Toaster } from './components/ui/Toaster'
import { getTheme, pageBackground } from './theme'
import { getTheme, pageBackground } from './lib/theme'
import { useSettings } from './store/settings'
import { useNav } from './store/nav'
import { useDownloads } from './store/downloads'
@@ -16,7 +16,7 @@ import { useDownloads } from './store/downloads'
// was guaranteed by downloads.ts importing it; now that the cycle is broken, App
// owns the eager load so it survives the views becoming lazy-loaded (PERF8).
import './store/sources'
import { queueSummaryOf } from './store/queueStats'
import { queueSummaryOf } from './lib/queueStats'
import { useResolvedDark } from './store/systemTheme'
import { logError } from './reportError'
@@ -26,16 +26,16 @@ import { logError } from './reportError'
// views use are imported eagerly above (`useDownloads` + `./store/sources`, and
// downloads → history), so lazy-loading the *view* never delays store startup.
const LibraryView = lazy(() =>
import('./components/LibraryView').then((m) => ({ default: m.LibraryView }))
import('./views/LibraryView').then((m) => ({ default: m.LibraryView }))
)
const HistoryView = lazy(() =>
import('./components/HistoryView').then((m) => ({ default: m.HistoryView }))
import('./views/HistoryView').then((m) => ({ default: m.HistoryView }))
)
const TerminalView = lazy(() =>
import('./components/TerminalView').then((m) => ({ default: m.TerminalView }))
import('./views/TerminalView').then((m) => ({ default: m.TerminalView }))
)
const SettingsView = lazy(() =>
import('./components/SettingsView').then((m) => ({ default: m.SettingsView }))
import('./views/SettingsView').then((m) => ({ default: m.SettingsView }))
)
// How often to check whether a scheduled ('saved' + due) download should promote
+1 -1
View File
@@ -27,7 +27,7 @@ import {
import { useEffect, useRef } from 'react'
import { type MediaKind } from '../store/downloads'
import { useNav } from '../store/nav'
import { QUALITY_OPTIONS } from '../qualityOptions'
import { QUALITY_OPTIONS } from '../lib/qualityOptions'
import { Select } from './Select'
import { Hint } from './Hint'
import { SegmentedControl } from './ui/SegmentedControl'
+1 -1
View File
@@ -3,7 +3,7 @@ import { makeStyles, mergeClasses } from '@fluentui/react-components'
import { VideoClipRegular, MusicNote2Regular } from '@fluentui/react-icons'
import type { MediaKind } from '@shared/ipc'
import { useResolvedDark } from '../store/systemTheme'
import { thumbColors } from '../theme'
import { thumbColors } from '../lib/theme'
const useStyles = makeStyles({
box: {
+3 -3
View File
@@ -27,8 +27,8 @@ import {
} from '@fluentui/react-icons'
import { useShallow } from 'zustand/react/shallow'
import { useDownloads, type DownloadItem } from '../store/downloads'
import { thumbUrl } from '../thumb'
import { fmtSchedule } from '../datetime'
import { thumbUrl } from '../lib/thumb'
import { fmtSchedule } from '../lib/datetime'
import { fmtSpeed, fmtEta } from '@shared/format'
import { MediaThumb } from './MediaThumb'
import { Hint } from './Hint'
@@ -36,7 +36,7 @@ import { StatusChip } from './ui/StatusChip'
import { useFocusStyles } from './ui/focusRing'
import { useTextStyles } from './ui/text'
import { SPACE, RADIUS, ICON, META_SEP } from './ui/tokens'
import { THUMB_MD } from '../thumbSizes'
import { THUMB_MD } from '../lib/thumbSizes'
const useStyles = makeStyles({
root: {
@@ -19,7 +19,7 @@ import {
} from '@fluentui/react-icons'
import type { CommandTemplate } from '@shared/ipc'
import { useTemplates } from '../store/templates'
import { newId } from '../id'
import { newId } from '../lib/id'
import { Hint } from './Hint'
import { EmptyState } from './ui/EmptyState'
import { SPACE } from './ui/tokens'
@@ -1,5 +1,5 @@
import { makeStyles, tokens, shorthands } from '@fluentui/react-components'
import { THUMB_LG } from '../../thumbSizes'
import { THUMB_LG } from '../../lib/thumbSizes'
import { SPACE, RADIUS, ELEVATION } from '../ui/tokens'
export const useDownloadBarStyles = makeStyles({
@@ -10,8 +10,8 @@ import {
} from '@shared/ipc'
import { useDownloads, type MediaKind } from '../../store/downloads'
import { useHistory } from '../../store/history'
import { QUALITY_OPTIONS } from '../../qualityOptions'
import { sameVideo } from '../../store/queueStats'
import { QUALITY_OPTIONS } from '../../lib/qualityOptions'
import { sameVideo } from '../../lib/queueStats'
import { useSettings } from '../../store/settings'
import { useNav } from '../../store/nav'
import {
@@ -20,7 +20,7 @@ import {
looksLikeChannelOrPlaylist,
firstUrlInText,
type SuggestionSource
} from '../../useClipboardLink'
} from '../../lib/useClipboardLink'
import { logError } from '../../reportError'
/** Pull the URL= target out of a dropped Windows .url Internet Shortcut file. */
@@ -4,7 +4,7 @@
* / window dependency (only a type-only import of DownloadItem) so it can be
* unit-tested without constructing the Zustand store or its preview ticker.
*/
import type { DownloadItem } from './downloads'
import type { DownloadItem } from '../store/downloads'
import { youtubeId } from '../lib/urlHelpers'
import { fmtSpeed, fmtEta } from '@shared/format'
@@ -4,7 +4,7 @@
* video id with no extra network probe. Anything non-YouTube without a probed
* thumbnail returns undefined, and the UI falls back to a kind icon.
*/
import { youtubeId } from './lib/urlHelpers'
import { youtubeId } from './urlHelpers'
/**
* Resolve a preview thumbnail URL for a media item. Prefers an explicit thumbnail
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useRef, useState } from 'react'
import { useSettings } from './store/settings'
import { useSettings } from '../store/settings'
// Pure URL helpers extracted to a standalone module so they can be tested
// without pulling in the Zustand store (L40). Re-exported here for existing
// consumers (DownloadBar, LibraryView) without an import-path change.
@@ -8,8 +8,8 @@ export {
looksLikeSingleVideo,
looksLikeChannelOrPlaylist,
firstUrlInText
} from './lib/urlHelpers'
import { looksLikeUrl } from './lib/urlHelpers'
} from './urlHelpers'
import { looksLikeUrl } from './urlHelpers'
/** Where an offered link came from — drives the banner's wording. */
export type SuggestionSource = 'clipboard' | 'external'
+1 -1
View File
@@ -1,5 +1,5 @@
import { type DownloadMeta, type MediaKind } from '@shared/ipc'
import { newId } from '../id'
import { newId } from '../lib/id'
import { youtubeId } from '../lib/urlHelpers'
import { type AddOptions, type DownloadItem } from './downloadTypes'
+1 -1
View File
@@ -1,5 +1,5 @@
import { isPreview as PREVIEW } from '../isPreview'
import { newId } from '../id'
import { newId } from '../lib/id'
import { type DownloadItem } from './downloadTypes'
// Mock seed data so every visual state is visible in the UI preview. Empty in a
+1 -1
View File
@@ -1,5 +1,5 @@
import { create } from 'zustand'
import { newId } from '../id'
import { newId } from '../lib/id'
/**
* A tiny transient-notification store (audit UX6/UX9). The app had no way to tell
@@ -10,13 +10,13 @@
} from '@fluentui/react-components'
import { ArrowDownloadRegular, ArrowClockwiseRegular, DismissRegular } from '@fluentui/react-icons'
import { useDownloads, type DownloadItem } from '../store/downloads'
import { queueSummaryOf } from '../store/queueStats'
import { DownloadBar } from './DownloadBar'
import { QueueItem } from './QueueItem'
import { VirtualList } from './VirtualList'
import { ScreenHeader, useScreenStyles } from './ui/Screen'
import { EmptyState } from './ui/EmptyState'
import { SPACE, ICON, META_SEP } from './ui/tokens'
import { queueSummaryOf } from '../lib/queueStats'
import { DownloadBar } from '../components/DownloadBar'
import { QueueItem } from '../components/QueueItem'
import { VirtualList } from '../components/VirtualList'
import { ScreenHeader, useScreenStyles } from '../components/ui/Screen'
import { EmptyState } from '../components/ui/EmptyState'
import { SPACE, ICON, META_SEP } from '../components/ui/tokens'
// Hoisted so the virtualizer gets stable function identities and doesn't churn its
// measurement/key cache on every render (PERF5).
@@ -22,21 +22,21 @@ import {
} from '@fluentui/react-icons'
import type { HistoryEntry, MediaKind } from '@shared/ipc'
import { useHistory } from '../store/history'
import { formatWhen } from '../datetime'
import { formatWhen } from '../lib/datetime'
import { useResolvedDark } from '../store/systemTheme'
import { useDownloads } from '../store/downloads'
import { thumbColors } from '../theme'
import { thumbUrl } from '../thumb'
import { MediaThumb } from './MediaThumb'
import { Hint } from './Hint'
import { Select } from './Select'
import { VirtualList } from './VirtualList'
import { ScreenHeader, useScreenStyles } from './ui/Screen'
import { EmptyState } from './ui/EmptyState'
import { useFocusStyles } from './ui/focusRing'
import { useTextStyles } from './ui/text'
import { SPACE, ICON, META_SEP } from './ui/tokens'
import { THUMB_SM } from '../thumbSizes'
import { thumbColors } from '../lib/theme'
import { thumbUrl } from '../lib/thumb'
import { MediaThumb } from '../components/MediaThumb'
import { Hint } from '../components/Hint'
import { Select } from '../components/Select'
import { VirtualList } from '../components/VirtualList'
import { ScreenHeader, useScreenStyles } from '../components/ui/Screen'
import { EmptyState } from '../components/ui/EmptyState'
import { useFocusStyles } from '../components/ui/focusRing'
import { useTextStyles } from '../components/ui/text'
import { SPACE, ICON, META_SEP } from '../components/ui/tokens'
import { THUMB_SM } from '../lib/thumbSizes'
const useStyles = makeStyles({
root: {
@@ -29,22 +29,22 @@ import type { MediaItem, Source, MediaKind } from '@shared/ipc'
import { useSources } from '../store/sources'
import { useSettings } from '../store/settings'
import { useNav } from '../store/nav'
import { useClipboardLink, looksLikeSingleVideo } from '../useClipboardLink'
import { useClipboardLink, looksLikeSingleVideo } from '../lib/useClipboardLink'
import { useDownloads, type DownloadStatus } from '../store/downloads'
import { thumbUrl } from '../thumb'
import { relTime } from '../datetime'
import { MediaThumb } from './MediaThumb'
import { VirtualList } from './VirtualList'
import { Hint } from './Hint'
import { ScreenHeader, useScreenStyles } from './ui/Screen'
import { StatusChip } from './ui/StatusChip'
import { SegmentedControl } from './ui/SegmentedControl'
import { EmptyState } from './ui/EmptyState'
import { LinkSuggestion } from './ui/LinkSuggestion'
import { useFocusStyles } from './ui/focusRing'
import { useTextStyles } from './ui/text'
import { SPACE, RADIUS, ICON, META_SEP } from './ui/tokens'
import { THUMB_XS } from '../thumbSizes'
import { thumbUrl } from '../lib/thumb'
import { relTime } from '../lib/datetime'
import { MediaThumb } from '../components/MediaThumb'
import { VirtualList } from '../components/VirtualList'
import { Hint } from '../components/Hint'
import { ScreenHeader, useScreenStyles } from '../components/ui/Screen'
import { StatusChip } from '../components/ui/StatusChip'
import { SegmentedControl } from '../components/ui/SegmentedControl'
import { EmptyState } from '../components/ui/EmptyState'
import { LinkSuggestion } from '../components/ui/LinkSuggestion'
import { useFocusStyles } from '../components/ui/focusRing'
import { useTextStyles } from '../components/ui/text'
import { SPACE, RADIUS, ICON, META_SEP } from '../components/ui/tokens'
import { THUMB_XS } from '../lib/thumbSizes'
/** Per-item status shown in the library: a live queue status, or pending/downloaded. */
type ItemStatus = DownloadStatus | 'pending'
@@ -22,7 +22,7 @@ import {
KeyboardRegular
} from '@fluentui/react-icons'
import { useSettings } from '../store/settings'
import { SPACE, ICON } from './ui/tokens'
import { SPACE, ICON } from '../components/ui/tokens'
const useStyles = makeStyles({
root: {
@@ -12,8 +12,8 @@ import {
} from '@fluentui/react-components'
import { SearchRegular } from '@fluentui/react-icons'
import { useSettings } from '../store/settings'
import { ScreenHeader, useScreenStyles } from './ui/Screen'
import { SPACE } from './ui/tokens'
import { ScreenHeader, useScreenStyles } from '../components/ui/Screen'
import { SPACE } from '../components/ui/tokens'
import { DownloadsCard } from './settings/DownloadsCard'
import { AppearanceCard } from './settings/AppearanceCard'
import { PostProcessingCard } from './settings/PostProcessingCard'
@@ -11,9 +11,9 @@ import {
} from '@fluentui/react-components'
import { PlayRegular, DismissRegular, DeleteRegular } from '@fluentui/react-icons'
import { useSettings } from '../store/settings'
import { ScreenHeader, useScreenStyles } from './ui/Screen'
import { EmptyState } from './ui/EmptyState'
import { SPACE } from './ui/tokens'
import { ScreenHeader, useScreenStyles } from '../components/ui/Screen'
import { EmptyState } from '../components/ui/EmptyState'
import { SPACE } from '../components/ui/tokens'
import { useTerminalRun, type LineKind } from './useTerminalRun'
const useStyles = makeStyles({
@@ -13,8 +13,8 @@ import {
import { InfoRegular, ArrowSyncRegular } from '@fluentui/react-icons'
import { type YtdlpUpdateChannel } from '@shared/ipc'
import { useSettings } from '../../store/settings'
import { Select } from '../Select'
import { useErrorTextStyles } from '../ui/errorText'
import { Select } from '../../components/Select'
import { useErrorTextStyles } from '../../components/ui/errorText'
import { useSettingsStyles } from './settingsStyles'
import { useAboutCard } from './useAboutCard'
@@ -12,9 +12,9 @@ import { PaintBucketRegular, AccessibilityRegular } from '@fluentui/react-icons'
import { type ThemeMode, type AccentColor } from '@shared/ipc'
import { useSettings } from '../../store/settings'
import { useSystemTheme } from '../../store/systemTheme'
import { Select } from '../Select'
import { ACCENT_OPTIONS } from '../../theme'
import { useFocusStyles } from '../ui/focusRing'
import { Select } from '../../components/Select'
import { ACCENT_OPTIONS } from '../../lib/theme'
import { useFocusStyles } from '../../components/ui/focusRing'
import { useSettingsStyles } from './settingsStyles'
const THEME_MODE_OPTIONS = [
@@ -1,6 +1,6 @@
import { Button, Card, Subtitle2, Caption1 } from '@fluentui/react-components'
import { DocumentArrowDownRegular, DocumentArrowUpRegular } from '@fluentui/react-icons'
import { useErrorTextStyles } from '../ui/errorText'
import { useErrorTextStyles } from '../../components/ui/errorText'
import { useSettingsStyles } from './settingsStyles'
import { useBackupCard } from './useBackupCard'
@@ -2,8 +2,8 @@ import { Field, Input, Button, Card, Subtitle2, Caption1 } from '@fluentui/react
import { CookiesRegular } from '@fluentui/react-icons'
import { COOKIE_BROWSERS, type CookieSource, type CookieBrowser } from '@shared/ipc'
import { useSettings } from '../../store/settings'
import { Select } from '../Select'
import { useErrorTextStyles } from '../ui/errorText'
import { Select } from '../../components/Select'
import { useErrorTextStyles } from '../../components/ui/errorText'
import { useSettingsStyles } from './settingsStyles'
import { useCookiesCard } from './useCookiesCard'
@@ -2,8 +2,8 @@ import { Field, Switch, Card, Subtitle2, Caption1 } from '@fluentui/react-compon
import { CodeRegular } from '@fluentui/react-icons'
import { useSettings } from '../../store/settings'
import { useTemplates } from '../../store/templates'
import { Select } from '../Select'
import { TemplateManager } from '../TemplateManager'
import { Select } from '../../components/Select'
import { TemplateManager } from '../../components/TemplateManager'
import { useSettingsStyles } from './settingsStyles'
export function CustomCommandsCard(): React.JSX.Element {
@@ -2,8 +2,8 @@ import { useState } from 'react'
import { Button, Card, Subtitle2, Caption1, Text } from '@fluentui/react-components'
import { BugRegular, CopyRegular, DeleteRegular } from '@fluentui/react-icons'
import { useErrorLog } from '../../store/errorlog'
import { useErrorTextStyles } from '../ui/errorText'
import { EmptyState } from '../ui/EmptyState'
import { useErrorTextStyles } from '../../components/ui/errorText'
import { EmptyState } from '../../components/ui/EmptyState'
import { useSettingsStyles } from './settingsStyles'
export function DiagnosticsCard(): React.JSX.Element {
@@ -11,9 +11,9 @@ import { FolderRegular, ArrowDownloadRegular } from '@fluentui/react-icons'
import { type MediaKind } from '@shared/ipc'
import { useSettings } from '../../store/settings'
import { useDownloads } from '../../store/downloads'
import { QUALITY_OPTIONS } from '../../qualityOptions'
import { Select } from '../Select'
import { SegmentedControl } from '../ui/SegmentedControl'
import { QUALITY_OPTIONS } from '../../lib/qualityOptions'
import { Select } from '../../components/Select'
import { SegmentedControl } from '../../components/ui/SegmentedControl'
import { useSettingsStyles } from './settingsStyles'
export function DownloadsCard(): React.JSX.Element {
@@ -1,7 +1,7 @@
import { Card, Subtitle2, Caption1 } from '@fluentui/react-components'
import { OptionsRegular } from '@fluentui/react-icons'
import { useSettings } from '../../store/settings'
import { DownloadOptionsForm } from '../DownloadOptionsForm'
import { DownloadOptionsForm } from '../../components/DownloadOptionsForm'
import { useSettingsStyles } from './settingsStyles'
export function PostProcessingCard(): React.JSX.Element {
@@ -17,7 +17,7 @@ import {
DismissRegular
} from '@fluentui/react-icons'
import { useSettings } from '../../store/settings'
import { useErrorTextStyles } from '../ui/errorText'
import { useErrorTextStyles } from '../../components/ui/errorText'
import { useSettingsStyles } from './settingsStyles'
import { useSoftwareUpdateCard } from './useSoftwareUpdateCard'
@@ -1,5 +1,5 @@
import { makeStyles, tokens, shorthands } from '@fluentui/react-components'
import { SPACE, RADIUS, ICON } from '../ui/tokens'
import { SPACE, RADIUS, ICON } from '../../components/ui/tokens'
// Shared styles for the Settings cards. Each card renders a single <Card> so it
// stays one direct child of SettingsView's root -- the search filter toggles
@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from 'react'
import { newId } from '../id'
import { newId } from '../lib/id'
export type LineKind = 'stdout' | 'stderr' | 'cmd' | 'sys'
export interface Line {