v9.0.0: promote the merged chunked-upload stack to master - #40
Merged
Conversation
This PR adds the TypeScript surface for chunked uploads. It contains no engine code. The new API is `startUpload` with `type: 'chunked'`. The options are: - `id` — the upload id. The consumer supplies it. It is required. - `path` — the file to send. - `parts` — a list of parts. Each part has a URL, headers, and a byte range. - `accept` — rules that say which HTTP responses are a success. Each rule is a status code and optional body text. These rules replace `acceptStatus` in all upload types, so the library has one shape. - `expiresAt` — the time when the library must stop the upload. It is required. The library validates the parts. The first part must start at byte 0. Each next part must start where the last part ends. The PR adds two functions. `chunkPlan` is a pure function: give it a file size, and it returns the byte ranges for the parts. A property test sweeps every size at a reduced scale. `removeUpload` releases a stopped upload's file and records. Codegen cannot model the raw/chunked union. Thus the native side gets a separate `startChunkedUpload` entry point. The public `startUpload` stays one function and routes on `options.type`. The native functions are stubs on both platforms. They return `E_NOT_IMPLEMENTED`. Thus this PR compiles and passes CI alone. The engine PRs above this one replace the stubs. The PR also turns on `noUncheckedIndexedAccess`. Diana type-checks the shipped `.ts` files with that setting, so the library must catch those breaks first. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This PR adds the Android engine for chunked uploads. At start, the library moves the file into its own directory. The library then owns the file. The library writes a durable manifest to disk. The manifest holds the parts, the status of each part, and the options. The engine sends the parts with WorkManager. A RandomAccessFile-backed body streams each part directly from the file. There are no chunk copy files, and disk usage does not double. A maximum of 3 parts transmit at one time (the window). The engine applies the accept rules and the expiry time. The engine writes each event to a journal before it emits the event. The library deletes the file only when the consumer acknowledges the `completed` event. `startUpload` with the same id resumes the upload. The engine skips the parts that the server accepted. The same id with different parts recreates the upload. The engine permits a recreate only when the upload is not running, and the new parts must tile the file exactly. Review fixes in this slice: - A job that v8 enqueued replays safely. The engine normalizes the legacy `acceptStatus` field. A test uses the literal v8 JSON shape. - The reconcile step is atomic under the store lock. - The work policy is `APPEND_OR_REPLACE`, and a worker returns success after it journals a terminal error. Thus a failing chain cannot silently drop a resume. - An ack race resolves cleanly. A missing manifest is a no-op. - A range-tiling guard protects the recreate rule. 84 JVM tests. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This PR adds the iOS engine for chunked uploads. The JS-visible behavior is the same as Android. The transport is a background `URLSession`. A background session can send only files. Thus the engine writes one temporary file for each part in flight, and deletes it when the part completes. The transient disk usage stays near 60 MB. There is no second full copy of the source file. The engine keeps a sliding window of 3 part tasks enqueued in the session. The session daemon continues the tasks when the app is suspended or terminated. When iOS relaunches the app, the engine reconciles the manifest with the daemon's task list, and then fills the window again. The background completion-handler flow is kept. Review fixes in this slice: - Same-id `startUpload` races are serialized natively. - An incarnation token stops the late callbacks of a removed upload. Without the token, those callbacks could corrupt a recreated upload with the same id. - The recreate rule and the stale temporary-file edges are covered. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This PR sets the library-wide transmission cap to 4 on both platforms. Before, both platforms sent one request at a time per host (an Android semaphore of 1; iOS `httpMaximumConnectionsPerHost` of 1). On Android, the cap is hard: each request must pass the semaphore. On iOS, the cap is a per-session, connection-level backstop. The window of 3 already bounds the parts of one chunked upload. The PR also: - Adds a chunked demo and a `removeUpload` button to the example app. - Rewrites the README and the CHANGELOG for v9. - Sets the version to 9.0.0. Full suite at the tip: typecheck and lint clean, jest 37, gradle 84, xcodebuild BUILD SUCCEEDED. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
arnonate
approved these changes
Sep 3, 2026
danseethaler
approved these changes
Sep 3, 2026
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.
This PR moves the merged chunked-upload work onto master. It replaces #39, which conflicted.
The stacked PRs #32–#35 were reviewed and merged, but their stack was rooted on
dylan/v9-3-configure, so their four squash commits landed on that branch and not on master. This branch carries those same four commits, cherry-picked onto the current master. The tree at the tip is byte-identical to the merged stack. There are no new changes, and there are no conflicts: the branch is a fast-forward of master.Prefer "Rebase and merge", so the four commits keep their identities on master. After the merge, master is v9.0.0 and gets the
v9.0.0tag.🤖 Generated with Claude Code