@action-x/ad-sdk 0.1.11 → 0.1.13

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
@@ -13,16 +13,16 @@ class q {
13
13
  */
14
14
  off(e, t) {
15
15
  if (!this.events[e]) return;
16
- const i = this.events[e].indexOf(t);
17
- i > -1 && this.events[e].splice(i, 1);
16
+ const n = this.events[e].indexOf(t);
17
+ n > -1 && this.events[e].splice(n, 1);
18
18
  }
19
19
  /**
20
20
  * Emit an event
21
21
  */
22
22
  emit(e, ...t) {
23
- this.events[e] && this.events[e].forEach((i) => {
23
+ this.events[e] && this.events[e].forEach((n) => {
24
24
  try {
25
- i(...t);
25
+ n(...t);
26
26
  } catch (s) {
27
27
  console.error(`[EventEmitter] Error in event handler for "${e}":`, s);
28
28
  }
@@ -45,7 +45,7 @@ class q {
45
45
  function m(r) {
46
46
  return r.replace(/<[^>]+>/g, " ").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, " ").replace(/\s{2,}/g, " ").trim();
47
47
  }
48
- class v {
48
+ class I {
49
49
  static getClickUrl(e) {
50
50
  return e.tracking.clickUrl || e.tracking.click_url || "#";
51
51
  }
@@ -63,30 +63,30 @@ class v {
63
63
  * @returns HTML string
64
64
  */
65
65
  static renderActionCard(e, t = {}) {
66
- var f;
67
- const { variant: i = "horizontal", includeWrapper: s = !0 } = t, n = e.adapted, o = this.getClickUrl(e), a = this.getImpressionUrl(e), c = (f = n.image) != null && f.url ? `<div class="ax-ad-image-wrap">
66
+ var h;
67
+ const { variant: n = "horizontal", includeWrapper: s = !0 } = t, i = e.adapted, o = this.getClickUrl(e), a = this.getImpressionUrl(e), c = (h = i.image) != null && h.url ? `<div class="ax-ad-image-wrap">
68
68
  <img
69
- src="${n.image.url}"
70
- alt="${n.title}"
69
+ src="${i.image.url}"
70
+ alt="${i.title}"
71
71
  class="ax-ad-image"
72
72
  loading="lazy"
73
73
  />
74
- </div>` : "", u = (n.brand || "").trim(), l = u && u.toLowerCase() !== "unknown" ? `<span class="ax-ad-brand">${n.brand}</span>` : "", d = `
74
+ </div>` : "", u = (i.brand || "").trim(), l = u && u.toLowerCase() !== "unknown" ? `<span class="ax-ad-brand">${i.brand}</span>` : "", d = `
75
75
  ${c}
76
76
  <div class="ax-ad-content">
77
77
  ${l}
78
- <h3 class="ax-ad-title">${n.title}</h3>
79
- ${n.body ? `<p class="ax-ad-body">${m(n.body)}</p>` : ""}
78
+ <h3 class="ax-ad-title">${i.title}</h3>
79
+ ${i.body ? `<p class="ax-ad-body">${m(i.body)}</p>` : ""}
80
80
  </div>
81
- `, h = s ? `<a
81
+ `, f = s ? `<a
82
82
  href="${o}"
83
- class="ax-ad-card ax-ad-card-${i} ax-ad-card-link"
83
+ class="ax-ad-card ax-ad-card-${n} ax-ad-card-link"
84
84
  target="_blank"
85
85
  rel="sponsored noopener noreferrer"
86
86
  data-ad-id="${e.original.id}"
87
87
  data-impression-url="${a}"
88
- >` : "", p = s ? "</a>" : "";
89
- return h + d + p;
88
+ >` : "", g = s ? "</a>" : "";
89
+ return f + d + g;
90
90
  }
91
91
  /**
92
92
  * Render Suffix ad as HTML string
@@ -95,14 +95,14 @@ class v {
95
95
  * @returns HTML string
96
96
  */
97
97
  static renderSuffixAd(e) {
98
- const t = e.adapted, i = this.getClickUrl(e), s = this.getImpressionUrl(e);
98
+ const t = e.adapted, n = this.getClickUrl(e), s = this.getImpressionUrl(e);
99
99
  return `
100
100
  <div class="ax-ad-suffix" data-ad-id="${e.original.id}">
101
101
  <div class="ax-ad-suffix-content">
102
102
  ${t.title ? `<h4 class="ax-ad-suffix-title">${t.title}</h4>` : ""}
103
103
  ${t.body ? `<p class="ax-ad-suffix-body">${m(t.body)}</p>` : ""}
104
104
  <a
105
- href="${i}"
105
+ href="${n}"
106
106
  class="ax-ad-suffix-link"
107
107
  target="_blank"
108
108
  rel="sponsored noopener noreferrer"
@@ -122,19 +122,19 @@ class v {
122
122
  * @returns HTML string
123
123
  */
124
124
  static renderSponsoredSource(e) {
125
- var n;
126
- const t = e.adapted, i = this.getClickUrl(e), s = this.getImpressionUrl(e);
125
+ var i;
126
+ const t = e.adapted, n = this.getClickUrl(e), s = this.getImpressionUrl(e);
127
127
  return `
128
128
  <div class="ax-ad-source" data-ad-id="${e.original.id}">
129
129
  <a
130
- href="${i}"
130
+ href="${n}"
131
131
  class="ax-ad-source-link"
132
132
  target="_blank"
133
133
  rel="sponsored noopener noreferrer"
134
134
  data-ad-id="${e.original.id}"
135
135
  data-impression-url="${s}"
136
136
  >
137
- ${(n = t.image) != null && n.url ? `<img src="${t.image.url}" alt="" class="ax-ad-source-icon" />` : ""}
137
+ ${(i = t.image) != null && i.url ? `<img src="${t.image.url}" alt="" class="ax-ad-source-icon" />` : ""}
138
138
  <div class="ax-ad-source-info">
139
139
  <span class="ax-ad-source-name">${t.title}</span>
140
140
  ${t.body ? `<span class="ax-ad-source-desc">${m(t.body)}</span>` : ""}
@@ -151,14 +151,14 @@ class v {
151
151
  * @returns HTML string
152
152
  */
153
153
  static renderLeadGenAd(e) {
154
- const t = e.adapted, i = this.getClickUrl(e), s = this.getImpressionUrl(e);
154
+ const t = e.adapted, n = this.getClickUrl(e), s = this.getImpressionUrl(e);
155
155
  return `
156
156
  <div class="ax-ad-leadgen" data-ad-id="${e.original.id}">
157
157
  <div class="ax-ad-leadgen-content">
158
158
  ${t.title ? `<h3 class="ax-ad-leadgen-title">${t.title}</h3>` : ""}
159
159
  ${t.body ? `<p class="ax-ad-leadgen-body">${m(t.body)}</p>` : ""}
160
160
  <a
161
- href="${i}"
161
+ href="${n}"
162
162
  class="ax-ad-leadgen-cta"
163
163
  target="_blank"
164
164
  rel="sponsored noopener noreferrer"
@@ -178,24 +178,24 @@ class v {
178
178
  * @param renderFn - Render function to use
179
179
  * @returns HTML string with all ads
180
180
  */
181
- static renderAds(e, t = v.renderActionCard.bind(v)) {
181
+ static renderAds(e, t = I.renderActionCard.bind(I)) {
182
182
  return e.map(t).join(`
183
183
  `);
184
184
  }
185
185
  }
186
- const L = "ad_session_id";
187
- function R() {
186
+ const P = "ad_session_id";
187
+ function K() {
188
188
  if (typeof window < "u") {
189
189
  const r = window.__AD_CONFIG__;
190
190
  if (r != null && r.apiKey)
191
191
  return r.apiKey;
192
192
  }
193
193
  }
194
- function K() {
194
+ function B() {
195
195
  var r;
196
196
  return typeof window < "u" ? !!((r = window.__AD_CONFIG__) != null && r.debug) : !1;
197
197
  }
198
- function U(r) {
198
+ function $(r) {
199
199
  if (r) return r;
200
200
  if (typeof window < "u") {
201
201
  const e = window.__AD_CONFIG__;
@@ -204,9 +204,9 @@ function U(r) {
204
204
  }
205
205
  return "/api/v1";
206
206
  }
207
- class P {
207
+ class M {
208
208
  constructor(e = {}) {
209
- this.memoryCache = /* @__PURE__ */ new Map(), this.sessionKey = e.sessionKey || L, this.storage = e.storage || "sessionStorage", (typeof window > "u" || typeof window.sessionStorage > "u") && (this.storage = "memory");
209
+ this.memoryCache = /* @__PURE__ */ new Map(), this.sessionKey = e.sessionKey || P, this.storage = e.storage || "sessionStorage", (typeof window > "u" || typeof window.sessionStorage > "u") && (this.storage = "memory");
210
210
  }
211
211
  /**
212
212
  * 获取 Session ID
@@ -240,7 +240,7 @@ class P {
240
240
  this.storage === "sessionStorage" ? sessionStorage.removeItem(this.sessionKey) : this.memoryCache.delete(this.sessionKey);
241
241
  }
242
242
  }
243
- const N = new P(), w = () => N.getSessionId();
243
+ const R = new M(), w = () => R.getSessionId();
244
244
  class A {
245
245
  constructor(e = {}) {
246
246
  this.explicitBaseUrl = e.baseUrl, this.timeout = e.timeout || 1e4, this.retryAttempts = e.retryAttempts ?? 2, this.retryDelay = e.retryDelay || 1e3, this.debug = e.debug || !1;
@@ -250,7 +250,7 @@ class A {
250
250
  */
251
251
  async trackImpression(e) {
252
252
  return this.sendRequest(
253
- `${U(this.explicitBaseUrl)}/ads/impression`,
253
+ `${$(this.explicitBaseUrl)}/ads/impression`,
254
254
  e,
255
255
  "impression"
256
256
  );
@@ -260,7 +260,7 @@ class A {
260
260
  */
261
261
  async trackClick(e) {
262
262
  return this.sendRequest(
263
- `${U(this.explicitBaseUrl)}/ads/click`,
263
+ `${$(this.explicitBaseUrl)}/ads/click`,
264
264
  e,
265
265
  "click"
266
266
  );
@@ -269,16 +269,16 @@ class A {
269
269
  * 通用请求发送方法(带重试)
270
270
  * 自动添加 X-API-Key header
271
271
  */
272
- async sendRequest(e, t, i) {
272
+ async sendRequest(e, t, n) {
273
273
  let s = null;
274
- for (let n = 0; n <= this.retryAttempts; n++) {
275
- const o = this.debug || K();
274
+ for (let i = 0; i <= this.retryAttempts; i++) {
275
+ const o = this.debug || B();
276
276
  try {
277
- o && (console.log(`[Analytics] Request URL (${i}):`, e), console.log(`[Analytics] Sending ${i} event (attempt ${n + 1}):`, t));
277
+ o && (console.log(`[Analytics] Request URL (${n}):`, e), console.log(`[Analytics] Sending ${n} event (attempt ${i + 1}):`, t));
278
278
  const a = new AbortController(), c = setTimeout(() => a.abort(), this.timeout), u = {
279
279
  "Content-Type": "application/json"
280
- }, l = R();
281
- l && (u["X-API-Key"] = l, o && console.log(`[Analytics] Adding X-API-Key header for ${i} event`));
280
+ }, l = K();
281
+ l && (u["X-API-Key"] = l, o && console.log(`[Analytics] Adding X-API-Key header for ${n} event`));
282
282
  const d = await fetch(e, {
283
283
  method: "POST",
284
284
  headers: u,
@@ -288,13 +288,13 @@ class A {
288
288
  });
289
289
  if (clearTimeout(c), !d.ok)
290
290
  throw new Error(`HTTP ${d.status}: ${d.statusText}`);
291
- const h = await d.json();
292
- return o && console.log(`[Analytics] ${i} event tracked successfully:`, h), h;
291
+ const f = await d.json();
292
+ return o && console.log(`[Analytics] ${n} event tracked successfully:`, f), f;
293
293
  } catch (a) {
294
- s = a, o && console.warn(`[Analytics] ${i} tracking failed (attempt ${n + 1}):`, a), n < this.retryAttempts && await this.delay(this.retryDelay * (n + 1));
294
+ s = a, o && console.warn(`[Analytics] ${n} tracking failed (attempt ${i + 1}):`, a), i < this.retryAttempts && await this.delay(this.retryDelay * (i + 1));
295
295
  }
296
296
  }
297
- return console.error(`[Analytics] ${i} tracking failed after ${this.retryAttempts + 1} attempts:`, s), null;
297
+ return console.error(`[Analytics] ${n} tracking failed after ${this.retryAttempts + 1} attempts:`, s), null;
298
298
  }
299
299
  /**
300
300
  * 延迟辅助方法
@@ -303,32 +303,32 @@ class A {
303
303
  return new Promise((t) => setTimeout(t, e));
304
304
  }
305
305
  }
306
- const O = new A(), S = (r, e) => e != null && e.baseUrl ? new A({ baseUrl: e.baseUrl }).trackImpression(r) : O.trackImpression(r), B = (r, e) => e != null && e.baseUrl ? new A({ baseUrl: e.baseUrl }).trackClick(r) : O.trackClick(r);
307
- function j(r, e) {
306
+ const T = new A(), b = (r, e) => e != null && e.baseUrl ? new A({ baseUrl: e.baseUrl }).trackImpression(r) : T.trackImpression(r), O = (r, e) => e != null && e.baseUrl ? new A({ baseUrl: e.baseUrl }).trackClick(r) : T.trackClick(r);
307
+ function z(r, e) {
308
308
  return `vt_${r}_${e}`;
309
309
  }
310
310
  async function W(r) {
311
- return Promise.all(r.map((e) => S(e)));
311
+ return Promise.all(r.map((e) => b(e)));
312
312
  }
313
- async function Q(r) {
314
- return Promise.all(r.map((e) => B(e)));
313
+ async function J(r) {
314
+ return Promise.all(r.map((e) => O(e)));
315
315
  }
316
- function J(r) {
316
+ function X(r) {
317
317
  const e = new A(r);
318
318
  return {
319
319
  trackImpression: (t) => e.trackImpression(t),
320
320
  trackClick: (t) => e.trackClick(t)
321
321
  };
322
322
  }
323
- function X(r = {}) {
324
- const e = new P(r);
323
+ function Z(r = {}) {
324
+ const e = new M(r);
325
325
  return {
326
326
  getSessionId: () => e.getSessionId(),
327
327
  regenerateSessionId: () => e.regenerateSessionId(),
328
328
  clearSessionId: () => e.clearSessionId()
329
329
  };
330
330
  }
331
- const C = class C {
331
+ const U = class U {
332
332
  static isDebugEnabled() {
333
333
  var e;
334
334
  return typeof window < "u" ? !!((e = window.__AD_CONFIG__) != null && e.debug) : !1;
@@ -342,81 +342,81 @@ const C = class C {
342
342
  /**
343
343
  * Render Action Card ad into container
344
344
  */
345
- static renderActionCard(e, t, i = {}) {
346
- t.innerHTML = v.renderActionCard(e, i);
345
+ static renderActionCard(e, t, n = {}) {
346
+ t.innerHTML = I.renderActionCard(e, n);
347
347
  const s = t.querySelector(".ax-ad-card-link");
348
- return s && s.addEventListener("click", (n) => {
349
- n.preventDefault(), this.handleClick(e, i);
350
- }), this.trackImpression(e, t, i), t;
348
+ return s && s.addEventListener("click", (i) => {
349
+ i.preventDefault(), this.handleClick(e, n);
350
+ }), this.trackImpression(e, t, n), t;
351
351
  }
352
352
  /**
353
353
  * Render Suffix ad into container
354
354
  */
355
- static renderSuffixAd(e, t, i = {}) {
356
- const s = i.variant || "block";
355
+ static renderSuffixAd(e, t, n = {}) {
356
+ const s = n.variant || "block";
357
357
  t.innerHTML = this.generateSuffixAdHTML(e, s);
358
- const n = t.querySelector(".ax-ad-suffix-link");
359
- return n && n.addEventListener("click", (o) => {
360
- o.preventDefault(), this.handleClick(e, i);
361
- }), this.trackImpression(e, t, i), t;
358
+ const i = t.querySelector(".ax-ad-suffix-link");
359
+ return i && i.addEventListener("click", (o) => {
360
+ o.preventDefault(), this.handleClick(e, n);
361
+ }), this.trackImpression(e, t, n), t;
362
362
  }
363
363
  /**
364
364
  * Render Sponsored Source ad into container
365
365
  */
366
- static renderSponsoredSource(e, t, i = {}) {
367
- const s = i.variant || "card";
366
+ static renderSponsoredSource(e, t, n = {}) {
367
+ const s = n.variant || "card";
368
368
  t.innerHTML = this.generateSponsoredSourceHTML(e, s);
369
- const n = t.querySelector(".ax-ad-source-link");
370
- return n && n.addEventListener("click", (o) => {
371
- o.preventDefault(), this.handleClick(e, i);
372
- }), this.trackImpression(e, t, i), t;
369
+ const i = t.querySelector(".ax-ad-source-link");
370
+ return i && i.addEventListener("click", (o) => {
371
+ o.preventDefault(), this.handleClick(e, n);
372
+ }), this.trackImpression(e, t, n), t;
373
373
  }
374
374
  /**
375
375
  * Render Lead Gen ad into container
376
376
  */
377
- static renderLeadGenAd(e, t, i = {}) {
378
- t.innerHTML = v.renderLeadGenAd(e);
377
+ static renderLeadGenAd(e, t, n = {}) {
378
+ t.innerHTML = I.renderLeadGenAd(e);
379
379
  const s = t.querySelector(".ax-ad-leadgen-cta");
380
- return s && s.addEventListener("click", (n) => {
381
- n.preventDefault(), this.handleClick(e, i);
382
- }), this.trackImpression(e, t, i), t;
380
+ return s && s.addEventListener("click", (i) => {
381
+ i.preventDefault(), this.handleClick(e, n);
382
+ }), this.trackImpression(e, t, n), t;
383
383
  }
384
384
  /**
385
385
  * Render multiple ads into container
386
386
  */
387
- static renderAds(e, t, i = this.renderActionCard.bind(this), s) {
387
+ static renderAds(e, t, n = this.renderActionCard.bind(this), s) {
388
388
  t.innerHTML = "";
389
- const n = document.createElement("div");
390
- return n.className = "ax-ads-container", e.forEach((o) => {
389
+ const i = document.createElement("div");
390
+ return i.className = "ax-ads-container", e.forEach((o) => {
391
391
  const a = document.createElement("div");
392
- a.className = "ax-ad-wrapper", i.call(this, o, a, s), n.appendChild(a);
393
- }), t.appendChild(n), t;
392
+ a.className = "ax-ad-wrapper", n.call(this, o, a, s), i.appendChild(a);
393
+ }), t.appendChild(i), t;
394
394
  }
395
395
  /**
396
396
  * Handle ad click
397
397
  * Directly opens click_url in a new window.
398
398
  */
399
399
  static handleClick(e, t) {
400
- const { onClick: i } = t, s = this.getClickUrl(e);
400
+ const { onClick: n } = t, s = this.getClickUrl(e);
401
401
  if (!s) {
402
402
  console.warn("[DOMRenderer] Missing click url for ad:", e.original.id);
403
403
  return;
404
404
  }
405
- i && i(e), this.isDebugEnabled() && console.log("[DOMRenderer] Redirect URL:", s), window.open(s, "_blank", "noopener,noreferrer");
405
+ n && n(e), this.isDebugEnabled() && console.log("[DOMRenderer] Redirect URL:", s), window.open(s, "_blank", "noopener,noreferrer");
406
406
  }
407
407
  /**
408
408
  * Track ad impression using IntersectionObserver (50% visible + 1000ms delay)
409
409
  * Falls back to immediate tracking if IntersectionObserver is unavailable.
410
410
  */
411
- static trackImpression(e, t, i) {
412
- 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) || ""}`;
411
+ static trackImpression(e, t, n) {
412
+ const { analytics: s, onImpression: i } = n, o = s ? `${s.requestId}:${s.slotId}:${e.original.id}:${this.getViewToken(e) || ""}` : `no-analytics:${e.original.id}:${this.getViewToken(e) || ""}`;
413
413
  if (this.trackedImpressionKeys.has(o))
414
414
  return;
415
415
  let a = !1;
416
416
  const c = () => {
417
417
  a || this.trackedImpressionKeys.has(o) || (a = !0, this.trackedImpressionKeys.add(o), u());
418
418
  }, u = () => {
419
- s ? S({
419
+ s ? b({
420
420
  requestId: s.requestId,
421
421
  adId: e.original.id,
422
422
  slotId: s.slotId,
@@ -429,24 +429,24 @@ const C = class C {
429
429
  viewToken: this.getViewToken(e),
430
430
  userId: s.userId
431
431
  }, { baseUrl: s.apiBaseUrl }).then(() => {
432
- n && n(e);
432
+ i && i(e);
433
433
  }).catch((l) => {
434
434
  console.error("[DOMRenderer] Analytics impression tracking failed:", l);
435
- }) : n && n(e);
435
+ }) : i && i(e);
436
436
  };
437
437
  if (typeof IntersectionObserver < "u") {
438
438
  let l = !1, d = null;
439
- const h = new IntersectionObserver(
440
- (f) => {
441
- f.forEach((k) => {
442
- l = k.isIntersecting && k.intersectionRatio >= 0.5, l ? d || (d = setTimeout(() => {
443
- d = null, l && (c(), h.disconnect());
439
+ const f = new IntersectionObserver(
440
+ (h) => {
441
+ h.forEach((v) => {
442
+ l = v.isIntersecting && v.intersectionRatio >= 0.5, l ? d || (d = setTimeout(() => {
443
+ d = null, l && (c(), f.disconnect());
444
444
  }, 1e3)) : d && (clearTimeout(d), d = null);
445
445
  });
446
446
  },
447
447
  { threshold: 0.5 }
448
- ), p = t.querySelector(`[data-ad-id="${e.original.id}"]`) || t;
449
- h.observe(p);
448
+ ), g = t.querySelector(`[data-ad-id="${e.original.id}"]`) || t;
449
+ f.observe(g);
450
450
  } else
451
451
  c();
452
452
  }
@@ -454,22 +454,22 @@ const C = class C {
454
454
  * Generate HTML for Suffix Ad variants
455
455
  */
456
456
  static generateSuffixAdHTML(e, t) {
457
- const i = e.adapted.title || "", s = m(e.adapted.body || "");
457
+ const n = e.adapted.title || "", s = m(e.adapted.body || "");
458
458
  return t === "inline" ? `
459
459
  <span class="ax-ad-suffix-link ax-ad-variant-inline" data-ad-id="${e.original.id}">
460
- ${i}
460
+ ${n}
461
461
  <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24" style="display:inline;vertical-align:middle;margin-left:4px">
462
462
  <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" />
463
463
  </svg>
464
464
  </span>
465
465
  ` : t === "minimal" ? `
466
466
  <span class="ax-ad-suffix-link ax-ad-variant-minimal" data-ad-id="${e.original.id}">
467
- ${i}
467
+ ${n}
468
468
  </span>
469
469
  ` : `
470
470
  <div class="ax-ad-suffix ax-ad-variant-block" data-ad-id="${e.original.id}">
471
471
  <div class="ax-ad-suffix-content">
472
- <p class="ax-ad-suffix-title">${i}</p>
472
+ <p class="ax-ad-suffix-title">${n}</p>
473
473
  <div style="display:flex;align-items:center;gap:8px;flex-shrink:0">
474
474
  <span class="ax-ad-sponsored-badge">Sponsored</span>
475
475
  <svg width="16" height="16" fill="none" stroke="#d1d5db" viewBox="0 0 24 24">
@@ -486,12 +486,12 @@ const C = class C {
486
486
  */
487
487
  static generateSponsoredSourceHTML(e, t) {
488
488
  var o;
489
- const i = e.adapted.title || "", s = m(e.adapted.body || ""), n = ((o = e.adapted.image) == null ? void 0 : o.url) || "";
489
+ const n = e.adapted.title || "", s = m(e.adapted.body || ""), i = ((o = e.adapted.image) == null ? void 0 : o.url) || "";
490
490
  return t === "list-item" ? `
491
491
  <div class="ax-ad-source ax-ad-variant-list-item" data-ad-id="${e.original.id}">
492
- ${n ? `<img src="${n}" alt="${i}" loading="lazy" />` : ""}
492
+ ${i ? `<img src="${i}" alt="${n}" loading="lazy" />` : ""}
493
493
  <div class="ax-ad-source-info">
494
- <span class="ax-ad-source-name">${i}</span>
494
+ <span class="ax-ad-source-name">${n}</span>
495
495
  <span class="ax-ad-sponsored-badge" style="font-size:9px">Ad</span>
496
496
  </div>
497
497
  <svg width="12" height="12" fill="none" stroke="#d1d5db" viewBox="0 0 24 24" style="flex-shrink:0">
@@ -501,17 +501,17 @@ const C = class C {
501
501
  ` : t === "minimal" ? `
502
502
  <div data-ad-id="${e.original.id}" style="display:inline-flex">
503
503
  <a class="ax-ad-source-link ax-ad-variant-minimal">
504
- ${n ? `<img src="${n}" alt="${i}" loading="lazy" style="width:16px;height:16px;border-radius:2px;object-fit:cover" />` : ""}
505
- <span>${i}</span>
504
+ ${i ? `<img src="${i}" alt="${n}" loading="lazy" style="width:16px;height:16px;border-radius:2px;object-fit:cover" />` : ""}
505
+ <span>${n}</span>
506
506
  <span class="ax-ad-sponsored-badge" style="font-size:9px">Ad</span>
507
507
  </a>
508
508
  </div>
509
509
  ` : `
510
510
  <div class="ax-ad-source ax-ad-variant-card" data-ad-id="${e.original.id}">
511
- ${n ? `<img src="${n}" alt="${i}" loading="lazy" style="width:48px;height:48px;border-radius:6px;object-fit:cover;flex-shrink:0" />` : ""}
511
+ ${i ? `<img src="${i}" alt="${n}" loading="lazy" style="width:48px;height:48px;border-radius:6px;object-fit:cover;flex-shrink:0" />` : ""}
512
512
  <div class="ax-ad-source-info">
513
513
  <div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">
514
- <span class="ax-ad-source-name">${i}</span>
514
+ <span class="ax-ad-source-name">${n}</span>
515
515
  <span class="ax-ad-sponsored-badge">Sponsored</span>
516
516
  </div>
517
517
  ${s ? `<p class="ax-ad-source-desc">${s}</p>` : ""}
@@ -523,9 +523,9 @@ const C = class C {
523
523
  `;
524
524
  }
525
525
  };
526
- C.trackedImpressionKeys = /* @__PURE__ */ new Set();
527
- let y = C;
528
- class T {
526
+ U.trackedImpressionKeys = /* @__PURE__ */ new Set();
527
+ let y = U;
528
+ class S {
529
529
  constructor() {
530
530
  this.cachedStaticInfo = null, this.cacheTimestamp = 0, this.CACHE_TTL = 36e5;
531
531
  }
@@ -540,10 +540,10 @@ class T {
540
540
  name: "Unknown App",
541
541
  publisher: { id: "unknown" }
542
542
  };
543
- const e = this.inferBundle(), t = this.inferAppName(), i = this.inferAppVersion(), s = this.inferPublisherId();
543
+ const e = this.inferBundle(), t = this.inferAppName(), n = this.inferAppVersion(), s = this.inferPublisherId();
544
544
  return {
545
545
  bundle: e,
546
- ver: i,
546
+ ver: n,
547
547
  name: t,
548
548
  publisher: {
549
549
  id: s,
@@ -564,15 +564,15 @@ class T {
564
564
  * 自动推断应用名称
565
565
  */
566
566
  inferAppName() {
567
- var s, n;
567
+ var s, i;
568
568
  if (typeof document > "u") return "Unknown App";
569
569
  const e = document.title;
570
570
  if (e && e !== "Loading..." && e.length < 100)
571
571
  return e;
572
572
  const t = (s = document.querySelector('meta[property="og:title"]')) == null ? void 0 : s.getAttribute("content");
573
573
  if (t) return t;
574
- const i = (n = document.querySelector('meta[name="application-name"]')) == null ? void 0 : n.getAttribute("content");
575
- return i || "Unknown App";
574
+ const n = (i = document.querySelector('meta[name="application-name"]')) == null ? void 0 : i.getAttribute("content");
575
+ return n || "Unknown App";
576
576
  }
577
577
  /**
578
578
  * 自动推断应用版本
@@ -587,11 +587,11 @@ class T {
587
587
  // 从manifest.json读取
588
588
  ];
589
589
  for (const t of e) {
590
- const i = document.querySelector(t);
591
- if (i) {
590
+ const n = document.querySelector(t);
591
+ if (n) {
592
592
  if (t.includes("manifest"))
593
593
  return "1.0.0";
594
- const s = i.getAttribute("content");
594
+ const s = n.getAttribute("content");
595
595
  if (s) return s;
596
596
  }
597
597
  }
@@ -601,9 +601,9 @@ class T {
601
601
  * 自动推断publisher ID
602
602
  */
603
603
  inferPublisherId() {
604
- var i, s;
604
+ var n, s;
605
605
  if (typeof document > "u") return "unknown";
606
- const e = (i = document.querySelector('meta[name="publisher-id"]')) == null ? void 0 : i.getAttribute("content");
606
+ const e = (n = document.querySelector('meta[name="publisher-id"]')) == null ? void 0 : n.getAttribute("content");
607
607
  if (e) return e;
608
608
  const t = (s = window.location) == null ? void 0 : s.hostname;
609
609
  return t ? t.replace(/\./g, "_") : "unknown";
@@ -612,7 +612,7 @@ class T {
612
612
  * Get singleton instance
613
613
  */
614
614
  static getInstance() {
615
- return this.instance || (this.instance = new T()), this.instance;
615
+ return this.instance || (this.instance = new S()), this.instance;
616
616
  }
617
617
  /**
618
618
  * Collect all available client information
@@ -622,7 +622,7 @@ class T {
622
622
  collect(e) {
623
623
  const t = Date.now();
624
624
  (!this.cachedStaticInfo || t - this.cacheTimestamp > this.CACHE_TTL) && (this.cachedStaticInfo = this.collectStaticInfo(), this.cacheTimestamp = t);
625
- const i = this.collectDynamicInfo();
625
+ const n = this.collectDynamicInfo();
626
626
  return {
627
627
  device: {
628
628
  ua: this.cachedStaticInfo.ua,
@@ -632,8 +632,8 @@ class T {
632
632
  model: this.cachedStaticInfo.model,
633
633
  make: this.cachedStaticInfo.make,
634
634
  language: this.cachedStaticInfo.language,
635
- connectiontype: i.connectiontype ?? 0,
636
- bandwidth: i.bandwidth,
635
+ connectiontype: n.connectiontype ?? 0,
636
+ bandwidth: n.bandwidth,
637
637
  ...(e == null ? void 0 : e.device) || {}
638
638
  // App overrides
639
639
  },
@@ -663,11 +663,11 @@ class T {
663
663
  collectStaticInfo() {
664
664
  if (typeof navigator > "u")
665
665
  return this.getFallbackInfo();
666
- const e = navigator.userAgent, t = this.detectOS(e), i = this.detectOSVersion(e);
666
+ const e = navigator.userAgent, t = this.detectOS(e), n = this.detectOSVersion(e);
667
667
  return {
668
668
  ua: e,
669
669
  os: t,
670
- osv: i,
670
+ osv: n,
671
671
  devicetype: this.detectDeviceType(e),
672
672
  model: this.detectModel(e),
673
673
  make: this.detectMake(e),
@@ -731,14 +731,14 @@ class T {
731
731
  const t = e.match(/OS (\d+)_(\d+)_?(\d+)?/);
732
732
  if (t)
733
733
  return `${t[1]}.${t[2]}${t[3] ? "." + t[3] : ""}`;
734
- const i = e.match(/Android (\d+)\.(\d+)/);
735
- if (i)
736
- return `${i[1]}.${i[2]}`;
734
+ const n = e.match(/Android (\d+)\.(\d+)/);
735
+ if (n)
736
+ return `${n[1]}.${n[2]}`;
737
737
  const s = e.match(/Windows NT (\d+\.\d+)/);
738
738
  if (s)
739
739
  return s[1];
740
- const n = e.match(/Mac OS X (\d+[._]\d+)/);
741
- return n ? n[1].replace("_", ".") : "Unknown";
740
+ const i = e.match(/Mac OS X (\d+[._]\d+)/);
741
+ return i ? i[1].replace("_", ".") : "Unknown";
742
742
  }
743
743
  /**
744
744
  * Detect Device Type (OpenRTB standard)
@@ -760,13 +760,13 @@ class T {
760
760
  const t = e.match(/iPhone(?:;\s*[^\)]*)?\s*(\d+,\d)?/);
761
761
  if (t) return `iPhone${t[1] || ""}`;
762
762
  if (/iPad/.test(e)) return "iPad";
763
- const i = e.match(/Samsung-.*(SM-\w+)/);
764
- if (i) return i[1];
763
+ const n = e.match(/Samsung-.*(SM-\w+)/);
764
+ if (n) return n[1];
765
765
  if (/Pixel/.test(e)) return "Google Pixel";
766
766
  const s = e.match(/(BARC-|HUAWEI-)?([A-Z]{2}\-\w{4})/);
767
767
  if (s) return s[2];
768
- const n = e.match(/(MI|Redmi|POCO)\s([\w\s]+)/);
769
- if (n) return n[1] + " " + n[2];
768
+ const i = e.match(/(MI|Redmi|POCO)\s([\w\s]+)/);
769
+ if (i) return i[1] + " " + i[2];
770
770
  if (/OnePlus/.test(e)) {
771
771
  const o = e.match(/OnePlus\s([A-Z\d]+)/);
772
772
  return o ? "OnePlus " + o[1] : "OnePlus";
@@ -834,7 +834,7 @@ class T {
834
834
  */
835
835
  inferCountry(e, t) {
836
836
  if (!e && !t) return;
837
- const i = {
837
+ const n = {
838
838
  "Asia/Shanghai": "CN",
839
839
  "Asia/Hong_Kong": "HK",
840
840
  "Asia/Taipei": "TW",
@@ -879,8 +879,8 @@ class T {
879
879
  "Australia/Sydney": "AU",
880
880
  "Pacific/Auckland": "NZ"
881
881
  };
882
- if (t && i[t])
883
- return i[t];
882
+ if (t && n[t])
883
+ return n[t];
884
884
  if (e) {
885
885
  const s = e.split("-")[1];
886
886
  if (s)
@@ -915,35 +915,35 @@ class T {
915
915
  this.cachedStaticInfo = null, this.cacheTimestamp = 0;
916
916
  }
917
917
  }
918
- const $ = () => T.getInstance();
919
- function b(r) {
920
- return $().collect(r);
918
+ const C = () => S.getInstance();
919
+ function k(r) {
920
+ return C().collect(r);
921
921
  }
922
- function Z() {
923
- return b().device;
922
+ function Y() {
923
+ return k().device;
924
924
  }
925
- function H() {
926
- return b().user;
925
+ function N() {
926
+ return k().user;
927
927
  }
928
- function Y() {
929
- return b().app;
928
+ function Q() {
929
+ return k().app;
930
930
  }
931
931
  function ee() {
932
- return b().geo;
932
+ return k().geo;
933
933
  }
934
- function D() {
935
- return H().id;
934
+ function H() {
935
+ return N().id;
936
936
  }
937
937
  function te() {
938
- $().clearCache();
938
+ C().clearCache();
939
939
  }
940
- function ie(r) {
941
- const e = b(r);
940
+ function ne(r) {
941
+ const e = k(r);
942
942
  return JSON.stringify(e, null, 2);
943
943
  }
944
944
  function se() {
945
945
  var t;
946
- const r = b();
946
+ const r = k();
947
947
  return [
948
948
  r.device.os,
949
949
  r.device.osv,
@@ -952,11 +952,33 @@ function se() {
952
952
  ((t = r.geo) == null ? void 0 : t.country) || "Unknown"
953
953
  ].join(" / ");
954
954
  }
955
- function M() {
955
+ function L() {
956
+ if (typeof crypto > "u" || !crypto.subtle)
957
+ throw new Error("Web Crypto API not supported");
958
+ }
959
+ async function G(r, e) {
960
+ L();
961
+ const t = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(e)), n = await crypto.subtle.importKey("raw", t, "AES-GCM", !1, ["encrypt"]), s = crypto.getRandomValues(new Uint8Array(12)), i = await crypto.subtle.encrypt(
962
+ { name: "AES-GCM", iv: s },
963
+ n,
964
+ new TextEncoder().encode(r)
965
+ ), o = new Uint8Array(s.length + i.byteLength);
966
+ return o.set(s), o.set(new Uint8Array(i), s.length), btoa(String.fromCharCode(...o));
967
+ }
968
+ async function F(r, e) {
969
+ L();
970
+ const t = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(e)), n = await crypto.subtle.importKey("raw", t, "AES-GCM", !1, ["decrypt"]), s = Uint8Array.from(atob(r), (c) => c.charCodeAt(0)), i = s.slice(0, 12), o = s.slice(12), a = await crypto.subtle.decrypt(
971
+ { name: "AES-GCM", iv: i },
972
+ n,
973
+ o
974
+ );
975
+ return new TextDecoder().decode(a);
976
+ }
977
+ function D() {
956
978
  var r;
957
979
  return typeof window < "u" ? !!((r = window.__AD_CONFIG__) != null && r.debug) : !1;
958
980
  }
959
- function ne(r) {
981
+ function ie(r) {
960
982
  var e, t;
961
983
  return {
962
984
  id: r.original.id,
@@ -983,37 +1005,51 @@ function ne(r) {
983
1005
  }
984
1006
  };
985
1007
  }
986
- async function F(r, e = {}) {
987
- const t = e.apiBaseUrl || "/api/v1", s = $().collect(), n = {
1008
+ async function V(r, e = {}) {
1009
+ const t = e.apiBaseUrl || "/api/v1", n = D(), i = C().collect(), o = {
988
1010
  ...r,
989
- clientInfo: s
990
- // Auto-injected
991
- }, o = {
1011
+ clientInfo: i
1012
+ }, a = {
992
1013
  "Content-Type": "application/json"
993
1014
  };
994
- 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));
995
- const a = await fetch(`${t}/ads/request`, {
1015
+ e.apiKey && (a["X-API-Key"] = e.apiKey);
1016
+ let c;
1017
+ if (e.apiKey && !n)
1018
+ try {
1019
+ c = { encryptedPayload: await G(JSON.stringify(o), e.apiKey) };
1020
+ } catch (f) {
1021
+ n && console.warn("[fetchAds] Encryption failed, using plaintext:", f), c = o;
1022
+ }
1023
+ else
1024
+ c = o;
1025
+ n && (console.log("[fetchAds] Request URL:", `${t}/ads/request`), console.log("[fetchAds] Request body:", c));
1026
+ const u = await fetch(`${t}/ads/request`, {
996
1027
  method: "POST",
997
- headers: o,
998
- body: JSON.stringify(n)
1028
+ headers: a,
1029
+ body: JSON.stringify(c)
999
1030
  });
1000
- if (!a.ok)
1001
- throw new Error(`Ad request failed: ${a.status} ${a.statusText}`);
1002
- const c = await a.json();
1003
- if (M() && console.log("[fetchAds] Response:", c), !c.success)
1004
- throw new Error(c.error || "Ad request failed");
1005
- return c.data;
1031
+ if (!u.ok)
1032
+ throw new Error(`Ad request failed: ${u.status} ${u.statusText}`);
1033
+ const l = await u.json();
1034
+ if (!l.success)
1035
+ throw new Error(l.error || "Ad request failed");
1036
+ let d = l.data;
1037
+ if (l.data.encryptedPayload && e.apiKey) {
1038
+ const f = await F(l.data.encryptedPayload, e.apiKey);
1039
+ d = JSON.parse(f);
1040
+ }
1041
+ return n && console.log("[fetchAds] Response:", d), d;
1006
1042
  }
1007
- const G = { width: 400, height: 200 }, I = {
1043
+ const j = { width: 400, height: 200 }, x = {
1008
1044
  variant: "horizontal",
1009
1045
  count: 1,
1010
1046
  preferences: {}
1011
1047
  };
1012
1048
  function _(r = {}) {
1013
1049
  const e = {
1014
- variant: r.variant ?? I.variant,
1015
- count: r.count ?? I.count,
1016
- preferences: { ...I.preferences, ...r.preferences }
1050
+ variant: r.variant ?? x.variant,
1051
+ count: r.count ?? x.count,
1052
+ preferences: { ...x.preferences, ...r.preferences }
1017
1053
  };
1018
1054
  return [
1019
1055
  {
@@ -1021,14 +1057,14 @@ function _(r = {}) {
1021
1057
  slotName: "Action Card",
1022
1058
  format: "action_card",
1023
1059
  variant: e.variant,
1024
- size: G,
1060
+ size: j,
1025
1061
  count: e.count,
1026
1062
  preferences: e.preferences,
1027
1063
  placement: { position: "below_fold", context: "post_response" }
1028
1064
  }
1029
1065
  ];
1030
1066
  }
1031
- const g = class g {
1067
+ const p = class p {
1032
1068
  constructor(e) {
1033
1069
  this.slots = {}, this.isLoading = !1, this.currentRequestId = null, this.adsAnalyticsMap = /* @__PURE__ */ new Map(), this.config = e, this.enabled = e.enabled !== !1, this.eventBus = new q(), this.slots_config = _(e.cardOption), typeof window < "u" && (window.__AD_CONFIG__ = {
1034
1070
  ...window.__AD_CONFIG__ || {},
@@ -1044,7 +1080,7 @@ const g = class g {
1044
1080
  async requestAds(e) {
1045
1081
  const t = "conversationContext" in e ? e : { conversationContext: e };
1046
1082
  this.currentUserId = this.resolveUserId(t.userContext);
1047
- const i = this.buildRequestKey(t), s = g.inFlightRequests.get(i);
1083
+ const n = this.buildRequestKey(t), s = p.inFlightRequests.get(n);
1048
1084
  if (s)
1049
1085
  return this.config.debug && console.log("[AdManager] Reusing in-flight request for identical context"), s;
1050
1086
  if (!this.enabled)
@@ -1052,9 +1088,9 @@ const g = class g {
1052
1088
  if (this.isLoading)
1053
1089
  throw this.config.debug && console.warn("[AdManager] Request already in progress"), new Error("Request already in progress");
1054
1090
  this.isLoading = !0, this.eventBus.emit("adsLoading"), this.config.debug && console.log("[AdManager] Starting ad request...");
1055
- const n = (async () => {
1091
+ const i = (async () => {
1056
1092
  try {
1057
- const o = await F(
1093
+ const o = await V(
1058
1094
  {
1059
1095
  conversationContext: t.conversationContext,
1060
1096
  userContext: t.userContext ? {
@@ -1093,10 +1129,10 @@ const g = class g {
1093
1129
  const a = o;
1094
1130
  throw this.eventBus.emit("adsError", a), a;
1095
1131
  } finally {
1096
- this.isLoading = !1, g.inFlightRequests.delete(i);
1132
+ this.isLoading = !1, p.inFlightRequests.delete(n);
1097
1133
  }
1098
1134
  })();
1099
- return g.inFlightRequests.set(i, n), n;
1135
+ return p.inFlightRequests.set(n, i), i;
1100
1136
  }
1101
1137
  buildRequestKey(e) {
1102
1138
  return JSON.stringify({
@@ -1111,30 +1147,30 @@ const g = class g {
1111
1147
  if (e != null && e.userId)
1112
1148
  return e.userId;
1113
1149
  try {
1114
- return D();
1150
+ return H();
1115
1151
  } catch {
1116
1152
  return;
1117
1153
  }
1118
1154
  }
1119
- render(e, t, i = {}) {
1120
- const s = typeof e != "string", n = s ? g.DEFAULT_SLOT_ID : e, o = s ? e : t, a = (s ? t : i) || {};
1155
+ render(e, t, n = {}) {
1156
+ const s = typeof e != "string", i = s ? p.DEFAULT_SLOT_ID : e, o = s ? e : t, a = (s ? t : n) || {};
1121
1157
  if (!o)
1122
1158
  return this.config.debug && console.warn("[AdManager] Render container is required"), null;
1123
- const c = this.slots[n];
1159
+ const c = this.slots[i];
1124
1160
  if (!c || !c.ads || c.ads.length === 0)
1125
- return this.config.debug && console.warn("[AdManager] No ads in slot:", n), null;
1161
+ return this.config.debug && console.warn("[AdManager] No ads in slot:", i), null;
1126
1162
  const u = a.adIndex ?? 0, l = c.ads[u];
1127
1163
  if (!l)
1128
- return this.config.debug && console.warn(`[AdManager] Ad at index ${u} not found in slot:`, n), null;
1129
- const d = this.adsAnalyticsMap.get(l.original.id), h = this.slots_config.find((k) => k.slotId === n), p = (h == null ? void 0 : h.format) || "action_card";
1164
+ return this.config.debug && console.warn(`[AdManager] Ad at index ${u} not found in slot:`, i), null;
1165
+ const d = this.adsAnalyticsMap.get(l.original.id), f = this.slots_config.find((v) => v.slotId === i), g = (f == null ? void 0 : f.format) || "action_card";
1130
1166
  o.innerHTML = "";
1131
- const f = {
1167
+ const h = {
1132
1168
  analytics: d,
1133
1169
  variant: a.variant,
1134
1170
  onClick: a.onClick,
1135
1171
  onImpression: a.onImpression
1136
1172
  };
1137
- return p === "suffix" ? y.renderSuffixAd(l, o, f) : p === "source" ? y.renderSponsoredSource(l, o, f) : p === "lead_gen" ? y.renderLeadGenAd(l, o, f) : y.renderActionCard(l, o, f);
1173
+ return g === "suffix" ? y.renderSuffixAd(l, o, h) : g === "source" ? y.renderSponsoredSource(l, o, h) : g === "lead_gen" ? y.renderLeadGenAd(l, o, h) : y.renderActionCard(l, o, h);
1138
1174
  }
1139
1175
  /**
1140
1176
  * Get ad slots data
@@ -1146,9 +1182,9 @@ const g = class g {
1146
1182
  * Check if a slot has ads
1147
1183
  */
1148
1184
  hasAds(e) {
1149
- var i;
1185
+ var n;
1150
1186
  const t = this.slots[e];
1151
- return (t == null ? void 0 : t.status) === "filled" && ((i = t.ads) == null ? void 0 : i.length) > 0;
1187
+ return (t == null ? void 0 : t.status) === "filled" && ((n = t.ads) == null ? void 0 : n.length) > 0;
1152
1188
  }
1153
1189
  /**
1154
1190
  * Get ads for a specific slot
@@ -1216,27 +1252,27 @@ const g = class g {
1216
1252
  */
1217
1253
  getAdsAnalytics(e) {
1218
1254
  const t = /* @__PURE__ */ new Map();
1219
- return e.forEach((i) => {
1220
- const s = this.adsAnalyticsMap.get(i);
1221
- s && t.set(i, s);
1255
+ return e.forEach((n) => {
1256
+ const s = this.adsAnalyticsMap.get(n);
1257
+ s && t.set(n, s);
1222
1258
  }), t;
1223
1259
  }
1224
1260
  /**
1225
1261
  * Track ad click using Analytics API
1226
1262
  */
1227
- async trackAdClick(e, t, i) {
1263
+ async trackAdClick(e, t, n) {
1228
1264
  const s = this.adsAnalyticsMap.get(e);
1229
1265
  if (!s || !this.currentRequestId)
1230
1266
  return this.config.debug && console.warn("[AdManager] No analytics info for ad:", e), null;
1231
- const n = w(), o = await B({
1267
+ const i = w(), o = await O({
1232
1268
  requestId: this.currentRequestId,
1233
1269
  adId: e,
1234
1270
  destinationUrl: t,
1235
- sessionId: n,
1271
+ sessionId: i,
1236
1272
  slotId: s.slotId,
1237
- adTitle: i == null ? void 0 : i.title,
1238
- format: i == null ? void 0 : i.format,
1239
- source: i == null ? void 0 : i.source,
1273
+ adTitle: n == null ? void 0 : n.title,
1274
+ format: n == null ? void 0 : n.format,
1275
+ source: n == null ? void 0 : n.source,
1240
1276
  userId: s.userId ?? this.currentUserId
1241
1277
  }, { baseUrl: s.apiBaseUrl });
1242
1278
  return o && (this.eventBus.emit("adClicked", e, s.slotId), this.config.debug && console.log("[AdManager] Click tracked via Analytics API:", o.eventId)), o;
@@ -1245,23 +1281,23 @@ const g = class g {
1245
1281
  * Track ad impression using Analytics API
1246
1282
  */
1247
1283
  async trackAdImpressionAPI(e, t) {
1248
- const i = this.adsAnalyticsMap.get(e);
1249
- if (!i || !this.currentRequestId)
1284
+ const n = this.adsAnalyticsMap.get(e);
1285
+ if (!n || !this.currentRequestId)
1250
1286
  return this.config.debug && console.warn("[AdManager] No analytics info for ad:", e), null;
1251
- const s = w(), n = await S({
1287
+ const s = w(), i = await b({
1252
1288
  requestId: this.currentRequestId,
1253
1289
  adId: e,
1254
- slotId: i.slotId,
1255
- position: i.position,
1256
- totalAds: i.totalAds,
1290
+ slotId: n.slotId,
1291
+ position: n.position,
1292
+ totalAds: n.totalAds,
1257
1293
  sessionId: s,
1258
1294
  adTitle: t == null ? void 0 : t.title,
1259
1295
  format: t == null ? void 0 : t.format,
1260
1296
  source: t == null ? void 0 : t.source,
1261
1297
  viewToken: t == null ? void 0 : t.viewToken,
1262
- userId: i.userId ?? this.currentUserId
1263
- }, { baseUrl: i.apiBaseUrl });
1264
- return n && (this.eventBus.emit("adImpression", e, i.slotId), this.config.debug && console.log("[AdManager] Impression tracked via Analytics API:", n.eventId)), n;
1298
+ userId: n.userId ?? this.currentUserId
1299
+ }, { baseUrl: n.apiBaseUrl });
1300
+ return i && (this.eventBus.emit("adImpression", e, n.slotId), this.config.debug && console.log("[AdManager] Impression tracked via Analytics API:", i.eventId)), i;
1265
1301
  }
1266
1302
  /**
1267
1303
  * Destroy the manager and clean up
@@ -1270,295 +1306,37 @@ const g = class g {
1270
1306
  this.removeAllListeners(), this.clearSlots(), this.config.debug && console.log("[AdManager] Destroyed");
1271
1307
  }
1272
1308
  };
1273
- g.DEFAULT_SLOT_ID = "action_card", g.inFlightRequests = /* @__PURE__ */ new Map();
1274
- let V = g;
1275
- function E() {
1276
- if (typeof window < "u") {
1277
- const r = window.__AD_CONFIG__;
1278
- if (r != null && r.apiKey)
1279
- return r.apiKey;
1280
- }
1281
- }
1282
- class z {
1283
- constructor(e = {}, t = "/api/v1") {
1284
- var i, s;
1285
- 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 = {
1286
- minVisiblePercentage: e.minVisiblePercentage ?? 50,
1287
- minViewableDuration: e.minViewableDuration ?? 1e3,
1288
- maxTrackingDuration: e.maxTrackingDuration ?? 6e4,
1289
- batchConfig: {
1290
- maxBatchSize: ((i = e.batchConfig) == null ? void 0 : i.maxBatchSize) ?? 5,
1291
- maxBatchWaitMs: ((s = e.batchConfig) == null ? void 0 : s.maxBatchWaitMs) ?? 1e4
1292
- },
1293
- debug: e.debug ?? !1
1294
- }, this.baseUrl = t;
1295
- }
1296
- /**
1297
- * Start tracking viewability for an ad element
1298
- */
1299
- startTracking(e, t, i, s, n) {
1300
- if (this.isTracking.get(e)) {
1301
- this.log(`[ViewabilityTracker] Already tracking ${e}, skipping`);
1302
- return;
1303
- }
1304
- this.log(`[ViewabilityTracker] Starting tracking for ${e}`);
1305
- const o = {
1306
- visiblePercentage: 0,
1307
- maxVisiblePercentage: 0,
1308
- totalVisibleTimeMs: 0,
1309
- currentVisibleTimeMs: 0,
1310
- isViewable: !1,
1311
- viewableAt: null,
1312
- enteredViewportAt: null,
1313
- enterCount: 0
1314
- };
1315
- this.metrics.set(e, o), this.isTracking.set(e, !0), this.eventQueue.set(e, []);
1316
- const a = new IntersectionObserver(
1317
- (u) => this.handleIntersection(e, u[0], i, s, n),
1318
- {
1319
- threshold: this.createThresholds()
1320
- }
1321
- );
1322
- a.observe(t), this.observers.set(e, a), this.startMonitoring(e, i, s, n);
1323
- const c = setTimeout(() => {
1324
- this.endTracking(e, i, s, n);
1325
- }, this.config.maxTrackingDuration);
1326
- this.timers.set(e, c);
1327
- }
1328
- /**
1329
- * Stop tracking an ad element
1330
- */
1331
- stopTracking(e) {
1332
- this.log(`[ViewabilityTracker] Manual stop tracking for ${e}`), this.cleanup(e);
1333
- }
1334
- /**
1335
- * Get current metrics for an ad
1336
- */
1337
- getMetrics(e) {
1338
- return this.metrics.get(e);
1339
- }
1340
- /**
1341
- * Handle IntersectionObserver callback
1342
- * Event-driven: Only process when state actually changes
1343
- */
1344
- handleIntersection(e, t, i, s, n) {
1345
- const o = this.metrics.get(e);
1346
- if (!o || !this.isTracking.get(e)) return;
1347
- const a = o.isViewable, c = Math.round(t.intersectionRatio * 100);
1348
- o.visiblePercentage = c, o.maxVisiblePercentage = Math.max(o.maxVisiblePercentage, c);
1349
- const u = Date.now(), l = c >= this.config.minVisiblePercentage;
1350
- if (l && !o.enteredViewportAt && (o.enteredViewportAt = u, o.enterCount++, this.log(`[ViewabilityTracker] ${e} entered viewport at ${u}`), this.queueEvent(e, {
1351
- adId: e,
1352
- sessionId: i,
1353
- requestId: s,
1354
- viewToken: n,
1355
- eventType: "enter_viewport",
1356
- visiblePercentage: c,
1357
- maxVisiblePercentage: o.maxVisiblePercentage,
1358
- totalVisibleTimeMs: o.totalVisibleTimeMs,
1359
- isViewable: !1,
1360
- timestamp: u
1361
- })), !l && o.enteredViewportAt) {
1362
- const d = u - o.enteredViewportAt;
1363
- o.totalVisibleTimeMs += d, o.enteredViewportAt = null, o.currentVisibleTimeMs = 0, this.log(`[ViewabilityTracker] ${e} exited viewport, total visible: ${o.totalVisibleTimeMs}ms`), this.queueEvent(e, {
1364
- adId: e,
1365
- sessionId: i,
1366
- requestId: s,
1367
- viewToken: n,
1368
- eventType: "exit_viewport",
1369
- visiblePercentage: c,
1370
- maxVisiblePercentage: o.maxVisiblePercentage,
1371
- totalVisibleTimeMs: o.totalVisibleTimeMs,
1372
- isViewable: o.isViewable,
1373
- timestamp: u
1374
- });
1375
- }
1376
- o.isViewable !== a && o.isViewable && this.log(`[ViewabilityTracker] ${e} became VIEWABLE!`), this.metrics.set(e, o);
1377
- }
1378
- /**
1379
- * Start monitoring loop for tracking duration
1380
- * Runs every 100ms to track continuous visible time
1381
- */
1382
- startMonitoring(e, t, i, s) {
1383
- const o = setInterval(() => {
1384
- const a = this.metrics.get(e);
1385
- if (!a || !this.isTracking.get(e)) {
1386
- clearInterval(o);
1387
- return;
1388
- }
1389
- const c = Date.now(), u = a.isViewable;
1390
- if (a.enteredViewportAt) {
1391
- const l = c - a.enteredViewportAt;
1392
- a.currentVisibleTimeMs = l, l >= this.config.minViewableDuration && a.visiblePercentage >= this.config.minVisiblePercentage && (a.isViewable = !0, u || (a.viewableAt = a.enteredViewportAt, this.log(`[ViewabilityTracker] ${e} BECAME VIEWABLE at ${a.viewableAt}`), this.queueEvent(e, {
1393
- adId: e,
1394
- sessionId: t,
1395
- requestId: i,
1396
- viewToken: s,
1397
- eventType: "become_viewable",
1398
- visiblePercentage: a.visiblePercentage,
1399
- maxVisiblePercentage: a.maxVisiblePercentage,
1400
- totalVisibleTimeMs: a.totalVisibleTimeMs,
1401
- isViewable: !0,
1402
- timestamp: c
1403
- })));
1404
- }
1405
- a.enteredViewportAt && (a.totalVisibleTimeMs += 100), this.metrics.set(e, a);
1406
- }, 100);
1407
- this.timers.set(`${e}_monitoring`, o);
1408
- }
1409
- /**
1410
- * Queue an event to be sent (batched)
1411
- */
1412
- queueEvent(e, t) {
1413
- var n, o;
1414
- const i = this.eventQueue.get(e);
1415
- if (!i) {
1416
- this.log(`[ViewabilityTracker] No queue found for ${e}, skipping event`);
1417
- return;
1418
- }
1419
- i.push(t), this.log(`[ViewabilityTracker] Queued ${t.eventType} for ${e} (queue size: ${i.length})`);
1420
- const s = ((n = this.config.batchConfig) == null ? void 0 : n.maxBatchSize) ?? 5;
1421
- if (i.length >= s)
1422
- this.flushQueue(e);
1423
- else {
1424
- const a = this.batchTimers.get(e);
1425
- a && clearTimeout(a);
1426
- const c = ((o = this.config.batchConfig) == null ? void 0 : o.maxBatchWaitMs) ?? 1e4, u = setTimeout(() => {
1427
- this.flushQueue(e);
1428
- }, c);
1429
- this.batchTimers.set(e, u);
1430
- }
1431
- }
1432
- /**
1433
- * Flush the event queue and send to server
1434
- */
1435
- async flushQueue(e) {
1436
- const t = this.eventQueue.get(e);
1437
- if (!t || t.length === 0) return;
1438
- const i = [...t];
1439
- t.length = 0, this.log(`[ViewabilityTracker] Flushing ${i.length} events for ${e}`);
1440
- try {
1441
- const s = {
1442
- "Content-Type": "application/json"
1443
- }, n = E();
1444
- n && (s["x-api-key"] = n), await fetch(`${this.baseUrl}/ads/viewability/batch`, {
1445
- method: "POST",
1446
- headers: s,
1447
- body: JSON.stringify({ events: i })
1448
- }), this.log(`[ViewabilityTracker] Successfully sent ${i.length} events for ${e}`);
1449
- } catch (s) {
1450
- this.log(`[ViewabilityTracker] Failed to send events for ${e}:`, s), t.unshift(...i);
1451
- }
1452
- }
1453
- /**
1454
- * End tracking and send final metrics
1455
- */
1456
- endTracking(e, t, i, s) {
1457
- const n = this.metrics.get(e);
1458
- if (!n) return;
1459
- this.log(`[ViewabilityTracker] Ending tracking for ${e}`), this.flushQueue(e);
1460
- const o = Date.now();
1461
- this.queueEvent(e, {
1462
- adId: e,
1463
- sessionId: t,
1464
- requestId: i,
1465
- viewToken: s,
1466
- eventType: "end_tracking",
1467
- visiblePercentage: n.visiblePercentage,
1468
- maxVisiblePercentage: n.maxVisiblePercentage,
1469
- totalVisibleTimeMs: n.totalVisibleTimeMs,
1470
- isViewable: n.isViewable,
1471
- timestamp: o
1472
- }), this.flushQueue(e), this.cleanup(e);
1473
- }
1474
- /**
1475
- * Cleanup resources for an ad
1476
- */
1477
- cleanup(e) {
1478
- const t = this.observers.get(e);
1479
- t && (t.disconnect(), this.observers.delete(e));
1480
- const i = this.timers.get(e);
1481
- i && (clearTimeout(i), this.timers.delete(e));
1482
- const s = this.timers.get(`${e}_monitoring`);
1483
- s && (clearInterval(s), this.timers.delete(`${e}_monitoring`));
1484
- const n = this.batchTimers.get(e);
1485
- n && (clearTimeout(n), this.batchTimers.delete(e)), this.flushQueue(e), this.isTracking.delete(e), this.metrics.delete(e), this.eventQueue.delete(e);
1486
- }
1487
- /**
1488
- * Create thresholds for IntersectionObserver
1489
- */
1490
- createThresholds() {
1491
- return [0, 0.25, 0.5, 0.75, 0.9, 1];
1492
- }
1493
- /**
1494
- * Stop all tracking
1495
- */
1496
- stopAll() {
1497
- const e = Array.from(this.isTracking.keys());
1498
- for (const t of e)
1499
- this.cleanup(t);
1500
- }
1501
- /**
1502
- * Debug logging
1503
- */
1504
- log(...e) {
1505
- this.config.debug && console.log(...e);
1506
- }
1507
- /**
1508
- * Send any pending events before page unload
1509
- */
1510
- setupBeforeUnload() {
1511
- typeof window < "u" && window.addEventListener("beforeunload", () => {
1512
- for (const e of this.eventQueue.keys()) {
1513
- const t = this.eventQueue.get(e);
1514
- if (t && t.length > 0) {
1515
- const i = {
1516
- "Content-Type": "application/json"
1517
- }, s = E();
1518
- s && (i["x-api-key"] = s), fetch(`${this.baseUrl}/ads/viewability/batch`, {
1519
- method: "POST",
1520
- headers: i,
1521
- keepalive: !0,
1522
- body: JSON.stringify({ events: t })
1523
- });
1524
- }
1525
- }
1526
- });
1527
- }
1528
- }
1529
- let x = null;
1530
- function re(r, e) {
1531
- return x || (x = new z(r, e), x.setupBeforeUnload()), x;
1532
- }
1533
- const oe = "0.1.0";
1309
+ p.DEFAULT_SLOT_ID = "action_card", p.inFlightRequests = /* @__PURE__ */ new Map();
1310
+ let E = p;
1311
+ const re = "0.1.0";
1534
1312
  export {
1535
- V as AdManager,
1313
+ E as AdManager,
1536
1314
  A as AnalyticsSender,
1537
- T as ClientInfoCollector,
1315
+ S as ClientInfoCollector,
1538
1316
  y as DOMRenderer,
1539
- v as HTMLRenderer,
1540
- oe as SDK_VERSION,
1541
- P as SessionManager,
1542
- z as ViewabilityTracker,
1543
- ne as adaptAdToKoahAd,
1317
+ I as HTMLRenderer,
1318
+ re as SDK_VERSION,
1319
+ M as SessionManager,
1320
+ ie as adaptAdToKoahAd,
1544
1321
  te as clearClientInfoCache,
1545
- J as createAnalytics,
1546
- X as createSession,
1547
- F as fetchAds,
1548
- j as generateViewToken,
1549
- Y as getAppInfo,
1550
- b as getClientInfo,
1551
- $ as getClientInfoCollector,
1552
- ie as getClientInfoJSON,
1322
+ X as createAnalytics,
1323
+ Z as createSession,
1324
+ F as decryptAES,
1325
+ G as encryptAES,
1326
+ V as fetchAds,
1327
+ z as generateViewToken,
1328
+ Q as getAppInfo,
1329
+ k as getClientInfo,
1330
+ C as getClientInfoCollector,
1331
+ ne as getClientInfoJSON,
1553
1332
  se as getClientInfoSummary,
1554
- Z as getDeviceInfo,
1333
+ Y as getDeviceInfo,
1555
1334
  ee as getGeoInfo,
1556
1335
  w as getSessionId,
1557
- D as getUserId,
1558
- H as getUserInfo,
1559
- re as getViewabilityTracker,
1560
- B as trackAdClick,
1561
- S as trackAdImpression,
1562
- Q as trackClicksBatch,
1336
+ H as getUserId,
1337
+ N as getUserInfo,
1338
+ O as trackAdClick,
1339
+ b as trackAdImpression,
1340
+ J as trackClicksBatch,
1563
1341
  W as trackImpressionsBatch
1564
1342
  };