feat(examples): showcase multipart, TUS resumable, and background downloads in Storage examples#989
Open
grdsdev wants to merge 14 commits into
Open
Conversation
27a5031 to
a4ccb0b
Compare
Contributor
Author
Code reviewFound 2 issues:
supabase-swift/Examples/Examples/Storage/FileUploadView.swift Lines 1 to 9 in a4ccb0b
supabase-swift/Examples/Examples/Storage/FileDownloadView.swift Lines 62 to 65 in a4ccb0b supabase-swift/Examples/Examples/Storage/FileDownloadView.swift Lines 228 to 236 in a4ccb0b 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
Adds `DownloadEngine` — an actor-based state machine that manages URLSessionDownloadTask lifecycle with pause/resume/cancel support. When the server returns `Accept-Ranges: bytes`, pausing captures resume data via `cancel(byProducingResumeData:)` so the next `resume()` call restarts from the last received byte. If the server does not support range requests the download restarts from byte 0. Changes: - New `DownloadEngine` actor with states: idle, starting, downloading, paused, completed, failed, cancelled - `DownloadSessionDelegate` refactored to callback-based routing (`DownloadTaskCallbacks`) instead of holding continuations directly; temp-file move is now done synchronously inside the delegate method so URLSession cannot reclaim the file before the move completes - `StorageFileAPI.download()` now wires through `DownloadEngine.makeTask` and documents pause/resume behavior - `StorageTransferTask.pause()` / `resume()` docs updated to cover downloads alongside TUS uploads - New `DownloadEngineTests` (Darwin-only) covering basic download, pause-then-resume, cancel-yields-cancelled-error, and network-error Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lude downloads Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers happy path, pause/resume cycles, cancel semantics, error handling, and concurrent download scenarios using a live Supabase instance via the existing withUploadedFile helper pattern. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1. Task-identity race in DownloadEngine: after pause() cancels the active URLSessionDownloadTask (ID=X) and resume() starts a new one (ID=Y), the stale URLError.cancelled from X could arrive while state is .downloading(Y) and incorrectly call cancel(). Fix: capture the task identifier at callback-registration time and guard every engine callback against a mismatch with the current active task. 2. HTTP error responses delivered as completed downloads: URLSession calls didFinishDownloadingTo for 4xx/5xx responses too, saving the error JSON as the "downloaded" file. Fix: check the HTTP status code in the delegate and parse the Supabase error envelope into a StorageError, delivering .failed instead of .success. Also adds StorageError.from(httpResponse:data:) as an internal factory shared by the delegate, and removes LockIsolated (unavailable in IntegrationTests target) from the multi-pause-cycle test in favour of a local actor. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nloads in Storage examples - Add `backgroundDownloadSessionIdentifier` to `StorageOptions` and wire it through `SupabaseClient` → `StorageClientConfiguration` so apps can opt into background download sessions via `SupabaseClientOptions`. - Configure the Examples app with a background-download session identifier and forward `application(_:handleEventsForBackgroundURLSession:completionHandler:)` in `AppDelegate` to `supabase.storage.handleBackgroundEvents(forSessionIdentifier:completionHandler:)`. - Rewrite `FileUploadView`: segmented picker for Smart / Multipart / Resumable (TUS) engines; real progress driven by `for await event in task.events`; Pause / Resume / Cancel buttons active for Resumable uploads via a retained `StorageUploadTask`. - Rewrite `FileDownloadView`: segmented picker for To Memory (`downloadData`) vs To Disk (`download`); real progress from event stream; disk mode notes background-session support. - Update `StorageExamplesView` navigation labels to reflect the new capabilities. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…on row The buttons were nested inside the same VStack as the ProgressView, making them a single List row whose height was driven by the ProgressView label. The buttons were clipped and never visible. Moving the HStack into a sibling view at the Section content level gives it its own List row and guaranteed vertical space, matching the intended UI. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…view After a To Disk download completed, the view read the entire file with Data(contentsOf:) regardless of size. For a 5 GB file this caused a matching 5 GB memory spike — exactly what the disk download mode is designed to avoid. Fix: only attempt an in-memory preview when the file is ≤ 10 MB. Larger files show the file URL and size instead, with a note explaining why the preview was skipped. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Preview required reading the downloaded bytes into memory, which defeats the purpose of demonstrating the download API. Both modes now show only metadata (size, path, mode) after a successful download. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add missing 'Created by' line to FileDownloadView and FileUploadView headers per AGENTS.md convention - Introduce isLoadingFiles flag in FileDownloadView so that listing bucket files does not collide with the isDownloading transfer state; prevents the progress bar from flashing during listing and avoids prematurely clearing download progress when loadFiles() completes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add NSAllowsLocalNetworking to bypass ATS for LAN IP addresses, enabling the app to connect to a local Supabase instance via the Mac's IP address when testing on a physical device. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
39ad389 to
aa78086
Compare
Both download modes (To Memory and To Disk) now expose Pause/Resume/Cancel controls via a type-erased DownloadController that wraps StorageTransferTask. Uses the new pause/resume support added in feat/storage-resumable-downloads. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
backgroundDownloadSessionIdentifiertoStorageOptionsand threads it throughSupabaseClient→StorageClientConfiguration, so apps usingSupabaseClientcan opt into background download sessions without needing a standaloneStorageClient.application(_:handleEventsForBackgroundURLSession:completionHandler:)inAppDelegatetosupabase.storage.handleBackgroundEvents(forSessionIdentifier:completionHandler:).FileUploadView— showcases all three upload engines with real progress from theAsyncStream<TransferEvent>API:StorageUploadTaskFileDownloadView— showcases both download paths with real progress:downloadData) — loads bytes in-process, image/text previewdownload) — saves to a temp file, background-session capable, noted in the UIStorageExamplesViewnavigation rows to reflect the new capabilities.Test plan
make PLATFORM=IOS XCODEBUILD_ARGUMENT=build xcodebuild).🤖 Generated with Claude Code