@action-x/ad-sdk 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- class O {
1
+ class B {
2
2
  constructor() {
3
3
  this.events = {};
4
4
  }
@@ -61,32 +61,27 @@ class w {
61
61
  */
62
62
  static renderActionCard(e, t = {}) {
63
63
  var f;
64
- const { variant: i = "horizontal", includeWrapper: s = !0 } = t, n = e.adapted, o = this.getClickUrl(e), a = this.getImpressionUrl(e), c = s ? `<div class="ax-ad-card ax-ad-card-${i}" data-ad-id="${e.original.id}">` : "", l = (f = n.image) != null && f.url ? `<img
64
+ const { variant: i = "horizontal", includeWrapper: s = !0 } = t, n = e.adapted, r = this.getClickUrl(e), a = this.getImpressionUrl(e), c = (f = n.image) != null && f.url ? `<img
65
65
  src="${n.image.url}"
66
66
  alt="${n.title}"
67
67
  class="ax-ad-image"
68
68
  loading="lazy"
69
- />` : "", d = (n.brand || "").trim(), u = d && d.toLowerCase() !== "unknown" ? `<span class="ax-ad-brand">${n.brand}</span>` : "", h = `
70
- ${l}
69
+ />` : "", d = (n.brand || "").trim(), l = d && d.toLowerCase() !== "unknown" ? `<span class="ax-ad-brand">${n.brand}</span>` : "", u = `
70
+ ${c}
71
71
  <div class="ax-ad-content">
72
- ${u}
72
+ ${l}
73
73
  <h3 class="ax-ad-title">${n.title}</h3>
74
74
  ${n.body ? `<p class="ax-ad-body">${n.body}</p>` : ""}
75
- <div class="ax-ad-footer">
76
- <a
77
- href="${o}"
78
- class="ax-ad-cta"
79
- target="_blank"
80
- rel="sponsored noopener noreferrer"
81
- data-ad-id="${e.original.id}"
82
- data-impression-url="${a}"
83
- >
84
- ${this.getCtaText(e)}
85
- </a>
86
- </div>
87
75
  </div>
88
- `, p = s ? "</div>" : "";
89
- return c + h + p;
76
+ `, h = s ? `<a
77
+ href="${r}"
78
+ class="ax-ad-card ax-ad-card-${i} ax-ad-card-link"
79
+ target="_blank"
80
+ rel="sponsored noopener noreferrer"
81
+ data-ad-id="${e.original.id}"
82
+ data-impression-url="${a}"
83
+ >` : "", p = s ? "</a>" : "";
84
+ return h + u + p;
90
85
  }
91
86
  /**
92
87
  * Render Suffix ad as HTML string
@@ -186,17 +181,17 @@ class w {
186
181
  const q = "ad_session_id";
187
182
  function L() {
188
183
  if (typeof window < "u") {
189
- const r = window.__AD_CONFIG__;
190
- if (r != null && r.apiKey)
191
- return r.apiKey;
184
+ const o = window.__AD_CONFIG__;
185
+ if (o != null && o.apiKey)
186
+ return o.apiKey;
192
187
  }
193
188
  }
194
189
  function R() {
195
- var r;
196
- return typeof window < "u" ? !!((r = window.__AD_CONFIG__) != null && r.debug) : !1;
190
+ var o;
191
+ return typeof window < "u" ? !!((o = window.__AD_CONFIG__) != null && o.debug) : !1;
197
192
  }
198
- function U(r) {
199
- if (r) return r;
193
+ function U(o) {
194
+ if (o) return o;
200
195
  if (typeof window < "u") {
201
196
  const e = window.__AD_CONFIG__;
202
197
  if (e != null && e.apiBaseUrl)
@@ -272,16 +267,16 @@ class x {
272
267
  async sendRequest(e, t, i) {
273
268
  let s = null;
274
269
  for (let n = 0; n <= this.retryAttempts; n++) {
275
- const o = this.debug || R();
270
+ const r = this.debug || R();
276
271
  try {
277
- o && (console.log(`[Analytics] Request URL (${i}):`, e), console.log(`[Analytics] Sending ${i} event (attempt ${n + 1}):`, t));
278
- const a = new AbortController(), c = setTimeout(() => a.abort(), this.timeout), l = {
272
+ r && (console.log(`[Analytics] Request URL (${i}):`, e), console.log(`[Analytics] Sending ${i} event (attempt ${n + 1}):`, t));
273
+ const a = new AbortController(), c = setTimeout(() => a.abort(), this.timeout), d = {
279
274
  "Content-Type": "application/json"
280
- }, d = L();
281
- d && (l["X-API-Key"] = d, o && console.log(`[Analytics] Adding X-API-Key header for ${i} event`));
275
+ }, l = L();
276
+ l && (d["X-API-Key"] = l, r && console.log(`[Analytics] Adding X-API-Key header for ${i} event`));
282
277
  const u = await fetch(e, {
283
278
  method: "POST",
284
- headers: l,
279
+ headers: d,
285
280
  body: JSON.stringify(t),
286
281
  keepalive: !0,
287
282
  signal: a.signal
@@ -289,9 +284,9 @@ class x {
289
284
  if (clearTimeout(c), !u.ok)
290
285
  throw new Error(`HTTP ${u.status}: ${u.statusText}`);
291
286
  const h = await u.json();
292
- return o && console.log(`[Analytics] ${i} event tracked successfully:`, h), h;
287
+ return r && console.log(`[Analytics] ${i} event tracked successfully:`, h), h;
293
288
  } 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));
289
+ s = a, r && console.warn(`[Analytics] ${i} tracking failed (attempt ${n + 1}):`, a), n < this.retryAttempts && await this.delay(this.retryDelay * (n + 1));
295
290
  }
296
291
  }
297
292
  return console.error(`[Analytics] ${i} tracking failed after ${this.retryAttempts + 1} attempts:`, s), null;
@@ -303,25 +298,25 @@ class x {
303
298
  return new Promise((t) => setTimeout(t, e));
304
299
  }
305
300
  }
306
- const B = new x(), I = (r, e) => e != null && e.baseUrl ? new x({ baseUrl: e.baseUrl }).trackImpression(r) : B.trackImpression(r), T = (r, e) => e != null && e.baseUrl ? new x({ baseUrl: e.baseUrl }).trackClick(r) : B.trackClick(r);
307
- function G(r, e) {
308
- return `vt_${r}_${e}`;
301
+ const O = new x(), I = (o, e) => e != null && e.baseUrl ? new x({ baseUrl: e.baseUrl }).trackImpression(o) : O.trackImpression(o), S = (o, e) => e != null && e.baseUrl ? new x({ baseUrl: e.baseUrl }).trackClick(o) : O.trackClick(o);
302
+ function z(o, e) {
303
+ return `vt_${o}_${e}`;
309
304
  }
310
- async function z(r) {
311
- return Promise.all(r.map((e) => I(e)));
305
+ async function j(o) {
306
+ return Promise.all(o.map((e) => I(e)));
312
307
  }
313
- async function j(r) {
314
- return Promise.all(r.map((e) => T(e)));
308
+ async function W(o) {
309
+ return Promise.all(o.map((e) => S(e)));
315
310
  }
316
- function W(r) {
317
- const e = new x(r);
311
+ function Q(o) {
312
+ const e = new x(o);
318
313
  return {
319
314
  trackImpression: (t) => e.trackImpression(t),
320
315
  trackClick: (t) => e.trackClick(t)
321
316
  };
322
317
  }
323
- function Q(r = {}) {
324
- const e = new P(r);
318
+ function J(o = {}) {
319
+ const e = new P(o);
325
320
  return {
326
321
  getSessionId: () => e.getSessionId(),
327
322
  regenerateSessionId: () => e.regenerateSessionId(),
@@ -344,7 +339,7 @@ const C = class C {
344
339
  */
345
340
  static renderActionCard(e, t, i = {}) {
346
341
  t.innerHTML = w.renderActionCard(e, i);
347
- const s = t.querySelector(".ax-ad-cta");
342
+ const s = t.querySelector(".ax-ad-card-link");
348
343
  return s && s.addEventListener("click", (n) => {
349
344
  n.preventDefault(), this.handleClick(e, i);
350
345
  }), this.trackImpression(e, t, i), t;
@@ -356,8 +351,8 @@ const C = class C {
356
351
  const s = i.variant || "block";
357
352
  t.innerHTML = this.generateSuffixAdHTML(e, s);
358
353
  const n = t.querySelector(".ax-ad-suffix-link");
359
- return n && n.addEventListener("click", (o) => {
360
- o.preventDefault(), this.handleClick(e, i);
354
+ return n && n.addEventListener("click", (r) => {
355
+ r.preventDefault(), this.handleClick(e, i);
361
356
  }), this.trackImpression(e, t, i), t;
362
357
  }
363
358
  /**
@@ -367,8 +362,8 @@ const C = class C {
367
362
  const s = i.variant || "card";
368
363
  t.innerHTML = this.generateSponsoredSourceHTML(e, s);
369
364
  const n = t.querySelector(".ax-ad-source-link");
370
- return n && n.addEventListener("click", (o) => {
371
- o.preventDefault(), this.handleClick(e, i);
365
+ return n && n.addEventListener("click", (r) => {
366
+ r.preventDefault(), this.handleClick(e, i);
372
367
  }), this.trackImpression(e, t, i), t;
373
368
  }
374
369
  /**
@@ -387,9 +382,9 @@ const C = class C {
387
382
  static renderAds(e, t, i = this.renderActionCard.bind(this), s) {
388
383
  t.innerHTML = "";
389
384
  const n = document.createElement("div");
390
- return n.className = "ax-ads-container", e.forEach((o) => {
385
+ return n.className = "ax-ads-container", e.forEach((r) => {
391
386
  const a = document.createElement("div");
392
- a.className = "ax-ad-wrapper", i.call(this, o, a, s), n.appendChild(a);
387
+ a.className = "ax-ad-wrapper", i.call(this, r, a, s), n.appendChild(a);
393
388
  }), t.appendChild(n), t;
394
389
  }
395
390
  /**
@@ -402,7 +397,7 @@ const C = class C {
402
397
  console.warn("[DOMRenderer] Missing click url for ad:", e.original.id);
403
398
  return;
404
399
  }
405
- s && s(e), i && T({
400
+ s && s(e), i && S({
406
401
  requestId: i.requestId,
407
402
  adId: e.original.id,
408
403
  destinationUrl: n,
@@ -411,8 +406,8 @@ const C = class C {
411
406
  adTitle: e.adapted.title,
412
407
  format: e.original.type,
413
408
  userId: i.userId
414
- }, { baseUrl: i.apiBaseUrl }).catch((o) => {
415
- console.error("[DOMRenderer] Analytics click tracking failed:", o);
409
+ }, { baseUrl: i.apiBaseUrl }).catch((r) => {
410
+ console.error("[DOMRenderer] Analytics click tracking failed:", r);
416
411
  }), this.isDebugEnabled() && console.log("[DOMRenderer] Redirect URL:", n), window.open(n, "_blank", "noopener,noreferrer");
417
412
  }
418
413
  /**
@@ -420,13 +415,13 @@ const C = class C {
420
415
  * Falls back to immediate tracking if IntersectionObserver is unavailable.
421
416
  */
422
417
  static trackImpression(e, t, i) {
423
- 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) || ""}`;
424
- if (this.trackedImpressionKeys.has(o))
418
+ const { analytics: s, onImpression: n } = i, r = s ? `${s.requestId}:${s.slotId}:${e.original.id}:${this.getViewToken(e) || ""}` : `no-analytics:${e.original.id}:${this.getViewToken(e) || ""}`;
419
+ if (this.trackedImpressionKeys.has(r))
425
420
  return;
426
421
  let a = !1;
427
422
  const c = () => {
428
- a || this.trackedImpressionKeys.has(o) || (a = !0, this.trackedImpressionKeys.add(o), l());
429
- }, l = () => {
423
+ a || this.trackedImpressionKeys.has(r) || (a = !0, this.trackedImpressionKeys.add(r), d());
424
+ }, d = () => {
430
425
  s ? I({
431
426
  requestId: s.requestId,
432
427
  adId: e.original.id,
@@ -441,17 +436,17 @@ const C = class C {
441
436
  userId: s.userId
442
437
  }, { baseUrl: s.apiBaseUrl }).then(() => {
443
438
  n && n(e);
444
- }).catch((d) => {
445
- console.error("[DOMRenderer] Analytics impression tracking failed:", d);
439
+ }).catch((l) => {
440
+ console.error("[DOMRenderer] Analytics impression tracking failed:", l);
446
441
  }) : n && n(e);
447
442
  };
448
443
  if (typeof IntersectionObserver < "u") {
449
- let d = !1, u = null;
444
+ let l = !1, u = null;
450
445
  const h = new IntersectionObserver(
451
446
  (f) => {
452
447
  f.forEach((v) => {
453
- d = v.isIntersecting && v.intersectionRatio >= 0.5, d ? u || (u = setTimeout(() => {
454
- u = null, d && (c(), h.disconnect());
448
+ l = v.isIntersecting && v.intersectionRatio >= 0.5, l ? u || (u = setTimeout(() => {
449
+ u = null, l && (c(), h.disconnect());
455
450
  }, 1e3)) : u && (clearTimeout(u), u = null);
456
451
  });
457
452
  },
@@ -496,8 +491,8 @@ const C = class C {
496
491
  * Generate HTML for Sponsored Source Ad variants
497
492
  */
498
493
  static generateSponsoredSourceHTML(e, t) {
499
- var o;
500
- const i = e.adapted.title || "", s = e.adapted.body || "", n = ((o = e.adapted.image) == null ? void 0 : o.url) || "";
494
+ var r;
495
+ const i = e.adapted.title || "", s = e.adapted.body || "", n = ((r = e.adapted.image) == null ? void 0 : r.url) || "";
501
496
  return t === "list-item" ? `
502
497
  <div class="ax-ad-source ax-ad-variant-list-item" data-ad-id="${e.original.id}">
503
498
  ${n ? `<img src="${n}" alt="${i}" loading="lazy" />` : ""}
@@ -536,7 +531,7 @@ const C = class C {
536
531
  };
537
532
  C.trackedImpressionKeys = /* @__PURE__ */ new Set();
538
533
  let y = C;
539
- class S {
534
+ class T {
540
535
  constructor() {
541
536
  this.cachedStaticInfo = null, this.cacheTimestamp = 0, this.CACHE_TTL = 36e5;
542
537
  }
@@ -623,7 +618,7 @@ class S {
623
618
  * Get singleton instance
624
619
  */
625
620
  static getInstance() {
626
- return this.instance || (this.instance = new S()), this.instance;
621
+ return this.instance || (this.instance = new T()), this.instance;
627
622
  }
628
623
  /**
629
624
  * Collect all available client information
@@ -779,8 +774,8 @@ class S {
779
774
  const n = e.match(/(MI|Redmi|POCO)\s([\w\s]+)/);
780
775
  if (n) return n[1] + " " + n[2];
781
776
  if (/OnePlus/.test(e)) {
782
- const o = e.match(/OnePlus\s([A-Z\d]+)/);
783
- return o ? "OnePlus " + o[1] : "OnePlus";
777
+ const r = e.match(/OnePlus\s([A-Z\d]+)/);
778
+ return r ? "OnePlus " + r[1] : "OnePlus";
784
779
  }
785
780
  }
786
781
  /**
@@ -926,86 +921,86 @@ class S {
926
921
  this.cachedStaticInfo = null, this.cacheTimestamp = 0;
927
922
  }
928
923
  }
929
- const $ = () => S.getInstance();
930
- function b(r) {
931
- return $().collect(r);
924
+ const $ = () => T.getInstance();
925
+ function b(o) {
926
+ return $().collect(o);
932
927
  }
933
- function J() {
928
+ function X() {
934
929
  return b().device;
935
930
  }
936
931
  function N() {
937
932
  return b().user;
938
933
  }
939
- function X() {
934
+ function Z() {
940
935
  return b().app;
941
936
  }
942
- function Z() {
937
+ function Y() {
943
938
  return b().geo;
944
939
  }
945
- function Y() {
940
+ function D() {
946
941
  return N().id;
947
942
  }
948
943
  function ee() {
949
944
  $().clearCache();
950
945
  }
951
- function te(r) {
952
- const e = b(r);
946
+ function te(o) {
947
+ const e = b(o);
953
948
  return JSON.stringify(e, null, 2);
954
949
  }
955
950
  function ie() {
956
951
  var t;
957
- const r = b();
952
+ const o = b();
958
953
  return [
959
- r.device.os,
960
- r.device.osv,
961
- r.app.name,
962
- r.user.id.slice(0, 8) + "...",
963
- ((t = r.geo) == null ? void 0 : t.country) || "Unknown"
954
+ o.device.os,
955
+ o.device.osv,
956
+ o.app.name,
957
+ o.user.id.slice(0, 8) + "...",
958
+ ((t = o.geo) == null ? void 0 : t.country) || "Unknown"
964
959
  ].join(" / ");
965
960
  }
966
961
  function M() {
967
- var r;
968
- return typeof window < "u" ? !!((r = window.__AD_CONFIG__) != null && r.debug) : !1;
962
+ var o;
963
+ return typeof window < "u" ? !!((o = window.__AD_CONFIG__) != null && o.debug) : !1;
969
964
  }
970
- function se(r) {
965
+ function se(o) {
971
966
  var e, t;
972
967
  return {
973
- id: r.original.id,
974
- type: r.original.type,
975
- score: r.original.score,
968
+ id: o.original.id,
969
+ type: o.original.type,
970
+ score: o.original.score,
976
971
  source: "internal",
977
972
  // Default source
978
973
  content: {
979
- title: r.adapted.title,
980
- body: r.adapted.body,
981
- image: (e = r.adapted.image) == null ? void 0 : e.url,
982
- cta_text: r.adapted.ctaText,
983
- price: (t = r.adapted.price) == null ? void 0 : t.display,
984
- rating: r.adapted.rating,
985
- brand: r.adapted.brand
974
+ title: o.adapted.title,
975
+ body: o.adapted.body,
976
+ image: (e = o.adapted.image) == null ? void 0 : e.url,
977
+ cta_text: o.adapted.ctaText,
978
+ price: (t = o.adapted.price) == null ? void 0 : t.display,
979
+ rating: o.adapted.rating,
980
+ brand: o.adapted.brand
986
981
  },
987
982
  tracking: {
988
- click_url: r.tracking.clickUrl || r.tracking.click_url || "",
989
- impression_url: r.tracking.impressionUrl || r.tracking.impression_url || ""
983
+ click_url: o.tracking.clickUrl || o.tracking.click_url || "",
984
+ impression_url: o.tracking.impressionUrl || o.tracking.impression_url || ""
990
985
  },
991
986
  metadata: {
992
- viewToken: r.tracking.viewToken || r.tracking.view_token,
993
- styling: r.adapted.styling
987
+ viewToken: o.tracking.viewToken || o.tracking.view_token,
988
+ styling: o.adapted.styling
994
989
  }
995
990
  };
996
991
  }
997
- async function D(r, e = {}) {
992
+ async function H(o, e = {}) {
998
993
  const t = e.apiBaseUrl || "/api/v1", s = $().collect(), n = {
999
- ...r,
994
+ ...o,
1000
995
  clientInfo: s
1001
996
  // Auto-injected
1002
- }, o = {
997
+ }, r = {
1003
998
  "Content-Type": "application/json"
1004
999
  };
1005
- 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));
1000
+ e.apiKey && (r["X-API-Key"] = e.apiKey), M() && (console.log("[fetchAds] Request URL:", `${t}/ads/request`), console.log("[fetchAds] Request params:", o), console.log("[fetchAds] Request body:", n));
1006
1001
  const a = await fetch(`${t}/ads/request`, {
1007
1002
  method: "POST",
1008
- headers: o,
1003
+ headers: r,
1009
1004
  body: JSON.stringify(n)
1010
1005
  });
1011
1006
  if (!a.ok)
@@ -1015,16 +1010,16 @@ async function D(r, e = {}) {
1015
1010
  throw new Error(c.error || "Ad request failed");
1016
1011
  return c.data;
1017
1012
  }
1018
- const H = { width: 400, height: 200 }, A = {
1013
+ const F = { width: 400, height: 200 }, A = {
1019
1014
  variant: "horizontal",
1020
1015
  count: 1,
1021
1016
  preferences: {}
1022
1017
  };
1023
- function _(r = {}) {
1018
+ function _(o = {}) {
1024
1019
  const e = {
1025
- variant: r.variant ?? A.variant,
1026
- count: r.count ?? A.count,
1027
- preferences: { ...A.preferences, ...r.preferences }
1020
+ variant: o.variant ?? A.variant,
1021
+ count: o.count ?? A.count,
1022
+ preferences: { ...A.preferences, ...o.preferences }
1028
1023
  };
1029
1024
  return [
1030
1025
  {
@@ -1032,7 +1027,7 @@ function _(r = {}) {
1032
1027
  slotName: "Action Card",
1033
1028
  format: "action_card",
1034
1029
  variant: e.variant,
1035
- size: H,
1030
+ size: F,
1036
1031
  count: e.count,
1037
1032
  preferences: e.preferences,
1038
1033
  placement: { position: "below_fold", context: "post_response" }
@@ -1041,7 +1036,7 @@ function _(r = {}) {
1041
1036
  }
1042
1037
  const g = class g {
1043
1038
  constructor(e) {
1044
- this.slots = {}, this.isLoading = !1, this.currentRequestId = null, this.adsAnalyticsMap = /* @__PURE__ */ new Map(), this.config = e, this.enabled = e.enabled !== !1, this.eventBus = new O(), this.slots_config = _(e.cardOption), typeof window < "u" && (window.__AD_CONFIG__ = {
1039
+ this.slots = {}, this.isLoading = !1, this.currentRequestId = null, this.adsAnalyticsMap = /* @__PURE__ */ new Map(), this.config = e, this.enabled = e.enabled !== !1, this.eventBus = new B(), this.slots_config = _(e.cardOption), typeof window < "u" && (window.__AD_CONFIG__ = {
1045
1040
  ...window.__AD_CONFIG__ || {},
1046
1041
  apiKey: e.apiKey,
1047
1042
  apiBaseUrl: e.apiBaseUrl,
@@ -1053,9 +1048,8 @@ const g = class g {
1053
1048
  });
1054
1049
  }
1055
1050
  async requestAds(e) {
1056
- var o;
1057
1051
  const t = "conversationContext" in e ? e : { conversationContext: e };
1058
- this.currentUserId = (o = t.userContext) == null ? void 0 : o.userId;
1052
+ this.currentUserId = this.resolveUserId(t.userContext);
1059
1053
  const i = this.buildRequestKey(t), s = g.inFlightRequests.get(i);
1060
1054
  if (s)
1061
1055
  return this.config.debug && console.log("[AdManager] Reusing in-flight request for identical context"), s;
@@ -1066,10 +1060,14 @@ const g = class g {
1066
1060
  this.isLoading = !0, this.eventBus.emit("adsLoading"), this.config.debug && console.log("[AdManager] Starting ad request...");
1067
1061
  const n = (async () => {
1068
1062
  try {
1069
- const a = await D(
1063
+ const r = await H(
1070
1064
  {
1071
1065
  conversationContext: t.conversationContext,
1072
- userContext: t.userContext ? { ...t.userContext, sessionId: t.userContext.sessionId ?? m() } : { sessionId: m() },
1066
+ userContext: t.userContext ? {
1067
+ ...t.userContext,
1068
+ userId: t.userContext.userId ?? this.currentUserId,
1069
+ sessionId: t.userContext.sessionId ?? m()
1070
+ } : { userId: this.currentUserId, sessionId: m() },
1073
1071
  slots: this.slots_config
1074
1072
  },
1075
1073
  {
@@ -1077,29 +1075,29 @@ const g = class g {
1077
1075
  apiKey: this.config.apiKey
1078
1076
  }
1079
1077
  );
1080
- this.currentRequestId = a.requestId, this.adsAnalyticsMap.clear(), a.slots.forEach((l) => {
1081
- l.ads.forEach((d, u) => {
1082
- const h = d.original.id;
1083
- this.adsAnalyticsMap.set(h, {
1084
- requestId: a.requestId,
1085
- slotId: l.slotId,
1086
- position: u,
1087
- totalAds: l.ads.length,
1078
+ this.currentRequestId = r.requestId, this.adsAnalyticsMap.clear(), r.slots.forEach((c) => {
1079
+ c.ads.forEach((d, l) => {
1080
+ const u = d.original.id;
1081
+ this.adsAnalyticsMap.set(u, {
1082
+ requestId: r.requestId,
1083
+ slotId: c.slotId,
1084
+ position: l,
1085
+ totalAds: c.ads.length,
1088
1086
  apiBaseUrl: this.config.apiBaseUrl,
1089
1087
  userId: this.currentUserId
1090
1088
  });
1091
1089
  });
1092
1090
  });
1093
- const c = {};
1094
- return a.slots.forEach((l) => {
1095
- c[l.slotId] = l;
1096
- }), this.slots = c, this.eventBus.emit("adsUpdated", this.slots), this.config.debug && console.log("[AdManager] Ads received:", {
1091
+ const a = {};
1092
+ return r.slots.forEach((c) => {
1093
+ a[c.slotId] = c;
1094
+ }), this.slots = a, this.eventBus.emit("adsUpdated", this.slots), this.config.debug && console.log("[AdManager] Ads received:", {
1097
1095
  slotCount: Object.keys(this.slots).length,
1098
1096
  slots: Object.keys(this.slots)
1099
- }), a;
1100
- } catch (a) {
1101
- const c = a;
1102
- throw this.eventBus.emit("adsError", c), c;
1097
+ }), r;
1098
+ } catch (r) {
1099
+ const a = r;
1100
+ throw this.eventBus.emit("adsError", a), a;
1103
1101
  } finally {
1104
1102
  this.isLoading = !1, g.inFlightRequests.delete(i);
1105
1103
  }
@@ -1115,25 +1113,34 @@ const g = class g {
1115
1113
  slots: this.slots_config
1116
1114
  });
1117
1115
  }
1116
+ resolveUserId(e) {
1117
+ if (e != null && e.userId)
1118
+ return e.userId;
1119
+ try {
1120
+ return D();
1121
+ } catch {
1122
+ return;
1123
+ }
1124
+ }
1118
1125
  render(e, t, i = {}) {
1119
- const s = typeof e != "string", n = s ? g.DEFAULT_SLOT_ID : e, o = s ? e : t, a = (s ? t : i) || {};
1120
- if (!o)
1126
+ const s = typeof e != "string", n = s ? g.DEFAULT_SLOT_ID : e, r = s ? e : t, a = (s ? t : i) || {};
1127
+ if (!r)
1121
1128
  return this.config.debug && console.warn("[AdManager] Render container is required"), null;
1122
1129
  const c = this.slots[n];
1123
1130
  if (!c || !c.ads || c.ads.length === 0)
1124
1131
  return this.config.debug && console.warn("[AdManager] No ads in slot:", n), null;
1125
- const l = a.adIndex ?? 0, d = c.ads[l];
1126
- if (!d)
1127
- return this.config.debug && console.warn(`[AdManager] Ad at index ${l} not found in slot:`, n), null;
1128
- const u = this.adsAnalyticsMap.get(d.original.id), h = this.slots_config.find((v) => v.slotId === n), p = (h == null ? void 0 : h.format) || "action_card";
1129
- o.innerHTML = "";
1132
+ const d = a.adIndex ?? 0, l = c.ads[d];
1133
+ if (!l)
1134
+ return this.config.debug && console.warn(`[AdManager] Ad at index ${d} not found in slot:`, n), null;
1135
+ const u = this.adsAnalyticsMap.get(l.original.id), h = this.slots_config.find((v) => v.slotId === n), p = (h == null ? void 0 : h.format) || "action_card";
1136
+ r.innerHTML = "";
1130
1137
  const f = {
1131
1138
  analytics: u,
1132
1139
  variant: a.variant,
1133
1140
  onClick: a.onClick,
1134
1141
  onImpression: a.onImpression
1135
1142
  };
1136
- return p === "suffix" ? y.renderSuffixAd(d, o, f) : p === "source" ? y.renderSponsoredSource(d, o, f) : p === "lead_gen" ? y.renderLeadGenAd(d, o, f) : y.renderActionCard(d, o, f);
1143
+ return p === "suffix" ? y.renderSuffixAd(l, r, f) : p === "source" ? y.renderSponsoredSource(l, r, f) : p === "lead_gen" ? y.renderLeadGenAd(l, r, f) : y.renderActionCard(l, r, f);
1137
1144
  }
1138
1145
  /**
1139
1146
  * Get ad slots data
@@ -1227,7 +1234,7 @@ const g = class g {
1227
1234
  const s = this.adsAnalyticsMap.get(e);
1228
1235
  if (!s || !this.currentRequestId)
1229
1236
  return this.config.debug && console.warn("[AdManager] No analytics info for ad:", e), null;
1230
- const n = m(), o = await T({
1237
+ const n = m(), r = await S({
1231
1238
  requestId: this.currentRequestId,
1232
1239
  adId: e,
1233
1240
  destinationUrl: t,
@@ -1238,7 +1245,7 @@ const g = class g {
1238
1245
  source: i == null ? void 0 : i.source,
1239
1246
  userId: s.userId ?? this.currentUserId
1240
1247
  }, { baseUrl: s.apiBaseUrl });
1241
- return o && (this.eventBus.emit("adClicked", e, s.slotId), this.config.debug && console.log("[AdManager] Click tracked via Analytics API:", o.eventId)), o;
1248
+ return r && (this.eventBus.emit("adClicked", e, s.slotId), this.config.debug && console.log("[AdManager] Click tracked via Analytics API:", r.eventId)), r;
1242
1249
  }
1243
1250
  /**
1244
1251
  * Track ad impression using Analytics API
@@ -1273,12 +1280,12 @@ g.DEFAULT_SLOT_ID = "action_card", g.inFlightRequests = /* @__PURE__ */ new Map(
1273
1280
  let V = g;
1274
1281
  function E() {
1275
1282
  if (typeof window < "u") {
1276
- const r = window.__AD_CONFIG__;
1277
- if (r != null && r.apiKey)
1278
- return r.apiKey;
1283
+ const o = window.__AD_CONFIG__;
1284
+ if (o != null && o.apiKey)
1285
+ return o.apiKey;
1279
1286
  }
1280
1287
  }
1281
- class F {
1288
+ class G {
1282
1289
  constructor(e = {}, t = "/api/v1") {
1283
1290
  var i, s;
1284
1291
  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 = {
@@ -1301,7 +1308,7 @@ class F {
1301
1308
  return;
1302
1309
  }
1303
1310
  this.log(`[ViewabilityTracker] Starting tracking for ${e}`);
1304
- const o = {
1311
+ const r = {
1305
1312
  visiblePercentage: 0,
1306
1313
  maxVisiblePercentage: 0,
1307
1314
  totalVisibleTimeMs: 0,
@@ -1311,9 +1318,9 @@ class F {
1311
1318
  enteredViewportAt: null,
1312
1319
  enterCount: 0
1313
1320
  };
1314
- this.metrics.set(e, o), this.isTracking.set(e, !0), this.eventQueue.set(e, []);
1321
+ this.metrics.set(e, r), this.isTracking.set(e, !0), this.eventQueue.set(e, []);
1315
1322
  const a = new IntersectionObserver(
1316
- (l) => this.handleIntersection(e, l[0], i, s, n),
1323
+ (d) => this.handleIntersection(e, d[0], i, s, n),
1317
1324
  {
1318
1325
  threshold: this.createThresholds()
1319
1326
  }
@@ -1341,54 +1348,54 @@ class F {
1341
1348
  * Event-driven: Only process when state actually changes
1342
1349
  */
1343
1350
  handleIntersection(e, t, i, s, n) {
1344
- const o = this.metrics.get(e);
1345
- if (!o || !this.isTracking.get(e)) return;
1346
- const a = o.isViewable, c = Math.round(t.intersectionRatio * 100);
1347
- o.visiblePercentage = c, o.maxVisiblePercentage = Math.max(o.maxVisiblePercentage, c);
1348
- const l = Date.now(), d = c >= this.config.minVisiblePercentage;
1349
- if (d && !o.enteredViewportAt && (o.enteredViewportAt = l, o.enterCount++, this.log(`[ViewabilityTracker] ${e} entered viewport at ${l}`), this.queueEvent(e, {
1351
+ const r = this.metrics.get(e);
1352
+ if (!r || !this.isTracking.get(e)) return;
1353
+ const a = r.isViewable, c = Math.round(t.intersectionRatio * 100);
1354
+ r.visiblePercentage = c, r.maxVisiblePercentage = Math.max(r.maxVisiblePercentage, c);
1355
+ const d = Date.now(), l = c >= this.config.minVisiblePercentage;
1356
+ if (l && !r.enteredViewportAt && (r.enteredViewportAt = d, r.enterCount++, this.log(`[ViewabilityTracker] ${e} entered viewport at ${d}`), this.queueEvent(e, {
1350
1357
  adId: e,
1351
1358
  sessionId: i,
1352
1359
  requestId: s,
1353
1360
  viewToken: n,
1354
1361
  eventType: "enter_viewport",
1355
1362
  visiblePercentage: c,
1356
- maxVisiblePercentage: o.maxVisiblePercentage,
1357
- totalVisibleTimeMs: o.totalVisibleTimeMs,
1363
+ maxVisiblePercentage: r.maxVisiblePercentage,
1364
+ totalVisibleTimeMs: r.totalVisibleTimeMs,
1358
1365
  isViewable: !1,
1359
- timestamp: l
1360
- })), !d && o.enteredViewportAt) {
1361
- const u = l - o.enteredViewportAt;
1362
- o.totalVisibleTimeMs += u, o.enteredViewportAt = null, o.currentVisibleTimeMs = 0, this.log(`[ViewabilityTracker] ${e} exited viewport, total visible: ${o.totalVisibleTimeMs}ms`), this.queueEvent(e, {
1366
+ timestamp: d
1367
+ })), !l && r.enteredViewportAt) {
1368
+ const u = d - r.enteredViewportAt;
1369
+ r.totalVisibleTimeMs += u, r.enteredViewportAt = null, r.currentVisibleTimeMs = 0, this.log(`[ViewabilityTracker] ${e} exited viewport, total visible: ${r.totalVisibleTimeMs}ms`), this.queueEvent(e, {
1363
1370
  adId: e,
1364
1371
  sessionId: i,
1365
1372
  requestId: s,
1366
1373
  viewToken: n,
1367
1374
  eventType: "exit_viewport",
1368
1375
  visiblePercentage: c,
1369
- maxVisiblePercentage: o.maxVisiblePercentage,
1370
- totalVisibleTimeMs: o.totalVisibleTimeMs,
1371
- isViewable: o.isViewable,
1372
- timestamp: l
1376
+ maxVisiblePercentage: r.maxVisiblePercentage,
1377
+ totalVisibleTimeMs: r.totalVisibleTimeMs,
1378
+ isViewable: r.isViewable,
1379
+ timestamp: d
1373
1380
  });
1374
1381
  }
1375
- o.isViewable !== a && o.isViewable && this.log(`[ViewabilityTracker] ${e} became VIEWABLE!`), this.metrics.set(e, o);
1382
+ r.isViewable !== a && r.isViewable && this.log(`[ViewabilityTracker] ${e} became VIEWABLE!`), this.metrics.set(e, r);
1376
1383
  }
1377
1384
  /**
1378
1385
  * Start monitoring loop for tracking duration
1379
1386
  * Runs every 100ms to track continuous visible time
1380
1387
  */
1381
1388
  startMonitoring(e, t, i, s) {
1382
- const o = setInterval(() => {
1389
+ const r = setInterval(() => {
1383
1390
  const a = this.metrics.get(e);
1384
1391
  if (!a || !this.isTracking.get(e)) {
1385
- clearInterval(o);
1392
+ clearInterval(r);
1386
1393
  return;
1387
1394
  }
1388
- const c = Date.now(), l = a.isViewable;
1395
+ const c = Date.now(), d = a.isViewable;
1389
1396
  if (a.enteredViewportAt) {
1390
- const d = c - a.enteredViewportAt;
1391
- 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, {
1397
+ const l = c - a.enteredViewportAt;
1398
+ 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, {
1392
1399
  adId: e,
1393
1400
  sessionId: t,
1394
1401
  requestId: i,
@@ -1403,13 +1410,13 @@ class F {
1403
1410
  }
1404
1411
  a.enteredViewportAt && (a.totalVisibleTimeMs += 100), this.metrics.set(e, a);
1405
1412
  }, 100);
1406
- this.timers.set(`${e}_monitoring`, o);
1413
+ this.timers.set(`${e}_monitoring`, r);
1407
1414
  }
1408
1415
  /**
1409
1416
  * Queue an event to be sent (batched)
1410
1417
  */
1411
1418
  queueEvent(e, t) {
1412
- var n, o;
1419
+ var n, r;
1413
1420
  const i = this.eventQueue.get(e);
1414
1421
  if (!i) {
1415
1422
  this.log(`[ViewabilityTracker] No queue found for ${e}, skipping event`);
@@ -1422,10 +1429,10 @@ class F {
1422
1429
  else {
1423
1430
  const a = this.batchTimers.get(e);
1424
1431
  a && clearTimeout(a);
1425
- const c = ((o = this.config.batchConfig) == null ? void 0 : o.maxBatchWaitMs) ?? 1e4, l = setTimeout(() => {
1432
+ const c = ((r = this.config.batchConfig) == null ? void 0 : r.maxBatchWaitMs) ?? 1e4, d = setTimeout(() => {
1426
1433
  this.flushQueue(e);
1427
1434
  }, c);
1428
- this.batchTimers.set(e, l);
1435
+ this.batchTimers.set(e, d);
1429
1436
  }
1430
1437
  }
1431
1438
  /**
@@ -1456,7 +1463,7 @@ class F {
1456
1463
  const n = this.metrics.get(e);
1457
1464
  if (!n) return;
1458
1465
  this.log(`[ViewabilityTracker] Ending tracking for ${e}`), this.flushQueue(e);
1459
- const o = Date.now();
1466
+ const r = Date.now();
1460
1467
  this.queueEvent(e, {
1461
1468
  adId: e,
1462
1469
  sessionId: t,
@@ -1467,7 +1474,7 @@ class F {
1467
1474
  maxVisiblePercentage: n.maxVisiblePercentage,
1468
1475
  totalVisibleTimeMs: n.totalVisibleTimeMs,
1469
1476
  isViewable: n.isViewable,
1470
- timestamp: o
1477
+ timestamp: r
1471
1478
  }), this.flushQueue(e), this.cleanup(e);
1472
1479
  }
1473
1480
  /**
@@ -1526,38 +1533,38 @@ class F {
1526
1533
  }
1527
1534
  }
1528
1535
  let k = null;
1529
- function ne(r, e) {
1530
- return k || (k = new F(r, e), k.setupBeforeUnload()), k;
1536
+ function ne(o, e) {
1537
+ return k || (k = new G(o, e), k.setupBeforeUnload()), k;
1531
1538
  }
1532
1539
  const re = "0.1.0";
1533
1540
  export {
1534
1541
  V as AdManager,
1535
1542
  x as AnalyticsSender,
1536
- S as ClientInfoCollector,
1543
+ T as ClientInfoCollector,
1537
1544
  y as DOMRenderer,
1538
1545
  w as HTMLRenderer,
1539
1546
  re as SDK_VERSION,
1540
1547
  P as SessionManager,
1541
- F as ViewabilityTracker,
1548
+ G as ViewabilityTracker,
1542
1549
  se as adaptAdToKoahAd,
1543
1550
  ee as clearClientInfoCache,
1544
- W as createAnalytics,
1545
- Q as createSession,
1546
- D as fetchAds,
1547
- G as generateViewToken,
1548
- X as getAppInfo,
1551
+ Q as createAnalytics,
1552
+ J as createSession,
1553
+ H as fetchAds,
1554
+ z as generateViewToken,
1555
+ Z as getAppInfo,
1549
1556
  b as getClientInfo,
1550
1557
  $ as getClientInfoCollector,
1551
1558
  te as getClientInfoJSON,
1552
1559
  ie as getClientInfoSummary,
1553
- J as getDeviceInfo,
1554
- Z as getGeoInfo,
1560
+ X as getDeviceInfo,
1561
+ Y as getGeoInfo,
1555
1562
  m as getSessionId,
1556
- Y as getUserId,
1563
+ D as getUserId,
1557
1564
  N as getUserInfo,
1558
1565
  ne as getViewabilityTracker,
1559
- T as trackAdClick,
1566
+ S as trackAdClick,
1560
1567
  I as trackAdImpression,
1561
- j as trackClicksBatch,
1562
- z as trackImpressionsBatch
1568
+ W as trackClicksBatch,
1569
+ j as trackImpressionsBatch
1563
1570
  };