@anilkumarthakur/vue3-recaptcha
Version:
A Vue 3 plugin for Google reCAPTCHA v2 (checkbox & invisible) and v3 integration
3 lines (2 loc) • 11.7 kB
JavaScript
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});let r=require("vue");var x=Symbol("vue3-recaptcha"),P="vue3-recaptcha-script",A="https://www.google.com/recaptcha/api.js",k=null,V=!1;function S(){return V&&typeof window<"u"&&typeof window.grecaptcha<"u"}function L(){return document.querySelector(`#${P}`)}function W(){const e=L();e&&e.remove(),k=null,V=!1}function H(e){const{siteKey:t,version:d,language:c,scriptUrl:n}=e;if(n)return n;const o=new URLSearchParams;return d==="v3"?o.set("render",t):(o.set("render","explicit"),typeof window<"u"&&(window.___grecaptcha_cfg=window.___grecaptcha_cfg??{},window.___grecaptcha_cfg.explicit=!0)),c&&o.set("hl",c),`${A}?${o.toString()}`}function I(e){return k||(S()?Promise.resolve():(k=new Promise((t,d)=>{const c=L();if(c){if(S()){t();return}c.addEventListener("load",()=>{V=!0,e.onLoad?.(),t()}),c.addEventListener("error",()=>{const o=new Error("Failed to load reCAPTCHA script");e.onError?.(o),d(o)});return}const n=document.createElement("script");n.id=P,n.src=H(e),n.async=!0,n.defer=!0,n.onload=()=>{e.version==="v3"?window.grecaptcha.ready(()=>{V=!0,e.onLoad?.(),t()}):(V=!0,e.onLoad?.(),t())},n.onerror=()=>{const o=new Error("Failed to load reCAPTCHA script");k=null,e.onError?.(o),d(o)},document.head.appendChild(n)}),k))}function N(){return new Promise((e,t)=>{if(S()){e();return}const d=window.setTimeout(()=>{window.clearInterval(c),t(new Error("Timeout waiting for reCAPTCHA to load"))},1e4),c=window.setInterval(()=>{typeof window.grecaptcha<"u"&&(window.clearInterval(c),window.clearTimeout(d),typeof window.grecaptcha.ready=="function"?window.grecaptcha.ready(()=>{V=!0,e()}):(V=!0,e()))},100)})}var T=(0,r.defineComponent)({name:"RecaptchaV2Checkbox",props:{siteKey:{type:String,default:void 0},theme:{type:String,default:"light"},size:{type:String,default:"normal"},tabindex:{type:Number,default:0},modelValue:{type:String,default:""}},emits:{"update:modelValue":e=>typeof e=="string",verify:e=>typeof e=="string",expire:null,error:e=>e instanceof Error,load:null},setup(e,{emit:t,expose:d}){const c=(0,r.ref)(null),n=(0,r.ref)(null),o=(0,r.ref)(!1),l=(0,r.inject)(x,void 0),i=(0,r.computed)(()=>e.siteKey??l?.siteKey??"");i.value||console.error("[vue3-recaptcha] Site key is required for RecaptchaV2Checkbox");function s(a){t("update:modelValue",a),t("verify",a)}function m(){t("update:modelValue",""),t("expire")}function g(a){t("update:modelValue",""),t("error",a)}async function y(){const a=c.value,v=i.value;if(!(!a||!v))try{S()||await I({siteKey:v,version:"v2"}),await new Promise(h=>{const u=window.setInterval(()=>{typeof window.grecaptcha?.render=="function"&&(window.clearInterval(u),h())},50)}),n.value=window.grecaptcha.render(a,{sitekey:v,theme:e.theme,size:e.size,tabindex:e.tabindex,callback:s,"expired-callback":m,"error-callback":()=>{g(new Error("reCAPTCHA verification error"))}}),o.value=!0,t("load")}catch(h){g(h instanceof Error?h:new Error(String(h)))}}function f(){const a=n.value;a!==null&&(window.grecaptcha.reset(a),t("update:modelValue",""))}function w(){const a=n.value;return a!==null?window.grecaptcha.getResponse(a):""}return(0,r.watch)(()=>[e.theme,e.size],()=>{const a=c.value;o.value&&a&&(a.innerHTML="",n.value=null,o.value=!1,y())}),(0,r.onMounted)(()=>{y()}),(0,r.onBeforeUnmount)(()=>{n.value=null}),d({reset:f,getResponse:w,widgetId:n}),()=>(0,r.createVNode)("div",{ref:c,class:"vue3-recaptcha-v2-checkbox",style:{display:"inline-block"}},null)}}),_=(0,r.defineComponent)({name:"RecaptchaV2Invisible",props:{siteKey:{type:String,default:void 0},badge:{type:String,default:"bottomright"},tabindex:{type:Number,default:0},modelValue:{type:String,default:""}},emits:{"update:modelValue":e=>typeof e=="string",verify:e=>typeof e=="string",expire:null,error:e=>e instanceof Error,load:null},setup(e,{emit:t,expose:d}){const c=(0,r.ref)(null),n=(0,r.ref)(null),o=(0,r.ref)(!1),l=(0,r.ref)(null),i=(0,r.ref)(null),s=(0,r.inject)(x,void 0),m=(0,r.computed)(()=>e.siteKey??s?.siteKey??"");m.value||console.error("[vue3-recaptcha] Site key is required for RecaptchaV2Invisible");function g(u){t("update:modelValue",u),t("verify",u);const p=l.value;p&&(l.value=null,i.value=null,p(u))}function y(){t("update:modelValue",""),t("expire")}function f(u){t("update:modelValue",""),t("error",u);const p=i.value;p&&(l.value=null,i.value=null,p(u))}async function w(){const u=c.value,p=m.value;if(!(!u||!p))try{S()||await I({siteKey:p,version:"v2"}),await new Promise(E=>{const R=window.setInterval(()=>{typeof window.grecaptcha?.render=="function"&&(window.clearInterval(R),E())},50)}),n.value=window.grecaptcha.render(u,{sitekey:p,size:"invisible",tabindex:e.tabindex,callback:g,"expired-callback":y,"error-callback":()=>{f(new Error("reCAPTCHA verification error"))}}),o.value=!0,t("load")}catch(E){f(E instanceof Error?E:new Error(String(E)))}}async function a(){o.value||await w();const u=n.value;if(u===null)throw new Error("[vue3-recaptcha] Widget not initialized");return new Promise((p,E)=>{const R=window.setTimeout(()=>{const b=i.value;l.value=null,i.value=null,b?.(new Error("[vue3-recaptcha] Verification timeout after 60 seconds"))},6e4);l.value=b=>{window.clearTimeout(R),p(b)},i.value=b=>{window.clearTimeout(R),E(b)};try{window.grecaptcha.execute(u)}catch(b){window.clearTimeout(R),l.value=null,i.value=null,E(b instanceof Error?b:new Error(String(b)))}})}function v(){const u=n.value;u!==null&&(window.grecaptcha.reset(u),t("update:modelValue",""),l.value=null,i.value=null)}function h(){const u=n.value;return u!==null?window.grecaptcha.getResponse(u):""}return(0,r.onMounted)(()=>{w()}),(0,r.onBeforeUnmount)(()=>{n.value=null,l.value=null,i.value=null}),d({execute:a,reset:v,getResponse:h,widgetId:n}),()=>(0,r.createVNode)("div",{ref:c,class:"vue3-recaptcha-v2-invisible",style:{display:"none"}},null)}}),C=(0,r.defineComponent)({name:"RecaptchaV3",props:{siteKey:{type:String,default:void 0},action:{type:String,default:"submit"},badge:{type:String,default:"bottomright"},hideBadge:{type:Boolean,default:!1},modelValue:{type:String,default:""}},emits:{"update:modelValue":e=>typeof e=="string",verify:e=>typeof e=="string",error:e=>e instanceof Error,load:null},setup(e,{emit:t,expose:d}){const c=(0,r.ref)(!1),n=(0,r.ref)(!1),o=(0,r.ref)(null);let l;const i=(0,r.inject)(x,void 0),s=(0,r.computed)(()=>e.siteKey??i?.siteKey??"");s.value||console.error("[vue3-recaptcha] Site key is required for RecaptchaV3");function m(){if(typeof document>"u")return;const f=document.querySelector(".grecaptcha-badge");f&&(f.style.visibility=e.hideBadge?"hidden":"visible")}async function g(){if(!(c.value||n.value)){n.value=!0,o.value=null;try{await I({siteKey:s.value,version:"v3",onLoad:()=>{c.value=!0,t("load")},onError:f=>{o.value=f,t("error",f)}}),c.value=!0}catch(f){const w=f instanceof Error?f:new Error(String(f));o.value=w,t("error",w)}finally{n.value=!1}}}async function y(f){if(c.value||await g(),typeof window.grecaptcha>"u"){const v=new Error("[vue3-recaptcha] grecaptcha is not available");throw t("error",v),v}const w=s.value,a=f??e.action??"submit";try{const v=await window.grecaptcha.execute(w,{action:a});return t("update:modelValue",v),t("verify",v),l!==void 0&&clearTimeout(l),l=setTimeout(()=>{t("update:modelValue","")},11e4),v}catch(v){const h=v instanceof Error?v:new Error(String(v));throw o.value=h,t("error",h),t("update:modelValue",""),h}}return(0,r.watch)(()=>e.hideBadge,m),(0,r.onMounted)(()=>{g().then(()=>{m()})}),(0,r.onBeforeUnmount)(()=>{l!==void 0&&clearTimeout(l)}),d({load:g,loadRecaptcha:g,execute:y,isLoaded:c,isLoading:n,error:o}),()=>(0,r.createVNode)("div",{class:"vue3-recaptcha-v3",style:{display:"none"}},null)}});function U(e={}){const t=(0,r.inject)(x,void 0),d=e.siteKey??t?.siteKey;if(!d)throw new Error("[vue3-recaptcha] Site key is required. Provide it via plugin options or composable options.");const c=d,n=(0,r.ref)(""),o=(0,r.ref)(!1),l=(0,r.ref)(!1),i=(0,r.ref)(null),s=(0,r.ref)(null);async function m(){if(S()){o.value=!0;return}l.value=!0,i.value=null;try{await I({siteKey:c,version:"v2",onError:a=>{i.value=a}}),o.value=!0}catch(a){throw i.value=a instanceof Error?a:new Error(String(a)),i.value}finally{l.value=!1}}async function g(a){return await m(),s.value!==null&&f(),new Promise((v,h)=>{try{const u=window.grecaptcha.render(a,{sitekey:c,theme:e.theme,size:e.size,tabindex:e.tabindex,callback:p=>{n.value=p},"expired-callback":()=>{n.value=""},"error-callback":()=>{i.value=new Error("reCAPTCHA verification error"),n.value=""}});s.value=u,v(u)}catch(u){const p=u instanceof Error?u:new Error(String(u));i.value=p,h(p)}})}async function y(){await m();const a=s.value;if(a===null)throw new Error("[vue3-recaptcha] Widget not rendered. Call render() first.");return new Promise((v,h)=>{const u=n.value,p=setInterval(()=>{n.value&&n.value!==u&&(clearInterval(p),clearTimeout(E),v(n.value))},100),E=setTimeout(()=>{clearInterval(p),h(new Error("[vue3-recaptcha] Execute timeout after 30 seconds"))},3e4);try{window.grecaptcha.execute(a)}catch(R){clearInterval(p),clearTimeout(E),h(R instanceof Error?R:new Error(String(R)))}})}function f(){const a=s.value;a!==null&&(window.grecaptcha.reset(a),n.value="")}function w(){const a=s.value;return a!==null?window.grecaptcha.getResponse(a):n.value}return(0,r.onUnmounted)(()=>{s.value=null,n.value=""}),{token:(0,r.readonly)(n),isReady:(0,r.readonly)(o),isLoading:(0,r.readonly)(l),error:(0,r.readonly)(i),widgetId:(0,r.readonly)(s),render:g,execute:y,reset:f,getResponse:w}}function q(e={}){const t=(0,r.inject)(x,void 0),d=e.siteKey??t?.siteKey;if(!d)throw new Error("[vue3-recaptcha] Site key is required. Provide it via plugin options or composable options.");const c=d,n=(0,r.ref)(""),o=(0,r.ref)(!1),l=(0,r.ref)(!1),i=(0,r.ref)(null);let s;async function m(){if(S()){o.value=!0;return}l.value=!0,i.value=null;try{await I({siteKey:c,version:"v3",onError:y=>{i.value=y}}),o.value=!0}catch(y){throw i.value=y instanceof Error?y:new Error(String(y)),i.value}finally{l.value=!1}}async function g(y){await m();const f=y??e.action??"submit";l.value=!0,i.value=null;try{const w=await window.grecaptcha.execute(c,{action:f});return n.value=w,s!==void 0&&clearTimeout(s),s=setTimeout(()=>{n.value=""},11e4),w}catch(w){const a=w instanceof Error?w:new Error(String(w));throw i.value=a,n.value="",a}finally{l.value=!1}}return(0,r.onUnmounted)(()=>{s!==void 0&&clearTimeout(s),n.value=""}),{token:(0,r.readonly)(n),isReady:(0,r.readonly)(o),isLoading:(0,r.readonly)(l),error:(0,r.readonly)(i),execute:g}}var K={install(e,t){if(!t?.siteKey){console.error("[vue3-recaptcha] Site key is required");return}const d=t.version??"v3",c=(0,r.ref)(!1);e.component("RecaptchaV2Checkbox",T),e.component("RecaptchaV2Invisible",_),e.component("RecaptchaV2",T),e.component("RecaptchaV3",C),e.component("Recaptcha",C);const n=async()=>{await I({siteKey:t.siteKey,version:d,language:t.language,scriptUrl:t.scriptUrl,onLoad:()=>{c.value=!0,t.onLoad?.()}}),c.value=!0},o={siteKey:t.siteKey,version:d,isLoaded:c,loadScript:n};e.provide(x,o),t.autoLoad!==!1&&n().catch(l=>{const i=l instanceof Error?l:new Error(String(l));console.error("[vue3-recaptcha] Failed to auto-load script:",i),t.onError?.(i)})}},z=K;exports.RECAPTCHA_INJECTION_KEY=x;exports.Recaptcha=C;exports.RecaptchaV3=C;exports.RecaptchaV2=T;exports.RecaptchaV2Checkbox=T;exports.RecaptchaV2Invisible=_;exports.VueRecaptchaPlugin=K;exports.default=K;exports.isRecaptchaLoaded=S;exports.loadRecaptchaScript=I;exports.recaptchaPlugin=z;exports.removeScript=W;exports.useRecaptchaV2=U;exports.useRecaptchaV3=q;exports.waitForRecaptcha=N;
//# sourceMappingURL=index.cjs.map