@action-x/ad-sdk 0.1.4 → 0.1.6

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/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- class O {
1
+ class B {
2
2
  constructor() {
3
3
  this.events = {};
4
4
  }
@@ -23,8 +23,8 @@ class O {
23
23
  this.events[e] && this.events[e].forEach((i) => {
24
24
  try {
25
25
  i(...t);
26
- } catch (n) {
27
- console.error(`[EventEmitter] Error in event handler for "${e}":`, n);
26
+ } catch (s) {
27
+ console.error(`[EventEmitter] Error in event handler for "${e}":`, s);
28
28
  }
29
29
  });
30
30
  }
@@ -42,7 +42,16 @@ class O {
42
42
  return ((t = this.events[e]) == null ? void 0 : t.length) || 0;
43
43
  }
44
44
  }
45
- class b {
45
+ class w {
46
+ static getClickUrl(e) {
47
+ return e.tracking.clickUrl || e.tracking.click_url || "#";
48
+ }
49
+ static getImpressionUrl(e) {
50
+ return e.tracking.impressionUrl || e.tracking.impression_url || "";
51
+ }
52
+ static getCtaText(e) {
53
+ return e.adapted.ctaText || e.adapted.cta_text || "Learn More";
54
+ }
46
55
  /**
47
56
  * Render Action Card ad as HTML string
48
57
  *
@@ -51,37 +60,37 @@ class b {
51
60
  * @returns HTML string
52
61
  */
53
62
  static renderActionCard(e, t = {}) {
54
- var h;
55
- const { variant: i = "horizontal", includeWrapper: n = !0 } = t, s = e.adapted, r = e.tracking, a = n ? `<div class="ax-ad-card ax-ad-card-${i}" data-ad-id="${e.original.id}">` : "", c = (h = s.image) != null && h.url ? `<img
56
- src="${s.image.url}"
57
- alt="${s.title}"
63
+ var m;
64
+ const { variant: i = "horizontal", includeWrapper: s = !0 } = t, n = e.adapted, o = this.getClickUrl(e), a = this.getImpressionUrl(e), c = s ? `<div class="ax-ad-card ax-ad-card-${i}" data-ad-id="${e.original.id}">` : "", l = (m = n.image) != null && m.url ? `<img
65
+ src="${n.image.url}"
66
+ alt="${n.title}"
58
67
  class="ax-ad-image"
59
68
  loading="lazy"
60
- />` : "", d = s.price ? `<span class="ax-ad-price">${s.price.display || s.price.value}</span>` : "", l = s.rating ? `<div class="ax-ad-rating" aria-label="Rating: ${s.rating}">
61
- ${"★".repeat(Math.floor(s.rating))}${"☆".repeat(5 - Math.floor(s.rating))}
62
- </div>` : "", u = s.brand ? `<span class="ax-ad-brand">${s.brand}</span>` : "", f = `
63
- ${c}
69
+ />` : "", d = n.price ? `<span class="ax-ad-price">${n.price.display || n.price.value}</span>` : "", u = n.rating ? `<div class="ax-ad-rating" aria-label="Rating: ${n.rating}">
70
+ ${"★".repeat(Math.floor(n.rating))}${"☆".repeat(5 - Math.floor(n.rating))}
71
+ </div>` : "", h = n.brand ? `<span class="ax-ad-brand">${n.brand}</span>` : "", p = `
72
+ ${l}
64
73
  <div class="ax-ad-content">
74
+ ${h}
75
+ <h3 class="ax-ad-title">${n.title}</h3>
76
+ ${n.body ? `<p class="ax-ad-body">${n.body}</p>` : ""}
65
77
  ${u}
66
- <h3 class="ax-ad-title">${s.title}</h3>
67
- ${s.body ? `<p class="ax-ad-body">${s.body}</p>` : ""}
68
- ${l}
69
78
  <div class="ax-ad-footer">
70
79
  ${d}
71
80
  <a
72
- href="${r.clickUrl}"
81
+ href="${o}"
73
82
  class="ax-ad-cta"
74
83
  target="_blank"
75
84
  rel="sponsored noopener noreferrer"
76
85
  data-ad-id="${e.original.id}"
77
- data-impression-url="${r.impressionUrl}"
86
+ data-impression-url="${a}"
78
87
  >
79
- ${s.ctaText || "Learn More"}
88
+ ${this.getCtaText(e)}
80
89
  </a>
81
90
  </div>
82
91
  </div>
83
- `, p = n ? "</div>" : "";
84
- return a + f + p;
92
+ `, f = s ? "</div>" : "";
93
+ return c + p + f;
85
94
  }
86
95
  /**
87
96
  * Render Suffix ad as HTML string
@@ -90,21 +99,21 @@ class b {
90
99
  * @returns HTML string
91
100
  */
92
101
  static renderSuffixAd(e) {
93
- const t = e.adapted, i = e.tracking;
102
+ const t = e.adapted, i = this.getClickUrl(e), s = this.getImpressionUrl(e);
94
103
  return `
95
104
  <div class="ax-ad-suffix" data-ad-id="${e.original.id}">
96
105
  <div class="ax-ad-suffix-content">
97
106
  ${t.title ? `<h4 class="ax-ad-suffix-title">${t.title}</h4>` : ""}
98
107
  ${t.body ? `<p class="ax-ad-suffix-body">${t.body}</p>` : ""}
99
108
  <a
100
- href="${i.clickUrl}"
109
+ href="${i}"
101
110
  class="ax-ad-suffix-link"
102
111
  target="_blank"
103
112
  rel="sponsored noopener noreferrer"
104
113
  data-ad-id="${e.original.id}"
105
- data-impression-url="${i.impressionUrl}"
114
+ data-impression-url="${s}"
106
115
  >
107
- ${t.ctaText || "Learn More"}
116
+ ${this.getCtaText(e)}
108
117
  </a>
109
118
  </div>
110
119
  </div>
@@ -118,16 +127,16 @@ class b {
118
127
  */
119
128
  static renderSponsoredSource(e) {
120
129
  var n;
121
- const t = e.adapted, i = e.tracking;
130
+ const t = e.adapted, i = this.getClickUrl(e), s = this.getImpressionUrl(e);
122
131
  return `
123
132
  <div class="ax-ad-source" data-ad-id="${e.original.id}">
124
133
  <a
125
- href="${i.clickUrl}"
134
+ href="${i}"
126
135
  class="ax-ad-source-link"
127
136
  target="_blank"
128
137
  rel="sponsored noopener noreferrer"
129
138
  data-ad-id="${e.original.id}"
130
- data-impression-url="${i.impressionUrl}"
139
+ data-impression-url="${s}"
131
140
  >
132
141
  ${(n = t.image) != null && n.url ? `<img src="${t.image.url}" alt="" class="ax-ad-source-icon" />` : ""}
133
142
  <div class="ax-ad-source-info">
@@ -146,21 +155,21 @@ class b {
146
155
  * @returns HTML string
147
156
  */
148
157
  static renderLeadGenAd(e) {
149
- const t = e.adapted, i = e.tracking;
158
+ const t = e.adapted, i = this.getClickUrl(e), s = this.getImpressionUrl(e);
150
159
  return `
151
160
  <div class="ax-ad-leadgen" data-ad-id="${e.original.id}">
152
161
  <div class="ax-ad-leadgen-content">
153
162
  ${t.title ? `<h3 class="ax-ad-leadgen-title">${t.title}</h3>` : ""}
154
163
  ${t.body ? `<p class="ax-ad-leadgen-body">${t.body}</p>` : ""}
155
164
  <a
156
- href="${i.clickUrl}"
165
+ href="${i}"
157
166
  class="ax-ad-leadgen-cta"
158
167
  target="_blank"
159
168
  rel="sponsored noopener noreferrer"
160
169
  data-ad-id="${e.original.id}"
161
- data-impression-url="${i.impressionUrl}"
170
+ data-impression-url="${s}"
162
171
  >
163
- ${t.ctaText || "Get Started"}
172
+ ${this.getCtaText(e)}
164
173
  </a>
165
174
  </div>
166
175
  </div>
@@ -173,21 +182,25 @@ class b {
173
182
  * @param renderFn - Render function to use
174
183
  * @returns HTML string with all ads
175
184
  */
176
- static renderAds(e, t = b.renderActionCard.bind(b)) {
185
+ static renderAds(e, t = w.renderActionCard.bind(w)) {
177
186
  return e.map(t).join(`
178
187
  `);
179
188
  }
180
189
  }
181
190
  const q = "ad_session_id";
182
- function B() {
191
+ function L() {
183
192
  if (typeof window < "u") {
184
- const o = window.__AD_CONFIG__;
185
- if (o != null && o.apiKey)
186
- return o.apiKey;
193
+ const r = window.__AD_CONFIG__;
194
+ if (r != null && r.apiKey)
195
+ return r.apiKey;
187
196
  }
188
197
  }
189
- function M(o) {
190
- if (o) return o;
198
+ function R() {
199
+ var r;
200
+ return typeof window < "u" ? !!((r = window.__AD_CONFIG__) != null && r.debug) : !1;
201
+ }
202
+ function U(r) {
203
+ if (r) return r;
191
204
  if (typeof window < "u") {
192
205
  const e = window.__AD_CONFIG__;
193
206
  if (e != null && e.apiBaseUrl)
@@ -195,7 +208,7 @@ function M(o) {
195
208
  }
196
209
  return "/api/v1";
197
210
  }
198
- class _ {
211
+ class P {
199
212
  constructor(e = {}) {
200
213
  this.memoryCache = /* @__PURE__ */ new Map(), this.sessionKey = e.sessionKey || q, this.storage = e.storage || "sessionStorage", (typeof window > "u" || typeof window.sessionStorage > "u") && (this.storage = "memory");
201
214
  }
@@ -231,8 +244,8 @@ class _ {
231
244
  this.storage === "sessionStorage" ? sessionStorage.removeItem(this.sessionKey) : this.memoryCache.delete(this.sessionKey);
232
245
  }
233
246
  }
234
- const L = new _(), m = () => L.getSessionId();
235
- class P {
247
+ const K = new P(), y = () => K.getSessionId();
248
+ class x {
236
249
  constructor(e = {}) {
237
250
  this.explicitBaseUrl = e.baseUrl, this.timeout = e.timeout || 1e4, this.retryAttempts = e.retryAttempts ?? 2, this.retryDelay = e.retryDelay || 1e3, this.debug = e.debug || !1;
238
251
  }
@@ -241,7 +254,7 @@ class P {
241
254
  */
242
255
  async trackImpression(e) {
243
256
  return this.sendRequest(
244
- `${M(this.explicitBaseUrl)}/ads/impression`,
257
+ `${U(this.explicitBaseUrl)}/ads/impression`,
245
258
  e,
246
259
  "impression"
247
260
  );
@@ -251,7 +264,7 @@ class P {
251
264
  */
252
265
  async trackClick(e) {
253
266
  return this.sendRequest(
254
- `${M(this.explicitBaseUrl)}/ads/click`,
267
+ `${U(this.explicitBaseUrl)}/ads/click`,
255
268
  e,
256
269
  "click"
257
270
  );
@@ -261,29 +274,31 @@ class P {
261
274
  * 自动添加 X-API-Key header
262
275
  */
263
276
  async sendRequest(e, t, i) {
264
- let n = null;
265
- for (let s = 0; s <= this.retryAttempts; s++)
277
+ let s = null;
278
+ for (let n = 0; n <= this.retryAttempts; n++) {
279
+ const o = this.debug || R();
266
280
  try {
267
- this.debug && console.log(`[Analytics] Sending ${i} event (attempt ${s + 1}):`, t);
268
- const r = new AbortController(), a = setTimeout(() => r.abort(), this.timeout), c = {
281
+ o && (console.log(`[Analytics] Request URL (${i}):`, e), console.log(`[Analytics] Sending ${i} event (attempt ${n + 1}):`, t));
282
+ const a = new AbortController(), c = setTimeout(() => a.abort(), this.timeout), l = {
269
283
  "Content-Type": "application/json"
270
- }, d = B();
271
- d && (c["X-API-Key"] = d, this.debug && console.log(`[Analytics] Adding X-API-Key header for ${i} event`));
272
- const l = await fetch(e, {
284
+ }, d = L();
285
+ d && (l["X-API-Key"] = d, o && console.log(`[Analytics] Adding X-API-Key header for ${i} event`));
286
+ const u = await fetch(e, {
273
287
  method: "POST",
274
- headers: c,
288
+ headers: l,
275
289
  body: JSON.stringify(t),
276
290
  keepalive: !0,
277
- signal: r.signal
291
+ signal: a.signal
278
292
  });
279
- if (clearTimeout(a), !l.ok)
280
- throw new Error(`HTTP ${l.status}: ${l.statusText}`);
281
- const u = await l.json();
282
- return this.debug && console.log(`[Analytics] ${i} event tracked successfully:`, u), u;
283
- } catch (r) {
284
- n = r, this.debug && console.warn(`[Analytics] ${i} tracking failed (attempt ${s + 1}):`, r), s < this.retryAttempts && await this.delay(this.retryDelay * (s + 1));
293
+ if (clearTimeout(c), !u.ok)
294
+ throw new Error(`HTTP ${u.status}: ${u.statusText}`);
295
+ const h = await u.json();
296
+ return o && console.log(`[Analytics] ${i} event tracked successfully:`, h), h;
297
+ } catch (a) {
298
+ s = a, o && console.warn(`[Analytics] ${i} tracking failed (attempt ${n + 1}):`, a), n < this.retryAttempts && await this.delay(this.retryDelay * (n + 1));
285
299
  }
286
- return console.error(`[Analytics] ${i} tracking failed after ${this.retryAttempts + 1} attempts:`, n), null;
300
+ }
301
+ return console.error(`[Analytics] ${i} tracking failed after ${this.retryAttempts + 1} attempts:`, s), null;
287
302
  }
288
303
  /**
289
304
  * 延迟辅助方法
@@ -292,145 +307,161 @@ class P {
292
307
  return new Promise((t) => setTimeout(t, e));
293
308
  }
294
309
  }
295
- const U = new P(), A = (o) => U.trackImpression(o), S = (o) => U.trackClick(o);
296
- function F(o, e) {
297
- return `vt_${o}_${e}`;
310
+ const O = new x(), I = (r, e) => e != null && e.baseUrl ? new x({ baseUrl: e.baseUrl }).trackImpression(r) : O.trackImpression(r), T = (r, e) => e != null && e.baseUrl ? new x({ baseUrl: e.baseUrl }).trackClick(r) : O.trackClick(r);
311
+ function G(r, e) {
312
+ return `vt_${r}_${e}`;
298
313
  }
299
- async function G(o) {
300
- return Promise.all(o.map((e) => A(e)));
314
+ async function j(r) {
315
+ return Promise.all(r.map((e) => I(e)));
301
316
  }
302
- async function D(o) {
303
- return Promise.all(o.map((e) => S(e)));
317
+ async function z(r) {
318
+ return Promise.all(r.map((e) => T(e)));
304
319
  }
305
- function j(o) {
306
- const e = new P(o);
320
+ function W(r) {
321
+ const e = new x(r);
307
322
  return {
308
323
  trackImpression: (t) => e.trackImpression(t),
309
324
  trackClick: (t) => e.trackClick(t)
310
325
  };
311
326
  }
312
- function z(o = {}) {
313
- const e = new _(o);
327
+ function Q(r = {}) {
328
+ const e = new P(r);
314
329
  return {
315
330
  getSessionId: () => e.getSessionId(),
316
331
  regenerateSessionId: () => e.regenerateSessionId(),
317
332
  clearSessionId: () => e.clearSessionId()
318
333
  };
319
334
  }
320
- const I = class I {
335
+ const C = class C {
336
+ static isDebugEnabled() {
337
+ var e;
338
+ return typeof window < "u" ? !!((e = window.__AD_CONFIG__) != null && e.debug) : !1;
339
+ }
340
+ static getClickUrl(e) {
341
+ return e.tracking.clickUrl || e.tracking.click_url || "";
342
+ }
343
+ static getViewToken(e) {
344
+ return e.tracking.viewToken || e.tracking.view_token;
345
+ }
321
346
  /**
322
347
  * Render Action Card ad into container
323
348
  */
324
349
  static renderActionCard(e, t, i = {}) {
325
- t.innerHTML = b.renderActionCard(e, i);
326
- const n = t.querySelector(".ax-ad-cta");
327
- return n && n.addEventListener("click", (s) => {
328
- s.preventDefault(), this.handleClick(e, i);
350
+ t.innerHTML = w.renderActionCard(e, i);
351
+ const s = t.querySelector(".ax-ad-cta");
352
+ return s && s.addEventListener("click", (n) => {
353
+ n.preventDefault(), this.handleClick(e, i);
329
354
  }), this.trackImpression(e, t, i), t;
330
355
  }
331
356
  /**
332
357
  * Render Suffix ad into container
333
358
  */
334
359
  static renderSuffixAd(e, t, i = {}) {
335
- const n = i.variant || "block";
336
- t.innerHTML = this.generateSuffixAdHTML(e, n);
337
- const s = t.querySelector(".ax-ad-suffix-link");
338
- return s && s.addEventListener("click", (r) => {
339
- r.preventDefault(), this.handleClick(e, i);
360
+ const s = i.variant || "block";
361
+ t.innerHTML = this.generateSuffixAdHTML(e, s);
362
+ const n = t.querySelector(".ax-ad-suffix-link");
363
+ return n && n.addEventListener("click", (o) => {
364
+ o.preventDefault(), this.handleClick(e, i);
340
365
  }), this.trackImpression(e, t, i), t;
341
366
  }
342
367
  /**
343
368
  * Render Sponsored Source ad into container
344
369
  */
345
370
  static renderSponsoredSource(e, t, i = {}) {
346
- const n = i.variant || "card";
347
- t.innerHTML = this.generateSponsoredSourceHTML(e, n);
348
- const s = t.querySelector(".ax-ad-source-link");
349
- return s && s.addEventListener("click", (r) => {
350
- r.preventDefault(), this.handleClick(e, i);
371
+ const s = i.variant || "card";
372
+ t.innerHTML = this.generateSponsoredSourceHTML(e, s);
373
+ const n = t.querySelector(".ax-ad-source-link");
374
+ return n && n.addEventListener("click", (o) => {
375
+ o.preventDefault(), this.handleClick(e, i);
351
376
  }), this.trackImpression(e, t, i), t;
352
377
  }
353
378
  /**
354
379
  * Render Lead Gen ad into container
355
380
  */
356
381
  static renderLeadGenAd(e, t, i = {}) {
357
- t.innerHTML = b.renderLeadGenAd(e);
358
- const n = t.querySelector(".ax-ad-leadgen-cta");
359
- return n && n.addEventListener("click", (s) => {
360
- s.preventDefault(), this.handleClick(e, i);
382
+ t.innerHTML = w.renderLeadGenAd(e);
383
+ const s = t.querySelector(".ax-ad-leadgen-cta");
384
+ return s && s.addEventListener("click", (n) => {
385
+ n.preventDefault(), this.handleClick(e, i);
361
386
  }), this.trackImpression(e, t, i), t;
362
387
  }
363
388
  /**
364
389
  * Render multiple ads into container
365
390
  */
366
- static renderAds(e, t, i = this.renderActionCard.bind(this), n) {
391
+ static renderAds(e, t, i = this.renderActionCard.bind(this), s) {
367
392
  t.innerHTML = "";
368
- const s = document.createElement("div");
369
- return s.className = "ax-ads-container", e.forEach((r) => {
393
+ const n = document.createElement("div");
394
+ return n.className = "ax-ads-container", e.forEach((o) => {
370
395
  const a = document.createElement("div");
371
- a.className = "ax-ad-wrapper", i.call(this, r, a, n), s.appendChild(a);
372
- }), t.appendChild(s), t;
396
+ a.className = "ax-ad-wrapper", i.call(this, o, a, s), n.appendChild(a);
397
+ }), t.appendChild(n), t;
373
398
  }
374
399
  /**
375
400
  * Handle ad click
376
401
  * First tracks the click (async, non-blocking), then opens the URL.
377
402
  */
378
403
  static handleClick(e, t) {
379
- const { analytics: i, onClick: n } = t;
380
- n && n(e), i && S({
404
+ const { analytics: i, onClick: s } = t, n = this.getClickUrl(e);
405
+ if (!n) {
406
+ console.warn("[DOMRenderer] Missing click url for ad:", e.original.id);
407
+ return;
408
+ }
409
+ s && s(e), i && T({
381
410
  requestId: i.requestId,
382
411
  adId: e.original.id,
383
- destinationUrl: e.tracking.clickUrl,
412
+ destinationUrl: n,
384
413
  slotId: i.slotId,
385
- sessionId: m(),
414
+ sessionId: y(),
386
415
  adTitle: e.adapted.title,
387
- format: e.original.type
388
- }).catch((s) => {
389
- console.error("[DOMRenderer] Analytics click tracking failed:", s);
390
- }), window.open(e.tracking.clickUrl, "_blank", "noopener,noreferrer");
416
+ format: e.original.type,
417
+ userId: i.userId
418
+ }, { baseUrl: i.apiBaseUrl }).catch((o) => {
419
+ console.error("[DOMRenderer] Analytics click tracking failed:", o);
420
+ }), this.isDebugEnabled() && console.log("[DOMRenderer] Redirect URL:", n), window.open(n, "_blank", "noopener,noreferrer");
391
421
  }
392
422
  /**
393
423
  * Track ad impression using IntersectionObserver (50% visible + 1000ms delay)
394
424
  * Falls back to immediate tracking if IntersectionObserver is unavailable.
395
425
  */
396
426
  static trackImpression(e, t, i) {
397
- const { analytics: n, onImpression: s } = i, r = n ? `${n.requestId}:${n.slotId}:${e.original.id}:${e.tracking.viewToken || ""}` : `no-analytics:${e.original.id}:${e.tracking.viewToken || ""}`;
398
- if (this.trackedImpressionKeys.has(r))
427
+ const { analytics: s, onImpression: n } = i, o = s ? `${s.requestId}:${s.slotId}:${e.original.id}:${this.getViewToken(e) || ""}` : `no-analytics:${e.original.id}:${this.getViewToken(e) || ""}`;
428
+ if (this.trackedImpressionKeys.has(o))
399
429
  return;
400
430
  let a = !1;
401
431
  const c = () => {
402
- a || this.trackedImpressionKeys.has(r) || (a = !0, this.trackedImpressionKeys.add(r), d());
403
- }, d = () => {
404
- n ? A({
405
- requestId: n.requestId,
432
+ a || this.trackedImpressionKeys.has(o) || (a = !0, this.trackedImpressionKeys.add(o), l());
433
+ }, l = () => {
434
+ s ? I({
435
+ requestId: s.requestId,
406
436
  adId: e.original.id,
407
- slotId: n.slotId,
408
- position: n.position,
409
- totalAds: n.totalAds,
410
- sessionId: m(),
437
+ slotId: s.slotId,
438
+ position: s.position,
439
+ totalAds: s.totalAds,
440
+ sessionId: y(),
411
441
  adTitle: e.adapted.title,
412
442
  format: e.original.type,
413
443
  source: "internal",
414
- viewToken: e.tracking.viewToken
415
- }).then(() => {
416
- s && s(e);
417
- }).catch((l) => {
418
- console.error("[DOMRenderer] Analytics impression tracking failed:", l);
419
- }) : s && s(e);
444
+ viewToken: this.getViewToken(e),
445
+ userId: s.userId
446
+ }, { baseUrl: s.apiBaseUrl }).then(() => {
447
+ n && n(e);
448
+ }).catch((d) => {
449
+ console.error("[DOMRenderer] Analytics impression tracking failed:", d);
450
+ }) : n && n(e);
420
451
  };
421
452
  if (typeof IntersectionObserver < "u") {
422
- let l = !1, u = null;
423
- const f = new IntersectionObserver(
424
- (h) => {
425
- h.forEach((w) => {
426
- l = w.isIntersecting && w.intersectionRatio >= 0.5, l ? u || (u = setTimeout(() => {
427
- u = null, l && (c(), f.disconnect());
453
+ let d = !1, u = null;
454
+ const h = new IntersectionObserver(
455
+ (f) => {
456
+ f.forEach((m) => {
457
+ d = m.isIntersecting && m.intersectionRatio >= 0.5, d ? u || (u = setTimeout(() => {
458
+ u = null, d && (c(), h.disconnect());
428
459
  }, 1e3)) : u && (clearTimeout(u), u = null);
429
460
  });
430
461
  },
431
462
  { threshold: 0.5 }
432
463
  ), p = t.querySelector(`[data-ad-id="${e.original.id}"]`) || t;
433
- f.observe(p);
464
+ h.observe(p);
434
465
  } else
435
466
  c();
436
467
  }
@@ -438,7 +469,7 @@ const I = class I {
438
469
  * Generate HTML for Suffix Ad variants
439
470
  */
440
471
  static generateSuffixAdHTML(e, t) {
441
- const i = e.adapted.title || "", n = e.adapted.body || "";
472
+ const i = e.adapted.title || "", s = e.adapted.body || "";
442
473
  return t === "inline" ? `
443
474
  <span class="ax-ad-suffix-link ax-ad-variant-inline" data-ad-id="${e.original.id}">
444
475
  ${i}
@@ -461,7 +492,7 @@ const I = class I {
461
492
  </svg>
462
493
  </div>
463
494
  </div>
464
- ${n ? `<p class="ax-ad-suffix-body">${n}</p>` : ""}
495
+ ${s ? `<p class="ax-ad-suffix-body">${s}</p>` : ""}
465
496
  </div>
466
497
  `;
467
498
  }
@@ -469,11 +500,11 @@ const I = class I {
469
500
  * Generate HTML for Sponsored Source Ad variants
470
501
  */
471
502
  static generateSponsoredSourceHTML(e, t) {
472
- var r;
473
- const i = e.adapted.title || "", n = e.adapted.body || "", s = ((r = e.adapted.image) == null ? void 0 : r.url) || "";
503
+ var o;
504
+ const i = e.adapted.title || "", s = e.adapted.body || "", n = ((o = e.adapted.image) == null ? void 0 : o.url) || "";
474
505
  return t === "list-item" ? `
475
506
  <div class="ax-ad-source ax-ad-variant-list-item" data-ad-id="${e.original.id}">
476
- ${s ? `<img src="${s}" alt="${i}" loading="lazy" />` : ""}
507
+ ${n ? `<img src="${n}" alt="${i}" loading="lazy" />` : ""}
477
508
  <div class="ax-ad-source-info">
478
509
  <span class="ax-ad-source-name">${i}</span>
479
510
  <span class="ax-ad-sponsored-badge" style="font-size:9px">Ad</span>
@@ -485,20 +516,20 @@ const I = class I {
485
516
  ` : t === "minimal" ? `
486
517
  <div data-ad-id="${e.original.id}" style="display:inline-flex">
487
518
  <a class="ax-ad-source-link ax-ad-variant-minimal">
488
- ${s ? `<img src="${s}" alt="${i}" loading="lazy" style="width:16px;height:16px;border-radius:2px;object-fit:cover" />` : ""}
519
+ ${n ? `<img src="${n}" alt="${i}" loading="lazy" style="width:16px;height:16px;border-radius:2px;object-fit:cover" />` : ""}
489
520
  <span>${i}</span>
490
521
  <span class="ax-ad-sponsored-badge" style="font-size:9px">Ad</span>
491
522
  </a>
492
523
  </div>
493
524
  ` : `
494
525
  <div class="ax-ad-source ax-ad-variant-card" data-ad-id="${e.original.id}">
495
- ${s ? `<img src="${s}" alt="${i}" loading="lazy" style="width:48px;height:48px;border-radius:6px;object-fit:cover;flex-shrink:0" />` : ""}
526
+ ${n ? `<img src="${n}" alt="${i}" loading="lazy" style="width:48px;height:48px;border-radius:6px;object-fit:cover;flex-shrink:0" />` : ""}
496
527
  <div class="ax-ad-source-info">
497
528
  <div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">
498
529
  <span class="ax-ad-source-name">${i}</span>
499
530
  <span class="ax-ad-sponsored-badge">Sponsored</span>
500
531
  </div>
501
- ${n ? `<p class="ax-ad-source-desc">${n}</p>` : ""}
532
+ ${s ? `<p class="ax-ad-source-desc">${s}</p>` : ""}
502
533
  </div>
503
534
  <svg width="16" height="16" fill="none" stroke="#d1d5db" viewBox="0 0 24 24" style="flex-shrink:0">
504
535
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
@@ -507,9 +538,9 @@ const I = class I {
507
538
  `;
508
539
  }
509
540
  };
510
- I.trackedImpressionKeys = /* @__PURE__ */ new Set();
511
- let y = I;
512
- class T {
541
+ C.trackedImpressionKeys = /* @__PURE__ */ new Set();
542
+ let b = C;
543
+ class S {
513
544
  constructor() {
514
545
  this.cachedStaticInfo = null, this.cacheTimestamp = 0, this.CACHE_TTL = 36e5;
515
546
  }
@@ -524,13 +555,13 @@ class T {
524
555
  name: "Unknown App",
525
556
  publisher: { id: "unknown" }
526
557
  };
527
- const e = this.inferBundle(), t = this.inferAppName(), i = this.inferAppVersion(), n = this.inferPublisherId();
558
+ const e = this.inferBundle(), t = this.inferAppName(), i = this.inferAppVersion(), s = this.inferPublisherId();
528
559
  return {
529
560
  bundle: e,
530
561
  ver: i,
531
562
  name: t,
532
563
  publisher: {
533
- id: n,
564
+ id: s,
534
565
  domain: window.location.hostname
535
566
  }
536
567
  };
@@ -548,14 +579,14 @@ class T {
548
579
  * 自动推断应用名称
549
580
  */
550
581
  inferAppName() {
551
- var n, s;
582
+ var s, n;
552
583
  if (typeof document > "u") return "Unknown App";
553
584
  const e = document.title;
554
585
  if (e && e !== "Loading..." && e.length < 100)
555
586
  return e;
556
- const t = (n = document.querySelector('meta[property="og:title"]')) == null ? void 0 : n.getAttribute("content");
587
+ const t = (s = document.querySelector('meta[property="og:title"]')) == null ? void 0 : s.getAttribute("content");
557
588
  if (t) return t;
558
- const i = (s = document.querySelector('meta[name="application-name"]')) == null ? void 0 : s.getAttribute("content");
589
+ const i = (n = document.querySelector('meta[name="application-name"]')) == null ? void 0 : n.getAttribute("content");
559
590
  return i || "Unknown App";
560
591
  }
561
592
  /**
@@ -575,8 +606,8 @@ class T {
575
606
  if (i) {
576
607
  if (t.includes("manifest"))
577
608
  return "1.0.0";
578
- const n = i.getAttribute("content");
579
- if (n) return n;
609
+ const s = i.getAttribute("content");
610
+ if (s) return s;
580
611
  }
581
612
  }
582
613
  return "1.0.0";
@@ -585,18 +616,18 @@ class T {
585
616
  * 自动推断publisher ID
586
617
  */
587
618
  inferPublisherId() {
588
- var i, n;
619
+ var i, s;
589
620
  if (typeof document > "u") return "unknown";
590
621
  const e = (i = document.querySelector('meta[name="publisher-id"]')) == null ? void 0 : i.getAttribute("content");
591
622
  if (e) return e;
592
- const t = (n = window.location) == null ? void 0 : n.hostname;
623
+ const t = (s = window.location) == null ? void 0 : s.hostname;
593
624
  return t ? t.replace(/\./g, "_") : "unknown";
594
625
  }
595
626
  /**
596
627
  * Get singleton instance
597
628
  */
598
629
  static getInstance() {
599
- return this.instance || (this.instance = new T()), this.instance;
630
+ return this.instance || (this.instance = new S()), this.instance;
600
631
  }
601
632
  /**
602
633
  * Collect all available client information
@@ -677,7 +708,7 @@ class T {
677
708
  collectUserInfo() {
678
709
  let e;
679
710
  try {
680
- e = localStorage.getItem("chatbox_user_id") || "", e || (e = this.generateUUID(), localStorage.setItem("chatbox_user_id", e));
711
+ e = localStorage.getItem("actionx_user_id") || "", e || (e = this.generateUUID(), localStorage.setItem("actionx_user_id", e));
681
712
  } catch {
682
713
  e = this.generateUUID();
683
714
  }
@@ -718,11 +749,11 @@ class T {
718
749
  const i = e.match(/Android (\d+)\.(\d+)/);
719
750
  if (i)
720
751
  return `${i[1]}.${i[2]}`;
721
- const n = e.match(/Windows NT (\d+\.\d+)/);
722
- if (n)
723
- return n[1];
724
- const s = e.match(/Mac OS X (\d+[._]\d+)/);
725
- return s ? s[1].replace("_", ".") : "Unknown";
752
+ const s = e.match(/Windows NT (\d+\.\d+)/);
753
+ if (s)
754
+ return s[1];
755
+ const n = e.match(/Mac OS X (\d+[._]\d+)/);
756
+ return n ? n[1].replace("_", ".") : "Unknown";
726
757
  }
727
758
  /**
728
759
  * Detect Device Type (OpenRTB standard)
@@ -747,13 +778,13 @@ class T {
747
778
  const i = e.match(/Samsung-.*(SM-\w+)/);
748
779
  if (i) return i[1];
749
780
  if (/Pixel/.test(e)) return "Google Pixel";
750
- const n = e.match(/(BARC-|HUAWEI-)?([A-Z]{2}\-\w{4})/);
751
- if (n) return n[2];
752
- const s = e.match(/(MI|Redmi|POCO)\s([\w\s]+)/);
753
- if (s) return s[1] + " " + s[2];
781
+ const s = e.match(/(BARC-|HUAWEI-)?([A-Z]{2}\-\w{4})/);
782
+ if (s) return s[2];
783
+ const n = e.match(/(MI|Redmi|POCO)\s([\w\s]+)/);
784
+ if (n) return n[1] + " " + n[2];
754
785
  if (/OnePlus/.test(e)) {
755
- const r = e.match(/OnePlus\s([A-Z\d]+)/);
756
- return r ? "OnePlus " + r[1] : "OnePlus";
786
+ const o = e.match(/OnePlus\s([A-Z\d]+)/);
787
+ return o ? "OnePlus " + o[1] : "OnePlus";
757
788
  }
758
789
  }
759
790
  /**
@@ -866,9 +897,9 @@ class T {
866
897
  if (t && i[t])
867
898
  return i[t];
868
899
  if (e) {
869
- const n = e.split("-")[1];
870
- if (n)
871
- return n.toUpperCase();
900
+ const s = e.split("-")[1];
901
+ if (s)
902
+ return s.toUpperCase();
872
903
  }
873
904
  }
874
905
  /**
@@ -899,101 +930,105 @@ class T {
899
930
  this.cachedStaticInfo = null, this.cacheTimestamp = 0;
900
931
  }
901
932
  }
902
- const $ = () => T.getInstance();
903
- function v(o) {
904
- return $().collect(o);
933
+ const $ = () => S.getInstance();
934
+ function v(r) {
935
+ return $().collect(r);
905
936
  }
906
- function W() {
937
+ function J() {
907
938
  return v().device;
908
939
  }
909
- function K() {
940
+ function N() {
910
941
  return v().user;
911
942
  }
912
- function Q() {
943
+ function X() {
913
944
  return v().app;
914
945
  }
915
- function J() {
946
+ function Z() {
916
947
  return v().geo;
917
948
  }
918
- function X() {
919
- return K().id;
949
+ function Y() {
950
+ return N().id;
920
951
  }
921
- function Z() {
952
+ function ee() {
922
953
  $().clearCache();
923
954
  }
924
- function Y(o) {
925
- const e = v(o);
955
+ function te(r) {
956
+ const e = v(r);
926
957
  return JSON.stringify(e, null, 2);
927
958
  }
928
- function ee() {
959
+ function ie() {
929
960
  var t;
930
- const o = v();
961
+ const r = v();
931
962
  return [
932
- o.device.os,
933
- o.device.osv,
934
- o.app.name,
935
- o.user.id.slice(0, 8) + "...",
936
- ((t = o.geo) == null ? void 0 : t.country) || "Unknown"
963
+ r.device.os,
964
+ r.device.osv,
965
+ r.app.name,
966
+ r.user.id.slice(0, 8) + "...",
967
+ ((t = r.geo) == null ? void 0 : t.country) || "Unknown"
937
968
  ].join(" / ");
938
969
  }
939
- function te(o) {
970
+ function M() {
971
+ var r;
972
+ return typeof window < "u" ? !!((r = window.__AD_CONFIG__) != null && r.debug) : !1;
973
+ }
974
+ function se(r) {
940
975
  var e, t;
941
976
  return {
942
- id: o.original.id,
943
- type: o.original.type,
944
- score: o.original.score,
977
+ id: r.original.id,
978
+ type: r.original.type,
979
+ score: r.original.score,
945
980
  source: "internal",
946
981
  // Default source
947
982
  content: {
948
- title: o.adapted.title,
949
- body: o.adapted.body,
950
- image: (e = o.adapted.image) == null ? void 0 : e.url,
951
- cta_text: o.adapted.ctaText,
952
- price: (t = o.adapted.price) == null ? void 0 : t.display,
953
- rating: o.adapted.rating,
954
- brand: o.adapted.brand
983
+ title: r.adapted.title,
984
+ body: r.adapted.body,
985
+ image: (e = r.adapted.image) == null ? void 0 : e.url,
986
+ cta_text: r.adapted.ctaText,
987
+ price: (t = r.adapted.price) == null ? void 0 : t.display,
988
+ rating: r.adapted.rating,
989
+ brand: r.adapted.brand
955
990
  },
956
991
  tracking: {
957
- click_url: o.tracking.clickUrl,
958
- impression_url: o.tracking.impressionUrl
992
+ click_url: r.tracking.clickUrl || r.tracking.click_url || "",
993
+ impression_url: r.tracking.impressionUrl || r.tracking.impression_url || ""
959
994
  },
960
995
  metadata: {
961
- viewToken: o.tracking.viewToken,
962
- styling: o.adapted.styling
996
+ viewToken: r.tracking.viewToken || r.tracking.view_token,
997
+ styling: r.adapted.styling
963
998
  }
964
999
  };
965
1000
  }
966
- async function R(o, e = {}) {
967
- const t = e.apiBaseUrl || "/api/v1", n = $().collect(), s = {
968
- ...o,
969
- clientInfo: n
1001
+ async function D(r, e = {}) {
1002
+ const t = e.apiBaseUrl || "/api/v1", s = $().collect(), n = {
1003
+ ...r,
1004
+ clientInfo: s
970
1005
  // Auto-injected
971
- }, r = {
1006
+ }, o = {
972
1007
  "Content-Type": "application/json"
973
1008
  };
974
- e.apiKey && (r["X-API-Key"] = e.apiKey);
1009
+ e.apiKey && (o["X-API-Key"] = e.apiKey), M() && (console.log("[fetchAds] Request URL:", `${t}/ads/request`), console.log("[fetchAds] Request params:", r), console.log("[fetchAds] Request body:", n));
975
1010
  const a = await fetch(`${t}/ads/request`, {
976
1011
  method: "POST",
977
- headers: r,
978
- body: JSON.stringify(s)
1012
+ headers: o,
1013
+ body: JSON.stringify(n)
979
1014
  });
980
1015
  if (!a.ok)
981
1016
  throw new Error(`Ad request failed: ${a.status} ${a.statusText}`);
982
1017
  const c = await a.json();
983
- if (!c.success)
1018
+ if (M() && console.log("[fetchAds] Response:", c), !c.success)
984
1019
  throw new Error(c.error || "Ad request failed");
985
1020
  return c.data;
986
1021
  }
987
- const N = { width: 400, height: 200 }, x = {
1022
+ const H = { width: 400, height: 200 }, A = {
988
1023
  variant: "horizontal",
989
1024
  count: 1,
990
1025
  preferences: {}
991
1026
  };
992
- function C(o = {}) {
1027
+ function _(r = {}) {
993
1028
  const e = {
994
- variant: o.variant ?? x.variant,
995
- count: o.count ?? x.count,
996
- preferences: { ...x.preferences, ...o.preferences }
1029
+ variant: r.variant ?? A.variant,
1030
+ count: r.count ?? A.count,
1031
+ preferences: { ...A.preferences, ...r.preferences }
997
1032
  };
998
1033
  return [
999
1034
  {
@@ -1001,7 +1036,7 @@ function C(o = {}) {
1001
1036
  slotName: "Action Card",
1002
1037
  format: "action_card",
1003
1038
  variant: e.variant,
1004
- size: N,
1039
+ size: H,
1005
1040
  count: e.count,
1006
1041
  preferences: e.preferences,
1007
1042
  placement: { position: "below_fold", context: "post_response" }
@@ -1010,10 +1045,11 @@ function C(o = {}) {
1010
1045
  }
1011
1046
  const g = class g {
1012
1047
  constructor(e) {
1013
- this.slots = {}, this.isLoading = !1, this.currentRequestId = null, this.adsAnalyticsMap = /* @__PURE__ */ new Map(), this.config = e, this.enabled = e.enabled !== !1, this.eventBus = new O(), this.slots_config = C(e.cardOption), typeof window < "u" && (window.__AD_CONFIG__ = {
1048
+ this.slots = {}, this.isLoading = !1, this.currentRequestId = null, this.adsAnalyticsMap = /* @__PURE__ */ new Map(), this.config = e, this.enabled = e.enabled !== !1, this.eventBus = new B(), this.slots_config = _(e.cardOption), typeof window < "u" && (window.__AD_CONFIG__ = {
1014
1049
  ...window.__AD_CONFIG__ || {},
1015
1050
  apiKey: e.apiKey,
1016
- apiBaseUrl: e.apiBaseUrl
1051
+ apiBaseUrl: e.apiBaseUrl,
1052
+ debug: !!e.debug
1017
1053
  }), this.config.debug && console.log("[AdManager] Initialized with config:", {
1018
1054
  apiBaseUrl: e.apiBaseUrl,
1019
1055
  hasApiKey: !!e.apiKey,
@@ -1021,20 +1057,23 @@ const g = class g {
1021
1057
  });
1022
1058
  }
1023
1059
  async requestAds(e) {
1024
- const t = "conversationContext" in e ? e : { conversationContext: e }, i = this.buildRequestKey(t), n = g.inFlightRequests.get(i);
1025
- if (n)
1026
- return this.config.debug && console.log("[AdManager] Reusing in-flight request for identical context"), n;
1060
+ var o;
1061
+ const t = "conversationContext" in e ? e : { conversationContext: e };
1062
+ this.currentUserId = (o = t.userContext) == null ? void 0 : o.userId;
1063
+ const i = this.buildRequestKey(t), s = g.inFlightRequests.get(i);
1064
+ if (s)
1065
+ return this.config.debug && console.log("[AdManager] Reusing in-flight request for identical context"), s;
1027
1066
  if (!this.enabled)
1028
1067
  throw this.config.debug && console.warn("[AdManager] Ads are disabled, skipping request"), new Error("Ads are disabled");
1029
1068
  if (this.isLoading)
1030
1069
  throw this.config.debug && console.warn("[AdManager] Request already in progress"), new Error("Request already in progress");
1031
1070
  this.isLoading = !0, this.eventBus.emit("adsLoading"), this.config.debug && console.log("[AdManager] Starting ad request...");
1032
- const s = (async () => {
1071
+ const n = (async () => {
1033
1072
  try {
1034
- const r = await R(
1073
+ const a = await D(
1035
1074
  {
1036
1075
  conversationContext: t.conversationContext,
1037
- userContext: t.userContext ? { ...t.userContext, sessionId: t.userContext.sessionId ?? m() } : { sessionId: m() },
1076
+ userContext: t.userContext ? { ...t.userContext, sessionId: t.userContext.sessionId ?? y() } : { sessionId: y() },
1038
1077
  slots: this.slots_config
1039
1078
  },
1040
1079
  {
@@ -1042,32 +1081,34 @@ const g = class g {
1042
1081
  apiKey: this.config.apiKey
1043
1082
  }
1044
1083
  );
1045
- this.currentRequestId = r.requestId, this.adsAnalyticsMap.clear(), r.slots.forEach((c) => {
1046
- c.ads.forEach((d, l) => {
1047
- const u = d.original.id;
1048
- this.adsAnalyticsMap.set(u, {
1049
- requestId: r.requestId,
1050
- slotId: c.slotId,
1051
- position: l,
1052
- totalAds: c.ads.length
1084
+ this.currentRequestId = a.requestId, this.adsAnalyticsMap.clear(), a.slots.forEach((l) => {
1085
+ l.ads.forEach((d, u) => {
1086
+ const h = d.original.id;
1087
+ this.adsAnalyticsMap.set(h, {
1088
+ requestId: a.requestId,
1089
+ slotId: l.slotId,
1090
+ position: u,
1091
+ totalAds: l.ads.length,
1092
+ apiBaseUrl: this.config.apiBaseUrl,
1093
+ userId: this.currentUserId
1053
1094
  });
1054
1095
  });
1055
1096
  });
1056
- const a = {};
1057
- return r.slots.forEach((c) => {
1058
- a[c.slotId] = c;
1059
- }), this.slots = a, this.eventBus.emit("adsUpdated", this.slots), this.config.debug && console.log("[AdManager] Ads received:", {
1097
+ const c = {};
1098
+ return a.slots.forEach((l) => {
1099
+ c[l.slotId] = l;
1100
+ }), this.slots = c, this.eventBus.emit("adsUpdated", this.slots), this.config.debug && console.log("[AdManager] Ads received:", {
1060
1101
  slotCount: Object.keys(this.slots).length,
1061
1102
  slots: Object.keys(this.slots)
1062
- }), r;
1063
- } catch (r) {
1064
- const a = r;
1065
- throw this.eventBus.emit("adsError", a), a;
1103
+ }), a;
1104
+ } catch (a) {
1105
+ const c = a;
1106
+ throw this.eventBus.emit("adsError", c), c;
1066
1107
  } finally {
1067
1108
  this.isLoading = !1, g.inFlightRequests.delete(i);
1068
1109
  }
1069
1110
  })();
1070
- return g.inFlightRequests.set(i, s), s;
1111
+ return g.inFlightRequests.set(i, n), n;
1071
1112
  }
1072
1113
  buildRequestKey(e) {
1073
1114
  return JSON.stringify({
@@ -1079,24 +1120,24 @@ const g = class g {
1079
1120
  });
1080
1121
  }
1081
1122
  render(e, t, i = {}) {
1082
- const n = typeof e != "string", s = n ? g.DEFAULT_SLOT_ID : e, r = n ? e : t, a = (n ? t : i) || {};
1083
- if (!r)
1123
+ const s = typeof e != "string", n = s ? g.DEFAULT_SLOT_ID : e, o = s ? e : t, a = (s ? t : i) || {};
1124
+ if (!o)
1084
1125
  return this.config.debug && console.warn("[AdManager] Render container is required"), null;
1085
- const c = this.slots[s];
1126
+ const c = this.slots[n];
1086
1127
  if (!c || !c.ads || c.ads.length === 0)
1087
- return this.config.debug && console.warn("[AdManager] No ads in slot:", s), null;
1088
- const d = a.adIndex ?? 0, l = c.ads[d];
1089
- if (!l)
1090
- return this.config.debug && console.warn(`[AdManager] Ad at index ${d} not found in slot:`, s), null;
1091
- const u = this.adsAnalyticsMap.get(l.original.id), f = this.slots_config.find((w) => w.slotId === s), p = (f == null ? void 0 : f.format) || "action_card";
1092
- r.innerHTML = "";
1093
- const h = {
1128
+ return this.config.debug && console.warn("[AdManager] No ads in slot:", n), null;
1129
+ const l = a.adIndex ?? 0, d = c.ads[l];
1130
+ if (!d)
1131
+ return this.config.debug && console.warn(`[AdManager] Ad at index ${l} not found in slot:`, n), null;
1132
+ const u = this.adsAnalyticsMap.get(d.original.id), h = this.slots_config.find((m) => m.slotId === n), p = (h == null ? void 0 : h.format) || "action_card";
1133
+ o.innerHTML = "";
1134
+ const f = {
1094
1135
  analytics: u,
1095
1136
  variant: a.variant,
1096
1137
  onClick: a.onClick,
1097
1138
  onImpression: a.onImpression
1098
1139
  };
1099
- return p === "suffix" ? y.renderSuffixAd(l, r, h) : p === "source" ? y.renderSponsoredSource(l, r, h) : p === "lead_gen" ? y.renderLeadGenAd(l, r, h) : y.renderActionCard(l, r, h);
1140
+ return p === "suffix" ? b.renderSuffixAd(d, o, f) : p === "source" ? b.renderSponsoredSource(d, o, f) : p === "lead_gen" ? b.renderLeadGenAd(d, o, f) : b.renderActionCard(d, o, f);
1100
1141
  }
1101
1142
  /**
1102
1143
  * Get ad slots data
@@ -1135,7 +1176,7 @@ const g = class g {
1135
1176
  * Update configuration
1136
1177
  */
1137
1178
  updateConfig(e) {
1138
- this.config = { ...this.config, ...e }, e.cardOption !== void 0 && (this.slots_config = C(this.config.cardOption)), this.config.debug && console.log("[AdManager] Config updated:", e);
1179
+ this.config = { ...this.config, ...e }, e.cardOption !== void 0 && (this.slots_config = _(this.config.cardOption)), this.config.debug && console.log("[AdManager] Config updated:", e);
1139
1180
  }
1140
1181
  /**
1141
1182
  * Clear all slot data
@@ -1179,28 +1220,29 @@ const g = class g {
1179
1220
  getAdsAnalytics(e) {
1180
1221
  const t = /* @__PURE__ */ new Map();
1181
1222
  return e.forEach((i) => {
1182
- const n = this.adsAnalyticsMap.get(i);
1183
- n && t.set(i, n);
1223
+ const s = this.adsAnalyticsMap.get(i);
1224
+ s && t.set(i, s);
1184
1225
  }), t;
1185
1226
  }
1186
1227
  /**
1187
1228
  * Track ad click using Analytics API
1188
1229
  */
1189
1230
  async trackAdClick(e, t, i) {
1190
- const n = this.adsAnalyticsMap.get(e);
1191
- if (!n || !this.currentRequestId)
1231
+ const s = this.adsAnalyticsMap.get(e);
1232
+ if (!s || !this.currentRequestId)
1192
1233
  return this.config.debug && console.warn("[AdManager] No analytics info for ad:", e), null;
1193
- const s = m(), r = await S({
1234
+ const n = y(), o = await T({
1194
1235
  requestId: this.currentRequestId,
1195
1236
  adId: e,
1196
1237
  destinationUrl: t,
1197
- sessionId: s,
1198
- slotId: n.slotId,
1238
+ sessionId: n,
1239
+ slotId: s.slotId,
1199
1240
  adTitle: i == null ? void 0 : i.title,
1200
1241
  format: i == null ? void 0 : i.format,
1201
- source: i == null ? void 0 : i.source
1202
- });
1203
- return r && (this.eventBus.emit("adClicked", e, n.slotId), this.config.debug && console.log("[AdManager] Click tracked via Analytics API:", r.eventId)), r;
1242
+ source: i == null ? void 0 : i.source,
1243
+ userId: s.userId ?? this.currentUserId
1244
+ }, { baseUrl: s.apiBaseUrl });
1245
+ return o && (this.eventBus.emit("adClicked", e, s.slotId), this.config.debug && console.log("[AdManager] Click tracked via Analytics API:", o.eventId)), o;
1204
1246
  }
1205
1247
  /**
1206
1248
  * Track ad impression using Analytics API
@@ -1209,19 +1251,20 @@ const g = class g {
1209
1251
  const i = this.adsAnalyticsMap.get(e);
1210
1252
  if (!i || !this.currentRequestId)
1211
1253
  return this.config.debug && console.warn("[AdManager] No analytics info for ad:", e), null;
1212
- const n = m(), s = await A({
1254
+ const s = y(), n = await I({
1213
1255
  requestId: this.currentRequestId,
1214
1256
  adId: e,
1215
1257
  slotId: i.slotId,
1216
1258
  position: i.position,
1217
1259
  totalAds: i.totalAds,
1218
- sessionId: n,
1260
+ sessionId: s,
1219
1261
  adTitle: t == null ? void 0 : t.title,
1220
1262
  format: t == null ? void 0 : t.format,
1221
1263
  source: t == null ? void 0 : t.source,
1222
- viewToken: t == null ? void 0 : t.viewToken
1223
- });
1224
- return s && (this.eventBus.emit("adImpression", e, i.slotId), this.config.debug && console.log("[AdManager] Impression tracked via Analytics API:", s.eventId)), s;
1264
+ viewToken: t == null ? void 0 : t.viewToken,
1265
+ userId: i.userId ?? this.currentUserId
1266
+ }, { baseUrl: i.apiBaseUrl });
1267
+ return n && (this.eventBus.emit("adImpression", e, i.slotId), this.config.debug && console.log("[AdManager] Impression tracked via Analytics API:", n.eventId)), n;
1225
1268
  }
1226
1269
  /**
1227
1270
  * Destroy the manager and clean up
@@ -1234,21 +1277,21 @@ g.DEFAULT_SLOT_ID = "action_card", g.inFlightRequests = /* @__PURE__ */ new Map(
1234
1277
  let V = g;
1235
1278
  function E() {
1236
1279
  if (typeof window < "u") {
1237
- const o = window.__AD_CONFIG__;
1238
- if (o != null && o.apiKey)
1239
- return o.apiKey;
1280
+ const r = window.__AD_CONFIG__;
1281
+ if (r != null && r.apiKey)
1282
+ return r.apiKey;
1240
1283
  }
1241
1284
  }
1242
- class H {
1285
+ class F {
1243
1286
  constructor(e = {}, t = "/api/v1") {
1244
- var i, n;
1287
+ var i, s;
1245
1288
  this.observers = /* @__PURE__ */ new Map(), this.metrics = /* @__PURE__ */ new Map(), this.timers = /* @__PURE__ */ new Map(), this.batchTimers = /* @__PURE__ */ new Map(), this.eventQueue = /* @__PURE__ */ new Map(), this.isTracking = /* @__PURE__ */ new Map(), this.config = {
1246
1289
  minVisiblePercentage: e.minVisiblePercentage ?? 50,
1247
1290
  minViewableDuration: e.minViewableDuration ?? 1e3,
1248
1291
  maxTrackingDuration: e.maxTrackingDuration ?? 6e4,
1249
1292
  batchConfig: {
1250
1293
  maxBatchSize: ((i = e.batchConfig) == null ? void 0 : i.maxBatchSize) ?? 5,
1251
- maxBatchWaitMs: ((n = e.batchConfig) == null ? void 0 : n.maxBatchWaitMs) ?? 1e4
1294
+ maxBatchWaitMs: ((s = e.batchConfig) == null ? void 0 : s.maxBatchWaitMs) ?? 1e4
1252
1295
  },
1253
1296
  debug: e.debug ?? !1
1254
1297
  }, this.baseUrl = t;
@@ -1256,13 +1299,13 @@ class H {
1256
1299
  /**
1257
1300
  * Start tracking viewability for an ad element
1258
1301
  */
1259
- startTracking(e, t, i, n, s) {
1302
+ startTracking(e, t, i, s, n) {
1260
1303
  if (this.isTracking.get(e)) {
1261
1304
  this.log(`[ViewabilityTracker] Already tracking ${e}, skipping`);
1262
1305
  return;
1263
1306
  }
1264
1307
  this.log(`[ViewabilityTracker] Starting tracking for ${e}`);
1265
- const r = {
1308
+ const o = {
1266
1309
  visiblePercentage: 0,
1267
1310
  maxVisiblePercentage: 0,
1268
1311
  totalVisibleTimeMs: 0,
@@ -1272,16 +1315,16 @@ class H {
1272
1315
  enteredViewportAt: null,
1273
1316
  enterCount: 0
1274
1317
  };
1275
- this.metrics.set(e, r), this.isTracking.set(e, !0), this.eventQueue.set(e, []);
1318
+ this.metrics.set(e, o), this.isTracking.set(e, !0), this.eventQueue.set(e, []);
1276
1319
  const a = new IntersectionObserver(
1277
- (d) => this.handleIntersection(e, d[0], i, n, s),
1320
+ (l) => this.handleIntersection(e, l[0], i, s, n),
1278
1321
  {
1279
1322
  threshold: this.createThresholds()
1280
1323
  }
1281
1324
  );
1282
- a.observe(t), this.observers.set(e, a), this.startMonitoring(e, i, n, s);
1325
+ a.observe(t), this.observers.set(e, a), this.startMonitoring(e, i, s, n);
1283
1326
  const c = setTimeout(() => {
1284
- this.endTracking(e, i, n, s);
1327
+ this.endTracking(e, i, s, n);
1285
1328
  }, this.config.maxTrackingDuration);
1286
1329
  this.timers.set(e, c);
1287
1330
  }
@@ -1301,59 +1344,59 @@ class H {
1301
1344
  * Handle IntersectionObserver callback
1302
1345
  * Event-driven: Only process when state actually changes
1303
1346
  */
1304
- handleIntersection(e, t, i, n, s) {
1305
- const r = this.metrics.get(e);
1306
- if (!r || !this.isTracking.get(e)) return;
1307
- const a = r.isViewable, c = Math.round(t.intersectionRatio * 100);
1308
- r.visiblePercentage = c, r.maxVisiblePercentage = Math.max(r.maxVisiblePercentage, c);
1309
- const d = Date.now(), l = c >= this.config.minVisiblePercentage;
1310
- if (l && !r.enteredViewportAt && (r.enteredViewportAt = d, r.enterCount++, this.log(`[ViewabilityTracker] ${e} entered viewport at ${d}`), this.queueEvent(e, {
1347
+ handleIntersection(e, t, i, s, n) {
1348
+ const o = this.metrics.get(e);
1349
+ if (!o || !this.isTracking.get(e)) return;
1350
+ const a = o.isViewable, c = Math.round(t.intersectionRatio * 100);
1351
+ o.visiblePercentage = c, o.maxVisiblePercentage = Math.max(o.maxVisiblePercentage, c);
1352
+ const l = Date.now(), d = c >= this.config.minVisiblePercentage;
1353
+ if (d && !o.enteredViewportAt && (o.enteredViewportAt = l, o.enterCount++, this.log(`[ViewabilityTracker] ${e} entered viewport at ${l}`), this.queueEvent(e, {
1311
1354
  adId: e,
1312
1355
  sessionId: i,
1313
- requestId: n,
1314
- viewToken: s,
1356
+ requestId: s,
1357
+ viewToken: n,
1315
1358
  eventType: "enter_viewport",
1316
1359
  visiblePercentage: c,
1317
- maxVisiblePercentage: r.maxVisiblePercentage,
1318
- totalVisibleTimeMs: r.totalVisibleTimeMs,
1360
+ maxVisiblePercentage: o.maxVisiblePercentage,
1361
+ totalVisibleTimeMs: o.totalVisibleTimeMs,
1319
1362
  isViewable: !1,
1320
- timestamp: d
1321
- })), !l && r.enteredViewportAt) {
1322
- const u = d - r.enteredViewportAt;
1323
- r.totalVisibleTimeMs += u, r.enteredViewportAt = null, r.currentVisibleTimeMs = 0, this.log(`[ViewabilityTracker] ${e} exited viewport, total visible: ${r.totalVisibleTimeMs}ms`), this.queueEvent(e, {
1363
+ timestamp: l
1364
+ })), !d && o.enteredViewportAt) {
1365
+ const u = l - o.enteredViewportAt;
1366
+ o.totalVisibleTimeMs += u, o.enteredViewportAt = null, o.currentVisibleTimeMs = 0, this.log(`[ViewabilityTracker] ${e} exited viewport, total visible: ${o.totalVisibleTimeMs}ms`), this.queueEvent(e, {
1324
1367
  adId: e,
1325
1368
  sessionId: i,
1326
- requestId: n,
1327
- viewToken: s,
1369
+ requestId: s,
1370
+ viewToken: n,
1328
1371
  eventType: "exit_viewport",
1329
1372
  visiblePercentage: c,
1330
- maxVisiblePercentage: r.maxVisiblePercentage,
1331
- totalVisibleTimeMs: r.totalVisibleTimeMs,
1332
- isViewable: r.isViewable,
1333
- timestamp: d
1373
+ maxVisiblePercentage: o.maxVisiblePercentage,
1374
+ totalVisibleTimeMs: o.totalVisibleTimeMs,
1375
+ isViewable: o.isViewable,
1376
+ timestamp: l
1334
1377
  });
1335
1378
  }
1336
- r.isViewable !== a && r.isViewable && this.log(`[ViewabilityTracker] ${e} became VIEWABLE!`), this.metrics.set(e, r);
1379
+ o.isViewable !== a && o.isViewable && this.log(`[ViewabilityTracker] ${e} became VIEWABLE!`), this.metrics.set(e, o);
1337
1380
  }
1338
1381
  /**
1339
1382
  * Start monitoring loop for tracking duration
1340
1383
  * Runs every 100ms to track continuous visible time
1341
1384
  */
1342
- startMonitoring(e, t, i, n) {
1343
- const r = setInterval(() => {
1385
+ startMonitoring(e, t, i, s) {
1386
+ const o = setInterval(() => {
1344
1387
  const a = this.metrics.get(e);
1345
1388
  if (!a || !this.isTracking.get(e)) {
1346
- clearInterval(r);
1389
+ clearInterval(o);
1347
1390
  return;
1348
1391
  }
1349
- const c = Date.now(), d = a.isViewable;
1392
+ const c = Date.now(), l = a.isViewable;
1350
1393
  if (a.enteredViewportAt) {
1351
- const l = c - a.enteredViewportAt;
1352
- a.currentVisibleTimeMs = l, l >= this.config.minViewableDuration && a.visiblePercentage >= this.config.minVisiblePercentage && (a.isViewable = !0, d || (a.viewableAt = a.enteredViewportAt, this.log(`[ViewabilityTracker] ${e} BECAME VIEWABLE at ${a.viewableAt}`), this.queueEvent(e, {
1394
+ const d = c - a.enteredViewportAt;
1395
+ a.currentVisibleTimeMs = d, d >= this.config.minViewableDuration && a.visiblePercentage >= this.config.minVisiblePercentage && (a.isViewable = !0, l || (a.viewableAt = a.enteredViewportAt, this.log(`[ViewabilityTracker] ${e} BECAME VIEWABLE at ${a.viewableAt}`), this.queueEvent(e, {
1353
1396
  adId: e,
1354
1397
  sessionId: t,
1355
1398
  requestId: i,
1356
- viewToken: n,
1399
+ viewToken: s,
1357
1400
  eventType: "become_viewable",
1358
1401
  visiblePercentage: a.visiblePercentage,
1359
1402
  maxVisiblePercentage: a.maxVisiblePercentage,
@@ -1364,29 +1407,29 @@ class H {
1364
1407
  }
1365
1408
  a.enteredViewportAt && (a.totalVisibleTimeMs += 100), this.metrics.set(e, a);
1366
1409
  }, 100);
1367
- this.timers.set(`${e}_monitoring`, r);
1410
+ this.timers.set(`${e}_monitoring`, o);
1368
1411
  }
1369
1412
  /**
1370
1413
  * Queue an event to be sent (batched)
1371
1414
  */
1372
1415
  queueEvent(e, t) {
1373
- var s, r;
1416
+ var n, o;
1374
1417
  const i = this.eventQueue.get(e);
1375
1418
  if (!i) {
1376
1419
  this.log(`[ViewabilityTracker] No queue found for ${e}, skipping event`);
1377
1420
  return;
1378
1421
  }
1379
1422
  i.push(t), this.log(`[ViewabilityTracker] Queued ${t.eventType} for ${e} (queue size: ${i.length})`);
1380
- const n = ((s = this.config.batchConfig) == null ? void 0 : s.maxBatchSize) ?? 5;
1381
- if (i.length >= n)
1423
+ const s = ((n = this.config.batchConfig) == null ? void 0 : n.maxBatchSize) ?? 5;
1424
+ if (i.length >= s)
1382
1425
  this.flushQueue(e);
1383
1426
  else {
1384
1427
  const a = this.batchTimers.get(e);
1385
1428
  a && clearTimeout(a);
1386
- const c = ((r = this.config.batchConfig) == null ? void 0 : r.maxBatchWaitMs) ?? 1e4, d = setTimeout(() => {
1429
+ const c = ((o = this.config.batchConfig) == null ? void 0 : o.maxBatchWaitMs) ?? 1e4, l = setTimeout(() => {
1387
1430
  this.flushQueue(e);
1388
1431
  }, c);
1389
- this.batchTimers.set(e, d);
1432
+ this.batchTimers.set(e, l);
1390
1433
  }
1391
1434
  }
1392
1435
  /**
@@ -1398,37 +1441,37 @@ class H {
1398
1441
  const i = [...t];
1399
1442
  t.length = 0, this.log(`[ViewabilityTracker] Flushing ${i.length} events for ${e}`);
1400
1443
  try {
1401
- const n = {
1444
+ const s = {
1402
1445
  "Content-Type": "application/json"
1403
- }, s = E();
1404
- s && (n["x-api-key"] = s), await fetch(`${this.baseUrl}/ads/viewability/batch`, {
1446
+ }, n = E();
1447
+ n && (s["x-api-key"] = n), await fetch(`${this.baseUrl}/ads/viewability/batch`, {
1405
1448
  method: "POST",
1406
- headers: n,
1449
+ headers: s,
1407
1450
  body: JSON.stringify({ events: i })
1408
1451
  }), this.log(`[ViewabilityTracker] Successfully sent ${i.length} events for ${e}`);
1409
- } catch (n) {
1410
- this.log(`[ViewabilityTracker] Failed to send events for ${e}:`, n), t.unshift(...i);
1452
+ } catch (s) {
1453
+ this.log(`[ViewabilityTracker] Failed to send events for ${e}:`, s), t.unshift(...i);
1411
1454
  }
1412
1455
  }
1413
1456
  /**
1414
1457
  * End tracking and send final metrics
1415
1458
  */
1416
- endTracking(e, t, i, n) {
1417
- const s = this.metrics.get(e);
1418
- if (!s) return;
1459
+ endTracking(e, t, i, s) {
1460
+ const n = this.metrics.get(e);
1461
+ if (!n) return;
1419
1462
  this.log(`[ViewabilityTracker] Ending tracking for ${e}`), this.flushQueue(e);
1420
- const r = Date.now();
1463
+ const o = Date.now();
1421
1464
  this.queueEvent(e, {
1422
1465
  adId: e,
1423
1466
  sessionId: t,
1424
1467
  requestId: i,
1425
- viewToken: n,
1468
+ viewToken: s,
1426
1469
  eventType: "end_tracking",
1427
- visiblePercentage: s.visiblePercentage,
1428
- maxVisiblePercentage: s.maxVisiblePercentage,
1429
- totalVisibleTimeMs: s.totalVisibleTimeMs,
1430
- isViewable: s.isViewable,
1431
- timestamp: r
1470
+ visiblePercentage: n.visiblePercentage,
1471
+ maxVisiblePercentage: n.maxVisiblePercentage,
1472
+ totalVisibleTimeMs: n.totalVisibleTimeMs,
1473
+ isViewable: n.isViewable,
1474
+ timestamp: o
1432
1475
  }), this.flushQueue(e), this.cleanup(e);
1433
1476
  }
1434
1477
  /**
@@ -1439,10 +1482,10 @@ class H {
1439
1482
  t && (t.disconnect(), this.observers.delete(e));
1440
1483
  const i = this.timers.get(e);
1441
1484
  i && (clearTimeout(i), this.timers.delete(e));
1442
- const n = this.timers.get(`${e}_monitoring`);
1443
- n && (clearInterval(n), this.timers.delete(`${e}_monitoring`));
1444
- const s = this.batchTimers.get(e);
1445
- s && (clearTimeout(s), this.batchTimers.delete(e)), this.flushQueue(e), this.isTracking.delete(e), this.metrics.delete(e), this.eventQueue.delete(e);
1485
+ const s = this.timers.get(`${e}_monitoring`);
1486
+ s && (clearInterval(s), this.timers.delete(`${e}_monitoring`));
1487
+ const n = this.batchTimers.get(e);
1488
+ n && (clearTimeout(n), this.batchTimers.delete(e)), this.flushQueue(e), this.isTracking.delete(e), this.metrics.delete(e), this.eventQueue.delete(e);
1446
1489
  }
1447
1490
  /**
1448
1491
  * Create thresholds for IntersectionObserver
@@ -1474,8 +1517,8 @@ class H {
1474
1517
  if (t && t.length > 0) {
1475
1518
  const i = {
1476
1519
  "Content-Type": "application/json"
1477
- }, n = E();
1478
- n && (i["x-api-key"] = n), fetch(`${this.baseUrl}/ads/viewability/batch`, {
1520
+ }, s = E();
1521
+ s && (i["x-api-key"] = s), fetch(`${this.baseUrl}/ads/viewability/batch`, {
1479
1522
  method: "POST",
1480
1523
  headers: i,
1481
1524
  keepalive: !0,
@@ -1487,38 +1530,38 @@ class H {
1487
1530
  }
1488
1531
  }
1489
1532
  let k = null;
1490
- function ie(o, e) {
1491
- return k || (k = new H(o, e), k.setupBeforeUnload()), k;
1533
+ function ne(r, e) {
1534
+ return k || (k = new F(r, e), k.setupBeforeUnload()), k;
1492
1535
  }
1493
- const ne = "0.1.0";
1536
+ const re = "0.1.0";
1494
1537
  export {
1495
1538
  V as AdManager,
1496
- P as AnalyticsSender,
1497
- T as ClientInfoCollector,
1498
- y as DOMRenderer,
1499
- b as HTMLRenderer,
1500
- ne as SDK_VERSION,
1501
- _ as SessionManager,
1502
- H as ViewabilityTracker,
1503
- te as adaptAdToKoahAd,
1504
- Z as clearClientInfoCache,
1505
- j as createAnalytics,
1506
- z as createSession,
1507
- R as fetchAds,
1508
- F as generateViewToken,
1509
- Q as getAppInfo,
1539
+ x as AnalyticsSender,
1540
+ S as ClientInfoCollector,
1541
+ b as DOMRenderer,
1542
+ w as HTMLRenderer,
1543
+ re as SDK_VERSION,
1544
+ P as SessionManager,
1545
+ F as ViewabilityTracker,
1546
+ se as adaptAdToKoahAd,
1547
+ ee as clearClientInfoCache,
1548
+ W as createAnalytics,
1549
+ Q as createSession,
1550
+ D as fetchAds,
1551
+ G as generateViewToken,
1552
+ X as getAppInfo,
1510
1553
  v as getClientInfo,
1511
1554
  $ as getClientInfoCollector,
1512
- Y as getClientInfoJSON,
1513
- ee as getClientInfoSummary,
1514
- W as getDeviceInfo,
1515
- J as getGeoInfo,
1516
- m as getSessionId,
1517
- X as getUserId,
1518
- K as getUserInfo,
1519
- ie as getViewabilityTracker,
1520
- S as trackAdClick,
1521
- A as trackAdImpression,
1522
- D as trackClicksBatch,
1523
- G as trackImpressionsBatch
1555
+ te as getClientInfoJSON,
1556
+ ie as getClientInfoSummary,
1557
+ J as getDeviceInfo,
1558
+ Z as getGeoInfo,
1559
+ y as getSessionId,
1560
+ Y as getUserId,
1561
+ N as getUserInfo,
1562
+ ne as getViewabilityTracker,
1563
+ T as trackAdClick,
1564
+ I as trackAdImpression,
1565
+ z as trackClicksBatch,
1566
+ j as trackImpressionsBatch
1524
1567
  };