@vio-live/web-sdk 0.29.0 → 0.32.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 +171 -0
- package/README.md +108 -15
- package/dist/{chunk-L6YYYKQK.js → chunk-C5Q6W4B2.js} +1392 -202
- package/dist/chunk-C5Q6W4B2.js.map +1 -0
- package/dist/{chunk-AG4G2S2M.js → chunk-IR4XYTZL.js} +493 -79
- package/dist/chunk-IR4XYTZL.js.map +1 -0
- package/dist/chunk-QGJUBVH3.js +3 -0
- package/dist/{chunk-67QESEV2.js.map → chunk-QGJUBVH3.js.map} +1 -1
- package/dist/core/index.d.ts +147 -3
- 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-D1DCVzOf.d.ts} +311 -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,64 @@ 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
|
+
function shippingRatesFor(productShipping, country) {
|
|
845
|
+
if (!Array.isArray(productShipping)) return [];
|
|
846
|
+
const want = String(country || "").trim().toUpperCase();
|
|
847
|
+
const out = [];
|
|
848
|
+
for (const s of productShipping) {
|
|
849
|
+
const countries = Array.isArray(s?.shipping_country) ? s.shipping_country : [];
|
|
850
|
+
const row = countries.find((c) => String(c?.country ?? "").trim().toUpperCase() === want);
|
|
851
|
+
const price = row?.price;
|
|
852
|
+
const amount = typeof price?.amount_incl_taxes === "number" ? price.amount_incl_taxes : price?.amount;
|
|
853
|
+
if (typeof amount !== "number" || !Number.isFinite(amount) || amount < 0) continue;
|
|
854
|
+
out.push({
|
|
855
|
+
id: String(s.id ?? ""),
|
|
856
|
+
name: String(s.name ?? ""),
|
|
857
|
+
price: amount,
|
|
858
|
+
currency: String(price?.currency_code ?? ""),
|
|
859
|
+
default: s.default === true,
|
|
860
|
+
description: typeof s.description === "string" ? s.description.trim() : "",
|
|
861
|
+
logoUrl: httpsUrlOrEmpty(s.logo_url ?? s.logoUrl)
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
return out.sort((a, b) => a.price - b.price);
|
|
865
|
+
}
|
|
708
866
|
var Channel = class {
|
|
709
867
|
constructor(client) {
|
|
710
868
|
this.product = new ChannelProduct(client);
|
|
@@ -723,6 +881,11 @@ var CommerceClient = class {
|
|
|
723
881
|
function createCommerceClient(options) {
|
|
724
882
|
return new CommerceClient(options);
|
|
725
883
|
}
|
|
884
|
+
function httpsUrlOrEmpty(value) {
|
|
885
|
+
if (typeof value !== "string") return "";
|
|
886
|
+
const url = value.trim();
|
|
887
|
+
return /^https:\/\/[^\s]+$/i.test(url) ? url : "";
|
|
888
|
+
}
|
|
726
889
|
|
|
727
890
|
// src/core/content.ts
|
|
728
891
|
var CONTENT_ID_QUERY = "vio_content";
|
|
@@ -1890,11 +2053,10 @@ async function getCartGraphQLOptions(sponsorId) {
|
|
|
1890
2053
|
}
|
|
1891
2054
|
var CUSTOMER_SESSION_KEY = "vio.customer_session_id.v1";
|
|
1892
2055
|
function getCustomerSessionId() {
|
|
1893
|
-
|
|
1894
|
-
let id = localStorage.getItem(CUSTOMER_SESSION_KEY);
|
|
2056
|
+
let id = storageGet("local", CUSTOMER_SESSION_KEY);
|
|
1895
2057
|
if (!id) {
|
|
1896
2058
|
id = "cs_" + Math.random().toString(36).slice(2, 11) + Date.now().toString(36);
|
|
1897
|
-
|
|
2059
|
+
storageSet("local", CUSTOMER_SESSION_KEY, id);
|
|
1898
2060
|
}
|
|
1899
2061
|
return id;
|
|
1900
2062
|
}
|
|
@@ -2881,19 +3043,23 @@ var CartManager = class extends EventTarget {
|
|
|
2881
3043
|
return formatPrice(this.totalAcrossSponsors, this.primaryCurrency);
|
|
2882
3044
|
}
|
|
2883
3045
|
// MARK: - Persistence
|
|
3046
|
+
/**
|
|
3047
|
+
* Keep the carts for the next page and the other tabs. Where storage
|
|
3048
|
+
* refuses (in-app browsers, private modes) nothing throws (safe-storage.ts):
|
|
3049
|
+
* the carts stay in this manager's own map, the add to cart and the
|
|
3050
|
+
* checkout go on, and the cart just does not survive a reload there.
|
|
3051
|
+
*/
|
|
2884
3052
|
persist() {
|
|
2885
|
-
if (typeof localStorage === "undefined") return;
|
|
2886
3053
|
try {
|
|
2887
3054
|
const obj = {};
|
|
2888
3055
|
for (const [k, v] of this.cartsBySponsor) obj[String(k)] = v;
|
|
2889
|
-
|
|
3056
|
+
storageSet("local", STORAGE_KEY, JSON.stringify(obj), { memory: false });
|
|
2890
3057
|
} catch {
|
|
2891
3058
|
}
|
|
2892
3059
|
}
|
|
2893
3060
|
loadFromStorage() {
|
|
2894
|
-
if (typeof localStorage === "undefined") return /* @__PURE__ */ new Map();
|
|
2895
3061
|
try {
|
|
2896
|
-
const raw =
|
|
3062
|
+
const raw = storageGet("local", STORAGE_KEY);
|
|
2897
3063
|
if (!raw) return /* @__PURE__ */ new Map();
|
|
2898
3064
|
const obj = JSON.parse(raw);
|
|
2899
3065
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -3055,13 +3221,15 @@ function sponsorIdentityFrom(boot, sponsorId) {
|
|
|
3055
3221
|
if (!name && !logoUrl) return null;
|
|
3056
3222
|
const termsUrl = pageUrlOrNull(sponsor.termsUrl);
|
|
3057
3223
|
const refundPolicyUrl = pageUrlOrNull(sponsor.refundPolicyUrl);
|
|
3224
|
+
const highlights = highlightsOf(sponsor.highlights);
|
|
3058
3225
|
return {
|
|
3059
3226
|
id,
|
|
3060
3227
|
name,
|
|
3061
3228
|
logoUrl,
|
|
3062
3229
|
avatarUrl: urlOrNull(sponsor.avatarUrl),
|
|
3063
3230
|
...termsUrl ? { termsUrl } : {},
|
|
3064
|
-
...refundPolicyUrl ? { refundPolicyUrl } : {}
|
|
3231
|
+
...refundPolicyUrl ? { refundPolicyUrl } : {},
|
|
3232
|
+
...highlights.length ? { highlights } : {}
|
|
3065
3233
|
};
|
|
3066
3234
|
} catch {
|
|
3067
3235
|
return null;
|
|
@@ -3156,6 +3324,20 @@ function rememberedSponsor(sponsorId) {
|
|
|
3156
3324
|
return null;
|
|
3157
3325
|
}
|
|
3158
3326
|
}
|
|
3327
|
+
function highlightsOf(value) {
|
|
3328
|
+
if (!Array.isArray(value)) return [];
|
|
3329
|
+
const out = [];
|
|
3330
|
+
for (const item of value) {
|
|
3331
|
+
if (!item || typeof item !== "object") continue;
|
|
3332
|
+
const { icon, title, text: text3 } = item;
|
|
3333
|
+
const t = typeof title === "string" ? title.trim() : "";
|
|
3334
|
+
if (!t) continue;
|
|
3335
|
+
const body = typeof text3 === "string" ? text3.trim() : "";
|
|
3336
|
+
out.push({ icon: typeof icon === "string" ? icon.trim() : "", title: t, ...body ? { text: body } : {} });
|
|
3337
|
+
if (out.length === 3) break;
|
|
3338
|
+
}
|
|
3339
|
+
return out;
|
|
3340
|
+
}
|
|
3159
3341
|
|
|
3160
3342
|
// src/core/checkout/payments/apple-pay.ts
|
|
3161
3343
|
var STRIPE_JS_URL = "https://js.stripe.com/v3";
|
|
@@ -3353,7 +3535,7 @@ async function prepareApplePay(config) {
|
|
|
3353
3535
|
}
|
|
3354
3536
|
|
|
3355
3537
|
// src/core/version.ts
|
|
3356
|
-
var SDK_VERSION = "0.
|
|
3538
|
+
var SDK_VERSION = "0.32.0";
|
|
3357
3539
|
|
|
3358
3540
|
// src/core/checkout/payments/stripe-embedded.ts
|
|
3359
3541
|
var CREATE_PAYMENT_INTENT_STRIPE_MUTATION = `
|
|
@@ -3519,11 +3701,8 @@ async function mountKlarnaExpressButton(opts) {
|
|
|
3519
3701
|
const returnUrl = opts.returnUrl ?? (typeof window !== "undefined" ? window.location.origin + window.location.pathname : "");
|
|
3520
3702
|
let settled = false;
|
|
3521
3703
|
button.on("click", () => {
|
|
3522
|
-
if (opts.pendingKey && opts.pendingContext
|
|
3523
|
-
|
|
3524
|
-
sessionStorage.setItem(opts.pendingKey, JSON.stringify(opts.pendingContext));
|
|
3525
|
-
} catch {
|
|
3526
|
-
}
|
|
3704
|
+
if (opts.pendingKey && opts.pendingContext) {
|
|
3705
|
+
storageSet("session", opts.pendingKey, JSON.stringify(opts.pendingContext));
|
|
3527
3706
|
}
|
|
3528
3707
|
const promise = sdk.Payment.initiate(() => ({
|
|
3529
3708
|
currency: opts.paymentRequest.currency,
|
|
@@ -4601,6 +4780,74 @@ function adyenReturnOutcome(payment) {
|
|
|
4601
4780
|
}
|
|
4602
4781
|
}
|
|
4603
4782
|
|
|
4783
|
+
// src/core/checkout/phone.ts
|
|
4784
|
+
var CALLING_CODES = {
|
|
4785
|
+
NO: "47",
|
|
4786
|
+
SE: "46",
|
|
4787
|
+
DK: "45",
|
|
4788
|
+
FI: "358",
|
|
4789
|
+
IS: "354",
|
|
4790
|
+
DE: "49",
|
|
4791
|
+
GB: "44",
|
|
4792
|
+
UK: "44",
|
|
4793
|
+
IE: "353",
|
|
4794
|
+
NL: "31",
|
|
4795
|
+
BE: "32",
|
|
4796
|
+
FR: "33",
|
|
4797
|
+
ES: "34",
|
|
4798
|
+
PT: "351",
|
|
4799
|
+
IT: "39",
|
|
4800
|
+
AT: "43",
|
|
4801
|
+
CH: "41",
|
|
4802
|
+
PL: "48",
|
|
4803
|
+
EE: "372",
|
|
4804
|
+
LV: "371",
|
|
4805
|
+
LT: "370",
|
|
4806
|
+
CZ: "420",
|
|
4807
|
+
SK: "421",
|
|
4808
|
+
HU: "36",
|
|
4809
|
+
US: "1",
|
|
4810
|
+
CA: "1"
|
|
4811
|
+
};
|
|
4812
|
+
var KNOWN_CODES = [...new Set(Object.values(CALLING_CODES))].sort((a, b) => b.length - a.length);
|
|
4813
|
+
var NATIONAL_LENGTH = {
|
|
4814
|
+
"47": [8, 8],
|
|
4815
|
+
"45": [8, 8],
|
|
4816
|
+
"46": [7, 9],
|
|
4817
|
+
"358": [6, 10],
|
|
4818
|
+
"49": [10, 11],
|
|
4819
|
+
"44": [10, 10],
|
|
4820
|
+
"1": [10, 10]
|
|
4821
|
+
};
|
|
4822
|
+
function callingCodeFor(country) {
|
|
4823
|
+
return CALLING_CODES[String(country ?? "").trim().toUpperCase()] ?? null;
|
|
4824
|
+
}
|
|
4825
|
+
function parsePhone(raw, country) {
|
|
4826
|
+
const typed = String(raw ?? "").trim().replace(/[\s\-().]/g, "");
|
|
4827
|
+
if (!typed) return null;
|
|
4828
|
+
let code = null;
|
|
4829
|
+
let national;
|
|
4830
|
+
if (/^(\+|00)/.test(typed)) {
|
|
4831
|
+
const digits = typed.replace(/^(\+|00)/, "");
|
|
4832
|
+
if (!/^\d+$/.test(digits)) return null;
|
|
4833
|
+
code = KNOWN_CODES.find((c) => digits.startsWith(c)) ?? null;
|
|
4834
|
+
if (!code) return null;
|
|
4835
|
+
national = digits.slice(code.length);
|
|
4836
|
+
} else {
|
|
4837
|
+
if (!/^\d+$/.test(typed)) return null;
|
|
4838
|
+
code = callingCodeFor(country);
|
|
4839
|
+
if (!code) return null;
|
|
4840
|
+
national = typed;
|
|
4841
|
+
}
|
|
4842
|
+
if (national.startsWith("0") && code !== "47" && code !== "45") national = national.slice(1);
|
|
4843
|
+
const [min, max] = NATIONAL_LENGTH[code] ?? [6, 12];
|
|
4844
|
+
if (national.length < min || national.length > max) return null;
|
|
4845
|
+
return { phone: national, phone_code: code };
|
|
4846
|
+
}
|
|
4847
|
+
function isValidPhone(raw, country) {
|
|
4848
|
+
return parsePhone(raw, country) !== null;
|
|
4849
|
+
}
|
|
4850
|
+
|
|
4604
4851
|
// src/core/checkout/checkout-manager.ts
|
|
4605
4852
|
function describeError(err) {
|
|
4606
4853
|
if (err instanceof Error) return err.message;
|
|
@@ -4618,6 +4865,7 @@ function describeError(err) {
|
|
|
4618
4865
|
}
|
|
4619
4866
|
return String(err);
|
|
4620
4867
|
}
|
|
4868
|
+
var KLARNA_CONFIRMED_KEY = "vio.klarna.confirmed.v1";
|
|
4621
4869
|
var KLARNA_PENDING_KEY = "vio.klarna.pending.v1";
|
|
4622
4870
|
var KLARNA_SHIPPING_OPTIONS = [
|
|
4623
4871
|
{
|
|
@@ -4781,15 +5029,20 @@ function buildCheckoutAddress(address) {
|
|
|
4781
5029
|
const zip = address.postalCode || address.postal_code || address.zip || null;
|
|
4782
5030
|
const country_code = address.countryCode || address.country_code || address.country || getGlobalCountryCode();
|
|
4783
5031
|
if (!firstName && !lastName && !address1 && !city && !zip) return null;
|
|
5032
|
+
const phone = parsePhone(address.phone, country_code);
|
|
4784
5033
|
return {
|
|
4785
5034
|
first_name: firstName,
|
|
4786
5035
|
last_name: lastName,
|
|
4787
5036
|
address1,
|
|
4788
5037
|
city,
|
|
4789
5038
|
zip,
|
|
4790
|
-
country_code
|
|
5039
|
+
country_code,
|
|
5040
|
+
...phone ? { phone: phone.phone, phone_code: phone.phone_code } : {}
|
|
4791
5041
|
};
|
|
4792
5042
|
}
|
|
5043
|
+
function isCompleteCheckoutAddress(a) {
|
|
5044
|
+
return !!a && ["first_name", "last_name", "address1", "city", "zip"].every((k) => String(a[k] ?? "").trim().length > 0);
|
|
5045
|
+
}
|
|
4793
5046
|
function adyenReturnUrl(params) {
|
|
4794
5047
|
let page = null;
|
|
4795
5048
|
if (typeof window !== "undefined" && window.location?.href) {
|
|
@@ -4854,6 +5107,18 @@ function resolveHttpsReturnUrl(overrideUrl, params = null) {
|
|
|
4854
5107
|
async function executeKlarnaGraphQL(query, variables, sponsorId) {
|
|
4855
5108
|
return executeCartGraphQL(query, variables, await getCartGraphQLOptions(sponsorId));
|
|
4856
5109
|
}
|
|
5110
|
+
function usesStripe(methods) {
|
|
5111
|
+
if (!Array.isArray(methods)) return false;
|
|
5112
|
+
return methods.some((m) => {
|
|
5113
|
+
if (String(m?.name ?? "").toLowerCase() !== "stripe") return false;
|
|
5114
|
+
const config = Array.isArray(m?.config) ? m.config : [];
|
|
5115
|
+
const key = config.find((c) => c?.name === "publishableKey")?.value;
|
|
5116
|
+
return typeof key === "string" && key.startsWith("pk_");
|
|
5117
|
+
});
|
|
5118
|
+
}
|
|
5119
|
+
function cartTotal(items) {
|
|
5120
|
+
return items.reduce((sum, i) => sum + (Number(i.unitPrice) || 0) * (Number(i.quantity) || 0), 0);
|
|
5121
|
+
}
|
|
4857
5122
|
var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
4858
5123
|
constructor(cartManager, deps = {}) {
|
|
4859
5124
|
super();
|
|
@@ -4907,7 +5172,9 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
4907
5172
|
/** In-flight `getOrderReference` per checkout id (see there). */
|
|
4908
5173
|
this.referenceInFlight = /* @__PURE__ */ new Map();
|
|
4909
5174
|
this.kustomController = null;
|
|
4910
|
-
|
|
5175
|
+
if (Configuration.isInitialized && Configuration.get()?.stripePublishableKey) {
|
|
5176
|
+
preloadStripeJs();
|
|
5177
|
+
}
|
|
4911
5178
|
if (typeof cartManager.addEventListener === "function") {
|
|
4912
5179
|
cartManager.addEventListener("change", () => this.onCartChange());
|
|
4913
5180
|
}
|
|
@@ -4944,6 +5211,9 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
4944
5211
|
if (!cart || cart.items.length === 0) {
|
|
4945
5212
|
throw new Error(`[VioCheckout] sponsor ${sponsorId} has no cart items`);
|
|
4946
5213
|
}
|
|
5214
|
+
if (!(cartTotal(cart.items) > 0)) {
|
|
5215
|
+
throw new Error(`[VioCheckout] sponsor ${sponsorId} has a cart that totals 0`);
|
|
5216
|
+
}
|
|
4947
5217
|
this.state = {
|
|
4948
5218
|
sponsorId,
|
|
4949
5219
|
session: ++this.sessionSeq,
|
|
@@ -5059,6 +5329,21 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5059
5329
|
} catch {
|
|
5060
5330
|
}
|
|
5061
5331
|
}
|
|
5332
|
+
/**
|
|
5333
|
+
* Nothing is created or paid for a cart that is empty or totals 0 — as
|
|
5334
|
+
* the SERVER has it (the callers read it from the server first). Throws,
|
|
5335
|
+
* so a payment button ends in its error path, never at a provider asking
|
|
5336
|
+
* for 0 kr.
|
|
5337
|
+
*/
|
|
5338
|
+
assertPayableCart(sponsorId) {
|
|
5339
|
+
const cart = this.cartManager.getCart(sponsorId);
|
|
5340
|
+
if (!cart || !Array.isArray(cart.items) || cart.items.length === 0) {
|
|
5341
|
+
throw new Error(`[CheckoutManager] the cart of sponsor ${sponsorId} is empty \u2014 nothing to pay`);
|
|
5342
|
+
}
|
|
5343
|
+
if (!(cartTotal(cart.items) > 0)) {
|
|
5344
|
+
throw new Error(`[CheckoutManager] the cart of sponsor ${sponsorId} totals 0 \u2014 nothing to pay`);
|
|
5345
|
+
}
|
|
5346
|
+
}
|
|
5062
5347
|
/** Update the backend checkout (terms are re-asserted unless overridden; the attribution rides along unless the caller gives its own). */
|
|
5063
5348
|
async updateCheckout(variables, sponsorId) {
|
|
5064
5349
|
const spId = sponsorId ?? this.state?.sponsorId;
|
|
@@ -5189,6 +5474,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5189
5474
|
const opts = await getCartGraphQLOptions(spId);
|
|
5190
5475
|
const res = await getAvailablePaymentMethods(opts);
|
|
5191
5476
|
if (res) this.paymentMethodsCache.set(spId, res);
|
|
5477
|
+
if (usesStripe(res)) preloadStripeJs();
|
|
5192
5478
|
return res;
|
|
5193
5479
|
} finally {
|
|
5194
5480
|
this.paymentMethodsPromises.delete(spId);
|
|
@@ -5288,11 +5574,21 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5288
5574
|
* backend cart + checkout exist, push email/address onto the checkout, and
|
|
5289
5575
|
* return everything the payment mutation needs.
|
|
5290
5576
|
*/
|
|
5291
|
-
async prepareRedirectPayment(sponsorId, formData, extraUpdateVars = {}, leaving = false) {
|
|
5577
|
+
async prepareRedirectPayment(sponsorId, formData, extraUpdateVars = {}, leaving = false, vippsWithAddress = false) {
|
|
5292
5578
|
const spId = sponsorId ?? this.state?.sponsorId;
|
|
5293
5579
|
if (!spId) throw new Error("[CheckoutManager] no sponsor for payment");
|
|
5294
5580
|
await this.cartManager.waitForCartMutations(spId);
|
|
5295
5581
|
await this.cartManager.refreshFromServer(spId);
|
|
5582
|
+
this.assertPayableCart(spId);
|
|
5583
|
+
const isVipps = extraUpdateVars?.paymentMethod === "Vipps";
|
|
5584
|
+
const addr = typeof formData === "object" && formData !== null ? formData : this.state?.address;
|
|
5585
|
+
const built = buildCheckoutAddress(addr);
|
|
5586
|
+
if (isVipps && vippsWithAddress && !(isCompleteCheckoutAddress(built) && built?.phone)) {
|
|
5587
|
+
throw new Error(
|
|
5588
|
+
"[CheckoutManager] the standard Vipps payment needs the complete delivery address (name, street, postcode, city and a mobile number) \u2014 no payment started"
|
|
5589
|
+
);
|
|
5590
|
+
}
|
|
5591
|
+
const addressObj = !isVipps ? built : vippsWithAddress ? built : null;
|
|
5296
5592
|
const cart = this.cartManager.getCart(spId);
|
|
5297
5593
|
let cartId = cart?.cartId;
|
|
5298
5594
|
if (!cartId) {
|
|
@@ -5315,9 +5611,6 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5315
5611
|
if (!checkoutId) {
|
|
5316
5612
|
throw new Error("[CheckoutManager] no backend checkout \u2014 cannot start the payment");
|
|
5317
5613
|
}
|
|
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
5614
|
const emailVal = (typeof formData === "string" ? formData : formData?.email) || this.state?.address?.email || "";
|
|
5322
5615
|
const hasEmail = !!emailVal && emailVal.includes("@");
|
|
5323
5616
|
if (!hasEmail && !isVipps) {
|
|
@@ -5412,6 +5705,11 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5412
5705
|
* so the caller can open the ordinary checkout instead. Without the flag
|
|
5413
5706
|
* the backend decides: Express while the cart has no delivery yet, a
|
|
5414
5707
|
* plain payment once the shopper chose one in our form.
|
|
5708
|
+
*
|
|
5709
|
+
* `express: false` is the checkout's standard path (2026-10-28): the
|
|
5710
|
+
* form's address — name, street, mobile — goes on the checkout before the
|
|
5711
|
+
* payment is created, and the delivery already chosen on the cart is what
|
|
5712
|
+
* Vipps charges for.
|
|
5415
5713
|
*/
|
|
5416
5714
|
async startVippsPayment(sponsorId, formData, options = {}) {
|
|
5417
5715
|
const waitFor = sponsorId ?? this.state?.sponsorId;
|
|
@@ -5420,7 +5718,8 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
5420
5718
|
sponsorId,
|
|
5421
5719
|
formData,
|
|
5422
5720
|
{ paymentMethod: "Vipps" },
|
|
5423
|
-
true
|
|
5721
|
+
true,
|
|
5722
|
+
options.express === false
|
|
5424
5723
|
);
|
|
5425
5724
|
const returnUrl = resolveHttpsReturnUrl(null, {
|
|
5426
5725
|
vio_payment: "success",
|
|
@@ -6757,14 +7056,13 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
6757
7056
|
* the SDK's resumed `complete` event — finish creating the order + confirm.
|
|
6758
7057
|
*/
|
|
6759
7058
|
async resumeKlarnaReturn() {
|
|
6760
|
-
|
|
6761
|
-
const raw = sessionStorage.getItem(KLARNA_PENDING_KEY);
|
|
7059
|
+
const raw = storageGet("session", KLARNA_PENDING_KEY);
|
|
6762
7060
|
if (!raw) return;
|
|
6763
7061
|
let pending2;
|
|
6764
7062
|
try {
|
|
6765
7063
|
pending2 = JSON.parse(raw);
|
|
6766
7064
|
} catch {
|
|
6767
|
-
|
|
7065
|
+
storageRemove("session", KLARNA_PENDING_KEY);
|
|
6768
7066
|
return;
|
|
6769
7067
|
}
|
|
6770
7068
|
const fromUrl = readKlarnaTokenFromUrl();
|
|
@@ -6822,7 +7120,7 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
6822
7120
|
async completeKlarnaOrder(authorizationToken, ctx, result) {
|
|
6823
7121
|
if (this.klarnaOrderInFlight) return;
|
|
6824
7122
|
this.klarnaOrderInFlight = true;
|
|
6825
|
-
if (
|
|
7123
|
+
if (storageGet("session", KLARNA_CONFIRMED_KEY) === authorizationToken) {
|
|
6826
7124
|
this.klarnaOrderInFlight = false;
|
|
6827
7125
|
return;
|
|
6828
7126
|
}
|
|
@@ -6850,10 +7148,8 @@ var CheckoutManager = class _CheckoutManager extends EventTarget {
|
|
|
6850
7148
|
}
|
|
6851
7149
|
const orderData = confirmRes.order || confirmRes;
|
|
6852
7150
|
const buyerRef = normalizeBuyerRef(confirmRes[BUYER_REF_FIELD]);
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
sessionStorage.removeItem(KLARNA_PENDING_KEY);
|
|
6856
|
-
}
|
|
7151
|
+
storageSet("session", KLARNA_CONFIRMED_KEY, authorizationToken);
|
|
7152
|
+
storageRemove("session", KLARNA_PENDING_KEY);
|
|
6857
7153
|
const state = this.state ?? { sponsorId: ctx.sponsorId, subtotal: ctx.orderAmount, currency: ctx.currency };
|
|
6858
7154
|
this.dispatchEvent(
|
|
6859
7155
|
new CustomEvent("payment-complete", {
|
|
@@ -7095,6 +7391,54 @@ function safeCall(fn) {
|
|
|
7095
7391
|
}
|
|
7096
7392
|
}
|
|
7097
7393
|
|
|
7394
|
+
// src/core/analytics/internal-traffic.ts
|
|
7395
|
+
var INTERNAL_KEY = "vio.internal.v1";
|
|
7396
|
+
var INTERNAL_PARAM = "vio_internal";
|
|
7397
|
+
function defaultInternalEnvironment() {
|
|
7398
|
+
return {
|
|
7399
|
+
location: typeof location !== "undefined" ? location : null,
|
|
7400
|
+
storage: localStorageOrNull()
|
|
7401
|
+
};
|
|
7402
|
+
}
|
|
7403
|
+
function resolveInternal(env = defaultInternalEnvironment()) {
|
|
7404
|
+
const param = internalParam(env.location?.search);
|
|
7405
|
+
if (param !== void 0) {
|
|
7406
|
+
writeInternal(param, env.storage);
|
|
7407
|
+
return param;
|
|
7408
|
+
}
|
|
7409
|
+
return readInternal(env.storage);
|
|
7410
|
+
}
|
|
7411
|
+
function readInternal(storage2 = defaultInternalEnvironment().storage) {
|
|
7412
|
+
try {
|
|
7413
|
+
return storage2?.getItem(INTERNAL_KEY) === "1";
|
|
7414
|
+
} catch {
|
|
7415
|
+
return false;
|
|
7416
|
+
}
|
|
7417
|
+
}
|
|
7418
|
+
function writeInternal(internal, storage2 = defaultInternalEnvironment().storage) {
|
|
7419
|
+
try {
|
|
7420
|
+
if (internal) storage2?.setItem(INTERNAL_KEY, "1");
|
|
7421
|
+
else storage2?.removeItem?.(INTERNAL_KEY);
|
|
7422
|
+
} catch {
|
|
7423
|
+
}
|
|
7424
|
+
}
|
|
7425
|
+
function internalParam(search) {
|
|
7426
|
+
try {
|
|
7427
|
+
const value = new URLSearchParams(typeof search === "string" ? search : "").get(INTERNAL_PARAM)?.trim();
|
|
7428
|
+
if (value === "1") return true;
|
|
7429
|
+
if (value === "0") return false;
|
|
7430
|
+
} catch {
|
|
7431
|
+
}
|
|
7432
|
+
return void 0;
|
|
7433
|
+
}
|
|
7434
|
+
function localStorageOrNull() {
|
|
7435
|
+
try {
|
|
7436
|
+
return typeof window !== "undefined" && window.localStorage ? window.localStorage : null;
|
|
7437
|
+
} catch {
|
|
7438
|
+
return null;
|
|
7439
|
+
}
|
|
7440
|
+
}
|
|
7441
|
+
|
|
7098
7442
|
// src/core/cart/slices.ts
|
|
7099
7443
|
function cartSlicesFrom(lines, resolveCampaign, fallbackCurrency) {
|
|
7100
7444
|
if (!Array.isArray(lines) || lines.length === 0) return [];
|
|
@@ -7171,6 +7515,7 @@ var FLUSH_AT_COUNT = 20;
|
|
|
7171
7515
|
var MAX_QUEUE = 500;
|
|
7172
7516
|
var RETRY_BACKOFF_MS = [2e3, 4e3, 8e3];
|
|
7173
7517
|
var ANON_KEY = "vio.anon.v1";
|
|
7518
|
+
var MAX_ITEMS = 100;
|
|
7174
7519
|
var SESSION_KEY = "vio.session.v1";
|
|
7175
7520
|
var IMPRESSION_THRESHOLD = 0.5;
|
|
7176
7521
|
var IMPRESSION_DWELL_MS = 1e3;
|
|
@@ -7178,7 +7523,14 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7178
7523
|
constructor() {
|
|
7179
7524
|
super(...arguments);
|
|
7180
7525
|
this.started = false;
|
|
7181
|
-
this.options = {
|
|
7526
|
+
this.options = {
|
|
7527
|
+
host: "custom",
|
|
7528
|
+
collector: true,
|
|
7529
|
+
dataLayer: false,
|
|
7530
|
+
debug: false,
|
|
7531
|
+
autoTrack: true,
|
|
7532
|
+
privateContent: false
|
|
7533
|
+
};
|
|
7182
7534
|
this.queue = [];
|
|
7183
7535
|
this.flushTimer = null;
|
|
7184
7536
|
this.retryAttempt = 0;
|
|
@@ -7199,6 +7551,14 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7199
7551
|
this.client = null;
|
|
7200
7552
|
/** The landing it was read from — persisted later when consent arrives after the first event. */
|
|
7201
7553
|
this.landing = null;
|
|
7554
|
+
/**
|
|
7555
|
+
* Internal traffic (ADR-0041): `client.internal: true` on every event while
|
|
7556
|
+
* set. Read once (`?vio_internal=1|0`, else `localStorage`) at `Vio.init()`
|
|
7557
|
+
* or on the first event; `setInternal()` changes it. `null` = not read yet.
|
|
7558
|
+
*/
|
|
7559
|
+
this.internal = null;
|
|
7560
|
+
/** The console line for testers goes out once per page load. */
|
|
7561
|
+
this.internalAnnounced = false;
|
|
7202
7562
|
/** Checkouts (`c:<id>`) and orders (`o:<number>`) this page load reported a `purchase` for: one each. */
|
|
7203
7563
|
this.purchased = /* @__PURE__ */ new Set();
|
|
7204
7564
|
/** Checkouts this page load reported an `add_payment_info` for: one each. */
|
|
@@ -7248,7 +7608,8 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7248
7608
|
collector: options.collector ?? this.options.collector,
|
|
7249
7609
|
dataLayer: options.dataLayer ?? this.options.dataLayer,
|
|
7250
7610
|
debug: options.debug ?? this.options.debug,
|
|
7251
|
-
autoTrack: options.autoTrack ?? this.options.autoTrack
|
|
7611
|
+
autoTrack: options.autoTrack ?? this.options.autoTrack,
|
|
7612
|
+
privateContent: options.privateContent ?? this.options.privateContent
|
|
7252
7613
|
};
|
|
7253
7614
|
if (options.sessionId) this.externalSessionId = options.sessionId;
|
|
7254
7615
|
if (this.started || !hasDom()) return;
|
|
@@ -7291,6 +7652,43 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7291
7652
|
identify(externalUserId) {
|
|
7292
7653
|
this.externalUserId = externalUserId ?? void 0;
|
|
7293
7654
|
}
|
|
7655
|
+
/**
|
|
7656
|
+
* Mark (or unmark) this browser as Vio's own traffic (ADR-0041): while
|
|
7657
|
+
* marked, every event carries `client.internal: true` and the collector's
|
|
7658
|
+
* reads leave it out. Remembered in `localStorage` (`vio.internal.v1`) —
|
|
7659
|
+
* the same mark `?vio_internal=1` / `?vio_internal=0` sets on any page.
|
|
7660
|
+
*/
|
|
7661
|
+
setInternal(internal) {
|
|
7662
|
+
this.internal = internal === true;
|
|
7663
|
+
writeInternal(this.internal);
|
|
7664
|
+
this.announceInternal();
|
|
7665
|
+
}
|
|
7666
|
+
/** Whether this browser is marked as internal traffic (reads the mark the first time). */
|
|
7667
|
+
get isInternal() {
|
|
7668
|
+
return this.syncInternal();
|
|
7669
|
+
}
|
|
7670
|
+
/**
|
|
7671
|
+
* Read the mark: the page's `?vio_internal=1|0` (remembered), else what the
|
|
7672
|
+
* browser remembers. Once per page load — `Vio.init()` calls it so a page
|
|
7673
|
+
* with the parameter marks the browser even if it never starts analytics;
|
|
7674
|
+
* `force` reads again.
|
|
7675
|
+
*/
|
|
7676
|
+
syncInternal(force = false) {
|
|
7677
|
+
if (this.internal === null || force) {
|
|
7678
|
+
this.internal = hasDom() ? resolveInternal() : readInternal(null);
|
|
7679
|
+
this.announceInternal();
|
|
7680
|
+
}
|
|
7681
|
+
return this.internal;
|
|
7682
|
+
}
|
|
7683
|
+
/** One console line when marked, so a tester can see the mark took. */
|
|
7684
|
+
announceInternal() {
|
|
7685
|
+
if (!this.internal || this.internalAnnounced) return;
|
|
7686
|
+
this.internalAnnounced = true;
|
|
7687
|
+
try {
|
|
7688
|
+
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.");
|
|
7689
|
+
} catch {
|
|
7690
|
+
}
|
|
7691
|
+
}
|
|
7294
7692
|
/** Queue one event. Works pre-init and pre-start (SSR: no-op). */
|
|
7295
7693
|
track(name, opts = {}) {
|
|
7296
7694
|
if (!hasDom()) return;
|
|
@@ -7335,7 +7733,7 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7335
7733
|
this.ensureSession();
|
|
7336
7734
|
if (this.impressedComponents.has(key)) return;
|
|
7337
7735
|
this.impressedComponents.add(key);
|
|
7338
|
-
this.track(name, { context });
|
|
7736
|
+
this.track(name, { context, commerce: impressionCommerce(opts.commerce) });
|
|
7339
7737
|
opts.onImpression?.();
|
|
7340
7738
|
observer.disconnect();
|
|
7341
7739
|
}, IMPRESSION_DWELL_MS);
|
|
@@ -7416,26 +7814,28 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7416
7814
|
// one is usually the tracking tail, not the page. The other host-given
|
|
7417
7815
|
// fields (broadcastId, componentTemplateId, errorCode, variant, …) are
|
|
7418
7816
|
// the host's responsibility: the SDK does not touch them.
|
|
7419
|
-
|
|
7817
|
+
// Con `privateContent` ninguno de los tres sale del dispositivo.
|
|
7818
|
+
content_url: this.options.privateContent ? void 0 : capContentUrl(ctx.contentUrl ?? (typeof location !== "undefined" ? location.href : void 0)),
|
|
7420
7819
|
// The host's own content id — its join key back onto its reporting.
|
|
7421
7820
|
// Explicit on the event when it fits, else what the SDK resolved for
|
|
7422
7821
|
// the page (already capped per source), else nothing.
|
|
7423
|
-
content_id: explicitContentId ?? fitsId(content.id),
|
|
7822
|
+
content_id: this.options.privateContent ? void 0 : explicitContentId ?? fitsId(content.id),
|
|
7424
7823
|
// Deletion-proof reporting: sources have no trash bin — the title
|
|
7425
7824
|
// snapshotted at event time keeps reports legible if content dies.
|
|
7426
7825
|
error_code: ctx.errorCode,
|
|
7427
|
-
content_title: capTitle(
|
|
7826
|
+
content_title: this.options.privateContent ? void 0 : capTitle(
|
|
7428
7827
|
ctx.contentTitle ?? content.title ?? (typeof document !== "undefined" && document.title ? document.title : void 0)
|
|
7429
7828
|
),
|
|
7430
7829
|
variant: ctx.variant
|
|
7431
7830
|
});
|
|
7432
7831
|
const com = opts.commerce;
|
|
7433
7832
|
const commerce = com ? compact({
|
|
7434
|
-
|
|
7833
|
+
// The collector rejects an event with more lines than its cap, whole.
|
|
7834
|
+
items: com.items?.slice(0, MAX_ITEMS).map(
|
|
7435
7835
|
(i) => compact({
|
|
7436
7836
|
product_id: String(i.productId),
|
|
7437
|
-
name: i.name,
|
|
7438
|
-
brand: i.brand,
|
|
7837
|
+
name: this.options.privateContent ? void 0 : i.name,
|
|
7838
|
+
brand: this.options.privateContent ? void 0 : i.brand,
|
|
7439
7839
|
variant_id: i.variantId !== void 0 ? String(i.variantId) : void 0,
|
|
7440
7840
|
price: i.price,
|
|
7441
7841
|
quantity: i.quantity
|
|
@@ -7452,7 +7852,8 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
7452
7852
|
// ids does not carry a stable identifier of a person either.
|
|
7453
7853
|
buyer_id: this.canPersist ? normalizeBuyerRef(com.buyerId) : void 0
|
|
7454
7854
|
}) : void 0;
|
|
7455
|
-
const
|
|
7855
|
+
const base = this.clientBlock();
|
|
7856
|
+
const client = this.syncInternal() ? { ...base ?? {}, internal: true } : base;
|
|
7456
7857
|
return {
|
|
7457
7858
|
event_id: uuid(),
|
|
7458
7859
|
name,
|
|
@@ -7981,6 +8382,15 @@ function safeStorageSet(key, value) {
|
|
|
7981
8382
|
} catch {
|
|
7982
8383
|
}
|
|
7983
8384
|
}
|
|
8385
|
+
function impressionCommerce(read) {
|
|
8386
|
+
if (!read) return void 0;
|
|
8387
|
+
try {
|
|
8388
|
+
const commerce = read();
|
|
8389
|
+
return commerce?.items?.length ? commerce : void 0;
|
|
8390
|
+
} catch {
|
|
8391
|
+
return void 0;
|
|
8392
|
+
}
|
|
8393
|
+
}
|
|
7984
8394
|
function compact(obj) {
|
|
7985
8395
|
const out = {};
|
|
7986
8396
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -8314,6 +8724,10 @@ var VioFacade = class {
|
|
|
8314
8724
|
this.surfaceMode = null;
|
|
8315
8725
|
this.surfaceRequest = null;
|
|
8316
8726
|
this.preloadPrivacyMode();
|
|
8727
|
+
try {
|
|
8728
|
+
this.analytics.syncInternal(true);
|
|
8729
|
+
} catch {
|
|
8730
|
+
}
|
|
8317
8731
|
this.checkoutManager?.clearPaymentMethodsCache();
|
|
8318
8732
|
if (this.slotDeclareTimer) {
|
|
8319
8733
|
clearTimeout(this.slotDeclareTimer);
|
|
@@ -8505,9 +8919,9 @@ var VioFacade = class {
|
|
|
8505
8919
|
for (const l of all) {
|
|
8506
8920
|
if (l.campaignId !== void 0 && l.campaignId === pageCampaignId) delete l.campaignId;
|
|
8507
8921
|
}
|
|
8508
|
-
const
|
|
8922
|
+
const memory2 = readSlotDeclaration(storageKey);
|
|
8509
8923
|
const keyOf = (l) => slotDeclarationKey(l, pageCampaignId);
|
|
8510
|
-
const pending2 = new Set(pendingSlotKeys(
|
|
8924
|
+
const pending2 = new Set(pendingSlotKeys(memory2, all.map(keyOf), now));
|
|
8511
8925
|
let locations = opts.force ? all : all.filter((l) => pending2.has(keyOf(l)));
|
|
8512
8926
|
if (locations.length === 0) return null;
|
|
8513
8927
|
if (locations.length > MAX_LOCATIONS_PER_DECLARATION) {
|
|
@@ -8540,11 +8954,11 @@ var VioFacade = class {
|
|
|
8540
8954
|
if (result?.mode === "merge") {
|
|
8541
8955
|
const unhandled = this.campaignNotTakenUp(result, locations, pageCampaignId);
|
|
8542
8956
|
const settled = keys.filter((k) => !unhandled.has(k));
|
|
8543
|
-
let next = rememberSlotKeys(
|
|
8957
|
+
let next = rememberSlotKeys(memory2, settled, now);
|
|
8544
8958
|
if (unhandled.size > 0) next = rememberSlotKeys(next, [...unhandled], failedAt(now));
|
|
8545
8959
|
writeSlotDeclaration(storageKey, next);
|
|
8546
8960
|
} else {
|
|
8547
|
-
writeSlotDeclaration(storageKey, rememberSlotKeys(
|
|
8961
|
+
writeSlotDeclaration(storageKey, rememberSlotKeys(memory2, keys, failedAt(now)));
|
|
8548
8962
|
warn(
|
|
8549
8963
|
"slots declared but the server ignored mode=merge (old server); not caching, will retry next load"
|
|
8550
8964
|
);
|
|
@@ -8994,6 +9408,6 @@ function vippsButtonAttributes(verb = "buy", opts = {}) {
|
|
|
8994
9408
|
};
|
|
8995
9409
|
}
|
|
8996
9410
|
|
|
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-
|
|
9411
|
+
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, showApplePaySheet, sponsorCampaignEntry, sponsorIdentityFrom, storageGet, storedLanding, toCampaignId, updateCheckout, updateItem, updateShippingsBySupplier, vippsButtonAttributes, withGatewayFeature, writeInternal };
|
|
9412
|
+
//# sourceMappingURL=chunk-IR4XYTZL.js.map
|
|
9413
|
+
//# sourceMappingURL=chunk-IR4XYTZL.js.map
|