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 🙏

© 2026 – Pkg Stats / Ryan Hefner

customer-chat-sdk

v1.4.8

Published

Customer Service SDK - One-line integration for customer support chat

Readme

CustomerSDK 使用文档

简介

CustomerSDK 是一个轻量级的客服 SDK,提供图标管理截图功能。适用于需要自行管理弹窗组件的项目场景。

特性

  • 悬浮图标 - 可拖动的悬浮图标,支持侧边吸附和磁性吸附
  • 截图功能 - 自动截图、压缩、上传
  • 设备识别 - 自动获取设备指纹 ID
  • 通知提醒 - 支持数字和文本通知徽章
  • 无 iframe - 不包含 iframe 管理,由项目自行实现弹窗

安装

npm install customer-chat-sdk
# 或
pnpm add customer-chat-sdk
# 或
yarn add customer-chat-sdk

快速开始

基础用法

import { CustomerSDK } from 'customer-chat-sdk'

// 创建 SDK 实例
const sdk = new CustomerSDK()

// 初始化(返回初始化结果,包含设备ID等)
const initResult = await sdk.init({
  debug: true, // 开发环境开启
  iconPosition: { x: 20, y: 80 },
  target: '#app'
})

console.log('Device ID:', initResult.deviceId)

// 设置图标点击回调
sdk.onIconClick(() => {
  // 打开您的弹窗组件
  openChatPopup()
})

完整示例(Vue 3)

<template>
  <div id="app">
    <ChatPopup
      ref="chatPopupRef"
      v-model:visible="chatVisible"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { CustomerSDK } from 'customer-chat-sdk'

const chatVisible = ref(false)
const chatPopupRef = ref()
let sdk: CustomerSDK | null = null

onMounted(async () => {
  sdk = new CustomerSDK()
  
  const initResult = await sdk.init({
    debug: true,
    screenshot: {
      engine: 'modern-screenshot',
      quality: 0.15,
      compress: true,
      interval: 5000
    },
    iconPosition: { x: 20, y: 80 },
    target: '#app',
    sideAttach: true,
    magnetic: true
  }, {
    sendData: (data) => {
      // 处理截图数据
      chatPopupRef.value?.handleScreenshotData(data)
    }
  })

  // 获取设备ID等信息
  console.log('Device ID:', initResult.deviceId)
  console.log('Referrer:', initResult.referrer)

  // 图标点击打开弹窗
  sdk.onIconClick(async () => {
    chatVisible.value = true
    
    // 启用截图
    const config = await fetchScreenshotConfig()
    if (config) {
      sdk?.triggerScreenshotConfig(JSON.stringify(config))
    }
  })
})

onUnmounted(() => {
  sdk?.destroy()
})
</script>

React 示例

import { useEffect, useRef, useState } from 'react'
import { CustomerSDK } from 'customer-chat-sdk'

function App() {
  const [chatVisible, setChatVisible] = useState(false)
  const sdkRef = useRef<CustomerSDK | null>(null)

  useEffect(() => {
    const sdk = new CustomerSDK()
    sdkRef.current = sdk

    sdk.init({
      debug: true,
      screenshot: {
        engine: 'modern-screenshot',
        quality: 0.15,
        compress: true
      },
      iconPosition: { x: 20, y: 80 },
      target: '#app'
    }, {
      sendData: (data) => {
        // 发送截图数据到后端
        fetch('/api/upload-screenshot', {
          method: 'POST',
          headers: { 'Content-Type': 'application/octet-stream' },
          body: data.data
        })
      }
    }).then((initResult) => {
      // 获取设备ID等信息
      console.log('Device ID:', initResult.deviceId)
      
      sdk.onIconClick(async () => {
        setChatVisible(true)
        const config = await fetchScreenshotConfig()
        if (config) {
          sdk.triggerScreenshotConfig(JSON.stringify(config))
        }
      })
    })

    return () => {
      sdk.destroy()
    }
  }, [])

  return <div id="app">...</div>
}

API 文档

CustomerSDK 类

构造函数

const sdk = new CustomerSDK()

init(config, screenshotCallback?)

初始化 SDK

const initResult = await sdk.init(config, screenshotCallback?)

返回值:

返回 InitResult 对象,包含:

  • deviceId: string - 设备ID(md5后的)
  • referrer: string - 页面来源
  • agent?: string - 代理商ID(如果配置了)
  • timestamp: number - 初始化时间戳

参数:

  • config: SDKConfig - SDK 配置
  • screenshotCallback?: ScreenshotMessageCallback - 截图回调(可选)

配置选项:

interface SDKConfig {
  debug?: boolean                    // 调试模式
  screenshot?: ScreenshotOptions    // 截图配置
  iconPosition?: {                  // 图标位置
    x?: number | string
    y?: number | string
  }
  target?: HTMLElement | string     // 图标挂载目标
  sideAttach?: boolean              // 侧边吸附(默认 true)
  sideHideRatio?: number            // 侧边隐藏比例(默认 0.5)
  magnetic?: boolean                // 磁性吸附(默认 true)
  magneticDirection?: 'x' | 'y' | 'both' // 磁性方向(默认 'x')
  margin?: number                   // 边距(默认 10px)
  autoAttachDelay?: number          // 自动吸附延迟(默认 3000ms)
  referrer?: string                 // 页面来源
  agent?: string                    // 代理商ID
  token?: string                    // 认证令牌
}

截图配置:

interface ScreenshotOptions {
  engine?: 'modern-screenshot' | 'snapdom' | 'html2canvas'
  quality?: number                  // 0-1,默认 0.15
  compress?: boolean                // 是否压缩
  interval?: number                 // 默认间隔(毫秒)
  maxWidth?: number                 // 最大宽度
  maxHeight?: number                // 最大高度
  outputFormat?: 'webp' | 'jpeg' | 'png'
  enableCORS?: boolean              // 启用 CORS
  proxyUrl?: string                 // 代理 URL
  corsMode?: 'simple' | 'smart' | 'proxy' | 'blob' | 'canvas-proxy'
  debug?: boolean                   // 截图调试
}

截图回调:

interface ScreenshotMessageCallback {
  sendData?: (data: {
    type: 'screenshotBinary'
    data: ArrayBuffer
  }) => void
  onConfig?: (config: string) => void
}

onIconClick(callback)

设置图标点击回调(也可以在 init 中配置)

// 方式1: 使用函数式 API(default 导出)- 可以直接调用
const CustomerSDK = await import('customer-chat-sdk')
await CustomerSDK.default.init(config)
CustomerSDK.default.onIconClick(() => {
  openChatPopup()
})

// 方式2: 使用类(命名导出)- 在 init 中配置(推荐)
const sdk = new CustomerSDK()
await sdk.init(config, screenshotCallback, {
  onIconClick: () => {
    openChatPopup()
  }
})

// 方式3: 使用类(命名导出)- 单独设置
const sdk = new CustomerSDK()
await sdk.init(config)
sdk.onIconClick(() => {
  openChatPopup()
})

updateToken(token, screenshotCallback?, initCallback?)

更新 token(用于用户登录/退出场景)

// 更新 token(会自动重新初始化)
await sdk.updateToken('new-token')

// 更新 token 并更新回调
await sdk.updateToken('new-token', {
  sendData: (data) => { /* ... */ }
}, {
  onIconClick: () => { /* ... */ }
})

showNotification(badgeCount, options?)

显示通知

sdk.showNotification(5, { pulse: true, autoHide: 5000 })
sdk.showNotification('新', { pulse: true })

clearNotification()

清除通知

sdk.clearNotification()

triggerScreenshotConfig(configJson)

启用/停止截图

// 启用截图
const config = {
  agent: 'your-agent-id',
  sign: 'your-sign',
  type: 1,
  topic: 'screenshot',
  routingKey: 'route-key',
  ttl: Date.now() + 3600000, // 1小时后过期
  duration: 5000 // 5秒间隔
}
sdk.triggerScreenshotConfig(JSON.stringify(config))

// 停止截图
sdk.triggerScreenshotConfig(JSON.stringify({
  ...config,
  ttl: 0 // 禁用
}))

showIcon() / hideIcon()

显示/隐藏图标

sdk.showIcon()
sdk.hideIcon()

getDeviceId()

获取设备ID(md5后的)

const deviceId = sdk.getDeviceId()
console.log('Device ID:', deviceId)

getInitResult()

获取初始化结果(包含设备ID等信息)

const initResult = sdk.getInitResult()
if (initResult) {
  console.log('Device ID:', initResult.deviceId)
  console.log('Referrer:', initResult.referrer)
  console.log('Timestamp:', initResult.timestamp)
}

getScreenshotManager() / getIconManager()

获取管理器实例(用于高级操作)

const screenshotManager = sdk.getScreenshotManager()
const iconManager = sdk.getIconManager()

destroy()

销毁 SDK

sdk.destroy()

完整工作流程

1. 初始化

const sdk = new CustomerSDK()
const initResult = await sdk.init({
  debug: true,
  screenshot: { /* ... */ },
  iconPosition: { x: 20, y: 80 },
  target: '#app'
}, {
  // 截图回调
  sendData: (data) => {
    // 处理截图数据
  }
}, {
  // 初始化回调(图标点击)
  onIconClick: async () => {
    openChatPopup()
    // 启用截图
    const config = await fetchScreenshotConfig()
    if (config) {
      sdk.triggerScreenshotConfig(JSON.stringify(config))
    }
  }
})

// 获取设备ID等信息
console.log('Device ID:', initResult.deviceId)
console.log('Referrer:', initResult.referrer)

2. 弹窗打开时启用截图

// 方式1: 在 init 中配置(推荐)
await sdk.init(config, screenshotCallback, {
  onIconClick: async () => {
    openChatPopup()
    const config = await fetchScreenshotConfig()
    sdk.triggerScreenshotConfig(JSON.stringify(config))
  }
})

// 方式2: 单独设置
sdk.onIconClick(async () => {
  openChatPopup()
  const config = await fetchScreenshotConfig()
  sdk.triggerScreenshotConfig(JSON.stringify(config))
})

2.1. 更新 token

// 用户登录后更新 token
await sdk.updateToken('new-token')

3. 弹窗关闭时停止截图

function closeChatPopup() {
  closePopup()
  sdk.triggerScreenshotConfig(JSON.stringify({
    ...config,
    ttl: 0
  }))
}

4. 清理

onUnmounted(() => {
  sdk?.destroy()
})

常见场景

只使用图标功能

const sdk = new CustomerSDK()
await sdk.init({
  debug: true,
  iconPosition: { x: 20, y: 80 },
  target: '#app'
})

sdk.onIconClick(() => {
  openChatPopup()
})

图标 + 截图

const sdk = new CustomerSDK()
await sdk.init({
  screenshot: {
    engine: 'modern-screenshot',
    quality: 0.15,
    compress: true
  }
}, {
  sendData: (data) => {
    sendToBackend(data)
  }
})

注意事项

  1. 调试模式:生产环境请关闭 debug: true
  2. 截图性能:合理设置截图间隔,避免过于频繁
  3. 内存管理:及时调用 destroy() 清理资源
  4. 错误处理:所有异步操作都应添加错误处理
  5. CORS 问题:如果遇到跨域问题,配置 proxyUrl 或调整 corsMode

动态导入示例

方式 1: 使用类(推荐)

const initCustomerSDK = async () => {
  // 动态导入
  const mod = await import('customer-chat-sdk')
  
  // 获取 CustomerSDK 类(命名导出)
  const { CustomerSDK } = mod
  
  // ✅ 重要:必须先实例化
  const sdk = new CustomerSDK()

  // 初始化(调用实例方法)
  const initResult = await sdk.init({
    debug: true,
    iconPosition: { x: 20, y: 80 },
    target: '#app'
  }, {
    sendData: (data) => {
      // 处理截图数据
    }
  })

  // 设置图标点击回调(调用实例方法)
  sdk.onIconClick(() => {
    openChatPopup()
  })

  return sdk
}

方式 2: 使用函数式 API(default 导出)

const initCustomerSDK = async () => {
  // 动态导入
  const mod = await import('customer-chat-sdk')
  
  // 获取 default 导出(函数式 API)
  const SDK = mod.default
  
  // ✅ 直接调用函数(不需要实例化)
  const initResult = await SDK.init({
    debug: true,
    iconPosition: { x: 20, y: 80 },
    target: '#app'
  })

  // 使用其他函数式 API
  SDK.showIcon()
  SDK.showNotification(5)
  
  return SDK
}

注意:函数式 API 使用全局单例,只能有一个实例。如果需要多个实例或更好的类型支持,推荐使用类的方式。

兼容性动态导入(自动检测)

const initCustomerSDK = async () => {
  const mod = await import('customer-chat-sdk')
  
  // 优先使用类的方式(推荐)
  if (mod.CustomerSDK && typeof mod.CustomerSDK === 'function') {
    const sdk = new mod.CustomerSDK()
    await sdk.init({ /* ... */ })
    sdk.onIconClick(() => { /* ... */ })
    return sdk
  }
  
  // 回退到函数式 API
  if (mod.default && mod.default.init) {
    const SDK = mod.default
    await SDK.init({ /* ... */ })
    SDK.showIcon()
    return SDK
  }
  
  throw new Error('CustomerSDK 未找到')
}

类型定义

import type {
  CustomerSDK,
  ScreenshotMessageCallback,
  SDKConfig,
  ScreenshotOptions,
  InitResult
} from 'customer-chat-sdk'

许可证

MIT