Port af391cbb (require node type for getting an available name);
c6b45188 (file-backed transfer buffers) is C# memory plumbing and a
no-op here.
- get_available_name takes an AvailableNameTarget. A file keeps its
extension last (name (1).ext); a folder appends to the whole name
(name (1)), so a folder named v1.2 no longer resolves to v1 (1).2.
- Split alternate_names into alternate_file_names and
alternate_folder_names, mirroring AlternateFileNameGenerator.
Breaking: get_available_name gains a parameter.
Port upstream 0aabea59: report_recently_accessed on ProtonDriveClient and
ProtonPhotosClient, batches of 50. Also read the ThirdParty/Sdk flags from
f257c20e on link and revision DTOs. Pin bumped to df3a717b.
Port 6cbf2f44 (stop retrying permanent API errors on block transfers)
and 20822176 (small file upload interop); 6ce47922 is a no-op here.
- Add ProtonApiError::is_retriable / ProtonError::is_retriable mirroring
C# RetryPolicy.IsRetriable: 4xx is permanent except 404, 408 and 429,
with envelope codes able to override the HTTP status.
- Gate upload_one_block's retry loop on it so a permanent rejection of a
revision fails immediately instead of being replayed three times.
- Extract BlockTargets from RevisionReader so the whole-file download
path, the public link download and the reader all re-mint expired
block URLs through one generation-deduplicated refresh.
- Fall back from the small upload to the block path on AlreadyExists
only; the small upload is not idempotent, so everything else keeps
propagating.
- Bound a server-supplied Retry-After by RetryPolicy::max_retry_after
(default 120 s) so a long rate-limit answer cannot look like a hang.
- Moves go through `move-multiple` in batches of 150, with an optional
target name per node (`move_nodes_streaming` / `NodeMoveItem`), a single
`InvalidRequirements` retry against the server's current name hash, and
passphrase signing for anonymously created nodes. A batch rejected as a
whole keeps its API error code on every node.
- Share memberships carry invite time and inviter email, and the inviter's
`drive.share-member.inviter` signature is verified as non-fatal metadata
(`verify_detached_with_context`).
- `Node` gains `direct_role` and `share_id`.
- Trashed detection reads `TrashTime` as well as the legacy `Trashed`.
Breaking: new public struct fields on `Node` and `ShareMembership`.
Ports upstream C# e0e198e2 (SavePhotosToTimelineAsync, itself the JS
saveToTimeline). Photos already on our photos volume are moved into the
timeline root via PUT photos/volumes/{vid}/links/transfer-multiple,
batched so no request carries more than ten links and a photo is never
split from its related photos; photos on another volume — from an album
shared with us — are copied via POST volumes/{vid}/links/{lid}/copy, one
request each. That closes the cross-volume copy hole (TS copyPhoto).
The re-encryption is what add_photos_to_album already did, so it moves
into a shared photo_target_payload: name re-encrypted to the target key
and signed by the photos membership address, name/content hashes under
the target hash key, node passphrase rewrapped so the original
NodePassphraseSignature survives.
A photo the server reports an incomplete group for is re-queued once
with the related photos it named; only its second answer becomes an
outcome, so outcomes arrive in completion order, not input order.
Also adds ProtonPhotosClient::enumerate_events (c8d03244's only
non-interop hunk) and bumps the upstream pin to c8d03244. Upstream
29e58378 (upload telemetry) and 0537d906 (NodeProvider refactor) are
deliberately not ported — see UPSTREAM_SYNC.md.