SwiftMiner 1.39
A substantial reliability, performance, and security release. SwiftMiner starts faster, is much harder to shake off restricted esports campaigns, makes degraded Twitch services visible, keeps sensitive secrets in the macOS Keychain, and presents mining state more clearly throughout the app.
🏆 Esports and restricted campaigns
Short, channel-restricted drop windows are detected sooner and survive incomplete Twitch data.
- Listens for Twitch stream-up events on the approved channels it is waiting for, starting an esports broadcast in seconds instead of waiting for the next minute-by-minute check.
- Remembers approved-channel lists across refreshes and launches when Twitch omits them, preserving their original campaign expiry and bounding the on-disk history to 600 campaigns.
- Uses recent stream-up events and carefully limited direct attempts when Twitch’s live-status query is incompatible, without repeatedly trying channels confirmed offline.
- Waits for subscription acknowledgements, preserves stream-event ordering, cleans up old waits safely, and rotates overflow channels so the same campaigns are not permanently excluded from push monitoring.
- Surfaces repeated channel-check failures in Needs Attention and notifications, ignores routine cancellations, clears recovered incidents promptly, and points to Override Stream or Twitch as immediate fallbacks.
- Keeps restricted campaigns on a fresh twenty-minute details window and merges newer Twitch status and dates into cached data, so an extended event is not hidden by an old end time.
⚡ Clearer mining status and Drops controls
The bolt means mining everywhere, and controls show what they actually selected.
- Uses the mining bolt consistently across the menu bar, Overview, cards, game summaries, Drops filters, and icon legend. Checkmark, warning, and clock badges distinguish healthy, attention, and waiting states; stopped mining no longer looks like a fault.
- Renames Fleet Health to Squad Health and keeps every Overview status symbol at the same clear visual size.
- Makes the All control in Drops select every campaign filter and clear every filter on the next click instead of repeatedly applying an invisible show-everything state.
🚀 Faster startup and less repeated work
Campaign refreshes, cache reads, and Overview presentation stop repeating work they already completed.
- Remembers ordinary campaign details for four hours rather than twenty minutes, avoiding hundreds of repeat detail requests after a restart while retaining the shorter window for restricted campaigns and account-link state.
- Keeps decoded campaign data in memory, coalesces concurrent refreshes, collects account snapshots concurrently, and uses indexed campaign, game, artwork, and feed lookups instead of repeated full scans.
- Builds shared and per-account views from one snapshot, skips cache rewrites when only timestamps changed, and writes dashboard identities only when their data actually changes.
- Logs token loading, real-time connection setup, each miner’s startup, the handoff to its mining loop, and total squad startup time so a slow launch can be diagnosed precisely.
🖼 Bounded caches and a calmer interface
Artwork, profile pictures, and volatile status updates stay within deliberate budgets.
- Bounds decoded artwork, profile pictures, and sampled tints in memory while sharing image downloads and processing work.
- Caps every image-cache folder on disk by both size and file count, evicting the oldest files once either budget is exceeded.
- Coalesces volatile telemetry and unchanged Dock badge refreshes, reduces decorative animation work, and stops animations when SwiftMiner is inactive or Reduce Motion is enabled without delaying meaningful state or progress changes.
🔒 Security and long-running reliability
Credentials are harder to lose or expose, and background work now ends with the account that owns it.
- Moves the SwiftBot signing secret, local API key, and dashboard OAuth client secrets from preferences into the macOS Keychain, migrating existing values after a successful Keychain write.
- Keeps an unreadable legacy account backup retryable instead of recording an empty migration as complete and later offering to delete the only remaining credential copy.
- Requires HTTPS for public web-dashboard sign-in while preserving plain HTTP for loopback and local-network access, protecting OAuth callbacks and week-long session cookies from travelling over the public internet unencrypted.
- Stops an account’s repeating background drop-state refresh before removing that account, preventing continued Twitch polling and retained services after deletion.
- Reports sustained outages of Twitch’s legacy real-time feed while periodic reconciliation keeps mining and claiming functional, and orders disconnect/reconnect signals so quick recoveries are reported correctly.
- Reads event-outbox timestamps with a fixed calendar, preserving webhook retry timing in regions using a non-Gregorian system calendar.
🔐 Local dashboard and diagnostics
Requests are bounded, failures are observable, and exported diagnostics explain more of what happened.
- Bounds local dashboard request headers and bodies, times out incomplete requests, and rejects malformed, duplicated, or unsupported body framing before authentication and routing.
- Adds event-outbox depth, oldest-event age, webhook timings, and real-time transport health to diagnostics so degraded delivery is easier to explain.
- Reorganises the large Overview implementation, expands regression coverage across the new reliability and security work, fixes SQLite test teardown warnings, and hardens release automation against generated-project and release-note drift.