UNPKG

@agnostack/next-shopify

Version:

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

159 lines • 9.58 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()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.handleCallback = void 0; const shopify_api_1 = require("@shopify/shopify-api"); const utils_1 = require("../../utils"); const shared_1 = require("../../../shared"); /* NOTE: typically handling: * "/api/auth/online/callback" * "/api/auth/offline/callback" * "/api/auth/online/callback/reauth" * "/api/auth/offline/callback/reauth" */ // TODO: delete this for legacy auth const handleCallback = (serverRuntimeConfig, data) => { const { API_PATHS, PAGE_PATHS, PAYMENT_CONFIG, } = serverRuntimeConfig; const { returnResponse = true } = data !== null && data !== void 0 ? data : {}; const prepareWebhookHandlers = (0, utils_1.getPrepareWebhookHandlers)(serverRuntimeConfig); return (req, res, params) => __awaiter(void 0, void 0, void 0, function* () { var _a, _b; const errorPath = PAGE_PATHS[shared_1.PAGE_ROUTE_NAMES.ERROR]; const { isOnline, reAuth } = params !== null && params !== void 0 ? params : {}; const { shop, host, state } = (_a = req.query) !== null && _a !== void 0 ? _a : {}; const authPayload = { rawRequest: req, rawResponse: res }; const handleResponse = (body, statusCode = 307) => { if (returnResponse) { return res.redirect(statusCode, body); } return { statusCode, body }; }; if ((0, shared_1.stringEmpty)(shop) || (0, shared_1.stringEmpty)(host)) { // HMMM: why is this a 303 (rather than a 302/307 or or anything)?? return handleResponse(`${errorPath}?code=${shared_1.ERROR_CODES.INVALID_CALLBACK}`, 303); } let redirectUrl = `${errorPath}?code=invalid_callback_response`; let shopify; try { const { shopify: _shopify, loadAppData, storeSession: encryptStoreSession, ensureBilling: handleEnsureBilling, } = yield (0, utils_1.getShopifyHelpers)(serverRuntimeConfig, { shop }); shopify = _shopify; const { session: _session } = yield shopify.auth.callback(authPayload); const session = _session === null || _session === void 0 ? void 0 : _session.toObject(); const offlineAuthRoute = API_PATHS[shared_1.API_ROUTE_NAMES.AUTH_OFFLINE]; const shouldProcessOfflineAuth = (isOnline && offlineAuthRoute); const shouldRegisterWebhooks = (!(0, shared_1.isTrue)(session === null || session === void 0 ? void 0 : session.isOnline) || !offlineAuthRoute); const shouldCheckBilling = PAYMENT_CONFIG === null || PAYMENT_CONFIG === void 0 ? void 0 : PAYMENT_CONFIG.required; // NOTE: handleEnsureBilling below handles calling encryptStoreSession for offline session when shouldCheckBilling if (isOnline || !shouldCheckBilling) { yield encryptStoreSession(session); } // NOTE: return early to process offline auth & callback (as webhooks cannot use the online one to make API calls) if (shouldProcessOfflineAuth) { // TODO: explore objectToQuerystring const queryParams = new URLSearchParams({ host, shop, state, reAuth, isOnline: false }).toString(); return handleResponse(`${offlineAuthRoute}?${queryParams}`); } if (shouldRegisterWebhooks) { let appId; try { const { appInfo } = yield loadAppData(); appId = (0, utils_1.normalizeShopifyId)(appInfo === null || appInfo === void 0 ? void 0 : appInfo.id).id; // eslint-disable-next-line no-empty } catch (_ignore) { console.info('Ignoring error loading appData', _ignore); } const webhookHandlers = prepareWebhookHandlers({ appId }); shopify.webhooks.addHandlers(webhookHandlers); // NOTE: webhooks cannot use an online session to make API calls to Shopify (but not all webooks may be doing that for all apps) yield shopify.webhooks.register({ session }); } const embeddedAppUrl = yield shopify.auth.getEmbeddedAppUrl(authPayload); // NOTE this is the final/successful return URL redirectUrl = `${embeddedAppUrl}${(0, shared_1.ensureLeadingSlash)(PAGE_PATHS[shared_1.PAGE_ROUTE_NAMES.SUCCESS])}`; if (shouldCheckBilling) { // NOTE: handleEnsureBilling handles calling encryptStoreSession for offline session when shouldCheckBilling const confirmationUrl = yield handleEnsureBilling(session, { reAuth }); if ((0, shared_1.stringNotEmpty)(confirmationUrl)) { redirectUrl = confirmationUrl; } } // NOTE confirm that state can be appended to the confirmationUrl, // otherwise we can append to the redirectUrl above the billing check redirectUrl = (0, shared_1.appendQuery)(redirectUrl, new URLSearchParams({ state }).toString()); } catch (error) { console.error('Error handling callback route', error); const errorMessage = 'Error handling callback route'; let baseErrorUrl = errorPath; if (shopify) { try { const embeddedAppUrl = yield shopify.auth.getEmbeddedAppUrl(authPayload); if ((0, shared_1.stringNotEmpty)(embeddedAppUrl)) { baseErrorUrl = `${embeddedAppUrl}${(0, shared_1.ensureLeadingSlash)(errorPath)}`; } // eslint-disable-next-line no-empty } catch (_ignore) { } } switch (true) { // TODO implement a custom SessionNotFound error case error instanceof shopify_api_1.InvalidHmacError: { console.warn(`${errorMessage}. InvalidHmac Error ${error.message}`); // HMMMM: not sure const authOnlinePath = API_PATHS[shared_1.API_ROUTE_NAMES.AUTH_ONLINE]; const authPath = isOnline ? authOnlinePath : API_PATHS[shared_1.API_ROUTE_NAMES.AUTH_OFFLINE] || authOnlinePath; // TODO: explore objectToQuerystring const queryParams = new URLSearchParams(Object.assign({ host, shop }, state && { state })).toString(); redirectUrl = `${authPath}?${queryParams}`; break; } case error instanceof shopify_api_1.CookieNotFound: { console.warn(`${errorMessage}. This may occur if Cookie is already deleted. CookieNotFound Error ${error.message}`); // HMMMM: not sure const authOnlinePath = API_PATHS[shared_1.API_ROUTE_NAMES.AUTH_ONLINE]; const authPath = isOnline ? authOnlinePath : API_PATHS[shared_1.API_ROUTE_NAMES.AUTH_OFFLINE] || authOnlinePath; // TODO: explore objectToQuerystring const queryParams = new URLSearchParams(Object.assign({ host, shop }, state && { state })).toString(); redirectUrl = `${authPath}?${queryParams}`; break; } case error instanceof shopify_api_1.BillingError: { console.error(`${errorMessage}. Billing Error ${error.message}`, error.errorData); redirectUrl = `${baseErrorUrl}?code=${shared_1.ERROR_CODES.BILLING}`; break; } case error instanceof shopify_api_1.GraphqlQueryError: { const errorMessages = (0, shared_1.ensureArray)((_b = error.response) === null || _b === void 0 ? void 0 : _b.errors).map(({ message }) => (0, shared_1.ensureString)(message)); console.error(`${errorMessage}. GraphqlQuery Error ${errorMessages.join('. ')}`); redirectUrl = `${baseErrorUrl}?code=${shared_1.ERROR_CODES.QUERY}`; break; } case error instanceof shopify_api_1.InvalidOAuthError: { console.error(`${errorMessage}. InvalidOAuth Error`, error); redirectUrl = `${baseErrorUrl}?code=${shared_1.ERROR_CODES.OAUTH}`; break; } default: { console.error(errorMessage, error); redirectUrl = `${baseErrorUrl}?code=${shared_1.ERROR_CODES.CALLBACK}`; } } } return handleResponse(redirectUrl); }); }; exports.handleCallback = handleCallback; //# sourceMappingURL=callback.js.map