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

@chnak/weixin-bot

v1.2.9

Published

WeChat iLink Bot SDK for Node.js

Readme

@chnak/weixin-bot

微信 iLink 机器人 API 的零依赖 Node.js SDK。

安装

npm install @chnak/weixin-bot

快速开始

import { WeixinBot } from '@chnak/weixin-bot'

const bot = new WeixinBot()
await bot.login()

bot.onMessage(async (msg) => {
  console.log(`[${msg.timestamp.toLocaleTimeString()}] ${msg.userId}: ${msg.text}`)
  await bot.reply(msg, `你说了: ${msg.text}`)
})

await bot.run()

API 参考

new WeixinBot(options?)

创建一个机器人客户端。

  • baseUrl?: string 覆盖 iLink API 的基础 URL。
  • tokenPath?: string 覆盖凭证文件路径。默认:~/.weixin-bot/credentials.json
  • onError?: (error: unknown) => void 接收轮询或处理器错误。

await bot.login(options?)

在需要时启动二维码登录,将凭证存储在本地,并返回活动会话。

  • force?: boolean 忽略缓存的凭证并要求重新二维码登录。

bot.onMessage(handler)

注册一个异步或同步消息处理器。每条收到的用户消息都会被转换为以下格式:

interface IncomingMessage {
  userId: string
  text: string
  type: 'text' | 'image' | 'voice' | 'file' | 'video'
  raw: WeixinMessage
  _contextToken: string
  timestamp: Date
}

await bot.reply(msg, text)

使用该消息的 context_token 回复收到的消息。

await bot.sendTyping(userId)

在微信聊天中显示"对方正在输入中..."(正在输入指示器)。自动通过 getconfig 获取所需的 typing_ticket。仅在 SDK 收到过该用户的至少一条上行消息后才能使用。

await bot.stopTyping(userId)

取消正在输入指示器。

await bot.send(userId, text)

使用该用户最新缓存的 context_token 发送主动文本消息。此方法仅在 SDK 收到过该用户的至少一条上行消息后才能使用。

await bot.sendImage(userId, filePath)

await bot.sendImage(userId, buffer, filename?)

发送图片消息。接受文件路径或 Buffer。

await bot.sendImage(userId, '/path/to/image.png')
await bot.sendImage(userId, imageBuffer, 'photo.png')

await bot.sendVideo(userId, filePath, opts?)

await bot.sendVideo(userId, buffer, filename?, opts?)

发送视频消息。接受文件路径或 Buffer。选项:

  • playLength?: number 视频时长(秒)。
await bot.sendVideo(userId, '/path/to/video.mp4', { playLength: 30 })
await bot.sendVideo(userId, videoBuffer, 'video.mp4', { playLength: 60 })

await bot.sendVoice(userId, filePath)

await bot.sendVoice(userId, buffer, filename?)

发送语音消息。接受文件路径或 Buffer。

await bot.sendVoice(userId, '/path/to/voice.silk')
await bot.sendVoice(userId, voiceBuffer, 'voice.silk')

await bot.sendFile(userId, filePath, fileName?)

await bot.sendFile(userId, buffer, fileName?)

发送文件附件。接受文件路径或 Buffer。如果未提供文件名,则从路径中推断。

await bot.sendFile(userId, '/path/to/document.pdf')
await bot.sendFile(userId, fileBuffer, 'report.pdf')

await bot.sendRefMessage(userId, title, refItem, content?)

发送引用(回复/引用)消息,引用另一条消息。参数:

  • title: string 引用的标题/描述。
  • refItem: MessageItem 要引用的消息项(例如 text_item、image_item)。
  • content?: { text?: string } 可选的回复内容。如果省略,则只发送引用而不发送文本。
// 回复文本,引用另一条文本消息
await bot.sendRefMessage(userId, '原消息', {
  type: MessageItemType.TEXT,
  text_item: { text: '这是原消息' }
}, { text: '这是我的回复' })

// 引用图片
const uploaded = await uploadMediaToCdn({ ... })
await bot.sendRefMessage(userId, '看这张图', {
  type: MessageItemType.IMAGE,
  image_item: buildImageMessage(uploaded)
})

downloadAndDecryptMedia(params)

从 CDN 下载媒体文件并解密。返回解密后的原始文件数据(Buffer)。

  • url: string CDN 媒体的 URL。
  • aesKey: string AES 密钥(hex 编码)。
import { downloadAndDecryptMedia } from '@chnak/weixin-bot'

// 从收到的图片消息中下载
const buffer = await downloadAndDecryptMedia({
  url: imageItem.url,
  aesKey: Buffer.from(imageItem.media.aes_key, 'base64').toString('hex')
})

// 保存到文件
import { writeFile } from 'node:fs/promises'
await writeFile('image.png', buffer)

// 或转为 base64
const base64 = buffer.toString('base64')

decryptAesEcb(ciphertext, key)

使用 AES-128-ECB 解密数据(PKCS7 padding 会自动移除)。

import { decryptAesEcb } from '@chnak/weixin-bot'

const plaintext = decryptAesEcb(encryptedBuffer, key)

await downloadMediaToFile(url, aesKey, destPath)

下载 CDN 媒体文件并解密,直接保存到指定路径。

  • url - CDN 媒体 URL
  • aesKey - AES key(base64 编码)
  • destPath - 保存路径
import { downloadMediaToFile } from '@chnak/weixin-bot'

// 从收到的图片消息下载并保存
await downloadMediaToFile(
  imageItem.url,
  imageItem.media.aes_key,  // base64 编码
  './downloads/image.png'
)

await bot.run()

启动长轮询循环,将收到的消息分发给已注册的处理程序,在临时故障时重连,并在会话过期时触发重新登录。

bot.stop()

优雅地停止长轮询循环。

工作原理

  1. login() 获取二维码登录 URL,等待微信确认,并保存返回的机器人令牌。
  2. run()getupdates 执行长轮询。
  3. 每条收到的消息都会被规范化为 IncomingMessage 并发送到您的回调函数。
  4. reply()send() 重用协议要求的内部管理的 context_token

协议

有关此 SDK 使用的线协议参考,请参阅 ../PROTOCOL.md

License

MIT