@ai-ad-network/frontend-sdk 1.1.1 → 1.1.2

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.
@@ -1,4 +1,4 @@
1
- import type { EntityInfo, EnhancedContentProps } from '@/types';
1
+ import type { EntityInfo, EnhancementOptions, EnhancedContentProps, KoahAd } from '@/types';
2
2
  /**
3
3
  * EnhancedContent Component
4
4
  *
@@ -51,3 +51,52 @@ export declare function useEntityStats(entities: EntityInfo[]): {
51
51
  byType: Record<string, number>;
52
52
  avgConfidence: number;
53
53
  };
54
+ /**
55
+ * EnhancedContentV2 Props
56
+ */
57
+ export interface EnhancedContentV2Props {
58
+ /** The ad data containing entity_link_content */
59
+ ad: KoahAd;
60
+ /** AI response context for styling */
61
+ aiContext?: string;
62
+ /** Custom class name */
63
+ className?: string;
64
+ /** Whether tracking is loading (unused but for API compatibility) */
65
+ isLoading?: boolean;
66
+ requestId: string;
67
+ slotId: string;
68
+ position: number;
69
+ totalAds: number;
70
+ enhancements?: EnhancementOptions;
71
+ onEntityClick?: (entity: EntityInfo) => void;
72
+ onImpression?: () => void;
73
+ }
74
+ /**
75
+ * EnhancedContentV2 - Entity Link Ad component with Analytics API tracking
76
+ *
77
+ * Renders content with entity-linked affiliate URLs and tracks clicks
78
+ * using the new Analytics API (POST /api/v1/ads/click).
79
+ *
80
+ * @example
81
+ * ```tsx
82
+ * <EnhancedContentV2
83
+ * ad={ad}
84
+ * requestId="req-123"
85
+ * slotId="slot-entity-link"
86
+ * position={0}
87
+ * totalAds={3}
88
+ * />
89
+ * ```
90
+ */
91
+ export declare function EnhancedContentV2({ ad, aiContext, className, isLoading: _isLoading, requestId, slotId, position, totalAds, enhancements, onEntityClick, onImpression, }: EnhancedContentV2Props): import("react/jsx-runtime").JSX.Element;
92
+ /**
93
+ * Convenience components for V2
94
+ */
95
+ /**
96
+ * Inline variant - for embedding within existing text
97
+ */
98
+ export declare function EnhancedContentV2Inline(props: Omit<EnhancedContentV2Props, 'className'>): import("react/jsx-runtime").JSX.Element;
99
+ /**
100
+ * Block variant - for standalone content blocks
101
+ */
102
+ export declare function EnhancedContentV2Block(props: EnhancedContentV2Props): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,76 @@
1
+ import type { KoahAd, BadgeStyle, OverlapStrategy } from '@/types';
2
+ import type { EntityInfo } from '@/types';
3
+ /**
4
+ * 🆕 Simplified EntityLinkAd Props
5
+ *
6
+ * This component automatically handles all analytics tracking parameters.
7
+ * You only need to provide the ad data and slot ID.
8
+ */
9
+ export interface EntityLinkAdProps {
10
+ /** The ad data to display (must contain entity_link_content) */
11
+ ad: KoahAd;
12
+ /** Slot identifier (business concept, e.g., "inline-entity", "content-enhancement") */
13
+ slotId: string;
14
+ /** AI response context for template selection */
15
+ aiContext?: string;
16
+ /** Custom class name */
17
+ className?: string;
18
+ /** Loading state */
19
+ isLoading?: boolean;
20
+ /** Badge style for entity links */
21
+ badgeStyle?: BadgeStyle;
22
+ /** Strategy for handling overlapping entities */
23
+ overlapStrategy?: OverlapStrategy;
24
+ /** Maximum number of entity links to show */
25
+ maxLinks?: number;
26
+ /** Minimum confidence threshold for entities */
27
+ minConfidence?: number;
28
+ /** Custom click callback (in addition to automatic tracking) */
29
+ onEntityClick?: (entity: EntityInfo) => void;
30
+ /** Custom impression callback (in addition to automatic tracking) */
31
+ onImpression?: () => void;
32
+ }
33
+ /**
34
+ * EntityLinkAd - Simplified component with automatic analytics tracking
35
+ *
36
+ * This component automatically injects all analytics tracking parameters
37
+ * (requestId, position, totalAds) from the SDK context and renders
38
+ * entity-linked content with click tracking.
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * // ✅ Simple usage - automatic tracking
43
+ * import { EntityLinkAd } from '@ai-ad-network/frontend-sdk';
44
+ *
45
+ * <EntityLinkAd
46
+ * ad={ad}
47
+ * slotId="inline-entity"
48
+ * aiContext={aiResponse}
49
+ * badgeStyle="subtle"
50
+ * />
51
+ *
52
+ * // With multiple ads
53
+ * {ads.map(ad => (
54
+ * <EntityLinkAd
55
+ * key={ad.id}
56
+ * ad={ad}
57
+ * slotId="inline-entity"
58
+ * />
59
+ * ))}
60
+ * ```
61
+ *
62
+ * @remarks
63
+ * For advanced use cases where you need explicit control over analytics parameters,
64
+ * use `EnhancedContentV2` directly.
65
+ */
66
+ export declare function EntityLinkAd({ ad, slotId, aiContext, className, isLoading, badgeStyle, overlapStrategy, maxLinks, minConfidence, onEntityClick, onImpression, }: EntityLinkAdProps): import("react/jsx-runtime").JSX.Element;
67
+ /**
68
+ * EntityLinkAdInline - Inline variant for embedding within existing text
69
+ */
70
+ export declare function EntityLinkAdInline(props: Omit<EntityLinkAdProps, 'className'>): import("react/jsx-runtime").JSX.Element;
71
+ /**
72
+ * EntityLinkAdBlock - Block variant for standalone content blocks
73
+ */
74
+ export declare function EntityLinkAdBlock(props: EntityLinkAdProps): import("react/jsx-runtime").JSX.Element;
75
+ export { EnhancedContentV2 } from './EnhancedContent';
76
+ export type { EnhancedContentV2Props } from './EnhancedContent';
package/dist/index.d.ts CHANGED
@@ -35,7 +35,11 @@ export { ActionCardAd } from './components/ActionCardAd.simple';
35
35
  export { ActionCardAdV2 } from './components/ActionCardAd';
36
36
  export type { ActionCardAdV2Props } from './components/ActionCardAd';
37
37
  export type { ActionCardAdProps } from './components/ActionCardAd.simple';
38
+ export { EntityLinkAd, EntityLinkAdInline, EntityLinkAdBlock } from './components/EntityLinkAd.simple';
39
+ export { EnhancedContentV2, EnhancedContentV2Inline, EnhancedContentV2Block, } from './components/EnhancedContent';
38
40
  export { EnhancedContent, EnhancedContentInline, EnhancedContentBlock, useEntityStats, } from './components/EnhancedContent';
41
+ export type { EnhancedContentV2Props } from './components/EnhancedContent';
42
+ export type { EntityLinkAdProps } from './components/EntityLinkAd.simple';
39
43
  export { SuffixAd } from './components/SuffixAd.simple';
40
44
  export { SuffixAdV2 } from './components/SuffixAd';
41
45
  export { SuffixAdInline, SuffixAdMinimal, } from './components/SuffixAd';
package/dist/index.esm.js CHANGED
@@ -3,7 +3,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import React, { useState, useRef, useCallback, useEffect, createContext, useContext, useMemo, Component } from "react";
5
5
  import useSWR from "swr";
6
- const SDK_VERSION = "1.1.1";
6
+ const SDK_VERSION = "1.1.2";
7
7
  var IntentType = /* @__PURE__ */ ((IntentType2) => {
8
8
  IntentType2["SHOPPING"] = "shopping";
9
9
  IntentType2["LEAD_GEN"] = "lead_gen";
@@ -1381,6 +1381,19 @@ function createSession(config = {}) {
1381
1381
  clearSessionId: () => manager.clearSessionId()
1382
1382
  };
1383
1383
  }
1384
+ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1385
+ __proto__: null,
1386
+ AnalyticsSender,
1387
+ SessionManager,
1388
+ createAnalytics,
1389
+ createSession,
1390
+ generateViewToken,
1391
+ getSessionId,
1392
+ trackAdClick,
1393
+ trackAdImpression,
1394
+ trackClicksBatch,
1395
+ trackImpressionsBatch
1396
+ }, Symbol.toStringTag, { value: "Module" }));
1384
1397
  function useAdTracking(ad, options = {}) {
1385
1398
  const {
1386
1399
  intersectionThreshold = 0.5,
@@ -2996,16 +3009,16 @@ const createParseClassName = (config) => {
2996
3009
  let bracketDepth = 0;
2997
3010
  let modifierStart = 0;
2998
3011
  let postfixModifierPosition;
2999
- for (let index = 0; index < className.length; index++) {
3000
- let currentCharacter = className[index];
3012
+ for (let index2 = 0; index2 < className.length; index2++) {
3013
+ let currentCharacter = className[index2];
3001
3014
  if (bracketDepth === 0) {
3002
- if (currentCharacter === firstSeparatorCharacter && (isSeparatorSingleCharacter || className.slice(index, index + separatorLength) === separator)) {
3003
- modifiers.push(className.slice(modifierStart, index));
3004
- modifierStart = index + separatorLength;
3015
+ if (currentCharacter === firstSeparatorCharacter && (isSeparatorSingleCharacter || className.slice(index2, index2 + separatorLength) === separator)) {
3016
+ modifiers.push(className.slice(modifierStart, index2));
3017
+ modifierStart = index2 + separatorLength;
3005
3018
  continue;
3006
3019
  }
3007
3020
  if (currentCharacter === "/") {
3008
- postfixModifierPosition = index;
3021
+ postfixModifierPosition = index2;
3009
3022
  continue;
3010
3023
  }
3011
3024
  }
@@ -3067,8 +3080,8 @@ const mergeClassList = (classList, configUtils) => {
3067
3080
  const classGroupsInConflict = [];
3068
3081
  const classNames = classList.trim().split(SPLIT_CLASSES_REGEX);
3069
3082
  let result = "";
3070
- for (let index = classNames.length - 1; index >= 0; index -= 1) {
3071
- const originalClassName = classNames[index];
3083
+ for (let index2 = classNames.length - 1; index2 >= 0; index2 -= 1) {
3084
+ const originalClassName = classNames[index2];
3072
3085
  const {
3073
3086
  modifiers,
3074
3087
  hasImportantModifier,
@@ -3106,12 +3119,12 @@ const mergeClassList = (classList, configUtils) => {
3106
3119
  return result;
3107
3120
  };
3108
3121
  function twJoin() {
3109
- let index = 0;
3122
+ let index2 = 0;
3110
3123
  let argument;
3111
3124
  let resolvedValue;
3112
3125
  let string = "";
3113
- while (index < arguments.length) {
3114
- if (argument = arguments[index++]) {
3126
+ while (index2 < arguments.length) {
3127
+ if (argument = arguments[index2++]) {
3115
3128
  if (resolvedValue = toValue(argument)) {
3116
3129
  string && (string += " ");
3117
3130
  string += resolvedValue;
@@ -5594,7 +5607,7 @@ function ActionCardAdV2({
5594
5607
  }
5595
5608
  );
5596
5609
  }
5597
- function getAnalyticsFromGlobal$2(adId, slotId) {
5610
+ function getAnalyticsFromGlobal$3(adId, slotId) {
5598
5611
  if (typeof window === "undefined") return null;
5599
5612
  const analytics = window.__AD_ANALYTICS__;
5600
5613
  if (!analytics || !analytics.requestId) return null;
@@ -5627,7 +5640,7 @@ function ActionCardAd({
5627
5640
  onImpression
5628
5641
  }) {
5629
5642
  const analytics = useMemo(() => {
5630
- return getAnalyticsFromGlobal$2(ad.id, slotId);
5643
+ return getAnalyticsFromGlobal$3(ad.id, slotId);
5631
5644
  }, [ad.id, slotId]);
5632
5645
  useEffect(() => {
5633
5646
  if (analytics) {
@@ -5732,9 +5745,9 @@ function EnhancedContent({
5732
5745
  onEntityClick == null ? void 0 : onEntityClick(entity);
5733
5746
  window.open(url, "_blank", "noopener,noreferrer");
5734
5747
  }, [onEntityClick]);
5735
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("enhanced-content", className), children: processedContent.map((part, index) => {
5748
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("enhanced-content", className), children: processedContent.map((part, index2) => {
5736
5749
  if (part.type === "text") {
5737
- return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: part.content }, index);
5750
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: part.content }, index2);
5738
5751
  }
5739
5752
  const { entity, url } = part;
5740
5753
  const isHovered = hoveredEntity === entity.text;
@@ -5768,7 +5781,7 @@ function EnhancedContent({
5768
5781
  renderBadge(entity, badgeStyle, isHovered)
5769
5782
  ]
5770
5783
  },
5771
- index
5784
+ index2
5772
5785
  );
5773
5786
  }) });
5774
5787
  }
@@ -5786,17 +5799,17 @@ function buildEnhancedContent(content, entities, entityUrlMap, _badgeStyle) {
5786
5799
  for (const entity of sortedEntities) {
5787
5800
  const replacement = entityUrlMap.get(entity.text);
5788
5801
  if (!replacement) continue;
5789
- let index;
5802
+ let index2;
5790
5803
  if (entity.startPosition >= 0) {
5791
- index = entity.startPosition;
5804
+ index2 = entity.startPosition;
5792
5805
  } else {
5793
- index = content.toLowerCase().indexOf(entity.text.toLowerCase(), lastIndex);
5806
+ index2 = content.toLowerCase().indexOf(entity.text.toLowerCase(), lastIndex);
5794
5807
  }
5795
- if (index === -1) continue;
5796
- if (index > lastIndex) {
5808
+ if (index2 === -1) continue;
5809
+ if (index2 > lastIndex) {
5797
5810
  parts.push({
5798
5811
  type: "text",
5799
- content: content.substring(lastIndex, index)
5812
+ content: content.substring(lastIndex, index2)
5800
5813
  });
5801
5814
  }
5802
5815
  parts.push({
@@ -5805,7 +5818,7 @@ function buildEnhancedContent(content, entities, entityUrlMap, _badgeStyle) {
5805
5818
  entity,
5806
5819
  url: replacement.affiliateUrl
5807
5820
  });
5808
- lastIndex = index + entity.text.length;
5821
+ lastIndex = index2 + entity.text.length;
5809
5822
  }
5810
5823
  if (lastIndex < content.length) {
5811
5824
  parts.push({
@@ -5826,10 +5839,10 @@ function filterOverlappingEntities(entities, content, strategy) {
5826
5839
  start = entity.startPosition;
5827
5840
  end = entity.endPosition;
5828
5841
  } else {
5829
- const index = content.toLowerCase().indexOf(entity.text.toLowerCase());
5830
- if (index === -1) continue;
5831
- start = index;
5832
- end = index + entity.text.length;
5842
+ const index2 = content.toLowerCase().indexOf(entity.text.toLowerCase());
5843
+ if (index2 === -1) continue;
5844
+ start = index2;
5845
+ end = index2 + entity.text.length;
5833
5846
  }
5834
5847
  const overlaps = usedRanges.some(
5835
5848
  (range) => !(end <= range.start || start >= range.end)
@@ -5942,6 +5955,268 @@ function useEntityStats(entities) {
5942
5955
  };
5943
5956
  }, [entities]);
5944
5957
  }
5958
+ function EnhancedContentV2({
5959
+ ad,
5960
+ aiContext,
5961
+ className,
5962
+ isLoading: _isLoading,
5963
+ requestId,
5964
+ slotId,
5965
+ position,
5966
+ totalAds,
5967
+ enhancements,
5968
+ onEntityClick,
5969
+ onImpression
5970
+ }) {
5971
+ var _a;
5972
+ const { impressionRef } = useAdTrackingV2({
5973
+ ad,
5974
+ requestId,
5975
+ slotId,
5976
+ position,
5977
+ totalAds,
5978
+ onImpression
5979
+ });
5980
+ const [hoveredEntity, setHoveredEntity] = useState(null);
5981
+ const entityContent = (_a = ad.content) == null ? void 0 : _a.entity_link_content;
5982
+ const options = {
5983
+ ...DEFAULT_OPTIONS,
5984
+ ...enhancements,
5985
+ ...entityContent ? {
5986
+ entities: entityContent.entities,
5987
+ replacements: entityContent.replacements
5988
+ } : {}
5989
+ };
5990
+ const content = (entityContent == null ? void 0 : entityContent.originalText) || aiContext || "";
5991
+ const processedContent = useMemo(() => {
5992
+ const { entities, replacements, maxLinks, minConfidence, badgeStyle, overlapStrategy } = options;
5993
+ const entityUrlMap = /* @__PURE__ */ new Map();
5994
+ for (const replacement of replacements) {
5995
+ entityUrlMap.set(replacement.originalText, replacement);
5996
+ }
5997
+ const minConf = minConfidence ?? DEFAULT_OPTIONS.minConfidence;
5998
+ const validEntities = entities.filter((e) => {
5999
+ const hasUrl = entityUrlMap.has(e.text);
6000
+ const confidenceOk = e.confidence >= minConf;
6001
+ return hasUrl && confidenceOk;
6002
+ });
6003
+ const sortedEntities = [...validEntities].sort((a, b) => {
6004
+ if (a.startPosition >= 0 && b.startPosition >= 0) {
6005
+ return a.startPosition - b.startPosition;
6006
+ }
6007
+ const aPos = content.toLowerCase().indexOf(a.text.toLowerCase());
6008
+ const bPos = content.toLowerCase().indexOf(b.text.toLowerCase());
6009
+ if (aPos === -1 && bPos === -1) {
6010
+ return b.confidence - a.confidence;
6011
+ }
6012
+ if (aPos === -1) return 1;
6013
+ if (bPos === -1) return -1;
6014
+ return aPos - bPos;
6015
+ });
6016
+ const max = maxLinks ?? DEFAULT_OPTIONS.maxLinks;
6017
+ const limitedEntities = sortedEntities.slice(0, max);
6018
+ const strategy = overlapStrategy ?? DEFAULT_OPTIONS.overlapStrategy;
6019
+ const filteredEntities = filterOverlappingEntities(
6020
+ limitedEntities,
6021
+ content,
6022
+ strategy
6023
+ );
6024
+ const style = badgeStyle ?? DEFAULT_OPTIONS.badgeStyle;
6025
+ return buildEnhancedContent(content, filteredEntities, entityUrlMap, style);
6026
+ }, [content, options]);
6027
+ const handleEntityClick = useCallback(async (entity, url) => {
6028
+ var _a2;
6029
+ const { trackAdClick: trackAdClick2 } = await Promise.resolve().then(() => index);
6030
+ await trackAdClick2({
6031
+ requestId,
6032
+ adId: ad.id,
6033
+ destinationUrl: url,
6034
+ sessionId: "",
6035
+ // Will be auto-generated
6036
+ slotId,
6037
+ adTitle: entity.text,
6038
+ format: "entity_link",
6039
+ source: (_a2 = ad.content) == null ? void 0 : _a2.brand
6040
+ });
6041
+ onEntityClick == null ? void 0 : onEntityClick(entity);
6042
+ window.open(url, "_blank", "noopener,noreferrer");
6043
+ }, [requestId, ad.id, ad.content, slotId, onEntityClick]);
6044
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
6045
+ "div",
6046
+ {
6047
+ ref: impressionRef,
6048
+ className: cn("ad-component enhanced-content", className),
6049
+ children: processedContent.map((part, index2) => {
6050
+ if (part.type === "text") {
6051
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: part.content }, index2);
6052
+ }
6053
+ const { entity, url } = part;
6054
+ const isHovered = hoveredEntity === entity.text;
6055
+ const badgeStyle = options.badgeStyle ?? DEFAULT_OPTIONS.badgeStyle;
6056
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
6057
+ "a",
6058
+ {
6059
+ href: url,
6060
+ onClick: (e) => {
6061
+ e.preventDefault();
6062
+ handleEntityClick(entity, url);
6063
+ },
6064
+ onMouseEnter: () => setHoveredEntity(entity.text),
6065
+ onMouseLeave: () => setHoveredEntity(null),
6066
+ className: cn(
6067
+ "entity-link inline-flex items-center gap-1 transition-all duration-200",
6068
+ "text-ad-primary hover:text-ad-primary/80 hover:underline",
6069
+ "font-medium cursor-pointer",
6070
+ "focus:outline-none focus:ring-2 focus:ring-ad-primary/50 focus:ring-offset-2 rounded",
6071
+ {
6072
+ "opacity-90": isHovered
6073
+ }
6074
+ ),
6075
+ "data-entity-type": entity.type,
6076
+ "data-entity-text": entity.text,
6077
+ "data-tracking": `entity_${entity.text.toLowerCase().replace(/\s+/g, "_")}`,
6078
+ rel: "sponsored noopener noreferrer",
6079
+ target: "_blank",
6080
+ children: [
6081
+ part.content,
6082
+ renderBadge(entity, badgeStyle, isHovered)
6083
+ ]
6084
+ },
6085
+ index2
6086
+ );
6087
+ })
6088
+ }
6089
+ );
6090
+ }
6091
+ function EnhancedContentV2Inline(props) {
6092
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
6093
+ EnhancedContentV2,
6094
+ {
6095
+ ...props,
6096
+ className: "inline"
6097
+ }
6098
+ );
6099
+ }
6100
+ function EnhancedContentV2Block(props) {
6101
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
6102
+ EnhancedContentV2,
6103
+ {
6104
+ ...props,
6105
+ className: "block"
6106
+ }
6107
+ );
6108
+ }
6109
+ function getAnalyticsFromGlobal$2(adId, slotId) {
6110
+ if (typeof window === "undefined") return null;
6111
+ const analytics = window.__AD_ANALYTICS__;
6112
+ if (!analytics || !analytics.requestId) return null;
6113
+ const { requestId, slotsMap, getAdAnalytics } = analytics;
6114
+ if (getAdAnalytics) {
6115
+ return getAdAnalytics(adId, slotId);
6116
+ }
6117
+ for (const [sid, slotInfo] of Object.entries(slotsMap || {})) {
6118
+ if (slotId && sid !== slotId) continue;
6119
+ const info = slotInfo;
6120
+ const position = (info.ads || []).findIndex((a) => a.id === adId);
6121
+ if (position !== -1) {
6122
+ return {
6123
+ requestId,
6124
+ slotId: sid,
6125
+ position,
6126
+ totalAds: info.count
6127
+ };
6128
+ }
6129
+ }
6130
+ return null;
6131
+ }
6132
+ function EntityLinkAd({
6133
+ ad,
6134
+ slotId,
6135
+ aiContext,
6136
+ className,
6137
+ isLoading = false,
6138
+ badgeStyle,
6139
+ overlapStrategy,
6140
+ maxLinks,
6141
+ minConfidence,
6142
+ onEntityClick,
6143
+ onImpression
6144
+ }) {
6145
+ const analytics = useMemo(() => {
6146
+ return getAnalyticsFromGlobal$2(ad.id, slotId);
6147
+ }, [ad.id, slotId]);
6148
+ useEffect(() => {
6149
+ if (analytics) {
6150
+ console.log(
6151
+ `[EntityLinkAd] Auto-tracking enabled: requestId=${analytics.requestId}, slotId=${analytics.slotId}, position=${analytics.position}, totalAds=${analytics.totalAds}`
6152
+ );
6153
+ } else {
6154
+ console.warn(
6155
+ `[EntityLinkAd] Analytics data not found. Make sure useAiAds has completed. Falling back to basic rendering without tracking.`
6156
+ );
6157
+ }
6158
+ }, [analytics]);
6159
+ const enhancementOptions = useMemo(() => {
6160
+ const options = {};
6161
+ if (badgeStyle !== void 0) options.badgeStyle = badgeStyle;
6162
+ if (overlapStrategy !== void 0) options.overlapStrategy = overlapStrategy;
6163
+ if (maxLinks !== void 0) options.maxLinks = maxLinks;
6164
+ if (minConfidence !== void 0) options.minConfidence = minConfidence;
6165
+ return Object.keys(options).length > 0 ? options : void 0;
6166
+ }, [badgeStyle, overlapStrategy, maxLinks, minConfidence]);
6167
+ if (!analytics || !analytics.requestId) {
6168
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
6169
+ EnhancedContentV2,
6170
+ {
6171
+ ad,
6172
+ aiContext,
6173
+ requestId: "",
6174
+ slotId,
6175
+ position: 0,
6176
+ totalAds: 1,
6177
+ className,
6178
+ isLoading,
6179
+ enhancements: enhancementOptions,
6180
+ onEntityClick,
6181
+ onImpression
6182
+ }
6183
+ );
6184
+ }
6185
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
6186
+ EnhancedContentV2,
6187
+ {
6188
+ ad,
6189
+ aiContext,
6190
+ requestId: analytics.requestId,
6191
+ slotId: analytics.slotId,
6192
+ position: analytics.position,
6193
+ totalAds: analytics.totalAds,
6194
+ className,
6195
+ isLoading,
6196
+ enhancements: enhancementOptions,
6197
+ onEntityClick,
6198
+ onImpression
6199
+ }
6200
+ );
6201
+ }
6202
+ function EntityLinkAdInline(props) {
6203
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
6204
+ EntityLinkAd,
6205
+ {
6206
+ ...props,
6207
+ className: "inline"
6208
+ }
6209
+ );
6210
+ }
6211
+ function EntityLinkAdBlock(props) {
6212
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
6213
+ EntityLinkAd,
6214
+ {
6215
+ ...props,
6216
+ className: "block"
6217
+ }
6218
+ );
6219
+ }
5945
6220
  class TextWeaver {
5946
6221
  constructor() {
5947
6222
  __publicField(this, "suffixTemplates", [
@@ -6451,8 +6726,8 @@ function FollowUpAdMixed({
6451
6726
  if (!ad) return questions.map((q) => ({ type: "question", content: q }));
6452
6727
  const result = [];
6453
6728
  let adInserted = false;
6454
- questions.forEach((question, index) => {
6455
- if (index === adPosition && !adInserted) {
6729
+ questions.forEach((question, index2) => {
6730
+ if (index2 === adPosition && !adInserted) {
6456
6731
  result.push({ type: "ad", content: ad });
6457
6732
  adInserted = true;
6458
6733
  }
@@ -6463,7 +6738,7 @@ function FollowUpAdMixed({
6463
6738
  }
6464
6739
  return result;
6465
6740
  }, [questions, ad, adPosition]);
6466
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("flex flex-wrap gap-2", className), children: items.map((item, index) => {
6741
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("flex flex-wrap gap-2", className), children: items.map((item, index2) => {
6467
6742
  if (item.type === "ad") {
6468
6743
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
6469
6744
  FollowUpAd,
@@ -6473,7 +6748,7 @@ function FollowUpAdMixed({
6473
6748
  onClick: onAdClick,
6474
6749
  onImpression: onAdImpression
6475
6750
  },
6476
- `ad-${index}`
6751
+ `ad-${index2}`
6477
6752
  );
6478
6753
  }
6479
6754
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -6489,7 +6764,7 @@ function FollowUpAdMixed({
6489
6764
  ),
6490
6765
  children: String(item.content)
6491
6766
  },
6492
- `question-${index}`
6767
+ `question-${index2}`
6493
6768
  );
6494
6769
  }) });
6495
6770
  }
@@ -6636,8 +6911,8 @@ function SourceListWithAds({
6636
6911
  if (!ad) return sources.map((s) => ({ type: "source", content: s }));
6637
6912
  const result = [];
6638
6913
  let adInserted = false;
6639
- sources.forEach((source, index) => {
6640
- if (index === adPosition && !adInserted) {
6914
+ sources.forEach((source, index2) => {
6915
+ if (index2 === adPosition && !adInserted) {
6641
6916
  result.push({ type: "ad", content: ad });
6642
6917
  adInserted = true;
6643
6918
  }
@@ -6648,7 +6923,7 @@ function SourceListWithAds({
6648
6923
  }
6649
6924
  return result;
6650
6925
  }, [sources, ad, adPosition]);
6651
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("space-y-1", className), children: items.map((item, index) => {
6926
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("space-y-1", className), children: items.map((item, index2) => {
6652
6927
  if (item.type === "ad") {
6653
6928
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
6654
6929
  SponsoredSource,
@@ -6658,7 +6933,7 @@ function SourceListWithAds({
6658
6933
  onClick: onAdClick,
6659
6934
  onImpression: onAdImpression
6660
6935
  },
6661
- `ad-${index}`
6936
+ `ad-${index2}`
6662
6937
  );
6663
6938
  }
6664
6939
  const source = item.content;
@@ -6682,7 +6957,7 @@ function SourceListWithAds({
6682
6957
  )
6683
6958
  ]
6684
6959
  },
6685
- `source-${index}`
6960
+ `source-${index2}`
6686
6961
  );
6687
6962
  }) });
6688
6963
  }
@@ -7529,7 +7804,7 @@ function StaticAdContainer({
7529
7804
  className
7530
7805
  ),
7531
7806
  style: { gap: `${gap}px` },
7532
- children: visibleAds.map((ad, index) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "animate-slide-up", style: { animationDelay: `${index * 30}ms` }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(StaticAd, { ad, size }) }, ad.id))
7807
+ children: visibleAds.map((ad, index2) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "animate-slide-up", style: { animationDelay: `${index2 * 30}ms` }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(StaticAd, { ad, size }) }, ad.id))
7533
7808
  }
7534
7809
  );
7535
7810
  }
@@ -7794,7 +8069,7 @@ function AdAnalyticsDashboard({
7794
8069
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6", children: [
7795
8070
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white/70 backdrop-blur-md rounded-2xl border border-ad-border/50 shadow-glass p-6", children: [
7796
8071
  /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-bold text-ad-text-primary mb-4", children: "Top Performing Ads" }),
7797
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-4", children: metrics.sort((a, b) => b.ctr - a.ctr).slice(0, 5).map((ad, index) => /* @__PURE__ */ jsxRuntimeExports.jsx(AdPerformanceRow, { ad, rank: index + 1 }, ad.adId)) })
8072
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-4", children: metrics.sort((a, b) => b.ctr - a.ctr).slice(0, 5).map((ad, index2) => /* @__PURE__ */ jsxRuntimeExports.jsx(AdPerformanceRow, { ad, rank: index2 + 1 }, ad.adId)) })
7798
8073
  ] }),
7799
8074
  showBySource && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white/70 backdrop-blur-md rounded-2xl border border-ad-border/50 shadow-glass p-6", children: [
7800
8075
  /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-bold text-ad-text-primary mb-4", children: "By Ad Source" }),
@@ -8805,6 +9080,12 @@ export {
8805
9080
  EnhancedContent,
8806
9081
  EnhancedContentBlock,
8807
9082
  EnhancedContentInline,
9083
+ EnhancedContentV2,
9084
+ EnhancedContentV2Block,
9085
+ EnhancedContentV2Inline,
9086
+ EntityLinkAd,
9087
+ EntityLinkAdBlock,
9088
+ EntityLinkAdInline,
8808
9089
  FollowUpAd,
8809
9090
  FollowUpAdMixed,
8810
9091
  FullPageLoading,