1 import { updateServerTime } from '@proton/crypto';
2 import type { ApiWithListener } from '@proton/shared/lib/api/createApi';
3 import noop from '@proton/utils/noop';
5 import type { APP_NAMES } from '../constants';
6 import { DEFAULT_TIMEOUT } from '../constants';
7 import { createTimeoutError, deserializeApiErrorData } from '../fetch/ApiError';
8 import { getIsAuthorizedApp, getIsDrawerPostMessage, postMessageFromIframe } from './helpers';
9 import { DRAWER_EVENTS } from './interfaces';
11 export const createDrawerApi = ({
15 parentApp: APP_NAMES | undefined;
17 }): ApiWithListener => {
20 const callback = (arg: any) => {
22 let timeout: ReturnType<typeof setTimeout> | undefined;
24 let resolve: (arg: any) => void = noop;
25 let reject: (error: any) => void = noop;
26 const promise = new Promise<any>((res, rej) => {
31 const handler = (event: MessageEvent) => {
32 if (!getIsDrawerPostMessage(event)) {
36 if (event.data.type === DRAWER_EVENTS.API_RESPONSE && event.data.payload.id === id) {
37 const { output, serverTime, data, success, isApiError } = event.data.payload;
39 window.removeEventListener('message', handler);
41 clearTimeout(timeout);
44 updateServerTime(serverTime);
46 if (success && data) {
47 if (output === 'raw') {
48 resolve({ ...data, headers: new Headers(data.headers), json: async () => data.json });
54 reject(deserializeApiErrorData(data));
61 if (parentApp && getIsAuthorizedApp(parentApp)) {
62 const hasAbortController = 'signal' in arg;
64 const newArg: any = { ...arg };
65 if (hasAbortController) {
67 (arg.signal as AbortSignal).onabort = () => {
68 postMessageFromIframe(
70 type: DRAWER_EVENTS.ABORT_REQUEST,
73 parentApp as APP_NAMES
77 postMessageFromIframe(
79 type: DRAWER_EVENTS.API_REQUEST,
80 payload: { arg: newArg, id, appVersion, hasAbortController },
84 window.addEventListener('message', handler);
86 // Reject the promise if the parent app does not respond
87 timeout = setTimeout(() => {
88 reject(createTimeoutError({}));
95 Object.defineProperties(callback, {
101 return Object.assign(callback as ApiWithListener, {
102 addEventListener: () => {},
103 removeEventListener: () => {},