{"_id":"@aardpro/captcha-browser","_rev":"4-9332f1272c3459f73edae0a514422cc5","name":"@aardpro/captcha-browser","dist-tags":{"latest":"3.0.0"},"versions":{"1.0.0":{"name":"@aardpro/captcha-browser","version":"1.0.0","keywords":["captcha","verification","click-captcha","browser","frontend"],"author":{"name":"aardpro"},"license":"MIT","_id":"@aardpro/captcha-browser@1.0.0","maintainers":[{"name":"aardpro","email":"chileehong@outlook.com"}],"homepage":"https://github.com/aardpro/captcha-browser#readme","bugs":{"url":"https://github.com/aardpro/captcha-browser/issues"},"dist":{"shasum":"6ef79dc052776e696b2a6d491e370014884df36d","tarball":"https://registry.npmjs.org/@aardpro/captcha-browser/-/captcha-browser-1.0.0.tgz","fileCount":6,"integrity":"sha512-8jolx6F86/BPEOZINkkwesCGrkt7Oz7BfHb9TCP2wJIeQm/eqSn+3ljZreWLAWM9a39ON+qhKIsJ9/liy8tG0A==","signatures":[{"sig":"MEUCIDvN8CdkKwTDYR6bPvxzLizzPlrASnye27XKqW5f2qdzAiEA7XKtILaMN2ffFJ/Ebku1Y6vdft5Lf6MF2wKEsaaHiq4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":60168},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"vite","build":"tsup","preview":"vite preview","build:watch":"tsup --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"aardpro","email":"chileehong@outlook.com"},"repository":{"url":"git+https://github.com/aardpro/captcha-browser.git","type":"git"},"_npmVersion":"11.6.0","description":"点击式行为验证码前端库 - Browser implementation","directories":{},"_nodeVersion":"22.19.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vite":"^5.0.0","typescript":"^5.3.0","@types/node":"^20.10.0"},"_npmOperationalInternal":{"tmp":"tmp/captcha-browser_1.0.0_1769499996964_0.2380310563221204","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@aardpro/captcha-browser","version":"1.0.1","keywords":["captcha","verification","click-captcha","browser","frontend"],"author":{"name":"aardpro"},"license":"MIT","_id":"@aardpro/captcha-browser@1.0.1","maintainers":[{"name":"aardpro","email":"chileehong@outlook.com"}],"homepage":"https://github.com/aardpro/captcha-browser#readme","bugs":{"url":"https://github.com/aardpro/captcha-browser/issues"},"dist":{"shasum":"1899bf424a62ebc462179916342b096376cef815","tarball":"https://registry.npmjs.org/@aardpro/captcha-browser/-/captcha-browser-1.0.1.tgz","fileCount":6,"integrity":"sha512-//+YONdWRh71UyYU5EQIlZP4QttExsMohnVaxQeRY4Dxmrb91/vBg609W4/eitFnx7M7CNdmOuwoFsDcCg/4uw==","signatures":[{"sig":"MEUCIQDkrG83z4OKMTU1U+HSum4oqQaVI8xqzS1P999i3kD+cgIgRHRGV7Gfsfqk64+odJTQdH9M7/vLw7IwNjzAktKqjz8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":63066},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"b88783fa8c91a75672e76c66d4539e8cf0e473d7","scripts":{"dev":"vite","build":"tsup","preview":"vite preview","build:watch":"tsup --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"aardpro","email":"chileehong@outlook.com"},"repository":{"url":"git+https://github.com/aardpro/captcha-browser.git","type":"git"},"_npmVersion":"11.6.0","description":"点击式行为验证码前端库 - Browser implementation","directories":{},"_nodeVersion":"22.19.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vite":"^5.0.0","typescript":"^5.3.0","@types/node":"^20.10.0"},"_npmOperationalInternal":{"tmp":"tmp/captcha-browser_1.0.1_1769614667976_0.22837510345022882","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@aardpro/captcha-browser","version":"2.1.0","keywords":["captcha","verification","click-captcha","browser","frontend"],"author":{"name":"aardpro"},"license":"MIT","_id":"@aardpro/captcha-browser@2.1.0","maintainers":[{"name":"aardpro","email":"chileehong@outlook.com"}],"homepage":"https://github.com/aardpro/captcha-browser#readme","bugs":{"url":"https://github.com/aardpro/captcha-browser/issues"},"dist":{"shasum":"e98a922c43820bcdafd7c6a1cba29a4ab02d5020","tarball":"https://registry.npmjs.org/@aardpro/captcha-browser/-/captcha-browser-2.1.0.tgz","fileCount":6,"integrity":"sha512-uWkRiiLD59oFBQ3oeHHdNIn11qSXpgkdAuWh797T0wG3BNISn3iqVjjHoXVAxfXonzYHvYuhjKz8DuXkK+dAzg==","signatures":[{"sig":"MEUCIH4Z4auo5l0UBk8zFu4UC3wjWdD4/kmhgaS3afIbRs6aAiEA9Z9lM6K79FF6NJgb9dqV2sgym27IFDtYjVb1yU12Nno=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aardpro%2fcaptcha-browser@2.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":64094},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"0f3ac639f3604a97bb718d7f9585140d5892f2f4","scripts":{"dev":"vite","build":"tsup","preview":"vite preview","build:watch":"tsup --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:2464da62-dc12-46c5-a27f-ad2e459167d7"}},"repository":{"url":"git+https://github.com/aardpro/captcha-browser.git","type":"git"},"_npmVersion":"12.0.2","description":"点击式行为验证码前端库 - Browser implementation","directories":{},"_nodeVersion":"22.23.2","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vite":"^5.0.0","typescript":"^5.3.0","@types/node":"^20.10.0"},"_npmOperationalInternal":{"tmp":"tmp/captcha-browser_2.1.0_1786092256569_0.31731558627757805","host":"s3://npm-registry-packages-npm-production"}},"3.0.0":{"name":"@aardpro/captcha-browser","version":"3.0.0","description":"点击式行为验证码前端库 - Browser implementation","type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"vite","build":"tsup","build:watch":"tsup --watch","preview":"vite preview","prepublishOnly":"npm run build"},"keywords":["captcha","verification","click-captcha","browser","frontend"],"author":{"name":"aardpro"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/aardpro/captcha-browser.git"},"bugs":{"url":"https://github.com/aardpro/captcha-browser/issues"},"homepage":"https://github.com/aardpro/captcha-browser#readme","devDependencies":{"@types/node":"^20.10.0","typescript":"^5.3.0","tsup":"^8.0.0","vite":"^5.0.0"},"dependencies":{},"gitHead":"cbba24ad6fa76694c90558d7fce4714e66887ce3","_id":"@aardpro/captcha-browser@3.0.0","_nodeVersion":"22.23.1","_npmVersion":"12.0.2","dist":{"integrity":"sha512-PXuDEMjn1jRC/c/CrXy6kwF+kxksXZ8TM9KuISDrZ0kQfHxfrwFgpnR1pyo61Kz0K4bujwGS1/znqSpXaOR0Zw==","shasum":"ee7877e9a570c0becfaf3a877acc5c2cf05fa078","tarball":"https://registry.npmjs.org/@aardpro/captcha-browser/-/captcha-browser-3.0.0.tgz","fileCount":6,"unpackedSize":58778,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aardpro%2fcaptcha-browser@3.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAVgrOeB+DLtqFaJo+8iEW/NBfxea975n/ams0aMTunWAiBHHJJS6SzdppCu55B2bfpm1gWmWbMHhVuQ18sne6Uvaw=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:2464da62-dc12-46c5-a27f-ad2e459167d7"}},"directories":{},"maintainers":[{"name":"aardpro","email":"chileehong@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/captcha-browser_3.0.0_1786094441158_0.685126355281948"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-27T07:46:36.804Z","modified":"2026-08-07T09:20:41.613Z","1.0.0":"2026-01-27T07:46:37.086Z","1.0.1":"2026-01-28T15:37:48.134Z","2.1.0":"2026-08-07T08:44:16.713Z","3.0.0":"2026-08-07T09:20:41.303Z"},"bugs":{"url":"https://github.com/aardpro/captcha-browser/issues"},"author":{"name":"aardpro"},"license":"MIT","homepage":"https://github.com/aardpro/captcha-browser#readme","keywords":["captcha","verification","click-captcha","browser","frontend"],"repository":{"type":"git","url":"git+https://github.com/aardpro/captcha-browser.git"},"description":"点击式行为验证码前端库 - Browser implementation","maintainers":[{"name":"aardpro","email":"chileehong@outlook.com"}],"readme":"# @aardpro/captcha-browser\n\n点击式行为验证码前端库 - Browser implementation\n\n零依赖、纯原生 JS，自带完整 UI（图片 + 状态栏 + 刷新/提交按钮 + 点击标记）。与后端 [`@aardpro/captcha-node`](https://www.npmjs.com/package/@aardpro/captcha-node) 配对使用。\n\n## 设计理念\n\n组件**只负责 UI**（渲染、收集点击、驱动流程），**网络请求和业务逻辑由调用方通过两个回调提供**：\n\n- `generateCaptcha()` —— 你自己 fetch 后端、附加鉴权/nonce、reshape 响应，返回图片和 token；\n- `verifyCaptcha(clicks, token)` —— 你自己 fetch 后端、做防重放、发短信等副作用，返回校验结果。\n\n这样组件不绑定任何服务端约定，适配任意后端（REST / RPC / 任意响应壳子）。\n\n## 功能特点\n\n- 🎯 点击式验证：用户按从左到右顺序点击图片上的字符\n- 🌐 双语：`lang: 'zh-CN' | 'en-US'`（默认 `zh-CN`），控制 widget 文案\n- 🔌 后端无关：网络与业务逻辑交给回调\n- 🎨 可定制：支持自定义点击标记样式\n- 📦 TypeScript：完整的类型定义\n- 🚀 零依赖：纯原生 JavaScript 实现\n\n## 安装\n\n```bash\n# npm\nnpm install @aardpro/captcha-browser\n\n# pnpm\npnpm add @aardpro/captcha-browser\n\n# bun\nbun add @aardpro/captcha-browser\n```\n\n## 快速开始\n\n```typescript\nimport { Captcha } from '@aardpro/captcha-browser';\n\n// 1. 提供两个回调（自行处理网络请求）\nconst generateCaptcha = async () => {\n  const response = await fetch('/api/captcha');\n  return await response.json(); // 期望 { success, data: { image, token } }\n};\n\nconst verifyCaptcha = async (clicks, token) => {\n  const response = await fetch('/api/verify', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({ input: clicks, token }),\n  });\n  return await response.json(); // 期望 { success, data: { valid } }\n};\n\n// 2. 实例化（generateCaptcha / verifyCaptcha 必填）\nconst captcha = new Captcha({\n  container: '#captcha-container',\n  generateCaptcha,\n  verifyCaptcha,\n});\n\n// 3. 生成验证码（页面挂载后调用一次）\nawait captcha.generate();\n\n// 4. 校验（用户按从左到右点完后调用）\nconst result = await captcha.verify();\n// result.data.valid === true / false\n```\n\n### 后端契约\n\n两个回调的返回值必须是包装形状：\n\n```typescript\n// generateCaptcha() 返回\n{ success: true, data: { image: string, token: string } }\n\n// verifyCaptcha() 返回\n{ success: true, data: { valid: boolean } }\n```\n\n用 [`@aardpro/captcha-node`](https://www.npmjs.com/package/@aardpro/captcha-node) 时，把它的原始返回包一层即可：\n\n```typescript\n// 生成\nconst { image, token } = await generateCaptcha({ chars, count: 4, secret });\nreturn { success: true, data: { image, token } };\n\n// 校验\nconst valid = verifyCaptcha({ token, input: clicks, secret });\nreturn { success: true, data: { valid } };\n```\n\n> 因为回调完全由你控制，所以防重放 nonce、鉴权头、发短信等副作用都可以直接写进 `verifyCaptcha` 里——这是组件自己发请求的方案做不到的。\n\n## 配置选项\n\n```typescript\nconst captcha = new Captcha({\n  container: '#captcha-container',     // 必填：元素或选择器\n  width: 400,                           // 图片宽度，需与后端 width 一致（默认 400）\n  generateCaptcha,                      // 必填：() => Promise<{ success, data:{image,token} }>\n  verifyCaptcha,                        // 必填：(clicks, token) => Promise<{ success, data:{valid} }>\n  lang: 'zh-CN',                           // 'zh-CN' | 'en-US'，默认 'zh-CN'。控制 widget 文案\n  markerStyle: {\n    color: '#667eea',\n    size: 24,\n    borderWidth: 2,\n  },\n  // 事件回调（全部可选）\n  onGenerate: (response) => {},\n  onGenerateError: (error) => {},\n  onClick: (coordinate, allCoordinates) => {},\n  onVerifySuccess: (response) => {},\n  onVerifyError: (error) => {},\n  onRefresh: () => {},\n});\n```\n\n### 事件监听\n\n```typescript\nconst captcha = new Captcha({\n  container: '#captcha-container',\n  generateCaptcha,\n  verifyCaptcha,\n  onGenerate: (response) => console.log('验证码已生成', response),\n  onClick: (coordinate, allCoordinates) =>\n    console.log('点击了', coordinate, '共', allCoordinates.length),\n  onVerifySuccess: (response) => console.log('验证通过！'),\n  onVerifyError: (error) => console.error('验证失败', error),\n});\n```\n\n## API 文档\n\n### Captcha 类\n\n#### 构造函数\n\n```typescript\nconstructor(options: {\n  container: HTMLElement | string;        // 必填\n  width?: number;                         // 默认 400\n  generateCaptcha: GenerateCaptchaFunction;   // 必填\n  verifyCaptcha: VerifyCaptchaFunction;       // 必填\n  lang?: 'zh-CN' | 'en-US';                     // 默认 'zh-CN'\n  markerStyle?: { color?: string; size?: number; borderWidth?: number };\n  onGenerate?: (response: CaptchaGenerateResponse) => void;\n  onGenerateError?: (error: Error) => void;\n  onClick?: (coordinate: [number, number], allCoordinates: [number, number][]) => void;\n  onVerifySuccess?: (response: CaptchaVerifyResponse) => void;\n  onVerifyError?: (error: Error) => void;\n  onRefresh?: () => void;\n})\n```\n\n#### 方法\n\n| 方法 | 说明 |\n|---|---|\n| `generate()` | 生成验证码（调用你的 `generateCaptcha`），`Promise<CaptchaGenerateResponse>` |\n| `verify()` | 校验点击坐标（调用你的 `verifyCaptcha`），`Promise<CaptchaVerifyResponse>` |\n| `refresh()` | 刷新（清空并重新生成） |\n| `clearClicks()` | 清除点击记录 |\n| `clearMarkers()` | 清除点击标记 |\n| `reset()` | 重置状态 |\n| `getClicks()` | 获取点击坐标 `[number, number][]`（相对图片左上角） |\n| `getToken()` | 获取当前 token |\n| `destroy()` | 销毁实例，清理 DOM 与事件 |\n\n## 开发\n\n```bash\nnpm install\nnpm run dev        # 运行 demo（vite，:3000，需后端在 :3001）\nnpm run build      # 构建（tsup）\nnpm run build:watch\n```\n\n## Demo\n\ndemo 里已经用回调方式对接后端（vite 会把 `/api` 代理到 `:3001`）：\n\n```bash\n# 终端 1：后端（在 captcha-node/server 下）\ncd ../captcha-node/server\nnpm install && npm start     # 监听 :3001\n\n# 终端 2：前端 demo\nnpm run dev                  # 开 http://localhost:3000\n```\n\n> 不要用 `file://` 直接打开 HTML —— module 脚本会加载失败导致一片空白，必须走 `npm run dev`。\n\n## License\n\nMIT\n","readmeFilename":"README.md"}