@vio-live/web-sdk 0.24.0 → 0.26.0

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.
@@ -1,4 +1,4 @@
1
- import { Vio, __decorateClass, primaryImageUrl, displayPrice, toCampaignId, getGlobalCurrency, ensureVippsButton, formatPrice, nexiReturnPaymentId, readNexiPending, kustomReturnOutcome, KUSTOM_RETURN_QUERY_KEYS, ADYEN_RETURN_METHOD, adyenReturnParams, ADYEN_RETURN_QUERY_KEYS, adyenReturnOutcome, AdyenOriginError, normalizeSlotId, autoSlotDisplayName, autoSlotId, normalizeScope, campaignCandidates } from './chunk-AXJKB2CW.js';
1
+ import { Vio, __decorateClass, primaryImageUrl, displayPrice, toCampaignId, getGlobalCurrency, ensureVippsButton, formatPrice, buyerRefOf, nexiReturnPaymentId, readNexiPending, kustomReturnOutcome, KUSTOM_RETURN_QUERY_KEYS, ADYEN_RETURN_METHOD, adyenReturnParams, ADYEN_RETURN_QUERY_KEYS, adyenReturnOutcome, gatewayHasBuyerRef, AdyenOriginError, normalizeSlotId, autoSlotDisplayName, autoSlotId, normalizeScope, campaignCandidates } from './chunk-5KWICUME.js';
2
2
  import { LitElement, css, html } from 'lit';
3
3
  import { property, state, query } from 'lit/decorators.js';
4
4
 
@@ -226,7 +226,7 @@ var SlotRegistration = class {
226
226
  this.unregister();
227
227
  if (!next) return;
228
228
  try {
229
- this.release = typeof Vio.registerSlot !== "function" ? null : next.campaignId !== void 0 ? Vio.registerSlot(next.id, next.displayName, next.campaignId) : Vio.registerSlot(next.id, next.displayName);
229
+ this.release = typeof Vio.registerSlot !== "function" ? null : next.campaignId !== void 0 ? Vio.registerSlot(next.id, next.displayName, next.campaignId, { kind: this.kind }) : Vio.registerSlot(next.id, next.displayName, { kind: this.kind });
230
230
  this.identity = next;
231
231
  } catch {
232
232
  this.release = null;
@@ -339,6 +339,7 @@ var VioProduct = class extends LitElement {
339
339
  this.vioCampaign = "";
340
340
  this.vioContentId = "";
341
341
  this.vioContentTitle = "";
342
+ this.componentTemplateId = "";
342
343
  this.slotRegistration = new SlotRegistration(this, "card");
343
344
  this.hasVariants = false;
344
345
  this.variants = void 0;
@@ -383,6 +384,7 @@ var VioProduct = class extends LitElement {
383
384
  }) : { slot: this.effectiveSlot || void 0 };
384
385
  return {
385
386
  ...base,
387
+ componentTemplateId: this.componentTemplateId || "product-card",
386
388
  ...this.vioContentId ? { contentId: this.vioContentId } : {},
387
389
  ...this.vioContentTitle ? { contentTitle: this.vioContentTitle } : {}
388
390
  };
@@ -581,11 +583,15 @@ var VioProduct = class extends LitElement {
581
583
  // The host's sponsor-id wins; without one, the slot's campaign sponsor.
582
584
  sponsorId: this.sponsorId || this.sponsorFromAttribution(),
583
585
  // The host adds to the cart: pass this through as `origin` so the
584
- // purchase is attributed to this place and campaign.
586
+ // purchase is attributed to this place, campaign, kind of element
587
+ // and page — the cart keeps it and Commerce receives it (ADR-0035).
585
588
  origin: {
586
589
  campaignId: attribution.campaignId,
587
590
  slot: attribution.slot,
588
- contentId: attribution.contentId
591
+ contentId: attribution.contentId,
592
+ componentKind: attribution.componentTemplateId,
593
+ contentUrl: attribution.contentUrl,
594
+ contentTitle: attribution.contentTitle
589
595
  }
590
596
  }
591
597
  })
@@ -675,6 +681,9 @@ __decorateClass([
675
681
  __decorateClass([
676
682
  property({ type: String, attribute: "vio-content-title" })
677
683
  ], VioProduct.prototype, "vioContentTitle", 2);
684
+ __decorateClass([
685
+ property({ type: String, attribute: "component-template-id" })
686
+ ], VioProduct.prototype, "componentTemplateId", 2);
678
687
  __decorateClass([
679
688
  property({ type: Boolean, attribute: "has-variants" })
680
689
  ], VioProduct.prototype, "hasVariants", 2);
@@ -753,6 +762,7 @@ var VioProductCarousel = class extends LitElement {
753
762
  }) : { slot: this.effectiveSlot || void 0 };
754
763
  return {
755
764
  ...base,
765
+ componentTemplateId: "product-carousel",
756
766
  ...this.vioContentId ? { contentId: this.vioContentId } : {},
757
767
  ...this.vioContentTitle ? { contentTitle: this.vioContentTitle } : {}
758
768
  };
@@ -994,7 +1004,6 @@ var VioProductCarousel = class extends LitElement {
994
1004
  this,
995
1005
  {
996
1006
  sponsorId: this.sponsorId > 0 ? this.sponsorId : void 0,
997
- componentTemplateId: "product-carousel",
998
1007
  // The slot is the real location id; the label only stands in for it.
999
1008
  locationId: this.effectiveSlot || this.label || void 0,
1000
1009
  ...this.attribution()
@@ -1022,7 +1031,6 @@ var VioProductCarousel = class extends LitElement {
1022
1031
  Vio.analytics.track("view_item_list", {
1023
1032
  context: {
1024
1033
  sponsorId: sponsorId > 0 ? sponsorId : void 0,
1025
- componentTemplateId: "product-carousel",
1026
1034
  locationId: this.effectiveSlot || this.label || void 0,
1027
1035
  ...this.attribution()
1028
1036
  },
@@ -1081,6 +1089,7 @@ var VioProductCarousel = class extends LitElement {
1081
1089
  image-url=${img}
1082
1090
  ?has-variants=${(p.variants?.length ?? 0) > 1}
1083
1091
  .vioSlot=${this.effectiveSlot}
1092
+ .componentTemplateId=${"product-carousel"}
1084
1093
  .vioCampaign=${this.effectiveCampaignId !== void 0 ? String(this.effectiveCampaignId) : ""}
1085
1094
  .vioContentId=${this.vioContentId}
1086
1095
  .vioContentTitle=${this.vioContentTitle}
@@ -1519,6 +1528,7 @@ var VioProductDetail = class extends LitElement {
1519
1528
  const contentTitle = this.fromCard && this.eventContentTitle || this.vioContentTitle;
1520
1529
  return {
1521
1530
  ...base,
1531
+ componentTemplateId: "product-detail",
1522
1532
  ...contentId ? { contentId } : {},
1523
1533
  ...contentTitle ? { contentTitle } : {}
1524
1534
  };
@@ -2055,7 +2065,6 @@ var VioProductDetail = class extends LitElement {
2055
2065
  Vio.analytics.track("view_item", {
2056
2066
  context: {
2057
2067
  sponsorId: this.sponsorId > 0 ? Number(this.sponsorId) : void 0,
2058
- componentTemplateId: "product-detail",
2059
2068
  ...this.attribution()
2060
2069
  },
2061
2070
  commerce: {
@@ -2378,14 +2387,14 @@ var VioProductDetail = class extends LitElement {
2378
2387
  const sponsor = Vio.bootstrapCache?.primarySponsor;
2379
2388
  const secondaries = Vio.bootstrapCache?.secondarySponsors ?? [];
2380
2389
  const sponsorName = sponsor?.id === this.sponsorId ? sponsor.name : secondaries.find((s) => s.id === this.sponsorId)?.name;
2381
- const { campaignId, slot, contentId } = this.attribution();
2390
+ const { campaignId, slot, contentId, componentTemplateId, contentUrl, contentTitle } = this.attribution();
2382
2391
  Vio.cart.addProduct({
2383
2392
  product: this.product,
2384
2393
  sponsorId: this.sponsorId,
2385
2394
  sponsorName,
2386
2395
  quantity: this.quantity,
2387
2396
  variantId: variant?.id,
2388
- origin: { campaignId, slot, contentId }
2397
+ origin: { campaignId, slot, contentId, componentKind: componentTemplateId, contentUrl, contentTitle }
2389
2398
  });
2390
2399
  return variant?.id;
2391
2400
  }
@@ -3353,11 +3362,12 @@ var VioCart = class extends LitElement {
3353
3362
  for (const sponsorId of [...this.carts.keys()]) {
3354
3363
  Vio.cart.clearSponsorCart(sponsorId);
3355
3364
  }
3365
+ const buyerRef = buyerRefOf({ result });
3356
3366
  this.dispatchEvent(
3357
3367
  new CustomEvent("vio:payment-success", {
3358
3368
  bubbles: true,
3359
3369
  composed: true,
3360
- detail: { method: "apple-pay", result }
3370
+ detail: { method: "apple-pay", result, ...buyerRef ? { buyerRef } : {} }
3361
3371
  })
3362
3372
  );
3363
3373
  });
@@ -3927,6 +3937,8 @@ var _VioCheckout = class _VioCheckout extends LitElement {
3927
3937
  this.paymentError = detail.method === "klarna" ? `Klarna-betalingen kunne ikke fullf\xF8res: ${detail.error}` : friendlyPaymentError(detail.error, detail.method);
3928
3938
  this.open = true;
3929
3939
  };
3940
+ /** Payment events still waiting for their buyer reference: settled early (without it) when the page hides or the element leaves. */
3941
+ this.pendingSuccessEmits = /* @__PURE__ */ new Set();
3930
3942
  }
3931
3943
  /** A payment is being started or confirmed right now: the overlay must not close under it. */
3932
3944
  get paymentInFlight() {
@@ -4617,13 +4629,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4617
4629
  this.orderConfirmed = true;
4618
4630
  this.open = true;
4619
4631
  void this.fillOrderNumber(checkoutId, sponsorId);
4620
- this.dispatchEvent(
4621
- new CustomEvent("vio:payment-success", {
4622
- bubbles: true,
4623
- composed: true,
4624
- detail: { method: vioMethod, sponsorId, orderId: checkoutId }
4625
- })
4626
- );
4632
+ void this.emitPaymentSuccess({ method: vioMethod, sponsorId, orderId: checkoutId }, checkoutId, sponsorId);
4627
4633
  } else if (outcome === "duplicate") {
4628
4634
  this.paymentError = CART_PAID_MESSAGE;
4629
4635
  this.open = true;
@@ -4965,6 +4971,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4965
4971
  this.unmountKlarna();
4966
4972
  this.unmountNexi();
4967
4973
  this.unmountAdyen();
4974
+ for (const settle of [...this.pendingSuccessEmits]) settle();
4968
4975
  super.disconnectedCallback();
4969
4976
  }
4970
4977
  updated(changed) {
@@ -5476,18 +5483,122 @@ var _VioCheckout = class _VioCheckout extends LitElement {
5476
5483
  this.confirmedMethod = method;
5477
5484
  this.orderConfirmed = true;
5478
5485
  this.open = true;
5479
- this.dispatchEvent(
5480
- new CustomEvent("vio:payment-success", {
5486
+ void this.fillOrderNumber(checkoutId, sponsorId);
5487
+ void this.emitPaymentSuccess(
5488
+ { method, sponsorId, result, checkoutId },
5489
+ checkoutId,
5490
+ sponsorId,
5491
+ () => Vio.cart.clearSponsorCart(sponsorId)
5492
+ );
5493
+ }
5494
+ static {
5495
+ /** Longest `vio:payment-success` waits for the checkout's buyer reference, and when it asks a second time. */
5496
+ this.BUYER_REF_WAIT_MS = 2500;
5497
+ }
5498
+ static {
5499
+ this.BUYER_REF_RETRY_AT_MS = 1200;
5500
+ }
5501
+ /**
5502
+ * `vio:payment-success` for the host and analytics — with the buyer
5503
+ * reference (`buyerRef`: shopcart's keyed hash of the email → analytics
5504
+ * `buyer_id`) when the checkout can say it. An emitter whose own answer
5505
+ * carried it (Apple Pay, Klarna native) sends at once; the others (a
5506
+ * redirect return, Stripe / Adyen / Nexi in the drawer, a provider's
5507
+ * receipt) ask the checkout — at once and, while it has neither order nor
5508
+ * reference, again at 1.2 s, since a webhook may write the checkout a
5509
+ * moment after the redirect — within 2.5 s, and
5510
+ * send without it when the answer is late or empty. Nothing is asked when
5511
+ * it cannot help (the gateway has no `buyer_ref` yet; a confirmation that
5512
+ * already answered). Only the event waits — the screen is already the
5513
+ * confirmation — and not past the page: when the page hides (`pagehide`,
5514
+ * `visibilitychange`) or the element leaves, the event goes out at once
5515
+ * without the reference. Exactly one event per call. `afterwards` runs
5516
+ * right after the event, so a path keeps the order it always had (the cart
5517
+ * is cleared after the event).
5518
+ */
5519
+ async emitPaymentSuccess(detail, checkoutId, sponsorId, afterwards) {
5520
+ let done = false;
5521
+ const finish = (buyerRef) => {
5522
+ if (done) return;
5523
+ done = true;
5524
+ const event = new CustomEvent("vio:payment-success", {
5481
5525
  bubbles: true,
5482
5526
  composed: true,
5483
- // `checkoutId` is Vio's own reference for the purchase — what the
5484
- // redirect path already sends as `orderId`; analytics falls back to it
5485
- // when the provider's result carries no order id.
5486
- detail: { method, sponsorId, result, checkoutId }
5487
- })
5488
- );
5489
- Vio.cart.clearSponsorCart(sponsorId);
5490
- void this.fillOrderNumber(checkoutId, sponsorId);
5527
+ detail: buyerRef ? { ...detail, buyerRef } : detail
5528
+ });
5529
+ this.dispatchEvent(event);
5530
+ if (!this.isConnected && typeof window !== "undefined") {
5531
+ window.dispatchEvent(new CustomEvent("vio:payment-success", { detail: event.detail }));
5532
+ }
5533
+ try {
5534
+ afterwards?.();
5535
+ } catch {
5536
+ }
5537
+ };
5538
+ const known = buyerRefOf(detail);
5539
+ if (known || !checkoutId || !this.shouldAskBuyerRef(detail)) {
5540
+ finish(known);
5541
+ return;
5542
+ }
5543
+ const settleEarly = () => finish();
5544
+ const onVisibility = () => {
5545
+ if (typeof document !== "undefined" && document.visibilityState === "hidden") settleEarly();
5546
+ };
5547
+ this.pendingSuccessEmits.add(settleEarly);
5548
+ window.addEventListener("pagehide", settleEarly);
5549
+ document.addEventListener("visibilitychange", onVisibility);
5550
+ try {
5551
+ finish(await this.askBuyerRef(checkoutId, sponsorId, () => done));
5552
+ } catch {
5553
+ finish();
5554
+ } finally {
5555
+ this.pendingSuccessEmits.delete(settleEarly);
5556
+ window.removeEventListener("pagehide", settleEarly);
5557
+ document.removeEventListener("visibilitychange", onVisibility);
5558
+ }
5559
+ }
5560
+ /** Whether asking the checkout for the buyer reference can still help. */
5561
+ shouldAskBuyerRef(detail) {
5562
+ if (typeof Vio.checkout.getOrderReference !== "function") return false;
5563
+ if (!gatewayHasBuyerRef()) return false;
5564
+ if ((detail.method === "apple-pay" || detail.method === "klarna") && detail.result) return false;
5565
+ return true;
5566
+ }
5567
+ /**
5568
+ * The buyer reference of a checkout: asked at once and, when that answer
5569
+ * failed or has neither the reference nor an order yet (the webhook has not
5570
+ * written the checkout), again at 1.2 s — all within 2.5 s. An order
5571
+ * without a reference is a settled answer: the backend has none, asking
5572
+ * again cannot help. `undefined` when the time is up, when the answer
5573
+ * stopped mattering (`stopped()`) or on failure.
5574
+ */
5575
+ async askBuyerRef(checkoutId, sponsorId, stopped) {
5576
+ const started = Date.now();
5577
+ const remaining = () => _VioCheckout.BUYER_REF_WAIT_MS - (Date.now() - started);
5578
+ let deadline;
5579
+ const timeUp = new Promise((resolve) => {
5580
+ deadline = setTimeout(() => resolve(null), _VioCheckout.BUYER_REF_WAIT_MS);
5581
+ });
5582
+ try {
5583
+ for (const at of [0, _VioCheckout.BUYER_REF_RETRY_AT_MS]) {
5584
+ const wait = Math.min(at - (Date.now() - started), remaining());
5585
+ if (wait > 0) await Promise.race([new Promise((resolve) => setTimeout(resolve, wait)), timeUp]);
5586
+ if (stopped() || remaining() <= 0) return void 0;
5587
+ try {
5588
+ const reference = await Promise.race([
5589
+ Vio.checkout.getOrderReference(checkoutId, sponsorId || void 0),
5590
+ timeUp
5591
+ ]);
5592
+ if (reference === null) return void 0;
5593
+ if (reference.buyerRef) return reference.buyerRef;
5594
+ if (reference.orderNumber !== null) return void 0;
5595
+ } catch {
5596
+ }
5597
+ }
5598
+ return void 0;
5599
+ } finally {
5600
+ clearTimeout(deadline);
5601
+ }
5491
5602
  }
5492
5603
  static {
5493
5604
  /** Waits between asks for the Vio order number: the order is often born a
@@ -5638,19 +5749,14 @@ var _VioCheckout = class _VioCheckout extends LitElement {
5638
5749
  this.confirmedMethod = method;
5639
5750
  this.open = true;
5640
5751
  const checkoutId = returnCheckoutId || this.checkoutState?.checkoutId;
5641
- this.dispatchEvent(
5642
- new CustomEvent("vio:payment-success", {
5643
- bubbles: true,
5644
- composed: true,
5645
- detail: { method, sponsorId, result, checkoutId }
5646
- })
5647
- );
5648
- if (sponsorId) {
5649
- try {
5650
- Vio.cart.clearSponsorCart(sponsorId);
5651
- } catch {
5752
+ void this.emitPaymentSuccess(
5753
+ { method, sponsorId, result, checkoutId },
5754
+ checkoutId,
5755
+ sponsorId,
5756
+ () => {
5757
+ if (sponsorId) Vio.cart.clearSponsorCart(sponsorId);
5652
5758
  }
5653
- }
5759
+ );
5654
5760
  }
5655
5761
  /** Back from the payment page, asking whether it was paid — and nothing
5656
5762
  * else on screen while we do. */
@@ -7105,5 +7211,5 @@ function registerVioElements() {
7105
7211
  }
7106
7212
 
7107
7213
  export { VioCart, VioCheckout, VioProduct, VioProductCarousel, VioProductDetail, VioTokens, applyVioTheme, registerVioElements };
7108
- //# sourceMappingURL=chunk-N6U65DWG.js.map
7109
- //# sourceMappingURL=chunk-N6U65DWG.js.map
7214
+ //# sourceMappingURL=chunk-A3LN5JEM.js.map
7215
+ //# sourceMappingURL=chunk-A3LN5JEM.js.map