@shopify/shopify-app-express
Version:
Shopify Express Middleware - to simplify the building of Shopify Apps with Express
1 lines • 8.53 kB
Source Map (JSON)
{"version":3,"file":"ensure-installed-on-shop.mjs","sources":["../../../../src/middlewares/ensure-installed-on-shop.ts"],"sourcesContent":["import {Request, Response, NextFunction} from 'express';\nimport {Session, Shopify} from '@shopify/shopify-api';\n\nimport {redirectToAuth} from '../redirect-to-auth';\nimport {AppConfigInterface} from '../config-types';\nimport {ApiAndConfigParams} from '../types';\nimport {AppInstallations} from '../app-installations';\n\nimport {EnsureInstalledMiddleware} from './types';\nimport {addCSPHeader} from './csp-headers';\nimport {validateAuthenticatedSession} from './validate-authenticated-session';\nimport {hasValidAccessToken} from './has-valid-access-token';\n\ntype EnsureInstalledParams = ApiAndConfigParams;\n\nexport function ensureInstalled({\n api,\n config,\n}: EnsureInstalledParams): EnsureInstalledMiddleware {\n return function ensureInstalledOnShop() {\n return async (req: Request, res: Response, next: NextFunction) => {\n config.logger.debug('Running ensureInstalledOnShop');\n\n if (!api.config.isEmbeddedApp) {\n config.logger.warning(\n 'ensureInstalledOnShop() should only be used in embedded apps; calling validateAuthenticatedSession() instead',\n );\n\n return validateAuthenticatedSession({api, config})()(req, res, next);\n }\n\n const shop = getRequestShop(api, config, req, res);\n if (!shop) {\n return undefined;\n }\n\n config.logger.debug('Checking if shop has installed the app', {shop});\n\n const sessionId = api.session.getOfflineId(shop);\n const session = await config.sessionStorage.loadSession(sessionId);\n\n const exitIframeRE = new RegExp(`^${config.exitIframePath}`, 'i');\n if (!session && !req.originalUrl.match(exitIframeRE)) {\n config.logger.debug(\n 'App installation was not found for shop, redirecting to auth',\n {shop},\n );\n\n return redirectToAuth({req, res, api, config});\n }\n\n if (api.config.isEmbeddedApp && req.query.embedded !== '1') {\n if (await sessionHasValidAccessToken(api, config, session)) {\n await embedAppIntoShopify(api, config, req, res, shop);\n return undefined;\n } else {\n config.logger.info(\n 'Found a session, but it is not valid. Redirecting to auth',\n {shop},\n );\n\n return redirectToAuth({req, res, api, config});\n }\n }\n\n addCSPHeader(api, req, res);\n\n config.logger.debug('App is installed and ready to load', {shop});\n\n return next();\n };\n };\n}\n\nexport function deleteAppInstallationHandler(\n appInstallations: AppInstallations,\n config: AppConfigInterface,\n) {\n return async function (\n _topic: string,\n shop: string,\n _body: any,\n _webhookId: string,\n ) {\n config.logger.debug('Deleting shop sessions', {shop});\n\n await appInstallations.delete(shop);\n };\n}\n\nfunction getRequestShop(\n api: Shopify,\n config: AppConfigInterface,\n req: Request,\n res: Response,\n): string | undefined {\n if (typeof req.query.shop !== 'string') {\n config.logger.error(\n 'ensureInstalledOnShop did not receive a shop query argument',\n {shop: req.query.shop},\n );\n\n res.status(400);\n res.send('No shop provided');\n return undefined;\n }\n\n const shop = api.utils.sanitizeShop(req.query.shop);\n\n if (!shop) {\n config.logger.error(\n 'ensureInstalledOnShop did not receive a valid shop query argument',\n {shop: req.query.shop},\n );\n\n res.status(422);\n res.send('Invalid shop provided');\n return undefined;\n }\n\n return shop;\n}\n\nasync function sessionHasValidAccessToken(\n api: Shopify,\n config: AppConfigInterface,\n session: Session | undefined,\n): Promise<boolean> {\n if (!session) {\n return false;\n }\n\n try {\n return (\n session.isActive(api.config.scopes) &&\n (await hasValidAccessToken(api, session))\n );\n } catch (error) {\n config.logger.error(`Could not check if session was valid: ${error}`, {\n shop: session.shop,\n });\n return false;\n }\n}\n\nasync function embedAppIntoShopify(\n api: Shopify,\n config: AppConfigInterface,\n req: Request,\n res: Response,\n shop: string,\n): Promise<void> {\n let embeddedUrl: string;\n try {\n embeddedUrl = await api.auth.getEmbeddedAppUrl({\n rawRequest: req,\n rawResponse: res,\n });\n } catch (error) {\n config.logger.error(\n `ensureInstalledOnShop did not receive a host query argument`,\n {shop},\n );\n\n res.status(400);\n res.send('No host provided');\n return;\n }\n\n config.logger.debug(\n `Request is not embedded but app is. Redirecting to ${embeddedUrl} to embed the app`,\n {shop},\n );\n\n res.redirect(embeddedUrl + req.path);\n}\n"],"names":[],"mappings":"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"}