Files
SRCmail/lib/jmap/request-limits.ts
T
Mathy Vanvoorden 1652a0ec62 fix: make bulwark respect server limits
If you have a large number of tags, getTagCounts would not be able to get the
unread counts because it did not respect maxCallsInRequest, even though the
value was actually read out, it was just ignored. There are also other places
where the limits were not respected.

Batching is now generalized in a helper that also takes maxObjectsInSet, which
also was ignored, into account and is applied to all functions.

In addition, the dev mock now also advertises and enforces the limits, so these
issues can get picked up during development.

Possible closes #699
Possibly closes #399
2026-07-30 22:11:40 +02:00

27 lines
1.2 KiB
TypeScript

/**
* A JMAP session advertises hard ceilings on what one request may carry: how
* many method calls it holds (`maxCallsInRequest`) and how many objects a
* single /get or /set may touch (`maxObjectsInGet`, `maxObjectsInSet`). Going
* over any of them fails the *whole* request, not the surplus, so a batch built
* from a list the user controls - tags, category tabs, a multi-select, an
* import - is split against the advertised limit before it is sent.
*
* Stalwart defaults to 16 method calls and 500 objects, so the ceilings are low
* enough to reach with ordinary use: nine tags is already 18 calls.
*/
/** Split `items` into consecutive batches of at most `size` entries. */
export function batched<T>(items: T[], size: number): T[][] {
const step = Math.max(1, Math.floor(size));
const result: T[][] = [];
for (let i = 0; i < items.length; i += step) {
result.push(items.slice(i, i + step));
}
return result;
}
/** How many items fit in one request when each item costs `callsPerItem` method calls. */
export function itemsPerRequest(maxCalls: number, callsPerItem: number): number {
return Math.max(1, Math.floor(maxCalls / callsPerItem));
}