Files
webmail/lib/files-sync/errors.ts
T

93 lines
2.6 KiB
TypeScript

/**
* What went wrong, in the words the settings page shows: keys under `files_sync.errors.`
* (the ui writes the strings). Errors are told apart by name, not instanceof: Next has more
* than one copy of a module.
*/
import type { FilesError } from '@/lib/desktop/types';
export type FilesSyncErrorName =
| 'offline'
| 'server_refused'
| 'too_large'
| 'name_invalid'
| 'disk_full'
| 'denied'
| 'busy'
| 'quota'
| 'not_found'
| 'policy'
| 'failed';
/** The key in the `files_sync` namespace. */
export function errorKey(name: FilesSyncErrorName): string {
return `errors.${name}`;
}
/** A disk answer the engine can't go on from for this item. */
export class LocalError extends Error {
constructor(readonly error: FilesError) {
super(`files:${error}`);
this.name = 'LocalError';
}
}
export function localErrorName(error: FilesError): FilesSyncErrorName {
switch (error) {
case 'full':
return 'disk_full';
case 'denied':
case 'outside':
case 'gesture':
return 'denied';
case 'busy':
return 'busy';
case 'name':
return 'name_invalid';
case 'policy':
return 'policy';
case 'missing':
return 'not_found';
default:
return 'failed';
}
}
/** The server can't be reached, or is too busy now: the work waits, nothing failed. */
export function isOffline(error: unknown): boolean {
const e = error as { name?: string; kind?: string; status?: number } | null;
if (e?.name !== 'TransportError') return false;
if (e.kind === 'network' || e.kind === 'rate') return true;
return e.kind === 'http' && typeof e.status === 'number' && e.status >= 500;
}
/** The server no longer takes this login. */
export function isAuthRefused(error: unknown): boolean {
const e = error as { name?: string; kind?: string } | null;
return e?.name === 'TransportError' && e.kind === 'auth';
}
/** What a server error on one item means. */
export function remoteErrorName(error: unknown): FilesSyncErrorName {
const e = error as { name?: string; type?: string; status?: number } | null;
if (isOffline(error)) return 'offline';
if (isAuthRefused(error)) return 'server_refused';
if (e?.name === 'TransportError' && e.status === 413) return 'too_large';
switch (e?.type) {
case 'overQuota':
return 'quota';
case 'forbidden':
case 'accountReadOnly':
return 'denied';
case 'notFound':
return 'not_found';
case 'tooLarge':
return 'too_large';
case 'invalidProperties':
case 'alreadyExists':
return 'name_invalid';
default:
return 'failed';
}
}