@occluze/tether 0.7.2 → 0.8.1

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.
Files changed (43) hide show
  1. package/README.md +4 -4
  2. package/dist/esm/astro.js +1 -1
  3. package/dist/esm/chunks/{account-W4FBRKXA.js → account-BS5MCC2R.js} +1 -1
  4. package/dist/esm/chunks/{account-pages-IM3OQTOP.js → account-pages-XR6QZ3DX.js} +1 -1
  5. package/dist/esm/chunks/{analytics-QDVOLZY3.js → analytics-BYN3QHBA.js} +1 -1
  6. package/dist/esm/chunks/{chunk-YC4JXWRG.js → chunk-2IVIZDT5.js} +1 -4
  7. package/dist/esm/chunks/{chunk-NYDZPTLP.js → chunk-A2PCQK2F.js} +1 -1
  8. package/dist/esm/chunks/{chunk-BMDYNMRC.js → chunk-A3GXCQJ4.js} +1 -1
  9. package/dist/esm/chunks/{chunk-GF6JTI65.js → chunk-COQ6ATC6.js} +1 -1
  10. package/dist/esm/chunks/chunk-EGIDFV3T.js +1 -0
  11. package/dist/esm/chunks/{chunk-CUL66KRA.js → chunk-EW3GKRT4.js} +1 -1
  12. package/dist/esm/chunks/{chunk-CXHPBT7N.js → chunk-FM7ZLLVP.js} +1 -1
  13. package/dist/esm/chunks/{chunk-AUVAN3KZ.js → chunk-FPJGQ7Z5.js} +1 -1
  14. package/dist/esm/chunks/chunk-GXCCTPDF.js +1 -0
  15. package/dist/esm/chunks/{chunk-RPI5C3EJ.js → chunk-HXZSNZOV.js} +1 -1
  16. package/dist/esm/chunks/{chunk-RJY76ESL.js → chunk-MJFKAMFM.js} +1 -1
  17. package/dist/esm/chunks/{chunk-QUECUXHD.js → chunk-TE5PNI76.js} +1 -1
  18. package/dist/esm/chunks/{chunk-CVNRODH3.js → chunk-X2JZPXLF.js} +1 -1
  19. package/dist/esm/chunks/{diagnose-3XHPZZNP.js → diagnose-IFRNCEYG.js} +1 -1
  20. package/dist/esm/chunks/{extras-C724KKG6.js → extras-3477M6Y7.js} +1 -1
  21. package/dist/esm/chunks/{markets-ui-WBWWQAGU.js → markets-ui-3L2UZ7PK.js} +1 -1
  22. package/dist/esm/chunks/{search-5NFIZBPJ.js → search-YR73GIWY.js} +1 -1
  23. package/dist/esm/index.js +1 -1
  24. package/dist/esm/server.js +2 -2
  25. package/dist/tether.js +26 -25
  26. package/dist/tether.min.js +1 -4
  27. package/dist/tether.min.js.map +4 -4
  28. package/dist/types/src/account/page-answers.d.ts +3 -1
  29. package/dist/types/src/analytics.d.ts +3 -1
  30. package/dist/types/src/cart/store.d.ts +8 -2
  31. package/dist/types/src/client.d.ts +8 -3
  32. package/dist/types/src/controls/navigation.d.ts +3 -1
  33. package/dist/types/src/dom.d.ts +3 -1
  34. package/dist/types/src/index.d.ts +3 -3
  35. package/dist/types/src/markup.d.ts +7 -5
  36. package/dist/types/src/presets/barba.d.ts +3 -1
  37. package/dist/types/src/product-state.d.ts +3 -1
  38. package/dist/types/src/server.d.ts +4 -4
  39. package/dist/types/src/store-html.d.ts +4 -4
  40. package/dist/types/src/version.d.ts +1 -0
  41. package/package.json +4 -1
  42. package/dist/esm/chunks/chunk-MRSDJPBC.js +0 -1
  43. package/dist/esm/chunks/chunk-QDHLXXAZ.js +0 -1
@@ -138,7 +138,9 @@ export interface Profile {
138
138
  firstName: string | null;
139
139
  lastName: string | null;
140
140
  }
141
- /** What a subscription action changed: the contract (pause, resume, cancel) or its next billing cycle (skip, unskip). */
141
+ /**
142
+ * What a subscription action changed: the contract (pause, resume, cancel) or its next billing cycle (skip, unskip).
143
+ */
142
144
  export type SubscriptionChange = {
143
145
  contract: {
144
146
  id: string | null;
@@ -1,2 +1,4 @@
1
- /** Called by the core with the events it buffered while this part loaded; the queue then handles events as they come. */
1
+ /**
2
+ * Called by the core with the events it buffered while this part loaded; the queue then handles events as they come.
3
+ */
2
4
  export declare function startAnalytics(queue: Event[]): Promise<void>;
@@ -147,14 +147,20 @@ export declare function forgetSavedCart(): void;
147
147
  export declare function keepQuietly(cart: ShopifyCart | null): void;
148
148
  /** Renders the document with the store's cart. */
149
149
  export declare function render(): void;
150
+ /**
151
+ * Why `tether:cart-updated` fired: `load` when the saved cart was loaded, failed to load or was forgotten; `pending`
152
+ * when quick clicks changed a quantity Shopify doesn't have yet, and `settled` once their last request is done; any
153
+ * other value names the change Shopify just answered. `docs/reference.md` lists them.
154
+ */
155
+ export type CartUpdateReason = 'load' | 'add' | 'update' | 'remove' | 'note' | 'attributes' | 'discount' | 'buyer-identity' | 'pending' | 'settled';
150
156
  /** @param reason The `reason` of `tether:cart-updated`. */
151
- export declare function announce(reason: string): void;
157
+ export declare function announce(reason: CartUpdateReason): void;
152
158
  /**
153
159
  * Keeps a cart Shopify sent after a change, shows it, and tells this page and the visitor's other tabs.
154
160
  *
155
161
  * @returns `cart`.
156
162
  */
157
- export declare function commit(cart: ShopifyCart | null, reason: string): ShopifyCart | null;
163
+ export declare function commit(cart: ShopifyCart | null, reason: CartUpdateReason): ShopifyCart | null;
158
164
  /** The outcome of loading the saved cart: the cart, `null` when there is none, or the failure. */
159
165
  export declare function settleLoad(outcome: {
160
166
  kind: 'loaded';
@@ -124,10 +124,15 @@ export declare function request<T>(conf: StorefrontConfig, query: QueryText, var
124
124
  export declare function gql<T>(query: QueryText, variables: Record<string, unknown>, isData: DataCheck<T>, options?: RequestOptions): Promise<T>;
125
125
  /** The check of `Tether.query()` and the server's `query()`, whose callers read `data` themselves. */
126
126
  export declare const hasData: (data: unknown) => data is object;
127
- /** `Tether.query()` and the server's `query()`: a document Tether didn't write, sent with `conf`. */
128
- export declare function untypedQuery<T>(conf: StorefrontConfig, text: string, variables?: Record<string, unknown>, options?: Omit<RequestOptions, 'operation'>): Promise<T>;
127
+ /**
128
+ * `Tether.query()` and the server's `query()`: a document Tether didn't write, sent with `conf`.
129
+ *
130
+ * @returns Shopify's `data`, checked only for being an object: the caller's own query decides its shape, so the caller
131
+ * checks the fields it reads.
132
+ */
133
+ export declare function untypedQuery(conf: StorefrontConfig, text: string, variables?: Record<string, unknown>, options?: Omit<RequestOptions, 'operation'>): Promise<object>;
129
134
  /** `Tether.query()`: `untypedQuery` with the browser's shared config. */
130
- export declare function query<T>(text: string, variables?: Record<string, unknown>, options?: Omit<RequestOptions, 'operation'>): Promise<T>;
135
+ export declare function query(text: string, variables?: Record<string, unknown>, options?: Omit<RequestOptions, 'operation'>): Promise<object>;
131
136
  /**
132
137
  * @param payload A mutation's payload.
133
138
  * @param name The mutation, for the error message.
@@ -5,7 +5,9 @@ interface PageHooks {
5
5
  mount: (root: Document) => unknown;
6
6
  unmount: () => void;
7
7
  }
8
- /** Records a mount of the whole document, so the `astro:page-load` of the same page sends no second round of requests. */
8
+ /**
9
+ * Records a mount of the whole document, so the `astro:page-load` of the same page sends no second round of requests.
10
+ */
9
11
  export declare function rememberDocumentMount(): void;
10
12
  /** Binds the document-wide listeners, once per page load of the script. */
11
13
  export declare function bindNavigation(hooks: PageHooks): void;
@@ -46,7 +46,9 @@ export declare const pageGlobal: (name: "TETHER_CONFIG" | "TETHER_INTEGRATION" |
46
46
  * `onLayoutChange` (else refreshes ScrollTrigger) and emits `tether:layout-changed`, also when either of those throws.
47
47
  */
48
48
  export declare function notifyLayoutChanged(reason: string): void;
49
- /** Notifies a layout change (`<reason>:images`) once every image in `root` that is still loading has loaded or failed. */
49
+ /**
50
+ * Notifies a layout change (`<reason>:images`) once every image in `root` that is still loading has loaded or failed.
51
+ */
50
52
  export declare function watchImages(root: ParentNode, reason: string): void;
51
53
  /**
52
54
  * Runs `task` with `aria-busy` on `el`; does nothing while `el` is already busy.
@@ -4,6 +4,7 @@ import { getProduct, getProducts, getRecommendations, clearProductCache, primePr
4
4
  import * as plans from './selling-plans.js';
5
5
  import { resolveProductKey } from './status.js';
6
6
  import { formatMoney, imageUrl } from './dom.js';
7
+ import { VERSION } from './version.js';
7
8
  import { setCountry } from './page-market.js';
8
9
  import { addGroup } from './controls/extras.js';
9
10
  import type { TetherConfig, TetherOptions, MarketsConfig } from './config.js';
@@ -11,13 +12,13 @@ import type { ShopifyCart } from './cart/store.js';
11
12
  import type { ProductScope } from './product.js';
12
13
  import type { DiagnoseOptions } from './diagnose.js';
13
14
  import type { TetherEvents } from './markup.js';
14
- export { addGroup, setCountry };
15
+ export { addGroup, setCountry, VERSION };
15
16
  export type { TetherOptions as TetherConfig, TetherConfig as ResolvedTetherConfig } from './config.js';
16
17
  export type { MarketsConfig, CartWarning } from './config.js';
17
18
  export type { Money } from './shopify-values.js';
18
19
  export type { Image as ShopifyImage, Metafield as ShopifyMetafield, Product as ShopifyProduct, ProductVariant as ShopifyVariant, SellingPlan as ShopifySellingPlanNode, SellingPlanAdjustmentValue, SellingPlanAllocation as ShopifySellingPlanAllocation, SellingPlanGroup as ShopifySellingPlanGroup, } from './fragments.js';
19
20
  export type { PlanInGroup as ShopifySellingPlan, PlanAdjustment, ProductWithPlans, VariantWithPlans, } from './selling-plans.js';
20
- export type { CartStatus, CartVariant as ShopifyCartVariant, ShopifyCart, ShopifyCartLine } from './cart/store.js';
21
+ export type { CartStatus, CartUpdateReason, CartVariant as ShopifyCartVariant, ShopifyCart, ShopifyCartLine, } from './cart/store.js';
21
22
  export type { Attributes, LineSpec as LineInput } from './cart/mutations.js';
22
23
  export type { TetherError, TetherErrorCode, GraphQLError, UserError } from './client.js';
23
24
  export type { ProductScope } from './product.js';
@@ -33,7 +34,6 @@ export type { AddressFields as CustomerAddressInput } from './account/operations
33
34
  export type { CustomerAddress, Fulfillment, MailingAddress, OrderDetail, OrderDetailLine, SubscriptionContract, SubscriptionLine, } from './account/page-answers.js';
34
35
  /** The helpers for selling plans, `Tether.plans`. */
35
36
  export type SellingPlanHelpers = typeof plans;
36
- export declare const VERSION = "0.7.2";
37
37
  /**
38
38
  * Mounts every product scope and product list inside `root`. Safe to call repeatedly.
39
39
  *
@@ -1,4 +1,4 @@
1
- import type { ShopifyCart } from './cart/store.js';
1
+ import type { CartUpdateReason, ShopifyCart } from './cart/store.js';
2
2
  import type { CartLineInput } from './cart/mutations.js';
3
3
  import type { CartWarning } from './config.js';
4
4
  import type { Product, ProductVariant } from './fragments.js';
@@ -23,8 +23,8 @@ export declare function qsa(root: ParentNode | null | undefined, selector: strin
23
23
  export declare const scoped: (root: Element | null | undefined, selector: string, scopeSelector: string) => HTMLElement[];
24
24
  /**
25
25
  * The events Tether dispatches, as `<prefix>:<name>` (`tether:cart-updated`), bubbling up to `document`, with the
26
- * detail each carries. `emit` takes only these, and `Tether.on()` passes on only the events `emit` dispatched, so a listener gets the
27
- * detail its event really has.
26
+ * detail each carries. `emit` takes only these, and `Tether.on()` passes on only the events `emit` dispatched, so a
27
+ * listener gets the detail its event really has.
28
28
  */
29
29
  export interface TetherEvents {
30
30
  ready: {
@@ -68,7 +68,7 @@ export interface TetherEvents {
68
68
  };
69
69
  'cart-updated': {
70
70
  cart: ShopifyCart | null;
71
- reason: string;
71
+ reason: CartUpdateReason;
72
72
  };
73
73
  'cart-toggled': {
74
74
  open: boolean;
@@ -125,7 +125,9 @@ export declare const ANALYTICS_EVENTS: readonly ["product-ready", "list-ready",
125
125
  export type AnalyticsEventName = (typeof ANALYTICS_EVENTS)[number];
126
126
  /** @returns The bubbling event `<prefix>:<name>`, known to `isOwnEvent`. */
127
127
  export declare function ownEvent<Name extends keyof TetherEvents>(name: Name, detail: TetherEvents[Name]): CustomEvent<TetherEvents[Name]>;
128
- /** @returns True for an event `ownEvent` created as `name`, false for any other, such as one another script dispatched. */
128
+ /**
129
+ * @returns True for an event `ownEvent` created as `name`, false for any other, such as one another script dispatched.
130
+ */
129
131
  export declare function isOwnEvent<Name extends keyof TetherEvents>(event: Event, name: Name): event is CustomEvent<TetherEvents[Name]>;
130
132
  /** Dispatches the bubbling event `<prefix>:<name>`. */
131
133
  export declare function emit<Name extends keyof TetherEvents>(name: Name, detail: TetherEvents[Name], target?: EventTarget): void;
@@ -21,7 +21,9 @@
21
21
  * Tether.unmount();
22
22
  */
23
23
  import type { TetherConfig } from '../config.js';
24
- /** `gsap`, `lenis` and `scrollTrigger` are getters, read each time they are used, so an instance made later is found. */
24
+ /**
25
+ * `gsap`, `lenis` and `scrollTrigger` are getters, read each time they are used, so an instance made later is found.
26
+ */
25
27
  interface BarbaPresetOptions {
26
28
  /** Default `window.gsap`. */
27
29
  gsap?: () => unknown;
@@ -98,7 +98,9 @@ export declare function initialChoice(product: Product, { variant, sellingPlan,
98
98
  * @returns `null` for a product without variants.
99
99
  */
100
100
  export declare function productView(product: Product, choice: ProductChoice, lowStock: number): ProductView | null;
101
- /** The `tether-bind` values that follow the variant and purchase. Thunks, so only the binds on the page are computed. */
101
+ /**
102
+ * The `tether-bind` values that follow the variant and purchase. Thunks, so only the binds on the page are computed.
103
+ */
102
104
  export declare function variantBindTexts(view: ProductView, format: Formatters): Map<string, () => BindText>;
103
105
  /**
104
106
  * The `tether-plan-bind` values of one plan in a plan list, for the variant.
@@ -42,8 +42,8 @@ interface HydrateOptions {
42
42
  images?: number;
43
43
  }
44
44
  /**
45
- * @returns `productPath` `/products` → `/products/<handle>`; templates with `{handle}` and `{id}` work too. `null` when
46
- * the path needs a handle or an id that is empty.
45
+ * @returns `productPath` `/products` → `/products/<handle>`; templates with `{handle}` and `{id}` work too. `null`
46
+ * when the path needs a handle or an id that is empty.
47
47
  */
48
48
  export declare function productUrl(handle: string, { productPath, id }?: {
49
49
  productPath?: string;
@@ -82,7 +82,7 @@ export declare function createStorefront(options?: StorefrontOptions): {
82
82
  id: string;
83
83
  } | null | undefined, intent?: "RELATED" | "COMPLEMENTARY") => Promise<Product[]>;
84
84
  config: ServerConfig;
85
- query: <T>(query: string, variables?: Record<string, unknown>, requestOptions?: {
85
+ query: (query: string, variables?: Record<string, unknown>, requestOptions?: {
86
86
  context?: boolean;
87
- }) => Promise<T>;
87
+ }) => Promise<object>;
88
88
  };
@@ -24,10 +24,10 @@
24
24
  * action, an email gate). An origin a site adds is trusted the same way.
25
25
  *
26
26
  * Not prevented: content wider than the description (a table or embed on a narrow screen, or a box given a large
27
- * width in pixels) overflows beside it, as in any HTML, and a capped shadow or outline still paints just past it. Tether
28
- * doesn't clip the element it fills (`contain: paint`, `overflow`), because that would cut off those wide tables and
29
- * embeds, stop margins collapsing through it and make it contain floats, changing how ordinary descriptions look. A
30
- * site that wants the clip sets it on that element in its own CSS.
27
+ * width in pixels) overflows beside it, as in any HTML, and a capped shadow or outline still paints just past it.
28
+ * Tether doesn't clip the element it fills (`contain: paint`, `overflow`), because that would cut off those wide
29
+ * tables and embeds, stop margins collapsing through it and make it contain floats, changing how ordinary
30
+ * descriptions look. A site that wants the clip sets it on that element in its own CSS.
31
31
  */
32
32
  /**
33
33
  * Store HTML as a fragment of content elements only.
@@ -0,0 +1 @@
1
+ export declare const VERSION = "0.8.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@occluze/tether",
3
- "version": "0.7.2",
3
+ "version": "0.8.1",
4
4
  "description": "Free, open-source alternative to Smootify and Storesynk (Shopyflow): Shopify products, cart and subscriptions in Webflow with HTML attributes. Optional Shopify to Webflow CMS sync.",
5
5
  "type": "module",
6
6
  "main": "dist/esm/index.js",
@@ -167,5 +167,8 @@
167
167
  "ignoreBinaries": [
168
168
  "tsc"
169
169
  ]
170
+ },
171
+ "overrides": {
172
+ "minimatch": "11.0.5"
170
173
  }
171
174
  }
@@ -1 +0,0 @@
1
- var e={diagnose:()=>import("./diagnose-3XHPZZNP.js"),markets:()=>import("./markets-ui-WBWWQAGU.js"),search:()=>import("./search-5NFIZBPJ.js"),extras:()=>import("./extras-C724KKG6.js"),account:()=>import("./account-W4FBRKXA.js"),"account-pages":()=>import("./account-pages-IM3OQTOP.js"),analytics:()=>import("./analytics-QDVOLZY3.js")},a=t=>e[t](),r=void 0;export{a,r as b};
@@ -1 +0,0 @@
1
- var S=Object.defineProperty;var G=(n,e,t)=>e in n?S(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var Fn=(n,e)=>{for(var t in e)S(n,t,{get:e[t],enumerable:!0})};var $n=(n,e,t)=>G(n,typeof e!="symbol"?e+"":e,t);var j=/^(\d{4})-(01|04|07|10)$/;function C(n){let e=j.exec(typeof n=="string"?n:"");return e?{year:Number(e[1]),month:Number(e[2])}:null}var R=n=>C(n)!==null,z=(n,e)=>`${n}-${String(e).padStart(2,"0")}`;function x(n,e=1){let t=C(n);if(!t)throw new Error(`not a quarterly Shopify API version: ${n}`);let o=t.year*4+(t.month-1)/3+e;return z(Math.floor(o/4),o%4*3+1)}function Hn(n,e=new Date){if(n==="unstable")return{version:n,ok:!1,note:'"unstable" changes without notice: pin a dated version such as 2026-07'};let t=C(n);if(!t)return{version:n,ok:!1,note:"not a quarterly version (YYYY-01, -04, -07 or -10)"};let o=new Date(Date.UTC(t.year,t.month-1,1)),r=new Date(Date.UTC(t.year,t.month-1+12,1)),i=(r.getTime()-e.getTime())/2630016e3,f=o<=e,c=`supported until about ${r.toISOString().slice(0,7)}`;return f?i<=0?c="no longer supported: Shopify falls back to the oldest supported version. Upgrade (see docs/reference.md)":i<3&&(c=`${c}: plan the upgrade to ${x(n)} or later (see docs/reference.md)`):c="not released yet (release candidate at best)",{version:n,ok:f&&i>0,monthsLeft:Math.round(i),next:x(n),note:c}}function O(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function Q(n,e){return O(n)?n[e]:void 0}function Z(n){return Array.isArray(n)?n:[]}function B(n){return typeof n=="string"&&n!==""?n:null}var W=n=>typeof n=="number"&&Number.isFinite(n)?n:null,Kn=n=>W(n)??0,E=(n,e)=>Z(n).map(t=>e(t)),Yn=(n,e)=>({nodes:E(Q(n,"nodes"),e)}),vn=n=>E(n,B).filter(e=>e!==null);var J=/^[A-Z]{2}$/,X=new Set(["XX","T1"]),q=new Set(["PT_BR","PT_PT","ZH_CN","ZH_TW"]),nn=/^[A-Z]{2,3}$/;function T(n){let e=(typeof n=="string"?n:"").trim().toUpperCase();return!J.test(e)||X.has(e)?null:e}function w(n){let e=(typeof n=="string"?n:"").trim().replace("-","_").toUpperCase();if(q.has(e))return e;let t=e.split("_")[0]??"";return nn.test(t)?t:null}var _="2026-07";var en=/^[A-Za-z0-9_.-]+$/,tn=/^(\$app(:[A-Za-z0-9_-]+)?|[A-Za-z0-9_.-]+)$/,on=/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,rn=/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/,sn=/^[A-Za-z_$][\w$]*$/,N="https://site.invalid",an=new Set(["localhost","127.0.0.1","[::1]"]),M=["saved","server","webflow"],un=["no-banner","default-banner","custom-banner"],y=n=>typeof n=="string"&&n!=="",ln=n=>typeof n=="function";function L(n,e){if(typeof n!="string"||!n)return"";let t=n.replace(/^https?:\/\//,"").replace(/\/.*$/,"");return gn(t)?t:(e("domain",n),"")}function U(n){if(!y(n))return!1;try{let e=new URL(n,`${N}/`);return e.origin===N?!0:e.protocol==="https:"||e.protocol==="http:"&&an.has(e.hostname)}catch{return!1}}function I(n,e){return n==null||n===""?null:typeof n=="string"&&(U(n)||cn(n))?n:(e("partsUrl",n),null)}function cn(n){if(typeof location>"u")return!1;try{return new URL(n).origin===location.origin}catch{return!1}}function fn(n){if(typeof n!="string")return null;try{let e=new URL(n);return e.protocol==="https:"&&e.href===new URL(e.origin).href?e.origin:null}catch{return null}}function F(n,e){if(!Array.isArray(n))return e("embedOrigins",n),[];let t=[],o=n;for(let r of o){let i=fn(r);i?t.push(i):e("embedOrigin",r)}return t}function dn(n){let e,t;if(typeof n=="string"){let o=n.indexOf(".");e=o>0?n.slice(0,o):"",t=n.slice(o+1)}else typeof n=="object"&&n!==null&&(e=Reflect.get(n,"namespace"),t=Reflect.get(n,"key"));return typeof e!="string"||typeof t!="string"?null:tn.test(e)&&en.test(t)?{namespace:e,key:t}:null}function $(n,e){if(!Array.isArray(n))return e("metafields",n),[];let t=[],o=n;for(let r of o){let i=dn(r);i?t.push(typeof r=="string"?r:i):e("metafield",r)}return t}var d=n=>e=>n(e)?e:void 0,gn=n=>y(n)&&on.test(n),pn=n=>y(n)&&rn.test(n),yn=n=>typeof n=="boolean"||y(n)&&sn.test(n),p=d(U),k=d(y),P=d(n=>typeof n=="boolean"),V=d(ln);function m(n,e,t,o){if(e==null)return null;if(!O(e))return o(n,e),null;let r={},i=t;for(let[f,c]of Object.entries(i)){let h=e[f];if(h===void 0)continue;let A=c(h);A===void 0?o(`${n}.${f}`,h):r[f]=A}return r}var mn={server:p,orderUrl:p,subscriptionsUrl:p,paymentUrl:p,logoutUrl:p,locale:k,navigate:V},On="customer accounts need the Worker since 0.7.0: set account.server",kn={country:k,language:k,locale:k},hn={detect:n=>{if(typeof n=="boolean")return n;let e=Array.isArray(n)?n:[n];return typeof n=="string"||Array.isArray(n)?M.filter(t=>e.includes(t)):void 0},locales:n=>{if(!O(n))return;let e={};for(let[t,o]of Object.entries(n)){let r=m(`markets.locales.${t}`,o,kn,()=>{});r&&(e[t]=r)}return e},cookie:d(pn),remember:P,strict:P},Cn={consent:n=>un.find(e=>e===n),proxy:n=>n!==void 0&&!!n},Tn={dataLayer:d(yn),shopify:n=>typeof n=="boolean"?n:m("analytics.shopify",n,Cn,()=>{})??void 0,onEvent:V};function H(n,e,t){let o=m("account",n,mn,e);if(o===null)return null;let{server:r}=o;return r===void 0?(t(On),null):{...o,server:r}}var b=(n,e)=>m("markets",n,hn,e),D=(n,e)=>m("analytics",n,Tn,e);var u={domain:"",token:"",apiVersion:_,country:void 0,language:void 0,locale:void 0,markets:null,prefix:"tether",productPath:"/product",collectionPath:"/collection",metafields:[],embedOrigins:[],imagesFirst:25,variantsFirst:100,sellingPlanGroupsFirst:10,sellingPlansFirst:25,collectionFirst:24,retries:2,revalidate:!0,storageKey:"",cartDrawerOpenClass:"is-open",openCartOnAdd:!0,cartFocus:!0,checkoutTarget:"_self",defaultPurchase:"one-time",variantUrl:!1,maxAge:60,lowStock:5,searchDelay:150,autoMount:!0,observe:!1,astro:!0,partsUrl:null,analytics:null,account:null,warningText:null,formatMoney:null,onLayoutChange:null,onCartOpen:null,onCartClose:null,onLineEnter:null,onLineLeave:null,onValueChange:null,onError:null,debug:!1},s={...u};function v(n){let e=t=>(l(`Tether.config is read-only (${String(t)}): pass options to Tether.init() instead`),!1);return new Proxy(n,{get(t,o){let r=Reflect.get(t,o);return typeof r=="object"&&r!==null?v(r):r},set:(t,o)=>e(o),deleteProperty:(t,o)=>e(o),defineProperty:(t,o)=>e(o)})}var ee=v(s),wn=/^[a-z][a-z0-9-]*$/,bn=["revalidate","openCartOnAdd","cartFocus","variantUrl","autoMount","observe","astro","debug"],An=["token","productPath","collectionPath","cartDrawerOpenClass"],Sn=["imagesFirst","variantsFirst","sellingPlanGroupsFirst","sellingPlansFirst","collectionFirst","retries","maxAge","lowStock","searchDelay"],xn=["warningText","formatMoney","onLayoutChange","onCartOpen","onCartClose","onLineEnter","onLineLeave","onValueChange","onError"];function g(n,e,t){return e!==void 0&&l(`invalid ${n} ${JSON.stringify(e)}: using ${JSON.stringify(t)}`),t}function a(n,e){l(`invalid ${n} ${JSON.stringify(e)}: ignored`)}function Rn(n){for(let e of Object.keys(n))e in u||l(`unknown option ${JSON.stringify(e)}: ignored`)}function En(n){return typeof n=="function"?n:null}function _n(n){return Object.fromEntries(xn.map(t=>[t,En(n[t])]))}function Nn(n,e){return typeof e=="number"&&Number.isInteger(e)&&e>=0?e:g(n,e,u[n])}function Pn(n,e){return typeof e=="boolean"?e:g(n,e,u[n])}function Mn(n,e){return typeof e=="string"?e:g(n,e,u[n])}function Ln(n){if(!(n==null||n==="")){try{if(typeof n=="string"&&Intl.getCanonicalLocales(n).length)return n}catch{}a("locale",n)}}function K(n,e,t){return t.find(o=>o===e)??g(n,e,t[0])}function Un(n){return n==="unstable"?(l('apiVersion "unstable" changes without notice. Pin a dated version (e.g. 2026-07).'),n):R(n)?n:g("apiVersion",n,u.apiVersion)}function Y(n,e,t){if(e==null||e==="")return;let o=t(e);if(o!==null)return o;a(n,e)}function In(n){Rn(n);let e=L(n.domain,a),t=typeof n.prefix=="string"&&wn.test(n.prefix)?n.prefix:g("prefix",n.prefix,u.prefix),o={...u,..._n(n),domain:e,apiVersion:Un(n.apiVersion),country:Y("country",n.country,T),locale:Ln(n.locale),partsUrl:I(n.partsUrl,a),language:Y("language",n.language,w),markets:b(n.markets,a),analytics:D(n.analytics,a),account:H(n.account,a,l),prefix:t,storageKey:typeof n.storageKey=="string"&&n.storageKey?n.storageKey:`${t}:cart:${e}`,metafields:$(n.metafields??[],a),embedOrigins:F(n.embedOrigins??[],a),checkoutTarget:K("checkoutTarget",n.checkoutTarget,["_self","_blank"]),defaultPurchase:K("defaultPurchase",n.defaultPurchase,["one-time","subscription"])};for(let r of Sn)o[r]=Nn(r,n[r]);for(let r of bn)o[r]=Pn(r,n[r]);for(let r of An)o[r]=Mn(r,n[r]);return o}var te=n=>b(n,a);function oe(n={}){let e=In(n);for(let t of Object.keys(s))t in e||Reflect.deleteProperty(s,t);return Object.assign(s,e)}var re=()=>!!(s.domain&&s.token);function ie(...n){s.debug&&console.log(`[${s.prefix}]`,...n)}function l(...n){console.warn(`[${s.prefix}]`,...n)}function se(n,e){if(l(e,n instanceof Error&&n.message?n.message:n),!!s.onError)try{s.onError(n,e)}catch(t){l("onError threw",t)}}function le(n){return n instanceof Error?n.message:String(n)}var fe={domain:["PUBLIC_SHOPIFY_DOMAIN","PUBLIC_SHOPIFY_STORE_DOMAIN","SHOPIFY_DOMAIN"],token:["PUBLIC_SHOPIFY_STOREFRONT_TOKEN","PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN","SHOPIFY_STOREFRONT_TOKEN"]};function de(n){if(typeof n!="string")return!1;try{return new URL(n).protocol==="https:"}catch{return!1}}function ge(n){return/^shp[a-z]{2}_/.test(n.trim())}function pe(n,e){if(!n)return"";let t=parseFloat(n.amount);if(Number.isNaN(t))return"";try{return new Intl.NumberFormat(e||void 0,{style:"currency",currency:n.currencyCode}).format(t)}catch{return`${n.currencyCode} ${t.toFixed(2)}`}}function ye(n,e,t){if(!/\{(handle|id)\}/.test(n))return e?`${n.replace(/\/$/,"")}/${encodeURIComponent(e)}`:null;let o=t?t.split("/").at(-1)??"":"";return n.includes("{handle}")&&!e||n.includes("{id}")&&!o?null:n.replace(/\{handle\}/g,encodeURIComponent(e??"")).replace(/\{id\}/g,encodeURIComponent(o))}function me(n){let e=String(n??"").trim();return e?e.startsWith("gid://")?e:/^\d+$/.test(e)?`gid://shopify/Product/${e}`:/\/products\/([^/?#]+)/.exec(e)?.[1]??e:null}export{Fn as a,$n as b,Hn as c,O as d,Q as e,Z as f,B as g,W as h,Kn as i,E as j,Yn as k,vn as l,M as m,dn as n,T as o,w as p,u as q,s as r,ee as s,In as t,te as u,oe as v,re as w,ie as x,l as y,se as z,le as A,fe as B,de as C,ge as D,pe as E,ye as F,me as G};