@vio-live/web-sdk 0.23.0 → 0.23.1
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/README.md +51 -18
- package/dist/chunk-45YKS5UG.js +3 -0
- package/dist/{chunk-25QECQDS.js.map → chunk-45YKS5UG.js.map} +1 -1
- package/dist/{chunk-AMDI7KH3.js → chunk-BRJMT7P4.js} +352 -146
- package/dist/chunk-BRJMT7P4.js.map +1 -0
- package/dist/{chunk-COCHGJ2K.js → chunk-UVDOKFGD.js} +89 -62
- package/dist/chunk-UVDOKFGD.js.map +1 -0
- package/dist/core/index.d.ts +90 -18
- 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-DSYvrBsB.d.ts → tokens-DDfZuHF6.d.ts} +4 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-25QECQDS.js +0 -3
- package/dist/chunk-AMDI7KH3.js.map +0 -1
- package/dist/chunk-COCHGJ2K.js.map +0 -1
|
@@ -1659,6 +1659,18 @@ var CartManager = class extends EventTarget {
|
|
|
1659
1659
|
await Promise.allSettled([...set]);
|
|
1660
1660
|
}
|
|
1661
1661
|
}
|
|
1662
|
+
/**
|
|
1663
|
+
* True while an AddItem/UpdateItem/DeleteItem of this sponsor OTHER than
|
|
1664
|
+
* `except` has not settled. A mutation applying its own answer passes
|
|
1665
|
+
* itself: its response is current for what IT sent — only the others make
|
|
1666
|
+
* it stale.
|
|
1667
|
+
*/
|
|
1668
|
+
hasMutationsInFlight(sponsorId, except) {
|
|
1669
|
+
const set = this.inFlightMutations.get(sponsorId);
|
|
1670
|
+
if (!set || set.size === 0) return false;
|
|
1671
|
+
for (const m of set) if (m !== except) return true;
|
|
1672
|
+
return false;
|
|
1673
|
+
}
|
|
1662
1674
|
/** Register a backend mutation so `waitForCartMutations` can await it. */
|
|
1663
1675
|
trackMutation(sponsorId, mutation) {
|
|
1664
1676
|
let set = this.inFlightMutations.get(sponsorId);
|
|
@@ -1687,10 +1699,10 @@ var CartManager = class extends EventTarget {
|
|
|
1687
1699
|
}
|
|
1688
1700
|
/** Apply a backend response only if no newer response was applied already.
|
|
1689
1701
|
* Returns false when it was discarded as stale. */
|
|
1690
|
-
applyBackendCart(sponsorId, backendCart, seq) {
|
|
1702
|
+
applyBackendCart(sponsorId, backendCart, seq, settling) {
|
|
1691
1703
|
if (seq < (this.appliedSeq.get(sponsorId) ?? 0)) return false;
|
|
1692
1704
|
this.appliedSeq.set(sponsorId, seq);
|
|
1693
|
-
this.updateFromBackendCart(sponsorId, backendCart);
|
|
1705
|
+
this.updateFromBackendCart(sponsorId, backendCart, { settling });
|
|
1694
1706
|
return true;
|
|
1695
1707
|
}
|
|
1696
1708
|
/** The final answer of a line's sync lost the per-sponsor seq race (another
|
|
@@ -1698,7 +1710,7 @@ var CartManager = class extends EventTarget {
|
|
|
1698
1710
|
* is the latest word. Copy its quantity (and price) so a server-side clamp
|
|
1699
1711
|
* — stock — doesn't leave the optimistic value behind for good, with the
|
|
1700
1712
|
* checkout / Apple Pay total built on it. */
|
|
1701
|
-
reconcileLineFromResponse(sponsorId, cartItemId, resCart) {
|
|
1713
|
+
reconcileLineFromResponse(sponsorId, cartItemId, resCart, settling) {
|
|
1702
1714
|
const cart = this.cartsBySponsor.get(sponsorId);
|
|
1703
1715
|
const line = cart?.items.find((i) => i.cartItemId === cartItemId || i.id === cartItemId);
|
|
1704
1716
|
const server = resCart.line_items?.find((li) => li.id === cartItemId);
|
|
@@ -1707,7 +1719,9 @@ var CartManager = class extends EventTarget {
|
|
|
1707
1719
|
let changed = false;
|
|
1708
1720
|
if (server.quantity !== line.quantity) {
|
|
1709
1721
|
line.quantity = server.quantity;
|
|
1710
|
-
|
|
1722
|
+
if (!this.hasMutationsInFlight(sponsorId, settling)) {
|
|
1723
|
+
line.origins = reconciledOrigins(line.origins, server.quantity);
|
|
1724
|
+
}
|
|
1711
1725
|
changed = true;
|
|
1712
1726
|
}
|
|
1713
1727
|
if (price != null && price !== line.unitPrice) {
|
|
@@ -1783,8 +1797,12 @@ var CartManager = class extends EventTarget {
|
|
|
1783
1797
|
this.cartIdPromises.set(sponsorId, creation);
|
|
1784
1798
|
return creation;
|
|
1785
1799
|
}
|
|
1786
|
-
/**
|
|
1787
|
-
|
|
1800
|
+
/**
|
|
1801
|
+
* Overwrite local cart state with the backend cart response (source of
|
|
1802
|
+
* truth). `opts.settling` is the mutation whose answer this is: it does not
|
|
1803
|
+
* count as "in flight" for the origins (see `hasMutationsInFlight`).
|
|
1804
|
+
*/
|
|
1805
|
+
updateFromBackendCart(sponsorId, backendCart, opts = {}) {
|
|
1788
1806
|
const cart = this.cartsBySponsor.get(sponsorId);
|
|
1789
1807
|
if (!cart) return;
|
|
1790
1808
|
if (backendCart.cart_id) cart.cartId = backendCart.cart_id;
|
|
@@ -1840,9 +1858,12 @@ var CartManager = class extends EventTarget {
|
|
|
1840
1858
|
currency: li.price?.currency_code || backendCart.currency || matchedLocal?.currency || "NOK",
|
|
1841
1859
|
imageUrl,
|
|
1842
1860
|
quantity: intended ?? li.quantity,
|
|
1843
|
-
// The server knows nothing about origins: keep the local ones
|
|
1844
|
-
// squared with
|
|
1845
|
-
|
|
1861
|
+
// The server knows nothing about origins: keep the local ones. They
|
|
1862
|
+
// are squared with its quantity (a stock clamp) only when no OTHER
|
|
1863
|
+
// mutation is in flight for this sponsor — an AddItem answering
|
|
1864
|
+
// while another is pending reports a quantity that is already old
|
|
1865
|
+
// (see `lineOrigins`).
|
|
1866
|
+
origins: matchedLocal ? this.hasMutationsInFlight(sponsorId, opts.settling) ? matchedLocal.origins : reconciledOrigins(matchedLocal.origins, intended ?? li.quantity) : void 0,
|
|
1846
1867
|
shipping: li.shipping,
|
|
1847
1868
|
availableShippings: li.available_shippings
|
|
1848
1869
|
};
|
|
@@ -1946,6 +1967,7 @@ var CartManager = class extends EventTarget {
|
|
|
1946
1967
|
const addedItem = existing ?? cart.items[cart.items.length - 1];
|
|
1947
1968
|
const addedLineId = addedItem.id;
|
|
1948
1969
|
const seq = this.nextSeq(opts.sponsorId);
|
|
1970
|
+
let settling;
|
|
1949
1971
|
const mutation = (async () => {
|
|
1950
1972
|
try {
|
|
1951
1973
|
const cartId = await this.ensureCartId(opts.sponsorId, opts.currency || void 0);
|
|
@@ -1960,7 +1982,7 @@ var CartManager = class extends EventTarget {
|
|
|
1960
1982
|
];
|
|
1961
1983
|
const resCart = await addItem(cartId, lineItemsInput, gqlOpts);
|
|
1962
1984
|
if (resCart && Array.isArray(resCart.line_items)) {
|
|
1963
|
-
this.applyBackendCart(opts.sponsorId, resCart, seq);
|
|
1985
|
+
this.applyBackendCart(opts.sponsorId, resCart, seq, settling);
|
|
1964
1986
|
}
|
|
1965
1987
|
}
|
|
1966
1988
|
} catch (err) {
|
|
@@ -1968,7 +1990,7 @@ var CartManager = class extends EventTarget {
|
|
|
1968
1990
|
const line = c?.items.find((i) => i.id === addedLineId);
|
|
1969
1991
|
if (c && line) {
|
|
1970
1992
|
line.quantity -= qty;
|
|
1971
|
-
|
|
1993
|
+
removeFromOrigin(line, opts.origin, qty);
|
|
1972
1994
|
if (line.quantity <= 0) c.items = c.items.filter((i) => i !== line);
|
|
1973
1995
|
if (c.items.length === 0) this.cartsBySponsor.delete(opts.sponsorId);
|
|
1974
1996
|
this.persist();
|
|
@@ -1977,6 +1999,7 @@ var CartManager = class extends EventTarget {
|
|
|
1977
1999
|
this.emitError("AddItem rejected by the backend \u2014 item removed from the cart", err);
|
|
1978
2000
|
}
|
|
1979
2001
|
})();
|
|
2002
|
+
settling = mutation;
|
|
1980
2003
|
this.trackMutation(opts.sponsorId, mutation);
|
|
1981
2004
|
return addedItem;
|
|
1982
2005
|
}
|
|
@@ -2061,6 +2084,7 @@ var CartManager = class extends EventTarget {
|
|
|
2061
2084
|
}
|
|
2062
2085
|
const sync = { sent: target };
|
|
2063
2086
|
this.qtySyncs.set(key, sync);
|
|
2087
|
+
let settling;
|
|
2064
2088
|
const run = (async () => {
|
|
2065
2089
|
let next = target;
|
|
2066
2090
|
let removalRetried = false;
|
|
@@ -2075,9 +2099,9 @@ var CartManager = class extends EventTarget {
|
|
|
2075
2099
|
if (next === sync.sent) next = void 0;
|
|
2076
2100
|
if (next === void 0) this.qtySyncs.delete(key);
|
|
2077
2101
|
if (resCart && Array.isArray(resCart.line_items)) {
|
|
2078
|
-
const applied = this.applyBackendCart(sponsorId, resCart, seq);
|
|
2102
|
+
const applied = this.applyBackendCart(sponsorId, resCart, seq, settling);
|
|
2079
2103
|
if (!applied && next === void 0) {
|
|
2080
|
-
this.reconcileLineFromResponse(sponsorId, cartItemId, resCart);
|
|
2104
|
+
this.reconcileLineFromResponse(sponsorId, cartItemId, resCart, settling);
|
|
2081
2105
|
}
|
|
2082
2106
|
}
|
|
2083
2107
|
} catch (err) {
|
|
@@ -2100,6 +2124,7 @@ var CartManager = class extends EventTarget {
|
|
|
2100
2124
|
}
|
|
2101
2125
|
}
|
|
2102
2126
|
})();
|
|
2127
|
+
settling = run;
|
|
2103
2128
|
this.trackMutation(sponsorId, run);
|
|
2104
2129
|
}
|
|
2105
2130
|
removeItem(lineItemId, sponsorId) {
|
|
@@ -2245,6 +2270,22 @@ function addOriginQuantity(line, origin, qty) {
|
|
|
2245
2270
|
}
|
|
2246
2271
|
line.origins = origins;
|
|
2247
2272
|
}
|
|
2273
|
+
function removeFromOrigin(line, origin, qty) {
|
|
2274
|
+
if (!(qty > 0) || !Array.isArray(line.origins)) return;
|
|
2275
|
+
let left = qty;
|
|
2276
|
+
if (origin) {
|
|
2277
|
+
const target = normalizeOrigin(origin);
|
|
2278
|
+
const index = line.origins.findIndex((o) => sameOrigin(o, target));
|
|
2279
|
+
if (index >= 0) {
|
|
2280
|
+
const found = line.origins[index];
|
|
2281
|
+
const take = Math.min(found.quantity, left);
|
|
2282
|
+
found.quantity -= take;
|
|
2283
|
+
left -= take;
|
|
2284
|
+
if (found.quantity <= 0) line.origins.splice(index, 1);
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
if (left > 0) removeOriginQuantity(line, left);
|
|
2288
|
+
}
|
|
2248
2289
|
function removeOriginQuantity(line, qty) {
|
|
2249
2290
|
if (!(qty > 0) || !Array.isArray(line.origins)) return;
|
|
2250
2291
|
let left = qty;
|
|
@@ -2270,8 +2311,11 @@ function lineOrigins(line) {
|
|
|
2270
2311
|
const known = (Array.isArray(line.origins) ? line.origins : []).filter((o) => o && o.quantity > 0);
|
|
2271
2312
|
const total = known.reduce((sum, o) => sum + o.quantity, 0);
|
|
2272
2313
|
const quantity = line.quantity > 0 ? line.quantity : 0;
|
|
2273
|
-
if (total
|
|
2274
|
-
return [...known.map((o) => ({ ...o })), { quantity: quantity - total }];
|
|
2314
|
+
if (total === quantity) return known.map((o) => ({ ...o }));
|
|
2315
|
+
if (total < quantity) return [...known.map((o) => ({ ...o })), { quantity: quantity - total }];
|
|
2316
|
+
const copy = { origins: known.map((o) => ({ ...o })) };
|
|
2317
|
+
removeOriginQuantity(copy, total - quantity);
|
|
2318
|
+
return copy.origins;
|
|
2275
2319
|
}
|
|
2276
2320
|
|
|
2277
2321
|
// src/core/checkout/payments/apple-pay.ts
|
|
@@ -2470,7 +2514,7 @@ async function prepareApplePay(config) {
|
|
|
2470
2514
|
}
|
|
2471
2515
|
|
|
2472
2516
|
// src/core/version.ts
|
|
2473
|
-
var SDK_VERSION = "0.23.
|
|
2517
|
+
var SDK_VERSION = "0.23.1";
|
|
2474
2518
|
|
|
2475
2519
|
// src/core/checkout/payments/stripe-embedded.ts
|
|
2476
2520
|
var CREATE_PAYMENT_INTENT_STRIPE_MUTATION = `
|
|
@@ -5847,19 +5891,24 @@ function toSmallestUnit(amount, currency) {
|
|
|
5847
5891
|
// src/core/content.ts
|
|
5848
5892
|
var CONTENT_ID_QUERY = "vio_content";
|
|
5849
5893
|
var CONTENT_TITLE_QUERY = "vio_content_title";
|
|
5894
|
+
var CONTENT_ID_MAX_LENGTH = 128;
|
|
5895
|
+
var CONTENT_TITLE_MAX_LENGTH = 255;
|
|
5850
5896
|
function resolveContent(init, doc = typeof document !== "undefined" ? document : null, loc = typeof location !== "undefined" ? location : null) {
|
|
5851
5897
|
try {
|
|
5852
5898
|
const query = parseQuery(loc?.search);
|
|
5853
|
-
const id = text(init?.contentId) ?? text(query.get(CONTENT_ID_QUERY)) ?? text(meta(doc, "name", "vio:content-id")) ?? stripQueryAndHash(text(attr(doc, 'link[rel="canonical"]', "href")) ?? text(meta(doc, "property", "og:url"))) ?? text(loc?.pathname);
|
|
5899
|
+
const id = fits(text(init?.contentId)) ?? fits(text(query.get(CONTENT_ID_QUERY))) ?? fits(text(meta(doc, "name", "vio:content-id"))) ?? fits(stripQueryAndHash(text(attr(doc, 'link[rel="canonical"]', "href")))) ?? fits(stripQueryAndHash(text(meta(doc, "property", "og:url")))) ?? fits(text(loc?.pathname));
|
|
5854
5900
|
const title = text(init?.contentTitle) ?? text(query.get(CONTENT_TITLE_QUERY)) ?? text(meta(doc, "name", "vio:content-title")) ?? text(meta(doc, "property", "og:title")) ?? text(doc?.title);
|
|
5855
5901
|
const out = {};
|
|
5856
5902
|
if (id !== void 0) out.id = id;
|
|
5857
|
-
if (title !== void 0) out.title = title.slice(0,
|
|
5903
|
+
if (title !== void 0) out.title = title.slice(0, CONTENT_TITLE_MAX_LENGTH);
|
|
5858
5904
|
return out;
|
|
5859
5905
|
} catch {
|
|
5860
5906
|
return {};
|
|
5861
5907
|
}
|
|
5862
5908
|
}
|
|
5909
|
+
function fits(value) {
|
|
5910
|
+
return value !== void 0 && value.length <= CONTENT_ID_MAX_LENGTH ? value : void 0;
|
|
5911
|
+
}
|
|
5863
5912
|
function text(value) {
|
|
5864
5913
|
if (value === void 0 || value === null) return void 0;
|
|
5865
5914
|
const s = String(value).trim();
|
|
@@ -5895,6 +5944,9 @@ function stripQueryAndHash(url) {
|
|
|
5895
5944
|
// src/core/slots.ts
|
|
5896
5945
|
var SLOT_ID_MAX_LENGTH = 100;
|
|
5897
5946
|
var SLOT_DECLARATION_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
5947
|
+
var SLOT_DECLARATION_FAILURE_TTL_MS = 60 * 60 * 1e3;
|
|
5948
|
+
var MAX_LOCATIONS_PER_DECLARATION = 100;
|
|
5949
|
+
var MAX_DECLARATIONS_PER_LOAD = 3;
|
|
5898
5950
|
function resolveSlotCampaign(boot, slot, now = Date.now(), platform) {
|
|
5899
5951
|
if (!boot) return null;
|
|
5900
5952
|
return findSlotAssignment(boot, slot, now, platform) ?? defaultCampaignEntry(boot);
|
|
@@ -5962,7 +6014,7 @@ function toNumber(value) {
|
|
|
5962
6014
|
}
|
|
5963
6015
|
function normalizeSlotId(value) {
|
|
5964
6016
|
if (typeof value !== "string") return "";
|
|
5965
|
-
return value.trim().slice(0, SLOT_ID_MAX_LENGTH);
|
|
6017
|
+
return value.trim().slice(0, SLOT_ID_MAX_LENGTH).trim();
|
|
5966
6018
|
}
|
|
5967
6019
|
function normalizeSlotLocations(slots) {
|
|
5968
6020
|
const out = [];
|
|
@@ -5978,8 +6030,11 @@ function normalizeSlotLocations(slots) {
|
|
|
5978
6030
|
return out;
|
|
5979
6031
|
}
|
|
5980
6032
|
function autoSlotId(kind, ordinal, scope) {
|
|
5981
|
-
const
|
|
5982
|
-
|
|
6033
|
+
const tail = `${kind}-${ordinal + 1}`;
|
|
6034
|
+
let prefix = normalizeScope(scope);
|
|
6035
|
+
const room = SLOT_ID_MAX_LENGTH - tail.length - 1;
|
|
6036
|
+
if (prefix.length > room) prefix = prefix.slice(0, Math.max(0, room)).replace(/-+$/, "");
|
|
6037
|
+
return `${prefix ? `${prefix}-` : ""}${tail}`;
|
|
5983
6038
|
}
|
|
5984
6039
|
function autoSlotDisplayName(kind, ordinal, scopeName) {
|
|
5985
6040
|
const label = `${kind.charAt(0).toUpperCase()}${kind.slice(1)} ${ordinal + 1}`;
|
|
@@ -5990,8 +6045,24 @@ function normalizeScope(scope) {
|
|
|
5990
6045
|
if (typeof scope !== "string") return "";
|
|
5991
6046
|
return scope.trim().replace(/\s+/g, "-");
|
|
5992
6047
|
}
|
|
5993
|
-
|
|
5994
|
-
|
|
6048
|
+
var SLOT_DECLARATION_MEMORY_CAP = 500;
|
|
6049
|
+
function slotDeclarationKey(location2) {
|
|
6050
|
+
return location2.displayName ? `${location2.id}${location2.displayName}` : location2.id;
|
|
6051
|
+
}
|
|
6052
|
+
function pendingSlotKeys(memory, keys, now = Date.now(), ttl = SLOT_DECLARATION_TTL_MS) {
|
|
6053
|
+
return keys.filter((key) => {
|
|
6054
|
+
const at = memory?.[key];
|
|
6055
|
+
if (typeof at !== "number" || !Number.isFinite(at)) return true;
|
|
6056
|
+
return now - at >= ttl || now < at;
|
|
6057
|
+
});
|
|
6058
|
+
}
|
|
6059
|
+
function rememberSlotKeys(memory, keys, at, cap = SLOT_DECLARATION_MEMORY_CAP) {
|
|
6060
|
+
const next = { ...memory ?? {} };
|
|
6061
|
+
for (const key of keys) next[key] = at;
|
|
6062
|
+
const entries = Object.entries(next);
|
|
6063
|
+
if (entries.length <= cap) return next;
|
|
6064
|
+
entries.sort((a, b) => b[1] - a[1]);
|
|
6065
|
+
return Object.fromEntries(entries.slice(0, cap));
|
|
5995
6066
|
}
|
|
5996
6067
|
function slotDeclarationStorageKey(platform, apiKey) {
|
|
5997
6068
|
return `vio.slots.${platform}.${fnv1a(apiKey)}`;
|
|
@@ -6005,31 +6076,95 @@ function fnv1a(input) {
|
|
|
6005
6076
|
return hash.toString(16).padStart(8, "0");
|
|
6006
6077
|
}
|
|
6007
6078
|
function readSlotDeclaration(storageKey) {
|
|
6008
|
-
if (typeof localStorage === "undefined") return null;
|
|
6009
6079
|
try {
|
|
6080
|
+
if (typeof localStorage === "undefined") return {};
|
|
6010
6081
|
const raw = localStorage.getItem(storageKey);
|
|
6011
|
-
if (!raw) return
|
|
6082
|
+
if (!raw) return {};
|
|
6012
6083
|
const parsed = JSON.parse(raw);
|
|
6013
|
-
if (!parsed ||
|
|
6014
|
-
|
|
6084
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
6085
|
+
if (Array.isArray(parsed.keys)) return {};
|
|
6086
|
+
const out = {};
|
|
6087
|
+
for (const [key, at] of Object.entries(parsed)) {
|
|
6088
|
+
if (typeof at === "number" && Number.isFinite(at)) out[key] = at;
|
|
6089
|
+
}
|
|
6090
|
+
return out;
|
|
6015
6091
|
} catch {
|
|
6016
|
-
return
|
|
6092
|
+
return {};
|
|
6017
6093
|
}
|
|
6018
6094
|
}
|
|
6019
6095
|
function writeSlotDeclaration(storageKey, memory) {
|
|
6020
|
-
if (typeof localStorage === "undefined") return;
|
|
6021
6096
|
try {
|
|
6097
|
+
if (typeof localStorage === "undefined") return;
|
|
6022
6098
|
localStorage.setItem(storageKey, JSON.stringify(memory));
|
|
6023
6099
|
} catch {
|
|
6024
6100
|
}
|
|
6025
6101
|
}
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
if (
|
|
6030
|
-
const
|
|
6031
|
-
const
|
|
6032
|
-
|
|
6102
|
+
|
|
6103
|
+
// src/core/cart/slices.ts
|
|
6104
|
+
function cartSlicesFrom(lines, resolveCampaign, fallbackCurrency) {
|
|
6105
|
+
if (!Array.isArray(lines) || lines.length === 0) return [];
|
|
6106
|
+
const slices = /* @__PURE__ */ new Map();
|
|
6107
|
+
for (const line of lines) {
|
|
6108
|
+
if (!line || typeof line !== "object") continue;
|
|
6109
|
+
const sponsorId = Number(line.sponsorId);
|
|
6110
|
+
const unitPrice = Number(line.unitPrice) || 0;
|
|
6111
|
+
for (const origin of lineOrigins(line)) {
|
|
6112
|
+
let campaignId = origin.campaignId;
|
|
6113
|
+
if (campaignId === void 0) {
|
|
6114
|
+
try {
|
|
6115
|
+
campaignId = resolveCampaign(origin.slot, sponsorId);
|
|
6116
|
+
} catch {
|
|
6117
|
+
campaignId = void 0;
|
|
6118
|
+
}
|
|
6119
|
+
}
|
|
6120
|
+
const key = campaignId === void 0 ? "default" : String(campaignId);
|
|
6121
|
+
let slice = slices.get(key);
|
|
6122
|
+
if (!slice) {
|
|
6123
|
+
slice = {
|
|
6124
|
+
campaignId,
|
|
6125
|
+
sponsors: /* @__PURE__ */ new Set(),
|
|
6126
|
+
slots: /* @__PURE__ */ new Set(),
|
|
6127
|
+
contents: /* @__PURE__ */ new Set(),
|
|
6128
|
+
items: /* @__PURE__ */ new Map(),
|
|
6129
|
+
value: 0,
|
|
6130
|
+
currency: line.currency || fallbackCurrency
|
|
6131
|
+
};
|
|
6132
|
+
slices.set(key, slice);
|
|
6133
|
+
}
|
|
6134
|
+
if (Number.isFinite(sponsorId)) slice.sponsors.add(sponsorId);
|
|
6135
|
+
if (origin.slot) slice.slots.add(origin.slot);
|
|
6136
|
+
if (origin.contentId) slice.contents.add(origin.contentId);
|
|
6137
|
+
const itemKey = `${line.productId}::${line.variantId ?? ""}`;
|
|
6138
|
+
const item = slice.items.get(itemKey);
|
|
6139
|
+
if (item) item.quantity = (item.quantity ?? 0) + origin.quantity;
|
|
6140
|
+
else {
|
|
6141
|
+
slice.items.set(itemKey, {
|
|
6142
|
+
productId: line.productId,
|
|
6143
|
+
name: line.name,
|
|
6144
|
+
brand: line.brand,
|
|
6145
|
+
variantId: line.variantId,
|
|
6146
|
+
price: unitPrice,
|
|
6147
|
+
quantity: origin.quantity
|
|
6148
|
+
});
|
|
6149
|
+
}
|
|
6150
|
+
slice.value += unitPrice * origin.quantity;
|
|
6151
|
+
}
|
|
6152
|
+
}
|
|
6153
|
+
const list = [...slices.values()];
|
|
6154
|
+
return list.map((s, i) => ({
|
|
6155
|
+
campaignId: s.campaignId,
|
|
6156
|
+
sponsorId: s.sponsors.size === 1 ? [...s.sponsors][0] : void 0,
|
|
6157
|
+
slot: s.slots.size === 1 ? [...s.slots][0] : void 0,
|
|
6158
|
+
contentId: s.contents.size === 1 ? [...s.contents][0] : void 0,
|
|
6159
|
+
items: [...s.items.values()],
|
|
6160
|
+
value: Math.round(s.value * 100) / 100,
|
|
6161
|
+
currency: s.currency,
|
|
6162
|
+
slice: i + 1,
|
|
6163
|
+
slices: list.length
|
|
6164
|
+
}));
|
|
6165
|
+
}
|
|
6166
|
+
function hasExplicitCampaign(lines) {
|
|
6167
|
+
return lines.some((line) => lineOrigins(line).some((o) => o.campaignId !== void 0));
|
|
6033
6168
|
}
|
|
6034
6169
|
|
|
6035
6170
|
// src/core/analytics/analytics-manager.ts
|
|
@@ -6229,25 +6364,34 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
6229
6364
|
if (!anonId) return null;
|
|
6230
6365
|
const boot = vioBootstrapCache();
|
|
6231
6366
|
const ctx = opts.context ?? {};
|
|
6232
|
-
const
|
|
6367
|
+
const explicitContentId = fitsId(ctx.contentId);
|
|
6368
|
+
const content = explicitContentId === void 0 || ctx.contentTitle === void 0 ? vioContent() : {};
|
|
6233
6369
|
const context = compact({
|
|
6234
6370
|
campaign_id: resolveCampaignId(ctx, boot),
|
|
6235
6371
|
broadcast_id: ctx.broadcastId,
|
|
6236
6372
|
campaign_component_id: ctx.campaignComponentId,
|
|
6237
6373
|
app_placement_id: ctx.appPlacementId,
|
|
6238
|
-
// A slot is a location id to the campaigns service (ADR-0027).
|
|
6239
|
-
|
|
6374
|
+
// A slot is a location id to the campaigns service (ADR-0027). An
|
|
6375
|
+
// explicit location id that does not fit gives way to the slot.
|
|
6376
|
+
location_id: fitsId(ctx.locationId) ?? fitsId(ctx.slot),
|
|
6240
6377
|
component_template_id: ctx.componentTemplateId,
|
|
6241
6378
|
sponsor_id: ctx.sponsorId,
|
|
6242
6379
|
activation_id: ctx.activationId,
|
|
6243
|
-
|
|
6380
|
+
// Cut to the collector's 2 048 — the query string first, since a long
|
|
6381
|
+
// one is usually the tracking tail, not the page. The other host-given
|
|
6382
|
+
// fields (broadcastId, componentTemplateId, errorCode, variant, …) are
|
|
6383
|
+
// the host's responsibility: the SDK does not touch them.
|
|
6384
|
+
content_url: capUrl(ctx.contentUrl ?? (typeof location !== "undefined" ? location.href : void 0)),
|
|
6244
6385
|
// The host's own content id — its join key back onto its reporting.
|
|
6245
|
-
// Explicit on the event, else what the SDK resolved for
|
|
6246
|
-
|
|
6386
|
+
// Explicit on the event when it fits, else what the SDK resolved for
|
|
6387
|
+
// the page (already capped per source), else nothing.
|
|
6388
|
+
content_id: explicitContentId ?? fitsId(content.id),
|
|
6247
6389
|
// Deletion-proof reporting: sources have no trash bin — the title
|
|
6248
6390
|
// snapshotted at event time keeps reports legible if content dies.
|
|
6249
6391
|
error_code: ctx.errorCode,
|
|
6250
|
-
content_title:
|
|
6392
|
+
content_title: capTitle(
|
|
6393
|
+
ctx.contentTitle ?? content.title ?? (typeof document !== "undefined" && document.title ? document.title : void 0)
|
|
6394
|
+
),
|
|
6251
6395
|
variant: ctx.variant
|
|
6252
6396
|
});
|
|
6253
6397
|
const com = opts.commerce;
|
|
@@ -6395,7 +6539,7 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
6395
6539
|
const d = ev.detail ?? {};
|
|
6396
6540
|
const line = this.findLine(d.productId, d.variantId);
|
|
6397
6541
|
this.track("add_to_cart", {
|
|
6398
|
-
context: { sponsorId: d.sponsorId !== void 0 ? Number(d.sponsorId) : void 0, slot: slotOf(d), ...contentOf(d) },
|
|
6542
|
+
context: { sponsorId: d.sponsorId !== void 0 ? Number(d.sponsorId) : void 0, campaignId: campaignOf(d), slot: slotOf(d), ...contentOf(d) },
|
|
6399
6543
|
commerce: {
|
|
6400
6544
|
items: [
|
|
6401
6545
|
{
|
|
@@ -6416,7 +6560,7 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
6416
6560
|
const d = ev.detail ?? {};
|
|
6417
6561
|
if (d.productId === void 0) return;
|
|
6418
6562
|
this.track("remove_from_cart", {
|
|
6419
|
-
context: { sponsorId: d.sponsorId, slot: slotOf(d), ...contentOf(d) },
|
|
6563
|
+
context: { sponsorId: d.sponsorId, campaignId: campaignOf(d), slot: slotOf(d), ...contentOf(d) },
|
|
6420
6564
|
commerce: {
|
|
6421
6565
|
items: [
|
|
6422
6566
|
{
|
|
@@ -6445,7 +6589,7 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
6445
6589
|
if (d.productId === void 0) return;
|
|
6446
6590
|
const price = Number(d.price);
|
|
6447
6591
|
this.track("select_item", {
|
|
6448
|
-
context: { sponsorId: d.sponsorId !== void 0 ? Number(d.sponsorId) : void 0, slot: slotOf(d), ...contentOf(d) },
|
|
6592
|
+
context: { sponsorId: d.sponsorId !== void 0 ? Number(d.sponsorId) : void 0, campaignId: campaignOf(d), slot: slotOf(d), ...contentOf(d) },
|
|
6449
6593
|
commerce: {
|
|
6450
6594
|
items: [
|
|
6451
6595
|
{
|
|
@@ -6464,38 +6608,42 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
6464
6608
|
});
|
|
6465
6609
|
on("vio:checkout-open", (ev) => {
|
|
6466
6610
|
const d = ev.detail ?? {};
|
|
6467
|
-
const
|
|
6611
|
+
const base = { sponsorId: d.sponsorId, campaignId: campaignOf(d), slot: slotOf(d), ...contentOf(d) };
|
|
6612
|
+
const { slices, explicit } = this.cartSlices(d.sponsorId);
|
|
6468
6613
|
if (slices.length > 1) {
|
|
6469
6614
|
for (const slice of slices) {
|
|
6470
6615
|
this.track("begin_checkout", {
|
|
6471
|
-
context: this.sliceContext(slice,
|
|
6472
|
-
commerce: slice
|
|
6616
|
+
context: this.sliceContext(slice, base),
|
|
6617
|
+
commerce: sliceCommerce(slice),
|
|
6618
|
+
props: { slice: slice.slice, slices: slice.slices }
|
|
6473
6619
|
});
|
|
6474
6620
|
}
|
|
6475
6621
|
return;
|
|
6476
6622
|
}
|
|
6477
6623
|
const snap = this.cartCommerce(d.sponsorId);
|
|
6478
6624
|
this.track("begin_checkout", {
|
|
6479
|
-
context:
|
|
6625
|
+
context: this.singleSliceContext(slices[0], explicit, base),
|
|
6480
6626
|
...snap ? { commerce: snap } : {}
|
|
6481
6627
|
});
|
|
6482
6628
|
});
|
|
6483
6629
|
on("vio:payment-success", (ev) => {
|
|
6484
6630
|
const d = ev.detail ?? {};
|
|
6485
6631
|
const sponsorId = d.sponsorId !== void 0 ? Number(d.sponsorId) : void 0;
|
|
6486
|
-
const
|
|
6632
|
+
const base = { sponsorId, campaignId: campaignOf(d), slot: slotOf(d), ...contentOf(d) };
|
|
6633
|
+
const { slices, explicit } = this.cartSlices(sponsorId);
|
|
6487
6634
|
if (slices.length > 1) {
|
|
6488
6635
|
for (const slice of slices) {
|
|
6489
6636
|
this.track("purchase", {
|
|
6490
|
-
context: this.sliceContext(slice,
|
|
6491
|
-
commerce: { ...slice
|
|
6637
|
+
context: this.sliceContext(slice, base),
|
|
6638
|
+
commerce: { ...sliceCommerce(slice), ...purchaseFromPaymentSuccess(d), paymentMethod: d.method },
|
|
6639
|
+
props: { slice: slice.slice, slices: slice.slices }
|
|
6492
6640
|
});
|
|
6493
6641
|
}
|
|
6494
6642
|
return;
|
|
6495
6643
|
}
|
|
6496
6644
|
const snap = this.cartCommerce(sponsorId);
|
|
6497
6645
|
this.track("purchase", {
|
|
6498
|
-
context:
|
|
6646
|
+
context: this.singleSliceContext(slices[0], explicit, base),
|
|
6499
6647
|
commerce: {
|
|
6500
6648
|
// value / currency / items: the cart snapshot, on every path.
|
|
6501
6649
|
...snap ?? {},
|
|
@@ -6523,67 +6671,50 @@ var AnalyticsManager = class extends EventTarget {
|
|
|
6523
6671
|
return items;
|
|
6524
6672
|
}
|
|
6525
6673
|
/**
|
|
6526
|
-
* The cart split per campaign
|
|
6527
|
-
*
|
|
6528
|
-
*
|
|
6529
|
-
* the line's sponsor. One slice per campaign: its items (quantities from
|
|
6530
|
-
* the origins), its value, and the slot / content when they are the same
|
|
6531
|
-
* for the whole slice. A cart with one campaign is one slice.
|
|
6674
|
+
* The cart split per campaign — the shared rule of cart/slices.ts over the
|
|
6675
|
+
* current cart (else the pre-clear snapshot), plus whether any unit named
|
|
6676
|
+
* its campaign itself (a cart without origins is reported as before).
|
|
6532
6677
|
*/
|
|
6533
6678
|
cartSlices(sponsorId) {
|
|
6534
6679
|
const lines = this.cartLines(sponsorId);
|
|
6535
|
-
if (lines.length === 0) return [];
|
|
6680
|
+
if (lines.length === 0) return { slices: [], explicit: false };
|
|
6536
6681
|
const boot = vioBootstrapCache();
|
|
6537
|
-
const slices =
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
if (!slice) {
|
|
6544
|
-
slice = {
|
|
6545
|
-
campaignId,
|
|
6546
|
-
commerce: { items: [], value: 0, currency: line.currency ?? this.lastCartSnapshot?.currency },
|
|
6547
|
-
slots: /* @__PURE__ */ new Set(),
|
|
6548
|
-
contents: /* @__PURE__ */ new Set(),
|
|
6549
|
-
lines: /* @__PURE__ */ new Map()
|
|
6550
|
-
};
|
|
6551
|
-
slices.set(key, slice);
|
|
6552
|
-
}
|
|
6553
|
-
if (origin.slot) slice.slots.add(origin.slot);
|
|
6554
|
-
if (origin.contentId) slice.contents.add(origin.contentId);
|
|
6555
|
-
const itemKey = `${line.productId}::${line.variantId ?? ""}`;
|
|
6556
|
-
const item = slice.lines.get(itemKey);
|
|
6557
|
-
if (item) item.quantity = (item.quantity ?? 0) + origin.quantity;
|
|
6558
|
-
else {
|
|
6559
|
-
const fresh = {
|
|
6560
|
-
productId: line.productId,
|
|
6561
|
-
name: line.name,
|
|
6562
|
-
brand: line.brand,
|
|
6563
|
-
variantId: line.variantId,
|
|
6564
|
-
price: line.unitPrice,
|
|
6565
|
-
quantity: origin.quantity
|
|
6566
|
-
};
|
|
6567
|
-
slice.lines.set(itemKey, fresh);
|
|
6568
|
-
slice.commerce.items.push(fresh);
|
|
6569
|
-
}
|
|
6570
|
-
slice.commerce.value = (slice.commerce.value ?? 0) + line.unitPrice * origin.quantity;
|
|
6571
|
-
}
|
|
6572
|
-
}
|
|
6573
|
-
return [...slices.values()].map((s) => ({
|
|
6574
|
-
campaignId: s.campaignId,
|
|
6575
|
-
slot: s.slots.size === 1 ? [...s.slots][0] : void 0,
|
|
6576
|
-
contentId: s.contents.size === 1 ? [...s.contents][0] : void 0,
|
|
6577
|
-
commerce: s.commerce
|
|
6578
|
-
}));
|
|
6682
|
+
const slices = cartSlicesFrom(
|
|
6683
|
+
lines,
|
|
6684
|
+
(slot, lineSponsorId) => resolveCampaignId({ slot, sponsorId: lineSponsorId }, boot),
|
|
6685
|
+
this.lastCartSnapshot?.currency
|
|
6686
|
+
);
|
|
6687
|
+
return { slices, explicit: hasExplicitCampaign(lines) };
|
|
6579
6688
|
}
|
|
6580
|
-
/**
|
|
6689
|
+
/**
|
|
6690
|
+
* The context of one of several per-campaign events: the slice's campaign,
|
|
6691
|
+
* slot and content — only its own; when the slice spans several slots or
|
|
6692
|
+
* articles the event names none rather than the one the click came from.
|
|
6693
|
+
*/
|
|
6581
6694
|
sliceContext(slice, base) {
|
|
6582
6695
|
return compact({
|
|
6583
6696
|
...base,
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6697
|
+
sponsorId: slice.sponsorId ?? base.sponsorId,
|
|
6698
|
+
campaignId: slice.campaignId,
|
|
6699
|
+
slot: slice.slot,
|
|
6700
|
+
contentId: slice.contentId,
|
|
6701
|
+
// The click's title only describes the click's content: when the slice
|
|
6702
|
+
// is another article (or several), the page's own title applies instead.
|
|
6703
|
+
contentTitle: slice.contentId !== void 0 && slice.contentId === base.contentId ? base.contentTitle : void 0
|
|
6704
|
+
});
|
|
6705
|
+
}
|
|
6706
|
+
/**
|
|
6707
|
+
* The context of a single-campaign checkout/purchase: when the cart's origins
|
|
6708
|
+
* say which campaign they came from, the event says it too (plus the slot /
|
|
6709
|
+
* content when unique) — a cart without origins is exactly as before.
|
|
6710
|
+
*/
|
|
6711
|
+
singleSliceContext(slice, explicit, base) {
|
|
6712
|
+
if (!slice || !explicit) return base;
|
|
6713
|
+
return compact({
|
|
6714
|
+
...base,
|
|
6715
|
+
campaignId: base.campaignId ?? slice.campaignId,
|
|
6716
|
+
slot: base.slot ?? slice.slot,
|
|
6717
|
+
contentId: base.contentId ?? slice.contentId
|
|
6587
6718
|
});
|
|
6588
6719
|
}
|
|
6589
6720
|
/** Current cart → commerce payload; falls back to the pre-clear snapshot. */
|
|
@@ -6691,10 +6822,10 @@ function resolveCampaignId(ctx, boot) {
|
|
|
6691
6822
|
const defaultId = boot?.campaign?.id;
|
|
6692
6823
|
if (ctx.slot) {
|
|
6693
6824
|
const platform = Configuration.isInitialized ? Configuration.get().platform : void 0;
|
|
6694
|
-
const assigned =
|
|
6825
|
+
const assigned = toNumber(findSlotAssignment(boot, ctx.slot, Date.now(), platform)?.id);
|
|
6695
6826
|
if (assigned !== void 0) return assigned;
|
|
6696
6827
|
}
|
|
6697
|
-
const sponsorId =
|
|
6828
|
+
const sponsorId = toNumber(ctx.sponsorId);
|
|
6698
6829
|
if (sponsorId === void 0) return defaultId;
|
|
6699
6830
|
try {
|
|
6700
6831
|
const campaigns = Array.isArray(boot?.campaigns) ? boot.campaigns : [];
|
|
@@ -6702,12 +6833,35 @@ function resolveCampaignId(ctx, boot) {
|
|
|
6702
6833
|
(c) => !!c && typeof c === "object" && c.status === "active" && campaignSponsorIds(c).includes(sponsorId)
|
|
6703
6834
|
);
|
|
6704
6835
|
const chosen = matches.find((c) => c.id === defaultId) ?? matches[0];
|
|
6705
|
-
const chosenId =
|
|
6836
|
+
const chosenId = toNumber(chosen?.id);
|
|
6706
6837
|
if (chosenId !== void 0) return chosenId;
|
|
6707
6838
|
} catch {
|
|
6708
6839
|
}
|
|
6709
6840
|
return defaultId;
|
|
6710
6841
|
}
|
|
6842
|
+
function campaignOf(detail) {
|
|
6843
|
+
return toNumber(detail.campaignId);
|
|
6844
|
+
}
|
|
6845
|
+
function fitsId(value) {
|
|
6846
|
+
if (value === void 0 || value === null) return void 0;
|
|
6847
|
+
const s = String(value);
|
|
6848
|
+
return s && s.length <= CONTENT_ID_MAX_LENGTH ? value : void 0;
|
|
6849
|
+
}
|
|
6850
|
+
function capTitle(value) {
|
|
6851
|
+
if (!value) return void 0;
|
|
6852
|
+
return value.length > CONTENT_TITLE_MAX_LENGTH ? value.slice(0, CONTENT_TITLE_MAX_LENGTH) : value;
|
|
6853
|
+
}
|
|
6854
|
+
var CONTENT_URL_MAX_LENGTH = 2048;
|
|
6855
|
+
function capUrl(value) {
|
|
6856
|
+
if (!value) return void 0;
|
|
6857
|
+
if (value.length <= CONTENT_URL_MAX_LENGTH) return value;
|
|
6858
|
+
const cut = value.search(/[?#]/);
|
|
6859
|
+
const withoutQuery = cut >= 0 ? value.slice(0, cut) : value;
|
|
6860
|
+
return withoutQuery.length <= CONTENT_URL_MAX_LENGTH ? withoutQuery : withoutQuery.slice(0, CONTENT_URL_MAX_LENGTH);
|
|
6861
|
+
}
|
|
6862
|
+
function sliceCommerce(slice) {
|
|
6863
|
+
return { items: slice.items, value: slice.value, currency: slice.currency };
|
|
6864
|
+
}
|
|
6711
6865
|
function slotOf(detail) {
|
|
6712
6866
|
return typeof detail.slot === "string" && detail.slot.trim() ? detail.slot.trim() : void 0;
|
|
6713
6867
|
}
|
|
@@ -6720,11 +6874,11 @@ function contentOf(detail) {
|
|
|
6720
6874
|
}
|
|
6721
6875
|
function campaignSponsorIds(campaign) {
|
|
6722
6876
|
const ids = [];
|
|
6723
|
-
const primary =
|
|
6877
|
+
const primary = toNumber(campaign.primarySponsor?.id);
|
|
6724
6878
|
if (primary !== void 0) ids.push(primary);
|
|
6725
6879
|
const secondaries = Array.isArray(campaign.secondarySponsors) ? campaign.secondarySponsors : [];
|
|
6726
6880
|
for (const s of secondaries) {
|
|
6727
|
-
const id =
|
|
6881
|
+
const id = toNumber(s?.id);
|
|
6728
6882
|
if (id !== void 0) ids.push(id);
|
|
6729
6883
|
}
|
|
6730
6884
|
return ids;
|
|
@@ -6742,11 +6896,6 @@ function firstId(...candidates) {
|
|
|
6742
6896
|
}
|
|
6743
6897
|
return void 0;
|
|
6744
6898
|
}
|
|
6745
|
-
function toNumber2(value) {
|
|
6746
|
-
if (value === void 0 || value === null || value === "") return void 0;
|
|
6747
|
-
const n = Number(value);
|
|
6748
|
-
return Number.isFinite(n) ? n : void 0;
|
|
6749
|
-
}
|
|
6750
6899
|
function pushGa4(event) {
|
|
6751
6900
|
const commerceNames = /* @__PURE__ */ new Set([
|
|
6752
6901
|
"view_item_list",
|
|
@@ -6803,8 +6952,11 @@ var VioFacade = class {
|
|
|
6803
6952
|
this.slotDeclareTimer = null;
|
|
6804
6953
|
/** A name appeared (or the key changed) since the registry was last declared. */
|
|
6805
6954
|
this.slotsDirty = false;
|
|
6806
|
-
/**
|
|
6807
|
-
this.
|
|
6955
|
+
/** Manifests POSTed by this page load (abuse / rollout guard, see declareSlots). */
|
|
6956
|
+
this.declarationsThisLoad = 0;
|
|
6957
|
+
/** Each cap warns once per page load. */
|
|
6958
|
+
this.warnedLocationCap = false;
|
|
6959
|
+
this.warnedDeclarationCap = false;
|
|
6808
6960
|
// Client-side managers — created lazily on first access. They don't
|
|
6809
6961
|
// need Vio.init() to work (state is purely local).
|
|
6810
6962
|
this.cartManager = null;
|
|
@@ -6825,26 +6977,26 @@ var VioFacade = class {
|
|
|
6825
6977
|
this.slotDeclareTimer = null;
|
|
6826
6978
|
}
|
|
6827
6979
|
this.slotsDirty = this.slotRegistry.size > 0;
|
|
6828
|
-
this.
|
|
6980
|
+
this.declarationsThisLoad = 0;
|
|
6981
|
+
this.warnedLocationCap = false;
|
|
6982
|
+
this.warnedDeclarationCap = false;
|
|
6829
6983
|
}
|
|
6830
6984
|
/**
|
|
6831
6985
|
* The content (article, page) this SDK instance is rendered in — what every
|
|
6832
6986
|
* analytics event carries as `content_id` / `content_title` when the event
|
|
6833
|
-
* has no explicit one
|
|
6834
|
-
*
|
|
6835
|
-
*
|
|
6836
|
-
* a
|
|
6987
|
+
* has no explicit one: init option → URL query → `vio:content-*` metas →
|
|
6988
|
+
* canonical/og:url → pathname (see `resolveContent`). Resolved LIVE on each
|
|
6989
|
+
* call — a few querySelectors — so an SPA route change, a new canonical or
|
|
6990
|
+
* a new title are seen without any re-init. Never throws; `{}` without a
|
|
6991
|
+
* document.
|
|
6837
6992
|
*/
|
|
6838
6993
|
content() {
|
|
6839
|
-
if (this.contentCache) return this.contentCache;
|
|
6840
6994
|
let init;
|
|
6841
6995
|
if (Configuration.isInitialized) {
|
|
6842
6996
|
const cfg = Configuration.get();
|
|
6843
6997
|
init = { contentId: cfg.contentId, contentTitle: cfg.contentTitle };
|
|
6844
6998
|
}
|
|
6845
|
-
|
|
6846
|
-
if (typeof document !== "undefined") this.contentCache = resolved;
|
|
6847
|
-
return resolved;
|
|
6999
|
+
return resolveContent(init);
|
|
6848
7000
|
}
|
|
6849
7001
|
get isInitialized() {
|
|
6850
7002
|
return Configuration.isInitialized;
|
|
@@ -6952,34 +7104,61 @@ var VioFacade = class {
|
|
|
6952
7104
|
* trimmed, cut at 100 chars, deduped; empties are dropped.
|
|
6953
7105
|
*/
|
|
6954
7106
|
async declareSlots(slots, opts = {}) {
|
|
7107
|
+
let storageKey;
|
|
7108
|
+
let keys = [];
|
|
7109
|
+
let now = Date.now();
|
|
6955
7110
|
try {
|
|
6956
|
-
const
|
|
6957
|
-
if (
|
|
7111
|
+
const all = normalizeSlotLocations(slots);
|
|
7112
|
+
if (all.length === 0) return null;
|
|
6958
7113
|
if (!Configuration.isInitialized) {
|
|
6959
7114
|
warn("declareSlots() before Vio.init() \u2014 nothing declared");
|
|
6960
7115
|
return null;
|
|
6961
7116
|
}
|
|
6962
7117
|
const cfg = Configuration.get();
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
const
|
|
6966
|
-
|
|
7118
|
+
storageKey = slotDeclarationStorageKey(cfg.platform, cfg.apiKey);
|
|
7119
|
+
now = Date.now();
|
|
7120
|
+
const memory = readSlotDeclaration(storageKey);
|
|
7121
|
+
const pending2 = new Set(pendingSlotKeys(memory, all.map(slotDeclarationKey), now));
|
|
7122
|
+
let locations = opts.force ? all : all.filter((l) => pending2.has(slotDeclarationKey(l)));
|
|
7123
|
+
if (locations.length === 0) return null;
|
|
7124
|
+
if (locations.length > MAX_LOCATIONS_PER_DECLARATION) {
|
|
7125
|
+
if (!this.warnedLocationCap) {
|
|
7126
|
+
this.warnedLocationCap = true;
|
|
7127
|
+
warn(
|
|
7128
|
+
`declareSlots(): ${locations.length} slots on one page \u2014 only the first ${MAX_LOCATIONS_PER_DECLARATION} are declared`
|
|
7129
|
+
);
|
|
7130
|
+
}
|
|
7131
|
+
locations = locations.slice(0, MAX_LOCATIONS_PER_DECLARATION);
|
|
7132
|
+
}
|
|
7133
|
+
keys = locations.map(slotDeclarationKey);
|
|
7134
|
+
if (!opts.force && this.declarationsThisLoad >= MAX_DECLARATIONS_PER_LOAD) {
|
|
7135
|
+
if (!this.warnedDeclarationCap) {
|
|
7136
|
+
this.warnedDeclarationCap = true;
|
|
7137
|
+
warn(
|
|
7138
|
+
`declareSlots(): already ${MAX_DECLARATIONS_PER_LOAD} manifests this page load \u2014 further ones are skipped (force: true to override)`
|
|
7139
|
+
);
|
|
7140
|
+
}
|
|
6967
7141
|
return null;
|
|
6968
7142
|
}
|
|
7143
|
+
this.declarationsThisLoad++;
|
|
6969
7144
|
const result = await this.api.declareManifest({
|
|
6970
7145
|
platform: cfg.platform,
|
|
6971
7146
|
mode: "merge",
|
|
6972
7147
|
locations
|
|
6973
7148
|
});
|
|
6974
7149
|
if (result?.mode === "merge") {
|
|
6975
|
-
writeSlotDeclaration(storageKey,
|
|
7150
|
+
writeSlotDeclaration(storageKey, rememberSlotKeys(memory, keys, now));
|
|
6976
7151
|
} else {
|
|
7152
|
+
writeSlotDeclaration(storageKey, rememberSlotKeys(memory, keys, failedAt(now)));
|
|
6977
7153
|
warn(
|
|
6978
7154
|
"slots declared but the server ignored mode=merge (old server); not caching, will retry next load"
|
|
6979
7155
|
);
|
|
6980
7156
|
}
|
|
6981
7157
|
return result;
|
|
6982
7158
|
} catch (err) {
|
|
7159
|
+
if (storageKey && keys.length > 0) {
|
|
7160
|
+
writeSlotDeclaration(storageKey, rememberSlotKeys(readSlotDeclaration(storageKey), keys, failedAt(now)));
|
|
7161
|
+
}
|
|
6983
7162
|
warn("declareSlots() failed \u2014", err);
|
|
6984
7163
|
return null;
|
|
6985
7164
|
}
|
|
@@ -7049,10 +7228,10 @@ var VioFacade = class {
|
|
|
7049
7228
|
attribution(slot, hint) {
|
|
7050
7229
|
const out = {};
|
|
7051
7230
|
try {
|
|
7052
|
-
const name =
|
|
7231
|
+
const name = normalizeSlotId(slot);
|
|
7053
7232
|
if (name) out.slot = name;
|
|
7054
7233
|
const boot = this.cachedBootstrap;
|
|
7055
|
-
const hinted =
|
|
7234
|
+
const hinted = toNumber(hint?.sponsorId);
|
|
7056
7235
|
if (boot) {
|
|
7057
7236
|
if (hinted !== void 0) {
|
|
7058
7237
|
const campaignId = resolveCampaignId({ slot: name || void 0, sponsorId: hinted }, boot);
|
|
@@ -7060,9 +7239,9 @@ var VioFacade = class {
|
|
|
7060
7239
|
out.sponsorId = hinted;
|
|
7061
7240
|
} else {
|
|
7062
7241
|
const campaign = this.campaignForSlot(name || null);
|
|
7063
|
-
const campaignId =
|
|
7242
|
+
const campaignId = toNumber(campaign?.id);
|
|
7064
7243
|
if (campaignId !== void 0) out.campaignId = campaignId;
|
|
7065
|
-
const sponsorId =
|
|
7244
|
+
const sponsorId = toNumber(campaign?.primarySponsor?.id);
|
|
7066
7245
|
if (sponsorId !== void 0) out.sponsorId = sponsorId;
|
|
7067
7246
|
}
|
|
7068
7247
|
} else if (hinted !== void 0) {
|
|
@@ -7075,6 +7254,35 @@ var VioFacade = class {
|
|
|
7075
7254
|
}
|
|
7076
7255
|
return out;
|
|
7077
7256
|
}
|
|
7257
|
+
/**
|
|
7258
|
+
* The cart split per campaign — the SAME rule `begin_checkout` / `purchase`
|
|
7259
|
+
* use, for hosts with their own analytics sink (Vev). Every unit of every
|
|
7260
|
+
* line goes to the campaign of its origin; units without one to the campaign
|
|
7261
|
+
* the current rule resolves for the line's sponsor (slot assignment → the
|
|
7262
|
+
* sponsor's active campaign → default); `slot` / `contentId` / `sponsorId`
|
|
7263
|
+
* only when they are the same for the whole slice; `value` with two
|
|
7264
|
+
* decimals; `slice` / `slices` number the parts. Pure over the current cart
|
|
7265
|
+
* (or over `opts.items`); `[]` when there is nothing.
|
|
7266
|
+
*/
|
|
7267
|
+
cartSlices(sponsorId, opts = {}) {
|
|
7268
|
+
try {
|
|
7269
|
+
let lines = [];
|
|
7270
|
+
if (Array.isArray(opts.items)) {
|
|
7271
|
+
lines = opts.items.filter((i) => sponsorId === void 0 || Number(i?.sponsorId) === Number(sponsorId));
|
|
7272
|
+
} else {
|
|
7273
|
+
this.cart.getAllCarts().forEach((state, id) => {
|
|
7274
|
+
if (sponsorId === void 0 || id === Number(sponsorId)) lines.push(...state.items);
|
|
7275
|
+
});
|
|
7276
|
+
}
|
|
7277
|
+
const boot = this.cachedBootstrap;
|
|
7278
|
+
return cartSlicesFrom(
|
|
7279
|
+
lines,
|
|
7280
|
+
(slot, lineSponsorId) => resolveCampaignId({ slot, sponsorId: lineSponsorId }, boot)
|
|
7281
|
+
);
|
|
7282
|
+
} catch {
|
|
7283
|
+
return [];
|
|
7284
|
+
}
|
|
7285
|
+
}
|
|
7078
7286
|
scheduleSlotDeclaration() {
|
|
7079
7287
|
if (this.slotDeclareTimer) clearTimeout(this.slotDeclareTimer);
|
|
7080
7288
|
this.slotDeclareTimer = setTimeout(() => {
|
|
@@ -7107,10 +7315,8 @@ var VioFacade = class {
|
|
|
7107
7315
|
function warn(...args) {
|
|
7108
7316
|
if (typeof console !== "undefined") console.warn("[Vio]", ...args);
|
|
7109
7317
|
}
|
|
7110
|
-
function
|
|
7111
|
-
|
|
7112
|
-
const n = Number(value);
|
|
7113
|
-
return Number.isFinite(n) ? n : void 0;
|
|
7318
|
+
function failedAt(now) {
|
|
7319
|
+
return now - (SLOT_DECLARATION_TTL_MS - SLOT_DECLARATION_FAILURE_TTL_MS);
|
|
7114
7320
|
}
|
|
7115
7321
|
var _vioGlobal = globalThis;
|
|
7116
7322
|
var Vio = _vioGlobal.__VIO_FACADE__ ?? (_vioGlobal.__VIO_FACADE__ = new VioFacade());
|
|
@@ -7164,6 +7370,6 @@ function vippsButtonAttributes(verb = "buy", opts = {}) {
|
|
|
7164
7370
|
};
|
|
7165
7371
|
}
|
|
7166
7372
|
|
|
7167
|
-
export { ADD_ITEM_MUTATION, ADYEN_RETURN_METHOD, ADYEN_RETURN_QUERY_KEYS, AdyenOriginError, AnalyticsManager, CREATE_CART_MUTATION, CREATE_CHECKOUT_MUTATION, CREATE_PAYMENT_STRIPE_MUTATION, CREATE_PAYMENT_VIPPS_MUTATION, CartManager, CheckoutManager, CommerceClient, Configuration, DELETE_ITEM_MUTATION, GET_AVAILABLE_PAYMENT_METHODS_QUERY, GET_CART_QUERY, GET_CHECKOUT_QUERY, GET_LINE_ITEMS_BY_SUPPLIER_QUERY, GET_VIPPS_STATUS_QUERY, KUSTOM_RETURN_QUERY_KEYS, SDK_VERSION, UPDATE_CHECKOUT_MUTATION, UPDATE_ITEM_MUTATION, UPDATE_SHIPPINGS_BY_SUPPLIER_MUTATION, VIPPS_BUTTON_SCRIPT, VIPPS_BUTTON_TAG, Vio, VioApi, VioApiError, __decorateClass, addItem, adyenReturnOutcome, adyenReturnParams, autoSlotDisplayName, autoSlotId, checkApplePayAvailability, createCart, createCheckout, createCommerceClient, createPaymentStripe, createPaymentVipps, createVioApi, deleteItem, displayPrice, ensureVippsButton, executeCartGraphQL, formatPrice, getAvailablePaymentMethods, getCart, getCartGraphQLOptions, getCheckout, getCustomerSessionId, getGlobalCurrency, getLineItemsBySupplier, getVippsStatus, kustomReturnOutcome, lineOrigins, nexiReturnPaymentId, normalizeOrigin, normalizeScope, primaryImageUrl, purchaseFromPaymentSuccess, readNexiPending, resolveCampaignId, resolveContent, resolveSlotCampaign, sameOrigin, showApplePaySheet, updateCheckout, updateItem, updateShippingsBySupplier, vippsButtonAttributes };
|
|
7168
|
-
//# sourceMappingURL=chunk-
|
|
7169
|
-
//# sourceMappingURL=chunk-
|
|
7373
|
+
export { ADD_ITEM_MUTATION, ADYEN_RETURN_METHOD, ADYEN_RETURN_QUERY_KEYS, AdyenOriginError, AnalyticsManager, CREATE_CART_MUTATION, CREATE_CHECKOUT_MUTATION, CREATE_PAYMENT_STRIPE_MUTATION, CREATE_PAYMENT_VIPPS_MUTATION, CartManager, CheckoutManager, CommerceClient, Configuration, DELETE_ITEM_MUTATION, GET_AVAILABLE_PAYMENT_METHODS_QUERY, GET_CART_QUERY, GET_CHECKOUT_QUERY, GET_LINE_ITEMS_BY_SUPPLIER_QUERY, GET_VIPPS_STATUS_QUERY, KUSTOM_RETURN_QUERY_KEYS, SDK_VERSION, UPDATE_CHECKOUT_MUTATION, UPDATE_ITEM_MUTATION, UPDATE_SHIPPINGS_BY_SUPPLIER_MUTATION, VIPPS_BUTTON_SCRIPT, VIPPS_BUTTON_TAG, Vio, VioApi, VioApiError, __decorateClass, addItem, adyenReturnOutcome, adyenReturnParams, autoSlotDisplayName, autoSlotId, cartSlicesFrom, checkApplePayAvailability, createCart, createCheckout, createCommerceClient, createPaymentStripe, createPaymentVipps, createVioApi, deleteItem, displayPrice, ensureVippsButton, executeCartGraphQL, formatPrice, getAvailablePaymentMethods, getCart, getCartGraphQLOptions, getCheckout, getCustomerSessionId, getGlobalCurrency, getLineItemsBySupplier, getVippsStatus, kustomReturnOutcome, lineOrigins, nexiReturnPaymentId, normalizeOrigin, normalizeScope, normalizeSlotId, primaryImageUrl, purchaseFromPaymentSuccess, readNexiPending, resolveCampaignId, resolveContent, resolveSlotCampaign, sameOrigin, showApplePaySheet, updateCheckout, updateItem, updateShippingsBySupplier, vippsButtonAttributes };
|
|
7374
|
+
//# sourceMappingURL=chunk-BRJMT7P4.js.map
|
|
7375
|
+
//# sourceMappingURL=chunk-BRJMT7P4.js.map
|