When a server (like fuckingfast.co) ignores the upper bound of a range request (returning bytes=start-end/total), aria2 aborts with 'Invalid range header'. This patch treats that error as transient and mutates the download payload to force connections=1 before re-enqueuing. This ensures aria2 issues an open-ended range request (bytes=start-) on the retry, seamlessly resuming the download.
aria2 prefixes HTTP statuses with 'status=XXX' in its onDownloadError payload instead of 'HTTP XXX'. These were falling through the transient check and causing instant, permanent failure instead of triggering the escalating backoff schedule.
Fallback to GET Range for metadata when HEAD fails or misses Content-Length. Fetch aria2 WS error payload via tellStatus. Escalate 429 retries with specific 60/120/300s backoff. Persist download fraction for paused tasks.
- Pass captured cookies and headers from UI state into the backend `fetch_metadata` command.
- Implement secure domain-matching redirect policy in the backend to prevent leaking cookies, headers, and Basic Auth credentials to third-party domains upon redirect.
- Ensure metadata fetches correctly identify authenticated files (e.g. from Gofile) without being redirected to login/error pages.
- Update 'fetch_metadata' to detect 'Accept-Ranges' HTTP header
- Persist 'resumable' flag in DownloadItem across backend and frontend
- Add confirmation dialog when pausing non-resumable downloads (single and bulk actions)
- Improve UI for start/pause/options buttons by adopting the application accent color on hover
- 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.
- Pass '--stop-with-process' to the aria2c command using the app's Process ID.
- Prevents aria2c from becoming an orphaned process and continuing downloads invisibly in the background after the app is forcefully closed or terminated.
- 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.
- Remove deprecated `cocoa` crate in favor of direct `objc` usage to fix future-incompatibilities warning from `block` dependency.
- Fix irrefutable `if let` pattern warning in macOS `SleepPreventer::Drop`.
- Fix memory leaks by properly releasing `alloc`-ed `NSString` and `NSAppleScript` objects.
- Fix AppKit thread safety by routing dock badge updates to the main thread via `run_on_main_thread`.
- 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
- Fix re-entrant deadlock in `legacy_download_queue_paths` by scoping DB lock
- Ensure `release_registered_id` runs in `remove_download` even if cleanup fails
- Add fallback to `std::fs::remove_file` if `trash::delete` fails
- Ignore 'cannot be paused now' error in `detach_download_for_reconfigure`
- Apply `break-all` and `whitespace-pre-wrap` to Toast messages to prevent UI overflow
- 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
- Revert hydrate_extension_pairing_token to consult the DB's
keychainAccessGranted flag instead of unconditionally skipping the
keychain. When the flag is true the backend tries the keychain; if
macOS trusts the current binary (no code-signature change) the read
succeeds silently and the modal is suppressed. When the flag is
false the keychain is skipped and the modal is shown exactly once.
- Fix the Grant Access button in the KeychainPermissionModal by
writing the result (token, persistent flag) directly into the store
instead of calling hydratePairingToken() again. The re-hydration
raced with Zustand's async persist middleware, which could read
keychainAccessGranted=false from the DB and flip persistent back
to false, re‑showing the modal in an endless loop.
- The scheduler defaults (enabled: false) were already correct in
both the Rust default_settings() and the frontend Zustand store;
no code change needed.
- 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.