@ai-ad-network/frontend-sdk 1.0.5 → 1.0.7

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.
@@ -0,0 +1,175 @@
1
+ # 🚀 快速集成清单(5 分钟完成)
2
+
3
+ ## 前置条件
4
+
5
+ - Node.js >= 16
6
+ - React >= 18
7
+ - 已有后端广告 API(`/api/v1/ads/request`)
8
+
9
+ ---
10
+
11
+ ## ✅ 集成步骤
12
+
13
+ ### 1️⃣ 安装 SDK(30 秒)
14
+
15
+ ```bash
16
+ npm install @ai-ad-network/frontend-sdk
17
+ ```
18
+
19
+ ### 2️⃣ 添加代码(2 分钟)
20
+
21
+ #### React Hook 方式(推荐)
22
+
23
+ ```tsx
24
+ import { useAdSlots } from '@ai-ad-network/frontend-sdk';
25
+
26
+ function MyChatApp() {
27
+ // ✅ 一行代码初始化,ClientInfo 自动采集!
28
+ const { slots, requestAds } = useAdSlots({
29
+ apiBaseUrl: '/api/v1',
30
+ slots: [{
31
+ slotId: 'main-ad',
32
+ format: 'action_card',
33
+ variant: 'horizontal',
34
+ size: { width: 280, height: 80 },
35
+ }],
36
+ enabled: true,
37
+ });
38
+
39
+ // 发送消息后请求广告
40
+ const onMessageSent = async (query: string, response: string) => {
41
+ // ✅ ClientInfo 会自动注入,无需手动传递!
42
+ await requestAds({
43
+ conversationContext: { query, response },
44
+ userContext: { sessionId: 'session-123' },
45
+ });
46
+ };
47
+
48
+ return (
49
+ <div>
50
+ {slots['main-ad']?.ads?.map(ad => (
51
+ <AdComponent key={ad.id} ad={ad} />
52
+ ))}
53
+ </div>
54
+ );
55
+ }
56
+ ```
57
+
58
+ #### 直接调用方式(非 React)
59
+
60
+ ```typescript
61
+ import { fetchAds } from '@ai-ad-network/frontend-sdk';
62
+
63
+ // ✅ 一行代码调用,ClientInfo 自动注入!
64
+ const result = await fetchAds({
65
+ conversationContext: { query, response },
66
+ userContext: { sessionId: 'session-123' },
67
+ slots: [{ slotId: 'main-ad', format: 'action_card' }],
68
+ }, { apiBaseUrl: '/api/v1' });
69
+ ```
70
+
71
+ ### 3️⃣ 验证集成(1 分钟)
72
+
73
+ 打开浏览器 Console,检查:
74
+
75
+ ```
76
+ ✅ [AI Ad Network SDK] v1.0.5
77
+ ✅ [SDK] ClientInfo collection: ENABLED
78
+ ✅ [useAdSlots] ClientInfo collected: { hasDevice: true, ... }
79
+ ```
80
+
81
+ 打开 Network 面板,检查请求 Payload:
82
+
83
+ ```json
84
+ {
85
+ "conversationContext": {...},
86
+ "userContext": {...},
87
+ "clientInfo": { // ✅ 确认存在!
88
+ "device": {...},
89
+ "app": {...},
90
+ "user": {...},
91
+ "geo": {...}
92
+ },
93
+ "slots": [...]
94
+ }
95
+ ```
96
+
97
+ ### 4️⃣ 完成!🎉
98
+
99
+ ---
100
+
101
+ ## 🔍 故障排查
102
+
103
+ ### ❌ Console 显示旧版本?
104
+
105
+ ```bash
106
+ rm -rf node_modules package-lock.json
107
+ npm install @ai-ad-network/frontend-sdk@latest
108
+ ```
109
+
110
+ ### ❌ Network 请求中没有 clientInfo?
111
+
112
+ **检查代码**:
113
+ - ✅ 是否使用了 `useAdSlots` 或 `fetchAds`?
114
+ - ✅ 是否调用了 `requestAds` 函数?
115
+ - ✅ SDK 版本是否 >= 1.0.5?
116
+
117
+ **调试**:
118
+ ```javascript
119
+ // Console 中执行
120
+ import { getClientInfoCollector } from '@ai-ad-network/frontend-sdk';
121
+ const info = getClientInfoCollector().collect();
122
+ console.log('ClientInfo:', info);
123
+ ```
124
+
125
+ ### ❌ 看到 "requestAds is not a function"?
126
+
127
+ 确保正确解构:
128
+ ```tsx
129
+ const { slots, requestAds } = useAdSlots({...});
130
+ // ^^^^^^^^^^^ 必须解构出来
131
+ ```
132
+
133
+ ---
134
+
135
+ ## 📚 完整文档
136
+
137
+ - 📖 [完整集成指南](./docs/QUICK_START.md)
138
+ - 🔧 [API 文档](./docs/COMPONENT_DOCUMENTATION.md)
139
+ - 🌍 [ClientInfo 详解](./docs/CLIENT_INFO_COLLECTION.md)
140
+
141
+ ---
142
+
143
+ ## 💡 最佳实践
144
+
145
+ ### ✅ DO(推荐做法)
146
+
147
+ - ✅ 在组件顶层初始化 `useAdSlots`
148
+ - ✅ 在消息发送成功后调用 `requestAds`
149
+ - ✅ 使用持久化的 sessionId
150
+ - ✅ 在开发环境启用 debug 模式
151
+
152
+ ### ❌ DON'T(避免做法)
153
+
154
+ - ❌ 不要手动构造 clientInfo
155
+ - ❌ 不要在循环中调用 `requestAds`
156
+ - ❌ 不要每次渲染都初始化 `useAdSlots`
157
+ - ❌ 不要忘记处理错误状态
158
+
159
+ ---
160
+
161
+ ## 🆘 需要帮助?
162
+
163
+ - 📧 Email: support@example.com
164
+ - 💬 Slack: #sdk-support
165
+ - 🐛 Issues: [GitHub Issues](https://github.com/your-repo/issues)
166
+
167
+ ---
168
+
169
+ **集成成功后,你将获得:**
170
+ - 🎯 精准的广告投放(基于设备、用户、地理位置)
171
+ - 📊 完整的数据追踪
172
+ - ⚡ 零配置的自动采集
173
+ - 🔒 OpenRTB 标准合规
174
+
175
+ **祝集成顺利!** 🚀
package/README.md CHANGED
@@ -1,8 +1,38 @@
1
1
  # AI Ad Network Frontend SDK
2
2
 
3
- > React SDK for displaying native, AI-powered ads in your application
3
+ > 🚀 **Zero-config** SDK for AI-powered native ads with automatic client info collection
4
+ >
5
+ > 📦 **Dual Support**: React SDK + Universal Framework-Agnostic SDK
6
+
7
+ ## 🎯 Choose Your Integration
8
+
9
+ ### React Projects (Original SDK)
10
+ ```bash
11
+ npm install @ai-ad-network/frontend-sdk
12
+ ```
13
+ ```tsx
14
+ import { AdProvider, useAiAds } from '@ai-ad-network/frontend-sdk';
15
+ ```
4
16
 
5
- ## Features
17
+ ### Any Other Framework (Universal SDK) ⭐ NEW
18
+ ```bash
19
+ npm install @ai-ad-network/frontend-sdk
20
+ ```
21
+ ```javascript
22
+ import { AdManager, DOMRenderer } from '@ai-ad-network/frontend-sdk/universal';
23
+ ```
24
+
25
+ **Universal SDK Works With:**
26
+ - ✅ Vanilla JavaScript
27
+ - ✅ Vue 2 & 3
28
+ - ✅ Angular
29
+ - ✅ Svelte
30
+ - ✅ SolidJS
31
+ - ✅ Any other framework
32
+
33
+ 📖 **[Universal SDK Guide](./docs/UNIVERSAL_SDK_GUIDE.md)** for non-React frameworks
34
+
35
+ ## ✨ Key Features
6
36
 
7
37
  - 🎯 **Intent-based Ad Delivery** - Ads matched to user intent
8
38
  - 🎨 **Native Ad Formats** - Action Cards, Suffix, Follow-up, Sponsored Sources
@@ -11,7 +41,98 @@
11
41
  - 🎭 **Headless Design** - Full customization with CSS variables
12
42
  - 📱 **Responsive** - Works on all screen sizes
13
43
  - 🔐 **Built-in Authentication** - API key support for secure access
14
- - 🌐 **OpenRTB Compliant** - Auto-collects device info for better ad targeting
44
+ - 🌐 **OpenRTB Compliant** - ✨ **Zero-config** auto-collection of device/app/user/geo info
45
+
46
+ ## 🚀 Zero-Config ClientInfo Collection
47
+
48
+ **No manual setup required!** The SDK automatically collects and injects OpenRTB-compliant client information:
49
+
50
+ ```tsx
51
+ import { useAdSlots } from '@ai-ad-network/frontend-sdk';
52
+
53
+ function ChatApp() {
54
+ const { requestAds } = useAdSlots({
55
+ apiBaseUrl: '/api/v1',
56
+ slots: [/* your slots */],
57
+ enabled: true,
58
+ });
59
+
60
+ // ✅ ClientInfo is AUTOMATICALLY collected and injected!
61
+ await requestAds({
62
+ conversationContext: { query, response },
63
+ userContext: { sessionId },
64
+ });
65
+
66
+ // Request payload automatically includes:
67
+ // {
68
+ // conversationContext: {...},
69
+ // userContext: {...},
70
+ // clientInfo: { // ← Zero-config! Auto-collected!
71
+ // device: { os, model, screen... },
72
+ // app: { bundle, name, version... },
73
+ // user: { id, consent... },
74
+ // geo: { country, language... }
75
+ // }
76
+ // }
77
+ }
78
+ ```
79
+
80
+ **What's auto-collected:**
81
+ - 🖥️ **Device Info**: OS, model, screen size, language
82
+ - 📱 **App Info**: Bundle ID, name, version (inferred from page)
83
+ - 👤 **User Info**: Unique ID (auto-generated & persistent)
84
+ - 🌍 **Geo Info**: Country, language (from timezone/locale)
85
+
86
+ 📖 **See [ClientInfo Documentation](./docs/CLIENT_INFO_COLLECTION.md)**
87
+
88
+ ---
89
+
90
+ ## 🆕 ClientInfo API ⭐ NEW
91
+
92
+ **Direct access to client information for your own use!**
93
+
94
+ The SDK now exposes convenient functions to access client info for analytics, personalization, A/B testing, and more.
95
+
96
+ ```typescript
97
+ // React SDK
98
+ import { getUserId, getDeviceInfo, getClientInfo } from '@ai-ad-network/frontend-sdk';
99
+
100
+ // Universal SDK (Vue, Angular, etc.)
101
+ import { getUserId, getDeviceInfo, getClientInfo } from '@ai-ad-network/frontend-sdk/universal';
102
+
103
+ // Get user ID for analytics
104
+ const userId = getUserId();
105
+ analytics.identify(userId);
106
+
107
+ // Get device info for conditional features
108
+ const device = getDeviceInfo();
109
+ if (device.devicetype === 1) {
110
+ // Mobile - enable mobile optimizations
111
+ } else {
112
+ // Desktop - enable desktop features
113
+ }
114
+
115
+ // Get complete info for personalization
116
+ const info = getClientInfo();
117
+ if (info.geo?.country === 'CN') {
118
+ loadChinesePaymentMethods();
119
+ }
120
+ ```
121
+
122
+ **Available Functions:**
123
+ - `getClientInfo()` - Get complete client information
124
+ - `getUserId()` - Get persistent user ID
125
+ - `getDeviceInfo()` - Get device info only
126
+ - `getUserInfo()` - Get user info only
127
+ - `getAppInfo()` - Get app info only
128
+ - `getGeoInfo()` - Get geo info only
129
+ - `getClientInfoJSON()` - Get as JSON string
130
+ - `getClientInfoSummary()` - Get human-readable summary
131
+ - `clearClientInfoCache()` - Force re-collection
132
+
133
+ 📖 **[Universal SDK Guide - ClientInfo API](./docs/UNIVERSAL_SDK_GUIDE.md#clientinfo-api--new)**
134
+
135
+ 📖 **See [Quick Start Guide](./docs/QUICK_START.md) for complete integration docs.**
15
136
 
16
137
  ## Installation
17
138
 
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.0.4";
6
+ const SDK_VERSION = "1.0.7";
7
7
  var IntentType = /* @__PURE__ */ ((IntentType2) => {
8
8
  IntentType2["SHOPPING"] = "shopping";
9
9
  IntentType2["LEAD_GEN"] = "lead_gen";
@@ -649,6 +649,45 @@ const _ClientInfoCollector = class _ClientInfoCollector {
649
649
  __publicField(_ClientInfoCollector, "instance");
650
650
  let ClientInfoCollector = _ClientInfoCollector;
651
651
  const getClientInfoCollector = () => ClientInfoCollector.getInstance();
652
+ function getClientInfo(options) {
653
+ const collector = getClientInfoCollector();
654
+ return collector.collect(options);
655
+ }
656
+ function getDeviceInfo() {
657
+ return getClientInfo().device;
658
+ }
659
+ function getUserInfo() {
660
+ return getClientInfo().user;
661
+ }
662
+ function getAppInfo() {
663
+ return getClientInfo().app;
664
+ }
665
+ function getGeoInfo() {
666
+ return getClientInfo().geo;
667
+ }
668
+ function getUserId() {
669
+ return getUserInfo().id;
670
+ }
671
+ function clearClientInfoCache() {
672
+ const collector = getClientInfoCollector();
673
+ collector.clearCache();
674
+ }
675
+ function getClientInfoJSON(options) {
676
+ const info = getClientInfo(options);
677
+ return JSON.stringify(info, null, 2);
678
+ }
679
+ function getClientInfoSummary() {
680
+ var _a;
681
+ const info = getClientInfo();
682
+ const parts = [
683
+ info.device.os,
684
+ info.device.osv,
685
+ info.app.name,
686
+ info.user.id.slice(0, 8) + "...",
687
+ ((_a = info.geo) == null ? void 0 : _a.country) || "Unknown"
688
+ ];
689
+ return parts.join(" / ");
690
+ }
652
691
  function adaptAdToKoahAd(adaptedAd) {
653
692
  var _a, _b;
654
693
  return {
@@ -7660,15 +7699,24 @@ export {
7660
7699
  TextWeaver,
7661
7700
  adaptAdToKoahAd,
7662
7701
  checkFrequencyControl,
7702
+ clearClientInfoCache,
7663
7703
  cn,
7664
7704
  createLogger,
7665
7705
  fetchAds,
7666
7706
  getAdById,
7667
7707
  getAdsByCategory,
7668
7708
  getAdsBySource,
7709
+ getAppInfo,
7710
+ getClientInfo,
7669
7711
  getClientInfoCollector,
7712
+ getClientInfoJSON,
7713
+ getClientInfoSummary,
7714
+ getDeviceInfo,
7715
+ getGeoInfo,
7670
7716
  getRandomAds,
7671
7717
  getSessionId,
7718
+ getUserId,
7719
+ getUserInfo,
7672
7720
  hashUserId,
7673
7721
  mockAds,
7674
7722
  mockAnalyticsData,
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
5
5
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
6
6
  const React = require("react");
7
7
  const useSWR = require("swr");
8
- const SDK_VERSION = "1.0.4";
8
+ const SDK_VERSION = "1.0.7";
9
9
  var IntentType = /* @__PURE__ */ ((IntentType2) => {
10
10
  IntentType2["SHOPPING"] = "shopping";
11
11
  IntentType2["LEAD_GEN"] = "lead_gen";
@@ -651,6 +651,45 @@ const _ClientInfoCollector = class _ClientInfoCollector {
651
651
  __publicField(_ClientInfoCollector, "instance");
652
652
  let ClientInfoCollector = _ClientInfoCollector;
653
653
  const getClientInfoCollector = () => ClientInfoCollector.getInstance();
654
+ function getClientInfo(options) {
655
+ const collector = getClientInfoCollector();
656
+ return collector.collect(options);
657
+ }
658
+ function getDeviceInfo() {
659
+ return getClientInfo().device;
660
+ }
661
+ function getUserInfo() {
662
+ return getClientInfo().user;
663
+ }
664
+ function getAppInfo() {
665
+ return getClientInfo().app;
666
+ }
667
+ function getGeoInfo() {
668
+ return getClientInfo().geo;
669
+ }
670
+ function getUserId() {
671
+ return getUserInfo().id;
672
+ }
673
+ function clearClientInfoCache() {
674
+ const collector = getClientInfoCollector();
675
+ collector.clearCache();
676
+ }
677
+ function getClientInfoJSON(options) {
678
+ const info = getClientInfo(options);
679
+ return JSON.stringify(info, null, 2);
680
+ }
681
+ function getClientInfoSummary() {
682
+ var _a;
683
+ const info = getClientInfo();
684
+ const parts = [
685
+ info.device.os,
686
+ info.device.osv,
687
+ info.app.name,
688
+ info.user.id.slice(0, 8) + "...",
689
+ ((_a = info.geo) == null ? void 0 : _a.country) || "Unknown"
690
+ ];
691
+ return parts.join(" / ");
692
+ }
654
693
  function adaptAdToKoahAd(adaptedAd) {
655
694
  var _a, _b;
656
695
  return {
@@ -7661,15 +7700,24 @@ exports.SuffixAdMinimal = SuffixAdMinimal;
7661
7700
  exports.TextWeaver = TextWeaver;
7662
7701
  exports.adaptAdToKoahAd = adaptAdToKoahAd;
7663
7702
  exports.checkFrequencyControl = checkFrequencyControl;
7703
+ exports.clearClientInfoCache = clearClientInfoCache;
7664
7704
  exports.cn = cn;
7665
7705
  exports.createLogger = createLogger;
7666
7706
  exports.fetchAds = fetchAds;
7667
7707
  exports.getAdById = getAdById;
7668
7708
  exports.getAdsByCategory = getAdsByCategory;
7669
7709
  exports.getAdsBySource = getAdsBySource;
7710
+ exports.getAppInfo = getAppInfo;
7711
+ exports.getClientInfo = getClientInfo;
7670
7712
  exports.getClientInfoCollector = getClientInfoCollector;
7713
+ exports.getClientInfoJSON = getClientInfoJSON;
7714
+ exports.getClientInfoSummary = getClientInfoSummary;
7715
+ exports.getDeviceInfo = getDeviceInfo;
7716
+ exports.getGeoInfo = getGeoInfo;
7671
7717
  exports.getRandomAds = getRandomAds;
7672
7718
  exports.getSessionId = getSessionId;
7719
+ exports.getUserId = getUserId;
7720
+ exports.getUserInfo = getUserInfo;
7673
7721
  exports.hashUserId = hashUserId;
7674
7722
  exports.mockAds = mockAds;
7675
7723
  exports.mockAnalyticsData = mockAnalyticsData;
package/dist/style.css CHANGED
@@ -675,6 +675,9 @@ video {
675
675
  .list-item {
676
676
  display: list-item;
677
677
  }
678
+ .hidden {
679
+ display: none;
680
+ }
678
681
  .aspect-\[4\/3\] {
679
682
  aspect-ratio: 4/3;
680
683
  }
@@ -1607,6 +1610,11 @@ video {
1607
1610
  .opacity-\[0\.02\] {
1608
1611
  opacity: 0.02;
1609
1612
  }
1613
+ .shadow {
1614
+ --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
1615
+ --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
1616
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
1617
+ }
1610
1618
  .shadow-glass {
1611
1619
  --tw-shadow: 0 4px 24px -1px rgba(0, 0, 0, 0.06), 0 2px 8px -1px rgba(0, 0, 0, 0.04);
1612
1620
  --tw-shadow-colored: 0 4px 24px -1px var(--tw-shadow-color), 0 2px 8px -1px var(--tw-shadow-color);
@@ -1638,6 +1646,11 @@ video {
1638
1646
  --tw-backdrop-blur: blur(4px);
1639
1647
  backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
1640
1648
  }
1649
+ .transition {
1650
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
1651
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1652
+ transition-duration: 150ms;
1653
+ }
1641
1654
  .transition-all {
1642
1655
  transition-property: all;
1643
1656
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);