Skip to content

Release v3.8.45 - #264

Merged
taylorcox75 merged 16 commits into
mainfrom
release/v3.8.45
Sep 21, 2026
Merged

taylorcox75 merged 16 commits into
mainfrom
release/v3.8.45

Conversation

@taylorcox75

Copy link
Copy Markdown
Owner

v3.8.45

New Features

Bugs Fixed

Maintenance / Build

  • Xcode 27 / iOS 27 SDK hard-fails app launch unless the native project adopts the UIScene life cycle — added expo-build-properties with scene support enabled, and updated the native torrent-file-copy config plugin to match the resulting AppDelegate template change
  • Added npm run simulator

Known follow-up (not blocking this release)

  • [Request] Allow untrusted server to stay on so I don't have to enable it every time I use the app. #256 stays open — the diagnosis/visibility fixes above are shipped, but the reporter's actual connection failure is still unconfirmed pending their diagnostic output.
  • The cold-launch .torrent-copy race-condition protection is structurally weaker under the new scene lifecycle (documented in plugins/withNativeTorrentFileCopy.js) and needs an on-device check: cold-launch by tapping a .torrent file in Files while the app isn't running.

Test plan

  • npx tsc --noEmit: exit 0
  • npm test: 80/80 suites, 1160/1160 tests passing
  • npm run lint: 0 errors, 38 warnings (baseline)
  • Individual PRs were reviewed and checks-verified; the select-mode header/Xcode 27 changes in particular have not been visually confirmed in a simulator by me and should get an on-device pass before merging.

⚠️ Merging this PR pushes main with "easBuild": true in package.json, which triggers ios-deploy.yml → eas build --profile production → eas submit to App Store Connect. Merge when you're ready to ship.

🤖 Generated with Claude Code

taylorcox75 and others added 16 commits September 20, 2026 17:49
feed.tsx rendered articles in whatever order qBittorrent's rss/items
returned (feed-storage order), so they appeared randomly sorted.
Add sortArticlesByDateDesc to utils/rss.ts and use it in the existing
useMemo. Undated or unparseable-date articles sort last and keep their
original relative order, so a feed with no dates renders unchanged.
…server

A GET against an unreachable server used to take ~43s (4 retry attempts x
the full 10s axios timeout, plus 500/1000/1500ms backoff) and, with
TanStack Query's own retry: 2 stacked on top for the torrent/transfer
polls, ~2 minutes before anything surfaced. Disconnect additionally
awaited a logout POST with nothing to cancel it, so it looked broken too.

- services/api/client.ts: withRetry now treats connectionTimeout as a
  total budget for the whole logical request instead of a per-attempt
  allowance, capping each attempt's axios timeout to the remaining budget
  (with a 1s floor) and skipping a retry whose backoff would blow the
  deadline. Added a session-scoped AbortController (abortInFlight()),
  used by default in get/post/postFormData/postUrlEncoded when the caller
  doesn't pass its own signal, and wired into setServer()/clearCookies()
  so every session teardown cancels in-flight requests. ERR_CANCELED now
  gets its own normalized message instead of falling into the generic
  branch — it was already correctly excluded from retry and from
  RECONNECTABLE_MESSAGES, this just makes it identifiable.
- services/server-manager.ts: disconnect() no longer awaits logout() —
  it fires it and calls apiClient.abortInFlight() so a hung logout can't
  block the disconnect button.
- context/TorrentContext.tsx, context/TransferContext.tsx: set retry: 0
  on the two polling queries, since the client already retries/backs off
  and a 2-3s poll gains nothing from TanStack retrying on top.

Fixes #254
Tapping a server on the not-connected screen flipped serverIsLoading
true the instant the connect mutation went pending, which unmounted
QuickConnectPanel in favor of the skeleton loader before falling back
to the panel once connect settled — a panel/skeleton/panel flash
(instant in airplane mode, ~10s on a real network per the issue).

Keep the panel mounted while a user-initiated connect (connectingId
set by this screen's own handleQuickConnect) is in flight; an
automatic background reconnect leaves connectingId null so it still
falls through to the skeleton as before (#245 behavior preserved).

Fixes #252
…first

Sort RSS feed articles newest-first
…and-cancellation

Fix requests hanging ~2 minutes and disconnect not working on a dead server
…el-flicker

Fix torrents screen flashing when tapping a disconnected server (#252)
Lets you switch servers from the torrents screen instead of going
Settings → Disconnect → Torrents → Connect. A compact server badge in
the header opens ServerSwitcherModal, which lists saved servers, marks
the connected one, and switches directly to whichever other one is
tapped via the existing connectToServer.
A rejected self-signed certificate was indistinguishable from a dead
server, so nobody could tell what was wrong. This does not fix the
reporter's underlying connection failure (still awaiting repro details
on the issue) — it ships the diagnosis/visibility half:

- utils/error.ts: isTlsRejection(error) recognizes iOS rejecting a
  server's TLS certificate from the free-text description RN's XHR
  bridge exposes on error.request.response, matched across all six
  locales since that text is localized to the device language.
- services/api/client.ts: the network-error branch throws a distinct
  "Certificate rejected..." message (with a clogWarn('TLS', ...)) when
  isTlsRejection matches, instead of the generic connection-timeout
  message, without touching the existing substring-matched strings.
- modules/insecure-cert-allowlist: exports
  isInsecureCertAllowlistAvailable() so a server wanting the allowlist
  flag on a binary that predates the native module (an OTA JS update
  shipped without it) is surfaced instead of silently no-op-ing —
  services/server-manager.ts warns via clogWarn('CERT', ...), and the
  server add/edit screens show a hint under the toggle.
- components/SuperDebugPanel.tsx: both REACH probes switch from
  fetch() to a raw XMLHttpRequest so the certificate-specific guidance
  (previously unreachable, since whatwg-fetch collapses every network
  failure into a bare "Network request failed") can actually fire.
- AGENTS.md: File Index updates plus a new §10 Gotcha entry about an
  OTA-shipped feature silently lacking its native half.
…sibility

Improve TLS-rejection diagnosis and visibility
Settings → Advanced's "View Connectivity Logs" row actually opened
qBittorrent's own server-side log viewer, which requires a live
connection and shows nothing on the failure the user is trying to
diagnose. Repurpose LogViewer to display services/connectivity-log.ts
(the app's own in-memory HTTP/auth/connection trail, already captured
but never surfaced) instead, add a Copy action, and rename the old row
to "Server Logs" since it's a legitimate separate feature, just
mislabeled. Delete services/log-storage.ts, which nothing populated.
Wire the app's connectivity log into a real Settings screen
Torrents screen (select mode):
- Bulk actions bar no longer covers the last card (measured height fed
  back as list bottom padding instead of a fixed value)
- Fixed the large gap above the first card after scrolling up, caused
  by a hardcoded header paddingTop sized for the full normal-mode
  header rather than select mode's shorter one (now measured)
- Header (Select All / Close) no longer scrolls away or gets scrolled
  over by cards during selection — it's pinned as a normal in-flow
  sibling instead of an absolute overlay while selectMode is active,
  and FlatList now declares flex: 1 explicitly rather than relying on
  being the sole flex participant

Connectivity log viewer:
- Fixed the header overflowing/clipping the Clear button on narrower
  screens by making the Copy button icon-only (matching the existing
  debug-info copy button convention) and letting the title truncate

Build:
- Xcode 27 / iOS 27 SDK hard-fails app launch unless the generated
  native project adopts the UIScene life cycle. Added expo-build-properties
  with ios.enableSceneSupport, and updated withNativeTorrentFileCopy's
  AppDelegate.swift template match for the resulting shape change (the
  cold-launch .torrent-copy path is weaker under scene lifecycle -
  documented in the plugin, needs on-device verification)
- Added npm run simulator, targeting a specific iOS 26.5 sim device

Changelog: added the 3.8.45 entry.
…d-xcode27

Fix select-mode header overlap/gap and Xcode 27 build crash
@taylorcox75
taylorcox75 merged commit 62539aa into main Sep 21, 2026
3 of 4 checks passed
@taylorcox75
taylorcox75 deleted the release/v3.8.45 branch September 21, 2026 02:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Seeding ETA should be visible

2 participants