UNPKG

@shopify/app-bridge

Version:

**Shopify is doubling our engineering staff in 2021! [Join our team and work on libraries like this one.](https://smrtr.io/5GGrc)**

216 lines (215 loc) 8.69 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); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createApp = exports.createAppWrapper = exports.createClientApp = exports.WINDOW_UNDEFINED_MESSAGE = void 0; var helper_1 = require("../actions/helper"); var Print_1 = require("../actions/Print"); var Error_1 = require("../actions/Error"); var MessageTransport_1 = require("../MessageTransport"); var shared_1 = require("../util/shared"); var env_1 = require("../util/env"); var Client_1 = require("../actions/Client"); var print_1 = require("./print"); var redirect_1 = require("./redirect"); var types_1 = require("./types"); var Hooks_1 = __importDefault(require("./Hooks")); exports.WINDOW_UNDEFINED_MESSAGE = 'window is not defined. Running an app outside a browser is not supported'; function redirectHandler(hostFrame, config) { var apiKey = config.apiKey, host = config.host, _a = config.forceRedirect, forceRedirect = _a === void 0 ? !env_1.isDevelopmentClient : _a; var location = redirect_1.getLocation(); if (env_1.isUnframed || !location || !apiKey || !host || !forceRedirect || !redirect_1.shouldRedirect(hostFrame)) { return; } var url = "https://" + host + "/apps/" + apiKey + location.pathname + (location.search || ''); redirect_1.redirect(url); } function appSetUp(app) { app.subscribe(Print_1.Action.APP, print_1.handleAppPrint); app.dispatch(Client_1.initialize()); } /** * @internal */ exports.createClientApp = function (transport, middlewares) { if (middlewares === void 0) { middlewares = []; } var getStateListeners = []; var transportListener = MessageTransport_1.createTransportListener(); var handler = function (event) { var message = event.data; var type = message.type, payload = message.payload; switch (type) { case 'getState': { var resolvers = getStateListeners.splice(0); resolvers.forEach(function (resolver) { return resolver(payload); }); break; } case 'dispatch': { transportListener.handleMessage(payload); var hasCallback = transportListener.handleActionDispatch(payload); if (hasCallback) { return; } // Throw an error if there are no subscriptions to this error var errorType = helper_1.findMatchInEnum(Error_1.Action, payload.type); if (errorType) { Error_1.throwError(errorType, payload); } break; } default: // Silently swallow unknown actions } }; transport.subscribe(handler); return function (config) { if (!config.host) { throw Error_1.fromAction('host must be provided', Error_1.AppActionType.INVALID_CONFIG); } if (!config.apiKey) { throw Error_1.fromAction('apiKey must be provided', Error_1.AppActionType.INVALID_CONFIG); } var decodedConfig; try { decodedConfig = decodeConfig(config); } catch (_a) { var message = "not a valid host, please use the value provided by Shopify"; throw Error_1.fromAction(message, Error_1.AppActionType.INVALID_CONFIG); } var dispatcher = createDispatcher(transport, decodedConfig); var subscribe = transportListener.createSubscribeHandler(dispatcher); // It is possible to initialize an app multiple times // Therefore we need to clear subscriptions to be safe dispatcher(types_1.MessageType.Unsubscribe); function dispatch(action) { dispatcher(types_1.MessageType.Dispatch, action); return action; } redirectHandler(transport.hostFrame, decodedConfig); var hooks = new Hooks_1.default(); var app = { localOrigin: transport.localOrigin, hooks: hooks, dispatch: function (action) { if (!app.hooks) { return dispatch(action); } return app.hooks.run(types_1.LifecycleHook.DispatchAction, dispatch, app, action); }, featuresAvailable: function (features) { return app.getState('features').then(function (state) { if (features) { Object.keys(state).forEach(function (feature) { if (!features.includes(feature)) { delete state[feature]; } }); } return state; }); }, getState: function (query) { return new Promise(function (resolve) { getStateListeners.push(resolve); dispatcher(types_1.MessageType.GetState); }).then(function (state) { var newState = state; if (query) { return query.split('.').reduce(function (_, key) { if (typeof state !== 'object' || Array.isArray(state)) { return undefined; } var stateValue = state[key]; newState = state[key]; return stateValue; }, undefined); } return newState; }); }, subscribe: subscribe, error: function (listener, id) { var unsubscribeCb = []; helper_1.forEachInEnum(Error_1.Action, function (eventNameSpace) { unsubscribeCb.push(subscribe(eventNameSpace, listener, id)); }); return function () { unsubscribeCb.forEach(function (unsubscribe) { return unsubscribe(); }); }; }, }; for (var _i = 0, middlewares_1 = middlewares; _i < middlewares_1.length; _i++) { var middleware = middlewares_1[_i]; middleware(hooks, app); } appSetUp(app); return app; }; }; /** * @internal */ function decodeConfig(config) { var _a; return __assign(__assign({}, config), { host: atob((_a = config.host) === null || _a === void 0 ? void 0 : _a.replace(/_/g, '/').replace(/-/g, '+')) }); } /** * @public */ function createAppWrapper(frame, localOrigin, middleware) { if (middleware === void 0) { middleware = []; } if (!frame) { throw Error_1.fromAction(exports.WINDOW_UNDEFINED_MESSAGE, Error_1.AppActionType.WINDOW_UNDEFINED); } var location = redirect_1.getLocation(); var origin = localOrigin || (location && location.origin); if (!origin) { throw Error_1.fromAction('local origin cannot be blank', Error_1.AppActionType.MISSING_LOCAL_ORIGIN); } var transport = MessageTransport_1.fromWindow(frame, origin); var appCreator = exports.createClientApp(transport, middleware); return appCreator; } exports.createAppWrapper = createAppWrapper; /** * Creates your application instance. * @param config - `apiKey` and `host` are both required. * @remarks * You will need to store `host` during the authentication process and then retrieve it for the code to work properly. To learn more about this process, see {@link https://help.shopify.com/api/embedded-apps/shop-origin | Getting and storing the shop origin}. * @public */ function createApp(config) { var currentWindow = redirect_1.getWindow(); if (!currentWindow) { return shared_1.serverAppBridge; } return createAppWrapper(currentWindow.top)(config); } exports.createApp = createApp; function createDispatcher(transport, config) { return function (type, payload) { transport.dispatch({ payload: payload, source: config, type: type, }); }; } /** * {@inheritdocs createApp} * @public */ exports.default = createApp;