npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@wfynbzlx666/sdk-telemetry

v0.0.1

Published

BMT 平台 SDK 遥测上报 - 事件缓冲、批量上报、跨标签页去重

Readme

@wfynbzlx666/sdk-telemetry

BMT 平台 SDK 遥测数据收集模块,提供统一的事件模型、批量缓冲上报、跨标签页去重和 Beacon 兜底等完整的遥测数据收集解决方案。

🚀 特性

  • 统一事件模型:标准化的事件类型和数据结构
  • 批量缓冲上报:智能批量处理,减少网络请求
  • 跨标签页去重:避免多标签页重复上报数据
  • Beacon 兜底:页面卸载时使用 sendBeacon 确保数据上报
  • 本地存储:离线时数据本地缓存,网络恢复后自动上报
  • 采样控制:灵活的采样率配置,控制数据上报量
  • 错误处理:完善的错误处理和重试机制
  • TypeScript 支持:完整的类型定义和 IntelliSense 支持

📦 安装

npm install @wfynbzlx666/sdk-telemetry

🎯 核心模块

Telemetry 主类

遥测系统的主入口,提供完整的事件跟踪和数据上报能力。

🚀 快速开始

import { Telemetry } from '@wfynbzlx666/sdk-telemetry'

// 初始化遥测
Telemetry.init({
  app: 'my-app',
  release: '1.0.0',
  endpoint: 'https://api.example.com/telemetry',
  debug: true
})

// 设置用户信息
Telemetry.setUser({
  id: 'user_123',
  email: '[email protected]',
  name: 'John Doe',
  role: 'user'
})

// 跟踪页面浏览
Telemetry.trackPageView('/dashboard', {
  title: 'Dashboard',
  loadTime: 1200,
  referrer: document.referrer
})

// 跟踪自定义事件
Telemetry.trackEvent('button_click', {
  buttonId: 'save-btn',
  section: 'settings',
  timestamp: Date.now()
})

// 跟踪错误
Telemetry.trackError('javascript_error', 'TypeError: Cannot read property...', {
  file: 'app.js',
  line: 42,
  column: 15
})

🔧 高级配置

import { Telemetry } from '@wfynbzlx666/sdk-telemetry'

// 完整配置示例
Telemetry.init({
  // 基础信息
  app: 'my-app',
  release: '1.0.0',
  environment: 'production',
  
  // 上报配置
  endpoint: 'https://api.example.com/v1/telemetry/ingest',
  batchSize: 50,              // 批次大小
  flushInterval: 5000,        // 刷新间隔 5 秒
  maxBatchEvents: 200,        // 最大批次事件数
  maxEventSize: 10240,        // 单个事件最大大小 10KB
  
  // 采样配置
  sampleRate: 0.1,            // 采样率 10%
  errorSampleRate: 1.0,       // 错误事件采样率 100%
  performanceSampleRate: 0.05, // 性能事件采样率 5%
  
  // 存储配置
  enableLocalStorage: true,   // 启用本地存储
  maxStorageSize: 5242880,    // 最大存储大小 5MB
  storageCleanupInterval: 3600000, // 存储清理间隔 1 小时
  
  // 功能开关
  enableBeacon: true,         // 启用 Beacon 兜底
  enableCrossTabDedup: true,  // 启用跨标签页去重
  enableAutoPageTracking: true, // 启用自动页面跟踪
  enableAutoErrorTracking: true, // 启用自动错误跟踪
  
  // 过滤器
  beforeSend: (event) => {
    // 事件发送前的过滤和处理
    if (event.type === 'error' && event.data.message?.includes('Script error')) {
      return null // 过滤脚本错误
    }
    return event
  },
  
  // 回调函数
  onSuccess: (batch) => {
    console.log('遥测数据上报成功:', batch.length)
  },
  
  onError: (error, batch) => {
    console.error('遥测数据上报失败:', error)
  },
  
  onStorageWarning: (usage, limit) => {
    console.warn(`存储使用量警告: ${usage}/${limit}`)
  },
  
  // 调试配置
  debug: process.env.NODE_ENV === 'development'
})

事件跟踪

提供多种类型的事件跟踪方法。

📄 页面跟踪

// 基础页面跟踪
Telemetry.trackPageView('/home')

// 详细页面跟踪
Telemetry.trackPageView('/products/123', {
  title: 'Product Details - iPhone 13',
  category: 'products',
  loadTime: 800,
  referrer: '/search?q=iphone',
  searchQuery: 'iphone',
  userId: 'user_123'
})

// 单页应用路由变化跟踪
function trackRouteChange(to: string, from: string) {
  Telemetry.trackPageView(to, {
    from,
    title: document.title,
    loadTime: performance.now(),
    navigationMode: 'spa'
  })
}

// 自动页面跟踪(已启用的情况下)
// 会自动监听 popstate 和 pushstate 事件

🎯 自定义事件跟踪

// 用户交互事件
Telemetry.trackEvent('button_click', {
  buttonId: 'download-btn',
  buttonText: 'Download App',
  section: 'hero',
  position: { x: 100, y: 200 }
})

// 业务事件
Telemetry.trackEvent('purchase_completed', {
  orderId: 'order_123',
  amount: 99.99,
  currency: 'USD',
  items: [
    { id: 'item_1', name: 'iPhone Case', price: 29.99 },
    { id: 'item_2', name: 'Screen Protector', price: 19.99 }
  ],
  paymentMethod: 'credit_card'
})

// 表单事件
Telemetry.trackEvent('form_submitted', {
  formId: 'contact-form',
  formType: 'contact',
  fields: ['name', 'email', 'message'],
  validationErrors: [],
  timeFilled: 45000 // 填写耗时 45 秒
})

// 搜索事件
Telemetry.trackEvent('search_performed', {
  query: 'wireless headphones',
  resultsCount: 24,
  filters: { brand: 'Apple', priceRange: '100-200' },
  searchDuration: 1200
})

❌ 错误跟踪

// JavaScript 错误跟踪
try {
  someRiskyOperation()
} catch (error) {
  Telemetry.trackError('operation_failed', error.message, {
    operation: 'someRiskyOperation',
    stack: error.stack,
    timestamp: Date.now(),
    userId: getCurrentUserId(),
    additionalContext: { /* 额外上下文 */ }
  })
}

// API 错误跟踪
fetch('/api/users')
  .then(response => {
    if (!response.ok) {
      Telemetry.trackError('api_error', `HTTP ${response.status}`, {
        url: '/api/users',
        method: 'GET',
        status: response.status,
        statusText: response.statusText,
        headers: Object.fromEntries(response.headers.entries())
      })
    }
    return response.json()
  })
  .catch(error => {
    Telemetry.trackError('network_error', error.message, {
      url: '/api/users',
      method: 'GET',
      errorType: 'NetworkError'
    })
  })

// 自动错误跟踪(已启用的情况下)
// 会自动监听 window.onerror 和 window.onunhandledrejection
window.addEventListener('error', (event) => {
  // 自动跟踪未捕获的 JavaScript 错误
})

window.addEventListener('unhandledrejection', (event) => {
  // 自动跟踪未处理的 Promise 拒绝
})

📊 性能跟踪

// API 性能跟踪
const startTime = performance.now()
const response = await fetch('/api/data')
const endTime = performance.now()

Telemetry.trackEvent('api_performance', {
  url: '/api/data',
  method: 'GET',
  duration: endTime - startTime,
  status: response.status,
  size: response.headers.get('content-length'),
  cacheStatus: response.headers.get('cache-control')
})

// 自定义性能指标
Telemetry.trackPerformance('custom_operation', {
  operation: 'data_processing',
  duration: 500,
  recordsProcessed: 1000,
  memoryUsage: performance.memory?.usedJSHeapSize
})

// 资源加载性能
const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    Telemetry.trackPerformance('resource_load', {
      name: entry.name,
      duration: entry.duration,
      size: entry.transferSize,
      type: entry.initiatorType
    })
  })
})
observer.observe({ entryTypes: ['resource'] })

事件构建器

提供便捷的事件构建函数。

🏗️ 预设事件构建器

import { 
  createPageEvent,
  createCustomEvent,
  createErrorEvent,
  createApiEvent,
  createPerfEvent 
} from '@wfynbzlx666/sdk-telemetry'

// 创建页面事件
const pageEvent = createPageEvent('/dashboard', {
  title: 'Dashboard',
  loadTime: 1200
})
Telemetry.track(pageEvent)

// 创建自定义事件
const customEvent = createCustomEvent('user_action', {
  action: 'download',
  resource: 'app'
})
Telemetry.track(customEvent)

// 创建错误事件
const errorEvent = createErrorEvent('validation_error', 'Email is required', {
  field: 'email',
  formId: 'signup-form'
})
Telemetry.track(errorEvent)

// 创建 API 事件
const apiEvent = createApiEvent('/api/users', 'GET', {
  duration: 300,
  status: 200,
  cached: false
})
Telemetry.track(apiEvent)

// 创建性能事件
const perfEvent = createPerfEvent('page_load', {
  duration: 2500,
  resources: 15,
  domElements: 400
})
Telemetry.track(perfEvent)

批量处理

智能的批量处理和上报机制。

📦 批量配置

import { TelemetryBatcher } from '@wfynbzlx666/sdk-telemetry'

// 创建自定义批处理器
const batcher = new TelemetryBatcher({
  maxBatchSize: 50,           // 最大批次大小
  flushInterval: 5000,        // 刷新间隔 5 秒
  maxWaitTime: 10000,         // 最大等待时间 10 秒
  
  // 自定义上报逻辑
  onFlush: async (events) => {
    console.log('上报事件批次:', events.length)
    
    try {
      const response = await fetch('/api/telemetry', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ events })
      })
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`)
      }
    } catch (error) {
      console.error('批次上报失败:', error)
      throw error
    }
  },
  
  // 批次过滤器
  beforeFlush: (events) => {
    // 过滤敏感数据
    return events.filter(event => !event.data?.sensitive)
  }
})

// 添加事件到批处理器
batcher.add({
  type: 'custom',
  timestamp: Date.now(),
  data: { action: 'user_login' }
})

// 手动刷新
await batcher.flush()

// 清理资源
batcher.destroy()

⚡ 实时上报

// 强制实时上报(跳过批处理)
Telemetry.trackEvent('critical_error', {
  error: 'Payment processing failed',
  orderId: 'order_123',
  amount: 99.99
}, {
  immediate: true // 立即上报,不等待批处理
})

// 高优先级事件
Telemetry.trackEvent('security_alert', {
  alertType: 'suspicious_login',
  userId: 'user_123',
  ip: '192.168.1.1'
}, {
  priority: 'high',
  immediate: true
})

存储管理

本地存储和离线支持。

💾 存储配置

import { TelemetryStorage } from '@wfynbzlx666/sdk-telemetry'

// 自定义存储配置
const storage = new TelemetryStorage({
  maxSize: 5242880,           // 最大存储 5MB
  cleanupInterval: 3600000,   // 清理间隔 1 小时
  retentionPeriod: 604800000, // 数据保留 7 天
  
  // 存储策略
  storageStrategy: 'lru',     // LRU 淘汰策略
  compressionEnabled: true,   // 启用压缩
  
  // 回调函数
  onStorageFull: (usage, limit) => {
    console.warn('存储空间已满:', usage, limit)
  },
  
  onCleanup: (removedCount, freedSpace) => {
    console.log('清理存储:', removedCount, freedSpace)
  }
})

// 手动存储操作
await storage.store('key', eventData)
const data = await storage.retrieve('key')
await storage.remove('key')
await storage.clear()

// 获取存储信息
const info = await storage.getStorageInfo()
console.log('存储信息:', {
  used: info.used,
  available: info.available,
  percentage: info.percentage
})

🔄 离线支持

// 离线检测和处理
Telemetry.init({
  // ... 其他配置
  
  // 离线处理
  onOffline: () => {
    console.log('网络离线,事件将缓存到本地')
  },
  
  onOnline: () => {
    console.log('网络恢复,开始上报缓存事件')
    // 自动上报缓存的事件
  },
  
  // 网络状态检测间隔
  networkCheckInterval: 30000 // 30 秒检测一次
})

// 手动处理离线缓存
if (!navigator.onLine) {
  // 离线状态,事件会自动缓存
  Telemetry.trackEvent('offline_action', { action: 'data_save' })
}

// 网络恢复时手动同步
window.addEventListener('online', () => {
  Telemetry.syncOfflineEvents()
})

📊 使用场景

1. Web 应用用户行为分析

import { Telemetry } from '@wfynbzlx666/sdk-telemetry'

class UserAnalytics {
  constructor() {
    this.initializeTelemetry()
    this.setupEventTracking()
  }
  
  private initializeTelemetry() {
    Telemetry.init({
      app: 'web-app',
      release: '2.1.0',
      environment: 'production',
      endpoint: 'https://analytics.example.com/events',
      sampleRate: 0.1,
      enableAutoPageTracking: true,
      enableAutoErrorTracking: true
    })
    
    // 设置用户信息
    const user = this.getCurrentUser()
    if (user) {
      Telemetry.setUser({
        id: user.id,
        email: user.email,
        role: user.role,
        subscription: user.subscription
      })
    }
  }
  
  private setupEventTracking() {
    // 跟踪按钮点击
    document.addEventListener('click', (event) => {
      const target = event.target as HTMLElement
      if (target.tagName === 'BUTTON' || target.closest('button')) {
        const button = target.closest('button')
        this.trackButtonClick(button)
      }
    })
    
    // 跟踪表单提交
    document.addEventListener('submit', (event) => {
      const form = event.target as HTMLFormElement
      this.trackFormSubmission(form)
    })
    
    // 跟踪搜索
    this.setupSearchTracking()
  }
  
  private trackButtonClick(button: HTMLElement) {
    Telemetry.trackEvent('button_click', {
      buttonId: button.id,
      buttonText: button.textContent?.trim(),
      section: this.getElementSection(button),
      page: window.location.pathname,
      timestamp: Date.now()
    })
  }
  
  private trackFormSubmission(form: HTMLFormElement) {
    const formData = new FormData(form)
    const fields = Array.from(formData.keys())
    
    Telemetry.trackEvent('form_submit', {
      formId: form.id,
      formAction: form.action,
      fieldCount: fields.length,
      fields: fields,
      page: window.location.pathname
    })
  }
  
  private setupSearchTracking() {
    const searchInput = document.querySelector('#search-input') as HTMLInputElement
    if (searchInput) {
      let searchTimeout: number
      
      searchInput.addEventListener('input', (event) => {
        clearTimeout(searchTimeout)
        searchTimeout = window.setTimeout(() => {
          const query = (event.target as HTMLInputElement).value
          if (query.length >= 3) {
            this.trackSearch(query)
          }
        }, 500) // 防抖 500ms
      })
    }
  }
  
  private trackSearch(query: string) {
    Telemetry.trackEvent('search_performed', {
      query,
      queryLength: query.length,
      page: window.location.pathname,
      timestamp: Date.now()
    })
  }
  
  // 跟踪业务事件
  trackPurchase(order: any) {
    Telemetry.trackEvent('purchase_completed', {
      orderId: order.id,
      amount: order.total,
      currency: order.currency,
      itemCount: order.items.length,
      paymentMethod: order.paymentMethod,
      discount: order.discount
    })
  }
  
  trackFeatureUsage(feature: string, context: any = {}) {
    Telemetry.trackEvent('feature_used', {
      feature,
      ...context,
      timestamp: Date.now()
    })
  }
}

// 初始化用户分析
const analytics = new UserAnalytics()

2. React 应用集成

// hooks/useTelemetry.ts
import { useEffect, useCallback } from 'react'
import { Telemetry } from '@wfynbzlx666/sdk-telemetry'

export function useTelemetry() {
  // 页面跟踪 Hook
  const trackPage = useCallback((path: string, data?: any) => {
    Telemetry.trackPageView(path, {
      ...data,
      timestamp: Date.now(),
      userAgent: navigator.userAgent,
      screenResolution: `${screen.width}x${screen.height}`
    })
  }, [])
  
  // 事件跟踪 Hook
  const trackEvent = useCallback((type: string, data?: any) => {
    Telemetry.trackEvent(type, {
      ...data,
      timestamp: Date.now()
    })
  }, [])
  
  // 错误跟踪 Hook
  const trackError = useCallback((error: Error, context?: any) => {
    Telemetry.trackError('react_error', error.message, {
      stack: error.stack,
      component: context?.component,
      props: context?.props,
      ...context
    })
  }, [])
  
  return { trackPage, trackEvent, trackError }
}

// components/TelemetryProvider.tsx
import React, { createContext, useContext, useEffect } from 'react'
import { useLocation } from 'react-router-dom'
import { Telemetry } from '@wfynbzlx666/sdk-telemetry'
import { useTelemetry } from '../hooks/useTelemetry'

const TelemetryContext = createContext<ReturnType<typeof useTelemetry> | null>(null)

export function TelemetryProvider({ children }: { children: React.ReactNode }) {
  const location = useLocation()
  const telemetry = useTelemetry()
  
  // 自动跟踪路由变化
  useEffect(() => {
    telemetry.trackPage(location.pathname, {
      title: document.title,
      referrer: document.referrer
    })
  }, [location.pathname, telemetry])
  
  // 错误边界集成
  useEffect(() => {
    const originalConsoleError = console.error
    console.error = (...args) => {
      telemetry.trackError(new Error(args.join(' ')), {
        type: 'console_error'
      })
      originalConsoleError.apply(console, args)
    }
    
    return () => {
      console.error = originalConsoleError
    }
  }, [telemetry])
  
  return (
    <TelemetryContext.Provider value={telemetry}>
      {children}
    </TelemetryContext.Provider>
  )
}

export const useTelemetryContext = () => {
  const context = useContext(TelemetryContext)
  if (!context) {
    throw new Error('useTelemetryContext must be used within TelemetryProvider')
  }
  return context
}

// components/ProductCard.tsx
import React from 'react'
import { useTelemetryContext } from './TelemetryProvider'

export function ProductCard({ product }: { product: any }) {
  const { trackEvent } = useTelemetryContext()
  
  const handleAddToCart = () => {
    trackEvent('add_to_cart', {
      productId: product.id,
      productName: product.name,
      price: product.price,
      category: product.category
    })
    
    // 实际的添加到购物车逻辑
    addToCart(product)
  }
  
  const handleViewDetails = () => {
    trackEvent('product_view', {
      productId: product.id,
      productName: product.name,
      source: 'product_card'
    })
  }
  
  return (
    <div className="product-card">
      <img src={product.image} alt={product.name} />
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <button onClick={handleViewDetails}>查看详情</button>
      <button onClick={handleAddToCart}>加入购物车</button>
    </div>
  )
}

3. 电商应用事件跟踪

import { Telemetry } from '@wfynbzlx666/sdk-telemetry'

class ECommerceAnalytics {
  constructor() {
    Telemetry.init({
      app: 'ecommerce-web',
      release: '3.2.1',
      endpoint: 'https://analytics.shop.com/events',
      sampleRate: 0.2, // 电商场景可能需要更高的采样率
      enableAutoPageTracking: false, // 手动控制页面跟踪
      enableCrossTabDedup: true
    })
  }
  
  // 产品相关事件
  trackProductView(product: any) {
    Telemetry.trackEvent('product_view', {
      productId: product.id,
      productName: product.name,
      category: product.category,
      price: product.price,
      inStock: product.stock > 0,
      viewSource: this.getViewSource()
    })
  }
  
  trackAddToCart(product: any, quantity: number = 1) {
    Telemetry.trackEvent('add_to_cart', {
      productId: product.id,
      productName: product.name,
      price: product.price,
      quantity,
      cartValue: this.getCurrentCartValue(),
      currency: 'USD'
    })
  }
  
  trackRemoveFromCart(product: any, quantity: number = 1) {
    Telemetry.trackEvent('remove_from_cart', {
      productId: product.id,
      quantity,
      remainingCartValue: this.getCurrentCartValue(),
      removalReason: 'user_action'
    })
  }
  
  // 购买流程事件
  trackCheckoutStart(cart: any) {
    Telemetry.trackEvent('checkout_start', {
      cartValue: cart.total,
      itemCount: cart.items.length,
      currency: cart.currency,
      items: cart.items.map(item => ({
        productId: item.productId,
        quantity: item.quantity,
        price: item.price
      }))
    })
  }
  
  trackCheckoutStep(step: number, stepName: string, data?: any) {
    Telemetry.trackEvent('checkout_step', {
      step,
      stepName,
      ...data,
      timestamp: Date.now()
    })
  }
  
  trackPurchase(order: any) {
    Telemetry.trackEvent('purchase', {
      orderId: order.id,
      transactionId: order.transactionId,
      revenue: order.total,
      tax: order.tax,
      shipping: order.shipping,
      currency: order.currency,
      paymentMethod: order.paymentMethod,
      items: order.items.map(item => ({
        productId: item.productId,
        productName: item.name,
        category: item.category,
        quantity: item.quantity,
        price: item.price
      })),
      customerType: this.getCustomerType(),
      promotions: order.promotions
    })
  }
  
  // 搜索和发现事件
  trackSearch(query: string, results: any[] = []) {
    Telemetry.trackEvent('search', {
      query: query.toLowerCase(),
      queryLength: query.length,
      resultsCount: results.length,
      hasResults: results.length > 0,
      searchType: this.getSearchType(),
      filters: this.getCurrentFilters()
    })
  }
  
  trackFilterApplied(filterType: string, filterValue: string) {
    Telemetry.trackEvent('filter_applied', {
      filterType,
      filterValue,
      currentPage: window.location.pathname,
      previousResultsCount: this.getPreviousResultsCount(),
      newResultsCount: this.getCurrentResultsCount()
    })
  }
  
  // 用户行为事件
  trackWishlistAdd(product: any) {
    Telemetry.trackEvent('wishlist_add', {
      productId: product.id,
      productName: product.name,
      price: product.price,
      source: this.getInteractionSource()
    })
  }
  
  trackReviewSubmit(product: any, rating: number, reviewText: string) {
    Telemetry.trackEvent('review_submit', {
      productId: product.id,
      rating,
      reviewLength: reviewText.length,
      hasPurchased: this.hasUserPurchasedProduct(product.id),
      daysSincePurchase: this.getDaysSincePurchase(product.id)
    })
  }
  
  // 营销和推广事件
  trackPromoCodeUsed(promoCode: string, discount: number) {
    Telemetry.trackEvent('promo_code_used', {
      promoCode,
      discountAmount: discount,
      cartValueBefore: this.getCartValueBeforeDiscount(),
      cartValueAfter: this.getCurrentCartValue()
    })
  }
  
  trackEmailCampaignClick(campaignId: string, emailId: string) {
    Telemetry.trackEvent('email_campaign_click', {
      campaignId,
      emailId,
      landingPage: window.location.pathname,
      userSegment: this.getUserSegment()
    })
  }
  
  // 性能监控
  trackPageLoadPerformance(pageName: string) {
    const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming
    
    Telemetry.trackEvent('page_performance', {
      pageName,
      loadTime: navigation.loadEventEnd - navigation.loadEventStart,
      domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
      firstPaint: this.getFirstPaintTime(),
      largestContentfulPaint: this.getLCPTime(),
      timeToInteractive: this.getTTITime()
    })
  }
  
  // 错误监控
  trackAPIError(endpoint: string, error: any) {
    Telemetry.trackError('api_error', error.message, {
      endpoint,
      statusCode: error.status,
      errorCode: error.code,
      userAction: this.getCurrentUserAction(),
      sessionId: this.getSessionId()
    })
  }
  
  // 辅助方法
  private getViewSource(): string {
    const referrer = document.referrer
    if (referrer.includes('search')) return 'search'
    if (referrer.includes('category')) return 'category'
    if (referrer.includes('recommendation')) return 'recommendation'
    return 'direct'
  }
  
  private getCurrentCartValue(): number {
    // 实现获取当前购物车价值的逻辑
    return 0
  }
  
  private getCustomerType(): string {
    // 实现获取客户类型的逻辑(新客户/老客户)
    return 'new'
  }
}

// 初始化电商分析
const ecommerceAnalytics = new ECommerceAnalytics()
export default ecommerceAnalytics

4. 错误监控和诊断

import { Telemetry } from '@wfynbzlx666/sdk-telemetry'

class ErrorMonitoring {
  private errorCounts: Map<string, number> = new Map()
  private errorThreshold = 10 // 错误阈值
  
  constructor() {
    this.setupGlobalErrorHandling()
    this.setupPerformanceMonitoring()
    this.setupResourceErrorMonitoring()
  }
  
  private setupGlobalErrorHandling() {
    // 捕获 JavaScript 错误
    window.addEventListener('error', (event) => {
      this.handleJavaScriptError(event)
    })
    
    // 捕获 Promise 拒绝
    window.addEventListener('unhandledrejection', (event) => {
      this.handleUnhandledRejection(event)
    })
    
    // 捕获 React 错误边界(如果使用 React)
    if (typeof window !== 'undefined' && (window as any).React) {
      this.setupReactErrorBoundary()
    }
  }
  
  private handleJavaScriptError(event: ErrorEvent) {
    const errorKey = `${event.filename}:${event.lineno}:${event.colno}`
    const errorCount = (this.errorCounts.get(errorKey) || 0) + 1
    this.errorCounts.set(errorKey, errorCount)
    
    Telemetry.trackError('javascript_error', event.message, {
      filename: event.filename,
      line: event.lineno,
      column: event.colno,
      stack: event.error?.stack,
      errorCount,
      isRecurring: errorCount > 1,
      userAgent: navigator.userAgent,
      url: window.location.href,
      timestamp: Date.now(),
      
      // 环境信息
      browserInfo: this.getBrowserInfo(),
      screenInfo: this.getScreenInfo(),
      memoryInfo: this.getMemoryInfo(),
      
      // 用户行为上下文
      lastUserAction: this.getLastUserAction(),
      pageLoadTime: this.getPageLoadTime(),
      timeOnPage: this.getTimeOnPage()
    })
    
    // 错误频率监控
    if (errorCount >= this.errorThreshold) {
      this.handleHighFrequencyError(errorKey, errorCount)
    }
  }
  
  private handleUnhandledRejection(event: PromiseRejectionEvent) {
    Telemetry.trackError('unhandled_promise_rejection', String(event.reason), {
      reason: event.reason,
      promise: event.promise,
      url: window.location.href,
      timestamp: Date.now(),
      
      // Promise 相关信息
      promiseState: 'rejected',
      handled: false,
      
      // 调试信息
      stackTrace: event.reason?.stack || 'No stack trace available',
      debugInfo: this.collectDebugInfo()
    })
  }
  
  private setupPerformanceMonitoring() {
    // 监控长任务
    if ('PerformanceObserver' in window) {
      const longTaskObserver = new PerformanceObserver((list) => {
        list.getEntries().forEach((entry) => {
          if (entry.duration > 50) { // 长于 50ms 的任务
            Telemetry.trackError('long_task', `Task blocked main thread for ${entry.duration}ms`, {
              duration: entry.duration,
              startTime: entry.startTime,
              name: entry.name,
              entryType: entry.entryType,
              url: window.location.href
            })
          }
        })
      })
      longTaskObserver.observe({ entryTypes: ['longtask'] })
    }
    
    // 监控内存使用
    if ('memory' in performance) {
      setInterval(() => {
        const memory = (performance as any).memory
        const usagePercentage = (memory.usedJSHeapSize / memory.jsHeapSizeLimit) * 100
        
        if (usagePercentage > 90) { // 内存使用超过 90%
          Telemetry.trackError('high_memory_usage', `Memory usage at ${usagePercentage.toFixed(2)}%`, {
            usedJSHeapSize: memory.usedJSHeapSize,
            totalJSHeapSize: memory.totalJSHeapSize,
            jsHeapSizeLimit: memory.jsHeapSizeLimit,
            usagePercentage,
            url: window.location.href
          })
        }
      }, 30000) // 每 30 秒检查一次
    }
  }
  
  private setupResourceErrorMonitoring() {
    // 监控资源加载错误
    window.addEventListener('error', (event) => {
      if (event.target !== window) {
        const target = event.target as HTMLElement
        Telemetry.trackError('resource_error', `Failed to load ${target.tagName}`, {
          resourceType: target.tagName.toLowerCase(),
          resourceUrl: (target as any).src || (target as any).href,
          parentElement: target.parentElement?.tagName,
          elementId: target.id,
          elementClass: target.className,
          url: window.location.href,
          timestamp: Date.now()
        })
      }
    }, true)
  }
  
  // 网络错误监控
  trackNetworkError(url: string, method: string, error: any) {
    Telemetry.trackError('network_error', error.message, {
      url,
      method,
      statusCode: error.status,
      statusText: error.statusText,
      timeout: error.timeout,
      networkType: this.getNetworkType(),
      connectionSpeed: this.getConnectionSpeed(),
      requestHeaders: error.config?.headers,
      responseHeaders: error.response?.headers,
      requestPayload: this.sanitizePayload(error.config?.data),
      retryCount: error.retryCount || 0
    })
  }
  
  // 自定义错误报告
  reportCustomError(errorType: string, message: string, context: any = {}) {
    Telemetry.trackError(errorType, message, {
      ...context,
      customError: true,
      reportedAt: Date.now(),
      sessionId: this.getSessionId(),
      userId: this.getUserId(),
      buildInfo: this.getBuildInfo()
    })
  }
  
  // 错误恢复监控
  trackErrorRecovery(errorType: string, recoveryAction: string, success: boolean) {
    Telemetry.trackEvent('error_recovery', {
      errorType,
      recoveryAction,
      success,
      recoveryTime: Date.now(),
      attemptCount: this.getRecoveryAttemptCount(errorType)
    })
  }
  
  // 辅助方法
  private getBrowserInfo() {
    return {
      userAgent: navigator.userAgent,
      language: navigator.language,
      platform: navigator.platform,
      cookieEnabled: navigator.cookieEnabled,
      onLine: navigator.onLine
    }
  }
  
  private getScreenInfo() {
    return {
      width: screen.width,
      height: screen.height,
      colorDepth: screen.colorDepth,
      pixelRatio: window.devicePixelRatio
    }
  }
  
  private getMemoryInfo() {
    if ('memory' in performance) {
      const memory = (performance as any).memory
      return {
        usedJSHeapSize: memory.usedJSHeapSize,
        totalJSHeapSize: memory.totalJSHeapSize,
        jsHeapSizeLimit: memory.jsHeapSizeLimit
      }
    }
    return null
  }
  
  private getNetworkType() {
    return (navigator as any).connection?.effectiveType || 'unknown'
  }
  
  private handleHighFrequencyError(errorKey: string, count: number) {
    Telemetry.trackEvent('high_frequency_error', {
      errorKey,
      errorCount: count,
      threshold: this.errorThreshold,
      url: window.location.href,
      timestamp: Date.now()
    })
  }
  
  private sanitizePayload(payload: any) {
    // 移除敏感信息
    if (!payload) return null
    
    const sanitized = { ...payload }
    const sensitiveFields = ['password', 'token', 'secret', 'key', 'auth']
    
    sensitiveFields.forEach(field => {
      if (sanitized[field]) {
        sanitized[field] = '[REDACTED]'
      }
    })
    
    return sanitized
  }
}

// 初始化错误监控
const errorMonitoring = new ErrorMonitoring()
export default errorMonitoring

🔧 配置选项

Telemetry 配置

interface TelemetryOptions {
  // 基础信息
  app: string                          // 应用名称
  release: string                      // 版本号
  environment?: string                 // 环境(development/staging/production)
  
  // 上报配置
  endpoint?: string                    // 上报端点
  batchSize?: number                   // 批次大小,默认 50
  flushInterval?: number               // 刷新间隔,默认 5000ms
  maxBatchEvents?: number              // 最大批次事件数,默认 200
  maxEventSize?: number                // 单个事件最大大小,默认 10KB
  
  // 采样配置
  sampleRate?: number                  // 采样率,默认 0.1
  errorSampleRate?: number             // 错误采样率,默认 1.0
  performanceSampleRate?: number       // 性能采样率,默认 0.05
  
  // 存储配置
  enableLocalStorage?: boolean         // 启用本地存储,默认 true
  maxStorageSize?: number              // 最大存储大小,默认 5MB
  storageCleanupInterval?: number      // 存储清理间隔,默认 1 小时
  
  // 功能开关
  enableBeacon?: boolean               // 启用 Beacon,默认 true
  enableCrossTabDedup?: boolean        // 启用跨标签页去重,默认 false
  enableAutoPageTracking?: boolean     // 启用自动页面跟踪,默认 false
  enableAutoErrorTracking?: boolean    // 启用自动错误跟踪,默认 false
  
  // 回调函数
  beforeSend?: (event: TelemetryEvent) => TelemetryEvent | null
  onSuccess?: (batch: TelemetryEvent[]) => void
  onError?: (error: Error, batch: TelemetryEvent[]) => void
  onStorageWarning?: (usage: number, limit: number) => void
  
  // 调试配置
  debug?: boolean                      // 调试模式,默认 false
}

事件类型

interface TelemetryEvent {
  type: string                         // 事件类型
  timestamp: number                    // 时间戳
  data: Record<string, any>            // 事件数据
  sessionId?: string                   // 会话 ID
  userId?: string                      // 用户 ID
  metadata?: Record<string, any>       // 元数据
}

// 预定义事件类型
type TelemetryEventType = 
  | 'page_view'                        // 页面浏览
  | 'custom'                           // 自定义事件
  | 'error'                            // 错误事件
  | 'performance'                      // 性能事件
  | 'api'                              // API 事件
  | 'user_action'                      // 用户操作

🔍 类型定义

// 用户信息
interface TelemetryUser {
  id: string
  email?: string
  name?: string
  role?: string
  [key: string]: any
}

// 存储信息
interface StorageInfo {
  used: number
  available: number
  total: number
  percentage: number
}

// 批处理器选项
interface BatcherOptions {
  maxBatchSize?: number
  flushInterval?: number
  maxWaitTime?: number
  onFlush?: (events: TelemetryEvent[]) => Promise<void>
  beforeFlush?: (events: TelemetryEvent[]) => TelemetryEvent[]
}

🚀 性能优化建议

1. 合理设置采样率

// 根据环境和事件类型设置不同的采样率
Telemetry.init({
  sampleRate: process.env.NODE_ENV === 'production' ? 0.05 : 1.0,
  errorSampleRate: 1.0,           // 错误事件始终收集
  performanceSampleRate: 0.01,    // 性能事件低采样率
})

2. 批量处理优化

// 优化批处理配置
Telemetry.init({
  batchSize: 100,                 // 增大批次减少请求次数
  flushInterval: 10000,           // 延长刷新间隔
  maxBatchEvents: 500,            // 增大最大批次
})

3. 事件过滤

// 过滤不必要的事件
Telemetry.init({
  beforeSend: (event) => {
    // 过滤调试事件
    if (event.type === 'debug' && process.env.NODE_ENV === 'production') {
      return null
    }
    
    // 过滤敏感数据
    if (event.data.password) {
      event.data.password = '[REDACTED]'
    }
    
    return event
  }
})

🤝 贡献指南

欢迎提交 Issue 和 Pull Request!

📄 许可证

MIT License