@occluze/tether 0.6.5 → 0.6.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@occluze/tether",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
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",
@@ -124,14 +124,14 @@ async function renderOrder(el) {
124
124
  const t = f.trackingInformation?.[0] || {};
125
125
  qsa(row, sel('fulfillment-bind')).concat(row.matches(sel('fulfillment-bind')) ? [row] : []).forEach((b) => {
126
126
  const k = get(b, 'fulfillment-bind');
127
- if (k === 'url') { if (https(t.url)) b.setAttribute('href', t.url); return; }
127
+ if (k === 'url') { const ok = https(t.url); if (ok) b.setAttribute('href', t.url); show(b, ok); return; } // no tracking link: hidden
128
128
  const v = { status: lower(f.latestShipmentStatus || f.status), date: date(f.createdAt), eta: f.estimatedDeliveryAt ? date(f.estimatedDeliveryAt) : '', company: t.company || '', number: t.number || '' }[k];
129
129
  if (v != null) setText(b, v);
130
130
  });
131
131
  }));
132
132
  showIn(el, 'order-show', {
133
133
  loading: false, ready: true, error: false, 'not-found': false, cancelled: Boolean(o.cancelledAt), shipped: ships.length > 0,
134
- returnable: [...returnable.values()].some((q) => q > 0), 'has-returns': (o.returns?.nodes || []).length > 0, 'return-requested': el.dataset.tetherReturned === '1',
134
+ returnable: [...returnable.values()].some((q) => q > 0), 'has-returns': el.dataset.tetherReturned !== '1' && (o.returns?.nodes || []).length > 0, 'return-requested': el.dataset.tetherReturned === '1',
135
135
  });
136
136
  state('ready');
137
137
  }
@@ -147,9 +147,13 @@ async function renderAddresses(root) {
147
147
  const boxes = qsa(root, sel('addresses'));
148
148
  if (!boxes.length) return;
149
149
  showGlobal(root, { 'addresses-loading': true, 'addresses-empty': false });
150
- let list = [];
151
- try { list = addressCache = await addresses(); } catch (err) { reportError(err, 'addresses'); }
152
- showGlobal(root, { 'addresses-loading': false, 'addresses-empty': list.length === 0 });
150
+ let list;
151
+ try { list = addressCache = await addresses(); } catch (err) {
152
+ reportError(err, 'addresses'); // not "no addresses yet": keep what's shown
153
+ showGlobal(root, { 'addresses-loading': false, 'addresses-error': true });
154
+ return;
155
+ }
156
+ showGlobal(root, { 'addresses-loading': false, 'addresses-empty': list.length === 0, 'addresses-error': false });
153
157
  boxes.forEach((box) => repeat(box, list, (row, a) => {
154
158
  row.dataset.tetherAddress = a.id;
155
159
  qsa(row, sel('address-bind')).concat(row.matches(sel('address-bind')) ? [row] : []).forEach((b) => {
@@ -174,9 +178,13 @@ async function renderSubscriptions(root) {
174
178
  const boxes = qsa(root, sel('subscriptions'));
175
179
  if (!boxes.length) return;
176
180
  showGlobal(root, { 'subscriptions-loading': true, 'subscriptions-empty': false });
177
- let list = [];
178
- try { list = await subscriptions(); } catch (err) { reportError(err, 'subscriptions'); }
179
- showGlobal(root, { 'subscriptions-loading': false, 'subscriptions-empty': list.length === 0 });
181
+ let list;
182
+ try { list = await subscriptions(); } catch (err) {
183
+ reportError(err, 'subscriptions');
184
+ showGlobal(root, { 'subscriptions-loading': false, 'subscriptions-error': true });
185
+ return;
186
+ }
187
+ showGlobal(root, { 'subscriptions-loading': false, 'subscriptions-empty': list.length === 0, 'subscriptions-error': false });
180
188
  boxes.forEach((box) => repeat(box, list, (row, c) => {
181
189
  row.dataset.tetherSubscription = c.id;
182
190
  row.setAttribute(attr('subscription-status'), lower(c.status));
@@ -225,6 +233,7 @@ export async function renderPages(root = document) {
225
233
 
226
234
  const fieldsOf = (form) => Object.fromEntries([...form.elements].filter((i) => i.name && i.type !== 'submit' && i.type !== 'button' && i.type !== 'checkbox').map((i) => [i.name, i.value]));
227
235
  async function act(el, fn, { error } = {}) {
236
+ if (el.getAttribute('aria-busy') === 'true') return undefined; // already sending: no second request (Enter, double click)
228
237
  el.classList.add('is-busy'); el.setAttribute('aria-busy', 'true');
229
238
  el.setAttribute(attr('form-state'), 'pending');
230
239
  qsa(el, sel('form-error')).forEach((e) => setText(e, ''));
@@ -246,14 +255,14 @@ function bindPages() {
246
255
  const f = e.target;
247
256
  if (f.matches?.(sel('profile-form'))) {
248
257
  e.preventDefault();
249
- act(f, () => updateProfile(fieldsOf(f)));
258
+ act(f, async () => { await updateProfile(fieldsOf(f)); await ctx.bindCustomer?.(document); });
250
259
  } else if (f.matches?.(sel('address-form'))) {
251
260
  e.preventDefault();
252
261
  const id = f.dataset.tetherAddressId || undefined;
253
262
  const isDefault = Boolean(f.elements?.isDefault?.checked);
254
263
  act(f, async () => { await saveAddress(fieldsOf(f), { id, isDefault }); f.reset(); delete f.dataset.tetherAddressId; await renderAddresses(document); });
255
264
  }
256
- });
265
+ }, true); // capture: before a router (Astro's ClientRouter) turns the submit into a navigation with the fields in the URL
257
266
  document.addEventListener('input', (e) => { if (e.target.closest?.(sel('profile-form'))) e.target.dataset.tetherTouched = '1'; });
258
267
  document.addEventListener('click', (e) => {
259
268
  const t = e.target;
@@ -283,9 +292,13 @@ function bindPages() {
283
292
  const sub = btn.closest('[data-tether-subscription]');
284
293
  const a = get(btn, 'subscription-action');
285
294
  if (!sub || !SUB_ACTIONS.includes(a) || btn.disabled || !confirmOk(btn)) return;
295
+ const id = sub.dataset.tetherSubscription;
286
296
  sub.setAttribute(attr('subscription-state'), 'pending');
287
- act(sub, async () => { await subscriptionAction(sub.dataset.tetherSubscription, a); await renderSubscriptions(document); }).then(() => {
288
- sub.setAttribute(attr('subscription-state'), sub.getAttribute(attr('form-state')) === 'error' ? 'error' : 'done');
297
+ act(sub, async () => { await subscriptionAction(id, a); await renderSubscriptions(document); }).then(() => {
298
+ const state = sub.getAttribute(attr('form-state')) === 'error' ? 'error' : 'done';
299
+ // The re-render may have replaced the row: mark the one that shows this subscription now.
300
+ qsa(document, '[data-tether-subscription]').filter((r) => r === sub || r.dataset.tetherSubscription === id)
301
+ .forEach((r) => r.setAttribute(attr('subscription-state'), state));
289
302
  });
290
303
  } else if ((btn = t.closest?.(sel('order-return')))) {
291
304
  e.preventDefault();
package/src/account.js CHANGED
@@ -271,14 +271,12 @@ export async function render(root = document) {
271
271
  a.setAttribute('href', u || `https://${cfg.domain}/account`);
272
272
  });
273
273
  if (!logged) return;
274
- const binds = qsa(root, sel('account-bind'));
275
- if (binds.length) {
276
- const c = await customer().catch((err) => { reportError(err, 'account'); return null; });
277
- binds.forEach((el) => {
278
- const v = { 'first-name': c?.firstName, 'last-name': c?.lastName, name: c?.displayName, email: c?.emailAddress?.emailAddress, address: c?.defaultAddress?.formatted?.join(', ') }[get(el, 'account-bind')];
279
- if (v != null) setText(el, v);
280
- });
281
- }
274
+ await bindCustomer(root);
275
+ // The order list and the account pages (order, addresses, subscriptions) load side by side.
276
+ await Promise.all([renderOrderList(root), PAGE_ATTRS.some((n) => qsa(root, sel(n)).length) ? pages().then((m) => m.renderPages(root)) : null]);
277
+ }
278
+
279
+ async function renderOrderList(root) {
282
280
  const lists = qsa(root, sel('orders'));
283
281
  if (lists.length) {
284
282
  // tether-show="orders-loading" / "orders-empty" (no orders yet).
@@ -305,7 +303,6 @@ export async function render(root = document) {
305
303
  if (get(node, 'order-bind') === 'url' && orderUrl(o)) node.setAttribute('href', orderUrl(o));
306
304
  }));
307
305
  }
308
- if (PAGE_ATTRS.some((n) => qsa(root, sel(n)).length)) await (await pages()).renderPages(root);
309
306
  }
310
307
 
311
308
 
@@ -331,8 +328,18 @@ function fillLines(box, items) {
331
328
  // only on pages that use them. It gets this module's login state, so both share one session.
332
329
  const PAGE_ATTRS = ['order', 'addresses', 'subscriptions', 'profile-form', 'address-form'];
333
330
  let pagesPart = null;
331
+ /** tether-account-bind: the customer's name, email, default address (again after a profile change). */
332
+ async function bindCustomer(root) {
333
+ const binds = qsa(root, sel('account-bind'));
334
+ if (!binds.length) return;
335
+ const c = await customer().catch((err) => { reportError(err, 'account'); return null; });
336
+ binds.forEach((el) => {
337
+ const v = { 'first-name': c?.firstName, 'last-name': c?.lastName, name: c?.displayName, email: c?.emailAddress?.emailAddress, address: c?.defaultAddress?.formatted?.join(', ') }[get(el, 'account-bind')];
338
+ if (v != null) setText(el, v);
339
+ });
340
+ }
334
341
  function pages() {
335
- pagesPart ||= loadPart('account-pages').then((m) => { m.setup({ server, serverFetch, query, customer, reset: () => { customerCache = null; serverState = null; } }); return m; });
342
+ pagesPart ||= loadPart('account-pages').then((m) => { m.setup({ server, serverFetch, query, customer, bindCustomer, reset: () => { customerCache = null; serverState = null; } }); return m; });
336
343
  return pagesPart;
337
344
  }
338
345
  const viaPages = (name) => (...a) => pages().then((m) => m[name](...a));
package/src/cart.js CHANGED
@@ -261,22 +261,30 @@ export const Cart = {
261
261
 
262
262
  /** Cart-level attributes, merged with existing ones. Value '' removes a key. */
263
263
  setAttributes(obj) {
264
- const merged = new Map((this.state?.attributes || []).map((a) => [a.key, a.value]));
265
- toAttributes(obj).forEach((a) => merged.set(a.key, a.value));
266
- const attributes = [...merged].filter(([, v]) => v !== '').map(([key, value]) => ({ key, value }));
267
- return this._queue(async () => this._commit(
268
- await this._mutate('cartAttributesUpdate', '$attributes: [AttributeInput!]!', 'attributes: $attributes', { attributes }, { attributes }),
269
- 'attributes',
270
- ));
264
+ const add = toAttributes(obj);
265
+ // Merged in the queue, with the cart as it is by then: quick calls in a row don't drop each other.
266
+ return this._queue(async () => {
267
+ const merged = new Map((this.state?.attributes || []).map((a) => [a.key, a.value]));
268
+ add.forEach((a) => merged.set(a.key, a.value));
269
+ const attributes = [...merged].filter(([, v]) => v !== '').map(([key, value]) => ({ key, value }));
270
+ return this._commit(
271
+ await this._mutate('cartAttributesUpdate', '$attributes: [AttributeInput!]!', 'attributes: $attributes', { attributes }, { attributes }),
272
+ 'attributes',
273
+ );
274
+ });
271
275
  },
272
276
 
273
277
  /** Replaces the discount codes. Pass [] to remove all. */
274
278
  setDiscountCodes(codes) {
275
- const discountCodes = (Array.isArray(codes) ? codes : [codes]).map((c) => String(c).trim()).filter(Boolean);
276
- return this._queue(async () => this._commit(
277
- await this._mutate('cartDiscountCodesUpdate', '$discountCodes: [String!]!', 'discountCodes: $discountCodes', { discountCodes }, { discountCodes }),
278
- 'discount',
279
- ));
279
+ return this._queue(async () => {
280
+ // A function gets the codes as they are by then (applyDiscount/removeDiscount in quick succession).
281
+ const list = typeof codes === 'function' ? codes((this.state?.discountCodes || []).map((d) => d.code)) : codes;
282
+ const discountCodes = (Array.isArray(list) ? list : [list]).map((c) => String(c).trim()).filter(Boolean);
283
+ return this._commit(
284
+ await this._mutate('cartDiscountCodesUpdate', '$discountCodes: [String!]!', 'discountCodes: $discountCodes', { discountCodes }, { discountCodes }),
285
+ 'discount',
286
+ );
287
+ });
280
288
  },
281
289
 
282
290
  /**
@@ -284,8 +292,7 @@ export const Cart = {
284
292
  * it's removed again and the promise rejects with code INVALID_DISCOUNT.
285
293
  */
286
294
  async applyDiscount(code) {
287
- const current = (this.state?.discountCodes || []).map((d) => d.code);
288
- const cart = await this.setDiscountCodes([...new Set([...current, code])]);
295
+ const cart = await this.setDiscountCodes((current) => [...new Set([...current, code])]);
289
296
  const hit = (cart?.discountCodes || []).find((d) => d.code.toLowerCase() === String(code).toLowerCase());
290
297
  if (hit?.applicable) return cart;
291
298
  await this.removeDiscount(code).catch(() => {});
@@ -294,7 +301,7 @@ export const Cart = {
294
301
 
295
302
  removeDiscount(code) {
296
303
  const k = String(code).toLowerCase();
297
- return this.setDiscountCodes((this.state?.discountCodes || []).map((d) => d.code).filter((c) => c.toLowerCase() !== k));
304
+ return this.setDiscountCodes((current) => current.filter((c) => c.toLowerCase() !== k));
298
305
  },
299
306
 
300
307
  /** { countryCode, email, phone } — changes currency/prices for that market. */
@@ -322,8 +329,10 @@ export const Cart = {
322
329
  if (tab) { try { tab.opener = null; } catch { /* ignore */ } }
323
330
 
324
331
  try {
325
- const data = await gql('query TetherCheckout($id: ID!) { cart(id: $id) { checkoutUrl } }', { id });
326
- let url = (this.beforeCheckout && await this.beforeCheckout().catch(() => null)) || data.cart?.checkoutUrl;
332
+ // Side by side: the cart's current checkout URL, and the account's own (beforeCheckout) if any.
333
+ const fresh = gql('query TetherCheckout($id: ID!) { cart(id: $id) { checkoutUrl } }', { id }).then((d) => d.cart?.checkoutUrl);
334
+ fresh.catch(() => {}); // not needed when beforeCheckout answers
335
+ let url = (this.beforeCheckout && await this.beforeCheckout().catch(() => null)) || await fresh;
327
336
  if (url && this.customerAccessToken) url += `${url.includes('?') ? '&' : '?'}logged_in=true`;
328
337
  if (!url) throw new TetherError('No checkoutUrl (cart empty or expired)');
329
338
  emit('checkout', { url, cart: this.state });
package/src/diagnose.js CHANGED
@@ -23,7 +23,7 @@ const SHOW = new Set([
23
23
  'subscription-selected', 'one-time-selected', 'has-savings', 'loading', 'ready', 'error', 'not-found',
24
24
  'cart-empty', 'cart-filled', 'cart-has-subscription', 'cart-no-subscription', 'cart-has-discount', 'cart-error', 'cart-warning',
25
25
  'list-empty', 'list-filled', 'search-empty', 'search-results', 'logged-in', 'logged-out', 'orders-empty', 'orders-loading',
26
- 'addresses-loading', 'addresses-empty', 'subscriptions-loading', 'subscriptions-empty',
26
+ 'addresses-loading', 'addresses-empty', 'addresses-error', 'subscriptions-loading', 'subscriptions-empty', 'subscriptions-error',
27
27
  ]);
28
28
  const BIND = new Set([
29
29
  'title', 'description', 'description-text', 'vendor', 'type', 'handle', 'published-at', 'price', 'total-price',
package/src/index.js CHANGED
@@ -21,14 +21,16 @@ import { attr, sel, get, qsa, emit, formatMoney, busy, parseJSONAttr, toAttribut
21
21
  import { loadPart, coreModules } from './lazy.js';
22
22
  import { mountedLists, liveLists, pruneLive, within, mountProduct, retryFailed, hydrateFromPage, settleMarket, trackMarket } from './mounting.js';
23
23
 
24
- export const VERSION = '0.6.5';
24
+ export const VERSION = '0.6.7';
25
25
 
26
26
  let initPromise = null;
27
27
  let observer = null;
28
+ let mountedBody = null; // the page body mount(document) last ran on (Astro's first page-load repeats it)
28
29
 
29
30
  /** Mount every product scope and product list inside `root`. Safe to call repeatedly. */
30
31
  export function mount(root = document) {
31
32
  if (!isConfigured()) return 0;
33
+ if (root === document) mountedBody = document.body;
32
34
  let count = 0;
33
35
  pruneLive(); // page transitions detach old roots: don't keep them alive
34
36
  hydrateFromPage(root); // products the server already rendered: no request needed
@@ -198,9 +200,9 @@ function bindControls() {
198
200
  const differs = target?.country && (String(target.country).toUpperCase() !== String(cfg.country || '').toUpperCase()
199
201
  || String(target.language || '').toUpperCase() !== String(cfg.language || '').toUpperCase());
200
202
  if (differs) setCountry(target.country, { language: target.language ?? null, locale: target.locale, remember: false }).then(() => mount(document), () => mount(document));
201
- else mount(document);
203
+ else if (mountedBody !== document.body) mount(document); // the first load is already mounted: no second round of requests
202
204
  }));
203
- document.addEventListener('astro:before-swap', () => unmount());
205
+ document.addEventListener('astro:before-swap', () => { mountedBody = null; unmount(); });
204
206
  }
205
207
 
206
208
  // Back online after a failed load: try the failed products and lists again.
@@ -1 +0,0 @@
1
- import{a as Q}from"./chunk-VPVJPNB4.js";import{b as h}from"./chunk-L2TRRKYV.js";import"./chunk-FIOZPPC5.js";import"./chunk-AJLPU2JC.js";import{A as R,B as $,D as x,G as q,b as a,e as X,g as A,h as p,o as f,p as k,s as y,u as T,w as Y}from"./chunk-K2YEQAIH.js";import"./chunk-VC46IEJQ.js";var N=()=>`${a.prefix}:account:${a.domain}`,J=()=>`${a.prefix}:account-login:${a.domain}`,O=()=>a.account?.remember?window.localStorage:window.sessionStorage,et=t=>btoa(String.fromCharCode(...new Uint8Array(t))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""),j=()=>et(crypto.getRandomValues(new Uint8Array(32))),ut=async t=>et(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t))),E=t=>(a.account?.navigate||(e=>window.location.assign(e)))(t),M=(t,e)=>{try{return JSON.parse(t.getItem(e)||"null")}catch{return null}},D=(t,e,n)=>{try{n?t.setItem(e,JSON.stringify(n)):t.removeItem(e)}catch{}},v=null,c=null,B=null,I=null,w=()=>a.account?.server?new URL(String(a.account.server),window.location.href).href.replace(/\/$/,""):"",z=()=>`${a.prefix}:account-hint:${a.domain}`,b=null;async function U(t,{method:e="GET",body:n}={}){let o=await fetch(`${w()}${t}`,{method:e,credentials:"include",headers:e==="POST"?{"Content-Type":"application/json","X-Tether-Account":"1"}:{},body:n?JSON.stringify(n):void 0}),r=await o.json().catch(()=>({}));if(!o.ok&&o.status!==401)throw new p(`Customer accounts: ${r.error||o.status}`,{status:o.status,userErrors:r.userErrors});return r}async function H(){b||(b=await U("/me"));try{b.loggedIn?window.localStorage.setItem(z(),"1"):window.localStorage.removeItem(z())}catch{}return b}async function P(){if(v)return v;let t=a.account?.shopDomain||a.domain,e=r=>fetch(`https://${t}/.well-known/${r}`).then(s=>{if(!s.ok)throw new p(`Customer accounts: ${r} answered ${s.status}`,{status:s.status});return s.json()}),[n,o]=await Promise.all([e("openid-configuration"),e("customer-account-api")]);return v={...n,graphql:o.graphql_api},v}var lt=()=>a.account?.callbackUrl||`${window.location.origin}${window.location.pathname}`;function nt(){return w()?!!b?.loggedIn:!!(c?.refresh||c?.access&&c.expiresAt>Date.now())}async function dt({returnTo:t=window.location.href,locale:e}={}){if(w()){let d=new URL(`${w()}/login`);d.searchParams.set("returnTo",t);let g=e||a.account.locale||(a.locale||"").split("-")[0];g&&d.searchParams.set("locale",g),a.country&&d.searchParams.set("country",String(a.country).toUpperCase()),E(d.toString());return}if(!a.account?.clientId)throw new p("Customer accounts: set account.clientId",{code:"NOT_CONFIGURED"});let n=await P(),o=j(),r=j(),s=j(),i=lt();D(window.sessionStorage,J(),{state:o,nonce:r,verifier:s,redirect:i,returnTo:t,at:Date.now()});let u=new URL(n.authorization_endpoint),m={client_id:a.account.clientId,scope:"openid email customer-account-api:full",response_type:"code",redirect_uri:i,state:o,nonce:r,code_challenge:await ut(s),code_challenge_method:"S256"},l=e||a.account.locale||(a.locale||"").split("-")[0];l&&(m.locale=l),a.country&&(m.region_country=String(a.country).toUpperCase()),Object.entries(m).forEach(([d,g])=>u.searchParams.set(d,g)),E(u.toString())}async function ot(t){let e=await P(),n=await fetch(a.account.tokenUrl||e.token_endpoint,{method:"POST",body:new URLSearchParams(t)}),o=await n.json().catch(()=>({}));if(!n.ok||!o.access_token)throw new p(`Customer accounts: token ${n.status} ${o.error||""}`.trim(),{status:n.status,code:n.status===400||n.status===401?"SESSION_ENDED":"TOKEN_FAILED"});return o}function ft(t){try{return JSON.parse(atob(t.split(".")[1].replace(/-/g,"+").replace(/_/g,"/")))}catch{return null}}function rt(t,e=c){c={access:t.access_token,expiresAt:Date.now()+Math.max(0,(Number(t.expires_in)||3600)-120)*1e3,refresh:t.refresh_token||e?.refresh,idToken:t.id_token||e?.idToken},D(O(),N(),c)}async function ht(){let t=new URLSearchParams(window.location.search),e=M(window.sessionStorage,J());if(!e||!t.has("code")&&!t.has("error")||t.get("state")!==e.state)return!1;D(window.sessionStorage,J(),null);let n=new URL(window.location.href);if(["code","state","iss","error","error_description"].forEach(m=>n.searchParams.delete(m)),window.history.replaceState(window.history.state,"",n),t.has("error"))return T("account-error",{error:t.get("error")}),!1;if(Date.now()-e.at>10*6e4)throw new p("Customer accounts: the login took too long, please try again");let o=await ot({grant_type:"authorization_code",client_id:a.account.clientId,redirect_uri:e.redirect,code:t.get("code"),code_verifier:e.verifier}),r=await P(),s=ft(o.id_token||""),i=[].concat(s?.aud||[]);if(!s||s.nonce!==e.nonce||s.iss!==r.issuer||!i.includes(a.account.clientId)||s.exp*1e3<Date.now())throw new p("Customer accounts: the login answer did not check out (nonce/issuer/audience)");rt(o,null),await st(),T("account-login",{});let u=e.returnTo&&new URL(e.returnTo,window.location.href);return u&&u.origin===window.location.origin&&u.href!==n.href&&E(u.href),!0}async function C(){return w()||(c||(c=M(O(),N())),!c)?null:c.access&&c.expiresAt>Date.now()?c.access:c.refresh?(B||(B=(async()=>{try{rt(await ot({grant_type:"refresh_token",client_id:a.account.clientId,refresh_token:c.refresh})),await st()}catch(t){if(t.code==="SESSION_ENDED")F();else throw t}finally{B=null}})()),await B,c?.access||null):(F(),null)}function F(){c=null,I=null,D(O(),N(),null),h.customerAccessToken=null}async function st(){h.customerAccessToken=c?.access||null,h.id()&&c?.access&&await h.setBuyerIdentity({customerAccessToken:c.access},{create:!1}).catch(t=>A(t,"account cart"))}async function V(t,e={}){if(w())throw new p("Customer accounts in server mode only answer customer() and orders()",{code:"NOT_ALLOWED"});let n=await C();if(!n)throw new p("Not logged in",{code:"NOT_LOGGED_IN"});let o=await P(),r=u=>fetch(o.graphql,{method:"POST",headers:{"Content-Type":"application/json",Authorization:u},body:JSON.stringify({query:t,variables:e})}),s=await r(n);s.status===401&&c?.refresh&&(c.expiresAt=0,s=await r(await C()));let i=await s.json().catch(()=>({}));if(!s.ok||i.errors?.length)throw new p(i.errors?.map(u=>u.message).join(" | ")||`Customer accounts: ${s.status}`,{status:s.status});return i.data}async function at(){if(w()){let e=await H();return e.loggedIn?{...e.customer,emailAddress:{emailAddress:e.customer.email},defaultAddress:{formatted:e.customer.address}}:null}return I||(I=(await V("query TetherCustomer{customer{id firstName lastName displayName emailAddress{emailAddress}defaultAddress{formatted}}}")).customer,I)}async function mt({first:t=10}={}){return w()?(await U(`/orders?first=${t}`)).orders||[]:(await V("query TetherOrders($first:Int!){customer{orders(first:$first,sortKey:PROCESSED_AT,reverse:true){nodes{id name processedAt financialStatus fulfillmentStatus statusPageUrl totalPrice{amount currencyCode}lineItems(first:20){nodes{title variantTitle quantity image{url altText}}}}}}}",{first:t})).customer?.orders?.nodes||[]}async function wt({returnTo:t=a.account?.logoutUrl||`${window.location.origin}/`}={}){if(w()){let r=await U("/logout",{method:"POST",body:{returnTo:t,cartId:h.id()}});b={loggedIn:!1};try{window.localStorage.removeItem(z())}catch{}T("account-logout",{}),r.logoutUrl?E(r.logoutUrl):K(document);return}let e=c?.idToken||M(O(),N())?.idToken;if(h.id()&&await h.setBuyerIdentity({customerAccessToken:null},{create:!1}).catch(()=>{}),F(),T("account-logout",{}),!e){K(document);return}let n=await P(),o=new URL(n.end_session_endpoint);o.searchParams.set("id_token_hint",e),o.searchParams.set("post_logout_redirect_uri",t),E(o.toString())}var gt=t=>{try{return new URL(t).protocol==="https:"}catch{return!1}},pt=t=>{try{return new Date(t).toLocaleDateString(a.locale||void 0)}catch{return t}};async function K(t=document){let e=w()?!!(await H().catch(()=>({loggedIn:!1}))).loggedIn:nt()||!!await C().catch(()=>null);if(y(t,f("show")).forEach(r=>{let s=k(r,"show");s==="logged-in"&&x(r,e),s==="logged-out"&&x(r,!e)}),y(t,f("account-link")).forEach(r=>{let s=k(r,"account-link"),i=s==="payment"&&(a.account?.paymentUrl||a.account?.subscriptionsUrl)||s==="subscriptions"&&a.account?.subscriptionsUrl;r.setAttribute("href",i||`https://${a.domain}/account`)}),!e)return;let n=y(t,f("account-bind"));if(n.length){let r=await at().catch(s=>(A(s,"account"),null));n.forEach(s=>{let i={"first-name":r?.firstName,"last-name":r?.lastName,name:r?.displayName,email:r?.emailAddress?.emailAddress,address:r?.defaultAddress?.formatted?.join(", ")}[k(s,"account-bind")];i!=null&&$(s,i)})}let o=y(t,f("orders"));if(o.length){let r=(u,m)=>y(t,f("show")).forEach(l=>{let d=k(l,"show");d==="orders-loading"&&x(l,u),d==="orders-empty"&&x(l,m)});r(!0,!1);let s=!1,i=await mt({first:parseInt(k(o[0],"limit")||"10",10)}).catch(u=>(A(u,"orders"),s=!0,[]));r(!1,!s&&i.length===0),o.forEach(u=>q(u,i,(m,l)=>{let d=l.lineItems?.nodes||[];y(m,f("order-bind")).forEach(g=>{let L=k(g,"order-bind");if(L==="url"){let S=G(l);S&&g.setAttribute("href",S);return}if(L==="image"){let S=d.find(it=>it.image)?.image;S&&R(g,S.url,S.altText||d[0]?.title||"");return}let W={name:l.name,date:pt(l.processedAt),total:Y(l.totalPrice),status:l.financialStatus?.toLowerCase(),fulfillment:l.fulfillmentStatus?.toLowerCase(),items:d.map(S=>`${S.quantity}\xD7 ${S.title}`).join(", ")}[L];W!=null&&$(g,W)}),y(m,f("order-lines")).forEach(g=>St(g,d)),k(m,"order-bind")==="url"&&G(l)&&m.setAttribute("href",G(l))}))}kt.some(r=>y(t,f(r)).length)&&await(await ct()).renderPages(t)}var yt=t=>String(t||"").split("/").pop().split("?")[0];function G(t){let e=a.account?.orderUrl;return e?String(e).replace("{id}",encodeURIComponent(yt(t.id))):gt(t.statusPageUrl)?t.statusPageUrl:null}function St(t,e){q(t,e,(n,o)=>{y(n,f("order-line")).concat(n.matches(f("order-line"))?[n]:[]).forEach(r=>{let s=k(r,"order-line");if(s==="image"){o.image&&R(r,o.image.url,o.image.altText||o.title);return}let i={title:o.title,"variant-title":o.variantTitle||"",quantity:String(o.quantity)}[s];i!=null&&$(r,i)})})}var kt=["order","addresses","subscriptions","profile-form","address-form"],Z=null;function ct(){return Z||(Z=Q("account-pages").then(t=>(t.setup({server:w,serverFetch:U,query:V,customer:at,reset:()=>{I=null,b=null}}),t))),Z}var _=t=>(...e)=>ct().then(n=>n[t](...e)),Et=_("order"),Ut=_("updateProfile"),Pt=_("addresses"),$t=_("saveAddress"),vt=_("deleteAddress"),Ct=_("subscriptions"),Nt=_("subscriptionAction"),Ot=_("requestReturn"),tt=!1;async function Dt(t=document){if(!tt){if(tt=!0,document.addEventListener("click",e=>{let n=e.target;n.closest?.(f("account-login"))?(e.preventDefault(),dt().catch(o=>A(o,"login"))):n.closest?.(f("account-logout"))&&(e.preventDefault(),wt().catch(o=>A(o,"logout")))}),w()){let e=new URL(window.location.href);e.searchParams.get("account")&&(e.searchParams.delete("account"),window.history.replaceState(window.history.state,"",e),T("account-login",{})),h.beforeCheckout=async()=>{if(!(await H()).loggedIn||!h.id())return null;let n=await U("/cart",{method:"POST",body:{cartId:h.id()}}).catch(()=>null);return n?.checkoutUrl?`${n.checkoutUrl}${n.checkoutUrl.includes("?")?"&":"?"}logged_in=true`:null}}else{try{await ht()}catch(e){A(e,"login")}!h.customerAccessToken&&await C().catch(()=>null)&&(h.customerAccessToken=c.access)}X("account",nt()?"logged in":"logged out")}await K(t)}export{Pt as addresses,at as customer,vt as deleteAddress,C as getToken,ht as handleCallback,nt as isLoggedIn,dt as login,wt as logout,Dt as mountAccount,Et as order,mt as orders,V as query,K as render,Ot as requestReturn,$t as saveAddress,Nt as subscriptionAction,Ct as subscriptions,Ut as updateProfile};
@@ -1 +0,0 @@
1
- import{A as V,B as I,D as X,G as T,b as Q,g as P,h as F,n as A,o as d,p as y,s as c,u as W,w as b}from"./chunk-K2YEQAIH.js";import"./chunk-VC46IEJQ.js";var C="amount currencyCode",R="id firstName lastName company address1 address2 city province zoneCode zip country countryCode phoneNumber formatted",L={order:`query TetherOrder($id:ID!){order(id:$id){id name number processedAt cancelledAt financialStatus fulfillmentStatus statusPageUrl requiresShipping totalPrice{${C}}subtotal{${C}}totalShipping{${C}}totalTax{${C}}shippingAddress{${R}}billingAddress{${R}}lineItems(first:50){nodes{id name title variantTitle quantity sku image{url altText}price{${C}}totalPrice{${C}}suggestedReturnReasonDefinitions(first:10){nodes{id name handle}}}}fulfillments(first:10){nodes{id status createdAt estimatedDeliveryAt latestShipmentStatus trackingInformation{company number url}}}returnInformation{returnableLineItems(first:50){nodes{quantity lineItem{id}}}}returns(first:10){nodes{id status}}}}`,addresses:`query TetherAddresses{customer{defaultAddress{id}addresses(first:20){nodes{${R}}}}}`,subscriptions:`query TetherSubscriptions{customer{subscriptionContracts(first:20,reverse:true){nodes{id status nextBillingDate currencyCode deliveryPrice{${C}}deliveryPolicy{interval intervalCount{count}}lines(first:20){nodes{id name title variantTitle quantity sku currentPrice{${C}}lineDiscountedPrice{${C}}image{url altText}}}upcomingBillingCycles(first:3){nodes{cycleIndex skipped billingAttemptExpectedDate}}}}}}`,contract:"query TetherContract($id:ID!){customer{subscriptionContract(id:$id){id status upcomingBillingCycles(first:3){nodes{cycleIndex skipped}}}}}"},S={profile:"mutation TetherProfile($input: CustomerUpdateInput!) { customerUpdate(input: $input) { customer { firstName lastName } userErrors { field message } } }",addressCreate:`mutation TetherAddressCreate($address:CustomerAddressInput!,$default:Boolean){customerAddressCreate(address:$address,defaultAddress:$default){customerAddress{${R}}userErrors{field message}}}`,addressUpdate:`mutation TetherAddressUpdate($id:ID!,$address:CustomerAddressInput,$default:Boolean){customerAddressUpdate(addressId:$id,address:$address,defaultAddress:$default){customerAddress{${R}}userErrors{field message}}}`,addressDelete:"mutation TetherAddressDelete($id: ID!) { customerAddressDelete(addressId: $id) { deletedAddressId userErrors { field message } } }",pause:"mutation TetherPause($id: ID!) { subscriptionContractPause(subscriptionContractId: $id) { contract { id status } userErrors { field message } } }",resume:"mutation TetherResume($id: ID!) { subscriptionContractActivate(subscriptionContractId: $id) { contract { id status } userErrors { field message } } }",cancel:"mutation TetherCancel($id: ID!) { subscriptionContractCancel(subscriptionContractId: $id) { contract { id status } userErrors { field message } } }",skip:"mutation TetherSkip($input: SubscriptionBillingCycleInput!) { subscriptionBillingCycleSkip(billingCycleInput: $input) { billingCycle { cycleIndex skipped } userErrors { field message } } }",unskip:"mutation TetherUnskip($input: SubscriptionBillingCycleInput!) { subscriptionBillingCycleUnskip(billingCycleInput: $input) { billingCycle { cycleIndex skipped } userErrors { field message } } }",returnRequest:"mutation TetherReturn($orderId: ID!, $lines: [RequestedLineItemInput!]!) { orderRequestReturn(orderId: $orderId, requestedLineItems: $lines) { return { id status } userErrors { field message } } }"},p=class extends Error{},q=e=>new RegExp(`^gid://shopify/${e}/\\d+(\\?[\\w=&.-]{1,80})?$`),re={Order:q("Order"),CustomerAddress:q("CustomerAddress"),SubscriptionContract:q("SubscriptionContract"),LineItem:q("LineItem"),ReturnReasonDefinition:q("ReturnReasonDefinition")};function D(e,t){let s=/^\d{1,20}$/.test(String(t??""))?`gid://shopify/${e}/${t}`:String(t??"");if(!re[e].test(s))throw new p(`${e} id`);return s}var N=(e,t=255)=>{if(e==null||e==="")return;if(typeof e!="string"&&typeof e!="number")throw new p("text");let s=String(e).replace(/[\u0000-\u001f\u007f]/g,"").trim();if(s.length>t)throw new p("too long");return s},ne=["firstName","lastName","company","address1","address2","city","zip","zoneCode","phoneNumber"];function ie(e={}){if(!e||typeof e!="object"||Array.isArray(e))throw new p("address");let t={};if(ne.forEach(s=>{let i=N(e[s]);i!==void 0&&(t[s]=i)}),e.countryCode!=null&&e.countryCode!==""){let s=String(e.countryCode).toUpperCase();if(!/^[A-Z]{2}$/.test(s))throw new p("countryCode");t.countryCode=s}return t}var $=e=>{let t=e?.userErrors||[];if(t.length){let s=new p(t.map(i=>i.message).join(" | "));throw s.userErrors=t,s}return e},Y={async order(e,{id:t}){return{order:(await e(L.order,{id:D("Order",t)}))?.order||null}},async profile(e,{firstName:t,lastName:s}){let i={};if(t!==void 0&&(i.firstName=N(t,100)??""),s!==void 0&&(i.lastName=N(s,100)??""),!Object.keys(i).length)throw new p("nothing to change");return{customer:$((await e(S.profile,{input:i}))?.customerUpdate).customer}},async addresses(e){let t=(await e(L.addresses,{}))?.customer,s=t?.defaultAddress?.id||null;return{addresses:(t?.addresses?.nodes||[]).map(i=>({...i,isDefault:i.id===s}))}},async saveAddress(e,{id:t,address:s,isDefault:i}){let r=ie(s||{}),n=i===!0?!0:void 0;return{address:$(t?(await e(S.addressUpdate,{id:D("CustomerAddress",t),address:Object.keys(r).length?r:null,default:n??null}))?.customerAddressUpdate:(await e(S.addressCreate,{address:r,default:n??!1}))?.customerAddressCreate).customerAddress}},async deleteAddress(e,{id:t}){return{deleted:$((await e(S.addressDelete,{id:D("CustomerAddress",t)}))?.customerAddressDelete).deletedAddressId}},async subscriptions(e){return{subscriptions:(await e(L.subscriptions,{}))?.customer?.subscriptionContracts?.nodes||[]}},async subscription(e,{id:t,action:s}){if(!["pause","resume","skip","unskip","cancel"].includes(s))throw new p("action");let i=D("SubscriptionContract",t),r=(await e(L.contract,{id:i}))?.customer?.subscriptionContract;if(!r){let o=new p("not found");throw o.status=404,o}if(s==="skip"||s==="unskip"){let o=r.upcomingBillingCycles?.nodes||[],u=s==="skip"?o.find(m=>!m.skipped):o.find(m=>m.skipped);if(!u)throw new p(s==="skip"?"no upcoming delivery to skip":"nothing skipped");return{billingCycle:$((await e(S[s],{input:{contractId:i,selector:{index:u.cycleIndex}}}))?.[s==="skip"?"subscriptionBillingCycleSkip":"subscriptionBillingCycleUnskip"]).billingCycle}}let n={pause:"subscriptionContractPause",resume:"subscriptionContractActivate",cancel:"subscriptionContractCancel"}[s];return{contract:$((await e(S[s],{id:i}))?.[n]).contract}},async requestReturn(e,{orderId:t,lines:s}){let i=D("Order",t);if(!Array.isArray(s)||!s.length||s.length>50)throw new p("lines");let r=s.map(a=>{let o=Number(a?.quantity);if(!Number.isInteger(o)||o<1||o>1e3)throw new p("quantity");let u={lineItemId:D("LineItem",a.lineItemId),quantity:o};a.reasonId&&(u.returnReasonDefinitionId=D("ReturnReasonDefinition",a.reasonId));let f=N(a.note,300);return f&&(u.customerNote=f),u});return{return:$((await e(S.returnRequest,{orderId:i,lines:r}))?.orderRequestReturn).return}}};var G=null,Z=!1;function De(e){G=e}var H=e=>{try{return new URL(e).protocol==="https:"}catch{return!1}},O=e=>{try{return new Date(e).toLocaleDateString(Q.locale||void 0)}catch{return e}},oe={order:e=>["GET",`/order?id=${encodeURIComponent(e.id)}`],addresses:()=>["GET","/addresses"],subscriptions:()=>["GET","/subscriptions"],profile:()=>["POST","/profile"],saveAddress:()=>["POST","/address"],deleteAddress:()=>["POST","/address/delete"],subscription:()=>["POST","/subscription"],requestReturn:()=>["POST","/return"]};async function w(e,t={}){let{server:s,serverFetch:i,query:r}=G;if(s()){let[n,a]=oe[e](t),o=await i(a,n==="POST"?{method:n,body:t}:{});if(o.loggedIn===!1)throw new F("Not logged in",{code:"NOT_LOGGED_IN",status:401});return o}try{return await Y[e]((n,a)=>r(n,a),t)}catch(n){throw n instanceof p?new F(n.message,{code:"INVALID",userErrors:n.userErrors}):n}}var U=e=>{G.reset(),W("account-updated",{what:e})},ae=e=>w("order",{id:e}).then(t=>t.order),de=({firstName:e,lastName:t}={})=>w("profile",{firstName:e,lastName:t}).then(s=>(U("profile"),s.customer)),ue=()=>w("addresses").then(e=>e.addresses),J=(e,{id:t,isDefault:s}={})=>w("saveAddress",{id:t,address:e,isDefault:s}).then(i=>(U("addresses"),i.address)),ce=e=>w("deleteAddress",{id:e}).then(t=>(U("addresses"),t.deleted)),le=()=>w("subscriptions").then(e=>e.subscriptions),pe=(e,t)=>w("subscription",{id:e,action:t}).then(s=>(U("subscriptions"),s)),fe=(e,t)=>w("requestReturn",{orderId:e,lines:t}).then(s=>(U("orders"),s.return));var x=e=>e?String(e).toLowerCase().replace(/_/g," "):"",z=e=>(e?.formatted||[]).join(", "),E=(e,t,s)=>c(e,d(t)).forEach(i=>{let r=y(i,t);r in s&&X(i,!!s[r])}),j=(e,t)=>E(e,"show",t);function me(e,t,s=null){T(e,t,(i,r)=>{let n=s&&s.get(r.id)||0;i.dataset.tetherLine=r.id,c(i,d("order-line")).concat(i.matches(d("order-line"))?[i]:[]).forEach(a=>{let o=y(a,"order-line");if(o==="image"){r.image&&V(a,r.image.url,r.image.altText||r.title);return}let u={title:r.title||r.name,"variant-title":r.variantTitle||"",quantity:String(r.quantity),price:r.price?b(r.price):"",total:r.totalPrice?b(r.totalPrice):"",sku:r.sku||"",returnable:String(n)}[o];u!=null&&I(a,u)}),E(i,"order-line-show",{returnable:n>0}),c(i,d("return-quantity")).forEach(a=>{a.max=String(n),a.min="0",a.value||(a.value="0"),a.disabled=n<1}),c(i,`select${d("return-reason")}`).forEach(a=>{let o=r.suggestedReturnReasonDefinitions?.nodes||[];a.dataset.tetherFilled!==r.id&&(a.dataset.tetherFilled=r.id,o.forEach(u=>a.appendChild(new Option(u.name,u.id))))})})}var he={order:d("order")};async function ee(e){let t=y(e,"order")||"",s=t.startsWith("url:")?new URL(window.location.href).searchParams.get(t.slice(4)||"id"):t,i=o=>e.setAttribute(A("order-state"),o);if(!s){i("not-found"),E(e,"order-show",{"not-found":!0});return}i("loading"),E(e,"order-show",{loading:!0,ready:!1,"not-found":!1,error:!1});let r;try{r=await ae(s)}catch(o){P(o,"order"),i("error"),E(e,"order-show",{loading:!1,error:!0});return}if(!r){i("not-found"),E(e,"order-show",{loading:!1,"not-found":!0});return}e.dataset.tetherOrderId=r.id;let n=new Map((r.returnInformation?.returnableLineItems?.nodes||[]).map(o=>[o.lineItem?.id,o.quantity])),a=r.fulfillments?.nodes||[];c(e,d("order-bind")).forEach(o=>{let u=y(o,"order-bind");if(u==="url"){H(r.statusPageUrl)&&o.setAttribute("href",r.statusPageUrl);return}let f={name:r.name,date:O(r.processedAt),total:b(r.totalPrice),subtotal:r.subtotal?b(r.subtotal):"",shipping:r.totalShipping?b(r.totalShipping):"",tax:r.totalTax?b(r.totalTax):"",status:x(r.financialStatus),fulfillment:x(r.fulfillmentStatus),"shipping-address":z(r.shippingAddress),"billing-address":z(r.billingAddress),items:(r.lineItems?.nodes||[]).map(m=>`${m.quantity}\xD7 ${m.title||m.name}`).join(", "),cancelled:r.cancelledAt?O(r.cancelledAt):""}[u];f!=null&&I(o,f)}),c(e,d("order-lines")).forEach(o=>me(o,r.lineItems?.nodes||[],n)),c(e,d("order-fulfillments")).forEach(o=>T(o,a,(u,f)=>{let m=f.trackingInformation?.[0]||{};c(u,d("fulfillment-bind")).concat(u.matches(d("fulfillment-bind"))?[u]:[]).forEach(h=>{let g=y(h,"fulfillment-bind");if(g==="url"){H(m.url)&&h.setAttribute("href",m.url);return}let l={status:x(f.latestShipmentStatus||f.status),date:O(f.createdAt),eta:f.estimatedDeliveryAt?O(f.estimatedDeliveryAt):"",company:m.company||"",number:m.number||""}[g];l!=null&&I(h,l)})})),E(e,"order-show",{loading:!1,ready:!0,error:!1,"not-found":!1,cancelled:!!r.cancelledAt,shipped:a.length>0,returnable:[...n.values()].some(o=>o>0),"has-returns":(r.returns?.nodes||[]).length>0,"return-requested":e.dataset.tetherReturned==="1"}),i("ready")}async function ge(e){let t=await G.customer().catch(()=>null);t&&["firstName","lastName"].forEach(s=>{let i=e.elements?.[s];i&&!i.dataset.tetherTouched&&(i.value=t[s]||"")})}var te=null;async function B(e){let t=c(e,d("addresses"));if(!t.length)return;j(e,{"addresses-loading":!0,"addresses-empty":!1});let s=[];try{s=te=await ue()}catch(i){P(i,"addresses")}j(e,{"addresses-loading":!1,"addresses-empty":s.length===0}),t.forEach(i=>T(i,s,(r,n)=>{r.dataset.tetherAddress=n.id,c(r,d("address-bind")).concat(r.matches(d("address-bind"))?[r]:[]).forEach(a=>{let o={formatted:z(n),name:[n.firstName,n.lastName].filter(Boolean).join(" "),company:n.company||"",address1:n.address1||"",address2:n.address2||"",city:n.city||"",zip:n.zip||"",province:n.province||"",country:n.country||"",phone:n.phoneNumber||""}[y(a,"address-bind")];o!=null&&I(a,o)}),E(r,"address-show",{default:n.isDefault,"not-default":!n.isDefault})}))}var ye=["pause","resume","skip","unskip","cancel"];function be(e){let t=e.upcomingBillingCycles?.nodes?.[0],s=e.status;return{active:s==="ACTIVE",paused:s==="PAUSED",cancelled:s==="CANCELLED",expired:s==="EXPIRED",failed:s==="FAILED",skipped:!!t?.skipped,"can-pause":s==="ACTIVE","can-resume":s==="PAUSED"||s==="FAILED","can-skip":s==="ACTIVE"&&!!t&&!t.skipped,"can-unskip":s==="ACTIVE"&&!!t?.skipped,"can-cancel":s==="ACTIVE"||s==="PAUSED"||s==="FAILED"}}async function se(e){let t=c(e,d("subscriptions"));if(!t.length)return;j(e,{"subscriptions-loading":!0,"subscriptions-empty":!1});let s=[];try{s=await le()}catch(i){P(i,"subscriptions")}j(e,{"subscriptions-loading":!1,"subscriptions-empty":s.length===0}),t.forEach(i=>T(i,s,(r,n)=>{r.dataset.tetherSubscription=n.id,r.setAttribute(A("subscription-status"),x(n.status));let a=n.lines?.nodes||[],o=n.deliveryPolicy?.intervalCount?.count||1,u=x(n.deliveryPolicy?.interval),f=a.reduce((h,g)=>h+parseFloat(g.lineDiscountedPrice?.amount||0),0);c(r,d("subscription-bind")).forEach(h=>{let g=y(h,"subscription-bind"),l={status:x(n.status),next:n.nextBillingDate?O(n.nextBillingDate):"",interval:u?o===1?u:`${o} ${u}s`:"",products:a.map(v=>`${v.quantity}\xD7 ${v.title}`).join(", "),total:a.length?b({amount:String(f),currencyCode:n.currencyCode}):"",delivery:n.deliveryPrice?b(n.deliveryPrice):""}[g];l!=null&&I(h,l)}),c(r,d("subscription-lines")).forEach(h=>T(h,a,(g,l)=>{c(g,d("subscription-line")).concat(g.matches(d("subscription-line"))?[g]:[]).forEach(v=>{let _=y(v,"subscription-line");if(_==="image"){l.image&&V(v,l.image.url,l.image.altText||l.title);return}let M={title:l.title,"variant-title":l.variantTitle||"",quantity:String(l.quantity),price:b(l.currentPrice)}[_];M!=null&&I(v,M)})}));let m=be(n);E(r,"subscription-show",m),c(r,d("subscription-action")).forEach(h=>{let g=y(h,"subscription-action"),l=m[`can-${g}`];h.disabled=!l,h.classList.toggle("is-disabled",!l)})}))}async function $e(e=document){Z||(Z=!0,Ae()),await Promise.all([...c(e,d("order")).map(t=>ee(t)),...c(e,d("profile-form")).map(t=>ge(t)),B(e),se(e)])}var K=e=>Object.fromEntries([...e.elements].filter(t=>t.name&&t.type!=="submit"&&t.type!=="button"&&t.type!=="checkbox").map(t=>[t.name,t.value]));async function k(e,t,{error:s}={}){e.classList.add("is-busy"),e.setAttribute("aria-busy","true"),e.setAttribute(A("form-state"),"pending"),c(e,d("form-error")).forEach(i=>I(i,""));try{let i=await t();return e.setAttribute(A("form-state"),"saved"),i}catch(i){e.setAttribute(A("form-state"),"error");let r=i?.userErrors?.map(n=>n.message).join(" ")||i?.message||"Something went wrong";c(e,d("form-error")).forEach(n=>I(n,r.replace(/^Customer accounts: /,""))),s&&P(i,s);return}finally{e.classList.remove("is-busy"),e.removeAttribute("aria-busy")}}function Ae(){document.addEventListener("submit",e=>{let t=e.target;if(t.matches?.(d("profile-form")))e.preventDefault(),k(t,()=>de(K(t)));else if(t.matches?.(d("address-form"))){e.preventDefault();let s=t.dataset.tetherAddressId||void 0,i=!!t.elements?.isDefault?.checked;k(t,async()=>{await J(K(t),{id:s,isDefault:i}),t.reset(),delete t.dataset.tetherAddressId,await B(document)})}}),document.addEventListener("input",e=>{e.target.closest?.(d("profile-form"))&&(e.target.dataset.tetherTouched="1")}),document.addEventListener("click",e=>{let t=e.target,s=t.closest?.("[data-tether-address]"),i=n=>{let a=y(n,"confirm");return!a||window.confirm(a)},r;if((r=t.closest?.(d("address-delete")))&&s)e.preventDefault(),i(r)&&k(s,async()=>{await ce(s.dataset.tetherAddress),await B(document)});else if((r=t.closest?.(d("address-default")))&&s)e.preventDefault(),k(s,async()=>{await J(null,{id:s.dataset.tetherAddress,isDefault:!0}),await B(document)});else if((r=t.closest?.(d("address-edit")))&&s){e.preventDefault();let n=(te||[]).find(o=>o.id===s.dataset.tetherAddress),a=document.querySelector(d("address-form"));n&&a&&(a.dataset.tetherAddressId=n.id,[...a.elements].forEach(o=>{o.name&&o.name in n&&(o.value=n[o.name]??""),o.name==="isDefault"&&(o.checked=n.isDefault)}),a.scrollIntoView?.({block:"nearest"}))}else if(r=t.closest?.(d("address-new"))){let n=document.querySelector(d("address-form"));n&&(n.reset(),delete n.dataset.tetherAddressId)}else if(r=t.closest?.(d("subscription-action"))){e.preventDefault();let n=r.closest("[data-tether-subscription]"),a=y(r,"subscription-action");if(!n||!ye.includes(a)||r.disabled||!i(r))return;n.setAttribute(A("subscription-state"),"pending"),k(n,async()=>{await pe(n.dataset.tetherSubscription,a),await se(document)}).then(()=>{n.setAttribute(A("subscription-state"),n.getAttribute(A("form-state"))==="error"?"error":"done")})}else if(r=t.closest?.(d("order-return"))){e.preventDefault();let n=r.closest(he.order);if(!n?.dataset.tetherOrderId)return;let a=c(n,"[data-tether-line]").map(o=>({lineItemId:o.dataset.tetherLine,quantity:parseInt(o.querySelector(d("return-quantity"))?.value||"0",10),reasonId:o.querySelector(d("return-reason"))?.value||void 0,note:o.querySelector(d("return-note"))?.value||void 0})).filter(o=>o.quantity>0);if(!a.length||!i(r))return;k(n,async()=>{await fe(n.dataset.tetherOrderId,a),n.dataset.tetherReturned="1",await ee(n)})}})}export{ue as addresses,ce as deleteAddress,ae as order,$e as renderPages,fe as requestReturn,J as saveAddress,De as setup,pe as subscriptionAction,le as subscriptions,de as updateProfile};
@@ -1 +0,0 @@
1
- import{c as Q}from"./chunk-FIOZPPC5.js";import{b as S,d as I,e as B}from"./chunk-AJLPU2JC.js";import{A as M,B as j,C as m,D as L,G as K,H as N,I as R,M as q,b as c,e as O,g as A,h as v,l as $,m as U,n as E,o as u,p as g,r as F,s as l,u as h,w as b}from"./chunk-K2YEQAIH.js";function G(t,e=1,n={}){let a=typeof t=="object"&&t!==null?t:{variantId:t,quantity:e,...n},s=I.variant(a.merchandiseId||a.variantId||a.id);if(!s)throw new v("add(): variantId is required");let r={merchandiseId:s,quantity:Math.max(1,parseInt(a.quantity??1,10)||1)},o=a.sellingPlanId||a.sellingPlan;o&&(r.sellingPlanId=I.sellingPlan(o));let i=q(a.attributes);return i.length&&(r.attributes=i),r}function V(t,e,n){return`mutation Tether_${t}(${e}){${t}(${n}){cart{...TetherCart}userErrors{field message}warnings{code message target}}}${S()}`}var H='a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])',k=null,W=t=>l(t,H).filter(e=>e.offsetParent!==null||e===document.activeElement);function x(t){l(document,u("cart-open")).forEach(e=>e.setAttribute("aria-expanded",String(t))),l(document,u("cart-drawer")).forEach(e=>{e.hasAttribute("role")||e.setAttribute("role","dialog"),!e.hasAttribute("aria-label")&&!e.hasAttribute("aria-labelledby")&&e.setAttribute("aria-label",g(e,"cart-label")||"Cart"),e.setAttribute("aria-modal",String(t)),e.classList.contains(c.cartDrawerOpenClass)||(e.setAttribute("aria-hidden","true"),c.cartFocus!==!1&&(e.inert=!0))})}var T=t=>/does not exist|not found|invalid id/i.test(t?.message||""),D={state:null,_chain:Promise.resolve(),id(){try{return localStorage.getItem(c.storageKey)}catch{return null}},_setId(t){try{t?localStorage.setItem(c.storageKey,t):localStorage.removeItem(c.storageKey)}catch{}},get lines(){return this.state?.lines?.nodes||[]},get count(){return this.state?.totalQuantity||0},lastError:null,customerAccessToken:null,pendingQty:new Map,warnings:[],loaded:!1,_take(t,e){let n=U(t,e);return this.warnings=(n.warnings||[]).filter((a,s,r)=>r.findIndex(o=>o.message===a.message)===s).map(a=>({...a,message:typeof c.warningText=="function"&&c.warningText(a)||a.message})),this.warnings.length&&h("cart-warning",{warnings:this.warnings}),n.cart},_queue(t){let e=this._chain.then(t,t).then(n=>(this.lastError&&(this.lastError=null,this.render()),n),n=>{throw this.lastError=n,this.render(),h("cart-error",{error:n}),n});return this._chain=e.catch(()=>{}),e},_commit(t,e){this.state=t,t?.id&&this._setId(t.id);try{localStorage.setItem(`${c.storageKey}:seen`,`${Date.now()}|${t?.totalQuantity||0}`)}catch{}return this.render(),h("cart-updated",{cart:t,reason:e}),t},async init(){let t=this.id();if(!t)return this.state=null,this.loaded=!0,this.render(),h("cart-updated",{cart:null,reason:"load"}),null;if(!this.loaded)try{let e=(localStorage.getItem(`${c.storageKey}:seen`)||"").split("|")[1];e&&l(document,u("cart-count")).forEach(n=>{/^\s*0?\s*$/.test(n.textContent)&&(n.textContent=e)})}catch{}try{let e=await $(`query TetherCart($id:ID!){cart(id:$id){...TetherCart}}${S()}`,{id:t});e.cart?this.state=e.cart:(this._setId(null),this.state=null)}catch(e){A(e,"cart load failed"),this.lastError=e,T(e)&&this._setId(null),this.state=null}return this.loaded=!0,this.render(),h("cart-updated",{cart:this.state,reason:"load"}),this.state},async _create(t={}){let e=c.country||this.customerAccessToken?{...c.country?{countryCode:String(c.country).toUpperCase()}:{},...this.customerAccessToken?{customerAccessToken:this.customerAccessToken}:{}}:void 0,n=await $(V("cartCreate","$input: CartInput!","input: $input"),{input:{buyerIdentity:e,...t}});return this._take(n.cartCreate,"cartCreate")},async _mutate(t,e,n,a,s){let r=this.id();if(!r)return s?this._create(s):null;try{let o=await $(V(t,`$cartId: ID!, ${e}`,`cartId: $cartId, ${n}`),{...a,cartId:r});return this._take(o[t],t)}catch(o){if(s&&T(o))return O("cart expired, creating a new one"),this._setId(null),this._create(s);throw o}},add(t,e=1,n={}){let a=(Array.isArray(t)?t:[t]).map(s=>G(s,e,n));return this._queue(async()=>{let s=await this._mutate("cartLinesAdd","$lines: [CartLineInput!]!","lines: $lines",{lines:a},{lines:a});return this._commit(s,"add"),h("added",{cart:s,lines:a}),c.openCartOnAdd&&this.open(),s})},updateLine(t,e){let n=typeof e=="number"?{quantity:e}:{...e};if(n.quantity!==void 0&&n.quantity<=0)return this.removeLine(t);let a={id:t};return n.quantity!==void 0&&(a.quantity=n.quantity),"sellingPlanId"in n&&(a.sellingPlanId=n.sellingPlanId?I.sellingPlan(n.sellingPlanId):null),n.attributes&&(a.attributes=q(n.attributes)),(n.merchandiseId||n.variantId)&&(a.merchandiseId=I.variant(n.merchandiseId||n.variantId)),this._queue(async()=>this._commit(await this._mutate("cartLinesUpdate","$lines: [CartLineUpdateInput!]!","lines: $lines",{lines:[a]}),"update"))},changeQuantity(t,e){let n=this.lines.find(o=>o.id===t);if(!n)return Promise.resolve(this.state);let a=Math.max(0,(this.pendingQty.get(t)?.qty??n.quantity)+e),s={qty:a,done:!1};this.pendingQty.set(t,s),this.render(),h("cart-updated",{cart:this.state,reason:"pending"});let r=()=>this.pendingQty.get(t)===s;return this._queue(async()=>{if(!r())return this.state;let o=this.lines.find(d=>d.id===t);if(o&&o.quantity===a)return this.state;let i=a>0?await this._mutate("cartLinesUpdate","$lines: [CartLineUpdateInput!]!","lines: $lines",{lines:[{id:t,quantity:a}]}):await this._mutate("cartLinesRemove","$lineIds: [ID!]!","lineIds: $lineIds",{lineIds:[t]});return r()?this._commit(i,a>0?"update":"remove"):(this.state=i,i?.id&&this._setId(i.id),i)}).finally(()=>{r()&&(this.pendingQty.delete(t),this.render(),h("cart-updated",{cart:this.state,reason:"settled"}))})},quantityOf(t){return this.pendingQty.get(t.id)?.qty??t.quantity},removeLine(t){let e=Array.isArray(t)?t:[t];return this._queue(async()=>this._commit(await this._mutate("cartLinesRemove","$lineIds: [ID!]!","lineIds: $lineIds",{lineIds:e}),"remove"))},clear(){let t=this.lines.map(e=>e.id);return t.length?this.removeLine(t):Promise.resolve(this.state)},setNote(t){return this._queue(async()=>this._commit(await this._mutate("cartNoteUpdate","$note: String!","note: $note",{note:t??""},{note:t??""}),"note"))},setAttributes(t){let e=new Map((this.state?.attributes||[]).map(a=>[a.key,a.value]));q(t).forEach(a=>e.set(a.key,a.value));let n=[...e].filter(([,a])=>a!=="").map(([a,s])=>({key:a,value:s}));return this._queue(async()=>this._commit(await this._mutate("cartAttributesUpdate","$attributes: [AttributeInput!]!","attributes: $attributes",{attributes:n},{attributes:n}),"attributes"))},setDiscountCodes(t){let e=(Array.isArray(t)?t:[t]).map(n=>String(n).trim()).filter(Boolean);return this._queue(async()=>this._commit(await this._mutate("cartDiscountCodesUpdate","$discountCodes: [String!]!","discountCodes: $discountCodes",{discountCodes:e},{discountCodes:e}),"discount"))},async applyDiscount(t){let e=(this.state?.discountCodes||[]).map(s=>s.code),n=await this.setDiscountCodes([...new Set([...e,t])]);if((n?.discountCodes||[]).find(s=>s.code.toLowerCase()===String(t).toLowerCase())?.applicable)return n;throw await this.removeDiscount(t).catch(()=>{}),new v(`Discount code not valid: ${t}`,{code:"INVALID_DISCOUNT"})},removeDiscount(t){let e=String(t).toLowerCase();return this.setDiscountCodes((this.state?.discountCodes||[]).map(n=>n.code).filter(n=>n.toLowerCase()!==e))},setBuyerIdentity(t,{create:e=!0}={}){return this._queue(async()=>{let n=await this._mutate("cartBuyerIdentityUpdate","$buyerIdentity: CartBuyerIdentityInput!","buyerIdentity: $buyerIdentity",{buyerIdentity:t},e?{buyerIdentity:t}:null).catch(a=>{if(e||!T(a))throw a;return this._setId(null),null});return this._commit(n,"buyer-identity")})},async checkout(t=c.checkoutTarget){let e=this.id();if(!e||this.state&&!this.count)return null;let n=t==="_blank"?window.open("","_blank"):null;if(n)try{n.opener=null}catch{}try{let a=await $("query TetherCheckout($id: ID!) { cart(id: $id) { checkoutUrl } }",{id:e}),s=this.beforeCheckout&&await this.beforeCheckout().catch(()=>null)||a.cart?.checkoutUrl;if(s&&this.customerAccessToken&&(s+=`${s.includes("?")?"&":"?"}logged_in=true`),!s)throw new v("No checkoutUrl (cart empty or expired)");return h("checkout",{url:s,cart:this.state}),n&&!n.closed?n.location.href=s:window.location.href=s,s}catch(a){return n&&n.close(),A(a,"checkout failed"),null}},drawers(){return l(document,u("cart-drawer"))},_open:!1,isOpen(){let t=this.drawers();return t.length?t.some(e=>e.classList.contains(c.cartDrawerOpenClass)):this._open},open(){if(this.isOpen())return;this._open=!0;let t=this.drawers().filter(e=>g(e,"cart-drawer")!=="manual");t.forEach(e=>{e.inert=!1,e.classList.add(c.cartDrawerOpenClass),e.setAttribute("aria-hidden","false")}),x(!0),c.cartFocus!==!1&&t[0]&&(k=document.activeElement,setTimeout(()=>{let e=W(t[0])[0]||t[0];e===t[0]&&!t[0].hasAttribute("tabindex")&&(t[0].tabIndex=-1),e.focus?.({preventScroll:!0})},60)),typeof c.onCartOpen=="function"&&c.onCartOpen(t),h("cart-toggled",{open:!0})},close(){if(!this.isOpen())return;this._open=!1;let t=this.drawers(),e=t.some(n=>n.contains(document.activeElement));t.forEach(n=>{n.classList.remove(c.cartDrawerOpenClass),n.setAttribute("aria-hidden","true"),c.cartFocus!==!1&&(n.inert=!0)}),x(!1),e&&k?.isConnected&&k.focus({preventScroll:!0}),k=null,typeof c.onCartClose=="function"&&c.onCartClose(t),h("cart-toggled",{open:!1})},toggle(){this.isOpen()?this.close():this.open()},subscribe(t){let e=()=>t(this.state,{open:this.isOpen(),count:this.count,loaded:this.loaded,warnings:this.warnings}),n=()=>e();return["cart-updated","cart-toggled"].forEach(a=>document.addEventListener(`${c.prefix}:${a}`,n)),e(),()=>["cart-updated","cart-toggled"].forEach(a=>document.removeEventListener(`${c.prefix}:${a}`,n))},render(){let t=this.state,e=t?t.totalQuantity:0,n=r=>t?b(t.cost?.[r]):"";x(this.isOpen()),l(document,u("cart-count")).forEach(r=>m(r,e)),l(document,u("cart-subtotal")).forEach(r=>m(r,n("subtotalAmount"))),l(document,u("cart-total")).forEach(r=>m(r,n("totalAmount"))),l(document,u("cart-checkout-charge")).forEach(r=>m(r,n("checkoutChargeAmount")));let a=this.lines.some(r=>r.sellingPlanAllocation),s={"cart-empty":e===0,"cart-filled":e>0,"cart-has-subscription":a,"cart-no-subscription":!a,"cart-has-discount":(t?.discountCodes||[]).some(r=>r.applicable),"cart-error":!!this.lastError,"cart-warning":this.warnings.length>0};l(document,u("cart-warning")).forEach(r=>m(r,[...new Set(this.warnings.map(o=>o.message))].join(" "))),l(document,u("show")).forEach(r=>{let o=g(r,"show");o in s&&!r.closest(u("product"))&&L(r,s[o])}),l(document,u("checkout")).forEach(r=>{r.classList.toggle("is-disabled",!e),r.setAttribute("aria-disabled",String(!e))}),l(document,`textarea${u("cart-note")},input${u("cart-note")}`).forEach(r=>{document.activeElement!==r&&(r.value=t?.note||"")}),l(document,u("cart-discounts")).forEach(r=>{K(r,t?.discountCodes||[],(o,i)=>{o.setAttribute(E("discount-code"),i.code);let d=o.querySelector(u("discount","code"))||(o.firstElementChild?null:o);d&&j(d,i.code),o.classList.toggle("is-inapplicable",!i.applicable)})}),l(document,u("cart-lines")).forEach(r=>{N(r,this.lines,o=>o.id,(o,i)=>J(o,i),{onEnter:c.onLineEnter,onLeave:c.onLineLeave})}),t&&R("cart")}};function z(t,e){let n=t.merchandise||{},a=t.sellingPlanAllocation?.sellingPlan;switch(e){case"title":return n.product?.title;case"product-title":return n.product?.title;case"variant-title":return n.title==="Default Title"?"":n.title;case"options":return(n.selectedOptions||[]).filter(s=>s.value!=="Default Title").map(s=>`${s.name}: ${s.value}`).join(", ");case"vendor":return n.product?.vendor;case"sku":return n.sku;case"price":return b(t.cost?.amountPerQuantity||n.price);case"compare-at-price":return b(t.cost?.compareAtAmountPerQuantity||n.compareAtPrice);case"line-total":return b(t.cost?.totalAmount);case"line-subtotal":return b(t.cost?.subtotalAmount);case"quantity":return D.quantityOf(t);case"plan":return a?.name||"";case"plan-description":return a?.description||"";case"components":return(t.lineComponents||[]).map(s=>`${s.quantity} \xD7 ${s.merchandise?.product?.title||""}`).join(", ");default:if(e.startsWith("attribute:")){let s=e.slice(10);return(t.attributes||[]).find(r=>r.key===s)?.value||""}return}}function J(t,e){let n=e.merchandise||{},a=!!e.sellingPlanAllocation;t.setAttribute(E("line-id"),e.id),t.classList.toggle("is-subscription",a),l(t,u("line")).forEach(i=>{let d=g(i,"line");if(d==="image")return M(i,n.image?.url||n.product?.featuredImage?.url,n.product?.title);if(d==="url"){let y=F(n.product?.handle,n.product?.id),_=new URLSearchParams;n.id&&_.set("variant",String(n.id).split("/").pop());let w=e.sellingPlanAllocation?.sellingPlan?.id;w&&_.set("selling_plan",w.split("/").pop());let C=_.toString();return i.setAttribute("href",C?`${y}${y.includes("?")?"&":"?"}${C}`:y)}let p=z(e,d);p!==void 0&&m(i,p)});let s=D.warnings.find(i=>i.target===e.id);t.classList.toggle("is-warning",!!s);let r=D.pendingQty.has(e.id);t.classList.toggle("is-busy",r),r?t.setAttribute("aria-busy","true"):t.removeAttribute("aria-busy"),l(t,u("line","warning")).forEach(i=>m(i,s?.message||""));let o={subscription:a,"one-time":!a,"on-sale":parseFloat(e.cost?.compareAtAmountPerQuantity?.amount)>parseFloat(e.cost?.amountPerQuantity?.amount),"has-components":(e.lineComponents||[]).length>0,warning:!!s};l(t,u("line-show")).forEach(i=>{let d=g(i,"line-show");d in o&&L(i,o[d])}),l(t,`select${u("line-plan")}`).forEach(i=>{let d=n.product?.handle;d&&Q(d).then(p=>{let y=B(p),w=[...!p.requiresSellingPlan&&g(i,"line-plan")!=="subscription-only"?[{value:"",label:i.getAttribute(E("one-time-label"))||"One-time purchase"}]:[],...y.map(f=>({value:f.id,label:f.name}))],C=w.map(f=>f.value).join("|");i.dataset.tetherSig!==C&&(i.innerHTML="",w.forEach(f=>{let P=document.createElement("option");P.value=f.value,P.textContent=f.label,i.appendChild(P)}),i.dataset.tetherSig=C),i.value=e.sellingPlanAllocation?.sellingPlan?.id||"",L(i,y.length>0)}).catch(p=>A(p,"line plan options"))})}export{W as a,D as b};
@@ -1 +0,0 @@
1
- var t={diagnose:()=>import("./diagnose-VXQBSD3A.js"),markets:()=>import("./markets-ui-F3R5T5EL.js"),search:()=>import("./search-NILMGYXG.js"),extras:()=>import("./extras-R4X34VQL.js"),account:()=>import("./account-QUBHQG3C.js"),"account-pages":()=>import("./account-pages-VWDHF6WA.js"),analytics:()=>import("./analytics-SLATWPLC.js")},r=o=>t[o](),a=void 0;export{r as a,a as b};