bw-frontend-sdk 1.0.0

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/README.md ADDED
@@ -0,0 +1,386 @@
1
+ # 前端埋点 SDK
2
+
3
+ 一个功能完整的前端埋点SDK,支持异常捕获、用户行为追踪、性能监控和第三方埋点集成。
4
+
5
+ ## 功能特性
6
+
7
+ - 🔍 **异常拦截**: 自动捕获 JavaScript 错误、Promise 拒绝、资源加载错误
8
+ - 📊 **事件追踪**: 自动追踪页面浏览、点击事件,支持自定义事件
9
+ - 📈 **性能监控**: 监控首屏加载时间、白屏时间、HTTP请求响应时间、页面渲染时间
10
+ - 👤 **用户行为追踪**: 追踪页面停留时间、滚动行为、表单交互、鼠标移动、键盘输入
11
+ - 🚀 **批量上报**: 支持批量上报,减少网络请求
12
+ - 🔧 **灵活配置**: 支持多种上报方式和第三方埋点
13
+ - 🛡️ **错误处理**: 完善的错误处理和重试机制
14
+ - 📦 **轻量级**: 体积小,性能优秀
15
+ - 🔗 **第三方集成**: 支持百度统计、友盟统计、神策数据、腾讯云分析、Google Analytics等
16
+
17
+ ## 安装
18
+
19
+ ```bash
20
+ npm install frontend-sdk
21
+ ```
22
+
23
+ ## 快速开始
24
+
25
+ ### 基础使用
26
+
27
+ ```javascript
28
+ import FrontendSDK from 'frontend-sdk'
29
+
30
+ const sdk = new FrontendSDK({
31
+ appId: 'your-app-id',
32
+ reportUrl: 'https://your-api.com/report',
33
+ enableErrorTracking: true,
34
+ enableEventTracking: true
35
+ })
36
+ ```
37
+
38
+ ### Vue 3 集成
39
+
40
+ ```javascript
41
+ // main.js
42
+ import { createApp } from 'vue'
43
+ import App from './App.vue'
44
+ import FrontendSDK from 'frontend-sdk'
45
+
46
+ const app = createApp(App)
47
+
48
+ // 初始化 SDK
49
+ const sdk = new FrontendSDK({
50
+ appId: 'your-app-id',
51
+ reportUrl: 'https://your-api.com/report'
52
+ })
53
+
54
+ // 全局注册
55
+ app.config.globalProperties.$sdk = sdk
56
+
57
+ // 全局错误处理
58
+ app.config.errorHandler = (error, instance, info) => {
59
+ sdk.reportError(error, {
60
+ component: instance?.$options?.name,
61
+ info: info
62
+ })
63
+ }
64
+
65
+ app.mount('#app')
66
+ ```
67
+
68
+ ### 在组件中使用
69
+
70
+ ```javascript
71
+ export default {
72
+ mounted() {
73
+ // 上报页面浏览
74
+ this.$sdk.reportEvent('page_view', {
75
+ page: 'home',
76
+ title: '首页'
77
+ })
78
+ },
79
+ methods: {
80
+ handleClick() {
81
+ // 上报点击事件
82
+ this.$sdk.reportEvent('button_click', {
83
+ buttonId: 'submit',
84
+ action: 'submit_form'
85
+ })
86
+ },
87
+ handleError() {
88
+ // 上报错误
89
+ this.$sdk.reportError(new Error('操作失败'), {
90
+ page: 'form',
91
+ action: 'submit'
92
+ })
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ ## 配置选项
99
+
100
+ ```javascript
101
+ const config = {
102
+ // 基础配置
103
+ appId: 'your-app-id', // 应用ID
104
+ appVersion: '1.0.0', // 应用版本
105
+ environment: 'production', // 环境
106
+
107
+ // 上报配置
108
+ reportUrl: 'https://api.com/report', // 上报地址
109
+ reportInterval: 5000, // 批量上报间隔(ms)
110
+ maxQueueSize: 100, // 最大队列大小
111
+
112
+ // 错误追踪配置
113
+ enableErrorTracking: true, // 启用错误追踪
114
+ enableUnhandledRejection: true, // 启用未处理Promise拒绝追踪
115
+ enableResourceError: true, // 启用资源错误追踪
116
+
117
+ // 事件追踪配置
118
+ enableEventTracking: true, // 启用事件追踪
119
+ enableClickTracking: true, // 启用点击追踪
120
+ enablePageViewTracking: true, // 启用页面浏览追踪
121
+
122
+ // 性能监控配置
123
+ enablePerformanceTracking: true, // 启用性能监控
124
+ enableResourceTracking: true, // 启用资源加载监控
125
+ enableApiTracking: true, // 启用API请求监控
126
+ enableInteractionTracking: true, // 启用用户交互性能监控
127
+
128
+ // 用户行为追踪配置
129
+ enableUserInteractionTracking: true, // 启用用户交互追踪
130
+ enableFormTracking: true, // 启用表单行为追踪
131
+ enableScrollTracking: true, // 启用滚动行为追踪
132
+ enableMouseTracking: false, // 启用鼠标移动追踪(可选)
133
+ enableKeyboardTracking: false, // 启用键盘输入追踪(可选)
134
+
135
+ // 第三方埋点配置
136
+ thirdPartyConfig: {
137
+ baidu: {
138
+ enabled: true,
139
+ siteId: 'your-baidu-site-id',
140
+ autoPageview: true
141
+ }, // 百度统计
142
+ umeng: {
143
+ enabled: true,
144
+ siteId: 'your-umeng-site-id',
145
+ autoPageview: true
146
+ }, // 友盟统计
147
+ sensors: {
148
+ enabled: true,
149
+ serverUrl: 'https://your-sensors-server.com',
150
+ siteId: 'your-sensors-site-id',
151
+ autoPageview: true
152
+ }, // 神策数据
153
+ tencent: {
154
+ enabled: true,
155
+ appId: 'your-tencent-app-id',
156
+ autoPageview: true
157
+ }, // 腾讯云分析
158
+ google: {
159
+ enabled: true,
160
+ measurementId: 'G-XXXXXXXXXX',
161
+ autoPageview: true
162
+ }, // Google Analytics
163
+ custom: { // 自定义第三方
164
+ enabled: true,
165
+ init: (config) => {
166
+ // 自定义第三方SDK初始化逻辑
167
+ return {
168
+ track: (eventName, data) => { /* 追踪事件 */ },
169
+ trackPageview: (data) => { /* 追踪页面浏览 */ },
170
+ setUser: (userData) => { /* 设置用户信息 */ },
171
+ trackPerformance: (data) => { /* 追踪性能指标 */ }
172
+ }
173
+ }
174
+ }
175
+ },
176
+
177
+ // 自定义上报函数
178
+ customReport: async (type, data) => {
179
+ // 自定义上报逻辑
180
+ }
181
+ }
182
+ ```
183
+
184
+ ## API 参考
185
+
186
+ ### FrontendSDK
187
+
188
+ #### 构造函数
189
+
190
+ ```javascript
191
+ new FrontendSDK(options)
192
+ ```
193
+
194
+ #### 方法
195
+
196
+ - `reportError(error, context)`: 手动上报错误
197
+ - `reportEvent(eventName, data)`: 手动上报事件
198
+ - `reportPerformance(metrics)`: 手动上报性能指标
199
+ - `reportBehavior(eventName, data)`: 手动上报用户行为
200
+ - `setUser(userInfo)`: 设置用户信息
201
+ - `setConfig(config)`: 更新配置
202
+ - `getPerformanceMetrics()`: 获取当前性能指标
203
+ - `getBehaviorData()`: 获取用户行为数据
204
+ - `getSessionId()`: 获取当前会话ID
205
+ - `isThirdPartySDKIntegrated(sdkName)`: 检查第三方SDK是否已集成
206
+ - `getIntegratedThirdPartySDKs()`: 获取已集成的第三方SDK列表
207
+ - `destroy()`: 销毁 SDK
208
+
209
+ ### 事件类型
210
+
211
+ - `javascript`: JavaScript 错误
212
+ - `unhandledrejection`: 未处理的 Promise 拒绝
213
+ - `resource`: 资源加载错误
214
+ - `click`: 点击事件
215
+ - `pageview`: 页面浏览事件
216
+ - `custom`: 自定义事件
217
+ - `performance`: 性能指标
218
+ - `behavior`: 用户行为
219
+ - `page_stay`: 页面停留时间
220
+ - `slow_resource`: 慢资源加载
221
+ - `slow_api`: 慢API请求
222
+
223
+ ## 性能监控
224
+
225
+ SDK 自动监控以下性能指标:
226
+
227
+ - **首屏加载时间**: First Contentful Paint (FCP)
228
+ - **最大内容绘制**: Largest Contentful Paint (LCP)
229
+ - **首次输入延迟**: First Input Delay (FID)
230
+ - **累积布局偏移**: Cumulative Layout Shift (CLS)
231
+ - **DOM加载时间**: DOM Content Loaded
232
+ - **页面完全加载时间**: Window Load
233
+ - **资源加载时间**: 图片、CSS、JS等资源加载性能
234
+ - **API请求响应时间**: Fetch和XMLHttpRequest请求性能
235
+
236
+ ## 用户行为追踪
237
+
238
+ SDK 自动追踪以下用户行为:
239
+
240
+ - **页面浏览**: 页面访问、路由变化、访问来源
241
+ - **点击行为**: 点击、双击、右键点击、触摸事件
242
+ - **表单交互**: 表单提交、字段变化、聚焦失焦
243
+ - **滚动行为**: 滚动深度、滚动位置
244
+ - **鼠标移动**: 鼠标轨迹(可选)
245
+ - **键盘输入**: 按键事件(可选)
246
+ - **页面停留时间**: 用户在页面的停留时长
247
+
248
+ ## 第三方埋点支持
249
+
250
+ ### 百度统计
251
+
252
+ ```javascript
253
+ // 在 HTML 中引入百度统计
254
+ <script>
255
+ var _hmt = _hmt || [];
256
+ (function() {
257
+ var hm = document.createElement("script");
258
+ hm.src = "https://hm.baidu.com/hm.js?YOUR_SITE_ID";
259
+ var s = document.getElementsByTagName("script")[0];
260
+ s.parentNode.insertBefore(hm, s);
261
+ })();
262
+ </script>
263
+ ```
264
+
265
+ ### 友盟统计
266
+
267
+ ```javascript
268
+ // 在 HTML 中引入友盟统计
269
+ <script>
270
+ (function() {
271
+ var um = document.createElement('script');
272
+ um.src = 'https://s4.cnzz.com/z_stat.php?id=YOUR_SITE_ID&web_id=YOUR_SITE_ID';
273
+ var s = document.getElementsByTagName('script')[0];
274
+ s.parentNode.insertBefore(um, s);
275
+ })();
276
+ </script>
277
+ ```
278
+
279
+ ### 神策数据
280
+
281
+ ```javascript
282
+ // 在 HTML 中引入神策数据
283
+ <script>
284
+ !function(e,t,n,s,a,c,i){e[s]=e[s]||function(){(e[s].q=e[s].q||[]).push(arguments)},a=t.createElement(n),c=t.getElementsByTagName(n)[0],a.async=1,a.src="https://www.sensorsdata.cn/sdk.js",c.parentNode.insertBefore(a,c)}(window,document,"script","sensors");
285
+ sensors.init("YOUR_SITE_ID");
286
+ </script>
287
+ ```
288
+
289
+ ### Google Analytics
290
+
291
+ ```javascript
292
+ // 在 HTML 中引入 Google Analytics
293
+ <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
294
+ <script>
295
+ window.dataLayer = window.dataLayer || [];
296
+ function gtag(){dataLayer.push(arguments);}
297
+ gtag('js', new Date());
298
+ gtag('config', 'G-XXXXXXXXXX');
299
+ </script>
300
+ ```
301
+
302
+ ## 完整使用示例
303
+
304
+ ```javascript
305
+ import FrontendSDK from 'frontend-sdk'
306
+
307
+ // 初始化SDK
308
+ const sdk = new FrontendSDK({
309
+ appId: 'your-app-id',
310
+ reportUrl: 'https://your-api.com/report',
311
+
312
+ // 启用所有功能
313
+ enableErrorTracking: true,
314
+ enableEventTracking: true,
315
+ enablePerformanceTracking: true,
316
+ enableUserInteractionTracking: true,
317
+ enableFormTracking: true,
318
+ enableScrollTracking: true,
319
+
320
+ // 第三方埋点配置
321
+ thirdPartyConfig: {
322
+ baidu: {
323
+ enabled: true,
324
+ siteId: 'your-baidu-site-id'
325
+ },
326
+ google: {
327
+ enabled: true,
328
+ measurementId: 'G-XXXXXXXXXX'
329
+ }
330
+ }
331
+ })
332
+
333
+ // 设置用户信息
334
+ sdk.setUser({
335
+ userId: 'user123',
336
+ userName: '张三',
337
+ userType: 'vip'
338
+ })
339
+
340
+ // 手动上报事件
341
+ sdk.reportEvent('button_click', {
342
+ buttonId: 'submit-btn',
343
+ buttonText: '提交'
344
+ })
345
+
346
+ // 手动上报性能指标
347
+ sdk.reportPerformance({
348
+ customMetric: 'custom_value',
349
+ pageLoadTime: 1500
350
+ })
351
+
352
+ // 手动上报用户行为
353
+ sdk.reportBehavior('form_start', {
354
+ formId: 'login-form',
355
+ formType: 'login'
356
+ })
357
+
358
+ // 获取性能指标
359
+ const metrics = sdk.getPerformanceMetrics()
360
+ console.log('性能指标:', metrics)
361
+
362
+ // 获取用户行为数据
363
+ const behaviorData = sdk.getBehaviorData()
364
+ console.log('行为数据:', behaviorData)
365
+
366
+ // 检查第三方SDK集成状态
367
+ const isGoogleIntegrated = sdk.isThirdPartySDKIntegrated('google')
368
+ console.log('Google Analytics集成状态:', isGoogleIntegrated)
369
+ ```
370
+
371
+ ## 构建
372
+
373
+ ```bash
374
+ # 安装依赖
375
+ npm install
376
+
377
+ # 构建
378
+ npm run build
379
+
380
+ # 开发模式
381
+ npm run dev
382
+ ```
383
+
384
+ ## 许可证
385
+
386
+ MIT
@@ -0,0 +1,2 @@
1
+ class e{constructor(e){this.config=e,this.isReporting=!1}async report(e,t){if(!this.isReporting){this.isReporting=!0;try{const i=this.formatReportData(e,t);this.config.getConfig().customReport?await this.config.getConfig().customReport(e,i):await this.defaultReport(e,i)}catch(e){console.error("上报失败:",e)}finally{this.isReporting=!1}}}formatReportData(e,t){return{...{type:e,timestamp:Date.now(),url:window.location.href,userAgent:navigator.userAgent,user:this.config.getUser(),config:{appId:this.config.getConfig().appId,appVersion:this.config.getConfig().appVersion,environment:this.config.getConfig().environment}},data:Array.isArray(t)?t:[t]}}async defaultReport(e,t){const i=this.config.getReportUrl(),r=this.config.getThirdPartyConfig();i&&await this.reportToBackend(i,t),r&&Object.keys(r).length>0&&await this.reportToThirdParty(r,t)}async reportToBackend(e,t){try{const i=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);return await i.json()}catch(e){throw console.error("后端上报失败:",e),e}}async reportToThirdParty(e,t){const i=[];e.baidu&&window._hmt&&i.push(this.reportToBaidu(e.baidu,t)),e.umeng&&window._um&&i.push(this.reportToUmeng(e.umeng,t)),e.sensors&&window.sensors&&i.push(this.reportToSensors(e.sensors,t)),e.tencent&&window.MTA&&i.push(this.reportToTencent(e.tencent,t)),e.custom&&i.push(this.reportToCustom(e.custom,t));try{await Promise.allSettled(i)}catch(e){console.error("第三方上报失败:",e)}}async reportToBaidu(e,t){window._hmt&&window._hmt.push(["_trackEvent",t.type,JSON.stringify(t.data)])}async reportToUmeng(e,t){window._um&&window._um.push(["track",t.type,t.data])}async reportToSensors(e,t){window.sensors&&window.sensors.track(t.type,t.data[0]||{})}async reportToTencent(e,t){window.MTA&&window.MTA.Event.stat(t.type,t.data[0]||{})}async reportToCustom(e,t){"function"==typeof e.report&&await e.report(t)}}class t{constructor(t){this.config=t,this.reporter=new e(t),this.errorQueue=[],this.isInitialized=!1}init(){if(this.isInitialized)return;const e=this.config.getConfig();e.enableErrorTracking&&this.setupErrorListener(),e.enableUnhandledRejection&&this.setupUnhandledRejectionListener(),e.enableResourceError&&this.setupResourceErrorListener(),this.isInitialized=!0}setupErrorListener(){window.addEventListener("error",e=>{this.handleError(e.error||e.message,{type:"javascript",filename:e.filename,lineno:e.lineno,colno:e.colno,stack:e.error?.stack})},!0)}setupUnhandledRejectionListener(){window.addEventListener("unhandledrejection",e=>{this.handleError(e.reason,{type:"unhandledrejection",stack:e.reason?.stack})})}setupResourceErrorListener(){window.addEventListener("error",e=>{e.target&&e.target!==window&&this.handleError(`Resource load failed: ${e.target.src||e.target.href}`,{type:"resource",tagName:e.target.tagName,src:e.target.src,href:e.target.href})},!0)}handleError(e,t={}){const i={message:e?.message||e?.toString()||e,stack:e?.stack||t.stack,type:t.type||"unknown",timestamp:Date.now(),url:window.location.href,userAgent:navigator.userAgent,...t};this.errorQueue.push(i),this.errorQueue.length>=this.config.getConfig().maxQueueSize&&this.flushErrorQueue(),0===this.config.getConfig().reportInterval&&this.reporter.report("error",[i])}reportError(e,t={}){this.handleError(e,t)}flushErrorQueue(){this.errorQueue.length>0&&(this.reporter.report("error",[...this.errorQueue]),this.errorQueue=[])}destroy(){this.flushErrorQueue(),this.isInitialized=!1}}class i{constructor(t){this.config=t,this.reporter=new e(t),this.eventQueue=[],this.isInitialized=!1,this.clickListener=null,this.pageViewListener=null}init(){if(this.isInitialized)return;const e=this.config.getConfig();e.enableClickTracking&&this.setupClickTracking(),e.enablePageViewTracking&&this.setupPageViewTracking(),this.setupPeriodicReport(),this.isInitialized=!0}setupClickTracking(){this.clickListener=e=>{const t=e.target,i={type:"click",timestamp:Date.now(),url:window.location.href,element:{tagName:t.tagName,className:t.className,id:t.id,text:t.textContent?.substring(0,50)},position:{x:e.clientX,y:e.clientY}};this.handleEvent("click",i)},document.addEventListener("click",this.clickListener,!0)}setupPageViewTracking(){this.handleEvent("pageview",{type:"pageview",timestamp:Date.now(),url:window.location.href,title:document.title,referrer:document.referrer}),this.pageViewListener=()=>{this.handleEvent("pageview",{type:"pageview",timestamp:Date.now(),url:window.location.href,title:document.title,referrer:document.referrer})},window.addEventListener("popstate",this.pageViewListener);const e=history.pushState,t=history.replaceState;history.pushState=function(...t){e.apply(history,t),setTimeout(()=>{this.pageViewListener()},0)}.bind(this),history.replaceState=function(...e){t.apply(history,e),setTimeout(()=>{this.pageViewListener()},0)}.bind(this)}setupPeriodicReport(){const e=this.config.getConfig().reportInterval;e>0&&setInterval(()=>{this.flushEventQueue()},e)}handleEvent(e,t){const i={eventName:e,...t,user:this.config.getUser(),config:{appId:this.config.getConfig().appId,appVersion:this.config.getConfig().appVersion,environment:this.config.getConfig().environment}};this.eventQueue.push(i),this.eventQueue.length>=this.config.getConfig().maxQueueSize&&this.flushEventQueue(),0===this.config.getConfig().reportInterval&&this.reporter.report("event",[i])}reportEvent(e,t={}){this.handleEvent(e,{type:"custom",timestamp:Date.now(),url:window.location.href,...t})}flushEventQueue(){this.eventQueue.length>0&&(this.reporter.report("event",[...this.eventQueue]),this.eventQueue=[])}destroy(){this.flushEventQueue(),this.clickListener&&document.removeEventListener("click",this.clickListener,!0),this.pageViewListener&&window.removeEventListener("popstate",this.pageViewListener),this.isInitialized=!1}}class r{constructor(t){this.config=t,this.reporter=new e(t),this.isInitialized=!1,this.pageStartTime=Date.now(),this.performanceQueue=[],this.thirdPartySDKs={},this.metrics={fcp:0,lcp:0,fid:0,cls:0,ttfb:0,domLoad:0,windowLoad:0,resourceLoad:[],apiRequests:[]}}init(){if(this.isInitialized)return;const e=this.config.getConfig();e.enablePerformanceTracking&&this.setupPerformanceMonitoring(),e.enableResourceTracking&&this.setupResourceMonitoring(),e.enableApiTracking&&this.setupApiMonitoring(),e.enableInteractionTracking&&this.setupInteractionMonitoring(),this.initThirdPartySDKs(),this.isInitialized=!0}setupPerformanceMonitoring(){"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{this.captureDOMLoadTime()}):this.captureDOMLoadTime(),window.addEventListener("load",()=>{this.captureWindowLoadTime(),this.captureWebVitals(),this.reportPerformanceMetrics()}),document.addEventListener("visibilitychange",()=>{document.hidden?this.handlePageHidden():this.handlePageVisible()})}setupResourceMonitoring(){const e=new PerformanceObserver(e=>{for(const t of e.getEntries())"resource"===t.entryType&&this.handleResourceLoad(t)});try{e.observe({entryTypes:["resource"]})}catch(e){this.setupResourceFallback()}}setupApiMonitoring(){const e=window.fetch;window.fetch=async(...t)=>{const i=performance.now();try{const r=await e(...t),n=performance.now();return this.handleApiRequest(t[0],n-i,r.status),r}catch(e){const r=performance.now();throw this.handleApiRequest(t[0],r-i,"error"),e}};const t=XMLHttpRequest.prototype.open,i=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(e,i,...r){return this._startTime=performance.now(),this._url=i,this._method=e,t.apply(this,[e,i,...r])},XMLHttpRequest.prototype.send=function(...e){const t=this,r=t.onreadystatechange;return t.onreadystatechange=function(){if(4===t.readyState){const e=performance.now()-t._startTime;this.handleApiRequest(t._url,e,t.status)}r&&r.apply(t,arguments)}.bind(this),i.apply(t,e)}.bind(this)}setupInteractionMonitoring(){let e=0,t=0;const i=r=>{0===e&&(e=performance.now(),t=e-this.metrics.fcp,this.metrics.fid=t,document.removeEventListener("click",i,!0),document.removeEventListener("keydown",i,!0),document.removeEventListener("touchstart",i,!0))};document.addEventListener("click",i,!0),document.addEventListener("keydown",i,!0),document.addEventListener("touchstart",i,!0)}captureDOMLoadTime(){this.metrics.domLoad=performance.now()}captureWindowLoadTime(){this.metrics.windowLoad=performance.now()}captureWebVitals(){if("PerformanceObserver"in window)try{new PerformanceObserver(e=>{for(const t of e.getEntries())"first-contentful-paint"===t.name&&(this.metrics.fcp=t.startTime)}).observe({entryTypes:["paint"]})}catch(e){console.warn("FCP监控失败:",e)}if("PerformanceObserver"in window)try{new PerformanceObserver(e=>{for(const t of e.getEntries())this.metrics.lcp=t.startTime}).observe({entryTypes:["largest-contentful-paint"]})}catch(e){console.warn("LCP监控失败:",e)}if("PerformanceObserver"in window)try{let e=0;new PerformanceObserver(t=>{for(const i of t.getEntries())i.hadRecentInput||(e+=i.value);this.metrics.cls=e}).observe({entryTypes:["layout-shift"]})}catch(e){console.warn("CLS监控失败:",e)}}handleResourceLoad(e){const t={name:e.name,type:e.initiatorType,duration:e.duration,size:e.transferSize,timestamp:Date.now()};this.metrics.resourceLoad.push(t),e.duration>3e3&&this.reportSlowResource(t)}handleApiRequest(e,t,i){const r={url:"string"==typeof e?e:e.toString(),duration:t,status:i,timestamp:Date.now()};this.metrics.apiRequests.push(r),t>5e3&&this.reportSlowApi(r)}handlePageHidden(){this.calculatePageStayTime()}handlePageVisible(){this.pageStartTime=Date.now()}calculatePageStayTime(){const e=Date.now()-this.pageStartTime;this.reportPageStayTime(e)}reportPerformanceMetrics(){const e={type:"performance",timestamp:Date.now(),url:window.location.href,userAgent:navigator.userAgent,metrics:this.metrics,user:this.config.getUser(),device:this.getDeviceInfo()};this.performanceQueue.push(e),this.performanceQueue.length>=this.config.getConfig().maxQueueSize&&this.flushPerformanceQueue(),0===this.config.getConfig().reportInterval&&this.reporter.report("performance",[e])}reportSlowResource(e){this.reporter.report("slow_resource",[e])}reportSlowApi(e){this.reporter.report("slow_api",[e])}reportPageStayTime(e){const t={type:"page_stay",url:window.location.href,stayTime:e,timestamp:Date.now()};this.reporter.report("page_stay",[t])}getDeviceInfo(){return{screen:{width:screen.width,height:screen.height,availWidth:screen.availWidth,availHeight:screen.availHeight,colorDepth:screen.colorDepth,pixelDepth:screen.pixelDepth},viewport:{width:window.innerWidth,height:window.innerHeight},connection:navigator.connection?{effectiveType:navigator.connection.effectiveType,downlink:navigator.connection.downlink,rtt:navigator.connection.rtt}:null,memory:navigator.memory?{usedJSHeapSize:navigator.memory.usedJSHeapSize,totalJSHeapSize:navigator.memory.totalJSHeapSize,jsHeapSizeLimit:navigator.memory.jsHeapSizeLimit}:null}}initThirdPartySDKs(){const e=this.config.getThirdPartyConfig();e.baidu&&window._hmt&&(this.thirdPartySDKs.baidu=window._hmt),e.umeng&&window._um&&(this.thirdPartySDKs.umeng=window._um),e.sensors&&window.sensors&&(this.thirdPartySDKs.sensors=window.sensors),e.tencent&&window.MTA&&(this.thirdPartySDKs.tencent=window.MTA)}flushPerformanceQueue(){this.performanceQueue.length>0&&(this.reporter.report("performance",[...this.performanceQueue]),this.performanceQueue=[])}reportPerformance(e={}){const t={type:"custom_performance",timestamp:Date.now(),url:window.location.href,metrics:e,user:this.config.getUser()};this.reporter.report("performance",[t])}getCurrentMetrics(){return{...this.metrics}}destroy(){this.flushPerformanceQueue(),this.isInitialized=!1}}class n{constructor(t){this.config=t,this.reporter=new e(t),this.isInitialized=!1,this.behaviorQueue=[],this.sessionId=this.generateSessionId(),this.pageStartTime=Date.now(),this.scrollDepth=0,this.mouseMovements=[],this.keyStrokes=[],this.formInteractions=[],this.behaviors={pageViews:[],clicks:[],scrolls:[],formSubmissions:[],navigation:[],timeOnPage:0}}init(){if(this.isInitialized)return;const e=this.config.getConfig();e.enablePageViewTracking&&this.setupPageViewTracking(),e.enableUserInteractionTracking&&this.setupUserInteractionTracking(),e.enableFormTracking&&this.setupFormTracking(),e.enableScrollTracking&&this.setupScrollTracking(),e.enableMouseTracking&&this.setupMouseTracking(),e.enableKeyboardTracking&&this.setupKeyboardTracking(),this.setupTimeTracking(),this.trackReferrer(),this.isInitialized=!0}setupPageViewTracking(){this.trackPageView(),this.setupRouteChangeTracking(),document.addEventListener("visibilitychange",()=>{document.hidden?this.handlePageHidden():this.handlePageVisible()})}setupRouteChangeTracking(){window.addEventListener("popstate",()=>{this.trackPageView()});const e=history.pushState,t=history.replaceState;history.pushState=function(...t){e.apply(history,t),setTimeout(()=>{this.trackPageView()},0)}.bind(this),history.replaceState=function(...e){t.apply(history,e),setTimeout(()=>{this.trackPageView()},0)}.bind(this)}setupUserInteractionTracking(){document.addEventListener("click",e=>{this.trackClick(e)},!0),document.addEventListener("dblclick",e=>{this.trackDoubleClick(e)},!0),document.addEventListener("contextmenu",e=>{this.trackRightClick(e)},!0),"ontouchstart"in window&&document.addEventListener("touchstart",e=>{this.trackTouch(e)},!0)}setupFormTracking(){document.addEventListener("submit",e=>{this.trackFormSubmission(e)},!0),document.addEventListener("change",e=>{"INPUT"!==e.target.tagName&&"SELECT"!==e.target.tagName&&"TEXTAREA"!==e.target.tagName||this.trackFormFieldChange(e)},!0),document.addEventListener("focus",e=>{"INPUT"!==e.target.tagName&&"SELECT"!==e.target.tagName&&"TEXTAREA"!==e.target.tagName||this.trackFormFieldFocus(e)},!0),document.addEventListener("blur",e=>{"INPUT"!==e.target.tagName&&"SELECT"!==e.target.tagName&&"TEXTAREA"!==e.target.tagName||this.trackFormFieldBlur(e)},!0)}setupScrollTracking(){let e;document.addEventListener("scroll",()=>{clearTimeout(e),e=setTimeout(()=>{const e=window.pageYOffset||document.documentElement.scrollTop,t=document.documentElement.scrollHeight,i=document.documentElement.clientHeight,r=Math.round(e/(t-i)*100);r>this.scrollDepth&&(this.scrollDepth=r,this.trackScroll(r,e))},100)},{passive:!0})}setupMouseTracking(){let e,t=[];document.addEventListener("mousemove",i=>{clearTimeout(e),t.push({x:i.clientX,y:i.clientY,timestamp:Date.now()}),t.length>100&&t.shift(),e=setTimeout(()=>{t.length>10&&(this.trackMouseMovement(t),t=[])},1e3)},{passive:!0})}setupKeyboardTracking(){document.addEventListener("keydown",e=>{"password"!==e.target.type&&this.trackKeyStroke(e)},!0)}setupTimeTracking(){setInterval(()=>{this.behaviors.timeOnPage+=1},1e3),window.addEventListener("beforeunload",()=>{this.reportTimeOnPage()})}trackReferrer(){const e=document.referrer;if(e){const t={type:"referrer",url:e,domain:this.extractDomain(e),timestamp:Date.now()};this.behaviors.navigation.push(t),this.reportBehavior("referrer",t)}}trackPageView(){const e={type:"pageview",url:window.location.href,title:document.title,timestamp:Date.now(),sessionId:this.sessionId,referrer:document.referrer};this.behaviors.pageViews.push(e),this.reportBehavior("pageview",e),this.pageStartTime=Date.now(),this.scrollDepth=0}trackClick(e){const t={type:"click",element:{tagName:e.target.tagName,className:e.target.className,id:e.target.id,text:e.target.textContent?.substring(0,50),href:e.target.href},position:{x:e.clientX,y:e.clientY,pageX:e.pageX,pageY:e.pageY},timestamp:Date.now(),sessionId:this.sessionId};this.behaviors.clicks.push(t),this.reportBehavior("click",t)}trackDoubleClick(e){const t={type:"doubleclick",element:{tagName:e.target.tagName,className:e.target.className,id:e.target.id},position:{x:e.clientX,y:e.clientY},timestamp:Date.now(),sessionId:this.sessionId};this.reportBehavior("doubleclick",t)}trackRightClick(e){const t={type:"rightclick",element:{tagName:e.target.tagName,className:e.target.className,id:e.target.id},position:{x:e.clientX,y:e.clientY},timestamp:Date.now(),sessionId:this.sessionId};this.reportBehavior("rightclick",t)}trackTouch(e){const t={type:"touch",touches:Array.from(e.touches).map(e=>({x:e.clientX,y:e.clientY,identifier:e.identifier})),timestamp:Date.now(),sessionId:this.sessionId};this.reportBehavior("touch",t)}trackFormSubmission(e){const t={type:"form_submission",form:{action:e.target.action,method:e.target.method,id:e.target.id,className:e.target.className},fields:this.getFormFields(e.target),timestamp:Date.now(),sessionId:this.sessionId};this.behaviors.formSubmissions.push(t),this.reportBehavior("form_submission",t)}trackFormFieldChange(e){const t={type:"form_field_change",field:{name:e.target.name,type:e.target.type,value:"password"===e.target.type?"***":e.target.value,id:e.target.id},timestamp:Date.now(),sessionId:this.sessionId};this.reportBehavior("form_field_change",t)}trackFormFieldFocus(e){const t={type:"form_field_focus",field:{name:e.target.name,type:e.target.type,id:e.target.id},timestamp:Date.now(),sessionId:this.sessionId};this.reportBehavior("form_field_focus",t)}trackFormFieldBlur(e){const t={type:"form_field_blur",field:{name:e.target.name,type:e.target.type,id:e.target.id},timestamp:Date.now(),sessionId:this.sessionId};this.reportBehavior("form_field_blur",t)}trackScroll(e,t){const i={type:"scroll",depth:e,scrollTop:t,timestamp:Date.now(),sessionId:this.sessionId};this.reportBehavior("scroll",i)}trackMouseMovement(e){const t={type:"mouse_movement",movements:e,timestamp:Date.now(),sessionId:this.sessionId};this.reportBehavior("mouse_movement",t)}trackKeyStroke(e){const t={type:"keystroke",key:e.key,code:e.code,ctrlKey:e.ctrlKey,shiftKey:e.shiftKey,altKey:e.altKey,metaKey:e.metaKey,timestamp:Date.now(),sessionId:this.sessionId};this.reportBehavior("keystroke",t)}handlePageHidden(){this.reportTimeOnPage()}handlePageVisible(){this.pageStartTime=Date.now()}reportTimeOnPage(){const e={type:"time_on_page",time:this.behaviors.timeOnPage,url:window.location.href,timestamp:Date.now(),sessionId:this.sessionId};this.reportBehavior("time_on_page",e)}reportBehavior(e,t){const i={type:e,data:t,user:this.config.getUser(),config:{appId:this.config.getConfig().appId,appVersion:this.config.getConfig().appVersion,environment:this.config.getConfig().environment}};this.behaviorQueue.push(i),this.behaviorQueue.length>=this.config.getConfig().maxQueueSize&&this.flushBehaviorQueue(),0===this.config.getConfig().reportInterval&&this.reporter.report("behavior",[i])}reportCustomBehavior(e,t={}){const i={type:"custom_behavior",eventName:e,...t,timestamp:Date.now(),sessionId:this.sessionId};this.reportBehavior("custom_behavior",i)}flushBehaviorQueue(){this.behaviorQueue.length>0&&(this.reporter.report("behavior",[...this.behaviorQueue]),this.behaviorQueue=[])}getFormFields(e){const t=[],i=e.elements;for(let e=0;e<i.length;e++){const r=i[e];r.name&&t.push({name:r.name,type:r.type,value:"password"===r.type?"***":r.value})}return t}extractDomain(e){try{return new URL(e).hostname}catch(t){return e}}generateSessionId(){return"session_"+Date.now()+"_"+Math.random().toString(36).substr(2,9)}getCurrentBehaviors(){return{...this.behaviors}}getSessionId(){return this.sessionId}destroy(){this.flushBehaviorQueue(),this.reportTimeOnPage(),this.isInitialized=!1}}class s{constructor(e){this.config=e,this.integratedSDKs={},this.isInitialized=!1}init(){if(this.isInitialized)return;const e=this.config.getThirdPartyConfig();e.baidu&&e.baidu.enabled&&this.initBaiduAnalytics(e.baidu),e.umeng&&e.umeng.enabled&&this.initUmengAnalytics(e.umeng),e.sensors&&e.sensors.enabled&&this.initSensorsAnalytics(e.sensors),e.tencent&&e.tencent.enabled&&this.initTencentAnalytics(e.tencent),e.google&&e.google.enabled&&this.initGoogleAnalytics(e.google),e.custom&&e.custom.enabled&&this.initCustomAnalytics(e.custom),this.isInitialized=!0}initBaiduAnalytics(e){try{window._hmt?(this.integratedSDKs.baidu={name:"baidu",instance:window._hmt,config:e},e.siteId&&window._hmt.push(["_setAccount",e.siteId]),!1!==e.autoPageview&&window._hmt.push(["_trackPageview"]),console.log("百度统计集成成功")):console.warn("百度统计未加载,请检查脚本是否正确引入")}catch(e){console.error("百度统计集成失败:",e)}}initUmengAnalytics(e){try{window._um?(this.integratedSDKs.umeng={name:"umeng",instance:window._um,config:e},e.siteId&&window._um.push(["setAccount",e.siteId]),!1!==e.autoPageview&&window._um.push(["trackPageview"]),console.log("友盟统计集成成功")):console.warn("友盟统计未加载,请检查脚本是否正确引入")}catch(e){console.error("友盟统计集成失败:",e)}}initSensorsAnalytics(e){try{window.sensors?(this.integratedSDKs.sensors={name:"sensors",instance:window.sensors,config:e},e.serverUrl&&window.sensors.setServerUrl(e.serverUrl),e.siteId&&window.sensors.setSiteId(e.siteId),!1!==e.autoPageview&&window.sensors.trackPageview(),console.log("神策数据集成成功")):console.warn("神策数据未加载,请检查脚本是否正确引入")}catch(e){console.error("神策数据集成失败:",e)}}initTencentAnalytics(e){try{window.MTA?(this.integratedSDKs.tencent={name:"tencent",instance:window.MTA,config:e},e.appId&&window.MTA.setAppId(e.appId),!1!==e.autoPageview&&window.MTA.trackPageview(),console.log("腾讯云分析集成成功")):console.warn("腾讯云分析未加载,请检查脚本是否正确引入")}catch(e){console.error("腾讯云分析集成失败:",e)}}initGoogleAnalytics(e){try{window.gtag?(this.integratedSDKs.google={name:"google",instance:window.gtag,config:e},e.measurementId&&window.gtag("config",e.measurementId,{page_title:document.title,page_location:window.location.href}),console.log("Google Analytics集成成功")):console.warn("Google Analytics未加载,请检查脚本是否正确引入")}catch(e){console.error("Google Analytics集成失败:",e)}}initCustomAnalytics(e){try{if("function"==typeof e.init){const t=e.init(e);this.integratedSDKs.custom={name:"custom",instance:t,config:e},console.log("自定义第三方集成成功")}else console.warn("自定义第三方配置缺少init函数")}catch(e){console.error("自定义第三方集成失败:",e)}}reportEvent(e,t={}){Object.values(this.integratedSDKs).forEach(i=>{try{this.reportToSDK(i,e,t)}catch(e){console.error(`上报事件到${i.name}失败:`,e)}})}reportPageView(e={}){Object.values(this.integratedSDKs).forEach(t=>{try{this.reportPageViewToSDK(t,e)}catch(e){console.error(`上报页面浏览到${t.name}失败:`,e)}})}reportUser(e={}){Object.values(this.integratedSDKs).forEach(t=>{try{this.reportUserToSDK(t,e)}catch(e){console.error(`上报用户信息到${t.name}失败:`,e)}})}reportPerformance(e={}){Object.values(this.integratedSDKs).forEach(t=>{try{this.reportPerformanceToSDK(t,e)}catch(e){console.error(`上报性能指标到${t.name}失败:`,e)}})}reportToSDK(e,t,i){switch(e.name){case"baidu":e.instance&&e.instance.push&&e.instance.push(["_trackEvent",t,JSON.stringify(i)]);break;case"umeng":e.instance&&e.instance.push&&e.instance.push(["track",t,i]);break;case"sensors":e.instance&&e.instance.track&&e.instance.track(t,i);break;case"tencent":e.instance&&e.instance.Event&&e.instance.Event.stat&&e.instance.Event.stat(t,i);break;case"google":e.instance&&"function"==typeof e.instance&&e.instance("event",t,i);break;case"custom":e.instance&&"function"==typeof e.instance.track&&e.instance.track(t,i);break;default:console.warn(`未知的SDK类型: ${e.name}`)}}reportPageViewToSDK(e,t){switch(e.name){case"baidu":e.instance&&e.instance.push&&e.instance.push(["_trackPageview",t.url||window.location.href]);break;case"umeng":e.instance&&e.instance.push&&e.instance.push(["trackPageview",t.url||window.location.href]);break;case"sensors":e.instance&&e.instance.trackPageview&&e.instance.trackPageview(t);break;case"tencent":e.instance&&e.instance.trackPageview&&e.instance.trackPageview(t.url||window.location.href);break;case"google":e.instance&&"function"==typeof e.instance&&e.instance("config",e.config.measurementId,{page_title:t.title||document.title,page_location:t.url||window.location.href});break;case"custom":e.instance&&"function"==typeof e.instance.trackPageview&&e.instance.trackPageview(t);break;default:console.warn(`未知的SDK类型: ${e.name}`)}}reportUserToSDK(e,t){switch(e.name){case"baidu":e.instance&&e.instance.push&&(e.instance.push(["_setUserTag","userId",t.userId]),e.instance.push(["_setUserTag","userType",t.userType]));break;case"umeng":e.instance&&e.instance.push&&(e.instance.push(["setUserTag","userId",t.userId]),e.instance.push(["setUserTag","userType",t.userType]));break;case"sensors":e.instance&&e.instance.setProfile&&e.instance.setProfile(t);break;case"tencent":e.instance&&e.instance.setUserInfo&&e.instance.setUserInfo(t);break;case"google":e.instance&&"function"==typeof e.instance&&e.instance("set","user_id",t.userId);break;case"custom":e.instance&&"function"==typeof e.instance.setUser&&e.instance.setUser(t);break;default:console.warn(`未知的SDK类型: ${e.name}`)}}reportPerformanceToSDK(e,t){switch(e.name){case"baidu":e.instance&&e.instance.push&&e.instance.push(["_trackEvent","performance",JSON.stringify(t)]);break;case"umeng":e.instance&&e.instance.push&&e.instance.push(["track","performance",t]);break;case"sensors":e.instance&&e.instance.track&&e.instance.track("performance",t);break;case"tencent":e.instance&&e.instance.Event&&e.instance.Event.stat&&e.instance.Event.stat("performance",t);break;case"google":e.instance&&"function"==typeof e.instance&&e.instance("event","performance",t);break;case"custom":e.instance&&"function"==typeof e.instance.trackPerformance&&e.instance.trackPerformance(t);break;default:console.warn(`未知的SDK类型: ${e.name}`)}}isSDKIntegrated(e){return!!this.integratedSDKs[e]}getIntegratedSDKs(){return Object.keys(this.integratedSDKs)}getSDKInstance(e){return this.integratedSDKs[e]?.instance||null}destroy(){Object.values(this.integratedSDKs).forEach(e=>{try{e.instance&&"function"==typeof e.instance.destroy&&e.instance.destroy()}catch(t){console.error(`销毁${e.name}失败:`,t)}}),this.integratedSDKs={},this.isInitialized=!1}}class o{constructor(e={}){this.config={appId:e.appId||"",appVersion:e.appVersion||"1.0.0",environment:e.environment||"production",reportUrl:e.reportUrl||"",reportInterval:e.reportInterval||5e3,maxQueueSize:e.maxQueueSize||100,enableErrorTracking:!1!==e.enableErrorTracking,enableUnhandledRejection:!1!==e.enableUnhandledRejection,enableResourceError:!1!==e.enableResourceError,enableEventTracking:!1!==e.enableEventTracking,enableClickTracking:!1!==e.enableClickTracking,enablePageViewTracking:!1!==e.enablePageViewTracking,enablePerformanceTracking:!1!==e.enablePerformanceTracking,enableResourceTracking:!1!==e.enableResourceTracking,enableApiTracking:!1!==e.enableApiTracking,enableInteractionTracking:!1!==e.enableInteractionTracking,enableUserInteractionTracking:!1!==e.enableUserInteractionTracking,enableFormTracking:!1!==e.enableFormTracking,enableScrollTracking:!1!==e.enableScrollTracking,enableMouseTracking:!1!==e.enableMouseTracking,enableKeyboardTracking:!1!==e.enableKeyboardTracking,thirdPartyConfig:e.thirdPartyConfig||{},user:e.user||null,customReport:e.customReport||null},this.user=null}updateConfig(e){this.config={...this.config,...e}}setUser(e){this.user=e}getConfig(){return this.config}getUser(){return this.user}getReportUrl(){return this.config.reportUrl}getThirdPartyConfig(){return this.config.thirdPartyConfig}isErrorTrackingEnabled(){return this.config.enableErrorTracking}isEventTrackingEnabled(){return this.config.enableEventTracking}}class a{constructor(e={}){this.config=new o(e),this.errorTracker=new t(this.config),this.eventTracker=new i(this.config),this.performanceTracker=new r(this.config),this.userBehaviorTracker=new n(this.config),this.thirdPartyIntegrator=new s(this.config),this.init()}init(){this.errorTracker.init(),this.eventTracker.init(),this.performanceTracker.init(),this.userBehaviorTracker.init(),this.thirdPartyIntegrator.init(),console.log("Frontend SDK 初始化完成")}reportError(e,t={}){this.errorTracker.reportError(e,t)}reportEvent(e,t={}){this.eventTracker.reportEvent(e,t)}reportPerformance(e={}){this.performanceTracker.reportPerformance(e)}reportBehavior(e,t={}){this.userBehaviorTracker.reportCustomBehavior(e,t)}setUser(e){this.config.setUser(e),this.thirdPartyIntegrator.reportUser(e)}setConfig(e){this.config.updateConfig(e)}getPerformanceMetrics(){return this.performanceTracker.getCurrentMetrics()}getBehaviorData(){return this.userBehaviorTracker.getCurrentBehaviors()}getSessionId(){return this.userBehaviorTracker.getSessionId()}isThirdPartySDKIntegrated(e){return this.thirdPartyIntegrator.isSDKIntegrated(e)}getIntegratedThirdPartySDKs(){return this.thirdPartyIntegrator.getIntegratedSDKs()}destroy(){this.errorTracker.destroy(),this.eventTracker.destroy(),this.performanceTracker.destroy(),this.userBehaviorTracker.destroy(),this.thirdPartyIntegrator.destroy(),console.log("Frontend SDK 已销毁")}}export{a as default};
2
+ //# sourceMappingURL=index.esm.js.map