{"version":3,"file":"chunk.deprecated-shop-login-button_DB7rWF6e.esm.js","sources":["../../../src/__deprecated__/constants/loginDefault.ts","../../../src/__deprecated__/common/utils/isCompactLayout.ts","../../../src/__deprecated__/common/constants.ts","../../../src/__deprecated__/common/bugsnag/constants.ts","../../../src/__deprecated__/common/bugsnag/utils.ts","../../../src/__deprecated__/common/bugsnag/index.ts","../../../src/__deprecated__/common/logging.ts","../../../src/__deprecated__/common/translator/i18n.ts","../../../src/__deprecated__/common/utils/utils.ts","../../../src/__deprecated__/common/utils/position.behavior.ts","../../../src/__deprecated__/common/utils/shopHub.ts","../../../src/__deprecated__/dynamicImports/opentelemetry/metrics.ts","../../../src/__deprecated__/common/utils/errors.ts","../../../src/__deprecated__/dynamicImports/opentelemetry/options.ts","../../../src/__deprecated__/dynamicImports/opentelemetry/singleton.ts","../../../src/__deprecated__/dynamicImports/opentelemetry/opentelemetry.ts","../../../src/__deprecated__/dynamicImports/opentelemetry/record.ts","../../../src/__deprecated__/common/utils/urls.ts","../../../src/__deprecated__/constants/loginButton.ts"],"sourcesContent":["/**\n * The default/standalone component is used for multiple flows. To disambiguate the flow for\n * analytics, we pass in an analytics context to the component. The \"flow\" here is specific\n * to the use-case, whereas the flow we pass to the authorize endpoint is more generic and\n * determines what (if any) side effects should happen after the user is authenticated.\n *\n * NOTE: The context name needs to be match those allow-listed in Pay.\n */\nexport enum DefaultComponentAnalyticsContext {\n Default = 'loginWithShop',\n CheckoutModal = 'loginWithShopCheckoutModal',\n ClassicCustomerAccounts = 'loginWithShopClassicCustomerAccounts',\n Prequal = 'loginWithShopPrequal',\n Web = 'loginWithShopShopWeb',\n SelfServe = 'loginWithShopSelfServe',\n CheckoutExtension = 'loginWithShopCheckoutExtension',\n PaymentRequest = 'loginWithShopPaymentRequest',\n CheckoutSheet = 'checkout_sheet',\n}\nexport const ANALYTICS_CONTEXT_TO_FLOW_MAP: Record<\n DefaultComponentAnalyticsContext,\n string\n> = {\n [DefaultComponentAnalyticsContext.Default]: 'default',\n [DefaultComponentAnalyticsContext.SelfServe]: 'self_serve_customer_accounts',\n [DefaultComponentAnalyticsContext.ClassicCustomerAccounts]:\n 'classic_customer_accounts',\n [DefaultComponentAnalyticsContext.Prequal]: 'shop_pay_installments_prequal',\n [DefaultComponentAnalyticsContext.PaymentRequest]: 'payment_request',\n [DefaultComponentAnalyticsContext.CheckoutExtension]: 'default',\n [DefaultComponentAnalyticsContext.CheckoutModal]: 'checkout_modal',\n [DefaultComponentAnalyticsContext.CheckoutSheet]: 'checkout_sheet',\n [DefaultComponentAnalyticsContext.Web]: '',\n};\n\nconst ELEMENT_PREFIX = 'shop-login-default';\nexport const IFRAME_CLASS_NAME = `${ELEMENT_PREFIX}-iframe`;\nexport const IFRAME_COMPACT_CLASS_NAME = `${ELEMENT_PREFIX}-iframe-compact`;\nexport const HEADER_CLASS_NAME = `${ELEMENT_PREFIX}-header`;\nexport const HEADER_CONTENTS_CONTAINER_CLASS_NAME = `${HEADER_CLASS_NAME}-contents-container`;\nexport const HEADER_TITLE_CLASS_NAME = `${HEADER_CLASS_NAME}-title`;\nexport const HEADER_DESCRIPTION_CLASS_NAME = `${HEADER_CLASS_NAME}-description`;\nexport const HEADER_DIVIDER_CLASS_NAME = `${HEADER_CLASS_NAME}-divider`;\nexport const FOOTER_CLASS_NAME = `${ELEMENT_PREFIX}-footer`;\nexport const FOOTER_CONTENT_CLASS_NAME = `${FOOTER_CLASS_NAME}-content`;\nexport const HIDDEN_ELEMENT_CLASS_NAME = `${ELEMENT_PREFIX}-hidden`;\nexport const CONTENT_CLASS_NAME = `${ELEMENT_PREFIX}-content`;\n\nconst RADIUS = `20px`;\nconst SMALL_SCREEN_THRESHOLD = 448;\n\nexport const getShopLoginDefaultTemplate = (extraAttributes = '') => `\n\n \n \n \n \n \n \n`;\n\nexport const HEADER_STYLE = `\n \n`;\n","import {DefaultComponentAnalyticsContext} from '../../constants/loginDefault';\n\nconst ANALYTICS_CONTEXTS_TO_COMPACT = [\n DefaultComponentAnalyticsContext.CheckoutModal,\n DefaultComponentAnalyticsContext.ClassicCustomerAccounts,\n DefaultComponentAnalyticsContext.Web,\n DefaultComponentAnalyticsContext.SelfServe,\n];\n\n/**\n * @param {string} analyticsContext the analytics context string\n * @returns {boolean} the given comtext is eligible for compact layout\n */\nexport function checkEligibleForCompactLayout(\n analyticsContext: DefaultComponentAnalyticsContext,\n): boolean {\n const applyCompactToAnalyticsContext = analyticsContext\n ? ANALYTICS_CONTEXTS_TO_COMPACT.includes(analyticsContext)\n : false;\n\n return applyCompactToAnalyticsContext;\n}\n","export const BUGSNAG_APP_ID = 'shop-js';\n\n// Set by rollup replace plugin\nexport const APP_VERSION = '__buildVersion';\n\nexport const SHOPIFY_S_COOKIE = '_shopify_s';\nexport const SHOPIFY_Y_COOKIE = '_shopify_y';\n\nexport const SPIN_DOMAIN_SUFFIX = /spin\\.(dev|shopify\\.io)$/;\nexport const SPIN_URL_SUFFIX = /\\.(?:(?:\\w|-)+\\.){3}spin\\.(dev|shopify\\.io)$/;\n\nexport const POPUP_CLOSE_CHECK_INTERVAL = 1000;\n\nexport const SIGN_IN_FORM_DATA_ATTRIBUTE = 'data-login-with-shop-sign-in';\nexport const SIGN_UP_FORM_DATA_ATTRIBUTE = 'data-login-with-shop-sign-up';\nconst SIGN_IN_FORM_SELECTOR = `form[${SIGN_IN_FORM_DATA_ATTRIBUTE}]`;\nconst SIGN_UP_FORM_SELECTOR = `form[${SIGN_UP_FORM_DATA_ATTRIBUTE}]`;\n\n// See https://shopify.dev/docs/themes/customer-engagement/additional-customer-information for input field names\nexport const CUSTOMER_EMAIL_INPUT_SELECTOR = 'input[name=\"customer[email]\"';\nexport const CUSTOMER_FIRST_NAME_INPUT_SELECTOR =\n 'input[name=\"customer[first_name]\"';\nexport const CUSTOMER_LAST_NAME_INPUT_SELECTOR =\n 'input[name=\"customer[last_name]\"';\n\nexport const SIGN_IN_FORM_EMAIL_INPUT_SELECTOR = `${SIGN_IN_FORM_SELECTOR} input[type=\"email\"],${SIGN_IN_FORM_SELECTOR} ${CUSTOMER_EMAIL_INPUT_SELECTOR}`;\nexport const SIGN_UP_FORM_EMAIL_INPUT_SELECTOR = `${SIGN_UP_FORM_SELECTOR} input[type=\"email\"],${SIGN_UP_FORM_SELECTOR} ${CUSTOMER_EMAIL_INPUT_SELECTOR}`;\n\nexport const MAX_Z_INDEX = '2147483647';\n","import type {ReleaseStage} from '@shopify/bugsnag-light-core';\n\nexport const RELEASE_STAGES: Record = {\n dev: 'development',\n spin: 'spin',\n staging: 'staging',\n prod: 'production',\n};\n\n/*\nThis is the notifier object Bugsnag's own JS client sends. It is required to trigger Bugsnag\nserver-side parsing of the `useragent` string as well as client IP logging.\n */\nexport const BUGSNAG_NOTIFIER = {\n name: 'Bugsnag JavaScript',\n version: '7.13.2',\n url: 'https://github.com/bugsnag/bugsnag-js',\n};\n","import {DefaultComponentAnalyticsContext} from '__deprecated__/constants/loginDefault';\nimport {parseErrorStack} from '@shopify/bugsnag-light-core';\nimport type {\n BugsnagClient,\n BugsnagEvent,\n ReleaseStage,\n} from '@shopify/bugsnag-light-core';\n\nimport {checkEligibleForCompactLayout} from '../utils/isCompactLayout';\nimport config from '../../../config';\nimport {BUGSNAG_APP_ID, APP_VERSION} from '../constants';\n\nimport {RELEASE_STAGES} from './constants';\n\n/**\n * Checks which environment shop-js is running in and returns the appropriate\n * release stage string. This corresponds to the Stage filter in the Bugsnag console.\n * @typedef ReleaseStage\n * @returns {ReleaseStage} The release stage that corresponds to this environment.\n */\nexport function getReleaseStage(): ReleaseStage {\n // Gets set at build time by rollup-replace\n // eslint-disable-next-line no-process-env\n const nodeEnv = process.env.NODE_ENV;\n\n switch (nodeEnv) {\n case 'spin':\n return RELEASE_STAGES.spin;\n case 'staging':\n return RELEASE_STAGES.staging;\n case 'production':\n return RELEASE_STAGES.prod;\n case 'development':\n default:\n return RELEASE_STAGES.dev;\n }\n}\n\n/**\n * Checks whether an error originated in shop-js.\n * @param {Error} error An error object.\n * @returns {boolean} `true` if the given error came from shop-js, `false` otherwise.\n */\nexport function isShopJsError(error: Error): boolean {\n const stack = parseErrorStack(error);\n if (stack.length === 0) return false;\n\n if (\n error.message?.includes('Backpressure applied') ||\n error.message?.includes(\n 'A network failure may have prevented the request from completing',\n )\n )\n return false;\n\n return stack.some((frame) => frame.file?.includes('shopifycloud/shop-js'));\n}\n\n/**\n * Adds the URLs of all shop-js bundles on the page to the Bugsnag event metadata.\n * This does not tell us which bundle the error came from, but it's still valuable\n * data to have.\n * @param {BugsnagEvent} event The Bugsnag Event to add metadata to.\n */\nfunction addBundleMetadata(event: BugsnagEvent) {\n const shopJsUrls = (\n Array.from(\n document.querySelectorAll('script[src*=\"/shop-js/\"]'),\n ) as HTMLScriptElement[]\n ).map((scriptTag) => scriptTag.src);\n addMetadata(event, {shopJsUrls});\n}\n\n/**\n * Adds metadata to the Bugsnag event to indicate whether the window.Shopify.featureAssets\n * object exists. We want to be conscious of the payload we send to Bugsnag, so sending the\n * entire object is not ideal. This is a compromise.\n * @param {BugsnagEvent} event The Bugsnag Event to add metadata to.\n */\nfunction addFeatureAssetsMetadata(event: BugsnagEvent) {\n const featureAssets: Record | undefined =\n window.Shopify?.featureAssets?.['shop-js'];\n const featureAssetsNonEmpty = Boolean(\n featureAssets && Object.keys(featureAssets).length > 0,\n );\n addMetadata(event, {shopJsFeatureAssetsExist: featureAssetsNonEmpty});\n}\n\n/**\n * Adds metadata to the Bugsnag event to indicate whether the compact UX is being used.\n * @param {BugsnagEventType} event The Bugsnag Event to add metadata to.\n */\nfunction addCompactUXMetadata(event: BugsnagEvent) {\n const compactShopLoginButton = Array.from(\n document.querySelectorAll('shop-login-button[compact]'),\n );\n compactShopLoginButton.filter((el) =>\n checkEligibleForCompactLayout(\n el.getAttribute('analytics-context') as DefaultComponentAnalyticsContext,\n ),\n );\n addMetadata(event, {compactUX: compactShopLoginButton.length > 0});\n}\n\n/**\n * Adds metadata to the Bugsnag event to identify the current domain.\n * @param {BugsnagEventType} event The Bugsnag Event to add metadata to.\n */\nfunction addDomainMetadata(event: BugsnagEvent) {\n const domain = window?.location?.hostname;\n addMetadata(event, {domain});\n}\n\n/**\n * Adds the error class and error message as a grouping hash to the Bugsnag event.\n * @param {BugsnagEvent} event The Bugsnag Event to add groupHash to.\n */\nfunction addGroupingHash(event: BugsnagEvent): void {\n const groupingHash = `${event.exceptions[0].errorClass}:${event.exceptions[0].message}`;\n event.groupingHash = groupingHash;\n}\n\n/**\n * Adds metadata to a Bugsnag event.\n * @param {BugsnagEvent} event The Bugsnag Event to add metadata to.\n * @param metadata\n */\nfunction addMetadata(event: BugsnagEvent, metadata: any) {\n event.metaData = {...event.metaData, ...metadata};\n}\n\n/**\n * Adds the current URL to the Bugsnag event request.\n * @param {BugsnagEvent} event The Bugsnag Event to add metadata to.\n */\nfunction addRequest(event: BugsnagEvent) {\n event.request = {\n url: window.location.href,\n };\n}\n\n/**\n * Adds the device information to the Bugsnag event.\n * @param {BugsnagEvent} event The Bugsnag Event to add metadata to.\n */\nfunction addDevice(event: BugsnagEvent) {\n const now = new Date();\n const time = now.toISOString();\n event.device = {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n locale: navigator.userLanguage || navigator.language,\n userAgent: navigator.userAgent,\n orientation: window.screen?.orientation?.type,\n time,\n };\n}\n\n/**\n * Adds the metadata and other relevant information to a Bugsnag event.\n * @param {BugsnagEvent} event The Bugsnag Event to add metadata to.\n */\nfunction onError(event: BugsnagEvent) {\n addBundleMetadata(event);\n addFeatureAssetsMetadata(event);\n addCompactUXMetadata(event);\n addDomainMetadata(event);\n addGroupingHash(event);\n addRequest(event);\n addDevice(event);\n}\n\n/**\n * Creates a Bugsnag client params metadata and with the default params.\n * @param metadata\n * @returns {BugsnagLightParams} The Bugsnag Params.\n */\nexport function createBugsnagParams(metadata: any) {\n return {\n apiKey: config.bugsnagApiKey,\n appId: BUGSNAG_APP_ID,\n appVersion: APP_VERSION,\n metadata: {\n // eslint-disable-next-line no-process-env\n bundleLocale: process.env.BUILD_LOCALE,\n ...metadata,\n } as any,\n onError,\n releaseStage: getReleaseStage(),\n };\n}\n\n/**\n * Adds a generic Bugsnag error handler to the window object.\n * @param {BugsnagLight} bugsnagClient\n */\nexport function addGenericBugsnagOnError(bugsnagClient: BugsnagClient) {\n if (!window) return;\n\n window.addEventListener('error', (event) => {\n const {error} = event;\n if (error && isShopJsError(error)) {\n bugsnagClient.notify(error);\n }\n });\n}\n","import {BugsnagLight} from '@shopify/bugsnag-light-core';\nimport type {BreadcrumbType, NotifyOptions} from '@shopify/bugsnag-light-core';\n\nimport {\n createBugsnagParams,\n getReleaseStage,\n addGenericBugsnagOnError,\n} from './utils';\nimport {RELEASE_STAGES} from './constants';\n\nlet client: BugsnagLight | undefined;\n\nconst Bugsnag = {\n /**\n * Start Bugsnag. Must be called before any other Bugsnag methods.\n * @param params\n * @param params.metadata Initial metadata to send with all captured events.\n */\n start: ({metadata}: {metadata: any}) => {\n if (client) {\n // eslint-disable-next-line no-console\n console.log('Bugsnag.start() has already been called. Ignoring.');\n return;\n }\n client = new BugsnagLight(createBugsnagParams(metadata));\n addGenericBugsnagOnError(client);\n },\n\n /**\n * Add a breadcrumb to the stack. Breadcrumbs are sent to Bugsnag when an error is sent, providing additional\n * data on what happened prior to the error.\n * @param {string} name The name of the breadcrumb.\n * @param {any} metaData Any additional data to send with the breadcrumb.\n * @param {BreadcrumbType} type The type of breadcrumb (i.e. \"navigation\" or \"request\"). See BreadcrumbType for options.\n */\n leaveBreadcrumb: (name: string, metaData: any, type: BreadcrumbType) => {\n if (!client) {\n // eslint-disable-next-line no-console\n console.log('Bugsnag.leaveBreadcrumb() called before start().');\n return;\n }\n\n if (getReleaseStage() === RELEASE_STAGES.spin) {\n // eslint-disable-next-line no-console\n console.log('[Bugsnag leaveBreadcrumb called]', name, metaData, type);\n return;\n }\n\n client.leaveBreadcrumb(name, metaData, type);\n },\n\n /**\n * Send a notification to Bugsnag.\n * @param {Error} error The error to log.\n * @param {BeforeNotifyCallback} onBeforeNotify Optional callback allows modifying the event before it is sent to Bugsnag.\n * Use to set `severity` or add metadata with the `addMetadata` function call. If callback returns false, the event will\n * not be sent. Should behave similar to the `onError` callback of the official Bugsnag client:\n * https://docs.bugsnag.com/platforms/javascript/reporting-handled-errors/#customizing-diagnostic-data\n * @param options\n */\n notify: (error: Error, options?: NotifyOptions) => {\n if (!client) {\n // eslint-disable-next-line no-console\n console.log('Bugsnag.notify() called before start().');\n return;\n }\n\n if (getReleaseStage() === RELEASE_STAGES.spin) {\n // eslint-disable-next-line no-console\n console.log('[Bugsnag notify called]', error);\n return;\n }\n\n client.notify(error, options);\n },\n};\n\nexport default Bugsnag;\n","import Bugsnag from './bugsnag';\n\n/**\n * Logs error message to console and sends to Bugsnag.\n * @param {string} message The error message to log.\n */\nexport function logError(message: string) {\n // eslint-disable-next-line no-console\n console.error(`[shop-js] ${message}`);\n Bugsnag.notify(new Error(message));\n}\n\n/**\n * Logs information message to console and leaves a Bugsnag breadcrumb.\n * @param {string} message The message to log.\n */\nexport function logInfo(message: string) {\n // eslint-disable-next-line no-console\n console.log(`[shop-js] ${message}`);\n Bugsnag.leaveBreadcrumb(message, {}, 'log');\n}\n\n/**\n * Logs a warning message to the developer and sends to Bugsnag as error.\n * @param {string} message The message to log.\n */\nexport function logWarning(message: string) {\n // eslint-disable-next-line no-console\n console.warn(message);\n Bugsnag.notify(new Error(message), {\n severity: 'warning',\n });\n}\n","import {logInfo} from '__deprecated__/common/logging';\nimport {getPaymentRequestLocale} from '__deprecated__/common/utils/paymentRequest';\n\nimport Bugsnag from '../bugsnag';\n\nimport {Dictionary, LocaleDictionary, SupportedLocale} from './types';\n\ninterface TranslateOptions {\n defaultValue?: string;\n [key: string]: any;\n}\n\nexport class I18n {\n static allowedLocales: SupportedLocale[] = [\n 'en',\n 'bg-BG',\n 'cs',\n 'da',\n 'de',\n 'el',\n 'es',\n 'fi',\n 'fr',\n 'hi',\n 'hr-HR',\n 'hu',\n 'id',\n 'it',\n 'ja',\n 'ko',\n 'lt-LT',\n 'ms',\n 'nb',\n 'nl',\n 'pl',\n 'pt-BR',\n 'pt-PT',\n 'ro-RO',\n 'ru',\n 'sk-SK',\n 'sl-SI',\n 'sv',\n 'th',\n 'tr',\n 'vi',\n 'zh-CN',\n 'zh-TW',\n ];\n\n static getDefaultLanguage(): SupportedLocale {\n const buildLocale =\n // eslint-disable-next-line no-process-env\n (process.env.BUILD_LOCALE as SupportedLocale) || undefined;\n if (buildLocale) {\n return buildLocale;\n }\n\n try {\n // override locale if it is a shop pay payment request checkout\n const paymentRequestLocale = getPaymentRequestLocale();\n\n const shopifyLocale =\n paymentRequestLocale ||\n document.documentElement.lang ||\n window.Shopify?.locale;\n if (shopifyLocale) {\n const parsedLocale = new Intl.Locale(shopifyLocale);\n if (I18n.allowedLocales.includes(shopifyLocale as SupportedLocale)) {\n return shopifyLocale as SupportedLocale;\n } else if (\n I18n.allowedLocales.includes(parsedLocale.language as SupportedLocale)\n ) {\n // fallback on the unsupported language, pick the language without the region (e.g. 'en-GB' -> 'en')\n return parsedLocale.language as SupportedLocale;\n } else {\n logInfo(\n `Unsupported locale: \"${shopifyLocale}\". Falling back to \"en\".`,\n );\n }\n }\n\n for (const preferredLanguage of navigator.languages) {\n if (\n I18n.allowedLocales.includes(preferredLanguage as SupportedLocale)\n ) {\n return preferredLanguage as SupportedLocale;\n }\n\n const parsedLocale = new Intl.Locale(preferredLanguage);\n if (\n I18n.allowedLocales.includes(parsedLocale.language as SupportedLocale)\n ) {\n return parsedLocale.language as SupportedLocale;\n }\n }\n } catch (error) {\n // these usually happens when the Intl API has detected an unsupported locale (e.g. 'mamma mia')\n }\n return 'en';\n }\n\n #translations: Dictionary;\n #locale: SupportedLocale =\n // eslint-disable-next-line no-process-env\n (process.env.BUILD_LOCALE as SupportedLocale) || I18n.getDefaultLanguage();\n\n constructor(translations: Dictionary) {\n this.#translations = translations;\n }\n\n get locale(): SupportedLocale {\n return this.#locale;\n }\n\n set locale(locale: SupportedLocale) {\n if (I18n.allowedLocales.includes(locale)) {\n this.#locale = locale;\n }\n }\n\n #needsPluralize(translations: LocaleDictionary | string, locals: any = {}) {\n return typeof translations !== 'string' && locals.count !== 'undefined';\n }\n\n #getPluralizeKey(translations: LocaleDictionary | string, count: number) {\n let key = count === 1 ? 'one' : 'other';\n\n if (\n count === 0 &&\n typeof translations !== 'string' &&\n translations.zero !== 'undefined'\n ) {\n key = 'zero';\n }\n\n return key;\n }\n\n #render(translation: string, locals: TranslateOptions = {}): string {\n const matches = translation.match(/\\{.+?\\}/g);\n\n if (matches) {\n return matches.reduce((res, match) => {\n const key = match.replace(/\\{(.*)\\}/, '$1');\n if (locals[key]) {\n return res.replace(match, locals[key]);\n } else {\n Bugsnag.notify(\n new Error(\n `i18n: Missing translation key '${key}' for '${translation}'`,\n ),\n );\n }\n return res;\n }, translation);\n }\n\n return translation;\n }\n\n translate(scope: string, locals: TranslateOptions = {}): string {\n const scopes = scope.split('.');\n let ret: LocaleDictionary | string | undefined =\n this.#translations[this.#locale];\n\n try {\n // Traverse through the translation data one \"scope\" at a time\n for (const scope of scopes) {\n switch (typeof ret) {\n case 'object':\n ret = ret[scope];\n break;\n case 'string':\n case 'undefined':\n throw new ReferenceError();\n }\n }\n\n // No key? Throw an error\n if (typeof ret === 'undefined') {\n throw new ReferenceError();\n }\n\n // Do we need to pluralize?\n if (this.#needsPluralize(ret, locals)) {\n ret = (ret as LocaleDictionary)[\n this.#getPluralizeKey(ret, locals.count)\n ];\n }\n\n return this.#render(ret as string, locals);\n } catch (err) {\n // If we can't find a translation, return the default value if one exists\n if (locals.defaultValue) {\n return locals.defaultValue;\n }\n\n // Otherwise, return the scope\n return scope;\n }\n }\n\n isEnglish(): boolean {\n return this.#locale === 'en';\n }\n}\n","import {v4 as uuidv4} from 'uuid';\n\nimport {POPUP_CLOSE_CHECK_INTERVAL} from '../constants';\n\nimport {StoreMetadata} from './types';\n\nconst getWindowPosition = () => {\n const left =\n window.screenLeft === undefined ? window.screenX : window.screenLeft;\n const top =\n window.screenTop === undefined ? window.screenY : window.screenTop;\n return {\n left,\n top,\n };\n};\n\nexport const getWindowSize = () => {\n const width = window.innerWidth || document.documentElement.clientWidth;\n const height = window.innerHeight || document.documentElement.clientHeight;\n return {\n width,\n height,\n };\n};\n\nconst getSystemZoom = () => {\n return screen.width && window.screen.availWidth\n ? screen.width / window.screen.availWidth\n : 1;\n};\n\ninterface PopupParameters {\n url: string;\n width: number;\n height: number;\n windowName?: string;\n onClose?: () => void;\n}\n\n/**\n * Opens a popup widow. Tries to put the window into the middle of the parent,\n * if possible. Otherwise puts it into the middle of the screen.\n * @param {object} root The root parameter object.\n * @param {string} root.url URL to display in the popup.\n * @param {number} root.width Target width of the popup.\n * @param {number} root.height Target height of the popup.\n * @param {string} root.windowName Optional name given to the popup window.\n * Should not contain whitespace. This will not be used as the window's title.\n * @param {Function} root.onClose Optional function called when the popup is closed.\n * @returns {Window} A reference to the popup window object.\n */\nexport function openPopupWindow({\n url,\n width,\n height,\n windowName,\n onClose,\n}: PopupParameters): Window | null {\n const windowPosition = getWindowPosition();\n const windowSize = getWindowSize();\n\n const clientWidth = windowSize.width || screen.width;\n const clientHeight = windowSize.height || screen.height;\n\n const systemZoom = getSystemZoom();\n const left = (clientWidth - width) / 2 / systemZoom + windowPosition.left;\n const top = (clientHeight - height) / 2 / systemZoom + windowPosition.top;\n\n const popupWindow: Window | null = window.open(\n url,\n windowName,\n `scrollbars=yes,width=${width},height=${height},top=${top},left=${left}`,\n );\n if (!popupWindow) return null;\n popupWindow.focus();\n\n if (onClose) {\n const closeCheckInterval = setInterval(() => {\n if (!popupWindow.closed) return;\n onClose();\n clearInterval(closeCheckInterval);\n }, POPUP_CLOSE_CHECK_INTERVAL);\n }\n\n return popupWindow;\n}\n\n/**\n * Updates the value on an HTML element if it's different to the current one.\n * @param {HTMLElement} element The HTML element to update.\n * @param {string} attribute The name of the attribute to set.\n * @param {string} value The new value for the attribute.\n * @param {boolean | undefined} forced whether to force a reload even if the URL matches\n */\nexport function updateAttribute(\n element: HTMLElement,\n attribute: string,\n value: string,\n forced?: boolean,\n) {\n if (!forced && element.getAttribute(attribute) === value) return;\n if ((element as Record)[attribute] === true) return;\n element.setAttribute(attribute, value);\n}\n\n/**\n * Updates an attribute in a given list of attributes, based on a given flag\n * @param {boolean} flag should this attribute be there?\n * @param {string} attributeName the name of the attribute\n * @param {string[]} attributeList pointer to the list in which to update it\n */\nexport function updateAttributeConditionally(\n flag: boolean,\n attributeName: string,\n attributeList: string[],\n) {\n const attributeIncluded = attributeList.includes(attributeName);\n\n if (flag && !attributeIncluded) {\n attributeList.push(attributeName);\n } else if (!flag && attributeIncluded) {\n attributeList.splice(attributeList.indexOf(attributeName), 1);\n }\n}\n\n/**\n * Updates the iframe src without pushing to the browser history stack. Does this by\n * removing the iframe from the DOM, updating the src attribute and then re-adding it.\n * @param {HTMLIFrameElement} iframe The iframe to navigate.\n * @param {string} src The new URL to navigate to.\n * @param {boolean | undefined} forced Whether to force a reload even if the URL matches.\n */\nexport function updateIframeSrc(\n iframe: HTMLIFrameElement,\n src: string,\n forced?: boolean,\n) {\n if (!forced && iframe.src === src) return;\n\n const parent = iframe.parentNode;\n if (!parent) return;\n\n parent.removeChild(iframe);\n iframe.setAttribute('src', src);\n parent.appendChild(iframe);\n}\n\n/**\n * Returns the UUID to be used as the Analytics Trace ID, to link events from one session together.\n * @returns {string} The Analytics Trace ID.\n */\nexport function getAnalyticsTraceId(): string {\n return uuidv4();\n}\n\n/**\n * Returns the duration in milliseconds between two dates, if defined.\n * @param {Date} from The earlier date\n * @param {Date} to The later date\n * @returns {number | undefined} The duration in ms between the given dates or undefined if it's not possible to calculate.\n */\nexport function getDuration(from?: Date, to?: Date): number | undefined {\n if (!from || !to) return undefined;\n return to.getTime() - from.getTime();\n}\n\n/**\n * Gets the store's metadata from meta.json file.\n * @param {string} storefrontOrigin The origin of the storefront.\n * @returns {Promise} The store's metadata, or null if it's not available.\n */\nexport async function getStoreMeta(\n storefrontOrigin: string = location.origin,\n): Promise {\n const response = fetch(`${storefrontOrigin}/meta.json`);\n try {\n const res = await response;\n const meta = await res.json();\n return meta;\n } catch {\n return null;\n }\n}\n\n/**\n * @param {string} storeUrl store url (e.g. `https://merchant.com` or\n * `http://store.myshopify.com`). Will validate that it's a valid URL and not\n * a subset.\n * @returns {string} The extracted hostname of the provided URL, or null if an error occurs in parsing hostname\n */\nexport function getHostName(storeUrl: string): string | null {\n try {\n return new URL(storeUrl).hostname;\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(`[Shop Pay] Store URL (${storeUrl}) is not valid`, error);\n return null;\n }\n}\n\n/**\n *\n *Extract a query parameter from the current URL.\n * @param {string} name The name of the query parameter to get.\n * @returns {string | null} The value of the query parameter or null if it doesn't exist.\n */\nexport function getQueryParam(name: string): string | null {\n const urlParams = new URLSearchParams(window.location.search);\n return urlParams.get(name);\n}\n\n/**\n * Climbs the DOM tree from the given shadow root to the document body. Yielding each HTML element along the way.\n * @param {ShadowRoot | Element} base The shadow root or element to start climbing from.\n * @yields {Element} The next HTML element in the DOM tree.\n */\nexport function* climbDomTree(base: ShadowRoot | Element): Generator {\n let current: ShadowRoot | Element | null = base;\n\n while (current) {\n if (current.parentElement) {\n current = current.parentElement;\n } else if (current instanceof ShadowRoot) {\n current = current.host;\n } else if (current instanceof Element) {\n const root = current.getRootNode();\n if (root instanceof ShadowRoot) {\n current = root.host;\n } else {\n break;\n }\n } else {\n break;\n }\n\n yield current;\n\n if (current === document.body) {\n break;\n }\n }\n}\n\ntype Callback = (...args: T) => void;\n/**\n * Debounces a function call by the given timeout.\n * @param {Callback} callback The function to call after the timeout has elapsed.\n * @param {number} timeout The timeout in milliseconds.\n * @returns {Callback} A function that will call the callback after the timeout has elapsed.\n */\nexport function debounce(\n callback: Callback,\n timeout: number,\n): (...args: T) => void {\n let timer: NodeJS.Timeout;\n\n return (...args: T) => {\n clearTimeout(timer);\n timer = setTimeout(() => {\n callback(...args);\n }, timeout);\n };\n}\n\n/**\n *\n *Remove trailing slash from a URL. If the URL is only a slash, it will be returned as is.\n * @param {string} urlString The URL to remove the trailing slash from.\n * @returns {string} The URL without the trailing slash.\n */\nexport function removeTrailingSlash(urlString: string): string {\n if (urlString === '/') return urlString;\n return urlString.endsWith('/') ? urlString.slice(0, -1) : urlString;\n}\n\n/**\n * Returns `true` if the given URLs are considered to have matching root domains. A \"match\"\n * in this case means that one domain is either a superdomain or a subdomain of the other.\n *\n * This solves the specific case of allowing postMessaging between domains like `lang.storefront.com`\n * and `storefront.com`. However once Sign in with Shop can be deployed on any surface this restriction\n * may need to be reconsidered.\n * @param {string} urlString1 A URL with a root domain or subdomain (i.e. \"http://merchant.com\" or \"http://fr.merchant.com\")\n * @param {string} urlString2 A URL with a root domain or subdomain (i.e. \"http://merchant.com\" or \"http://fr.merchant.com\")\n * @returns {boolean} `true` if the root domains of the given URLs match\n */\nexport function isRootDomainMatch(\n urlString1: string,\n urlString2: string,\n): boolean {\n try {\n const host1Tokens = new URL(urlString1).host.split('.').reverse();\n const host2Tokens = new URL(urlString2).host.split('.').reverse();\n for (let i = 0; i < Math.min(host1Tokens.length, host2Tokens.length); i++) {\n if (host1Tokens[i] !== host2Tokens[i]) {\n return false;\n }\n }\n return true;\n } catch (err) {\n return false;\n }\n}\n\n/**\n * Applies a partial set of styles to an element.\n * @param {HTMLElement} element The element to apply the styles to.\n * @param {Partial} styles The (partial) styles to apply to the element.\n * @returns {CSSStyleDeclaration} The element's style object.\n */\nexport function applyStylesToElement(\n element: HTMLElement,\n styles: Partial,\n): CSSStyleDeclaration {\n return Object.assign(element.style, styles);\n}\n\n/**\n * Detect if user is using mobile (logic inspired from Core)\n * @returns {boolean} Whether the user is using a mobile browser\n */\nexport function isMobileBrowser(): boolean {\n return (\n Boolean(navigator.userAgent) &&\n /(android|iphone|ipad|mobile|phone)/i.test(navigator.userAgent)\n );\n}\n\n/**\n * Detect specifically if this is an iOS platform\n * @returns {boolean} Whether the device is running iOS\n */\nexport function isIOSPlatform(): boolean {\n return (\n Boolean(navigator.userAgent) &&\n /(iphone|ipad|ipod)/i.test(navigator.userAgent)\n );\n}\n\n/**\n * On iOS, the keyboard zooms in when a form input is focused.\n * For the email listener flows, this results in a zoomed-in\n * OTP modal. To force an unzoom, we create an input element\n * and focus it, which unzooms the view.\n *\n * This problem arises from both:\n * Autozoom functionality in iOS\n * Inability to autofocus a field in an IFRAME\n * @returns {void}\n */\nexport function unzoomIos() {\n if (!isiOSSafari()) {\n return;\n }\n\n const elementId = 'shop-pay-safari-unzoom';\n const existingElement = document.getElementById(elementId);\n if (existingElement) return existingElement.focus();\n\n const input = document.createElement('input');\n input.id = elementId;\n input.style.fontSize = '16px';\n input.style.width = '1px';\n input.style.height = '1px';\n input.style.position = 'fixed';\n input.style.bottom = '-1000px';\n input.style.right = '-1000px';\n input.style.transform = 'translate(1000px, 1000px)';\n input.setAttribute('aria-hidden', 'true');\n\n document.body.appendChild(input);\n input.focus({preventScroll: true});\n}\n\n/**\n * Determines if we are using iOS.\n * @returns {boolean} True if we are using iOS Safari\n */\nfunction isiOSSafari() {\n const ua = window.navigator.userAgent;\n const iOS = Boolean(ua.match(/iPad/i)) || Boolean(ua.match(/iPhone/i));\n const webkit = Boolean(ua.match(/WebKit/i));\n const iOSSafari = iOS && webkit && !ua.match(/CriOS/i);\n return iOSSafari;\n}\n\n/**\n * Checks whether the given value passed to a component attribute is empty.\n * @param {string} value The value passed to a component attribute.\n * @returns {boolean} `true` if the given value is null or empty, `false` otherwise.\n */\nexport function isEmptyAttributeValue(value: string | null) {\n return value === null || value.trim() === '';\n}\n\n/**\n * A function that resolves a promise with a max timeout\n * This function was written by Chat-GPT3.5. Prompt by gioele\n * @param {Promise} promise the promise to race with a timeout\n * @param {number} timeoutMs the timeout in milliseconds\n * @returns {Promise} either the resolved promise or a rejected promise with a timeout error\n */\nexport function promiseWithTimeout(\n promise: Promise,\n timeoutMs: number,\n): Promise {\n let timeoutId: NodeJS.Timeout;\n\n const timeoutPromise = new Promise((resolve) => {\n timeoutId = setTimeout(() => {\n resolve();\n }, timeoutMs);\n });\n\n return Promise.race([promise, timeoutPromise]).finally(() => {\n clearTimeout(timeoutId);\n });\n}\n\n/**\n * Extract feature flags exported from a storefront-renderer Shop Pay specific script tag\n * @returns {Record} feature name and value pairs\n */\nexport function getFeatures(): Record {\n const featuresTag = document.querySelector(\n 'script#shop-js-features',\n )?.innerHTML;\n if (featuresTag) {\n return JSON.parse(featuresTag);\n } else {\n return {};\n }\n}\n\n/**\n * Find and parse the storefront analytics meta tag\n * @returns {Record} storefront analytics information\n */\nexport function getStorefrontAnalytics(): Record {\n const analyticsTag = document.querySelector(\n 'script#shop-js-analytics',\n )?.innerHTML;\n if (analyticsTag) {\n return JSON.parse(analyticsTag);\n } else {\n return {};\n }\n}\n","import {\n arrow,\n ComputePositionConfig,\n ComputePositionReturn,\n flip,\n limitShift,\n offset,\n Placement,\n shift,\n Side,\n} from '@floating-ui/dom';\n\nimport {\n SMALL_SCREEN_WIDTH,\n MEDIUM_SCREEN_WIDTH,\n} from '../shop-sheet-modal/constants-compact';\n\nexport interface PositionData extends ComputePositionReturn {\n staticSide: Side;\n}\n\nexport type PositionOverrides = {[key in Side]: string} | Record;\n\n// Behavior type is the control plane that allows us to\n// load different behavior configurations.\nexport enum PositionBehaviorType {\n Dynamic = 'DYNAMIC',\n Mobile = 'MOBILE',\n Center = 'CENTER',\n Corner = 'CORNER',\n}\n\nexport enum PositionVariant {\n Corner = 'corner',\n Default = 'default',\n}\n\n// This object maps to some floating-ui constructs it's primary purpose is to\n// enable the config[key -> PositionBehaviorType] setup and eliminate the `if -> else` code\n// that would be present when checking for the different PositionBehaviorTypes\n// The `config` property is what would get passed to the computePosition\n// function provided by floating-ui\n// Because floating-ui only calculates values it does not apply them, we need\n// to handle how we want to deal with the values. The `computePosition` is an async function.\n// The `fn` property is what is used to respond to the result of `computePosition` and to apply\n// calculated position information to the floating/arrow elements.\n// `PositionData` is all the calculated position values. The intent of the position module\n// is to **only** deal with positioning. So we need to expose the position data\n// so that the consumer can make informed decisions about how to apply animations or\n// any other concern outside of positioning.\ninterface BehaviorConfiguration {\n config: ComputePositionConfig;\n fn: (options: ComputePositionReturn) => PositionData | null;\n}\n\nexport const centerBehavior = (\n floatingElement: HTMLElement,\n overlayElement: HTMLElement,\n overrides: PositionOverrides = {},\n): BehaviorConfiguration => ({\n config: {},\n fn: () => {\n const arrowElement: HTMLDivElement | null =\n floatingElement.querySelector('.arrow');\n\n if (arrowElement !== null) {\n arrowElement.style.display = 'none';\n }\n\n const overridesPresent = Object.keys(overrides).length > 0;\n\n // set the overrides via css variables\n if (overridesPresent) {\n Object.assign(floatingElement.style, overrides, {position: 'absolute'});\n }\n\n overlayElement.classList.toggle('centered', !overridesPresent);\n\n return null;\n },\n});\n// The object key repsents a placement side. Floating-ui can report placent as\n// -start, , -end, where side can be top, right, bottom, left.\n// For the arrow we only care about the and this is why we do placement.split(-).\n// The mapping that is happening here represents where the arrow will be on the floating element.\n// So, if the floating element is placed at the top the arrow will be placed on the bottom of\n// the floating element.\nconst staticSideMap = new Map([\n ['top', 'bottom'],\n ['top-end', 'bottom'],\n ['top-start', 'bottom'],\n ['right', 'left'],\n ['right-end', 'left'],\n ['right-start', 'left'],\n ['bottom', 'top'],\n ['bottom-end', 'top'],\n ['bottom-start', 'top'],\n ['left', 'right'],\n ['left-end', 'right'],\n ['left-start', 'right'],\n]);\n\nexport const dynamicBehavior = (\n floatingElement: HTMLElement,\n _overlayElement: any,\n _positionOverrides: any,\n anchorPosition?: Side,\n): BehaviorConfiguration => {\n let arrowElement: HTMLDivElement | null =\n floatingElement.querySelector('.arrow');\n\n floatingElement.style.position = 'absolute';\n\n if (arrowElement === null) {\n arrowElement = document.createElement('div');\n arrowElement.className = 'arrow';\n floatingElement.appendChild(arrowElement);\n }\n\n return {\n config: {\n placement: anchorPosition ?? 'right',\n middleware: [\n offset(22),\n anchorPosition\n ? undefined\n : shift({\n limiter: limitShift({\n // modal.border-radius (32) + arrow.width(24) + margin of safety 8\n // this stops the caret from becoming detached from the modal due to\n // the border radius when it's being shifted\n offset: 64,\n }),\n }),\n flip({\n fallbackPlacements: anchorPosition ? [] : ['left', 'top', 'bottom'],\n }),\n // modal.border-radius (32)\n // this stops the caret from becoming detached from the modal due to\n // the border radius\n arrow({element: arrowElement, padding: 32}),\n {\n name: 'center',\n async fn() {\n // Ideally here we would use floating-ui's detectOverflow, but it was\n // returning some confusing values which caused the modal to center\n // when it shouldn't have. There wasn't enough time to dig into the issue\n // so going with the brute force option and using a media query. When\n // there is time to look into this, the code change will live here.\n // https://floating-ui.com/docs/detectOverflow\n const mediaQuery = window.matchMedia(\n `screen and (((min-width: ${\n SMALL_SCREEN_WIDTH + 1\n }px) and (max-width: ${MEDIUM_SCREEN_WIDTH - 1}px)) or (max-height: 750px))`,\n );\n\n return {\n data: {\n center: mediaQuery.matches,\n },\n };\n },\n },\n ],\n },\n fn: ({x, y, placement, strategy, middlewareData}) => {\n const {center} = middlewareData;\n\n if (center.center) {\n if (arrowElement !== null) {\n arrowElement.style.display = 'none';\n }\n // Fun math to center modal https://stackoverflow.com/a/62282447/603520\n Object.assign(floatingElement.style, {\n top: `${(window.innerHeight - floatingElement.offsetHeight) / 2}px`,\n left: `${(window.innerWidth - floatingElement.offsetWidth) / 2}px`,\n bottom: '',\n right: '',\n });\n\n return null;\n }\n\n Object.assign(floatingElement.style, {\n left: `${x}px`,\n top: `${y}px`,\n right: '',\n bottom: '',\n });\n\n const {arrow} = middlewareData;\n const staticSide = staticSideMap.get(placement) as Side;\n\n // only one of the x or y will be defined.\n // For top/bottom placement y will be defined\n // For left/right placement x will be defined\n // The -12px (1/2 of the 24x24) represents how much to shift the arrow off the\n // floating element to give the appearce of the arrow because in actuallity it is a square.\n if (arrowElement !== null) {\n Object.assign(arrowElement.style, {\n left: arrow?.x === undefined ? '' : `${arrow?.x}px`,\n top: arrow?.y === undefined ? '' : `${arrow?.y}px`,\n right: '',\n bottom: '',\n display: '',\n [staticSide]: '-12px',\n });\n }\n\n return {\n x,\n y,\n strategy,\n placement,\n staticSide,\n middlewareData,\n };\n },\n };\n};\n\nexport const mobileBehavior = (\n floatingElement: HTMLElement,\n): BehaviorConfiguration => ({\n config: {},\n fn: () => {\n Object.assign(floatingElement.style, {\n top: 'auto !important',\n right: '0 !important',\n bottom: '0 !important',\n left: 'auto',\n });\n\n return null;\n },\n});\n\nexport const corneredBehavior = (\n floatingElement: HTMLElement,\n overlayElement: HTMLElement,\n overrides: PositionOverrides = {},\n): BehaviorConfiguration => ({\n config: {},\n fn: () => {\n const arrowElement: HTMLDivElement | null =\n floatingElement.querySelector('.arrow');\n\n if (arrowElement !== null) {\n arrowElement.style.display = 'none';\n }\n\n const overridesPresent = Object.keys(overrides).length > 0;\n\n // set the overrides via css variables\n if (overridesPresent) {\n Object.assign(floatingElement.style, overrides, {position: 'absolute'});\n }\n\n overlayElement.classList.toggle('sda-cornered', !overridesPresent);\n\n return null;\n },\n});\n\nexport const config = {\n [PositionBehaviorType.Dynamic]: dynamicBehavior,\n [PositionBehaviorType.Center]: centerBehavior,\n [PositionBehaviorType.Mobile]: mobileBehavior,\n [PositionBehaviorType.Corner]: corneredBehavior,\n};\n","/**\n * @file Utility file which creates a singleton instance\n * used for communicating between components via a pub/sub mechanism\n */\n\nexport enum ShopHubTopic {\n UserStatusIdentity = 'userstatuschange:identity',\n UserStatusScope = 'userstatuschange:scope',\n UserSessionCreate = 'usersession:create',\n}\n\ninterface GenericTopicPayload {}\n\ninterface ShopHubTopicPayloadLookup {\n [ShopHubTopic.UserStatusIdentity]: GenericTopicPayload;\n [ShopHubTopic.UserStatusScope]: GenericTopicPayload;\n [ShopHubTopic.UserSessionCreate]: {\n avatar?: string;\n initial: string;\n email?: string;\n };\n}\n\n/**\n * The payload for a given topic, or the union of all payloads if no topic is specified\n * Usage:\n * ShopHubPayload // UserSessionCreatePayload\n * ShopHubPayload // GenericTopicPayload\n * ShopHubPayload // GenericTopicPayload | UserSessionCreatePayload | ...\n */\nexport type ShopHubPayload<\n TTopicType extends ShopHubTopic | undefined = undefined,\n> = TTopicType extends keyof ShopHubTopicPayloadLookup\n ? ShopHubTopicPayloadLookup[TTopicType]\n : ShopHubTopicPayloadLookup[keyof ShopHubTopicPayloadLookup];\n\ninterface ShopHubTopicEntry {\n publisherId: string;\n callback: (payload: ShopHubPayload) => void;\n}\ntype ShopHubTopicEntries = {\n [key in ShopHubTopic]?: ShopHubTopicEntry[];\n};\n\nexport const ShopHub = (() => {\n class ShopSingleton {\n private _topics: ShopHubTopicEntries;\n\n constructor() {\n this._topics = {};\n }\n\n subscribe(\n topic: TTopicType,\n publisherId: string,\n callback: (payload: ShopHubPayload) => void,\n ): void {\n this._topics[topic] = [\n // eslint-disable-next-line no-warning-comments\n // TODO: Fix TS error\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n ...(this._topics[topic] || []),\n {\n publisherId,\n callback,\n },\n ] as ShopHubTopicEntries[TTopicType];\n }\n\n unsubscribe(\n topic: TTopicType,\n publisherId: string,\n ): void {\n // eslint-disable-next-line no-warning-comments\n // TODO: Fix TS error\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n this._topics[topic] = (this._topics[topic] || []).filter(\n // eslint-disable-next-line no-warning-comments\n // TODO: Fix TS error\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n (entry) => entry.publisherId !== publisherId,\n ) as ShopHubTopicEntries[TTopicType];\n }\n\n unsubscribeAll(publisherId: string): void {\n Object.keys(this._topics).forEach((topic: string): void => {\n this.unsubscribe(topic as ShopHubTopic, publisherId);\n });\n }\n\n publish(\n topic: TTopicType,\n publisherId: string,\n payload: ShopHubPayload,\n ) {\n this._topics[topic]?.forEach((entry) => {\n if (entry.publisherId === publisherId) return;\n\n entry.callback(payload);\n });\n }\n }\n\n let instance: ShopSingleton;\n\n return {\n getInstance: (): ShopSingleton => {\n if (!instance) {\n instance = new ShopSingleton();\n }\n\n return instance;\n },\n };\n})();\n","/* eslint-disable @shopify/typescript-prefer-pascal-case-enums */\nimport type {MetricsConfig} from '@shopify/opentelemetry-sdk';\n\nenum MetricInstrumentType {\n Histogram = 'Histogram',\n Counter = 'Counter',\n UpDownCounter = 'UpDownCounter',\n}\n\nenum ValueType {\n INT = 0,\n DOUBLE = 1,\n}\n\nexport enum TelemetryMetricId {\n InvalidStorefrontOrigin = 'shop_js_invalid_storefront_origin',\n RequestShowCalledBeforeIframeLoaded = 'shop_js_request_show_called_before_iframe_loaded',\n HandleSilentError = 'shop_js_handle_silent_error',\n MonorailProducerError = 'shop_js_monorail_producer_error',\n}\n\nexport const metrics: MetricsConfig = {\n [TelemetryMetricId.InvalidStorefrontOrigin]: {\n type: MetricInstrumentType.Counter,\n description: 'Number of times the storefront origin is invalid',\n valueType: ValueType.INT,\n },\n [TelemetryMetricId.RequestShowCalledBeforeIframeLoaded]: {\n type: MetricInstrumentType.Counter,\n description:\n 'Number of times requestShow is called before iframe is loaded',\n valueType: ValueType.INT,\n },\n [TelemetryMetricId.HandleSilentError]: {\n type: MetricInstrumentType.Counter,\n description: 'Number of times silent errors are handled',\n valueType: ValueType.INT,\n },\n [TelemetryMetricId.MonorailProducerError]: {\n type: MetricInstrumentType.Counter,\n description: 'Number of times Monorail Producer failed to send event',\n valueType: ValueType.INT,\n },\n};\n","import {getAnalyticsTraceId} from './utils';\n\nexport class PayTimeoutError extends Error {\n name = 'PayTimeoutError';\n code = 'pay_timeout_error';\n\n constructor(\n message: string,\n public analyticsTraceId: string = getAnalyticsTraceId(),\n ) {\n super(message);\n }\n}\n\nexport class MonorailProducerError extends Error {\n name = 'MonorailProducerError';\n code = 'monorail_producer_error';\n\n constructor(\n message: string,\n public analyticsTraceId: string = getAnalyticsTraceId(),\n ) {\n super(message);\n }\n}\n\nexport class AbortSignalReceivedError extends Error {\n name = 'AbortSignalReceivedError';\n code = 'abort_signal_received_error';\n\n constructor(\n message: string,\n public analyticsTraceId: string = getAnalyticsTraceId(),\n ) {\n super(message);\n }\n}\n\nexport class CustomElementAlreadyDefinedError extends Error {\n name = 'CustomElementAlreadyDefinedError';\n code = 'custom_element_already_defined_error';\n\n constructor(\n message: string,\n public analyticsTraceId: string = getAnalyticsTraceId(),\n ) {\n super(message);\n }\n}\n","import type {DefaultOtelServiceOptions} from '@shopify/opentelemetry-sdk';\n\nimport {metrics} from './metrics';\n\nexport const options: DefaultOtelServiceOptions = {\n serviceName: 'shop-js',\n throttleLimit: 1000,\n prefixMetric: false,\n metrics,\n // NOTE:\n // If OtelService env variable is any value different from 'staging' or 'production',\n // it will attempt to send otel metrics to http://localhost:4318/v1/metrics\n // Since we are not running the otel collector locally, we will always use the staging.\n // eslint-disable-next-line no-process-env\n env: process.env.NODE_ENV === 'production' ? 'production' : 'staging',\n};\n","import type {OtelService} from '@shopify/opentelemetry-sdk';\n\nimport {getOtelService} from './opentelemetry';\n\nlet OtelServicePromise: Promise;\nlet retriesLeft = 3;\n\nexport const getOtelServiceSingleton: (\n overrideSingleton?: boolean,\n) => Promise = (overrideSingleton = false) => {\n if (OtelServicePromise && !overrideSingleton) {\n return OtelServicePromise;\n }\n\n OtelServicePromise = getOtelService();\n return OtelServicePromise;\n};\n\nexport const getOtelServiceSingletonWithRetries: () => Promise =\n async () => {\n try {\n const opentelService = await getOtelServiceSingleton(true);\n return opentelService;\n } catch (error) {\n retriesLeft--;\n if (retriesLeft > 0) {\n return getOtelServiceSingletonWithRetries();\n }\n throw error;\n }\n };\n","import type {OtelService} from '@shopify/opentelemetry-sdk';\n\nimport {options} from './options';\n\nexport const getOtelService: () => Promise = () => {\n return new Promise((resolve, reject) => {\n import('@shopify/opentelemetry-sdk')\n .then((OpentelImport) => {\n const DefaultOtelService = OpentelImport.DefaultOtelService;\n const otelService = new DefaultOtelService(options);\n resolve(otelService);\n })\n .catch((error) => {\n reject(error);\n });\n });\n};\n","import type {Attributes} from '@shopify/opentelemetry-sdk';\nimport Bugsnag from '__deprecated__/common/bugsnag';\n\nimport {getOtelServiceSingletonWithRetries} from './singleton';\nimport {TelemetryMetricId} from './metrics';\n\nexport const record: (\n telemetryMetricId: TelemetryMetricId,\n value: number,\n tags: Attributes,\n) => void = (telemetryMetricId, value, tags) => {\n // eslint-disable-next-line no-process-env\n if (!process.env.ENABLE_OPENTEL) return;\n\n getOtelServiceSingletonWithRetries()\n .then((otelService) => {\n otelService.record(telemetryMetricId, value, tags);\n })\n .catch((error) => {\n Bugsnag.notify(error);\n });\n};\n","import {\n recordOpentel,\n TelemetryMetricId,\n} from '__deprecated__/dynamicImports/opentelemetry';\n\n// eslint-disable-next-line no-process-env\nexport const PAY_AUTH_DOMAIN = process.env.PAY_AUTH_DOMAIN;\n// eslint-disable-next-line no-process-env\nexport const PAY_AUTH_DOMAIN_ALT = process.env.PAY_AUTH_ALT_DOMAIN;\n// eslint-disable-next-line no-process-env\nexport const SHOP_WEBSITE_DOMAIN = process.env.SHOP_WEBSITE_DOMAIN;\n\nexport enum InvalidUrlError {\n UsingLocalhost = 'using_localhost',\n NotUsingHttps = 'not_using_https',\n HasPath = 'has_path',\n HasHash = 'has_hash',\n HasSearch = 'has_search',\n InvalidUrl = 'invalid_url',\n}\n\n/**\n * Checks if the storefront origin is valid.\n * @param {string} storefrontOrigin - The storefront origin to validate.\n * @returns {boolean} True if the storefront origin is valid, false otherwise.\n */\nexport function validateStorefrontOrigin(storefrontOrigin: string): boolean {\n let error;\n try {\n const url = new URL(storefrontOrigin);\n if (\n (url.hostname === 'localhost' || url.hostname === '127.0.0.1') &&\n url.protocol !== 'https:'\n ) {\n error = InvalidUrlError.UsingLocalhost;\n } else if (url.protocol !== 'https:') {\n error = InvalidUrlError.NotUsingHttps;\n } else if (url.pathname !== '/') {\n error = InvalidUrlError.HasPath;\n } else if (url.hash) {\n error = InvalidUrlError.HasHash;\n } else if (url.search) {\n error = InvalidUrlError.HasSearch;\n }\n } catch (_) {\n error = InvalidUrlError.InvalidUrl;\n } finally {\n if (error) {\n // eslint-disable-next-line no-console\n console.error(`[shop-js] Invalid storefront origin: ${storefrontOrigin}`);\n recordOpentel(TelemetryMetricId.InvalidStorefrontOrigin, 1, {\n error,\n });\n }\n }\n\n return error === undefined;\n}\n","export const AUTHORIZE_POPUP_WIDTH = 432;\nexport const AUTHORIZE_POPUP_HEIGHT = 600;\n\nconst HEIGHT = '0';\nconst WIDTH = '100%';\n\nexport const LOAD_TIMEOUT_MS = 10000;\nexport const EMAIL_LISTENER_DEBOUNCE_MS = 200;\n\nexport const SHOP_LOGIN_BUTTON_HTML = ``;\nexport const SHOP_LOGIN_DEFAULT_STYLE = ``;\n\nexport const ERRORS = {\n temporarilyUnavailable: {\n code: 'temporarily_unavailable',\n message: 'Shop login is temporarily unavailable',\n },\n};\n\nexport const ATTRIBUTE_CLIENT_ID = 'client-id';\nexport const ATTRIBUTE_VERSION = 'version';\nexport const ATTRIBUTE_ACTION = 'action';\nexport const ATTRIBUTE_STOREFRONT_ORIGIN = 'storefront-origin';\nexport const ATTRIBUTE_KEEP_MODAL_OPEN = 'keep-modal-open';\n\n// Do not render the \"Contine with Shop\" button. Used if you only want to use the input listener or requestShow function.\nexport const ATTRIBUTE_HIDE_BUTTON = 'hide-button';\n\n// Prevent Pay from showing the sign up flow\nexport const ATTRIBUTE_DISABLE_SIGN_UP = 'disable-sign-up';\n\n// Redirect to this URI after successful Pay authentication\nexport const ATTRIBUTE_REDIRECT_URI = 'redirect-uri';\n\n// Redirect to this URI on click of the button\nexport const ATTRIBUTE_UX_MODE = 'ux-mode';\n\n// Attribute to indicate which redirect type to use (e.g. 'top_frame' or 'pop_up')\nexport const ATTRIBUTE_REDIRECT_TYPE = 'redirect-type';\n\n// Automatically open the modal if an active Pay user cookie is detected\nexport const ATTRIBUTE_AUTO_OPEN = 'auto-open';\n\n// String to define in which context shop-login-button is used. Each distinct feature should pass a unique analytics context string.\nexport const ATTRIBUTE_ANALYTICS_CONTEXT = 'analytics-context';\n\n// Analytics trace ID to override the default generated trace ID\nexport const ATTRIBUTE_ANALYTICS_TRACE_ID = 'analytics-trace-id';\n\n// Attribute which sets the `compact` layout in the component\nexport const ATTRIBUTE_COMPACT = 'compact';\n\n// Attribute which sets the position variant of the modal\nexport const ATTRIBUTE_POSITION_VARIANT = 'position-variant';\n\n// Attribute to indicate that you want to use the OAuth code flow (if value is 'code')\nexport const ATTRIBUTE_RESPONSE_TYPE = 'response-type';\n\n// Attribute to indicate what response-mode you want (e.g, 'query', 'web_message')\nexport const ATTRIBUTE_RESPONSE_MODE = 'response-mode';\n\n// Attribute for PKCE code challenge in an OAuth code flow\nexport const ATTRIBUTE_CODE_CHALLENGE = 'code-challenge';\n\n// Attribute for PKCE code challenge method in an OAuth code flow\nexport const ATTRIBUTE_CODE_CHALLENGE_METHOD = 'code-challenge-method';\n\n// Attribute for state in an OAuth code flow\nexport const ATTRIBUTE_STATE = 'state';\n\n// Attribute for scope in an OAuth code flow\nexport const ATTRIBUTE_SCOPE = 'scope';\n\n// Attribute for avoiding the pay alternate domain that enable features such as passkeys.\nexport const ATTRIBUTE_AVOID_PAY_ALT_DOMAIN = 'avoid-pay-alt-domain';\n\n// Attribute for avoiding the bouce through sdk-session and going straight to sdk-authorize\n// for performance if you're confident the user will never have a Pay session.\nexport const ATTRIBUTE_AVOID_SDK_SESSION = 'avoid-sdk-session';\n\n// Attribute to indicate what Sign In With Shop flow to use (e.g., 'prequal', 'default')\nexport const ATTRIBUTE_FLOW = 'flow';\n\n// Attribute to indicate the version of the Sign In With Shop flow (e.g., 'sign_in', 'sign_up')\nexport const ATTRIBUTE_FLOW_VERSION = 'flow-version';\n\n// Attribute for email login_hint\nexport const ATTRIBUTE_EMAIL = 'email';\n\n// Attribute for modal anchor\nexport const ATTRIBUTE_ANCHOR_SELECTOR = 'anchor-to';\n\n// Attribute to enable developer mode\nexport const ATTRIBUTE_DEV_MODE = 'dev-mode';\n\n// Attribute to customize the modal title\nexport const ATTRIBUTE_MODAL_TITLE = 'modal-title';\n\n// Attribute to customize the modal description\nexport const ATTRIBUTE_MODAL_DESCRIPTION = 'modal-description';\n\n// Attribute to customize the modal logo src\nexport const ATTRIBUTE_MODAL_LOGO_SRC = 'modal-logo-src';\n\n// Attribute for API key of the app\nexport const ATTRIBUTE_API_KEY = 'api-key';\n\nexport const ATTRIBUTE_POP_UP_NAME = 'pop-up-name';\n\nexport const ATTRIBUTE_POP_UP_FEATURES = 'pop-up-features';\n\nexport const ATTRIBUTE_MODAL_BRAND = 'modal-brand';\n\n// Enables the personalization consent feature for a specific use-case\nexport const ATTRIBUTE_CONSENT_CHALLENGE = 'consent-challenge';\n\nexport const ATTRIBUTE_CHECKOUT_REDIRECT_URL = 'checkout-redirect-url';\n\nexport const ATTRIBUTE_CHECKOUT_VERSION = 'checkout-version';\n\nexport const ATTRIBUTE_SHOP_ID = 'shop-id';\n\nexport const ATTRIBUTE_REQUIRE_VERIFICATION = 'require-verification';\n\n// Attributes to provide the customer's first & last name.\n// Note: If Shop derives a name from the Shop account's billing address, that will be preferred over these values.\nexport const ATTRIBUTE_FIRST_NAME = 'first-name';\nexport const ATTRIBUTE_LAST_NAME = 'last-name';\n\n// Additional data sent to Shop Server for the checkout modal use case.\nexport const ATTRIBUTE_CHECKOUT_TOKEN = 'checkout-token';\nexport const ATTRIBUTE_TRANSACTION_PARAMS = 'transaction-params';\n\nexport const ATTRIBUTE_SHOP_PERMANENT_DOMAIN = 'shop-permanent-domain';\n\nexport const ATTRIBUTE_SOURCE = 'source';\n"],"names":["DefaultComponentAnalyticsContext","Default","SelfServe","ClassicCustomerAccounts","Prequal","PaymentRequest","CheckoutExtension","CheckoutModal","CheckoutSheet","Web","ANALYTICS_CONTEXTS_TO_COMPACT","APP_VERSION","RELEASE_STAGES","getReleaseStage","addCompactUXMetadata","event","compactShopLoginButton","Array","from","document","querySelectorAll","filter","el","checkEligibleForCompactLayout","analyticsContext","getAttribute","includes","addMetadata","compactUX","length","metadata","metaData","Object","assign","onError","shopJsUrls","map","scriptTag","src","addBundleMetadata","featureAssets","_b","_a","window","Shopify","shopJsFeatureAssetsExist","Boolean","keys","addFeatureAssetsMetadata","domain","location","hostname","addDomainMetadata","groupingHash","exceptions","errorClass","message","addGroupingHash","request","url","href","addRequest","time","Date","toISOString","device","locale","navigator","userLanguage","language","userAgent","orientation","screen","type","addDevice","addGenericBugsnagOnError","bugsnagClient","addEventListener","error","stack","parseErrorStack","some","frame","file","isShopJsError","notify","client","Bugsnag","start","console","log","BugsnagLight","apiKey","config","bugsnagApiKey","appId","appVersion","bundleLocale","releaseStage","createBugsnagParams","leaveBreadcrumb","name","options","logError","Error","I18n","getDefaultLanguage","constructor","translations","_I18n_translations","set","this","_I18n_locale","__classPrivateFieldSet","__classPrivateFieldGet","allowedLocales","translate","scope","locals","scopes","split","ret","ReferenceError","_I18n_instances","_I18n_needsPluralize","call","count","_I18n_render","err","defaultValue","isEnglish","getAnalyticsTraceId","uuidv4","getHostName","storeUrl","URL","isRootDomainMatch","urlString1","urlString2","host1Tokens","host","reverse","host2Tokens","i","Math","min","getStorefrontAnalytics","analyticsTag","querySelector","innerHTML","JSON","parse","_I18n_getPluralizeKey","key","zero","translation","matches","match","reduce","res","replace","PositionBehaviorType","PositionVariant","Map","ShopHubTopic","MetricInstrumentType","ValueType","TelemetryMetricId","Dynamic","Center","Mobile","Corner","MonorailProducerError","analyticsTraceId","super","code","AbortSignalReceivedError","serviceName","throttleLimit","prefixMetric","metrics","InvalidStorefrontOrigin","Counter","description","valueType","INT","RequestShowCalledBeforeIframeLoaded","HandleSilentError","env","OtelServicePromise","retriesLeft","getOtelServiceSingleton","overrideSingleton","Promise","resolve","reject","import","then","OpentelImport","otelService","DefaultOtelService","catch","getOtelServiceSingletonWithRetries","__awaiter","record","telemetryMetricId","value","tags","PAY_AUTH_DOMAIN","PAY_AUTH_DOMAIN_ALT","InvalidUrlError","ATTRIBUTE_ANALYTICS_TRACE_ID"],"mappings":"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"}