UNPKG

@shopify/app-bridge-core

Version:

**[Join our team and work on libraries like this one.](https://www.shopify.ca/careers)**

201 lines (200 loc) 7.91 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Context = void 0; exports.fromFrame = fromFrame; exports.fromWindow = fromWindow; exports.createTransportListener = createTransportListener; var Error_1 = require("./actions/Error"); var validator_1 = require("./actions/validator"); var types_1 = require("./client/types"); var collection_1 = require("./util/collection"); var env_1 = require("./util/env"); var Context; (function (Context) { Context["Modal"] = "Modal"; Context["Main"] = "Main"; })(Context || (exports.Context = Context = {})); /** * Create a MessageTransport from a Frame. * @remarks * Used on the host-side to create a postMessage MessageTransport. * @beta */ function fromFrame(frame, localOrigin, context) { var handlers = []; var host = frame.host, frameWindow = frame.window; if (!host) { throw (0, Error_1.fromAction)('App frame is undefined', Error_1.AppActionType.WINDOW_UNDEFINED); } if (env_1.isUnframed && window.MobileWebView) { Object.assign(window.MobileWebView, { postMessageToIframe: function (message, origin) { frameWindow === null || frameWindow === void 0 ? void 0 : frameWindow.postMessage(message, origin); if (isDispatchAction(message)) { host.postMessage(JSON.stringify(message.payload), location.origin); } }, updateIframeUrl: function (newUrl) { var currentWindowLocation = window.location; var frameWindowLocation = (frame.window || {}).location; try { var newUrlOrigin = new URL(newUrl).origin; if (newUrlOrigin === localOrigin && frameWindowLocation) { frameWindowLocation.replace(newUrl); } else { currentWindowLocation.href = newUrl; } } catch (_) { // Noop } }, }); } host.addEventListener('message', function (event) { if (event.source === host || !(0, validator_1.isAppMessage)(event)) { return; } if (event.origin !== localOrigin) { var errorMessage = "Message origin '".concat(event.origin, "' does not match app origin '").concat(localOrigin, "'."); var payload = (0, Error_1.invalidOriginAction)(errorMessage); var message = { type: 'dispatch', payload: payload, }; frameWindow === null || frameWindow === void 0 ? void 0 : frameWindow.postMessage(message, event.origin); return; } if (env_1.isUnframed && window.MobileWebView) { var payload = JSON.stringify({ id: 'unframed://fromClient', origin: localOrigin, data: event.data, }); window.MobileWebView.postMessage(payload); return; } for (var _i = 0, handlers_1 = handlers; _i < handlers_1.length; _i++) { var handler = handlers_1[_i]; handler(event); } }); return { context: context, localOrigin: localOrigin, frameWindow: frameWindow, hostFrame: host, dispatch: function (message) { frameWindow === null || frameWindow === void 0 ? void 0 : frameWindow.postMessage(message, localOrigin); }, subscribe: function (handler) { return (0, collection_1.addAndRemoveFromCollection)(handlers, handler); }, }; } /** * Create a MessageTransport from a parent window. * @remarks * Used on the client-side to create a postMessage MessageTransport. * @internalremarks * In unframed mode, message should be dispatched via MobileWebView.postMessage instead of postMessage. * @beta */ function fromWindow(contentWindow, localOrigin) { var handlers = []; if (typeof window !== undefined) { window.addEventListener('message', function (event) { if ((window === contentWindow && !env_1.isUnframed) || event.source !== contentWindow || !((0, validator_1.isAppBridgeAction)(event.data.payload) || (0, validator_1.isAppMessage)(event))) { return; } for (var _i = 0, handlers_2 = handlers; _i < handlers_2.length; _i++) { var handler = handlers_2[_i]; handler(event); } }); } return { localOrigin: localOrigin, hostFrame: contentWindow, dispatch: function (message) { var _a; if (!((_a = message.source) === null || _a === void 0 ? void 0 : _a.host)) { return; } if (env_1.isUnframed && window && window.MobileWebView) { var payload = JSON.stringify({ id: 'unframed://fromClient', origin: localOrigin, data: message, }); window.MobileWebView.postMessage(payload); return; } var messageOrigin = new URL("https://".concat(message.source.host)).origin; contentWindow.postMessage(message, messageOrigin); }, subscribe: function (handler) { return (0, collection_1.addAndRemoveFromCollection)(handlers, handler); }, }; } function createTransportListener() { var listeners = []; var actionListeners = {}; function createSubscribeHandler(dispatcher) { function subscribe() { if (arguments.length < 2) { // eslint-disable-next-line prefer-rest-params return (0, collection_1.addAndRemoveFromCollection)(listeners, { callback: arguments[0] }); } // eslint-disable-next-line prefer-rest-params var _a = Array.from(arguments), type = _a[0], callback = _a[1], id = _a[2]; var actionCallback = { callback: callback, id: id }; var payload = { type: type, id: id }; if (!Object.prototype.hasOwnProperty.call(actionListeners, type)) { actionListeners[type] = []; } if (dispatcher) { dispatcher(types_1.MessageType.Subscribe, payload); } return (0, collection_1.addAndRemoveFromCollection)(actionListeners[type], actionCallback, function () { if (dispatcher) { dispatcher(types_1.MessageType.Unsubscribe, payload); } }); } return subscribe; } return { createSubscribeHandler: createSubscribeHandler, handleMessage: function (message) { listeners.forEach(function (listener) { return listener.callback(message); }); }, handleActionDispatch: function (_a) { var type = _a.type, payload = _a.payload; var hasCallback = false; if (Object.prototype.hasOwnProperty.call(actionListeners, type)) { for (var _i = 0, _b = actionListeners[type]; _i < _b.length; _i++) { var listener = _b[_i]; var id = listener.id, callback = listener.callback; var matchId = payload && payload.id === id; if (matchId || !id) { callback(payload); hasCallback = true; } } } return hasCallback; }, }; } function isDispatchAction(message) { return (message !== null && typeof message === 'object' && !Array.isArray(message) && message.type === 'dispatch' && typeof message.payload === 'object'); }