penpal
Version:
A promise-based library for communicating with iframes via postMessage.
107 lines (81 loc) • 3.33 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _enums = require("../enums");
var _createDestructor = _interopRequireDefault(require("../createDestructor"));
var _createLogger = _interopRequireDefault(require("../createLogger"));
var _getOriginFromSrc = _interopRequireDefault(require("./getOriginFromSrc"));
var _handleAckMessageFactory = _interopRequireDefault(require("./handleAckMessageFactory"));
var _handleSynMessageFactory = _interopRequireDefault(require("./handleSynMessageFactory"));
var _methodSerialization = require("../methodSerialization");
var _monitorIframeRemoval = _interopRequireDefault(require("./monitorIframeRemoval"));
var _startConnectionTimeout = _interopRequireDefault(require("../startConnectionTimeout"));
var _validateIframeHasSrcOrSrcDoc = _interopRequireDefault(require("./validateIframeHasSrcOrSrcDoc"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Attempts to establish communication with an iframe.
*/
var _default = options => {
let {
iframe,
methods = {},
childOrigin,
timeout,
debug = false
} = options;
const log = (0, _createLogger.default)(debug);
const destructor = (0, _createDestructor.default)('Parent', log);
const {
onDestroy,
destroy
} = destructor;
if (!childOrigin) {
(0, _validateIframeHasSrcOrSrcDoc.default)(iframe);
childOrigin = (0, _getOriginFromSrc.default)(iframe.src);
} // If event.origin is "null", the remote protocol is file: or data: and we
// must post messages with "*" as targetOrigin when sending messages.
// https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Using_window.postMessage_in_extensions
const originForSending = childOrigin === 'null' ? '*' : childOrigin;
const serializedMethods = (0, _methodSerialization.serializeMethods)(methods);
const handleSynMessage = (0, _handleSynMessageFactory.default)(log, serializedMethods, childOrigin, originForSending);
const handleAckMessage = (0, _handleAckMessageFactory.default)(serializedMethods, childOrigin, originForSending, destructor, log);
const promise = new Promise((resolve, reject) => {
const stopConnectionTimeout = (0, _startConnectionTimeout.default)(timeout, destroy);
const handleMessage = event => {
if (event.source !== iframe.contentWindow || !event.data) {
return;
}
if (event.data.penpal === _enums.MessageType.Syn) {
handleSynMessage(event);
return;
}
if (event.data.penpal === _enums.MessageType.Ack) {
const callSender = handleAckMessage(event);
if (callSender) {
stopConnectionTimeout();
resolve(callSender);
}
return;
}
};
window.addEventListener(_enums.NativeEventType.Message, handleMessage);
log('Parent: Awaiting handshake');
(0, _monitorIframeRemoval.default)(iframe, destructor);
onDestroy(error => {
window.removeEventListener(_enums.NativeEventType.Message, handleMessage);
if (error) {
reject(error);
}
});
});
return {
promise,
destroy() {
// Don't allow consumer to pass an error into destroy.
destroy();
}
};
};
exports.default = _default;
;