UNPKG

8.63 kBJavaScriptView Raw
1"use strict";
2var __assign = (this && this.__assign) || function () {
3 __assign = Object.assign || function(t) {
4 for (var s, i = 1, n = arguments.length; i < n; i++) {
5 s = arguments[i];
6 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7 t[p] = s[p];
8 }
9 return t;
10 };
11 return __assign.apply(this, arguments);
12};
13var __importDefault = (this && this.__importDefault) || function (mod) {
14 return (mod && mod.__esModule) ? mod : { "default": mod };
15};
16Object.defineProperty(exports, "__esModule", { value: true });
17exports.createApp = exports.createAppWrapper = exports.createClientApp = exports.WINDOW_UNDEFINED_MESSAGE = void 0;
18var helper_1 = require("../actions/helper");
19var Print_1 = require("../actions/Print");
20var Error_1 = require("../actions/Error");
21var MessageTransport_1 = require("../MessageTransport");
22var shared_1 = require("../util/shared");
23var env_1 = require("../util/env");
24var Client_1 = require("../actions/Client");
25var print_1 = require("./print");
26var redirect_1 = require("./redirect");
27var types_1 = require("./types");
28var Hooks_1 = __importDefault(require("./Hooks"));
29exports.WINDOW_UNDEFINED_MESSAGE = 'window is not defined. Running an app outside a browser is not supported';
30function redirectHandler(hostFrame, config) {
31 var apiKey = config.apiKey, host = config.host, _a = config.forceRedirect, forceRedirect = _a === void 0 ? !env_1.isDevelopmentClient : _a;
32 var location = redirect_1.getLocation();
33 if (env_1.isFrameless ||
34 !location ||
35 !apiKey ||
36 !host ||
37 !forceRedirect ||
38 !redirect_1.shouldRedirect(hostFrame)) {
39 return;
40 }
41 var url = "https://" + host + "/apps/" + apiKey + location.pathname + (location.search || '');
42 redirect_1.redirect(url);
43}
44function appSetUp(app) {
45 app.subscribe(Print_1.Action.APP, print_1.handleAppPrint);
46 app.dispatch(Client_1.initialize());
47}
48/**
49 * @internal
50 */
51exports.createClientApp = function (transport, middlewares) {
52 if (middlewares === void 0) { middlewares = []; }
53 var getStateListeners = [];
54 var transportListener = MessageTransport_1.createTransportListener();
55 var handler = function (event) {
56 var message = event.data;
57 var type = message.type, payload = message.payload;
58 switch (type) {
59 case 'getState':
60 var resolvers = getStateListeners.splice(0);
61 resolvers.forEach(function (resolver) { return resolver(payload); });
62 break;
63 case 'dispatch':
64 transportListener.handleMessage(payload);
65 var hasCallback = transportListener.handleActionDispatch(payload);
66 if (hasCallback) {
67 return;
68 }
69 // Throw an error if there are no subscriptions to this error
70 var errorType = helper_1.findMatchInEnum(Error_1.Action, payload.type);
71 if (errorType) {
72 Error_1.throwError(errorType, payload);
73 }
74 break;
75 default:
76 // Silently swallow unknown actions
77 }
78 };
79 transport.subscribe(handler);
80 return function (config) {
81 if (!config.host) {
82 throw Error_1.fromAction('host must be provided', Error_1.AppActionType.INVALID_CONFIG);
83 }
84 if (!config.apiKey) {
85 throw Error_1.fromAction('apiKey must be provided', Error_1.AppActionType.INVALID_CONFIG);
86 }
87 var decodedConfig;
88 try {
89 decodedConfig = decodeConfig(config);
90 }
91 catch (_a) {
92 var message = "not a valid host, please use the value provided by Shopify";
93 throw Error_1.fromAction(message, Error_1.AppActionType.INVALID_CONFIG);
94 }
95 var dispatcher = createDispatcher(transport, decodedConfig);
96 var subscribe = transportListener.createSubscribeHandler(dispatcher);
97 // It is possible to initialize an app multiple times
98 // Therefore we need to clear subscriptions to be safe
99 dispatcher(types_1.MessageType.Unsubscribe);
100 function dispatch(action) {
101 dispatcher(types_1.MessageType.Dispatch, action);
102 return action;
103 }
104 redirectHandler(transport.hostFrame, decodedConfig);
105 var hooks = new Hooks_1.default();
106 var app = {
107 localOrigin: transport.localOrigin,
108 hooks: hooks,
109 dispatch: function (action) {
110 if (!app.hooks) {
111 return dispatch(action);
112 }
113 return app.hooks.run(types_1.LifecycleHook.DispatchAction, dispatch, app, action);
114 },
115 featuresAvailable: function (features) {
116 return app.getState('features').then(function (state) {
117 if (features) {
118 Object.keys(state).forEach(function (feature) {
119 if (!features.includes(feature)) {
120 delete state[feature];
121 }
122 });
123 }
124 return state;
125 });
126 },
127 getState: function (query) {
128 return new Promise(function (resolve) {
129 getStateListeners.push(resolve);
130 dispatcher(types_1.MessageType.GetState);
131 }).then(function (state) {
132 if (query) {
133 return query.split('.').reduce(function (value, key) {
134 if (typeof state !== 'object' || Array.isArray(state)) {
135 return undefined;
136 }
137 value = state[key];
138 state = value;
139 return value;
140 }, undefined);
141 }
142 return state;
143 });
144 },
145 subscribe: subscribe,
146 error: function (listener, id) {
147 var unsubscribeCb = [];
148 helper_1.forEachInEnum(Error_1.Action, function (eventNameSpace) {
149 unsubscribeCb.push(subscribe(eventNameSpace, listener, id));
150 });
151 return function () {
152 unsubscribeCb.forEach(function (unsubscribe) { return unsubscribe(); });
153 };
154 },
155 };
156 for (var _i = 0, middlewares_1 = middlewares; _i < middlewares_1.length; _i++) {
157 var middleware = middlewares_1[_i];
158 middleware(hooks, app);
159 }
160 appSetUp(app);
161 return app;
162 };
163};
164/**
165 * @internal
166 */
167function decodeConfig(config) {
168 var _a;
169 return __assign(__assign({}, config), { host: atob((_a = config.host) === null || _a === void 0 ? void 0 : _a.replace(/_/g, '/').replace(/-/g, '+')) });
170}
171/**
172 * @public
173 */
174function createAppWrapper(frame, localOrigin, middleware) {
175 if (middleware === void 0) { middleware = []; }
176 if (!frame) {
177 throw Error_1.fromAction(exports.WINDOW_UNDEFINED_MESSAGE, Error_1.AppActionType.WINDOW_UNDEFINED);
178 }
179 var location = redirect_1.getLocation();
180 var origin = localOrigin || (location && location.origin);
181 if (!origin) {
182 throw Error_1.fromAction('local origin cannot be blank', Error_1.AppActionType.MISSING_LOCAL_ORIGIN);
183 }
184 var transport = MessageTransport_1.fromWindow(frame, origin);
185 var appCreator = exports.createClientApp(transport, middleware);
186 return appCreator;
187}
188exports.createAppWrapper = createAppWrapper;
189/**
190 * Creates your application instance.
191 * @param config - `apiKey` and `host` are both required.
192 * @remarks
193 * 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}.
194 * @public
195 */
196function createApp(config) {
197 var currentWindow = redirect_1.getWindow();
198 if (!currentWindow) {
199 return shared_1.serverAppBridge;
200 }
201 return createAppWrapper(currentWindow.top)(config);
202}
203exports.createApp = createApp;
204function createDispatcher(transport, config) {
205 return function (type, payload) {
206 transport.dispatch({
207 payload: payload,
208 source: config,
209 type: type,
210 });
211 };
212}
213/**
214 * {@inheritdocs createApp}
215 * @public
216 */
217exports.default = createApp;