@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.
- package/CHANGELOG.md +219 -0
- package/README.md +127 -19
- package/dist/chunk-QGJUBVH3.js +3 -0
- package/dist/{chunk-67QESEV2.js.map → chunk-QGJUBVH3.js.map} +1 -1
- package/dist/{chunk-L6YYYKQK.js → chunk-T5B74YBQ.js} +1433 -205
- package/dist/chunk-T5B74YBQ.js.map +1 -0
- package/dist/{chunk-AG4G2S2M.js → chunk-ZORYG4W3.js} +1153 -169
- package/dist/chunk-ZORYG4W3.js.map +1 -0
- package/dist/core/index.d.ts +891 -556
- package/dist/core/index.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +3 -3
- package/dist/{tokens-Dok4d21V.d.ts → tokens-B7GVA_qB.d.ts} +325 -21
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-67QESEV2.js +0 -3
- package/dist/chunk-AG4G2S2M.js.map +0 -1
- package/dist/chunk-L6YYYKQK.js.map +0 -1
|
@@ -207,9 +207,9 @@ function slotDeclarationKey(location2, pageCampaignId) {
|
|
|
207
207
|
const kind = normalizeSlotKind(location2.kind);
|
|
208
208
|
return location2.id + (location2.displayName ? `${location2.displayName}` : "") + (campaignId !== void 0 ? `${campaignId}` : "") + (kind !== void 0 ? `${kind}` : "");
|
|
209
209
|
}
|
|
210
|
-
function pendingSlotKeys(
|
|
210
|
+
function pendingSlotKeys(memory2, keys, now = Date.now(), ttl = SLOT_DECLARATION_TTL_MS) {
|
|
211
211
|
return keys.filter((key) => {
|
|
212
|
-
const at =
|
|
212
|
+
const at = memory2?.[key];
|
|
213
213
|
if (typeof at !== "number" || !Number.isFinite(at)) return true;
|
|
214
214
|
return now - at >= ttl || now < at;
|
|
215
215
|
});
|
|
@@ -218,8 +218,8 @@ function slotKeyId(key) {
|
|
|
218
218
|
const cut4 = key.search(/[\u001f\u001e\u001d]/);
|
|
219
219
|
return cut4 >= 0 ? key.slice(0, cut4) : key;
|
|
220
220
|
}
|
|
221
|
-
function rememberSlotKeys(
|
|
222
|
-
const next = { ...
|
|
221
|
+
function rememberSlotKeys(memory2, keys, at, cap = SLOT_DECLARATION_MEMORY_CAP) {
|
|
222
|
+
const next = { ...memory2 ?? {} };
|
|
223
223
|
const ids = new Set(keys.map(slotKeyId));
|
|
224
224
|
for (const existing of Object.keys(next)) {
|
|
225
225
|
if (ids.has(slotKeyId(existing)) && !keys.includes(existing)) delete next[existing];
|
|
@@ -258,10 +258,10 @@ function readSlotDeclaration(storageKey) {
|
|
|
258
258
|
return {};
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
|
-
function writeSlotDeclaration(storageKey,
|
|
261
|
+
function writeSlotDeclaration(storageKey, memory2) {
|
|
262
262
|
try {
|
|
263
263
|
if (typeof localStorage === "undefined") return;
|
|
264
|
-
localStorage.setItem(storageKey, JSON.stringify(
|
|
264
|
+
localStorage.setItem(storageKey, JSON.stringify(memory2));
|
|
265
265
|
} catch {
|
|
266
266
|
}
|
|
267
267
|
}
|
|
@@ -466,6 +466,51 @@ function createVioApi(options) {
|
|
|
466
466
|
return new VioApi(options);
|
|
467
467
|
}
|
|
468
468
|
|
|
469
|
+
// src/core/safe-storage.ts
|
|
470
|
+
var memory = {
|
|
471
|
+
local: /* @__PURE__ */ new Map(),
|
|
472
|
+
session: /* @__PURE__ */ new Map()
|
|
473
|
+
};
|
|
474
|
+
function area(kind) {
|
|
475
|
+
try {
|
|
476
|
+
const s = globalThis[kind === "local" ? "localStorage" : "sessionStorage"];
|
|
477
|
+
return s && typeof s.getItem === "function" ? s : null;
|
|
478
|
+
} catch {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
function storageGet(kind, key) {
|
|
483
|
+
const kept = memory[kind];
|
|
484
|
+
if (kept.has(key)) return kept.get(key) ?? null;
|
|
485
|
+
const s = area(kind);
|
|
486
|
+
if (!s) return null;
|
|
487
|
+
try {
|
|
488
|
+
return s.getItem(key);
|
|
489
|
+
} catch {
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
function storageSet(kind, key, value, opts = {}) {
|
|
494
|
+
try {
|
|
495
|
+
const s = area(kind);
|
|
496
|
+
if (s) {
|
|
497
|
+
s.setItem(key, value);
|
|
498
|
+
memory[kind].delete(key);
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
} catch {
|
|
502
|
+
}
|
|
503
|
+
if (opts.memory !== false) memory[kind].set(key, value);
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
function storageRemove(kind, key) {
|
|
507
|
+
memory[kind].delete(key);
|
|
508
|
+
try {
|
|
509
|
+
area(kind)?.removeItem(key);
|
|
510
|
+
} catch {
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
469
514
|
// src/core/types.ts
|
|
470
515
|
function displayPrice(product) {
|
|
471
516
|
const p = product.price;
|
|
@@ -475,37 +520,24 @@ function displayPrice(product) {
|
|
|
475
520
|
function getGlobalCountryCode() {
|
|
476
521
|
const g = globalThis;
|
|
477
522
|
if (g.__VIO_COUNTRY__) return g.__VIO_COUNTRY__;
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
const v = localStorage.getItem("vio.country");
|
|
481
|
-
if (v) return v;
|
|
482
|
-
} catch {
|
|
483
|
-
}
|
|
484
|
-
}
|
|
523
|
+
const stored = storageGet("local", "vio.country");
|
|
524
|
+
if (stored) return stored;
|
|
485
525
|
return "NO";
|
|
486
526
|
}
|
|
487
527
|
function getGlobalLocale() {
|
|
488
528
|
const g = globalThis;
|
|
489
529
|
if (g.__VIO_LOCALE__) return g.__VIO_LOCALE__;
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
const v = localStorage.getItem("vio.locale");
|
|
493
|
-
if (v) return v;
|
|
494
|
-
} catch {
|
|
495
|
-
}
|
|
496
|
-
}
|
|
530
|
+
const stored = storageGet("local", "vio.locale");
|
|
531
|
+
if (stored) return stored;
|
|
497
532
|
return "nb-NO";
|
|
498
533
|
}
|
|
499
534
|
function getGlobalSymbol(currency) {
|
|
500
535
|
const activeCurrency = currency || getGlobalCurrency();
|
|
501
536
|
const g = globalThis;
|
|
502
537
|
if (!currency && g.__VIO_SYMBOL__) return g.__VIO_SYMBOL__;
|
|
503
|
-
if (!currency
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
if (v) return v;
|
|
507
|
-
} catch {
|
|
508
|
-
}
|
|
538
|
+
if (!currency) {
|
|
539
|
+
const v = storageGet("local", "vio.symbol");
|
|
540
|
+
if (v) return v;
|
|
509
541
|
}
|
|
510
542
|
const curr = String(activeCurrency).toUpperCase();
|
|
511
543
|
if (curr === "NOK" || curr === "DKK") return "Kr";
|
|
@@ -519,13 +551,8 @@ function getGlobalSymbol(currency) {
|
|
|
519
551
|
function getGlobalCurrency() {
|
|
520
552
|
const g = globalThis;
|
|
521
553
|
if (g.__VIO_CURRENCY__) return g.__VIO_CURRENCY__;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
const v = localStorage.getItem("vio.currency");
|
|
525
|
-
if (v) return v;
|
|
526
|
-
} catch {
|
|
527
|
-
}
|
|
528
|
-
}
|
|
554
|
+
const stored = storageGet("local", "vio.currency");
|
|
555
|
+
if (stored) return stored;
|
|
529
556
|
return "NOK";
|
|
530
557
|
}
|
|
531
558
|
var validatedLocales = /* @__PURE__ */ new Map();
|
|
@@ -665,6 +692,80 @@ var GET_PRODUCT_SELLER = (
|
|
|
665
692
|
}
|
|
666
693
|
`
|
|
667
694
|
);
|
|
695
|
+
var GET_PRODUCT_SHIPPING = (
|
|
696
|
+
/* GraphQL */
|
|
697
|
+
`
|
|
698
|
+
query GetProductShipping(
|
|
699
|
+
$productIds: [Int!]
|
|
700
|
+
$useCache: Boolean!
|
|
701
|
+
$currency: String
|
|
702
|
+
$shippingCountryCode: String
|
|
703
|
+
) {
|
|
704
|
+
Channel {
|
|
705
|
+
GetProductsByIds(
|
|
706
|
+
product_ids: $productIds
|
|
707
|
+
useCache: $useCache
|
|
708
|
+
currency: $currency
|
|
709
|
+
shipping_country_code: $shippingCountryCode
|
|
710
|
+
) {
|
|
711
|
+
id
|
|
712
|
+
product_shipping {
|
|
713
|
+
id
|
|
714
|
+
name
|
|
715
|
+
description
|
|
716
|
+
default
|
|
717
|
+
shipping_country {
|
|
718
|
+
country
|
|
719
|
+
price {
|
|
720
|
+
amount
|
|
721
|
+
amount_incl_taxes
|
|
722
|
+
currency_code
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
`
|
|
730
|
+
);
|
|
731
|
+
var GET_PRODUCT_SHIPPING_WITH_LOGO = (
|
|
732
|
+
/* GraphQL */
|
|
733
|
+
`
|
|
734
|
+
query GetProductShippingWithLogo(
|
|
735
|
+
$productIds: [Int!]
|
|
736
|
+
$useCache: Boolean!
|
|
737
|
+
$currency: String
|
|
738
|
+
$shippingCountryCode: String
|
|
739
|
+
) {
|
|
740
|
+
Channel {
|
|
741
|
+
GetProductsByIds(
|
|
742
|
+
product_ids: $productIds
|
|
743
|
+
useCache: $useCache
|
|
744
|
+
currency: $currency
|
|
745
|
+
shipping_country_code: $shippingCountryCode
|
|
746
|
+
) {
|
|
747
|
+
id
|
|
748
|
+
product_shipping {
|
|
749
|
+
id
|
|
750
|
+
name
|
|
751
|
+
description
|
|
752
|
+
logo_url
|
|
753
|
+
default
|
|
754
|
+
shipping_country {
|
|
755
|
+
country
|
|
756
|
+
price {
|
|
757
|
+
amount
|
|
758
|
+
amount_incl_taxes
|
|
759
|
+
currency_code
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
`
|
|
767
|
+
);
|
|
768
|
+
var gatewayHasShippingLogo;
|
|
668
769
|
var ChannelProduct = class {
|
|
669
770
|
constructor(client) {
|
|
670
771
|
this.client = client;
|
|
@@ -704,7 +805,77 @@ var ChannelProduct = class {
|
|
|
704
805
|
return null;
|
|
705
806
|
}
|
|
706
807
|
}
|
|
808
|
+
/**
|
|
809
|
+
* The product's shipping rates for the page's market (or `country`),
|
|
810
|
+
* cheapest first; `[]` when it has none there, `null` when they could not
|
|
811
|
+
* be read. Never throws. Never from the cache, for the reason given at
|
|
812
|
+
* getSellerCompany.
|
|
813
|
+
*/
|
|
814
|
+
async getShippingRates(productId, options = {}) {
|
|
815
|
+
const country = options.country || getGlobalCountryCode();
|
|
816
|
+
const variables = {
|
|
817
|
+
productIds: [productId],
|
|
818
|
+
useCache: false,
|
|
819
|
+
currency: options.currency ?? getGlobalCurrency(),
|
|
820
|
+
shippingCountryCode: country
|
|
821
|
+
};
|
|
822
|
+
try {
|
|
823
|
+
let data;
|
|
824
|
+
if (gatewayHasShippingLogo === false) {
|
|
825
|
+
data = await this.client.request(GET_PRODUCT_SHIPPING, variables);
|
|
826
|
+
} else {
|
|
827
|
+
try {
|
|
828
|
+
data = await this.client.request(GET_PRODUCT_SHIPPING_WITH_LOGO, variables);
|
|
829
|
+
gatewayHasShippingLogo = true;
|
|
830
|
+
} catch (err) {
|
|
831
|
+
if (!/logo_url/.test(String(err?.message ?? ""))) throw err;
|
|
832
|
+
gatewayHasShippingLogo = false;
|
|
833
|
+
data = await this.client.request(GET_PRODUCT_SHIPPING, variables);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
const product = data.Channel?.GetProductsByIds?.[0];
|
|
837
|
+
if (!product) return null;
|
|
838
|
+
return shippingRatesFor(product.product_shipping, country);
|
|
839
|
+
} catch {
|
|
840
|
+
return null;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
707
843
|
};
|
|
844
|
+
var FILLER_SHIPPING_DESCRIPTIONS = Object.freeze(["by outshifter", "default shipping method"]);
|
|
845
|
+
function shippingDescriptionOf(value, repeats = []) {
|
|
846
|
+
const text3 = typeof value === "string" ? value.trim() : "";
|
|
847
|
+
if (!text3) return "";
|
|
848
|
+
const key = text3.toLowerCase();
|
|
849
|
+
if (FILLER_SHIPPING_DESCRIPTIONS.includes(key)) return "";
|
|
850
|
+
for (const r of repeats) {
|
|
851
|
+
if (typeof r === "string" && r.trim() && r.trim().toLowerCase() === key) return "";
|
|
852
|
+
}
|
|
853
|
+
return text3;
|
|
854
|
+
}
|
|
855
|
+
function shippingRatesFor(productShipping, country) {
|
|
856
|
+
if (!Array.isArray(productShipping)) return [];
|
|
857
|
+
const want = String(country || "").trim().toUpperCase();
|
|
858
|
+
const out = [];
|
|
859
|
+
for (const s of productShipping) {
|
|
860
|
+
const countries = Array.isArray(s?.shipping_country) ? s.shipping_country : [];
|
|
861
|
+
const row = countries.find((c) => String(c?.country ?? "").trim().toUpperCase() === want);
|
|
862
|
+
const price = row?.price;
|
|
863
|
+
const amount = typeof price?.amount_incl_taxes === "number" ? price.amount_incl_taxes : price?.amount;
|
|
864
|
+
if (typeof amount !== "number" || !Number.isFinite(amount) || amount < 0) continue;
|
|
865
|
+
const name = String(s.name ?? "");
|
|
866
|
+
const description = shippingDescriptionOf(s.description, [name]);
|
|
867
|
+
out.push({
|
|
868
|
+
id: String(s.id ?? ""),
|
|
869
|
+
name,
|
|
870
|
+
price: amount,
|
|
871
|
+
currency: String(price?.currency_code ?? ""),
|
|
872
|
+
default: s.default === true,
|
|
873
|
+
description,
|
|
874
|
+
logoUrl: httpsUrlOrEmpty(s.logo_url ?? s.logoUrl)
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
return out.sort((a, b) => a.price - b.price);
|
|
878
|
+
}
|
|
708
879
|
var Channel = class {
|
|
709
880
|
constructor(client) {
|
|
710
881
|
this.product = new ChannelProduct(client);
|
|
@@ -723,6 +894,11 @@ var CommerceClient = class {
|
|
|
723
894
|
function createCommerceClient(options) {
|
|
724
895
|
return new CommerceClient(options);
|
|
725
896
|
}
|
|
897
|
+
function httpsUrlOrEmpty(value) {
|
|
898
|
+
if (typeof value !== "string") return "";
|
|
899
|
+
const url = value.trim();
|
|
900
|
+
return /^https:\/\/[^\s]+$/i.test(url) ? url : "";
|
|
901
|
+
}
|
|
726
902
|
|
|
727
903
|
// src/core/content.ts
|
|
728
904
|
var CONTENT_ID_QUERY = "vio_content";
|
|
@@ -1851,7 +2027,7 @@ query Config {
|
|
|
1851
2027
|
}
|
|
1852
2028
|
}
|
|
1853
2029
|
`;
|
|
1854
|
-
async function getCartGraphQLOptions(sponsorId) {
|
|
2030
|
+
async function getCartGraphQLOptions(sponsorId, ctx) {
|
|
1855
2031
|
const facade = globalThis.__VIO_FACADE__;
|
|
1856
2032
|
if (!Configuration.isInitialized) {
|
|
1857
2033
|
await Configuration.whenReady();
|
|
@@ -1869,14 +2045,31 @@ async function getCartGraphQLOptions(sponsorId) {
|
|
|
1869
2045
|
const anyCfg = cfg;
|
|
1870
2046
|
let commerceKey = anyCfg.apiKey;
|
|
1871
2047
|
let sponsorResolved = false;
|
|
1872
|
-
|
|
2048
|
+
let channelId;
|
|
2049
|
+
let channelMissing = false;
|
|
2050
|
+
const askedChannel = ctx?.channelId === null || ctx?.channelId === void 0 ? "" : String(ctx.channelId).trim();
|
|
2051
|
+
if (sponsorId && typeof facade?.sponsorCommerce === "function") {
|
|
2052
|
+
const sponsor = facade.sponsorCommerce(sponsorId, ctx ?? {});
|
|
2053
|
+
if (sponsor?.commerce?.apiKey) {
|
|
2054
|
+
commerceKey = sponsor.commerce.apiKey;
|
|
2055
|
+
sponsorResolved = true;
|
|
2056
|
+
const ch = sponsor.commerce.channelId;
|
|
2057
|
+
if (ch !== null && ch !== void 0 && String(ch).trim()) channelId = String(ch).trim();
|
|
2058
|
+
} else if (askedChannel && facade.bootstrapCache) {
|
|
2059
|
+
channelMissing = true;
|
|
2060
|
+
}
|
|
2061
|
+
} else if (sponsorId && !askedChannel && typeof facade?.findSponsor === "function") {
|
|
1873
2062
|
const sponsor = facade.findSponsor(sponsorId);
|
|
1874
2063
|
if (sponsor?.commerce?.apiKey) {
|
|
1875
2064
|
commerceKey = sponsor.commerce.apiKey;
|
|
1876
2065
|
sponsorResolved = true;
|
|
1877
2066
|
}
|
|
1878
2067
|
}
|
|
1879
|
-
if (
|
|
2068
|
+
if (channelMissing && typeof console !== "undefined") {
|
|
2069
|
+
console.warn(
|
|
2070
|
+
`[Vio] channel ${askedChannel} of sponsor ${sponsorId} is no longer in the bootstrap \u2014 not calling it with another channel's key`
|
|
2071
|
+
);
|
|
2072
|
+
} else if (sponsorId && !sponsorResolved && typeof console !== "undefined") {
|
|
1880
2073
|
console.warn(
|
|
1881
2074
|
`[Vio] no commerce key for sponsor ${sponsorId} \u2014 falling back to the platform apiKey, which the commerce API will reject. Is the sponsor configured, and did Vio.init run before this call?`
|
|
1882
2075
|
);
|
|
@@ -1885,16 +2078,17 @@ async function getCartGraphQLOptions(sponsorId) {
|
|
|
1885
2078
|
endpoint: anyCfg.graphQLBase || "https://graph-ql-dev.vio.live",
|
|
1886
2079
|
apiKey: anyCfg.apiKey,
|
|
1887
2080
|
commerceKey,
|
|
1888
|
-
sponsorResolved
|
|
2081
|
+
sponsorResolved,
|
|
2082
|
+
...channelId ? { channelId } : {},
|
|
2083
|
+
...channelMissing ? { channelMissing } : {}
|
|
1889
2084
|
};
|
|
1890
2085
|
}
|
|
1891
2086
|
var CUSTOMER_SESSION_KEY = "vio.customer_session_id.v1";
|
|
1892
2087
|
function getCustomerSessionId() {
|
|
1893
|
-
|
|
1894
|
-
let id = localStorage.getItem(CUSTOMER_SESSION_KEY);
|
|
2088
|
+
let id = storageGet("local", CUSTOMER_SESSION_KEY);
|
|
1895
2089
|
if (!id) {
|
|
1896
2090
|
id = "cs_" + Math.random().toString(36).slice(2, 11) + Date.now().toString(36);
|
|
1897
|
-
|
|
2091
|
+
storageSet("local", CUSTOMER_SESSION_KEY, id);
|
|
1898
2092
|
}
|
|
1899
2093
|
return id;
|
|
1900
2094
|
}
|
|
@@ -2149,7 +2343,18 @@ async function getVippsStatus(variables, options) {
|
|
|
2149
2343
|
}
|
|
2150
2344
|
|
|
2151
2345
|
// src/core/cart/cart-manager.ts
|
|
2152
|
-
var
|
|
2346
|
+
var CART_STORAGE_PREFIX = "vio.cart.v1";
|
|
2347
|
+
function cartStorageKey(scope) {
|
|
2348
|
+
return scope ? `${CART_STORAGE_PREFIX}:${scope}` : CART_STORAGE_PREFIX;
|
|
2349
|
+
}
|
|
2350
|
+
function cartScopeOf(environment, apiKey) {
|
|
2351
|
+
let h = 2166136261;
|
|
2352
|
+
for (let i = 0; i < apiKey.length; i++) {
|
|
2353
|
+
h ^= apiKey.charCodeAt(i);
|
|
2354
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
2355
|
+
}
|
|
2356
|
+
return `${environment || "production"}:${h.toString(16).padStart(8, "0")}`;
|
|
2357
|
+
}
|
|
2153
2358
|
function finalTarget(sync) {
|
|
2154
2359
|
return sync.steps.reduce((quantity, step) => quantity + step.delta, sync.sent);
|
|
2155
2360
|
}
|
|
@@ -2177,6 +2382,17 @@ function queueStep(sync, target, origin) {
|
|
|
2177
2382
|
else sync.steps.push({ delta: -left });
|
|
2178
2383
|
}
|
|
2179
2384
|
}
|
|
2385
|
+
function cartCampaignOf(cart) {
|
|
2386
|
+
const items = cart?.items ?? [];
|
|
2387
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
2388
|
+
const origins = items[i]?.origins ?? [];
|
|
2389
|
+
for (let j = origins.length - 1; j >= 0; j--) {
|
|
2390
|
+
const id = Number(origins[j]?.campaignId);
|
|
2391
|
+
if (Number.isInteger(id) && id > 0) return id;
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
return void 0;
|
|
2395
|
+
}
|
|
2180
2396
|
function lineId() {
|
|
2181
2397
|
return "li_" + Math.random().toString(36).slice(2, 10) + Date.now().toString(36);
|
|
2182
2398
|
}
|
|
@@ -2187,7 +2403,7 @@ function normId(val) {
|
|
|
2187
2403
|
return String(val).trim();
|
|
2188
2404
|
}
|
|
2189
2405
|
var CartManager = class extends EventTarget {
|
|
2190
|
-
constructor() {
|
|
2406
|
+
constructor(scope = "") {
|
|
2191
2407
|
super();
|
|
2192
2408
|
/** In-flight CreateCart per sponsor — two quick adds must share ONE backend
|
|
2193
2409
|
* cart (two CreateCarts split the items and one silently disappears). */
|
|
@@ -2211,6 +2427,21 @@ var CartManager = class extends EventTarget {
|
|
|
2211
2427
|
* in parallel; each response re-applied the whole backend cart, so an
|
|
2212
2428
|
* older one landing after a newer optimistic change rolled the line back.) */
|
|
2213
2429
|
this.qtySyncs = /* @__PURE__ */ new Map();
|
|
2430
|
+
/**
|
|
2431
|
+
* Bumped per sponsor each time its backend cart is dropped because its
|
|
2432
|
+
* channel went away: the lines as they stood then (`carryOver`) go to the
|
|
2433
|
+
* new backend cart, so an add whose local units were already counted in
|
|
2434
|
+
* them must not send its own AddItem as well (see `addManual`).
|
|
2435
|
+
*/
|
|
2436
|
+
this.rebuildEpoch = /* @__PURE__ */ new Map();
|
|
2437
|
+
/** The lines to give the next backend cart of a sponsor, after its channel went away. */
|
|
2438
|
+
this.carryOver = /* @__PURE__ */ new Map();
|
|
2439
|
+
/**
|
|
2440
|
+
* Whether this is the page's connection now. A manager left behind by a
|
|
2441
|
+
* re-init (another key) still finishes its requests and keeps its own
|
|
2442
|
+
* carts, but says nothing to the page: no `vio:cart-*` events.
|
|
2443
|
+
*/
|
|
2444
|
+
this.active = true;
|
|
2214
2445
|
/** Quantity intents for lines whose backend id hasn't arrived yet — replayed
|
|
2215
2446
|
* when the AddItem response reconciles (keyed by product::variant). */
|
|
2216
2447
|
this.pendingQtyIntents = /* @__PURE__ */ new Map();
|
|
@@ -2224,7 +2455,7 @@ var CartManager = class extends EventTarget {
|
|
|
2224
2455
|
* that changed (`source: 'storage'`); nothing when nothing did.
|
|
2225
2456
|
*/
|
|
2226
2457
|
this.onStorage = (e) => {
|
|
2227
|
-
if (e.key !== null && e.key !==
|
|
2458
|
+
if (e.key !== null && e.key !== this.storageKey) return;
|
|
2228
2459
|
const stored = this.loadFromStorage();
|
|
2229
2460
|
const changed = [];
|
|
2230
2461
|
for (const sponsorId of /* @__PURE__ */ new Set([...this.cartsBySponsor.keys(), ...stored.keys()])) {
|
|
@@ -2240,11 +2471,28 @@ var CartManager = class extends EventTarget {
|
|
|
2240
2471
|
this.emit();
|
|
2241
2472
|
for (const sponsorId of changed) this.emitCartUpdated(sponsorId, "storage");
|
|
2242
2473
|
};
|
|
2474
|
+
this.storageKey = cartStorageKey(scope);
|
|
2243
2475
|
this.cartsBySponsor = this.loadFromStorage();
|
|
2476
|
+
if (scope && this.cartsBySponsor.size === 0) {
|
|
2477
|
+
const legacy = this.loadFromStorage(CART_STORAGE_PREFIX);
|
|
2478
|
+
if (legacy.size > 0) {
|
|
2479
|
+
this.cartsBySponsor = legacy;
|
|
2480
|
+
this.persist();
|
|
2481
|
+
storageRemove("local", CART_STORAGE_PREFIX);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2244
2484
|
if (typeof window !== "undefined" && typeof window.addEventListener === "function") {
|
|
2245
2485
|
window.addEventListener("storage", this.onStorage);
|
|
2246
2486
|
}
|
|
2247
2487
|
}
|
|
2488
|
+
/** The page's connection is (or is no longer) this one; see `active`. */
|
|
2489
|
+
setActive(active) {
|
|
2490
|
+
this.active = active;
|
|
2491
|
+
}
|
|
2492
|
+
/** Tell the listeners what this connection's carts hold now (after the page switched to it). */
|
|
2493
|
+
announce() {
|
|
2494
|
+
this.emit();
|
|
2495
|
+
}
|
|
2248
2496
|
nextSeq(sponsorId) {
|
|
2249
2497
|
const n = (this.mutationSeq.get(sponsorId) ?? 0) + 1;
|
|
2250
2498
|
this.mutationSeq.set(sponsorId, n);
|
|
@@ -2338,15 +2586,118 @@ var CartManager = class extends EventTarget {
|
|
|
2338
2586
|
emitError(message, err) {
|
|
2339
2587
|
if (typeof console !== "undefined") console.warn("[CartManager]", message, err ?? "");
|
|
2340
2588
|
this.dispatchEvent(new CustomEvent("error", { detail: { message } }));
|
|
2341
|
-
if (typeof document !== "undefined") {
|
|
2589
|
+
if (this.active && typeof document !== "undefined") {
|
|
2342
2590
|
document.dispatchEvent(
|
|
2343
2591
|
new CustomEvent("vio:cart-error", { bubbles: true, detail: { message } })
|
|
2344
2592
|
);
|
|
2345
2593
|
}
|
|
2346
2594
|
}
|
|
2347
2595
|
// MARK: - Backend cart sync (Vio Commerce GraphQL)
|
|
2348
|
-
/**
|
|
2349
|
-
|
|
2596
|
+
/**
|
|
2597
|
+
* The options of a sponsor's backend cart: the key of the channel it was
|
|
2598
|
+
* created on (`channelMissing` when the bootstrap no longer lists it). A
|
|
2599
|
+
* cart from before channels were remembered keeps the sponsor's first
|
|
2600
|
+
* block, as when it was created, and remembers that channel from now on.
|
|
2601
|
+
*/
|
|
2602
|
+
async cartOptions(sponsorId) {
|
|
2603
|
+
const cart = this.cartsBySponsor.get(sponsorId);
|
|
2604
|
+
if (cart?.cartId && cart.channelId) {
|
|
2605
|
+
return getCartGraphQLOptions(sponsorId, { channelId: cart.channelId });
|
|
2606
|
+
}
|
|
2607
|
+
if (!cart?.cartId) return getCartGraphQLOptions(sponsorId);
|
|
2608
|
+
const opts = await getCartGraphQLOptions(sponsorId, { campaignId: null });
|
|
2609
|
+
const now = this.cartsBySponsor.get(sponsorId);
|
|
2610
|
+
if (now?.cartId && !now.channelId && opts.sponsorResolved && opts.channelId) {
|
|
2611
|
+
now.channelId = opts.channelId;
|
|
2612
|
+
this.persist();
|
|
2613
|
+
}
|
|
2614
|
+
return opts;
|
|
2615
|
+
}
|
|
2616
|
+
/**
|
|
2617
|
+
* The backend cart to call for a sponsor, with the key of its channel. When
|
|
2618
|
+
* the bootstrap no longer lists that channel the stale cart is dropped and a
|
|
2619
|
+
* new one is created on the sponsor's current channel with the same lines
|
|
2620
|
+
* (`dropStaleBackendCart` + `ensureCartId`) — never a call with a key of
|
|
2621
|
+
* another channel. `undefined` when there is no backend cart (or none could
|
|
2622
|
+
* be made).
|
|
2623
|
+
*/
|
|
2624
|
+
async liveCart(sponsorId) {
|
|
2625
|
+
const cart = this.cartsBySponsor.get(sponsorId);
|
|
2626
|
+
const cartId = cart?.cartId;
|
|
2627
|
+
if (!cart || !cartId) return void 0;
|
|
2628
|
+
const opts = await this.cartOptions(sponsorId);
|
|
2629
|
+
if (!opts.channelMissing) {
|
|
2630
|
+
const current = this.cartsBySponsor.get(sponsorId)?.cartId;
|
|
2631
|
+
if (current && current !== cartId) return { cartId: current, opts: await this.cartOptions(sponsorId) };
|
|
2632
|
+
return { cartId, opts };
|
|
2633
|
+
}
|
|
2634
|
+
const now = this.cartsBySponsor.get(sponsorId);
|
|
2635
|
+
if (now?.cartId === cartId) this.dropStaleBackendCart(sponsorId);
|
|
2636
|
+
const rebuilt = await this.ensureCartId(sponsorId, now?.currency || void 0, now?.shippingCountry || void 0);
|
|
2637
|
+
if (!rebuilt) return void 0;
|
|
2638
|
+
return { cartId: rebuilt, opts: await this.cartOptions(sponsorId) };
|
|
2639
|
+
}
|
|
2640
|
+
/**
|
|
2641
|
+
* The channel of a sponsor's cart is gone from the bootstrap (the campaign
|
|
2642
|
+
* moved, a refresh after hours): forget the backend cart and its line ids,
|
|
2643
|
+
* keep the lines, and remember them as they stand now for the next backend
|
|
2644
|
+
* cart (`carryOver`). Queued quantity syncs of the old cart are dropped —
|
|
2645
|
+
* their quantities are in the lines carried.
|
|
2646
|
+
*/
|
|
2647
|
+
dropStaleBackendCart(sponsorId) {
|
|
2648
|
+
const cart = this.cartsBySponsor.get(sponsorId);
|
|
2649
|
+
if (!cart?.cartId) return;
|
|
2650
|
+
const carried = cart.items.filter((item) => item.quantity > 0).map((item) => ({ productId: item.productId, variantId: item.variantId, origins: lineOrigins(item) }));
|
|
2651
|
+
delete cart.cartId;
|
|
2652
|
+
delete cart.channelId;
|
|
2653
|
+
for (const item of cart.items) delete item.cartItemId;
|
|
2654
|
+
for (const key of [...this.qtySyncs.keys()]) {
|
|
2655
|
+
if (key.startsWith(`${sponsorId}:`)) this.qtySyncs.delete(key);
|
|
2656
|
+
}
|
|
2657
|
+
this.carryOver.set(sponsorId, carried);
|
|
2658
|
+
this.rebuildEpoch.set(sponsorId, (this.rebuildEpoch.get(sponsorId) ?? 0) + 1);
|
|
2659
|
+
this.persist();
|
|
2660
|
+
}
|
|
2661
|
+
/** Give a new backend cart the lines of the one whose channel went away — each unit with its own origin. */
|
|
2662
|
+
async replayCarriedLines(sponsorId, cartId, carried, opts) {
|
|
2663
|
+
let last;
|
|
2664
|
+
const seq = this.nextSeq(sponsorId);
|
|
2665
|
+
try {
|
|
2666
|
+
const privacyMode = await currentPrivacyMode();
|
|
2667
|
+
for (const line of carried) {
|
|
2668
|
+
for (const origin of line.origins) {
|
|
2669
|
+
if (!(origin.quantity > 0)) continue;
|
|
2670
|
+
const { quantity, ...place } = origin;
|
|
2671
|
+
const wire = Object.keys(place).length ? lineOriginWire(normalizeOrigin(place), { page: currentOriginPage(), privacyMode }) : void 0;
|
|
2672
|
+
last = await addItem(
|
|
2673
|
+
cartId,
|
|
2674
|
+
[
|
|
2675
|
+
{
|
|
2676
|
+
product_id: Number(line.productId || 0),
|
|
2677
|
+
quantity,
|
|
2678
|
+
variant_id: line.variantId != null ? Number(line.variantId) : null,
|
|
2679
|
+
...wire ? { origin: wire } : {}
|
|
2680
|
+
}
|
|
2681
|
+
],
|
|
2682
|
+
opts
|
|
2683
|
+
);
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
} catch (err) {
|
|
2687
|
+
this.emitError("moving the cart to the current channel failed \u2014 some lines may not be in it", err);
|
|
2688
|
+
}
|
|
2689
|
+
const res = last;
|
|
2690
|
+
if (res && Array.isArray(res.line_items)) this.applyBackendCart(sponsorId, res, seq);
|
|
2691
|
+
}
|
|
2692
|
+
/**
|
|
2693
|
+
* Ensure the sponsor cart exists server-side; returns its backend cart id.
|
|
2694
|
+
* A new backend cart is created on the channel of the campaign in context —
|
|
2695
|
+
* `ctx.campaignId` (the add's origin), else the campaign the cart's lines
|
|
2696
|
+
* came from, else `Vio.init`'s — and remembers it (`channelId`). An existing
|
|
2697
|
+
* one whose channel the bootstrap no longer lists is created again on the
|
|
2698
|
+
* current channel, with its lines (`liveCart`).
|
|
2699
|
+
*/
|
|
2700
|
+
async ensureCartId(sponsorId, currency, shippingCountry, ctx = {}) {
|
|
2350
2701
|
const activeCurrency = currency || getGlobalCurrency();
|
|
2351
2702
|
const activeCountry = shippingCountry || getGlobalCountryCode();
|
|
2352
2703
|
let cart = this.cartsBySponsor.get(sponsorId);
|
|
@@ -2356,11 +2707,15 @@ var CartManager = class extends EventTarget {
|
|
|
2356
2707
|
} else {
|
|
2357
2708
|
cart.shippingCountry = activeCountry;
|
|
2358
2709
|
}
|
|
2359
|
-
if (cart.cartId)
|
|
2710
|
+
if (cart.cartId) {
|
|
2711
|
+
if (!cart.channelId) return cart.cartId;
|
|
2712
|
+
return (await this.liveCart(sponsorId))?.cartId;
|
|
2713
|
+
}
|
|
2360
2714
|
const inFlight = this.cartIdPromises.get(sponsorId);
|
|
2361
2715
|
if (inFlight) return inFlight;
|
|
2362
2716
|
const creation = (async () => {
|
|
2363
|
-
const
|
|
2717
|
+
const campaignId = ctx.campaignId ?? cartCampaignOf(cart);
|
|
2718
|
+
const opts = await getCartGraphQLOptions(sponsorId, campaignId !== void 0 ? { campaignId } : void 0);
|
|
2364
2719
|
if (!opts.sponsorResolved) {
|
|
2365
2720
|
this.emitError(`no commerce key resolved for sponsor ${sponsorId} \u2014 cart not synced`);
|
|
2366
2721
|
return void 0;
|
|
@@ -2375,6 +2730,8 @@ var CartManager = class extends EventTarget {
|
|
|
2375
2730
|
);
|
|
2376
2731
|
if (backendCart?.cart_id) {
|
|
2377
2732
|
cart.cartId = backendCart.cart_id;
|
|
2733
|
+
if (opts.channelId) cart.channelId = opts.channelId;
|
|
2734
|
+
else delete cart.channelId;
|
|
2378
2735
|
if (Array.isArray(backendCart.line_items) && backendCart.line_items.length > 0) {
|
|
2379
2736
|
this.updateFromBackendCart(sponsorId, backendCart);
|
|
2380
2737
|
} else {
|
|
@@ -2388,6 +2745,11 @@ var CartManager = class extends EventTarget {
|
|
|
2388
2745
|
this.persist();
|
|
2389
2746
|
this.emit();
|
|
2390
2747
|
}
|
|
2748
|
+
const carried = this.carryOver.get(sponsorId);
|
|
2749
|
+
if (carried) {
|
|
2750
|
+
this.carryOver.delete(sponsorId);
|
|
2751
|
+
if (carried.length > 0) await this.replayCarriedLines(sponsorId, backendCart.cart_id, carried, opts);
|
|
2752
|
+
}
|
|
2391
2753
|
}
|
|
2392
2754
|
} catch (err) {
|
|
2393
2755
|
this.emitError("createCart failed", err);
|
|
@@ -2480,7 +2842,7 @@ var CartManager = class extends EventTarget {
|
|
|
2480
2842
|
this.emit();
|
|
2481
2843
|
const syncedCartId = cart.cartId;
|
|
2482
2844
|
if (syncedCartId) {
|
|
2483
|
-
for (const id of removedBeforeSync) this.syncQuantity(sponsorId, syncedCartId, id, 0);
|
|
2845
|
+
for (const id of removedBeforeSync) this.syncQuantity(sponsorId, syncedCartId, id, 0, void 0, cart.channelId);
|
|
2484
2846
|
}
|
|
2485
2847
|
if (this.pendingQtyIntents.size > 0) {
|
|
2486
2848
|
const currentCart = this.cartsBySponsor.get(sponsorId);
|
|
@@ -2572,13 +2934,17 @@ var CartManager = class extends EventTarget {
|
|
|
2572
2934
|
this.emit();
|
|
2573
2935
|
const addedItem = existing ?? cart.items[cart.items.length - 1];
|
|
2574
2936
|
const addedLineId = addedItem.id;
|
|
2937
|
+
const epochAtAdd = this.rebuildEpoch.get(opts.sponsorId) ?? 0;
|
|
2575
2938
|
const seq = this.nextSeq(opts.sponsorId);
|
|
2576
2939
|
let settling;
|
|
2577
2940
|
const mutation = (async () => {
|
|
2578
2941
|
try {
|
|
2579
|
-
const cartId = await this.ensureCartId(opts.sponsorId, opts.currency || void 0
|
|
2942
|
+
const cartId = await this.ensureCartId(opts.sponsorId, opts.currency || void 0, void 0, {
|
|
2943
|
+
campaignId: opts.origin?.campaignId
|
|
2944
|
+
});
|
|
2945
|
+
if ((this.rebuildEpoch.get(opts.sponsorId) ?? 0) !== epochAtAdd) return;
|
|
2580
2946
|
if (cartId) {
|
|
2581
|
-
const gqlOpts = await
|
|
2947
|
+
const gqlOpts = await this.cartOptions(opts.sponsorId);
|
|
2582
2948
|
const origin = opts.origin ? lineOriginWire(normalizeOrigin(opts.origin), {
|
|
2583
2949
|
page: currentOriginPage(),
|
|
2584
2950
|
privacyMode: await currentPrivacyMode()
|
|
@@ -2647,7 +3013,7 @@ var CartManager = class extends EventTarget {
|
|
|
2647
3013
|
const addedOrigin = increase ? latestOrigin(item) : void 0;
|
|
2648
3014
|
if (target <= 0) {
|
|
2649
3015
|
cart.items = cart.items.filter((i) => i !== item);
|
|
2650
|
-
if (typeof document !== "undefined") {
|
|
3016
|
+
if (this.active && typeof document !== "undefined") {
|
|
2651
3017
|
document.dispatchEvent(
|
|
2652
3018
|
new CustomEvent("vio:removed-from-cart", {
|
|
2653
3019
|
bubbles: true,
|
|
@@ -2674,12 +3040,17 @@ var CartManager = class extends EventTarget {
|
|
|
2674
3040
|
if (cart.items.length === 0) this.cartsBySponsor.delete(sponsorId);
|
|
2675
3041
|
this.persist();
|
|
2676
3042
|
this.emit();
|
|
2677
|
-
if (!cart.cartId)
|
|
3043
|
+
if (!cart.cartId) {
|
|
3044
|
+
if (this.cartIdPromises.has(sponsorId)) {
|
|
3045
|
+
this.pendingQtyIntents.set(this.intentKey(item.productId, item.variantId), target);
|
|
3046
|
+
}
|
|
3047
|
+
return;
|
|
3048
|
+
}
|
|
2678
3049
|
if (!targetItemId) {
|
|
2679
3050
|
this.pendingQtyIntents.set(this.intentKey(item.productId, item.variantId), target);
|
|
2680
3051
|
return;
|
|
2681
3052
|
}
|
|
2682
|
-
this.syncQuantity(sponsorId, cart.cartId, targetItemId, target, addedOrigin);
|
|
3053
|
+
this.syncQuantity(sponsorId, cart.cartId, targetItemId, target, addedOrigin, cart.channelId);
|
|
2683
3054
|
}
|
|
2684
3055
|
/** Send a line's target quantity to the backend — ONE request in flight per
|
|
2685
3056
|
* line. Targets that arrive while one is in flight queue behind it as
|
|
@@ -2691,7 +3062,7 @@ var CartManager = class extends EventTarget {
|
|
|
2691
3062
|
* optimistic quantity through any backend response (see
|
|
2692
3063
|
* `updateFromBackendCart`); a rejection drops what was queued and
|
|
2693
3064
|
* reconciles the cart from the server. */
|
|
2694
|
-
syncQuantity(sponsorId, backendCartId, cartItemId, target, origin) {
|
|
3065
|
+
syncQuantity(sponsorId, backendCartId, cartItemId, target, origin, channelId) {
|
|
2695
3066
|
const key = this.qtySyncKey(sponsorId, cartItemId);
|
|
2696
3067
|
const active = this.qtySyncs.get(key);
|
|
2697
3068
|
if (active) {
|
|
@@ -2706,9 +3077,19 @@ var CartManager = class extends EventTarget {
|
|
|
2706
3077
|
let nextOrigin = origin;
|
|
2707
3078
|
let removalRetried = false;
|
|
2708
3079
|
while (next !== void 0) {
|
|
3080
|
+
let gqlOpts;
|
|
3081
|
+
if (this.cartsBySponsor.get(sponsorId)?.cartId) {
|
|
3082
|
+
const live = await this.liveCart(sponsorId);
|
|
3083
|
+
if (!live || live.cartId !== backendCartId) {
|
|
3084
|
+
if (this.qtySyncs.get(key) === sync) this.qtySyncs.delete(key);
|
|
3085
|
+
break;
|
|
3086
|
+
}
|
|
3087
|
+
gqlOpts = live.opts;
|
|
3088
|
+
} else {
|
|
3089
|
+
gqlOpts = await getCartGraphQLOptions(sponsorId, channelId ? { channelId, retired: true } : void 0);
|
|
3090
|
+
}
|
|
2709
3091
|
const seq = this.nextSeq(sponsorId);
|
|
2710
3092
|
try {
|
|
2711
|
-
const gqlOpts = await getCartGraphQLOptions(sponsorId);
|
|
2712
3093
|
const originWire = next > 0 && nextOrigin ? lineOriginWire(nextOrigin, { page: currentOriginPage(), privacyMode: await currentPrivacyMode() }) : void 0;
|
|
2713
3094
|
const resCart = next <= 0 ? await deleteItem(backendCartId, cartItemId, gqlOpts) : originWire ? await updateItem(backendCartId, cartItemId, null, next, gqlOpts, { origin: originWire }) : await updateItem(backendCartId, cartItemId, null, next, gqlOpts);
|
|
2714
3095
|
const step = sync.steps.shift();
|
|
@@ -2768,10 +3149,9 @@ var CartManager = class extends EventTarget {
|
|
|
2768
3149
|
}
|
|
2769
3150
|
/** Refresh the local cart from the backend (source of truth). */
|
|
2770
3151
|
async fetchCartFromBackend(sponsorId) {
|
|
2771
|
-
const
|
|
2772
|
-
if (!
|
|
2773
|
-
const
|
|
2774
|
-
const resCart = await getCart(cart.cartId, gqlOpts);
|
|
3152
|
+
const live = await this.liveCart(sponsorId);
|
|
3153
|
+
if (!live) return null;
|
|
3154
|
+
const resCart = await getCart(live.cartId, live.opts);
|
|
2775
3155
|
if (resCart) this.updateFromBackendCart(sponsorId, resCart);
|
|
2776
3156
|
return resCart;
|
|
2777
3157
|
}
|
|
@@ -2795,8 +3175,9 @@ var CartManager = class extends EventTarget {
|
|
|
2795
3175
|
if (!cart?.cartId) return cart;
|
|
2796
3176
|
let resCart;
|
|
2797
3177
|
try {
|
|
2798
|
-
const
|
|
2799
|
-
|
|
3178
|
+
const live = await this.liveCart(sponsorId);
|
|
3179
|
+
if (!live) return this.cartsBySponsor.get(sponsorId);
|
|
3180
|
+
resCart = await getCart(live.cartId, live.opts);
|
|
2800
3181
|
} catch (err) {
|
|
2801
3182
|
if (typeof console !== "undefined") {
|
|
2802
3183
|
console.warn("[CartManager] GetCart before the checkout failed \u2014 the local cart stands", err);
|
|
@@ -2815,7 +3196,7 @@ var CartManager = class extends EventTarget {
|
|
|
2815
3196
|
}
|
|
2816
3197
|
/** `vio:cart-updated` on `document` — see `CartUpdatedDetail`. */
|
|
2817
3198
|
emitCartUpdated(sponsorId, source) {
|
|
2818
|
-
if (typeof document === "undefined") return;
|
|
3199
|
+
if (!this.active || typeof document === "undefined") return;
|
|
2819
3200
|
const cart = this.cartsBySponsor.get(sponsorId);
|
|
2820
3201
|
const items = (cart?.items ?? []).map((item) => ({ ...item }));
|
|
2821
3202
|
const detail = {
|
|
@@ -2831,17 +3212,15 @@ var CartManager = class extends EventTarget {
|
|
|
2831
3212
|
}
|
|
2832
3213
|
/** Line items grouped by supplier (shipping is per-supplier server-side). */
|
|
2833
3214
|
async fetchLineItemsBySupplier(sponsorId) {
|
|
2834
|
-
const
|
|
2835
|
-
if (!
|
|
2836
|
-
|
|
2837
|
-
return getLineItemsBySupplier(cart.cartId, gqlOpts);
|
|
3215
|
+
const live = await this.liveCart(sponsorId);
|
|
3216
|
+
if (!live) return null;
|
|
3217
|
+
return getLineItemsBySupplier(live.cartId, live.opts);
|
|
2838
3218
|
}
|
|
2839
3219
|
/** Set the chosen shipping option per supplier on the backend cart. */
|
|
2840
3220
|
async updateShippingsBySupplier(sponsorId, data) {
|
|
2841
|
-
const
|
|
2842
|
-
if (!
|
|
2843
|
-
const
|
|
2844
|
-
const resCart = await updateShippingsBySupplier(cart.cartId, data, gqlOpts);
|
|
3221
|
+
const live = await this.liveCart(sponsorId);
|
|
3222
|
+
if (!live) return null;
|
|
3223
|
+
const resCart = await updateShippingsBySupplier(live.cartId, data, live.opts);
|
|
2845
3224
|
if (resCart && Array.isArray(resCart.line_items)) {
|
|
2846
3225
|
this.updateFromBackendCart(sponsorId, resCart);
|
|
2847
3226
|
}
|
|
@@ -2881,19 +3260,23 @@ var CartManager = class extends EventTarget {
|
|
|
2881
3260
|
return formatPrice(this.totalAcrossSponsors, this.primaryCurrency);
|
|
2882
3261
|
}
|
|
2883
3262
|
// MARK: - Persistence
|
|
3263
|
+
/**
|
|
3264
|
+
* Keep the carts for the next page and the other tabs. Where storage
|
|
3265
|
+
* refuses (in-app browsers, private modes) nothing throws (safe-storage.ts):
|
|
3266
|
+
* the carts stay in this manager's own map, the add to cart and the
|
|
3267
|
+
* checkout go on, and the cart just does not survive a reload there.
|
|
3268
|
+
*/
|
|
2884
3269
|
persist() {
|
|
2885
|
-
if (typeof localStorage === "undefined") return;
|
|
2886
3270
|
try {
|
|
2887
3271
|
const obj = {};
|
|
2888
3272
|
for (const [k, v] of this.cartsBySponsor) obj[String(k)] = v;
|
|
2889
|
-
|
|
3273
|
+
storageSet("local", this.storageKey, JSON.stringify(obj), { memory: false });
|
|
2890
3274
|
} catch {
|
|
2891
3275
|
}
|
|
2892
3276
|
}
|
|
2893
|
-
loadFromStorage() {
|
|
2894
|
-
if (typeof localStorage === "undefined") return /* @__PURE__ */ new Map();
|
|
3277
|
+
loadFromStorage(key = this.storageKey) {
|
|
2895
3278
|
try {
|
|
2896
|
-
const raw =
|
|
3279
|
+
const raw = storageGet("local", key);
|
|
2897
3280
|
if (!raw) return /* @__PURE__ */ new Map();
|
|
2898
3281
|
const obj = JSON.parse(raw);
|
|
2899
3282
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -3044,6 +3427,56 @@ function findSponsorIn(boot, sponsorId) {
|
|
|
3044
3427
|
}
|
|
3045
3428
|
return void 0;
|
|
3046
3429
|
}
|
|
3430
|
+
function channelIdOf(value) {
|
|
3431
|
+
if (value === null || value === void 0) return void 0;
|
|
3432
|
+
const s = String(value).trim();
|
|
3433
|
+
return s ? s : void 0;
|
|
3434
|
+
}
|
|
3435
|
+
function sells(s) {
|
|
3436
|
+
const commerce = s?.commerce;
|
|
3437
|
+
if (!commerce || typeof commerce !== "object") return false;
|
|
3438
|
+
const key = commerce.apiKey;
|
|
3439
|
+
return typeof key === "string" && key.trim() !== "";
|
|
3440
|
+
}
|
|
3441
|
+
function sellingBlocksIn(boot, sponsorId) {
|
|
3442
|
+
const id = toSponsorId(sponsorId);
|
|
3443
|
+
const out = [];
|
|
3444
|
+
if (id === void 0 || !boot || typeof boot !== "object") return out;
|
|
3445
|
+
const take = (s, campaignId) => {
|
|
3446
|
+
if (!s || typeof s !== "object" || Number(s.id) !== id || !sells(s)) return;
|
|
3447
|
+
out.push({ campaignId: toCampaignId(campaignId), sponsor: s });
|
|
3448
|
+
};
|
|
3449
|
+
try {
|
|
3450
|
+
const defaultId = boot.campaign?.id;
|
|
3451
|
+
take(boot.primarySponsor, defaultId);
|
|
3452
|
+
if (Array.isArray(boot.secondarySponsors)) for (const s of boot.secondarySponsors) take(s, defaultId);
|
|
3453
|
+
const campaigns = Array.isArray(boot.campaigns) ? boot.campaigns : [];
|
|
3454
|
+
for (const c of campaigns) {
|
|
3455
|
+
if (!c || typeof c !== "object") continue;
|
|
3456
|
+
take(c.primarySponsor, c.id);
|
|
3457
|
+
if (Array.isArray(c.secondarySponsors)) for (const s of c.secondarySponsors) take(s, c.id);
|
|
3458
|
+
}
|
|
3459
|
+
} catch {
|
|
3460
|
+
}
|
|
3461
|
+
return out;
|
|
3462
|
+
}
|
|
3463
|
+
function sponsorCommerceIn(boot, sponsorId, ctx = {}) {
|
|
3464
|
+
try {
|
|
3465
|
+
const blocks = sellingBlocksIn(boot, sponsorId);
|
|
3466
|
+
if (blocks.length === 0) return void 0;
|
|
3467
|
+
const channel = channelIdOf(ctx?.channelId);
|
|
3468
|
+
if (channel !== void 0) {
|
|
3469
|
+
return blocks.find((b) => channelIdOf(b.sponsor.commerce.channelId) === channel)?.sponsor;
|
|
3470
|
+
}
|
|
3471
|
+
for (const campaignId of campaignCandidates(ctx?.campaignId)) {
|
|
3472
|
+
const found = blocks.find((b) => b.campaignId === campaignId);
|
|
3473
|
+
if (found) return found.sponsor;
|
|
3474
|
+
}
|
|
3475
|
+
return blocks[0].sponsor;
|
|
3476
|
+
} catch {
|
|
3477
|
+
return void 0;
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3047
3480
|
function sponsorIdentityFrom(boot, sponsorId) {
|
|
3048
3481
|
try {
|
|
3049
3482
|
const id = toSponsorId(sponsorId);
|
|
@@ -3055,13 +3488,15 @@ function sponsorIdentityFrom(boot, sponsorId) {
|
|
|
3055
3488
|
if (!name && !logoUrl) return null;
|
|
3056
3489
|
const termsUrl = pageUrlOrNull(sponsor.termsUrl);
|
|
3057
3490
|
const refundPolicyUrl = pageUrlOrNull(sponsor.refundPolicyUrl);
|
|
3491
|
+
const highlights = highlightsOf(sponsor.highlights);
|
|
3058
3492
|
return {
|
|
3059
3493
|
id,
|
|
3060
3494
|
name,
|
|
3061
3495
|
logoUrl,
|
|
3062
3496
|
avatarUrl: urlOrNull(sponsor.avatarUrl),
|
|
3063
3497
|
...termsUrl ? { termsUrl } : {},
|
|
3064
|
-
...refundPolicyUrl ? { refundPolicyUrl } : {}
|
|
3498
|
+
...refundPolicyUrl ? { refundPolicyUrl } : {},
|
|
3499
|
+
...highlights.length ? { highlights } : {}
|
|
3065
3500
|
};
|
|
3066
3501
|
} catch {
|
|
3067
3502
|
return null;
|
|
@@ -3087,7 +3522,8 @@ function normalizeEntry(raw) {
|
|
|
3087
3522
|
const checkoutId = typeof r.checkoutId === "string" ? r.checkoutId.trim() : "";
|
|
3088
3523
|
const sponsorId = toSponsorId(r.sponsorId);
|
|
3089
3524
|
if (!checkoutId || sponsorId === void 0) return null;
|
|
3090
|
-
|
|
3525
|
+
const channelId = channelIdOf(r.channelId);
|
|
3526
|
+
return { checkoutId, sponsorId, name: nameOf(r.name), logoUrl: urlOrNull(r.logoUrl), ...channelId ? { channelId } : {} };
|
|
3091
3527
|
}
|
|
3092
3528
|
function readEntries() {
|
|
3093
3529
|
const store = storageRefusedWrite ? null : sessionStore();
|
|
@@ -3127,8 +3563,9 @@ function rememberCheckoutSponsor(checkoutId, sponsor) {
|
|
|
3127
3563
|
name = previous.name;
|
|
3128
3564
|
logoUrl = previous.logoUrl;
|
|
3129
3565
|
}
|
|
3566
|
+
const channelId = channelIdOf(sponsor.channelId) ?? (previous && previous.sponsorId === sponsorId ? previous.channelId : void 0);
|
|
3130
3567
|
const next = entries.filter((e) => e.checkoutId !== id);
|
|
3131
|
-
next.push({ checkoutId: id, sponsorId, name, logoUrl });
|
|
3568
|
+
next.push({ checkoutId: id, sponsorId, name, logoUrl, ...channelId ? { channelId } : {} });
|
|
3132
3569
|
writeEntries(next.slice(-CHECKOUT_SPONSOR_MEMORY_MAX));
|
|
3133
3570
|
} catch {
|
|
3134
3571
|
}
|
|
@@ -3156,6 +3593,20 @@ function rememberedSponsor(sponsorId) {
|
|
|
3156
3593
|
return null;
|
|
3157
3594
|
}
|
|
3158
3595
|
}
|
|
3596
|
+
function highlightsOf(value) {
|
|
3597
|
+
if (!Array.isArray(value)) return [];
|
|
3598
|
+
const out = [];
|
|
3599
|
+
for (const item of value) {
|
|
3600
|
+
if (!item || typeof item !== "object") continue;
|
|
3601
|
+
const { icon, title, text: text3 } = item;
|
|
3602
|
+
const t = typeof title === "string" ? title.trim() : "";
|
|
3603
|
+
if (!t) continue;
|
|
3604
|
+
const body = typeof text3 === "string" ? text3.trim() : "";
|
|
3605
|
+
out.push({ icon: typeof icon === "string" ? icon.trim() : "", title: t, ...body ? { text: body } : {} });
|
|
3606
|
+
if (out.length === 3) break;
|
|
3607
|
+
}
|
|
3608
|
+
return out;
|
|
3609
|
+
}
|
|
3159
3610
|
|
|
3160
3611
|
// src/core/checkout/payments/apple-pay.ts
|
|
3161
3612
|
var STRIPE_JS_URL = "https://js.stripe.com/v3";
|
|
@@ -3353,7 +3804,7 @@ async function prepareApplePay(config) {
|
|
|
3353
3804
|
}
|
|
3354
3805
|
|
|
3355
3806
|
// src/core/version.ts
|
|
3356
|
-
var SDK_VERSION = "0.
|
|
3807
|
+
var SDK_VERSION = "0.33.0";
|
|
3357
3808
|
|
|
3358
3809
|
// src/core/checkout/payments/stripe-embedded.ts
|
|
3359
3810
|
var CREATE_PAYMENT_INTENT_STRIPE_MUTATION = `
|
|
@@ -3519,11 +3970,8 @@ async function mountKlarnaExpressButton(opts) {
|
|
|
3519
3970
|
const returnUrl = opts.returnUrl ?? (typeof window !== "undefined" ? window.location.origin + window.location.pathname : "");
|
|
3520
3971
|
let settled = false;
|
|
3521
3972
|
button.on("click", () => {
|
|
3522
|
-
if (opts.pendingKey && opts.pendingContext
|
|
3523
|
-
|
|
3524
|
-
sessionStorage.setItem(opts.pendingKey, JSON.stringify(opts.pendingContext));
|
|
3525
|
-
} catch {
|
|
3526
|
-
}
|
|
3973
|
+
if (opts.pendingKey && opts.pendingContext) {
|
|
3974
|
+
storageSet("session", opts.pendingKey, JSON.stringify(opts.pendingContext));
|
|
3527
3975
|
}
|
|
3528
3976
|
const promise = sdk.Payment.initiate(() => ({
|
|
3529
3977
|
currency: opts.paymentRequest.currency,
|
|
@@ -4601,6 +5049,74 @@ function adyenReturnOutcome(payment) {
|
|
|
4601
5049
|
}
|
|
4602
5050
|
}
|
|
4603
5051
|
|
|
5052
|
+
// src/core/checkout/phone.ts
|
|
5053
|
+
var CALLING_CODES = {
|
|
5054
|
+
NO: "47",
|
|
5055
|
+
SE: "46",
|
|
5056
|
+
DK: "45",
|
|
5057
|
+
FI: "358",
|
|
5058
|
+
IS: "354",
|
|
5059
|
+
DE: "49",
|
|
5060
|
+
GB: "44",
|
|
5061
|
+
UK: "44",
|
|
5062
|
+
IE: "353",
|
|
5063
|
+
NL: "31",
|
|
5064
|
+
BE: "32",
|
|
5065
|
+
FR: "33",
|
|
5066
|
+
ES: "34",
|
|
5067
|
+
PT: "351",
|
|
5068
|
+
IT: "39",
|
|
5069
|
+
AT: "43",
|
|
5070
|
+
CH: "41",
|
|
5071
|
+
PL: "48",
|
|
5072
|
+
EE: "372",
|
|
5073
|
+
LV: "371",
|
|
5074
|
+
LT: "370",
|
|
5075
|
+
CZ: "420",
|
|
5076
|
+
SK: "421",
|
|
5077
|
+
HU: "36",
|
|
5078
|
+
US: "1",
|
|
5079
|
+
CA: "1"
|
|
5080
|
+
};
|
|
5081
|
+
var KNOWN_CODES = [...new Set(Object.values(CALLING_CODES))].sort((a, b) => b.length - a.length);
|
|
5082
|
+
var NATIONAL_LENGTH = {
|
|
5083
|
+
"47": [8, 8],
|
|
5084
|
+
"45": [8, 8],
|
|
5085
|
+
"46": [7, 9],
|
|
5086
|
+
"358": [6, 10],
|
|
5087
|
+
"49": [10, 11],
|
|
5088
|
+
"44": [10, 10],
|
|
5089
|
+
"1": [10, 10]
|
|
5090
|
+
};
|
|
5091
|
+
function callingCodeFor(country) {
|
|
5092
|
+
return CALLING_CODES[String(country ?? "").trim().toUpperCase()] ?? null;
|
|
5093
|
+
}
|
|
5094
|
+
function parsePhone(raw, country) {
|
|
5095
|
+
const typed = String(raw ?? "").trim().replace(/[\s\-().]/g, "");
|
|
5096
|
+
if (!typed) return null;
|
|
5097
|
+
let code = null;
|
|
5098
|
+
let national;
|
|
5099
|
+
if (/^(\+|00)/.test(typed)) {
|
|
5100
|
+
const digits = typed.replace(/^(\+|00)/, "");
|
|
5101
|
+
if (!/^\d+$/.test(digits)) return null;
|
|
5102
|
+
code = KNOWN_CODES.find((c) => digits.startsWith(c)) ?? null;
|
|
5103
|
+
if (!code) return null;
|
|
5104
|
+
national = digits.slice(code.length);
|
|
5105
|
+
} else {
|
|
5106
|
+
if (!/^\d+$/.test(typed)) return null;
|
|
5107
|
+
code = callingCodeFor(country);
|
|
5108
|
+
if (!code) return null;
|
|
5109
|
+
national = typed;
|
|
5110
|
+
}
|
|
5111
|
+
if (national.startsWith("0") && code !== "47" && code !== "45") national = national.slice(1);
|
|
5112
|
+
const [min, max] = NATIONAL_LENGTH[code] ?? [6, 12];
|
|
5113
|
+
if (national.length < min || national.length > max) return null;
|
|
5114
|
+
return { phone: national, phone_code: code };
|
|
5115
|
+
}
|
|
5116
|
+
function isValidPhone(raw, country) {
|
|
5117
|
+
return parsePhone(raw, country) !== null;
|
|
5118
|
+
}
|
|
5119
|
+
|
|
4604
5120
|
// src/core/checkout/checkout-manager.ts
|
|
4605
5121
|
function describeError(err) {
|
|
4606
5122
|
if (err instanceof Error) return err.message;
|
|
@@ -4618,6 +5134,7 @@ function describeError(err) {
|
|
|
4618
5134
|
}
|
|
4619
5135
|
return String(err);
|
|
4620
5136
|
}
|
|
5137
|
+
var KLARNA_CONFIRMED_KEY = "vio.klarna.confirmed.v1";
|
|
4621
5138
|
var KLARNA_PENDING_KEY = "vio.klarna.pending.v1";
|
|
4622
5139
|
var KLARNA_SHIPPING_OPTIONS = [
|
|
4623
5140
|
{
|
|
@@ -4781,15 +5298,20 @@ function buildCheckoutAddress(address) {
|
|
|
4781
5298
|
const zip = address.postalCode || address.postal_code || address.zip || null;
|
|
4782
5299
|
const country_code = address.countryCode || address.country_code || address.country || getGlobalCountryCode();
|
|
4783
5300
|
if (!firstName && !lastName && !address1 && !city && !zip) return null;
|
|
5301
|
+
const phone = parsePhone(address.phone, country_code);
|
|
4784
5302
|
return {
|
|
4785
5303
|
first_name: firstName,
|
|
4786
5304
|
last_name: lastName,
|
|
4787
5305
|
address1,
|
|
4788
5306
|
city,
|
|
4789
5307
|
zip,
|
|
4790
|
-
country_code
|
|
5308
|
+
country_code,
|
|
5309
|
+
...phone ? { phone: phone.phone, phone_code: phone.phone_code } : {}
|
|
4791
5310
|
};
|
|
4792
5311
|
}
|
|
5312
|
+
function isCompleteCheckoutAddress(a) {
|
|
5313
|
+
return !!a && ["first_name", "last_name", "address1", "city", "zip"].every((k) => String(a[k] ?? "").trim().length > 0);
|
|
5314
|
+
}
|
|
4793
5315
|
function adyenReturnUrl(params) {
|
|
4794
5316
|
let page = null;
|
|
4795
5317
|
if (typeof window !== "undefined" && window.location?.href) {
|
|
@@ -4851,8 +5373,20 @@ function resolveHttpsReturnUrl(overrideUrl, params = null) {
|
|
|
4851
5373
|
}
|
|
4852
5374
|
return url;
|
|
4853
5375
|
}
|
|
4854
|
-
async function executeKlarnaGraphQL(query, variables,
|
|
4855
|
-
return executeCartGraphQL(query, variables,
|
|
5376
|
+
async function executeKlarnaGraphQL(query, variables, options) {
|
|
5377
|
+
return executeCartGraphQL(query, variables, options);
|
|
5378
|
+
}
|
|
5379
|
+
function usesStripe(methods) {
|
|
5380
|
+
if (!Array.isArray(methods)) return false;
|
|
5381
|
+
return methods.some((m) => {
|
|
5382
|
+
if (String(m?.name ?? "").toLowerCase() !== "stripe") return false;
|
|
5383
|
+
const config = Array.isArray(m?.config) ? m.config : [];
|
|
5384
|
+
const key = config.find((c) => c?.name === "publishableKey")?.value;
|
|
5385
|
+
return typeof key === "string" && key.startsWith("pk_");
|
|
5386
|
+
});
|
|
5387
|
+
}
|
|
5388
|
+
function cartTotal(items) {
|
|
5389
|
+
return items.reduce((sum, i) => sum + (Number(i.unitPrice) || 0) * (Number(i.quantity) || 0), 0);
|
|
4856
5390
|
}
|
|
4857
5391
|
var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
4858
5392
|
constructor(cartManager, deps = {}) {
|
|
@@ -4907,7 +5441,9 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
4907
5441
|
/** In-flight `getOrderReference` per checkout id (see there). */
|
|
4908
5442
|
this.referenceInFlight = /* @__PURE__ */ new Map();
|
|
4909
5443
|
this.kustomController = null;
|
|
4910
|
-
|
|
5444
|
+
if (Configuration.isInitialized && Configuration.get()?.stripePublishableKey) {
|
|
5445
|
+
preloadStripeJs();
|
|
5446
|
+
}
|
|
4911
5447
|
if (typeof cartManager.addEventListener === "function") {
|
|
4912
5448
|
cartManager.addEventListener("change", () => this.onCartChange());
|
|
4913
5449
|
}
|
|
@@ -4921,8 +5457,44 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
4921
5457
|
return this.currentStateValue;
|
|
4922
5458
|
}
|
|
4923
5459
|
set state(next) {
|
|
5460
|
+
if (next?.checkoutId && next.sponsorId && !next.channelId) {
|
|
5461
|
+
const remembered = rememberedCheckoutSponsor(next.checkoutId);
|
|
5462
|
+
const channelId = (remembered?.sponsorId === next.sponsorId ? remembered.channelId : void 0) ?? this.cartManager.getCart(next.sponsorId)?.channelId;
|
|
5463
|
+
if (channelId) next = { ...next, channelId };
|
|
5464
|
+
}
|
|
4924
5465
|
this.currentStateValue = next;
|
|
4925
|
-
if (next?.checkoutId && next.sponsorId)
|
|
5466
|
+
if (next?.checkoutId && next.sponsorId) {
|
|
5467
|
+
this.rememberSponsorOfCheckout(next.checkoutId, next.sponsorId, next.channelId);
|
|
5468
|
+
}
|
|
5469
|
+
}
|
|
5470
|
+
/**
|
|
5471
|
+
* The options of a call for a sponsor's cart or checkout: the key of the
|
|
5472
|
+
* channel the checkout lives on — what this tab remembered for the
|
|
5473
|
+
* checkout (a return from a redirect, after the cart was cleared), the open
|
|
5474
|
+
* checkout's, else the cart's — even if a bootstrap refresh no longer lists
|
|
5475
|
+
* it (an open checkout keeps paying with its own key). Without any, the
|
|
5476
|
+
* sponsor's block as `getCartGraphQLOptions` resolves it.
|
|
5477
|
+
*/
|
|
5478
|
+
async gqlOptions(sponsorId, checkoutId) {
|
|
5479
|
+
const channelId = this.channelOf(sponsorId, checkoutId);
|
|
5480
|
+
return getCartGraphQLOptions(sponsorId, channelId ? { channelId, retired: true } : void 0);
|
|
5481
|
+
}
|
|
5482
|
+
/** See `gqlOptions`. */
|
|
5483
|
+
channelOf(sponsorId, checkoutId) {
|
|
5484
|
+
try {
|
|
5485
|
+
if (!sponsorId) return void 0;
|
|
5486
|
+
const state = this.state?.sponsorId === sponsorId ? this.state : null;
|
|
5487
|
+
const id = checkoutId ?? state?.checkoutId;
|
|
5488
|
+
if (id) {
|
|
5489
|
+
const remembered = rememberedCheckoutSponsor(id);
|
|
5490
|
+
if (remembered?.channelId && remembered.sponsorId === sponsorId) return remembered.channelId;
|
|
5491
|
+
if (state?.checkoutId === id && state.channelId) return state.channelId;
|
|
5492
|
+
}
|
|
5493
|
+
const cart = this.cartManager.getCart(sponsorId);
|
|
5494
|
+
return cart?.cartId ? cart.channelId : void 0;
|
|
5495
|
+
} catch {
|
|
5496
|
+
return void 0;
|
|
5497
|
+
}
|
|
4926
5498
|
}
|
|
4927
5499
|
/** The open checkout's lines as a signature, to tell a real change from an echo. */
|
|
4928
5500
|
cartSignature(sponsorId) {
|
|
@@ -4944,6 +5516,9 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
4944
5516
|
if (!cart || cart.items.length === 0) {
|
|
4945
5517
|
throw new Error(`[VioCheckout] sponsor ${sponsorId} has no cart items`);
|
|
4946
5518
|
}
|
|
5519
|
+
if (!(cartTotal(cart.items) > 0)) {
|
|
5520
|
+
throw new Error(`[VioCheckout] sponsor ${sponsorId} has a cart that totals 0`);
|
|
5521
|
+
}
|
|
4947
5522
|
this.state = {
|
|
4948
5523
|
sponsorId,
|
|
4949
5524
|
session: ++this.sessionSeq,
|
|
@@ -4994,7 +5569,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
4994
5569
|
throw new Error(`[CheckoutManager] Failed to obtain cart_id for sponsor ${sponsorId}`);
|
|
4995
5570
|
}
|
|
4996
5571
|
}
|
|
4997
|
-
const opts = await
|
|
5572
|
+
const opts = await this.gqlOptions(sponsorId);
|
|
4998
5573
|
const attribution = await this.attributionFor(sponsorId);
|
|
4999
5574
|
const checkout = attribution ? await createCheckout(cartId, opts, { attribution }) : await createCheckout(cartId, opts);
|
|
5000
5575
|
if (checkout?.id) {
|
|
@@ -5059,10 +5634,25 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5059
5634
|
} catch {
|
|
5060
5635
|
}
|
|
5061
5636
|
}
|
|
5637
|
+
/**
|
|
5638
|
+
* Nothing is created or paid for a cart that is empty or totals 0 — as
|
|
5639
|
+
* the SERVER has it (the callers read it from the server first). Throws,
|
|
5640
|
+
* so a payment button ends in its error path, never at a provider asking
|
|
5641
|
+
* for 0 kr.
|
|
5642
|
+
*/
|
|
5643
|
+
assertPayableCart(sponsorId) {
|
|
5644
|
+
const cart = this.cartManager.getCart(sponsorId);
|
|
5645
|
+
if (!cart || !Array.isArray(cart.items) || cart.items.length === 0) {
|
|
5646
|
+
throw new Error(`[CheckoutManager] the cart of sponsor ${sponsorId} is empty \u2014 nothing to pay`);
|
|
5647
|
+
}
|
|
5648
|
+
if (!(cartTotal(cart.items) > 0)) {
|
|
5649
|
+
throw new Error(`[CheckoutManager] the cart of sponsor ${sponsorId} totals 0 \u2014 nothing to pay`);
|
|
5650
|
+
}
|
|
5651
|
+
}
|
|
5062
5652
|
/** Update the backend checkout (terms are re-asserted unless overridden; the attribution rides along unless the caller gives its own). */
|
|
5063
5653
|
async updateCheckout(variables, sponsorId) {
|
|
5064
5654
|
const spId = sponsorId ?? this.state?.sponsorId;
|
|
5065
|
-
const opts = await
|
|
5655
|
+
const opts = await this.gqlOptions(spId);
|
|
5066
5656
|
const attribution = "attribution" in variables ? void 0 : await this.attributionFor(spId);
|
|
5067
5657
|
const fullVars = {
|
|
5068
5658
|
buyerAcceptsPurchaseConditions: true,
|
|
@@ -5078,7 +5668,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5078
5668
|
return updated;
|
|
5079
5669
|
}
|
|
5080
5670
|
async getCheckout(checkoutId, sponsorId) {
|
|
5081
|
-
const opts = await
|
|
5671
|
+
const opts = await this.gqlOptions(sponsorId ?? this.sponsorIdOfCheckout(checkoutId) ?? this.state?.sponsorId, checkoutId);
|
|
5082
5672
|
return getCheckout(checkoutId, opts);
|
|
5083
5673
|
}
|
|
5084
5674
|
/**
|
|
@@ -5101,8 +5691,9 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5101
5691
|
if (!request) {
|
|
5102
5692
|
const asked = (async () => {
|
|
5103
5693
|
try {
|
|
5104
|
-
const opts = await
|
|
5105
|
-
sponsorId ?? this.sponsorIdOfCheckout(checkoutId) ?? this.state?.sponsorId
|
|
5694
|
+
const opts = await this.gqlOptions(
|
|
5695
|
+
sponsorId ?? this.sponsorIdOfCheckout(checkoutId) ?? this.state?.sponsorId,
|
|
5696
|
+
checkoutId
|
|
5106
5697
|
);
|
|
5107
5698
|
return await getCheckoutReference(checkoutId, opts);
|
|
5108
5699
|
} catch {
|
|
@@ -5155,7 +5746,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5155
5746
|
* sponsor's name and logo as known now — so a confirmation after a redirect
|
|
5156
5747
|
* or a reload can name the brand. Written again only when something changed.
|
|
5157
5748
|
*/
|
|
5158
|
-
rememberSponsorOfCheckout(checkoutId, sponsorId) {
|
|
5749
|
+
rememberSponsorOfCheckout(checkoutId, sponsorId, channelId) {
|
|
5159
5750
|
try {
|
|
5160
5751
|
let identity = null;
|
|
5161
5752
|
try {
|
|
@@ -5165,10 +5756,10 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5165
5756
|
}
|
|
5166
5757
|
const name = identity?.name || this.cartManager.getCart(sponsorId)?.sponsorName || "";
|
|
5167
5758
|
const logoUrl = identity?.logoUrl ?? null;
|
|
5168
|
-
const key = JSON.stringify([checkoutId, sponsorId, name, logoUrl]);
|
|
5759
|
+
const key = JSON.stringify([checkoutId, sponsorId, name, logoUrl, channelId ?? null]);
|
|
5169
5760
|
if (key === this.lastRememberedSponsor) return;
|
|
5170
5761
|
this.lastRememberedSponsor = key;
|
|
5171
|
-
rememberCheckoutSponsor(checkoutId, { sponsorId, name, logoUrl });
|
|
5762
|
+
rememberCheckoutSponsor(checkoutId, { sponsorId, name, logoUrl, channelId });
|
|
5172
5763
|
} catch {
|
|
5173
5764
|
}
|
|
5174
5765
|
}
|
|
@@ -5186,9 +5777,10 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5186
5777
|
if (inFlight) return inFlight;
|
|
5187
5778
|
const promise = (async () => {
|
|
5188
5779
|
try {
|
|
5189
|
-
const opts = await
|
|
5780
|
+
const opts = await this.gqlOptions(spId);
|
|
5190
5781
|
const res = await getAvailablePaymentMethods(opts);
|
|
5191
5782
|
if (res) this.paymentMethodsCache.set(spId, res);
|
|
5783
|
+
if (usesStripe(res)) preloadStripeJs();
|
|
5192
5784
|
return res;
|
|
5193
5785
|
} finally {
|
|
5194
5786
|
this.paymentMethodsPromises.delete(spId);
|
|
@@ -5222,7 +5814,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5222
5814
|
cartId = await this.cartManager.ensureCartId(spId);
|
|
5223
5815
|
}
|
|
5224
5816
|
if (!cartId) return [];
|
|
5225
|
-
const opts = await
|
|
5817
|
+
const opts = await this.gqlOptions(spId);
|
|
5226
5818
|
const supplierGroups = await getLineItemsBySupplier(cartId, opts);
|
|
5227
5819
|
this.shippingsResolved = Array.isArray(supplierGroups);
|
|
5228
5820
|
const firstGroup = Array.isArray(supplierGroups) ? supplierGroups[0] : null;
|
|
@@ -5276,7 +5868,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5276
5868
|
if (!spId) return null;
|
|
5277
5869
|
const cart = this.cartManager.getCart(spId);
|
|
5278
5870
|
if (!cart?.cartId) return null;
|
|
5279
|
-
const opts = await
|
|
5871
|
+
const opts = await this.gqlOptions(spId);
|
|
5280
5872
|
const updated = await updateShippingsBySupplier(cart.cartId, data, opts);
|
|
5281
5873
|
if (updated) {
|
|
5282
5874
|
this.cartManager.updateFromBackendCart(spId, updated);
|
|
@@ -5288,11 +5880,21 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5288
5880
|
* backend cart + checkout exist, push email/address onto the checkout, and
|
|
5289
5881
|
* return everything the payment mutation needs.
|
|
5290
5882
|
*/
|
|
5291
|
-
async prepareRedirectPayment(sponsorId, formData, extraUpdateVars = {}, leaving = false) {
|
|
5883
|
+
async prepareRedirectPayment(sponsorId, formData, extraUpdateVars = {}, leaving = false, vippsWithAddress = false) {
|
|
5292
5884
|
const spId = sponsorId ?? this.state?.sponsorId;
|
|
5293
5885
|
if (!spId) throw new Error("[CheckoutManager] no sponsor for payment");
|
|
5294
5886
|
await this.cartManager.waitForCartMutations(spId);
|
|
5295
5887
|
await this.cartManager.refreshFromServer(spId);
|
|
5888
|
+
this.assertPayableCart(spId);
|
|
5889
|
+
const isVipps = extraUpdateVars?.paymentMethod === "Vipps";
|
|
5890
|
+
const addr = typeof formData === "object" && formData !== null ? formData : this.state?.address;
|
|
5891
|
+
const built = buildCheckoutAddress(addr);
|
|
5892
|
+
if (isVipps && vippsWithAddress && !(isCompleteCheckoutAddress(built) && built?.phone)) {
|
|
5893
|
+
throw new Error(
|
|
5894
|
+
"[CheckoutManager] the standard Vipps payment needs the complete delivery address (name, street, postcode, city and a mobile number) \u2014 no payment started"
|
|
5895
|
+
);
|
|
5896
|
+
}
|
|
5897
|
+
const addressObj = !isVipps ? built : vippsWithAddress ? built : null;
|
|
5296
5898
|
const cart = this.cartManager.getCart(spId);
|
|
5297
5899
|
let cartId = cart?.cartId;
|
|
5298
5900
|
if (!cartId) {
|
|
@@ -5301,7 +5903,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5301
5903
|
if (!cartId) {
|
|
5302
5904
|
throw new Error(`[CheckoutManager] Failed to obtain cart_id for sponsor ${spId}`);
|
|
5303
5905
|
}
|
|
5304
|
-
const opts = await
|
|
5906
|
+
const opts = await this.gqlOptions(spId);
|
|
5305
5907
|
const attribution = await this.attributionFor(spId);
|
|
5306
5908
|
let checkoutId = this.state?.checkoutId;
|
|
5307
5909
|
if (!checkoutId) {
|
|
@@ -5315,9 +5917,6 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5315
5917
|
if (!checkoutId) {
|
|
5316
5918
|
throw new Error("[CheckoutManager] no backend checkout \u2014 cannot start the payment");
|
|
5317
5919
|
}
|
|
5318
|
-
const isVipps = extraUpdateVars?.paymentMethod === "Vipps";
|
|
5319
|
-
const addr = typeof formData === "object" && formData !== null ? formData : this.state?.address;
|
|
5320
|
-
const addressObj = !isVipps ? buildCheckoutAddress(addr) : null;
|
|
5321
5920
|
const emailVal = (typeof formData === "string" ? formData : formData?.email) || this.state?.address?.email || "";
|
|
5322
5921
|
const hasEmail = !!emailVal && emailVal.includes("@");
|
|
5323
5922
|
if (!hasEmail && !isVipps) {
|
|
@@ -5412,6 +6011,11 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5412
6011
|
* so the caller can open the ordinary checkout instead. Without the flag
|
|
5413
6012
|
* the backend decides: Express while the cart has no delivery yet, a
|
|
5414
6013
|
* plain payment once the shopper chose one in our form.
|
|
6014
|
+
*
|
|
6015
|
+
* `express: false` is the checkout's standard path (2026-10-28): the
|
|
6016
|
+
* form's address — name, street, mobile — goes on the checkout before the
|
|
6017
|
+
* payment is created, and the delivery already chosen on the cart is what
|
|
6018
|
+
* Vipps charges for.
|
|
5415
6019
|
*/
|
|
5416
6020
|
async startVippsPayment(sponsorId, formData, options = {}) {
|
|
5417
6021
|
const waitFor = sponsorId ?? this.state?.sponsorId;
|
|
@@ -5420,7 +6024,8 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5420
6024
|
sponsorId,
|
|
5421
6025
|
formData,
|
|
5422
6026
|
{ paymentMethod: "Vipps" },
|
|
5423
|
-
true
|
|
6027
|
+
true,
|
|
6028
|
+
options.express === false
|
|
5424
6029
|
);
|
|
5425
6030
|
const returnUrl = resolveHttpsReturnUrl(null, {
|
|
5426
6031
|
vio_payment: "success",
|
|
@@ -5457,7 +6062,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5457
6062
|
/** Vipps' own payment state for the checkout — see getVippsStatus in
|
|
5458
6063
|
* cart-queries.ts for why this exists instead of trusting GetCheckout. */
|
|
5459
6064
|
async getVippsStatus(checkoutId, sponsorId) {
|
|
5460
|
-
const opts = await
|
|
6065
|
+
const opts = await this.gqlOptions(sponsorId ?? this.sponsorIdOfCheckout(checkoutId) ?? this.state?.sponsorId, checkoutId);
|
|
5461
6066
|
return getVippsStatus({ checkoutId }, opts);
|
|
5462
6067
|
}
|
|
5463
6068
|
/**
|
|
@@ -5474,7 +6079,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5474
6079
|
if (!cartId) {
|
|
5475
6080
|
throw new Error(`[CheckoutManager] Failed to obtain cart_id for sponsor ${spId}`);
|
|
5476
6081
|
}
|
|
5477
|
-
const opts = await
|
|
6082
|
+
const opts = await this.gqlOptions(spId);
|
|
5478
6083
|
let checkoutId = this.state?.checkoutId;
|
|
5479
6084
|
if (!checkoutId) {
|
|
5480
6085
|
const checkoutRes = await this.createCheckout(spId, "kustom");
|
|
@@ -5520,7 +6125,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5520
6125
|
const spId = sponsorId ?? this.state?.sponsorId;
|
|
5521
6126
|
const checkoutId = this.state?.checkoutId;
|
|
5522
6127
|
if (!spId || !checkoutId) return null;
|
|
5523
|
-
const opts = await
|
|
6128
|
+
const opts = await this.gqlOptions(spId);
|
|
5524
6129
|
suspendKustom();
|
|
5525
6130
|
try {
|
|
5526
6131
|
return await syncPaymentKustom(checkoutId, opts);
|
|
@@ -5530,7 +6135,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5530
6135
|
}
|
|
5531
6136
|
/** Re-read a Kustom order — used on the confirmation return trip. */
|
|
5532
6137
|
async getKustomOrder(orderId, sponsorId) {
|
|
5533
|
-
const opts = await
|
|
6138
|
+
const opts = await this.gqlOptions(sponsorId ?? this.state?.sponsorId);
|
|
5534
6139
|
return getKustomOrder(orderId, opts);
|
|
5535
6140
|
}
|
|
5536
6141
|
/** Render a Kustom html_snippet (e.g. the confirmation receipt) into a container. */
|
|
@@ -5550,7 +6155,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5550
6155
|
if (!cartId) {
|
|
5551
6156
|
throw new Error(`[CheckoutManager] Failed to obtain cart_id for sponsor ${spId}`);
|
|
5552
6157
|
}
|
|
5553
|
-
const opts = await
|
|
6158
|
+
const opts = await this.gqlOptions(spId);
|
|
5554
6159
|
let checkoutId = this.state?.checkoutId;
|
|
5555
6160
|
if (!checkoutId) {
|
|
5556
6161
|
const checkoutRes = await this.createCheckout(spId, "qliro");
|
|
@@ -5620,7 +6225,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5620
6225
|
}
|
|
5621
6226
|
/** Re-read the Qliro order owned by a checkout — the confirmation trip. */
|
|
5622
6227
|
async getQliroOrder(checkoutId, sponsorId) {
|
|
5623
|
-
const opts = await
|
|
6228
|
+
const opts = await this.gqlOptions(sponsorId ?? this.sponsorIdOfCheckout(checkoutId) ?? this.state?.sponsorId, checkoutId);
|
|
5624
6229
|
return getQliroOrder(checkoutId, opts);
|
|
5625
6230
|
}
|
|
5626
6231
|
/**
|
|
@@ -5638,7 +6243,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5638
6243
|
if (!cartId) {
|
|
5639
6244
|
throw new Error(`[CheckoutManager] Failed to obtain cart_id for sponsor ${spId}`);
|
|
5640
6245
|
}
|
|
5641
|
-
const opts = await
|
|
6246
|
+
const opts = await this.gqlOptions(spId);
|
|
5642
6247
|
let checkoutId = this.state?.checkoutId;
|
|
5643
6248
|
if (!checkoutId) {
|
|
5644
6249
|
const checkoutRes = await this.createCheckout(spId, "walley");
|
|
@@ -5675,7 +6280,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5675
6280
|
}
|
|
5676
6281
|
/** Re-read the Walley session owned by a checkout — the confirmation trip. */
|
|
5677
6282
|
async getWalleyOrder(checkoutId, sponsorId) {
|
|
5678
|
-
const opts = await
|
|
6283
|
+
const opts = await this.gqlOptions(sponsorId ?? this.sponsorIdOfCheckout(checkoutId) ?? this.state?.sponsorId, checkoutId);
|
|
5679
6284
|
return getWalleyOrder(checkoutId, opts);
|
|
5680
6285
|
}
|
|
5681
6286
|
/**
|
|
@@ -5701,7 +6306,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5701
6306
|
if (!cartId) {
|
|
5702
6307
|
throw new Error(`[CheckoutManager] Failed to obtain cart_id for sponsor ${spId}`);
|
|
5703
6308
|
}
|
|
5704
|
-
const opts = await
|
|
6309
|
+
const opts = await this.gqlOptions(spId);
|
|
5705
6310
|
const stored = resume ? readNexiPending() : null;
|
|
5706
6311
|
const pending2 = stored && stored.paymentId === resume?.paymentId ? stored : null;
|
|
5707
6312
|
let checkoutId = this.state?.checkoutId;
|
|
@@ -5935,7 +6540,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5935
6540
|
}
|
|
5936
6541
|
/** Re-read the Nexi payment owned by a checkout. */
|
|
5937
6542
|
async getNexiOrder(checkoutId, sponsorId) {
|
|
5938
|
-
const opts = await
|
|
6543
|
+
const opts = await this.gqlOptions(sponsorId ?? this.sponsorIdOfCheckout(checkoutId) ?? this.state?.sponsorId, checkoutId);
|
|
5939
6544
|
return getNexiOrder(checkoutId, opts);
|
|
5940
6545
|
}
|
|
5941
6546
|
/**
|
|
@@ -6013,7 +6618,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
6013
6618
|
* finalised on the server.
|
|
6014
6619
|
*/
|
|
6015
6620
|
async getAdyenPayment(checkoutId, proof = {}, sponsorId) {
|
|
6016
|
-
const opts = await
|
|
6621
|
+
const opts = await this.gqlOptions(sponsorId ?? this.sponsorIdOfCheckout(checkoutId) ?? this.state?.sponsorId, checkoutId);
|
|
6017
6622
|
return getAdyenPayment({ checkoutId, ...proof }, opts);
|
|
6018
6623
|
}
|
|
6019
6624
|
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
@@ -6292,7 +6897,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
6292
6897
|
console.warn("[VioCheckout] updateCheckout before Apple Pay confirm failed:", err);
|
|
6293
6898
|
}
|
|
6294
6899
|
}
|
|
6295
|
-
const gqlOpts = await
|
|
6900
|
+
const gqlOpts = await this.gqlOptions(spId);
|
|
6296
6901
|
const createRes = await createPaymentApplePay({ checkoutId }, gqlOpts);
|
|
6297
6902
|
const gatewayId = String(createRes?.gateway_merchant_id ?? "");
|
|
6298
6903
|
if (gatewayId.startsWith("pk_")) this.applePayPublishableKey = gatewayId;
|
|
@@ -6544,7 +7149,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
6544
7149
|
const json = await executeKlarnaGraphQL(
|
|
6545
7150
|
CREATE_PAYMENT_KLARNA_NATIVE_MUTATION,
|
|
6546
7151
|
variables,
|
|
6547
|
-
sponsorId
|
|
7152
|
+
await this.gqlOptions(sponsorId, checkoutId)
|
|
6548
7153
|
);
|
|
6549
7154
|
const nativeRes = json?.data?.Payment?.CreatePaymentKlarnaNative;
|
|
6550
7155
|
if (!nativeRes || !nativeRes.client_token) {
|
|
@@ -6694,7 +7299,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
6694
7299
|
const json = await executeKlarnaGraphQL(
|
|
6695
7300
|
CREATE_PAYMENT_KLARNA_NATIVE_MUTATION,
|
|
6696
7301
|
variables,
|
|
6697
|
-
sponsorId
|
|
7302
|
+
await this.gqlOptions(sponsorId, checkoutId)
|
|
6698
7303
|
);
|
|
6699
7304
|
const nativeRes = json?.data?.Payment?.CreatePaymentKlarnaNative;
|
|
6700
7305
|
if (!nativeRes || !nativeRes.client_token) {
|
|
@@ -6757,14 +7362,13 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
6757
7362
|
* the SDK's resumed `complete` event — finish creating the order + confirm.
|
|
6758
7363
|
*/
|
|
6759
7364
|
async resumeKlarnaReturn() {
|
|
6760
|
-
|
|
6761
|
-
const raw = sessionStorage.getItem(KLARNA_PENDING_KEY);
|
|
7365
|
+
const raw = storageGet("session", KLARNA_PENDING_KEY);
|
|
6762
7366
|
if (!raw) return;
|
|
6763
7367
|
let pending2;
|
|
6764
7368
|
try {
|
|
6765
7369
|
pending2 = JSON.parse(raw);
|
|
6766
7370
|
} catch {
|
|
6767
|
-
|
|
7371
|
+
storageRemove("session", KLARNA_PENDING_KEY);
|
|
6768
7372
|
return;
|
|
6769
7373
|
}
|
|
6770
7374
|
const fromUrl = readKlarnaTokenFromUrl();
|
|
@@ -6822,7 +7426,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
6822
7426
|
async completeKlarnaOrder(authorizationToken, ctx, result) {
|
|
6823
7427
|
if (this.klarnaOrderInFlight) return;
|
|
6824
7428
|
this.klarnaOrderInFlight = true;
|
|
6825
|
-
if (
|
|
7429
|
+
if (storageGet("session", KLARNA_CONFIRMED_KEY) === authorizationToken) {
|
|
6826
7430
|
this.klarnaOrderInFlight = false;
|
|
6827
7431
|
return;
|
|
6828
7432
|
}
|
|
@@ -6837,12 +7441,10 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
6837
7441
|
shippingAddress: buildKlarnaAddress(address),
|
|
6838
7442
|
customer: buildKlarnaCustomer(address)
|
|
6839
7443
|
};
|
|
7444
|
+
const klarnaSponsorId = ctx?.sponsorId ?? this.state?.sponsorId;
|
|
7445
|
+
const klarnaOptions = await this.gqlOptions(klarnaSponsorId, ctx?.checkoutId ?? this.state?.checkoutId);
|
|
6840
7446
|
const json = await withBuyerRef(
|
|
6841
|
-
(withRef) => executeKlarnaGraphQL(
|
|
6842
|
-
confirmPaymentKlarnaNativeMutation(withRef),
|
|
6843
|
-
variables,
|
|
6844
|
-
ctx?.sponsorId ?? this.state?.sponsorId
|
|
6845
|
-
)
|
|
7447
|
+
(withRef) => executeKlarnaGraphQL(confirmPaymentKlarnaNativeMutation(withRef), variables, klarnaOptions)
|
|
6846
7448
|
);
|
|
6847
7449
|
const confirmRes = json?.data?.Payment?.ConfirmPaymentKlarnaNative;
|
|
6848
7450
|
if (!confirmRes) {
|
|
@@ -6850,10 +7452,8 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
6850
7452
|
}
|
|
6851
7453
|
const orderData = confirmRes.order || confirmRes;
|
|
6852
7454
|
const buyerRef = normalizeBuyerRef(confirmRes[BUYER_REF_FIELD]);
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
sessionStorage.removeItem(KLARNA_PENDING_KEY);
|
|
6856
|
-
}
|
|
7455
|
+
storageSet("session", KLARNA_CONFIRMED_KEY, authorizationToken);
|
|
7456
|
+
storageRemove("session", KLARNA_PENDING_KEY);
|
|
6857
7457
|
const state = this.state ?? { sponsorId: ctx.sponsorId, subtotal: ctx.orderAmount, currency: ctx.currency };
|
|
6858
7458
|
this.dispatchEvent(
|
|
6859
7459
|
new CustomEvent("payment-complete", {
|
|
@@ -7095,6 +7695,54 @@ function safeCall(fn) {
|
|
|
7095
7695
|
}
|
|
7096
7696
|
}
|
|
7097
7697
|
|
|
7698
|
+
// src/core/analytics/internal-traffic.ts
|
|
7699
|
+
var INTERNAL_KEY = "vio.internal.v1";
|
|
7700
|
+
var INTERNAL_PARAM = "vio_internal";
|
|
7701
|
+
function defaultInternalEnvironment() {
|
|
7702
|
+
return {
|
|
7703
|
+
location: typeof location !== "undefined" ? location : null,
|
|
7704
|
+
storage: localStorageOrNull()
|
|
7705
|
+
};
|
|
7706
|
+
}
|
|
7707
|
+
function resolveInternal(env = defaultInternalEnvironment()) {
|
|
7708
|
+
const param = internalParam(env.location?.search);
|
|
7709
|
+
if (param !== void 0) {
|
|
7710
|
+
writeInternal(param, env.storage);
|
|
7711
|
+
return param;
|
|
7712
|
+
}
|
|
7713
|
+
return readInternal(env.storage);
|
|
7714
|
+
}
|
|
7715
|
+
function readInternal(storage2 = defaultInternalEnvironment().storage) {
|
|
7716
|
+
try {
|
|
7717
|
+
return storage2?.getItem(INTERNAL_KEY) === "1";
|
|
7718
|
+
} catch {
|
|
7719
|
+
return false;
|
|
7720
|
+
}
|
|
7721
|
+
}
|
|
7722
|
+
function writeInternal(internal, storage2 = defaultInternalEnvironment().storage) {
|
|
7723
|
+
try {
|
|
7724
|
+
if (internal) storage2?.setItem(INTERNAL_KEY, "1");
|
|
7725
|
+
else storage2?.removeItem?.(INTERNAL_KEY);
|
|
7726
|
+
} catch {
|
|
7727
|
+
}
|
|
7728
|
+
}
|
|
7729
|
+
function internalParam(search) {
|
|
7730
|
+
try {
|
|
7731
|
+
const value = new URLSearchParams(typeof search === "string" ? search : "").get(INTERNAL_PARAM)?.trim();
|
|
7732
|
+
if (value === "1") return true;
|
|
7733
|
+
if (value === "0") return false;
|
|
7734
|
+
} catch {
|
|
7735
|
+
}
|
|
7736
|
+
return void 0;
|
|
7737
|
+
}
|
|
7738
|
+
function localStorageOrNull() {
|
|
7739
|
+
try {
|
|
7740
|
+
return typeof window !== "undefined" && window.localStorage ? window.localStorage : null;
|
|
7741
|
+
} catch {
|
|
7742
|
+
return null;
|
|
7743
|
+
}
|
|
7744
|
+
}
|
|
7745
|
+
|
|
7098
7746
|
// src/core/cart/slices.ts
|
|
7099
7747
|
function cartSlicesFrom(lines, resolveCampaign, fallbackCurrency) {
|
|
7100
7748
|
if (!Array.isArray(lines) || lines.length === 0) return [];
|
|
@@ -7171,6 +7819,7 @@ var FLUSH_AT_COUNT = 20;
|
|
|
7171
7819
|
var MAX_QUEUE = 500;
|
|
7172
7820
|
var RETRY_BACKOFF_MS = [2e3, 4e3, 8e3];
|
|
7173
7821
|
var ANON_KEY = "vio.anon.v1";
|
|
7822
|
+
var MAX_ITEMS = 100;
|
|
7174
7823
|
var SESSION_KEY = "vio.session.v1";
|
|
7175
7824
|
var IMPRESSION_THRESHOLD = 0.5;
|
|
7176
7825
|
var IMPRESSION_DWELL_MS = 1e3;
|
|
@@ -7178,7 +7827,14 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7178
7827
|
constructor() {
|
|
7179
7828
|
super(...arguments);
|
|
7180
7829
|
this.started = false;
|
|
7181
|
-
this.options = {
|
|
7830
|
+
this.options = {
|
|
7831
|
+
host: "custom",
|
|
7832
|
+
collector: true,
|
|
7833
|
+
dataLayer: false,
|
|
7834
|
+
debug: false,
|
|
7835
|
+
autoTrack: true,
|
|
7836
|
+
privateContent: false
|
|
7837
|
+
};
|
|
7182
7838
|
this.queue = [];
|
|
7183
7839
|
this.flushTimer = null;
|
|
7184
7840
|
this.retryAttempt = 0;
|
|
@@ -7199,6 +7855,14 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7199
7855
|
this.client = null;
|
|
7200
7856
|
/** The landing it was read from — persisted later when consent arrives after the first event. */
|
|
7201
7857
|
this.landing = null;
|
|
7858
|
+
/**
|
|
7859
|
+
* Internal traffic (ADR-0041): `client.internal: true` on every event while
|
|
7860
|
+
* set. Read once (`?vio_internal=1|0`, else `localStorage`) at `Vio.init()`
|
|
7861
|
+
* or on the first event; `setInternal()` changes it. `null` = not read yet.
|
|
7862
|
+
*/
|
|
7863
|
+
this.internal = null;
|
|
7864
|
+
/** The console line for testers goes out once per page load. */
|
|
7865
|
+
this.internalAnnounced = false;
|
|
7202
7866
|
/** Checkouts (`c:<id>`) and orders (`o:<number>`) this page load reported a `purchase` for: one each. */
|
|
7203
7867
|
this.purchased = /* @__PURE__ */ new Set();
|
|
7204
7868
|
/** Checkouts this page load reported an `add_payment_info` for: one each. */
|
|
@@ -7248,7 +7912,8 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7248
7912
|
collector: options.collector ?? this.options.collector,
|
|
7249
7913
|
dataLayer: options.dataLayer ?? this.options.dataLayer,
|
|
7250
7914
|
debug: options.debug ?? this.options.debug,
|
|
7251
|
-
autoTrack: options.autoTrack ?? this.options.autoTrack
|
|
7915
|
+
autoTrack: options.autoTrack ?? this.options.autoTrack,
|
|
7916
|
+
privateContent: options.privateContent ?? this.options.privateContent
|
|
7252
7917
|
};
|
|
7253
7918
|
if (options.sessionId) this.externalSessionId = options.sessionId;
|
|
7254
7919
|
if (this.started || !hasDom()) return;
|
|
@@ -7291,6 +7956,43 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7291
7956
|
identify(externalUserId) {
|
|
7292
7957
|
this.externalUserId = externalUserId ?? void 0;
|
|
7293
7958
|
}
|
|
7959
|
+
/**
|
|
7960
|
+
* Mark (or unmark) this browser as Vio's own traffic (ADR-0041): while
|
|
7961
|
+
* marked, every event carries `client.internal: true` and the collector's
|
|
7962
|
+
* reads leave it out. Remembered in `localStorage` (`vio.internal.v1`) —
|
|
7963
|
+
* the same mark `?vio_internal=1` / `?vio_internal=0` sets on any page.
|
|
7964
|
+
*/
|
|
7965
|
+
setInternal(internal) {
|
|
7966
|
+
this.internal = internal === true;
|
|
7967
|
+
writeInternal(this.internal);
|
|
7968
|
+
this.announceInternal();
|
|
7969
|
+
}
|
|
7970
|
+
/** Whether this browser is marked as internal traffic (reads the mark the first time). */
|
|
7971
|
+
get isInternal() {
|
|
7972
|
+
return this.syncInternal();
|
|
7973
|
+
}
|
|
7974
|
+
/**
|
|
7975
|
+
* Read the mark: the page's `?vio_internal=1|0` (remembered), else what the
|
|
7976
|
+
* browser remembers. Once per page load — `Vio.init()` calls it so a page
|
|
7977
|
+
* with the parameter marks the browser even if it never starts analytics;
|
|
7978
|
+
* `force` reads again.
|
|
7979
|
+
*/
|
|
7980
|
+
syncInternal(force = false) {
|
|
7981
|
+
if (this.internal === null || force) {
|
|
7982
|
+
this.internal = hasDom() ? resolveInternal() : readInternal(null);
|
|
7983
|
+
this.announceInternal();
|
|
7984
|
+
}
|
|
7985
|
+
return this.internal;
|
|
7986
|
+
}
|
|
7987
|
+
/** One console line when marked, so a tester can see the mark took. */
|
|
7988
|
+
announceInternal() {
|
|
7989
|
+
if (!this.internal || this.internalAnnounced) return;
|
|
7990
|
+
this.internalAnnounced = true;
|
|
7991
|
+
try {
|
|
7992
|
+
console.info("[Vio.analytics] this browser is marked as internal traffic (vio_internal=1): its events are not counted. Open any page with ?vio_internal=0 to undo.");
|
|
7993
|
+
} catch {
|
|
7994
|
+
}
|
|
7995
|
+
}
|
|
7294
7996
|
/** Queue one event. Works pre-init and pre-start (SSR: no-op). */
|
|
7295
7997
|
track(name, opts = {}) {
|
|
7296
7998
|
if (!hasDom()) return;
|
|
@@ -7335,7 +8037,7 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7335
8037
|
this.ensureSession();
|
|
7336
8038
|
if (this.impressedComponents.has(key)) return;
|
|
7337
8039
|
this.impressedComponents.add(key);
|
|
7338
|
-
this.track(name, { context });
|
|
8040
|
+
this.track(name, { context, commerce: impressionCommerce(opts.commerce) });
|
|
7339
8041
|
opts.onImpression?.();
|
|
7340
8042
|
observer.disconnect();
|
|
7341
8043
|
}, IMPRESSION_DWELL_MS);
|
|
@@ -7416,26 +8118,28 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7416
8118
|
// one is usually the tracking tail, not the page. The other host-given
|
|
7417
8119
|
// fields (broadcastId, componentTemplateId, errorCode, variant, …) are
|
|
7418
8120
|
// the host's responsibility: the SDK does not touch them.
|
|
7419
|
-
|
|
8121
|
+
// Con `privateContent` ninguno de los tres sale del dispositivo.
|
|
8122
|
+
content_url: this.options.privateContent ? void 0 : capContentUrl(ctx.contentUrl ?? (typeof location !== "undefined" ? location.href : void 0)),
|
|
7420
8123
|
// The host's own content id — its join key back onto its reporting.
|
|
7421
8124
|
// Explicit on the event when it fits, else what the SDK resolved for
|
|
7422
8125
|
// the page (already capped per source), else nothing.
|
|
7423
|
-
content_id: explicitContentId ?? fitsId(content.id),
|
|
8126
|
+
content_id: this.options.privateContent ? void 0 : explicitContentId ?? fitsId(content.id),
|
|
7424
8127
|
// Deletion-proof reporting: sources have no trash bin — the title
|
|
7425
8128
|
// snapshotted at event time keeps reports legible if content dies.
|
|
7426
8129
|
error_code: ctx.errorCode,
|
|
7427
|
-
content_title: capTitle(
|
|
8130
|
+
content_title: this.options.privateContent ? void 0 : capTitle(
|
|
7428
8131
|
ctx.contentTitle ?? content.title ?? (typeof document !== "undefined" && document.title ? document.title : void 0)
|
|
7429
8132
|
),
|
|
7430
8133
|
variant: ctx.variant
|
|
7431
8134
|
});
|
|
7432
8135
|
const com = opts.commerce;
|
|
7433
8136
|
const commerce = com ? compact({
|
|
7434
|
-
|
|
8137
|
+
// The collector rejects an event with more lines than its cap, whole.
|
|
8138
|
+
items: com.items?.slice(0, MAX_ITEMS).map(
|
|
7435
8139
|
(i) => compact({
|
|
7436
8140
|
product_id: String(i.productId),
|
|
7437
|
-
name: i.name,
|
|
7438
|
-
brand: i.brand,
|
|
8141
|
+
name: this.options.privateContent ? void 0 : i.name,
|
|
8142
|
+
brand: this.options.privateContent ? void 0 : i.brand,
|
|
7439
8143
|
variant_id: i.variantId !== void 0 ? String(i.variantId) : void 0,
|
|
7440
8144
|
price: i.price,
|
|
7441
8145
|
quantity: i.quantity
|
|
@@ -7452,7 +8156,8 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7452
8156
|
// ids does not carry a stable identifier of a person either.
|
|
7453
8157
|
buyer_id: this.canPersist ? normalizeBuyerRef(com.buyerId) : void 0
|
|
7454
8158
|
}) : void 0;
|
|
7455
|
-
const
|
|
8159
|
+
const base = this.clientBlock();
|
|
8160
|
+
const client = this.syncInternal() ? { ...base ?? {}, internal: true } : base;
|
|
7456
8161
|
return {
|
|
7457
8162
|
event_id: uuid(),
|
|
7458
8163
|
name,
|
|
@@ -7981,6 +8686,15 @@ function safeStorageSet(key, value) {
|
|
|
7981
8686
|
} catch {
|
|
7982
8687
|
}
|
|
7983
8688
|
}
|
|
8689
|
+
function impressionCommerce(read) {
|
|
8690
|
+
if (!read) return void 0;
|
|
8691
|
+
try {
|
|
8692
|
+
const commerce = read();
|
|
8693
|
+
return commerce?.items?.length ? commerce : void 0;
|
|
8694
|
+
} catch {
|
|
8695
|
+
return void 0;
|
|
8696
|
+
}
|
|
8697
|
+
}
|
|
7984
8698
|
function compact(obj) {
|
|
7985
8699
|
const out = {};
|
|
7986
8700
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -8254,6 +8968,8 @@ function cut3(value, max) {
|
|
|
8254
8968
|
|
|
8255
8969
|
// src/core/client.ts
|
|
8256
8970
|
var SLOT_DECLARATION_DEBOUNCE_MS = 1e3;
|
|
8971
|
+
var BOOTSTRAP_MAX_AGE_MS = 5 * 6e4;
|
|
8972
|
+
var BOOTSTRAP_REFRESH_BACKOFF_MS = 6e4;
|
|
8257
8973
|
var PRIVACY_MODE_TIMEOUT_MS = 1500;
|
|
8258
8974
|
var PRIVACY_UNKNOWN_TTL_MS = 6e4;
|
|
8259
8975
|
function privacyModeOf(value) {
|
|
@@ -8269,9 +8985,23 @@ function privacyModeOfSurface(res) {
|
|
|
8269
8985
|
var VioFacade = class {
|
|
8270
8986
|
constructor() {
|
|
8271
8987
|
this.apiInstance = null;
|
|
8988
|
+
/** Commerce clients by sponsor AND key: one sponsor may sell on several channels (one per campaign). */
|
|
8272
8989
|
this.commerceClients = /* @__PURE__ */ new Map();
|
|
8273
8990
|
this.bootstrapPromise = null;
|
|
8274
8991
|
this.cachedBootstrap = null;
|
|
8992
|
+
/** When the cached bootstrap arrived (ms epoch). */
|
|
8993
|
+
this.bootstrapAt = 0;
|
|
8994
|
+
/** A refresh of the bootstrap in flight (`refreshStaleBootstrap`). */
|
|
8995
|
+
this.bootstrapRefresh = null;
|
|
8996
|
+
this.bootstrapRefreshFailedAt = 0;
|
|
8997
|
+
/** The `visibilitychange` listener is installed once per page. */
|
|
8998
|
+
this.visibilityHooked = false;
|
|
8999
|
+
/**
|
|
9000
|
+
* Every selling block this page has seen, by `sponsorId:channelId` — so a
|
|
9001
|
+
* checkout opened on a channel keeps its key after a bootstrap refresh no
|
|
9002
|
+
* longer lists that channel (`sponsorCommerce(…, { retired: true })`).
|
|
9003
|
+
*/
|
|
9004
|
+
this.seenChannels = /* @__PURE__ */ new Map();
|
|
8275
9005
|
/** Last bootstrap failure — short backoff so cart mutations don't hammer a
|
|
8276
9006
|
* dead endpoint on every call. */
|
|
8277
9007
|
this.bootstrapFailedAt = 0;
|
|
@@ -8295,7 +9025,17 @@ var VioFacade = class {
|
|
|
8295
9025
|
this.warnedDeclarationCap = false;
|
|
8296
9026
|
// Client-side managers — created lazily on first access. They don't
|
|
8297
9027
|
// need Vio.init() to work (state is purely local).
|
|
8298
|
-
|
|
9028
|
+
/**
|
|
9029
|
+
* One cart manager per connection (environment + key), each with its own
|
|
9030
|
+
* storage entry; `Vio.cart` is a stable front for the current one, so a
|
|
9031
|
+
* re-init with another key switches carts without the page re-subscribing.
|
|
9032
|
+
* A manager left behind keeps its carts (they come back if the page switches
|
|
9033
|
+
* back) and finishes its requests into ITS carts, never the new one's.
|
|
9034
|
+
*/
|
|
9035
|
+
this.cartManagers = /* @__PURE__ */ new Map();
|
|
9036
|
+
this.cartScope = "";
|
|
9037
|
+
this.cartFront = null;
|
|
9038
|
+
this.cartEvents = new EventTarget();
|
|
8299
9039
|
this.checkoutManager = null;
|
|
8300
9040
|
this.analyticsManager = null;
|
|
8301
9041
|
/** What the surface answered of its privacy mode (`GET /v2/mobile/surface`) and when; `unknown` expires after a minute. */
|
|
@@ -8305,15 +9045,28 @@ var VioFacade = class {
|
|
|
8305
9045
|
}
|
|
8306
9046
|
init(config) {
|
|
8307
9047
|
Configuration.init(config);
|
|
9048
|
+
try {
|
|
9049
|
+
const resolved = Configuration.get();
|
|
9050
|
+
this.switchCartScope(cartScopeOf(resolved.environment, resolved.apiKey));
|
|
9051
|
+
} catch {
|
|
9052
|
+
}
|
|
8308
9053
|
this.apiInstance = null;
|
|
8309
9054
|
this.commerceClients.clear();
|
|
8310
9055
|
this.bootstrapPromise = null;
|
|
8311
9056
|
this.cachedBootstrap = null;
|
|
9057
|
+
this.bootstrapAt = 0;
|
|
9058
|
+
this.bootstrapRefresh = null;
|
|
9059
|
+
this.bootstrapRefreshFailedAt = 0;
|
|
9060
|
+
this.seenChannels.clear();
|
|
8312
9061
|
this.bootstrapFailedAt = 0;
|
|
8313
9062
|
this.generation++;
|
|
8314
9063
|
this.surfaceMode = null;
|
|
8315
9064
|
this.surfaceRequest = null;
|
|
8316
9065
|
this.preloadPrivacyMode();
|
|
9066
|
+
try {
|
|
9067
|
+
this.analytics.syncInternal(true);
|
|
9068
|
+
} catch {
|
|
9069
|
+
}
|
|
8317
9070
|
this.checkoutManager?.clearPaymentMethodsCache();
|
|
8318
9071
|
if (this.slotDeclareTimer) {
|
|
8319
9072
|
clearTimeout(this.slotDeclareTimer);
|
|
@@ -8352,8 +9105,66 @@ var VioFacade = class {
|
|
|
8352
9105
|
// MARK: - Client-side managers (no init required)
|
|
8353
9106
|
/** Multi-sponsor cart manager. Reactive — listen via addEventListener('change', ...). */
|
|
8354
9107
|
get cart() {
|
|
8355
|
-
if (!this.
|
|
8356
|
-
return this.
|
|
9108
|
+
if (!this.cartFront) this.cartFront = this.makeCartFront();
|
|
9109
|
+
return this.cartFront;
|
|
9110
|
+
}
|
|
9111
|
+
/** The cart manager of the page's connection now (created on first use). */
|
|
9112
|
+
currentCartManager() {
|
|
9113
|
+
const scope = this.cartScope;
|
|
9114
|
+
let manager = this.cartManagers.get(scope);
|
|
9115
|
+
if (!manager) {
|
|
9116
|
+
const created = new CartManager(scope);
|
|
9117
|
+
for (const type of ["change", "error"]) {
|
|
9118
|
+
created.addEventListener(type, (e) => {
|
|
9119
|
+
if (this.cartManagers.get(this.cartScope) !== created) return;
|
|
9120
|
+
this.cartEvents.dispatchEvent(new CustomEvent(type, { detail: e.detail }));
|
|
9121
|
+
});
|
|
9122
|
+
}
|
|
9123
|
+
this.cartManagers.set(scope, created);
|
|
9124
|
+
manager = created;
|
|
9125
|
+
}
|
|
9126
|
+
return manager;
|
|
9127
|
+
}
|
|
9128
|
+
/**
|
|
9129
|
+
* `Vio.cart`: every property and method is the current connection's
|
|
9130
|
+
* manager's; the listeners live on the front, so they survive a switch.
|
|
9131
|
+
*/
|
|
9132
|
+
makeCartFront() {
|
|
9133
|
+
const events = this.cartEvents;
|
|
9134
|
+
const listenerMethods = {
|
|
9135
|
+
addEventListener: events.addEventListener.bind(events),
|
|
9136
|
+
removeEventListener: events.removeEventListener.bind(events),
|
|
9137
|
+
dispatchEvent: events.dispatchEvent.bind(events)
|
|
9138
|
+
};
|
|
9139
|
+
return new Proxy(Object.create(CartManager.prototype), {
|
|
9140
|
+
get: (_target, prop) => {
|
|
9141
|
+
if (typeof prop === "string" && prop in listenerMethods) return listenerMethods[prop];
|
|
9142
|
+
const manager = this.currentCartManager();
|
|
9143
|
+
const value = Reflect.get(manager, prop, manager);
|
|
9144
|
+
if (typeof value !== "function" || Object.prototype.hasOwnProperty.call(manager, prop)) return value;
|
|
9145
|
+
return value.bind(manager);
|
|
9146
|
+
},
|
|
9147
|
+
set: (_target, prop, value) => Reflect.set(this.currentCartManager(), prop, value),
|
|
9148
|
+
has: (_target, prop) => Reflect.has(this.currentCartManager(), prop),
|
|
9149
|
+
// A property defined on Vio.cart (a test's spy, a host's patch) lands on
|
|
9150
|
+
// the current manager, where its own methods find it.
|
|
9151
|
+
defineProperty: (_target, prop, descriptor) => Reflect.defineProperty(this.currentCartManager(), prop, descriptor),
|
|
9152
|
+
deleteProperty: (_target, prop) => Reflect.deleteProperty(this.currentCartManager(), prop),
|
|
9153
|
+
getOwnPropertyDescriptor: (_target, prop) => {
|
|
9154
|
+
const own = Reflect.getOwnPropertyDescriptor(this.currentCartManager(), prop);
|
|
9155
|
+
return own ? { ...own, configurable: true } : void 0;
|
|
9156
|
+
}
|
|
9157
|
+
});
|
|
9158
|
+
}
|
|
9159
|
+
/** After `init`: the carts are the new connection's. Says `change` when that switched them. */
|
|
9160
|
+
switchCartScope(scope) {
|
|
9161
|
+
if (scope === this.cartScope) return;
|
|
9162
|
+
this.cartManagers.get(this.cartScope)?.setActive(false);
|
|
9163
|
+
this.cartScope = scope;
|
|
9164
|
+
if (!this.cartFront) return;
|
|
9165
|
+
const manager = this.currentCartManager();
|
|
9166
|
+
manager.setActive(true);
|
|
9167
|
+
manager.announce();
|
|
8357
9168
|
}
|
|
8358
9169
|
/** Checkout flow manager. Subscribes to cart state via the CartManager; asks here for the order's attribution. */
|
|
8359
9170
|
get checkout() {
|
|
@@ -8401,7 +9212,7 @@ var VioFacade = class {
|
|
|
8401
9212
|
const promise = this.api.bootstrap(Configuration.get().platform).then(
|
|
8402
9213
|
(res) => {
|
|
8403
9214
|
if (generation !== this.generation) return this.bootstrap();
|
|
8404
|
-
this.
|
|
9215
|
+
this.adoptBootstrap(res);
|
|
8405
9216
|
this.bootstrapFailedAt = 0;
|
|
8406
9217
|
if (this.slotsDirty) this.scheduleSlotDeclaration();
|
|
8407
9218
|
this.preloadPrivacyMode();
|
|
@@ -8421,6 +9232,85 @@ var VioFacade = class {
|
|
|
8421
9232
|
get bootstrapCache() {
|
|
8422
9233
|
return this.cachedBootstrap;
|
|
8423
9234
|
}
|
|
9235
|
+
/** A bootstrap becomes the page's: when it arrived, the channels it lists, and the tab-visible refresh. */
|
|
9236
|
+
adoptBootstrap(res) {
|
|
9237
|
+
this.cachedBootstrap = res;
|
|
9238
|
+
this.bootstrapAt = Date.now();
|
|
9239
|
+
try {
|
|
9240
|
+
const ids = /* @__PURE__ */ new Set();
|
|
9241
|
+
const add = (s) => {
|
|
9242
|
+
const id = toSponsorId(s?.id);
|
|
9243
|
+
if (id !== void 0) ids.add(id);
|
|
9244
|
+
};
|
|
9245
|
+
add(res?.primarySponsor);
|
|
9246
|
+
if (Array.isArray(res?.secondarySponsors)) res.secondarySponsors.forEach(add);
|
|
9247
|
+
if (Array.isArray(res?.campaigns)) {
|
|
9248
|
+
for (const c of res.campaigns) {
|
|
9249
|
+
if (!c || typeof c !== "object") continue;
|
|
9250
|
+
add(c.primarySponsor);
|
|
9251
|
+
if (Array.isArray(c.secondarySponsors)) c.secondarySponsors.forEach(add);
|
|
9252
|
+
}
|
|
9253
|
+
}
|
|
9254
|
+
for (const id of ids) {
|
|
9255
|
+
for (const { sponsor } of sellingBlocksIn(res, id)) {
|
|
9256
|
+
const channel = channelIdOf(sponsor.commerce.channelId);
|
|
9257
|
+
if (channel !== void 0) this.seenChannels.set(`${id}:${channel}`, sponsor);
|
|
9258
|
+
}
|
|
9259
|
+
}
|
|
9260
|
+
} catch {
|
|
9261
|
+
}
|
|
9262
|
+
this.hookVisibility();
|
|
9263
|
+
}
|
|
9264
|
+
/**
|
|
9265
|
+
* The bootstrap is cached for the page's life, but a tab can stay open for
|
|
9266
|
+
* days: when it becomes visible again and the cached one is older than
|
|
9267
|
+
* five minutes, it is fetched again (new campaigns, channels). The old one
|
|
9268
|
+
* stays until the new one arrives — and stays if the refresh fails. Carts
|
|
9269
|
+
* keep their lines; a cart whose channel the new bootstrap no longer lists
|
|
9270
|
+
* is moved to the current channel the next time it is used (CartManager),
|
|
9271
|
+
* and an open checkout keeps paying with the key of its own channel.
|
|
9272
|
+
*/
|
|
9273
|
+
hookVisibility() {
|
|
9274
|
+
if (this.visibilityHooked) return;
|
|
9275
|
+
if (typeof document === "undefined" || typeof document.addEventListener !== "function") return;
|
|
9276
|
+
this.visibilityHooked = true;
|
|
9277
|
+
document.addEventListener("visibilitychange", () => {
|
|
9278
|
+
try {
|
|
9279
|
+
if (document.visibilityState === "visible") void this.refreshStaleBootstrap();
|
|
9280
|
+
} catch {
|
|
9281
|
+
}
|
|
9282
|
+
});
|
|
9283
|
+
}
|
|
9284
|
+
/** Fetch the bootstrap again when the cached one is older than `maxAgeMs`; never throws, never clears the cache. */
|
|
9285
|
+
refreshStaleBootstrap(maxAgeMs = BOOTSTRAP_MAX_AGE_MS) {
|
|
9286
|
+
try {
|
|
9287
|
+
if (this.bootstrapRefresh) return this.bootstrapRefresh;
|
|
9288
|
+
if (!this.cachedBootstrap || this.bootstrapPromise || !Configuration.isInitialized) return Promise.resolve();
|
|
9289
|
+
const now = Date.now();
|
|
9290
|
+
if (now - this.bootstrapAt < maxAgeMs) return Promise.resolve();
|
|
9291
|
+
if (this.bootstrapRefreshFailedAt && now - this.bootstrapRefreshFailedAt < BOOTSTRAP_REFRESH_BACKOFF_MS) {
|
|
9292
|
+
return Promise.resolve();
|
|
9293
|
+
}
|
|
9294
|
+
const generation = this.generation;
|
|
9295
|
+
const refresh = this.api.bootstrap(Configuration.get().platform).then(
|
|
9296
|
+
(res) => {
|
|
9297
|
+
if (generation !== this.generation || !res || typeof res !== "object") return;
|
|
9298
|
+
this.adoptBootstrap(res);
|
|
9299
|
+
this.bootstrapRefreshFailedAt = 0;
|
|
9300
|
+
if (this.slotsDirty) this.scheduleSlotDeclaration();
|
|
9301
|
+
},
|
|
9302
|
+
() => {
|
|
9303
|
+
if (generation === this.generation) this.bootstrapRefreshFailedAt = Date.now();
|
|
9304
|
+
}
|
|
9305
|
+
).finally(() => {
|
|
9306
|
+
if (this.bootstrapRefresh === refresh) this.bootstrapRefresh = null;
|
|
9307
|
+
});
|
|
9308
|
+
this.bootstrapRefresh = refresh;
|
|
9309
|
+
return refresh;
|
|
9310
|
+
} catch {
|
|
9311
|
+
return Promise.resolve();
|
|
9312
|
+
}
|
|
9313
|
+
}
|
|
8424
9314
|
/**
|
|
8425
9315
|
* Who a sponsor is to a shopper — `{ id, name, logoUrl, avatarUrl }` — by
|
|
8426
9316
|
* the ONE rule every element uses (`sponsorIdentityFrom`): the live
|
|
@@ -8455,22 +9345,60 @@ var VioFacade = class {
|
|
|
8455
9345
|
}
|
|
8456
9346
|
}
|
|
8457
9347
|
/**
|
|
8458
|
-
*
|
|
8459
|
-
*
|
|
9348
|
+
* The block a sponsor sells with — its `commerce.apiKey` and `channelId` —
|
|
9349
|
+
* by the rule one article = one campaign = one channel = one sponsor (see
|
|
9350
|
+
* `sponsorCommerceIn`): `ctx.channelId` → that channel's block only (a cart
|
|
9351
|
+
* created on a channel is only called with its key); else the campaign in
|
|
9352
|
+
* context — `ctx.campaignId` candidates (the click's, the element's
|
|
9353
|
+
* `vio-campaign`, an ancestor's `data-vio-campaign`), then
|
|
9354
|
+
* `Vio.init({ campaignId })` — when the sponsor takes part in it; else the
|
|
9355
|
+
* sponsor's first block that sells (the behaviour before). `campaignId:
|
|
9356
|
+
* null` means no campaign at all, not even `Vio.init`'s. `retired: true`
|
|
9357
|
+
* also answers a channel the current bootstrap no longer lists with the
|
|
9358
|
+
* block this page saw for it (an open checkout after a bootstrap refresh).
|
|
9359
|
+
* Blocks with `commerce: null` are skipped. `null` when none; never throws.
|
|
9360
|
+
*/
|
|
9361
|
+
sponsorCommerce(sponsorId, ctx = {}) {
|
|
9362
|
+
try {
|
|
9363
|
+
const id = toSponsorId(sponsorId);
|
|
9364
|
+
if (id === void 0) return null;
|
|
9365
|
+
const channel = channelIdOf(ctx?.channelId);
|
|
9366
|
+
if (channel !== void 0) {
|
|
9367
|
+
const listed = sponsorCommerceIn(this.cachedBootstrap, id, { channelId: channel });
|
|
9368
|
+
if (listed) return listed;
|
|
9369
|
+
return ctx.retired ? this.seenChannels.get(`${id}:${channel}`) ?? null : null;
|
|
9370
|
+
}
|
|
9371
|
+
const campaignId = ctx?.campaignId === null ? [] : this.pageCampaignCandidates(ctx?.campaignId);
|
|
9372
|
+
return sponsorCommerceIn(this.cachedBootstrap, id, { campaignId }) ?? null;
|
|
9373
|
+
} catch {
|
|
9374
|
+
return null;
|
|
9375
|
+
}
|
|
9376
|
+
}
|
|
9377
|
+
/**
|
|
9378
|
+
* Get a CommerceClient scoped to a sponsor (via bootstrap) — on the
|
|
9379
|
+
* channel of the campaign in context (`ctx.campaignId`, the element's
|
|
9380
|
+
* candidates first; see `sponsorCommerce`) or of `ctx.channelId`. Without
|
|
9381
|
+
* `ctx`, the page's campaign (`Vio.init`) when the sponsor takes part in
|
|
9382
|
+
* it, else the sponsor's first selling block, as before. Clients are kept
|
|
9383
|
+
* per sponsor and key. Throws if bootstrap hasn't been called or nothing of
|
|
9384
|
+
* the sponsor sells there.
|
|
8460
9385
|
*/
|
|
8461
|
-
commerceFor(sponsorId) {
|
|
9386
|
+
commerceFor(sponsorId, ctx) {
|
|
8462
9387
|
sponsorId = Number(sponsorId);
|
|
8463
|
-
const
|
|
8464
|
-
if (existing) return existing;
|
|
8465
|
-
const sponsor = this.findSponsor(sponsorId);
|
|
9388
|
+
const sponsor = this.sponsorCommerce(sponsorId, ctx ?? {});
|
|
8466
9389
|
if (!sponsor) {
|
|
9390
|
+
const channel = channelIdOf(ctx?.channelId);
|
|
8467
9391
|
throw new Error(
|
|
8468
|
-
`[Vio] Sponsor ${sponsorId} not found in bootstrap. Call Vio.bootstrap() first or pass commerce-key directly.`
|
|
9392
|
+
channel !== void 0 ? `[Vio] Channel ${channel} of sponsor ${sponsorId} not found in bootstrap.` : `[Vio] Sponsor ${sponsorId} not found in bootstrap. Call Vio.bootstrap() first or pass commerce-key directly.`
|
|
8469
9393
|
);
|
|
8470
9394
|
}
|
|
9395
|
+
const apiKey = sponsor.commerce.apiKey;
|
|
9396
|
+
const cacheKey = `${sponsorId}:${apiKey}`;
|
|
9397
|
+
const existing = this.commerceClients.get(cacheKey);
|
|
9398
|
+
if (existing) return existing;
|
|
8471
9399
|
const cfg = Configuration.get();
|
|
8472
|
-
const client = createCommerceClient({ endpoint: cfg.graphQLBase, apiKey
|
|
8473
|
-
this.commerceClients.set(
|
|
9400
|
+
const client = createCommerceClient({ endpoint: cfg.graphQLBase, apiKey });
|
|
9401
|
+
this.commerceClients.set(cacheKey, client);
|
|
8474
9402
|
return client;
|
|
8475
9403
|
}
|
|
8476
9404
|
/** Get a CommerceClient using an explicit commerce apiKey (skip bootstrap). */
|
|
@@ -8505,9 +9433,9 @@ var VioFacade = class {
|
|
|
8505
9433
|
for (const l of all) {
|
|
8506
9434
|
if (l.campaignId !== void 0 && l.campaignId === pageCampaignId) delete l.campaignId;
|
|
8507
9435
|
}
|
|
8508
|
-
const
|
|
9436
|
+
const memory2 = readSlotDeclaration(storageKey);
|
|
8509
9437
|
const keyOf = (l) => slotDeclarationKey(l, pageCampaignId);
|
|
8510
|
-
const pending2 = new Set(pendingSlotKeys(
|
|
9438
|
+
const pending2 = new Set(pendingSlotKeys(memory2, all.map(keyOf), now));
|
|
8511
9439
|
let locations = opts.force ? all : all.filter((l) => pending2.has(keyOf(l)));
|
|
8512
9440
|
if (locations.length === 0) return null;
|
|
8513
9441
|
if (locations.length > MAX_LOCATIONS_PER_DECLARATION) {
|
|
@@ -8540,11 +9468,11 @@ var VioFacade = class {
|
|
|
8540
9468
|
if (result?.mode === "merge") {
|
|
8541
9469
|
const unhandled = this.campaignNotTakenUp(result, locations, pageCampaignId);
|
|
8542
9470
|
const settled = keys.filter((k) => !unhandled.has(k));
|
|
8543
|
-
let next = rememberSlotKeys(
|
|
9471
|
+
let next = rememberSlotKeys(memory2, settled, now);
|
|
8544
9472
|
if (unhandled.size > 0) next = rememberSlotKeys(next, [...unhandled], failedAt(now));
|
|
8545
9473
|
writeSlotDeclaration(storageKey, next);
|
|
8546
9474
|
} else {
|
|
8547
|
-
writeSlotDeclaration(storageKey, rememberSlotKeys(
|
|
9475
|
+
writeSlotDeclaration(storageKey, rememberSlotKeys(memory2, keys, failedAt(now)));
|
|
8548
9476
|
warn(
|
|
8549
9477
|
"slots declared but the server ignored mode=merge (old server); not caching, will retry next load"
|
|
8550
9478
|
);
|
|
@@ -8809,9 +9737,10 @@ var VioFacade = class {
|
|
|
8809
9737
|
* The attribution of the order a sponsor's cart is about to become
|
|
8810
9738
|
* (ADR-0035 phase B) — what `CreateCheckout` / `UpdateCheckout` send as
|
|
8811
9739
|
* `attribution` and shopcart writes on the order: the surface (its SDK
|
|
8812
|
-
* key), the
|
|
8813
|
-
*
|
|
8814
|
-
*
|
|
9740
|
+
* key), the campaign of the order — always one the cart's sponsor takes part
|
|
9741
|
+
* in (`orderCampaign`: the cart lines' own campaign, else the page's;
|
|
9742
|
+
* without one, the campaign that explains most units of the cart under the
|
|
9743
|
+
* same rule `purchase` is split by — `cartSlices`) and, on a surface KNOWN to be `standard`
|
|
8815
9744
|
* (`privacyModeNow`), the page (`content()`'s url as origin + path, and
|
|
8816
9745
|
* title) and where the session came in: the landing the session REMEMBERS
|
|
8817
9746
|
* (`storedLanding`, else the one analytics resolved on this page) — never
|
|
@@ -8823,10 +9752,13 @@ var VioFacade = class {
|
|
|
8823
9752
|
try {
|
|
8824
9753
|
const config = Configuration.isInitialized ? Configuration.get() : void 0;
|
|
8825
9754
|
const content = this.content();
|
|
9755
|
+
const sponsor = toSponsorId(sponsorId);
|
|
9756
|
+
const belongs = (campaignId) => campaignId === void 0 || campaignTakesSponsor(this.cachedBootstrap, campaignId, sponsor);
|
|
8826
9757
|
return checkoutAttributionOf({
|
|
8827
9758
|
surfaceKey: config?.apiKey,
|
|
8828
|
-
pageCampaignId:
|
|
8829
|
-
slices
|
|
9759
|
+
pageCampaignId: this.orderCampaign(sponsor),
|
|
9760
|
+
// The fallback campaign of the slices, too, only when it is the sponsor's.
|
|
9761
|
+
slices: this.cartSlices(sponsorId).filter((slice) => belongs(slice.campaignId)),
|
|
8830
9762
|
content: { url: content.url, title: content.title },
|
|
8831
9763
|
landing: this.rememberedLanding(),
|
|
8832
9764
|
privacyMode: this.privacyModeNow()
|
|
@@ -8835,6 +9767,29 @@ var VioFacade = class {
|
|
|
8835
9767
|
return void 0;
|
|
8836
9768
|
}
|
|
8837
9769
|
}
|
|
9770
|
+
/**
|
|
9771
|
+
* The campaign an order of `sponsorId` is credited to — one article = one
|
|
9772
|
+
* campaign = one sponsor, so it is always one the sponsor takes part in:
|
|
9773
|
+
* the campaign the cart's own lines were added from (their origins; the one
|
|
9774
|
+
* that explains most units), else the page's — the elements' campaigns on
|
|
9775
|
+
* the page (`vio-campaign` / `data-vio-campaign`, in document order), then
|
|
9776
|
+
* `Vio.init({ campaignId })` — the first one active with that sponsor.
|
|
9777
|
+
* `undefined` when neither says one (the slices then decide). Without a
|
|
9778
|
+
* sponsor, the page's campaign as before.
|
|
9779
|
+
*/
|
|
9780
|
+
orderCampaign(sponsorId) {
|
|
9781
|
+
const boot = this.cachedBootstrap;
|
|
9782
|
+
if (sponsorId !== void 0) {
|
|
9783
|
+
const lines = [...this.cart.getCart(sponsorId)?.items ?? []];
|
|
9784
|
+
const fromLines = dominantCampaignOf(
|
|
9785
|
+
cartSlicesFrom(lines, () => void 0).filter(
|
|
9786
|
+
(slice) => slice.campaignId !== void 0 && campaignTakesSponsor(boot, slice.campaignId, sponsorId)
|
|
9787
|
+
)
|
|
9788
|
+
);
|
|
9789
|
+
if (fromLines !== void 0) return fromLines;
|
|
9790
|
+
}
|
|
9791
|
+
return toNumber(activeCampaignEntry(boot, this.pageCampaignCandidates(documentCampaignHints()), sponsorId)?.id);
|
|
9792
|
+
}
|
|
8838
9793
|
/** The landing the session remembers: what the first page stored, else what analytics resolved on this page load (consent pending); null otherwise. */
|
|
8839
9794
|
rememberedLanding() {
|
|
8840
9795
|
try {
|
|
@@ -8936,6 +9891,35 @@ var VioFacade = class {
|
|
|
8936
9891
|
return findSponsorIn(this.cachedBootstrap, sponsorId);
|
|
8937
9892
|
}
|
|
8938
9893
|
};
|
|
9894
|
+
function campaignTakesSponsor(boot, campaignId, sponsorId) {
|
|
9895
|
+
if (sponsorId === void 0 || !boot) return true;
|
|
9896
|
+
try {
|
|
9897
|
+
const listed = (Array.isArray(boot.campaigns) ? boot.campaigns : []).filter(
|
|
9898
|
+
(c) => !!c && typeof c === "object" && toNumber(c.id) === campaignId
|
|
9899
|
+
);
|
|
9900
|
+
if (listed.length > 0) return listed.some((c) => campaignSponsorIds(c).includes(sponsorId));
|
|
9901
|
+
if (toNumber(boot.campaign?.id) === campaignId) {
|
|
9902
|
+
const entry = defaultCampaignEntry(boot);
|
|
9903
|
+
return !!entry && campaignSponsorIds(entry).includes(sponsorId);
|
|
9904
|
+
}
|
|
9905
|
+
return true;
|
|
9906
|
+
} catch {
|
|
9907
|
+
return true;
|
|
9908
|
+
}
|
|
9909
|
+
}
|
|
9910
|
+
function documentCampaignHints() {
|
|
9911
|
+
try {
|
|
9912
|
+
if (typeof document === "undefined" || typeof document.querySelectorAll !== "function") return [];
|
|
9913
|
+
const out = [];
|
|
9914
|
+
document.querySelectorAll("[vio-campaign], [data-vio-campaign]").forEach((el) => {
|
|
9915
|
+
const value = el.getAttribute("vio-campaign") || el.getAttribute("data-vio-campaign");
|
|
9916
|
+
if (value) out.push(value);
|
|
9917
|
+
});
|
|
9918
|
+
return out;
|
|
9919
|
+
} catch {
|
|
9920
|
+
return [];
|
|
9921
|
+
}
|
|
9922
|
+
}
|
|
8939
9923
|
function warn(...args) {
|
|
8940
9924
|
if (typeof console !== "undefined") console.warn("[Vio]", ...args);
|
|
8941
9925
|
}
|
|
@@ -8994,6 +9978,6 @@ function vippsButtonAttributes(verb = "buy", opts = {}) {
|
|
|
8994
9978
|
};
|
|
8995
9979
|
}
|
|
8996
9980
|
|
|
8997
|
-
export { ADD_ITEM_MUTATION, ADYEN_RETURN_METHOD, ADYEN_RETURN_QUERY_KEYS, AdyenOriginError, AnalyticsManager, BUYER_REF_MAX_LENGTH, 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, CartManager, CheckoutManager, CommerceClient, Configuration, DELETE_ITEM_MUTATION, GET_AVAILABLE_PAYMENT_METHODS_QUERY, GET_CART_QUERY, GET_CHECKOUT_QUERY, GET_LINE_ITEMS_BY_SUPPLIER_QUERY, GET_VIPPS_STATUS_QUERY, GRAPHQL_INT_MAX, KUSTOM_RETURN_QUERY_KEYS, LINE_ORIGIN_CAPS, SDK_VERSION, 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, __decorateClass, activeCampaignEntry, addItem, adyenReturnOutcome, adyenReturnParams, autoSlotDisplayName, autoSlotId, buyerRefOf, campaignCandidates, capContentUrl, cartSlicesFrom, checkApplePayAvailability, checkoutAttributionOf, checkoutSponsorOf, componentKindOf, createCart, createCheckout, createCommerceClient, createPaymentStripe, createPaymentVipps, createVioApi, deleteItem, displayPrice, dominantCampaignOf, ensureVippsButton, entryContextOf, executeCartGraphQL, formatPrice, gatewayHas, gatewayHasBuyerRef, getAvailablePaymentMethods, getCart, getCartGraphQLOptions, getCheckout, getCheckoutReference, getCustomerSessionId, getGlobalCurrency, getLineItemsBySupplier, getVippsStatus, isUnknownFeatureError, isUnknownTokenError, kustomReturnOutcome, landingUrl, lineOriginWire, lineOrigins, nexiReturnPaymentId, normalizeBuyerRef, normalizeOrigin, normalizeScope, normalizeSlotId, normalizeSlotKind, originAndPath, primaryImageUrl, purchaseFromPaymentSuccess, purchaseIdsOf, readNexiPending, rememberedCheckoutSponsor, resetGatewayFeatures, resolveCampaignId, resolveClientContext, resolveContent, resolveLanding, resolveSlotCampaign, sameOrigin, showApplePaySheet, sponsorCampaignEntry, sponsorIdentityFrom, storedLanding, toCampaignId, updateCheckout, updateItem, updateShippingsBySupplier, vippsButtonAttributes, withGatewayFeature };
|
|
8998
|
-
//# sourceMappingURL=chunk-
|
|
8999
|
-
//# sourceMappingURL=chunk-
|
|
9981
|
+
export { ADD_ITEM_MUTATION, ADYEN_RETURN_METHOD, ADYEN_RETURN_QUERY_KEYS, AdyenOriginError, AnalyticsManager, BUYER_REF_MAX_LENGTH, 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, CartManager, CheckoutManager, CommerceClient, Configuration, DELETE_ITEM_MUTATION, GET_AVAILABLE_PAYMENT_METHODS_QUERY, GET_CART_QUERY, GET_CHECKOUT_QUERY, GET_LINE_ITEMS_BY_SUPPLIER_QUERY, GET_VIPPS_STATUS_QUERY, GRAPHQL_INT_MAX, INTERNAL_KEY, INTERNAL_PARAM, KUSTOM_RETURN_QUERY_KEYS, LINE_ORIGIN_CAPS, SDK_VERSION, 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, __decorateClass, activeCampaignEntry, addItem, adyenReturnOutcome, adyenReturnParams, autoSlotDisplayName, autoSlotId, buyerRefOf, campaignCandidates, capContentUrl, cartSlicesFrom, checkApplePayAvailability, checkoutAttributionOf, checkoutSponsorOf, componentKindOf, createCart, createCheckout, createCommerceClient, createPaymentStripe, createPaymentVipps, createVioApi, deleteItem, displayPrice, dominantCampaignOf, ensureVippsButton, entryContextOf, executeCartGraphQL, formatPrice, gatewayHas, gatewayHasBuyerRef, getAvailablePaymentMethods, getCart, getCartGraphQLOptions, getCheckout, getCheckoutReference, getCustomerSessionId, getGlobalCountryCode, getGlobalCurrency, getLineItemsBySupplier, getVippsStatus, isUnknownFeatureError, isUnknownTokenError, isValidPhone, kustomReturnOutcome, landingUrl, lineOriginWire, lineOrigins, nexiReturnPaymentId, normalizeBuyerRef, normalizeOrigin, normalizeScope, normalizeSlotId, normalizeSlotKind, originAndPath, primaryImageUrl, purchaseFromPaymentSuccess, purchaseIdsOf, readInternal, readNexiPending, rememberedCheckoutSponsor, resetGatewayFeatures, resolveCampaignId, resolveClientContext, resolveContent, resolveInternal, resolveLanding, resolveSlotCampaign, sameOrigin, shippingDescriptionOf, showApplePaySheet, sponsorCampaignEntry, sponsorIdentityFrom, storageGet, storedLanding, toCampaignId, updateCheckout, updateItem, updateShippingsBySupplier, vippsButtonAttributes, withGatewayFeature, writeInternal };
|
|
9982
|
+
//# sourceMappingURL=chunk-ZORYG4W3.js.map
|
|
9983
|
+
//# sourceMappingURL=chunk-ZORYG4W3.js.map
|