Skip to main content

Changelog

Every improvement, automatically tracked from our commit history.

Subscribe via Atom feed
← Prev Page 79 of 266 Next →
February 25, 2026
patch Desktop Shell

Fix crash on photo drop from cloud-mounted drives

Desktop 1.66.3 → 1.66.4 | 6dc9c6a0
Details

LocalStorageProvider.StoreFileAsync was synchronous despite the async

signature — it called File.OpenRead + SHA256.HashData on the UI thread.

When the source file is on a cloud mount (Google Drive, iCloud), the

read can stall or timeout, throwing an IOException that propagated up

through the Avalonia dispatcher as an unhandled exception, killing the app.

Fixed by making StoreFileAsync truly async: file hashing now uses an

async FileStream with SHA256.ComputeHashAsync on a background thread,

with a 30-second timeout via linked CancellationTokenSource.

Desktop v1.66.4

patch Journal

Journal v1.8.1: photo sections with layout options

Journal 1.8.0 → 1.8.1 | 20f3d7e3
Details

Add photo section editor with file picker, layout selector (Full Width /

2 Column / 3 Column), and photo preview grid. Photos stored via

IStorageProvider (content-addressable dedup). PhotoSectionView displays

photos using AsyncImage with UniformGrid layout based on PhotoLayout.

Wire IStorageProvider resolution in JournalPlugin via capability broker,

passed to ViewModel for storage access. Add photo section to both Feed

and Focused view rendering.

patch CoreDesktop Shell

Enforce proper rate limit backoff across cloud sync stack

Core 1.15.1 → 1.15.2 | Desktop 1.66.2 → 1.66.3 | 8baf1e94
Details

The cloud sync was hitting 429 rate limits and not properly backing off,

causing repeated error spam. The C# refresh timer kept calling GetQuota()

every 15 seconds even during rate limits, generating cascading 429 errors.

Rust API client (api_client.rs):

  • Added sliding window request counter that enforces 75% of the server's

advertised rate limit (450 req/60s instead of 600). Proactively throttles

before hitting the server limit.

  • Changed 429 backoff to use 2x the server's Retry-After header with a

60-second floor. Previously used 1x which allowed immediate re-triggering.

  • Counter limits are updated from server config on sync engine startup.

Rust FFI layer:

  • Added PrivStackError::RateLimited (= 36) to distinguish rate limits from

generic CloudSyncError. Previously all rate limit errors mapped to

CloudSyncError and C# couldn't tell them apart.

  • Rate limit errors now log as WARN instead of ERROR (expected transient).
  • CloudSyncStatus now includes is_rate_limited and rate_limit_remaining_secs

fields, populated from the API client's gate state.

C# desktop:

  • CloudSyncSettingsViewModel.RefreshStatusAsync() checks is_rate_limited

from status and skips all API calls (quota, devices, tokens) when true.

This eliminates the cascading 429 errors from the refresh timer.

  • Catches PrivStackError.RateLimited specifically instead of falling through

to the generic exception handler.

  • Status refresh timer slows from 15s to 30s during rate limit pause (still

updates the remaining-seconds display but doesn't hit the API).

  • Added IsRateLimited and RateLimitDisplay observable properties for UI.

Rust v1.15.2, Desktop v1.66.3

patch IO

Add .whitesource configuration file

patch Desktop Shell

Add reattach button and padding to detached AI tray window

Desktop 1.66.1 → 1.66.2 | 064ad877
Details
  • Add IsDetached property and RequestReattach command to AiSuggestionTrayViewModel
  • Show reattach button (dock icon) in tab strip when tray is detached
  • Add content margin (8px sides/bottom) to AiTrayWindow for breathing room
  • Wire ReattachRequested event in MainWindow detach/reattach lifecycle
  • Version bump 1.66.1 → 1.66.2
← Prev Page 79 of 266 Next →

Get notified about new releases