@vio-live/web-sdk 0.23.1 → 0.24.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.
@@ -11,6 +11,245 @@ var __decorateClass = (decorators, target, key, kind) => {
11
11
  return result;
12
12
  };
13
13
 
14
+ // src/core/slots.ts
15
+ var SLOT_ID_MAX_LENGTH = 100;
16
+ var SLOT_DECLARATION_TTL_MS = 24 * 60 * 60 * 1e3;
17
+ var SLOT_DECLARATION_FAILURE_TTL_MS = 60 * 60 * 1e3;
18
+ var MAX_LOCATIONS_PER_DECLARATION = 100;
19
+ var MAX_DECLARATIONS_PER_LOAD = 3;
20
+ function resolveSlotCampaign(boot, slot, now = Date.now(), platform, pageCampaignId, sponsorId) {
21
+ if (!boot) return null;
22
+ const page = activeCampaignEntry(boot, pageCampaignId);
23
+ const assignment = findSlotAssignmentDetail(boot, slot, now, platform);
24
+ const sponsor = toNumber(sponsorId);
25
+ if (assignment && assignmentApplies(assignment, page, sponsor)) return assignment.campaign;
26
+ return activeCampaignEntry(boot, pageCampaignId, sponsor) ?? (sponsor !== void 0 ? sponsorCampaignEntry(boot, sponsor) : null) ?? defaultCampaignEntry(boot);
27
+ }
28
+ function sponsorCampaignEntry(boot, sponsorId) {
29
+ const id = toNumber(sponsorId);
30
+ if (!boot || id === void 0) return null;
31
+ try {
32
+ const matches = activeCampaigns(boot).filter((c) => campaignSponsorIds(c).includes(id));
33
+ if (matches.length === 0) return null;
34
+ const defaultId = toNumber(boot.campaign?.id);
35
+ return matches.find((c) => toNumber(c.id) === defaultId) ?? matches[0] ?? null;
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+ function assignmentApplies(assignment, page, sponsorId) {
41
+ if (assignment.slot.source !== "page") return true;
42
+ if (isStalePageAssignment(assignment, page)) return false;
43
+ return sponsorId === void 0 || campaignSponsorIds(assignment.campaign).includes(sponsorId);
44
+ }
45
+ function isStalePageAssignment(assignment, page) {
46
+ return !!page && assignment.slot.source === "page" && toNumber(page.id) !== toNumber(assignment.campaign.id);
47
+ }
48
+ function toCampaignId(value) {
49
+ let n;
50
+ if (typeof value === "number") n = value;
51
+ else if (typeof value === "string" && /^\s*\d+\s*$/.test(value)) n = Number(value);
52
+ else return void 0;
53
+ return Number.isSafeInteger(n) && n > 0 ? n : void 0;
54
+ }
55
+ function campaignCandidates(hint) {
56
+ const raw = Array.isArray(hint) ? hint : [hint];
57
+ const out = [];
58
+ for (const v of raw) {
59
+ const id = toCampaignId(v);
60
+ if (id !== void 0 && !out.includes(id)) out.push(id);
61
+ }
62
+ return out;
63
+ }
64
+ function activeCampaignEntry(boot, hint, sponsorId) {
65
+ if (!boot) return null;
66
+ try {
67
+ const active = activeCampaigns(boot);
68
+ for (const id of campaignCandidates(hint)) {
69
+ const entry = active.find((c) => toNumber(c.id) === id);
70
+ if (!entry) continue;
71
+ if (sponsorId !== void 0 && !campaignSponsorIds(entry).includes(sponsorId)) continue;
72
+ return entry;
73
+ }
74
+ } catch {
75
+ }
76
+ return null;
77
+ }
78
+ function campaignSponsorIds(campaign) {
79
+ const ids = [];
80
+ const primary = toNumber(campaign.primarySponsor?.id);
81
+ if (primary !== void 0) ids.push(primary);
82
+ const secondaries = Array.isArray(campaign.secondarySponsors) ? campaign.secondarySponsors : [];
83
+ for (const s of secondaries) {
84
+ const id = toNumber(s?.id);
85
+ if (id !== void 0) ids.push(id);
86
+ }
87
+ return ids;
88
+ }
89
+ function findSlotAssignmentDetail(boot, slot, now = Date.now(), platform) {
90
+ const name = typeof slot === "string" ? slot.trim() : "";
91
+ if (!boot || !name) return null;
92
+ try {
93
+ const matches = [];
94
+ for (const campaign of activeCampaigns(boot)) {
95
+ const match = slotsOf(campaign).find((s) => assignmentMatches(s, name, now, platform));
96
+ if (match) matches.push({ campaign, slot: match });
97
+ }
98
+ if (matches.length === 0) return null;
99
+ const defaultId = toNumber(boot.campaign?.id);
100
+ return matches.find((m) => toNumber(m.campaign.id) === defaultId) ?? matches[0] ?? null;
101
+ } catch {
102
+ return null;
103
+ }
104
+ }
105
+ function defaultCampaignEntry(boot) {
106
+ if (!boot?.campaign || typeof boot.campaign !== "object") return null;
107
+ const defaultId = toNumber(boot.campaign.id);
108
+ if (defaultId === void 0) return null;
109
+ try {
110
+ const listed = wellFormedCampaigns(boot).find((c) => toNumber(c.id) === defaultId);
111
+ if (listed) return listed;
112
+ } catch {
113
+ }
114
+ return {
115
+ ...boot.campaign,
116
+ isDefault: true,
117
+ primarySponsor: boot.primarySponsor ?? null,
118
+ secondarySponsors: Array.isArray(boot.secondarySponsors) ? boot.secondarySponsors : [],
119
+ slots: []
120
+ };
121
+ }
122
+ function wellFormedCampaigns(boot) {
123
+ const list = Array.isArray(boot.campaigns) ? boot.campaigns : [];
124
+ return list.filter((c) => !!c && typeof c === "object");
125
+ }
126
+ function activeCampaigns(boot) {
127
+ return wellFormedCampaigns(boot).filter((c) => c.status === "active");
128
+ }
129
+ function slotsOf(campaign) {
130
+ const slots = Array.isArray(campaign.slots) ? campaign.slots : [];
131
+ return slots.filter((s) => !!s && typeof s === "object");
132
+ }
133
+ function assignmentMatches(s, name, now, platform) {
134
+ if (typeof s.name !== "string" || s.name.trim() !== name) return false;
135
+ if (platform && s.platform != null && s.platform !== platform) return false;
136
+ const start = parseTime(s.startDate);
137
+ if (start !== void 0 && start > now) return false;
138
+ const end = parseTime(s.endDate);
139
+ if (end !== void 0 && now >= end) return false;
140
+ return true;
141
+ }
142
+ function parseTime(value) {
143
+ if (value == null || value === "") return void 0;
144
+ const t = Date.parse(String(value));
145
+ return Number.isFinite(t) ? t : void 0;
146
+ }
147
+ function toNumber(value) {
148
+ if (value === void 0 || value === null || value === "") return void 0;
149
+ const n = Number(value);
150
+ return Number.isFinite(n) ? n : void 0;
151
+ }
152
+ function normalizeSlotId(value) {
153
+ if (typeof value !== "string") return "";
154
+ return value.trim().slice(0, SLOT_ID_MAX_LENGTH).trim();
155
+ }
156
+ function normalizeSlotLocations(slots) {
157
+ const out = [];
158
+ const seen = /* @__PURE__ */ new Set();
159
+ if (!Array.isArray(slots)) return out;
160
+ for (const raw of slots) {
161
+ const id = normalizeSlotId(typeof raw === "string" ? raw : raw?.id);
162
+ if (!id || seen.has(id)) continue;
163
+ seen.add(id);
164
+ const displayName = raw && typeof raw === "object" && typeof raw.displayName === "string" ? raw.displayName.trim() : "";
165
+ const campaignId = raw && typeof raw === "object" ? toCampaignId(raw.campaignId) : void 0;
166
+ const location2 = { id };
167
+ if (displayName) location2.displayName = displayName;
168
+ if (campaignId !== void 0) location2.campaignId = campaignId;
169
+ out.push(location2);
170
+ }
171
+ return out;
172
+ }
173
+ function autoSlotId(kind, ordinal, scope) {
174
+ const tail = `${kind}-${ordinal + 1}`;
175
+ let prefix = normalizeScope(scope);
176
+ const room = SLOT_ID_MAX_LENGTH - tail.length - 1;
177
+ if (prefix.length > room) prefix = prefix.slice(0, Math.max(0, room)).replace(/-+$/, "");
178
+ return `${prefix ? `${prefix}-` : ""}${tail}`;
179
+ }
180
+ function autoSlotDisplayName(kind, ordinal, scopeName) {
181
+ const label = `${kind.charAt(0).toUpperCase()}${kind.slice(1)} ${ordinal + 1}`;
182
+ const name = typeof scopeName === "string" ? scopeName.trim() : "";
183
+ return name ? `${label} \xB7 ${name}` : label;
184
+ }
185
+ function normalizeScope(scope) {
186
+ if (typeof scope !== "string") return "";
187
+ return scope.trim().replace(/\s+/g, "-");
188
+ }
189
+ var SLOT_DECLARATION_MEMORY_CAP = 500;
190
+ function slotDeclarationKey(location2, pageCampaignId) {
191
+ const campaignId = toCampaignId(location2.campaignId) ?? toCampaignId(pageCampaignId);
192
+ return location2.id + (location2.displayName ? `${location2.displayName}` : "") + (campaignId !== void 0 ? `${campaignId}` : "");
193
+ }
194
+ function pendingSlotKeys(memory, keys, now = Date.now(), ttl = SLOT_DECLARATION_TTL_MS) {
195
+ return keys.filter((key) => {
196
+ const at = memory?.[key];
197
+ if (typeof at !== "number" || !Number.isFinite(at)) return true;
198
+ return now - at >= ttl || now < at;
199
+ });
200
+ }
201
+ function slotKeyId(key) {
202
+ const cut = key.search(/[\u001f\u001e]/);
203
+ return cut >= 0 ? key.slice(0, cut) : key;
204
+ }
205
+ function rememberSlotKeys(memory, keys, at, cap = SLOT_DECLARATION_MEMORY_CAP) {
206
+ const next = { ...memory ?? {} };
207
+ const ids = new Set(keys.map(slotKeyId));
208
+ for (const existing of Object.keys(next)) {
209
+ if (ids.has(slotKeyId(existing)) && !keys.includes(existing)) delete next[existing];
210
+ }
211
+ for (const key of keys) next[key] = at;
212
+ const entries = Object.entries(next);
213
+ if (entries.length <= cap) return next;
214
+ entries.sort((a, b) => b[1] - a[1]);
215
+ return Object.fromEntries(entries.slice(0, cap));
216
+ }
217
+ function slotDeclarationStorageKey(platform, apiKey) {
218
+ return `vio.slots.${platform}.${fnv1a(apiKey)}`;
219
+ }
220
+ function fnv1a(input) {
221
+ let hash = 2166136261;
222
+ for (let i = 0; i < input.length; i++) {
223
+ hash ^= input.charCodeAt(i);
224
+ hash = Math.imul(hash, 16777619) >>> 0;
225
+ }
226
+ return hash.toString(16).padStart(8, "0");
227
+ }
228
+ function readSlotDeclaration(storageKey) {
229
+ try {
230
+ if (typeof localStorage === "undefined") return {};
231
+ const raw = localStorage.getItem(storageKey);
232
+ if (!raw) return {};
233
+ const parsed = JSON.parse(raw);
234
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
235
+ if (Array.isArray(parsed.keys)) return {};
236
+ const out = {};
237
+ for (const [key, at] of Object.entries(parsed)) {
238
+ if (typeof at === "number" && Number.isFinite(at)) out[key] = at;
239
+ }
240
+ return out;
241
+ } catch {
242
+ return {};
243
+ }
244
+ }
245
+ function writeSlotDeclaration(storageKey, memory) {
246
+ try {
247
+ if (typeof localStorage === "undefined") return;
248
+ localStorage.setItem(storageKey, JSON.stringify(memory));
249
+ } catch {
250
+ }
251
+ }
252
+
14
253
  // src/core/configuration.ts
15
254
  var DEFAULT_URLS = {
16
255
  // The Vio Backend development environment was removed on 2026-09-16; its REST
@@ -49,6 +288,8 @@ var ConfigurationSingleton = class {
49
288
  platform: input.platform ?? "web",
50
289
  contentId: input.contentId,
51
290
  contentTitle: input.contentTitle,
291
+ campaignId: toCampaignId(input.campaignId),
292
+ debug: input.debug === true,
52
293
  apiBase: input.apiBase ?? defaults.apiBase,
53
294
  graphQLBase: input.graphQLBase ?? defaults.graphQLBase,
54
295
  eventsBase: input.eventsBase ?? defaults.eventsBase,
@@ -2514,7 +2755,7 @@ async function prepareApplePay(config) {
2514
2755
  }
2515
2756
 
2516
2757
  // src/core/version.ts
2517
- var SDK_VERSION = "0.23.1";
2758
+ var SDK_VERSION = "0.24.0";
2518
2759
 
2519
2760
  // src/core/checkout/payments/stripe-embedded.ts
2520
2761
  var CREATE_PAYMENT_INTENT_STRIPE_MUTATION = `
@@ -5941,165 +6182,6 @@ function stripQueryAndHash(url) {
5941
6182
  return clean.trim() || void 0;
5942
6183
  }
5943
6184
 
5944
- // src/core/slots.ts
5945
- var SLOT_ID_MAX_LENGTH = 100;
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;
5950
- function resolveSlotCampaign(boot, slot, now = Date.now(), platform) {
5951
- if (!boot) return null;
5952
- return findSlotAssignment(boot, slot, now, platform) ?? defaultCampaignEntry(boot);
5953
- }
5954
- function findSlotAssignment(boot, slot, now = Date.now(), platform) {
5955
- const name = typeof slot === "string" ? slot.trim() : "";
5956
- if (!boot || !name) return null;
5957
- try {
5958
- const matches = activeCampaigns(boot).filter(
5959
- (c) => slotsOf(c).some((s) => assignmentMatches(s, name, now, platform))
5960
- );
5961
- if (matches.length === 0) return null;
5962
- const defaultId = toNumber(boot.campaign?.id);
5963
- return matches.find((c) => toNumber(c.id) === defaultId) ?? matches[0] ?? null;
5964
- } catch {
5965
- return null;
5966
- }
5967
- }
5968
- function defaultCampaignEntry(boot) {
5969
- if (!boot?.campaign || typeof boot.campaign !== "object") return null;
5970
- const defaultId = toNumber(boot.campaign.id);
5971
- if (defaultId === void 0) return null;
5972
- try {
5973
- const listed = wellFormedCampaigns(boot).find((c) => toNumber(c.id) === defaultId);
5974
- if (listed) return listed;
5975
- } catch {
5976
- }
5977
- return {
5978
- ...boot.campaign,
5979
- isDefault: true,
5980
- primarySponsor: boot.primarySponsor ?? null,
5981
- secondarySponsors: Array.isArray(boot.secondarySponsors) ? boot.secondarySponsors : [],
5982
- slots: []
5983
- };
5984
- }
5985
- function wellFormedCampaigns(boot) {
5986
- const list = Array.isArray(boot.campaigns) ? boot.campaigns : [];
5987
- return list.filter((c) => !!c && typeof c === "object");
5988
- }
5989
- function activeCampaigns(boot) {
5990
- return wellFormedCampaigns(boot).filter((c) => c.status === "active");
5991
- }
5992
- function slotsOf(campaign) {
5993
- const slots = Array.isArray(campaign.slots) ? campaign.slots : [];
5994
- return slots.filter((s) => !!s && typeof s === "object");
5995
- }
5996
- function assignmentMatches(s, name, now, platform) {
5997
- if (typeof s.name !== "string" || s.name.trim() !== name) return false;
5998
- if (platform && s.platform != null && s.platform !== platform) return false;
5999
- const start = parseTime(s.startDate);
6000
- if (start !== void 0 && start > now) return false;
6001
- const end = parseTime(s.endDate);
6002
- if (end !== void 0 && now >= end) return false;
6003
- return true;
6004
- }
6005
- function parseTime(value) {
6006
- if (value == null || value === "") return void 0;
6007
- const t = Date.parse(String(value));
6008
- return Number.isFinite(t) ? t : void 0;
6009
- }
6010
- function toNumber(value) {
6011
- if (value === void 0 || value === null || value === "") return void 0;
6012
- const n = Number(value);
6013
- return Number.isFinite(n) ? n : void 0;
6014
- }
6015
- function normalizeSlotId(value) {
6016
- if (typeof value !== "string") return "";
6017
- return value.trim().slice(0, SLOT_ID_MAX_LENGTH).trim();
6018
- }
6019
- function normalizeSlotLocations(slots) {
6020
- const out = [];
6021
- const seen = /* @__PURE__ */ new Set();
6022
- if (!Array.isArray(slots)) return out;
6023
- for (const raw of slots) {
6024
- const id = normalizeSlotId(typeof raw === "string" ? raw : raw?.id);
6025
- if (!id || seen.has(id)) continue;
6026
- seen.add(id);
6027
- const displayName = raw && typeof raw === "object" && typeof raw.displayName === "string" ? raw.displayName.trim() : "";
6028
- out.push(displayName ? { id, displayName } : { id });
6029
- }
6030
- return out;
6031
- }
6032
- function autoSlotId(kind, ordinal, scope) {
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}`;
6038
- }
6039
- function autoSlotDisplayName(kind, ordinal, scopeName) {
6040
- const label = `${kind.charAt(0).toUpperCase()}${kind.slice(1)} ${ordinal + 1}`;
6041
- const name = typeof scopeName === "string" ? scopeName.trim() : "";
6042
- return name ? `${label} \xB7 ${name}` : label;
6043
- }
6044
- function normalizeScope(scope) {
6045
- if (typeof scope !== "string") return "";
6046
- return scope.trim().replace(/\s+/g, "-");
6047
- }
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));
6066
- }
6067
- function slotDeclarationStorageKey(platform, apiKey) {
6068
- return `vio.slots.${platform}.${fnv1a(apiKey)}`;
6069
- }
6070
- function fnv1a(input) {
6071
- let hash = 2166136261;
6072
- for (let i = 0; i < input.length; i++) {
6073
- hash ^= input.charCodeAt(i);
6074
- hash = Math.imul(hash, 16777619) >>> 0;
6075
- }
6076
- return hash.toString(16).padStart(8, "0");
6077
- }
6078
- function readSlotDeclaration(storageKey) {
6079
- try {
6080
- if (typeof localStorage === "undefined") return {};
6081
- const raw = localStorage.getItem(storageKey);
6082
- if (!raw) return {};
6083
- const parsed = JSON.parse(raw);
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;
6091
- } catch {
6092
- return {};
6093
- }
6094
- }
6095
- function writeSlotDeclaration(storageKey, memory) {
6096
- try {
6097
- if (typeof localStorage === "undefined") return;
6098
- localStorage.setItem(storageKey, JSON.stringify(memory));
6099
- } catch {
6100
- }
6101
- }
6102
-
6103
6185
  // src/core/cart/slices.ts
6104
6186
  function cartSlicesFrom(lines, resolveCampaign, fallbackCurrency) {
6105
6187
  if (!Array.isArray(lines) || lines.length === 0) return [];
@@ -6817,27 +6899,27 @@ function vioCart() {
6817
6899
  return null;
6818
6900
  }
6819
6901
  }
6820
- function resolveCampaignId(ctx, boot) {
6902
+ function resolveCampaignId(ctx, boot, opts = {}) {
6821
6903
  if (ctx.campaignId !== void 0) return ctx.campaignId;
6822
6904
  const defaultId = boot?.campaign?.id;
6905
+ const config = Configuration.isInitialized ? Configuration.get() : void 0;
6906
+ const sponsorId = toNumber(ctx.sponsorId);
6907
+ const candidates = [
6908
+ ...Array.isArray(opts.pageCampaignId) ? opts.pageCampaignId : [opts.pageCampaignId],
6909
+ config?.campaignId
6910
+ ];
6911
+ const page = activeCampaignEntry(boot, candidates, sponsorId);
6823
6912
  if (ctx.slot) {
6824
- const platform = Configuration.isInitialized ? Configuration.get().platform : void 0;
6825
- const assigned = toNumber(findSlotAssignment(boot, ctx.slot, Date.now(), platform)?.id);
6826
- if (assigned !== void 0) return assigned;
6913
+ const assignment = findSlotAssignmentDetail(boot, ctx.slot, Date.now(), config?.platform);
6914
+ if (assignment && assignmentApplies(assignment, activeCampaignEntry(boot, candidates), sponsorId)) {
6915
+ const assigned = toNumber(assignment.campaign.id);
6916
+ if (assigned !== void 0) return assigned;
6917
+ }
6827
6918
  }
6828
- const sponsorId = toNumber(ctx.sponsorId);
6919
+ const pageId = toNumber(page?.id);
6920
+ if (pageId !== void 0) return pageId;
6829
6921
  if (sponsorId === void 0) return defaultId;
6830
- try {
6831
- const campaigns = Array.isArray(boot?.campaigns) ? boot.campaigns : [];
6832
- const matches = campaigns.filter(
6833
- (c) => !!c && typeof c === "object" && c.status === "active" && campaignSponsorIds(c).includes(sponsorId)
6834
- );
6835
- const chosen = matches.find((c) => c.id === defaultId) ?? matches[0];
6836
- const chosenId = toNumber(chosen?.id);
6837
- if (chosenId !== void 0) return chosenId;
6838
- } catch {
6839
- }
6840
- return defaultId;
6922
+ return toNumber(sponsorCampaignEntry(boot, sponsorId)?.id) ?? defaultId;
6841
6923
  }
6842
6924
  function campaignOf(detail) {
6843
6925
  return toNumber(detail.campaignId);
@@ -6872,17 +6954,6 @@ function contentOf(detail) {
6872
6954
  if (typeof detail.contentTitle === "string" && detail.contentTitle.trim()) out.contentTitle = detail.contentTitle.trim();
6873
6955
  return out;
6874
6956
  }
6875
- function campaignSponsorIds(campaign) {
6876
- const ids = [];
6877
- const primary = toNumber(campaign.primarySponsor?.id);
6878
- if (primary !== void 0) ids.push(primary);
6879
- const secondaries = Array.isArray(campaign.secondarySponsors) ? campaign.secondarySponsors : [];
6880
- for (const s of secondaries) {
6881
- const id = toNumber(s?.id);
6882
- if (id !== void 0) ids.push(id);
6883
- }
6884
- return ids;
6885
- }
6886
6957
  function purchaseFromPaymentSuccess(d) {
6887
6958
  const r = d.result ?? {};
6888
6959
  const orderId = firstId(d.orderId, r.confirmation?.orderId, d.checkoutId);
@@ -6946,8 +7017,11 @@ var VioFacade = class {
6946
7017
  * (another key or environment) is still in flight after a re-init; its answer
6947
7018
  * belongs to that configuration and must not land in this one. */
6948
7019
  this.generation = 0;
6949
- /** Slot ids present on the page (`Vio.registerSlot`): how many elements hold each + its display name. */
7020
+ /** Slot ids present on the page (`Vio.registerSlot`): how many elements hold each, its display name and its own campaign. */
6950
7021
  this.slotRegistry = /* @__PURE__ */ new Map();
7022
+ /** Slots already warned about (`dashboard`: the dashboard's assignment stands; `replaced`: this page moved it). */
7023
+ this.warnedDashboardSlots = /* @__PURE__ */ new Set();
7024
+ this.warnedReplacedSlots = /* @__PURE__ */ new Set();
6951
7025
  /** Pending debounced declaration of the registry. */
6952
7026
  this.slotDeclareTimer = null;
6953
7027
  /** A name appeared (or the key changed) since the registry was last declared. */
@@ -6980,6 +7054,8 @@ var VioFacade = class {
6980
7054
  this.declarationsThisLoad = 0;
6981
7055
  this.warnedLocationCap = false;
6982
7056
  this.warnedDeclarationCap = false;
7057
+ this.warnedDashboardSlots.clear();
7058
+ this.warnedReplacedSlots.clear();
6983
7059
  }
6984
7060
  /**
6985
7061
  * The content (article, page) this SDK instance is rendered in — what every
@@ -7117,9 +7193,14 @@ var VioFacade = class {
7117
7193
  const cfg = Configuration.get();
7118
7194
  storageKey = slotDeclarationStorageKey(cfg.platform, cfg.apiKey);
7119
7195
  now = Date.now();
7196
+ const pageCampaignId = cfg.campaignId;
7197
+ for (const l of all) {
7198
+ if (l.campaignId !== void 0 && l.campaignId === pageCampaignId) delete l.campaignId;
7199
+ }
7120
7200
  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)));
7201
+ const keyOf = (l) => slotDeclarationKey(l, pageCampaignId);
7202
+ const pending2 = new Set(pendingSlotKeys(memory, all.map(keyOf), now));
7203
+ let locations = opts.force ? all : all.filter((l) => pending2.has(keyOf(l)));
7123
7204
  if (locations.length === 0) return null;
7124
7205
  if (locations.length > MAX_LOCATIONS_PER_DECLARATION) {
7125
7206
  if (!this.warnedLocationCap) {
@@ -7130,7 +7211,7 @@ var VioFacade = class {
7130
7211
  }
7131
7212
  locations = locations.slice(0, MAX_LOCATIONS_PER_DECLARATION);
7132
7213
  }
7133
- keys = locations.map(slotDeclarationKey);
7214
+ keys = locations.map(keyOf);
7134
7215
  if (!opts.force && this.declarationsThisLoad >= MAX_DECLARATIONS_PER_LOAD) {
7135
7216
  if (!this.warnedDeclarationCap) {
7136
7217
  this.warnedDeclarationCap = true;
@@ -7144,10 +7225,16 @@ var VioFacade = class {
7144
7225
  const result = await this.api.declareManifest({
7145
7226
  platform: cfg.platform,
7146
7227
  mode: "merge",
7147
- locations
7228
+ locations,
7229
+ ...pageCampaignId !== void 0 ? { campaignId: pageCampaignId } : {}
7148
7230
  });
7231
+ this.reportAssignments(result, locations, pageCampaignId, cfg.debug);
7149
7232
  if (result?.mode === "merge") {
7150
- writeSlotDeclaration(storageKey, rememberSlotKeys(memory, keys, now));
7233
+ const unhandled = this.campaignNotTakenUp(result, locations, pageCampaignId);
7234
+ const settled = keys.filter((k) => !unhandled.has(k));
7235
+ let next = rememberSlotKeys(memory, settled, now);
7236
+ if (unhandled.size > 0) next = rememberSlotKeys(next, [...unhandled], failedAt(now));
7237
+ writeSlotDeclaration(storageKey, next);
7151
7238
  } else {
7152
7239
  writeSlotDeclaration(storageKey, rememberSlotKeys(memory, keys, failedAt(now)));
7153
7240
  warn(
@@ -7166,21 +7253,24 @@ var VioFacade = class {
7166
7253
  /**
7167
7254
  * Register a slot present on the page (the `<vio-*>` elements call it with
7168
7255
  * their effective id — the host's `vio-slot` or the auto-generated one —
7169
- * and the optional display name). The registry is declared ONCE, debounced,
7170
- * after the first successful bootstrap — and again whenever a new id or a
7171
- * new display name appears. A `displayName` given later for an id already
7172
- * registered replaces the one kept; `undefined` leaves it alone. The
7173
- * returned function unregisters; removal never re-declares.
7256
+ * the optional display name, and the element's own campaign when it has
7257
+ * one: `vio-campaign` or an ancestor's `data-vio-campaign`). The registry is
7258
+ * declared ONCE, debounced, after the first successful bootstrap — and again
7259
+ * whenever a new id, display name or campaign appears. A `displayName` /
7260
+ * `campaignId` given later for an id already registered replaces the one
7261
+ * kept; `undefined` leaves it alone. The returned function unregisters;
7262
+ * removal never re-declares.
7174
7263
  */
7175
- registerSlot(name, displayName) {
7264
+ registerSlot(name, displayName, campaignId) {
7176
7265
  const id = normalizeSlotId(name);
7177
7266
  if (!id) return () => {
7178
7267
  };
7179
7268
  const label = typeof displayName === "string" && displayName.trim() ? displayName.trim() : void 0;
7269
+ const campaign = toCampaignId(campaignId);
7180
7270
  const entry = this.slotRegistry.get(id);
7181
7271
  let changed = false;
7182
7272
  if (!entry) {
7183
- this.slotRegistry.set(id, { count: 1, displayName: label });
7273
+ this.slotRegistry.set(id, { count: 1, displayName: label, campaignId: campaign });
7184
7274
  changed = true;
7185
7275
  } else {
7186
7276
  entry.count++;
@@ -7188,6 +7278,10 @@ var VioFacade = class {
7188
7278
  entry.displayName = label;
7189
7279
  changed = true;
7190
7280
  }
7281
+ if (campaign !== void 0 && campaign !== entry.campaignId) {
7282
+ entry.campaignId = campaign;
7283
+ changed = true;
7284
+ }
7191
7285
  }
7192
7286
  if (changed) {
7193
7287
  this.slotsDirty = true;
@@ -7208,9 +7302,30 @@ var VioFacade = class {
7208
7302
  * open campaign for the init platform, else the surface's default. With no
7209
7303
  * slot, the default. `null` before the bootstrap. See `resolveSlotCampaign`.
7210
7304
  */
7211
- campaignForSlot(slot) {
7212
- const platform = Configuration.isInitialized ? Configuration.get().platform : void 0;
7213
- return resolveSlotCampaign(this.cachedBootstrap, slot ?? null, Date.now(), platform);
7305
+ campaignForSlot(slot, hint) {
7306
+ const config = Configuration.isInitialized ? Configuration.get() : void 0;
7307
+ return resolveSlotCampaign(
7308
+ this.cachedBootstrap,
7309
+ slot ?? null,
7310
+ Date.now(),
7311
+ config?.platform,
7312
+ this.pageCampaignCandidates(hint?.campaignId),
7313
+ toNumber(hint?.sponsorId)
7314
+ );
7315
+ }
7316
+ /** The page-campaign candidates in precedence order: the element's (own, ancestor), then `Vio.init`'s. */
7317
+ pageCampaignCandidates(hint) {
7318
+ const config = Configuration.isInitialized ? Configuration.get() : void 0;
7319
+ return campaignCandidates([...Array.isArray(hint) ? hint : [hint], config?.campaignId]);
7320
+ }
7321
+ /**
7322
+ * The campaign the PAGE belongs to (`Vio.init({ campaignId })`, ADR-0034
7323
+ * amendment 3), as the last bootstrap lists it — only when it is there and
7324
+ * active; `null` otherwise (no page campaign, paused, unknown, no bootstrap).
7325
+ */
7326
+ pageCampaign() {
7327
+ const config = Configuration.isInitialized ? Configuration.get() : void 0;
7328
+ return activeCampaignEntry(this.cachedBootstrap, config?.campaignId);
7214
7329
  }
7215
7330
  /**
7216
7331
  * THE attribution helper — the SDK elements, Vev and Replit all use this
@@ -7222,8 +7337,12 @@ var VioFacade = class {
7222
7337
  *
7223
7338
  * `hint.sponsorId` — when the caller already knows the sponsor (a card with
7224
7339
  * `sponsor-id`) it is kept as `sponsorId`, and the campaign follows the same
7225
- * cascade analytics uses (slot assignment → the sponsor's active campaign →
7226
- * default), so what the cart remembers matches what the events say.
7340
+ * cascade analytics uses (slot assignment → page campaign → the sponsor's
7341
+ * active campaign → default), so what the cart remembers matches what the
7342
+ * events say — the page campaign applies there only when that sponsor takes
7343
+ * part in it. `hint.campaignId` — the element's own page campaign
7344
+ * candidates (`vio-campaign`, an ancestor's `data-vio-campaign`), ahead of
7345
+ * `Vio.init`'s; an unusable one falls through to the next; `0` = unset.
7227
7346
  */
7228
7347
  attribution(slot, hint) {
7229
7348
  const out = {};
@@ -7232,13 +7351,16 @@ var VioFacade = class {
7232
7351
  if (name) out.slot = name;
7233
7352
  const boot = this.cachedBootstrap;
7234
7353
  const hinted = toNumber(hint?.sponsorId);
7354
+ const pageCampaignId = this.pageCampaignCandidates(hint?.campaignId);
7235
7355
  if (boot) {
7236
7356
  if (hinted !== void 0) {
7237
- const campaignId = resolveCampaignId({ slot: name || void 0, sponsorId: hinted }, boot);
7357
+ const campaignId = resolveCampaignId({ slot: name || void 0, sponsorId: hinted }, boot, {
7358
+ pageCampaignId
7359
+ });
7238
7360
  if (campaignId !== void 0) out.campaignId = campaignId;
7239
7361
  out.sponsorId = hinted;
7240
7362
  } else {
7241
- const campaign = this.campaignForSlot(name || null);
7363
+ const campaign = this.campaignForSlot(name || null, { campaignId: pageCampaignId });
7242
7364
  const campaignId = toNumber(campaign?.id);
7243
7365
  if (campaignId !== void 0) out.campaignId = campaignId;
7244
7366
  const sponsorId = toNumber(campaign?.primarySponsor?.id);
@@ -7283,15 +7405,62 @@ var VioFacade = class {
7283
7405
  return [];
7284
7406
  }
7285
7407
  }
7408
+ /**
7409
+ * What the micro did with the page's campaign per slot (`assignment`):
7410
+ * `console.debug` when `Vio.init({ debug: true })`; a warning once per
7411
+ * slot when the dashboard's own assignment stands (only for a slot this
7412
+ * page actually sent a campaign for) and once per slot when this page moved
7413
+ * it from an earlier page assignment (`replaced`).
7414
+ */
7415
+ reportAssignments(result, sent, pageCampaignId, debug) {
7416
+ const answered = Array.isArray(result?.locations) ? result.locations : [];
7417
+ const campaignFor = (id) => sent.find((l) => l.id === id)?.campaignId ?? pageCampaignId;
7418
+ for (const l of answered) {
7419
+ if (!l || typeof l !== "object" || !l.assignment) continue;
7420
+ if (debug && typeof console !== "undefined") console.debug("[Vio] slot", l.locationId, "assignment:", l.assignment);
7421
+ const sentCampaign = campaignFor(l.locationId);
7422
+ if (sentCampaign === void 0) continue;
7423
+ if (l.assignment === "dashboard" && !this.warnedDashboardSlots.has(l.locationId)) {
7424
+ this.warnedDashboardSlots.add(l.locationId);
7425
+ warn(`slot ${l.locationId} is assigned from the dashboard; the page's campaign is ignored there`);
7426
+ }
7427
+ if (l.assignment === "replaced" && !this.warnedReplacedSlots.has(l.locationId)) {
7428
+ this.warnedReplacedSlots.add(l.locationId);
7429
+ warn(`slot ${l.locationId} moved to campaign ${sentCampaign} by this page (it replaced an earlier page assignment)`);
7430
+ }
7431
+ }
7432
+ }
7433
+ /**
7434
+ * The memory keys of the sent locations whose campaign the micro did not
7435
+ * take up: every location when a campaign was sent and no answer carries
7436
+ * `assignment` (an older micro), or the ones answered `none` for a campaign
7437
+ * the bootstrap lists as active. They are remembered with the 1 h TTL.
7438
+ */
7439
+ campaignNotTakenUp(result, sent, pageCampaignId) {
7440
+ const out = /* @__PURE__ */ new Set();
7441
+ const withCampaign = sent.filter((l) => (l.campaignId ?? pageCampaignId) !== void 0);
7442
+ if (withCampaign.length === 0) return out;
7443
+ const answered = Array.isArray(result?.locations) ? result.locations : [];
7444
+ const anyAssignment = answered.some((l) => l && typeof l === "object" && !!l.assignment);
7445
+ for (const l of withCampaign) {
7446
+ const answer = answered.find((a) => a && a.locationId === l.id);
7447
+ const campaignId = l.campaignId ?? pageCampaignId;
7448
+ const notTaken = !anyAssignment || answer?.assignment === "none" && activeCampaignEntry(this.cachedBootstrap, campaignId) !== null;
7449
+ if (notTaken) out.add(slotDeclarationKey(l, pageCampaignId));
7450
+ }
7451
+ return out;
7452
+ }
7286
7453
  scheduleSlotDeclaration() {
7287
7454
  if (this.slotDeclareTimer) clearTimeout(this.slotDeclareTimer);
7288
7455
  this.slotDeclareTimer = setTimeout(() => {
7289
7456
  this.slotDeclareTimer = null;
7290
7457
  this.slotsDirty = false;
7291
7458
  void this.declareSlots(
7292
- [...this.slotRegistry.entries()].map(
7293
- ([id, { displayName }]) => displayName ? { id, displayName } : id
7294
- )
7459
+ [...this.slotRegistry.entries()].map(([id, { displayName, campaignId }]) => ({
7460
+ id,
7461
+ ...displayName ? { displayName } : {},
7462
+ ...campaignId !== void 0 ? { campaignId } : {}
7463
+ }))
7295
7464
  );
7296
7465
  }, SLOT_DECLARATION_DEBOUNCE_MS);
7297
7466
  }
@@ -7370,6 +7539,6 @@ function vippsButtonAttributes(verb = "buy", opts = {}) {
7370
7539
  };
7371
7540
  }
7372
7541
 
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
7542
+ 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, activeCampaignEntry, addItem, adyenReturnOutcome, adyenReturnParams, autoSlotDisplayName, autoSlotId, campaignCandidates, 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, sponsorCampaignEntry, toCampaignId, updateCheckout, updateItem, updateShippingsBySupplier, vippsButtonAttributes };
7543
+ //# sourceMappingURL=chunk-AXJKB2CW.js.map
7544
+ //# sourceMappingURL=chunk-AXJKB2CW.js.map