@action-x/ad-sdk 0.1.3 → 0.1.5

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 P {
1
+ class B {
2
2
  constructor() {
3
3
  this.events = {};
4
4
  }
@@ -23,8 +23,8 @@ class P {
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,7 @@ class P {
42
42
  return ((t = this.events[e]) == null ? void 0 : t.length) || 0;
43
43
  }
44
44
  }
45
- class y {
45
+ class v {
46
46
  /**
47
47
  * Render Action Card ad as HTML string
48
48
  *
@@ -52,22 +52,22 @@ class y {
52
52
  */
53
53
  static renderActionCard(e, t = {}) {
54
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}"
55
+ const { variant: i = "horizontal", includeWrapper: s = !0 } = t, n = e.adapted, r = e.tracking, a = s ? `<div class="ax-ad-card ax-ad-card-${i}" data-ad-id="${e.original.id}">` : "", c = (h = n.image) != null && h.url ? `<img
56
+ src="${n.image.url}"
57
+ alt="${n.title}"
58
58
  class="ax-ad-image"
59
59
  loading="lazy"
60
- />` : "", l = s.price ? `<span class="ax-ad-price">${s.price.display || s.price.value}</span>` : "", d = 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>` : "", p = `
60
+ />` : "", d = n.price ? `<span class="ax-ad-price">${n.price.display || n.price.value}</span>` : "", l = n.rating ? `<div class="ax-ad-rating" aria-label="Rating: ${n.rating}">
61
+ ${"★".repeat(Math.floor(n.rating))}${"☆".repeat(5 - Math.floor(n.rating))}
62
+ </div>` : "", u = n.brand ? `<span class="ax-ad-brand">${n.brand}</span>` : "", f = `
63
63
  ${c}
64
64
  <div class="ax-ad-content">
65
65
  ${u}
66
- <h3 class="ax-ad-title">${s.title}</h3>
67
- ${s.body ? `<p class="ax-ad-body">${s.body}</p>` : ""}
68
- ${d}
66
+ <h3 class="ax-ad-title">${n.title}</h3>
67
+ ${n.body ? `<p class="ax-ad-body">${n.body}</p>` : ""}
68
+ ${l}
69
69
  <div class="ax-ad-footer">
70
- ${l}
70
+ ${d}
71
71
  <a
72
72
  href="${r.clickUrl}"
73
73
  class="ax-ad-cta"
@@ -76,12 +76,12 @@ class y {
76
76
  data-ad-id="${e.original.id}"
77
77
  data-impression-url="${r.impressionUrl}"
78
78
  >
79
- ${s.ctaText || "Learn More"}
79
+ ${n.ctaText || "Learn More"}
80
80
  </a>
81
81
  </div>
82
82
  </div>
83
- `, m = n ? "</div>" : "";
84
- return a + p + m;
83
+ `, p = s ? "</div>" : "";
84
+ return a + f + p;
85
85
  }
86
86
  /**
87
87
  * Render Suffix ad as HTML string
@@ -117,7 +117,7 @@ class y {
117
117
  * @returns HTML string
118
118
  */
119
119
  static renderSponsoredSource(e) {
120
- var n;
120
+ var s;
121
121
  const t = e.adapted, i = e.tracking;
122
122
  return `
123
123
  <div class="ax-ad-source" data-ad-id="${e.original.id}">
@@ -129,7 +129,7 @@ class y {
129
129
  data-ad-id="${e.original.id}"
130
130
  data-impression-url="${i.impressionUrl}"
131
131
  >
132
- ${(n = t.image) != null && n.url ? `<img src="${t.image.url}" alt="" class="ax-ad-source-icon" />` : ""}
132
+ ${(s = t.image) != null && s.url ? `<img src="${t.image.url}" alt="" class="ax-ad-source-icon" />` : ""}
133
133
  <div class="ax-ad-source-info">
134
134
  <span class="ax-ad-source-name">${t.title}</span>
135
135
  ${t.body ? `<span class="ax-ad-source-desc">${t.body}</span>` : ""}
@@ -173,20 +173,29 @@ class y {
173
173
  * @param renderFn - Render function to use
174
174
  * @returns HTML string with all ads
175
175
  */
176
- static renderAds(e, t = y.renderActionCard.bind(y)) {
176
+ static renderAds(e, t = v.renderActionCard.bind(v)) {
177
177
  return e.map(t).join(`
178
178
  `);
179
179
  }
180
180
  }
181
- const U = "/api/v1/ads", O = "ad_session_id";
182
- function L() {
181
+ const O = "ad_session_id";
182
+ function q() {
183
183
  if (typeof window < "u") {
184
184
  const o = window.__AD_CONFIG__;
185
185
  if (o != null && o.apiKey)
186
186
  return o.apiKey;
187
187
  }
188
188
  }
189
- class C {
189
+ function C(o) {
190
+ if (o) return o;
191
+ if (typeof window < "u") {
192
+ const e = window.__AD_CONFIG__;
193
+ if (e != null && e.apiBaseUrl)
194
+ return e.apiBaseUrl;
195
+ }
196
+ return "/api/v1";
197
+ }
198
+ class _ {
190
199
  constructor(e = {}) {
191
200
  this.memoryCache = /* @__PURE__ */ new Map(), this.sessionKey = e.sessionKey || O, this.storage = e.storage || "sessionStorage", (typeof window > "u" || typeof window.sessionStorage > "u") && (this.storage = "memory");
192
201
  }
@@ -222,17 +231,17 @@ class C {
222
231
  this.storage === "sessionStorage" ? sessionStorage.removeItem(this.sessionKey) : this.memoryCache.delete(this.sessionKey);
223
232
  }
224
233
  }
225
- const B = new C(), f = () => B.getSessionId();
226
- class V {
234
+ const L = new _(), m = () => L.getSessionId();
235
+ class x {
227
236
  constructor(e = {}) {
228
- this.baseUrl = e.baseUrl || U, this.timeout = e.timeout || 1e4, this.retryAttempts = e.retryAttempts ?? 2, this.retryDelay = e.retryDelay || 1e3, this.debug = e.debug || !1;
237
+ this.explicitBaseUrl = e.baseUrl, this.timeout = e.timeout || 1e4, this.retryAttempts = e.retryAttempts ?? 2, this.retryDelay = e.retryDelay || 1e3, this.debug = e.debug || !1;
229
238
  }
230
239
  /**
231
240
  * 发送广告展示事件
232
241
  */
233
242
  async trackImpression(e) {
234
243
  return this.sendRequest(
235
- `${this.baseUrl}/impression`,
244
+ `${C(this.explicitBaseUrl)}/ads/impression`,
236
245
  e,
237
246
  "impression"
238
247
  );
@@ -242,7 +251,7 @@ class V {
242
251
  */
243
252
  async trackClick(e) {
244
253
  return this.sendRequest(
245
- `${this.baseUrl}/click`,
254
+ `${C(this.explicitBaseUrl)}/ads/click`,
246
255
  e,
247
256
  "click"
248
257
  );
@@ -252,29 +261,29 @@ class V {
252
261
  * 自动添加 X-API-Key header
253
262
  */
254
263
  async sendRequest(e, t, i) {
255
- let n = null;
256
- for (let s = 0; s <= this.retryAttempts; s++)
264
+ let s = null;
265
+ for (let n = 0; n <= this.retryAttempts; n++)
257
266
  try {
258
- this.debug && console.log(`[Analytics] Sending ${i} event (attempt ${s + 1}):`, t);
267
+ this.debug && console.log(`[Analytics] Sending ${i} event (attempt ${n + 1}):`, t);
259
268
  const r = new AbortController(), a = setTimeout(() => r.abort(), this.timeout), c = {
260
269
  "Content-Type": "application/json"
261
- }, l = L();
262
- l && (c["X-API-Key"] = l, this.debug && console.log(`[Analytics] Adding X-API-Key header for ${i} event`));
263
- const d = await fetch(e, {
270
+ }, d = q();
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, {
264
273
  method: "POST",
265
274
  headers: c,
266
275
  body: JSON.stringify(t),
267
276
  keepalive: !0,
268
277
  signal: r.signal
269
278
  });
270
- if (clearTimeout(a), !d.ok)
271
- throw new Error(`HTTP ${d.status}: ${d.statusText}`);
272
- const u = await d.json();
279
+ if (clearTimeout(a), !l.ok)
280
+ throw new Error(`HTTP ${l.status}: ${l.statusText}`);
281
+ const u = await l.json();
273
282
  return this.debug && console.log(`[Analytics] ${i} event tracked successfully:`, u), u;
274
283
  } catch (r) {
275
- n = r, this.debug && console.warn(`[Analytics] ${i} tracking failed (attempt ${s + 1}):`, r), s < this.retryAttempts && await this.delay(this.retryDelay * (s + 1));
284
+ s = r, this.debug && console.warn(`[Analytics] ${i} tracking failed (attempt ${n + 1}):`, r), n < this.retryAttempts && await this.delay(this.retryDelay * (n + 1));
276
285
  }
277
- return console.error(`[Analytics] ${i} tracking failed after ${this.retryAttempts + 1} attempts:`, n), null;
286
+ return console.error(`[Analytics] ${i} tracking failed after ${this.retryAttempts + 1} attempts:`, s), null;
278
287
  }
279
288
  /**
280
289
  * 延迟辅助方法
@@ -283,50 +292,50 @@ class V {
283
292
  return new Promise((t) => setTimeout(t, e));
284
293
  }
285
294
  }
286
- const E = new V(), x = (o) => E.trackImpression(o), A = (o) => E.trackClick(o);
287
- function H(o, e) {
295
+ const P = new x(), S = (o, e) => e != null && e.baseUrl ? new x({ baseUrl: e.baseUrl }).trackImpression(o) : P.trackImpression(o), T = (o, e) => e != null && e.baseUrl ? new x({ baseUrl: e.baseUrl }).trackClick(o) : P.trackClick(o);
296
+ function F(o, e) {
288
297
  return `vt_${o}_${e}`;
289
298
  }
290
- async function D(o) {
291
- return Promise.all(o.map((e) => x(e)));
292
- }
293
299
  async function G(o) {
294
- return Promise.all(o.map((e) => A(e)));
300
+ return Promise.all(o.map((e) => S(e)));
295
301
  }
296
- function F(o) {
297
- const e = new V(o);
302
+ async function D(o) {
303
+ return Promise.all(o.map((e) => T(e)));
304
+ }
305
+ function j(o) {
306
+ const e = new x(o);
298
307
  return {
299
308
  trackImpression: (t) => e.trackImpression(t),
300
309
  trackClick: (t) => e.trackClick(t)
301
310
  };
302
311
  }
303
- function j(o = {}) {
304
- const e = new C(o);
312
+ function z(o = {}) {
313
+ const e = new _(o);
305
314
  return {
306
315
  getSessionId: () => e.getSessionId(),
307
316
  regenerateSessionId: () => e.regenerateSessionId(),
308
317
  clearSessionId: () => e.clearSessionId()
309
318
  };
310
319
  }
311
- class v {
320
+ const M = class M {
312
321
  /**
313
322
  * Render Action Card ad into container
314
323
  */
315
324
  static renderActionCard(e, t, i = {}) {
316
- t.innerHTML = y.renderActionCard(e, i);
317
- const n = t.querySelector(".ax-ad-cta");
318
- return n && n.addEventListener("click", (s) => {
319
- s.preventDefault(), this.handleClick(e, i);
325
+ t.innerHTML = v.renderActionCard(e, i);
326
+ const s = t.querySelector(".ax-ad-cta");
327
+ return s && s.addEventListener("click", (n) => {
328
+ n.preventDefault(), this.handleClick(e, i);
320
329
  }), this.trackImpression(e, t, i), t;
321
330
  }
322
331
  /**
323
332
  * Render Suffix ad into container
324
333
  */
325
334
  static renderSuffixAd(e, t, i = {}) {
326
- const n = i.variant || "block";
327
- t.innerHTML = this.generateSuffixAdHTML(e, n);
328
- const s = t.querySelector(".ax-ad-suffix-link");
329
- return s && s.addEventListener("click", (r) => {
335
+ const s = i.variant || "block";
336
+ t.innerHTML = this.generateSuffixAdHTML(e, s);
337
+ const n = t.querySelector(".ax-ad-suffix-link");
338
+ return n && n.addEventListener("click", (r) => {
330
339
  r.preventDefault(), this.handleClick(e, i);
331
340
  }), this.trackImpression(e, t, i), t;
332
341
  }
@@ -334,10 +343,10 @@ class v {
334
343
  * Render Sponsored Source ad into container
335
344
  */
336
345
  static renderSponsoredSource(e, t, i = {}) {
337
- const n = i.variant || "card";
338
- t.innerHTML = this.generateSponsoredSourceHTML(e, n);
339
- const s = t.querySelector(".ax-ad-source-link");
340
- return s && s.addEventListener("click", (r) => {
346
+ const s = i.variant || "card";
347
+ t.innerHTML = this.generateSponsoredSourceHTML(e, s);
348
+ const n = t.querySelector(".ax-ad-source-link");
349
+ return n && n.addEventListener("click", (r) => {
341
350
  r.preventDefault(), this.handleClick(e, i);
342
351
  }), this.trackImpression(e, t, i), t;
343
352
  }
@@ -345,39 +354,39 @@ class v {
345
354
  * Render Lead Gen ad into container
346
355
  */
347
356
  static renderLeadGenAd(e, t, i = {}) {
348
- t.innerHTML = y.renderLeadGenAd(e);
349
- const n = t.querySelector(".ax-ad-leadgen-cta");
350
- return n && n.addEventListener("click", (s) => {
351
- s.preventDefault(), this.handleClick(e, i);
357
+ t.innerHTML = v.renderLeadGenAd(e);
358
+ const s = t.querySelector(".ax-ad-leadgen-cta");
359
+ return s && s.addEventListener("click", (n) => {
360
+ n.preventDefault(), this.handleClick(e, i);
352
361
  }), this.trackImpression(e, t, i), t;
353
362
  }
354
363
  /**
355
364
  * Render multiple ads into container
356
365
  */
357
- static renderAds(e, t, i = this.renderActionCard.bind(this), n) {
366
+ static renderAds(e, t, i = this.renderActionCard.bind(this), s) {
358
367
  t.innerHTML = "";
359
- const s = document.createElement("div");
360
- return s.className = "ax-ads-container", e.forEach((r) => {
368
+ const n = document.createElement("div");
369
+ return n.className = "ax-ads-container", e.forEach((r) => {
361
370
  const a = document.createElement("div");
362
- a.className = "ax-ad-wrapper", i.call(this, r, a, n), s.appendChild(a);
363
- }), t.appendChild(s), t;
371
+ a.className = "ax-ad-wrapper", i.call(this, r, a, s), n.appendChild(a);
372
+ }), t.appendChild(n), t;
364
373
  }
365
374
  /**
366
375
  * Handle ad click
367
376
  * First tracks the click (async, non-blocking), then opens the URL.
368
377
  */
369
378
  static handleClick(e, t) {
370
- const { analytics: i, onClick: n } = t;
371
- n && n(e), i && A({
379
+ const { analytics: i, onClick: s } = t;
380
+ s && s(e), i && T({
372
381
  requestId: i.requestId,
373
382
  adId: e.original.id,
374
383
  destinationUrl: e.tracking.clickUrl,
375
384
  slotId: i.slotId,
376
- sessionId: f(),
385
+ sessionId: m(),
377
386
  adTitle: e.adapted.title,
378
387
  format: e.original.type
379
- }).catch((s) => {
380
- console.error("[DOMRenderer] Analytics click tracking failed:", s);
388
+ }, { baseUrl: i.apiBaseUrl }).catch((n) => {
389
+ console.error("[DOMRenderer] Analytics click tracking failed:", n);
381
390
  }), window.open(e.tracking.clickUrl, "_blank", "noopener,noreferrer");
382
391
  }
383
392
  /**
@@ -385,44 +394,51 @@ class v {
385
394
  * Falls back to immediate tracking if IntersectionObserver is unavailable.
386
395
  */
387
396
  static trackImpression(e, t, i) {
388
- const { analytics: n, onImpression: s } = i, r = () => {
389
- n ? x({
390
- requestId: n.requestId,
397
+ const { analytics: s, onImpression: n } = i, r = s ? `${s.requestId}:${s.slotId}:${e.original.id}:${e.tracking.viewToken || ""}` : `no-analytics:${e.original.id}:${e.tracking.viewToken || ""}`;
398
+ if (this.trackedImpressionKeys.has(r))
399
+ return;
400
+ let a = !1;
401
+ const c = () => {
402
+ a || this.trackedImpressionKeys.has(r) || (a = !0, this.trackedImpressionKeys.add(r), d());
403
+ }, d = () => {
404
+ s ? S({
405
+ requestId: s.requestId,
391
406
  adId: e.original.id,
392
- slotId: n.slotId,
393
- position: n.position,
394
- totalAds: n.totalAds,
395
- sessionId: f(),
407
+ slotId: s.slotId,
408
+ position: s.position,
409
+ totalAds: s.totalAds,
410
+ sessionId: m(),
396
411
  adTitle: e.adapted.title,
397
412
  format: e.original.type,
398
413
  source: "internal",
399
414
  viewToken: e.tracking.viewToken
400
- }).then(() => {
401
- s && s(e);
402
- }).catch((a) => {
403
- console.error("[DOMRenderer] Analytics impression tracking failed:", a);
404
- }) : s && s(e);
415
+ }, { baseUrl: s.apiBaseUrl }).then(() => {
416
+ n && n(e);
417
+ }).catch((l) => {
418
+ console.error("[DOMRenderer] Analytics impression tracking failed:", l);
419
+ }) : n && n(e);
405
420
  };
406
421
  if (typeof IntersectionObserver < "u") {
407
- const a = new IntersectionObserver(
408
- (l) => {
409
- l.forEach((d) => {
410
- d.isIntersecting && (setTimeout(() => {
411
- r();
412
- }, 1e3), a.disconnect());
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());
428
+ }, 1e3)) : u && (clearTimeout(u), u = null);
413
429
  });
414
430
  },
415
431
  { threshold: 0.5 }
416
- ), c = t.querySelector(`[data-ad-id="${e.original.id}"]`) || t;
417
- a.observe(c);
432
+ ), p = t.querySelector(`[data-ad-id="${e.original.id}"]`) || t;
433
+ f.observe(p);
418
434
  } else
419
- r();
435
+ c();
420
436
  }
421
437
  /**
422
438
  * Generate HTML for Suffix Ad variants
423
439
  */
424
440
  static generateSuffixAdHTML(e, t) {
425
- const i = e.adapted.title || "", n = e.adapted.body || "";
441
+ const i = e.adapted.title || "", s = e.adapted.body || "";
426
442
  return t === "inline" ? `
427
443
  <span class="ax-ad-suffix-link ax-ad-variant-inline" data-ad-id="${e.original.id}">
428
444
  ${i}
@@ -445,7 +461,7 @@ class v {
445
461
  </svg>
446
462
  </div>
447
463
  </div>
448
- ${n ? `<p class="ax-ad-suffix-body">${n}</p>` : ""}
464
+ ${s ? `<p class="ax-ad-suffix-body">${s}</p>` : ""}
449
465
  </div>
450
466
  `;
451
467
  }
@@ -454,10 +470,10 @@ class v {
454
470
  */
455
471
  static generateSponsoredSourceHTML(e, t) {
456
472
  var r;
457
- const i = e.adapted.title || "", n = e.adapted.body || "", s = ((r = e.adapted.image) == null ? void 0 : r.url) || "";
473
+ const i = e.adapted.title || "", s = e.adapted.body || "", n = ((r = e.adapted.image) == null ? void 0 : r.url) || "";
458
474
  return t === "list-item" ? `
459
475
  <div class="ax-ad-source ax-ad-variant-list-item" data-ad-id="${e.original.id}">
460
- ${s ? `<img src="${s}" alt="${i}" loading="lazy" />` : ""}
476
+ ${n ? `<img src="${n}" alt="${i}" loading="lazy" />` : ""}
461
477
  <div class="ax-ad-source-info">
462
478
  <span class="ax-ad-source-name">${i}</span>
463
479
  <span class="ax-ad-sponsored-badge" style="font-size:9px">Ad</span>
@@ -469,20 +485,20 @@ class v {
469
485
  ` : t === "minimal" ? `
470
486
  <div data-ad-id="${e.original.id}" style="display:inline-flex">
471
487
  <a class="ax-ad-source-link ax-ad-variant-minimal">
472
- ${s ? `<img src="${s}" alt="${i}" loading="lazy" style="width:16px;height:16px;border-radius:2px;object-fit:cover" />` : ""}
488
+ ${n ? `<img src="${n}" alt="${i}" loading="lazy" style="width:16px;height:16px;border-radius:2px;object-fit:cover" />` : ""}
473
489
  <span>${i}</span>
474
490
  <span class="ax-ad-sponsored-badge" style="font-size:9px">Ad</span>
475
491
  </a>
476
492
  </div>
477
493
  ` : `
478
494
  <div class="ax-ad-source ax-ad-variant-card" data-ad-id="${e.original.id}">
479
- ${s ? `<img src="${s}" alt="${i}" loading="lazy" style="width:48px;height:48px;border-radius:6px;object-fit:cover;flex-shrink:0" />` : ""}
495
+ ${n ? `<img src="${n}" alt="${i}" loading="lazy" style="width:48px;height:48px;border-radius:6px;object-fit:cover;flex-shrink:0" />` : ""}
480
496
  <div class="ax-ad-source-info">
481
497
  <div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">
482
498
  <span class="ax-ad-source-name">${i}</span>
483
499
  <span class="ax-ad-sponsored-badge">Sponsored</span>
484
500
  </div>
485
- ${n ? `<p class="ax-ad-source-desc">${n}</p>` : ""}
501
+ ${s ? `<p class="ax-ad-source-desc">${s}</p>` : ""}
486
502
  </div>
487
503
  <svg width="16" height="16" fill="none" stroke="#d1d5db" viewBox="0 0 24 24" style="flex-shrink:0">
488
504
  <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" />
@@ -490,8 +506,10 @@ class v {
490
506
  </div>
491
507
  `;
492
508
  }
493
- }
494
- class S {
509
+ };
510
+ M.trackedImpressionKeys = /* @__PURE__ */ new Set();
511
+ let y = M;
512
+ class $ {
495
513
  constructor() {
496
514
  this.cachedStaticInfo = null, this.cacheTimestamp = 0, this.CACHE_TTL = 36e5;
497
515
  }
@@ -506,13 +524,13 @@ class S {
506
524
  name: "Unknown App",
507
525
  publisher: { id: "unknown" }
508
526
  };
509
- const e = this.inferBundle(), t = this.inferAppName(), i = this.inferAppVersion(), n = this.inferPublisherId();
527
+ const e = this.inferBundle(), t = this.inferAppName(), i = this.inferAppVersion(), s = this.inferPublisherId();
510
528
  return {
511
529
  bundle: e,
512
530
  ver: i,
513
531
  name: t,
514
532
  publisher: {
515
- id: n,
533
+ id: s,
516
534
  domain: window.location.hostname
517
535
  }
518
536
  };
@@ -530,14 +548,14 @@ class S {
530
548
  * 自动推断应用名称
531
549
  */
532
550
  inferAppName() {
533
- var n, s;
551
+ var s, n;
534
552
  if (typeof document > "u") return "Unknown App";
535
553
  const e = document.title;
536
554
  if (e && e !== "Loading..." && e.length < 100)
537
555
  return e;
538
- const t = (n = document.querySelector('meta[property="og:title"]')) == null ? void 0 : n.getAttribute("content");
556
+ const t = (s = document.querySelector('meta[property="og:title"]')) == null ? void 0 : s.getAttribute("content");
539
557
  if (t) return t;
540
- const i = (s = document.querySelector('meta[name="application-name"]')) == null ? void 0 : s.getAttribute("content");
558
+ const i = (n = document.querySelector('meta[name="application-name"]')) == null ? void 0 : n.getAttribute("content");
541
559
  return i || "Unknown App";
542
560
  }
543
561
  /**
@@ -557,8 +575,8 @@ class S {
557
575
  if (i) {
558
576
  if (t.includes("manifest"))
559
577
  return "1.0.0";
560
- const n = i.getAttribute("content");
561
- if (n) return n;
578
+ const s = i.getAttribute("content");
579
+ if (s) return s;
562
580
  }
563
581
  }
564
582
  return "1.0.0";
@@ -567,18 +585,18 @@ class S {
567
585
  * 自动推断publisher ID
568
586
  */
569
587
  inferPublisherId() {
570
- var i, n;
588
+ var i, s;
571
589
  if (typeof document > "u") return "unknown";
572
590
  const e = (i = document.querySelector('meta[name="publisher-id"]')) == null ? void 0 : i.getAttribute("content");
573
591
  if (e) return e;
574
- const t = (n = window.location) == null ? void 0 : n.hostname;
592
+ const t = (s = window.location) == null ? void 0 : s.hostname;
575
593
  return t ? t.replace(/\./g, "_") : "unknown";
576
594
  }
577
595
  /**
578
596
  * Get singleton instance
579
597
  */
580
598
  static getInstance() {
581
- return this.instance || (this.instance = new S()), this.instance;
599
+ return this.instance || (this.instance = new $()), this.instance;
582
600
  }
583
601
  /**
584
602
  * Collect all available client information
@@ -700,11 +718,11 @@ class S {
700
718
  const i = e.match(/Android (\d+)\.(\d+)/);
701
719
  if (i)
702
720
  return `${i[1]}.${i[2]}`;
703
- const n = e.match(/Windows NT (\d+\.\d+)/);
704
- if (n)
705
- return n[1];
706
- const s = e.match(/Mac OS X (\d+[._]\d+)/);
707
- return s ? s[1].replace("_", ".") : "Unknown";
721
+ const s = e.match(/Windows NT (\d+\.\d+)/);
722
+ if (s)
723
+ return s[1];
724
+ const n = e.match(/Mac OS X (\d+[._]\d+)/);
725
+ return n ? n[1].replace("_", ".") : "Unknown";
708
726
  }
709
727
  /**
710
728
  * Detect Device Type (OpenRTB standard)
@@ -729,10 +747,10 @@ class S {
729
747
  const i = e.match(/Samsung-.*(SM-\w+)/);
730
748
  if (i) return i[1];
731
749
  if (/Pixel/.test(e)) return "Google Pixel";
732
- const n = e.match(/(BARC-|HUAWEI-)?([A-Z]{2}\-\w{4})/);
733
- if (n) return n[2];
734
- const s = e.match(/(MI|Redmi|POCO)\s([\w\s]+)/);
735
- if (s) return s[1] + " " + s[2];
750
+ const s = e.match(/(BARC-|HUAWEI-)?([A-Z]{2}\-\w{4})/);
751
+ if (s) return s[2];
752
+ const n = e.match(/(MI|Redmi|POCO)\s([\w\s]+)/);
753
+ if (n) return n[1] + " " + n[2];
736
754
  if (/OnePlus/.test(e)) {
737
755
  const r = e.match(/OnePlus\s([A-Z\d]+)/);
738
756
  return r ? "OnePlus " + r[1] : "OnePlus";
@@ -848,9 +866,9 @@ class S {
848
866
  if (t && i[t])
849
867
  return i[t];
850
868
  if (e) {
851
- const n = e.split("-")[1];
852
- if (n)
853
- return n.toUpperCase();
869
+ const s = e.split("-")[1];
870
+ if (s)
871
+ return s.toUpperCase();
854
872
  }
855
873
  }
856
874
  /**
@@ -881,35 +899,35 @@ class S {
881
899
  this.cachedStaticInfo = null, this.cacheTimestamp = 0;
882
900
  }
883
901
  }
884
- const T = () => S.getInstance();
885
- function g(o) {
886
- return T().collect(o);
887
- }
888
- function z() {
889
- return g().device;
890
- }
891
- function q() {
892
- return g().user;
902
+ const I = () => $.getInstance();
903
+ function b(o) {
904
+ return I().collect(o);
893
905
  }
894
906
  function W() {
895
- return g().app;
907
+ return b().device;
908
+ }
909
+ function K() {
910
+ return b().user;
896
911
  }
897
912
  function Q() {
898
- return g().geo;
913
+ return b().app;
899
914
  }
900
915
  function J() {
901
- return q().id;
916
+ return b().geo;
902
917
  }
903
918
  function X() {
904
- T().clearCache();
919
+ return K().id;
905
920
  }
906
- function Z(o) {
907
- const e = g(o);
921
+ function Z() {
922
+ I().clearCache();
923
+ }
924
+ function Y(o) {
925
+ const e = b(o);
908
926
  return JSON.stringify(e, null, 2);
909
927
  }
910
- function Y() {
928
+ function ee() {
911
929
  var t;
912
- const o = g();
930
+ const o = b();
913
931
  return [
914
932
  o.device.os,
915
933
  o.device.osv,
@@ -918,7 +936,7 @@ function Y() {
918
936
  ((t = o.geo) == null ? void 0 : t.country) || "Unknown"
919
937
  ].join(" / ");
920
938
  }
921
- function ee(o) {
939
+ function te(o) {
922
940
  var e, t;
923
941
  return {
924
942
  id: o.original.id,
@@ -945,10 +963,10 @@ function ee(o) {
945
963
  }
946
964
  };
947
965
  }
948
- async function K(o, e = {}) {
949
- const t = e.apiBaseUrl || "/api/v1", n = T().collect(), s = {
966
+ async function R(o, e = {}) {
967
+ const t = e.apiBaseUrl || "/api/v1", s = I().collect(), n = {
950
968
  ...o,
951
- clientInfo: n
969
+ clientInfo: s
952
970
  // Auto-injected
953
971
  }, r = {
954
972
  "Content-Type": "application/json"
@@ -957,7 +975,7 @@ async function K(o, e = {}) {
957
975
  const a = await fetch(`${t}/ads/request`, {
958
976
  method: "POST",
959
977
  headers: r,
960
- body: JSON.stringify(s)
978
+ body: JSON.stringify(n)
961
979
  });
962
980
  if (!a.ok)
963
981
  throw new Error(`Ad request failed: ${a.status} ${a.statusText}`);
@@ -966,16 +984,16 @@ async function K(o, e = {}) {
966
984
  throw new Error(c.error || "Ad request failed");
967
985
  return c.data;
968
986
  }
969
- const R = { width: 400, height: 200 }, k = {
987
+ const N = { width: 400, height: 200 }, A = {
970
988
  variant: "horizontal",
971
989
  count: 1,
972
990
  preferences: {}
973
991
  };
974
- function $(o = {}) {
992
+ function U(o = {}) {
975
993
  const e = {
976
- variant: o.variant ?? k.variant,
977
- count: o.count ?? k.count,
978
- preferences: { ...k.preferences, ...o.preferences }
994
+ variant: o.variant ?? A.variant,
995
+ count: o.count ?? A.count,
996
+ preferences: { ...A.preferences, ...o.preferences }
979
997
  };
980
998
  return [
981
999
  {
@@ -983,16 +1001,16 @@ function $(o = {}) {
983
1001
  slotName: "Action Card",
984
1002
  format: "action_card",
985
1003
  variant: e.variant,
986
- size: R,
1004
+ size: N,
987
1005
  count: e.count,
988
1006
  preferences: e.preferences,
989
1007
  placement: { position: "below_fold", context: "post_response" }
990
1008
  }
991
1009
  ];
992
1010
  }
993
- const w = class w {
1011
+ const g = class g {
994
1012
  constructor(e) {
995
- this.slots = {}, this.isLoading = !1, this.currentRequestId = null, this.adsAnalyticsMap = /* @__PURE__ */ new Map(), this.config = e, this.enabled = e.enabled !== !1, this.eventBus = new P(), this.slots_config = $(e.cardOption), typeof window < "u" && (window.__AD_CONFIG__ = {
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 B(), this.slots_config = U(e.cardOption), typeof window < "u" && (window.__AD_CONFIG__ = {
996
1014
  ...window.__AD_CONFIG__ || {},
997
1015
  apiKey: e.apiKey,
998
1016
  apiBaseUrl: e.apiBaseUrl
@@ -1003,60 +1021,75 @@ const w = class w {
1003
1021
  });
1004
1022
  }
1005
1023
  async requestAds(e) {
1024
+ const t = "conversationContext" in e ? e : { conversationContext: e }, i = this.buildRequestKey(t), s = g.inFlightRequests.get(i);
1025
+ if (s)
1026
+ return this.config.debug && console.log("[AdManager] Reusing in-flight request for identical context"), s;
1006
1027
  if (!this.enabled)
1007
1028
  throw this.config.debug && console.warn("[AdManager] Ads are disabled, skipping request"), new Error("Ads are disabled");
1008
1029
  if (this.isLoading)
1009
1030
  throw this.config.debug && console.warn("[AdManager] Request already in progress"), new Error("Request already in progress");
1010
1031
  this.isLoading = !0, this.eventBus.emit("adsLoading"), this.config.debug && console.log("[AdManager] Starting ad request...");
1011
- const t = "conversationContext" in e ? e : { conversationContext: e };
1012
- try {
1013
- const i = await K(
1014
- {
1015
- conversationContext: t.conversationContext,
1016
- userContext: t.userContext ? { ...t.userContext, sessionId: t.userContext.sessionId ?? f() } : { sessionId: f() },
1017
- slots: this.slots_config
1018
- },
1019
- {
1020
- apiBaseUrl: this.config.apiBaseUrl,
1021
- apiKey: this.config.apiKey
1022
- }
1023
- );
1024
- this.currentRequestId = i.requestId, this.adsAnalyticsMap.clear(), i.slots.forEach((s) => {
1025
- s.ads.forEach((r, a) => {
1026
- const c = r.original.id;
1027
- this.adsAnalyticsMap.set(c, {
1028
- requestId: i.requestId,
1029
- slotId: s.slotId,
1030
- position: a,
1031
- totalAds: s.ads.length
1032
+ const n = (async () => {
1033
+ try {
1034
+ const r = await R(
1035
+ {
1036
+ conversationContext: t.conversationContext,
1037
+ userContext: t.userContext ? { ...t.userContext, sessionId: t.userContext.sessionId ?? m() } : { sessionId: m() },
1038
+ slots: this.slots_config
1039
+ },
1040
+ {
1041
+ apiBaseUrl: this.config.apiBaseUrl,
1042
+ apiKey: this.config.apiKey
1043
+ }
1044
+ );
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,
1053
+ apiBaseUrl: this.config.apiBaseUrl
1054
+ });
1032
1055
  });
1033
1056
  });
1034
- });
1035
- const n = {};
1036
- return i.slots.forEach((s) => {
1037
- n[s.slotId] = s;
1038
- }), this.slots = n, this.eventBus.emit("adsUpdated", this.slots), this.config.debug && console.log("[AdManager] Ads received:", {
1039
- slotCount: Object.keys(this.slots).length,
1040
- slots: Object.keys(this.slots)
1041
- }), i;
1042
- } catch (i) {
1043
- const n = i;
1044
- throw this.eventBus.emit("adsError", n), n;
1045
- } finally {
1046
- this.isLoading = !1;
1047
- }
1057
+ const a = {};
1058
+ return r.slots.forEach((c) => {
1059
+ a[c.slotId] = c;
1060
+ }), this.slots = a, this.eventBus.emit("adsUpdated", this.slots), this.config.debug && console.log("[AdManager] Ads received:", {
1061
+ slotCount: Object.keys(this.slots).length,
1062
+ slots: Object.keys(this.slots)
1063
+ }), r;
1064
+ } catch (r) {
1065
+ const a = r;
1066
+ throw this.eventBus.emit("adsError", a), a;
1067
+ } finally {
1068
+ this.isLoading = !1, g.inFlightRequests.delete(i);
1069
+ }
1070
+ })();
1071
+ return g.inFlightRequests.set(i, n), n;
1072
+ }
1073
+ buildRequestKey(e) {
1074
+ return JSON.stringify({
1075
+ apiBaseUrl: this.config.apiBaseUrl,
1076
+ apiKey: this.config.apiKey,
1077
+ conversationContext: e.conversationContext,
1078
+ userContext: e.userContext || null,
1079
+ slots: this.slots_config
1080
+ });
1048
1081
  }
1049
1082
  render(e, t, i = {}) {
1050
- const n = typeof e != "string", s = n ? w.DEFAULT_SLOT_ID : e, r = n ? e : t, a = (n ? t : i) || {};
1083
+ const s = typeof e != "string", n = s ? g.DEFAULT_SLOT_ID : e, r = s ? e : t, a = (s ? t : i) || {};
1051
1084
  if (!r)
1052
1085
  return this.config.debug && console.warn("[AdManager] Render container is required"), null;
1053
- const c = this.slots[s];
1086
+ const c = this.slots[n];
1054
1087
  if (!c || !c.ads || c.ads.length === 0)
1055
- return this.config.debug && console.warn("[AdManager] No ads in slot:", s), null;
1056
- const l = a.adIndex ?? 0, d = c.ads[l];
1057
- if (!d)
1058
- return this.config.debug && console.warn(`[AdManager] Ad at index ${l} not found in slot:`, s), null;
1059
- const u = this.adsAnalyticsMap.get(d.original.id), p = this.slots_config.find((_) => _.slotId === s), m = (p == null ? void 0 : p.format) || "action_card";
1088
+ return this.config.debug && console.warn("[AdManager] No ads in slot:", n), null;
1089
+ const d = a.adIndex ?? 0, l = c.ads[d];
1090
+ if (!l)
1091
+ return this.config.debug && console.warn(`[AdManager] Ad at index ${d} not found in slot:`, n), null;
1092
+ const u = this.adsAnalyticsMap.get(l.original.id), f = this.slots_config.find((w) => w.slotId === n), p = (f == null ? void 0 : f.format) || "action_card";
1060
1093
  r.innerHTML = "";
1061
1094
  const h = {
1062
1095
  analytics: u,
@@ -1064,7 +1097,7 @@ const w = class w {
1064
1097
  onClick: a.onClick,
1065
1098
  onImpression: a.onImpression
1066
1099
  };
1067
- return m === "suffix" ? v.renderSuffixAd(d, r, h) : m === "source" ? v.renderSponsoredSource(d, r, h) : m === "lead_gen" ? v.renderLeadGenAd(d, r, h) : v.renderActionCard(d, r, h);
1100
+ 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);
1068
1101
  }
1069
1102
  /**
1070
1103
  * Get ad slots data
@@ -1103,7 +1136,7 @@ const w = class w {
1103
1136
  * Update configuration
1104
1137
  */
1105
1138
  updateConfig(e) {
1106
- 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
+ this.config = { ...this.config, ...e }, e.cardOption !== void 0 && (this.slots_config = U(this.config.cardOption)), this.config.debug && console.log("[AdManager] Config updated:", e);
1107
1140
  }
1108
1141
  /**
1109
1142
  * Clear all slot data
@@ -1147,28 +1180,28 @@ const w = class w {
1147
1180
  getAdsAnalytics(e) {
1148
1181
  const t = /* @__PURE__ */ new Map();
1149
1182
  return e.forEach((i) => {
1150
- const n = this.adsAnalyticsMap.get(i);
1151
- n && t.set(i, n);
1183
+ const s = this.adsAnalyticsMap.get(i);
1184
+ s && t.set(i, s);
1152
1185
  }), t;
1153
1186
  }
1154
1187
  /**
1155
1188
  * Track ad click using Analytics API
1156
1189
  */
1157
1190
  async trackAdClick(e, t, i) {
1158
- const n = this.adsAnalyticsMap.get(e);
1159
- if (!n || !this.currentRequestId)
1191
+ const s = this.adsAnalyticsMap.get(e);
1192
+ if (!s || !this.currentRequestId)
1160
1193
  return this.config.debug && console.warn("[AdManager] No analytics info for ad:", e), null;
1161
- const s = f(), r = await A({
1194
+ const n = m(), r = await T({
1162
1195
  requestId: this.currentRequestId,
1163
1196
  adId: e,
1164
1197
  destinationUrl: t,
1165
- sessionId: s,
1166
- slotId: n.slotId,
1198
+ sessionId: n,
1199
+ slotId: s.slotId,
1167
1200
  adTitle: i == null ? void 0 : i.title,
1168
1201
  format: i == null ? void 0 : i.format,
1169
1202
  source: i == null ? void 0 : i.source
1170
- });
1171
- return r && (this.eventBus.emit("adClicked", e, n.slotId), this.config.debug && console.log("[AdManager] Click tracked via Analytics API:", r.eventId)), r;
1203
+ }, { baseUrl: s.apiBaseUrl });
1204
+ return r && (this.eventBus.emit("adClicked", e, s.slotId), this.config.debug && console.log("[AdManager] Click tracked via Analytics API:", r.eventId)), r;
1172
1205
  }
1173
1206
  /**
1174
1207
  * Track ad impression using Analytics API
@@ -1177,19 +1210,19 @@ const w = class w {
1177
1210
  const i = this.adsAnalyticsMap.get(e);
1178
1211
  if (!i || !this.currentRequestId)
1179
1212
  return this.config.debug && console.warn("[AdManager] No analytics info for ad:", e), null;
1180
- const n = f(), s = await x({
1213
+ const s = m(), n = await S({
1181
1214
  requestId: this.currentRequestId,
1182
1215
  adId: e,
1183
1216
  slotId: i.slotId,
1184
1217
  position: i.position,
1185
1218
  totalAds: i.totalAds,
1186
- sessionId: n,
1219
+ sessionId: s,
1187
1220
  adTitle: t == null ? void 0 : t.title,
1188
1221
  format: t == null ? void 0 : t.format,
1189
1222
  source: t == null ? void 0 : t.source,
1190
1223
  viewToken: t == null ? void 0 : t.viewToken
1191
- });
1192
- return s && (this.eventBus.emit("adImpression", e, i.slotId), this.config.debug && console.log("[AdManager] Impression tracked via Analytics API:", s.eventId)), s;
1224
+ }, { baseUrl: i.apiBaseUrl });
1225
+ return n && (this.eventBus.emit("adImpression", e, i.slotId), this.config.debug && console.log("[AdManager] Impression tracked via Analytics API:", n.eventId)), n;
1193
1226
  }
1194
1227
  /**
1195
1228
  * Destroy the manager and clean up
@@ -1198,25 +1231,25 @@ const w = class w {
1198
1231
  this.removeAllListeners(), this.clearSlots(), this.config.debug && console.log("[AdManager] Destroyed");
1199
1232
  }
1200
1233
  };
1201
- w.DEFAULT_SLOT_ID = "action_card";
1202
- let I = w;
1203
- function M() {
1234
+ g.DEFAULT_SLOT_ID = "action_card", g.inFlightRequests = /* @__PURE__ */ new Map();
1235
+ let V = g;
1236
+ function E() {
1204
1237
  if (typeof window < "u") {
1205
1238
  const o = window.__AD_CONFIG__;
1206
1239
  if (o != null && o.apiKey)
1207
1240
  return o.apiKey;
1208
1241
  }
1209
1242
  }
1210
- class N {
1243
+ class H {
1211
1244
  constructor(e = {}, t = "/api/v1") {
1212
- var i, n;
1245
+ var i, s;
1213
1246
  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 = {
1214
1247
  minVisiblePercentage: e.minVisiblePercentage ?? 50,
1215
1248
  minViewableDuration: e.minViewableDuration ?? 1e3,
1216
1249
  maxTrackingDuration: e.maxTrackingDuration ?? 6e4,
1217
1250
  batchConfig: {
1218
1251
  maxBatchSize: ((i = e.batchConfig) == null ? void 0 : i.maxBatchSize) ?? 5,
1219
- maxBatchWaitMs: ((n = e.batchConfig) == null ? void 0 : n.maxBatchWaitMs) ?? 1e4
1252
+ maxBatchWaitMs: ((s = e.batchConfig) == null ? void 0 : s.maxBatchWaitMs) ?? 1e4
1220
1253
  },
1221
1254
  debug: e.debug ?? !1
1222
1255
  }, this.baseUrl = t;
@@ -1224,7 +1257,7 @@ class N {
1224
1257
  /**
1225
1258
  * Start tracking viewability for an ad element
1226
1259
  */
1227
- startTracking(e, t, i, n, s) {
1260
+ startTracking(e, t, i, s, n) {
1228
1261
  if (this.isTracking.get(e)) {
1229
1262
  this.log(`[ViewabilityTracker] Already tracking ${e}, skipping`);
1230
1263
  return;
@@ -1242,14 +1275,14 @@ class N {
1242
1275
  };
1243
1276
  this.metrics.set(e, r), this.isTracking.set(e, !0), this.eventQueue.set(e, []);
1244
1277
  const a = new IntersectionObserver(
1245
- (l) => this.handleIntersection(e, l[0], i, n, s),
1278
+ (d) => this.handleIntersection(e, d[0], i, s, n),
1246
1279
  {
1247
1280
  threshold: this.createThresholds()
1248
1281
  }
1249
1282
  );
1250
- a.observe(t), this.observers.set(e, a), this.startMonitoring(e, i, n, s);
1283
+ a.observe(t), this.observers.set(e, a), this.startMonitoring(e, i, s, n);
1251
1284
  const c = setTimeout(() => {
1252
- this.endTracking(e, i, n, s);
1285
+ this.endTracking(e, i, s, n);
1253
1286
  }, this.config.maxTrackingDuration);
1254
1287
  this.timers.set(e, c);
1255
1288
  }
@@ -1269,36 +1302,36 @@ class N {
1269
1302
  * Handle IntersectionObserver callback
1270
1303
  * Event-driven: Only process when state actually changes
1271
1304
  */
1272
- handleIntersection(e, t, i, n, s) {
1305
+ handleIntersection(e, t, i, s, n) {
1273
1306
  const r = this.metrics.get(e);
1274
1307
  if (!r || !this.isTracking.get(e)) return;
1275
1308
  const a = r.isViewable, c = Math.round(t.intersectionRatio * 100);
1276
1309
  r.visiblePercentage = c, r.maxVisiblePercentage = Math.max(r.maxVisiblePercentage, c);
1277
- const l = Date.now(), d = c >= this.config.minVisiblePercentage;
1278
- if (d && !r.enteredViewportAt && (r.enteredViewportAt = l, r.enterCount++, this.log(`[ViewabilityTracker] ${e} entered viewport at ${l}`), this.queueEvent(e, {
1310
+ const d = Date.now(), l = c >= this.config.minVisiblePercentage;
1311
+ if (l && !r.enteredViewportAt && (r.enteredViewportAt = d, r.enterCount++, this.log(`[ViewabilityTracker] ${e} entered viewport at ${d}`), this.queueEvent(e, {
1279
1312
  adId: e,
1280
1313
  sessionId: i,
1281
- requestId: n,
1282
- viewToken: s,
1314
+ requestId: s,
1315
+ viewToken: n,
1283
1316
  eventType: "enter_viewport",
1284
1317
  visiblePercentage: c,
1285
1318
  maxVisiblePercentage: r.maxVisiblePercentage,
1286
1319
  totalVisibleTimeMs: r.totalVisibleTimeMs,
1287
1320
  isViewable: !1,
1288
- timestamp: l
1289
- })), !d && r.enteredViewportAt) {
1290
- const u = l - r.enteredViewportAt;
1321
+ timestamp: d
1322
+ })), !l && r.enteredViewportAt) {
1323
+ const u = d - r.enteredViewportAt;
1291
1324
  r.totalVisibleTimeMs += u, r.enteredViewportAt = null, r.currentVisibleTimeMs = 0, this.log(`[ViewabilityTracker] ${e} exited viewport, total visible: ${r.totalVisibleTimeMs}ms`), this.queueEvent(e, {
1292
1325
  adId: e,
1293
1326
  sessionId: i,
1294
- requestId: n,
1295
- viewToken: s,
1327
+ requestId: s,
1328
+ viewToken: n,
1296
1329
  eventType: "exit_viewport",
1297
1330
  visiblePercentage: c,
1298
1331
  maxVisiblePercentage: r.maxVisiblePercentage,
1299
1332
  totalVisibleTimeMs: r.totalVisibleTimeMs,
1300
1333
  isViewable: r.isViewable,
1301
- timestamp: l
1334
+ timestamp: d
1302
1335
  });
1303
1336
  }
1304
1337
  r.isViewable !== a && r.isViewable && this.log(`[ViewabilityTracker] ${e} became VIEWABLE!`), this.metrics.set(e, r);
@@ -1307,21 +1340,21 @@ class N {
1307
1340
  * Start monitoring loop for tracking duration
1308
1341
  * Runs every 100ms to track continuous visible time
1309
1342
  */
1310
- startMonitoring(e, t, i, n) {
1343
+ startMonitoring(e, t, i, s) {
1311
1344
  const r = setInterval(() => {
1312
1345
  const a = this.metrics.get(e);
1313
1346
  if (!a || !this.isTracking.get(e)) {
1314
1347
  clearInterval(r);
1315
1348
  return;
1316
1349
  }
1317
- const c = Date.now(), l = a.isViewable;
1350
+ const c = Date.now(), d = a.isViewable;
1318
1351
  if (a.enteredViewportAt) {
1319
- const d = c - a.enteredViewportAt;
1320
- 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, {
1352
+ const l = c - a.enteredViewportAt;
1353
+ 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, {
1321
1354
  adId: e,
1322
1355
  sessionId: t,
1323
1356
  requestId: i,
1324
- viewToken: n,
1357
+ viewToken: s,
1325
1358
  eventType: "become_viewable",
1326
1359
  visiblePercentage: a.visiblePercentage,
1327
1360
  maxVisiblePercentage: a.maxVisiblePercentage,
@@ -1338,23 +1371,23 @@ class N {
1338
1371
  * Queue an event to be sent (batched)
1339
1372
  */
1340
1373
  queueEvent(e, t) {
1341
- var s, r;
1374
+ var n, r;
1342
1375
  const i = this.eventQueue.get(e);
1343
1376
  if (!i) {
1344
1377
  this.log(`[ViewabilityTracker] No queue found for ${e}, skipping event`);
1345
1378
  return;
1346
1379
  }
1347
1380
  i.push(t), this.log(`[ViewabilityTracker] Queued ${t.eventType} for ${e} (queue size: ${i.length})`);
1348
- const n = ((s = this.config.batchConfig) == null ? void 0 : s.maxBatchSize) ?? 5;
1349
- if (i.length >= n)
1381
+ const s = ((n = this.config.batchConfig) == null ? void 0 : n.maxBatchSize) ?? 5;
1382
+ if (i.length >= s)
1350
1383
  this.flushQueue(e);
1351
1384
  else {
1352
1385
  const a = this.batchTimers.get(e);
1353
1386
  a && clearTimeout(a);
1354
- const c = ((r = this.config.batchConfig) == null ? void 0 : r.maxBatchWaitMs) ?? 1e4, l = setTimeout(() => {
1387
+ const c = ((r = this.config.batchConfig) == null ? void 0 : r.maxBatchWaitMs) ?? 1e4, d = setTimeout(() => {
1355
1388
  this.flushQueue(e);
1356
1389
  }, c);
1357
- this.batchTimers.set(e, l);
1390
+ this.batchTimers.set(e, d);
1358
1391
  }
1359
1392
  }
1360
1393
  /**
@@ -1366,36 +1399,36 @@ class N {
1366
1399
  const i = [...t];
1367
1400
  t.length = 0, this.log(`[ViewabilityTracker] Flushing ${i.length} events for ${e}`);
1368
1401
  try {
1369
- const n = {
1402
+ const s = {
1370
1403
  "Content-Type": "application/json"
1371
- }, s = M();
1372
- s && (n["x-api-key"] = s), await fetch(`${this.baseUrl}/ads/viewability/batch`, {
1404
+ }, n = E();
1405
+ n && (s["x-api-key"] = n), await fetch(`${this.baseUrl}/ads/viewability/batch`, {
1373
1406
  method: "POST",
1374
- headers: n,
1407
+ headers: s,
1375
1408
  body: JSON.stringify({ events: i })
1376
1409
  }), this.log(`[ViewabilityTracker] Successfully sent ${i.length} events for ${e}`);
1377
- } catch (n) {
1378
- this.log(`[ViewabilityTracker] Failed to send events for ${e}:`, n), t.unshift(...i);
1410
+ } catch (s) {
1411
+ this.log(`[ViewabilityTracker] Failed to send events for ${e}:`, s), t.unshift(...i);
1379
1412
  }
1380
1413
  }
1381
1414
  /**
1382
1415
  * End tracking and send final metrics
1383
1416
  */
1384
- endTracking(e, t, i, n) {
1385
- const s = this.metrics.get(e);
1386
- if (!s) return;
1417
+ endTracking(e, t, i, s) {
1418
+ const n = this.metrics.get(e);
1419
+ if (!n) return;
1387
1420
  this.log(`[ViewabilityTracker] Ending tracking for ${e}`), this.flushQueue(e);
1388
1421
  const r = Date.now();
1389
1422
  this.queueEvent(e, {
1390
1423
  adId: e,
1391
1424
  sessionId: t,
1392
1425
  requestId: i,
1393
- viewToken: n,
1426
+ viewToken: s,
1394
1427
  eventType: "end_tracking",
1395
- visiblePercentage: s.visiblePercentage,
1396
- maxVisiblePercentage: s.maxVisiblePercentage,
1397
- totalVisibleTimeMs: s.totalVisibleTimeMs,
1398
- isViewable: s.isViewable,
1428
+ visiblePercentage: n.visiblePercentage,
1429
+ maxVisiblePercentage: n.maxVisiblePercentage,
1430
+ totalVisibleTimeMs: n.totalVisibleTimeMs,
1431
+ isViewable: n.isViewable,
1399
1432
  timestamp: r
1400
1433
  }), this.flushQueue(e), this.cleanup(e);
1401
1434
  }
@@ -1407,10 +1440,10 @@ class N {
1407
1440
  t && (t.disconnect(), this.observers.delete(e));
1408
1441
  const i = this.timers.get(e);
1409
1442
  i && (clearTimeout(i), this.timers.delete(e));
1410
- const n = this.timers.get(`${e}_monitoring`);
1411
- n && (clearInterval(n), this.timers.delete(`${e}_monitoring`));
1412
- const s = this.batchTimers.get(e);
1413
- s && (clearTimeout(s), this.batchTimers.delete(e)), this.flushQueue(e), this.isTracking.delete(e), this.metrics.delete(e), this.eventQueue.delete(e);
1443
+ const s = this.timers.get(`${e}_monitoring`);
1444
+ s && (clearInterval(s), this.timers.delete(`${e}_monitoring`));
1445
+ const n = this.batchTimers.get(e);
1446
+ n && (clearTimeout(n), this.batchTimers.delete(e)), this.flushQueue(e), this.isTracking.delete(e), this.metrics.delete(e), this.eventQueue.delete(e);
1414
1447
  }
1415
1448
  /**
1416
1449
  * Create thresholds for IntersectionObserver
@@ -1442,8 +1475,8 @@ class N {
1442
1475
  if (t && t.length > 0) {
1443
1476
  const i = {
1444
1477
  "Content-Type": "application/json"
1445
- }, n = M();
1446
- n && (i["x-api-key"] = n), fetch(`${this.baseUrl}/ads/viewability/batch`, {
1478
+ }, s = E();
1479
+ s && (i["x-api-key"] = s), fetch(`${this.baseUrl}/ads/viewability/batch`, {
1447
1480
  method: "POST",
1448
1481
  headers: i,
1449
1482
  keepalive: !0,
@@ -1454,39 +1487,39 @@ class N {
1454
1487
  });
1455
1488
  }
1456
1489
  }
1457
- let b = null;
1458
- function te(o, e) {
1459
- return b || (b = new N(o, e), b.setupBeforeUnload()), b;
1490
+ let k = null;
1491
+ function ie(o, e) {
1492
+ return k || (k = new H(o, e), k.setupBeforeUnload()), k;
1460
1493
  }
1461
- const ie = "0.1.0";
1494
+ const se = "0.1.0";
1462
1495
  export {
1463
- I as AdManager,
1464
- V as AnalyticsSender,
1465
- S as ClientInfoCollector,
1466
- v as DOMRenderer,
1467
- y as HTMLRenderer,
1468
- ie as SDK_VERSION,
1469
- C as SessionManager,
1470
- N as ViewabilityTracker,
1471
- ee as adaptAdToKoahAd,
1472
- X as clearClientInfoCache,
1473
- F as createAnalytics,
1474
- j as createSession,
1475
- K as fetchAds,
1476
- H as generateViewToken,
1477
- W as getAppInfo,
1478
- g as getClientInfo,
1479
- T as getClientInfoCollector,
1480
- Z as getClientInfoJSON,
1481
- Y as getClientInfoSummary,
1482
- z as getDeviceInfo,
1483
- Q as getGeoInfo,
1484
- f as getSessionId,
1485
- J as getUserId,
1486
- q as getUserInfo,
1487
- te as getViewabilityTracker,
1488
- A as trackAdClick,
1489
- x as trackAdImpression,
1490
- G as trackClicksBatch,
1491
- D as trackImpressionsBatch
1496
+ V as AdManager,
1497
+ x as AnalyticsSender,
1498
+ $ as ClientInfoCollector,
1499
+ y as DOMRenderer,
1500
+ v as HTMLRenderer,
1501
+ se as SDK_VERSION,
1502
+ _ as SessionManager,
1503
+ H as ViewabilityTracker,
1504
+ te as adaptAdToKoahAd,
1505
+ Z as clearClientInfoCache,
1506
+ j as createAnalytics,
1507
+ z as createSession,
1508
+ R as fetchAds,
1509
+ F as generateViewToken,
1510
+ Q as getAppInfo,
1511
+ b as getClientInfo,
1512
+ I as getClientInfoCollector,
1513
+ Y as getClientInfoJSON,
1514
+ ee as getClientInfoSummary,
1515
+ W as getDeviceInfo,
1516
+ J as getGeoInfo,
1517
+ m as getSessionId,
1518
+ X as getUserId,
1519
+ K as getUserInfo,
1520
+ ie as getViewabilityTracker,
1521
+ T as trackAdClick,
1522
+ S as trackAdImpression,
1523
+ D as trackClicksBatch,
1524
+ G as trackImpressionsBatch
1492
1525
  };