@shopify/hydrogen 2023.4.2 → 2023.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/development/index.cjs +1 -1
- package/dist/development/index.cjs.map +1 -1
- package/dist/development/index.js +1 -1
- package/dist/development/index.js.map +1 -1
- package/dist/production/index.cjs +1 -1
- package/dist/production/index.cjs.map +1 -1
- package/dist/production/index.js +1 -1
- package/dist/production/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/seo/log-seo-tags.ts","../../src/storefront.ts","../../src/utils/hash.ts","../../src/cache/strategies.ts","../../src/utils/parse-json.ts","../../src/cache/api.ts","../../src/cache/sub-request.ts","../../src/cache/fetch.ts","../../src/constants.ts","../../src/utils/uuid.ts","../../src/utils/warning.ts","../../src/version.ts","../../src/with-cache.ts","../../src/cache/in-memory.ts","../../src/routing/redirect.ts","../../src/routing/graphiql.ts","../../src/seo/seo.ts","../../src/seo/generate-seo-tags.ts","../../src/pagination/Pagination.ts","../../src/index.ts"],"names":["isStale","result","errors","graphiqlLoader","schema","html","loggerMarkup","createElement","useMemo","useLocation","NextLink","params","flattenConnection","getShopifyCookies"],"mappings":"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","sourcesContent":["import type {CustomHeadTagObject} from './generate-seo-tags';\n\nexport default function Logger({headTags}: {headTags: CustomHeadTagObject[]}) {\n logSeoTags(headTags);\n\n return null;\n}\n\nconst headingStyle = 'text-transform: uppercase;';\nconst titleStyle =\n 'text-transform: uppercase; font-weight: bold; text-transform: uppercase;font-weight: bold';\n\nexport function logSeoTags(headTags: CustomHeadTagObject[]) {\n console.log(' ');\n console.log('%cSEO Meta Tags', `${titleStyle}`);\n console.log(' ');\n\n headTags.forEach((tag) => {\n if (tag.tag === 'script') {\n console.log(`%c• JSON LD `, headingStyle);\n\n if (tag.children) {\n try {\n console.table(JSON.parse(tag.children), ['name', 'content']);\n } catch {\n console.log(tag.children);\n }\n }\n } else {\n console.log(`%c• ${tag.tag} `, headingStyle);\n\n if (tag.children) {\n if (typeof tag.children === 'string') {\n console.log(`↳ ${tag.children}`);\n } else {\n try {\n Object.entries(JSON.parse(tag.children)).map(([key, val]) =>\n console.log(`↳ ${val}`),\n );\n } catch {\n console.log(tag.children);\n }\n }\n }\n\n if (tag.props.property === 'og:image:url') {\n const urlKey = tag.props.content as string;\n\n fetchImage(urlKey)\n .then((image) => {\n const imageStyle = `font-size: 400px; padding: 10px; background: white url(${image}) no-repeat center; background-size: contain;`;\n\n console.log(`%c• Share image preview`, headingStyle);\n console.log('%c ', imageStyle);\n console.log(`↳ ${urlKey}`);\n })\n .catch((err) => {\n console.error(err);\n });\n }\n\n Object.entries(tag.props).map(([key, val]) => {\n console.log(`↳ ${key} → ${val}`);\n });\n }\n console.log(' ');\n });\n}\n\nasync function fetchImage(url: string) {\n const result = await fetch(url);\n const data = await result.blob();\n const buff = await data.arrayBuffer();\n const base64String = arrayBufferToBase64(buff);\n\n return `data:image/png;base64,${base64String}`;\n}\n\nfunction arrayBufferToBase64(buffer: ArrayBuffer) {\n let binary = '';\n const bytes = new Uint8Array(buffer);\n const len = bytes.byteLength;\n\n for (let index = 0; index < len; index++) {\n binary += String.fromCharCode(bytes[index]);\n }\n\n return btoa(binary);\n}\n","import {\n createStorefrontClient as createStorefrontUtilities,\n getShopifyCookies,\n type StorefrontApiResponseOk,\n type StorefrontClientProps,\n SHOPIFY_S,\n SHOPIFY_Y,\n SHOPIFY_STOREFRONT_ID_HEADER,\n SHOPIFY_STOREFRONT_Y_HEADER,\n SHOPIFY_STOREFRONT_S_HEADER,\n} from '@shopify/hydrogen-react';\nimport type {ExecutionArgs} from 'graphql';\nimport {fetchWithServerCache, checkGraphQLErrors} from './cache/fetch';\nimport {STOREFRONT_REQUEST_GROUP_ID_HEADER} from './constants';\nimport {\n CacheNone,\n CacheLong,\n CacheShort,\n CacheCustom,\n generateCacheControlHeader,\n type CachingStrategy,\n} from './cache/strategies';\nimport {generateUUID} from './utils/uuid';\nimport {parseJSON} from './utils/parse-json';\nimport {\n CountryCode,\n LanguageCode,\n} from '@shopify/hydrogen-react/storefront-api-types';\nimport {warnOnce} from './utils/warning';\nimport {LIB_VERSION} from './version';\n\ntype StorefrontApiResponse<T> = StorefrontApiResponseOk<T>;\n\nexport type I18nBase = {\n language: LanguageCode;\n country: CountryCode;\n};\n\n/**\n * Wraps all the returned utilities from `createStorefrontClient`.\n */\nexport type StorefrontClient<TI18n extends I18nBase> = {\n storefront: Storefront<TI18n>;\n};\n\n/**\n * Maps all the queries found in the project to variables and return types.\n */\nexport interface StorefrontQueries {\n // Example of how a generated query type looks like:\n // '#graphql query q1 {...}': {return: Q1Query; variables: Q1QueryVariables};\n}\n\n/**\n * Maps all the mutations found in the project to variables and return types.\n */\nexport interface StorefrontMutations {\n // Example of how a generated mutation type looks like:\n // '#graphql mutation m1 {...}': {return: M1Mutation; variables: M1MutationVariables};\n}\n\n// Default type for `variables` in storefront client\ntype GenericVariables = ExecutionArgs['variableValues'];\n\n// Use this type to make parameters optional in storefront client\n// when no variables need to be passed.\ntype EmptyVariables = {[key: string]: never};\n\n// These are the variables that are automatically added to the storefront API.\n// We use this type to make parameters optional in storefront client\n// when these are the only variables that can be passed.\ntype AutoAddedVariableNames = 'country' | 'language';\n\ntype IsOptionalVariables<OperationTypeValue extends {variables: any}> = Omit<\n OperationTypeValue['variables'],\n AutoAddedVariableNames\n> extends EmptyVariables\n ? true // No need to pass variables\n : GenericVariables extends OperationTypeValue['variables']\n ? true // We don't know what variables are needed\n : false; // Variables are known and required\n\ntype StorefrontCommonOptions<Variables extends GenericVariables> = {\n headers?: HeadersInit;\n storefrontApiVersion?: string;\n} & (IsOptionalVariables<{variables: Variables}> extends true\n ? {variables?: Variables}\n : {variables: Variables});\n\ntype StorefrontQuerySecondParam<\n RawGqlString extends keyof StorefrontQueries | string = string,\n> = (RawGqlString extends keyof StorefrontQueries\n ? StorefrontCommonOptions<StorefrontQueries[RawGqlString]['variables']>\n : StorefrontCommonOptions<GenericVariables>) & {cache?: CachingStrategy};\n\ntype StorefrontMutateSecondParam<\n RawGqlString extends keyof StorefrontMutations | string = string,\n> = RawGqlString extends keyof StorefrontMutations\n ? StorefrontCommonOptions<StorefrontMutations[RawGqlString]['variables']>\n : StorefrontCommonOptions<GenericVariables>;\n\n/**\n * Interface to interact with the Storefront API.\n */\nexport type Storefront<TI18n extends I18nBase = I18nBase> = {\n /** The function to run a query on Storefront API. */\n query: <OverrideReturnType = any, RawGqlString extends string = string>(\n query: RawGqlString,\n ...options: RawGqlString extends keyof StorefrontQueries // Do we have any generated query types?\n ? IsOptionalVariables<StorefrontQueries[RawGqlString]> extends true\n ? [StorefrontQuerySecondParam<RawGqlString>?] // Using codegen, query has no variables\n : [StorefrontQuerySecondParam<RawGqlString>] // Using codegen, query needs variables\n : [StorefrontQuerySecondParam?] // No codegen, variables always optional\n ) => Promise<\n RawGqlString extends keyof StorefrontQueries // Do we have any generated query types?\n ? StorefrontQueries[RawGqlString]['return'] // Using codegen, return type is known\n : OverrideReturnType // No codegen, let user specify return type\n >;\n /** The function to run a mutation on Storefront API. */\n mutate: <OverrideReturnType = any, RawGqlString extends string = string>(\n mutation: RawGqlString,\n ...options: RawGqlString extends keyof StorefrontMutations // Do we have any generated mutation types?\n ? IsOptionalVariables<StorefrontMutations[RawGqlString]> extends true\n ? [StorefrontMutateSecondParam<RawGqlString>?] // Using codegen, mutation has no variables\n : [StorefrontMutateSecondParam<RawGqlString>] // Using codegen, mutation needs variables\n : [StorefrontMutateSecondParam?] // No codegen, variables always optional\n ) => Promise<\n RawGqlString extends keyof StorefrontMutations // Do we have any generated mutation types?\n ? StorefrontMutations[RawGqlString]['return'] // Using codegen, return type is known\n : OverrideReturnType // No codegen, let user specify return type\n >;\n /** The cache instance passed in from the `createStorefrontClient` argument. */\n cache?: Cache;\n /** Re-export of [`CacheNone`](/docs/api/hydrogen/utilities/cachenone). */\n CacheNone: typeof CacheNone;\n /** Re-export of [`CacheLong`](/docs/api/hydrogen/utilities/cachelong). */\n CacheLong: typeof CacheLong;\n /** Re-export of [`CacheShort`](/docs/api/hydrogen/utilities/cacheshort). */\n CacheShort: typeof CacheShort;\n /** Re-export of [`CacheCustom`](/docs/api/hydrogen/utilities/cachecustom). */\n CacheCustom: typeof CacheCustom;\n /** Re-export of [`generateCacheControlHeader`](/docs/api/hydrogen/utilities/generatecachecontrolheader). */\n generateCacheControlHeader: typeof generateCacheControlHeader;\n /** Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint. See [`getPublicTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/utilities/createstorefrontclient#:~:text=%27graphql%27.-,getPublicTokenHeaders,-(props%3F%3A) for more details. */\n getPublicTokenHeaders: ReturnType<\n typeof createStorefrontUtilities\n >['getPublicTokenHeaders'];\n /** Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint for API calls made from a server. See [`getPrivateTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/utilities/createstorefrontclient#:~:text=storefrontApiVersion-,getPrivateTokenHeaders,-(props%3F%3A) for more details.*/\n getPrivateTokenHeaders: ReturnType<\n typeof createStorefrontUtilities\n >['getPrivateTokenHeaders'];\n /** Creates the fully-qualified URL to your myshopify.com domain. See [`getShopifyDomain` in Hydrogen React](/docs/api/hydrogen-react/utilities/createstorefrontclient#:~:text=StorefrontClientReturn-,getShopifyDomain,-(props%3F%3A) for more details. */\n getShopifyDomain: ReturnType<\n typeof createStorefrontUtilities\n >['getShopifyDomain'];\n /** Creates the fully-qualified URL to your store's GraphQL endpoint. See [`getStorefrontApiUrl` in Hydrogen React](/docs/api/hydrogen-react/utilities/createstorefrontclient#:~:text=storeDomain-,getStorefrontApiUrl,-(props%3F%3A) for more details.*/\n getApiUrl: ReturnType<\n typeof createStorefrontUtilities\n >['getStorefrontApiUrl'];\n /** Determines if the error is resulted from a Storefront API call. */\n isApiError: (error: any) => boolean;\n /** The `i18n` object passed in from the `createStorefrontClient` argument. */\n i18n: TI18n;\n};\n\ntype HydrogenClientProps<TI18n> = {\n /** Storefront API headers. If on Oxygen, use `getStorefrontHeaders()` */\n storefrontHeaders?: StorefrontHeaders;\n /** An instance that implements the [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache) */\n cache?: Cache;\n /** @deprecated use storefrontHeaders instead */\n buyerIp?: string;\n /** @deprecated use storefrontHeaders instead */\n requestGroupId?: string | null;\n /** The globally unique identifier for the Shop */\n storefrontId?: string;\n /** The `waitUntil` function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform. */\n waitUntil?: ExecutionContext['waitUntil'];\n /** An object containing a country code and language code */\n i18n?: TI18n;\n};\n\nexport type CreateStorefrontClientOptions<TI18n extends I18nBase> =\n HydrogenClientProps<TI18n> & StorefrontClientProps;\n\ntype StorefrontHeaders = {\n /** A unique ID that correlates all sub-requests together. */\n requestGroupId: string | null;\n /** The IP address of the client. */\n buyerIp: string | null;\n /** The cookie header from the client */\n cookie: string | null;\n};\n\ntype StorefrontQueryOptions = StorefrontQuerySecondParam & {\n query: string;\n mutation?: never;\n};\n\ntype StorefrontMutationOptions = StorefrontMutateSecondParam & {\n query?: never;\n mutation: string;\n cache?: never;\n};\n\nconst StorefrontApiError = class extends Error {} as ErrorConstructor;\nexport const isStorefrontApiError = (error: any) =>\n error instanceof StorefrontApiError;\n\nconst isQueryRE = /(^|}\\s)query[\\s({]/im;\nconst isMutationRE = /(^|}\\s)mutation[\\s({]/im;\n\nfunction minifyQuery(string: string) {\n return string\n .replace(/\\s*#.*$/gm, '') // Remove GQL comments\n .replace(/\\s+/gm, ' ') // Minify spaces\n .trim();\n}\n\nconst defaultI18n: I18nBase = {language: 'EN', country: 'US'};\n\n/**\n * This function extends `createStorefrontClient` from [Hydrogen React](/docs/api/hydrogen-react/latest/utilities/createstorefrontclient). The additional arguments enable internationalization (i18n), caching, and other features particular to Remix and Oxygen.\n *\n * Learn more about [data fetching in Hydrogen](/docs/custom-storefronts/hydrogen/data-fetching/fetch-data).\n */\nexport function createStorefrontClient<TI18n extends I18nBase>(\n options: CreateStorefrontClientOptions<TI18n>,\n): StorefrontClient<TI18n> {\n const {\n storefrontHeaders,\n cache,\n waitUntil,\n buyerIp,\n i18n,\n requestGroupId,\n storefrontId,\n ...clientOptions\n } = options;\n if (!cache) {\n // TODO: should only warn in development\n warnOnce(\n 'Storefront API client created without a cache instance. This may slow down your sub-requests.',\n );\n }\n\n const {\n getPublicTokenHeaders,\n getPrivateTokenHeaders,\n getStorefrontApiUrl,\n getShopifyDomain,\n } = createStorefrontUtilities(clientOptions);\n\n const getHeaders = clientOptions.privateStorefrontToken\n ? getPrivateTokenHeaders\n : getPublicTokenHeaders;\n\n const defaultHeaders = getHeaders({\n contentType: 'json',\n buyerIp: storefrontHeaders?.buyerIp || buyerIp,\n });\n\n defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] =\n storefrontHeaders?.requestGroupId || requestGroupId || generateUUID();\n\n if (storefrontId) defaultHeaders[SHOPIFY_STOREFRONT_ID_HEADER] = storefrontId;\n if (LIB_VERSION) defaultHeaders['user-agent'] = `Hydrogen ${LIB_VERSION}`;\n\n if (storefrontHeaders && storefrontHeaders.cookie) {\n const cookies = getShopifyCookies(storefrontHeaders.cookie ?? '');\n\n if (cookies[SHOPIFY_Y])\n defaultHeaders[SHOPIFY_STOREFRONT_Y_HEADER] = cookies[SHOPIFY_Y];\n if (cookies[SHOPIFY_S])\n defaultHeaders[SHOPIFY_STOREFRONT_S_HEADER] = cookies[SHOPIFY_S];\n }\n\n // Deprecation warning\n if (!storefrontHeaders) {\n warnOnce(\n '\"requestGroupId\" and \"buyerIp\" will be deprecated in the next calendar release. Please use \"getStorefrontHeaders\"',\n );\n }\n\n async function fetchStorefrontApi<T>({\n query,\n mutation,\n variables,\n cache: cacheOptions,\n headers = [],\n storefrontApiVersion,\n }: StorefrontQueryOptions | StorefrontMutationOptions): Promise<T> {\n const userHeaders =\n headers instanceof Headers\n ? Object.fromEntries(headers.entries())\n : Array.isArray(headers)\n ? Object.fromEntries(headers)\n : headers;\n\n query = query ?? mutation;\n\n const queryVariables = {...variables};\n\n if (i18n) {\n if (!variables?.country && /\\$country/.test(query)) {\n queryVariables.country = i18n.country;\n }\n\n if (!variables?.language && /\\$language/.test(query)) {\n queryVariables.language = i18n.language;\n }\n }\n\n const url = getStorefrontApiUrl({storefrontApiVersion});\n const requestInit: RequestInit = {\n method: 'POST',\n headers: {...defaultHeaders, ...userHeaders},\n body: JSON.stringify({\n query,\n variables: queryVariables,\n }),\n };\n\n const [body, response] = await fetchWithServerCache(url, requestInit, {\n cacheInstance: mutation ? undefined : cache,\n cache: cacheOptions || CacheShort(),\n shouldCacheResponse: checkGraphQLErrors,\n waitUntil,\n });\n\n if (!response.ok) {\n /**\n * The Storefront API might return a string error, or a JSON-formatted {error: string}.\n * We try both and conform them to a single {errors} format.\n */\n let errors;\n try {\n errors = parseJSON(body);\n } catch (_e) {\n errors = [{message: body}];\n }\n\n throwError(response, errors);\n }\n\n const {data, errors} = body as StorefrontApiResponse<T>;\n\n if (errors?.length) throwError(response, errors, StorefrontApiError);\n\n return data as T;\n }\n\n return {\n storefront: {\n /**\n * Sends a GraphQL query to the Storefront API.\n *\n * Example:\n *\n * ```js\n * async function loader ({context: {storefront}}) {\n * const data = await storefront.query('query { ... }', {\n * variables: {},\n * cache: storefront.CacheLong()\n * });\n * }\n * ```\n */\n query: <Storefront['query']>((query: string, payload) => {\n query = minifyQuery(query);\n if (isMutationRE.test(query))\n throw new Error('storefront.query cannot execute mutations');\n\n return fetchStorefrontApi({...payload, query});\n }),\n /**\n * Sends a GraphQL mutation to the Storefront API.\n *\n * Example:\n *\n * ```js\n * async function loader ({context: {storefront}}) {\n * await storefront.mutate('mutation { ... }', {\n * variables: {},\n * });\n * }\n * ```\n */\n mutate: <Storefront['mutate']>((mutation: string, payload) => {\n mutation = minifyQuery(mutation);\n if (isQueryRE.test(mutation))\n throw new Error('storefront.mutate cannot execute queries');\n\n return fetchStorefrontApi({...payload, mutation});\n }),\n cache,\n CacheNone,\n CacheLong,\n CacheShort,\n CacheCustom,\n generateCacheControlHeader,\n getPublicTokenHeaders,\n getPrivateTokenHeaders,\n getShopifyDomain,\n getApiUrl: getStorefrontApiUrl,\n /**\n * Wether it's a GraphQL error returned in the Storefront API response.\n *\n * Example:\n *\n * ```js\n * async function loader ({context: {storefront}}) {\n * try {\n * await storefront.query(...);\n * } catch(error) {\n * if (storefront.isApiError(error)) {\n * // ...\n * }\n *\n * throw error;\n * }\n * }\n * ```\n */\n isApiError: isStorefrontApiError,\n i18n: (i18n ?? defaultI18n) as TI18n,\n },\n };\n}\n\nfunction throwError<T>(\n response: Response,\n errors: StorefrontApiResponse<T>['errors'],\n ErrorConstructor = Error,\n) {\n const reqId = response.headers.get('x-request-id');\n const reqIdMessage = reqId ? ` - Request ID: ${reqId}` : '';\n\n if (errors) {\n const errorMessages =\n typeof errors === 'string'\n ? errors\n : errors.map((error) => error.message).join('\\n');\n\n throw new ErrorConstructor(errorMessages + reqIdMessage);\n }\n\n throw new ErrorConstructor(\n `API response error: ${response.status}` + reqIdMessage,\n );\n}\n","type QueryKey = string | readonly unknown[];\n\nexport function hashKey(queryKey: QueryKey): string {\n const rawKeys = Array.isArray(queryKey) ? queryKey : [queryKey];\n let hash = '';\n\n // Keys from `storefront.query` are in the following shape:\n // ['prefix', 'api-endpoint', {body:'query',headers:{}}]\n // Since the API endpoint already contains the shop domain and api version,\n // we can ignore the headers and only use the `body` from the payload.\n for (const key of rawKeys) {\n if (key != null) {\n if (typeof key === 'object') {\n // Queries from useQuery might not have a `body`. In that case,\n // fallback to a safer (but slower) stringify.\n if (!!key.body && typeof key.body === 'string') {\n hash += key.body;\n } else {\n hash += JSON.stringify(key);\n }\n } else {\n hash += key;\n }\n }\n }\n\n return hash;\n}\n","/**\n * Override options for a cache strategy.\n */\nexport interface AllCacheOptions {\n /**\n * The caching mode, generally `public`, `private`, or `no-store`.\n */\n mode?: string;\n /**\n * The maximum amount of time in seconds that a resource will be considered fresh. See `max-age` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#:~:text=Response%20Directives-,max%2Dage,-The%20max%2Dage).\n */\n maxAge?: number;\n /**\n * Indicate that the cache should serve the stale response in the background while revalidating the cache. See `stale-while-revalidate` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate).\n */\n staleWhileRevalidate?: number;\n /**\n * Similar to `maxAge` but specific to shared caches. See `s-maxage` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#s-maxage).\n */\n sMaxAge?: number;\n /**\n * Indicate that the cache should serve the stale response if an error occurs while revalidating the cache. See `stale-if-error` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-if-error).\n */\n staleIfError?: number;\n}\n\n/**\n * Use the `CachingStrategy` to define a custom caching mechanism for your data. Or use one of the pre-defined caching strategies: CacheNone, CacheShort, CacheLong.\n */\nexport type CachingStrategy = AllCacheOptions;\n\nexport type NoStoreStrategy = {\n mode: string;\n};\n\nconst PUBLIC = 'public';\nconst PRIVATE = 'private';\nexport const NO_STORE = 'no-store';\n\nconst optionMapping: {\n [key: string]: string;\n} = {\n maxAge: 'max-age',\n staleWhileRevalidate: 'stale-while-revalidate',\n sMaxAge: 's-maxage',\n staleIfError: 'stale-if-error',\n};\n\nexport function generateCacheControlHeader(\n cacheOptions: CachingStrategy,\n): string {\n const cacheControl: string[] = [];\n Object.keys(cacheOptions).forEach((key: string) => {\n if (key === 'mode') {\n cacheControl.push(cacheOptions[key] as string);\n } else if (optionMapping[key]) {\n cacheControl.push(\n `${optionMapping[key]}=${cacheOptions[key as keyof CachingStrategy]}`,\n );\n }\n });\n return cacheControl.join(', ');\n}\n\n/**\n *\n * @public\n */\nexport function CacheNone(): NoStoreStrategy {\n return {\n mode: NO_STORE,\n };\n}\n\nfunction guardExpirableModeType(overrideOptions?: CachingStrategy) {\n if (\n overrideOptions?.mode &&\n overrideOptions?.mode !== PUBLIC &&\n overrideOptions?.mode !== PRIVATE\n ) {\n throw Error(\"'mode' must be either 'public' or 'private'\");\n }\n}\n\n/**\n *\n * @public\n */\nexport function CacheShort(overrideOptions?: CachingStrategy): AllCacheOptions {\n guardExpirableModeType(overrideOptions);\n return {\n mode: PUBLIC,\n maxAge: 1,\n staleWhileRevalidate: 9,\n ...overrideOptions,\n };\n}\n\n/**\n *\n * @public\n */\nexport function CacheLong(overrideOptions?: CachingStrategy): AllCacheOptions {\n guardExpirableModeType(overrideOptions);\n return {\n mode: PUBLIC,\n maxAge: 3600, // 1 hour\n staleWhileRevalidate: 82800, // 23 Hours\n ...overrideOptions,\n };\n}\n\n/**\n *\n * @public\n */\nexport function CacheCustom(overrideOptions: CachingStrategy): AllCacheOptions {\n return overrideOptions as AllCacheOptions;\n}\n","export function parseJSON(json: any) {\n if (String(json).includes('__proto__')) return JSON.parse(json, noproto);\n return JSON.parse(json);\n}\nfunction noproto(k: string, v: string) {\n if (k !== '__proto__') return v;\n}\n","import type {CachingStrategy} from './strategies';\nimport {CacheShort, generateCacheControlHeader} from './strategies';\n\nfunction logCacheApiStatus(status: string | null, url: string) {\n // // eslint-disable-next-line no-console\n // console.log('\\n' + status, url);\n}\n\nfunction getCacheControlSetting(\n userCacheOptions?: CachingStrategy,\n options?: CachingStrategy,\n): CachingStrategy {\n if (userCacheOptions && options) {\n return {\n ...userCacheOptions,\n ...options,\n };\n } else {\n return userCacheOptions || CacheShort();\n }\n}\n\nfunction generateDefaultCacheControlHeader(\n userCacheOptions?: CachingStrategy,\n): string {\n return generateCacheControlHeader(getCacheControlSetting(userCacheOptions));\n}\n\n/**\n * Get an item from the cache. If a match is found, returns a tuple\n * containing the `JSON.parse` version of the response as well\n * as the response itself so it can be checked for staleness.\n */\nasync function getItem(\n cache: Cache,\n request: Request,\n): Promise<Response | undefined> {\n if (!cache) return;\n\n const response = await cache.match(request);\n if (!response) {\n logCacheApiStatus('MISS', request.url);\n return;\n }\n\n logCacheApiStatus('HIT', request.url);\n\n return response;\n}\n\n/**\n * Put an item into the cache.\n */\nasync function setItem(\n cache: Cache,\n request: Request,\n response: Response,\n userCacheOptions: CachingStrategy,\n) {\n if (!cache) return;\n\n /**\n * We are manually managing staled request by adding this workaround.\n * Why? cache control header support is dependent on hosting platform\n *\n * For example:\n *\n * Cloudflare's Cache API does not support `stale-while-revalidate`.\n * Cloudflare cache control header has a very odd behaviour.\n * Say we have the following cache control header on a request:\n *\n * public, max-age=15, stale-while-revalidate=30\n *\n * When there is a cache.match HIT, the cache control header would become\n *\n * public, max-age=14400, stale-while-revalidate=30\n *\n * == `stale-while-revalidate` workaround ==\n * Update response max-age so that:\n *\n * max-age = max-age + stale-while-revalidate\n *\n * For example:\n *\n * public, max-age=1, stale-while-revalidate=9\n * |\n * V\n * public, max-age=10, stale-while-revalidate=9\n *\n * Store the following information in the response header:\n *\n * cache-put-date - UTC time string of when this request is PUT into cache\n *\n * Note on `cache-put-date`: The `response.headers.get('date')` isn't static. I am\n * not positive what date this is returning but it is never over 500 ms\n * after subtracting from the current timestamp.\n *\n * `isStale` function will use the above information to test for stale-ness of a cached response\n */\n\n const cacheControl = getCacheControlSetting(userCacheOptions);\n\n // The padded cache-control to mimic stale-while-revalidate\n request.headers.set(\n 'cache-control',\n generateDefaultCacheControlHeader(\n getCacheControlSetting(cacheControl, {\n maxAge:\n (cacheControl.maxAge || 0) + (cacheControl.staleWhileRevalidate || 0),\n }),\n ),\n );\n // The cache-control we want to set on response\n const cacheControlString = generateDefaultCacheControlHeader(\n getCacheControlSetting(cacheControl),\n );\n\n // CF will override cache-control, so we need to keep a non-modified real-cache-control\n // cache-control is still necessary for mini-oxygen\n response.headers.set('cache-control', cacheControlString);\n response.headers.set('real-cache-control', cacheControlString);\n response.headers.set('cache-put-date', new Date().toUTCString());\n\n logCacheApiStatus('PUT', request.url);\n await cache.put(request, response);\n}\n\nasync function deleteItem(cache: Cache, request: Request) {\n if (!cache) return;\n\n logCacheApiStatus('DELETE', request.url);\n await cache.delete(request);\n}\n\n/**\n * Manually check the response to see if it's stale.\n */\nfunction isStale(request: Request, response: Response) {\n const responseDate = response.headers.get('cache-put-date');\n const cacheControl = response.headers.get('real-cache-control');\n let responseMaxAge = 0;\n\n if (cacheControl) {\n const maxAgeMatch = cacheControl.match(/max-age=(\\d*)/);\n if (maxAgeMatch && maxAgeMatch.length > 1) {\n responseMaxAge = parseFloat(maxAgeMatch[1]);\n }\n }\n\n if (!responseDate) {\n return false;\n }\n\n const ageInMs =\n new Date().valueOf() - new Date(responseDate as string).valueOf();\n const age = ageInMs / 1000;\n\n const result = age > responseMaxAge;\n\n if (result) {\n logCacheApiStatus('STALE', request.url);\n }\n\n return result;\n}\n\n/**\n *\n * @private\n */\nexport const CacheAPI = {\n get: getItem,\n set: setItem,\n delete: deleteItem,\n generateDefaultCacheControlHeader,\n isStale,\n};\n","import {parseJSON} from '../utils/parse-json';\nimport {CacheAPI} from './api';\nimport {\n CacheShort,\n type CachingStrategy,\n type AllCacheOptions,\n} from './strategies.js';\n\n/**\n * Wrapper Cache functions for sub queries\n */\n\n/**\n * Cache API is weird. We just need a full URL, so we make one up.\n */\nfunction getKeyUrl(key: string) {\n return `https://shopify.dev/?${key}`;\n}\n\nfunction getCacheOption(userCacheOptions?: CachingStrategy): AllCacheOptions {\n return userCacheOptions || CacheShort();\n}\n\nexport function generateSubRequestCacheControlHeader(\n userCacheOptions?: CachingStrategy,\n): string {\n return CacheAPI.generateDefaultCacheControlHeader(\n getCacheOption(userCacheOptions),\n );\n}\n\n/**\n * Get an item from the cache. If a match is found, returns a tuple\n * containing the `JSON.parse` version of the response as well\n * as the response itself so it can be checked for staleness.\n * @private\n */\nexport async function getItemFromCache(\n cache: Cache,\n key: string,\n): Promise<undefined | [any, Response]> {\n if (!cache) return;\n const url = getKeyUrl(key);\n const request = new Request(url);\n\n const response = await CacheAPI.get(cache, request);\n\n if (!response) {\n return;\n }\n\n const text = await response.text();\n try {\n return [parseJSON(text), response];\n } catch {\n return [text, response];\n }\n}\n\n/**\n * Put an item into the cache.\n * @private\n */\nexport async function setItemInCache(\n cache: Cache,\n key: string,\n value: any,\n userCacheOptions?: CachingStrategy,\n) {\n if (!cache) return;\n\n const url = getKeyUrl(key);\n const request = new Request(url);\n const response = new Response(JSON.stringify(value));\n\n await CacheAPI.set(\n cache,\n request,\n response,\n getCacheOption(userCacheOptions),\n );\n}\n\n/**\n *\n * @private\n */\nexport async function deleteItemFromCache(cache: Cache, key: string) {\n if (!cache) return;\n\n const url = getKeyUrl(key);\n const request = new Request(url);\n\n await CacheAPI.delete(cache, request);\n}\n\n/**\n * Manually check the response to see if it's stale.\n * @private\n */\nexport function isStale(key: string, response: Response) {\n return CacheAPI.isStale(new Request(getKeyUrl(key)), response);\n}\n","import {hashKey} from '../utils/hash.js';\nimport {CacheShort, CachingStrategy} from './strategies';\nimport {getItemFromCache, setItemInCache, isStale} from './sub-request';\n\n/**\n * The cache key is used to uniquely identify a value in the cache.\n */\nexport type CacheKey = string | readonly unknown[];\n\nexport type WithCacheOptions<T = unknown> = {\n strategy?: CachingStrategy | null;\n cacheInstance?: Cache;\n shouldCacheResult?: (value: T) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n};\n\nexport type FetchCacheOptions = {\n cache?: CachingStrategy;\n cacheInstance?: Cache;\n cacheKey?: CacheKey;\n shouldCacheResponse?: (body: any, response: Response) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n returnType?: 'json' | 'text' | 'arrayBuffer' | 'blob';\n};\n\nfunction toSerializableResponse(body: any, response: Response) {\n return [\n body,\n {\n status: response.status,\n statusText: response.statusText,\n headers: Array.from(response.headers.entries()),\n },\n ] satisfies [any, ResponseInit];\n}\n\nfunction fromSerializableResponse([body, init]: [any, ResponseInit]) {\n return [body, new Response(body, init)] as const;\n}\n\n// Check if the response body has GraphQL errors\n// https://spec.graphql.org/June2018/#sec-Response-Format\nexport const checkGraphQLErrors = (body: any) => !body?.errors;\n\n// Lock to prevent revalidating the same sub-request\n// in the same isolate. Note that different isolates\n// in the same colo could duplicate the revalidation\n// since this is only an in-memory lock.\n// https://github.com/Shopify/oxygen-platform/issues/625\nconst swrLock = new Set<string>();\n\nexport async function runWithCache<T = unknown>(\n cacheKey: CacheKey,\n actionFn: () => T | Promise<T>,\n {\n strategy = CacheShort(),\n cacheInstance,\n shouldCacheResult = () => true,\n waitUntil,\n }: WithCacheOptions<T>,\n): Promise<T> {\n if (!cacheInstance || !strategy) return actionFn();\n\n const key = hashKey([\n // '__HYDROGEN_CACHE_ID__', // TODO purgeQueryCacheOnBuild\n ...(typeof cacheKey === 'string' ? [cacheKey] : cacheKey),\n ]);\n\n const cachedItem = await getItemFromCache(cacheInstance, key);\n // console.log('--- Cache', cachedItem ? 'HIT' : 'MISS');\n\n if (cachedItem) {\n const [cachedResult, cacheInfo] = cachedItem;\n\n if (!swrLock.has(key) && isStale(key, cacheInfo)) {\n swrLock.add(key);\n\n // Important: Run revalidation asynchronously.\n const revalidatingPromise = Promise.resolve().then(async () => {\n try {\n const result = await actionFn();\n\n if (shouldCacheResult(result)) {\n await setItemInCache(cacheInstance, key, result, strategy);\n }\n } catch (error: any) {\n if (error.message) {\n error.message = 'SWR in sub-request failed: ' + error.message;\n }\n\n console.error(error);\n } finally {\n swrLock.delete(key);\n }\n });\n\n // Asynchronously wait for it in workers\n waitUntil?.(revalidatingPromise);\n }\n\n return cachedResult;\n }\n\n const result = await actionFn();\n\n /**\n * Important: Do this async\n */\n if (shouldCacheResult(result)) {\n const setItemInCachePromise = setItemInCache(\n cacheInstance,\n key,\n result,\n strategy,\n );\n\n waitUntil?.(setItemInCachePromise);\n }\n\n return result;\n}\n\n/**\n * `fetch` equivalent that stores responses in cache.\n * Useful for calling third-party APIs that need to be cached.\n * @private\n */\nexport async function fetchWithServerCache(\n url: string,\n requestInit: Request | RequestInit,\n {\n cacheInstance,\n cache: cacheOptions,\n cacheKey = [url, requestInit],\n shouldCacheResponse = () => true,\n waitUntil,\n returnType = 'json',\n }: FetchCacheOptions = {},\n): Promise<readonly [any, Response]> {\n if (!cacheOptions && (!requestInit.method || requestInit.method === 'GET')) {\n cacheOptions = CacheShort();\n }\n\n return runWithCache(\n cacheKey,\n async () => {\n const response = await fetch(url, requestInit);\n let data;\n\n try {\n data = await response[returnType]();\n } catch {\n data = await response.text();\n }\n\n return toSerializableResponse(data, response);\n },\n {\n cacheInstance,\n waitUntil,\n strategy: cacheOptions ?? null,\n shouldCacheResult: (result) =>\n shouldCacheResponse(...fromSerializableResponse(result)),\n },\n ).then(fromSerializableResponse);\n}\n","export const STOREFRONT_REQUEST_GROUP_ID_HEADER =\n 'Custom-Storefront-Request-Group-ID';\n","/*\n * Generate a UUID using crypto and fallback to Math.random if crypto is not available.\n */\nexport function generateUUID() {\n if (typeof crypto !== 'undefined' && !!crypto.randomUUID) {\n return crypto.randomUUID();\n } else {\n return `weak-${Math.random().toString(16).substring(2)}`;\n }\n}\n","const warnings = new Set<string>();\nexport const warnOnce = (string: string) => {\n if (!warnings.has(string)) {\n console.warn(string);\n warnings.add(string);\n }\n};\n","export const LIB_VERSION = '2023.4.2';\n","import {type CacheKey, runWithCache} from './cache/fetch';\nimport type {CachingStrategy} from './cache/strategies';\n\ntype CreateWithCacheOptions = {\n /** An instance that implements the [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache) */\n cache: Cache;\n /** The `waitUntil` function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform. */\n waitUntil: ExecutionContext['waitUntil'];\n};\n\n/**\n * Creates a utility function that executes an asynchronous operation\n * like `fetch` and caches the result according to the strategy provided.\n * Use this to call any third-party APIs from loaders or actions.\n * By default, it uses the `CacheShort` strategy.\n *\n */\nexport function createWithCache_unstable<T = unknown>(\n options: CreateWithCacheOptions,\n): CreateWithCacheReturn<T> {\n const {cache, waitUntil} = options;\n return function withCache<T = unknown>(\n cacheKey: CacheKey,\n strategy: CachingStrategy,\n actionFn: () => T | Promise<T>,\n ) {\n return runWithCache<T>(cacheKey, actionFn, {\n strategy,\n cacheInstance: cache,\n waitUntil,\n });\n };\n}\n\n/**\n * This is a caching async function. Whatever data is returned from the `actionFn` will be cached according to the strategy provided.\n *\n * Use the `CachingStrategy` to define a custom caching mechanism for your data. Or use one of the built-in caching strategies: `CacheNone`, `CacheShort`, `CacheLong`.\n */\ntype CreateWithCacheReturn<T> = (\n cacheKey: CacheKey,\n strategy: CachingStrategy,\n actionFn: () => T | Promise<T>,\n) => Promise<T>;\n\nexport type WithCache = ReturnType<typeof createWithCache_unstable>;\n","type CacheMatch = {\n body: Uint8Array;\n timestamp: number;\n status: number;\n headers: [string, string][];\n};\n\n/**\n * This is a limited implementation of an in-memory cache.\n * It only supports the `cache-control` header.\n * It does NOT support `age` or `expires` headers.\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Cache\n */\nexport class InMemoryCache implements Cache {\n #store: Map<string, CacheMatch>;\n\n constructor() {\n this.#store = new Map();\n }\n\n add(request: RequestInfo): Promise<void> {\n throw new Error('Method not implemented. Use `put` instead.');\n }\n\n addAll(requests: RequestInfo[]): Promise<void> {\n throw new Error('Method not implemented. Use `put` instead.');\n }\n\n matchAll(\n request?: RequestInfo,\n options?: CacheQueryOptions,\n ): Promise<readonly Response[]> {\n throw new Error('Method not implemented. Use `match` instead.');\n }\n\n async put(request: Request, response: Response) {\n if (request.method !== 'GET') {\n throw new TypeError('Cannot cache response to non-GET request.');\n }\n\n if (response.status === 206) {\n throw new TypeError(\n 'Cannot cache response to a range request (206 Partial Content).',\n );\n }\n\n if (response.headers.get('vary')?.includes('*')) {\n throw new TypeError(\"Cannot cache response with 'Vary: *' header.\");\n }\n\n this.#store.set(request.url, {\n body: new Uint8Array(await response.arrayBuffer()),\n status: response.status,\n headers: [...response.headers],\n timestamp: Date.now(),\n });\n }\n\n async match(request: Request) {\n if (request.method !== 'GET') return;\n\n const match = this.#store.get(request.url);\n\n if (!match) {\n return;\n }\n\n const {body, timestamp, ...metadata} = match;\n\n const headers = new Headers(metadata.headers);\n const cacheControl =\n headers.get('cache-control') || headers.get('real-cache-control') || '';\n const maxAge = parseInt(\n cacheControl.match(/max-age=(\\d+)/)?.[1] || '0',\n 10,\n );\n const swr = parseInt(\n cacheControl.match(/stale-while-revalidate=(\\d+)/)?.[1] || '0',\n 10,\n );\n const age = (Date.now() - timestamp) / 1000;\n\n const isMiss = age > maxAge + swr;\n\n if (isMiss) {\n this.#store.delete(request.url);\n return;\n }\n\n const isStale = age > maxAge;\n\n headers.set('cache', isStale ? 'STALE' : 'HIT');\n headers.set('date', new Date(timestamp).toUTCString());\n\n return new Response(body, {\n status: metadata.status ?? 200,\n headers,\n });\n }\n\n async delete(request: Request) {\n if (this.#store.has(request.url)) {\n this.#store.delete(request.url);\n return true;\n }\n return false;\n }\n\n keys(request?: Request) {\n const cacheKeys = [] as Request[];\n\n for (const url of this.#store.keys()) {\n if (!request || request.url === url) {\n cacheKeys.push(new Request(url));\n }\n }\n\n return Promise.resolve(cacheKeys);\n }\n}\n","import {redirect} from '@remix-run/server-runtime';\nimport type {UrlRedirectConnection} from '@shopify/hydrogen-react/storefront-api-types';\nimport type {I18nBase, Storefront} from '../storefront';\n\ntype StorefrontRedirect = {\n storefront: Storefront<I18nBase>;\n request: Request;\n response?: Response;\n};\n\n/**\n * Queries the Storefront API to see if there is any redirect\n * created for the current route and performs it. Otherwise,\n * it returns the response passed in the parameters. Useful for\n * conditionally redirecting after a 404 response.\n *\n * @see {@link https://help.shopify.com/en/manual/online-store/menus-and-links/url-redirect Creating URL redirects in Shopify}\n */\nexport async function storefrontRedirect(\n options: StorefrontRedirect,\n): Promise<Response> {\n const {\n storefront,\n request,\n response = new Response('Not Found', {status: 404}),\n } = options;\n\n const {pathname, search} = new URL(request.url);\n const redirectFrom = pathname + search;\n\n try {\n const {urlRedirects} = await storefront.query<{\n urlRedirects: UrlRedirectConnection;\n }>(REDIRECT_QUERY, {\n variables: {query: 'path:' + redirectFrom},\n });\n\n const location = urlRedirects?.edges?.[0]?.node?.target;\n\n if (location) {\n return new Response(null, {status: 302, headers: {location}});\n }\n\n const searchParams = new URLSearchParams(search);\n const redirectTo =\n searchParams.get('return_to') || searchParams.get('redirect');\n\n if (redirectTo) {\n if (isLocalPath(redirectTo)) {\n return redirect(redirectTo);\n } else {\n console.warn(\n `Cross-domain redirects are not supported. Tried to redirect from ${redirectFrom} to ${redirectTo}`,\n );\n }\n }\n } catch (error) {\n console.error(\n `Failed to fetch redirects from Storefront API for route ${redirectFrom}`,\n error,\n );\n }\n\n return response;\n}\n\nfunction isLocalPath(url: string) {\n try {\n // We don't want to redirect cross domain,\n // doing so could create fishing vulnerability\n // If `new URL()` succeeds, it's a fully qualified\n // url which is cross domain. If it fails, it's just\n // a path, which will be the current domain.\n new URL(url);\n } catch (e) {\n return true;\n }\n\n return false;\n}\n\nconst REDIRECT_QUERY = `#graphql\n query redirects($query: String) {\n urlRedirects(first: 1, query: $query) {\n edges {\n node {\n target\n }\n }\n }\n }\n`;\n","import type {LoaderArgs} from '@remix-run/server-runtime';\nimport type {Storefront} from '../storefront';\n\ntype GraphiQLLoader = (args: LoaderArgs) => Promise<Response>;\n\nexport const graphiqlLoader: GraphiQLLoader = async function graphiqlLoader({\n context,\n}: LoaderArgs) {\n const storefront = context?.storefront as Storefront | undefined;\n if (!storefront) {\n throw new Error(\n `GraphiQL: Hydrogen's storefront client must be injected in the loader context.`,\n );\n }\n\n const url = storefront.getApiUrl();\n const accessToken =\n storefront.getPublicTokenHeaders()['X-Shopify-Storefront-Access-Token'];\n\n return new Response(\n `\n<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <title>GraphiQL</title>\n <style>\n body {\n height: 100%;\n margin: 0;\n width: 100%;\n overflow: hidden;\n }\n\n #graphiql {\n height: 100vh;\n }\n </style>\n\n <script\n src=\"https://unpkg.com/react@17/umd/react.development.js\"\n integrity=\"sha512-Vf2xGDzpqUOEIKO+X2rgTLWPY+65++WPwCHkX2nFMu9IcstumPsf/uKKRd5prX3wOu8Q0GBylRpsDB26R6ExOg==\"\n crossorigin=\"anonymous\"\n ></script>\n <script\n src=\"https://unpkg.com/react-dom@17/umd/react-dom.development.js\"\n integrity=\"sha512-Wr9OKCTtq1anK0hq5bY3X/AvDI5EflDSAh0mE9gma+4hl+kXdTJPKZ3TwLMBcrgUeoY0s3dq9JjhCQc7vddtFg==\"\n crossorigin=\"anonymous\"\n ></script>\n <link rel=\"stylesheet\" href=\"https://unpkg.com/graphiql/graphiql.min.css\" />\n </head>\n\n <body>\n <div id=\"graphiql\">Loading...</div>\n <script\n src=\"https://unpkg.com/graphiql/graphiql.min.js\"\n type=\"application/javascript\"\n ></script>\n <script>\n ReactDOM.render(\n React.createElement(GraphiQL, {\n fetcher: GraphiQL.createFetcher({\n url: '${url}',\n headers: {\n 'X-Shopify-Storefront-Access-Token': '${accessToken}',\n }\n }),\n defaultEditorToolsVisibility: true,\n initialTabs: [{query: '{\\\\n shop {\\\\n name\\\\n }\\\\n}'}]\n }),\n document.getElementById('graphiql'),\n );\n </script>\n </body>\n</html>\n `,\n {status: 200, headers: {'content-type': 'text/html'}},\n );\n};\n","import {createElement, Fragment, lazy, Suspense, useMemo} from 'react';\nimport {\n type Location,\n type Params,\n useLocation,\n useMatches,\n} from '@remix-run/react';\nimport {generateSeoTags, type SeoConfig} from './generate-seo-tags';\nimport {type Thing} from 'schema-dts';\n\nimport type {\n AppData,\n LoaderFunction,\n SerializeFrom,\n} from '@remix-run/server-runtime';\n\nconst SeoLogger = lazy(() => import('./log-seo-tags'));\n\nexport interface SeoHandleFunction<\n Loader extends LoaderFunction | unknown = unknown,\n StructuredDataSchema extends Thing = Thing,\n> {\n (args: {\n data: Loader extends LoaderFunction ? SerializeFrom<Loader> : AppData;\n id: string;\n params: Params;\n pathname: Location['pathname'];\n search: Location['search'];\n hash: Location['hash'];\n key: string;\n }): Partial<SeoConfig<StructuredDataSchema>>;\n}\n\ninterface SeoProps {\n /** Enable debug mode that prints SEO properties for route in the console */\n debug?: boolean;\n}\n\nexport function Seo({debug}: SeoProps) {\n const matches = useMatches();\n const location = useLocation();\n\n // Capture the seo and jsonLd configs from the route matches\n const seoConfig = useMemo(() => {\n return (\n matches\n .flatMap((match) => {\n const {handle, ...routeMatch} = match;\n const routeData = {...routeMatch, ...location};\n const handleSeo = handle?.seo;\n const loaderSeo = routeMatch?.data?.seo;\n\n if (!handleSeo && !loaderSeo) {\n return [];\n }\n\n // if seo is defined in the handle, invoke it with the route data\n if (handleSeo) {\n return recursivelyInvokeOrReturn(handle.seo, routeData);\n } else {\n return [loaderSeo];\n }\n })\n // merge route seo (priority) with the root seo if both are present\n // jsonLd definitions are instead concatenated because there can be\n // multiple jsonLd tags on any given root+route. e.g root renders Organization\n // schema and a product page renders Product schema\n .reduce((acc, current) => {\n // remove seo properties with falsy values\n Object.keys(current).forEach(\n (key) => !current[key] && delete current[key],\n );\n\n const {jsonLd} = current;\n\n if (!jsonLd) {\n return {...acc, ...current};\n }\n\n // concatenate jsonLds if present\n if (!acc?.jsonLd) {\n return {...acc, ...current, jsonLd: [jsonLd]};\n } else {\n if (Array.isArray(jsonLd)) {\n return {\n ...acc,\n ...current,\n jsonLd: [...acc.jsonLd, ...jsonLd],\n };\n } else {\n return {\n ...acc,\n ...current,\n jsonLd: [...acc.jsonLd, jsonLd],\n };\n }\n }\n }, {} as SeoConfig<Thing>)\n );\n }, [matches, location]);\n\n // Generate seo and jsonLd tags from the route seo configs\n // and return the jsx elements as html\n const {html, loggerMarkup} = useMemo(() => {\n const headTags = generateSeoTags(seoConfig);\n const html = headTags.map((tag) => {\n if (tag.tag === 'script') {\n return createElement(tag.tag, {\n ...tag.props,\n key: tag.key,\n dangerouslySetInnerHTML: {__html: tag.children},\n });\n }\n\n return createElement(tag.tag, {...tag.props, key: tag.key}, tag.children);\n });\n\n const loggerMarkup = createElement(\n Suspense,\n {fallback: null},\n createElement(SeoLogger, {headTags}),\n );\n\n return {html, loggerMarkup};\n }, [seoConfig]);\n\n return createElement(Fragment, null, html, debug && loggerMarkup);\n}\n\n/**\n * Recursively invoke a function or return the value\n * @param value\n * @param rest\n * @returns\n */\nexport function recursivelyInvokeOrReturn<T, R extends any[]>(\n value: T | ((...rest: R) => T),\n ...rest: R\n): T | Record<string, T> {\n if (value instanceof Function) {\n return recursivelyInvokeOrReturn<T, R>(value(...rest), ...rest);\n }\n\n let result: Record<string, T> = {};\n\n if (Array.isArray(value)) {\n result = value.reduce((acc, item) => {\n return [...acc, recursivelyInvokeOrReturn(item)];\n }, []);\n\n return result;\n }\n\n if (value instanceof Object) {\n const entries = Object.entries(value);\n\n entries.forEach(([key, val]) => {\n // @ts-expect-error\n result[key] = recursivelyInvokeOrReturn<T, R>(val, ...rest);\n });\n\n return result;\n }\n\n return value;\n}\n","import type {ComponentPropsWithoutRef} from 'react';\nimport type {Maybe} from '@shopify/hydrogen-react/storefront-api-types';\nimport type {Thing, WithContext} from 'schema-dts';\n\nconst ERROR_PREFIX = 'Error in SEO input: ';\n\n// TODO: Refactor this into more reusable validators or use a library like zod to do this if we decide to use it in\n// other places. @cartogram\nexport const schema = {\n title: {\n validate: <T>(value: Maybe<T>): NonNullable<T> => {\n if (typeof value !== 'string') {\n throw new Error(ERROR_PREFIX.concat('`title` should be a string'));\n }\n\n if (typeof value === 'string' && value.length > 120) {\n throw new Error(\n ERROR_PREFIX.concat(\n '`title` should not be longer than 120 characters',\n ),\n );\n }\n\n return value;\n },\n },\n description: {\n validate: <T>(value: Maybe<T>): NonNullable<T> => {\n if (typeof value !== 'string') {\n throw new Error(\n ERROR_PREFIX.concat('`description` should be a string'),\n );\n }\n\n if (typeof value === 'string' && value.length > 155) {\n throw new Error(\n ERROR_PREFIX.concat(\n '`description` should not be longer than 155 characters',\n ),\n );\n }\n\n return value;\n },\n },\n url: {\n validate: <T>(value: Maybe<T>): NonNullable<T> => {\n if (typeof value !== 'string') {\n throw new Error(ERROR_PREFIX.concat('`url` should be a string'));\n }\n\n if (typeof value === 'string' && !value.startsWith('http')) {\n throw new Error(ERROR_PREFIX.concat('`url` should be a valid URL'));\n }\n\n return value;\n },\n },\n handle: {\n validate: <T>(value: Maybe<T>): NonNullable<T> => {\n if (typeof value !== 'string') {\n throw new Error(ERROR_PREFIX.concat('`handle` should be a string'));\n }\n\n if (typeof value === 'string' && !value.startsWith('@')) {\n throw new Error(ERROR_PREFIX.concat('`handle` should start with `@`'));\n }\n\n return value;\n },\n },\n};\n\nexport interface SeoConfig<Schema extends Thing = Thing> {\n /**\n * The <title> HTML element defines the document's title that is shown in a browser's title bar or a page's tab. It\n * only contains text; tags within the element are ignored.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title\n */\n title?: Maybe<string>;\n /**\n * Generate the title from a template that includes a `%s` placeholder for the title.\n *\n * @example\n * ```js\n * {\n * title: 'My Page',\n * titleTemplate: 'My Site - %s',\n * }\n * ```\n */\n titleTemplate?: Maybe<string> | null;\n /**\n * The media associated with the given page (images, videos, etc). If you pass a string, it will be used as the\n * `og:image` meta tag. If you pass an object or an array of objects, that will be used to generate `og:<type of\n * media>` meta tags. The `url` property should be the URL of the media. The `height` and `width` properties are\n * optional and should be the height and width of the media. The `altText` property is optional and should be a\n * description of the media.\n *\n * @example\n * ```js\n * {\n * media: [\n * {\n * url: 'https://example.com/image.jpg',\n * type: 'image',\n * height: '400',\n * width: '400',\n * altText: 'A custom snowboard with an alpine color pallet.',\n * }\n * ]\n * }\n * ```\n *\n */\n media?:\n | Maybe<string>\n | Partial<SeoMedia>\n | (Partial<SeoMedia> | Maybe<string>)[];\n /**\n * The description of the page. This is used in the `name=\"description\"` meta tag as well as the `og:description` meta\n * tag.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta\n */\n description?: Maybe<string>;\n /**\n * The canonical URL of the page. This is used to tell search engines which URL is the canonical version of a page.\n * This is useful when you have multiple URLs that point to the same page. The value here will be used in the\n * `rel=\"canonical\"` link tag as well as the `og:url` meta tag.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link\n */\n url?: Maybe<string>;\n /**\n * The handle is used to generate the `twitter:site` and `twitter:creator` meta tags. Include the `@` symbol in the\n * handle.\n *\n * @example\n * ```js\n * {\n * handle: '@shopify'\n * }\n * ```\n */\n handle?: Maybe<string>;\n /**\n * The `jsonLd` property is used to generate the `application/ld+json` script tag. This is used to provide structured\n * data to search engines. The value should be an object that conforms to the schema.org spec. The `type` property\n * should be the type of schema you are using. The `type` property is required and should be one of the following:\n *\n * - `Product`\n * - `ItemList`\n * - `Organization`\n * - `WebSite`\n * - `WebPage`\n * - `BlogPosting`\n * - `Thing`\n *\n * @example\n * ```js\n * {\n * jsonLd: {\n * '@context': 'https://schema.org',\n * '@type': 'Product',\n * name: 'My Product',\n * image: 'https://hydrogen.shop/image.jpg',\n * description: 'A product that is great',\n * sku: '12345',\n * mpn: '12345',\n * brand: {\n * '@type': 'Thing',\n * name: 'My Brand',\n * },\n * aggregateRating: {\n * '@type': 'AggregateRating',\n * ratingValue: '4.5',\n * reviewCount: '100',\n * },\n * offers: {\n * '@type': 'Offer',\n * priceCurrency: 'USD',\n * price: '100',\n * priceValidUntil: '2020-11-05',\n * itemCondition: 'https://schema.org/NewCondition',\n * availability: 'https://schema.org/InStock',\n * seller: {\n * '@type': 'Organization',\n * name: 'My Brand',\n * },\n * },\n * }\n * }\n * ```\n *\n * @see https://schema.org/docs/schemas.html\n * @see https://developers.google.com/search/docs/guides/intro-structured-data\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script\n *\n */\n jsonLd?: WithContext<Schema> | WithContext<Schema>[];\n /**\n * The `alternates` property is used to specify the language and geographical targeting when you have multiple\n * versions of the same page in different languages. The `url` property tells search engines about these variations\n * and helps them to serve the correct version to their users.\n *\n * @example\n * ```js\n * {\n * alternates: [\n * {\n * language: 'en-US',\n * url: 'https://hydrogen.shop/en-us',\n * default: true,\n * },\n * {\n * language: 'fr-CA',\n * url: 'https://hydrogen.shop/fr-ca',\n * },\n * ]\n * }\n * ```\n *\n * @see https://support.google.com/webmasters/answer/189077?hl=en\n */\n alternates?: LanguageAlternate | LanguageAlternate[];\n /**\n * The `robots` property is used to specify the robots meta tag. This is used to tell search engines which pages\n * should be indexed and which should not.\n *\n * @see https://developers.google.com/search/reference/robots_meta_tag\n */\n robots?: RobotsOptions;\n}\n\n/**\n * @see https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag\n */\nexport interface RobotsOptions {\n /**\n * Set the maximum size of an image preview for this page in a search results Can be one of the following:\n *\n * - `none` - No image preview is to be shown.\n * - `standard` - A default image preview may be shown.\n * - `large` - A larger image preview, up to the width of the viewport, may be shown.\n *\n * If no value is specified a default image preview size is used.\n */\n maxImagePreview?: 'none' | 'standard' | 'large';\n /**\n * A number representing the maximum of amount characters to use as a textual snippet for a search result. This value\n * can also be set to one of the following special values:\n *\n * - 0 - No snippet is to be shown. Equivalent to nosnippet.\n * - 1 - The Search engine will choose the snippet length that it believes is most effective to help users discover\n * your content and direct users to your site\n * - -1 - No limit on the number of characters that can be shown in the snippet.\n */\n maxSnippet?: number;\n /**\n * The maximum number of seconds for videos on this page to show in search results. This value can also be set to one\n * of the following special values:\n *\n * - 0 - A static image may be used with the `maxImagePreview` setting.\n * - 1 - There is no limit to the size of the video preview.\n *\n * This applies to all forms of search results (at Google: web search, Google Images, Google Videos, Discover,\n * Assistant).\n */\n maxVideoPreview?: number;\n /**\n * Do not show a cached link in search results.\n */\n noArchive?: boolean;\n /**\n * Do not follow the links on this page.\n *\n * @see https://developers.google.com/search/docs/advanced/guidelines/qualify-outbound-links\n */\n noFollow?: boolean;\n /**\n * Do not index images on this page.\n */\n noImageIndex?: boolean;\n /**\n * Do not show this page, media, or resource in search results.\n */\n noIndex?: boolean;\n /**\n * Do not show a text snippet or video preview in the search results for this page.\n */\n noSnippet?: boolean;\n /**\n * Do not offer translation of this page in search results.\n */\n noTranslate?: boolean;\n /**\n * Do not show this page in search results after the specified date/time.\n */\n unavailableAfter?: string;\n}\n\nexport interface LanguageAlternate {\n /**\n * Language code for the alternate page. This is used to generate the hreflang meta tag property.\n */\n language: string;\n /**\n * Whether the alternate page is the default page. This will add the `x-default` attribution to the language code.\n */\n default?: boolean;\n /**\n * The url of the alternate page. This is used to generate the hreflang meta tag property.\n */\n url: string;\n}\n\nexport type SeoMedia = {\n /**\n * Used to generate og:<type of media> meta tag\n */\n type: 'image' | 'video' | 'audio';\n /**\n * The url value populates both url and secure_url and is used to infer the og:<type of media>:type meta tag.\n */\n url: Maybe<string> | undefined;\n /**\n * The height in pixels of the media. This is used to generate the og:<type of media>:height meta tag.\n */\n height: Maybe<number> | undefined;\n /**\n * The width in pixels of the media. This is used to generate the og:<type of media>:width meta tag.\n */\n width: Maybe<number> | undefined;\n /**\n * The alt text for the media. This is used to generate the og:<type of media>:alt meta tag.\n */\n altText: Maybe<string> | undefined;\n};\n\ntype TagKey = 'title' | 'base' | 'meta' | 'link' | 'script';\n\nexport interface CustomHeadTagObject {\n tag: TagKey;\n props: Record<string, unknown>;\n children?: string;\n key: string;\n}\n\n/**\n * The `generateSeoTags` function generates the SEO title, meta, link and script (JSON Linking Data) tags for a page. It\n * pairs well with the SEO component in `@shopify/hydrogen` when building a Hydrogen Remix app, but can be used on its\n * own if you want to generate the tags yourself.\n */\nexport function generateSeoTags<\n Schema extends Thing,\n T extends SeoConfig<Schema> = SeoConfig<Schema>,\n>(seoInput: T): CustomHeadTagObject[] {\n const tagResults: CustomHeadTagObject[] = [];\n\n for (const seoKey of Object.keys(seoInput)) {\n switch (seoKey) {\n case 'title': {\n const content = validate(schema.title, seoInput.title);\n const title = renderTitle(seoInput?.titleTemplate, content);\n\n if (!title) {\n break;\n }\n\n tagResults.push(\n generateTag('title', {title}),\n generateTag('meta', {property: 'og:title', content: title}),\n generateTag('meta', {name: 'twitter:title', content: title}),\n );\n\n break;\n }\n\n case 'description': {\n const content = validate(schema.description, seoInput.description);\n\n if (!content) {\n break;\n }\n\n tagResults.push(\n generateTag('meta', {\n name: 'description',\n content,\n }),\n generateTag('meta', {\n property: 'og:description',\n content,\n }),\n generateTag('meta', {\n name: 'twitter:description',\n content,\n }),\n );\n\n break;\n }\n\n case 'url': {\n const content = validate(schema.url, seoInput.url);\n\n if (!content) {\n break;\n }\n\n tagResults.push(\n generateTag('link', {\n rel: 'canonical',\n href: content,\n }),\n generateTag('meta', {\n property: 'og:url',\n content,\n }),\n );\n\n break;\n }\n\n case 'handle': {\n const content = validate(schema.handle, seoInput.handle);\n\n if (!content) {\n break;\n }\n\n tagResults.push(\n generateTag('meta', {name: 'twitter:site', content}),\n generateTag('meta', {name: 'twitter:creator', content}),\n );\n\n break;\n }\n\n case 'media': {\n let content;\n const values = ensureArray(seoInput.media);\n\n for (const media of values) {\n if (typeof media === 'string') {\n tagResults.push(\n generateTag('meta', {name: 'og:image', content: media}),\n );\n }\n\n if (media && typeof media === 'object') {\n const type = media.type || 'image';\n\n // Order matters here when adding multiple media tags @see https://ogp.me/#array\n const normalizedMedia = media\n ? {\n url: media?.url,\n secure_url: media?.url,\n type: inferMimeType(media.url),\n width: media?.width,\n height: media?.height,\n alt: media?.altText,\n }\n : {};\n\n for (const key of Object.keys(normalizedMedia)) {\n if (normalizedMedia[key as keyof typeof normalizedMedia]) {\n content = normalizedMedia[\n key as keyof typeof normalizedMedia\n ] as string;\n\n tagResults.push(\n generateTag(\n 'meta',\n {\n property: `og:${type}:${key}`,\n content,\n },\n normalizedMedia.url as string,\n ),\n );\n }\n }\n }\n }\n break;\n }\n\n case 'jsonLd': {\n const jsonLdBlocks = ensureArray(seoInput.jsonLd);\n let index = 0;\n for (const block of jsonLdBlocks) {\n if (typeof block !== 'object') {\n continue;\n }\n\n const tag = generateTag(\n 'script',\n {\n type: 'application/ld+json',\n children: JSON.stringify(block),\n },\n // @ts-expect-error\n `json-ld-${block?.['@type'] || block?.name || index++}`,\n );\n\n tagResults.push(tag);\n }\n\n break;\n }\n\n case 'alternates': {\n const alternates = ensureArray(seoInput.alternates);\n\n for (const alternate of alternates) {\n if (!alternate) {\n continue;\n }\n\n const {language, url, default: defaultLang} = alternate;\n\n const hrefLang = language\n ? `${language}${defaultLang ? '-default' : ''}`\n : undefined;\n\n tagResults.push(\n generateTag('link', {\n rel: 'alternate',\n hrefLang,\n href: url,\n }),\n );\n }\n\n break;\n }\n\n case 'robots': {\n if (!seoInput.robots) {\n break;\n }\n\n const {\n maxImagePreview,\n maxSnippet,\n maxVideoPreview,\n noArchive,\n noFollow,\n noImageIndex,\n noIndex,\n noSnippet,\n noTranslate,\n unavailableAfter,\n } = seoInput.robots;\n\n const robotsParams = [\n noArchive && 'noarchive',\n noImageIndex && 'noimageindex',\n noSnippet && 'nosnippet',\n noTranslate && `notranslate`,\n maxImagePreview && `max-image-preview:${maxImagePreview}`,\n maxSnippet && `max-snippet:${maxSnippet}`,\n maxVideoPreview && `max-video-preview:${maxVideoPreview}`,\n unavailableAfter && `unavailable_after:${unavailableAfter}`,\n ];\n\n let robotsParam =\n (noIndex ? 'noindex' : 'index') +\n ',' +\n (noFollow ? 'nofollow' : 'follow');\n\n for (let param of robotsParams) {\n if (param) {\n robotsParam += `,${param}`;\n }\n }\n\n tagResults.push(\n generateTag('meta', {name: 'robots', content: robotsParam}),\n );\n\n break;\n }\n\n default: {\n // TODO: We should be able to catch unaccounted for keys at compile time\n // let exhaustiveCheck: never = seoKey;\n\n break;\n }\n }\n }\n\n return tagResults.flat().sort((a, b) => a.key.localeCompare(b.key));\n}\n\nexport function generateTag<T extends TagKey>(\n tagName: T,\n input: ComponentPropsWithoutRef<T>,\n group?: string,\n): CustomHeadTagObject {\n const tag: CustomHeadTagObject = {tag: tagName, props: {}, key: ''};\n\n // title tags don't have props so move to children\n if (tagName === 'title') {\n tag.children = input.title as string;\n tag.key = generateKey(tag);\n\n return tag;\n }\n\n // also move the input children to children and delete it\n if (tagName === 'script') {\n tag.children = typeof input.children === 'string' ? input.children : '';\n tag.key = generateKey(tag, group);\n delete input.children;\n tag.props = input;\n return tag;\n }\n\n // the rest goes on props\n tag.props = input;\n\n // remove empty props\n Object.keys(tag.props).forEach(\n (key) => !tag.props[key] && delete tag.props[key],\n );\n\n tag.key = generateKey(tag, group);\n\n return tag;\n}\n\n//**\n// * Generate a unique key for a tag\n// * @param tag - a generated tag object\n// * @param group? - the group the tag belongs to\n// * @returns - a unique key to be used for react\n// */\nexport function generateKey(tag: CustomHeadTagObject, group?: string) {\n const {tag: tagName, props} = tag;\n\n if (tagName === 'title') {\n // leading 0 moves title to the top when sorting\n return '0-title';\n }\n\n if (tagName === 'meta') {\n // leading 0 moves meta to the top when sorting exclude secure_url from the logic because the content is the same as\n // url\n const priority =\n props.content === group &&\n typeof props.property === 'string' &&\n !props.property.endsWith('secure_url') &&\n '0';\n const groupName = [group, priority];\n\n return [tagName, ...groupName, props.property || props.name]\n .filter((x) => x)\n .join('-');\n }\n\n if (tagName === 'link') {\n const key = [tagName, props.rel, props.hrefLang || props.media]\n .filter((x) => x)\n .join('-');\n\n // replace spaces with dashes, needed for media prop\n return key.replace(/\\s+/g, '-');\n }\n\n if (tagName === 'script') {\n return `${tagName}-${group}`;\n }\n\n return `${tagName}-${props.type}`;\n}\n\nfunction renderTitle<T extends CustomHeadTagObject['children']>(\n template?:\n | string\n | ((title: string) => string | undefined)\n | undefined\n | null,\n title?: T | null,\n): string | undefined {\n if (!title) {\n return undefined;\n }\n\n if (!template) {\n return title;\n }\n\n if (typeof template === 'function') {\n return template(title);\n }\n\n return template.replace('%s', title ?? '');\n}\n\nfunction inferMimeType(url: Maybe<string> | undefined) {\n const ext = url && url.split('.').pop();\n\n switch (ext) {\n case 'svg':\n return 'image/svg+xml';\n case 'png':\n return 'image/png';\n case 'gif':\n return 'image/gif';\n case 'swf':\n return 'application/x-shockwave-flash';\n case 'mp3':\n return 'audio/mpeg';\n case 'jpg':\n case 'jpeg':\n default:\n return 'image/jpeg';\n }\n}\n\nexport type SchemaType =\n | 'Product'\n | 'ItemList'\n | 'Organization'\n | 'WebSite'\n | 'WebPage'\n | 'BlogPosting'\n | 'Thing';\n\nfunction ensureArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value];\n}\n\nfunction validate<T>(\n schema: {validate: <T>(data: T) => NonNullable<T>},\n data: T,\n): T {\n try {\n return schema.validate<T>(data);\n } catch (error: unknown) {\n console.warn((error as Error).message);\n return data;\n }\n}\n","import {createElement, useEffect, useMemo, useState} from 'react';\nimport type {Maybe, PageInfo} from '@shopify/hydrogen/storefront-api-types';\nimport {flattenConnection} from '@shopify/hydrogen-react';\nimport {Link, LinkProps, useNavigation, useLocation} from '@remix-run/react';\n\ntype Connection<NodesType> =\n | {\n nodes: Array<NodesType>;\n pageInfo: PageInfo;\n }\n | {\n edges: {\n node: Array<NodesType>;\n };\n pageInfo: PageInfo;\n };\n\ntype PaginationState<NodesType> = {\n nodes?: Array<NodesType>;\n pageInfo?: PageInfo | null;\n};\n\ninterface PaginationInfo<NodesType> {\n /** The paginated array of nodes. You should map over and render this array. */\n nodes: Array<NodesType>;\n /** The `<NextLink>` is a helper component that makes it easy to navigate to the next page of paginated data. Alternatively you can build your own `<Link>` component: `<Link to={nextPageUrl} state={state} preventScrollReset />` */\n NextLink: (props: Omit<LinkProps, 'to'>) => JSX.Element | null;\n /** The `<PreviousLink>` is a helper component that makes it easy to navigate to the previous page of paginated data. Alternatively you can build your own `<Link>` component: `<Link to={previousPageUrl} state={state} preventScrollReset />` */\n PreviousLink: (props: Omit<LinkProps, 'to'>) => JSX.Element | null;\n /** The URL to the previous page of paginated data. Use this prop to build your own `<Link>` component. */\n previousPageUrl: string;\n /** The URL to the next page of paginated data. Use this prop to build your own `<Link>` component. */\n nextPageUrl: string;\n /** True if the cursor has next paginated data */\n hasNextPage: boolean;\n /** True if the cursor has previous paginated data */\n hasPreviousPage: boolean;\n /** True if we are in the process of fetching another page of data */\n isLoading: boolean;\n /** The `state` property is important to use when building your own `<Link>` component if you want paginated data to continuously append to the page. This means that every time the user clicks \"Next page\", the next page of data will be apppended inline with the previous page. If you want the whole page to re-render with only the next page results, do not pass the `state` prop to the Remix `<Link>` component. */\n state: {\n nodes: Array<NodesType>;\n pageInfo: {\n endCursor: Maybe<string> | undefined;\n startCursor: Maybe<string> | undefined;\n hasPreviousPage: boolean;\n };\n };\n}\n\ntype PaginationProps<NodesType> = {\n /** The response from `storefront.query` for a paginated request. Make sure the query is passed pagination variables and that the query has `pageInfo` with `hasPreviousPage`, `hasNextpage`, `startCursor`, and `endCursor` defined. */\n connection: Connection<NodesType>;\n /** A render prop that includes pagination data and helpers. */\n children: PaginationRenderProp<NodesType>;\n};\n\ntype PaginationRenderProp<NodesType> = (\n props: PaginationInfo<NodesType>,\n) => JSX.Element | null;\n\n/**\n *\n * The [Storefront API uses cursors](https://shopify.dev/docs/api/usage/pagination-graphql) to paginate through lists of data\n * and the \\`<Pagination />\\` component makes it easy to paginate data from the Storefront API.\n *\n * @prop connection The response from `storefront.query` for a paginated request. Make sure the query is passed pagination variables and that the query has `pageInfo` with `hasPreviousPage`, `hasNextpage`, `startCursor`, and `endCursor` defined.\n * @prop children A render prop that includes pagination data and helpers.\n */\nexport function Pagination<NodesType>({\n connection,\n children = () => {\n console.warn('<Pagination> requires children to work properly');\n return null;\n },\n}: PaginationProps<NodesType>) {\n const transition = useNavigation();\n const isLoading = transition.state === 'loading';\n const {\n endCursor,\n hasNextPage,\n hasPreviousPage,\n nextPageUrl,\n nodes,\n previousPageUrl,\n startCursor,\n } = usePagination<NodesType>(connection);\n\n const state = useMemo(\n () => ({\n pageInfo: {\n endCursor,\n hasPreviousPage,\n startCursor,\n },\n nodes,\n }),\n [endCursor, hasPreviousPage, startCursor, nodes],\n );\n\n const NextLink = useMemo(\n () =>\n function NextLink(props: Omit<LinkProps, 'to'>) {\n return hasNextPage\n ? createElement(Link, {\n preventScrollReset: true,\n ...props,\n to: nextPageUrl,\n state,\n replace: true,\n })\n : null;\n },\n [hasNextPage, nextPageUrl],\n );\n\n const PreviousLink = useMemo(\n () =>\n function PrevLink(props: Omit<LinkProps, 'to'>) {\n return hasPreviousPage\n ? createElement(Link, {\n preventScrollReset: true,\n ...props,\n to: previousPageUrl,\n state,\n replace: true,\n })\n : null;\n },\n [hasPreviousPage, previousPageUrl],\n );\n\n return children({\n state,\n hasNextPage,\n hasPreviousPage,\n isLoading,\n nextPageUrl,\n nodes,\n previousPageUrl,\n NextLink,\n PreviousLink,\n });\n}\n\n/**\n * Get cumulative pagination logic for a given connection\n */\nexport function usePagination<NodesType>(\n connection: Connection<NodesType>,\n): Omit<\n PaginationInfo<NodesType>,\n 'isLoading' | 'state' | 'NextLink' | 'PreviousLink'\n> & {\n startCursor: Maybe<string> | undefined;\n endCursor: Maybe<string> | undefined;\n} {\n const {state, search} = useLocation() as {\n state?: PaginationState<NodesType>;\n search?: string;\n };\n\n const params = new URLSearchParams(search);\n const direction = params.get('direction');\n const isPrevious = direction === 'previous';\n\n const nodes = useMemo(() => {\n if (!state || !state?.nodes) {\n return flattenConnection(connection);\n }\n\n if (isPrevious) {\n return [...flattenConnection(connection), ...state.nodes];\n } else {\n return [...state.nodes, ...flattenConnection(connection)];\n }\n }, [state, connection]);\n\n // `connection` represents the data that came from the server\n // `state` represents the data that came from the client\n const currentPageInfo = useMemo(() => {\n let pageStartCursor =\n state?.pageInfo?.startCursor === undefined\n ? connection.pageInfo.startCursor\n : state.pageInfo.startCursor;\n\n let pageEndCursor =\n state?.pageInfo?.endCursor === undefined\n ? connection.pageInfo.endCursor\n : state.pageInfo.endCursor;\n\n if (state?.nodes) {\n if (isPrevious) {\n pageStartCursor = connection.pageInfo.startCursor;\n } else {\n pageEndCursor = connection.pageInfo.endCursor;\n }\n }\n\n const previousPageExists =\n state?.pageInfo?.hasPreviousPage === undefined\n ? connection.pageInfo.hasPreviousPage\n : state.pageInfo.hasPreviousPage;\n\n const nextPageExists =\n state?.pageInfo?.hasNextPage === undefined\n ? connection.pageInfo.hasNextPage\n : state.pageInfo.hasNextPage;\n\n return {\n startCursor: pageStartCursor,\n endCursor: pageEndCursor,\n hasPreviousPage: previousPageExists,\n hasNextPage: nextPageExists,\n };\n }, [\n isPrevious,\n state,\n connection.pageInfo.hasNextPage,\n connection.pageInfo.hasPreviousPage,\n connection.pageInfo.startCursor,\n connection.pageInfo.endCursor,\n ]);\n\n const previousPageUrl = useMemo(() => {\n const params = new URLSearchParams(search);\n params.set('direction', 'previous');\n currentPageInfo.startCursor &&\n params.set('cursor', currentPageInfo.startCursor);\n return `?${params.toString()}`;\n }, [search, currentPageInfo.startCursor]);\n\n const nextPageUrl = useMemo(() => {\n const params = new URLSearchParams(search);\n params.set('direction', 'next');\n currentPageInfo.endCursor &&\n params.set('cursor', currentPageInfo.endCursor);\n return `?${params.toString()}`;\n }, [search, currentPageInfo.endCursor]);\n\n return {...currentPageInfo, previousPageUrl, nextPageUrl, nodes};\n}\n\n/**\n * @param request The request object passed to your Remix loader function.\n * @param options Options for how to configure the pagination variables. Includes the ability to change how many nodes are within each page.\n *\n * @returns Variables to be used with the `storefront.query` function\n */\nexport function getPaginationVariables(\n request: Request,\n options: {pageBy: number} = {pageBy: 20},\n) {\n if (!(request instanceof Request)) {\n throw new Error(\n 'getPaginationVariables must be called with the Request object passed to your loader function',\n );\n }\n\n const {pageBy} = options;\n const searchParams = new URLSearchParams(new URL(request.url).search);\n\n const cursor = searchParams.get('cursor') ?? undefined;\n const direction =\n searchParams.get('direction') === 'previous' ? 'previous' : 'next';\n const isPrevious = direction === 'previous';\n\n const prevPage = {\n last: pageBy,\n startCursor: cursor ?? null,\n };\n\n const nextPage = {\n first: pageBy,\n endCursor: cursor ?? null,\n };\n\n const variables = isPrevious ? prevPage : nextPage;\n\n return variables;\n}\n","export * from './storefront';\nexport * from './with-cache';\nexport {\n CacheCustom,\n CacheLong,\n CacheNone,\n CacheShort,\n generateCacheControlHeader,\n} from './cache/strategies';\nexport {InMemoryCache} from './cache/in-memory';\n\nexport {storefrontRedirect} from './routing/redirect';\nexport {graphiqlLoader} from './routing/graphiql';\nexport {Seo} from './seo/seo';\nexport {type SeoConfig} from './seo/generate-seo-tags';\nexport type {SeoHandleFunction} from './seo/seo';\nexport {\n Pagination as Pagination__unstable,\n getPaginationVariables as getPaginationVariables__unstable,\n} from './pagination/Pagination';\n\nexport {\n AnalyticsEventName,\n AnalyticsPageType,\n ExternalVideo,\n flattenConnection,\n getClientBrowserParameters,\n getShopifyCookies,\n Image,\n IMAGE_FRAGMENT,\n MediaFile,\n ModelViewer,\n Money,\n parseGid,\n parseMetafield,\n sendShopifyAnalytics,\n ShopifySalesChannel,\n ShopPayButton,\n storefrontApiCustomScalars,\n useMoney,\n useShopifyCookies,\n Video,\n} from '@shopify/hydrogen-react';\n\nexport type {\n ClientBrowserParameters,\n ParsedMetafields,\n ShopifyAddToCart,\n ShopifyAddToCartPayload,\n ShopifyAnalytics,\n ShopifyAnalyticsPayload,\n ShopifyAnalyticsProduct,\n ShopifyCookies,\n ShopifyPageView,\n ShopifyPageViewPayload,\n StorefrontApiResponse,\n StorefrontApiResponseError,\n StorefrontApiResponseOk,\n StorefrontApiResponseOkPartial,\n StorefrontApiResponsePartial,\n} from '@shopify/hydrogen-react';\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/seo/log-seo-tags.ts","../../src/storefront.ts","../../src/utils/hash.ts","../../src/cache/strategies.ts","../../src/utils/parse-json.ts","../../src/cache/api.ts","../../src/cache/sub-request.ts","../../src/cache/fetch.ts","../../src/constants.ts","../../src/utils/uuid.ts","../../src/utils/warning.ts","../../src/version.ts","../../src/with-cache.ts","../../src/cache/in-memory.ts","../../src/routing/redirect.ts","../../src/routing/graphiql.ts","../../src/seo/seo.ts","../../src/seo/generate-seo-tags.ts","../../src/pagination/Pagination.ts","../../src/index.ts"],"names":["isStale","result","errors","graphiqlLoader","schema","html","loggerMarkup","createElement","useMemo","useLocation","NextLink","params","flattenConnection","getShopifyCookies"],"mappings":"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","sourcesContent":["import type {CustomHeadTagObject} from './generate-seo-tags';\n\nexport default function Logger({headTags}: {headTags: CustomHeadTagObject[]}) {\n logSeoTags(headTags);\n\n return null;\n}\n\nconst headingStyle = 'text-transform: uppercase;';\nconst titleStyle =\n 'text-transform: uppercase; font-weight: bold; text-transform: uppercase;font-weight: bold';\n\nexport function logSeoTags(headTags: CustomHeadTagObject[]) {\n console.log(' ');\n console.log('%cSEO Meta Tags', `${titleStyle}`);\n console.log(' ');\n\n headTags.forEach((tag) => {\n if (tag.tag === 'script') {\n console.log(`%c• JSON LD `, headingStyle);\n\n if (tag.children) {\n try {\n console.table(JSON.parse(tag.children), ['name', 'content']);\n } catch {\n console.log(tag.children);\n }\n }\n } else {\n console.log(`%c• ${tag.tag} `, headingStyle);\n\n if (tag.children) {\n if (typeof tag.children === 'string') {\n console.log(`↳ ${tag.children}`);\n } else {\n try {\n Object.entries(JSON.parse(tag.children)).map(([key, val]) =>\n console.log(`↳ ${val}`),\n );\n } catch {\n console.log(tag.children);\n }\n }\n }\n\n if (tag.props.property === 'og:image:url') {\n const urlKey = tag.props.content as string;\n\n fetchImage(urlKey)\n .then((image) => {\n const imageStyle = `font-size: 400px; padding: 10px; background: white url(${image}) no-repeat center; background-size: contain;`;\n\n console.log(`%c• Share image preview`, headingStyle);\n console.log('%c ', imageStyle);\n console.log(`↳ ${urlKey}`);\n })\n .catch((err) => {\n console.error(err);\n });\n }\n\n Object.entries(tag.props).map(([key, val]) => {\n console.log(`↳ ${key} → ${val}`);\n });\n }\n console.log(' ');\n });\n}\n\nasync function fetchImage(url: string) {\n const result = await fetch(url);\n const data = await result.blob();\n const buff = await data.arrayBuffer();\n const base64String = arrayBufferToBase64(buff);\n\n return `data:image/png;base64,${base64String}`;\n}\n\nfunction arrayBufferToBase64(buffer: ArrayBuffer) {\n let binary = '';\n const bytes = new Uint8Array(buffer);\n const len = bytes.byteLength;\n\n for (let index = 0; index < len; index++) {\n binary += String.fromCharCode(bytes[index]);\n }\n\n return btoa(binary);\n}\n","import {\n createStorefrontClient as createStorefrontUtilities,\n getShopifyCookies,\n type StorefrontApiResponseOk,\n type StorefrontClientProps,\n SHOPIFY_S,\n SHOPIFY_Y,\n SHOPIFY_STOREFRONT_ID_HEADER,\n SHOPIFY_STOREFRONT_Y_HEADER,\n SHOPIFY_STOREFRONT_S_HEADER,\n} from '@shopify/hydrogen-react';\nimport type {ExecutionArgs} from 'graphql';\nimport {fetchWithServerCache, checkGraphQLErrors} from './cache/fetch';\nimport {STOREFRONT_REQUEST_GROUP_ID_HEADER} from './constants';\nimport {\n CacheNone,\n CacheLong,\n CacheShort,\n CacheCustom,\n generateCacheControlHeader,\n type CachingStrategy,\n} from './cache/strategies';\nimport {generateUUID} from './utils/uuid';\nimport {parseJSON} from './utils/parse-json';\nimport {\n CountryCode,\n LanguageCode,\n} from '@shopify/hydrogen-react/storefront-api-types';\nimport {warnOnce} from './utils/warning';\nimport {LIB_VERSION} from './version';\n\ntype StorefrontApiResponse<T> = StorefrontApiResponseOk<T>;\n\nexport type I18nBase = {\n language: LanguageCode;\n country: CountryCode;\n};\n\n/**\n * Wraps all the returned utilities from `createStorefrontClient`.\n */\nexport type StorefrontClient<TI18n extends I18nBase> = {\n storefront: Storefront<TI18n>;\n};\n\n/**\n * Maps all the queries found in the project to variables and return types.\n */\nexport interface StorefrontQueries {\n // Example of how a generated query type looks like:\n // '#graphql query q1 {...}': {return: Q1Query; variables: Q1QueryVariables};\n}\n\n/**\n * Maps all the mutations found in the project to variables and return types.\n */\nexport interface StorefrontMutations {\n // Example of how a generated mutation type looks like:\n // '#graphql mutation m1 {...}': {return: M1Mutation; variables: M1MutationVariables};\n}\n\n// Default type for `variables` in storefront client\ntype GenericVariables = ExecutionArgs['variableValues'];\n\n// Use this type to make parameters optional in storefront client\n// when no variables need to be passed.\ntype EmptyVariables = {[key: string]: never};\n\n// These are the variables that are automatically added to the storefront API.\n// We use this type to make parameters optional in storefront client\n// when these are the only variables that can be passed.\ntype AutoAddedVariableNames = 'country' | 'language';\n\ntype IsOptionalVariables<OperationTypeValue extends {variables: any}> = Omit<\n OperationTypeValue['variables'],\n AutoAddedVariableNames\n> extends EmptyVariables\n ? true // No need to pass variables\n : GenericVariables extends OperationTypeValue['variables']\n ? true // We don't know what variables are needed\n : false; // Variables are known and required\n\ntype StorefrontCommonOptions<Variables extends GenericVariables> = {\n headers?: HeadersInit;\n storefrontApiVersion?: string;\n} & (IsOptionalVariables<{variables: Variables}> extends true\n ? {variables?: Variables}\n : {variables: Variables});\n\ntype StorefrontQuerySecondParam<\n RawGqlString extends keyof StorefrontQueries | string = string,\n> = (RawGqlString extends keyof StorefrontQueries\n ? StorefrontCommonOptions<StorefrontQueries[RawGqlString]['variables']>\n : StorefrontCommonOptions<GenericVariables>) & {cache?: CachingStrategy};\n\ntype StorefrontMutateSecondParam<\n RawGqlString extends keyof StorefrontMutations | string = string,\n> = RawGqlString extends keyof StorefrontMutations\n ? StorefrontCommonOptions<StorefrontMutations[RawGqlString]['variables']>\n : StorefrontCommonOptions<GenericVariables>;\n\n/**\n * Interface to interact with the Storefront API.\n */\nexport type Storefront<TI18n extends I18nBase = I18nBase> = {\n /** The function to run a query on Storefront API. */\n query: <OverrideReturnType = any, RawGqlString extends string = string>(\n query: RawGqlString,\n ...options: RawGqlString extends keyof StorefrontQueries // Do we have any generated query types?\n ? IsOptionalVariables<StorefrontQueries[RawGqlString]> extends true\n ? [StorefrontQuerySecondParam<RawGqlString>?] // Using codegen, query has no variables\n : [StorefrontQuerySecondParam<RawGqlString>] // Using codegen, query needs variables\n : [StorefrontQuerySecondParam?] // No codegen, variables always optional\n ) => Promise<\n RawGqlString extends keyof StorefrontQueries // Do we have any generated query types?\n ? StorefrontQueries[RawGqlString]['return'] // Using codegen, return type is known\n : OverrideReturnType // No codegen, let user specify return type\n >;\n /** The function to run a mutation on Storefront API. */\n mutate: <OverrideReturnType = any, RawGqlString extends string = string>(\n mutation: RawGqlString,\n ...options: RawGqlString extends keyof StorefrontMutations // Do we have any generated mutation types?\n ? IsOptionalVariables<StorefrontMutations[RawGqlString]> extends true\n ? [StorefrontMutateSecondParam<RawGqlString>?] // Using codegen, mutation has no variables\n : [StorefrontMutateSecondParam<RawGqlString>] // Using codegen, mutation needs variables\n : [StorefrontMutateSecondParam?] // No codegen, variables always optional\n ) => Promise<\n RawGqlString extends keyof StorefrontMutations // Do we have any generated mutation types?\n ? StorefrontMutations[RawGqlString]['return'] // Using codegen, return type is known\n : OverrideReturnType // No codegen, let user specify return type\n >;\n /** The cache instance passed in from the `createStorefrontClient` argument. */\n cache?: Cache;\n /** Re-export of [`CacheNone`](/docs/api/hydrogen/utilities/cachenone). */\n CacheNone: typeof CacheNone;\n /** Re-export of [`CacheLong`](/docs/api/hydrogen/utilities/cachelong). */\n CacheLong: typeof CacheLong;\n /** Re-export of [`CacheShort`](/docs/api/hydrogen/utilities/cacheshort). */\n CacheShort: typeof CacheShort;\n /** Re-export of [`CacheCustom`](/docs/api/hydrogen/utilities/cachecustom). */\n CacheCustom: typeof CacheCustom;\n /** Re-export of [`generateCacheControlHeader`](/docs/api/hydrogen/utilities/generatecachecontrolheader). */\n generateCacheControlHeader: typeof generateCacheControlHeader;\n /** Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint. See [`getPublicTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/utilities/createstorefrontclient#:~:text=%27graphql%27.-,getPublicTokenHeaders,-(props%3F%3A) for more details. */\n getPublicTokenHeaders: ReturnType<\n typeof createStorefrontUtilities\n >['getPublicTokenHeaders'];\n /** Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint for API calls made from a server. See [`getPrivateTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/utilities/createstorefrontclient#:~:text=storefrontApiVersion-,getPrivateTokenHeaders,-(props%3F%3A) for more details.*/\n getPrivateTokenHeaders: ReturnType<\n typeof createStorefrontUtilities\n >['getPrivateTokenHeaders'];\n /** Creates the fully-qualified URL to your myshopify.com domain. See [`getShopifyDomain` in Hydrogen React](/docs/api/hydrogen-react/utilities/createstorefrontclient#:~:text=StorefrontClientReturn-,getShopifyDomain,-(props%3F%3A) for more details. */\n getShopifyDomain: ReturnType<\n typeof createStorefrontUtilities\n >['getShopifyDomain'];\n /** Creates the fully-qualified URL to your store's GraphQL endpoint. See [`getStorefrontApiUrl` in Hydrogen React](/docs/api/hydrogen-react/utilities/createstorefrontclient#:~:text=storeDomain-,getStorefrontApiUrl,-(props%3F%3A) for more details.*/\n getApiUrl: ReturnType<\n typeof createStorefrontUtilities\n >['getStorefrontApiUrl'];\n /** Determines if the error is resulted from a Storefront API call. */\n isApiError: (error: any) => boolean;\n /** The `i18n` object passed in from the `createStorefrontClient` argument. */\n i18n: TI18n;\n};\n\ntype HydrogenClientProps<TI18n> = {\n /** Storefront API headers. If on Oxygen, use `getStorefrontHeaders()` */\n storefrontHeaders?: StorefrontHeaders;\n /** An instance that implements the [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache) */\n cache?: Cache;\n /** @deprecated use storefrontHeaders instead */\n buyerIp?: string;\n /** @deprecated use storefrontHeaders instead */\n requestGroupId?: string | null;\n /** The globally unique identifier for the Shop */\n storefrontId?: string;\n /** The `waitUntil` function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform. */\n waitUntil?: ExecutionContext['waitUntil'];\n /** An object containing a country code and language code */\n i18n?: TI18n;\n};\n\nexport type CreateStorefrontClientOptions<TI18n extends I18nBase> =\n HydrogenClientProps<TI18n> & StorefrontClientProps;\n\ntype StorefrontHeaders = {\n /** A unique ID that correlates all sub-requests together. */\n requestGroupId: string | null;\n /** The IP address of the client. */\n buyerIp: string | null;\n /** The cookie header from the client */\n cookie: string | null;\n};\n\ntype StorefrontQueryOptions = StorefrontQuerySecondParam & {\n query: string;\n mutation?: never;\n};\n\ntype StorefrontMutationOptions = StorefrontMutateSecondParam & {\n query?: never;\n mutation: string;\n cache?: never;\n};\n\nconst StorefrontApiError = class extends Error {} as ErrorConstructor;\nexport const isStorefrontApiError = (error: any) =>\n error instanceof StorefrontApiError;\n\nconst isQueryRE = /(^|}\\s)query[\\s({]/im;\nconst isMutationRE = /(^|}\\s)mutation[\\s({]/im;\n\nfunction minifyQuery(string: string) {\n return string\n .replace(/\\s*#.*$/gm, '') // Remove GQL comments\n .replace(/\\s+/gm, ' ') // Minify spaces\n .trim();\n}\n\nconst defaultI18n: I18nBase = {language: 'EN', country: 'US'};\n\n/**\n * This function extends `createStorefrontClient` from [Hydrogen React](/docs/api/hydrogen-react/latest/utilities/createstorefrontclient). The additional arguments enable internationalization (i18n), caching, and other features particular to Remix and Oxygen.\n *\n * Learn more about [data fetching in Hydrogen](/docs/custom-storefronts/hydrogen/data-fetching/fetch-data).\n */\nexport function createStorefrontClient<TI18n extends I18nBase>(\n options: CreateStorefrontClientOptions<TI18n>,\n): StorefrontClient<TI18n> {\n const {\n storefrontHeaders,\n cache,\n waitUntil,\n buyerIp,\n i18n,\n requestGroupId,\n storefrontId,\n ...clientOptions\n } = options;\n if (!cache) {\n // TODO: should only warn in development\n warnOnce(\n 'Storefront API client created without a cache instance. This may slow down your sub-requests.',\n );\n }\n\n const {\n getPublicTokenHeaders,\n getPrivateTokenHeaders,\n getStorefrontApiUrl,\n getShopifyDomain,\n } = createStorefrontUtilities(clientOptions);\n\n const getHeaders = clientOptions.privateStorefrontToken\n ? getPrivateTokenHeaders\n : getPublicTokenHeaders;\n\n const defaultHeaders = getHeaders({\n contentType: 'json',\n buyerIp: storefrontHeaders?.buyerIp || buyerIp,\n });\n\n defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] =\n storefrontHeaders?.requestGroupId || requestGroupId || generateUUID();\n\n if (storefrontId) defaultHeaders[SHOPIFY_STOREFRONT_ID_HEADER] = storefrontId;\n if (LIB_VERSION) defaultHeaders['user-agent'] = `Hydrogen ${LIB_VERSION}`;\n\n if (storefrontHeaders && storefrontHeaders.cookie) {\n const cookies = getShopifyCookies(storefrontHeaders.cookie ?? '');\n\n if (cookies[SHOPIFY_Y])\n defaultHeaders[SHOPIFY_STOREFRONT_Y_HEADER] = cookies[SHOPIFY_Y];\n if (cookies[SHOPIFY_S])\n defaultHeaders[SHOPIFY_STOREFRONT_S_HEADER] = cookies[SHOPIFY_S];\n }\n\n // Deprecation warning\n if (!storefrontHeaders) {\n warnOnce(\n '\"requestGroupId\" and \"buyerIp\" will be deprecated in the next calendar release. Please use \"getStorefrontHeaders\"',\n );\n }\n\n async function fetchStorefrontApi<T>({\n query,\n mutation,\n variables,\n cache: cacheOptions,\n headers = [],\n storefrontApiVersion,\n }: StorefrontQueryOptions | StorefrontMutationOptions): Promise<T> {\n const userHeaders =\n headers instanceof Headers\n ? Object.fromEntries(headers.entries())\n : Array.isArray(headers)\n ? Object.fromEntries(headers)\n : headers;\n\n query = query ?? mutation;\n\n const queryVariables = {...variables};\n\n if (i18n) {\n if (!variables?.country && /\\$country/.test(query)) {\n queryVariables.country = i18n.country;\n }\n\n if (!variables?.language && /\\$language/.test(query)) {\n queryVariables.language = i18n.language;\n }\n }\n\n const url = getStorefrontApiUrl({storefrontApiVersion});\n const requestInit: RequestInit = {\n method: 'POST',\n headers: {...defaultHeaders, ...userHeaders},\n body: JSON.stringify({\n query,\n variables: queryVariables,\n }),\n };\n\n const [body, response] = await fetchWithServerCache(url, requestInit, {\n cacheInstance: mutation ? undefined : cache,\n cache: cacheOptions || CacheShort(),\n shouldCacheResponse: checkGraphQLErrors,\n waitUntil,\n });\n\n if (!response.ok) {\n /**\n * The Storefront API might return a string error, or a JSON-formatted {error: string}.\n * We try both and conform them to a single {errors} format.\n */\n let errors;\n try {\n errors = parseJSON(body);\n } catch (_e) {\n errors = [{message: body}];\n }\n\n throwError(response, errors);\n }\n\n const {data, errors} = body as StorefrontApiResponse<T>;\n\n if (errors?.length) throwError(response, errors, StorefrontApiError);\n\n return data as T;\n }\n\n return {\n storefront: {\n /**\n * Sends a GraphQL query to the Storefront API.\n *\n * Example:\n *\n * ```js\n * async function loader ({context: {storefront}}) {\n * const data = await storefront.query('query { ... }', {\n * variables: {},\n * cache: storefront.CacheLong()\n * });\n * }\n * ```\n */\n query: <Storefront['query']>((query: string, payload) => {\n query = minifyQuery(query);\n if (isMutationRE.test(query))\n throw new Error('storefront.query cannot execute mutations');\n\n return fetchStorefrontApi({...payload, query});\n }),\n /**\n * Sends a GraphQL mutation to the Storefront API.\n *\n * Example:\n *\n * ```js\n * async function loader ({context: {storefront}}) {\n * await storefront.mutate('mutation { ... }', {\n * variables: {},\n * });\n * }\n * ```\n */\n mutate: <Storefront['mutate']>((mutation: string, payload) => {\n mutation = minifyQuery(mutation);\n if (isQueryRE.test(mutation))\n throw new Error('storefront.mutate cannot execute queries');\n\n return fetchStorefrontApi({...payload, mutation});\n }),\n cache,\n CacheNone,\n CacheLong,\n CacheShort,\n CacheCustom,\n generateCacheControlHeader,\n getPublicTokenHeaders,\n getPrivateTokenHeaders,\n getShopifyDomain,\n getApiUrl: getStorefrontApiUrl,\n /**\n * Wether it's a GraphQL error returned in the Storefront API response.\n *\n * Example:\n *\n * ```js\n * async function loader ({context: {storefront}}) {\n * try {\n * await storefront.query(...);\n * } catch(error) {\n * if (storefront.isApiError(error)) {\n * // ...\n * }\n *\n * throw error;\n * }\n * }\n * ```\n */\n isApiError: isStorefrontApiError,\n i18n: (i18n ?? defaultI18n) as TI18n,\n },\n };\n}\n\nfunction throwError<T>(\n response: Response,\n errors: StorefrontApiResponse<T>['errors'],\n ErrorConstructor = Error,\n) {\n const reqId = response.headers.get('x-request-id');\n const reqIdMessage = reqId ? ` - Request ID: ${reqId}` : '';\n\n if (errors) {\n const errorMessages =\n typeof errors === 'string'\n ? errors\n : errors.map((error) => error.message).join('\\n');\n\n throw new ErrorConstructor(errorMessages + reqIdMessage);\n }\n\n throw new ErrorConstructor(\n `API response error: ${response.status}` + reqIdMessage,\n );\n}\n","type QueryKey = string | readonly unknown[];\n\nexport function hashKey(queryKey: QueryKey): string {\n const rawKeys = Array.isArray(queryKey) ? queryKey : [queryKey];\n let hash = '';\n\n // Keys from `storefront.query` are in the following shape:\n // ['prefix', 'api-endpoint', {body:'query',headers:{}}]\n // Since the API endpoint already contains the shop domain and api version,\n // we can ignore the headers and only use the `body` from the payload.\n for (const key of rawKeys) {\n if (key != null) {\n if (typeof key === 'object') {\n // Queries from useQuery might not have a `body`. In that case,\n // fallback to a safer (but slower) stringify.\n if (!!key.body && typeof key.body === 'string') {\n hash += key.body;\n } else {\n hash += JSON.stringify(key);\n }\n } else {\n hash += key;\n }\n }\n }\n\n return hash;\n}\n","/**\n * Override options for a cache strategy.\n */\nexport interface AllCacheOptions {\n /**\n * The caching mode, generally `public`, `private`, or `no-store`.\n */\n mode?: string;\n /**\n * The maximum amount of time in seconds that a resource will be considered fresh. See `max-age` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#:~:text=Response%20Directives-,max%2Dage,-The%20max%2Dage).\n */\n maxAge?: number;\n /**\n * Indicate that the cache should serve the stale response in the background while revalidating the cache. See `stale-while-revalidate` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate).\n */\n staleWhileRevalidate?: number;\n /**\n * Similar to `maxAge` but specific to shared caches. See `s-maxage` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#s-maxage).\n */\n sMaxAge?: number;\n /**\n * Indicate that the cache should serve the stale response if an error occurs while revalidating the cache. See `stale-if-error` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-if-error).\n */\n staleIfError?: number;\n}\n\n/**\n * Use the `CachingStrategy` to define a custom caching mechanism for your data. Or use one of the pre-defined caching strategies: CacheNone, CacheShort, CacheLong.\n */\nexport type CachingStrategy = AllCacheOptions;\n\nexport type NoStoreStrategy = {\n mode: string;\n};\n\nconst PUBLIC = 'public';\nconst PRIVATE = 'private';\nexport const NO_STORE = 'no-store';\n\nconst optionMapping: {\n [key: string]: string;\n} = {\n maxAge: 'max-age',\n staleWhileRevalidate: 'stale-while-revalidate',\n sMaxAge: 's-maxage',\n staleIfError: 'stale-if-error',\n};\n\nexport function generateCacheControlHeader(\n cacheOptions: CachingStrategy,\n): string {\n const cacheControl: string[] = [];\n Object.keys(cacheOptions).forEach((key: string) => {\n if (key === 'mode') {\n cacheControl.push(cacheOptions[key] as string);\n } else if (optionMapping[key]) {\n cacheControl.push(\n `${optionMapping[key]}=${cacheOptions[key as keyof CachingStrategy]}`,\n );\n }\n });\n return cacheControl.join(', ');\n}\n\n/**\n *\n * @public\n */\nexport function CacheNone(): NoStoreStrategy {\n return {\n mode: NO_STORE,\n };\n}\n\nfunction guardExpirableModeType(overrideOptions?: CachingStrategy) {\n if (\n overrideOptions?.mode &&\n overrideOptions?.mode !== PUBLIC &&\n overrideOptions?.mode !== PRIVATE\n ) {\n throw Error(\"'mode' must be either 'public' or 'private'\");\n }\n}\n\n/**\n *\n * @public\n */\nexport function CacheShort(overrideOptions?: CachingStrategy): AllCacheOptions {\n guardExpirableModeType(overrideOptions);\n return {\n mode: PUBLIC,\n maxAge: 1,\n staleWhileRevalidate: 9,\n ...overrideOptions,\n };\n}\n\n/**\n *\n * @public\n */\nexport function CacheLong(overrideOptions?: CachingStrategy): AllCacheOptions {\n guardExpirableModeType(overrideOptions);\n return {\n mode: PUBLIC,\n maxAge: 3600, // 1 hour\n staleWhileRevalidate: 82800, // 23 Hours\n ...overrideOptions,\n };\n}\n\n/**\n *\n * @public\n */\nexport function CacheCustom(overrideOptions: CachingStrategy): AllCacheOptions {\n return overrideOptions as AllCacheOptions;\n}\n","export function parseJSON(json: any) {\n if (String(json).includes('__proto__')) return JSON.parse(json, noproto);\n return JSON.parse(json);\n}\nfunction noproto(k: string, v: string) {\n if (k !== '__proto__') return v;\n}\n","import type {CachingStrategy} from './strategies';\nimport {CacheShort, generateCacheControlHeader} from './strategies';\n\nfunction logCacheApiStatus(status: string | null, url: string) {\n // // eslint-disable-next-line no-console\n // console.log('\\n' + status, url);\n}\n\nfunction getCacheControlSetting(\n userCacheOptions?: CachingStrategy,\n options?: CachingStrategy,\n): CachingStrategy {\n if (userCacheOptions && options) {\n return {\n ...userCacheOptions,\n ...options,\n };\n } else {\n return userCacheOptions || CacheShort();\n }\n}\n\nfunction generateDefaultCacheControlHeader(\n userCacheOptions?: CachingStrategy,\n): string {\n return generateCacheControlHeader(getCacheControlSetting(userCacheOptions));\n}\n\n/**\n * Get an item from the cache. If a match is found, returns a tuple\n * containing the `JSON.parse` version of the response as well\n * as the response itself so it can be checked for staleness.\n */\nasync function getItem(\n cache: Cache,\n request: Request,\n): Promise<Response | undefined> {\n if (!cache) return;\n\n const response = await cache.match(request);\n if (!response) {\n logCacheApiStatus('MISS', request.url);\n return;\n }\n\n logCacheApiStatus('HIT', request.url);\n\n return response;\n}\n\n/**\n * Put an item into the cache.\n */\nasync function setItem(\n cache: Cache,\n request: Request,\n response: Response,\n userCacheOptions: CachingStrategy,\n) {\n if (!cache) return;\n\n /**\n * We are manually managing staled request by adding this workaround.\n * Why? cache control header support is dependent on hosting platform\n *\n * For example:\n *\n * Cloudflare's Cache API does not support `stale-while-revalidate`.\n * Cloudflare cache control header has a very odd behaviour.\n * Say we have the following cache control header on a request:\n *\n * public, max-age=15, stale-while-revalidate=30\n *\n * When there is a cache.match HIT, the cache control header would become\n *\n * public, max-age=14400, stale-while-revalidate=30\n *\n * == `stale-while-revalidate` workaround ==\n * Update response max-age so that:\n *\n * max-age = max-age + stale-while-revalidate\n *\n * For example:\n *\n * public, max-age=1, stale-while-revalidate=9\n * |\n * V\n * public, max-age=10, stale-while-revalidate=9\n *\n * Store the following information in the response header:\n *\n * cache-put-date - UTC time string of when this request is PUT into cache\n *\n * Note on `cache-put-date`: The `response.headers.get('date')` isn't static. I am\n * not positive what date this is returning but it is never over 500 ms\n * after subtracting from the current timestamp.\n *\n * `isStale` function will use the above information to test for stale-ness of a cached response\n */\n\n const cacheControl = getCacheControlSetting(userCacheOptions);\n\n // The padded cache-control to mimic stale-while-revalidate\n request.headers.set(\n 'cache-control',\n generateDefaultCacheControlHeader(\n getCacheControlSetting(cacheControl, {\n maxAge:\n (cacheControl.maxAge || 0) + (cacheControl.staleWhileRevalidate || 0),\n }),\n ),\n );\n // The cache-control we want to set on response\n const cacheControlString = generateDefaultCacheControlHeader(\n getCacheControlSetting(cacheControl),\n );\n\n // CF will override cache-control, so we need to keep a non-modified real-cache-control\n // cache-control is still necessary for mini-oxygen\n response.headers.set('cache-control', cacheControlString);\n response.headers.set('real-cache-control', cacheControlString);\n response.headers.set('cache-put-date', new Date().toUTCString());\n\n logCacheApiStatus('PUT', request.url);\n await cache.put(request, response);\n}\n\nasync function deleteItem(cache: Cache, request: Request) {\n if (!cache) return;\n\n logCacheApiStatus('DELETE', request.url);\n await cache.delete(request);\n}\n\n/**\n * Manually check the response to see if it's stale.\n */\nfunction isStale(request: Request, response: Response) {\n const responseDate = response.headers.get('cache-put-date');\n const cacheControl = response.headers.get('real-cache-control');\n let responseMaxAge = 0;\n\n if (cacheControl) {\n const maxAgeMatch = cacheControl.match(/max-age=(\\d*)/);\n if (maxAgeMatch && maxAgeMatch.length > 1) {\n responseMaxAge = parseFloat(maxAgeMatch[1]);\n }\n }\n\n if (!responseDate) {\n return false;\n }\n\n const ageInMs =\n new Date().valueOf() - new Date(responseDate as string).valueOf();\n const age = ageInMs / 1000;\n\n const result = age > responseMaxAge;\n\n if (result) {\n logCacheApiStatus('STALE', request.url);\n }\n\n return result;\n}\n\n/**\n *\n * @private\n */\nexport const CacheAPI = {\n get: getItem,\n set: setItem,\n delete: deleteItem,\n generateDefaultCacheControlHeader,\n isStale,\n};\n","import {parseJSON} from '../utils/parse-json';\nimport {CacheAPI} from './api';\nimport {\n CacheShort,\n type CachingStrategy,\n type AllCacheOptions,\n} from './strategies.js';\n\n/**\n * Wrapper Cache functions for sub queries\n */\n\n/**\n * Cache API is weird. We just need a full URL, so we make one up.\n */\nfunction getKeyUrl(key: string) {\n return `https://shopify.dev/?${key}`;\n}\n\nfunction getCacheOption(userCacheOptions?: CachingStrategy): AllCacheOptions {\n return userCacheOptions || CacheShort();\n}\n\nexport function generateSubRequestCacheControlHeader(\n userCacheOptions?: CachingStrategy,\n): string {\n return CacheAPI.generateDefaultCacheControlHeader(\n getCacheOption(userCacheOptions),\n );\n}\n\n/**\n * Get an item from the cache. If a match is found, returns a tuple\n * containing the `JSON.parse` version of the response as well\n * as the response itself so it can be checked for staleness.\n * @private\n */\nexport async function getItemFromCache(\n cache: Cache,\n key: string,\n): Promise<undefined | [any, Response]> {\n if (!cache) return;\n const url = getKeyUrl(key);\n const request = new Request(url);\n\n const response = await CacheAPI.get(cache, request);\n\n if (!response) {\n return;\n }\n\n const text = await response.text();\n try {\n return [parseJSON(text), response];\n } catch {\n return [text, response];\n }\n}\n\n/**\n * Put an item into the cache.\n * @private\n */\nexport async function setItemInCache(\n cache: Cache,\n key: string,\n value: any,\n userCacheOptions?: CachingStrategy,\n) {\n if (!cache) return;\n\n const url = getKeyUrl(key);\n const request = new Request(url);\n const response = new Response(JSON.stringify(value));\n\n await CacheAPI.set(\n cache,\n request,\n response,\n getCacheOption(userCacheOptions),\n );\n}\n\n/**\n *\n * @private\n */\nexport async function deleteItemFromCache(cache: Cache, key: string) {\n if (!cache) return;\n\n const url = getKeyUrl(key);\n const request = new Request(url);\n\n await CacheAPI.delete(cache, request);\n}\n\n/**\n * Manually check the response to see if it's stale.\n * @private\n */\nexport function isStale(key: string, response: Response) {\n return CacheAPI.isStale(new Request(getKeyUrl(key)), response);\n}\n","import {hashKey} from '../utils/hash.js';\nimport {CacheShort, CachingStrategy} from './strategies';\nimport {getItemFromCache, setItemInCache, isStale} from './sub-request';\n\n/**\n * The cache key is used to uniquely identify a value in the cache.\n */\nexport type CacheKey = string | readonly unknown[];\n\nexport type WithCacheOptions<T = unknown> = {\n strategy?: CachingStrategy | null;\n cacheInstance?: Cache;\n shouldCacheResult?: (value: T) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n};\n\nexport type FetchCacheOptions = {\n cache?: CachingStrategy;\n cacheInstance?: Cache;\n cacheKey?: CacheKey;\n shouldCacheResponse?: (body: any, response: Response) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n returnType?: 'json' | 'text' | 'arrayBuffer' | 'blob';\n};\n\nfunction toSerializableResponse(body: any, response: Response) {\n return [\n body,\n {\n status: response.status,\n statusText: response.statusText,\n headers: Array.from(response.headers.entries()),\n },\n ] satisfies [any, ResponseInit];\n}\n\nfunction fromSerializableResponse([body, init]: [any, ResponseInit]) {\n return [body, new Response(body, init)] as const;\n}\n\n// Check if the response body has GraphQL errors\n// https://spec.graphql.org/June2018/#sec-Response-Format\nexport const checkGraphQLErrors = (body: any) => !body?.errors;\n\n// Lock to prevent revalidating the same sub-request\n// in the same isolate. Note that different isolates\n// in the same colo could duplicate the revalidation\n// since this is only an in-memory lock.\n// https://github.com/Shopify/oxygen-platform/issues/625\nconst swrLock = new Set<string>();\n\nexport async function runWithCache<T = unknown>(\n cacheKey: CacheKey,\n actionFn: () => T | Promise<T>,\n {\n strategy = CacheShort(),\n cacheInstance,\n shouldCacheResult = () => true,\n waitUntil,\n }: WithCacheOptions<T>,\n): Promise<T> {\n if (!cacheInstance || !strategy) return actionFn();\n\n const key = hashKey([\n // '__HYDROGEN_CACHE_ID__', // TODO purgeQueryCacheOnBuild\n ...(typeof cacheKey === 'string' ? [cacheKey] : cacheKey),\n ]);\n\n const cachedItem = await getItemFromCache(cacheInstance, key);\n // console.log('--- Cache', cachedItem ? 'HIT' : 'MISS');\n\n if (cachedItem) {\n const [cachedResult, cacheInfo] = cachedItem;\n\n if (!swrLock.has(key) && isStale(key, cacheInfo)) {\n swrLock.add(key);\n\n // Important: Run revalidation asynchronously.\n const revalidatingPromise = Promise.resolve().then(async () => {\n try {\n const result = await actionFn();\n\n if (shouldCacheResult(result)) {\n await setItemInCache(cacheInstance, key, result, strategy);\n }\n } catch (error: any) {\n if (error.message) {\n error.message = 'SWR in sub-request failed: ' + error.message;\n }\n\n console.error(error);\n } finally {\n swrLock.delete(key);\n }\n });\n\n // Asynchronously wait for it in workers\n waitUntil?.(revalidatingPromise);\n }\n\n return cachedResult;\n }\n\n const result = await actionFn();\n\n /**\n * Important: Do this async\n */\n if (shouldCacheResult(result)) {\n const setItemInCachePromise = setItemInCache(\n cacheInstance,\n key,\n result,\n strategy,\n );\n\n waitUntil?.(setItemInCachePromise);\n }\n\n return result;\n}\n\n/**\n * `fetch` equivalent that stores responses in cache.\n * Useful for calling third-party APIs that need to be cached.\n * @private\n */\nexport async function fetchWithServerCache(\n url: string,\n requestInit: Request | RequestInit,\n {\n cacheInstance,\n cache: cacheOptions,\n cacheKey = [url, requestInit],\n shouldCacheResponse = () => true,\n waitUntil,\n returnType = 'json',\n }: FetchCacheOptions = {},\n): Promise<readonly [any, Response]> {\n if (!cacheOptions && (!requestInit.method || requestInit.method === 'GET')) {\n cacheOptions = CacheShort();\n }\n\n return runWithCache(\n cacheKey,\n async () => {\n const response = await fetch(url, requestInit);\n let data;\n\n try {\n data = await response[returnType]();\n } catch {\n data = await response.text();\n }\n\n return toSerializableResponse(data, response);\n },\n {\n cacheInstance,\n waitUntil,\n strategy: cacheOptions ?? null,\n shouldCacheResult: (result) =>\n shouldCacheResponse(...fromSerializableResponse(result)),\n },\n ).then(fromSerializableResponse);\n}\n","export const STOREFRONT_REQUEST_GROUP_ID_HEADER =\n 'Custom-Storefront-Request-Group-ID';\n","/*\n * Generate a UUID using crypto and fallback to Math.random if crypto is not available.\n */\nexport function generateUUID() {\n if (typeof crypto !== 'undefined' && !!crypto.randomUUID) {\n return crypto.randomUUID();\n } else {\n return `weak-${Math.random().toString(16).substring(2)}`;\n }\n}\n","const warnings = new Set<string>();\nexport const warnOnce = (string: string) => {\n if (!warnings.has(string)) {\n console.warn(string);\n warnings.add(string);\n }\n};\n","export const LIB_VERSION = '2023.4.3';\n","import {type CacheKey, runWithCache} from './cache/fetch';\nimport type {CachingStrategy} from './cache/strategies';\n\ntype CreateWithCacheOptions = {\n /** An instance that implements the [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache) */\n cache: Cache;\n /** The `waitUntil` function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform. */\n waitUntil: ExecutionContext['waitUntil'];\n};\n\n/**\n * Creates a utility function that executes an asynchronous operation\n * like `fetch` and caches the result according to the strategy provided.\n * Use this to call any third-party APIs from loaders or actions.\n * By default, it uses the `CacheShort` strategy.\n *\n */\nexport function createWithCache_unstable<T = unknown>(\n options: CreateWithCacheOptions,\n): CreateWithCacheReturn<T> {\n const {cache, waitUntil} = options;\n return function withCache<T = unknown>(\n cacheKey: CacheKey,\n strategy: CachingStrategy,\n actionFn: () => T | Promise<T>,\n ) {\n return runWithCache<T>(cacheKey, actionFn, {\n strategy,\n cacheInstance: cache,\n waitUntil,\n });\n };\n}\n\n/**\n * This is a caching async function. Whatever data is returned from the `actionFn` will be cached according to the strategy provided.\n *\n * Use the `CachingStrategy` to define a custom caching mechanism for your data. Or use one of the built-in caching strategies: `CacheNone`, `CacheShort`, `CacheLong`.\n */\ntype CreateWithCacheReturn<T> = (\n cacheKey: CacheKey,\n strategy: CachingStrategy,\n actionFn: () => T | Promise<T>,\n) => Promise<T>;\n\nexport type WithCache = ReturnType<typeof createWithCache_unstable>;\n","type CacheMatch = {\n body: Uint8Array;\n timestamp: number;\n status: number;\n headers: [string, string][];\n};\n\n/**\n * This is a limited implementation of an in-memory cache.\n * It only supports the `cache-control` header.\n * It does NOT support `age` or `expires` headers.\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Cache\n */\nexport class InMemoryCache implements Cache {\n #store: Map<string, CacheMatch>;\n\n constructor() {\n this.#store = new Map();\n }\n\n add(request: RequestInfo): Promise<void> {\n throw new Error('Method not implemented. Use `put` instead.');\n }\n\n addAll(requests: RequestInfo[]): Promise<void> {\n throw new Error('Method not implemented. Use `put` instead.');\n }\n\n matchAll(\n request?: RequestInfo,\n options?: CacheQueryOptions,\n ): Promise<readonly Response[]> {\n throw new Error('Method not implemented. Use `match` instead.');\n }\n\n async put(request: Request, response: Response) {\n if (request.method !== 'GET') {\n throw new TypeError('Cannot cache response to non-GET request.');\n }\n\n if (response.status === 206) {\n throw new TypeError(\n 'Cannot cache response to a range request (206 Partial Content).',\n );\n }\n\n if (response.headers.get('vary')?.includes('*')) {\n throw new TypeError(\"Cannot cache response with 'Vary: *' header.\");\n }\n\n this.#store.set(request.url, {\n body: new Uint8Array(await response.arrayBuffer()),\n status: response.status,\n headers: [...response.headers],\n timestamp: Date.now(),\n });\n }\n\n async match(request: Request) {\n if (request.method !== 'GET') return;\n\n const match = this.#store.get(request.url);\n\n if (!match) {\n return;\n }\n\n const {body, timestamp, ...metadata} = match;\n\n const headers = new Headers(metadata.headers);\n const cacheControl =\n headers.get('cache-control') || headers.get('real-cache-control') || '';\n const maxAge = parseInt(\n cacheControl.match(/max-age=(\\d+)/)?.[1] || '0',\n 10,\n );\n const swr = parseInt(\n cacheControl.match(/stale-while-revalidate=(\\d+)/)?.[1] || '0',\n 10,\n );\n const age = (Date.now() - timestamp) / 1000;\n\n const isMiss = age > maxAge + swr;\n\n if (isMiss) {\n this.#store.delete(request.url);\n return;\n }\n\n const isStale = age > maxAge;\n\n headers.set('cache', isStale ? 'STALE' : 'HIT');\n headers.set('date', new Date(timestamp).toUTCString());\n\n return new Response(body, {\n status: metadata.status ?? 200,\n headers,\n });\n }\n\n async delete(request: Request) {\n if (this.#store.has(request.url)) {\n this.#store.delete(request.url);\n return true;\n }\n return false;\n }\n\n keys(request?: Request) {\n const cacheKeys = [] as Request[];\n\n for (const url of this.#store.keys()) {\n if (!request || request.url === url) {\n cacheKeys.push(new Request(url));\n }\n }\n\n return Promise.resolve(cacheKeys);\n }\n}\n","import {redirect} from '@remix-run/server-runtime';\nimport type {UrlRedirectConnection} from '@shopify/hydrogen-react/storefront-api-types';\nimport type {I18nBase, Storefront} from '../storefront';\n\ntype StorefrontRedirect = {\n storefront: Storefront<I18nBase>;\n request: Request;\n response?: Response;\n};\n\n/**\n * Queries the Storefront API to see if there is any redirect\n * created for the current route and performs it. Otherwise,\n * it returns the response passed in the parameters. Useful for\n * conditionally redirecting after a 404 response.\n *\n * @see {@link https://help.shopify.com/en/manual/online-store/menus-and-links/url-redirect Creating URL redirects in Shopify}\n */\nexport async function storefrontRedirect(\n options: StorefrontRedirect,\n): Promise<Response> {\n const {\n storefront,\n request,\n response = new Response('Not Found', {status: 404}),\n } = options;\n\n const {pathname, search} = new URL(request.url);\n const redirectFrom = pathname + search;\n\n try {\n const {urlRedirects} = await storefront.query<{\n urlRedirects: UrlRedirectConnection;\n }>(REDIRECT_QUERY, {\n variables: {query: 'path:' + redirectFrom},\n });\n\n const location = urlRedirects?.edges?.[0]?.node?.target;\n\n if (location) {\n return new Response(null, {status: 302, headers: {location}});\n }\n\n const searchParams = new URLSearchParams(search);\n const redirectTo =\n searchParams.get('return_to') || searchParams.get('redirect');\n\n if (redirectTo) {\n if (isLocalPath(redirectTo)) {\n return redirect(redirectTo);\n } else {\n console.warn(\n `Cross-domain redirects are not supported. Tried to redirect from ${redirectFrom} to ${redirectTo}`,\n );\n }\n }\n } catch (error) {\n console.error(\n `Failed to fetch redirects from Storefront API for route ${redirectFrom}`,\n error,\n );\n }\n\n return response;\n}\n\nfunction isLocalPath(url: string) {\n try {\n // We don't want to redirect cross domain,\n // doing so could create fishing vulnerability\n // If `new URL()` succeeds, it's a fully qualified\n // url which is cross domain. If it fails, it's just\n // a path, which will be the current domain.\n new URL(url);\n } catch (e) {\n return true;\n }\n\n return false;\n}\n\nconst REDIRECT_QUERY = `#graphql\n query redirects($query: String) {\n urlRedirects(first: 1, query: $query) {\n edges {\n node {\n target\n }\n }\n }\n }\n`;\n","import type {LoaderArgs} from '@remix-run/server-runtime';\nimport type {Storefront} from '../storefront';\n\ntype GraphiQLLoader = (args: LoaderArgs) => Promise<Response>;\n\nexport const graphiqlLoader: GraphiQLLoader = async function graphiqlLoader({\n context,\n}: LoaderArgs) {\n const storefront = context?.storefront as Storefront | undefined;\n if (!storefront) {\n throw new Error(\n `GraphiQL: Hydrogen's storefront client must be injected in the loader context.`,\n );\n }\n\n const url = storefront.getApiUrl();\n const accessToken =\n storefront.getPublicTokenHeaders()['X-Shopify-Storefront-Access-Token'];\n\n return new Response(\n `\n<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <title>GraphiQL</title>\n <style>\n body {\n height: 100%;\n margin: 0;\n width: 100%;\n overflow: hidden;\n }\n\n #graphiql {\n height: 100vh;\n }\n </style>\n\n <script\n src=\"https://unpkg.com/react@17/umd/react.development.js\"\n integrity=\"sha512-Vf2xGDzpqUOEIKO+X2rgTLWPY+65++WPwCHkX2nFMu9IcstumPsf/uKKRd5prX3wOu8Q0GBylRpsDB26R6ExOg==\"\n crossorigin=\"anonymous\"\n ></script>\n <script\n src=\"https://unpkg.com/react-dom@17/umd/react-dom.development.js\"\n integrity=\"sha512-Wr9OKCTtq1anK0hq5bY3X/AvDI5EflDSAh0mE9gma+4hl+kXdTJPKZ3TwLMBcrgUeoY0s3dq9JjhCQc7vddtFg==\"\n crossorigin=\"anonymous\"\n ></script>\n <link rel=\"stylesheet\" href=\"https://unpkg.com/graphiql/graphiql.min.css\" />\n </head>\n\n <body>\n <div id=\"graphiql\">Loading...</div>\n <script\n src=\"https://unpkg.com/graphiql/graphiql.min.js\"\n type=\"application/javascript\"\n ></script>\n <script>\n ReactDOM.render(\n React.createElement(GraphiQL, {\n fetcher: GraphiQL.createFetcher({\n url: '${url}',\n headers: {\n 'X-Shopify-Storefront-Access-Token': '${accessToken}',\n }\n }),\n defaultEditorToolsVisibility: true,\n initialTabs: [{query: '{\\\\n shop {\\\\n name\\\\n }\\\\n}'}]\n }),\n document.getElementById('graphiql'),\n );\n </script>\n </body>\n</html>\n `,\n {status: 200, headers: {'content-type': 'text/html'}},\n );\n};\n","import {createElement, Fragment, lazy, Suspense, useMemo} from 'react';\nimport {\n type Location,\n type Params,\n useLocation,\n useMatches,\n} from '@remix-run/react';\nimport {generateSeoTags, type SeoConfig} from './generate-seo-tags';\nimport {type Thing} from 'schema-dts';\n\nimport type {\n AppData,\n LoaderFunction,\n SerializeFrom,\n} from '@remix-run/server-runtime';\n\nconst SeoLogger = lazy(() => import('./log-seo-tags'));\n\nexport interface SeoHandleFunction<\n Loader extends LoaderFunction | unknown = unknown,\n StructuredDataSchema extends Thing = Thing,\n> {\n (args: {\n data: Loader extends LoaderFunction ? SerializeFrom<Loader> : AppData;\n id: string;\n params: Params;\n pathname: Location['pathname'];\n search: Location['search'];\n hash: Location['hash'];\n key: string;\n }): Partial<SeoConfig<StructuredDataSchema>>;\n}\n\ninterface SeoProps {\n /** Enable debug mode that prints SEO properties for route in the console */\n debug?: boolean;\n}\n\nexport function Seo({debug}: SeoProps) {\n const matches = useMatches();\n const location = useLocation();\n\n // Capture the seo and jsonLd configs from the route matches\n const seoConfig = useMemo(() => {\n return (\n matches\n .flatMap((match) => {\n const {handle, ...routeMatch} = match;\n const routeData = {...routeMatch, ...location};\n const handleSeo = handle?.seo;\n const loaderSeo = routeMatch?.data?.seo;\n\n if (!handleSeo && !loaderSeo) {\n return [];\n }\n\n // if seo is defined in the handle, invoke it with the route data\n if (handleSeo) {\n return recursivelyInvokeOrReturn(handle.seo, routeData);\n } else {\n return [loaderSeo];\n }\n })\n // merge route seo (priority) with the root seo if both are present\n // jsonLd definitions are instead concatenated because there can be\n // multiple jsonLd tags on any given root+route. e.g root renders Organization\n // schema and a product page renders Product schema\n .reduce((acc, current) => {\n // remove seo properties with falsy values\n Object.keys(current).forEach(\n (key) => !current[key] && delete current[key],\n );\n\n const {jsonLd} = current;\n\n if (!jsonLd) {\n return {...acc, ...current};\n }\n\n // concatenate jsonLds if present\n if (!acc?.jsonLd) {\n return {...acc, ...current, jsonLd: [jsonLd]};\n } else {\n if (Array.isArray(jsonLd)) {\n return {\n ...acc,\n ...current,\n jsonLd: [...acc.jsonLd, ...jsonLd],\n };\n } else {\n return {\n ...acc,\n ...current,\n jsonLd: [...acc.jsonLd, jsonLd],\n };\n }\n }\n }, {} as SeoConfig<Thing>)\n );\n }, [matches, location]);\n\n // Generate seo and jsonLd tags from the route seo configs\n // and return the jsx elements as html\n const {html, loggerMarkup} = useMemo(() => {\n const headTags = generateSeoTags(seoConfig);\n const html = headTags.map((tag) => {\n if (tag.tag === 'script') {\n return createElement(tag.tag, {\n ...tag.props,\n key: tag.key,\n dangerouslySetInnerHTML: {__html: tag.children},\n });\n }\n\n return createElement(tag.tag, {...tag.props, key: tag.key}, tag.children);\n });\n\n const loggerMarkup = createElement(\n Suspense,\n {fallback: null},\n createElement(SeoLogger, {headTags}),\n );\n\n return {html, loggerMarkup};\n }, [seoConfig]);\n\n return createElement(Fragment, null, html, debug && loggerMarkup);\n}\n\n/**\n * Recursively invoke a function or return the value\n * @param value\n * @param rest\n * @returns\n */\nexport function recursivelyInvokeOrReturn<T, R extends any[]>(\n value: T | ((...rest: R) => T),\n ...rest: R\n): T | Record<string, T> {\n if (value instanceof Function) {\n return recursivelyInvokeOrReturn<T, R>(value(...rest), ...rest);\n }\n\n let result: Record<string, T> = {};\n\n if (Array.isArray(value)) {\n result = value.reduce((acc, item) => {\n return [...acc, recursivelyInvokeOrReturn(item)];\n }, []);\n\n return result;\n }\n\n if (value instanceof Object) {\n const entries = Object.entries(value);\n\n entries.forEach(([key, val]) => {\n // @ts-expect-error\n result[key] = recursivelyInvokeOrReturn<T, R>(val, ...rest);\n });\n\n return result;\n }\n\n return value;\n}\n","import type {ComponentPropsWithoutRef} from 'react';\nimport type {Maybe} from '@shopify/hydrogen-react/storefront-api-types';\nimport type {Thing, WithContext} from 'schema-dts';\n\nconst ERROR_PREFIX = 'Error in SEO input: ';\n\n// TODO: Refactor this into more reusable validators or use a library like zod to do this if we decide to use it in\n// other places. @cartogram\nexport const schema = {\n title: {\n validate: <T>(value: Maybe<T>): NonNullable<T> => {\n if (typeof value !== 'string') {\n throw new Error(ERROR_PREFIX.concat('`title` should be a string'));\n }\n\n if (typeof value === 'string' && value.length > 120) {\n throw new Error(\n ERROR_PREFIX.concat(\n '`title` should not be longer than 120 characters',\n ),\n );\n }\n\n return value;\n },\n },\n description: {\n validate: <T>(value: Maybe<T>): NonNullable<T> => {\n if (typeof value !== 'string') {\n throw new Error(\n ERROR_PREFIX.concat('`description` should be a string'),\n );\n }\n\n if (typeof value === 'string' && value.length > 155) {\n throw new Error(\n ERROR_PREFIX.concat(\n '`description` should not be longer than 155 characters',\n ),\n );\n }\n\n return value;\n },\n },\n url: {\n validate: <T>(value: Maybe<T>): NonNullable<T> => {\n if (typeof value !== 'string') {\n throw new Error(ERROR_PREFIX.concat('`url` should be a string'));\n }\n\n if (typeof value === 'string' && !value.startsWith('http')) {\n throw new Error(ERROR_PREFIX.concat('`url` should be a valid URL'));\n }\n\n return value;\n },\n },\n handle: {\n validate: <T>(value: Maybe<T>): NonNullable<T> => {\n if (typeof value !== 'string') {\n throw new Error(ERROR_PREFIX.concat('`handle` should be a string'));\n }\n\n if (typeof value === 'string' && !value.startsWith('@')) {\n throw new Error(ERROR_PREFIX.concat('`handle` should start with `@`'));\n }\n\n return value;\n },\n },\n};\n\nexport interface SeoConfig<Schema extends Thing = Thing> {\n /**\n * The <title> HTML element defines the document's title that is shown in a browser's title bar or a page's tab. It\n * only contains text; tags within the element are ignored.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title\n */\n title?: Maybe<string>;\n /**\n * Generate the title from a template that includes a `%s` placeholder for the title.\n *\n * @example\n * ```js\n * {\n * title: 'My Page',\n * titleTemplate: 'My Site - %s',\n * }\n * ```\n */\n titleTemplate?: Maybe<string> | null;\n /**\n * The media associated with the given page (images, videos, etc). If you pass a string, it will be used as the\n * `og:image` meta tag. If you pass an object or an array of objects, that will be used to generate `og:<type of\n * media>` meta tags. The `url` property should be the URL of the media. The `height` and `width` properties are\n * optional and should be the height and width of the media. The `altText` property is optional and should be a\n * description of the media.\n *\n * @example\n * ```js\n * {\n * media: [\n * {\n * url: 'https://example.com/image.jpg',\n * type: 'image',\n * height: '400',\n * width: '400',\n * altText: 'A custom snowboard with an alpine color pallet.',\n * }\n * ]\n * }\n * ```\n *\n */\n media?:\n | Maybe<string>\n | Partial<SeoMedia>\n | (Partial<SeoMedia> | Maybe<string>)[];\n /**\n * The description of the page. This is used in the `name=\"description\"` meta tag as well as the `og:description` meta\n * tag.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta\n */\n description?: Maybe<string>;\n /**\n * The canonical URL of the page. This is used to tell search engines which URL is the canonical version of a page.\n * This is useful when you have multiple URLs that point to the same page. The value here will be used in the\n * `rel=\"canonical\"` link tag as well as the `og:url` meta tag.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link\n */\n url?: Maybe<string>;\n /**\n * The handle is used to generate the `twitter:site` and `twitter:creator` meta tags. Include the `@` symbol in the\n * handle.\n *\n * @example\n * ```js\n * {\n * handle: '@shopify'\n * }\n * ```\n */\n handle?: Maybe<string>;\n /**\n * The `jsonLd` property is used to generate the `application/ld+json` script tag. This is used to provide structured\n * data to search engines. The value should be an object that conforms to the schema.org spec. The `type` property\n * should be the type of schema you are using. The `type` property is required and should be one of the following:\n *\n * - `Product`\n * - `ItemList`\n * - `Organization`\n * - `WebSite`\n * - `WebPage`\n * - `BlogPosting`\n * - `Thing`\n *\n * @example\n * ```js\n * {\n * jsonLd: {\n * '@context': 'https://schema.org',\n * '@type': 'Product',\n * name: 'My Product',\n * image: 'https://hydrogen.shop/image.jpg',\n * description: 'A product that is great',\n * sku: '12345',\n * mpn: '12345',\n * brand: {\n * '@type': 'Thing',\n * name: 'My Brand',\n * },\n * aggregateRating: {\n * '@type': 'AggregateRating',\n * ratingValue: '4.5',\n * reviewCount: '100',\n * },\n * offers: {\n * '@type': 'Offer',\n * priceCurrency: 'USD',\n * price: '100',\n * priceValidUntil: '2020-11-05',\n * itemCondition: 'https://schema.org/NewCondition',\n * availability: 'https://schema.org/InStock',\n * seller: {\n * '@type': 'Organization',\n * name: 'My Brand',\n * },\n * },\n * }\n * }\n * ```\n *\n * @see https://schema.org/docs/schemas.html\n * @see https://developers.google.com/search/docs/guides/intro-structured-data\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script\n *\n */\n jsonLd?: WithContext<Schema> | WithContext<Schema>[];\n /**\n * The `alternates` property is used to specify the language and geographical targeting when you have multiple\n * versions of the same page in different languages. The `url` property tells search engines about these variations\n * and helps them to serve the correct version to their users.\n *\n * @example\n * ```js\n * {\n * alternates: [\n * {\n * language: 'en-US',\n * url: 'https://hydrogen.shop/en-us',\n * default: true,\n * },\n * {\n * language: 'fr-CA',\n * url: 'https://hydrogen.shop/fr-ca',\n * },\n * ]\n * }\n * ```\n *\n * @see https://support.google.com/webmasters/answer/189077?hl=en\n */\n alternates?: LanguageAlternate | LanguageAlternate[];\n /**\n * The `robots` property is used to specify the robots meta tag. This is used to tell search engines which pages\n * should be indexed and which should not.\n *\n * @see https://developers.google.com/search/reference/robots_meta_tag\n */\n robots?: RobotsOptions;\n}\n\n/**\n * @see https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag\n */\nexport interface RobotsOptions {\n /**\n * Set the maximum size of an image preview for this page in a search results Can be one of the following:\n *\n * - `none` - No image preview is to be shown.\n * - `standard` - A default image preview may be shown.\n * - `large` - A larger image preview, up to the width of the viewport, may be shown.\n *\n * If no value is specified a default image preview size is used.\n */\n maxImagePreview?: 'none' | 'standard' | 'large';\n /**\n * A number representing the maximum of amount characters to use as a textual snippet for a search result. This value\n * can also be set to one of the following special values:\n *\n * - 0 - No snippet is to be shown. Equivalent to nosnippet.\n * - 1 - The Search engine will choose the snippet length that it believes is most effective to help users discover\n * your content and direct users to your site\n * - -1 - No limit on the number of characters that can be shown in the snippet.\n */\n maxSnippet?: number;\n /**\n * The maximum number of seconds for videos on this page to show in search results. This value can also be set to one\n * of the following special values:\n *\n * - 0 - A static image may be used with the `maxImagePreview` setting.\n * - 1 - There is no limit to the size of the video preview.\n *\n * This applies to all forms of search results (at Google: web search, Google Images, Google Videos, Discover,\n * Assistant).\n */\n maxVideoPreview?: number;\n /**\n * Do not show a cached link in search results.\n */\n noArchive?: boolean;\n /**\n * Do not follow the links on this page.\n *\n * @see https://developers.google.com/search/docs/advanced/guidelines/qualify-outbound-links\n */\n noFollow?: boolean;\n /**\n * Do not index images on this page.\n */\n noImageIndex?: boolean;\n /**\n * Do not show this page, media, or resource in search results.\n */\n noIndex?: boolean;\n /**\n * Do not show a text snippet or video preview in the search results for this page.\n */\n noSnippet?: boolean;\n /**\n * Do not offer translation of this page in search results.\n */\n noTranslate?: boolean;\n /**\n * Do not show this page in search results after the specified date/time.\n */\n unavailableAfter?: string;\n}\n\nexport interface LanguageAlternate {\n /**\n * Language code for the alternate page. This is used to generate the hreflang meta tag property.\n */\n language: string;\n /**\n * Whether the alternate page is the default page. This will add the `x-default` attribution to the language code.\n */\n default?: boolean;\n /**\n * The url of the alternate page. This is used to generate the hreflang meta tag property.\n */\n url: string;\n}\n\nexport type SeoMedia = {\n /**\n * Used to generate og:<type of media> meta tag\n */\n type: 'image' | 'video' | 'audio';\n /**\n * The url value populates both url and secure_url and is used to infer the og:<type of media>:type meta tag.\n */\n url: Maybe<string> | undefined;\n /**\n * The height in pixels of the media. This is used to generate the og:<type of media>:height meta tag.\n */\n height: Maybe<number> | undefined;\n /**\n * The width in pixels of the media. This is used to generate the og:<type of media>:width meta tag.\n */\n width: Maybe<number> | undefined;\n /**\n * The alt text for the media. This is used to generate the og:<type of media>:alt meta tag.\n */\n altText: Maybe<string> | undefined;\n};\n\ntype TagKey = 'title' | 'base' | 'meta' | 'link' | 'script';\n\nexport interface CustomHeadTagObject {\n tag: TagKey;\n props: Record<string, unknown>;\n children?: string;\n key: string;\n}\n\n/**\n * The `generateSeoTags` function generates the SEO title, meta, link and script (JSON Linking Data) tags for a page. It\n * pairs well with the SEO component in `@shopify/hydrogen` when building a Hydrogen Remix app, but can be used on its\n * own if you want to generate the tags yourself.\n */\nexport function generateSeoTags<\n Schema extends Thing,\n T extends SeoConfig<Schema> = SeoConfig<Schema>,\n>(seoInput: T): CustomHeadTagObject[] {\n const tagResults: CustomHeadTagObject[] = [];\n\n for (const seoKey of Object.keys(seoInput)) {\n switch (seoKey) {\n case 'title': {\n const content = validate(schema.title, seoInput.title);\n const title = renderTitle(seoInput?.titleTemplate, content);\n\n if (!title) {\n break;\n }\n\n tagResults.push(\n generateTag('title', {title}),\n generateTag('meta', {property: 'og:title', content: title}),\n generateTag('meta', {name: 'twitter:title', content: title}),\n );\n\n break;\n }\n\n case 'description': {\n const content = validate(schema.description, seoInput.description);\n\n if (!content) {\n break;\n }\n\n tagResults.push(\n generateTag('meta', {\n name: 'description',\n content,\n }),\n generateTag('meta', {\n property: 'og:description',\n content,\n }),\n generateTag('meta', {\n name: 'twitter:description',\n content,\n }),\n );\n\n break;\n }\n\n case 'url': {\n const content = validate(schema.url, seoInput.url);\n\n if (!content) {\n break;\n }\n\n tagResults.push(\n generateTag('link', {\n rel: 'canonical',\n href: content,\n }),\n generateTag('meta', {\n property: 'og:url',\n content,\n }),\n );\n\n break;\n }\n\n case 'handle': {\n const content = validate(schema.handle, seoInput.handle);\n\n if (!content) {\n break;\n }\n\n tagResults.push(\n generateTag('meta', {name: 'twitter:site', content}),\n generateTag('meta', {name: 'twitter:creator', content}),\n );\n\n break;\n }\n\n case 'media': {\n let content;\n const values = ensureArray(seoInput.media);\n\n for (const media of values) {\n if (typeof media === 'string') {\n tagResults.push(\n generateTag('meta', {name: 'og:image', content: media}),\n );\n }\n\n if (media && typeof media === 'object') {\n const type = media.type || 'image';\n\n // Order matters here when adding multiple media tags @see https://ogp.me/#array\n const normalizedMedia = media\n ? {\n url: media?.url,\n secure_url: media?.url,\n type: inferMimeType(media.url),\n width: media?.width,\n height: media?.height,\n alt: media?.altText,\n }\n : {};\n\n for (const key of Object.keys(normalizedMedia)) {\n if (normalizedMedia[key as keyof typeof normalizedMedia]) {\n content = normalizedMedia[\n key as keyof typeof normalizedMedia\n ] as string;\n\n tagResults.push(\n generateTag(\n 'meta',\n {\n property: `og:${type}:${key}`,\n content,\n },\n normalizedMedia.url as string,\n ),\n );\n }\n }\n }\n }\n break;\n }\n\n case 'jsonLd': {\n const jsonLdBlocks = ensureArray(seoInput.jsonLd);\n let index = 0;\n for (const block of jsonLdBlocks) {\n if (typeof block !== 'object') {\n continue;\n }\n\n const tag = generateTag(\n 'script',\n {\n type: 'application/ld+json',\n children: JSON.stringify(block),\n },\n // @ts-expect-error\n `json-ld-${block?.['@type'] || block?.name || index++}`,\n );\n\n tagResults.push(tag);\n }\n\n break;\n }\n\n case 'alternates': {\n const alternates = ensureArray(seoInput.alternates);\n\n for (const alternate of alternates) {\n if (!alternate) {\n continue;\n }\n\n const {language, url, default: defaultLang} = alternate;\n\n const hrefLang = language\n ? `${language}${defaultLang ? '-default' : ''}`\n : undefined;\n\n tagResults.push(\n generateTag('link', {\n rel: 'alternate',\n hrefLang,\n href: url,\n }),\n );\n }\n\n break;\n }\n\n case 'robots': {\n if (!seoInput.robots) {\n break;\n }\n\n const {\n maxImagePreview,\n maxSnippet,\n maxVideoPreview,\n noArchive,\n noFollow,\n noImageIndex,\n noIndex,\n noSnippet,\n noTranslate,\n unavailableAfter,\n } = seoInput.robots;\n\n const robotsParams = [\n noArchive && 'noarchive',\n noImageIndex && 'noimageindex',\n noSnippet && 'nosnippet',\n noTranslate && `notranslate`,\n maxImagePreview && `max-image-preview:${maxImagePreview}`,\n maxSnippet && `max-snippet:${maxSnippet}`,\n maxVideoPreview && `max-video-preview:${maxVideoPreview}`,\n unavailableAfter && `unavailable_after:${unavailableAfter}`,\n ];\n\n let robotsParam =\n (noIndex ? 'noindex' : 'index') +\n ',' +\n (noFollow ? 'nofollow' : 'follow');\n\n for (let param of robotsParams) {\n if (param) {\n robotsParam += `,${param}`;\n }\n }\n\n tagResults.push(\n generateTag('meta', {name: 'robots', content: robotsParam}),\n );\n\n break;\n }\n\n default: {\n // TODO: We should be able to catch unaccounted for keys at compile time\n // let exhaustiveCheck: never = seoKey;\n\n break;\n }\n }\n }\n\n return tagResults.flat().sort((a, b) => a.key.localeCompare(b.key));\n}\n\nexport function generateTag<T extends TagKey>(\n tagName: T,\n input: ComponentPropsWithoutRef<T>,\n group?: string,\n): CustomHeadTagObject {\n const tag: CustomHeadTagObject = {tag: tagName, props: {}, key: ''};\n\n // title tags don't have props so move to children\n if (tagName === 'title') {\n tag.children = input.title as string;\n tag.key = generateKey(tag);\n\n return tag;\n }\n\n // also move the input children to children and delete it\n if (tagName === 'script') {\n tag.children = typeof input.children === 'string' ? input.children : '';\n tag.key = generateKey(tag, group);\n delete input.children;\n tag.props = input;\n return tag;\n }\n\n // the rest goes on props\n tag.props = input;\n\n // remove empty props\n Object.keys(tag.props).forEach(\n (key) => !tag.props[key] && delete tag.props[key],\n );\n\n tag.key = generateKey(tag, group);\n\n return tag;\n}\n\n//**\n// * Generate a unique key for a tag\n// * @param tag - a generated tag object\n// * @param group? - the group the tag belongs to\n// * @returns - a unique key to be used for react\n// */\nexport function generateKey(tag: CustomHeadTagObject, group?: string) {\n const {tag: tagName, props} = tag;\n\n if (tagName === 'title') {\n // leading 0 moves title to the top when sorting\n return '0-title';\n }\n\n if (tagName === 'meta') {\n // leading 0 moves meta to the top when sorting exclude secure_url from the logic because the content is the same as\n // url\n const priority =\n props.content === group &&\n typeof props.property === 'string' &&\n !props.property.endsWith('secure_url') &&\n '0';\n const groupName = [group, priority];\n\n return [tagName, ...groupName, props.property || props.name]\n .filter((x) => x)\n .join('-');\n }\n\n if (tagName === 'link') {\n const key = [tagName, props.rel, props.hrefLang || props.media]\n .filter((x) => x)\n .join('-');\n\n // replace spaces with dashes, needed for media prop\n return key.replace(/\\s+/g, '-');\n }\n\n if (tagName === 'script') {\n return `${tagName}-${group}`;\n }\n\n return `${tagName}-${props.type}`;\n}\n\nfunction renderTitle<T extends CustomHeadTagObject['children']>(\n template?:\n | string\n | ((title: string) => string | undefined)\n | undefined\n | null,\n title?: T | null,\n): string | undefined {\n if (!title) {\n return undefined;\n }\n\n if (!template) {\n return title;\n }\n\n if (typeof template === 'function') {\n return template(title);\n }\n\n return template.replace('%s', title ?? '');\n}\n\nfunction inferMimeType(url: Maybe<string> | undefined) {\n const ext = url && url.split('.').pop();\n\n switch (ext) {\n case 'svg':\n return 'image/svg+xml';\n case 'png':\n return 'image/png';\n case 'gif':\n return 'image/gif';\n case 'swf':\n return 'application/x-shockwave-flash';\n case 'mp3':\n return 'audio/mpeg';\n case 'jpg':\n case 'jpeg':\n default:\n return 'image/jpeg';\n }\n}\n\nexport type SchemaType =\n | 'Product'\n | 'ItemList'\n | 'Organization'\n | 'WebSite'\n | 'WebPage'\n | 'BlogPosting'\n | 'Thing';\n\nfunction ensureArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value];\n}\n\nfunction validate<T>(\n schema: {validate: <T>(data: T) => NonNullable<T>},\n data: T,\n): T {\n try {\n return schema.validate<T>(data);\n } catch (error: unknown) {\n console.warn((error as Error).message);\n return data;\n }\n}\n","import {createElement, useEffect, useMemo, useState} from 'react';\nimport type {Maybe, PageInfo} from '@shopify/hydrogen/storefront-api-types';\nimport {flattenConnection} from '@shopify/hydrogen-react';\nimport {Link, LinkProps, useNavigation, useLocation} from '@remix-run/react';\n\ntype Connection<NodesType> =\n | {\n nodes: Array<NodesType>;\n pageInfo: PageInfo;\n }\n | {\n edges: {\n node: Array<NodesType>;\n };\n pageInfo: PageInfo;\n };\n\ntype PaginationState<NodesType> = {\n nodes?: Array<NodesType>;\n pageInfo?: PageInfo | null;\n};\n\ninterface PaginationInfo<NodesType> {\n /** The paginated array of nodes. You should map over and render this array. */\n nodes: Array<NodesType>;\n /** The `<NextLink>` is a helper component that makes it easy to navigate to the next page of paginated data. Alternatively you can build your own `<Link>` component: `<Link to={nextPageUrl} state={state} preventScrollReset />` */\n NextLink: (props: Omit<LinkProps, 'to'>) => JSX.Element | null;\n /** The `<PreviousLink>` is a helper component that makes it easy to navigate to the previous page of paginated data. Alternatively you can build your own `<Link>` component: `<Link to={previousPageUrl} state={state} preventScrollReset />` */\n PreviousLink: (props: Omit<LinkProps, 'to'>) => JSX.Element | null;\n /** The URL to the previous page of paginated data. Use this prop to build your own `<Link>` component. */\n previousPageUrl: string;\n /** The URL to the next page of paginated data. Use this prop to build your own `<Link>` component. */\n nextPageUrl: string;\n /** True if the cursor has next paginated data */\n hasNextPage: boolean;\n /** True if the cursor has previous paginated data */\n hasPreviousPage: boolean;\n /** True if we are in the process of fetching another page of data */\n isLoading: boolean;\n /** The `state` property is important to use when building your own `<Link>` component if you want paginated data to continuously append to the page. This means that every time the user clicks \"Next page\", the next page of data will be apppended inline with the previous page. If you want the whole page to re-render with only the next page results, do not pass the `state` prop to the Remix `<Link>` component. */\n state: {\n nodes: Array<NodesType>;\n pageInfo: {\n endCursor: Maybe<string> | undefined;\n startCursor: Maybe<string> | undefined;\n hasPreviousPage: boolean;\n };\n };\n}\n\ntype PaginationProps<NodesType> = {\n /** The response from `storefront.query` for a paginated request. Make sure the query is passed pagination variables and that the query has `pageInfo` with `hasPreviousPage`, `hasNextpage`, `startCursor`, and `endCursor` defined. */\n connection: Connection<NodesType>;\n /** A render prop that includes pagination data and helpers. */\n children: PaginationRenderProp<NodesType>;\n};\n\ntype PaginationRenderProp<NodesType> = (\n props: PaginationInfo<NodesType>,\n) => JSX.Element | null;\n\n/**\n *\n * The [Storefront API uses cursors](https://shopify.dev/docs/api/usage/pagination-graphql) to paginate through lists of data\n * and the \\`<Pagination />\\` component makes it easy to paginate data from the Storefront API.\n *\n * @prop connection The response from `storefront.query` for a paginated request. Make sure the query is passed pagination variables and that the query has `pageInfo` with `hasPreviousPage`, `hasNextpage`, `startCursor`, and `endCursor` defined.\n * @prop children A render prop that includes pagination data and helpers.\n */\nexport function Pagination<NodesType>({\n connection,\n children = () => {\n console.warn('<Pagination> requires children to work properly');\n return null;\n },\n}: PaginationProps<NodesType>) {\n const transition = useNavigation();\n const isLoading = transition.state === 'loading';\n const {\n endCursor,\n hasNextPage,\n hasPreviousPage,\n nextPageUrl,\n nodes,\n previousPageUrl,\n startCursor,\n } = usePagination<NodesType>(connection);\n\n const state = useMemo(\n () => ({\n pageInfo: {\n endCursor,\n hasPreviousPage,\n startCursor,\n },\n nodes,\n }),\n [endCursor, hasPreviousPage, startCursor, nodes],\n );\n\n const NextLink = useMemo(\n () =>\n function NextLink(props: Omit<LinkProps, 'to'>) {\n return hasNextPage\n ? createElement(Link, {\n preventScrollReset: true,\n ...props,\n to: nextPageUrl,\n state,\n replace: true,\n })\n : null;\n },\n [hasNextPage, nextPageUrl],\n );\n\n const PreviousLink = useMemo(\n () =>\n function PrevLink(props: Omit<LinkProps, 'to'>) {\n return hasPreviousPage\n ? createElement(Link, {\n preventScrollReset: true,\n ...props,\n to: previousPageUrl,\n state,\n replace: true,\n })\n : null;\n },\n [hasPreviousPage, previousPageUrl],\n );\n\n return children({\n state,\n hasNextPage,\n hasPreviousPage,\n isLoading,\n nextPageUrl,\n nodes,\n previousPageUrl,\n NextLink,\n PreviousLink,\n });\n}\n\n/**\n * Get cumulative pagination logic for a given connection\n */\nexport function usePagination<NodesType>(\n connection: Connection<NodesType>,\n): Omit<\n PaginationInfo<NodesType>,\n 'isLoading' | 'state' | 'NextLink' | 'PreviousLink'\n> & {\n startCursor: Maybe<string> | undefined;\n endCursor: Maybe<string> | undefined;\n} {\n const {state, search} = useLocation() as {\n state?: PaginationState<NodesType>;\n search?: string;\n };\n\n const params = new URLSearchParams(search);\n const direction = params.get('direction');\n const isPrevious = direction === 'previous';\n\n const nodes = useMemo(() => {\n if (!state || !state?.nodes) {\n return flattenConnection(connection);\n }\n\n if (isPrevious) {\n return [...flattenConnection(connection), ...state.nodes];\n } else {\n return [...state.nodes, ...flattenConnection(connection)];\n }\n }, [state, connection]);\n\n // `connection` represents the data that came from the server\n // `state` represents the data that came from the client\n const currentPageInfo = useMemo(() => {\n let pageStartCursor =\n state?.pageInfo?.startCursor === undefined\n ? connection.pageInfo.startCursor\n : state.pageInfo.startCursor;\n\n let pageEndCursor =\n state?.pageInfo?.endCursor === undefined\n ? connection.pageInfo.endCursor\n : state.pageInfo.endCursor;\n\n if (state?.nodes) {\n if (isPrevious) {\n pageStartCursor = connection.pageInfo.startCursor;\n } else {\n pageEndCursor = connection.pageInfo.endCursor;\n }\n }\n\n const previousPageExists =\n state?.pageInfo?.hasPreviousPage === undefined\n ? connection.pageInfo.hasPreviousPage\n : state.pageInfo.hasPreviousPage;\n\n const nextPageExists =\n state?.pageInfo?.hasNextPage === undefined\n ? connection.pageInfo.hasNextPage\n : state.pageInfo.hasNextPage;\n\n return {\n startCursor: pageStartCursor,\n endCursor: pageEndCursor,\n hasPreviousPage: previousPageExists,\n hasNextPage: nextPageExists,\n };\n }, [\n isPrevious,\n state,\n connection.pageInfo.hasNextPage,\n connection.pageInfo.hasPreviousPage,\n connection.pageInfo.startCursor,\n connection.pageInfo.endCursor,\n ]);\n\n const previousPageUrl = useMemo(() => {\n const params = new URLSearchParams(search);\n params.set('direction', 'previous');\n currentPageInfo.startCursor &&\n params.set('cursor', currentPageInfo.startCursor);\n return `?${params.toString()}`;\n }, [search, currentPageInfo.startCursor]);\n\n const nextPageUrl = useMemo(() => {\n const params = new URLSearchParams(search);\n params.set('direction', 'next');\n currentPageInfo.endCursor &&\n params.set('cursor', currentPageInfo.endCursor);\n return `?${params.toString()}`;\n }, [search, currentPageInfo.endCursor]);\n\n return {...currentPageInfo, previousPageUrl, nextPageUrl, nodes};\n}\n\n/**\n * @param request The request object passed to your Remix loader function.\n * @param options Options for how to configure the pagination variables. Includes the ability to change how many nodes are within each page.\n *\n * @returns Variables to be used with the `storefront.query` function\n */\nexport function getPaginationVariables(\n request: Request,\n options: {pageBy: number} = {pageBy: 20},\n) {\n if (!(request instanceof Request)) {\n throw new Error(\n 'getPaginationVariables must be called with the Request object passed to your loader function',\n );\n }\n\n const {pageBy} = options;\n const searchParams = new URLSearchParams(new URL(request.url).search);\n\n const cursor = searchParams.get('cursor') ?? undefined;\n const direction =\n searchParams.get('direction') === 'previous' ? 'previous' : 'next';\n const isPrevious = direction === 'previous';\n\n const prevPage = {\n last: pageBy,\n startCursor: cursor ?? null,\n };\n\n const nextPage = {\n first: pageBy,\n endCursor: cursor ?? null,\n };\n\n const variables = isPrevious ? prevPage : nextPage;\n\n return variables;\n}\n","export * from './storefront';\nexport * from './with-cache';\nexport {\n CacheCustom,\n CacheLong,\n CacheNone,\n CacheShort,\n generateCacheControlHeader,\n} from './cache/strategies';\nexport {InMemoryCache} from './cache/in-memory';\n\nexport {storefrontRedirect} from './routing/redirect';\nexport {graphiqlLoader} from './routing/graphiql';\nexport {Seo} from './seo/seo';\nexport {type SeoConfig} from './seo/generate-seo-tags';\nexport type {SeoHandleFunction} from './seo/seo';\nexport {\n Pagination as Pagination__unstable,\n getPaginationVariables as getPaginationVariables__unstable,\n} from './pagination/Pagination';\n\nexport {\n AnalyticsEventName,\n AnalyticsPageType,\n ExternalVideo,\n flattenConnection,\n getClientBrowserParameters,\n getShopifyCookies,\n Image,\n IMAGE_FRAGMENT,\n MediaFile,\n ModelViewer,\n Money,\n parseGid,\n parseMetafield,\n sendShopifyAnalytics,\n ShopifySalesChannel,\n ShopPayButton,\n storefrontApiCustomScalars,\n useMoney,\n useShopifyCookies,\n Video,\n} from '@shopify/hydrogen-react';\n\nexport type {\n ClientBrowserParameters,\n ParsedMetafields,\n ShopifyAddToCart,\n ShopifyAddToCartPayload,\n ShopifyAnalytics,\n ShopifyAnalyticsPayload,\n ShopifyAnalyticsProduct,\n ShopifyCookies,\n ShopifyPageView,\n ShopifyPageViewPayload,\n StorefrontApiResponse,\n StorefrontApiResponseError,\n StorefrontApiResponseOk,\n StorefrontApiResponseOkPartial,\n StorefrontApiResponsePartial,\n} from '@shopify/hydrogen-react';\n"]}
|