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

@aardpro/captcha-browser

v3.0.0

Published

点击式行为验证码前端库 - Browser implementation

Readme

@aardpro/captcha-browser

点击式行为验证码前端库 - Browser implementation

零依赖、纯原生 JS,自带完整 UI(图片 + 状态栏 + 刷新/提交按钮 + 点击标记)。与后端 @aardpro/captcha-node 配对使用。

设计理念

组件只负责 UI(渲染、收集点击、驱动流程),网络请求和业务逻辑由调用方通过两个回调提供

  • generateCaptcha() —— 你自己 fetch 后端、附加鉴权/nonce、reshape 响应,返回图片和 token;
  • verifyCaptcha(clicks, token) —— 你自己 fetch 后端、做防重放、发短信等副作用,返回校验结果。

这样组件不绑定任何服务端约定,适配任意后端(REST / RPC / 任意响应壳子)。

功能特点

  • 🎯 点击式验证:用户按从左到右顺序点击图片上的字符
  • 🌐 双语:lang: 'zh-CN' | 'en-US'(默认 zh-CN),控制 widget 文案
  • 🔌 后端无关:网络与业务逻辑交给回调
  • 🎨 可定制:支持自定义点击标记样式
  • 📦 TypeScript:完整的类型定义
  • 🚀 零依赖:纯原生 JavaScript 实现

安装

# npm
npm install @aardpro/captcha-browser

# pnpm
pnpm add @aardpro/captcha-browser

# bun
bun add @aardpro/captcha-browser

快速开始

import { Captcha } from '@aardpro/captcha-browser';

// 1. 提供两个回调(自行处理网络请求)
const generateCaptcha = async () => {
  const response = await fetch('/api/captcha');
  return await response.json(); // 期望 { success, data: { image, token } }
};

const verifyCaptcha = async (clicks, token) => {
  const response = await fetch('/api/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ input: clicks, token }),
  });
  return await response.json(); // 期望 { success, data: { valid } }
};

// 2. 实例化(generateCaptcha / verifyCaptcha 必填)
const captcha = new Captcha({
  container: '#captcha-container',
  generateCaptcha,
  verifyCaptcha,
});

// 3. 生成验证码(页面挂载后调用一次)
await captcha.generate();

// 4. 校验(用户按从左到右点完后调用)
const result = await captcha.verify();
// result.data.valid === true / false

后端契约

两个回调的返回值必须是包装形状:

// generateCaptcha() 返回
{ success: true, data: { image: string, token: string } }

// verifyCaptcha() 返回
{ success: true, data: { valid: boolean } }

@aardpro/captcha-node 时,把它的原始返回包一层即可:

// 生成
const { image, token } = await generateCaptcha({ chars, count: 4, secret });
return { success: true, data: { image, token } };

// 校验
const valid = verifyCaptcha({ token, input: clicks, secret });
return { success: true, data: { valid } };

因为回调完全由你控制,所以防重放 nonce、鉴权头、发短信等副作用都可以直接写进 verifyCaptcha 里——这是组件自己发请求的方案做不到的。

配置选项

const captcha = new Captcha({
  container: '#captcha-container',     // 必填:元素或选择器
  width: 400,                           // 图片宽度,需与后端 width 一致(默认 400)
  generateCaptcha,                      // 必填:() => Promise<{ success, data:{image,token} }>
  verifyCaptcha,                        // 必填:(clicks, token) => Promise<{ success, data:{valid} }>
  lang: 'zh-CN',                           // 'zh-CN' | 'en-US',默认 'zh-CN'。控制 widget 文案
  markerStyle: {
    color: '#667eea',
    size: 24,
    borderWidth: 2,
  },
  // 事件回调(全部可选)
  onGenerate: (response) => {},
  onGenerateError: (error) => {},
  onClick: (coordinate, allCoordinates) => {},
  onVerifySuccess: (response) => {},
  onVerifyError: (error) => {},
  onRefresh: () => {},
});

事件监听

const captcha = new Captcha({
  container: '#captcha-container',
  generateCaptcha,
  verifyCaptcha,
  onGenerate: (response) => console.log('验证码已生成', response),
  onClick: (coordinate, allCoordinates) =>
    console.log('点击了', coordinate, '共', allCoordinates.length),
  onVerifySuccess: (response) => console.log('验证通过!'),
  onVerifyError: (error) => console.error('验证失败', error),
});

API 文档

Captcha 类

构造函数

constructor(options: {
  container: HTMLElement | string;        // 必填
  width?: number;                         // 默认 400
  generateCaptcha: GenerateCaptchaFunction;   // 必填
  verifyCaptcha: VerifyCaptchaFunction;       // 必填
  lang?: 'zh-CN' | 'en-US';                     // 默认 'zh-CN'
  markerStyle?: { color?: string; size?: number; borderWidth?: number };
  onGenerate?: (response: CaptchaGenerateResponse) => void;
  onGenerateError?: (error: Error) => void;
  onClick?: (coordinate: [number, number], allCoordinates: [number, number][]) => void;
  onVerifySuccess?: (response: CaptchaVerifyResponse) => void;
  onVerifyError?: (error: Error) => void;
  onRefresh?: () => void;
})

方法

| 方法 | 说明 | |---|---| | generate() | 生成验证码(调用你的 generateCaptcha),Promise<CaptchaGenerateResponse> | | verify() | 校验点击坐标(调用你的 verifyCaptcha),Promise<CaptchaVerifyResponse> | | refresh() | 刷新(清空并重新生成) | | clearClicks() | 清除点击记录 | | clearMarkers() | 清除点击标记 | | reset() | 重置状态 | | getClicks() | 获取点击坐标 [number, number][](相对图片左上角) | | getToken() | 获取当前 token | | destroy() | 销毁实例,清理 DOM 与事件 |

开发

npm install
npm run dev        # 运行 demo(vite,:3000,需后端在 :3001)
npm run build      # 构建(tsup)
npm run build:watch

Demo

demo 里已经用回调方式对接后端(vite 会把 /api 代理到 :3001):

# 终端 1:后端(在 captcha-node/server 下)
cd ../captcha-node/server
npm install && npm start     # 监听 :3001

# 终端 2:前端 demo
npm run dev                  # 开 http://localhost:3000

不要用 file:// 直接打开 HTML —— module 脚本会加载失败导致一片空白,必须走 npm run dev

License

MIT