trpc-browser
Version:
tRPC adapters and links for everywhere in the browser
93 lines • 3.9 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.popupLink = void 0;
const constants_1 = require("../shared/constants");
const base_1 = require("./internal/base");
const popupLink = (opts) => {
const messageHandlerMap = new Map();
const closeHandlerSet = new Set();
let popupWindow = null;
async function getPopup(loadListenWindow) {
if (!popupWindow || popupWindow.closed) {
popupWindow = opts.createPopup();
await Promise.race([
// wait til window is loaded (same origin)
new Promise((resolve) => {
var _a;
try {
(_a = popupWindow === null || popupWindow === void 0 ? void 0 : popupWindow.addEventListener) === null || _a === void 0 ? void 0 : _a.call(popupWindow, 'load', resolve);
}
catch (_b) {
// if this throws, it's a cross-origin popup and should stay pending (never resolve)
}
}),
// this is needed for cross-origin popups as they don't have a load event
new Promise((resolve) => {
loadListenWindow.addEventListener('message', (event) => {
if (event.data === constants_1.TRPC_BROWSER_LOADED_EVENT) {
resolve();
}
});
}),
// expect the popup to load after 15s max, in case non of the above events fire
new Promise((resolve) => {
console.warn('Could not detect if popup loading succeeded after 15s timeout, continuing anyway');
setTimeout(resolve, 15000);
}),
]);
// subscribe to popup closing
try {
if (!popupWindow.addEventListener) {
throw new Error('popupWindow.addEventListener is not a function');
}
popupWindow.addEventListener('beforeunload', () => {
popupWindow = null;
});
}
catch (_a) {
// this throws on cross-origin popups, fallback to polling to check if popup is closed
const pid = setInterval(() => {
if (popupWindow && popupWindow.closed) {
popupWindow = null;
closeHandlerSet.forEach((handler) => {
handler();
});
clearInterval(pid);
}
}, 1000);
}
}
return popupWindow;
}
return (0, base_1.createBaseLink)({
async postMessage(message) {
const popup = await getPopup(opts.listenWindow);
return popup.postMessage(message, {
targetOrigin: opts.postOrigin,
});
},
addMessageListener(listener) {
const handler = (ev) => {
listener(ev.data);
};
messageHandlerMap.set(listener, handler);
opts.listenWindow.addEventListener('message', handler);
},
removeMessageListener(listener) {
const handler = messageHandlerMap.get(listener);
if (handler) {
opts.listenWindow.removeEventListener('message', handler);
}
},
addCloseListener(listener) {
opts.listenWindow.addEventListener('beforeunload', listener);
closeHandlerSet.add(listener);
},
removeCloseListener(listener) {
opts.listenWindow.removeEventListener('beforeunload', listener);
closeHandlerSet.delete(listener);
},
});
};
exports.popupLink = popupLink;
//# sourceMappingURL=popup.js.map
;