UNPKG

@agnostack/next-shopify

Version:

Please contact agnoStack via info@agnostack.com for any questions

124 lines • 7.61 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAuthErrorResponse = exports.getCallback = exports.getPrepareWebhookHandlers = exports.getInitializedShopify = exports.allowLocalBypass = exports.getSecurityHeader = void 0; const chalk_1 = __importDefault(require("chalk")); require("@shopify/shopify-api/adapters/node"); const shopify_api_1 = require("@shopify/shopify-api"); const shared_1 = require("../../shared"); const VALID_WEBHOOK_TOPICS = Object.keys(shared_1.API_WEBHOOK_TOPICS); // NOTE rejection response shows accepted value is "frame-ancestors https://admin.shopify.com https://[shop].myshopify.com" const getSecurityHeader = (shop, { isEmbeddedApp } = {}) => (((0, shared_1.stringNotEmpty)(shop) && (0, shared_1.isTrue)(isEmbeddedApp)) ? `frame-ancestors https://${encodeURIComponent(shop)} https://admin.shopify.com;` : "frame-ancestors 'none';"); exports.getSecurityHeader = getSecurityHeader; // NOTE: this should handle running in next to test non-shopify functionality const allowLocalBypass = ({ SHOPIFY_RUN_MODE, APP_CONFIG } = {}) => ((SHOPIFY_RUN_MODE !== 'cli') && (!APP_CONFIG.apiSecretKey || !APP_CONFIG.hostName || !APP_CONFIG.apiKey || !APP_CONFIG.scopes)); exports.allowLocalBypass = allowLocalBypass; const getInitializedShopify = (serverRuntimeConfig) => { // NOTE: this should handle running in next to test non-shopify functionality const shouldBypassProtect = (0, exports.allowLocalBypass)(serverRuntimeConfig); if (shouldBypassProtect) { console.info(`${chalk_1.default.yellowBright('next-shopify')} - [${chalk_1.default.bold('getInitializedShopify')}]: ${`Bypassing local protect - should ONLY happen when running in next to test non-shopify functionality!`}`); return undefined; } return (0, shopify_api_1.shopifyApi)(serverRuntimeConfig.APP_CONFIG); }; exports.getInitializedShopify = getInitializedShopify; const getPrepareWebhookHandlers = (serverRuntimeConfig) => { const { APP_WEBHOOKS, APP_WEBHOOKS_MUTABLE_TOPICS } = serverRuntimeConfig; return (params) => (Object.entries((0, shared_1.ensureObject)(APP_WEBHOOKS)).reduce((_webhookHandlers, [webhookTopic, webhooks]) => { var _a; if (!VALID_WEBHOOK_TOPICS.includes(webhookTopic)) { console.warn(`Ignoring unsupported webhook topic: ${webhookTopic}`); return _webhookHandlers; } if ((((_a = APP_WEBHOOKS_MUTABLE_TOPICS === null || APP_WEBHOOKS_MUTABLE_TOPICS === void 0 ? void 0 : APP_WEBHOOKS_MUTABLE_TOPICS[webhookTopic]) === null || _a === void 0 ? void 0 : _a.enabled) != undefined) && !(0, shared_1.isTrue)(APP_WEBHOOKS_MUTABLE_TOPICS[webhookTopic].enabled)) { console.warn(`Ignoring disabled webhook topic: ${webhookTopic}`); return _webhookHandlers; } const queryString = new URLSearchParams(params).toString(); return Object.assign(Object.assign({}, _webhookHandlers), { [webhookTopic]: (0, shared_1.ensureArray)(webhooks).reduce((_topicWebhooks, _a) => { var { url, path, callback: _callback, callbackUrl: _callbackUrl, deliveryMethod = shopify_api_1.DeliveryMethod.Http } = _a, // NOTE: this lets us support more advanced webhook types (EventBridgeWebhookHandler or PubSubWebhookHandler) webhookConfig = __rest(_a, ["url", "path", "callback", "callbackUrl", "deliveryMethod"]); const callbackUrl = (0, shared_1.appendQuery)(_callbackUrl || url || path, queryString); console.info(`${chalk_1.default.yellowBright('next-shopify')} - [${chalk_1.default.bold(webhookTopic)}]: ${`Adding webhook handler [${deliveryMethod}]${callbackUrl ? ` using callbackUrl: ${callbackUrl}` : ''}.`}`); return [ ..._topicWebhooks, Object.assign(Object.assign(Object.assign({ deliveryMethod }, webhookConfig), callbackUrl && { callbackUrl }), (callbackUrl || _callback) && { callback: (topic, shop, rawBody, webhookId, ...params) => __awaiter(void 0, void 0, void 0, function* () { if (_callback) { console.log(`Webhook callback for ${shop}:${topic}:${webhookId}`); return _callback(topic, shop, rawBody, webhookId, ...params); } return true; }), }) ]; }, []) }); }, {})); }; exports.getPrepareWebhookHandlers = getPrepareWebhookHandlers; const getCallback = (data, { reAuth, isOnline }) => { const authCallbacks = reAuth ? { online: data[shared_1.API_ROUTE_NAMES.AUTH_ONLINE_CALLBACK_REAUTH], offline: data[shared_1.API_ROUTE_NAMES.AUTH_OFFLINE_CALLBACK_REAUTH], } : { online: data[shared_1.API_ROUTE_NAMES.AUTH_ONLINE_CALLBACK], offline: data[shared_1.API_ROUTE_NAMES.AUTH_OFFLINE_CALLBACK], }; return isOnline ? authCallbacks.online : authCallbacks.offline || authCallbacks.online; }; exports.getCallback = getCallback; const getAuthErrorResponse = (serverRuntimeConfig, { error }) => { const { message, data } = error; const { PAGE_PATHS } = serverRuntimeConfig; // TODO determine appropriate url in case of an error const reauthorizationUrl = (data === null || data === void 0 ? void 0 : data.redirectUrl) || `${PAGE_PATHS[shared_1.PAGE_ROUTE_NAMES.ERROR]}`; // NOTE: old example code below // const { API_URLS } = serverRuntimeConfig // const queryParams = new URLSearchParams({ // shop, // reAuth: (error instanceof ShopifySessionAuthenticationError), // }).toString() // const reauthorizationUrl = data?.redirectUrl || `${API_URLS[API_ROUTE_NAMES.AUTH_ONLINE]}?${queryParams}` // HMMMMM: do we not need host here?? return { statusCode: 403, message, headers: { 'X-Shopify-API-Request-Failure-Reauthorize': '1', // TODO: what about cyclical loop on bad auth?? 'X-Shopify-API-Request-Failure-Reauthorize-Url': reauthorizationUrl, }, }; }; exports.getAuthErrorResponse = getAuthErrorResponse; //# sourceMappingURL=shopify.js.map