@vio-live/web-sdk 0.29.0 → 0.33.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.
@@ -185,6 +185,12 @@ interface SponsorCommerceBlock {
185
185
  channelId?: string | null;
186
186
  paymentMethods?: string[];
187
187
  }
188
+ /** One of a brand's promises («Rask levering» / «2-5 virkedager»), with a line icon of the SDK's set. */
189
+ interface SponsorHighlight {
190
+ icon: string;
191
+ title: string;
192
+ text?: string | null;
193
+ }
188
194
  interface Sponsor {
189
195
  id: number;
190
196
  name: string;
@@ -197,6 +203,8 @@ interface Sponsor {
197
203
  termsUrl?: string | null;
198
204
  /** The brand's returns / refund policy page. */
199
205
  refundPolicyUrl?: string | null;
206
+ /** The brand's promises (Settings → Brand): up to three, shown under the buy zone of the product detail. */
207
+ highlights?: SponsorHighlight[] | null;
200
208
  commerce: SponsorCommerceBlock;
201
209
  }
202
210
  /**
@@ -481,6 +489,19 @@ interface CommerceClientOptions {
481
489
  /** Per-sponsor commerce apiKey (from bootstrap.primarySponsor.commerce.apiKey). */
482
490
  apiKey: string;
483
491
  }
492
+ /** One shipping rate of a product for a country, tax included. */
493
+ interface ProductShippingRate {
494
+ id: string;
495
+ name: string;
496
+ /** Major units, tax included when the backend says it. */
497
+ price: number;
498
+ currency: string;
499
+ default: boolean;
500
+ /** What the brand wrote for the rate — in practice its delivery time («Leveringstid 1-5 dager»); '' when none. */
501
+ description: string;
502
+ /** The carrier's logo for the rate (https), '' when none. */
503
+ logoUrl: string;
504
+ }
484
505
  interface GetProductsByIdsOptions {
485
506
  product_ids: number[];
486
507
  currency?: string | null;
@@ -506,6 +527,16 @@ declare class ChannelProduct {
506
527
  * price and no images. `useCache: false` neither reads nor writes it.
507
528
  */
508
529
  getSellerCompany(productId: number): Promise<string | null>;
530
+ /**
531
+ * The product's shipping rates for the page's market (or `country`),
532
+ * cheapest first; `[]` when it has none there, `null` when they could not
533
+ * be read. Never throws. Never from the cache, for the reason given at
534
+ * getSellerCompany.
535
+ */
536
+ getShippingRates(productId: number, options?: {
537
+ currency?: string | null;
538
+ country?: string | null;
539
+ }): Promise<ProductShippingRate[] | null>;
509
540
  }
510
541
  declare class Channel {
511
542
  readonly product: ChannelProduct;
@@ -596,6 +627,15 @@ interface SponsorCartState {
596
627
  currency: string;
597
628
  /** Backend (Vio Commerce) cart id, once created. */
598
629
  cartId?: string;
630
+ /**
631
+ * The commerce channel the backend cart was created on (the sponsor's
632
+ * block for the campaign the first line came from). Every later cart and
633
+ * checkout call for this cart uses THAT channel's key; when the bootstrap
634
+ * no longer lists it, the cart is created again on the current channel with
635
+ * its lines. Absent on carts created before 0.33 (they keep the sponsor's
636
+ * first block, as then, and learn it on the next call).
637
+ */
638
+ channelId?: string;
599
639
  shippingCountry?: string;
600
640
  subtotal?: number;
601
641
  shipping?: number;
@@ -603,385 +643,88 @@ interface SponsorCartState {
603
643
  }
604
644
 
605
645
  /**
606
- * CartManager — multi-sponsor cart state.
646
+ * What the commerce gateway may not know yet.
607
647
  *
608
- * Mirrors iOS's `CartManager` + `cartsBySponsor`. Holds local state in
609
- * memory and persists to localStorage. Reactive: dispatches a `change`
610
- * CustomEvent that UI components subscribe to (Web Components react via
611
- * `requestUpdate()`).
648
+ * The SDK ships ahead of the gateway more than once a quarter: a selection
649
+ * (`buyer_ref`, 2026-10-19), an argument (`origin` on the cart lines,
650
+ * `attribution` on the checkout — ADR-0035 phase B). A gateway that does not
651
+ * have the field refuses the WHOLE operation at validation — before anything
652
+ * runs, with no `data` — so each such operation is sent again without the
653
+ * field, once, and the answer remembered for the page load. An operation that
654
+ * DID run and failed is never repeated: for a mutation that would be a second
655
+ * charge, a second line in the cart.
612
656
  *
613
- * The backend cart (Vio Commerce GraphQL CreateCart / AddItem / UpdateItem /
614
- * DeleteItem) is kept in sync optimistically from here; since 0.26 every add
615
- * and every increase tells it where the units come from (`origin`, ADR-0035
616
- * phase B) so the order is born attributed — see `origin-wire.ts`.
657
+ * One mechanism for all of them, so the next field costs a token here and a
658
+ * call to `withGatewayFeature`, not a new copy of the retry.
617
659
  */
660
+ type GatewayFeature = 'buyer_ref' | 'line_origin' | 'checkout_attribution';
661
+ /** Whether this page load still expects the gateway to know `feature` (false once it refused it). */
662
+ declare function gatewayHas(feature: GatewayFeature): boolean;
663
+ /** Forget what this page load learned (tests). One feature, or all of them. */
664
+ declare function resetGatewayFeatures(feature?: GatewayFeature): void;
665
+ /**
666
+ * True when `err` is the gateway refusing something it does not know, named
667
+ * `token` (`Cannot query field "buyer_ref" on type …`, `Unknown argument
668
+ * "origin" on field …`, `Unknown type "CartLineOriginInput"`, `Field "origin" is
669
+ * not defined by type "LineItemInput"`): a validation error, with no `data`
670
+ * and no `path` because nothing ran — safe to send again without it, a
671
+ * mutation included. Anything that ran (data present, or an error with a
672
+ * path) or any other message is not.
673
+ */
674
+ declare function isUnknownTokenError(err: unknown, token: string): boolean;
675
+ /** `isUnknownTokenError` for any of the names a feature goes by. */
676
+ declare function isUnknownFeatureError(err: unknown, feature: GatewayFeature): boolean;
677
+ /**
678
+ * Runs `request(true)` (the operation with the feature); when the gateway
679
+ * does not know it, `request(false)` (without it) — and from then on, for
680
+ * this page load, straight to the latter. Said once in the console: a
681
+ * gateway behind the SDK is worth knowing about, and so is a renamed type.
682
+ */
683
+ declare function withGatewayFeature<T>(feature: GatewayFeature, request: (supported: boolean) => Promise<T>): Promise<T>;
618
684
 
619
- interface CartChangeDetail {
620
- cartsBySponsor: Map<number, SponsorCartState>;
621
- itemCount: number;
622
- }
623
685
  /**
624
- * Detail of `vio:cart-updated` (on `document`): a sponsor's cart as it stands
625
- * after this tab learned of it from somewhere other than its own taps —
626
- * `source: 'server'`: GetCart, applied right before a checkout is built on it
627
- * (`refreshFromServer`); `source: 'storage'`: another tab of the same site
628
- * wrote it (an add there, a payment that cleared it). The lines are copies.
686
+ * A line origin as Commerce receives it (ADR-0035 phase B): `origin` on each
687
+ * line of `AddItem` and, when the quantity goes UP, on `UpdateItem` — the
688
+ * origin of the units that update adds. shopcart keeps every origin of a
689
+ * line with its units (`cart_item.origins`) and writes the order from them:
690
+ * `order_item.campaign_id` / `location_id` / `component_kind`, and the
691
+ * order's page when the checkout does not name one.
692
+ *
693
+ * snake_case on the wire, the caps of shopcart's `LineOriginDto` enforced
694
+ * here, once. Pure: `lineOriginWire()` takes the origin and the page.
629
695
  */
630
- interface CartUpdatedDetail {
631
- sponsorId: number;
632
- cartId?: string;
633
- items: CartLineItem[];
634
- itemCount: number;
635
- subtotal: number;
636
- currency: string;
637
- source: 'server' | 'storage';
638
- }
639
- interface AddProductOptions {
640
- product: Product;
641
- sponsorId: number;
642
- sponsorName?: string;
643
- quantity?: number;
644
- variantId?: number;
645
- /** Where these units come from (`Vio.attribution(slot)`); see `CartOrigin`. */
646
- origin?: CartOrigin;
696
+
697
+ /** The largest `Int` GraphQL coerces; a bigger id would fail the whole mutation. */
698
+ declare const GRAPHQL_INT_MAX = 2147483647;
699
+ /** `LineOriginDto` (shopcart `cart/dtos/send/line-origin.dto.ts`). */
700
+ interface LineOriginWire {
701
+ campaign_id?: number;
702
+ location_id?: string;
703
+ component_kind?: string;
704
+ content_url?: string;
705
+ content_title?: string;
647
706
  }
648
- /** Minimal product shape — for callers who only have e.g. mock data, not a full Product. */
649
- interface AddManualOptions {
650
- productId: number;
651
- sponsorId: number;
652
- sponsorName?: string;
653
- brand: string;
654
- name: string;
655
- unitPrice: number;
656
- currency: string;
657
- imageUrl: string;
658
- quantity?: number;
659
- variantId?: number;
660
- /** Where these units come from (`Vio.attribution(slot)`); see `CartOrigin`. */
661
- origin?: CartOrigin;
707
+ /** The caps of `LineOriginDto` — a longer value is refused whole by the API, so it is cut here. */
708
+ declare const LINE_ORIGIN_CAPS: Readonly<{
709
+ locationId: 100;
710
+ componentKind: 32;
711
+ contentUrl: 2048;
712
+ contentTitle: 255;
713
+ }>;
714
+ /** The page the units are added from, for an origin that does not carry its own. */
715
+ interface OriginPage {
716
+ contentUrl?: string;
717
+ contentTitle?: string;
662
718
  }
663
- declare class CartManager extends EventTarget {
664
- private cartsBySponsor;
665
- /** In-flight CreateCart per sponsor — two quick adds must share ONE backend
666
- * cart (two CreateCarts split the items and one silently disappears). */
667
- private cartIdPromises;
668
- /** Monotonic mutation counter per sponsor + last applied response, so a
669
- * slow response can't overwrite the state of a newer one. */
670
- private mutationSeq;
671
- private appliedSeq;
672
- /** In-flight AddItem/UpdateItem/DeleteItem per sponsor. Callers that need
673
- * the backend cart to reflect a just-made change (e.g. fetching shippings
674
- * right after an add) should `await waitForCartMutations(sponsorId)` first
675
- * — otherwise they can race the mutation and see the cart from before it
676
- * landed (Alan, 2026-08-18: shippings queried before AddItem settled,
677
- * came back empty). */
678
- private inFlightMutations;
679
- /** Per-line quantity sync with the backend: at most ONE UpdateItem /
680
- * DeleteItem in flight per line. Targets that arrive while one is in flight
681
- * are coalesced into `pending` (only the latest survives) and sent when the
682
- * current request settles. Keyed by `${sponsorId}:${cartItemId}`.
683
- * (Alan, 2026-10-15: a burst of +/− clicks fired one UpdateItem per click
684
- * in parallel; each response re-applied the whole backend cart, so an
685
- * older one landing after a newer optimistic change rolled the line back.) */
686
- private qtySyncs;
687
- constructor();
688
- private nextSeq;
689
- /** Resolves once every in-flight AddItem/UpdateItem/DeleteItem for this
690
- * sponsor has settled (success or failure), including ones started while
691
- * waiting (a quantity intent replayed by an AddItem reconcile). No-op if
692
- * nothing is pending. */
693
- waitForCartMutations(sponsorId: number): Promise<void>;
694
- /**
695
- * True while an AddItem/UpdateItem/DeleteItem of this sponsor OTHER than
696
- * `except` has not settled. A mutation applying its own answer passes
697
- * itself: its response is current for what IT sent — only the others make
698
- * it stale.
699
- */
700
- private hasMutationsInFlight;
701
- /** Register a backend mutation so `waitForCartMutations` can await it. */
702
- private trackMutation;
703
- private qtySyncKey;
704
- /** The quantity a line is heading to (pending beats in flight), or
705
- * undefined when no quantity sync is active for it. */
706
- private intendedQuantity;
707
- /** Apply a backend response only if no newer response was applied already.
708
- * Returns false when it was discarded as stale. */
709
- private applyBackendCart;
710
- /** The final answer of a line's sync lost the per-sponsor seq race (another
711
- * line answered later): the cart as a whole is stale, but for THIS line it
712
- * is the latest word. Copy its quantity (and price) so a server-side clamp
713
- * — stock — doesn't leave the optimistic value behind for good, with the
714
- * checkout / Apple Pay total built on it. */
715
- private reconcileLineFromResponse;
716
- /** Surface a cart sync problem to hosts/UI (and the console). */
717
- private emitError;
718
- /** Ensure the sponsor cart exists server-side; returns its backend cart id. */
719
- ensureCartId(sponsorId: number, currency?: string, shippingCountry?: string): Promise<string | undefined>;
719
+ interface LineOriginWireOptions {
720
+ /** The current page, for an origin that does not carry its own. */
721
+ page?: OriginPage;
720
722
  /**
721
- * Overwrite local cart state with the backend cart response (source of
722
- * truth). `opts.settling` is the mutation whose answer this is: it does not
723
- * count as "in flight" for the origins (see `hasMutationsInFlight`).
724
- * `opts.authoritative` is a GetCart taken with nothing of this tab's in
725
- * flight (`refreshFromServer`): an empty answer then means the cart IS
726
- * empty, and the local lines go — not an add still on its way.
727
- */
728
- updateFromBackendCart(sponsorId: number, backendCart: {
729
- cart_id?: string;
730
- currency?: string;
731
- shipping_country?: string;
732
- subtotal?: number;
733
- shipping?: number;
734
- available_shipping_countries?: string[];
735
- line_items?: Array<{
736
- id: string;
737
- product_id: number;
738
- variant_id?: number | string | null;
739
- variant_title?: string | null;
740
- brand?: string | null;
741
- title?: string | null;
742
- quantity: number;
743
- image?: string | {
744
- url?: string;
745
- } | null;
746
- imageUrl?: string | null;
747
- image_url?: string | null;
748
- price?: {
749
- amount?: number;
750
- amount_incl_taxes?: number | null;
751
- currency_code?: string;
752
- } | null;
753
- shipping?: unknown;
754
- available_shippings?: unknown[];
755
- }>;
756
- }, opts?: {
757
- settling?: Promise<unknown>;
758
- authoritative?: boolean;
759
- }): void;
760
- /** Add a Product DTO to a sponsor's cart. Bumps quantity if already present.
761
- * When a variantId is given, the line uses the VARIANT's price / image / title
762
- * (not the product base), so different combinations are priced correctly. */
763
- addProduct(opts: AddProductOptions): CartLineItem;
764
- /** Add a manually-specified line item (no Product DTO). */
765
- addManual(opts: AddManualOptions): CartLineItem;
766
- /** Quantity intents for lines whose backend id hasn't arrived yet — replayed
767
- * when the AddItem response reconciles (keyed by product::variant). */
768
- private pendingQtyIntents;
769
- private intentKey;
770
- private findLine;
771
- /** Change a line's quantity by `delta`, computed on the manager's CURRENT
772
- * quantity — not on whatever a UI rendered a moment ago. A burst of +/−
773
- * clicks before a re-render therefore asks for 2, 3, 4… and not for the
774
- * same target several times. Reaching 0 removes the line. */
775
- adjustQuantity(lineItemId: string, sponsorId: number, delta: number, opts?: {
776
- origin?: CartOrigin;
777
- }): void;
778
- /** Set a line's quantity (0 or less removes it). Optimistic: the local
779
- * state and `change` update at once; the backend is synced through
780
- * `syncQuantity`, one request in flight per line, latest target wins. */
781
- updateQuantity(lineItemId: string, sponsorId: number, quantity: number, opts?: {
782
- origin?: CartOrigin;
783
- }): void;
784
- /** Send a line's target quantity to the backend — ONE request in flight per
785
- * line. Targets that arrive while one is in flight queue behind it as
786
- * steps (`queueStep`): reduced like the line's origins, sent in order once
787
- * the current request settles — one request per queued increase from a
788
- * different origin, one for a net decrease — so the server ends on the
789
- * last intent, credits every increase to its own origin, and never sees two
790
- * updates racing each other. While the sync is active the line keeps its
791
- * optimistic quantity through any backend response (see
792
- * `updateFromBackendCart`); a rejection drops what was queued and
793
- * reconciles the cart from the server. */
794
- private syncQuantity;
795
- removeItem(lineItemId: string, sponsorId: number): void;
796
- clearSponsorCart(sponsorId: number): void;
797
- clearAllCarts(): void;
798
- /** Refresh the local cart from the backend (source of truth). */
799
- fetchCartFromBackend(sponsorId: number): Promise<unknown>;
800
- /**
801
- * The cart as the server has it, for the moment a checkout is about to be
802
- * built on it: what the shopper is about to pay must be what the page shows.
803
- * Waits for this tab's own mutations (their answers are the server's too),
804
- * then applies GetCart as it is — a line another tab added, one it removed,
805
- * an empty cart — and tells the page: `change` for the drawer, and
806
- * `vio:cart-updated` on `document` (`source: 'server'`) for a host that
807
- * draws its own. A mutation that starts while the server is answering makes
808
- * that answer old: it is asked once more. Nothing to ask without a backend
809
- * cart. A GetCart that fails leaves the local state as it was and does not
810
- * throw — the checkout then goes on with the lines the last mutation
811
- * answered, as it always did. Resolves with the sponsor's cart.
812
- */
813
- refreshFromServer(sponsorId: number): Promise<SponsorCartState | undefined>;
814
- /** `vio:cart-updated` on `document` — see `CartUpdatedDetail`. */
815
- private emitCartUpdated;
816
- /**
817
- * Another tab of the site wrote the carts: adopt what it wrote, sponsor by
818
- * sponsor — its lines and its backend cart id, or nothing when it cleared
819
- * the cart (a payment) — except for a sponsor this tab is mid-write for:
820
- * its own answer lands in a moment and is persisted then, over whatever
821
- * the other tab had. `key` is null when the other tab cleared the whole
822
- * storage. Says `change` (the drawer) and `vio:cart-updated` per sponsor
823
- * that changed (`source: 'storage'`); nothing when nothing did.
824
- */
825
- private onStorage;
826
- /** Line items grouped by supplier (shipping is per-supplier server-side). */
827
- fetchLineItemsBySupplier(sponsorId: number): Promise<unknown>;
828
- /** Set the chosen shipping option per supplier on the backend cart. */
829
- updateShippingsBySupplier(sponsorId: number, data: Array<{
830
- shipping_id: string;
831
- supplier_id: number;
832
- }>): Promise<unknown>;
833
- getAllCarts(): Map<number, SponsorCartState>;
834
- getCart(sponsorId: number): SponsorCartState | undefined;
835
- get itemCount(): number;
836
- subtotalForSponsor(sponsorId: number): number;
837
- get totalAcrossSponsors(): number;
838
- get primaryCurrency(): string;
839
- formatTotal(): string;
840
- private persist;
841
- private loadFromStorage;
842
- private emit;
843
- }
844
- /**
845
- * Only the attribution fields, trimmed; `{}` when nothing is known. The kind
846
- * of element is kept as Commerce and the collector name it (`card`,
847
- * `carousel`, `detail` — `componentKindOf`), from `componentKind` or from
848
- * the `componentTemplateId` an element's attribution carries (`product-card`);
849
- * the page as origin + path (`contentUrl`) and its title, within Commerce's caps.
850
- */
851
- declare function normalizeOrigin(origin: CartOrigin | null | undefined): CartOrigin;
852
- /** Two origins are the same place when campaign, slot, content and kind of element all match (the page's URL and title are attributes of the place, not its identity). */
853
- declare function sameOrigin(a: CartOrigin, b: CartOrigin): boolean;
854
- /**
855
- * The origins of a line for reporting: what it carries, plus an empty origin
856
- * for any units it does not account for (a cart persisted before origins
857
- * existed, a server-side bump). Their quantities add up to the line's.
858
- */
859
- declare function lineOrigins(line: Pick<CartLineItem, 'origins' | 'quantity'>): CartLineOrigin[];
860
-
861
- /**
862
- * Who sells — the sponsor's (brand's) display identity: its name and logo.
863
- *
864
- * ONE rule for every place that names a sponsor (the product detail, the
865
- * carousel's retailer line, the cart, the checkout header, the confirmation,
866
- * the payment event and `getOrderReference`): the bootstrap's sponsor block —
867
- * the config's primary and secondaries, then every `campaigns[]` primary and
868
- * secondaries, first match — and, when the bootstrap does not know the id,
869
- * what this tab remembered of the checkout, then the cart's `sponsorName`.
870
- *
871
- * In a checkout and on its confirmation the sponsor is the CHECKOUT's (the
872
- * cart's sponsor, the one the order is with), never the page's attribution:
873
- * an article of brand A may sell a product of brand B.
874
- *
875
- * Pure helpers and a tiny per-checkout memory in `sessionStorage`; no DOM.
876
- */
877
-
878
- /** What a sponsor looks like to a shopper. `name` is the brand's display name. */
879
- interface SponsorIdentity {
880
- id: number;
881
- name: string;
882
- /** The brand's logo, as the bootstrap gives it (never rewritten); `null` when it has none. */
883
- logoUrl: string | null;
884
- avatarUrl: string | null;
885
- /** The brand's purchase terms page — https only; `null` when it has none. */
886
- termsUrl?: string | null;
887
- /** The brand's returns / refund policy page — https only; `null` when it has none. */
888
- refundPolicyUrl?: string | null;
889
- }
890
- /** The sponsor of a checkout / an order as events and `getOrderReference` carry it. */
891
- type CheckoutSponsor = Pick<SponsorIdentity, 'id' | 'name' | 'logoUrl'>;
892
- /** `sessionStorage` key of the per-checkout memory. */
893
- declare const CHECKOUT_SPONSOR_STORAGE_KEY = "vio.checkoutSponsor.v1";
894
- /**
895
- * The identity of a sponsor from a bootstrap (`findSponsorIn`): its trimmed
896
- * name and its logo / avatar URLs as given (an empty string is `null`).
897
- * `null` when the bootstrap does not know the id, or the block says neither
898
- * a name nor a logo. Pure, never throws.
899
- */
900
- declare function sponsorIdentityFrom(boot: BootstrapResponse | null | undefined, sponsorId: number | string | null | undefined): SponsorIdentity | null;
901
-
902
- /**
903
- * What the commerce gateway may not know yet.
904
- *
905
- * The SDK ships ahead of the gateway more than once a quarter: a selection
906
- * (`buyer_ref`, 2026-10-19), an argument (`origin` on the cart lines,
907
- * `attribution` on the checkout — ADR-0035 phase B). A gateway that does not
908
- * have the field refuses the WHOLE operation at validation — before anything
909
- * runs, with no `data` — so each such operation is sent again without the
910
- * field, once, and the answer remembered for the page load. An operation that
911
- * DID run and failed is never repeated: for a mutation that would be a second
912
- * charge, a second line in the cart.
913
- *
914
- * One mechanism for all of them, so the next field costs a token here and a
915
- * call to `withGatewayFeature`, not a new copy of the retry.
916
- */
917
- type GatewayFeature = 'buyer_ref' | 'line_origin' | 'checkout_attribution';
918
- /** Whether this page load still expects the gateway to know `feature` (false once it refused it). */
919
- declare function gatewayHas(feature: GatewayFeature): boolean;
920
- /** Forget what this page load learned (tests). One feature, or all of them. */
921
- declare function resetGatewayFeatures(feature?: GatewayFeature): void;
922
- /**
923
- * True when `err` is the gateway refusing something it does not know, named
924
- * `token` (`Cannot query field "buyer_ref" on type …`, `Unknown argument
925
- * "origin" on field …`, `Unknown type "CartLineOriginInput"`, `Field "origin" is
926
- * not defined by type "LineItemInput"`): a validation error, with no `data`
927
- * and no `path` because nothing ran — safe to send again without it, a
928
- * mutation included. Anything that ran (data present, or an error with a
929
- * path) or any other message is not.
930
- */
931
- declare function isUnknownTokenError(err: unknown, token: string): boolean;
932
- /** `isUnknownTokenError` for any of the names a feature goes by. */
933
- declare function isUnknownFeatureError(err: unknown, feature: GatewayFeature): boolean;
934
- /**
935
- * Runs `request(true)` (the operation with the feature); when the gateway
936
- * does not know it, `request(false)` (without it) — and from then on, for
937
- * this page load, straight to the latter. Said once in the console: a
938
- * gateway behind the SDK is worth knowing about, and so is a renamed type.
939
- */
940
- declare function withGatewayFeature<T>(feature: GatewayFeature, request: (supported: boolean) => Promise<T>): Promise<T>;
941
-
942
- /**
943
- * A line origin as Commerce receives it (ADR-0035 phase B): `origin` on each
944
- * line of `AddItem` and, when the quantity goes UP, on `UpdateItem` — the
945
- * origin of the units that update adds. shopcart keeps every origin of a
946
- * line with its units (`cart_item.origins`) and writes the order from them:
947
- * `order_item.campaign_id` / `location_id` / `component_kind`, and the
948
- * order's page when the checkout does not name one.
949
- *
950
- * snake_case on the wire, the caps of shopcart's `LineOriginDto` enforced
951
- * here, once. Pure: `lineOriginWire()` takes the origin and the page.
952
- */
953
-
954
- /** The largest `Int` GraphQL coerces; a bigger id would fail the whole mutation. */
955
- declare const GRAPHQL_INT_MAX = 2147483647;
956
- /** `LineOriginDto` (shopcart `cart/dtos/send/line-origin.dto.ts`). */
957
- interface LineOriginWire {
958
- campaign_id?: number;
959
- location_id?: string;
960
- component_kind?: string;
961
- content_url?: string;
962
- content_title?: string;
963
- }
964
- /** The caps of `LineOriginDto` — a longer value is refused whole by the API, so it is cut here. */
965
- declare const LINE_ORIGIN_CAPS: Readonly<{
966
- locationId: 100;
967
- componentKind: 32;
968
- contentUrl: 2048;
969
- contentTitle: 255;
970
- }>;
971
- /** The page the units are added from, for an origin that does not carry its own. */
972
- interface OriginPage {
973
- contentUrl?: string;
974
- contentTitle?: string;
975
- }
976
- interface LineOriginWireOptions {
977
- /** The current page, for an origin that does not carry its own. */
978
- page?: OriginPage;
979
- /**
980
- * The surface's privacy mode. Only on a `standard` surface do the slot
981
- * (`location_id`) and the page (`content_url`, `content_title`) travel —
982
- * which screen a unit was sold from is what `minimal` keeps private, the
983
- * same promise the collector keeps for the events. `campaign_id` and
984
- * `component_kind` always do. Default `unknown`: fail closed.
723
+ * The surface's privacy mode. Only on a `standard` surface do the slot
724
+ * (`location_id`) and the page (`content_url`, `content_title`) travel —
725
+ * which screen a unit was sold from is what `minimal` keeps private, the
726
+ * same promise the collector keeps for the events. `campaign_id` and
727
+ * `component_kind` always do. Default `unknown`: fail closed.
985
728
  */
986
729
  privacyMode?: SurfacePrivacyMode | 'unknown';
987
730
  }
@@ -1206,6 +949,63 @@ declare function autoSlotDisplayName(kind: SlotKind, ordinal: number, scopeName?
1206
949
  /** A scope value fit for an id: trimmed, inner whitespace → `-`. */
1207
950
  declare function normalizeScope(scope: string | null | undefined): string;
1208
951
 
952
+ /**
953
+ * Who sells — the sponsor's (brand's) display identity: its name and logo.
954
+ *
955
+ * ONE rule for every place that names a sponsor (the product detail, the
956
+ * carousel's retailer line, the cart, the checkout header, the confirmation,
957
+ * the payment event and `getOrderReference`): the bootstrap's sponsor block —
958
+ * the config's primary and secondaries, then every `campaigns[]` primary and
959
+ * secondaries, first match — and, when the bootstrap does not know the id,
960
+ * what this tab remembered of the checkout, then the cart's `sponsorName`.
961
+ *
962
+ * In a checkout and on its confirmation the sponsor is the CHECKOUT's (the
963
+ * cart's sponsor, the one the order is with), never the page's attribution:
964
+ * an article of brand A may sell a product of brand B.
965
+ *
966
+ * Pure helpers and a tiny per-checkout memory in `sessionStorage`; no DOM.
967
+ */
968
+
969
+ /** What a sponsor looks like to a shopper. `name` is the brand's display name. */
970
+ interface SponsorIdentity {
971
+ id: number;
972
+ name: string;
973
+ /** The brand's logo, as the bootstrap gives it (never rewritten); `null` when it has none. */
974
+ logoUrl: string | null;
975
+ avatarUrl: string | null;
976
+ /** The brand's purchase terms page — https only; `null` when it has none. */
977
+ termsUrl?: string | null;
978
+ /** The brand's returns / refund policy page — https only; `null` when it has none. */
979
+ refundPolicyUrl?: string | null;
980
+ /** The brand's promises (at most three, each with a title); absent when it has none. */
981
+ highlights?: SponsorHighlight[];
982
+ }
983
+ /** The sponsor of a checkout / an order as events and `getOrderReference` carry it. */
984
+ type CheckoutSponsor = Pick<SponsorIdentity, 'id' | 'name' | 'logoUrl'>;
985
+ /** `sessionStorage` key of the per-checkout memory. */
986
+ declare const CHECKOUT_SPONSOR_STORAGE_KEY = "vio.checkoutSponsor.v1";
987
+ /**
988
+ * Where a sponsor sells right now: the campaign in context (`campaignId` —
989
+ * the element's `vio-campaign`, an ancestor's `data-vio-campaign`, the
990
+ * click's `campaignId`, `Vio.init`'s, in that order of precedence) or the
991
+ * channel a cart was created on (`channelId`).
992
+ */
993
+ interface SponsorCommerceContext {
994
+ campaignId?: CampaignHint;
995
+ channelId?: string | number | null;
996
+ }
997
+ /** A sponsor block that can sell: it carries a commerce block with an API key. */
998
+ type SellingSponsor = Sponsor & {
999
+ commerce: SponsorCommerceBlock;
1000
+ };
1001
+ /**
1002
+ * The identity of a sponsor from a bootstrap (`findSponsorIn`): its trimmed
1003
+ * name and its logo / avatar URLs as given (an empty string is `null`).
1004
+ * `null` when the bootstrap does not know the id, or the block says neither
1005
+ * a name nor a logo. Pure, never throws.
1006
+ */
1007
+ declare function sponsorIdentityFrom(boot: BootstrapResponse | null | undefined, sponsorId: number | string | null | undefined): SponsorIdentity | null;
1008
+
1209
1009
  /**
1210
1010
  * Vio.analytics — the web SDK's half of the Vio Analytics pipeline.
1211
1011
  *
@@ -1331,6 +1131,21 @@ interface AnalyticsStartOptions {
1331
1131
  * its own rotating session.
1332
1132
  */
1333
1133
  sessionId?: string;
1134
+ /**
1135
+ * Dejar de capturar QUÉ contenido se está viendo: sin `content_url`,
1136
+ * `content_title`, `content_id` ni nombre/marca de producto. Default false
1137
+ * (se captura).
1138
+ *
1139
+ * Para superficies donde el contenido ES el dato sensible — una app de
1140
+ * salud: la pantalla abierta y el producto comprado revelan la condición
1141
+ * aunque el dispositivo sea anónimo. El funnel se sigue midiendo: ids de
1142
+ * campaña y componente, cantidades e importes.
1143
+ *
1144
+ * El colector lo aplica igual del lado del servidor para las surfaces
1145
+ * marcadas (`client_apps.privacy_mode = 'minimal'`); este interruptor evita
1146
+ * que el dato salga del dispositivo.
1147
+ */
1148
+ privateContent?: boolean;
1334
1149
  /** Send to the Vio collector. Default true. */
1335
1150
  collector?: boolean;
1336
1151
  /** Also push GA4 e-commerce events to window.dataLayer (publisher feature). */
@@ -1362,6 +1177,14 @@ declare class AnalyticsManager extends EventTarget {
1362
1177
  private client;
1363
1178
  /** The landing it was read from — persisted later when consent arrives after the first event. */
1364
1179
  private landing;
1180
+ /**
1181
+ * Internal traffic (ADR-0041): `client.internal: true` on every event while
1182
+ * set. Read once (`?vio_internal=1|0`, else `localStorage`) at `Vio.init()`
1183
+ * or on the first event; `setInternal()` changes it. `null` = not read yet.
1184
+ */
1185
+ private internal;
1186
+ /** The console line for testers goes out once per page load. */
1187
+ private internalAnnounced;
1365
1188
  /** Checkouts (`c:<id>`) and orders (`o:<number>`) this page load reported a `purchase` for: one each. */
1366
1189
  private readonly purchased;
1367
1190
  /** Checkouts this page load reported an `add_payment_info` for: one each. */
@@ -1392,6 +1215,24 @@ declare class AnalyticsManager extends EventTarget {
1392
1215
  stop(): void;
1393
1216
  /** Attach the partner's user id (opaque) to all subsequent events. */
1394
1217
  identify(externalUserId: string | null): void;
1218
+ /**
1219
+ * Mark (or unmark) this browser as Vio's own traffic (ADR-0041): while
1220
+ * marked, every event carries `client.internal: true` and the collector's
1221
+ * reads leave it out. Remembered in `localStorage` (`vio.internal.v1`) —
1222
+ * the same mark `?vio_internal=1` / `?vio_internal=0` sets on any page.
1223
+ */
1224
+ setInternal(internal: boolean): void;
1225
+ /** Whether this browser is marked as internal traffic (reads the mark the first time). */
1226
+ get isInternal(): boolean;
1227
+ /**
1228
+ * Read the mark: the page's `?vio_internal=1|0` (remembered), else what the
1229
+ * browser remembers. Once per page load — `Vio.init()` calls it so a page
1230
+ * with the parameter marks the browser even if it never starts analytics;
1231
+ * `force` reads again.
1232
+ */
1233
+ syncInternal(force?: boolean): boolean;
1234
+ /** One console line when marked, so a tester can see the mark took. */
1235
+ private announceInternal;
1395
1236
  /** Queue one event. Works pre-init and pre-start (SSR: no-op). */
1396
1237
  track(name: AnalyticsEventName, opts?: TrackOptions): void;
1397
1238
  /** The sinks and the queue for one built event — `track`'s second half. */
@@ -1410,6 +1251,11 @@ declare class AnalyticsManager extends EventTarget {
1410
1251
  /** Called the one time the impression is tracked (e.g. to fire a
1411
1252
  * companion view_item_list). */
1412
1253
  onImpression?: () => void;
1254
+ /** What the element shows, read when the impression fires: its
1255
+ * products go out as `commerce.items` (the collector counts a
1256
+ * per-product impression from them, ADR-0041). Nothing when it
1257
+ * answers no items. */
1258
+ commerce?: () => AnalyticsCommerce | null | undefined;
1413
1259
  }): () => void;
1414
1260
  /** Force a flush (mostly for tests). */
1415
1261
  flush(): Promise<void>;
@@ -1721,190 +1567,531 @@ interface CheckoutAttributionInput {
1721
1567
  /** Where the session came in (`resolveLanding()`): referrer, utm, landing page. */
1722
1568
  landing?: Landing | null;
1723
1569
  /**
1724
- * The surface's privacy mode. Only on a `standard` surface do the page
1725
- * (`content_url`, `content_title`) and the entry context travel: which
1726
- * screen the sale was made on and why the shopper was there is what
1727
- * `minimal` keeps private — the same promise the collector keeps for the
1728
- * events. `unknown` (it could not be learnt) counts as `minimal`: what can
1729
- * reveal it is only sent when the surface is known to allow it. The surface
1730
- * and the campaign always travel.
1570
+ * The surface's privacy mode. Only on a `standard` surface do the page
1571
+ * (`content_url`, `content_title`) and the entry context travel: which
1572
+ * screen the sale was made on and why the shopper was there is what
1573
+ * `minimal` keeps private — the same promise the collector keeps for the
1574
+ * events. `unknown` (it could not be learnt) counts as `minimal`: what can
1575
+ * reveal it is only sent when the surface is known to allow it. The surface
1576
+ * and the campaign always travel.
1577
+ */
1578
+ privacyMode?: SurfacePrivacyMode | 'unknown';
1579
+ }
1580
+ /**
1581
+ * The attribution for the wire, or `undefined` when there is nothing to say.
1582
+ * The campaign is the page's; without one, the campaign that explains most
1583
+ * units of the cart under the same rule `purchase` is split by (ties: the
1584
+ * higher value, then the first). The page (origin + path) and the entry go
1585
+ * only on a `standard` surface.
1586
+ */
1587
+ declare function checkoutAttributionOf(input: CheckoutAttributionInput): CheckoutAttributionWire | undefined;
1588
+ /** The landing as `entry`, capped; `undefined` when it says nothing. */
1589
+ declare function entryContextOf(landing: Landing | null | undefined): EntryContextWire | undefined;
1590
+ /**
1591
+ * The campaign that explains most units of the cart — over the slices
1592
+ * `purchase` is split by, so the order names the campaign the biggest
1593
+ * purchase event names. Ties go to the higher value, then to the first
1594
+ * slice. Units nobody attributes (a slice without campaign) never win.
1595
+ */
1596
+ declare function dominantCampaignOf(slices: ReadonlyArray<CartSlice> | null | undefined): number | undefined;
1597
+
1598
+ /**
1599
+ * Vipps MobilePay Payment Adapter — GraphQL Integration & Types.
1600
+ *
1601
+ * Vipps payment integration uses 2 GraphQL operations:
1602
+ *
1603
+ * 1. `CreatePaymentVipps` mutation:
1604
+ * Initiates a Vipps payment session for a checkout and returns `payment_url`.
1605
+ *
1606
+ * 2. `GetVippsStatus` query:
1607
+ * Queries Vipps payment state directly for a checkout (`state`).
1608
+ */
1609
+
1610
+ /**
1611
+ * GraphQL mutation to create a Vipps payment session.
1612
+ */
1613
+ declare const CREATE_PAYMENT_VIPPS_MUTATION = "\nmutation CreatePaymentVipps($checkoutId: String!, $email: String, $returnUrl: String!, $express: Boolean) {\n Payment {\n CreatePaymentVipps(checkout_id: $checkoutId, email: $email, return_url: $returnUrl, express: $express) {\n payment_url\n reference\n express\n reason\n }\n }\n}\n";
1614
+ /**
1615
+ * GraphQL query to fetch current Vipps payment status.
1616
+ */
1617
+ declare const GET_VIPPS_STATUS_QUERY = "\nquery GetVippsStatus($checkoutId: String!) {\n Payment {\n GetVippsStatus(checkout_id: $checkoutId) {\n state\n duplicate_of\n }\n }\n}\n";
1618
+ interface CreatePaymentVippsVariables extends Record<string, unknown> {
1619
+ checkoutId: string;
1620
+ /** Optional since Express: Vipps hands the email back with the payment. */
1621
+ email?: string;
1622
+ returnUrl: string;
1623
+ /**
1624
+ * `true` asks for Express — address and delivery chosen inside the Vipps
1625
+ * app. When the cart cannot have it, no payment is created and the answer
1626
+ * says `express: false` with the reason; the caller then opens the
1627
+ * ordinary checkout.
1628
+ */
1629
+ express?: boolean;
1630
+ }
1631
+ interface CreatePaymentVippsResponse {
1632
+ /** Absent when Express was asked for and refused. */
1633
+ payment_url?: string;
1634
+ /** The reference the seller reads in its Vipps portal. */
1635
+ reference?: string;
1636
+ express?: boolean;
1637
+ reason?: string;
1638
+ }
1639
+ interface GetVippsStatusVariables extends Record<string, unknown> {
1640
+ checkoutId: string;
1641
+ }
1642
+ interface VippsStatusResult {
1643
+ state: string;
1644
+ /** Set when this checkout was closed as a duplicate: the checkout that paid the cart. */
1645
+ duplicate_of?: string | null;
1646
+ }
1647
+ type VippsPaymentState = 'CREATED' | 'INITIATED' | 'AUTHORIZED' | 'TERMINATED' | 'EXPIRED' | string;
1648
+ /**
1649
+ * Executes the `CreatePaymentVipps` GraphQL mutation.
1650
+ */
1651
+ declare function createPaymentVipps(variables: CreatePaymentVippsVariables | Record<string, unknown>, options?: CartQueryOptions): Promise<CreatePaymentVippsResponse | null>;
1652
+ /**
1653
+ * Executes the `GetVippsStatus` GraphQL query.
1654
+ */
1655
+ declare function getVippsStatus(variables: GetVippsStatusVariables | Record<string, unknown>, options?: CartQueryOptions): Promise<VippsStatusResult | null>;
1656
+
1657
+ declare const CREATE_CART_MUTATION = "\nmutation CreateCart($customerSessionId: String!, $currency: String!, $shippingCountry: String) {\n Cart {\n CreateCart(customer_session_id: $customerSessionId, currency: $currency, shipping_country: $shippingCountry) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
1658
+ declare const ADD_ITEM_MUTATION = "\nmutation AddItem($cartId: String!, $lineItems: [LineItemInput!]!) {\n Cart {\n AddItem(cart_id: $cartId, line_items: $lineItems) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
1659
+ declare const DELETE_ITEM_MUTATION = "\nmutation DeleteItem($cartId: String!, $cartItemId: String!) {\n Cart {\n DeleteItem(cart_id: $cartId, cart_item_id: $cartItemId) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
1660
+ declare const UPDATE_ITEM_MUTATION: string;
1661
+ /** `UpdateItem` with the `origin` of the added units (`CartLineOriginInput`, snake_case fields — see `lineOriginWire`). */
1662
+ declare const UPDATE_ITEM_WITH_ORIGIN_MUTATION: string;
1663
+ declare const GET_CART_QUERY = "\nquery GetCart($cartId: String!) {\n Cart {\n GetCart(cart_id: $cartId) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
1664
+ declare const GET_LINE_ITEMS_BY_SUPPLIER_QUERY = "\nquery GetLineItemsBySupplier($cartId: String!) {\n Cart {\n GetLineItemsBySupplier(cart_id: $cartId) {\n supplier {\n id\n name\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n }\n }\n}\n";
1665
+ declare const UPDATE_SHIPPINGS_BY_SUPPLIER_MUTATION = "\nmutation UpdateShippingsBySupplier($cartId: String!, $data: [DataUpdateShippingsBySupplier!]!) {\n Cart {\n UpdateShippingsBySupplier(cart_id: $cartId, data: $data) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
1666
+ declare const CREATE_CHECKOUT_MUTATION: string;
1667
+ /** `CreateCheckout` with the checkout's `attribution` (`CheckoutAttributionInput`, snake_case fields — see `checkoutAttributionOf`). */
1668
+ declare const CREATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION: string;
1669
+ declare const UPDATE_CHECKOUT_MUTATION: string;
1670
+ /** `UpdateCheckout` with the checkout's `attribution` (`CheckoutAttributionInput`). */
1671
+ declare const UPDATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION: string;
1672
+ declare const GET_CHECKOUT_QUERY = "\nquery GetCheckout($checkoutId: String!) {\n Checkout {\n GetCheckout(checkout_id: $checkoutId) {\n buyer_accepts_purchase_conditions\n buyer_accepts_terms_conditions\n created_at\n updated_at\n id\n deleted_at\n success_url\n cancel_url\n payment_method\n email\n status\n checkout_url\n origin_payment_id\n duplicate_of\n billing_address {\n id\n first_name\n last_name\n phone_code\n phone\n company\n address1\n address2\n city\n province\n province_code\n country\n country_code\n zip\n }\n shipping_address {\n id\n first_name\n last_name\n phone_code\n phone\n company\n address1\n address2\n city\n province\n province_code\n country\n country_code\n zip\n }\n available_payment_methods {\n name\n }\n discount_code\n cart {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n totals {\n currency_code\n subtotal\n shipping\n total\n taxes\n tax_rate\n discounts\n }\n }\n }\n}\n";
1673
+ declare const GET_AVAILABLE_PAYMENT_METHODS_QUERY = "\nquery Config {\n Payment {\n GetAvailablePaymentMethods {\n config {\n name\n type\n value\n }\n name\n }\n }\n}\n";
1674
+
1675
+ /** Transport options for a cart/checkout GraphQL call. */
1676
+ interface CartQueryOptions {
1677
+ endpoint?: string;
1678
+ apiKey?: string;
1679
+ /** Sponsor commerce key — goes in the Authorization header. */
1680
+ commerceKey?: string;
1681
+ /** True when the commerce key came from a resolved sponsor (bootstrap).
1682
+ * False = we fell back to the host apiKey — writes like CreateCart should
1683
+ * NOT proceed with the wrong key (the cart would be orphaned). */
1684
+ sponsorResolved?: boolean;
1685
+ /** The commerce channel of the key (`commerce.channelId` of the block it came from), when known. */
1686
+ channelId?: string;
1687
+ /**
1688
+ * True when a channel was asked for (`ctx.channelId`) and the bootstrap no
1689
+ * longer lists it for the sponsor: the call must not go out with another
1690
+ * channel's key — a cart on that channel is rebuilt on the current one.
1691
+ */
1692
+ channelMissing?: boolean;
1693
+ }
1694
+ /** Which channel's key a cart / checkout call takes (see `getCartGraphQLOptions`). */
1695
+ interface CartKeyContext {
1696
+ /** The channel the cart (or checkout) lives on: only that channel's key. */
1697
+ channelId?: string | number | null;
1698
+ /** The campaign in context (candidates in precedence order); `null` = none at all, not even `Vio.init`'s. */
1699
+ campaignId?: number | string | null | ReadonlyArray<number | string | null | undefined>;
1700
+ /** A channel the bootstrap no longer lists still answers with the key this page saw for it (an open checkout). */
1701
+ retired?: boolean;
1702
+ }
1703
+ /**
1704
+ * Resolve endpoint + keys for cart GraphQL calls. Awaits Vio.bootstrap() once
1705
+ * if it hasn't run yet (the sponsor commerce keys come from bootstrap), then
1706
+ * uses the sponsor's commerce apiKey (via the Vio facade on globalThis,
1707
+ * avoiding an import cycle); falls back to the host apiKey.
1708
+ */
1709
+ declare function getCartGraphQLOptions(sponsorId?: number, ctx?: CartKeyContext): Promise<CartQueryOptions>;
1710
+ /**
1711
+ * Stable per-browser customer session id (backend CreateCart requires one).
1712
+ * Never throws: where storage is refused (in-app browsers) the id lives in
1713
+ * this page's memory — still one per shopper, never the shared
1714
+ * `cs_session_default` every storage-less browser used to send.
1715
+ */
1716
+ declare function getCustomerSessionId(): string;
1717
+ interface GraphQLEnvelope {
1718
+ data?: Record<string, Record<string, unknown>> | null;
1719
+ errors?: Array<{
1720
+ message?: string;
1721
+ path?: unknown;
1722
+ }>;
1723
+ }
1724
+ /** Execute a GraphQL query/mutation against the configured commerce endpoint.
1725
+ * Callers that skip `getCartGraphQLOptions()` (or pass a bare sponsorId) get
1726
+ * it resolved here instead of silently sending an unauthenticated request.
1727
+ * Rejects after `CART_GRAPHQL_TIMEOUT_MS` (and aborts the fetch). */
1728
+ declare function executeCartGraphQL(query: string, variables: Record<string, unknown>, options?: CartQueryOptions | number | undefined): Promise<GraphQLEnvelope>;
1729
+ declare function createCart(customerSessionId: string, currency: string, shippingCountry?: string | null, options?: CartQueryOptions): Promise<any>;
1730
+ /**
1731
+ * `AddItem`. A line may carry `origin` (`LineOriginWire`: where its units
1732
+ * come from — ADR-0035 phase B). A gateway that predates the field refuses
1733
+ * the whole mutation at validation (`LineItemInput` has no `origin`), so the
1734
+ * lines are sent again without it, once per page load — see gateway-features.
1735
+ */
1736
+ declare function addItem(cartId: string, lineItems: unknown[], options?: CartQueryOptions): Promise<any>;
1737
+ declare function deleteItem(cartId: string, cartItemId: string, options?: CartQueryOptions): Promise<any>;
1738
+ /**
1739
+ * `UpdateItem`. `extra.origin` is where the units a quantity INCREASE adds
1740
+ * come from (ADR-0035 phase B); the server credits the new units to it. Sent
1741
+ * only with it; a gateway that predates the argument gets the legacy
1742
+ * mutation instead, once per page load — see gateway-features.
1743
+ */
1744
+ declare function updateItem(cartId: string, cartItemId: string, shippingId?: string | null, qty?: number | null, options?: CartQueryOptions, extra?: {
1745
+ origin?: LineOriginWire;
1746
+ }): Promise<any>;
1747
+ declare function getCart(cartId: string, options?: CartQueryOptions): Promise<any>;
1748
+ declare function getLineItemsBySupplier(cartId: string, options?: CartQueryOptions): Promise<any>;
1749
+ declare function updateShippingsBySupplier(cartId: string, data: unknown[], options?: CartQueryOptions): Promise<any>;
1750
+ /**
1751
+ * `CreateCheckout`. With `extra.attribution` (`CheckoutAttributionWire`:
1752
+ * the surface, the page's campaign, the page and the entry — ADR-0035 phase
1753
+ * B) the checkout is born attributed; a gateway that predates the argument
1754
+ * gets the legacy mutation, once per page load — see gateway-features.
1755
+ */
1756
+ declare function createCheckout(cartId: string, options?: CartQueryOptions, extra?: {
1757
+ attribution?: CheckoutAttributionWire;
1758
+ }): Promise<any>;
1759
+ /**
1760
+ * `UpdateCheckout`. `variables.attribution` (`CheckoutAttributionWire`) is
1761
+ * merged key by key over what the checkout has; a gateway that predates the
1762
+ * argument gets the legacy mutation without it, once per page load.
1763
+ */
1764
+ declare function updateCheckout(variables: Record<string, unknown>, options?: CartQueryOptions): Promise<any>;
1765
+ declare function getCheckout(checkoutId: string, options?: CartQueryOptions): Promise<any>;
1766
+ /** What a checkout says of itself after paying: its Vio order number, once the order exists, and its buyer reference. */
1767
+ interface CheckoutReference {
1768
+ orderNumber: number | null;
1769
+ buyerRef: string | null;
1770
+ }
1771
+ /** The order number (null while the order does not exist yet) and the buyer reference (null when the API does not say it). */
1772
+ declare function getCheckoutReference(checkoutId: string, options?: CartQueryOptions): Promise<CheckoutReference>;
1773
+ declare function getAvailablePaymentMethods(options?: CartQueryOptions): Promise<any>;
1774
+ declare const CREATE_PAYMENT_STRIPE_MUTATION = "\nmutation CreatePaymentStripe($checkoutId: String!, $successUrl: String!, $paymentMethod: String!, $email: String!) {\n Payment {\n CreatePaymentStripe(checkout_id: $checkoutId, success_url: $successUrl, payment_method: $paymentMethod, email: $email) {\n order_id\n checkout_url\n }\n }\n}\n";
1775
+ declare function createPaymentStripe(variables: Record<string, unknown>, options?: CartQueryOptions): Promise<any>;
1776
+
1777
+ /**
1778
+ * CartManager — multi-sponsor cart state.
1779
+ *
1780
+ * Mirrors iOS's `CartManager` + `cartsBySponsor`. Holds local state in
1781
+ * memory and persists to localStorage. Reactive: dispatches a `change`
1782
+ * CustomEvent that UI components subscribe to (Web Components react via
1783
+ * `requestUpdate()`).
1784
+ *
1785
+ * The backend cart (Vio Commerce GraphQL CreateCart / AddItem / UpdateItem /
1786
+ * DeleteItem) is kept in sync optimistically from here; since 0.26 every add
1787
+ * and every increase tells it where the units come from (`origin`, ADR-0035
1788
+ * phase B) so the order is born attributed — see `origin-wire.ts`.
1789
+ */
1790
+
1791
+ interface CartChangeDetail {
1792
+ cartsBySponsor: Map<number, SponsorCartState>;
1793
+ itemCount: number;
1794
+ }
1795
+ /**
1796
+ * Detail of `vio:cart-updated` (on `document`): a sponsor's cart as it stands
1797
+ * after this tab learned of it from somewhere other than its own taps —
1798
+ * `source: 'server'`: GetCart, applied right before a checkout is built on it
1799
+ * (`refreshFromServer`); `source: 'storage'`: another tab of the same site
1800
+ * wrote it (an add there, a payment that cleared it). The lines are copies.
1801
+ */
1802
+ interface CartUpdatedDetail {
1803
+ sponsorId: number;
1804
+ cartId?: string;
1805
+ items: CartLineItem[];
1806
+ itemCount: number;
1807
+ subtotal: number;
1808
+ currency: string;
1809
+ source: 'server' | 'storage';
1810
+ }
1811
+ interface AddProductOptions {
1812
+ product: Product;
1813
+ sponsorId: number;
1814
+ sponsorName?: string;
1815
+ quantity?: number;
1816
+ variantId?: number;
1817
+ /** Where these units come from (`Vio.attribution(slot)`); see `CartOrigin`. */
1818
+ origin?: CartOrigin;
1819
+ }
1820
+ /** Minimal product shape — for callers who only have e.g. mock data, not a full Product. */
1821
+ interface AddManualOptions {
1822
+ productId: number;
1823
+ sponsorId: number;
1824
+ sponsorName?: string;
1825
+ brand: string;
1826
+ name: string;
1827
+ unitPrice: number;
1828
+ currency: string;
1829
+ imageUrl: string;
1830
+ quantity?: number;
1831
+ variantId?: number;
1832
+ /** Where these units come from (`Vio.attribution(slot)`); see `CartOrigin`. */
1833
+ origin?: CartOrigin;
1834
+ }
1835
+ declare class CartManager extends EventTarget {
1836
+ private cartsBySponsor;
1837
+ /** In-flight CreateCart per sponsor — two quick adds must share ONE backend
1838
+ * cart (two CreateCarts split the items and one silently disappears). */
1839
+ private cartIdPromises;
1840
+ /** Monotonic mutation counter per sponsor + last applied response, so a
1841
+ * slow response can't overwrite the state of a newer one. */
1842
+ private mutationSeq;
1843
+ private appliedSeq;
1844
+ /** In-flight AddItem/UpdateItem/DeleteItem per sponsor. Callers that need
1845
+ * the backend cart to reflect a just-made change (e.g. fetching shippings
1846
+ * right after an add) should `await waitForCartMutations(sponsorId)` first
1847
+ * — otherwise they can race the mutation and see the cart from before it
1848
+ * landed (Alan, 2026-08-18: shippings queried before AddItem settled,
1849
+ * came back empty). */
1850
+ private inFlightMutations;
1851
+ /** Per-line quantity sync with the backend: at most ONE UpdateItem /
1852
+ * DeleteItem in flight per line. Targets that arrive while one is in flight
1853
+ * are coalesced into `pending` (only the latest survives) and sent when the
1854
+ * current request settles. Keyed by `${sponsorId}:${cartItemId}`.
1855
+ * (Alan, 2026-10-15: a burst of +/− clicks fired one UpdateItem per click
1856
+ * in parallel; each response re-applied the whole backend cart, so an
1857
+ * older one landing after a newer optimistic change rolled the line back.) */
1858
+ private qtySyncs;
1859
+ /**
1860
+ * Bumped per sponsor each time its backend cart is dropped because its
1861
+ * channel went away: the lines as they stood then (`carryOver`) go to the
1862
+ * new backend cart, so an add whose local units were already counted in
1863
+ * them must not send its own AddItem as well (see `addManual`).
1864
+ */
1865
+ private rebuildEpoch;
1866
+ /** The lines to give the next backend cart of a sponsor, after its channel went away. */
1867
+ private carryOver;
1868
+ /** The storage key of this connection's carts. */
1869
+ private readonly storageKey;
1870
+ /**
1871
+ * Whether this is the page's connection now. A manager left behind by a
1872
+ * re-init (another key) still finishes its requests and keeps its own
1873
+ * carts, but says nothing to the page: no `vio:cart-*` events.
1874
+ */
1875
+ private active;
1876
+ constructor(scope?: string);
1877
+ /** The page's connection is (or is no longer) this one; see `active`. */
1878
+ setActive(active: boolean): void;
1879
+ /** Tell the listeners what this connection's carts hold now (after the page switched to it). */
1880
+ announce(): void;
1881
+ private nextSeq;
1882
+ /** Resolves once every in-flight AddItem/UpdateItem/DeleteItem for this
1883
+ * sponsor has settled (success or failure), including ones started while
1884
+ * waiting (a quantity intent replayed by an AddItem reconcile). No-op if
1885
+ * nothing is pending. */
1886
+ waitForCartMutations(sponsorId: number): Promise<void>;
1887
+ /**
1888
+ * True while an AddItem/UpdateItem/DeleteItem of this sponsor OTHER than
1889
+ * `except` has not settled. A mutation applying its own answer passes
1890
+ * itself: its response is current for what IT sent — only the others make
1891
+ * it stale.
1892
+ */
1893
+ private hasMutationsInFlight;
1894
+ /** Register a backend mutation so `waitForCartMutations` can await it. */
1895
+ private trackMutation;
1896
+ private qtySyncKey;
1897
+ /** The quantity a line is heading to (pending beats in flight), or
1898
+ * undefined when no quantity sync is active for it. */
1899
+ private intendedQuantity;
1900
+ /** Apply a backend response only if no newer response was applied already.
1901
+ * Returns false when it was discarded as stale. */
1902
+ private applyBackendCart;
1903
+ /** The final answer of a line's sync lost the per-sponsor seq race (another
1904
+ * line answered later): the cart as a whole is stale, but for THIS line it
1905
+ * is the latest word. Copy its quantity (and price) so a server-side clamp
1906
+ * — stock — doesn't leave the optimistic value behind for good, with the
1907
+ * checkout / Apple Pay total built on it. */
1908
+ private reconcileLineFromResponse;
1909
+ /** Surface a cart sync problem to hosts/UI (and the console). */
1910
+ private emitError;
1911
+ /**
1912
+ * The options of a sponsor's backend cart: the key of the channel it was
1913
+ * created on (`channelMissing` when the bootstrap no longer lists it). A
1914
+ * cart from before channels were remembered keeps the sponsor's first
1915
+ * block, as when it was created, and remembers that channel from now on.
1916
+ */
1917
+ private cartOptions;
1918
+ /**
1919
+ * The backend cart to call for a sponsor, with the key of its channel. When
1920
+ * the bootstrap no longer lists that channel the stale cart is dropped and a
1921
+ * new one is created on the sponsor's current channel with the same lines
1922
+ * (`dropStaleBackendCart` + `ensureCartId`) — never a call with a key of
1923
+ * another channel. `undefined` when there is no backend cart (or none could
1924
+ * be made).
1925
+ */
1926
+ liveCart(sponsorId: number): Promise<{
1927
+ cartId: string;
1928
+ opts: CartQueryOptions;
1929
+ } | undefined>;
1930
+ /**
1931
+ * The channel of a sponsor's cart is gone from the bootstrap (the campaign
1932
+ * moved, a refresh after hours): forget the backend cart and its line ids,
1933
+ * keep the lines, and remember them as they stand now for the next backend
1934
+ * cart (`carryOver`). Queued quantity syncs of the old cart are dropped —
1935
+ * their quantities are in the lines carried.
1936
+ */
1937
+ private dropStaleBackendCart;
1938
+ /** Give a new backend cart the lines of the one whose channel went away — each unit with its own origin. */
1939
+ private replayCarriedLines;
1940
+ /**
1941
+ * Ensure the sponsor cart exists server-side; returns its backend cart id.
1942
+ * A new backend cart is created on the channel of the campaign in context —
1943
+ * `ctx.campaignId` (the add's origin), else the campaign the cart's lines
1944
+ * came from, else `Vio.init`'s — and remembers it (`channelId`). An existing
1945
+ * one whose channel the bootstrap no longer lists is created again on the
1946
+ * current channel, with its lines (`liveCart`).
1947
+ */
1948
+ ensureCartId(sponsorId: number, currency?: string, shippingCountry?: string, ctx?: Pick<CartKeyContext, 'campaignId'>): Promise<string | undefined>;
1949
+ /**
1950
+ * Overwrite local cart state with the backend cart response (source of
1951
+ * truth). `opts.settling` is the mutation whose answer this is: it does not
1952
+ * count as "in flight" for the origins (see `hasMutationsInFlight`).
1953
+ * `opts.authoritative` is a GetCart taken with nothing of this tab's in
1954
+ * flight (`refreshFromServer`): an empty answer then means the cart IS
1955
+ * empty, and the local lines go — not an add still on its way.
1956
+ */
1957
+ updateFromBackendCart(sponsorId: number, backendCart: {
1958
+ cart_id?: string;
1959
+ currency?: string;
1960
+ shipping_country?: string;
1961
+ subtotal?: number;
1962
+ shipping?: number;
1963
+ available_shipping_countries?: string[];
1964
+ line_items?: Array<{
1965
+ id: string;
1966
+ product_id: number;
1967
+ variant_id?: number | string | null;
1968
+ variant_title?: string | null;
1969
+ brand?: string | null;
1970
+ title?: string | null;
1971
+ quantity: number;
1972
+ image?: string | {
1973
+ url?: string;
1974
+ } | null;
1975
+ imageUrl?: string | null;
1976
+ image_url?: string | null;
1977
+ price?: {
1978
+ amount?: number;
1979
+ amount_incl_taxes?: number | null;
1980
+ currency_code?: string;
1981
+ } | null;
1982
+ shipping?: unknown;
1983
+ available_shippings?: unknown[];
1984
+ }>;
1985
+ }, opts?: {
1986
+ settling?: Promise<unknown>;
1987
+ authoritative?: boolean;
1988
+ }): void;
1989
+ /** Add a Product DTO to a sponsor's cart. Bumps quantity if already present.
1990
+ * When a variantId is given, the line uses the VARIANT's price / image / title
1991
+ * (not the product base), so different combinations are priced correctly. */
1992
+ addProduct(opts: AddProductOptions): CartLineItem;
1993
+ /** Add a manually-specified line item (no Product DTO). */
1994
+ addManual(opts: AddManualOptions): CartLineItem;
1995
+ /** Quantity intents for lines whose backend id hasn't arrived yet — replayed
1996
+ * when the AddItem response reconciles (keyed by product::variant). */
1997
+ private pendingQtyIntents;
1998
+ private intentKey;
1999
+ private findLine;
2000
+ /** Change a line's quantity by `delta`, computed on the manager's CURRENT
2001
+ * quantity — not on whatever a UI rendered a moment ago. A burst of +/−
2002
+ * clicks before a re-render therefore asks for 2, 3, 4… and not for the
2003
+ * same target several times. Reaching 0 removes the line. */
2004
+ adjustQuantity(lineItemId: string, sponsorId: number, delta: number, opts?: {
2005
+ origin?: CartOrigin;
2006
+ }): void;
2007
+ /** Set a line's quantity (0 or less removes it). Optimistic: the local
2008
+ * state and `change` update at once; the backend is synced through
2009
+ * `syncQuantity`, one request in flight per line, latest target wins. */
2010
+ updateQuantity(lineItemId: string, sponsorId: number, quantity: number, opts?: {
2011
+ origin?: CartOrigin;
2012
+ }): void;
2013
+ /** Send a line's target quantity to the backend — ONE request in flight per
2014
+ * line. Targets that arrive while one is in flight queue behind it as
2015
+ * steps (`queueStep`): reduced like the line's origins, sent in order once
2016
+ * the current request settles — one request per queued increase from a
2017
+ * different origin, one for a net decrease — so the server ends on the
2018
+ * last intent, credits every increase to its own origin, and never sees two
2019
+ * updates racing each other. While the sync is active the line keeps its
2020
+ * optimistic quantity through any backend response (see
2021
+ * `updateFromBackendCart`); a rejection drops what was queued and
2022
+ * reconciles the cart from the server. */
2023
+ private syncQuantity;
2024
+ removeItem(lineItemId: string, sponsorId: number): void;
2025
+ clearSponsorCart(sponsorId: number): void;
2026
+ clearAllCarts(): void;
2027
+ /** Refresh the local cart from the backend (source of truth). */
2028
+ fetchCartFromBackend(sponsorId: number): Promise<unknown>;
2029
+ /**
2030
+ * The cart as the server has it, for the moment a checkout is about to be
2031
+ * built on it: what the shopper is about to pay must be what the page shows.
2032
+ * Waits for this tab's own mutations (their answers are the server's too),
2033
+ * then applies GetCart as it is — a line another tab added, one it removed,
2034
+ * an empty cart — and tells the page: `change` for the drawer, and
2035
+ * `vio:cart-updated` on `document` (`source: 'server'`) for a host that
2036
+ * draws its own. A mutation that starts while the server is answering makes
2037
+ * that answer old: it is asked once more. Nothing to ask without a backend
2038
+ * cart. A GetCart that fails leaves the local state as it was and does not
2039
+ * throw — the checkout then goes on with the lines the last mutation
2040
+ * answered, as it always did. Resolves with the sponsor's cart.
1731
2041
  */
1732
- privacyMode?: SurfacePrivacyMode | 'unknown';
1733
- }
1734
- /**
1735
- * The attribution for the wire, or `undefined` when there is nothing to say.
1736
- * The campaign is the page's; without one, the campaign that explains most
1737
- * units of the cart under the same rule `purchase` is split by (ties: the
1738
- * higher value, then the first). The page (origin + path) and the entry go
1739
- * only on a `standard` surface.
1740
- */
1741
- declare function checkoutAttributionOf(input: CheckoutAttributionInput): CheckoutAttributionWire | undefined;
1742
- /** The landing as `entry`, capped; `undefined` when it says nothing. */
1743
- declare function entryContextOf(landing: Landing | null | undefined): EntryContextWire | undefined;
1744
- /**
1745
- * The campaign that explains most units of the cart — over the slices
1746
- * `purchase` is split by, so the order names the campaign the biggest
1747
- * purchase event names. Ties go to the higher value, then to the first
1748
- * slice. Units nobody attributes (a slice without campaign) never win.
1749
- */
1750
- declare function dominantCampaignOf(slices: ReadonlyArray<CartSlice> | null | undefined): number | undefined;
1751
-
1752
- /**
1753
- * Vipps MobilePay Payment Adapter — GraphQL Integration & Types.
1754
- *
1755
- * Vipps payment integration uses 2 GraphQL operations:
1756
- *
1757
- * 1. `CreatePaymentVipps` mutation:
1758
- * Initiates a Vipps payment session for a checkout and returns `payment_url`.
1759
- *
1760
- * 2. `GetVippsStatus` query:
1761
- * Queries Vipps payment state directly for a checkout (`state`).
1762
- */
1763
-
1764
- /**
1765
- * GraphQL mutation to create a Vipps payment session.
1766
- */
1767
- declare const CREATE_PAYMENT_VIPPS_MUTATION = "\nmutation CreatePaymentVipps($checkoutId: String!, $email: String, $returnUrl: String!, $express: Boolean) {\n Payment {\n CreatePaymentVipps(checkout_id: $checkoutId, email: $email, return_url: $returnUrl, express: $express) {\n payment_url\n reference\n express\n reason\n }\n }\n}\n";
1768
- /**
1769
- * GraphQL query to fetch current Vipps payment status.
1770
- */
1771
- declare const GET_VIPPS_STATUS_QUERY = "\nquery GetVippsStatus($checkoutId: String!) {\n Payment {\n GetVippsStatus(checkout_id: $checkoutId) {\n state\n duplicate_of\n }\n }\n}\n";
1772
- interface CreatePaymentVippsVariables extends Record<string, unknown> {
1773
- checkoutId: string;
1774
- /** Optional since Express: Vipps hands the email back with the payment. */
1775
- email?: string;
1776
- returnUrl: string;
2042
+ refreshFromServer(sponsorId: number): Promise<SponsorCartState | undefined>;
2043
+ /** `vio:cart-updated` on `document` — see `CartUpdatedDetail`. */
2044
+ private emitCartUpdated;
1777
2045
  /**
1778
- * `true` asks for Express — address and delivery chosen inside the Vipps
1779
- * app. When the cart cannot have it, no payment is created and the answer
1780
- * says `express: false` with the reason; the caller then opens the
1781
- * ordinary checkout.
2046
+ * Another tab of the site wrote the carts: adopt what it wrote, sponsor by
2047
+ * sponsor — its lines and its backend cart id, or nothing when it cleared
2048
+ * the cart (a payment) — except for a sponsor this tab is mid-write for:
2049
+ * its own answer lands in a moment and is persisted then, over whatever
2050
+ * the other tab had. `key` is null when the other tab cleared the whole
2051
+ * storage. Says `change` (the drawer) and `vio:cart-updated` per sponsor
2052
+ * that changed (`source: 'storage'`); nothing when nothing did.
1782
2053
  */
1783
- express?: boolean;
1784
- }
1785
- interface CreatePaymentVippsResponse {
1786
- /** Absent when Express was asked for and refused. */
1787
- payment_url?: string;
1788
- /** The reference the seller reads in its Vipps portal. */
1789
- reference?: string;
1790
- express?: boolean;
1791
- reason?: string;
1792
- }
1793
- interface GetVippsStatusVariables extends Record<string, unknown> {
1794
- checkoutId: string;
1795
- }
1796
- interface VippsStatusResult {
1797
- state: string;
1798
- /** Set when this checkout was closed as a duplicate: the checkout that paid the cart. */
1799
- duplicate_of?: string | null;
1800
- }
1801
- type VippsPaymentState = 'CREATED' | 'INITIATED' | 'AUTHORIZED' | 'TERMINATED' | 'EXPIRED' | string;
1802
- /**
1803
- * Executes the `CreatePaymentVipps` GraphQL mutation.
1804
- */
1805
- declare function createPaymentVipps(variables: CreatePaymentVippsVariables | Record<string, unknown>, options?: CartQueryOptions): Promise<CreatePaymentVippsResponse | null>;
1806
- /**
1807
- * Executes the `GetVippsStatus` GraphQL query.
1808
- */
1809
- declare function getVippsStatus(variables: GetVippsStatusVariables | Record<string, unknown>, options?: CartQueryOptions): Promise<VippsStatusResult | null>;
1810
-
1811
- declare const CREATE_CART_MUTATION = "\nmutation CreateCart($customerSessionId: String!, $currency: String!, $shippingCountry: String) {\n Cart {\n CreateCart(customer_session_id: $customerSessionId, currency: $currency, shipping_country: $shippingCountry) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
1812
- declare const ADD_ITEM_MUTATION = "\nmutation AddItem($cartId: String!, $lineItems: [LineItemInput!]!) {\n Cart {\n AddItem(cart_id: $cartId, line_items: $lineItems) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
1813
- declare const DELETE_ITEM_MUTATION = "\nmutation DeleteItem($cartId: String!, $cartItemId: String!) {\n Cart {\n DeleteItem(cart_id: $cartId, cart_item_id: $cartItemId) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
1814
- declare const UPDATE_ITEM_MUTATION: string;
1815
- /** `UpdateItem` with the `origin` of the added units (`CartLineOriginInput`, snake_case fields — see `lineOriginWire`). */
1816
- declare const UPDATE_ITEM_WITH_ORIGIN_MUTATION: string;
1817
- declare const GET_CART_QUERY = "\nquery GetCart($cartId: String!) {\n Cart {\n GetCart(cart_id: $cartId) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
1818
- declare const GET_LINE_ITEMS_BY_SUPPLIER_QUERY = "\nquery GetLineItemsBySupplier($cartId: String!) {\n Cart {\n GetLineItemsBySupplier(cart_id: $cartId) {\n supplier {\n id\n name\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n }\n }\n}\n";
1819
- declare const UPDATE_SHIPPINGS_BY_SUPPLIER_MUTATION = "\nmutation UpdateShippingsBySupplier($cartId: String!, $data: [DataUpdateShippingsBySupplier!]!) {\n Cart {\n UpdateShippingsBySupplier(cart_id: $cartId, data: $data) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
1820
- declare const CREATE_CHECKOUT_MUTATION: string;
1821
- /** `CreateCheckout` with the checkout's `attribution` (`CheckoutAttributionInput`, snake_case fields — see `checkoutAttributionOf`). */
1822
- declare const CREATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION: string;
1823
- declare const UPDATE_CHECKOUT_MUTATION: string;
1824
- /** `UpdateCheckout` with the checkout's `attribution` (`CheckoutAttributionInput`). */
1825
- declare const UPDATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION: string;
1826
- declare const GET_CHECKOUT_QUERY = "\nquery GetCheckout($checkoutId: String!) {\n Checkout {\n GetCheckout(checkout_id: $checkoutId) {\n buyer_accepts_purchase_conditions\n buyer_accepts_terms_conditions\n created_at\n updated_at\n id\n deleted_at\n success_url\n cancel_url\n payment_method\n email\n status\n checkout_url\n origin_payment_id\n duplicate_of\n billing_address {\n id\n first_name\n last_name\n phone_code\n phone\n company\n address1\n address2\n city\n province\n province_code\n country\n country_code\n zip\n }\n shipping_address {\n id\n first_name\n last_name\n phone_code\n phone\n company\n address1\n address2\n city\n province\n province_code\n country\n country_code\n zip\n }\n available_payment_methods {\n name\n }\n discount_code\n cart {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n totals {\n currency_code\n subtotal\n shipping\n total\n taxes\n tax_rate\n discounts\n }\n }\n }\n}\n";
1827
- declare const GET_AVAILABLE_PAYMENT_METHODS_QUERY = "\nquery Config {\n Payment {\n GetAvailablePaymentMethods {\n config {\n name\n type\n value\n }\n name\n }\n }\n}\n";
1828
-
1829
- /** Transport options for a cart/checkout GraphQL call. */
1830
- interface CartQueryOptions {
1831
- endpoint?: string;
1832
- apiKey?: string;
1833
- /** Sponsor commerce key — goes in the Authorization header. */
1834
- commerceKey?: string;
1835
- /** True when the commerce key came from a resolved sponsor (bootstrap).
1836
- * False = we fell back to the host apiKey — writes like CreateCart should
1837
- * NOT proceed with the wrong key (the cart would be orphaned). */
1838
- sponsorResolved?: boolean;
1839
- }
1840
- /**
1841
- * Resolve endpoint + keys for cart GraphQL calls. Awaits Vio.bootstrap() once
1842
- * if it hasn't run yet (the sponsor commerce keys come from bootstrap), then
1843
- * uses the sponsor's commerce apiKey (via the Vio facade on globalThis,
1844
- * avoiding an import cycle); falls back to the host apiKey.
1845
- */
1846
- declare function getCartGraphQLOptions(sponsorId?: number): Promise<CartQueryOptions>;
1847
- /** Stable per-browser customer session id (backend CreateCart requires one). */
1848
- declare function getCustomerSessionId(): string;
1849
- interface GraphQLEnvelope {
1850
- data?: Record<string, Record<string, unknown>> | null;
1851
- errors?: Array<{
1852
- message?: string;
1853
- path?: unknown;
1854
- }>;
2054
+ private onStorage;
2055
+ /** Line items grouped by supplier (shipping is per-supplier server-side). */
2056
+ fetchLineItemsBySupplier(sponsorId: number): Promise<unknown>;
2057
+ /** Set the chosen shipping option per supplier on the backend cart. */
2058
+ updateShippingsBySupplier(sponsorId: number, data: Array<{
2059
+ shipping_id: string;
2060
+ supplier_id: number;
2061
+ }>): Promise<unknown>;
2062
+ getAllCarts(): Map<number, SponsorCartState>;
2063
+ getCart(sponsorId: number): SponsorCartState | undefined;
2064
+ get itemCount(): number;
2065
+ subtotalForSponsor(sponsorId: number): number;
2066
+ get totalAcrossSponsors(): number;
2067
+ get primaryCurrency(): string;
2068
+ formatTotal(): string;
2069
+ /**
2070
+ * Keep the carts for the next page and the other tabs. Where storage
2071
+ * refuses (in-app browsers, private modes) nothing throws (safe-storage.ts):
2072
+ * the carts stay in this manager's own map, the add to cart and the
2073
+ * checkout go on, and the cart just does not survive a reload there.
2074
+ */
2075
+ private persist;
2076
+ private loadFromStorage;
2077
+ private emit;
1855
2078
  }
1856
- /** Execute a GraphQL query/mutation against the configured commerce endpoint.
1857
- * Callers that skip `getCartGraphQLOptions()` (or pass a bare sponsorId) get
1858
- * it resolved here instead of silently sending an unauthenticated request.
1859
- * Rejects after `CART_GRAPHQL_TIMEOUT_MS` (and aborts the fetch). */
1860
- declare function executeCartGraphQL(query: string, variables: Record<string, unknown>, options?: CartQueryOptions | number | undefined): Promise<GraphQLEnvelope>;
1861
- declare function createCart(customerSessionId: string, currency: string, shippingCountry?: string | null, options?: CartQueryOptions): Promise<any>;
1862
- /**
1863
- * `AddItem`. A line may carry `origin` (`LineOriginWire`: where its units
1864
- * come from — ADR-0035 phase B). A gateway that predates the field refuses
1865
- * the whole mutation at validation (`LineItemInput` has no `origin`), so the
1866
- * lines are sent again without it, once per page load — see gateway-features.
1867
- */
1868
- declare function addItem(cartId: string, lineItems: unknown[], options?: CartQueryOptions): Promise<any>;
1869
- declare function deleteItem(cartId: string, cartItemId: string, options?: CartQueryOptions): Promise<any>;
1870
- /**
1871
- * `UpdateItem`. `extra.origin` is where the units a quantity INCREASE adds
1872
- * come from (ADR-0035 phase B); the server credits the new units to it. Sent
1873
- * only with it; a gateway that predates the argument gets the legacy
1874
- * mutation instead, once per page load — see gateway-features.
1875
- */
1876
- declare function updateItem(cartId: string, cartItemId: string, shippingId?: string | null, qty?: number | null, options?: CartQueryOptions, extra?: {
1877
- origin?: LineOriginWire;
1878
- }): Promise<any>;
1879
- declare function getCart(cartId: string, options?: CartQueryOptions): Promise<any>;
1880
- declare function getLineItemsBySupplier(cartId: string, options?: CartQueryOptions): Promise<any>;
1881
- declare function updateShippingsBySupplier(cartId: string, data: unknown[], options?: CartQueryOptions): Promise<any>;
1882
2079
  /**
1883
- * `CreateCheckout`. With `extra.attribution` (`CheckoutAttributionWire`:
1884
- * the surface, the page's campaign, the page and the entry — ADR-0035 phase
1885
- * B) the checkout is born attributed; a gateway that predates the argument
1886
- * gets the legacy mutation, once per page load — see gateway-features.
2080
+ * Only the attribution fields, trimmed; `{}` when nothing is known. The kind
2081
+ * of element is kept as Commerce and the collector name it (`card`,
2082
+ * `carousel`, `detail` — `componentKindOf`), from `componentKind` or from
2083
+ * the `componentTemplateId` an element's attribution carries (`product-card`);
2084
+ * the page as origin + path (`contentUrl`) and its title, within Commerce's caps.
1887
2085
  */
1888
- declare function createCheckout(cartId: string, options?: CartQueryOptions, extra?: {
1889
- attribution?: CheckoutAttributionWire;
1890
- }): Promise<any>;
2086
+ declare function normalizeOrigin(origin: CartOrigin | null | undefined): CartOrigin;
2087
+ /** Two origins are the same place when campaign, slot, content and kind of element all match (the page's URL and title are attributes of the place, not its identity). */
2088
+ declare function sameOrigin(a: CartOrigin, b: CartOrigin): boolean;
1891
2089
  /**
1892
- * `UpdateCheckout`. `variables.attribution` (`CheckoutAttributionWire`) is
1893
- * merged key by key over what the checkout has; a gateway that predates the
1894
- * argument gets the legacy mutation without it, once per page load.
2090
+ * The origins of a line for reporting: what it carries, plus an empty origin
2091
+ * for any units it does not account for (a cart persisted before origins
2092
+ * existed, a server-side bump). Their quantities add up to the line's.
1895
2093
  */
1896
- declare function updateCheckout(variables: Record<string, unknown>, options?: CartQueryOptions): Promise<any>;
1897
- declare function getCheckout(checkoutId: string, options?: CartQueryOptions): Promise<any>;
1898
- /** What a checkout says of itself after paying: its Vio order number, once the order exists, and its buyer reference. */
1899
- interface CheckoutReference {
1900
- orderNumber: number | null;
1901
- buyerRef: string | null;
1902
- }
1903
- /** The order number (null while the order does not exist yet) and the buyer reference (null when the API does not say it). */
1904
- declare function getCheckoutReference(checkoutId: string, options?: CartQueryOptions): Promise<CheckoutReference>;
1905
- declare function getAvailablePaymentMethods(options?: CartQueryOptions): Promise<any>;
1906
- declare const CREATE_PAYMENT_STRIPE_MUTATION = "\nmutation CreatePaymentStripe($checkoutId: String!, $successUrl: String!, $paymentMethod: String!, $email: String!) {\n Payment {\n CreatePaymentStripe(checkout_id: $checkoutId, success_url: $successUrl, payment_method: $paymentMethod, email: $email) {\n order_id\n checkout_url\n }\n }\n}\n";
1907
- declare function createPaymentStripe(variables: Record<string, unknown>, options?: CartQueryOptions): Promise<any>;
2094
+ declare function lineOrigins(line: Pick<CartLineItem, 'origins' | 'quantity'>): CartLineOrigin[];
1908
2095
 
1909
2096
  /**
1910
2097
  * Stripe on our own page — the Payment Element, no redirect.
@@ -2493,6 +2680,8 @@ interface CheckoutAddress {
2493
2680
  postalCode: string;
2494
2681
  city: string;
2495
2682
  country?: string;
2683
+ /** Mobile number (Norwegian, 8 digits, optional +47) — sent as `phone` + `phone_code`. */
2684
+ phone?: string;
2496
2685
  }
2497
2686
  interface CheckoutState {
2498
2687
  /** Sponsor id whose cart is being checked out. */
@@ -2509,6 +2698,8 @@ interface CheckoutState {
2509
2698
  currency: string;
2510
2699
  /** Backend checkout id (Vio Commerce CreateCheckout). */
2511
2700
  checkoutId?: string;
2701
+ /** The commerce channel the checkout lives on (its cart's): every call for it uses that channel's key. */
2702
+ channelId?: string;
2512
2703
  /** Full backend checkout payload (untyped upstream). */
2513
2704
  checkout?: unknown;
2514
2705
  /** Klarna Payments session id (native GraphQL flow). */
@@ -2637,6 +2828,17 @@ declare class CheckoutManager extends EventTarget {
2637
2828
  */
2638
2829
  private get state();
2639
2830
  private set state(value);
2831
+ /**
2832
+ * The options of a call for a sponsor's cart or checkout: the key of the
2833
+ * channel the checkout lives on — what this tab remembered for the
2834
+ * checkout (a return from a redirect, after the cart was cleared), the open
2835
+ * checkout's, else the cart's — even if a bootstrap refresh no longer lists
2836
+ * it (an open checkout keeps paying with its own key). Without any, the
2837
+ * sponsor's block as `getCartGraphQLOptions` resolves it.
2838
+ */
2839
+ private gqlOptions;
2840
+ /** See `gqlOptions`. */
2841
+ private channelOf;
2640
2842
  /** The last checkout + identity written to the memory — the state is set on every keystroke of the form. */
2641
2843
  private lastRememberedSponsor;
2642
2844
  /** Backend checkouts this page load announced with `vio:checkout-created`: one event each. */
@@ -2709,6 +2911,13 @@ declare class CheckoutManager extends EventTarget {
2709
2911
  * page load; never throws.
2710
2912
  */
2711
2913
  private announceCheckout;
2914
+ /**
2915
+ * Nothing is created or paid for a cart that is empty or totals 0 — as
2916
+ * the SERVER has it (the callers read it from the server first). Throws,
2917
+ * so a payment button ends in its error path, never at a provider asking
2918
+ * for 0 kr.
2919
+ */
2920
+ private assertPayableCart;
2712
2921
  /** Update the backend checkout (terms are re-asserted unless overridden; the attribution rides along unless the caller gives its own). */
2713
2922
  updateCheckout(variables: Record<string, unknown>, sponsorId?: number): Promise<any>;
2714
2923
  getCheckout(checkoutId: string, sponsorId?: number): Promise<any>;
@@ -2800,6 +3009,11 @@ declare class CheckoutManager extends EventTarget {
2800
3009
  * so the caller can open the ordinary checkout instead. Without the flag
2801
3010
  * the backend decides: Express while the cart has no delivery yet, a
2802
3011
  * plain payment once the shopper chose one in our form.
3012
+ *
3013
+ * `express: false` is the checkout's standard path (2026-10-28): the
3014
+ * form's address — name, street, mobile — goes on the checkout before the
3015
+ * payment is created, and the delivery already chosen on the cart is what
3016
+ * Vipps charges for.
2803
3017
  */
2804
3018
  startVippsPayment(sponsorId?: number, formData?: unknown, options?: {
2805
3019
  express?: boolean;
@@ -3179,9 +3393,23 @@ declare function resolveContent(init?: ContentInit | null, doc?: Document | null
3179
3393
  type PrivacyAnswer = SurfacePrivacyMode | 'unknown';
3180
3394
  declare class VioFacade {
3181
3395
  private apiInstance;
3396
+ /** Commerce clients by sponsor AND key: one sponsor may sell on several channels (one per campaign). */
3182
3397
  private commerceClients;
3183
3398
  private bootstrapPromise;
3184
3399
  private cachedBootstrap;
3400
+ /** When the cached bootstrap arrived (ms epoch). */
3401
+ private bootstrapAt;
3402
+ /** A refresh of the bootstrap in flight (`refreshStaleBootstrap`). */
3403
+ private bootstrapRefresh;
3404
+ private bootstrapRefreshFailedAt;
3405
+ /** The `visibilitychange` listener is installed once per page. */
3406
+ private visibilityHooked;
3407
+ /**
3408
+ * Every selling block this page has seen, by `sponsorId:channelId` — so a
3409
+ * checkout opened on a channel keeps its key after a bootstrap refresh no
3410
+ * longer lists that channel (`sponsorCommerce(…, { retired: true })`).
3411
+ */
3412
+ private seenChannels;
3185
3413
  /** Last bootstrap failure — short backoff so cart mutations don't hammer a
3186
3414
  * dead endpoint on every call. */
3187
3415
  private bootstrapFailedAt;
@@ -3203,7 +3431,17 @@ declare class VioFacade {
3203
3431
  /** Each cap warns once per page load. */
3204
3432
  private warnedLocationCap;
3205
3433
  private warnedDeclarationCap;
3206
- private cartManager;
3434
+ /**
3435
+ * One cart manager per connection (environment + key), each with its own
3436
+ * storage entry; `Vio.cart` is a stable front for the current one, so a
3437
+ * re-init with another key switches carts without the page re-subscribing.
3438
+ * A manager left behind keeps its carts (they come back if the page switches
3439
+ * back) and finishes its requests into ITS carts, never the new one's.
3440
+ */
3441
+ private cartManagers;
3442
+ private cartScope;
3443
+ private cartFront;
3444
+ private readonly cartEvents;
3207
3445
  private checkoutManager;
3208
3446
  private analyticsManager;
3209
3447
  /** What the surface answered of its privacy mode (`GET /v2/mobile/surface`) and when; `unknown` expires after a minute. */
@@ -3225,6 +3463,15 @@ declare class VioFacade {
3225
3463
  get config(): ResolvedConfig;
3226
3464
  /** Multi-sponsor cart manager. Reactive — listen via addEventListener('change', ...). */
3227
3465
  get cart(): CartManager;
3466
+ /** The cart manager of the page's connection now (created on first use). */
3467
+ private currentCartManager;
3468
+ /**
3469
+ * `Vio.cart`: every property and method is the current connection's
3470
+ * manager's; the listeners live on the front, so they survive a switch.
3471
+ */
3472
+ private makeCartFront;
3473
+ /** After `init`: the carts are the new connection's. Says `change` when that switched them. */
3474
+ private switchCartScope;
3228
3475
  /** Checkout flow manager. Subscribes to cart state via the CartManager; asks here for the order's attribution. */
3229
3476
  get checkout(): CheckoutManager;
3230
3477
  /**
@@ -3245,6 +3492,20 @@ declare class VioFacade {
3245
3492
  */
3246
3493
  bootstrap(): Promise<BootstrapResponse>;
3247
3494
  get bootstrapCache(): BootstrapResponse | null;
3495
+ /** A bootstrap becomes the page's: when it arrived, the channels it lists, and the tab-visible refresh. */
3496
+ private adoptBootstrap;
3497
+ /**
3498
+ * The bootstrap is cached for the page's life, but a tab can stay open for
3499
+ * days: when it becomes visible again and the cached one is older than
3500
+ * five minutes, it is fetched again (new campaigns, channels). The old one
3501
+ * stays until the new one arrives — and stays if the refresh fails. Carts
3502
+ * keep their lines; a cart whose channel the new bootstrap no longer lists
3503
+ * is moved to the current channel the next time it is used (CartManager),
3504
+ * and an open checkout keeps paying with the key of its own channel.
3505
+ */
3506
+ private hookVisibility;
3507
+ /** Fetch the bootstrap again when the cached one is older than `maxAgeMs`; never throws, never clears the cache. */
3508
+ private refreshStaleBootstrap;
3248
3509
  /**
3249
3510
  * Who a sponsor is to a shopper — `{ id, name, logoUrl, avatarUrl }` — by
3250
3511
  * the ONE rule every element uses (`sponsorIdentityFrom`): the live
@@ -3262,10 +3523,32 @@ declare class VioFacade {
3262
3523
  checkoutId?: string | null;
3263
3524
  }): SponsorIdentity | null;
3264
3525
  /**
3265
- * Get a CommerceClient scoped to a specific sponsor (via bootstrap).
3266
- * Throws if bootstrap hasn't been called or the sponsor is unknown.
3267
- */
3268
- commerceFor(sponsorId: number): CommerceClient;
3526
+ * The block a sponsor sells with — its `commerce.apiKey` and `channelId` —
3527
+ * by the rule one article = one campaign = one channel = one sponsor (see
3528
+ * `sponsorCommerceIn`): `ctx.channelId` → that channel's block only (a cart
3529
+ * created on a channel is only called with its key); else the campaign in
3530
+ * context — `ctx.campaignId` candidates (the click's, the element's
3531
+ * `vio-campaign`, an ancestor's `data-vio-campaign`), then
3532
+ * `Vio.init({ campaignId })` — when the sponsor takes part in it; else the
3533
+ * sponsor's first block that sells (the behaviour before). `campaignId:
3534
+ * null` means no campaign at all, not even `Vio.init`'s. `retired: true`
3535
+ * also answers a channel the current bootstrap no longer lists with the
3536
+ * block this page saw for it (an open checkout after a bootstrap refresh).
3537
+ * Blocks with `commerce: null` are skipped. `null` when none; never throws.
3538
+ */
3539
+ sponsorCommerce(sponsorId: number | string | null | undefined, ctx?: SponsorCommerceContext & {
3540
+ retired?: boolean;
3541
+ }): SellingSponsor | null;
3542
+ /**
3543
+ * Get a CommerceClient scoped to a sponsor (via bootstrap) — on the
3544
+ * channel of the campaign in context (`ctx.campaignId`, the element's
3545
+ * candidates first; see `sponsorCommerce`) or of `ctx.channelId`. Without
3546
+ * `ctx`, the page's campaign (`Vio.init`) when the sponsor takes part in
3547
+ * it, else the sponsor's first selling block, as before. Clients are kept
3548
+ * per sponsor and key. Throws if bootstrap hasn't been called or nothing of
3549
+ * the sponsor sells there.
3550
+ */
3551
+ commerceFor(sponsorId: number, ctx?: SponsorCommerceContext): CommerceClient;
3269
3552
  /** Get a CommerceClient using an explicit commerce apiKey (skip bootstrap). */
3270
3553
  commerceWithKey(commerceApiKey: string): CommerceClient;
3271
3554
  /**
@@ -3375,9 +3658,10 @@ declare class VioFacade {
3375
3658
  * The attribution of the order a sponsor's cart is about to become
3376
3659
  * (ADR-0035 phase B) — what `CreateCheckout` / `UpdateCheckout` send as
3377
3660
  * `attribution` and shopcart writes on the order: the surface (its SDK
3378
- * key), the page's campaign (`pageCampaign()`; without one, the campaign
3379
- * that explains most units of the cart under the same rule `purchase` is
3380
- * split by — `cartSlices`) and, on a surface KNOWN to be `standard`
3661
+ * key), the campaign of the order — always one the cart's sponsor takes part
3662
+ * in (`orderCampaign`: the cart lines' own campaign, else the page's;
3663
+ * without one, the campaign that explains most units of the cart under the
3664
+ * same rule `purchase` is split by — `cartSlices`) and, on a surface KNOWN to be `standard`
3381
3665
  * (`privacyModeNow`), the page (`content()`'s url as origin + path, and
3382
3666
  * title) and where the session came in: the landing the session REMEMBERS
3383
3667
  * (`storedLanding`, else the one analytics resolved on this page) — never
@@ -3386,6 +3670,17 @@ declare class VioFacade {
3386
3670
  * limits. `undefined` when there is nothing to say; never throws.
3387
3671
  */
3388
3672
  orderAttribution(sponsorId?: number): CheckoutAttributionWire | undefined;
3673
+ /**
3674
+ * The campaign an order of `sponsorId` is credited to — one article = one
3675
+ * campaign = one sponsor, so it is always one the sponsor takes part in:
3676
+ * the campaign the cart's own lines were added from (their origins; the one
3677
+ * that explains most units), else the page's — the elements' campaigns on
3678
+ * the page (`vio-campaign` / `data-vio-campaign`, in document order), then
3679
+ * `Vio.init({ campaignId })` — the first one active with that sponsor.
3680
+ * `undefined` when neither says one (the slices then decide). Without a
3681
+ * sponsor, the page's campaign as before.
3682
+ */
3683
+ private orderCampaign;
3389
3684
  /** The landing the session remembers: what the first page stored, else what analytics resolved on this page load (consent pending); null otherwise. */
3390
3685
  private rememberedLanding;
3391
3686
  /**
@@ -3435,6 +3730,46 @@ declare const BUYER_REF_MAX_LENGTH = 128;
3435
3730
  /** The reference when `value` is one; `undefined` for anything else (never an email). */
3436
3731
  declare function normalizeBuyerRef(value: unknown): string | undefined;
3437
3732
 
3733
+ /**
3734
+ * Internal traffic (ADR-0041 §5): a browser of Vio's own people — Angelo,
3735
+ * Michael, the agents, a tester — marks itself so its visits never count.
3736
+ *
3737
+ * Opening ANY page that runs the SDK with `?vio_internal=1` marks the browser
3738
+ * (`localStorage`, `vio.internal.v1`); `?vio_internal=0` clears the mark.
3739
+ * While marked, every analytics event carries `client.internal: true` and the
3740
+ * collector's reads leave it out. A host can do the same from code with
3741
+ * `Vio.analytics.setInternal(true | false)`.
3742
+ *
3743
+ * The mark is the tester's own explicit choice, not a tracking identifier: it
3744
+ * is written even before consent (`requireConsent`), like a preference.
3745
+ *
3746
+ * Pure like `client-context.ts`: takes the globals it reads (defaults to the
3747
+ * real ones) and never throws — in-app browsers and sandboxed frames throw on
3748
+ * `localStorage` access, and then the page simply is not marked.
3749
+ */
3750
+
3751
+ /** Where the browser remembers it is internal (per origin, across sessions). */
3752
+ declare const INTERNAL_KEY = "vio.internal.v1";
3753
+ /** The URL parameter that marks (`1`) or clears (`0`) the browser. */
3754
+ declare const INTERNAL_PARAM = "vio_internal";
3755
+ interface InternalEnvironment {
3756
+ location?: {
3757
+ search?: unknown;
3758
+ } | null;
3759
+ /** The persistent memory; `null` = none (SSR, blocked, in-app browser). */
3760
+ storage?: StorageLike | null;
3761
+ }
3762
+ /**
3763
+ * Whether this browser is internal: the URL's `vio_internal` decides (and is
3764
+ * remembered) when it is `1` or `0`; otherwise what is remembered. Any other
3765
+ * value of the parameter is ignored.
3766
+ */
3767
+ declare function resolveInternal(env?: InternalEnvironment): boolean;
3768
+ /** What the browser remembers (`false` without storage). */
3769
+ declare function readInternal(storage?: StorageLike | null | undefined): boolean;
3770
+ /** Remember (or forget) the mark. Never throws. */
3771
+ declare function writeInternal(internal: boolean, storage?: StorageLike | null | undefined): void;
3772
+
3438
3773
  /**
3439
3774
  * SDK version reported in analytics events (`sdk_version`) and available
3440
3775
  * to consumers. Kept as a constant (not a package.json import) so the
@@ -3442,7 +3777,7 @@ declare function normalizeBuyerRef(value: unknown): string | undefined;
3442
3777
  *
3443
3778
  * RELEASE CHECKLIST: bump together with package.json (see CONTRIBUTING).
3444
3779
  */
3445
- declare const SDK_VERSION = "0.29.0";
3780
+ declare const SDK_VERSION = "0.33.0";
3446
3781
 
3447
3782
  /**
3448
3783
  * Vipps MobilePay's own button, the way the design guidelines ask for it.
@@ -3471,4 +3806,4 @@ declare function vippsButtonAttributes(verb?: 'buy' | 'pay' | 'express' | 'conti
3471
3806
  language?: string;
3472
3807
  }): Record<string, string>;
3473
3808
 
3474
- export { ADD_ITEM_MUTATION, type AddManualOptions, type AddProductOptions, type AnalyticsCommerce, type AnalyticsContext, type AnalyticsEventName, type AnalyticsItemInput, AnalyticsManager, type AnalyticsStartOptions, type ApplePayConfig, type ApplePayResult, type Attribution, BUYER_REF_MAX_LENGTH, type BootstrapCampaign, type BootstrapCampaignEntry, type BootstrapCampaignStatus, type BootstrapResponse, type BootstrapSlot, CHECKOUT_ATTRIBUTION_CAPS, CHECKOUT_SPONSOR_STORAGE_KEY, CLIENT_LANDING_URL_MAX_LENGTH, CONTENT_URL_MAX_LENGTH, CREATE_CART_MUTATION, CREATE_CHECKOUT_MUTATION, CREATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION, CREATE_PAYMENT_STRIPE_MUTATION, CREATE_PAYMENT_VIPPS_MUTATION, type CampaignHint, type CartChangeDetail, type CartLineItem, type CartLineOrigin, CartManager, type CartOrigin, type CartQueryOptions, type CartSlice, type CartUpdatedDetail, type CheckoutAddress, type CheckoutAttributionInput, type CheckoutAttributionWire, type CheckoutChangeDetail, CheckoutManager, type CheckoutManagerDeps, type CheckoutOpenDetail, type CheckoutReference, type CheckoutSponsor, type CheckoutState, type ClientContext, CommerceClient, Configuration, type ContentRef, type CreatePaymentVippsResponse, type CreatePaymentVippsVariables, DELETE_ITEM_MUTATION, type EntryContextWire, type Environment, GET_AVAILABLE_PAYMENT_METHODS_QUERY, GET_CART_QUERY, GET_CHECKOUT_QUERY, GET_LINE_ITEMS_BY_SUPPLIER_QUERY, GET_VIPPS_STATUS_QUERY, GRAPHQL_INT_MAX, type GatewayFeature, type GetVippsStatusVariables, type ImageSize, LINE_ORIGIN_CAPS, type Landing, type LineOriginWire, type LineOriginWireOptions, type ManifestLocation, type ManifestRequest, type ManifestResult, type OrderReference, type OriginPage, type PaymentCompleteDetail, type PaymentMethod, type PaymentSelectDetail, type PaymentSuccessDetail, type PaymentSuccessResult, type PlacementComponent, type Product, type ProductCategory, type ProductImage, type ProductOption, type ProductPrice, type ProductVariant, type PurchaseIds, type RegisterSlotOptions, type ResolvedConfig, SDK_VERSION, type SlotInput, type SlotKind, type Sponsor, type SponsorCartState, type SponsorCommerceBlock, type SponsorIdentity, type SurfacePrivacyMode, type SurfaceResponse, type TrackOptions, UPDATE_CHECKOUT_MUTATION, UPDATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION, UPDATE_ITEM_MUTATION, UPDATE_ITEM_WITH_ORIGIN_MUTATION, UPDATE_SHIPPINGS_BY_SUPPLIER_MUTATION, VIPPS_BUTTON_SCRIPT, VIPPS_BUTTON_TAG, Vio, VioApi, VioApiError, type VioConfig, type VioItem, type VioPlatform, type VippsPaymentState, type VippsStatusResult, activeCampaignEntry, addItem, autoSlotDisplayName, autoSlotId, buyerRefOf, campaignCandidates, capContentUrl, cartSlicesFrom, checkApplePayAvailability, checkoutAttributionOf, componentKindOf, createCart, createCheckout, createCommerceClient, createPaymentStripe, createPaymentVipps, createVioApi, deleteItem, displayPrice, dominantCampaignOf, ensureVippsButton, entryContextOf, executeCartGraphQL, formatPrice, gatewayHas, getAvailablePaymentMethods, getCart, getCartGraphQLOptions, getCheckout, getCheckoutReference, getCustomerSessionId, getGlobalCurrency, getLineItemsBySupplier, getVippsStatus, isUnknownFeatureError, isUnknownTokenError, landingUrl, lineOriginWire, lineOrigins, normalizeBuyerRef, normalizeOrigin, normalizeScope, normalizeSlotKind, originAndPath, primaryImageUrl, purchaseFromPaymentSuccess, purchaseIdsOf, resetGatewayFeatures, resolveCampaignId, resolveClientContext, resolveContent, resolveLanding, resolveSlotCampaign, sameOrigin, showApplePaySheet, sponsorCampaignEntry, sponsorIdentityFrom, storedLanding, toCampaignId, updateCheckout, updateItem, updateShippingsBySupplier, vippsButtonAttributes, withGatewayFeature };
3809
+ export { ADD_ITEM_MUTATION, type AddManualOptions, type AddProductOptions, type AnalyticsCommerce, type AnalyticsContext, type AnalyticsEventName, type AnalyticsItemInput, AnalyticsManager, type AnalyticsStartOptions, type ApplePayConfig, type ApplePayResult, type Attribution, BUYER_REF_MAX_LENGTH, type BootstrapCampaign, type BootstrapCampaignEntry, type BootstrapCampaignStatus, type BootstrapResponse, type BootstrapSlot, CHECKOUT_ATTRIBUTION_CAPS, CHECKOUT_SPONSOR_STORAGE_KEY, CLIENT_LANDING_URL_MAX_LENGTH, CONTENT_URL_MAX_LENGTH, CREATE_CART_MUTATION, CREATE_CHECKOUT_MUTATION, CREATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION, CREATE_PAYMENT_STRIPE_MUTATION, CREATE_PAYMENT_VIPPS_MUTATION, type CampaignHint, type CartChangeDetail, type CartLineItem, type CartLineOrigin, CartManager, type CartOrigin, type CartQueryOptions, type CartSlice, type CartUpdatedDetail, type CheckoutAddress, type CheckoutAttributionInput, type CheckoutAttributionWire, type CheckoutChangeDetail, CheckoutManager, type CheckoutManagerDeps, type CheckoutOpenDetail, type CheckoutReference, type CheckoutSponsor, type CheckoutState, type ClientContext, CommerceClient, Configuration, type ContentRef, type CreatePaymentVippsResponse, type CreatePaymentVippsVariables, DELETE_ITEM_MUTATION, type EntryContextWire, type Environment, GET_AVAILABLE_PAYMENT_METHODS_QUERY, GET_CART_QUERY, GET_CHECKOUT_QUERY, GET_LINE_ITEMS_BY_SUPPLIER_QUERY, GET_VIPPS_STATUS_QUERY, GRAPHQL_INT_MAX, type GatewayFeature, type GetVippsStatusVariables, INTERNAL_KEY, INTERNAL_PARAM, type ImageSize, LINE_ORIGIN_CAPS, type Landing, type LineOriginWire, type LineOriginWireOptions, type ManifestLocation, type ManifestRequest, type ManifestResult, type OrderReference, type OriginPage, type PaymentCompleteDetail, type PaymentMethod, type PaymentSelectDetail, type PaymentSuccessDetail, type PaymentSuccessResult, type PlacementComponent, type Product, type ProductCategory, type ProductImage, type ProductOption, type ProductPrice, type ProductVariant, type PurchaseIds, type RegisterSlotOptions, type ResolvedConfig, SDK_VERSION, type SlotInput, type SlotKind, type Sponsor, type SponsorCartState, type SponsorCommerceBlock, type SponsorIdentity, type SurfacePrivacyMode, type SurfaceResponse, type TrackOptions, UPDATE_CHECKOUT_MUTATION, UPDATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION, UPDATE_ITEM_MUTATION, UPDATE_ITEM_WITH_ORIGIN_MUTATION, UPDATE_SHIPPINGS_BY_SUPPLIER_MUTATION, VIPPS_BUTTON_SCRIPT, VIPPS_BUTTON_TAG, Vio, VioApi, VioApiError, type VioConfig, type VioItem, type VioPlatform, type VippsPaymentState, type VippsStatusResult, activeCampaignEntry, addItem, autoSlotDisplayName, autoSlotId, buyerRefOf, campaignCandidates, capContentUrl, cartSlicesFrom, checkApplePayAvailability, checkoutAttributionOf, componentKindOf, createCart, createCheckout, createCommerceClient, createPaymentStripe, createPaymentVipps, createVioApi, deleteItem, displayPrice, dominantCampaignOf, ensureVippsButton, entryContextOf, executeCartGraphQL, formatPrice, gatewayHas, getAvailablePaymentMethods, getCart, getCartGraphQLOptions, getCheckout, getCheckoutReference, getCustomerSessionId, getGlobalCurrency, getLineItemsBySupplier, getVippsStatus, isUnknownFeatureError, isUnknownTokenError, landingUrl, lineOriginWire, lineOrigins, normalizeBuyerRef, normalizeOrigin, normalizeScope, normalizeSlotKind, originAndPath, primaryImageUrl, purchaseFromPaymentSuccess, purchaseIdsOf, readInternal, resetGatewayFeatures, resolveCampaignId, resolveClientContext, resolveContent, resolveInternal, resolveLanding, resolveSlotCampaign, sameOrigin, showApplePaySheet, sponsorCampaignEntry, sponsorIdentityFrom, storedLanding, toCampaignId, updateCheckout, updateItem, updateShippingsBySupplier, vippsButtonAttributes, withGatewayFeature, writeInternal };