PageSourceSearch

https://www.doodly.com/assets/projects/user_pages/stripe-checkout-2DRIRV4Y.js

js doodly.com collected 2026-10-01 12:34:11 UTC 81,276 bytes, 2,052 lines download raw bytes

1import {
2  CheckoutConfigurationErrorV1,
3  CheckoutCriticalError,
4  CheckoutExistingOrders,
5  CheckoutLoadingV1,
6  CheckoutMultiStepV2,
7  CheckoutShippingProfileSelectV1,
8  CheckoutSubmitButtonV1,
9  CheckoutSubmitNotificationV1,
10  CheckoutTosV1,
11  ERROR_CODES,
12  STRIPE_SKIP_SHIPPING_ID,
13  addressErrors,
14  buildCustomFields,
15  buildProductSelectBatched,
16  calculateStripeChangeResolveDetails,
17  calculateStripeClickResolveDetails,
18  checkValidCustomFields,
19  collectLeads,
20  contactErrors,
21  convertAddressFromSession,
22  convertAddressFromStripe,
23  convertToStripeAddress,
24  getCartEstimatedTotal,
25  getStripeMode,
26  hasErrors,
27  hasPhysicalProducts,
28  hasUpgradeDowngradeItems,
29  isActionableCheckoutError,
30  makeCurrentPageFetcher,
31  normalizeServerCheckoutError,
32  parseCssVars,
33  productErrors,
34  renderedHref,
35  scrollToFirstVisibleError,
36  serverCheckoutErrorMessage,
37  setupOrderSummaries,
38  shippingOptionErrors,
39  tosErrors
40} from "./chunk-SYANC6RH.js";
41import "./chunk-W3RKY5WP.js";
42import {
43  CFFetcherError,
44  Fetcher,
45  MANUALLY_ABORTED,
46  checkoutNonceParams,
47  fetchCheckoutNonce,
48  init_fetcher,
49  init_nonce,
50  isBackendError,
51  isFetcherError,
52  isResponseError
53} from "./chunk-YSVSPNWW.js";
54import "./chunk-372FPXG6.js";
55import {
56  atom,
57  computed,
58  deepEqual,
59  formatNumberToCurrency,
60  init_general,
61  init_nanostores
62} from "./chunk-BY72GGKB.js";
63import "./chunk-4AIF3XZW.js";
64import "./chunk-TLMSI2UF.js";
65import {
66  init_input_v1
67} from "./chunk-FQR6BHZQ.js";
68import {
69  IntlTel_initPhoneInput,
70  init_cf_utils,
71  uuidv4
72} from "./chunk-KIZY5IRN.js";
73import "./chunk-5NUE6T5P.js";
74import {
75  CF2Component,
76  init_runtime,
77  registerComponent
78} from "./chunk-NQUHJ6NR.js";
79import {
80  __publicField,
81  init_define_process
82} from "./chunk-RFSPGZ3L.js";
83
84// projects/lib/packages/yggdrasil-blueprints/__generated__/packs/stripe-checkout.ts
85init_define_process();
86
87// projects/lib/packages/yggdrasil-blueprints/__generated__/blueprints/stripe-checkout.ts
88init_define_process();
89init_input_v1();
90
91// projects/lib/packages/yggdrasil-blueprints/src/Elements/Checkout/V2/StripeCheckout/stripeCheckout.ts
92init_define_process();
93
94// projects/lib/packages/yggdrasil-blueprints/src/Elements/Checkout/V2/StripeCheckout/summary.ts
95init_define_process();
96init_general();
97init_fetcher();
98var orderPreviewFetcher = makeCurrentPageFetcher({
99  customEvent: "CF2:OrderPreview"
100});
101var lastOrderPreviewData;
102var lastOrderPreviewResponse;
103function hasValidDataForLineItemSubtotal(payload) {
104  const { cart } = payload;
105  const productSelectErrors = productErrors(cart, true);
106  return !hasErrors(productSelectErrors);
107}
108async function fetchOrderPreview(payload, onStart) {
109  const dataToPreview = buildOrderPreviewPayload(payload);
110  if (lastOrderPreviewResponse && deepEqual(dataToPreview, lastOrderPreviewData)) {
111    return lastOrderPreviewResponse;
112  }
113  lastOrderPreviewData = dataToPreview;
114  if (onStart) onStart();
115  const response = await orderPreviewFetcher.post("/order_preview", dataToPreview);
116  if (!isResponseError(response)) {
117    lastOrderPreviewResponse = response;
118    return lastOrderPreviewResponse;
119  } else {
120    return response;
121  }
122}
123function processOrderPreviewResponseForSummary(summaryData) {
124  let nextInvoiceText;
125  if (summaryData.next_invoice_date) {
126    const nextInvoiceDate = new Date(summaryData.next_invoice_date);
127    const currentDate = /* @__PURE__ */ new Date();
128    const diff = nextInvoiceDate.getTime() - currentDate.getTime();
129    if (diff > 5 * 60 * 1e3) {
130      if (diff < 24 * 60 * 60 * 1e3) {
131        nextInvoiceText = nextInvoiceDate.toLocaleString();
132      } else {
133        nextInvoiceText = nextInvoiceDate.toLocaleDateString();
134      }
135    }
136  }
137  return {
138    currency: summaryData.currency,
139    line_items: summaryData.line_items,
140    total: {
141      amount: parseFloat(summaryData.total_amount?.amount),
142      formatted: summaryData.total_amount_formatted,
143      amount_cents: summaryData.total_amount_cents
144    },
145    discount: {
146      amount: parseFloat(summaryData.discount_amount?.amount),
147      formatted: summaryData.discount_amount_formatted,
148      amount_cents: summaryData.discount_amount_cents
149    },
150    lineItemSubtotal: {
151      amount: parseFloat(summaryData.line_item_subtotal?.amount),
152      formatted: summaryData.line_item_subtotal_formatted,
153      amount_cents: summaryData.line_item_subtotal_cents
154    },
155    discounts: (summaryData.discounts ?? []).map((discount) => {
156      return {
157        name: discount.name,
158        code: discount.code,
159        amount_formatted: "-" + formatNumberToCurrency(summaryData.currency_symbol, discount.amount)
160      };
161    }),
162    ...nextInvoiceText ? { next_invoice_date: nextInvoiceText } : {},
163    subtotal: {
164      amount: parseFloat(summaryData.subtotal_amount.amount),
165      formatted: summaryData.subtotal_amount_formatted,
166      amount_cents: summaryData.subtotal_amount_cents
167    },
168    shipping: {
169      amount: parseFloat(summaryData.shipping_amount.amount),
170      formatted: summaryData.shipping_amount_formatted,
171      amount_cents: summaryData.shipping_amount_cents
172    },
173    tax: {
174      amount: parseFloat(summaryData.tax_amount.amount),
175      formatted: summaryData.tax_amount_formatted,
176      amount_cents: summaryData.tax_amount_cents
177    },
178    ...summaryData.upcoming_invoice?.interim_amount ? {
179      interim: {
180        amount: parseFloat(summaryData.upcoming_invoice.interim_amount.amount),
181        formatted: summaryData.upcoming_invoice?.interim_amount_formatted,
182        amount_cents: summaryData.upcoming_invoice?.interim_amount_cents
183      }
184    } : {},
185    ...summaryData.upcoming_invoice ? {
186      upcoming_invoice: {
187        line_items: summaryData.upcoming_invoice.line_items.filter((i) => i.interim).map((item) => {
188          return {
189            variant_name: item.variant_name,
190            quantity: item.quantity,
191            amount: parseFloat(item.amount.amount),
192            formatted: item.amount_formatted
193          };
194        })
195      }
196    } : {}
197  };
198}
199function buildCartDetails(cart) {
200  const orderId = cart.order_id;
201  const lineItems = cart.items.map(({ price_id, line_item_id, variant_id, quantity }) => {
202    const data = {
203      variant_id,
204      price_id,
205      ...line_item_id ? { line_item_id } : {},
206      quantity
207    };
208    return data;
209  });
210  return { order_id: orderId, line_items: lineItems };
211}
212function buildOrderPreviewPayload(payload) {
213  const { address, shippingOption, cart, integrations_stripe_installation_id, coupon_code } = payload;
214  const isPhysical = hasPhysicalProducts(cart);
215  return {
216    integrations_stripe_installation_id,
217    order: {
218      full_preview: true,
219      coupon_codes: coupon_code,
220      ...address ? buildAddressParams(address, isPhysical) ?? {} : {},
221      ...buildCartDetails(cart),
222      ...shippingOption?.amount ? { selected_shipping_option: shippingOption } : {}
223    }
224  };
225}
226function buildAddressParams(address, isPhysical) {
227  const delivery_address = { ...address };
228  const billing_address = address.id ? { id: address.id } : { ...address };
229  if (isPhysical) {
230    return {
231      delivery_address,
232      billing_address
233    };
234  } else {
235    return { billing_address };
236  }
237}
238
239// projects/lib/packages/yggdrasil-blueprints/src/Elements/Checkout/V2/StripeCheckout/consts.ts
240init_define_process();
241var stripeElementsForms = ["linkAuthentication", "shipping", "billing", "payment"];
242var FORM_STRUCTURE_BY_TOTAL_STEPS = {
243  1: [["linkAuthentication", "shipping", "billing", "shippingOption", "products", "payment", "tos"]],
244  2: [
245    ["linkAuthentication", "contact"],
246    ["shipping", "billing", "shippingOption", "products", "payment", "tos"]
247  ],
248  3: [["products"], ["linkAuthentication", "contact"], ["shipping", "billing", "shippingOption", "payment", "tos"]]
249};
250
251// projects/lib/packages/yggdrasil-blueprints/src/Elements/Checkout/V2/StripeCheckout/errors.ts
252init_define_process();
253var StripeCheckoutErrorCode = /* @__PURE__ */ ((StripeCheckoutErrorCode2) => {
254  StripeCheckoutErrorCode2[StripeCheckoutErrorCode2["STRIPE_LIB_INITIALIZATION_ERROR"] = 1] = "STRIPE_LIB_INITIALIZATION_ERROR";
255  StripeCheckoutErrorCode2[StripeCheckoutErrorCode2["STRIPE_ADDRESS_ELEMENT_INITIALIZATION_ERROR"] = 2] = "STRIPE_ADDRESS_ELEMENT_INITIALIZATION_ERROR";
256  StripeCheckoutErrorCode2[StripeCheckoutErrorCode2["STRIPE_PAYMENT_ELEMENT_INITIALIZATION_ERROR"] = 4] = "STRIPE_PAYMENT_ELEMENT_INITIALIZATION_ERROR";
257  StripeCheckoutErrorCode2[StripeCheckoutErrorCode2["STRIPE_LINK_AUTHENTICATION_ELEMENT_INITIALIZATION_ERROR"] = 8] = "STRIPE_LINK_AUTHENTICATION_ELEMENT_INITIALIZATION_ERROR";
258  StripeCheckoutErrorCode2[StripeCheckoutErrorCode2["STRIPE_EXPRESS_CHECKOUT_ELEMENT_INITIALIZATION_ERROR"] = 16] = "STRIPE_EXPRESS_CHECKOUT_ELEMENT_INITIALIZATION_ERROR";
259  StripeCheckoutErrorCode2[StripeCheckoutErrorCode2["API_SESSION_INITIALIZATION_ERROR"] = 32] = "API_SESSION_INITIALIZATION_ERROR";
260  StripeCheckoutErrorCode2[StripeCheckoutErrorCode2["MOUNT_REJECTED_ERROR"] = 64] = "MOUNT_REJECTED_ERROR";
261  return StripeCheckoutErrorCode2;
262})(StripeCheckoutErrorCode || {});
263function getStripeCheckoutErrorMessage(stripeErrors) {
264  if (stripeErrors.length > 0) {
265    const errorCodeMask = `0x${Number(stripeErrors.reduce((acc, val) => acc | val, 0)).toString(16)}`;
266    return "Error initializing Checkout Element. Code: " + errorCodeMask;
267  }
268}
269function getInitialStripeCheckoutErrors() {
270  const initialCriticalErrors = [];
271  if (!globalThis.globalResourceData.productVariantWithNoBump?.id) {
272    initialCriticalErrors.push({ code: ERROR_CODES.EMPTY_PRODUCTS_ERROR });
273  }
274  return initialCriticalErrors;
275}
276
277// projects/lib/packages/yggdrasil-blueprints/src/Elements/Checkout/V2/StripeCheckout/stripeCheckout.ts
278init_fetcher();
279init_cf_utils();
280
281// projects/lib/packages/yggdrasil-blueprints/src/Elements/Checkout/V2/StripeCheckout/api.ts
282init_define_process();
283init_fetcher();
284init_nonce();
285function makeApiFetcher(options) {
286  const { headers, ...requestOptions } = options;
287  const fetcher = new Fetcher({
288    debug: true,
289    pathPrefix: "/user_pages/api/v1/",
290    headers: {
291      Accept: "application/json",
292      "Content-Type": "application/json",
293      ...headers ?? {}
294    },
295    requestOptions: {
296      retries: 3,
297      timeoutMS: 3e4,
298      timeoutAfterRetrial: 1e3,
299      shouldCaptureServerError: true,
300      convertThrowToErrorResponse: true,
301      ...requestOptions
302    }
303  });
304  return fetcher;
305}
306var stripeSessionApiFetcher = makeApiFetcher({
307  onlyOneInflightRequest: true,
308  simulateNetworkError: false,
309  // `stripe_get_session` only syncs the contact and mints a customer session, so a
310  // replay is harmless. It is also the call that fails when Stripe's per-object lock
311  // is held (ENG-7225) — the one case where retrying a 5xx is exactly the fix.
312  retryServerErrors: true,
313  // Same reasoning for a timed-out attempt. This is deliberately not switched on for
314  // `stripeSubmitFetcher` below: replaying a submit is a much heavier claim to make.
315  retryTimeouts: true,
316  // ...but bound the sequence in wall clock. Making `retries` finally apply to timeouts is
317  // a behaviour change, and on the inherited `timeoutMS: 30000` / `retries: 3` it would
318  // cost the buyer 3 x 30s + 2 x 1s = 92s of blank checkout before the banner, and issue 3
319  // backend requests per browser. Aborting a fetch does not stop the Rails request — Puma
320  // holds the thread until it responds — so those retries would amplify load onto a pool
321  // whose threads are already parked on the object-lock sleep, which is precisely when a
322  // timeout is most likely. 15s clears the server's 8s sleep budget plus a normal Stripe
323  // round trip, and 2 attempts keep the retry that actually fixes a transient lock while
324  // holding the worst case at ~31s — the same ceiling buyers saw before.
325  timeoutMS: 15e3,
326  retries: 2
327});
328var stripeSubmitFetcher = new Fetcher({
329  debug: true,
330  method: "POST",
331  headers: {
332    Accept: "application/json",
333    "Content-Type": "application/json",
334    "X-CF2-POST-TYPE": "submit"
335  },
336  requestOptions: {
337    retries: 3,
338    timeoutMS: 6e4,
339    timeoutAfterRetrial: 1e3,
340    shouldCaptureServerError: true,
341    convertThrowToErrorResponse: true,
342    onlyOneInflightRequest: true,
343    canAbort: false
344  }
345});
346function isStripeError(error) {
347  if (typeof error === "object") {
348    const stripeError = error;
349    if (stripeError?.code && stripeError?.message) {
350      return true;
351    }
352  }
353  return false;
354}
355async function postSubmit(payload) {
356  const nonce = await fetchCheckoutNonce();
357  const response = await stripeSubmitFetcher.fetch(
358    renderedHref(),
359    {
360      credentials: "same-origin",
361      body: JSON.stringify({ ...payload, ...checkoutNonceParams(nonce) })
362    },
363    {}
364  );
365  if (isResponseError(response)) {
366    return response;
367  } else {
368    let body;
369    if (response.headers.get("Content-Type").includes("text/html")) {
370      body = {
371        next_url: response.headers.get("Location")
372      };
373    } else {
374      body = await response.json();
375    }
376    if (response.ok) {
377      return {
378        ...body,
379        headers: {
380          get: (name) => response.headers?.get(name)
381        }
382      };
383    } else if (response.status === 422) {
384      return {
385        fetcherErrorType: 1 /* Backend */,
386        error: normalizeServerCheckoutError(body)
387      };
388    } else {
389      return {
390        fetcherErrorType: 0 /* Internal */,
391        error: `Unexpected response status ${response.status}`
392      };
393    }
394  }
395}
396
397// projects/lib/packages/yggdrasil-blueprints/src/Elements/Checkout/V2/StripeCheckout/store.ts
398init_define_process();
399init_nanostores();
400function ensureCheckoutStoreInitialized() {
401  globalThis.Checkout.store = globalThis.Checkout.store ?? {
402    state: atom("start" /* START */),
403    coupons: {
404      appliedCode: atom(""),
405      currentCode: atom(""),
406      errorMessage: atom(""),
407      state: atom("ready" /* READY */)
408    },
409    summary: atom({
410      state: "waiting" /* WAITING */,
411      data: {}
412    }),
413    checkout: {
414      step: atom(0)
415    },
416    submitting: atom({
417      state: "idle" /* IDLE */
418    }),
419    criticalErrors: atom(getInitialStripeCheckoutErrors()),
420    featureFlags: {},
421    selectedOrderDetailId: atom(null)
422  };
423  globalThis.Checkout.computed = globalThis.Checkout.computed ?? {
424    checkoutCart: buildProductSelectBatched()
425  };
426  globalThis.Checkout.computed.isCouponReady = computed(
427    [globalThis.Checkout.store.state, globalThis.Checkout.computed.checkoutCart],
428    (state, cart) => {
429      const showAllProductErrors = true;
430      const pErrors = globalThis.Checkout.utils.productErrors(cart, showAllProductErrors);
431      return state == globalThis.Checkout.StoreStates.START && !globalThis.Checkout.utils.hasErrors(pErrors);
432    }
433  );
434  return {
435    ...globalThis.Checkout.store,
436    ...globalThis.Checkout.computed
437  };
438}
439
440// projects/lib/packages/yggdrasil-blueprints/src/Elements/Checkout/V2/StripeCheckout/stripe.ts
441init_define_process();
442var Stripe;
443var stripeCurrency = "usd";
444var stripeInstallationId = "";
445function ensureStripeInitialized() {
446  if (!Stripe) {
447    const {
448      stripePublishableKey,
449      stripeAccountId,
450      stripeInstallationId: instalationId,
451      stripeCurrency: currency
452    } = document.querySelector("#payment-gateway-keys").dataset;
453    Stripe = globalThis.Stripe?.(stripePublishableKey, {
454      stripeAccount: stripeAccountId,
455      betas: ["disable_deferred_intent_client_validation_beta_1"]
456    });
457    stripeInstallationId = instalationId;
458    stripeCurrency = currency;
459  }
460  return Stripe;
461}
462function ensureStripeScriptLoaded() {
463  if (globalThis.Stripe) return Promise.resolve();
464  const lazyScript = document.querySelector('script[data-lazy-src*="stripe"]');
465  if (!lazyScript) return Promise.resolve();
466  return new Promise((resolve, reject) => {
467    const script = document.createElement("script");
468    script.src = lazyScript.getAttribute("data-lazy-src");
469    script.onload = () => resolve();
470    script.onerror = () => reject(new Error("Failed to load Stripe.js"));
471    lazyScript.parentNode.insertBefore(script, lazyScript);
472    lazyScript.remove();
473  });
474}
475function buildStripeFonts() {
476  const fonts = [];
477  const googleFontsSrc = document.getElementById("cf-lander-font-families")?.href;
478  if (googleFontsSrc) {
479    fonts.push({ cssSrc: googleFontsSrc });
480  }
481  try {
482    const serializedCustomFonts = JSON.parse(
483      document.getElementById("cf-lander-serialized-custom-fonts")?.textContent ?? "[]"
484    );
485    fonts.push(
486      ...serializedCustomFonts.map(
487        (customFont) => ({
488          family: customFont.family,
489          src: customFont.files.map((src) => `url(${new URL(src, document.location.href).toString()})`).join(",")
490        })
491      )
492    );
493  } catch (e) {
494    console.error("Error preparing custom fonts to stripe elements", e);
495  }
496  return fonts;
497}
498
499// projects/lib/packages/yggdrasil-blueprints/src/Elements/Checkout/V2/StripeCheckout/enums.ts
500init_define_process();
501var CheckoutStates = /* @__PURE__ */ ((CheckoutStates2) => {
502  CheckoutStates2["GUEST"] = "guest";
503  CheckoutStates2["OTO"] = "oto";
504  CheckoutStates2["SAVED"] = "saved";
505  return CheckoutStates2;
506})(CheckoutStates || {});
507
508// projects/lib/packages/yggdrasil-blueprints/src/Elements/Checkout/V2/StripeCheckout/stripeCheckout.ts
509init_cf_utils();
510function createInstance(component) {
511  const stripe = ensureStripeInitialized();
512  const store = ensureCheckoutStoreInitialized();
513  return new StripeCheckoutLogic(component, stripe, store);
514}
515var CHECKOUT_STATES = Object.values(CheckoutStates);
516var STRIPE_INSTRUMENT_REJECTION_CODES = /* @__PURE__ */ new Set([
517  "card_declined",
518  "card_not_supported",
519  "currency_not_supported",
520  "expired_card",
521  "incorrect_cvc",
522  "incorrect_number",
523  "incorrect_zip",
524  "processing_error"
525]);
526var StripeCheckoutLogic = class {
527  constructor(component, stripe, store) {
528    this.component = component;
529    this.stripe = stripe;
530    this.store = store;
531    __publicField(this, "_stripeData");
532    __publicField(this, "guestInputFields", {});
533    __publicField(this, "paymentDeclined", false);
534    __publicField(this, "submitedOnce", false);
535    __publicField(this, "checkoutData", { contact: {}, address: {} });
536    __publicField(this, "digitalPaymentData", { contact: {}, address: {}, shippingRateId: "" });
537    __publicField(this, "parsedAppearence");
538    __publicField(this, "summaryLineItemSubtotalCents");
539    __publicField(this, "summaryLineItems");
540    __publicField(this, "stripeElementOptions");
541    __publicField(this, "stripeFonts");
542    __publicField(this, "shippingComponents");
543    __publicField(this, "selectedShippingOption");
544    __publicField(this, "errors");
545    __publicField(this, "element");
546    __publicField(this, "loadingComponents");
547    __publicField(this, "submitButtons");
548    __publicField(this, "submitNotifications");
549    __publicField(this, "sendOrderPreviewTimer");
550    __publicField(this, "lastSubmitFailure", null);
551    __publicField(this, "setupErrors");
552    __publicField(this, "oldHasPhysical");
553    __publicField(this, "preventOrderPreview", false);
554    __publicField(this, "submitInFlight", false);
555    // Identity-tracked entry the summary subscriber pushes into `errors.globalErrors` so we
556    // can remove exactly it without clobbering globals set by submit-time flows.
557    __publicField(this, "summaryErrorEntry", null);
558    __publicField(this, "couponStateBeforeApplying");
559    __publicField(this, "sentToTracking", { email: null, firstName: null, lastName: null, phone: null });
560    __publicField(this, "trackingTimer");
561    this._stripeData = {};
562    CHECKOUT_STATES.forEach((state) => {
563      this._stripeData[state] = {
564        stripeElements: null,
565        mountedElements: {
566          shipping: {},
567          billing: {},
568          expressCheckout: {},
569          linkAuthentication: {},
570          payment: {}
571        }
572      };
573    });
574    this.element = component.element;
575    this.errors = { globalErrors: [], fields: {} };
576    this.setupErrors = [];
577    this.parsedAppearence = parseCssVars(component.element, this.component.appearance);
578    this.stripeFonts = buildStripeFonts();
579    const cart = this.store.checkoutCart.get();
580    if (globalThis.sessionData.contact.email) {
581      this.checkoutData.contact.email = globalThis.sessionData.contact.email;
582    }
583    this.updateWithShippingAddress(cart);
584    globalThis.montedElements = this.montedElements;
585    console.log("[Stripe] appearance => ", this.parsedAppearence);
586  }
587  triggerTrackingForStripeElement(data) {
588    clearTimeout(this.trackingTimer);
589    this.trackingTimer = setTimeout(() => {
590      try {
591        if (data.email && this.sentToTracking.email !== data.email) {
592          this.sentToTracking.email = data.email;
593          this.createTrackingInput("email", data.email);
594        }
595        if (data.firstName && this.sentToTracking.firstName !== data.firstName && !this.guestInputFields.first_name) {
596          this.sentToTracking.firstName = data.firstName;
597          this.createTrackingInput("first_name", data.firstName);
598        }
599        if (data.lastName && this.sentToTracking.lastName !== data.lastName && !this.guestInputFields.last_name) {
600          this.sentToTracking.lastName = data.lastName;
601          this.createTrackingInput("last_name", data.lastName);
602        }
603        if (data.phone && this.sentToTracking.phone !== data.phone && !this.guestInputFields.phone_number) {
604          this.sentToTracking.phone = data.phone;
605          this.createTrackingInput("phone_number", data.phone);
606        }
607      } catch (error) {
608        console.error("[Stripe] Tracking helper error:", error);
609      }
610    }, 200);
611  }
612  createTrackingInput(name, value) {
613    const input = document.createElement("input");
614    input.type = name.includes("email") ? "email" : "text";
615    input.name = name;
616    input.value = value;
617    input.style.cssText = "position:absolute;
617left:-9999px;opacity:0;pointer-events:none";
618    document.body.appendChild(input);
619    input.dispatchEvent(new Event("focusout", { bubbles: true }));
620    input.dispatchEvent(new Event("change", { bubbles: true }));
621    input.dispatchEvent(new Event("blur", { bubbles: true }));
622    document.body.removeChild(input);
623  }
624  async ensureStripeSession() {
625    const startedAt = Date.now();
626    const sessionResponse = await stripeSessionApiFetcher.post("checkouts/stripe_get_session", {
627      referrer_url: window.location.href,
628      integrations_stripe_installation_id: stripeInstallationId
629    });
630    if (isResponseError(sessionResponse)) {
631      const failureKind = this.sessionFailureKind(sessionResponse);
632      const durationMs = Date.now() - startedAt;
633      if (failureKind === "superseded" && !this.component.element.isConnected) {
634        globalThis.Honeybadger?.notify("StripeCheckout session superseded", {
635          context: { durationMs, checkoutState: this.getState() }
636        });
637        return null;
638      }
639      this.pushSetupError(32 /* API_SESSION_INITIALIZATION_ERROR */, void 0, {
640        failureKind,
641        durationMs
642      });
643    } else {
644      return sessionResponse;
645    }
646  }
647  // Maps the fetcher error to a stable label:
648  //   'timeout_error' — every attempt hit the fetcher's own 30s timer
649  //   'server_error'  — the endpoint 5xx'd on every attempt
650  //   'network_error' — the request itself failed
651  //   'superseded'    — a later request on the same fetcher replaced this one
652  sessionFailureKind(response) {
653    if (!isFetcherError(response)) return "backend_error";
654    const error = response.error;
655    if (error === MANUALLY_ABORTED) return "superseded";
656    if (error instanceof CFFetcherError) return error.type.toLowerCase();
657    return String(error);
658  }
659  backfillContactData() {
660    const shouldUseGarlic = this.getState() === "guest";
661    ["first_name", "last_name", "email", "phone_number", "name"].forEach((k) => {
662      if (k === "phone_number" && !this.hasPhoneNumber()) return;
663      const garlicValue = shouldUseGarlic ? globalThis.cfGarlicUtils.retrieve(k) : "";
664      const sessionValue = globalThis.sessionData.contact[k];
665      if (!garlicValue && !sessionValue) return;
666      if (k === "name" && !this.checkoutData.contact.first_name) {
667        const [first_name, ...last_names] = garlicValue.split(" ");
668        this.checkoutData.contact.first_name = first_name;
669        this.checkoutData.contact.last_name = last_names.join(" ");
670      } else {
671        this.checkoutData.contact[k] = sessionValue ?? garlicValue;
672      }
673    });
674    this.syncInputFields();
675  }
676  updateInputState(name, value) {
677    globalThis.cfGarlicUtils.store(name, value);
678    if (value) {
679      this.guestInputFields[name].closest('[data-page-element="Input/V1"]').classList.add("hasValue");
680    } else {
681      this.guestInputFields[name].closest('[data-page-element="Input/V1"]').classList.remove("hasValue");
682    }
683  }
684  storeShippingDataFromExpress(data) {
685    if (!data) return;
686    if (data.name) globalThis.cfGarlicUtils.store("name", data.name);
687    if (!data.address) return;
688    const address = convertAddressFromStripe(data.address);
689    Object.keys(address).forEach((k) => {
690      if (address[k]) globalThis.cfGarlicUtils.store(k, address[k]);
691    });
692  }
693  syncInputFields() {
694    Object.keys(this.guestInputFields).forEach((k) => {
695      const value = this.checkoutData.contact[k];
696      if (k == "phone_number") {
697        ;
698        this.guestInputFields[k].iti.setNumber(value ?? "");
699      } else {
700        this.guestInputFields[k].value = value ?? "";
701      }
702      this.updateInputState(k, value);
703    });
704  }
705  errorInputForInput(input) {
706    const id = input.closest("[data-page-element]").getAttribute("id");
707    return this.element.querySelector(`[data-input-id="${id}"]`);
708  }
709  updateWithShippingAddress(cart) {
710    this.checkoutData.address = {};
711    if (hasPhysicalProducts(cart)) {
712      const sessionShippingAddress = globalThis.sessionData.contact.shipping_addresses?.[0] ?? globalThis.sessionData.contact.billing_addresses?.[0];
713      if (sessionShippingAddress) {
714        this.checkoutData.address = convertAddressFromSession(sessionShippingAddress);
715      }
716    }
717    if (this.getState() == "oto" && !hasPhysicalProducts(cart)) {
718      const sessionBillingAddress = globalThis.sessionData.contact.billing_addresses?.[0];
719      if (sessionBillingAddress) {
720        this.checkoutData.address = convertAddressFromSession(sessionBillingAddress);
721      }
722    }
723    if (globalThis.sessionData.contact) {
724      this.checkoutData.contact.first_name = globalThis.sessionData.contact.first_name;
725      this.checkoutData.contact.last_name = globalThis.sessionData.contact.last_name;
726      this.checkoutData.contact.phone_number = globalThis.sessionData.contact.phone_number;
727      this.syncInputFields();
728    }
729  }
730  initializeElements(session, amount) {
731    const cart = this.store.checkoutCart.get();
732    this.stripeElementOptions = {
733      amount,
734      mode: getStripeMode(cart, amount),
735      currency: stripeCurrency.toLowerCase() ?? "usd",
736      appearance: this.parsedAppearence,
737      loader: "never",
738      fonts: this.stripeFonts,
739      locale: this.component.locale,
740      ...this.component.paymentGateway.disable_stripe_payment_method_future_usage ? {} : { setup_future_usage: "off_session" },
741      ...session?.can_use_dpm ? {} : { payment_method_types: ["card"] },
742      ...session?.stripe_options ?? {}
743    };
744    this.stripeElements = this.stripe.elements(this.stripeElementOptions);
745    globalThis.stripeElements = this.stripeElements;
746    this.stripeElements.on("update-end", () => {
747      this.updatingExpressEnded();
748    });
749  }
750  mount() {
751    if (!this.stripe) {
752      this.pushSetupError(1 /* STRIPE_LIB_INITIALIZATION_ERROR */);
753      return;
754    }
755    this.submitNotifications = this.component.getComponentGroup(CheckoutSubmitNotificationV1);
756    this.detectIfReturningFailedPayment();
757    this.backfillContactData();
758    Promise.all([
759      this.ensureStripeSession(),
760      CheckoutExistingOrders.fetch({
761        integrations_stripe_installation_id: stripeInstallationId
762      }).catch((error) => {
763        const cause = error instanceof CheckoutCriticalError ? error.cause : null;
764        if (cause !== MANUALLY_ABORTED) throw error;
765      }).then(() => {
766        this.updateSubmitButton();
767      })
768    ]).then(([sessionData]) => {
769      if (sessionData) {
770        const cart = this.store.checkoutCart.get();
771        const intialAmount = getCartEstimatedTotal(cart);
772        this.initializeElements(sessionData, intialAmount);
773        this.sendOrderPreview();
774        setTimeout(() => {
775          this.oneTimeListeners();
776        }, 1e3);
777      }
778    }).catch((error) => {
779      this.pushSetupError(64 /* MOUNT_REJECTED_ERROR */, void 0, {
780        failureKind: "mount_rejected",
781        mountError: String(error?.message ?? error),
782        // Keep the stack and any wrapped cause: the notify message is held constant per
783        // code for grouping, so context is the only place the specific failure survives.
784        mountErrorStack: error?.stack,
785        mountErrorCause: error?.cause ? String(error.cause?.message ?? error.cause) : void 0
786      });
787    });
788    setupOrderSummaries(this.component);
789    this.component.setHandlers(CheckoutMultiStepV2, {
790      onValidateStep: (step) => this.validateStep(step),
791      onStepChange: (oldStep, step) => {
792        this.stripeElements.update({ appearance: this.parsedAppearence });
793        const formStructure = FORM_STRUCTURE_BY_TOTAL_STEPS[this.getTotalSteps()];
794        if (formStructure[oldStep].includes("contact") && oldStep < step) {
795          collectLeads(this.checkoutData.contact);
796        }
797      }
798    });
799    this.component.setHandlers(CheckoutTosV1, {
800      onAcceptedChange: (accepted) => {
801        if (this.submitedOnce && accepted) {
802          this.clearErrors("tos");
803          this.showErrors();
804        }
805      }
806    });
807    this.shippingComponents = this.component.getComponentGroup(CheckoutShippingProfileSelectV1, {
808      onSelectOption: (option) => this.selectShippingOption(option)
809    });
810    window.addEventListener("ON_APPLY_COUPON", (event) => {
811      this.sendOrderPreview(event.detail);
812    });
813    window.addEventListener("ON_CLEAR_COUPON", (event) => {
814      this.sendOrderPreview(event.detail);
815    });
816    this.loadingComponents = this.component.getComponentGroup(CheckoutLoadingV1);
817    this.submitButtons = this.component.getComponentGroup(CheckoutSubmitButtonV1, {
818      // NOTE: returned so the button can tell a finished attempt from one that is
819      // still running, and unlock itself when we never got as far as the POST.
820      onSubmit: () => this.handleSubmit(this.selectedShippingOption)
821    });
822  }
823  detectIfReturningFailedPayment() {
824    const urlParams = new URLSearchParams(window.location.search);
825    const failedPaymentMessage = urlParams.get("failed_payment_message");
826    if (failedPaymentMessage) {
827      const decodedFailedMessage = decodeURIComponent(failedPaymentMessage.replace(/\+/g, " "));
828      this.handleError({ message: decodedFailedMessage }, true);
829      const visibleSubmitButton = this.getStateElement().querySelector("[data-page-element='CheckoutSubmitButton/V1']");
830      $("html, body").stop(true, true).animate(
831        {
832          scrollTop: $(visibleSubmitButton).offset().top - 100
833        },
834        500
835      );
836      this.submitedOnce = true;
837    }
838  }
839  submitCheckout(redirectOverride) {
840    return this.handleSubmit(this.selectedShippingOption, false, redirectOverride);
841  }
842  clearErrors(field) {
843    this.errors.globalErrors = [];
844    if (field) {
845      delete this.errors.fields[field];
846    }
847  }
848  clearAllErrors() {
849    this.errors.globalErrors = [];
850    this.errors.fields = {};
851  }
852  pushGlobalError(message) {
853    this.errors.globalErrors.push({ message });
854  }
855  pushFieldError(field, message) {
856    this.errors.fields[field] = { message };
857  }
858  showErrors({ shouldScrollToError } = { shouldScrollToError: false }) {
859    const stepStore = this.store.checkout.step;
860    const currentStep = stepStore.get();
861    const totalSteps = this.getTotalSteps();
862    let wrapperStateElement = this.getStateElement();
863    let hasFieldErrors = false;
864    let firstFieldWithError = null;
865    const formStructure = FORM_STRUCTURE_BY_TOTAL_STEPS[totalSteps];
866    for (let stepIndex = 0; stepIndex < formStructure.length; stepIndex++) {
867      const stepFields = formStructure[stepIndex];
868      for (const field of stepFields) {
869        if (this.errors.fields[field]) {
870          hasFieldErrors = true;
871          if (stepIndex !== currentStep) stepStore.set(stepIndex);
872          if (!firstFieldWithError) firstFieldWithError = field;
873          break;
874        }
875      }
876    }
877    if (totalSteps > 1) {
878      wrapperStateElement = wrapperStateElement.querySelector(
879        `.elMultiStepBody[data-step-number="${stepStore.get() + 1}"]`
880      );
881    }
882    Object.keys(this.guestInputFields).forEach((field) => {
883      if (this.errors.fields[field]) {
884        const errorfield = this.errorInputForInput(this.guestInputFields[field]);
885        errorfield.style.height = "20px";
886        errorfield.previousElementSibling.classList.add("elInputError");
887        errorfield.textContent = this.errors.fields[field].message;
888      }
889    });
890    const generalErrorsWrapper = wrapperStateElement.querySelector(".checkout-general-errors-wrapper");
891    this.component.element.querySelectorAll(".checkout-general-errors-wrapper").forEach((w) => {
892      w.classList.add("forceHide");
893      const span = w.querySelector("span");
894      if (span) span.innerHTML = "";
895    });
896    const hasGlobalErrors = this.errors.globalErrors.length && this.errors?.globalErrors?.[0]?.message;
897    if (hasGlobalErrors) {
898      const errorMessage = this.errors.globalErrors[0].message;
899      generalErrorsWrapper.querySelector("span").innerHTML = errorMessage;
900      generalErrorsWrapper.classList.remove("forceHide");
901    }
902    if (shouldScrollToError && (hasGlobalErrors || hasFieldErrors)) {
903      if (stripeElementsForms.includes(firstFieldWithError)) {
904        const scrollToElement = wrapperStateElement.querySelector(`.stripe-${firstFieldWithError}`);
905        scrollToFirstVisibleError(scrollToElement);
906      } else {
907        scrollToFirstVisibleError(generalErrorsWrapper);
908      }
909    }
910  }
911  removeSubmitNotification() {
912    this.submitNotifications.setStatus("", "", "");
913  }
914  setSubmitNotification(text, subtext, extraText) {
915    this.submitNotifications.setStatus(text, subtext, extraText);
916  }
917  get montedElements() {
918    return this._stripeData[this.getState()].mountedElements;
919  }
920  get stripeElements() {
921    return this._stripeData[this.getState()].stripeElements;
922  }
923  set stripeElements(stripeElement) {
924    this._stripeData[this.getState()].stripeElements = stripeElement;
925  }
926  getState() {
927    return this.component.element.dataset.currentState;
928  }
929  setState(state) {
930    this.component.element.dataset.currentState = state;
931  }
932  updatingExpressStarted() {
933    this.getStateElement().querySelector(".stripe-express-loader-wrapper")?.classList.remove("forceHide");
934    this.getStateElement().querySelector(".stripe-expressCheckout")?.classList.add("elHidden");
935  }
936  updatingExpressEnded() {
937    this.getStateElement().querySelector(".stripe-express-loader-wrapper")?.classList.add("forceHide");
938    this.getStateElement().querySelector(".stripe-expressCheckout")?.classList.remove("elHidden");
939  }
940  getStateElement() {
941    return this.component.element.querySelector(`[data-state="${this.component.element.dataset.currentState}"]`);
942  }
943  unmountElement(name) {
944    if (!this.montedElements[name].element) return;
945    this.montedElements[name].element.unmount();
946    const stripeElement = this.getStateElement().querySelector(`.stripe-${name}`);
947    delete stripeElement?.style.opacity;
948    this.montedElements[name].lastChangeEvent = null;
949    this.montedElements[name].mounted = false;
950  }
951  mountElement(name, options, overrideSelector, overrideMountName) {
952    console.log("[Stripe] mounteElement =>", name, options);
953    const state = this.getState();
954    const selector = overrideSelector ?? `.stripe-${name}`;
955    const hasElement = this.getStateElement().querySelector(selector);
956    if (!hasElement) return;
957    const mountName = overrideMountName ?? name;
958    if (!this.montedElements[mountName].element) {
959      options = options ?? {};
960      this.montedElements[mountName].element = this.stripeElements.create(name, options);
961    }
962    this.montedElements[mountName].element.mount(`[data-state=${state}] ${selector}`);
963    this.montedElements[mountName].mounted = true;
964  }
965  mountLink() {
966    if (this.montedElements.linkAuthentication.mounted) return;
967    const options = {};
968    if (this.checkoutData.contact.email) {
969      options.defaultValues = { email: this.checkoutData.contact.email };
970    }
971    this.mountElement("linkAuthentication", options);
972    this.montedElements.linkAuthentication.element?.on("change", (event) => {
973      this.removeSubmitNotificationStripeElementChange();
974      console.log("[Stripe] linkAuthentication [incoming-event]: ", event);
975      delete this.errors.fields["linkAuthentication"];
976      this.montedElements.linkAuthentication.lastChangeEvent = event;
977      if (!event.complete) return;
978      this.checkoutData.contact.email = event.value.email;
979      this.triggerTrackingForStripeElement({ email: event.value.email });
980      this.updatePaymentElementDefaultValues();
981    });
982    this.montedElements.linkAuthentication.element?.on("ready", () => {
983      this.elementReady("linkAuthentication");
984      this.elementReady("contact-form");
985    });
986    this.montedElements.linkAuthentication.element?.on(
987      "loaderror",
988      (error) => this.handleStripeElementLoadingError(error)
989    );
990  }
991  pushSetupError(code, customMessage, context) {
992    this.setupErrors.push(code);
993    const setupErrorComponent = this.component.getComponent(CheckoutConfigurationErrorV1);
994    const errorMessage = customMessage || getStripeCheckoutErrorMessage(this.setupErrors);
995    setupErrorComponent.setErrors(errorMessage);
996    scrollToFirstVisibleError(setupErrorComponent.element);
997    globalThis.Honeybadger?.notify(`StripeCheckout setup error: ${StripeCheckoutErrorCode[code]}`, {
998      context: {
999        errorCode: `0x${code.toString(16)}`,
1000        // The banner shows the OR of all codes pushed so far. Report it too so
1001        // a banner screenshot (e.g. "Code: 0x24") can be matched to notices.
1002        errorMask: `0x${this.setupErrors.reduce((acc, val) => acc | val, 0).toString(16)}`,
1003        checkoutState: this.getState(),
1004        hasContactEmail: Boolean(globalThis.sessionData?.contact?.email),
1005        ...context ?? {}
1006      }
1007    });
1008  }
1009  handleStripeElementLoadingError({ elementType, error }) {
1010    const errorEnumName = `STRIPE_${elementType.split(/(?=[A-Z])/).join("_").toUpperCase()}_ELEMENT_INITIALIZATION_ERROR`;
1011    const errorCode = StripeCheckoutErrorCode[errorEnumName];
1012    const errorMessage = error?.message ? `Error loading ${elementType} element: ${error.message}` : getStripeCheckoutErrorMessage([errorCode]);
1013    this.pushSetupError(errorCode, errorMessage, { elementType, stripeError: error });
1014    console.error(`Stripe ${elementType} element initialization error: `, error);
1015  }
1016  getTotalSteps() {
1017    return this.getState() !== "guest" ? 1 : this.component.totalSteps;
1018  }
1019  mountAddress() {
1020    const options = this.addressOptions;
1021    const mode = options.mode;
1022    const state = this.getState();
1023    if (this.montedElements[mode].mounted) return;
1024    if (mode === "billing" && state === "oto" /* OTO */ && !this.paymentDeclined) return;
1025    const stateElement = this.getStateElement();
1026    const otherMode = options.mode == "shipping" ? "billing" : "shipping";
1027    stateElement.querySelector(`.stripe-address-${otherMode}-container`)?.classList.add("forceHide");
1028    this.unmountElement(otherMode);
1029    if (mode === "billing" && !this.component.billingEnabled) {
1030      const contactFormElement = stateElement.querySelector(".stripe-contact-form");
1031      contactFormElement?.classList.remove("forceHide");
1032      return;
1033    }
1034    if (mode === "shipping" && !this.component.billingEnabled && this.component.totalSteps === 1) {
1035      const contactFormElement = stateElement.querySelector(".stripe-contact-form");
1036      contactFormElement?.classList.add("forceHide");
1037    }
1038    const stripeElement = stateElement.querySelector(`.stripe-${mode}`);
1039    stateElement.querySelector('[data-stripe-loading-element="address"]').classList.remove("forceHide");
1040    stripeElement.classList.add("elAbsolute");
1041    delete stripeElement.style.opacity;
1042    stateElement.querySelector(`.stripe-address-${mode}-container`)?.classList.remove("forceHide");
1043    this.mountElement("address", options, `.stripe-${mode}`, mode);
1044    this.montedElements[mode].element?.on("change", (event) => {
1045      this.removeSubmitNotificationStripeElementChange();
1046      this.montedElements[mode].lastChangeEvent = event;
1047      delete this.errors.fields[mode];
1048      const parsedData = this.parsedAddressEventData(event);
1049      console.log("[Stripe] address [incoming-event]: ", event);
1050      this.checkoutData.contact.first_name = parsedData.first_name;
1051      this.checkoutData.contact.last_name = parsedData.last_name;
1052      this.checkoutData.contact.phone_number = parsedData.phone_number;
1053      this.triggerTrackingForStripeElement({
1054        firstName: parsedData.first_name,
1055        lastName: parsedData.last_name,
1056        phone: parsedData.phone_number
1057      });
1058      this.syncInputFields();
1059      this.updatePaymentElementDefaultValues();
1060      this.checkoutData.address = parsedData.address;
1061      if (hasPhysicalProducts(globalThis.Checkout.computed.checkoutCart.get())) {
1062        if (this.hasValidAddress(this.checkoutData.address)) {
1063          this.shippingComponents.setLoading();
1064        } else {
1065          this.shippingComponents.setInvalidAddress();
1066        }
1067      }
1068      this.sendOrderPreview({ throttle: true });
1069    });
1070    this.montedElements[mode].element?.on("ready", () => {
1071      stateElement.querySelector(`.stripe-address-${mode}-container`).classList.remove("forceHide");
1072      this.elementReady(mode);
1073    });
1074    this.montedElements[mode].element?.on("loaderror", (error) => this.handleStripeElementLoadingError(error));
1075  }
1076  parsedAddressEventData(event) {
1077    const data = {};
1078    if (event.value.firstName || event.value.lastName) {
1079      data.first_name = event.value.firstName;
1080      data.last_name = event.value.lastName;
1081    } else {
1082      const [first_name, ...last_name] = (event.value?.name ?? "").split(" ");
1083      data.first_name = first_name;
1084      data.last_name = last_name.join(" ");
1085    }
1086    data.phone_number = event.value.phone;
1087    data.address = convertAddressFromStripe(event.value.address);
1088    return data;
1089  }
1090  get paymentOptions() {
1091    let address = "auto";
1092    if (!this.component.billingEnabled && this.component.billingFields === "if_required") {
1093      address = "if_required";
1094    }
1095    return {
1096      defaultValues: this.generatePaymentDefaultValues(),
1097      fields: {
1098        billingDetails: {
1099          name: "never",
1100          phone: "auto",
1101          address
1102        }
1103      }
1104    };
1105  }
1106  mountPayment() {
1107    if (this.montedElements.payment.mounted) return;
1108    const options = {
1109      terms: { card: "never" },
1110      ...this.paymentOptions
1111    };
1112    this.mountElement("payment", options);
1113    this.montedElements.payment.element?.on("change", (event) => {
1114      this.removeSubmitNotificationStripeElementChange();
1115      delete this.errors.fields["payment"];
1116      console.log("[Stripe] paymentMethods [incoming-event]: ", event);
1117      this.montedElements.payment.lastChangeEvent = event;
1118      this.sendOrderPreview({ throttle: true });
1119    });
1120    this.montedElements.payment.element?.on("ready", () => {
1121      this.elementReady("payment");
1122    });
1123    this.montedElements.payment.element?.on("loaderror", (error) => this.handleStripeElementLoadingError(error));
1124  }
1125  generatePaymentDefaultValues() {
1126    const defaultValues = {};
1127    if (this.checkoutData.contact.first_name || this.checkoutData.contact.last_name) {
1128      defaultValues.billingDetails = defaultValues?.billingDetails ?? {};
1129      defaultValues.billingDetails.name = [
1130        this.checkoutData.contact.first_name ?? "",
1131        this.checkoutData.contact.last_name ?? ""
1132      ].filter(Boolean).join(" ");
1133    }
1134    if (this.checkoutData.contact.email) {
1135      defaultValues.billingDetails = defaultValues?.billingDetails ?? {};
1136      defaultValues.billingDetails.email = this.checkoutData.contact.email;
1137    }
1138    if (this.checkoutData.contact.phone_number && this.hasPhoneNumber()) {
1139      defaultValues.billingDetails = defaultValues?.billingDetails ?? {};
1140      defaultValues.billingDetails.phone = this.checkoutData.contact.phone_number;
1141    }
1142    return defaultValues;
1143  }
1144  updatePaymentElementDefaultValues() {
1145    if (this.getState() !== "guest") return;
1146    this.montedElements.payment.element?.update({
1147      ...this.paymentOptions
1148    });
1149  }
1150  handleOrderPreviewForExpressCheckout(response, resolve) {
1151    const cart = this.store.checkoutCart.get();
1152    this.stripeElements.update({
1153      amount: response.total_amount_cents,
1154      mode: getStripeMode(cart, response.total_amount_cents)
1155    });
1156    const changeResolveDetails = calculateStripeChangeResolveDetails(
1157      response.line_items,
1158      response.shipping_quotes_response?.options,
1159      response.selected_shipping_option,
1160      response.total_amount_cents,
1161      response.discount_amount_cents
1162    );
1163    resolve(changeResolveDetails);
1164  }
1165  // What the wallet sheet asks for. Express Checkout has no billing-address-change event, so the
1166  // shipping address is the only address the sheet can collect before `confirm` — and the preview
1167  // round trip it triggers is also the only thing that moves the sheet off the pre-discount,
1168  // pre-tax subtotal the Elements were mounted with. Ask for it unless neither is needed.
1169  expressClickResolveDetails() {
1170    const cart = this.store.checkoutCart.get();
1171    const summary = this.store.summary.get();
1172    const totalAmountCents = summary.data?.total?.amount_cents;
1173    const finalTotalKnown = summary.state == "ok" /* OK */ && totalAmountCents != null;
1174    const needsAddress = hasPhysicalProducts(cart) || !!this.component.paymentGateway.stripe_tax_enabled || !finalTotalKnown;
1175    if (needsAddress) {
1176      return calculateStripeClickResolveDetails({
1177        needsAddress,
1178        phoneNumberRequired: this.hasPhoneNumber(),
1179        lineItems: this.summaryLineItems,
1180        // `line_item_subtotal_cents` sums every invoice line including shipping, while
1181        // `line_items` excludes it — so the selected rate has to be named here, or the buyer is
1182        // shown their delivery charge as "Taxes".
1183        totalAmountCents: this.summaryLineItemSubtotalCents,
1184        shippingOption: this.selectedShippingOption
1185      });
1186    }
1187    this.stripeElements.update({
1188      amount: totalAmountCents,
1189      mode: getStripeMode(cart, totalAmountCents)
1190    });
1191    return calculateStripeClickResolveDetails({
1192      needsAddress,
1193      phoneNumberRequired: this.hasPhoneNumber(),
1194      lineItems: this.summaryLineItems,
1195      totalAmountCents,
1196      discountAmountCents: summary.data?.discount?.amount_cents
1197    });
1198  }
1199  // Settles the wallet's pending update exactly once, and never rejects: a handler that leaves
1200  // the sheet unsettled is not an error the wallet can show, it is a ~30s "Payment Not Completed"
1201  // timeout.
1202  async sendExpressCheckoutOrderPreview(resolve, reject) {
1203    let settled = false;
1204    const settle = (settleWith) => {
1205      if (settled) return;
1206      settleWith();
1207      settled = true;
1208    };
1209    try {
1210      const cart = this.store.checkoutCart.get();
1211      const dataToPreview = {
1212        cart,
1213        address: this.digitalPaymentData.address,
1214        integrations_stripe_installation_id: stripeInstallationId
1215      };
1216      const couponState = this.store.coupons.state.get();
1217      let couponCode;
1218      if (couponState == "applying" /* APPLYING */) {
1219        couponCode = this.store.coupons.currentCode.get();
1220      } else {
1221        couponCode = this.store.coupons.appliedCode.get();
1222      }
1223      dataToPreview.coupon_code = couponCode;
1224      dataToPreview.shippingOption = this.formatExpressShippingOption(this.digitalPaymentData.shippingRateId);
1225      const response = await fetchOrderPreview(dataToPreview);
1226      if (isResponseError(response)) {
1227        settle(reject);
1228      } else {
1229        settle(() => this.handleOrderPreviewForExpressCheckout(response, resolve));
1230      }
1231    } catch (error) {
1232      settle(reject);
1233      globalThis.Honeybadger?.notify("StripeCheckout express preview failed", {
1234        context: {
1235          error: error?.message ?? String(error),
1236          errorName: error?.name,
1237          checkoutState: this.getState(),
1238          summaryState: this.store.summary.get().state
1239        }
1240      });
1241    }
1242  }
1243  mountExpress() {
1244    if (this.montedElements.expressCheckout.mounted) return;
1245    this.mountElement("expressCheckout", {
1246      paymentMethods: { link: this.component.payWithLinkEnabled ? "auto" : "never" }
1247    });
1248    this.montedElements.expressCheckout.element?.on("confirm", (evt) => {
1249      const shippingOption = this.formatExpressShippingOption(evt.shippingRate?.id);
1250      this.storeShippingDataFromExpress(evt.shippingAddress ?? evt.billingDetails);
1251      this.handleSubmit(shippingOption, true);
1252    });
1253    this.montedElements.expressCheckout.element?.on("click", ({ resolve }) => {
1254      let resolveDetails;
1255      try {
1256        resolveDetails = this.expressClickResolveDetails();
1257      } catch (error) {
1258        resolveDetails = calculateStripeClickResolveDetails({
1259          needsAddress: true,
1260          phoneNumberRequired: this.hasPhoneNumber(),
1261          lineItems: this.summaryLineItems,
1262          totalAmountCents: this.summaryLineItemSubtotalCents,
1263          shippingOption: this.selectedShippingOption
1264        });
1265        globalThis.Honeybadger?.notify("StripeCheckout express click failed", {
1266          context: {
1267            error: error?.message ?? String(error),
1268            errorName: error?.name,
1269            checkoutState: this.getState(),
1270            summaryState: this.store.summary.get().state
1271          }
1272        });
1273      }
1274      resolve(resolveDetails);
1275    });
1276    this.montedElements.expressCheckout.element?.on("shippingaddresschange", async ({ address, resolve, reject }) => {
1277      this.digitalPaymentData.address = convertAddressFromStripe(address);
1278      await this.sendExpressCheckoutOrderPreview(resolve, reject);
1279    });
1280    this.montedElements.expressCheckout.element?.on("cancel", () => {
1281      const cart = this.store.checkoutCart.get();
1282      this.stripeElements.update({
1283        amount: this.summaryLineItemSubtotalCents,
1284        mode: getStripeMode(cart, this.summaryLineItemSubtotalCents)
1285      });
1286    });
1287    this.montedElements.expressCheckout.element?.on("shippingratechange", async ({ shippingRate, resolve, reject }) => {
1288      this.digitalPaymentData.shippingRateId = shippingRate.id;
1289      await this.sendExpressCheckoutOrderPreview(resolve, reject);
1290    });
1291    this.montedElements.payment.element?.on("loaderror", (error) => this.handleStripeElementLoadingError(error));
1292  }
1293  formatExpressShippingOption(id) {
1294    if (id && id != STRIPE_SKIP_SHIPPING_ID) {
1295      return JSON.parse(id);
1296    }
1297  }
1298  elementReady(name) {
1299    const stateElement = this.getStateElement();
1300    const loaderElementName = ["shipping", "billing"].includes(name) ? "address" : name;
1301    const loaderElement = stateElement.querySelector(`[data-stripe-loading-element="${loaderElementName}"]`);
1302    const stripeElement = stateElement.querySelector(`.stripe-${name}`);
1303    this.stripeElements.update({ appearance: this.parsedAppearence });
1304    let obeserverTimeout;
1305    const resizeObserver = new ResizeObserver(() => {
1306      clearTimeout(obeserverTimeout);
1307      obeserverTimeout = setTimeout(() => {
1308        resizeObserver.disconnect();
1309        this.stripeElements.update({ appearance: this.parsedAppearence });
1310        loaderElement.classList.add("forceHide");
1311        stripeElement.classList.remove("elAbsolute");
1312        stripeElement.style.opacity = "1";
1313      }, 500);
1314    });
1315    resizeObserver.observe(stripeElement);
1316  }
1317  oneTimeListeners() {
1318    const signOutButtonthis = this.component.element.querySelector(".sign-out-button");
1319    signOutButtonthis.addEventListener("click", () => {
1320      fetch("/contacts/sign_out", {
1321        method: "DELETE",
1322        headers: { "Content-Type": "application/json" },
1323        credentials: "same-origin"
1324      }).then(() => this.ensureStripeSession()).then((session) => {
1325        if (session) {
1326          this.store.checkout.step.set(0);
1327          this.setState("guest");
1328          this.initializeElements(session, this.summaryLineItemSubtotalCents);
1329          setTimeout(() => {
1330            this.updateElementsDisplay();
1331            const cart = this.store.checkoutCart.get();
1332            CheckoutExistingOrders.clearUpdatableOrders(cart.items[0]?.product_id);
1333          }, 1e3);
1334        }
1335      });
1336    });
1337    this.component.getComponents("Input/V1").forEach((inputComponent) => {
1338      const input = inputComponent.element.querySelector("input");
1339      const inputName = input.getAttribute("name");
1340      if (!["first_name", "last_name", "phone_number"].includes(inputName)) return;
1341      if (inputName == "phone_number") {
1342        IntlTel_initPhoneInput(input, { initialCountry: globalThis.cfVisitorData?.country ?? "us" });
1343      }
1344      this.guestInputFields[inputName] = input;
1345      ["input", "focus"].forEach((eventName) => {
1346        input.addEventListener(eventName, () => {
1347          const errorfield = this.errorInputForInput(input);
1348          errorfield.style.height = "0px";
1349          errorfield.previousElementSibling.classList.remove("elInputError");
1350          errorfield.textContent = "";
1351        });
1352      });
1353      input.addEventListener("blur", (event) => {
1354        const input2 = event.target;
1355        let value = input2.value;
1356        if (inputName == "phone_number") {
1357          value = input2.iti.getNumber();
1358        }
1359        this.checkoutData.contact[inputName] = value;
1360        this.updateInputState(inputName, value);
1361        this.updatePaymentElementDefaultValues();
1362      });
1363    });
1364    this.store.checkoutCart.subscribe(() => {
1365      this.updateElementsDisplay();
1366      this.sendOrderPreview();
1367      if (this.submitedOnce) {
1368        this.clearErrors("products");
1369        this.showErrors();
1370      }
1371    });
1372    this.listenAndSurfaceSummaryErrors();
1373  }
1374  // Mirrors Rebilly's `listenAndUpdateCheckoutErrors` (rebilly-checkout.ygg): when an
1375  // order-preview error lands on `summary.error.message`, surface it via the same
1376  // `.checkout-general-errors-wrapper` that submit-time errors use.
1377  listenAndSurfaceSummaryErrors() {
1378    this.store.summary.subscribe((summary) => {
1379      const message = summary?.state === "error" /* ERROR */ && summary?.error?.message ? summary.error.message : null;
1380      if (this.summaryErrorEntry) {
1381        const idx = this.errors.globalErrors.indexOf(this.summaryErrorEntry);
1382        if (idx >= 0) this.errors.globalErrors.splice(idx, 1);
1383        this.summaryErrorEntry = null;
1384      }
1385      if (message) {
1386        this.summaryErrorEntry = { message };
1387        this.errors.globalErrors.push(this.summaryErrorEntry);
1388      }
1389      this.showErrors();
1390    });
1391  }
1392  updateElementsDisplay() {
1393    this.cartAddressUpdates();
1394    this.updatePaymentElement();
1395    this.updateShippingOptionsDisplay();
1396    this.updateSubmitButton();
1397  }
1398  updatePaymentElement() {
1399    if (this.hasPaymentElement()) {
1400      this.mountPayment();
1401      this.mountExpress();
1402      this.mountLink();
1403      this.getStateElement().querySelector(".stripe-payment-container")?.classList.remove("forceHide");
1404      this.getStateElement().querySelector(".stripe-expressCheckout-container")?.classList.remove("forceHide");
1405    } else {
1406      this.unmountElement("linkAuthentication");
1407      this.unmountElement("payment");
1408      this.unmountElement("expressCheckout");
1409      this.getStateElement().querySelector(".stripe-payment-container")?.classList.add("forceHide");
1410      this.getStateElement().querySelector(".stripe-expressCheckout-container")?.classList.add("forceHide");
1411    }
1412  }
1413  cartAddressUpdates() {
1414    const cart = this.store.checkoutCart.get();
1415    const hasPhysical = hasPhysicalProducts(cart);
1416    if (this.oldHasPhysical != hasPhysical) {
1417      this.updateWithShippingAddress(cart);
1418    }
1419    if (this.getState() == "oto") {
1420      if (this.otoRequiresShippingForm() || this.paymentDeclined) {
1421        this.mountAddress();
1422        this.getStateElement().querySelector(".stripe-address")?.classList.remove("forceHide");
1423      } else {
1424        this.getStateElement().querySelector(".stripe-address")?.classList.add("forceHide");
1425      }
1426      if (hasUpgradeDowngradeItems(cart)) {
1427        this.getStateElement().querySelector('[data-page-element="CheckoutProductSelectBump/V2"]')?.classList.add("forceHide");
1428      } else {
1429        this.getStateElement().querySelector('[data-page-element="CheckoutProductSelectBump/V2"]')?.classList.remove("forceHide");
1430      }
1431    } else if (hasUpgradeDowngradeItems(cart)) {
1432      this.getStateElement().querySelector(".stripe-address")?.classList.add("forceHide");
1433    } else {
1434      this.mountAddress();
1435      this.getStateElement().querySelector(".stripe-address")?.classList.remove("forceHide");
1436    }
1437    this.oldHasPhysical = hasPhysical;
1438  }
1439  updateSubmitButton() {
1440    if (this.submitInFlight) return;
1441    const cart = this.store.checkoutCart.get();
1442    if (hasUpgradeDowngradeItems(cart)) {
1443      this.submitButtons.update(this.component.buttonUpgradeDowngrade);
1444    } else {
1445      this.submitButtons.setButtonInitialHTML();
1446    }
1447  }
1448  get addressOptions() {
1449    const hasPhysical = hasPhysicalProducts(this.store.checkoutCart.get());
1450    const options = {
1451      mode: hasPhysical ? "shipping" : "billing",
1452      fields: { phone: this.hasPhoneNumber() ? "always" : "never" },
1453      validation: this.hasPhoneNumber() ? { phone: { required: "always" } } : {},
1454      display: {
1455        name: "split"
1456      }
1457    };
1458    options.autocomplete = { mode: "automatic" };
1459    options.defaultValues = {};
1460    if (Object.keys(this.checkoutData.address).length || this.get
1460State() == "oto") {
1461      options.defaultValues.address = convertToStripeAddress(this.checkoutData.address);
1462    }
1463    const { first_name, last_name, phone_number } = this.checkoutData.contact ?? {};
1464    if (options.display.name == "split") {
1465      if (first_name) options.defaultValues.firstName = first_name;
1466      if (last_name) options.defaultValues.lastName = last_name;
1467    } else {
1468      if (first_name) {
1469        options.defaultValues.name = first_name;
1470        if (last_name) {
1471          options.defaultValues.name += ` ${last_name}`;
1472        }
1473      }
1474    }
1475    if (this.checkoutData.contact.phone_number && this.hasPhoneNumber()) {
1476      options.defaultValues.phone = this.checkoutData.contact.phone_number;
1477    }
1478    if (options.defaultValues.address && first_name && last_name) {
1479      const phoneNumberObj = this.hasPhoneNumber() ? { phone: phone_number } : {};
1480      options.contacts = [
1481        { name: `${first_name} ${last_name}`, address: options.defaultValues.address, ...phoneNumberObj }
1482      ];
1483    }
1484    return options;
1485  }
1486  hasPhoneNumber() {
1487    const showPhoneNumber = this.component.contactFields.includes("phone_number");
1488    return showPhoneNumber;
1489  }
1490  stripeElementHasError(type) {
1491    return !!this.montedElements[type].lastChangeEvent && !this.montedElements[type].lastChangeEvent?.complete;
1492  }
1493  shouldClearFormErrors(type) {
1494    return !this.submitedOnce && this.stripeElementHasError(type);
1495  }
1496  clearStripeElement(type) {
1497    console.log("[Stripe][clearStripeElement] =>", type);
1498    this.montedElements[type].element?.clear();
1499  }
1500  processCheckoutError(errorsByForm) {
1501    for (const [, errors] of Object.entries(errorsByForm)) {
1502      for (const [field, error] of Object.entries(errors?.fields ?? {})) {
1503        if (!error) continue;
1504        this.pushFieldError(field, error.message);
1505      }
1506      if (errors?.globalErrors?.length) {
1507        this.pushGlobalError(errors.globalErrors[0].message);
1508      }
1509    }
1510    return !hasErrors(this.errors);
1511  }
1512  shippingOptionErrors() {
1513    const state = this.component.getComponent(CheckoutShippingProfileSelectV1);
1514    const cart = this.store.checkoutCart.get();
1515    if (hasUpgradeDowngradeItems(cart)) {
1516      return null;
1517    } else if (state) {
1518      const { shippingOptions, shippingOption, loadingShipping } = state;
1519      return shippingOptionErrors(loadingShipping, cart, shippingOptions, shippingOption, true, null);
1520    }
1521  }
1522  tosErrors() {
1523    const state = this.component.getComponent(CheckoutTosV1);
1524    if (state) {
1525      return tosErrors(state.accepted, true, true);
1526    }
1527  }
1528  contactErrors() {
1529    return contactErrors(this.checkoutData.contact, Object.keys(this.guestInputFields));
1530  }
1531  stripeFormErrors(type) {
1532    if (this.shouldValidateStripeElements() && this.stripeElementHasError(type)) {
1533      return { fields: { [type]: { message: "has error" } } };
1534    }
1535  }
1536  formErrorsByFormName(formName) {
1537    switch (formName) {
1538      case "products":
1539        return productErrors(this.store.checkoutCart.get(), true);
1540      case "shippingOption":
1541        return this.shippingOptionErrors();
1542      case "tos":
1543        return this.tosErrors();
1544      case "contact":
1545        return this.contactErrors();
1546    }
1547  }
1548  async validateStep(step) {
1549    this.clearAllErrors();
1550    const formErrors = {};
1551    const curretStepForms = FORM_STRUCTURE_BY_TOTAL_STEPS[this.getTotalSteps()][step];
1552    let hasStripeElementInStep = false;
1553    for (const field of curretStepForms) {
1554      if (stripeElementsForms.includes(field)) {
1555        hasStripeElementInStep = true;
1556        formErrors[field] = this.stripeFormErrors(field);
1557      } else {
1558        formErrors[field] = this.formErrorsByFormName(field);
1559      }
1560    }
1561    const formValid = this.processCheckoutError(formErrors);
1562    if (!formValid && hasStripeElementInStep) {
1563      await this.stripeElements.submit();
1564      if (this.shouldClearFormErrors("billing")) this.clearStripeElement("billing");
1565      if (this.shouldClearFormErrors("shipping")) this.clearStripeElement("shipping");
1566      if (this.shouldClearFormErrors("payment")) this.clearStripeElement("payment");
1567    }
1568    const customFieldsValid = checkValidCustomFields(this.component.element);
1569    const valid = formValid && customFieldsValid;
1570    if (!valid) {
1571      this.showErrors({ shouldScrollToError: true });
1572    }
1573    return valid;
1574  }
1575  updateShippingOptionsDisplay() {
1576    const stateElement = this.getStateElement();
1577    const cart = this.store.checkoutCart.get();
1578    if (hasPhysicalProducts(cart) && !hasUpgradeDowngradeItems(cart)) {
1579      stateElement.querySelector(".shipping-options-container")?.classList.remove("forceHide");
1580      this.shippingComponents.show();
1581    } else {
1582      this.shippingComponents.hide();
1583      stateElement.querySelector(".shipping-options-container")?.classList.add("forceHide");
1584    }
1585  }
1586  selectShippingOption(option) {
1587    this.selectedShippingOption = option;
1588    this.shippingComponents.setOption(option);
1589    this.sendOrderPreview();
1590    if (this.submitedOnce) {
1591      this.clearErrors("shippingOption");
1592      this.showErrors();
1593    }
1594  }
1595  updateShippingOptions(update) {
1596    this.shippingComponents.update(update);
1597  }
1598  async sendOrderPreview(options) {
1599    const { skipUpdatingStripe, throttle, isCouponValidation, skipThrottle, forceOrderPreview } = options ?? {};
1600    if (this.preventOrderPreview && !forceOrderPreview) return;
1601    const { summary } = this.store;
1602    const cart = this.store.checkoutCart.get();
1603    if (!cart.items?.length) {
1604      if (this.store.coupons.appliedCode.get() || this.store.coupons.currentCode.get()) {
1605        this.store.coupons.appliedCode.set("");
1606        this.store.coupons.currentCode.set("");
1607        this.store.coupons.state.set("ready" /* READY */);
1608      }
1609      summary.set({ state: "waiting" /* WAITING */ });
1610      return;
1611    }
1612    const couponStateBeforeApplying = this.store.coupons.state.get();
1613    if (isCouponValidation && couponStateBeforeApplying != "applying" /* APPLYING */) {
1614      this.couponStateBeforeApplying = couponStateBeforeApplying;
1615      this.store.coupons.state.set("applying" /* APPLYING */);
1616    }
1617    const payload = this.hasValidAddress(this.checkoutData.address) ? {
1618      address: this.checkoutData.address,
1619      shippingOption: this.selectedShippingOption,
1620      cart
1621    } : { cart };
1622    payload.integrations_stripe_installation_id = stripeInstallationId;
1623    const couponState = this.store.coupons.state.get();
1624    let couponCode;
1625    if (couponState == "applying" /* APPLYING */) {
1626      couponCode = this.store.coupons.currentCode.get();
1627    } else {
1628      couponCode = this.store.coupons.appliedCode.get();
1629    }
1630    payload.coupon_code = couponCode;
1631    const canUpdateSummary = this.hasValidDataForSummaryUpdate(payload);
1632    const canFetchLineItemSubtotal = hasValidDataForLineItemSubtotal(payload);
1633    if (!canUpdateSummary) {
1634      summary.set({
1635        state: "waiting" /* WAITING */
1636      });
1637    }
1638    if (canUpdateSummary && !canFetchLineItemSubtotal) {
1639      return;
1640    }
1641    this.updatingExpressStarted();
1642    clearTimeout(this.sendOrderPreviewTimer);
1643    const sendOrderPreviewFn = async () => {
1644      const response = await fetchOrderPreview(payload, () => {
1645        if (canUpdateSummary) {
1646          if (hasPhysicalProducts(cart)) {
1647            this.shippingComponents.setLoading();
1648          }
1649          summary.set({
1650            state: "calculating" /* CALCULATING */
1651          });
1652        }
1653      });
1654      if (canFetchLineItemSubtotal && !isResponseError(response)) {
1655        this.summaryLineItems = response.line_items;
1656        this.summaryLineItemSubtotalCents = response.line_item_subtotal_cents;
1657        const currentCode = this.store.coupons.currentCode.get();
1658        const couponCodeApplied = response.discounts?.find(
1659          (discount) => discount.code?.toUpperCase() == currentCode?.toUpperCase()
1660        );
1661        if (couponCodeApplied) {
1662          this.store.coupons.appliedCode.set(currentCode);
1663          this.store.coupons.state.set("applied" /* APPLIED */);
1664        } else {
1665          this.store.coupons.state.set("ready" /* READY */);
1666        }
1667        if (!skipUpdatingStripe) {
1668          this.stripeElements.update({
1669            amount: response.line_item_subtotal_cents,
1670            mode: getStripeMode(cart, response.line_item_subtotal_cents)
1671          });
1672        }
1673      } else if (isBackendError(response)) {
1674        this.updatingExpressEnded();
1675        if (isResponseError(response)) {
1676          this.handleOrderPreviewErrorForExpress(response.error);
1677        }
1678      }
1679      if (canUpdateSummary || couponCode) {
1680        if (isResponseError(response)) {
1681          if (isBackendError(response)) {
1682            this.handleOrderPreviewErrorForSummary(response.error);
1683          }
1684        } else {
1685          const summaryResponse = processOrderPreviewResponseForSummary(response);
1686          const { shipping_quotes_response, selected_shipping_option } = response;
1687          this.selectedShippingOption = selected_shipping_option;
1688          summary.set({
1689            state: "ok" /* OK */,
1690            data: summaryResponse
1691          });
1692          if (hasPhysicalProducts(cart)) {
1693            this.shippingComponents.setShippingOptions(
1694              shipping_quotes_response?.options ?? [],
1695              selected_shipping_option
1696            );
1697          }
1698        }
1699      }
1700    };
1701    if (skipThrottle) {
1702      return await sendOrderPreviewFn();
1703    } else {
1704      this.sendOrderPreviewTimer = setTimeout(
1705        async () => {
1706          await sendOrderPreviewFn();
1707        },
1708        throttle ? 500 : 0
1709      );
1710    }
1711  }
1712  startLoadingState() {
1713    this.submitInFlight = true;
1714    this.loadingComponents.show();
1715    this.submitButtons.setSubmittingText();
1716  }
1717  removeLoadingState() {
1718    this.submitInFlight = false;
1719    this.loadingComponents.hide();
1720    this.submitButtons.setButtonInitialHTML();
1721  }
1722  handleStripeError(error) {
1723    if (!this.hasPaymentElement() && STRIPE_INSTRUMENT_REJECTION_CODES.has(error.code)) {
1724      this.paymentDeclined = true;
1725      this.updateElementsDisplay();
1726    }
1727    return error.message;
1728  }
1729  handleOrderPreviewErrorForExpress(response) {
1730    const errorDetail = response.details?.[0];
1731    if (errorDetail?.type == "InvalidCouponError") {
1732      this.store.coupons.appliedCode.set("");
1733      this.store.coupons.currentCode.set("");
1734      this.store.coupons.errorMessage.set(errorDetail.message);
1735      this.store.coupons.state.set("error" /* ERROR */);
1736    } else {
1737      globalThis.Checkout.store.coupons.state.set(this.couponStateBeforeApplying);
1738    }
1739  }
1740  handleOrderPreviewErrorForSummary(response) {
1741    const errorDetail = response.details?.[0];
1742    if (errorDetail?.type == "InvalidCouponError") {
1743      const summaryResponse = processOrderPreviewResponseForSummary(errorDetail.preview);
1744      this.store.summary.set({
1745        state: "ok" /* OK */,
1746        data: summaryResponse
1747      });
1748    } else if (errorDetail?.message) {
1749      this.store.summary.set({
1750        state: "error" /* ERROR */,
1751        error: { message: errorDetail.message }
1752      });
1753    } else {
1754      this.store.summary.set({
1755        state: "error" /* ERROR */,
1756        error: { message: "There was an error calculating your order total" }
1757      });
1758    }
1759  }
1760  handleError(error, skipRemoveLoadingState = false) {
1761    const GENERIC_PAYMENT_ERROR = "There was a problem processing your payment. Please try again or use a different payment method.";
1762    console.error("Error Submiting Payment:", error);
1763    if (!skipRemoveLoadingState) {
1764      this.removeLoadingState();
1765    }
1766    let displayMessage = "";
1767    let actionable = true;
1768    if (isStripeError(error)) {
1769      displayMessage = this.handleStripeError(error);
1770    } else {
1771      displayMessage = serverCheckoutErrorMessage(error) ?? GENER
1771IC_PAYMENT_ERROR;
1772      actionable = isActionableCheckoutError(error);
1773    }
1774    this.lastSubmitFailure = { message: displayMessage, actionable };
1775    this.setSubmitNotification("Failed Submit", displayMessage);
1776  }
1777  async processStripeResponse(next_url, { error, paymentIntent }) {
1778    if (error) {
1779      this.handleError(error);
1780    } else if (paymentIntent.status === "succeeded") {
1781      fetch(next_url, {
1782        method: "GET",
1783        redirect: "manual"
1784      }).then((response) => {
1785        if (response.status >= 300 && response.status < 400) {
1786          const location = response.headers.get("Location");
1787          window.location.href = location;
1788        } else {
1789          response.text().then((data) => {
1790            const jsonResponse = JSON.parse(data);
1791            this.handleError({
1792              message: jsonResponse.error
1793            });
1794          });
1795        }
1796      });
1797    } else if (paymentIntent.status === "processing") {
1798      setTimeout(async () => {
1799        const result = await this.stripe.retrievePaymentIntent(paymentIntent.client_secret);
1800        this.processStripeResponse(next_url, result);
1801      }, 1e3);
1802    } else {
1803      const voucherNextActions = ["konbini_display_details", "boleto_display_details", "oxxo_display_details", "multibanco_display_details"];
1804      const nextActionType = paymentIntent.next_action?.type;
1805      if (paymentIntent.status === "requires_action" && nextActionType && voucherNextActions.includes(nextActionType)) {
1806        window.location.href = next_url;
1807      } else {
1808        this.removeLoadingState();
1809      }
1810    }
1811  }
1812  async handleServerResponse(response) {
1813    if (isResponseError(response)) {
1814      this.handleError(response.error);
1815    } else {
1816      if (response.payment_intent?.status === "requires_action") {
1817        const result = await this.stripe.handleNextAction({
1818          clientSecret: response.payment_intent.client_secret
1819        });
1820        if (result.error) {
1821          this.handleError(result.error);
1822        } else if ("setupIntent" in result && result.setupIntent) {
1823          if (result.setupIntent.status === "succeeded") {
1824            window.location.href = response.next_url;
1825          } else {
1826            this.removeLoadingState();
1827          }
1828        } else {
1829          await this.processStripeResponse(response.next_url, result);
1830        }
1831      } else if (response.next_url) {
1832        window.location.href = response.next_url;
1833      } else {
1834        this.handleError(response);
1835      }
1836    }
1837  }
1838  shouldIncludeRegistration() {
1839    return document.getElementsByName("registration[calendar_event_id]")?.length > 0;
1840  }
1841  buildRegistrationDetails() {
1842    return {
1843      calendar_event_id: document.getElementsByName("registration[calendar_event_id]")[0].value,
1844      occurs_at: document.getElementsByName("registration[occurs_at]")[0].value
1845    };
1846  }
1847  buildSubmitPayload(shippingOption, idempotencyKey, confirmationToken, redirectOverride) {
1848    const customFields = buildCustomFields();
1849    const cart = this.store.checkoutCart.get();
1850    const coupon = this.store.coupons.appliedCode.get();
1851    const defaultRedirect = this.element.querySelector('[href="#submit-checkout-form"]')?.getAttribute("data-on-submit-go-to");
1852    const redirect_to = redirectOverride || defaultRedirect;
1853    const payload = {
1854      ...customFields ? customFields : {},
1855      payment_processor: "stripe",
1856      integrations_stripe_installation_id: stripeInstallationId,
1857      request_idempotency: idempotencyKey,
1858      skip_optin_track: document.getElementById("cfAR")?.getAttribute("data-leads-collected") === "true",
1859      purchase: {
1860        coupon_codes: [coupon].filter(Boolean),
1861        process_new_order: true,
1862        selected_shipping_option: shippingOption,
1863        order_id: cart.order_id,
1864        product_variants: cart.items.map(({ variant_id, price_id, line_item_id, quantity }) => {
1865          return {
1866            id: variant_id,
1867            quantity,
1868            price_id,
1869            ...line_item_id ? { line_item_id } : {}
1870          };
1871        })
1872      }
1873    };
1874    if (redirect_to) {
1875      payload.redirect_to = redirect_to;
1876    }
1877    if (confirmationToken) {
1878      payload.token = confirmationToken.id;
1879    } else if (hasUpgradeDowngradeItems(cart)) {
1880      payload.contact = {
1881        email: globalThis.sessionData.contact.email,
1882        first_name: globalThis.sessionData.contact.first_name,
1883        last_name: globalThis.sessionData.contact.last_name,
1884        phone_number: globalThis.sessionData.contact.phone_number
1885      };
1886    } else {
1887      payload.contact = {
1888        email: globalThis.sessionData.contact.email,
1889        first_name: this.checkoutData.contact.first_name,
1890        last_name: this.checkoutData.contact.last_name,
1891        phone_number: this.checkoutData.contact.phone_number
1892      };
1893      if (Object.keys(this.checkoutData.address).length) {
1894        payload.contact.shipping_addresses_attributes = [
1895          {
1896            physical_address_attributes: {
1897              address_one: this.checkoutData.address.address_one,
1898              address_two: this.checkoutData.address.address_two,
1899              city: this.checkoutData.address.city,
1900              region_name: this.checkoutData.address.state,
1901              country_id: this.checkoutData.address.country,
1902              postal_code: this.checkoutData.address.postal_code
1903            }
1904          }
1905        ];
1906      }
1907    }
1908    if (this.shouldIncludeRegistration()) payload["registration"] = this.buildRegistrationDetail
1908s();
1909    return payload;
1910  }
1911  otoRequiresShippingForm() {
1912    const hasPhysical = hasPhysicalProducts(this.store.checkoutCart.get());
1913    return hasPhysical && !globalThis.sessionData.contact.shipping_addresses?.[0];
1914  }
1915  hasPaymentElement() {
1916    return !hasUpgradeDowngradeItems(this.store.checkoutCart.get()) && ["guest", "saved"].includes(this.getState()) || this.paymentDeclined;
1917  }
1918  shouldValidateStripeElements() {
1919    return this.hasPaymentElement() || this.otoRequiresShippingForm();
1920  }
1921  hasStripeToken() {
1922    return this.hasPaymentElement();
1923  }
1924  async handleSubmit(shippingOption, isExpress, redirectOverride) {
1925    this.removeSubmitNotification();
1926    this.lastSubmitFailure = null;
1927    this.submitedOnce = true;
1928    if (!isExpress && !await this.validateStep(this.store.checkout.step.get())) {
1929      return false;
1930    }
1931    if (!isExpress && !checkValidCustomFields(this.component.element)) {
1932      return false;
1933    }
1934    if (!isExpress) {
1935      if (this.shouldValidateStripeElements()) {
1936        const submitError = await this.stripeElements.submit();
1937        if (submitError.error) {
1938          console.log("[Stripe] submitError =>", submitError);
1939          return false;
1940        }
1941      }
1942      if (this.store.summary.get().state != "ok" /* OK */) return false;
1943    }
1944    this.startLoadingState();
1945    let confirmationToken;
1946    if (isExpress || this.hasStripeToken()) {
1947      const confirmationTokenResult = await this.stripe.createConfirmationToken({
1948        elements: this.stripeElements,
1949        params: {
1950          payment_method_data: {
1951            billing_details: {
1952              name: this.checkoutData.contact.first_name + " " + this.checkoutData.contact.last_name,
1953              phone: this.checkoutData.contact.phone_number,
1954              email: this.checkoutData.contact.email
1955            }
1956          }
1957        }
1958      });
1959      if (confirmationTokenResult.error) {
1960        this.handleError(confirmationTokenResult.error);
1961        return false;
1962      }
1963      confirmationToken = confirmationTokenResult.confirmationToken;
1964    }
1965    const payload = this.buildSubmitPayload(shippingOption, uuidv4(), confirmationToken, redirectOverride);
1966    const response = await postSubmit(payload);
1967    await this.handleServerResponse(response);
1968    return !this.lastSubmitFailure;
1969  }
1970  hasValidAddress(address) {
1971    let addressErrorsVal;
1972    const cart = this.store.checkoutCart.get();
1973    if (!hasPhysicalProducts(cart) && !this.component.billingEnabled || hasUpgradeDowngradeItems(cart) && !this.hasPaymentElement()) {
1974      addressErrorsVal = null;
1975    } else if (this.getState() == "oto" && !hasPhysicalProducts(cart) && !this.hasPaymentElement()) {
1976      addressErrorsVal = addressErrors(address ?? {}, true, []);
1977    } else {
1978      let requiredFields = ["address_one", "city", "state", "country", "postal_code"];
1979      const stripeAddressFieldExceptions = globalThis.globalResourceData.stripeAddressFieldExceptions;
1980      if (address?.country && stripeAddressFieldExceptions.postalCodeless.includes(address?.country)) {
1981        requiredFields = requiredFields.filter((field) => field !== "postal_code");
1982      }
1983      if (address?.country && stripeAddressFieldExceptions.cityless.includes(address?.country)) {
1984        requiredFields = requiredFields.filter((field) => field !== "city");
1985      }
1986      if (address?.country && stripeAddressFieldExceptions.regionless.includes(address?.country)) {
1987        requiredFields = requiredFields.filter((field) => field !== "state");
1988      }
1989      addressErrorsVal = addressErrors(address ?? {}, true, requiredFields);
1990    }
1991    return !hasErrors(addressErrorsVal);
1992  }
1993  hasValidDataForSummaryUpdate(payload) {
1994    const { cart, address } = payload;
1995    const productSelectErrors = productErrors(cart, true);
1996    const hasValidAddress = this.hasValidAddress(address);
1997    return !hasErrors(productSelectErrors) && hasValidAddress;
1998  }
1999  // NOTE: for OTO this gets triggered after mounted.
2000  // We can enhance it later to only skip after this mounting change event.
2001  // Firstly we need to understand how to verify that
2002  removeSubmitNotificationStripeElementChange() {
2003    if (this.getState() != "oto" /* OTO */) this.removeSubmitNotification();
2004  }
2005};
2006
2007// projects/lib/packages/yggdrasil-blueprints/__generated__/blueprints/stripe-checkout.ts
2008init_runtime();
2009var StripeCheckout = class extends CF2Component {
2010  constructor(el, runtimeSel) {
2011    super(el, runtimeSel);
2012    __publicField(this, "checkout");
2013    __publicField(this, "_lazyInitPending");
2014  }
2015  _doInitialize() {
2016    this.checkout = createInstance(this);
2017  }
2018  _doMount() {
2019    this.checkout.mount();
2020  }
2021  initialize() {
2022    if (this.lazyLoadCheckout) {
2023      this._lazyInitPending = true;
2024      ensureCheckoutStoreInitialized();
2025      return;
2026    }
2027    this._doInitialize();
2028  }
2029  mount() {
2030    if (this._lazyInitPending) {
2031      return;
2032    }
2033    this._doMount();
2034  }
2035  async _performLazyInit() {
2036    this._lazyInitPending = false;
2037    await ensureStripeScriptLoaded();
2038    this._doInitialize();
2039    this._doMount();
2040  }
2041  getCart() {
2042    return this.checkout.store.checkoutCart.get();
2043  }
2044  async submitOTO(redirectOverride) {
2045    const ok = await this.checkout.submitCheckout(redirectOverride);
2046    const failure = this.checkout.lastSubmitFailure;
2047    return { ok, actionable: failure ? failure.actionable : true, message: failure && failure.message };
2048  }
2049};
2050registerComponent("StripeCheckout", StripeCheckout);
2051window["StripeCheckout"] = StripeCheckout;
2052//# sourceMappingURL=stripe-checkout-2DRIRV4Y.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.