• v0.18.5 — iPhone uploads sent an empty body; the queue now owns the bytes
    Some checks failed
    Audit / cargo audit (backend) (push) Failing after 9m1s
    Audit / npm audit (frontend) (push) Successful in 1m10s
    Checks / Backend — cargo test + clippy + fmt (push) Failing after 55s
    Checks / Keepsake viewer — builds, self-contained, committed artifact in sync (push) Has been cancelled
    Checks / E2E — typecheck + lint (push) Has been cancelled
    E2E / Playwright E2E (chromium + webkit) (push) Has been cancelled
    E2E / Cross-UA smoke matrix (push) Has been cancelled
    Checks / Frontend — vitest + svelte-check (push) Has been cancelled

    fabi released this 2026-08-22 15:57:47 +00:00 | 2 commits to main since this release

    Frontend only. Backend unchanged since v0.18.0, no migration touched (31), so the
    app image is re-tagged and v0.18.4 remains a valid rollback target.

    Measured at the proxy during the live event: iPhone POSTs arrived with
    content_length=0 in 7-22 ms. Nothing reached the wire, so this was never a
    transport problem. addToQueue stored the picked File itself, and WebKit persists
    a File in IndexedDB as a REFERENCE to an OS file that iOS deletes once the picker
    closes. The neutered File still reports .name and .size, send() does not throw,
    and an empty body goes out.

    • Bytes are copied at pick time, chunked at 4 MB so a 500 MB video cannot take
      the tab with it.
    • An unreadable blob is TERMINAL and never retried, detected by probing one
      real byte because .size lies. This also stops items queued before the fix,
      which still hold dead references, from retrying forever.

    v0.18.4 made this worse rather than better: it reclassified the resulting 400 as
    retryable, so every dead photo re-sent an empty body five times — 79 failed
    requests against 1 success. That reclassification is still correct for a
    genuinely truncated body; what was missing is that an empty body never gets that
    far now.

    Downloads