@abconvert/headless 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,7 +25,7 @@ The package has no runtime dependencies. React, Next.js, and Hydrogen are option
25
25
  |---|---|
26
26
  | `@abconvert/headless` | The client for any server, edge runtime, or browser. Start here on a stack that is not listed below. |
27
27
  | `@abconvert/headless/react` | `ABConvertProvider` and the `useABConvert` hook for a React app. |
28
- | `@abconvert/headless/next` | Next.js 14 and later: the middleware that assigns before the page renders, and the client for your server components. |
28
+ | `@abconvert/headless/next` | Next.js 14.2.10 and later 14.2 releases, 15.1 to 15.4, and 16: the middleware that assigns before the page renders, and the client for your server components. |
29
29
  | `@abconvert/headless/hydrogen` | Hydrogen 2026.10 and later. Tracks from Hydrogen's analytics and waits for the visitor's consent. |
30
30
  | `@abconvert/headless/hydrogen/analytics-provider` | Hydrogen before 2026.10, where your app renders `<Analytics.Provider>`. |
31
31
 
@@ -0,0 +1,35 @@
1
+ /** The parts of Hydrogen's cart store state the cart attributes component reads. */
2
+ export interface HydrogenCartState {
3
+ data: {
4
+ /** The cart's Storefront API GID, or `null` when no cart exists yet. */
5
+ id: string | null;
6
+ /** Cart-level attributes. */
7
+ attributes: {
8
+ key: string;
9
+ value: string | null;
10
+ }[];
11
+ };
12
+ /** `true` while the store loads the full cart. */
13
+ loading: boolean;
14
+ /** Present while a full cart load runs. */
15
+ readonly readyPromise?: PromiseLike<void>;
16
+ /** `true` while the store reloads the cart in the background. */
17
+ revalidating?: boolean;
18
+ /** The parts of the cart with changes in flight. */
19
+ pending: {
20
+ lines: {
21
+ size: number;
22
+ };
23
+ discountCodes: {
24
+ size: number;
25
+ };
26
+ note: boolean;
27
+ attributes: boolean;
28
+ };
29
+ }
30
+ /** `useCart` as `createCartComponents` returns it: the slice of cart state a selector picks. */
31
+ export type UseCart = <S>(selector: (state: HydrogenCartState) => S) => S;
32
+ export interface CartAttributesProps {
33
+ /** `useCart` from the module where you call `createCartComponents`. */
34
+ useCart: UseCart;
35
+ }
@@ -0,0 +1,35 @@
1
+ /** The parts of Hydrogen's cart store state the cart attributes component reads. */
2
+ export interface HydrogenCartState {
3
+ data: {
4
+ /** The cart's Storefront API GID, or `null` when no cart exists yet. */
5
+ id: string | null;
6
+ /** Cart-level attributes. */
7
+ attributes: {
8
+ key: string;
9
+ value: string | null;
10
+ }[];
11
+ };
12
+ /** `true` while the store loads the full cart. */
13
+ loading: boolean;
14
+ /** Present while a full cart load runs. */
15
+ readonly readyPromise?: PromiseLike<void>;
16
+ /** `true` while the store reloads the cart in the background. */
17
+ revalidating?: boolean;
18
+ /** The parts of the cart with changes in flight. */
19
+ pending: {
20
+ lines: {
21
+ size: number;
22
+ };
23
+ discountCodes: {
24
+ size: number;
25
+ };
26
+ note: boolean;
27
+ attributes: boolean;
28
+ };
29
+ }
30
+ /** `useCart` as `createCartComponents` returns it: the slice of cart state a selector picks. */
31
+ export type UseCart = <S>(selector: (state: HydrogenCartState) => S) => S;
32
+ export interface CartAttributesProps {
33
+ /** `useCart` from the module where you call `createCartComponents`. */
34
+ useCart: UseCart;
35
+ }
package/dist/hydrogen.cjs CHANGED
@@ -1 +1 @@
1
- var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var index_exports={};__export(index_exports,{ABConvertProvider:()=>ABConvertProvider,createABConvert:()=>createABConvert,keepPrivateWhenTested:()=>keepPrivateWhenTested,useABConvert:()=>import_react3.useABConvert});module.exports=__toCommonJS(index_exports);var globals=()=>globalThis;function attempt(read,fallback){try{return read()??fallback}catch{return fallback}}function shopifyAnalytics(){return attempt(()=>{let bus=globals().Shopify?.analytics;return typeof bus?.addDestination=="function"?bus:null},null)}var import_react=require("react"),import_headless=require("@abconvert/headless"),import_react2=require("@abconvert/headless/react");async function createABConvert(options){let{client,cacheFacts}=await(0,import_headless.openClient)({...options,expectCustomerPrivacy:!0},{write:"changed"});return cacheFacts().loaded||withoutTests.add(client),client}var withoutTests=new WeakSet,PUBLIC=/(^|,)\s*public\s*(?=,|$)/i;function keepPrivateWhenTested(headers,client){if(!withoutTests.has(client)&&!client.isPageTested()&&!client.getSetCookieHeaders().length)return!1;let changed=!1;for(let name of["Cache-Control","Oxygen-Cache-Control"]){let value=headers.get(name);!value||!PUBLIC.test(value)||(headers.set(name,value.replace(PUBLIC,"$1private")),changed=!0)}return changed}function fromAddToCart(payload){let{currentLine,prevLine}=payload??{},variantId=currentLine?.merchandise?.id,quantity=(currentLine?.quantity??0)-(prevLine?.quantity??0);return!variantId||!(quantity>0)?null:{variantId,productId:currentLine.merchandise?.product?.id,quantity}}function fromPageView(payload){let url=payload?.url;return typeof url=="string"?{url}:{}}function fromProductView(payload){let products=payload?.products;if(!Array.isArray(products))return[];let page=fromPageView(payload);return products.flatMap(product=>product?.id||product?.variantId?[{productId:product.id,variantId:product.variantId,...page}]:[])}function subscribeTo(subscribe,track){subscribe("page_viewed",payload=>track("page_viewed",fromPageView(payload))),subscribe("product_viewed",payload=>{for(let viewed of fromProductView(payload))track("product_viewed",viewed)}),subscribe("product_added_to_cart",payload=>{let added=fromAddToCart(payload);added&&track("product_added_to_cart",added)})}var connected=!1;function hydrogenProvider(useConnect,warning){function HydrogenEvents(){let{track}=(0,import_react2.useABConvert)(),connect=useConnect();return(0,import_react.useEffect)(()=>{connected||(connected=!0,connect(track)||console.warn(warning))},[]),null}return function(props){return(0,import_react.createElement)(import_react2.ABConvertProvider,{...props,expectCustomerPrivacy:!0},(0,import_react.createElement)(HydrogenEvents),props.children)}}var import_react3=require("@abconvert/headless/react"),connectBus=()=>track=>{let bus=shopifyAnalytics();return bus?.addDestination({name:"abconvert",setup:({subscribe})=>subscribeTo(subscribe,track)}),bus!==null},ABConvertProvider=hydrogenProvider(connectBus,"[ABConvert] No Hydrogen analytics bus on this page, so page views, product views and add to cart are not tracked. Render <ShopifyScripts> above <ABConvertProvider>, or on Hydrogen 2026.4 and earlier import from @abconvert/headless/hydrogen/analytics-provider.");
1
+ var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var index_exports={};__export(index_exports,{ABConvertCartAttributes:()=>ABConvertCartAttributes,ABConvertProvider:()=>ABConvertProvider,createABConvert:()=>createABConvert,keepPrivateWhenTested:()=>keepPrivateWhenTested,useABConvert:()=>import_react5.useABConvert,useCartReadyForCheckout:()=>useCartReadyForCheckout});module.exports=__toCommonJS(index_exports);var globals=()=>globalThis;function attempt(read,fallback){try{return read()??fallback}catch{return fallback}}function shopifyAnalytics(){return attempt(()=>{let bus=globals().Shopify?.analytics;return typeof bus?.addDestination=="function"?bus:null},null)}function shopifyUpdateCart(){return attempt(()=>{let updateCart=globals().Shopify?.actions?.updateCart;return typeof updateCart=="function"?updateCart:null},null)}var import_react=require("react"),import_headless=require("@abconvert/headless"),import_react2=require("@abconvert/headless/react");async function createABConvert(options){let{client,cacheFacts}=await(0,import_headless.openClient)({...options,expectCustomerPrivacy:!0},{write:"changed"});return cacheFacts().loaded||withoutTests.add(client),client}var withoutTests=new WeakSet,PUBLIC=/(^|,)\s*public\s*(?=,|$)/i;function keepPrivateWhenTested(headers,client){if(!withoutTests.has(client)&&!client.isPageTested()&&!client.getSetCookieHeaders().length)return!1;let changed=!1;for(let name of["Cache-Control","Oxygen-Cache-Control"]){let value=headers.get(name);!value||!PUBLIC.test(value)||(headers.set(name,value.replace(PUBLIC,"$1private")),changed=!0)}return changed}function fromAddToCart(payload){let{currentLine,prevLine}=payload??{},variantId=currentLine?.merchandise?.id,quantity=(currentLine?.quantity??0)-(prevLine?.quantity??0);return!variantId||!(quantity>0)?null:{variantId,productId:currentLine.merchandise?.product?.id,quantity}}function fromPageView(payload){let url=payload?.url;return typeof url=="string"?{url}:{}}function fromProductView(payload){let products=payload?.products;if(!Array.isArray(products))return[];let page=fromPageView(payload);return products.flatMap(product=>product?.id||product?.variantId?[{productId:product.id,variantId:product.variantId,...page}]:[])}function subscribeTo(subscribe,track){subscribe("page_viewed",payload=>track("page_viewed",fromPageView(payload))),subscribe("product_viewed",payload=>{for(let viewed of fromProductView(payload))track("product_viewed",viewed)}),subscribe("product_added_to_cart",payload=>{let added=fromAddToCart(payload);added&&track("product_added_to_cart",added)})}var connected=!1;function hydrogenProvider(useConnect,warning){function HydrogenEvents(){let{track}=(0,import_react2.useABConvert)(),connect=useConnect();return(0,import_react.useEffect)(()=>{connected||(connected=!0,connect(track)||console.warn(warning))},[]),null}return function(props){return(0,import_react.createElement)(import_react2.ABConvertProvider,{...props,expectCustomerPrivacy:!0},(0,import_react.createElement)(HydrogenEvents),props.children)}}var import_react5=require("@abconvert/headless/react");var import_react3=require("react"),import_react4=require("@abconvert/headless/react");var MAX_RETRY_DELAY=3e4;function isMissing(attributes,ours){return ours.some(({key,value})=>attributes.find(attribute=>attribute.key===key)?.value!==value)}function mergeAttributes(attributes,ours){let keys=new Set(ours.map(({key})=>key));return[...attributes.filter(({key})=>!keys.has(key)).map(({key,value})=>({key,value:value??""})),...ours]}var isSettled=state=>!state.loading&&!state.readyPromise&&!state.revalidating&&state.pending.lines.size===0&&state.pending.discountCodes.size===0&&!state.pending.note&&!state.pending.attributes;function ABConvertCartAttributes({useCart}){let abconvert=(0,import_react4.useABConvert)(),cartId=useCart(state=>state.data.id),attributes=useCart(state=>state.data.attributes),settled=useCart(isSettled),sending=(0,import_react3.useRef)(!1),retryAt=(0,import_react3.useRef)(0),[failures,setFailures]=(0,import_react3.useState)(0);return(0,import_react3.useEffect)(()=>{let timer=setTimeout(()=>{let updateCart=shopifyUpdateCart();if(!cartId||!settled||!updateCart||updateCart.isDefault()||sending.current||Date.now()<retryAt.current)return;let ours=abconvert.getCartAttributes();isMissing(attributes,ours)&&(sending.current=!0,updateCart({attributes:mergeAttributes(attributes,ours)}).then(({userErrors})=>{if(userErrors?.length)throw new Error(userErrors[0].message);setFailures(0)}).catch(()=>{let delay=Math.min(1e3*2**failures,MAX_RETRY_DELAY);retryAt.current=Date.now()+delay,setTimeout(()=>setFailures(count=>count+1),delay)}).finally(()=>{sending.current=!1}))});return()=>clearTimeout(timer)},[abconvert,cartId,settled,attributes,failures]),null}function useCartReadyForCheckout(useCart){let abconvert=(0,import_react4.useABConvert)(),attributes=useCart(state=>state.data.attributes),[ready,setReady]=(0,import_react3.useState)(!1);return(0,import_react3.useEffect)(()=>setReady(!isMissing(attributes,abconvert.getCartAttributes())),[abconvert,attributes]),ready}var connectBus=()=>track=>{let bus=shopifyAnalytics();return bus?.addDestination({name:"abconvert",setup:({subscribe})=>subscribeTo(subscribe,track)}),bus!==null},ABConvertProvider=hydrogenProvider(connectBus,"[ABConvert] No Hydrogen analytics bus on this page, so page views, product views and add to cart are not tracked. Render <ShopifyScripts> above <ABConvertProvider>, or on Hydrogen 2026.4 and earlier import from @abconvert/headless/hydrogen/analytics-provider.");
@@ -10,3 +10,9 @@ export declare const ABConvertProvider: (props: HydrogenProviderProps) => ReactE
10
10
  export declare function createABConvert(options: Omit<ABConvertOptions, 'expectCustomerPrivacy'> & { request: RequestLike }): Promise<ServerABConvert>;
11
11
  /** On a route in Oxygen's full-page cache, after the loader's reads: turns a public Cache-Control private when a test can change this route (isPageTested), when the response sets a cookie, or when the client could not load the tests. True when it changed a header. */
12
12
  export declare function keepPrivateWhenTested(headers: Headers, client: Pick<ServerABConvert, 'isPageTested' | 'getSetCookieHeaders'>): boolean;
13
+ import type { CartAttributesProps, UseCart } from './hydrogen/cart-types.cjs';
14
+ export type { CartAttributesProps, HydrogenCartState, UseCart } from './hydrogen/cart-types.cjs';
15
+ /** Writes ABConvert's cart attributes to Hydrogen's cart whenever it lacks one or holds an older value, keeping the others. Render it once, inside CartProvider and ABConvertProvider, with your app's useCart. A failed update is tried again after 1, 2, 4... seconds, up to 30. */
16
+ export declare function ABConvertCartAttributes(props: CartAttributesProps): null;
17
+ /** True once the cart carries ABConvert's current attributes: checkout charges what they say, so hold the checkout button until then. */
18
+ export declare function useCartReadyForCheckout(useCart: UseCart): boolean;
@@ -10,3 +10,9 @@ export declare const ABConvertProvider: (props: HydrogenProviderProps) => ReactE
10
10
  export declare function createABConvert(options: Omit<ABConvertOptions, 'expectCustomerPrivacy'> & { request: RequestLike }): Promise<ServerABConvert>;
11
11
  /** On a route in Oxygen's full-page cache, after the loader's reads: turns a public Cache-Control private when a test can change this route (isPageTested), when the response sets a cookie, or when the client could not load the tests. True when it changed a header. */
12
12
  export declare function keepPrivateWhenTested(headers: Headers, client: Pick<ServerABConvert, 'isPageTested' | 'getSetCookieHeaders'>): boolean;
13
+ import type { CartAttributesProps, UseCart } from './hydrogen/cart-types.js';
14
+ export type { CartAttributesProps, HydrogenCartState, UseCart } from './hydrogen/cart-types.js';
15
+ /** Writes ABConvert's cart attributes to Hydrogen's cart whenever it lacks one or holds an older value, keeping the others. Render it once, inside CartProvider and ABConvertProvider, with your app's useCart. A failed update is tried again after 1, 2, 4... seconds, up to 30. */
16
+ export declare function ABConvertCartAttributes(props: CartAttributesProps): null;
17
+ /** True once the cart carries ABConvert's current attributes: checkout charges what they say, so hold the checkout button until then. */
18
+ export declare function useCartReadyForCheckout(useCart: UseCart): boolean;
package/dist/hydrogen.js CHANGED
@@ -1 +1 @@
1
- var globals=()=>globalThis;function attempt(read,fallback){try{return read()??fallback}catch{return fallback}}function shopifyAnalytics(){return attempt(()=>{let bus=globals().Shopify?.analytics;return typeof bus?.addDestination=="function"?bus:null},null)}import{createElement,useEffect}from"react";import{openClient}from"@abconvert/headless";import{ABConvertProvider as ReactProvider,useABConvert}from"@abconvert/headless/react";async function createABConvert(options){let{client,cacheFacts}=await openClient({...options,expectCustomerPrivacy:!0},{write:"changed"});return cacheFacts().loaded||withoutTests.add(client),client}var withoutTests=new WeakSet,PUBLIC=/(^|,)\s*public\s*(?=,|$)/i;function keepPrivateWhenTested(headers,client){if(!withoutTests.has(client)&&!client.isPageTested()&&!client.getSetCookieHeaders().length)return!1;let changed=!1;for(let name of["Cache-Control","Oxygen-Cache-Control"]){let value=headers.get(name);!value||!PUBLIC.test(value)||(headers.set(name,value.replace(PUBLIC,"$1private")),changed=!0)}return changed}function fromAddToCart(payload){let{currentLine,prevLine}=payload??{},variantId=currentLine?.merchandise?.id,quantity=(currentLine?.quantity??0)-(prevLine?.quantity??0);return!variantId||!(quantity>0)?null:{variantId,productId:currentLine.merchandise?.product?.id,quantity}}function fromPageView(payload){let url=payload?.url;return typeof url=="string"?{url}:{}}function fromProductView(payload){let products=payload?.products;if(!Array.isArray(products))return[];let page=fromPageView(payload);return products.flatMap(product=>product?.id||product?.variantId?[{productId:product.id,variantId:product.variantId,...page}]:[])}function subscribeTo(subscribe,track){subscribe("page_viewed",payload=>track("page_viewed",fromPageView(payload))),subscribe("product_viewed",payload=>{for(let viewed of fromProductView(payload))track("product_viewed",viewed)}),subscribe("product_added_to_cart",payload=>{let added=fromAddToCart(payload);added&&track("product_added_to_cart",added)})}var connected=!1;function hydrogenProvider(useConnect,warning){function HydrogenEvents(){let{track}=useABConvert(),connect=useConnect();return useEffect(()=>{connected||(connected=!0,connect(track)||console.warn(warning))},[]),null}return function(props){return createElement(ReactProvider,{...props,expectCustomerPrivacy:!0},createElement(HydrogenEvents),props.children)}}import{useABConvert as useABConvert2}from"@abconvert/headless/react";var connectBus=()=>track=>{let bus=shopifyAnalytics();return bus?.addDestination({name:"abconvert",setup:({subscribe})=>subscribeTo(subscribe,track)}),bus!==null},ABConvertProvider=hydrogenProvider(connectBus,"[ABConvert] No Hydrogen analytics bus on this page, so page views, product views and add to cart are not tracked. Render <ShopifyScripts> above <ABConvertProvider>, or on Hydrogen 2026.4 and earlier import from @abconvert/headless/hydrogen/analytics-provider.");export{ABConvertProvider,createABConvert,keepPrivateWhenTested,useABConvert2 as useABConvert};
1
+ var globals=()=>globalThis;function attempt(read,fallback){try{return read()??fallback}catch{return fallback}}function shopifyAnalytics(){return attempt(()=>{let bus=globals().Shopify?.analytics;return typeof bus?.addDestination=="function"?bus:null},null)}function shopifyUpdateCart(){return attempt(()=>{let updateCart=globals().Shopify?.actions?.updateCart;return typeof updateCart=="function"?updateCart:null},null)}import{createElement,useEffect}from"react";import{openClient}from"@abconvert/headless";import{ABConvertProvider as ReactProvider,useABConvert}from"@abconvert/headless/react";async function createABConvert(options){let{client,cacheFacts}=await openClient({...options,expectCustomerPrivacy:!0},{write:"changed"});return cacheFacts().loaded||withoutTests.add(client),client}var withoutTests=new WeakSet,PUBLIC=/(^|,)\s*public\s*(?=,|$)/i;function keepPrivateWhenTested(headers,client){if(!withoutTests.has(client)&&!client.isPageTested()&&!client.getSetCookieHeaders().length)return!1;let changed=!1;for(let name of["Cache-Control","Oxygen-Cache-Control"]){let value=headers.get(name);!value||!PUBLIC.test(value)||(headers.set(name,value.replace(PUBLIC,"$1private")),changed=!0)}return changed}function fromAddToCart(payload){let{currentLine,prevLine}=payload??{},variantId=currentLine?.merchandise?.id,quantity=(currentLine?.quantity??0)-(prevLine?.quantity??0);return!variantId||!(quantity>0)?null:{variantId,productId:currentLine.merchandise?.product?.id,quantity}}function fromPageView(payload){let url=payload?.url;return typeof url=="string"?{url}:{}}function fromProductView(payload){let products=payload?.products;if(!Array.isArray(products))return[];let page=fromPageView(payload);return products.flatMap(product=>product?.id||product?.variantId?[{productId:product.id,variantId:product.variantId,...page}]:[])}function subscribeTo(subscribe,track){subscribe("page_viewed",payload=>track("page_viewed",fromPageView(payload))),subscribe("product_viewed",payload=>{for(let viewed of fromProductView(payload))track("product_viewed",viewed)}),subscribe("product_added_to_cart",payload=>{let added=fromAddToCart(payload);added&&track("product_added_to_cart",added)})}var connected=!1;function hydrogenProvider(useConnect,warning){function HydrogenEvents(){let{track}=useABConvert(),connect=useConnect();return useEffect(()=>{connected||(connected=!0,connect(track)||console.warn(warning))},[]),null}return function(props){return createElement(ReactProvider,{...props,expectCustomerPrivacy:!0},createElement(HydrogenEvents),props.children)}}import{useABConvert as useABConvert3}from"@abconvert/headless/react";import{useEffect as useEffect2,useRef,useState}from"react";import{useABConvert as useABConvert2}from"@abconvert/headless/react";var MAX_RETRY_DELAY=3e4;function isMissing(attributes,ours){return ours.some(({key,value})=>attributes.find(attribute=>attribute.key===key)?.value!==value)}function mergeAttributes(attributes,ours){let keys=new Set(ours.map(({key})=>key));return[...attributes.filter(({key})=>!keys.has(key)).map(({key,value})=>({key,value:value??""})),...ours]}var isSettled=state=>!state.loading&&!state.readyPromise&&!state.revalidating&&state.pending.lines.size===0&&state.pending.discountCodes.size===0&&!state.pending.note&&!state.pending.attributes;function ABConvertCartAttributes({useCart}){let abconvert=useABConvert2(),cartId=useCart(state=>state.data.id),attributes=useCart(state=>state.data.attributes),settled=useCart(isSettled),sending=useRef(!1),retryAt=useRef(0),[failures,setFailures]=useState(0);return useEffect2(()=>{let timer=setTimeout(()=>{let updateCart=shopifyUpdateCart();if(!cartId||!settled||!updateCart||updateCart.isDefault()||sending.current||Date.now()<retryAt.current)return;let ours=abconvert.getCartAttributes();isMissing(attributes,ours)&&(sending.current=!0,updateCart({attributes:mergeAttributes(attributes,ours)}).then(({userErrors})=>{if(userErrors?.length)throw new Error(userErrors[0].message);setFailures(0)}).catch(()=>{let delay=Math.min(1e3*2**failures,MAX_RETRY_DELAY);retryAt.current=Date.now()+delay,setTimeout(()=>setFailures(count=>count+1),delay)}).finally(()=>{sending.current=!1}))});return()=>clearTimeout(timer)},[abconvert,cartId,settled,attributes,failures]),null}function useCartReadyForCheckout(useCart){let abconvert=useABConvert2(),attributes=useCart(state=>state.data.attributes),[ready,setReady]=useState(!1);return useEffect2(()=>setReady(!isMissing(attributes,abconvert.getCartAttributes())),[abconvert,attributes]),ready}var connectBus=()=>track=>{let bus=shopifyAnalytics();return bus?.addDestination({name:"abconvert",setup:({subscribe})=>subscribeTo(subscribe,track)}),bus!==null},ABConvertProvider=hydrogenProvider(connectBus,"[ABConvert] No Hydrogen analytics bus on this page, so page views, product views and add to cart are not tracked. Render <ShopifyScripts> above <ABConvertProvider>, or on Hydrogen 2026.4 and earlier import from @abconvert/headless/hydrogen/analytics-provider.");export{ABConvertCartAttributes,ABConvertProvider,createABConvert,keepPrivateWhenTested,useABConvert3 as useABConvert,useCartReadyForCheckout};