An edit that removed an entry was dropped at flush, because a server
value with more keys counted as already applied. Other fixes in the same
path:
- the local copy after a flush is the server's read-back, never what was
sent, since Stalwart 1.0 stores a data: URI as a blob
- a delete or a newer edit after a lost response no longer reads as a
change on the server, and an edit made during a refused send stays
- a create only becomes a card with its uid if that card holds what was
sent, otherwise it is a refused conflict
- a refused or failed flush no longer stops contacts syncing
- request limits come from the session
- answers wait for the first full pass
- paging goes by anchor, so a deleted card doesn't make the next one
get skipped and swept
contacts.test.ts: "continues a stopped full sync" now checks the anchor
instead of position 2000, because the cursor no longer pages by position.
Fixes from the review of api.files:
- `files.attach` to a new draft runs `onBeforeAttachmentUpload` for each
file and the server's total size limit before `compose.open`, which
runs neither; refused files come back in `refused`
- a write is refused when a folder above the target is missing from the
listing, instead of counting it as not shared
- `onFileMove` reports the item as it was, from where it was, like the
Files app's own move
- writes are counted against the 20-a-minute limit before the drive is
listed, so refused writes count and cost no listing
- reads stop the download past 20 MB (`fetchBlobArrayBuffer` with a
limit) and answer `too_big` when the listed size was wrong
- when the server refuses the new content of a replaced file, the old
version's copy is taken out of the trash again
The two getText assertions on `fetchBlobArrayBuffer` now expect the
account (undefined for the own drive) and the byte limit, since the
call passes both.
Both make the server fetch the sender's domain. The test that every
default value is allowed now also names senderFavicons (on by default,
which a plugin may no longer set); the rest of it is as it was.
exif.test.ts: the case "falls back to the file date" now expects no
date, since IFD0's DateTime is the file's change date, not the date
the photo was taken.
The host reads the size a PNG, GIF, JPEG, WebP or BMP declares in its
header first: over 50 megapixels it answers too_big, trackers and tiny
images are never decoded, a format whose header it can't read is
unsupported, and large images are decoded at the target width. A browser
that throws a TypeError on createImageBitmap's options decodes without
them.
The tests' stand-in pictures are now PNG headers instead of JSON (the
code reads the header), so image-shrink.test.ts and
plugin-host-attachment-image.test.ts build them that way, and the first
shrink test expects the resize options on createImageBitmap.
api.email.getThread fetches only the newest 50 messages of a thread
(Thread/get, then Email/get for those ids) instead of all of them with
their bodies. api.email.getThreadCount answers the number of messages
from Thread/get, with its own rate limit.
plugin-host-thread.test.ts now expects getThreadEmails to be called with
{ newest: 50 }, the new option that limits what is fetched.