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

@xiaofeiwuuu/ws-client

v0.1.0

Published

极简、零依赖的浏览器 WebSocket 客户端 SDK:内置协议、自动重连、心跳、请求-响应、类型推导。

Readme

@xiaofeiwuuu/ws-client

极简、零运行时依赖的浏览器 WebSocket 客户端 SDK。

  • 🔌 开箱即用:内置一套官方协议,createSocket({ url }) 即可,无需配置编解码。
  • 🔁 自动重连:指数退避;被踢下线(close 4001)等自动不重连。
  • 💓 心跳保活:ping/pong 探测"假死"连接,失活自动断开重连。
  • 📨 请求-响应:await socket.request(...),自带超时与业务错误。
  • 🧩 类型推导:传入消息映射,on/request 的 payload 与返回值自动推导,拼错 type 直接编译报错。
  • 🪶 可替换协议:需要 protobuf / msgpack 时覆盖 encode/decode 即可。

通信协议契约见 PROTOCOL.md(语言无关,可直接交付后端)。


安装

pnpm add @xiaofeiwuuu/ws-client

1. 快速上手

import { createSocket, BizError } from '@xiaofeiwuuu/ws-client'

const socket = createSocket({ url: 'wss://your-server/ws' })

// 订阅服务端推送,返回 off();不用记事件名配对,卸载时调一下即可
const off = socket.on('chat', (msg) => console.log('收到', msg))

// 只推,不等回包
socket.send('enterRoom', { roomId: 1 })

// 请求-响应:成功 / 超时 / 业务错误统一在一个 try/catch
try {
  const list = await socket.request('getList', { page: 1 })
} catch (e) {
  if (e instanceof BizError) console.log('业务失败', e.raw.code, e.raw.msg)
  else console.log('超时或断线', (e as Error).message)
}

off() // 取消订阅

不传 encode/decode 就用内置协议(见第 4 节),消息形如 { v:1, type, id?, payload? }


2. 类型推导(强烈推荐)

createSocket 传两张映射表,on/request 全程类型安全:

// 服务端 → 你:推送消息(type -> payload)
interface ServerMessages {
  chat: { from: string; text: string }
  notify: { title: string; level: number }
}
// 你 → 服务端:请求-响应(type -> { req, res })
interface ApiMap {
  getUser: { req: { id: number }; res: { id: number; name: string } }
  login: { req: { token: string }; res: { uid: number } }
}

const socket = createSocket<ServerMessages, ApiMap>({ url: 'wss://...' })

socket.on('chat', (msg) => msg.text)          // msg 自动是 { from, text }
socket.on('chatt', () => {})                   // ❌ 编译报错:拼错 type
const u = await socket.request('getUser', { id: 1 })  // u 自动是 { id, name }

不传泛型时一切照常宽松为 any,不影响使用。


3. 重连 / 订阅恢复 / 心跳

const socket = createSocket({
  url: 'wss://...',

  // 连接成功(每次都会调,isReconnect 区分首连/重连)
  onOpen: (isReconnect) => { if (!isReconnect) subscribeTopics() },
  // 断线重连成功后调用 —— 在这里重发服务端订阅(否则重连后收不到推送!)
  onReconnect: () => subscribeTopics(),
  onClose: (e) => console.log('closed', e.code),
  onError: (err) => console.error(err.message),

  reconnect: { baseDelay: 500, maxDelay: 10000, maxRetries: Infinity },
  heartbeat: { interval: 15000, timeout: 5000 }, // 后端不支持 ping/pong 时设 { enabled: false }

  // 自定义"哪些关闭码不重连"(默认 1000/4001/4002 不重连)
  shouldReconnect: (e) => e.code !== 1000 && e.code !== 4001,
})

function subscribeTopics() {
  socket.send('subscribe', { topic: 'chat' })
}

订阅分两层:① 你 on() 的回调存在连接之外,重连后自动还在;② 你告诉后端"我要某主题"的服务端订阅,后端断线即忘,必须在 onReconnect重发

⚠️ 心跳依赖后端实现 ping→pong。后端不回 pong 会被误判为假死并反复重连——这种情况请显式 heartbeat: { enabled: false }


4. 内置协议与自定义

默认编解码(对齐 PROTOCOL.md v1):

// 发送:{ "v":1, "type":"getUser", "id":7, "payload":{...} }
// 响应:{ "v":1, "type":"getUser", "id":7, "code":0, "payload":{...} }   // code!=0 → BizError
// 心跳:{ "v":1, "type":"ping" } / { "v":1, "type":"pong" }

需要 protobuf / msgpack / 或对接已有协议时,覆盖这几个函数即可,其余逻辑不变:

createSocket({
  url,
  encode: (type, payload, id) => myEncode({ type, payload, id }), // 返回 string 或 ArrayBuffer
  decode: (raw) => myDecode(raw),                                  // 返回 { type, payload, id, code? }
  isBizError: (msg) => msg.code !== 0,
})

API 速查

| 方法 / 选项 | 说明 | |---|---| | createSocket<S, A>(opts) | 创建连接,自动开始连接 + 心跳 | | socket.on(type, handler) | 订阅推送,返回 off() | | socket.send(type, payload?) | 只推,不等回包 | | socket.request(type, payload?, timeout=10000) | 请求-响应,返回 Promise | | socket.close() | 主动关闭,之后不再重连 | | opts.maxBuffer | 未连接时缓冲条数上限(默认 1000) | | opts.reconnect / opts.heartbeat | 重连 / 心跳配置 | | opts.onOpen/onClose/onError/onReconnect | 生命周期回调 |


环境

  • 面向浏览器(使用全局 WebSocket)。
  • 在 Node 中测试需自行 polyfill:globalThis.WebSocket = require('ws')

License

MIT