Skip to content

feat(upload): status endpoint for cross-refresh resume #146

@rubenhensen

Description

@rubenhensen

Background

#145 added idempotent retry of the most recently committed chunk: a client whose chunk-PUT response was lost can replay the same chunk with the previous token and the server returns the cached response without re-writing or double-counting. This unblocked transparent in-session retry in postguard-js (encryption4all/postguard-js#47).

What's still missing is cross-refresh / cross-process resume. Today, if the user reloads the page, navigates away and back, or the browser tab crashes mid-upload, all in-flight state is lost on the client even though the server's last_chunk cache and the on-disk file are still intact (assuming the session hasn't been evicted past its idle TTL).

#117 and #136 both flagged this. @dobby-coder's audit at #136 (comment) sketched two designs; we picked idempotent retry for #145. This issue tracks the second one.

Proposed design

A new authenticated GET endpoint that returns the current upload state so a client can rehydrate after losing its in-memory state:

GET /fileupload/{uuid}/status
Authorization: Bearer <recovery_token>

200 OK
{
  \"uploaded\": <bytes>,
  \"cryptify_token\": \"<current rolling token>\",
  \"prev_token\": \"<previous rolling token, may be null if no chunk committed yet>\",
  \"prev_uploaded\": <byte offset of last committed chunk, may be null>
}
  • recovery_token is issued at upload_init time alongside the first cryptifytoken, returned in a separate response field (e.g. recovery_token). The client stores it in IndexedDB along with the upload UUID.
  • The client uses prev_token + prev_uploaded to feed the existing idempotent-retry path on the very next chunk PUT, so the server's rolling-token chain stays intact even if the browser missed the response.
  • 404 (with the structured upload_session_not_found body from feat(upload): structured 404 body + configurable session TTL #144) when the session has been evicted or never existed.

Why this needs Phase 2 first

Cross-refresh resume only makes sense if the upload session itself survives a server restart. Today FileState is in-memory only (#116), so a Procolix redeploy or pod crash already wipes the session regardless of whether the client could remember the UUID. This issue should be picked up after the Postgres-backed sessions land (#116, #134) — otherwise we're shipping client recovery for a server that can't actually recover.

Out of scope for this issue

  • The client-side IndexedDB persistence and rehydrate-on-reload flow in postguard-js — tracked separately at encryption4all/postguard-js#X (filed alongside this).
  • Resumable downloads — also tracked separately in postguard-js (cryptify's FileServer already supports Range, so it's a pure SDK concern).

Acceptance criteria

  • GET /fileupload/{uuid}/status returns the schema above for live sessions
  • Endpoint requires the recovery_token issued at init; missing/invalid → 401
  • Evicted/unknown session → 404 with upload_session_not_found body (matches feat(upload): structured 404 body + configurable session TTL #144)
  • upload_init response includes the recovery_token (additive — old clients ignore it)
  • Documented in `api-description.yaml`
  • Unit tests cover hit / 401 / 404 / state-after-N-chunks cases

Refs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions