UNPKG

penpal

Version:

A promise-based library for communicating with iframes via postMessage.

101 lines (85 loc) 3.45 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _errorSerialization = require("./errorSerialization"); var _enums = require("./enums"); /** * Listens for "call" messages coming from the remote, executes the corresponding method, and * responds with the return value. */ var _default = (info, serializedMethods, log) => { const { localName, local, remote, originForSending, originForReceiving } = info; let destroyed = false; const handleMessageEvent = event => { if (event.source !== remote || event.data.penpal !== _enums.MessageType.Call) { return; } if (originForReceiving !== '*' && event.origin !== originForReceiving) { log("".concat(localName, " received message from origin ").concat(event.origin, " which did not match expected origin ").concat(originForReceiving)); return; } const callMessage = event.data; const { methodName, args, id } = callMessage; log("".concat(localName, ": Received ").concat(methodName, "() call")); const createPromiseHandler = resolution => { return returnValue => { log("".concat(localName, ": Sending ").concat(methodName, "() reply")); if (destroyed) { // It's possible to throw an error here, but it would need to be thrown asynchronously // and would only be catchable using window.onerror. This is because the consumer // is merely returning a value from their method and not calling any function // that they could wrap in a try-catch. Even if the consumer were to catch the error, // the value of doing so is questionable. Instead, we'll just log a message. log("".concat(localName, ": Unable to send ").concat(methodName, "() reply due to destroyed connection")); return; } const message = { penpal: _enums.MessageType.Reply, id, resolution, returnValue }; if (resolution === _enums.Resolution.Rejected && returnValue instanceof Error) { message.returnValue = (0, _errorSerialization.serializeError)(returnValue); message.returnValueIsError = true; } try { remote.postMessage(message, originForSending); } catch (err) { // If a consumer attempts to send an object that's not cloneable (e.g., window), // we want to ensure the receiver's promise gets rejected. if (err.name === _enums.NativeErrorName.DataCloneError) { const errorReplyMessage = { penpal: _enums.MessageType.Reply, id, resolution: _enums.Resolution.Rejected, returnValue: (0, _errorSerialization.serializeError)(err), returnValueIsError: true }; remote.postMessage(errorReplyMessage, originForSending); } throw err; } }; }; new Promise(resolve => resolve(serializedMethods[methodName].apply(serializedMethods, args))).then(createPromiseHandler(_enums.Resolution.Fulfilled), createPromiseHandler(_enums.Resolution.Rejected)); }; local.addEventListener(_enums.NativeEventType.Message, handleMessageEvent); return () => { destroyed = true; local.removeEventListener(_enums.NativeEventType.Message, handleMessageEvent); }; }; exports.default = _default;