@vio-live/web-sdk 0.4.0 → 0.4.2

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.
@@ -1512,6 +1512,13 @@ var CartManager = class extends EventTarget {
1512
1512
  * slow response can't overwrite the state of a newer one. */
1513
1513
  this.mutationSeq = /* @__PURE__ */ new Map();
1514
1514
  this.appliedSeq = /* @__PURE__ */ new Map();
1515
+ /** In-flight AddItem/UpdateItem/DeleteItem per sponsor. Callers that need
1516
+ * the backend cart to reflect a just-made change (e.g. fetching shippings
1517
+ * right after an add) should `await waitForCartMutations(sponsorId)` first
1518
+ * — otherwise they can race the mutation and see the cart from before it
1519
+ * landed (Alan, 2026-08-18: shippings queried before AddItem settled,
1520
+ * came back empty). */
1521
+ this.inFlightMutations = /* @__PURE__ */ new Map();
1515
1522
  /** Quantity intents for lines whose backend id hasn't arrived yet — replayed
1516
1523
  * when the AddItem response reconciles (keyed by product::variant). */
1517
1524
  this.pendingQtyIntents = /* @__PURE__ */ new Map();
@@ -1522,6 +1529,16 @@ var CartManager = class extends EventTarget {
1522
1529
  this.mutationSeq.set(sponsorId, n);
1523
1530
  return n;
1524
1531
  }
1532
+ /** Resolves once any in-flight AddItem/UpdateItem/DeleteItem for this
1533
+ * sponsor has settled (success or failure). No-op if nothing is pending. */
1534
+ async waitForCartMutations(sponsorId) {
1535
+ const p = this.inFlightMutations.get(sponsorId);
1536
+ if (!p) return;
1537
+ try {
1538
+ await p;
1539
+ } catch {
1540
+ }
1541
+ }
1525
1542
  /** Apply a backend response only if no newer response was applied already. */
1526
1543
  applyBackendCart(sponsorId, backendCart, seq) {
1527
1544
  if (seq < (this.appliedSeq.get(sponsorId) ?? 0)) return;
@@ -1735,7 +1752,7 @@ var CartManager = class extends EventTarget {
1735
1752
  const addedItem = existing ?? cart.items[cart.items.length - 1];
1736
1753
  const addedLineId = addedItem.id;
1737
1754
  const seq = this.nextSeq(opts.sponsorId);
1738
- void (async () => {
1755
+ const mutation = (async () => {
1739
1756
  try {
1740
1757
  const cartId = await this.ensureCartId(opts.sponsorId, opts.currency || void 0);
1741
1758
  if (cartId) {
@@ -1765,6 +1782,12 @@ var CartManager = class extends EventTarget {
1765
1782
  this.emitError("AddItem rejected by the backend \u2014 item removed from the cart", err);
1766
1783
  }
1767
1784
  })();
1785
+ this.inFlightMutations.set(opts.sponsorId, mutation);
1786
+ void mutation.finally(() => {
1787
+ if (this.inFlightMutations.get(opts.sponsorId) === mutation) {
1788
+ this.inFlightMutations.delete(opts.sponsorId);
1789
+ }
1790
+ });
1768
1791
  return addedItem;
1769
1792
  }
1770
1793
  intentKey(productId, variantId) {
@@ -1791,7 +1814,7 @@ var CartManager = class extends EventTarget {
1791
1814
  }
1792
1815
  const backendCartId = cart.cartId;
1793
1816
  const seq = this.nextSeq(sponsorId);
1794
- void (async () => {
1817
+ const mutation = (async () => {
1795
1818
  try {
1796
1819
  const gqlOpts = await getCartGraphQLOptions(sponsorId);
1797
1820
  const resCart = quantity <= 0 ? await deleteItem(backendCartId, targetItemId, gqlOpts) : await updateItem(backendCartId, targetItemId, null, quantity, gqlOpts);
@@ -1803,6 +1826,12 @@ var CartManager = class extends EventTarget {
1803
1826
  void this.fetchCartFromBackend(sponsorId);
1804
1827
  }
1805
1828
  })();
1829
+ this.inFlightMutations.set(sponsorId, mutation);
1830
+ void mutation.finally(() => {
1831
+ if (this.inFlightMutations.get(sponsorId) === mutation) {
1832
+ this.inFlightMutations.delete(sponsorId);
1833
+ }
1834
+ });
1806
1835
  }
1807
1836
  removeItem(lineItemId, sponsorId) {
1808
1837
  this.updateQuantity(lineItemId, sponsorId, 0);
@@ -2357,41 +2386,95 @@ function findPayNowCategory(categories) {
2357
2386
  const byId = (re) => categories.find((c) => c?.identifier && re.test(c.identifier));
2358
2387
  const byName = (re) => categories.find((c) => c?.name && re.test(c.name));
2359
2388
  const cat = categories.find((c) => c?.identifier === "pay_now") ?? byName(/betal\s*n[åa]|pay\s*now/i) ?? byId(/pay_now|direct_debit|direct_bank_transfer|pay_in_full|klarna_pay_now/i) ?? byName(/direkte|bank|kort|straks|sofort/i) ?? categories.find((c) => c?.identifier && !/pay_later|pay_over_time|slice_it/.test(c.identifier));
2389
+ console.log("findPayNowCategory - Selected: ", cat);
2360
2390
  return cat?.identifier ?? null;
2361
2391
  }
2362
2392
  async function createKlarnaPaymentsWidget(input) {
2363
2393
  const Klarna = await loadKpLib();
2394
+ console.log("[DEBUG Klarna] Initializing Klarna Payments");
2364
2395
  Klarna.Payments.init({ client_token: input.clientToken });
2396
+ console.log("[DEBUG Klarna] Klarna Payments initialized");
2397
+ Klarna.Payments.on?.("fullscreenOverlayShown", () => {
2398
+ console.log("[DEBUG Klarna] FULLSCREEN OVERLAY SHOWN");
2399
+ });
2400
+ Klarna.Payments.on?.("fullscreenOverlayHidden", () => {
2401
+ console.log("[DEBUG Klarna] FULLSCREEN OVERLAY HIDDEN");
2402
+ });
2365
2403
  let selected = input.category ?? findPayNowCategory(input.categories) ?? input.categories[0]?.identifier ?? "pay_now";
2404
+ if (typeof console !== "undefined") {
2405
+ console.log("[VioKlarna] Received payment_method_categories from backend:", input.categories);
2406
+ console.log("[VioKlarna] Selected initial payment_method_category:", selected);
2407
+ }
2408
+ const load = (category) => {
2409
+ if (category) selected = category;
2410
+ if (typeof console !== "undefined") {
2411
+ console.log(
2412
+ "[VioKlarna] Klarna.Payments.load calling with payment_method_category:",
2413
+ selected,
2414
+ "container:",
2415
+ input.container
2416
+ );
2417
+ }
2418
+ if (input.container && "innerHTML" in input.container) {
2419
+ input.container.innerHTML = "";
2420
+ }
2421
+ return new Promise((resolve, reject) => {
2422
+ try {
2423
+ Klarna.Payments.load(
2424
+ { container: input.container, payment_method_category: selected },
2425
+ {},
2426
+ (res) => {
2427
+ if (typeof console !== "undefined") {
2428
+ console.log(
2429
+ "[VioKlarna] Klarna.Payments.load response for payment_method_category:",
2430
+ selected,
2431
+ res
2432
+ );
2433
+ }
2434
+ if (res?.error) reject(res.error);
2435
+ else resolve({ showForm: res?.show_form !== false });
2436
+ }
2437
+ );
2438
+ } catch (err) {
2439
+ reject(err);
2440
+ }
2441
+ });
2442
+ };
2366
2443
  return {
2367
2444
  categories: input.categories,
2368
2445
  get selected() {
2369
2446
  return selected;
2370
2447
  },
2371
- load(category) {
2372
- if (category) selected = category;
2373
- return new Promise((resolve, reject) => {
2374
- try {
2375
- Klarna.Payments.load(
2376
- { container: input.container, payment_method_category: selected },
2377
- {},
2378
- (res) => {
2379
- if (res?.error) reject(res.error);
2380
- else resolve({ showForm: res?.show_form !== false });
2381
- }
2382
- );
2383
- } catch (err) {
2384
- reject(err);
2385
- }
2386
- });
2387
- },
2388
- authorize(data) {
2448
+ load,
2449
+ async authorize(category, data) {
2450
+ const cat = category || selected;
2451
+ if (typeof console !== "undefined") {
2452
+ console.log("[DEBUG Klarna] BEFORE AUTHORIZE", {
2453
+ argumentCategory: category,
2454
+ argumentData: data,
2455
+ selected,
2456
+ resolvedCategory: cat
2457
+ });
2458
+ }
2459
+ if (cat && cat !== selected) {
2460
+ await load(cat);
2461
+ }
2462
+ const finalData = { payment_method_category: cat, ...data ?? {} };
2463
+ if (typeof console !== "undefined") {
2464
+ console.log("[DEBUG Klarna] FINAL AUTHORIZE", { cat, selected, finalData });
2465
+ }
2389
2466
  return new Promise((resolve, reject) => {
2390
2467
  try {
2468
+ if (typeof console !== "undefined") {
2469
+ console.log("[DEBUG Klarna] ABOUT TO CALL AUTHORIZE");
2470
+ }
2391
2471
  Klarna.Payments.authorize(
2392
- { payment_method_category: selected, auto_finalize: true },
2393
- data ?? {},
2472
+ { payment_method_category: cat, auto_finalize: true },
2473
+ finalData,
2394
2474
  (res) => {
2475
+ if (typeof console !== "undefined") {
2476
+ console.log("[DEBUG Klarna] RAW AUTHORIZE RESPONSE:", JSON.stringify(res, null, 2));
2477
+ }
2395
2478
  if (res?.approved && res.authorization_token) {
2396
2479
  resolve(res.authorization_token);
2397
2480
  } else if (res?.error) {
@@ -2403,6 +2486,9 @@ async function createKlarnaPaymentsWidget(input) {
2403
2486
  }
2404
2487
  }
2405
2488
  );
2489
+ if (typeof console !== "undefined") {
2490
+ console.log("[DEBUG Klarna] AUTHORIZE CALL RETURNED");
2491
+ }
2406
2492
  } catch (err) {
2407
2493
  reject(err);
2408
2494
  }
@@ -2770,13 +2856,18 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
2770
2856
  }
2771
2857
  /**
2772
2858
  * Real shipping options from the backend cart (per supplier), mapped to the
2773
- * KlarnaShippingOption shape (minor units). Empty array on failure — callers
2774
- * fall back to the static KLARNA_SHIPPING_OPTIONS.
2859
+ * KlarnaShippingOption shape (minor units). Empty array on failure/no
2860
+ * options — Klarna callers use that as-is (no static fallback anymore, see
2861
+ * 2026-08-18: it only ever papered over a race, now fixed via
2862
+ * `waitForCartMutations`). `KLARNA_SHIPPING_OPTIONS` is still used
2863
+ * separately by Apple Pay's synchronous sheet setup, which can't await
2864
+ * this at all.
2775
2865
  */
2776
2866
  async fetchAvailableShippings(sponsorId) {
2777
2867
  try {
2778
2868
  const spId = sponsorId ?? this.state?.sponsorId;
2779
2869
  if (!spId) return [];
2870
+ await this.cartManager.waitForCartMutations(spId);
2780
2871
  const cart = this.cartManager.getCart(spId);
2781
2872
  let cartId = cart?.cartId;
2782
2873
  if (!cartId) {
@@ -3335,8 +3426,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
3335
3426
  async mountKlarnaPayments(container, opts) {
3336
3427
  if (!this.state) throw new Error("[VioCheckout] no active checkout \u2014 call open() first");
3337
3428
  const sponsorId = this.state.sponsorId;
3338
- const fetchedShippings = await this.fetchAvailableShippings(sponsorId);
3339
- const shippings = fetchedShippings.length > 0 ? fetchedShippings : KLARNA_SHIPPING_OPTIONS;
3429
+ const shippings = await this.fetchAvailableShippings(sponsorId);
3340
3430
  const { ctx } = opts?.withShipping ? this.buildKlarnaInstantContext(opts.shippingId, shippings) : { ctx: this.buildKlarnaPendingContext() };
3341
3431
  const selectedOpt = shippings.find((s) => s.id === opts?.shippingId) ?? shippings[0];
3342
3432
  if (selectedOpt?.id && selectedOpt?.supplierId) {
@@ -3396,6 +3486,12 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
3396
3486
  if (!nativeRes || !nativeRes.client_token) {
3397
3487
  throw new Error("Klarna session creation failed: missing client_token");
3398
3488
  }
3489
+ if (typeof console !== "undefined") {
3490
+ console.log(
3491
+ "[VioCheckout] CreatePaymentKlarnaNative payment_method_categories:",
3492
+ nativeRes.payment_method_categories
3493
+ );
3494
+ }
3399
3495
  if (nativeRes.checkout_id) {
3400
3496
  ctx.checkoutId = nativeRes.checkout_id;
3401
3497
  this.state = { ...this.state, checkoutId: nativeRes.checkout_id };
@@ -3421,9 +3517,15 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
3421
3517
  return widget.selected;
3422
3518
  },
3423
3519
  load: (category) => widget.load(category),
3424
- authorize: async () => {
3520
+ authorize: async (category) => {
3425
3521
  try {
3426
- const token = await widget.authorize();
3522
+ const addr = buildKlarnaAddress(this.state?.address);
3523
+ const customer = buildKlarnaCustomer(this.state?.address);
3524
+ const authData = {
3525
+ ...addr ? { billing_address: addr, shipping_address: addr } : {},
3526
+ ...customer ? { customer } : {}
3527
+ };
3528
+ const token = await widget.authorize(category, authData);
3427
3529
  await this.completeKlarnaOrder(token, ctx, { authorizationToken: token });
3428
3530
  } catch (err) {
3429
3531
  if (typeof console !== "undefined") {
@@ -3451,7 +3553,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
3451
3553
  /** Cart snapshot + chosen shipping line/amount, for express purchases. */
3452
3554
  buildKlarnaInstantContext(shippingId, availableShippings = []) {
3453
3555
  const base = this.buildKlarnaPendingContext();
3454
- const options = availableShippings.length > 0 ? availableShippings : KLARNA_SHIPPING_OPTIONS;
3556
+ const options = availableShippings;
3455
3557
  const shipping = (shippingId ? options.find((o) => o.id === shippingId) : void 0) ?? options.find((o) => o.preselected) ?? options[0];
3456
3558
  const orderLines = [...base.orderLines];
3457
3559
  if (shipping) {
@@ -3483,8 +3585,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
3483
3585
  async startKlarnaInstant() {
3484
3586
  if (!this.state) throw new Error("[VioCheckout] no active checkout \u2014 call open() first");
3485
3587
  const sponsorId = this.state.sponsorId;
3486
- const fetchedShippings = await this.fetchAvailableShippings(sponsorId);
3487
- const shippings = fetchedShippings.length > 0 ? fetchedShippings : KLARNA_SHIPPING_OPTIONS;
3588
+ const shippings = await this.fetchAvailableShippings(sponsorId);
3488
3589
  const { ctx } = this.buildKlarnaInstantContext(void 0, shippings);
3489
3590
  let clientToken;
3490
3591
  let categories;
@@ -3854,6 +3955,6 @@ var VioFacade = class {
3854
3955
  var _vioGlobal = globalThis;
3855
3956
  var Vio = _vioGlobal.__VIO_FACADE__ ?? (_vioGlobal.__VIO_FACADE__ = new VioFacade());
3856
3957
 
3857
- export { ADD_ITEM_MUTATION, CREATE_CART_MUTATION, CREATE_CHECKOUT_MUTATION, CREATE_PAYMENT_STRIPE_MUTATION, CREATE_PAYMENT_VIPPS_MUTATION, CartManager, CheckoutManager, CommerceClient, Configuration, DELETE_ITEM_MUTATION, GET_AVAILABLE_PAYMENT_METHODS_QUERY, GET_CART_QUERY, GET_CHECKOUT_QUERY, GET_LINE_ITEMS_BY_SUPPLIER_QUERY, GET_VIPPS_STATUS_QUERY, KLARNA_SHIPPING_OPTIONS, UPDATE_CHECKOUT_MUTATION, UPDATE_ITEM_MUTATION, UPDATE_SHIPPINGS_BY_SUPPLIER_MUTATION, Vio, VioApi, VioApiError, __decorateClass, addItem, checkApplePayAvailability, createCart, createCheckout, createCommerceClient, createPaymentStripe, createPaymentVipps, createVioApi, deleteItem, displayPrice, executeCartGraphQL, formatPrice, getAvailablePaymentMethods, getCart, getCartGraphQLOptions, getCheckout, getCustomerSessionId, getGlobalCurrency, getLineItemsBySupplier, getVippsStatus, primaryImageUrl, showApplePaySheet, updateCheckout, updateItem, updateShippingsBySupplier };
3858
- //# sourceMappingURL=chunk-NP2KCM7X.js.map
3859
- //# sourceMappingURL=chunk-NP2KCM7X.js.map
3958
+ export { ADD_ITEM_MUTATION, CREATE_CART_MUTATION, CREATE_CHECKOUT_MUTATION, CREATE_PAYMENT_STRIPE_MUTATION, CREATE_PAYMENT_VIPPS_MUTATION, CartManager, CheckoutManager, CommerceClient, Configuration, DELETE_ITEM_MUTATION, GET_AVAILABLE_PAYMENT_METHODS_QUERY, GET_CART_QUERY, GET_CHECKOUT_QUERY, GET_LINE_ITEMS_BY_SUPPLIER_QUERY, GET_VIPPS_STATUS_QUERY, UPDATE_CHECKOUT_MUTATION, UPDATE_ITEM_MUTATION, UPDATE_SHIPPINGS_BY_SUPPLIER_MUTATION, Vio, VioApi, VioApiError, __decorateClass, addItem, checkApplePayAvailability, createCart, createCheckout, createCommerceClient, createPaymentStripe, createPaymentVipps, createVioApi, deleteItem, displayPrice, executeCartGraphQL, formatPrice, getAvailablePaymentMethods, getCart, getCartGraphQLOptions, getCheckout, getCustomerSessionId, getGlobalCurrency, getLineItemsBySupplier, getVippsStatus, primaryImageUrl, showApplePaySheet, updateCheckout, updateItem, updateShippingsBySupplier };
3959
+ //# sourceMappingURL=chunk-KMIARP6X.js.map
3960
+ //# sourceMappingURL=chunk-KMIARP6X.js.map