UNPKG

@shopify/hydrogen

Version:
1,199 lines (1,099 loc) • 105 kB
import * as react from 'react'; import { ReactNode, ComponentType, ScriptHTMLAttributes, FC, Ref, ComponentProps } from 'react'; import { BuyerInput, LanguageCode, CountryCode, Cart, CartMetafieldsSetInput, Scalars, CartUserError, MetafieldsSetUserError, MetafieldDeleteUserError, CartWarning, Product, ProductVariant, CartLine, ComponentizableCartLine, CurrencyCode, AttributeInput, CartBuyerIdentityInput, CartInput, CartLineInput, CartLineUpdateInput, CartSelectedDeliveryOptionInput, PageInfo, Maybe, ProductOptionValue, SelectedOptionInput, ProductOption, ProductVariantConnection } from '@shopify/hydrogen-react/storefront-api-types'; import { createStorefrontClient as createStorefrontClient$1, StorefrontClientProps, RichText as RichText$1, ShopPayButton as ShopPayButton$1 } from '@shopify/hydrogen-react'; export { AnalyticsEventName, AnalyticsPageType, ClientBrowserParameters, ExternalVideo, IMAGE_FRAGMENT, Image, MappedProductOptions, MediaFile, ModelViewer, Money, ParsedMetafields, ShopifyAnalytics as SendShopifyAnalyticsEvent, ShopifyAddToCart, ShopifyAddToCartPayload, ShopifyAnalyticsPayload, ShopifyAnalyticsProduct, ShopifyCookies, ShopifyPageView, ShopifyPageViewPayload, ShopifySalesChannel, StorefrontApiResponse, StorefrontApiResponseError, StorefrontApiResponseOk, StorefrontApiResponseOkPartial, StorefrontApiResponsePartial, Video, customerAccountApiCustomScalars, decodeEncodedVariant, flattenConnection, getAdjacentAndFirstAvailableVariants, getClientBrowserParameters, getProductOptions, getShopifyCookies, isOptionValueCombinationInEncodedVariant, mapSelectedProductOptionToObject, parseGid, parseMetafield, sendShopifyAnalytics, storefrontApiCustomScalars, useLoadScript, useMoney, useSelectedOptionInUrlParam, useShopifyCookies } from '@shopify/hydrogen-react'; import { ExecutionArgs } from 'graphql'; import { SessionData, FlashSessionData, Session, SessionStorage, LoaderFunctionArgs, LoaderFunction, SerializeFrom } from '@remix-run/server-runtime'; import * as react_jsx_runtime from 'react/jsx-runtime'; import { FetcherWithComponents, LinkProps, MetaFunction, Params, Location } from '@remix-run/react'; import { PartialDeep } from 'type-fest'; import { RouteConfigEntry } from '@remix-run/route-config'; import { WithContext, Thing } from 'schema-dts'; /** * Override options for a cache strategy. */ interface AllCacheOptions { /** * The caching mode, generally `public`, `private`, or `no-store`. */ mode?: string; /** * The maximum amount of time in seconds that a resource will be considered fresh. See `max-age` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#:~:text=Response%20Directives-,max%2Dage,-The%20max%2Dage). */ maxAge?: number; /** * Indicate that the cache should serve the stale response in the background while revalidating the cache. See `stale-while-revalidate` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate). */ staleWhileRevalidate?: number; /** * Similar to `maxAge` but specific to shared caches. See `s-maxage` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#s-maxage). */ sMaxAge?: number; /** * Indicate that the cache should serve the stale response if an error occurs while revalidating the cache. See `stale-if-error` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-if-error). */ staleIfError?: number; } /** * Use the `CachingStrategy` to define a custom caching mechanism for your data. Or use one of the pre-defined caching strategies: CacheNone, CacheShort, CacheLong. */ type CachingStrategy = AllCacheOptions; type NoStoreStrategy = { mode: string; }; declare function generateCacheControlHeader(cacheOptions: CachingStrategy): string; /** * * @public */ declare function CacheNone(): NoStoreStrategy; /** * * @public */ declare function CacheShort(overrideOptions?: CachingStrategy): AllCacheOptions; /** * * @public */ declare function CacheLong(overrideOptions?: CachingStrategy): AllCacheOptions; /** * * @public */ declare function CacheCustom(overrideOptions: CachingStrategy): AllCacheOptions; /** Convert a union type to an intersection type using [distributive conditional types](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types). Inspired by [this Stack Overflow answer](https://stackoverflow.com/a/50375286/2172153). @example ``` import type {UnionToIntersection} from 'type-fest'; type Union = {the(): void} | {great(arg: string): void} | {escape: boolean}; type Intersection = UnionToIntersection<Union>; //=> {the(): void; great(arg: string): void; escape: boolean}; ``` A more applicable example which could make its way into your library code follows. @example ``` import type {UnionToIntersection} from 'type-fest'; class CommandOne { commands: { a1: () => undefined, b1: () => undefined, } } class CommandTwo { commands: { a2: (argA: string) => undefined, b2: (argB: string) => undefined, } } const union = [new CommandOne(), new CommandTwo()].map(instance => instance.commands); type Union = typeof union; //=> {a1(): void; b1(): void} | {a2(argA: string): void; b2(argB: string): void} type Intersection = UnionToIntersection<Union>; //=> {a1(): void; b1(): void; a2(argA: string): void; b2(argB: string): void} ``` @category Type */ type UnionToIntersection<Union> = ( // `extends unknown` is always going to be the case and is used to convert the // `Union` into a [distributive conditional // type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types). Union extends unknown ? (distributedUnion: Union) => void : never) extends ((mergedIntersection: infer Intersection) => void) ? Intersection & Union : never; /** Create a union of all keys from a given type, even those exclusive to specific union members. Unlike the native `keyof` keyword, which returns keys present in **all** union members, this type returns keys from **any** member. @link https://stackoverflow.com/a/49402091 @example ``` import type {KeysOfUnion} from 'type-fest'; type A = { common: string; a: number; }; type B = { common: string; b: string; }; type C = { common: string; c: boolean; }; type Union = A | B | C; type CommonKeys = keyof Union; //=> 'common' type AllKeys = KeysOfUnion<Union>; //=> 'common' | 'a' | 'b' | 'c' ``` @category Object */ type KeysOfUnion<ObjectType> = // Hack to fix https://github.com/sindresorhus/type-fest/issues/1008 keyof UnionToIntersection<ObjectType extends unknown ? Record<keyof ObjectType, never> : never>; /** Returns a boolean for whether the two given types are equal. @link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650 @link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796 Use-cases: - If you want to make a conditional branch based on the result of a comparison of two types. @example ``` import type {IsEqual} from 'type-fest'; // This type returns a boolean for whether the given array includes the given item. // `IsEqual` is used to compare the given array at position 0 and the given item and then return true if they are equal. type Includes<Value extends readonly any[], Item> = Value extends readonly [Value[0], ...infer rest] ? IsEqual<Value[0], Item> extends true ? true : Includes<rest, Item> : false; ``` @category Type Guard @category Utilities */ type IsEqual<A, B> = (<G>() => G extends A & G | G ? 1 : 2) extends (<G>() => G extends B & G | G ? 1 : 2) ? true : false; /** Filter out keys from an object. Returns `never` if `Exclude` is strictly equal to `Key`. Returns `never` if `Key` extends `Exclude`. Returns `Key` otherwise. @example ``` type Filtered = Filter<'foo', 'foo'>; //=> never ``` @example ``` type Filtered = Filter<'bar', string>; //=> never ``` @example ``` type Filtered = Filter<'bar', 'foo'>; //=> 'bar' ``` @see {Except} */ type Filter<KeyType, ExcludeType> = IsEqual<KeyType, ExcludeType> extends true ? never : (KeyType extends ExcludeType ? never : KeyType); type ExceptOptions = { /** Disallow assigning non-specified properties. Note that any omitted properties in the resulting type will be present in autocomplete as `undefined`. @default false */ requireExactProps?: boolean; }; /** Create a type from an object type without certain keys. We recommend setting the `requireExactProps` option to `true`. This type is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type). The `Omit` type does not restrict the omitted keys to be keys present on the given type, while `Except` does. The benefits of a stricter type are avoiding typos and allowing the compiler to pick up on rename refactors automatically. This type was proposed to the TypeScript team, which declined it, saying they prefer that libraries implement stricter versions of the built-in types ([microsoft/TypeScript#30825](https://github.com/microsoft/TypeScript/issues/30825#issuecomment-523668235)). @example ``` import type {Except} from 'type-fest'; type Foo = { a: number; b: string; }; type FooWithoutA = Except<Foo, 'a'>; //=> {b: string} const fooWithoutA: FooWithoutA = {a: 1, b: '2'}; //=> errors: 'a' does not exist in type '{ b: string; }' type FooWithoutB = Except<Foo, 'b', {requireExactProps: true}>; //=> {a: number} & Partial<Record<"b", never>> const fooWithoutB: FooWithoutB = {a: 1, b: '2'}; //=> errors at 'b': Type 'string' is not assignable to type 'undefined'. // The `Omit` utility type doesn't work when omitting specific keys from objects containing index signatures. // Consider the following example: type UserData = { [metadata: string]: string; email: string; name: string; role: 'admin' | 'user'; }; // `Omit` clearly doesn't behave as expected in this case: type PostPayload = Omit<UserData, 'email'>; //=> type PostPayload = { [x: string]: string; [x: number]: string; } // In situations like this, `Except` works better. // It simply removes the `email` key while preserving all the other keys. type PostPayload = Except<UserData, 'email'>; //=> type PostPayload = { [x: string]: string; name: string; role: 'admin' | 'user'; } ``` @category Object */ type Except<ObjectType, KeysType extends keyof ObjectType, Options extends ExceptOptions = { requireExactProps: false; }> = { [KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType]; } & (Options["requireExactProps"] extends true ? Partial<Record<KeysType, never>> : {}); /** Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability. @example ``` import type {Simplify} from 'type-fest'; type PositionProps = { top: number; left: number; }; type SizeProps = { width: number; height: number; }; // In your editor, hovering over `Props` will show a flattened object with all the properties. type Props = Simplify<PositionProps & SizeProps>; ``` Sometimes it is desired to pass a value as a function argument that has a different type. At first inspection it may seem assignable, and then you discover it is not because the `value`'s type definition was defined as an interface. In the following example, `fn` requires an argument of type `Record<string, unknown>`. If the value is defined as a literal, then it is assignable. And if the `value` is defined as type using the `Simplify` utility the value is assignable. But if the `value` is defined as an interface, it is not assignable because the interface is not sealed and elsewhere a non-string property could be added to the interface. If the type definition must be an interface (perhaps it was defined in a third-party npm package), then the `value` can be defined as `const value: Simplify<SomeInterface> = ...`. Then `value` will be assignable to the `fn` argument. Or the `value` can be cast as `Simplify<SomeInterface>` if you can't re-declare the `value`. @example ``` import type {Simplify} from 'type-fest'; interface SomeInterface { foo: number; bar?: string; baz: number | undefined; } type SomeType = { foo: number; bar?: string; baz: number | undefined; }; const literal = {foo: 123, bar: 'hello', baz: 456}; const someType: SomeType = literal; const someInterface: SomeInterface = literal; function fn(object: Record<string, unknown>): void {} fn(literal); // Good: literal object type is sealed fn(someType); // Good: type is sealed fn(someInterface); // Error: Index signature for type 'string' is missing in type 'someInterface'. Because `interface` can be re-opened fn(someInterface as Simplify<SomeInterface>); // Good: transform an `interface` into a `type` ``` @link https://github.com/microsoft/TypeScript/issues/15300 @see SimplifyDeep @category Object */ type Simplify<T> = { [KeyType in keyof T]: T[KeyType]; } & {}; /** Returns a boolean for whether the given type is `never`. @link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919 @link https://stackoverflow.com/a/53984913/10292952 @link https://www.zhenghao.io/posts/ts-never Useful in type utilities, such as checking if something does not occur. @example ``` import type {IsNever, And} from 'type-fest'; // https://github.com/andnp/SimplyTyped/blob/master/src/types/strings.ts type AreStringsEqual<A extends string, B extends string> = And< IsNever<Exclude<A, B>> extends true ? true : false, IsNever<Exclude<B, A>> extends true ? true : false >; type EndIfEqual<I extends string, O extends string> = AreStringsEqual<I, O> extends true ? never : void; function endIfEqual<I extends string, O extends string>(input: I, output: O): EndIfEqual<I, O> { if (input === output) { process.exit(0); } } endIfEqual('abc', 'abc'); //=> never endIfEqual('abc', '123'); //=> void ``` @category Type Guard @category Utilities */ type IsNever<T> = [ T ] extends [ never ] ? true : false; /** Works similar to the built-in `Pick` utility type, except for the following differences: - Distributes over union types and allows picking keys from any member of the union type. - Primitives types are returned as-is. - Picks all keys if `Keys` is `any`. - Doesn't pick `number` from a `string` index signature. @example ``` type ImageUpload = { url: string; size: number; thumbnailUrl: string; }; type VideoUpload = { url: string; duration: number; encodingFormat: string; }; // Distributes over union types and allows picking keys from any member of the union type type MediaDisplay = HomomorphicPick<ImageUpload | VideoUpload, "url" | "size" | "duration">; //=> {url: string; size: number} | {url: string; duration: number} // Primitive types are returned as-is type Primitive = HomomorphicPick<string | number, 'toUpperCase' | 'toString'>; //=> string | number // Picks all keys if `Keys` is `any` type Any = HomomorphicPick<{a: 1; b: 2} | {c: 3}, any>; //=> {a: 1; b: 2} | {c: 3} // Doesn't pick `number` from a `string` index signature type IndexSignature = HomomorphicPick<{[k: string]: unknown}, number>; //=> {} */ type HomomorphicPick<T, Keys extends KeysOfUnion<T>> = { [P in keyof T as Extract<P, Keys>]: T[P]; }; /** Create a type that makes the given keys optional. The remaining keys are kept as is. The sister of the `SetRequired` type. Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are optional. @example ``` import type {SetOptional} from 'type-fest'; type Foo = { a: number; b?: string; c: boolean; } type SomeOptional = SetOptional<Foo, 'b' | 'c'>; // type SomeOptional = { // a: number; // b?: string; // Was already optional and still is. // c?: boolean; // Is now optional. // } ``` @category Object */ type SetOptional<BaseType, Keys extends keyof BaseType> = BaseType extends unknown // To distribute `BaseType` when it's a union type. ? Simplify< // Pick just the keys that are readonly from the base type. Except<BaseType, Keys> & // Pick the keys that should be mutable from the base type and make them mutable. Partial<HomomorphicPick<BaseType, Keys>>> : never; /** * This file has utilities to create GraphQL clients * that consume the types generated by the preset. */ /** * A generic type for `variables` in GraphQL clients */ type GenericVariables = ExecutionArgs["variableValues"]; /** * Use this type to make parameters optional in GraphQL clients * when no variables need to be passed. */ type EmptyVariables = { [key: string]: never; }; /** * GraphQL client's generic operation interface. */ interface CodegenOperations { [key: string]: any; } /** * Used as the return type for GraphQL clients. It picks * the return type from the generated operation types. * @example * graphqlQuery: (...) => Promise<ClientReturn<...>> * graphqlQuery: (...) => Promise<{data: ClientReturn<...>}> */ type ClientReturn<GeneratedOperations extends CodegenOperations, RawGqlString extends string, OverrideReturnType extends any = never> = IsNever<OverrideReturnType> extends true ? RawGqlString extends keyof GeneratedOperations ? GeneratedOperations[RawGqlString]["return"] : any : OverrideReturnType; /** * Checks if the generated variables for an operation * are optional or required. */ type IsOptionalVariables<VariablesParam, OptionalVariableNames extends string = never, VariablesWithoutOptionals = Omit<VariablesParam, OptionalVariableNames>> = VariablesWithoutOptionals extends EmptyVariables ? true : GenericVariables extends VariablesParam ? true : Partial<VariablesWithoutOptionals> extends VariablesWithoutOptionals ? true : false; /** * Used as the type for the GraphQL client's variables. It checks * the generated operation types to see if variables are optional. * @example * graphqlQuery: (query: string, param: ClientVariables<...>) => Promise<...> * Where `param` is required. */ type ClientVariables<GeneratedOperations extends CodegenOperations, RawGqlString extends string, OptionalVariableNames extends string = never, VariablesKey extends string = "variables", GeneratedVariables = RawGqlString extends keyof GeneratedOperations ? SetOptional<GeneratedOperations[RawGqlString]["variables"], Extract<keyof GeneratedOperations[RawGqlString]["variables"], OptionalVariableNames>> : GenericVariables, VariablesWrapper = Record<VariablesKey, GeneratedVariables>> = IsOptionalVariables<GeneratedVariables, OptionalVariableNames> extends true ? Partial<VariablesWrapper> : VariablesWrapper; /** * Similar to ClientVariables, but makes the whole wrapper optional: * @example * graphqlQuery: (query: string, ...params: ClientVariablesInRestParams<...>) => Promise<...> * Where the first item in `params` might be optional depending on the query. */ type ClientVariablesInRestParams<GeneratedOperations extends CodegenOperations, RawGqlString extends string, OtherParams extends Record<string, any> = {}, OptionalVariableNames extends string = never, ProcessedVariables = OtherParams & ClientVariables<GeneratedOperations, RawGqlString, OptionalVariableNames>> = Partial<OtherParams> extends OtherParams ? IsOptionalVariables<GeneratedOperations[RawGqlString]["variables"], OptionalVariableNames> extends true ? [ ProcessedVariables? ] : [ ProcessedVariables ] : [ ProcessedVariables ]; declare class GraphQLError extends Error { /** * If an error can be associated to a particular point in the requested * GraphQL document, it should contain a list of locations. */ locations?: Array<{ line: number; column: number; }>; /** * If an error can be associated to a particular field in the GraphQL result, * it _must_ contain an entry with the key `path` that details the path of * the response field which experienced the error. This allows clients to * identify whether a null result is intentional or caused by a runtime error. */ path?: Array<string | number>; /** * Reserved for implementors to extend the protocol however they see fit, * and hence there are no additional restrictions on its contents. */ extensions?: { [key: string]: unknown; }; constructor(message?: string, options?: Pick<GraphQLError, 'locations' | 'path' | 'extensions' | 'stack' | 'cause'> & { query?: string; queryVariables?: GenericVariables; requestId?: string | null; clientOperation?: string; }); get [Symbol.toStringTag](): string; /** * Note: `toString()` is internally used by `console.log(...)` / `console.error(...)` * when ingesting logs in Oxygen production. Therefore, we want to make sure that * the error message is as informative as possible instead of `[object Object]`. */ toString(): string; /** * Note: toJSON` is internally used by `JSON.stringify(...)`. * The most common scenario when this error instance is going to be stringified is * when it's passed to Remix' `json` and `defer` functions: e.g. `{promise: storefront.query(...)}`. * In this situation, we don't want to expose private error information to the browser so we only * do it in development. */ toJSON(): Pick<GraphQLError, "message" | "locations" | "path" | "extensions" | "stack" | "name">; } type RequestEventPayload = { __fromVite?: boolean; url: string; eventType: 'request' | 'subrequest'; requestId?: string | null; purpose?: string | null; startTime: number; endTime?: number; cacheStatus?: 'MISS' | 'HIT' | 'STALE' | 'PUT'; waitUntil?: WaitUntil; graphql?: string | null; stackInfo?: { file?: string; func?: string; line?: number; column?: number; }; responsePayload?: any; responseInit?: Omit<ResponseInit, 'headers'> & { headers?: [string, string][]; }; cache?: { status?: string; strategy?: string; key?: string | readonly unknown[]; }; displayName?: string; }; declare const CUSTOMER_ACCOUNT_SESSION_KEY = "customerAccount"; declare const BUYER_SESSION_KEY = "buyer"; interface HydrogenSessionData { [CUSTOMER_ACCOUNT_SESSION_KEY]: { accessToken?: string; expiresAt?: string; refreshToken?: string; codeVerifier?: string; idToken?: string; nonce?: string; state?: string; redirectPath?: string; }; // for B2B buyer context [BUYER_SESSION_KEY]: Partial<BuyerInput>; } interface HydrogenSession< Data = SessionData, FlashData = FlashSessionData, > { get: Session<HydrogenSessionData & Data, FlashData>['get']; set: Session<HydrogenSessionData & Data, FlashData>['set']; unset: Session<HydrogenSessionData & Data, FlashData>['unset']; commit: () => ReturnType< SessionStorage<HydrogenSessionData & Data, FlashData>['commitSession'] >; isPending?: boolean; } type WaitUntil = (promise: Promise<unknown>) => void; interface HydrogenEnv { SESSION_SECRET: string; PUBLIC_STOREFRONT_API_TOKEN: string; PRIVATE_STOREFRONT_API_TOKEN: string; PUBLIC_STORE_DOMAIN: string; PUBLIC_STOREFRONT_ID: string; PUBLIC_CUSTOMER_ACCOUNT_API_CLIENT_ID: string; PUBLIC_CUSTOMER_ACCOUNT_API_URL: string; PUBLIC_CHECKOUT_DOMAIN: string; SHOP_ID: string; } type StorefrontHeaders = { /** A unique ID that correlates all sub-requests together. */ requestGroupId: string | null; /** The IP address of the client. */ buyerIp: string | null; /** The cookie header from the client */ cookie: string | null; /** The purpose header value for debugging */ purpose: string | null; }; declare global { interface Window { privacyBanner: PrivacyBanner; Shopify: { customerPrivacy: CustomerPrivacy; }; } interface Document { addEventListener<K extends keyof CustomEventMap>( type: K, listener: (this: Document, ev: CustomEventMap[K]) => void, ): void; removeEventListener<K extends keyof CustomEventMap>( type: K, listener: (this: Document, ev: CustomEventMap[K]) => void, ): void; dispatchEvent<K extends keyof CustomEventMap>(ev: CustomEventMap[K]): void; } var __H2O_LOG_EVENT: undefined | ((event: RequestEventPayload) => void); var __remix_devServerHooks: | undefined | {getCriticalCss: (...args: unknown[]) => any}; } type I18nBase = { language: LanguageCode; country: CountryCode; }; type JsonGraphQLError$1 = ReturnType<GraphQLError['toJSON']>; type StorefrontApiErrors = JsonGraphQLError$1[] | undefined; type StorefrontError = { errors?: StorefrontApiErrors; }; /** * Wraps all the returned utilities from `createStorefrontClient`. */ type StorefrontClient<TI18n extends I18nBase> = { storefront: Storefront<TI18n>; }; /** * Maps all the queries found in the project to variables and return types. */ interface StorefrontQueries { } /** * Maps all the mutations found in the project to variables and return types. */ interface StorefrontMutations { } type AutoAddedVariableNames = 'country' | 'language'; type StorefrontCommonExtraParams = { headers?: HeadersInit; storefrontApiVersion?: string; displayName?: string; }; /** * Interface to interact with the Storefront API. */ type Storefront<TI18n extends I18nBase = I18nBase> = { query: <OverrideReturnType extends any = never, RawGqlString extends string = string>(query: RawGqlString, ...options: ClientVariablesInRestParams<StorefrontQueries, RawGqlString, StorefrontCommonExtraParams & Pick<StorefrontQueryOptions, 'cache'>, AutoAddedVariableNames>) => Promise<ClientReturn<StorefrontQueries, RawGqlString, OverrideReturnType> & StorefrontError>; mutate: <OverrideReturnType extends any = never, RawGqlString extends string = string>(mutation: RawGqlString, ...options: ClientVariablesInRestParams<StorefrontMutations, RawGqlString, StorefrontCommonExtraParams, AutoAddedVariableNames>) => Promise<ClientReturn<StorefrontMutations, RawGqlString, OverrideReturnType> & StorefrontError>; cache?: Cache; CacheNone: typeof CacheNone; CacheLong: typeof CacheLong; CacheShort: typeof CacheShort; CacheCustom: typeof CacheCustom; generateCacheControlHeader: typeof generateCacheControlHeader; getPublicTokenHeaders: ReturnType<typeof createStorefrontClient$1>['getPublicTokenHeaders']; getPrivateTokenHeaders: ReturnType<typeof createStorefrontClient$1>['getPrivateTokenHeaders']; getShopifyDomain: ReturnType<typeof createStorefrontClient$1>['getShopifyDomain']; getApiUrl: ReturnType<typeof createStorefrontClient$1>['getStorefrontApiUrl']; i18n: TI18n; }; type HydrogenClientProps<TI18n> = { /** Storefront API headers. If on Oxygen, use `getStorefrontHeaders()` */ storefrontHeaders?: StorefrontHeaders; /** An instance that implements the [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache) */ cache?: Cache; /** The globally unique identifier for the Shop */ storefrontId?: string; /** The `waitUntil` function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform. */ waitUntil?: WaitUntil; /** An object containing a country code and language code */ i18n?: TI18n; /** Whether it should print GraphQL errors automatically. Defaults to true */ logErrors?: boolean | ((error?: Error) => boolean); }; type CreateStorefrontClientOptions<TI18n extends I18nBase> = HydrogenClientProps<TI18n> & StorefrontClientProps; type StorefrontQueryOptions = StorefrontCommonExtraParams & { query: string; mutation?: never; cache?: CachingStrategy; }; /** * This function extends `createStorefrontClient` from [Hydrogen React](/docs/api/hydrogen-react/2025-01/utilities/createstorefrontclient). The additional arguments enable internationalization (i18n), caching, and other features particular to Remix and Oxygen. * * Learn more about [data fetching in Hydrogen](/docs/custom-storefronts/hydrogen/data-fetching/fetch-data). */ declare function createStorefrontClient<TI18n extends I18nBase>(options: CreateStorefrontClientOptions<TI18n>): StorefrontClient<TI18n>; declare function formatAPIResult<T>(data: T, errors: StorefrontApiErrors): T & StorefrontError; type CreateStorefrontClientForDocs<TI18n extends I18nBase> = { storefront?: StorefrontForDoc<TI18n>; }; type StorefrontForDoc<TI18n extends I18nBase = I18nBase> = { /** The function to run a query on Storefront API. */ query?: <TData = any>(query: string, options: StorefrontQueryOptionsForDocs) => Promise<TData & StorefrontError>; /** The function to run a mutation on Storefront API. */ mutate?: <TData = any>(mutation: string, options: StorefrontMutationOptionsForDocs) => Promise<TData & StorefrontError>; /** The cache instance passed in from the `createStorefrontClient` argument. */ cache?: Cache; /** Re-export of [`CacheNone`](/docs/api/hydrogen/2025-01/utilities/cachenone). */ CacheNone?: typeof CacheNone; /** Re-export of [`CacheLong`](/docs/api/hydrogen/2025-01/utilities/cachelong). */ CacheLong?: typeof CacheLong; /** Re-export of [`CacheShort`](/docs/api/hydrogen/2025-01/utilities/cacheshort). */ CacheShort?: typeof CacheShort; /** Re-export of [`CacheCustom`](/docs/api/hydrogen/2025-01/utilities/cachecustom). */ CacheCustom?: typeof CacheCustom; /** Re-export of [`generateCacheControlHeader`](/docs/api/hydrogen/2025-01/utilities/generatecachecontrolheader). */ generateCacheControlHeader?: typeof generateCacheControlHeader; /** Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint. See [`getPublicTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/2025-01/utilities/createstorefrontclient#:~:text=%27graphql%27.-,getPublicTokenHeaders,-(props%3F%3A) for more details. */ getPublicTokenHeaders?: ReturnType<typeof createStorefrontClient$1>['getPublicTokenHeaders']; /** Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint for API calls made from a server. See [`getPrivateTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/2025-01/utilities/createstorefrontclient#:~:text=storefrontApiVersion-,getPrivateTokenHeaders,-(props%3F%3A) for more details.*/ getPrivateTokenHeaders?: ReturnType<typeof createStorefrontClient$1>['getPrivateTokenHeaders']; /** Creates the fully-qualified URL to your myshopify.com domain. See [`getShopifyDomain` in Hydrogen React](/docs/api/hydrogen-react/2025-01/utilities/createstorefrontclient#:~:text=StorefrontClientReturn-,getShopifyDomain,-(props%3F%3A) for more details. */ getShopifyDomain?: ReturnType<typeof createStorefrontClient$1>['getShopifyDomain']; /** Creates the fully-qualified URL to your store's GraphQL endpoint. See [`getStorefrontApiUrl` in Hydrogen React](/docs/api/hydrogen-react/2025-01/utilities/createstorefrontclient#:~:text=storeDomain-,getStorefrontApiUrl,-(props%3F%3A) for more details.*/ getApiUrl?: ReturnType<typeof createStorefrontClient$1>['getStorefrontApiUrl']; /** The `i18n` object passed in from the `createStorefrontClient` argument. */ i18n?: TI18n; }; type StorefrontQueryOptionsForDocs = { /** The variables for the GraphQL query statement. */ variables?: Record<string, unknown>; /** The cache strategy for this query. Default to max-age=1, stale-while-revalidate=86399. */ cache?: CachingStrategy; /** Additional headers for this query. */ headers?: HeadersInit; /** Override the Storefront API version for this query. */ storefrontApiVersion?: string; /** The name of the query for debugging in the Subrequest Profiler. */ displayName?: string; }; type StorefrontMutationOptionsForDocs = { /** The variables for the GraphQL mutation statement. */ variables?: Record<string, unknown>; /** Additional headers for this query. */ headers?: HeadersInit; /** Override the Storefront API version for this query. */ storefrontApiVersion?: string; /** The name of the query for debugging in the Subrequest Profiler. */ displayName?: string; }; type CrossRuntimeRequest = { url?: string; method?: string; headers: { get?: (key: string) => string | null | undefined; [key: string]: any; }; }; type DataFunctionValue = Response | NonNullable<unknown> | null; type JsonGraphQLError = ReturnType<GraphQLError['toJSON']>; type Buyer = Partial<BuyerInput>; type CustomerAPIResponse<ReturnType> = { data: ReturnType; errors: Array<{ message: string; locations?: Array<{ line: number; column: number; }>; path?: Array<string>; extensions: { code: string; }; }>; extensions: { cost: { requestQueryCost: number; actualQueryCakes: number; throttleStatus: { maximumAvailable: number; currentAvailable: number; restoreRate: number; }; }; }; }; interface CustomerAccountQueries { } interface CustomerAccountMutations { } type LoginOptions = { uiLocales?: LanguageCode; }; type LogoutOptions = { postLogoutRedirectUri?: string; headers?: HeadersInit; }; type CustomerAccount = { /** Start the OAuth login flow. This function should be called and returned from a Remix loader. * It redirects the customer to a Shopify login domain. It also defined the final path the customer * lands on at the end of the oAuth flow with the value of the `return_to` query param. (This is * automatically setup unless `customAuthStatusHandler` option is in use) * * @param options.uiLocales - The displayed language of the login page. Only support for the following languages: * `en`, `fr`, `cs`, `da`, `de`, `es`, `fi`, `it`, `ja`, `ko`, `nb`, `nl`, `pl`, `pt-BR`, `pt-PT`, * `sv`, `th`, `tr`, `vi`, `zh-CN`, `zh-TW`. If supplied any other language code, it will default to `en`. * */ login: (options?: LoginOptions) => Promise<Response>; /** On successful login, the customer redirects back to your app. This function validates the OAuth response and exchanges the authorization code for an access token and refresh token. It also persists the tokens on your session. This function should be called and returned from the Remix loader configured as the redirect URI within the Customer Account API settings in admin. */ authorize: () => Promise<Response>; /** Returns if the customer is logged in. It also checks if the access token is expired and refreshes it if needed. */ isLoggedIn: () => Promise<boolean>; /** Check for a not logged in customer and redirect customer to login page. The redirect can be overwritten with `customAuthStatusHandler` option. */ handleAuthStatus: () => void | DataFunctionValue; /** Returns CustomerAccessToken if the customer is logged in. It also run a expiry check and does a token refresh if needed. */ getAccessToken: () => Promise<string | undefined>; /** Creates the fully-qualified URL to your store's GraphQL endpoint.*/ getApiUrl: () => string; /** Logout the customer by clearing the session and redirecting to the login domain. It should be called and returned from a Remix action. The path app should redirect to after logout can be setup in Customer Account API settings in admin. * * @param options.postLogoutRedirectUri - The url to redirect customer to after logout, should be a relative URL. This url will need to included in Customer Account API's application setup for logout URI. The default value is current app origin, which is automatically setup in admin when using `--customer-account-push` flag with dev. * @param options.headers - These will be passed along to the logout redirect. You can use these to set/clear cookies on logout, like the cart. * */ logout: (options?: LogoutOptions) => Promise<Response>; /** Execute a GraphQL query against the Customer Account API. This method execute `handleAuthStatus()` ahead of query. */ query: <OverrideReturnType extends any = never, RawGqlString extends string = string>(query: RawGqlString, ...options: ClientVariablesInRestParams<CustomerAccountQueries, RawGqlString>) => Promise<Omit<CustomerAPIResponse<ClientReturn<CustomerAccountQueries, RawGqlString, OverrideReturnType>>, 'errors'> & { errors?: JsonGraphQLError[]; }>; /** Execute a GraphQL mutation against the Customer Account API. This method execute `handleAuthStatus()` ahead of mutation. */ mutate: <OverrideReturnType extends any = never, RawGqlString extends string = string>(mutation: RawGqlString, ...options: ClientVariablesInRestParams<CustomerAccountMutations, RawGqlString>) => Promise<Omit<CustomerAPIResponse<ClientReturn<CustomerAccountMutations, RawGqlString, OverrideReturnType>>, 'errors'> & { errors?: JsonGraphQLError[]; }>; /** Set buyer information into session.*/ setBuyer: (buyer: Buyer) => void; /** Get buyer token and company location id from session.*/ getBuyer: () => Promise<Buyer>; /** Deprecated. Please use setBuyer. Set buyer information into session.*/ UNSTABLE_setBuyer: (buyer: Buyer) => void; /** Deprecated. Please use getBuyer. Get buyer token and company location id from session.*/ UNSTABLE_getBuyer: () => Promise<Buyer>; }; type CustomerAccountOptions = { /** The client requires a session to persist the auth and refresh token. By default Hydrogen ships with cookie session storage, but you can use [another session storage](https://remix.run/docs/en/main/utils/sessions) implementation. */ session: HydrogenSession; /** Unique UUID prefixed with `shp_` associated with the application, this should be visible in the customer account api settings in the Hydrogen admin channel. Mock.shop doesn't automatically supply customerAccountId. Use `npx shopify hydrogen env pull` to link your store credentials. */ customerAccountId: string; /** The shop id. Mock.shop doesn't automatically supply shopId. Use `npx shopify hydrogen env pull` to link your store credentials */ shopId: string; /** Override the version of the API */ customerApiVersion?: string; /** The object for the current Request. It should be provided by your platform. */ request: CrossRuntimeRequest; /** The waitUntil function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform. */ waitUntil?: WaitUntil; /** This is the route in your app that authorizes the customer after logging in. Make sure to call `customer.authorize()` within the loader on this route. It defaults to `/account/authorize`. */ authUrl?: string; /** Use this method to overwrite the default logged-out redirect behavior. The default handler [throws a redirect](https://remix.run/docs/en/main/utils/redirect#:~:text=!session) to `/account/login` with current path as `return_to` query param. */ customAuthStatusHandler?: () => DataFunctionValue; /** Whether it should print GraphQL errors automatically. Defaults to true */ logErrors?: boolean | ((error?: Error) => boolean); /** The path to redirect to after login. Defaults to `/account`. */ defaultRedirectPath?: string; /** The path to login. Defaults to `/account/login`. */ loginPath?: string; /** The oauth authorize path. Defaults to `/account/authorize`. */ authorizePath?: string; /** Deprecated. `unstableB2b` is now stable. Please remove. */ unstableB2b?: boolean; /** Localization data. */ language?: LanguageCode; }; type CartOptionalInput = { /** * The cart id. * @default cart.getCartId(); */ cartId?: Scalars['ID']['input']; /** * The country code. * @default storefront.i18n.country */ country?: CountryCode; /** * The language code. * @default storefront.i18n.language */ language?: LanguageCode; }; type MetafieldWithoutOwnerId = Omit<CartMetafieldsSetInput, 'ownerId'>; type CartQueryOptions = { /** * The storefront client instance created by [`createStorefrontClient`](docs/api/hydrogen/latest/utilities/createstorefrontclient). */ storefront: Storefront; /** * A function that returns the cart ID. */ getCartId: () => string | undefined; /** * The cart fragment to override the one used in this query. */ cartFragment?: string; /** * The customer account instance created by [`createCustomerAccount`](docs/api/hydrogen/latest/customer/createcustomeraccount). */ customerAccount?: CustomerAccount; }; type CartReturn = Cart & { errors?: StorefrontApiErrors; }; type CartQueryData = { cart: Cart; userErrors?: CartUserError[] | MetafieldsSetUserError[] | MetafieldDeleteUserError[]; warnings?: CartWarning[]; }; type CartQueryDataReturn = CartQueryData & { errors?: StorefrontApiErrors; }; type CartQueryReturn<T> = (requiredParams: T, optionalParams?: CartOptionalInput) => Promise<CartQueryData>; declare const AnalyticsEvent: { PAGE_VIEWED: "page_viewed"; PRODUCT_VIEWED: "product_viewed"; COLLECTION_VIEWED: "collection_viewed"; CART_VIEWED: "cart_viewed"; SEARCH_VIEWED: "search_viewed"; CART_UPDATED: "cart_updated"; PRODUCT_ADD_TO_CART: "product_added_to_cart"; PRODUCT_REMOVED_FROM_CART: "product_removed_from_cart"; CUSTOM_EVENT: `custom_${string}`; }; type OtherData = { /** Any other data that should be included in the event. */ [key: string]: unknown; }; type BasePayload = { /** The shop data passed in from the `AnalyticsProvider`. */ shop: ShopAnalytics | null; /** The custom data passed in from the `AnalyticsProvider`. */ customData?: AnalyticsProviderProps['customData']; }; type UrlPayload = { /** The url location of when this event is collected. */ url: string; }; type ProductPayload = { /** The product id. */ id: Product['id']; /** The product title. */ title: Product['title']; /** The displaying variant price. */ price: ProductVariant['price']['amount']; /** The product vendor. */ vendor: Product['vendor']; /** The displaying variant id. */ variantId: ProductVariant['id']; /** The displaying variant title. */ variantTitle: ProductVariant['title']; /** The quantity of product. */ quantity: number; /** The product sku. */ sku?: ProductVariant['sku']; /** The product type. */ productType?: Product['productType']; }; type ProductsPayload = { /** The products associated with this event. */ products: Array<ProductPayload & OtherData>; }; type CollectionPayloadDetails = { /** The collection id. */ id: string; /** The collection handle. */ handle: string; }; type CollectionPayload = { collection: CollectionPayloadDetails; }; type SearchPayload = { /** The search term used for the search results page */ searchTerm: string; /** The search results */ searchResults?: any; }; type CartPayload = { /** The current cart state. */ cart: CartReturn | null; /** The previous cart state. */ prevCart: CartReturn | null; }; type CartLinePayload = { /** The previous state of the cart line that got updated. */ prevLine?: CartLine | ComponentizableCartLine; /** The current state of the cart line that got updated. */ currentLine?: CartLine | ComponentizableCartLine; }; type CollectionViewPayload = CollectionPayload & UrlPayload & BasePayload; type ProductViewPayload = ProductsPayload & UrlPayload & BasePayload; type CartViewPayload = CartPayload & UrlPayload & BasePayload; type PageViewPayload = UrlPayload & BasePayload; type SearchViewPayload = SearchPayload & UrlPayload & BasePayload; type CartUpdatePayload = CartPayload & BasePayload & OtherData; type CartLineUpdatePayload = CartLinePayload & CartPayload & BasePayload & OtherData; type CustomEventPayload = BasePayload & OtherData; type BasicViewProps = { data?: OtherData; customData?: OtherData; }; type ProductViewProps = { data: ProductsPayload; customData?: OtherData; }; type CollectionViewProps = { data: CollectionPayload; customData?: OtherData; }; type SearchViewProps = { data?: SearchPayload; customData?: OtherData; }; type CustomViewProps = { type: typeof AnalyticsEvent.CUSTOM_EVENT; data?: OtherData; customData?: OtherData; }; declare function AnalyticsProductView(props: ProductViewProps): react_jsx_runtime.JSX.Element; declare function AnalyticsCollectionView(props: CollectionViewProps): react_jsx_runtime.JSX.Element; declare function AnalyticsCartView(props: BasicViewProps): react_jsx_runtime.JSX.Element; declare function AnalyticsSearchView(props: SearchViewProps): react_jsx_runtime.JSX.Element; declare function AnalyticsCustomView(props: CustomViewProps): react_jsx_runtime.JSX.Element; type ConsentStatus = boolean | undefined; type VisitorConsent = { marketing: ConsentStatus; analytics: ConsentStatus; preferences: ConsentStatus; sale_of_data: ConsentStatus; }; type VisitorConsentCollected = { analyticsAllowed: boolean; firstPartyMarketingAllowed: boolean; marketingAllowed: boolean; preferencesAllowed: boolean; saleOfDataAllowed: boolean; thirdPartyMarketingAllowed: boolean; }; type CustomerPrivacyApiLoaded = boolean; type CustomerPrivacyConsentConfig = { checkoutRootDomain: string; storefrontRootDomain?: string; storefrontAccessToken: string; country?: CountryCode; /** The privacyBanner refers to `language` as `locale` */ locale?: LanguageCode; }; type SetConsentHeadlessParams = VisitorConsent & CustomerPrivacyConsentConfig & { headlessStorefront?: boolean; }; /** Ideally this type should come from the Custoemr Privacy API sdk analyticsProcessingAllowed - currentVisitorConsent doesMerchantSupportGranularConsent firstPartyMarketingAllowed getCCPAConsent getRegulation getShopPrefs getTrackingConsent isRegulationEnforced marketingAllowed preferencesProcessingAllowed saleOfDataAllowed saleOfDataRegion setCCPAConsent setTrackingConsent shouldShowBanner shouldShowCCPABanner shouldShowGDPRBanner thirdPartyMarketingAllowed **/ type OriginalCustomerPrivacy = { currentVisitorConsent: () => VisitorConsent; preferencesProcessingAllowed: () => boolean; saleOfDataAllowed: () => boolean; marketingAllowed: () => boolean; analyticsProcessingAllowed: () => boolean; setTrackingConsent: (consent: SetConsentHeadlessParams, callback: (data: { error: string; } | undefined) => void) => void; }; type CustomerPrivacy$1 = Omit<OriginalCustomerPrivacy, 'setTrackingConsent'> & { setTrackingConsent: (consent: VisitorConsent, // we have already applied the headlessStorefront in the override callback: (data: { error: string; } | undefined) => void) => void; }; type PrivacyBanner$1 = { loadBanner: (options?: Partial<CustomerPrivacyConsentConfig>) => void; showPreferences: (options?: Partial<CustomerPrivacyConsentConfig>) => void; }; interface CustomEventMap$1 { visitorConsentCollected: CustomEvent<VisitorConsentCollected>; customerPrivacyApiLoaded: CustomEvent<CustomerPrivacyApiLoaded>; } type CustomerPrivacyApiProps = { /** The production shop checkout domain url. */ checkoutDomain: string; /** The storefront access token for the shop. */ storefrontAccessToken: string; /** Whether to load the Shopify privacy banner as configured in Shopify admin. Defaults to true. */ withPrivacyBanner?: boolean; /** Country code for the shop. */ country?: CountryCode; /** Language code for the shop. */ locale?: LanguageCode; /** Callback to be called when visitor consent is collected. */ onVisitorConsentCollected?: (consent: VisitorConsentCollected) => void; /** Callback to be call when customer privacy api is ready. */ onReady?: () => void; }; declare function useCustomerPrivacy(props: CustomerPrivacyApiProps): { customerPrivacy: CustomerPrivacy$1 | null; privacyBanner?: PrivacyBanner$1 | null; }; type ShopAnalytics = { /** The shop ID. */ shopId: string; /** The language code that is being displayed to user. */ acceptedLanguage: LanguageCode; /** The currency code that is being displayed to user. */ currency: CurrencyCode; /** The Hydrogen subchannel ID generated by Oxygen in the environment variable. */ hydrogenSubchannelId: string | '0'; }; type Consent = Partial<Pick<CustomerPrivacyApiProps, 'checkoutDomain' | 'storefrontAccessToken' | 'withPrivacyBanner' | 'country'>> & { language?: LanguageCode; }; type AnalyticsProviderProps = { /** React children to render. */ children?: ReactNode; /** The cart or cart promise to track for cart analytics. When there is a difference between the state of the cart, `AnalyticsProvider` will trigger a `cart_updated` event. It will also produce `product_added_to_cart` and `product_removed_from_cart` based on cart line quantity and cart line id changes. */ cart: Promise<CartReturn | null> | CartReturn | null; /** An optional function to set wether the user can be tracked. Defaults to Customer Privacy API's `window.Shopify.customerPrivacy.analyticsProcessingAllowed()`. */ canTrack?: () => boolean; /** An optional custom payload to pass to all events. e.g language/locale/currency. */ customData?: Record<string, unknown>; /*