1 import { deleteVersionCookies } from '@proton/components/helpers/versionCookie';
2 import { getApiError } from '@proton/shared/lib/api/helpers/apiErrorHelper';
3 import { wait } from '@proton/shared/lib/helpers/promise';
4 import noop from '@proton/utils/noop';
6 import { setCurrentRetries } from '../../helpers/earlyAccessDesynchronization';
8 const API_ERROR_KEY = 'API_ERROR_REFRESH';
9 const EARLY_ACCESS_KEY = 'EARLY_ACCESS_RESET';
11 export const clearAutomaticErrorRefresh = () => {
12 sessionStorage.removeItem(API_ERROR_KEY);
13 sessionStorage.removeItem(EARLY_ACCESS_KEY);
16 const handleEarlyAccessRefresh = () => {
17 const oldValue = Number(sessionStorage.getItem(EARLY_ACCESS_KEY));
18 // If it's the first time, we try a simple reload.
20 sessionStorage.setItem(EARLY_ACCESS_KEY, '1');
21 window.location.reload();
24 // If this error happens a second time, we force delete everything regarding version cookie and attempt another reload.
26 sessionStorage.setItem(EARLY_ACCESS_KEY, '2');
27 deleteVersionCookies();
29 window.location.reload();
35 const handleApiErrorRefresh = () => {
36 if (!sessionStorage.getItem(API_ERROR_KEY)) {
37 sessionStorage.setItem(API_ERROR_KEY, 'true');
38 window.location.reload();
44 const handleError = (error: any) => {
45 const apiError = getApiError(error);
46 // If there is no API error message or it's a chunk loading error, assume it's a resource loading error.
47 if (!apiError.message || error?.message?.includes('chunk')) {
48 if (handleEarlyAccessRefresh()) {
51 } else if (apiError.message) {
52 if (handleApiErrorRefresh()) {
59 export const wrapUnloadError = <T>(promise: Promise<T>): Promise<T> => {
60 // In Firefox, navigation events cancel ongoing network requests. This triggers the error handler and error
61 // screen to be displayed. We set up a 'beforeunload' listener to detect unload to not unnecessarily
62 // show cancelled network requests errors as fatal errors, and keep showing the loader screen instead.
65 const handleUnload = () => {
69 const listen = () => {
70 window.addEventListener('beforeunload', handleUnload);
72 window.removeEventListener('beforeunload', handleUnload);
76 const unlisten = listen();
80 clearAutomaticErrorRefresh();
85 // Wait an arbitrary amount of time to ensure the unload listener is first.
88 // Never resolve the promise if the browser has unloaded or if we're refreshing
89 if (unloaded || handleError(e)) {
90 return new Promise(noop);