Audit Assignment 06 lifecycle paths and preserve truthful state across ambiguous Aria2 resume failures. Clean up partial startup listener registration and prevent stale resume workers from leaking or releasing current permits.
Guard scheduler system actions against pending work, serialize diagnostic log transitions, and keep speed-limit saves truthful after backend failures.\n\nNo linked issue was found for this audit.
Serialize queue controls, make multi-item moves atomic, await stale enqueue cleanup, and guard late media and progress events. Add deterministic table sorting and regression coverage for worst-case lifecycle races.
Reject stale extension media cookie headers before yt-dlp metadata work, preserve ordinary capture cookies, and advance the companion extension.
Stream redacted diagnostic logs only while the visible Logs view is active, with bounded batched updates and race-safe snapshot handoff.
- Preserved extension-captured cookies through the Add modal, with a clean fallback when captured cookies break metadata fetching.
- Prevented batched extension captures from losing URLs or reusing stale cookie/header contexts.
- Fixed pause/resume and enqueue generation races, including cancellation during queue reservation and replay after task removal.
- Made startup database initialization safe under React StrictMode.
- Serialized keyring operations and corrected Linux legacy migration/deletion behavior.
- Restored `Downloading` state after yt-dlp retries.
- Replaced hardcoded media heights with dynamically detected formats, including nonstandard qualities such as 576p and 2880p.
Move the collapsed sidebar reveal control into the app shell so Settings, Scheduler, Speed Limiter, Logs, and Downloads all have a recovery path. Keep separate collapsed spacing for macOS and Windows/Linux window controls to avoid overlap.\n\nFixes #9
- Refine toast animations and durations
- Prevent extension-captured cookies from being sent across cross-origin redirects
- Clear stale extension metadata properly for single-link handoffs
- Disable completion sound by default and update settings labels
- Handle AudioContext suspension for completion chimes
Modernize the Tools release surfaces for the cross-platform re-release checklist.
- make Speed Limiter presets unit-aware and persist custom removable quick presets
- keep diagnostic logging opt-in on clean installs and honor the saved log state on startup
- stage Scheduler enablement edits without discarding unsaved draft changes
- extend persisted settings and bindings for log opt-in and speed preset state
Verification:
- npm run build
- npm test -- --run src/store/useDownloadStore.test.ts
- cargo test --lib
- cargo test settings --lib
Play the completion sound through the app with Web Audio so it is not tied to whether desktop notifications are enabled or whether a platform-specific notification sound name is supported.
Keep the notification body focused on completion status and leave the settings toggle available even when notifications are disabled.
Disable the native Windows frame at startup and render in-app window controls so packaged builds use Firelink's own titlebar placement instead of the default OS chrome.
Apply CREATE_NO_WINDOW to raw child processes used by the aria2 daemon and shared engine version checks. Route ffmpeg and deno checks through the same hidden version-check helper so Settings > Engine does not flash console windows.
Normalize Windows extended-length paths before returning approved download roots to the UI, while keeping canonicalization for backend safety checks. Detect yt-dlp's embedded runtime per platform so Windows onedir builds look for python*.dll instead of macOS Python.framework.
Verification: npm run build; cargo check --manifest-path src-tauri/Cargo.toml; cargo test --manifest-path src-tauri/Cargo.toml --lib; node --check scripts/smoke-packaged-app.js; Ruby YAML parse for .github/workflows/release.yml; git diff --check.
- Ensure yt-dlp partial files are cleaned up on error exits.
- Handle Semaphore closure gracefully without panicking.
- Replace busy-polling in wait_permit_released with Notify.
- Fix extension server silent failure with retry loop and logging.
- Ignore malformed existing scheduler settings instead of failing.
- Add final symlink checks before revealing/opening downloads.
- Delay listener registration in App.tsx until core is ready.
- Sanitize Referer header to prevent injection.
- Implement scheduler hydration barrier to prevent premature triggers
- Track scheduler exact runs using keys to avoid false stops
- Use 'System Events' for accurate macOS automation permissions
- Prevent system-sleep via proper idle assertions
- Ensure download pauses use channel acknowledgements (PauseWithAck)
- Require Firelink ownership before replacing files in add/conflict UI
- Retain partial download assets when removing entries without deletion
- Clear progress state in store when downloads complete or pause to reduce churn
- Handle empty/invalid queue selections gracefully
- Created root-level ToastProvider and useToast hook
- Replaced scattered ad-hoc toast states with unified provider
- Updated Settings, Scheduler, Speed Limiter, App, and DownloadTable to use ToastContext
- Added variant support (success, info, warning, error) with distinct styling
- Refined toast animations and styling for modern aesthetics
- Adjusted auto-dismiss behavior to ignore actionable or important errors
- Add backendRegisteredIds and backendDispatchPromises for single dispatch enforcement
- Add detach_download_for_reconfigure to safely modify properties of active downloads
- Add applyProperties logic handling completed, failed, paused, and active queues
- Add extractValidDownloadUrls and fix multi-url paste handling
- Setup vitest and add useDownloadStore unit tests for backend registration lifecycle
- Strip password, cookies, and headers from download_queue before writing
to store.bin; secrets remain in-memory for the active session only.
- Move extension pairing token from PersistedSettings to the OS keychain,
rotating it on upgrade from versions that persisted it as plaintext.
- Add ignores_legacy_extension_pairing_token_field test to confirm serde
silently drops the old field so existing installs migrate cleanly.
- Document intentional retention of URLs (signed params are the download
source and cannot be redacted without breaking resume/retry).
This commit replaces the frontend-imperative download dispatcher with a centralized backend `QueueManager`. It acts as the sole concurrency gatekeeper using a single `tokio::sync::Semaphore` across all download paths (aria2 RPC, native HTTP, yt-dlp media).
Backend Changes:
- **queue**: Added `QueueManager` to manage an ordered `VecDeque` of tasks, semaphore permits, and retirement debt (CAS resize).
- **commands**: Replaced direct start commands with `enqueue_download`, `enqueue_many`, `move_in_queue`, and `remove_from_queue`.
- **ipc**: Exported `DownloadStateEvent` and `QueueDirection` to the frontend.
- **tests**: Added 11 integration tests covering idle-parking, idempotent releases, CAS underflow prevention, and gid-completion races.
Frontend Changes:
- **store**: Made `useDownloadStore` reactive to the backend via the `download-state` event.
- **store**: Removed `processQueue` and introduced `pendingOrder` to track the accurate sequence of queued items.
- **ui**: Updated `DownloadItem` with queue visuals (clock icon, position badge).
- **ui**: Added Move Up/Down controls to interact with the backend queue reordering API.
- Add global Cmd+V keyboard paste support for downloading links
- Restore striped background styling for alternate rows in download list
- Add ghost rows to seamlessly fill empty download space
- Map correctly formatted item size into the queue immediately
- Remove unused Tauri manager imports from backend
- Fix config location typo to enable authentication
- Wire up bundled Deno to handle YouTube PoW challenges
- Implement iOS/TV player spoofing to bypass web blocks
- Replace fragile regex progress parsing with structured templates
- Add auto-reconnect logic to Aria2 WebSocket
- Deduplicate media domains and fetch dynamically on frontend
- Replace polling loops with global tokio_tungstenite WebSocket listener
- Map Download IDs to Aria2 GIDs in AppState
- Route all standard downloads to Aria2 daemon, mapping all config options
- Refactor path resolution into a DRY helper function
- Add missing terabyte multiplier to frontend speed parser
- refactor(backend): use tokio::sync::Mutex for DbState and update commands to async
- fix(backend): remove unconditional post-queue system action in scheduler
- refactor(backend): remove dead WebSocket aria2 progress loop
- fix(backend): use character count for deep link payload length check
- fix(backend): implement dynamic port fallback for extension server
- build(backend): apply macos codesigning step for release builds
- security(backend): add explicitly defined Content-Security-Policy
- fix(frontend): replace pause_download API call with remove_download for file cleanup
- fix(frontend): resolve bug ignoring 0% progress reporting
- fix(frontend): append instead of overwrite deep link URLs when Add Modal is open
- style(frontend): append standard .dark class for dark mode themes
- style(frontend): remove ghost row layout hack from download table
- build: decouple typescript binding generation from build step