1 import { CrossStorageTimeoutError, CrossStorageUnsupportedError } from './errors';
2 import type { CrossStorageMessage } from './interface';
3 import { getIsSupported } from './support';
11 const createGuest = <MessagePayload>(urlTarget: string) => {
12 let iframe: HTMLIFrameElement;
13 let state = States.INIT;
15 promise: Promise<void>;
17 reject: (error: Error) => void;
19 const url = new URL(urlTarget);
21 const messagePromiseCache: {
22 [key: string]: { resolve: (value: any) => void; reject: (error: Error) => void };
25 const initPromise = () => {
26 promiseHandler = {} as any;
27 promiseHandler.promise = new Promise<void>((resolve, reject) => {
28 promiseHandler.resolve = resolve;
29 promiseHandler.reject = reject;
31 promiseHandler.promise.catch(() => {});
34 const initListener = (origin: string) => {
35 const timeoutHandle = window.setTimeout(() => {
37 promiseHandler.reject(new CrossStorageTimeoutError());
40 window.addEventListener('message', (event: MessageEvent<CrossStorageMessage>) => {
45 const contentWindow = iframe?.contentWindow;
46 if (!iframe || !contentWindow || event.origin !== origin || event.source !== contentWindow) {
50 const eventData = event.data;
51 if (!eventData?.type) {
55 if (eventData.type === 'init') {
56 window.clearTimeout(timeoutHandle);
57 if (getIsSupported(eventData.payload.value)) {
58 state = States.SUCCESS;
59 promiseHandler.resolve();
62 promiseHandler.reject(new CrossStorageUnsupportedError());
66 if (state !== States.SUCCESS) {
70 if (eventData.type === 'response') {
71 if (eventData.status === 'success') {
72 messagePromiseCache[eventData.id]?.resolve(eventData.payload);
74 if (eventData.status === 'error') {
75 messagePromiseCache[eventData.id]?.reject(eventData.payload);
81 const loadIframe = (url: string) => {
82 iframe = window.document.createElement('iframe');
86 iframe.style.display = 'none';
87 document.body.appendChild(iframe);
90 const getState = () => {
94 const getMessagePromise = <T>(id: number) => {
95 return new Promise<T>((resolve, reject) => {
96 messagePromiseCache[id] = {
103 const postMessage = async (message: CrossStorageMessage) => {
104 await promiseHandler.promise;
105 iframe.contentWindow?.postMessage(message, url.origin);
108 const postAndGetMessage = async <T>(messagePayload: MessagePayload) => {
109 const messageId = id++;
110 const promise = getMessagePromise<T>(messageId);
114 payload: messagePayload,
119 const initChildCrossStorage = () => {
121 initListener(url.origin);
122 loadIframe(url.toString());
125 initChildCrossStorage();
128 supported: async () => {
130 await promiseHandler.promise;
141 export default createGuest;