Skip to main content

Crate coven

Crate coven 

Source
Expand description

End-to-end encrypted, multi-writer SQLite sync over host-selected storage.

The host owns its SQLite schema and domain. Coven owns the connection, captures host writes, stores protocol state, and synchronizes rows and blobs. Hosts use the crate-root API; implementation modules remain private.

let _ = coven::store_sync::StoreSync::connect;

Re-exports§

pub use coven_database::rusqlite;

Structs§

ActivatedContinuation
Exact durable state required to continue an activated Store device.
AffectedRow
One table/primary-key identity affected by the shared part of a write.
AuthorizeRequest
An authorization request the host drives itself: the URL to open plus the PKCE verifier and state value coven checks during exchange. For hosts that capture the redirect outside coven’s localhost callback server — e.g. a mobile OS auth session (ASWebAuthenticationSession / Custom Tabs) redirecting to a custom URI scheme, where binding a localhost port and open::that don’t apply.
BlobBody
A blob as a sized stream of already-final bytes: sealed chunks for an encrypted home, plaintext for a browsable one. Encryption-agnostic and concrete (no dyn Stream). next_part hands the bytes to a streaming upload in bounded windows so a large blob is never held whole in memory; the only collect is the single-request path for blobs at or below a provider’s multipart threshold.
BlobDecl
Where a blob-bearing table’s blob columns live, declared by the host so coven can derive every blob a row references without a runtime callback. Resolved against the live schema into the database’s BlobDecls each cycle.
BlobFileFailure
A local blob file that failed to unwind after a host write failed. Names the blob so a host learns which files are left behind, not just that some were.
BlobFileFailures
Every blob that failed to unwind, in the order they were attempted.
BlobRef
A blob a row references: its cloud identity, encryption scope, and the two declared properties (provenance + fill). coven derives it from the row’s declared columns (crate::synced_schema::BlobDecl) via the database’s BlobDecls. Where its bytes live depends on its locality and provenance: a user-provided Local blob is the user’s file at its path; a host-provided Local blob is in coven’s local store (storage/local/<namespace>/<id>); a Remote blob’s device-local copy is a cache copy (storage/pinned/<namespace>/<locator-hash> / storage/cache/<namespace>/<locator-hash>, built from the validated namespace + exact locator hash — see blob::cache).
BlobStream
One opened blob, ready to serve ranges. Held by a host that is streaming or seeking a blob (playback probing a codec header, then a tail, then decoding forward) rather than loading it whole.
Circle
One Circle as Circles::list reports it: its id, display name, the local identity’s role when it holds active access, and the derived state. The name is absent for a Circle with no resolved metadata (inactive, conflicted, or deleted); the role is present only when the local identity holds active roster membership.
CircleCloseParticipant
One participant in an in-flight epoch close and its slot settlement.
CircleCloseStatus
The read-only status of a Circle’s in-flight epoch close: which participant slots hold responses, exclusions, or nothing.
CircleControlCoord
Exact coordinate of one signed circle control entry.
CircleEpochCloseId
The stable identity of one Circle epoch close, derived from the durable operation that opened it. It names the close a Circles::close_status inspects and the reserved response and outcome slots that settle it; a close’s identity is fixed for its lifetime and survives cancellation and retry.
CircleId
A self-certifying 128-bit circle identity encoded as canonical lowercase base32.
CircleMemberInfo
CircleOperationId
CircleOperationInfo
Circles
The coven.circles() namespace. Borrowed from its Store Circle owner.
CloudHomeConfig
The cloud home: which provider backs sync and its per-provider settings. One cohesive unit — connecting picks a provider and fills its fields; disconnecting resets the whole thing to default.
CloudKitAcceptedShareRecord
CloudKitAtomicCreateBatch
CloudKitProviderIdentity
CloudKitRecordCreate
CloudKitRecordVersion
CloudKitShare
CloudObjectVersion
Opaque provider revision for an exact mutable object.
CloudOutboxLiveQuery
A committed view of coven’s durable cloud work.
CloudOutboxSnapshot
CloudVersionedObject
CommitFrontier
Exact materialized cut across author streams.
Config
Sync + storage configuration for one store.
ConnectedCloudHome
A cloud-home setup that Coven has connected and committed.
Coven
CovenBuilder
CovenConfig
CovenHandle
The cipher a store’s app-data sealing runs under, resolved from custody.
CovenReadHandle
A read-only handle over one coven store, for a same-store secondary reader.
CrossPrincipalProbeReceipt
DeviceActivity
Activity summary for a single remote device.
DeviceJoinAbandonment
DeviceJoinActivation
DeviceJoinAttemptId
DeviceJoinJournalDatabase
Durable role journal. Each row stores a closed progress value; SQLite’s compare-and-swap update rejects stale or skipped transitions.
DeviceJoinJournalRecord
DeviceJoinOfferBundle
The out-of-band kickoff: the offer plus everything the transport needs to carry the rest of the exchange. The host encodes this however it delivers a join code; coven does not choose that encoding.
DeviceJoinReadiness
DeviceJoinTransportParams
The slots and seal key one attempt’s artifacts travel through.
DeviceJoinTransportTiming
How often to look for a counterpart’s artifact, and how long to keep looking before giving up on it.
DevicePairingHost
A listener behind the one QR code shown by the existing device. It accepts one exact signed identity, survives client reconnects, and returns the same sealed invitation on every retry.
DevicePairingOffer
The one code an existing device displays. Possession of this code grants access only to this pairing session; Store credentials remain sealed to the joining identity the existing device approves.
DevicePairingRequest
The identity submitted after scanning an owner’s offer. The whole signed request is sealed to that offer’s ephemeral key before it crosses the LAN.
EagerCacheFillProgress
EncryptionService
Manages encryption keys and provides XChaCha20-Poly1305 encryption/decryption
ExactObjectRef
Exact stored representation of one immutable object.
ExactSlotProbeReceipt
ExactUpload
One immutable exact object together with a replayable source for its final stored bytes. Provider adapters derive their own native checksums from this source and can reopen it after an ambiguous create response.
ExternalBlob
An external user-owned file a blob id resolves to, read back from a local_blob_refs row. The blob’s plaintext lives at path (an absolute file Coven references but does not own); size is its registered plaintext length, combined with the row’s signed content hash to validate the exact file.
FixedClock
Every now() returns the same instant.
HeldStorePosition
InMemoryCloudHome
In-memory CloudHome backed by a HashMap. Clone shares one backing store, so clones act as separate devices reading and writing the same cloud bucket, and a test can keep its own handle for direct at-rest assertions while each device owns an exact cloud-home clone.
JoinedStore
KeyFingerprint
Stable wire identity of one 32-byte encryption key: its full SHA-256 digest, serialized as exactly 64 lowercase hex digits.
LiveQuery
A query over the store’s reader that runs initially and whenever a committed row change can affect its result.
LiveQueryClosed
LiveQueryRequests
Changes the absolute request evaluated by a reconfigurable live query.
LiveQueryRevision
Identifies an absolute request accepted by a reconfigurable live query.
MakeRemoteRoot
MasterKeyring
A store’s master key material: every key it holds. This is the value custody implementations store, unlock, and re-protect — never a cipher. coven builds the EncryptionService cipher from it internally; custody never touches cipher machinery.
MemberInfo
MembershipConflictChoice
Migration
One ordered step in the host’s synced-schema ladder.
MigrationContext
Host SQL inside one schema-migration transaction.
OAuthClientCreds
OAuth client credentials for one provider — the consuming app’s registered OAuth application. coven ships no app credentials of its own.
OAuthClients
The consuming app’s OAuth clients. Each Coven builder retains its own value, so unrelated apps in one process never share credentials.
OAuthTokens
Tokens returned from an OAuth authorization or refresh.
ObjectHash
ObjectSlot
Exact logical and physical location persisted before an immutable write.
OutboxFailure
OwnerRecoveryAuthority
Exact Owner grant and recovery-stream authority used to create a replacement device when no activated device continuation survives.
Passphrase
A memorized secret that wraps a payload under Argon2id. Held zeroizing — the whole struct is cleared on drop, so no copy of the passphrase outlives it.
PendingWrite
Durable write information returned by CovenHandle::pending_writes.
PreparedDevicePairing
The joining device’s retained side of a pairing attempt. It owns no secret key bytes; the pending identity stays in the configured key custody and is addressed by the signed request’s public key until the join commits.
PreparedExternalBlob
A user-owned file whose plaintext size and SHA-256 digest Coven read in one pass. Its content facts stay private and can only be consumed by external blob registration.
ProviderAdminGrantId
ProviderAdminGrantRecord
ProviderCapabilityProof
ProviderDeviceBinding
ProviderReadyDeviceBootstrap
ProvisionalDeviceBootstrap
PublishedPosition
Exact position that made a write visible to peers.
QueuedDelete
One cloud object the durable queue is holding a tombstone for.
QueuedMakeRemote
QueuedUpload
One upload the durable cloud queue is holding, as a host renders it.
Read
A database read that starts when awaited.
ReconfigurableLiveQuery
A tracked query whose absolute request can change without replacing the subscription.
ReconfigurableLiveQueryEvent
One query result and the exact request used to produce it.
ResolvedProviderBinding
RestoreCodeInfo
UI-ready info from a decoded restore code.
RestoreSource
Cloud provider source for restore: the join info a restore code carries plus the extras it can’t (RestoreCode omits OAuth tokens because they expire — the user re-authenticates on restore — and holds no live CloudKit driver).
RowBlobRef
One exact blob-bearing row version. A reference becomes stale when the live row stamp or any declared blob value changes.
RowChange
One row change extracted from a changeset.
S3CloudHome
S3-backed cloud home.
SealedDevicePairingRequest
SequentialIdProvider
Deterministic but unique: "{prefix}-0", "{prefix}-1", … Preserves the per-entity uniqueness invariant while being reproducible across runs.
SqlContext
Host SQL inside one journaled write transaction.
SqlReadContext
Host SQL against Coven’s retained database connection.
StoreBatchCommitRef
Exact identity of one signed Store commit candidate.
StoreCommitCoord
Closed coordinate of one Store commit in its author stream.
StoreDeviceId
The stable identity of one device in a Store, derived from the Store root and the device’s registration origin. It names a device across the protocol — in membership, commit authorship, and epoch-close participation — and is what Circles::exclude_close_device and Circles::close_status address.
StoreDir
Typed wrapper for a store directory path.
StoreKeys
One store’s key material: the encryption master key, cloud-home credentials, and OAuth tokens, each stored under a store-scoped keyring account ({base}:{store_id}). The store’s signing identity is not here — it goes through crate::identity_custody::IdentityCustody, the same way the master key goes through crate::custody::KeyCustody.
StoreLayout
The host’s on-disk layout for stores: which directory they live under. One rule shared by create, open, join, and restore, so a host that wants libraries/<id> instead of coven’s default stores/<id> names it once here rather than each flow hardwiring (or working around) coven’s own choice.
StoreMemberProviderAccessGrantRef
StuckReclaimOperation
A journalled reclaim operation whose last run failed with an error that running it again cannot change.
SyncLoopAlerts
SyncLoopSuccess
SyncedTable
A table that participates in changeset sync, declared at startup by the host and passed to CovenBuilder::synced_tables.
SystemClock
Production clock: real wall time.
Timestamp
A parsed HLC timestamp.
TransferLimits
How many blob transfers coven runs at once in each of its two transfer loops: the upload drain and the pin/download loop. An open-time blob-engine tunable the host sets on the builder, carried on the Database alongside the other open-time blob config and read back by each loop, which holds &Database.
UploadControl
One exact upload’s progress reporting and absolute pause state. Provider request bodies consult this before yielding each network chunk, so pausing stops the active request without closing its upload session; resuming lets that same request continue from the next byte.
UploadFailure
UploadFailures
UserKeypair
Ed25519 keypair for signing changesets and membership changes. The same seed can derive an X25519 keypair for key wrapping.
UuidProvider
Production provider: random v4 UUIDs.
WriteBatch
WriteId
Stable identity of one successfully committed host transaction.
WriteReceipt
Result of one successful host transaction and its durable publication identity.
WriteRetractionWitness
Durable proof that a previously published write cannot activate.

Enums§

AdmittingDeviceJoinProgress
The existing device’s current user-visible operation while admitting the joining device.
ApproveDevicePairingError
Audience
The one audience a synced row belongs to.
AwsPrincipal
BlobCacheError
Why a blob-cache operation failed.
BlobReplacement
A blob’s replacement story: whether the row carrying it may ever be repointed at a different blob. Orthogonal to Provenance and CacheFill; a blob declares all three.
BlobScope
Which key encrypts a blob, as a host names it on a BlobRef.
BlockedOperation
One durable operation a successful cycle left waiting on a person.
BlockedOperationId
Names one blocked operation for a retry, whichever kind it is.
BootstrapError
Why joining or restoring a store failed. Both are the same operation — bootstrap a store from the cloud — differing only in their entry data (an admission that wraps the store key vs a restore code that carries the bucket credentials), so they share one error shape rather than two that duplicate most of their variants and then have to map between each other.
CacheFill
A blob’s Remote story: how a device gets the bytes once the blob is Remote. A cache-mechanism setting — it describes a blob only while Remote — that applies to ANY blob regardless of Provenance. Orthogonal to provenance; a blob declares both.
ChangeOp
The operation type for a changeset entry.
CircleCloseSettlement
The settlement of one participant device’s create-once epoch-close response slot: it published its own applied frontier, an Owner excluded it, or the slot is still empty.
CircleError
Why a Circle command or query failed. Maps the internal typed refusals 1:1 with stable identifiers and carries the ids a caller needs to display or retry. Write-path outcomes (a durable write’s local/published/blocked/conflicted status) are not here — those stay on WriteStatus/WriteBlock.
CircleOperationBlock
Why a durable Circle operation cannot currently publish. One variant per production block site; each future block site adds its own.
CircleOperationKind
CircleOperationState
CircleRole
CircleState
The public derived state of one Circle. Mapped once from the internal current state; Circles::list reports it per Circle.
CloudAccessOutcome
CloudAccessState
CloudCipher
How a cloud home protects its objects at rest. An Encrypted home seals every object under the store key (the default); a Plaintext home stores objects in the clear so the bucket is browsable, and drops the .enc suffix.
CloudFileReadError
CloudHomeCredentials
Credentials for the cloud home, stored as a single JSON keyring entry.
CloudHomeError
Errors from raw cloud storage operations.
CloudHomeJoinInfo
Information needed to join a cloud home from another device.
CloudHomeKeyState
Whether the selected cloud-home storage needs an available master key.
CloudHomeRollbackError
Which durable key material could not be restored after setup failed.
CloudHomeSetupError
Why a proposed cloud home was not installed.
CloudHomeSetupFailure
CloudHomeUnlockError
Why a returning opaque cloud home could not be unlocked and connected.
CloudKitEnvironment
CloudKitScope
CloudKitShareAcceptance
CloudKitSharePermission
CloudProvider
Cloud home provider selection.
ConditionalWriteOutcome
ConfigError
Configuration errors.
CovenError
CovenMigrationError
CovenMigrationPolicy
DbError
An error from the owned database.
DeviceAdmissionError
DeviceJoinAction
DeviceJoinApproval
DeviceJoinApprovalPolicy
Whether the driver approves an access request, and on whose say-so.
DeviceJoinDriveOutcome
How a driven join ended for the admitting side.
DeviceJoinError
DeviceJoinRole
The two sides of a join. One device admits — it answers the access request, prepares the storage grant, signs the approval, registers the device and activates it — and the other is the device being admitted.
DeviceJoinStatus
Derived from a journal record on demand and never stored, so it carries no wire form of its own.
DeviceJoinTransportError
Why a transfer through the transport failed.
DeviceJoinTransportKind
One artifact kind in transit. Every kind has exactly one producing role in the protocol and exactly one slot per attempt.
DeviceJoinTransportOutcome
How a join driven through the transport ended for the joining device.
DevicePairingError
DevicePairingPhase
The durable user-visible phase of one joining-device enrollment. Invitation bytes remain private because they contain the sealed Store admission; callers only need the operation they can resume.
DevicePairingTransportError
DeviceProviderAdmissionCompletion
DeviceProviderReadiness
DeviceRegistrationRequest
A same-provider registration needs no second signature: the joining device’s access request already signed the complete registration. A cross-provider registration additionally signs the response slot allocated after the administrator publishes its challenge.
DrainOutcome
EagerCacheFillError
EagerCacheFillStatus
EncryptionError
ExactCreateOutcome
ExactUploadSource
ExactUploadVerification
How an exact cloud write proves that the stored bytes match their declared object reference. This is local host policy and is never accepted from an invitation or another device.
GoogleDriveCorpus
HeldStoreCoordinate
HeldStorePositionReason
HomeStorage
How a cloud home stores its objects: opaque (encrypted, unreadable to anyone who can read the bucket) or browsable (stored in the clear at readable paths). This is not about who can reach the bucket — the storage provider’s own access control applies either way; it is about whether what they store is legible. The host picks it once, when it creates the home; it cannot change later (it determines how every object is written). One choice drives two mechanisms together:
IdentityCustody
How a store’s device-signing identity is protected. Selected on the builder, resolved once per store — the identity sibling of crate::custody::KeyCustody, same shape.
IdentityError
Why a host’s initialize_identity call failed.
JoiningDeviceJoinProgress
The joining device’s current user-visible operation. These values describe the work actually executing or the exact counterpart artifact being awaited; hosts render them directly instead of collapsing the whole join into one indeterminate state.
KeyCustody
How a store’s master key is protected. The builder accepts this and never sees a cipher again — coven resolves the selection into a MasterKeyCustody and builds every cipher from what it supplies.
KeyError
MakeLocalError
Why a make_local could not complete.
MakeRemoteError
Why a make_remote (or its cancel) could not be started.
MakeRemoteProgress
How far a gated root’s make-remote transition has got, as its durable intent records it. The write id a publication carries is bookkeeping the transition owns, so it is not part of this.
MasterKeyError
Why importing or staging a master key failed.
MemberRole
MembershipConflictInfo
MigrationError
Why running the synced-schema ladder failed. Carried as its own arm of OpenError at the Database::open boundary — not flattened into a DbError string — so the variants stay typed for the engine’s own tests, the snapshot bootstrap gate, and hosts matching MigrationError::SchemaTooNew to prompt an app update.
MigrationStep
How a migration applies its change to the synced schema.
OAuthClientCredsError
An OAuth client set is missing a provider or names a provider that does not use OAuth.
OAuthError
OutboxFailureKind
PhysicalObjectLocator
Provider-specific physical address for a caller-reserved immutable slot.
Provenance
A blob’s Local story: where its bytes live while the blob is Local, and whether bringing it back from Remote needs a destination path. Orthogonal to CacheFill (the Remote story) — a blob declares both.
ProviderAccessLocator
Stable provider authority that can be withdrawn without rediscovering a member by mutable account metadata.
ProviderAccessWithdrawal
ProviderPrincipalId
QueuedUploadPhase
ReclaimTarget
The exact object a reclaim authorizes the deletion of, together with the kind-specific locator needed to physically delete it and confirm its absence. Every kind shares one signed evidence → authorization → receipt chain; the kind selects only the eligibility proof and the readback prefix.
ReconfigurableLiveQueryCause
Why a reconfigurable live query produced an event.
RestoreAuthority
The closed authority a restore operation may exercise.
RestoreCodeError
RetryBlockedOperationError
Why one blocked operation could not be handed back to the sync loop.
RetryStuckReclaimError
Why the sync loop could not return a stuck reclaim operation to its journal.
RowBlobAuthority
The authority state that determines where one row version’s blob lives. A remote-audience blob remains PendingRemote while its verified plaintext is local and no cloud object has been created; Remote carries the exact package authority needed to open its committed object.
RowIdentity
How (table, id) names one logical row across every device.
S3EndpointBinding
SealError
Why sealing or opening a host’s app-data failed.
StartDevicePairingError
StorageError
StoreProviderBinding
Provider namespace/corpus facts signed once by the Store root.
SyncError
SyncLoopFailure
SyncLoopStatus
A sync-loop status the host renders. The loop reports provider reachability, publication, and one terminal status. Blocked is a successful storage cycle with durable operations waiting on a person; Synchronized has none, while Failed means the cycle itself failed. The in-progress marker is the variant itself, so there is no separate “syncing” flag.
UploadFailureCause
WriteBlock
A semantic write fault. Retrying transport cannot change this result.
WriteError
A failed atomic write, tagged with whether the write had already committed.
WriteResolution
WriteStatus
Current durable state of one host transaction.

Constants§

CHUNK_SIZE
64KB plaintext chunks

Traits§

BlobTransitionObserver
Notified about coven’s blob transitions, for host-specific bookkeeping and UI: per-blob upload progress while a make_remote uploads, per-blob materialize progress while a make_local copies files back, and the synchronous make-local completion the host turns into its own UI event.
Clock
Wall-clock source. Returns a full DateTime<Utc>; callers derive .timestamp() / .to_rfc3339() as they need.
CloudHome
CloudKitOps
Synchronous interface for raw CloudKit record operations. Implemented by a host bridge to its platform CloudKit driver. Methods block the calling thread while CloudKit async operations complete.
DeviceIdentityCustody
A device’s signing identity’s custody FOR ONE STORE: who unlocks it, where a newly established one is written, and how it is removed. The signing-key sibling of MasterKeyCustody, same three-method shape and the same per-store selection, over UserKeypair instead of a store’s master keyring.
DeviceProviderAccessAdministrator
ExactCloudHome
A cloud home admitted to sync: raw object operations and exact immutable slots are one provider capability, so callers cannot open the home and then ask it to hand back a second provider object.
ExactSlotStorage
Low-level cloud storage. Implementations handle a single store.
IdProvider
Identifier source. Yields a fresh unique id per call.
MasterKeyCustody
A store’s master keyring’s custody: who unlocks it, where a newly established or rotated one is written, and how it is removed. Implemented once per protection policy (the OS keyring, a passphrase-wrapped file, an in-memory session value, or a host’s own).
PartSink
The one per-provider streaming-upload surface: a session that accepts ordered parts and commits. The central write_blob driver opens one of these for a large blob and pumps BlobBody parts into it — no backend writes its own upload loop, collect, or progress call.

Functions§

content_hash
The content hash a blob-bearing row carries: the lowercase-hex SHA-256 of the blob’s plaintext bytes, computed at import and stored in the row’s blob columns alongside the declared size. The row is carried in a signed changeset (and in a signed snapshot), so this hash is signed by the row’s author — that is what makes it authoritative: on download coven hashes the decrypted plaintext and requires equality with the row’s hash, so the bytes are pinned by the author, not by the cloud key they happened to arrive under. A host computes this over a blob’s plaintext at import and writes it into the row’s declared hash column, the same way it writes the plaintext length into the size column.
decode_restore_code_info
Decode a restore code and return UI-ready info.
fetch_account_email
install_test_keyring_service
join_with_device_pairing
Complete the joining side after scanning the existing device’s one pairing code. The local session returns the invitation sealed to this attempt; the existing Store transport then performs registration and bootstrap. The caller’s Coven migration policy controls every writer open during bootstrap.
keyring_service
The registered keyring service name. Err when the host never ran the startup set_keyring_service call — surfaced so a mis-ordered host gets a typed error, not a panic deep inside a key operation.
no_progress
A progress sink that discards its reports. For write calls whose payload is a small control file (head pointers, the snapshot) where no per-file progress bar is driven — only the blob outbox surfaces progress.
prepare_external_blob
Stream a user-owned file once and prepare its opaque content identity for registration. progress receives the cumulative bytes consumed after each read.
restore_from_cloud
Restore a store from cloud storage.
restore_from_code
Restore a store from a restore code string.
set_keyring_service
Register the process-wide keyring: the service name every entry is stored under, and the platform keyring store that backs it. Both are one-time startup registration and must run before any key operation. The store is installed before the name is recorded, so a failed installation leaves no registration behind. Re-registering the same name is a no-op; a different name is a startup contradiction and fails. Fails with KeyError::UnsupportedKeyringPlatform on a target with no bundled store.
write_atomic
Install bytes as the complete contents of path.
write_cloud_object_stream

Type Aliases§

BoxPartSink
A boxed PartSink borrowing its home for 'a.
ClockRef
Shared handle to a clock. Held by Clone types (CovenHandle, CovenReadHandle) so they clone the handle, not the implementation.
CloudObjectStream
CovenResult
DeviceJoinOffer
DeviceProviderAccessRequest
DeviceProviderAdmissionApproval
DownloadProgress
Reports how many bytes of a cloud object have arrived from the provider. The count is cumulative and advances once per received stream buffer.
IdRef
Shared handle to an id provider. Held by Clone types that need to share one id source, so they clone the handle, not the implementation.
JoiningDeviceJoinProgressObserver
A joining device’s retained progress sink. Provider reads keep a clone while their response stream is active, so every received buffer reaches the host.
UploadProgress
Reports how many bytes of a write have reached the backend so far. Called with the cumulative byte count as the body uploads; backends that can’t observe sub-call progress call it once at the end with the full size. The count is of the bytes handed to write (the encrypted payload).