Skip to content

Wire upload resume: capture recovery_token, implement GET /status for cross-restart resume #65

Description

@rubenhensen

Cryptify shipped the upload-resume protocol (cryptify#148, cryptify#145, cryptify#144) as part of cryptify#136. pg-js already covers some of it but the cross-restart path is missing.

What pg-js already does

What is missing

1. `recovery_token` is not captured from `initUpload`

`POST /fileupload/init` now returns a 32-byte hex `recovery_token` in the JSON body. `initUpload` in `src/api/cryptify.ts` only reads `uuid` from the JSON and the rolling token from the `cryptifytoken` header. The recovery token is silently dropped.

It needs to be returned from `initUpload` so the caller can persist it. Suggested shape:

```ts
interface FileState {
token: string;
uuid: string;
recoveryToken: string; // new — required for cross-restart resume
prevToken?: string;
}
```

2. No `GET /fileupload/{uuid}/status` call

When an addon/website is resumed after a refresh or process restart, it has `{uuid, recoveryToken}` from local storage but no `cryptify_token`. There's currently no pg-js function that calls `GET /fileupload/{uuid}/status` with `X-Recovery-Token` to rehydrate `FileState`.

Suggested API:

```ts
export async function resumeUpload(
cryptifyUrl: string,
uuid: string,
recoveryToken: string,
signal?: AbortSignal
): Promise<{ state: FileState; uploaded: number }>;
```

  • Returns the current `uploaded` byte offset and the rehydrated `FileState` (token, prevToken if present).
  • 404 `upload_session_not_found` → `UploadSessionExpiredError` (reuse the existing throw helper).

3. Persistence is consumer-owned

pg-js shouldn't try to persist `{uuid, recoveryToken}` itself — the storage layer differs per host (Office addin roamingSettings, Thunderbird `browser.storage`, website IndexedDB). Just expose the values and let the consumer decide. The consumer issues are tracked downstream:

Related — separate issue

Download-side Range support has its own bug: pg-js's `downloadRange` already requires `206 Partial Content`, but cryptify's `FileServer` never returns 206 (it uses Rocket's `sized_body`, which has no Range handling). That's tracked at cryptify#153 — server-side fix, no pg-js change needed once cryptify honours Range.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions