Run `cargo update` to bump transitive dependencies, fixing 10 of 11
alerts (h2, ring, idna, mio, tokio, bytes, time, quinn-proto,
rustls-webpki, unsafe-libyaml).
Replace deprecated `tempdir` dev-dependency with `tempfile` to
eliminate the `remove_dir_all` vulnerability (the last alert).
* refactor: replace reqwest with ureq to reduce binary size
reqwest's blocking API is built on top of its async implementation,
pulling in tokio, hyper, futures, and ~84 other transitive dependencies
even though we only make simple synchronous HTTP calls.
ureq is a synchronous-only HTTP client that eliminates the async
runtime entirely. This reduces transitive dependencies from 227 to 143
and the linked dylib from 4.5 MB to 3.7 MB (-18%). The .a archive
drops from 28 MB to 26 MB, but real savings will be larger once
linked into libflutter with dead code stripping.
The network API surface is unchanged — three functions (patch check,
file download, event reporting) using POST/GET with JSON.
* chore: add ureq to spell check dictionary
* refactor: use into_body() instead of body_mut() where response is consumed
* fix: simplify network error matching to avoid fragile string checks
Consolidate HostNotFound, ConnectionFailed, and all Io errors into
a single network-error arm instead of pattern-matching on error
message strings that could change across OS versions or locales.
* chore: add TODO for misleading network error message
* test: test api calls
* chore: add docs
* chore: fix cspell
* fix: use no-op network hooks in multi_engine tests
Set no-op network hooks after init_for_testing so the fire-and-forget
thread spawned by report_launch_success completes instantly without
network I/O, preventing leaked threads from interfering with subsequent
serial tests that use mock servers.
Previously, checkForUpdate returned upToDate after a rollback because
the condition `next != null && current?.number != next.number` treated
a null next patch as "up to date". After a rollback, the Rust updater
correctly uninstalls the patch (next becomes null), but the app is still
running the rolled-back patch (current is non-null). The simplified
condition `current?.number != next?.number` correctly detects this
mismatch and returns restartRequired.
Fixes https://github.com/shorebirdtech/shorebird/issues/3206
* fix: improve inflate error handling and validate compressed patches
Addresses #2989: "pipe reader has been dropped" / "failed to fill whole
buffer" errors during patch inflation were masking the real root cause.
Three changes:
1. Join the decompression thread and propagate its error as the primary
failure, rather than fire-and-forget logging. The patching thread's
broken-pipe error is a side-effect, not the cause. Also drop the pipe
reader before joining to avoid deadlock when patching fails.
2. Validate the downloaded compressed patch (non-empty, valid zstd magic
bytes) before attempting decompression, so corrupt/truncated downloads
produce a clear error instead of cryptic pipe errors.
3. Log the download size in download_to_path to help diagnose truncated
downloads in the field.
* docs: expand comment on drop(fresh_r) to clarify deadlock risk
* feat: log app_id, patch number, and version before download
* test: add inflate tests for corrupt data and invalid magic
* test: cover decompression-error-as-primary-cause path in inflate
Uses a valid zstd frame followed by a corrupt second frame so that
bipatch::Reader::new succeeds but decompression fails midway, verifying
that the decompression error is reported as the primary cause.
Users sometimes gate app startup on checkForUpdate() or update()
completing (e.g. awaiting in initState before showing content), which
can cause the app to appear stuck on the splash screen when the
network is slow.
Add warning doc comments to both methods recommending the .then()
pattern for startup code, and update README examples to use .then().
Fixes https://github.com/shorebirdtech/shorebird/issues/3179
* feat: add enhanced error messages for file operations
Add a file_errors module that provides context-aware error messages
for file operations. When file operations fail, users now see:
- The specific operation that failed (create, read, write, rename, etc.)
- The full path involved
- Helpful hints about possible causes based on error type
- Android-specific hints for permission errors (SELinux, Work Profile,
MDM/Knox policies, app cloning features)
This helps diagnose issues like "Permission denied (os error 13)" by
indicating which operation failed and suggesting possible causes.
The scenario is:
1. User is running patch 2 (booted successfully, so last_booted_patch = 2)
2. While the app is still running, they call the check-for-update API
3. Patch 3 is downloaded and installed (next_boot_patch = 3)
4. Before the app restarts, they check again and patch 4 is available
5. The buggy code is supposed to delete patch 3 (never booted), but instead deletes patch 2 (the last known-good patch)
6. Patch 4 is set as next_boot_patch
If patch 4 boots fine, nobody notices. But if patch 4 fails to boot and the system tries to roll back to patch 2, those artifacts are gone.
* feat: move patch verification from boot time to install time
* feat: make it switchable
* chore: update comments
* fix: test invalid yaml
* chore: update readme
* feat: add more comments to readme
* doc: more readme updates
* chore: rename to patch_verification
* fix: make tests pass on Windows
* Run ci on all supported building OSes
* Add os name to CI step
* Build rust crates on all oses
* tweak
* Only run rust on multiple oses for now
* chore: add cspell checking and make pass
* chore(shorebird_code_push): minor improvements to example (#242)
* chore(shorebird_code_push): v2.0.2 (#243)
* chore: fix cspell
---------
Co-authored-by: Felix Angelov <felix@shorebird.dev>