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
- Ensure `initDB` sorts active items by `queuePosition` before dispatching to preserve expected backend execution order on startup.
- Update `resumeDownload` to explicitly move items to the end of the queue visually by assigning a new max `queuePosition`, synchronizing frontend representation with backend queue behavior.
- Change `queuePosition` calculations to use `Math.max` via `reduce` rather than array `.length`, preventing duplicate queue position assignments upon deletions and avoiding call stack limit exceptions for massive queues.
- Modify `DownloadTable.tsx` sorting to enforce active downloads appearing at the top of the queue view, deferring to `queuePosition` only for pending items.
- Exclude active items from `moveInQueue` logic and UI to prevent visual corruption and silent queue scrambling.
- Prevent backward state transitions for downloads in frontend store.
- Add Downloading event emission upon aria2 unpause.
- Fix toast container visual bleed on exit by adding overflow-hidden.
- Add retry backoff for deleted files to prevent Windows file lock errors.
- Lowercase checksum hash types before passing to aria2.
- Clean up lingering files upon checksum verification failure.
- Convert Tauri AppHandle arguments to support generic runtimes.
- Fix "Date added" showing "Invalid date" on redownload by standardizing to ISO string format
- Update handleExtensionDownload to fallback to AddDownloadsModal on silent download dispatch failure
- Fix macOS sleep prevention by utilizing IOKit assertions (PreventSystemSleep and NetworkClientActive) to maintain network connection when display sleeps
- Improve resumeDownload to eagerly update UI state to "Queued" to fix progress bar freezing on resume
- Ensure robust error handling for removeDownload to maintain consistent frontend store state
- Use `e.detail === 2` for double clicks in `DownloadTable.tsx`
- Add `user-select: none` to list items in `index.css`
- Delete existing assets before enqueueing in `redownload` action
- Remove redundant `onDoubleClick` props from `DownloadItem.tsx`
The root cause was hydrate_extension_pairing_token accessing the
keychain when keychainAccessGranted was true in the DB. Any keychain
access on macOS triggers the system prompt when the binary signature
changes after an update.
Architecture change: two-store model.
- The SQLite settings DB is now the primary store for the token.
hydrate_extension_pairing_token reads from it exclusively -- it
never touches the OS keychain. No system prompt on startup.
- The OS keychain remains defence-in-depth: grant_keychain_access
still writes the token there, but it is only reached from the
explicit Grant Access button, so any system prompt is user-initiated.
DB helpers: load_pairing_token_from_settings / save_pairing_token_to_settings
hydrate_extension_pairing_token: reads from DB, skips keychain entirely
grant_keychain_access: syncs token to DB after keychain access
Frontend: extensionPairingToken included in partialize for auto-persist
- Disable log capture by default in both backend (LOG_PAUSED=true) and
frontend (isPaused=true) to avoid unnecessary disk I/O and battery drain.
- Add a global contextmenu listener that prevents the webview's default
right-click menu (Reload, etc.) so the app behaves like a native macOS
window. Custom context menus in DownloadItem, LogsView, and Sidebar
still work because their handlers preventDefault() before the document
listener fires.
- Sort the download table by queuePosition when viewing a specific queue
so the move-up/down controls produce a visible reorder instead of a
silent position swap with no UI feedback.
- Rework the keychain access flow to eliminate the OS credential prompt
that appeared before the app's own KeychainPermissionModal after every
binary update. hydrate_extension_pairing_token now always skips the
keychain; only the explicit Grant Access button (grant_keychain_access)
triggers the OS prompt, which is user-initiated and therefore acceptable
even when macOS trust resets after a code-signature change.
- Default LOG_PAUSED to true in backend.
- Combine tauri_plugin_log filters to drop backend logs when paused.
- Create frontend logger wrapper to intercept and drop logs before IPC when paused.
- Sync LogsView state directly with logger wrapper and handle initialization races.
Disabled implicit system/environment variable proxy fallbacks in reqwest, yt-dlp, and aria2c when no proxy is explicitly provided. Updated useDownloadStore to strictly return 'none' when 'none' is selected or when 'system' proxy is empty, matching IDM/FDM behavior and ignoring http_proxy environment variables.
- 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
- launch Firefox handoffs through authenticated reconnect
- preserve usable drafts when metadata lookup fails
- reject stale metadata results and retry failed rows only
- Remove 'Add to list' function from UI and state store
- Replace 'Add to...' button with 'Add to queue' menu in AddDownloadsModal
- Prevent completed items from displaying in queue views
- Fix right-click context menu overflow clipping the queue submenu
- Gracefully discard completed items when batch-assigning to queues
- Fix 'Show in finder' for unfinished entries to open destination folder
- Add 'Add to queue' submenu for unfinished items
- Support Shift/Cmd modifiers for multi-selection in download list
- Implement mass-action context menu for multi-selected downloads
- Enhance DeleteConfirmationModal to handle mass deletions gracefully
- Replace split 'Default Download Path' and 'All Categories Base' with a canonical baseDownloadFolder and categorySubfolders model
- Retain absolute category overrides only where required
- Update Add window to accurately reflect intended destination:
- Single URL: specific category path
- Multiple URLs: base folder with explanatory text
- Manual Browse override: selected folder
- Centralize path resolution logic shared by Rust backend and UI
- 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).
- Reset items with 'downloading' or 'processing' status to 'queued'
before re-enqueue on startup to prevent phantom active state
- Include 'processing' status in recovery filter (was a zombie path)
- Remove redundant LazyStore('store.bin') from settingsStore.ts;
import shared instance from useDownloadStore.ts instead
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.