{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/server/boundary/headers.ts","../../../src/server/boundary/error.tsx","../../../src/server/boundary/index.ts","../../../src/server/version.ts","../../../src/server/authenticate/webhooks/register.ts","../../../src/server/authenticate/admin/billing/cancel.ts","../../../src/server/authenticate/admin/billing/require.ts","../../../src/server/clients/admin/graphql.ts","../../../src/server/clients/admin/factory.ts","../../../src/server/authenticate/admin/helpers/create-admin-api-context.ts","../../../src/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.ts","../../../src/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.ts","../../../src/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.ts","../../../src/server/authenticate/admin/helpers/handle-client-error.ts","../../../src/server/authenticate/admin/helpers/redirect-with-app-bridge-headers.ts","../../../src/server/authenticate/admin/helpers/validate-redirect-url.ts","../../../src/server/authenticate/admin/helpers/render-app-bridge.ts","../../../src/server/authenticate/admin/helpers/redirect.ts","../../../src/server/authenticate/admin/helpers/trigger-after-auth-hook.ts","../../../src/server/authenticate/admin/helpers/validate-shop-and-host-params.ts","../../../src/server/authenticate/admin/billing/helpers.ts","../../../src/server/authenticate/admin/billing/request.ts","../../../src/server/authenticate/admin/billing/check.ts","../../../src/server/authenticate/admin/billing/create-usage-record.ts","../../../src/server/authenticate/admin/billing/update-usage-subscription-capped-amount.ts","../../../src/server/authenticate/admin/helpers/redirect-to-install-page.ts","../../../src/server/authenticate/admin/scope/client/fetch-scopes-details.ts","../../../src/server/authenticate/admin/scope/request.ts","../../../src/server/authenticate/admin/scope/query.ts","../../../src/server/authenticate/admin/scope/client/revoke-scopes.ts","../../../src/server/authenticate/admin/scope/revoke.ts","../../../src/server/authenticate/admin/scope/factory.ts","../../../src/server/authenticate/admin/authenticate.ts","../../../src/server/clients/storefront/factory.ts","../../../src/server/helpers/create-or-load-offline-session.ts","../../../src/server/helpers/refresh-token.ts","../../../src/server/helpers/ensure-offline-token-is-not-expired.ts","../../../src/server/helpers/ensure-valid-offline-session.ts","../../../src/server/authenticate/webhooks/authenticate.ts","../../../src/server/override-logger.ts","../../../src/server/authenticate/login/login.ts","../../../src/server/errors.ts","../../../src/server/unauthenticated/admin/factory.ts","../../../src/server/authenticate/public/extension/authenticate.ts","../../../src/server/authenticate/public/checkout/authenticate.ts","../../../src/server/authenticate/public/appProxy/authenticate.ts","../../../src/server/authenticate/public/customer-account/authenticate.ts","../../../src/server/authenticate/public/factory.ts","../../../src/server/unauthenticated/storefront/factory.ts","../../../src/server/authenticate/admin/strategies/token-exchange.ts","../../../src/server/authenticate/admin/strategies/merchant-custom-app.ts","../../../src/server/authenticate/helpers/idempotent-promise-handler.ts","../../../src/server/authenticate/flow/authenticate.ts","../../../src/server/authenticate/fulfillment-service/authenticate.ts","../../../src/server/authenticate/pos/authenticate.ts","../../../src/server/future/flags.ts","../../../src/server/shopify-app.ts","../../../src/server/index.ts"],"sourcesContent":["import {HeadersArgs} from './types';\n\nexport function headersBoundary(headers: HeadersArgs): Headers {\n  const {parentHeaders, loaderHeaders, actionHeaders, errorHeaders} = headers;\n\n  if (errorHeaders && Array.from(errorHeaders.entries()).length > 0) {\n    return errorHeaders;\n  }\n\n  return new Headers([\n    ...(parentHeaders ? Array.from(parentHeaders.entries()) : []),\n    ...(loaderHeaders ? Array.from(loaderHeaders.entries()) : []),\n    ...(actionHeaders ? Array.from(actionHeaders.entries()) : []),\n  ]);\n}\n","import {createElement} from 'react';\n\nexport function errorBoundary(error: any) {\n  if (\n    error.constructor.name === 'ErrorResponse' ||\n    error.constructor.name === 'ErrorResponseImpl'\n  ) {\n    return createElement('div', {\n      dangerouslySetInnerHTML: {__html: error.data || 'Handling response'},\n    });\n  }\n\n  throw error;\n}\n","import {headersBoundary} from './headers';\nimport {errorBoundary} from './error';\n\n/**\n * A collection of functions that handle the necessary code for error boundaries in routes using authenticate.admin.\n */\nexport const boundary = {\n  /**\n   * A function that handles errors or thrown responses.\n   *\n   * @example\n   * <caption>Catching errors in a route</caption>\n   * ```ts\n   * // /app/routes/admin/widgets.ts\n   * import { boundary } from \"@yan-ad/shopify-app-tanstack/server\";\n   *\n   * export function ErrorBoundary() {\n   *   return boundary.error(useRouteError());\n   * }\n   * ```\n   */\n  error: errorBoundary,\n\n  /**\n   * A function that sets the appropriate document response headers.\n   *\n   * @example\n   * <caption>Catching errors in a route</caption>\n   * ```ts\n   * // /app/routes/admin/widgets.ts\n   * import { boundary } from \"@yan-ad/shopify-app-tanstack/server\";\n   *\n   * export const headers = (headersArgs) => {\n   *   return boundary.headers(headersArgs);\n   * };\n   * ```\n   */\n  headers: headersBoundary,\n};\n","export const SHOPIFY_REACT_ROUTER_LIBRARY_VERSION = '1.2.0';\n","import type {BasicParams} from '../../types';\n\nimport type {RegisterWebhooksOptions} from './types';\n\nexport function registerWebhooksFactory({api, logger}: BasicParams) {\n  return async function registerWebhooks({session}: RegisterWebhooksOptions) {\n    return api.webhooks\n      .register({session})\n      .then((response) => {\n        Object.entries(response).forEach(([topic, topicResults]) => {\n          topicResults.forEach(({success, ...rest}) => {\n            if (success) {\n              logger.debug('Registered webhook', {\n                topic,\n                shop: session.shop,\n                operation: rest.operation,\n              });\n            } else {\n              logger.error('Failed to register webhook', {\n                topic,\n                shop: session.shop,\n                result: JSON.stringify(rest.result),\n              });\n            }\n          });\n        });\n\n        return response;\n      })\n      .catch((error) => {\n        const graphQLErrors: {extensions: {code?: string}}[] =\n          error.body?.errors?.graphQLErrors || [];\n\n        const throttled = graphQLErrors.find(\n          ({extensions: {code}}) => code === 'THROTTLED',\n        );\n\n        if (throttled) {\n          logger.error('Failed to register webhooks', {\n            shop: session.shop,\n            error: JSON.stringify(error),\n          });\n        } else {\n          throw error;\n        }\n      });\n  };\n}\n","import {HttpResponseError, Session} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport {\n  invalidateAccessToken,\n  respondToInvalidSessionToken,\n} from '../../helpers';\n\nimport type {CancelBillingOptions} from './types';\n\nexport function cancelBillingFactory(\n  params: BasicParams,\n  request: Request,\n  session: Session,\n) {\n  return async function cancelBilling(options: CancelBillingOptions) {\n    const {api, logger} = params;\n\n    logger.debug('Cancelling billing', {shop: session.shop, ...options});\n\n    try {\n      return await api.billing.cancel({\n        session,\n        subscriptionId: options.subscriptionId,\n        isTest: options.isTest,\n        prorate: options.prorate,\n      });\n    } catch (error) {\n      if (error instanceof HttpResponseError && error.response.code === 401) {\n        logger.debug('API token was invalid, responding to invalid session', {\n          shop: session.shop,\n        });\n\n        await invalidateAccessToken(params, session);\n\n        throw respondToInvalidSessionToken({\n          params,\n          request,\n          retryRequest: true,\n        });\n      }\n      throw error;\n    }\n  };\n}\n","import {\n  BillingCheckResponseObject,\n  HttpResponseError,\n  Session,\n} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport type {AppConfigArg} from '../../../config-types';\nimport {\n  invalidateAccessToken,\n  respondToInvalidSessionToken,\n} from '../../helpers';\n\nimport type {RequireBillingOptions} from './types';\n\nexport function requireBillingFactory<Config extends AppConfigArg>(\n  params: BasicParams,\n  request: Request,\n  session: Session,\n) {\n  const {api, logger} = params;\n\n  return async function requireBilling(options: RequireBillingOptions<Config>) {\n    const logContext = {\n      shop: session.shop,\n      plans: options.plans,\n      isTest: options.isTest,\n    };\n\n    logger.debug('Checking billing for the shop', logContext);\n\n    let data: BillingCheckResponseObject;\n    try {\n      data = await api.billing.check({\n        session,\n        plans: options.plans as string[],\n        isTest: options.isTest,\n        returnObject: true,\n      });\n    } catch (error) {\n      if (error instanceof HttpResponseError && error.response.code === 401) {\n        logger.debug(\n          'API token was invalid, responding to invalid session',\n          logContext,\n        );\n\n        await invalidateAccessToken(params, session);\n\n        throw respondToInvalidSessionToken({\n          params,\n          request,\n          retryRequest: true,\n        });\n      }\n      throw error;\n    }\n\n    if (!data.hasActivePayment) {\n      logger.debug('Billing check failed', logContext);\n      throw await options.onFailure(new Error('Billing check failed'));\n    }\n\n    logger.debug('Billing check succeeded', logContext);\n\n    return data;\n  };\n}\n","import {AdminOperations} from '@shopify/admin-api-client';\n\nimport {GraphQLClient} from '../types';\n\nimport {AdminClientOptions} from './types';\n\n// eslint-disable-next-line no-warning-comments\n// TODO: This is actually just a call through to the Shopify API client, but with a different API. We should eventually\n// move this over to the library layer. While doing that, we should also allow the apiVersion to be passed into the REST\n// client request calls.\nexport function graphqlClientFactory({\n  params,\n  handleClientError,\n  session,\n}: AdminClientOptions): GraphQLClient<AdminOperations> {\n  return async function query(operation, options) {\n    const client = new params.api.clients.Graphql({\n      session,\n      apiVersion: options?.apiVersion,\n    });\n\n    try {\n      // We convert the incoming response to a Response object to bring this client closer to the React Router client.\n      const apiResponse = await client.request(operation, {\n        variables: options?.variables,\n        retries: options?.tries ? options.tries - 1 : 0,\n        headers: options?.headers,\n        signal: options?.signal,\n      });\n\n      return new Response(JSON.stringify(apiResponse));\n    } catch (error) {\n      if (handleClientError) {\n        throw await handleClientError({error, params, session});\n      }\n\n      throw error;\n    }\n  };\n}\n","import {Session} from '@shopify/shopify-api';\n\nimport {BasicParams} from '../../types';\n\nimport {graphqlClientFactory} from './graphql';\nimport type {AdminApiContext} from './types';\n\ninterface AdminClientOptions {\n  params: BasicParams;\n  session: Session;\n  handleClientError?: (error: any) => Promise<void>;\n}\n\nexport function adminClientFactory({\n  params,\n  handleClientError,\n  session,\n}: AdminClientOptions): AdminApiContext {\n  return {\n    graphql: graphqlClientFactory({params, session, handleClientError}),\n  };\n}\n","import {Session} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport {\n  AdminApiContext,\n  HandleAdminClientError,\n  adminClientFactory,\n} from '../../../clients/admin';\n\nexport function createAdminApiContext(\n  session: Session,\n  params: BasicParams,\n  handleClientError: HandleAdminClientError,\n): AdminApiContext {\n  return adminClientFactory({\n    session,\n    params,\n    handleClientError,\n  });\n}\n","import {redirect} from '../../../helpers/redirect-response';\nimport type {BasicParams} from '../../../types';\nimport {AppDistribution} from '../../../types';\n\nexport async function redirectToShopifyOrAppRoot(\n  request: Request,\n  params: BasicParams,\n  responseHeaders?: Headers,\n): Promise<never> {\n  const {api, config} = params;\n  const url = new URL(request.url);\n\n  const host = api.utils.sanitizeHost(url.searchParams.get('host')!)!;\n  const shop = api.utils.sanitizeShop(url.searchParams.get('shop')!)!;\n\n  let redirectUrl;\n  if (config.distribution === AppDistribution.ShopifyAdmin) {\n    redirectUrl = `/?shop=${shop}&host=${encodeURIComponent(host)}`;\n  } else {\n    redirectUrl = await api.auth.getEmbeddedAppUrl({rawRequest: request});\n  }\n\n  throw redirect(redirectUrl, {headers: responseHeaders});\n}\n","import {BasicParams, AppDistribution} from '../../../types';\n\nimport {redirectToShopifyOrAppRoot} from './redirect-to-shopify-or-app-root';\n\nexport const ensureAppIsEmbeddedIfRequired = async (\n  params: BasicParams,\n  request: Request,\n) => {\n  const {api, logger, config} = params;\n  const url = new URL(request.url);\n\n  const shop = url.searchParams.get('shop')!;\n\n  if (\n    config.distribution !== AppDistribution.ShopifyAdmin &&\n    url.searchParams.get('embedded') !== '1'\n  ) {\n    logger.debug('App is not embedded, redirecting to Shopify', {shop});\n    await redirectToShopifyOrAppRoot(request, {api, logger, config});\n  }\n};\n","import {BasicParams, AppDistribution} from '../../../types';\n\nimport {redirectToBouncePage} from './redirect-to-bounce-page';\n\nconst SESSION_TOKEN_PARAM = 'id_token';\n\nexport const ensureSessionTokenSearchParamIfRequired = async (\n  params: BasicParams,\n  request: Request,\n) => {\n  const {logger, config} = params;\n  const url = new URL(request.url);\n\n  const shop = url.searchParams.get('shop')!;\n  const searchParamSessionToken = url.searchParams.get(SESSION_TOKEN_PARAM);\n  const isEmbedded = url.searchParams.get('embedded') === '1';\n\n  if (\n    config.distribution !== AppDistribution.ShopifyAdmin &&\n    isEmbedded &&\n    !searchParamSessionToken\n  ) {\n    logger.debug(\n      'Missing session token in search params, going to bounce page',\n      {shop},\n    );\n    redirectToBouncePage(params, url);\n  }\n};\n","import {HttpResponseError} from '@shopify/shopify-api';\n\nimport type {HandleAdminClientError} from '../../../clients/admin/types';\nimport {HandleClientErrorOptions} from '../strategies/types';\n\nexport function handleClientErrorFactory({\n  request,\n  onError,\n}: HandleClientErrorOptions): HandleAdminClientError {\n  return async function handleClientError({\n    error,\n    params,\n    session,\n  }): Promise<never> {\n    if (error instanceof HttpResponseError !== true) {\n      params.logger.debug(\n        `Got a response error from the API: ${error.message}`,\n        {shop: session.shop},\n      );\n      throw error;\n    }\n\n    params.logger.debug(\n      `Got an HTTP response error from the API: ${error.message}`,\n      {\n        shop: session.shop,\n        code: error.response.code,\n        statusText: error.response.statusText,\n        body: JSON.stringify(error.response.body),\n      },\n    );\n\n    if (onError) {\n      await onError({request, session, error});\n    }\n\n    // forward a minimal copy of the upstream HTTP response instead of an Error:\n    throw new Response(JSON.stringify(error.response.body), {\n      status: error.response.code,\n      headers: {\n        'Content-Type': error.response.headers!['Content-Type'] as string,\n      },\n    });\n  };\n}\n","import {REAUTH_URL_HEADER} from '../../const';\n\nexport function redirectWithAppBridgeHeaders(redirectUri: string): never {\n  throw new Response(undefined, {\n    status: 401,\n    statusText: 'Unauthorized',\n    headers: getAppBridgeHeaders(redirectUri),\n  });\n}\n\nexport function getAppBridgeHeaders(url: string) {\n  return new Headers({[REAUTH_URL_HEADER]: url});\n}\n","import {ShopifyError} from '@shopify/shopify-api';\n\ninterface Options {\n  requireSSL?: boolean;\n  throwOnInvalid?: boolean;\n}\n\ntype SanitizedRedirectUrl<OptionsArg extends Options> =\n  OptionsArg['throwOnInvalid'] extends false ? URL | undefined : URL;\n\nconst FILE_URI_MATCH = /\\/\\/\\//;\nconst INVALID_RELATIVE_URL = /[/\\\\][/\\\\]/;\nconst WHITESPACE_CHARACTER = /\\s/;\nconst VALID_PROTOCOLS = ['https:', 'http:'];\n\nfunction isSafe(\n  domain: string,\n  redirectUrl: unknown,\n  requireSSL: boolean | undefined = true,\n): redirectUrl is string {\n  if (typeof redirectUrl !== 'string') {\n    return false;\n  }\n\n  if (\n    FILE_URI_MATCH.test(redirectUrl) ||\n    WHITESPACE_CHARACTER.test(redirectUrl)\n  ) {\n    return false;\n  }\n\n  let url: URL;\n\n  try {\n    url = new URL(redirectUrl, domain);\n  } catch (error) {\n    return false;\n  }\n\n  if (INVALID_RELATIVE_URL.test(url.pathname)) {\n    return false;\n  }\n\n  if (!VALID_PROTOCOLS.includes(url.protocol)) {\n    return false;\n  }\n\n  if (requireSSL && url.protocol !== 'https:') {\n    return false;\n  }\n\n  return true;\n}\n\nexport function sanitizeRedirectUrl<OptionsArg extends Options>(\n  domain: string,\n  redirectUrl: unknown,\n  options: OptionsArg = {} as OptionsArg,\n): SanitizedRedirectUrl<OptionsArg> {\n  if (isSafe(domain, redirectUrl, options.requireSSL)) {\n    return new URL(redirectUrl, domain) as SanitizedRedirectUrl<OptionsArg>;\n  } else if (options.throwOnInvalid === false) {\n    return undefined as SanitizedRedirectUrl<OptionsArg>;\n  } else {\n    throw new ShopifyError('Invalid URL. Refusing to redirect');\n  }\n}\n","import {BasicParams, AppDistribution} from '../../../types';\nimport {appBridgeUrl} from '../../helpers/app-bridge-url';\nimport {addDocumentResponseHeaders} from '../../helpers/add-response-headers';\n\nimport {sanitizeRedirectUrl} from './validate-redirect-url';\n\nimport type {RedirectTarget} from '.';\n\nexport interface RedirectToOptions {\n  url: string | URL;\n  target?: RedirectTarget;\n}\n\nexport function renderAppBridge(\n  {config}: BasicParams,\n  request: Request,\n  redirectTo?: RedirectToOptions,\n): never {\n  let redirectToScript = '';\n  if (redirectTo) {\n    const destination = sanitizeRedirectUrl(config.appUrl, redirectTo.url);\n\n    const target = redirectTo.target ?? '_top';\n\n    redirectToScript = `<script>window.open(${JSON.stringify(\n      destination.toString(),\n    )}, ${JSON.stringify(target)})</script>`;\n  }\n\n  const responseHeaders = new Headers({\n    'content-type': 'text/html;charset=utf-8',\n  });\n  const isEmbeddedApp = config.distribution !== AppDistribution.ShopifyAdmin;\n  addDocumentResponseHeaders(\n    responseHeaders,\n    isEmbeddedApp,\n    new URL(request.url).searchParams.get('shop'),\n  );\n\n  throw new Response(\n    `\n      <script data-api-key=\"${config.apiKey}\" src=\"${appBridgeUrl()}\"></script>\n      ${redirectToScript}\n    `,\n    {headers: responseHeaders},\n  );\n}\n","import {redirect as responseRedirect} from '../../../helpers/redirect-response';\nimport {BasicParams, AppDistribution} from '../../../types';\nimport {getSessionTokenHeader} from '../../helpers/get-session-token-header';\n\nimport {renderAppBridge} from './render-app-bridge';\nimport {redirectWithAppBridgeHeaders} from './redirect-with-app-bridge-headers';\n\nexport type RedirectTarget = '_self' | '_parent' | '_top' | '_blank';\nexport type RedirectInit = number | (ResponseInit & {target?: RedirectTarget});\nexport type RedirectFunction = (url: string, init?: RedirectInit) => Response;\n\ninterface ParseURLOptions {\n  params: BasicParams;\n  url: string;\n  base: string;\n  shop: string;\n  init: RedirectInit;\n}\n\ninterface ParsedURL {\n  url: URL;\n  target: RedirectTarget;\n}\n\nexport function redirectFactory(\n  params: BasicParams,\n  request: Request,\n  shop: string,\n): RedirectFunction {\n  const {config, logger} = params;\n\n  return function redirect(url, init: RedirectInit) {\n    const {searchParams} = new URL(request.url);\n    const {url: parsedUrl, target} = parseURL({\n      params,\n      url,\n      base: config.appUrl,\n      shop,\n      init,\n    });\n\n    logger.debug('Redirecting', {shop, url: parsedUrl.toString()});\n\n    const isSameOrigin = parsedUrl.origin === new URL(config.appUrl).origin;\n    if (isSameOrigin) {\n      searchParams.forEach((value, key) => {\n        if (!parsedUrl.searchParams.has(key)) {\n          parsedUrl.searchParams.set(key, value);\n        }\n      });\n    }\n\n    if (target === '_self') {\n      if (isBounceRequest(request)) {\n        throw renderAppBridge(params, request, {\n          url: parsedUrl.toString(),\n          target,\n        });\n      } else {\n        return responseRedirect(parsedUrl.toString(), init);\n      }\n    } else if (isDataRequest(request)) {\n      throw redirectWithAppBridgeHeaders(parsedUrl.toString());\n    } else if (isEmbeddedRequest(request)) {\n      throw renderAppBridge(params, request, {\n        url: parsedUrl.toString(),\n        target,\n      });\n    }\n    return responseRedirect(url, init);\n  };\n}\n\nfunction isBounceRequest(request: Request) {\n  return (\n    Boolean(getSessionTokenHeader(request)) &&\n    request.headers.has('X-Shopify-Bounce')\n  );\n}\n\nfunction isDataRequest(request: Request) {\n  const isGet = request.method === 'GET';\n  const sessionTokenHeader = Boolean(getSessionTokenHeader(request));\n\n  return (\n    sessionTokenHeader &&\n    !isBounceRequest(request) &&\n    (!isEmbeddedRequest(request) || !isGet)\n  );\n}\n\nfunction isEmbeddedRequest(request: Request) {\n  const {searchParams} = new URL(request.url);\n\n  return searchParams.get('embedded') === '1';\n}\n\nfunction parseURL({params, base, init, shop, url}: ParseURLOptions): ParsedURL {\n  let target: RedirectTarget | undefined =\n    typeof init !== 'number' && init?.target ? init.target : undefined;\n\n  if (isAdminRemotePath(url)) {\n    const {config} = params;\n\n    const adminPath = getAdminRemotePath(url);\n    const cleanShopName = shop.replace('.myshopify.com', '');\n\n    if (!target) {\n      target =\n        config.distribution === AppDistribution.ShopifyAdmin\n          ? '_self'\n          : '_parent';\n    }\n\n    return {\n      url: new URL(\n        `https://admin.shopify.com/store/${cleanShopName}${adminPath}`,\n      ),\n      target,\n    };\n  } else {\n    return {\n      url: new URL(url, base),\n      target: target ?? '_self',\n    };\n  }\n}\n\nconst ADMIN_REGEX = /^shopify:\\/*admin\\//i;\n\nfunction isAdminRemotePath(url: string) {\n  return ADMIN_REGEX.test(url);\n}\n\nfunction getAdminRemotePath(url: string | URL) {\n  const parsedUrl = removeRestrictedParams(new URL(url)).href;\n  return parsedUrl.replace(ADMIN_REGEX, '/');\n}\n\nconst embeddedFrameParamsToRemove = [\n  'hmac',\n  'locale',\n  'protocol',\n  'session',\n  'id_token',\n  'shop',\n  'timestamp',\n  'host',\n  'embedded',\n  // sent when clicking rel=\"home\" nav item\n  'appLoadId',\n];\n\nfunction removeRestrictedParams(url: URL | string) {\n  const newUrl = new URL(url);\n  embeddedFrameParamsToRemove.forEach((param) =>\n    newUrl.searchParams.delete(param),\n  );\n  return newUrl;\n}\n","import {Session} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport {AuthorizationStrategy} from '../strategies/types';\n\nimport {createAdminApiContext} from './create-admin-api-context';\n\nexport async function triggerAfterAuthHook(\n  params: BasicParams,\n  session: Session,\n  request: Request,\n  authStrategy: AuthorizationStrategy,\n) {\n  const {config, logger} = params;\n  if (config.hooks.afterAuth) {\n    logger.info('Running afterAuth hook', {shop: session.shop});\n\n    const admin = createAdminApiContext(\n      session,\n      params,\n      authStrategy.handleClientError(request),\n    );\n\n    await config.hooks.afterAuth({\n      session,\n      admin,\n    });\n  }\n}\n","import {redirect} from '../../../helpers/redirect-response';\nimport {BasicParams, AppDistribution} from '../../../types';\n\nexport function validateShopAndHostParams(\n  params: BasicParams,\n  request: Request,\n) {\n  const {api, config, logger} = params;\n\n  if (config.distribution !== AppDistribution.ShopifyAdmin) {\n    const url = new URL(request.url);\n    const shop = api.utils.sanitizeShop(url.searchParams.get('shop')!);\n    if (!shop) {\n      logger.debug('Missing or invalid shop, redirecting to login path', {\n        shop,\n      });\n      throw redirectToLoginPath(request, params);\n    }\n\n    const host = api.utils.sanitizeHost(url.searchParams.get('host')!);\n    if (!host) {\n      logger.debug('Invalid host, redirecting to login path', {\n        shop,\n        host: url.searchParams.get('host'),\n      });\n      throw redirectToLoginPath(request, params);\n    }\n  }\n}\n\nfunction redirectToLoginPath(request: Request, params: BasicParams): never {\n  const {config, logger} = params;\n\n  const {pathname} = new URL(request.url);\n  if (pathname.endsWith(config.auth.loginPath)) {\n    const message =\n      `Detected call to shopify.authenticate.admin() from configured login path ` +\n      `('${config.auth.loginPath}'), please make sure to call shopify.login() from that route instead.`;\n\n    logger.debug(message);\n    throw new Response(message, {status: 500});\n  }\n\n  throw redirect(config.auth.loginPath);\n}\n","import {redirect} from '../../../helpers/redirect-response';\nimport {BasicParams} from '../../../types';\nimport {getAppBridgeHeaders} from '../helpers';\n\nexport function redirectOutOfApp(\n  params: BasicParams,\n  request: Request,\n  url: string,\n  shop: string,\n): never {\n  const {config, logger} = params;\n\n  logger.debug('Redirecting out of app', {shop, url});\n\n  const requestUrl = new URL(request.url);\n  const isEmbeddedRequest = requestUrl.searchParams.get('embedded') === '1';\n  const isXhrRequest = request.headers.get('authorization');\n\n  if (isXhrRequest) {\n    throw new Response(undefined, {\n      status: 401,\n      statusText: 'Unauthorized',\n      headers: getAppBridgeHeaders(url),\n    });\n  } else if (isEmbeddedRequest) {\n    const params = new URLSearchParams({\n      shop,\n      host: requestUrl.searchParams.get('host')!,\n      exitIframe: url,\n    });\n\n    throw redirect(`${config.auth.exitIframePath}?${params.toString()}`);\n  } else {\n    // This will only ever happen for non-embedded apps, because the authenticator will stop before reaching this point\n    throw redirect(url);\n  }\n}\n","import {\n  BillingRequestResponseObject,\n  HttpResponseError,\n  Session,\n} from '@shopify/shopify-api';\n\nimport {AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {\n  invalidateAccessToken,\n  respondToInvalidSessionToken,\n} from '../../helpers';\n\nimport {redirectOutOfApp} from './helpers';\nimport type {RequestBillingOptions} from './types';\n\nexport function requestBillingFactory<Config extends AppConfigArg>(\n  params: BasicParams,\n  request: Request,\n  session: Session,\n) {\n  return async function requestBilling({\n    plan,\n    isTest,\n    returnUrl,\n    ...overrides\n  }: RequestBillingOptions<Config>): Promise<never> {\n    const {api, logger} = params;\n\n    logger.info('Requesting billing', {\n      shop: session.shop,\n      plan,\n      isTest,\n      returnUrl,\n    });\n\n    let result: BillingRequestResponseObject;\n    try {\n      result = await api.billing.request({\n        plan: plan as string,\n        session,\n        isTest,\n        returnUrl,\n        returnObject: true,\n        ...overrides,\n      });\n    } catch (error) {\n      if (error instanceof HttpResponseError && error.response.code === 401) {\n        logger.debug('API token was invalid, responding to invalid session', {\n          shop: session.shop,\n        });\n\n        await invalidateAccessToken(params, session);\n\n        throw respondToInvalidSessionToken({\n          params,\n          request,\n          retryRequest: true,\n        });\n      }\n      throw error;\n    }\n\n    throw redirectOutOfApp(\n      params,\n      request,\n      result.confirmationUrl,\n      session.shop,\n    );\n  };\n}\n","import {HttpResponseError, Session} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport type {AppConfigArg} from '../../../config-types';\nimport {\n  invalidateAccessToken,\n  respondToInvalidSessionToken,\n} from '../../helpers';\n\nimport type {CheckBillingOptions} from './types';\n\nexport function checkBillingFactory<Config extends AppConfigArg>(\n  params: BasicParams,\n  request: Request,\n  session: Session,\n) {\n  return async function checkBilling(\n    options: CheckBillingOptions<Config> = {},\n  ) {\n    const {api, logger} = params;\n\n    logger.debug('Checking billing plans', {shop: session.shop, ...options});\n\n    try {\n      return await api.billing.check({\n        session,\n        plans: options.plans as string[],\n        isTest: options.isTest,\n        returnObject: true,\n      });\n    } catch (error) {\n      if (error instanceof HttpResponseError && error.response.code === 401) {\n        logger.debug('API token was invalid, responding to invalid session', {\n          shop: session.shop,\n        });\n\n        await invalidateAccessToken(params, session);\n\n        throw respondToInvalidSessionToken({\n          params,\n          request,\n          retryRequest: true,\n        });\n      }\n      throw error;\n    }\n  };\n}\n","import {HttpResponseError, Session} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport {\n  invalidateAccessToken,\n  respondToInvalidSessionToken,\n} from '../../helpers';\n\nimport type {CreateUsageRecordOptions} from './types';\n\nexport function createUsageRecordFactory(\n  params: BasicParams,\n  request: Request,\n  session: Session,\n) {\n  return async function createUsageRecord(options: CreateUsageRecordOptions) {\n    const {api, logger} = params;\n\n    logger.debug('Create usage record', {shop: session.shop, ...options});\n\n    try {\n      return await api.billing.createUsageRecord({\n        ...options,\n        session,\n      });\n    } catch (error) {\n      if (error instanceof HttpResponseError && error.response.code === 401) {\n        logger.debug('API token was invalid, responding to invalid session', {\n          shop: session.shop,\n        });\n\n        await invalidateAccessToken(params, session);\n\n        throw respondToInvalidSessionToken({\n          params,\n          request,\n          retryRequest: true,\n        });\n      }\n      throw error;\n    }\n  };\n}\n","import {\n  HttpResponseError,\n  Session,\n  UpdateCappedAmountConfirmation,\n} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport {\n  invalidateAccessToken,\n  respondToInvalidSessionToken,\n} from '../../helpers';\n\nimport {UpdateUsageCappedAmountOptions} from './types';\nimport {redirectOutOfApp} from './helpers';\n\nexport function updateUsageCappedAmountFactory(\n  params: BasicParams,\n  request: Request,\n  session: Session,\n) {\n  return async function updateUsageCappedAmount(\n    options: UpdateUsageCappedAmountOptions,\n  ): Promise<never> {\n    const {api, logger} = params;\n\n    logger.debug('Updating usage subscription capped amount', {\n      shop: session.shop,\n      ...options,\n    });\n\n    let result: UpdateCappedAmountConfirmation;\n    try {\n      result = await api.billing.updateUsageCappedAmount({\n        session,\n        subscriptionLineItemId: options.subscriptionLineItemId,\n        cappedAmount: options.cappedAmount,\n      });\n    } catch (error) {\n      if (error instanceof HttpResponseError && error.response.code === 401) {\n        logger.debug('API token was invalid, responding to invalid session', {\n          shop: session.shop,\n        });\n\n        await invalidateAccessToken(params, session);\n\n        throw respondToInvalidSessionToken({\n          params,\n          request,\n          retryRequest: true,\n        });\n      }\n      throw error;\n    }\n\n    throw redirectOutOfApp(\n      params,\n      request,\n      result.confirmationUrl,\n      session.shop,\n    );\n  };\n}\n","import {redirect as responseRedirect} from '../../../helpers/redirect-response';\nimport type {BasicParams} from '../../../types';\nimport {AppDistribution} from '../../../types';\n\nimport {redirectWithAppBridgeHeaders} from './redirect-with-app-bridge-headers';\n\nexport async function redirectToInstallPage(\n  params: BasicParams,\n  shop: string,\n  optionalScopes: string[] = [],\n): Promise<never> {\n  const installUrl = buildInstallUrl(params, shop, optionalScopes);\n  if (params.config.distribution === AppDistribution.ShopifyAdmin) {\n    throw responseRedirect(installUrl);\n  } else {\n    throw redirectWithAppBridgeHeaders(installUrl);\n  }\n}\n\nfunction buildInstallUrl(\n  params: BasicParams,\n  shop: string,\n  optionalScopes: string[] = [],\n) {\n  const baseInstallUrl = buildBaseInstallUrl(params, shop);\n  baseInstallUrl.search = buildParamsInstallUrl(\n    params,\n    optionalScopes,\n  ).toString();\n  return baseInstallUrl.href;\n}\n\nfunction buildBaseInstallUrl({api}: BasicParams, shop: string) {\n  const cleanShop = api.utils.sanitizeShop(shop, true);\n  return new URL(`https://${cleanShop}/admin/oauth/install`);\n}\n\nfunction buildParamsInstallUrl(\n  {config}: BasicParams,\n  optionalScopes: string[] = [],\n) {\n  const optionalScopesParam =\n    optionalScopes && optionalScopes.length > 0\n      ? {optional_scopes: optionalScopes.join(',')}\n      : undefined;\n\n  const query = {\n    client_id: config.apiKey,\n    scope: config.scopes?.toString() || '',\n    ...optionalScopesParam,\n  };\n  return new URLSearchParams(query);\n}\n","import {AdminApiContext} from '../../../../clients';\n\nexport interface FetchScopesDetailResponse {\n  app: {\n    requestedAccessScopes: {\n      handle: string;\n    }[];\n    optionalAccessScopes: {\n      handle: string;\n    }[];\n    installation: {\n      accessScopes: {\n        handle: string;\n      }[];\n    };\n  };\n}\n\nconst FETCH_SCOPES_DETAIL_QUERY = `#graphql\nquery FetchAccessScopes{\n  app {\n    requestedAccessScopes {\n      handle\n    }\n    optionalAccessScopes {\n      handle\n    }\n    installation {\n      accessScopes {\n        handle\n      }\n    }\n  }\n}`;\n\nexport async function fetchScopeDetail(\n  admin: AdminApiContext,\n): Promise<FetchScopesDetailResponse> {\n  const fetchScopeDetailResult = await admin.graphql(FETCH_SCOPES_DETAIL_QUERY);\n\n  const resultContent = await fetchScopeDetailResult.json();\n  return resultContent.data;\n}\n","import {AuthScopes, Session} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport {redirectToInstallPage} from '../helpers/redirect-to-install-page';\nimport {AdminApiContext} from '../../../clients';\n\nimport {fetchScopeDetail} from './client/fetch-scopes-details';\n\nexport function requestScopesFactory(\n  params: BasicParams,\n  session: Session,\n  admin: AdminApiContext,\n) {\n  return async function requestScopes(scopes: string[]) {\n    const {logger} = params;\n\n    logger.debug('Requesting optional scopes: ', {shop: session.shop, scopes});\n\n    if (scopes.length === 0) return;\n    if (await alreadyGranted(scopes, admin)) return;\n\n    throw await redirectToInstallPage(params, session.shop, scopes);\n  };\n\n  async function alreadyGranted(scopes: string[], admin: AdminApiContext) {\n    const scopesDetail = await fetchScopeDetail(admin);\n    const grantedScopes = scopesDetail.app.installation.accessScopes.map(\n      (scope) => scope.handle,\n    );\n    return new AuthScopes(grantedScopes).has(scopes);\n  }\n}\n","import {AuthScopes, Session} from '@shopify/shopify-api';\n\nimport {AdminApiContext} from '../../../clients';\nimport type {BasicParams} from '../../../types';\n\nimport {ScopesDetail} from './types';\nimport {\n  FetchScopesDetailResponse,\n  fetchScopeDetail,\n} from './client/fetch-scopes-details';\n\nexport function queryScopesFactory(\n  params: BasicParams,\n  session: Session,\n  admin: AdminApiContext,\n) {\n  return async function queryScopes() {\n    const {logger} = params;\n\n    logger.debug('Querying scopes details: ', {\n      shop: session.shop,\n    });\n\n    const scopesDetail = await fetchScopeDetail(admin);\n    return mapFetchScopeDetail(scopesDetail);\n  };\n}\n\nexport function mapFetchScopeDetail(\n  scopesDetailResponse: FetchScopesDetailResponse,\n): ScopesDetail {\n  const appInformation = scopesDetailResponse.app;\n\n  const granted = new AuthScopes(\n    appInformation.installation.accessScopes.map((scope) => scope.handle),\n  ).toArray(true);\n\n  const required = new AuthScopes(\n    appInformation.requestedAccessScopes.map((scope) => scope.handle),\n  ).toArray(true);\n\n  const optional = new AuthScopes(\n    appInformation.optionalAccessScopes.map((scope) => scope.handle),\n  ).toArray(true);\n\n  return {\n    granted,\n    required,\n    optional,\n  };\n}\n","import {AdminApiContext} from '../../../../clients';\n\nexport interface RevokeScopesResponse {\n  revoked: {\n    handle: string;\n  }[];\n  userErrors: {\n    field: string;\n    message: string;\n  }[];\n}\n\nconst REVOKE_SCOPE_MUTATION = `#graphql\nmutation AppRevokeAccessScopes($scopes: [String!]!) {\n  appRevokeAccessScopes(scopes: $scopes){\n    revoked {\n      handle\n    }\n    userErrors {\n      field\n      message\n    }\n  }\n}`;\n\nexport async function revokeScopes(\n  admin: AdminApiContext,\n  scopes: string[],\n): Promise<RevokeScopesResponse> {\n  const revokeScopesResult = await admin.graphql(REVOKE_SCOPE_MUTATION, {\n    variables: {\n      scopes,\n    },\n  });\n\n  const resultContent = await revokeScopesResult.json();\n  return resultContent.data.appRevokeAccessScopes;\n}\n","import {Session} from '@shopify/shopify-api';\n\nimport {AdminApiContext} from '../../../clients';\nimport type {BasicParams} from '../../../types';\n\nimport {revokeScopes} from './client/revoke-scopes';\n\nexport function revokeScopesFactory(\n  params: BasicParams,\n  session: Session,\n  admin: AdminApiContext,\n) {\n  return async function revoke(scopes: string[]) {\n    const {logger} = params;\n\n    await validateScopes(scopes);\n\n    logger.debug('Revoke scopes: ', {\n      shop: session.shop,\n      scopes,\n    });\n\n    const revokeScopesResult = await revokeScopes(admin, scopes);\n    if (revokeScopesResult.userErrors?.length > 0) {\n      logger.error('Failed to revoke scopes: ', {\n        shop: session.shop,\n        errors: revokeScopesResult.userErrors,\n      });\n\n      throw new Response(JSON.stringify(revokeScopesResult.userErrors), {\n        status: 422,\n        headers: {\n          'Content-Type': 'application/json',\n        },\n      });\n    }\n\n    return {\n      revoked: revokeScopesResult.revoked.map((scope) => scope.handle),\n    };\n  };\n}\n\nasync function validateScopes(scopes: string[]) {\n  if (!scopes || scopes.length === 0) {\n    throw new Response('No scopes provided', {status: 400});\n  }\n}\n","import {Session} from '@shopify/shopify-api';\n\nimport {BasicParams} from '../../../types';\nimport {AdminApiContext} from '../../../clients';\n\nimport {ScopesApiContext} from './types';\nimport {requestScopesFactory} from './request';\nimport {queryScopesFactory} from './query';\nimport {revokeScopesFactory} from './revoke';\n\nexport function scopesApiFactory(\n  params: BasicParams,\n  session: Session,\n  admin: AdminApiContext,\n): ScopesApiContext {\n  return {\n    query: queryScopesFactory(params, session, admin),\n    request: requestScopesFactory(params, session, admin),\n    revoke: revokeScopesFactory(params, session, admin),\n  };\n}\n","import {JwtPayload, Session} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../types';\nimport {AppDistribution} from '../../types';\nimport type {AppConfigArg} from '../../config-types';\nimport {\n  getSessionTokenHeader,\n  ensureCORSHeadersFactory,\n  getSessionTokenFromUrlParam,\n  respondToBotRequest,\n  respondToOptionsRequest,\n  validateSessionToken,\n  getShopFromRequest,\n} from '../helpers';\n\nimport {\n  cancelBillingFactory,\n  requestBillingFactory,\n  requireBillingFactory,\n  checkBillingFactory,\n  createUsageRecordFactory,\n  updateUsageCappedAmountFactory,\n} from './billing';\nimport type {\n  AdminContext,\n  AuthenticateAdmin,\n  EmbeddedAdminContext,\n  NonEmbeddedAdminContext,\n} from './types';\nimport {\n  createAdminApiContext,\n  ensureAppIsEmbeddedIfRequired,\n  ensureSessionTokenSearchParamIfRequired,\n  redirectFactory,\n  renderAppBridge,\n  validateShopAndHostParams,\n} from './helpers';\nimport {AuthorizationStrategy} from './strategies/types';\nimport {scopesApiFactory} from './scope/factory';\n\nexport interface SessionTokenContext {\n  shop: string;\n  sessionId?: string;\n  sessionToken?: string;\n  payload?: JwtPayload;\n}\n\ninterface AuthStrategyParams extends BasicParams {\n  strategy: AuthorizationStrategy;\n}\n\nexport function authStrategyFactory<ConfigArg extends AppConfigArg>({\n  strategy,\n  ...params\n}: AuthStrategyParams): AuthenticateAdmin<ConfigArg> {\n  const {api, logger, config} = params;\n\n  async function respondToBouncePageRequest(request: Request) {\n    const url = new URL(request.url);\n\n    if (url.pathname.endsWith(config.auth.patchSessionTokenPath)) {\n      logger.debug('Rendering bounce page', {\n        shop: getShopFromRequest(request),\n      });\n      throw renderAppBridge({config, logger, api}, request);\n    }\n  }\n\n  async function respondToExitIframeRequest(request: Request) {\n    const url = new URL(request.url);\n\n    if (url.pathname.endsWith(config.auth.exitIframePath)) {\n      const destination = url.searchParams.get('exitIframe')!;\n\n      logger.debug('Rendering exit iframe page', {\n        shop: getShopFromRequest(request),\n        destination,\n      });\n      throw renderAppBridge({config, logger, api}, request, {url: destination});\n    }\n  }\n\n  type AdminContextBase =\n    | EmbeddedAdminContext<ConfigArg>\n    | NonEmbeddedAdminContext<ConfigArg>;\n\n  function createContext(\n    request: Request,\n    session: Session,\n    authStrategy: AuthorizationStrategy,\n    sessionToken?: JwtPayload,\n  ): AdminContext<ConfigArg> {\n    let context: AdminContextBase = {\n      admin: createAdminApiContext(\n        session,\n        params,\n        authStrategy.handleClientError(request),\n      ),\n      billing: {\n        require: requireBillingFactory(params, request, session),\n        check: checkBillingFactory(params, request, session),\n        request: requestBillingFactory(params, request, session),\n        cancel: cancelBillingFactory(params, request, session),\n        createUsageRecord: createUsageRecordFactory(params, request, session),\n        updateUsageCappedAmount: updateUsageCappedAmountFactory(\n          params,\n          request,\n          session,\n        ),\n      },\n\n      session,\n      cors: ensureCORSHeadersFactory(params, request),\n    };\n\n    context = addEmbeddedFeatures(context, request, session, sessionToken);\n    context = addScopesFeatures(context);\n\n    return context as AdminContext<ConfigArg>;\n  }\n\n  function addEmbeddedFeatures(\n    context: AdminContextBase,\n    request: Request,\n    session: Session,\n    sessionToken?: JwtPayload,\n  ) {\n    if (config.distribution === AppDistribution.ShopifyAdmin) {\n      return context;\n    }\n    return {\n      ...context,\n      sessionToken,\n      redirect: redirectFactory(params, request, session.shop),\n    };\n  }\n\n  function addScopesFeatures(context: AdminContextBase) {\n    return {\n      ...context,\n      scopes: scopesApiFactory(params, context.session, context.admin),\n    };\n  }\n\n  return async function authenticateAdmin(request: Request) {\n    try {\n      respondToBotRequest(params, request);\n      respondToOptionsRequest(params, request);\n      await respondToBouncePageRequest(request);\n      await respondToExitIframeRequest(request);\n\n      // If this is a valid request, but it doesn't have a session token header, this is a document request. We need to\n      // ensure we're embedded if needed and we have the information needed to load the session.\n      if (!getSessionTokenHeader(request)) {\n        validateShopAndHostParams(params, request);\n        await ensureAppIsEmbeddedIfRequired(params, request);\n        await ensureSessionTokenSearchParamIfRequired(params, request);\n      }\n\n      logger.info('Authenticating admin request', {\n        shop: getShopFromRequest(request),\n      });\n\n      const {payload, shop, sessionId, sessionToken} =\n        await getSessionTokenContext(params, request);\n\n      logger.debug('Loading session from storage', {shop, sessionId});\n      const existingSession = sessionId\n        ? await config.sessionStorage!.loadSession(sessionId)\n        : undefined;\n\n      const session = await strategy.authenticate(request, {\n        session: existingSession,\n        sessionToken,\n        shop,\n      });\n\n      return createContext(request, session, strategy, payload);\n    } catch (errorOrResponse) {\n      if (errorOrResponse instanceof Response) {\n        logger.debug('Authenticate returned a response', {\n          shop: getShopFromRequest(request),\n        });\n        ensureCORSHeadersFactory(params, request)(errorOrResponse);\n      }\n\n      throw errorOrResponse;\n    }\n  };\n}\n\nasync function getSessionTokenContext(\n  params: BasicParams,\n  request: Request,\n): Promise<SessionTokenContext> {\n  const {api, config, logger} = params;\n\n  const headerSessionToken = getSessionTokenHeader(request);\n  const searchParamSessionToken = getSessionTokenFromUrlParam(request);\n  const sessionToken = (headerSessionToken || searchParamSessionToken)!;\n\n  logger.debug('Attempting to authenticate session token', {\n    shop: getShopFromRequest(request),\n    hasHeaderSessionToken: Boolean(headerSessionToken),\n    hasSearchParamSessionToken: Boolean(searchParamSessionToken),\n  });\n\n  if (config.distribution !== AppDistribution.ShopifyAdmin) {\n    const payload = await validateSessionToken(params, request, sessionToken);\n    const dest = new URL(payload.dest);\n    const shop = dest.hostname;\n\n    logger.debug('Session token is valid - authenticated', {shop});\n    const sessionId = config.useOnlineTokens\n      ? api.session.getJwtSessionId(shop, payload.sub)\n      : api.session.getOfflineId(shop);\n\n    return {shop, payload, sessionId, sessionToken};\n  }\n\n  const url = new URL(request.url);\n  const shop = url.searchParams.get('shop')!;\n\n  const sessionId = await api.session.getCurrentId({\n    isOnline: config.useOnlineTokens,\n    rawRequest: request,\n  });\n\n  return {shop, sessionId, payload: undefined, sessionToken};\n}\n","import {Session} from '@shopify/shopify-api';\n\nimport {BasicParams} from '../../types';\n\nimport type {StorefrontContext} from '.';\n\nexport function storefrontClientFactory({\n  params,\n  session,\n}: {\n  params: BasicParams;\n  session: Session;\n}): StorefrontContext {\n  const {api} = params;\n\n  return {\n    graphql: async (query, options = {}) => {\n      const client = new api.clients.Storefront({\n        session,\n        apiVersion: options.apiVersion,\n      });\n\n      const apiResponse = await client.request(query, {\n        variables: options?.variables,\n        retries: options?.tries ? options.tries - 1 : 0,\n        headers: options?.headers,\n      });\n\n      return new Response(JSON.stringify(apiResponse));\n    },\n  };\n}\n","import {AppDistribution, BasicParams} from '../types';\n\nexport async function createOrLoadOfflineSession(\n  {api, config, logger}: BasicParams,\n  shop: string,\n) {\n  if (config.distribution === AppDistribution.ShopifyAdmin) {\n    logger.debug('Creating custom app session from configured access token', {\n      shop,\n    });\n    return api.session.customAppSession(shop);\n  } else {\n    logger.debug('Loading offline session from session storage', {shop});\n    const offlineSessionId = api.session.getOfflineId(shop);\n    const session = await config.sessionStorage!.loadSession(offlineSessionId);\n\n    return session;\n  }\n}\n","import {\n  HttpResponseError,\n  InvalidJwtError,\n  Session,\n} from '@shopify/shopify-api';\n\nimport {BasicParams} from '../types';\n\nexport default async function refreshToken(\n  params: BasicParams,\n  shop: string,\n  refreshToken: string,\n): Promise<Session> {\n  const {api} = params;\n  try {\n    const {session} = await api.auth.refreshToken({\n      shop,\n      refreshToken,\n    });\n    return session;\n  } catch (error) {\n    if (\n      error instanceof InvalidJwtError ||\n      (error instanceof HttpResponseError &&\n        error.response.code === 400 &&\n        error.response.body?.error === 'invalid_subject_token')\n    ) {\n      throw error;\n    }\n    throw new Response(undefined, {\n      status: 500,\n      statusText: 'Internal Server Error',\n    });\n  }\n}\n","import {Session} from '@shopify/shopify-api';\n\nimport {AppDistribution, BasicParams} from '../types';\n\nimport refreshToken from './refresh-token';\n\n// 5 minutes\nexport const WITHIN_MILLISECONDS_OF_EXPIRY = 5 * 60 * 1000;\n\nexport async function ensureOfflineTokenIsNotExpired(\n  session: Session,\n  params: BasicParams,\n  shop: string,\n) {\n  const {config} = params;\n  if (\n    config.future?.expiringOfflineAccessTokens &&\n    session.isExpired(WITHIN_MILLISECONDS_OF_EXPIRY) &&\n    config.distribution !== AppDistribution.ShopifyAdmin &&\n    session.refreshToken\n  ) {\n    const offlineSession = await refreshToken(\n      params,\n      shop,\n      session.refreshToken,\n    );\n\n    await config.sessionStorage!.storeSession(offlineSession);\n    return offlineSession;\n  }\n  return session;\n}\n","import {BasicParams} from '../types';\n\nimport {createOrLoadOfflineSession} from './create-or-load-offline-session';\nimport {ensureOfflineTokenIsNotExpired} from './ensure-offline-token-is-not-expired';\n\nexport async function ensureValidOfflineSession(\n  params: BasicParams,\n  shop: string,\n) {\n  const session = await createOrLoadOfflineSession(params, shop);\n\n  if (!session) return undefined;\n\n  return ensureOfflineTokenIsNotExpired(session, params, shop);\n}\n","import {WebhookValidationErrorReason, WebhookType} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../types';\nimport {adminClientFactory} from '../../clients';\nimport {handleClientErrorFactory} from '../admin/helpers';\nimport {ensureValidOfflineSession} from '../../helpers';\n\nimport type {\n  AuthenticateWebhook,\n  WebhookContext,\n  WebhookContextWithoutSession,\n} from './types';\n\nexport function authenticateWebhookFactory<Topics extends string>(\n  params: BasicParams,\n): AuthenticateWebhook<Topics> {\n  const {api, logger} = params;\n\n  return async function authenticate(\n    request: Request,\n  ): Promise<WebhookContext<Topics>> {\n    if (request.method !== 'POST') {\n      logger.debug(\n        'Received a non-POST request for a webhook. Only POST requests are allowed.',\n        {url: request.url, method: request.method},\n      );\n      throw new Response(undefined, {\n        status: 405,\n        statusText: 'Method not allowed',\n      });\n    }\n\n    const rawBody = await request.text();\n\n    const check = await api.webhooks.validate({\n      rawBody,\n      rawRequest: request,\n    });\n\n    if (check.valid === false) {\n      if (check.reason === WebhookValidationErrorReason.InvalidHmac) {\n        logger.debug('Webhook HMAC validation failed', check);\n        throw new Response(undefined, {\n          status: 401,\n          statusText: 'Unauthorized',\n        });\n      } else {\n        logger.debug('Webhook validation failed', check);\n        throw new Response(undefined, {status: 400, statusText: 'Bad Request'});\n      }\n    }\n    const session = await ensureValidOfflineSession(params, check.domain);\n\n    let webhookContext: WebhookContextWithoutSession<Topics>;\n\n    const eventsWebhookId =\n      request.headers.get('shopify-webhook-id') ??\n      request.headers.get('X-Shopify-Webhook-Id') ??\n      check.eventId ??\n      '';\n\n    if (check.webhookType === WebhookType.Webhooks) {\n      webhookContext = {\n        apiVersion: check.apiVersion,\n        shop: check.domain,\n        topic: check.topic as Topics,\n        webhookId: check.webhookId,\n        payload: JSON.parse(rawBody),\n        subTopic: check.subTopic || undefined,\n        session: undefined,\n        admin: undefined,\n        webhookType: check.webhookType,\n        name: check.name,\n        triggeredAt: check.triggeredAt,\n        eventId: check.eventId,\n      };\n    } else {\n      webhookContext = {\n        apiVersion: check.apiVersion,\n        shop: check.domain,\n        topic: check.topic as Topics,\n        webhookId: eventsWebhookId,\n        payload: JSON.parse(rawBody),\n        session: undefined,\n        admin: undefined,\n        webhookType: check.webhookType,\n        handle: check.handle,\n        action: check.action,\n        resourceId: check.resourceId,\n        triggeredAt: check.triggeredAt,\n        eventId: check.eventId,\n      };\n    }\n\n    if (!session) {\n      return webhookContext;\n    }\n\n    const admin = adminClientFactory({\n      params,\n      session,\n      handleClientError: handleClientErrorFactory({request}),\n    });\n\n    return {\n      ...webhookContext,\n      session,\n      admin,\n    };\n  };\n}\n","import {compare} from 'compare-versions';\nimport {FeatureDeprecatedError, Shopify} from '@shopify/shopify-api';\n\nimport {SHOPIFY_REACT_ROUTER_LIBRARY_VERSION} from './version';\n\n// eslint-disable-next-line no-warning-comments\n// TODO This has been copied from shopify-app-express, it should be extracted into a shared package\n// https://github.com/orgs/Shopify/projects/6899/views/1?pane=issue&itemId=28358070\nexport function overrideLogger(logger: Shopify['logger']): Shopify['logger'] {\n  const baseContext = {package: 'shopify-app'};\n\n  const warningFunction: Shopify['logger']['warning'] = (\n    message,\n    context = {},\n  ) => logger.warning(message, {...baseContext, ...context});\n\n  function deprecated(warningFunction: Shopify['logger']['warning']) {\n    return function (version: string, message: string): Promise<void> {\n      if (compare(SHOPIFY_REACT_ROUTER_LIBRARY_VERSION, version, '>=')) {\n        throw new FeatureDeprecatedError(\n          `Feature was deprecated in version ${version}`,\n        );\n      }\n\n      return warningFunction(`[Deprecated | ${version}] ${message}`);\n    };\n  }\n\n  return {\n    ...logger,\n    log: (severity, message, context = {}) =>\n      logger.log(severity, message, {...baseContext, ...context}),\n    debug: (message, context = {}) =>\n      logger.debug(message, {...baseContext, ...context}),\n    info: (message, context = {}) =>\n      logger.info(message, {...baseContext, ...context}),\n    warning: warningFunction,\n    error: (message, context = {}) =>\n      logger.error(message, {...baseContext, ...context}),\n    deprecated: deprecated(warningFunction),\n  };\n}\n","import {redirect} from '../../helpers/redirect-response';\nimport {\n  BasicParams,\n  LoginError,\n  LoginErrorType,\n  AppDistribution,\n} from '../../types';\n\nexport function loginFactory(params: BasicParams) {\n  const {api, config, logger} = params;\n\n  return async function login(request: Request): Promise<LoginError | never> {\n    const url = new URL(request.url);\n    const shopParam = url.searchParams.get('shop');\n\n    if (request.method === 'GET' && !shopParam) {\n      return {};\n    }\n\n    const shop: string | null =\n      shopParam || ((await request.formData()).get('shop') as string);\n\n    if (!shop) {\n      logger.debug('Missing shop parameter', {shop});\n      return {shop: LoginErrorType.MissingShop};\n    }\n\n    const shopWithoutProtocol = shop\n      .replace(/^https?:\\/\\//, '')\n      .replace(/\\/$/, '');\n    const shopWithDomain =\n      shop?.indexOf('.') === -1\n        ? `${shopWithoutProtocol}.myshopify.com`\n        : shopWithoutProtocol;\n    const sanitizedShop = api.utils.sanitizeShop(shopWithDomain);\n\n    if (!sanitizedShop) {\n      logger.debug('Invalid shop parameter', {shop});\n      return {shop: LoginErrorType.InvalidShop};\n    }\n\n    const authPath = `${config.appUrl}${config.auth.path}?shop=${sanitizedShop}`;\n\n    const adminPath = api.utils.legacyUrlToShopAdminUrl(sanitizedShop);\n    const installPath = `https://${adminPath}/oauth/install?client_id=${config.apiKey}`;\n\n    const shouldInstall = config.distribution !== AppDistribution.ShopifyAdmin;\n    const redirectUrl = shouldInstall ? installPath : authPath;\n\n    logger.info(`Redirecting login request to ${redirectUrl}`, {\n      shop: sanitizedShop,\n    });\n\n    throw redirect(redirectUrl);\n  };\n}\n","import {ShopifyError} from '@shopify/shopify-api';\n\nexport class SessionNotFoundError extends ShopifyError {}\n","import {ensureValidOfflineSession} from '../../helpers';\nimport {SessionNotFoundError} from '../../errors';\nimport {BasicParams} from '../../types';\nimport {adminClientFactory} from '../../clients/admin';\n\nimport {UnauthenticatedAdminContext} from './types';\n\nexport function unauthenticatedAdminContextFactory(params: BasicParams) {\n  return async (shop: string): Promise<UnauthenticatedAdminContext> => {\n    const session = await ensureValidOfflineSession(params, shop);\n\n    if (!session) {\n      throw new SessionNotFoundError(\n        `Could not find a session for shop ${shop} when creating unauthenticated admin context`,\n      );\n    }\n\n    return {\n      session,\n      admin: adminClientFactory({params, session}),\n    };\n  };\n}\n","import {BasicParams} from '../../../types';\nimport {\n  respondToBotRequest,\n  respondToOptionsRequest,\n  getSessionTokenHeader,\n  validateSessionToken,\n  ensureCORSHeadersFactory,\n  getShopFromRequest,\n} from '../../helpers';\n\nimport {AuthenticateExtension, ExtensionContext} from './types';\n\nexport function authenticateExtensionFactory(\n  params: BasicParams,\n  requestType: string,\n): AuthenticateExtension {\n  return async function authenticateExtension(\n    request,\n    options = {},\n  ): Promise<ExtensionContext> {\n    const {logger} = params;\n\n    const corsHeaders = options.corsHeaders ?? [];\n\n    respondToBotRequest(params, request);\n    respondToOptionsRequest(params, request, corsHeaders);\n\n    const sessionTokenHeader = getSessionTokenHeader(request);\n\n    logger.info(`Authenticating ${requestType} request`, {\n      shop: getShopFromRequest(request),\n    });\n\n    if (!sessionTokenHeader) {\n      logger.debug('Request did not contain a session token', {\n        shop: getShopFromRequest(request),\n      });\n      throw new Response(undefined, {\n        status: 401,\n        statusText: 'Unauthorized',\n      });\n    }\n\n    return {\n      sessionToken: await validateSessionToken(\n        params,\n        request,\n        sessionTokenHeader,\n        {checkAudience: false, retryRequest: false},\n      ),\n      cors: ensureCORSHeadersFactory(params, request, corsHeaders),\n    };\n  };\n}\n","import type {BasicParams} from '../../../types';\nimport {authenticateExtensionFactory} from '../extension/authenticate';\n\nimport type {AuthenticateCheckout} from './types';\n\nexport function authenticateCheckoutFactory(\n  params: BasicParams,\n): AuthenticateCheckout {\n  return authenticateExtensionFactory(\n    params,\n    'checkout',\n  ) as AuthenticateCheckout;\n}\n","import {adminClientFactory, storefrontClientFactory} from '../../../clients';\nimport {ensureValidOfflineSession} from '../../../helpers';\nimport {BasicParams} from '../../../types';\n\nimport {\n  AppProxyContext,\n  AppProxyContextWithSession,\n  AuthenticateAppProxy,\n  LiquidResponseFunction,\n} from './types';\n\nexport function authenticateAppProxyFactory(\n  params: BasicParams,\n): AuthenticateAppProxy {\n  const {logger} = params;\n\n  return async function authenticate(\n    request: Request,\n  ): Promise<AppProxyContext | AppProxyContextWithSession> {\n    const url = new URL(request.url);\n    const shop = url.searchParams.get('shop')!;\n    logger.info('Authenticating app proxy request', {shop});\n\n    if (!(await validateAppProxyHmac(params, url))) {\n      logger.info('App proxy request has invalid signature', {shop});\n      throw new Response(undefined, {\n        status: 400,\n        statusText: 'Bad Request',\n      });\n    }\n\n    const session = await ensureValidOfflineSession(params, shop);\n\n    if (!session) {\n      logger.debug('Could not find offline session, returning empty context', {\n        shop,\n        ...Object.fromEntries(url.searchParams.entries()),\n      });\n\n      const context: AppProxyContext = {\n        liquid,\n        session: undefined,\n        admin: undefined,\n        storefront: undefined,\n      };\n\n      return context;\n    }\n\n    const context: AppProxyContextWithSession = {\n      liquid,\n      session,\n      admin: adminClientFactory({params, session}),\n      storefront: storefrontClientFactory({params, session}),\n    };\n\n    return context;\n  };\n}\n\nconst liquid: LiquidResponseFunction = (body, initAndOptions) => {\n  const processedBody = processLiquidBody(body);\n\n  if (typeof initAndOptions !== 'object') {\n    return new Response(processedBody, {\n      status: initAndOptions || 200,\n      headers: {\n        'Content-Type': 'application/liquid',\n      },\n    });\n  }\n\n  const {layout, ...responseInit} = initAndOptions || {};\n  const responseBody =\n    layout === false ? `{% layout none %} ${processedBody}` : processedBody;\n\n  const headers = new Headers(responseInit.headers);\n  headers.set('Content-Type', 'application/liquid');\n\n  return new Response(responseBody, {\n    ...responseInit,\n    headers,\n  });\n};\n\nasync function validateAppProxyHmac(\n  params: BasicParams,\n  url: URL,\n): Promise<boolean> {\n  const {api, logger} = params;\n\n  try {\n    let searchParams = new URLSearchParams(url.search);\n    if (!searchParams.get('index')) {\n      searchParams.delete('index');\n    }\n\n    let isValid = await api.utils.validateHmac(\n      Object.fromEntries(searchParams.entries()),\n      {signator: 'appProxy'},\n    );\n\n    if (!isValid) {\n      const cleanPath = url.pathname\n        .replace(/^\\//, '')\n        .replace(/\\/$/, '')\n        .replaceAll('/', '.');\n      const data = `routes%2F${cleanPath}`;\n\n      searchParams = new URLSearchParams(\n        `?_data=${data}&${searchParams.toString().replace(/^\\?/, '')}`,\n      );\n\n      isValid = await api.utils.validateHmac(\n        Object.fromEntries(searchParams.entries()),\n        {signator: 'appProxy'},\n      );\n\n      if (!isValid) {\n        const searchParams = new URLSearchParams(\n          `?_data=${data}._index&${url.search.replace(/^\\?/, '')}`,\n        );\n\n        isValid = await api.utils.validateHmac(\n          Object.fromEntries(searchParams.entries()),\n          {signator: 'appProxy'},\n        );\n      }\n    }\n\n    return isValid;\n  } catch (error) {\n    const shop = url.searchParams.get('shop')!;\n    logger.info(error.message, {shop});\n    throw new Response(undefined, {status: 400, statusText: 'Bad Request'});\n  }\n}\n\nfunction processLiquidBody(body: string) {\n  return (\n    body\n      // Add trailing slashes to relative form action URLs\n      .replaceAll(\n        /<(form[^>]+)action=\"(\\/[^\"?]+)(\\?[^\"]+)?\">/g,\n        '<$1action=\"$2/$3\">',\n      )\n      // Add trailing slashes to relative link href URLs\n      .replaceAll(/<(a[^>]+)href=\"(\\/[^\"?]+)(\\?[^\"]+)?\">/g, '<$1href=\"$2/$3\">')\n  );\n}\n","import {BasicParams} from '../../../types';\nimport {authenticateExtensionFactory} from '../extension/authenticate';\n\nimport {AuthenticateCustomerAccount} from './types';\n\nexport function authenticateCustomerAccountFactory(\n  params: BasicParams,\n): AuthenticateCustomerAccount {\n  return authenticateExtensionFactory(\n    params,\n    'customer account',\n  ) as AuthenticateCustomerAccount;\n}\n","import {BasicParams} from '../../types';\n\nimport {authenticateCheckoutFactory} from './checkout/authenticate';\nimport {authenticateAppProxyFactory} from './appProxy/authenticate';\nimport {authenticateCustomerAccountFactory} from './customer-account/authenticate';\nimport {AuthenticatePublic} from './types';\n\nexport function authenticatePublicFactory(params: BasicParams) {\n  const authenticateCheckout = authenticateCheckoutFactory(params);\n  const authenticateAppProxy = authenticateAppProxyFactory(params);\n  const authenticateCustomerAccount =\n    authenticateCustomerAccountFactory(params);\n\n  const context: AuthenticatePublic = {\n    checkout: authenticateCheckout,\n    appProxy: authenticateAppProxy,\n    customerAccount: authenticateCustomerAccount,\n  };\n\n  return context;\n}\n","import {SessionNotFoundError} from '../../errors';\nimport {BasicParams} from '../../types';\nimport {storefrontClientFactory} from '../../clients/storefront';\nimport {ensureValidOfflineSession} from '../../helpers';\n\nimport {\n  UnauthenticatedStorefrontContext,\n  GetUnauthenticatedStorefrontContext,\n} from './types';\n\nexport function unauthenticatedStorefrontContextFactory(\n  params: BasicParams,\n): GetUnauthenticatedStorefrontContext {\n  return async (shop: string): Promise<UnauthenticatedStorefrontContext> => {\n    const session = await ensureValidOfflineSession(params, shop);\n\n    if (!session) {\n      throw new SessionNotFoundError(\n        `Could not find a session for shop ${shop} when creating unauthenticated storefront context`,\n      );\n    }\n\n    return {\n      session,\n      storefront: storefrontClientFactory({params, session}),\n    };\n  };\n}\n","import {\n  HttpResponseError,\n  InvalidJwtError,\n  RequestedTokenType,\n  Session,\n} from '@shopify/shopify-api';\n\nimport {AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {\n  respondToInvalidSessionToken,\n  invalidateAccessToken,\n  getShopFromRequest,\n} from '../../helpers';\nimport {handleClientErrorFactory, triggerAfterAuthHook} from '../helpers';\nimport {HandleAdminClientError} from '../../../clients';\nimport {WITHIN_MILLISECONDS_OF_EXPIRY} from '../../../helpers';\n\nimport {\n  AuthorizationStrategy,\n  SessionContext,\n  OnErrorOptions,\n  AuthStrategyFactory,\n} from './types';\n\nexport const createTokenExchangeStrategy: AuthStrategyFactory<any> = <\n  Config extends AppConfigArg,\n>(\n  params: BasicParams<Config['future']>,\n): AuthorizationStrategy => {\n  const {api, config, logger} = params;\n\n  async function exchangeToken({\n    request,\n    shop,\n    sessionToken,\n    requestedTokenType,\n  }: {\n    request: Request;\n    shop: string;\n    sessionToken: string;\n    requestedTokenType: RequestedTokenType;\n  }): Promise<{session: Session}> {\n    try {\n      console.log(\n        'config.future.expiringOfflineAccessTokens',\n        config.future.expiringOfflineAccessTokens,\n      );\n      return await api.auth.tokenExchange({\n        sessionToken,\n        shop,\n        requestedTokenType,\n        expiring: config.future.expiringOfflineAccessTokens,\n      });\n    } catch (error) {\n      if (\n        error instanceof InvalidJwtError ||\n        (error instanceof HttpResponseError &&\n          error.response.code === 400 &&\n          error.response.body?.error === 'invalid_subject_token')\n      ) {\n        throw respondToInvalidSessionToken({\n          params: {api, config, logger},\n          request,\n          retryRequest: true,\n        });\n      }\n\n      throw new Response(undefined, {\n        status: 500,\n        statusText: 'Internal Server Error',\n      });\n    }\n  }\n\n  async function handleAfterAuthHook(\n    session: Session,\n    request: Request,\n    sessionToken: string,\n  ) {\n    await config.idempotentPromiseHandler.handlePromise({\n      promiseFunction: () => {\n        return triggerAfterAuthHook(params, session, request, {\n          authenticate,\n          handleClientError,\n        });\n      },\n      identifier: sessionToken,\n    });\n  }\n\n  async function authenticate(\n    request: Request,\n    sessionContext: SessionContext,\n  ): Promise<Session> {\n    const {shop, session, sessionToken} = sessionContext;\n\n    if (!sessionToken) throw new InvalidJwtError();\n\n    if (\n      !session ||\n      !session.isActive(undefined, WITHIN_MILLISECONDS_OF_EXPIRY)\n    ) {\n      logger.info('No valid session found', {shop});\n      logger.info('Requesting offline access token', {shop});\n      const {session: offlineSession} = await exchangeToken({\n        request,\n        sessionToken,\n        shop,\n        requestedTokenType: RequestedTokenType.OfflineAccessToken,\n      });\n\n      await config.sessionStorage!.storeSession(offlineSession);\n\n      let newSession = offlineSession;\n\n      if (config.useOnlineTokens) {\n        logger.info('Requesting online access token', {shop});\n        const {session: onlineSession} = await exchangeToken({\n          request,\n          sessionToken,\n          shop,\n          requestedTokenType: RequestedTokenType.OnlineAccessToken,\n        });\n\n        await config.sessionStorage!.storeSession(onlineSession);\n        newSession = onlineSession;\n      }\n\n      logger.debug('Request is valid, loaded session from session token', {\n        shop: newSession.shop,\n        isOnline: newSession.isOnline,\n      });\n\n      try {\n        await handleAfterAuthHook(newSession, request, sessionToken);\n      } catch (errorOrResponse) {\n        if (errorOrResponse instanceof Response) {\n          throw errorOrResponse;\n        }\n\n        throw new Response(undefined, {\n          status: 500,\n          statusText: 'Internal Server Error',\n        });\n      }\n\n      return newSession;\n    }\n\n    return session!;\n  }\n\n  function handleClientError(request: Request): HandleAdminClientError {\n    return handleClientErrorFactory({\n      request,\n      onError: async ({session, error}: OnErrorOptions) => {\n        if (error.response.code === 401) {\n          logger.debug('Responding to invalid access token', {\n            shop: getShopFromRequest(request),\n          });\n          await invalidateAccessToken({config, api, logger}, session);\n\n          respondToInvalidSessionToken({\n            params: {config, api, logger},\n            request,\n          });\n        }\n      },\n    });\n  }\n\n  return {\n    authenticate,\n    handleClientError,\n  };\n};\n","import {Session, ShopifyError} from '@shopify/shopify-api';\n\nimport {AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {HandleAdminClientError} from '../../../clients';\nimport {handleClientErrorFactory} from '../helpers';\n\nimport {\n  AuthorizationStrategy,\n  OnErrorOptions,\n  SessionContext,\n  AuthStrategyFactory,\n} from './types';\n\nexport const createMerchantCustomAuthStrategy: AuthStrategyFactory<any> = <\n  Config extends AppConfigArg,\n>(\n  params: BasicParams<Config['future']>,\n): AuthorizationStrategy => {\n  const {api, logger} = params;\n\n  async function authenticate(\n    _request: Request,\n    sessionContext: SessionContext,\n  ): Promise<Session | never> {\n    const {shop} = sessionContext;\n\n    logger.debug(\n      'Building session from configured access token for merchant custom app',\n      {shop},\n    );\n    const session = api.session.customAppSession(shop);\n\n    return session;\n  }\n\n  function handleClientError(request: Request): HandleAdminClientError {\n    return handleClientErrorFactory({\n      request,\n      onError: async ({error}: OnErrorOptions) => {\n        if (error.response.code === 401) {\n          logger.info(\n            'Request failed with 401. Review your API credentials or generate new tokens. https://shopify.dev/docs/apps/build/authentication-authorization/access-token-types/generate-app-access-tokens-admin#rotating-api-credentials-for-admin-created-apps ',\n          );\n          throw new ShopifyError(\n            'Unauthorized: Access token has been revoked.',\n          );\n        }\n      },\n    });\n  }\n\n  return {\n    authenticate,\n    handleClientError,\n  };\n};\n","export interface IdempotentHandlePromiseParams {\n  promiseFunction: () => Promise<any>;\n  identifier: string;\n}\n\nconst IDENTIFIER_TTL_MS = 60000;\n\nexport class IdempotentPromiseHandler {\n  protected identifiers: Map<string, number>;\n\n  constructor() {\n    this.identifiers = new Map<string, number>();\n  }\n\n  async handlePromise({\n    promiseFunction,\n    identifier,\n  }: IdempotentHandlePromiseParams): Promise<any> {\n    try {\n      if (this.isPromiseRunnable(identifier)) {\n        await promiseFunction();\n      }\n    } finally {\n      this.clearStaleIdentifiers();\n    }\n\n    return Promise.resolve();\n  }\n\n  private isPromiseRunnable(identifier: string) {\n    if (!this.identifiers.has(identifier)) {\n      this.identifiers.set(identifier, Date.now());\n      return true;\n    }\n    return false;\n  }\n\n  private async clearStaleIdentifiers() {\n    this.identifiers.forEach((date, identifier, map) => {\n      if (Date.now() - date > IDENTIFIER_TTL_MS) {\n        map.delete(identifier);\n      }\n    });\n  }\n}\n","import {adminClientFactory} from '../../clients/admin';\nimport {ensureValidOfflineSession} from '../../helpers';\nimport {BasicParams} from '../../types';\n\nimport type {AuthenticateFlow, FlowContext} from './types';\n\nexport function authenticateFlowFactory(params: BasicParams): AuthenticateFlow {\n  const {api, logger} = params;\n\n  return async function authenticate(request: Request): Promise<FlowContext> {\n    logger.info('Authenticating flow request');\n\n    if (request.method !== 'POST') {\n      logger.debug(\n        'Received a non-POST request for flow. Only POST requests are allowed.',\n        {url: request.url, method: request.method},\n      );\n      throw new Response(undefined, {\n        status: 405,\n        statusText: 'Method not allowed',\n      });\n    }\n\n    const rawBody = await request.text();\n    const result = await api.flow.validate({\n      rawBody,\n      rawRequest: request,\n    });\n\n    if (result.valid === false) {\n      logger.error('Received an invalid flow request', {reason: result.reason});\n\n      throw new Response(undefined, {\n        status: 400,\n        statusText: 'Bad Request',\n      });\n    }\n\n    const payload = JSON.parse(rawBody);\n\n    logger.debug('Flow request is valid, looking for an offline session', {\n      shop: payload.shopify_domain,\n    });\n\n    const session = await ensureValidOfflineSession(\n      params,\n      payload.shopify_domain,\n    );\n\n    if (!session) {\n      logger.info('Flow request could not find session', {\n        shop: payload.shopify_domain,\n      });\n      throw new Response(undefined, {\n        status: 400,\n        statusText: 'Bad Request',\n      });\n    }\n\n    logger.debug('Found a session for the flow request', {shop: session.shop});\n\n    return {\n      session,\n      payload,\n      admin: adminClientFactory({params, session}),\n    };\n  };\n}\n","import {ShopifyHeader} from '@shopify/shopify-api';\n\nimport {adminClientFactory} from '../../clients/admin';\nimport {BasicParams} from '../../types';\nimport {ensureValidOfflineSession} from '../../helpers';\n\nimport type {\n  AuthenticateFulfillmentService,\n  FulfillmentServiceContext,\n} from './types';\n\nexport function authenticateFulfillmentServiceFactory(\n  params: BasicParams,\n): AuthenticateFulfillmentService {\n  const {api, logger} = params;\n\n  return async function authenticate(\n    request: Request,\n  ): Promise<FulfillmentServiceContext> {\n    logger.info('Authenticating fulfillment service request');\n\n    if (request.method !== 'POST') {\n      logger.debug(\n        'Received a non-POST request for fulfillment service. Only POST requests are allowed.',\n        {url: request.url, method: request.method},\n      );\n      throw new Response(undefined, {\n        status: 405,\n        statusText: 'Method not allowed',\n      });\n    }\n\n    const rawBody = await request.text();\n    const result = await api.fulfillmentService.validate({\n      rawBody,\n      rawRequest: request,\n    });\n\n    if (result.valid === false) {\n      logger.error('Received an invalid fulfillment service request', {\n        reason: result.reason,\n      });\n\n      throw new Response(undefined, {\n        status: 400,\n        statusText: 'Bad Request',\n      });\n    }\n\n    const payload = JSON.parse(rawBody);\n    const shop = request.headers.get(ShopifyHeader.Domain) || '';\n\n    logger.debug(\n      'Fulfillment service request is valid, looking for an offline session',\n      {\n        shop,\n      },\n    );\n\n    const session = await ensureValidOfflineSession(params, shop);\n\n    if (!session) {\n      logger.info('Fulfillment service request could not find session', {\n        shop,\n      });\n      throw new Response(undefined, {\n        status: 400,\n        statusText: 'Bad Request',\n      });\n    }\n\n    logger.debug('Found a session for the fulfillment service request', {\n      shop,\n    });\n\n    return {\n      session,\n      payload,\n      admin: adminClientFactory({params, session}),\n    };\n  };\n}\n","import {BasicParams} from '../../types';\nimport {authenticateExtensionFactory} from '../public/extension/authenticate';\n\nimport type {AuthenticatePOS} from './types';\n\nexport function authenticatePOSFactory(params: BasicParams): AuthenticatePOS {\n  return authenticateExtensionFactory(params, 'pos') as AuthenticatePOS;\n}\n","import type {ConfigParams, Shopify} from '@shopify/shopify-api';\n\nimport type {AppConfig} from '../config-types';\n\n// When adding new flags, you should also add them to the `TEST_FUTURE_FLAGS` object in `test-config.ts` to ensure that\n// it doesn't cause regressions.\n/**\n * Set future flags using the `future` configuration field to opt in to upcoming breaking changes.\n *\n * With this feature, you can prepare for major releases ahead of time, as well as try out new features before they are released.\n * @publicDocs\n */\nexport interface FutureFlags {\n  /**\n   * When enabled, the app will start using expiring offline access tokens and automatically refresh them when they are close to expiring.\n   *\n   * @default false\n   */\n  expiringOfflineAccessTokens?: boolean;\n}\n\n// When adding new flags, use this format:\n// apiFutureFlag: Future extends FutureFlags ? Future['reactRouterFutureFlag'] : false;\nexport interface ApiFutureFlags<Future extends FutureFlagOptions> {\n  expiringOfflineAccessTokens: Future extends FutureFlags\n    ? Future['expiringOfflineAccessTokens']\n    : false;\n  unstable_managedPricingSupport: true;\n}\n\nexport type ApiConfigWithFutureFlags<Future extends FutureFlagOptions> =\n  ConfigParams<ApiFutureFlags<Future>>;\n\nexport type FutureFlagOptions = FutureFlags | undefined;\n\nexport type FeatureEnabled<\n  Future extends FutureFlagOptions,\n  Flag extends keyof FutureFlags,\n> = Future extends FutureFlags\n  ? Future[Flag] extends true\n    ? true\n    : false\n  : false;\n\nexport function logDisabledFutureFlags(\n  _config: AppConfig,\n  _logger: Shopify['logger'],\n) {\n  // When future flags are added to the FutureFlags interface, add logging here\n  // Example:\n  // const logFlag = (flag: string, message: string) =>\n  //   _logger.info(`Future flag ${flag} is disabled.\\n\\n  ${message}\\n`);\n  //\n  // if (!_config.future.someFutureFlag) {\n  //   logFlag('someFutureFlag', 'Description of what this flag enables');\n  // }\n}\n","import '@shopify/shopify-api/adapters/web-api';\nimport {\n  ConfigInterface as ApiConfig,\n  ShopifyError,\n  shopifyApi,\n} from '@shopify/shopify-api';\nimport {SessionStorage} from '@shopify/shopify-app-session-storage';\n\nimport {type AppConfig, type AppConfigArg} from './config-types';\nimport {\n  AppDistribution,\n  type BasicParams,\n  type ShopifyApp,\n  type ShopifyAppBase,\n  type AdminApp,\n  type SingleMerchantApp,\n  type AppStoreApp,\n} from './types';\nimport {SHOPIFY_REACT_ROUTER_LIBRARY_VERSION} from './version';\nimport {registerWebhooksFactory} from './authenticate/webhooks';\nimport {authStrategyFactory} from './authenticate/admin/authenticate';\nimport {authenticateWebhookFactory} from './authenticate/webhooks/authenticate';\nimport {overrideLogger} from './override-logger';\nimport {addDocumentResponseHeadersFactory} from './authenticate/helpers';\nimport {loginFactory} from './authenticate/login/login';\nimport {unauthenticatedAdminContextFactory} from './unauthenticated/admin';\nimport {authenticatePublicFactory} from './authenticate/public';\nimport {unauthenticatedStorefrontContextFactory} from './unauthenticated/storefront';\nimport {createTokenExchangeStrategy} from './authenticate/admin/strategies/token-exchange';\nimport {createMerchantCustomAuthStrategy} from './authenticate/admin/strategies/merchant-custom-app';\nimport {IdempotentPromiseHandler} from './authenticate/helpers/idempotent-promise-handler';\nimport {authenticateFlowFactory} from './authenticate/flow/authenticate';\nimport {authenticateFulfillmentServiceFactory} from './authenticate/fulfillment-service/authenticate';\nimport {authenticatePOSFactory} from './authenticate/pos/authenticate';\nimport {FutureFlagOptions, logDisabledFutureFlags} from './future/flags';\n\n/**\n * Creates an object your app will use to interact with Shopify.\n *\n * @param appConfig Configuration options for your Shopify app, such as the scopes your app needs.\n * @returns `ShopifyApp` An object constructed using your appConfig.  It has methods for interacting with Shopify.\n * @publicDocs\n *\n * @example\n * <caption>The minimum viable configuration</caption>\n * ```ts\n * // /shopify.server.ts\n * import { shopifyApp } from \"@yan-ad/shopify-app-tanstack/server\";\n *\n * const shopify = shopifyApp({\n *   apiKey: process.env.SHOPIFY_API_KEY!,\n *   apiSecretKey: process.env.SHOPIFY_API_SECRET!,\n *   scopes: process.env.SCOPES?.split(\",\")!,\n *   appUrl: process.env.SHOPIFY_APP_URL!,\n * });\n * export default shopify;\n * ```\n */\nexport function shopifyApp<\n  Config extends AppConfigArg<Storage, Future>,\n  Storage extends SessionStorage,\n  Future extends FutureFlagOptions = Config['future'],\n>(appConfig: Readonly<Config>): ShopifyApp<Config> {\n  const api = deriveApi(appConfig);\n  const config = deriveConfig<Storage>(appConfig, api.config);\n  const logger = overrideLogger(api.logger);\n\n  if (appConfig.webhooks) {\n    api.webhooks.addHandlers(appConfig.webhooks);\n  }\n\n  const params: BasicParams = {api, config, logger};\n\n  let strategy;\n  if (config.distribution === AppDistribution.ShopifyAdmin) {\n    strategy = createMerchantCustomAuthStrategy(params);\n  } else {\n    strategy = createTokenExchangeStrategy(params);\n  }\n\n  const authStrategy = authStrategyFactory({\n    ...params,\n    strategy,\n  });\n\n  const shopify:\n    | AdminApp<Config>\n    | AppStoreApp<Config>\n    | SingleMerchantApp<Config> = {\n    sessionStorage: config.sessionStorage,\n    addDocumentResponseHeaders: addDocumentResponseHeadersFactory(params),\n    registerWebhooks: registerWebhooksFactory(params),\n    authenticate: {\n      admin: authStrategy,\n      flow: authenticateFlowFactory(params),\n      fulfillmentService: authenticateFulfillmentServiceFactory(params),\n      pos: authenticatePOSFactory(params),\n      public: authenticatePublicFactory(params),\n      webhook: authenticateWebhookFactory<string>(params),\n    },\n    unauthenticated: {\n      admin: unauthenticatedAdminContextFactory(params),\n      storefront: unauthenticatedStorefrontContextFactory(params),\n    },\n  };\n\n  if (\n    isAppStoreApp(shopify, appConfig) ||\n    isSingleMerchantApp(shopify, appConfig)\n  ) {\n    shopify.login = loginFactory(params);\n  }\n\n  logDisabledFutureFlags(config, logger);\n\n  return shopify as ShopifyApp<Config>;\n}\n\nfunction isAppStoreApp<Config extends AppConfigArg>(\n  _shopify: ShopifyAppBase<Config>,\n  config: Config,\n): _shopify is AppStoreApp<Config> {\n  return config.distribution === AppDistribution.AppStore;\n}\n\nfunction isSingleMerchantApp<Config extends AppConfigArg>(\n  _shopify: ShopifyAppBase<Config>,\n  config: Config,\n): _shopify is SingleMerchantApp<Config> {\n  return config.distribution === AppDistribution.SingleMerchant;\n}\n\n// This function is only exported so we can unit test it without having to mock the underlying module.\n// It's not available to consumers of the library because it is not exported in the index module, and never should be.\nexport function deriveApi(appConfig: AppConfigArg): BasicParams['api'] {\n  let appUrl: URL;\n  try {\n    appUrl = new URL(appConfig.appUrl);\n  } catch (error) {\n    const message =\n      appConfig.appUrl === ''\n        ? `Detected an empty appUrl configuration, please make sure to set the necessary environment variables.\\n` +\n          `If you're deploying your app, you can find more information at https://shopify.dev/docs/apps/launch/deployment/deploy-web-app/deploy-to-hosting-service#step-4-set-up-environment-variables`\n        : `Invalid appUrl configuration '${appConfig.appUrl}', please provide a valid URL.`;\n    throw new ShopifyError(message);\n  }\n\n  /* eslint-disable no-process-env */\n  if (appUrl.hostname === 'localhost' && !appUrl.port && process.env.PORT) {\n    appUrl.port = process.env.PORT;\n  }\n  /* eslint-enable no-process-env */\n  appConfig.appUrl = appUrl.origin;\n\n  let userAgentPrefix = `TanStack Router Library v${SHOPIFY_REACT_ROUTER_LIBRARY_VERSION}`;\n  if (appConfig.userAgentPrefix) {\n    userAgentPrefix = `${appConfig.userAgentPrefix} | ${userAgentPrefix}`;\n  }\n\n  return shopifyApi({\n    ...appConfig,\n    hostName: appUrl.host,\n    hostScheme: appUrl.protocol.replace(':', '') as 'http' | 'https',\n    userAgentPrefix,\n    isEmbeddedApp: true,\n    isCustomStoreApp: appConfig.distribution === AppDistribution.ShopifyAdmin,\n    billing: appConfig.billing,\n    future: {\n      unstable_managedPricingSupport: true,\n    },\n    _logDisabledFutureFlags: false,\n  });\n}\n\nfunction deriveConfig<Storage extends SessionStorage>(\n  appConfig: AppConfigArg,\n  apiConfig: ApiConfig,\n): AppConfig<Storage> {\n  if (\n    !appConfig.sessionStorage &&\n    appConfig.distribution !== AppDistribution.ShopifyAdmin\n  ) {\n    throw new ShopifyError(\n      'Please provide a valid session storage. Refer to https://github.com/yanuaraditia/shopify-app-tanstack/blob/main/README.md#session-storage-options for options.',\n    );\n  }\n\n  const authPathPrefix = appConfig.authPathPrefix || '/auth';\n  appConfig.distribution = appConfig.distribution ?? AppDistribution.AppStore;\n\n  return {\n    ...appConfig,\n    ...apiConfig,\n    billing: appConfig.billing,\n    scopes: apiConfig.scopes,\n    idempotentPromiseHandler: new IdempotentPromiseHandler(),\n    canUseLoginForm: appConfig.distribution !== AppDistribution.ShopifyAdmin,\n    useOnlineTokens: appConfig.useOnlineTokens ?? false,\n    hooks: appConfig.hooks ?? {},\n    sessionStorage: appConfig.sessionStorage as Storage,\n    future: appConfig.future ?? {},\n    auth: {\n      path: authPathPrefix,\n      callbackPath: `${authPathPrefix}/callback`,\n      patchSessionTokenPath: `${authPathPrefix}/session-token`,\n      exitIframePath: `${authPathPrefix}/exit-iframe`,\n      loginPath: `${authPathPrefix}/login`,\n    },\n    distribution: appConfig.distribution,\n  };\n}\n","import '@shopify/shopify-api/adapters/web-api';\nimport {setAbstractRuntimeString} from '@shopify/shopify-api/runtime';\n\nsetAbstractRuntimeString(() => {\n  return `React Router`;\n});\n\nexport {\n  LogSeverity,\n  DeliveryMethod,\n  BillingInterval,\n  BillingReplacementBehavior,\n  ApiVersion,\n  Session,\n} from '@shopify/shopify-api';\n\nexport type {JwtPayload} from '@shopify/shopify-api';\n\nexport type * from './types-contexts';\nexport type {ShopifyApp, LoginError} from './types';\nexport {LoginErrorType, AppDistribution} from './types';\nexport {boundary} from './boundary';\nexport {shopifyApp} from './shopify-app';\nexport * from './errors';\n"],"mappings":"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"}