UNPKG

@shopify/app-bridge-host

Version:

App Bridge Host contains middleware and components that are meant to be consumed by the app's host. The middleware and `Frame` component are responsible for facilitating messages posted between the client and host, and used to act on actions sent from the

173 lines (172 loc) 7.88 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); var app_bridge_1 = require("@shopify/app-bridge"); var validator_1 = require("@shopify/app-bridge/actions/validator"); var Error_1 = require("@shopify/app-bridge/actions/Error"); var collection_1 = require("@shopify/app-bridge/util/collection"); var actions_1 = require("./actions"); var clientValidator_1 = require("./clientValidator"); function buildMiddleware(key, dispatchClientEventHandler) { var transports = []; var subscribers = []; var store; var middleware = function (hostStore) { store = hostStore; return function (next) { return function (action) { if (validator_1.isAppBridgeAction(action)) { for (var _i = 0, transports_1 = transports; _i < transports_1.length; _i++) { var transport = transports_1[_i]; var features = store.getState()[key].features[transport.context]; if (validator_1.isPermitted(features, action, app_bridge_1.PermissionType.Subscribe)) { transport.dispatch({ payload: action, type: 'dispatch', }); } } } return next(action); }; }; }; middleware.load = function provideApplicationInterface(data) { var config = data.config; var clientHandlers = createClientHandlers(); store.dispatch(actions_1.apiClientLoad(config)); return { attach: function (to) { var _this = this; var contextualClientHandlers = clientHandlers[to.context]; contextualClientHandlers.unsubscribe(); var unsubscribe = to.subscribe(function (event) { var context = to.context; var action = event.data; var type = action && action.type; var payload = action && action.payload; var source = action && action.source; if (!clientValidator_1.isValidConfig(source, config)) { clientValidator_1.throwInvalidConfigError(source, config, payload); } if (to.frameWindow !== event.source) { return; } for (var _i = 0, subscribers_1 = subscribers; _i < subscribers_1.length; _i++) { var listener = subscribers_1[_i]; listener(action); } switch (type) { case 'dispatch': var features = _this.getState().features[context]; if (!validator_1.isPermitted(features, payload, app_bridge_1.PermissionType.Dispatch)) { store.dispatch(Error_1.permissionAction(payload)); return; } store.dispatch(__assign({}, payload, { source: source })); if (dispatchClientEventHandler) { var appId = config.appId, shopId = config.shopId; dispatchClientEventHandler({ action: payload, appId: appId, shopId: shopId, }); } break; case 'getState': var defaultState = _this.getState(); var state = __assign({}, defaultState, { features: defaultState.features[context], context: context }); to.dispatch({ type: type, payload: state, }); break; case 'subscribe': contextualClientHandlers.subscribe(payload); break; case 'unsubscribe': contextualClientHandlers.unsubscribe(payload); break; default: Error_1.throwError(Error_1.ActionType.INVALID_ACTION, action, 'Unknown action type. Expected `dispatch` or `getState`.'); } }); var detach = collection_1.addAndRemoveFromCollection(transports, to, unsubscribe); return function (unload) { if (unload === void 0) { unload = true; } var origin = new URL(config.url).origin; var removed = detach() && !transports.find(function (transport) { return transport.localOrigin === origin; }); contextualClientHandlers.unsubscribe(); if (removed && unload) { store.dispatch(actions_1.apiClientUnload(config)); } }; }, dispatch: function (action) { store.dispatch(action); }, getState: function () { return store.getState()[key]; }, subscribe: function (listener) { return collection_1.addAndRemoveFromCollection(subscribers, listener); }, isTransportSubscribed: function (context, type, id) { return clientHandlers[context].isSubscribed(type, id); }, }; }; return middleware; } exports.buildMiddleware = buildMiddleware; function createClientHandlers() { var _a, _b; var subscriptions = (_a = {}, _a[app_bridge_1.Context.Main] = {}, _a[app_bridge_1.Context.Modal] = {}, _a); return _b = {}, _b[app_bridge_1.Context.Main] = createSubscriptionsHandler(subscriptions[app_bridge_1.Context.Main]), _b[app_bridge_1.Context.Modal] = createSubscriptionsHandler(subscriptions[app_bridge_1.Context.Modal]), _b; } function createSubscriptionsHandler(subscriptions) { return { isSubscribed: function (type, id) { var contextSubscribers = subscriptions[type] || []; var subscribers = contextSubscribers.filter(function (sub) { return sub.id === id; }); return subscribers.length > 0; }, subscribe: function (payload) { var type = payload.type; if (!subscriptions[type]) { subscriptions[type] = []; } var eventSubscriptions = subscriptions[type] || []; collection_1.addAndRemoveFromCollection(eventSubscriptions, payload); }, unsubscribe: function (payload) { if (!payload) { subscriptions = {}; return; } var type = payload.type, id = payload.id; var eventSubscriptions = subscriptions[type]; if (!eventSubscriptions) { return; } if (id) { var index = eventSubscriptions.findIndex(function (sub) { return sub.id === id; }); if (index >= 0) { return eventSubscriptions.splice(index); } } eventSubscriptions.pop(); }, }; }