@shopify/hydrogen 2.0.0-alpha.2 → 2.0.0-alpha.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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var hydrogenReact = require('@shopify/hydrogen-react');
3
+ var storefrontKitReact = require('@shopify/storefront-kit-react');
4
4
  var serverRuntime = require('@remix-run/server-runtime');
5
5
 
6
6
  // src/storefront.ts
@@ -335,16 +335,12 @@ function createStorefrontClient({
335
335
  "Storefront API client created without a cache instance. This may slow down your sub-requests."
336
336
  );
337
337
  }
338
- clientOptions.storeDomain = clientOptions.storeDomain.replace(
339
- ".myshopify.com",
340
- ""
341
- );
342
338
  const {
343
339
  getPublicTokenHeaders,
344
340
  getPrivateTokenHeaders,
345
341
  getStorefrontApiUrl,
346
342
  getShopifyDomain
347
- } = hydrogenReact.createStorefrontClient(clientOptions);
343
+ } = storefrontKitReact.createStorefrontClient(clientOptions);
348
344
  const getHeaders = clientOptions.privateStorefrontToken ? getPrivateTokenHeaders : getPublicTokenHeaders;
349
345
  const defaultHeaders = getHeaders({ contentType: "json" });
350
346
  defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = requestGroupId;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/storefront.ts","../../src/utils/hash.ts","../../src/cache/strategies.ts","../../src/cache/api.ts","../../src/cache/sub-request.ts","../../src/cache/fetch.ts","../../src/constants.ts","../../src/utils/uuid.ts","../../src/utils/parse-json.ts","../../src/utils/warning.ts","../../src/cache/in-memory.ts","../../src/routing/redirect.ts","../../src/routing/graphiql.ts"],"names":["isStale","response","body","errors"],"mappings":"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","sourcesContent":["import {\n createStorefrontClient as createStorefrontUtilities,\n type StorefrontApiResponseOk,\n} from '@shopify/hydrogen-react';\nimport type {ExecutionArgs} from 'graphql';\nimport {fetchWithServerCache, checkGraphQLErrors} from './cache/fetch';\nimport {\n STOREFRONT_API_BUYER_IP_HEADER,\n STOREFRONT_REQUEST_GROUP_ID_HEADER,\n} 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';\n\ntype StorefrontApiResponse<T> = StorefrontApiResponseOk<T>;\n\nexport type StorefrontClient = ReturnType<typeof createStorefrontClient>;\nexport type Storefront = StorefrontClient['storefront'];\n\nexport type CreateStorefrontClientOptions = Parameters<\n typeof createStorefrontUtilities\n>[0] & {\n cache?: Cache;\n buyerIp?: string;\n requestGroupId?: string;\n waitUntil?: ExecutionContext['waitUntil'];\n i18n?: {\n language: LanguageCode;\n country: CountryCode;\n pathPrefix?: string;\n };\n};\n\ntype StorefrontCommonOptions = {\n variables?: ExecutionArgs['variableValues'] & {\n country?: CountryCode;\n language?: LanguageCode;\n };\n headers?: HeadersInit;\n storefrontApiVersion?: string;\n};\n\nexport type StorefrontQueryOptions = StorefrontCommonOptions & {\n query: string;\n mutation?: never;\n cache?: CachingStrategy;\n};\n\nexport type StorefrontMutationOptions = StorefrontCommonOptions & {\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\nexport function createStorefrontClient({\n cache,\n waitUntil,\n buyerIp,\n i18n = {language: 'EN', country: 'US'},\n requestGroupId = generateUUID(),\n ...clientOptions\n}: CreateStorefrontClientOptions) {\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 clientOptions.storeDomain = clientOptions.storeDomain.replace(\n '.myshopify.com',\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({contentType: 'json'});\n\n defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = requestGroupId;\n if (buyerIp) defaultHeaders[STOREFRONT_API_BUYER_IP_HEADER] = buyerIp;\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 = {\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: <T>(\n query: string,\n payload?: StorefrontCommonOptions & {cache?: CachingStrategy},\n ) => {\n query = minifyQuery(query);\n if (isMutationRE.test(query))\n throw new Error('storefront.query cannot execute mutations');\n\n return fetchStorefrontApi<T>({...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: <T>(mutation: string, payload?: StorefrontCommonOptions) => {\n mutation = minifyQuery(mutation);\n if (isQueryRE.test(mutation))\n throw new Error('storefront.mutate cannot execute queries');\n\n return fetchStorefrontApi<T>({...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 // Add default value for pathPefix.\n i18n: {pathPrefix: '', ...i18n},\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","export interface AllCacheOptions {\n mode?: string;\n maxAge?: number;\n staleWhileRevalidate?: number;\n sMaxAge?: number;\n staleIfError?: number;\n}\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","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 {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 return [await response.json(), response];\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\nexport type FetchCacheOptions = {\n cache?: CachingStrategy;\n cacheInstance?: Cache;\n cacheKey?: string | readonly unknown[];\n shouldCacheResponse?: (body: any, response: Response) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n returnType?: 'json' | 'text' | 'arrayBuffer' | 'blob';\n};\n\nfunction serializeResponse(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 ];\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\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 const doFetch = 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 [data, response] as const;\n };\n\n if (!cacheInstance || !cacheKey || !cacheOptions) return doFetch();\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 [cachedValue, 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 [body, response] = await doFetch();\n\n if (shouldCacheResponse(body, response)) {\n await setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\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 const [body, init] = cachedValue;\n return [body, new Response(body, init)];\n }\n\n const [body, response] = await doFetch();\n\n /**\n * Important: Do this async\n */\n if (shouldCacheResponse(body, response)) {\n const setItemInCachePromise = setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\n\n waitUntil?.(setItemInCachePromise);\n }\n\n return [body, response];\n}\n","export const STOREFRONT_REQUEST_GROUP_ID_HEADER =\n 'Custom-Storefront-Request-Group-ID';\nexport const STOREFRONT_API_BUYER_IP_HEADER = 'Shopify-Storefront-Buyer-IP';\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","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","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","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 {Storefront} from '../storefront';\n\ntype StorefrontRedirect = {\n storefront: Storefront;\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 storefront,\n request,\n response = new Response('Not Found', {status: 404}),\n}: StorefrontRedirect): Promise<Response> {\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 storefrontApiVersion: '2023-01',\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 {StorefrontClient} from '../storefront';\n\nexport function graphiqlLoader(\n {context} = {} as LoaderArgs & {\n context: LoaderArgs['context'] & StorefrontClient;\n },\n) {\n if (!context?.storefront) {\n throw new Error(\n `GraphiQL: Hydrogen's storefront client must be injected in the loader context.`,\n );\n }\n\n const url = context.storefront.getApiUrl();\n const accessToken =\n context.storefront.getPublicTokenHeaders()[\n 'X-Shopify-Storefront-Access-Token'\n ];\n\n return new Response(\n `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=utf-8/>\n <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui\">\n <title>Shopify Storefront API</title>\n <link rel=\"stylesheet\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css\" />\n <link rel=\"shortcut icon\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png\" />\n <script src=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js\"></script>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>window.addEventListener('load', function (event) {\n GraphQLPlayground.init(document.getElementById('root'), {\n endpoint: '${url}',\n settings:{\n 'request.globalHeaders': {\n Accept: 'application/json',\n 'Content-Type': 'application/graphql',\n 'X-Shopify-Storefront-Access-Token': '${accessToken}'\n }\n },\n tabs: [{\n endpoint: '${url}',\n query: '{ shop { name } }'\n }]\n })\n })</script>\n</body>\n</html>\n `,\n {status: 200, headers: {'content-type': 'text/html'}},\n );\n}\n"]}
1
+ {"version":3,"sources":["../../src/storefront.ts","../../src/utils/hash.ts","../../src/cache/strategies.ts","../../src/cache/api.ts","../../src/cache/sub-request.ts","../../src/cache/fetch.ts","../../src/constants.ts","../../src/utils/uuid.ts","../../src/utils/parse-json.ts","../../src/utils/warning.ts","../../src/cache/in-memory.ts","../../src/routing/redirect.ts","../../src/routing/graphiql.ts"],"names":["isStale","response","body","errors"],"mappings":"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","sourcesContent":["import {\n createStorefrontClient as createStorefrontUtilities,\n type StorefrontApiResponseOk,\n} from '@shopify/storefront-kit-react';\nimport type {ExecutionArgs} from 'graphql';\nimport {fetchWithServerCache, checkGraphQLErrors} from './cache/fetch';\nimport {\n STOREFRONT_API_BUYER_IP_HEADER,\n STOREFRONT_REQUEST_GROUP_ID_HEADER,\n} 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/storefront-kit-react/storefront-api-types';\nimport {warnOnce} from './utils/warning';\n\ntype StorefrontApiResponse<T> = StorefrontApiResponseOk<T>;\n\nexport type StorefrontClient = ReturnType<typeof createStorefrontClient>;\nexport type Storefront = StorefrontClient['storefront'];\n\nexport type CreateStorefrontClientOptions = Parameters<\n typeof createStorefrontUtilities\n>[0] & {\n cache?: Cache;\n buyerIp?: string;\n requestGroupId?: string;\n waitUntil?: ExecutionContext['waitUntil'];\n i18n?: {\n language: LanguageCode;\n country: CountryCode;\n pathPrefix?: string;\n };\n};\n\ntype StorefrontCommonOptions = {\n variables?: ExecutionArgs['variableValues'] & {\n country?: CountryCode;\n language?: LanguageCode;\n };\n headers?: HeadersInit;\n storefrontApiVersion?: string;\n};\n\nexport type StorefrontQueryOptions = StorefrontCommonOptions & {\n query: string;\n mutation?: never;\n cache?: CachingStrategy;\n};\n\nexport type StorefrontMutationOptions = StorefrontCommonOptions & {\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\nexport function createStorefrontClient({\n cache,\n waitUntil,\n buyerIp,\n i18n = {language: 'EN', country: 'US'},\n requestGroupId = generateUUID(),\n ...clientOptions\n}: CreateStorefrontClientOptions) {\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({contentType: 'json'});\n\n defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = requestGroupId;\n if (buyerIp) defaultHeaders[STOREFRONT_API_BUYER_IP_HEADER] = buyerIp;\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 = {\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: <T>(\n query: string,\n payload?: StorefrontCommonOptions & {cache?: CachingStrategy},\n ) => {\n query = minifyQuery(query);\n if (isMutationRE.test(query))\n throw new Error('storefront.query cannot execute mutations');\n\n return fetchStorefrontApi<T>({...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: <T>(mutation: string, payload?: StorefrontCommonOptions) => {\n mutation = minifyQuery(mutation);\n if (isQueryRE.test(mutation))\n throw new Error('storefront.mutate cannot execute queries');\n\n return fetchStorefrontApi<T>({...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 // Add default value for pathPefix.\n i18n: {pathPrefix: '', ...i18n},\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","export interface AllCacheOptions {\n mode?: string;\n maxAge?: number;\n staleWhileRevalidate?: number;\n sMaxAge?: number;\n staleIfError?: number;\n}\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","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 {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 return [await response.json(), response];\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\nexport type FetchCacheOptions = {\n cache?: CachingStrategy;\n cacheInstance?: Cache;\n cacheKey?: string | readonly unknown[];\n shouldCacheResponse?: (body: any, response: Response) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n returnType?: 'json' | 'text' | 'arrayBuffer' | 'blob';\n};\n\nfunction serializeResponse(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 ];\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\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 const doFetch = 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 [data, response] as const;\n };\n\n if (!cacheInstance || !cacheKey || !cacheOptions) return doFetch();\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 [cachedValue, 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 [body, response] = await doFetch();\n\n if (shouldCacheResponse(body, response)) {\n await setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\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 const [body, init] = cachedValue;\n return [body, new Response(body, init)];\n }\n\n const [body, response] = await doFetch();\n\n /**\n * Important: Do this async\n */\n if (shouldCacheResponse(body, response)) {\n const setItemInCachePromise = setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\n\n waitUntil?.(setItemInCachePromise);\n }\n\n return [body, response];\n}\n","export const STOREFRONT_REQUEST_GROUP_ID_HEADER =\n 'Custom-Storefront-Request-Group-ID';\nexport const STOREFRONT_API_BUYER_IP_HEADER = 'Shopify-Storefront-Buyer-IP';\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","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","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","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/storefront-kit-react/storefront-api-types';\nimport type {Storefront} from '../storefront';\n\ntype StorefrontRedirect = {\n storefront: Storefront;\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 storefront,\n request,\n response = new Response('Not Found', {status: 404}),\n}: StorefrontRedirect): Promise<Response> {\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 storefrontApiVersion: '2023-01',\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 {StorefrontClient} from '../storefront';\n\nexport function graphiqlLoader(\n {context} = {} as LoaderArgs & {\n context: LoaderArgs['context'] & StorefrontClient;\n },\n) {\n if (!context?.storefront) {\n throw new Error(\n `GraphiQL: Hydrogen's storefront client must be injected in the loader context.`,\n );\n }\n\n const url = context.storefront.getApiUrl();\n const accessToken =\n context.storefront.getPublicTokenHeaders()[\n 'X-Shopify-Storefront-Access-Token'\n ];\n\n return new Response(\n `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=utf-8/>\n <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui\">\n <title>Shopify Storefront API</title>\n <link rel=\"stylesheet\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css\" />\n <link rel=\"shortcut icon\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png\" />\n <script src=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js\"></script>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>window.addEventListener('load', function (event) {\n GraphQLPlayground.init(document.getElementById('root'), {\n endpoint: '${url}',\n settings:{\n 'request.globalHeaders': {\n Accept: 'application/json',\n 'Content-Type': 'application/graphql',\n 'X-Shopify-Storefront-Access-Token': '${accessToken}'\n }\n },\n tabs: [{\n endpoint: '${url}',\n query: '{ shop { name } }'\n }]\n })\n })</script>\n</body>\n</html>\n `,\n {status: 200, headers: {'content-type': 'text/html'}},\n );\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { createStorefrontClient as createStorefrontClient$1 } from '@shopify/hydrogen-react';
1
+ import { createStorefrontClient as createStorefrontClient$1 } from '@shopify/storefront-kit-react';
2
2
  import { redirect } from '@remix-run/server-runtime';
3
3
 
4
4
  // src/storefront.ts
@@ -333,10 +333,6 @@ function createStorefrontClient({
333
333
  "Storefront API client created without a cache instance. This may slow down your sub-requests."
334
334
  );
335
335
  }
336
- clientOptions.storeDomain = clientOptions.storeDomain.replace(
337
- ".myshopify.com",
338
- ""
339
- );
340
336
  const {
341
337
  getPublicTokenHeaders,
342
338
  getPrivateTokenHeaders,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/storefront.ts","../../src/utils/hash.ts","../../src/cache/strategies.ts","../../src/cache/api.ts","../../src/cache/sub-request.ts","../../src/cache/fetch.ts","../../src/constants.ts","../../src/utils/uuid.ts","../../src/utils/parse-json.ts","../../src/utils/warning.ts","../../src/cache/in-memory.ts","../../src/routing/redirect.ts","../../src/routing/graphiql.ts"],"names":["isStale","response","body","errors"],"mappings":"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","sourcesContent":["import {\n createStorefrontClient as createStorefrontUtilities,\n type StorefrontApiResponseOk,\n} from '@shopify/hydrogen-react';\nimport type {ExecutionArgs} from 'graphql';\nimport {fetchWithServerCache, checkGraphQLErrors} from './cache/fetch';\nimport {\n STOREFRONT_API_BUYER_IP_HEADER,\n STOREFRONT_REQUEST_GROUP_ID_HEADER,\n} 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';\n\ntype StorefrontApiResponse<T> = StorefrontApiResponseOk<T>;\n\nexport type StorefrontClient = ReturnType<typeof createStorefrontClient>;\nexport type Storefront = StorefrontClient['storefront'];\n\nexport type CreateStorefrontClientOptions = Parameters<\n typeof createStorefrontUtilities\n>[0] & {\n cache?: Cache;\n buyerIp?: string;\n requestGroupId?: string;\n waitUntil?: ExecutionContext['waitUntil'];\n i18n?: {\n language: LanguageCode;\n country: CountryCode;\n pathPrefix?: string;\n };\n};\n\ntype StorefrontCommonOptions = {\n variables?: ExecutionArgs['variableValues'] & {\n country?: CountryCode;\n language?: LanguageCode;\n };\n headers?: HeadersInit;\n storefrontApiVersion?: string;\n};\n\nexport type StorefrontQueryOptions = StorefrontCommonOptions & {\n query: string;\n mutation?: never;\n cache?: CachingStrategy;\n};\n\nexport type StorefrontMutationOptions = StorefrontCommonOptions & {\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\nexport function createStorefrontClient({\n cache,\n waitUntil,\n buyerIp,\n i18n = {language: 'EN', country: 'US'},\n requestGroupId = generateUUID(),\n ...clientOptions\n}: CreateStorefrontClientOptions) {\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 clientOptions.storeDomain = clientOptions.storeDomain.replace(\n '.myshopify.com',\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({contentType: 'json'});\n\n defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = requestGroupId;\n if (buyerIp) defaultHeaders[STOREFRONT_API_BUYER_IP_HEADER] = buyerIp;\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 = {\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: <T>(\n query: string,\n payload?: StorefrontCommonOptions & {cache?: CachingStrategy},\n ) => {\n query = minifyQuery(query);\n if (isMutationRE.test(query))\n throw new Error('storefront.query cannot execute mutations');\n\n return fetchStorefrontApi<T>({...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: <T>(mutation: string, payload?: StorefrontCommonOptions) => {\n mutation = minifyQuery(mutation);\n if (isQueryRE.test(mutation))\n throw new Error('storefront.mutate cannot execute queries');\n\n return fetchStorefrontApi<T>({...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 // Add default value for pathPefix.\n i18n: {pathPrefix: '', ...i18n},\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","export interface AllCacheOptions {\n mode?: string;\n maxAge?: number;\n staleWhileRevalidate?: number;\n sMaxAge?: number;\n staleIfError?: number;\n}\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","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 {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 return [await response.json(), response];\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\nexport type FetchCacheOptions = {\n cache?: CachingStrategy;\n cacheInstance?: Cache;\n cacheKey?: string | readonly unknown[];\n shouldCacheResponse?: (body: any, response: Response) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n returnType?: 'json' | 'text' | 'arrayBuffer' | 'blob';\n};\n\nfunction serializeResponse(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 ];\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\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 const doFetch = 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 [data, response] as const;\n };\n\n if (!cacheInstance || !cacheKey || !cacheOptions) return doFetch();\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 [cachedValue, 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 [body, response] = await doFetch();\n\n if (shouldCacheResponse(body, response)) {\n await setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\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 const [body, init] = cachedValue;\n return [body, new Response(body, init)];\n }\n\n const [body, response] = await doFetch();\n\n /**\n * Important: Do this async\n */\n if (shouldCacheResponse(body, response)) {\n const setItemInCachePromise = setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\n\n waitUntil?.(setItemInCachePromise);\n }\n\n return [body, response];\n}\n","export const STOREFRONT_REQUEST_GROUP_ID_HEADER =\n 'Custom-Storefront-Request-Group-ID';\nexport const STOREFRONT_API_BUYER_IP_HEADER = 'Shopify-Storefront-Buyer-IP';\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","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","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","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 {Storefront} from '../storefront';\n\ntype StorefrontRedirect = {\n storefront: Storefront;\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 storefront,\n request,\n response = new Response('Not Found', {status: 404}),\n}: StorefrontRedirect): Promise<Response> {\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 storefrontApiVersion: '2023-01',\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 {StorefrontClient} from '../storefront';\n\nexport function graphiqlLoader(\n {context} = {} as LoaderArgs & {\n context: LoaderArgs['context'] & StorefrontClient;\n },\n) {\n if (!context?.storefront) {\n throw new Error(\n `GraphiQL: Hydrogen's storefront client must be injected in the loader context.`,\n );\n }\n\n const url = context.storefront.getApiUrl();\n const accessToken =\n context.storefront.getPublicTokenHeaders()[\n 'X-Shopify-Storefront-Access-Token'\n ];\n\n return new Response(\n `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=utf-8/>\n <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui\">\n <title>Shopify Storefront API</title>\n <link rel=\"stylesheet\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css\" />\n <link rel=\"shortcut icon\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png\" />\n <script src=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js\"></script>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>window.addEventListener('load', function (event) {\n GraphQLPlayground.init(document.getElementById('root'), {\n endpoint: '${url}',\n settings:{\n 'request.globalHeaders': {\n Accept: 'application/json',\n 'Content-Type': 'application/graphql',\n 'X-Shopify-Storefront-Access-Token': '${accessToken}'\n }\n },\n tabs: [{\n endpoint: '${url}',\n query: '{ shop { name } }'\n }]\n })\n })</script>\n</body>\n</html>\n `,\n {status: 200, headers: {'content-type': 'text/html'}},\n );\n}\n"]}
1
+ {"version":3,"sources":["../../src/storefront.ts","../../src/utils/hash.ts","../../src/cache/strategies.ts","../../src/cache/api.ts","../../src/cache/sub-request.ts","../../src/cache/fetch.ts","../../src/constants.ts","../../src/utils/uuid.ts","../../src/utils/parse-json.ts","../../src/utils/warning.ts","../../src/cache/in-memory.ts","../../src/routing/redirect.ts","../../src/routing/graphiql.ts"],"names":["isStale","response","body","errors"],"mappings":"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","sourcesContent":["import {\n createStorefrontClient as createStorefrontUtilities,\n type StorefrontApiResponseOk,\n} from '@shopify/storefront-kit-react';\nimport type {ExecutionArgs} from 'graphql';\nimport {fetchWithServerCache, checkGraphQLErrors} from './cache/fetch';\nimport {\n STOREFRONT_API_BUYER_IP_HEADER,\n STOREFRONT_REQUEST_GROUP_ID_HEADER,\n} 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/storefront-kit-react/storefront-api-types';\nimport {warnOnce} from './utils/warning';\n\ntype StorefrontApiResponse<T> = StorefrontApiResponseOk<T>;\n\nexport type StorefrontClient = ReturnType<typeof createStorefrontClient>;\nexport type Storefront = StorefrontClient['storefront'];\n\nexport type CreateStorefrontClientOptions = Parameters<\n typeof createStorefrontUtilities\n>[0] & {\n cache?: Cache;\n buyerIp?: string;\n requestGroupId?: string;\n waitUntil?: ExecutionContext['waitUntil'];\n i18n?: {\n language: LanguageCode;\n country: CountryCode;\n pathPrefix?: string;\n };\n};\n\ntype StorefrontCommonOptions = {\n variables?: ExecutionArgs['variableValues'] & {\n country?: CountryCode;\n language?: LanguageCode;\n };\n headers?: HeadersInit;\n storefrontApiVersion?: string;\n};\n\nexport type StorefrontQueryOptions = StorefrontCommonOptions & {\n query: string;\n mutation?: never;\n cache?: CachingStrategy;\n};\n\nexport type StorefrontMutationOptions = StorefrontCommonOptions & {\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\nexport function createStorefrontClient({\n cache,\n waitUntil,\n buyerIp,\n i18n = {language: 'EN', country: 'US'},\n requestGroupId = generateUUID(),\n ...clientOptions\n}: CreateStorefrontClientOptions) {\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({contentType: 'json'});\n\n defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = requestGroupId;\n if (buyerIp) defaultHeaders[STOREFRONT_API_BUYER_IP_HEADER] = buyerIp;\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 = {\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: <T>(\n query: string,\n payload?: StorefrontCommonOptions & {cache?: CachingStrategy},\n ) => {\n query = minifyQuery(query);\n if (isMutationRE.test(query))\n throw new Error('storefront.query cannot execute mutations');\n\n return fetchStorefrontApi<T>({...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: <T>(mutation: string, payload?: StorefrontCommonOptions) => {\n mutation = minifyQuery(mutation);\n if (isQueryRE.test(mutation))\n throw new Error('storefront.mutate cannot execute queries');\n\n return fetchStorefrontApi<T>({...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 // Add default value for pathPefix.\n i18n: {pathPrefix: '', ...i18n},\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","export interface AllCacheOptions {\n mode?: string;\n maxAge?: number;\n staleWhileRevalidate?: number;\n sMaxAge?: number;\n staleIfError?: number;\n}\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","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 {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 return [await response.json(), response];\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\nexport type FetchCacheOptions = {\n cache?: CachingStrategy;\n cacheInstance?: Cache;\n cacheKey?: string | readonly unknown[];\n shouldCacheResponse?: (body: any, response: Response) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n returnType?: 'json' | 'text' | 'arrayBuffer' | 'blob';\n};\n\nfunction serializeResponse(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 ];\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\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 const doFetch = 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 [data, response] as const;\n };\n\n if (!cacheInstance || !cacheKey || !cacheOptions) return doFetch();\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 [cachedValue, 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 [body, response] = await doFetch();\n\n if (shouldCacheResponse(body, response)) {\n await setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\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 const [body, init] = cachedValue;\n return [body, new Response(body, init)];\n }\n\n const [body, response] = await doFetch();\n\n /**\n * Important: Do this async\n */\n if (shouldCacheResponse(body, response)) {\n const setItemInCachePromise = setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\n\n waitUntil?.(setItemInCachePromise);\n }\n\n return [body, response];\n}\n","export const STOREFRONT_REQUEST_GROUP_ID_HEADER =\n 'Custom-Storefront-Request-Group-ID';\nexport const STOREFRONT_API_BUYER_IP_HEADER = 'Shopify-Storefront-Buyer-IP';\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","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","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","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/storefront-kit-react/storefront-api-types';\nimport type {Storefront} from '../storefront';\n\ntype StorefrontRedirect = {\n storefront: Storefront;\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 storefront,\n request,\n response = new Response('Not Found', {status: 404}),\n}: StorefrontRedirect): Promise<Response> {\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 storefrontApiVersion: '2023-01',\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 {StorefrontClient} from '../storefront';\n\nexport function graphiqlLoader(\n {context} = {} as LoaderArgs & {\n context: LoaderArgs['context'] & StorefrontClient;\n },\n) {\n if (!context?.storefront) {\n throw new Error(\n `GraphiQL: Hydrogen's storefront client must be injected in the loader context.`,\n );\n }\n\n const url = context.storefront.getApiUrl();\n const accessToken =\n context.storefront.getPublicTokenHeaders()[\n 'X-Shopify-Storefront-Access-Token'\n ];\n\n return new Response(\n `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=utf-8/>\n <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui\">\n <title>Shopify Storefront API</title>\n <link rel=\"stylesheet\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css\" />\n <link rel=\"shortcut icon\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png\" />\n <script src=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js\"></script>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>window.addEventListener('load', function (event) {\n GraphQLPlayground.init(document.getElementById('root'), {\n endpoint: '${url}',\n settings:{\n 'request.globalHeaders': {\n Accept: 'application/json',\n 'Content-Type': 'application/graphql',\n 'X-Shopify-Storefront-Access-Token': '${accessToken}'\n }\n },\n tabs: [{\n endpoint: '${url}',\n query: '{ shop { name } }'\n }]\n })\n })</script>\n</body>\n</html>\n `,\n {status: 200, headers: {'content-type': 'text/html'}},\n );\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var hydrogenReact = require('@shopify/hydrogen-react');
3
+ var storefrontKitReact = require('@shopify/storefront-kit-react');
4
4
  var serverRuntime = require('@remix-run/server-runtime');
5
5
 
6
- function k(e){let t=Array.isArray(e)?e:[e],r="";for(let o of t)o!=null&&(typeof o=="object"?!!o.body&&typeof o.body=="string"?r+=o.body:r+=JSON.stringify(o):r+=o);return r}var P="public",ne="private",se="no-store",N={maxAge:"max-age",staleWhileRevalidate:"stale-while-revalidate",sMaxAge:"s-maxage",staleIfError:"stale-if-error"};function S(e){let t=[];return Object.keys(e).forEach(r=>{r==="mode"?t.push(e[r]):N[r]&&t.push(`${N[r]}=${e[r]}`);}),t.join(", ")}function q(){return {mode:se}}function $(e){if(e?.mode&&e?.mode!==P&&e?.mode!==ne)throw Error("'mode' must be either 'public' or 'private'")}function f(e){return $(e),{mode:P,maxAge:1,staleWhileRevalidate:9,...e}}function U(e){return $(e),{mode:P,maxAge:3600,staleWhileRevalidate:82800,...e}}function O(e){return e}function w(e,t){return e&&t?{...e,...t}:e||f()}function v(e){return S(w(e))}async function ae(e,t){if(!e)return;let r=await e.match(t);if(!r){t.url;return}return t.url,r}async function ie(e,t,r,o){if(!e)return;let n=w(o);t.headers.set("cache-control",v(w(n,{maxAge:(n.maxAge||0)+(n.staleWhileRevalidate||0)})));let a=v(w(n));r.headers.set("cache-control",a),r.headers.set("real-cache-control",a),r.headers.set("cache-put-date",new Date().toUTCString()),t.url,await e.put(t,r);}async function ce(e,t){!e||(t.url,await e.delete(t));}function ue(e,t){let r=t.headers.get("cache-put-date"),o=t.headers.get("real-cache-control"),n=0;if(o){let c=o.match(/max-age=(\d*)/);c&&c.length>1&&(n=parseFloat(c[1]));}if(!r)return !1;let p=(new Date().valueOf()-new Date(r).valueOf())/1e3>n;return p&&(e.url,void 0),p}var x={get:ae,set:ie,delete:ce,generateDefaultCacheControlHeader:v,isStale:ue};function _(e){return `https://shopify.dev/?${e}`}function pe(e){return e||f()}async function j(e,t){if(!e)return;let r=_(t),o=new Request(r),n=await x.get(e,o);if(!!n)return [await n.json(),n]}async function D(e,t,r,o){if(!e)return;let n=_(t),a=new Request(n),i=new Response(JSON.stringify(r));await x.set(e,a,i,pe(o));}function F(e,t){return x.isStale(new Request(_(e)),t)}function Q(e,t){return [e,{status:t.status,statusText:t.statusText,headers:Array.from(t.headers.entries())}]}var G=e=>!e?.errors,H=new Set;async function W(e,t,{cacheInstance:r,cache:o,cacheKey:n=[e,t],shouldCacheResponse:a=()=>!0,waitUntil:i,returnType:p="json"}={}){!o&&(!t.method||t.method==="GET")&&(o=f());let c=async()=>{let s=await fetch(e,t),l;try{l=await s[p]();}catch{l=await s.text();}return [l,s]};if(!r||!n||!o)return c();let u=k([...typeof n=="string"?[n]:n]),y=await j(r,u);if(y){let[s,l]=y;if(!H.has(u)&&F(u,l)){H.add(u);let m=Promise.resolve().then(async()=>{try{let[h,R]=await c();a(h,R)&&await D(r,u,Q(h,R),o);}catch(h){h.message&&(h.message="SWR in sub-request failed: "+h.message),console.error(h);}finally{H.delete(u);}});i?.(m);}let[C,A]=s;return [C,new Response(C,A)]}let[g,d]=await c();if(a(g,d)){let s=D(r,u,Q(g,d),o);i?.(s);}return [g,d]}var B="Custom-Storefront-Request-Group-ID",J="Shopify-Storefront-Buyer-IP";function V(){return typeof crypto<"u"&&!!crypto.randomUUID?crypto.randomUUID():`weak-${Math.random().toString(16).substring(2)}`}function Y(e){return String(e).includes("__proto__")?JSON.parse(e,le):JSON.parse(e)}function le(e,t){if(e!=="__proto__")return t}var K=new Set,X=e=>{K.has(e)||(console.warn(e),K.add(e));};var ee=class extends Error{},he=e=>e instanceof ee,ge=/(^|}\s)query[\s({]/im,de=/(^|}\s)mutation[\s({]/im;function z(e){return e.replace(/\s*#.*$/gm,"").replace(/\s+/gm," ").trim()}function We({cache:e,waitUntil:t,buyerIp:r,i18n:o={language:"EN",country:"US"},requestGroupId:n=V(),...a}){e||X("Storefront API client created without a cache instance. This may slow down your sub-requests."),a.storeDomain=a.storeDomain.replace(".myshopify.com","");let{getPublicTokenHeaders:i,getPrivateTokenHeaders:p,getStorefrontApiUrl:c,getShopifyDomain:u}=hydrogenReact.createStorefrontClient(a),g=(a.privateStorefrontToken?p:i)({contentType:"json"});g[B]=n,r&&(g[J]=r);async function d({query:s,mutation:l,variables:C,cache:A,headers:m=[],storefrontApiVersion:h}){let R=m instanceof Headers?Object.fromEntries(m.entries()):Array.isArray(m)?Object.fromEntries(m):m;s=s??l;let E={...C};o&&(!C?.country&&/\$country/.test(s)&&(E.country=o.country),!C?.language&&/\$language/.test(s)&&(E.language=o.language));let te=c({storefrontApiVersion:h}),re={method:"POST",headers:{...g,...R},body:JSON.stringify({query:s,variables:E})},[T,I]=await W(te,re,{cacheInstance:l?void 0:e,cache:A||f(),shouldCacheResponse:G,waitUntil:t});if(!I.ok){let b;try{b=Y(T);}catch{b=[{message:T}];}Z(I,b);}let{data:oe,errors:M}=T;return M?.length&&Z(I,M,ee),oe}return {storefront:{query:(s,l)=>{if(s=z(s),de.test(s))throw new Error("storefront.query cannot execute mutations");return d({...l,query:s})},mutate:(s,l)=>{if(s=z(s),ge.test(s))throw new Error("storefront.mutate cannot execute queries");return d({...l,mutation:s})},cache:e,CacheNone:q,CacheLong:U,CacheShort:f,CacheCustom:O,generateCacheControlHeader:S,getPublicTokenHeaders:i,getPrivateTokenHeaders:p,getShopifyDomain:u,getApiUrl:c,isApiError:he,i18n:{pathPrefix:"",...o}}}}function Z(e,t,r=Error){let o=e.headers.get("x-request-id"),n=o?` - Request ID: ${o}`:"";if(t){let a=typeof t=="string"?t:t.map(i=>i.message).join(`
6
+ function k(e){let t=Array.isArray(e)?e:[e],r="";for(let o of t)o!=null&&(typeof o=="object"?!!o.body&&typeof o.body=="string"?r+=o.body:r+=JSON.stringify(o):r+=o);return r}var P="public",ne="private",se="no-store",N={maxAge:"max-age",staleWhileRevalidate:"stale-while-revalidate",sMaxAge:"s-maxage",staleIfError:"stale-if-error"};function S(e){let t=[];return Object.keys(e).forEach(r=>{r==="mode"?t.push(e[r]):N[r]&&t.push(`${N[r]}=${e[r]}`);}),t.join(", ")}function q(){return {mode:se}}function $(e){if(e?.mode&&e?.mode!==P&&e?.mode!==ne)throw Error("'mode' must be either 'public' or 'private'")}function f(e){return $(e),{mode:P,maxAge:1,staleWhileRevalidate:9,...e}}function O(e){return $(e),{mode:P,maxAge:3600,staleWhileRevalidate:82800,...e}}function U(e){return e}function w(e,t){return e&&t?{...e,...t}:e||f()}function v(e){return S(w(e))}async function ae(e,t){if(!e)return;let r=await e.match(t);if(!r){t.url;return}return t.url,r}async function ie(e,t,r,o){if(!e)return;let n=w(o);t.headers.set("cache-control",v(w(n,{maxAge:(n.maxAge||0)+(n.staleWhileRevalidate||0)})));let a=v(w(n));r.headers.set("cache-control",a),r.headers.set("real-cache-control",a),r.headers.set("cache-put-date",new Date().toUTCString()),t.url,await e.put(t,r);}async function ce(e,t){!e||(t.url,await e.delete(t));}function ue(e,t){let r=t.headers.get("cache-put-date"),o=t.headers.get("real-cache-control"),n=0;if(o){let c=o.match(/max-age=(\d*)/);c&&c.length>1&&(n=parseFloat(c[1]));}if(!r)return !1;let p=(new Date().valueOf()-new Date(r).valueOf())/1e3>n;return p&&(e.url,void 0),p}var x={get:ae,set:ie,delete:ce,generateDefaultCacheControlHeader:v,isStale:ue};function _(e){return `https://shopify.dev/?${e}`}function pe(e){return e||f()}async function j(e,t){if(!e)return;let r=_(t),o=new Request(r),n=await x.get(e,o);if(!!n)return [await n.json(),n]}async function D(e,t,r,o){if(!e)return;let n=_(t),a=new Request(n),i=new Response(JSON.stringify(r));await x.set(e,a,i,pe(o));}function F(e,t){return x.isStale(new Request(_(e)),t)}function Q(e,t){return [e,{status:t.status,statusText:t.statusText,headers:Array.from(t.headers.entries())}]}var G=e=>!e?.errors,H=new Set;async function W(e,t,{cacheInstance:r,cache:o,cacheKey:n=[e,t],shouldCacheResponse:a=()=>!0,waitUntil:i,returnType:p="json"}={}){!o&&(!t.method||t.method==="GET")&&(o=f());let c=async()=>{let s=await fetch(e,t),l;try{l=await s[p]();}catch{l=await s.text();}return [l,s]};if(!r||!n||!o)return c();let u=k([...typeof n=="string"?[n]:n]),y=await j(r,u);if(y){let[s,l]=y;if(!H.has(u)&&F(u,l)){H.add(u);let m=Promise.resolve().then(async()=>{try{let[h,R]=await c();a(h,R)&&await D(r,u,Q(h,R),o);}catch(h){h.message&&(h.message="SWR in sub-request failed: "+h.message),console.error(h);}finally{H.delete(u);}});i?.(m);}let[C,A]=s;return [C,new Response(C,A)]}let[g,d]=await c();if(a(g,d)){let s=D(r,u,Q(g,d),o);i?.(s);}return [g,d]}var B="Custom-Storefront-Request-Group-ID",J="Shopify-Storefront-Buyer-IP";function V(){return typeof crypto<"u"&&!!crypto.randomUUID?crypto.randomUUID():`weak-${Math.random().toString(16).substring(2)}`}function Y(e){return String(e).includes("__proto__")?JSON.parse(e,le):JSON.parse(e)}function le(e,t){if(e!=="__proto__")return t}var K=new Set,X=e=>{K.has(e)||(console.warn(e),K.add(e));};var ee=class extends Error{},he=e=>e instanceof ee,ge=/(^|}\s)query[\s({]/im,de=/(^|}\s)mutation[\s({]/im;function z(e){return e.replace(/\s*#.*$/gm,"").replace(/\s+/gm," ").trim()}function We({cache:e,waitUntil:t,buyerIp:r,i18n:o={language:"EN",country:"US"},requestGroupId:n=V(),...a}){e||X("Storefront API client created without a cache instance. This may slow down your sub-requests.");let{getPublicTokenHeaders:i,getPrivateTokenHeaders:p,getStorefrontApiUrl:c,getShopifyDomain:u}=storefrontKitReact.createStorefrontClient(a),g=(a.privateStorefrontToken?p:i)({contentType:"json"});g[B]=n,r&&(g[J]=r);async function d({query:s,mutation:l,variables:C,cache:A,headers:m=[],storefrontApiVersion:h}){let R=m instanceof Headers?Object.fromEntries(m.entries()):Array.isArray(m)?Object.fromEntries(m):m;s=s??l;let E={...C};o&&(!C?.country&&/\$country/.test(s)&&(E.country=o.country),!C?.language&&/\$language/.test(s)&&(E.language=o.language));let te=c({storefrontApiVersion:h}),re={method:"POST",headers:{...g,...R},body:JSON.stringify({query:s,variables:E})},[T,I]=await W(te,re,{cacheInstance:l?void 0:e,cache:A||f(),shouldCacheResponse:G,waitUntil:t});if(!I.ok){let b;try{b=Y(T);}catch{b=[{message:T}];}Z(I,b);}let{data:oe,errors:M}=T;return M?.length&&Z(I,M,ee),oe}return {storefront:{query:(s,l)=>{if(s=z(s),de.test(s))throw new Error("storefront.query cannot execute mutations");return d({...l,query:s})},mutate:(s,l)=>{if(s=z(s),ge.test(s))throw new Error("storefront.mutate cannot execute queries");return d({...l,mutation:s})},cache:e,CacheNone:q,CacheLong:O,CacheShort:f,CacheCustom:U,generateCacheControlHeader:S,getPublicTokenHeaders:i,getPrivateTokenHeaders:p,getShopifyDomain:u,getApiUrl:c,isApiError:he,i18n:{pathPrefix:"",...o}}}}function Z(e,t,r=Error){let o=e.headers.get("x-request-id"),n=o?` - Request ID: ${o}`:"";if(t){let a=typeof t=="string"?t:t.map(i=>i.message).join(`
7
7
  `);throw new r(a+n)}throw new r(`API response error: ${e.status}`+n)}var L=class{#e;constructor(){this.#e=new Map;}add(t){throw new Error("Method not implemented. Use `put` instead.")}addAll(t){throw new Error("Method not implemented. Use `put` instead.")}matchAll(t,r){throw new Error("Method not implemented. Use `match` instead.")}async put(t,r){if(t.method!=="GET")throw new TypeError("Cannot cache response to non-GET request.");if(r.status===206)throw new TypeError("Cannot cache response to a range request (206 Partial Content).");if(r.headers.get("vary")?.includes("*"))throw new TypeError("Cannot cache response with 'Vary: *' header.");this.#e.set(t.url,{body:new Uint8Array(await r.arrayBuffer()),status:r.status,headers:[...r.headers],timestamp:Date.now()});}async match(t){if(t.method!=="GET")return;let r=this.#e.get(t.url);if(!r)return;let{body:o,timestamp:n,...a}=r,i=new Headers(a.headers),p=i.get("cache-control")||i.get("real-cache-control")||"",c=parseInt(p.match(/max-age=(\d+)/)?.[1]||"0",10),u=parseInt(p.match(/stale-while-revalidate=(\d+)/)?.[1]||"0",10),y=(Date.now()-n)/1e3;if(y>c+u){this.#e.delete(t.url);return}let d=y>c;return i.set("cache",d?"STALE":"HIT"),i.set("date",new Date(n).toUTCString()),new Response(o,{status:a.status??200,headers:i})}async delete(t){return this.#e.has(t.url)?(this.#e.delete(t.url),!0):!1}keys(t){let r=[];for(let o of this.#e.keys())(!t||t.url===o)&&r.push(new Request(o));return Promise.resolve(r)}};async function ye({storefront:e,request:t,response:r=new Response("Not Found",{status:404})}){let{pathname:o,search:n}=new URL(t.url),a=o+n;try{let{urlRedirects:i}=await e.query(Se,{variables:{query:"path:"+a},storefrontApiVersion:"2023-01"}),p=i?.edges?.[0]?.node?.target;if(p)return new Response(null,{status:302,headers:{location:p}});let c=new URLSearchParams(n),u=c.get("return_to")||c.get("redirect");if(u){if(Ce(u))return serverRuntime.redirect(u);console.warn(`Cross-domain redirects are not supported. Tried to redirect from ${a} to ${u}`);}}catch(i){console.error(`Failed to fetch redirects from Storefront API for route ${a}`,i);}return r}function Ce(e){try{new URL(e);}catch{return !0}return !1}var Se=`#graphql
8
8
  query redirects($query: String) {
9
9
  urlRedirects(first: 1, query: $query) {
@@ -47,8 +47,8 @@ function k(e){let t=Array.isArray(e)?e:[e],r="";for(let o of t)o!=null&&(typeof
47
47
  </html>
48
48
  `,{status:200,headers:{"content-type":"text/html"}})}
49
49
 
50
- exports.CacheCustom = O;
51
- exports.CacheLong = U;
50
+ exports.CacheCustom = U;
51
+ exports.CacheLong = O;
52
52
  exports.CacheNone = q;
53
53
  exports.CacheShort = f;
54
54
  exports.InMemoryCache = L;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/storefront.ts","../../src/utils/hash.ts","../../src/cache/strategies.ts","../../src/cache/api.ts","../../src/cache/sub-request.ts","../../src/cache/fetch.ts","../../src/constants.ts","../../src/utils/uuid.ts","../../src/utils/parse-json.ts","../../src/utils/warning.ts","../../src/cache/in-memory.ts","../../src/routing/redirect.ts","../../src/routing/graphiql.ts"],"names":["createStorefrontUtilities","hashKey","queryKey","rawKeys","hash","key","PUBLIC","PRIVATE","NO_STORE","optionMapping","generateCacheControlHeader","cacheOptions","cacheControl","CacheNone","guardExpirableModeType","overrideOptions","CacheShort","CacheLong","CacheCustom","getCacheControlSetting","userCacheOptions","options","generateDefaultCacheControlHeader","getItem","cache","request","response","setItem","cacheControlString","deleteItem","isStale","responseDate","responseMaxAge","maxAgeMatch","result","CacheAPI","getKeyUrl","getCacheOption","getItemFromCache","url","setItemInCache","value","serializeResponse","body","checkGraphQLErrors","swrLock","fetchWithServerCache","requestInit","cacheInstance","cacheKey","shouldCacheResponse","waitUntil","returnType","doFetch","data","cachedItem","cachedValue","cacheInfo","revalidatingPromise","error","init","setItemInCachePromise","STOREFRONT_REQUEST_GROUP_ID_HEADER","STOREFRONT_API_BUYER_IP_HEADER","generateUUID","parseJSON","json","noproto","k","v","warnings","warnOnce","string","StorefrontApiError","isStorefrontApiError","isQueryRE","isMutationRE","minifyQuery","createStorefrontClient","buyerIp","i18n","requestGroupId","clientOptions","getPublicTokenHeaders","getPrivateTokenHeaders","getStorefrontApiUrl","getShopifyDomain","defaultHeaders","fetchStorefrontApi","query","mutation","variables","headers","storefrontApiVersion","userHeaders","queryVariables","errors","throwError","payload","ErrorConstructor","reqId","reqIdMessage","errorMessages","InMemoryCache","#store","requests","match","timestamp","metadata","maxAge","swr","age","cacheKeys","redirect","storefrontRedirect","storefront","pathname","search","redirectFrom","urlRedirects","REDIRECT_QUERY","location","searchParams","redirectTo","isLocalPath","graphiqlLoader","context","accessToken"],"mappings":"AAAA,OACE,0BAA0BA,OAErB,0BCDA,SAASC,EAAQC,EAA4B,CAClD,IAAMC,EAAU,MAAM,QAAQD,CAAQ,EAAIA,EAAW,CAACA,CAAQ,EAC1DE,EAAO,GAMX,QAAWC,KAAOF,EACZE,GAAO,OACL,OAAOA,GAAQ,SAGb,CAAC,CAACA,EAAI,MAAQ,OAAOA,EAAI,MAAS,SACpCD,GAAQC,EAAI,KAEZD,GAAQ,KAAK,UAAUC,CAAG,EAG5BD,GAAQC,GAKd,OAAOD,CACT,CCbA,IAAME,EAAS,SACTC,GAAU,UACHC,GAAW,WAElBC,EAEF,CACF,OAAQ,UACR,qBAAsB,yBACtB,QAAS,WACT,aAAc,gBAChB,EAEO,SAASC,EACdC,EACQ,CACR,IAAMC,EAAyB,CAAC,EAChC,cAAO,KAAKD,CAAY,EAAE,QAASN,GAAgB,CAC7CA,IAAQ,OACVO,EAAa,KAAKD,EAAaN,EAAc,EACpCI,EAAcJ,IACvBO,EAAa,KACX,GAAGH,EAAcJ,MAAQM,EAAaN,IACxC,CAEJ,CAAC,EACMO,EAAa,KAAK,IAAI,CAC/B,CAMO,SAASC,GAA6B,CAC3C,MAAO,CACL,KAAML,EACR,CACF,CAEA,SAASM,EAAuBC,EAAmC,CACjE,GACEA,GAAiB,MACjBA,GAAiB,OAAST,GAC1BS,GAAiB,OAASR,GAE1B,MAAM,MAAM,6CAA6C,CAE7D,CAMO,SAASS,EAAWD,EAAoD,CAC7E,OAAAD,EAAuBC,CAAe,EAC/B,CACL,KAAMT,EACN,OAAQ,EACR,qBAAsB,EACtB,GAAGS,CACL,CACF,CAMO,SAASE,EAAUF,EAAoD,CAC5E,OAAAD,EAAuBC,CAAe,EAC/B,CACL,KAAMT,EACN,OAAQ,KACR,qBAAsB,MACtB,GAAGS,CACL,CACF,CAMO,SAASG,EAAYH,EAAmD,CAC7E,OAAOA,CACT,CCzFA,SAASI,EACPC,EACAC,EACiB,CACjB,OAAID,GAAoBC,EACf,CACL,GAAGD,EACH,GAAGC,CACL,EAEOD,GAAoBJ,EAAW,CAE1C,CAEA,SAASM,EACPF,EACQ,CACR,OAAOV,EAA2BS,EAAuBC,CAAgB,CAAC,CAC5E,CAOA,eAAeG,GACbC,EACAC,EAC+B,CAC/B,GAAI,CAACD,EAAO,OAEZ,IAAME,EAAW,MAAMF,EAAM,MAAMC,CAAO,EAC1C,GAAI,CAACC,EAAU,CACaD,EAAQ,IAClC,MACF,CAEA,OAAyBA,EAAQ,IAE1BC,CACT,CAKA,eAAeC,GACbH,EACAC,EACAC,EACAN,EACA,CACA,GAAI,CAACI,EAAO,OAyCZ,IAAMZ,EAAeO,EAAuBC,CAAgB,EAG5DK,EAAQ,QAAQ,IACd,gBACAH,EACEH,EAAuBP,EAAc,CACnC,QACGA,EAAa,QAAU,IAAMA,EAAa,sBAAwB,EACvE,CAAC,CACH,CACF,EAEA,IAAMgB,EAAqBN,EACzBH,EAAuBP,CAAY,CACrC,EAIAc,EAAS,QAAQ,IAAI,gBAAiBE,CAAkB,EACxDF,EAAS,QAAQ,IAAI,qBAAsBE,CAAkB,EAC7DF,EAAS,QAAQ,IAAI,iBAAkB,IAAI,KAAK,EAAE,YAAY,CAAC,EAEtCD,EAAQ,IACjC,MAAMD,EAAM,IAAIC,EAASC,CAAQ,CACnC,CAEA,eAAeG,GAAWL,EAAcC,EAAkB,CACpD,CAACD,IAEuBC,EAAQ,IACpC,MAAMD,EAAM,OAAOC,CAAO,EAC5B,CAKA,SAASK,GAAQL,EAAkBC,EAAoB,CACrD,IAAMK,EAAeL,EAAS,QAAQ,IAAI,gBAAgB,EACpDd,EAAec,EAAS,QAAQ,IAAI,oBAAoB,EAC1DM,EAAiB,EAErB,GAAIpB,EAAc,CAChB,IAAMqB,EAAcrB,EAAa,MAAM,eAAe,EAClDqB,GAAeA,EAAY,OAAS,IACtCD,EAAiB,WAAWC,EAAY,EAAE,EAE9C,CAEA,GAAI,CAACF,EACH,MAAO,GAOT,IAAMG,GAHJ,IAAI,KAAK,EAAE,QAAQ,EAAI,IAAI,KAAKH,CAAsB,EAAE,QAAQ,GAC5C,IAEDC,EAErB,OAAIE,IACyBT,EAAQ,IAAnC,QAGKS,CACT,CAMO,IAAMC,EAAW,CACtB,IAAKZ,GACL,IAAKI,GACL,OAAQE,GACR,kCAAAP,EACA,QAAAQ,EACF,EClKA,SAASM,EAAU/B,EAAa,CAC9B,MAAO,wBAAwBA,GACjC,CAEA,SAASgC,GAAejB,EAAqD,CAC3E,OAAOA,GAAoBJ,EAAW,CACxC,CAgBA,eAAsBsB,EACpBd,EACAnB,EACsC,CACtC,GAAI,CAACmB,EAAO,OACZ,IAAMe,EAAMH,EAAU/B,CAAG,EACnBoB,EAAU,IAAI,QAAQc,CAAG,EAEzBb,EAAW,MAAMS,EAAS,IAAIX,EAAOC,CAAO,EAElD,GAAI,EAACC,EAIL,MAAO,CAAC,MAAMA,EAAS,KAAK,EAAGA,CAAQ,CACzC,CAMA,eAAsBc,EACpBhB,EACAnB,EACAoC,EACArB,EACA,CACA,GAAI,CAACI,EAAO,OAEZ,IAAMe,EAAMH,EAAU/B,CAAG,EACnBoB,EAAU,IAAI,QAAQc,CAAG,EACzBb,EAAW,IAAI,SAAS,KAAK,UAAUe,CAAK,CAAC,EAEnD,MAAMN,EAAS,IACbX,EACAC,EACAC,EACAW,GAAejB,CAAgB,CACjC,CACF,CAmBO,SAASU,EAAQzB,EAAaqB,EAAoB,CACvD,OAAOS,EAAS,QAAQ,IAAI,QAAQC,EAAU/B,CAAG,CAAC,EAAGqB,CAAQ,CAC/D,CCnFA,SAASgB,EAAkBC,EAAWjB,EAAoB,CACxD,MAAO,CACLiB,EACA,CACE,OAAQjB,EAAS,OACjB,WAAYA,EAAS,WACrB,QAAS,MAAM,KAAKA,EAAS,QAAQ,QAAQ,CAAC,CAChD,CACF,CACF,CAIO,IAAMkB,EAAsBD,GAAc,CAACA,GAAM,OAOlDE,EAAU,IAAI,IAOpB,eAAsBC,EACpBP,EACAQ,EACA,CACE,cAAAC,EACA,MAAOrC,EACP,SAAAsC,EAAW,CAACV,EAAKQ,CAAW,EAC5B,oBAAAG,EAAsB,IAAM,GAC5B,UAAAC,EACA,WAAAC,EAAa,MACf,EAAuB,CAAC,EACW,CAC/B,CAACzC,IAAiB,CAACoC,EAAY,QAAUA,EAAY,SAAW,SAClEpC,EAAeK,EAAW,GAG5B,IAAMqC,EAAU,SAAY,CAC1B,IAAM3B,EAAW,MAAM,MAAMa,EAAKQ,CAAW,EACzCO,EAEJ,GAAI,CACFA,EAAO,MAAM5B,EAAS0B,GAAY,CACpC,MAAE,CACAE,EAAO,MAAM5B,EAAS,KAAK,CAC7B,CAEA,MAAO,CAAC4B,EAAM5B,CAAQ,CACxB,EAEA,GAAI,CAACsB,GAAiB,CAACC,GAAY,CAACtC,EAAc,OAAO0C,EAAQ,EAEjE,IAAMhD,EAAMJ,EAAQ,CAElB,GAAI,OAAOgD,GAAa,SAAW,CAACA,CAAQ,EAAIA,CAClD,CAAC,EAEKM,EAAa,MAAMjB,EAAiBU,EAAe3C,CAAG,EAG5D,GAAIkD,EAAY,CACd,GAAM,CAACC,EAAaC,CAAS,EAAIF,EAEjC,GAAI,CAACV,EAAQ,IAAIxC,CAAG,GAAKyB,EAAQzB,EAAKoD,CAAS,EAAG,CAChDZ,EAAQ,IAAIxC,CAAG,EAGf,IAAMqD,EAAsB,QAAQ,QAAQ,EAAE,KAAK,SAAY,CAC7D,GAAI,CACF,GAAM,CAACf,EAAMjB,CAAQ,EAAI,MAAM2B,EAAQ,EAEnCH,EAAoBP,EAAMjB,CAAQ,GACpC,MAAMc,EACJQ,EACA3C,EACAqC,EAAkBC,EAAMjB,CAAQ,EAChCf,CACF,CAEJ,OAASgD,EAAP,CACIA,EAAM,UACRA,EAAM,QAAU,8BAAgCA,EAAM,SAGxD,QAAQ,MAAMA,CAAK,CACrB,QAAE,CACAd,EAAQ,OAAOxC,CAAG,CACpB,CACF,CAAC,EAGD8C,IAAYO,CAAmB,CACjC,CAEA,GAAM,CAACf,EAAMiB,CAAI,EAAIJ,EACrB,MAAO,CAACb,EAAM,IAAI,SAASA,EAAMiB,CAAI,CAAC,CACxC,CAEA,GAAM,CAACjB,EAAMjB,CAAQ,EAAI,MAAM2B,EAAQ,EAKvC,GAAIH,EAAoBP,EAAMjB,CAAQ,EAAG,CACvC,IAAMmC,EAAwBrB,EAC5BQ,EACA3C,EACAqC,EAAkBC,EAAMjB,CAAQ,EAChCf,CACF,EAEAwC,IAAYU,CAAqB,CACnC,CAEA,MAAO,CAAClB,EAAMjB,CAAQ,CACxB,CCtIO,IAAMoC,EACX,qCACWC,EAAiC,8BCCvC,SAASC,GAAe,CAC7B,OAAI,OAAO,OAAW,KAAe,CAAC,CAAC,OAAO,WACrC,OAAO,WAAW,EAElB,QAAQ,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC,GAEzD,CCTO,SAASC,EAAUC,EAAW,CACnC,OAAI,OAAOA,CAAI,EAAE,SAAS,WAAW,EAAU,KAAK,MAAMA,EAAMC,EAAO,EAChE,KAAK,MAAMD,CAAI,CACxB,CACA,SAASC,GAAQC,EAAWC,EAAW,CACrC,GAAID,IAAM,YAAa,OAAOC,CAChC,CCNA,IAAMC,EAAW,IAAI,IACRC,EAAYC,GAAmB,CACrCF,EAAS,IAAIE,CAAM,IACtB,QAAQ,KAAKA,CAAM,EACnBF,EAAS,IAAIE,CAAM,EAEvB,ET4DA,IAAMC,GAAqB,cAAc,KAAM,CAAC,EACnCC,GAAwBf,GACnCA,aAAiBc,GAEbE,GAAY,uBACZC,GAAe,0BAErB,SAASC,EAAYL,EAAgB,CACnC,OAAOA,EACJ,QAAQ,YAAa,EAAE,EACvB,QAAQ,QAAS,GAAG,EACpB,KAAK,CACV,CAEO,SAASM,GAAuB,CACrC,MAAAtD,EACA,UAAA2B,EACA,QAAA4B,EACA,KAAAC,EAAO,CAAC,SAAU,KAAM,QAAS,IAAI,EACrC,eAAAC,EAAiBjB,EAAa,KAC3BkB,CACL,EAAkC,CAC3B1D,GAEH+C,EACE,+FACF,EAGFW,EAAc,YAAcA,EAAc,YAAY,QACpD,iBACA,EACF,EAEA,GAAM,CACJ,sBAAAC,EACA,uBAAAC,EACA,oBAAAC,EACA,iBAAAC,CACF,EAAItF,GAA0BkF,CAAa,EAMrCK,GAJaL,EAAc,uBAC7BE,EACAD,GAE8B,CAAC,YAAa,MAAM,CAAC,EAEvDI,EAAezB,GAAsCmB,EACjDF,IAASQ,EAAexB,GAAkCgB,GAE9D,eAAeS,EAAsB,CACnC,MAAAC,EACA,SAAAC,EACA,UAAAC,EACA,MAAOhF,EACP,QAAAiF,EAAU,CAAC,EACX,qBAAAC,CACF,EAAmE,CACjE,IAAMC,EACJF,aAAmB,QACf,OAAO,YAAYA,EAAQ,QAAQ,CAAC,EACpC,MAAM,QAAQA,CAAO,EACrB,OAAO,YAAYA,CAAO,EAC1BA,EAENH,EAAQA,GAASC,EAEjB,IAAMK,EAAiB,CAAC,GAAGJ,CAAS,EAEhCX,IACE,CAACW,GAAW,SAAW,YAAY,KAAKF,CAAK,IAC/CM,EAAe,QAAUf,EAAK,SAG5B,CAACW,GAAW,UAAY,aAAa,KAAKF,CAAK,IACjDM,EAAe,SAAWf,EAAK,WAInC,IAAMzC,GAAM8C,EAAoB,CAAC,qBAAAQ,CAAoB,CAAC,EAChD9C,GAAc,CAClB,OAAQ,OACR,QAAS,CAAC,GAAGwC,EAAgB,GAAGO,CAAW,EAC3C,KAAM,KAAK,UAAU,CACnB,MAAAL,EACA,UAAWM,CACb,CAAC,CACH,EAEM,CAACpD,EAAMjB,CAAQ,EAAI,MAAMoB,EAAqBP,GAAKQ,GAAa,CACpE,cAAe2C,EAAW,OAAYlE,EACtC,MAAOb,GAAgBK,EAAW,EAClC,oBAAqB4B,EACrB,UAAAO,CACF,CAAC,EAED,GAAI,CAACzB,EAAS,GAAI,CAKhB,IAAIsE,EACJ,GAAI,CACFA,EAAS/B,EAAUtB,CAAI,CACzB,MAAE,CACAqD,EAAS,CAAC,CAAC,QAASrD,CAAI,CAAC,CAC3B,CAEAsD,EAAWvE,EAAUsE,CAAM,CAC7B,CAEA,GAAM,CAAC,KAAA1C,GAAM,OAAA0C,CAAM,EAAIrD,EAEvB,OAAIqD,GAAQ,QAAQC,EAAWvE,EAAUsE,EAAQvB,EAAkB,EAE5DnB,EACT,CAEA,MAAO,CACL,WAAY,CAeV,MAAO,CACLmC,EACAS,IACG,CAEH,GADAT,EAAQZ,EAAYY,CAAK,EACrBb,GAAa,KAAKa,CAAK,EACzB,MAAM,IAAI,MAAM,2CAA2C,EAE7D,OAAOD,EAAsB,CAAC,GAAGU,EAAS,MAAAT,CAAK,CAAC,CAClD,EAcA,OAAQ,CAAIC,EAAkBQ,IAAsC,CAElE,GADAR,EAAWb,EAAYa,CAAQ,EAC3Bf,GAAU,KAAKe,CAAQ,EACzB,MAAM,IAAI,MAAM,0CAA0C,EAE5D,OAAOF,EAAsB,CAAC,GAAGU,EAAS,SAAAR,CAAQ,CAAC,CACrD,EACA,MAAAlE,EACA,UAAAX,EACA,UAAAI,EACA,WAAAD,EACA,YAAAE,EACA,2BAAAR,EACA,sBAAAyE,EACA,uBAAAC,EACA,iBAAAE,EACA,UAAWD,EAoBX,WAAYX,GAEZ,KAAM,CAAC,WAAY,GAAI,GAAGM,CAAI,CAChC,CACF,CACF,CAEA,SAASiB,EACPvE,EACAsE,EACAG,EAAmB,MACnB,CACA,IAAMC,EAAQ1E,EAAS,QAAQ,IAAI,cAAc,EAC3C2E,EAAeD,EAAQ,kBAAkBA,IAAU,GAEzD,GAAIJ,EAAQ,CACV,IAAMM,EACJ,OAAON,GAAW,SACdA,EACAA,EAAO,IAAKrC,GAAUA,EAAM,OAAO,EAAE,KAAK;AAAA,CAAI,EAEpD,MAAM,IAAIwC,EAAiBG,EAAgBD,CAAY,CACzD,CAEA,MAAM,IAAIF,EACR,uBAAuBzE,EAAS,SAAW2E,CAC7C,CACF,CUjRO,IAAME,EAAN,KAAqC,CAC1CC,GAEA,aAAc,CACZ,KAAKA,GAAS,IAAI,GACpB,CAEA,IAAI/E,EAAqC,CACvC,MAAM,IAAI,MAAM,4CAA4C,CAC9D,CAEA,OAAOgF,EAAwC,CAC7C,MAAM,IAAI,MAAM,4CAA4C,CAC9D,CAEA,SACEhF,EACAJ,EAC8B,CAC9B,MAAM,IAAI,MAAM,8CAA8C,CAChE,CAEA,MAAM,IAAII,EAAkBC,EAAoB,CAC9C,GAAID,EAAQ,SAAW,MACrB,MAAM,IAAI,UAAU,2CAA2C,EAGjE,GAAIC,EAAS,SAAW,IACtB,MAAM,IAAI,UACR,iEACF,EAGF,GAAIA,EAAS,QAAQ,IAAI,MAAM,GAAG,SAAS,GAAG,EAC5C,MAAM,IAAI,UAAU,8CAA8C,EAGpE,KAAK8E,GAAO,IAAI/E,EAAQ,IAAK,CAC3B,KAAM,IAAI,WAAW,MAAMC,EAAS,YAAY,CAAC,EACjD,OAAQA,EAAS,OACjB,QAAS,CAAC,GAAGA,EAAS,OAAO,EAC7B,UAAW,KAAK,IAAI,CACtB,CAAC,CACH,CAEA,MAAM,MAAMD,EAAkB,CAC5B,GAAIA,EAAQ,SAAW,MAAO,OAE9B,IAAMiF,EAAQ,KAAKF,GAAO,IAAI/E,EAAQ,GAAG,EAEzC,GAAI,CAACiF,EACH,OAGF,GAAM,CAAC,KAAA/D,EAAM,UAAAgE,KAAcC,CAAQ,EAAIF,EAEjCd,EAAU,IAAI,QAAQgB,EAAS,OAAO,EACtChG,EACJgF,EAAQ,IAAI,eAAe,GAAKA,EAAQ,IAAI,oBAAoB,GAAK,GACjEiB,EAAS,SACbjG,EAAa,MAAM,eAAe,IAAI,IAAM,IAC5C,EACF,EACMkG,EAAM,SACVlG,EAAa,MAAM,8BAA8B,IAAI,IAAM,IAC3D,EACF,EACMmG,GAAO,KAAK,IAAI,EAAIJ,GAAa,IAIvC,GAFeI,EAAMF,EAASC,EAElB,CACV,KAAKN,GAAO,OAAO/E,EAAQ,GAAG,EAC9B,MACF,CAEA,IAAMK,EAAUiF,EAAMF,EAEtB,OAAAjB,EAAQ,IAAI,QAAS9D,EAAU,QAAU,KAAK,EAC9C8D,EAAQ,IAAI,OAAQ,IAAI,KAAKe,CAAS,EAAE,YAAY,CAAC,EAE9C,IAAI,SAAShE,EAAM,CACxB,OAAQiE,EAAS,QAAU,IAC3B,QAAAhB,CACF,CAAC,CACH,CAEA,MAAM,OAAOnE,EAAkB,CAC7B,OAAI,KAAK+E,GAAO,IAAI/E,EAAQ,GAAG,GAC7B,KAAK+E,GAAO,OAAO/E,EAAQ,GAAG,EACvB,IAEF,EACT,CAEA,KAAKA,EAAmB,CACtB,IAAMuF,EAAY,CAAC,EAEnB,QAAWzE,KAAO,KAAKiE,GAAO,KAAK,GAC7B,CAAC/E,GAAWA,EAAQ,MAAQc,IAC9ByE,EAAU,KAAK,IAAI,QAAQzE,CAAG,CAAC,EAInC,OAAO,QAAQ,QAAQyE,CAAS,CAClC,CACF,ECvHA,OAAQ,YAAAC,OAAe,4BAkBvB,eAAsBC,GAAmB,CACvC,WAAAC,EACA,QAAA1F,EACA,SAAAC,EAAW,IAAI,SAAS,YAAa,CAAC,OAAQ,GAAG,CAAC,CACpD,EAA0C,CACxC,GAAM,CAAC,SAAA0F,EAAU,OAAAC,CAAM,EAAI,IAAI,IAAI5F,EAAQ,GAAG,EACxC6F,EAAeF,EAAWC,EAEhC,GAAI,CACF,GAAM,CAAC,aAAAE,CAAY,EAAI,MAAMJ,EAAW,MAErCK,GAAgB,CACjB,UAAW,CAAC,MAAO,QAAUF,CAAY,EACzC,qBAAsB,SACxB,CAAC,EAEKG,EAAWF,GAAc,QAAQ,IAAI,MAAM,OAEjD,GAAIE,EACF,OAAO,IAAI,SAAS,KAAM,CAAC,OAAQ,IAAK,QAAS,CAAC,SAAAA,CAAQ,CAAC,CAAC,EAG9D,IAAMC,EAAe,IAAI,gBAAgBL,CAAM,EACzCM,EACJD,EAAa,IAAI,WAAW,GAAKA,EAAa,IAAI,UAAU,EAE9D,GAAIC,EAAY,CACd,GAAIC,GAAYD,CAAU,EACxB,OAAOV,GAASU,CAAU,EAE1B,QAAQ,KACN,oEAAoEL,QAAmBK,GACzF,CAEJ,CACF,OAAShE,EAAP,CACA,QAAQ,MACN,2DAA2D2D,IAC3D3D,CACF,CACF,CAEA,OAAOjC,CACT,CAEA,SAASkG,GAAYrF,EAAa,CAChC,GAAI,CAMF,IAAI,IAAIA,CAAG,CACb,MAAE,CACA,MAAO,EACT,CAEA,MAAO,EACT,CAEA,IAAMiF,GAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EC3EhB,SAASK,GACd,CAAC,QAAAC,CAAO,EAAI,CAAC,EAGb,CACA,GAAI,CAACA,GAAS,WACZ,MAAM,IAAI,MACR,gFACF,EAGF,IAAMvF,EAAMuF,EAAQ,WAAW,UAAU,EACnCC,EACJD,EAAQ,WAAW,sBAAsB,EACvC,qCAGJ,OAAO,IAAI,SACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAeevF;AAAA;AAAA;AAAA;AAAA;AAAA,kDAK+BwF;AAAA;AAAA;AAAA;AAAA,qBAI7BxF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQjB,CAAC,OAAQ,IAAK,QAAS,CAAC,eAAgB,WAAW,CAAC,CACtD,CACF","sourcesContent":["import {\n createStorefrontClient as createStorefrontUtilities,\n type StorefrontApiResponseOk,\n} from '@shopify/hydrogen-react';\nimport type {ExecutionArgs} from 'graphql';\nimport {fetchWithServerCache, checkGraphQLErrors} from './cache/fetch';\nimport {\n STOREFRONT_API_BUYER_IP_HEADER,\n STOREFRONT_REQUEST_GROUP_ID_HEADER,\n} 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';\n\ntype StorefrontApiResponse<T> = StorefrontApiResponseOk<T>;\n\nexport type StorefrontClient = ReturnType<typeof createStorefrontClient>;\nexport type Storefront = StorefrontClient['storefront'];\n\nexport type CreateStorefrontClientOptions = Parameters<\n typeof createStorefrontUtilities\n>[0] & {\n cache?: Cache;\n buyerIp?: string;\n requestGroupId?: string;\n waitUntil?: ExecutionContext['waitUntil'];\n i18n?: {\n language: LanguageCode;\n country: CountryCode;\n pathPrefix?: string;\n };\n};\n\ntype StorefrontCommonOptions = {\n variables?: ExecutionArgs['variableValues'] & {\n country?: CountryCode;\n language?: LanguageCode;\n };\n headers?: HeadersInit;\n storefrontApiVersion?: string;\n};\n\nexport type StorefrontQueryOptions = StorefrontCommonOptions & {\n query: string;\n mutation?: never;\n cache?: CachingStrategy;\n};\n\nexport type StorefrontMutationOptions = StorefrontCommonOptions & {\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\nexport function createStorefrontClient({\n cache,\n waitUntil,\n buyerIp,\n i18n = {language: 'EN', country: 'US'},\n requestGroupId = generateUUID(),\n ...clientOptions\n}: CreateStorefrontClientOptions) {\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 clientOptions.storeDomain = clientOptions.storeDomain.replace(\n '.myshopify.com',\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({contentType: 'json'});\n\n defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = requestGroupId;\n if (buyerIp) defaultHeaders[STOREFRONT_API_BUYER_IP_HEADER] = buyerIp;\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 = {\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: <T>(\n query: string,\n payload?: StorefrontCommonOptions & {cache?: CachingStrategy},\n ) => {\n query = minifyQuery(query);\n if (isMutationRE.test(query))\n throw new Error('storefront.query cannot execute mutations');\n\n return fetchStorefrontApi<T>({...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: <T>(mutation: string, payload?: StorefrontCommonOptions) => {\n mutation = minifyQuery(mutation);\n if (isQueryRE.test(mutation))\n throw new Error('storefront.mutate cannot execute queries');\n\n return fetchStorefrontApi<T>({...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 // Add default value for pathPefix.\n i18n: {pathPrefix: '', ...i18n},\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","export interface AllCacheOptions {\n mode?: string;\n maxAge?: number;\n staleWhileRevalidate?: number;\n sMaxAge?: number;\n staleIfError?: number;\n}\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","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 {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 return [await response.json(), response];\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\nexport type FetchCacheOptions = {\n cache?: CachingStrategy;\n cacheInstance?: Cache;\n cacheKey?: string | readonly unknown[];\n shouldCacheResponse?: (body: any, response: Response) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n returnType?: 'json' | 'text' | 'arrayBuffer' | 'blob';\n};\n\nfunction serializeResponse(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 ];\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\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 const doFetch = 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 [data, response] as const;\n };\n\n if (!cacheInstance || !cacheKey || !cacheOptions) return doFetch();\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 [cachedValue, 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 [body, response] = await doFetch();\n\n if (shouldCacheResponse(body, response)) {\n await setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\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 const [body, init] = cachedValue;\n return [body, new Response(body, init)];\n }\n\n const [body, response] = await doFetch();\n\n /**\n * Important: Do this async\n */\n if (shouldCacheResponse(body, response)) {\n const setItemInCachePromise = setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\n\n waitUntil?.(setItemInCachePromise);\n }\n\n return [body, response];\n}\n","export const STOREFRONT_REQUEST_GROUP_ID_HEADER =\n 'Custom-Storefront-Request-Group-ID';\nexport const STOREFRONT_API_BUYER_IP_HEADER = 'Shopify-Storefront-Buyer-IP';\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","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","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","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 {Storefront} from '../storefront';\n\ntype StorefrontRedirect = {\n storefront: Storefront;\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 storefront,\n request,\n response = new Response('Not Found', {status: 404}),\n}: StorefrontRedirect): Promise<Response> {\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 storefrontApiVersion: '2023-01',\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 {StorefrontClient} from '../storefront';\n\nexport function graphiqlLoader(\n {context} = {} as LoaderArgs & {\n context: LoaderArgs['context'] & StorefrontClient;\n },\n) {\n if (!context?.storefront) {\n throw new Error(\n `GraphiQL: Hydrogen's storefront client must be injected in the loader context.`,\n );\n }\n\n const url = context.storefront.getApiUrl();\n const accessToken =\n context.storefront.getPublicTokenHeaders()[\n 'X-Shopify-Storefront-Access-Token'\n ];\n\n return new Response(\n `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=utf-8/>\n <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui\">\n <title>Shopify Storefront API</title>\n <link rel=\"stylesheet\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css\" />\n <link rel=\"shortcut icon\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png\" />\n <script src=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js\"></script>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>window.addEventListener('load', function (event) {\n GraphQLPlayground.init(document.getElementById('root'), {\n endpoint: '${url}',\n settings:{\n 'request.globalHeaders': {\n Accept: 'application/json',\n 'Content-Type': 'application/graphql',\n 'X-Shopify-Storefront-Access-Token': '${accessToken}'\n }\n },\n tabs: [{\n endpoint: '${url}',\n query: '{ shop { name } }'\n }]\n })\n })</script>\n</body>\n</html>\n `,\n {status: 200, headers: {'content-type': 'text/html'}},\n );\n}\n"]}
1
+ {"version":3,"sources":["../../src/storefront.ts","../../src/utils/hash.ts","../../src/cache/strategies.ts","../../src/cache/api.ts","../../src/cache/sub-request.ts","../../src/cache/fetch.ts","../../src/constants.ts","../../src/utils/uuid.ts","../../src/utils/parse-json.ts","../../src/utils/warning.ts","../../src/cache/in-memory.ts","../../src/routing/redirect.ts","../../src/routing/graphiql.ts"],"names":["createStorefrontUtilities","hashKey","queryKey","rawKeys","hash","key","PUBLIC","PRIVATE","NO_STORE","optionMapping","generateCacheControlHeader","cacheOptions","cacheControl","CacheNone","guardExpirableModeType","overrideOptions","CacheShort","CacheLong","CacheCustom","getCacheControlSetting","userCacheOptions","options","generateDefaultCacheControlHeader","getItem","cache","request","response","setItem","cacheControlString","deleteItem","isStale","responseDate","responseMaxAge","maxAgeMatch","result","CacheAPI","getKeyUrl","getCacheOption","getItemFromCache","url","setItemInCache","value","serializeResponse","body","checkGraphQLErrors","swrLock","fetchWithServerCache","requestInit","cacheInstance","cacheKey","shouldCacheResponse","waitUntil","returnType","doFetch","data","cachedItem","cachedValue","cacheInfo","revalidatingPromise","error","init","setItemInCachePromise","STOREFRONT_REQUEST_GROUP_ID_HEADER","STOREFRONT_API_BUYER_IP_HEADER","generateUUID","parseJSON","json","noproto","k","v","warnings","warnOnce","string","StorefrontApiError","isStorefrontApiError","isQueryRE","isMutationRE","minifyQuery","createStorefrontClient","buyerIp","i18n","requestGroupId","clientOptions","getPublicTokenHeaders","getPrivateTokenHeaders","getStorefrontApiUrl","getShopifyDomain","defaultHeaders","fetchStorefrontApi","query","mutation","variables","headers","storefrontApiVersion","userHeaders","queryVariables","errors","throwError","payload","ErrorConstructor","reqId","reqIdMessage","errorMessages","InMemoryCache","#store","requests","match","timestamp","metadata","maxAge","swr","age","cacheKeys","redirect","storefrontRedirect","storefront","pathname","search","redirectFrom","urlRedirects","REDIRECT_QUERY","location","searchParams","redirectTo","isLocalPath","graphiqlLoader","context","accessToken"],"mappings":"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","sourcesContent":["import {\n createStorefrontClient as createStorefrontUtilities,\n type StorefrontApiResponseOk,\n} from '@shopify/storefront-kit-react';\nimport type {ExecutionArgs} from 'graphql';\nimport {fetchWithServerCache, checkGraphQLErrors} from './cache/fetch';\nimport {\n STOREFRONT_API_BUYER_IP_HEADER,\n STOREFRONT_REQUEST_GROUP_ID_HEADER,\n} 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/storefront-kit-react/storefront-api-types';\nimport {warnOnce} from './utils/warning';\n\ntype StorefrontApiResponse<T> = StorefrontApiResponseOk<T>;\n\nexport type StorefrontClient = ReturnType<typeof createStorefrontClient>;\nexport type Storefront = StorefrontClient['storefront'];\n\nexport type CreateStorefrontClientOptions = Parameters<\n typeof createStorefrontUtilities\n>[0] & {\n cache?: Cache;\n buyerIp?: string;\n requestGroupId?: string;\n waitUntil?: ExecutionContext['waitUntil'];\n i18n?: {\n language: LanguageCode;\n country: CountryCode;\n pathPrefix?: string;\n };\n};\n\ntype StorefrontCommonOptions = {\n variables?: ExecutionArgs['variableValues'] & {\n country?: CountryCode;\n language?: LanguageCode;\n };\n headers?: HeadersInit;\n storefrontApiVersion?: string;\n};\n\nexport type StorefrontQueryOptions = StorefrontCommonOptions & {\n query: string;\n mutation?: never;\n cache?: CachingStrategy;\n};\n\nexport type StorefrontMutationOptions = StorefrontCommonOptions & {\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\nexport function createStorefrontClient({\n cache,\n waitUntil,\n buyerIp,\n i18n = {language: 'EN', country: 'US'},\n requestGroupId = generateUUID(),\n ...clientOptions\n}: CreateStorefrontClientOptions) {\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({contentType: 'json'});\n\n defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = requestGroupId;\n if (buyerIp) defaultHeaders[STOREFRONT_API_BUYER_IP_HEADER] = buyerIp;\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 = {\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: <T>(\n query: string,\n payload?: StorefrontCommonOptions & {cache?: CachingStrategy},\n ) => {\n query = minifyQuery(query);\n if (isMutationRE.test(query))\n throw new Error('storefront.query cannot execute mutations');\n\n return fetchStorefrontApi<T>({...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: <T>(mutation: string, payload?: StorefrontCommonOptions) => {\n mutation = minifyQuery(mutation);\n if (isQueryRE.test(mutation))\n throw new Error('storefront.mutate cannot execute queries');\n\n return fetchStorefrontApi<T>({...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 // Add default value for pathPefix.\n i18n: {pathPrefix: '', ...i18n},\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","export interface AllCacheOptions {\n mode?: string;\n maxAge?: number;\n staleWhileRevalidate?: number;\n sMaxAge?: number;\n staleIfError?: number;\n}\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","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 {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 return [await response.json(), response];\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\nexport type FetchCacheOptions = {\n cache?: CachingStrategy;\n cacheInstance?: Cache;\n cacheKey?: string | readonly unknown[];\n shouldCacheResponse?: (body: any, response: Response) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n returnType?: 'json' | 'text' | 'arrayBuffer' | 'blob';\n};\n\nfunction serializeResponse(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 ];\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\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 const doFetch = 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 [data, response] as const;\n };\n\n if (!cacheInstance || !cacheKey || !cacheOptions) return doFetch();\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 [cachedValue, 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 [body, response] = await doFetch();\n\n if (shouldCacheResponse(body, response)) {\n await setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\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 const [body, init] = cachedValue;\n return [body, new Response(body, init)];\n }\n\n const [body, response] = await doFetch();\n\n /**\n * Important: Do this async\n */\n if (shouldCacheResponse(body, response)) {\n const setItemInCachePromise = setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\n\n waitUntil?.(setItemInCachePromise);\n }\n\n return [body, response];\n}\n","export const STOREFRONT_REQUEST_GROUP_ID_HEADER =\n 'Custom-Storefront-Request-Group-ID';\nexport const STOREFRONT_API_BUYER_IP_HEADER = 'Shopify-Storefront-Buyer-IP';\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","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","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","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/storefront-kit-react/storefront-api-types';\nimport type {Storefront} from '../storefront';\n\ntype StorefrontRedirect = {\n storefront: Storefront;\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 storefront,\n request,\n response = new Response('Not Found', {status: 404}),\n}: StorefrontRedirect): Promise<Response> {\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 storefrontApiVersion: '2023-01',\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 {StorefrontClient} from '../storefront';\n\nexport function graphiqlLoader(\n {context} = {} as LoaderArgs & {\n context: LoaderArgs['context'] & StorefrontClient;\n },\n) {\n if (!context?.storefront) {\n throw new Error(\n `GraphiQL: Hydrogen's storefront client must be injected in the loader context.`,\n );\n }\n\n const url = context.storefront.getApiUrl();\n const accessToken =\n context.storefront.getPublicTokenHeaders()[\n 'X-Shopify-Storefront-Access-Token'\n ];\n\n return new Response(\n `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=utf-8/>\n <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui\">\n <title>Shopify Storefront API</title>\n <link rel=\"stylesheet\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css\" />\n <link rel=\"shortcut icon\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png\" />\n <script src=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js\"></script>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>window.addEventListener('load', function (event) {\n GraphQLPlayground.init(document.getElementById('root'), {\n endpoint: '${url}',\n settings:{\n 'request.globalHeaders': {\n Accept: 'application/json',\n 'Content-Type': 'application/graphql',\n 'X-Shopify-Storefront-Access-Token': '${accessToken}'\n }\n },\n tabs: [{\n endpoint: '${url}',\n query: '{ shop { name } }'\n }]\n })\n })</script>\n</body>\n</html>\n `,\n {status: 200, headers: {'content-type': 'text/html'}},\n );\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { createStorefrontClient as createStorefrontClient$1 } from '@shopify/hydrogen-react';
1
+ import { createStorefrontClient as createStorefrontClient$1 } from '@shopify/storefront-kit-react';
2
2
  import { ExecutionArgs } from 'graphql';
3
- import { LanguageCode, CountryCode } from '@shopify/hydrogen-react/storefront-api-types';
3
+ import { LanguageCode, CountryCode } from '@shopify/storefront-kit-react/storefront-api-types';
4
4
  import * as _remix_run_server_runtime from '@remix-run/server-runtime';
5
5
  import { LoaderArgs } from '@remix-run/server-runtime';
6
6
 
@@ -1,7 +1,7 @@
1
- import { createStorefrontClient } from '@shopify/hydrogen-react';
1
+ import { createStorefrontClient } from '@shopify/storefront-kit-react';
2
2
  import { redirect } from '@remix-run/server-runtime';
3
3
 
4
- function k(e){let t=Array.isArray(e)?e:[e],r="";for(let o of t)o!=null&&(typeof o=="object"?!!o.body&&typeof o.body=="string"?r+=o.body:r+=JSON.stringify(o):r+=o);return r}var P="public",ne="private",se="no-store",N={maxAge:"max-age",staleWhileRevalidate:"stale-while-revalidate",sMaxAge:"s-maxage",staleIfError:"stale-if-error"};function S(e){let t=[];return Object.keys(e).forEach(r=>{r==="mode"?t.push(e[r]):N[r]&&t.push(`${N[r]}=${e[r]}`);}),t.join(", ")}function q(){return {mode:se}}function $(e){if(e?.mode&&e?.mode!==P&&e?.mode!==ne)throw Error("'mode' must be either 'public' or 'private'")}function f(e){return $(e),{mode:P,maxAge:1,staleWhileRevalidate:9,...e}}function U(e){return $(e),{mode:P,maxAge:3600,staleWhileRevalidate:82800,...e}}function O(e){return e}function w(e,t){return e&&t?{...e,...t}:e||f()}function v(e){return S(w(e))}async function ae(e,t){if(!e)return;let r=await e.match(t);if(!r){t.url;return}return t.url,r}async function ie(e,t,r,o){if(!e)return;let n=w(o);t.headers.set("cache-control",v(w(n,{maxAge:(n.maxAge||0)+(n.staleWhileRevalidate||0)})));let a=v(w(n));r.headers.set("cache-control",a),r.headers.set("real-cache-control",a),r.headers.set("cache-put-date",new Date().toUTCString()),t.url,await e.put(t,r);}async function ce(e,t){!e||(t.url,await e.delete(t));}function ue(e,t){let r=t.headers.get("cache-put-date"),o=t.headers.get("real-cache-control"),n=0;if(o){let c=o.match(/max-age=(\d*)/);c&&c.length>1&&(n=parseFloat(c[1]));}if(!r)return !1;let p=(new Date().valueOf()-new Date(r).valueOf())/1e3>n;return p&&(e.url,void 0),p}var x={get:ae,set:ie,delete:ce,generateDefaultCacheControlHeader:v,isStale:ue};function _(e){return `https://shopify.dev/?${e}`}function pe(e){return e||f()}async function j(e,t){if(!e)return;let r=_(t),o=new Request(r),n=await x.get(e,o);if(!!n)return [await n.json(),n]}async function D(e,t,r,o){if(!e)return;let n=_(t),a=new Request(n),i=new Response(JSON.stringify(r));await x.set(e,a,i,pe(o));}function F(e,t){return x.isStale(new Request(_(e)),t)}function Q(e,t){return [e,{status:t.status,statusText:t.statusText,headers:Array.from(t.headers.entries())}]}var G=e=>!e?.errors,H=new Set;async function W(e,t,{cacheInstance:r,cache:o,cacheKey:n=[e,t],shouldCacheResponse:a=()=>!0,waitUntil:i,returnType:p="json"}={}){!o&&(!t.method||t.method==="GET")&&(o=f());let c=async()=>{let s=await fetch(e,t),l;try{l=await s[p]();}catch{l=await s.text();}return [l,s]};if(!r||!n||!o)return c();let u=k([...typeof n=="string"?[n]:n]),y=await j(r,u);if(y){let[s,l]=y;if(!H.has(u)&&F(u,l)){H.add(u);let m=Promise.resolve().then(async()=>{try{let[h,R]=await c();a(h,R)&&await D(r,u,Q(h,R),o);}catch(h){h.message&&(h.message="SWR in sub-request failed: "+h.message),console.error(h);}finally{H.delete(u);}});i?.(m);}let[C,A]=s;return [C,new Response(C,A)]}let[g,d]=await c();if(a(g,d)){let s=D(r,u,Q(g,d),o);i?.(s);}return [g,d]}var B="Custom-Storefront-Request-Group-ID",J="Shopify-Storefront-Buyer-IP";function V(){return typeof crypto<"u"&&!!crypto.randomUUID?crypto.randomUUID():`weak-${Math.random().toString(16).substring(2)}`}function Y(e){return String(e).includes("__proto__")?JSON.parse(e,le):JSON.parse(e)}function le(e,t){if(e!=="__proto__")return t}var K=new Set,X=e=>{K.has(e)||(console.warn(e),K.add(e));};var ee=class extends Error{},he=e=>e instanceof ee,ge=/(^|}\s)query[\s({]/im,de=/(^|}\s)mutation[\s({]/im;function z(e){return e.replace(/\s*#.*$/gm,"").replace(/\s+/gm," ").trim()}function We({cache:e,waitUntil:t,buyerIp:r,i18n:o={language:"EN",country:"US"},requestGroupId:n=V(),...a}){e||X("Storefront API client created without a cache instance. This may slow down your sub-requests."),a.storeDomain=a.storeDomain.replace(".myshopify.com","");let{getPublicTokenHeaders:i,getPrivateTokenHeaders:p,getStorefrontApiUrl:c,getShopifyDomain:u}=createStorefrontClient(a),g=(a.privateStorefrontToken?p:i)({contentType:"json"});g[B]=n,r&&(g[J]=r);async function d({query:s,mutation:l,variables:C,cache:A,headers:m=[],storefrontApiVersion:h}){let R=m instanceof Headers?Object.fromEntries(m.entries()):Array.isArray(m)?Object.fromEntries(m):m;s=s??l;let E={...C};o&&(!C?.country&&/\$country/.test(s)&&(E.country=o.country),!C?.language&&/\$language/.test(s)&&(E.language=o.language));let te=c({storefrontApiVersion:h}),re={method:"POST",headers:{...g,...R},body:JSON.stringify({query:s,variables:E})},[T,I]=await W(te,re,{cacheInstance:l?void 0:e,cache:A||f(),shouldCacheResponse:G,waitUntil:t});if(!I.ok){let b;try{b=Y(T);}catch{b=[{message:T}];}Z(I,b);}let{data:oe,errors:M}=T;return M?.length&&Z(I,M,ee),oe}return {storefront:{query:(s,l)=>{if(s=z(s),de.test(s))throw new Error("storefront.query cannot execute mutations");return d({...l,query:s})},mutate:(s,l)=>{if(s=z(s),ge.test(s))throw new Error("storefront.mutate cannot execute queries");return d({...l,mutation:s})},cache:e,CacheNone:q,CacheLong:U,CacheShort:f,CacheCustom:O,generateCacheControlHeader:S,getPublicTokenHeaders:i,getPrivateTokenHeaders:p,getShopifyDomain:u,getApiUrl:c,isApiError:he,i18n:{pathPrefix:"",...o}}}}function Z(e,t,r=Error){let o=e.headers.get("x-request-id"),n=o?` - Request ID: ${o}`:"";if(t){let a=typeof t=="string"?t:t.map(i=>i.message).join(`
4
+ function k(e){let t=Array.isArray(e)?e:[e],r="";for(let o of t)o!=null&&(typeof o=="object"?!!o.body&&typeof o.body=="string"?r+=o.body:r+=JSON.stringify(o):r+=o);return r}var P="public",ne="private",se="no-store",N={maxAge:"max-age",staleWhileRevalidate:"stale-while-revalidate",sMaxAge:"s-maxage",staleIfError:"stale-if-error"};function S(e){let t=[];return Object.keys(e).forEach(r=>{r==="mode"?t.push(e[r]):N[r]&&t.push(`${N[r]}=${e[r]}`);}),t.join(", ")}function q(){return {mode:se}}function $(e){if(e?.mode&&e?.mode!==P&&e?.mode!==ne)throw Error("'mode' must be either 'public' or 'private'")}function f(e){return $(e),{mode:P,maxAge:1,staleWhileRevalidate:9,...e}}function O(e){return $(e),{mode:P,maxAge:3600,staleWhileRevalidate:82800,...e}}function U(e){return e}function w(e,t){return e&&t?{...e,...t}:e||f()}function v(e){return S(w(e))}async function ae(e,t){if(!e)return;let r=await e.match(t);if(!r){t.url;return}return t.url,r}async function ie(e,t,r,o){if(!e)return;let n=w(o);t.headers.set("cache-control",v(w(n,{maxAge:(n.maxAge||0)+(n.staleWhileRevalidate||0)})));let a=v(w(n));r.headers.set("cache-control",a),r.headers.set("real-cache-control",a),r.headers.set("cache-put-date",new Date().toUTCString()),t.url,await e.put(t,r);}async function ce(e,t){!e||(t.url,await e.delete(t));}function ue(e,t){let r=t.headers.get("cache-put-date"),o=t.headers.get("real-cache-control"),n=0;if(o){let c=o.match(/max-age=(\d*)/);c&&c.length>1&&(n=parseFloat(c[1]));}if(!r)return !1;let p=(new Date().valueOf()-new Date(r).valueOf())/1e3>n;return p&&(e.url,void 0),p}var x={get:ae,set:ie,delete:ce,generateDefaultCacheControlHeader:v,isStale:ue};function _(e){return `https://shopify.dev/?${e}`}function pe(e){return e||f()}async function j(e,t){if(!e)return;let r=_(t),o=new Request(r),n=await x.get(e,o);if(!!n)return [await n.json(),n]}async function D(e,t,r,o){if(!e)return;let n=_(t),a=new Request(n),i=new Response(JSON.stringify(r));await x.set(e,a,i,pe(o));}function F(e,t){return x.isStale(new Request(_(e)),t)}function Q(e,t){return [e,{status:t.status,statusText:t.statusText,headers:Array.from(t.headers.entries())}]}var G=e=>!e?.errors,H=new Set;async function W(e,t,{cacheInstance:r,cache:o,cacheKey:n=[e,t],shouldCacheResponse:a=()=>!0,waitUntil:i,returnType:p="json"}={}){!o&&(!t.method||t.method==="GET")&&(o=f());let c=async()=>{let s=await fetch(e,t),l;try{l=await s[p]();}catch{l=await s.text();}return [l,s]};if(!r||!n||!o)return c();let u=k([...typeof n=="string"?[n]:n]),y=await j(r,u);if(y){let[s,l]=y;if(!H.has(u)&&F(u,l)){H.add(u);let m=Promise.resolve().then(async()=>{try{let[h,R]=await c();a(h,R)&&await D(r,u,Q(h,R),o);}catch(h){h.message&&(h.message="SWR in sub-request failed: "+h.message),console.error(h);}finally{H.delete(u);}});i?.(m);}let[C,A]=s;return [C,new Response(C,A)]}let[g,d]=await c();if(a(g,d)){let s=D(r,u,Q(g,d),o);i?.(s);}return [g,d]}var B="Custom-Storefront-Request-Group-ID",J="Shopify-Storefront-Buyer-IP";function V(){return typeof crypto<"u"&&!!crypto.randomUUID?crypto.randomUUID():`weak-${Math.random().toString(16).substring(2)}`}function Y(e){return String(e).includes("__proto__")?JSON.parse(e,le):JSON.parse(e)}function le(e,t){if(e!=="__proto__")return t}var K=new Set,X=e=>{K.has(e)||(console.warn(e),K.add(e));};var ee=class extends Error{},he=e=>e instanceof ee,ge=/(^|}\s)query[\s({]/im,de=/(^|}\s)mutation[\s({]/im;function z(e){return e.replace(/\s*#.*$/gm,"").replace(/\s+/gm," ").trim()}function We({cache:e,waitUntil:t,buyerIp:r,i18n:o={language:"EN",country:"US"},requestGroupId:n=V(),...a}){e||X("Storefront API client created without a cache instance. This may slow down your sub-requests.");let{getPublicTokenHeaders:i,getPrivateTokenHeaders:p,getStorefrontApiUrl:c,getShopifyDomain:u}=createStorefrontClient(a),g=(a.privateStorefrontToken?p:i)({contentType:"json"});g[B]=n,r&&(g[J]=r);async function d({query:s,mutation:l,variables:C,cache:A,headers:m=[],storefrontApiVersion:h}){let R=m instanceof Headers?Object.fromEntries(m.entries()):Array.isArray(m)?Object.fromEntries(m):m;s=s??l;let E={...C};o&&(!C?.country&&/\$country/.test(s)&&(E.country=o.country),!C?.language&&/\$language/.test(s)&&(E.language=o.language));let te=c({storefrontApiVersion:h}),re={method:"POST",headers:{...g,...R},body:JSON.stringify({query:s,variables:E})},[T,I]=await W(te,re,{cacheInstance:l?void 0:e,cache:A||f(),shouldCacheResponse:G,waitUntil:t});if(!I.ok){let b;try{b=Y(T);}catch{b=[{message:T}];}Z(I,b);}let{data:oe,errors:M}=T;return M?.length&&Z(I,M,ee),oe}return {storefront:{query:(s,l)=>{if(s=z(s),de.test(s))throw new Error("storefront.query cannot execute mutations");return d({...l,query:s})},mutate:(s,l)=>{if(s=z(s),ge.test(s))throw new Error("storefront.mutate cannot execute queries");return d({...l,mutation:s})},cache:e,CacheNone:q,CacheLong:O,CacheShort:f,CacheCustom:U,generateCacheControlHeader:S,getPublicTokenHeaders:i,getPrivateTokenHeaders:p,getShopifyDomain:u,getApiUrl:c,isApiError:he,i18n:{pathPrefix:"",...o}}}}function Z(e,t,r=Error){let o=e.headers.get("x-request-id"),n=o?` - Request ID: ${o}`:"";if(t){let a=typeof t=="string"?t:t.map(i=>i.message).join(`
5
5
  `);throw new r(a+n)}throw new r(`API response error: ${e.status}`+n)}var L=class{#e;constructor(){this.#e=new Map;}add(t){throw new Error("Method not implemented. Use `put` instead.")}addAll(t){throw new Error("Method not implemented. Use `put` instead.")}matchAll(t,r){throw new Error("Method not implemented. Use `match` instead.")}async put(t,r){if(t.method!=="GET")throw new TypeError("Cannot cache response to non-GET request.");if(r.status===206)throw new TypeError("Cannot cache response to a range request (206 Partial Content).");if(r.headers.get("vary")?.includes("*"))throw new TypeError("Cannot cache response with 'Vary: *' header.");this.#e.set(t.url,{body:new Uint8Array(await r.arrayBuffer()),status:r.status,headers:[...r.headers],timestamp:Date.now()});}async match(t){if(t.method!=="GET")return;let r=this.#e.get(t.url);if(!r)return;let{body:o,timestamp:n,...a}=r,i=new Headers(a.headers),p=i.get("cache-control")||i.get("real-cache-control")||"",c=parseInt(p.match(/max-age=(\d+)/)?.[1]||"0",10),u=parseInt(p.match(/stale-while-revalidate=(\d+)/)?.[1]||"0",10),y=(Date.now()-n)/1e3;if(y>c+u){this.#e.delete(t.url);return}let d=y>c;return i.set("cache",d?"STALE":"HIT"),i.set("date",new Date(n).toUTCString()),new Response(o,{status:a.status??200,headers:i})}async delete(t){return this.#e.has(t.url)?(this.#e.delete(t.url),!0):!1}keys(t){let r=[];for(let o of this.#e.keys())(!t||t.url===o)&&r.push(new Request(o));return Promise.resolve(r)}};async function ye({storefront:e,request:t,response:r=new Response("Not Found",{status:404})}){let{pathname:o,search:n}=new URL(t.url),a=o+n;try{let{urlRedirects:i}=await e.query(Se,{variables:{query:"path:"+a},storefrontApiVersion:"2023-01"}),p=i?.edges?.[0]?.node?.target;if(p)return new Response(null,{status:302,headers:{location:p}});let c=new URLSearchParams(n),u=c.get("return_to")||c.get("redirect");if(u){if(Ce(u))return redirect(u);console.warn(`Cross-domain redirects are not supported. Tried to redirect from ${a} to ${u}`);}}catch(i){console.error(`Failed to fetch redirects from Storefront API for route ${a}`,i);}return r}function Ce(e){try{new URL(e);}catch{return !0}return !1}var Se=`#graphql
6
6
  query redirects($query: String) {
7
7
  urlRedirects(first: 1, query: $query) {
@@ -45,6 +45,6 @@ function k(e){let t=Array.isArray(e)?e:[e],r="";for(let o of t)o!=null&&(typeof
45
45
  </html>
46
46
  `,{status:200,headers:{"content-type":"text/html"}})}
47
47
 
48
- export { O as CacheCustom, U as CacheLong, q as CacheNone, f as CacheShort, L as InMemoryCache, We as createStorefrontClient, S as generateCacheControlHeader, Re as graphiqlLoader, he as isStorefrontApiError, ye as storefrontRedirect };
48
+ export { U as CacheCustom, O as CacheLong, q as CacheNone, f as CacheShort, L as InMemoryCache, We as createStorefrontClient, S as generateCacheControlHeader, Re as graphiqlLoader, he as isStorefrontApiError, ye as storefrontRedirect };
49
49
  //# sourceMappingURL=out.js.map
50
50
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/storefront.ts","../../src/utils/hash.ts","../../src/cache/strategies.ts","../../src/cache/api.ts","../../src/cache/sub-request.ts","../../src/cache/fetch.ts","../../src/constants.ts","../../src/utils/uuid.ts","../../src/utils/parse-json.ts","../../src/utils/warning.ts","../../src/cache/in-memory.ts","../../src/routing/redirect.ts","../../src/routing/graphiql.ts"],"names":["createStorefrontUtilities","hashKey","queryKey","rawKeys","hash","key","PUBLIC","PRIVATE","NO_STORE","optionMapping","generateCacheControlHeader","cacheOptions","cacheControl","CacheNone","guardExpirableModeType","overrideOptions","CacheShort","CacheLong","CacheCustom","getCacheControlSetting","userCacheOptions","options","generateDefaultCacheControlHeader","getItem","cache","request","response","setItem","cacheControlString","deleteItem","isStale","responseDate","responseMaxAge","maxAgeMatch","result","CacheAPI","getKeyUrl","getCacheOption","getItemFromCache","url","setItemInCache","value","serializeResponse","body","checkGraphQLErrors","swrLock","fetchWithServerCache","requestInit","cacheInstance","cacheKey","shouldCacheResponse","waitUntil","returnType","doFetch","data","cachedItem","cachedValue","cacheInfo","revalidatingPromise","error","init","setItemInCachePromise","STOREFRONT_REQUEST_GROUP_ID_HEADER","STOREFRONT_API_BUYER_IP_HEADER","generateUUID","parseJSON","json","noproto","k","v","warnings","warnOnce","string","StorefrontApiError","isStorefrontApiError","isQueryRE","isMutationRE","minifyQuery","createStorefrontClient","buyerIp","i18n","requestGroupId","clientOptions","getPublicTokenHeaders","getPrivateTokenHeaders","getStorefrontApiUrl","getShopifyDomain","defaultHeaders","fetchStorefrontApi","query","mutation","variables","headers","storefrontApiVersion","userHeaders","queryVariables","errors","throwError","payload","ErrorConstructor","reqId","reqIdMessage","errorMessages","InMemoryCache","#store","requests","match","timestamp","metadata","maxAge","swr","age","cacheKeys","redirect","storefrontRedirect","storefront","pathname","search","redirectFrom","urlRedirects","REDIRECT_QUERY","location","searchParams","redirectTo","isLocalPath","graphiqlLoader","context","accessToken"],"mappings":"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","sourcesContent":["import {\n createStorefrontClient as createStorefrontUtilities,\n type StorefrontApiResponseOk,\n} from '@shopify/hydrogen-react';\nimport type {ExecutionArgs} from 'graphql';\nimport {fetchWithServerCache, checkGraphQLErrors} from './cache/fetch';\nimport {\n STOREFRONT_API_BUYER_IP_HEADER,\n STOREFRONT_REQUEST_GROUP_ID_HEADER,\n} 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';\n\ntype StorefrontApiResponse<T> = StorefrontApiResponseOk<T>;\n\nexport type StorefrontClient = ReturnType<typeof createStorefrontClient>;\nexport type Storefront = StorefrontClient['storefront'];\n\nexport type CreateStorefrontClientOptions = Parameters<\n typeof createStorefrontUtilities\n>[0] & {\n cache?: Cache;\n buyerIp?: string;\n requestGroupId?: string;\n waitUntil?: ExecutionContext['waitUntil'];\n i18n?: {\n language: LanguageCode;\n country: CountryCode;\n pathPrefix?: string;\n };\n};\n\ntype StorefrontCommonOptions = {\n variables?: ExecutionArgs['variableValues'] & {\n country?: CountryCode;\n language?: LanguageCode;\n };\n headers?: HeadersInit;\n storefrontApiVersion?: string;\n};\n\nexport type StorefrontQueryOptions = StorefrontCommonOptions & {\n query: string;\n mutation?: never;\n cache?: CachingStrategy;\n};\n\nexport type StorefrontMutationOptions = StorefrontCommonOptions & {\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\nexport function createStorefrontClient({\n cache,\n waitUntil,\n buyerIp,\n i18n = {language: 'EN', country: 'US'},\n requestGroupId = generateUUID(),\n ...clientOptions\n}: CreateStorefrontClientOptions) {\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 clientOptions.storeDomain = clientOptions.storeDomain.replace(\n '.myshopify.com',\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({contentType: 'json'});\n\n defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = requestGroupId;\n if (buyerIp) defaultHeaders[STOREFRONT_API_BUYER_IP_HEADER] = buyerIp;\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 = {\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: <T>(\n query: string,\n payload?: StorefrontCommonOptions & {cache?: CachingStrategy},\n ) => {\n query = minifyQuery(query);\n if (isMutationRE.test(query))\n throw new Error('storefront.query cannot execute mutations');\n\n return fetchStorefrontApi<T>({...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: <T>(mutation: string, payload?: StorefrontCommonOptions) => {\n mutation = minifyQuery(mutation);\n if (isQueryRE.test(mutation))\n throw new Error('storefront.mutate cannot execute queries');\n\n return fetchStorefrontApi<T>({...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 // Add default value for pathPefix.\n i18n: {pathPrefix: '', ...i18n},\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","export interface AllCacheOptions {\n mode?: string;\n maxAge?: number;\n staleWhileRevalidate?: number;\n sMaxAge?: number;\n staleIfError?: number;\n}\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","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 {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 return [await response.json(), response];\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\nexport type FetchCacheOptions = {\n cache?: CachingStrategy;\n cacheInstance?: Cache;\n cacheKey?: string | readonly unknown[];\n shouldCacheResponse?: (body: any, response: Response) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n returnType?: 'json' | 'text' | 'arrayBuffer' | 'blob';\n};\n\nfunction serializeResponse(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 ];\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\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 const doFetch = 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 [data, response] as const;\n };\n\n if (!cacheInstance || !cacheKey || !cacheOptions) return doFetch();\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 [cachedValue, 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 [body, response] = await doFetch();\n\n if (shouldCacheResponse(body, response)) {\n await setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\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 const [body, init] = cachedValue;\n return [body, new Response(body, init)];\n }\n\n const [body, response] = await doFetch();\n\n /**\n * Important: Do this async\n */\n if (shouldCacheResponse(body, response)) {\n const setItemInCachePromise = setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\n\n waitUntil?.(setItemInCachePromise);\n }\n\n return [body, response];\n}\n","export const STOREFRONT_REQUEST_GROUP_ID_HEADER =\n 'Custom-Storefront-Request-Group-ID';\nexport const STOREFRONT_API_BUYER_IP_HEADER = 'Shopify-Storefront-Buyer-IP';\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","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","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","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 {Storefront} from '../storefront';\n\ntype StorefrontRedirect = {\n storefront: Storefront;\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 storefront,\n request,\n response = new Response('Not Found', {status: 404}),\n}: StorefrontRedirect): Promise<Response> {\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 storefrontApiVersion: '2023-01',\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 {StorefrontClient} from '../storefront';\n\nexport function graphiqlLoader(\n {context} = {} as LoaderArgs & {\n context: LoaderArgs['context'] & StorefrontClient;\n },\n) {\n if (!context?.storefront) {\n throw new Error(\n `GraphiQL: Hydrogen's storefront client must be injected in the loader context.`,\n );\n }\n\n const url = context.storefront.getApiUrl();\n const accessToken =\n context.storefront.getPublicTokenHeaders()[\n 'X-Shopify-Storefront-Access-Token'\n ];\n\n return new Response(\n `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=utf-8/>\n <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui\">\n <title>Shopify Storefront API</title>\n <link rel=\"stylesheet\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css\" />\n <link rel=\"shortcut icon\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png\" />\n <script src=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js\"></script>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>window.addEventListener('load', function (event) {\n GraphQLPlayground.init(document.getElementById('root'), {\n endpoint: '${url}',\n settings:{\n 'request.globalHeaders': {\n Accept: 'application/json',\n 'Content-Type': 'application/graphql',\n 'X-Shopify-Storefront-Access-Token': '${accessToken}'\n }\n },\n tabs: [{\n endpoint: '${url}',\n query: '{ shop { name } }'\n }]\n })\n })</script>\n</body>\n</html>\n `,\n {status: 200, headers: {'content-type': 'text/html'}},\n );\n}\n"]}
1
+ {"version":3,"sources":["../../src/storefront.ts","../../src/utils/hash.ts","../../src/cache/strategies.ts","../../src/cache/api.ts","../../src/cache/sub-request.ts","../../src/cache/fetch.ts","../../src/constants.ts","../../src/utils/uuid.ts","../../src/utils/parse-json.ts","../../src/utils/warning.ts","../../src/cache/in-memory.ts","../../src/routing/redirect.ts","../../src/routing/graphiql.ts"],"names":["createStorefrontUtilities","hashKey","queryKey","rawKeys","hash","key","PUBLIC","PRIVATE","NO_STORE","optionMapping","generateCacheControlHeader","cacheOptions","cacheControl","CacheNone","guardExpirableModeType","overrideOptions","CacheShort","CacheLong","CacheCustom","getCacheControlSetting","userCacheOptions","options","generateDefaultCacheControlHeader","getItem","cache","request","response","setItem","cacheControlString","deleteItem","isStale","responseDate","responseMaxAge","maxAgeMatch","result","CacheAPI","getKeyUrl","getCacheOption","getItemFromCache","url","setItemInCache","value","serializeResponse","body","checkGraphQLErrors","swrLock","fetchWithServerCache","requestInit","cacheInstance","cacheKey","shouldCacheResponse","waitUntil","returnType","doFetch","data","cachedItem","cachedValue","cacheInfo","revalidatingPromise","error","init","setItemInCachePromise","STOREFRONT_REQUEST_GROUP_ID_HEADER","STOREFRONT_API_BUYER_IP_HEADER","generateUUID","parseJSON","json","noproto","k","v","warnings","warnOnce","string","StorefrontApiError","isStorefrontApiError","isQueryRE","isMutationRE","minifyQuery","createStorefrontClient","buyerIp","i18n","requestGroupId","clientOptions","getPublicTokenHeaders","getPrivateTokenHeaders","getStorefrontApiUrl","getShopifyDomain","defaultHeaders","fetchStorefrontApi","query","mutation","variables","headers","storefrontApiVersion","userHeaders","queryVariables","errors","throwError","payload","ErrorConstructor","reqId","reqIdMessage","errorMessages","InMemoryCache","#store","requests","match","timestamp","metadata","maxAge","swr","age","cacheKeys","redirect","storefrontRedirect","storefront","pathname","search","redirectFrom","urlRedirects","REDIRECT_QUERY","location","searchParams","redirectTo","isLocalPath","graphiqlLoader","context","accessToken"],"mappings":"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","sourcesContent":["import {\n createStorefrontClient as createStorefrontUtilities,\n type StorefrontApiResponseOk,\n} from '@shopify/storefront-kit-react';\nimport type {ExecutionArgs} from 'graphql';\nimport {fetchWithServerCache, checkGraphQLErrors} from './cache/fetch';\nimport {\n STOREFRONT_API_BUYER_IP_HEADER,\n STOREFRONT_REQUEST_GROUP_ID_HEADER,\n} 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/storefront-kit-react/storefront-api-types';\nimport {warnOnce} from './utils/warning';\n\ntype StorefrontApiResponse<T> = StorefrontApiResponseOk<T>;\n\nexport type StorefrontClient = ReturnType<typeof createStorefrontClient>;\nexport type Storefront = StorefrontClient['storefront'];\n\nexport type CreateStorefrontClientOptions = Parameters<\n typeof createStorefrontUtilities\n>[0] & {\n cache?: Cache;\n buyerIp?: string;\n requestGroupId?: string;\n waitUntil?: ExecutionContext['waitUntil'];\n i18n?: {\n language: LanguageCode;\n country: CountryCode;\n pathPrefix?: string;\n };\n};\n\ntype StorefrontCommonOptions = {\n variables?: ExecutionArgs['variableValues'] & {\n country?: CountryCode;\n language?: LanguageCode;\n };\n headers?: HeadersInit;\n storefrontApiVersion?: string;\n};\n\nexport type StorefrontQueryOptions = StorefrontCommonOptions & {\n query: string;\n mutation?: never;\n cache?: CachingStrategy;\n};\n\nexport type StorefrontMutationOptions = StorefrontCommonOptions & {\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\nexport function createStorefrontClient({\n cache,\n waitUntil,\n buyerIp,\n i18n = {language: 'EN', country: 'US'},\n requestGroupId = generateUUID(),\n ...clientOptions\n}: CreateStorefrontClientOptions) {\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({contentType: 'json'});\n\n defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = requestGroupId;\n if (buyerIp) defaultHeaders[STOREFRONT_API_BUYER_IP_HEADER] = buyerIp;\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 = {\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: <T>(\n query: string,\n payload?: StorefrontCommonOptions & {cache?: CachingStrategy},\n ) => {\n query = minifyQuery(query);\n if (isMutationRE.test(query))\n throw new Error('storefront.query cannot execute mutations');\n\n return fetchStorefrontApi<T>({...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: <T>(mutation: string, payload?: StorefrontCommonOptions) => {\n mutation = minifyQuery(mutation);\n if (isQueryRE.test(mutation))\n throw new Error('storefront.mutate cannot execute queries');\n\n return fetchStorefrontApi<T>({...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 // Add default value for pathPefix.\n i18n: {pathPrefix: '', ...i18n},\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","export interface AllCacheOptions {\n mode?: string;\n maxAge?: number;\n staleWhileRevalidate?: number;\n sMaxAge?: number;\n staleIfError?: number;\n}\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","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 {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 return [await response.json(), response];\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\nexport type FetchCacheOptions = {\n cache?: CachingStrategy;\n cacheInstance?: Cache;\n cacheKey?: string | readonly unknown[];\n shouldCacheResponse?: (body: any, response: Response) => boolean;\n waitUntil?: ExecutionContext['waitUntil'];\n returnType?: 'json' | 'text' | 'arrayBuffer' | 'blob';\n};\n\nfunction serializeResponse(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 ];\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\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 const doFetch = 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 [data, response] as const;\n };\n\n if (!cacheInstance || !cacheKey || !cacheOptions) return doFetch();\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 [cachedValue, 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 [body, response] = await doFetch();\n\n if (shouldCacheResponse(body, response)) {\n await setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\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 const [body, init] = cachedValue;\n return [body, new Response(body, init)];\n }\n\n const [body, response] = await doFetch();\n\n /**\n * Important: Do this async\n */\n if (shouldCacheResponse(body, response)) {\n const setItemInCachePromise = setItemInCache(\n cacheInstance,\n key,\n serializeResponse(body, response),\n cacheOptions,\n );\n\n waitUntil?.(setItemInCachePromise);\n }\n\n return [body, response];\n}\n","export const STOREFRONT_REQUEST_GROUP_ID_HEADER =\n 'Custom-Storefront-Request-Group-ID';\nexport const STOREFRONT_API_BUYER_IP_HEADER = 'Shopify-Storefront-Buyer-IP';\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","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","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","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/storefront-kit-react/storefront-api-types';\nimport type {Storefront} from '../storefront';\n\ntype StorefrontRedirect = {\n storefront: Storefront;\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 storefront,\n request,\n response = new Response('Not Found', {status: 404}),\n}: StorefrontRedirect): Promise<Response> {\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 storefrontApiVersion: '2023-01',\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 {StorefrontClient} from '../storefront';\n\nexport function graphiqlLoader(\n {context} = {} as LoaderArgs & {\n context: LoaderArgs['context'] & StorefrontClient;\n },\n) {\n if (!context?.storefront) {\n throw new Error(\n `GraphiQL: Hydrogen's storefront client must be injected in the loader context.`,\n );\n }\n\n const url = context.storefront.getApiUrl();\n const accessToken =\n context.storefront.getPublicTokenHeaders()[\n 'X-Shopify-Storefront-Access-Token'\n ];\n\n return new Response(\n `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=utf-8/>\n <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui\">\n <title>Shopify Storefront API</title>\n <link rel=\"stylesheet\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css\" />\n <link rel=\"shortcut icon\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png\" />\n <script src=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js\"></script>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>window.addEventListener('load', function (event) {\n GraphQLPlayground.init(document.getElementById('root'), {\n endpoint: '${url}',\n settings:{\n 'request.globalHeaders': {\n Accept: 'application/json',\n 'Content-Type': 'application/graphql',\n 'X-Shopify-Storefront-Access-Token': '${accessToken}'\n }\n },\n tabs: [{\n endpoint: '${url}',\n query: '{ shop { name } }'\n }]\n })\n })</script>\n</body>\n</html>\n `,\n {status: 200, headers: {'content-type': 'text/html'}},\n );\n}\n"]}
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "@shopify:registry": "https://registry.npmjs.org"
6
6
  },
7
7
  "type": "module",
8
- "version": "2.0.0-alpha.2",
8
+ "version": "2.0.0-alpha.3",
9
9
  "main": "dist/index.cjs",
10
10
  "module": "dist/production/index.js",
11
11
  "types": "dist/production/index.d.ts",
@@ -45,14 +45,14 @@
45
45
  ],
46
46
  "peerDependencies": {
47
47
  "@remix-run/react": "*",
48
- "@remix-run/server-runtime": "0.0.0-experimental-e18af792a",
49
- "@shopify/hydrogen-react": "*"
48
+ "@remix-run/server-runtime": "1.11.0",
49
+ "@shopify/storefront-kit-react": "*"
50
50
  },
51
51
  "dependencies": {
52
52
  "recursive-readdir": "^2.2.3"
53
53
  },
54
54
  "devDependencies": {
55
- "@shopify/hydrogen-react": "*",
55
+ "@shopify/storefront-kit-react": "*",
56
56
  "@types/recursive-readdir": "^2.2.1"
57
57
  }
58
58
  }