{"version":3,"file":"helpers-B1aQh_ad.mjs","names":[],"sources":["../../../node_modules/@shopify/shopify-api/dist/esm/runtime/platform/runtime-string.mjs","../../../src/server/types.ts","../../../src/server/authenticate/const.ts","../../../src/server/authenticate/helpers/app-bridge-url.ts","../../../src/server/authenticate/helpers/add-response-headers.ts","../../../src/server/authenticate/helpers/ensure-cors-headers.ts","../../../src/server/helpers/redirect-response.ts","../../../src/server/authenticate/admin/helpers/redirect-to-bounce-page.ts","../../../src/server/authenticate/helpers/respond-to-invalid-session-token.ts","../../../src/server/authenticate/helpers/get-shop-from-request.ts","../../../src/server/authenticate/helpers/validate-session-token.ts","../../../src/server/authenticate/helpers/get-session-token-header.ts","../../../src/server/authenticate/helpers/invalidate-access-token.ts","../../../src/server/authenticate/helpers/reject-bot-request.ts","../../../src/server/authenticate/helpers/respond-to-options-request.ts"],"sourcesContent":["// eslint-disable-next-line import/no-mutable-exports\nlet abstractRuntimeString = () => {\n    throw new Error(\"Missing adapter implementation for 'abstractRuntimeString' - make sure to import the appropriate adapter for your platform\");\n};\nfunction setAbstractRuntimeString(func) {\n    abstractRuntimeString = func;\n}\n\nexport { abstractRuntimeString, setAbstractRuntimeString };\n//# sourceMappingURL=runtime-string.mjs.map\n","import {RegisterReturn, Shopify} from '@shopify/shopify-api';\nimport {SessionStorage} from '@shopify/shopify-app-session-storage';\n\nimport type {AuthenticateAdmin} from './authenticate/admin/types';\nimport type {AuthenticateFlow} from './authenticate/flow/types';\nimport {AuthenticateFulfillmentService} from './authenticate/fulfillment-service/types';\nimport type {AuthenticatePublic} from './authenticate/public/types';\nimport type {\n  AuthenticateWebhook,\n  RegisterWebhooksOptions,\n} from './authenticate/webhooks/types';\nimport type {AppConfig, AppConfigArg} from './config-types';\nimport type {\n  ApiConfigWithFutureFlags,\n  ApiFutureFlags,\n  FutureFlagOptions,\n} from './future/flags';\nimport type {Unauthenticated} from './unauthenticated/types';\nimport type {AuthenticatePOS} from './authenticate/pos/types';\n\nexport interface BasicParams<\n  Future extends FutureFlagOptions = FutureFlagOptions,\n> {\n  api: Shopify<ApiConfigWithFutureFlags<Future>, any, ApiFutureFlags<Future>>;\n  config: AppConfig;\n  logger: Shopify['logger'];\n}\n\n// eslint-disable-next-line no-warning-comments\n// TODO: Use this enum to replace the isCustomStoreApp config option in shopify-api-js\nexport enum AppDistribution {\n  AppStore = 'app_store',\n  SingleMerchant = 'single_merchant',\n  ShopifyAdmin = 'shopify_admin',\n}\n\ntype RegisterWebhooks = (\n  options: RegisterWebhooksOptions,\n) => Promise<RegisterReturn | void>;\n\nexport enum LoginErrorType {\n  MissingShop = 'MISSING_SHOP',\n  InvalidShop = 'INVALID_SHOP',\n}\n\nexport interface LoginError {\n  shop?: LoginErrorType;\n}\n\ntype Login = (request: Request) => Promise<LoginError | never>;\n\ntype AddDocumentResponseHeaders = (request: Request, headers: Headers) => void;\n\ntype SessionStorageType<Config extends AppConfigArg> =\n  Config['sessionStorage'] extends SessionStorage\n    ? Config['sessionStorage']\n    : SessionStorage;\n\ninterface Authenticate<Config extends AppConfigArg> {\n  /**\n   * Authenticate an admin Request and get back an authenticated admin context.  Use the authenticated admin context to interact with Shopify.\n   *\n   * Examples of when to use this are requests from your app's UI, or requests from admin extensions.\n   *\n   * If there is no session for the Request, this will redirect the merchant to correct auth flows.\n   *\n   * @example\n   * <caption>Authenticating a request for an embedded app.</caption>\n   * ```ts\n   * // /app/routes/**\\/*.jsx\n   * import { LoaderFunctionArgs, json } from \"@tanstack/react-router\";\n   * import { authenticate } from \"../../shopify.server\";\n   *\n   * export async function loader({ request }: LoaderFunctionArgs) {\n   *   const {admin, session, sessionToken, billing} = authenticate.admin(request);\n   *   const response = await admin.graphql(`{ shop { name } }`)\n   *\n   *   return (await response.json());\n   * }\n   * ```\n   * ```ts\n   * // /app/shopify.server.ts\n   * import { ApiVersion, shopifyApp } from \"@yan-ad/shopify-app-tanstack/server\";\n   *\n   * const shopify = shopifyApp({\n   *   // ...etc\n   * });\n   * export default shopify;\n   * export const authenticate = shopify.authenticate;\n   * ```\n   */\n  admin: AuthenticateAdmin<Config>;\n\n  /**\n   * Authenticate a Flow extension Request and get back an authenticated context, containing an admin context to access\n   * the API, and the payload of the request.\n   *\n   * If there is no session for the Request, this will return an HTTP 400 error.\n   *\n   * Note that this will always be a POST request.\n   *\n   * @example\n   * <caption>Authenticating a Flow extension request.</caption>\n   * ```ts\n   * // /app/routes/**\\/*.jsx\n   * import { ActionFunctionArgs, json } from \"@tanstack/react-router\";\n   * import { authenticate } from \"../../shopify.server\";\n   *\n   * export async function action({ request }: ActionFunctionArgs) {\n   *   const {admin, session, payload} = authenticate.flow(request);\n   *\n   *   // Perform flow extension logic\n   *\n   *   // Return a 200 response\n   *   return null;\n   * }\n   * ```\n   * ```ts\n   * // /app/shopify.server.ts\n   * import { ApiVersion, shopifyApp } from \"@yan-ad/shopify-app-tanstack/server\";\n   *\n   * const shopify = shopifyApp({\n   *   // ...etc\n   * });\n   * export default shopify;\n   * export const authenticate = shopify.authenticate;\n   * ```\n   */\n  flow: AuthenticateFlow;\n\n  /**\n   * Authenticate a request from a fulfillment service and get back an authenticated context.\n   *\n   * @example\n   * <caption>Shopify session for the fulfillment service request.</caption>\n   * <description>Use the session associated with this request to use the Admin GraphQL API </description>\n   * ```ts\n   * // /app/routes/fulfillment_order_notification.ts\n   * import { ActionFunctionArgs } from \"@tanstack/react-router\";\n   * import { authenticate } from \"../shopify.server\";\n   *\n   * export async function action({ request }: ActionFunctionArgs) {\n   *   const { admin, session } = await authenticate.fulfillmentService(request);\n   *\n   *   console.log(session.id)\n   *\n   *   return new Response();\n   * }\n   * ```\n   * */\n  fulfillmentService: AuthenticateFulfillmentService;\n\n  /**\n   * Authenticate a request from a POS UI extension\n   *\n   * @example\n   * <caption>Authenticating a POS UI extension request</caption>\n   * ```ts\n   * // /app/routes/public/widgets.ts\n   * import { LoaderFunctionArgs, json } from \"@tanstack/react-router\";\n   * import { authenticate } from \"../shopify.server\";\n   *\n   * export const loader = async ({ request }: LoaderFunctionArgs) => {\n   *   const { sessionToken, cors } = await authenticate.pos(\n   *     request,\n   *   );\n   *   return cors({my: \"data\", shop: sessionToken.dest}));\n   * };\n   * ```\n   */\n  pos: AuthenticatePOS;\n\n  /**\n   * Authenticate a public request and get back a session token.\n   *\n   * @example\n   * <caption>Authenticating a request from a checkout extension</caption>\n   *\n   * ```ts\n   * // /app/routes/api/checkout.jsx\n   * import { LoaderFunctionArgs, json } from \"@tanstack/react-router\";\n   * import { authenticate } from \"../../shopify.server\";\n   * import { getWidgets } from \"~/db/widgets\";\n   *\n   * export async function loader({ request }: LoaderFunctionArgs) {\n   *   const {sessionToken} = authenticate.public.checkout(request);\n   *\n   *   return (await getWidgets(sessionToken));\n   * }\n   * ```\n   */\n  public: AuthenticatePublic;\n\n  /**\n   * Authenticate a Shopify webhook request, get back an authenticated admin context and details on the webhook request\n   * \n   * @example\n   * <caption>Authenticating a webhook request</caption>\n   *\n   * ```ts\n   * // app/routes/webhooks.ts\n   * import { ActionFunctionArgs } from \"@tanstack/react-router\";\n   * import { authenticate } from \"../shopify.server\";\n   * import db from \"../db.server\";\n   *\n   * export const action = async ({ request }: ActionFunctionArgs) => {\n   *   const { topic, shop, session, payload } = await authenticate.webhook(request);\n   * \n   *   // Webhook requests can trigger after an app is uninstalled\n   *   // If the app is already uninstalled, the session may be undefined.\n   *   if (!session) {\n   *     throw new Response();\n   *   }\n   * \n   *   // Handle the webhook\n   *   console.log(`${TOPIC} webhook received with payload:`, JSON.stringify(payload))\n   *\n   *   throw new Response();\n   * };\n   * ```\n   * \n   * @example\n   * <caption>Registering app-specific webhooks (Recommended)</caption>\n   * ```toml\n   * # shopify.app.toml\n   * [webhooks]\n   * api_version = \"2024-07\"\n\n   *   [[webhooks.subscriptions]]\n   *   topics = [\"products/create\"]\n   *   uri = \"/webhooks/products/create\"\n   * \n   * ```\n   * \n   * @example\n   * <caption>Registering shop-specific webhooks.</caption>\n   * <description>In many cases you won't need this. Please see: [https://shopify.dev/docs/apps/build/webhooks/subscribe#app-specific-vs-shop-specific-subscriptions](https://shopify.dev/docs/apps/build/webhooks/subscribe#app-specific-vs-shop-specific-subscriptions)\n   * </description>\n   * ```ts\n   * // app/shopify.server.ts\n   * import { DeliveryMethod, shopifyApp } from \"@yan-ad/shopify-app-tanstack/server\";\n   *\n   * const shopify = shopifyApp({\n   *   webhooks: {\n   *     PRODUCTS_CREATE: {\n   *       deliveryMethod: DeliveryMethod.Http,\n   *       callbackUrl: \"/webhooks/products/create\",\n   *     },\n   *   },\n   *   hooks: {\n   *     afterAuth: async ({ session }) => {\n   *       // Register webhooks for the shop\n   *       // In this example, every shop will have these webhooks\n   *       // You could wrap this in some custom shop specific conditional logic if needed\n   *       shopify.registerWebhooks({ session });\n   *     },\n   *   },\n   *   // ...etc\n   * });\n   * ```\n   */\n  webhook: AuthenticateWebhook<string>;\n}\n\nexport interface ShopifyAppBase<Config extends AppConfigArg> {\n  /**\n   * The `SessionStorage` instance you passed in as a config option.\n   *\n   * @example\n   * <caption>Storing sessions with Prisma.</caption>\n   * <description>Import the `@shopify/shopify-app-session-storage-prisma` package to store sessions in your Prisma database.</description>\n   * ```ts\n   * // /app/shopify.server.ts\n   * import { shopifyApp } from \"@yan-ad/shopify-app-tanstack/server\";\n   * import { PrismaSessionStorage } from \"@shopify/shopify-app-session-storage-prisma\";\n   * import prisma from \"~/db.server\";\n   *\n   * const shopify = shopifyApp({\n   *   sessionStorage: new PrismaSessionStorage(prisma),\n   *   // ...etc\n   * })\n   *\n   * // shopify.sessionStorage is an instance of PrismaSessionStorage\n   * ```\n   */\n  sessionStorage?: SessionStorageType<Config>;\n\n  /**\n   * Adds the required Content Security Policy headers for Shopify apps to the given Headers object.\n   *\n   * {@link https://shopify.dev/docs/apps/store/security/iframe-protection}\n   *\n   * @example\n   * <caption>Return headers on all requests.</caption>\n   * <description>Add headers to all HTML requests by calling `shopify.addDocumentResponseHeaders` in `entry.server.tsx`.</description>\n   *\n   * ```\n   * // ~/shopify.server.ts\n   * import { shopifyApp } from \"@yan-ad/shopify-app-tanstack/server\";\n   *\n   * const shopify = shopifyApp({\n   *   // ...etc\n   * });\n   * export default shopify;\n   * export const addDocumentResponseheaders = shopify.addDocumentResponseheaders;\n   * ```\n   *\n   * ```ts\n   * // entry.server.tsx\n   * import { addDocumentResponseHeaders } from \"~/shopify.server\";\n   *\n   * export default function handleRequest(\n   *   request: Request,\n   *   responseStatusCode: number,\n   *   responseHeaders: Headers,\n   *   reactRouterContext: EntryContext\n   * ) {\n   *   const markup = renderToString(\n   *     <ReactRouterServer context={reactRouterContext} url={request.url} />\n   *   );\n   *\n   *   responseHeaders.set(\"Content-Type\", \"text/html\");\n   *   addDocumentResponseHeaders(request, responseHeaders);\n   *\n   *   return new Response(\"<!DOCTYPE html>\" + markup, {\n   *     status: responseStatusCode,\n   *     headers: responseHeaders,\n   *   });\n   * }\n   * ```\n   */\n  addDocumentResponseHeaders: AddDocumentResponseHeaders;\n\n  /**\n   * Register shop-specific webhook subscriptions using the Admin GraphQL API.\n   *\n   * In many cases defining app-specific webhooks in the `shopify.app.toml` will be sufficient and easier to manage.  Please see:\n   *\n   * {@link https://shopify.dev/docs/apps/build/webhooks/subscribe#app-specific-vs-shop-specific-subscriptions}\n   *\n   * You should only use this if you need shop-specific webhooks.\n   *\n   * @example\n   * <caption>Registering shop-specific webhooks after install</caption>\n   * <description>Trigger the registration to create the shop-specific webhook subscriptions after a merchant installs your app using the `afterAuth` hook. Learn more about [subscribing to webhooks.](https://shopify.dev/docs/api/shopify-app-react-router/v3/guide-webhooks)</description>\n   * ```ts\n   * // app/shopify.server.ts\n   * import { DeliveryMethod, shopifyApp } from \"@yan-ad/shopify-app-tanstack/server\";\n   *\n   * const shopify = shopifyApp({\n   *   webhooks: {\n   *     PRODUCTS_CREATE: {\n   *       deliveryMethod: DeliveryMethod.Http,\n   *       callbackUrl: \"/webhooks/products/create\",\n   *     },\n   *   },\n   *   hooks: {\n   *     afterAuth: async ({ session }) => {\n   *       // Register webhooks for the shop\n   *       // In this example, every shop will have these webhooks\n   *       // You could wrap this in some custom shop specific conditional logic if needed\n   *       shopify.registerWebhooks({ session });\n   *     },\n   *   },\n   *   // ...etc\n   * });\n   * ```\n   */\n  registerWebhooks: RegisterWebhooks;\n\n  /**\n   * Ways to authenticate requests from different surfaces across Shopify.\n   *\n   * @example\n   * <caption>Authenticate Shopify requests.</caption>\n   * <description>Use the functions in `authenticate` to validate requests coming from Shopify.</description>\n   * ```ts\n   * // /app/shopify.server.ts\n   * import { ApiVersion, shopifyApp } from \"@yan-ad/shopify-app-tanstack/server\";\n   *\n   * const shopify = shopifyApp({\n   *   // ...etc\n   * });\n   * export default shopify;\n   * ```\n   * ```ts\n   * // /app/routes/**\\/*.jsx\n   * import { LoaderFunctionArgs, json } from \"@tanstack/react-router\";\n   * import shopify from \"../../shopify.server\";\n   *\n   * export async function loader({ request }: LoaderFunctionArgs) {\n   *   const {admin, session, sessionToken, billing} = shopify.authenticate.admin(request);\n   *   const response = admin.graphql(`{ shop { name } }`)\n   *\n   *   return (await response.json());\n   * }\n   * ```\n   */\n  authenticate: Authenticate<Config>;\n\n  /**\n   * Ways to get Contexts from requests that do not originate from Shopify.\n   *\n   * @example\n   * <caption>Using unauthenticated contexts.</caption>\n   * <description>Create contexts for requests that don't come from Shopify.</description>\n   * ```ts\n   * // /app/shopify.server.ts\n   * import { ApiVersion, shopifyApp } from \"@yan-ad/shopify-app-tanstack/server\";\n   *\n   * const shopify = shopifyApp({\n   *   // ...etc\n   * });\n   * export default shopify;\n   * ```\n   * ```ts\n   * // /app/routes/**\\/*.jsx\n   * import { LoaderFunctionArgs, json } from \"@tanstack/react-router\";\n   * import { authenticateExternal } from \"~/helpers/authenticate\"\n   * import shopify from \"../../shopify.server\";\n   *\n   * export async function loader({ request }: LoaderFunctionArgs) {\n   *   const shop = await authenticateExternal(request)\n   *   const {admin} = await shopify.unauthenticated.admin(shop);\n   *   const response = admin.graphql(`{ shop { currencyCode } }`)\n   *\n   *   return (await response.json());\n   * }\n   * ```\n   */\n  unauthenticated: Unauthenticated;\n}\n\nexport interface ShopifyAppLogin {\n  /**\n   * Log a merchant in, and redirect them to the app root. Will redirect the merchant to authentication if a shop is\n   * present in the URL search parameters or form data.\n   *\n   * This function won't be present when the `distribution` config option is set to `AppDistribution.ShopifyAdmin`,\n   * because Admin apps aren't allowed to show a login page.\n   *\n   * @example\n   * <caption>Creating a login page.</caption>\n   * <description>Use `shopify.login` to create a login form, in a route that can handle GET and POST requests.</description>\n   * ```ts\n   * // /app/shopify.server.ts\n   * import { ApiVersion, shopifyApp } from \"@yan-ad/shopify-app-tanstack/server\";\n   *\n   * const shopify = shopifyApp({\n   *   // ...etc\n   * });\n   * export default shopify;\n   * ```\n   * ```ts\n   * // /app/routes/auth/login.tsx\n   * import shopify from \"../../shopify.server\";\n   *\n   * export async function loader({ request }: LoaderFunctionArgs) {\n   *   const errors = shopify.login(request);\n   *\n   *   return (errors);\n   * }\n   *\n   * export async function action({ request }: ActionFunctionArgs) {\n   *   const errors = shopify.login(request);\n   *\n   *   return (errors);\n   * }\n   *\n   * export default function Auth() {\n   *   const actionData = useActionData<typeof action>();\n   *   const [shop, setShop] = useState(\"\");\n   *\n   *   return (\n   *     <Page>\n   *       <Card>\n   *         <Form method=\"post\">\n   *           <FormLayout>\n   *             <Text variant=\"headingMd\" as=\"h2\">\n   *               Login\n   *             </Text>\n   *             <TextField\n   *               type=\"text\"\n   *               name=\"shop\"\n   *               label=\"Shop domain\"\n   *               helpText=\"e.g: my-shop-domain.myshopify.com\"\n   *               value={shop}\n   *               onChange={setShop}\n   *               autoComplete=\"on\"\n   *               error={actionData?.errors.shop}\n   *             />\n   *             <Button submit primary>\n   *               Submit\n   *             </Button>\n   *           </FormLayout>\n   *         </Form>\n   *       </Card>\n   *     </Page>\n   *   );\n   * }\n   * ```\n   */\n  login: Login;\n}\n\nexport type AdminApp<Config extends AppConfigArg> = ShopifyAppBase<Config>;\nexport type SingleMerchantApp<Config extends AppConfigArg> =\n  ShopifyAppBase<Config> & ShopifyAppLogin;\nexport type AppStoreApp<Config extends AppConfigArg> = ShopifyAppBase<Config> &\n  ShopifyAppLogin;\n\ntype EnforceSessionStorage<Config extends AppConfigArg, Base> = Base & {\n  sessionStorage: SessionStorageType<Config>;\n};\n\n/**\n * An object your app can use to interact with Shopify.\n *\n * By default, the app's distribution is `AppStore`.\n */\nexport type ShopifyApp<Config extends AppConfigArg> =\n  Config['distribution'] extends AppDistribution.ShopifyAdmin\n    ? AdminApp<Config>\n    : Config['distribution'] extends AppDistribution.SingleMerchant\n      ? EnforceSessionStorage<Config, SingleMerchantApp<Config>>\n      : Config['distribution'] extends AppDistribution.AppStore\n        ? EnforceSessionStorage<Config, AppStoreApp<Config>>\n        : EnforceSessionStorage<Config, AppStoreApp<Config>>;\n","export const APP_BRIDGE_URL =\n  'https://cdn.shopify.com/shopifycloud/app-bridge.js';\n\nexport const POLARIS_URL = 'https://cdn.shopify.com/shopifycloud/polaris.js';\n\nexport const CDN_URL = 'https://cdn.shopify.com';\n\nexport const REAUTH_URL_HEADER =\n  'X-Shopify-API-Request-Failure-Reauthorize-Url';\n\nexport const RETRY_INVALID_SESSION_HEADER = {\n  'X-Shopify-Retry-Invalid-Session-Request': '1',\n};\n\nexport const CORS_HEADERS = {\n  'Access-Control-Allow-Origin': '*',\n  'Access-Control-Allow-Headers': 'Authorization',\n  'Access-Control-Expose-Headers': REAUTH_URL_HEADER,\n};\n","import {APP_BRIDGE_URL} from '../const';\n\nlet appBridgeUrlOverride: string | undefined;\nexport function setAppBridgeUrlOverride(url: string) {\n  appBridgeUrlOverride = url;\n}\n\nexport function appBridgeUrl() {\n  return appBridgeUrlOverride || APP_BRIDGE_URL;\n}\n","import type {BasicParams} from '../../types';\nimport {AppDistribution} from '../../types';\nimport {APP_BRIDGE_URL, CDN_URL, POLARIS_URL} from '../const';\n\nexport type AddDocumentResponseHeadersFunction = (\n  request: Request,\n  headers: Headers,\n) => void;\n\nexport function addDocumentResponseHeadersFactory(\n  params: BasicParams,\n): AddDocumentResponseHeadersFunction {\n  const {api, config} = params;\n\n  return function (request: Request, headers: Headers) {\n    const {searchParams} = new URL(request.url);\n    const shop = api.utils.sanitizeShop(searchParams.get('shop')!);\n\n    const isEmbeddedApp = config.distribution !== AppDistribution.ShopifyAdmin;\n    addDocumentResponseHeaders(headers, isEmbeddedApp, shop);\n  };\n}\n\nexport function addDocumentResponseHeaders(\n  headers: Headers,\n  isEmbeddedApp: boolean,\n  shop: string | null | undefined,\n) {\n  if (shop) {\n    headers.set(\n      'Link',\n      `<${CDN_URL}>; rel=\"preconnect\", <${APP_BRIDGE_URL}>; rel=\"preload\"; as=\"script\", <${POLARIS_URL}>; rel=\"preload\"; as=\"script\"`,\n    );\n  }\n\n  if (isEmbeddedApp) {\n    if (shop) {\n      headers.set(\n        'Content-Security-Policy',\n        `frame-ancestors https://${shop} https://admin.shopify.com https://*.spin.dev https://admin.myshopify.io https://admin.shop.dev;`,\n      );\n    }\n  } else {\n    headers.set('Content-Security-Policy', `frame-ancestors 'none';`);\n  }\n}\n","import {BasicParams} from '../../types';\nimport {REAUTH_URL_HEADER} from '../const';\n\nexport interface EnsureCORSFunction {\n  (response: Response): Response;\n}\n\nexport function ensureCORSHeadersFactory(\n  params: BasicParams,\n  request: Request,\n  corsHeaders: string[] = [],\n): EnsureCORSFunction {\n  const {logger, config} = params;\n\n  return function ensureCORSHeaders(response) {\n    const origin = request.headers.get('Origin');\n    if (origin && origin !== config.appUrl) {\n      logger.debug(\n        'Request comes from a different origin, adding CORS headers',\n      );\n\n      const corsHeadersSet = new Set([\n        'Authorization',\n        'Content-Type',\n        ...corsHeaders,\n      ]);\n\n      response.headers.set('Access-Control-Allow-Origin', '*');\n      response.headers.set(\n        'Access-Control-Allow-Headers',\n        [...corsHeadersSet].join(', '),\n      );\n      response.headers.set('Access-Control-Expose-Headers', REAUTH_URL_HEADER);\n    }\n\n    return response;\n  };\n}\n","export type RedirectInit = number | ResponseInit;\n\nexport function redirect(url: string, init: RedirectInit = 302): Response {\n  const responseInit = typeof init === 'number' ? {status: init} : init;\n  const headers = new Headers(responseInit.headers);\n  headers.set('Location', url);\n\n  return new Response(null, {\n    ...responseInit,\n    headers,\n    status: responseInit.status ?? 302,\n  });\n}\n","import {redirect} from '../../../helpers/redirect-response';\nimport {BasicParams} from '../../../types';\n\nexport const redirectToBouncePage = (params: BasicParams, url: URL): never => {\n  const {config} = params;\n\n  // Make sure we always point to the configured app URL so it also works behind reverse proxies (that alter the Host\n  // header).\n  const searchParams = url.searchParams;\n  searchParams.delete('id_token');\n  searchParams.set(\n    'shopify-reload',\n    `${config.appUrl}${url.pathname}?${searchParams.toString()}`,\n  );\n\n  // eslint-disable-next-line no-warning-comments\n  // TODO Make sure this works on chrome without a tunnel (weird HTTPS redirect issue)\n  // https://github.com/orgs/Shopify/projects/6899/views/1?pane=issue&itemId=28376650\n  throw redirect(\n    `${config.auth.patchSessionTokenPath}?${searchParams.toString()}`,\n  );\n};\n","import {redirectToBouncePage} from '../admin/helpers/redirect-to-bounce-page';\nimport {RETRY_INVALID_SESSION_HEADER} from '../const';\nimport {BasicParams} from '../../types';\n\ninterface RespondToInvalidSessionTokenParams {\n  params: BasicParams;\n  request: Request;\n  retryRequest?: boolean;\n}\n\nexport function respondToInvalidSessionToken({\n  params,\n  request,\n  retryRequest = false,\n}: RespondToInvalidSessionTokenParams) {\n  const {api, logger, config} = params;\n\n  const isDocumentRequest = !request.headers.get('authorization');\n  if (isDocumentRequest) {\n    return redirectToBouncePage({api, logger, config}, new URL(request.url));\n  }\n\n  throw new Response(undefined, {\n    status: 401,\n    statusText: 'Unauthorized',\n    headers: retryRequest ? RETRY_INVALID_SESSION_HEADER : {},\n  });\n}\n","export function getShopFromRequest(request: Request) {\n  const url = new URL(request.url);\n  return url.searchParams.get('shop')!;\n}\n","import {JwtPayload} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../types';\n\nimport {respondToInvalidSessionToken} from './respond-to-invalid-session-token';\nimport {getShopFromRequest} from './get-shop-from-request';\n\ninterface ValidateSessionTokenOptions {\n  checkAudience?: boolean;\n  retryRequest?: boolean;\n}\n\nexport async function validateSessionToken(\n  params: BasicParams,\n  request: Request,\n  token: string,\n  {checkAudience = true, retryRequest = true}: ValidateSessionTokenOptions = {},\n): Promise<JwtPayload> {\n  const {api, logger} = params;\n  const shop = getShopFromRequest(request);\n  logger.debug('Validating session token', {shop});\n\n  try {\n    const payload = await api.session.decodeSessionToken(token, {\n      checkAudience,\n    });\n    logger.debug('Session token is valid - validated', {shop});\n\n    return payload;\n  } catch (error) {\n    logger.debug(`Failed to validate session token: ${error.message}`, {\n      shop,\n    });\n\n    throw respondToInvalidSessionToken({params, request, retryRequest});\n  }\n}\n","const SESSION_TOKEN_PARAM = 'id_token';\n\nexport function getSessionTokenHeader(request: Request): string | undefined {\n  return request.headers.get('authorization')?.replace('Bearer ', '');\n}\n\nexport function getSessionTokenFromUrlParam(request: Request): string | null {\n  const url = new URL(request.url);\n\n  return url.searchParams.get(SESSION_TOKEN_PARAM);\n}\n","import {Session} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../types';\n\nexport async function invalidateAccessToken(\n  params: BasicParams,\n  session: Session,\n): Promise<void> {\n  const {logger, config} = params;\n\n  logger.debug(`Invalidating access token for session - ${session.id}`, {\n    shop: session.shop,\n  });\n\n  session.accessToken = undefined;\n  await config.sessionStorage!.storeSession(session);\n}\n","import {isbot} from 'isbot';\n\nimport type {BasicParams} from '../../types';\n\nconst SHOPIFY_POS_USER_AGENT = /Shopify POS\\//;\nconst SHOPIFY_MOBILE_USER_AGENT = /Shopify Mobile\\//;\n\nconst SHOPIFY_USER_AGENTS = [SHOPIFY_POS_USER_AGENT, SHOPIFY_MOBILE_USER_AGENT];\n\nexport function respondToBotRequest(\n  {logger}: BasicParams,\n  request: Request,\n): void | never {\n  const userAgent = request.headers.get('User-Agent') ?? '';\n\n  // We call isbot below to prevent good (self-identifying) bots from triggering auth requests, but there are some\n  // Shopify-specific cases we want to allow that are identified as bots by isbot.\n  if (SHOPIFY_USER_AGENTS.some((agent) => agent.test(userAgent))) {\n    logger.debug('Request is from a Shopify agent, allow');\n    return;\n  }\n\n  if (isbot(userAgent)) {\n    logger.debug('Request is from a bot, skipping auth');\n    throw new Response(undefined, {status: 410, statusText: 'Gone'});\n  }\n}\n","import {BasicParams} from '../../types';\n\nimport {ensureCORSHeadersFactory} from './ensure-cors-headers';\n\nexport function respondToOptionsRequest(\n  params: BasicParams,\n  request: Request,\n  corsHeaders?: string[],\n) {\n  if (request.method === 'OPTIONS') {\n    const ensureCORSHeaders = ensureCORSHeadersFactory(\n      params,\n      request,\n      corsHeaders,\n    );\n\n    throw ensureCORSHeaders(\n      new Response(null, {\n        status: 204,\n        headers: {\n          'Access-Control-Max-Age': '7200',\n        },\n      }),\n    );\n  }\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}