{"_id":"@captcha-la/vue","name":"@captcha-la/vue","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.1":{"name":"@captcha-la/vue","version":"1.0.1","description":"Official Captchala CAPTCHA Vue 3 component - Smart CAPTCHA protection for your Vue applications","main":"dist/captchala-vue.cjs.js","module":"dist/captchala-vue.esm.js","types":"dist/index.d.ts","exports":{".":{"import":"./dist/captchala-vue.esm.js","require":"./dist/captchala-vue.cjs.js","types":"./dist/index.d.ts"}},"sideEffects":false,"scripts":{"build":"vite build","dev":"vite build --watch","prepublishOnly":"npm run build"},"peerDependencies":{"vue":"^3.2.0"},"devDependencies":{"@vitejs/plugin-vue":"^5.0.0","typescript":"^5.0.0","vite":"^5.0.0","vite-plugin-dts":"^4.5.4","vue":"^3.4.0","vue-tsc":"^2.0.0"},"repository":{"type":"git","url":"git+https://github.com/Captcha-La/vue.git"},"bugs":{"url":"https://github.com/Captcha-La/vue/issues"},"homepage":"https://docs.captcha.la/sdk/web/vue","keywords":["captcha","captchala","vue","vue3","component","bot-protection","security","verification"],"author":{"name":"CaptchaLa","email":"supply@captcha.la"},"license":"MIT","publishConfig":{"access":"public"},"_id":"@captcha-la/vue@1.0.1","gitHead":"353ab2a868277f97462858ad6d4e2cc36c5f1be6","_nodeVersion":"22.17.1","_npmVersion":"10.9.2","dist":{"integrity":"sha512-ZogsFnHajwAU95RQXqufJFTl9C/PV99vSoBlfKoufRX4Ys7gYxw1s8y0pohIwWC6wo+4RIdPnkdClrDK/T7Z9g==","shasum":"a0bee1ea585f430b3cf656ce63ab83ea304756a3","tarball":"https://registry.npmjs.org/@captcha-la/vue/-/vue-1.0.1.tgz","fileCount":8,"unpackedSize":25613,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDVXkTMuVWcycywi1B9PFgBKL/mUxW1txrIaTSLtSMtiAiAHqRqkVlwtxSSQqA7ltny3CMdUwUTxYRl5iS9D1FClpw=="}]},"_npmUser":{"name":"captcha_la","email":"support@captcha.la"},"directories":{},"maintainers":[{"name":"captcha_la","email":"support@captcha.la"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/vue_1.0.1_1777627186324_0.8407735459370367"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-01T09:19:46.243Z","1.0.1":"2026-05-01T09:19:46.500Z","modified":"2026-05-01T09:19:46.719Z"},"maintainers":[{"name":"captcha_la","email":"support@captcha.la"}],"description":"Official Captchala CAPTCHA Vue 3 component - Smart CAPTCHA protection for your Vue applications","homepage":"https://docs.captcha.la/sdk/web/vue","keywords":["captcha","captchala","vue","vue3","component","bot-protection","security","verification"],"repository":{"type":"git","url":"git+https://github.com/Captcha-La/vue.git"},"author":{"name":"CaptchaLa","email":"supply@captcha.la"},"bugs":{"url":"https://github.com/Captcha-La/vue/issues"},"license":"MIT","readme":"# @captcha-la/vue\n\n[English](./README.md) · [简体中文](./README.zh-CN.md)\n\nCaptchala 验证码 Vue 3 官方组件 —— 为你的 Vue 应用提供智能 CAPTCHA 防护。\n\n[![npm version](https://img.shields.io/npm/v/@captcha-la/vue.svg)](https://www.npmjs.com/package/@captcha-la/vue)\n[![npm downloads](https://img.shields.io/npm/dm/@captcha-la/vue.svg)](https://www.npmjs.com/package/@captcha-la/vue)\n[![license](https://img.shields.io/npm/l/@captcha-la/vue.svg)](https://github.com/Captcha-La/vue/blob/main/LICENSE)\n\n## 安装\n\n```bash\nnpm install @captcha-la/vue\n# or\nyarn add @captcha-la/vue\n# or\npnpm add @captcha-la/vue\n```\n\n## 快速上手\n\n```vue\n<template>\n  <Captchala\n    app-key=\"your-app-key\"\n    product=\"popup\"\n    @success=\"handleSuccess\"\n    @error=\"handleError\"\n  />\n</template>\n\n<script setup>\nimport { Captchala } from '@captcha-la/vue'\n\nfunction handleSuccess(result) {\n  console.log('验证成功')\n  console.log('Token:', result.token)\n  // 把 token 提交到你自己的后端校验\n}\n\nfunction handleError(error) {\n  console.error('验证失败:', error)\n}\n</script>\n```\n\n## Props\n\n| 属性 | 类型 | 默认值 | 说明 |\n|------|------|--------|------|\n| `appKey` | `string` | *必填* | Captchala 应用 key |\n| `serverToken` | `string` | - | 服务端签发的一次性 challenge token。当应用配置 `server_token_required=true` 时必填，详见下方 [生产环境：使用 serverToken](#生产环境使用-servertoken)。 |\n| `product` | `'popup' \\| 'float' \\| 'embed' \\| 'bind'` | `'popup'` | 显示模式 |\n| `action` | `string` | `'default'` | 业务场景标识 (例如 'login'、'register'、'checkout') |\n| `lang` | `string` | `'zh-CN'` | 语言代码 (`'zh-CN'`、`'en'`、`'ja'` 等) |\n\n## 事件\n\n| 事件 | Payload | 说明 |\n|------|---------|------|\n| `success` | `{ token, type, action }` | 验证成功时触发 |\n| `error` | `error` | 验证失败时触发 |\n| `close` | - | 验证码关闭时触发 |\n| `ready` | - | 验证码就绪时触发 |\n\n## 通过 ref 调用方法\n\n```vue\n<template>\n  <Captchala ref=\"captchaRef\" app-key=\"your-app-key\" />\n  <button @click=\"handleVerify\">触发验证</button>\n</template>\n\n<script setup>\nimport { ref } from 'vue'\nimport { Captchala } from '@captcha-la/vue'\n\nconst captchaRef = ref()\n\nfunction handleVerify() {\n  captchaRef.value?.verify()\n}\n</script>\n```\n\n| 方法 | 说明 |\n|------|------|\n| `verify()` | 手动触发验证 |\n| `reset()` | 重置验证码状态 |\n| `destroy()` | 销毁验证码实例 |\n| `bindTo(selector)` | 绑定到指定元素（仅 'bind' 模式） |\n\n## 显示模式\n\n### Popup 模式（默认）\n点击按钮弹出验证对话框。\n\n```vue\n<Captchala app-key=\"your-key\" product=\"popup\" />\n```\n\n### Float 模式\n浮动面板形式的验证码。\n\n```vue\n<Captchala app-key=\"your-key\" product=\"float\" />\n```\n\n### Embed 模式\n直接嵌入页面的验证码。\n\n```vue\n<Captchala app-key=\"your-key\" product=\"embed\" />\n```\n\n### Bind 模式\n将验证码绑定到已有按钮，点击该按钮时触发验证。\n\n```vue\n<template>\n  <Captchala\n    ref=\"captchaRef\"\n    app-key=\"your-key\"\n    product=\"bind\"\n    @success=\"handleSuccess\"\n  />\n  <button id=\"submit-btn\">提交</button>\n</template>\n\n<script setup>\nimport { ref, onMounted } from 'vue'\n\nconst captchaRef = ref()\n\nonMounted(() => {\n  captchaRef.value?.bindTo('#submit-btn')\n})\n\nfunction handleSuccess(result) {\n  // 此时可以拿 result.token 提交表单\n}\n</script>\n```\n\n## 生产环境：使用 `serverToken`\n\n生产环境（注册 / 登录 / 支付等）推荐使用 **服务端签发的一次性 token**。\n后端持有 `app_secret`，调用 `POST /v1/server/challenge/issue`（带\n`X-App-Key` + `X-App-Secret`）签发一次性 `server_token`（TTL 5 分钟，单次消费），\n再下发给前端。这样可以避免任何拿到公开 `app_key` 的人通过打码平台批量调用。\n\n```vue\n<template>\n  <div v-if=\"!serverToken\">Loading...</div>\n  <Captchala\n    v-else\n    :server-token=\"serverToken\"\n    app-key=\"pk_your_public_app_key\"\n    action=\"login\"\n    @success=\"onSuccess\"\n  />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted } from 'vue'\nimport { Captchala } from '@captcha-la/vue'\n\nconst serverToken = ref<string>()\n\nonMounted(async () => {\n  // 你自己的后端代理 /v1/server/challenge/issue\n  const r = await fetch('/api/captcha-token')\n  const d = await r.json()\n  serverToken.value = d.server_token\n})\n\nfunction onSuccess(result: { token: string }) {\n  console.log('pass_token:', result.token)\n}\n</script>\n```\n\n后端示例（Node.js / Express）：\n\n```js\n// server.js — 在你自己的 /api/captcha-token handler 里调用\napp.get('/api/captcha-token', async (req, res) => {\n  const r = await fetch('https://apiv1.captcha.la/v1/server/challenge/issue', {\n    method: 'POST',\n    headers: {\n      'X-App-Key': process.env.CAPTCHALA_APP_KEY,\n      'X-App-Secret': process.env.CAPTCHALA_APP_SECRET,\n      'Content-Type': 'application/x-www-form-urlencoded'\n    },\n    body: 'action=login&ttl=300'\n  })\n  const { data } = await r.json()\n  res.json({ server_token: data.server_token })\n})\n```\n\n注意事项：\n- 永远不要把 `X-App-Secret` 放进浏览器代码。\n- 每个 `server_token` 只能用一次，每次挂载组件前都要重新生成。\n- 老应用如果 `server_token_required=false`，仍然可以只用公开 `appKey` 模式。\n\n## 服务端校验\n\n收到 `onSuccess` 返回的 token 后，在你的服务端做最终校验：\n\n```js\n// 你的后端\nconst response = await fetch('https://api.captcha.la/v1/risk/consume', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application/json',\n    'X-App-Key': 'your-app-key',\n    'X-App-Secret': 'your-app-secret'\n  },\n  body: JSON.stringify({ token })\n})\n\nconst result = await response.json()\nif (result.code === 0 && result.data.valid) {\n  // token 有效，放行后续业务\n}\n```\n\n## TypeScript 支持\n\n完整 TypeScript 类型已内置：\n\n```ts\nimport { Captchala, type CaptchalaProps, type CaptchalaResult } from '@captcha-la/vue'\n```\n\n## 开源协议\n\nMIT，详见 [LICENSE](./LICENSE)。\n\n## 链接\n\n- [官网](https://captcha.la)\n- [文档](https://docs.captcha.la/zh-CN/sdk/web/vue)\n- [Dashboard](https://dash.captcha.la)\n","readmeFilename":"README.zh-CN.md","_rev":"1-99eb8000ac18ac5e343de948c5f5f0f6"}