mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
Follow-ups to the review of the push, keyword and identity work: - A send that names no sender, like the List-Unsubscribe mailto: of the unified view, fell back to the first identity in server order, which on Stalwart 1.0 is a group's. It now takes the login's own identity, with addresses compared regardless of case. - Re-register creates the replacement subscription before it destroys the old one, so at Stalwart's limit (15 per account by default) it failed with `overQuota`. It now frees the old record's place and tries once more. - On 1.0 the push settings note goes by the emailpush capability alone and ignores refusals remembered under 0.16. On 0.16 a group the user belongs to is recognised by its identity, so a member without calendars, contacts or files keeps the group's junk filter and is no longer told the group sends no notifications. - Plugin imports can no longer set Stalwart 1.0's attachment keywords, and `keywords.discover` leaves them out. - Batch mark-as-read showed messages the server refused as read. It now updates only what was written and reports the rest, and thread expansion and category-tab moves keep what a partly refused batch did write. - Refused read and star changes from shortcuts, the list, the viewer and Pro tabs show "Failed to update email" instead of an unhandled rejection. The automatic mark-as-read on opening stays quiet. - A tag whose id predates the 128-byte limit can have its colour changed again. - The state-regression guard notes that a multi-node 1.0 cluster can trip it harmlessly, at the cost of one extra full fetch.
69 lines
2.5 KiB
TypeScript
69 lines
2.5 KiB
TypeScript
/**
|
|
* JMAP errors carried on a thrown `Error`.
|
|
*
|
|
* A method error or a SetError names what went wrong in its `type`
|
|
* (`overQuota`, `forbidden`, `invalidProperties`, ...) and, for
|
|
* `invalidProperties`, which `properties` the server refused. Callers
|
|
* branch on those instead of parsing the human-readable description, which
|
|
* differs between servers and Stalwart releases.
|
|
*/
|
|
|
|
/** The parts of a JMAP method error or SetError a caller can branch on. */
|
|
export interface JmapErrorInfo {
|
|
type?: string;
|
|
description?: string;
|
|
properties?: string[];
|
|
}
|
|
|
|
export type JmapError = Error & {
|
|
jmapType?: string;
|
|
jmapProperties?: string[];
|
|
jmapSetError?: boolean;
|
|
jmapFailedIds?: string[];
|
|
};
|
|
|
|
/** An `Error` with `message` that keeps the server's error type and properties. */
|
|
export function jmapError(message: string, info?: JmapErrorInfo | null): JmapError {
|
|
const error: JmapError = new Error(message);
|
|
if (info?.type) error.jmapType = info.type;
|
|
if (info?.properties?.length) error.jmapProperties = [...info.properties];
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* {@link jmapError} for a SetError: the server looked at one object of a /set
|
|
* call and refused it (`notCreated`, `notUpdated`, `notDestroyed`, RFC 8620
|
|
* §5.3), as opposed to refusing the whole method call. The same type can come
|
|
* either way (`forbidden` is both), and only the SetError says something about
|
|
* that object.
|
|
*/
|
|
export function jmapSetError(message: string, info?: JmapErrorInfo | null): JmapError {
|
|
const error = jmapError(message, info);
|
|
error.jmapSetError = true;
|
|
return error;
|
|
}
|
|
|
|
/** Whether a thrown value is a SetError (see {@link jmapSetError}). */
|
|
export function isJmapSetError(error: unknown): boolean {
|
|
return (error as JmapError | null | undefined)?.jmapSetError === true;
|
|
}
|
|
|
|
/** The JMAP error type a thrown value carries, if any. */
|
|
export function jmapErrorType(error: unknown): string | undefined {
|
|
return (error as JmapError | null | undefined)?.jmapType;
|
|
}
|
|
|
|
/** The properties an `invalidProperties` error named, if any. */
|
|
export function jmapErrorProperties(error: unknown): string[] {
|
|
return (error as JmapError | null | undefined)?.jmapProperties ?? [];
|
|
}
|
|
|
|
/**
|
|
* The objects a write of several left unchanged, when the error names them: a
|
|
* /set refuses objects one by one and applies the rest. Null when it doesn't
|
|
* say (after a failed request, for one), so any of them may be unchanged.
|
|
*/
|
|
export function jmapErrorFailedIds(error: unknown): string[] | null {
|
|
return (error as JmapError | null | undefined)?.jmapFailedIds ?? null;
|
|
}
|